summaryrefslogtreecommitdiffstats
path: root/private/os2
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/os2
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to '')
-rw-r--r--private/os2/client/apinums.h439
-rw-r--r--private/os2/client/apiworke.h50
-rw-r--r--private/os2/client/coninit.c94
-rw-r--r--private/os2/client/conrqust.c449
-rw-r--r--private/os2/client/crypt.h579
-rw-r--r--private/os2/client/dllcnfg.c228
-rw-r--r--private/os2/client/dllcopy.c2161
-rw-r--r--private/os2/client/dlldbcs.c163
-rw-r--r--private/os2/client/dlldir.c1705
-rw-r--r--private/os2/client/dllea.c1974
-rw-r--r--private/os2/client/dllerror.c667
-rw-r--r--private/os2/client/dllevent.c1161
-rw-r--r--private/os2/client/dllfile.c653
-rw-r--r--private/os2/client/dllfind.c2265
-rw-r--r--private/os2/client/dllflopy.c1241
-rw-r--r--private/os2/client/dllfs16.c5177
-rw-r--r--private/os2/client/dllfsd.c1463
-rw-r--r--private/os2/client/dllhandl.c6367
-rw-r--r--private/os2/client/dllimmon.c312
-rw-r--r--private/os2/client/dllinit.c1156
-rw-r--r--private/os2/client/dllioctl.c3792
-rw-r--r--private/os2/client/dllkbd.c2443
-rw-r--r--private/os2/client/dllldr16.c1107
-rw-r--r--private/os2/client/dllloadr.c325
-rw-r--r--private/os2/client/dllmisc.c536
-rw-r--r--private/os2/client/dllmon.c773
-rw-r--r--private/os2/client/dllmou.c1855
-rw-r--r--private/os2/client/dllmsc16.c506
-rw-r--r--private/os2/client/dllmsg.c1424
-rw-r--r--private/os2/client/dllmsg16.c142
-rw-r--r--private/os2/client/dllmsl16.c712
-rw-r--r--private/os2/client/dllmutex.c1039
-rw-r--r--private/os2/client/dllmuxwt.c1423
-rw-r--r--private/os2/client/dllname.c1862
-rw-r--r--private/os2/client/dllnb.c1827
-rw-r--r--private/os2/client/dllnet16.c5295
-rw-r--r--private/os2/client/dllnls.c1116
-rw-r--r--private/os2/client/dllnls16.c417
-rw-r--r--private/os2/client/dllnp.c2567
-rw-r--r--private/os2/client/dllnp16.c226
-rw-r--r--private/os2/client/dllpip16.c66
-rw-r--r--private/os2/client/dllpipe.c157
-rw-r--r--private/os2/client/dllpmnt.c1793
-rw-r--r--private/os2/client/dllpmnt1.c2224
-rw-r--r--private/os2/client/dllpmsha.c536
-rw-r--r--private/os2/client/dllpmwin.c91
-rw-r--r--private/os2/client/dllque.c940
-rw-r--r--private/os2/client/dllque16.c267
-rw-r--r--private/os2/client/dllremot.c491
-rw-r--r--private/os2/client/dllsem.c483
-rw-r--r--private/os2/client/dllsem16.c4340
-rw-r--r--private/os2/client/dllsig16.c499
-rw-r--r--private/os2/client/dllsm.c814
-rw-r--r--private/os2/client/dllsm16.c107
-rw-r--r--private/os2/client/dllsub16.c430
-rw-r--r--private/os2/client/dlltask.c5965
-rw-r--r--private/os2/client/dlltimer.c1101
-rw-r--r--private/os2/client/dlltsk16.c164
-rw-r--r--private/os2/client/dllutil.c1533
-rw-r--r--private/os2/client/dllvio.c2422
-rw-r--r--private/os2/client/dllvm.c636
-rw-r--r--private/os2/client/dllvm16.c3240
-rw-r--r--private/os2/client/dllwin32.c302
-rw-r--r--private/os2/client/dllxcpt.c508
-rw-r--r--private/os2/client/fileinit.c1066
-rw-r--r--private/os2/client/i386/dll16.asm1121
-rw-r--r--private/os2/client/i386/dllthunk.asm111
-rw-r--r--private/os2/client/i386/doscalls.asm19738
-rw-r--r--private/os2/client/i386/ldrstart.asm263
-rw-r--r--private/os2/client/makefile6
-rw-r--r--private/os2/client/mips/dllthunk.s117
-rw-r--r--private/os2/client/nlstable.c2938
-rw-r--r--private/os2/client/os2dir.c329
-rw-r--r--private/os2/client/os2dll.def177
-rw-r--r--private/os2/client/os2file.c214
-rw-r--r--private/os2/client/os2misc.c341
-rw-r--r--private/os2/client/os2null.c174
-rw-r--r--private/os2/client/os2que.c631
-rw-r--r--private/os2/client/os2sem.c1043
-rw-r--r--private/os2/client/os2sig.c875
-rw-r--r--private/os2/client/os2task.c870
-rw-r--r--private/os2/client/os2test.c117
-rw-r--r--private/os2/client/os2vm.c507
-rw-r--r--private/os2/client/os2xcpt.c188
-rw-r--r--private/os2/client/packoff.h34
-rw-r--r--private/os2/client/packon.h32
-rw-r--r--private/os2/client/rap.h376
-rw-r--r--private/os2/client/remtypes.h176
-rw-r--r--private/os2/client/rxp.h402
-rw-r--r--private/os2/client/rxuser.h115
-rw-r--r--private/os2/client/smbgtpt.h920
-rw-r--r--private/os2/client/smbtypes.h360
-rw-r--r--private/os2/client/sources123
-rw-r--r--private/os2/client/thunk/acsnetb.def12
-rw-r--r--private/os2/client/thunk/all.cmd30
-rw-r--r--private/os2/client/thunk/apilist.awk20
-rw-r--r--private/os2/client/thunk/apilist.c327
-rw-r--r--private/os2/client/thunk/doscalls.def179
-rw-r--r--private/os2/client/thunk/doscalls.mif2370
-rw-r--r--private/os2/client/thunk/doscalls.thk453
-rw-r--r--private/os2/client/thunk/dosthk.tif299
-rw-r--r--private/os2/client/thunk/include/assert.h34
-rw-r--r--private/os2/client/thunk/include/bios.h175
-rw-r--r--private/os2/client/thunk/include/cmacros.inc1236
-rw-r--r--private/os2/client/thunk/include/conio.h36
-rw-r--r--private/os2/client/thunk/include/ctype.h96
-rw-r--r--private/os2/client/thunk/include/custcntl.h82
-rw-r--r--private/os2/client/thunk/include/dde.h115
-rw-r--r--private/os2/client/thunk/include/debug.inc274
-rw-r--r--private/os2/client/thunk/include/debugsys.inc442
-rw-r--r--private/os2/client/thunk/include/direct.h36
-rw-r--r--private/os2/client/thunk/include/dos.h209
-rw-r--r--private/os2/client/thunk/include/dosx.inc47
-rw-r--r--private/os2/client/thunk/include/drivinit.h157
-rw-r--r--private/os2/client/thunk/include/errno.h71
-rw-r--r--private/os2/client/thunk/include/exe386.h603
-rw-r--r--private/os2/client/thunk/include/exe386pe.h870
-rw-r--r--private/os2/client/thunk/include/fcntl.h35
-rw-r--r--private/os2/client/thunk/include/float.h140
-rw-r--r--private/os2/client/thunk/include/gdidefs.inc1200
-rw-r--r--private/os2/client/thunk/include/graph.h427
-rw-r--r--private/os2/client/thunk/include/int2fapi.inc85
-rw-r--r--private/os2/client/thunk/include/int31.inc136
-rw-r--r--private/os2/client/thunk/include/io.h47
-rw-r--r--private/os2/client/thunk/include/krnl32.h132
-rw-r--r--private/os2/client/thunk/include/limits.h33
-rw-r--r--private/os2/client/thunk/include/locale.h78
-rw-r--r--private/os2/client/thunk/include/malloc.h136
-rw-r--r--private/os2/client/thunk/include/math.h235
-rw-r--r--private/os2/client/thunk/include/memory.h56
-rw-r--r--private/os2/client/thunk/include/newexe.h363
-rw-r--r--private/os2/client/thunk/include/newexe.inc321
-rw-r--r--private/os2/client/thunk/include/pgchart.h219
-rw-r--r--private/os2/client/thunk/include/prd.inc69
-rw-r--r--private/os2/client/thunk/include/printer.h258
-rw-r--r--private/os2/client/thunk/include/process.h91
-rw-r--r--private/os2/client/thunk/include/search.h41
-rw-r--r--private/os2/client/thunk/include/setjmp.h37
-rw-r--r--private/os2/client/thunk/include/share.h15
-rw-r--r--private/os2/client/thunk/include/signal.h71
-rw-r--r--private/os2/client/thunk/include/spool.h174
-rw-r--r--private/os2/client/thunk/include/stdarg.h42
-rw-r--r--private/os2/client/thunk/include/stddef.h65
-rw-r--r--private/os2/client/thunk/include/stdio.h224
-rw-r--r--private/os2/client/thunk/include/stdlib.h204
-rw-r--r--private/os2/client/thunk/include/string.h121
-rw-r--r--private/os2/client/thunk/include/style.h206
-rw-r--r--private/os2/client/thunk/include/sys/locking.h16
-rw-r--r--private/os2/client/thunk/include/sys/stat.h59
-rw-r--r--private/os2/client/thunk/include/sys/timeb.h42
-rw-r--r--private/os2/client/thunk/include/sys/types.h31
-rw-r--r--private/os2/client/thunk/include/sys/utime.h43
-rw-r--r--private/os2/client/thunk/include/sysinfo.inc53
-rw-r--r--private/os2/client/thunk/include/tdb.inc208
-rw-r--r--private/os2/client/thunk/include/testing.h43
-rw-r--r--private/os2/client/thunk/include/time.h114
-rw-r--r--private/os2/client/thunk/include/userproc.h38
-rw-r--r--private/os2/client/thunk/include/varargs.h43
-rw-r--r--private/os2/client/thunk/include/vdmad.inc143
-rw-r--r--private/os2/client/thunk/include/version.h1
-rw-r--r--private/os2/client/thunk/include/vkd.inc172
-rw-r--r--private/os2/client/thunk/include/vmm.inc2234
-rw-r--r--private/os2/client/thunk/include/vpicd.inc86
-rw-r--r--private/os2/client/thunk/include/vtd.inc35
-rw-r--r--private/os2/client/thunk/include/win32.h90
-rw-r--r--private/os2/client/thunk/include/winbase.h2224
-rw-r--r--private/os2/client/thunk/include/wincon.h458
-rw-r--r--private/os2/client/thunk/include/windef.h248
-rw-r--r--private/os2/client/thunk/include/windefs.inc122
-rw-r--r--private/os2/client/thunk/include/windows.h3479
-rw-r--r--private/os2/client/thunk/include/windows.inc2190
-rw-r--r--private/os2/client/thunk/include/winerror.h1778
-rw-r--r--private/os2/client/thunk/include/winexp.h47
-rw-r--r--private/os2/client/thunk/include/wingdi.h1030
-rw-r--r--private/os2/client/thunk/include/winkern.inc441
-rw-r--r--private/os2/client/thunk/include/winmm.h41
-rw-r--r--private/os2/client/thunk/include/winnet.h78
-rw-r--r--private/os2/client/thunk/include/winnt.h532
-rw-r--r--private/os2/client/thunk/include/winuser.h2075
-rw-r--r--private/os2/client/thunk/inetapi.def64
-rw-r--r--private/os2/client/thunk/kbdcalls.def41
-rw-r--r--private/os2/client/thunk/ldrtabs/dump.cmd151
-rw-r--r--private/os2/client/thunk/ldrtabs/nedump.c228
-rw-r--r--private/os2/client/thunk/mailslot.def19
-rw-r--r--private/os2/client/thunk/makefile294
-rw-r--r--private/os2/client/thunk/moncalls.def18
-rw-r--r--private/os2/client/thunk/moucalls.def40
-rw-r--r--private/os2/client/thunk/msg.def20
-rw-r--r--private/os2/client/thunk/nampipes.def26
-rw-r--r--private/os2/client/thunk/netapi.os2bin0 -> 247860 bytes
-rw-r--r--private/os2/client/thunk/netoem.def15
-rw-r--r--private/os2/client/thunk/nls.def21
-rw-r--r--private/os2/client/thunk/os2def.tif318
-rw-r--r--private/os2/client/thunk/os2sm.def13
-rw-r--r--private/os2/client/thunk/pmnt.def67
-rw-r--r--private/os2/client/thunk/pmshapi.def10
-rw-r--r--private/os2/client/thunk/pmwin.def9
-rw-r--r--private/os2/client/thunk/quecalls.def12
-rw-r--r--private/os2/client/thunk/r2xfer.asm555
-rw-r--r--private/os2/client/thunk/sesmgr.def52
-rw-r--r--private/os2/client/thunk/thunkcom/cod1632.c1482
-rw-r--r--private/os2/client/thunk/thunkcom/cod1632b.c245
-rw-r--r--private/os2/client/thunk/thunkcom/cod1632b.h1
-rw-r--r--private/os2/client/thunk/thunkcom/cod3216.c2563
-rw-r--r--private/os2/client/thunk/thunkcom/cod3216.h20
-rw-r--r--private/os2/client/thunk/thunkcom/cod3216b.c1015
-rw-r--r--private/os2/client/thunk/thunkcom/cod3216g.c598
-rw-r--r--private/os2/client/thunk/thunkcom/codegen.c1000
-rw-r--r--private/os2/client/thunk/thunkcom/codegen.h99
-rw-r--r--private/os2/client/thunk/thunkcom/combine.c209
-rw-r--r--private/os2/client/thunk/thunkcom/error.c105
-rw-r--r--private/os2/client/thunk/thunkcom/error.h23
-rw-r--r--private/os2/client/thunk/thunkcom/fprot.h173
-rw-r--r--private/os2/client/thunk/thunkcom/globals.c24
-rw-r--r--private/os2/client/thunk/thunkcom/globals.h16
-rw-r--r--private/os2/client/thunk/thunkcom/htotdl.c251
-rw-r--r--private/os2/client/thunk/thunkcom/makefile97
-rw-r--r--private/os2/client/thunk/thunkcom/makfprot.cmd60
-rw-r--r--private/os2/client/thunk/thunkcom/mkhthk.cmd2
-rw-r--r--private/os2/client/thunk/thunkcom/ml.err258
-rw-r--r--private/os2/client/thunk/thunkcom/mtclex.c2115
-rw-r--r--private/os2/client/thunk/thunkcom/mtclex.l245
-rw-r--r--private/os2/client/thunk/thunkcom/mtcpars.y1504
-rw-r--r--private/os2/client/thunk/thunkcom/ncform178
-rw-r--r--private/os2/client/thunk/thunkcom/rcpp.err334
-rw-r--r--private/os2/client/thunk/thunkcom/sample.thk175
-rw-r--r--private/os2/client/thunk/thunkcom/symtab.c443
-rw-r--r--private/os2/client/thunk/thunkcom/symtab.h50
-rw-r--r--private/os2/client/thunk/thunkcom/thunk.c490
-rw-r--r--private/os2/client/thunk/thunkcom/thunk.def6
-rw-r--r--private/os2/client/thunk/thunkcom/thunk.h57
-rw-r--r--private/os2/client/thunk/thunkcom/thunk.txt1828
-rw-r--r--private/os2/client/thunk/thunkcom/thunkcom1458
-rw-r--r--private/os2/client/thunk/thunkcom/thunkcom.cmd13
-rw-r--r--private/os2/client/thunk/thunkcom/types.c999
-rw-r--r--private/os2/client/thunk/thunkcom/types.h250
-rw-r--r--private/os2/client/thunk/thunkcom/yacc/yypars.c258
-rw-r--r--private/os2/client/thunk/viocalls.def102
-rw-r--r--private/os2/client/tstr.h292
-rw-r--r--private/os2/client/tstring.h243
-rw-r--r--private/os2/client/vdmredir.c1
-rw-r--r--private/os2/client/vdmredir.h443
-rw-r--r--private/os2/client/vrdebug.h603
-rw-r--r--private/os2/client/vrremote.c1831
-rw-r--r--private/os2/client/vrremote.h101
-rw-r--r--private/os2/dirs31
-rw-r--r--private/os2/doc/ansi.src440
-rw-r--r--private/os2/doc/apistat273
-rw-r--r--private/os2/doc/dos32.scr576
-rw-r--r--private/os2/doc/fy92.pptbin0 -> 11708 bytes
-rw-r--r--private/os2/doc/incompat.os255
-rw-r--r--private/os2/doc/ioctls.txt3703
-rw-r--r--private/os2/doc/os2api.txt694
-rw-r--r--private/os2/doc/os2dbg.docbin0 -> 16384 bytes
-rw-r--r--private/os2/doc/os2nt.txt674
-rw-r--r--private/os2/doc/pmnt.docbin0 -> 58404 bytes
-rw-r--r--private/os2/doc/pmntover.docbin0 -> 99840 bytes
-rw-r--r--private/os2/doc/pownt.oldbin0 -> 30012 bytes
-rw-r--r--private/os2/doc/pownt.pptbin0 -> 21060 bytes
-rw-r--r--private/os2/doc/relnotes.docbin0 -> 23552 bytes
-rw-r--r--private/os2/doc/w32thk.docbin0 -> 20992 bytes
-rw-r--r--private/os2/inc/conapi.h404
-rw-r--r--private/os2/inc/conrqust.h162
-rw-r--r--private/os2/inc/dllcopy.h35
-rw-r--r--private/os2/inc/dlldbcs.h48
-rw-r--r--private/os2/inc/dllfile.h69
-rw-r--r--private/os2/inc/iovector.h528
-rw-r--r--private/os2/inc/ldrdbg.h40
-rw-r--r--private/os2/inc/ldrtabs.h444
-rw-r--r--private/os2/inc/ldrxport.h75
-rw-r--r--private/os2/inc/mi.h504
-rw-r--r--private/os2/inc/monitor.h68
-rw-r--r--private/os2/inc/nb30p.h83
-rw-r--r--private/os2/inc/netb.h133
-rw-r--r--private/os2/inc/netrqust.h338
-rw-r--r--private/os2/inc/os2.h98
-rw-r--r--private/os2/inc/os2crt.h23
-rw-r--r--private/os2/inc/os2dbg.h129
-rw-r--r--private/os2/inc/os2dev.h522
-rw-r--r--private/os2/inc/os2dll.h1202
-rw-r--r--private/os2/inc/os2dll16.h322
-rw-r--r--private/os2/inc/os2err.h631
-rw-r--r--private/os2/inc/os2file.h442
-rw-r--r--private/os2/inc/os2flopy.h83
-rw-r--r--private/os2/inc/os2ldr.h67
-rw-r--r--private/os2/inc/os2net16.h974
-rw-r--r--private/os2/inc/os2nls.h388
-rw-r--r--private/os2/inc/os2nt.h986
-rw-r--r--private/os2/inc/os2res.h80
-rw-r--r--private/os2/inc/os2srv.h1650
-rw-r--r--private/os2/inc/os2ssmsg.h886
-rw-r--r--private/os2/inc/os2ssrtl.h476
-rw-r--r--private/os2/inc/os2sub.h416
-rw-r--r--private/os2/inc/os2tile.h85
-rw-r--r--private/os2/inc/os2v12.h1106
-rw-r--r--private/os2/inc/os2v20.h2582
-rw-r--r--private/os2/inc/os2win.h767
-rw-r--r--private/os2/inc/pmnt.h306
-rw-r--r--private/os2/inc/sesgrp.h180
-rw-r--r--private/os2/inc/sesport.h659
-rw-r--r--private/os2/ldr/basedef.h233
-rw-r--r--private/os2/ldr/basemac.h129
-rw-r--r--private/os2/ldr/bseerr.h856
-rw-r--r--private/os2/ldr/exe386.h870
-rw-r--r--private/os2/ldr/ldrdbcs.c159
-rw-r--r--private/os2/ldr/ldrdbcs.h48
-rw-r--r--private/os2/ldr/ldrdll.def28
-rw-r--r--private/os2/ldr/ldrextrn.h127
-rw-r--r--private/os2/ldr/ldrfixup.c483
-rw-r--r--private/os2/ldr/ldrinit.c1415
-rw-r--r--private/os2/ldr/ldrmte.c4290
-rw-r--r--private/os2/ldr/ldrste.c1159
-rw-r--r--private/os2/ldr/ldrsubr.c1962
-rw-r--r--private/os2/ldr/ldrutil.c228
-rw-r--r--private/os2/ldr/ldrvars.h928
-rw-r--r--private/os2/ldr/ldrvars.inc23
-rw-r--r--private/os2/ldr/makefile6
-rw-r--r--private/os2/ldr/mi.h497
-rw-r--r--private/os2/ldr/newexe.h464
-rw-r--r--private/os2/ldr/os2defp.h30
-rw-r--r--private/os2/ldr/seldesc.h265
-rw-r--r--private/os2/ldr/seldesc.inc163
-rw-r--r--private/os2/ldr/sources75
-rw-r--r--private/os2/loader/loader.c571
-rw-r--r--private/os2/loader/makefile6
-rw-r--r--private/os2/loader/sources69
-rw-r--r--private/os2/msg/oso001.007bin0 -> 127687 bytes
-rw-r--r--private/os2/msg/oso001.009bin0 -> 108095 bytes
-rw-r--r--private/os2/msg/oso001.010bin0 -> 119914 bytes
-rw-r--r--private/os2/msg/oso001.012bin0 -> 111163 bytes
-rw-r--r--private/os2/msg/oso001.016bin0 -> 124338 bytes
-rw-r--r--private/os2/msg/oso001.029bin0 -> 105229 bytes
-rw-r--r--private/os2/os2ses/conrqust.c199
-rw-r--r--private/os2/os2ses/event.c4205
-rw-r--r--private/os2/os2ses/event.h203
-rw-r--r--private/os2/os2ses/i386/bekbd.asm778
-rw-r--r--private/os2/os2ses/i386/cfkbd.asm794
-rw-r--r--private/os2/os2ses/i386/dkkbd.asm790
-rw-r--r--private/os2/os2ses/i386/frkbd.asm1153
-rw-r--r--private/os2/os2ses/i386/grkbd.asm768
-rw-r--r--private/os2/os2ses/i386/itkbd.asm1127
-rw-r--r--private/os2/os2ses/i386/jpkbd.asm1482
-rw-r--r--private/os2/os2ses/i386/kbdxlat.asm2470
-rw-r--r--private/os2/os2ses/i386/lakbd.asm788
-rw-r--r--private/os2/os2ses/i386/nlkbd.asm784
-rw-r--r--private/os2/os2ses/i386/nokbd.asm791
-rw-r--r--private/os2/os2ses/i386/pokbd.asm773
-rw-r--r--private/os2/os2ses/i386/sfkbd.asm788
-rw-r--r--private/os2/os2ses/i386/sgkbd.asm788
-rw-r--r--private/os2/os2ses/i386/spkbd.asm786
-rw-r--r--private/os2/os2ses/i386/sukbd.asm785
-rw-r--r--private/os2/os2ses/i386/svkbd.asm785
-rw-r--r--private/os2/os2ses/i386/ukkbd.asm1129
-rw-r--r--private/os2/os2ses/i386/uskbd.asm761
-rw-r--r--private/os2/os2ses/imrqust.c261
-rw-r--r--private/os2/os2ses/kbd.h27
-rw-r--r--private/os2/os2ses/kbddd.inc269
-rw-r--r--private/os2/os2ses/kbdnls.c191
-rw-r--r--private/os2/os2ses/kbdrqust.c4046
-rw-r--r--private/os2/os2ses/kbdtable.c653
-rw-r--r--private/os2/os2ses/kbdxlat.inc164
-rw-r--r--private/os2/os2ses/makefile6
-rw-r--r--private/os2/os2ses/mon.h82
-rw-r--r--private/os2/os2ses/monrqust.c793
-rw-r--r--private/os2/os2ses/mou.h28
-rw-r--r--private/os2/os2ses/mourqust.c235
-rw-r--r--private/os2/os2ses/nls.c349
-rw-r--r--private/os2/os2ses/ntinitss.c1650
-rw-r--r--private/os2/os2ses/ntrqust.c402
-rw-r--r--private/os2/os2ses/os2.c1750
-rw-r--r--private/os2/os2ses/os2.rc155
-rw-r--r--private/os2/os2ses/os2ses.h324
-rw-r--r--private/os2/os2ses/prtrqust.c327
-rw-r--r--private/os2/os2ses/sources90
-rw-r--r--private/os2/os2ses/struc.inc513
-rw-r--r--private/os2/os2ses/tmrqust.c125
-rw-r--r--private/os2/os2ses/trans.c463
-rw-r--r--private/os2/os2ses/trans.h491
-rw-r--r--private/os2/os2ses/util.c899
-rw-r--r--private/os2/os2ses/vio.h83
-rw-r--r--private/os2/os2ses/violvb.c770
-rw-r--r--private/os2/os2ses/vionls.c196
-rw-r--r--private/os2/os2ses/viorqust.c2809
-rw-r--r--private/os2/os2ses/viotty.c1538
-rw-r--r--private/os2/os2ss/makefile6
-rw-r--r--private/os2/os2ss/os2ss.c165
-rw-r--r--private/os2/os2ss/os2ss.rc52
-rw-r--r--private/os2/os2ss/sbcnfg.c1674
-rw-r--r--private/os2/os2ss/sbinit.c96
-rw-r--r--private/os2/os2ss/sbreqst.c181
-rw-r--r--private/os2/os2ss/sources68
-rw-r--r--private/os2/server/apiinit.c98
-rw-r--r--private/os2/server/apireqst.c754
-rw-r--r--private/os2/server/concreat.c343
-rw-r--r--private/os2/server/coninit.c166
-rw-r--r--private/os2/server/consignl.c348
-rw-r--r--private/os2/server/conthrds.c400
-rw-r--r--private/os2/server/makefile6
-rw-r--r--private/os2/server/os2srv.c256
-rw-r--r--private/os2/server/os2srv.rc90
-rw-r--r--private/os2/server/process.c813
-rw-r--r--private/os2/server/sources88
-rw-r--r--private/os2/server/srvcnfg.c2589
-rw-r--r--private/os2/server/srvdebug.c717
-rw-r--r--private/os2/server/srvevent.c180
-rw-r--r--private/os2/server/srvfile.c638
-rw-r--r--private/os2/server/srvinit.c736
-rw-r--r--private/os2/server/srvmutex.c159
-rw-r--r--private/os2/server/srvmuxwt.c613
-rw-r--r--private/os2/server/srvname.c820
-rw-r--r--private/os2/server/srvnet.c415
-rw-r--r--private/os2/server/srvnls.c1410
-rw-r--r--private/os2/server/srvobjmn.c338
-rw-r--r--private/os2/server/srvque.c1256
-rw-r--r--private/os2/server/srvsem.c260
-rw-r--r--private/os2/server/srvsm.c1091
-rw-r--r--private/os2/server/srvtask.c4982
-rw-r--r--private/os2/server/srvvm.c2775
-rw-r--r--private/os2/server/srvwin.c330
-rw-r--r--private/os2/server/srvxcpt.c1885
-rw-r--r--private/os2/server/wait.c187
-rw-r--r--private/os2/server/xtlexec.c256
-rw-r--r--private/os2/ssrtl/consys.c966
-rw-r--r--private/os2/ssrtl/datetime.c130
-rw-r--r--private/os2/ssrtl/i386/setjmp.asm157
-rw-r--r--private/os2/ssrtl/makefile6
-rw-r--r--private/os2/ssrtl/nls.c1136
-rw-r--r--private/os2/ssrtl/ntmap.c606
-rw-r--r--private/os2/ssrtl/qhandle.c314
-rw-r--r--private/os2/ssrtl/shandle.c498
-rw-r--r--private/os2/ssrtl/sources47
-rw-r--r--private/os2/ssrtl/sswinapi.c2265
432 files changed, 291528 insertions, 0 deletions
diff --git a/private/os2/client/apinums.h b/private/os2/client/apinums.h
new file mode 100644
index 000000000..eca6d531d
--- /dev/null
+++ b/private/os2/client/apinums.h
@@ -0,0 +1,439 @@
+
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1987-1991 **/
+/********************************************************************/
+
+#define API_WShareEnum 0
+#define API_WShareGetInfo 1
+#define API_WShareSetInfo 2
+#define API_WShareAdd 3
+#define API_WShareDel 4
+#define API_NetShareCheck 5
+#define API_WSessionEnum 6
+#define API_WSessionGetInfo 7
+#define API_WSessionDel 8
+#define API_WConnectionEnum 9
+#define API_WFileEnum 10
+#define API_WFileGetInfo 11
+#define API_WFileClose 12
+#define API_WServerGetInfo 13
+#define API_WServerSetInfo 14
+#define API_WServerDiskEnum 15
+#define API_WServerAdminCommand 16
+#define API_NetAuditOpen 17
+#define API_WAuditClear 18
+#define API_NetErrorLogOpen 19
+#define API_WErrorLogClear 20
+#define API_NetCharDevEnum 21
+#define API_NetCharDevGetInfo 22
+#define API_WCharDevControl 23
+#define API_NetCharDevQEnum 24
+#define API_NetCharDevQGetInfo 25
+#define API_WCharDevQSetInfo 26
+#define API_WCharDevQPurge 27
+#define API_WCharDevQPurgeSelf 28
+#define API_WMessageNameEnum 29
+#define API_WMessageNameGetInfo 30
+#define API_WMessageNameAdd 31
+#define API_WMessageNameDel 32
+#define API_WMessageNameFwd 33
+#define API_WMessageNameUnFwd 34
+#define API_WMessageBufferSend 35
+#define API_WMessageFileSend 36
+#define API_WMessageLogFileSet 37
+#define API_WMessageLogFileGet 38
+#define API_WServiceEnum 39
+#define API_WServiceInstall 40
+#define API_WServiceControl 41
+#define API_WAccessEnum 42
+#define API_WAccessGetInfo 43
+#define API_WAccessSetInfo 44
+#define API_WAccessAdd 45
+#define API_WAccessDel 46
+#define API_WGroupEnum 47
+#define API_WGroupAdd 48
+#define API_WGroupDel 49
+#define API_WGroupAddUser 50
+#define API_WGroupDelUser 51
+#define API_WGroupGetUsers 52
+#define API_WUserEnum 53
+#define API_WUserAdd 54
+#define API_WUserDel 55
+#define API_WUserGetInfo 56
+#define API_WUserSetInfo 57
+#define API_WUserPasswordSet 58
+#define API_WUserGetGroups 59
+#define API_DeadTableEntry 60
+/* This line and number replaced a Dead Entry */
+#define API_WWkstaSetUID 62
+#define API_WWkstaGetInfo 63
+#define API_WWkstaSetInfo 64
+#define API_WUseEnum 65
+#define API_WUseAdd 66
+#define API_WUseDel 67
+#define API_WUseGetInfo 68
+#define API_WPrintQEnum 69
+#define API_WPrintQGetInfo 70
+#define API_WPrintQSetInfo 71
+#define API_WPrintQAdd 72
+#define API_WPrintQDel 73
+#define API_WPrintQPause 74
+#define API_WPrintQContinue 75
+#define API_WPrintJobEnum 76
+#define API_WPrintJobGetInfo 77
+#define API_WPrintJobSetInfo_OLD 78
+/* This line and number replaced a Dead Entry */
+/* This line and number replaced a Dead Entry */
+#define API_WPrintJobDel 81
+#define API_WPrintJobPause 82
+#define API_WPrintJobContinue 83
+#define API_WPrintDestEnum 84
+#define API_WPrintDestGetInfo 85
+#define API_WPrintDestControl 86
+#define API_WProfileSave 87
+#define API_WProfileLoad 88
+#define API_WStatisticsGet 89
+#define API_WStatisticsClear 90
+#define API_NetRemoteTOD 91
+#define API_WNetBiosEnum 92
+#define API_WNetBiosGetInfo 93
+#define API_NetServerEnum 94
+#define API_I_NetServerEnum 95
+#define API_WServiceGetInfo 96
+/* This line and number replaced a Dead Entry */
+/* This line and number replaced a Dead Entry */
+/* This line and number replaced a Dead Entry */
+/* This line and number replaced a Dead Entry */
+/* This line and number replaced a Dead Entry */
+/* This line and number replaced a Dead Entry */
+#define API_WPrintQPurge 103
+#define API_NetServerEnum2 104
+#define API_WAccessGetUserPerms 105
+#define API_WGroupGetInfo 106
+#define API_WGroupSetInfo 107
+#define API_WGroupSetUsers 108
+#define API_WUserSetGroups 109
+#define API_WUserModalsGet 110
+#define API_WUserModalsSet 111
+#define API_WFileEnum2 112
+#define API_WUserAdd2 113
+#define API_WUserSetInfo2 114
+#define API_WUserPasswordSet2 115
+#define API_I_NetServerEnum2 116
+#define API_WConfigGet2 117
+#define API_WConfigGetAll2 118
+#define API_WGetDCName 119
+#define API_NetHandleGetInfo 120
+#define API_NetHandleSetInfo 121
+#define API_WStatisticsGet2 122
+#define API_WBuildGetInfo 123
+#define API_WFileGetInfo2 124
+#define API_WFileClose2 125
+#define API_WNetServerReqChallenge 126
+#define API_WNetServerAuthenticate 127
+#define API_WNetServerPasswordSet 128
+#define API_WNetAccountDeltas 129
+#define API_WNetAccountSync 130
+#define API_WUserEnum2 131
+#define API_WWkstaUserLogon 132
+#define API_WWkstaUserLogoff 133
+#define API_WLogonEnum 134
+#define API_WErrorLogRead 135
+#define API_WI_NetPathType 136
+#define API_WI_NetPathCanonicalize 137
+#define API_WI_NetPathCompare 138
+#define API_WI_NetNameValidate 139
+#define API_WI_NetNameCanonicalize 140
+#define API_WI_NetNameCompare 141
+#define API_WAuditRead 142
+#define API_WPrintDestAdd 143
+#define API_WPrintDestSetInfo 144
+#define API_WPrintDestDel 145
+#define API_WUserValidate2 146
+#define API_WPrintJobSetInfo 147
+#define API_TI_NetServerDiskEnum 148
+#define API_TI_NetServerDiskGetInfo 149
+#define API_TI_FTVerifyMirror 150
+#define API_TI_FTAbortVerify 151
+#define API_TI_FTGetInfo 152
+#define API_TI_FTSetInfo 153
+#define API_TI_FTLockDisk 154
+#define API_TI_FTFixError 155
+#define API_TI_FTAbortFix 156
+#define API_TI_FTDiagnoseError 157
+#define API_TI_FTGetDriveStats 158
+/* This line and number replaced a Dead Entry */
+#define API_TI_FTErrorGetInfo 160
+/* This line and number replaced a Dead Entry */
+/* This line and number replaced a Dead Entry */
+#define API_NetAccessCheck 163
+#define API_NetAlertRaise 164
+#define API_NetAlertStart 165
+#define API_NetAlertStop 166
+#define API_NetAuditWrite 167
+#define API_NetIRemoteAPI 168
+#define API_NetServiceStatus 169
+#define API_I_NetServerRegister 170
+#define API_I_NetServerDeregister 171
+#define API_I_NetSessionEntryMake 172
+#define API_I_NetSessionEntryClear 173
+#define API_I_NetSessionEntryGetInfo 174
+#define API_I_NetSessionEntrySetInfo 175
+#define API_I_NetConnectionEntryMake 176
+#define API_I_NetConnectionEntryClear 177
+#define API_I_NetConnectionEntrySetInfo 178
+#define API_I_NetConnectionEntryGetInfo 179
+#define API_I_NetFileEntryMake 180
+#define API_I_NetFileEntryClear 181
+#define API_I_NetFileEntrySetInfo 182
+#define API_I_NetFileEntryGetInfo 183
+#define API_AltSrvMessageBufferSend 184
+#define API_AltSrvMessageFileSend 185
+#define API_wI_NetRplWkstaEnum 186
+#define API_wI_NetRplWkstaGetInfo 187
+#define API_wI_NetRplWkstaSetInfo 188
+#define API_wI_NetRplWkstaAdd 189
+#define API_wI_NetRplWkstaDel 190
+#define API_wI_NetRplProfileEnum 191
+#define API_wI_NetRplProfileGetInfo 192
+#define API_wI_NetRplProfileSetInfo 193
+#define API_wI_NetRplProfileAdd 194
+#define API_wI_NetRplProfileDel 195
+#define API_wI_NetRplProfileClone 196
+#define API_wI_NetRplBaseProfileEnum 197
+/* This line and number replaced a Dead Entry */
+/* This line and number replaced a Dead Entry */
+/* This line and number replaced a Dead Entry */
+#define API_WIServerSetInfo 201
+/* This line and number replaced a Dead Entry */
+/* This line and number replaced a Dead Entry */
+/* This line and number replaced a Dead Entry */
+#define API_WPrintDriverEnum 205
+#define API_WPrintQProcessorEnum 206
+#define API_WPrintPortEnum 207
+#define API_WNetWriteUpdateLog 208
+#define API_WNetAccountUpdate 209
+#define API_WNetAccountConfirmUpdate 210
+#define API_WConfigSet 211
+#define API_WAccountsReplicate 212
+#define MAX_API 212
+
+#if DBG
+#ifdef APINAMES
+PSZ Os2NetAPIName [MAX_API+1] = {
+ "API_WShareEnum" ,// 0
+ "API_WShareGetInfo" ,// 1
+ "API_WShareSetInfo" ,// 2
+ "API_WShareAdd" ,// 3
+ "API_WShareDel" ,// 4
+ "API_NetShareCheck" ,// 5
+ "API_WSessionEnum" ,// 6
+ "API_WSessionGetInfo" ,// 7
+ "API_WSessionDel" ,// 8
+ "API_WConnectionEnum" ,// 9
+ "API_WFileEnum" ,// 10
+ "API_WFileGetInfo" ,// 11
+ "API_WFileClose" ,// 12
+ "API_WServerGetInfo" ,// 13
+ "API_WServerSetInfo" ,// 14
+ "API_WServerDiskEnum" ,// 15
+ "API_WServerAdminCommand" ,// 16
+ "API_NetAuditOpen" ,// 17
+ "API_WAuditClear" ,// 18
+ "API_NetErrorLogOpen" ,// 19
+ "API_WErrorLogClear" ,// 20
+ "API_NetCharDevEnum" ,// 21
+ "API_NetCharDevGetInfo" ,// 22
+ "API_WCharDevControl" ,// 23
+ "API_NetCharDevQEnum" ,// 24
+ "API_NetCharDevQGetInfo" ,// 25
+ "API_WCharDevQSetInfo" ,// 26
+ "API_WCharDevQPurge" ,// 27
+ "API_WCharDevQPurgeSelf" ,// 28
+ "API_WMessageNameEnum" ,// 29
+ "API_WMessageNameGetInfo" ,// 30
+ "API_WMessageNameAdd" ,// 31
+ "API_WMessageNameDel" ,// 32
+ "API_WMessageNameFwd" ,// 33
+ "API_WMessageNameUnFwd" ,// 34
+ "API_WMessageBufferSend" ,// 35
+ "API_WMessageFileSend" ,// 36
+ "API_WMessageLogFileSet" ,// 37
+ "API_WMessageLogFileGet" ,// 38
+ "API_WServiceEnum" ,// 39
+ "API_WServiceInstall" ,// 40
+ "API_WServiceControl" ,// 41
+ "API_WAccessEnum" ,// 42
+ "API_WAccessGetInfo" ,// 43
+ "API_WAccessSetInfo" ,// 44
+ "API_WAccessAdd" ,// 45
+ "API_WAccessDel" ,// 46
+ "API_WGroupEnum" ,// 47
+ "API_WGroupAdd" ,// 48
+ "API_WGroupDel" ,// 49
+ "API_WGroupAddUser" ,// 50
+ "API_WGroupDelUser" ,// 51
+ "API_WGroupGetUsers" ,// 52
+ "API_WUserEnum" ,// 53
+ "API_WUserAdd" ,// 54
+ "API_WUserDel" ,// 55
+ "API_WUserGetInfo" ,// 56
+ "API_WUserSetInfo" ,// 57
+ "API_WUserPasswordSet" ,// 58
+ "API_WUserGetGroups" ,// 59
+ "API_DeadTableEntry" ,// 60
+ "Dead Entry #61" ,// 61 This line and number replaced a Dead Entry
+ "API_WWkstaSetUID" ,// 62
+ "API_WWkstaGetInfo" ,// 63
+ "API_WWkstaSetInfo" ,// 64
+ "API_WUseEnum" ,// 65
+ "API_WUseAdd" ,// 66
+ "API_WUseDel" ,// 67
+ "API_WUseGetInfo" ,// 68
+ "API_WPrintQEnum" ,// 69
+ "API_WPrintQGetInfo" ,// 70
+ "API_WPrintQSetInfo" ,// 71
+ "API_WPrintQAdd" ,// 72
+ "API_WPrintQDel" ,// 73
+ "API_WPrintQPause" ,// 74
+ "API_WPrintQContinue" ,// 75
+ "API_WPrintJobEnum" ,// 76
+ "API_WPrintJobGetInfo" ,// 77
+ "API_WPrintJobSetInfo_OLD" ,// 78
+ "Dead Entry #79" ,// This line and number replaced a Dead Entry
+ "Dead Entry #80" ,// This line and number replaced a Dead Entry
+ "API_WPrintJobDel" ,// 81
+ "API_WPrintJobPause" ,// 82
+ "API_WPrintJobContinue" ,// 83
+ "API_WPrintDestEnum" ,// 84
+ "API_WPrintDestGetInfo" ,// 85
+ "API_WPrintDestControl" ,// 86
+ "API_WProfileSave" ,// 87
+ "API_WProfileLoad" ,// 88
+ "API_WStatisticsGet" ,// 89
+ "API_WStatisticsClear" ,// 90
+ "API_NetRemoteTOD" ,// 91
+ "API_WNetBiosEnum" ,// 92
+ "API_WNetBiosGetInfo" ,// 93
+ "API_NetServerEnum" ,// 94
+ "API_I_NetServerEnum" ,// 95
+ "API_WServiceGetInfo" ,// 96
+ "Dead Entry #97" ,// This line and number replaced a Dead Entry
+ "Dead Entry #98" ,// This line and number replaced a Dead Entry
+ "Dead Entry #99" ,// This line and number replaced a Dead Entry
+ "Dead Entry #100" ,// This line and number replaced a Dead Entry
+ "Dead Entry #101" ,// This line and number replaced a Dead Entry
+ "Dead Entry #102" ,// This line and number replaced a Dead Entry
+ "API_WPrintQPurge" ,// 103
+ "API_NetServerEnum2" ,// 104
+ "API_WAccessGetUserPerms" ,// 105
+ "API_WGroupGetInfo" ,// 106
+ "API_WGroupSetInfo" ,// 107
+ "API_WGroupSetUsers" ,// 108
+ "API_WUserSetGroups" ,// 109
+ "API_WUserModalsGet" ,// 110
+ "API_WUserModalsSet" ,// 111
+ "API_WFileEnum2" ,// 112
+ "API_WUserAdd2" ,// 113
+ "API_WUserSetInfo2" ,// 114
+ "API_WUserPasswordSet2" ,// 115
+ "API_I_NetServerEnum2" ,// 116
+ "API_WConfigGet2" ,// 117
+ "API_WConfigGetAll2" ,// 118
+ "API_WGetDCName" ,// 119
+ "API_NetHandleGetInfo" ,// 120
+ "API_NetHandleSetInfo" ,// 121
+ "API_WStatisticsGet2" ,// 122
+ "API_WBuildGetInfo" ,// 123
+ "API_WFileGetInfo2" ,// 124
+ "API_WFileClose2" ,// 125
+ "API_WNetServerReqChallenge" ,// 126
+ "API_WNetServerAuthenticate" ,// 127
+ "API_WNetServerPasswordSet" ,// 128
+ "API_WNetAccountDeltas" ,// 129
+ "API_WNetAccountSync" ,// 130
+ "API_WUserEnum2" ,// 131
+ "API_WWkstaUserLogon" ,// 132
+ "API_WWkstaUserLogoff" ,// 133
+ "API_WLogonEnum" ,// 134
+ "API_WErrorLogRead" ,// 135
+ "API_WI_NetPathType" ,// 136
+ "API_WI_NetPathCanonicalize" ,// 137
+ "API_WI_NetPathCompare" ,// 138
+ "API_WI_NetNameValidate" ,// 139
+ "API_WI_NetNameCanonicalize" ,// 140
+ "API_WI_NetNameCompare" ,// 141
+ "API_WAuditRead" ,// 142
+ "API_WPrintDestAdd" ,// 143
+ "API_WPrintDestSetInfo" ,// 144
+ "API_WPrintDestDel" ,// 145
+ "API_WUserValidate2" ,// 146
+ "API_WPrintJobSetInfo" ,// 147
+ "API_TI_NetServerDiskEnum" ,// 148
+ "API_TI_NetServerDiskGetInfo" ,// 149
+ "API_TI_FTVerifyMirror" ,// 150
+ "API_TI_FTAbortVerify" ,// 151
+ "API_TI_FTGetInfo" ,// 152
+ "API_TI_FTSetInfo" ,// 153
+ "API_TI_FTLockDisk" ,// 154
+ "API_TI_FTFixError" ,// 155
+ "API_TI_FTAbortFix" ,// 156
+ "API_TI_FTDiagnoseError" ,// 157
+ "API_TI_FTGetDriveStats" ,// 158
+ "Dead Entry #159" ,// This line and number replaced a Dead Entry
+ "API_TI_FTErrorGetInfo" ,// 160
+ "Dead Entry #161" ,// This line and number replaced a Dead Entry
+ "Dead Entry #162" ,// This line and number replaced a Dead Entry
+ "API_NetAccessCheck" ,// 163
+ "API_NetAlertRaise" ,// 164
+ "API_NetAlertStart" ,// 165
+ "API_NetAlertStop" ,// 166
+ "API_NetAuditWrite" ,// 167
+ "API_NetIRemoteAPI" ,// 168
+ "API_NetServiceStatus" ,// 169
+ "API_I_NetServerRegister" ,// 170
+ "API_I_NetServerDeregister" ,// 171
+ "API_I_NetSessionEntryMake" ,// 172
+ "API_I_NetSessionEntryClear" ,// 173
+ "API_I_NetSessionEntryGetInfo" ,// 174
+ "API_I_NetSessionEntrySetInfo" ,// 175
+ "API_I_NetConnectionEntryMake" ,// 176
+ "API_I_NetConnectionEntryClear" ,// 177
+ "API_I_NetConnectionEntrySetInfo" ,// 178
+ "API_I_NetConnectionEntryGetInfo" ,// 179
+ "API_I_NetFileEntryMake" ,// 180
+ "API_I_NetFileEntryClear" ,// 181
+ "API_I_NetFileEntrySetInfo" ,// 182
+ "API_I_NetFileEntryGetInfo" ,// 183
+ "API_AltSrvMessageBufferSend" ,// 184
+ "API_AltSrvMessageFileSend" ,// 185
+ "API_wI_NetRplWkstaEnum" ,// 186
+ "API_wI_NetRplWkstaGetInfo" ,// 187
+ "API_wI_NetRplWkstaSetInfo" ,// 188
+ "API_wI_NetRplWkstaAdd" ,// 189
+ "API_wI_NetRplWkstaDel" ,// 190
+ "API_wI_NetRplProfileEnum" ,// 191
+ "API_wI_NetRplProfileGetInfo" ,// 192
+ "API_wI_NetRplProfileSetInfo" ,// 193
+ "API_wI_NetRplProfileAdd" ,// 194
+ "API_wI_NetRplProfileDel" ,// 195
+ "API_wI_NetRplProfileClone" ,// 196
+ "API_wI_NetRplBaseProfileEnum" ,// 197
+ "Dead Entry #198" ,// This line and number replaced a Dead Entry
+ "Dead Entry #199" ,// This line and number replaced a Dead Entry
+ "Dead Entry #200" ,// This line and number replaced a Dead Entry
+ "API_WIServerSetInfo" ,// 201
+ "Dead Entry #202" ,// This line and number replaced a Dead Entry
+ "Dead Entry #203" ,// This line and number replaced a Dead Entry
+ "Dead Entry #204" ,// This line and number replaced a Dead Entry
+ "API_WPrintDriverEnum" ,// 205
+ "API_WPrintQProcessorEnum" ,// 206
+ "API_WPrintPortEnum" ,// 207
+ "API_WNetWriteUpdateLog" ,// 208
+ "API_WNetAccountUpdate" ,// 209
+ "API_WNetAccountConfirmUpdate" ,// 210
+ "API_WConfigSet" ,// 211
+ "API_WAccountsReplicate" }; // 212
+#endif
+#endif
diff --git a/private/os2/client/apiworke.h b/private/os2/client/apiworke.h
new file mode 100644
index 000000000..f5c85d24d
--- /dev/null
+++ b/private/os2/client/apiworke.h
@@ -0,0 +1,50 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1987-1992 **/
+/********************************************************************/
+
+/*++
+
+Revision History:
+
+ 16-Jan-1992 JohnRo
+ The redirector always expects UNICODE for the transact parm name.
+
+--*/
+
+#ifndef _APIWORKE_
+#define _APIWORKE_
+
+/*
+ * apiworke.h - General defines used by the API worker.
+ */
+
+#define REM_MAX_PARMS 360
+#define BUF_INC 200
+
+
+#define REM_NO_SRV_RESOURCE 55
+#define REM_NO_ADMIN_RIGHTS 44
+
+#define REM_API_TIMEOUT 5000 /* 5 second timeout */
+
+/* The REM_API_TXT is the text string that is copied into the parmater
+ * packet of the redirector transaction IOCTl following "\\SERVERNAME".
+ * The additional \0 is so that the password field is terminated.
+ * APIEXTR is the length of this field.
+ */
+#define REM_APITXT L"\\PIPE\\LANMAN\0"
+#define APIEXTR (sizeof(REM_APITXT))
+
+/* The pointer identifiers in the descriptor stings are all lower case so
+ * thet a quick check can be made for a pointer type. The IS_POINTER macro
+ * just checks for > 'Z' for maximum speed.
+ */
+
+#define IS_POINTER(x) ((x) > 'Z')
+
+
+#define RANGE_F(x,y,z) (((unsigned long)x >= (unsigned long)y) && \
+ ((unsigned long)x < ((unsigned long)y + z)))
+
+#endif // ndef _APIWORKE_
diff --git a/private/os2/client/coninit.c b/private/os2/client/coninit.c
new file mode 100644
index 000000000..b2d8f544f
--- /dev/null
+++ b/private/os2/client/coninit.c
@@ -0,0 +1,94 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ coninit.c
+
+Abstract:
+
+ This module initialize the connection with the session console port
+
+Author:
+
+ Avi Nathan (avin) 23-Jul-1991
+
+Revision History:
+
+
+--*/
+
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+
+#define NTOS2_ONLY
+#include "conrqust.h"
+
+extern PVOID Os2SessionCtrlDataBaseAddress;
+extern PVOID Os2SessionDataBaseAddress;
+extern PUCHAR LVBBuffer;
+extern HANDLE Ow2hSession;
+
+NTSTATUS
+Od2InitializeSessionPort(OUT PBOOLEAN RootProcessInSession)
+{
+
+ SesGrpId = (ULONG)Ow2hSession;
+
+ *RootProcessInSession = (BOOLEAN)SesGrp->FirstProcess;
+
+ if (SesGrp->FirstProcess)
+ {
+ SesGrp->FirstProcess = FALSE;
+
+ //RtlInitializeResource( (PRTL_RESOURCE)SesGrp->StdHandleLock );
+ }
+
+ MoniorOpenedForThisProcess = FALSE;
+
+ // BUGBUG! find cleanup code and close the port, or let exit cleanup
+
+ return( 0 );
+}
+
+
+APIRET
+OpenLVBsection()
+{
+ NTSTATUS Status;
+ SEL Sel;
+ I386DESCRIPTOR Desc;
+
+
+ //
+ // Set A Data segment selector in the LDT
+ //
+
+ Desc.BaseAddress = (ULONG)LVBBuffer;
+ Desc.Limit = SesGrp->MaxLVBsize-1;
+ Desc.Type = READ_WRITE_DATA;
+
+ //
+ // Apply tiling scheme
+ //
+ Sel = (SEL)FLATTOSEL((Desc.BaseAddress));
+ //
+ Status = Nt386SetDescriptorLDT (
+ NULL,
+ Sel,
+ Desc);
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint("OpenLVB: Can't Set LDT desc Error=%lx\n", Status);
+#endif
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ VioBuff = (PVOID)LVBBuffer;
+
+ return(NO_ERROR);
+}
+
diff --git a/private/os2/client/conrqust.c b/private/os2/client/conrqust.c
new file mode 100644
index 000000000..1cf50262c
--- /dev/null
+++ b/private/os2/client/conrqust.c
@@ -0,0 +1,449 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ conrqust.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 console API calls
+
+Author:
+
+ Avi Nathan (avin) 23-Jul-1991
+
+Revision History:
+
+
+--*/
+
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "conrqust.h"
+
+
+extern PVOID Os2SessionCtrlDataBaseAddress;
+extern HANDLE Od2StdHandleLockHandle;
+
+APIRET
+DosSleep(
+ IN ULONG MilliSeconds
+ );
+
+NTSTATUS
+Od2AlertableWaitForSingleObject(
+ IN HANDLE handle
+ );
+
+#if DBG
+PSZ Od2ExecPgmTable[] =
+{
+ "RemoveConsoleThread",
+ "RestartConsoleThread",
+ "AddWin32ChildProcess",
+ "RemWin32ChildProcess",
+ "UnKnown"
+};
+#endif
+
+APIRET
+Od2SendExecPgmRequest(
+ IN EXECREQUESTNUMBER RequestType
+ )
+{
+ SCREQUESTMSG Request;
+ NTSTATUS Status;
+
+#if DBG
+ IF_OD2_DEBUG( LPC )
+ {
+ DbgPrint( "Od2SendExecPgmRequest: send %s(%u) request\n",
+ (RequestType > 3) ? Od2ExecPgmTable[4] :
+ Od2ExecPgmTable[RequestType], RequestType
+ );
+ }
+#endif
+
+ Request.Request = WinCreateProcess;
+ Request.d.WinExecPgm.Request = RequestType;
+
+ //PORT_MSG_TOTAL_LENGTH(Request) = sizeof(SCREQUESTMSG);
+ //PORT_MSG_DATA_LENGTH(Request) = sizeof(SCREQUESTMSG) - sizeof(PORT_MESSAGE);
+ PORT_MSG_TOTAL_LENGTH(Request) = FIELD_OFFSET( SCREQUESTMSG, d) +
+ sizeof(WINEXECPGM_MSG);
+ PORT_MSG_DATA_LENGTH(Request) = FIELD_OFFSET( SCREQUESTMSG, d) +
+ sizeof(WINEXECPGM_MSG) - sizeof(PORT_MESSAGE);
+ PORT_MSG_ZERO_INIT(Request) = 0L;
+
+ Status = NtRequestWaitReplyPort( CtrlPortHandle,
+ (PPORT_MESSAGE) &Request,
+ (PPORT_MESSAGE) &Request);
+
+ if (!NT_SUCCESS(Status)){
+#if DBG
+ DbgPrint( "Od2SendExecPgmRequest(%u): failure at NtRequestReplyPort %lx\n",
+ RequestType, Status);
+#endif
+ return(Or2MapNtStatusToOs2Error(
+ Status,ERROR_ACCESS_DENIED));
+ }
+ return(Request.Status);
+}
+
+
+APIRET
+Od2RemoveConsoleThread()
+{
+ return(Od2SendExecPgmRequest(RemoveConsoleThread));
+}
+
+
+APIRET
+Od2RestartConsoleThread()
+{
+ return(Od2SendExecPgmRequest(RestartConsoleThread));
+}
+
+
+APIRET
+Od2AddWin32ChildProcess()
+{
+ return(Od2SendExecPgmRequest(AddWin32ChildProcess));
+}
+
+
+APIRET
+Od2RemoveWin32ChildProcess()
+{
+ return(Od2SendExecPgmRequest(RemWin32ChildProcess));
+}
+
+
+APIRET
+Od2CallRootProcessThruLPC(
+ IN OUT PSCREQUESTMSG Request,
+ IN PCH OutBuffer,
+ OUT PCH InBuffer,
+ IN HANDLE hSem,
+ IN ULONG ArgLength
+ )
+{
+ NTSTATUS NtStatus;
+ APIRET Status;
+ ULONG *pLeng, MaxLen;
+ PCH InPtr = (PCH)Os2SessionCtrlDataBaseAddress;
+
+ //PORT_MSG_TOTAL_LENGTH(*Request) = sizeof(SCREQUESTMSG);
+ //PORT_MSG_DATA_LENGTH(*Request) = sizeof(SCREQUESTMSG) - sizeof(PORT_MESSAGE);
+ PORT_MSG_TOTAL_LENGTH(*Request) = (CSHORT)(FIELD_OFFSET( SCREQUESTMSG, d) +
+ ArgLength);
+ PORT_MSG_DATA_LENGTH(*Request) = (CSHORT)(FIELD_OFFSET( SCREQUESTMSG, d) +
+ ArgLength - sizeof(PORT_MESSAGE));
+ PORT_MSG_ZERO_INIT(*Request) = 0L;
+
+#if DBG
+ IF_OD2_DEBUG2(OS2_EXE, LPC)
+ {
+ DbgPrint("SendCtrlConsoleRequest: Request %u:%u, In %p, Out %p, hSem %lx\n",
+ Request->Request, Request->d.Prt.Request, OutBuffer, InBuffer, hSem);
+ }
+#endif
+
+ if (hSem != NULL)
+ {
+ Status = Od2AlertableWaitForSingleObject(hSem);
+ if ( Status )
+ {
+ return(ERROR_VIO_INVALID_HANDLE); /* =>BUGBUG fix the error code */
+ }
+ }
+
+ if (Request->Request == KbdRequest || Request->Request == MouRequest ||
+ Request->Request == MonRequest || Request->Request == PrtRequest)
+ {
+ if ((InBuffer != NULL) || (OutBuffer != NULL))
+ {
+ MaxLen = OS2_CON_PORT_MSG_SIZE;
+ pLeng = &Request->d.Prt.d.Write.Length;
+
+ if ( Request->Request == KbdRequest )
+ {
+ pLeng = &Request->d.Kbd.Length;
+ MaxLen = OS2_KBD_PORT_MSG_SIZE;
+ InPtr += KBD_OFFSET;
+ }
+
+ if ( *pLeng > MaxLen )
+ {
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ DbgPrint("SendCtrlConsoleRequest: length 0x%lx too long\n",
+ *pLeng);
+#endif
+ *pLeng = MaxLen;
+ }
+
+ if (OutBuffer != NULL)
+ {
+ RtlMoveMemory(InPtr,
+ OutBuffer,
+ *pLeng);
+ }
+ }
+
+ NtStatus = NtRequestWaitReplyPort( CtrlPortHandle,
+ (PPORT_MESSAGE) Request,
+ (PPORT_MESSAGE) Request);
+
+ if ( !NT_SUCCESS( NtStatus ))
+ {
+#if DBG
+ DbgPrint( "OS2DLL: Unable to send CTRL request - Status == %X\n",
+ NtStatus);
+#endif
+
+ if (hSem != NULL)
+ {
+ NtReleaseMutant(hSem, NULL);
+ }
+
+ return(ERROR_VIO_INVALID_HANDLE); // =>BUGBUG fix the error code
+
+ }
+ ASSERT ( PORT_MSG_TYPE(*Request) == LPC_REPLY );
+
+ if ((InBuffer != NULL) && ! Request->Status )
+ {
+ RtlMoveMemory(InBuffer,
+ InPtr,
+ *pLeng);
+ }
+
+ } else
+ {
+#if DBG
+ DbgPrint ("SendCtrlConsoleRequest: illegal request %lu\n",
+ Request->Request);
+ return( ERROR_INVALID_PARAMETER );
+#endif
+ }
+
+ Status = Request->Status;
+
+ if (hSem != NULL)
+ {
+ NtReleaseMutant(hSem, NULL);
+ }
+
+ if ( Status == -2)
+ {
+ /*
+ * This call is from EventReleaseLPC
+ * terminate thread if not Thread1
+ */
+
+ if (Od2CurrentThreadId() != 1);
+ {
+ DosSleep((ULONG)-1);
+ }
+
+ Status = 0;
+ }
+
+ return( Status );
+}
+
+
+APIRET
+SendCtrlConsoleRequest(
+ IN OUT PSCREQUESTMSG Request,
+ IN PCH OutBuffer,
+ OUT PCH InBuffer,
+ IN HANDLE hSem
+ )
+{
+
+ return (Od2CallRootProcessThruLPC(
+ Request, OutBuffer, InBuffer, hSem, sizeof(Request->d)));
+}
+
+
+APIRET
+Od2LockCtrlRequestDataBuffer()
+{
+ APIRET Status;
+
+ Status = Od2WaitForSingleObject( CtrlDataSemaphore,
+ TRUE,
+ NULL);
+ if ( Status )
+ {
+ return(ERROR_VIO_INVALID_HANDLE); /* =>BUGBUG fix the error code */
+ }
+}
+
+
+VOID
+Od2UnlockCtrlRequestDataBuffer()
+{
+ NtReleaseSemaphore( CtrlDataSemaphore,
+ 1,
+ NULL);
+}
+
+#if DBG
+VOID
+AcquireStdHandleLock(
+ IN PSZ CallingRoutine
+ )
+{
+ PTEB Teb;
+
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ Teb = NtCurrentTeb();
+ DbgPrint("entering AcquireStdHandleLock for client id %ld%ld in %s\n",
+ Teb->ClientId.UniqueProcess,
+ Teb->ClientId.UniqueThread,
+ CallingRoutine);
+ Od2WaitForSingleObject( Od2StdHandleLockHandle, TRUE, NULL );
+ DbgPrint("leaving AcquireStdHandleLock for client id %ld%ld in %s\n",
+ Teb->ClientId.UniqueProcess,
+ Teb->ClientId.UniqueThread,
+ CallingRoutine);
+ } else
+ {
+ Od2WaitForSingleObject( Od2StdHandleLockHandle, TRUE, NULL );
+ }
+}
+
+
+VOID
+ReleaseStdHandleLock(
+ IN PSZ CallingRoutine
+ )
+{
+ PTEB Teb;
+
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ Teb = NtCurrentTeb();
+ DbgPrint("entering ReleaseStdHandleLock for client id %ld%ld in %s\n",
+ Teb->ClientId.UniqueProcess,
+ Teb->ClientId.UniqueThread,
+ CallingRoutine);
+ NtReleaseSemaphore( Od2StdHandleLockHandle, 1, NULL);
+ DbgPrint("leaving ReleaseStdHandleLock for client id %ld%ld in %s\n",
+ Teb->ClientId.UniqueProcess,
+ Teb->ClientId.UniqueThread,
+ CallingRoutine);
+ } else
+ {
+ NtReleaseSemaphore( Od2StdHandleLockHandle, 1, NULL);
+ }
+}
+#else
+VOID
+AcquireStdHandleLock()
+{
+ Od2WaitForSingleObject( Od2StdHandleLockHandle, TRUE, NULL );
+}
+
+
+VOID
+ReleaseStdHandleLock()
+{
+ NtReleaseSemaphore( Od2StdHandleLockHandle, 1, NULL);
+}
+#endif
+
+
+APIRET
+KbdDupLogHandle(
+ IN HANDLE hKbd
+ )
+{
+ SCREQUESTMSG Request;
+ NTSTATUS Status;
+#if DBG
+ PSZ RoutineName;
+
+ RoutineName = "KbdDupLogHandle";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering\n", RoutineName);
+ }
+#endif
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.Request = KbdRequest;
+ Request.d.Kbd.Request = KBDDupLogHandle;
+ Request.d.Kbd.hKbd = hKbd;
+ Status = SendCtrlConsoleRequest(&Request,
+ NULL,
+ NULL,
+ NULL);
+
+ /*
+ * handle return status (free handle if failed, validate if successed)
+ */
+
+ if ( Status )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", RoutineName, Status);
+#endif
+ return(Status);
+ }
+
+ return NO_ERROR;
+}
+
+
+APIRET
+Od2WaitForSingleObject(
+ IN HANDLE Semaphore,
+ IN BOOLEAN Alertable,
+ IN PLARGE_INTEGER TimeOut OPTIONAL
+ )
+{
+ NTSTATUS NtStatus;
+ LARGE_INTEGER StartTimeStamp;
+
+ do {
+ if (TimeOut) {
+ Od2StartTimeout(&StartTimeStamp);
+ }
+ NtStatus = NtWaitForSingleObject(Semaphore,
+ Alertable,
+ TimeOut);
+#if DBG
+ if (NtStatus == STATUS_USER_APC) {
+ DbgPrint("[%d,%d] WARNING !!! Od2WaitForSingleObject was broken by APC\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ );
+ }
+#endif
+ } while (NtStatus == STATUS_USER_APC &&
+ (NtStatus = Od2ContinueTimeout(&StartTimeStamp, TimeOut)) == STATUS_SUCCESS
+ );
+
+ if (( !NT_SUCCESS(NtStatus) ) ||
+ (NtStatus == STATUS_TIMEOUT) ||
+ (NtStatus == STATUS_ABANDONED) ||
+ (NtStatus == STATUS_ALERTED))
+ {
+ return ERROR_SEM_TIMEOUT;
+ }
+
+ return NO_ERROR;
+}
+
diff --git a/private/os2/client/crypt.h b/private/os2/client/crypt.h
new file mode 100644
index 000000000..298a248e5
--- /dev/null
+++ b/private/os2/client/crypt.h
@@ -0,0 +1,579 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ crypt.h
+
+Abstract:
+
+ This module contains the public data structures and API definitions
+ needed to utilize the encryption library
+
+
+Author:
+
+ David Chalmers (Davidc) 21-October-1991
+
+Revision History:
+
+--*/
+
+#ifndef _NTCRYPT_
+#define _NTCRYPT_
+
+#ifndef MIDL_PASS // Don't confuse MIDL
+
+#ifndef RPC_NO_WINDOWS_H // Don't let rpc.h include windows.h
+#define RPC_NO_WINDOWS_H
+#endif // RPC_NO_WINDOWS_H
+
+#include <rpc.h>
+#endif // MIDL_PASS
+
+
+/////////////////////////////////////////////////////////////////////////
+// //
+// Core encryption types //
+// //
+/////////////////////////////////////////////////////////////////////////
+
+
+#define CLEAR_BLOCK_LENGTH 8
+
+typedef struct _CLEAR_BLOCK {
+ CHAR data[CLEAR_BLOCK_LENGTH];
+} CLEAR_BLOCK;
+typedef CLEAR_BLOCK * PCLEAR_BLOCK;
+
+
+#define CYPHER_BLOCK_LENGTH 8
+
+typedef struct _CYPHER_BLOCK {
+ CHAR data[CYPHER_BLOCK_LENGTH];
+} CYPHER_BLOCK;
+typedef CYPHER_BLOCK * PCYPHER_BLOCK;
+
+
+#define BLOCK_KEY_LENGTH 7
+
+typedef struct _BLOCK_KEY {
+ CHAR data[BLOCK_KEY_LENGTH];
+} BLOCK_KEY;
+typedef BLOCK_KEY * PBLOCK_KEY;
+
+
+
+
+/////////////////////////////////////////////////////////////////////////
+// //
+// Arbitrary length data encryption types //
+// //
+/////////////////////////////////////////////////////////////////////////
+
+typedef struct _CRYPT_BUFFER {
+ ULONG Length; // Number of valid bytes in buffer
+ ULONG MaximumLength; // Number of bytes pointed to by Buffer
+ PVOID Buffer;
+} CRYPT_BUFFER;
+typedef CRYPT_BUFFER * PCRYPT_BUFFER;
+
+typedef CRYPT_BUFFER CLEAR_DATA;
+typedef CLEAR_DATA * PCLEAR_DATA;
+
+typedef CRYPT_BUFFER DATA_KEY;
+typedef DATA_KEY * PDATA_KEY;
+
+typedef CRYPT_BUFFER CYPHER_DATA;
+typedef CYPHER_DATA * PCYPHER_DATA;
+
+
+
+/////////////////////////////////////////////////////////////////////////
+// //
+// Lan Manager data types //
+// //
+/////////////////////////////////////////////////////////////////////////
+
+
+//
+// Define a LanManager compatible password
+//
+// A LanManager password is a null-terminated ansi string consisting of a
+// maximum of 14 characters (not including terminator)
+//
+
+typedef CHAR * PLM_PASSWORD;
+
+
+
+//
+// Define the result of the 'One Way Function' (OWF) on a LM password
+//
+
+#define LM_OWF_PASSWORD_LENGTH (CYPHER_BLOCK_LENGTH * 2)
+
+typedef struct _LM_OWF_PASSWORD {
+ CYPHER_BLOCK data[2];
+} LM_OWF_PASSWORD;
+typedef LM_OWF_PASSWORD * PLM_OWF_PASSWORD;
+
+
+
+//
+// Define the challenge sent by the Lanman server during logon
+//
+
+#define LM_CHALLENGE_LENGTH CLEAR_BLOCK_LENGTH
+
+typedef CLEAR_BLOCK LM_CHALLENGE;
+typedef LM_CHALLENGE * PLM_CHALLENGE;
+
+
+
+//
+// Define the response sent by redirector in response to challenge from server
+//
+
+#define LM_RESPONSE_LENGTH (CYPHER_BLOCK_LENGTH * 3)
+
+typedef struct _LM_RESPONSE {
+ CYPHER_BLOCK data[3];
+} LM_RESPONSE;
+typedef LM_RESPONSE * PLM_RESPONSE;
+
+
+
+//
+// Define the result of the reversible encryption of an OWF'ed password.
+//
+
+#define ENCRYPTED_LM_OWF_PASSWORD_LENGTH (CYPHER_BLOCK_LENGTH * 2)
+
+typedef struct _ENCRYPTED_LM_OWF_PASSWORD {
+ CYPHER_BLOCK data[2];
+} ENCRYPTED_LM_OWF_PASSWORD;
+typedef ENCRYPTED_LM_OWF_PASSWORD * PENCRYPTED_LM_OWF_PASSWORD;
+
+
+
+//
+// Define the session key maintained by the redirector and server
+//
+
+#define LM_SESSION_KEY_LENGTH LM_CHALLENGE_LENGTH
+
+typedef LM_CHALLENGE LM_SESSION_KEY;
+typedef LM_SESSION_KEY * PLM_SESSION_KEY;
+
+
+
+//
+// Define the index type used to encrypt OWF Passwords
+//
+
+typedef LONG CRYPT_INDEX;
+typedef CRYPT_INDEX * PCRYPT_INDEX;
+
+
+
+/////////////////////////////////////////////////////////////////////////
+// //
+// 'NT' encryption types that are used to duplicate existing LM //
+// functionality with improved algorithms. //
+// //
+/////////////////////////////////////////////////////////////////////////
+
+
+typedef UNICODE_STRING NT_PASSWORD;
+typedef NT_PASSWORD * PNT_PASSWORD;
+
+
+#define NT_OWF_PASSWORD_LENGTH LM_OWF_PASSWORD_LENGTH
+
+typedef LM_OWF_PASSWORD NT_OWF_PASSWORD;
+typedef NT_OWF_PASSWORD * PNT_OWF_PASSWORD;
+
+
+#define NT_CHALLENGE_LENGTH LM_CHALLENGE_LENGTH
+
+typedef LM_CHALLENGE NT_CHALLENGE;
+typedef NT_CHALLENGE * PNT_CHALLENGE;
+
+
+#define NT_RESPONSE_LENGTH LM_RESPONSE_LENGTH
+
+typedef LM_RESPONSE NT_RESPONSE;
+typedef NT_RESPONSE * PNT_RESPONSE;
+
+
+#define ENCRYPTED_NT_OWF_PASSWORD_LENGTH ENCRYPTED_LM_OWF_PASSWORD_LENGTH
+
+typedef ENCRYPTED_LM_OWF_PASSWORD ENCRYPTED_NT_OWF_PASSWORD;
+typedef ENCRYPTED_NT_OWF_PASSWORD * PENCRYPTED_NT_OWF_PASSWORD;
+
+
+#define NT_SESSION_KEY_LENGTH LM_SESSION_KEY_LENGTH
+
+typedef LM_SESSION_KEY NT_SESSION_KEY;
+typedef NT_SESSION_KEY * PNT_SESSION_KEY;
+
+
+
+/////////////////////////////////////////////////////////////////////////
+// //
+// 'NT' encryption types for new functionality not present in LM //
+// //
+/////////////////////////////////////////////////////////////////////////
+
+
+//
+// The user session key is similar to the LM and NT session key except it
+// is different for each user on the system. This allows it to be used
+// for secure user communication with a server.
+//
+#define USER_SESSION_KEY_LENGTH (CYPHER_BLOCK_LENGTH * 2)
+
+typedef struct _USER_SESSION_KEY {
+ CYPHER_BLOCK data[2];
+} USER_SESSION_KEY;
+typedef USER_SESSION_KEY * PUSER_SESSION_KEY;
+
+
+
+////////////////////////////////////////////////////////////////////////////
+// //
+// Encryption library API macros //
+// //
+// To conceal the purpose of these functions to someone dumping out the //
+// encryption dll they have been purposefully given unhelpful names. //
+// Each has an associated macro that should be used by system components //
+// to access these routines in a readable way. //
+// //
+////////////////////////////////////////////////////////////////////////////
+
+#define RtlEncryptBlock SystemFunction001
+#define RtlDecryptBlock SystemFunction002
+#define RtlEncryptStdBlock SystemFunction003
+#define RtlEncryptData SystemFunction004
+#define RtlDecryptData SystemFunction005
+#define RtlCalculateLmOwfPassword SystemFunction006
+#define RtlCalculateNtOwfPassword SystemFunction007
+#define RtlCalculateLmResponse SystemFunction008
+#define RtlCalculateNtResponse SystemFunction009
+#define RtlCalculateUserSessionKeyLm SystemFunction010
+#define RtlCalculateUserSessionKeyNt SystemFunction011
+#define RtlEncryptLmOwfPwdWithLmOwfPwd SystemFunction012
+#define RtlDecryptLmOwfPwdWithLmOwfPwd SystemFunction013
+#define RtlEncryptNtOwfPwdWithNtOwfPwd SystemFunction014
+#define RtlDecryptNtOwfPwdWithNtOwfPwd SystemFunction015
+#define RtlEncryptLmOwfPwdWithLmSesKey SystemFunction016
+#define RtlDecryptLmOwfPwdWithLmSesKey SystemFunction017
+#define RtlEncryptNtOwfPwdWithNtSesKey SystemFunction018
+#define RtlDecryptNtOwfPwdWithNtSesKey SystemFunction019
+#define RtlEncryptLmOwfPwdWithUserKey SystemFunction020
+#define RtlDecryptLmOwfPwdWithUserKey SystemFunction021
+#define RtlEncryptNtOwfPwdWithUserKey SystemFunction022
+#define RtlDecryptNtOwfPwdWithUserKey SystemFunction023
+#define RtlEncryptLmOwfPwdWithIndex SystemFunction024
+#define RtlDecryptLmOwfPwdWithIndex SystemFunction025
+#define RtlEncryptNtOwfPwdWithIndex SystemFunction026
+#define RtlDecryptNtOwfPwdWithIndex SystemFunction027
+#define RtlGetUserSessionKeyClient SystemFunction028
+#define RtlGetUserSessionKeyServer SystemFunction029
+#define RtlEqualLmOwfPassword SystemFunction030
+#define RtlEqualNtOwfPassword SystemFunction031
+
+
+////////////////////////////////////////////////////////////////////////////
+// //
+// Encryption library API function prototypes //
+// //
+////////////////////////////////////////////////////////////////////////////
+
+
+//
+// Core block encryption functions
+//
+
+NTSTATUS
+RtlEncryptBlock(
+ IN PCLEAR_BLOCK ClearBlock,
+ IN PBLOCK_KEY BlockKey,
+ OUT PCYPHER_BLOCK CypherBlock
+ );
+
+NTSTATUS
+RtlDecryptBlock(
+ IN PCYPHER_BLOCK CypherBlock,
+ IN PBLOCK_KEY BlockKey,
+ OUT PCLEAR_BLOCK ClearBlock
+ );
+
+NTSTATUS
+RtlEncryptStdBlock(
+ IN PBLOCK_KEY BlockKey,
+ OUT PCYPHER_BLOCK CypherBlock
+ );
+
+//
+// Arbitrary length data encryption functions
+//
+
+NTSTATUS
+RtlEncryptData(
+ IN PCLEAR_DATA ClearData,
+ IN PDATA_KEY DataKey,
+ OUT PCYPHER_DATA CypherData
+ );
+
+NTSTATUS
+RtlDecryptData(
+ IN PCYPHER_DATA CypherData,
+ IN PDATA_KEY DataKey,
+ OUT PCLEAR_DATA ClearData
+ );
+
+//
+// Password hashing functions (One Way Function)
+//
+
+NTSTATUS
+RtlCalculateLmOwfPassword(
+ IN PLM_PASSWORD LmPassword,
+ OUT PLM_OWF_PASSWORD LmOwfPassword
+ );
+
+NTSTATUS
+RtlCalculateNtOwfPassword(
+ IN PNT_PASSWORD NtPassword,
+ OUT PNT_OWF_PASSWORD NtOwfPassword
+ );
+
+
+
+//
+// OWF password comparison functions
+//
+
+BOOLEAN
+RtlEqualLmOwfPassword(
+ IN PLM_OWF_PASSWORD LmOwfPassword1,
+ IN PLM_OWF_PASSWORD LmOwfPassword2
+ );
+
+BOOLEAN
+RtlEqualNtOwfPassword(
+ IN PNT_OWF_PASSWORD NtOwfPassword1,
+ IN PNT_OWF_PASSWORD NtOwfPassword2
+ );
+
+
+
+//
+// Functions for calculating response to server challenge
+//
+
+NTSTATUS
+RtlCalculateLmResponse(
+ IN PLM_CHALLENGE LmChallenge,
+ IN PLM_OWF_PASSWORD LmOwfPassword,
+ OUT PLM_RESPONSE LmResponse
+ );
+
+
+NTSTATUS
+RtlCalculateNtResponse(
+ IN PNT_CHALLENGE NtChallenge,
+ IN PNT_OWF_PASSWORD NtOwfPassword,
+ OUT PNT_RESPONSE NtResponse
+ );
+
+
+
+
+//
+// Functions for calculating User Session Key.
+//
+
+//
+// Calculate a User Session Key from LM data
+//
+NTSTATUS
+RtlCalculateUserSessionKeyLm(
+ IN PLM_RESPONSE LmResponse,
+ IN PLM_OWF_PASSWORD LmOwfPassword,
+ OUT PUSER_SESSION_KEY UserSessionKey
+ );
+
+//
+// Calculate a User Session Key from NT data
+//
+NTSTATUS
+RtlCalculateUserSessionKeyNt(
+ IN PNT_RESPONSE NtResponse,
+ IN PNT_OWF_PASSWORD NtOwfPassword,
+ OUT PUSER_SESSION_KEY UserSessionKey
+ );
+
+
+
+
+
+//
+// OwfPassword encryption functions
+//
+
+
+//
+// Encrypt OwfPassword using OwfPassword as the key
+//
+NTSTATUS
+RtlEncryptLmOwfPwdWithLmOwfPwd(
+ IN PLM_OWF_PASSWORD DataLmOwfPassword,
+ IN PLM_OWF_PASSWORD KeyLmOwfPassword,
+ OUT PENCRYPTED_LM_OWF_PASSWORD EncryptedLmOwfPassword
+ );
+
+NTSTATUS
+RtlDecryptLmOwfPwdWithLmOwfPwd(
+ IN PENCRYPTED_LM_OWF_PASSWORD EncryptedLmOwfPassword,
+ IN PLM_OWF_PASSWORD KeyLmOwfPassword,
+ OUT PLM_OWF_PASSWORD DataLmOwfPassword
+ );
+
+
+NTSTATUS
+RtlEncryptNtOwfPwdWithNtOwfPwd(
+ IN PNT_OWF_PASSWORD DataNtOwfPassword,
+ IN PNT_OWF_PASSWORD KeyNtOwfPassword,
+ OUT PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword
+ );
+
+NTSTATUS
+RtlDecryptNtOwfPwdWithNtOwfPwd(
+ IN PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword,
+ IN PNT_OWF_PASSWORD KeyNtOwfPassword,
+ OUT PNT_OWF_PASSWORD DataNtOwfPassword
+ );
+
+
+//
+// Encrypt OwfPassword using SessionKey as the key
+//
+NTSTATUS
+RtlEncryptLmOwfPwdWithLmSesKey(
+ IN PLM_OWF_PASSWORD LmOwfPassword,
+ IN PLM_SESSION_KEY LmSessionKey,
+ OUT PENCRYPTED_LM_OWF_PASSWORD EncryptedLmOwfPassword
+ );
+
+NTSTATUS
+RtlDecryptLmOwfPwdWithLmSesKey(
+ IN PENCRYPTED_LM_OWF_PASSWORD EncryptedLmOwfPassword,
+ IN PLM_SESSION_KEY LmSessionKey,
+ OUT PLM_OWF_PASSWORD LmOwfPassword
+ );
+
+
+NTSTATUS
+RtlEncryptNtOwfPwdWithNtSesKey(
+ IN PNT_OWF_PASSWORD NtOwfPassword,
+ IN PNT_SESSION_KEY NtSessionKey,
+ OUT PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword
+ );
+
+NTSTATUS
+RtlDecryptNtOwfPwdWithNtSesKey(
+ IN PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword,
+ IN PNT_SESSION_KEY NtSessionKey,
+ OUT PNT_OWF_PASSWORD NtOwfPassword
+ );
+
+
+//
+// Encrypt OwfPassword using UserSessionKey as the key
+//
+NTSTATUS
+RtlEncryptLmOwfPwdWithUserKey(
+ IN PLM_OWF_PASSWORD LmOwfPassword,
+ IN PUSER_SESSION_KEY UserSessionKey,
+ OUT PENCRYPTED_LM_OWF_PASSWORD EncryptedLmOwfPassword
+ );
+
+NTSTATUS
+RtlDecryptLmOwfPwdWithUserKey(
+ IN PENCRYPTED_LM_OWF_PASSWORD EncryptedLmOwfPassword,
+ IN PUSER_SESSION_KEY UserSessionKey,
+ OUT PLM_OWF_PASSWORD LmOwfPassword
+ );
+
+NTSTATUS
+RtlEncryptNtOwfPwdWithUserKey(
+ IN PNT_OWF_PASSWORD NtOwfPassword,
+ IN PUSER_SESSION_KEY UserSessionKey,
+ OUT PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword
+ );
+
+NTSTATUS
+RtlDecryptNtOwfPwdWithUserKey(
+ IN PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword,
+ IN PUSER_SESSION_KEY UserSessionKey,
+ OUT PNT_OWF_PASSWORD NtOwfPassword
+ );
+
+
+//
+// Encrypt OwfPassword using an index as the key
+//
+NTSTATUS
+RtlEncryptLmOwfPwdWithIndex(
+ IN PLM_OWF_PASSWORD LmOwfPassword,
+ IN PCRYPT_INDEX Index,
+ OUT PENCRYPTED_LM_OWF_PASSWORD EncryptedLmOwfPassword
+ );
+
+NTSTATUS
+RtlDecryptLmOwfPwdWithIndex(
+ IN PENCRYPTED_LM_OWF_PASSWORD EncryptedLmOwfPassword,
+ IN PCRYPT_INDEX Index,
+ OUT PLM_OWF_PASSWORD LmOwfPassword
+ );
+
+
+NTSTATUS
+RtlEncryptNtOwfPwdWithIndex(
+ IN PNT_OWF_PASSWORD NtOwfPassword,
+ IN PCRYPT_INDEX Index,
+ OUT PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword
+ );
+
+NTSTATUS
+RtlDecryptNtOwfPwdWithIndex(
+ IN PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword,
+ IN PCRYPT_INDEX Index,
+ OUT PNT_OWF_PASSWORD NtOwfPassword
+ );
+
+
+//
+// Get the user session key for an RPC connection
+//
+
+#ifndef MIDL_PASS // Don't confuse MIDL
+NTSTATUS
+RtlGetUserSessionKeyClient(
+ IN PVOID RpcContextHandle OPTIONAL,
+ OUT PUSER_SESSION_KEY UserSessionKey
+ );
+
+NTSTATUS
+RtlGetUserSessionKeyServer(
+ IN PVOID RpcContextHandle OPTIONAL,
+ OUT PUSER_SESSION_KEY UserSessionKey
+ );
+#endif // MIDL_PASS
+
+#endif // _NTCRYPT_
+
diff --git a/private/os2/client/dllcnfg.c b/private/os2/client/dllcnfg.c
new file mode 100644
index 000000000..c8b1c92df
--- /dev/null
+++ b/private/os2/client/dllcnfg.c
@@ -0,0 +1,228 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllcnfg.c
+
+Abstract:
+
+ This module contains the code related to the processing of
+ CONFIG.SYS in the client.
+
+Author:
+
+ Ofer Porat (oferp) 4-Jan-1993
+
+Environment:
+
+ User Mode only
+
+Revision History:
+
+ This code was originally in dllinit.c.
+
+--*/
+
+#define INCL_OS2V20_ALL
+#include "os2dll.h"
+#include "os2win.h"
+
+
+static BOOLEAN Od2ConfigDotSysCreated = FALSE;
+static ULONG Od2ConfigSysAllowedAccess;
+
+static CHAR Od2CanonicalDiskConfigDotSys[] = "\\OS2SS\\DRIVES\\C:\\CONFIG.SYS";
+static CHAR Od2CanonicalConfigDotSys[MAX_PATH] = "\\OS2SS\\DRIVES\\";
+
+VOID
+Ow2ConfigSysPopup(
+ VOID
+ );
+
+BOOLEAN
+Od2FileIsConfigSys(
+ IN OUT PANSI_STRING FileName_A,
+ IN ULONG AccessMode,
+ OUT PNTSTATUS ResultStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks to see if the user wants to access the config.sys file. If so,
+ a message is sent to the server requesting creation of this file. If the file is
+ created, the file name is changed to the internal name of os2conf.nt. Some
+ bookkeeping information about the usage of config.sys is also kept internally.
+ The request to the server is sent only once for the entire process. Additional
+ requests for access to config.sys will simply modify the name, since the file
+ already exists. A popup is generated if the user requests READWRITE access
+ when he doesn't have the privilege. Internal info is kept on what kind of
+ access to config.sys is allowed, so additional calls can be processed without
+ further messages to the server.
+
+ Revision (2/10/93):
+ if CLIENT_POPUP_ON_READ is true (defined in inc\os2ssrtl.h) then we also
+ generate a popup on read access requests, so the user knows he can't write.
+ this is in case the editor doesn't inform him that he can't write.
+
+Arguments:
+
+ FileName_A -- supplies the name of the user's file. If this is C:\CONFIG.SYS, and
+ the file is successfully created, the name will be modified to the name
+ of os2config.nt (= <systemdir>\os2\os2conf.nt).
+
+ AccessMode -- the desired access to the file. either OPEN_ACCESS_READONLY or
+ OPEN_ACCESS_READWRITE. If the desired access can't be granted,
+ ResultStatus will be STATUS_ACCESS_DENIED, and the file won't be created.
+
+ ResultStatus -- returns an NT error code that may describe many errors possible
+ during the creation attempt.
+
+Return Value:
+
+ FALSE -- FileName_A is not "C:\CONFIG.SYS". The name is not modified and ResultStatus
+ is STATUS_OBJECT_TYPE_MISMATCH.
+
+ TRUE -- FileName_A is "C:\CONFIG.SYS". ResultStatus indicates if the operation was
+ successful. If it was, the name is modified to that of os2conf.nt.
+
+--*/
+
+{
+ OS2_API_MSG m;
+ POS2_CONFIGSYS_MSG a = &m.u.CreateConfigSysRequest;
+ NTSTATUS Status;
+ ULONG StringLen;
+ PSZ NameBuffer;
+
+ if (_stricmp(FileName_A->Buffer, Od2CanonicalDiskConfigDotSys) != 0) {
+ *ResultStatus = STATUS_OBJECT_TYPE_MISMATCH;
+ return(FALSE);
+ }
+
+ //
+ // Special handling of c:\config.sys
+ // opening this file is mapped to the OS/2 SS config.sys
+ //
+
+ //
+ // Check the parameter
+ //
+
+ if (AccessMode != OPEN_ACCESS_READONLY &&
+ AccessMode != OPEN_ACCESS_READWRITE) {
+ *ResultStatus = STATUS_INVALID_PARAMETER;
+ return(TRUE);
+ }
+
+ if (!Od2ConfigDotSysCreated) {
+ do { // A 1-time loop to allow break upon error
+
+#if OS2CONF_NAME_OPT
+ if (GetSystemDirectoryA(Od2CanonicalConfigDotSys + FILE_PREFIX_LENGTH, MAX_PATH) == 0) {
+#if DBG
+ IF_OD2_DEBUG(MISC) {
+ KdPrint(("Od2FileIsConfigSys: Cannot obtain name of system directory\n"));
+ }
+#endif
+ Status = STATUS_UNEXPECTED_IO_ERROR;
+ break;
+ }
+#else
+ strcpy(Od2CanonicalConfigDotSys + FILE_PREFIX_LENGTH, "C:");
+#endif
+
+ strcat(Od2CanonicalConfigDotSys, OS2CONF_NAMEA);
+
+ //
+ // Now call the server to do the work
+ //
+
+ a->RequiredAccess = AccessMode;
+
+ Od2CallSubsystem(&m, NULL, Os2CreateConfigSys, sizeof(*a));
+
+ Od2ConfigSysAllowedAccess = a->AllowedAccess;
+ Status = a->ReturnStatus;
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG(MISC) {
+ KdPrint(("Od2FileIsConfigSys: server os2conf.nt creator failed, Status = %lx\n", Status));
+ }
+#endif
+ if (Status == STATUS_ACCESS_DENIED &&
+ AccessMode == OPEN_ACCESS_READWRITE &&
+ Od2ConfigSysAllowedAccess == OPEN_ACCESS_READONLY) {
+
+ Ow2ConfigSysPopup();
+ }
+
+ break;
+ }
+
+#if CLIENT_POPUP_ON_READ
+ if (Od2ConfigSysAllowedAccess == OPEN_ACCESS_READONLY) {
+ Ow2ConfigSysPopup();
+ }
+#endif
+ Od2ConfigDotSysCreated = TRUE;
+
+ } while (FALSE);
+
+ if (!NT_SUCCESS(Status)) {
+ *ResultStatus = Status;
+ return(TRUE);
+ }
+
+ } else {
+ if (Od2ConfigSysAllowedAccess == OPEN_ACCESS_READONLY) {
+#if CLIENT_POPUP_ON_READ
+ Ow2ConfigSysPopup();
+#endif
+ if (AccessMode == OPEN_ACCESS_READWRITE) {
+#if !CLIENT_POPUP_ON_READ
+ Ow2ConfigSysPopup();
+#endif
+#if DBG
+ IF_OD2_DEBUG(MISC) {
+ KdPrint(("Od2FileIsConfigSys: denying write access to os2conf.nt\n"));
+ }
+#endif
+ *ResultStatus = STATUS_ACCESS_DENIED;
+ return(TRUE);
+ }
+ }
+ }
+
+ //
+ // We now replace the file name with our own file name.
+ // We assume that the name is on Od2Heap. This is fine since
+ // that's where Od2Canonicalize gets it from. We allocate a new
+ // buffer from the same heap.
+ //
+
+ StringLen = strlen(Od2CanonicalConfigDotSys) + 1;
+ NameBuffer = (PSZ)RtlAllocateHeap(Od2Heap, 0, StringLen);
+
+ if (NameBuffer == NULL) {
+#if DBG
+ IF_OD2_DEBUG(MISC) {
+ KdPrint(("Od2FileIsConfigSys: Cannot allocate space for canoncial name\n"));
+ }
+#endif
+ *ResultStatus = STATUS_NO_MEMORY;
+ return(TRUE);
+ }
+
+ RtlMoveMemory(NameBuffer, Od2CanonicalConfigDotSys, StringLen);
+ RtlFreeHeap(Od2Heap, 0, FileName_A->Buffer);
+ Od2InitMBString(FileName_A, NameBuffer);
+
+ *ResultStatus = STATUS_SUCCESS;
+ return (TRUE);
+}
+
diff --git a/private/os2/client/dllcopy.c b/private/os2/client/dllcopy.c
new file mode 100644
index 000000000..7daba3437
--- /dev/null
+++ b/private/os2/client/dllcopy.c
@@ -0,0 +1,2161 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllcopy.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 DosCopy API
+
+Author:
+
+ Therese Stowell (thereses) 21-Jan-1990
+ ported from cruiser file doscall1\doscopy.c
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FILESYS
+#include "os2dll.h"
+#include "dllcopy.h"
+
+APIRET
+CopyTree(
+ IN PSTRING SourcePath,
+ IN HANDLE ParentSourceHandle,
+ IN PSTRING TargetPath,
+ IN HANDLE ParentTargetHandle,
+ IN PVOID IoBuffer,
+ IN ULONG IoBufferSize,
+ IN PVOID FindBuffer,
+ IN ULONG SourceType,
+ IN ULONG TargetType,
+ IN ULONG CopyOption
+ );
+
+APIRET
+Od2CopyFile(
+ IN PSTRING SourcePath,
+ IN HANDLE ParentSourceHandle,
+ IN PSTRING TargetPath,
+ IN HANDLE ParentTargetHandle,
+ IN PVOID IoBuffer,
+ IN ULONG IoBufferSize,
+ IN ULONG SourceType,
+ IN ULONG TargetType,
+ IN ULONG CopyOption,
+ IN BOOLEAN TreeCopy
+ );
+
+BOOLEAN
+CheckNeedEa(
+ PFILE_FULL_EA_INFORMATION EaList
+ );
+
+APIRET
+CreateTargetFromNul(
+ IN PSTRING TargetPath,
+ IN HANDLE ParentTargetHandle,
+ IN ULONG TargetType,
+ IN ULONG CopyOption
+ );
+
+APIRET
+GetCopyFileType(
+ IN PSTRING FileName,
+ IN OUT PULONG CopyFileType,
+ IN BOOLEAN Target
+ )
+
+/*++
+
+Routine Description:
+
+ This routine figures out what type a file is for copy purposes.
+
+Arguments:
+
+ FileName - file to get type of
+
+ CopyFileType - on input, the type returned by Canonicalize
+ on output, the type of file (COT_DIRECTORY, COT_FILE, etc)
+
+ Target - whether the FileName is the target
+
+Return Value:
+
+ ERROR_FILE_NOT_FOUND - the source file doesn't exist or the target
+ file parent dir doesn't exist.
+
+--*/
+
+{
+ NTSTATUS Status;
+ HANDLE ObjHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ USHORT FileType;
+ BOOLEAN Directory;
+ APIRET RetCode;
+ USHORT DeviceAttributes;
+ UNICODE_STRING FileName_U;
+
+ //
+ // if the type returned by Canonicalize is device or
+ // named pipe, we know that's the right type of the file and we return
+ // immediately. otherwise, we need to open the file to see if it is
+ // a device or named pipe that Canonicalize didn't recognize or if
+ // it's a directory.
+ //
+
+ if (*CopyFileType & FILE_TYPE_DEV) {
+ *CopyFileType = COT_DEVICE;
+ return NO_ERROR;
+ } else if (*CopyFileType & FILE_TYPE_NMPIPE) {
+ *CopyFileType = COT_OTHER;
+ return NO_ERROR;
+ }
+ else if (*CopyFileType & FILE_TYPE_PIPE) {
+ *CopyFileType = COT_OTHER;
+ return NO_ERROR;
+ }
+ else if (*CopyFileType & FILE_TYPE_MAILSLOT) {
+ *CopyFileType = COT_OTHER;
+ return NO_ERROR;
+ }
+
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &FileName_U,
+ FileName,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("GetCopyFileType: no memory for Unicode Conversion\n");
+ }
+#endif
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &FileName_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ do {
+ Status = NtOpenFile(&ObjHandle,
+ Target ?
+ // (SYNCHRONIZE | FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA) :
+ (SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_READ_DATA) :
+ (SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_READ_DATA),
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+
+ RtlFreeUnicodeString (&FileName_U);
+ if (!NT_SUCCESS(Status)) {
+ if (!Target)
+ return Or2MapNtStatusToOs2Error(Status, ERROR_FILE_NOT_FOUND);
+ else {
+
+ //
+ // if parent exists, Status should be STATUS_OBJECT_NAME_NOT_FOUND
+ //
+
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
+ *CopyFileType = COT_PARENT;
+ }
+
+ //
+ // if the parent doesn't exist, we assume that the target is a
+ // named pipe
+ //
+
+ else {
+ *CopyFileType = COT_OTHER;
+ }
+ return NO_ERROR;
+ }
+ }
+ RetCode = MapFileType(ObjHandle,&Directory,&FileType,&DeviceAttributes);
+ NtClose(ObjHandle);
+ if (RetCode) {
+ return RetCode;
+ }
+ if (Directory) {
+ *CopyFileType = COT_DIRECTORY;
+ }
+ else if (FileType == FHT_DISKFILE) {
+ *CopyFileType = COT_FILE;
+ }
+ else if (FileType == FHT_CHRDEV) {
+ *CopyFileType = COT_DEVICE;
+ }
+ return NO_ERROR;
+}
+
+APIRET
+DosCopy(
+ IN PSZ OldFileName,
+ IN PSZ NewFileName,
+ IN ULONG CopyOption
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies a file.
+
+Arguments:
+
+ OldFileName - The ASCIIZ path name of the source file,
+ subdirectory, or character device. Wildcards are not
+ allowed.
+
+ NewFileName - The ASCIIZ path name of the target file,
+ subdirectory, or character device. Wildcards are not
+ allowed.
+
+ CopyOption - A bit map that defines how the DOSCOPY function will be done.
+
+ The bit field mapping is shown as follows:
+
+ fsOpMode 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ bits R R R R R R R R R R R R R F A E
+
+ E Existing Target File Disposition
+
+ A Append/Replace Mode
+
+ F EA bit; fail copy/discard EA's
+
+ R Reserved and must be set to zero.
+
+Return Value:
+
+ TBS
+
+--*/
+
+{
+ APIRET RetCode;
+ STRING SourceCanonicalName;
+ STRING TargetCanonicalName;
+ ULONG SourceType;
+ ULONG TargetType;
+ ULONG SourceFlags;
+ ULONG TargetFlags;
+ ULONG IoBufferSize;
+ PVOID IoBuffer;
+ struct FIND_BUFFER {
+ FILE_DIRECTORY_INFORMATION DirInfo;
+ CHAR Name[CCHMAXPATH-1];
+ } FindBuffer;
+ PSZ LastComponent, NewTarget;
+ ULONG TargetPathLen;
+ BOOLEAN fAppendSlash;
+ NTSTATUS Status;
+
+ //
+ // Validate opmode
+ //
+
+ if (CopyOption & ~DCPY_ALL) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ if (RetCode = Od2Canonicalize( OldFileName,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &SourceCanonicalName,
+ NULL,
+ &SourceFlags,
+ &SourceType) != NO_ERROR) {
+ return RetCode;
+ }
+ //
+ // Special handling of <boot-drive>:\config.sys
+ // opening this file is mapped to the OS/2 SS config.sys
+ //
+ if (Od2FileIsConfigSys(&SourceCanonicalName, OPEN_ACCESS_READONLY, &Status))
+ {
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to init for config.sys
+
+ RtlFreeHeap(Od2Heap,0,SourceCanonicalName.Buffer);
+ return Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ }
+
+ SourceFlags = 0;
+ SourceType = FILE_TYPE_FILE;
+ }
+
+ if (SourceFlags & CANONICALIZE_META_CHARS_FOUND) {
+ RtlFreeHeap(Od2Heap,0,SourceCanonicalName.Buffer);
+ return ERROR_FILE_NOT_FOUND;
+ }
+
+ if (SourceType & FILE_TYPE_PSDEV) {
+ //
+ // NUL device - continue, in order to create the target file
+ // anyhow, like os/2 does.
+ //
+/*
+ if (!strcmp(SourceCanonicalName.Buffer, "@0")){
+ //
+ // NUL device - just return OK
+ //
+ RtlFreeHeap(Od2Heap,0,SourceCanonicalName.Buffer);
+ return(NO_ERROR);
+ }
+ RtlFreeHeap(Od2Heap,0,SourceCanonicalName.Buffer);
+ return ERROR_ACCESS_DENIED;
+*/
+ if (strcmp(SourceCanonicalName.Buffer, "@0")){
+ RtlFreeHeap(Od2Heap,0,SourceCanonicalName.Buffer);
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ //
+ // Determine type of source object. We already know if
+ // the source is a device or named pipe because Canonicalize
+ // determines it. It is possible that the source is a device or
+ // named pipe without it being detected by Canonicalize. We also need
+ // to know whether it's a file or directory. So we open it.
+ //
+
+ if (strcmp(SourceCanonicalName.Buffer, "@0")) {
+ RetCode = GetCopyFileType(&SourceCanonicalName,
+ &SourceType,
+ FALSE);
+
+ if ((RetCode == ERROR_FILE_NOT_FOUND) && (SourceType == FILE_TYPE_FILE)) {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ }
+ if (RetCode) {
+ RtlFreeHeap(Od2Heap,0,SourceCanonicalName.Buffer);
+ return RetCode;
+ }
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("oldfilename is %s\n",SourceCanonicalName.Buffer);
+ DbgPrint("Object type: Source - %u\n", SourceType);
+ }
+#endif
+
+ //
+ // canonicalize destination name
+ //
+
+ if (RetCode = Od2Canonicalize(NewFileName,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &TargetCanonicalName,
+ NULL,
+ &TargetFlags,
+ &TargetType) != NO_ERROR) {
+ RtlFreeHeap(Od2Heap,0,SourceCanonicalName.Buffer);
+ return RetCode;
+ }
+ //
+ // Special handling of <boot-drive>:\config.sys
+ // opening this file is mapped to the OS/2 SS config.sys
+ //
+ if (Od2FileIsConfigSys(&TargetCanonicalName, OPEN_ACCESS_READWRITE, &Status))
+ {
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to init for config.sys
+
+ RtlFreeHeap(Od2Heap,0,SourceCanonicalName.Buffer);
+ RtlFreeHeap(Od2Heap,0,TargetCanonicalName.Buffer);
+ return Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ }
+
+ TargetFlags = 0;
+ TargetType = FILE_TYPE_FILE;
+ }
+
+ if (TargetFlags & CANONICALIZE_META_CHARS_FOUND) {
+ RtlFreeHeap(Od2Heap,0,SourceCanonicalName.Buffer);
+ RtlFreeHeap(Od2Heap,0,TargetCanonicalName.Buffer);
+ return ERROR_FILE_NOT_FOUND;
+ }
+ if (TargetType & FILE_TYPE_PSDEV) {
+ RtlFreeHeap(Od2Heap,0,SourceCanonicalName.Buffer);
+ if (!strcmp(TargetCanonicalName.Buffer, "@0")){
+ //
+ // NUL device - just return OK
+ //
+ RtlFreeHeap(Od2Heap,0,TargetCanonicalName.Buffer);
+ return(NO_ERROR);
+ }
+ RtlFreeHeap(Od2Heap,0,TargetCanonicalName.Buffer);
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // Determine type of target object. We already know if
+ // the target is a device or named pipe because Canonicalize
+ // determines it. It is possible that the target is a device or
+ // named pipe without it being detected by Canonicalize. We also need
+ // to know whether it's a file or directory. So we open it.
+ //
+
+ RetCode = GetCopyFileType(&TargetCanonicalName,
+ &TargetType,
+ TRUE);
+ if (RetCode) {
+ RtlFreeHeap(Od2Heap,0,SourceCanonicalName.Buffer);
+ RtlFreeHeap(Od2Heap,0,TargetCanonicalName.Buffer);
+ return RetCode;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("newfilename is %s\n",TargetCanonicalName.Buffer);
+ DbgPrint("Object type: Target - %u\n", TargetType);
+ }
+#endif
+
+ //
+ // Perform validation
+ //
+ // Error if the source is a directory and the target exists
+ // but is not a directory.
+ //
+
+ if (SourceType == COT_DIRECTORY
+ && TargetType != COT_DIRECTORY
+ && TargetType != COT_PARENT) {
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("ERROR: Source is a directory, target is not.\n") ;
+ }
+#endif
+ RetCode = ERROR_DIRECTORY;
+ goto DosCopyAbort_2 ;
+ }
+
+ //
+ // Error if target is a directory and source is a device;
+ // e.g. we don't want to create X:\DIR\LPT1.
+ //
+
+ if (SourceType == COT_DEVICE
+ && TargetType == COT_DIRECTORY) {
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("ERROR: Source is a device, target is a directory.\n") ;
+ }
+#endif
+ RetCode = ERROR_DIRECTORY ;
+ goto DosCopyAbort_2 ;
+ }
+
+ //
+ // Error if the target is the same directory as the source or is a
+ // subdirectory of it.
+ //
+ // NOTE: If the source and target refer to the same file, the error
+ // will occur when trying to open the target for writing after
+ // the source has been opened deny-write.
+ //
+ // WARNING: This test will not catch the scenario where one directory
+ // can be referred to with two distinct fully-qualified
+ // pathnames, e.g. \\SERVER\SHARE\DIR and S:\DIR.
+ //
+
+ TargetPathLen = TargetCanonicalName.Length;
+
+ if (SourceType == COT_DIRECTORY
+ && SourceCanonicalName.Length <= (USHORT)TargetPathLen
+ && (strncmp(SourceCanonicalName.Buffer,
+ TargetCanonicalName.Buffer,
+ (ULONG)(SourceCanonicalName.Length)) == (int) 0)
+ && (SourceCanonicalName.Length == (USHORT)TargetPathLen
+ || (TargetCanonicalName.Buffer[SourceCanonicalName.Length] == '\\')
+ || (SourceFlags & CANONICALIZE_IS_ROOT_DIRECTORY)!=0)) {
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("ERROR: Source and target are the same, or target is a subdirectory of the source. \n");
+ }
+#endif
+ RetCode = ERROR_DIRECTORY ;
+ goto DosCopyAbort_2 ;
+ }
+
+ //
+ // Now we're getting close to the real work...
+ //
+ // Allocate as big a buffer as possible for EAs and file I/O
+ //
+
+ IoBufferSize = MAX_ALIGNED_EA_LIST_SIZE;
+ IoBuffer = 0;
+ Status = NtAllocateVirtualMemory(NtCurrentProcess(),
+ &IoBuffer,
+ 0,
+ &IoBufferSize,
+ MEM_COMMIT,
+ PAGE_READWRITE
+ );
+ if (!NT_SUCCESS(Status)) {
+ RetCode = ERROR_NOT_ENOUGH_MEMORY;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("ERROR: Could not allocate %u bytes of memory for I/O.\n",
+ MAX_ALIGNED_EA_LIST_SIZE) ;
+ }
+#endif
+ goto DosCopyAbort_2 ;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Allocated %u bytes of memory for I/O.\n", IoBufferSize) ;
+ }
+#endif
+
+ //
+ // If the source is a file and the target is a directory, we need to
+ // take the filename portion of the source pathname and append it to
+ // the target pathname, e.g. X:\DIRA\FILE.EXT to Y:\DIRB
+ //
+
+ if ((SourceType == COT_FILE || SourceType == COT_OTHER)
+ && TargetType == COT_DIRECTORY) {
+
+ //
+ // Determine filename portion of the source, to be appended to
+ // the target.
+ //
+
+ LastComponent = FindLastComponent(SourceCanonicalName.Buffer);
+
+ //
+ // A slash will be have to appended if the target is not the root
+ // directory of a drive.
+ //
+
+ fAppendSlash =(BOOLEAN)((TargetFlags & CANONICALIZE_IS_ROOT_DIRECTORY) == 0);
+
+ //
+ // Check to see if new name will fit in buffer;
+ // if not, return error
+ //
+
+ if (TargetPathLen+strlen(LastComponent)+fAppendSlash > CCHMAXPATH-1) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("ERROR: Real target pathname is too long:\n\tTarget path=%s\n\tTarget file=%s\n",
+ TargetCanonicalName.Buffer,LastComponent) ;
+ }
+#endif
+ RetCode = ERROR_FILENAME_EXCED_RANGE ;
+ goto DosCopyAbort_3 ;
+ }
+
+ //
+ // allocate a new heap buffer for the target and copy old target in.
+ //
+
+ NewTarget = RtlAllocateHeap(Od2Heap,0,TargetPathLen+strlen(LastComponent)+fAppendSlash+1);
+ if (NewTarget == NULL) {
+#if DBG
+ KdPrint(( "OS2: DosCopy, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ RetCode = ERROR_NOT_ENOUGH_MEMORY;
+ goto DosCopyAbort_3 ;
+ }
+ strncpy(NewTarget,TargetCanonicalName.Buffer,TargetPathLen);
+
+ //
+ // Finally, do the append operation
+ //
+
+ if (fAppendSlash) NewTarget[TargetPathLen++] = '\\' ;
+ strcpy(NewTarget + TargetPathLen,LastComponent) ;
+
+ RtlFreeHeap(Od2Heap,0,TargetCanonicalName.Buffer);
+ RtlInitString(&TargetCanonicalName,NewTarget);
+
+ //
+ // Modify the target type
+ //
+
+ TargetType = COT_FILE ;
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("New target pathname: %s\n",TargetCanonicalName.Buffer ) ;
+ }
+#endif
+ }
+
+ //
+ // NOW LET'S DO THE REAL WORK!
+ //
+
+ if (SourceType == COT_DIRECTORY) {
+
+ //
+ // TREE COPY
+ //
+ // Append mode should be DCPY_EXISTING in tree copy in case there is a
+ // file existing in both the source and target directories.
+ //
+
+ // CopyOption &= ~DCPY_APPEND ;
+ CopyOption |= DCPY_EXISTING ;
+
+ //
+ // Change target type from parent to directory
+ //
+
+ if (TargetType == COT_PARENT)
+ TargetType = COT_DIRECTORY ;
+
+ RetCode = CopyTree(&SourceCanonicalName,
+ (HANDLE) NULL,
+ &TargetCanonicalName,
+ (HANDLE) NULL,
+ IoBuffer,
+ IoBufferSize,
+ (PVOID) &FindBuffer,
+ SourceType,
+ TargetType,
+ CopyOption) ;
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Top-level copy_tree(...) returns %u\n", RetCode) ;
+ }
+#endif
+
+ } else {
+
+ //
+ // FILE COPY
+ //
+ // Change target type from parent to file
+ //
+
+ if (TargetType == COT_PARENT)
+ TargetType = COT_FILE ;
+
+ //
+ // if Source is NUL, do not copy, just create target file
+ //
+
+ if (!strcmp(SourceCanonicalName.Buffer, "@0")){
+ RetCode = CreateTargetFromNul(&TargetCanonicalName,
+ (HANDLE) NULL,
+ TargetType,
+ CopyOption);
+ }
+ else {
+ RetCode = Od2CopyFile(&SourceCanonicalName,
+ (HANDLE) NULL,
+ &TargetCanonicalName,
+ (HANDLE) NULL,
+ IoBuffer,
+ IoBufferSize,
+ SourceType,
+ TargetType,
+ CopyOption,
+ FALSE) ;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Top-level copy_file(...) returns %u\n", RetCode) ;
+ }
+#endif
+ }
+
+
+DosCopyAbort_3:
+
+ //
+ // Free the buffer for file I/O.
+ //
+
+ Status = NtFreeVirtualMemory(NtCurrentProcess(),
+ &IoBuffer,
+ &IoBufferSize,
+ MEM_RELEASE
+ );
+
+DosCopyAbort_2:
+
+ //
+ // Free the name buffers
+ //
+
+ RtlFreeHeap(Od2Heap,0,SourceCanonicalName.Buffer);
+ RtlFreeHeap(Od2Heap,0,TargetCanonicalName.Buffer);
+
+ //
+ // Return the error to the caller.
+ //
+
+ return(RetCode);
+}
+
+APIRET
+DosICopy(
+ IN PSZ OldFileName,
+ IN PSZ NewFileName,
+ IN ULONG CopyOption
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies a file by calling DosCopy.
+
+Arguments:
+
+ OldFileName - The ASCIIZ path name of the source file,
+ subdirectory, or character device. Wildcards are not
+ allowed.
+
+ NewFileName - The ASCIIZ path name of the target file,
+ subdirectory, or character device. Wildcards are not
+ allowed.
+
+ CopyOption - A bit map that defines how the DOSCOPY function will be done.
+
+ The bit field mapping is shown as follows:
+
+ fsOpMode 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ bits R R R R R R R R R R R R R F A E
+
+ E Existing Target File Disposition
+
+ A Append/Replace Mode
+
+ F EA bit; fail copy/discard EA's
+
+ R Reserved and must be set to zero.
+
+Return Value:
+
+ TBS
+
+--*/
+
+{
+
+ return(DosCopy(OldFileName,NewFileName,CopyOption));
+
+}
+APIRET
+CopyTree(
+ IN PSTRING SourcePath,
+ IN HANDLE ParentSourceHandle,
+ IN PSTRING TargetPath,
+ IN HANDLE ParentTargetHandle,
+ IN PVOID IoBuffer,
+ IN ULONG IoBufferSize,
+ IN PVOID FindBuffer,
+ IN ULONG SourceType,
+ IN ULONG TargetType,
+ IN ULONG CopyOption
+ )
+
+/*++
+
+Routine Description:
+
+ This routine recursively copies a directory tree. it does the
+ following:
+
+ create destination directory, if it doesn't exist
+ for each entry in source directory
+ if (directory)
+ CopyTree
+ else
+ CopyFile
+
+Arguments:
+
+ SourcePath - name of source file. if a parent handle is passed in,
+ this contains only the last component in the path.
+
+ ParentSourceHandle - handle to parent directory of source file
+
+ TargetPath - name of target file. if a parent handle is passed in,
+ this contains only the last component in the path.
+
+ ParentTargetHandle - handle to parent directory of target file
+
+ IoBuffer - buffer to use for setting EAs and copying data.
+
+ IoBufferSize - size of buffer. it's large enough to hold all the EAs
+ for a file.
+
+ FindBuffer - buffer to use for getting entries in source directory. it's
+ large enough to contain one entry.
+
+ SourceType - whether source is file, dir, device, named pipe
+
+ TargetType - whether target is file, dir, device, named pipe
+
+ CopyOption - append, replace, fail if eas not supported
+
+Return Value:
+
+ TBS.
+
+--*/
+
+{
+ APIRET RetCode;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ HANDLE SourceHandle;
+ HANDLE TargetHandle;
+ STRING ChildSourceName;
+ STRING ChildTargetName;
+ STRING FileName;
+ UNICODE_STRING FileName_U;
+ LARGE_INTEGER AllocationSize;
+ FILE_EA_INFORMATION EaInfo;
+ FILE_BASIC_INFORMATION BasicInfo;
+ NTSTATUS Status;
+ PFILE_DIRECTORY_INFORMATION DirEntry;
+ UNICODE_STRING SourcePath_U, TargetPath_U;
+
+ //
+ // Initialize return value
+ //
+
+ RetCode = NO_ERROR;
+
+ //
+ // Create the target, if it doesn't exist, with the source's extended
+ // attributes.
+ //
+ // to do this:
+ // query the source directory's EAs
+ // NtCreateFile(CREATE_DIRECTORY, open or create, EAs)
+ // if the createfile fails because EAs aren't supported
+ // NtCreateFile(no EAs)
+ //
+
+ //
+ // open the source
+ //
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &SourcePath_U,
+ SourcePath,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("CopyTree: no memory for Unicode Conversion\n");
+ }
+#endif
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &SourcePath_U,
+ OBJ_CASE_INSENSITIVE,
+ ParentSourceHandle,
+ NULL);
+
+ do {
+ Status = NtOpenFile(&SourceHandle,
+ FILE_LIST_DIRECTORY |
+ FILE_READ_EA |
+ FILE_READ_ATTRIBUTES |
+ SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+ RtlFreeUnicodeString (&SourcePath_U);
+
+ if (!(NT_SUCCESS(Status))) {
+// RetCode = ERROR_PATH_NOT_FOUND;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("CopyTree: Error at NtOpen %lx\n", Status);
+ }
+#endif
+ return Or2MapNtStatusToOs2Error(Status, ERROR_PATH_NOT_FOUND);
+ }
+
+ //
+ // since we can't do FILE_OPEN_IF with directories, we first try to open
+ // the directory. if that fails, we create it.
+ //
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &TargetPath_U,
+ TargetPath,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("CopyTree: no memory for Unicode Conversion\n");
+ }
+#endif
+ goto CopyTreeAbort_2 ;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &TargetPath_U,
+ OBJ_CASE_INSENSITIVE,
+ ParentTargetHandle,
+ NULL);
+
+ do {
+ Status = NtOpenFile(&TargetHandle,
+ SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+
+ if (!(NT_SUCCESS(Status))) {
+ if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto CopyTreeAbort_2 ;
+ }
+ else {
+
+ do {
+ Status = NtQueryInformationFile(SourceHandle,
+ &IoStatus,
+ &EaInfo,
+ sizeof (EaInfo),
+ FileEaInformation);
+ } while (RetryIO(Status, SourceHandle));
+ if (!(NT_SUCCESS(Status))) {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto CopyTreeAbort_2 ;
+ }
+ if (EaInfo.EaSize > MAX_ALIGNED_EA_LIST_SIZE)
+ ASSERT(FALSE);
+
+ do {
+ Status = NtQueryInformationFile(SourceHandle,
+ &IoStatus,
+ &BasicInfo,
+ sizeof (BasicInfo),
+ FileBasicInformation);
+ } while (RetryIO(Status, SourceHandle));
+ if (!(NT_SUCCESS(Status))) {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto CopyTreeAbort_2 ;
+ }
+
+ do {
+ Status = NtQueryEaFile(SourceHandle,
+ &IoStatus,
+ IoBuffer,
+ IoBufferSize,
+ FALSE,
+ (PVOID) NULL,
+ 0,
+ (PULONG) NULL,
+ TRUE
+ );
+ } while (RetryIO(Status, SourceHandle));
+
+ if (!(NT_SUCCESS(Status)) && Status != STATUS_NO_EAS_ON_FILE) {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto CopyTreeAbort_2 ;
+ }
+
+ AllocationSize = RtlConvertUlongToLargeInteger(0);
+ do {
+ Status = NtCreateFile(&TargetHandle,
+ SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ &AllocationSize,
+ BasicInfo.FileAttributes,
+ FILE_SHARE_READ,
+ FILE_CREATE,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+ IoBuffer,
+ EaInfo.EaSize
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+
+ if (!(NT_SUCCESS(Status))) {
+
+ //
+ // Make sure the destination supports EAs. If not, fail the copy
+ // according to the F bit of the FsOpMode parameter and the presence
+ // of need EAs in the source.
+ //
+
+ if (Status == STATUS_EAS_NOT_SUPPORTED) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Target filesystem does not support EA's\n");
+ }
+#endif
+ if(CheckNeedEa((PFILE_FULL_EA_INFORMATION) IoBuffer)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("...and source dir has need EAs; aborting!\n");
+ }
+#endif
+ RetCode = ERROR_NEED_EAS_FOUND;
+ goto CopyTreeAbort_2;
+ }
+ if(CopyOption & DCPY_EA_FAIL_COPY) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("...and EA_fail_copy bit is set; aborting!\n");
+ }
+#endif
+ RetCode = ERROR_EAS_NOT_SUPPORTED;
+ goto CopyTreeAbort_2;
+ } else {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("...so source EA's will be discarded.\n");
+ }
+#endif
+ do {
+ Status = NtCreateFile(&TargetHandle,
+ SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ &AllocationSize,
+ BasicInfo.FileAttributes,
+ FILE_SHARE_READ,
+ FILE_OPEN_IF,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+ if (!(NT_SUCCESS(Status))) {
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_FILE_NOT_FOUND);
+ goto CopyTreeAbort_2;
+ }
+ }
+ }
+ else {
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_FILE_NOT_FOUND);
+ goto CopyTreeAbort_2;
+ }
+ }
+ }
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Target directory %s opened/created.\n",TargetPath->Buffer);
+ }
+#endif
+
+ for (Status = NtQueryDirectoryFile(SourceHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ FindBuffer,
+ sizeof (FILE_DIRECTORY_INFORMATION) + CCHMAXPATH - 1,
+ FileDirectoryInformation,
+ TRUE,
+ NULL,
+ TRUE);
+ NT_SUCCESS(Status);
+ Status = NtQueryDirectoryFile(SourceHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ FindBuffer,
+ sizeof (FILE_DIRECTORY_INFORMATION) + CCHMAXPATH - 1,
+ FileDirectoryInformation,
+ TRUE,
+ NULL,
+ FALSE)) {
+
+ //
+ // Skip "." and ".." entries
+ //
+ DirEntry = (PFILE_DIRECTORY_INFORMATION) FindBuffer;
+
+ //
+ // What we get back from Nt is Unicode
+ //
+
+ DirEntry->FileName[(DirEntry->FileNameLength)/2] = 0;
+ RtlInitUnicodeString (&FileName_U,
+ DirEntry->FileName);
+ //
+ // Convert it to Ansi
+ //
+ Status = Od2UnicodeStringToMBString(
+ &FileName,
+ &FileName_U,
+ TRUE);
+ ASSERT(NT_SUCCESS(Status));
+ if (!NT_SUCCESS(Status)){
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("CopyTree: no memory for Unicode Conversion\n");
+ }
+#endif
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_NOT_ENOUGH_MEMORY);
+ goto CopyTreeAbort_2;
+ }
+
+ if (!strcmp(FileName.Buffer,CURRENT_DIRECTORY) ||
+ !strcmp(FileName.Buffer,PARENT_DIRECTORY))
+ continue ;
+
+ ChildTargetName.Buffer = ChildSourceName.Buffer = FileName.Buffer;
+ ChildTargetName.Length = ChildSourceName.Length = FileName.Length;
+ ChildTargetName.MaximumLength = ChildSourceName.MaximumLength =
+ FileName.MaximumLength + (USHORT)1;
+
+ //
+ // Now make the recursive call. the reason we don't pass the source's
+ // attributes to CopyTree or CopyFile is we can't guarantee that
+ // the file/dir won't be deleted and recreated in the middle because
+ // we don't have an open handle to the object.
+ //
+
+ if (DirEntry->FileAttributes & FILE_DIRECTORY) {
+
+ //
+ // TREE COPY
+ //
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("About to call copy_tree():\n\tSource=%s\n\tTarget=%s\n",
+ ChildSourceName.Buffer,ChildTargetName.Buffer) ;
+ }
+#endif
+ RetCode = CopyTree(&ChildSourceName,
+ SourceHandle,
+ &ChildTargetName,
+ TargetHandle,
+ IoBuffer,
+ IoBufferSize,
+ FindBuffer,
+ SourceType,
+ TargetType,
+ CopyOption) ;
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Recursive CopyTree(...) returns %u\n", RetCode) ;
+ }
+#endif
+ } else {
+
+ //
+ // FILE COPY
+ //
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("About to call copy_file():\n\tSource=%s\n\tTarget=%s\n",
+ ChildSourceName.Buffer,ChildTargetName.Buffer) ;
+ }
+#endif
+ RetCode = Od2CopyFile(&ChildSourceName,
+ SourceHandle,
+ &ChildTargetName,
+ TargetHandle,
+ IoBuffer,
+ IoBufferSize,
+ SourceType,
+ TargetType,
+ CopyOption,
+ TRUE) ;
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Recursive copy_file(...) returns %u\n", RetCode) ;
+ }
+#endif
+ }
+
+ if (RetCode)
+ goto CopyTreeAbort_3 ;
+
+ } // End of NtQueryDirectory loop
+
+ if (!(NT_SUCCESS(Status)) && (Status != STATUS_NO_MORE_FILES)) {
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("ERROR: DosFindFirst/Next returns %u\n", RetCode) ;
+ }
+#endif
+ goto CopyTreeAbort_3 ;
+ }
+ else
+ RetCode = NO_ERROR;
+
+CopyTreeAbort_3:
+ NtClose(TargetHandle);
+
+CopyTreeAbort_2:
+ NtClose(SourceHandle);
+ RtlFreeUnicodeString (&TargetPath_U);
+
+ //
+ // Return the error to the caller.
+ //
+
+ return(RetCode) ;
+}
+
+// Notice: the function below takes only raw file EA data, not an FEA2 list
+NTSTATUS
+Od2SizeFEA2Data(
+ PFEA2 pFEA2,
+ PULONG pSize
+ )
+{
+ ULONG size = 0;
+ PFEA2 ptr = pFEA2;
+
+ try
+ {
+ while (ptr->oNextEntryOffset != 0)
+ ptr = (PFEA2)((PBYTE)ptr + ptr->oNextEntryOffset);
+
+ if (ptr->cbName != 0) // Just to protect against empty/bad EA list
+ {
+ size = (ULONG)ptr - (ULONG)pFEA2;
+ size += FIELD_OFFSET(FEA2, szName)
+ + ptr->cbValue
+ + ptr->cbName + 1;
+ size = (size + 3) & ~0x3; // align to ULONG
+ }
+ else if (ptr != pFEA2)
+ {
+ // This is wrong: we have a non-empty EA list and the last entry
+ // has a .cbName of 0
+ return STATUS_EA_LIST_INCONSISTENT;
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ return STATUS_EA_LIST_INCONSISTENT;
+ }
+
+ *pSize = size;
+ return STATUS_SUCCESS;
+}
+
+APIRET
+Od2CopyFile(
+ IN PSTRING SourcePath,
+ IN HANDLE ParentSourceHandle,
+ IN PSTRING TargetPath,
+ IN HANDLE ParentTargetHandle,
+ IN PVOID IoBuffer,
+ IN ULONG IoBufferSize,
+ IN ULONG SourceType,
+ IN ULONG TargetType,
+ IN ULONG CopyOption,
+ IN BOOLEAN TreeCopy
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies or appends from the source file to the target file.
+ it does the following:
+
+ open source
+ read sources EAs, attributes, size
+ create/open target using source's info
+ read data from source and write it to target
+
+Arguments:
+
+ SourcePath - name of source file. if a parent handle is passed in,
+ this contains only the last component in the path.
+
+ ParentSourceHandle - handle to parent directory of source file
+
+ TargetPath - name of target file. if a parent handle is passed in,
+ this contains only the last component in the path.
+
+ ParentTargetHandle - handle to parent directory of target file
+
+ IoBuffer - buffer to use for setting EAs and copying data.
+
+ IoBufferSize - size of buffer. it's large enough to hold all the EAs
+ for a file.
+
+ SourceType - whether source is file, dir, device, named pipe
+
+ TargetType - whether target is file, dir, device, named pipe
+
+ CopyOption - append, replace, fail if eas not supported
+
+ TreeCopy - whether this is a tree copy
+
+Return Value:
+
+ TBS.
+
+--*/
+
+{
+ APIRET RetCode;
+ NTSTATUS Status;
+ NTSTATUS ReadStatus = STATUS_SUCCESS;
+ NTSTATUS WriteStatus = STATUS_SUCCESS;
+ USHORT fsCopyFileFlags = 0 ;
+ HANDLE SourceHandle;
+ HANDLE TargetHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ FILE_EA_INFORMATION EaInfo;
+ FILE_BASIC_INFORMATION SourceBasicInfo;
+ FILE_BASIC_INFORMATION TargetBasicInfo;
+ FILE_STANDARD_INFORMATION StandardInfo;
+ FILE_POSITION_INFORMATION PositionInfo;
+ FILE_DISPOSITION_INFORMATION DispositionInfo;
+ FILE_ALLOCATION_INFORMATION AllocationInfo;
+ FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
+ LARGE_INTEGER FileOffset;
+ ULONG CreateDisposition;
+ ULONG ActionTaken;
+ ULONG Key;
+ UNICODE_STRING SourcePath_U, TargetPath_U;
+
+ //
+ // Set TargetPath_U Length to zero, so we know what to do
+ // at Abort_2:
+ //
+
+ TargetPath_U.Length = 0;
+
+ //
+ // Determine if the source and target are regular files
+ //
+
+ fsCopyFileFlags |= CFF_SOURCE_IS_FILE *
+ (SourceType != COT_DEVICE
+ && SourceType != COT_OTHER) ;
+ fsCopyFileFlags |= CFF_TARGET_IS_FILE *
+ (TargetType != COT_DEVICE
+ && TargetType != COT_OTHER) ;
+
+ //
+ // based on the append and replace flags, initialize CreateDisposition.
+ //
+
+ if (fsCopyFileFlags & CFF_TARGET_IS_FILE) {
+ if (CopyOption & DCPY_APPEND) {
+ CreateDisposition = FILE_OPEN_IF;
+ }
+ else if (CopyOption & DCPY_EXISTING) {
+ CreateDisposition = FILE_OVERWRITE_IF;
+ }
+ else {
+ CreateDisposition = FILE_CREATE;
+ }
+ }
+
+ //
+ // If the target is a device or named pipe, just open it.
+ // NOTE: Since the target cannot be a device in a tree copy, there's
+ // no danger here of these flags being reset when copy_file()
+ // is called by copy_tree()
+ //
+
+ else {
+ CopyOption &= ~(DCPY_EXISTING | DCPY_APPEND);
+ CreateDisposition = FILE_OPEN;
+ }
+
+ //
+ // open the source
+ //
+
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &SourcePath_U,
+ SourcePath,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("CopyFile: no memory for Unicode Conversion\n");
+ }
+#endif
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &SourcePath_U,
+ OBJ_CASE_INSENSITIVE,
+ ParentSourceHandle,
+ NULL);
+
+ do {
+ Status = NtOpenFile(&SourceHandle,
+ FILE_READ_DATA |
+ FILE_READ_EA |
+ FILE_READ_ATTRIBUTES |
+ SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+
+ RtlFreeUnicodeString (&SourcePath_U);
+ if (!NT_SUCCESS(Status)) {
+ RetCode = ERROR_PATH_NOT_FOUND;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("ERROR: NtOpenFile(%s, ...) returns %X\n",
+ SourcePath,Status) ;
+ }
+#endif
+ goto CopyFileAbort_1 ;
+ }
+
+ //
+ // Get EAs, attributes, and filesize.
+ //
+
+ do {
+ Status = NtQueryInformationFile(SourceHandle,
+ &IoStatus,
+ &EaInfo,
+ sizeof (EaInfo),
+ FileEaInformation);
+ } while (RetryIO(Status, SourceHandle));
+ if (!(NT_SUCCESS(Status))) {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto CopyFileAbort_2 ;
+ }
+ if (EaInfo.EaSize > MAX_ALIGNED_EA_LIST_SIZE)
+ ASSERT(FALSE);
+
+ do {
+ Status = NtQueryInformationFile(SourceHandle,
+ &IoStatus,
+ &StandardInfo,
+ sizeof (StandardInfo),
+ FileStandardInformation);
+ } while (RetryIO(Status, SourceHandle));
+
+ if (!(NT_SUCCESS(Status))) {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto CopyFileAbort_2 ;
+ }
+
+ do {
+ Status = NtQueryInformationFile(SourceHandle,
+ &IoStatus,
+ &SourceBasicInfo,
+ sizeof (SourceBasicInfo),
+ FileBasicInformation);
+ } while (RetryIO(Status, SourceHandle));
+
+ if (!(NT_SUCCESS(Status))) {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto CopyFileAbort_2 ;
+ }
+
+ do {
+ Status = NtQueryEaFile(SourceHandle,
+ &IoStatus,
+ IoBuffer,
+ IoBufferSize,
+ FALSE,
+ (PVOID) NULL,
+ 0,
+ (PULONG) NULL,
+ TRUE
+ );
+ } while (RetryIO(Status, SourceHandle));
+
+ if (!(NT_SUCCESS(Status)) && Status != STATUS_NO_EAS_ON_FILE) {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto CopyFileAbort_2 ;
+ }
+
+ //
+ // create/open target
+ //
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &TargetPath_U,
+ TargetPath,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("CopyFile: no memory for Unicode Conversion\n");
+ }
+#endif
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &TargetPath_U,
+ OBJ_CASE_INSENSITIVE,
+ ParentTargetHandle,
+ NULL);
+
+ do {
+ // BUGBUG - Oct. 11 92: Workaround for LAN bug which returns a size of
+ // 4 for EAs of files w/o EAs (local yields 0). NtCreateFile
+ // failed with such an EA size (even though the .CbList of
+ // IoBuffer is 0).
+ if (EaInfo.EaSize <= 4) // 4 and below means no EAs
+ Status = NtCreateFile(&TargetHandle,
+ FILE_WRITE_ATTRIBUTES | DELETE | FILE_READ_ATTRIBUTES |
+ FILE_WRITE_DATA | FILE_ADD_SUBDIRECTORY | SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ &StandardInfo.EndOfFile,
+ SourceBasicInfo.FileAttributes,
+ FILE_SHARE_READ,
+ CreateDisposition,
+ FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0
+ );
+ else
+ {
+ ULONG sz;
+
+ // BUGBUG - Oct. 11 92: Workaround for NT bug where NtQueryInformationFile
+ // returns a wrong size for the file EA's
+ Status = Od2SizeFEA2Data(IoBuffer, &sz);
+ if (Status == STATUS_SUCCESS)
+ Status = NtCreateFile(&TargetHandle,
+ FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | DELETE | FILE_READ_ATTRIBUTES |
+ FILE_WRITE_DATA | FILE_ADD_SUBDIRECTORY | SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ &StandardInfo.EndOfFile,
+ SourceBasicInfo.FileAttributes,
+ FILE_SHARE_READ,
+ CreateDisposition,
+ FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT,
+ IoBuffer,
+ sz
+ );
+ }
+ } while (RetryCreateOpen(Status, &Obja));
+
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtCreateFile for target returned %lx\n", Status) ;
+ }
+#endif
+
+ //
+ // Make sure the destination supports EAs. If not, fail the copy
+ // according to the F bit of the FsOpMode parameter and the presence
+ // of need EAs in the source.
+ //
+
+ if (Status == STATUS_EAS_NOT_SUPPORTED) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Target filesystem does not support EA's\n");
+ }
+#endif
+ if(CheckNeedEa((PFILE_FULL_EA_INFORMATION) IoBuffer)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("...and source dir has need EAs; aborting!\n");
+ }
+#endif
+ RetCode = ERROR_NEED_EAS_FOUND;
+ goto CopyFileAbort_2;
+ }
+ if(CopyOption & DCPY_EA_FAIL_COPY) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("...and EA_fail_copy bit is set; aborting!\n");
+ }
+#endif
+ RetCode = ERROR_EAS_NOT_SUPPORTED;
+ goto CopyFileAbort_2;
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("...so source EA's will be discarded.\n");
+ }
+#endif
+ do {
+ Status = NtCreateFile(&TargetHandle,
+ FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | DELETE | FILE_READ_ATTRIBUTES |
+ FILE_WRITE_DATA | FILE_ADD_SUBDIRECTORY | SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ &StandardInfo.EndOfFile,
+ SourceBasicInfo.FileAttributes,
+ FILE_SHARE_READ,
+ CreateDisposition | FILE_SYNCHRONOUS_IO_NONALERT,
+ FILE_SEQUENTIAL_ONLY,
+ NULL,
+ 0
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtCreateFile for target returned %X\n", Status) ;
+ }
+#endif
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_FILE_NOT_FOUND);
+ goto CopyFileAbort_2;
+ }
+ }
+ }
+ else {
+
+ //
+ // if this is a tree copy, E=0 and A=0, and the open failed because
+ // the file existed, we return no_error.
+ //
+
+ if (Status == STATUS_ACCESS_DENIED && TreeCopy &&
+ !(CopyOption & (DCPY_APPEND | DCPY_EXISTING))) {
+ RetCode = NO_ERROR;
+ }
+ else {
+ if (Status == STATUS_OBJECT_NAME_COLLISION) {
+ RetCode = ERROR_ACCESS_DENIED;
+ }
+ else {
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ }
+ }
+ goto CopyFileAbort_2;
+ }
+ }
+ //
+ // if file existed (action == opened) and replace and append bits are off,
+ // we fail the operation.
+ //
+
+ ActionTaken = IoStatus.Information;
+ if ((ActionTaken == FILE_OPENED) &&
+ (!(CopyOption & (DCPY_EXISTING | DCPY_APPEND)))) {
+ RetCode = ERROR_ACCESS_DENIED;
+ goto CopyFileAbort_3;
+ }
+
+ //
+ // If target was opened and we're in append mode, save the target's
+ // original size and time. then set target file pointer to the end of
+ // the file.
+ //
+
+ if ((IoStatus.Information == FILE_OPENED) && (CopyOption & DCPY_APPEND)) {
+ do {
+ Status = NtQueryInformationFile(TargetHandle,
+ &IoStatus,
+ &TargetBasicInfo,
+ sizeof (TargetBasicInfo),
+ FileBasicInformation);
+ } while (RetryIO(Status, TargetHandle));
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtQueryInformationFile(BasicInfo) for target returned %X\n", Status) ;
+ }
+#endif
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto CopyFileAbort_3 ;
+ }
+ do {
+ Status = NtQueryInformationFile(TargetHandle,
+ &IoStatus,
+ &StandardInfo,
+ sizeof (StandardInfo),
+ FileStandardInformation);
+ } while (RetryIO(Status, TargetHandle));
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtQueryInformationFile(StandardInfo) for target returned %X\n", Status) ;
+ }
+#endif
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto CopyFileAbort_3 ;
+ }
+
+ PositionInfo.CurrentByteOffset = StandardInfo.EndOfFile;
+ do {
+ Status = NtSetInformationFile(TargetHandle,
+ &IoStatus,
+ &PositionInfo,
+ sizeof (PositionInfo),
+ FilePositionInformation);
+ } while (RetryIO(Status, TargetHandle));
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtSetInformationFile(PositionInfo) for target returned %X\n", Status) ;
+ }
+#endif
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_FILE_NOT_FOUND);
+ goto CopyFileAbort_3;
+ }
+ }
+
+ //
+ // copy data
+ // BUGBUG when devices and named pipes are added, this loop will have
+ // to change.
+ //
+
+ Key = (ULONG) Od2Process->Pib.ProcessId;
+ FileOffset = RtlConvertLongToLargeInteger(FILE_USE_FILE_POINTER_POSITION);
+
+ while (TRUE) {
+ do {
+ ReadStatus = NtReadFile(SourceHandle,
+ (HANDLE) NULL,
+ (PIO_APC_ROUTINE) NULL,
+ (PVOID) NULL,
+ &IoStatus,
+ IoBuffer,
+ IoBufferSize,
+ &FileOffset,
+ &Key
+ );
+ } while (RetryIO(Status, SourceHandle));
+ if ((!NT_SUCCESS(ReadStatus)) && (ReadStatus != STATUS_END_OF_FILE)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtReadFile returned %X\n", ReadStatus) ;
+ }
+#endif
+ RetCode = Or2MapNtStatusToOs2Error(ReadStatus, ERROR_ACCESS_DENIED);
+ goto CopyFileAbort_5;
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtReadFile: Read %u bytes from source file\n", IoStatus.Information) ;
+ }
+#endif
+ if (ReadStatus == STATUS_END_OF_FILE) {
+ RetCode = NO_ERROR;
+ break;
+ }
+ do {
+ WriteStatus = NtWriteFile(TargetHandle,
+ (HANDLE) NULL,
+ (PIO_APC_ROUTINE) NULL,
+ (PVOID) NULL,
+ &IoStatus,
+ IoBuffer,
+ IoStatus.Information,
+ &FileOffset,
+ &Key
+ );
+ } while (RetryIO(Status, TargetHandle));
+ if (!NT_SUCCESS(WriteStatus)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtWriteFile returned %X\n", WriteStatus) ;
+ }
+#endif
+ RetCode = Or2MapNtStatusToOs2Error(WriteStatus, ERROR_ACCESS_DENIED);
+ break;
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtWriteFile: wrote %u bytes to target source file\n", IoStatus.Information) ;
+ }
+#endif
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ if (ReadStatus) DbgPrint("ERROR: NtReadFile(...) returns %X\n", ReadStatus) ;
+ if (WriteStatus) DbgPrint("ERROR: NtWriteFile(...) returns %X\n", WriteStatus) ;
+ }
+#endif
+
+ if (RetCode)
+ goto CopyFileAbort_5 ;
+
+ //
+ // if target was created or replaced, set its time to that of the source.
+ //
+
+ if ((ActionTaken == FILE_CREATED) || (ActionTaken == FILE_SUPERSEDED)) {
+ do {
+ Status = NtSetInformationFile(TargetHandle,
+ &IoStatus,
+ &SourceBasicInfo,
+ sizeof (SourceBasicInfo),
+ FileBasicInformation);
+ } while (RetryIO(Status, TargetHandle));
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtSetInformationFile(BasicInfo) for target returned %X\n", Status) ;
+ }
+#endif
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ goto CopyFileAbort_5;
+ }
+ }
+
+CopyFileAbort_5:
+
+ //
+ // With append mode, resize target file and reset its dates on error
+ //
+
+ if (RetCode && (CopyOption & DCPY_APPEND)) {
+
+ //
+ // Ignore errors, since we can't do any recovery
+ //
+
+ EndOfFileInfo.EndOfFile = StandardInfo.EndOfFile;
+
+ do {
+ Status = NtSetInformationFile(TargetHandle,
+ &IoStatus,
+ &EndOfFileInfo,
+ sizeof (EndOfFileInfo),
+ FileEndOfFileInformation
+ );
+ } while (RetryIO(Status, TargetHandle));
+
+ AllocationInfo.AllocationSize = StandardInfo.EndOfFile;
+
+ do {
+ Status = NtSetInformationFile(TargetHandle,
+ &IoStatus,
+ &AllocationInfo,
+ sizeof (AllocationInfo),
+ FileAllocationInformation
+ );
+ } while (RetryIO(Status, TargetHandle));
+
+ do {
+ Status = NtSetInformationFile(TargetHandle,
+ &IoStatus,
+ &TargetBasicInfo,
+ sizeof (TargetBasicInfo),
+ FileBasicInformation
+ );
+ } while (RetryIO(Status, TargetHandle));
+ }
+
+CopyFileAbort_3:
+
+ //
+ // With create/replace mode: delete target file on error
+ //
+
+ if (RetCode) {
+ if ((ActionTaken == FILE_CREATED) || (ActionTaken == FILE_SUPERSEDED)) {
+
+ //
+ // Don't check for error, since we can't do any recovery
+ //
+
+ DispositionInfo.DeleteFile = TRUE;
+ do {
+ Status = NtSetInformationFile(TargetHandle,
+ &IoStatus,
+ &DispositionInfo,
+ sizeof (DispositionInfo),
+ FileDispositionInformation);
+ } while (RetryIO(Status, TargetHandle));
+ }
+ }
+
+ //
+ // Close the target file
+ //
+
+ NtClose(TargetHandle) ;
+
+CopyFileAbort_2:
+
+ //
+ // Close the source file
+ //
+
+ // Free Unicode string
+ //
+ if (TargetPath_U.Length > 0)
+ RtlFreeUnicodeString (&TargetPath_U);
+
+ NtClose(SourceHandle);
+
+CopyFileAbort_1:
+
+ //
+ // Return the error to the caller.
+ //
+
+ return(RetCode) ;
+}
+
+
+BOOLEAN
+CheckNeedEa(
+ PFILE_FULL_EA_INFORMATION EaList
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks for a NEED EA in an EA list
+
+Arguments:
+
+ EaList - NT format EA list
+
+Return Value:
+
+ FALSE if EA list has no NEED EAs.
+ TRUE if any of the EAs in the list are NEED EAs.
+
+--*/
+
+{
+ while (TRUE) {
+ if(EaList->Flags & FILE_NEED_EA) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("This EA has needea set; returning 1\n");
+ }
+#endif
+ return(TRUE);
+ }
+ if (EaList->NextEntryOffset == 0L) {
+ break;
+ }
+ EaList = (PFILE_FULL_EA_INFORMATION) ((CHAR *) EaList + EaList->NextEntryOffset);
+ }
+ return FALSE;
+}
+
+
+APIRET
+CreateTargetFromNul(
+ IN PSTRING TargetPath,
+ IN HANDLE ParentTargetHandle,
+ IN ULONG TargetType,
+ IN ULONG CopyOption
+ )
+
+/*++
+
+Routine Description:
+
+ This routine create/open a target file.
+
+Arguments:
+
+ TargetPath - name of target file. if a parent handle is passed in,
+ this contains only the last component in the path.
+
+ ParentTargetHandle - handle to parent directory of target file
+
+ TargetType - whether target is file, dir, device, named pipe
+
+ CopyOption - append, replace, fail if eas not supported
+
+Return Value:
+
+ TBS.
+
+--*/
+
+{
+ APIRET RetCode;
+ NTSTATUS Status;
+ USHORT fsCopyFileFlags = 0 ;
+ HANDLE TargetHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ ULONG CreateDisposition;
+ UNICODE_STRING TargetPath_U;
+
+ fsCopyFileFlags |= CFF_TARGET_IS_FILE *
+ (TargetType != COT_DEVICE
+ && TargetType != COT_OTHER) ;
+
+ //
+ // based on the append and replace flags, initialize CreateDisposition.
+ //
+
+ if (fsCopyFileFlags & CFF_TARGET_IS_FILE) {
+ if (CopyOption & DCPY_APPEND) {
+ CreateDisposition = FILE_OPEN_IF;
+ }
+ else if (CopyOption & DCPY_EXISTING) {
+ CreateDisposition = FILE_OVERWRITE_IF;
+ }
+ else {
+ CreateDisposition = FILE_CREATE;
+ }
+ }
+
+ //
+ // If the target is a device or named pipe, just open it.
+ // NOTE: Since the target cannot be a device in a tree copy, there's
+ // no danger here of these flags being reset when copy_file()
+ // is called by copy_tree()
+ //
+
+ else {
+ CopyOption &= ~(DCPY_EXISTING | DCPY_APPEND);
+ CreateDisposition = FILE_OPEN;
+ }
+
+ //
+ // create/open target
+ //
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &TargetPath_U,
+ TargetPath,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("CreateTargetFromNul: no memory for Unicode Conversion\n");
+ }
+#endif
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &TargetPath_U,
+ OBJ_CASE_INSENSITIVE,
+ ParentTargetHandle,
+ NULL);
+
+ do {
+ Status = NtCreateFile(&TargetHandle,
+ FILE_WRITE_ATTRIBUTES | DELETE | FILE_READ_ATTRIBUTES |
+ FILE_WRITE_DATA | FILE_ADD_SUBDIRECTORY | SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ,
+ CreateDisposition,
+ FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("CreateTargetFromNul: NtCreateFile for target returned %lx\n", Status) ;
+ }
+#endif
+ }
+
+ //
+ // Close the target file
+ //
+
+ NtClose(TargetHandle) ;
+
+ //
+ // Free Unicode string
+ //
+
+ if (TargetPath_U.Length > 0)
+ RtlFreeUnicodeString (&TargetPath_U);
+
+ //
+ // Return the error to the caller.
+ //
+
+ return(RetCode) ;
+}
diff --git a/private/os2/client/dlldbcs.c b/private/os2/client/dlldbcs.c
new file mode 100644
index 000000000..5beaf6f43
--- /dev/null
+++ b/private/os2/client/dlldbcs.c
@@ -0,0 +1,163 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ dlldbcs.c
+
+Abstract:
+
+ This module contains the multibyte string functions.
+
+Author:
+
+ Akihiko Sasaki (V-AkihiS) 23-June-1993
+
+Revision History:
+
+--*/
+
+#ifdef DBCS
+
+#include "os2dll.h"
+#include "dlldbcs.h"
+#include "conrqust.h"
+#include "os2win.h"
+
+
+unsigned char * _CRTAPI1
+Od2MultiByteStrchr(
+ const unsigned char *string,
+ unsigned short c
+ )
+{
+ const unsigned char ch = (unsigned char)c;
+
+ while (*string != ch) {
+ if (Ow2NlsIsDBCSLeadByte(*string, SesGrp->DosCP)) {
+ string++;
+ }
+ if (*string == '\0')
+ return NULL;
+ string++;
+ }
+ return (unsigned char *)string;
+}
+
+unsigned char * _CRTAPI1
+Od2MultiByteStrrchr(
+ const unsigned char *string,
+ unsigned short c
+ )
+{
+ const unsigned char ch = (unsigned char)c;
+ const unsigned char *lastoccurence = NULL;
+
+ while (1) {
+ if (Ow2NlsIsDBCSLeadByte(*string, SesGrp->DosCP)) {
+ string++;
+ } else {
+ if (*string == ch)
+ lastoccurence = string;
+ }
+ if (*string == '\0')
+ return (unsigned char *)lastoccurence;
+ string++;
+ }
+}
+
+unsigned char * _CRTAPI1
+Od2MultiByteStrstr(
+ const unsigned char *string1,
+ const unsigned char *string2
+ )
+{
+ if (*string2 == '\0')
+ return (unsigned char *)string1;
+ while((string1 = Od2MultiByteStrchr(string1, *string2)) != NULL) {
+ const unsigned char *substring1 = string1;
+ const unsigned char *substring2 = string2;
+
+ while (1) {
+ if (Ow2NlsIsDBCSLeadByte(*substring1, SesGrp->DosCP)) {
+ if (Ow2NlsIsDBCSLeadByte(*substring2, SesGrp->DosCP)) {
+ if (*substring1++ == *substring2++) {
+ if (*substring2 == '\0')
+ if (*substring1 == '\0')
+ return (unsigned char *)string1;
+ else
+ return NULL;
+ else if (*substring1++ != *substring2++)
+ break;
+ } else {
+ if (*substring1 == '\0' || *substring2 == '\0')
+ return NULL;
+ substring1 +=2;
+ substring2 +=2;
+ }
+ } else {
+ if (*substring2 == '\0') {
+ return (unsigned char *)string1;
+ } else {
+ substring1++;
+ if (*substring1 == '\0')
+ return NULL;
+ substring1++;
+ substring2++;
+ }
+ }
+ } else {
+ if (Ow2NlsIsDBCSLeadByte(*substring2, SesGrp->DosCP)) {
+ if (*substring1 == '\0') {
+ return NULL;
+ } else {
+ substring2++;
+ if (*substring2 == '\0')
+ return NULL;
+ substring1++;
+ substring2++;
+ }
+
+ } else {
+ if (*substring2 == '\0')
+ return (unsigned char *)string1;
+ else if (*substring1 == '\0')
+ return NULL;
+ else if (*substring1++ != *substring2++)
+ break;
+ }
+ }
+ }
+ string1++;
+ }
+ return NULL;
+}
+
+unsigned char * _CRTAPI1
+Od2MultiByteStrpbrk(
+ const unsigned char *string1,
+ const unsigned char *string2
+ )
+{
+ const unsigned char *substring1, *substring2;
+
+ substring1 = string1;
+ while (*substring1 != '\0') {
+ substring2 = string2;
+ if (Ow2NlsIsDBCSLeadByte(*substring1, SesGrp->DosCP)) {
+ substring1++;
+ if (*substring1 == '\0')
+ return NULL;
+ } else {
+ while (*substring2 != '\0') {
+ if (*substring1 == *substring2)
+ return (unsigned char *)substring1;
+ substring2++;
+ }
+ }
+ substring1++;
+ }
+ return NULL;
+}
+#endif
diff --git a/private/os2/client/dlldir.c b/private/os2/client/dlldir.c
new file mode 100644
index 000000000..58e892dab
--- /dev/null
+++ b/private/os2/client/dlldir.c
@@ -0,0 +1,1705 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dlldir.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 directory manipulation API calls
+
+Author:
+
+ Therese Stowell (thereses) 19-Oct-1989
+
+Revision History:
+
+ Yaron Shamir (yarons) 20-May-1991
+ Fixed all bug found by Filio test suite (GetCurrentDirectory return
+ upper case; various error codes)
+ Yaron Shamir (yarons) 22-May-1991
+ Converted to Unicode.
+
+
+--*/
+
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FILESYS
+#include "os2dll.h"
+#include "os2win.h"
+#include <direct.h>
+
+VOID
+SetLocalCurrentDirectory(
+ PSTRING CurrentDirectoryString,
+ HANDLE CurrentDirectoryHandle
+ );
+
+ULONG
+Od2Oem_getdcwd(
+ ULONG DiskNumber,
+ LPSTR lpBuffer,
+ DWORD nBufferLength
+ );
+
+ULONG
+Od2Oem_chdrive(
+ ULONG DiskNumber
+ );
+
+ULONG
+Od2Oem_chdir_chdrive(
+ LPSTR lpBuffer
+ );
+
+APIRET
+GetCurrentDirectoryW(
+ DWORD nBufferLength,
+ LPWSTR lpBuffer
+ );
+
+APIRET
+Od2GetCurrentDirectory(
+ IN ULONG DiskNumber,
+ OUT PSTRING *CurrentDirectoryString,
+ OUT PHANDLE CurrentDirectoryHandle,
+ OUT PULONG DirectoryNameLength,
+ IN BOOLEAN Verify
+ );
+// DiskName is used by VerifyDriveExists
+
+
+// BUGBUG at some point, need to read config.sys and set up symbolic links
+// for drives.
+
+
+APIRET
+VerifyDriveExists(
+ IN ULONG DiskNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine verifies that a drive exists
+
+Arguments:
+
+ DiskNumber - 1-based drive number
+
+Return Value:
+
+
+
+--*/
+
+{
+ CHAR DiskName[] = "\\OS2SS\\DRIVES\\D:\\";
+ STRING DiskNameString;
+ UNICODE_STRING DiskNameString_U;
+ NTSTATUS Status;
+ HANDLE DiskHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ APIRET RetCode;
+
+ DiskName[DRIVE_LETTER+FILE_PREFIX_LENGTH] = (CHAR) (DiskNumber + '@');
+ Od2InitMBString(&DiskNameString,DiskName);
+
+ //
+ // UNICODE conversion -
+ //
+ RetCode = Od2MBStringToUnicodeString(
+ &DiskNameString_U,
+ &DiskNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ ASSERT ( FALSE );
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("VerifyDriveExists: no memory for Unicode Conversion\n");
+ }
+#endif
+ //return STATUS_NO_MEMORY;
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ InitializeObjectAttributes(
+ &Obja,
+ &DiskNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ do {
+ Status = NtOpenFile(&DiskHandle,
+ FILE_READ_DATA | SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ // BUGBUG since we're opening the root directory, do we set FILE_DIRECTORY_FILE?
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+
+ RtlFreeUnicodeString (&DiskNameString_U);
+
+ if ( NT_SUCCESS(Status) ) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("calling NtOpenFile with %s succeeded.\n",DiskName);
+ }
+#endif
+ NtClose(DiskHandle);
+ }
+ else {
+ // from dllname.c lines ~1060
+ // force return of ERROR_INVALID_DRIVE
+ //return (ERROR_INVALID_DRIVE);
+ // Fixed by MJarus, 2/16/93 :
+ // The previous was done by BeniL since Or2MapStatus
+ // returns ERROR_PATH_NOT_FOUND in some cases when
+ // it works thru the network
+ // But it has to check some special codes (to pass
+ // the CT herror)
+ if (( Status == STATUS_NO_MEDIA_IN_DEVICE ) ||
+ ( Status == STATUS_DEVICE_NOT_READY ))
+ {
+ RetCode = ERROR_NOT_READY;
+ } else if ( Status == STATUS_MEDIA_WRITE_PROTECTED )
+ {
+ RetCode = ERROR_WRITE_PROTECT;
+ } else
+ {
+ RetCode = ERROR_INVALID_DRIVE;
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("calling NtOpenFile with %s failed.\n",DiskName);
+ DbgPrint("status is %X, RetCode %lu.\n", Status, RetCode);
+ }
+#endif
+ }
+ return RetCode;
+}
+
+
+APIRET
+DosSetDefaultDisk(
+ IN ULONG DiskNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the current drive for a process
+
+Arguments:
+
+ DiskNumber - 1-based drive number
+
+Return Value:
+
+ ERROR_INVALID_DRIVE - the specified drive doesn't exist
+
+--*/
+
+{
+ PSTRING DirectoryNameString;
+ APIRET RetCode;
+ ULONG DirectoryLength;
+ HANDLE CurDirHandle;
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosSetDefaultDisk";
+ #endif
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("%s %d \n", RoutineName, DiskNumber);
+ }
+#endif
+ if (DiskNumber > MAX_DRIVES)
+ return ERROR_INVALID_DRIVE;
+ RetCode = VerifyDriveExists(DiskNumber);
+ if ( RetCode ) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("%s %d Failed on VerifyDriveExists Rc == %lu\n",
+ RoutineName, DiskNumber, RetCode);
+ }
+#endif
+ return (RetCode);
+ }
+
+ //
+ // get rid of the old default disk's current directory
+ // and set it to the current dir of default disk
+ //
+
+ if (Od2CurrentDisk != DiskNumber-1) {
+ if (Od2Oem_chdrive(DiskNumber)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("%s %d Failed on _chdrive\n",
+ RoutineName, DiskNumber);
+ }
+#endif
+ return(ERROR_INVALID_DRIVE);
+ }
+ RetCode = Od2GetCurrentDirectory(DiskNumber - 1,
+ &DirectoryNameString,
+ &CurDirHandle,
+ &DirectoryLength,
+ TRUE
+ );
+ if (RetCode != NO_ERROR) {
+ return(RetCode);
+ }
+
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ SetLocalCurrentDirectory(DirectoryNameString,CurDirHandle);
+ Od2CurrentDisk = DiskNumber-1;
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RtlFreeHeap(Od2Heap, 0, DirectoryNameString);
+ }
+
+ return NO_ERROR;
+}
+
+
+APIRET
+DosQueryCurrentDisk(
+ OUT PULONG DiskNumber,
+ OUT PULONG LogicalDrives
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the current drive for a process and a bitmap of
+ all existing drives.
+
+Arguments:
+
+ DiskNumber - where to return the current drive
+
+ LogicalDrives - where to return a bitmap of all existing drives.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG LogicalDrivesMap;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosQueryCurrentDisk";
+ #endif
+
+
+ if (!(LogicalDrivesMap = GetLogicalDrives())) {
+ return ERROR_INVALID_DRIVE;
+ }
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ try {
+ *DiskNumber = Od2CurrentDisk + 1;
+ *LogicalDrives = LogicalDrivesMap;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ LogicalDrivesMap = 0;
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (!LogicalDrivesMap)
+ {
+ Od2ExitGP();
+ return ERROR_INVALID_ADDRESS;
+ }
+ return NO_ERROR;
+}
+
+VOID
+AllocateCurrentDirectory(
+ PSTRING CurrentDirectoryString,
+ HANDLE CurrentDirectoryHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine saves the current directory for the current drive.
+
+Arguments:
+
+ CurrentDirectoryString - new current directory
+
+ CurrentDirectoryHandle - handle to new open current directory
+
+Return Value:
+
+ none.
+
+Note:
+
+ The caller must have the FileLock.
+
+--*/
+
+{
+ //
+ // if (root dir)
+ // pCurDir = NULL;
+ //
+
+ if (CurrentDirectoryString->Length == FILE_PREFIX_LENGTH+ROOTDIRLENGTH) {
+ Od2CurrentDirectory.pCurDir = NULL;
+ }
+
+ //
+ // else
+ // store the dir handle
+ // allocate heap space for string and copy it in
+ //
+
+ else {
+ Od2CurrentDirectory.NtHandle = CurrentDirectoryHandle;
+
+ //
+ // we allocate space for the CURRENT_DIRECTORY_STRING and the string
+ // itself all at once.
+ //
+
+ Od2CurrentDirectory.pCurDir = RtlAllocateHeap(Od2Heap, 0,
+ sizeof(CURRENT_DIRECTORY_STRING) +
+ CurrentDirectoryString->Length+1); // +1 is for NUL
+ if (Od2CurrentDirectory.pCurDir == NULL) {
+#if DBG
+ KdPrint(( "OS2: AllocateCurrentDirectory, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return;
+ }
+
+ Od2CurrentDirectory.pCurDir->CurDirString.Length =
+ CurrentDirectoryString->Length;
+ Od2CurrentDirectory.pCurDir->CurDirString.MaximumLength =
+ (USHORT) (CurrentDirectoryString->Length+1);
+
+ //
+ // heap space was allocated for string after the CURRENT_DIRECTORY_STRING
+ // structure. set up string pointer here (buffer). then copy the
+ // string in.
+ //
+
+ Od2CurrentDirectory.pCurDir->CurDirString.Buffer = (PSZ) (((ULONG) (Od2CurrentDirectory.pCurDir)) +
+ sizeof(CURRENT_DIRECTORY_STRING));
+ RtlMoveMemory(Od2CurrentDirectory.pCurDir->CurDirString.Buffer,
+ CurrentDirectoryString->Buffer,
+ CurrentDirectoryString->Length+1
+ );
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("new current dir is %s\n",Od2CurrentDirectory.pCurDir->CurDirString.Buffer);
+ DbgPrint("Length is %d\n",Od2CurrentDirectory.pCurDir->CurDirString.Length);
+ DbgPrint("MaximumLength is %d\n",Od2CurrentDirectory.pCurDir->CurDirString.MaximumLength);
+ }
+#endif
+ }
+}
+
+VOID
+FreeCurrentDirectory(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees the current directory for the current drive
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+Note:
+
+ We let the server free the open handle to the directory.
+
+ File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ if (Od2CurrentDirectory.pCurDir != NULL) {
+ RtlFreeHeap( Od2Heap, 0, Od2CurrentDirectory.pCurDir );
+ Od2CurrentDirectory.pCurDir = NULL;
+ }
+}
+
+VOID
+SetLocalCurrentDirectory(
+ PSTRING CurrentDirectoryString,
+ HANDLE CurrentDirectoryHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees the old current directory for the current drive
+ and sets up the new one.
+
+Arguments:
+
+ CurrentDirectoryString - new current directory
+
+ CurrentDirectoryHandle - handle to new open current directory
+
+Return Value:
+
+ none.
+
+Note:
+
+ File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ FreeCurrentDirectory();
+ AllocateCurrentDirectory(CurrentDirectoryString,
+ CurrentDirectoryHandle
+ );
+}
+
+
+
+APIRET
+DosSetCurrentDir(
+ IN PSZ DirectoryName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the current directory for a process.
+
+Arguments:
+
+ DirectoryName - new current directory
+
+Return Value:
+
+ ERROR_PATH_NOT_FOUND - new current directory doesn't exist
+
+ ERROR_NOT_ENOUGH_MEMORY - couldn't allocate port memory to hold dirname
+
+--*/
+
+{
+ NTSTATUS Status;
+ APIRET RetCode;
+ STRING CanonicalNameString;
+ UNICODE_STRING CanonicalNameString_U;
+ HANDLE DirHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ ULONG DiskNumber;
+ ULONG FileType;
+ ULONG FileFlags;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosSetCurrentDir";
+ #endif
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("%s: %s\n", RoutineName, DirectoryName);
+ }
+#endif
+
+ //
+ // Canonicalize the directory string
+ //
+
+ RetCode = Od2Canonicalize(DirectoryName,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &CanonicalNameString,
+ NULL,
+ &FileFlags,
+ &FileType
+ );
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("%s: Od2Canonicalize returned %d\n",
+ RoutineName, RetCode);
+ }
+#endif
+ return(ERROR_PATH_NOT_FOUND);
+// return RetCode;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("canonicalize returned %s\n",CanonicalNameString.Buffer);
+ }
+#endif
+
+ if ((FileType & (FILE_TYPE_NMPIPE | FILE_TYPE_DEV | FILE_TYPE_UNC | FILE_TYPE_PSDEV)) ||
+ (FileFlags & CANONICALIZE_META_CHARS_FOUND)) {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("not a filename or metas found\n");
+ }
+#endif
+ return ERROR_PATH_NOT_FOUND;
+ }
+
+ ASSERT (CanonicalNameString.Buffer[FILE_PREFIX_LENGTH+COLON] == ':');
+ ASSERT (CanonicalNameString.Buffer[FILE_PREFIX_LENGTH+FIRST_SLASH] != '\0');
+
+ //
+ // Open the directory string
+ //
+ //
+ // UNICODE conversion -
+ //
+ RetCode = Od2MBStringToUnicodeString(
+ &CanonicalNameString_U,
+ &CanonicalNameString,
+ TRUE);
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("%s: no memory for Unicode Conversion\n",
+ RoutineName);
+ }
+#endif
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalNameString_U,
+ OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
+ NULL,
+ NULL);
+
+ do {
+ Status = NtOpenFile(&DirHandle,
+ FILE_LIST_DIRECTORY | SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+
+ RtlFreeUnicodeString (&CanonicalNameString_U);
+ if (!NT_SUCCESS(Status)) {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtOpenFile failed.\n");
+ DbgPrint("St == %X\n",Status);
+ }
+#endif
+ return ERROR_PATH_NOT_FOUND;
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtOpenFile succeeded.\n");
+ }
+#endif
+
+ //
+ // now that the file is opened, we need to make sure that it isn't a
+ // device or named pipe that Canonicalize didn't detect.
+ //
+
+ if (CheckFileType(DirHandle,FILE_TYPE_NMPIPE | FILE_TYPE_DEV)) {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ NtClose(DirHandle);
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("not a filename\n");
+ }
+#endif
+ return ERROR_PATH_NOT_FOUND;
+ }
+
+ if (CanonicalNameString.Buffer[FILE_PREFIX_LENGTH+DRIVE_LETTER] > 'Z')
+ DiskNumber = CanonicalNameString.Buffer[FILE_PREFIX_LENGTH+DRIVE_LETTER] - 'a'; // zero-based drive number
+ else
+ DiskNumber = CanonicalNameString.Buffer[FILE_PREFIX_LENGTH+DRIVE_LETTER] - 'A'; // zero-based drive number
+
+ if (Od2Oem_chdir_chdrive(DirectoryName)){
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ NtClose(DirHandle);
+ return ERROR_PATH_NOT_FOUND;
+ }
+
+ //
+ // if the new curdir is the root, we don't keep the handle to it open
+ //
+
+ if (CanonicalNameString.Length == FILE_PREFIX_LENGTH+ROOTDIRLENGTH) { // root directory
+ NtClose(DirHandle);
+ DirHandle = NULL;
+ }
+
+ NtClose(Od2DirHandles[DiskNumber]);
+ Od2DirHandles[DiskNumber] = DirHandle;
+ Od2DirHandlesIsValid[DiskNumber] = TRUE;
+
+ //
+ // if the directory was change successfully, we need to
+ // update Od2CurrentDirectory because we maintain a copy of
+ // that information in the DLL.
+ //
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (DiskNumber == Od2CurrentDisk) {
+ SetLocalCurrentDirectory(&CanonicalNameString,DirHandle);
+ }
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return NO_ERROR;
+}
+
+VOID
+SetUpRootDirectory(
+ IN ULONG DiskNumber,
+ OUT PSTRING *RootDirectoryString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the "\d:\" where d is the drive letter specified.
+ The returned string is allocated from the heap.
+
+Arguments:
+
+ DiskNumber - 0-based drive number
+
+ RootDirectoryString - where to return the root directory. heap
+ space is allocated and the pointer to it is stored here.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CHAR DiskName[] = "\\OS2SS\\DRIVES\\D:\\";
+
+ DiskName[DRIVE_LETTER+FILE_PREFIX_LENGTH] = (CHAR) (DiskNumber + 'A');
+ *RootDirectoryString = RtlAllocateHeap(Od2Heap, 0,
+ sizeof(STRING) +
+ FILE_PREFIX_LENGTH + DRIVE_LETTER_SIZE + 1
+ );
+ if (*RootDirectoryString == NULL) {
+#if DBG
+ KdPrint(( "OS2: SetUpRootDirectory, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return;
+ }
+
+ (*RootDirectoryString)->Length = FILE_PREFIX_LENGTH+DRIVE_LETTER_SIZE;
+ (*RootDirectoryString)->MaximumLength = FILE_PREFIX_LENGTH+DRIVE_LETTER_SIZE + 1;
+ (*RootDirectoryString)->Buffer = (PSZ) (((ULONG) (*RootDirectoryString)) +
+ sizeof(STRING));
+ RtlMoveMemory((*RootDirectoryString)->Buffer,
+ DiskName,
+ FILE_PREFIX_LENGTH+DRIVE_LETTER_SIZE + 1
+ );
+}
+
+
+
+APIRET
+Od2GetCurrentDirectory(
+ IN ULONG DiskNumber,
+ OUT PSTRING *CurrentDirectoryString,
+ OUT PHANDLE CurrentDirectoryHandle,
+ OUT PULONG DirectoryNameLength,
+ IN BOOLEAN Verify
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the current directory for a particular drive.
+ The curdir string is returned in an allocated buffer, beginning with
+ "\d:\".
+
+Arguments:
+
+ DiskNumber - 0-based drive number
+
+ CurrentDirectoryString - where to return the current directory. heap
+ space is allocated and the pointer to it is stored here.
+
+ CurrentDirectoryHandle - where to return NT handle to current directory.
+
+ DirectoryNameLength - on output, length of current directory, not including
+ NULL.
+
+ Verify - whether to verify that path still exists. we do for
+ DosQueryCurrentDir. we don't for path canonicalization.
+
+Return Value:
+
+ ERROR_INVALID_DRIVE - specified drive doesn't exist
+
+ ERROR_BUFFER_OVERFLOW - current directory won't fit in buffer
+
+--*/
+
+{
+ HANDLE NtDirectoryHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ CHAR DiskName[] = "\\OS2SS\\DRIVES\\D:\\";
+ STRING RootDirString;
+ NTSTATUS Status;
+ APIRET RetCode;
+ UNICODE_STRING TmpString_U;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "GetCurrentDirectory";
+ #endif
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("%s: disk # %ld, Current %ld\n",
+ RoutineName, DiskNumber, Od2CurrentDisk);
+ }
+#endif
+
+ //
+ // we maintain the current directory for the current drive in the DLL,
+ // so if the requested drive is the current drive, we don't have to
+ // call the server.
+ //
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (DiskNumber == Od2CurrentDisk) {
+
+ //
+ // verify that current dir still exists. it doesn't matter whether
+ // the contents of the drive have changed. if the current directory
+ // on floppy a: is "os2\bin" and floppy b: is inserted into the
+ // drive, if "os2\bin" exists on floppy b:, the current directory
+ // is not changed. if "os2\bin" does not exist on floppy b:, the
+ // current directory is set to the root. because we're not trying
+ // to verify that the volume hasn't changed, we need to call
+ // NtOpenFile, not NtQueryDirectoryFile, because open takes a path
+ // rather than a handle.
+ //
+ // if the current directory is the root, verify that the drive exists.
+ //
+
+ if (Od2CurrentDirectory.pCurDir == NULL) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (Verify) {
+ if (RetCode = VerifyDriveExists(DiskNumber+1)) {
+ return (RetCode);
+ }
+ }
+ SetUpRootDirectory(DiskNumber,CurrentDirectoryString);
+ if (*CurrentDirectoryString == NULL) {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ *DirectoryNameLength = FILE_PREFIX_LENGTH+DRIVE_LETTER_SIZE;
+ *CurrentDirectoryHandle = NULL;
+ return NO_ERROR;
+ }
+
+ //
+ // if caller wants it, make sure that current directory path exists.
+ //
+
+ if (Verify) {
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &TmpString_U,
+ &(Od2CurrentDirectory.pCurDir->CurDirString),
+ TRUE);
+
+ InitializeObjectAttributes(&Obja,
+ &TmpString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ do {
+ Status = NtOpenFile(&NtDirectoryHandle,
+ FILE_LIST_DIRECTORY | SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+ RtlFreeUnicodeString (&TmpString_U);
+
+ if (!NT_SUCCESS(Status)) {
+
+ // current directory path doesn't exist, so
+ // set current directory to root. if it fails, ignore the
+ // error.
+ //
+
+ DiskName[DRIVE_LETTER+FILE_PREFIX_LENGTH] = (CHAR) (DiskNumber + 'A');
+ Od2InitMBString(&RootDirString,DiskName);
+ SetLocalCurrentDirectory(&RootDirString,NULL);
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (Od2Oem_chdir_chdrive(RootDirString.Buffer)){
+ return ERROR_INVALID_DRIVE;
+ }
+ NtClose(Od2DirHandles[DiskNumber]);
+ Od2DirHandles[DiskNumber] = NULL;
+ Od2DirHandlesIsValid[DiskNumber] = TRUE;
+ if (RetCode = VerifyDriveExists(DiskNumber+1)) {
+ return (RetCode);
+ }
+ else {
+ SetUpRootDirectory(DiskNumber,CurrentDirectoryString);
+ if (*CurrentDirectoryString == NULL) {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ *DirectoryNameLength = FILE_PREFIX_LENGTH+DRIVE_LETTER_SIZE;
+ *CurrentDirectoryHandle = NULL;
+ return NO_ERROR;
+ }
+ }
+ NtClose(NtDirectoryHandle);
+ }
+
+ //
+ // allocate heap space to return current directory string in
+ //
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("current dir is %s\n",Od2CurrentDirectory.pCurDir->CurDirString.Buffer);
+ DbgPrint("Length is %d\n",Od2CurrentDirectory.pCurDir->CurDirString.Length);
+ DbgPrint("MaximumLength is %d\n",Od2CurrentDirectory.pCurDir->CurDirString.MaximumLength);
+ }
+#endif
+
+ *CurrentDirectoryString = RtlAllocateHeap(Od2Heap, 0,
+ sizeof(STRING) +
+ Od2CurrentDirectory.pCurDir->CurDirString.Length+1
+ );
+ if (*CurrentDirectoryString == NULL) {
+#if DBG
+ KdPrint(( "OS2: Od2GetCurrentDirectory, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ (*CurrentDirectoryString)->Length =
+ Od2CurrentDirectory.pCurDir->CurDirString.Length;
+ (*CurrentDirectoryString)->MaximumLength =
+ (USHORT) (Od2CurrentDirectory.pCurDir->CurDirString.Length + 1);
+
+ //
+ // heap space was allocated for string after the STRING
+ // structure. set up string pointer here (buffer). then copy the
+ // string in. don't copy the drive letter.
+ //
+
+ (*CurrentDirectoryString)->Buffer = (PSZ) (((ULONG) (*CurrentDirectoryString)) +
+ sizeof(STRING));
+ RtlMoveMemory((*CurrentDirectoryString)->Buffer,
+ Od2CurrentDirectory.pCurDir->CurDirString.Buffer,
+ Od2CurrentDirectory.pCurDir->CurDirString.Length + 1
+ );
+
+ //
+ // Upcase string, since OS2 expects this (at least for FAT filesys)
+ //
+
+ RtlUpperString( *CurrentDirectoryString, *CurrentDirectoryString );
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("returning the following current dir string:\n");
+ DbgPrint("current dir is %s\n",(*CurrentDirectoryString)->Buffer);
+ DbgPrint("Length is %d\n",(*CurrentDirectoryString)->Length);
+ DbgPrint("MaximumLength is %d\n",(*CurrentDirectoryString)->MaximumLength);
+ }
+#endif
+
+ *DirectoryNameLength = (*CurrentDirectoryString)->Length;
+ *CurrentDirectoryHandle = Od2CurrentDirectory.NtHandle;
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return NO_ERROR;
+ }
+
+ //
+ // the requested current directory is not on the current drive.
+ //
+
+ else {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ *CurrentDirectoryString = RtlAllocateHeap(Od2Heap, 0,
+ CCHMAXPATH + sizeof(STRING) + DRIVE_LETTER_SIZE + FILE_PREFIX_LENGTH);
+ if (*CurrentDirectoryString == NULL) {
+#if DBG
+ KdPrint(( "OS2: Od2GetCurrentDirectory, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlZeroMemory( *CurrentDirectoryString, CCHMAXPATH + sizeof(STRING) + DRIVE_LETTER_SIZE + FILE_PREFIX_LENGTH);
+
+ if (Od2DirHandlesIsValid[DiskNumber] == FALSE) {
+ RetCode = Od2InitCurrentDir(DiskNumber);
+ if (RetCode != NO_ERROR) {
+ RtlFreeHeap(Od2Heap, 0, *CurrentDirectoryString);
+ return(RetCode);
+ }
+ }
+
+ (*CurrentDirectoryString)->Buffer = (PSZ) (((ULONG) (*CurrentDirectoryString)) +
+ sizeof(STRING));
+ RtlMoveMemory((*CurrentDirectoryString)->Buffer, "\\OS2SS\\DRIVES\\", FILE_PREFIX_LENGTH);
+ if (Od2Oem_getdcwd((DiskNumber + 1),
+ (PSZ) (((*CurrentDirectoryString)->Buffer) + FILE_PREFIX_LENGTH),
+ CCHMAXPATH + DRIVE_LETTER_SIZE)) {
+ RtlFreeHeap(Od2Heap,0,*CurrentDirectoryString);
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ (*CurrentDirectoryString)->Length = strlen((*CurrentDirectoryString)->Buffer);
+ (*CurrentDirectoryString)->MaximumLength = (*CurrentDirectoryString)->Length + 1;
+ *DirectoryNameLength = (*CurrentDirectoryString)->Length;
+ *CurrentDirectoryHandle = Od2DirHandles[DiskNumber];
+ return NO_ERROR;
+ }
+ ASSERT (FALSE); // should never get here
+}
+
+
+APIRET
+DosQueryCurrentDir(
+ IN ULONG DiskNumber, // 1-based drive number
+ OUT PSZ DirectoryName,
+ IN OUT PULONG DirectoryNameLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the current directory for a particular drive and
+ process.
+
+Arguments:
+
+ DiskNumber - which drive to use
+
+ DirectoryName - where to return the current directory
+
+ DirectoryNameLength - on input, length of buffer. on output, length of
+ current directory.
+
+Return Value:
+
+ ERROR_INVALID_DRIVE - specified drive doesn't exist
+
+ ERROR_BUFFER_OVERFLOW - current directory won't fit in buffer
+
+--*/
+
+{
+ PSTRING DirectoryNameString;
+ ULONG Disk; // 0-based drive number
+ APIRET RetCode;
+ ULONG DirectoryLength,BufferLength;
+ HANDLE CurDirHandle;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosQueryCurrentDir";
+ #endif
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("%s: drive # %ld\n", RoutineName, DiskNumber);
+ }
+#endif
+ Disk = DiskNumber-1;
+ if (DiskNumber > MAX_DRIVES)
+ return ERROR_INVALID_DRIVE;
+ else if (DiskNumber == 0) {
+ Disk = Od2CurrentDisk;
+ }
+ try {
+ BufferLength = *DirectoryNameLength;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if( RetCode = VerifyDriveExists(Disk + 1))
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("DosQueryCurrentDir %d Failed on VerifyDriveExists Rc == %lu\n",
+ Disk + 1, RetCode);
+ }
+#endif
+ return (RetCode);
+ }
+
+ RetCode = Od2GetCurrentDirectory(Disk,
+ &DirectoryNameString,
+ &CurDirHandle,
+ &DirectoryLength,
+ TRUE
+ );
+
+ if (RetCode != NO_ERROR) {
+ return(RetCode);
+ }
+
+ //
+ // copy string to user's buffer. GetCurrentDirectory returns the
+ // current directory beginning with the drive letter, but the user
+ // doesn't get the drive letter, so start copying past it. we test for
+ // a non-root directory because we shouldn't touch the user's buffer
+ // if it is the root dir.
+ //
+
+ try {
+
+ //
+ // if not root directory, copy name
+ //
+ DirectoryLength -= (FILE_PREFIX_LENGTH + DRIVE_LETTER_SIZE);
+
+ if (DirectoryLength >= *DirectoryNameLength) {
+ RtlFreeHeap(Od2Heap,0,DirectoryNameString);
+ *DirectoryNameLength = DirectoryLength +1;
+ return ERROR_BUFFER_OVERFLOW;
+ }
+ strncpy(DirectoryName,
+ DirectoryNameString->Buffer + FILE_PREFIX_LENGTH + DRIVE_LETTER_SIZE,
+ DirectoryLength + 1
+ );
+ *DirectoryNameLength = DirectoryLength +1;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("%s: length %ld and name %s\n",
+ RoutineName, *DirectoryNameLength, DirectoryName);
+ }
+#endif
+ RtlFreeHeap(Od2Heap,0,DirectoryNameString);
+ return NO_ERROR;
+}
+
+
+APIRET
+DosCreateDir(
+ IN PSZ DirectoryName,
+ IN PEAOP2 DirectoryAttributes OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine makes a directory.
+
+Arguments:
+
+ DirectoryName - name of directory
+
+ DirectoryAttributes - optional extended attributes for directory
+
+Return Value:
+
+ ERROR_PATH_NOT_FOUND - DirectoryName is a device or pipe name.
+
+ ERROR_FILE_NOT_FOUND - some component of DirectoryName doesn't exist.
+
+Note:
+ The FileLock must be acquired in the calling procedure
+
+--*/
+
+{
+ APIRET RetCode;
+ STRING CanonicalNameString;
+ UNICODE_STRING CanonicalNameString_U;
+ ULONG FileType;
+ ULONG FileFlags;
+ USHORT DeviceAttribute;
+ HANDLE DirHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("entering MkDir with %s\n",DirectoryName);
+ }
+#endif
+
+ RetCode = Od2Canonicalize(DirectoryName,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &CanonicalNameString,
+ &DirHandle,
+ &FileFlags,
+ &FileType
+ );
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("CreateDir: Od2Canonicalize returned %d\n", RetCode);
+ }
+#endif
+ if (RetCode == ERROR_FILE_NOT_FOUND || RetCode == ERROR_INVALID_NAME) {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ }
+ return RetCode;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("canonicalize returned %s\n",CanonicalNameString.Buffer);
+ }
+#endif
+
+ if (FileType & (FILE_TYPE_NMPIPE | FILE_TYPE_DEV | FILE_TYPE_PSDEV)) {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return ERROR_ACCESS_DENIED;
+ }
+
+ if (FileFlags & CANONICALIZE_META_CHARS_FOUND) {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return ERROR_PATH_NOT_FOUND;
+ }
+ //
+ // UNICODE conversion -
+ //
+ RetCode = Od2MBStringToUnicodeString(
+ &CanonicalNameString_U,
+ &CanonicalNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("DosCreateDir: no memory for Unicode Conversion\n");
+ }
+#endif
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ DirHandle,
+ NULL);
+
+ RetCode = OpenCreatePath(&DirHandle,
+ FILE_WRITE_EA | SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ 0L,
+ 0L,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_CREATE,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+ DirectoryAttributes,
+ (PUSHORT) &FileType,
+ &DeviceAttribute,
+ TRUE
+ );
+
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ RtlFreeUnicodeString (&CanonicalNameString_U);
+
+ if (RetCode != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("DosCreateDir: OpenCreatePath returned %ld\n",RetCode);
+ }
+#endif
+ if (RetCode == ERROR_INVALID_NAME)
+ {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ }
+ return RetCode;
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("NtCreateFile successful\n");
+ }
+#endif
+
+ NtClose(DirHandle);
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("mkdir successful\n");
+ }
+#endif
+ return NO_ERROR;
+}
+
+APIRET
+DeleteObject(
+ IN PSZ ObjectName,
+ IN ULONG ObjectType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deletes a file or directory object.
+
+Arguments:
+
+ ObjectName - name of directory
+
+ ObjectType - type of object to delete
+
+Return Value:
+
+ TBS
+
+--*/
+
+{
+ NTSTATUS Status;
+ APIRET RetCode = NO_ERROR;
+ STRING CanonicalNameString;
+ WCHAR CurrentDirectory_U[CCHMAXPATH];
+ CHAR CurrentDirectory_A[CCHMAXPATH];
+ STRING CanonicalCurrentDirectory;
+ ANSI_STRING str_a;
+ UNICODE_STRING str_u;
+ UNICODE_STRING CanonicalNameString_U;
+ ULONG FileType;
+ ULONG FileFlags;
+ HANDLE ObjHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ FILE_DISPOSITION_INFORMATION FileDispInfo;
+
+ RetCode = Od2Canonicalize(ObjectName,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &CanonicalNameString,
+ &ObjHandle,
+ &FileFlags,
+ &FileType
+ );
+ if (RetCode != NO_ERROR)
+ {
+ if ((RetCode != ERROR_FILENAME_EXCED_RANGE)
+ && (RetCode != ERROR_NOT_READY)
+ && (RetCode != ERROR_WRITE_PROTECT)
+ /* && (RetCode != ERROR_FILE_NOT_FOUND) */
+ )
+ {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ }
+ return RetCode;
+ }
+
+ //
+ // Special handling of <boot-drive>:\config.sys
+ // opening this file is mapped to the OS/2 SS config.sys
+ //
+ if (Od2FileIsConfigSys(&CanonicalNameString, OPEN_ACCESS_READWRITE, &Status))
+ {
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to init for config.sys
+
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ }
+
+ FileFlags = 0;
+ FileType = FILE_TYPE_FILE;
+ ObjHandle = NULL;
+ }
+
+ if (FileFlags & CANONICALIZE_META_CHARS_FOUND)
+ {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return ERROR_PATH_NOT_FOUND;
+ }
+ if (FileFlags & CANONICALIZE_IS_ROOT_DIRECTORY)
+ {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return ERROR_ACCESS_DENIED;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("canonicalize returned %s\n",CanonicalNameString.Buffer);
+ }
+#endif
+
+ if (FileType & (FILE_TYPE_NMPIPE | FILE_TYPE_DEV | FILE_TYPE_PSDEV)) {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return ERROR_PATH_NOT_FOUND;
+ }
+
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &CanonicalNameString_U,
+ &CanonicalNameString,
+ TRUE);
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("DeleteObject: no memory for Unicode Conversion\n");
+ }
+#endif
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ ObjHandle,
+ NULL);
+
+ do {
+ Status = NtOpenFile(&ObjHandle,
+ DELETE,
+ &Obja,
+ &IoStatus,
+ 0,
+ ObjectType
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ RtlFreeUnicodeString (&CanonicalNameString_U);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtOpenFile returned %X\n",Status);
+ }
+#endif
+ switch (Status) {
+ case STATUS_OBJECT_NAME_INVALID:
+ //
+ // BUGBUG - This error code can appear in (at least) two
+ // cases: abc.lkjlkj (FAT only, need to be mapped to EXCEED_RANGE)
+ // or .a (FAT only, needs to be mapped to PATH_NOT_FOUND).
+ // NtOpen returns to the same status - we need to check
+ // the pathname to determine the problem.
+ //
+ return (ERROR_PATH_NOT_FOUND);
+
+ case STATUS_OBJECT_PATH_SYNTAX_BAD:
+ if (ObjectType == FILE_NON_DIRECTORY_FILE) {
+ return (ERROR_FILE_NOT_FOUND);
+ }
+ else {
+ return (ERROR_PATH_NOT_FOUND);
+ }
+
+ case STATUS_SHARING_VIOLATION:
+ if (ObjectType == FILE_DIRECTORY_FILE) {
+ GetCurrentDirectoryW((DWORD)(sizeof(CurrentDirectory_U)), CurrentDirectory_U);
+
+ //
+ // convert UNICODE-STRING to ANSI-STRING
+ //
+ RtlInitUnicodeString(&str_u, (PWSTR) CurrentDirectory_U);
+ str_a.Buffer = CurrentDirectory_A;
+ str_a.MaximumLength = sizeof(CurrentDirectory_A);
+ Od2UnicodeStringToMBString(&str_a, &str_u, FALSE);
+ CurrentDirectory_A[str_a.Length] = '\0';
+
+ Od2Canonicalize(CurrentDirectory_A,
+ CANONICALIZE_FILE_OR_DEV,
+ &CanonicalCurrentDirectory,
+ &ObjHandle,
+ &FileFlags,
+ &FileType
+ );
+ if (!strcmp(CanonicalNameString.Buffer, CanonicalCurrentDirectory.Buffer)) {
+ return (ERROR_CURRENT_DIRECTORY);
+ }
+ }
+ return (ERROR_SHARING_VIOLATION);
+
+ default:
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_PATH_NOT_FOUND));
+ }
+ }
+
+ //
+ // now that the file is opened, we need to make sure that it isn't a
+ // device or named pipe that Canonicalize didn't detect.
+ //
+
+ if (CheckFileType(ObjHandle,FILE_TYPE_NMPIPE | FILE_TYPE_DEV)) {
+ NtClose(ObjHandle);
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("not a file/dir name\n");
+ }
+#endif
+ return ERROR_PATH_NOT_FOUND;
+ }
+
+// //
+// // ObjectType is FILE_DIRECTORY_FILE or NULL. If it's FILE..., NtOpenFile
+// // will fail if the path isn't a directory. If it's NULL, we need to
+// // verify that the path is a file.
+// //
+//
+// if (ObjectType == 0) {
+// Status = NtQueryInformationFile(ObjHandle,
+// &IoStatus,
+// &FileStandardInfo,
+// sizeof (FileStandardInfo),
+// FileStandardInformation);
+// ASSERT( NT_SUCCESS( Status ) );
+// if (FileStandardInfo.Directory) {
+// NtClose(ObjHandle);
+// return ERROR_ACCESS_DENIED;
+// }
+// }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtOpenFile successful\n");
+ DbgPrint("value of iostatus.info is %ld\n",IoStatus.Information);
+ }
+#endif
+
+ FileDispInfo.DeleteFile = TRUE;
+ do {
+ Status = NtSetInformationFile(ObjHandle,
+ &IoStatus,
+ (PVOID) &FileDispInfo,
+ sizeof (FileDispInfo),
+ FileDispositionInformation
+ );
+ } while (RetryIO(Status, ObjHandle));
+ NtClose(ObjHandle);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtSetInformationFile returned %X\n",Status);
+ }
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_PATH_NOT_FOUND));
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtSetInformationFile successful\n");
+ }
+#endif
+ return NO_ERROR;
+}
+
+
+APIRET
+DosDeleteDir(
+ IN PSZ DirectoryName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes a directory.
+
+Arguments:
+
+ DirectoryName - name of directory
+
+Return Value:
+
+ ERROR_PATH_NOT_FOUND - DirectoryName is a device or pipe name.
+
+ ERROR_FILE_NOT_FOUND - some component of DirectoryName doesn't exist.
+
+--*/
+
+{
+ APIRET RetCode;
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("entering RmDir with %s\n",DirectoryName);
+ }
+#endif
+ RetCode = DeleteObject(DirectoryName,FILE_DIRECTORY_FILE);
+ if (RetCode == ERROR_FILE_NOT_FOUND) {
+ return(ERROR_PATH_NOT_FOUND);
+ }
+ return RetCode;
+}
+
+
+APIRET
+DosQueryVerify(
+ OUT PBOOL32 Verify
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the value of the Verify flag.
+
+Arguments:
+
+ Verify - where to return the value of verify.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ try {
+ *Verify = (BOOL32) VerifyFlag;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return NO_ERROR;
+}
+
+
+APIRET
+DosSetVerify(
+ IN BOOL32 Verify
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the value of the Verify flag.
+
+Arguments:
+
+ Verify - new value of verify flag
+
+Return Value:
+
+ ERROR_INVALID_VERIFY_SWITCH - new value of verify flag is invalid.
+
+--*/
+
+{
+ if ((Verify != TRUE) && (Verify != FALSE))
+ return ERROR_INVALID_VERIFY_SWITCH;
+ VerifyFlag = (BOOLEAN) Verify;
+ return NO_ERROR;
+}
diff --git a/private/os2/client/dllea.c b/private/os2/client/dllea.c
new file mode 100644
index 000000000..b3a3f3405
--- /dev/null
+++ b/private/os2/client/dllea.c
@@ -0,0 +1,1974 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllea.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 extended attributes manipulation
+ API calls
+
+Author:
+
+ Therese Stowell (thereses) 03-Nov-1989
+
+Revision History:
+
+ Yaron Shamir (yarons) 20-May-1991
+ Fixed bugs found by filio test suite.
+
+--*/
+
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FILESYS
+#include "os2dll.h"
+
+
+BOOLEAN
+NtTimeToFatTimeAndDate (
+ OUT PFTIME FatTime,
+ OUT PFDATE FatDate,
+ IN LARGE_INTEGER NtTime
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts a 64-bit NT time value to its corresponding
+ Fat Date/Time structure
+
+Arguments:
+
+ FatTime - Receives the corresponding Fat Time
+
+ FatDate - Receives the corresponding Fat Date
+
+ NtTime - Supplies the input time to convert
+
+Return Value:
+
+ BOOLEAN - TRUE if the time is within the range of Fat and FALSE
+ otherwise
+
+adapted from NtTimeToFatTimeandDate
+
+--*/
+
+{
+ TIME_FIELDS TimeFields;
+ LARGE_INTEGER LocalTime;
+
+ if (NtTime.LowPart == 0 && NtTime.HighPart == 0) {
+ FatTime->twosecs = 0;
+ FatTime->minutes = 0;
+ FatTime->hours = 0;
+ FatDate->year = 0;
+ FatDate->month = 0;
+ FatDate->day = 0;
+ return FALSE;
+ }
+
+ //
+ // Convert UTC to Local time
+ //
+
+ if (!(NT_SUCCESS(RtlSystemTimeToLocalTime ( &NtTime, &LocalTime))))
+ {
+ return FALSE;
+ }
+
+ //
+ // Convert the input to the a time field record
+ //
+
+ RtlTimeToTimeFields( &LocalTime, &TimeFields );
+
+ //
+ // Check the range of the date found in the time field record
+ //
+
+ if ((TimeFields.Year < 1980) || (TimeFields.Year > (1980 + 128))) {
+ return FALSE;
+ }
+
+ //
+ // The year will fit in Fat so simply copy over the information
+ //
+
+ FatTime->twosecs = (USHORT) (TimeFields.Second / 2);
+ FatTime->minutes = TimeFields.Minute;
+ FatTime->hours = TimeFields.Hour;
+
+ FatDate->year = (USHORT) (TimeFields.Year - 1980);
+ FatDate->month = TimeFields.Month;
+ FatDate->day = TimeFields.Day;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+FatTimeAndDateToNtTime(
+ OUT PLARGE_INTEGER NtTime,
+ IN FTIME FatTime,
+ IN FDATE FatDate
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts a Fat time/date value to an NtTime
+
+Arguments:
+
+ NtTime - Receives the corresponding date/time
+
+ FatTime - Supplies the input time
+
+ FatDate - Supplies the input date
+
+Return Value:
+
+ BOOLEAN - Return TRUE if the input time/date is well formed and
+ FALSE otherwise
+
+--*/
+
+{
+ TIME_FIELDS TimeFields;
+ LARGE_INTEGER LocalTime;
+
+ //
+ // Pack the input time/date into a time field record
+ //
+
+ TimeFields.Year = (CSHORT) (FatDate.year + 1980);
+ TimeFields.Month = FatDate.month;
+ TimeFields.Day = FatDate.day;
+ TimeFields.Hour = FatTime.hours;
+ TimeFields.Minute = FatTime.minutes;
+ TimeFields.Second = (CSHORT) (FatTime.twosecs * 2);
+ TimeFields.Milliseconds = 0;
+
+ //
+ // Convert the time field record to Nt LARGE_INTEGER
+ //
+
+ if (!RtlTimeFieldsToTime( &TimeFields, &LocalTime )) {
+
+ NtTime->LowPart = 0;
+ NtTime->HighPart = 0;
+
+ return FALSE;
+ }
+
+ //
+ // Convert Local time to UTC
+ //
+
+ if (!(NT_SUCCESS(RtlLocalTimeToSystemTime ( &LocalTime, NtTime))))
+ {
+ NtTime->LowPart = 0;
+ NtTime->HighPart = 0;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+APIRET
+GetEaListLength(
+ IN HANDLE NtHandle,
+ OUT PULONG EaListSize
+)
+
+/*++
+
+Routine Description:
+
+ This routine returns the OS/2 format size of an EA list, given an NT
+ handle to the open file.
+
+Arguments:
+
+ NtHandle - handle to file to return EA size of
+
+ EaListSize - where to store EA size
+
+Return Value:
+
+ ERROR_INVALID_ACCESS - handle not open in a mode that allows ea size
+ retrieval.
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ FILE_EA_INFORMATION EaInfo;
+
+ do {
+ Status = NtQueryInformationFile(NtHandle,
+ &IoStatus,
+ &EaInfo,
+ sizeof (EaInfo),
+ FileEaInformation);
+ } while (RetryIO(Status, NtHandle));
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_ACCESS));
+ }
+ *EaListSize = MAX(MINFEALISTSIZE, EaInfo.EaSize); // FEA list size
+ return NO_ERROR;
+}
+
+
+APIRET
+SetEAList(
+ IN HANDLE NtHandle,
+ IN OUT PBYTE UserBuffer,
+ IN ULONG Length
+)
+
+/*++
+
+Routine Description:
+
+ This routine sets a list of EAs for a particular file.
+
+Arguments:
+
+ NtHandle - handle to file to store EAs for
+
+ UserBuffer - OS/2 format list of EAs
+
+ Length - length of data in UserBuffer
+
+Return Value:
+
+ ERROR_EA_LIST_TOO_LONG - EA list exceeds maximum length.
+
+ ERROR_INSUFFICIENT_BUFFER - buffer passed in is not long enough to contain
+ an EAOP.
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ PFEA2 FeaPtr;
+ ULONG FeaListLength;
+
+ if (Length < (sizeof (EAOP2))) {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+ try {
+ FeaListLength = ((PEAOP2)UserBuffer)->fpFEA2List->cbList;
+ FeaListLength -= MINFEALISTSIZE; // subtract size of cbList
+ FeaPtr = ((PEAOP2)UserBuffer)->fpFEA2List->list;
+ Od2ProbeForRead(FeaPtr,FeaListLength,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ if (FeaListLength != 0) {
+ do {
+ Status = NtSetEaFile(NtHandle,
+ &IoStatus,
+ FeaPtr,
+ FeaListLength
+ );
+ } while (RetryIO(Status, NtHandle));
+ if (!NT_SUCCESS(Status))
+ {
+ try
+ {
+ ((PEAOP2)UserBuffer)->oError = IoStatus.Information; // BUGBUG check this value
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+#if DBG
+ IF_OD2_DEBUG( TEMP )
+ {
+ DbgPrint("SetEAList: NtSetEaFile failed, Status=%x\n",
+ Status);
+ }
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_EA_LIST_INCONSISTENT));
+ }
+ }
+ return NO_ERROR;
+}
+
+APIRET
+GetGEAList(
+ IN HANDLE NtHandle,
+ OUT PBYTE UserBuffer,
+ IN ULONG Length
+)
+
+/*++
+
+Routine Description:
+
+ This routine retrieves a list of EAs given a list of EA names.
+
+Arguments:
+
+ NtHandle - handle to file to retrieve EAs for
+
+ UserBuffer - EAOP containing list of names and buffer to store them in
+
+ Length - length of data in UserBuffer
+
+Return Value:
+
+ ERROR_BUFFER_OVERFLOW - buffer passed in is not long enough to contain
+ an EAOP or destination buffer is not large enough to contain all the
+ requested EAs.
+
+ ERROR_NOT_ENOUGH_MEMORY - memory to read the EAs into could not be
+ allocated.
+
+ ERROR_EA_LIST_INCONSISTENT - the length of the EA name doesn't correspond
+ to the length of the buffer
+
+--*/
+
+{
+ NTSTATUS Status;
+ PGEA2 GeaPtr;
+ PFEA2 FeaPtr;
+ ULONG GeaListLength;
+ ULONG FeaListLength;
+ FEA2LIST *fpFEA2List;
+ IO_STATUS_BLOCK IoStatus;
+
+ if (Length < (sizeof (EAOP2)))
+ {
+ return ERROR_BUFFER_OVERFLOW;
+ }
+
+ try
+ {
+ fpFEA2List = ((PEAOP2)UserBuffer)->fpFEA2List;
+ FeaListLength = fpFEA2List->cbList;
+ if (FeaListLength < MINFEALISTSIZE)
+ {
+ return ERROR_BUFFER_OVERFLOW;
+ }
+ FeaListLength -= MINFEALISTSIZE; // subtract size of cbList
+ FeaPtr = fpFEA2List->list;
+ Od2ProbeForWrite(FeaPtr,FeaListLength,1);
+ GeaListLength = ((PEAOP2)UserBuffer)->fpGEA2List->cbList - MINFEALISTSIZE;
+ GeaPtr = ((PEAOP2)UserBuffer)->fpGEA2List->list;
+ Od2ProbeForRead(GeaPtr,GeaListLength,1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if (GeaListLength != 0)
+ {
+ do {
+ Status = NtQueryEaFile(NtHandle,
+ &IoStatus,
+ FeaPtr,
+ FeaListLength,
+ FALSE,
+ GeaPtr,
+ GeaListLength,
+ NULL,
+ FALSE
+ );
+ } while (RetryIO(Status, NtHandle));
+ if (!NT_SUCCESS(Status))
+ {
+ try
+ {
+ // BUGBUG check this value
+ ((PEAOP2)UserBuffer)->oError = IoStatus.Information;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ #if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("NtQueryEaFile failed, Status=%X\n", Status);
+ }
+ #endif
+ if (Status == STATUS_NO_EAS_ON_FILE)
+ {
+ /* No EAs on file. Just set the .cbList field to 4 to indicate to
+ the OS/2 1.x emulation that fact. We still need to build an FEA
+ list with empty data fields */
+ fpFEA2List->cbList=sizeof(ULONG);
+
+ return NO_ERROR;
+ }
+ else
+ return Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ }
+ /* Fix the FEA2 list's .cbList created by
+ GetGEAList:
+ - unlike Cruiser, NT leaves the .cbList
+ untouched (rather than reflecting the total FEA2
+ list size)
+ - the .fEA field of each FEA2 entry is set incorrectly (i.e. not
+ FEA_NEEDEA)
+ */
+ /* BUGBUG - Try to remove the workaround below after NT Beta */
+ Od2FixFEA2List(fpFEA2List);
+ }
+ else
+ fpFEA2List->cbList = sizeof(ULONG); /* To signify an empty FEA2 list */
+
+ return NO_ERROR;
+}
+
+VOID
+MapAttributesToNt(
+ IN USHORT Os2Attributes,
+ OUT OPTIONAL PBOOLEAN Directory,
+ OUT PULONG NtAttributes
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts attributes from OS/2 format to NT format.
+
+Arguments:
+
+ Os2Attributes - the attributes in OS/2 format.
+
+ Directory - the Directory field associated with the NT directory
+ entry.
+
+ NtAttributes - where the converted attributes are returned.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ *NtAttributes = (ULONG) Os2Attributes;
+ if (Os2Attributes == 0) {
+ *NtAttributes = FILE_ATTRIBUTE_NORMAL;
+ }
+ else if (Os2Attributes & FILE_DIRECTORY) {
+ if (Directory != NULL) {
+ *Directory = TRUE;
+ }
+ *NtAttributes &= ~FILE_DIRECTORY;
+ }
+}
+
+
+APIRET
+SetFileInfo(
+ IN HANDLE NtHandle,
+ IN PBYTE Buffer,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets attributes for a given file
+
+Arguments:
+
+ NtHandle - handle to file to set attributes for
+
+ UserBuffer - buffer containing attributes
+
+ Length - length of data in UserBuffer
+
+Return Value:
+
+ ERROR_INVALID_ACCESS - user doesn't have access to set the attributes
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ FILE_BASIC_INFORMATION BasicInfo;
+ FILE_STANDARD_INFORMATION StandardInfo;
+ PFILESTATUS InfoBufPtr;
+ USHORT attrFileVal;
+
+ //
+ // Length has to be at least the date/time fields i.e. 12
+ //
+ if (Length < 12) {
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ InfoBufPtr = (PFILESTATUS) Buffer;
+
+ // if zero is passed in as OS/2 time and date, pass zero as NT time.
+ // otherwise, call conversion routine.
+
+ try {
+ if (( *(PUSHORT)( &(InfoBufPtr->ftimeCreation) ) == 0) &&
+ ( *(PUSHORT)( &(InfoBufPtr->fdateCreation) ) == 0)) {
+ BasicInfo.CreationTime.LowPart = 0;
+ BasicInfo.CreationTime.HighPart = 0;
+ }
+ else {
+ if (!FatTimeAndDateToNtTime(&BasicInfo.CreationTime,
+ InfoBufPtr->ftimeCreation,
+ InfoBufPtr->fdateCreation))
+ return ERROR_INVALID_PARAMETER;
+ }
+ if (( *(PUSHORT)( &(InfoBufPtr->ftimeLastAccess) ) == 0) &&
+ ( *(PUSHORT)( &(InfoBufPtr->fdateLastAccess) ) == 0)) {
+ BasicInfo.LastAccessTime.LowPart = 0;
+ BasicInfo.LastAccessTime.HighPart = 0;
+ }
+ else {
+ if (!FatTimeAndDateToNtTime(&BasicInfo.LastAccessTime,
+ InfoBufPtr->ftimeLastAccess,
+ InfoBufPtr->fdateLastAccess))
+ return ERROR_INVALID_PARAMETER;
+ }
+ if (( *(PUSHORT)( &(InfoBufPtr->ftimeLastWrite) ) == 0) &&
+ ( *(PUSHORT)( &(InfoBufPtr->fdateLastWrite) ) == 0)) {
+ BasicInfo.LastWriteTime.LowPart = 0;
+ BasicInfo.LastWriteTime.HighPart = 0;
+ }
+ else {
+ if (!FatTimeAndDateToNtTime(&BasicInfo.LastWriteTime,
+ InfoBufPtr->ftimeLastWrite,
+ InfoBufPtr->fdateLastWrite))
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If the current attribute of the file/directory is FILE_ATTRIBUTE_DIRECTORY
+ // leave it like that.
+ //
+
+ do {
+ Status = NtQueryInformationFile(NtHandle,
+ &IoStatus,
+ &StandardInfo,
+ sizeof (StandardInfo),
+ FileStandardInformation
+ );
+ } while (RetryIO(Status, NtHandle));
+
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_ACCESS));
+ }
+
+ if (StandardInfo.Directory) {
+ BasicInfo.FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
+ } else {
+ attrFileVal = *((PUSHORT) (&(InfoBufPtr->attrFile)));
+ if (attrFileVal & ~ATTR_CHANGEABLE) {
+ return ERROR_ACCESS_DENIED;
+ }
+ if (attrFileVal == 0) {
+ BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
+ } else {
+ BasicInfo.FileAttributes = attrFileVal;
+ }
+ }
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+
+ // don't want to change these fields, so set them to zero.
+
+ BasicInfo.ChangeTime.LowPart = 0;
+ BasicInfo.ChangeTime.HighPart = 0;
+
+ do {
+ Status = NtSetInformationFile(NtHandle,
+ &IoStatus,
+ &BasicInfo,
+ sizeof (BasicInfo),
+ FileBasicInformation);
+ } while (RetryIO(Status, NtHandle));
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
+ }
+
+ return NO_ERROR;
+}
+
+
+APIRET
+GetFileInfo(
+ IN HANDLE NtHandle,
+ IN ULONG FileInformationLevel,
+ OUT PBYTE Buffer,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retrieves attributes and EA size for a given file
+
+Arguments:
+
+ NtHandle - handle to file to retrieve attributes for
+
+ FileInformationLevel - which type of data to return
+
+ Buffer - buffer to store attributes in (unprobed)
+
+ Length - length of UserBuffer
+
+Return Value:
+
+ ERROR_INVALID_ACCESS - user doesn't have access to retrieve the attributes
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ FILE_BASIC_INFORMATION BasicInfo;
+ FILE_STANDARD_INFORMATION StandardInfo;
+ PFILEFINDBUF4 InfoBufPtr;
+ APIRET RetCode;
+ USHORT Attributes;
+
+ if (Length < sizeof(FILESTATUS))
+ return ERROR_BUFFER_OVERFLOW;
+
+ // get end of file information
+
+ do {
+ Status = NtQueryInformationFile(NtHandle,
+ &IoStatus,
+ &StandardInfo,
+ sizeof (StandardInfo),
+ FileStandardInformation);
+ } while (RetryIO(Status, NtHandle));
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE));
+ }
+
+ // get date/time information
+
+ do {
+ Status = NtQueryInformationFile(NtHandle,
+ &IoStatus,
+ &BasicInfo,
+ sizeof (BasicInfo),
+ FileBasicInformation);
+ } while (RetryIO(Status, NtHandle));
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE));
+ }
+ InfoBufPtr = (PFILEFINDBUF4) Buffer;
+
+ // the data returned doesn't have a oNextEntryOffset field.
+ InfoBufPtr = (PFILEFINDBUF4) ((ULONG)InfoBufPtr - sizeof(InfoBufPtr->oNextEntryOffset));
+
+ try {
+ // convert creation time
+
+ NtTimeToFatTimeAndDate(&InfoBufPtr->ftimeCreation,
+ &InfoBufPtr->fdateCreation,
+ BasicInfo.CreationTime);
+
+ // convert last access time
+
+ NtTimeToFatTimeAndDate(&InfoBufPtr->ftimeLastAccess,
+ &InfoBufPtr->fdateLastAccess,
+ BasicInfo.LastAccessTime);
+
+ // convert last write time
+
+ NtTimeToFatTimeAndDate(&InfoBufPtr->ftimeLastWrite,
+ &InfoBufPtr->fdateLastWrite,
+ BasicInfo.LastWriteTime);
+
+ // BUGBUG - Therese, what should we do here if .HighPart is non-zero
+
+ InfoBufPtr->cbFile = StandardInfo.EndOfFile.LowPart;
+ InfoBufPtr->cbFileAlloc = StandardInfo.AllocationSize.LowPart;
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("cbFile is %ld\n",StandardInfo.EndOfFile.LowPart);
+ DbgPrint("cbFileAlloc is %ld\n",StandardInfo.AllocationSize.LowPart);
+ }
+#endif
+
+ MapAttributesToOs2(BasicInfo.FileAttributes,&Attributes);
+ InfoBufPtr->attrFile = Attributes & ATTR_ALL;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("attrFile is %lx\n",Attributes & ATTR_ALL);
+ }
+#endif
+
+ if (FileInformationLevel == FIL_STANDARD)
+ return NO_ERROR;
+
+ if (Length < (sizeof(FILESTATUS) + sizeof(ULONG)))
+ return ERROR_BUFFER_OVERFLOW;
+ RetCode = GetEaListLength(NtHandle,&InfoBufPtr->cbList);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("GetEaListLength returned %ld\n",RetCode);
+ DbgPrint("EaListLength is %ld\n",InfoBufPtr->cbList);
+ }
+#endif
+ return RetCode;
+}
+
+
+APIRET
+DosQueryFileInfo(
+ IN HFILE FileHandle,
+ IN ULONG FileInformationLevel,
+ OUT PBYTE Buffer,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retrieves attributes, EA size, and EAs for a given file
+
+Arguments:
+
+ FileHandle - OS/2 handle to file to retrieve information for
+
+ FileInformationLevel - type of data to return
+
+ UserBuffer - buffer to store information in
+
+ Length - length of UserBuffer
+
+Return Value:
+
+ ERROR_INVALID_LEVEL - infolevel is invalid
+
+ ERROR_INVALID_HANDLE - file handle is not allocated
+
+ ERROR_INVALID_ACCESS - user doesn't have access to retrieve the attributes or EAs
+
+--*/
+
+{
+ APIRET RetCode;
+ HANDLE NtHandle;
+ PFILE_HANDLE hFileRecord;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosQueryFileInfo";
+ #endif
+
+ if ((FileInformationLevel < FIL_STANDARD) || (FileInformationLevel > MAXQFILEINFOLEVEL))
+ return ERROR_INVALID_LEVEL;
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
+ if (RetCode != NO_ERROR) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+
+ //
+ // DosQueryFileInfo is valid for pipes and devices
+ //
+
+ NtHandle = hFileRecord->NtHandle;
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (FileInformationLevel <= FIL_QUERYEASIZE) {
+ RetCode = GetFileInfo(NtHandle,
+ FileInformationLevel,
+ Buffer,
+ Length);
+ }
+ else if (FileInformationLevel == FIL_QUERYEASFROMLIST)
+ {
+ RetCode = GetGEAList(NtHandle,
+ Buffer,
+ Length);
+ }
+ return RetCode;
+}
+
+
+APIRET
+DosSetFileInfo(
+ IN HFILE FileHandle,
+ IN ULONG FileInformationLevel,
+ IN OUT PBYTE Buffer,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets attributes and EAs for a given file
+
+Arguments:
+
+ FileHandle - OS/2 handle to file to set information for
+
+ FileInformationLevel - type of data to set
+
+ UserBuffer - buffer containing information to set
+
+ Length - length of data in UserBuffer
+
+Return Value:
+
+ ERROR_INVALID_LEVEL - infolevel is invalid
+
+ ERROR_INVALID_HANDLE - file handle is not allocated
+
+ ERROR_INVALID_ACCESS - user doesn't have access to set the attributes or EAs
+
+--*/
+
+{
+ APIRET RetCode;
+ HANDLE NtHandle;
+ PFILE_HANDLE hFileRecord;
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_ACCESS_INFORMATION FileAccessInfo;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosSetFileInfo";
+ #endif
+
+ if ((FileInformationLevel < FIL_STANDARD) ||
+ (FileInformationLevel > MAXSETFILEINFOLEVEL))
+ return ERROR_INVALID_LEVEL;
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
+ if (RetCode != NO_ERROR) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ if (hFileRecord->FileType &
+ (FILE_TYPE_DEV | FILE_TYPE_PIPE | FILE_TYPE_NMPIPE | FILE_TYPE_PSDEV)) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE;
+ }
+ NtHandle = hFileRecord->NtHandle;
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // We need to check whether we have READONLY access to this handle.
+ // If true, we should return with ERROR_ACCESS_DENIED.
+ //
+
+ do {
+ RetCode = NtQueryInformationFile(NtHandle,
+ &IoStatusBlock,
+ &FileAccessInfo,
+ sizeof(FILE_ACCESS_INFORMATION),
+ FileAccessInformation
+ );
+ } while (RetryIO(RetCode, NtHandle));
+
+ if (!(NT_SUCCESS(RetCode))) {
+ return (Or2MapNtStatusToOs2Error(RetCode, ERROR_INVALID_ACCESS));
+ }
+
+ if (!(FileAccessInfo.AccessFlags & FILE_WRITE_DATA)) {
+ return(ERROR_ACCESS_DENIED);
+ }
+
+ if (FileInformationLevel == FIL_STANDARD) {
+
+ //
+ // This is here to fix a problem with DosSetfileInfo for this function
+ // the attrFile is not used but SetFileInfo wants it to be set
+ //
+ if (Length >= ((sizeof(FILESTATUS)) - sizeof(USHORT))) {
+ PFILESTATUS InfoBufPtr;
+ InfoBufPtr = (PFILESTATUS) Buffer;
+ (*(PUSHORT) (&(InfoBufPtr->attrFile))) = (USHORT) FILE_ARCHIVED;
+ }
+
+ RetCode = SetFileInfo(NtHandle,
+ Buffer,
+ Length);
+ }
+ else if (FileInformationLevel == FIL_SETEAS) {
+ RetCode = SetEAList(NtHandle,
+ Buffer,
+ Length);
+ }
+ else
+ RetCode = ERROR_NOT_SUPPORTED;
+
+ return RetCode;
+}
+
+
+APIRET
+DosQueryPathInfo(
+ IN PSZ pszPath,
+ IN ULONG FileInformationLevel,
+ OUT PBYTE Buffer,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retrieves attributes, EA size, and EAs for a given file
+ and canonicalizes filenames.
+
+Arguments:
+
+ pszPath - filename to retrieve information about
+
+ FileInformationLevel - type of data to return
+
+ UserBuffer - buffer to store information in
+
+ Length - length of UserBuffer
+
+Return Value:
+
+ ERROR_INVALID_LEVEL - infolevel is invalid
+
+ ERROR_INVALID_ACCESS - user doesn't have access to retrieve the attributes
+ or EAs
+
+ ERROR_BUFFER_OVERFLOW - requested information won't fit in buffer
+
+--*/
+
+{
+ NTSTATUS Status;
+ APIRET RetCode = NO_ERROR;
+ STRING CanonicalNameString;
+ UNICODE_STRING CanonicalNameString_U;
+ ULONG FileType;
+ ULONG FileFlags;
+ STRING AddString;
+ STRING TransBuffer;
+ USHORT PrefixLength;
+ PCHAR pServerName;
+ USHORT DriveIndex;
+ HANDLE PathHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ ULONG Flags;
+ ACCESS_MASK RequestedAccess;
+ ULONG ShareAccess;
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("entering qpathinfo with %s\n",pszPath);
+ }
+#endif
+
+ if ((FileInformationLevel < FIL_STANDARD) ||
+ (FileInformationLevel > MAXQPATHINFOLEVEL) ||
+ (FileInformationLevel == FIL_QUERYALLEAS))
+ return ERROR_INVALID_LEVEL;
+
+ if (FileInformationLevel == FIL_QUERYFULLNAME)
+ {
+ Flags = FULL_PATH_REQUIRED;
+ }
+ else {
+ Flags = 0;
+ }
+
+ RetCode = Od2Canonicalize(pszPath,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &CanonicalNameString,
+ NULL,
+ &FileFlags,
+ &FileType
+ );
+ if (RetCode != NO_ERROR) {
+ return RetCode;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("canonicalize returned %s and file type %lu\n",
+ CanonicalNameString.Buffer, FileType);
+ }
+#endif
+
+ //
+ // If Od2Canonicalize return with NO_ERROR then the file name is valid
+ //
+
+ if (FileInformationLevel == FIL_NAMEISVALID) {
+ return(NO_ERROR);
+ }
+
+ //
+ // Special handling of <boot-drive>:\config.sys
+ // opening this file is mapped to the OS/2 SS config.sys
+ //
+ if (Od2FileIsConfigSys(&CanonicalNameString, OPEN_ACCESS_READONLY, &Status)) {
+ if (!NT_SUCCESS(Status)) {
+
+ // failed to init for config.sys
+
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ }
+ FileFlags = 0;
+ FileType = FILE_TYPE_FILE;
+ }
+
+ if (FileInformationLevel == FIL_QUERYFULLNAME)
+ {
+ //
+ // Alocate space for translation buffers.
+ //
+
+ if ((AddString.Buffer = RtlAllocateHeap (Od2Heap, 0, 12)) == NULL) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Not enough memory to allocate buffer for AddString\n");
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ //
+ // Process the string.
+ //
+
+ TransBuffer.Length = 0;
+
+ switch (FileType) {
+ case FILE_TYPE_FILE:
+ //
+ // Od2Canonicalize returns \OS2SS\DRIVES\fullpath
+ // DosQPathInfo should return fullpath
+ //
+
+ PrefixLength = FILE_PREFIX_LENGTH;
+ AddString.Length = 0;
+
+ // convert path to lower case and drive letter to upper case
+
+ for (DriveIndex = 0;
+ DriveIndex < CanonicalNameString.Length - FILE_PREFIX_LENGTH;
+ DriveIndex++
+ ) {
+ if (CanonicalNameString.Buffer[FILE_PREFIX_LENGTH + DriveIndex] == ':') {
+ CanonicalNameString.Buffer[FILE_PREFIX_LENGTH + DriveIndex - 1] =
+ toupper(CanonicalNameString.Buffer[FILE_PREFIX_LENGTH + DriveIndex - 1]);
+ }
+ else {
+ CanonicalNameString.Buffer[FILE_PREFIX_LENGTH + DriveIndex] =
+ tolower(CanonicalNameString.Buffer[FILE_PREFIX_LENGTH + DriveIndex]);
+ }
+ }
+ break;
+
+ case FILE_TYPE_DEV:
+ //
+ // Od2Canonicalize returns \DosDevices\device
+ // DosQPathInfo should return \DEV\device
+ //
+
+ PrefixLength = DEV_PREFIX_LENGTH;
+ AddString.Length = 5;
+ RtlMoveMemory(AddString.Buffer, "\\DEV\\", AddString.Length);
+ break;
+
+ case FILE_TYPE_NMPIPE:
+ //
+ // Od2Canonicalize returns \OS2SS\PIPE\pipename
+ // DosQPathInfo should return \PIPE\pipename
+ //
+
+ PrefixLength = NMPIPE_PREFIX_LENGTH;
+ AddString.Length = 6;
+ RtlMoveMemory(AddString.Buffer, "\\PIPE\\", AddString.Length);
+ RtlUpperString(&CanonicalNameString, &CanonicalNameString);
+ break;
+
+ case FILE_TYPE_UNC:
+ //
+ // Od2Canonicalize returns \OS2SS\UNC\fullpath
+ // DosQPathInfo should return full UNC path
+ //
+
+ PrefixLength = UNC_PREFIX_LENGTH;
+ AddString.Length = 2;
+ RtlMoveMemory(AddString.Buffer, "\\\\", AddString.Length);
+
+ // convert server name to upper case
+
+ for (pServerName = CanonicalNameString.Buffer + UNC_PREFIX_LENGTH;
+ *pServerName != '\\';
+ pServerName++
+ ) {
+ *pServerName = toupper(*pServerName);
+ }
+ break;
+
+ case FILE_TYPE_PSDEV:
+ //
+ // Od2Canonicalize returns @n
+ // DosQPathInfo should return \DEV\device
+ //
+
+ PrefixLength = PSDEV_PREFIX_LENGTH;
+ AddString.Length = 5;
+ RtlMoveMemory(AddString.Buffer, "\\DEV\\", AddString.Length);
+
+ TransBuffer.Length = TransBuffer.MaximumLength = strlen(pszPath);
+ if ((TransBuffer.Buffer = RtlAllocateHeap (Od2Heap, 0, TransBuffer.Length)) == NULL) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Not enough memory to allocate buffer for translation\n");
+ }
+#endif
+ RtlFreeHeap(Od2Heap,0,AddString.Buffer);
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ RtlMoveMemory(TransBuffer.Buffer, pszPath, TransBuffer.Length);
+ RtlUpperString(&TransBuffer, &TransBuffer);
+ break;
+
+ case FILE_TYPE_MAILSLOT:
+ //
+ // Od2Canonicalize returns \OS2SS\MAILSLOT\mailslotname
+ // DosQPathInfo should return fullpath as a file
+ //
+
+ PrefixLength = MAILSLOT_PREFIX_LENGTH;
+ AddString.Buffer[0] = CONVERTTOASCII(Od2CurrentDisk);
+ AddString.Length = 12;
+ RtlMoveMemory(&AddString.Buffer[1], ":\\mailslot\\", AddString.Length);
+ break;
+
+ case FILE_TYPE_COM:
+ //
+ // Od2Canonicalize returns \DosDevices\device
+ // DosQPathInfo should return \DEV\device
+ //
+
+ PrefixLength = COM_PREFIX_LENGTH;
+ AddString.Length = 5;
+ RtlMoveMemory(AddString.Buffer, "\\DEV\\", AddString.Length);
+ break;
+
+ default:
+ PrefixLength = FILE_PREFIX_LENGTH;
+ AddString.Length = 0;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Unexpected file type %lu after canonicalize\n", FileType);
+ }
+#endif
+ }
+
+ //
+ // Check user's buffer size.
+ //
+
+ if ((ULONG)(CanonicalNameString.Length + 1 - PrefixLength +
+ AddString.Length + TransBuffer.Length) > Length) {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ RtlFreeHeap(Od2Heap,0,AddString.Buffer);
+ if (TransBuffer.Length) {
+ RtlFreeHeap(Od2Heap,0,TransBuffer.Buffer);
+ }
+ return ERROR_BUFFER_OVERFLOW;
+ }
+
+ //
+ // Copy full name to user's buffer.
+ //
+
+ try {
+ RtlMoveMemory(Buffer, AddString.Buffer, AddString.Length);
+
+ if (FileType == FILE_TYPE_PSDEV) {
+ RtlMoveMemory(Buffer + AddString.Length, TransBuffer.Buffer, TransBuffer.Length);
+ Buffer[AddString.Length + TransBuffer.Length] = 0;
+ }
+ else {
+ RtlMoveMemory(Buffer + AddString.Length,
+ CanonicalNameString.Buffer + PrefixLength,
+ CanonicalNameString.Length - PrefixLength);
+ Buffer[CanonicalNameString.Length + AddString.Length - PrefixLength] = 0;
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ RtlFreeHeap(Od2Heap,0,AddString.Buffer);
+ if (TransBuffer.Length) {
+ RtlFreeHeap(Od2Heap,0,TransBuffer.Buffer);
+ }
+ return NO_ERROR;
+ }
+
+ //
+ // check for file name being invalid type
+ //
+
+ if (FileFlags & CANONICALIZE_META_CHARS_FOUND)
+ {
+ RetCode = ERROR_INVALID_PATH;
+ }
+ else if ((FileFlags & CANONICALIZE_IS_ROOT_DIRECTORY) &&
+ (FileInformationLevel > FIL_QUERYEASIZE))
+ {
+ RetCode = ERROR_ACCESS_DENIED;
+ }
+ else if (FileType & (FILE_TYPE_DEV | FILE_TYPE_PSDEV))
+ {
+ RetCode = ERROR_INVALID_ACCESS;
+ }
+
+
+ if (RetCode != NO_ERROR)
+ {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return RetCode;
+ }
+ if (FileFlags & CANONICALIZE_IS_ROOT_DIRECTORY)
+ {
+ RtlZeroMemory(Buffer,sizeof(FILESTATUS));
+ ((PFILESTATUS)Buffer)->attrFile = FILE_DIRECTORY;
+ if (FileInformationLevel == FIL_QUERYEASIZE)
+ ((PFILESTATUS2)Buffer)->cbList = MINFEALISTSIZE;
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return NO_ERROR;
+ }
+
+ //
+ // OS/2 requires open-for-read/deny-write for qpathinfo, except for
+ // FIL_STANDARD, which does not use sharing.
+ //
+
+ if (FileInformationLevel == FIL_STANDARD)
+ {
+ RequestedAccess = SYNCHRONIZE | FILE_READ_ATTRIBUTES;
+ ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ }
+ else if (FileInformationLevel == FIL_QUERYEASIZE)
+ {
+ RequestedAccess = SYNCHRONIZE | FILE_READ_EA | FILE_READ_ATTRIBUTES;
+ ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ }
+ else if (FileInformationLevel == FIL_QUERYEASFROMLIST)
+ {
+ RequestedAccess = SYNCHRONIZE | FILE_READ_EA | FILE_READ_ATTRIBUTES;
+ ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ }
+ else
+ {
+ RequestedAccess = SYNCHRONIZE | FILE_READ_EA;
+ ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ }
+
+ //
+ // UNICODE conversion -
+ //
+ RetCode = Od2MBStringToUnicodeString(
+ &CanonicalNameString_U,
+ &CanonicalNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("DosQueryPathInfo: no memory for Unicode Conversion\n");
+ }
+#endif
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ do {
+ Status = NtOpenFile(&PathHandle,
+ RequestedAccess,
+ &Obja,
+ &IoStatus,
+ ShareAccess,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ RtlFreeUnicodeString (&CanonicalNameString_U);
+ if (!(NT_SUCCESS(Status)))
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("NtOpenFile returned %X\n",Status);
+ }
+#endif
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_ACCESS);
+ return (RetCode);
+ }
+
+ //
+ // now that the file is opened, we need to make sure that it isn't a
+ // device that Canonicalize didn't detect.
+ //
+
+ if (CheckFileType(PathHandle,FILE_TYPE_DEV))
+ {
+ NtClose(PathHandle);
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("path is a device\n");
+ }
+#endif
+ return ERROR_INVALID_ACCESS;
+ }
+
+ if (FileInformationLevel <= FIL_QUERYEASIZE)
+ {
+ RtlZeroMemory(Buffer,Length);
+ RetCode = GetFileInfo(PathHandle,
+ FileInformationLevel,
+ Buffer,
+ Length);
+ }
+ else if (FileInformationLevel == FIL_QUERYEASFROMLIST)
+ {
+ RetCode = GetGEAList(PathHandle,
+ Buffer,
+ Length);
+ }
+ else
+ {
+ RetCode = ERROR_NOT_SUPPORTED;
+ }
+ NtClose(PathHandle);
+ return RetCode;
+}
+
+
+APIRET
+DosSetPathInfo(
+ IN PSZ pszPath,
+ IN ULONG FileInformationLevel,
+ IN OUT PBYTE Buffer,
+ IN ULONG Length,
+ IN ULONG Flags
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets attributes and EAs for a given file.
+
+Arguments:
+
+ pszPath - filename to set information for
+
+ FileInformationLevel - type of data to set
+
+ UserBuffer - buffer containing information to set
+
+ Length - length of data in UserBuffer
+
+ Flags - if the DSPI_WRTTHRU bit is set then all disk writes will
+ go through any cache to the disk.
+
+Return Value:
+
+ ERROR_INVALID_LEVEL - infolevel is invalid
+
+ ERROR_INVALID_ACCESS - user doesn't have access to set the attributes or
+ EAs
+
+ ERROR_BUFFER_OVERFLOW - requested information won't fit in buffer
+
+--*/
+
+{
+ NTSTATUS Status;
+ APIRET RetCode = NO_ERROR;
+ STRING CanonicalNameString;
+ UNICODE_STRING CanonicalNameString_U;
+ ULONG FileType;
+ ULONG FileFlags;
+ HANDLE PathHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ ACCESS_MASK RequestedAccess;
+ ULONG CreateOptions;
+
+ if ((FileInformationLevel < FIL_STANDARD) ||
+ (FileInformationLevel > MAXSETPATHINFOLEVEL)) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // check flags value.
+ //
+
+ if ((Flags != 0) && (Flags != DSPI_WRTTHRU)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ RetCode = Od2Canonicalize(pszPath,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &CanonicalNameString,
+ &PathHandle,
+ &FileFlags,
+ &FileType
+ );
+ if (RetCode != NO_ERROR) {
+ return RetCode;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("canonicalize returned %s\n",CanonicalNameString.Buffer);
+ }
+#endif
+
+ //
+ // Special handling of <boot-drive>:\config.sys
+ // opening this file is mapped to the OS/2 SS config.sys
+ //
+ if (Od2FileIsConfigSys(&CanonicalNameString, OPEN_ACCESS_READWRITE, &Status)) {
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to init for config.sys
+
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ }
+ FileFlags = 0;
+ FileType = FILE_TYPE_FILE;
+ PathHandle = NULL;
+ }
+
+ //
+ // check for file name being invalid type
+ //
+ if (FileFlags & CANONICALIZE_META_CHARS_FOUND) {
+ RetCode = ERROR_INVALID_PATH;
+ }
+ else if (FileType & (FILE_TYPE_DEV | FILE_TYPE_PSDEV)) {
+ RetCode = ERROR_INVALID_ACCESS;
+ }
+ else if (FileFlags & CANONICALIZE_IS_ROOT_DIRECTORY) {
+ RetCode = ERROR_ACCESS_DENIED;
+ }
+ if (RetCode != NO_ERROR) {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return RetCode;
+ }
+
+ //
+ // OS/2 requires open-for-write/deny-both for setpathinfo.
+ //
+
+ if (FileInformationLevel == FIL_STANDARD)
+ RequestedAccess = SYNCHRONIZE | FILE_WRITE_ATTRIBUTES;
+ else
+ RequestedAccess = SYNCHRONIZE | FILE_WRITE_EA;
+
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &CanonicalNameString_U,
+ &CanonicalNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("DosSetPathInfo: no memory for Unicode Conversion\n");
+ }
+#endif
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ PathHandle,
+ NULL);
+
+ CreateOptions = FILE_SYNCHRONOUS_IO_NONALERT;
+ if (Flags & DSPI_WRTTHRU)
+ CreateOptions |= FILE_WRITE_THROUGH;
+ do {
+ Status = NtOpenFile(&PathHandle,
+ RequestedAccess,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_VALID_FLAGS,
+ CreateOptions
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ RtlFreeUnicodeString (&CanonicalNameString_U);
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtCreateFile returned %X\n",Status);
+ }
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_ACCESS));
+ }
+
+ //
+ // now that the file is opened, we need to make sure that it isn't a
+ // device that Canonicalize didn't detect.
+ //
+
+ if (CheckFileType(PathHandle,FILE_TYPE_DEV)) {
+ NtClose(PathHandle);
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("path is a device\n");
+ }
+#endif
+ return ERROR_INVALID_ACCESS;
+ }
+
+ if (FileInformationLevel == FIL_STANDARD) {
+ RetCode = SetFileInfo(PathHandle,
+ Buffer,
+ Length);
+ }
+ else if (FileInformationLevel == FIL_SETEAS) {
+ RetCode = SetEAList(PathHandle,
+ Buffer,
+ Length);
+ }
+ else
+ RetCode = ERROR_NOT_SUPPORTED;
+ NtClose(PathHandle);
+ return RetCode;
+}
+
+
+
+APIRET
+DosEnumAttribute(
+ IN ULONG RefType,
+ IN PVOID FileRef,
+ IN ULONG EntryNum,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ IN OUT PULONG ActualLength,
+ IN ULONG FileInformationLevel
+ )
+
+/*++
+
+Routine Description:
+
+ This routine enumerates a specific file's extended attributes.
+
+Arguments:
+
+ RefType - type of file reference (handle or filename)
+
+ FileRef - handle or filename
+
+ EntryNum - starting entry in EA list
+
+ Buffer - data buffer
+
+ Length - data buffer size
+
+ ActualLength - on input, the number of entries to return. on output,
+ the number of entries returned.
+
+ FileInformationLevel - type of information requested.
+
+Return Value:
+
+ ERROR_INVALID_LEVEL - infolevel is invalid
+
+ ERROR_BUFFER_OVERFLOW - requested information won't fit in buffer
+
+--*/
+
+{
+ NTSTATUS Status;
+ APIRET RetCode;
+ STRING CanonicalNameString;
+ UNICODE_STRING CanonicalNameString_U;
+ ULONG FileType;
+ ULONG FileFlags;
+ HANDLE PathHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ ULONG NumberFound;
+ PDENA1 Os2Ea, PrevEa;
+ PFEA2 NtEa;
+ PFILE_HANDLE hFileRecord;
+ ULONG BufferLength;
+ PVOID EaBuffer;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosEnumAttribute";
+ #endif
+
+ //
+ // check the parameters
+ //
+
+ if ((RefType > ENUMEA_REFTYPE_MAX) || EntryNum == 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (FileInformationLevel != ENUM_EANAME)
+ {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ try {
+ *(volatile PULONG) ActualLength = *(volatile PULONG) ActualLength;
+ Od2ProbeForWrite(Buffer,Length,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (*ActualLength == 0)
+ {
+ return NO_ERROR;
+ }
+
+ //
+ // if the FileRef is a pathname, we need to open it to have a handle
+ // to pass to NtQueryEaFile
+ //
+
+ if (RefType == ENUMEA_REFTYPE_PATH)
+ {
+ RetCode = Od2Canonicalize(FileRef,
+ /* BUGBUG - Why allow a pipe ? */
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &CanonicalNameString,
+ &PathHandle,
+ &FileFlags,
+ &FileType
+ );
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("canonicalize returned %s\n",CanonicalNameString.Buffer);
+ }
+#endif
+
+ //
+ // check for file name being invalid type
+ //
+
+ if (FileFlags & CANONICALIZE_META_CHARS_FOUND)
+ {
+ RetCode = ERROR_INVALID_PATH;
+ }
+ else if (FileFlags & CANONICALIZE_IS_ROOT_DIRECTORY)
+ {
+ RetCode = ERROR_ACCESS_DENIED;
+ }
+ else if (FileType & (FILE_TYPE_DEV | FILE_TYPE_PSDEV | FILE_TYPE_PIPE))
+ {
+ RetCode = ERROR_INVALID_ACCESS;
+ }
+
+ if (RetCode != NO_ERROR)
+ {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return RetCode;
+ }
+
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &CanonicalNameString_U,
+ &CanonicalNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("DosEnumAttribute: no memory for Unicode Conversion\n");
+ }
+#endif
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ PathHandle,
+ NULL);
+
+ do {
+ Status = NtOpenFile(&PathHandle,
+ SYNCHRONIZE | FILE_READ_EA,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ RtlFreeUnicodeString (&CanonicalNameString_U);
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtOpenFile returned %X\n",Status);
+ }
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_PATH_NOT_FOUND));
+ }
+
+ //
+ // now that the file is opened, we need to make sure that it isn't a
+ // device that Canonicalize didn't detect.
+ //
+
+ if (CheckFileType(PathHandle,FILE_TYPE_DEV)) {
+ NtClose(PathHandle);
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("path is a device\n");
+ }
+#endif
+ return ERROR_INVALID_ACCESS;
+ }
+ }
+ else
+ {
+ /* BUGBUG - Note that the call below is translated to some other call
+ if DBG is NOT defined => DosEnumAttribute() needs to be tested without
+ DBG */
+ AcquireFileLockShared( // prevent the handle from being closed
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RetCode = DereferenceFileHandle(
+ *(HFILE *)FileRef,
+ &hFileRecord);
+ if (RetCode != NO_ERROR)
+ {
+ /* BUGBUG - Note that the call below is translated to some other call
+ if DBG is NOT defined => DosEnumAttribute() needs to be tested without
+ DBG */
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ PathHandle = hFileRecord->NtHandle;
+ }
+
+ //
+ // allocate a buffer large enough to hold all the EAs for a file.
+ //
+
+ BufferLength = MAX_ALIGNED_EA_LIST_SIZE;
+ EaBuffer = 0;
+ Status = NtAllocateVirtualMemory(NtCurrentProcess(),
+ &EaBuffer,
+ 0,
+ &BufferLength,
+ MEM_COMMIT,
+ PAGE_READWRITE
+ );
+ if (!(NT_SUCCESS(Status))) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // since we're passing in an EntryNum, as opposed to a GEA, NtQueryFile
+ // will return STATUS_NO_EAS_ON_FILE if the requested entry does not
+ // exist. NtQueryEaFile returns STATUS_BUFFER_OVERFLOW if no EAs will
+ // fit in the buffer.
+ //
+
+ // Around build 304, entries are now 1-based (not 0-based) so there is no
+ // need to decrement EntryNum
+
+ do
+ {
+ Status = NtQueryEaFile(PathHandle,
+ &IoStatus,
+ EaBuffer,
+ BufferLength,
+ FALSE,
+ NULL,
+ 0,
+ &EntryNum,
+ FALSE);
+ } while (RetryIO(Status, PathHandle));
+ if (Status != STATUS_SUCCESS)
+ {
+ if (Status == STATUS_NO_EAS_ON_FILE)
+ {
+ *ActualLength = 0;
+ RetCode = NO_ERROR;
+ }
+ /* BUGBUG - Seems like this error code below is returned by HPFS &
+ NTFS when a file has no EA's */
+ else if ((Status == STATUS_NONEXISTENT_EA_ENTRY) || (EntryNum == 0))
+ {
+ *ActualLength = 0;
+ RetCode = NO_ERROR;
+ }
+ else
+ {
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_EAS_NOT_SUPPORTED);
+ }
+ goto CleanUp;
+ }
+ else if (IoStatus.Information == 0) /* Size of retrieved EA's is 0 ! */
+ {
+ *ActualLength = 0;
+ RetCode = NO_ERROR;
+ goto CleanUp;
+ }
+
+ NumberFound = 0;
+ RetCode = NO_ERROR;
+ Os2Ea = PrevEa = Buffer;
+ NtEa = EaBuffer;
+ while ((Length >= (ULONG)(DENA1_sizeof(NtEa))) && (NumberFound < *ActualLength)) {
+ RtlMoveMemory(Os2Ea,NtEa,DENA1_sizeof(NtEa));
+ Os2Ea->oNextEntryOffset = DENA1_oNextEntryOffset(Os2Ea);
+ if (Length < Os2Ea->oNextEntryOffset)
+ Length = 0;
+ else
+ Length -= Os2Ea->oNextEntryOffset;
+ NumberFound++;
+ PrevEa = Os2Ea;
+ if (NtEa->oNextEntryOffset == 0) {
+ break;
+ }
+ else {
+ Os2Ea = (PDENA1) ((PCHAR) Os2Ea + Os2Ea->oNextEntryOffset);
+ NtEa = (PFEA2) ((PCHAR) NtEa + NtEa->oNextEntryOffset);
+ }
+ }
+
+ //
+ // if NtQueryDirectoryFile returned an EA but it wouldn't fit in
+ // the user's buffer, return ERROR_BUFFER_OVERFLOW.
+ //
+
+ if (NumberFound == 0) {
+ RetCode = ERROR_BUFFER_OVERFLOW;
+ goto CleanUp;
+ }
+
+ PrevEa->oNextEntryOffset = 0;
+ *ActualLength = NumberFound;
+
+CleanUp:
+ if (RefType == ENUMEA_REFTYPE_PATH) {
+ NtClose(PathHandle);
+ }
+ else {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ }
+ NtFreeVirtualMemory(NtCurrentProcess(),
+ &EaBuffer,
+ &BufferLength,
+ MEM_RELEASE
+ );
+ return RetCode;
+}
diff --git a/private/os2/client/dllerror.c b/private/os2/client/dllerror.c
new file mode 100644
index 000000000..35af17d60
--- /dev/null
+++ b/private/os2/client/dllerror.c
@@ -0,0 +1,667 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllerror.c
+
+Abstract:
+
+ This module implements the Error OS/2 V2.0 API Calls
+
+Author:
+
+ Steve Wood (stevewo) 20-Sep-1989 (Adapted from URTL\alloc.c)
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_ERRORMSG
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "conrqust.h"
+#include "os2win.h"
+
+
+APIRET
+DosError(
+ IN ULONG ErrorFlags
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSERROR_MSG a = &m.u.DosError;
+ ULONG ErrorAction;
+ ULONG OriginalErrorAction;
+
+ //
+ // Validate the parameter
+ //
+
+ if (ErrorFlags & ~(DE_ENABLE_HARD_ERRORS | DE_DISABLE_EXCEPTIONS)) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ OriginalErrorAction = Od2Process->ErrorAction;
+
+ //
+ // Calculate the new ErrorAction bits
+ //
+ ErrorAction = 0;
+ if (ErrorFlags & DE_ENABLE_HARD_ERRORS) {
+ ErrorAction |= OD2_ENABLE_HARD_ERROR_POPUP;
+ }
+
+ if (!(ErrorFlags & DE_DISABLE_EXCEPTIONS)) {
+ ErrorAction |= OD2_ENABLE_ACCESS_VIO_POPUP;
+ }
+
+
+ //
+ // Store the new ErrorAction bits
+ //
+
+ Od2Process->ErrorAction &= ~(OD2_ENABLE_HARD_ERROR_POPUP |
+ OD2_ENABLE_ACCESS_VIO_POPUP);
+ Od2Process->ErrorAction |= ErrorAction;
+
+
+ if (Od2Process->ErrorAction != OriginalErrorAction) {
+ a->ErrorAction = Od2Process->ErrorAction;
+
+ Od2CallSubsystem( &m, NULL, Os2Error, sizeof( *a ) );
+ }
+
+ //
+ // Return success
+ //
+
+ return( NO_ERROR );
+}
+
+typedef struct _ERRORTABLE {
+ ULONG ErrorCode : 16;
+ ULONG ErrorClass : 8;
+ ULONG ErrorAction : 4;
+ ULONG ErrorLocus : 4;
+} ERRORTABLE, *PERRORTABLE;
+
+ERRORTABLE Od2ErrorTable[] = {
+ ERROR_ACCESS_DENIED, ERRCLASS_AUTH, ERRACT_USER, ERRLOC_UNK,
+// ERROR_ADAP_HDW_ERR, ERRCLASS_HRDFAIL,ERRACT_ABORT, ERRLOC_NET,
+ ERROR_ALREADY_ASSIGNED, ERRCLASS_ALREADY,ERRACT_USER, ERRLOC_NET,
+ ERROR_ALREADY_EXISTS, ERRCLASS_ALREADY,ERRACT_USER, ERRLOC_UNK,
+ ERROR_ARENA_TRASHED, ERRCLASS_APPERR, ERRACT_PANIC, ERRLOC_MEM,
+ ERROR_AUTODATASEG_EXCEEDS_64K, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_BAD_ARGUMENTS, ERRCLASS_BADFMT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_BAD_COMMAND, ERRCLASS_INTRN, ERRACT_PANIC, ERRLOC_UNK,
+// ERROR_BAD_DEV_TYPE, ERRCLASS_BADFMT, ERRACT_USER, ERRLOC_NET,
+ ERROR_BAD_DRIVER_LEVEL, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_DISK,
+ ERROR_BAD_ENVIRONMENT, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_MEM,
+ ERROR_BAD_FORMAT, ERRCLASS_BADFMT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_BAD_LENGTH, ERRCLASS_INTRN, ERRACT_PANIC, ERRLOC_UNK,
+// ERROR_BAD_NETPATH, ERRCLASS_NOTFND, ERRACT_USER, ERRLOC_NET,
+// ERROR_BAD_NET_NAME, ERRCLASS_NOTFND, ERRACT_USER, ERRLOC_NET,
+// ERROR_BAD_NET_RESP, ERRCLASS_BADFMT, ERRACT_ABORT, ERRLOC_NET,
+ ERROR_BAD_PATHNAME, ERRCLASS_BADFMT, ERRACT_USER, ERRLOC_UNK,
+ ERROR_BAD_PIPE, ERRCLASS_NOTFND, ERRACT_USER, ERRLOC_UNK,
+// ERROR_BAD_REM_ADAP, ERRCLASS_HRDFAIL,ERRACT_ABORT, ERRLOC_NET,
+ ERROR_BAD_THREADID_ADDR, ERRCLASS_BADFMT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_BAD_UNIT, ERRCLASS_INTRN, ERRACT_PANIC, ERRLOC_UNK,
+ ERROR_BAD_EXE_FORMAT, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_BROKEN_PIPE, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_BUFFER_OVERFLOW, ERRCLASS_APPERR, ERRACT_RETRY, ERRLOC_MEM,
+ ERROR_BUSY_DRIVE, ERRCLASS_ALREADY,ERRACT_DLYRET, ERRLOC_DISK,
+ ERROR_CANNOT_MAKE, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_DISK,
+ ERROR_CALL_NOT_IMPLEMENTED, ERRCLASS_SYSFAIL,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_CHILD_NOT_COMPLETE, ERRCLASS_NOTFND, ERRACT_DLYRET, ERRLOC_UNK,
+ ERROR_CRC, ERRCLASS_MEDIA, ERRACT_ABORT, ERRLOC_DISK,
+ ERROR_CURRENT_DIRECTORY, ERRCLASS_AUTH, ERRACT_USER, ERRLOC_DISK,
+ ERROR_CRITSEC_OVERFLOW, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_CRITSEC_UNDERFLOW, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+// ERROR_DEV_NOT_EXIST, ERRCLASS_HRDFAIL,ERRACT_ABORT, ERRLOC_NET,
+ ERROR_DIRECT_ACCESS_HANDLE, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_DISK,
+ ERROR_DIR_NOT_EMPTY, ERRCLASS_CANT, ERRACT_USER, ERRLOC_DISK,
+ ERROR_DIR_NOT_ROOT, ERRCLASS_CANT, ERRACT_USER, ERRLOC_DISK,
+ ERROR_DISCARDED, ERRCLASS_NOTFND, ERRACT_ABORT, ERRLOC_MEM,
+ ERROR_DISK_CHANGE, ERRCLASS_MEDIA, ERRACT_USER, ERRLOC_DISK,
+ ERROR_DISK_FULL, ERRCLASS_OUTRES, ERRACT_USER, ERRLOC_DISK,
+ ERROR_DRIVE_LOCKED, ERRCLASS_LOCKED, ERRACT_DLYRET, ERRLOC_DISK,
+ ERROR_DUP_FCB, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+// ERROR_DUP_NAME, ERRCLASS_ALREADY,ERRACT_ABORT, ERRLOC_NET,
+ ERROR_DYNLINK_FROM_INVALID_RING,ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_TSTDUP, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_TSTOVFL, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_EXCL_SEM_ALREADY_OWNED, ERRCLASS_ALREADY,ERRACT_DLYRET, ERRLOC_UNK,
+ ERROR_ENVVAR_NOT_FOUND, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_FAIL_I24, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_FCB_UNAVAILABLE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_FILE_EXISTS, ERRCLASS_ALREADY,ERRACT_USER, ERRLOC_DISK,
+ ERROR_FILE_NOT_FOUND, ERRCLASS_NOTFND, ERRACT_USER, ERRLOC_DISK,
+ ERROR_GEN_FAILURE, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INFLOOP_IN_RELOC_CHAIN, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INSUFFICIENT_BUFFER, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INTERRUPT, ERRCLASS_UNK, ERRACT_RETRY, ERRLOC_UNK,
+ ERROR_INVALID_ACCESS, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_AT_INTERRUPT_TIME,ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_BLOCK, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_MEM,
+ ERROR_INVALID_CALLGATE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_CATEGORY, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_DATA, ERRCLASS_BADFMT, ERRACT_ABORT, ERRLOC_UNK,
+// ERROR_INVALID_DLL_INIT_RING, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_DRIVE, ERRCLASS_NOTFND, ERRACT_USER, ERRLOC_DISK,
+ ERROR_INVALID_EVENT_COUNT, ERRCLASS_BADFMT, ERRACT_ABORT, ERRLOC_UNK,
+// ERROR_INVALID_EXITROUTINE_RING, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_FLAG_NUMBER, ERRCLASS_BADFMT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_FUNCTION, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_HANDLE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_LEVEL, ERRCLASS_BADFMT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_LIST_FORMAT, ERRCLASS_BADFMT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_NAME, ERRCLASS_BADFMT, ERRACT_USER, ERRLOC_UNK,
+ ERROR_INVALID_ORDINAL, ERRCLASS_BADFMT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_PARAMETER, ERRCLASS_BADFMT, ERRACT_USER, ERRLOC_UNK,
+ ERROR_INVALID_PASSWORD, ERRCLASS_AUTH, ERRACT_USER, ERRLOC_UNK,
+// ERROR_INVALID_STARTING_RING, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_SEGMENT_NUMBER, ERRCLASS_BADFMT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_TARGET_HANDLE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_VERIFY_SWITCH, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_PROCID, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_PDELTA, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_PCLASS, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_SCOPE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_THREADID, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_STARTING_CODESEG, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_STACKSEG, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_SEGDPL, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_MODULETYPE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_EXE_SIGNATURE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_MINALLOCSIZE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_FAIL_I24, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_ITERATED_DATA_EXCEEDS_64K,ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_IOPL_NOT_ENABLED, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_LABEL_TOO_LONG, ERRCLASS_BADFMT, ERRACT_USER, ERRLOC_DISK,
+ ERROR_LOCK_VIOLATION, ERRCLASS_LOCKED, ERRACT_DLYRET, ERRLOC_DISK,
+ ERROR_MAX_THRDS_REACHED, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOD_NOT_FOUND, ERRCLASS_NOTFND, ERRACT_USER, ERRLOC_UNK,
+ ERROR_MONITORS_NOT_SUPPORTED, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MORE_DATA, ERRCLASS_UNK, ERRACT_RETRY, ERRLOC_UNK,
+ ERROR_NEGATIVE_SEEK, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_DISK,
+// ERROR_NETNAME_DELETED, ERRCLASS_HRDFAIL,ERRACT_ABORT, ERRLOC_NET,
+ ERROR_NET_WRITE_FAULT, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_NET,
+// ERROR_NETWORK_ACCESS_DENIED, ERRCLASS_AUTH, ERRACT_USER, ERRLOC_NET,
+// ERROR_NETWORK_BUSY, ERRCLASS_TEMPSIT,ERRACT_DLYRET, ERRLOC_NET,
+ ERROR_NOT_CURRENT_CTRY, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_NOT_DOS_DISK, ERRCLASS_MEDIA, ERRACT_INTRET, ERRLOC_DISK,
+ ERROR_NOT_ENOUGH_MEMORY, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_MEM,
+ ERROR_NOT_LOCKED, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_NOT_READY, ERRCLASS_HRDFAIL,ERRACT_INTRET, ERRLOC_UNK,
+ ERROR_NOT_SAME_DEVICE, ERRCLASS_UNK, ERRACT_USER, ERRLOC_DISK,
+ ERROR_NOT_SUPPORTED, ERRCLASS_BADFMT, ERRACT_USER, ERRLOC_NET,
+ ERROR_NO_CHILD_PROCESS, ERRCLASS_NOTFND, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_NO_DATA, ERRCLASS_CANT, ERRACT_DLYRET, ERRLOC_UNK,
+ ERROR_NO_ITEMS, ERRCLASS_NOTFND, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_NO_MORE_FILES, ERRCLASS_NOTFND, ERRACT_USER, ERRLOC_DISK,
+ ERROR_NO_MORE_SEARCH_HANDLES, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_NO_SIGNAL_SENT, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+// ERROR_NO_SPOOL_SPACE, ERRCLASS_OUTRES, ERRACT_DLYRET, ERRLOC_NET,
+ ERROR_NO_PROC_SLOTS, ERRCLASS_OUTRES, ERRACT_DLYRET, ERRLOC_UNK,
+ ERROR_NO_VOLUME_LABEL, ERRCLASS_NOTFND, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_OPEN_FAILED, ERRCLASS_NOTFND, ERRACT_USER, ERRLOC_UNK,
+ ERROR_OUT_OF_PAPER, ERRCLASS_TEMPSIT,ERRACT_INTRET, ERRLOC_SERDEV,
+ ERROR_OUT_OF_STRUCTURES, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_PATH_BUSY, ERRCLASS_ALREADY,ERRACT_USER, ERRLOC_UNK,
+ ERROR_PATH_NOT_FOUND, ERRCLASS_NOTFND, ERRACT_USER, ERRLOC_DISK,
+ ERROR_PIPE_BUSY, ERRCLASS_ALREADY,ERRACT_DLYRET, ERRLOC_UNK,
+ ERROR_PIPE_NOT_CONNECTED, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+// ERROR_PRINTQ_FULL, ERRCLASS_OUTRES, ERRACT_DLYRET, ERRLOC_NET,
+// ERROR_PRINT_CANCELLED, ERRCLASS_HRDFAIL,ERRACT_ABORT, ERRLOC_NET,
+ ERROR_PROC_NOT_FOUND, ERRCLASS_NOTFND, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_PROTECTION_VIOLATION, ERRCLASS_AUTH, ERRACT_PANIC, ERRLOC_UNK,
+ ERROR_READ_FAULT, ERRCLASS_HRDFAIL,ERRACT_ABORT, ERRLOC_UNK,
+// ERROR_REDIR_PAUSED, ERRCLASS_TEMPSIT,ERRACT_RETRY, ERRLOC_NET,
+ ERROR_RELOC_CHAIN_XEEDS_SEGLIM, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+// ERROR_REM_NOT_LIST, ERRCLASS_TEMPSIT,ERRACT_DLYRET, ERRLOC_NET,
+// ERROR_REQ_NOT_ACCEP, ERRCLASS_BADFMT, ERRACT_ABORT, ERRLOC_NET,
+ ERROR_RING2SEG_MUST_BE_MOVABLE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SAME_DRIVE, ERRCLASS_CANT, ERRACT_USER, ERRLOC_UNK,
+ ERROR_SECTOR_NOT_FOUND, ERRCLASS_MEDIA, ERRACT_ABORT, ERRLOC_DISK,
+ ERROR_SEEK, ERRCLASS_HRDFAIL,ERRACT_RETRY, ERRLOC_DISK,
+ ERROR_SEEK_ON_DEVICE, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SEM_IS_SET, ERRCLASS_ALREADY,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SEM_NOT_FOUND, ERRCLASS_NOTFND, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SEM_OWNER_DIED, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SEM_TIMEOUT, ERRCLASS_TIME, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SEM_USER_LIMIT, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SHARING_BUFFER_EXCEEDED, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_MEM,
+// ERROR_SHARING_PAUSED, ERRCLASS_TEMPSIT,ERRACT_DLYRET, ERRLOC_NET,
+ ERROR_SHARING_VIOLATION, ERRCLASS_LOCKED, ERRACT_DLYRET, ERRLOC_DISK,
+ ERROR_SIGNAL_PENDING, ERRCLASS_CANT, ERRACT_DLYRET, ERRLOC_UNK,
+ ERROR_SIGNAL_REFUSED, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SYSTEM_TRACE, ERRCLASS_CANT, ERRACT_INTRET, ERRLOC_UNK,
+// ERROR_TOO_MANY_CMDS, ERRCLASS_OUTRES, ERRACT_DLYRET, ERRLOC_NET,
+ ERROR_TOO_MANY_MUXWAITERS, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+// ERROR_TOO_MANY_NAMES, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_NET,
+ ERROR_TOO_MANY_OPEN_FILES, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_TOO_MANY_SEMAPHORES, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_TOO_MANY_SEM_REQUESTS, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+// ERROR_TOO_MANY_SESS, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_NET,
+ ERROR_TOO_MANY_TCBS, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+// ERROR_UNEXP_NET_ERR, ERRCLASS_SYSFAIL,ERRACT_ABORT, ERRLOC_NET,
+ ERROR_VC_DISCONNECTED, ERRCLASS_HRDFAIL,ERRACT_RETRY, ERRLOC_NET,
+ ERROR_VIOKBD_REQUEST, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_WAIT_NO_CHILDREN, ERRCLASS_NOTFND, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_WRITE_FAULT, ERRCLASS_HRDFAIL,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_WRITE_PROTECT, ERRCLASS_MEDIA, ERRACT_INTRET, ERRLOC_DISK,
+ ERROR_WRONG_DISK, ERRCLASS_MEDIA, ERRACT_INTRET, ERRLOC_DISK,
+ ERROR_NOT_DESCENDANT, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_NOT_SESSION_MANAGER, ERRCLASS_AUTH, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_EXE_MARKED_INVALID, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_UNCERTAIN_MEDIA, ERRCLASS_INTRN, ERRACT_ABORT, ERRLOC_DISK,
+ ERROR_FILENAME_EXCED_RANGE, ERRCLASS_BADFMT, ERRACT_USER, ERRLOC_DISK,
+ ERROR_META_EXPANSION_TOO_LONG, ERRCLASS_BADFMT, ERRACT_USER, ERRLOC_DISK,
+ ERROR_RING2_STACK_IN_USE, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_MEM,
+ ERROR_CODE_PAGE_NOT_FOUND, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_CPLIST_TOO_SMALL, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_CP_NOT_MOVED, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_CP_SWITCH_INCOMPLETE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_INVALID_CODE_PAGE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_CANNOT_CREATE_KCB, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_CODEPAGE_LOAD_INCOMPL,ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_DETACHED, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_FOCUS_ALREADY_ACTIVE, ERRCLASS_ALREADY,ERRACT_DLYRET, ERRLOC_UNK,
+ ERROR_KBD_FOCUS_REQUIRED, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_INVALID_CODEPAGE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_INVALID_CODEPAGE_ID, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_INVALID_HANDLE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_KEYBOARD_BUSY, ERRCLASS_TEMPSIT,ERRACT_RETRY, ERRLOC_UNK,
+ ERROR_KBD_NO_CODEPAGE_SUPPORT, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_NO_MORE_HANDLE, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_UNABLE_TO_FOCUS, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MODE_SWITCH_INIT, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_DISPLAY_PARMS, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_INVALID_IOWAIT, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_INV_ENTRY_PT, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_INV_HANDLE, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_INV_MASK, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_INVALID_ASCIIZ, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_INVALID_MASK, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOU_DETACHED, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_UNEXPECTED_SLOT_RETURNED, ERRCLASS_INTRN, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_DOSSUB_SHRINK, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_DOSSUB_NOMEM, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_MEM,
+ ERROR_DOSSUB_OVERLAP, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_DOSSUB_BADSIZE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_DOSSUB_BADFLAG, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_DOSSUB_BADSELECTOR, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MR_MSG_TOO_LONG, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MR_MID_NOT_FOUND, ERRCLASS_NOTFND, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MR_UN_ACC_MSGF, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MR_INV_MSGF_FORMAT, ERRCLASS_BADFMT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MR_INV_IVCOUNT, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MR_UN_PERFORM, ERRCLASS_CANT, ERRACT_DLYRET, ERRLOC_UNK,
+ ERROR_TS_WAKEUP, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_TS_SEMHANDLE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_TS_NOTIMER, ERRCLASS_OUTRES, ERRACT_DLYRET, ERRLOC_UNK,
+ ERROR_TS_HANDLE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_TS_DATETIME, ERRCLASS_BADFMT, ERRACT_USER, ERRLOC_UNK,
+ ERROR_SYS_INTERNAL, ERRCLASS_SYSFAIL,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_CURRENT_NAME, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_PROC_NOT_OWNED, ERRCLASS_AUTH, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_PROC_OWNED, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_DUPLICATE, ERRCLASS_ALREADY,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_ELEMENT_NOT_EXIST, ERRCLASS_NOTFND, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_NO_MEMORY, ERRCLASS_OUTRES, ERRACT_DLYRET, ERRLOC_MEM,
+ ERROR_QUE_INVALID_NAME, ERRCLASS_BADFMT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_INVALID_PRIORITY, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_INVALID_HANDLE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_LINK_NOT_FOUND, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_MEMORY_ERROR, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_PREV_AT_END, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_PROC_NO_ACCESS, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_EMPTY, ERRCLASS_CANT, ERRACT_DLYRET, ERRLOC_UNK,
+ ERROR_QUE_NAME_NOT_EXIST, ERRCLASS_NOTFND, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_NOT_INITIALIZED, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_UNABLE_TO_ACCESS, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_UNABLE_TO_ADD, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_UNABLE_TO_INIT, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_INVALID_MASK, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_PTR, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_APTR, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_RPTR, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_CPTR, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_LPTR, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_MODE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_WIDTH, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_ATTR, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_ROW, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_COL, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_TOPROW, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_BOTROW, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_RIGHTCOL, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_LEFTCOL, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_BAD_CP, ERRCLASS_NOTFND, ERRACT_IGNORE, ERRLOC_UNK,
+ ERROR_VIO_DETACHED, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_FONT, ERRCLASS_NOTFND, ERRACT_IGNORE, ERRLOC_UNK,
+ ERROR_VIO_ILLEGAL_DURING_POPUP, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_INTERNAL_RESOURCE, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_NA_CP, ERRCLASS_NOTFND, ERRACT_IGNORE, ERRLOC_UNK,
+ ERROR_VIO_NO_CP, ERRCLASS_NOTFND, ERRACT_IGNORE, ERRLOC_UNK,
+ ERROR_VIO_SHELL_INIT, ERRCLASS_TEMPSIT,ERRACT_RETRY, ERRLOC_UNK,
+ ERROR_VIO_USER_FONT, ERRCLASS_APPERR, ERRACT_IGNORE, ERRLOC_UNK,
+ ERROR_VIO_WAIT_FLAG, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_UNLOCK, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_TRANSPARENT_POPUP, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_BAD_RESERVE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SCS_CALL, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SCS_VALUE, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SGS_NOT_SESSION_MGR, ERRCLASS_AUTH, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_SET_TITLE, ERRCLASS_CANT, ERRACT_IGNORE, ERRLOC_UNK,
+ ERROR_SMG_BAD_RESERVE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_INVALID_BOND_OPTION, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_INVALID_DATA_LENGTH, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_INVALID_RELATED_OPT, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_INVALID_SELECT_OPT, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_INVALID_START_MODE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_INVALID_STOP_OPTION, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_INVALID_TRACE_OPTION, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_NOT_BOUND, ERRCLASS_NOTFND, ERRACT_IGNORE, ERRLOC_UNK,
+ ERROR_SMG_NO_HARD_ERRORS, ERRCLASS_SYSFAIL,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_PROCESS_NOT_PARENT, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_RETRY_SUB_ALLOC, ERRCLASS_OUTRES, ERRACT_RETRY, ERRLOC_UNK,
+ ERROR_SMG_SESSION_NON_SELECT, ERRCLASS_CANT, ERRACT_RETRY, ERRLOC_UNK,
+ ERROR_SMG_SESSION_NOT_FOREGRND, ERRCLASS_CANT, ERRACT_RETRY, ERRLOC_UNK,
+ ERROR_SMG_SESSION_NOT_PARENT, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_START_IN_BACKGROUND, ERRCLASS_ALREADY,ERRACT_IGNORE, ERRLOC_UNK,
+ ERROR_KBD_PARAMETER, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_NO_DEVICE, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_INVALID_IOWAIT, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_INVALID_LENGTH, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_INVALID_ECHO_MASK, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_INVALID_INPUT_MASK, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MON_INVALID_PARMS, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MON_INVALID_DEVNAME, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MON_INVALID_HANDLE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MON_BUFFER_TOO_SMALL, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MON_BUFFER_EMPTY, ERRCLASS_NOTFND, ERRACT_DLYRET, ERRLOC_UNK,
+ ERROR_MON_DATA_TOO_LARGE, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_NO_DEVICE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_INV_PARMS, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_CANT_RESET, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_INV_MODULE, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_NO_DATA, ERRCLASS_NOTFND, ERRACT_DLYRET, ERRLOC_UNK,
+ ERROR_MOUSE_PTR_DRAWN, ERRCLASS_UNK, ERRACT_IGNORE, ERRLOC_UNK,
+ ERROR_INVALID_FREQUENCY, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_NLS_NO_COUNTRY_FILE, ERRCLASS_SYSFAIL,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_NLS_OPEN_FAILED, ERRCLASS_SYSFAIL,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_NLS_TABLE_TRUNCATED, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_NLS_BAD_TYPE, ERRCLASS_SYSFAIL,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_NLS_TYPE_NOT_FOUND, ERRCLASS_SYSFAIL,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_SMG_ONLY, ERRCLASS_AUTH, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_INVALID_ASCIIZ, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_DEREGISTER, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_NO_POPUP, ERRCLASS_APPERR, ERRACT_IGNORE, ERRLOC_UNK,
+ ERROR_VIO_EXISTING_POPUP, ERRCLASS_LOCKED, ERRACT_DLYRET, ERRLOC_UNK,
+ ERROR_KBD_SMG_ONLY, ERRCLASS_AUTH, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_INVALID_ASCIIZ, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_INVALID_MASK, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_REGISTER, ERRCLASS_ALREADY,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_KBD_DEREGISTER, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_SMG_ONLY, ERRCLASS_AUTH, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_REGISTER, ERRCLASS_ALREADY,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_MOUSE_DEREGISTER, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_BAD_ACTION, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_INVALID_CALL, ERRCLASS_ALREADY,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SCS_SG_NOTFOUND, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SCS_NOT_SHELL, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_INVALID_PARMS, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_FUNCTION_OWNED, ERRCLASS_ALREADY,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_RETURN, ERRCLASS_ALREADY,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SCS_INVALID_FUNCTION, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SCS_NOT_SESSION_MGR, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_REGISTER, ERRCLASS_ALREADY,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_NO_MODE_THREAD, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_NO_SAVE_RESTORE_THD, ERRCLASS_APPERR, ERRACT_IGNORE, ERRLOC_UNK,
+ ERROR_VIO_IN_BG, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_NOT_BASESHELL, ERRCLASS_AUTH, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_BAD_STATUSREQ, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_INVALID_PROGRAM_TYPE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_INVALID_PGM_CONTROL, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_QUE_INVALID_WAIT, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_LOCK, ERRCLASS_ALREADY,ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_INVALID_HANDLE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_ILLEGAL_DURING_LOCK, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_VIO_INVALID_LENGTH, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_HANDLE_EOF, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_HANDLE_DISK_FULL, ERRCLASS_OUTRES, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_INVALID_SESSION_ID, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_SESSION_NOT_FOUND, ERRCLASS_NOTFND, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_SMG_NO_SESSIONS, ERRCLASS_OUTRES, ERRACT_RETRY, ERRLOC_UNK,
+ ERROR_NO_COUNTRY_OR_CODEPAGE, ERRCLASS_APPERR, ERRACT_ABORT, ERRLOC_UNK,
+ ERROR_NOT_FROZEN, ERRCLASS_CANT, ERRACT_ABORT, ERRLOC_UNK,
+ NO_ERROR, ERRCLASS_UNK, ERRACT_ABORT, ERRLOC_UNK
+};
+
+APIRET
+DosErrClass(
+ IN ULONG ErrorCode,
+ OUT PULONG ErrorClass,
+ OUT PULONG ErrorAction,
+ OUT PULONG ErrorLocus
+ )
+{
+ PERRORTABLE ErrorTableEntry;
+
+ //
+ // Scan table of known error codes. End of table is marked with NO_ERROR
+ // entry.
+ //
+
+ ErrorTableEntry = &Od2ErrorTable[ 0 ];
+ while (ErrorTableEntry->ErrorCode != NO_ERROR) {
+ if (ErrorTableEntry->ErrorCode == ErrorCode) {
+ break;
+ }
+ else {
+ ErrorTableEntry++;
+ }
+ }
+
+
+ //
+ // Either entry found or default NO_ERROR entry found. Fill in the three
+ // out parameters with the Error Class, Action and Locus information from
+ // the table entry.
+ //
+
+ try {
+ *ErrorClass = ErrorTableEntry->ErrorClass;
+ *ErrorAction = ErrorTableEntry->ErrorAction;
+ *ErrorLocus = ErrorTableEntry->ErrorLocus;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Return success
+ //
+
+ return( NO_ERROR );
+}
+
+typedef struct _X_FILE_NAME_INFORMATION {
+ FILE_NAME_INFORMATION f;
+ char x[255];
+} X_FILE_NAME_INFORMATION;
+
+typedef struct _X_OBJECT_NAME_INFORMATION {
+ OBJECT_NAME_INFORMATION f;
+ char x[255];
+} X_OBJECT_NAME_INFORMATION;
+
+BOOLEAN
+RetryIO(
+ NTSTATUS Status,
+ HANDLE Handle
+ )
+{
+ NTSTATUS LocalStatus;
+// IO_STATUS_BLOCK IoStatus;
+// X_FILE_NAME_INFORMATION FileNameInfo;
+ X_OBJECT_NAME_INFORMATION ObjectNameInfo;
+ ULONG ReturnedSize;
+ UNICODE_STRING Name_U;
+ int ReturnedAction, Drive;
+ BOOLEAN WriteProtectError;
+
+ if (!((Od2Process->ErrorAction & OD2_ENABLE_HARD_ERROR_POPUP) &&
+ (
+ (Status == STATUS_NO_MEDIA_IN_DEVICE) ||
+ (Status == STATUS_DEVICE_NOT_READY) ||
+ (Status == STATUS_MEDIA_WRITE_PROTECTED)
+ )
+ )
+ ) {
+ return (FALSE);
+ }
+
+ LocalStatus = NtQueryObject(Handle,
+ ObjectNameInformation,
+ &ObjectNameInfo,
+ sizeof(ObjectNameInfo),
+ &ReturnedSize
+ );
+ if (!NT_SUCCESS(LocalStatus)) {
+#if DBG
+ DbgPrint("HardError - Status = %lx\n", LocalStatus);
+#endif
+ Drive = 0; // No Drive information
+ }
+ else {
+#if DBG
+ DbgPrint("HardError - ObjectName = %ws\n", ObjectNameInfo.f.Name.Buffer);
+#endif
+ ObjectNameInfo.f.Name.Length = 16; // "\Device\Floppy0\"
+ RtlInitUnicodeString(&Name_U, L"\\Device\\Floppy0\\");
+ Name_U.Length = 16;
+ if (RtlEqualUnicodeString(&ObjectNameInfo.f.Name, &Name_U, TRUE)) {
+ Drive = 1; // This is Drive A:
+#if DBG
+ DbgPrint("HardError - Accessing drive A:\n");
+#endif
+ }
+ else {
+ RtlInitUnicodeString(&Name_U, L"\\Device\\Floppy1\\");
+ Name_U.Length = 16;
+ if (RtlEqualUnicodeString(&ObjectNameInfo.f.Name, &Name_U, TRUE)) {
+ Drive = 2; // This is Drive B:
+#if DBG
+ DbgPrint("HardError - Accessing drive B:\n");
+#endif
+ }
+ else {
+ Drive = 0; // No Drive information
+ }
+ }
+ }
+
+ WriteProtectError = (Status == STATUS_MEDIA_WRITE_PROTECTED) ?
+ (BOOLEAN)TRUE : (BOOLEAN)FALSE;
+
+ LocalStatus = Ow2HardErrorPopup(
+ Drive,
+ WriteProtectError,
+ &ReturnedAction,
+ &Od2Process->ApplName[0]
+ );
+
+ if (!NT_SUCCESS(LocalStatus)) {
+ ASSERT(NT_SUCCESS(LocalStatus));
+ return (FALSE);
+ }
+
+ if (ReturnedAction == OS2SS_IDIGNORE) {
+ return (FALSE);
+ }
+ else if (ReturnedAction == OS2SS_IDABORT) {
+ Od2DosExit( EXIT_PROCESS, 0, TC_HARDERROR );
+ }
+ else { // OS2SS_RETRY
+ return (TRUE);
+ }
+}
+
+BOOLEAN
+RetryCreateOpen(
+ NTSTATUS Status,
+ POBJECT_ATTRIBUTES pObja
+ )
+{
+ NTSTATUS LocalStatus;
+ IO_STATUS_BLOCK IoStatus;
+ X_FILE_NAME_INFORMATION FileNameInfo;
+ int ReturnedAction, Drive;
+ BOOLEAN WriteProtectError;
+
+ if (!((Od2Process->ErrorAction & OD2_ENABLE_HARD_ERROR_POPUP) &&
+ (
+ (Status == STATUS_NO_MEDIA_IN_DEVICE) ||
+ (Status == STATUS_DEVICE_NOT_READY) ||
+ (Status == STATUS_MEDIA_WRITE_PROTECTED)
+ )
+ )
+ ) {
+ return (FALSE);
+ }
+
+ if (pObja->RootDirectory != NULL) {
+ LocalStatus = NtQueryInformationFile(pObja->RootDirectory,
+ &IoStatus,
+ &FileNameInfo,
+ sizeof(X_FILE_NAME_INFORMATION),
+ FileNameInformation
+ );
+ if (!NT_SUCCESS(LocalStatus)) {
+#if DBG
+ DbgPrint("HardError - Status = %lx\n", LocalStatus);
+#endif
+ Drive = 0; // No Drive information
+ }
+ else {
+#if DBG
+ DbgPrint("HardError - Filename = %ws\n", FileNameInfo.f.FileName);
+#endif
+ Drive = 0; // No Drive information
+ }
+ }
+ else {
+ Drive =
+ RtlUpperChar((CHAR)pObja->ObjectName->Buffer[FILE_PREFIX_LENGTH+DRIVE_LETTER]) - 'A' + 1;
+ }
+
+ WriteProtectError = (Status == STATUS_MEDIA_WRITE_PROTECTED) ?
+ (BOOLEAN)TRUE : (BOOLEAN)FALSE;
+
+ LocalStatus = Ow2HardErrorPopup(
+ Drive,
+ WriteProtectError,
+ &ReturnedAction,
+ &Od2Process->ApplName[0]
+ );
+
+ if (!NT_SUCCESS(LocalStatus)) {
+ ASSERT(NT_SUCCESS(LocalStatus));
+ return (FALSE);
+ }
+
+ if (ReturnedAction == OS2SS_IDIGNORE) {
+ return (FALSE);
+ } else if (ReturnedAction == OS2SS_IDABORT) {
+ Od2DosExit( EXIT_PROCESS, 0, TC_HARDERROR );
+ }
+ else {
+ return (TRUE);
+ }
+}
+
diff --git a/private/os2/client/dllevent.c b/private/os2/client/dllevent.c
new file mode 100644
index 000000000..193ac249e
--- /dev/null
+++ b/private/os2/client/dllevent.c
@@ -0,0 +1,1161 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllevent.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 Event Semaphore API Calls.
+
+Author:
+
+ Steve Wood (stevewo) 07-Feb-1990
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+
+APIRET
+DosCreateEventSem(
+ IN PSZ ObjectName,
+ OUT PHEV EventHandle,
+ IN ULONG CreateAttributes,
+ IN BOOL32 InitialState
+ )
+{
+ NTSTATUS Status;
+ OS2_API_MSG m;
+ POS2_DOSCREATEEVENTSEM_MSG a = &m.u.DosCreateEventSem;
+ POS2_DOSCLOSEEVENTSEM_MSG a1 = &m.u.DosCloseEventSem;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ APIRET rc;
+ BOOLEAN SharedSem;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ OD2_SEMAPHORE Semaphore;
+
+ //
+ // Validate the simple parameters
+ //
+
+ if ((CreateAttributes & ~DC_SEM_SHARED) ||
+ ((InitialState != TRUE) && (InitialState != FALSE))
+ ) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ //
+ // probe handle pointer
+ //
+
+ try {
+ Od2ProbeForWrite( (PVOID)EventHandle, sizeof( EventHandle ), 1 );
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Capture and validate any semaphore name.
+ //
+
+ rc = Od2CaptureObjectName( ObjectName,
+ CANONICALIZE_SEMAPHORE,
+ 0,
+ &CaptureBuffer,
+ &a->ObjectName
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Determine if a shared or private semaphore.
+ //
+
+ if (CaptureBuffer != NULL || CreateAttributes & DC_SEM_SHARED) {
+ SharedSem = TRUE;
+ }
+ else {
+ SharedSem = FALSE;
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table,
+ // creating it if necessary.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, TRUE );
+ if (!SemaphoreTable) {
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ }
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ //
+ // Mark the fact that we are creating a semaphore handle.
+ //
+ a->HandleIndex = 0xFFFFFFFF;
+
+ if (SharedSem) {
+ //
+ // Shared semaphore. Set the shared semaphore attribute and pass
+ // the call to the OS/2 subsystem to create the system wide semaphore
+ // handle value.
+ //
+
+ a->CreateAttributes = CreateAttributes | DC_SEM_SHARED;
+ a->InitialState = (BOOLEAN)InitialState;
+ rc = Od2CallSubsystem( &m,
+ CaptureBuffer,
+ Os2CreateEventSem,
+ sizeof( *a )
+ );
+
+ //
+ // Free any capture buffer, since the subsystem has saved away any
+ // semaphore name in its table.
+ //
+
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ }
+
+ //
+ // Return if an error was discovered.
+ //
+
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // At this point, the semaphore handle index has been stored in
+ // a->HandleIndex by the OS/2 subsystem and a->NtEventHandle contains
+ // an NT handle to the NT Event.
+ //
+
+ }
+ else {
+ //
+ // Private semaphore. Create an NT NotificationEvent that will
+ // be used to implement the semantics of an OS/2 2.0 Event Semaphore.
+ //
+
+ Status = NtCreateEvent( &a->NtEventHandle,
+ EVENT_ALL_ACCESS,
+ NULL,
+ NotificationEvent,
+ (BOOLEAN) InitialState
+ );
+
+ //
+ // Return an error if unable to create the NT event.
+ //
+
+ if (!NT_SUCCESS( Status )) {
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ }
+
+ //
+ // Initialize the OS/2 Semaphore structure.
+ //
+
+ Semaphore.Type = Od2EventSem;
+ Semaphore.Shared = SharedSem;
+ Semaphore.PointerCount = 0;
+ Semaphore.OpenCount = 1;
+ Semaphore.u.Value = (PVOID)a->NtEventHandle;
+
+ //
+ // Create an entry in the appropriate semaphore table, which will copy
+ // the semaphore structure into the table entry and return an index to
+ // the entry in a->HandleIndex
+ //
+
+ if (!Or2CreateHandle( SemaphoreTable,
+ &a->HandleIndex,
+ (PVOID)&Semaphore
+ )
+ ) {
+ //
+ // Unable to create the entry. Close the NT event handle, as
+ // it will not be used. If this is a shared semaphore created, then
+ // call the OS/2 subsystem to close our reference to this shared
+ // OS/2 semaphore.
+ //
+
+ NtClose( a->NtEventHandle );
+ if (SharedSem) {
+ a1->HandleIndex = a->HandleIndex;
+ Od2CallSubsystem( &m, NULL, Os2CloseEventSem, sizeof( *a1 ) );
+ }
+
+ //
+ // Return an error.
+ //
+
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ //
+ // Success. Store a valid OS/2 2.0 Semaphore handle in the location
+ // specified by the caller and return success to the caller.
+ //
+
+ *EventHandle = Od2ConstructSemaphoreHandle( SharedSem,
+ a->HandleIndex
+ );
+ return( NO_ERROR );
+}
+
+
+APIRET
+DosOpenEventSem(
+ IN PSZ ObjectName,
+ IN OUT PHEV EventHandle
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSOPENEVENTSEM_MSG a = &m.u.DosOpenEventSem;
+ POS2_DOSCLOSEEVENTSEM_MSG a1 = &m.u.DosCloseEventSem;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ OD2_SEMAPHORE NewSemaphore;
+ POD2_SEMAPHORE Semaphore;
+ BOOLEAN SharedSem;
+ APIRET rc;
+
+ //
+ // probe handle pointer
+ //
+ try {
+ Od2ProbeForWrite( (PVOID)EventHandle, sizeof( EventHandle ), 1 );
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Capture and validate any semaphore name.
+ //
+
+ rc = Od2CaptureObjectName( ObjectName,
+ CANONICALIZE_SEMAPHORE,
+ 0,
+ &CaptureBuffer,
+ &a->ObjectName
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Determine if opening the semaphore by name or by handle.
+ //
+
+ if (CaptureBuffer != NULL) {
+ //
+ // If a semaphore name was given, then we are opening the semaphore
+ // by name, so call the OS/2 Subsystem to do the name lookup.
+ //
+
+ a->HandleIndex = 0xFFFFFFFF;
+ rc = Od2CallSubsystem( &m,
+ CaptureBuffer,
+ Os2OpenEventSem,
+ sizeof( *a )
+ );
+
+ //
+ // Free any capture buffer, since the name has served its purpose
+ // at this point.
+ //
+
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ RtlZeroMemory( &a->ObjectName, sizeof( a->ObjectName ) );
+ }
+
+ //
+ // Return if an error was discovered.
+ //
+
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // At this point, the semaphore handle has been stored in
+ // a->HandleIndex by the OS/2 subsystem but a->NtEventHandle is still
+ // uninitialized, since we don't know if this is the first reference
+ // to this shared semaphore by this process. Set the shared semaphore
+ // flag.
+ //
+
+ SharedSem = TRUE;
+
+ //
+ // If the caller specified both the name and the handle, make sure
+ // the named mapped to the same handle value that they specified.
+ //
+
+ if (*EventHandle != NULL &&
+ *EventHandle != Od2ConstructSemaphoreHandle( SharedSem,
+ a->HandleIndex
+ )
+ ) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+ }
+ else {
+ //
+ // Opening by handle. Validate the handle and get the shared/private
+ // flag.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( *EventHandle,
+ &SharedSem,
+ &a->HandleIndex
+ );
+ //
+ // Return if invalid handle.
+ //
+
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Creating is okay if this is a shared semaphore open. Return the
+ // appropriate error code if table does not exist or cant be created.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, SharedSem );
+ if (!SemaphoreTable) {
+ return( SharedSem ? ERROR_NOT_ENOUGH_MEMORY : ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Now lock the semaphore table while we figure out what we are doing and
+ // do it.
+ //
+
+ AcquireHandleTableLock( SemaphoreTable );
+
+ //
+ // See if the semaphore handle maps to an allocated entry in the table.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ a->HandleIndex,
+ TRUE
+ );
+ if (Semaphore == NULL || *(PULONG)Semaphore == 0) {
+ //
+ // No entry in the table for this semaphore handle. Error if not
+ // a shared semaphore.
+ //
+
+ if (!SharedSem) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+ else {
+
+ //
+ // This is the first usage of this shared semaphore handle by
+ // the calling process, so call the OS/2 subsystem so that it
+ // can bump its reference count.
+ //
+
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2OpenEventSem,
+ sizeof( *a )
+ );
+ if (rc == NO_ERROR) {
+ //
+ // If we succeeded, then the semaphore was not deleted
+ // in between the two calls to the subsystem, so add an
+ // entry for this handle in the semaphore table, using the
+ // NT Event handle we got from the subsystem.
+ //
+
+ NewSemaphore.Type = Od2EventSem;
+ NewSemaphore.Shared = TRUE;
+ NewSemaphore.PointerCount = 0;
+ NewSemaphore.OpenCount = 1;
+ NewSemaphore.u.Value = (PVOID)a->NtEventHandle;
+
+ if (!Or2CreateHandle( SemaphoreTable,
+ &a->HandleIndex,
+ (PVOID)&NewSemaphore
+ )
+ ) {
+ //
+ // Unable to create the entry. Close the NT event
+ // handle, as it will not be used. Then call the
+ // OS/2 subsystem to close our reference to this shared
+ // OS/2 semaphore. Set the appropriate error code.
+ //
+
+ NtClose( a->NtEventHandle );
+ a1->HandleIndex = a->HandleIndex;
+ Od2CallSubsystem( &m,
+ NULL,
+ Os2CloseEventSem,
+ sizeof( *a1 )
+ );
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+ }
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is an Event semaphore.
+ // Set the appropriate error code if not.
+ //
+
+ else
+ if (Semaphore->Type != Od2EventSem) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+
+ //
+ // Entry in semaphore table is for an Event semaphore, see if the OpenCount
+ // is about to overflow, and set the appropriate error code if it is.
+ //
+
+ else
+ if (Semaphore->OpenCount == 0xFFFF) {
+ rc = ERROR_TOO_MANY_OPENS;
+ }
+
+ //
+ // Everything is okay, so bump the open count in the semaphore table entry.
+ //
+
+ else {
+ Semaphore->OpenCount++;
+ }
+
+ //
+ // All done mucking about, so release the semaphore table lock.
+ //
+
+ ReleaseHandleTableLock( SemaphoreTable );
+
+ //
+ // If no errors, store a valid OS/2 2.0 Semaphore handle in the location
+ // specified by the caller and return success to the caller.
+ //
+
+ if (rc == NO_ERROR) {
+ *EventHandle = Od2ConstructSemaphoreHandle( SharedSem,
+ a->HandleIndex
+ );
+ }
+
+ //
+ // Return an error code to the caller.
+ //
+
+ return( rc );
+}
+
+
+APIRET
+DosCloseEventSem(
+ IN HEV EventHandle
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSCLOSEEVENTSEM_MSG a = &m.u.DosCloseEventSem;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ HANDLE NtEventHandle;
+ BOOLEAN SharedSem;
+ APIRET rc;
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( EventHandle,
+ &SharedSem,
+ &a->HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ a->HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is an Event semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2EventSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table is for an Event semaphore, so decrement the
+ // OpenCount and see if it has gone to zero.
+ //
+
+ if (--Semaphore->OpenCount == 0) {
+
+ //
+ // OpenCount is now zero, so we can really close the semaphore
+ // and delete the entry in the semaphore table.
+ //
+
+ //
+ // First make sure that no thread in this process is waiting on this
+ // event. If there is one waiting on it, increment the open count and
+ // return an error.
+ //
+
+
+ //if { !(Od2Process->Pib.Status & PS_EXITLIST) && (Od2SearchForWaitingThread( Semaphore )) ) {
+ // Semaphore->OpenCount++;
+ // ReleaseHandleTableLock( SemaphoreTable );
+ // rc = ERROR_SEM_BUSY;
+ // }
+ //
+ //else {
+
+ //
+ // Okay to really close this event semaphore. First destroy
+ // the handle, which will unlock the handle table.
+ //
+
+ NtEventHandle = Semaphore->u.EventHandle;
+ Or2DestroyHandle( SemaphoreTable, a->HandleIndex );
+ NtClose( NtEventHandle );
+
+ //
+ // If this is a shared semaphore, call the subsystem so that it
+ // can decrement its open count, as this process is not longer
+ // using the shared semaphore handle.
+ //
+
+ if (SharedSem) {
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2CloseEventSem,
+ sizeof( *a )
+ );
+ }
+ // }
+ }
+ else {
+ //
+ // OpenCount is still non-zero, so just release the semaphore table
+ // lock.
+ //
+
+ ReleaseHandleTableLock( SemaphoreTable );
+ }
+
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
+
+
+APIRET
+DosResetEventSem(
+ IN HEV EventHandle,
+ OUT PULONG PostCount
+ )
+{
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ BOOLEAN SharedSem;
+ ULONG HandleIndex;
+ APIRET rc;
+ NTSTATUS Status;
+ HANDLE NtEventHandle;
+ LONG NtEventCount;
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( EventHandle,
+ &SharedSem,
+ &HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is an Event semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2EventSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+
+ //
+ // Entry in semaphore table is for an Event semaphore, so extract the
+ // NT Event handle from the record and release the lock, so we are
+ // not holding the lock when the semaphore is reset.
+ //
+
+ NtEventHandle = Semaphore->u.EventHandle;
+ ReleaseHandleTableLock( SemaphoreTable );
+
+ //
+ // Call the NT system service to reset the event's signal count.
+ //
+
+ Status = NtResetEvent( NtEventHandle, &NtEventCount );
+ if (NT_SUCCESS( Status )) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosResetEventSem Handle %lx, PreviousCount %lx\n",
+ NtEventHandle, NtEventCount);
+ }
+#endif
+ //
+ // If successful, the map the NT signal count into the 64K limitation
+ // implemented by OS/2 2.0
+ //
+
+ try {
+ if (NtEventCount > 0xFFFF) {
+ *PostCount = 0xFFFF;
+ }
+ else {
+ *PostCount = NtEventCount;
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // If the event was already reset, let the caller know, although this
+ // is a non-fatal error.
+ //
+
+ if (rc == NO_ERROR) {
+ if (NtEventCount == 0) {
+ rc = ERROR_ALREADY_RESET;
+ }
+ }
+ }
+ else {
+ //
+ // If the NT system service failed, then some other thread must
+ // have closed the semaphore so return an error.
+ //
+
+ rc = ERROR_INVALID_HANDLE;
+ }
+
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
+
+
+APIRET
+DosPostEventSem(
+ IN HEV EventHandle
+ )
+{
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ BOOLEAN SharedSem;
+ ULONG HandleIndex;
+ APIRET rc;
+ NTSTATUS Status;
+ HANDLE NtEventHandle;
+ LONG NtEventCount;
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( EventHandle,
+ &SharedSem,
+ &HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is an Event semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2EventSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table is for an Event semaphore, so extract the
+ // NT Event handle from the record and release the lock, so we are
+ // not holding the lock when the semaphore is set.
+ //
+
+ NtEventHandle = Semaphore->u.EventHandle;
+ ReleaseHandleTableLock( SemaphoreTable );
+
+ //
+ // Call the NT system service to set (increment) the event's signal
+ // count.
+ //
+
+ Status = NtSetEvent( NtEventHandle, &NtEventCount );
+ if (NT_SUCCESS( Status )) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosPostEventSem Handle %lx, PreviousCount %lx\n",
+ NtEventHandle, NtEventCount);
+ }
+#endif
+ //
+ // If successful, see if this the signal count has exceeded the 64K
+ // limitation implemented by OS/2 2.0 and return the appropriate
+ // error code.
+ //
+
+ if (NtEventCount != 0) {
+ if (NtEventCount >= 0xFFFF) {
+ rc = ERROR_TOO_MANY_POSTS;
+ }
+ else {
+ rc = ERROR_ALREADY_POSTED;
+ }
+ }
+ }
+ else {
+ //
+ // If the NT system service failed, then some other thread must
+ // have closed the semaphore so return an error.
+ //
+
+ rc = ERROR_INVALID_HANDLE;
+ }
+
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
+
+
+APIRET
+DosWaitEventSem(
+ IN HEV EventHandle,
+ IN ULONG Timeout
+ )
+{
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ BOOLEAN SharedSem;
+ ULONG HandleIndex;
+ APIRET rc;
+ NTSTATUS Status;
+ HANDLE NtEventHandle;
+ LARGE_INTEGER CapturedTimeout;
+ PLARGE_INTEGER NtTimeout;
+ LARGE_INTEGER StartTimeStamp;
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( EventHandle,
+ &SharedSem,
+ &HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Capture the timeout value and convert it into an NT timeout value.
+ //
+
+ NtTimeout = Od2CaptureTimeout( Timeout, (PLARGE_INTEGER)&CapturedTimeout );
+
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+DosWaitEventSem_retry:
+ if (NtTimeout) {
+ Od2StartTimeout(&StartTimeStamp);
+ }
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is an Event semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2EventSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table is for an Event semaphore, so extract the
+ // NT Event handle from the record and release the lock, so we are
+ // not holding the lock while we are waiting.
+ //
+
+ NtEventHandle = Semaphore->u.EventHandle;
+
+ //
+ // Call the NT system service to wait for this event to be signalled.
+ // This is an alertable wait, since by definition all OS/2 waits are
+ // alertable.
+ //
+
+ Od2ThreadWaitingOnSemaphore( SemaphoreTable, Semaphore, TRUE );
+ Status = NtWaitForSingleObject( NtEventHandle, TRUE, NtTimeout );
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ ASSERT(FALSE);
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is an Event semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2EventSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ ASSERT(FALSE);
+ return( ERROR_INVALID_HANDLE );
+ }
+ ReleaseHandleTableLock( SemaphoreTable );
+ Od2ThreadWaitingOnSemaphore( SemaphoreTable, Semaphore, FALSE );
+
+ if (NT_SUCCESS( Status )) {
+ if (Status == STATUS_SUCCESS) {
+ }
+ else
+ if (Status == STATUS_ABANDONED) {
+ rc = ERROR_SEM_OWNER_DIED;
+ }
+ else
+ if (Status == STATUS_TIMEOUT) {
+ rc = ERROR_TIMEOUT;
+ }
+ else
+ if (Status == STATUS_USER_APC) {
+#if DBG
+ DbgPrint("[%d,%d] WARNING !!! DosWaitEventSem was broken by APC\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ );
+#endif
+ if (Od2ContinueTimeout(&StartTimeStamp, NtTimeout) == STATUS_SUCCESS) {
+ goto DosWaitEventSem_retry;
+ }
+ else {
+ rc = ERROR_TIMEOUT;
+ }
+ }
+ else
+ if (Status == STATUS_ALERTED) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("[%d,%d] DosWaitEventSem ALERTED\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId());
+ }
+#endif
+ rc = ERROR_INTERRUPT;
+ }
+ else
+ {
+ // Some success status that we don't know about. We will
+ // be safe in this case and will print appropriate message.
+#if DBG
+ DbgPrint("[%d,%d] DosWaitEventSem BUGBUG Unkownd success status = %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(), Status);
+#endif
+ rc = ERROR_INTERRUPT;
+ }
+ }
+ else {
+ //
+ // If the NT system service failed, then some other thread must
+ // have closed the semaphore so return an error or this thread was
+ // alerted out of the wait. Return the appropriate error code.
+ //
+
+ if (Status == STATUS_INVALID_HANDLE) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+ else {
+ rc = Or2MapStatus( Status );
+ }
+ }
+
+
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
+
+
+APIRET
+DosQueryEventSem(
+ IN HEV EventHandle,
+ OUT PULONG PostCount
+ )
+{
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ BOOLEAN SharedSem;
+ ULONG HandleIndex;
+ APIRET rc;
+ NTSTATUS Status;
+ EVENT_BASIC_INFORMATION EventInformation;
+ HANDLE NtEventHandle;
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( EventHandle,
+ &SharedSem,
+ &HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is an Event semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2EventSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table is for an Event semaphore, so extract the
+ // NT Event handle from the record and release the lock, so we are
+ // not holding the lock while we are doing the query.
+ //
+
+ NtEventHandle = Semaphore->u.EventHandle;
+ ReleaseHandleTableLock( SemaphoreTable );
+
+ //
+ // Call the NT system service to query the event's signal count.
+ //
+
+ Status = NtQueryEvent( Semaphore->u.EventHandle,
+ EventBasicInformation,
+ (PVOID)&EventInformation,
+ sizeof( EventInformation ),
+ NULL
+ );
+ if (NT_SUCCESS( Status )) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosQueryEventSem Handle %lx, Count %lx\n",
+ NtEventHandle,EventInformation.EventState );
+ }
+#endif
+ //
+ // If successful, the map the NT signal count into the 64K limitation
+ // implemented by OS/2 2.0
+ //
+
+ try {
+ if ((ULONG)EventInformation.EventState > 0xFFFF) {
+ *PostCount = 0xFFFF;
+ }
+ else {
+ *PostCount = (ULONG)EventInformation.EventState;
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ }
+ else {
+ //
+ // If the NT system service failed, then some other thread must
+ // have closed the semaphore so return an error.
+ //
+
+ rc = ERROR_INVALID_HANDLE;
+ }
+
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
diff --git a/private/os2/client/dllfile.c b/private/os2/client/dllfile.c
new file mode 100644
index 000000000..e33f8ca9d
--- /dev/null
+++ b/private/os2/client/dllfile.c
@@ -0,0 +1,653 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllfile.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 filename APIs: DosDelete,
+ DosMove, DosEditName
+
+Author:
+
+ Therese Stowell (thereses) 17-Jan-1990
+
+Revision History:
+
+--*/
+
+
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FILESYS
+#include "os2dll.h"
+#ifdef DBCS
+// MSKK Sep.27.1993 V-AkihiS
+#include "conrqust.h"
+#include "os2win.h"
+#endif
+
+extern
+APIRET
+DeleteObject(
+ IN PSZ ObjectName,
+ IN ULONG ObjectType
+ );
+
+
+
+APIRET
+DosDelete(
+ IN PSZ FileName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deletes a file.
+
+Arguments:
+
+ FileName - file to delete
+
+Return Value:
+
+ TBS
+
+--*/
+
+{
+ APIRET RetCode;
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("entering DosDelete with %s\n",FileName);
+ }
+#endif
+ RetCode = DeleteObject(FileName,FILE_NON_DIRECTORY_FILE);
+ return RetCode;
+}
+
+BOOLEAN
+ScanForPathChars(
+ PSZ String
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks for path characters ("/","\")in a string.
+
+Arguments:
+
+ String - string to scan for path chars
+
+Return Value:
+
+ TRUE - path character found
+
+ FALSE - path character not found
+
+--*/
+
+{
+ while (*String) {
+ if ((*String == '\\') || (*String == '/'))
+ return TRUE;
+// if (DBCS(String))
+ if (IsDbcs(String)) // MSKK fix for NON-DBCS build break
+ String++;
+ String++;
+ }
+ return FALSE;
+}
+
+
+APIRET
+DosEditName(
+ IN ULONG EditLevel,
+ IN PSZ SourceString,
+ IN PSZ EditString,
+ OUT PBYTE Buffer,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes two strings, a source and editing string, and composes
+ a third string using them. The editing string may contain wildcard
+ characters. The source may not. This API is used to determine the
+ destination filename in a rename or copy. For example, if the source
+ string is "foo.bar" and the editing string is "*.exe", the resulting
+ string is "foo.exe".
+
+Arguments:
+
+ EditLevel - type of editing to perform
+
+ SourceString - source string
+
+ EditString - editing string
+
+ Buffer - where to store the resulting string
+
+ Length - length of buffer
+
+Return Value:
+
+ ERROR_INVALID_PARAMETER - invalid editlevel.
+
+ ERROR_INVALID_NAME - the source or edit string contains path characters.
+
+ ERROR_BUFFER_OVERFLOW - the resulting string will not fit in the user's
+ buffer.
+
+--*/
+
+{
+ ULONG ResultLength;
+ PCHAR pSrc, pEd, pRes, pDelimit;
+
+ //
+ // check edit level
+ //
+ if (EditLevel != EDIT_LEVEL_ONE) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // check for path chars in source and editstring
+ //
+ try {
+ if (ScanForPathChars(SourceString))
+ return ERROR_INVALID_NAME;
+ if (ScanForPathChars(EditString))
+ return ERROR_INVALID_NAME;
+
+ pSrc = SourceString;
+ pEd = EditString;
+ pRes = Buffer;
+ ResultLength = 0;
+ while (*pEd) {
+ if (ResultLength <Length) {
+ switch (*pEd) {
+ case '*':
+ pDelimit = pEd+1;
+ while ((ResultLength <Length) &&
+ (*pSrc != '\0') &&
+ !(CharsEqual(pSrc,pDelimit))) {
+#ifdef DBCS
+// MSKK Mar.24.1993 V-AkihiS
+// MSKK Sep.27.1993 V-AkihiS
+ if (IsDbcs(pSrc)) {
+ *pRes++ = *pSrc++;
+ ResultLength++;
+ if ((ResultLength < Length) && (*pSrc != '\0')) {
+ *pRes++ = *pSrc++;
+ ResultLength++;
+ }
+ } else {
+ *pRes++ = UCase(*pSrc);
+ pSrc++;
+ ResultLength++;
+ }
+#else
+// if (DBCS(pSrc)) {
+ if (IsDbcs(pSrc)) { // MSKK fix for NON-DBCS build break
+ *pRes++ = *pSrc++;
+ ResultLength++;
+ }
+ if (ResultLength <Length) {
+ *pRes++ = UCase(*pSrc);
+ pSrc++;
+ ResultLength++;
+ }
+#endif
+ }
+ break;
+ case '?':
+ if ((*pSrc != '.') && (*pSrc != '\0')) {
+#ifdef DBCS
+// MSKK Mar.24.1993 V-AkihiS
+// MSKK Sep.27.1993 V-AkihiS
+ if (IsDbcs(pSrc)) {
+ *pRes++ = *pSrc++;
+ ResultLength++;
+ if ((ResultLength < Length) && (*pSrc != '\0')) {
+ *pRes++ = *pSrc++;
+ ResultLength++;
+ }
+ } else {
+ *pRes++ = UCase(*pSrc);
+ pSrc++;
+ ResultLength++;
+ }
+#else
+// if (DBCS(pSrc)) {
+ if (IsDbcs(pSrc)) { // MSKK fix for NON-DBCS build break
+ *pRes++ = *pSrc++;
+ ResultLength++;
+ }
+ if (ResultLength <Length) {
+ *pRes++ = UCase(*pSrc);
+ pSrc++;
+ ResultLength++;
+ }
+#endif
+ }
+ break;
+ case '.':
+ while ((*pSrc != '.') && (*pSrc != '\0')) {
+// if (DBCS(pSrc))
+ if (IsDbcs(pSrc)) // MSKK fix for NON-DBCS build break
+ pSrc++;
+ pSrc++;
+ }
+ *pRes++ = '.'; // from EditMask, even if src doesn't
+ // have one, so always put one.
+ ResultLength++;
+ if (*pSrc) // point one past '.'
+ pSrc++;
+ break;
+ default:
+ if ((*pSrc != '.') && (*pSrc != '\0')) {
+// if (DBCS(pSrc))
+ if (IsDbcs(pSrc)) // MSKK fix for NON-DBCS build break
+ pSrc++;
+ pSrc++;
+ }
+#ifdef DBCS
+// MSKK Mar.24.1993 V-AkihiS
+// MSKK Sep.27.1993 V-AkihiS
+ if (IsDbcs(pEd)) {
+ *pRes++ = *pEd++;
+ ResultLength++;
+ if ((ResultLength < Length) && (*pEd != '\0')) {
+ *pRes++ = *pEd;
+ ResultLength++;
+ }
+ } else {
+ *pRes++ = UCase(*pEd);
+ ResultLength++;
+ }
+#else
+// if (DBCS(pEd)) {
+ if (IsDbcs(pEd)) { // MSKK fix for NON-DBCS build break
+ *pRes++ = *pEd++;
+ ResultLength++;
+ }
+ if (ResultLength <Length) {
+ *pRes++ = UCase(*pEd);
+ ResultLength++;
+ }
+#endif
+ }
+ pEd++;
+ }
+ else {
+ return ERROR_BUFFER_OVERFLOW;
+ }
+ }
+ if (ResultLength < Length) {
+ *pRes = '\0';
+// ResBufLen = ++ResultLength;
+ return(NO_ERROR);
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return ERROR_BUFFER_OVERFLOW;
+}
+
+
+APIRET
+DosMove(
+ IN PSZ OldFileName,
+ IN PSZ NewFileName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine renames a file or directory
+
+Arguments:
+
+ OldFileName - file to rename
+
+ NewFileName - new name of file
+
+Return Value:
+
+ TBS
+
+--*/
+
+{
+ NTSTATUS Status;
+ APIRET RetCode = NO_ERROR;
+ STRING OldNameString, NewNameString;
+ UNICODE_STRING OldNameString_U, NewNameString_U;
+ ULONG FileType;
+ ULONG FileFlags;
+ HANDLE OldFileHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ typedef struct _FILE_RENAME_INFORMATION_BUFFER {
+ FILE_RENAME_INFORMATION NameLengthAndFirstChar;
+ CHAR RestOfName[255];
+ } FILE_RENAME_INFORMATION_BUFFER;
+ FILE_RENAME_INFORMATION_BUFFER FileRenameInfo;
+ BOOLEAN OldIsConfigSys = FALSE;
+ BOOLEAN NewIsConfigSys = FALSE;
+
+ //
+ // canonicalize old file name
+ //
+
+
+ RetCode = Od2Canonicalize(OldFileName,
+ CANONICALIZE_FILE_OR_DEV,
+ &OldNameString,
+ NULL,
+ &FileFlags,
+ &FileType
+ );
+ if (RetCode != NO_ERROR)
+ {
+ if (RetCode != ERROR_FILENAME_EXCED_RANGE && RetCode != ERROR_FILE_NOT_FOUND)
+ {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ }
+ return RetCode;
+ }
+
+ //
+ // Special handling of <boot-drive>:\config.sys
+ // opening this file is mapped to the OS/2 SS config.sys
+ //
+ if (Od2FileIsConfigSys(&OldNameString, OPEN_ACCESS_READWRITE, &Status))
+ {
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to init for config.sys
+
+ RtlFreeHeap(Od2Heap,0,OldNameString.Buffer);
+ return Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ }
+
+ FileFlags = 0;
+ FileType = FILE_TYPE_FILE;
+ OldIsConfigSys = TRUE;
+ }
+
+ if (FileFlags & CANONICALIZE_META_CHARS_FOUND) {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ }
+ else if (FileFlags & CANONICALIZE_IS_ROOT_DIRECTORY) {
+ RetCode = ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // check for old file name being invalid type
+ //
+// BUGBUG rename of \pipe\ directory is ok. why???? remember this when
+// implementing named pipes.
+
+ else if (FileType & (FILE_TYPE_NMPIPE | FILE_TYPE_DEV | FILE_TYPE_PSDEV | FILE_TYPE_MAILSLOT)) {
+ RetCode = ERROR_ACCESS_DENIED;
+ }
+ if (RetCode != NO_ERROR) {
+ RtlFreeHeap(Od2Heap,0,OldNameString.Buffer);
+ return RetCode;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("returned from Canonicalize with oldname: %s\n",OldNameString.Buffer);
+ }
+#endif
+
+ //
+ // canonicalize new file name
+ //
+
+ RetCode = Od2Canonicalize(NewFileName,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &NewNameString,
+ NULL,
+ &FileFlags,
+ &FileType
+ );
+ if (RetCode != NO_ERROR)
+ {
+ if (RetCode != ERROR_FILENAME_EXCED_RANGE && RetCode != ERROR_FILE_NOT_FOUND)
+ {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ }
+ RtlFreeHeap(Od2Heap,0,OldNameString.Buffer);
+ return RetCode;
+ }
+
+
+ //
+ // Special handling of <boot-drive>:\config.sys
+ // opening this file is mapped to the OS/2 SS config.sys
+ //
+ if (Od2FileIsConfigSys(&NewNameString, OPEN_ACCESS_READWRITE, &Status))
+ {
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to init for config.sys
+
+ RtlFreeHeap(Od2Heap,0,OldNameString.Buffer);
+ RtlFreeHeap(Od2Heap,0,NewNameString.Buffer);
+ return Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ }
+
+ FileFlags = 0;
+ FileType = FILE_TYPE_FILE;
+ NewIsConfigSys = TRUE;
+ }
+
+ //
+ // check for new file name being invalid type
+ //
+
+ if (FileFlags & CANONICALIZE_META_CHARS_FOUND) {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ }
+ else if (FileFlags & CANONICALIZE_IS_ROOT_DIRECTORY) {
+ RetCode = ERROR_ACCESS_DENIED;
+ }
+ else if (FileType & (FILE_TYPE_NMPIPE | FILE_TYPE_DEV | FILE_TYPE_PSDEV | FILE_TYPE_MAILSLOT)) {
+ RetCode = ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // \Config.sys and \Startup.cmd which are on the boot device are mapped
+ // to the OS/2 SS files which may be on a different device alltogether
+ // with the NT tree. Allow thw move only for this special case.
+ //
+
+ else if (OldIsConfigSys) {
+ if (RtlUpperChar(NewNameString.Buffer[FILE_PREFIX_LENGTH+DRIVE_LETTER]) !=
+ (CHAR)('A' + Od2BootDrive)) {
+ RetCode = ERROR_NOT_SAME_DEVICE;
+ }
+ }
+
+ else if (NewIsConfigSys) {
+ if (RtlUpperChar(OldNameString.Buffer[FILE_PREFIX_LENGTH+DRIVE_LETTER]) !=
+ (CHAR)('A' + Od2BootDrive)) {
+ RetCode = ERROR_NOT_SAME_DEVICE;
+ }
+ }
+
+ //
+ // check that old and new names are on same device
+ //
+
+ else if (!(FileType & FILE_TYPE_UNC) &&
+ (RtlUpperChar(OldNameString.Buffer[FILE_PREFIX_LENGTH+DRIVE_LETTER]) !=
+ RtlUpperChar(NewNameString.Buffer[FILE_PREFIX_LENGTH+DRIVE_LETTER]))) {
+ RetCode = ERROR_NOT_SAME_DEVICE;
+ }
+ if (RetCode != NO_ERROR) {
+ RtlFreeHeap(Od2Heap,0,OldNameString.Buffer);
+ RtlFreeHeap(Od2Heap,0,NewNameString.Buffer);
+ return RetCode;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("returned from Canonicalize with newname: %s\n",NewNameString.Buffer);
+ }
+#endif
+
+ //
+ // open old file
+ //
+
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &OldNameString_U,
+ &OldNameString,
+ TRUE);
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("Od2MBStringToUnicodeString returned %lu\n",RetCode);
+ }
+#endif
+ RtlFreeHeap(Od2Heap,0,OldNameString.Buffer);
+ RtlFreeHeap(Od2Heap,0,NewNameString.Buffer);
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &OldNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ do {
+ Status = NtOpenFile(&OldFileHandle,
+ DELETE | SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ 0,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+ RtlFreeUnicodeString (&OldNameString_U);
+
+ if (!NT_SUCCESS(Status)) {
+ RtlFreeHeap(Od2Heap,0,OldNameString.Buffer);
+ RtlFreeHeap(Od2Heap,0,NewNameString.Buffer);
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtOpenFile returned %X\n",Status);
+ }
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_PATH_NOT_FOUND));
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtOpenFile successful\n");
+ }
+#endif
+
+ //
+ // now that the file is opened, we need to make sure that it isn't a
+ // device or named pipe that Canonicalize didn't detect.
+ // +
+
+ if (CheckFileType(OldFileHandle,FILE_TYPE_NMPIPE | FILE_TYPE_DEV | FILE_TYPE_MAILSLOT)) {
+ RtlFreeHeap(Od2Heap,0,OldNameString.Buffer);
+ RtlFreeHeap(Od2Heap,0,NewNameString.Buffer);
+ NtClose(OldFileHandle);
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("source is not a file/dir name\n");
+ }
+#endif
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // the following code initializes the FileNameInfo structure for the
+ // call to NtSetInformationFile, then makes the call.
+ //
+
+ //
+ // UNICODE conversion -
+ //
+ RetCode = Od2MBStringToUnicodeString(
+ &NewNameString_U,
+ &NewNameString,
+ TRUE);
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("Od2MBStringToUnicodeString-2 returned %lu\n",RetCode);
+ }
+#endif
+ RtlFreeHeap(Od2Heap,0,OldNameString.Buffer);
+ RtlFreeHeap(Od2Heap,0,NewNameString.Buffer);
+ return RetCode;
+ }
+
+ //
+ // Set All RenameInfo fields and call NT
+ //
+ FileRenameInfo.NameLengthAndFirstChar.ReplaceIfExists = FALSE;
+ FileRenameInfo.NameLengthAndFirstChar.RootDirectory = NULL;
+ FileRenameInfo.NameLengthAndFirstChar.FileNameLength = NewNameString_U.Length;
+ RtlMoveMemory(&(FileRenameInfo.NameLengthAndFirstChar.FileName),
+ NewNameString_U.Buffer,
+ NewNameString_U.Length
+ );
+ if (NT_SUCCESS(Status)) {
+ do {
+ Status = NtSetInformationFile(OldFileHandle,
+ &IoStatus,
+ (PVOID) &FileRenameInfo,
+ sizeof (FileRenameInfo),
+ FileRenameInformation
+ );
+ } while (RetryIO(Status, OldFileHandle));
+ }
+ RtlFreeHeap(Od2Heap,0,OldNameString.Buffer);
+ RtlFreeHeap(Od2Heap,0,NewNameString.Buffer);
+ RtlFreeUnicodeString(&NewNameString_U);
+ NtClose(OldFileHandle);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtSetInformationFile returned %X\n",Status);
+ }
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_PATH_NOT_FOUND));
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("NtSetInformationFile successful\n");
+ }
+#endif
+}
diff --git a/private/os2/client/dllfind.c b/private/os2/client/dllfind.c
new file mode 100644
index 000000000..fb208c04f
--- /dev/null
+++ b/private/os2/client/dllfind.c
@@ -0,0 +1,2265 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dllfind.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 findfirst/next/close APIs
+
+Author:
+
+ Therese Stowell (thereses) 5-Jan-1990
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FILESYS
+#include "os2dll.h"
+#ifdef DBCS
+// MSKK Sep.29.1993 V-AkihiS
+#include "conrqust.h"
+#include "os2win.h"
+#endif
+
+
+APIRET
+AllocateSearchHandle(
+ OUT PHDIR SearchHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a search handle and saves the data associated
+ with a search.
+
+Arguments:
+
+ SearchHandle - where to store the OS/2 search handle
+
+Return Value:
+
+ none.
+
+Note:
+
+ As an optimization, we could remember the number of the last search
+ handle and start looking for a new one from there.
+
+ The caller must have the FileLock exclusively.
+
+--*/
+
+{
+ ULONG i;
+ ULONG NewTableLength;
+ PSEARCH_RECORD *NewTable;
+
+ for (i=2;i<SearchHandleTableLength;i++) {
+ if (SearchHandleTable[i] == SEARCH_HANDLE_FREE) {
+ try {
+ *SearchHandle = (HDIR) i;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return NO_ERROR;
+ }
+ }
+ NewTableLength = SearchHandleTableLength + SEARCH_TABLE_HANDLE_INCREMENT;
+ NewTable = RtlAllocateHeap(Od2Heap,0,NewTableLength * sizeof(ULONG));
+ if (NewTable == NULL) {
+#if DBG
+ KdPrint(( "OS2: AllocateSearchHandle, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ RtlMoveMemory(NewTable,SearchHandleTable,SearchHandleTableLength * sizeof(ULONG));
+ for (i=SearchHandleTableLength;i<NewTableLength;i++) {
+ NewTable[i] = SEARCH_HANDLE_FREE;
+ }
+ if (SearchHandleTableLength != INITIAL_SEARCH_HANDLES) {
+ RtlFreeHeap(Od2Heap,0,SearchHandleTable);
+ }
+ SearchHandleTable = NewTable;
+ try {
+ *SearchHandle = (HDIR) SearchHandleTableLength;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ SearchHandleTableLength = NewTableLength;
+ Od2ExitGP();
+ }
+
+ SearchHandleTableLength = NewTableLength;
+
+ return NO_ERROR;
+}
+
+APIRET
+FreeSearchHandle(
+ IN HDIR SearchHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees a search handle.
+
+Arguments:
+
+ SearchHandle - OS/2 search handle to free
+
+Return Value:
+
+ none.
+
+Note:
+
+ The caller must have the FileLock exclusively.
+
+--*/
+
+{
+ PSEARCH_RECORD SearchRecord;
+
+ // we need to close the NT directory handle associated with the search
+ // and free the search record.
+
+ if (SearchHandleTable[(ULONG) SearchHandle] != SEARCH_HANDLE_FREE) {
+ SearchRecord = (PSEARCH_RECORD) SearchHandleTable[((ULONG)SearchHandle)];
+ NtClose(SearchRecord->NtHandle);
+ RtlFreeHeap(Od2Heap,0,SearchRecord);
+ SearchHandleTable[(ULONG) SearchHandle] = SEARCH_HANDLE_FREE;
+ return NO_ERROR;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("FreeSeachHandle: invalid handle %x\n",SearchHandle);
+ }
+#endif
+ return ERROR_INVALID_HANDLE;
+}
+
+APIRET
+SaveSearchInfo(
+ IN BOOLEAN Rewind,
+ IN PFILE_DIRECTORY_INFORMATION RewindEntry,
+ IN PVOID FindBuffer,
+ IN ULONG BufferLength,
+ IN HANDLE DirectoryHandle,
+ IN ULONG Attributes,
+ IN OUT PHDIR UserSearchHandle,
+ IN ULONG FileInformationLevel
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a search handle and saves the data associated
+ with a search.
+
+Arguments:
+
+ Rewind - whether to rewind the search
+
+ RewindEntry - pointer to the entry to rewind from
+
+ FindBuffer - buffer containing entries returned by NtQueryDirectoryFile
+
+ BufferLength - length of FindBuffer
+
+ DirectoryHandle - the NT search handle
+
+ Attributes - The attributes used in the search
+
+ UserSearchHandle - where to store the OS/2 search handle (unprobed)
+
+Return Value:
+
+ ERROR_INVALID_HANDLE - the specified search handle was invalid.
+
+--*/
+
+{
+ APIRET RetCode;
+ PSEARCH_RECORD SearchRecord;
+ ULONG SearchHandle;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "SaveSearchInfo";
+ #endif
+
+ try {
+ SearchHandle = (ULONG) *UserSearchHandle;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (SearchHandle == HDIR_CREATE) {
+ RetCode = AllocateSearchHandle(UserSearchHandle);
+ SearchHandle = (ULONG) *UserSearchHandle;
+ } else if (SearchHandle < SearchHandleTableLength) {
+ if (SearchHandleTable[SearchHandle] == SEARCH_HANDLE_FREE) {
+ if (SearchHandle != HDIR_SYSTEM) {
+ RetCode = ERROR_INVALID_HANDLE;
+ } else {
+ RetCode = NO_ERROR;
+ }
+ }
+ else {
+ NtClose(SearchHandleTable[SearchHandle]->NtHandle); // close the old handle of DosFindFirst
+ if (SearchHandleTable[SearchHandle]->FindBuffer != NULL) { // free FindBuffer
+ RtlFreeHeap(Od2Heap,0,SearchHandleTable[SearchHandle]->FindBuffer);
+ }
+ RtlFreeHeap(Od2Heap,0,SearchHandleTable[SearchHandle]);
+ RetCode = NO_ERROR;
+ }
+ }
+ else {
+ RetCode = ERROR_INVALID_HANDLE;
+ }
+
+ if (RetCode != NO_ERROR) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ return RetCode;
+ }
+
+ SearchHandleTable[SearchHandle] = RtlAllocateHeap(Od2Heap,0,sizeof(SEARCH_RECORD));
+ if (SearchHandleTable[SearchHandle] == NULL) {
+#if DBG
+ KdPrint(( "OS2: AllocateSearchHandle, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ SearchRecord = (PSEARCH_RECORD) SearchHandleTable[SearchHandle];
+ SearchRecord->Attributes = Attributes;
+ SearchRecord->NtHandle = DirectoryHandle;
+ SearchRecord->InformationLevel = FileInformationLevel;
+ if (Rewind) {
+ SearchRecord->FindBuffer = FindBuffer;
+ SearchRecord->BufferLength = BufferLength;
+ SearchRecord->RewindEntry = RewindEntry;
+ }
+ else {
+ SearchRecord->FindBuffer = NULL;
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ }
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return NO_ERROR;
+}
+
+
+
+APIRET
+UpdateSearchInfo(
+ IN BOOLEAN Rewind,
+ IN PFILE_DIRECTORY_INFORMATION RewindEntry,
+ IN PVOID FindBuffer,
+ IN ULONG BufferLength,
+ IN HDIR SearchHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine updates the search record after a FindNext.
+
+Arguments:
+
+ Rewind - whether to rewind the search
+
+ RewindEntry - pointer to the entry to rewind from
+
+ SearchHandle - which search record to update
+
+Return Value:
+
+ none.
+
+Note:
+
+ The caller must have the FileLock shared. we convert it to exclusive.
+
+--*/
+
+{
+ PSEARCH_RECORD SearchRecord;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "UpdateSearchInfo";
+ #endif
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("entering UpdateSearchInfo. rewind is %d\n",Rewind);
+ }
+#endif
+ PromoteFileLocktoExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (SearchHandleTable[(ULONG) SearchHandle] == SEARCH_HANDLE_FREE) {
+ ASSERT(FALSE);
+ }
+
+ SearchRecord = (PSEARCH_RECORD) SearchHandleTable[((ULONG)SearchHandle)];
+ if (Rewind) {
+ SearchRecord->FindBuffer = FindBuffer;
+ SearchRecord->BufferLength = BufferLength;
+ SearchRecord->RewindEntry = RewindEntry;
+ }
+ else {
+ SearchRecord->FindBuffer = NULL;
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("leaving UpdateSearchInfo.\n");
+ }
+#endif
+ return NO_ERROR;
+}
+
+
+BOOLEAN
+MatchAttributes(
+ IN ULONG FoundAttributes,
+ IN ULONG RequestedAttributes,
+ IN BOOLEAN Directory
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether the FoundAttributes match the
+ RequestedAttributes, according to OS/2 matching rules.
+
+Arguments:
+
+ FoundAttributes - the attributes, in NT format, associated with
+ the found directory entry.
+
+ RequestedAttributes - the desired attributes set, in OS/2 format.
+
+ Directory - the Directory field associated with the found directory
+ entry.
+
+Return Value:
+
+ TRUE - the attributes match
+
+ FALSE - the attributes do not match
+
+--*/
+
+{
+
+ // turn off attributes that we don't base searches on (readonly, archived, and
+ // control.
+
+ FoundAttributes &= ~ATTR_IGNORE;
+
+ // map NT attributes to OS/2 attributes
+
+ if (Directory) {
+ FoundAttributes |= FILE_DIRECTORY;
+ }
+ else if (FoundAttributes & FILE_ATTRIBUTE_NORMAL) {
+ if (RequestedAttributes & ATTR_NOT_NORM)
+ return FALSE;
+ else
+ return TRUE;
+ }
+ //
+ // the following code is a direct port of OS/2 code.
+ //
+ // the result is non-zero if an attribute is not in the RequestedAttribute set
+ // and in the FoundAttribute set and in the {hidden, system, directory}
+ // important set. This means that we do not have a match.
+ //
+ if ((~RequestedAttributes & FoundAttributes) &
+ (FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY)) {
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+}
+
+VOID
+MapAttributesToOs2(
+ IN ULONG NtAttributes,
+ OUT PUSHORT Os2Attributes
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts attributes from NT format to OS/2 format.
+
+Arguments:
+
+ NtAttributes - the attributes in NT format.
+
+ Os2Attributes - where the converted attributes are returned.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ *Os2Attributes = (USHORT) NtAttributes;
+ if (*Os2Attributes & FILE_ATTRIBUTE_NORMAL) {
+ *Os2Attributes = 0;
+ }
+}
+
+// The purpose of the following CopyXXX routines is to isolate the transfer
+// of data into the user buffer so that any changes in format
+// are easily dealt with. this is in anticipation of Darryl's alignment
+// DCR being passed.
+
+// alignment note: we use the RtlStore/RetrieveUlong/short macros to
+// read from and store to the naturally unaligned (packed) find and ea
+// buffers. we do not check other pointers for alignment before accessing
+// them.
+
+APIRET
+CopycbList(
+ IN ULONG cbList,
+ IN OUT PVOID *UserBuffer,
+ IN OUT PULONG UserBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies the EA list length field to the user's buffer.
+ The buffer pointer is updated to point past the cblist field. It is
+ assumed that there is enough space for the cblist.
+
+Arguments:
+
+ cbList - the EA list length.
+
+ UserBuffer - where to store the cblist.
+
+ UserBufferLength - Available space in the userbuffer.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ try {
+ RtlStoreUlong(*UserBuffer,cbList);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ *UserBuffer = (PBYTE)(*UserBuffer) + sizeof(ULONG);
+ *UserBufferLength = *UserBufferLength - sizeof(ULONG);
+ return NO_ERROR;
+}
+
+APIRET
+CopyFileName(
+ IN PSZ FileName,
+ IN ULONG FileNameLength,
+ IN OUT PVOID *UserBuffer,
+ IN OUT PULONG UserBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies the filenamelength and filename field to the user's
+ buffer. The buffer pointer is updated to point past the filename and
+ filenamelength fields.
+
+Arguments:
+
+ FileName - The filename to copy.
+
+ FileNameLength - Length of the filename (not including NULL).
+
+ UserBuffer - Where to store the filename.
+
+ UserBufferLength - Available space in the userbuffer.
+
+Return Value:
+
+ ERROR_BUFFER_OVERFLOW - there wasn't adequate space to store the filename
+ and filenamelength in the user buffer.
+
+--*/
+
+{
+
+ if (*UserBufferLength < (FileNameLength + (2 * sizeof(UCHAR)))) {
+ return ERROR_BUFFER_OVERFLOW;
+ }
+ *UserBufferLength = *UserBufferLength -
+ (FileNameLength + (2 * sizeof(UCHAR)));
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("copying filename, %s\n",FileName);
+ }
+#endif
+ try {
+ //
+ // store the filenamelength in the first byte of the buffer
+ //
+ *((PCHAR) (*UserBuffer)) = (UCHAR) FileNameLength;
+ //
+ // update the buffer pointer past the filenamelength
+ //
+ *UserBuffer = (PBYTE)(*UserBuffer) + sizeof(UCHAR);
+ //
+ // copy the filename
+ //
+ RtlMoveMemory(*UserBuffer,FileName,FileNameLength);
+ //
+ // update the buffer pointer past the filename
+ //
+ *UserBuffer = (PBYTE)(*UserBuffer) + FileNameLength;
+ //
+ // null terminate the filename
+ //
+ *((PCHAR) (*UserBuffer)) = 0;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ //
+ // update the buffer pointer past the filenamelength
+ //
+ *UserBuffer = (PBYTE)(*UserBuffer) + sizeof(UCHAR);
+ return NO_ERROR;
+}
+
+APIRET
+CopyFileAttributes(
+ IN PFILE_FULL_DIR_INFORMATION NtEntry,
+ IN OUT PVOID *UserBuffer,
+ IN OUT PULONG UserBufferLength,
+ IN ULONG InfoLevel
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies the attributes fields to the user's
+ buffer. The buffer pointer is updated to point past the attributes.
+
+Arguments:
+
+ NtEntry - The attributes in NT form.
+
+ UserBuffer - Where to store the filename.
+
+ UserBufferLength - Available space in the userbuffer.
+
+ InfoLevel - The level of file information requested.
+
+Return Value:
+
+ ERROR_BUFFER_OVERFLOW - there wasn't adequate space to store the filename
+ and filenamelength in the user buffer.
+
+Note:
+
+ Since this structure is dword-aligned, we could figure out at the
+ beginning whether the structure begins on a dword boundary and skip the
+ macros if it does.
+
+--*/
+
+{
+ PFILEFINDBUF4 BufPtr;
+ USHORT Attributes;
+
+ if (InfoLevel == FIL_STANDARD)
+ {
+ if (*UserBufferLength < ATTR_SIZE3) {
+ return ERROR_BUFFER_OVERFLOW;
+ }
+ *UserBufferLength -= ATTR_SIZE3;
+ }
+ else
+ {
+ if (*UserBufferLength < ATTR_SIZE4) {
+ return ERROR_BUFFER_OVERFLOW;
+ }
+ *UserBufferLength -= ATTR_SIZE4;
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("copying attributes\n");
+ }
+#endif
+ BufPtr = (PFILEFINDBUF4) *UserBuffer;
+
+ try {
+
+ // fill in oNextEntryOffset later.
+ // convert creation time
+
+ NtTimeToFatTimeAndDate(&(BufPtr->ftimeCreation),
+ &(BufPtr->fdateCreation),
+ NtEntry->CreationTime);
+
+ // convert last access time
+
+ NtTimeToFatTimeAndDate(&(BufPtr->ftimeLastAccess),
+ &(BufPtr->fdateLastAccess),
+ NtEntry->LastAccessTime);
+
+ // convert last write time
+
+ NtTimeToFatTimeAndDate(&(BufPtr->ftimeLastWrite),
+ &(BufPtr->fdateLastWrite),
+ NtEntry->LastWriteTime);
+
+ // BUGBUG - Therese, what should we do here if .HighPart is non-zero
+
+ BufPtr->cbFile = NtEntry->EndOfFile.LowPart;
+ BufPtr->cbFileAlloc = NtEntry->AllocationSize.LowPart;
+
+ if (InfoLevel == FIL_STANDARD)
+ {
+ MapAttributesToOs2(
+ ((PFILE_DIRECTORY_INFORMATION)NtEntry)->FileAttributes,
+ &Attributes);
+ }
+ else
+ {
+ MapAttributesToOs2(
+ NtEntry->FileAttributes,
+ &Attributes);
+ }
+
+ BufPtr->attrFile = (ULONG)(Attributes & ATTR_ALL);
+ if (InfoLevel == FIL_STANDARD)
+ {
+ *UserBuffer = (PBYTE)(*UserBuffer) + ATTR_SIZE3; // BUGBUG check this
+ }
+ else if (InfoLevel == FIL_QUERYEASIZE)
+ {
+ BufPtr->cbList = NtEntry->EaSize;
+ /* Note that NT returns 0 when no EA's on file. OS/2 expects the
+ size of the .cbList field */
+ if (BufPtr->cbList == 0)
+ BufPtr->cbList = MINFEALISTSIZE;
+ *UserBuffer = (PBYTE)(*UserBuffer) + ATTR_SIZE4; // BUGBUG check this
+ }
+ else /* InfoLevel == FIL_QUERYEASFROMLIST */
+ {
+ /* BUGBUG - I don't believe that anyone is looking at that field */
+ BufPtr->cbList = NtEntry->EaSize;
+ *UserBuffer = (PBYTE)(*UserBuffer) + ATTR_SIZE4
+ - sizeof(BufPtr->cbList);
+ }
+
+ } except( EXCEPTION_EXECUTE_HANDLER ){
+ Od2ExitGP();
+ }
+ //
+ // update buffer pointer past attributes
+ //
+ return NO_ERROR;
+}
+
+APIRET
+EditBuffer(
+ IN ULONG InfoLevel,
+ IN ULONG RequestedAttributes,
+ IN HANDLE NtDirectoryHandle,
+ IN OUT PULONG NumberOfEntries,
+ IN PVOID Buffer,
+ IN ULONG BufferLength,
+ IN OUT PFILEFINDBUF4 *LastEntry,
+ IN OUT PVOID *UserBuffer,
+ IN OUT PULONG UserBufferLength,
+ IN OUT PEAOP2 UserEaop,
+ OUT PBOOLEAN Rewind,
+ OUT PFILE_DIRECTORY_INFORMATION *RewindEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies the information returned by NtQueryDirectory to
+ the user's buffer and retrieves any additional information based on
+ the infolevel. It also removes any entries returned by NtQueryDirectory
+ if the attributes don't match the RequestedAttributes parameter.
+
+Arguments:
+
+ InfoLevel - The level of file information requested.
+
+ RequestedAttributes - The attribute used in searching for FileName.
+
+ NtDirectoryHandle - handle to open directory
+
+ NumberOfEntries - on input, number of entries needed. on output,
+ number of entries found. this parameter has meaning regardless of
+ whether an error code was returned.
+
+ Buffer - entries returned by NtQueryDirectoryFile
+
+ BufferLength - length of data returned by NtQueryDirectoryFile
+
+ LastEntry - on input, the last entry stored in the user buffer by the
+ last call to EditBuffer. on exit, the last entry stored in the user
+ buffer. used to update oNextEntryOffset.
+
+ UserBuffer - where to store matching entries. this pointer is updated
+ to point past the returned entries on return. (unprobed)
+
+ UserBufferLength - remaining buffer length
+
+ UserEaop - user's EAOP, if infolevel == QUERYEAS (unprobed)
+ BUGBUG need to TRY this
+
+ Rewind - Whether search needs to be rewound.
+
+ RewindEntry - entry from which to continue scan
+
+Return Value:
+
+ ERROR_BUFFER_OVERFLOW - there wasn't adequate space to store all the
+ requested entries in the user buffer.
+
+ ERROR_EAS_DIDNT_FIT - there wasn't adequate space to store the EAs for
+ one of the requested entries.
+
+--*/
+
+{
+ ULONG NumberOfEntriesRequested;
+ PFILE_FULL_DIR_INFORMATION CurrentEntry;
+ STRING FileName;
+ UNICODE_STRING FileName_U;
+ BOOLEAN Directory;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ HANDLE FoundEntryHandle;
+ BOOLEAN Done; // whether we've hit the end of the NT buffer
+ APIRET RetCode;
+ NTSTATUS Status;
+ PFILEFINDBUF4 CurrentUserEntry, PreviousUserEntry;
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("entering EditBuffer with requestednumentries == %ld\n",*NumberOfEntries);
+ }
+#endif
+ NumberOfEntriesRequested = *NumberOfEntries;
+ *NumberOfEntries = 0; // number of entries copied
+ CurrentEntry = (PFILE_FULL_DIR_INFORMATION) Buffer;
+ if (BufferLength == 0)
+ {
+ return ERROR_BUFFER_OVERFLOW;
+ }
+ //
+ // we can break out of the while loop for three reasons:
+ // 1) we run out of user buffer space. if there are still entries left
+ // in the NT buffer, we need to save the rewind information. we
+ // return error_buffer_overflow if the last entry wouldn't fit. if
+ // infolevel == 3 and all but the EA data will fit for the last entry,
+ // we return error_eas_didnt_fit. we increment the returnedentry
+ // counter. we also return the rewind
+ // information because the only time we return an entry without its
+ // EAs is if it's the only entry returned. if there are other entries
+ // in the buffer, we need to rewind so that entry will be returned
+ // again. we leave it up to the caller to
+ // determine the correct error code, depending on whether any entries
+ // were returned.
+ // 2) we have copied the requested number of entries. if there are still
+ // entries left in the NT buffer, we need to save the rewind
+ // information.
+ // 3) we have exhausted the NT entries. this can happen if the entries
+ // returned by NT don't match the requested attributes. we return
+ // the number copied and no error.
+ //
+ Done = FALSE;
+ *RewindEntry = (PFILE_DIRECTORY_INFORMATION) CurrentEntry;
+ *Rewind = FALSE;
+ CurrentUserEntry = NULL;
+ while ((*UserBufferLength) &&
+ (*NumberOfEntries < NumberOfEntriesRequested) &&
+ (!Done))
+ {
+ if (InfoLevel == FIL_STANDARD)
+ {
+ //
+ // What we get back from Nt is Unicode
+ //
+
+ ((PFILE_DIRECTORY_INFORMATION)CurrentEntry)->FileName
+ [(((PFILE_DIRECTORY_INFORMATION)CurrentEntry)->FileNameLength)/2] = 0;
+ RtlInitUnicodeString (&FileName_U,
+ ((PFILE_DIRECTORY_INFORMATION)CurrentEntry)->FileName);
+ //
+ // Convert it to Ansi
+ //
+ RetCode = Od2UnicodeStringToMBString(
+ &FileName,
+ &FileName_U,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("cannot convert to Unicode\n");
+ }
+ ASSERT( FALSE );
+#endif
+ return(RetCode);
+ }
+ Directory = (BOOLEAN)((((PFILE_DIRECTORY_INFORMATION)CurrentEntry)->FileAttributes
+ & FILE_ATTRIBUTE_DIRECTORY) != 0);
+ }
+ else
+ {
+ //
+ // What we get back from Nt is Unicode
+ //
+ CurrentEntry->FileName[(CurrentEntry->FileNameLength)/2] = 0;
+ RtlInitUnicodeString (&FileName_U,
+ CurrentEntry->FileName);
+ //
+ // Convert it to Ansi
+ //
+ RetCode = Od2UnicodeStringToMBString(
+ &FileName,
+ &FileName_U,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("cannot convert to Unicode\n");
+ }
+ ASSERT( FALSE );
+#endif
+ return(RetCode);
+ }
+ Directory = (BOOLEAN)((CurrentEntry->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
+ }
+
+ if (MatchAttributes(CurrentEntry->FileAttributes,
+ RequestedAttributes,
+ Directory))
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("attributes match\n");
+ }
+#endif
+ PreviousUserEntry = CurrentUserEntry;
+ CurrentUserEntry = *UserBuffer;
+ if (RetCode = CopyFileAttributes(CurrentEntry,
+ UserBuffer,
+ UserBufferLength,
+ InfoLevel))
+ {
+ if (RetCode == ERROR_BUFFER_OVERFLOW)
+ {
+ *Rewind = TRUE;
+ if (PreviousUserEntry)
+ {
+ PreviousUserEntry->oNextEntryOffset = 0;
+ }
+ }
+ return RetCode;
+ }
+
+ if (InfoLevel != FIL_QUERYEASFROMLIST)
+ {
+ if (RetCode = CopyFileName(FileName.Buffer,
+ FileName.Length,
+ UserBuffer,
+ UserBufferLength)) {
+ if (RetCode == ERROR_BUFFER_OVERFLOW) {
+ *Rewind = TRUE;
+ if (PreviousUserEntry) {
+ PreviousUserEntry->oNextEntryOffset = 0;
+ }
+ }
+ return RetCode;
+ }
+ }
+ else
+ {
+
+ //
+ // if EA information is requested and the returned entry
+ // is '.' or '..', return an empty ea list.
+ //
+
+ if ((!strcmp(FileName.Buffer,".")) ||
+ (!strcmp(FileName.Buffer,"..")))
+ {
+ UserEaop->fpFEA2List = *UserBuffer;
+ UserEaop->fpFEA2List->cbList = MINFEALISTSIZE;
+ *UserBufferLength -= UserEaop->fpFEA2List->cbList;
+ *UserBuffer = (PBYTE)(*UserBuffer) + UserEaop->fpFEA2List->cbList;
+ }
+ else
+ {
+
+ //
+ // we must be able to fit the name and the cblist in the buffer.
+ // otherwise it's error_buffer_overflow.
+ //
+ if (*UserBufferLength < (ULONG)(MINFEALISTSIZE + FileName.Length))
+ {
+ *Rewind = TRUE;
+ if (PreviousUserEntry)
+ {
+ PreviousUserEntry->oNextEntryOffset = 0;
+ }
+ return ERROR_BUFFER_OVERFLOW;
+ }
+
+ InitializeObjectAttributes( &Obja,
+ &FileName_U,
+ OBJ_CASE_INSENSITIVE,
+ NtDirectoryHandle,
+ NULL);
+ // BUGBUG test for sharing_violation when it's implemented
+ do {
+ Status = NtOpenFile(&FoundEntryHandle,
+ SYNCHRONIZE | FILE_READ_EA,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ } while (RetryIO(Status, &FoundEntryHandle));
+ if (!(NT_SUCCESS(Status)))
+ {
+ //BUGBUG fix this part
+ //
+ // if we don't have access to the file, we return an error
+ // and the filename. the search can continue past this
+ // entry. if there are other entries in the buffer, we
+ // return no error and don't return this entry. that way
+ // the entry is the only thing in the buffer when the
+ // error is returned.
+ //
+ if (Status == STATUS_ACCESS_DENIED) {
+ if (CurrentEntry->NextEntryOffset != 0) {
+ *Rewind = TRUE;
+ *RewindEntry = (PFILE_DIRECTORY_INFORMATION) ((PCHAR) CurrentEntry + CurrentEntry->NextEntryOffset);
+ }
+ *NumberOfEntries += 1;
+ return ERROR_ACCESS_DENIED;
+ }
+ return ERROR_FILE_NOT_FOUND; //BUGBUG bogus error
+ }
+ /* BUGBUG - Looks like a strange practise below to destroy
+ the user's fpFEA2List. In the case of the OS/2 ss, we call
+ DosFindFirst only with a temporary local buffer so leave
+ it for now */
+ UserEaop->fpFEA2List = *UserBuffer;
+ UserEaop->fpFEA2List->cbList = *UserBufferLength;
+ RetCode = GetGEAList(FoundEntryHandle,
+ (PBYTE)UserEaop,
+ sizeof(EAOP2)
+ );
+ if (RetCode != NO_ERROR)
+ {
+ if (RetCode==ERROR_BUFFER_OVERFLOW) {
+
+ //
+ // we have already verified that there is enough
+ // room in the buffer for the cblist.
+ //
+
+ CurrentUserEntry->cbList = CurrentEntry->EaSize;
+ CurrentUserEntry->oNextEntryOffset = 0;
+ *UserBuffer = (PCHAR)(*UserBuffer) + sizeof(CurrentUserEntry->cbList);
+ *NumberOfEntries += 1;
+ NtClose(FoundEntryHandle);
+ return ERROR_EAS_DIDNT_FIT;
+ }
+ else {
+ NtClose(FoundEntryHandle);
+ return RetCode;
+ }
+ }
+ else
+ {
+ NtClose(FoundEntryHandle);
+
+ *UserBufferLength -= UserEaop->fpFEA2List->cbList;
+ *UserBuffer = (PBYTE)(*UserBuffer) + UserEaop->fpFEA2List->cbList;
+ }
+
+ }
+ if (RetCode = CopyFileName(
+ FileName.Buffer,
+ FileName.Length,
+ UserBuffer,
+ UserBufferLength)) {
+ if (PreviousUserEntry) {
+ PreviousUserEntry->oNextEntryOffset = 0;
+ }
+ return RetCode;
+ }
+ }
+ *NumberOfEntries += 1;
+
+ //
+ // the first time through the loop, if editbuffer was already
+ // called for the call to the API, we set up the oNextEntryOffset
+ // of the last entry returned.
+ //
+
+ if (*LastEntry != NULL) {
+ ASSERT ((*LastEntry)->oNextEntryOffset == 0);
+ (*LastEntry)->oNextEntryOffset = RoundUpToUlong(((ULONG)CurrentUserEntry - (ULONG)*LastEntry));
+ *LastEntry = NULL;
+ }
+ CurrentUserEntry->oNextEntryOffset = RoundUpToUlong(((ULONG)*UserBuffer - (ULONG)CurrentUserEntry));
+ *UserBuffer = (PVOID) ((PCHAR)(CurrentUserEntry) + CurrentUserEntry->oNextEntryOffset);
+ }
+ if (CurrentEntry->NextEntryOffset == 0) {
+ Done = TRUE;
+ }
+ CurrentEntry = (PFILE_FULL_DIR_INFORMATION) ((PCHAR) CurrentEntry + CurrentEntry->NextEntryOffset);
+ *RewindEntry = (PFILE_DIRECTORY_INFORMATION) CurrentEntry;
+ Od2FreeMBString (&FileName);
+ }
+
+ //
+ // if we get here and the number of entries copied is zero, some were
+ // found but the attributes didn't match. we don't touch the user's
+ // buffer.
+ //
+
+ if (*NumberOfEntries > 0) {
+ CurrentUserEntry->oNextEntryOffset = 0;
+ *LastEntry = CurrentUserEntry;
+ }
+
+ //
+ // if we get here with NT entries left in the buffer, we've copied the
+ // requested number. we need to save the rewind information.
+ //
+ if (!Done) {
+ *Rewind = TRUE;
+ }
+ return NO_ERROR;
+}
+
+
+APIRET
+DosFindFirst(
+ IN PSZ FileName,
+ IN OUT PHDIR DirectoryHandle,
+ IN ULONG FileAttributes,
+ IN PFILEFINDBUF3 Buffer,
+ IN ULONG Length,
+ IN OUT PULONG CountEntriesFound,
+ IN ULONG FileInformationLevel
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the OS/2 API DosFindFirst.
+
+Arguments:
+
+ FileName - The name to be search for. may contain wildcard characters.
+
+ DirectoryHandle - The search handle associated with this particular
+ search. An input DirectoryHandle of 1 is specified to be always
+ available. An input DirectoryHandle of -1 indicates to allocate a
+ new handle. The handle is returned by overwriting the -1. Reuse of
+ this DirectoryHandle in another DosFindFirst closes the association
+ with the previously related DosFindFirst and opens a new association
+ with the current DosFindFirst.
+
+ FileAttributes - The attribute used in searching for FileName.
+
+ Buffer - Where to store the results of the search.
+
+ Length - Length of Buffer
+
+ CountEntriesFound - on input, this contains the number of entries
+ requested. on output, it contains the number of entries found.
+
+ FileInformationLevel - The level of file information requested.
+
+
+Return Value:
+
+ see OS/2 spec.
+
+--*/
+
+{
+ STRING CanonicalNameString;
+ UNICODE_STRING CanonicalNameString_U;
+ ULONG FileType;
+ ULONG FileFlags;
+ PCHAR LastElement;
+ PCHAR CurrentChar;
+ HANDLE NtDirectoryHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ ULONG BufferLength;
+ PVOID FindBuffer;
+ ULONG OneOs2EntrySize, OneNtEntrySize;
+ FILE_INFORMATION_CLASS InformationClass;
+ BOOLEAN RestartScan;
+ BOOLEAN Rewind;
+ PUNICODE_STRING pSearchString;
+ STRING SearchString;
+ UNICODE_STRING SearchString_U;
+ PFILE_DIRECTORY_INFORMATION RewindEntry;
+ ULONG EntriesNeeded;
+ ULONG EntriesRequested;
+ ULONG EntriesFound;
+ PEAOP2 UserEAOP=NULL;
+ PFILEFINDBUF3 UserBuffer;
+ APIRET RetCode;
+ NTSTATUS Status;
+ BOOLEAN OneEntry;
+ PFILEFINDBUF4 LastEntry;
+
+ if ((FileInformationLevel < FIL_STANDARD) ||
+ (FileInformationLevel > MAXFINDINFOLEVEL))
+ {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ try
+ {
+ if ((EntriesRequested = *CountEntriesFound) == 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+ Od2ProbeForWrite(CountEntriesFound, sizeof(ULONG), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ){
+ Od2ExitGP();
+ }
+ if (FileAttributes & ~(ATTR_ALL | ATTR_NOT_NORM))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ RetCode = Od2Canonicalize(FileName,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &CanonicalNameString,
+ NULL,
+ &FileFlags,
+ &FileType
+ );
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ if (FileType & FILE_TYPE_PSDEV)
+ {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return ERROR_ACCESS_DENIED;
+ }
+
+ if (FileFlags & CANONICALIZE_IS_ROOT_DIRECTORY)
+ {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return ERROR_NO_MORE_FILES;
+ }
+
+
+ // get pointer to last element in string. we do this by scanning from the
+ // beginning for \s. we must scan from the beginning to be dbcs correct.
+
+//BUGBUG need to special case devices. what about named pipes? currently
+// only UNC is distinguished
+
+ if (FileType & FILE_TYPE_UNC)
+ {
+ // add 10 for skipping '\OS2SS\UNC'
+ LastElement = CanonicalNameString.Buffer+10;
+ }
+ else
+ {
+ // skipping '\OS2SS\DRIVES\X:'
+ LastElement = CanonicalNameString.Buffer+FILE_PREFIX_LENGTH+FIRST_SLASH;
+ }
+ ASSERT (*LastElement == '\\');
+ CurrentChar = LastElement + 1;
+ while (*CurrentChar != 0)
+ {
+ while ((*CurrentChar != 0) && (*CurrentChar != '\\'))
+ {
+#ifdef DBCS
+// MSKK Apr.12.1993 V-AkihiS
+// MSKK Sep.29.1993 V-AkihiS
+// if (IsDBCSLeadByte(*CurrentChar))
+ if (Ow2NlsIsDBCSLeadByte(*CurrentChar, SesGrp->DosCP))
+ {
+ CurrentChar++;
+ }
+ if (*CurrentChar)
+ {
+ CurrentChar++;
+ }
+#else
+ CurrentChar++;
+#endif
+ }
+ if (*CurrentChar == '\\')
+ {
+ LastElement = CurrentChar++;
+ }
+ }
+
+ //
+ // open the parent directory. if it's the root directory, we need to
+ // open "\OS2SS\DRIVES\d:\", otherwise we open "\OS2SS\DRIVES\d:\foo".
+ // note that the root directory ends in a '\' and the other cases don't.
+ //
+
+ if (LastElement == CanonicalNameString.Buffer+FILE_PREFIX_LENGTH+FIRST_SLASH) { // if root directory
+ if (!(FileType & FILE_TYPE_UNC)) {
+ CanonicalNameString.Length = FILE_PREFIX_LENGTH+ROOTDIRLENGTH; // we know the string length
+ CanonicalNameString.MaximumLength = CanonicalNameString.Length;
+ // and don't want to overwrite
+ }
+ } // the char.
+ else { // else
+ *LastElement = 0; // overwrite '\'
+ Od2InitMBString(&CanonicalNameString,CanonicalNameString.Buffer);
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("parent directory is %s\n",CanonicalNameString.Buffer);
+ }
+#endif
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &CanonicalNameString_U,
+ &CanonicalNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("DosFindFirst: no memory for Unicode Conversion\n");
+ }
+#endif
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ do {
+ Status = NtOpenFile(&NtDirectoryHandle,
+ SYNCHRONIZE | FILE_LIST_DIRECTORY,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE
+ );
+ } while (RetryIO(Status, NtDirectoryHandle));
+ RtlFreeUnicodeString (&CanonicalNameString_U);
+ if (!(NT_SUCCESS(Status))) {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return ERROR_PATH_NOT_FOUND;
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("opening parent directory succeeded\n");
+ }
+#endif
+
+ // if level three is used, the user passed in an EAOP and we need to retrieve
+ // the real buffer pointer and length from it.
+
+ if (FileInformationLevel == FIL_QUERYEASFROMLIST)
+ {
+ if (Length < (sizeof (EAOP2)))
+ {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ NtClose(NtDirectoryHandle);
+ *CountEntriesFound = 0;
+
+ return ERROR_BUFFER_OVERFLOW;
+ }
+ Length = Length - sizeof(EAOP2);
+ UserEAOP = (PEAOP2)Buffer;
+ UserBuffer = (PFILEFINDBUF3) ((ULONG)Buffer + sizeof(EAOP2));
+ }
+ else
+ {
+ UserBuffer = Buffer;
+ }
+
+ if (FileInformationLevel == FIL_STANDARD)
+ {
+ OneOs2EntrySize = FIND_LEVEL_ONE_INFO_SIZE;
+ OneNtEntrySize = sizeof(FILE_DIRECTORY_INFORMATION);
+ InformationClass = FileDirectoryInformation;
+ }
+ else
+ {
+ OneOs2EntrySize = FIND_LEVEL_TWO_INFO_SIZE;
+ OneNtEntrySize = sizeof(FILE_FULL_DIR_INFORMATION);
+ InformationClass = FileFullDirectoryInformation;
+ }
+
+ /* BUGBUG - This check could be performed earlier (i.e. before opening the
+ directory). However, since under OS/2 when calling DosFindFirsts with both an
+ invalid path AND a too small buffer an error about the directory
+ is returned, we need to try and open the directory and only after
+ that check the length of the user-supplied buffer.
+ */
+ if (Length < OneOs2EntrySize)
+ {
+ *CountEntriesFound = 0;
+ NtClose(NtDirectoryHandle);
+ // os2 1.x returns ERROR_NO_MORE_FILES and not ERROR_BUFFER_OVERFLOW
+ return ERROR_NO_MORE_FILES;
+ }
+
+ // allocate a buffer. the size of this buffer is
+ // big enough to contain the same number of entries (in NT format) that would
+ // fit into the user's buffer (in OS/2 format).
+
+ ASSERT(OneOs2EntrySize < OneNtEntrySize);
+ ASSERT((OneNtEntrySize & (sizeof(ULONG)-1))==0);
+ if (EntriesRequested == 1)
+ {
+ /* When calculating 'BufferLength', compute how many chars were
+ planned in the user-supplied buffer, then multiply by the size of
+ one char in the NT structure. The expression looks like:
+ size of NT structure w/o the name array
+ + (number of chars allowed in Cruiser structure) *
+ (size of one char in NT structure)
+ The whole size should now be aligned to 4 bytes boundary
+ */
+ if (FileInformationLevel == FIL_STANDARD) {
+ BufferLength = FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName)
+ + (Length - FIELD_OFFSET(FILEFINDBUF3, achName))
+ / sizeof(((FILEFINDBUF3 *)0)->achName[0])
+ * sizeof(((FILE_DIRECTORY_INFORMATION *)0)->FileName[0]);
+ }
+ else {
+ BufferLength = FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName)
+ + (Length - FIELD_OFFSET(FILEFINDBUF4, achName))
+ / sizeof(((FILEFINDBUF4 *)0)->achName[0])
+ * sizeof(((FILE_FULL_DIR_INFORMATION *)0)->FileName[0]);
+ }
+ // Align BufferLength to 4 bytes boundary
+ BufferLength = (BufferLength + 3) & 0xfffffffc;
+ }
+ else
+ BufferLength = OneNtEntrySize * (Length / OneOs2EntrySize);
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("user buffer size is %ld\n",Length);
+ DbgPrint("allocating a buffer of size %ld\n",BufferLength);
+ }
+#endif
+ FindBuffer = RtlAllocateHeap(Od2Heap,0,BufferLength);
+ if (FindBuffer == NULL)
+ {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ NtClose(NtDirectoryHandle);
+ return ERROR_NOT_ENOUGH_MEMORY; // BUGBUG bogus error
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("buffer allocation succeeded\n");
+ }
+#endif
+ Od2InitMBString(&SearchString,LastElement+1);
+
+ RetCode = Od2MBStringToUnicodeString(
+ &SearchString_U,
+ &SearchString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("DosFindFirst: no memory for Unicode Conversion-2\n");
+ }
+#endif
+ return RetCode;
+ }
+
+ pSearchString = &SearchString_U;
+
+ //
+ // Special case *.* to * since it is so common. Otherwise transmogrify
+ // the input name according to the following rules:
+ //
+ // - Change all ? to DOS_QM
+ // - Change all . followed by ? or * to DOS_DOT
+ // - Change an ending *. into DOS_STAR
+ //
+ // These transmogrifications are all done in place.
+ //
+ // This piece of code was heavily inspired by Windows base\client\filefind.c
+ //
+
+ if ( (SearchString_U.Length == 6) &&
+ (RtlCompareMemory(SearchString_U.Buffer, L"*.*", 6) == 6) ) {
+
+ SearchString_U.Length = sizeof(WCHAR); // leave only the first '*'
+
+ } else {
+
+ ULONG Index;
+ WCHAR *NameChar;
+
+ for ( Index = 0, NameChar = SearchString_U.Buffer;
+ Index < SearchString_U.Length/sizeof(WCHAR);
+ Index++, NameChar++) {
+
+ if ((*NameChar == L'?') || (*NameChar == L'*')) {
+
+ if (*NameChar == L'?') {
+ *NameChar = DOS_QM;
+ }
+
+ if (Index && *(NameChar - 1) == L'.') {
+ *(NameChar - 1) = DOS_DOT;
+ }
+ }
+ }
+
+ if ((*(NameChar - 2) == L'*') && (*(NameChar - 1) == L'.')) {
+ *(NameChar - 2) = DOS_STAR;
+ SearchString_U.Length -= sizeof(WCHAR);
+ }
+ }
+
+ RestartScan = TRUE;
+ EntriesFound = 0;
+ LastEntry = NULL;
+ while (EntriesFound < EntriesRequested)
+ {
+ if ((EntriesRequested - EntriesFound) == 1) // if one entry needed
+ OneEntry = TRUE;
+ else
+ OneEntry = FALSE;
+ do {
+ Status = NtQueryDirectoryFile(NtDirectoryHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ FindBuffer,
+ BufferLength,
+ InformationClass,
+ OneEntry,
+ pSearchString,
+ RestartScan);
+ } while (RetryIO(Status, NtDirectoryHandle));
+ //
+ // if the call to NtQueryDirectoryFile fails, we end the search.
+ // if it failed because there were no more matching files and we
+ // found at least one match, we return the match and no error and
+ // save the search information. otherwise we don't save the search
+ // information.
+ //
+ if (Status != STATUS_SUCCESS)
+ {
+#if DBG
+ IF_OD2_DEBUG( TEMP )
+ {
+ DbgPrint("NtQueryDirectoryFile failed, Status=%x\n",
+ Status);
+ }
+#endif
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ try
+ {
+ *CountEntriesFound = EntriesFound;
+ } except( EXCEPTION_EXECUTE_HANDLER ){
+ NtClose(NtDirectoryHandle);
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ RtlFreeUnicodeString(&SearchString_U);
+ Od2ExitGP();
+ }
+ if (((Status == STATUS_BUFFER_OVERFLOW) ||
+ (Status == STATUS_NO_MORE_FILES)) &&
+ (EntriesFound > 0))
+ {
+ Rewind = FALSE;
+ RetCode = SaveSearchInfo(Rewind,
+ RewindEntry,
+ FindBuffer,
+ BufferLength,
+ NtDirectoryHandle,
+ FileAttributes,
+ DirectoryHandle,
+ FileInformationLevel);
+ if (RetCode != NO_ERROR)
+ {
+ NtClose(NtDirectoryHandle);
+ }
+#if DBG
+ IF_OD2_DEBUG( TEMP )
+ {
+ DbgPrint("SaveSearchInfo returned RetCode=%d\n",
+ RetCode);
+ }
+#endif
+ RtlFreeUnicodeString(&SearchString_U);
+ return RetCode;
+ }
+ else {
+ NtClose(NtDirectoryHandle);
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ RtlFreeUnicodeString(&SearchString_U);
+ if (Status == ERROR_NO_MORE_FILES) {
+ return ERROR_NO_MORE_FILES;
+ }
+ else {
+ return ERROR_FILE_NOT_FOUND; // BUGBUG bogus error
+ }
+ }
+ }
+ RestartScan = FALSE;
+ EntriesNeeded = EntriesRequested - EntriesFound;
+
+
+ RetCode = EditBuffer(FileInformationLevel,
+ FileAttributes,
+ NtDirectoryHandle,
+ &EntriesNeeded,
+ FindBuffer,
+ IoStatus.Information,
+ &LastEntry,
+ (PVOID *) &UserBuffer,
+ &Length,
+ UserEAOP,
+ &Rewind,
+ &RewindEntry
+ );
+ EntriesFound += EntriesNeeded;
+
+ // we use the return code from EditBuffer and the number of
+ // entries returned to determine what to return to the user.
+ // the basic rules are:
+ // if infolevel 1 and not enough room for any entries
+ // ERROR_BUFFER_OVERFLOW
+ // if infolevel 2 or 3 and not enough room for entry + cblist of first entry
+ // ERROR_BUFFER_OVERFLOW
+ // if infolevel 3
+ // if not enough room for EAs for first entry
+ // copy entry + cblist
+ // return ERROR_EAS_DIDNT_FIT
+ //
+ // this translates into the following pseudocode:
+ //
+ // if (RetCode)
+ // if (entries found == 0)
+ // don't create search handle
+ // return retcode
+ // if (retcode == ERROR_EAS_DIDNT_FIT)
+ // if (entries found == 1)
+ // create search handle
+ // return retcode
+ // else
+ // create search handle
+ // decrement found count
+ // else if (retcode == ERROR_ACCESS_DENIED)
+ // if (entries found == 1)
+ // create search handle
+ // copy filename to front of buffer
+ // point rewind entry to next entry
+ // return retcode
+ // else
+ // create search handle
+ // decrement found count
+ // else if (retcode == ERROR_BUFFER_OVERFLOW | ERROR_NO_MORE_FILES)
+ // create search handle
+ // return no error
+ // else
+ // don't create search handle
+ // return retcode
+
+ // if we get a return code, we stop getting more entries.
+ // first, we free up the memory we've allocated.
+ // then, if no entries have been found, we bag the search
+ // entirely by closing the directory handle and returning the
+ // error. if some entries have been found and ERROR_EAS_DIDNT_FIT
+ // was returned, we need to find out whether the error applied to
+ // the first (and only) entry in the buffer. if it did, we return
+ // the error. otherwise we don't. in any case, we save the search
+ // information and return a valid handle and search count.
+
+ if (RetCode != NO_ERROR) {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ if (EntriesFound == 0) {
+ NtClose(NtDirectoryHandle);
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ RtlFreeUnicodeString(&SearchString_U);
+ return RetCode;
+ }
+ if (RetCode == ERROR_EAS_DIDNT_FIT) {
+ try {
+ *CountEntriesFound = EntriesFound;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ RtlFreeUnicodeString(&SearchString_U);
+ Od2ExitGP();
+ }
+ RetCode = SaveSearchInfo( Rewind,
+ RewindEntry,
+ FindBuffer,
+ BufferLength,
+ NtDirectoryHandle,
+ FileAttributes,
+ DirectoryHandle,
+ FileInformationLevel);
+ if (RetCode != NO_ERROR) {
+ RtlFreeUnicodeString(&SearchString_U);
+ return RetCode;
+ }
+ if (EntriesFound == 1) {
+ RtlFreeUnicodeString(&SearchString_U);
+ return ERROR_EAS_DIDNT_FIT;
+ }
+ else {
+ *CountEntriesFound--;
+ RtlFreeUnicodeString(&SearchString_U);
+ return NO_ERROR;
+ }
+ }
+ //
+ // if the return code is error_buffer_overflow or error_no_more_files,
+ // and one or more entries has successfully been stored in the user's
+ // buffer, we return success.
+ //
+ else if ((RetCode == ERROR_BUFFER_OVERFLOW) ||
+ (RetCode == ERROR_NO_MORE_FILES)) {
+ try {
+ *CountEntriesFound = EntriesFound;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ RtlFreeUnicodeString(&SearchString_U);
+ Od2ExitGP();
+ }
+ RetCode = SaveSearchInfo(Rewind,
+ RewindEntry,
+ FindBuffer,
+ BufferLength,
+ NtDirectoryHandle,
+ FileAttributes,
+ DirectoryHandle,
+ FileInformationLevel);
+ RtlFreeUnicodeString(&SearchString_U);
+ return RetCode;
+ }
+ //
+ // we get here if one or more entries has been successfully stored
+ // in the user's buffer, but we encountered an error other than
+ // buffer_overflow, no_more_files, or eas_didnt_fit. we fail the
+ // search and return the error code.
+ //
+ else {
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ RtlFreeUnicodeString(&SearchString_U);
+ NtClose(NtDirectoryHandle);
+ return RetCode;
+ }
+ }
+
+ //
+ // if we get here, EditBuffer returned NO_ERROR.
+ //
+
+ pSearchString = NULL;
+ }
+ //
+ // if we get here, we've found all the requested entries. save the
+ // search information and return.
+ //
+ RetCode = SaveSearchInfo(Rewind,
+ RewindEntry,
+ FindBuffer,
+ BufferLength,
+ NtDirectoryHandle,
+ FileAttributes,
+ DirectoryHandle,
+ FileInformationLevel);
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ RtlFreeUnicodeString(&SearchString_U);
+ return RetCode;
+}
+
+/*++
+
+Routine Description:
+
+ This routine is used by the OS/2 1.x subsystem to inquire what type of search
+ is performed with the specified directory handle so that we can make the
+ required transformations according to the search level.
+
+Return value:
+
+ The search's info level or -1 if handle is invalid.
+--*/
+
+ULONG
+Internal_return_search_level(
+ IN HDIR DirectoryHandle
+ )
+{
+ if ((((ULONG)DirectoryHandle) >= SearchHandleTableLength) ||
+ (((ULONG) SearchHandleTable[((ULONG)DirectoryHandle)]) == SEARCH_HANDLE_FREE)) {
+ return (ULONG)(-1);
+ }
+
+ return (SearchHandleTable[((ULONG)DirectoryHandle)]->InformationLevel);
+}
+
+APIRET
+DosFindNext(
+ IN HDIR DirectoryHandle,
+ IN PFILEFINDBUF3 Buffer,
+ IN ULONG Length,
+ IN OUT PULONG CountEntriesFound
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the OS/2 API DosFindNext.
+
+Arguments:
+
+ DirectoryHandle - The search handle associated with this particular
+ search.
+
+ Buffer - Where to store the results of the search.
+
+ Length - Length of Buffer
+
+ CountEntriesFound - on input, this contains the number of entries
+ requested. on output, it contains the number of entries found.
+
+Return Value:
+
+ see OS/2 spec.
+
+--*/
+
+{
+ PSEARCH_RECORD SearchRecord;
+ IO_STATUS_BLOCK IoStatus;
+ ULONG BufferLength;
+ PVOID FindBuffer;
+ ULONG OneOs2EntrySize, OneNtEntrySize;
+ FILE_INFORMATION_CLASS InformationClass;
+ BOOLEAN Rewind;
+ PFILE_DIRECTORY_INFORMATION RewindEntry;
+ ULONG EntriesNeeded;
+ ULONG EntriesFound;
+ ULONG EntriesRequested;
+ PEAOP2 UserEAOP=NULL;
+ PFILEFINDBUF3 UserBuffer;
+ APIRET RetCode;
+ NTSTATUS Status;
+ BOOLEAN OneEntry;
+ PFILEFINDBUF4 LastEntry;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosFindNext";
+ #endif
+
+ try {
+ if ((EntriesRequested = *CountEntriesFound) == 0) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if ((((ULONG)DirectoryHandle) >= SearchHandleTableLength) ||
+ (((ULONG) SearchHandleTable[((ULONG)DirectoryHandle)]) == SEARCH_HANDLE_FREE)) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE;
+ }
+ SearchRecord = SearchHandleTable[((ULONG)DirectoryHandle)];
+
+ EntriesFound = 0;
+
+ // if level three is used, the user passed in an EAOP and we need to retrieve
+ // the real buffer pointer and length from it.
+
+ if (SearchRecord->InformationLevel == FIL_QUERYEASFROMLIST)
+ {
+ if (Length < (sizeof (EAOP2)))
+ {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_BUFFER_OVERFLOW;
+ }
+ Length = Length - sizeof(EAOP2);
+ UserEAOP = (PEAOP2)Buffer;
+ UserBuffer = (PFILEFINDBUF3) ((ULONG)Buffer + sizeof(EAOP2));
+ }
+ else
+ {
+ UserBuffer = Buffer;
+ }
+
+ //
+ // if we have some entries left over from last time, use them first.
+ //
+
+ LastEntry = NULL;
+ if (SearchRecord->FindBuffer != NULL)
+ {
+ EntriesNeeded = EntriesRequested - EntriesFound;
+ FindBuffer = SearchRecord->FindBuffer;
+ BufferLength = SearchRecord->BufferLength;
+ RetCode = EditBuffer(SearchRecord->InformationLevel,
+ SearchRecord->Attributes,
+ SearchRecord->NtHandle,
+ &EntriesNeeded,
+ SearchRecord->RewindEntry,
+ (ULONG)SearchRecord->FindBuffer+BufferLength-(ULONG)SearchRecord->RewindEntry,
+ &LastEntry,
+ (PVOID *) &UserBuffer,
+ &Length,
+ UserEAOP,
+ &Rewind,
+ &RewindEntry
+ );
+ EntriesFound += EntriesNeeded;
+ if (RetCode != NO_ERROR)
+ goto EditBufferError;
+ RetCode = UpdateSearchInfo(Rewind,
+ RewindEntry,
+ FindBuffer,
+ BufferLength,
+ DirectoryHandle);
+ if (EntriesFound == EntriesRequested)
+ goto Done;
+ //
+ // if we get here, all the entries in the buffer were used.
+ //
+ }
+ if (SearchRecord->InformationLevel == FIL_STANDARD)
+ {
+ OneOs2EntrySize = FIND_LEVEL_ONE_INFO_SIZE;
+ OneNtEntrySize = sizeof(FILE_DIRECTORY_INFORMATION);
+ InformationClass = FileDirectoryInformation;
+ }
+ else
+ {
+ OneOs2EntrySize = FIND_LEVEL_TWO_INFO_SIZE;
+ OneNtEntrySize = sizeof(FILE_FULL_DIR_INFORMATION);
+ InformationClass = FileFullDirectoryInformation;
+ }
+
+ // allocate a buffer. the size of this buffer is
+ // big enough to contain the same number of entries (in NT format) that would
+ // fit into the user's buffer (in OS/2 format).
+
+ ASSERT(OneOs2EntrySize < OneNtEntrySize);
+ ASSERT((OneNtEntrySize & (sizeof(ULONG)-1))==0);
+ BufferLength = OneNtEntrySize * (Length / OneOs2EntrySize);
+ FindBuffer = RtlAllocateHeap(Od2Heap,0,BufferLength);
+ if (FindBuffer == NULL)
+ {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_NOT_ENOUGH_MEMORY; // BUGBUG bogus error
+ }
+ while (EntriesFound < EntriesRequested)
+ {
+ if ((EntriesRequested - EntriesFound) == 1) // if one entry needed
+ OneEntry = TRUE;
+ else
+ OneEntry = FALSE;
+ do {
+ Status = NtQueryDirectoryFile(SearchRecord->NtHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ FindBuffer,
+ BufferLength,
+ InformationClass,
+ OneEntry,
+ NULL,
+ FALSE); // multiple files for testing
+ } while (RetryIO(Status, SearchRecord->NtHandle));
+ //
+ // if the call to NtQueryDirectoryFile fails, we end the search.
+ // if it failed because there were no more matching files and we
+ // found at least one match, we return the match and no error and
+ // save the search information. otherwise we don't save the search
+ // information.
+ //
+ if (Status != STATUS_SUCCESS)
+ {
+ try
+ {
+ *CountEntriesFound = EntriesFound;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ Od2ExitGP();
+ }
+ if (((Status == STATUS_BUFFER_OVERFLOW) ||
+ (Status == STATUS_NO_MORE_FILES)) &&
+ (EntriesFound > 0)) {
+ Rewind = FALSE;
+ RetCode = UpdateSearchInfo(Rewind,
+ RewindEntry,
+ FindBuffer,
+ BufferLength,
+ DirectoryHandle);
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ else {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ if (Status == STATUS_NO_MORE_FILES) {
+ return ERROR_NO_MORE_FILES;
+ }
+ else {
+ return ERROR_FILE_NOT_FOUND; //BUGBUG bogus erro
+ }
+ }
+ }
+ EntriesNeeded = EntriesRequested - EntriesFound;
+ RetCode = EditBuffer(SearchRecord->InformationLevel,
+ SearchRecord->Attributes,
+ SearchRecord->NtHandle,
+ &EntriesNeeded,
+ FindBuffer,
+ IoStatus.Information,
+ &LastEntry,
+ (PVOID *) &UserBuffer,
+ &Length,
+ UserEAOP,
+ &Rewind,
+ &RewindEntry
+ );
+ EntriesFound += EntriesNeeded;
+
+ // we use the return code from EditBuffer and the number of
+ // entries returned to determine what to return to the user.
+ // the basic rules are:
+ // if infolevel 1 and not enough room for any entries
+ // ERROR_BUFFER_OVERFLOW
+ // if infolevel 2 or 3 and not enough room for entry + cblist of first entry
+ // ERROR_BUFFER_OVERFLOW
+ // if infolevel 3
+ // if not enough room for EAs for first entry
+ // copy entry + cblist
+ // return ERROR_EAS_DIDNT_FIT
+ //
+ // this translates into the following pseudocode:
+ //
+ // if (RetCode)
+ // if (entries found == 0)
+ // return retcode
+ // if (retcode == ERROR_EAS_DIDNT_FIT)
+ // if (entries found == 1)
+ // return retcode
+ // else
+ // decrement found count
+ //
+ // else if (retcode == ERROR_BUFFER_OVERFLOW | ERROR_NO_MORE_FILES)
+ // if (entries > 0)
+ // return no error
+ // else
+ // return retcode
+ // else
+ // return retcode
+
+ // if we get a return code, we stop getting more entries.
+ // first, we free up the memory we've allocated.
+ // then, if no entries have been found, we bag the search
+ // entirely by closing the directory handle and returning the
+ // error. if some entries have been found and ERROR_EAS_DIDNT_FIT
+ // was returned, we need to find out whether the error applied to
+ // the first (and only) entry in the buffer. if it did, we return
+ // the error. otherwise we don't. in any case, we save the search
+ // information and return a valid handle and search count.
+
+ if (RetCode != NO_ERROR) {
+EditBufferError:
+ if (EntriesFound == 0) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ return RetCode;
+ }
+ if (RetCode == ERROR_EAS_DIDNT_FIT) {
+ try {
+ *CountEntriesFound = EntriesFound;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ Od2ExitGP();
+ }
+ RetCode = UpdateSearchInfo(Rewind,
+ RewindEntry,
+ FindBuffer,
+ BufferLength,
+ DirectoryHandle);
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (RetCode != NO_ERROR) {
+ return RetCode;
+ }
+ if (EntriesFound == 1) {
+ return ERROR_EAS_DIDNT_FIT;
+ }
+ else {
+ *CountEntriesFound--;
+ return NO_ERROR;
+ }
+ }
+ //
+ // if the return code is error_buffer_overflow or error_no_more_files,
+ // and one or more entries has successfully been stored in the user's
+ // buffer, we return success.
+ //
+ else if ((RetCode == ERROR_BUFFER_OVERFLOW) ||
+ (RetCode == ERROR_NO_MORE_FILES)) {
+ if (EntriesFound > 0) {
+ try {
+ *CountEntriesFound = EntriesFound;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ Od2ExitGP();
+ }
+ RetCode = UpdateSearchInfo(Rewind,
+ RewindEntry,
+ FindBuffer,
+ BufferLength,
+ DirectoryHandle);
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ else {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ return RetCode;
+ }
+ }
+ //
+ // we get here if one or more entries has been successfully stored
+ // in the user's buffer, but we encountered an error other than
+ // buffer_overflow, no_more_files, or eas_didnt_fit. we fail the
+ // search and return the error code.
+ //
+ else {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RtlFreeHeap(Od2Heap,0,FindBuffer);
+ return RetCode;
+ }
+ ASSERT (FALSE); // we should never get here
+ }
+ //
+ // if we get here, EditBuffer returned NO_ERROR.
+ //
+ }
+
+ //
+ // if we get here, we've found all the requested entries. save the
+ // search information and return.
+ //
+ RetCode = UpdateSearchInfo(Rewind,
+ RewindEntry,
+ FindBuffer,
+ BufferLength,
+ DirectoryHandle);
+Done:
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+
+}
+
+APIRET
+DosFindClose(
+ IN HDIR DirectoryHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the OS/2 API DosFindClose.
+
+Arguments:
+
+ DirectoryHandle - The search handle associated with this particular
+ search.
+
+Return Value:
+
+ see OS/2 spec.
+
+--*/
+
+{
+ APIRET RetCode;
+ PSEARCH_RECORD SearchRecord;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosFindClose";
+ #endif
+
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if ((((ULONG)DirectoryHandle) >= SearchHandleTableLength) ||
+ (((ULONG) SearchHandleTable[((ULONG)DirectoryHandle)]) == SEARCH_HANDLE_FREE)) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE;
+ }
+ SearchRecord = (PSEARCH_RECORD) SearchHandleTable[((ULONG)DirectoryHandle)];
+ if (SearchRecord->FindBuffer != NULL) {
+ RtlFreeHeap(Od2Heap,0,SearchRecord->FindBuffer);
+ }
+ RetCode = FreeSearchHandle(DirectoryHandle);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+}
diff --git a/private/os2/client/dllflopy.c b/private/os2/client/dllflopy.c
new file mode 100644
index 000000000..78e331efd
--- /dev/null
+++ b/private/os2/client/dllflopy.c
@@ -0,0 +1,1241 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllflopy.c
+
+Abstract:
+
+ This module implements floppy disk related functions.
+
+Author:
+
+ Ofer Porat (oferp) 6-21-93
+
+Revision History:
+
+--*/
+
+#include "os2dll.h"
+#include "os2dev.h"
+#include "os2err.h"
+#include <ntdddisk.h>
+#include "os2flopy.h"
+
+
+//
+// Some constants
+//
+
+#define MAX_FLOPPY_DRIVES 5 // limit on number of floppy drives in system
+#define MAX_GEOMETRIES_PER_DRIVE 6 // limit on number of different geometries for a single drive
+
+#define SHORT_BPB_LENGTH 25 // length of initial DOS-like section of BPB
+#define LONG_BPB_LENGTH 36 // length of total OS/2 BPB
+#define BOOT_SECTOR_BPB_OFFSET 11 // offset of short BPB in a floppy's boot sector
+
+
+//
+// Data type definitions
+//
+
+//
+// The following structure is used to hold per-floppy-drive information:
+// 1) IsDeviceBpbValid asserts the validity of DeviceBpb which is used to
+// hold the recommended BPB for the device.
+// 2) IsMediaBpbValid asserts the validity of the following fields, which
+// are considered a unit:
+// a) MediaBpb -- BPB for the current media in drive
+// b) MediaType -- NT Media Type based on MediaBpb
+// c) TrueMediaGeometry -- contains the true media dimensions in case MediaBpb
+// is a fake BPB given by the user.
+//
+
+typedef struct _OD2_FLOPPYDISK_INFORMATION {
+ BOOLEAN IsDeviceBpbValid;
+ BOOLEAN IsMediaBpbValid;
+ MEDIA_TYPE MediaType;
+ DISK_GEOMETRY TrueMediaGeometry;
+ BIOSPARAMETERBLOCK DeviceBpb;
+ BIOSPARAMETERBLOCK MediaBpb;
+} OD2_FLOPPYDISK_INFORMATION, *POD2_FLOPPYDISK_INFORMATION;
+
+#if 0
+//
+// This structure is used to read the object name for floppy drives in
+// order to determine their number. It's large enough to contain
+// L"\\Device\\Floppy" plus some spare
+//
+
+//
+// Disabled, see below in Od2IdentifyDiskDrive()
+//
+
+typedef struct _X_OBJECT_NAME_INFORMATION {
+ OBJECT_NAME_INFORMATION i;
+ WCHAR n[20];
+} X_OBJECT_NAME_INFORMATION, *PX_OBJECT_NAME_INFORMATION;
+#endif
+
+
+//
+// Global variables
+//
+
+//
+// The following table holds default short BPBs for the common
+// drive types.
+//
+
+static BIOSPARAMETERBLOCK Od2StdBpb[8] = {
+ {512, 1, 1, 2, 112, 1*8*40, 0xFE, 1, 8, 1, 0, 0}, // 160KB 5.25"
+ {512, 1, 1, 2, 112, 1*9*40, 0xFC, 2, 9, 1, 0, 0}, // 180KB 5.25"
+ {512, 2, 1, 2, 112, 2*8*40, 0xFF, 1, 8, 2, 0, 0}, // 320KB 5.25"
+ {512, 2, 1, 2, 112, 2*9*40, 0xFD, 2, 9, 2, 0, 0}, // 360KB 5.25"
+ {512, 1, 1, 2, 224, 2*15*80, 0xF9, 7, 15, 2, 0, 0}, // 1.2MB 5.25"
+ {512, 2, 1, 2, 112, 2*9*80, 0xF9, 3, 9, 2, 0, 0}, // 720KB 3.5"
+ {512, 1, 1, 2, 224, 2*18*80, 0xF0, 9, 18, 2, 0, 0}, // 1.44MB 3.5"
+ {512, 2, 1, 2, 240, 2*36*80, 0xF0, 9, 36, 2, 0, 0} // 2.88MB 3.5"
+ };
+
+//
+// The following resource lock protects Od2DiskBlocks & Od2Geometries
+//
+
+static RTL_RESOURCE Od2DisksLock;
+
+#define AcquireDisksLockExclusive() (VOID) RtlAcquireResourceExclusive(&Od2DisksLock, TRUE)
+#define AcquireDisksLockShared() (VOID) RtlAcquireResourceShared(&Od2DisksLock, TRUE)
+#define ReleaseDisksLockExclusive() (VOID) RtlReleaseResource(&Od2DisksLock)
+#define ReleaseDisksLockShared() (VOID) RtlReleaseResource(&Od2DisksLock)
+#define ConvertDisksLockExclusiveToShared() (VOID) RtlConvertExclusiveToShared(&Od2DisksLock)
+#define ConvertDisksLockSharedToExclusive() (VOID) RtlConvertSharedToExclusive(&Od2DisksLock)
+
+//
+// Od2Geometries is used for reading in geometries from drives
+//
+
+static DISK_GEOMETRY Od2Geometries[MAX_GEOMETRIES_PER_DRIVE];
+
+//
+// Od2DiskBlocks holds the floppy disk information for the system.
+//
+
+static OD2_FLOPPYDISK_INFORMATION Od2DiskBlocks[MAX_FLOPPY_DRIVES];
+
+
+//
+// Code comes next
+//
+
+
+APIRET
+Od2IdentifyDiskDrive(
+ IN HANDLE NtHandle,
+ IN PULONG pDriveNumberPermanentStorageLocation,
+ OUT PULONG pDriveNumber
+ )
+{
+// X_OBJECT_NAME_INFORMATION ObjectName;
+ FILE_FS_DEVICE_INFORMATION FsDeviceInfoBuffer;
+ IO_STATUS_BLOCK IoStatus;
+ NTSTATUS Status;
+ ULONG DriveNumber;
+
+//
+// Initially it was intended that the drive number be discovered by
+// using NtQueryObject() to find the object name which should be
+// something like \Device\Floppy0, and from this it's possible to
+// tell the drive number.
+//
+// It turns out however that NT does not have a name for a drive
+// opened in this fashion (\os2ss\drives\a:). So, instead, DosOpen()
+// was modified to put the drive letter which it knows about in
+// *pDriveNumberPermanentStorageLocation. It sets the high bit on.
+// During the first time, this routine checks to see that it's actually
+// a floppy drive. After this it sets the high bit off, and later on it
+// only uses the drive number it has already figured out in DosOpen().
+//
+
+ DriveNumber = *pDriveNumberPermanentStorageLocation;
+
+ if (DriveNumber != (ULONG) NULL &&
+ DriveNumber <= MAX_FLOPPY_DRIVES) {
+
+ *pDriveNumber = DriveNumber - 1;
+ return(NO_ERROR);
+ }
+
+ Status = NtQueryVolumeInformationFile(NtHandle,
+ &IoStatus,
+ &FsDeviceInfoBuffer,
+ sizeof(FsDeviceInfoBuffer),
+ FileFsDeviceInformation
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2IdentifyDiskDrive: unable to NtQueryVolumeInfo, Status == %lx\n",
+ Status));
+ }
+#endif
+ return(Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE));
+ }
+
+ if (FsDeviceInfoBuffer.DeviceType != FILE_DEVICE_DISK ||
+ !(FsDeviceInfoBuffer.Characteristics & FILE_DEVICE_IS_MOUNTED)) {
+
+ return(ERROR_INVALID_HANDLE);
+ }
+
+ //
+ // currently we support only floppy drives ...
+ //
+
+ if (!(FsDeviceInfoBuffer.Characteristics & FILE_FLOPPY_DISKETTE)) {
+
+ return(ERROR_NOT_SUPPORTED);
+ }
+
+#if 1
+ //
+ // This is the altername code -- it just leaves the drive number
+ // obtained from DosOpen()
+ //
+
+ DriveNumber &= 0x7fffffff;
+
+ if (DriveNumber != (ULONG) NULL &&
+ DriveNumber <= MAX_FLOPPY_DRIVES) {
+
+ *pDriveNumber = DriveNumber - 1;
+ *pDriveNumberPermanentStorageLocation = DriveNumber;
+ return(NO_ERROR);
+
+ } else {
+
+ //
+ // Drive obtained from DosOpen() is not good.
+ // return an error
+ //
+
+ return(ERROR_INVALID_DRIVE);
+ }
+
+#else
+
+ //
+ // This is the code that should have worked -- get the drive name from NT
+ //
+
+ Status = NtQueryObject(NtHandle,
+ ObjectNameInformation,
+ &ObjectName,
+ sizeof(ObjectName),
+ NULL
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2IdentifyDiskDrive: unable to NtQueryObject, Status == %lx\n",
+ Status));
+ }
+#endif
+ if (Status == STATUS_BUFFER_OVERFLOW) {
+ return(ERROR_INVALID_DRIVE);
+ } else {
+ return(Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_DRIVE));
+ }
+ }
+
+ if (ObjectName.i.Name.Length != 30 ||
+ RtlCompareMemory(ObjectName.i.Name.Buffer, L"\\Device\\Floppy", 28) != 28) {
+
+ return(ERROR_INVALID_DRIVE);
+ }
+
+ DriveNumber = (ULONG) (ObjectName.n[14] - L'0');
+ *pDriveNumber = DriveNumber;
+ *pDriveNumberPermanentStorageLocation = DriveNumber + 1;
+ return(NO_ERROR);
+
+#endif
+}
+
+
+VOID
+Od2DetermineMediaType(
+ OUT PMEDIA_TYPE pMediaType,
+ IN PBIOSPARAMETERBLOCK pBPB
+ )
+{
+ MEDIA_TYPE MediaType = Unknown;
+
+ switch (pBPB->bDeviceType) {
+
+ case DEVTYPE_35:
+ case DEVTYPE_UNKNOWN:
+
+ if (RtlCompareMemory(pBPB, &Od2StdBpb[6], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
+ MediaType = F3_1Pt44_512;
+ break;
+ }
+ if (RtlCompareMemory(pBPB, &Od2StdBpb[5], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
+ MediaType = F3_720_512;
+ break;
+ }
+ if (RtlCompareMemory(pBPB, &Od2StdBpb[7], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
+ MediaType = F3_2Pt88_512;
+ break;
+ }
+ break;
+
+ case DEVTYPE_48TPI:
+ case DEVTYPE_96TPI:
+
+ if (RtlCompareMemory(pBPB, &Od2StdBpb[4], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
+ MediaType = F5_1Pt2_512;
+ break;
+ }
+ if (RtlCompareMemory(pBPB, &Od2StdBpb[3], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
+ MediaType = F5_360_512;
+ break;
+ }
+ if (RtlCompareMemory(pBPB, &Od2StdBpb[2], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
+ MediaType = F5_320_512;
+ break;
+ }
+ if (RtlCompareMemory(pBPB, &Od2StdBpb[1], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
+ MediaType = F5_180_512;
+ break;
+ }
+ if (RtlCompareMemory(pBPB, &Od2StdBpb[0], SHORT_BPB_LENGTH) == SHORT_BPB_LENGTH) {
+ MediaType = F5_160_512;
+ break;
+ }
+ break;
+
+ case DEVTYPE_FIXED:
+ MediaType = FixedMedia;
+ break;
+
+ case DEVTYPE_TAPE:
+ MediaType = RemovableMedia;
+ break;
+ }
+
+ *pMediaType = MediaType;
+}
+
+
+VOID
+Od2ComputeTrueGeometry(
+ IN HANDLE NtHandle,
+ IN BOOLEAN EnforceFakeGeometry,
+ OUT PDISK_GEOMETRY pTrueGeometry,
+ IN PBIOSPARAMETERBLOCK pFakeBpb,
+ IN MEDIA_TYPE FakeMediaType
+ )
+{
+ IO_STATUS_BLOCK IoStatus;
+ NTSTATUS Status;
+
+ if (!EnforceFakeGeometry) {
+
+ Status = NtDeviceIoControlFile(
+ NtHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL,
+ 0,
+ pTrueGeometry,
+ sizeof(DISK_GEOMETRY));
+
+ if (NT_SUCCESS(Status) && IoStatus.Information >= sizeof(DISK_GEOMETRY)) {
+ return;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2ComputeTrueGeometry: unable to get true geometry (using fake), Status == %lx\n",
+ Status));
+ }
+#endif
+ }
+
+ pTrueGeometry->MediaType = FakeMediaType;
+ pTrueGeometry->Cylinders = RtlConvertUlongToLargeInteger((ULONG) pFakeBpb->cCylinders);
+ pTrueGeometry->TracksPerCylinder = (ULONG) pFakeBpb->cHeads;
+ pTrueGeometry->SectorsPerTrack = (ULONG) pFakeBpb->usSectorsPerTrack;
+ pTrueGeometry->BytesPerSector = (ULONG) pFakeBpb->usBytesPerSector;
+}
+
+
+APIRET
+Od2AcquireDeviceBPB(
+ IN ULONG DriveNumber,
+ IN HANDLE NtHandle,
+ IN BOOLEAN Validate,
+ IN BOOLEAN UseDefault,
+ IN OUT PBIOSPARAMETERBLOCK pBpb OPTIONAL
+ )
+{
+ IO_STATUS_BLOCK IoStatus;
+ NTSTATUS Status;
+ APIRET RetCode = NO_ERROR;
+ PBOOLEAN pIsValid;
+ MEDIA_TYPE MediaType;
+ ULONG GeometryIndex;
+ LONG StdBpbIndex;
+ POD2_FLOPPYDISK_INFORMATION DiskInfo;
+ PBIOSPARAMETERBLOCK pBPB;
+
+
+ if (DriveNumber >= MAX_FLOPPY_DRIVES) {
+ return(ERROR_INVALID_DRIVE);
+ }
+
+ DiskInfo = &Od2DiskBlocks[DriveNumber];
+ pBPB = &DiskInfo->DeviceBpb;
+ pIsValid = &DiskInfo->IsDeviceBpbValid;
+
+ if (Validate) {
+
+ AcquireDisksLockShared();
+
+ if (*pIsValid) {
+
+ if (ARGUMENT_PRESENT(pBpb)) {
+ RtlMoveMemory(pBpb, pBPB, sizeof(BIOSPARAMETERBLOCK));
+ }
+ ReleaseDisksLockShared();
+ return(NO_ERROR);
+ }
+
+ ConvertDisksLockSharedToExclusive();
+
+ if (*pIsValid) {
+
+ if (ARGUMENT_PRESENT(pBpb)) {
+ RtlMoveMemory(pBpb, pBPB, sizeof(BIOSPARAMETERBLOCK));
+ }
+ ReleaseDisksLockExclusive();
+ return(NO_ERROR);
+ }
+
+ } else {
+
+ AcquireDisksLockExclusive();
+ }
+
+ *pIsValid = FALSE;
+
+ if (!UseDefault) {
+
+ RtlMoveMemory(pBPB, pBpb, sizeof(BIOSPARAMETERBLOCK));
+
+ Od2DetermineMediaType(
+ &MediaType,
+ pBPB
+ );
+
+ if (MediaType == Unknown) {
+ RetCode = ERROR_INVALID_DATA;
+ } else {
+ *pIsValid = TRUE;
+ }
+
+ goto Cleanup;
+ }
+
+ Status = NtDeviceIoControlFile(
+ NtHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_DISK_GET_MEDIA_TYPES,
+ NULL,
+ 0,
+ Od2Geometries,
+ sizeof(Od2Geometries));
+
+ if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2AcquireDeviceBPB: unable to NtDeviceIoCtl, Status == %lx\n",
+ Status));
+ }
+#endif
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ goto Cleanup;
+ }
+
+ if (IoStatus.Information < sizeof(DISK_GEOMETRY)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2AcquireDeviceBPB: NtDeviceIoCtl returned short length = %lx\n",
+ IoStatus.Information));
+ }
+#endif
+ RetCode = ERROR_INVALID_DRIVE;
+ goto Cleanup;
+ }
+
+ if (Status == STATUS_BUFFER_OVERFLOW) {
+ GeometryIndex = MAX_GEOMETRIES_PER_DRIVE - 1;
+ } else {
+ GeometryIndex = (IoStatus.Information / sizeof(DISK_GEOMETRY)) - 1;
+ }
+
+ MediaType = Od2Geometries[GeometryIndex].MediaType;
+
+ if (MediaType == FixedMedia ||
+ MediaType == Unknown) {
+
+ pBPB->fsDeviceAttr = 0x1; // non-removable, no media change detect
+ } else if (MediaType == RemovableMedia) {
+
+ pBPB->fsDeviceAttr = 0x0; // removable, no media change detect
+ } else {
+
+ pBPB->fsDeviceAttr = 0x2; // removable, yes media change detect
+ }
+
+ pBPB->cCylinders = (USHORT) Od2Geometries[GeometryIndex].Cylinders.LowPart;
+
+ StdBpbIndex = -1L;
+
+ switch (MediaType) {
+
+ case F5_1Pt2_512:
+ pBPB->bDeviceType = DEVTYPE_96TPI;
+ StdBpbIndex = 4L;
+ break;
+
+ case F5_360_512:
+ pBPB->bDeviceType = DEVTYPE_96TPI;
+ StdBpbIndex = 3L;
+ break;
+
+ case F5_320_512:
+ pBPB->bDeviceType = DEVTYPE_96TPI;
+ StdBpbIndex = 2L;
+ break;
+
+ case F5_320_1024:
+ pBPB->bDeviceType = DEVTYPE_96TPI;
+ break;
+
+ case F5_180_512:
+ pBPB->bDeviceType = DEVTYPE_96TPI;
+ StdBpbIndex = 1L;
+ break;
+
+ case F5_160_512:
+ pBPB->bDeviceType = DEVTYPE_96TPI;
+ StdBpbIndex = 0L;
+ break;
+
+ case F3_1Pt44_512:
+ pBPB->bDeviceType = DEVTYPE_UNKNOWN;
+ StdBpbIndex = 6L;
+ break;
+
+ case F3_720_512:
+ pBPB->bDeviceType = DEVTYPE_UNKNOWN;
+ StdBpbIndex = 5L;
+ break;
+
+ case F3_20Pt8_512:
+ pBPB->bDeviceType = DEVTYPE_UNKNOWN;
+ break;
+
+ case F3_2Pt88_512:
+ pBPB->bDeviceType = DEVTYPE_UNKNOWN;
+ StdBpbIndex = 7L;
+ break;
+
+ case FixedMedia:
+ pBPB->bDeviceType = DEVTYPE_FIXED;
+ break;
+
+ case RemovableMedia:
+ pBPB->bDeviceType = DEVTYPE_TAPE;
+ break;
+
+ default:
+ pBPB->bDeviceType = DEVTYPE_UNKNOWN;
+ break;
+ }
+
+ if (StdBpbIndex == -1L) {
+
+ //
+ // unrecognized device type
+ //
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2AcquireDeviceBPB: recommended BPB asked for unknown dev type = %lx\n",
+ MediaType));
+ }
+#endif
+ RetCode = ERROR_INVALID_DRIVE;
+ goto Cleanup;
+ }
+
+ RtlMoveMemory(pBPB, &Od2StdBpb[StdBpbIndex], SHORT_BPB_LENGTH);
+
+ if (ARGUMENT_PRESENT(pBpb)) {
+ RtlMoveMemory(pBpb, pBPB, sizeof(BIOSPARAMETERBLOCK));
+ }
+
+ *pIsValid = TRUE;
+
+Cleanup:
+
+ ReleaseDisksLockExclusive();
+ return(RetCode);
+}
+
+
+APIRET
+Od2AcquireMediaBPB(
+ IN ULONG DriveNumber,
+ IN HANDLE NtHandle,
+ IN BOOLEAN Validate,
+ IN BOOLEAN UseDefault,
+ IN BOOLEAN EnforceFakeGeometry,
+ IN OUT PBIOSPARAMETERBLOCK pBpb OPTIONAL,
+ OUT PMEDIA_TYPE pMediaType OPTIONAL,
+ OUT PDISK_GEOMETRY pTrueMediaGeometry OPTIONAL
+ )
+{
+ IO_STATUS_BLOCK IoStatus;
+ NTSTATUS Status;
+ APIRET RetCode = NO_ERROR;
+ PBOOLEAN pIsValid;
+ LARGE_INTEGER BootSecOffset;
+ PBYTE BootSecBuffer;
+ POD2_FLOPPYDISK_INFORMATION DiskInfo;
+ PBIOSPARAMETERBLOCK pBPB;
+ PDISK_GEOMETRY pTrueGeometry;
+
+ if (DriveNumber >= MAX_FLOPPY_DRIVES) {
+ return(ERROR_INVALID_DRIVE);
+ }
+
+ DiskInfo = &Od2DiskBlocks[DriveNumber];
+ pBPB = &DiskInfo->MediaBpb;
+ pIsValid = &DiskInfo->IsMediaBpbValid;
+ pTrueGeometry = &DiskInfo->TrueMediaGeometry;
+
+ if (Validate) {
+
+ if (!EnforceFakeGeometry) {
+
+ AcquireDisksLockShared();
+
+ if (*pIsValid) {
+
+ if (ARGUMENT_PRESENT(pBpb)) {
+ RtlMoveMemory(pBpb, pBPB, sizeof(BIOSPARAMETERBLOCK));
+ }
+ if (ARGUMENT_PRESENT(pMediaType)) {
+ *pMediaType = DiskInfo->MediaType;
+ }
+ if (ARGUMENT_PRESENT(pTrueMediaGeometry)) {
+ RtlMoveMemory(pTrueMediaGeometry, pTrueGeometry, sizeof(DISK_GEOMETRY));
+ }
+ ReleaseDisksLockShared();
+ return(NO_ERROR);
+ }
+
+ ConvertDisksLockSharedToExclusive();
+
+ } else {
+
+ AcquireDisksLockExclusive();
+ }
+
+ if (*pIsValid) {
+
+ if (EnforceFakeGeometry) {
+
+ Od2ComputeTrueGeometry(
+ NtHandle,
+ TRUE,
+ pTrueGeometry,
+ pBPB,
+ DiskInfo->MediaType);
+ }
+
+ if (ARGUMENT_PRESENT(pBpb)) {
+ RtlMoveMemory(pBpb, pBPB, sizeof(BIOSPARAMETERBLOCK));
+ }
+ if (ARGUMENT_PRESENT(pMediaType)) {
+ *pMediaType = DiskInfo->MediaType;
+ }
+ if (ARGUMENT_PRESENT(pTrueMediaGeometry)) {
+ RtlMoveMemory(pTrueMediaGeometry, pTrueGeometry, sizeof(DISK_GEOMETRY));
+ }
+ ReleaseDisksLockExclusive();
+ return(NO_ERROR);
+ }
+
+ } else {
+
+ AcquireDisksLockExclusive();
+ }
+
+ *pIsValid = FALSE;
+
+ if (!UseDefault) {
+
+ RtlMoveMemory(pBPB, pBpb, sizeof(BIOSPARAMETERBLOCK));
+
+ Od2DetermineMediaType(
+ &DiskInfo->MediaType,
+ pBPB
+ );
+
+ if (DiskInfo->MediaType == Unknown) {
+ RetCode = ERROR_INVALID_DATA;
+ } else {
+
+ Od2ComputeTrueGeometry(
+ NtHandle,
+ EnforceFakeGeometry,
+ pTrueGeometry,
+ pBPB,
+ DiskInfo->MediaType);
+
+ if (ARGUMENT_PRESENT(pMediaType)) {
+ *pMediaType = DiskInfo->MediaType;
+ }
+ if (ARGUMENT_PRESENT(pTrueMediaGeometry)) {
+ RtlMoveMemory(pTrueMediaGeometry, pTrueGeometry, sizeof(DISK_GEOMETRY));
+ }
+ *pIsValid = TRUE;
+ }
+
+ goto Cleanup;
+ }
+
+ Status = NtDeviceIoControlFile(
+ NtHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL,
+ 0,
+ Od2Geometries,
+ sizeof(Od2Geometries));
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2AcquireMediaBPB: unable to NtDeviceIoCtl, Status == %lx\n",
+ Status));
+ }
+#endif
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ goto Cleanup;
+ }
+
+ if (IoStatus.Information < sizeof(DISK_GEOMETRY)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2AcquireMediaBPB: NtDeviceIoCtl returned short length = %lx\n",
+ IoStatus.Information));
+ }
+#endif
+ RetCode = ERROR_INVALID_DRIVE;
+ goto Cleanup;
+ }
+
+ DiskInfo->MediaType = Od2Geometries[0].MediaType;
+
+ RtlMoveMemory(pTrueGeometry, Od2Geometries, sizeof(DISK_GEOMETRY));
+
+ if (DiskInfo->MediaType == FixedMedia ||
+ DiskInfo->MediaType == Unknown) {
+
+ pBPB->fsDeviceAttr = 0x1; // non-removable, no media change detect
+ } else if (DiskInfo->MediaType == RemovableMedia) {
+
+ pBPB->fsDeviceAttr = 0x0; // removable, no media change detect
+ } else {
+
+ pBPB->fsDeviceAttr = 0x2; // removable, yes media change detect
+ }
+
+ pBPB->cCylinders = (USHORT) Od2Geometries[0].Cylinders.LowPart;
+
+ switch (DiskInfo->MediaType) {
+
+ case F5_1Pt2_512:
+ case F5_360_512:
+ case F5_320_512:
+ case F5_320_1024:
+ case F5_180_512:
+ case F5_160_512:
+ pBPB->bDeviceType = DEVTYPE_96TPI;
+ break;
+
+ case F3_1Pt44_512:
+ case F3_720_512:
+ case F3_20Pt8_512:
+ case F3_2Pt88_512:
+ pBPB->bDeviceType = DEVTYPE_UNKNOWN;
+ break;
+
+ case FixedMedia:
+ pBPB->bDeviceType = DEVTYPE_FIXED;
+ break;
+
+ case RemovableMedia:
+ pBPB->bDeviceType = DEVTYPE_TAPE;
+ break;
+
+ default:
+ pBPB->bDeviceType = DEVTYPE_UNKNOWN;
+ break;
+ }
+
+ //
+ // Get BPB for current media
+ // by reading it off the disk
+ //
+
+ BootSecOffset.HighPart = BootSecOffset.LowPart = 0L;
+
+ BootSecBuffer = (PBYTE) RtlAllocateHeap(Od2Heap, 0, Od2Geometries[0].BytesPerSector);
+
+ if (BootSecBuffer == NULL) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2AcquireMediaBPB: unable to alloc buffer for boot sector\n"));
+ }
+#endif
+ RetCode = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ Status = NtReadFile(
+ NtHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ BootSecBuffer,
+ Od2Geometries[0].BytesPerSector,
+ &BootSecOffset,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2AcquireMediaBPB: unable to NtReadFile, Status = %lx\n", Status));
+ }
+#endif
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_NOT_READY);
+ RtlFreeHeap(Od2Heap, 0, BootSecBuffer);
+ goto Cleanup;
+ }
+
+ //
+ // check validity of boot sector
+ //
+
+ if ((IoStatus.Information >= 36) &&
+ (BootSecBuffer[0] == 0x69 || BootSecBuffer[0] == 0xE9 ||
+ (BootSecBuffer[0] == 0xEB && BootSecBuffer[2] == 0x90)) &&
+ ((BootSecBuffer[21] & 0xF0) == 0xF0)) {
+
+
+ RtlMoveMemory(pBPB, BootSecBuffer + BOOT_SECTOR_BPB_OFFSET, SHORT_BPB_LENGTH);
+
+ if (ARGUMENT_PRESENT(pBpb)) {
+ RtlMoveMemory(pBpb, pBPB, sizeof(BIOSPARAMETERBLOCK));
+ }
+ if (ARGUMENT_PRESENT(pMediaType)) {
+ *pMediaType = DiskInfo->MediaType;
+ }
+ if (ARGUMENT_PRESENT(pTrueMediaGeometry)) {
+ RtlMoveMemory(pTrueMediaGeometry, pTrueGeometry, sizeof(DISK_GEOMETRY));
+ }
+
+ *pIsValid = TRUE;
+
+ } else {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2AcquireMediaBPB: unable to recognize boot sector\n"));
+ }
+#endif
+ RetCode = ERROR_INVALID_DRIVE;
+ }
+
+ RtlFreeHeap(Od2Heap, 0, BootSecBuffer);
+
+Cleanup:
+
+ ReleaseDisksLockExclusive();
+ return(RetCode);
+}
+
+
+ULONG
+Od2ComputeDiskOffset(
+ IN PBIOSPARAMETERBLOCK pBpb,
+ IN PDISK_GEOMETRY pTrueGeometry,
+ IN ULONG Head,
+ IN ULONG Cylinder,
+ IN ULONG Sector
+ )
+{
+ ULONG TrackOffset, SectorOffset, ByteOffset;
+
+ if (Head >= (ULONG) pBpb->cHeads ||
+ Sector >= (ULONG) pBpb->usSectorsPerTrack ||
+ Cylinder >= (ULONG) pBpb->cCylinders) {
+
+ return((ULONG) -1); // invalid parameter given
+ }
+
+ TrackOffset = Head +
+ Cylinder *
+ pTrueGeometry->TracksPerCylinder;
+
+ SectorOffset = Sector +
+ TrackOffset *
+ pTrueGeometry->SectorsPerTrack;
+
+ ByteOffset = (SectorOffset + pBpb->cHiddenSectors) *
+ pTrueGeometry->BytesPerSector;
+
+ return(ByteOffset);
+}
+
+
+APIRET
+Od2ReadWriteVerifyTrack(
+ IN HANDLE NtHandle,
+ IN ULONG Command,
+ IN PTRACKLAYOUT TrackLayout,
+ IN PBYTE pData OPTIONAL,
+ IN ULONG CountSectors,
+ IN PBIOSPARAMETERBLOCK pBpb,
+ IN PDISK_GEOMETRY pTrueGeometry
+ )
+{
+ IO_STATUS_BLOCK IoStatus;
+ LARGE_INTEGER BigByteOffset;
+ NTSTATUS Status;
+ PBYTE Buffer;
+ ULONG ByteOffset;
+ ULONG ByteLength;
+ ULONG Sector;
+
+ if (Command >= TRACK_CMD_LIMIT) {
+ return(ERROR_NOT_SUPPORTED);
+ }
+
+ if (TrackLayout->bCommand == 1) {
+
+ if ((ULONG) TrackLayout->usFirstSector + CountSectors > (ULONG) pBpb->usSectorsPerTrack) {
+ return(ERROR_SECTOR_NOT_FOUND);
+ }
+
+ ByteLength = CountSectors * (ULONG) pBpb->usBytesPerSector;
+
+ ByteOffset = Od2ComputeDiskOffset(
+ pBpb,
+ pTrueGeometry,
+ (ULONG) TrackLayout->usHead,
+ (ULONG) TrackLayout->usCylinder,
+ (ULONG) TrackLayout->usFirstSector);
+
+ if (ByteOffset == (ULONG) -1) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2ReadWriteVerifyTrack: Invalid sector location given (1)\n"));
+ }
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ BigByteOffset = RtlConvertUlongToLargeInteger(ByteOffset);
+
+ if (Command == VERIFY_TRACK_CMD) {
+
+ Buffer = (PBYTE) RtlAllocateHeap(Od2Heap, 0, ByteLength);
+
+ if (Buffer == NULL) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2ReadWriteVerifyTrack: Unable to allocate memory for track verification (1)\n"));
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ } else {
+ Buffer = pData;
+ }
+
+ if (Command == WRITE_TRACK_CMD) {
+
+ Status = NtWriteFile(
+ NtHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ Buffer,
+ ByteLength,
+ &BigByteOffset,
+ NULL);
+ } else {
+
+ Status = NtReadFile(
+ NtHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ Buffer,
+ ByteLength,
+ &BigByteOffset,
+ NULL);
+
+ }
+
+ if (Command == VERIFY_TRACK_CMD) {
+ RtlFreeHeap(Od2Heap, 0, Buffer);
+ }
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2ReadWriteVerifyTrack: NtRead/WriteFile (1) failed, Status = %lx\n", Status));
+ }
+#endif
+ return(Or2MapNtStatusToOs2Error(Status, ERROR_NOT_READY));
+ }
+
+ if (IoStatus.Information != ByteLength) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2ReadWriteVerifyTrack: NtRead/WriteFile (1) partial read/write, Wanted = %lx, Actual = %lx\n",
+ ByteOffset, IoStatus.Information));
+ }
+#endif
+ return(ERROR_NOT_READY); // Bogus return code
+ }
+
+ } else {
+
+ //
+ // We have a sector list, write it sector by sector
+ //
+
+ ULONG i,j;
+
+ ByteLength = (ULONG) pBpb->usBytesPerSector;
+
+ if (Command == VERIFY_TRACK_CMD) {
+
+ Buffer = (PBYTE) RtlAllocateHeap(Od2Heap, 0, ByteLength);
+
+ if (Buffer == NULL) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2ReadWriteVerifyTrack: Unable to allocate memory for track verification (2)\n"));
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ } else {
+
+ Buffer = pData;
+ }
+
+ for (i = 0, j = (ULONG) TrackLayout->usFirstSector;
+ i < CountSectors;
+ i++, j++) {
+
+ Sector = ((ULONG) TrackLayout->TrackTable[j].usSectorNumber) - 1;
+
+ ByteOffset = Od2ComputeDiskOffset(
+ pBpb,
+ pTrueGeometry,
+ (ULONG) TrackLayout->usHead,
+ (ULONG) TrackLayout->usCylinder,
+ Sector);
+
+ if (ByteOffset == (ULONG) -1) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2ReadWriteVerifyTrack: Invalid sector location given (2), table position = %ld\n", j));
+ }
+#endif
+ if (Command == VERIFY_TRACK_CMD) {
+ RtlFreeHeap(Od2Heap, 0, Buffer);
+ }
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ BigByteOffset = RtlConvertUlongToLargeInteger(ByteOffset);
+
+ if (Command == WRITE_TRACK_CMD) {
+
+ Status = NtWriteFile(
+ NtHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ Buffer,
+ ByteLength,
+ &BigByteOffset,
+ NULL);
+ } else {
+
+ Status = NtReadFile(
+ NtHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ Buffer,
+ ByteLength,
+ &BigByteOffset,
+ NULL);
+
+ }
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2ReadWriteVerifyTrack: NtRead/WriteFile (2) failed, Status = %lx\n", Status));
+ }
+#endif
+ if (Command == VERIFY_TRACK_CMD) {
+ RtlFreeHeap(Od2Heap, 0, Buffer);
+ }
+ return(Or2MapNtStatusToOs2Error(Status, ERROR_NOT_READY));
+ }
+
+ if (IoStatus.Information != ByteLength) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2ReadWriteVerifyTrack: NtRead/WriteFile (2) partial read/write, Wanted = %lx, Actual = %lx\n",
+ ByteOffset, IoStatus.Information));
+ }
+#endif
+ if (Command == VERIFY_TRACK_CMD) {
+ RtlFreeHeap(Od2Heap, 0, Buffer);
+ }
+ return(ERROR_NOT_READY); // Bogus return code
+ }
+
+ Buffer += ByteLength;
+ }
+
+ if (Command == VERIFY_TRACK_CMD) {
+ RtlFreeHeap(Od2Heap, 0, Buffer);
+ }
+ }
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+Od2FormatTrack(
+ IN HANDLE NtHandle,
+ IN PTRACKFORMAT TrackFormat,
+ IN ULONG CountSectors,
+ IN BYTE FormatSectorSizeType,
+ IN PBIOSPARAMETERBLOCK pBpb,
+ IN MEDIA_TYPE MediaType
+ )
+{
+ FORMAT_PARAMETERS FormP;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+
+ //
+ // Check that user's parameters don't contradict BPB
+ //
+
+ if (FormatSectorSizeType > 0x3 ||
+ (((USHORT)128) << FormatSectorSizeType) != pBpb->usBytesPerSector ||
+ CountSectors != (ULONG) pBpb->usSectorsPerTrack ||
+ (ULONG) TrackFormat->usHead >= (ULONG) pBpb->cHeads ||
+ (ULONG) TrackFormat->usCylinder >= (ULONG) pBpb->cCylinders) {
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2FormatTrack: Format parameters given contradict BPB\n"));
+ }
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ FormP.MediaType = MediaType;
+ FormP.StartCylinderNumber = (ULONG) TrackFormat->usCylinder;
+ FormP.EndCylinderNumber = (ULONG) TrackFormat->usCylinder;
+ FormP.StartHeadNumber = (ULONG) TrackFormat->usHead;
+ FormP.EndHeadNumber = (ULONG) TrackFormat->usHead;
+
+ Status = NtDeviceIoControlFile(
+ NtHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_DISK_FORMAT_TRACKS,
+ &FormP,
+ sizeof(FormP),
+ NULL,
+ 0);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Od2FormatTrack: NtDeviceIoControlFile failed, Status = %lx\n", Status));
+ }
+#endif
+ return(Or2MapNtStatusToOs2Error(Status, ERROR_NOT_READY));
+ }
+
+ return(NO_ERROR);
+}
+
+
+VOID
+Od2DiskIOInitialize(
+ VOID
+ )
+{
+ RtlInitializeResource(&Od2DisksLock);
+}
+
+
+VOID
+Od2DiskIOTerminate(
+ VOID
+ )
+{
+ RtlDeleteResource(&Od2DisksLock);
+}
diff --git a/private/os2/client/dllfs16.c b/private/os2/client/dllfs16.c
new file mode 100644
index 000000000..4011fdf9d
--- /dev/null
+++ b/private/os2/client/dllfs16.c
@@ -0,0 +1,5177 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllfs16.c
+
+Abstract:
+
+ This module implements 32 equivalents of OS/2 V1.21 File System
+ API Calls that are not trivially mapped to Cruiser APIs. These
+ are called from 16->32 thunks (i386\doscalls.asm).
+
+
+Author:
+
+ Yaron Shamir (YaronS) 30-May-1991
+
+Revision History:
+
+ Patrick Questembert (patrickq) 2-Feb-1992:
+ Added Dos16QFSAttach
+ Patrick Questembert (patrickq) 10-Feb-1992:
+ Added Dos16MkDir2
+
+--*/
+
+#define NTOS2_ONLY
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FSD
+#define INCL_OS2V20_ERRORMSG
+#include "os2dll.h"
+#include "os2dll16.h"
+
+typedef struct _ASYNCREAD{
+ HFILE hf;
+ PULONG hsemRam;
+ PUSHORT pusErrCode;
+ PVOID pvBuf;
+ ULONG cbBuf;
+ PUSHORT pcbBytesRead;
+} ASYNCREAD, *PASYNCREAD;
+
+APIRET
+DosPhysicalDisk(
+ IN ULONG function,
+ OUT PBYTE pBuf,
+ OUT ULONG cbBuf,
+ IN PBYTE pParams,
+ IN ULONG cbParams
+ )
+{
+ SYSTEM_DEVICE_INFORMATION SystemInfo;
+
+ switch (function) {
+ case INFO_COUNT_PARTITIONABLE_DISKS:
+
+ if ((pParams != NULL) || (cbParams != 0) || (cbBuf < 2)) {
+ return (ERROR_INVALID_PARAMETER);
+ }
+
+ try {
+ Od2ProbeForWrite(pBuf, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ NtQuerySystemInformation(
+ SystemDeviceInformation,
+ &SystemInfo,
+ sizeof(SYSTEM_DEVICE_INFORMATION),
+ NULL
+ );
+
+ *(PUSHORT)pBuf = (USHORT)SystemInfo.NumberOfDisks;
+ break;
+
+ case INFO_FREEIOCTLHANDLE:
+ case INFO_GETIOCTLHANDLE:
+
+#if DBG
+ KdPrint(("DosPhysicalDisk: Function %d Not Implemented\n", function));
+#endif
+ return (ERROR_INVALID_FUNCTION);
+ }
+ return (NO_ERROR);
+}
+
+APIRET
+DosFileIO(
+ IN HFILE FileHandle,
+ IN PBYTE CommandBuffer,
+ IN ULONG Length,
+ OUT PUSHORT ErrorOffset
+ )
+{
+ APIRET RetCode = NO_ERROR;
+ PFILE_HANDLE hFileRecord;
+ PUSHORT CurrentCmd;
+ PFIOLOCKCMD16 pLock;
+ PFIOUNLOCKCMD16 pUnlock;
+ PFIOSEEKCMD16 pSeek;
+ PFIOREADWRITE16 pRW;
+ PFIOLOCKREC16 pLockRec;
+ PFIOUNLOCKREC16 pUnlockRec;
+ FILE_POSITION_INFORMATION FilePosition;
+ FILE_STANDARD_INFORMATION FileStandardInfo;
+ LARGE_INTEGER TmpLarge;
+ LARGE_INTEGER TmpLarge2;
+ IO_STATUS_BLOCK IoStatus;
+ NTSTATUS Status;
+ HANDLE NtFileHandle;
+ ULONG Key;
+ USHORT i;
+ #if DBG
+ PSZ RoutineName = "DosFileIO";
+ #endif
+
+ try {
+ Od2ProbeForWrite(ErrorOffset, sizeof(USHORT), 1);
+ Od2ProbeForRead(CommandBuffer, Length, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RetCode = DereferenceFileHandle(FileHandle, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+
+ NtFileHandle = hFileRecord->NtHandle;
+
+ CurrentCmd = (PUSHORT)CommandBuffer;
+ Key = (ULONG) Od2Process->Pib.ProcessId;
+
+ while ((PBYTE)CurrentCmd < (CommandBuffer + Length)) {
+ switch (*CurrentCmd) {
+ case FIO_LOCK:
+#if DBG
+ IF_OS2_DEBUG( FILESYS ) {
+ DbgPrint("DosFileIO: going to lock file %u time(s)\n", ((PFIOLOCKCMD16)CurrentCmd)->cLockCnt);
+ }
+#endif
+ Status = STATUS_SUCCESS;
+ pLock = (PFIOLOCKCMD16)CurrentCmd;
+ pLockRec = (PFIOLOCKREC16)(pLock + 1);
+ for (i = 0;
+ (i < pLock->cLockCnt) && NT_SUCCESS(Status);
+ i++, pLockRec++
+ ) {
+
+ //
+ // The usage of Key: A combination of KEY == NULL and EXCLUSIVE == TRUE
+ // in NtLockFile() let us NtReadFile()/NtWriteFile() on that
+ // region with KEY == NULL from the same process but not from
+ // another process. A combination of KEY == pid and EXCLUSIVE == FALSE
+ // in NtLockFile() let us NtReadFile() with KEY == NULL from every
+ // process, and doesn't let us NtWriteFile() with KEY == NULL from any
+ // process, incuding the owner of the locked region.
+ //
+
+ TmpLarge = RtlConvertUlongToLargeInteger(pLockRec->cbStart);
+ TmpLarge2 = RtlConvertUlongToLargeInteger(pLockRec->cbLength);
+ Status = NtLockFile(
+ NtFileHandle,
+ 0,
+ NULL,
+ NULL,
+ &IoStatus,
+ &TmpLarge,
+ &TmpLarge2,
+ ((pLockRec->fShare == FIO_NOSHARE) ? 0L : Key),
+ (BOOLEAN)((pLock->cTimeOut == 0) ? TRUE : FALSE),
+ (BOOLEAN)((pLockRec->fShare == FIO_NOSHARE) ? TRUE : FALSE)
+ );
+#if DBG
+ IF_OS2_DEBUG( FILESYS ) {
+ DbgPrint("DosFileIO: locked file from 0x%lX, length 0x%lX, exclusive %s\n",
+ pLockRec->cbStart, pLockRec->cbLength, ((pLockRec->fShare == FIO_NOSHARE) ?
+ "TRUE" : "FALSE"));
+ DbgPrint(" IoStatus.Status %u, Status %u\n", IoStatus.Status, Status);
+ }
+#endif
+ }
+ if (NT_SUCCESS(Status)) {
+ CurrentCmd = (PUSHORT)(pLock + 1);
+ CurrentCmd = (PUSHORT)((PBYTE)CurrentCmd + (pLock->cLockCnt * sizeof(FIOLOCKREC16)));
+ }
+ break;
+
+ case FIO_UNLOCK:
+#if DBG
+ IF_OS2_DEBUG( FILESYS ) {
+ DbgPrint("DosFileIO: going to unlock file %u time(s)\n", ((PFIOUNLOCKCMD16)CurrentCmd)->cUnlockCnt);
+ }
+#endif
+ Status = STATUS_SUCCESS;
+ pUnlock = (PFIOUNLOCKCMD16)CurrentCmd;
+ pUnlockRec = (PFIOUNLOCKREC16)(pUnlock + 1);
+ for (i = 0;
+ (i < pUnlock->cUnlockCnt) && NT_SUCCESS(Status);
+ i++, pUnlockRec++
+ ) {
+ TmpLarge = RtlConvertUlongToLargeInteger(pUnlockRec->cbStart);
+ TmpLarge2 = RtlConvertUlongToLargeInteger(pUnlockRec->cbLength);
+ Status = NtUnlockFile(
+ NtFileHandle,
+ &IoStatus,
+ &TmpLarge,
+ &TmpLarge2,
+ (ULONG) NULL // try it once with key == NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+ Status = NtUnlockFile(
+ NtFileHandle,
+ &IoStatus,
+ &TmpLarge,
+ &TmpLarge2,
+ Key // try it again with key == pid
+ );
+ }
+#if DBG
+ IF_OS2_DEBUG( FILESYS ) {
+ DbgPrint("DosFileIO: unlocked file from 0x%lX, length 0x%lX\n",
+ pUnlockRec->cbStart, pUnlockRec->cbLength);
+ DbgPrint(" IoStatus.Status %u, Status %u\n", IoStatus.Status, Status);
+ }
+#endif
+ }
+ if (NT_SUCCESS(Status)) {
+ CurrentCmd = (PUSHORT)(pUnlock + 1);
+ CurrentCmd = (PUSHORT)((PBYTE)CurrentCmd + (pUnlock->cUnlockCnt * sizeof(FIOUNLOCKREC16)));
+ }
+ break;
+
+ case FIO_SEEK:
+ Status = STATUS_SUCCESS;
+ pSeek = (PFIOSEEKCMD16)CurrentCmd;
+ switch (pSeek->fsMethod) {
+ case FILE_BEGIN:
+ FilePosition.CurrentByteOffset =
+ RtlConvertUlongToLargeInteger(pSeek->cbDistance);
+ break;
+
+ case FILE_CURRENT:
+ do {
+ Status = NtQueryInformationFile(
+ NtFileHandle,
+ &IoStatus,
+ &FilePosition,
+ sizeof(FILE_POSITION_INFORMATION),
+ FilePositionInformation);
+ } while (RetryIO(Status, NtFileHandle));
+ if (!NT_SUCCESS(Status)) {
+ break;
+ }
+ TmpLarge = RtlConvertUlongToLargeInteger(pSeek->cbDistance);
+ FilePosition.CurrentByteOffset = RtlLargeIntegerAdd(
+ FilePosition.CurrentByteOffset, TmpLarge);
+ break;
+
+ case FILE_END:
+ do {
+ Status = NtQueryInformationFile(
+ NtFileHandle,
+ &IoStatus,
+ &FileStandardInfo,
+ sizeof(FILE_STANDARD_INFORMATION),
+ FileStandardInformation);
+ } while (RetryIO(Status, NtFileHandle));
+ if (!NT_SUCCESS(Status)) {
+ break;
+ }
+ TmpLarge = RtlConvertUlongToLargeInteger(pSeek->cbDistance);
+ FilePosition.CurrentByteOffset = RtlLargeIntegerAdd(
+ FileStandardInfo.EndOfFile, TmpLarge);
+ break;
+ }
+ if (!NT_SUCCESS(Status)) {
+ break;
+ }
+ do {
+ Status = NtSetInformationFile(
+ NtFileHandle,
+ &IoStatus,
+ &FilePosition,
+ sizeof(FILE_POSITION_INFORMATION),
+ FilePositionInformation);
+ } while (RetryIO(Status, NtFileHandle));
+ if (NT_SUCCESS(Status)) {
+ pSeek->cbNewPosition = FilePosition.CurrentByteOffset.LowPart;
+ CurrentCmd = (PUSHORT)(pSeek + 1);
+#if DBG
+ IF_OS2_DEBUG( FILESYS ) {
+ DbgPrint("DosFileIO: seeked file - method %u , distance 0x%lX, new position 0x%lX\n",
+ pSeek->fsMethod, pSeek->cbDistance, pSeek->cbNewPosition);
+ DbgPrint(" IoStatus.Status %u, Status %u\n", IoStatus.Status, Status);
+ }
+#endif
+ }
+ break;
+
+ case FIO_READ:
+ pRW = (PFIOREADWRITE16)CurrentCmd;
+ do {
+ Status = NtReadFile(
+ NtFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ FARPTRTOFLAT(pRW->pbBuffer),
+ pRW->cbBufferLen,
+ NULL,
+ NULL
+ );
+ } while (RetryIO(Status, NtFileHandle));
+ if (NT_SUCCESS(Status)) {
+ pRW->cbActualLen = (USHORT)IoStatus.Information;
+ CurrentCmd = (PUSHORT)(pRW + 1);
+#if DBG
+ IF_OS2_DEBUG( FILESYS ) {
+ DbgPrint("DosFileIO: read %u bytes from file\n", pRW->cbActualLen);
+ }
+#endif
+ }
+#if DBG
+ else
+ IF_OS2_DEBUG( FILESYS ) {
+ DbgPrint("DosFileIO: unable to read file, status 0x%lX\n", Status);
+ }
+#endif
+ break;
+
+ case FIO_WRITE:
+ pRW = (PFIOREADWRITE16)CurrentCmd;
+ do {
+ Status = NtWriteFile(
+ NtFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ FARPTRTOFLAT(pRW->pbBuffer),
+ pRW->cbBufferLen,
+ NULL,
+ NULL
+ );
+ } while (RetryIO(Status, NtFileHandle));
+ if (NT_SUCCESS(Status)) {
+ pRW->cbActualLen = (USHORT)IoStatus.Information;
+ CurrentCmd = (PUSHORT)(pRW + 1);
+#if DBG
+ IF_OS2_DEBUG( FILESYS ) {
+ DbgPrint("DosFileIO: wrote %u bytes to file\n", pRW->cbActualLen);
+ }
+#endif
+ }
+ break;
+
+ default:
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ if (!NT_SUCCESS(Status)) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ *ErrorOffset = (USHORT)((PBYTE)CurrentCmd - CommandBuffer);
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
+ }
+ }
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ return (NO_ERROR);
+}
+
+APIRET
+DosQFileMode(
+ PSZ pszFName,
+ PUSHORT pusAttr,
+ ULONG ulReserved
+ )
+{
+ APIRET rc = NO_ERROR;
+ FILEFINDBUF4 PathInfoBuf;
+ PFILEFINDBUF4 pinfobuf;
+
+ UNREFERENCED_PARAMETER(ulReserved);
+
+
+ if (rc = DosQueryPathInfo ( pszFName, FIL_STANDARD,
+ (PBYTE) &PathInfoBuf, sizeof(PathInfoBuf))) {
+ return(rc == ERROR_INVALID_PATH ? ERROR_PATH_NOT_FOUND : rc);
+ }
+ //
+ // try to assign pusAttr
+ //
+
+ try {
+ pinfobuf = &PathInfoBuf;
+ (PUCHAR) pinfobuf -= 4;
+ *pusAttr = (USHORT)(pinfobuf->attrFile);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ return(NO_ERROR);
+}
+
+APIRET
+DosSetFileMode(
+ PSZ pszFName,
+ ULONG ulAttr,
+ ULONG ulReserved
+ )
+{
+ APIRET rc = NO_ERROR;
+ FILESTATUS PathInfoBuf;
+ UNREFERENCED_PARAMETER(ulReserved);
+
+
+ //
+ // take the simple check of valid attributes first
+ //
+
+ if ((ulAttr >= 8 && ulAttr < 0x20) || (ulAttr >= 0x28 && ulAttr < 0x100)) {
+ return(ERROR_ACCESS_DENIED);
+ }
+
+ if (rc = DosQueryPathInfo ( pszFName, FIL_STANDARD,
+ (PBYTE) &PathInfoBuf, sizeof(PathInfoBuf))) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DosSetFileMode: Error at DosQueryPathInfo, Status %d\n",
+ rc));
+ }
+#endif
+ return(rc);
+ }
+
+ PathInfoBuf.attrFile = ulAttr;
+
+ if (rc = DosSetPathInfo ( pszFName, FIL_STANDARD,
+ (PBYTE) &PathInfoBuf, sizeof(PathInfoBuf), 0)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DosSetFileMode: Error at DosSetPathInfo, Status %d\n",
+ rc));
+ }
+#endif
+ return(rc);
+ }
+ return(NO_ERROR);
+}
+
+APIRET
+Dos16DupHandle(
+ IN HFILE hfOld,
+ IN OUT PUSHORT phfNew
+ )
+{
+ HFILE hfNew;
+ APIRET Rc;
+
+ //
+ // Special casing 0xFFFF which means 'create new handle'
+ //
+
+ try {
+ Od2ProbeForWrite(phfNew, sizeof(USHORT), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ hfNew = (HFILE) *phfNew;
+
+ //
+ // Special casing 0xFFFF which means 'create new handle'
+ //
+
+ if (hfNew == (HFILE)0xFFFF)
+ hfNew = (HFILE)0xFFFFFFFF;
+ //
+ // Call Cruiser style function (dllhandl.c)
+ //
+
+ Rc = DosDupHandle(hfOld, &hfNew);
+
+ *phfNew = (USHORT) hfNew;
+
+ return (Rc);
+}
+
+
+VOID
+Od2AsyncReadThread(ULONG param)
+{
+
+ PASYNCREAD pAsync = (PASYNCREAD)param;
+ ULONG pcbBytesRead;
+ APIRET rc = DosRead(
+ pAsync->hf,
+ pAsync->pvBuf,
+ pAsync->cbBuf,
+ &pcbBytesRead);
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ if (rc != NO_ERROR){
+ KdPrint(("DosReadAsync: Od2AsyncReadThread Fails at DosRead, Error %d\n", rc));
+ }
+ }
+#endif
+ *(pAsync->pcbBytesRead) = (USHORT) pcbBytesRead;
+ *(pAsync->pusErrCode) = (USHORT)rc;
+
+ //
+ // wakeup the user thread, return error code
+ //
+ rc = DosSemClear(pAsync->hsemRam);
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ if (rc != NO_ERROR){
+ KdPrint(("DosReadAsync: Od2AsyncReadThread Fails at DosSemClear, Error %d\n", rc));
+ }
+ }
+#endif
+
+ RtlFreeHeap(Od2Heap, 0, pAsync);
+ DosExit( EXIT_THREAD, rc);
+}
+
+APIRET
+DosReadAsync(HFILE hf,
+ PULONG hsemRam,
+ PUSHORT pusErrCode,
+ PVOID pvBuf,
+ ULONG cbBuf,
+ PUSHORT pcbBytesRead)
+{
+ APIRET rc;
+ TID ThreadId;
+ PASYNCREAD pAsync;
+
+ try {
+ *pusErrCode = 0;
+ *pcbBytesRead = 0;
+ Od2ProbeForWrite(pvBuf, cbBuf, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ pAsync = RtlAllocateHeap( Od2Heap, 0, sizeof( *pAsync) );
+ if (pAsync == NULL) {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ //
+ // fill in values for async thread (this routine's stack will
+ // be over once thread is started)
+ //
+ pAsync->hf = hf;
+ pAsync->hsemRam = hsemRam;
+ pAsync->pusErrCode = pusErrCode;
+ pAsync->pvBuf = pvBuf;
+ pAsync->cbBuf = cbBuf;
+ pAsync->pcbBytesRead = pcbBytesRead;
+
+ rc = DosCreateThread(
+ &ThreadId,
+ (PFNTHREAD)Od2AsyncReadThread,
+ (ULONG) pAsync,
+ DCT_RUNABLE,
+ 1); // stack size 4k
+ if (rc != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DosReadAsync: Fail DosCreateThread, Error %d\n", rc));
+ }
+#endif
+ return(ERROR_NO_PROC_SLOTS);
+ }
+
+ return NO_ERROR;
+}
+
+VOID
+Od2AsyncWriteThread(ULONG param)
+{
+
+ PASYNCREAD pAsync = (PASYNCREAD)param;
+ ULONG pcbBytesWritten;
+ APIRET rc = DosWrite(
+ pAsync->hf,
+ pAsync->pvBuf,
+ pAsync->cbBuf,
+ &pcbBytesWritten);
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ if (rc != NO_ERROR){
+ KdPrint(("DosWriteAsync: Od2AsyncWriteThread Fails at DosWrite, Error %d\n", rc));
+ }
+ }
+#endif
+ *(pAsync->pcbBytesRead) = (USHORT) pcbBytesWritten;
+ *(pAsync->pusErrCode) = (USHORT)rc;
+
+ //
+ // wakeup the user thread, return error code
+ //
+ rc = DosSemClear(pAsync->hsemRam);
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ if (rc != NO_ERROR){
+ KdPrint(("DosWriteAsync: Od2AsyncWriteThread Fails at DosSemClear, Error %d\n", rc));
+ }
+ }
+#endif
+
+ RtlFreeHeap(Od2Heap, 0, pAsync);
+ DosExit( EXIT_THREAD, rc);
+}
+
+APIRET
+DosWriteAsync(HFILE hf,
+ PULONG hsemRam,
+ PUSHORT pusErrCode,
+ PVOID pvBuf,
+ ULONG cbBuf,
+ PUSHORT pcbBytesWritten)
+{
+ APIRET rc;
+ TID ThreadId;
+ PASYNCREAD pAsync;
+
+ try {
+ *pusErrCode = 0;
+ *pcbBytesWritten = 0;
+ Od2ProbeForWrite(pvBuf, cbBuf, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ pAsync = (PASYNCREAD)RtlAllocateHeap( Od2Heap, 0, sizeof( *pAsync) );
+ if (pAsync == NULL) {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ //
+ // fill in values for async thread (this routine's stack will
+ // be over once thread is started)
+ //
+ pAsync->hf = hf;
+ pAsync->hsemRam = hsemRam;
+ pAsync->pusErrCode = pusErrCode;
+ pAsync->pvBuf = pvBuf;
+ pAsync->cbBuf = cbBuf;
+ pAsync->pcbBytesRead = pcbBytesWritten;
+
+ rc = DosCreateThread(
+ &ThreadId,
+ (PFNTHREAD)Od2AsyncWriteThread,
+ (ULONG) pAsync,
+ DCT_RUNABLE,
+ 1); // stack size 4k
+ if (rc != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DosWriteAsync: Fail DosCreateThread, Error %d\n", rc));
+ }
+ return(ERROR_NO_PROC_SLOTS);
+#endif
+ }
+ return NO_ERROR;
+}
+
+APIRET
+DosFindNotifyClose(void)
+{
+#if DBG
+ KdPrint(("DosFindNotifyClose: Not Implemented Yet\n"));
+#endif
+ return NO_ERROR;
+}
+
+APIRET
+DosFindNotifyFirst(void)
+{
+#if DBG
+ KdPrint(("DosFindNotifyFirst: Not Implemented Yet\n"));
+#endif
+ return NO_ERROR;
+}
+
+APIRET
+DosFindNotifyNext(void)
+{
+#if DBG
+ KdPrint(("DosFindNotifyNext: Not Implemented Yet\n"));
+#endif
+ return NO_ERROR;
+}
+
+APIRET
+Dos16QFSAttach(
+ IN PSZ pszDev,
+ IN ULONG usOrdinal,
+ IN ULONG usInfoLevel,
+ OUT PBYTE pFSAttBuf,
+ IN OUT PUSHORT pcbAttBuf,
+ IN ULONG ulReserved)
+{
+ USHORT tmp_cbName, tmp_cbFSDName, tmp_cbFSAData;
+ APIRET rc;
+ ULONG AttBuf;
+
+ if (ulReserved != 0L)
+ {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ try {
+ Od2ProbeForWrite(pcbAttBuf, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ AttBuf = (ULONG) *pcbAttBuf;
+
+ rc = DosQueryFSAttach(
+ pszDev,
+ usOrdinal,
+ usInfoLevel,
+ pFSAttBuf,
+ &AttBuf
+ );
+
+ *pcbAttBuf = (USHORT) AttBuf;
+
+ if (rc)
+ {
+#if DBG
+ IF_OD2_DEBUG(FILESYS)
+ {
+ KdPrint(("Dos16QFSAttach: Error at DosQueryFSAttach, Status %d\n",
+ rc));
+ }
+#endif
+ return(rc);
+ }
+
+ tmp_cbName = *(PUSHORT)(pFSAttBuf + sizeof(USHORT));
+ tmp_cbFSDName = *(PUSHORT)(pFSAttBuf + sizeof(USHORT)*2);
+ tmp_cbFSAData = *(PUSHORT)(pFSAttBuf + sizeof(USHORT)*3);
+
+ /* Move szName */
+ strncpy (pFSAttBuf + sizeof(USHORT)*2, /* dst addr in OS/2 1.x struct */
+ pFSAttBuf + sizeof(USHORT)*4, /* src addr in OS/2 2.0 struct */
+ tmp_cbName + 1 /* Length */ );
+
+ /* Set cbFSDName */
+ *(PUSHORT)(pFSAttBuf + sizeof(USHORT)*2 + tmp_cbName + 1) =
+ tmp_cbFSDName;
+ /* Move szFSDName */
+ strncpy (pFSAttBuf + sizeof(USHORT)*2
+ + tmp_cbName + 1
+ + sizeof(USHORT), /* dst addr in OS/2 1.x struct */
+ pFSAttBuf + sizeof(USHORT)*4
+ + tmp_cbName +1, /* src addr in OS/2 2.0 struct */
+ tmp_cbFSDName + 1 /* Length */ );
+
+ /* Set cbFSAData */
+ *(PUSHORT)(pFSAttBuf + sizeof(USHORT)*2 + tmp_cbName + 1
+ + sizeof(USHORT) + tmp_cbFSDName + 1) = tmp_cbFSAData;
+ /* Move rgFSAData */
+ strncpy (pFSAttBuf + sizeof(USHORT)*2
+ + tmp_cbName + 1
+ + sizeof(USHORT)
+ + tmp_cbFSDName + 1
+ + sizeof(USHORT), /* dst addr in OS/2 1.x struct */
+ pFSAttBuf + sizeof(USHORT)*4
+ + tmp_cbName + 1
+ + tmp_cbFSDName + 1, /* src addr in OS/2 2.0 struct */
+ tmp_cbFSAData + 1 /* Length */ );
+
+ return(NO_ERROR);
+}
+
+/*++
+
+Routine description:
+
+ Computes the size (including the cbList field) needed to convert a given
+ OS/2 1.x FEA list into a Cruiser FEA2 list.
+ Also returns the number of entries in the FEA list.
+
+Parameters:
+
+ pfealist -
+ Pointer to the source OS/2 1.x style FEA list.
+ psize_FEA2 -
+ Pointer to variable to receive the resulting FEA2 list size.
+ pnum_FEAs -
+ Pointer to variable to receive the number of FEA entries. If NULL, the
+ number won't be returned.
+
+Return value:
+
+ NO_ERROR -
+ All is well.
+ ERROR_EA_LIST_INCONSISTENT -
+ Bad supplied OS/2 1.x FEA list. Also covers the case of invalid pointer.
+
+--*/
+
+ULONG
+Od2SizeFEA2ListFromFEAList(
+ IN PFEALIST fpFEAList,
+ OUT PULONG psize_FEA2,
+ OUT PULONG pnum_FEAs)
+{
+ ULONG FEA_list_len, FEA2_total_size;
+ ULONG num_FEAs, FEA_offset;
+ PFEA pFEA;
+
+ try
+ {
+ /* Validate that FEA list can be accessed according to its own advertised
+ length */
+ Od2ProbeForRead(fpFEAList, fpFEAList->cbList, 1);
+
+ /* We need now to compute how many FEA's we have and at the same time
+ compute how much memory we need to allocate for the new style FEA list. */
+ FEA_list_len = fpFEAList->cbList - sizeof(ULONG);
+
+ for (num_FEAs=FEA_offset=0, FEA2_total_size=sizeof(ULONG);
+ FEA_offset < FEA_list_len;
+ num_FEAs++)
+ {
+ pFEA = (PFEA)
+ ( (PBYTE)&(fpFEAList->list[0]) +
+ FEA_offset );
+ FEA_offset += sizeof(FEA) + pFEA->cbName + 1 + pFEA->cbValue;
+ FEA2_total_size += sizeof(ULONG) /* .oNextEntryOffset */
+ + sizeof(BYTE) /* .fEA */
+ + sizeof(BYTE) /* .cbName */
+ + sizeof(USHORT) /* .cbValue */
+ + pFEA->cbName + 1
+ + pFEA->cbValue;
+ /* Round FEA2_total_size up to ULONG boundary, as specified in the
+ NT EA structure */
+ if (FEA_offset < FEA_list_len) /* Not last entry */
+ FEA2_total_size = (FEA2_total_size + sizeof(ULONG) - 1) &
+ ~(sizeof(ULONG) - 1);
+ }
+ //Here FEA_offset should be exactly equal to FEA_list_len
+ if (FEA_offset != FEA_list_len)
+ return (ERROR_EA_LIST_INCONSISTENT);
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ Od2ExitGP();
+ }
+
+// /* BUGBUG - Is the case below really inconsistent ? Check on OS/2 */
+// if (num_FEAs == 0)
+// {
+// return ERROR_EA_LIST_INCONSISTENT;
+// }
+
+ if (psize_FEA2 != NULL)
+ *psize_FEA2 = FEA2_total_size;
+ if (pnum_FEAs != NULL)
+ *pnum_FEAs = num_FEAs;
+
+ return NO_ERROR;
+}
+
+/*++
+
+Routine description:
+
+ Computes the size (including
+ the cbList field) needed to convert a given
+ OS/2 1.x GEA list into a Cruiser GEA2 list.
+ Also returns the number of entries in the GEA list.
+
+Parameters:
+
+ pgealist -
+ Pointer to the source OS/2 1.x style GEA list.
+ psize_GEA2 -
+ Pointer to variable to receive the resulting GEA2 list size.
+ pnum_GEAs -
+ Pointer to variable to receive the number of GEA entries. If NULL, the
+ number won't be returned.
+
+Return value:
+
+ NO_ERROR -
+ All is well.
+ ERROR_EA_LIST_INCONSISTENT -
+ Bad supplied OS/2 1.x GEA list. Also covers the case of invalid pointer.
+
+--*/
+
+ULONG
+Od2SizeGEA2ListFromGEAList(
+ IN PGEALIST fpGEAList,
+ OUT PULONG psize_GEA2,
+ OUT PULONG pnum_GEAs)
+{
+ ULONG GEA_list_len, GEA2_total_size;
+ ULONG num_GEAs, GEA_offset;
+ PGEA pGEA;
+
+ try
+ {
+ /* Validate that GEA list can be accessed according to its own advertised
+ length */
+ Od2ProbeForRead(fpGEAList, fpGEAList->cbList, 1);
+
+ /* We need now to compute how many GEA's we have and at the same time
+ compute how much memory we need to allocate for the new style GEA list. */
+ GEA_list_len = fpGEAList->cbList - sizeof(ULONG);
+
+ for (num_GEAs=GEA_offset=0, GEA2_total_size=sizeof(ULONG);
+ GEA_offset < GEA_list_len;
+ num_GEAs++)
+ {
+ pGEA = (PGEA)
+ ( (PBYTE)&(fpGEAList->list[0]) +
+ GEA_offset );
+ if (pGEA->cbName == 0)
+ return ERROR_EA_LIST_INCONSISTENT;
+ GEA_offset += sizeof(BYTE)
+ + pGEA->cbName + 1;
+ GEA2_total_size += sizeof(ULONG) /* .oNextEntryOffset */
+ + sizeof(BYTE) /* .cbName */
+ + pGEA->cbName + 1;
+ /* Round GEA2_total_size up to ULONG boundary, as specified in the
+ NT EA structure */
+ if (GEA_offset < GEA_list_len) /* Not last entry */
+ GEA2_total_size = (GEA2_total_size + sizeof(ULONG) - 1) &
+ ~(sizeof(ULONG) - 1);
+ }
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ Od2ExitGP();
+ }
+
+ /* BUGBUG - Is the case below really inconsistent ? Check on OS/2 */
+ if (num_GEAs == 0)
+ {
+ return ERROR_EA_LIST_INCONSISTENT;
+ }
+
+ if (GEA_offset > GEA_list_len)
+ {
+ return ERROR_EA_LIST_INCONSISTENT;
+ }
+
+ if (psize_GEA2 != NULL)
+ *psize_GEA2 = GEA2_total_size;
+ if (pnum_GEAs != NULL)
+ *pnum_GEAs = num_GEAs;
+
+ return NO_ERROR;
+}
+
+ULONG
+Od2SizeFEAListFromFEA2List(
+ IN PFEA2LIST fpFEA2List,
+ OUT PULONG psize_FEA OPTIONAL,
+ OUT PULONG pnum_FEAs OPTIONAL)
+{
+ ULONG FEA2_list_len, FEA_total_size;
+ ULONG num_FEAs;
+ PFEA2 pFEA2;
+
+ try
+ {
+ /* Validate that FEA2 list can be accessed according to its own advertised
+ length */
+ Od2ProbeForRead(fpFEA2List, fpFEA2List->cbList, 1);
+
+ /* We need now to compute how many FEA's we have and at the same time
+ compute how much memory we need to allocate for the old style FEA list. */
+ FEA2_list_len = fpFEA2List->cbList - sizeof(ULONG);
+
+ num_FEAs = 0;
+ pFEA2 = &(fpFEA2List->list[0]);
+ FEA_total_size = sizeof(ULONG);
+
+ while (1)
+ {
+ FEA_total_size += sizeof(BYTE)*2
+ + sizeof(USHORT)
+ + pFEA2->cbName + 1
+ + pFEA2->cbValue;
+ num_FEAs++;
+
+ if (pFEA2->oNextEntryOffset != 0)
+ {
+ pFEA2 = (FEA2 *)
+ ( (PBYTE)pFEA2
+ + pFEA2->oNextEntryOffset );
+ }
+ else
+ break; /* End of FEA2 list */
+ }
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ Od2ExitGP();
+ }
+
+ /* BUGBUG - Is the case below really inconsistent ? Check on OS/2 */
+ if (num_FEAs == 0)
+ {
+ return ERROR_EA_LIST_INCONSISTENT;
+ }
+
+ if (psize_FEA != NULL)
+ *psize_FEA = FEA_total_size;
+ if (pnum_FEAs != NULL)
+ *pnum_FEAs = num_FEAs;
+
+ return NO_ERROR;
+}
+
+/*++
+
+Routine description:
+
+ Translate an OS/2 1.x FEA list into a Cruiser FEA2 list. Allocates space for
+ the target buffer if needed. No allocation is made in the case of an error
+ return. Translate attribute names to uppercase, like OS/2 1.x
+
+Parameters:
+
+ ppfea2list -
+ Points to a buffer which is to contain the pointer to the resulting FEA2
+ list. If the fea2list_length paramter is 0, then memory will be allocated for
+ the list.
+ Otherwise, The fea2list_length parameter indicates its size (ERROR_BUFFER_OVERFLOW
+ may be returned if the size specified is too small).
+ fea2list_length -
+ Length of the supplied FEA2 list buffer. Use 0 to request dynamic allocation
+ of the list.
+ pfealist -
+ Pointer to the source OS/2 1.x style FEA list.
+
+Return value:
+
+ NO_ERROR -
+ All is well.
+ ERROR_BUFFER_OVERFLOW -
+ Supplied target buffer is too small.
+ ERROR_EA_LIST_INCONSISTENT -
+ Bad supplied OS/2 1.x FEA list. Also covers the case of invalid pointer.
+
+--*/
+
+APIRET
+Od2ConvertFEAtoFEA2(
+ OUT PFEA2LIST *ppfea2list,
+ IN ULONG fea2list_length,
+ IN PFEALIST fpFEAList)
+{
+ ULONG FEA2_total_size;
+ ULONG num_FEAs, i;
+ PFEA pFEA;
+ PFEA2 pFEA2;
+ PFEA2LIST fpFEA2List;
+ BOOLEAN allocated_here = FALSE;
+
+ if (Od2SizeFEA2ListFromFEAList(fpFEAList, &FEA2_total_size, &num_FEAs) !=
+ NO_ERROR)
+ {
+ return ERROR_EA_LIST_INCONSISTENT;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Computed num_FEAs=%d\n", num_FEAs));
+ }
+#endif
+
+ /* Translate the OS/2 1.x FEA list into a Cruiser FEA2 list */
+
+ if (fea2list_length == 0)
+ {
+ /* Allocate space for the new FEA2 list */
+ allocated_here = TRUE;
+ /* Note that we rely here on the Rtl allocation code to return 4-bytes
+ aligned addresses (it does to 16) */
+ fpFEA2List = (PFEA2LIST)RtlAllocateHeap(
+ Od2Heap, 0,
+ FEA2_total_size
+ );
+ if (fpFEA2List == NULL) {
+#if DBG
+ KdPrint(( "OS2: Od2ConvertFEAtoFEA2, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+ else
+ {
+ if (fea2list_length < FEA2_total_size)
+ return ERROR_BUFFER_OVERFLOW;
+ else
+ fpFEA2List = *ppfea2list;
+ }
+
+ /* Copy the whole list to new format */
+
+ fpFEA2List->cbList = FEA2_total_size;
+
+ try
+ {
+ for (i=0, pFEA2=&(fpFEA2List->list[0]),
+ pFEA=&(fpFEAList->list[0]);
+ i<num_FEAs;
+ i++)
+ {
+ /* 0 and FEA_NEEDEA are allowed. Note that Cruiser code will
+ * also return an error if we just copy the supplied .fEA but
+ * it returns ERROR_INVALID_EA_NAME while OS/2 1.x expects
+ * ERROR_EA_LIST_INCONSISTENT.
+ */
+ if ((pFEA->fEA != 0) &&
+ (pFEA->fEA != FEA_NEEDEA))
+ {
+ if (allocated_here)
+ RtlFreeHeap(Od2Heap, 0, fpFEA2List);
+
+ return ERROR_EA_LIST_INCONSISTENT;
+ }
+ pFEA2->fEA = pFEA->fEA;
+ pFEA2->cbName = pFEA->cbName;
+ pFEA2->cbValue = pFEA->cbValue;
+ /* Copy name */
+ strcpy(pFEA2->szName, (char *)pFEA + sizeof(FEA));
+ /* For OS/2 1.x compatibility */
+ _strupr(pFEA2->szName);
+ /* Copy data */
+ memcpy((char *)(pFEA2->szName) + pFEA2->cbName + 1,
+ (char *)pFEA + sizeof(FEA) + pFEA->cbName + 1,
+ pFEA->cbValue);
+
+ if (i < (num_FEAs-1)) /* Not last entry */
+ {
+ /* Warning: Do NOT use 'sizeof(FEA2)'. This yields 12 instead of 9
+ because the structure is rounded-up to ULONG alignment */
+ pFEA2->oNextEntryOffset = pFEA2->cbName + 1 + pFEA2->cbValue
+ + sizeof(ULONG) /* oNextEntryOffset */
+ + sizeof(BYTE)*2 /* fEA & cbName */
+ + sizeof(USHORT); /* cbValue */
+
+ /* Align pFEA2->oNextEntryOffset to 4-bytes boundary */
+ pFEA2->oNextEntryOffset =
+ (pFEA2->oNextEntryOffset + sizeof(ULONG) - 1) &
+ ~(sizeof(ULONG) - 1);
+ }
+ else
+ pFEA2->oNextEntryOffset = 0; /* Last entry */
+
+ if (i < (num_FEAs-1)) /* Not last entry */
+ {
+ /* Advance both pointers */
+ pFEA2 = (PFEA2)
+ ((PBYTE)pFEA2 + pFEA2->oNextEntryOffset);
+ pFEA = (PFEA)
+ ((PBYTE)pFEA + sizeof(FEA) + pFEA->cbName + 1 +
+ pFEA->cbValue);
+ }
+ }
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (allocated_here)
+ RtlFreeHeap(Od2Heap, 0, fpFEA2List);
+
+ return ERROR_EA_LIST_INCONSISTENT;
+ }
+
+ *ppfea2list = fpFEA2List; /* Return FEA2 list */
+
+ return NO_ERROR;
+}
+
+/*++
+
+Routine description:
+
+ Translate an OS/2 1.x GEA list into a Cruiser GEA2 list. Allocates space for
+ the target buffer if needed. No allocation is made in the case of an error
+ return. Convert attribute names to uppercase for OS/2 1.x compatibility.
+
+Parameters:
+
+ ppgea2list -
+ Points to a buffer which is to contain the pointer to the resulting GEA2
+ list. If the gea2list_length paramter is 0, then memory will be allocated for
+ the list.
+ Otherwise, The gea2list_length parameter indicates its size (ERROR_BUFFER_OVERFLOW
+ may be returned if the size specified is too small).
+ gea2list_length -
+ Length of the supplied GEA2 list buffer. Use 0 to request dynamic allocation
+ of the list.
+ pgealist -
+ Pointer to the source OS/2 1.x style GEA list.
+
+Return value:
+
+ NO_ERROR -
+ All is well.
+ ERROR_BUFFER_OVERFLOW -
+ Supplied target buffer is too small.
+ ERROR_EA_LIST_INCONSISTENT -
+ Bad supplied OS/2 1.x GEA list. Also covers the case of invalid pointer.
+
+--*/
+
+APIRET
+Od2ConvertGEAtoGEA2(
+ IN PGEA2LIST *ppgea2list,
+ IN ULONG gea2list_length,
+ IN PGEALIST fpGEAList)
+{
+ ULONG GEA2_total_size;
+ ULONG num_GEAs, i;
+ PGEA pGEA;
+ PGEA2 pGEA2;
+ PGEA2LIST fpGEA2List;
+ BOOLEAN allocated_here = FALSE;
+ APIRET ret;
+
+ ret = Od2SizeGEA2ListFromGEAList(fpGEAList, &GEA2_total_size, &num_GEAs);
+ if (ret != NO_ERROR)
+ {
+ return ret;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Computed num_GEAs=%d\n", num_GEAs));
+ }
+#endif
+
+ /* Translate the OS/2 1.x GEA list into a Cruiser GEA2 list */
+
+ if (gea2list_length == 0)
+ {
+ /* Allocate space for the new GEA2 list */
+ allocated_here = TRUE;
+ /* Note that we rely here on the Rtl allocation code to return 4-bytes
+ aligned addresses (it does to 16) */
+ fpGEA2List = (PGEA2LIST)RtlAllocateHeap(
+ Od2Heap, 0,
+ GEA2_total_size
+ );
+ if (fpGEA2List == NULL) {
+#if DBG
+ KdPrint(( "OS2: Od2ConvertGEAtoGEA2, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+ else
+ {
+ if (gea2list_length < GEA2_total_size)
+ return ERROR_BUFFER_OVERFLOW;
+ else
+ fpGEA2List = *ppgea2list;
+ }
+
+ /* Copy the whole list to new format */
+
+ fpGEA2List->cbList = GEA2_total_size;
+
+ try
+ {
+ for (i=0, pGEA2=&(fpGEA2List->list[0]),
+ pGEA=&(fpGEAList->list[0]);
+ i<num_GEAs;
+ i++)
+ {
+ pGEA2->cbName = pGEA->cbName;
+ /* Copy name */
+ strcpy(pGEA2->szName, pGEA->szName);
+ /* For OS/2 1.x compatibility */
+ _strupr(pGEA2->szName);
+
+ if (i < (num_GEAs-1)) /* Not last entry */
+ {
+ pGEA2->oNextEntryOffset = pGEA2->cbName + 1
+ + sizeof(ULONG) /* oNextEntryOffset */
+ + sizeof(BYTE); /* cbName */
+
+ /* Align pGEA2->oNextEntryOffset to 4-bytes boundary */
+
+ pGEA2->oNextEntryOffset =
+ (pGEA2->oNextEntryOffset + sizeof(ULONG) - 1) &
+ ~(sizeof(ULONG) - 1);
+ }
+ else
+ pGEA2->oNextEntryOffset = 0; /* Last entry */
+
+ if (i < (num_GEAs-1)) /* Not last entry */
+ {
+ /* Advance both pointers */
+ pGEA2 = (PGEA2)
+ ((PBYTE)pGEA2 + pGEA2->oNextEntryOffset);
+ pGEA = (PGEA)
+ ((PBYTE)pGEA
+ + sizeof(BYTE)
+ + pGEA->cbName + 1);
+ }
+ }
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (allocated_here)
+ RtlFreeHeap(Od2Heap, 0, fpGEA2List);
+
+ Od2ExitGP();
+ }
+
+ *ppgea2list = fpGEA2List; /* Return GEA2 list */
+
+ return NO_ERROR;
+}
+
+
+/*++
+
+Routine description:
+
+ Translate a Cruiser FEA2 list into an OS/2 1.x FEA list. Allocates space for
+ the target buffer if needed. No allocation is made in the case of an error
+ return.
+ Translates all attributes names to uppercase, just as OS/2 1.x does.
+
+Parameters:
+
+ ppfealist -
+ Points to a buffer which is to contain the pointer to the resulting FEA
+ list. If the fealist_length paramter is 0, then memory will be allocated for
+ the list.
+ Otherwise, The fealist_length parameter indicates its size (ERROR_BUFFER_OVERFLOW
+ may be returned if the size specified is too small).
+ fealist_length -
+ Length of the supplied FEA list buffer. Use 0 to request dynamic allocation
+ of the list.
+ pfea2list -
+ Pointer to the source Cruiser style FEA2 list.
+
+Return value:
+
+ NO_ERROR -
+ All is well.
+ ERROR_BUFFER_OVERFLOW -
+ Supplied target buffer is too small.
+ ERROR_EA_LIST_INCONSISTENT -
+ Bad supplied Cruiser FEA2 list. Also covers the case of invalid pointer.
+
+--*/
+
+
+APIRET
+Od2ConvertFEA2toFEA(
+ IN PFEALIST *ppfealist,
+ IN ULONG fealist_length,
+ IN PFEA2LIST fpFEA2List)
+{
+ ULONG FEA_total_size;
+ ULONG num_FEAs, i;
+ PFEA pFEA;
+ PFEA2 pFEA2;
+ PFEALIST fpFEAList;
+ BOOLEAN allocated_here = FALSE;
+
+ if (Od2SizeFEAListFromFEA2List(fpFEA2List, &FEA_total_size, &num_FEAs) !=
+ NO_ERROR)
+ {
+ return ERROR_EA_LIST_INCONSISTENT;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Computed num_FEA2s=%d\n", num_FEAs));
+ }
+#endif
+
+ /* Translate the Cruiser FEA2 list into an OS/2 1.x FEA list */
+
+ if (fealist_length == 0)
+ {
+ /* Allocate space for the new FEA list */
+ allocated_here = TRUE;
+ fpFEAList = (PFEALIST)RtlAllocateHeap(
+ Od2Heap, 0,
+ FEA_total_size
+ );
+ if (fpFEAList == NULL) {
+#if DBG
+ KdPrint(( "OS2: Od2ConvertFEA2toFEA, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+ else
+ {
+ if (fealist_length < FEA_total_size)
+ return ERROR_BUFFER_OVERFLOW;
+ else
+ fpFEAList = *ppfealist;
+ }
+
+ /* Copy the whole list to new format */
+
+ fpFEAList->cbList = FEA_total_size;
+
+ try
+ {
+ for (i=0, pFEA=&(fpFEAList->list[0]),
+ pFEA2=&(fpFEA2List->list[0]);
+ i<num_FEAs;
+ i++)
+ {
+ pFEA->cbName = pFEA2->cbName;
+ pFEA->cbValue = pFEA2->cbValue;
+ pFEA->fEA = pFEA2->fEA;
+ /* Copy name */
+ strcpy((char *)pFEA + sizeof(FEA),
+ pFEA2->szName);
+ /* Convert to uppercase, for OS/2 1.x compatibility */
+ _strupr((char *)pFEA + sizeof(FEA));
+ /* Copy data */
+ memcpy((char *)pFEA + sizeof(FEA) + pFEA->cbName + 1,
+ (char *)(pFEA2->szName) + pFEA2->cbName + 1,
+ pFEA2->cbValue);
+
+ if (i < (num_FEAs-1)) /* Not last entry */
+ {
+ /* Advance both pointers */
+ pFEA2 = (PFEA2)
+ ((PBYTE)pFEA2 + pFEA2->oNextEntryOffset);
+ pFEA = (PFEA)
+ ((PBYTE)pFEA + sizeof(FEA) + pFEA->cbName + 1 +
+ pFEA->cbValue);
+ }
+ }
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (allocated_here)
+ RtlFreeHeap(Od2Heap, 0, fpFEAList);
+
+ Od2ExitGP();
+ }
+
+ *ppfealist = fpFEAList; /* Return FEA list */
+
+ return NO_ERROR;
+}
+
+/*++
+
+Routine description:
+
+ Translate a Cruiser DENA1 list into an OS/2 1.x DENA1_16 list. The target
+ buffer must have been previously allocated and it's size should be indicated.
+ Note that it is OK not to be able to store all the DENA1 list into the target
+ buffer.
+ Translates all attributes names to uppercase, just as OS/2 1.x does.
+
+Parameters:
+
+ pdena1_16_list -
+ Points to a buffer which is to contain the the resulting DENA1_16 list.
+ The dena_16_length parameter indicates its size.
+ pnum_entries -
+ Pointer to variable to store the number of DENA1_16 entries stored into the
+ resulting DENA1_16 list.
+ dena_16_length -
+ Length of the supplied DENA1 buffer.
+ pdena1_list -
+ Pointer to the source Cruiser DENA1 list.
+
+Return value:
+
+ NO_ERROR -
+ All is well.
+
+--*/
+
+
+APIRET
+Od2ConvertCruiserDena1ListtoDena1List16(
+ OUT PVOID pdena1_16_list,
+ OUT PULONG pnum_entries,
+ IN ULONG dena_16_length,
+ IN PVOID pdena1_list)
+{
+ DENA1 *pdena1;
+ DENA1_16 *pdena1_16;
+ ULONG new_entry_size, total_dena1_16_size;
+ ULONG number_converted;
+
+ pdena1 = (DENA1 *)pdena1_list;
+ pdena1_16 = (DENA1_16 *)pdena1_16_list;
+ *pnum_entries = 0;
+ total_dena1_16_size = 0;
+ number_converted = 0;
+
+ /* Not really an endless loop - see 'break's below */
+ while (1)
+ {
+ new_entry_size = FIELD_OFFSET(DENA1_16, szName) + pdena1->cbName + 1;
+
+ if ((total_dena1_16_size + new_entry_size) <= dena_16_length)
+ {
+ total_dena1_16_size += new_entry_size;
+ (*pnum_entries)++;
+ pdena1_16->reserved = 0; /* Reserved */
+ pdena1_16->cbName = pdena1->cbName;
+ pdena1_16->cbValue = pdena1->cbValue;
+ strcpy(pdena1_16->szName,
+ pdena1->szName);
+ /* For OS/2 1.x compatibility */
+ _strupr(pdena1_16->szName);
+
+ number_converted++;
+ if (pdena1->oNextEntryOffset != 0)
+ {
+ pdena1_16 = (DENA1_16 *) ((PBYTE)pdena1_16 + new_entry_size);
+ pdena1 = (DENA1 *) ((PBYTE)pdena1 + pdena1->oNextEntryOffset);
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ //
+ // if there is no conversion from DENA1 to DENA1_16, return
+ // ERROR_BUFFER_OVERFLOW.
+ //
+
+ if (number_converted == 0) {
+ return ERROR_BUFFER_OVERFLOW;
+ } else {
+ return NO_ERROR;
+ }
+}
+
+APIRET
+Od2ConvertDENA1ListToGEAList(
+ GEALIST *pGEAList,
+ DENA1_16 *denap,
+ ULONG count)
+{
+ ULONG GEA_list_len = pGEAList->cbList - sizeof(ULONG);
+ ULONG GEA_list_offset = 0;
+ GEA *GEA_ptr;
+
+ try
+ {
+ while ( count-- > 0)
+ {
+ if (GEA_list_offset >= GEA_list_len)
+ return ERROR_BUFFER_OVERFLOW;
+ GEA_ptr = (GEA *)
+ ((ULONG)&pGEAList->list[0]
+ + GEA_list_offset);
+ if ((GEA_list_offset + FIELD_OFFSET(GEA, szName)) > GEA_list_len)
+ return ERROR_BUFFER_OVERFLOW;
+ GEA_ptr->cbName = denap->cbName;
+ if ((GEA_list_offset
+ + FIELD_OFFSET(GEA, szName)
+ + denap->cbName + 1) > GEA_list_len)
+ return ERROR_BUFFER_OVERFLOW;
+ strcpy(GEA_ptr->szName, denap->szName);
+
+ denap = (DENA1_16 *)((ULONG)denap
+ + FIELD_OFFSET(DENA1_16, szName)
+ + denap->cbName + 1);
+ GEA_list_offset += (FIELD_OFFSET(GEA, szName)
+ + GEA_ptr->cbName + 1);
+ }
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ return ERROR_BUFFER_OVERFLOW;
+ }
+
+ pGEAList->cbList = GEA_list_offset + sizeof(ULONG);
+
+ return NO_ERROR;
+}
+
+
+/*++
+
+Routine description:
+
+ Assumes all parameters are valid. Sets the target FEA list based on a source
+ GEA2 list. Sets all .cbValue's to 0 (no data available).
+ Performs no allocation of the target buffer.
+ Translates all attributes names to uppercase, just as OS/2 1.x does.
+ Also, sets all .fEA fields to 0, like OS/2 1.x in case of an empty FEA list.
+
+Return value:
+
+ NO_ERROR
+
+--*/
+
+APIRET
+Od2SetEmptyFEAListfromGEA2List(
+ FEALIST *fpFEAList, /* Target */
+ GEA2LIST *fpGEA2List)
+{
+ GEA2 *pGEA2;
+ FEA *pFEA;
+ BYTE *pbyte;
+ ULONG total_FEA_size;
+
+ pGEA2 = &(fpGEA2List->list[0]);
+ pbyte = (PBYTE)fpFEAList;
+ total_FEA_size = sizeof(ULONG);
+ pFEA = (FEA *) ( pbyte + total_FEA_size );
+
+ while (1)
+ {
+ pFEA->fEA = 0;
+ pFEA->cbName = pGEA2->cbName;
+ pFEA->cbValue = 0;
+ strcpy((PBYTE)pFEA + sizeof(FEA),
+ pGEA2->szName);
+ /* For OS/2 1.x compatibility */
+ _strupr((PBYTE)pFEA + sizeof(FEA));
+
+ total_FEA_size += sizeof(FEA) + pFEA->cbName + 1;
+
+ if (pGEA2->oNextEntryOffset != 0)
+ {
+ pGEA2 = (GEA2 *)( (PBYTE)pGEA2 + pGEA2->oNextEntryOffset );
+ pFEA = (FEA *) ( pbyte + total_FEA_size );
+ }
+ else
+ break; /* End of GEA2 list */
+ }
+
+ fpFEAList->cbList = total_FEA_size;
+
+ return NO_ERROR;
+}
+
+APIRET
+Dos16MkDir(
+ IN PSZ DirName,
+ IN ULONG ulReserved)
+{
+ if (ulReserved != 0)
+ return ERROR_INVALID_PARAMETER;
+
+ return DosCreateDir(DirName, NULL);
+}
+
+APIRET
+Dos16MkDir2(
+ IN PSZ DirName,
+ IN OUT PEAOP pEAOP,
+ IN ULONG ulReserved)
+{
+ APIRET rc;
+ EAOP2 eaop2;
+
+ /* BUGBUG - Disallow EA with total size > 64K */
+
+ if (ulReserved != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (pEAOP == NULL) /* No EA's */
+ {
+ return (DosCreateDir(DirName, NULL));
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pEAOP, sizeof(EAOP), 1);
+ }
+ except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ rc = Od2ConvertFEAtoFEA2(
+ &(eaop2.fpFEA2List),
+ 0, /* To request allocation of the memory for the list */
+ FARPTRTOFLAT(pEAOP->fpFEAList));
+ /* Note that we don't do anything with the fpGEAList field since this
+ list is ignored */
+
+ if (rc != NO_ERROR)
+ return (ERROR_EA_LIST_INCONSISTENT);
+
+ rc = DosCreateDir(DirName,
+ &eaop2);
+
+ if (rc != 0)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16MkDir2: Error at DosCreateDir, rc = %d\n",
+ rc));
+ }
+#endif
+ /* BUGBUG - The error code returned would be irrelevant to the
+ OS/2 1.x EA list so better return 0. Converting the Error
+ position now would be tricky, considering the list is
+ inconsistent. In the future, best is to check the OS/2 1.x
+ EA list thoroughly before calling DosCreateDir */
+ pEAOP->oError = 0;
+ }
+
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpFEA2List);
+
+ return rc;
+}
+
+
+APIRET
+Dos16Open2(
+ IN PSZ pszFname,
+ OUT PUSHORT phf,
+ OUT PUSHORT pusAction,
+ IN ULONG ulFSize,
+ IN ULONG ulAttr,
+ IN ULONG ulOpenFlags,
+ IN ULONG fsOpenMode,
+ IN OUT PEAOP pEAOP OPTIONAL,
+ IN ULONG ulReserved)
+{
+ APIRET rc;
+ EAOP2 eaop2;
+ ULONG Action;
+ HFILE hf;
+
+ /* BUGBUG - Disallow EA with total size > 64K */
+
+ if (ulReserved != 0)
+ return ERROR_INVALID_PARAMETER;
+
+ try
+ {
+ Od2ProbeForWrite(phf, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pusAction, sizeof(USHORT), 1);
+ }
+ except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ hf = (HFILE) *phf;
+ Action = *pusAction;
+
+ if (pEAOP == NULL) /* No EA's */
+ {
+ rc = DosOpen(
+ pszFname,
+ &hf,
+ &Action,
+ ulFSize,
+ ulAttr,
+ ulOpenFlags,
+ fsOpenMode,
+ (PEAOP2)NULL);
+
+ if (rc == NO_ERROR)
+ {
+ *pusAction = (USHORT)Action;
+ *phf = (USHORT)hf;
+ }
+
+ return (rc);
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pEAOP, sizeof(EAOP), 1);
+ }
+ except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ rc = Od2ConvertFEAtoFEA2(
+ &(eaop2.fpFEA2List),
+ 0, /* To request allocation of the memory for the list */
+ FARPTRTOFLAT(pEAOP->fpFEAList));
+ /* Note that we don't do anything with the fpGEAList field since this
+ list is ignored */
+
+ if (rc != NO_ERROR)
+ {
+ if (!((ulOpenFlags & FILE_CREATE) ||
+ (ulOpenFlags & FILE_TRUNCATE)))
+ {
+ // Don't return an error at that point because it is possible that
+ // the EAOP is not used in case no file is created ! It seems strange
+ // to pass an EAOP when opening a file for read, but CMD.EXE does it
+ // with an invalid FEA list and OS/2 accepts it.
+ rc = DosOpen(
+ pszFname,
+ &hf,
+ &Action,
+ ulFSize,
+ ulAttr,
+ ulOpenFlags,
+ fsOpenMode,
+ (PEAOP2)NULL);
+
+ if (rc == NO_ERROR)
+ {
+ *pusAction = (USHORT)Action;
+ *phf = (USHORT)hf;
+ }
+#if DBG
+ if (rc != 0)
+ {
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16Open2: Error at DosOpen, rc = %d\n",
+ rc));
+ }
+ }
+#endif
+ return rc;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16Open2: Bad EA list, rc = %d\n",
+ rc));
+ }
+#endif
+
+ return rc;
+ }
+
+ rc = DosOpen(
+ pszFname,
+ &hf,
+ &Action,
+ ulFSize,
+ ulAttr,
+ ulOpenFlags,
+ fsOpenMode,
+ &eaop2);
+
+ if (rc == NO_ERROR)
+ {
+ *pusAction = (USHORT)Action;
+ *phf = (USHORT)hf;
+ }
+
+ if (rc != 0)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16Open2: Error at DosOpen, rc = %d\n",
+ rc));
+ }
+#endif
+ /* BUGBUG - The error code returned would be irrelevant to the
+ OS/2 1.x EA list so better return 0. Converting the Error
+ position now would be tricky, considering the list is
+ inconsistent. In the future, best is to check the OS/2 1.x
+ EA list thoroughly before calling DosCreateDir */
+ pEAOP->oError = 0;
+ }
+
+ RtlFreeHeap(
+ Od2Heap, 0,
+ eaop2.fpFEA2List);
+
+ return rc;
+}
+
+APIRET
+Dos16Open(
+ IN PSZ pszFileName,
+ OUT PUSHORT phf,
+ OUT PUSHORT pusAction,
+ IN ULONG cbFile,
+ IN ULONG ulAttribute,
+ IN ULONG fsOpenFlags,
+ IN ULONG fsOpenMode,
+ IN ULONG ulReserved)
+{
+ ULONG Action;
+ HFILE hf;
+ APIRET Rc;
+
+ if (ulReserved != 0)
+ return ERROR_INVALID_PARAMETER;
+
+ try
+ {
+ Od2ProbeForWrite(phf, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pusAction, sizeof(USHORT), 1);
+ }
+ except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ hf = (HFILE) *phf;
+ Action = *pusAction;
+
+ Rc = DosOpen(
+ pszFileName,
+ &hf,
+ &Action,
+ cbFile,
+ ulAttribute,
+ fsOpenFlags,
+ fsOpenMode,
+ (PEAOP2)NULL /* No EA's */
+ );
+
+ *pusAction = (USHORT)Action;
+ *phf = (USHORT)hf;
+
+ return (Rc);
+}
+
+
+
+APIRET
+Dos16Read(
+ IN HFILE FileHandle,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PUSHORT BytesRead
+ )
+
+{
+ APIRET Rc;
+ ULONG Bytes;
+
+ try
+ {
+ Od2ProbeForWrite(BytesRead, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ Bytes = (ULONG) *BytesRead;
+
+ Rc = DosRead(
+ FileHandle,
+ Buffer,
+ Length,
+ &Bytes );
+
+ *BytesRead = (USHORT) Bytes;
+
+ return (Rc);
+}
+
+
+APIRET
+Dos16Write(
+ IN HFILE FileHandle,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PUSHORT BytesWritten
+ )
+
+{
+ APIRET Rc;
+ ULONG Bytes;
+
+ try
+ {
+ Od2ProbeForWrite(BytesWritten, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ Bytes = (ULONG) *BytesWritten;
+
+ Rc = DosWrite(
+ FileHandle,
+ Buffer,
+ Length,
+ &Bytes );
+
+ *BytesWritten = (USHORT) Bytes;
+
+ return (Rc);
+}
+
+
+APIRET
+Dos16QueryFHState(
+ IN HFILE FileHandle,
+ OUT PUSHORT pOpenMode
+ )
+
+{
+ APIRET Rc;
+ ULONG OpenMode;
+
+ try
+ {
+ Od2ProbeForWrite(pOpenMode, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ OpenMode = (ULONG) *pOpenMode;
+
+ Rc = DosQueryFHState(
+ FileHandle,
+ &OpenMode );
+
+ *pOpenMode = (USHORT) OpenMode;
+
+ return (Rc);
+}
+
+
+APIRET
+Dos16QueryHType(
+ IN HFILE FileHandle,
+ OUT PUSHORT pHandleType,
+ OUT PUSHORT pDeviceFlags
+ )
+
+{
+ APIRET Rc;
+ ULONG HandleType;
+ ULONG DeviceFlags;
+
+ try
+ {
+ Od2ProbeForWrite(pHandleType, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pDeviceFlags, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ HandleType = (ULONG) *pHandleType;
+ DeviceFlags = (ULONG) *pDeviceFlags;
+
+ Rc = DosQueryHType(
+ FileHandle,
+ &HandleType,
+ &DeviceFlags );
+
+ *pHandleType = (USHORT) HandleType;
+ *pDeviceFlags = (USHORT) DeviceFlags;
+
+ return (Rc);
+}
+
+
+APIRET
+Dos16FSCtl(
+ IN PBYTE Data,
+ IN ULONG DataLength,
+ OUT PUSHORT pActualDataLength,
+ IN PBYTE Parameters,
+ IN ULONG ParametersLength,
+ IN OUT PUSHORT pActualParametersLength,
+ IN ULONG Function,
+ IN PSZ RouteName,
+ IN HFILE FileHandle,
+ IN ULONG RoutingMethod
+ )
+
+{
+ APIRET Rc;
+ ULONG ActualDataLength;
+ ULONG ActualParametersLength;
+
+ try
+ {
+ Od2ProbeForWrite(pActualDataLength, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pActualParametersLength, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ ActualDataLength = (ULONG) *pActualDataLength;
+ ActualParametersLength = (ULONG) *pActualParametersLength;
+
+ Rc = DosFSCtl(
+ Data,
+ DataLength,
+ &ActualDataLength,
+ Parameters,
+ ParametersLength,
+ &ActualParametersLength,
+ Function,
+ RouteName,
+ FileHandle,
+ RoutingMethod
+ );
+
+ *pActualDataLength = (USHORT) ActualDataLength;
+ *pActualParametersLength = (USHORT) ActualParametersLength;
+
+ return (Rc);
+}
+
+
+APIRET
+Dos16QueryCurrentDir(
+ IN ULONG DiskNumber,
+ OUT PSZ DirectoryName,
+ IN OUT PSHORT pDirectoryNameLength
+ )
+
+{
+ APIRET Rc;
+ ULONG DirectoryNameLength;
+
+ try
+ {
+ Od2ProbeForWrite(pDirectoryNameLength, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ DirectoryNameLength = (ULONG) *pDirectoryNameLength;
+
+ Rc = DosQueryCurrentDir(
+ DiskNumber & 0xff, // fix bug only have 26 drives
+ DirectoryName,
+ &DirectoryNameLength
+ );
+
+ *pDirectoryNameLength = (USHORT) DirectoryNameLength;
+
+ return (Rc);
+}
+
+
+APIRET
+Dos16QueryCurrentDisk(
+ OUT PUSHORT pDiskNumber,
+ OUT PULONG LogicalDrives
+ )
+
+{
+ APIRET Rc;
+ ULONG DiskNumber;
+
+ try
+ {
+ Od2ProbeForWrite(pDiskNumber, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ DiskNumber = (ULONG) *pDiskNumber;
+
+ Rc = DosQueryCurrentDisk(
+ &DiskNumber,
+ LogicalDrives
+ );
+
+ *pDiskNumber = (USHORT) DiskNumber;
+
+ return (Rc);
+}
+
+
+APIRET
+Dos16QueryVerify(
+ OUT PUSHORT pVerify
+ )
+
+{
+ APIRET Rc;
+ ULONG Verify;
+
+ try
+ {
+ Od2ProbeForWrite(pVerify, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ Verify = (ULONG) *pVerify;
+
+ Rc = DosQueryVerify(
+ &Verify
+ );
+
+ *pVerify = (USHORT) Verify;
+
+ return (Rc);
+}
+
+
+APIRET
+Dos16ErrClass(
+ IN ULONG ErrorCode,
+ OUT PUSHORT pErrorClass,
+ OUT PUSHORT pErrorAction,
+ OUT PUSHORT pErrorLocus
+ )
+
+{
+ APIRET Rc;
+ ULONG ErrorClass;
+ ULONG ErrorAction;
+ ULONG ErrorLocus;
+
+ try
+ {
+ Od2ProbeForWrite(pErrorClass, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pErrorAction, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pErrorLocus, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ ErrorClass = (ULONG) *pErrorClass;
+ ErrorAction = (ULONG) *pErrorAction;
+ ErrorLocus = (ULONG) *pErrorLocus;
+
+ Rc = DosErrClass(
+ ErrorCode,
+ &ErrorClass,
+ &ErrorAction,
+ &ErrorLocus
+ );
+
+ *pErrorClass = (USHORT) ErrorClass;
+ *pErrorAction = (USHORT) ErrorAction;
+ *pErrorLocus = (USHORT) ErrorLocus;
+
+ return (Rc);
+}
+
+APIRET
+Dos16EnumAttribute(
+ IN ULONG RefType,
+ IN PVOID FileRef,
+ IN ULONG EntryNum,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ IN OUT PULONG pActualCount,
+ IN ULONG FileInformationLevel,
+ IN ULONG ulReserved
+ )
+{
+ ULONG guess_dena_buf_size;
+ PVOID cruiser_dena_buf;
+ ULONG tmp_entry_num;
+ APIRET rc;
+
+ if (ulReserved != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pActualCount, sizeof(ULONG), 1);
+ Od2ProbeForWrite(Buffer, Length, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ /* Allocate a temporary buffer to hold the DENA1 structures (Cruiser format).
+ We need to take the worst case. The Cruiser DENA1 adds one ULONG field
+ for each entry + requires 4-bytes alignement. */
+ guess_dena_buf_size = Length + (Length/5 + 1) * (sizeof(ULONG) + 3);
+ cruiser_dena_buf = (PVOID)RtlAllocateHeap(Od2Heap, 0, guess_dena_buf_size);
+ if (cruiser_dena_buf == NULL) {
+#if DBG
+ KdPrint(( "OS2: Dos16EnumAttribute, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ tmp_entry_num = *pActualCount;
+
+ if (RefType == ENUMEA_REFTYPE_FHANDLE)
+ {
+ /* Convert PUSHORT pointer to file handle to a PULONG pointer */
+ ULONG tmp_file_ref;
+
+ try
+ {
+ tmp_file_ref = (ULONG)*((USHORT *)FileRef);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ rc = DosEnumAttribute(
+ RefType,
+ &tmp_file_ref,
+ EntryNum,
+ cruiser_dena_buf,
+ guess_dena_buf_size,
+ &tmp_entry_num,
+ FileInformationLevel);
+ }
+ else
+ {
+ rc = DosEnumAttribute(
+ RefType,
+ FileRef,
+ EntryNum,
+ cruiser_dena_buf,
+ guess_dena_buf_size,
+ &tmp_entry_num,
+ FileInformationLevel);
+ }
+
+ if (rc != NO_ERROR)
+ {
+ RtlFreeHeap(Od2Heap, 0, cruiser_dena_buf);
+
+ return rc;
+ }
+
+ if (tmp_entry_num != 0)
+ {
+ rc = Od2ConvertCruiserDena1ListtoDena1List16(
+ Buffer, /* Target buffer */
+ pActualCount, /* Number of resulting DENA1_16 entries */
+ Length, /* Length of target buffer */
+ cruiser_dena_buf /* Source cruiser DENA1 list */
+ );
+ }
+ else
+ *pActualCount = 0;
+
+ RtlFreeHeap(Od2Heap, 0, cruiser_dena_buf);
+
+ return rc;
+}
+
+VOID
+TranslateStartFindBuf4toFindBuf2(
+ OUT PFILEFINDBUF2 pDstBuf,
+ IN PFILEFINDBUF4 pSrcBuf
+ )
+{
+ pDstBuf->fdateCreation = pSrcBuf->fdateCreation;
+ pDstBuf->ftimeCreation = pSrcBuf->ftimeCreation;
+ pDstBuf->fdateLastAccess = pSrcBuf->fdateLastAccess;
+ pDstBuf->ftimeLastAccess = pSrcBuf->ftimeLastAccess;
+ pDstBuf->fdateLastWrite = pSrcBuf->fdateLastWrite;
+ pDstBuf->ftimeLastWrite = pSrcBuf->ftimeLastWrite;
+ pDstBuf->cbFile = pSrcBuf->cbFile;
+ pDstBuf->cbFileAlloc = pSrcBuf->cbFileAlloc;
+ pDstBuf->attrFile = (USHORT)(pSrcBuf->attrFile);
+}
+
+VOID
+TranslateFindBuf4toFindBuf2(
+ OUT PFILEFINDBUF2 pDstBuf,
+ IN PFILEFINDBUF4 pSrcBuf
+ )
+{
+ pDstBuf->fdateCreation = pSrcBuf->fdateCreation;
+ pDstBuf->ftimeCreation = pSrcBuf->ftimeCreation;
+ pDstBuf->fdateLastAccess = pSrcBuf->fdateLastAccess;
+ pDstBuf->ftimeLastAccess = pSrcBuf->ftimeLastAccess;
+ pDstBuf->fdateLastWrite = pSrcBuf->fdateLastWrite;
+ pDstBuf->ftimeLastWrite = pSrcBuf->ftimeLastWrite;
+ pDstBuf->cbFile = pSrcBuf->cbFile;
+ pDstBuf->cbFileAlloc = pSrcBuf->cbFileAlloc;
+ pDstBuf->attrFile = (USHORT)(pSrcBuf->attrFile);
+ pDstBuf->cbList = pSrcBuf->cbList;
+ pDstBuf->cchName = pSrcBuf->cchName;
+ // copy filename and null terminate
+ RtlMoveMemory (&pDstBuf->achName, &pSrcBuf->achName, pDstBuf->cchName);
+ pDstBuf->achName[pDstBuf->cchName] = '\0';
+}
+
+VOID
+TranslateFindBuf3toFindBuf(
+ OUT PFILEFINDBUF1 pDstBuf,
+ IN PFILEFINDBUF3 pSrcBuf
+ )
+{
+ pDstBuf->fdateCreation = pSrcBuf->fdateCreation;
+ pDstBuf->ftimeCreation = pSrcBuf->ftimeCreation;
+ pDstBuf->fdateLastAccess = pSrcBuf->fdateLastAccess;
+ pDstBuf->ftimeLastAccess = pSrcBuf->ftimeLastAccess;
+ pDstBuf->fdateLastWrite = pSrcBuf->fdateLastWrite;
+ pDstBuf->ftimeLastWrite = pSrcBuf->ftimeLastWrite;
+ pDstBuf->cbFile = pSrcBuf->cbFile;
+ pDstBuf->cbFileAlloc = pSrcBuf->cbFileAlloc;
+ pDstBuf->attrFile = (USHORT)(pSrcBuf->attrFile);
+ pDstBuf->cchName = pSrcBuf->cchName;
+ // copy filename and null terminate
+ RtlMoveMemory (&pDstBuf->achName, &pSrcBuf->achName, pDstBuf->cchName);
+ pDstBuf->achName[pDstBuf->cchName] = '\0';
+}
+
+VOID
+TranslateFileStatustoFileStatus16(
+ OUT PFILESTATUS16 pDstBuf,
+ IN PFILESTATUS pSrcBuf
+ )
+{
+ pDstBuf->fdateCreation = pSrcBuf->fdateCreation;
+ pDstBuf->ftimeCreation = pSrcBuf->ftimeCreation;
+ pDstBuf->fdateLastAccess = pSrcBuf->fdateLastAccess;
+ pDstBuf->ftimeLastAccess = pSrcBuf->ftimeLastAccess;
+ pDstBuf->fdateLastWrite = pSrcBuf->fdateLastWrite;
+ pDstBuf->ftimeLastWrite = pSrcBuf->ftimeLastWrite;
+ pDstBuf->cbFile = pSrcBuf->cbFile;
+ pDstBuf->cbFileAlloc = pSrcBuf->cbFileAlloc;
+ pDstBuf->attrFile = (USHORT)(pSrcBuf->attrFile);
+}
+
+VOID
+TranslateFileStatus16toFileStatus(
+ OUT PFILESTATUS pDstBuf,
+ IN PFILESTATUS16 pSrcBuf
+ )
+{
+ pDstBuf->fdateCreation = pSrcBuf->fdateCreation;
+ pDstBuf->ftimeCreation = pSrcBuf->ftimeCreation;
+ pDstBuf->fdateLastAccess = pSrcBuf->fdateLastAccess;
+ pDstBuf->ftimeLastAccess = pSrcBuf->ftimeLastAccess;
+ pDstBuf->fdateLastWrite = pSrcBuf->fdateLastWrite;
+ pDstBuf->ftimeLastWrite = pSrcBuf->ftimeLastWrite;
+ pDstBuf->cbFile = pSrcBuf->cbFile;
+ pDstBuf->cbFileAlloc = pSrcBuf->cbFileAlloc;
+ pDstBuf->attrFile = (ULONG)(pSrcBuf->attrFile);
+}
+
+VOID
+TranslateFileStatus2toFileStatus2_16(
+ OUT PFILESTATUS2_16 pDstBuf,
+ IN PFILESTATUS2 pSrcBuf
+ )
+{
+ pDstBuf->fdateCreation = pSrcBuf->fdateCreation;
+ pDstBuf->ftimeCreation = pSrcBuf->ftimeCreation;
+ pDstBuf->fdateLastAccess = pSrcBuf->fdateLastAccess;
+ pDstBuf->ftimeLastAccess = pSrcBuf->ftimeLastAccess;
+ pDstBuf->fdateLastWrite = pSrcBuf->fdateLastWrite;
+ pDstBuf->ftimeLastWrite = pSrcBuf->ftimeLastWrite;
+ pDstBuf->cbFile = pSrcBuf->cbFile;
+ pDstBuf->cbFileAlloc = pSrcBuf->cbFileAlloc;
+ pDstBuf->attrFile = (USHORT)(pSrcBuf->attrFile);
+ pDstBuf->cbList = pSrcBuf->cbList;
+}
+
+ //
+ // A service routine to translate the return buffer of
+ // DosFindFirst and DosFindNext to the 16 bit counterparts.
+ //
+
+VOID
+TranslateFindBuf(
+ IN PFILEFINDBUF1 pDstBuf,
+ IN PFILEFINDBUF3 pSrcBuf
+ )
+{
+ pDstBuf->fdateCreation = pSrcBuf->fdateCreation;
+ pDstBuf->ftimeCreation = pSrcBuf->ftimeCreation;
+ pDstBuf->fdateLastAccess = pSrcBuf->fdateLastAccess;
+ pDstBuf->ftimeLastAccess = pSrcBuf->ftimeLastAccess;
+ pDstBuf->fdateLastWrite = pSrcBuf->fdateLastWrite;
+ pDstBuf->ftimeLastWrite = pSrcBuf->ftimeLastWrite;
+ pDstBuf->cbFile = pSrcBuf->cbFile;
+ pDstBuf->cbFileAlloc = pSrcBuf->cbFileAlloc;
+ pDstBuf->attrFile = (USHORT)(pSrcBuf->attrFile);
+ pDstBuf->cchName = pSrcBuf->cchName;
+ //
+ // copy filename and null terminate
+ //
+ RtlMoveMemory (&pDstBuf->achName, &pSrcBuf->achName, pDstBuf->cchName);
+ pDstBuf->achName[pDstBuf->cchName] = 0;
+}
+
+
+APIRET
+Dos16FindFirst(
+ IN PSZ FileName,
+ IN OUT PUSHORT pDirectoryHandle,
+ IN ULONG FileAttributes,
+ IN PFILEFINDBUF1 Buffer,
+ IN ULONG Length,
+ IN OUT PUSHORT CountEntriesFound,
+ IN ULONG Reserved
+ )
+
+{
+ APIRET rc = NO_ERROR;
+ FILEFINDBUF3 SrcBuffer3;
+ PFILEFINDBUF1 pDstBuffer, pMaxBuffer;
+ ULONG LocalCount = 1;
+ ULONG EntriesRequested;
+ ULONG EntriesFound = 0;
+ HDIR DirectoryHandle;
+ ULONG buf_len;
+
+ if (Reserved != 0)
+ return ERROR_INVALID_PARAMETER;
+
+ //
+ // We map the function into DosFindFirst (dllfind.c)
+ // few differences (1.2 vs 2.0):
+ // - Buffer is PFILEFINDBUF1 vs PFILEFINDBUF3 (need to copy!)
+ // - ulReserved becomes infolevel FIL_STANDARD
+ //
+ // so - we query one entry at a time and copy until the
+ // buffer given is full
+
+ /* Determine a buffer length which will allow for the same precise file name
+ length as with original 1.x style supplied buffer (in case of a request
+ for one entry) */
+ /* Note that even if buffer is quite small, we don't repport an error now
+ because OS/2 first checks the path */
+ if (Length < FIELD_OFFSET(FILEFINDBUF1, cchName))
+ buf_len = Length + FIELD_SIZE(FILEFINDBUF3, oNextEntryOffset);
+ else
+ buf_len = Length
+ + FIELD_SIZE(FILEFINDBUF3, oNextEntryOffset)
+ + FIELD_SIZE(FILEFINDBUF3, attrFile)
+ - FIELD_SIZE(FILEFINDBUF1, attrFile);
+
+ try
+ {
+ Od2ProbeForWrite(pDirectoryHandle, sizeof(USHORT), 1);
+ Od2ProbeForWrite(CountEntriesFound, sizeof(USHORT), 1);
+ Od2ProbeForWrite(Buffer, Length, 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if ((EntriesRequested = (ULONG)*CountEntriesFound) == 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ DirectoryHandle = (HDIR) *pDirectoryHandle;
+
+ //
+ // special care for -1 (make it a long)
+ //
+
+ if (DirectoryHandle == (HDIR)0xFFFF)
+ {
+ DirectoryHandle = (HDIR)0xFFFFFFFF;
+ }
+
+ /* Request one entry */
+ rc = DosFindFirst (
+ FileName,
+ &DirectoryHandle,
+ FileAttributes,
+ &SrcBuffer3,
+ buf_len,
+ &LocalCount,
+ FIL_STANDARD);
+
+ *pDirectoryHandle = (USHORT) DirectoryHandle;
+
+ if (rc != NO_ERROR)
+ {
+ //
+ // not even one entry
+ //
+ *CountEntriesFound = 0;
+#if DBG
+ if (rc != ERROR_NO_MORE_FILES)
+ {
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16FindFirst: Fail at DosFindFirst, Error %d\n", rc));
+ }
+ }
+#endif
+ if (rc == ERROR_FILE_NOT_FOUND) {
+ return ERROR_NO_MORE_FILES;
+ }
+ else if (rc == ERROR_INVALID_DRIVE) {
+ //
+ // it makes more sense, but OS/2 1.3 returns the other one...
+ //
+ return(ERROR_PATH_NOT_FOUND);
+ }
+ else
+ return (rc);
+ }
+
+ pMaxBuffer = (PFILEFINDBUF1) ((ULONG)(Buffer) + Length);
+ pDstBuffer = Buffer;
+ TranslateFindBuf(pDstBuffer,&SrcBuffer3);
+ EntriesRequested--;
+ EntriesFound++;
+
+ //
+ // copy rest of entries
+ //
+
+ for (
+/*
+pDstBuffer++;
+*/
+ pDstBuffer = (PFILEFINDBUF1)(
+ (PBYTE)&(pDstBuffer->achName[0])
+ + pDstBuffer->cchName + 1);
+ ((pDstBuffer+1) <= pMaxBuffer) && (EntriesRequested > 0);
+/*
+ pDstBuffer++,
+*/
+ pDstBuffer = (PFILEFINDBUF1)(
+ (PBYTE)&(pDstBuffer->achName[0])
+ + pDstBuffer->cchName + 1),
+ EntriesRequested--, EntriesFound++
+ )
+ {
+ /* Request the next entry */
+ rc = DosFindNext (
+ DirectoryHandle,
+ &SrcBuffer3,
+ sizeof (SrcBuffer3), //BUGBUG - Fix that parameter (see calculations, 'buf_len' above)
+ &LocalCount
+ );
+ if (rc != NO_ERROR)
+ {
+ *CountEntriesFound = (USHORT) EntriesFound;
+#if DBG
+ if (rc != ERROR_NO_MORE_FILES)
+ {
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16FindFirst: Fail at DosFindNext, Error %d\n", rc));
+ }
+ }
+#endif
+ if ( (rc == ERROR_BUFFER_OVERFLOW) ||
+ (rc == ERROR_NO_MORE_FILES)
+ )
+ return NO_ERROR;
+ else
+ return (rc);
+ }
+ TranslateFindBuf(pDstBuffer,&SrcBuffer3);
+ }
+
+ *CountEntriesFound = (USHORT) EntriesFound;
+
+#if DBG
+ if (EntriesRequested > 0)
+ {
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16FindFirst: Buffer Overflow \n"));
+ }
+ }
+#endif
+
+ return (NO_ERROR);
+}
+
+APIRET
+Dos16FindFirst2(
+ IN PSZ FileName,
+ IN OUT PUSHORT pDirectoryHandle,
+ IN ULONG FileAttributes,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ IN OUT PUSHORT CountEntriesFound,
+ IN ULONG infolevel,
+ IN ULONG Reserved
+ )
+{
+ APIRET rc;
+ ULONG LocalCount;
+ HDIR DirectoryHandle;
+
+#define Buffer_ptr ((PBYTE)Buffer) /* PBYTE alias for 'Buffer' */
+
+ if (Reserved != 0)
+ return ERROR_INVALID_PARAMETER;
+
+ if (infolevel == FIL_STANDARD)
+ {
+ return(Dos16FindFirst(FileName,
+ pDirectoryHandle,
+ FileAttributes,
+ (PFILEFINDBUF1)Buffer,
+ Length,
+ CountEntriesFound,
+ Reserved));
+ }
+ else if ( (infolevel != FIL_QUERYEASIZE) &&
+ (infolevel != FIL_QUERYEASFROMLIST) )
+ return ERROR_INVALID_LEVEL;
+
+ /* Validate the user-supplied pointers */
+ try
+ {
+ Od2ProbeForWrite(pDirectoryHandle, sizeof(USHORT), 1);
+ Od2ProbeForWrite(CountEntriesFound, sizeof(USHORT), 1);
+ Od2ProbeForWrite(Buffer, Length, 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if ((LocalCount = (ULONG)*CountEntriesFound) == 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ DirectoryHandle = (HDIR) *pDirectoryHandle;
+ // special care for -1 (make it a long)
+ if (DirectoryHandle == (HDIR)0xFFFF)
+ {
+ DirectoryHandle = (HDIR)0xFFFFFFFF;
+ }
+
+#if NEVER
+/* PQ - The code till the #endif is probably fine, except that
+ the Cruiser DosFindNext apparently can't handle requests for more than
+ one file at a time.
+*/
+
+ if (infolevel == FIL_QUERYEASIZE)
+ {
+ int i;
+ BYTE *target_ptr, *source_ptr;
+ PFILEFINDBUF4 pfindbuf4;
+ PFILEFINDBUF2 pfindbuf2;
+ PBYTE tmp_buf;
+ ULONG tmp_buf_size;
+
+ /* Allocate a temporary buffer. Note that the FILEFINDBUF4 structure
+ is bigger:
+ - additional .oNextEntryOffset field (4 bytes)
+ - .attr field ULONG instead of USHORT (2 bytes)
+ - if more than one entry is requested, alignement between structures
+ may add up to 3 bytes per entry
+ Due to the way we operate here (see code below), i.e. because we copy
+ entries one by one, we need not be concerned about the padding but
+ only add 6 bytes to the length indicated by the user.
+ Note that we assume that the buffer supplied will successfully
+ hold one entry (regardless of what the requested entries count is)
+ so that, even though we retrieve only one entry the first time, we
+ will allocate a buffer of length Length+6.
+ */
+ tmp_buf_size = Length + 6;
+ tmp_buf = RtlAllocateHeap(Od2Heap, 0, tmp_buf_size);
+ if (tmp_buf == NULL) {
+#if DBG
+ KdPrint(( "OS2: Dos16FindFirst2, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ rc = DosFindFirst (
+ FileName,
+ pDirectoryHandle,
+ FileAttributes,
+ (PFILEFINDBUF3)tmp_buf,
+ tmp_buf_size,
+ &LocalCount,
+ FIL_QUERYEASIZE);
+
+ *pDirectoryHandle = (USHORT)DirectoryHandle;
+
+ if ( (rc != NO_ERROR) &&
+ !((rc == ERROR_BUFFER_OVERFLOW) && (LocalCount != 0)) &&
+ !((rc == ERROR_NO_MORE_FILES) && (LocalCount != 0)) )
+ {
+ // not even one entry
+ // BUGBUG - Check in which error cases the CountEntriesFound variable
+ // is set (to 0).
+ *CountEntriesFound = 0;
+#if DBG
+ if (rc != ERROR_NO_MORE_FILES)
+ {
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16FindFirst2: Fail at DosFindFirst, Error %d\n", rc));
+ }
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ if (rc == ERROR_FILE_NOT_FOUND)
+ return ERROR_NO_MORE_FILES;
+ else
+ return (rc);
+ }
+
+ for (i=0, target_ptr=Buffer_ptr,
+ source_ptr=(PBYTE)tmp_buf;
+ i < (int)LocalCount;
+ i++)
+ {
+ /* Copy FILEFINDBUF4 to target user buffer as a
+ FILEFINDBUF2 structure */
+ pfindbuf2 = (PFILEFINDBUF2)target_ptr;
+ pfindbuf4 = (PFILEFINDBUF4)source_ptr;
+ TranslateFindBuf4toFindBuf2(
+ pfindbuf2,
+ pfindbuf4);
+ target_ptr = (PBYTE)&(pfindbuf2->achName[0])
+ + pfindbuf2->cchName + 1;
+ source_ptr = (PBYTE)&(pfindbuf4->achName[0])
+ + pfindbuf4->cchName + 1;
+ /* Cruiser alignement */
+ source_ptr = (PBYTE)( ((ULONG)source_ptr + sizeof(ULONG) - 1) &
+ ~(sizeof(ULONG) - 1));
+ } /* End: for (i ... ) */
+
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ *CountEntriesFound = (USHORT)LocalCount;
+
+ return NO_ERROR;
+ }
+
+#endif /* NEVER */
+
+ if (infolevel == FIL_QUERYEASIZE)
+ {
+ PFILEFINDBUF4 pfindbuf4;
+ PFILEFINDBUF2 pfindbuf2;
+ PBYTE tmp_buf;
+ ULONG tmp_buf_size;
+ ULONG len;
+ ULONG entries_found = 0;
+ ULONG entries_requested = LocalCount;
+
+ /* Allocate a temporary buffer. Note that the FILEFINDBUF4 structure
+ is bigger:
+ - additional .oNextEntryOffset field (4 bytes)
+ - .attr field ULONG instead of USHORT (2 bytes)
+ - if more than one entry is requested, alignement between structures
+ may add up to 3 bytes per entry
+ Due to the way we operate here (see code below), i.e. because we copy
+ entries one by one, we need not be concerned about the padding but
+ only add 6 bytes to the length indicated by the user.
+ Note that we assume that the buffer supplied will successfully
+ hold one entry (regardless of what the requested entries count is)
+ so that, even though we retrieve only one entry the first time, we
+ will allocate a buffer of length Length+6.
+ */
+ tmp_buf_size = Length + 6;
+ tmp_buf = RtlAllocateHeap(Od2Heap, 0, tmp_buf_size);
+ if (tmp_buf == NULL) {
+#if DBG
+ KdPrint(( "OS2: Dos16FindFirst2, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ pfindbuf4 = (PFILEFINDBUF4)tmp_buf;
+ pfindbuf2 = (PFILEFINDBUF2)Buffer_ptr;
+ len = 0;
+
+ LocalCount = 1;
+ rc = DosFindFirst (
+ FileName,
+ &DirectoryHandle,
+ FileAttributes,
+ (PFILEFINDBUF3)tmp_buf,
+ /* To reflect the room left in the user's target buffer */
+ MAX((LONG)tmp_buf_size - (LONG)len, 0),
+ &LocalCount,
+ FIL_QUERYEASIZE);
+
+ *pDirectoryHandle = (USHORT)DirectoryHandle;
+
+ if (rc == NO_ERROR)
+ {
+ entries_found++;
+
+ /****************************************/
+ /* Copy file found to the user's buffer */
+ /****************************************/
+
+ TranslateFindBuf4toFindBuf2(
+ pfindbuf2,
+ pfindbuf4);
+ pfindbuf2 = (PFILEFINDBUF2) ((PBYTE)&(pfindbuf2->achName[0])
+ + pfindbuf2->cchName + 1);
+ len = (PBYTE)pfindbuf2 - (PBYTE)Buffer_ptr;
+ }
+
+ while ((rc == NO_ERROR) && (entries_found < entries_requested))
+ {
+ LocalCount = 1;
+ rc = DosFindNext (
+ DirectoryHandle,
+ (PFILEFINDBUF3)tmp_buf,
+ /* To reflect the room left in the user's target buffer */
+ MAX((LONG)tmp_buf_size - (LONG)len, 0),
+ &LocalCount);
+
+ if (rc == NO_ERROR)
+ {
+ entries_found++;
+
+ /****************************************/
+ /* Copy file found to the user's buffer */
+ /****************************************/
+
+ TranslateFindBuf4toFindBuf2(
+ pfindbuf2,
+ pfindbuf4);
+ pfindbuf2 = (PFILEFINDBUF2) ((PBYTE)&(pfindbuf2->achName[0])
+ + pfindbuf2->cchName + 1);
+ len = (PBYTE)pfindbuf2 - (PBYTE)Buffer_ptr;
+ }
+ } /* while */
+
+ if ( ((rc == ERROR_BUFFER_OVERFLOW) ||
+ (rc == ERROR_NO_MORE_FILES)) &&
+ (entries_found != 0)
+ )
+ rc = NO_ERROR;
+
+ if (rc != NO_ERROR)
+ {
+ // BUGBUG - Check in which error cases the CountEntriesFound variable
+ // is set (to 0).
+ *CountEntriesFound = (USHORT)entries_found;
+#if DBG
+ if (rc != ERROR_NO_MORE_FILES)
+ {
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16FindFirst2: Fail at DosFindNext, Error %d\n", rc));
+ }
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ if (rc == ERROR_FILE_NOT_FOUND)
+ return ERROR_NO_MORE_FILES;
+ else
+ return (rc);
+ }
+ else
+ {
+ *CountEntriesFound = (USHORT)entries_found;
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ return (NO_ERROR);
+ }
+ } /* End: if QUERYEASIZE */
+#if NEVER
+/* PQ - The code till the #endif is probably fine, except that
+ the Cruiser DosFindNext apparently can't handle requests for more than
+ one file at a time.
+*/
+ else if (infolevel == FIL_QUERYEASFROMLIST)
+ {
+ PGEALIST fpGEAList;
+ PGEA2LIST fpGEA2List;
+ int i;
+ BYTE *target_ptr, *source_ptr;
+ FEALIST *target_FEA_list;
+ FEA2LIST *source_FEA2_list;
+ PFILEFINDBUF4 pfindbuf4;
+ PFILEFINDBUF2 pfindbuf2;
+ PBYTE tmp_buf;
+ ULONG tmp_buf_size;
+
+ /* Validate the user-supplied EAOP part of the buffer */
+ try
+ {
+ fpGEAList = FARPTRTOFLAT( ((EAOP *)Buffer)->fpGEAList );
+
+ Od2ProbeForRead( fpGEAList,
+ fpGEAList->cbList,
+ 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ rc = Od2ConvertGEAtoGEA2(
+ &fpGEA2List,
+ 0, /* Request allocation for the GEA2 list */
+ fpGEAList);
+
+ if (rc != NO_ERROR)
+ {
+ return rc;
+ }
+
+ /* Alocate a temporary buffer to store find information with same size as
+ the user-supplied buffer. Although Cruiser-style info takes more space
+ (vs OS/2 1.21 info) we can't allocate a bigger temporary buffer because
+ then, if we do manage to get an entry in it but can't squeeze it in the
+ actual user's buffer, what should we do with that entry ? It should be
+ returned by a following DosFindNext() call but we already fished it out
+ with no straightforward way to put it back ! */
+ tmp_buf_size = Length + 6; /* We can safely add 6 since it reflects the
+ .oNextEntryOffset field of one entry */
+ tmp_buf = (PBYTE)RtlAllocateHeap(Od2Heap, 0, tmp_buf_size);
+ if (tmp_buf == NULL) {
+#if DBG
+ KdPrint(( "OS2: Dos16FindFirst2, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Initialize EAOP2 structure at beginning of buffer */
+ ((EAOP2 *)tmp_buf)->fpGEA2List = fpGEA2List;
+ ((EAOP2 *)tmp_buf)->fpFEA2List = NULL;
+ ((EAOP2 *)tmp_buf)->oError = 0;
+
+ pfindbuf4 = (PFILEFINDBUF4)(tmp_buf + sizeof(EAOP2));
+ pfindbuf2 = (PFILEFINDBUF2)(Buffer_ptr + sizeof(EAOP));
+
+ rc = DosFindFirst (
+ FileName,
+ &DirectoryHandle,
+ FileAttributes,
+ (PFILEFINDBUF3)tmp_buf,
+ tmp_buf_size,
+ &LocalCount,
+ FIL_QUERYEASFROMLIST);
+
+ *pDirectoryHandle = (USHORT)DirectoryHandle;
+
+ if (rc == ERROR_EAS_DIDNT_FIT)
+ {
+ //BUGBUG - Check that !
+ *CountEntriesFound = 1;
+ TranslateStartFindBuf4toFindBuf2(
+ pfindbuf2,
+ pfindbuf4);
+
+ /* Copy also cbList, which indicates the size of EA's for the file */
+ pfindbuf2->cbList = pfindbuf4->cbList;
+
+ RtlFreeHeap(Od2Heap, 0, fpGEA2List);
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ return ERROR_EAS_DIDNT_FIT;
+ }
+
+ if ( (rc != NO_ERROR) &&
+ !((rc == ERROR_BUFFER_OVERFLOW) && (LocalCount != 0)) &&
+ !((rc == ERROR_NO_MORE_FILES) && (LocalCount != 0)) )
+ {
+ //
+ // not even one entry
+ //
+ // BUGBUG - Check in which error cases the CountEntriesFound variable
+ // is set (to 0).
+ *CountEntriesFound = 0;
+#if DBG
+ if (rc != ERROR_NO_MORE_FILES)
+ {
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16FindFirst2: Fail at DosFindFirst, Error %d\n", rc));
+ }
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0, fpGEA2List);
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ if (rc == ERROR_FILE_NOT_FOUND)
+ return ERROR_NO_MORE_FILES;
+ else
+ return (rc);
+ }
+
+ for (i=0, target_ptr=Buffer_ptr + sizeof(EAOP),
+ source_ptr=(PBYTE)tmp_buf + sizeof(EAOP2);
+ i < (int)LocalCount;
+ i++)
+ {
+ /* Copy FILEFINDBUF4 to target user buffer as a
+ FILEFINDBUF2 structure */
+ pfindbuf2 = (PFILEFINDBUF2)target_ptr;
+ pfindbuf4 = (PFILEFINDBUF4)source_ptr;
+ TranslateStartFindBuf4toFindBuf2(
+ pfindbuf2,
+ pfindbuf4);
+ target_FEA_list = (FEALIST *)(&(pfindbuf2->cbList));
+ source_FEA2_list = (FEA2LIST *)(&(pfindbuf4->cbList));
+ if (source_FEA2_list->cbList == sizeof(ULONG)) /* No EA's found */
+ {
+ Od2SetEmptyFEAListfromGEA2List(
+ target_FEA_list,
+ fpGEA2List);
+ }
+ else
+ {
+ PFEALIST fpFEAList = (PFEALIST)&(pfindbuf2->cbList);
+
+ Od2ConvertFEA2toFEA(
+ &target_FEA_list,
+ Length, /* Just use a non-zero value */
+ source_FEA2_list);
+ }
+ target_ptr = (PBYTE)target_FEA_list + target_FEA_list->cbList;
+ source_ptr = (PBYTE)source_FEA2_list + source_FEA2_list->cbList;
+ /* cbName - length of match object name */
+ *target_ptr = *source_ptr;
+ /* Assume name is null-terminated */
+ strcpy( target_ptr + 1,
+ source_ptr + 1);
+ target_ptr += 1 + (*target_ptr + 1);
+ source_ptr += 1 + (*source_ptr + 1);
+ /* Cruiser alignement */
+ source_ptr = (PBYTE)( ((ULONG)source_ptr + sizeof(ULONG) - 1) &
+ ~(sizeof(ULONG) - 1));
+ } /* End: for (i ... ) */
+
+ *CountEntriesFound = (USHORT)LocalCount;
+
+ RtlFreeHeap(Od2Heap, 0, fpGEA2List);
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ return (NO_ERROR);
+ }
+#endif /* NEVER */
+ else if (infolevel == FIL_QUERYEASFROMLIST)
+ {
+ PGEALIST fpGEAList;
+ PGEA2LIST fpGEA2List;
+ BYTE *target_ptr, *source_ptr;
+ FEALIST *target_FEA_list;
+ FEA2LIST *source_FEA2_list;
+ PFILEFINDBUF4 pfindbuf4;
+ PFILEFINDBUF2 pfindbuf2;
+ PBYTE tmp_buf;
+ ULONG tmp_buf_size;
+ ULONG len;
+ ULONG entries_found = 0;
+ ULONG entries_requested = LocalCount;
+
+ /* Check that the user's buffer has at least an EAOP structure */
+ if (Length < sizeof(EAOP))
+ {
+ return ERROR_BUFFER_OVERFLOW;
+ }
+
+ /* Validate the user-supplied EAOP part of the buffer */
+ try
+ {
+ fpGEAList = FARPTRTOFLAT( ((EAOP *)Buffer)->fpGEAList );
+
+ Od2ProbeForRead( fpGEAList,
+ fpGEAList->cbList,
+ 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ rc = Od2ConvertGEAtoGEA2(
+ &fpGEA2List,
+ 0, /* Request allocation for the GEA2 list */
+ fpGEAList);
+
+ if (rc != NO_ERROR)
+ {
+ return ERROR_EA_LIST_INCONSISTENT;
+ }
+
+ /* Alocate a temporary buffer to store find information with same size as
+ the user-supplied buffer. Although Cruiser-style info takes more space
+ (vs OS/2 1.21 info) we can't allocate a bigger temporary buffer because
+ then, if we do manage to get an entry in it but can't squeeze it in the
+ actual user's buffer, what should we do with that entry ? It should be
+ returned by a following DosFindNext() call but we already fished it out
+ with no straightforward way to put it back ! */
+ tmp_buf_size = Length + 6; /* We can safely add 6 since it reflects the
+ .oNextEntryOffset field of one entry */
+ tmp_buf = (PBYTE)RtlAllocateHeap(Od2Heap, 0, tmp_buf_size);
+ if (tmp_buf == NULL) {
+#if DBG
+ KdPrint(( "OS2: Od2ConvertFEA2toFEA, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Initialize EAOP2 structure at beginning of buffer */
+ ((EAOP2 *)tmp_buf)->fpGEA2List = fpGEA2List;
+ ((EAOP2 *)tmp_buf)->fpFEA2List = NULL;
+ ((EAOP2 *)tmp_buf)->oError = 0;
+
+ pfindbuf4 = (PFILEFINDBUF4)(tmp_buf + sizeof(EAOP2));
+ pfindbuf2 = (PFILEFINDBUF2)(Buffer_ptr + sizeof(EAOP));
+ len = sizeof(EAOP);
+
+ LocalCount = 1;
+ rc = DosFindFirst (
+ FileName,
+ &DirectoryHandle,
+ FileAttributes,
+ (PFILEFINDBUF3)tmp_buf,
+ /* To reflect the room left in the user's target buffer */
+ MAX((LONG)tmp_buf_size - (LONG)len, 0),
+ &LocalCount,
+ FIL_QUERYEASFROMLIST);
+
+ *pDirectoryHandle = (USHORT)DirectoryHandle;
+
+ if (rc == NO_ERROR)
+ {
+ entries_found++;
+
+ /****************************************/
+ /* Copy file found to the user's buffer */
+ /****************************************/
+
+ /* Copy FILEFINDBUF4 to target user buffer as a
+ FILEFINDBUF2 structure */
+ TranslateStartFindBuf4toFindBuf2(
+ pfindbuf2,
+ pfindbuf4);
+ target_FEA_list = (FEALIST *)(&(pfindbuf2->cbList));
+ source_FEA2_list = (FEA2LIST *)(&(pfindbuf4->cbList));
+ if (source_FEA2_list->cbList == sizeof(ULONG)) /* No EA's found */
+ {
+ Od2SetEmptyFEAListfromGEA2List(
+ target_FEA_list,
+ fpGEA2List);
+ }
+ else
+ {
+ PFEALIST fpFEAList = (PFEALIST)&(pfindbuf2->cbList);
+
+ Od2ConvertFEA2toFEA(
+ &target_FEA_list,
+ Length, /* Just use a non-zero value */
+ source_FEA2_list);
+ }
+ target_ptr = (PBYTE)target_FEA_list + target_FEA_list->cbList;
+ source_ptr = (PBYTE)source_FEA2_list + source_FEA2_list->cbList;
+
+ /* Copy file name */
+ /* cbName - length of match object name */
+ *target_ptr = *source_ptr;
+ /* Assume name is null-terminated */
+ strcpy( target_ptr + 1,
+ source_ptr + 1);
+ target_ptr += 1 + (*target_ptr + 1);
+ len = target_ptr - Buffer_ptr;
+ pfindbuf2 = (PFILEFINDBUF2)target_ptr;
+ }
+
+ while ((rc == NO_ERROR) && (entries_found < entries_requested))
+ {
+ LocalCount = 1;
+ rc = DosFindNext (
+ DirectoryHandle,
+ (PFILEFINDBUF3)tmp_buf,
+ /* To reflect the room left in the user's target buffer */
+ MAX((LONG)tmp_buf_size - (LONG)len, 0),
+ &LocalCount);
+
+ if (rc == NO_ERROR)
+ {
+ entries_found++;
+
+ /****************************************/
+ /* Copy file found to the user's buffer */
+ /****************************************/
+
+ /* Copy FILEFINDBUF4 to target user buffer as a
+ FILEFINDBUF2 structure */
+ TranslateStartFindBuf4toFindBuf2(
+ pfindbuf2,
+ pfindbuf4);
+ target_FEA_list = (FEALIST *)(&(pfindbuf2->cbList));
+ source_FEA2_list = (FEA2LIST *)(&(pfindbuf4->cbList));
+ if (source_FEA2_list->cbList == sizeof(ULONG)) /* No EA's found */
+ {
+ Od2SetEmptyFEAListfromGEA2List(
+ target_FEA_list,
+ fpGEA2List);
+ }
+ else
+ {
+ PFEALIST fpFEAList = (PFEALIST)&(pfindbuf2->cbList);
+
+ Od2ConvertFEA2toFEA(
+ &target_FEA_list,
+ Length, /* Just use a non-zero value */
+ source_FEA2_list);
+ }
+ target_ptr = (PBYTE)target_FEA_list + target_FEA_list->cbList;
+ source_ptr = (PBYTE)source_FEA2_list + source_FEA2_list->cbList;
+
+ /* Copy file name */
+ /* cbName - length of match object name */
+ *target_ptr = *source_ptr;
+ /* Assume name is null-terminated */
+ strcpy( target_ptr + 1,
+ source_ptr + 1);
+ target_ptr += 1 + (*target_ptr + 1);
+ len = target_ptr - Buffer_ptr;
+ pfindbuf2 = (PFILEFINDBUF2)target_ptr;
+ }
+ } /* while */
+
+ if ( ((rc == ERROR_BUFFER_OVERFLOW) ||
+ (rc == ERROR_NO_MORE_FILES)) &&
+ (entries_found != 0)
+ )
+ rc = NO_ERROR;
+
+ if (rc == ERROR_EAS_DIDNT_FIT)
+ {
+ /* BUGBUG - Assumption made here that the beginning of the find
+ buffer for the last file is correct. Check that.
+ */
+
+ *CountEntriesFound = (USHORT)entries_found + 1;
+ TranslateStartFindBuf4toFindBuf2(
+ pfindbuf2,
+ pfindbuf4);
+
+ /* Copy also cbList, which indicates the size of EA's for the file */
+ pfindbuf2->cbList = pfindbuf4->cbList;
+
+ RtlFreeHeap(Od2Heap, 0, fpGEA2List);
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ return ERROR_EAS_DIDNT_FIT;
+ }
+ else if (rc != NO_ERROR)
+ {
+ // BUGBUG - Check in which error cases the CountEntriesFound variable
+ // is set (to 0).
+ *CountEntriesFound = (USHORT)entries_found;
+#if DBG
+ if (rc != ERROR_NO_MORE_FILES)
+ {
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16FindFirst2: Fail at DosFindNext, Error %d\n", rc));
+ }
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0, fpGEA2List);
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ if (rc == ERROR_FILE_NOT_FOUND)
+ return ERROR_NO_MORE_FILES;
+ else
+ return (rc);
+ }
+ else
+ {
+ *CountEntriesFound = (USHORT)entries_found;
+ RtlFreeHeap(Od2Heap, 0, fpGEA2List);
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ return (NO_ERROR);
+ }
+ } /* End: if QUERYEASFROMLIST */
+
+} /* End: Dos16FindFirst2() */
+#undef Buffer_ptr
+
+/* Defined in 'dllfind.c' */
+extern ULONG Internal_return_search_level(IN HDIR DirectoryHandle);
+
+APIRET
+Dos16FindNext_new(
+ IN HDIR DirectoryHandle,
+ IN PFILEFINDBUF1 Buffer,
+ IN ULONG Length,
+ IN OUT PUSHORT CountEntriesFound
+ )
+{
+#define Buffer_ptr ((PBYTE)Buffer) /* PBYTE alias for 'Buffer' */
+ APIRET rc = NO_ERROR;
+ ULONG LocalCount;
+ ULONG InfoLevel;
+ PBYTE tmp_buf;
+ ULONG tmp_buf_size;
+ ULONG len;
+
+ /* BUGBUG - Maybe redundant if thunk is performing signed conversion - check. */
+ if (DirectoryHandle == (HDIR)0xFFFF)
+ DirectoryHandle = (HDIR)0xFFFFFFFF;
+
+ InfoLevel = Internal_return_search_level(DirectoryHandle);
+
+ if ((InfoLevel != -1) &&
+ (InfoLevel != FIL_STANDARD) &&
+ (InfoLevel != FIL_QUERYEASIZE) &&
+ (InfoLevel != FIL_QUERYEASFROMLIST))
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16FindNext: Internal error. InfoLevel for handle %d\n",
+ DirectoryHandle, InfoLevel));
+ }
+#endif
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // We map the function into DosFindNext (dllfind.c)
+ // differences (1.2 vs 2.0):
+ // - Buffer is PFILEFINDBUF1 vs PFILEFINDBUF3 (need to copy!)
+ //
+ /* BUGBUG - Check if a length of 0 is not considered valid (NOP) */
+ if (Length < sizeof(FILEFINDBUF1))
+ return (ERROR_INVALID_PARAMETER);
+
+ try
+ {
+ Od2ProbeForWrite(CountEntriesFound, sizeof(USHORT), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if ((LocalCount = (ULONG)*CountEntriesFound) == 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (InfoLevel == -1)
+ {
+ return ERROR_INVALID_HANDLE;
+ }
+
+ if (InfoLevel == FIL_STANDARD)
+ {
+ int i;
+ BYTE *target_ptr, *source_ptr;
+ PFILEFINDBUF3 pfindbuf3;
+ PFILEFINDBUF1 pfindbuf;
+
+ /* Allocate a temporary buffer. Note that the FILEFINDBUF3 structure
+ is bigger:
+ - additional .oNextEntryOffset field (4 bytes)
+ - .attr field ULONG instead of USHORT (2 bytes)
+ - if more than one entry is requested, alignement between structures
+ may add up to 3 bytes per entry
+ Due to the way we operate here (see code below), i.e. because we copy
+ entries one by one, we need not be concerned about the padding but
+ only add 6 bytes to the length indicated by the user.
+ Note that we assume that the buffer supplied will successfully
+ hold one entry (regardless of what the requested entries count is)
+ so that, even though we retrieve only one entry the first time, we
+ will allocate a buffer of length Length+6.
+ */
+ tmp_buf_size = Length + 6;
+ tmp_buf = RtlAllocateHeap(Od2Heap, 0, tmp_buf_size);
+ if (tmp_buf == NULL) {
+#if DBG
+ KdPrint(( "OS2: Dos16FindNext_new, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ rc = DosFindNext(
+ DirectoryHandle,
+ (PFILEFINDBUF3)tmp_buf,
+ tmp_buf_size,
+ &LocalCount);
+
+ if ( (rc != NO_ERROR) &&
+ !((rc == ERROR_BUFFER_OVERFLOW) && (LocalCount != 0)) &&
+ !((rc == ERROR_NO_MORE_FILES) && (LocalCount != 0)) )
+ {
+ // not even one entry
+ // BUGBUG - Check in which error cases the CountEntriesFound variable
+ // is set (to 0).
+ *CountEntriesFound = 0;
+#if DBG
+ if (rc != ERROR_NO_MORE_FILES)
+ {
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16FindFirst2: Fail at DosFindFirst, Error %d\n", rc));
+ }
+ }
+#endif
+
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ if (rc == ERROR_FILE_NOT_FOUND)
+ return ERROR_NO_MORE_FILES;
+ else
+ return (rc);
+ }
+
+ for (i=0, target_ptr=Buffer_ptr,
+ source_ptr=(PBYTE)tmp_buf;
+ i < (int)LocalCount;
+ i++)
+ {
+ /* Copy FILEFINDBUF3 to target user buffer as a
+ FILEFINDBUF structure */
+ pfindbuf = (PFILEFINDBUF1)target_ptr;
+ pfindbuf3 = (PFILEFINDBUF3)source_ptr;
+ TranslateFindBuf3toFindBuf(
+ pfindbuf,
+ pfindbuf3);
+ target_ptr = (PBYTE)&(pfindbuf->achName[0])
+ + pfindbuf->cchName + 1;
+ source_ptr = (PBYTE)&(pfindbuf3->achName[0])
+ + pfindbuf3->cchName + 1;
+ /* Cruiser alignement */
+ source_ptr = (PBYTE)( ((ULONG)source_ptr + sizeof(ULONG) - 1) &
+ ~(sizeof(ULONG) - 1));
+ } /* End: for (i ... ) */
+
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ *CountEntriesFound = (USHORT)LocalCount;
+
+ return NO_ERROR;
+ }
+#if NEVER
+/* PQ - The code till the #endif is probably fine, except that
+ the Cruiser DosFindNext apparently can't handle requests for more than
+ one file at a time.
+*/
+ else if (InfoLevel == FIL_QUERYEASIZE)
+ {
+ int i;
+ BYTE *target_ptr, *source_ptr;
+ PFILEFINDBUF4 pfindbuf4;
+ PFILEFINDBUF2 pfindbuf2;
+
+ /* Allocate a temporary buffer. Note that the FILEFINDBUF4 structure
+ is bigger:
+ - additional .oNextEntryOffset field (4 bytes)
+ - .attr field ULONG instead of USHORT (2 bytes)
+ - if more than one entry is requested, alignement between structures
+ may add up to 3 bytes per entry
+ Due to the way we operate here (see code below), i.e. because we copy
+ entries one by one, we need not be concerned about the padding but
+ only add 6 bytes to the length indicated by the user.
+ Note that we assume that the buffer supplied will successfully
+ hold one entry (regardless of what the requested entries count is)
+ so that, even though we retrieve only one entry the first time, we
+ will allocate a buffer of length Length+6.
+ */
+ tmp_buf_size = Length + 6;
+ tmp_buf = RtlAllocateHeap(Od2Heap, 0, tmp_buf_size);
+ if (tmp_buf == NULL) {
+#if DBG
+ KdPrint(( "OS2: Dos16FindNext_new, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ rc = DosFindNext(
+ DirectoryHandle,
+ (PFILEFINDBUF3)tmp_buf,
+ tmp_buf_size,
+ &LocalCount);
+
+ if ( (rc != NO_ERROR) &&
+ !((rc == ERROR_BUFFER_OVERFLOW) && (LocalCount != 0)) &&
+ !((rc == ERROR_NO_MORE_FILES) && (LocalCount != 0)) )
+ {
+ // not even one entry
+ // BUGBUG - Check in which error cases the CountEntriesFound variable
+ // is set (to 0).
+ *CountEntriesFound = 0;
+#if DBG
+ if (rc != ERROR_NO_MORE_FILES)
+ {
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16FindFirst2: Fail at DosFindFirst, Error %d\n", rc));
+ }
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ if (rc == ERROR_FILE_NOT_FOUND)
+ return ERROR_NO_MORE_FILES;
+ else
+ return (rc);
+ }
+
+ for (i=0, target_ptr=Buffer_ptr,
+ source_ptr=(PBYTE)tmp_buf;
+ i < (int)LocalCount;
+ i++)
+ {
+ /* Copy FILEFINDBUF4 to target user buffer as a
+ FILEFINDBUF2 structure */
+ pfindbuf2 = (PFILEFINDBUF2)target_ptr;
+ pfindbuf4 = (PFILEFINDBUF4)source_ptr;
+ TranslateFindBuf4toFindBuf2(
+ pfindbuf2,
+ pfindbuf4);
+ target_ptr = (PBYTE)&(pfindbuf2->achName[0])
+ + pfindbuf2->cchName + 1;
+ source_ptr = (PBYTE)&(pfindbuf4->achName[0])
+ + pfindbuf4->cchName + 1;
+ /* Cruiser alignement */
+ source_ptr = (PBYTE)( ((ULONG)source_ptr + sizeof(ULONG) - 1) &
+ ~(sizeof(ULONG) - 1));
+ } /* End: for (i ... ) */
+
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ *CountEntriesFound = (USHORT)LocalCount;
+
+ return NO_ERROR;
+ } /* End: QUERYEASIZE */
+#endif /* NEVER */
+ else if (InfoLevel == FIL_QUERYEASIZE)
+ {
+ PFILEFINDBUF4 pfindbuf4;
+ PFILEFINDBUF2 pfindbuf2;
+ ULONG entries_found = 0;
+ ULONG entries_requested = LocalCount;
+
+ /* Allocate a temporary buffer. Note that the FILEFINDBUF4 structure
+ is bigger:
+ - additional .oNextEntryOffset field (4 bytes)
+ - .attr field ULONG instead of USHORT (2 bytes)
+ - if more than one entry is requested, alignement between structures
+ may add up to 3 bytes per entry
+ Due to the way we operate here (see code below), i.e. because we copy
+ entries one by one, we need not be concerned about the padding but
+ only add 6 bytes to the length indicated by the user.
+ Note that we assume that the buffer supplied will successfully
+ hold one entry (regardless of what the requested entries count is)
+ so that, even though we retrieve only one entry the first time, we
+ will allocate a buffer of length Length+6.
+ */
+ tmp_buf_size = Length + 6;
+ tmp_buf = RtlAllocateHeap(Od2Heap, 0, tmp_buf_size);
+ if (tmp_buf == NULL) {
+#if DBG
+ KdPrint(( "OS2: Dos16FindNext_new, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ pfindbuf4 = (PFILEFINDBUF4)tmp_buf;
+ pfindbuf2 = (PFILEFINDBUF2)Buffer_ptr;
+ len = 0;
+
+ rc = NO_ERROR;
+ while ((rc == NO_ERROR) && (entries_found < entries_requested))
+ {
+ LocalCount = 1;
+ rc = DosFindNext (
+ DirectoryHandle,
+ (PFILEFINDBUF3)tmp_buf,
+ /* To reflect the room left in the user's target buffer */
+ MAX((LONG)tmp_buf_size - (LONG)len,0),
+ &LocalCount);
+
+ if (rc == NO_ERROR)
+ {
+ entries_found++;
+
+ /****************************************/
+ /* Copy file found to the user's buffer */
+ /****************************************/
+
+ TranslateFindBuf4toFindBuf2(
+ pfindbuf2,
+ pfindbuf4);
+ pfindbuf2 = (PFILEFINDBUF2) ((PBYTE)&(pfindbuf2->achName[0])
+ + pfindbuf2->cchName + 1);
+ len = (PBYTE)pfindbuf2 - (PBYTE)Buffer_ptr;
+ }
+ } /* while */
+
+ if ( ((rc == ERROR_BUFFER_OVERFLOW) ||
+ (rc == ERROR_NO_MORE_FILES)) &&
+ (entries_found != 0)
+ )
+ rc = NO_ERROR;
+
+ if (rc != NO_ERROR)
+ {
+ // BUGBUG - Check in which error cases the CountEntriesFound variable
+ // is set (to 0).
+ *CountEntriesFound = (USHORT)entries_found;
+#if DBG
+ if (rc != ERROR_NO_MORE_FILES)
+ {
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16FindFirst2: Fail at DosFindNext, Error %d\n", rc));
+ }
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ if (rc == ERROR_FILE_NOT_FOUND)
+ return ERROR_NO_MORE_FILES;
+ else
+ return (rc);
+ }
+ else
+ {
+ *CountEntriesFound = (USHORT)entries_found;
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ return (NO_ERROR);
+ }
+ } /* End: if QUERYEASIZE */
+#if NEVER
+/* PQ - The code till the #endif is probably fine, except that
+ the Cruiser DosFindNext apparently can't handle requests for more than
+ one file at a time.
+*/
+ else if (InfoLevel == FIL_QUERYEASFROMLIST)
+ {
+ PGEALIST fpGEAList;
+ PGEA2LIST fpGEA2List;
+ int i;
+ BYTE *target_ptr, *source_ptr;
+ FEALIST *target_FEA_list;
+ FEA2LIST *source_FEA2_list;
+ PFILEFINDBUF4 pfindbuf4;
+ PFILEFINDBUF2 pfindbuf2;
+
+ /* Validate the user-supplied EAOP part of the buffer */
+ try
+ {
+ fpGEAList = FARPTRTOFLAT( ((EAOP *)Buffer)->fpGEAList );
+
+ Od2ProbeForRead( fpGEAList,
+ fpGEAList->cbList,
+ 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ rc = Od2ConvertGEAtoGEA2(
+ &fpGEA2List,
+ 0, /* Request allocation for the GEA2 list */
+ fpGEAList);
+
+ if (rc != NO_ERROR)
+ {
+ return ERROR_EA_LIST_INCONSISTENT;
+ }
+
+ /* Alocate a temporary buffer to store find information with same size as
+ the user-supplied buffer. Although Cruiser-style info takes more space
+ (vs OS/2 1.21 info) we can't allocate a bigger temporary buffer because
+ then, if we do manage to get an entry in it but can't squeeze it in the
+ actual user's buffer, what should we do with that entry ? It should be
+ returned by a following DosFindNext() call but we already fished it out
+ with no straightforward way to put it back ! */
+ tmp_buf_size = Length + 6; /* We can safely add 6 since it reflects the
+ .oNextEntryOffset field of one entry */
+ tmp_buf = (PBYTE)RtlAllocateHeap(Od2Heap, 0, tmp_buf_size);
+ if (tmp_buf == NULL) {
+#if DBG
+ KdPrint(( "OS2: Dos16FindNext_new, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Initialize EAOP2 structure at beginning of buffer */
+ ((EAOP2 *)tmp_buf)->fpGEA2List = fpGEA2List;
+ ((EAOP2 *)tmp_buf)->fpFEA2List = NULL;
+ ((EAOP2 *)tmp_buf)->oError = 0;
+
+ pfindbuf4 = (PFILEFINDBUF4)(tmp_buf + sizeof(EAOP2));
+ pfindbuf2 = (PFILEFINDBUF2)(Buffer_ptr + sizeof(EAOP));
+
+ rc = DosFindNext (
+ DirectoryHandle,
+ (PFILEFINDBUF3)tmp_buf,
+ tmp_buf_size,
+ &LocalCount);
+
+ if (rc == ERROR_EAS_DIDNT_FIT)
+ {
+ //BUGBUG - Check that !
+ *CountEntriesFound = 1;
+ TranslateStartFindBuf4toFindBuf2(
+ pfindbuf2,
+ pfindbuf4);
+
+ /* Copy also cbList, which indicates the size of EA's for the file */
+ pfindbuf2->cbList = pfindbuf4->cbList;
+
+ RtlFreeHeap(Od2Heap, 0, fpGEA2List);
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ return ERROR_EAS_DIDNT_FIT;
+ }
+
+ if ( (rc != NO_ERROR) &&
+ !((rc == ERROR_BUFFER_OVERFLOW) && (LocalCount != 0)) &&
+ !((rc == ERROR_NO_MORE_FILES) && (LocalCount != 0)) )
+ {
+ //
+ // not even one entry
+ //
+ // BUGBUG - Check in which error cases the CountEntriesFound variable
+ // is set (to 0).
+ *CountEntriesFound = 0;
+#if DBG
+ if (rc != ERROR_NO_MORE_FILES)
+ {
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16FindFirst2: Fail at DosFindFirst, Error %d\n", rc));
+ }
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0, fpGEA2List);
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ if (rc == ERROR_FILE_NOT_FOUND)
+ return ERROR_NO_MORE_FILES;
+ else
+ return (rc);
+ }
+
+ for (i=0, target_ptr=Buffer_ptr + sizeof(EAOP),
+ source_ptr=(PBYTE)tmp_buf + sizeof(EAOP2);
+ i < (int)LocalCount;
+ i++)
+ {
+ /* Copy FILEFINDBUF4 to target user buffer as a
+ FILEFINDBUF2 structure */
+ pfindbuf2 = (PFILEFINDBUF2)target_ptr;
+ pfindbuf4 = (PFILEFINDBUF4)source_ptr;
+ TranslateStartFindBuf4toFindBuf2(
+ pfindbuf2,
+ pfindbuf4);
+ target_FEA_list = (FEALIST *)(&(pfindbuf2->cbList));
+ source_FEA2_list = (FEA2LIST *)(&(pfindbuf4->cbList));
+ if (source_FEA2_list->cbList == sizeof(ULONG)) /* No EA's found */
+ {
+ Od2SetEmptyFEAListfromGEA2List(
+ target_FEA_list,
+ fpGEA2List);
+ }
+ else
+ {
+ PFEALIST fpFEAList = (PFEALIST)&(pfindbuf2->cbList);
+
+ Od2ConvertFEA2toFEA(
+ &target_FEA_list,
+ Length, /* Just use a non-zero value */
+ source_FEA2_list);
+ }
+ target_ptr = (PBYTE)target_FEA_list + target_FEA_list->cbList;
+ source_ptr = (PBYTE)source_FEA2_list + source_FEA2_list->cbList;
+ /* cbName - length of match object name */
+ *target_ptr = *source_ptr;
+ /* Assume name is null-terminated */
+ strcpy( target_ptr + 1,
+ source_ptr + 1);
+ target_ptr += 1 + (*target_ptr + 1);
+ source_ptr += 1 + (*source_ptr + 1);
+ /* Cruiser alignement */
+ source_ptr = (PBYTE)( ((ULONG)source_ptr + sizeof(ULONG) - 1) &
+ ~(sizeof(ULONG) - 1));
+ } /* End: for (i ... ) */
+
+ *CountEntriesFound = (USHORT)LocalCount;
+
+ RtlFreeHeap(Od2Heap, 0, fpGEA2List);
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ return (NO_ERROR);
+ }
+#endif /* NEVER */
+ else if (InfoLevel == FIL_QUERYEASFROMLIST)
+ {
+ PGEALIST fpGEAList;
+ PGEA2LIST fpGEA2List;
+ FEALIST *target_FEA_list;
+ FEA2LIST *source_FEA2_list;
+ PFILEFINDBUF4 pfindbuf4;
+ PFILEFINDBUF2 pfindbuf2;
+ ULONG entries_requested = LocalCount;
+ ULONG entries_found = 0;
+ PBYTE target_ptr, source_ptr;
+
+ /* Check that the user's buffer has at least an EAOP structure */
+ if (Length < sizeof(EAOP))
+ {
+ return ERROR_BUFFER_OVERFLOW;
+ }
+
+ /* Validate the user-supplied EAOP part of the buffer */
+ try
+ {
+ fpGEAList = FARPTRTOFLAT( ((EAOP *)Buffer)->fpGEAList );
+
+ Od2ProbeForRead( fpGEAList,
+ fpGEAList->cbList,
+ 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ rc = Od2ConvertGEAtoGEA2(
+ &fpGEA2List,
+ 0, /* Request allocation for the GEA2 list */
+ fpGEAList);
+
+ if (rc != NO_ERROR)
+ {
+ return ERROR_EA_LIST_INCONSISTENT;
+ }
+
+ /* Alocate a temporary buffer to store find information with same size as
+ the user-supplied buffer. Although Cruiser-style info takes more space
+ (vs OS/2 1.21 info) we can't allocate a bigger temporary buffer because
+ then, if we do manage to get an entry in it but can't squeeze it in the
+ actual user's buffer, what should we do with that entry ? It should be
+ returned by a following DosFindNext() call but we already fished it out
+ with no straightforward way to put it back ! */
+ tmp_buf_size = Length + 6; /* We can safely add 6 since it reflects the
+ .oNextEntryOffset field of one entry */
+ tmp_buf = (PBYTE)RtlAllocateHeap(Od2Heap, 0, tmp_buf_size);
+ if (tmp_buf == NULL) {
+#if DBG
+ KdPrint(( "OS2: Dos16FindNext_new, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Initialize EAOP2 structure at beginning of buffer */
+ ((EAOP2 *)tmp_buf)->fpGEA2List = fpGEA2List;
+ ((EAOP2 *)tmp_buf)->fpFEA2List = NULL;
+ ((EAOP2 *)tmp_buf)->oError = 0;
+
+ pfindbuf4 = (PFILEFINDBUF4)(tmp_buf + sizeof(EAOP2));
+ pfindbuf2 = (PFILEFINDBUF2)(Buffer_ptr + sizeof(EAOP));
+ len = sizeof(EAOP);
+
+ rc = NO_ERROR;
+ while ((rc == NO_ERROR) && (entries_found < entries_requested))
+ {
+ LocalCount = 1;
+ rc = DosFindNext (
+ DirectoryHandle,
+ (PFILEFINDBUF3)tmp_buf,
+ /* To reflect the room left in the user's target buffer */
+ MAX((LONG)tmp_buf_size - (LONG)len,0),
+ &LocalCount);
+
+ if (rc == NO_ERROR)
+ {
+ entries_found++;
+
+ /****************************************/
+ /* Copy file found to the user's buffer */
+ /****************************************/
+
+ /* Copy FILEFINDBUF4 to target user buffer as a
+ FILEFINDBUF2 structure */
+ TranslateStartFindBuf4toFindBuf2(
+ pfindbuf2,
+ pfindbuf4);
+ target_FEA_list = (FEALIST *)(&(pfindbuf2->cbList));
+ source_FEA2_list = (FEA2LIST *)(&(pfindbuf4->cbList));
+ if (source_FEA2_list->cbList == sizeof(ULONG)) /* No EA's found */
+ {
+ Od2SetEmptyFEAListfromGEA2List(
+ target_FEA_list,
+ fpGEA2List);
+ }
+ else
+ {
+ PFEALIST fpFEAList = (PFEALIST)&(pfindbuf2->cbList);
+
+ Od2ConvertFEA2toFEA(
+ &target_FEA_list,
+ Length, /* Just use a non-zero value */
+ source_FEA2_list);
+ }
+ target_ptr = (PBYTE)target_FEA_list + target_FEA_list->cbList;
+ source_ptr = (PBYTE)source_FEA2_list + source_FEA2_list->cbList;
+
+ /* Copy file name */
+ /* cbName - length of match object name */
+ *target_ptr = *source_ptr;
+ /* Assume name is null-terminated */
+ strcpy( target_ptr + 1,
+ source_ptr + 1);
+ target_ptr += 1 + (*target_ptr + 1);
+ len = target_ptr - Buffer_ptr;
+ pfindbuf2 = (PFILEFINDBUF2)target_ptr;
+ }
+ } /* while */
+
+ if ( ((rc == ERROR_BUFFER_OVERFLOW) ||
+ (rc == ERROR_NO_MORE_FILES)) &&
+ (entries_found != 0)
+ )
+ rc = NO_ERROR;
+
+ if (rc == ERROR_EAS_DIDNT_FIT)
+ {
+ /* BUGBUG - Assumption made here that the beginning of the find
+ buffer for the last file is correct. Check that.
+ */
+
+ *CountEntriesFound = (USHORT)entries_found + 1;
+ TranslateStartFindBuf4toFindBuf2(
+ pfindbuf2,
+ pfindbuf4);
+
+ /* Copy also cbList, which indicates the size of EA's for the file */
+ pfindbuf2->cbList = pfindbuf4->cbList;
+
+ RtlFreeHeap(Od2Heap, 0, fpGEA2List);
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ return ERROR_EAS_DIDNT_FIT;
+ }
+ else if (rc != NO_ERROR)
+ {
+ // BUGBUG - Check in which error cases the CountEntriesFound variable
+ // is set (to 0).
+ *CountEntriesFound = (USHORT)entries_found;
+#if DBG
+ if (rc != ERROR_NO_MORE_FILES)
+ {
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16FindFirst2: Fail at DosFindNext, Error %d\n", rc));
+ }
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0, fpGEA2List);
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ if (rc == ERROR_FILE_NOT_FOUND)
+ return ERROR_NO_MORE_FILES;
+ else
+ return (rc);
+ }
+ else
+ {
+ *CountEntriesFound = (USHORT)entries_found;
+ RtlFreeHeap(Od2Heap, 0, fpGEA2List);
+ RtlFreeHeap(Od2Heap, 0, tmp_buf);
+
+ return (NO_ERROR);
+ }
+ } /* End: if QUERYEASFROMLIST */
+} /* End: Dos16FindNext() */
+#undef Buffer_ptr
+
+
+APIRET
+Dos16FindNext(
+ IN HDIR DirectoryHandle,
+ IN PFILEFINDBUF1 Buffer,
+ IN ULONG Length,
+ IN OUT PUSHORT CountEntriesFound
+ )
+{
+ APIRET rc = NO_ERROR;
+ FILEFINDBUF3 SrcBuffer3;
+ PFILEFINDBUF1 pDstBuffer, pMaxBuffer;
+ ULONG LocalCount = 1;
+ ULONG EntriesRequested;
+ ULONG EntriesFound = 0;
+ ULONG InfoLevel;
+
+ /* BUGBUG - Maybe redundant if thunk is performing signed conversion - check. */
+ if (DirectoryHandle == (HDIR)0xFFFF)
+ DirectoryHandle = (HDIR)0xFFFFFFFF;
+
+ InfoLevel = Internal_return_search_level(DirectoryHandle);
+
+ if (InfoLevel != FIL_STANDARD)
+ {
+ return Dos16FindNext_new(
+ DirectoryHandle,
+ Buffer,
+ Length,
+ CountEntriesFound);
+ }
+
+ //
+ // We map the function into DosFindNext (dllfind.c)
+ // differences (1.2 vs 2.0):
+ // - Buffer is PFILEFINDBUF1 vs PFILEFINDBUF3 (need to copy!)
+ //
+ // so - we query one entry at a time and copy until the
+ // buffer given is full
+
+ if (Length < sizeof(FILEFINDBUF1))
+ return (ERROR_INVALID_PARAMETER);
+
+ try
+ {
+ Od2ProbeForWrite(CountEntriesFound, sizeof(USHORT), 1);
+ Od2ProbeForWrite(Buffer, Length, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if ((EntriesRequested = (ULONG)*CountEntriesFound) == 0) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ pMaxBuffer = (PFILEFINDBUF1) ((ULONG)(Buffer) + Length);
+
+ //
+ // copy entries
+ //
+
+ for ( pDstBuffer = Buffer;
+ ((pDstBuffer+1) <= pMaxBuffer) && (EntriesRequested > 0);
+/*
+ pDstBuffer++,
+*/
+ pDstBuffer = (PFILEFINDBUF1)(
+ (PBYTE)&(pDstBuffer->achName[0])
+ + pDstBuffer->cchName + 1),
+ EntriesRequested--, EntriesFound++
+ )
+ {
+ rc = DosFindNext (
+ DirectoryHandle,
+ &SrcBuffer3,
+ sizeof (SrcBuffer3),
+ &LocalCount
+ );
+ if (rc != NO_ERROR)
+ {
+ *CountEntriesFound = (USHORT) EntriesFound;
+#if DBG
+ if (rc != ERROR_NO_MORE_FILES)
+ {
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Dos16FindNext: Fail at DosFindNext, Error %d\n", rc));
+ }
+ }
+#endif
+ /* BUGBUG - Looks suspicious: I think BUFFER_OVERFLOW is no error
+ ONLY if we got some files */
+ if ( (rc == ERROR_BUFFER_OVERFLOW) ||
+ ((rc == ERROR_NO_MORE_FILES) && (EntriesFound != 0))
+ )
+ rc = NO_ERROR;
+
+ return (rc);
+ }
+
+ TranslateFindBuf(pDstBuffer,&SrcBuffer3);
+ } /* End: for (pDstBuffer ... ) */
+
+ *CountEntriesFound = (USHORT) EntriesFound;
+
+#if DBG
+ if (EntriesRequested > 0)
+ {
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("Dos16FindNext: Buffer Overflow \n"));
+ }
+ }
+#endif
+
+ return (NO_ERROR);
+}
+
+
+
+APIRET Dos16QPathInfo(
+ IN PSZ pszPath,
+ IN ULONG ulInfoLevel,
+ IN OUT PBYTE pInfoBuf,
+ IN ULONG cbInfoBuf,
+ IN ULONG ulReserved)
+{
+ APIRET rc;
+
+ if (ulReserved != 0)
+ return ERROR_INVALID_PARAMETER;
+
+ if (ulInfoLevel == FIL_STANDARD)
+ {
+ FILESTATUS fst;
+
+ if (cbInfoBuf < sizeof(FILESTATUS16))
+ return ERROR_BUFFER_OVERFLOW;
+
+ try
+ {
+ Od2ProbeForWrite(pInfoBuf,
+ sizeof(FILESTATUS16),
+ 1);
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ rc =DosQueryPathInfo(
+ pszPath,
+ ulInfoLevel,
+ (PBYTE)&fst,
+ sizeof(FILESTATUS));
+
+ if (rc == NO_ERROR)
+ {
+ TranslateFileStatustoFileStatus16 (
+ (FILESTATUS16 *)pInfoBuf,
+ &fst);
+ }
+
+ return rc;
+ }
+ else if (ulInfoLevel == FIL_QUERYEASIZE)
+ {
+ FILESTATUS2 fst;
+ FILESTATUS2_16 *pfst16 = (FILESTATUS2_16 *)pInfoBuf;
+
+ if (cbInfoBuf < sizeof(FILESTATUS2_16))
+ return ERROR_BUFFER_OVERFLOW;
+
+ try
+ {
+ Od2ProbeForWrite(pInfoBuf,
+ sizeof(FILESTATUS2_16),
+ 1);
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ rc =DosQueryPathInfo(
+ pszPath,
+ ulInfoLevel,
+ (PBYTE)&fst,
+ sizeof(FILESTATUS2));
+
+ if (rc == NO_ERROR)
+ {
+ /* Set FILESTATUS16 structure from FILESTATUS structure */
+ pfst16->fdateCreation = fst.fdateCreation;
+ pfst16->ftimeCreation = fst.ftimeCreation;
+ pfst16->fdateLastAccess = fst.fdateLastAccess;
+ pfst16->ftimeLastAccess = fst.ftimeLastAccess;
+ pfst16->fdateLastWrite = fst.fdateLastWrite;
+ pfst16->ftimeLastWrite = fst.ftimeLastWrite;
+ pfst16->cbFile = fst.cbFile;
+ pfst16->cbFileAlloc = fst.cbFileAlloc;
+ pfst16->attrFile = (USHORT)fst.attrFile;
+ pfst16->cbList = fst.cbList;
+ }
+
+ return rc;
+ }
+ else if ((ulInfoLevel == FIL_NAMEISVALID) ||
+ (ulInfoLevel == FIL_QUERYFULLNAME))
+ {
+ /* BUGBUG - Note that in the case of FIL_QUERYEASIZE, we get a
+ buffer size corresponding to the size needed for the new style
+ FEA2 list, which is more than what is needed for the FEA list.
+ The only correct way would be to actually retrieve the attributes
+ for the file into a temporary buffer, then calculate the FEA list
+ counterpart size. This is not done here (at least for now). */
+
+ return DosQueryPathInfo(
+ pszPath,
+ ulInfoLevel,
+ pInfoBuf,
+ cbInfoBuf);
+ }
+ else if (ulInfoLevel == FIL_QUERYEASFROMLIST)
+ {
+ EAOP2 eaop2;
+ ULONG FEA_list_length, GEA_list_length;
+ ULONG guess_FEA2_list_size;
+ FEALIST *pfealist;
+ GEALIST *pgealist;
+
+ if (cbInfoBuf < sizeof(EAOP))
+ return ERROR_BUFFER_OVERFLOW;
+
+ try
+ {
+ /* Write because the .oError field may be written to */
+ Od2ProbeForWrite(pInfoBuf, sizeof(EAOP), 1);
+
+ pfealist = (PFEALIST)FARPTRTOFLAT(((EAOP *)pInfoBuf)->fpFEAList);
+ FEA_list_length = pfealist->cbList;
+ Od2ProbeForWrite(pfealist, FEA_list_length, 1);
+
+ pgealist = (PGEALIST)FARPTRTOFLAT(((EAOP *)pInfoBuf)->fpGEAList);
+ GEA_list_length = pgealist->cbList;
+ Od2ProbeForRead(pgealist, GEA_list_length, 1);
+
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ /* We need to estimate the buffer size needed to contain the FEA2 list.
+ We must take the worst case, i.e. each FEA2 entry has a size of 1
+ modulo 4 so that we need to add 3 for each FEA entry due to alignement
+ requirements under OS/2 2.0. In addition, each entry adds one ULONG.
+ Now, how many entries do we have ? Again, we must take the worst-case
+ assumption, i.e. that each entry has the minimal length. The conclusion
+ is: each entry is taken to have a name length of 0, i.e. a name string
+ of length 1 */
+
+ guess_FEA2_list_size = FEA_list_length +
+ (FEA_list_length/5 + 1) * (sizeof(ULONG) + 3);
+
+ eaop2.fpFEA2List = (PFEA2LIST)RtlAllocateHeap(Od2Heap, 0,
+ guess_FEA2_list_size);
+ if (eaop2.fpFEA2List == NULL) {
+#if DBG
+ KdPrint(( "OS2: Dos16PathInfo, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ eaop2.fpFEA2List->cbList = guess_FEA2_list_size;
+
+ rc = Od2ConvertGEAtoGEA2(
+ &eaop2.fpGEA2List,
+ 0, /* Request allocation for the GEA list */
+ pgealist);
+
+ if (rc != 0)
+ {
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpFEA2List);
+
+ return ERROR_EA_LIST_INCONSISTENT;
+ }
+
+ rc = DosQueryPathInfo(
+ pszPath,
+ ulInfoLevel,
+ (PBYTE)&eaop2,
+ sizeof(EAOP2));
+
+ if (rc != NO_ERROR)
+ {
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpFEA2List);
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpGEA2List);
+
+ return rc;
+ }
+ if (eaop2.fpFEA2List->cbList == sizeof(ULONG)) /* No EAs */
+ {
+ Od2SetEmptyFEAListfromGEA2List(
+ pfealist, /* Target */
+ eaop2.fpGEA2List);
+ }
+ else
+ {
+ /* BUGBUG - It seems the fpFEA2List->cbList field is set incorrectly
+ by the Cruiser code (actually NT). Also, the .fEA (type) field of
+ each entry has incorrect values. The rest of the list looked OK.
+ In the meantime, fix it by hand */
+ /* BUGBUG - Check if I didn't fix it already on Cruiser side */
+ Od2FixFEA2List(eaop2.fpFEA2List);
+
+ rc = Od2ConvertFEA2toFEA(
+ &pfealist,
+ FEA_list_length,
+ eaop2.fpFEA2List);
+ }
+
+ /* BUGBUG - In case the supplied buffer is too small to contain the
+ requested FEA list, under Cruiser the fpFEA2List->cbList is nevertheless
+ set to the size of the extended attributes on disk (all of them, even
+ if only a subset was requested). Then, the size of the buffer required
+ to retrieve those attributes is less or equal to twice that number.
+ Here I do nothing (i.e. I don't copy this value back to the user's
+ fpFEAList->cbList) because:
+ 1. I didn't find documentation of the same behavior for OS/2 1.x
+ 2. Supporting that would require Cruiser FEA2 list to OS/2 1.x FEA
+ list conversion (which would require actually fetching the FEA2
+ list) so better drop it for now.
+ */
+
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpFEA2List);
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpGEA2List);
+
+ /* The oError field is not meaningfull, so better return 0 */
+ ((EAOP *)pInfoBuf)->oError = 0;
+
+ if (rc != NO_ERROR)
+ return ERROR_BUFFER_OVERFLOW;
+ else
+ return NO_ERROR;
+ } /* End: if (ulInfoLevel == FIL_QUERYEASFROMLIST) */
+ else
+ return ERROR_INVALID_LEVEL;
+}
+
+APIRET
+DosQFileInfo(
+ HFILE hf,
+ ULONG ulInfoLevel,
+ PVOID pInfoBuf,
+ ULONG cbInfoBuf
+ )
+{
+ APIRET rc;
+
+ if ( (ulInfoLevel != FIL_STANDARD) &&
+ (ulInfoLevel != FIL_QUERYEASIZE) &&
+ (ulInfoLevel != FIL_QUERYEASFROMLIST) &&
+ (ulInfoLevel != FIL_QUERYALLEAS) ) //This level is undocumented,
+ // used by the OS/2 filio204, var.
+ // 47+ component test.
+ {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ if (ulInfoLevel == FIL_STANDARD)
+ {
+ FILESTATUS FileStatus;
+
+ if (cbInfoBuf < sizeof(FILESTATUS16))
+ {
+ return ERROR_BUFFER_OVERFLOW;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pInfoBuf,
+ sizeof(FILESTATUS16),
+ 1);
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ //
+ // call DosQueryFileInfo
+ //
+ rc = DosQueryFileInfo (
+ hf,
+ FIL_STANDARD,
+ (PBYTE)(&FileStatus),
+ sizeof(FILESTATUS)
+ );
+
+ if (rc != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("DosQFileInfo: Fail at DosQueryFileInfo, Error %d\n", rc));
+ }
+#endif
+ return rc;
+ }
+
+ TranslateFileStatustoFileStatus16 (
+ (PFILESTATUS16)pInfoBuf,
+ &FileStatus);
+
+ return NO_ERROR;
+ }
+ else if (ulInfoLevel == FIL_QUERYEASIZE)
+ {
+ FILESTATUS2 fst;
+
+ if (cbInfoBuf < sizeof(FILESTATUS2_16))
+ return ERROR_BUFFER_OVERFLOW;
+
+ try
+ {
+ Od2ProbeForWrite(pInfoBuf,
+ sizeof(FILESTATUS2_16),
+ 1);
+ }
+ except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ //
+ // call DosQueryFileInfo
+ //
+ rc = DosQueryFileInfo (
+ hf,
+ FIL_QUERYEASIZE,
+ (PBYTE)(&fst),
+ sizeof(FILESTATUS2)
+ );
+
+ if (rc == NO_ERROR)
+ {
+ /* Set FILESTATUS2_16 structure from FILESTATUS2 structure */
+ TranslateFileStatus2toFileStatus2_16 (
+ (PFILESTATUS2_16)pInfoBuf,
+ &fst);
+ }
+
+ return rc;
+ }
+ else if (ulInfoLevel == FIL_QUERYEASFROMLIST)
+ {
+ EAOP2 eaop2;
+ ULONG FEA_list_length, GEA_list_length;
+ ULONG guess_FEA2_list_size;
+ FEALIST *pfealist;
+ GEALIST *pgealist;
+
+ try
+ {
+ /* Write because the .oError field may be written to */
+ Od2ProbeForWrite(pInfoBuf, sizeof(EAOP), 1);
+
+ pfealist = (PFEALIST)FARPTRTOFLAT(((EAOP *)pInfoBuf)->fpFEAList);
+ FEA_list_length = pfealist->cbList;
+ Od2ProbeForWrite(pfealist, FEA_list_length, 1);
+
+ pgealist = (PGEALIST)FARPTRTOFLAT(((EAOP *)pInfoBuf)->fpGEAList);
+ GEA_list_length = pgealist->cbList;
+ Od2ProbeForWrite(pgealist, GEA_list_length, 1);
+
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ /* We need to estimate the buffer size needed to contain the FEA2 list.
+ We must take the worst case, i.e. each FEA2 entry has a size of 1
+ modulo 4 so that we need to add 3 for each FEA entry due to alignement
+ requirements under OS/2 2.0. In addition, each entry adds one ULONG.
+ Now, how many entries do we have ? Again, we must take the worst-case
+ assumption, i.e. that each entry has the minimal length. The conclusion
+ is: each entry is taken to have a name length of 0, i.e. a name string
+ of length 1 */
+
+ guess_FEA2_list_size = FEA_list_length +
+ (FEA_list_length/5 + 1) * (sizeof(ULONG) + 3);
+
+ eaop2.fpFEA2List = (PFEA2LIST)RtlAllocateHeap(Od2Heap, 0,
+ guess_FEA2_list_size);
+ if (eaop2.fpFEA2List == NULL) {
+#if DBG
+ KdPrint(( "OS2: Dos16QPathInfo, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ eaop2.fpFEA2List->cbList = guess_FEA2_list_size;
+
+ rc = Od2ConvertGEAtoGEA2(
+ &eaop2.fpGEA2List,
+ 0, /* Request allocation for the GEA list */
+ pgealist);
+
+ if (rc != 0)
+ {
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpFEA2List);
+
+ return ERROR_EA_LIST_INCONSISTENT;
+ }
+
+ //
+ // call DosQueryFileInfo
+ //
+ rc = DosQueryFileInfo (
+ hf,
+ FIL_QUERYEASFROMLIST,
+ (PBYTE)&eaop2,
+ sizeof(EAOP2)
+ );
+
+ if (rc != NO_ERROR)
+ {
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpFEA2List);
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpGEA2List);
+
+ return rc;
+ }
+ if (eaop2.fpFEA2List->cbList == sizeof(ULONG)) /* No EAs */
+ {
+ Od2SetEmptyFEAListfromGEA2List(
+ pfealist, /* Target */
+ eaop2.fpGEA2List);
+ }
+ else
+ {
+ /* BUGBUG - It seems the fpFEA2List->cbList field is set incorrectly
+ by the Cruiser code (actually NT). Also, the .fEA (type) field of
+ each entry has incorrect values. The rest of the list looked OK.
+ In the meantime, fix it by hand */
+ /* BUGBUG - Check if I didn't fix it already on Cruiser side */
+ Od2FixFEA2List(eaop2.fpFEA2List);
+
+ rc = Od2ConvertFEA2toFEA(
+ &pfealist,
+ FEA_list_length,
+ eaop2.fpFEA2List);
+ }
+
+ /* BUGBUG - In case the supplied buffer is too small to contain the
+ requested FEA list, under Cruiser the fpFEA2List->cbList is nevertheless
+ set to the size of the extended attributes on disk (all of them, even
+ if only a subset was requested). Then, the size of the buffer required
+ to retrieve those attributes is less or equal to twice that number.
+ Here I do nothing (i.e. I don't copy this value back to the user's
+ fpFEAList->cbList) because:
+ 1. I didn't find documentation of the same behavior for OS/2 1.x
+ 2. Supporting that would require Cruiser FEA2 list to OS/2 1.x FEA
+ list conversion (which would require actually fetching the FEA2
+ list) so better drop it for now.
+ */
+
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpFEA2List);
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpGEA2List);
+
+ /* The oError field is not meaningfull, so better return 0 */
+ ((EAOP *)pInfoBuf)->oError = 0;
+
+ if (rc != NO_ERROR)
+ return ERROR_BUFFER_OVERFLOW;
+ else
+ return NO_ERROR;
+ } /* End: if (ulInfoLevel == FIL_QUERYEASFROMLIST) */
+ else // FIL_QUERYALLEAS - UNDOCUMENTED, used as far as I know only by
+ // component test, filio204 var 47+
+ {
+ EAOP tmp_eaop;
+ ULONG count;
+ DENA1_16 *dena_list_p;
+ FEALIST *pfealist;
+ ULONG FEA_list_length;
+ APIRET rc;
+
+ try
+ {
+ /* Write because the .oError field may be written to */
+ Od2ProbeForWrite(pInfoBuf, sizeof(EAOP), 1);
+
+ pfealist = (PFEALIST)FARPTRTOFLAT(((EAOP *)pInfoBuf)->fpFEAList);
+ FEA_list_length = pfealist->cbList;
+ Od2ProbeForWrite(pfealist, FEA_list_length, 1);
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ // Alocate space for the DENA1 list we are going to obtain. We take the
+ // space planned for the FEA list as the size
+ dena_list_p = RtlAllocateHeap( Od2Heap, 0, pfealist->cbList );
+ if (dena_list_p == NULL) {
+#if DBG
+ KdPrint(( "OS2: Dos16QPathInf, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ count = 0xFFFFFFFFL;
+ rc = Dos16EnumAttribute(
+ ENUMEA_REFTYPE_FHANDLE,
+ (PVOID)&hf,
+ 1L, // start with 1st attribute
+ (PVOID)dena_list_p,
+ pfealist->cbList, // size of output buffer
+ &count,
+ ENUMEA_LEVEL_NO_VALUE,
+ 0L);
+ if (rc != NO_ERROR)
+ {
+ RtlFreeHeap(Od2Heap, 0, dena_list_p);
+ return rc;
+ }
+
+ if (count == 0)
+ {
+ RtlFreeHeap(Od2Heap, 0, dena_list_p);
+ pfealist->cbList = sizeof(ULONG); // empty list
+ return NO_ERROR;
+ }
+
+ // Alocate space for the GEA list we are going to build. We take the
+ // space planned for the FEA list as the size
+ tmp_eaop.fpGEAList = RtlAllocateHeap( Od2Heap, 0, pfealist->cbList );
+ if (tmp_eaop.fpGEAList == NULL) {
+#if DBG
+ KdPrint(( "OS2: Dos16QPathInfo, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ tmp_eaop.fpGEAList->cbList = pfealist->cbList;
+
+ rc = Od2ConvertDENA1ListToGEAList(
+ tmp_eaop.fpGEAList,
+ dena_list_p,
+ count);
+
+ if (rc != NO_ERROR)
+ {
+ RtlFreeHeap(Od2Heap, 0, dena_list_p);
+ RtlFreeHeap(Od2Heap, 0, tmp_eaop.fpGEAList);
+ return rc;
+ }
+
+ tmp_eaop.fpFEAList = pfealist; // use the user's buffer
+
+ /* The basic block below implements:
+
+ DosQFileInfo(
+ hf,
+ FIL_QUERYEASFROMLIST,
+ &tmp_eaop,
+ cbInfoBuf); // user-supplied
+
+ similar to the regular DosQFileInfo but with an EAOP not with
+ 16-bit addresses. I could have added another level + a boolean
+ parameter and called DosQFileInfo recursively but I didn't want
+ to add another layer for the sake of an obscure level 4 case.
+ */
+
+ {
+ EAOP2 eaop2;
+ ULONG FEA_list_length, GEA_list_length;
+ ULONG guess_FEA2_list_size;
+ FEALIST *pfealist;
+ GEALIST *pgealist;
+ PVOID pInfoBuf = (PVOID)&tmp_eaop;
+
+ try
+ {
+ /* Write because the .oError field may be written to */
+ Od2ProbeForWrite(pInfoBuf, sizeof(EAOP), 1);
+
+ pfealist = (PFEALIST)((EAOP *)pInfoBuf)->fpFEAList;
+ FEA_list_length = pfealist->cbList;
+ Od2ProbeForWrite(pfealist, FEA_list_length, 1);
+
+ pgealist = (PGEALIST)((EAOP *)pInfoBuf)->fpGEAList;
+ GEA_list_length = pgealist->cbList;
+ Od2ProbeForWrite(pgealist, GEA_list_length, 1);
+
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ RtlFreeHeap(Od2Heap, 0, dena_list_p);
+ RtlFreeHeap(Od2Heap, 0, tmp_eaop.fpGEAList);
+ Od2ExitGP();
+ }
+
+ /* We need to estimate the buffer size needed to contain the FEA2 list.
+ We must take the worst case, i.e. each FEA2 entry has a size of 1
+ modulo 4 so that we need to add 3 for each FEA entry due to alignement
+ requirements under OS/2 2.0. In addition, each entry adds one ULONG.
+ Now, how many entries do we have ? Again, we must take the worst-case
+ assumption, i.e. that each entry has the minimal length. The conclusion
+ is: each entry is taken to have a name length of 0, i.e. a name string
+ of length 1 */
+
+ guess_FEA2_list_size = FEA_list_length +
+ (FEA_list_length/5 + 1) * (sizeof(ULONG) + 3);
+
+ eaop2.fpFEA2List = (PFEA2LIST)RtlAllocateHeap(Od2Heap, 0,
+ guess_FEA2_list_size);
+ if (eaop2.fpFEA2List == NULL) {
+#if DBG
+ KdPrint(( "OS2: Dos16QPathInfo, no memory in Od2Heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ eaop2.fpFEA2List->cbList = guess_FEA2_list_size;
+
+ rc = Od2ConvertGEAtoGEA2(
+ &eaop2.fpGEA2List,
+ 0, /* Request allocation for the GEA list */
+ pgealist);
+
+ if (rc != 0)
+ {
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpFEA2List);
+
+ RtlFreeHeap(Od2Heap, 0, dena_list_p);
+ RtlFreeHeap(Od2Heap, 0, tmp_eaop.fpGEAList);
+
+ return ERROR_EA_LIST_INCONSISTENT;
+ }
+
+ //
+ // call DosQueryFileInfo
+ //
+ rc = DosQueryFileInfo (
+ hf,
+ FIL_QUERYEASFROMLIST,
+ (PBYTE)&eaop2,
+ sizeof(EAOP2)
+ );
+
+ if (rc != NO_ERROR)
+ {
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpFEA2List);
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpGEA2List);
+
+ RtlFreeHeap(Od2Heap, 0, dena_list_p);
+ RtlFreeHeap(Od2Heap, 0, tmp_eaop.fpGEAList);
+
+ return rc;
+ }
+ if (eaop2.fpFEA2List->cbList == sizeof(ULONG)) /* No EAs */
+ {
+ Od2SetEmptyFEAListfromGEA2List(
+ pfealist, /* Target */
+ eaop2.fpGEA2List);
+ }
+ else
+ {
+ /* BUGBUG - It seems the fpFEA2List->cbList field is set incorrectly
+ by the Cruiser code (actually NT). Also, the .fEA (type) field of
+ each entry has incorrect values. The rest of the list looked OK.
+ In the meantime, fix it by hand */
+ /* BUGBUG - Check if I didn't fix it already on Cruiser side */
+ Od2FixFEA2List(eaop2.fpFEA2List);
+
+ rc = Od2ConvertFEA2toFEA(
+ &pfealist,
+ FEA_list_length,
+ eaop2.fpFEA2List);
+ }
+
+ /* BUGBUG - In case the supplied buffer is too small to contain the
+ requested FEA list, under Cruiser the fpFEA2List->cbList is nevertheless
+ set to the size of the extended attributes on disk (all of them, even
+ if only a subset was requested). Then, the size of the buffer required
+ to retrieve those attributes is less or equal to twice that number.
+ Here I do nothing (i.e. I don't copy this value back to the user's
+ fpFEAList->cbList) because:
+ 1. I didn't find documentation of the same behavior for OS/2 1.x
+ 2. Supporting that would require Cruiser FEA2 list to OS/2 1.x FEA
+ list conversion (which would require actually fetching the FEA2
+ list) so better drop it for now.
+ */
+
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpFEA2List);
+ RtlFreeHeap(Od2Heap, 0, eaop2.fpGEA2List);
+
+ /* The oError field is not meaningfull, so better return 0 */
+ ((EAOP *)pInfoBuf)->oError = 0;
+
+ RtlFreeHeap(Od2Heap, 0, dena_list_p);
+ RtlFreeHeap(Od2Heap, 0, tmp_eaop.fpGEAList);
+
+ if (rc != NO_ERROR)
+ return ERROR_BUFFER_OVERFLOW;
+ else
+ return NO_ERROR;
+ }
+ }
+}
+
+APIRET
+Dos16SetPathInfo(PSZ pszPath,
+ ULONG ulInfoLevel,
+ PBYTE pInfoBuf,
+ ULONG cbInfoBuf,
+ ULONG flOptions,
+ ULONG ulReserved)
+{
+ APIRET rc;
+
+ if (ulReserved != 0)
+ return ERROR_INVALID_PARAMETER;
+
+ if (ulInfoLevel == FIL_STANDARD)
+ {
+ FILESTATUS fst;
+
+ if (cbInfoBuf < sizeof(FILESTATUS16))
+ return ERROR_BUFFER_OVERFLOW;
+
+ try
+ {
+ Od2ProbeForRead(pInfoBuf,
+ sizeof(FILESTATUS16),
+ 1);
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if ((flOptions != DSPI_WRTTHRU) &&
+ (flOptions != 0))
+ return ERROR_INVALID_PARAMETER;
+
+ /* Set FILESTATUS structure from FILESTATUS16 structure */
+ TranslateFileStatus16toFileStatus (
+ &fst,
+ (FILESTATUS16 *)pInfoBuf);
+
+ rc =DosSetPathInfo(
+ pszPath,
+ ulInfoLevel,
+ (PBYTE)&fst,
+ sizeof(FILESTATUS),
+ flOptions);
+
+ return rc;
+ }
+ /* Request to set the EA's for the file */
+ else if (ulInfoLevel == FIL_QUERYEASIZE)
+ {
+ EAOP2 eaop2;
+ EAOP *peaop = (EAOP *)pInfoBuf;
+ FEALIST *fpFEAList;
+
+ if (cbInfoBuf < sizeof(EAOP))
+ return ERROR_BUFFER_OVERFLOW;
+
+ try
+ {
+ Od2ProbeForWrite(pInfoBuf,
+ sizeof(EAOP),
+ 1);
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ fpFEAList = FARPTRTOFLAT(peaop->fpFEAList);
+
+ try
+ {
+ Od2ProbeForRead(fpFEAList,
+ fpFEAList->cbList,
+ 1);
+ }
+ except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ rc = Od2ConvertFEAtoFEA2(
+ &(eaop2.fpFEA2List),
+ 0L, /* To request allocation of the memory for the list */
+ fpFEAList);
+ /* Note that we don't do anything with the fpGEAList field since this
+ list is ignored */
+
+ if (rc != NO_ERROR)
+ return (ERROR_EA_LIST_INCONSISTENT);
+
+ rc =DosSetPathInfo(
+ pszPath,
+ ulInfoLevel,
+ (PBYTE)&eaop2,
+ sizeof(EAOP2),
+ flOptions);
+
+ return rc;
+ }
+ else
+ return ERROR_INVALID_LEVEL;
+}
+
+
+APIRET
+Dos16SetFileInfo(
+ HFILE hf,
+ ULONG ulInfoLevel,
+ PVOID pInfoBuf,
+ ULONG cbInfoBuf
+ )
+{
+ APIRET rc;
+
+ if (ulInfoLevel == FIL_STANDARD)
+ {
+ FILESTATUS16 *pfst16 = pInfoBuf;
+ FILESTATUS fst;
+
+ if (cbInfoBuf < 12)
+ return ERROR_INSUFFICIENT_BUFFER;
+
+ /* Get the file's attributes: we need this field to be set. In OS/2
+ 1.x, this field is not used by DosSetFileInfo but it is expected
+ but the Cruiser code (as well as by the corresponding NT API) */
+ rc = DosQueryFileInfo(
+ hf,
+ FIL_STANDARD,
+ (PVOID)&fst,
+ sizeof(FILESTATUS));
+
+ if (rc != NO_ERROR)
+ return rc;
+
+ try
+ {
+ Od2ProbeForRead(pInfoBuf,
+ 12,
+ 1);
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ fst.fdateCreation = pfst16->fdateCreation;
+ fst.ftimeCreation = pfst16->ftimeCreation;
+ fst.fdateLastAccess = pfst16->fdateLastAccess;
+ fst.ftimeLastAccess = pfst16->ftimeLastAccess;
+ fst.fdateLastWrite = pfst16->fdateLastWrite;
+ fst.ftimeLastWrite = pfst16->ftimeLastWrite;
+
+ /* We rely here on the fact that first 12 bytes of Cruiser
+ FILESTATUS are identical to FILESTATUS16. Note that only
+ the first 6 USHORT fields of the structure are used by this
+ API. */
+ rc = DosSetFileInfo(
+ hf,
+ FIL_STANDARD,
+ (PVOID)&fst,
+ sizeof(FILESTATUS));
+
+ return rc;
+ }
+ /* Request to set the EA's for the file */
+ else if (ulInfoLevel == FIL_QUERYEASIZE)
+ {
+ EAOP2 eaop2;
+ EAOP *peaop = (EAOP *)pInfoBuf;
+ FEALIST *fpFEAList;
+
+ if (cbInfoBuf < sizeof(EAOP))
+ return ERROR_INSUFFICIENT_BUFFER;
+
+ try
+ {
+ Od2ProbeForRead(pInfoBuf,
+ sizeof(EAOP),
+ 1);
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ fpFEAList = FARPTRTOFLAT(peaop->fpFEAList);
+
+ try
+ {
+ Od2ProbeForRead(fpFEAList,
+ fpFEAList->cbList,
+ 1);
+ }
+ except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ rc = Od2ConvertFEAtoFEA2(
+ &(eaop2.fpFEA2List),
+ 0L, /* To request allocation of the memory for the list */
+ fpFEAList);
+ /* Note that we don't do anything with the fpGEAList field since this
+ list is ignored */
+
+ if (rc != NO_ERROR)
+ return (ERROR_EA_LIST_INCONSISTENT);
+
+ rc =DosSetFileInfo(
+ hf,
+ FIL_QUERYEASIZE,
+ (PBYTE)&eaop2,
+ sizeof(EAOP2));
+
+ return rc;
+ }
+ else
+ return ERROR_INVALID_LEVEL;
+}
diff --git a/private/os2/client/dllfsd.c b/private/os2/client/dllfsd.c
new file mode 100644
index 000000000..48b1fe253
--- /dev/null
+++ b/private/os2/client/dllfsd.c
@@ -0,0 +1,1463 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllfsd.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 fsd-related APIs: DosQueryFsInfo,
+ DosSetFsInfo
+
+Author:
+
+ Therese Stowell (thereses) 17-Jan-1990
+
+Revision History:
+
+ Patrick Questembert (patrickq) 2-Feb-1992:
+ Fixed & enhanced the DosQueryFSAttach call.
+
+--*/
+
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FSD
+#include "os2dll.h"
+#include "os2win.h"
+
+// macro to probe string arguments passed to APIs
+#define PROBE_STRING(s) ((VOID) ((s) == NULL ? 0 : strlen(s)))
+
+
+APIRET
+ProcessLabel(
+ IN PVOLUMELABEL Buffer,
+ IN ULONG Length,
+ OUT PFILE_FS_LABEL_INFORMATION LabelBuffer
+ );
+
+APIRET
+OpenDrive(
+ IN ULONG DiskNumber,
+ IN ULONG RequestedAccess,
+ OUT PHANDLE DriveHandle
+ );
+
+APIRET
+DosSetCurrentDir(
+ IN PSZ DirectoryName
+ );
+
+APIRET
+DosQueryFSInfo(
+ IN ULONG DiskNumber,
+ IN ULONG FsInformationLevel,
+ IN PBYTE Buffer,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns allocation or label information for a volume.
+
+Arguments:
+
+ DiskNumber - which volume to return information for
+
+ FsInformationLevel - what type of information to return
+
+ Buffer - where to return information
+
+ Length - length of buffer
+
+Return Value:
+
+ ERROR_INVALID_LEVEL - invalid FsInformationLevel
+
+ ERROR_INVALID_DRIVE - specified volume does not exist
+
+ ERROR_BUFFER_OVERFLOW - requested information won't fit in buffer
+
+--*/
+
+{
+ APIRET RetCode;
+ NTSTATUS Status;
+ HANDLE DiskHandle;
+ IO_STATUS_BLOCK IoStatus;
+ struct LABEL_BUFFER {
+ FILE_FS_VOLUME_INFORMATION VolumeInfo;
+ WCHAR Label[MAX_LABEL_LENGTH];
+ } VolInfoBuffer;
+ FILE_FS_SIZE_INFORMATION FsSizeInfoBuffer;
+ PFSINFO FsInfoBuf;
+ PFSALLOCATE FsAllocBuf;
+ STRING LabelString;
+ UNICODE_STRING LabelString_U;
+ ULONG i;
+
+ if (FsInformationLevel > FSIL_VOLSER) {
+ return ERROR_INVALID_LEVEL;
+ }
+ if (DiskNumber > MAX_DRIVES) {
+ return ERROR_INVALID_DRIVE;
+ }
+ RetCode = OpenDrive(DiskNumber,
+ FILE_READ_DATA,
+ &DiskHandle
+ );
+ if (RetCode != NO_ERROR) {
+ return RetCode;
+ }
+ if (FsInformationLevel == FSIL_ALLOC) {
+ if (Length < sizeof(FSALLOCATE)) {
+ NtClose(DiskHandle);
+ return ERROR_BUFFER_OVERFLOW;
+ }
+ do {
+ Status = NtQueryVolumeInformationFile(DiskHandle,
+ &IoStatus,
+ &FsSizeInfoBuffer,
+ sizeof(FsSizeInfoBuffer),
+ FileFsSizeInformation
+ );
+ } while (RetryIO(Status, DiskHandle));
+ NtClose(DiskHandle);
+ if (!NT_SUCCESS(Status)) {
+ return ERROR_INVALID_DRIVE;
+ }
+ FsAllocBuf = (PFSALLOCATE) Buffer;
+ try {
+ FsAllocBuf->ulReserved = 0;
+ FsAllocBuf->cSectorUnit = FsSizeInfoBuffer.SectorsPerAllocationUnit;
+ // BUGBUG - what do we do here if .HighPart is non-zero
+ FsAllocBuf->cUnit = FsSizeInfoBuffer.TotalAllocationUnits.LowPart;
+ FsAllocBuf->cUnitAvail = FsSizeInfoBuffer.AvailableAllocationUnits.LowPart;
+ FsAllocBuf->cbSector = BYTES_PER_SECTOR;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ }
+ else {
+ if (Length < (FIELD_OFFSET(FSINFO, vol) + 1)) {
+ NtClose(DiskHandle);
+ return ERROR_BUFFER_OVERFLOW;
+ }
+ do {
+ Status = NtQueryVolumeInformationFile(DiskHandle,
+ &IoStatus,
+ &VolInfoBuffer,
+ sizeof(VolInfoBuffer),
+ FileFsVolumeInformation
+ );
+ } while (RetryIO(Status, DiskHandle));
+ NtClose(DiskHandle);
+ if (!NT_SUCCESS(Status)) {
+ return ERROR_INVALID_DRIVE;
+ }
+ if (Length < (FIELD_OFFSET(FSINFO, vol)+(VolInfoBuffer.VolumeInfo.VolumeLabelLength / 2))) {
+ return ERROR_BUFFER_OVERFLOW;
+ }
+ FsInfoBuf = (PFSINFO) Buffer;
+ try {
+ for (i = 0; i < 12; i++) {
+ FsInfoBuf->vol.szVolLabel[i] = 0;
+ }
+ FsInfoBuf->ulVSN = VolInfoBuffer.VolumeInfo.VolumeSerialNumber;
+
+ LabelString_U.Length = (USHORT)(VolInfoBuffer.VolumeInfo.VolumeLabelLength);
+ LabelString_U.MaximumLength = (USHORT)(LabelString_U.Length +(USHORT)1);
+ LabelString_U.Buffer = VolInfoBuffer.VolumeInfo.VolumeLabel;
+ LabelString.Length = (USHORT)VolInfoBuffer.VolumeInfo.VolumeLabelLength;
+ LabelString.MaximumLength = LabelString.Length + (USHORT)1;
+ LabelString.Buffer = FsInfoBuf->vol.szVolLabel;
+ RetCode = Od2UnicodeStringToMBString(&LabelString,
+ &LabelString_U,
+ FALSE);
+ FsInfoBuf->vol.cch = (BYTE) LabelString.Length;
+#if DBG
+ IF_OD2_DEBUG( FSD ) {
+ DbgPrint("volume label length is %d and label is %s\n",FsInfoBuf->vol.cch,FsInfoBuf->vol.szVolLabel);
+ }
+#endif
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ }
+ return RetCode;
+}
+
+APIRET
+DosSetFSInfo(
+ ULONG DiskNumber,
+ ULONG FsInformationLevel,
+ PBYTE Buffer,
+ ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets label information for a volume.
+
+Arguments:
+
+ DiskNumber - which volume to set information for
+
+ FsInformationLevel - what type of information to set
+
+ Buffer - information to set
+
+ Length - length of buffer
+
+Return Value:
+
+ ERROR_INVALID_LEVEL - invalid FsInformationLevel
+
+ ERROR_INVALID_DRIVE - specified volume does not exist
+
+ ERROR_INSUFFICIENT_BUFFER - buffer is too small to contain specified
+ information
+
+--*/
+
+{
+ APIRET RetCode;
+ NTSTATUS Status;
+ HANDLE DiskHandle;
+ IO_STATUS_BLOCK IoStatus;
+ struct LABEL_BUFFER {
+ FILE_FS_LABEL_INFORMATION LabelInfo;
+ WCHAR Label[MAX_LABEL_LENGTH];
+ } LabelBuffer;
+
+ if (DiskNumber > MAX_DRIVES) {
+ return ERROR_INVALID_DRIVE;
+ }
+ if (FsInformationLevel != FSIL_VOLSER) {
+ return ERROR_INVALID_LEVEL;
+ }
+ RetCode = OpenDrive(DiskNumber,
+ FILE_WRITE_DATA,
+ &DiskHandle
+ );
+ if (RetCode != NO_ERROR) {
+ return RetCode;
+ }
+ RetCode = ProcessLabel((PVOLUMELABEL) Buffer,
+ Length,
+ (PFILE_FS_LABEL_INFORMATION) &LabelBuffer
+ );
+ if (RetCode != NO_ERROR) {
+ NtClose(DiskHandle);
+ return RetCode;
+ }
+ do {
+ Status = NtSetVolumeInformationFile(DiskHandle,
+ &IoStatus,
+ &LabelBuffer,
+ sizeof(LabelBuffer),
+ FileFsLabelInformation
+ );
+ } while (RetryIO(Status, DiskHandle));
+ NtClose(DiskHandle);
+ if (!NT_SUCCESS(Status)) {
+ if (Status == STATUS_INVALID_VOLUME_LABEL)
+ return ERROR_INVALID_NAME;
+ else
+ return ERROR_INVALID_DRIVE;
+ }
+ return NO_ERROR;
+}
+
+
+APIRET
+OpenDrive(
+ IN ULONG DiskNumber,
+ IN ULONG RequestedAccess,
+ OUT PHANDLE DriveHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a drive and returns a handle to it.
+
+Arguments:
+
+ DiskNumber - which volume to open
+
+ RequestedAccess - requested open access to drive
+
+ DriveHandle - where to return open handle to drive
+
+Return Value:
+
+ ERROR_INVALID_DRIVE - specified volume does not exist
+
+--*/
+
+{
+ CHAR DiskName[] = "\\OS2SS\\DRIVES\\D:\\";
+ STRING DiskNameString;
+ UNICODE_STRING DiskNameString_U;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ APIRET RetCode;
+
+
+ if (DiskNumber == 0) // default drive
+ DiskNumber = Od2CurrentDisk;
+ else
+ DiskNumber -= 1; // make drive 0-based
+ // BUGBUG when we add remote drives, need to fix this
+ DiskName[DRIVE_LETTER+FILE_PREFIX_LENGTH] = (CHAR) (DiskNumber + 'A');
+ Od2InitMBString(&DiskNameString,DiskName);
+
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &DiskNameString_U,
+ &DiskNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("OpenDrive: no memory for Unicode Conversion\n");
+ }
+#endif
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &DiskNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ do {
+ Status = NtOpenFile(DriveHandle,
+ RequestedAccess | SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+ RtlFreeUnicodeString (&DiskNameString_U);
+ if (!NT_SUCCESS(Status)) {
+ return ERROR_INVALID_DRIVE;
+ }
+ return NO_ERROR;
+}
+
+APIRET
+ProcessLabel(
+ IN PVOLUMELABEL Buffer,
+ IN ULONG Length,
+ OUT PFILE_FS_LABEL_INFORMATION LabelBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks a volume label for validity and copies it to an
+ NT buffer.
+
+Arguments:
+
+ Buffer - buffer containing os/2 format volume label (unprobed)
+
+ Length - length of buffer
+
+ LabelBuffer - where to store processed label
+
+Return Value:
+
+ ERROR_INSUFFICIENT_BUFFER - buffer is too small to contain the label
+
+ ERROR_LABEL_TOO_LONG - the volume label is too long
+
+--*/
+
+{
+ STRING LabelString;
+ APIRET RetCode;
+ UNICODE_STRING LabelString_U;
+
+ if (!Length)
+ return ERROR_INSUFFICIENT_BUFFER;
+ try {
+ LabelBuffer->VolumeLabelLength = Buffer->cch;
+ if ((LabelBuffer->VolumeLabelLength+1) > Length)
+ return ERROR_INSUFFICIENT_BUFFER;
+ if (LabelBuffer->VolumeLabelLength > MAX_LABEL_LENGTH)
+ return ERROR_LABEL_TOO_LONG;
+
+ Od2InitMBString(&LabelString,(PSZ)(Buffer->szVolLabel));
+#ifdef DBCS
+// MSKK Nov.04.1993 V-AkihiS
+ LabelString.Length = Buffer->cch;
+#endif
+
+
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &LabelString_U,
+ &LabelString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("ProcessLabel: no memory for Unicode Conversion\n");
+ }
+#endif
+ return RetCode;
+ }
+
+#ifdef DBCS
+// MSKK Apr.18.1993 V-AkihiS
+ //
+ // Use UNICODE string length as volume label Length for DBCS support.
+ //
+ LabelBuffer->VolumeLabelLength = LabelString_U.Length;
+#else
+ //
+ // Since we are talking WCHAR, double length
+ //
+ LabelBuffer->VolumeLabelLength = LabelBuffer->VolumeLabelLength * 2;
+#endif
+
+ RtlMoveMemory(&(LabelBuffer->VolumeLabel),
+ LabelString_U.Buffer,
+ LabelBuffer->VolumeLabelLength);
+
+ RtlFreeUnicodeString (&LabelString_U);
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return NO_ERROR;
+}
+
+APIRET
+DosFSCtl(
+ IN PBYTE Data,
+ IN ULONG DataLength,
+ OUT PULONG ActualDataLength,
+ IN PBYTE Parameters,
+ IN ULONG ParametersLength,
+ IN OUT PULONG ActualParametersLength,
+ IN ULONG Function,
+ IN PSZ RouteName,
+ IN HFILE FileHandle,
+ IN ULONG RoutingMethod
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+BUGBUG whenever this is sorted out, finish probing parms
+
+--*/
+
+{
+#if 0
+ HANDLE NtHandle;
+ NTSTATUS Status;
+ APIRET RetCode;
+ STRING CanonicalNameString;
+ UNICODE_STRING CanonicalNameString_U;
+ ULONG FileType;
+ ULONG FileFlags;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ PFILE_HANDLE hFileRecord;
+#endif
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosFSCtl";
+ #endif
+
+ UNREFERENCED_PARAMETER(ParametersLength);
+
+ UNREFERENCED_PARAMETER(Data);
+ UNREFERENCED_PARAMETER(DataLength);
+ UNREFERENCED_PARAMETER(ActualDataLength);
+ UNREFERENCED_PARAMETER(Parameters);
+ UNREFERENCED_PARAMETER(ActualParametersLength);
+ UNREFERENCED_PARAMETER(Function);
+ UNREFERENCED_PARAMETER(RouteName);
+ UNREFERENCED_PARAMETER(FileHandle);
+ UNREFERENCED_PARAMETER(RoutingMethod);
+
+ return ERROR_INVALID_FUNCTION;
+
+#if 0
+ if ((RoutingMethod < FSCTL_HANDLE) || (RoutingMethod > FSCTL_FSDNAME))
+ return ERROR_INVALID_LEVEL;
+
+ if (RoutingMethod == FSCTL_HANDLE) {
+ if (RouteName != NULL)
+ return ERROR_INVALID_PARAMETER;
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
+ if (RetCode != NO_ERROR) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ if (hFileRecord->FileType &
+ (FILE_TYPE_DEV | FILE_TYPE_PIPE | FILE_TYPE_NMPIPE)) {
+ // BUGBUG at some point, NMPIPE and DEV will probably be ok
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE;
+ }
+ else {
+ NtHandle = hFileRecord->NtHandle;
+ }
+ }
+ else if (RoutingMethod == FSCTL_PATHNAME) {
+ if (FileHandle != (HFILE) -1)
+ return ERROR_INVALID_PARAMETER;
+ // BUGBUG need to append \ if d:
+ RetCode = Od2Canonicalize(RouteName,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &CanonicalNameString,
+ &NtHandle,
+ &FileFlags, // BUGBUG should we fail if root?
+ &FileType
+ );
+ if (RetCode != NO_ERROR) {
+ return ERROR_INVALID_PATH;
+ }
+ if (FileType & (FILE_TYPE_DEV | FILE_TYPE_PSDEV | FILE_TYPE_NMPIPE)) {
+ RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
+ return ERROR_INVALID_PATH;
+ }
+#if DBG
+ IF_OD2_DEBUG( FSD ) {
+ DbgPrint("canonicalize returned %s\n",CanonicalNameString.Buffer);
+ }
+#endif
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &CanonicalNameString_U,
+ &CanonicalNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("DosFSCtl: no memory for Unicode Conversion\n");
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ NtHandle,
+ NULL);
+
+ do {
+ Status = NtOpenFile(&NtHandle,
+ SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+ RtlFreeUnicodeString (&CanonicalNameString_U);
+
+
+ if (!(NT_SUCCESS(Status))) {
+ RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
+#if DBG
+ IF_OD2_DEBUG( FSD ) {
+ DbgPrint("NtOpenFile returned %X\n",Status);
+ }
+#endif
+ return ERROR_PATH_NOT_FOUND; // BUGBUG bogus error
+ }
+ }
+ else { // FSCTL_FSDNAME
+ if (FileHandle != (HFILE) -1)
+ return ERROR_INVALID_PARAMETER;
+ try {
+ Od2InitMBString(&CanonicalNameString,RouteName);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &CanonicalNameString_U,
+ &CanonicalNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("DosFSCtl: no memory for Unicode Conversion-2\n");
+ }
+#endif
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ do {
+ Status = NtOpenFile(&NtHandle,
+ SYNCHRONIZE,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ } while (RetryCreateOpen(Status, &Obja));
+ RtlFreeUnicodeString (&CanonicalNameString_U);
+
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OD2_DEBUG( FSD ) {
+ DbgPrint("NtOpenFile returned %X\n",Status);
+ }
+#endif
+ return ERROR_INVALID_FSD_NAME;
+ }
+ }
+
+ Status = NtFsControlFile(NtHandle,
+ (HANDLE) NULL,
+ (PIO_APC_ROUTINE) NULL,
+ (PVOID) NULL,
+ &IoStatus,
+ Function,
+ (PVOID) Parameters,
+ *ActualParametersLength,
+ (PVOID) Data,
+ DataLength
+ );
+
+ if (RoutingMethod == FSCTL_HANDLE) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ }
+ else if (RoutingMethod == FSCTL_PATHNAME) {
+ NtClose(NtHandle);
+ RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
+ }
+ else { // FSCTL_FSDNAME
+ NtClose(NtHandle);
+ }
+ if (!NT_SUCCESS(Status)) {
+ if (Status == STATUS_BUFFER_OVERFLOW)
+ return ERROR_BUFFER_OVERFLOW;
+ else
+ return ERROR_INVALID_FUNCTION; // BUGBUG errors should be mapped
+ }
+ else {
+ try {
+ *ActualDataLength = IoStatus.Information;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return NO_ERROR;
+ }
+#endif
+}
+
+
+APIRET
+DosFSAttach(
+ IN PSZ DeviceName,
+ IN PSZ FsName,
+ IN PBYTE FsData,
+ IN ULONG FsDataLength,
+ IN ULONG AttachFlags
+ )
+
+/*++
+
+Routine Description:
+
+ This function partially implements the DosFSAttach() API. The only valid FsName is "LAN".
+ The format expected for the arguments is as follows:
+
+ DeviceName -- device name, e.g. "J:", "LPT1:"
+ FsName -- "LAN"
+ FsData -- either "\01\0SHARENAME" for a regular connection or
+ "\02\0SHARENAME\0PASSWORD" for a password connection or
+ "\03\0SHARENAME\0PASSWORD\0USERNAME" for a username/password connection.
+ FsDataLength -- length of FsData
+ AttachFlags -- FS_ATTACH or FS_DETACH
+
+ The function connects to the network using WNetAdd/DelConnection(). Therefore it'll use the
+ multiple provider router to connect to any type of network for which NT has a redirector.
+ The SHARENAME format depends on the network you're trying to reach. for LanMan/MsNet networks
+ it's "\\\\sharename\\servername".
+
+ If DeviceName is a drive letter, the drive is automatically reset to the root directory after
+ a connection, and before a disconnection. This is for compatibility with OS/2.
+
+Arguments:
+
+ see above + documentation of DosFSAttach().
+
+Return Value:
+
+ error status.
+
+--*/
+
+{
+ NETRESOURCEA netr;
+ PSZ passwd = NULL;
+ PSZ username = NULL;
+ ULONG Drive = (ULONG)-1;
+ ULONG Length;
+ ULONG rc;
+ APIRET nrc;
+ CHAR DriveBuf[4];
+
+ try {
+ PROBE_STRING(DeviceName);
+ PROBE_STRING(FsName);
+ Od2ProbeForRead(FsData, FsDataLength, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (FsName == NULL ||
+ _stricmp(FsName, "LAN") != 0) {
+#if DBG
+ IF_OD2_DEBUG( FSD ) {
+ KdPrint(("DosFSAttach: Invalid FSD name\n"));
+ }
+#endif
+ return(ERROR_INVALID_FSD_NAME);
+ }
+
+ if (DeviceName != NULL &&
+ DeviceName[0] != '\0' &&
+ DeviceName[1] == ':' &&
+ DeviceName[2] == '\0') { // is the device a disk drive?
+
+ int ch;
+
+ ch = toupper((UCHAR) DeviceName[0]);
+
+ if (isalpha(ch)) {
+
+ Drive = (ULONG) (ch - 'A');
+
+ if (Od2CurrentDisk == Drive) {
+#if DBG
+ IF_OD2_DEBUG( FSD ) {
+ KdPrint(("DosFSAttach: attempt to attach/detach current drive = %ld\n", Drive));
+ }
+#endif
+ return(ERROR_DEVICE_IN_USE);
+ }
+
+ DriveBuf[0] = (UCHAR) ch;
+ DriveBuf[1] = ':';
+ DriveBuf[2] = '\\';
+ DriveBuf[3] = '\0';
+
+ } else {
+#if DBG
+ IF_OD2_DEBUG( FSD ) {
+ KdPrint(("DosFSAttach: Invalid drive letter = %c\n", ch));
+ }
+#endif
+ return(ERROR_INVALID_DRIVE);
+ }
+ }
+
+ if (AttachFlags == FS_ATTACH) {
+
+ if (FsDataLength < 3 ||
+ FsData[0] == 0 ||
+ FsData[0] > 3 ||
+ FsData[1] != 0) {
+#if DBG
+ IF_OD2_DEBUG( FSD ) {
+ KdPrint(("DosFSAttach: Unsupported FsData structure\n"));
+ }
+#endif
+ return(ERROR_NOT_SUPPORTED);
+ }
+
+ netr.lpLocalName = DeviceName;
+ netr.lpRemoteName = (PSZ) FsData + 2;
+
+ try {
+
+ Length = strlen(netr.lpRemoteName);
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ netr.lpProvider = NULL;
+ netr.dwType = RESOURCETYPE_ANY;
+
+ if (FsData[0] >= 2) {
+
+ passwd = netr.lpRemoteName + Length + 1;
+ if (FsData + FsDataLength <= passwd) {
+#if DBG
+ IF_OD2_DEBUG( FSD ) {
+ KdPrint(("DosFSAttach: FsData overflow\n"));
+ }
+#endif
+ return(ERROR_INVALID_PATH);
+ }
+
+ try {
+
+ Length = strlen(passwd);
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (FsData[0] == 3) {
+
+ username = passwd + Length + 1;
+ if (FsData + FsDataLength <= username) {
+#if DBG
+ IF_OD2_DEBUG( FSD ) {
+ KdPrint(("DosFSAttach: FsData overflow\n"));
+ }
+#endif
+ return(ERROR_INVALID_PATH);
+ }
+
+ try {
+
+ (VOID) strlen(username);
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ }
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FSD ) {
+ KdPrint(("DosFSAttach: calling WNetAddConnection2()\n"));
+ }
+#endif
+
+ rc = WNetAddConnection2A(&netr,
+ passwd,
+ username,
+ 0);
+
+ if (rc == NO_ERROR && Drive != (ULONG)-1) {
+
+ //
+ // initialize the connection to the root directory on target drive
+ //
+
+ (VOID) DosSetCurrentDir(DriveBuf);
+ }
+
+ } else if (AttachFlags == FS_DETACH) {
+
+ if (Drive != (ULONG)-1) {
+
+ //
+ // go back to root directory on target drive
+ //
+
+ (VOID) DosSetCurrentDir(DriveBuf);
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FSD ) {
+ KdPrint(("DosFSAttach: calling WNetCancelConnection2()\n"));
+ }
+#endif
+
+ //
+ // In the case that the disk that will be deattached is the current disk
+ // (from Win32 point of view), change the current disk according to
+ // OS2 ss (Od2CurrentDisk).
+ //
+ {
+ PSZ pBuffer;
+ DWORD length;
+
+ length = GetCurrentDirectoryA(0, NULL);
+ pBuffer = RtlAllocateHeap(Od2Heap, 0, length);
+ GetCurrentDirectoryA(length, pBuffer);
+ if (toupper(pBuffer[0]) == toupper(DeviceName[0])) {
+ DriveBuf[0] = (UCHAR) Od2CurrentDisk + 'A';
+ DriveBuf[1] = ':';
+ DriveBuf[2] = '\0';
+ SetCurrentDirectoryA(DriveBuf);
+ }
+ RtlFreeHeap(Od2Heap, 0, pBuffer);
+ }
+
+ rc = WNetCancelConnection2A(DeviceName,
+ 0,
+ TRUE);
+ } else {
+#if DBG
+ IF_OD2_DEBUG( FSD ) {
+ KdPrint(("DosFSAttach: Invalid level\n"));
+ }
+#endif
+ return(ERROR_INVALID_LEVEL);
+ }
+
+ switch (rc) {
+
+ case NO_ERROR:
+ nrc = NO_ERROR;
+ break;
+
+ case ERROR_ACCESS_DENIED:
+ case ERROR_ALREADY_ASSIGNED:
+ case ERROR_BAD_DEV_TYPE:
+ case ERROR_INVALID_PASSWORD:
+ nrc = (APIRET) rc;
+ break;
+
+ case 1200L: /* ERROR_BAD_DEVICE */
+ case 2250L: /* ERROR_NOT_CONNECTED */
+ nrc = ERROR_INVALID_DRIVE;
+ break;
+
+ case ERROR_BAD_NET_NAME:
+ case 1203L: /* ERROR_NO_NET_OR_BAD_PATH */
+ case 2138L: /* ERROR_NO_NETWORK */
+ nrc = ERROR_INVALID_PATH;
+ break;
+
+ case 2404L: /* ERROR_DEVICE_IN_USE */
+ case 2401L: /* ERROR_OPEN_FILES */
+ nrc = ERROR_DEVICE_IN_USE;
+ break;
+
+ default:
+ nrc = ERROR_INVALID_PATH;
+ break;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FSD ) {
+ KdPrint(("DosFSAttach: rc = %lx, nrc = %x\n", rc, nrc));
+ }
+#endif
+
+ return(nrc);
+}
+
+/* Dos32FsAttach() */
+/* Attact or detach */
+//#define FS_ATTACH 0 /* Attach file server */
+//#define FS_DETACH 1 /* Detach file server */
+
+APIRET
+DosQueryFSAttach(
+ IN PSZ DeviceName,
+ IN ULONG Ordinal,
+ IN ULONG FsInformationLevel,
+ OUT PBYTE FsAttributes,
+ IN OUT PULONG FsAttributesLength
+ )
+
+/*++
+
+Routine Description:
+
+ BUGBUG - Note that the FSAData[] field is left empty for local drives.
+ Query by ordinal is not supported.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ ULONG DriveNumber;
+ USHORT NameLength;
+ PFSQBUFFER2 BufPtr;
+ char *StrPtr;
+ APIRET rc;
+
+ if ((FsInformationLevel < FSAIL_QUERYNAME) ||
+ (FsInformationLevel > FSAIL_DRVNUMBER)) {
+ return ERROR_INVALID_LEVEL;
+ }
+ BufPtr = (PFSQBUFFER2) FsAttributes;
+ try {
+ if (*FsAttributesLength < (sizeof(FSQBUFFER)-1))
+ return ERROR_BUFFER_OVERFLOW;
+ if (FsInformationLevel == FSAIL_QUERYNAME)
+ {
+ NTSTATUS Status;
+ STRING TargetCanonicalName;
+ UNICODE_STRING TargetUnicodeName;
+ ULONG TargetType;
+ ULONG TargetFlags;
+ OBJECT_ATTRIBUTES object_attributes;
+ ULONG attr_len;
+ char actual_file_name[256];
+ /* Local parameters for the NtOpenFile() call */
+ IO_STATUS_BLOCK io_status_block;
+ HANDLE hand;
+ /* For NtQueryInformationFile */
+ char tmp_buf[1024];
+ PFILE_FS_ATTRIBUTE_INFORMATION pFileFsInfo;
+ FILE_FS_DEVICE_INFORMATION DeviceInfo;
+
+ /* Handle the non X: case */
+ if (DeviceName[COLON] != ':')
+ {
+ STRING TargetCanonicalName;
+ ULONG TargetType;
+ ULONG TargetFlags;
+
+ /* If not a drive letter, then must be \DEV\xxx or
+ /DEV/xxx */
+ if ((_strnicmp(DeviceName,"\\DEV\\",5)) &&
+ (_strnicmp(DeviceName,"/DEV/",5)))
+ {
+ return ERROR_INVALID_PATH;
+ }
+
+ NameLength = (USHORT)strlen(DeviceName);
+
+ rc = Od2Canonicalize(DeviceName,
+ CANONICALIZE_FILE_OR_DEV,
+ &TargetCanonicalName,
+ NULL,
+ &TargetFlags,
+ &TargetType);
+
+ if (rc != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint(
+ "DosQueryFSAttach: Failed to Od2Canonicalize(\"%s\") - rc = %x\n",
+ DeviceName, rc);
+ }
+#endif
+ return ERROR_INVALID_PATH;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("Canonical name is <%s>\n",
+ TargetCanonicalName.Buffer);
+ }
+#endif
+ /* BUGBUG - Check meaning of code below (from 'dllcopy.c, DosCopy()) */
+ if (TargetFlags & CANONICALIZE_META_CHARS_FOUND)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("DosQueryFSAttach: <%s> has META_CHARS\n",
+ DeviceName);
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0,TargetCanonicalName.Buffer);
+ return ERROR_INVALID_PATH;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("Type = <%x>, Flags = <%x>\n",
+ TargetType, TargetFlags);
+ }
+#endif
+
+ if (!(TargetType & FILE_TYPE_DEV) &&
+ !(TargetType & FILE_TYPE_PSDEV) &&
+ !(TargetType & FILE_TYPE_COM))
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("DosQueryFSAttach: <%s> is not a valid device\n",
+ DeviceName);
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0,TargetCanonicalName.Buffer);
+ return ERROR_INVALID_PATH;
+ }
+
+ /* Note that although some devices are marked as pseudo, under
+ OS/2 1.21, I found none such devices, hence the line below */
+ BufPtr->iType = FSAT_CHARDEV;
+ BufPtr->cbName = NameLength;
+ BufPtr->cbFSDName = 0;
+ BufPtr->cbFSAData = 0;
+ StrPtr = BufPtr->szName;
+ strncpy(StrPtr,DeviceName,NameLength+1);
+ _strupr(StrPtr); /* Convert string to uppercase, just like under OS/2 1.x */
+ StrPtr += NameLength+1;
+ StrPtr[0] = '\0'; /* "" - no file-system name for \\dev\xxx */
+ *FsAttributesLength = (ULONG)(StrPtr
+ + BufPtr->cbFSDName + 1
+ + BufPtr->cbFSAData
+ - (PBYTE)BufPtr);
+ RtlFreeHeap(Od2Heap, 0,TargetCanonicalName.Buffer);
+
+ return NO_ERROR;
+ }
+
+ DriveNumber = (ULONG) (UCase(DeviceName[DRIVE_LETTER]) - 'A');
+ if ((DeviceName[FIRST_SLASH] != '\0') ||
+ (DriveNumber >= MAX_DRIVES))
+ {
+ return ERROR_INVALID_DRIVE;
+ }
+
+ strcpy(actual_file_name, DeviceName);
+ strcat(actual_file_name,"\\");
+
+ rc = Od2Canonicalize(actual_file_name,
+ CANONICALIZE_FILE_OR_DEV,
+ &TargetCanonicalName,
+ NULL,
+ &TargetFlags,
+ &TargetType);
+
+ if (rc != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint(
+ "DosQueryFSAttach: Failed to Od2Canonicalize(\"%s\") - rc = %x\n",
+ actual_file_name, rc);
+ }
+#endif
+ return ERROR_INVALID_DRIVE;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("Canonical name is <%s>\n",
+ TargetCanonicalName.Buffer);
+ }
+#endif
+
+ rc = Od2MBStringToUnicodeString(
+ &TargetUnicodeName,
+ &TargetCanonicalName,
+ TRUE);
+
+ if (rc)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("DosQueryFSAttach: no memory for Unicode Conversion\n");
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0,TargetCanonicalName.Buffer);
+ return rc;
+ }
+
+ RtlFreeHeap(Od2Heap, 0, TargetCanonicalName.Buffer);
+
+ InitializeObjectAttributes(
+ &object_attributes,
+ &TargetUnicodeName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE) NULL,
+ NULL);
+
+ do {
+ Status = NtOpenFile(
+ &hand,
+ SYNCHRONIZE | FILE_READ_ATTRIBUTES,
+ &object_attributes,
+ &io_status_block,
+ FILE_SHARE_READ,
+ FILE_DIRECTORY_FILE
+ );
+ } while (RetryCreateOpen(Status, &object_attributes));
+
+ RtlFreeUnicodeString(&TargetUnicodeName);
+
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint(
+ "DosQueryFSAttach: Failed to NtOpenFile (%s) - rc = %x\n",
+ DeviceName, Status);
+ }
+#endif
+ return ERROR_INVALID_DRIVE;
+ }
+
+ do {
+ Status = NtQueryVolumeInformationFile(
+ hand,
+ &io_status_block,
+ tmp_buf,
+ 1024,
+ FileFsAttributeInformation
+ );
+ } while (RetryIO(Status, hand));
+
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint(
+ "DosQueryFSAttach: Failed to NtQueryVolumeInformation (%s) - rc = %x\n",
+ DeviceName, Status);
+ }
+#endif
+ NtClose(hand);
+ return ERROR_INVALID_DRIVE;
+ }
+
+ do {
+ Status = NtQueryVolumeInformationFile(
+ hand,
+ &io_status_block,
+ &DeviceInfo,
+ sizeof (DeviceInfo),
+ FileFsDeviceInformation);
+ } while (RetryIO(Status, hand));
+
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint(
+ "DosQueryFSAttach: Failed to NtQueryVolumeInformation (%s) - rc = %x\n",
+ DeviceName, Status);
+ }
+#endif
+ NtClose(hand);
+ return ERROR_INVALID_DRIVE;
+ }
+
+ pFileFsInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)tmp_buf;
+ BufPtr->cbFSAData = 0;
+ StrPtr = BufPtr->szName;
+ strcpy(StrPtr,DeviceName);
+ BufPtr->cbName = (USHORT)strlen(StrPtr);
+ _strupr(StrPtr); /* Convert string to uppercase, just like under OS/2 1.x */
+ StrPtr += BufPtr->cbName + 1;
+
+ Od2nCopyWstrToStr(StrPtr, pFileFsInfo->FileSystemName,
+ pFileFsInfo->FileSystemNameLength/2);
+
+ if (DeviceInfo.Characteristics & FILE_REMOTE_DEVICE)
+ {
+ // NT returns FAT, HPFS & NTFS (xlated above to HPFS) even for
+ // LAN drives, so fix it to be 'LAN' as under OS/2
+ strcpy(StrPtr, "LAN");
+ }
+ //Translate NTFS to HPFS (the closest OS/2 equivalent)
+ else if (!strcmp(StrPtr, "NTFS"))
+ strcpy(StrPtr, "HPFS");
+
+ BufPtr->cbFSDName = (USHORT)strlen(StrPtr); /* File-system name length,
+ not including the \0 */
+
+ if (DeviceInfo.Characteristics & FILE_REMOTE_DEVICE)
+ {
+ char tmp_buf[256];
+ ULONG count = 256;
+
+ BufPtr->iType = FSAT_REMOTEDRV;
+ // Get the share name for the drive, if possible
+ if (!WNetGetConnectionA(
+ BufPtr->szName, // drive letter
+ tmp_buf, // result buffer
+ &count))
+ {
+ if ((ULONG)(StrPtr
+ + BufPtr->cbFSDName + 1
+ + BufPtr->cbFSAData
+ + strlen(tmp_buf) + 1
+ - (PBYTE)BufPtr) <=
+ *FsAttributesLength)
+ {
+ try
+ {
+ strcpy(StrPtr + BufPtr->cbFSDName + 1,
+ tmp_buf);
+#ifdef DBCS
+// MSKK Jul.22.1993 V-AkihiS
+// cbFSAData counts null.
+ BufPtr->cbFSAData = strlen(StrPtr + BufPtr->cbFSDName + 1) + 1;
+#else
+ BufPtr->cbFSAData = strlen(StrPtr + BufPtr->cbFSDName + 1);
+#endif
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ // Just ignore error
+ BufPtr->cbFSAData = 0; // Just in case ...
+ }
+ }
+ }
+ }
+ else
+ BufPtr->iType = FSAT_LOCALDRV;
+
+ attr_len = (ULONG)(StrPtr
+ + BufPtr->cbFSDName + 1
+ + BufPtr->cbFSAData
+ - (PBYTE)BufPtr);
+
+#if NEVER
+ /* If one is interested, here's the full list: */
+ switch (DeviceInfo.DeviceType)
+ {
+ case FILE_DEVICE_CD_ROM:
+ case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
+ case FILE_DEVICE_DISK:
+ case FILE_DEVICE_DISK_FILE_SYSTEM:
+ case FILE_DEVICE_FILE_SYSTEM:
+ case FILE_DEVICE_VIRTUAL_DISK:
+ case FILE_DEVICE_NETWORK:
+ case FILE_DEVICE_NETWORK_FILE_SYSTEM:
+ case FILE_DEVICE_TAPE:
+ case FILE_DEVICE_TAPE_FILE_SYSTEM:
+ case FILE_DEVICE_CONTROLLER:
+ case FILE_DEVICE_DATALINK:
+ case FILE_DEVICE_DFS:
+ case FILE_DEVICE_KEYBOARD:
+ case FILE_DEVICE_MAILSLOT:
+ case FILE_DEVICE_MOUSE:
+ case FILE_DEVICE_NAMED_PIPE:
+ case FILE_DEVICE_NULL:
+ case FILE_DEVICE_PARALLEL_PORT:
+ case FILE_DEVICE_PHYSICAL_NETCARD:
+ case FILE_DEVICE_PRINTER:
+ case FILE_DEVICE_SERIAL_PORT:
+ case FILE_DEVICE_SCREEN:
+ case FILE_DEVICE_SOUND:
+ case FILE_DEVICE_STREAMS:
+ case FILE_DEVICE_TRANSPORT:
+ case FILE_DEVICE_UNKNOWN:
+ case FILE_DEVICE_NETWORK_BROWSER:
+ case FILE_DEVICE_WAVE_IN:
+ case FILE_DEVICE_WAVE_OUT:
+ case FILE_DEVICE_8042_PORT:
+ case FILE_DEVICE_INPORT_PORT:
+ case FILE_DEVICE_SERIAL_MOUSE_PORT:
+ case FILE_DEVICE_BEEP:
+ case FILE_DEVICE_SCANNER:
+ case FILE_DEVICE_VIDEO:
+ case FILE_DEVICE_MULTIPLE_UNC_PROVIDER:
+ }
+#endif /* NEVER */
+
+ /* Update the user-supplied output value only after all has succeeded */
+ /* BUGBUG - We should do that same for the FsInformation buffer */
+ *FsAttributesLength = attr_len;
+ NtClose(hand);
+ }
+ else
+ {
+ /* BUGBUG - Query by ordinal not supported */
+ if (!Ordinal)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+ return ERROR_INVALID_FUNCTION;
+ }
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+ return NO_ERROR;
+}
+
+
+/* DosQueryFSAttach() */
+/* Information level types (defines method of query) */
+//#define FSAIL_QUERYNAME 1 /* Return data for a Drive or Device */
+//#define FSAIL_DEVNUMBER 2 /* Return data for Ordinal Device # */
+//#define FSAIL_DRVNUMBER 3 /* Return data for Ordinal Drive # */
+
+/* Item types (from data structure item "iType") */
+//#define FSAT_CHARDEV 1 /* Resident character device */
+//#define FSAT_PSEUDODEV 2 /* Pseudo-character device */
+//#define FSAT_LOCALDRV 3 /* Local drive */
+//#define FSAT_REMOTEDRV 4 /* Remote drive attached to FSD */
diff --git a/private/os2/client/dllhandl.c b/private/os2/client/dllhandl.c
new file mode 100644
index 000000000..4f87f6fc0
--- /dev/null
+++ b/private/os2/client/dllhandl.c
@@ -0,0 +1,6367 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllhandl.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 file handle manipulation API calls
+
+Author:
+
+ Therese Stowell (thereses) 19-Oct-1989
+
+Revision History:
+
+ Yaron Shamir (yarons) 20-May-1991
+ fix bugs found by fileio test suite (map error code in OpenCreatePath)
+
+--*/
+
+//
+// Serialization
+//
+// File I/O must be serialized in three ways:
+// 1) on a per-file basis to prevent disk corruption
+// 2) on a per-open instance basis to prevent corruption of
+// the file pointer and other per open instance data and
+// to prevent one thread from closing the handle while
+// another thread is performing a handle-based operation
+// 3) on a per-process basis to prevent corruption of the file
+// handle table.
+//
+// The NT IO system performs the first two types of serialization when
+// synchronous IO mode is used. The OS/2 subsystem performs the third
+// type of serialization using a spin lock, AcquireFileLock(). This
+// lock allows multiple readers and one writer.
+//
+
+// BUGBUG to speed up some calls, store access in handle table
+
+
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FILESYS
+#include "os2dll.h"
+#include "conrqust.h"
+
+
+NTSTATUS
+Od2AlertableWaitForSingleObject(
+ IN HANDLE handle
+ );
+
+
+OS2IO_VECTORS NulVectors = {
+ NulOpenRoutine,
+ NonFileSetHandleStateRoutine,
+ DeviceQueryHTypeRoutine,
+ DeviceCloseRoutine,
+ DeviceDupHandleRoutine,
+ NulReadRoutine,
+ NulWriteRoutine
+ };
+
+OS2IO_VECTORS ConVectors = {
+ ConOpenRoutine,
+ NonFileSetHandleStateRoutine,
+ DeviceQueryHTypeRoutine,
+ DeviceCloseRoutine,
+ DeviceDupHandleRoutine,
+ ConReadRoutine,
+ ScreenWriteRoutine
+ };
+
+OS2IO_VECTORS ComVectors = {
+ ComOpenRoutine,
+ NonFileSetHandleStateRoutine,
+ DeviceQueryHTypeRoutine,
+ ComCloseRoutine,
+ ComDupHandleRoutine,
+ ComReadRoutine,
+ ComWriteRoutine
+ };
+
+OS2IO_VECTORS LptVectors = {
+ LptOpenRoutine,
+ NonFileSetHandleStateRoutine,
+ DeviceQueryHTypeRoutine,
+ DeviceCloseRoutine,
+ DeviceDupHandleRoutine,
+ TmpReadRoutine,
+ TmpWriteRoutine
+// LptReadRoutine,
+// LptWriteRoutine
+ };
+
+OS2IO_VECTORS KbdVectors = {
+ KbdOpenRoutine,
+ NonFileSetHandleStateRoutine,
+ DeviceQueryHTypeRoutine,
+ KbdCloseRoutine,
+ KbdDupHandleRoutine,
+ KbdReadRoutine,
+ NulWriteRoutine
+ };
+
+OS2IO_VECTORS MouseVectors = {
+ MouseOpenRoutine,
+ NonFileSetHandleStateRoutine,
+ DeviceQueryHTypeRoutine,
+ MouseCloseRoutine,
+ MouseDupHandleRoutine,
+ TmpReadRoutine,
+ TmpWriteRoutine
+// MouseReadRoutine,
+// MouseWriteRoutine
+ };
+
+OS2IO_VECTORS ClockVectors = {
+ ClockOpenRoutine,
+ NonFileSetHandleStateRoutine,
+ DeviceQueryHTypeRoutine,
+ DeviceCloseRoutine,
+ DeviceDupHandleRoutine,
+ TmpReadRoutine,
+ TmpWriteRoutine
+// ClockReadRoutine,
+// ClockWriteRoutine
+ };
+
+OS2IO_VECTORS ScreenVectors = {
+ ScreenOpenRoutine,
+ NonFileSetHandleStateRoutine,
+ DeviceQueryHTypeRoutine,
+ DeviceCloseRoutine,
+ DeviceDupHandleRoutine,
+ NulReadRoutine,
+ ScreenWriteRoutine
+// ScreenReadRoutine,
+// ScreenWriteRoutine
+ };
+
+OS2IO_VECTORS PointerVectors = {
+ PointerOpenRoutine,
+ NonFileSetHandleStateRoutine,
+ DeviceQueryHTypeRoutine,
+ DeviceCloseRoutine,
+ DeviceDupHandleRoutine,
+ TmpReadRoutine,
+ TmpWriteRoutine
+// PointerReadRoutine,
+// PointerWriteRoutine
+ };
+
+OS2IO_VECTORS FileVectors = {
+ FileOpenRoutine,
+ FileSetHandleStateRoutine,
+ FileQueryHTypeRoutine,
+ FileCloseRoutine,
+ FileDupHandleRoutine,
+ FileReadRoutine,
+ FileWriteRoutine
+ };
+
+OS2IO_VECTORS DeviceVectors = {
+ FileOpenRoutine,
+ NonFileSetHandleStateRoutine,
+ DeviceQueryHTypeRoutine,
+ FileCloseRoutine,
+ FileDupHandleRoutine,
+ FileReadRoutine,
+ FileWriteRoutine
+ };
+
+/*
+
+OS2IO_VECTORS PseudoDeviceVectors = {
+ PsDeviceSetHandleStateRoutine,
+ PsDeviceCloseRoutine,
+ PsDeviceDupHandleRoutine,
+ PsDeviceReadRoutine,
+ PsDeviceWriteRoutine
+ };
+*/
+
+OS2IO_VECTORS RemoteVectors = {
+ NULL,
+ RemoteSetHandleStateRoutine,
+ RemoteQueryHTypeRoutine,
+ RemoteCloseRoutine,
+ RemoteDupHandleRoutine,
+ RemoteReadRoutine,
+ RemoteWriteRoutine
+ };
+
+OS2IO_VECTORS MonitorVectors = {
+ NULL,
+ NoSuppSetHandleStateRoutine,
+ NoSuppQueryHTypeRoutine,
+ NoSuppCloseRoutine,
+ NoSuppDupHandleRoutine,
+ TmpReadRoutine,
+ TmpWriteRoutine
+// MonitorReadRoutine,
+// MonitorWriteRoutine
+ };
+
+
+
+POS2IO_VECTORS IoVectorArray[] = {&NulVectors,
+ &ConVectors,
+ &ComVectors, // same as AuxVectors
+ &LptVectors, // same as PrnVectors
+ &KbdVectors,
+ &MouseVectors,
+ &ClockVectors,
+ &ScreenVectors,
+ &PointerVectors,
+ &FileVectors,
+ &FileVectors, // &PipeVectors, (deleted)
+ &DeviceVectors,
+ &RemoteVectors,
+ &MonitorVectors
+ };
+
+VOID
+MapShareAccess(
+ IN ULONG OpenMode,
+ OUT PULONG DesiredAccess,
+ OUT PULONG ShareAccess
+ );
+
+APIRET
+DereferenceFileHandle(
+ IN HFILE FileHandle,
+ OUT PFILE_HANDLE *hFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps a file handle to a file handle record
+
+Arguments:
+
+ FileHandle - handle to map
+
+ hFileRecord - where to store pointer to file handle record
+
+Return Value:
+
+ ERROR_INVALID_HANDLE - handle is invalid
+
+Note:
+
+ File lock must be acquired shared or exclusive BEFORE calling this routine
+
+--*/
+
+{
+
+ //
+ // Check for invalid handle.
+ //
+
+ if ((((ULONG) FileHandle) >= HandleTableLength) ||
+ (!(HandleTable[(ULONG) FileHandle].Flags & FILE_HANDLE_VALID))) {
+ return ERROR_INVALID_HANDLE;
+ }
+ *hFileRecord = &(HandleTable[(ULONG) FileHandle]);
+ return NO_ERROR;
+}
+
+
+PFILE_HANDLE
+DereferenceFileHandleNoCheck(
+ IN HFILE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps a file handle to a file handle record without checking
+ the handle's validity
+
+Arguments:
+
+ FileHandle - handle to map
+
+Return Value:
+
+ pointer to file handle record
+
+Note:
+
+ File lock must be acquired shared or exclusive BEFORE calling this routine
+
+--*/
+
+{
+ return &(HandleTable[(ULONG) FileHandle]);
+}
+
+
+VOID
+InvalidateHandle(
+ IN PFILE_HANDLE hFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine marks an OS/2 file handle invalid.
+
+Arguments:
+
+ hFileRecord - pointer to record of OS/2 handle to mark invalid
+
+Return Value:
+
+ none.
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ if (hFileRecord->Flags & FILE_HANDLE_ALLOCATED) {
+ hFileRecord->Flags &= ~FILE_HANDLE_VALID;
+ }
+ else
+ ASSERT(FALSE);
+}
+
+
+
+VOID
+ValidateHandle(
+ IN PFILE_HANDLE hFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine marks an OS/2 file handle valid.
+
+Arguments:
+
+ hFileRecord - pointer to record of OS/2 handle to mark valid
+
+Return Value:
+
+ none.
+
+Note:
+
+ File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ if (hFileRecord->Flags & FILE_HANDLE_ALLOCATED) {
+ hFileRecord->Flags |= FILE_HANDLE_VALID;
+ }
+ else
+ ASSERT(FALSE);
+}
+
+
+
+APIRET
+AllocateHandle(
+ OUT PHFILE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates an OS/2 file handle. The file handle is marked
+ reserved but not valid. If another thread tries to use the handle, an
+ error will be returned.
+
+Arguments:
+
+ FileHandle - where to store the allocated handle (unprobed)
+
+Return Value:
+
+ ERROR_TOO_MANY_OPEN_FILES - no free file handles.
+
+Note:
+
+ File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ ULONG i;
+ for (i=0;i<HandleTableLength;i++) {
+ if (HandleTable[i].Flags == FILE_HANDLE_FREE) {
+ HandleTable[i].Flags = FILE_HANDLE_ALLOCATED;
+ try {
+ *FileHandle = (HFILE) i;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return NO_ERROR;
+ }
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] file handle allocation failed - no free handles.\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ return ERROR_TOO_MANY_OPEN_FILES;
+}
+
+
+
+APIRET
+FreeHandle(
+ IN HFILE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees an OS/2 file handle.
+
+Arguments:
+
+ FileHandle - handle to free
+
+Return Value:
+
+ ERROR_INVALID_HANDLE - handle is not allocated
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ if (HandleTable[(ULONG) FileHandle].Flags & FILE_HANDLE_ALLOCATED) {
+ HandleTable[(ULONG) FileHandle].Flags = FILE_HANDLE_FREE;
+ return NO_ERROR;
+ }
+ else
+ ASSERT (FALSE);
+ // return ERROR_INVALID_HANDLE;
+}
+
+
+
+APIRET
+CheckMode(
+ IN ULONG RequestedMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks for valid access/sharing flags and checks that
+ reserved bits are off.
+
+Arguments:
+
+ RequestedMode - openmode passed to DosOpen API
+
+Return Value:
+
+ ERROR_INVALID_ACCESS - mode is invalid
+
+--*/
+
+{
+ ULONG check;
+
+
+ //
+ // Word 1 is all reserved
+ // nibble 3 of word 0 is all ok
+ //
+ if (RequestedMode & 0xFFFF0000) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // check nibble 2
+ //
+ check = RequestedMode & 0xF00;
+ if ( (check >= 0x400 && check <= 0xF00) ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // check nibble 0
+ //
+ check = RequestedMode & 0xF;
+ if ( (check >= 0x3 && check <= 0x7) ||
+ (check >= 0xB && check <= 0xF) ) {
+ return ERROR_INVALID_ACCESS;
+ }
+
+ //
+ // check nibble 1
+ //
+ check = RequestedMode & 0xF0;
+ if ( (check == 0) ||
+ (check >= 0x50 && check <= 0x80) ||
+ (check >= 0xD0 && check <= 0xF0) ) {
+ return ERROR_INVALID_ACCESS;
+ }
+/* if (((RequestedMode & SHARE_FLAGS) > OPEN_SHARE_DENYNONE) ||
+ ((RequestedMode & SHARE_FLAGS) < OPEN_SHARE_DENYREADWRITE))
+ return ERROR_INVALID_ACCESS;
+
+ if ((RequestedMode & ACCESS_FLAGS) > OPEN_ACCESS_READWRITE)
+ return ERROR_INVALID_ACCESS;
+*/
+ return NO_ERROR;
+}
+
+
+APIRET
+UpdateFileSize(
+ IN HANDLE NtHandle,
+ IN ULONG NewFileSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine changes the size of a file.
+
+Arguments:
+
+ NtHandle - NT handle to file to change the size of
+
+ NewFileSize - new size of file
+
+Return Value:
+
+ ERROR_INVALID_ACCESS - the file was not open in a mode which allowed
+ the file size to be changed.
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ FILE_END_OF_FILE_INFORMATION EofInfo;
+ APIRET rc;
+
+ //
+ // call NtSetInformationFile to set new size and EOF
+ //
+
+ EofInfo.EndOfFile = RtlConvertUlongToLargeInteger(NewFileSize);
+
+ do {
+ Status = NtSetInformationFile(NtHandle,
+ &IoStatus,
+ &EofInfo,
+ sizeof(EofInfo),
+ FileEndOfFileInformation
+ );
+ } while (RetryIO(Status, NtHandle));
+
+ if (!(NT_SUCCESS(Status))) {
+ rc = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_ACCESS);
+ }
+ else {
+ rc = NO_ERROR;
+ }
+
+ return rc;
+}
+
+
+APIRET
+DosOpen(
+ IN PSZ FileName,
+ OUT PHFILE FileHandle,
+ OUT PULONG ActionTaken,
+ IN ULONG CreateSize,
+ IN ULONG FileAttribute,
+ IN ULONG OpenFlags,
+ IN ULONG OpenMode,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file.
+
+Arguments:
+
+ FileName - name of file to open
+
+ FileHandle - where to store OS/2 handle
+
+ ActionTaken - whether file was opened, created, or replaced
+
+ CreateSize - size of file, if created or replaced.
+
+ FileAttribute - attribute of file, if created.
+
+ OpenFlags - whether to open, create, or replace the file if it exists or
+ doesn't exist.
+
+ OpenMode - mode in which to open the file (access, sharing, direct access,
+ etc.)
+
+ ExtendedFileAttr - extended attributes to set, if created or replaced.
+
+Return Value:
+
+ ERROR_ACCESS_DENIED - requested operation could not be performed because
+ caller didn't have correct access rights
+
+ ERROR_PATH_NOT_FOUND - direct access requested and pathname is not "d:\"
+ or a device
+
+ ERROR_INVALID_PARAMETER - open mode or open flags contains an invalid
+ value.
+
+--*/
+
+{
+ NTSTATUS Status;
+ APIRET RetCode;
+ PSZ CanonicalName;
+ STRING CanonicalNameString;
+ UNICODE_STRING CanonicalNameString_U;
+ ULONG FileType;
+ ULONG FileFlags;
+ USHORT DeviceAttribute;
+ PFILE_HANDLE hFileRecord;
+ HANDLE NtFileHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ ULONG ShareAccess;
+ ULONG Attributes;
+ ULONG DesiredAccess;
+ ULONG CreateDisposition;
+ ULONG CreateOptions;
+ IO_VECTOR_TYPE VectorType;
+ HFILE hLocalHandle;
+ HANDLE ComReadEvent;
+ HANDLE ComWriteEvent;
+ HANDLE ComIOCtlEvent;
+ ULONG DriveNumber = 0L;
+ SECURITY_QUALITY_OF_SERVICE DefaultSqos =
+ { sizeof(SECURITY_QUALITY_OF_SERVICE),
+ SecurityImpersonation,
+ SECURITY_DYNAMIC_TRACKING,
+ TRUE };
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosOpen";
+ #endif
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] entering DosOpen(%s)\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ FileName));
+ }
+#endif
+ try {
+ Od2ProbeForWrite((PVOID)FileHandle, sizeof(HFILE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (RetCode = CheckMode(OpenMode))
+ return RetCode;
+
+ //
+ // history of the following code:
+ // a bug in 1.2 was found whereby process A could open a file deny_write
+ // and process B could open the same file for read, specifying replace_if_exists.
+ // the net result is that process B could affect the contents of the file
+ // when A had specifically tried to prevent it. this bug was fixed by
+ // requiring that a process have a write access handle in order to replace.
+ // this was implemented by checking that if OPEN_ACTION_REPLACE_IF_EXISTS was
+ // specified that OpenMode wasn't OPEN_ACCESS_READONLY. thus the call to
+ // DosOpen would fail even if the file didn't exist.
+ // so we disallow OPEN_ACCESS_READONLY & OPEN_ACTION_REPLACE_IF_EXISTS
+ //
+ // we also disallow creates with a non-zero CreateSize for read-only handles.
+ // this is because the data in the file is undefined. if the file is open
+ // for write access, we can call NT to set the end-of-file pointer to the
+ // CreateSize. this call will zero out all the bytes up to the end-of-file
+ // pointer. or the user can write out data. but if the handle is read-only,
+ // we can't set the end-of-file pointer and the user won't be able to read
+ // the file. this is also a security issue.
+ //
+
+ if (((OpenMode & ACCESS_FLAGS) == OPEN_ACCESS_READONLY) &&
+ (OpenFlags & OPEN_ACTION_REPLACE_IF_EXISTS)) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // check for invalid locality of reference value
+ //
+
+ if ((OpenMode & LOCALITY_FLAGS) > OPEN_FLAGS_RANDOMSEQUENTIAL) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // check file attributes. these don't need to be mapped because
+ // the NT values correspond to the v20 values.
+ //
+ // FILE_ATTRIBUTE_NORMAL is never passed to NT on a create because it
+ // maps to an attribute of zero and FILE_ARCHIVED is always set.
+ //
+
+ if (FileAttribute & ~ATTR_CHANGEABLE) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ Attributes = FileAttribute | FILE_ARCHIVED;
+
+ //
+ // check validity of OpenFlags
+ //
+ if ((OpenFlags & OPEN_ACTION_RESERVED) ||
+ ((OpenFlags & (OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_REPLACE_IF_EXISTS)) > OPEN_ACTION_REPLACE_IF_EXISTS))
+ {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ //
+ // map open flags
+ //
+ // if the user asked to replace a file, we need WRITE_DAC access to the
+ // file so we add it here.
+ //
+
+ switch (OpenFlags) {
+ case (OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS):
+ CreateDisposition = FILE_OVERWRITE_IF;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] setting file_overwrite_if\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ break;
+ case (OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS):
+ CreateDisposition = FILE_OVERWRITE;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] setting file_overwrite\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ break;
+ case (OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS):
+ CreateDisposition = FILE_OPEN_IF;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] setting file_open_if\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ break;
+ case (OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS):
+ CreateDisposition = FILE_OPEN;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] setting file_open\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ break;
+ case (OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS):
+ CreateDisposition = FILE_CREATE;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] setting file_create\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ break;
+ default:
+ return ERROR_OPEN_FAILED;
+ }
+
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RetCode = AllocateHandle(&hLocalHandle);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (RetCode) {
+ return RetCode;
+ }
+
+ //
+ // if direct access requested, make sure path is just a drive letter
+ // check CreateDisposition
+ //
+
+ if (OpenMode & OPEN_FLAGS_DASD) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] DASD open\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ if (CreateDisposition != FILE_OPEN) {
+ RetCode = ERROR_INVALID_PARAMETER;
+ }
+ else {
+ try {
+ if ((FileName[1] != ':') || (FileName[2] != '\0'))
+ RetCode = ERROR_PATH_NOT_FOUND;
+ else {
+ CanonicalName = RtlAllocateHeap(Od2Heap,0,17); // length of \os2ss\drives\x:
+ strcpy (CanonicalName,"\\OS2SS\\DRIVES\\");
+ CanonicalName[14] = FileName[0];
+ CanonicalName[15] = ':';
+ CanonicalName[16] = '\0';
+ DriveNumber = (((ULONG)toupper((UCHAR)FileName[0])) - 'A' + 1) | 0x80000000;
+ FileType = FILE_TYPE_FILE;
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ FreeHandle(hLocalHandle);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (CanonicalName == NULL) {
+#if DBG
+ KdPrint(("[%d,%d] OS2: Od2Canonicalise, no memory in Od2Heap\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else {
+ Od2ExitGP();
+ }
+ }
+ }
+ if (RetCode) {
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ FreeHandle(hLocalHandle);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ Od2InitMBString(&CanonicalNameString,CanonicalName);
+ NtFileHandle = NULL; // don't have current directory open
+ }
+ else
+ {
+ RetCode = Od2Canonicalize(FileName,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &CanonicalNameString,
+ &NtFileHandle,
+ &FileFlags, // BUGBUG shouldn't we check for root dir
+ &FileType
+ );
+ if ((RetCode != NO_ERROR)|| (FileFlags & CANONICALIZE_META_CHARS_FOUND)) {
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ FreeHandle(hLocalHandle);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (RetCode == NO_ERROR && (FileFlags & CANONICALIZE_META_CHARS_FOUND)) {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ RetCode = ERROR_FILE_NOT_FOUND;
+ }
+ return RetCode;
+ }
+
+ //
+ // Special handling of <boot-drive>:\config.sys
+ // opening this file is mapped to the OS/2 SS config.sys
+ //
+
+ if (Od2FileIsConfigSys(&CanonicalNameString,
+ ((OpenMode & ACCESS_FLAGS) == OPEN_ACCESS_READONLY) ?
+ OPEN_ACCESS_READONLY :
+ OPEN_ACCESS_READWRITE,
+ &Status))
+ {
+ if (!NT_SUCCESS(Status))
+ {
+ // failed to init for config.sys
+
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ FreeHandle(hLocalHandle);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RtlFreeHeap(Od2Heap, 0, CanonicalNameString.Buffer);
+ return Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ }
+
+ NtFileHandle = NULL;
+ FileFlags = 0;
+ FileType = FILE_TYPE_FILE;
+ //OpenMode = (OpenMode & ~SHARE_FLAGS) | OPEN_SHARE_DENYREADWRITE;
+ }
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] canonical name is %s\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ CanonicalNameString.Buffer));
+ }
+#endif
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &CanonicalNameString_U,
+ &CanonicalNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("[%d,%d] DosOpen: no memory for Unicode Conversion\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0, CanonicalNameString.Buffer);
+ return RetCode;
+ }
+
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ NtFileHandle,
+ NULL);
+
+ //
+ // Set up a default Security-Quality-of-Service in case this
+ // DosOpen() will implicitly connect us to a protected server.
+ // The default SQoS is the same as in Win32 CreateFile(). We
+ // discovered this SQoS is necessary when it turned out that the
+ // os2ss couldn't print when a print manager printer is installed
+ // on LPT ports. The reason was that the LPT write requests were
+ // getting redirected to the print spooler (a protected server) and
+ // it requires an SQoS.
+ //
+
+ Obja.SecurityQualityOfService = &DefaultSqos;
+
+ //
+ // in OS/2, the device header is checked for a bit that indicates whether
+ // the device should be added to the sharing set. this is not supported
+ // in NT.
+ //
+ // map sharing flags
+ //
+
+ MapShareAccess(OpenMode,&DesiredAccess,&ShareAccess);
+
+ if (OpenMode & OPEN_FLAGS_DASD) {
+
+ //
+ // We must have FILE_SHARE_WRITE for DASD, or else
+ // NT won't allow us to lock the volume.
+ //
+
+ ShareAccess |= FILE_SHARE_WRITE;
+ }
+
+ //
+ // Nt does not allow pipes to have EAs access on them.
+ //
+ if ( FileType == FILE_TYPE_PIPE ||
+ FileType == FILE_TYPE_NMPIPE ||
+ FileType == FILE_TYPE_MAILSLOT) {
+
+ DesiredAccess &= ~( FILE_READ_EA | FILE_WRITE_EA);
+
+ /* This is commented out now, cause FILE_WRITE_ATTRIBUTES is always
+ given to DesiredAccess. (T-EYALA, 1/94)
+ //
+ // Nt require pipes to have WRITE_ATTRIBUTES access to perform
+ // operations like DosSetNPHState. No equivalent requirement on os/2
+ //
+ DesiredAccess |= FILE_WRITE_ATTRIBUTES;
+ */ //
+ // Also, Nt does not support yet the sharing semantics of pipe
+ // clients under OS/2. To work around it, we do not allow
+ // the client to specify DENY_READ_WRITE --> specify DENY_NONE instead
+ //
+ if (ShareAccess == 0){
+ ShareAccess = FILE_SHARE_WRITE | FILE_SHARE_READ;
+ }
+ }
+
+ DesiredAccess |= SYNCHRONIZE;
+
+ //
+ // set up CreateOptions
+ // BUGBUG need to handle FAIL_ON_ERROR
+ //
+
+ if (FileType == FILE_TYPE_NMPIPE) {
+ CreateOptions = FILE_NON_DIRECTORY_FILE;
+ }
+ else {
+ CreateOptions = FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE;
+ }
+ if (OpenMode & OPEN_FLAGS_WRITE_THROUGH)
+ CreateOptions |= FILE_WRITE_THROUGH;
+ if (OpenMode & OPEN_FLAGS_SEQUENTIAL)
+ CreateOptions |= FILE_SEQUENTIAL_ONLY;
+
+ switch (FileType) {
+ case FILE_TYPE_FILE:
+ VectorType = FileVectorType;
+ break;
+ case FILE_TYPE_PIPE:
+ VectorType = PipeVectorType;
+ break;
+ case FILE_TYPE_NMPIPE:
+ VectorType = FileVectorType;
+ break;
+ case FILE_TYPE_UNC:
+ VectorType = FileVectorType;
+ break;
+ case FILE_TYPE_DEV:
+ VectorType = DeviceVectorType;
+ break;
+ case FILE_TYPE_PSDEV:
+ VectorType = CanonicalNameString.Buffer[1] - '0';
+ break;
+ case FILE_TYPE_MAILSLOT:
+ VectorType = FileVectorType;
+ break;
+ case FILE_TYPE_COM:
+ VectorType = ComVectorType;
+ // Delete the SYNCHRONOUSE flags. The COM device
+ // is accessed ASYNCHRONOUS
+ CreateOptions &= ~(FILE_SYNCHRONOUS_IO_NONALERT |
+ FILE_SYNCHRONOUS_IO_ALERT);
+ DesiredAccess &= ~SYNCHRONIZE;
+ break;
+ default:
+#if DBG
+ KdPrint(("[%d,%d] unsupported filetype in DosOpen\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ ASSERT (FALSE); // not supported
+#endif
+ break;
+ }
+
+ RetCode = IoVectorArray[VectorType]->OpenRoutine(&NtFileHandle,
+ DesiredAccess,
+ &Obja,
+ &IoStatus,
+ CreateSize,
+ ActionTaken,
+ Attributes,
+ ShareAccess,
+ CreateDisposition,
+ CreateOptions,
+ ExtendedFileAttr,
+ (PUSHORT) &FileType,
+ &DeviceAttribute
+ );
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ RtlFreeUnicodeString (&CanonicalNameString_U);
+ if (RetCode) {
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ FreeHandle(hLocalHandle);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // BUGBUG - ERROR_INVALID_NAME can appear in (at least) two
+ // cases: abc.lkjlkj (FAT only, need to be mapped to EXCEED_RANGE)
+ // or .a (FAT only, needs to be mapped to FILE_NOT_FOUND).
+ // Nt returns to OpenCreatePath the same status - we need to check
+ // the pathname to determine the problem.
+ //
+ if (RetCode == ERROR_INVALID_NAME){
+ //
+ // Check for the case that the pathname includes
+ // characters that are valid for HPFS but not for FAT etc.
+ // We don't catch this is Od2Canonicalize for performance
+ // (not querying the volume for the file system)
+ //
+ CHAR FatInvalidChars[] = {
+ '[',
+ ']',
+ '+',
+ '=',
+ ';',
+ ','};
+ CHAR *pc = FileName;
+ CHAR c;
+ while (*pc){
+ c = *pc++;
+ if (strchr( FatInvalidChars, c )) {
+ return ERROR_INVALID_NAME;
+ }
+ }
+
+ return(ERROR_FILE_NOT_FOUND);
+
+ }
+
+ if (!(OpenFlags & OPEN_ACTION_CREATE_IF_NEW) && RetCode == ERROR_FILE_NOT_FOUND) {
+ return(ERROR_OPEN_FAILED);
+ }
+ if (((OpenFlags | OPEN_ACTION_CREATE_IF_NEW) == OPEN_ACTION_CREATE_IF_NEW) && RetCode == ERROR_ACCESS_DENIED) {
+ return(ERROR_OPEN_FAILED);
+ }
+ return RetCode;
+ }
+
+ if (VectorType == FileVectorType) {
+
+ //
+ // if the path was not what we determined, update vector type.
+ // BUGBUG - is this an error?
+ //
+
+ if (FileType != FILE_TYPE_FILE) {
+ switch (FileType) {
+ case FILE_TYPE_PIPE:
+ VectorType = PipeVectorType;
+ break;
+ case FILE_TYPE_NMPIPE:
+ case FILE_TYPE_MAILSLOT:
+ break;
+ case FILE_TYPE_DEV:
+ VectorType = DeviceVectorType;
+ break;
+ default:
+#if DBG
+ KdPrint(("[%d,%d] unsupported filetype in DosOpen\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ ASSERT (FALSE); // not supported
+#endif
+ break;
+ }
+ }
+ }
+
+ if (FileType == FILE_TYPE_COM) {
+ Status = NtCreateEvent(&ComReadEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("[%d,%d] OS2DLL: DosOpen-Unable to NtCreateEvent()-for ComRead, Status = %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+#endif
+ }
+
+ Status = NtCreateEvent(&ComWriteEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("[%d,%d] OS2DLL: DosOpen-Unable to NtCreateEvent()-for ComWrite, Status = %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+#endif
+ }
+
+ Status = NtCreateEvent(&ComIOCtlEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("[%d,%d] OS2DLL: DosOpen-Unable to NtCreateEvent()-for ComIOCtl, Status = %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+#endif
+ }
+ }
+ else {
+ ComReadEvent = NULL;
+ ComWriteEvent = NULL;
+
+ if (DriveNumber != 0L) {
+
+ //
+ // NtAsyncIOCtlEvent also doubles as a storage point for
+ // the drive number when opening a DASD.
+ // Drives are based at 1 (which is drive A:)
+ //
+ // Note that the high bit is initially turned on, so that
+ // the disk ioctl routines know that they should check the
+ // device is really a floppy drive.
+ //
+
+ ComIOCtlEvent = (HANDLE) DriveNumber;
+ } else {
+ ComIOCtlEvent = NULL;
+ }
+ }
+
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ hFileRecord = DereferenceFileHandleNoCheck(hLocalHandle);
+ hFileRecord->NtHandle = NtFileHandle;
+ hFileRecord->NtAsyncReadEvent = ComReadEvent;
+ hFileRecord->NtAsyncWriteEvent = ComWriteEvent;
+ hFileRecord->NtAsyncIOCtlEvent = ComIOCtlEvent;
+ hFileRecord->FileType = (USHORT) FileType;
+ hFileRecord->Flags |= OpenMode & QFHSTATE_FLAGS;
+ hFileRecord->DeviceAttribute = DeviceAttribute;
+ hFileRecord->IoVectorType = VectorType;
+
+ //
+ // validate file handle
+ //
+
+ ValidateHandle(hFileRecord);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ *FileHandle = hLocalHandle;
+ return NO_ERROR;
+}
+
+APIRET
+Od2DeviceShare(
+ IN SHARE_OPERATION Operation,
+ IN IO_VECTOR_TYPE VectorType,
+ IN ULONG DesiredAccess,
+ IN ULONG ShareAccess
+ )
+{
+ OS2_API_MSG m;
+ POS2_SHARE_MSG a = &m.u.DeviceShare;
+
+ a->Operation = Operation;
+ a->VectorType = VectorType;
+ a->DesiredAccess = DesiredAccess;
+ a->ShareAccess = ShareAccess;
+ Od2CallSubsystem( &m, NULL, Oi2DeviceShare, sizeof( *a ) );
+ if (m.ReturnedErrorValue != NO_ERROR) {
+ return( m.ReturnedErrorValue );
+ }
+}
+
+APIRET
+NulOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ )
+
+{
+ APIRET RetCode;
+ UNREFERENCED_PARAMETER(FileHandle);
+ UNREFERENCED_PARAMETER(ObjectAttributes);
+ UNREFERENCED_PARAMETER(IoStatus);
+ UNREFERENCED_PARAMETER(CreateSize);
+ UNREFERENCED_PARAMETER(FileAttributes);
+ UNREFERENCED_PARAMETER(CreateOptions);
+ UNREFERENCED_PARAMETER(ExtendedFileAttr);
+ UNREFERENCED_PARAMETER(FileType);
+
+#if DBG
+ IF_OD2_DEBUG(FILESYS)
+ {
+ KdPrint(("[%d,%d] DosOpen(NUL): NulOpenRoutine\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+
+ //
+ // call the server to add the device to the sharer
+ //
+
+ RetCode = Od2DeviceShare(AddShare,NulVectorType,DesiredAccess,ShareAccess);
+ if (RetCode != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG(FILESYS)
+ {
+ KdPrint(("[%d,%d] NulOpenRoutine: unable to share request\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ return RetCode;
+ }
+
+ //
+ // return the correct device attribute
+ //
+
+ *DeviceAttribute = DEVICE_ATTRIBUTE_NUL | DEVICE_ATTRIBUTE_CHAR | 0x80;
+ /* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */
+
+ //
+ // map ActionTaken
+ //
+
+ *ActionTaken = MapDeviceAction(CreateDisposition);
+
+ return NO_ERROR;
+}
+
+APIRET
+ConOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ )
+
+{
+ APIRET RetCode;
+ UNREFERENCED_PARAMETER(FileHandle);
+ UNREFERENCED_PARAMETER(ObjectAttributes);
+ UNREFERENCED_PARAMETER(IoStatus);
+ UNREFERENCED_PARAMETER(CreateSize);
+ UNREFERENCED_PARAMETER(FileAttributes);
+ UNREFERENCED_PARAMETER(CreateOptions);
+ UNREFERENCED_PARAMETER(ExtendedFileAttr);
+ UNREFERENCED_PARAMETER(FileType);
+
+#if DBG
+ IF_OD2_DEBUG(VIO_FILE)
+ {
+ KdPrint(("[%d,%d] DosOpen(CON): ConOpenRoutine\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+
+ //
+ // call the server to add the device to the sharer
+ //
+
+ RetCode = Od2DeviceShare(AddShare,ConVectorType,DesiredAccess,ShareAccess);
+ if (RetCode != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG(VIO_FILE)
+ {
+ KdPrint(("[%d,%d] ConOpenRoutine: unable to share request\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ return RetCode;
+ }
+
+ //
+ // return the correct device attribute
+ //
+
+ *DeviceAttribute = DEVICE_ATTRIBUTE_STDOUT | DEVICE_ATTRIBUTE_STDIN | DEVICE_ATTRIBUTE_CHAR |
+ 0x80 /* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */ ;
+
+ //
+ // set HANDLE
+ //
+
+ *FileHandle = SesGrp->hConsoleOutput;
+
+ //
+ // map ActionTaken
+ //
+
+ *ActionTaken = MapDeviceAction(CreateDisposition);
+
+ return NO_ERROR;
+}
+
+APIRET
+ComOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ )
+
+{
+ APIRET RetCode;
+
+#if DBG
+ IF_OD2_DEBUG(FILESYS)
+ {
+ KdPrint(("[%d,%d] DosOpen(COM): ComOpenRoutine\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+
+ //
+ // we support inherited handles by duping. all Nt handles are opened
+ // noinherit.
+ //
+ // pass parameters, and pFileType
+ //
+
+ RetCode = OpenCreatePath(FileHandle,
+ DesiredAccess,
+ ObjectAttributes,
+ IoStatus,
+ CreateSize,
+ FileAttributes,
+ ShareAccess,
+ CreateDisposition,
+ CreateOptions,
+ ExtendedFileAttr,
+ FileType,
+ DeviceAttribute,
+ FALSE
+ );
+
+ if (RetCode) {
+ return RetCode;
+ }
+
+ //
+ // set up ActionTaken value.
+ //
+
+ try {
+ if (IoStatus->Information == FILE_SUPERSEDED)
+ *ActionTaken = FILE_EXISTED;
+ else
+ *ActionTaken = IoStatus->Information;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ NtClose(*FileHandle);
+ Od2ExitGP();
+ }
+
+ return NO_ERROR;
+}
+
+APIRET
+LptOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ )
+
+{
+ APIRET RetCode;
+ UNREFERENCED_PARAMETER(FileHandle);
+ UNREFERENCED_PARAMETER(ObjectAttributes);
+ UNREFERENCED_PARAMETER(IoStatus);
+ UNREFERENCED_PARAMETER(CreateSize);
+ UNREFERENCED_PARAMETER(FileAttributes);
+ UNREFERENCED_PARAMETER(CreateOptions);
+ UNREFERENCED_PARAMETER(ExtendedFileAttr);
+ UNREFERENCED_PARAMETER(FileType);
+
+#if DBG
+ IF_OD2_DEBUG(FILESYS)
+ {
+ KdPrint(("[%d,%d] DosOpen(LPT): LptOpenRoutine\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+
+ //
+ // call the server to add the device to the sharer
+ //
+
+ RetCode = Od2DeviceShare(AddShare,LptVectorType,DesiredAccess,ShareAccess);
+ if (RetCode != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG(FILESYS)
+ {
+ KdPrint(("[%d,%d] LptOpenRoutine: unable to share request\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ return RetCode;
+ }
+
+ //
+ // BUGBUG call the windows input thread
+ //
+
+ //
+ // return the correct device attribute
+ //
+
+ *DeviceAttribute = DEVICE_ATTRIBUTE_DEFAULT_CHAR;
+
+ //
+ // map ActionTaken
+ //
+
+ *ActionTaken = MapDeviceAction(CreateDisposition);
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ )
+
+{
+ APIRET RetCode;
+ UNREFERENCED_PARAMETER(ObjectAttributes);
+ UNREFERENCED_PARAMETER(IoStatus);
+ UNREFERENCED_PARAMETER(CreateSize);
+ UNREFERENCED_PARAMETER(FileAttributes);
+ UNREFERENCED_PARAMETER(CreateOptions);
+ UNREFERENCED_PARAMETER(ExtendedFileAttr);
+ UNREFERENCED_PARAMETER(FileType);
+
+#if DBG
+ IF_OD2_DEBUG(KBD_FILE)
+ {
+ KdPrint(("[%d,%d] DosOpen(KBD$): KbdOpenRoutine\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+
+ //
+ // call the server to add the device to the sharer
+ //
+
+ RetCode = Od2DeviceShare(AddShare,KbdVectorType,DesiredAccess,ShareAccess);
+ if (RetCode != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG(KBD_FILE)
+ {
+ KdPrint(("[%d,%d] KbdOpenRoutine: unable to share request\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ return RetCode;
+ }
+
+ //
+ // return the correct device attribute
+ //
+
+ *DeviceAttribute = DEVICE_ATTRIBUTE_STDIN | DEVICE_ATTRIBUTE_CHAR | DEVICE_ATTRIBUTE_CONSOLE |
+ DEVICE_ATTRIBUTE_OPEN | 0x80 ;
+ /* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */
+
+ //
+ // set HANDLE
+ //
+
+ *FileHandle = (HANDLE)SesGrp->PhyKbd;
+
+ //
+ // map ActionTaken
+ //
+
+ *ActionTaken = MapDeviceAction(CreateDisposition);
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MouseOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ )
+
+{
+ APIRET RetCode;
+ UNREFERENCED_PARAMETER(ObjectAttributes);
+ UNREFERENCED_PARAMETER(IoStatus);
+ UNREFERENCED_PARAMETER(CreateSize);
+ UNREFERENCED_PARAMETER(FileAttributes);
+ UNREFERENCED_PARAMETER(CreateOptions);
+ UNREFERENCED_PARAMETER(ExtendedFileAttr);
+ UNREFERENCED_PARAMETER(FileType);
+
+#if DBG
+ IF_OD2_DEBUG(MOU_FILE)
+ {
+ KdPrint(("[%d,%d] DosOpen(MOUSE$): MouOpenRoutine\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+
+ //
+ // call the server to add the device to the sharer
+ //
+
+ RetCode = Od2DeviceShare(AddShare,MouseVectorType,DesiredAccess,ShareAccess);
+ if (RetCode != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG(MOU_FILE)
+ {
+ KdPrint(("[%d,%d] MouOpenRoutine: unable to share request\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ return RetCode;
+ }
+
+ //
+ // call the windows input thread
+ //
+
+ RetCode = DevMouOpen(FileHandle);
+
+ if ( RetCode ) {
+ ASSERT(FALSE);
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] MouseOpenRouine: Error returned from DevMouOpen %d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ RetCode));
+ }
+#endif
+ return(RetCode);
+ }
+
+ //
+ // return the correct device attribute
+ //
+
+ *DeviceAttribute = DEVICE_ATTRIBUTE_CHAR | DEVICE_ATTRIBUTE_CONSOLE | DEVICE_ATTRIBUTE_OPEN |
+ 0x80 /* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */;
+
+ //
+ // map ActionTaken
+ //
+
+ *ActionTaken = MapDeviceAction(CreateDisposition);
+
+ return NO_ERROR;
+}
+
+
+APIRET
+ClockOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ )
+
+{
+ APIRET RetCode;
+ UNREFERENCED_PARAMETER(FileHandle);
+ UNREFERENCED_PARAMETER(ObjectAttributes);
+ UNREFERENCED_PARAMETER(IoStatus);
+ UNREFERENCED_PARAMETER(CreateSize);
+ UNREFERENCED_PARAMETER(FileAttributes);
+ UNREFERENCED_PARAMETER(CreateOptions);
+ UNREFERENCED_PARAMETER(ExtendedFileAttr);
+ UNREFERENCED_PARAMETER(FileType);
+
+#if DBG
+ IF_OD2_DEBUG(FILESYS)
+ {
+ KdPrint(("[%d,%d] DosOpen(CLOCK$): ClockOpenRoutine\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+
+ //
+ // call the server to add the device to the sharer
+ //
+
+ RetCode = Od2DeviceShare(AddShare,ClockVectorType,DesiredAccess,ShareAccess);
+ if (RetCode != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG(FILESYS)
+ {
+ KdPrint(("[%d,%d] ClockOpenRoutine: unable to share request\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ return RetCode;
+ }
+
+ //
+ // BUGBUG call NT
+ //
+
+ //
+ // return the correct device attribute
+ //
+
+ *DeviceAttribute = DEVICE_ATTRIBUTE_CLOCK | DEVICE_ATTRIBUTE_CHAR |
+ 0x80 /* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */;
+
+ //
+ // map ActionTaken
+ //
+
+ *ActionTaken = MapDeviceAction(CreateDisposition);
+
+ return NO_ERROR;
+}
+
+APIRET
+ScreenOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ )
+
+{
+ APIRET RetCode;
+ UNREFERENCED_PARAMETER(ObjectAttributes);
+ UNREFERENCED_PARAMETER(IoStatus);
+ UNREFERENCED_PARAMETER(CreateSize);
+ UNREFERENCED_PARAMETER(FileAttributes);
+ UNREFERENCED_PARAMETER(CreateOptions);
+ UNREFERENCED_PARAMETER(ExtendedFileAttr);
+ UNREFERENCED_PARAMETER(FileType);
+
+#if DBG
+ IF_OD2_DEBUG(VIO_FILE)
+ {
+ KdPrint(("[%d,%d] DosOpen(SCREEN$): ScreenOpenRoutine\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+
+ //
+ // call the server to add the device to the sharer
+ //
+
+ RetCode = Od2DeviceShare(AddShare,ScreenVectorType,DesiredAccess,ShareAccess);
+ if (RetCode != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG(VIO_FILE)
+ {
+ KdPrint(("[%d,%d] ScreenOpenRoutine: unable to share request\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ return RetCode;
+ }
+
+ //
+ // BUGBUG call windows input thread
+ //
+
+ //
+ // set HANDLE
+ //
+
+ *FileHandle = (HANDLE)SesGrp->hConsoleOutput;
+
+ //
+ // return the correct device attribute
+ //
+
+ *DeviceAttribute = DEVICE_ATTRIBUTE_STDOUT | DEVICE_ATTRIBUTE_CHAR |
+ 0x80 /* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */;
+
+ //
+ // map ActionTaken
+ //
+
+ *ActionTaken = MapDeviceAction(CreateDisposition);
+
+ return NO_ERROR;
+}
+
+APIRET
+PointerOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ )
+
+{
+ APIRET RetCode;
+ UNREFERENCED_PARAMETER(FileHandle);
+ UNREFERENCED_PARAMETER(ObjectAttributes);
+ UNREFERENCED_PARAMETER(IoStatus);
+ UNREFERENCED_PARAMETER(CreateSize);
+ UNREFERENCED_PARAMETER(FileAttributes);
+ UNREFERENCED_PARAMETER(CreateOptions);
+ UNREFERENCED_PARAMETER(ExtendedFileAttr);
+ UNREFERENCED_PARAMETER(FileType);
+
+#if DBG
+ IF_OD2_DEBUG(FILESYS)
+ {
+ KdPrint(("[%d,%d] DosOpen(POINTER$): PointerOpenRoutine\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+
+ // BUGBUG might want to change device open to
+ // call one routine that calls sharer and maps action and calls
+ // device specific routine
+ //
+ // call the server to add the device to the sharer
+ //
+
+ RetCode = Od2DeviceShare(AddShare,PointerVectorType,DesiredAccess,ShareAccess);
+ if (RetCode != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG(FILESYS)
+ {
+ KdPrint(("[%d,%d] PointerOpenRoutine: unable to share request\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ return RetCode;
+ }
+
+ //
+ // BUGBUG call windows input thread
+ //
+
+ //
+ // return the correct device attribute
+ //
+
+ *DeviceAttribute = DEVICE_ATTRIBUTE_CHAR | 0x80 /* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */;
+
+ //
+ // map ActionTaken
+ //
+
+ *ActionTaken = MapDeviceAction(CreateDisposition);
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MapFileType(
+ IN HANDLE FileHandle,
+ OUT PBOOLEAN Directory OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps an NT device type to an OS/2 file type.
+
+Arguments:
+
+ FileHandle - NT handle to file
+
+ Directory - where to return whether the handle is for a directory
+
+ FileType - where to store OS/2 file type
+
+ DeviceAttribute - where to store the device attribute
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ FILE_BASIC_INFORMATION BasicInfo;
+ FILE_FS_DEVICE_INFORMATION DeviceInfo;
+
+ //
+ // in Canonicalize, we try to determine the type of a filename based
+ // on naming conventions. we use this information to determine whether
+ // an operation is legal (i.e. renaming a device is illegal). we detect
+ // named pipes (\PIPE\), devices (\DEV\) plus list of pseudo-character
+ // devices or drive letter, and UNC. all other names are assumed to
+ // be filenames. We can't detect remote names.
+ //
+ // It is possible to open a path that is a device or named pipe without
+ // being able to detect it in Canonicalize. For path-based operations
+ // that don't create an object, we verify the filetype after the open
+ // has occurred. this is because an operation that's illegal in OS/2
+ // may not be illegal in NT. We use the information returned by this call
+ // to store as the filetype associated with the file handle.
+ //
+ // no access is required to query StandardInformation or DeviceInformation.
+ //
+
+ if (ARGUMENT_PRESENT(Directory)) {
+ do {
+ Status = NtQueryInformationFile(FileHandle,
+ &IoStatus,
+ &BasicInfo,
+ sizeof (BasicInfo),
+ FileBasicInformation);
+ } while (RetryIO(Status, FileHandle));
+ if (!NT_SUCCESS( Status )) {
+ return Or2MapNtStatusToOs2Error(Status, ERROR_FILE_NOT_FOUND);
+ }
+ *Directory = ((BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
+ }
+
+ do {
+ Status = NtQueryVolumeInformationFile(FileHandle,
+ &IoStatus,
+ &DeviceInfo,
+ sizeof (DeviceInfo),
+ FileFsDeviceInformation);
+ } while (RetryIO(Status, FileHandle));
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] MapFileType: Error from NtQueryVolumeInformation, %lx\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+ }
+#endif
+ return Or2MapNtStatusToOs2Error(Status, ERROR_FILE_NOT_FOUND);
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] MapFileType: DeviceType=%ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ DeviceInfo.DeviceType));
+ }
+#endif
+ switch (DeviceInfo.DeviceType) {
+ case FILE_DEVICE_DATALINK:
+ case FILE_DEVICE_DFS:
+ case FILE_DEVICE_PHYSICAL_NETCARD:
+ case FILE_DEVICE_TRANSPORT:
+ case FILE_DEVICE_UNKNOWN:
+
+ case FILE_DEVICE_CD_ROM:
+ case FILE_DEVICE_DISK:
+ case FILE_DEVICE_VIRTUAL_DISK:
+ case FILE_DEVICE_TAPE:
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] MapFileType: disk file \n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *DeviceAttribute = 0;
+ *FileType = FILE_TYPE_FILE;
+ break;
+ case FILE_DEVICE_NETWORK:
+ *DeviceAttribute = 0;
+ *FileType = FILE_TYPE_UNC;
+ break;
+ case FILE_DEVICE_NAMED_PIPE:
+ *DeviceAttribute = 0;
+ *FileType = FILE_TYPE_NMPIPE;
+ break;
+ case FILE_DEVICE_MAILSLOT:
+ *DeviceAttribute = 0;
+ *FileType = FILE_TYPE_MAILSLOT;
+ break;
+ case FILE_DEVICE_SERIAL_PORT:
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] MapFileType: COM device \n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *FileType = FILE_TYPE_COM;
+ *DeviceAttribute = DEVICE_ATTRIBUTE_CHAR | DEVICE_ATTRIBUTE_OPEN |
+ DEVICE_ATTRIBUTE_GENIOCTL | 0x80;
+ /* 0x80 stands for level 1 */
+ break;
+ case FILE_DEVICE_SCREEN:
+ case FILE_DEVICE_KEYBOARD:
+ case FILE_DEVICE_MOUSE:
+ case FILE_DEVICE_NULL:
+ case FILE_DEVICE_PRINTER:
+ case FILE_DEVICE_SOUND:
+ case FILE_DEVICE_PARALLEL_PORT:
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] MapFileType: character device \n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *FileType = FILE_TYPE_DEV;
+ *DeviceAttribute = DEVICE_ATTRIBUTE_NUL | DEVICE_ATTRIBUTE_STDIN;
+ if (DeviceInfo.DeviceType == FILE_DEVICE_NULL)
+ *DeviceAttribute = DEVICE_ATTRIBUTE_CHAR | DEVICE_ATTRIBUTE_NUL | 0x80;
+ /* 0x80 stands for level 1 */
+ else if (DeviceInfo.DeviceType == FILE_DEVICE_PARALLEL_PORT)
+ *DeviceAttribute = DEVICE_ATTRIBUTE_CHAR | DEVICE_ATTRIBUTE_OPEN | 0x80;
+ /* 0x80 stands for level 1 */
+ else if (DeviceInfo.DeviceType == FILE_DEVICE_KEYBOARD)
+ *DeviceAttribute |= DEVICE_ATTRIBUTE_STDIN;
+ else if (DeviceInfo.DeviceType == FILE_DEVICE_SCREEN)
+ *DeviceAttribute |= DEVICE_ATTRIBUTE_STDOUT;
+ else if (DeviceInfo.DeviceType == FILE_DEVICE_PRINTER)
+ *DeviceAttribute = 0;
+ break;
+
+ default:
+#if DBG
+ KdPrint(("[%d,%d] error: unknown device type in MapFileType %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ DeviceInfo.DeviceType));
+#endif
+ return ERROR_PATH_NOT_FOUND;
+ break;
+ }
+ return NO_ERROR;
+
+}
+
+
+BOOLEAN
+CheckFileType(
+ IN HANDLE FileHandle,
+ IN USHORT FileTypes
+ )
+
+/*++
+
+Routine Description:
+
+ This routine verifies that the handle is one of the specified types
+ (file types == device, pipe, pseudochar device, file).
+ Note that since the filetype value for file is zero, there is no way
+ to check for files.
+
+Arguments:
+
+ FileHandle - NT handle to file
+
+ FileTypes - file types to check for
+
+Return Value:
+
+ TBS
+
+--*/
+
+{
+ USHORT FileType;
+ APIRET RetCode;
+ USHORT DeviceAttribute;
+
+ RetCode = MapFileType(FileHandle,NULL, &FileType,&DeviceAttribute);
+ ASSERT (!RetCode);
+ if (RetCode){
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] CheckFileType: Error returned from MapFileType %d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ RetCode));
+ }
+#endif
+ return FALSE;
+ }
+ return ((BOOLEAN )((FileType & FileTypes) != 0));
+}
+
+APIRET
+FileOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ )
+{
+ APIRET RetCode;
+
+ //
+ // we support inherited handles by duping. all Nt handles are opened
+ // noinherit.
+ //
+ // pass parameters, and pFileType
+ //
+
+ RetCode = OpenCreatePath(FileHandle,
+ DesiredAccess,
+ ObjectAttributes,
+ IoStatus,
+ CreateSize,
+ FileAttributes,
+ ShareAccess,
+ CreateDisposition,
+ CreateOptions,
+ ExtendedFileAttr,
+ FileType,
+ DeviceAttribute,
+ FALSE
+ );
+
+ if (RetCode) {
+ if ((RetCode == ERROR_SHARING_VIOLATION) && (*FileType == FILE_TYPE_NMPIPE)){
+ return(ERROR_ACCESS_DENIED);
+ }
+ return RetCode;
+ }
+
+ //
+ // set up ActionTaken value.
+ //
+
+ try {
+ if (IoStatus->Information == FILE_SUPERSEDED)
+ *ActionTaken = FILE_EXISTED;
+ else
+ *ActionTaken = IoStatus->Information;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ NtClose(*FileHandle);
+ Od2ExitGP();
+ }
+
+ //
+ // if file was replaced or created, we need to set the end-of-file pointer.
+ // we know the file-size change will succeed because we require a writeable
+ // handle if replace or create (with a non-zero CreateSize) is requested.
+ // The call to UpdateFileSize shouldn't actually change the size of the
+ // file. It will just set the end-of-file pointer to the createsize. NT
+ // puts the end-of-file pointer at the beginning of the file on create,
+ // regardless of the file size.
+ //
+ // If the UpdateFileSize fails, we fail the open but don't try to delete
+ // the file. We can't open the file for delete because it will fail if
+ // any other process has the file open, so we can't delete the file.
+ // Also, if the UpdateFileSize fails, the system is probably messed up
+ // enough that a delete would fail. However, we don't expect the
+ // UpdateFileSize to ever fail because all it's doing is setting the file
+ // pointer.
+ //
+
+ if ((*ActionTaken == FILE_CREATED && CreateSize != 0) ||
+ (*ActionTaken == FILE_TRUNCATED)) {
+ if (RetCode = UpdateFileSize(*FileHandle,CreateSize)) {
+ // NtClose(*FileHandle);
+ return NO_ERROR;
+ // return ERROR_ACCESS_DENIED; // BUGBUG bogus error?
+ }
+ }
+ return NO_ERROR;
+}
+
+
+APIRET
+OpenCreatePath(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute,
+ IN BOOLEAN OpenDirectory
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens/creates a file/directory, puts EAs into NT format,
+ and maps the file type. It should be called when NtCreateFile would be
+ called, as opposed to when NtOpenFile would be called.
+
+Arguments:
+
+ FileHandle - where to return NT handle to file
+
+ DesiredAccess - requested access to file
+
+ ObjectAttributes - NT attributes of file
+
+ IoStatus - io status block
+
+ CreateSize - size of file, if created.
+
+ FileAttributes - attributes of file, if created.
+
+ ShareAccess - access to file allowed to subsequent openers
+
+ CreateDisposition - whether to open/create/truncate if exists/doesn't exist
+
+ CreateOptions - state of open file (synchronous, write-through, etc)
+
+ ExtendedFileAttr - extended attributes to set, if created or replaced.
+BUGBUG need to probe this
+ FileType - where to return type of open file
+
+ OpenDirectory - whether or not opened object can be directory
+
+Return Value:
+
+ ERROR_ACCESS_DENIED - the open could not be performed because
+ caller didn't have correct access rights
+
+--*/
+
+{
+ NTSTATUS Status;
+ APIRET RetCode;
+ LARGE_INTEGER AllocationSize;
+ PVOID EaBuffer;
+ ULONG EaListLength;
+ BOOLEAN Directory;
+
+ DBG_UNREFERENCED_LOCAL_VARIABLE(Directory);
+ //
+ // convert EA format here.
+ //
+
+ if (ExtendedFileAttr) {
+ EaListLength = ExtendedFileAttr->fpFEA2List->cbList - MINFEALISTSIZE;
+ if (EaListLength) {
+ EaBuffer = ExtendedFileAttr->fpFEA2List->list;
+ }
+ else {
+ EaBuffer = NULL;
+ }
+ }
+ else {
+ EaBuffer = NULL;
+ EaListLength = 0;
+ }
+
+
+ if (!OpenDirectory) {
+ CreateOptions |= FILE_NON_DIRECTORY_FILE;
+ } else {
+ CreateOptions |= FILE_DIRECTORY_FILE;
+ }
+
+ //
+ // open/create file/dir
+ //
+
+ AllocationSize = RtlConvertUlongToLargeInteger(CreateSize);
+
+ do {
+ Status = NtCreateFile(FileHandle,
+ DesiredAccess,
+ ObjectAttributes,
+ IoStatus,
+ &AllocationSize,
+ FileAttributes,
+ ShareAccess,
+ CreateDisposition,
+ CreateOptions,
+ EaBuffer,
+ EaListLength
+ );
+ } while (RetryCreateOpen(Status, ObjectAttributes));
+
+ //
+ // If we got STATUS_ACCESS_DENIED it may have happened because of trying
+ // to open a file on a CD-ROM. In this case, the FILE_WRITE_ATTRIBUTES
+ // flag in the DesiredAccess causes this error code, and we should open the file
+ // without it (only in READONLY).
+ //
+
+ if ((Status == STATUS_ACCESS_DENIED) &&
+ ((CreateDisposition == FILE_OPEN) ||
+ (CreateDisposition == FILE_OPEN_IF)) &&
+ (!(DesiredAccess & FILE_WRITE_DATA))) {
+
+ do {
+ Status = NtCreateFile(FileHandle,
+ DesiredAccess & ~(FILE_WRITE_ATTRIBUTES),
+ ObjectAttributes,
+ IoStatus,
+ &AllocationSize,
+ FileAttributes,
+ ShareAccess,
+ CreateDisposition,
+ CreateOptions,
+ EaBuffer,
+ EaListLength
+ );
+ } while (RetryCreateOpen(Status, ObjectAttributes));
+ }
+
+ if (!(NT_SUCCESS(Status)))
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ KdPrint(("[%d,%d] St == %X\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+ }
+#endif
+ switch (Status) {
+ case STATUS_OBJECT_NAME_COLLISION:
+ RetCode = ERROR_ACCESS_DENIED;
+ break;
+
+ case STATUS_DISK_FULL:
+ if (CreateOptions & FILE_DIRECTORY_FILE) {
+ // FILIO014(test 2)
+ RetCode = ERROR_ACCESS_DENIED;
+ break;
+ }
+
+ case STATUS_OBJECT_NAME_INVALID:
+ RetCode = ERROR_FILENAME_EXCED_RANGE;
+ break;
+
+ case STATUS_FILE_IS_A_DIRECTORY:
+ if (!OpenDirectory) {
+ RetCode = ERROR_ACCESS_DENIED;
+ break;
+ }
+ // fall through
+
+ default:
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_PATH_NOT_FOUND);
+ }
+ return (RetCode);
+ }
+
+ if (RetCode = MapFileType(*FileHandle,NULL, FileType, DeviceAttribute)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] Retcode == %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ RetCode));
+ KdPrint(("[%d,%d] returned from MapFileType\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ NtClose(*FileHandle);
+ return( ERROR_ACCESS_DENIED );
+ }
+
+// //
+// // the only time the following test should fail is if this routine
+// // was called by Dos32Open and the path specified by the user was
+// // a directory.
+// //
+//
+// if (OpenDirectory != Directory) {
+// NtClose(*FileHandle);
+// return( ERROR_ACCESS_DENIED );
+// }
+
+ return( NO_ERROR ); // success
+}
+
+
+APIRET
+DosQueryFHState(
+ IN HFILE FileHandle,
+ OUT PULONG OpenMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the open mode for a file handle.
+
+Arguments:
+
+ FileHandle - OS/2 file handle
+
+ OpenMode - where to return open mode
+
+Return Value:
+
+ ERROR_INVALID_HANDLE - the file handle is not open
+
+--*/
+
+{
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosQueryFHState";
+ #endif
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+
+ RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ if (hFileRecord->FileType == FILE_TYPE_MAILSLOT) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return (ERROR_INVALID_HANDLE);
+ }
+ try {
+ *OpenMode = hFileRecord->Flags & QFHSTATE_FLAGS;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ Od2ExitGP();
+ }
+
+// BUGBUG add test for psdev. if psdev, return device and no header.
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return NO_ERROR;
+}
+
+APIRET
+NonFileSetHandleStateRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ IN ULONG OpenMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the open mode for a pipe handle.
+
+Arguments:
+
+ hFileRecord - pointer to record of OS/2 pipe handle
+
+ OpenMode - open mode to set
+
+Return Value:
+
+ TBS
+
+Note:
+
+ FileLock must be owned exclusively when calling this routine.
+
+--*/
+
+{
+ hFileRecord->Flags &= ~SETFHSTATE_FLAGS;
+ hFileRecord->Flags |= OpenMode;
+ return NO_ERROR;
+}
+
+APIRET
+FileSetHandleStateRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ IN ULONG OpenMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the open mode for a file handle.
+
+Arguments:
+
+ hFileRecord - pointer to record of OS/2 file handle
+
+ OpenMode - open mode to set
+
+Return Value:
+
+ TBS
+
+Note:
+
+ FileLock must be owned exclusively when calling this routine.
+
+--*/
+
+{
+ NTSTATUS Status;
+ FILE_MODE_INFORMATION ModeInfo;
+ IO_STATUS_BLOCK IoStatus;
+
+ if (hFileRecord->FileType == FILE_TYPE_MAILSLOT) {
+ return (ERROR_INVALID_HANDLE);
+ }
+
+ if ((hFileRecord->FileType != FILE_TYPE_NMPIPE) &&
+ (hFileRecord->FileType != FILE_TYPE_PIPE)){
+ ModeInfo.Mode = FILE_SYNCHRONOUS_IO_NONALERT;
+ }
+ else {
+ ModeInfo.Mode = 0;
+ }
+
+ if (OpenMode & OPEN_FLAGS_WRITE_THROUGH)
+ ModeInfo.Mode |= FILE_WRITE_THROUGH;
+ do {
+ Status = NtSetInformationFile(hFileRecord->NtHandle,
+ &IoStatus,
+ &ModeInfo,
+ sizeof (ModeInfo),
+ FileModeInformation);
+ } while (RetryIO(Status, hFileRecord->NtHandle));
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_GEN_FAILURE));
+ }
+ hFileRecord->Flags &= ~SETFHSTATE_FLAGS;
+ hFileRecord->Flags |= OpenMode;
+ return NO_ERROR;
+}
+
+APIRET
+NoSuppSetHandleStateRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ IN ULONG OpenMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the open mode for a file handle.
+
+Arguments:
+
+ hFileRecord - pointer to record of OS/2 file handle
+
+ OpenMode - open mode to set
+
+Return Value:
+
+ TBS
+
+Note:
+
+ FileLock must be owned exclusively when calling this routine.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(hFileRecord);
+ UNREFERENCED_PARAMETER(OpenMode);
+
+#if DBG
+ IF_OD2_DEBUG(FILESYS)
+ {
+ KdPrint(("[%d,%d] DosSetHandleState: not support for this handle\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+
+APIRET
+DosSetFHState(
+ IN HFILE FileHandle,
+ IN ULONG OpenMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the open mode for a file handle.
+
+Arguments:
+
+ FileHandle - OS/2 file handle
+
+ OpenMode - open mode to set
+
+Return Value:
+
+ ERROR_INVALID_PARAMETER - the open mode contains an illegal value
+
+ ERROR_INVALID_HANDLE - the file handle is not open
+
+--*/
+
+{
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosSetFHState";
+ #endif
+
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+
+ RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+
+ if (OpenMode & ~SETFHSTATE_FLAGS) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ RetCode = IoVectorArray[hFileRecord->IoVectorType]->SetHandleStateRoutine(hFileRecord,OpenMode);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+}
+
+
+APIRET
+DeviceQueryHTypeRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PULONG HandleType,
+ OUT PULONG DeviceFlags
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the handle type of con
+
+Arguments:
+
+ hFileRecord - pointer to record of OS/2 con handle
+
+ HandleType - where to store the handle type
+
+ DeviceFlags - where to store the device flags
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ *DeviceFlags = hFileRecord->DeviceAttribute;
+ *HandleType = HANDTYPE_DEVICE;
+ return NO_ERROR;
+}
+
+
+
+
+APIRET
+FileQueryHTypeRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PULONG HandleType,
+ OUT PULONG DeviceFlags
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the handle type of file
+
+Arguments:
+
+ hFileRecord - pointer to record of OS/2 kbd handle
+
+ HandleType - where to store the handle type
+
+ DeviceFlags - where to store the device flags
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ FILE_FS_DEVICE_INFORMATION FsDeviceInfo;
+
+ *DeviceFlags = hFileRecord->DeviceAttribute;
+ if ((hFileRecord->FileType == FILE_TYPE_NMPIPE) ||
+ (hFileRecord->FileType == FILE_TYPE_PIPE)) {
+ *HandleType = HANDTYPE_PIPE;
+ }
+ else if (hFileRecord->FileType == FILE_TYPE_MAILSLOT) {
+ return ERROR_INVALID_HANDLE;
+ }
+ else {
+ *HandleType = HANDTYPE_FILE;
+ do {
+ Status = NtQueryVolumeInformationFile(
+ hFileRecord->NtHandle,
+ &IoStatus,
+ &FsDeviceInfo,
+ sizeof(FsDeviceInfo),
+ FileFsDeviceInformation
+ );
+ } while (RetryIO(Status, hFileRecord->NtHandle));
+ if (NT_SUCCESS(Status) &&
+ (FsDeviceInfo.Characteristics & FILE_REMOTE_DEVICE)) {
+ *HandleType |= HANDTYPE_NETWORK;
+ }
+ }
+ return NO_ERROR;
+}
+
+
+APIRET
+NoSuppQueryHTypeRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PULONG HandleType,
+ OUT PULONG DeviceFlags
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the handle type of co
+
+Arguments:
+
+ hFileRecord - pointer to record of OS/2 con handle
+
+ HandleType - where to store the handle type
+
+ DeviceFlags - where to store the device flags
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(hFileRecord);
+ UNREFERENCED_PARAMETER(HandleType);
+ UNREFERENCED_PARAMETER(DeviceFlags);
+
+#if DBG
+ IF_OD2_DEBUG(FILESYS)
+ {
+ KdPrint(("[%d,%d] DosQueryHType: not support for this handle\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+
+
+APIRET
+DosQueryHType(
+ IN HFILE FileHandle,
+ OUT PULONG HandleType,
+ OUT PULONG DeviceFlags
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the handle type of a file (file, pipe, device, etc.)
+
+15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+
+C I O G C N S K
+H B P LEVEL I L U C B
+R M N O K L R D
+
+
+*DeviceAttr = DEFAULT_DEVICE_ATTRIBUTE;
+NUL and CLOCK devices are emulated by subsystem, so we set the bits on open
+MapFileType figures out if block/char dev and removable media (if block device)
+
+if (handle == 0)
+
+
+Arguments:
+
+ FileHandle - OS/2 file handle
+
+ HandleType - where to store the handle type
+
+ DeviceFlags - where to store the device flags
+
+Return Value:
+
+ ERROR_INVALID_HANDLE - the file handle is not open
+
+--*/
+
+{
+ PFILE_HANDLE hFileRecord;
+ APIRET RetCode;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosQueryHType";
+ #endif
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+
+ RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+
+ //
+ // probe out parms here so code isn't duplicated.
+ //
+
+ try {
+ Od2ProbeForWrite(HandleType, sizeof(ULONG), 1);
+ Od2ProbeForWrite(DeviceFlags, sizeof(ULONG), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ Od2ExitGP();
+ }
+ RetCode = IoVectorArray[hFileRecord->IoVectorType]->QueryHandleTypeRoutine(hFileRecord,HandleType,DeviceFlags);
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+}
+
+APIRET
+FileCloseRoutine(
+ IN PFILE_HANDLE hFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes an OS/2 file handle. The handle is not freed.
+
+Arguments:
+
+ VectorType - handle type
+
+ hFileRecord - pointer to record of OS/2 file handle to close.
+
+Return Value:
+
+ TBS
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ InvalidateHandle(hFileRecord);
+ NtClose(hFileRecord->NtHandle);
+ return( NO_ERROR );
+}
+
+APIRET
+DeviceCloseRoutine(
+ IN PFILE_HANDLE hFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes an OS/2 handle to a device. The handle is not freed.
+
+Arguments:
+
+ VectorType - device type
+
+ hFileRecord - pointer to record of OS/2 handle to close.
+
+Return Value:
+
+ TBS
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ ULONG ShareAccess;
+ ULONG DesiredAccess;
+
+ //
+ // map share accesses
+ //
+
+ MapShareAccess(hFileRecord->Flags,&DesiredAccess,&ShareAccess);
+
+ InvalidateHandle(hFileRecord);
+
+ return Od2DeviceShare(RemoveShare,
+ hFileRecord->IoVectorType,
+ DesiredAccess,
+ ShareAccess
+ );
+}
+
+APIRET
+KbdCloseRoutine(
+ IN PFILE_HANDLE hFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes an OS/2 handle to a device. The handle is not freed.
+
+Arguments:
+
+ VectorType - device type
+
+ hFileRecord - pointer to record of OS/2 handle to close.
+
+Return Value:
+
+ TBS
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ ULONG ShareAccess;
+ ULONG DesiredAccess;
+ SCREQUESTMSG Request;
+ NTSTATUS Status;
+
+ //
+ // map share accesses
+ //
+
+ MapShareAccess(hFileRecord->Flags,&DesiredAccess,&ShareAccess);
+
+ InvalidateHandle(hFileRecord);
+
+ if (hFileRecord->DeviceAttribute & DEVICE_ATTRIBUTE_GENIOCTL)
+ {
+ return Od2DeviceShare(RemoveShare,
+ hFileRecord->IoVectorType,
+ DesiredAccess,
+ ShareAccess
+ );
+ } else
+ {
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.hKbd = hFileRecord->NtHandle;
+ Request.Request = KbdRequest;
+ Request.d.Kbd.Request = KBDClose;
+ Status = SendCtrlConsoleRequest(&Request, NULL, NULL, NULL);
+
+ return NO_ERROR;
+ }
+}
+
+APIRET
+MouseCloseRoutine(
+ IN PFILE_HANDLE hFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes an OS/2 handle to a device. The handle is not freed.
+
+Arguments:
+
+ VectorType - device type
+
+ hFileRecord - pointer to record of OS/2 handle to close.
+
+Return Value:
+
+ TBS
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ ULONG ShareAccess;
+ ULONG DesiredAccess;
+ APIRET ApiRet;
+
+ //
+ // map share accesses
+ //
+
+ MapShareAccess(hFileRecord->Flags,&DesiredAccess,&ShareAccess);
+
+ InvalidateHandle(hFileRecord);
+
+ ApiRet = Od2DeviceShare(RemoveShare,
+ hFileRecord->IoVectorType,
+ DesiredAccess,
+ ShareAccess
+ );
+
+ if (!ApiRet)
+ {
+ ApiRet = DevMouClose();
+ }
+
+ return ApiRet;
+}
+
+APIRET
+ComCloseRoutine(
+ IN PFILE_HANDLE hFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes an OS/2 COM handle. The handle is not freed.
+
+Arguments:
+
+ VectorType - handle type
+
+ hFileRecord - pointer to record of OS/2 file handle to close.
+
+Return Value:
+
+ TBS
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ InvalidateHandle(hFileRecord);
+ NtClose(hFileRecord->NtAsyncReadEvent);
+ NtClose(hFileRecord->NtAsyncWriteEvent);
+ NtClose(hFileRecord->NtAsyncIOCtlEvent);
+ NtClose(hFileRecord->NtHandle);
+ return( NO_ERROR );
+}
+
+APIRET
+NoSuppCloseRoutine(
+ IN PFILE_HANDLE hFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes an OS/2 handle to a device. The handle is not freed.
+
+Arguments:
+
+ VectorType - device type
+
+ hFileRecord - pointer to record of OS/2 handle to close.
+
+Return Value:
+
+ TBS
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(hFileRecord);
+
+#if DBG
+ IF_OD2_DEBUG(FILESYS)
+ {
+ KdPrint(("[%d,%d] DosClose: not support for this handle\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+APIRET
+Od2CloseHandle(
+ IN PFILE_HANDLE hFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes an OS/2 file handle. The handle is not freed.
+
+Arguments:
+
+ hFileRecord - pointer to record of OS/2 file handle to close.
+
+Return Value:
+
+ TBS
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ return (IoVectorArray[hFileRecord->IoVectorType]->CloseRoutine(hFileRecord));
+}
+
+APIRET
+FileDupHandleRoutine(
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine duplicates an OS/2 file handle.
+
+Arguments:
+
+ VectorType - handle type
+
+ hOldFileRecord - pointer to OS/2 file handle record to duplicate
+
+ hNewFileRecord - pointer to allocated new OS/2 file handle record
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ //
+ // duplicate the NT handle and copy the flags, etc here.
+ //
+ // duped handles are always inherited.
+ //
+
+ Status = NtDuplicateObject(NtCurrentProcess(),
+ hOldFileRecord->NtHandle,
+ NtCurrentProcess(),
+ &(hNewFileRecord->NtHandle),
+ (ACCESS_MASK) NULL,
+ OBJ_CASE_INSENSITIVE,
+ DUPLICATE_SAME_ACCESS
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] NtDuplicateObject failed in FileDupHandle. Status is = %X.\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+ }
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE));
+ }
+ hNewFileRecord->FileType = hOldFileRecord->FileType;
+ hNewFileRecord->IoVectorType = hOldFileRecord->IoVectorType;
+
+ //
+ // OS/2 sets the flags to zero in duped handle. this applies to the flags that are
+ // stored in the handle (inheritance, writethrough, cache, fail-error), but
+ // not to those stored in the SFT (access and sharing).
+ //
+
+ hNewFileRecord->Flags = hOldFileRecord->Flags & ~SETFHSTATE_FLAGS;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] HandleTable[OldFileHandle] flags = %ld NtHandle = %ld FileType = %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hOldFileRecord->Flags,hOldFileRecord->NtHandle,hOldFileRecord->FileType));
+ KdPrint(("[%d,%d] HandleTable[NewFileHandle] flags = %ld NtHandle = %ld FileType = %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hNewFileRecord->Flags,hNewFileRecord->NtHandle,hNewFileRecord->FileType));
+ }
+#endif
+ ValidateHandle(hNewFileRecord);
+ return NO_ERROR;
+}
+
+APIRET
+ComDupHandleRoutine(
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine duplicates an OS/2 COM handle.
+
+Arguments:
+
+ VectorType - handle type
+
+ hOldFileRecord - pointer to OS/2 file handle record to duplicate
+
+ hNewFileRecord - pointer to allocated new OS/2 file handle record
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ //
+ // duplicate the NT handle and copy the flags, etc here.
+ //
+ // duped handles are always inherited.
+ //
+
+ Status = NtDuplicateObject(NtCurrentProcess(),
+ hOldFileRecord->NtHandle,
+ NtCurrentProcess(),
+ &(hNewFileRecord->NtHandle),
+ (ACCESS_MASK) NULL,
+ OBJ_CASE_INSENSITIVE,
+ DUPLICATE_SAME_ACCESS
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] NtDuplicateObject failed in FileDupHandle. Status is = %X.\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+ }
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE));
+ }
+ hNewFileRecord->FileType = hOldFileRecord->FileType;
+ hNewFileRecord->IoVectorType = hOldFileRecord->IoVectorType;
+
+ Status = NtCreateEvent(&hNewFileRecord->NtAsyncReadEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("[%d,%d] OS2DLL: DosOpen-Unable to NtCreateEvent()-for ComRead, Status = %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+#endif
+ }
+
+ Status = NtCreateEvent(&hNewFileRecord->NtAsyncWriteEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("[%d,%d] OS2DLL: DosOpen-Unable to NtCreateEvent()-for ComWrite, Status = %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+#endif
+ }
+
+ Status = NtCreateEvent(&hNewFileRecord->NtAsyncIOCtlEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("[%d,%d] OS2DLL: DosOpen-Unable to NtCreateEvent()-for ComIOCtl, Status = %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+#endif
+ }
+
+ //
+ // OS/2 sets the flags to zero in duped handle. this applies to the flags that are
+ // stored in the handle (inheritance, writethrough, cache, fail-error), but
+ // not to those stored in the SFT (access and sharing).
+ //
+
+ hNewFileRecord->Flags = hOldFileRecord->Flags & ~SETFHSTATE_FLAGS;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] HandleTable[OldFileHandle] flags = %ld NtHandle = %ld FileType = %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hOldFileRecord->Flags,hOldFileRecord->NtHandle,hOldFileRecord->FileType));
+ KdPrint(("[%d,%d] HandleTable[NewFileHandle] flags = %ld NtHandle = %ld FileType = %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hNewFileRecord->Flags,hNewFileRecord->NtHandle,hNewFileRecord->FileType));
+ }
+#endif
+ ValidateHandle(hNewFileRecord);
+ return NO_ERROR;
+}
+
+VOID
+MapShareAccess(
+ IN ULONG OpenMode,
+ OUT PULONG DesiredAccess,
+ OUT PULONG ShareAccess
+ )
+{
+ *ShareAccess = 0;
+ if (((OpenMode & SHARE_FLAGS) != (OPEN_SHARE_DENYREADWRITE)) &&
+ ((OpenMode & SHARE_FLAGS) != (OPEN_SHARE_DENYREAD))) {
+ *ShareAccess |= FILE_SHARE_READ;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] setting read share access\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ }
+ if (((OpenMode & SHARE_FLAGS) != (OPEN_SHARE_DENYREADWRITE)) &&
+ ((OpenMode & SHARE_FLAGS) != (OPEN_SHARE_DENYWRITE))) {
+ *ShareAccess |= FILE_SHARE_WRITE;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] setting write share access\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ }
+
+ //
+ // map requested access
+ //
+
+ *DesiredAccess = FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES;
+
+ if (((OpenMode & ACCESS_FLAGS) == OPEN_ACCESS_READONLY) ||
+ (OpenMode & OPEN_ACCESS_READWRITE)) {
+ *DesiredAccess |= FILE_READ_DATA;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] setting request read access\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ }
+ if (OpenMode & (OPEN_ACCESS_WRITEONLY | OPEN_ACCESS_READWRITE)) {
+ *DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] setting request write access\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ }
+}
+
+APIRET
+DeviceDupHandleRoutine(
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine duplicates an OS/2 handle to a device.
+
+Arguments:
+
+ hOldFileRecord - pointer to OS/2 handle record to duplicate
+
+ hNewFileRecord - pointer to allocated new OS/2 handle record
+
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ ULONG ShareAccess;
+ ULONG DesiredAccess;
+ APIRET RetCode;
+
+ // map share accesses
+
+ MapShareAccess(hOldFileRecord->Flags,&DesiredAccess,&ShareAccess);
+
+ RetCode = Od2DeviceShare(DupShare,
+ hOldFileRecord->IoVectorType,
+ DesiredAccess,
+ ShareAccess
+ );
+ if (RetCode != NO_ERROR)
+ {
+ ASSERT (FALSE);
+ return RetCode;
+ }
+ hNewFileRecord->Flags = hOldFileRecord->Flags & ~SETFHSTATE_FLAGS;
+
+ hNewFileRecord->NtHandle = hOldFileRecord->NtHandle;
+ hNewFileRecord->FileType = hOldFileRecord->FileType;
+ hNewFileRecord->IoVectorType = hOldFileRecord->IoVectorType;
+ ValidateHandle(hNewFileRecord);
+ return NO_ERROR;
+}
+
+APIRET
+KbdDupHandleRoutine(
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine duplicates an OS/2 handle to a device.
+
+Arguments:
+
+ hOldFileRecord - pointer to OS/2 handle record to duplicate
+
+ hNewFileRecord - pointer to allocated new OS/2 handle record
+
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ ULONG ShareAccess;
+ ULONG DesiredAccess;
+ APIRET RetCode;
+
+ // map share accesses
+
+ MapShareAccess(hOldFileRecord->Flags,&DesiredAccess,&ShareAccess);
+
+ if (hOldFileRecord->DeviceAttribute & DEVICE_ATTRIBUTE_GENIOCTL)
+ {
+ RetCode = Od2DeviceShare(DupShare,
+ hOldFileRecord->IoVectorType,
+ DesiredAccess,
+ ShareAccess
+ );
+ } else
+ {
+
+ RetCode = KbdDupLogHandle(hOldFileRecord->NtHandle);
+ }
+ if (RetCode != NO_ERROR)
+ {
+ ASSERT (FALSE);
+ return RetCode;
+ }
+
+ hNewFileRecord->Flags = hOldFileRecord->Flags & ~SETFHSTATE_FLAGS;
+
+ hNewFileRecord->NtHandle = hOldFileRecord->NtHandle;
+ hNewFileRecord->FileType = hOldFileRecord->FileType;
+ hNewFileRecord->IoVectorType = hOldFileRecord->IoVectorType;
+ ValidateHandle(hNewFileRecord);
+ return NO_ERROR;
+}
+
+APIRET
+MouseDupHandleRoutine(
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine duplicates an OS/2 handle to a device.
+
+Arguments:
+
+ hOldFileRecord - pointer to OS/2 handle record to duplicate
+
+ hNewFileRecord - pointer to allocated new OS/2 handle record
+
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ ULONG ShareAccess;
+ ULONG DesiredAccess;
+ APIRET RetCode;
+
+ // map share accesses
+
+ MapShareAccess(hOldFileRecord->Flags,&DesiredAccess,&ShareAccess);
+
+ RetCode = Od2DeviceShare(DupShare,
+ hOldFileRecord->IoVectorType,
+ DesiredAccess,
+ ShareAccess
+ );
+ if (RetCode != NO_ERROR)
+ {
+ ASSERT (FALSE);
+ return RetCode;
+ }
+
+ RetCode = DevMouOpen(&(hNewFileRecord->NtHandle));
+
+ if ( RetCode )
+ {
+ ASSERT(FALSE);
+ return(RetCode);
+ }
+
+ hNewFileRecord->Flags = hOldFileRecord->Flags & ~SETFHSTATE_FLAGS;
+
+// hNewFileRecord->NtHandle = hOldFileRecord->NtHandle;
+ hNewFileRecord->FileType = hOldFileRecord->FileType;
+ hNewFileRecord->IoVectorType = hOldFileRecord->IoVectorType;
+ ValidateHandle(hNewFileRecord);
+ return NO_ERROR;
+}
+
+APIRET
+NoSuppDupHandleRoutine(
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine duplicates an OS/2 handle to a device.
+
+Arguments:
+
+ hOldFileRecord - pointer to OS/2 handle record to duplicate
+
+ hNewFileRecord - pointer to allocated new OS/2 handle record
+
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(hOldFileRecord);
+ UNREFERENCED_PARAMETER(hNewFileRecord);
+
+#if DBG
+ IF_OD2_DEBUG(FILESYS)
+ {
+ KdPrint(("[%d,%d] DosDupHandle: no support for this handle\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+
+APIRET
+DosDupHandle(
+ IN HFILE OldFileHandle,
+ IN OUT PHFILE NewFileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine duplicates an OS/2 file handle.
+
+Arguments:
+
+ OldFileHandle - OS/2 file handle to duplicate
+
+ NewFileHandle - where to store new OS/2 file handle
+
+Return Value:
+
+ ERROR_INVALID_HANDLE - the OldFileHandle is not open
+
+ ERROR_INVALID_TARGET_HANDLE - the NewFileHandle is not open
+
+--*/
+
+{
+ APIRET RetCode;
+ PFILE_HANDLE hOldFileRecord;
+ PFILE_HANDLE hNewFileRecord;
+ HFILE TargetHandle;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosDupHandle";
+ #endif
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] entering DosDupHandle. OldFileHandle = %ld. NewFileHandle = %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ OldFileHandle,*NewFileHandle));
+ }
+#endif
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid source handle.
+ //
+
+ RetCode = DereferenceFileHandle(OldFileHandle,&hOldFileRecord);
+ if (RetCode) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ try {
+ TargetHandle = *NewFileHandle;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ Od2ExitGP();
+ }
+
+ //
+ // If user requested a new target handle, allocate one.
+ //
+
+ if (TargetHandle == (HFILE) DDH_NEW_HANDLE) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] allocating a new handle\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ if (RetCode = AllocateHandle(NewFileHandle)) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ hNewFileRecord = DereferenceFileHandleNoCheck(*NewFileHandle);
+ }
+
+ //
+ // Else, if the existing handle in the new slow is open, close it, but don't free it.
+ //
+
+ else {
+
+ //
+ // Check for invalid target handle
+ //
+
+ RetCode = DereferenceFileHandle(TargetHandle,&hNewFileRecord);
+ if (RetCode && (((ULONG) TargetHandle) >= HandleTableLength)) {
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_TARGET_HANDLE;
+ }
+ if (TargetHandle == OldFileHandle) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_TARGET_HANDLE;
+ }
+
+ if (RetCode) {
+ //
+ // A forced dup to a free handle - allocate
+ //
+ if (RetCode = AllocateHandle(NewFileHandle)) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ hNewFileRecord = DereferenceFileHandleNoCheck(*NewFileHandle);
+ }
+ else {
+
+ //
+ // The file handle is open - close it
+ //
+ RetCode = Od2CloseHandle(hNewFileRecord); // closes handle without freeing
+ }
+ }
+
+ //
+ // now duplicate the handle itself
+ //
+ RetCode = IoVectorArray[hOldFileRecord->IoVectorType]->DupHandleRoutine(hOldFileRecord,hNewFileRecord);
+ if (RetCode)
+ FreeHandle(*NewFileHandle);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+}
+
+
+APIRET
+DosSetMaxFH(
+ IN ULONG MaxFileHandles
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increases the size of the file handle table.
+
+Arguments:
+
+ MaxFileHandles - new size of the file handle table.
+
+Return Value:
+
+ ERROR_INVALID_PARAMETER - the new size is smaller than the old size.
+
+--*/
+
+{
+ PFILE_HANDLE NewTable;
+ ULONG i;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosSetMaxFH";
+ #endif
+
+ //
+ // The maximum number of file handles
+ //
+ if (MaxFileHandles > 32768) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // if trying to shrink table, return error.
+ //
+
+ if (MaxFileHandles < HandleTableLength) {
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // if no change in table size, return no error.
+ //
+
+ if (MaxFileHandles == HandleTableLength) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return NO_ERROR;
+ }
+
+ //
+ // allocate heap space for new table and copy old one over it.
+ // initialize new handles.
+ // if the old table was allocated from heap space, as opposed to instance
+ // data, free the space.
+ //
+
+ NewTable = RtlAllocateHeap(Od2Heap,0,MaxFileHandles * sizeof(FILE_HANDLE));
+ if (NewTable == NULL) {
+#if DBG
+ KdPrint(("[%d,%d] OS2: DosSetMaxFH, no memory in Od2Heap\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ ASSERT(FALSE);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ RtlMoveMemory(NewTable,HandleTable,HandleTableLength * sizeof(FILE_HANDLE));
+ for (i=HandleTableLength;i<MaxFileHandles;i++)
+ NewTable[i].Flags = FILE_HANDLE_FREE;
+ if (HandleTableLength != INITIALFILEHANDLES)
+ RtlFreeHeap(Od2Heap,0,HandleTable);
+ HandleTable = NewTable;
+ HandleTableLength = MaxFileHandles;
+
+ //
+ // print out handle table
+ //
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] new max file handles is %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ HandleTableLength));
+ }
+#endif
+ for (i=0;i<MaxFileHandles;i++) {
+ if (NewTable[i].Flags == FILE_HANDLE_FREE) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] NewTable[%ld] is free\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ i));
+ }
+#endif
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] NewTable[%ld] flags = %ld NtHandle = %ld FileType = %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ i,
+ NewTable[i].Flags,NewTable[i].NtHandle,NewTable[i].FileType));
+ }
+#endif
+ }
+ }
+
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return NO_ERROR;
+}
+
+
+APIRET
+DosClose(
+ IN HFILE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes an OS/2 file handle.
+
+Arguments:
+
+ FileHandle - OS/2 file handle to close.
+
+Return Value:
+
+ ERROR_INVALID_HANDLE - the file handle is not open
+
+--*/
+
+{
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosClose";
+ #endif
+
+
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] handle is %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ FileHandle));
+ KdPrint(("[%d,%d] HandleTableLength is %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ HandleTableLength));
+ }
+#endif
+
+ //
+ // Check for invalid handle.
+ //
+
+ RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ RetCode = Od2CloseHandle(hFileRecord); // this retcode is intentionally ignored
+ RetCode = FreeHandle(FileHandle);
+ ASSERT (!(RetCode));
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return NO_ERROR;
+}
+
+
+APIRET
+ConReadRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads from kbd.
+
+Arguments:
+
+ hFileRecord - pointer to OS/2 file handle record to read from
+
+ Buffer - buffer to read data into
+
+ Length - length of buffer
+
+ BytesRead - where to store number of bytes read
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ This routine releases the filelock.
+
+--*/
+
+{
+ NTSTATUS Status;
+ FILE_HANDLE KbdHandle;
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "ConReadRoutine";
+ #endif
+
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ KdPrint(("[%d,%d] ConReadRoutine: Length %lu, Handle %p\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Length,
+ hFileRecord ));
+ }
+#endif
+
+ if ((hFileRecord->Flags & ACCESS_FLAGS ) == OPEN_ACCESS_WRITEONLY)
+ {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_ACCESS_DENIED;
+ }
+
+ /*
+ * CON handle cannot keep 2 handles in NtHandle field (for Screen & Kbd).
+ * So, we kkep only the VIO handle.
+ * For the read function, we prepare a dummy entry.
+ */
+
+ KbdHandle = *hFileRecord;
+ KbdHandle.NtHandle = (HANDLE)SesGrp->PhyKbd;
+
+ Status = KbdRead(&KbdHandle, Buffer, Length, BytesRead, KBDRead);
+
+ return(Status);
+
+}
+
+
+APIRET
+KbdReadRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads from kbd.
+
+Arguments:
+
+ hFileRecord - pointer to OS/2 file handle record to read from
+
+ Buffer - buffer to read data into
+
+ Length - length of buffer
+
+ BytesRead - where to store number of bytes read
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ This routine releases the filelock.
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "KbdReadRoutine";
+ #endif
+
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ KdPrint(("[%d,%d] KbdReadRoutine: Length %lu, Handle %p\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Length,
+ hFileRecord ));
+ }
+#endif
+
+ if ((hFileRecord->Flags & ACCESS_FLAGS ) == OPEN_ACCESS_WRITEONLY)
+ {
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_ACCESS_DENIED;
+ }
+
+ Status = KbdRead(hFileRecord, Buffer, Length, BytesRead, KBDRead);
+
+ return(Status);
+
+}
+
+APIRET
+TmpReadRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns an error.
+
+Arguments:
+
+ hFileRecord - pointer to OS/2 file handle record to read from
+
+ Buffer - buffer to read data into
+
+ Length - length of buffer
+
+ BytesRead - where to store number of bytes read
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ This routine releases the filelock.
+
+--*/
+
+{
+ APIRET RetCode;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "TmpReadRoutine";
+ #endif
+
+ UNREFERENCED_PARAMETER(hFileRecord);
+ UNREFERENCED_PARAMETER(Buffer);
+ UNREFERENCED_PARAMETER(Length);
+ UNREFERENCED_PARAMETER(BytesRead);
+
+ if ((hFileRecord->Flags & ACCESS_FLAGS ) == OPEN_ACCESS_WRITEONLY)
+ {
+ RetCode = ERROR_ACCESS_DENIED;
+ } else
+ {
+ RetCode = ERROR_NOT_SUPPORTED;
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ return RetCode;
+}
+
+APIRET
+NulReadRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ This routine always returns success with the number of bytes read
+ equal to 0
+
+Arguments:
+
+ hFileRecord - pointer to OS/2 file handle record to read from
+
+ Buffer - buffer to read data into
+
+ Length - length of buffer
+
+ BytesRead - where to store number of bytes read
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ This routine releases the filelock.
+
+--*/
+
+{
+ APIRET RetCode;
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "NulReadRoutine";
+ #endif
+
+ UNREFERENCED_PARAMETER(Buffer);
+ UNREFERENCED_PARAMETER(Length);
+
+ if ((hFileRecord->Flags & ACCESS_FLAGS ) == OPEN_ACCESS_WRITEONLY)
+ {
+ RetCode = ERROR_ACCESS_DENIED;
+ } else
+ {
+ *BytesRead = 0;
+ RetCode = NO_ERROR;
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ return RetCode;
+
+}
+
+
+APIRET
+FileReadRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads from an OS/2 file handle.
+
+Arguments:
+
+ hFileRecord - pointer to OS/2 file handle record to read from
+
+ Buffer - buffer to read data into
+
+ Length - length of buffer
+
+ BytesRead - where to store number of bytes read
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ This routine releases the filelock.
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ LARGE_INTEGER FileOffset;
+ HANDLE NtHandle;
+ HANDLE Event;
+ BOOLEAN fNPipe;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "FileReadRoutine";
+ #endif
+
+ // BUGBUG need to check for alignment and probe validity
+
+ FileOffset = RtlConvertLongToLargeInteger(FILE_USE_FILE_POINTER_POSITION);
+ NtHandle = hFileRecord->NtHandle;
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ fNPipe = ((hFileRecord->FileType == FILE_TYPE_NMPIPE) ||
+ (hFileRecord->FileType == FILE_TYPE_PIPE)) ? TRUE : FALSE;
+ if (fNPipe) {
+ Status = NtCreateEvent(&Event,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE
+ );
+ if (Status != STATUS_SUCCESS) {
+#if DBG
+ DbgPrint("[%d,%d] FileReadRoutine: Unable to NtCreateEvent(), Status 0x%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+#endif
+ return( Status );
+ }
+ }
+
+ do {
+ Status = NtReadFile(NtHandle,
+ (fNPipe ? Event : (HANDLE)NULL),
+ (PIO_APC_ROUTINE) NULL,
+ (PVOID) NULL,
+ &IoStatus,
+ Buffer,
+ Length,
+ (fNPipe ? NULL : &FileOffset),
+ NULL
+ );
+ } while (RetryIO(Status, NtHandle));
+ //
+ // If the operation was successful, return the total number of bytes
+ // read, otherwise, if the error was STATUS_END_OF_FILE, return success,
+ // but no bytes transferred, otherwise, return an appropriate error.
+ //
+
+ if (NT_SUCCESS(Status) && !(Status == STATUS_PENDING)) {
+ *BytesRead = IoStatus.Information;
+ if (fNPipe) {
+ NtClose(Event);
+ }
+ return NO_ERROR;
+ } else if (Status == STATUS_END_OF_FILE) {
+ *BytesRead = 0;
+ if (fNPipe) {
+ NtClose(Event);
+ }
+ return NO_ERROR;
+ } else if ((Status == STATUS_PENDING) && fNPipe) {
+ Status = Od2AlertableWaitForSingleObject(Event);
+ NtClose(Event);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] ReadFileRoutine, Pipe, Status %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+ }
+#endif
+ *BytesRead = IoStatus.Information;
+ return ERROR_ACCESS_DENIED;
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] ReadFileRoutine, Pipe, Block completed successfully \n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesRead = IoStatus.Information;
+ return NO_ERROR;
+ }
+ } else {
+ if (fNPipe) {
+ NtClose(Event);
+ }
+ if (fNPipe) {
+ if (Status == STATUS_PIPE_EMPTY) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosRead Named pipe: STATUS_PIPE_EMPTY\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+// *BytesRead = IoStatus.Information;
+ *BytesRead = 0;
+ return ERROR_NO_DATA;
+ }
+ else if (Status == STATUS_END_OF_FILE) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosRead Named pipe: STATUS_END_OF_FILE\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesRead = 0;
+ return NO_ERROR;
+ }
+ else if (Status == STATUS_PIPE_BROKEN) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosRead Named pipe: STATUS_PIPE_BROKEN\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesRead = 0;
+ //return ERROR_BROKEN_PIPE;
+ //
+ // Return NO_ERROR for compatibility (SQL server, setup).
+ //
+ return NO_ERROR;
+ }
+ else if (Status == STATUS_PIPE_LISTENING) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosRead Named pipe: STATUS_PIPE_LISTEMING\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesRead = 0;
+ return NO_ERROR;
+ }
+ else if (Status == STATUS_INVALID_PIPE_STATE) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosRead Named pipe: STATUS_INVALID_PIPE_STATE\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesRead = 0;
+ return ERROR_PIPE_NOT_CONNECTED;
+ }
+ else if (Status == STATUS_PIPE_DISCONNECTED) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosRead Named pipe: STATUS_PIPE_DISCONNECTED\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesRead = 0;
+ return ERROR_PIPE_NOT_CONNECTED;
+ }
+ else if (Status == STATUS_ACCESS_DENIED) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosRead Named pipe: STATUS_ACCESS_DENIED\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesRead = 0;
+ return ERROR_ACCESS_DENIED;
+ }
+ else if (Status == STATUS_BUFFER_OVERFLOW) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosRead Named pipe: STATUS_BUFFER_OVERFLOW\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesRead = IoStatus.Information;
+ return ERROR_MORE_DATA;
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosRead on a named pipe - map status %lx to ERROR_ACCESS_DENIED\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+ }
+#endif
+ *BytesRead = 0;
+ return ERROR_ACCESS_DENIED; // BUGBUG bogus error
+ }
+ }
+ else {
+ *BytesRead = 0;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] DosRead (not a named pipe) - returned status %lx\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+ }
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
+ }
+ }
+}
+
+
+APIRET
+DosRead(
+ IN HFILE FileHandle,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads from an OS/2 file handle.
+
+Arguments:
+
+ FileHandle - OS/2 file handle to read from.
+
+ Buffer - buffer to read data into
+
+ Length - length of buffer
+
+ BytesRead - where to store number of bytes read
+
+Return Value:
+
+ ERROR_INVALID_HANDLE - the file handle is not open
+
+ ERROR_ACCESS_DENIED - the file handle is not open in a mode which allows
+ reading
+
+--*/
+
+{
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosRead";
+ #endif
+
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] DosRead: handle is %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ FileHandle));
+ }
+#endif
+
+ //
+ // Check for invalid handle.
+ //
+
+ try {
+ Od2ProbeForWrite(BytesRead, sizeof(ULONG), 1);
+ Od2ProbeForWrite(Buffer,Length,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ Od2ExitGP();
+ }
+ RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ if (Length == 0) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ *BytesRead = 0;
+ return NO_ERROR;
+ }
+ RetCode = IoVectorArray[hFileRecord->IoVectorType]->ReadRoutine(hFileRecord,
+ Buffer,
+ Length,
+ BytesRead);
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ if ((hFileRecord->FileType == FILE_TYPE_NMPIPE) ||
+ (hFileRecord->FileType == FILE_TYPE_PIPE)) {
+ KdPrint(("[%d,%d] DosRead on Named pipe: Handle %ld Status %ld Bytes Requested %d Bytes Read %d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ FileHandle, RetCode, Length, *BytesRead));
+ }
+ }
+#endif
+ return RetCode;
+}
+
+
+APIRET
+FileWriteRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes to an OS/2 file handle.
+
+Arguments:
+
+ hFileRecord - pointer to OS/2 file handle record to write to
+
+ Buffer - buffer to write data to
+
+ Length - length of buffer
+
+ BytesWritten - where to store number of bytes written
+
+Return Value:
+
+ TBS
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ LARGE_INTEGER FileOffset;
+ HANDLE NtHandle;
+ HANDLE Event;
+ BOOLEAN fNPipe;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "FileWriteRoutine";
+ #endif
+
+
+ // BUGBUG need to check for alignment and probe validity
+
+ FileOffset = RtlConvertLongToLargeInteger(FILE_USE_FILE_POINTER_POSITION);
+ NtHandle = hFileRecord->NtHandle;
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ fNPipe = ((hFileRecord->FileType == FILE_TYPE_NMPIPE) ||
+ (hFileRecord->FileType == FILE_TYPE_PIPE)) ? TRUE : FALSE;
+ if (fNPipe) {
+ Status = NtCreateEvent(&Event,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE
+ );
+ if (Status != STATUS_SUCCESS) {
+#if DBG
+ DbgPrint("[%d,%d] FileWriteRoutine: Unable to NtCreateEvent(), Status 0x%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+#endif
+ return( Status );
+ }
+ }
+
+ do {
+ Status = NtWriteFile(NtHandle,
+ (fNPipe ? Event : (HANDLE)NULL),
+ (PIO_APC_ROUTINE) NULL,
+ (PVOID) NULL,
+ &IoStatus,
+ Buffer,
+ Length,
+ (fNPipe ? NULL : &FileOffset),
+ NULL
+ );
+ } while (RetryIO(Status, NtHandle));
+ //
+ // If the write was successful, then return the correct number of bytes to
+ // the caller. If the error was STATUS_DISK_FULL, return 0 bytes written,
+ // but no error to the caller. Otherwise, figure out an appropriate error
+ // and return that error.
+ //
+
+ if (NT_SUCCESS(Status) && !(Status == STATUS_PENDING)) {
+ *BytesWritten = IoStatus.Information;
+ if (!NT_SUCCESS(IoStatus.Status)){
+#if DBG
+ KdPrint(("[%d,%d] WriteFileRoutine, Pipe, Status SUCCESS, IoStatus %lx\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ IoStatus.Status));
+#endif
+ }
+ if (fNPipe) {
+ NtClose(Event);
+ }
+ return NO_ERROR;
+ } else if (Status == STATUS_DISK_FULL) {
+ *BytesWritten = 0;
+ if (fNPipe) {
+ NtClose(Event);
+ }
+ return NO_ERROR;
+ } else if ((Status == STATUS_PENDING) && fNPipe) {
+ Status = Od2AlertableWaitForSingleObject(Event);
+ NtClose(Event);
+ if (!NT_SUCCESS(Status)) {
+ if (Status == STATUS_PIPE_DISCONNECTED) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosWrite Named pipe: STATUS_PIPE_DISCONNECTED\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesWritten = 0;
+ return ERROR_PIPE_NOT_CONNECTED;
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] WriteFileRoutine, Pipe, Status %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+ }
+#endif
+ *BytesWritten = 0;
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] WriteFileRoutine, Pipe, Blocking succeeded\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesWritten = IoStatus.Information;
+ return NO_ERROR;
+ }
+ } else {
+ if (fNPipe) {
+ NtClose(Event);
+ }
+ if (fNPipe) {
+ if (Status == STATUS_PIPE_EMPTY) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosWrite Named pipe: STATUS_PIPE_EMPTY\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesWritten = IoStatus.Information;
+ return ERROR_NO_DATA;
+ }
+ if (Status == STATUS_END_OF_FILE) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosWrite Named pipe: STATUS_END_OF_FILE\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesWritten = 0;
+ return NO_ERROR;
+ }
+ if (Status == STATUS_PIPE_DISCONNECTED) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosWrite Named pipe: STATUS_PIPE_DISCONNECTED\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesWritten = 0;
+ return ERROR_PIPE_NOT_CONNECTED;
+ }
+ if (Status == STATUS_PIPE_BROKEN) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosWrite Named pipe: STATUS_PIPE_BROKEN\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesWritten = 0;
+ //return ERROR_BROKEN_PIPE;
+ //
+ // Return NO_ERROR for compatibility (SQL server, setup).
+ //
+ return NO_ERROR;
+ }
+ if (Status == STATUS_PIPE_CLOSING) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] DosWrite Named pipe: STATUS_PIPE_CLOSING\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ *BytesWritten = 0;
+ return ERROR_BROKEN_PIPE;
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("[%d,%d] WriteFileRoutine, Pipe, Status %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+ }
+#endif
+ *BytesWritten = 0;
+ return ERROR_ACCESS_DENIED; // BUGBUG bogus error
+ }
+ }
+ else {
+ *BytesWritten = 0;
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
+ }
+ }
+}
+
+
+APIRET
+TmpWriteRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns an error.
+
+Arguments:
+
+ hFileRecord - pointer to OS/2 pipe handle record to write to
+
+ Buffer - buffer to write data to
+
+ Length - length of buffer
+
+ BytesWritten - where to store number of bytes written
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ This routine releases the filelock.
+
+--*/
+
+{
+ APIRET RetCode;
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "TmpWriteRoutine";
+ #endif
+ UNREFERENCED_PARAMETER(Buffer);
+ UNREFERENCED_PARAMETER(Length);
+ UNREFERENCED_PARAMETER(BytesWritten);
+
+ if ((hFileRecord->Flags & ACCESS_FLAGS ) == OPEN_ACCESS_READONLY)
+ {
+ RetCode = ERROR_ACCESS_DENIED;
+ } else
+ {
+ RetCode = ERROR_NOT_SUPPORTED;
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ return RetCode;
+
+}
+
+
+APIRET
+NulWriteRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ )
+
+/*++
+
+Routine Description:
+
+ This routine always returns success with the number of bytes written
+ equal to Length.
+
+Arguments:
+
+ hFileRecord - pointer to OS/2 pipe handle record to write to
+
+ Buffer - buffer to write data to
+
+ Length - length of buffer
+
+ BytesWritten - where to store number of bytes written
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ This routine releases the filelock.
+
+--*/
+
+{
+ APIRET RetCode;
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "NulWriteRoutine";
+ #endif
+
+ UNREFERENCED_PARAMETER(Buffer);
+ UNREFERENCED_PARAMETER(Length);
+
+ if ((hFileRecord->Flags & ACCESS_FLAGS ) == OPEN_ACCESS_READONLY)
+ {
+ RetCode = ERROR_ACCESS_DENIED;
+ } else
+ {
+ *BytesWritten = Length;
+ RetCode = NO_ERROR;
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ return RetCode;
+}
+
+
+APIRET
+ScreenWriteRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ )
+
+/*++
+
+Routine Description:
+
+ This routine write to the con.
+
+Arguments:
+
+ hFileRecord - pointer to OS/2 pipe handle record to write to
+
+ Buffer - buffer to write data to
+
+ Length - length of buffer
+
+ BytesWritten - where to store number of bytes written
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ This routine releases the filelock.
+
+--*/
+
+{
+ APIRET RetCode;
+ ULONG Flags;
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "ScreenWriteRoutine";
+ #endif
+
+#if DBG
+ IF_OD2_DEBUG(VIO_FILE)
+ {
+ KdPrint(("[%d,%d] ScreenWriteRoutine: Length %lu, Handle %p\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Length, hFileRecord ));
+ }
+#endif
+
+ Flags = hFileRecord->Flags;
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if ((Flags & ACCESS_FLAGS ) == OPEN_ACCESS_READONLY)
+ {
+ RetCode = ERROR_ACCESS_DENIED;
+ } else
+ {
+ RetCode = VioWrite(hFileRecord, Buffer, Length, BytesWritten, VIOWrtScreen);
+ }
+
+ return(RetCode);
+}
+
+
+APIRET
+DosWrite(
+ IN HFILE FileHandle,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes to an OS/2 file handle.
+
+Arguments:
+
+ FileHandle - OS/2 file handle to write to.
+
+ Buffer - buffer to write data to
+
+ Length - length of buffer
+
+ BytesWritten - where to store number of bytes written
+
+Return Value:
+
+ ERROR_INVALID_HANDLE - the file handle is not open
+
+ ERROR_ACCESS_DENIED - the file handle is not open in a mode which allows
+ writing
+
+--*/
+
+{
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosWrite";
+ #endif
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] Entering DosWrite with handle %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ FileHandle));
+ }
+#endif
+
+ //
+ // Check for invalid handle.
+ //
+
+ try {
+ Od2ProbeForWrite(BytesWritten, sizeof(ULONG), 1);
+ Od2ProbeForRead(Buffer,Length,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ Od2ExitGP();
+ }
+ RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ if (Length == 0) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ *BytesWritten = 0;
+ return NO_ERROR;
+ }
+ RetCode = IoVectorArray[hFileRecord->IoVectorType]->WriteRoutine(hFileRecord,
+ Buffer,
+ Length,
+ BytesWritten);
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ if ((hFileRecord->FileType == FILE_TYPE_NMPIPE) ||
+ (hFileRecord->FileType == FILE_TYPE_PIPE)) {
+ KdPrint(("[%d,%d] DosWrite on Named pipe: Handle %ld Status %ld Bytes Requested %d Bytes Written %d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ FileHandle, RetCode, Length, *BytesWritten));
+ }
+ }
+#endif
+ return RetCode;
+}
+
+
+APIRET
+DosSetFileSize(
+ IN HFILE FileHandle,
+ IN ULONG NewFileSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine changes the size of a file.
+
+Arguments:
+
+ FileHandle - OS/2 file handle of file to change size of
+
+ NewFileSize - new size of file
+
+Return Value:
+
+ ERROR_INVALID_HANDLE - the file handle is not open
+
+--*/
+
+{
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ HANDLE NtHandle;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosSetFileSize";
+ #endif
+
+ //
+ // do a very stupid parameter check for compatibility.
+ //
+
+ if ((LONG)NewFileSize < 0)
+ return ERROR_INVALID_PARAMETER;
+
+ // OS/2 doesn't change file pointer for this call
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+
+ RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ if (hFileRecord->FileType &
+ (FILE_TYPE_DEV | FILE_TYPE_PIPE | FILE_TYPE_NMPIPE | FILE_TYPE_MAILSLOT)) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE;
+ }
+ NtHandle = hFileRecord->NtHandle;
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RetCode = UpdateFileSize(NtHandle,NewFileSize);
+ return RetCode;
+}
+
+
+APIRET
+FlushOneFile(
+ IN PFILE_HANDLE hFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine flushes the buffers for one file
+
+Arguments:
+
+ FileHandle - OS/2 file handle of file to flush buffers for
+
+Return Value:
+
+ ERROR_INVALID_ACCESS - ??
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatus;
+ NTSTATUS Status;
+
+ if (hFileRecord->Flags & (OPEN_ACCESS_WRITEONLY | OPEN_ACCESS_READWRITE)) {
+ Status = NtFlushBuffersFile(hFileRecord->NtHandle,
+ &IoStatus);
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_ACCESS));
+ }
+ }
+ return NO_ERROR;
+}
+
+
+APIRET
+DosResetBuffer(
+ IN HFILE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine flushes the buffers for one file or all of a process's files
+
+Arguments:
+
+ FileHandle - OS/2 file handle of file to flush buffers for
+
+Return Value:
+
+ ERROR_INVALID_HANDLE - the file handle is not open
+
+--*/
+
+{
+ ULONG i;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosResetBuffer";
+ #endif
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // 0xFFFF means Flush All handles
+ //
+ if (((USHORT) FileHandle) != 0xFFFF) {
+
+ //
+ // Check for invalid handle.
+ //
+
+ RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
+ if (RetCode) {
+ ;
+ }
+ else if (hFileRecord->FileType &
+ (FILE_TYPE_DEV | FILE_TYPE_MAILSLOT)) {
+ RetCode = ERROR_INVALID_HANDLE;
+ }
+ else {
+ RetCode = FlushOneFile(hFileRecord);
+ }
+ }
+ else {
+ RetCode = NO_ERROR;
+ for (i=0;i<HandleTableLength;i++) {
+ hFileRecord = DereferenceFileHandleNoCheck((HFILE) i);
+ if ((hFileRecord->Flags & FILE_HANDLE_VALID) &&
+ (!(hFileRecord->FileType &
+ (FILE_TYPE_DEV | FILE_TYPE_MAILSLOT)))) {
+ if (RetCode = FlushOneFile(hFileRecord)) {
+ break;
+ }
+ }
+ }
+ }
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+}
+
+
+APIRET
+DosSetFilePtr(
+ IN HFILE FileHandle,
+ IN LONG StartingFilePosition,
+ IN ULONG NewFilePosition,
+ IN OUT PULONG CurrentFilePosition
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the file pointer for a file
+
+Arguments:
+
+ FileHandle - OS/2 file handle of file to set file pointer for
+
+ StartingFilePosition - number of bytes to seek by
+
+ NewFilePosition - whether to seek from the beginning, current file
+ position, or end of the file.
+
+ CurrentFilePosition - where to store the new current file position
+
+Return Value:
+
+ ERROR_INVALID_HANDLE - the file handle is not open
+
+ ERROR_SEEK_ON_DEVICE - the handle is for a device or pipe
+
+ ERROR_INVALID_FUNCTION - the NewFilePosition parameter contains an
+ invalid value
+
+--*/
+
+{
+ FILE_POSITION_INFORMATION PositionInfo;
+ FILE_STANDARD_INFORMATION StandardInfo;
+ IO_STATUS_BLOCK IoStatus;
+ LONG NewPosition;
+ NTSTATUS Status;
+ HANDLE NtHandle;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosSetFilePtr";
+ #endif
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] *** entering DosSetFilePtr , handle is %d ***\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ FileHandle
+ ));
+ }
+#endif
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+
+ RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
+ if (RetCode != NO_ERROR) {
+ ;
+ }
+ else if (hFileRecord->FileType &
+ (FILE_TYPE_DEV | FILE_TYPE_PIPE | FILE_TYPE_NMPIPE | FILE_TYPE_MAILSLOT)) {
+ RetCode = ERROR_SEEK_ON_DEVICE;
+ }
+ else if (NewFilePosition > FILE_END) {
+ RetCode = ERROR_INVALID_FUNCTION;
+ }
+ if (RetCode != NO_ERROR) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+
+ //
+ // no serialization around the query/set calls is needed because
+ // if the app duped/inherited handles, so that there are multiple processes
+ // have handles to the same seek pointer, it can't depend on the order in
+ // which multiple I/O operations to that handle happen.
+ //
+
+ NtHandle = hFileRecord->NtHandle;
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (NewFilePosition == FILE_BEGIN) {
+ NewPosition = StartingFilePosition;
+ }
+ else if (NewFilePosition == FILE_CURRENT) {
+
+ //
+ // READ or WRITE access is required to get position information.
+ //
+
+ do {
+ Status = NtQueryInformationFile(NtHandle,
+ &IoStatus,
+ &PositionInfo,
+ sizeof (PositionInfo),
+ FilePositionInformation);
+ } while (RetryIO(Status, NtHandle));
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_ACCESS));
+ }
+ // BUGBUG - Therese, what do we do here if .HighPart is non-zero
+ NewPosition = PositionInfo.CurrentByteOffset.LowPart +
+ StartingFilePosition;
+ }
+ else if (NewFilePosition == FILE_END) {
+
+ //
+ // no access is required to get standard information.
+ //
+
+ do {
+ Status = NtQueryInformationFile(NtHandle,
+ &IoStatus,
+ &StandardInfo,
+ sizeof (StandardInfo),
+ FileStandardInformation
+ );
+ } while (RetryIO(Status, NtHandle));
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_ACCESS));
+ }
+ // BUGBUG - Therese, what do we do here if an overflow occurs or if
+ // the .HighPart is non-zero? The old code potentially had
+ // the overflow problem as well.
+ NewPosition = StandardInfo.EndOfFile.LowPart + StartingFilePosition;
+ }
+ else
+ ASSERT ( FALSE ); // we should never get here because we checked
+ // the NewPosition parameter above
+
+ if (NewPosition < 0) {
+ return ERROR_NEGATIVE_SEEK;
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] new position is %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ NewPosition));
+ }
+#endif
+ if (NewPosition == 0) {
+ PositionInfo.CurrentByteOffset.LowPart = 0;
+ PositionInfo.CurrentByteOffset.HighPart = 0;
+ }
+ else {
+ // BUGBUG - Therese, same .HighPart problem. Also, why the -1?
+ PositionInfo.CurrentByteOffset.LowPart = NewPosition;
+ PositionInfo.CurrentByteOffset.HighPart = 0;;
+// PositionInfo.CurrentBlock = BYTES_TO_BLOCKS(NewPosition) - 1;
+// PositionInfo.CurrentByte = BYTES_TO_OFFSET(NewPosition);
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] Current Byte Low = %ld Current Byte High = %ld\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ PositionInfo.CurrentByteOffset.LowPart,PositionInfo.CurrentByteOffset.HighPart));
+ }
+#endif
+ do {
+ Status = NtSetInformationFile(NtHandle,
+ &IoStatus,
+ &PositionInfo,
+ sizeof (PositionInfo),
+ FilePositionInformation);
+ } while (RetryIO(Status, NtHandle));
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_GEN_FAILURE));
+ }
+ try {
+ *CurrentFilePosition = NewPosition;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return NO_ERROR;
+}
+
+
+APIRET
+DosFileLocks(
+ IN HFILE FileHandle,
+ IN PFILELOCK UnlockRequest,
+ IN PFILELOCK LockRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine locks and/or unlocks a region of a file
+
+Arguments:
+
+ FileHandle - OS/2 file handle of file to lock/unlock region of
+
+ UnlockRequest - range to unlock in file
+
+ LockRequest - range to lock in file
+
+Return Value:
+
+ ERROR_INVALID_HANDLE - the file handle is not open
+
+ ERROR_LOCK_VIOLATION - lock conflicted with existing lock or unlock
+ specified non-locked region.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatus;
+ LARGE_INTEGER FileOffset;
+ LARGE_INTEGER FileLength;
+ NTSTATUS Status;
+ ULONG Key;
+ HANDLE NtHandle;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ LONG Range;
+ #if DBG
+ PSZ RoutineName = "DosFileLocks";
+ #endif
+
+ //
+ // The usage of Key: A combination of KEY == NULL and EXCLUSIVE == TRUE
+ // in NtLockFile() let us NtReadFile()/NtWriteFile() on that
+ // region with KEY == NULL from the same process but not from
+ // another process. A combination of KEY == pid and EXCLUSIVE == FALSE
+ // in NtLockFile() let us NtReadFile() with KEY == NULL from every
+ // process, and doesn't let us NtWriteFile() with KEY == NULL from any
+ // process, incuding the owner of the locked region.
+ //
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("[%d,%d] *** entering DosFileLocks ***\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ ));
+ }
+#endif
+ AcquireFileLockShared( // prevent file handle from going away
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+
+ RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ if (hFileRecord->FileType &
+ (FILE_TYPE_DEV | FILE_TYPE_PIPE | FILE_TYPE_NMPIPE | FILE_TYPE_MAILSLOT)) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE;
+ }
+
+ Key = (ULONG) Od2Process->Pib.ProcessId;
+ NtHandle = hFileRecord->NtHandle;
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (UnlockRequest != NULL) {
+ try {
+ FileOffset = RtlConvertLongToLargeInteger(UnlockRequest->lOffset);
+ Range = UnlockRequest->lRange;
+ FileLength = RtlConvertLongToLargeInteger(Range);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ if (Range == 0)
+ return ERROR_LOCK_VIOLATION;
+ Status = NtUnlockFile(NtHandle,
+ &IoStatus,
+ &FileOffset,
+ &FileLength,
+ (ULONG) NULL // try it once with key == NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+ Status = NtUnlockFile(NtHandle,
+ &IoStatus,
+ &FileOffset,
+ &FileLength,
+ Key // try it again with key == pid
+ );
+ }
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_LOCK_VIOLATION));
+ }
+ }
+
+ if (LockRequest != NULL) {
+ try {
+ FileOffset = RtlConvertLongToLargeInteger(LockRequest->lOffset);
+ Range = LockRequest->lRange;
+ FileLength = RtlConvertLongToLargeInteger(Range);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ if (Range == 0)
+ return ERROR_LOCK_VIOLATION;
+ Status = NtLockFile(NtHandle,
+ (HANDLE) NULL,
+ (PIO_APC_ROUTINE) NULL,
+ (PVOID) NULL,
+ &IoStatus,
+ &FileOffset,
+ &FileLength,
+ (ULONG)NULL,
+ (BOOLEAN)TRUE,
+ (BOOLEAN)TRUE
+ );
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_LOCK_VIOLATION));
+ }
+ }
+ return NO_ERROR;
+}
+
+
+APIRET
+DosSetFileLocks(
+ IN HFILE FileHandle,
+ IN PFILELOCK UnlockRequest,
+ IN PFILELOCK LockRequest
+ )
+{
+ return (DosFileLocks(FileHandle, UnlockRequest, LockRequest));
+}
+
+APIRET
+DummyApiRoutine(
+ IN PULONG OutData
+ );
+
+APIRET
+DummyApiRoutine(
+ IN PULONG OutData
+ )
+{
+ try {
+ *OutData = 0;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ return( NO_ERROR );
+}
+
+APIRET
+ComReadRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads from an OS/2 file handle.
+
+Arguments:
+
+ hFileRecord - pointer to OS/2 file handle record to read from
+
+ Buffer - buffer to read data into
+
+ Length - length of buffer
+
+ BytesRead - where to store number of bytes read
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ This routine releases the filelock.
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus, IoStatus2;
+ LARGE_INTEGER FileOffset;
+ HANDLE NtHandle;
+ HANDLE ComReadEvent;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "ComReadRoutine";
+ #endif
+
+ // BUGBUG need to check for alignment and probe validity
+
+ FileOffset = RtlConvertLongToLargeInteger(0);
+ NtHandle = hFileRecord->NtHandle;
+ ComReadEvent = hFileRecord->NtAsyncReadEvent;
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ IoStatus.Status = STATUS_PENDING;
+ IoStatus.Information = 0L;
+
+ Status = NtReadFile(NtHandle,
+ ComReadEvent,
+ (PIO_APC_ROUTINE) NULL,
+ (PVOID) NULL,
+ &IoStatus,
+ Buffer,
+ Length,
+ &FileOffset,
+ NULL
+ );
+ //
+ // If the operation was successful, return the total number of bytes
+ // read, otherwise, if the error was STATUS_END_OF_FILE, return success,
+ // but no bytes transferred, otherwise, return an appropriate error.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+ *BytesRead = IoStatus.Information;
+ return NO_ERROR;
+ } else if (Status == STATUS_END_OF_FILE) {
+ *BytesRead = 0;
+ return NO_ERROR;
+ } else if (Status == STATUS_PENDING) {
+ Status = Od2AlertableWaitForSingleObject(ComReadEvent);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("[%d,%d] OS2DLL: COM Read error: Status = %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+#endif
+ *BytesRead = IoStatus.Information;
+ return ERROR_ACCESS_DENIED;
+ }
+ else {
+ if (IoStatus.Status == STATUS_PENDING) {
+
+ Status = NtCancelIoFile(
+ NtHandle,
+ &IoStatus2
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("[%d,%d] OS2DLL: COM Cancel Read Io error: Status = %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+#endif
+ *BytesRead = IoStatus.Information;
+ return ERROR_ACCESS_DENIED;
+
+ } else {
+
+ do {
+
+ Status = Od2AlertableWaitForSingleObject(ComReadEvent);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("[%d,%d] OS2DLL: COM Read error (2): Status = %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status));
+#endif
+ *BytesRead = IoStatus.Information;
+ return ERROR_ACCESS_DENIED;
+ }
+
+ } while ( IoStatus.Status == STATUS_PENDING );
+ }
+ }
+
+ *BytesRead = IoStatus.Information;
+ return NO_ERROR;
+ }
+ }
+ else {
+ *BytesRead = 0;
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
+ }
+}
+
+APIRET
+ComWriteRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes to an OS/2 file handle.
+
+Arguments:
+
+ hFileRecord - pointer to OS/2 file handle record to write to
+
+ Buffer - buffer to write data to
+
+ Length - length of buffer
+
+ BytesWritten - where to store number of bytes written
+
+Return Value:
+
+ TBS
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ LARGE_INTEGER FileOffset;
+ HANDLE NtHandle;
+ HANDLE ComWriteEvent;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "ComWriteRoutine";
+ #endif
+
+
+ // BUGBUG need to check for alignment and probe validity
+
+ FileOffset = RtlConvertLongToLargeInteger(0);
+ NtHandle = hFileRecord->NtHandle;
+ ComWriteEvent = hFileRecord->NtAsyncWriteEvent;
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ Status = NtWriteFile(NtHandle,
+ ComWriteEvent,
+ (PIO_APC_ROUTINE) NULL,
+ (PVOID) NULL,
+ &IoStatus,
+ Buffer,
+ Length,
+ &FileOffset,
+ NULL
+ );
+ //
+ // If the write was successful, then return the correct number of bytes to
+ // the caller. If the error was STATUS_DISK_FULL, return 0 bytes written,
+ // but no error to the caller. Otherwise, figure out an appropriate error
+ // and return that error.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+ *BytesWritten = IoStatus.Information;
+ if (!NT_SUCCESS(IoStatus.Status)){
+#if DBG
+ KdPrint(("[%d,%d] ComWriteRoutine, Status SUCCESS, IoStatus %lx\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ IoStatus.Status));
+#endif
+ }
+ return NO_ERROR;
+ } else if (Status == STATUS_PENDING) {
+ Status = Od2AlertableWaitForSingleObject(ComWriteEvent);
+ if (!NT_SUCCESS(Status)) {
+ *BytesWritten = 0;
+ return ERROR_ACCESS_DENIED;
+ }
+ else {
+ *BytesWritten = IoStatus.Information;
+ return NO_ERROR;
+ }
+ } else {
+ *BytesWritten = 0;
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
+ }
+}
diff --git a/private/os2/client/dllimmon.c b/private/os2/client/dllimmon.c
new file mode 100644
index 000000000..b093d43a0
--- /dev/null
+++ b/private/os2/client/dllimmon.c
@@ -0,0 +1,312 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllimmon.c
+
+Abstract:
+
+ This module implements 32 equivalents of OS/2 V1.21
+ IMMON API Calls.
+ The APIs are called from 16->32 thunks (i386\doscalls.asm).
+
+Status :
+
+
+ IMMONINSTALL
+ IMMONDEINSTALL
+
+ IMMONSTATUS
+
+ IMMONACTIVE
+ IMMONINACTIVE
+
+Author:
+
+ Akihiko Sasaki (V-AkihiS) 14-December-1992
+
+Revision History:
+
+--*/
+
+#ifdef JAPAN
+
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "conrqust.h"
+#include "os2nls.h"
+
+extern PVOID Os2SessionCtrlDataBaseAddress;
+
+BOOL
+ServeImmonRequest(IN PNETREQUEST PReq,
+ OUT PVOID PStatus);
+
+
+
+APIRET
+SendImmonRequest(IN PSCREQUESTMSG Request)
+{
+ ULONG WinStatus;
+
+ ServeImmonRequest(&Request->d.Net, (PVOID)&WinStatus);
+
+ return((APIRET)WinStatus);
+}
+
+#if DBG
+#define EXCEPTION_IN_IMMON() \
+ { \
+ Od2ExitGP(); \
+ }
+
+#else
+#define EXCEPTION_IN_IMMON() \
+ Od2ExitGP();
+
+#endif
+
+#if DBG
+#define CHECK_RETURN_STATUS() \
+ if ( Status ) \
+ { \
+ KdPrint(("%s: status %lu\n", FuncName, Status)); \
+ return(Status); \
+ }
+#else
+#define CHECK_RETURN_STATUS() \
+ if ( Status ) \
+ { \
+ return(Status); \
+ }
+#endif
+
+
+APIRET
+IMMonInstall(IN PMONINSBLK InsBlk)
+{
+ SCREQUESTMSG Request;
+ APIRET Status;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "IMMonInstall";
+
+ {
+ KdPrint(("%s: entering\n",
+ FuncName));
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+ try
+ {
+ if (InsBlk->cb != sizeof(MONINSBLK))
+ {
+ return(ERROR_INVALID_PARAMETER);
+ }
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_IMMON()
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Immon.Request = IMMONActive;
+ Request.Request = ImmonRequest;
+ Status = SendImmonRequest(&Request);
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+IMMonDeinstall(IN ULONG ulReserved)
+{
+ SCREQUESTMSG Request;
+ APIRET Status;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "IMMonDeinstall";
+
+ {
+ KdPrint(("%s: entering with %lx\n",
+ FuncName, ulReserved));
+ }
+#endif
+
+ /*
+ * check parameter
+ */
+
+ if (ulReserved != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Immon.Request = IMMONInactive;
+ Request.Request = ImmonRequest;
+ Status = SendImmonRequest(&Request);
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+IMMonStatus(IN OUT PMONSTATBLK StatBlk)
+{
+ SCREQUESTMSG Request;
+ APIRET Status;
+ PCHAR pInfoBuf = (PCHAR)Os2SessionCtrlDataBaseAddress;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "IMMonStatus";
+
+ {
+ KdPrint(("%s: entering\n", FuncName));
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ if (StatBlk->cb != sizeof(MONSTATBLK))
+ {
+#if DBG
+ KdPrint(("StatBlk->cb = %d,size of struct = %d\n", StatBlk->cb, sizeof(MONSTATBLK)));
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+ Od2ProbeForWrite(FARPTRTOFLAT(StatBlk->pInfoBuf), StatBlk->cbInfoBuf, 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_IMMON()
+ }
+
+ if (Status = Od2LockCtrlRequestDataBuffer()) {
+ return(Status);
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ RtlMoveMemory(&Request.d.Immon.d.MonStatBlk, StatBlk, StatBlk->cb);
+ Request.d.Immon.d.MonStatBlk.pInfoBuf = pInfoBuf;
+ Request.d.Immon.Request = IMMONStatus;
+ Request.Request = ImmonRequest;
+
+ Status = SendImmonRequest(&Request);
+
+ RtlMoveMemory(FARPTRTOFLAT(StatBlk->pInfoBuf), pInfoBuf, StatBlk->cbInfoBuf);
+
+ //
+ // Dec.30.1992 I should do error check here, but I have no time to write it.
+ //
+
+ Od2UnlockCtrlRequestDataBuffer();
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+IMMonActive(IN ULONG ulReserved)
+{
+ SCREQUESTMSG Request;
+ APIRET Status;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "IMMonActive";
+
+ {
+ KdPrint(("%s: entering\n", FuncName));
+ }
+#endif
+
+ /*
+ * check parameter
+ */
+
+ if (ulReserved != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Immon.Request = IMMONActive;
+ Request.Request = ImmonRequest;
+ Status = SendImmonRequest(&Request);
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+IMMonInactive(IN ULONG ulReserved)
+{
+ SCREQUESTMSG Request;
+ APIRET Status;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "IMMonInactive";
+
+ {
+ KdPrint(("%s: entering\n", FuncName));
+ }
+#endif
+
+ /*
+ * check parameter
+ */
+
+ if (ulReserved != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Immon.Request = IMMONInactive;
+ Request.Request = ImmonRequest;
+ Status = SendImmonRequest(&Request);
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+#endif
diff --git a/private/os2/client/dllinit.c b/private/os2/client/dllinit.c
new file mode 100644
index 000000000..b45afadaa
--- /dev/null
+++ b/private/os2/client/dllinit.c
@@ -0,0 +1,1156 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllinit.c
+
+Abstract:
+
+ This module contains the initialization code for the OS/2 Subsystem
+ Client DLL.
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Environment:
+
+ User Mode only
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_ALL
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "conrqust.h"
+#include "os2nls.h"
+#include "os2win.h"
+
+/*
+ * Local prototypes
+ */
+
+NTSTATUS
+Od2SetGlobalInfoSel();
+
+VOID
+Od2FixupEnvironmentFromSM( VOID );
+
+VOID
+EntryFlat(VOID);
+
+VOID
+Od2DosExit(
+ ULONG ExitAction,
+ ULONG ExitResult,
+ ULONG ExitReason
+ );
+
+VOID
+Od2RaiseStackException( VOID );
+
+NTSTATUS Od2InitSem();
+
+ //
+ // GLobal Os2dll variables: see definition in ..\inc\os2dll.h
+ //
+ULONG Od2GlobalInfoSeg;
+ULONG Os2Debug;
+SYSTEM_BASIC_INFORMATION Od2NtSysInfo;
+PVOID Od2Heap;
+PVOID Od2TiledHeap;
+PVOID Od2Environment;
+ULONG Od2EnvCommandOffset;
+ULONG Od2BootDrive;
+ULONG Od2SystemDrive;
+HANDLE Od2PortHandle;
+PVOID Od2PortHeap;
+ULONG Od2PortMemoryRemoteDelta;
+POD2_PROCESS Od2Process;
+POD2_THREAD Od2Thread1;
+HANDLE Od2DeviceDirectory;
+PSZ Od2LibPath;
+USHORT Od2LibPathLength;
+POD2_MSGFILE Od2MsgFile;
+PUCHAR Od2SystemRoot;
+ULONG Od2Start16Stack;
+ULONG Od2Start16DS;
+OD2_SIG_HANDLER_REC SigHandlerRec;
+POD2_SIG_HANDLER_REC pSigHandlerRec = &SigHandlerRec;
+OD2_VEC_HANDLER_REC VecHandlerRec = {0,0,0,0,0,0,0};
+POD2_VEC_HANDLER_REC pVecHandlerRec = &VecHandlerRec;
+ULONG Od2ExecPgmErrorText;
+ULONG Od2ExecPgmErrorTextLength;
+char ErrorBuffer[50];
+ULONG Od2Saved16Stack;
+ULONG Od2SessionNumber;
+
+extern HANDLE Ow2hOs2srvPort;
+
+ //
+ // Program Name Info set in os2ses\os2.c
+ //
+extern char Od2PgmFullPathBuf[];
+extern PSZ Od2PgmFilePath;
+extern ULONG Od2PgmFullPathBufLength;
+
+extern PSZ Od2CommandLinePtr; // set by startprocess os2ses\ntinitss.c
+
+PPEB_OS2_DATA PebOs2Data;
+
+
+BOOLEAN
+Od2ProcessIsDetached(VOID)
+{
+ return(Od2Process->Pib.Type == PT_DETACHED);
+}
+
+VOID
+_Od2InfiniteSleep(VOID);
+
+//
+// Infinite alertable delay. Used in the thread that wait to be terminated.
+// SuspendThread can't be used due to design bug in NT: assincronious suspend
+// may be denggerous - the process lock in kernel might be owned by the thread.
+//
+
+VOID
+Od2InfiniteSleep(VOID)
+{
+ LARGE_INTEGER timeout;
+ NTSTATUS Status;
+
+ // TEB isn't restored and it can be invalid. Don't use it.
+ // Od2Process can be free already, don't use it too.
+
+ Status = NtTestAlert();
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("Od2InfiniteSleep, NtTestAlert Status=%x\n",
+ Status);
+ }
+#endif // DBG
+
+ timeout.LowPart = 0;
+ timeout.HighPart = 0x80000000; // Infinity
+
+ //
+ // The delay must be alertable to allow context change. If the context wasn't
+ // changed, continue to wait.
+ //
+
+ while (TRUE)
+ {
+ Status = NtDelayExecution(
+ TRUE, // alertable
+ &timeout);
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("Od2InfiniteSleep, NtDelayExecution Status=%x\n",
+ Status);
+ }
+#endif // DBG
+ }
+}
+
+BOOLEAN
+Od2InitCreateProcessMessage(
+ OUT PSCREQ_CREATE pCreate
+ )
+/*++
+
+Routine Description:
+
+ This function is the part of DLL initialization routines for the
+ OS/2 Emulation Subsystem Client DLL to be done before calling os2srv
+ to CreateProcess.
+
+Arguments:
+
+ pCreate- A message to os2srv to put parameter values in.
+
+Return Value:
+
+ False if initialization failed else return True.
+
+--*/
+{
+ NTSTATUS Status;
+ PPEB Peb;
+ ULONG RegionSize;
+
+ //
+ // Get the Peb address. Allocate the OS/2 subsystem specific portion
+ // within the Peb. This structure will be filled in by the server
+ // process as part of the connect logic.
+ //
+
+ Peb = NtCurrentPeb();
+ if (!Peb->SubSystemData)
+ {
+ Peb->SubSystemData = RtlAllocateHeap( Peb->ProcessHeap, 0,
+ sizeof( PEB_OS2_DATA )
+ );
+ if (!Peb->SubSystemData)
+ {
+#if DBG
+ KdPrint(("Od2InitCreateProcessMessage: out of memory, fail load\n"));
+#endif
+ ASSERT( FALSE );
+ return FALSE;
+ }
+ PebOs2Data = (PPEB_OS2_DATA)Peb->SubSystemData;
+ PebOs2Data->Length = sizeof( PEB_OS2_DATA );
+ } else
+ {
+ PebOs2Data = RtlAllocateHeap( Peb->ProcessHeap, 0,
+ sizeof( PEB_OS2_DATA )
+ );
+ if (!PebOs2Data)
+ {
+#if DBG
+ KdPrint(("Od2InitCreateProcessMessage: out of memory, fail load\n"));
+#endif
+ ASSERT( FALSE );
+ return FALSE;
+ }
+ PebOs2Data->Length = sizeof( PEB_OS2_DATA );
+ }
+
+ //
+ // Allocate space for the heap that will be used to contain the
+ // data structures maintained by the OS/2 Client DLL. The heap will
+ // grow dynamically.
+ // Also, create a heap for tiled objects (semaphores) the value for this
+ // HeapBase must be in the first 512 meg of the address space.
+ // The reason is that when this heap is used to create Semaphores we
+ // need to be able to do CRMA on them for 16-bit programs.
+ //
+ Od2Environment = (PVOID) OD2TILEDHEAP_BASE;
+ RegionSize = OD2TILEDHEAP_SIZE;
+ Status = NtAllocateVirtualMemory( NtCurrentProcess(),
+ (PVOID *)&Od2Environment,
+ 0,
+ &RegionSize,
+ MEM_RESERVE,
+ PAGE_READWRITE
+ );
+ if ( !NT_SUCCESS( Status ) )
+ {
+#if DBG
+ KdPrint(("Od2InitCreateProcessMessage: out of memory, fail load\n"));
+#endif
+ return( FALSE );
+ }
+ Od2TiledHeap = RtlCreateHeap( HEAP_GROWABLE,
+ Od2Environment,
+ OD2TILEDHEAP_SIZE,
+ 4 * 1024,
+ 0,
+ NULL
+ );
+
+ if (Od2TiledHeap == NULL)
+ {
+#if DBG
+ KdPrint(("Od2InitCreateProcessMessage: out of memory, fail load\n"));
+ ASSERT( FALSE );
+#endif
+ return( FALSE );
+ }
+
+ //
+ // Create a heap for the OS/2 client non-tiled objects.
+ //
+
+ Od2Heap = RtlCreateHeap( HEAP_GROWABLE,
+ NULL,
+ 64 * 1024, // Initial size of heap is 64K
+ 4 * 1024,
+ 0,
+ NULL
+ );
+ if (Od2Heap == NULL)
+ {
+#if DBG
+ KdPrint(("Od2InitCreateProcessMessage: out of memory, fail load\n"));
+ ASSERT( FALSE );
+#endif
+ return( FALSE );
+ }
+
+ //
+ // Initialize the Od2Process and Od2Thread1 variables
+ //
+
+ Status = Od2InitializeTask();
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(("Od2InitCreateProcessMessage: Error %lx at Od2InitializeTask, Fail Loading\n", Status));
+ ASSERT( FALSE );
+#endif
+ return( FALSE );
+ }
+
+//#if (sizeof(PEB_OS2_DATA) > (12*sizoef(ULONG)))
+//#err PEB_OS2_DATA is larger than place in SCREQ_CREATE, please update sesport.h
+//#endif
+
+ pCreate->d.In.SignalDeliverer = (PVOID)_Od2SignalDeliverer;
+ pCreate->d.In.ExitListDispatcher = (PVOID)_Od2ExitListDispatcher;
+ pCreate->d.In.InfiniteSleep = (PVOID)_Od2InfiniteSleep;
+ pCreate->d.In.FreezeThread = (PVOID)_Od2FreezeThread;
+ pCreate->d.In.UnfreezeThread = (PVOID)_Od2UnfreezeThread;
+ pCreate->d.In.VectorHandler = (PVOID) pVecHandlerRec;
+ pCreate->d.In.CritSectionAddr = (PVOID) EntryFlat;
+ pCreate->d.In.ClientPib = (PVOID)&Od2Process->Pib;
+ pCreate->d.In.ClientOs2Tib = (PVOID)&Od2Thread1->Os2Tib;
+ pCreate->d.In.InitialPebOs2Length = PebOs2Data->Length;
+
+ return( TRUE );
+}
+
+VOID
+Od2HandleCreateProcessRespond(
+ IN PSCREQ_CREATE pCreate
+ )
+/*++
+
+Routine Description:
+
+ This function is the part of DLL initialization routines for the
+ OS/2 Emulation Subsystem Client DLL to be done after calling os2srv
+ to CreateProcess (using the info returns from the server).
+
+Arguments:
+
+ pCreate- A message from os2srv to get parameter values from.
+
+
+--*/
+{
+ ULONG Priority;
+
+ //
+ // Save the priority set by the server...
+ //
+ Priority = Od2Thread1->Os2Tib.Priority;
+
+ RtlZeroMemory( &Od2Thread1->Os2Tib, sizeof( Od2Thread1->Os2Tib ) );
+ Od2Thread1->Os2Tib.ThreadId = pCreate->d.Out.Os2TibThreadId;
+ Od2Thread1->Os2Tib.Priority = Priority;
+ Od2Thread1->Os2Tib.Version = pCreate->d.Out.Os2TibVersion;
+
+ RtlZeroMemory( &Od2Process->Pib, sizeof( Od2Process->Pib ) );
+ Od2Process->Pib.ProcessId = (PID)pCreate->d.Out.PibProcessId;
+ Od2Process->Pib.ParentProcessId = (PID)pCreate->d.Out.PibParentProcessId;
+ Od2Process->Pib.ImageFileHandle = (HMODULE)pCreate->d.Out.PibImageFileHandle;
+ Od2Process->Pib.Status = pCreate->d.Out.PibStatus;
+ Od2Process->Pib.Type = pCreate->d.Out.PibType;
+
+ RtlMoveMemory( PebOs2Data,
+ &pCreate->d.Out.InitialPebOs2Data[0],
+ PebOs2Data->Length
+ );
+
+ Od2BootDrive = pCreate->d.Out.BootDrive;
+ Od2SystemDrive = pCreate->d.Out.SystemDrive;
+ Od2DeviceDirectory = pCreate->d.Out.DeviceDirectory;
+ CtrlPortHandle = pCreate->d.Out.CtrlPortHandle;
+ Od2SessionNumber = pCreate->d.Out.SessionNumber;
+
+ Od2GlobalInfoSeg = (ULONG)pCreate->d.Out.GInfoAddr;
+}
+
+
+BOOLEAN
+Od2DllInitialize(
+ IN PVOID DllHandle,
+ IN ULONG Reason,
+ IN PCONTEXT Context OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This function is the DLL initialization routine for the OS/2 Emulation
+ Subsystem Client DLL. This function gets control when the applications
+ links to this DLL are snapped.
+
+Arguments:
+
+ Context - Supplies an optional context buffer that will be restored
+ after all DLL initialization has been completed. If this
+ parameter is NULL then this is a dynamic snap of this module.
+ Otherwise this is a static snap prior to the user process
+ gaining control.
+
+Return Value:
+
+ False if initialization failed else return True.
+
+History:
+ Nov-5-1992 - Yaron Shamir - os2dll.dll vanishes. Ths code become part of os2.exe.
+ This routine is called directly from os2ses\os2.c
+--*/
+
+{
+ NTSTATUS Status;
+ PCHAR CommandLine;
+ PCH src, dst, s;
+ APIRET RetCode;
+ SECURITY_QUALITY_OF_SERVICE DynamicQos;
+ BOOLEAN RootProcessInSession;
+ ULONG RegionSize;
+ PSZ Win32CurDirs;
+ ULONG Win32CurDirsIndex;
+
+ Status = STATUS_SUCCESS;
+
+// DbgBreakPoint();
+
+ if ( Reason == DLL_PROCESS_ATTACH ) {
+
+ //
+ // Setup error buffer for 16-bit loading errors
+ //
+ Od2ExecPgmErrorText = (ULONG) &ErrorBuffer;
+ Od2ExecPgmErrorTextLength = 0;
+
+ //
+ // Set up the security quality of service parameters to use over the
+ // port. Use the most efficient (least overhead) - which is dynamic
+ // rather than static tracking.
+ //
+
+ DynamicQos.ImpersonationLevel = SecurityImpersonation;
+ DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
+ DynamicQos.EffectiveOnly = TRUE;
+
+
+ //
+ // Remember our DLL handle in a global variable.
+ //
+ // Od2DllHandle = (HMODULE)DllHandle;
+
+ //
+ // Save away system information in a global variable
+ //
+
+ Status = NtQuerySystemInformation( SystemBasicInformation,
+ &Od2NtSysInfo,
+ sizeof( Od2NtSysInfo ),
+ NULL
+ );
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("Od2DllInitialize: Error %lx at NtQuerySystemInformation,Fail Loading\n",
+ Status));
+#endif
+ ASSERT( FALSE );
+ return( FALSE );
+ }
+
+ //
+ // Allocate the OS/2 Environment block and fill it in with the strings
+ // ser get from win32. The format of the OS/2 Environment block is:
+ //
+ // <Environment Strings>
+ // '\0'
+ // <Full Path Name of Image File>
+ // '\0'
+ // <Command String>
+ // <Argument Strings>
+ // '\0'
+ //
+ // where <Environment Strings> contains zero or more null terminated
+ // strings of the format NAME=value
+ //
+ // <Full Path Name of Image File> is a null terminated string
+ // that specifies the full path of the image file that was loaded
+ // into this process.
+ //
+ // <Command String> is a null terminated string that represents
+ // first token on the command line. Typically, the full path of
+ // the image file was derived from this string by defaulting the
+ // extenstion and search the PATH environment variable for the
+ // image file.
+ //
+ // <Argument Strings> contains zero or more null terminated
+ // strings that represent the arguments to the program. By
+ // convention, the OS/2 Command Processor (CMD.EXE) passes a
+ // single argument string that is everything after the command
+ // name.
+ //
+ // '\0' are explicit, extra, null characters used to separate the
+ // sections of the environment block. They are in addition to the
+ // null characters used to terminate the strings in each section.
+ //
+
+ Od2Environment = (PVOID) OD2ENVIRONMENT_BASE;
+
+ //
+ // get the environment variables from win32, and copy/edit them
+ // in the tiled segment starting at OD2ENVIRONMENT_BASE
+ //
+
+ Win32CurDirs = s = (PSZ)GetEnvironmentStrings();
+ dst = Od2Environment;
+
+ //
+ // 1st measure the size of commitment needed, and commit it
+ //
+
+ //
+ // watch for the current directories (appear in environment
+ // in the form "=C:=C:\foo"
+ //
+
+ Win32CurDirsIndex = (ULONG)-1;
+ while (*s) {
+ if (*s == '=') {
+ Win32CurDirsIndex = s - Win32CurDirs;
+ break;
+ }
+ s++;
+ while (*s++) {
+ }
+ }
+
+ if (Win32CurDirsIndex != (ULONG)-1) {
+ src = NULL;
+ while (*s) {
+ if (src == NULL && *s != '='){
+ src = s;
+ }
+ s++;
+ while (*s++) {
+ }
+ }
+ if (src == NULL) {
+ src = s;
+ }
+
+ } else {
+ Win32CurDirsIndex = 0;
+ src = Win32CurDirs;
+ }
+
+ //
+ // reserve 64K for environment (one tiled segment)
+ //
+ RegionSize = _64K;
+ Status = NtAllocateVirtualMemory( NtCurrentProcess(),
+ (PVOID *)&Od2Environment,
+ 0,
+ &RegionSize,
+ MEM_RESERVE,
+ PAGE_READWRITE
+ );
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ KdPrint(("Od2DllInitialize: out of memory, fail load\n"));
+#endif
+ return( FALSE );
+ }
+ //
+ // commit enough memory to hold initial environment
+ //
+ RegionSize = (s - src) + Win32CurDirsIndex + CCHMAXPATH * 2; // 500 extra for additions
+ Status = NtAllocateVirtualMemory( NtCurrentProcess(),
+ (PVOID *)&Od2Environment,
+ 0,
+ &RegionSize,
+ MEM_COMMIT,
+ PAGE_READWRITE
+ );
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ KdPrint(("Od2DllInitialize: out of memory, fail load\n"));
+#endif
+ return( FALSE );
+ }
+
+
+ if (Win32CurDirsIndex != 0) {
+ RtlMoveMemory(dst, Win32CurDirs, Win32CurDirsIndex);
+ dst += Win32CurDirsIndex;
+ }
+
+ if ((src - s) != 0) {
+ RtlMoveMemory(dst, src, (s - src));
+ dst += (s - src);
+ }
+
+ *dst++ = 0; // terminate the environment block
+
+ //
+ // Copy the image file name if one was given.
+ //
+ strncpy( dst, Od2PgmFullPathBuf, Od2PgmFullPathBufLength);
+ dst+= Od2PgmFullPathBufLength;
+ *dst++ = '\0'; // null to terminate image file name
+
+ //
+ // Copy the command line argument strings.
+ //
+
+ CommandLine = dst;
+ strcpy(CommandLine, Od2CommandLinePtr);
+ //
+ // put 2 NULLs at the end of the command line
+ //
+ dst += strlen(CommandLine) + 1;
+ *dst = '\0';
+ //
+ // null to terminate first token of command line.
+ //
+ dst = CommandLine;
+#ifdef DBCS
+// MSKK Apr.12.1993 V-AkihiS
+// Support charaters which code are greater than 0x80
+// (i.e. DBCS).
+ while ((UCHAR)*dst > ' ') {
+#else
+ while (*dst > ' ') {
+#endif
+ dst++;
+ }
+ *dst = '\0';
+
+ Od2PortHandle = Ow2hOs2srvPort;
+
+ strncpy( Od2Process->ApplName,
+ Od2PgmFilePath,
+ OS2_MAX_APPL_NAME);
+
+ Od2LibPath = RtlAllocateHeap( Od2Heap, 0, CCHMAXPATH);
+ if (!Od2LibPath)
+ {
+#if DBG
+ KdPrint(("OS2: Od2DllInitialize: out of heap memory, fail load\n"));
+#endif
+ ASSERT( FALSE );
+ return FALSE;
+ }
+ Od2LibPathLength = (USHORT)
+ GetEnvironmentVariableA("Os2LibPath", Od2LibPath, CCHMAXPATH);
+
+ //
+ // Find if new session
+ //
+
+ Status = Od2InitializeSessionPort(&RootProcessInSession);
+ if (!NT_SUCCESS( Status )){
+#if DBG
+ KdPrint(( "OS2: Unable to connect to OS2 Subsystem - Status == %X\n",
+ Status));
+#endif
+ return( FALSE );
+ }
+
+ //
+ // Initialize the NLS support
+ //
+
+ RetCode = Od2InitNls(PebOs2Data->CodePage,
+ RootProcessInSession);
+ if (RetCode){
+#if DBG
+ KdPrint(("OS2: Od2DllInitialize: RetCode %d at Od2InitNIs, Fail Loading\n",
+ RetCode));
+#endif
+ return( FALSE );
+ }
+
+ //
+ // Initialize the file system
+ //
+
+ if (PebOs2Data->StartedBySm) {
+ RetCode = Od2InitializeFileSystemForSM(
+ PebOs2Data->InitialDefaultDrive,
+ PebOs2Data->StdIn,
+ PebOs2Data->StdOut,
+ PebOs2Data->StdErr
+ );
+ } else if (RootProcessInSession) {
+ RetCode = Od2InitializeFileSystemForChildSM(
+ PebOs2Data->SizeOfInheritedHandleTable,
+ PebOs2Data->InitialDefaultDrive
+ );
+ }
+ else {
+ RetCode = Od2InitializeFileSystemForExec(
+ PebOs2Data->SizeOfInheritedHandleTable,
+ PebOs2Data->InitialDefaultDrive
+ );
+ }
+
+ Od2Process->ErrorAction =
+ OD2_ENABLE_ACCESS_VIO_POPUP | OD2_ENABLE_HARD_ERROR_POPUP;
+
+ if (RetCode) {
+#if DBG
+ KdPrint(("OS2: Od2DllInitialize: RetCode %d at Od2InitializeFileSystem, Fail Loading\n",
+ RetCode));
+#endif
+ return( FALSE );
+ }
+
+ Od2InitializeThread( Od2Thread1 ); // Status always SUCCESS
+
+ //
+ // Store the address of the environment block and imbedded command line
+ // in the OS/2 Process Information Block (PIB)
+ //
+
+ Od2Process->Pib.Environment = Od2Environment;
+ Od2Process->Pib.CommandLine = CommandLine;
+
+ //
+ // FIX, FIX - The following variables need to be inherited via the
+ // pConnectionInformation->InitialPebOs2Data structure
+ //
+
+ Od2Process->VerifyFlag = TRUE;
+ Od2Process->MaximumFileHandles = 20;
+
+
+ Status = Od2InitSem();
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(("Od2InitDllInitialize: Error %lx at Od2InitSem, Fail Loading\n", Status));
+ ASSERT( FALSE );
+#endif
+ return( FALSE );
+ }
+ //
+ // Initialize the Timers component.
+ //
+
+ Status = Od2InitializeTimers();
+ if (!NT_SUCCESS( Status )){
+#if DBG
+ ASSERT( FALSE );
+ KdPrint(("Od2DllInitialize: Error %lx at Od2InitializeTimers, Fail Loading\n",
+ Status));
+#endif
+ return( FALSE );
+ }
+
+ //
+ // Initialize the Netbios component.
+ //
+
+ Od2NetbiosInitialize();
+
+ //
+ // Initialize the Disk IoCtl component.
+ //
+
+ Od2DiskIOInitialize();
+
+ //
+ // Initialize the system message file.
+ //
+
+ Status = Od2InitializeMessageFile();
+ if (!NT_SUCCESS( Status )){
+#if DBG
+ ASSERT( FALSE );
+ KdPrint(("Od2DllInitialize: Error %lx at Od2InitializeMessageFile, Fail Loading\n",
+ Status));
+#endif
+ return( FALSE );
+ }
+
+ Od2FixupEnvironmentFromSM();
+ //
+ // FIX, FIX - when we get DLLs, then DLL Initialization procedures
+ // need to get called at this point.
+ //
+
+ if (ARGUMENT_PRESENT( Context )) {
+ PebOs2Data->ClientStartAddress = (PVOID)CONTEXT_TO_PROGRAM_COUNTER(Context);
+ CONTEXT_TO_PROGRAM_COUNTER(Context) = (PVOID)Od2ProcessStartup;
+ }
+
+ if (!NT_SUCCESS(Od2SetGlobalInfoSel())){
+#if DBG
+ KdPrint(("DosGetInfoSeg: failed\n"));
+#endif
+ return(FALSE);
+ }
+ }
+ if (!NT_SUCCESS( Status ))
+ return( FALSE );
+ else
+ return( TRUE );
+}
+
+
+VOID
+Od2FixupEnvironmentFromSM( VOID )
+{
+ UCHAR c;
+ PCHAR src, dst;
+ BOOLEAN InKeyword;
+
+ src = Od2Process->Pib.Environment;
+ dst = src;
+
+ while (*src) {
+ InKeyword = TRUE;
+ while (c = *src) {
+ if (!InKeyword) {
+ if (c == '\\') {
+ if (!_strnicmp( src, "\\BootDevice", 11 )) {
+ *dst++ = (CHAR) ('A' + Od2BootDrive);
+ *dst++ = ':';
+ src += 11;
+ if (*src != '\\') {
+ *dst++ = '\\';
+ }
+ continue;
+ }
+ else
+ if (!_strnicmp( src, "\\SystemDisk", 11 )) {
+ *dst++ = (CHAR) ('A' + Od2SystemDrive);
+ *dst++ = ':';
+ src += 11;
+ if (*src != '\\') {
+ *dst++ = '\\';
+ }
+ continue;
+ }
+ }
+ }
+ else
+ if (c == '=') {
+ InKeyword = FALSE;
+ }
+ else
+ if (c >= 'a' && c <= 'z') {
+ c = c - (UCHAR)'a' + (UCHAR)'A';
+ }
+
+#ifdef DBCS
+// MSKK Mar.24.1993 V-AkihiS
+ if (Ow2NlsIsDBCSLeadByte(c, SesGrp->DosCP)) {
+ *dst++ = c;
+ src++;
+ if (*src) {
+ *dst++ = *src++;
+ }
+ }
+ else {
+ *dst++ = c;
+ src++;
+ }
+#else
+ *dst++ = c;
+ src++;
+#endif
+ }
+
+ *dst++ = c;
+ src++;
+ }
+ *dst++ = '\0';
+ src++;
+
+ while (c = *src) {
+ if (c == '\\') {
+ if (!_strnicmp( src, "\\BootDevice", 11 )) {
+ *dst++ = (CHAR) ('A' + Od2BootDrive);
+ *dst++ = ':';
+ src += 11;
+ if (*src != '\\') {
+ *dst++ = '\\';
+ }
+ }
+ else
+ if (!_strnicmp( src, "\\SystemDisk", 11 )) {
+ *dst++ = (CHAR) ('A' + Od2SystemDrive);
+ *dst++ = ':';
+ src += 11;
+ if (*src != '\\') {
+ *dst++ = '\\';
+ }
+ }
+ else {
+#ifdef DBCS
+// MSKK Mar.24.1993 V-AkihiS
+ if (Ow2NlsIsDBCSLeadByte(c, SesGrp->DosCP)) {
+ *dst++ = c;
+ src++;
+ if (*src) {
+ *dst++ = *src++;
+ }
+ }
+ else {
+ *dst++ = c;
+ src++;
+ }
+#else
+ *dst++ = c;
+ src++;
+#endif
+ }
+ }
+ else {
+#ifdef DBCS
+// MSKK Mar.24.1993 V-AkihiS
+ if (Ow2NlsIsDBCSLeadByte(c, SesGrp->DosCP)) {
+ *dst++ = c;
+ src++;
+ if (*src) {
+ *dst++ = *src++;
+ }
+ }
+ else {
+ *dst++ = c;
+ src++;
+ }
+#else
+ *dst++ = c;
+ src++;
+#endif
+ }
+ }
+ *dst++ = c;
+
+ src = Od2Process->Pib.CommandLine;
+ Od2Process->Pib.CommandLine = dst;
+
+ while (*src) {
+ while (c = *src) {
+ if (c == '\\') {
+ if (!_strnicmp( src, "\\BootDevice", 11 )) {
+ *dst++ = (CHAR) ('A' + Od2BootDrive);
+ *dst++ = ':';
+ src += 11;
+ if (*src != '\\') {
+ *dst++ = '\\';
+ }
+ }
+ else
+ if (!_strnicmp( src, "\\SystemDisk", 11 )) {
+ *dst++ = (CHAR) ('A' + Od2SystemDrive);
+ *dst++ = ':';
+ src += 11;
+ if (*src != '\\') {
+ *dst++ = '\\';
+ }
+ }
+ else {
+#ifdef DBCS
+// MSKK Mar.24.1993 V-AkihiS
+ if (Ow2NlsIsDBCSLeadByte(c, SesGrp->DosCP)) {
+ *dst++ = c;
+ src++;
+ if (*src) {
+ *dst++ = *src++;
+ }
+ }
+ else {
+ *dst++ = c;
+ src++;
+ }
+#else
+ *dst++ = c;
+ src++;
+#endif
+ }
+ }
+ else {
+#ifdef DBCS
+// MSKK Mar.24.1993 V-AkihiS
+ if (Ow2NlsIsDBCSLeadByte(c, SesGrp->DosCP)) {
+ *dst++ = c;
+ src++;
+ if (*src) {
+ *dst++ = *src++;
+ }
+ }
+ else {
+ *dst++ = c;
+ src++;
+ }
+#else
+ *dst++ = c;
+ src++;
+#endif
+ }
+ }
+
+ *dst++ = c;
+ src++;
+ }
+ *dst++ = '\0';
+}
+
+
+/**** Currently this routine is not in use - don't remove for now (11-5-92 YaronS)
+ULONG
+Od2ProcessException(
+ IN PEXCEPTION_POINTERS ExceptionInfo,
+ OUT PEXCEPTION_RECORD ExceptionRecord
+ )
+{
+ PTEB ThreadInfo;
+ NTSTATUS Status, ExceptionCode;
+ ULONG RegionSize;
+ ULONG CurrentStackLimit;
+ ULONG GuardPageLimit;
+
+#if DBG
+ IF_OD2_DEBUG( EXCEPTIONS ) {
+ KdPrint(("entering Od2ProcessException\n"));
+ }
+#endif
+ ExceptionCode = ExceptionInfo->ExceptionRecord->ExceptionCode;
+
+ // copy exception record to caller's buffer
+
+ RtlMoveMemory(ExceptionRecord,ExceptionInfo->ExceptionRecord,sizeof(EXCEPTION_RECORD));
+ if ((XCPT_FATAL_EXCEPTION & ExceptionCode) == XCPT_FATAL_EXCEPTION) {
+
+ //
+ // if this is a PTERM, the thread has already been notified of its
+ // impending death, so kill it.
+ // otherwise, call DosExit for the thread.
+ //
+
+ if (ExceptionCode != XCPT_PROCESS_TERMINATE &&
+ ExceptionCode != XCPT_ASYNC_PROCESS_TERMINATE) {
+
+ //
+ // if this was a signal, acknowledge it.
+ //
+
+ if (ExceptionCode == XCPT_SIGNAL) {
+ ULONG Signal;
+ Signal = ExceptionRecord->ExceptionInformation[0];
+ Od2AcknowledgeSignalException(Signal);
+ }
+// Od2DosExit(EXIT_PROCESS,
+// ERROR_PROTECTION_VIOLATION, // FIX, FIX - decode status
+// TC_TRAP);
+// ASSERT (FALSE); // we should never get here
+ }
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+ else {
+ if (ExceptionCode == XCPT_GUARD_PAGE_VIOLATION) {
+ ThreadInfo = NtCurrentTeb();
+
+ //
+ // make sure that exception address is within stack range.
+ // if it isn't, we continue execution. this is because we're
+ // the last possible handler and this is not a fatal exception.
+ //
+
+ CurrentStackLimit = (ULONG) ThreadInfo->NtTib.StackLimit;
+ if ((ExceptionInfo->ExceptionRecord->ExceptionInformation[1] >=
+ (ULONG)ThreadInfo->NtTib.StackBase) ||
+ (ExceptionInfo->ExceptionRecord->ExceptionInformation[1] <
+ CurrentStackLimit)) {
+ return (ULONG)EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ GuardPageLimit = ROUND_DOWN_TO_PAGES(ExceptionInfo->ExceptionRecord->ExceptionInformation[1]) - Od2NtSysInfo.PageSize;
+
+ //
+ // verify that we haven't exceeded our stack
+ //
+
+ if (CurrentStackLimit > GuardPageLimit) {
+ Od2RaiseStackException();
+ return (ULONG)EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ //
+ // commit new guard page
+ //
+
+ RegionSize = Od2NtSysInfo.PageSize;
+ Status = NtAllocateVirtualMemory(NtCurrentProcess(),
+ (PVOID *) &GuardPageLimit,
+ 0,
+ &RegionSize,
+ MEM_COMMIT,
+ PAGE_READWRITE | PAGE_GUARD);
+ if (Status != STATUS_SUCCESS) {
+ Od2RaiseStackException();
+ }
+ }
+ return (ULONG)EXCEPTION_CONTINUE_EXECUTION;
+ }
+}
+********/
+
+
+VOID
+Od2ExceptionHandler(
+ IN PEXCEPTION_RECORD ExceptionRecord
+ )
+
+{
+ NTSTATUS ExceptionCode;
+ OS2_API_MSG m;
+ POS2_TERMINATETHREAD_MSG a = &m.u.TerminateThread;
+
+ ExceptionCode = ExceptionRecord->ExceptionCode;
+
+ if (ExceptionCode == XCPT_PROCESS_TERMINATE ||
+ ExceptionCode == XCPT_ASYNC_PROCESS_TERMINATE) {
+
+ //
+ // Remove high bit to indicate loader error
+ //
+ a->ExitResult = ~0x80000000 & Od2Process->ResultCodes.ExitResult;
+ Od2CallSubsystem( &m, NULL, Oi2TerminateThread, 0 );
+ }
+ else {
+// ASSERT (FALSE);
+ }
+}
+
+
+VOID
+Od2ProcessStartup(
+ IN PPEB Peb
+ )
+{
+ PULONG BadPointer = (PULONG)1;
+ PFNPROCESS StartAddress;
+
+ // Call 32 bit Entry Point. If it returns, then
+ // exit the process with the return value as the exit code.
+ //
+
+ StartAddress = (PFNPROCESS)(PebOs2Data->ClientStartAddress);
+
+// try {
+ DosExit( EXIT_PROCESS, (*StartAddress)( Peb ));
+
+ //
+ // If DosExit fails, then force an exception.
+ //
+
+ *BadPointer = 0;
+// }
+// except( Od2ProcessException(GetExceptionInformation(),&ExceptionRecord) ) {
+// Od2ExceptionHandler(&ExceptionRecord);
+// }
+}
+
diff --git a/private/os2/client/dllioctl.c b/private/os2/client/dllioctl.c
new file mode 100644
index 000000000..a686c8301
--- /dev/null
+++ b/private/os2/client/dllioctl.c
@@ -0,0 +1,3792 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllioctl.c
+
+Abstract:
+
+ This module implements 32 equivalents of OS/2 V1.21 File System
+ API Calls that are not trivially mapped to Cruiser APIs. These
+ are called from 16->32 thunks (i386\doscalls.asm).
+
+
+Author:
+
+ Yaron Shamir (YaronS) 30-May-1991
+
+Revision History:
+
+ Patrick Questembert (patrickq) 2-Feb-1992:
+ Added Dos16QFSAttach
+ Patrick Questembert (patrickq) 10-Feb-1992:
+ Added Dos16MkDir2
+ Beni Lavi (benil) 3-May-92
+ This file was split from dllfs16.c
+
+--*/
+
+#define NTOS2_ONLY
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FSD
+#define INCL_OS2V20_ERRORMSG
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "sesport.h"
+#include "conrqust.h"
+#include <ntdddisk.h>
+#include "os2flopy.h"
+
+#include "ntddser.h"
+#include "ntddpar.h"
+#if PMNT
+#define INCL_32BIT
+#include "pmnt.h"
+#endif
+
+NTSTATUS
+Od2AlertableWaitForSingleObject(
+ IN HANDLE handle
+ );
+
+#ifdef JAPAN
+// MSKK May.07.1993 V-AkihiS
+extern USHORT KbdType, KbdSubType;
+extern BYTE OemId, OemSubType;
+
+#define Od2IsIBM02_Keyboard(KbdType, OEMId, OEMSubType) \
+ (KbdType == 7 && OEMId == 0 && OEMSubType == 3)
+#endif
+
+union _IO {
+ SERIAL_BAUD_RATE SerialBaudRate;
+ SERIAL_LINE_CONTROL SerialLineControl;
+ UCHAR SerialImmediateChar;
+ SERIAL_STATUS SerialStatus;
+ SERIAL_TIMEOUTS SerialTimeouts;
+ SERIAL_HANDFLOW SerialHandflow;
+ ULONG SerialWaitMask;
+ SERIAL_CHARS SerialChars;
+ SERIAL_QUEUE_SIZE SerialQueueSize;
+ ULONG SerialDTRRTS;
+ PAR_QUERY_INFORMATION ParQueryInformation;
+ PAR_SET_INFORMATION ParSetInformation;
+} IO;
+
+static BYTE ParCharPerLine;
+static BYTE ParLinesPerInch;
+static BYTE ParInfiniteRetry;
+
+#if PMNT
+extern APIRET MouSetPtrPosPM(PPTRLOC p);
+extern APIRET MouGetPtrPosPM(PPTRLOC p);
+#endif
+
+USHORT
+MapSerialCommErr(ULONG SerErr)
+{
+ USHORT MappedSerErr = 0;
+
+ if (SerErr & SERIAL_ERROR_FRAMING) {
+ MappedSerErr |= FRAMING_ERROR;
+ }
+ if (SerErr & SERIAL_ERROR_OVERRUN) {
+ MappedSerErr |= RX_HARDWARE_OVERRUN;
+ }
+ if (SerErr & SERIAL_ERROR_QUEUEOVERRUN) {
+ MappedSerErr |= RX_QUE_OVERRUN;
+ }
+ if (SerErr & SERIAL_ERROR_PARITY) {
+ MappedSerErr |= PARITY_ERROR;
+ }
+ return(MappedSerErr);
+}
+
+BOOLEAN
+ErrorAtWaitForAsyncComIOCtl(
+ NTSTATUS Status,
+ HANDLE ComEvent,
+ APIRET *RetCode
+ )
+{
+ if (Status == STATUS_SUCCESS) {
+ return (FALSE);
+ } else if (Status == STATUS_PENDING) {
+ Status = Od2AlertableWaitForSingleObject(ComEvent);
+ if (!NT_SUCCESS(Status)) {
+ *RetCode = ERROR_PROTECTION_VIOLATION;
+ return(TRUE);
+ }
+ } else {
+ *RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_PROTECTION_VIOLATION);
+#if DBG
+ KdPrint(("OS2DLL: ErrorAtWaitForAsyncComIOCtl - Status = %x\n", Status));
+#endif
+ return (TRUE);
+ }
+}
+
+#if DBG
+UCHAR DosDevIOCtl2NotValidStr[] = "DosDevIOCtl2: Category %d, Function 0x%x Not Valid\n";
+UCHAR DosDevIOCtlNotValidStr[] = "DosDevIOCtl: Category %d, Function 0x%x Not Valid\n";
+UCHAR DosDevIOCtl2NotImplementedYetStr[] = "DosDevIOCtl2: Category %d, Function 0x%x Not Implemented Yet\n";
+UCHAR DosDevIOCtlNotImplementedYetStr[] = "DosDevIOCtl: Category %d, Function 0x%x Not Implemented Yet\n";
+#endif
+
+APIRET
+DosDevIOCtl2(
+ PVOID pvData,
+ ULONG cbData,
+ PVOID pvParmList,
+ ULONG cbParmList,
+ ULONG Function,
+ ULONG Category,
+ HFILE hDev
+ )
+{
+ NTSTATUS Status = 0;
+ APIRET RetCode;
+ ULONG IoControlCode;
+ ULONG IoCtlParamLength;
+ PCHAR IoOutputBuffer;
+ ULONG IoOutputBufferLength;
+ HANDLE NtHandle;
+ IO_STATUS_BLOCK IoStatus;
+ PVOID Io = (PVOID)&IO;
+ PLINECONTROL pLineCtrl;
+ PDCBINFO pDCBInfo;
+ PRXQUEUE pRXQueue;
+ PFRAME pFrame;
+ PFONTINFO pFontInfo;
+ BYTE ParInfo;
+ UCHAR MaskOn, MaskOff;
+ int SetOnlyFunction = FALSE;
+ int ComSetOnlyFunction = FALSE;
+ IO_VECTOR_TYPE IoVectorType;
+ USHORT NumChar;
+ PKBDKEYINFO pKbdInfo;
+ ULONG WaitFlag, Handle;
+ BYTE Byte;
+ ULONG ModemStatus;
+ BYTE LineStatus;
+ FILE_FS_DEVICE_INFORMATION FsDeviceInfoBuffer;
+ ULONG TmpReadTimeout;
+ HANDLE ComIOCtlEvent;
+ HANDLE ComReadEvent;
+ PFILE_HANDLE hFileRecord;
+
+ ULONG DriveNumber;
+ PULONG pDriveNumberPermanentStorageLocation;
+ PBIOSPARAMETERBLOCK pBPB;
+ ULONG BpbRequestType;
+ ULONG DiskCommand;
+ BIOSPARAMETERBLOCK PrivateBpb;
+ MEDIA_TYPE PrivateMediaType;
+ DISK_GEOMETRY PrivateTrueGeometry;
+ PTRACKLAYOUT TrackLayout;
+ ULONG CountSectors;
+ PTRACKFORMAT TrackFormat;
+ BYTE FormatSectorSizeType;
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosDevIOCtl2 (Called directly or redirected from DosDevIOCtl)";
+ #endif
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DosDevIOCtl2: Category: %ld, Function: %lx\n", Category, Function));
+ }
+#endif
+
+ //
+ // Check for invalid handle.
+ //
+
+ RetCode = DereferenceFileHandle(hDev, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ NtHandle = hFileRecord->NtHandle;
+ IoVectorType = hFileRecord->IoVectorType;
+ ComIOCtlEvent = hFileRecord->NtAsyncIOCtlEvent;
+ pDriveNumberPermanentStorageLocation = (PULONG) &hFileRecord->NtAsyncIOCtlEvent;
+ ComReadEvent = hFileRecord->NtAsyncReadEvent;
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ switch (Category) {
+
+ case IOCTL_ASYNC: /* Serial Device Control */
+
+ if (IoVectorType != ComVectorType) {
+#if DBG
+ KdPrint(("DosDevIOCtl[2]: Category %d, Function 0x%x with non-COM(%d) type handle\n",
+ Category, Function, IoVectorType));
+#endif
+ RetCode = ERROR_BAD_COMMAND;
+ break;
+ }
+
+ switch (Function) {
+
+ case ASYNC_SETBAUDRATE: /* Set Baud Rate */
+
+ if (cbParmList < sizeof(USHORT)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForRead(pvParmList, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ IoControlCode = IOCTL_SERIAL_SET_BAUD_RATE;
+ IO.SerialBaudRate.BaudRate = (ULONG)(*(PUSHORT)pvParmList);
+ IoCtlParamLength = sizeof(SERIAL_BAUD_RATE);
+ IoOutputBuffer = NULL;
+ IoOutputBufferLength = 0;
+ ComSetOnlyFunction = TRUE;
+ break;
+
+ case ASYNC_SETLINECTRL: /* Set Line Control */
+
+ if (cbParmList < 3) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForRead(pvParmList, 3, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ IoControlCode = IOCTL_SERIAL_SET_LINE_CONTROL;
+ pLineCtrl = (PLINECONTROL)pvParmList;
+ IO.SerialLineControl.StopBits = pLineCtrl->bStopBits;
+ IO.SerialLineControl.Parity = pLineCtrl->bParity;
+ IO.SerialLineControl.WordLength = pLineCtrl->bDataBits;
+ IoCtlParamLength = sizeof(SERIAL_LINE_CONTROL);
+ IoOutputBuffer = NULL;
+ IoOutputBufferLength = 0;
+ ComSetOnlyFunction = TRUE;
+ break;
+
+ case ASYNC_TRANSMITIMM: /* Transmit Immediate Char */
+
+ if (cbParmList < 1) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForRead(pvParmList, 1, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ IoControlCode = IOCTL_SERIAL_IMMEDIATE_CHAR;
+ IO.SerialImmediateChar = *(PUCHAR)pvParmList;
+ IoCtlParamLength = sizeof(UCHAR);
+ IoOutputBuffer = NULL;
+ IoOutputBufferLength = 0;
+ ComSetOnlyFunction = TRUE;
+ break;
+
+ case ASYNC_SETBREAKOFF: /* Set Break Off */
+
+ case ASYNC_SETBREAKON: /* Set Break On */
+
+ if (cbData < sizeof(USHORT)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ if (Function == ASYNC_SETBREAKOFF) {
+ IoControlCode = IOCTL_SERIAL_SET_BREAK_OFF;
+ }
+ else {
+ IoControlCode = IOCTL_SERIAL_SET_BREAK_ON;
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IoControlCode,
+ NULL,
+ 0,
+ NULL,
+ 0
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_COMMSTATUS,
+ NULL,
+ 0,
+ &IO,
+ sizeof(SERIAL_STATUS)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ *(PUSHORT)pvData = MapSerialCommErr(IO.SerialStatus.Errors);
+ break;
+
+
+ case ASYNC_SETMODEMCTRL: /* Set Modem Control Signals */
+
+ if (cbData < sizeof(USHORT)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ if (cbParmList < 2) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForRead(pvParmList, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ MaskOn = *(PUCHAR)pvParmList;
+ MaskOff = *((PUCHAR)pvParmList + 1);
+ if (MaskOn & 0x1) { /* Set DTR */
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_SET_DTR,
+ NULL,
+ 0,
+ NULL,
+ 0
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ }
+ if (MaskOn & 0x2) { /* Set RTS */
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_SET_RTS,
+ NULL,
+ 0,
+ NULL,
+ 0
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ }
+ if (!(MaskOff & 0x1)) { /* Clear DTR */
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_CLR_DTR,
+ NULL,
+ 0,
+ NULL,
+ 0
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ }
+ if (MaskOn & 0x1) { /* Clear RTS */
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_CLR_RTS,
+ NULL,
+ 0,
+ NULL,
+ 0
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_COMMSTATUS,
+ NULL,
+ 0,
+ &IO,
+ sizeof(SERIAL_STATUS)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ *(PUSHORT)pvData = MapSerialCommErr(IO.SerialStatus.Errors);
+ break;
+
+
+ case ASYNC_STOPTRANSMIT: /* Stop Transmit */
+
+ IoControlCode = IOCTL_SERIAL_SET_XOFF;
+ Io = NULL;
+ IoCtlParamLength = 0;
+ IoOutputBuffer = NULL;
+ IoOutputBufferLength = 0;
+ ComSetOnlyFunction = TRUE;
+
+ case ASYNC_STARTTRANSMIT: /* Start Transmit */
+
+ IoControlCode = IOCTL_SERIAL_SET_XON;
+ Io = NULL;
+ IoCtlParamLength = 0;
+ IoOutputBuffer = NULL;
+ IoOutputBufferLength = 0;
+ ComSetOnlyFunction = TRUE;
+
+ case ASYNC_GETBAUDRATE: /* Get Baud Rate */
+
+ if (cbData < 2) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_BAUD_RATE,
+ NULL,
+ 0,
+ &IO,
+ sizeof(SERIAL_BAUD_RATE)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ *(PUSHORT)pvData = (USHORT)IO.SerialBaudRate.BaudRate;
+ break;
+
+ case ASYNC_GETLINECTRL: /* Get Line Control */
+
+ if (cbData < 4) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, 4, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_LINE_CONTROL,
+ NULL,
+ 0,
+ &IO,
+ sizeof(SERIAL_LINE_CONTROL)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ pLineCtrl = (PLINECONTROL)pvData;
+ pLineCtrl->bDataBits = IO.SerialLineControl.WordLength;
+ pLineCtrl->bParity = IO.SerialLineControl.Parity;
+ pLineCtrl->bStopBits = IO.SerialLineControl.StopBits;
+ /*
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_HANDFLOW,
+ NULL,
+ 0,
+ &IO,
+ sizeof(SERIAL_HANDFLOW)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ pLineCtrl->fTransBreak =
+ (IO.SerialHandflow.FlowReplace & SERIAL_BREAK_CHAR) ? (BYTE)1 : (BYTE)0;
+ */
+ /* BUGBUG - How to determine if a break is being sent? */
+ pLineCtrl->fTransBreak = 0;
+ break;
+
+ case ASYNC_GETCOMMSTATUS: /* Get Comm Status */
+
+ if (cbData < 1) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, 1, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_COMMSTATUS,
+ NULL,
+ 0,
+ &IO,
+ sizeof(SERIAL_STATUS)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ *(PUCHAR)pvData = (UCHAR)(IO.SerialStatus.HoldReasons & ~SERIAL_RX_WAITING_FOR_DSR);
+ if (IO.SerialStatus.HoldReasons & SERIAL_RX_WAITING_FOR_DSR) {
+ *(PUCHAR)pvData |= RX_WAITING_FOR_DSR;
+ }
+ if (IO.SerialStatus.WaitForImmediate) {
+ *(PUCHAR)pvData |= TX_WAITING_TO_SEND_IMM;
+ }
+ break;
+
+ case ASYNC_GETCOMMERROR: /* Get COM Error Word */
+
+ if (cbData < sizeof(USHORT)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_COMMSTATUS,
+ NULL,
+ 0,
+ &IO,
+ sizeof(SERIAL_STATUS)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ *(PUSHORT)pvData = MapSerialCommErr(IO.SerialStatus.Errors);
+ break;
+
+ case ASYNC_GETCOMMEVENT: /* Get COM Event Information */
+
+ // BUGBUG the Nt has no IOCTL to support this yet
+ // 6-Feb-92
+ // Following code is not correct.
+ if (cbData < sizeof(USHORT)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_WAIT_MASK,
+ NULL,
+ 0,
+ &IO,
+ sizeof(ULONG)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ *(PUSHORT)pvData = (USHORT)(IO.SerialWaitMask & 0x1ff);
+ break;
+
+ case ASYNC_GETDCBINFO: /* Get Device Control Block */
+
+ if (cbData < sizeof(DCBINFO)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(DCBINFO), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ pDCBInfo = (PDCBINFO)pvData;
+ pDCBInfo->fbTimeout = 0;
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_TIMEOUTS,
+ NULL,
+ 0,
+ &IO,
+ sizeof(SERIAL_TIMEOUTS)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ if (IO.SerialTimeouts.ReadIntervalTimeout == 0) {
+ pDCBInfo->usReadTimeout = (USHORT)((IO.SerialTimeouts.ReadTotalTimeoutConstant - 10) / 10);
+ pDCBInfo->fbTimeout |= MODE_READ_TIMEOUT;
+ }
+ else if (IO.SerialTimeouts.ReadTotalTimeoutConstant != 0) {
+ pDCBInfo->usReadTimeout = (USHORT)((IO.SerialTimeouts.ReadTotalTimeoutConstant - 10) / 10);
+ pDCBInfo->fbTimeout |= MODE_WAIT_READ_TIMEOUT;
+ }
+ else {
+ pDCBInfo->usReadTimeout = 0;
+ pDCBInfo->fbTimeout |= MODE_NOWAIT_READ_TIMEOUT;
+ }
+ if ((IO.SerialTimeouts.WriteTotalTimeoutMultiplier != 0) ||
+ (IO.SerialTimeouts.WriteTotalTimeoutConstant != 0)) {
+ pDCBInfo->usWriteTimeout = (USHORT)((IO.SerialTimeouts.WriteTotalTimeoutConstant - 10) / 10);
+ }
+ else {
+ pDCBInfo->fbTimeout |= MODE_NO_WRITE_TIMEOUT;
+ pDCBInfo->usWriteTimeout = 0;
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_CHARS,
+ NULL,
+ 0,
+ &IO,
+ sizeof(SERIAL_CHARS)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ pDCBInfo->bErrorReplacementChar = IO.SerialChars.ErrorChar;
+ pDCBInfo->bBreakReplacementChar = IO.SerialChars.BreakChar;
+ pDCBInfo->bXONChar = IO.SerialChars.XonChar;
+ pDCBInfo->bXOFFChar = IO.SerialChars.XoffChar;
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_HANDFLOW,
+ NULL,
+ 0,
+ &IO,
+ sizeof(SERIAL_HANDFLOW)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ pDCBInfo->fbCtlHndShake = (BYTE)IO.SerialHandflow.ControlHandShake;
+ pDCBInfo->fbFlowReplace = (BYTE)IO.SerialHandflow.FlowReplace;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("ASYNC_GETDCBINFO\n"));
+ KdPrint(("Write Timeout: %x\n", pDCBInfo->usWriteTimeout & 0xffff));
+ KdPrint(("Read Timeout: %x\n", pDCBInfo->usReadTimeout & 0xffff));
+ KdPrint(("Flags1 : %x\n", pDCBInfo->fbCtlHndShake & 0xff));
+ KdPrint(("Flags2 : %x\n", pDCBInfo->fbFlowReplace & 0xff));
+ KdPrint(("Flags3 : %x\n", pDCBInfo->fbTimeout & 0xff));
+ }
+#endif
+ break;
+
+ case ASYNC_SETDCBINFO: /* Set Device Control Block */
+
+ if (cbParmList < sizeof(DCBINFO)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForRead(pvParmList, sizeof(DCBINFO), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ pDCBInfo = (PDCBINFO)pvParmList;
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("ASYNC_SETDCBINFO\n"));
+ KdPrint(("Write Timeout: %x\n", pDCBInfo->usWriteTimeout & 0xffff));
+ KdPrint(("Read Timeout: %x\n", pDCBInfo->usReadTimeout & 0xffff));
+ KdPrint(("Flags1 : %x\n", pDCBInfo->fbCtlHndShake & 0xff));
+ KdPrint(("Flags2 : %x\n", pDCBInfo->fbFlowReplace & 0xff));
+ KdPrint(("Flags3 : %x\n", pDCBInfo->fbTimeout & 0xff));
+ }
+#endif
+ TmpReadTimeout = (ULONG) pDCBInfo->usReadTimeout * 10L + 10L;
+
+ //
+ // BUGBUG: Prevent NT from waiting more than 1000 MSec
+ // inside the device driver when the mode is
+ // MODE_WAIT_READ_TIMEOUT.
+ // OS/2 cancels pending IOs when ASYNC_SETDCBINFO
+ // with MODE_WAIT_READ_TIMEOUT
+ // is called with 0 ReadTimeout while NT does not.
+ // Therefore, we have to force a timeout exit.
+ //
+
+#if 0
+ if (((pDCBInfo->fbTimeout & 0x6) == MODE_WAIT_READ_TIMEOUT) &&
+ (TmpReadTimeout > 1000)
+ ) {
+ TmpReadTimeout = 1000;
+ }
+#else
+ //
+ // New better handling: Sets the read event. This releases
+ // any thread which might be waiting in ComReadRoutine().
+ // That thread will figure out its been aborted, and will cancel
+ // the I/O operation.
+ //
+
+ if (((pDCBInfo->fbTimeout & 0x6) == MODE_WAIT_READ_TIMEOUT) &&
+ (pDCBInfo->usReadTimeout == 0)
+ ) {
+
+ Status = NtSetEvent(
+ ComReadEvent,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DosDevIoCtl2: SETDCBINFO - NtSetEvent failed, Status = %lx", Status));
+ }
+#endif
+ }
+ }
+#endif
+
+ switch (pDCBInfo->fbTimeout & 0x6) {
+ case 0:
+ /* Illegal value */
+ return(ERROR_PROTECTION_VIOLATION);
+ break;
+
+ case MODE_READ_TIMEOUT:
+ /* Normal read timeout processing */
+ IO.SerialTimeouts.ReadIntervalTimeout = 0;
+ IO.SerialTimeouts.ReadTotalTimeoutMultiplier = 0;
+ IO.SerialTimeouts.ReadTotalTimeoutConstant = TmpReadTimeout;
+ break;
+
+ case MODE_WAIT_READ_TIMEOUT:
+ /* Wait for something */
+ IO.SerialTimeouts.ReadIntervalTimeout = 0xffffffffL;
+ IO.SerialTimeouts.ReadTotalTimeoutMultiplier = 0xffffffffL;
+ IO.SerialTimeouts.ReadTotalTimeoutConstant = TmpReadTimeout;
+ break;
+
+ case MODE_NOWAIT_READ_TIMEOUT:
+ /* No wait timeout */
+ IO.SerialTimeouts.ReadIntervalTimeout = 0xffffffff;
+ IO.SerialTimeouts.ReadTotalTimeoutMultiplier = 0;
+ IO.SerialTimeouts.ReadTotalTimeoutConstant = 0;
+ break;
+
+ }
+ if (pDCBInfo->fbTimeout & MODE_NO_WRITE_TIMEOUT) { /* infinite write timeout */
+ IO.SerialTimeouts.WriteTotalTimeoutMultiplier = 0;
+ IO.SerialTimeouts.WriteTotalTimeoutConstant = 0;
+ }
+ else {
+ IO.SerialTimeouts.WriteTotalTimeoutMultiplier = 0;
+ IO.SerialTimeouts.WriteTotalTimeoutConstant = (ULONG) pDCBInfo->usWriteTimeout * 10L + 10L;
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_SET_TIMEOUTS,
+ &IO,
+ sizeof(SERIAL_TIMEOUTS),
+ NULL,
+ 0
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_CHARS,
+ NULL,
+ 0,
+ &IO,
+ sizeof(SERIAL_CHARS)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ IO.SerialChars.ErrorChar = pDCBInfo->bErrorReplacementChar;
+ IO.SerialChars.BreakChar = pDCBInfo->bBreakReplacementChar;
+
+ //
+ // The NT driver does not allow XON == XOFF.
+ // OS/2 programs usually set XON = XOFF = 0 when not using XON/XOFF
+ // handshaking. Therefore, we allow this situation by leaving the
+ // XON/XOFF chars at their previous values (an alternative is to set
+ // XON = 0, XOFF = 1).
+ //
+
+ if (((pDCBInfo->fbFlowReplace & (MODE_AUTO_TRANSMIT|MODE_AUTO_RECEIVE)) == 0) &&
+ (pDCBInfo->bXONChar == pDCBInfo->bXOFFChar)) {
+ //
+ // leave chars at previous values
+ //
+ } else {
+ IO.SerialChars.XonChar = pDCBInfo->bXONChar;
+ IO.SerialChars.XoffChar = pDCBInfo->bXOFFChar;
+ }
+
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_SET_CHARS,
+ &IO,
+ sizeof(SERIAL_CHARS),
+ NULL,
+ 0
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_HANDFLOW,
+ NULL,
+ 0,
+ &IO,
+ sizeof(SERIAL_HANDFLOW)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ IO.SerialHandflow.ControlHandShake =
+ ((ULONG) pDCBInfo->fbCtlHndShake) & ~SERIAL_CONTROL_INVALID;
+ IO.SerialHandflow.FlowReplace =
+ ((ULONG) pDCBInfo->fbFlowReplace) & ~SERIAL_FLOW_INVALID;
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_SET_HANDFLOW,
+ &IO,
+ sizeof(SERIAL_HANDFLOW),
+ NULL,
+ 0
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ break;
+
+ case ASYNC_GETINQUECOUNT: /* Get Receive Queue Characters */
+
+ case ASYNC_GETOUTQUECOUNT: /* Get Transmit Queue Characters */
+
+ if (cbData < sizeof(RXQUEUE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(RXQUEUE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ pRXQueue = (PRXQUEUE)pvData;
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_COMMSTATUS,
+ NULL,
+ 0,
+ &IO,
+ sizeof(SERIAL_STATUS)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ if (Function == ASYNC_GETINQUECOUNT) {
+ pRXQueue->cch = (USHORT)IO.SerialStatus.AmountInInQueue;
+ pRXQueue->cb = 1024; /* according to the PRM */
+ }
+ else {
+ pRXQueue->cch = (USHORT)IO.SerialStatus.AmountInOutQueue;
+ pRXQueue->cb = 1024; /* according to the PRM */
+ }
+ break;
+
+ case ASYNC_GETMODEMINPUT: /* Get Modem Input */
+
+ if (cbData < sizeof(BYTE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_MODEMSTATUS,
+ NULL,
+ 0,
+ &ModemStatus,
+ sizeof(ModemStatus)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ *(PBYTE)pvData = (BYTE)ModemStatus;
+ break;
+
+ case ASYNC_GETLINESTATUS: /* Get Line Status */
+
+ if (cbData < sizeof(BYTE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_COMMSTATUS,
+ NULL,
+ 0,
+ &IO,
+ sizeof(SERIAL_STATUS)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+ LineStatus = 0;
+ if (IO.SerialStatus.AmountInOutQueue != 0) {
+ LineStatus |= (WRITE_REQUEST_QUEUED | DATA_IN_TX_QUE);
+ }
+ if (((IO.SerialStatus.HoldReasons &
+ (SERIAL_TX_WAITING_FOR_CTS |
+ SERIAL_TX_WAITING_FOR_DSR |
+ SERIAL_TX_WAITING_FOR_DCD |
+ SERIAL_TX_WAITING_FOR_XON |
+ SERIAL_TX_WAITING_XOFF_SENT |
+ SERIAL_TX_WAITING_ON_BREAK)) == 0) &&
+ (IO.SerialStatus.AmountInOutQueue != 0)
+ ) {
+ LineStatus |= HARDWARE_TRANSMITTING;
+ }
+ if (IO.SerialStatus.WaitForImmediate) {
+ LineStatus |= CHAR_READY_TO_SEND_IMM;
+ }
+ *(PBYTE)pvData = LineStatus;
+ break;
+
+ case ASYNC_GETMODEMOUTPUT: /* Get Modem Output */
+
+ if (cbData < sizeof(BYTE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_SERIAL_GET_DTRRTS,
+ NULL,
+ 0,
+ &IO,
+ sizeof(IO.SerialDTRRTS)
+ );
+ if (ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode)) {
+ return (RetCode);
+ }
+
+ *(PBYTE)pvData = 0;
+ if (IO.SerialDTRRTS & SERIAL_DTR_STATE) {
+ *(PBYTE)pvData |= DTR_ON;
+ }
+ if (IO.SerialDTRRTS & SERIAL_RTS_STATE) {
+ *(PBYTE)pvData |= RTS_ON;
+ }
+ break;
+
+ default:
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+ case IOCTL_PRINTER: /* Printer Device Control */
+
+ switch (Function) {
+
+ case PRT_SETFRAMECTL: /* Set Frame Control */
+
+ if (cbData < sizeof(FRAME)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForRead(pvData, sizeof(FRAME), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ pFrame = (PFRAME)pvData;
+ ParCharPerLine = pFrame->bCharsPerLine;
+ ParLinesPerInch = pFrame->bLinesPerInch;
+ break;
+
+ case PRT_SETINFINITERETRY: /* Set Infinite Retry */
+
+ if (cbData < sizeof(BYTE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForRead(pvData, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ ParInfiniteRetry = *(PBYTE)pvData;
+ break;
+
+ case PRT_INITPRINTER: /* Init Printer */
+
+ IoControlCode = IOCTL_PAR_SET_INFORMATION;
+ IO.ParSetInformation.Init = PARALLEL_INIT;
+ IoCtlParamLength = sizeof(PAR_SET_INFORMATION);
+ IoOutputBuffer = NULL;
+ IoOutputBufferLength = 0;
+ SetOnlyFunction = TRUE;
+ break;
+
+ case PRT_ACTIVATEFONT: /* Activate Font */
+
+ break;
+
+ case PRT_GETFRAMECTL: /* Get Frame Control */
+
+ if (cbData < sizeof(FRAME)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(FRAME), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ pFrame = (PFRAME)pvData;
+ pFrame->bCharsPerLine = ParCharPerLine;
+ pFrame->bLinesPerInch = ParLinesPerInch;
+ break;
+
+ case PRT_GETINFINITERETRY: /* Get Infinite Retry */
+
+ if (cbData < sizeof(BYTE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ *(PBYTE)pvData = ParInfiniteRetry;
+ break;
+
+ case PRT_GETPRINTERSTATUS: /* Get Printer Status */
+
+ if (cbData < sizeof(BYTE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ Status = NtDeviceIoControlFile( NtHandle,
+ 0,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_PAR_QUERY_INFORMATION,
+ NULL,
+ 0,
+ &IO,
+ sizeof(PAR_QUERY_INFORMATION)
+ );
+ if (!NT_SUCCESS(Status)) {
+ return(ERROR_PROTECTION_VIOLATION);
+ }
+ ParInfo = 0;
+ if (IO.ParQueryInformation.Status & PARALLEL_SELECTED) {
+ ParInfo |= PRINTER_SELECTED;
+ }
+ if (IO.ParQueryInformation.Status & PARALLEL_PAPER_EMPTY) {
+ ParInfo |= PRINTER_OUT_OF_PAPER;
+ }
+ if ((IO.ParQueryInformation.Status & PARALLEL_BUSY) == 0) {
+ ParInfo |= PRINTER_NOT_BUSY;
+ }
+ *(PBYTE)pvData = ParInfo;
+ break;
+
+ case PRT_QUERYACTIVEFONT: /* Query Active Font */
+
+ if (cbData < sizeof(FONTINFO)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(FONTINFO), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ pFontInfo = (PFONTINFO)pvData;
+ pFontInfo->idCodePage = 0;
+ pFontInfo->idFont = 0;
+ break;
+
+ case PRT_VERIFYFONT: /* Verify Font */
+
+ break;
+
+ default:
+#if DBG
+ KdPrint((DosDevIOCtl2NotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+ case IOCTL_SCR_AND_PTRDRAW: /* PTR : Screen/Pointer-Draw Control */
+ if (IoVectorType != MouseVectorType)
+ {
+#if DBG
+ KdPrint(("DosDevIOCtl2: Category %d, Function 0x%x with non-Mouse(%d) type handle\n",
+ Category, Function, IoVectorType));
+#endif
+ RetCode = ERROR_BAD_COMMAND;
+ break;
+ }
+
+ switch (Function)
+ {
+ case PTR_GETPTRDRAWADDRESS: /* retrives entry-point address for the pointer-draw function */
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+
+ default:
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+ case IOCTL_KEYBOARD: /* KBD : Keyboard Control */
+ if ((IoVectorType != KbdVectorType) &&
+ (IoVectorType != ScreenVectorType))
+ {
+#if DBG
+ KdPrint(("DosDevIOCtl2: Category %d, Function 0x%x with non-Kbd(%d) type handle\n",
+ Category, Function, IoVectorType));
+#endif
+ RetCode = ERROR_BAD_COMMAND;
+ break;
+ }
+
+ switch (Function)
+ {
+ case KBD_CREATE: /* Create Logical Keyboard */
+
+ case KBD_DESTROY: /* Free Logical Keyboard */
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+
+ case KBD_GETCODEPAGEID: /* Get Code Page */
+
+ if ((cbData < sizeof(CPID)) ||
+ (cbParmList != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvData, sizeof(CPID), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = KbdGetCpId((PUSHORT)pvData,
+ (ULONG)hDev);
+
+ break;
+
+ case KBD_GETINPUTMODE: /* Get Input Mode */
+
+ if ((cbData < sizeof(BYTE)) ||
+ (cbParmList != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvData, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = KbdGetInputMode((PBYTE)pvData,
+ (ULONG)hDev);
+
+ break;
+
+ case KBD_GETINTERIMFLAG: /* Get Interim Flag */
+
+ if ((cbData < sizeof(BYTE)) ||
+ (cbParmList != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvData, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = KbdGetInterimFlag((PBYTE)pvData,
+ (ULONG)hDev);
+
+ break;
+
+ case KBD_GETKEYBDTYPE: /* Get Keybaord Type */
+
+ if ((cbData < sizeof(KBDTYPE)) ||
+ (cbParmList != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvData, sizeof(KBDTYPE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ ((PKBDTYPE)pvData)->reserved1 = 0;
+ ((PKBDTYPE)pvData)->reserved2 = 0;
+
+ RetCode = KbdGetKbdType((PUSHORT)pvData,
+ (ULONG)hDev);
+
+ break;
+
+ case KBD_GETSESMGRHOTKEY: /* Get Hot-Key Info */
+
+ if ((cbData < sizeof(HOTKEY)) ||
+ (cbParmList < 2))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvData, sizeof(KBDTYPE), 1);
+ Od2ProbeForRead(pvParmList, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = KbdGetHotKey((PUSHORT)pvParmList,
+ (PBYTE)pvData,
+ (ULONG)hDev);
+
+ break;
+
+ case KBD_GETSHIFTSTATE: /* Get Shift State */
+
+ if ((cbData < sizeof(SHIFTSTATE)) ||
+ (cbParmList != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvData, sizeof(SHIFTSTATE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = KbdGetShiftState((PBYTE)pvData,
+ (ULONG)hDev);
+
+ break;
+
+ case KBD_PEEKCHAR: /* Peek Character Data Record */
+
+ if ((cbData < sizeof(KBDKEYINFO)) ||
+ (cbParmList < 2))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvData, sizeof(KBDKEYINFO), 1);
+ Od2ProbeForWrite(pvParmList, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = KbdPeek((PKBDKEYINFO)pvData,
+ (ULONG)hDev);
+
+ if (((PKBDKEYINFO)pvData)->fbStatus & 0x40)
+ {
+ *(PUSHORT)pvParmList = KBD_DATA_RECEIVED;
+ } else
+ *(PUSHORT)pvParmList = 0;
+
+ if (SesGrp->ModeFlag & 1)
+ {
+ *(PUSHORT)pvParmList |= KBD_DATA_BINARY;
+ }
+
+ break;
+
+ case KBD_READCHAR: /* Read Character Data Record */
+
+ try
+ {
+ Od2ProbeForWrite(pvParmList, sizeof(USHORT), 1);
+ NumChar = (USHORT)(*((PUSHORT) pvParmList) & 0x7FFF);
+ Od2ProbeForWrite(pvData, sizeof(KBDKEYINFO) * NumChar, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if ((cbData < (NumChar * sizeof(KBDKEYINFO))) ||
+ (cbParmList < 2))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (NumChar > 16)
+ {
+ NumChar = 16; // return ERROR_INVALID_PARAMETER;
+ }
+
+ pKbdInfo = (PKBDKEYINFO)pvData;
+
+ WaitFlag = ((*(PUSHORT)pvParmList) & KBD_READ_NOWAIT) ?
+ IO_NOWAIT : IO_WAIT;
+
+ if (SesGrp->ModeFlag & 1)
+ {
+ *(PUSHORT)pvParmList = KBD_DATA_BINARY;
+ } else
+ *(PUSHORT)pvParmList = 0;
+
+ for (; NumChar ; NumChar-- )
+ {
+
+ if (RetCode = KbdCharIn(pKbdInfo,
+ WaitFlag,
+ (ULONG)hDev))
+ {
+ break;
+ }
+
+ (*(PUSHORT)pvParmList)++ ;
+ }
+
+ break;
+
+ case KBD_SETFGNDSCREENGRP: /* Set Foreground Screen Group */
+
+#if DBG
+ KdPrint(("DosDevIOCtl2: Category %d, Function 0x%x Illegal For User\n",
+ Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+
+ case KBD_SETFOCUS: /* Set Keyboard Focus */
+
+ if ((pvData != 0L) ||
+ (cbData != 0) ||
+ (cbParmList < 2 ))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ Handle = (ULONG)(*(PUSHORT)pvParmList);
+
+ //
+ // Check for invalid handle.
+ //
+
+ RetCode = DereferenceFileHandle((HFILE)Handle, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ break;
+ }
+ NtHandle = hFileRecord->NtHandle;
+ IoVectorType = hFileRecord->IoVectorType;
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if ((IoVectorType != KbdVectorType) &&
+ (IoVectorType != ScreenVectorType))
+ {
+#if DBG
+ KdPrint(("DosDevIOCtl2: Category %d, Function 0x%x with non-logical-Kbd(%d) type handle\n",
+ Category, Function, IoVectorType));
+#endif
+ RetCode = ERROR_INVALID_PARAMETER;
+ break;
+ }
+
+ RetCode = KbdGetFocus(IO_NOWAIT, /* *(PUSHORT)pvData, */
+ Handle);
+
+ break;
+
+ case KBD_SETINTERIMFLAG: /* Set Interim Flag */
+
+ if ((cbParmList < sizeof(BYTE)) ||
+ (cbData != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if ((Byte = *(PBYTE)pvParmList) & ~(CONVERSION_REQUEST | INTERIM_CHAR))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ RetCode = KbdSetInterimFlag(Byte,
+ (ULONG)hDev);
+
+ break;
+
+ case KBD_SETKCB: /* Bind Logical Keyboard to the Physical */
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+
+ case KBD_SETINPUTMODE: /* Set Input Mode */
+
+ if ((cbParmList < sizeof(BYTE)) ||
+ (cbData != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+#if PMNT
+ // Accept 0x82:
+ // 0x80 - BINARY_MODE
+ // 0x02 - ? (but issued by PM - BUGBUG - find out what it does)
+ if ((Byte = *(PBYTE)pvParmList & ~0x2) // Clear 0x2 bit
+ & ~(BINARY_MODE | SHIFT_REPORT_MODE))
+#else
+ if ((Byte = *(PBYTE)pvParmList) & ~(BINARY_MODE | SHIFT_REPORT_MODE))
+#endif
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ RetCode = KbdSetInputMode(Byte,
+ (ULONG)hDev);
+ break;
+
+ case KBD_SETNLS: /* Install Code Page */
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+
+ case KBD_SETSESMGRHOTKEY: /* Set New Hot-Key Info */
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+
+ case KBD_SETSHIFTSTATE: /* Set Shift State */
+
+ if ((cbParmList < sizeof(SHIFTSTATE)) ||
+ (cbData != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvParmList, sizeof(SHIFTSTATE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = KbdSetShiftState((PBYTE)pvParmList,
+ (ULONG)hDev);
+
+ break;
+
+ case KBD_SETTRANSTABLE: /* Set Translation Table */
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+
+ case KBD_SETTYPAMATICRATE: /* Set Keyboard Typamatic Rate */
+
+ if ((cbParmList < sizeof(RATEDELAY)) ||
+ (cbData != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, sizeof(RATEDELAY), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = KbdSetTypamaticRate((PBYTE)pvParmList,
+ (ULONG)hDev);
+
+ break;
+
+ case KBD_XLATESCAN: /* Translate Scan Code */
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+
+#if PMNT
+ // Called by InitKeyboard(), PMWIN
+ case KBD_GETHARDWAREID:
+ if ((cbData < 2) ||
+ (cbParmList != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ // For structure fields, see p7-90 of the IBM I/O Subsystems
+ // and Device Support, Vol. 1
+
+ try
+ {
+ // The value below is what we get under OS/2 1.3
+ // & AST Premium 386/33 (got them by single-step tru
+ // PM with OS/2 KD)
+ *(USHORT *)pvData = 2*sizeof(USHORT);
+
+ if (cbData < 4)
+ break;
+
+#ifdef JAPAN
+// MSKK May.07.1993 V-AkihiS
+ if (Od2IsIBM02_Keyboard(KbdType, OemId, OemSubType)) {
+ //
+ // Hardware ID of IBM-J 5576-002 keyboard is 0xAB90.
+ //
+ *(USHORT *)((ULONG)pvData + sizeof(USHORT)) = 0xAB90;
+ }
+ else
+ {
+ // BUGBUG - get the keyboard HW ID at run-time !
+ *(USHORT *)((ULONG)pvData + sizeof(USHORT)) = 0xAB41;
+ }
+#else
+ // We check we can copy the HW ID field
+ // 0xAB41 is for the 102 keys keyboard
+ *(USHORT *)((ULONG)pvData + sizeof(USHORT)) = 0xAB41;
+#endif
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = NO_ERROR;
+ break;
+
+ // Called by InitKeyboard(), PMWIN
+ case KBD_GETCPANDCOUNTRY:
+ if ((cbData < 2) ||
+ (cbParmList != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ // For structure fields, see p7-91 of the IBM I/O Subsystems
+ // and Device Support, Vol. 1
+
+ try
+ {
+ // The values below are what we get under OS/2 1.3
+ // & AST Premium 386/33 (got them by single-step tru
+ // PMWIN.InitKeyboard with OS/2 KD)
+#ifdef JAPAN
+// MSKK May.07.1993 V-AkihiS
+ *(USHORT *)pvData = 2*sizeof(USHORT) +
+ strlen("JP") + 1 +
+ strlen("103 ") + 1;
+#else
+ *(USHORT *)pvData = 12; // 2*sizeof(USHORT) + 3 + 5
+#endif
+
+ if (cbData < 4)
+ break;
+
+#ifdef JAPAN
+// MSKK May.07.1993 V-AkihiS
+ // We checked we can copy the kbCP field
+ *(USHORT *)((ULONG)pvData + sizeof(USHORT)) = 0x3A4;
+#else
+#if DBG
+ DbgPrint("Os2: KBD_GETCPANDCOUNTRY - code-page values:\n");
+ DbgPrint(" PrimaryCp: %d\n",
+ SesGrp->PrimaryCP);
+ DbgPrint(" DosCp: %d\n",
+ SesGrp->DosCP);
+ DbgPrint(" KbdCp: %d\n",
+ SesGrp->KbdCP);
+#endif //DBG
+ if (SesGrp->PrimaryCP != 0)
+ {
+ // We checked we can copy the kbCP field
+ *(USHORT *)((ULONG)pvData + sizeof(USHORT)) = (USHORT)SesGrp->PrimaryCP;
+ }
+ else if (SesGrp->DosCP != 0)
+ {
+ *(USHORT *)((ULONG)pvData + sizeof(USHORT)) = (USHORT)SesGrp->DosCP;
+ }
+ else if (SesGrp->KbdCP != 0)
+ {
+ *(USHORT *)((ULONG)pvData + sizeof(USHORT)) = (USHORT)SesGrp->KbdCP;
+ }
+ else
+ *(USHORT *)((ULONG)pvData + sizeof(USHORT)) = 0x1B5;
+#endif
+
+ // Copy as much as we can
+#ifdef JAPAN
+// MSKK May.07.1993 V-AkihiS
+ strncpy((char *)pvData + 2*sizeof(USHORT),
+ "JP",
+ cbData - 4);
+#else
+ strncpy((char *)pvData + 2*sizeof(USHORT),
+ &SesGrp->KeyboardLayout[0],
+ (((cbData - 4) < 2) ? cbData - 4 : 2));
+ // Make it null-terminated if less than 2 chars
+ if ((cbData > 2*sizeof(USHORT)+ 2) &&
+ (strlen(&SesGrp->KeyboardLayout[0]) < 2))
+ *((char *)pvData + 2*sizeof(USHORT) + 2) = '\0';
+ else
+ {
+ // Make it null-terminated if 2 chars
+ if (cbData > 2*sizeof(USHORT)+ 3)
+ *((char *)pvData + 2*sizeof(USHORT) + 3) = '\0';
+ }
+#if DBG
+ DbgPrint("Os2: KBD_GETCPANDCOUNTRY - keyboard layout: <%s>\n",
+ (char *)pvData + 2*sizeof(USHORT));
+#endif //DBG
+#endif // not JAPAN
+#ifdef JAPAN
+// MSKK May.19.1993 V-AkihiS
+ strncpy((char *)pvData + 2*sizeof(USHORT)+ 3,
+ "103 ",
+ cbData - 4 - 3);
+#else
+ //Copy the subcountry keyboard code
+ //Usually 103 for US, 189 for FR
+ memcpy((char *)pvData + 2*sizeof(USHORT) + 3,
+ &SesGrp->KeyboardName[0],
+ (((cbData - 2*sizeof(USHORT) - 3) < 4) ?
+ cbData - 2*sizeof(USHORT) - 3 : 4));
+#if DBG
+ DbgPrint("Os2: KBD_GETCPANDCOUNTRY - keyboard name: <%s>\n",
+ (char *)pvData + 2*sizeof(USHORT) + 3);
+#endif //DBG
+#endif // not JAPAN
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = NO_ERROR;
+ break;
+
+#endif // PMNT
+ default:
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+ case IOCTL_POINTINGDEVICE: /* MOU : Pointing-Device (Mouse) Control */
+ if (IoVectorType != MouseVectorType)
+ {
+#if DBG
+ KdPrint(("DosDevIOCtl2: Category %d, Function 0x%x with non-Mouse(%d) type handle\n",
+ Category, Function, IoVectorType));
+#endif
+ RetCode = ERROR_BAD_COMMAND;
+ break;
+ }
+
+ switch (Function)
+ {
+ case MOU_ALLOWPTRDRAW:
+
+ if ((cbParmList != 0) ||
+ (pvParmList != 0L) ||
+ (cbData != 0) ||
+ (pvData != 0L))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ RetCode = MouAllowPtrDraw((ULONG)hDev);
+
+ break;
+
+ case MOU_DRAWPTR: /* Draw Ptr Anywhere */
+
+ if ((cbParmList != 0) ||
+ (pvParmList != 0L) ||
+ (cbData != 0) ||
+ (pvData != 0L))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ RetCode = MouDrawPtr((ULONG)hDev);
+
+ break;
+
+ case MOU_GETBUTTONCOUNT: /* Get Button Number */
+
+ if ((cbParmList != 0) ||
+ (pvParmList != 0L) ||
+ (cbData < 2))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvData, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = MouGetNumButtons((PUSHORT)pvData,
+ (ULONG)hDev);
+
+ break;
+
+ case MOU_GETEVENTMASK: /* Get Event Mask */
+
+ if ((cbParmList != 0) ||
+ (pvParmList != 0L) ||
+ (cbData < 2))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvData, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = MouGetEventMask((PUSHORT)pvData,
+ (ULONG)hDev);
+
+ break;
+
+ case MOU_GETHOTKEYBUTTON: /* Get Mouse Equivalent for the HotKey */
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+
+ case MOU_GETMICKEYCOUNT: /* Get Count of Mickeys per Centimeter */
+
+ if ((cbParmList != 0) ||
+ (pvParmList != 0L) ||
+ (cbData < 2))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvData, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = MouGetNumMickeys((PUSHORT)pvData,
+ (ULONG)hDev);
+
+ break;
+
+ case MOU_GETMOUSTATUS: /* Get Mouse Status */
+
+ if ((cbParmList != 0) ||
+ (pvParmList != 0L) ||
+ (cbData < 2))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvData, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = MouGetDevStatus((PUSHORT)pvData,
+ (ULONG)hDev);
+
+ break;
+
+ case MOU_GETPTRPOS: /* Get Mouse Position */
+
+ if ((cbParmList != 0) ||
+ (pvParmList != 0L) ||
+ (cbData < sizeof(PTRLOC)))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvData, sizeof(PTRLOC), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+#if PMNT
+ if (ProcessIsPMProcess())
+ {
+ RetCode = MouGetPtrPosPM((PPTRLOC)pvData);
+ }
+ else
+ RetCode = MouGetPtrPos((PPTRLOC)pvData,
+ (ULONG)hDev);
+#else
+ RetCode = MouGetPtrPos((PPTRLOC)pvData,
+ (ULONG)hDev);
+#endif // else of #if PMNT
+
+ break;
+
+ case MOU_GETPTRSHAPE: /* Get Mouse Shape */
+
+ if ((cbParmList < 10) ||
+ (cbData < sizeof(PTRSHAPE)))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvParmList, cbParmList, 1);
+ Od2ProbeForWrite(pvData, sizeof(PTRSHAPE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = MouGetPtrShape((PBYTE)pvParmList,
+ (PPTRSHAPE)pvData,
+ (ULONG)hDev);
+
+ break;
+
+ case MOU_GETQUESTATUS: /* Get Queue Status */
+
+ if ((cbParmList != 0) ||
+ (pvParmList != 0L) ||
+ (cbData < sizeof(MOUQUEINFO)))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvData, sizeof(MOUQUEINFO), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = MouGetNumQueEl((PMOUQUEINFO)pvData,
+ (ULONG)hDev);
+
+ break;
+
+ case MOU_GETSCALEFACTORS: /* Get Scaling Factor */
+
+ if ((cbParmList != 0) ||
+ (pvParmList != 0L) ||
+ (cbData < sizeof(SCALEFACT)))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pvData, sizeof(SCALEFACT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = MouGetScaleFact((PSCALEFACT)pvData,
+ (ULONG)hDev);
+
+ break;
+
+ case MOU_READEVENTQUE: /* Read Event Queue */
+
+ if ((cbParmList < 2) ||
+ (cbData < sizeof(MOUEVENTINFO)))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pvData, sizeof(MOUEVENTINFO), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = MouReadEventQue((PMOUEVENTINFO)pvData,
+ (PUSHORT)pvParmList,
+ (ULONG)hDev);
+
+ break;
+
+ case MOU_REMOVEPTR: /* Remove Ptr */
+
+ if ((cbData != 0) ||
+ (pvData != 0L) ||
+ (cbParmList < sizeof(NOPTRRECT)))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, sizeof(NOPTRRECT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = MouRemovePtr((PNOPTRRECT)pvParmList,
+ (ULONG)hDev);
+
+ break;
+
+ case MOU_SCREENSWITCH: /* Screen Switch */
+
+ if ((cbParmList < sizeof(SCREENGROUP)) ||
+ (cbData != 0) ||
+ (pvData != 0L))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, sizeof(SCREENGROUP), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = MouScreenSwitch((PBYTE)pvParmList,
+ (ULONG)hDev);
+
+ break;
+
+ case MOU_SETEVENTMASK: /* Set Evenet Mask */
+
+ if ((cbParmList < 2) ||
+ (pvData != 0L) ||
+ (cbData != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = MouSetEventMask((PUSHORT)pvParmList,
+ (ULONG)hDev);
+
+ break;
+
+ case MOU_SETHOTKEYBUTTON: /* Set Mouse Equivalent for the HotKey */
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+
+ case MOU_SETMOUSTATUS: /* Set Mouse Status */
+
+ if ((cbParmList < 2) ||
+ (pvData != 0L) ||
+ (cbData != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = MouSetDevStatus((PUSHORT)pvParmList,
+ (ULONG)hDev);
+
+ break;
+
+ case MOU_SETPROTDRAWADDRESS: /* Notified Mouse Device Drive Address */
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+
+ case MOU_SETPTRPOS: /* Set Mouse Position */
+
+ if ((cbParmList < sizeof(PTRLOC)) ||
+ (pvData != 0L) ||
+ (cbData != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, sizeof(PTRLOC), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+#if PMNT
+ if (ProcessIsPMProcess())
+ {
+ RetCode = MouSetPtrPosPM((PPTRLOC)pvParmList);
+ }
+ else
+ RetCode = MouSetPtrPos((PPTRLOC)pvParmList,
+ (ULONG)hDev);
+#else
+ RetCode = MouSetPtrPos((PPTRLOC)pvParmList,
+ (ULONG)hDev);
+#endif // else of #if PMNT
+
+ break;
+
+ case MOU_SETPTRSHAPE: /* Set Mouse Shape */
+
+ if ((cbParmList < sizeof(PTRSHAPE)) ||
+ (cbData < 10))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, cbParmList, 1);
+ Od2ProbeForRead(pvParmList, sizeof(PTRSHAPE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = MouSetPtrShape((PBYTE)pvParmList,
+ (PPTRSHAPE)pvData,
+ (ULONG)hDev);
+
+ break;
+
+ case MOU_SETREALDRAWADDRESS: /* Notified Mouse Device Drive Address */
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+
+ case MOU_SETSCALEFACTORS: /* Set Scaling Factor */
+
+ if ((cbParmList < sizeof(SCALEFACT)) ||
+ (pvData != 0L) ||
+ (cbData != 0))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, sizeof(SCALEFACT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = MouSetScaleFact((PSCALEFACT)pvParmList,
+ (ULONG)hDev);
+
+ break;
+
+ case MOU_UPDATEDISPLAYMODE: /* New Display Mode */
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+
+ default:
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+ case IOCTL_MONITOR: /* MON : Character-Monitor Control */
+ if (IoVectorType != MonitorVectorType)
+ {
+#if DBG
+ KdPrint(("DosDevIOCtl2: Category %d, Function 0x%x with non-Monitor(%d) type handle\n",
+ Category, Function, IoVectorType));
+#endif
+ RetCode = ERROR_BAD_COMMAND;
+ break;
+ }
+
+ switch (Function)
+ {
+ case MON_REGISTERMONITOR: /* Register a Monitor */
+
+ try
+ {
+ Od2ProbeForRead(pvData, sizeof(MONITORPOSITION), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if (cbData != sizeof(MONITORPOSITION))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ RetCode = DosMonReg((ULONG)hDev,
+ (PBYTE)((PMONITORPOSITION)pvData)->pbInBuf,
+ (PBYTE)((PMONITORPOSITION)pvData)->pbInBuf+
+ ((PMONITORPOSITION)pvData)->offOutBuf,
+ (ULONG)(((PMONITORPOSITION)pvData)->fPosition),
+ (ULONG)(((PMONITORPOSITION)pvData)->index));
+ break;
+
+ default:
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+ case IOCTL_GENERAL: /* DEV : General Device Control */
+ switch (Function)
+ {
+ case DEV_FLUSHINPUT:
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, cbParmList, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ break;
+
+ case DEV_FLUSHOUTPUT: /* flush the output buffer */
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, cbParmList, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ NtFlushBuffersFile(NtHandle, &IoStatus);
+ break;
+
+ case DEV_QUERYMONSUPPORT: /* query for monitor support */
+
+ if ((IoVectorType != MouseVectorType) &&
+ (IoVectorType != KbdVectorType))
+ {
+#if DBG
+ KdPrint(("DosDevIOCtl2: Monitor Not supported for Device type %d\n",
+ IoVectorType));
+#endif
+ RetCode = ERROR_MONITORS_NOT_SUPPORTED;
+ break;
+ }
+
+ try
+ {
+ Od2ProbeForRead(pvParmList, 1, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if (*(PBYTE)pvParmList != 0)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ break;
+
+ default:
+
+#if DBG
+ KdPrint((DosDevIOCtl2NotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+
+ case IOCTL_DISK: /* Disk/Diskette Control */
+
+ switch (Function) {
+
+ case DSK_LOCKDRIVE:
+ case DSK_UNLOCKDRIVE:
+
+ if (cbParmList < sizeof(BYTE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForRead(pvParmList, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Ignore pvParmList -- it's just a reserved value
+ //
+
+ Status = NtFsControlFile(
+ NtHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ (Function == DSK_LOCKDRIVE) ?
+ FSCTL_LOCK_VOLUME :
+ FSCTL_UNLOCK_VOLUME,
+ NULL,
+ 0L,
+ NULL,
+ 0L);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DevDevIoCtl2() -- (UN)LOCKVOLUME, unable to NtFsControlFile, Status == %lx\n",
+ Status));
+ }
+#endif
+ RetCode = Or2MapNtStatusToOs2Error(Status, ERROR_BUSY_DRIVE);
+ break;
+ }
+ break;
+
+ case DSK_SETLOGICALMAP: /* Set Logical Map */
+
+ if (cbData < sizeof(BYTE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ *(PBYTE)pvData = 0;
+ break;
+
+ case DSK_BLOCKREMOVABLE: /* Check if block Device is Removable */
+
+ if (cbData < sizeof(BYTE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ // RetryIO() is not applied to DosDevIOCtl()
+ Status = NtQueryVolumeInformationFile(NtHandle,
+ &IoStatus,
+ &FsDeviceInfoBuffer,
+ sizeof(FsDeviceInfoBuffer),
+ FileFsDeviceInformation
+ );
+ if (NT_SUCCESS(Status)) {
+ *(PBYTE)pvData = (FsDeviceInfoBuffer.Characteristics & FILE_REMOVABLE_MEDIA) ? 0 : 1;
+ }
+ else {
+ *(PBYTE)pvData = 1; /* Non Removable */
+ }
+ break;
+
+ case DSK_GETLOGICALMAP: /* Get Logical Map */
+
+ if (cbData < sizeof(BYTE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForWrite(pvData, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ *(PBYTE)pvData = 0;
+ break;
+
+ case DSK_GETDEVICEPARAMS:
+
+ if (cbData < sizeof(BIOSPARAMETERBLOCK) ||
+ cbParmList < 1) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ try {
+ Od2ProbeForWrite(pvData, cbData, 1);
+ Od2ProbeForRead(pvParmList, cbParmList, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ pBPB = (PBIOSPARAMETERBLOCK) pvData;
+ BpbRequestType = (ULONG) (*(PBYTE) pvParmList);
+
+ //
+ // BpbRequestType is a byte designating:
+ // 0 - return recommended BPB for the drive type
+ // 1 - return current BPB for the media
+ //
+
+ RetCode = Od2IdentifyDiskDrive(
+ NtHandle,
+ pDriveNumberPermanentStorageLocation,
+ &DriveNumber);
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DevDevIoCtl2() -- GETDEVICEPARAMS, unable to Od2IdentifyDiskDrive, RetCode == %lx\n",
+ RetCode));
+ }
+#endif
+ break;
+ }
+
+ if (BpbRequestType & 0x1) {
+
+ RetCode = Od2AcquireMediaBPB(
+ DriveNumber,
+ NtHandle,
+ TRUE,
+ TRUE,
+ FALSE,
+ pBPB,
+ NULL,
+ NULL);
+ } else {
+
+ RetCode = Od2AcquireDeviceBPB(
+ DriveNumber,
+ NtHandle,
+ TRUE,
+ TRUE,
+ pBPB);
+ }
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DevDevIoCtl2() -- GETDEVICEPARAMS, unable to Od2AcquireBPB, RetCode == %lx\n",
+ RetCode));
+ }
+#endif
+ break;
+ }
+
+ break;
+
+ case DSK_SETDEVICEPARAMS:
+
+ if (cbData < sizeof(BIOSPARAMETERBLOCK) ||
+ cbParmList < 1) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ try {
+ Od2ProbeForRead(pvData, cbData, 1);
+ Od2ProbeForRead(pvParmList, cbParmList, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ pBPB = (PBIOSPARAMETERBLOCK) pvData;
+ BpbRequestType = (ULONG) (*(PBYTE) pvParmList);
+
+ RetCode = Od2IdentifyDiskDrive(
+ NtHandle,
+ pDriveNumberPermanentStorageLocation,
+ &DriveNumber);
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DevDevIoCtl2() -- SETDEVICEPARAMS, unable to Od2IdentifyDiskDrive, RetCode == %lx\n",
+ RetCode));
+ }
+#endif
+ break;
+ }
+
+ switch (BpbRequestType) {
+
+ case BUILD_BPB_FROM_MEDIUM:
+
+ RetCode = Od2AcquireMediaBPB(
+ DriveNumber,
+ NtHandle,
+ FALSE,
+ TRUE,
+ FALSE,
+ NULL,
+ NULL,
+ NULL);
+ break;
+
+ case REPLACE_BPB_FOR_DEVICE:
+
+ RetCode = Od2AcquireDeviceBPB(
+ DriveNumber,
+ NtHandle,
+ FALSE,
+ FALSE,
+ pBPB);
+ break;
+
+ case REPLACE_BPB_FOR_MEDIUM:
+
+ RetCode = Od2AcquireMediaBPB(
+ DriveNumber,
+ NtHandle,
+ FALSE,
+ FALSE,
+ FALSE,
+ pBPB,
+ NULL,
+ NULL);
+ break;
+
+ default:
+
+ RetCode = ERROR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DevDevIoCtl2() -- SETDEVICEPARAMS, unable to Od2AcquireBPB, RetCode == %lx\n",
+ RetCode));
+ }
+#endif
+ break;
+ }
+ break;
+
+ case DSK_READTRACK:
+ case DSK_WRITETRACK:
+ case DSK_VERIFYTRACK:
+
+ if (cbParmList < sizeof(TRACKLAYOUT)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ try {
+ Od2ProbeForRead(pvParmList, cbParmList, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ TrackLayout = (PTRACKLAYOUT) pvParmList;
+
+ {
+ ULONG l = (ULONG) TrackLayout->usFirstSector + (ULONG) TrackLayout->cSectors;
+
+ if (l > 1 && (cbParmList < sizeof(TRACKLAYOUT) + (l-1) * 2 * sizeof(USHORT))) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+ }
+
+ RetCode = Od2IdentifyDiskDrive(
+ NtHandle,
+ pDriveNumberPermanentStorageLocation,
+ &DriveNumber);
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DevDevIoCtl2() -- READWRITEVERIFYTRACK, unable to Od2IdentifyDiskDrive, RetCode == %lx\n",
+ RetCode));
+ }
+#endif
+ break;
+ }
+
+ RetCode = Od2AcquireMediaBPB(
+ DriveNumber,
+ NtHandle,
+ TRUE,
+ TRUE,
+ FALSE,
+ &PrivateBpb,
+ &PrivateMediaType,
+ &PrivateTrueGeometry);
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DevDevIoCtl2() -- READWRITEVERIFYTRACK, unable to Od2AcquireMediaBPB, RetCode == %lx\n",
+ RetCode));
+ }
+#endif
+ break;
+ }
+
+ if (PrivateMediaType == Unknown ||
+ PrivateMediaType == RemovableMedia ||
+ PrivateMediaType == FixedMedia) {
+
+ RetCode = ERROR_INVALID_DRIVE;
+ break;
+ }
+
+ CountSectors = (ULONG) TrackLayout->cSectors;
+
+ if (CountSectors > (ULONG) PrivateBpb.usSectorsPerTrack) {
+
+ RetCode = ERROR_SECTOR_NOT_FOUND;
+ break;
+ }
+
+ if (Function != DSK_VERIFYTRACK) {
+
+ if (cbData != 0) {
+
+ if (cbData < CountSectors * (ULONG) PrivateBpb.usBytesPerSector) {
+ RetCode = ERROR_INVALID_PARAMETER;
+ break;
+ }
+
+ } else {
+ cbData = CountSectors * (ULONG) PrivateBpb.usBytesPerSector;
+ }
+
+ try {
+ if (Function == DSK_READTRACK) {
+ Od2ProbeForWrite(pvData, cbData, 1);
+ } else {
+ Od2ProbeForRead(pvData, cbData, 1);
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ }
+
+ {
+ ULONG i, j;
+
+ for (i = 0, j = (ULONG) TrackLayout->usFirstSector;
+ i < CountSectors;
+ i++, j++) {
+
+ if ((ULONG) (TrackLayout->TrackTable[j].usSectorSize) !=
+ (ULONG) PrivateBpb.usBytesPerSector) {
+
+ return(ERROR_BAD_LENGTH);
+ }
+ }
+ }
+
+ switch (Function) {
+ case DSK_READTRACK:
+ DiskCommand = READ_TRACK_CMD;
+ break;
+ case DSK_WRITETRACK:
+ DiskCommand = WRITE_TRACK_CMD;
+ break;
+ case DSK_VERIFYTRACK:
+ DiskCommand = VERIFY_TRACK_CMD;
+ break;
+ }
+
+ RetCode = Od2ReadWriteVerifyTrack(
+ NtHandle,
+ DiskCommand,
+ TrackLayout,
+ pvData,
+ CountSectors,
+ &PrivateBpb,
+ &PrivateTrueGeometry);
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DevDevIoCtl2() -- Od2ReadWriteVerifyTrack failed, RetCode == %lx\n",
+ RetCode));
+ }
+#endif
+ break;
+ }
+
+ break;
+
+ case DSK_FORMATVERIFY:
+
+ if (cbParmList < sizeof(TRACKFORMAT)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ try {
+ Od2ProbeForRead(pvParmList, cbParmList, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ TrackFormat = (PTRACKFORMAT) pvParmList;
+
+ {
+ ULONG l = (ULONG) TrackFormat->cSectors;
+
+ if (l > 1 && (cbParmList < sizeof(TRACKFORMAT) + (l-1) * 4 * sizeof(BYTE))) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+ }
+
+ if (TrackFormat->bCommand != 1) {
+
+ //
+ // We only support a standard track format command
+ // (since that's what NT supports...)
+ //
+
+ return(ERROR_NOT_SUPPORTED);
+ }
+
+ RetCode = Od2IdentifyDiskDrive(
+ NtHandle,
+ pDriveNumberPermanentStorageLocation,
+ &DriveNumber);
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DevDevIoCtl2() -- FORMATVERIFY, unable to Od2IdentifyDiskDrive, RetCode == %lx\n",
+ RetCode));
+ }
+#endif
+ break;
+ }
+
+ RetCode = Od2AcquireMediaBPB(
+ DriveNumber,
+ NtHandle,
+ TRUE,
+ TRUE,
+ TRUE,
+ &PrivateBpb,
+ &PrivateMediaType,
+ NULL);
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DevDevIoCtl2() -- FORMATVERIFY, unable to Od2AcquireMediaBPB, RetCode == %lx\n",
+ RetCode));
+ }
+#endif
+ break;
+ }
+
+ if (PrivateMediaType == Unknown ||
+ PrivateMediaType == RemovableMedia ||
+ PrivateMediaType == FixedMedia) {
+
+ RetCode = ERROR_INVALID_DRIVE;
+ break;
+ }
+
+ CountSectors = (ULONG) TrackFormat->cSectors;
+
+ FormatSectorSizeType = TrackFormat->FormatTable[0].bBytesSector;
+
+ {
+ ULONG i;
+
+ for (i = 1;
+ i < CountSectors;
+ i++) {
+
+ if (TrackFormat->FormatTable[i].bBytesSector !=
+ FormatSectorSizeType) {
+
+ return(ERROR_NOT_SUPPORTED);
+ }
+ }
+ }
+
+ RetCode = Od2FormatTrack(
+ NtHandle,
+ TrackFormat,
+ CountSectors,
+ FormatSectorSizeType,
+ &PrivateBpb,
+ PrivateMediaType);
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DevDevIoCtl2() -- Od2FormatTrack failed, RetCode == %lx\n",
+ RetCode));
+ }
+#endif
+ break;
+ }
+
+ break;
+
+ case 0x4:
+
+ //
+ // This is an undocumented IOCTL that DSKIMAGE uses. Apparently it
+ // has something to do with mounting an FSD, whatever that means.
+ // Anyway, I don't think we need to do anything, so we return success.
+ //
+
+#if DBG
+ KdPrint(("DosDevIOCtl[2]: Category %d, Function 0x%x Not implemented. Returning NO_ERROR\n", Category, Function));
+#endif
+ break;
+
+ case DSK_REDETERMINEMEDIA:
+
+ if (cbParmList < sizeof(BYTE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ try {
+ Od2ProbeForRead(pvParmList, sizeof(BYTE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Ignore pvParmList -- it's just a reserved value
+ //
+
+ RetCode = Od2IdentifyDiskDrive(
+ NtHandle,
+ pDriveNumberPermanentStorageLocation,
+ &DriveNumber);
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DevDevIoCtl2() -- REDETERMINEMEDIA, unable to Od2IdentifyDiskDrive, RetCode == %lx\n",
+ RetCode));
+ }
+#endif
+ break;
+ }
+
+ RetCode = Od2AcquireMediaBPB(
+ DriveNumber,
+ NtHandle,
+ FALSE,
+ TRUE,
+ FALSE,
+ NULL,
+ NULL,
+ NULL);
+
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DevDevIoCtl2() -- REDETERMINEMEDIA, unable to Od2AcquireMediaBPB, RetCode == %lx\n",
+ RetCode));
+ }
+#endif
+ break;
+ }
+ break;
+
+ default:
+#if DBG
+ KdPrint((DosDevIOCtl2NotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+
+ default:
+ // Check for User defined categories
+ if ((Category >= 0x80) && (Category <= 0xff)) {
+#if DBG
+ KdPrint(("DosDevIOCtl2: User Category %d, Function 0x%x was called\n", Category, Function));
+#endif
+ Status = NtDeviceIoControlFile( NtHandle,
+ 0,
+ NULL,
+ NULL,
+ &IoStatus,
+ CTL_CODE(Category|0x8000,Function|0x800,METHOD_BUFFERED,FILE_ANY_ACCESS),
+ pvParmList,
+ cbParmList,
+ pvData,
+ cbData
+ );
+ if (!NT_SUCCESS(Status)) {
+ RetCode = ERROR_PROTECTION_VIOLATION;
+ }
+ }
+ else {
+#if DBG
+ KdPrint((DosDevIOCtl2NotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_CATEGORY;
+ }
+ break;
+ }
+
+ if (ComSetOnlyFunction) {
+ Status = NtDeviceIoControlFile( NtHandle,
+ ComIOCtlEvent,
+ NULL,
+ NULL,
+ &IoStatus,
+ IoControlCode,
+ Io,
+ IoCtlParamLength,
+ IoOutputBuffer,
+ IoOutputBufferLength
+ );
+
+ // Wait and Set the value at RetCode only
+
+ ErrorAtWaitForAsyncComIOCtl(Status, ComIOCtlEvent, &RetCode);
+ }
+ else if (SetOnlyFunction) {
+ Status = NtDeviceIoControlFile( NtHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ IoControlCode,
+ Io,
+ IoCtlParamLength,
+ IoOutputBuffer,
+ IoOutputBufferLength
+ );
+ if (!NT_SUCCESS(Status)) {
+ RetCode = ERROR_PROTECTION_VIOLATION;
+ }
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("Exit from DosDevIOCtl[2](), retcode = %d\n", RetCode));
+ }
+#endif
+
+ return(RetCode);
+}
+
+APIRET
+DosDevIOCtl(
+ PVOID pvData,
+ PVOID pvParmList,
+ ULONG Function,
+ ULONG Category,
+ HFILE hDev
+ )
+{
+ APIRET RetCode = NO_ERROR;
+ PVOID pData;
+ ULONG cbData;
+ PVOID pParmList;
+ ULONG cbParmList;
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosDevIOCtl";
+ #endif
+
+ //
+ // The following line is necessary because OS/2 ignores the high
+ // byte of Category
+ //
+
+ Category &= 0xffL;
+
+ pData = pvData;
+ pParmList = pvParmList;
+
+ switch (Category) {
+ case IOCTL_ASYNC: /* Serial Device Control */
+
+ switch (Function) {
+
+ case ASYNC_SETBAUDRATE: /* Set Baud Rate */
+
+ pData = NULL;
+ cbData = 0;
+ cbParmList = sizeof(SERIAL_BAUD_RATE);
+ break;
+
+ case ASYNC_SETLINECTRL: /* Set Line Control */
+
+ pData = NULL;
+ cbData = 0;
+ cbParmList = 3;
+ break;
+
+ case ASYNC_TRANSMITIMM: /* Transmit Immediate Char */
+
+ pData = NULL;
+ cbData = 0;
+ cbParmList = 1;
+ break;
+
+ case ASYNC_SETBREAKOFF: /* Set Break Off */
+
+ case ASYNC_SETBREAKON: /* Set Break On */
+
+ cbData = sizeof(USHORT);
+ pParmList = NULL;
+ cbParmList = 0;
+ break;
+
+ case ASYNC_SETMODEMCTRL: /* Set Modem Control Signals */
+
+ cbData = sizeof(USHORT);
+ cbParmList = 2; /* sizeof(MODEMSTATUS) */
+ break;
+
+ case ASYNC_STOPTRANSMIT: /* Stop Tarnsmit */
+
+ cbData = 0;
+ cbParmList = 0;
+ break;
+
+ case ASYNC_STARTTRANSMIT: /* Start Transmit */
+
+ cbData = 0;
+ cbParmList = 0;
+ break;
+
+ case ASYNC_GETBAUDRATE: /* Get Baud Rate */
+
+ cbData = sizeof(USHORT);
+ cbParmList = 0;
+ break;
+
+ case ASYNC_GETLINECTRL: /* Get Line Control */
+
+ cbData = 4;
+ cbParmList = 0;
+ break;
+
+ case ASYNC_GETCOMMSTATUS: /* Get Comm Status */
+
+ cbData = sizeof(BYTE);
+ cbParmList = 0;
+ break;
+
+ case ASYNC_GETCOMMERROR: /* Get COM Error Word */
+
+ cbData = sizeof(USHORT);
+ cbParmList = 0;
+ break;
+
+ case ASYNC_GETCOMMEVENT: /* Get COM Event Information */
+
+ cbData = sizeof(USHORT);
+ cbParmList = 0;
+ break;
+
+ case ASYNC_SETDCBINFO: /* Set Device Control Block */
+
+ cbData = 0;
+ cbParmList = sizeof(DCBINFO);
+ break;
+
+ case ASYNC_GETDCBINFO: /* Get Device Control Block */
+
+ cbData = sizeof(DCBINFO);
+ cbParmList = 0;
+ break;
+
+ case ASYNC_GETINQUECOUNT: /* Get Receive Queue Characters */
+
+ case ASYNC_GETOUTQUECOUNT: /* Get Transmit Queue Characters */
+
+ cbData = sizeof(RXQUEUE);
+ cbParmList = 0;
+ break;
+
+ case ASYNC_GETMODEMINPUT: /* Get Modem Input */
+
+ case ASYNC_GETLINESTATUS: /* Get Line Status */
+
+ case ASYNC_GETMODEMOUTPUT: /* Get Modem Output */
+
+ cbData = sizeof(BYTE);
+ cbParmList = 0;
+ break;
+
+ default:
+
+#if DBG
+ KdPrint((DosDevIOCtlNotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+ case IOCTL_PRINTER: /* Printer Device Control */
+
+ switch (Function) {
+
+ case PRT_SETFRAMECTL: /* Set Frame Control */
+
+ case PRT_GETFRAMECTL: /* Get Frame Control */
+
+ cbData = sizeof(FRAME);
+ cbParmList = 1;
+ break;
+
+ case PRT_INITPRINTER: /* Init Printer */
+
+ cbData = 0;
+ cbParmList = 1;
+ break;
+
+ case PRT_SETINFINITERETRY: /* Set Infinite Retry */
+
+ case PRT_GETINFINITERETRY: /* Get Infinite Retry */
+
+ case PRT_GETPRINTERSTATUS: /* Get Printer Status */
+
+ cbData = 1;
+ cbParmList = 1;
+ break;
+
+ case PRT_ACTIVATEFONT: /* Activate Font */
+
+ case PRT_QUERYACTIVEFONT: /* Query Active Font */
+
+ case PRT_VERIFYFONT: /* Verify Font */
+
+#if DBG
+ KdPrint((DosDevIOCtlNotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+
+ default:
+
+#if DBG
+ KdPrint((DosDevIOCtlNotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+ case IOCTL_SCR_AND_PTRDRAW: /* PTR : Screen/Pointer-Draw Control */
+ switch (Function)
+ {
+ case PTR_GETPTRDRAWADDRESS: /* retrives entry-point address for the pointer-draw function */
+
+ cbData = sizeof(PTRDRAWFUNCTION);
+ cbParmList = 0;
+ break;
+
+ default:
+
+#if DBG
+ KdPrint((DosDevIOCtlNotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+ case IOCTL_KEYBOARD: /* KBD : Keyboard Control */
+ switch (Function)
+ {
+ case KBD_CREATE: /* Create Logical Keyboard */
+
+ cbData = 0;
+ cbParmList = 4; // BUGBUG ??
+ break;
+
+ case KBD_DESTROY: /* Free Logical Keyboard */
+
+ cbData = 0;
+ cbParmList = 2; // BUGBUG ??
+ break;
+
+ case KBD_GETCODEPAGEID: /* Get Code Page */
+
+ cbData = sizeof(CPID);
+ cbParmList = 0;
+ break;
+
+ case KBD_GETINPUTMODE: /* Get Input Mode */
+
+ case KBD_GETINTERIMFLAG: /* Get Interim Flag */
+
+ cbData = 1;
+ cbParmList = 0;
+ break;
+
+ case KBD_GETKEYBDTYPE: /* Get Keyboard Type */
+
+ cbData = sizeof(KBDTYPE);
+ cbParmList = 0;
+ break;
+
+ case KBD_GETSESMGRHOTKEY: /* Get Hot-Key Info */
+
+ cbData = sizeof(HOTKEY);
+ cbParmList = 2;
+ break;
+
+ case KBD_GETSHIFTSTATE: /* Get Shift State */
+
+ cbData = sizeof(SHIFTSTATE);
+ cbParmList = 0;
+ break;
+
+ case KBD_PEEKCHAR: /* Peek Character Data Record */
+
+ cbData = sizeof(KBDKEYINFO);
+ cbParmList = 2;
+ break;
+
+ case KBD_READCHAR: /* Read Character Data Record */
+
+ cbData = sizeof(KBDKEYINFO) * (*((PUSHORT) pvParmList) & 0x7FFF);
+ cbParmList = 2;
+ break;
+
+ case KBD_SETFGNDSCREENGRP: /* Set Foreground Screen Group */
+
+ cbData = 0;
+ cbParmList = sizeof(SCREENGROUP);
+ break;
+
+ case KBD_SETFOCUS: /* Set Keyboard Focus */
+
+ case KBD_SETKCB: /* Bind Logical Keyboard to the Physical */
+
+ cbData = 0;
+ cbParmList = 2; // BUGBUG for 16-bits handle only (except Interim)
+ break;
+
+ case KBD_SETINPUTMODE: /* Set Input Mode */
+
+ case KBD_SETINTERIMFLAG: /* Set Interim Flag */
+
+ cbData = 0;
+ cbParmList = 1;
+ break;
+
+ case KBD_SETNLS: /* Install Code Page */
+
+ cbData = 0;
+ cbParmList = sizeof(CODEPAGEINFO);
+ break;
+
+ case KBD_SETSESMGRHOTKEY: /* Set New Hot-Key Info */
+
+ cbData = 0;
+ cbParmList = sizeof(HOTKEY);
+ break;
+
+ case KBD_SETSHIFTSTATE: /* Set Shift State */
+
+ cbData = 0;
+ cbParmList = sizeof(SHIFTSTATE);
+ break;
+
+ case KBD_SETTRANSTABLE: /* Set Translation Table */
+
+ cbData = 0;
+ cbParmList = 256; // BUGBUG-check
+ break;
+
+ case KBD_SETTYPAMATICRATE: /* Set Keyboard Typamatic Rate */
+
+ cbData = 0;
+ cbParmList = sizeof(RATEDELAY);
+ break;
+
+ case KBD_XLATESCAN: /* Translate Scan Code */
+
+ cbData = sizeof(KBDTRANS);
+ cbParmList = 2;
+ break;
+
+#if PMNT
+ // Called by InitKeyboard(), PMWIN
+ case KBD_GETHARDWAREID:
+ try
+ {
+ cbData = *(USHORT *)pvData;
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+ cbParmList = 0;
+ break;
+
+ // Called by InitKeyboard(), PMWIN
+ case KBD_GETCPANDCOUNTRY:
+ try
+ {
+ cbData = *(USHORT *)pvData;
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+ cbParmList = 0;
+ break;
+#endif // PMNT
+ default:
+
+#if DBG
+ KdPrint((DosDevIOCtlNotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+ case IOCTL_POINTINGDEVICE: /* MOU : Pointing-Device (Mouse) Control */
+ switch (Function)
+ {
+ case MOU_ALLOWPTRDRAW: /* Allow Ptr Draw */
+
+ case MOU_DRAWPTR: /* Draw Ptr Anywhere */
+
+ cbData = 0;
+ cbParmList = 0;
+ break;
+
+ case MOU_GETBUTTONCOUNT: /* Get Button Number */
+
+ case MOU_GETEVENTMASK: /* Get Event Mask */
+
+ case MOU_GETHOTKEYBUTTON: /* Get Mouse Equivalent for the HotKey */
+
+ case MOU_GETMICKEYCOUNT: /* Get Count of Mickeys per Centimeter */
+
+ case MOU_GETMOUSTATUS: /* Get Mouse Status */
+
+ cbData = 2;
+ cbParmList = 0;
+#if PMNT
+ pParmList = NULL;
+#endif
+ break;
+
+ case MOU_GETPTRPOS: /* Get Mouse Position */
+
+ cbData = sizeof(PTRLOC);
+ cbParmList = 0;
+ break;
+
+ case MOU_GETPTRSHAPE: /* Get Mouse Shape */
+
+ cbData = sizeof(PTRSHAPE);
+ cbParmList = 200; // BUGBUG ??
+ break;
+
+ case MOU_GETQUESTATUS: /* Get Queue Status */
+
+ cbData = sizeof(MOUQUEINFO);
+ cbParmList = 0;
+ break;
+
+ case MOU_GETSCALEFACTORS: /* Get Scaling Factor */
+
+ cbData = sizeof(SCALEFACT);
+ cbParmList = 0;
+ break;
+
+ case MOU_READEVENTQUE: /* Read Event Queue */
+
+ cbData = sizeof(MOUEVENTINFO);
+ cbParmList = 2;
+ break;
+
+ case MOU_REMOVEPTR: /* Remove Ptr */
+
+ cbData = 0;
+ cbParmList = sizeof(NOPTRRECT);
+ break;
+
+ case MOU_SCREENSWITCH: /* Screen Switch */
+
+ cbData = 0;
+ cbParmList = sizeof(SCREENGROUP);
+ break;
+
+ case MOU_SETEVENTMASK: /* Set Evenet Mask */
+
+ case MOU_SETHOTKEYBUTTON: /* Set Mouse Equivalent for the HotKey */
+
+ case MOU_SETMOUSTATUS: /* Set Mouse Status */
+
+ cbData = 0;
+ cbParmList = 2;
+ break;
+
+ case MOU_SETPROTDRAWADDRESS: /* Notified Mouse Device Drive Address */
+
+ cbData = 0;
+ cbParmList = sizeof(PTRDRAWFUNCTION);
+ break;
+
+ case MOU_SETPTRPOS: /* Set Mouse Position */
+
+ cbData = 0;
+ cbParmList = sizeof(PTRLOC);
+ break;
+
+ case MOU_SETPTRSHAPE: /* Set Mouse Shape */
+
+ cbData = 200; // BUGBUG ??
+ cbParmList = sizeof(PTRSHAPE);
+ break;
+
+ case MOU_SETREALDRAWADDRESS: /* Notified Mouse Device Drive Address */
+
+ cbData = 0;
+ cbParmList = sizeof(PTRDRAWFUNCTION);
+ break;
+
+ case MOU_SETSCALEFACTORS: /* Set Scaling Factor */
+
+ cbData = 0;
+ cbParmList = sizeof(SCALEFACT);
+ break;
+
+ case MOU_UPDATEDISPLAYMODE: /* New Display Mode */
+
+ cbData = 0;
+ cbParmList = sizeof(VIOMODEINFO);
+ break;
+
+ default:
+
+#if DBG
+ KdPrint((DosDevIOCtlNotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+ case IOCTL_MONITOR: /* MON : Character-Monitor Control */
+ switch (Function)
+ {
+ case MON_REGISTERMONITOR: /* Register a Monitor */
+
+ cbData = sizeof(MONITORPOSITION);
+ cbParmList = 1;
+ break;
+
+ default:
+
+#if DBG
+ KdPrint((DosDevIOCtlNotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+ case IOCTL_GENERAL: /* DEV : General Device Control */
+ switch (Function)
+ {
+ case DEV_FLUSHINPUT: /* flush the input buffer */
+ case DEV_FLUSHOUTPUT: /* flush the output buffer */
+ case DEV_QUERYMONSUPPORT: /* query for monitor support */
+
+ cbData = 0;
+ cbParmList = 1;
+ break;
+
+ default:
+
+#if DBG
+ KdPrint((DosDevIOCtlNotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+ case IOCTL_DISK: /* Disk/Diskette Control */
+
+ switch (Function) {
+
+ case DSK_LOCKDRIVE: /* Lock a drive */
+ case DSK_UNLOCKDRIVE: /* Unlock a drive */
+
+ cbData = 0;
+ cbParmList = 1;
+ break;
+
+ case DSK_SETLOGICALMAP: /* Set Logical Map */
+
+ cbData = 1;
+ cbParmList = 1;
+ break;
+
+ case DSK_BLOCKREMOVABLE:
+
+ cbData = 1;
+ cbParmList = 1;
+ break;
+
+ case DSK_GETLOGICALMAP:
+
+ cbData = 1;
+ cbParmList = 1;
+ break;
+
+ case DSK_GETDEVICEPARAMS:
+
+ cbData = sizeof(BIOSPARAMETERBLOCK);
+ cbParmList = 1;
+ break;
+
+ case DSK_SETDEVICEPARAMS:
+
+ cbData = sizeof(BIOSPARAMETERBLOCK);
+ cbParmList = 1;
+ break;
+
+ case DSK_READTRACK:
+ case DSK_WRITETRACK:
+ case DSK_VERIFYTRACK:
+
+ try {
+ Od2ProbeForRead(pvParmList, sizeof(TRACKLAYOUT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ {
+ PTRACKLAYOUT TL = (PTRACKLAYOUT) pvParmList;
+ ULONG l = (ULONG) TL->usFirstSector + (ULONG) TL->cSectors;
+
+ cbParmList = sizeof(*TL) +
+ ((l > 1) ?
+ ((l - 1) * 2 * sizeof(USHORT)) :
+ 0);
+ }
+
+ cbData = 0; // bogus -- will be computed later
+
+ break;
+
+ case DSK_FORMATVERIFY:
+
+ try {
+ Od2ProbeForRead(pvParmList, sizeof(TRACKFORMAT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ {
+ PTRACKFORMAT TF = (PTRACKFORMAT) pvParmList;
+ ULONG l = (ULONG) TF->cSectors;
+
+ cbParmList = sizeof(*TF) +
+ ((l > 1) ?
+ ((l - 1) * 4 * sizeof(BYTE)) :
+ 0);
+ }
+
+ cbData = 0;
+
+ break;
+
+ case DSK_REDETERMINEMEDIA:
+
+ cbData = 0;
+ cbParmList = 1;
+ break;
+
+
+ case 0x4:
+
+ cbParmList = 0;
+ cbData = 0;
+ break;
+
+ default:
+#if DBG
+ KdPrint((DosDevIOCtlNotValidStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_FUNCTION;
+ break;
+ }
+ break;
+
+ default:
+ // Check for User defined categories
+ if ((Category >= 0x80) && (Category <= 0xff)) {
+ cbData = 0;
+ cbParmList = 0;
+ break;
+ }
+ else {
+#if DBG
+ KdPrint((DosDevIOCtlNotImplementedYetStr, Category, Function));
+#endif
+ RetCode = ERROR_INVALID_CATEGORY;
+ }
+ break;
+ }
+
+ if (RetCode == NO_ERROR) {
+ RetCode = DosDevIOCtl2(pData, cbData, pParmList, cbParmList, Function, Category, hDev);
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ KdPrint(("DosDevIOCtl: Returned from DosDevIOCtl2(), retcode = %d\n", RetCode));
+ }
+#endif
+
+ return(RetCode);
+}
+
diff --git a/private/os2/client/dllkbd.c b/private/os2/client/dllkbd.c
new file mode 100644
index 000000000..cbde0616c
--- /dev/null
+++ b/private/os2/client/dllkbd.c
@@ -0,0 +1,2443 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllkbd.c
+
+Abstract:
+
+ This module implements 32 equivalents of OS/2 V1.21
+ KBD API Calls.
+ The APIs are called from 16->32 thunks (i386\doscalls.asm).
+
+Status :
+
+
+ KBDCHARIN
+ KBDPEEK
+ KBDSTRINGIN
+ KBDFLUSHBUFFER
+
+ KBDGETSTATUS
+ KBDSETSTATUS
+
+ KBDOPEN
+ KBDCLOSE
+ KBDGETFOCUS
+ KBDFREEFOCUS
+
+ KBDREGISTER - stubs
+ KBDDEREGISTER - stubs
+
+ KBDGETCP
+ KBDSETCP
+
+ KBDSETCUSTXT - stubs
+ KBDXLATE - stubs
+
+ KBDSETFGND
+ KBDSYNCH
+ KBDSHELLINIT
+ KBDGETHWID
+; KBDSETHWID
+; KBDSWITCHFGND
+; KBDLOADINSTANCE
+; KBDPROCESSINIT
+
+Author:
+
+ Yaron Shamir (YaronS) 07-June-1991
+ (stubs)
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "conrqust.h"
+#include "os2nls.h"
+#if PMNT
+#define INCL_32BIT
+#include "pmnt.h"
+#endif
+
+
+APIRET
+Od2KbdCheckHkbdAndFocus(
+ IN ULONG hKbd,
+ IN HANDLE *Handle
+#if DBG
+ ,IN PSZ FuncName
+#endif
+ );
+
+APIRET
+Od2KbdCheckHkbd(
+ IN ULONG hKbd,
+ OUT PFILE_HANDLE *hFileRecord,
+ IN BOOL ReleaseLock
+#if DBG
+ ,IN PSZ FuncName
+#endif
+ );
+
+#if DBG
+#define EXCEPTION_IN_KBD() \
+ { \
+ DbgPrint ("Exception in %s\n", FuncName); \
+ Od2ExitGP(); \
+ }
+
+#else
+#define EXCEPTION_IN_KBD() \
+ Od2ExitGP();
+
+#endif
+
+#if DBG
+#define KBD_SEND_LPC_REQUEST(Rc, Request, BufIn, hSem) \
+ IF_OD2_DEBUG(KBD) \
+ { \
+ DbgPrint("%s: Request %u\n", \
+ FuncName, Request.d.Kbd.Request); \
+ } \
+ \
+ Request.Request = KbdRequest; \
+ \
+ Rc = SendCtrlConsoleRequest(&Request, NULL, BufIn, hSem); \
+
+#else
+#define KBD_SEND_LPC_REQUEST(Rc, Request, BufIn, hSem) \
+ Request.Request = KbdRequest; \
+ \
+ Rc = SendCtrlConsoleRequest(&Request, NULL, BufIn, hSem); \
+
+#endif
+
+
+APIRET
+KbdFlushBuffer(IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdFlushBuffer";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx\n", FuncName, hKbd);
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdFlushBuffer()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDFlushBuffer;
+ Request.d.Kbd.hKbd = kHandle;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, KbdDataSemaphore);
+
+ /*
+ * handle return status
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ return(RetCode);
+ }
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdCharIn(OUT PKBDKEYINFO Info,
+ IN ULONG Wait,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdCharIn";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx(wait %s-%lx)\n",
+ FuncName, hKbd, (Wait == IO_WAIT) ? "Yes" : "No", Wait);
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdCharIn()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForWrite(Info, sizeof(KBDKEYINFO), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_KBD()
+ }
+
+ if ((Wait != IO_WAIT) && (Wait != IO_NOWAIT))
+ {
+ return ERROR_KBD_INVALID_IOWAIT;
+ }
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDCharIn;
+ Request.d.Kbd.hKbd = kHandle;
+ Request.d.Kbd.fWait = Wait;
+ Request.d.Kbd.Length = 0;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, KbdDataSemaphore);
+ /*
+ * handle return status (get char info if successed)
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ return(RetCode);
+ }
+
+ *Info = Request.d.Kbd.d.KeyInfo;
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: Char %x, Scan %x\n",
+ FuncName, Info->chChar, Info->chScan );
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdPeek(OUT PKBDKEYINFO Info,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdPeek";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx\n", FuncName, hKbd);
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdPeek()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForWrite(Info, sizeof(KBDKEYINFO), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_KBD()
+ }
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDPeek;
+ Request.d.Kbd.hKbd = kHandle;
+ Request.d.Kbd.Length = 0;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, KbdDataSemaphore);
+
+ /*
+ * handle return status (get char info if successed)
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+
+ return(RetCode);
+ }
+
+ *Info = Request.d.Kbd.d.KeyInfo;
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: Char %x, Scan %x\n",
+ FuncName, Info->chChar, Info->chScan );
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdStringIn(OUT PCH Buffer,
+ IN OUT PSTRINGINBUF Length,
+ IN ULONG Wait,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdStringIn";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx(wait %s-%lx, length %lx)\n",
+ FuncName, hKbd, (Wait == IO_WAIT) ? "Yes" : "No", Wait, Length->cb);
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdStringIn()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForWrite(Length, sizeof(STRINGINBUF), 1);
+ Od2ProbeForWrite(Buffer, Length->cb, 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_KBD()
+ }
+
+ if ((Wait != IO_WAIT) && (Wait != IO_NOWAIT))
+ {
+ return ERROR_KBD_INVALID_IOWAIT;
+ }
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ if ( Length->cb > OS2_KBD_PORT_MSG_SIZE )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: String too long %lx\n", FuncName, *Length);
+#endif
+
+ return ERROR_KBD_PARAMETER;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Length = (ULONG)Length->cb;
+ Request.d.Kbd.d.String = *Length;
+ Request.d.Kbd.Request = KBDStringIn;
+ Request.d.Kbd.hKbd = kHandle;
+ Request.d.Kbd.fWait = Wait;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, Buffer, KbdDataSemaphore);
+
+ /*
+ * handle return status (get string info if successed)
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ return(RetCode);
+ }
+
+ Length->cchIn = (USHORT)Request.d.Kbd.d.String.cchIn;
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: Length %u, String %x, ...\n",
+ FuncName, Length->cchIn, *Buffer );
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdGetStatus(IN OUT PKBDINFO KbdInfo,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdGetStatus";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx, Length %u\n",
+ FuncName, hKbd, KbdInfo->cb);
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdGetStatus()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForWrite(KbdInfo, sizeof(KBDINFO), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_KBD()
+ }
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+
+ if (RetCode != NO_ERROR)
+ {
+ return ((RetCode == ERROR_INVALID_HANDLE) ? ERROR_KBD_INVALID_HANDLE : RetCode);
+ }
+
+ if (KbdInfo->cb < sizeof(KBDINFO))
+ {
+ return ERROR_KBD_INVALID_LENGTH;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDGetStatus;
+ Request.d.Kbd.hKbd = kHandle;
+ Request.d.Kbd.d.KbdInfo = *KbdInfo;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status (get status info if successed)
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+
+ return RetCode ;
+ }
+
+ *KbdInfo = Request.d.Kbd.d.KbdInfo;
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: Mask %x, Char %x, Interim %x, State %x\n",
+ FuncName, KbdInfo->fsMask, KbdInfo->chTurnAround,
+ KbdInfo->fsInterim, KbdInfo->fsState);
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdSetStatus(IN OUT PKBDINFO KbdInfo,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdSetStatus";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx, Mask %x, Char %x, Interim %x, State %x\n",
+ FuncName, hKbd, KbdInfo->fsMask, KbdInfo->chTurnAround,
+ KbdInfo->fsInterim, KbdInfo->fsState);
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdSetStatus()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForRead(KbdInfo, sizeof(KBDINFO), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_KBD()
+ }
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ if (KbdInfo->cb != sizeof(KBDINFO))
+ {
+ return ERROR_KBD_INVALID_LENGTH;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDSetStatus;
+ Request.d.Kbd.hKbd = kHandle;
+ Request.d.Kbd.d.KbdInfo = *KbdInfo;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+
+ return(RetCode);
+ }
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdGetFocus( IN ULONG Wait,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ LARGE_INTEGER TimeOut;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdGetFocus";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx(wait %s-%lx)\n",
+ FuncName, hKbd, (Wait == IO_WAIT) ? "Yes" : "No", Wait);
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdGetFocus()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+// #ifdef DBCS
+// MSKK Oct.11.1993 V-AkihiS
+// KbdGetFocus of MS OS/2 V1.21 doesn't check Wait parameter legalty.
+// It uses bit #0 of Wait parameter.
+ /*
+ * get bit #0 of Wait parameter.
+ */
+ Wait &= IO_NOWAIT;
+//#else
+ /*
+ * check parameter legalty
+ */
+
+// if ((Wait != IO_WAIT) && (Wait != IO_NOWAIT))
+// {
+// return ERROR_KBD_INVALID_IOWAIT;
+// }
+//#endif
+
+ RetCode = Od2KbdCheckHkbd(hKbd,
+ &hFileRecord,
+ (BOOL)TRUE
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ if (hKbd == SesGrp->KbdInFocus)
+ {
+ return(ERROR_KBD_FOCUS_ALREADY_ACTIVE);
+ }
+
+ /*
+ * catch kbdFocus semaphore
+ */
+
+ TimeOut.LowPart = 0L;
+ TimeOut.HighPart = 0L;
+
+ RetCode = Od2WaitForSingleObject( FocusSemaphore,
+ (BOOLEAN)TRUE,
+ ((Wait == IO_WAIT) ? NULL : &TimeOut));
+
+ if ( RetCode )
+ {
+ return(ERROR_KBD_UNABLE_TO_FOCUS);
+ }
+
+ SesGrp->KbdInFocus = hKbd;
+ SesGrp->NoKbdFocus = FALSE;
+
+ /* BUGBUG=> check HKBD again
+#if DBG
+ DbgPrint ("%s: hKbd was releasd while waiting for focus\n",
+ FuncName);
+#endif
+ return ERROR_KBD_INVALID_HANDLE; */
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDNewFocus;
+ Request.d.Kbd.hKbd = hFileRecord->NtHandle;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status (release semaphore if failed)
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ SesGrp->KbdInFocus = 0;
+ SesGrp->NoKbdFocus = TRUE;
+ NtReleaseSemaphore (FocusSemaphore,
+ 1,
+ NULL);
+ return(ERROR_KBD_UNABLE_TO_FOCUS);
+ }
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdFreeFocus( IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdFreeFocus";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx\n", FuncName, hKbd);
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdFreeFocus()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDFreeFocus;
+ Request.d.Kbd.hKbd = kHandle;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status
+ */
+
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+
+ SesGrp->KbdInFocus = 0;
+ SesGrp->NoKbdFocus = TRUE;
+ NtReleaseSemaphore (FocusSemaphore,
+ 1,
+ NULL);
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdClose( IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdClose";
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx\n", FuncName, hKbd);
+ }
+
+#endif
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdClose()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ RetCode = Od2KbdCheckHkbd(hKbd,
+ &hFileRecord,
+ (BOOL)FALSE
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ Request.d.Kbd.hKbd = hFileRecord->NtHandle;
+ InvalidateHandle(hFileRecord);
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDClose;
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status
+ */
+
+ if ( RetCode )
+ {
+ // BUGBUG=> what could happend ?
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ }
+
+ AcquireFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+ FreeHandle((HFILE)hKbd);
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdOpen( OUT PUSHORT hKbd)
+{
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ HFILE hFile;
+ HANDLE Handle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdOpen";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering\n", FuncName);
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdOpen()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForWrite(hKbd, sizeof(USHORT), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_KBD()
+ }
+
+ //
+ // Allocate an Os2 Handle
+ //
+
+ AcquireFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ RetCode = AllocateHandle(&hFile);
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: unable to allocate FileHandle\n", FuncName);
+ }
+#endif
+
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ RetCode = KbdOpenLogHandle(&Handle);
+
+ AcquireFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * handle return status (free handle if failed, validate if successed)
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+
+ FreeHandle(hFile);
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+ return(RetCode);
+ }
+
+ hFileRecord = DereferenceFileHandleNoCheck(hFile);
+ hFileRecord->NtHandle = Handle;
+ hFileRecord->Flags |= FHT_CHRDEV;
+ hFileRecord->DeviceAttribute = DEVICE_ATTRIBUTE_STDIN | DEVICE_ATTRIBUTE_NUL;
+ hFileRecord->FileType = FILE_TYPE_DEV;
+ hFileRecord->IoVectorType = KbdVectorType;
+
+ //
+ // validate file handle
+ //
+
+ ValidateHandle(hFileRecord);
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ *hKbd = (USHORT)hFile;
+
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: returns %lx\n", FuncName, *hKbd);
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdDeRegister()
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdDeRegister";
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdDeRegister()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+KbdRegister( IN PSZ pszModuleName,
+ IN PSZ pszEntryName,
+ IN ULONG fFunctions)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdRegister";
+#endif
+
+ UNREFERENCED_PARAMETER(pszModuleName);
+ UNREFERENCED_PARAMETER(pszEntryName);
+ UNREFERENCED_PARAMETER(fFunctions);
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdRegister()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+KbdGetCp( IN ULONG usReserved,
+ OUT PUSHORT pIdCodePage,
+ IN ULONG hKbd)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdGetCp";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: hKbd %lx\n", FuncName, hKbd);
+ }
+
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdGetCp()()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ if (usReserved)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pIdCodePage, sizeof(USHORT), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_KBD()
+ }
+
+ return(KbdGetCpId(pIdCodePage, hKbd));
+}
+
+
+APIRET
+KbdSetCp( IN ULONG usReserved,
+ IN ULONG idCodePage,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdSetCp";
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: hKbd %lx, CP %lu\n", FuncName, hKbd, idCodePage);
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdSetCp()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ if (usReserved)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+#ifdef DBCS
+// MSKK Apr.15.1993 V-AkihiS
+// allow code page = 0
+ if (( idCodePage != 0 ) &&
+ ( idCodePage != SesGrp->PrimaryCP ) &&
+ ( idCodePage != SesGrp->SecondaryCP ))
+#else
+ if (( idCodePage == 0 ) ||
+ (( idCodePage != SesGrp->PrimaryCP ) &&
+ ( idCodePage != SesGrp->SecondaryCP )))
+#endif
+ {
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: invalid CP %lu\n", idCodePage);
+ }
+#endif
+ return (ERROR_KBD_INVALID_CODEPAGE);
+ }
+
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.d.CodePage = idCodePage;
+ Request.d.Kbd.Request = KBDSetCp;
+ Request.d.Kbd.hKbd = kHandle;
+ Request.d.Kbd.d.CodePage = idCodePage;
+
+ KBD_SEND_LPC_REQUEST(RetCode , Request, NULL, NULL);
+
+ /*
+ * handle return status
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+
+ return(RetCode);
+ }
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdSetCustXt( IN PUSHORT pusTransTbl,
+ IN ULONG hKbd)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdSetCustXt";
+#endif
+
+ UNREFERENCED_PARAMETER(pusTransTbl);
+ UNREFERENCED_PARAMETER(hKbd);
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdSetCustXt()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+KbdXlate( IN OUT PVOID pkbxlKeyStroke,
+ IN ULONG hKbd)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdXlate";
+#endif
+
+ UNREFERENCED_PARAMETER(pkbxlKeyStroke);
+ UNREFERENCED_PARAMETER(hKbd);
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdXlate()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+KbdGetHWID( OUT PKBDHWID pkbdhwid,
+ IN ULONG hKbd)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdGetHWID";
+#endif
+
+ UNREFERENCED_PARAMETER(pkbdhwid);
+ UNREFERENCED_PARAMETER(hKbd);
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdGetHWID()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+KbdRead(IN PFILE_HANDLE hFileRecord,
+ OUT PCH Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead,
+ IN KBDREQUESTNUMBER RequestType)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdRead";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx(length %lx)\n",
+ FuncName, hFileRecord, Length);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ if (!SesGrp->NoKbdFocus)
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint ("%s: other hKbd in focus\n", FuncName);
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ FuncName
+ #endif
+ );
+ return ERROR_KBD_FOCUS_REQUIRED;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ //
+ // Addjust the buffer length so that it wont overflows. We don't have to
+ // return with an error. (t-eyala. Feb 94)
+ //
+
+ Request.d.Kbd.Length = (Length > OS2_KBD_PORT_MSG_SIZE ? OS2_KBD_PORT_MSG_SIZE : Length);
+
+// if ( Request.d.Kbd.Length > OS2_KBD_PORT_MSG_SIZE )
+// {
+//#if DBG
+// IF_OD2_DEBUG( KBD )
+// DbgPrint("%s: read %lx too long\n", FuncName, Length);
+//#endif
+// ReleaseFileLockShared(
+// #if DBG
+// FuncName
+// #endif
+// );
+// return ERROR_KBD_PARAMETER;
+// }
+
+ Request.d.Kbd.Request = RequestType;
+ Request.d.Kbd.hKbd = (HANDLE)SesGrp->PhyKbd;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, Buffer, KbdDataSemaphore);
+
+ /*
+ * handle return status (get string info if successed)
+ */
+
+ ReleaseFileLockShared(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ return(RetCode);
+ }
+
+ *BytesRead = Request.d.Kbd.Length;
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdGetCpId( OUT PUSHORT pIdCodePage,
+ IN ULONG hKbd)
+{
+// SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdGetCpId";
+#endif
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+// Request.d.Kbd.Request = KBDGetCp;
+// Request.d.Kbd.hKbd = kHandle;
+//
+// KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+//
+// /*
+// * handle return status
+// */
+//
+// if ( RetCode )
+// {
+#if DBG
+// IF_OD2_DEBUG( KBD )
+// DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+// return(RetCode);
+// }
+//
+// *pIdCodePage = Request.d.Kbd.d.CodePage;
+
+ *pIdCodePage = (USHORT)SesGrp->KbdCP ;
+
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: hKbd %lx, Cp %u\n", FuncName, hKbd, *pIdCodePage);
+ }
+#endif
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+KbdGetInputMode(OUT PBYTE pInputMode,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdGetInputMode";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx\n", FuncName, hKbd);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDGetInputMode;
+ Request.d.Kbd.hKbd = kHandle;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status (get status info if successed)
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ return(RetCode);
+ }
+
+ *pInputMode = (BYTE)Request.d.Kbd.d.InputMode;
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: Mode %x\n",
+ FuncName, *pInputMode );
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdGetInterimFlag(OUT PBYTE pInterimFlag,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdGetInTerimFlag";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx\n", FuncName, hKbd);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDGetInterimFlag;
+ Request.d.Kbd.hKbd = kHandle;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status (get status info if successed)
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ return(RetCode);
+ }
+
+ *pInterimFlag = (BYTE)Request.d.Kbd.d.Interim;
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: Flag %x\n",
+ FuncName, *pInterimFlag );
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdGetKbdType(OUT PUSHORT pKbdType,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdGetKbdType";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx\n", FuncName, hKbd);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDGetKbdType;
+ Request.d.Kbd.hKbd = kHandle;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status (get status info if successed)
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ return(RetCode);
+ }
+
+#ifdef JAPAN
+// MSKK May.07.1993 V-AkihiS
+ ((PKBDTYPE)pKbdType)->usType = Request.d.Kbd.d.KbdType[0];
+ ((PKBDTYPE)pKbdType)->reserved1 = Request.d.Kbd.d.KbdType[1];
+ ((PKBDTYPE)pKbdType)->reserved2 = Request.d.Kbd.d.KbdType[2];
+#else
+ *pKbdType = Request.d.Kbd.d.KbdType;
+#endif
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: Type %x\n",
+ FuncName, *pKbdType );
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdGetHotKey(IN PUSHORT pParm,
+ OUT PBYTE pHotKey,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdGetHotKey";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx\n", FuncName, hKbd);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDGetHotKey;
+ Request.d.Kbd.hKbd = kHandle;
+ *((PUSHORT)&Request.d.Kbd.d.HotKey[0]) = *pParm;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status (get status info if successed)
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ return(RetCode);
+ }
+
+ *pParm = *((PUSHORT)&Request.d.Kbd.d.HotKey[0]);
+ RtlMoveMemory(pHotKey, &Request.d.Kbd.d.HotKey[2], sizeof(Request.d.Kbd.d.HotKey) - 2);
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: Parm %x, HotKey %x,%x,%x,%x,%x,%x\n",
+ FuncName, *pParm, pHotKey[0], pHotKey[1], pHotKey[2],
+ pHotKey[3], pHotKey[4], pHotKey[5] );
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdGetShiftState(OUT PBYTE pvData,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdGetShiftState";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx\n", FuncName, hKbd);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDGetShiftState;
+ Request.d.Kbd.hKbd = kHandle;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status (get status info if successed)
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ return(RetCode);
+ }
+
+ RtlMoveMemory(pvData, &Request.d.Kbd.d.Shift, sizeof(SHIFTSTATE));
+
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: returns State %u, NlsState %u\n",
+ FuncName, ((PSHIFTSTATE)pvData)->fsState,
+ ((PSHIFTSTATE)pvData)->fNLS);
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdSetInputMode(IN BYTE InputMode,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdSetInputMode";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx, Mode %x\n",
+ FuncName, hKbd, InputMode);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDSetInputMode;
+ Request.d.Kbd.hKbd = kHandle;
+ Request.d.Kbd.d.InputMode = (UCHAR)InputMode;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ return(RetCode);
+ }
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdSetInterimFlag(IN BYTE InterimFlag,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdSetInTerimFlag";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx, Flag %x\n",
+ FuncName, hKbd, InterimFlag);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDSetInTerimFlag;
+ Request.d.Kbd.hKbd = kHandle;
+ Request.d.Kbd.d.Interim = (UCHAR)InterimFlag;
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ return(RetCode);
+ }
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdSetShiftState(OUT PBYTE Shift,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdSetShiftState";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx, State %u, NlsState %u\n",
+ FuncName, hKbd, ((PSHIFTSTATE)Shift)->fsState,
+ ((PSHIFTSTATE)Shift)->fNLS);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDSetShiftState;
+ Request.d.Kbd.hKbd = kHandle;
+ RtlMoveMemory(&Request.d.Kbd.d.Shift, Shift, sizeof(SHIFTSTATE));
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ return(RetCode);
+ }
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdSetTypamaticRate(IN PBYTE pRateDelay,
+ IN ULONG hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ HANDLE kHandle;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdSetTypamaticRate";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: entering with %lx, Delay %u, rate %u\n",
+ FuncName, hKbd, ((PRATEDELAY)pRateDelay)->usDelay,
+ ((PRATEDELAY)pRateDelay)->usRate);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ RetCode = Od2KbdCheckHkbdAndFocus(hKbd,
+ &kHandle
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDSetTypamaticRate;
+ Request.d.Kbd.hKbd = kHandle;
+ RtlMoveMemory(&Request.d.Kbd.d.RateDelay, pRateDelay, sizeof(RATEDELAY));
+
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint("%s: status %lx\n", FuncName, RetCode);
+#endif
+ return(RetCode);
+ }
+
+ return NO_ERROR;
+}
+
+
+APIRET
+KbdSetFgnd(IN ULONG hKbd)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdSetFgnd";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: hKbd %lx\n", FuncName, hKbd);
+ }
+
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdSetFgnd()\n");
+#endif
+ return(ERROR_KBD_KEYBOARD_BUSY);
+ }
+#endif
+
+ return (ERROR_KBD_SMG_ONLY);
+}
+
+
+APIRET
+KbdSynch(IN ULONG fWait)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdSynch";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: Wait %s-%lx\n",
+ FuncName, ( fWait == IO_WAIT ) ? "Yes" : "No", fWait);
+ }
+
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call KbdSynch()\n");
+#endif
+ return(ERROR_KBD_EXTENDED_SG);
+ }
+#endif
+
+ return (ERROR_KBD_SMG_ONLY);
+}
+
+
+APIRET
+KbdShellInit()
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdShellInit";
+
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: calleds\n", FuncName );
+ }
+
+#endif
+
+ return (ERROR_KBD_SMG_ONLY);
+}
+
+
+APIRET
+KbdOpenLogHandle( OUT PHANDLE hKbd)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "KbdOpenLogHandle";
+#endif
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Kbd.Request = KBDOpen;
+ KBD_SEND_LPC_REQUEST(RetCode, Request, NULL, NULL);
+
+ /*
+ * handle return status (free handle if failed, validate if successed)
+ */
+
+
+ *hKbd = (HANDLE) Request.d.Kbd.hKbd;
+
+ return(RetCode);
+}
+
+
+APIRET
+Od2KbdCheckHkbdAndFocus(
+ IN ULONG hKbd,
+ IN HANDLE *Handle
+#if DBG
+ ,IN PSZ FuncName
+#endif
+ )
+{
+ APIRET RetCode = NO_ERROR;
+ PFILE_HANDLE hFileRecord;
+
+ if (!hKbd)
+ {
+ if (!SesGrp->NoKbdFocus)
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint ("%s: hKbd not in focus\n", FuncName);
+#endif
+ return ERROR_KBD_FOCUS_REQUIRED;
+ }
+
+ *Handle = SesGrp->PhyKbd;
+
+ return(NO_ERROR);
+
+ }
+
+ RetCode = Od2KbdCheckHkbd(hKbd,
+ &hFileRecord,
+ (BOOL)FALSE
+ #if DBG
+ ,FuncName
+ #endif
+ );
+
+ if (RetCode != NO_ERROR)
+ {
+ return RetCode;
+ }
+
+ if (!SesGrp->NoKbdFocus && (SesGrp->KbdInFocus != hKbd) ||
+ (SesGrp->NoKbdFocus && (hFileRecord->NtHandle != SesGrp->PhyKbd)))
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ DbgPrint ("%s: hKbd not in focus\n", FuncName);
+#endif
+ RetCode = ERROR_KBD_FOCUS_REQUIRED;
+ }
+
+ *Handle = hFileRecord->NtHandle;
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ return(RetCode);
+
+}
+
+
+APIRET
+Od2KbdCheckHkbd(
+ IN ULONG hKbd,
+ OUT PFILE_HANDLE *hFileRecord,
+ IN BOOL ReleaseLock
+#if DBG
+ ,IN PSZ FuncName
+#endif
+ )
+{
+ APIRET RetCode = NO_ERROR;
+ PFILE_HANDLE FileRecord;
+
+ AcquireFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+ try
+ {
+ RetCode = DereferenceFileHandle((HFILE)hKbd, &FileRecord);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+ EXCEPTION_IN_KBD()
+ }
+
+ if ((RetCode != NO_ERROR) ||
+ (FileRecord->IoVectorType != KbdVectorType))
+ {
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ DbgPrint("%s: illegal FileHandle\n", FuncName);
+ }
+#endif
+ if (RetCode)
+ return RetCode;
+ else
+ //return ERROR_KBD_INVALID_HANDLE;
+ return ERROR_KBD_FOCUS_REQUIRED;
+ }
+
+ *hFileRecord = FileRecord;
+
+ if (ReleaseLock)
+ {
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ }
+ return(RetCode);
+}
+
+
diff --git a/private/os2/client/dllldr16.c b/private/os2/client/dllldr16.c
new file mode 100644
index 000000000..2da53ff96
--- /dev/null
+++ b/private/os2/client/dllldr16.c
@@ -0,0 +1,1107 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllldr16.c
+
+Abstract:
+
+ This module implements 32 equivalents of OS/2 V2.0 Loader
+ API Calls. These are called from 16->32 thunks (i386\doscalls.asm).
+
+
+Author:
+
+ Yaron Shamir (YaronS) 22-Apr-1991
+
+Revision History:
+
+--*/
+
+#include <stdlib.h>
+#include <string.h>
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "os2tile.h"
+#include <mi.h>
+#include <ldrxport.h>
+#ifdef DBCS
+// MSKK Apr.19.1993 V-AkihiS
+//
+// OS/2 internal multibyte string function.
+//
+#include "dlldbcs.h"
+#define strpbrk Od2MultiByteStrpbrk
+#define strchr Od2MultiByteStrchr
+#define strrchr Od2MultiByteStrrchr
+#endif
+
+extern int DosScanEnv(PSZ pszValName, PSZ *ppresult);
+extern ldrlibi_t InitRecords[MAX_INIT_RECORDS];
+extern ULONG Od2EnvCommandOffset;
+extern ULONG GetFlatAddrOf16BitStack();
+extern CHAR ResourceUsage[LDT_DISJOINT_ENTRIES];
+#if DBG
+extern USHORT Os2DebugSel;
+#endif
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 260
+#endif
+
+BOOLEAN
+Od2ExpandOd2LibPathElements(
+ OUT PCHAR ExpandedString,
+ IN ULONG MaxSize
+ )
+{
+ PCHAR TmpPtr;
+ PCHAR CurPathElement;
+ PCHAR EndOfOd2LibPath;
+ ULONG SizeCounter = 0;
+ ULONG Size;
+ ULONG FileFlags;
+ ULONG FileType;
+ APIRET RetCode;
+ STRING CanonicalPathElement;
+ CHAR PathElement[128];
+
+ ExpandedString[0] = '\0';
+ CurPathElement = strchr(Od2LibPath, '='); // skip the Os2LibPath= string
+ if (CurPathElement == NULL) {
+ CurPathElement = Od2LibPath;
+ }
+ else {
+ CurPathElement++; // In order to include the '='
+ }
+ EndOfOd2LibPath = Od2LibPath + Od2LibPathLength;
+ while (CurPathElement < EndOfOd2LibPath) {
+ TmpPtr = strchr(CurPathElement, ';');
+ if (TmpPtr == NULL) {
+ Size = strlen(CurPathElement);
+ if (Size == 0) {
+ break;
+ }
+ }
+ else {
+ Size = TmpPtr - CurPathElement;
+ if (Size == 0) {
+ CurPathElement++;
+ continue;
+ }
+ }
+ if (Size >= sizeof(PathElement)) {
+ // skip this path element - it is too big to handle
+ CurPathElement += Size + 1;
+ continue;
+ }
+ RtlMoveMemory(PathElement, CurPathElement, Size);
+ PathElement[Size] = '\0';
+ CurPathElement += Size + 1;
+
+ RetCode = Od2Canonicalize(PathElement,
+ CANONICALIZE_FILE_OR_DEV,
+ &CanonicalPathElement,
+ NULL,
+ &FileFlags,
+ &FileType
+ );
+ if (RetCode == NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("canonicalize returned %s\n",CanonicalPathElement.Buffer);
+ }
+#endif
+ if (SizeCounter != 0) {
+ if ((SizeCounter + CanonicalPathElement.Length + 1) >= MaxSize) {
+ return(FALSE);
+ }
+ ExpandedString[SizeCounter++] = ';';
+ }
+ else {
+ if (SizeCounter + CanonicalPathElement.Length >= MaxSize) {
+ return(FALSE);
+ }
+ }
+ RtlMoveMemory(&ExpandedString[SizeCounter], CanonicalPathElement.Buffer,
+ CanonicalPathElement.Length);
+ SizeCounter += CanonicalPathElement.Length;
+ ExpandedString[SizeCounter] = '\0';
+ RtlFreeHeap(Od2Heap, 0, CanonicalPathElement.Buffer);
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2ExpandOs2LibPathElements: Od2Canonicalize returned %d\n", RetCode);
+ }
+#endif
+ }
+ }
+ return(TRUE);
+}
+
+
+BOOLEAN
+Od2ExpandPathElements(
+ IN PSZ PathPtr,
+ OUT PCHAR ExpandedString,
+ IN ULONG MaxSize
+ )
+{
+ PCHAR TmpPtr;
+ PCHAR CurPathElement;
+ PCHAR EndOfPath;
+ ULONG SizeCounter;
+ ULONG Size;
+ ULONG FileFlags;
+ ULONG FileType;
+ APIRET RetCode;
+ STRING CanonicalPathElement;
+ CHAR PathElement[CCHMAXPATH+14]; // 14 is for '\OS2SS\DRIVES\'
+
+ ExpandedString[0] = '\0';
+ //
+ // First thing to do is to add the current directory to the search PATH
+ //
+ RetCode = Od2Canonicalize(".",
+ CANONICALIZE_FILE_OR_DEV,
+ &CanonicalPathElement,
+ NULL,
+ &FileFlags,
+ &FileType
+ );
+ if (RetCode == NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("OS2: canonicalize . returned %s\n",CanonicalPathElement.Buffer);
+ }
+#endif
+ if (CanonicalPathElement.Length >= MaxSize) {
+ return(FALSE);
+ }
+ RtlMoveMemory(ExpandedString, CanonicalPathElement.Buffer,
+ CanonicalPathElement.Length);
+ SizeCounter = CanonicalPathElement.Length;
+ ExpandedString[SizeCounter] = '\0';
+ RtlFreeHeap(Od2Heap, 0, CanonicalPathElement.Buffer);
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("OS2: Od2ExpandPathElements: Od2Canonicalize returned %d\n", RetCode);
+ }
+#endif
+ return(FALSE);
+ }
+
+ CurPathElement = PathPtr;
+ EndOfPath = PathPtr + strlen(PathPtr);
+ while (CurPathElement < EndOfPath) {
+ TmpPtr = strchr(CurPathElement, ';');
+ if (TmpPtr == NULL) {
+ Size = strlen(CurPathElement);
+ if (Size == 0) {
+ break;
+ }
+ }
+ else {
+ Size = TmpPtr - CurPathElement;
+ if (Size == 0) {
+ CurPathElement++;
+ continue;
+ }
+ }
+ if (Size >= sizeof(PathElement)) {
+ // skip this path element - it is too big to handle
+ CurPathElement += Size + 1;
+ continue;
+ }
+ RtlMoveMemory(PathElement, CurPathElement, Size);
+ PathElement[Size] = '\0';
+ CurPathElement += Size + 1;
+
+ RetCode = Od2Canonicalize(PathElement,
+ CANONICALIZE_FILE_OR_DEV,
+ &CanonicalPathElement,
+ NULL,
+ &FileFlags,
+ &FileType
+ );
+ if (RetCode == NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("OS2: canonicalize returned %s\n",CanonicalPathElement.Buffer);
+ }
+#endif
+ if ((SizeCounter + CanonicalPathElement.Length + 1) >= MaxSize) {
+ return(FALSE);
+ }
+ ExpandedString[SizeCounter++] = ';';
+ RtlMoveMemory(&ExpandedString[SizeCounter], CanonicalPathElement.Buffer,
+ CanonicalPathElement.Length);
+ SizeCounter += CanonicalPathElement.Length;
+ ExpandedString[SizeCounter] = '\0';
+ RtlFreeHeap(Od2Heap, 0, CanonicalPathElement.Buffer);
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("OS2: Od2ExpandPathElements: Od2Canonicalize returned %d\n", RetCode);
+ }
+#endif
+ }
+ }
+//#if DBG
+// KdPrint(("The search PATH is: %s\n", ExpandedString));
+//#endif
+ return(TRUE);
+}
+
+
+APIRET
+DosLoadModuleNE(
+ IN PCHAR pszFailName,
+ IN ULONG cbFailName,
+ IN PCHAR pszModName,
+ OUT PUSHORT phMod
+ )
+{
+ APIRET Rc;
+ OS2_API_MSG m;
+ P_LDRLOADMODULE_MSG a = &m.u.LdrLoadModule;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ STRING ModuleNameString;
+ STRING FailNameString;
+ STRING LibPathNameString;
+ // Remember that \OS2SS\DRIVES\ is added for each path element !
+ // Let's assume the smallest component is 5 chars long (like C:\X;)
+ // (although it could be less, like "." or "\")
+ // => we need to add 14 * (MAXPATHLEN/5) = MAXPATHLEN*3
+ CHAR ExpandedLibPath[MAXPATHLEN*4];
+ BOOLEAN MemAllocatedForModName;
+ ULONG FileFlags;
+ ULONG FileType;
+ ULONG Len;
+ ldrrei_t exec_info;
+ ldrrei_t *pexec_info = &exec_info;
+ ULONG NumOfInitRecords;
+ ULONG i;
+ ULONG RetCode;
+ ULONG FlatAddrOf16BitStack;
+
+ //
+ // Very tricky code. The EBX holds the flat address of the
+ // stack of the current running thread. This value is used by
+ // the init routine of the newly loaded DLL if it has no
+ // stack of its own. The EBX is initialized in client\i386\doscalls.asm
+ //
+ //_asm { mov FlatAddrOf16BitStack, ebx };
+ FlatAddrOf16BitStack = GetFlatAddrOf16BitStack();
+
+ //
+ // probe phmod pointer.
+ //
+
+ try {
+ Od2ProbeForWrite(phMod, sizeof(USHORT), 1);
+ if ((pszFailName != NULL) && (cbFailName > 0)) {
+ pszFailName[0] = 0;
+ pszFailName[cbFailName - 1] = 0;
+ }
+ Len = strlen(pszModName);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (Len > 2) {
+ if (pszModName[1] == ':') {
+ if (Len >= CCHMAXPATH) {
+ //
+ // Check for any meta characters
+ //
+ if (strpbrk(pszModName, "*?") != NULL)
+ return(ERROR_INVALID_NAME);
+ else
+ return(ERROR_FILE_NOT_FOUND);
+ }
+ }
+ else {
+ if (Len >= (CCHMAXPATH-2)) {
+ //
+ // Store Modulename string to pszFailName
+ //
+ if ((pszFailName != NULL) && (cbFailName > 0)) {
+ Len = min(Len, cbFailName - 1);
+ RtlMoveMemory(pszFailName, pszModName, Len);
+ pszFailName[Len] = '\0';
+ }
+
+ //
+ // Check for any meta characters
+ //
+ if (strpbrk(pszModName, "*?") != NULL)
+ return(ERROR_INVALID_NAME);
+ else
+ return(ERROR_FILE_NOT_FOUND);
+ }
+ }
+ }
+
+ //
+ // Check for any meta characters
+ //
+ if (strpbrk(pszModName, "*?") != NULL) {
+ //
+ // Store Modulename string to pszFailName
+ //
+ if ((pszFailName != NULL) && (cbFailName > 0)) {
+ Len = min(Len, cbFailName - 1);
+ RtlMoveMemory(pszFailName, pszModName, Len);
+ pszFailName[Len] = '\0';
+ }
+ return(ERROR_INVALID_NAME);
+ }
+
+ if ((strchr(pszModName, '.') != NULL) &&
+ (strpbrk(pszModName, "\\/") == NULL)
+ ) {
+ if ((pszFailName != NULL) && (cbFailName > 0)) {
+ Len = min(Len, cbFailName - 1);
+ RtlMoveMemory(pszFailName, pszModName, Len);
+ pszFailName[Len] = '\0';
+ }
+ return(ERROR_FILE_NOT_FOUND);
+ }
+
+ if (strpbrk(pszModName, ":\\/.") == NULL) {
+ RtlInitString(&ModuleNameString, pszModName);
+ MemAllocatedForModName = FALSE;
+ }
+ else {
+ Rc = Od2Canonicalize(pszModName,
+ CANONICALIZE_FILE_OR_DEV,
+ &ModuleNameString,
+ NULL,
+ &FileFlags,
+ &FileType
+ );
+ if (Rc != NO_ERROR) {
+ return(Rc);
+ }
+ MemAllocatedForModName = TRUE;
+ }
+
+ FailNameString.Buffer = NULL;
+ FailNameString.Length = 0;
+ FailNameString.MaximumLength = (USHORT)cbFailName;
+ if (FailNameString.MaximumLength == 0) {
+ FailNameString.MaximumLength++;
+ }
+
+ Od2ExpandOd2LibPathElements(ExpandedLibPath, sizeof(ExpandedLibPath));
+ RtlInitString(&LibPathNameString, ExpandedLibPath);
+
+ CaptureBuffer = Od2AllocateCaptureBuffer(
+ 4,
+ 0,
+ ModuleNameString.MaximumLength +
+ FailNameString.MaximumLength +
+ LibPathNameString.MaximumLength +
+ MAX_INIT_RECORDS * sizeof(ldrlibi_t)
+ );
+ if (CaptureBuffer == NULL) {
+ if (MemAllocatedForModName) {
+ RtlFreeHeap(Od2Heap, 0, ModuleNameString.Buffer);
+ }
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ Od2CaptureMessageString( CaptureBuffer,
+ ModuleNameString.Buffer,
+ ModuleNameString.Length,
+ ModuleNameString.MaximumLength,
+ &a->ModuleName
+ );
+ if (MemAllocatedForModName) {
+ RtlFreeHeap(Od2Heap, 0, ModuleNameString.Buffer);
+ }
+
+ Od2CaptureMessageString( CaptureBuffer,
+ FailNameString.Buffer,
+ FailNameString.Length,
+ FailNameString.MaximumLength,
+ &a->FailName
+ );
+
+ Od2CaptureMessageString( CaptureBuffer,
+ LibPathNameString.Buffer,
+ LibPathNameString.Length,
+ LibPathNameString.MaximumLength,
+ &a->LibPathName
+ );
+
+ Od2CaptureMessageString( CaptureBuffer,
+ NULL,
+ 0,
+ MAX_INIT_RECORDS * sizeof(ldrlibi_t),
+ &a->InitRecords
+ );
+
+ Od2CallSubsystem( &m, CaptureBuffer, Ol2LdrLoadModule, sizeof( *a ) );
+
+ Rc = m.ReturnedErrorValue;
+ if (Rc != NO_ERROR) {
+ if (pszFailName != NULL) {
+ RtlCopyMemory(pszFailName, a->FailName.Buffer, a->FailName.Length);
+ pszFailName[a->FailName.Length] = '\0';
+ }
+ }
+ else {
+ NumOfInitRecords = a->NumOfInitRecords;
+ RtlCopyMemory(InitRecords, a->InitRecords.Buffer,
+ NumOfInitRecords * sizeof(ldrlibi_t));
+ RtlCopyMemory(pexec_info, &a->ExecInfo, sizeof(exec_info));
+ pexec_info->ei_envsel = FLATTOSEL(Od2Environment);
+ pexec_info->ei_comoff = (USHORT)Od2EnvCommandOffset;
+ }
+
+ Od2FreeCaptureBuffer( CaptureBuffer );
+
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("Values in exec_info:\n");
+ DbgPrint("ei_startaddr=%x\n", pexec_info->ei_startaddr); /* instruction pointer */
+ DbgPrint("ei_stackaddr=%x\n", pexec_info->ei_stackaddr); /* instruction pointer */
+ DbgPrint("ei_ds=%x\n", pexec_info->ei_ds); /* instruction pointer */
+ DbgPrint("ei_dgroupsize=%x\n", pexec_info->ei_dgroupsize); /* instruction pointer */
+ DbgPrint("ei_heapsize=%x\n", pexec_info->ei_heapsize); /* instruction pointer */
+ DbgPrint("ei_loadtype=%x\n", pexec_info->ei_loadtype); /* instruction pointer */
+ DbgPrint("ei_envsel=%x\n", pexec_info->ei_envsel); /* instruction pointer */
+ DbgPrint("ei_comoff=%x\n", pexec_info->ei_comoff); /* instruction pointer */
+ DbgPrint("ei_stacksize=%x\n", pexec_info->ei_stacksize); /* instruction pointer */
+ DbgPrint("ei_hmod=%x\n", pexec_info->ei_hmod); /* instruction pointer */
+ }
+#endif
+
+//#if DBG
+// {
+// OS2_API_MSG m;
+// P_LDRDUMPSEGMENTS_MSG a = &m.u.LdrDumpSegments;
+//
+// DbgPrint("DosLoadModuleNE: dumping segments !\n");
+//
+// Od2CallSubsystem( &m, NULL, Ol2LdrDumpSegments, sizeof( *a ) );
+// }
+//#endif
+
+ if (Rc == NO_ERROR) {
+ //
+ // Go over all DLLs init routines
+ //
+ for (i = 0; i < NumOfInitRecords; i++) {
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("=== Calling Init routine for module %s\n", pszModName);
+ }
+#endif
+ if (InitRecords[i].stackaddr.ptr_sel == 0) {
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("Replacing SS:SP of module\n");
+ }
+#endif
+ InitRecords[i].stackaddr.ptr_sel = FLATTOSEL(FlatAddrOf16BitStack);
+ InitRecords[i].stackaddr.ptr_off = (USHORT)FlatAddrOf16BitStack;
+ }
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("Values of libi:\n");
+ DbgPrint("startaddr=%x\n", InitRecords[i].startaddr); /* instruction pointer */
+ DbgPrint("stackaddr=%x\n", InitRecords[i].stackaddr); /* instruction pointer */
+ DbgPrint("ds=%x\n", InitRecords[i].ds); /* instruction pointer */
+ DbgPrint("heapsize=%x\n", InitRecords[i].heapsize); /* instruction pointer */
+ DbgPrint("handle=%x\n", InitRecords[i].handle); /* instruction pointer */
+ }
+#endif
+ RetCode = ldrLibiInit(&InitRecords[i], pexec_info);
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("=== Init routine returned %d\n", RetCode);
+ }
+#endif
+ }
+ *phMod = (USHORT)a->ModuleHandle;
+ }
+
+ return (Rc);
+}
+
+APIRET
+DosQueryModuleNameNE(
+ IN ULONG hMod,
+ IN ULONG cbBuf,
+ OUT PCHAR pchBuf
+ )
+{
+ OS2_API_MSG m;
+ P_LDRGETMODULENAME_MSG a = &m.u.LdrGetModuleName;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ STRING ModuleNameString;
+ APIRET Rc;
+
+ //
+ // probe pchBuf pointer.
+ //
+ try {
+ Od2ProbeForWrite(pchBuf, cbBuf, 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (cbBuf <= 1) {
+ return(ERROR_BAD_LENGTH);
+ }
+
+ ModuleNameString.Buffer = NULL;
+ ModuleNameString.Length = 0;
+ ModuleNameString.MaximumLength = (USHORT)cbBuf;
+ CaptureBuffer = Od2AllocateCaptureBuffer(
+ 1,
+ 0,
+ ModuleNameString.MaximumLength
+ );
+ if (CaptureBuffer == NULL) {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ a->ModuleHandle = hMod;
+ Od2CaptureMessageString( CaptureBuffer,
+ ModuleNameString.Buffer,
+ ModuleNameString.Length,
+ ModuleNameString.MaximumLength,
+ &a->ModuleName
+ );
+
+ Od2CallSubsystem( &m, CaptureBuffer, Ol2LdrGetModuleName, sizeof( *a ) );
+
+ Rc = m.ReturnedErrorValue;
+ if (Rc == NO_ERROR) {
+ strcpy(pchBuf, a->ModuleName.Buffer);
+ }
+
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ return(Rc);
+}
+
+APIRET
+DosQueryModuleHandleNE(
+ IN PSZ pszModName,
+ OUT PUSHORT phMod
+ )
+{
+ APIRET Rc;
+ OS2_API_MSG m;
+ P_LDRGETMODULEHANDLE_MSG a = &m.u.LdrGetModuleHandle;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ STRING ModuleNameString;
+ STRING LibPathNameString;
+ // Remember that \OS2SS\DRIVES\ is added for each path element !
+ // Let's assume the smallest component is 5 chars long (like C:\X;)
+ // (although it could be less, like "." or "\")
+ // => we need to add 14 * (MAXPATHLEN/5) = MAXPATHLEN*3
+ CHAR ExpandedLibPath[MAXPATHLEN*4];
+ BOOLEAN MemAllocatedForModName;
+ ULONG FileFlags;
+ ULONG FileType;
+ ULONG Len;
+
+ //
+ // probe phmod pointer.
+ //
+
+ try {
+ Len = strlen(pszModName);
+ Od2ProbeForWrite(phMod, sizeof(USHORT), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Check for any meta charaters
+ if (strpbrk(pszModName, "*?") != NULL) {
+ return(ERROR_INVALID_NAME);
+ }
+
+ if (strpbrk(pszModName, ":\\/.") == NULL) {
+ if (strcmp(pszModName,"DOSCALL1") == 0) {
+ RtlInitString(&ModuleNameString, "DOSCALLS");
+ MemAllocatedForModName = FALSE;
+ }
+ else {
+ RtlInitString(&ModuleNameString, pszModName);
+ MemAllocatedForModName = FALSE;
+ }
+ }
+ else {
+ Rc = Od2Canonicalize(pszModName,
+ CANONICALIZE_FILE_OR_DEV,
+ &ModuleNameString,
+ NULL,
+ &FileFlags,
+ &FileType
+ );
+ if (Rc != NO_ERROR) {
+ return(Rc);
+ }
+ MemAllocatedForModName = TRUE;
+ }
+
+ Od2ExpandOd2LibPathElements(ExpandedLibPath, sizeof(ExpandedLibPath));
+ RtlInitString(&LibPathNameString, ExpandedLibPath);
+
+ CaptureBuffer = Od2AllocateCaptureBuffer(
+ 2,
+ 0,
+ ModuleNameString.MaximumLength +
+ LibPathNameString.MaximumLength
+ );
+ if (CaptureBuffer == NULL) {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ Od2CaptureMessageString( CaptureBuffer,
+ ModuleNameString.Buffer,
+ ModuleNameString.Length,
+ ModuleNameString.MaximumLength,
+ &a->ModuleName
+ );
+ if (MemAllocatedForModName == TRUE) {
+ RtlFreeHeap(Od2Heap, 0, ModuleNameString.Buffer);
+ }
+
+ Od2CaptureMessageString( CaptureBuffer,
+ LibPathNameString.Buffer,
+ LibPathNameString.Length,
+ LibPathNameString.MaximumLength,
+ &a->LibPathName
+ );
+
+ Od2CallSubsystem( &m, CaptureBuffer, Ol2LdrGetModuleHandle, sizeof( *a ) );
+
+ Rc = m.ReturnedErrorValue;
+ if (Rc == NO_ERROR) {
+ *phMod = (USHORT)a->ModuleHandle;
+ }
+
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ return(Rc);
+}
+
+APIRET
+DosGetProcAddrNE(
+ IN ULONG hMod,
+ IN PSZ pszProcName,
+ OUT PULONG pProcAddr
+ )
+{
+
+ USHORT uTmp;
+ APIRET Rc;
+ OS2_API_MSG m;
+ P_LDRGETPROCADDR_MSG a = &m.u.LdrGetProcAddr;
+ POS2_CAPTURE_HEADER CaptureBuffer = NULL;
+ STRING ProcNameString;
+ BOOLEAN NameIsOrdinal;
+
+ //
+ // probe pprocaddr pointer.
+ //
+
+ try {
+ Od2ProbeForWrite(pProcAddr, sizeof(ULONG), 1);
+
+ //
+ // Check if flat address corresponds to selector index 0
+ //
+ if ((FLATTOSEL(pszProcName)) != 7) { // This is a text string
+ strlen((PCHAR) pszProcName);
+ if (*pszProcName == '#') {
+ a->ProcNameIsOrdinal = TRUE;
+ NameIsOrdinal = TRUE;
+ a->OrdinalNumber = atoi(pszProcName + 1);
+ }
+ else {
+ a->ProcNameIsOrdinal = FALSE;
+ NameIsOrdinal = FALSE;
+ RtlInitString(&ProcNameString, pszProcName);
+ }
+ }
+ else {
+ //
+ // Clear high bits of pszProcName and call
+ //
+ uTmp = (USHORT)pszProcName;
+ a->ProcNameIsOrdinal = TRUE;
+ NameIsOrdinal = TRUE;
+ a->OrdinalNumber = uTmp;
+ }
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (!NameIsOrdinal) {
+ CaptureBuffer = Od2AllocateCaptureBuffer(
+ 1,
+ 0,
+ ProcNameString.MaximumLength
+ );
+ if (CaptureBuffer == NULL) {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ Od2CaptureMessageString( CaptureBuffer,
+ ProcNameString.Buffer,
+ ProcNameString.Length,
+ ProcNameString.MaximumLength,
+ &a->ProcName
+ );
+ }
+
+ a->ModuleHandle = hMod;
+ Od2CallSubsystem( &m, CaptureBuffer, Ol2LdrGetProcAddr, sizeof( *a ) );
+
+ Rc = m.ReturnedErrorValue;
+ if (Rc == NO_ERROR) {
+ *pProcAddr = a->ProcAddr;
+ }
+
+ if (!NameIsOrdinal) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ }
+ return(Rc);
+}
+
+APIRET
+DosFreeModuleNE(
+ IN ULONG hMod
+ )
+{
+ OS2_API_MSG m;
+ P_LDRFREEMODULE_MSG a = &m.u.LdrFreeModule;
+ APIRET Rc;
+
+ a->ModuleHandle = hMod;
+ Od2CallSubsystem( &m, NULL, Ol2LdrFreeModule, sizeof( *a ) );
+
+ Rc = m.ReturnedErrorValue;
+ return(Rc);
+}
+
+APIRET
+DosQueryAppTypeNE(
+ IN PSZ pszAppName,
+ OUT PUSHORT pusType
+ )
+{
+ OS2_API_MSG m;
+ P_LDRQAPPTYPE_MSG a = &m.u.LdrQAppType;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ STRING AppNameString;
+ STRING PathNameString;
+ // Remember that \OS2SS\DRIVES\ is added for each path element !
+ // Let's assume the smallest component is 5 chars long (like C:\X;)
+ // (although it could be less, like "." or "\")
+ // => we need to add 14 * (MAXPATHLEN/5) = MAXPATHLEN*3
+ CHAR ExpandedPath[MAXPATHLEN*4];
+ BOOLEAN MemAllocatedForAppName;
+ ULONG FileFlags;
+ ULONG FileType;
+ ULONG Len;
+ PSZ PathPtr;
+ APIRET Rc;
+
+ //
+ // probe pchBuf pointer.
+ //
+ try {
+ Len = strlen(pszAppName); // just to trigger GP read exception
+ Od2ProbeForWrite(pusType, sizeof(USHORT), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (Len > 2) {
+ if (pszAppName[1] == ':') {
+ if (Len >= CCHMAXPATH) {
+ return(ERROR_FILE_NOT_FOUND);
+ }
+ }
+ else {
+ if (Len >= (CCHMAXPATH-2)) {
+ return(ERROR_FILE_NOT_FOUND);
+ }
+ }
+ }
+
+ if (strpbrk(pszAppName, ":\\/") == NULL) {
+ RtlInitString(&AppNameString, pszAppName);
+ MemAllocatedForAppName = FALSE;
+ }
+ else {
+ Rc = Od2Canonicalize(pszAppName,
+ CANONICALIZE_FILE_OR_DEV,
+ &AppNameString,
+ NULL,
+ &FileFlags,
+ &FileType
+ );
+ if (Rc != NO_ERROR) {
+ return(Rc);
+ }
+ MemAllocatedForAppName = TRUE;
+ }
+
+ Rc = DosScanEnv("PATH", &PathPtr);
+ if (Rc != NO_ERROR) {
+ PathPtr = "";
+ }
+
+ Od2ExpandPathElements(PathPtr, ExpandedPath, sizeof(ExpandedPath));
+ RtlInitString(&PathNameString, ExpandedPath);
+
+ CaptureBuffer = Od2AllocateCaptureBuffer(
+ 2,
+ 0,
+ AppNameString.MaximumLength +
+ PathNameString.MaximumLength
+ );
+ if (CaptureBuffer == NULL) {
+ if (MemAllocatedForAppName) {
+ RtlFreeHeap(Od2Heap, 0, AppNameString.Buffer);
+ }
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ Od2CaptureMessageString( CaptureBuffer,
+ AppNameString.Buffer,
+ AppNameString.Length,
+ AppNameString.MaximumLength,
+ &a->AppName
+ );
+
+ if (MemAllocatedForAppName) {
+ RtlFreeHeap(Od2Heap, 0, AppNameString.Buffer);
+ }
+
+ Od2CaptureMessageString( CaptureBuffer,
+ PathNameString.Buffer,
+ PathNameString.Length,
+ PathNameString.MaximumLength,
+ &a->PathName
+ );
+
+ Od2CallSubsystem( &m, CaptureBuffer, Ol2LdrQAppType, sizeof( *a ) );
+
+ Rc = m.ReturnedErrorValue;
+ if (Rc == NO_ERROR) {
+ *pusType = (USHORT)a->AppType;
+ }
+
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ return(Rc);
+}
+
+
+APIRET
+DosScanEnvNE(
+ IN PSZ pszValName,
+ OUT PSZ *ppresult
+ )
+{
+ ULONG rc;
+ ULONG value;
+
+
+ //
+ // probe pprsult pointer.
+ //
+
+ try {
+ Od2ProbeForWrite(ppresult,sizeof(ULONG), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ if ((rc = DosScanEnv(pszValName, ppresult)) != NO_ERROR)
+ return(rc);
+
+ value = (ULONG) *ppresult;
+
+ *ppresult = (PSZ)(FLATTOFARPTR(value));
+ return (NO_ERROR);
+}
+
+APIRET
+DosGetResourceNE(
+ ULONG hMod,
+ ULONG idType,
+ ULONG idName,
+ PSEL psel)
+{
+ OS2_API_MSG m;
+ P_LDRGETRESOURCE_MSG a = &m.u.LdrGetResource;
+ APIRET Rc;
+ ULONG SegNo;
+ ULONG sel;
+
+ try {
+ Od2ProbeForWrite(psel, sizeof(USHORT), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ a->ModuleHandle = hMod;
+ a->ResourceType = idType;
+ a->ResourceName = idName;
+
+ AcquireTaskLock();
+
+ Od2CallSubsystem( &m, NULL, Ol2LdrGetResource, sizeof( *a ) );
+
+ Rc = m.ReturnedErrorValue;
+ if (Rc == NO_ERROR) {
+ *psel = (SEL)a->ResourceSel;
+#if DBG
+ if ((Os2DebugSel != 0) && (*psel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosGetResource returning sel=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ *psel);
+ }
+#endif
+
+ // This loop is for Long resources. It marks all segments of a resource.
+ sel = (*psel >> 3) - (0x2000 - LDT_DISJOINT_ENTRIES);
+ for (SegNo=0; SegNo<a->NumberOfSegments; SegNo++) {
+ ResourceUsage[sel]++;
+ sel =+ 8;
+ }
+ }
+
+ ReleaseTaskLock();
+
+ return(Rc);
+}
+
+APIRET
+DosGetResource2NE(
+ ULONG hMod,
+ ULONG idType,
+ ULONG idName,
+ PVOID pData)
+{
+ OS2_API_MSG m;
+ P_LDRGETRESOURCE_MSG a = &m.u.LdrGetResource;
+ APIRET Rc;
+ ULONG SegNo;
+ ULONG sel;
+
+
+ try {
+ Od2ProbeForWrite(pData, sizeof(ULONG), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ a->ModuleHandle = hMod;
+ a->ResourceType = idType;
+ a->ResourceName = idName;
+
+ AcquireTaskLock();
+
+ Od2CallSubsystem( &m, NULL, Ol2LdrGetResource, sizeof( *a ) );
+
+ Rc = m.ReturnedErrorValue;
+ if (Rc == NO_ERROR) {
+ *(PULONG)pData = a->ResourceAddr;
+#if DBG
+ if ((Os2DebugSel != 0) && (((USHORT)(a->ResourceAddr >> 16)) == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosGetResource returning sel=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ ((USHORT)(a->ResourceAddr >> 16)));
+ }
+#endif
+ // This loop is for Long resources. It marks all segments of a resource.
+ sel = (a->ResourceAddr >> 19) - (0x2000 - LDT_DISJOINT_ENTRIES);
+ for (SegNo=0; SegNo<a->NumberOfSegments; SegNo++) {
+ ResourceUsage[sel]++;
+ sel+=8;
+ }
+// ResourceUsage[(a->ResourceAddr >> 19) - (0x2000 - LDT_DISJOINT_ENTRIES)]++;
+ }
+
+ ReleaseTaskLock();
+
+ return(Rc);
+}
+
+APIRET
+DosFreeResourceNE(
+ PVOID pData)
+{
+ OS2_API_MSG m;
+ P_LDRFREERESOURCE_MSG a = &m.u.LdrFreeResource;
+ SEL Sel;
+ USHORT ResourceIndex;
+ APIRET Rc;
+
+ a->ResourceAddr = (ULONG)pData;
+
+ Od2CallSubsystem( &m, NULL, Ol2LdrFreeResource, sizeof( *a ) );
+
+ Rc = m.ReturnedErrorValue;
+
+#if DBG
+ if ((Os2DebugSel != 0) && ((USHORT)((ULONG)pData >> 16) == Os2DebugSel))
+ {
+ if (Rc == NO_ERROR)
+ DbgPrint("[%x,%x] DosFreeResource called on sel=%x (successfull)\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ (USHORT)((ULONG)pData >> 16));
+ else
+ DbgPrint("[%x,%x] DosFreeResource called on sel=%x, rc=%d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ (USHORT)((ULONG)pData >> 16),
+ Rc);
+ }
+#endif
+
+ if (Rc == NO_ERROR) {
+ Sel = FLATTOSEL(pData);
+ ResourceIndex = (Sel >> 3) - (0x2000 - LDT_DISJOINT_ENTRIES);
+ if (ResourceUsage[ResourceIndex] > 0) {
+ ResourceUsage[ResourceIndex]--;
+ }
+ else {
+ return(ERROR_ACCESS_DENIED);
+ }
+ }
+
+ return(Rc);
+}
diff --git a/private/os2/client/dllloadr.c b/private/os2/client/dllloadr.c
new file mode 100644
index 000000000..41fdeff86
--- /dev/null
+++ b/private/os2/client/dllloadr.c
@@ -0,0 +1,325 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllloadr.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 Loader API Calls
+
+Author:
+
+ Steve Wood (stevewo) 20-Sep-1989
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_LOADER
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+
+APIRET
+DosLoadModule(
+ OUT PSZ ErrorText,
+ IN ULONG ErrorTextLength,
+ IN PSZ ModuleName,
+ OUT PHMODULE ModuleHandle
+ )
+{
+ NTSTATUS Status;
+ ULONG Characteristics;
+ STRING ModuleNameString;
+ UNICODE_STRING ModuleNameString_U;
+ APIRET RetCode;
+
+ try {
+ Od2InitMBString( &ModuleNameString, ModuleName );
+ *ModuleHandle = 0;
+ Od2ProbeForWrite(ErrorText,ErrorTextLength,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &ModuleNameString_U,
+ &ModuleNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+// DbgPrint("DosLoadModule: no memory for Unicode Conversion\n");
+#endif
+ return RetCode;
+ }
+
+ Status = LdrLoadDll( NULL,
+ &Characteristics,
+ &ModuleNameString_U,
+ (PVOID *)ModuleHandle
+ );
+ RtlFreeUnicodeString (&ModuleNameString_U);
+ if (NT_SUCCESS( Status )) {
+ return( NO_ERROR );
+ }
+ else {
+ return( Or2MapNtStatusToOs2Error(Status, ERROR_FILE_NOT_FOUND) );
+ }
+}
+
+
+APIRET
+DosFreeModule(
+ IN HMODULE ModuleHandle
+ )
+{
+ NTSTATUS Status;
+
+ Status = LdrUnloadDll( (PVOID)ModuleHandle );
+ if (NT_SUCCESS( Status )) {
+ return( NO_ERROR );
+ }
+ else {
+ return( Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE) );
+ }
+}
+
+
+APIRET
+DosQueryProcAddr(
+ IN HMODULE ModuleHandle,
+ IN ULONG ProcOrdinal,
+ IN PSZ ProcName OPTIONAL,
+ OUT PFN *ProcAddress
+ )
+{
+ NTSTATUS Status;
+ STRING ProcedureNameString;
+ PSTRING ProcedureName;
+
+ if (ARGUMENT_PRESENT( ProcName )) {
+ ProcedureName = &ProcedureNameString;
+ try {
+ Od2InitMBString( ProcedureName, ProcName );
+ *ProcAddress = 0;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ }
+ else {
+ ProcedureName = NULL;
+ try {
+ *ProcAddress = 0;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ }
+
+ Status = LdrGetProcedureAddress( (PVOID)ModuleHandle,
+ ProcedureName,
+ ProcOrdinal,
+ (PVOID *)ProcAddress
+ );
+ if (NT_SUCCESS( Status )) {
+ return( NO_ERROR );
+ }
+ else {
+ return( Or2MapNtStatusToOs2Error(Status, ERROR_PROC_NOT_FOUND) );
+ }
+}
+
+
+APIRET
+DosQueryProcType(
+ IN HMODULE ModuleHandle,
+ IN ULONG ProcOrdinal,
+ IN PSZ ProcName OPTIONAL,
+ OUT PULONG *ProcType
+ )
+{
+ APIRET rc;
+ PFN ProcAddress;
+
+ rc = DosQueryProcAddr( ModuleHandle, ProcOrdinal, ProcName, &ProcAddress );
+ if (rc == NO_ERROR) {
+ try {
+ *ProcType = (PULONG)(PT_32BIT);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ }
+
+ return( rc );
+}
+
+APIRET
+DosQueryModuleHandle(
+ IN PSZ ModuleName,
+ OUT PHMODULE ModuleHandle
+ )
+{
+ UNREFERENCED_PARAMETER(ModuleName);
+ UNREFERENCED_PARAMETER(ModuleHandle);
+ return( ERROR_INVALID_FUNCTION );
+}
+
+
+APIRET
+DosQueryModuleName(
+ IN HMODULE ModuleHandle,
+ IN ULONG ModuleNameLength,
+ OUT PSZ ModuleName
+ )
+{
+ UNREFERENCED_PARAMETER(ModuleHandle);
+ UNREFERENCED_PARAMETER(ModuleNameLength);
+ UNREFERENCED_PARAMETER(ModuleName);
+ return( ERROR_INVALID_FUNCTION );
+}
+
+
+APIRET
+DosGetResource(
+ IN HMODULE ModuleHandle,
+ IN ULONG ResourceTypeId,
+ IN ULONG ResourceNameId,
+ OUT PVOID *ResourceBaseAddress
+ )
+{
+ PVOID DllHandle;
+ NTSTATUS Status;
+ PIMAGE_RESOURCE_DATA_ENTRY ResourceEntry;
+ ULONG IdPath[ 3 ];
+
+ if (ModuleHandle != NULL) {
+ DllHandle = (PVOID) ModuleHandle;
+ }
+ else {
+ DllHandle = (PVOID) NtCurrentPeb()->ImageBaseAddress;
+ }
+
+ try {
+ *ResourceBaseAddress = 0;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ IdPath[ 0 ] = ResourceTypeId;
+ IdPath[ 1 ] = ResourceNameId;
+ IdPath[ 2 ] = 0; // language neutral resource
+
+ Status = LdrFindResource_U( DllHandle,
+ IdPath,
+ 3,
+ &ResourceEntry
+ );
+ if (NT_SUCCESS( Status )) {
+ Status = LdrAccessResource( DllHandle,
+ ResourceEntry,
+ ResourceBaseAddress,
+ (PULONG)NULL
+ );
+ }
+
+ if (!NT_SUCCESS( Status )) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+ else {
+ return( NO_ERROR );
+ }
+}
+
+
+APIRET
+DosQueryResourceSize(
+ IN HMODULE ModuleHandle,
+ IN ULONG ResourceTypeId,
+ IN ULONG ResourceNameId,
+ OUT PULONG ResourceSize
+ )
+{
+ PVOID DllHandle;
+ NTSTATUS Status;
+ PIMAGE_RESOURCE_DATA_ENTRY ResourceEntry;
+ ULONG IdPath[ 3 ];
+
+ if (ModuleHandle != NULL) {
+ DllHandle = (PVOID) ModuleHandle;
+ }
+ else {
+ DllHandle = (PVOID) NtCurrentPeb()->ImageBaseAddress;
+ }
+
+ try {
+ *ResourceSize = 0;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ IdPath[ 0 ] = ResourceTypeId;
+ IdPath[ 1 ] = ResourceNameId;
+ IdPath[ 2 ] = 0; // language neutral resource
+
+ Status = LdrFindResource_U( DllHandle,
+ IdPath,
+ 3,
+ &ResourceEntry
+ );
+ if (NT_SUCCESS( Status )) {
+ Status = LdrAccessResource( DllHandle,
+ ResourceEntry,
+ NULL,
+ ResourceSize
+ );
+ }
+
+ if (!NT_SUCCESS( Status )) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+ else {
+ return( NO_ERROR );
+ }
+}
+
+
+
+
+APIRET
+DosQueryAppType(
+ IN PSZ ImageFileName,
+ OUT PULONG AppTypeFlags
+ )
+{
+ UNREFERENCED_PARAMETER(ImageFileName);
+ try {
+ *AppTypeFlags = FAPPTYP_NOTWINDOWCOMPAT;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ return( NO_ERROR );
+}
+
+
+APIRET
+DosReplaceModule(
+ IN PSZ pszOldModule,
+ IN PSZ pszNewModule,
+ IN PSZ pszBackupModule
+ )
+{
+ UNREFERENCED_PARAMETER(pszOldModule);
+ UNREFERENCED_PARAMETER(pszNewModule);
+ UNREFERENCED_PARAMETER(pszBackupModule);
+ return( ERROR_INVALID_FUNCTION );
+}
diff --git a/private/os2/client/dllmisc.c b/private/os2/client/dllmisc.c
new file mode 100644
index 000000000..719d15a54
--- /dev/null
+++ b/private/os2/client/dllmisc.c
@@ -0,0 +1,536 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllmisc.c
+
+Abstract:
+
+ This module implements some miscellaneous OS/2 V2.0 API Calls
+
+Author:
+
+ Steve Wood (stevewo) 20-Sep-1989 (Adapted from URTL\alloc.c)
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_DEVICE_SUPPORT
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "conrqust.h"
+#include "os2win.h"
+
+extern BOOLEAN FPUinit_unmask;
+
+#define HARDWARE_NODE L"\\Registry\\Machine\\Hardware"
+#define WORK_SIZE 1024
+#define KEY_VALUE_BUFFER_SIZE 20240
+WCHAR workbuffer[WORK_SIZE];
+UCHAR KeyValueBuffer[KEY_VALUE_BUFFER_SIZE];
+UNICODE_STRING WorkName;
+
+APIRET
+DosQuerySysInfo(
+ IN ULONG SysInfoIndexStart,
+ IN ULONG SysInfoIndexEnd,
+ OUT PBYTE Buffer,
+ IN ULONG Length
+ )
+{
+ ULONG SysInfoIndex;
+ ULONG Value;
+ PULONG ValueDest;
+ LARGE_INTEGER SystemTime;
+ LARGE_INTEGER LocalTime;
+ NTSTATUS Status;
+
+#if DBG
+ IF_OD2_DEBUG( DEVICE_SUPPORT ) {
+ DbgPrint( "Entering DosQuerySysInfo( %ld, %ld, %lX, %ld )\n",
+ SysInfoIndexStart, SysInfoIndexEnd, Buffer, Length
+ );
+ }
+#endif
+
+ //
+ // Validate the input parameters
+ //
+
+ if (SysInfoIndexStart > SysInfoIndexEnd ||
+ SysInfoIndexStart < 1 ||
+ SysInfoIndexEnd > QSV_MAXIMUM_INDEX
+ ) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ if (Length < ((SysInfoIndexEnd - SysInfoIndexStart + 1) * sizeof( ULONG ))) {
+ return( ERROR_BUFFER_OVERFLOW );
+ }
+
+ //
+ // Get the requested information into the Value local varible.
+ //
+
+ try {
+ ValueDest = (PULONG)Buffer;
+ for (SysInfoIndex=SysInfoIndexStart;
+ SysInfoIndex<=SysInfoIndexEnd;
+ SysInfoIndex++
+ ) {
+ switch( SysInfoIndex ) {
+ //
+ // Bogus path limitations inheritied from OS/2. Our implementation
+ // does not have any limitations, other than available memory. But
+ // tell them what they expect to hear from OS/2 anyway.
+ //
+
+ case QSV_MAX_PATH_LENGTH:
+ Value = CCHMAXPATH;
+ break;
+
+
+ //
+ // Bogus limitation on the number of text mode (e.g. ANSI terminal)
+ // application sessions. Our implementation does not have any
+ // limitations other than available memory. But tell them what
+ // they expected to hear from OS/2 anyway.
+ //
+
+ case QSV_MAX_TEXT_SESSIONS:
+ Value = 16;
+ break;
+
+
+ //
+ // Bogus limitation on the number of Presentation Manager
+ // application sessions. Our implementation does not have any
+ // limitations other than available memory. But tell them what
+ // they expected to hear from OS/2 anyway.
+ //
+
+ case QSV_MAX_PM_SESSIONS:
+ Value = 16;
+ break;
+
+
+ //
+ // Not relevant until we get a software DOS simulator for non-Intel
+ // machines.
+ //
+
+ case QSV_MAX_VDM_SESSIONS:
+ Value = 0; // Machine dependent
+ break;
+
+
+ //
+ // Return the index of the boot drive.
+ //
+
+ case QSV_BOOT_DRIVE:
+ Value = Od2BootDrive+1;
+ break;
+
+
+ //
+ // Our system always runs with dynamic priority, so always return
+ // true.
+ //
+
+ case QSV_DYN_PRI_VARIATION:
+ Value = TRUE;
+ break;
+
+
+ //
+ // Our system does not currently implement a MAXWAIT concept,
+ // although it will at some point implement priority shuffling
+ // as a fix for user mode priority inversion. For now return
+ // return the default OS/2 2.0 value
+ //
+
+ case QSV_MAX_WAIT:
+ Value = 100;
+ break;
+
+
+ //
+ // Our system only has a single quantum value, so return the
+ // same number for both Minimum and Maximum time slice. For
+ // now this number will be the OS/2 2.0 constant without regard
+ // to the quantum value that the NT kernel is using.
+ //
+
+ case QSV_MIN_SLICE:
+ case QSV_MAX_SLICE:
+ Value = 248;
+ break;
+
+
+ //
+ // Finally, a real number we can return. Return the physical
+ // page size from the NT System Information record. This
+ // is NOT the allocation granularity.
+ //
+
+ case QSV_PAGE_SIZE:
+ Value = Od2NtSysInfo.PageSize;
+ break;
+
+
+ //
+ // Major version number is 20
+ //
+
+ case QSV_VERSION_MAJOR:
+ Value = 20;
+ break;
+
+
+ //
+ // Minor version number is 10
+ //
+
+ case QSV_VERSION_MINOR:
+ Value = 10;
+ break;
+
+
+ //
+ // Revision number is 0 (what is this on Cruiser?)
+ // FIX, FIX
+ //
+
+ case QSV_VERSION_REVISION:
+ Value = 0;
+ break;
+
+
+ //
+ // Free running millisecond counter
+ // FIX, FIX - need to get real timer in PCR
+ //
+
+ case QSV_MS_COUNT:
+ NtQuerySystemTime( &SystemTime );
+
+ //
+ // Convert UTC to Local time
+ //
+
+ Status = RtlSystemTimeToLocalTime ( &SystemTime, &LocalTime);
+ if (!NT_SUCCESS( Status ))
+ {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_PARAMETER ));
+ }
+
+ Value = LocalTime.LowPart / 10;
+ break;
+
+ //
+ // Low dword of time in seconds since January 1, 1970
+ //
+
+ case QSV_TIME_LOW:
+ NtQuerySystemTime( &SystemTime );
+
+ //
+ // Convert UTC to Local time
+ //
+
+ Status = RtlSystemTimeToLocalTime ( &SystemTime, &LocalTime);
+ if (!NT_SUCCESS( Status ))
+ {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_PARAMETER ));
+ }
+
+ RtlTimeToSecondsSince1970( &LocalTime,
+ &Value
+ );
+ break;
+
+ //
+ // High dword of time in seconds since January 1, 1970
+ // FIX, FIX - late in 21st century this is non-zero
+ //
+
+ case QSV_TIME_HIGH:
+ Value = 0;
+ break;
+
+ //
+ // Physical memory on system
+ //
+
+ case QSV_TOTPHYSMEM:
+ Value = 1024 * Od2NtSysInfo.PageSize;
+ break;
+
+ //
+ // Resident memory on system
+ //
+
+ case QSV_TOTRESMEM: // FIX, FIX
+ Value = 128 * Od2NtSysInfo.PageSize;
+ break;
+
+ //
+ // Available memory for all processes
+ //
+
+ case QSV_TOTAVAILMEM: // FIX, FIX
+ Value = Od2NtSysInfo.MaximumUserModeAddress -
+ Od2NtSysInfo.MinimumUserModeAddress;
+ break;
+
+ //
+ // Avail private mem for calling proc
+ //
+
+ case QSV_MAXPRMEM:
+ Value = Od2NtSysInfo.MaximumUserModeAddress -
+ Od2NtSysInfo.MinimumUserModeAddress;
+ break;
+
+ //
+ // Avail shared mem for calling proc
+ //
+
+ case QSV_MAXSHMEM:
+ Value = Od2NtSysInfo.MaximumUserModeAddress -
+ Od2NtSysInfo.MinimumUserModeAddress;
+ break;
+
+ //
+ // Timer interval in tenths of ms
+ //
+
+ case QSV_TIMER_INTERVAL:
+ Value = Od2NtSysInfo.TimerResolution / 100;
+ break;
+
+ //
+ // max len of one component in a name
+ //
+
+ case QSV_MAX_COMP_LENGTH:
+ Value = CCHMAXCOMP;
+ break;
+
+ //
+ // Return an error if invalid index specified.
+ //
+
+ default:
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ //
+ // Now store the value in the caller's buffer
+ //
+
+ *ValueDest++ = (ULONG)Value;
+ }
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ //
+ // Return success
+ //
+
+ return( NO_ERROR );
+}
+
+
+APIRET
+DosBeep(
+ IN ULONG Frequency,
+ IN ULONG Duration
+ )
+{
+ APIRET RetCode;
+#if DBG
+ PSZ RoutineName;
+
+ RoutineName = "DosBeep";
+ IF_OD2_DEBUG( DEVICE_SUPPORT )
+ {
+ DbgPrint( "%s: Frequency %ld, Duration %ld\n",
+ RoutineName, Frequency, Duration);
+ }
+#endif
+
+ if (( Frequency < 37 ) || ( Frequency >= 0x8000 ))
+ {
+ return (ERROR_INVALID_FREQUENCY);
+ }
+
+ if(!(RetCode = Ow2ConBeep(Frequency, Duration)))
+ {
+ RetCode = DosSleep(Duration);
+ } else
+ {
+#if DBG
+ IF_OD2_DEBUG( DEVICE_SUPPORT )
+ {
+ DbgPrint( "%s: rc %lu\n", RoutineName, RetCode);
+ }
+#endif
+ }
+
+ return( RetCode );
+}
+
+
+APIRET
+DosDevConfig(
+ OUT PVOID DeviceInformation,
+ IN ULONG DeviceInformationIndex
+ )
+{
+ ULONG Value;
+ ULONG ValueLength = 1;
+// SYSTEM_PROCESSOR_INFORMATION Info;
+ SYSTEM_DEVICE_INFORMATION SystemInfo;
+ HANDLE Handle;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING WorkName;
+ NTSTATUS status;
+
+#if DBG
+ IF_OD2_DEBUG( DEVICE_SUPPORT ) {
+ DbgPrint( "Entering DosDevConfig( %lX, %ld )\n",
+ DeviceInformation, DeviceInformationIndex
+ );
+ }
+#endif
+
+ switch ( DeviceInformationIndex ) {
+
+ case DDC_NUMBER_PRINTERS:
+ case DDC_NUMBER_RS232_PORTS:
+ case DDC_NUMBER_DISKETTE_DRIVES:
+
+ NtQuerySystemInformation(
+ SystemDeviceInformation,
+ &SystemInfo,
+ sizeof(SYSTEM_DEVICE_INFORMATION),
+ NULL
+ );
+ ValueLength = 2;
+ break;
+ }
+
+ switch ( DeviceInformationIndex ) {
+
+ case DDC_NUMBER_PRINTERS:
+
+ Value = SystemInfo.NumberOfParallelPorts;
+ break;
+
+ case DDC_NUMBER_RS232_PORTS:
+
+ Value = SystemInfo.NumberOfSerialPorts;
+ break;
+
+ case DDC_NUMBER_DISKETTE_DRIVES:
+
+ Value = SystemInfo.NumberOfFloppies;
+ break;
+
+ case DDC_MATH_COPROCESSOR:
+
+ RtlInitUnicodeString(&WorkName,
+ L"\\registry\\machine\\hardware\\description\\system\\floatingpointprocessor"
+ );
+ InitializeObjectAttributes(&ObjectAttributes,
+ &WorkName,
+ 0,
+ (HANDLE) 0,
+ NULL);
+ ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
+ status = NtOpenKey(&Handle,
+ MAXIMUM_ALLOWED,
+ &ObjectAttributes);
+ if (NT_SUCCESS(status)) {
+ FPUinit_unmask = TRUE;
+ Value = TRUE;
+ }
+ else {
+ Value = FALSE;
+ }
+ break;
+
+ case DDC_PC_SUBMODEL_TYPE:
+
+ Value = 0;
+ break;
+
+ case DDC_PC_MODEL_TYPE:
+
+ Value = 0xf8; // Return as a PS/2 Model 80
+ break;
+
+ case DDC_PRIMARY_DISPLAY_TYPE:
+
+ Value = 1; // Return as a non-monochrome display
+ break;
+
+ case DDC_COPROCESSORTYPE:
+
+ Value = 1;
+ break;
+
+ //
+ // Return an error if invalid index specified.
+ //
+
+ default:
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ //
+ // Now store the value in the caller's buffer using the correct
+ // alignment and size. Since this API does not have a Length parameter
+ // no checking is done to see if user buffer is big enough.
+ //
+
+ try {
+ switch ( ValueLength ) {
+ case 1:
+ *(PUCHAR)DeviceInformation = (UCHAR)Value;
+ break;
+
+ case 2:
+ *(PUSHORT)DeviceInformation = (USHORT)Value;
+ break;
+
+ case 4:
+ *(PULONG)DeviceInformation = (ULONG)Value;
+ break;
+
+ //
+ // Internal error if we get here
+ //
+
+ default:
+ DbgBreakPoint();
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Return success
+ //
+
+ return( NO_ERROR );
+}
diff --git a/private/os2/client/dllmon.c b/private/os2/client/dllmon.c
new file mode 100644
index 000000000..76518ac8a
--- /dev/null
+++ b/private/os2/client/dllmon.c
@@ -0,0 +1,773 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllmon.c
+
+Abstract:
+
+ This module implements 32 equivalents of OS/2 V1.21
+ MON API Calls.
+ The APIs are called from 16->32 thunks (i386\doscalls.asm).
+
+ All APIs are composed from the following steps:
+
+ 1. debug API info
+ 1. check parameter legalty (Od2ProbeForRead/Write, other)
+ 2. prepare Message parameters
+ 3. send request to server (OS2.EXE) thru SendMonConsoleRequset
+ 4. handle return status (i.e. free handle if failed, validate if successed)
+
+Author:
+
+ Michael Jarus (mjarus) 15-jan-1992
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "conrqust.h"
+#include "monitor.h"
+
+
+extern ULONG Od2SessionNumber;
+
+APIRET CHECK_HMON(IN ULONG hMon,
+ OUT PFILE_HANDLE *hFileRecord,
+#if DBG
+ IN PSZ FuncName,
+#endif
+ IN ULONG ReleaseFlag);
+
+struct
+{
+ MONDEVNUMBER DeviceCode;
+ PSZ DeviceName;
+ USHORT NameLength;
+ USHORT MinSize;
+} MonDevTable[] =
+ { { KbdDevice, "KBD$", 4 , 127},
+ { MouseDevice, "MOUSE$", 6, 127 },
+ { 0, NULL, 0, 0 }
+ };
+
+#if DBG
+#define EXCEPTION_IN_MON() \
+ { \
+ IF_OD2_DEBUG(MON) \
+ { \
+ KdPrint(("%s: GP Exception\n", FuncName)); \
+ } \
+ return ERROR_MON_INVALID_PARMS; \
+ }
+#else
+#define EXCEPTION_IN_MON() \
+ { \
+ return ERROR_MON_INVALID_PARMS; \
+ }
+#endif
+
+#if DBG
+#define SendMonConsoleRequest(Rc, Request) \
+ IF_OD2_DEBUG(MON) \
+ { \
+ KdPrint(("SendMonCtrlConsoleRequest: Request %u\n", \
+ Request.d.Mon.Request)); \
+ } \
+ \
+ Request.Request = MonRequest; \
+ \
+ Rc = SendCtrlConsoleRequest(&Request, NULL, NULL, NULL);
+#else
+#define SendMonConsoleRequest(Rc, Request) \
+ Request.Request = MonRequest; \
+ \
+ Rc = SendCtrlConsoleRequest(&Request, NULL, NULL, NULL);
+#endif
+
+
+APIRET
+DosMonOpen(IN PSZ pDevName,
+ OUT PUSHORT phMon)
+{
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ SCREQUESTMSG Request;
+ HFILE hMon;
+ USHORT Index;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosMonOpen";
+
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("<%u> %s: dev %s\n", (USHORT)(Od2CurrentThreadId()),
+ FuncName, pDevName));
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ if (MoniorOpenedForThisProcess)
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ KdPrint(("<%u> %s: monitor already opend for the process\n",
+ (USHORT)(Od2CurrentThreadId()), FuncName, pDevName));
+#endif
+ return ERROR_MON_INVALID_PARMS; //BUGBUG=> ??
+ }
+
+ try
+ { Od2ProbeForWrite(phMon, sizeof(USHORT), 1);
+ for ( Index = 0 ; MonDevTable[Index].DeviceName ; Index++ )
+ {
+ if (!_strnicmp(MonDevTable[Index].DeviceName,
+ pDevName,
+ MonDevTable[Index].NameLength + 1))
+ {
+ break;
+ }
+ }
+
+ if (!MonDevTable[Index].DeviceName)
+ {
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: invalid device %s\n", FuncName, pDevName));
+ }
+#endif
+
+ return ERROR_MON_INVALID_DEVNAME;
+ }
+
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MON()
+ }
+
+ //
+ // Allocate an Os2 Handle
+ //
+
+ AcquireFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ RetCode = AllocateHandle(&hMon);
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: unable to allocate FileHandle\n", FuncName));
+ }
+#endif
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Mon.Request = MONOpen;
+ Request.d.Mon.d.OpenClose.MonDevice = MonDevTable[Index].DeviceCode;
+ SendMonConsoleRequest(RetCode, Request);
+
+ AcquireFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * handle return status (free handle if failed, validate if successed)
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ KdPrint(("%s: status %lx\n", FuncName, RetCode));
+#endif
+ FreeHandle(hMon);
+ } else
+ {
+ hFileRecord = DereferenceFileHandleNoCheck(hMon);
+ hFileRecord->NtHandle = Request.d.Mon.d.OpenClose.hMON;
+ hFileRecord->IoVectorType = MonitorVectorType;
+ //hFileRecord->Flags |= fsOpenMode & QFHSTATE_FLAGS;
+ //hFileRecord->FileType = FILE_TYPE_NMPIPE;
+
+ //
+ // validate file handle
+ //
+
+ ValidateHandle(hFileRecord);
+
+ *phMon = (USHORT)hMon;
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: returns %lx\n", FuncName, *phMon));
+ }
+#endif
+
+ MoniorOpenedForThisProcess = TRUE;
+
+ }
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ return RetCode;
+}
+
+
+APIRET
+DosMonClose(IN ULONG hMon)
+{
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ SCREQUESTMSG Request;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosMonClose";
+
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("<%u> %s: hMon %lx\n",
+ (USHORT)(Od2CurrentThreadId()), FuncName, hMon));
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ if (RetCode = CHECK_HMON(hMon,
+ &hFileRecord,
+ #if DBG
+ FuncName,
+ #endif
+ FALSE))
+ {
+ return RetCode;
+ }
+
+ InvalidateHandle(hFileRecord);
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Mon.Request = MONClose;
+ Request.d.Mon.d.OpenClose.hMON = hFileRecord->NtHandle;
+
+ SendMonConsoleRequest(RetCode, Request);
+
+ AcquireFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ FreeHandle((HFILE)hMon);
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * handle return status
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ KdPrint(("%s: status %lx\n", FuncName, RetCode));
+#endif
+ return(RetCode);
+ }
+
+ MoniorOpenedForThisProcess = FALSE;
+
+ return NO_ERROR;
+}
+
+
+APIRET
+DosMonRead(IN PBYTE pInBuffer,
+ IN ULONG fWait,
+ IN PBYTE pDataBuf,
+ IN OUT PUSHORT pcbDataSize)
+{
+ APIRET RetCode;
+ SCREQUESTMSG Request;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosMonRead";
+
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("<%u> %s: size %x, wait %lx\n",
+ (USHORT)(Od2CurrentThreadId()), FuncName, *pcbDataSize, fWait));
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ if ((fWait != DCWW_WAIT) && (fWait != DCWW_NOWAIT))
+ {
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: invalid wait parameter %lx\n", FuncName, fWait));
+ }
+#endif
+
+ return ERROR_MON_INVALID_PARMS;
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pcbDataSize, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pDataBuf, *pcbDataSize, 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MON()
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Mon.Request = MONRead;
+ Request.d.Mon.d.rwParms.fWait = (USHORT)fWait;
+ Request.d.Mon.d.rwParms.ProcessId = (ULONG)Od2Process->Pib.ProcessId;
+ Request.d.Mon.d.rwParms.Length = *pcbDataSize;
+ Request.d.Mon.d.rwParms.MonBuffer = pInBuffer;
+
+ SendMonConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ KdPrint(("%s: status %lx\n", FuncName, RetCode));
+#endif
+ return(RetCode);
+ }
+
+ *pcbDataSize = Request.d.Mon.d.rwParms.Length;
+ RtlMoveMemory( pDataBuf, Request.d.Mon.d.rwParms.ioBuff, *pcbDataSize );
+
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: data was read (length %x)\n", FuncName, *pcbDataSize));
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+DosMonReg( IN ULONG hMon,
+ IN PBYTE pInBuffer,
+ IN PBYTE pOutBuffer,
+ IN ULONG fPosition,
+ IN ULONG usIndex)
+{
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ SCREQUESTMSG Request;
+ USHORT InSize, OutSize;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosMonReg";
+
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("<%u> %s: handle %lx, position %lx, index %lx, InBuf %p(InSize %x), OutBuf %p(OutSize %x)\n", (USHORT)(Od2CurrentThreadId()),
+ FuncName, hMon, fPosition, usIndex, pInBuffer, *(PUSHORT)pInBuffer, pOutBuffer, *(PUSHORT) pOutBuffer));
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ if (FLATTOSEL((ULONG)pInBuffer) != FLATTOSEL((ULONG)pOutBuffer))
+ {
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: buffer in seperate segments %x, %x\n",
+ FuncName, FLATTOSEL((ULONG)pInBuffer), FLATTOSEL((ULONG)pOutBuffer)));
+ }
+#endif
+
+ return ERROR_MON_INVALID_PARMS;
+ }
+
+ if (!strcmp(Od2Process->ApplName, "EPSILON.EXE"))
+ {
+ /*
+ * Hack for bug #8368 (GP while pressing char quickly on startup)
+ * (mjarus, 7/8/93)
+ */
+
+ return(ERROR_MONITORS_NOT_SUPPORTED);
+ }
+
+ try
+ {
+ InSize = ((MONIN*)pInBuffer)->cb;
+ OutSize = ((MONOUT*)pOutBuffer)->cb;
+
+ RtlZeroMemory(pInBuffer, InSize);
+ RtlZeroMemory(pOutBuffer, OutSize);
+
+ ((MONIN*)pInBuffer)->cb = InSize;
+ ((MONOUT*)pOutBuffer)->cb = OutSize;
+
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MON()
+ }
+
+ if ((InSize < MIN_KBD_MON_BUFFER) ||
+ (OutSize < MIN_KBD_MON_BUFFER))
+ {
+ /*
+ * Buffer too small
+ */
+
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: buffer too small %d, %d\n",
+ FuncName, *(PUSHORT)pInBuffer, *(PUSHORT) pOutBuffer));
+ }
+#endif
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ if ((usIndex != 0xFFFF) && (usIndex != Od2SessionNumber)) // BUGBUG-> fix it
+ {
+ if (usIndex == 0)
+ {
+ //
+ // a win32 process is in foreground - attach to current session
+ //
+ usIndex = Od2SessionNumber;
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: index is 0, set to Od2SessionNumber %lx\n",
+ FuncName, Od2SessionNumber));
+ }
+#endif
+ }
+ else
+ {
+ /*
+ * Illegal index
+ */
+
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: illegal index %lx\n",
+ FuncName, usIndex));
+ }
+#endif
+
+ return ERROR_MON_INVALID_PARMS;
+ }
+ }
+
+ if ((pInBuffer == pOutBuffer) ||
+ ((pInBuffer < pOutBuffer) && ((pInBuffer + InSize) > pOutBuffer)) ||
+ ((pInBuffer > pOutBuffer) && (pInBuffer < (pOutBuffer + OutSize))))
+ {
+ /*
+ * Buffer operlap
+ */
+
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: buffer overlap %p(%d), %p(%d)\n",
+ FuncName, pInBuffer, *(PUSHORT)pInBuffer, pOutBuffer, *(PUSHORT) pOutBuffer));
+ }
+#endif
+
+ return ERROR_MON_INVALID_PARMS;
+ }
+
+ if (fPosition > MONITOR_SPECIEL_END)
+ {
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: unknown position %lx\n", FuncName, fPosition));
+ }
+#endif
+ return ERROR_MON_INVALID_PARMS;
+ }
+
+ if (RetCode = CHECK_HMON(hMon,
+ &hFileRecord,
+ #if DBG
+ FuncName,
+ #endif
+ TRUE))
+ {
+ return RetCode;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Mon.Request = MONReg;
+ Request.d.Mon.d.Reg.hMON = hFileRecord->NtHandle;
+ Request.d.Mon.d.Reg.Pos = fPosition;
+ Request.d.Mon.d.Reg.Index = usIndex;
+ Request.d.Mon.d.Reg.In = pInBuffer;
+ Request.d.Mon.d.Reg.InSize = InSize;
+ Request.d.Mon.d.Reg.Out = pOutBuffer;
+ Request.d.Mon.d.Reg.OutSize = OutSize;
+ Request.d.Mon.d.Reg.ProcessId = (ULONG)Od2Process->Pib.ProcessId;
+
+ SendMonConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ KdPrint(("%s: status %lx\n", FuncName, RetCode));
+#endif
+ return(RetCode);
+ }
+
+ *((PUSHORT)&(pInBuffer[2])) = (USHORT)(Request.d.Mon.d.Reg.InSize + 2);
+ *((PUSHORT)&(pOutBuffer[2])) = (USHORT)(Request.d.Mon.d.Reg.OutSize + 2);
+
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: hMon %lx was register\n", FuncName, hMon));
+ }
+#endif
+ return NO_ERROR;
+}
+
+
+APIRET
+DosMonWrite(IN PBYTE pOutBuffer,
+ IN PBYTE pDataBuf,
+ IN ULONG cbDataSize)
+{
+ APIRET RetCode;
+ SCREQUESTMSG Request;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosMonWrite";
+
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("<%u> %s: size %x\n",
+ (USHORT)(Od2CurrentThreadId()), FuncName, cbDataSize));
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ if (cbDataSize > MON_BUFFER_SIZE)
+ {
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: too long %x\n", FuncName, cbDataSize));
+ }
+#endif
+
+ cbDataSize = MON_BUFFER_SIZE;
+ }
+
+ try
+ {
+ RtlMoveMemory(Request.d.Mon.d.rwParms.ioBuff, pDataBuf, cbDataSize );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MON()
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Mon.Request = MONWrite;
+ Request.d.Mon.d.rwParms.Length = (USHORT)cbDataSize;
+ Request.d.Mon.d.rwParms.MonBuffer = pOutBuffer;
+ Request.d.Mon.d.rwParms.ProcessId = (ULONG)Od2Process->Pib.ProcessId;
+
+ SendMonConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ KdPrint(("%s: status %lx\n", FuncName, RetCode));
+#endif
+ return(RetCode);
+ }
+
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: data was written (length %x)\n", FuncName, cbDataSize));
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+CHECK_HMON(IN ULONG hMon,
+ OUT PFILE_HANDLE *hFileRecord,
+#if DBG
+ IN PSZ FuncName,
+#endif
+ IN ULONG ReleaseFlag)
+
+/*++
+
+Routine Description:
+
+ This routine check the legalty of Monitor handle
+ The routine cehck for: 1. legal handle, 2. handle of monitor type
+
+Arguments:
+
+ hMon - handle to check
+
+ hFileRecord - where to store pointer to file handle record
+
+ FuncName - name of calling API
+
+ ReleaseFlag - flag indicate if File lock must be released before return
+
+Return Value:
+
+ ERROR_MON_INVALID_HANDLE - handle is invalid
+
+Note:
+
+
+--*/
+
+{
+ APIRET RetCode;
+
+ AcquireFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ RetCode = DereferenceFileHandle((HFILE)hMon, hFileRecord);
+
+ if (RetCode || (*hFileRecord)->IoVectorType != MonitorVectorType)
+ {
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+
+#if DBG
+ IF_OD2_DEBUG(MON)
+ {
+ KdPrint(("%s: illegal MonitorHandle %lx\n", FuncName, hMon));
+ }
+#endif
+ return ERROR_MON_INVALID_HANDLE;
+ }
+
+ if (ReleaseFlag)
+ {
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ }
+
+ return NO_ERROR;
+}
diff --git a/private/os2/client/dllmou.c b/private/os2/client/dllmou.c
new file mode 100644
index 000000000..a50876496
--- /dev/null
+++ b/private/os2/client/dllmou.c
@@ -0,0 +1,1855 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllmou.c
+
+Abstract:
+
+ This module implements 32 equivalents of OS/2 V1.21
+ MOU API Calls.
+ The APIs are called from 16->32 thunks (i386\doscalls.asm).
+
+Author:
+
+ Michael Jarus (mjarus) 16-Dec-1991
+ (stubs)
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "conrqust.h"
+#if PMNT
+#define INCL_32BIT
+#include "pmnt.h"
+#endif
+
+#if DBG
+#define CHECK_HMOU(hMou, hFileRecord, RoutineName) \
+ AcquireFileLockExclusive(RoutineName); \
+ try \
+ { \
+ RetCode = DereferenceFileHandle((HFILE)hMou, &hFileRecord); \
+ } \
+ except( EXCEPTION_EXECUTE_HANDLER ) \
+ { \
+ Od2ExitGP(); \
+ } \
+ if ((RetCode != NO_ERROR) || \
+ (hFileRecord->IoVectorType != MouseVectorType)) \
+ { \
+ ReleaseFileLockExclusive(RoutineName); \
+ IF_OD2_DEBUG(MOU) \
+ { \
+ KdPrint(("%s: illegal FileHandle\n", RoutineName)); \
+ } \
+ if (RetCode) \
+ return RetCode; \
+ else \
+ return ERROR_BAD_COMMAND; \
+ } //return ERROR_MOUSE_INVALID_HANDLE
+#else
+#define CHECK_HMOU(hMou, hFileRecord) \
+ AcquireFileLockExclusive(); \
+ try \
+ { \
+ RetCode = DereferenceFileHandle((HFILE)hMou, &hFileRecord); \
+ } \
+ except( EXCEPTION_EXECUTE_HANDLER ) \
+ { \
+ Od2ExitGP(); \
+ } \
+ if ((RetCode != NO_ERROR) || \
+ (hFileRecord->IoVectorType != MouseVectorType)) \
+ { \
+ ReleaseFileLockExclusive(); \
+ if (RetCode) \
+ return RetCode; \
+ else \
+ return ERROR_BAD_COMMAND; \
+ } //return ERROR_MOUSE_INVALID_HANDLE
+#endif
+
+#define SET_MOU_REQUEST(s, R, hFileRecord) \
+ s.Request = R; \
+ s.hMOU = (HANDLE) hFileRecord->NtHandle;
+
+#if DBG
+#define CHECK_MOU_SUCCESS(RetCode) \
+ if ( RetCode ) \
+ { \
+ IF_OD2_DEBUG( MOU) \
+ KdPrint(("%s: status %lx\n", FuncName, RetCode)); \
+ return(RetCode); \
+ }
+#else
+#define CHECK_MOU_SUCCESS(RetCode) \
+ if ( RetCode ) \
+ { \
+ return(RetCode); \
+ }
+#endif
+
+#if DBG
+#define EXCEPTION_IN_MOU() \
+ { \
+ Od2ExitGP(); \
+ }
+
+#else
+#define EXCEPTION_IN_MOU() \
+ Od2ExitGP(); \
+
+#endif
+
+#if DBG
+#define SendMouCtrlConsoleRequest(Rc, Request) \
+ IF_OD2_DEBUG(MOU) \
+ { \
+ KdPrint(("SendMouCtrlConsoleRequest: Request %u\n", \
+ Request.d.Mou.Request)); \
+ } \
+ \
+ Request.Request = MouRequest; \
+ \
+ Rc = SendCtrlConsoleRequest(&Request, NULL, NULL, NULL); \
+
+#else
+#define SendMouCtrlConsoleRequest(Rc, Request) \
+ Request.Request = MouRequest; \
+ \
+ Rc = SendCtrlConsoleRequest(&Request, NULL, NULL, NULL);
+#endif
+
+
+
+
+APIRET
+MouReadEventQue(OUT PMOUEVENTINFO MouEvent,
+ IN PUSHORT Wait,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ LARGE_INTEGER TimeOut;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouReadEventQue";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx (wait %u)\n", FuncName, hMou, *Wait));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouReadEventQue()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Request.d.Mou.fWait = *Wait;
+ Od2ProbeForWrite(MouEvent, sizeof(MOUEVENTINFO), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ if ((*Wait != MOU_WAIT) && (*Wait != MOU_NOWAIT))
+ {
+ return ERROR_MOUSE_INVALID_IOWAIT;
+ //return ERROR_MOUSE_INV_PARMS;
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUReadEventQue, hFileRecord)
+
+ TimeOut.LowPart = 0L;
+ TimeOut.HighPart = 0L;
+
+ RetCode = Od2WaitForSingleObject( MouDataSemaphore,
+ (BOOLEAN)TRUE,
+ (*Wait == MOU_WAIT) ? NULL : &TimeOut);
+
+ if ( RetCode )
+ {
+ RtlZeroMemory(MouEvent, sizeof(MOUEVENTINFO));
+ return(ERROR_MOUSE_INVALID_HANDLE); /* =>BUGBUG fix the error code */
+ }
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ NtReleaseMutant(MouDataSemaphore, NULL);
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ *MouEvent = Request.d.Mou.d.MouInfo;
+
+#if DBG
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: event %u (%u:%u)\n", FuncName,
+ MouEvent->fs, MouEvent->row, MouEvent->col));
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MouFlushQue(IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouFlushQue";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouFlushQue()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUFlushQue, hFileRecord)
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MouClose(IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouClose";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouClose()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUClose, hFileRecord)
+ InvalidateHandle(hFileRecord);
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ if ( RetCode )
+ {
+ // BUGBUG=> what could happend ?
+#if DBG
+ IF_OD2_DEBUG( MOU )
+ KdPrint(("%s: status %lx\n", FuncName, RetCode));
+#endif
+ }
+
+ AcquireFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+ FreeHandle((HFILE)hMou);
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+MouDeRegister()
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouDeRegister";
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouDeRegister()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+MouDrawPtr(IN ULONG hMou)
+{
+#if DBG
+ PSZ FuncName;
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouDrawPtr()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+#if DBG
+ FuncName = "MouDrawPtr";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ UNSUPPORTED_API()
+ }
+#endif
+ return NO_ERROR;
+}
+
+
+APIRET
+MouGetDevStatus(OUT PUSHORT DevStatus,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouGetDevStatus";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouGetDevStatus()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForWrite(DevStatus, 2, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUGetDevStatus, hFileRecord)
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ *DevStatus = (USHORT)Request.d.Mou.d.Setup;
+#if DBG
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: returns Status %x\n", FuncName, *DevStatus));
+ }
+#endif
+ return NO_ERROR;
+}
+
+
+APIRET
+MouGetEventMask(OUT PUSHORT EventMask,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouGetEventMask";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouGetEventMask()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForWrite(EventMask, 2, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUGetEventMask, hFileRecord)
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ *EventMask = (USHORT)Request.d.Mou.d.Setup;
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MouGetNumButtons(OUT PUSHORT NumButtons,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouGetNumButtons";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouGetNumButtons()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForWrite(NumButtons, 2, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUGetNumButtons, hFileRecord)
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ *NumButtons = (USHORT)Request.d.Mou.d.Setup;
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MouGetNumMickeys(OUT PUSHORT NumMickeys,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouGetNumMickeys";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouGetNumMickeys()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForWrite(NumMickeys, 2, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUGetNumMickeys, hFileRecord)
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ *NumMickeys = (USHORT)Request.d.Mou.d.Setup;
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MouGetNumQueEl(OUT PMOUQUEINFO NumQueEl,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouGetNumQueEl";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouGetNumQueEl()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForWrite(NumQueEl, sizeof(PMOUQUEINFO), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUGetNumQueEl, hFileRecord)
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ *NumQueEl = Request.d.Mou.d.NumEvent;
+
+#if DBG
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: Size %u, EventNum %u\n",
+ FuncName, NumQueEl->cmaxEvents, NumQueEl->cEvents));
+ }
+#endif
+ return NO_ERROR;
+}
+
+
+APIRET
+MouGetPtrPos(OUT PPTRLOC PtrPos,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouGetPtrPos";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouGetPtrPos()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForWrite(PtrPos, sizeof(PTRLOC), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUGetPtrPos, hFileRecord)
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ *PtrPos = Request.d.Mou.d.Loc;
+
+#if DBG
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: returns Pos %u:%u\n",
+ FuncName, PtrPos->row, PtrPos->col));
+ }
+#endif
+ return NO_ERROR;
+}
+
+
+APIRET
+MouGetPtrShape(OUT PBYTE PtrMask,
+ OUT PPTRSHAPE PtrShape,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouGetPtrShape";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouGetPtrShape()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForWrite(PtrMask, sizeof(4), 1);
+ Od2ProbeForWrite(PtrShape, sizeof(PTRSHAPE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUGetPtrShape, hFileRecord)
+ Request.d.Mou.d.Shape = *PtrShape;
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ *PtrShape = Request.d.Mou.d.Shape;
+
+ //
+ // We return the default mask of OS/2 which is 0xffff, 0x7700
+ // so we don't have to use the lpc here.
+ //
+
+ *(USHORT *)PtrMask = 0xffff;
+ *(USHORT *)(PtrMask + 2) = 0x7700;
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MouGetScaleFact(OUT PSCALEFACT ScaleFact,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouGetScaleFact";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouGetScaleFact()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForWrite(ScaleFact, sizeof(SCALEFACT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUGetScaleFact, hFileRecord)
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ *ScaleFact = Request.d.Mou.d.ScalFact;
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MouOpen(IN PSZ DriveName,
+ OUT PUSHORT hMou)
+{
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ HANDLE Handle;
+ HFILE hFile;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouOpen";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering\n", FuncName));
+ }
+#endif
+
+ UNREFERENCED_PARAMETER(DriveName);
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouOpen()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForWrite(hMou, 2, 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+ //
+ // Allocate an Os2 Handle
+ //
+ AcquireFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ RetCode = AllocateHandle(&hFile);
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: unable to allocate FileHandle\n", FuncName));
+ }
+#endif
+
+ return RetCode;
+ }
+
+ RetCode = DevMouOpen(&Handle);
+
+ AcquireFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * handle return status (free handle if failed, validate if successed)
+ */
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( MOU )
+ KdPrint(("%s: status %lx\n", FuncName, RetCode));
+#endif
+
+ FreeHandle(hFile);
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+ return(RetCode);
+ }
+
+ hFileRecord = DereferenceFileHandleNoCheck(hFile);
+ //hFileRecord->Flags |= fsOpenMode & QFHSTATE_FLAGS;
+ hFileRecord->NtHandle = Handle;
+ //hFileRecord->FileType = FILE_TYPE_NMPIPE;
+ hFileRecord->IoVectorType = MouseVectorType;
+
+ //
+ // validate file handle
+ //
+
+ ValidateHandle(hFileRecord);
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ *hMou = (USHORT) hFile;
+
+#if DBG
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: returns %lx\n", FuncName, *hMou));
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MouRegister( IN PSZ pszModuleName,
+ IN PSZ pszEntryName,
+ IN ULONG fFunctions)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouRegister";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering\n", FuncName));
+ }
+#endif
+
+ UNREFERENCED_PARAMETER(pszModuleName);
+ UNREFERENCED_PARAMETER(pszEntryName);
+ UNREFERENCED_PARAMETER(fFunctions);
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouRegister()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+MouRemovePtr(IN PNOPTRRECT Rect,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouRemovePtr";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouRemovePtr()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForRead(Rect, sizeof(NOPTRRECT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+#if 0
+ /*
+ * check for invalid parameters
+ */
+
+ if (((SHORT) Rect->row < 0) || ((SHORT) Rect->cRow <0) ||
+ ((SHORT) Rect->col < 0) || ((SHORT) Rect->cCol <0) ||
+ (Rect->row > 49)|| (Rect->cRow > 49)||
+ (Rect->col > 79)|| (Rect->cCol > 79)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+ //
+ // upper bounds need to be corrected for the real screen size
+ //
+#endif
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOURemovePtr, hFileRecord)
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MouSetDevStatus(IN PUSHORT DevStatus,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouSetDevStatus";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx, Status %x\n",
+ FuncName, hMou, *DevStatus));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouSetDevStatus()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForRead(DevStatus, 2, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUSetDevStatus, hFileRecord)
+
+ Request.d.Mou.d.Setup = (ULONG) *DevStatus;
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MouSetEventMask(IN PUSHORT EventMask,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouSetEventMask";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouSetEventMask()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForRead(EventMask, 2, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUSetEventMask, hFileRecord)
+
+ Request.d.Mou.d.Setup = *EventMask;
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MouSetPtrPos(IN PPTRLOC PtrPos,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouSetPtrPos";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx, Pos %u:%u\n",
+ FuncName, hMou, PtrPos->row, PtrPos->col));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouSetPtrPos()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForRead(PtrPos, sizeof(PTRLOC), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+#if 0
+ /*
+ * check for invalid parameters
+ */
+
+ if (((SHORT) PtrPos->row < 0) || ((SHORT) PtrPos->col < 0) ||
+ (PtrPos->row > 49)|| (PtrPos->col > 79)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+ //
+ // upper bounds need to be corrected for the real screen size
+ //
+#endif
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUSetPtrPos, hFileRecord)
+
+ Request.d.Mou.d.Loc = *PtrPos;
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MouSetPtrShape(IN PBYTE PtrMask,
+ IN PPTRSHAPE PtrShape,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouSetPtrShape";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+ UNREFERENCED_PARAMETER(PtrMask);
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouSetPtrShape()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForRead(PtrShape, sizeof(PTRSHAPE), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUSetPtrShape, hFileRecord)
+ Request.d.Mou.d.Shape = *PtrShape;
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ return NO_ERROR;
+}
+
+
+APIRET
+MouSetScaleFact(IN PSCALEFACT ScaleFact,
+ IN ULONG hMou)
+{
+ SCREQUESTMSG Request;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouSetScaleFact";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouSetScaleFact()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ /*
+ * check parameter legalty
+ */
+
+ try
+ {
+ Od2ProbeForRead(ScaleFact, sizeof(SCALEFACT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_MOU()
+ }
+
+#if DBG
+ CHECK_HMOU(hMou, hFileRecord, FuncName)
+#else
+ CHECK_HMOU(hMou, hFileRecord)
+#endif
+
+ ReleaseFileLockExclusive(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+
+ /*
+ * check for invalid parameters
+ */
+
+ if (((SHORT) ScaleFact->rowScale < 0) || ((SHORT) ScaleFact->colScale < 0)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ SET_MOU_REQUEST(Request.d.Mou, MOUSetScaleFact, hFileRecord)
+
+ Request.d.Mou.d.ScalFact = *ScaleFact;
+
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ /*
+ * handle return status
+ */
+
+ CHECK_MOU_SUCCESS(RetCode)
+
+ return NO_ERROR;
+}
+
+
+APIRET
+DevMouOpen(OUT PHANDLE FileHandle)
+{
+ SCREQUESTMSG Request;
+ PSZ FuncName;
+ APIRET RetCode;
+
+ FuncName = "DevMouOpen";
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Mou.Request = MOUOpen;
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ *FileHandle = (HANDLE) Request.d.Mou.hMOU;
+ return(RetCode);
+}
+
+
+APIRET
+DevMouClose()
+{
+ SCREQUESTMSG Request;
+ PSZ FuncName;
+ APIRET RetCode;
+
+ FuncName = "DevMouClose";
+
+ /*
+ * prepare Message parameters & send request to server (OS2)
+ */
+
+ Request.d.Mou.Request = MOUClose;
+ SendMouCtrlConsoleRequest(RetCode, Request);
+
+ return(RetCode);
+}
+
+
+APIRET
+MouAllowPtrDraw(IN ULONG hMou)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouAllowPtrDraw";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+MouScreenSwitch(IN PBYTE pScreenGroup,
+ IN ULONG hMou)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouScreenSwitch";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: entering with %lx\n", FuncName, hMou));
+ }
+#endif
+
+ UNREFERENCED_PARAMETER(pScreenGroup);
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+MouSynch(IN ULONG fWait)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "MouSynch";
+
+ IF_OD2_DEBUG(MOU)
+ {
+ KdPrint(("%s: Wait %s-%lx\n",
+ FuncName, ( fWait ) ? "Yes" : "No", fWait));
+ }
+
+#endif
+
+#if PMNT
+ /*
+ * check for PM apps
+ */
+
+ if (ProcessIsPMApp()) {
+#if DBG
+ DbgPrint("Error: A PM application should not call MouSynch()\n");
+#endif
+ return(ERROR_MOU_EXTENDED_SG);
+ }
+#endif
+
+ return (ERROR_MOUSE_SMG_ONLY);
+}
+
+
diff --git a/private/os2/client/dllmsc16.c b/private/os2/client/dllmsc16.c
new file mode 100644
index 000000000..e743bd8be
--- /dev/null
+++ b/private/os2/client/dllmsc16.c
@@ -0,0 +1,506 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllmsc16.c
+
+Abstract:
+
+ This module implements 32 equivalents of Misc OS/2 V1.21
+ API Calls and 16b implementation service routines.
+ The APIs are called from 16->32 thunks (i386\doscalls.asm).
+
+
+Author:
+
+ Yaron Shamir (YaronS) 12-Apr-1991
+
+Revision History:
+
+ Patrick Questembert (PatrickQ) 20-Jul-1992
+ Add PM/NT API's
+
+--*/
+
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_TIMERS
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_NLS
+#include "os2dll.h"
+#include "os2dll16.h"
+#include <mi.h>
+#include <ldrxport.h>
+#include <stdlib.h>
+#if PMNT
+#define INCL_32BIT
+#include "pmnt.h"
+#endif
+
+extern ULONG SesGrpId;
+extern ULONG Od2SessionNumber;
+extern USHORT Od2GetFSSelector(VOID);
+extern ULONG Od2GlobalInfoSeg;
+extern BOOLEAN Od2SigHandAlreadyInProgress;
+SEL Od2GlobalInfoSel;
+#if PMNT
+BOOLEAN Od2GetInfoSegWasCalled = TRUE;
+#else
+BOOLEAN Od2GetInfoSegWasCalled;
+#endif
+
+BOOLEAN FPUinit_unmask = FALSE; // see Od216ApiPrint below
+
+#include "thunk\apilist.c" /* Generated automatically */
+
+#if DBG
+USHORT Os2DebugTID = 0x0;
+#endif
+
+VOID Od216ApiPrint(
+ ULONG ApiNumber
+ )
+{
+#if DBG
+ USHORT tid, pid;
+#endif
+ CONTEXT Context;
+
+ ((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->ApiIndex = ApiNumber-4;
+ //
+ // The current thread is in 32bit now. This flag will be used by
+ // implementation of critical section and thread suspend. During signal processing
+ // this flag isn't changed
+ //
+ if (!(Od2SigHandAlreadyInProgress && Od2CurrentThreadId() == 1) ) {
+ ((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Os2Tib.
+ MustCompleteForceFlag |= MCF_IN32BIT;
+ }
+
+#if DBG
+ IF_OD2_DEBUG ( APIS ) {
+ pid = (USHORT)(Od2Process->Pib.ProcessId);
+ tid = (USHORT)(Od2CurrentThreadId());
+
+ if ((Os2DebugTID == 0) || (Os2DebugTID == tid))
+ {
+ KdPrint(("[PID %d: TID %d] %s\n",
+ pid, tid, Od216ApiTable[(ApiNumber-4)/(sizeof(PSZ))]));
+ }
+ }
+#endif
+
+ //
+ // BUGBUG YS 5/31/92:
+ // This code fixes a weird sequence that the 16B runtime of SQL
+ // is performing - it unmasks the FPU exceptions, and then when
+ // a denormalize exception happens it goes and terminates the
+ // app. This unmasking happens in the C startup code (fpinit?)
+ // FPUinit_unmask starts FALSE, set to TRUE when DosDevConfig()
+ // is called to query for MATH coprocessor, if it is present.
+ // All this is a hack to work around the problem. We need to look
+ // closely why this denorm exception occurs.
+ //
+
+ if (FPUinit_unmask){
+ Context.ContextFlags = CONTEXT_FLOATING_POINT;
+ NtGetContextThread( NtCurrentThread(), &Context );
+ //
+ // 0x3f means that all exceptions are handled by the 387 itself
+ //
+ if ((Context.FloatSave.ControlWord & 0x3f) != 0x3f) {
+#if DBG
+ IF_OD2_DEBUG ( MISC ) {
+ KdPrint(("Thread Floating Point Exception Unmasked. Mask it. Thread %d, Mask was %x. Now 0x3f\n",
+ tid,(Context.FloatSave.ControlWord & 0x3f)));
+ }
+#endif
+ Context.FloatSave.ControlWord |= 0x3f;
+ NtSetContextThread( NtCurrentThread(), &Context );
+ FPUinit_unmask = FALSE;
+ }
+ }
+}
+
+ //
+ // A few interface routines for os2ses, to get at client structures
+ //
+PVOID IsOs2Thread()
+{
+ return (NtCurrentTeb()->EnvironmentPointer);
+}
+
+ULONG Od2ThreadId()
+{
+ return(Od2CurrentThreadId());
+
+}
+
+ULONG Od2ProcessId()
+{
+ return ((ULONG)Od2Process->Pib.ProcessId);
+}
+
+PSZ Od2ApplName()
+{
+ return (Od2Process->ApplName);
+}
+
+PSZ Od2GetLastAPI()
+{
+ ULONG i = ((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->ApiIndex;
+ if (i){
+ return (Od216ApiTable[(i)/(sizeof(PSZ))]);
+ }
+ else {
+ return("None");
+ }
+}
+ //
+ // We switch stacks between the 16 bit app code and the 32b
+ // flat system code. The following two routines are called
+ // by the thunks
+ //
+
+ULONG GetSaved32Esp()
+{
+return (((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Saved32Esp);
+}
+
+VOID Save32Esp( ULONG Esp)
+{
+ ((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Saved32Esp = Esp;
+ if (Od2CurrentThreadId() == 1) {
+ Od2Process->Pib.Saved32Esp = Esp;
+ }
+}
+
+BOOLEAN Save16Esp(VOID)
+{
+ //
+ // IMORTANT !!!
+ // This routine is used in thunk. EBX register must not be used inside it. This
+ // value will be used by signal handler as pointer to 16bit stackin the case
+ // that it will interrupt thread1 in thunk entry.
+ //
+ return ((USHORT)(Od2CurrentThreadId()) == 1);
+}
+
+APIRET
+DosCLIAccess(VOID)
+{
+ return(NO_ERROR);
+}
+
+APIRET
+DosPortAccess(IN ULONG ulReserved,
+ IN ULONG fRelease,
+ IN ULONG ulFirstPort,
+ IN ULONG ulLastPort)
+{
+ UNREFERENCED_PARAMETER(ulReserved);
+ UNREFERENCED_PARAMETER(fRelease);
+ UNREFERENCED_PARAMETER(ulFirstPort);
+ UNREFERENCED_PARAMETER(ulLastPort);
+#if DBG
+ KdPrint(("DosPortAccess not supported\n"));
+#endif
+ return(ERROR_NOT_SUPPORTED);
+}
+
+
+NTSTATUS
+Od2SetGlobalInfoSel()
+{
+ NTSTATUS Status;
+ SEL Sel;
+ I386DESCRIPTOR Desc;
+
+ //
+ // Set A Data segment selector in the LDT
+ //
+
+ Desc.BaseAddress = Od2GlobalInfoSeg;
+ Desc.Limit = sizeof(GINFOSEG) -1;
+ Desc.Type = READ_DATA;
+
+ //
+ // Apply tiling scheme
+ //
+ Sel = FLATTOSEL(Od2GlobalInfoSeg);
+ Status = Nt386SetDescriptorLDT (
+ NULL,
+ Sel,
+ Desc);
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(("Od2SetGlobalInfoSel: Error %lx Initializeing GlobalInfoSeg, Fail Loading\n", Status));
+ ASSERT( FALSE );
+#endif
+ return(Status);
+ }
+
+ Od2GlobalInfoSel = Sel;
+ return(STATUS_SUCCESS);
+}
+
+
+APIRET
+DosGetInfoSeg(
+ PSEL pselGlobal,
+ PSEL pselLocal
+ )
+{
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Entering DosGetInfoSeg.\n"));
+ }
+#endif
+
+ try {
+ *pselGlobal = Od2GlobalInfoSel;
+ *pselLocal = Od2GetFSSelector();
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ Od2GetInfoSegWasCalled = TRUE;
+ return (NO_ERROR);
+}
+
+
+APIRET
+DosGetMachineMode(
+ PBYTE pMachMode
+ )
+{
+
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Entering DosGetMachineMode.\n"));
+ }
+#endif
+ //
+ // probe pointer.
+ //
+
+ try {
+ *pMachMode = /* OS2_MODE */ 1; // YOSEFD Apr-1-1996 This define was removed
+ // from stdlib.h (\public\sdk\inc\crt).
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return (NO_ERROR);
+}
+
+APIRET
+DosGetVersion(
+ PUSHORT pVer
+ )
+{
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Entering DosGetVersion.\n"));
+ }
+#endif
+ //
+ // probe address pointer.
+ //
+
+ try {
+#ifdef JAPAN
+// MSKK Apr.05.1993 V-AkihiS
+// Return as V1.21
+ *pVer = 0x0A15;
+#else
+ *pVer = 0x0A1e;
+#endif
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return (NO_ERROR);
+}
+
+PVOID
+Od2GetTebInfoSeg(void)
+{
+
+return(&((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Os2Tib.LInfoSeg);
+
+}
+
+APIRET
+DosGetEnv(
+ PSEL pselEnv,
+ PUSHORT pOffsetCmd
+ )
+{
+ LINFOSEG *pLocalInfo;
+// PTEB Teb;
+// POS2_TIB Os2Tib;
+// APIRET rc;
+
+
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Entering DosGetEnv.\n"));
+ }
+#endif
+ //
+ // probe address pointer.
+ //
+
+ try {
+ pLocalInfo = (LINFOSEG *) Od2GetTebInfoSeg();
+// Teb = NtCurrentTeb();
+// Os2Tib = (POS2_TIB) Teb->NtTib.SubSystemTib;
+// pLocalInfo = (LINFOSEG *) &(Os2Tib->LInfoSeg),
+
+ *pselEnv = pLocalInfo->selEnvironment;
+ *pOffsetCmd = pLocalInfo->offCmdLine;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ return (NO_ERROR);
+}
+
+APIRET
+DosReturn(
+ ULONG param1,
+ ULONG param2
+ )
+{
+ UNREFERENCED_PARAMETER(param1);
+ UNREFERENCED_PARAMETER(param2);
+
+ return( NO_ERROR );
+}
+
+APIRET
+DosPTrace(
+ pPTRACEBUF pvTraceBuf
+ )
+{
+
+ APIRET rc;
+ OS2_API_MSG m;
+ pPTRACEBUF a = (pPTRACEBUF)(&(m.u.DosPTrace));
+ try {
+ Od2ProbeForWrite((PVOID)pvTraceBuf, sizeof(PTRACEBUF), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Entering DosPtrace.\n"));
+ }
+#endif
+
+ RtlMoveMemory((PVOID)a, pvTraceBuf, sizeof(PTRACEBUF));
+ rc = Od2CallSubsystem( &m, NULL, Os2Ptrace, sizeof( *a) );
+ //
+ // copy data and results back
+ //
+ RtlMoveMemory(pvTraceBuf, (PVOID)a, sizeof(PTRACEBUF));
+ return(rc);
+}
+
+APIRET
+DosQSysInfo(
+ IN ULONG SysInfoIndex,
+ OUT PSHORT Buffer,
+ IN ULONG Length
+ )
+{
+ //
+ // Validate the input parameters
+ //
+
+ if (SysInfoIndex != 0) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ if (Length < 2) {
+ return( ERROR_BUFFER_OVERFLOW );
+ }
+
+ //
+ // Get the requested information into the Value local varible.
+ //
+
+ try {
+ Od2ProbeForWrite(Buffer, Length, 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Bogus path limitations inheritied from OS/2. Our implementation
+ // does not have any limitations, other than available memory. But
+ // tell them what they expect to hear from OS/2 anyway.
+ //
+
+ *Buffer = CCHMAXPATH;
+
+ //
+ // Return success
+ //
+
+ return( NO_ERROR );
+}
+
+void
+Od2UpdateLocalInfoAtStart()
+{
+ POS2_TIB Tib;
+ LINFOSEG *pLocalInfo;
+ ldrrei_t *pexecinfo;
+
+ Tib = &((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Os2Tib;
+
+ //
+ // Set Local Information Fields
+ //
+ pLocalInfo = (LINFOSEG *) &(Tib->LInfoSeg),
+ pexecinfo = (PVOID) LDRExecInfo;
+#ifdef PMNT
+ // we do not know whether a process is a PM Process
+ // until loading terminates
+ // 1st thread fields are determined here (see Od2InitializeThread())
+ // Note: PMSHELL has typeProcess & sgCurrent of a PM Process under PM\NT,
+ // but not under OS2 native
+ if (ProcessIsPMProcess()) {
+ pLocalInfo->sgCurrent = (USHORT)(32 + Od2SessionNumber); //PQ - see PMWIN\wininit1.c, this is SGID_PM
+ // and all PM processes have a session number
+ // above or equal to this number
+ pLocalInfo->typeProcess = 3; // Indicates a PM process
+ }
+ else {
+ pLocalInfo->sgCurrent = (USHORT)Od2SessionNumber; // What's a more appropriate value?
+ pLocalInfo->typeProcess = 0; // BUGBUG - BRIEF3.1 for Beta 1 YS. PT_WINDOWABLEVIO; // meaning windowed, protected mode
+ }
+#endif
+ pLocalInfo->selEnvironment = pexecinfo->ei_envsel;
+ pLocalInfo->offCmdLine = pexecinfo->ei_comoff;
+ pLocalInfo->cbDataSegment = pexecinfo->ei_dgroupsize;
+ pLocalInfo->cbStack = pexecinfo->ei_stacksize;
+ pLocalInfo->cbHeap = pexecinfo->ei_heapsize;
+ pLocalInfo->hmod = pexecinfo->ei_hmod;
+ pLocalInfo->selDS = pexecinfo->ei_ds;
+ pLocalInfo->tidCurrent = (USHORT)(Od2CurrentThreadId());
+ Tib->LInfoSeg.IsRealTEB = 0;
+
+ return;
+}
diff --git a/private/os2/client/dllmsg.c b/private/os2/client/dllmsg.c
new file mode 100644
index 000000000..b577c480e
--- /dev/null
+++ b/private/os2/client/dllmsg.c
@@ -0,0 +1,1424 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllmsg.c
+
+Abstract:
+
+ This module implements the Message OS/2 V2.0 API Calls
+
+Author:
+
+ Steve Wood (stevewo) 20-Sep-1989
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_ERRORMSG
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_NLS
+
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "conrqust.h"
+#ifdef DBCS
+// MSKK Oct.29.1993 V-AkihIS
+#include "os2win.h"
+#endif
+#include <stdio.h>
+#ifdef DBCS
+// MSKK Jun.16.1993 V-AkihiS
+//
+// OS/2 internal multibyte string function.
+//
+#include "dlldbcs.h"
+#define strpbrk Od2MultiByteStrpbrk
+#define strchr Od2MultiByteStrchr
+#define strrchr Od2MultiByteStrrchr
+#endif
+
+
+
+BOOLEAN
+Od2FindMessageInRam(
+ IN PSZ MsgPathName,
+ IN ULONG MsgNumber,
+ IN PBYTE pMsgSeg,
+ OUT PSZ *MsgText,
+ OUT PULONG MsgLen,
+ IN OUT PSZ CompId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches a program's message segment for the message. This is done before the file
+ is searched for. Currently, this routine only works with os/2 1.x 16 bit segments, since the
+ format of 2.x segments was not available at the time of writing.
+
+ This code was adapted from the assembler sources of DosTrueGetMessage() in OS/2.
+
+ A description of how OS/2 handles ram messages:
+
+ The user calls DosGetMessage() without the 8th parameter which is the pointer to the message segment.
+ The linker then modifies this call as follows: it adds a message segment to the executable. It
+ modifies the DosGetMessage() call to call inside a small piece of code in the message segment. This
+ code pushes the 8th parameter (pointer to the message segment) on the stack, and calls the real
+ OS/2 API which is called DosTrueGetMessage(). This API expects this 8th parameter pointing to the
+ msg segment to already exist. Since this "thunk" process is done internally in the OS/2 program code,
+ our OS2SS DosTrueGetMessage() function also receives this 8th parameter on the stack.
+
+ A general description of the format of an os/2 1.x message segment:
+
+ 10 byte signature ("\xffMKMSGSEG")
+ 2 byte version number (should be 1)
+ 2 reserved bytes
+ 2 byte offset of the start of the file table
+ <now comes the small piece of code mentioned earlier>
+ now comes the file table:
+ 2 byte count of the number of files supported in the message segment.
+ table of 2-byte offsets pointing to the file names.
+ table of 2-byte offsets pointing to each file's message table.
+ text of null-terminated file names.
+ now, for each file supported, there is a message table in the following format:
+ 3 byte component ID name
+ 2-byte count of # of msgs from the file contained in the segment
+ table of 2-byte offsets pointing to each message entry in the table
+ now come the message entries, each one of the following format:
+ 2-byte message ID
+ 2-byte message length (including severity byte)
+ message text (not null-terminated, first byte is severity).
+
+Arguments:
+
+ MsgPathName -- supplies pathname of messagefile containing the wanted message.
+ MsgNumber -- supplies the message number in the file to search for.
+ pMsgSeg -- a pointer to the 16 bit message segment
+ MsgText -- returns a pointer to the message text in the ram segement (including severity character).
+ MsgLen -- returns the length of the string in MsgText
+ CompId -- supplies a pointer to a buffer of length at least COMP_ID_LEN. if message is found in ram,
+ returns the component ID.
+
+Return Value:
+
+ TRUE -- Message was successfully located in RAM. In this case, MsgText,
+ MsgLen and CompID are valid.
+ FALSE -- Unable to locate message in RAM.
+
+--*/
+
+{
+ PMSGSEGMENT_HEADER16 pHeader = (PMSGSEGMENT_HEADER16) pMsgSeg;
+ PSZ MsgFileName, FileNamePtr, CurrentMsgPtr;
+ PBYTE TablePtr;
+ USHORT FileCount, MsgCount, i;
+ PUSHORT WordPtr, CurrentMsgHdrPtr;
+
+ try {
+
+ //
+ // if it's the system msg file -- skip ram search
+ //
+
+ if (_stricmp(MsgPathName, OD2_MESSAGE_RESOURCE_FILENAME) == 0) {
+ return(FALSE);
+ }
+
+ //
+ // get last component of msg file path name
+ //
+
+ MsgFileName = strrchr(MsgPathName, '\\');
+ if (MsgFileName != NULL) {
+ MsgFileName++;
+ } else if ((MsgFileName = strrchr(MsgPathName, ':')) != NULL) {
+ MsgFileName++;
+ } else {
+ MsgFileName = MsgPathName;
+ }
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ try {
+ Od2ProbeForRead(pHeader, sizeof(pHeader), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ return(FALSE);
+ }
+
+ if (pHeader->Signature[0] != 0xff ||
+ strncmp(pHeader->Signature + 1, "MKMSGSEG", 9) != 0 ||
+ pHeader->Version != 1) {
+ return(FALSE);
+ }
+
+ WordPtr = (PUSHORT) (pMsgSeg + pHeader->FileTableOffset);
+
+ try {
+ FileCount = *WordPtr++;
+ if (FileCount == 0) {
+ return(FALSE);
+ }
+ Od2ProbeForRead(WordPtr, 2 * FileCount * sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ for (i = 0; i < FileCount; i++) {
+ FileNamePtr = (PSZ) (pMsgSeg + WordPtr[i]);
+ try {
+ if (_stricmp(MsgFileName, FileNamePtr) == 0) {
+ break;
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ }
+
+ if (i == FileCount) {
+ return(FALSE);
+ }
+
+ TablePtr = pMsgSeg + WordPtr[i + FileCount];
+
+ try {
+ RtlMoveMemory(CompId, TablePtr, COMP_ID_LEN);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ WordPtr = (PUSHORT) (TablePtr + COMP_ID_LEN);
+
+ try {
+ MsgCount = *WordPtr++;
+ Od2ProbeForRead(WordPtr, MsgCount * sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ for (i = 0; i < MsgCount; i++) {
+ CurrentMsgHdrPtr = (PUSHORT) (pMsgSeg + WordPtr[i]);
+ try {
+ if ((ULONG) (CurrentMsgHdrPtr[0]) != MsgNumber) {
+ continue;
+ }
+
+ *MsgLen = (ULONG) (CurrentMsgHdrPtr[1]);
+ CurrentMsgPtr = (PSZ) (CurrentMsgHdrPtr + 2);
+ Od2ProbeForRead(CurrentMsgPtr, *MsgLen, 1);
+ *MsgText = CurrentMsgPtr;
+
+ return(TRUE);
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ }
+ return(FALSE);
+}
+
+APIRET
+Od2FindMessageFile(
+ IN PSZ MessageFileName,
+ OUT POD2_MSGFILE *ReturnedMsgFile
+ )
+{
+ APIRET rc;
+ PLIST_ENTRY ListHead, ListNext;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE File;
+ IO_STATUS_BLOCK IoStatus;
+ HANDLE Section;
+ POD2_MSGFILE MsgFile;
+ ULONG CountBytes;
+ POD2_MSGFILE_HEADER MsgFileHeader;
+ POD2_MSGFILE_HEADER16 MsgFileHeader16;
+ STRING MessageFileString;
+ UNICODE_STRING MessageFileString_U;
+ ULONG MessageFileFlags;
+ ULONG MessageFileType;
+ FILE_STANDARD_INFORMATION StdInfo;
+ BOOL Od2MsgFileFlag = FALSE;
+ CHAR SystemMessageFileName[CCHMAXPATH];
+ CHAR FoundMessageFileName[CCHMAXPATH];
+ CHAR SearchPath[1024];
+ ULONG LangId;
+ PSZ PathPtr;
+
+ //
+ // See if requesting a message from the system message file (OSO001.MSG).
+ // If so, then just return that message file that was created during
+ // process initialization.
+ //
+
+ try {
+ if (!_stricmp( MessageFileName, OD2_MESSAGE_RESOURCE_FILENAME ))
+ {
+ if (Od2MsgFile != NULL)
+ {
+ *ReturnedMsgFile = Od2MsgFile;
+ return( NO_ERROR );
+ }
+
+#ifdef DBCS
+// MSKK Nov.12.1992 V-AkihiS
+// Change message file acording to current code page.
+ if (SesGrp->DosCP == SesGrp->PrimaryCP || SesGrp->DosCP == 0)
+ {
+ LangId = SesGrp->LanguageID;
+ } else if (SesGrp->DosCP == SesGrp->SecondaryCP)
+ {
+ LangId = LANG_ENGLISH;
+ } else {
+ LangId = SesGrp->LanguageID;
+ }
+#else
+ LangId = SesGrp->LanguageID;
+#endif
+ if (LangId > 999)
+ {
+#ifdef JAPAN
+// MSKK Jun.16.1993 V-AkihiS
+ LangId = LANG_JAPANESE;
+#else
+ LangId = LANG_ENGLISH;
+#endif
+ }
+ sprintf(SystemMessageFileName, "%s\\os2\\oso001.%3.3u",
+ Od2SystemRoot, LangId);
+ MessageFileName = SystemMessageFileName;
+ Od2MsgFileFlag = TRUE;
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Order to search:
+ //
+ // - message resource (Call DosGetResource)
+ //
+ // If not found there then constuct a search path with the following
+ // components and search that for the file name.
+ // - root directory of boot drive
+ // - current directory
+ // - DPATH environment variable
+ //
+
+ //
+ // Check if the message file name is fully specified (i.e. it includes
+ // a drive or path name).
+ //
+
+ if (strpbrk(MessageFileName, ":/\\") != NULL) {
+ strcpy(FoundMessageFileName, MessageFileName);
+ }
+ else {
+ SearchPath[0] = '\\';
+ SearchPath[1] = ';';
+ SearchPath[2] = '.';
+ SearchPath[3] = '\0';
+ //
+ // Expand Path elements without root dir but with current dir
+ //
+ rc = DosScanEnv("DPATH", &PathPtr);
+ if (rc == NO_ERROR) {
+ SearchPath[3] = ';'; // after the "\;."
+ strncpy(&SearchPath[4], PathPtr, sizeof(SearchPath)-5); // after the "\;.;"
+ SearchPath[sizeof(SearchPath)-1] = '\0'; // just to be safe
+ }
+ rc = DosSearchPath(SEARCH_PATH, SearchPath, MessageFileName,
+ FoundMessageFileName, sizeof(FoundMessageFileName)
+ );
+ if (rc != NO_ERROR) {
+ return(ERROR_FILE_NOT_FOUND);
+ }
+ }
+
+ //
+ // Canonicalize message file name
+ //
+
+ rc = Od2Canonicalize( FoundMessageFileName,
+ CANONICALIZE_FILE_OR_DEV,
+ &MessageFileString,
+ NULL,
+ &MessageFileFlags,
+ &MessageFileType
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ Section = NULL;
+ MsgFile = NULL;
+
+ if (MessageFileType != FILE_TYPE_FILE) {
+ rc = ERROR_ACCESS_DENIED;
+ }
+
+ if (MessageFileFlags != 0) {
+ rc = ERROR_PATH_NOT_FOUND;
+ }
+
+ if (rc != NO_ERROR) {
+ goto ErrorExit;
+ }
+
+ //
+ // Here with a fully qualified name. Search the list of message files
+ // that we have mapped already and see if it is there. If so, then
+ // just return the base address of the mapped file.
+ //
+
+ if (!Od2MsgFileFlag)
+ {
+ ListHead = &Od2Process->MsgFileList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ MsgFile = CONTAINING_RECORD( ListNext, OD2_MSGFILE, Link );
+ if (RtlEqualString( &MessageFileString, &MsgFile->FileName, TRUE )) {
+ *ReturnedMsgFile = MsgFile;
+ goto ErrorExit;
+ return( NO_ERROR );
+ }
+
+ ListNext = ListNext->Flink;
+ }
+ }
+
+ //
+ // This is the first time the message file has been referenced by this
+ // process, so open the file, create a section for it and map a view of
+ // the section. We can close the file after the section has been
+ // created as it will not go away until the section is closed, which
+ // wont happen until process death.
+ //
+
+ //
+ // UNICODE conversion -
+ //
+
+ rc = Od2MBStringToUnicodeString(
+ &MessageFileString_U,
+ &MessageFileString,
+ TRUE);
+
+ if (rc)
+ {
+#if DBG
+// DbgPrint("Od2FindMessageFile: no memory for Unicode Conversion\n");
+#endif
+ RtlFreeHeap( Od2Heap, 0, MessageFileString.Buffer );
+ return rc;
+ }
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &MessageFileString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+ Status = NtOpenFile( &File,
+ SYNCHRONIZE | FILE_READ_DATA,
+ &ObjectAttributes,
+ &IoStatus,
+ FILE_SHARE_READ,
+ 0
+ );
+ if (!NT_SUCCESS( Status ))
+ {
+ rc = Or2MapStatus( Status );
+
+ //
+ // change to correct error msg in case of sharing violation
+ //
+
+ if (rc == ERROR_SHARING_VIOLATION) {
+ rc = ERROR_MR_UN_ACC_MSGF;
+ }
+
+ //
+ // Maybe be try system message file, which is not english
+ // but we have the english file on our machine.
+ //
+ if (( rc == ERROR_FILE_NOT_FOUND ) && Od2MsgFileFlag &&
+#ifdef JAPAN
+// MSKK Jun.16.1993 V-AkihiS
+ ( LangId != LANG_JAPANESE ))
+#else
+ ( LangId != LANG_ENGLISH ))
+#endif
+ {
+#ifdef JAPAN
+// MSKK Jul.29.1993 V-AKihIS
+ LangId = LANG_JAPANESE;
+ MessageFileString_U.Buffer[MessageFileString_U.Length - 3] = '0';
+ MessageFileString_U.Buffer[MessageFileString_U.Length - 2] =
+ '0' + ((LANG_JAPANESE & 0xF0) >> 4);
+ MessageFileString_U.Buffer[MessageFileString_U.Length - 1] =
+ '0' + (LANG_JAPANESE & 0x0F);
+#else
+ LangId = LANG_ENGLISH;
+ MessageFileString_U.Buffer[MessageFileString_U.Length - 3] = '0';
+ MessageFileString_U.Buffer[MessageFileString_U.Length - 2] =
+ '0' + ((LANG_ENGLISH & 0xF0) >> 4);
+ MessageFileString_U.Buffer[MessageFileString_U.Length - 1] =
+ '0' + (LANG_ENGLISH & 0x0F);
+#endif
+ Status = NtOpenFile( &File,
+ SYNCHRONIZE | FILE_READ_DATA,
+ &ObjectAttributes,
+ &IoStatus,
+ FILE_SHARE_READ,
+ 0
+ );
+ if (!NT_SUCCESS( Status ))
+ {
+ rc = Or2MapStatus( Status );
+ RtlFreeUnicodeString (&MessageFileString_U);
+ goto ErrorExit;
+ }
+ } else
+ {
+ RtlFreeUnicodeString (&MessageFileString_U);
+ goto ErrorExit;
+ }
+ }
+ RtlFreeUnicodeString (&MessageFileString_U);
+
+ Status = NtQueryInformationFile(File,
+ &IoStatus,
+ &StdInfo,
+ sizeof (StdInfo),
+ FileStandardInformation);
+ if (!NT_SUCCESS( Status )) {
+ rc = Or2MapStatus( Status );
+ goto ErrorExit;
+ }
+
+ //
+ // Create a memory section backed by the opened message file
+ //
+
+ Status = NtCreateSection( &Section,
+ SECTION_MAP_READ,
+ NULL,
+ NULL,
+ PAGE_READONLY,
+ SEC_COMMIT,
+ File
+ );
+ NtClose( File );
+ if ( !NT_SUCCESS( Status ) ) {
+ rc = Or2MapStatus( Status );
+ goto ErrorExit;
+ }
+
+ CountBytes = sizeof( OD2_MSGFILE ) + MessageFileString.Length + 1;
+ MsgFile = RtlAllocateHeap( Od2Heap, 0, CountBytes );
+ if (MsgFile == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto ErrorExit;
+ }
+
+ MsgFile->BaseAddress = 0;
+ MsgFile->Size = 0;
+ MsgFile->SectionHandle = Section;
+ MsgFile->FileName.Length = MessageFileString.Length;
+ MsgFile->FileName.MaximumLength = MessageFileString.Length;
+ MsgFile->FileName.Buffer = (PCH)(MsgFile+1);
+ MsgFile->Type = MSG_FILE_TYPE_OS2_20;
+ RtlMoveMemory( MsgFile->FileName.Buffer,
+ MessageFileString.Buffer,
+ MessageFileString.Length
+ );
+
+ Status = NtMapViewOfSection( Section,
+ NtCurrentProcess(),
+ &MsgFile->BaseAddress,
+ 0,
+ 0,
+ NULL,
+ &MsgFile->Size,
+ /*
+ Value in MsgFile->Size is a multiple of 0x1000
+ and is changed later to match the true size of the
+ msg file.
+ */
+ ViewUnmap,
+ 0,
+ PAGE_READONLY
+ );
+ if (!NT_SUCCESS( Status )) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto ErrorExit;
+ }
+
+ /* Fix the size of the file with the true size */
+ MsgFile->Size = StdInfo.EndOfFile.LowPart;
+
+ MsgFileHeader = (POD2_MSGFILE_HEADER)MsgFile->BaseAddress;
+ MsgFileHeader16 = (POD2_MSGFILE_HEADER16)MsgFile->BaseAddress;
+ if ((MsgFileHeader->HeaderLength != FIELD_OFFSET( OD2_MSGFILE_HEADER,
+ MessageOffsets ) ||
+ strncmp( MsgFileHeader->Signature, "_NTMSGF", 7 ))
+ &&
+ ((MsgFileHeader16->HeaderMsgFF != 0xff) ||
+ (strncmp( MsgFileHeader16->Signature, "MKMSGF", 6 )))
+ ) {
+ NtUnmapViewOfSection( NtCurrentProcess(), MsgFile->BaseAddress );
+ RtlFreeHeap( Od2Heap, 0, MsgFile );
+ NtClose( Section );
+ return( ERROR_MR_INV_MSGF_FORMAT );
+ }
+
+ if (!strncmp( MsgFileHeader16->Signature, "MKMSGF", 6 )) {
+ MsgFile->Type = MSG_FILE_TYPE_OS2_1x;
+ }
+
+ if (Od2MsgFileFlag)
+ {
+ Od2MsgFile = RtlAllocateHeap( Od2Heap, 0, sizeof( OD2_MSGFILE ) );
+ if (Od2MsgFile == NULL)
+ {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto ErrorExit;
+ }
+ RtlMoveMemory( Od2MsgFile,
+ MsgFile,
+ sizeof( OD2_MSGFILE )
+ );
+ *ReturnedMsgFile = Od2MsgFile;
+ } else
+ {
+ InsertTailList( &Od2Process->MsgFileList, &MsgFile->Link );
+ *ReturnedMsgFile = MsgFile;
+ }
+
+ rc = NO_ERROR;
+
+ErrorExit:
+ if (MessageFileString.Buffer != NULL) {
+ RtlFreeHeap( Od2Heap, 0, MessageFileString.Buffer );
+ }
+
+ if (Section != NULL) {
+ NtClose( Section );
+ }
+
+ if ((rc != NO_ERROR) && (MsgFile != NULL)) {
+ RtlFreeHeap( Od2Heap, 0, MsgFile );
+ }
+
+ return( rc );
+}
+
+APIRET
+DosGetMessage(
+ IN PSZ Variables[],
+ IN ULONG CountVariables,
+ OUT PCHAR Buffer,
+ IN ULONG Length,
+ IN ULONG MessageNumber,
+ IN PSZ MessageFileName,
+ OUT PULONG MessageLength,
+ IN PBYTE pMsgSeg
+ )
+{
+ APIRET rc;
+ POD2_MSGFILE MsgFile;
+ PSZ Message, MessageBuffer, s;
+ CHAR MessageSeverity;
+ ULONG i, Offset;
+ ULONG LengthInFile, BufferLength;
+ CHAR CompId[COMP_ID_LEN];
+ BOOLEAN IsRamMsg;
+
+ //
+ // We start off by doing a search in the executable ram image for
+ // the message. pMsgSeg (if valid) is a pointer to the program's message
+ // segement. We currently only handle 16 bit os/2 1.x message segments.
+ //
+
+ IsRamMsg = Od2FindMessageInRam(MessageFileName,
+ MessageNumber,
+ pMsgSeg,
+ &Message,
+ &LengthInFile,
+ CompId);
+
+ if (IsRamMsg) {
+ goto RamSegProcessJunction; // found it, go process
+ }
+
+ //
+ // Otherwise, go search for the file.
+ //
+ // Get a pointer to the message file, mapped into memory. Return an
+ // error if not found or invalid format.
+ //
+
+ rc = Od2FindMessageFile( MessageFileName,
+ &MsgFile
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get a pointer to the message file header and validate the message
+ // number as being within range of the first and last message Id
+ // described by the message file. Return an error if it is not.
+ //
+
+ if (MsgFile->Type == MSG_FILE_TYPE_OS2_20) {
+
+ POD2_MSGFILE_HEADER MsgFileHeader;
+
+ MsgFileHeader = (POD2_MSGFILE_HEADER)MsgFile->BaseAddress;
+ if (MessageNumber < MsgFileHeader->BaseMessageId) {
+ return( ERROR_MR_MID_NOT_FOUND );
+ }
+ MessageNumber -= MsgFileHeader->BaseMessageId;
+ if (MessageNumber >= MsgFileHeader->CountOfMessages) {
+ return( ERROR_MR_MID_NOT_FOUND );
+ }
+
+
+ //
+ // Calculate a pointer to the actual message and calculate the length
+ // of the message as the difference between the offset of this message
+ // and the offset of the next message or end of file if retreiving the
+ // last message.
+ //
+
+ Offset = MsgFileHeader->MessageOffsets[ MessageNumber ];
+ Message = (PSZ)MsgFileHeader + Offset;
+ if (MessageNumber+1 == MsgFileHeader->CountOfMessages) {
+ LengthInFile = MsgFile->Size - Offset;
+ }
+ else {
+ LengthInFile = MsgFileHeader->MessageOffsets[ MessageNumber+1 ] -
+ Offset;
+ }
+
+
+ //
+ // Extract the first character of the message, which is the severity
+ // of the message. Return message not found if the severity is '?'
+ // as it marks a place holder for unused message numbers.
+ //
+
+ MessageSeverity = *Message;
+ if (MessageSeverity == '?') {
+ return( ERROR_MR_MID_NOT_FOUND );
+ }
+
+
+ //
+ // Allocate a buffer to hold a null terminated copy of the message,
+ // plus an extra 9 bytes in case we have to prefix the message with
+ // the error code ('W'arning and 'E'rror severity only).
+ //
+
+ MessageBuffer = RtlAllocateHeap( Od2Heap, 0, LengthInFile + COMP_ID_LEN + 6);
+ if (!MessageBuffer) {
+#if DBG
+ KdPrint(("Os2: DosGetMessage out of heap memory\n"));
+#endif
+ ASSERT( FALSE );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ s = MessageBuffer;
+
+
+ //
+ // If the severity of the message is 'W'arning or 'E'rror then copy the
+ // 3 character component id from the message file header, the 4 character
+ // ASCII representation of the message number and 2 trailing separator
+ // characters ": ". A total of 9 extra bytes.
+ //
+
+ if (MessageSeverity == 'W' || MessageSeverity == 'E') {
+ RtlMoveMemory( s, MsgFileHeader->Component, COMP_ID_LEN );
+ s += COMP_ID_LEN;
+ i = 4;
+ while (i--) {
+ s[ i ] = (CHAR)((MessageNumber % 10) + '0');
+ MessageNumber /= 10;
+ }
+ s += 4;
+ *s++ = ':';
+ *s++ = ' ';
+ BufferLength = COMP_ID_LEN + 6;
+ }
+ else {
+ BufferLength = 0;
+ }
+
+
+ //
+ // Now copy the message from the mapped message file into the allocated
+ // buffer and null terminate the message in the buffer. Remember not
+ // to include the message severity code.
+ //
+
+ RtlMoveMemory( s, ++Message, LengthInFile-1 );
+ s[ LengthInFile-1 ] = '\0';
+ BufferLength += LengthInFile - 1;
+ }
+
+ else /* (MsgFile->Type == MSG_FILE_TYPE_OS2_1x) */ {
+
+ POD2_MSGFILE_HEADER16 MsgFileHeader16;
+ POD2_MSGFILE_HEADER_SYS16 SysMsgFileHeader16;
+
+ MsgFileHeader16 = (POD2_MSGFILE_HEADER16)MsgFile->BaseAddress;
+ if (MessageNumber < (ULONG)(MsgFileHeader16->BaseMessageId)) {
+ return( ERROR_MR_MID_NOT_FOUND );
+ }
+ MessageNumber -= MsgFileHeader16->BaseMessageId;
+ if (MessageNumber >= (ULONG)(MsgFileHeader16->CountOfMessages)) {
+ return( ERROR_MR_MID_NOT_FOUND );
+ }
+
+
+ //
+ // Calculate a pointer to the actual message and calculate the length
+ // of the message as the difference between the offset of this message
+ // and the offset of the next message or end of file if retreiving the
+ // last message.
+ //
+ // For system message file always create ULONG offset of messages,
+ // so use OD2_MSGFILE_HEADER_SYS16 instaed of OD2_MSGFILE_HEADER16.
+ // change: mjarus - Aug 30, 1992.
+ //
+ // Correction: For "huge" message file the offset table is ULONG array
+ // so use OD2_MSGFILE_HEADER_SYS16 instaed of OD2_MSGFILE_HEADER16.
+ // This is determinated by the first byte of the Resered field (one
+ // for small files (USHORT array) and zero for huge files (ULONG array).
+ // change: mjarus - jan 12, 1993.
+ //
+ if(MsgFileHeader16->Reserved[0] == 0)
+ {
+ SysMsgFileHeader16 = (POD2_MSGFILE_HEADER_SYS16)MsgFileHeader16;
+ Offset = SysMsgFileHeader16->MessageOffsets[ MessageNumber ];
+ Message = (PSZ)SysMsgFileHeader16 + Offset;
+ if (MessageNumber+1 == (ULONG)(SysMsgFileHeader16->CountOfMessages)) {
+ LengthInFile = MsgFile->Size - Offset;
+ }
+ else { /* if(MsgFileHeader16->Reserved[0] == 1) */
+ LengthInFile = SysMsgFileHeader16->MessageOffsets[ MessageNumber+1 ] -
+ Offset;
+ }
+ } else
+ {
+ Offset = MsgFileHeader16->MessageOffsets[ MessageNumber ];
+ Message = (PSZ)MsgFileHeader16 + Offset;
+ if (MessageNumber+1 == (ULONG)(MsgFileHeader16->CountOfMessages)) {
+ LengthInFile = MsgFile->Size - Offset;
+ }
+ else {
+ LengthInFile = MsgFileHeader16->MessageOffsets[ MessageNumber+1 ] -
+ Offset;
+ }
+ }
+
+
+ //
+ // Extract the first character of the message, which is the severity
+ // of the message. Return message not found if the severity is '?'
+ // as it marks a place holder for unused message numbers.
+ //
+
+RamSegProcessJunction:
+
+ MessageSeverity = *Message;
+ if (MessageSeverity == '?') {
+ return( ERROR_MR_MID_NOT_FOUND );
+ }
+
+
+ //
+ // Allocate a buffer to hold a null terminated copy of the message,
+ // plus an extra 9 bytes in case we have to prefix the message with
+ // the error code ('W'arning and 'E'rror severity only).
+ //
+
+ MessageBuffer = RtlAllocateHeap( Od2Heap, 0, LengthInFile + COMP_ID_LEN + 6 );
+ if (!MessageBuffer) {
+#if DBG
+ KdPrint(("Os2: DosGetMessage out of heap memory\n"));
+#endif
+ ASSERT( FALSE );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ s = MessageBuffer;
+
+
+ //
+ // If the severity of the message is 'W'arning or 'E'rror then copy the
+ // 3 character component id from the message file header, the 4 character
+ // ASCII representation of the message number and 2 trailing separator
+ // characters ": ". A total of 9 extra bytes.
+ //
+
+ if (MessageSeverity == 'W' || MessageSeverity == 'E') {
+ RtlMoveMemory( s,
+ IsRamMsg ? CompId :
+ MsgFileHeader16->Component,
+ COMP_ID_LEN );
+ s += COMP_ID_LEN;
+ i = 4;
+ while (i--) {
+ s[ i ] = (CHAR)((MessageNumber % 10) + '0');
+ MessageNumber /= 10;
+ }
+ s += 4;
+ *s++ = ':';
+ *s++ = ' ';
+ BufferLength = COMP_ID_LEN + 6;
+ }
+ else {
+ BufferLength = 0;
+ }
+
+
+ //
+ // Now copy the message from the mapped message file into the allocated
+ // buffer and null terminate the message in the buffer. Remember not
+ // to include the message severity code.
+ //
+
+ RtlMoveMemory( s, ++Message, LengthInFile-1 );
+ s[ LengthInFile-1 ] = '\0';
+ BufferLength += LengthInFile - 1;
+ }
+
+ //
+ // Now call DosInsertMessage to process any insert strings and copy the
+ // resulting message into the caller's buffer.
+ //
+
+ rc = DosInsertMessage( Variables,
+ CountVariables,
+ MessageBuffer,
+ BufferLength,
+ Buffer,
+ Length,
+ MessageLength
+ );
+
+
+ //
+ // All done, free the message buffer and return any error code to the
+ // caller.
+ //
+
+ RtlFreeHeap( Od2Heap, 0, MessageBuffer );
+ return( rc );
+}
+
+APIRET
+DosInsertMessage(
+ IN PSZ Variables[],
+ IN ULONG CountVariables,
+ IN PCHAR Message,
+ IN ULONG MessageLength,
+ OUT PCHAR Buffer,
+ IN ULONG Length,
+ OUT PULONG ActualMessageLength
+ )
+{
+ UCHAR c, MaxInsert;
+ PUCHAR Src, Dst, InsSrc;
+ ULONG i, DstLength;
+
+ //
+ // May not specify more than 9 insert parameters. These correspond to
+ // %1 through %p in the input message string.
+ //
+
+ if (CountVariables > 9) {
+ return( ERROR_MR_INV_IVCOUNT );
+ }
+
+
+ //
+ // Calculate the character representation of the maximum %n value in the
+ // input message that will trigger an insertion.
+ //
+
+ MaxInsert = (UCHAR)('0' + CountVariables);
+
+
+ //
+ // Now copy the input message to the output buffer, looking for insert
+ // specifiers (%n) and making sure we do not overflow the output buffer.
+ //
+
+ Src = Message;
+ Dst = Buffer;
+ DstLength = 0;
+ try {
+ while (MessageLength != 0) {
+
+ //
+ // Get the next character from the input message
+ //
+
+ c = *Src++;
+ MessageLength--;
+
+
+ //
+ // If it is a percent sign ('%') and there is at least one more
+ // character in the input message and that character is a valid
+ // insert specifier based on the number of insertion strings passed
+ // to this functions (CountVariables), then do the insertion.
+ //
+
+ if (c == '%' && MessageLength && *Src > '0' && *Src <= MaxInsert) {
+
+ //
+ // Valid insertion specifier. Get the corresponding pointer
+ // to the string to insert and copy that string to the output
+ // buffer, making sure we do not overflow the output buffer.
+ // Skip over the insert specifier in the input message.
+ //
+
+ i = *Src++ - '1';
+ MessageLength--;
+ InsSrc = Variables[ i ];
+ while (c = *InsSrc++) {
+#ifdef DBCS
+// MSKK Mar.03.1993 V-AkihiS
+ if (Ow2NlsIsDBCSLeadByte(c, SesGrp->DosCP)) {
+ if (DstLength < Length-1) {
+ *Dst++ = c;
+ *Dst++ = *InsSrc++;
+ DstLength += 2;
+ } else {
+ *ActualMessageLength = DstLength;
+ return( ERROR_MR_MSG_TOO_LONG );
+ }
+ } else {
+ if (DstLength++ >= Length) {
+ *ActualMessageLength = Length;
+ return( ERROR_MR_MSG_TOO_LONG );
+ } else {
+ *Dst++ = c;
+ }
+ }
+#else
+ if (DstLength++ >= Length) {
+ *ActualMessageLength = Length;
+ return( ERROR_MR_MSG_TOO_LONG );
+ }
+ *Dst++ = c;
+#endif
+ }
+ }
+ else {
+
+ //
+ // Not an insert specifier, so copy this character into the output
+ // buffer, making sure we do not overflow the output buffer.
+ //
+
+#ifdef DBCS
+// MSKK Mar.03.1993 V-AkihiS
+ if (IsDBCSLeadByte(c)) {
+ if (DstLength < Length-1) {
+ *Dst++ = c;
+ *Dst++ = *Src++;
+ MessageLength--;
+ DstLength += 2;
+ } else {
+ *ActualMessageLength = DstLength;
+ return( ERROR_MR_MSG_TOO_LONG );
+ }
+ } else {
+ if (DstLength++ >= Length) {
+ *ActualMessageLength = Length;
+ return( ERROR_MR_MSG_TOO_LONG );
+ } else {
+ *Dst++ = c;
+ }
+ }
+#else
+ if (DstLength++ >= Length) {
+ *ActualMessageLength = Length;
+ return( ERROR_MR_MSG_TOO_LONG );
+ }
+ *Dst++ = c;
+#endif
+ }
+ }
+
+ //
+ // Success, return the actual length of the message written to the output
+ // buffer.
+ //
+
+ *ActualMessageLength = DstLength;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return( NO_ERROR );
+}
+
+
+APIRET
+DosPutMessage(
+ IN HFILE FileHandle,
+ IN ULONG MessageLength,
+ IN PCHAR Message
+ )
+{
+#ifdef DBCS
+// MSKK Apr.22.1993 V-AkihiS
+//
+// Bug fix. Handle DBCS.
+//
+ PCHAR sPrev, sCurrent;
+ ULONG Discard;
+ BOOL IsFlushed;
+ USHORT PrevPosition;
+ APIRET rc;
+
+ sCurrent = sPrev = Message;
+ PrevPosition = 0;
+ try {
+ while (sCurrent < Message + MessageLength) {
+ if (sCurrent[0] == '\r' && sCurrent[1] == '\n') {
+ if ((PrevPosition + (sCurrent - sPrev)) >= 79) {
+ //
+ // If a wordwrap is needed, write CR+LF.
+ //
+ rc = DosWrite( FileHandle,
+ (PVOID)"\r\n",
+ 2,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+ }
+
+ //
+ // Write charaters from previous position to CR+LF.
+ //
+ sCurrent += 2;
+ rc = DosWrite( FileHandle,
+ (PVOID)sPrev,
+ sCurrent - sPrev,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+ IsFlushed = TRUE;
+ sPrev = sCurrent;
+ PrevPosition = 0;
+ } else if (*sCurrent == ' ') {
+ if ((PrevPosition + (sCurrent - sPrev)) >= 79) {
+ //
+ // If a wordwrap is needed, write CR+LF.
+ //
+ rc = DosWrite( FileHandle,
+ (PVOID)"\r\n",
+ 2,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+
+ PrevPosition = 0;
+ }
+
+ //
+ // Write charaters from previous position to
+ // current position.
+ //
+ rc = DosWrite( FileHandle,
+ (PVOID)sPrev,
+ sCurrent - sPrev + 1,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+ IsFlushed = TRUE;
+ PrevPosition += (sCurrent - sPrev + 1);
+ sPrev = ++sCurrent;
+ } else if (Ow2NlsIsDBCSLeadByte(*sCurrent, SesGrp->DosCP)) {
+ if ((PrevPosition + (sCurrent - sPrev)) >= 79) {
+ //
+ // If a wordwrap is needed, write CR+LF.
+ //
+ rc = DosWrite( FileHandle,
+ (PVOID)"\r\n",
+ 2,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+
+ PrevPosition = 0;
+ }
+
+ if (sCurrent != sPrev) {
+ //
+ // Write charaters from previous position to
+ // (current position - 1).
+ //
+ rc = DosWrite( FileHandle,
+ (PVOID)sPrev,
+ sCurrent - sPrev,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+ }
+
+ if ((PrevPosition + (sCurrent - sPrev) + 2) >= 79) {
+ //
+ // In this case, there is no space to write DBCS
+ // character(Consider CR+LF space).
+ // So DBCS character should be written in next line.
+ //
+
+ rc = DosWrite( FileHandle,
+ (PVOID)"\r\n",
+ 2,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+ PrevPosition = 2;
+ } else {
+ PrevPosition += (sCurrent - sPrev + 2);
+ }
+
+ if (*(sCurrent+1)) {
+ //
+ // Write DBCS character.
+ //
+ rc = DosWrite( FileHandle,
+ (PVOID)sCurrent,
+ 2,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+ sCurrent += 2;
+ } else {
+ //
+ // Write character.
+ //
+ rc = DosWrite( FileHandle,
+ (PVOID)sCurrent,
+ 1,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+ sCurrent ++;
+ }
+ sPrev = sCurrent;
+ IsFlushed = TRUE;
+ } else {
+ //
+ // if charater is SBCS, only increment the pointer
+ // which indicates the current position in message
+ // string.
+ //
+ IsFlushed = FALSE;
+ sCurrent++;
+ }
+ }
+
+ //
+ // If all of message are not written, flush them.
+ //
+ if (!IsFlushed) {
+ if ((PrevPosition + (sCurrent - sPrev)) >= 79) {
+ rc = DosWrite( FileHandle,
+ (PVOID)"\r\n",
+ 2,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+ }
+ rc = DosWrite( FileHandle,
+ (PVOID)sPrev,
+ sCurrent - sPrev,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ return( NO_ERROR );
+#else
+ PCHAR sStart, sBlank, sCurrent, sEnd;
+ ULONG Discard;
+ APIRET rc;
+
+ sBlank = sStart = sCurrent = Message;
+ sEnd = sCurrent + MessageLength;
+ rc = NO_ERROR;
+ try {
+ while (sCurrent < sEnd) {
+ if (sCurrent[ 0 ] == '\r' && sCurrent[ 1 ] == '\n') {
+ if ((sCurrent - sStart) >= 80) {
+ rc = DosWrite( FileHandle,
+ (PVOID)sStart,
+ sBlank - sStart + 1,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+
+ rc = DosWrite( FileHandle,
+ (PVOID)"\r\n",
+ 2,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+
+ sStart = sCurrent = sBlank + 1;
+ }
+ else {
+ sCurrent += 2;
+ rc = DosWrite( FileHandle,
+ (PVOID)sStart,
+ sCurrent - sStart,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+
+ sStart = sBlank = sCurrent;
+ }
+ }
+ else
+ if (*sCurrent == ' ')
+ {
+ if ((sCurrent - sStart) >= 80) {
+ rc = DosWrite( FileHandle,
+ (PVOID)sStart,
+ sBlank - sStart + 1,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+
+ rc = DosWrite( FileHandle,
+ (PVOID)"\r\n",
+ 2,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+
+ sStart = sCurrent = sBlank + 1;
+ }
+ else {
+ sBlank = sCurrent++;
+ }
+ }
+ else {
+ sCurrent++;
+ }
+ }
+
+ if (sCurrent > sStart) {
+ if ((sCurrent - sStart) >= 80) {
+ rc = DosWrite( FileHandle,
+ (PVOID)sStart,
+ sBlank - sStart + 1,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+
+ rc = DosWrite( FileHandle,
+ (PVOID)"\r\n",
+ 2,
+ &Discard
+ );
+ if (rc != NO_ERROR) {
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+ }
+
+ sStart = sCurrent = sBlank + 1;
+ }
+
+ rc = DosWrite( FileHandle,
+ (PVOID)sStart,
+ sCurrent - sStart,
+ &Discard
+ );
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ return( (rc == ERROR_ACCESS_DENIED) ? ERROR_MR_UN_PERFORM : rc );
+#endif
+}
+
+
+APIRET
+DosQueryMessageCP(
+ PCHAR Buffer,
+ ULONG Length,
+ IN PSZ MessageFileName,
+ OUT PULONG ActualLength
+ )
+{
+ UNREFERENCED_PARAMETER(Buffer);
+ UNREFERENCED_PARAMETER(Length);
+ UNREFERENCED_PARAMETER(MessageFileName);
+ UNREFERENCED_PARAMETER(ActualLength);
+ return( ERROR_INVALID_FUNCTION );
+}
+
+
+NTSTATUS
+Od2InitializeMessageFile( VOID )
+{
+ Od2MsgFile = NULL;
+ return( STATUS_SUCCESS );
+}
diff --git a/private/os2/client/dllmsg16.c b/private/os2/client/dllmsg16.c
new file mode 100644
index 000000000..1f38b8b5c
--- /dev/null
+++ b/private/os2/client/dllmsg16.c
@@ -0,0 +1,142 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllmsg16.c
+
+Abstract:
+
+ This module implements 32 equivalents of OS/2 V1.21
+ MSG API Calls.
+ The APIs are called from 16->32 thunks (i386\doscalls.asm).
+
+
+Author:
+
+ Yaron Shamir (YaronS) 07-June-1991
+ (stubs)
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_ERRORMSG
+
+#include "os2dll.h"
+#include "os2dll16.h"
+
+
+APIRET
+DosTrueGetMessage(
+ IN PSZ Variables[],
+ IN ULONG CountVariables,
+ OUT PCHAR Buffer,
+ IN ULONG Length,
+ IN ULONG MessageNumber,
+ IN PSZ MessageFileName,
+ OUT PUSHORT pMessageLength,
+ IN PBYTE pMsgSeg
+ )
+{
+ APIRET rc;
+ int i;
+ PSZ Vtable[9];
+ ULONG MessageLength;
+
+ if (CountVariables > 9)
+ {
+ return( ERROR_MR_INV_IVCOUNT );
+ }
+
+ try {
+ Od2ProbeForRead(Variables, sizeof(ULONG) * CountVariables, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ try {
+ Od2ProbeForWrite(pMessageLength, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ for (i = 0; i < (int)CountVariables; i++) {
+ Vtable[i] = (PSZ)(FARPTRTOFLAT(Variables[i]));
+
+ }
+
+ MessageLength = (ULONG) *pMessageLength;
+
+ rc = DosGetMessage(
+ Vtable,
+ CountVariables,
+ Buffer,
+ Length,
+ MessageNumber,
+ MessageFileName,
+ &MessageLength,
+ pMsgSeg
+ );
+
+ *pMessageLength = (USHORT) MessageLength;
+
+ return (rc);
+}
+
+APIRET
+DosInsMessage(
+ IN PSZ Variables[],
+ IN ULONG CountVariables,
+ IN PCHAR Message,
+ IN ULONG MessageLength,
+ OUT PCHAR Buffer,
+ IN ULONG Length,
+ OUT PSHORT pActualMessageLength
+ )
+{
+ APIRET rc;
+ int i;
+ PSZ Vtable[9];
+ ULONG ActualMessageLength;
+
+ if (CountVariables > 9)
+ {
+ return( ERROR_MR_INV_IVCOUNT );
+ }
+
+ try {
+ Od2ProbeForRead(Variables, sizeof(ULONG) * CountVariables, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ try {
+ Od2ProbeForWrite(pActualMessageLength, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ for (i = 0; i < (int)CountVariables; i++) {
+ Vtable[i] = (PSZ)(FARPTRTOFLAT(Variables[i]));
+ }
+
+ ActualMessageLength = (ULONG) *pActualMessageLength;
+
+ rc = DosInsertMessage(
+ Vtable,
+ CountVariables,
+ Message,
+ MessageLength,
+ Buffer,
+ Length,
+ &ActualMessageLength
+ );
+
+ *pActualMessageLength = (USHORT) ActualMessageLength;
+
+ return(rc);
+}
+
diff --git a/private/os2/client/dllmsl16.c b/private/os2/client/dllmsl16.c
new file mode 100644
index 000000000..f109ffd10
--- /dev/null
+++ b/private/os2/client/dllmsl16.c
@@ -0,0 +1,712 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllmsl16.c
+
+Abstract:
+
+ This module implements the OS/2 V1.x Lanman Mailslot APIs.
+
+Author:
+
+ Beni Lavi (benil) 3-Mar-1992
+
+Revision History:
+
+--*/
+
+
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FILESYS
+#include "os2dll.h"
+
+#define NERR_NetNotStarted 2102
+
+APIRET
+Dos16MakeMailslot(
+ IN PSZ pName,
+ IN ULONG MessageSize,
+ IN ULONG MailslotSize,
+ OUT PUSHORT pMailslot
+ )
+{
+ APIRET RetCode;
+ NTSTATUS Status;
+ HFILE hLocalHandle;
+ PFILE_HANDLE hFileRecord;
+ STRING CanonicalNameString;
+ UNICODE_STRING CanonicalNameString_U;
+ ULONG FileType;
+ ULONG FileFlags;
+ ULONG CalculatedMailslotSize;
+ HANDLE NtFileHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ PSECURITY_DESCRIPTOR securityDescriptor;
+ CHAR localSecurityDescriptor[SECURITY_DESCRIPTOR_MIN_LENGTH];
+
+ #if DBG
+ PSZ RoutineName = "DosMakeMailslot";
+ #endif
+
+ try {
+ Od2ProbeForWrite(pMailslot, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RetCode = AllocateHandle(&hLocalHandle);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (RetCode) {
+ return RetCode;
+ }
+
+ RetCode = Od2Canonicalize(pName,
+ CANONICALIZE_MAILSLOT,
+ &CanonicalNameString,
+ &NtFileHandle,
+ &FileFlags, // BUGBUG shouldn't we check for root dir
+ &FileType
+ );
+ if ((RetCode != NO_ERROR)|| (FileFlags & CANONICALIZE_META_CHARS_FOUND)) {
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ FreeHandle(hLocalHandle);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (RetCode == NO_ERROR && (FileFlags & CANONICALIZE_META_CHARS_FOUND)) {
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ RetCode = ERROR_FILE_NOT_FOUND;
+ }
+ return RetCode;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("canonical name is %s\n",CanonicalNameString.Buffer);
+ }
+#endif
+
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &CanonicalNameString_U,
+ &CanonicalNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("Dos16MakeMailslot: no memory for Unicode Conversion\n");
+ }
+#endif
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ FreeHandle(hLocalHandle);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+
+ Status = RtlCreateSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION );
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint("DosMakeMailslot: failed at RtlCreateSecurityDescriptor %x\n", Status);
+ ASSERT(FALSE);
+#endif
+ return ERROR_ACCESS_DENIED;
+ }
+
+ Status = RtlSetDaclSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ (BOOLEAN)TRUE,
+ (PACL) NULL,
+ (BOOLEAN)FALSE );
+
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint("DosMakeMailslot: failed at RtlSetDaclSecurityDescriptor %x\n", Status);
+ ASSERT(FALSE);
+#endif
+ return ERROR_ACCESS_DENIED;
+ }
+ securityDescriptor = (PSECURITY_DESCRIPTOR) &localSecurityDescriptor;
+ InitializeObjectAttributes( &Obja,
+ &CanonicalNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ NtFileHandle,
+ securityDescriptor
+ );
+
+ CalculatedMailslotSize = MailslotSize * 2;
+ if (CalculatedMailslotSize < 4096) {
+ CalculatedMailslotSize = 4096;
+ }
+
+ Status = NtCreateMailslotFile(
+ &NtFileHandle,
+ SYNCHRONIZE |
+ FILE_READ_DATA | FILE_WRITE_DATA |
+ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
+ &Obja,
+ &IoStatus,
+ FILE_SYNCHRONOUS_IO_ALERT,
+ CalculatedMailslotSize,
+ MessageSize,
+ NULL // WAIT FOREVER
+ );
+
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ RtlFreeUnicodeString (&CanonicalNameString_U);
+
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("St == %X\n",Status);
+ }
+#endif
+
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ FreeHandle(hLocalHandle);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Map some of the NT error codes where there is a clear mapping
+ //
+ switch (Status) {
+ case STATUS_OBJECT_NAME_COLLISION:
+ return ERROR_ALREADY_EXISTS;
+
+ default:
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_PATH_NOT_FOUND));
+ }
+ }
+
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ hFileRecord = DereferenceFileHandleNoCheck(hLocalHandle);
+ hFileRecord->NtHandle = NtFileHandle;
+ hFileRecord->FileType = (USHORT) FILE_TYPE_MAILSLOT;
+ hFileRecord->Flags |= OPEN_SHARE_DENYREAD & QFHSTATE_FLAGS;
+ hFileRecord->DeviceAttribute = 0;
+ hFileRecord->IoVectorType = FileVectorType;
+
+ //
+ // validate file handle
+ //
+
+ ValidateHandle(hFileRecord);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ *pMailslot = (USHORT)hLocalHandle;
+ return NO_ERROR;
+}
+
+APIRET
+Dos16DeleteMailslot(
+ IN HFILE Mailslot
+ )
+{
+ APIRET RetCode;
+
+ RetCode = DosClose(Mailslot);
+
+ return NO_ERROR;
+}
+
+APIRET
+Dos16MailslotInfo(
+ IN HFILE Mailslot,
+ OUT PUSHORT pMessageSize,
+ OUT PUSHORT pMailslotSize,
+ OUT PUSHORT pNextSize,
+ OUT PUSHORT pNextPriority,
+ OUT PUSHORT pMessages
+ )
+{
+ APIRET RetCode;
+ NTSTATUS Status;
+ PFILE_HANDLE hFileRecord;
+ HANDLE NtFileHandle;
+ IO_STATUS_BLOCK IoStatus;
+ FILE_MAILSLOT_QUERY_INFORMATION MailslotInfo;
+ #if DBG
+ PSZ RoutineName = "DosMakeMailslot";
+ #endif
+
+
+ try {
+ Od2ProbeForWrite(pMessageSize, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pMailslotSize, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pNextSize, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pNextPriority, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pMessages, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RetCode = DereferenceFileHandle(Mailslot, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ if (hFileRecord->FileType != FILE_TYPE_MAILSLOT) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE;
+ }
+ NtFileHandle = hFileRecord->NtHandle;
+
+ Status = NtQueryInformationFile(
+ NtFileHandle,
+ &IoStatus,
+ &MailslotInfo,
+ sizeof(FILE_MAILSLOT_QUERY_INFORMATION),
+ FileMailslotQueryInformation
+ );
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if (!(NT_SUCCESS(Status))) {
+ return ERROR_INVALID_HANDLE;
+ }
+
+ *pMessageSize = (USHORT)MailslotInfo.MaximumMessageSize;
+ *pMailslotSize = (USHORT)MailslotInfo.MailslotQuota;
+ *pNextSize = (USHORT)((MailslotInfo.NextMessageSize == MAILSLOT_NO_MESSAGE)
+ ? 0 : MailslotInfo.NextMessageSize);
+ *pNextPriority = 0;
+ *pMessages = (USHORT)MailslotInfo.MessagesAvailable;
+
+ return NO_ERROR;
+}
+
+APIRET
+Dos16ReadMailslot(
+ IN HANDLE Mailslot,
+ OUT PCHAR pBuffer,
+ OUT PUSHORT pReturned,
+ OUT PUSHORT pNextSize,
+ OUT PUSHORT pNextPriority,
+ IN LONG Timeout
+ )
+{
+ APIRET RetCode;
+ NTSTATUS Status;
+ PFILE_HANDLE hFileRecord;
+ HANDLE NtFileHandle;
+ IO_STATUS_BLOCK IoStatus;
+ ULONG FileType;
+ LARGE_INTEGER NtTimeout;
+ ULONG BytesRead;
+ FILE_MAILSLOT_QUERY_INFORMATION MailslotQueryInfo;
+ FILE_MAILSLOT_SET_INFORMATION MailslotSetInfo;
+ #if DBG
+ PSZ RoutineName = "DosReadMailslot";
+ #endif
+
+ try {
+ Od2ProbeForWrite(pReturned, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pNextSize, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pNextPriority, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+
+ RetCode = DereferenceFileHandle(Mailslot, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ NtFileHandle = hFileRecord->NtHandle;
+ FileType = hFileRecord->FileType;
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if (FileType != FILE_TYPE_MAILSLOT) {
+ return ERROR_INVALID_HANDLE;
+ }
+
+ //
+ // Set the timeout to the value requested by the read operation
+ //
+ if (Timeout == -1 /*MAILSLOT_NO_TIMEOUT*/) {
+ NtTimeout = RtlConvertLongToLargeInteger(MAILSLOT_WAIT_FOREVER);
+ }
+ else {
+ NtTimeout = RtlEnlargedIntegerMultiply(-10000, Timeout);
+ }
+ MailslotSetInfo.ReadTimeout = &NtTimeout;
+
+ Status = NtSetInformationFile(
+ NtFileHandle,
+ &IoStatus,
+ &MailslotSetInfo,
+ sizeof(FILE_MAILSLOT_SET_INFORMATION),
+ FileMailslotSetInformation
+ );
+
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_BROKEN_PIPE));
+ }
+
+ //
+ // Get the maximum possible size of the buffer
+ //
+ Status = NtQueryInformationFile(
+ NtFileHandle,
+ &IoStatus,
+ &MailslotQueryInfo,
+ sizeof(FILE_MAILSLOT_QUERY_INFORMATION),
+ FileMailslotQueryInformation
+ );
+
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_BROKEN_PIPE));
+ }
+
+ Status = NtReadFile(
+ NtFileHandle,
+ 0,
+ NULL,
+ NULL,
+ &IoStatus,
+ pBuffer,
+ MailslotQueryInfo.MaximumMessageSize,
+ NULL,
+ NULL
+ );
+
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_BROKEN_PIPE));
+ }
+
+ BytesRead = IoStatus.Information;
+
+ //
+ // Get Info about next message in buffer
+ //
+ Status = NtQueryInformationFile(
+ NtFileHandle,
+ &IoStatus,
+ &MailslotQueryInfo,
+ sizeof(FILE_MAILSLOT_QUERY_INFORMATION),
+ FileMailslotQueryInformation
+ );
+
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_BROKEN_PIPE));
+ }
+
+ *pReturned = (USHORT)BytesRead;
+ if (MailslotQueryInfo.NextMessageSize == MAILSLOT_NO_MESSAGE) {
+ *pNextSize = 0;
+ }
+ else {
+ *pNextSize = (USHORT)MailslotQueryInfo.NextMessageSize;
+ }
+ *pNextPriority = 0;
+
+ return NO_ERROR;
+}
+
+APIRET
+Dos16PeekMailslot(
+ IN HANDLE Mailslot,
+ OUT PCHAR pBuffer,
+ OUT PUSHORT pReturned,
+ OUT PUSHORT pNextSize,
+ OUT PUSHORT pNextPriority
+ )
+{
+ APIRET RetCode;
+ NTSTATUS Status;
+ PFILE_HANDLE hFileRecord;
+ HANDLE NtFileHandle;
+ IO_STATUS_BLOCK IoStatus;
+ ULONG FileType;
+ FILE_MAILSLOT_QUERY_INFORMATION MailslotInfo;
+ FILE_MAILSLOT_PEEK_BUFFER MailslotPeekBuffer;
+ #if DBG
+ PSZ RoutineName = "DosPeekMailslot";
+ #endif
+
+ try {
+ Od2ProbeForWrite(pReturned, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pNextSize, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pNextPriority, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+
+ RetCode = DereferenceFileHandle(Mailslot, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+ NtFileHandle = hFileRecord->NtHandle;
+ FileType = hFileRecord->FileType;
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if (FileType != FILE_TYPE_MAILSLOT) {
+ return ERROR_INVALID_HANDLE;
+ }
+
+ Status = NtQueryInformationFile(
+ NtFileHandle,
+ &IoStatus,
+ &MailslotInfo,
+ sizeof(FILE_MAILSLOT_QUERY_INFORMATION),
+ FileMailslotQueryInformation
+ );
+
+ if (!(NT_SUCCESS(Status))) {
+ return ERROR_BROKEN_PIPE;
+ }
+
+ if (MailslotInfo.NextMessageSize == (ULONG)(MAILSLOT_NO_MESSAGE)) {
+ *pReturned = 0;
+ *pNextSize = 0;
+ *pNextPriority = 0;
+ return (NO_ERROR);
+ }
+
+ Status = NtFsControlFile( NtFileHandle,
+ 0,
+ NULL,
+ NULL,
+ &IoStatus,
+ FSCTL_MAILSLOT_PEEK,
+ &MailslotPeekBuffer,
+ sizeof(FILE_MAILSLOT_PEEK_BUFFER),
+ pBuffer,
+ MailslotInfo.NextMessageSize
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_BROKEN_PIPE));
+ }
+
+ *pReturned = (USHORT)MailslotPeekBuffer.MessageLength;
+ if (MailslotPeekBuffer.NumberOfMessages <= 1) {
+ *pNextSize = 0;
+ }
+ else {
+ //
+ // We don't have enough information to determine the NextSize
+ // value so we play it safe
+ //
+ *pNextSize = (USHORT)MailslotInfo.MaximumMessageSize;
+ }
+ *pNextPriority = 0;
+
+ return NO_ERROR;
+}
+
+APIRET
+Dos16WriteMailslot(
+ IN PSZ pName,
+ OUT PCHAR pBuffer,
+ IN ULONG BufferSize,
+ IN ULONG Priority,
+ IN ULONG Class,
+ IN LONG Timeout
+ )
+{
+ APIRET RetCode;
+ NTSTATUS Status;
+ ULONG FileType;
+ ULONG FileFlags;
+ STRING CanonicalNameString;
+ UNICODE_STRING CanonicalNameString_U;
+ HANDLE NtFileHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+
+ UNREFERENCED_PARAMETER(Priority);
+ UNREFERENCED_PARAMETER(Class);
+ UNREFERENCED_PARAMETER(Timeout);
+
+ try {
+ Od2ProbeForRead(pBuffer, BufferSize, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ RetCode = Od2Canonicalize(pName,
+ CANONICALIZE_MAILSLOT,
+ &CanonicalNameString,
+ &NtFileHandle,
+ &FileFlags,
+ &FileType
+ );
+ if (RetCode != NO_ERROR) {
+ return (ERROR_FILE_NOT_FOUND);
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("canonical name is %s\n",CanonicalNameString.Buffer);
+ }
+#endif
+
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &CanonicalNameString_U,
+ &CanonicalNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("Dos16WriteMailslot: no memory for Unicode Conversion\n");
+ }
+#endif
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ NtFileHandle,
+ NULL);
+
+ Status = NtOpenFile(
+ &NtFileHandle,
+ SYNCHRONIZE | FILE_WRITE_DATA | FILE_READ_DATA,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_ALERT
+ );
+
+ RtlFreeHeap(Od2Heap,0,CanonicalNameString.Buffer);
+ RtlFreeUnicodeString (&CanonicalNameString_U);
+
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_PATH_NOT_FOUND));
+ }
+
+ Status = NtWriteFile(
+ NtFileHandle,
+ 0,
+ NULL,
+ NULL,
+ &IoStatus,
+ pBuffer,
+ BufferSize,
+ NULL,
+ 0
+ );
+
+ if (!(NT_SUCCESS(Status))) {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_BROKEN_PIPE));
+ }
+
+ Status = NtClose(NtFileHandle);
+
+ return NO_ERROR;
+}
diff --git a/private/os2/client/dllmutex.c b/private/os2/client/dllmutex.c
new file mode 100644
index 000000000..e6846f403
--- /dev/null
+++ b/private/os2/client/dllmutex.c
@@ -0,0 +1,1039 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllmutex.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 Mutex Semaphore API Calls.
+
+Author:
+
+ Steve Wood (stevewo) 07-Feb-1990
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+
+
+APIRET
+DosCreateMutexSem(
+ IN PSZ ObjectName,
+ IN OUT PHMTX MutexHandle,
+ IN ULONG CreateAttributes,
+ IN BOOL32 InitialState
+ )
+{
+ NTSTATUS Status;
+ OS2_API_MSG m;
+ POS2_DOSCREATEMUTEXSEM_MSG a = &m.u.DosCreateMutexSem;
+ POS2_DOSCLOSEMUTEXSEM_MSG a1 = &m.u.DosCloseMutexSem;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ APIRET rc;
+ BOOLEAN SharedSem;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ OD2_SEMAPHORE Semaphore;
+ POD2_MUTEX_SEMAPHORE Mutex;
+
+ //
+ // Validate the simple parameters
+ //
+
+ if ((CreateAttributes & ~DC_SEM_SHARED) ||
+ ((InitialState != TRUE) && (InitialState != FALSE))
+ ) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ //
+ // probe handle pointer
+ //
+
+ try {
+ Od2ProbeForWrite( (PVOID)MutexHandle, sizeof( MutexHandle ), 1 );
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Capture and validate any semaphore name.
+ //
+
+ rc = Od2CaptureObjectName( ObjectName,
+ CANONICALIZE_SEMAPHORE,
+ 0,
+ &CaptureBuffer,
+ &a->ObjectName
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Determine if a shared or private semaphore.
+ //
+
+ if (CaptureBuffer != NULL || CreateAttributes & DC_SEM_SHARED) {
+ SharedSem = TRUE;
+ }
+ else {
+ SharedSem = FALSE;
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table,
+ // creating it if necessary.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, TRUE );
+ if (!SemaphoreTable) {
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ }
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ Mutex = RtlAllocateHeap( Od2Heap, 0, sizeof( *Mutex ) );
+ if (Mutex == NULL) {
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ }
+
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ //
+ // Create an NT Mutant that will be used to implement the semantics
+ // of an OS/2 2.0 Mutex Semaphore. Must always do this in the client so
+ // the initial owner gets marked correctly.
+ //
+
+ Status = NtCreateMutant( &a->NtMutantHandle,
+ MUTANT_ALL_ACCESS,
+ NULL,
+ (BOOLEAN)InitialState
+ );
+
+ //
+ // Return an error if unable to create the NT Mutant.
+ //
+
+ if (!NT_SUCCESS( Status )) {
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ }
+ RtlFreeHeap( Od2Heap, 0, Mutex );
+
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ //
+ // Mark the fact that we are creating a semaphore handle.
+ //
+ a->HandleIndex = 0xFFFFFFFF;
+
+ if (SharedSem) {
+ //
+ // Shared semaphore. Set the shared semaphore attribute and pass
+ // the call to the OS/2 subsystem to create the system wide semaphore
+ // handle value.
+ //
+
+ a->InitialState = (BOOLEAN) InitialState;
+ rc = Od2CallSubsystem( &m,
+ CaptureBuffer,
+ Os2CreateMutexSem,
+ sizeof( *a )
+ );
+
+ //
+ // Free any capture buffer, since the subsystem has saved away any
+ // semaphore name in its table.
+ //
+
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ }
+
+ //
+ // Return if an error was discovered.
+ //
+
+ if (rc != NO_ERROR) {
+ RtlFreeHeap( Od2Heap, 0, Mutex );
+ NtClose( a->NtMutantHandle );
+ return( rc );
+ }
+
+ //
+ // At this point, the semaphore handle index has been stored in
+ // a->HandleIndex by the OS/2 subsystem and it has made a copy of
+ // the NT Mutant handle we created.
+ //
+ }
+
+ //
+ // Initialize the OS/2 Semaphore structure.
+ //
+
+ Semaphore.Type = Od2MutexSem;
+ Semaphore.Shared = SharedSem;
+ Semaphore.PointerCount = 0;
+ Semaphore.OpenCount = 1;
+
+ Mutex->MutantHandle = a->NtMutantHandle;
+ if (InitialState) {
+ Mutex->OwnerRequestLevel = 1;
+ Mutex->OwnerTid = (TID)Od2CurrentThreadId();
+ }
+ else {
+ Mutex->OwnerRequestLevel = 0;
+ Mutex->OwnerTid = 0;
+ }
+ Semaphore.u.Mutex = Mutex;
+
+ //
+ // Create an entry in the appropriate semaphore table, which will copy
+ // the semaphore structure into the table entry and return an index to
+ // the entry in a->HandleIndex
+ //
+
+ if (!Or2CreateHandle( SemaphoreTable,
+ &a->HandleIndex,
+ (PVOID)&Semaphore
+ )
+ ) {
+ //
+ // Unable to create the entry. Close the NT Mutant handle, as
+ // it will not be used. If this is a shared semaphore created, then
+ // call the OS/2 subsystem to close our reference to this shared
+ // OS/2 semaphore.
+ //
+
+ RtlFreeHeap( Od2Heap, 0, Mutex );
+ NtClose( a->NtMutantHandle );
+ if (SharedSem) {
+ a1->HandleIndex = a->HandleIndex;
+ Od2CallSubsystem( &m, NULL, Os2CloseMutexSem, sizeof( *a1 ) );
+ }
+
+ //
+ // Return an error.
+ //
+
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ //
+ // Success. Store a valid OS/2 2.0 Semaphore handle in the location
+ // specified by the caller and return success to the caller.
+ //
+
+ *MutexHandle = Od2ConstructSemaphoreHandle( SharedSem,
+ a->HandleIndex
+ );
+ return( NO_ERROR );
+}
+
+
+APIRET
+DosOpenMutexSem(
+ IN PSZ ObjectName,
+ IN OUT PHMTX MutexHandle
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSOPENMUTEXSEM_MSG a = &m.u.DosOpenMutexSem;
+ POS2_DOSCLOSEMUTEXSEM_MSG a1 = &m.u.DosCloseMutexSem;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ OD2_SEMAPHORE NewSemaphore;
+ POD2_SEMAPHORE Semaphore;
+ POD2_MUTEX_SEMAPHORE Mutex;
+ BOOLEAN SharedSem;
+ APIRET rc;
+
+ //
+ // probe handle pointer
+ //
+
+ try {
+ Od2ProbeForWrite( (PVOID)MutexHandle, sizeof( MutexHandle ), 1 );
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Capture and validate any semaphore name.
+ //
+
+ rc = Od2CaptureObjectName( ObjectName,
+ CANONICALIZE_SEMAPHORE,
+ 0,
+ &CaptureBuffer,
+ &a->ObjectName
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Determine if opening the semaphore by name or by handle.
+ //
+
+ if (CaptureBuffer != NULL) {
+ //
+ // If a semaphore name was given, then we are opening the semaphore
+ // by name, so call the OS/2 Subsystem to do the name lookup.
+ //
+
+ a->HandleIndex = 0xFFFFFFFF;
+ rc = Od2CallSubsystem( &m,
+ CaptureBuffer,
+ Os2OpenMutexSem,
+ sizeof( *a )
+ );
+
+ //
+ // Free any capture buffer, since the name has served its purpose
+ // at this point.
+ //
+
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ RtlZeroMemory( &a->ObjectName, sizeof( a->ObjectName ) );
+ }
+
+ //
+ // Return if an error was discovered.
+ //
+
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // At this point, the semaphore handle index has been stored in
+ // a->HandleIndex by the OS/2 subsystem but a->NtMutantHandle is still
+ // uninitialized, since we don't know if this is the first reference
+ // to this shared semaphore by this process. Set the shared semaphore
+ // flag.
+ //
+
+ SharedSem = TRUE;
+
+
+ //
+ // If the caller specified both the name and the handle, make sure
+ // the named mapped to the same handle value that they specified.
+ //
+
+ if (*MutexHandle != NULL &&
+ *MutexHandle != Od2ConstructSemaphoreHandle( SharedSem,
+ a->HandleIndex
+ )
+ ) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+ }
+ else {
+ //
+ // Opening by handle. Validate the handle and get the shared/private
+ // flag.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( *MutexHandle,
+ &SharedSem,
+ &a->HandleIndex
+ );
+ //
+ // Return if invalid handle.
+ //
+
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Creating is okay if this is a shared semaphore open. Return the
+ // appropriate error code if table does not exist or cant be created.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, SharedSem );
+ if (!SemaphoreTable) {
+ return( SharedSem ? ERROR_NOT_ENOUGH_MEMORY : ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Now lock the semaphore table while we figure out what we are doing and
+ // do it.
+ //
+
+ AcquireHandleTableLock( SemaphoreTable );
+
+ //
+ // See if the semaphore handle maps to an allocated entry in the table.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ a->HandleIndex,
+ TRUE
+ );
+ if (Semaphore == NULL || *(PULONG)Semaphore == 0) {
+ //
+ // No entry in the table for this semaphore handle. Error if not
+ // a shared semaphore.
+ //
+
+ if (!SharedSem) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+ else {
+
+ //
+ // This is the first usage of this shared semaphore handle by
+ // the calling process, so call the OS/2 subsystem so that it
+ // can bump its reference count.
+ //
+
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2OpenMutexSem,
+ sizeof( *a )
+ );
+ if (rc == NO_ERROR) {
+ //
+ // If we succeeded, then the semaphore was not deleted
+ // inbetween the two calls to the subsystem, so add an
+ // entry for this handle in the semaphore table, using the
+ // NT Mutant handle we got from the subsystem.
+ //
+
+ NewSemaphore.Type = Od2MutexSem;
+ NewSemaphore.Shared = TRUE;
+ NewSemaphore.PointerCount = 0;
+ NewSemaphore.OpenCount = 1;
+
+ Mutex = RtlAllocateHeap( Od2Heap, 0, sizeof( *Mutex ) );
+ if (Mutex == NULL) {
+ NtClose( a->NtMutantHandle );
+ a1->HandleIndex = a->HandleIndex;
+ Od2CallSubsystem( &m,
+ NULL,
+ Os2CloseMutexSem,
+ sizeof( *a1 )
+ );
+
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ Mutex->MutantHandle = a->NtMutantHandle;
+ Mutex->OwnerRequestLevel = 0;
+ Mutex->OwnerTid = 0;
+
+ NewSemaphore.u.Mutex = Mutex;
+
+ if (!Or2CreateHandle( SemaphoreTable,
+ &a->HandleIndex,
+ (PVOID)&NewSemaphore
+ )
+ ) {
+ //
+ // Unable to create the entry. Close the NT Mutant
+ // handle, as it will not be used. Then call the
+ // OS/2 subsystem to close our reference to this shared
+ // OS/2 semaphore. Set the appropriate error code.
+ //
+
+ RtlFreeHeap( Od2Heap, 0, Mutex );
+ NtClose( a->NtMutantHandle );
+ a1->HandleIndex = a->HandleIndex;
+ Od2CallSubsystem( &m,
+ NULL,
+ Os2CloseMutexSem,
+ sizeof( *a1 )
+ );
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+ }
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is a Mutex semaphore.
+ // Set the appropriate error code if not.
+ //
+
+ else
+ if (Semaphore->Type != Od2MutexSem) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+
+ //
+ // Entry in semaphore table is for a Mutex semaphore, see if the OpenCount
+ // is about to overflow, and set the appropriate error code if it is.
+ //
+
+ else
+ if (Semaphore->OpenCount == 0xFFFF) {
+ rc = ERROR_TOO_MANY_OPENS;
+ }
+
+ //
+ // Everything is okay, so bump the open count in the semaphore table entry.
+ //
+
+ else {
+ Semaphore->OpenCount++;
+ }
+
+ //
+ // All done mucking about, so release the semaphore table lock.
+ //
+
+ ReleaseHandleTableLock( SemaphoreTable );
+
+ //
+ // If no errors, store a valid OS/2 2.0 Semaphore handle in the location
+ // specified by the caller and return success to the caller.
+ //
+
+ if (rc == NO_ERROR) {
+ *MutexHandle = Od2ConstructSemaphoreHandle( SharedSem,
+ a->HandleIndex
+ );
+ }
+
+ //
+ // Return an error code to the caller.
+ //
+
+ return( rc );
+}
+
+
+APIRET
+DosCloseMutexSem(
+ IN HMTX MutexHandle
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSCLOSEMUTEXSEM_MSG a = &m.u.DosCloseMutexSem;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ POD2_MUTEX_SEMAPHORE Mutex;
+ BOOLEAN SharedSem;
+ APIRET rc;
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( MutexHandle,
+ &SharedSem,
+ &a->HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ a->HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is a Mutex semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2MutexSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table is for a Mutex semaphore, so decrement the
+ // OpenCount and see if it has gone to zero.
+ //
+
+ if (--Semaphore->OpenCount == 0) {
+
+ //
+ // OpenCount is now zero, so we can really close the semaphore
+ // and delete the entry in the semaphore table.
+ //
+
+ Mutex = Semaphore->u.Mutex;
+
+ //
+ // First make sure the mutex is not owned by a thread in this process
+ // If it is, increment the open count and return an error. Otherwise
+ // make sure that no thread in this process is waiting on this mutex
+ // If there is one waiting on it, increment the open count and return
+ // an error.
+ //
+
+ if (Mutex->OwnerTid != 0 || Od2SearchForWaitingThread( Semaphore )) {
+ Semaphore->OpenCount++;
+ ReleaseHandleTableLock( SemaphoreTable );
+ rc = ERROR_SEM_BUSY;
+ }
+ else {
+ //
+ // Okay to really close this mutex semaphore. First destroy
+ // the handle, which will unlock the handle table.
+ //
+
+ Or2DestroyHandle( SemaphoreTable, a->HandleIndex );
+ NtClose( Mutex->MutantHandle );
+ RtlFreeHeap( Od2Heap, 0, Mutex );
+
+ //
+ // If this is a shared semaphore, call the subsystem so that it
+ // can decrement its open count, as this process is not longer
+ // using the shared semaphore handle.
+ //
+
+ if (SharedSem) {
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2CloseMutexSem,
+ sizeof( *a )
+ );
+ }
+ }
+ }
+ else {
+ //
+ // OpenCount is still non-zero, so just release the semaphore table
+ // lock.
+ //
+
+ ReleaseHandleTableLock( SemaphoreTable );
+ }
+
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
+
+
+APIRET
+DosRequestMutexSem(
+ IN HMTX MutexHandle,
+ IN ULONG Timeout
+ )
+{
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ POD2_MUTEX_SEMAPHORE Mutex;
+ BOOLEAN SharedSem;
+ ULONG HandleIndex;
+ APIRET rc;
+ NTSTATUS Status;
+ HANDLE NtMutantHandle;
+ LARGE_INTEGER CapturedTimeout;
+ PLARGE_INTEGER NtTimeout;
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( MutexHandle,
+ &SharedSem,
+ &HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Capture the timeout value and convert it into an NT timeout value.
+ //
+
+ NtTimeout = Od2CaptureTimeout( Timeout, (PLARGE_INTEGER)&CapturedTimeout );
+
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is a Mutex semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2MutexSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table is for a Mutex semaphore, so extract the
+ // NT Mutant handle from the record and release the lock, so we are
+ // not holding the lock while we are waiting.
+ //
+
+ Mutex = Semaphore->u.Mutex;
+
+ //
+ // Entry in semaphore table is for a Mutex semaphore, so extract the
+ // NT Mutant handle from the record and release the lock, so we are
+ // not holding the lock when the semaphore is released.
+ //
+
+ //
+ // Entry in semaphore table is for a Mutex semaphore, so see if the calling
+ // thread is already the owner. If so, just increment the request level.
+ // If the calling thread does not own the mutex, then we need to block
+ // attempting to acquire the mutant object that is backing this semaphore.
+ //
+
+ Mutex = Semaphore->u.Mutex;
+ if (Mutex->OwnerTid == (TID)Od2CurrentThreadId()) {
+ Mutex->OwnerRequestLevel += 1;
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( NO_ERROR );
+ }
+
+ //
+ // Call the NT system service to wait for this Mutant to be released.
+ // This is an alertable wait, since by definition all OS/2 waits are
+ // alertable.
+ //
+
+ NtMutantHandle = Semaphore->u.Mutex->MutantHandle;
+ Od2ThreadWaitingOnSemaphore( SemaphoreTable, Semaphore, TRUE );
+ Status = NtWaitForSingleObject( Mutex->MutantHandle, TRUE, NtTimeout );
+ if (NT_SUCCESS( Status )) {
+ if (Status == STATUS_SUCCESS) {
+ Mutex->OwnerTid = (TID)Od2CurrentThreadId();
+ Mutex->OwnerRequestLevel = 1;
+ }
+ else
+ if (Status == STATUS_ABANDONED) {
+ rc = ERROR_SEM_OWNER_DIED;
+ }
+ else
+ if (Status == STATUS_TIMEOUT) {
+ rc = ERROR_TIMEOUT;
+ }
+ else
+ if (Status == STATUS_USER_APC || Status == STATUS_ALERTED) {
+ rc = ERROR_INTERRUPT;
+ }
+ }
+ else {
+ //
+ // If the NT system service failed, then some other thread must
+ // have closed the semaphore so return an error or this thread was
+ // alerted out of the wait. Return the appropriate error code.
+ //
+
+ if (Status == STATUS_INVALID_HANDLE) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+ else {
+ rc = Or2MapStatus( Status );
+ }
+ }
+ Od2ThreadWaitingOnSemaphore( SemaphoreTable, Semaphore, FALSE );
+
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
+
+
+APIRET
+DosReleaseMutexSem(
+ IN HMTX MutexHandle
+ )
+{
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ POD2_MUTEX_SEMAPHORE Mutex;
+ BOOLEAN SharedSem;
+ ULONG HandleIndex;
+ APIRET rc;
+ NTSTATUS Status;
+ LONG NtMutantCount;
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( MutexHandle,
+ &SharedSem,
+ &HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is a Mutex semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2MutexSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table is for a Mutex semaphore, so see if the calling
+ // thread is already the owner. If so, just decrement the request level
+ // and if the request level goes to zero we need to release the mutant
+ // that is backing this mutex. If the calling thread does not own the
+ // mutex, return an error.
+ //
+
+ Mutex = Semaphore->u.Mutex;
+ if (Mutex->OwnerTid != (TID)Od2CurrentThreadId()) {
+ rc = ERROR_NOT_OWNER;
+ }
+ else
+
+ //
+ // If the calling thread is the owner and this release will be their
+ // last, do the work to really release it.
+ //
+
+ if ((Mutex->OwnerRequestLevel -= 1) == 0) {
+ //
+ // Mark the mutex as unowned.
+ //
+
+ Mutex->OwnerTid = NULL;
+
+ //
+ // Call the NT system service to release the Mutant
+ //
+
+ Status = NtReleaseMutant( Semaphore->u.Mutex->MutantHandle,
+ &NtMutantCount
+ );
+
+ //
+ // Okay to release the semaphore handle table lock
+ //
+
+ ReleaseHandleTableLock( SemaphoreTable );
+
+ if (!NT_SUCCESS( Status )) {
+ //
+ // If the NT system service failed, then some other thread must
+ // have closed the semaphore so return an error.
+ //
+
+ if (Status == STATUS_MUTANT_NOT_OWNED) {
+ rc = ERROR_NOT_OWNER;
+ }
+ else {
+ rc = ERROR_INVALID_HANDLE;
+ }
+ }
+ else
+ if (Status == STATUS_ABANDONED) {
+ rc = ERROR_SEM_OWNER_DIED;
+ }
+ }
+ else {
+ //
+ // All the work is done, as they still own the mutex or were not
+ // the owner in the first place, so okay to release the semaphore
+ // handle table lock
+ //
+
+ ReleaseHandleTableLock( SemaphoreTable );
+ }
+
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
+
+
+APIRET
+DosQueryMutexSem(
+ IN HMTX MutexHandle,
+ OUT PPID OwnerPid,
+ OUT PTID OwnerTid,
+ OUT PULONG OwnerRequestLevel
+ )
+{
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ POD2_MUTEX_SEMAPHORE Mutex;
+ BOOLEAN SharedSem;
+ ULONG HandleIndex;
+ APIRET rc;
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( MutexHandle,
+ &SharedSem,
+ &HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is a Mutex semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2MutexSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table is for a Mutex semaphore, so extract the
+ // NT Mutant handle from the record, along with the current owning
+ // thread.
+ //
+
+ Mutex = Semaphore->u.Mutex;
+ try {
+ if (Mutex->OwnerTid != 0) {
+ *OwnerTid = Mutex->OwnerTid;
+ *OwnerPid = Od2Process->Pib.ProcessId;
+ *OwnerRequestLevel = Mutex->OwnerRequestLevel;
+ }
+ else {
+ *OwnerPid = 0;
+ *OwnerTid = 0;
+ *OwnerRequestLevel = 0;
+ }
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Release the semaphore table lock and return any error code.
+ //
+
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( rc );
+}
diff --git a/private/os2/client/dllmuxwt.c b/private/os2/client/dllmuxwt.c
new file mode 100644
index 000000000..bdd6d3e81
--- /dev/null
+++ b/private/os2/client/dllmuxwt.c
@@ -0,0 +1,1423 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllmuxwt.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 MuxWait Semaphore API Calls.
+
+Author:
+
+ Steve Wood (stevewo) 07-Feb-1990
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+
+
+APIRET
+Od2AddMuxWait(
+ IN POD2_MUXWAIT_SEMAPHORE MuxWait,
+ IN PSEMRECORD MuxWaitEntry
+ )
+{
+ POD2_MUXWAIT_RECORD MuxWaitRecord;
+ APIRET rc;
+ BOOLEAN SharedSem;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ ULONG Handle;
+ USHORT i;
+
+ if (MuxWait->CountMuxWaitRecords == DCMW_MAX_SEMRECORDS) {
+ return( ERROR_TOO_MANY_SEMAPHORES );
+ }
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if not a
+ // valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( MuxWaitEntry->hsemCur,
+ &SharedSem,
+ &Handle
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside the
+ // current limits of the table. If the mapping is successful then the
+ // semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ Handle,
+ TRUE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Now see if this semaphore is already in the MuxWait semaphore.
+ // Return an error if it is.
+ //
+
+ MuxWaitRecord = &MuxWait->MuxWaitRecords[ 0 ];
+ for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
+ if (MuxWaitRecord->Semaphore == Semaphore) {
+ return( ERROR_DUPLICATE_HANDLE );
+ }
+
+ MuxWaitRecord++;
+ }
+
+
+ //
+ // Entry in semaphore table exists, so make sure it is not a MuxWait
+ // semaphore. Also make sure it is that same type of semaphore as the
+ // first semaphore. Also make sure if the MuxWait semaphore that all
+ // the component semaphores are also shared. Return an error if any
+ // of these conditions are not met.
+ //
+
+ if (Semaphore->Type == Od2MuxWaitSem) {
+ return( ERROR_WRONG_TYPE );
+ }
+
+ if (MuxWait->CountMuxWaitRecords == 0) {
+ MuxWait->Type = Semaphore->Type;
+ }
+ else
+ if (Semaphore->Type != MuxWait->Type) {
+ return( ERROR_WRONG_TYPE );
+ }
+
+ //
+ // At this point everything is copasetic, so fill in the next available
+ // record in the MuxWait semaphore.
+ //
+
+ MuxWaitRecord->SemHandle = MuxWaitEntry->hsemCur;
+ MuxWaitRecord->UserKey = MuxWaitEntry->ulUser;
+ MuxWaitRecord->Semaphore = Od2ReferenceSemaphore( Semaphore );
+ MuxWait->CountMuxWaitRecords++;
+
+ return( NO_ERROR );
+}
+
+
+APIRET
+Od2DeleteMuxWait(
+ IN POD2_MUXWAIT_SEMAPHORE MuxWait,
+ IN ULONG MuxWaitEntryIndex,
+ IN HSEM MuxWaitEntrySem OPTIONAL
+ )
+{
+ POD2_MUXWAIT_RECORD MuxWaitRecord;
+ USHORT i;
+
+ if (MuxWait->CountMuxWaitRecords == 0) {
+ return( ERROR_EMPTY_MUXWAIT );
+ }
+
+ MuxWaitRecord = &MuxWait->MuxWaitRecords[ 0 ];
+ for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
+ if (ARGUMENT_PRESENT( MuxWaitEntrySem )) {
+ if (MuxWaitRecord->SemHandle == MuxWaitEntrySem) {
+ break;
+ }
+ }
+ else
+ if (i == (USHORT)MuxWaitEntryIndex) {
+ break;
+ }
+
+ MuxWaitRecord++;
+ }
+
+ if (i == MuxWait->CountMuxWaitRecords) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ Od2DereferenceSemaphore( MuxWaitRecord->Semaphore );
+
+ MuxWait->CountMuxWaitRecords -= 1;
+ for (; i<MuxWait->CountMuxWaitRecords; i++) {
+ *MuxWaitRecord = *(MuxWaitRecord+1);
+ MuxWaitRecord++;
+ }
+ MuxWaitRecord->Semaphore = NULL;
+ MuxWaitRecord->SemHandle = 0;
+ MuxWaitRecord->UserKey = 0;
+
+ return( NO_ERROR );
+}
+
+
+
+APIRET
+DosCreateMuxWaitSem(
+ IN PSZ ObjectName,
+ IN OUT PHMUX MuxWaitHandle,
+ IN ULONG CountMuxWaitEntries,
+ IN SEMRECORD MuxWaitEntries[],
+ IN ULONG CreateAttributes
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSCREATEMUXWAITSEM_MSG a = &m.u.DosCreateMuxWaitSem;
+ POS2_DOSCLOSEMUXWAITSEM_MSG a1 = &m.u.DosCloseMuxWaitSem;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ PSEMRECORD CapturedMuxWaitEntries;
+ APIRET rc;
+ ULONG i;
+ BOOLEAN SharedSem;
+ ULONG MuxWaitType;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ OD2_SEMAPHORE Semaphore;
+ POD2_MUXWAIT_SEMAPHORE MuxWait;
+
+ //
+ // Validate the simple parameters
+ //
+
+ MuxWaitType = CreateAttributes & (DCMW_WAIT_ANY | DCMW_WAIT_ALL);
+ if (MuxWaitType == 0 ||
+ !(MuxWaitType ^ (DCMW_WAIT_ANY | DCMW_WAIT_ALL)) ||
+ CreateAttributes & ~(DC_SEM_SHARED | DCMW_WAIT_ANY | DCMW_WAIT_ALL)
+ ) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ if (CountMuxWaitEntries > DCMW_MAX_SEMRECORDS) {
+ return( ERROR_TOO_MANY_SEMAPHORES );
+ }
+
+ //
+ // probe handle pointer and MuxWaitEntries buffer
+ //
+
+ try {
+ Od2ProbeForWrite( (PVOID)MuxWaitHandle, sizeof( MuxWaitHandle ), 1 );
+ Od2ProbeForRead(MuxWaitEntries,sizeof(SEMRECORD)*CountMuxWaitEntries,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Capture and validate any semaphore name.
+ //
+
+ rc = Od2CaptureObjectName( ObjectName,
+ CANONICALIZE_SEMAPHORE,
+ sizeof( OD2_MUXWAIT_SEMAPHORE ),
+ &CaptureBuffer,
+ &a->ObjectName
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Determine if a shared or private semaphore.
+ //
+
+ if (CaptureBuffer != NULL || CreateAttributes & DC_SEM_SHARED) {
+ SharedSem = TRUE;
+ }
+ else {
+ SharedSem = FALSE;
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table,
+ // creating it if necessary. Lock the table for the duration of this
+ // API call.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, TRUE );
+ if (!SemaphoreTable) {
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ }
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+
+ //
+ // Initialize the Client OS/2 Semaphore Structure
+ //
+
+ Semaphore.Type = Od2MuxWaitSem;
+ Semaphore.Shared = SharedSem;
+ Semaphore.PointerCount = 0;
+ Semaphore.OpenCount = 1;
+ Semaphore.u.MuxWait = MuxWait = NULL;
+
+
+ //
+ // Mark the fact that we are creating a semaphore handle.
+ //
+
+ a->HandleIndex = 0xFFFFFFFF;
+
+ if (SharedSem) {
+ //
+ // For shared semaphores, we need to pass the create to OS/2 Subsystem
+ // so that it can manager adds and deletes.
+ //
+
+ //
+ // If one or more SEMRECORDs then allocate space for a copy in the
+ // CaptureBuffer so we can pass the array to the server.
+ //
+
+ if (CountMuxWaitEntries != 0) {
+ if (CaptureBuffer == NULL) {
+ CaptureBuffer = Od2AllocateCaptureBuffer(
+ 1,
+ 0,
+ (sizeof( OD2_MUXWAIT_SEMAPHORE ) + 3) & ~3
+ );
+ if (CaptureBuffer == NULL) {
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ }
+
+ Od2AllocateMessagePointer( CaptureBuffer,
+ CountMuxWaitEntries * sizeof( SEMRECORD ),
+ (PVOID *)&(a->MuxWaitEntries)
+ );
+ CapturedMuxWaitEntries = a->MuxWaitEntries;
+ for (i=0; i<CountMuxWaitEntries; i++) {
+ CapturedMuxWaitEntries->ulUser = MuxWaitEntries->ulUser;
+ rc = Od2ValidateSemaphoreHandle(
+ MuxWaitEntries->hsemCur,
+ &SharedSem,
+ (PULONG)&CapturedMuxWaitEntries->hsemCur
+ );
+ if (rc != NO_ERROR) {
+ break;
+ }
+ else
+ if (!SharedSem) {
+ rc = ERROR_WRONG_TYPE;
+ break;
+ }
+ else {
+ MuxWaitEntries++;
+ CapturedMuxWaitEntries++;
+ }
+ }
+ }
+ else {
+ a->MuxWaitEntries = NULL;
+ }
+
+ if (rc != NO_ERROR) {
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ }
+
+ return( rc );
+ }
+
+
+ //
+ // Pass the call to the OS/2 subsystem to create the system wide
+ // semaphore handle value.
+ //
+
+ a->CreateAttributes = CreateAttributes | DC_SEM_SHARED;
+ a->CountMuxWaitEntries = CountMuxWaitEntries;
+
+ rc = Od2CallSubsystem( &m,
+ CaptureBuffer,
+ Os2CreateMuxWaitSem,
+ sizeof( *a )
+ );
+
+ //
+ // Free any capture buffer, since the subsystem has saved away any
+ // semaphore name in its table.
+ //
+
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ }
+
+ //
+ // At this point, the semaphore handle index has been stored in
+ // a->HandleIndex by the OS/2 subsystem, if rc is NO_ERROR
+ //
+
+ }
+ else {
+ //
+ // Private semaphore. Allocate the muxwait semaphore structure.
+ // Return an error if not enough memory to allocate the structure.
+ //
+
+ MuxWait = RtlAllocateHeap( Od2Heap, 0, sizeof( *MuxWait ) );
+ if (MuxWait == NULL) {
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ //
+ // Initialize the muxwait semaphore sturcture to contain zero records.
+ //
+
+ MuxWait->CountMuxWaitRecords = 0;
+ MuxWait->Type = 0;
+ MuxWait->WaitAll = (BOOLEAN)((CreateAttributes & DCMW_WAIT_ALL) != 0);
+ MuxWait->Reserved = 0;
+
+
+ //
+ // Loop over the input array of SEMRECORDs adding them one at a time
+ // to the muxwait semaphore. Bail out of loop if any errors occur.
+ // Lock the semaphore table prior to entering the loop so that things
+ // change change out from under us.
+ //
+
+ AcquireHandleTableLock( SemaphoreTable );
+ for (i=0; i<CountMuxWaitEntries; i++) {
+ rc = Od2AddMuxWait( MuxWait,
+ MuxWaitEntries
+ );
+ if (rc != NO_ERROR) {
+ break;
+ }
+ else {
+ MuxWaitEntries++;
+ }
+ }
+
+ //
+ // All done. If successful, store the address of the muxwait structure
+ // in the semaphore structure.
+ //
+
+ if (rc == NO_ERROR) {
+ Semaphore.u.MuxWait = MuxWait;
+ }
+ }
+
+ //
+ // Create an entry in the appropriate semaphore table, which will copy
+ // the semaphore structure into the table entry and return an index to
+ // the entry in a->HandleIndex
+ //
+
+ if (rc != NO_ERROR ||
+ !Or2CreateHandle( SemaphoreTable,
+ &a->HandleIndex,
+ (PVOID)&Semaphore
+ )
+ ) {
+ //
+ // Error occurred. Cleanup any partial results.
+ //
+
+ if (!SharedSem) {
+ if (MuxWait != NULL) {
+ //
+ // For a private muxwait semaphore, deconstruct whatever
+ // portion of the muxwait semaphore that was successfully
+ // constructed and then free the allocated memory and release
+ // the lock we acquired at the beginning of the construction
+ // process.
+ //
+
+ while (Od2DeleteMuxWait( MuxWait, 0, 0 ) == NO_ERROR) {
+ ;
+ }
+
+ RtlFreeHeap( Od2Heap, 0, MuxWait );
+ }
+
+ ReleaseHandleTableLock( SemaphoreTable );
+ }
+ else
+ if (a->HandleIndex != -1) {
+ //
+ // If this is a shared semaphore that successfully created the
+ // handle in the OS/2 subsystem, then call the subsystem to
+ // close our reference to this shared OS/2 semaphore.
+ //
+
+ a1->HandleIndex = a->HandleIndex;
+ Od2CallSubsystem( &m, NULL, Os2CloseMuxWaitSem, sizeof( *a1 ) );
+ }
+
+
+ //
+ // Return the error code to the caller.
+ //
+
+ if (rc == NO_ERROR) {
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ else {
+ return( rc );
+ }
+ }
+
+
+ //
+ // Okay to release the lock we held while building the private muxwait
+ // semaphore.
+ //
+
+ if (!SharedSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ }
+
+
+ //
+ // Success. Store a valid OS/2 2.0 Semaphore handle in the location
+ // specified by the caller and return success to the caller.
+ //
+
+ *MuxWaitHandle = Od2ConstructSemaphoreHandle( SharedSem,
+ a->HandleIndex
+ );
+ return( NO_ERROR );
+}
+
+
+APIRET
+DosOpenMuxWaitSem(
+ IN PSZ ObjectName,
+ IN OUT PHMUX MuxWaitHandle
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSOPENMUXWAITSEM_MSG a = &m.u.DosOpenMuxWaitSem;
+ POS2_DOSCLOSEMUXWAITSEM_MSG a1 = &m.u.DosCloseMuxWaitSem;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ OD2_SEMAPHORE NewSemaphore;
+ POD2_SEMAPHORE Semaphore;
+ BOOLEAN SharedSem;
+ APIRET rc;
+
+
+ //
+ // probe handle pointer
+ //
+
+ try {
+ Od2ProbeForWrite( (PVOID)MuxWaitHandle, sizeof( MuxWaitHandle ), 1 );
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Capture and validate any semaphore name.
+ //
+
+ rc = Od2CaptureObjectName( ObjectName,
+ CANONICALIZE_SEMAPHORE,
+ 0,
+ &CaptureBuffer,
+ &a->ObjectName
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Determine if opening the semaphore by name or by handle.
+ //
+
+ if (CaptureBuffer != NULL) {
+ //
+ // If a semaphore name was given, then we are opening the semaphore
+ // by name, so call the OS/2 Subsystem to do the name lookup.
+ //
+
+ a->HandleIndex = 0xFFFFFFFF;
+ rc = Od2CallSubsystem( &m,
+ CaptureBuffer,
+ Os2OpenMuxWaitSem,
+ sizeof( *a )
+ );
+
+ //
+ // Free any capture buffer, since the name has served its purpose
+ // at this point.
+ //
+
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ RtlZeroMemory( &a->ObjectName, sizeof( a->ObjectName ) );
+ }
+
+ //
+ // Return if an error was discovered.
+ //
+
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // At this point, the semaphore handle index has been stored in
+ // a->HandleIndex by the OS/2 subsystem. Set the shared semaphore
+ // flag.
+ //
+
+ SharedSem = TRUE;
+
+
+ //
+ // If the caller specified both the name and the handle, make sure
+ // the named mapped to the same handle value that they specified.
+ //
+
+ if (*MuxWaitHandle != NULL &&
+ *MuxWaitHandle != Od2ConstructSemaphoreHandle( SharedSem,
+ a->HandleIndex
+ )
+ ) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+ }
+ else {
+ //
+ // Opening by handle. Validate the handle and get the shared/private
+ // flag.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( *MuxWaitHandle,
+ &SharedSem,
+ &a->HandleIndex
+ );
+
+ //
+ // Return if invalid handle.
+ //
+
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Creating is okay if this is a shared semaphore open. Return the
+ // appropriate error code if table does not exist or cant be created.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, SharedSem );
+ if (!SemaphoreTable) {
+ return( SharedSem ? ERROR_NOT_ENOUGH_MEMORY : ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Now lock the semaphore table while we figure out what we are doing and
+ // do it.
+ //
+
+ AcquireHandleTableLock( SemaphoreTable );
+
+ //
+ // See if the semaphore handle maps to an allocated entry in the table.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ a->HandleIndex,
+ TRUE
+ );
+ if (Semaphore == NULL || *(PULONG)Semaphore == 0) {
+ //
+ // No entry in the table for this semaphore handle. Error if not
+ // a shared semaphore.
+ //
+
+ if (!SharedSem) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+ else {
+
+ //
+ // This is the first usage of this shared semaphore handle by
+ // the calling process, so call the OS/2 subsystem so that it
+ // can bump its reference count.
+ //
+
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2OpenMuxWaitSem,
+ sizeof( *a )
+ );
+ if (rc == NO_ERROR) {
+ //
+ // If we succeeded, then the semaphore was not deleted
+ // in between the two calls to the subsystem, so add an
+ // entry for this handle in the semaphore table.
+ //
+
+ NewSemaphore.Type = Od2MuxWaitSem;
+ NewSemaphore.Shared = TRUE;
+ NewSemaphore.PointerCount = 0;
+ NewSemaphore.OpenCount = 1;
+ NewSemaphore.u.MuxWait = 0;
+
+ if (!Or2CreateHandle( SemaphoreTable,
+ &a->HandleIndex,
+ (PVOID)&NewSemaphore
+ )
+ ) {
+ //
+ // Unable to create the entry. Call the OS/2 subsystem
+ // to close our reference to this shared OS/2 semaphore.
+ // Set the appropriate error code.
+ //
+
+ a1->HandleIndex = a->HandleIndex;
+ Od2CallSubsystem( &m,
+ NULL,
+ Os2CloseMuxWaitSem,
+ sizeof( *a1 )
+ );
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+ }
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is a MuxWait semaphore.
+ // Set the appropriate error code if not.
+ //
+
+ else
+ if (Semaphore->Type != Od2MuxWaitSem) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+
+ //
+ // Entry in semaphore table is for a MuxWait semaphore, see if the
+ // OpenCount is about to overflow, and set the appropriate error code
+ // if it is.
+ //
+
+ else
+ if (Semaphore->OpenCount == 0xFFFF) {
+ rc = ERROR_TOO_MANY_OPENS;
+ }
+
+ //
+ // Everything is okay, so bump the open count in the semaphore table entry.
+ //
+
+ else {
+ Semaphore->OpenCount++;
+ }
+
+ //
+ // All done mucking about, so release the semaphore table lock.
+ //
+
+ ReleaseHandleTableLock( SemaphoreTable );
+
+ //
+ // If no errors, store a valid OS/2 2.0 Semaphore handle in the location
+ // specified by the caller and return success to the caller.
+ //
+
+ if (rc == NO_ERROR) {
+ *MuxWaitHandle = Od2ConstructSemaphoreHandle( SharedSem,
+ a->HandleIndex
+ );
+ }
+
+ //
+ // Return an error code to the caller.
+ //
+
+ return( rc );
+}
+
+
+APIRET
+DosCloseMuxWaitSem(
+ IN HMUX MuxWaitHandle
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSCLOSEMUXWAITSEM_MSG a = &m.u.DosCloseMuxWaitSem;
+ POD2_MUXWAIT_SEMAPHORE MuxWait;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ BOOLEAN SharedSem;
+ APIRET rc;
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( MuxWaitHandle,
+ &SharedSem,
+ &a->HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ a->HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is a MuxWait semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2MuxWaitSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table is for a MuxWait semaphore, so decrement the
+ // OpenCount and see if it has gone to zero.
+ //
+
+ if (--Semaphore->OpenCount == 0) {
+ //
+ // OpenCount is now zero, so we can really close the semaphore
+ // and delete the entry in the semaphore table.
+ //
+
+ //
+ // First make sure that no thread in this process is waiting on this
+ // muxwait semaphore. If there is one waiting on it, increment the
+ // open count and return an error.
+ //
+
+ if (Od2SearchForWaitingThread( Semaphore )) {
+ Semaphore->OpenCount++;
+ ReleaseHandleTableLock( SemaphoreTable );
+ rc = ERROR_SEM_BUSY;
+ }
+ else {
+ //
+ // Okay to really close this muxwait semaphore. First destroy
+ // the handle, which will unlock the handle table.
+ //
+
+ MuxWait = Semaphore->u.MuxWait;
+ Or2DestroyHandle( SemaphoreTable, a->HandleIndex );
+
+ if (!SharedSem) {
+ //
+ // If not a shared semaphore, free the muxwait structure
+ // associated with this muxwait semaphore.
+ //
+
+ if (MuxWait != NULL) {
+ while (Od2DeleteMuxWait( MuxWait, 0, 0 ) == NO_ERROR) {
+ ;
+ }
+
+ RtlFreeHeap( Od2Heap, 0, MuxWait );
+ }
+ }
+ else {
+
+ //
+ // If this is a shared semaphore, call the subsystem so that it
+ // can decrement its open count, as this process is no longer
+ // using the shared semaphore handle.
+ //
+
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2CloseMuxWaitSem,
+ sizeof( *a )
+ );
+ }
+ }
+ }
+ else {
+ //
+ // OpenCount is still non-zero, so just release the semaphore table
+ // lock.
+ //
+
+ ReleaseHandleTableLock( SemaphoreTable );
+ }
+
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
+
+
+APIRET
+DosWaitMuxWaitSem(
+ IN HMUX MuxWaitHandle,
+ IN ULONG Timeout,
+ OUT PULONG UserValue
+ )
+{
+ NTSTATUS Status;
+ OS2_API_MSG m;
+ POS2_DOSWAITMUXWAITSEM_MSG a = &m.u.DosWaitMuxWaitSem;
+ POD2_MUXWAIT_SEMAPHORE MuxWait;
+ POD2_MUXWAIT_RECORD MuxWaitRecord;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ OD2_SEMAPHORE_TYPE MuxWaitType;
+ BOOLEAN SharedSem;
+ APIRET rc;
+ USHORT i;
+ HANDLE NtHandles[ MAXIMUM_WAIT_OBJECTS ];
+ PLARGE_INTEGER NtTimeout;
+
+ try {
+ *UserValue = 0;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Capture the timeout value and convert it into an NT timeout value.
+ //
+
+ NtTimeout = Od2CaptureTimeout( Timeout, (PLARGE_INTEGER)&a->Timeout );
+
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+retry:
+ rc = Od2ValidateSemaphoreHandle( MuxWaitHandle,
+ &SharedSem,
+ &a->HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ a->HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is a MuxWait semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2MuxWaitSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ if (SharedSem) {
+ Od2ThreadWaitingOnSemaphore( SemaphoreTable, Semaphore, TRUE );
+
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2WaitMuxWaitSem,
+ sizeof( *a )
+ );
+
+ Od2ThreadWaitingOnSemaphore( SemaphoreTable, Semaphore, FALSE );
+ }
+ else {
+ MuxWait = Semaphore->u.MuxWait;
+ if (MuxWait->CountMuxWaitRecords == 0) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_EMPTY_MUXWAIT );
+ }
+
+ MuxWaitRecord = &MuxWait->MuxWaitRecords[ 0 ];
+ MuxWaitType = MuxWait->Type;
+ for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
+ if (MuxWaitType == Od2EventSem) {
+ NtHandles[ i ] = MuxWaitRecord->Semaphore->u.EventHandle;
+ }
+ else
+ if (MuxWaitType == Od2MutexSem) {
+ NtHandles[ i ] = MuxWaitRecord->Semaphore->u.Mutex->MutantHandle;
+ }
+ else {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ MuxWaitRecord++;
+ }
+
+ Od2ThreadWaitingOnSemaphore( SemaphoreTable, Semaphore, TRUE );
+
+ Status = NtWaitForMultipleObjects(
+ (CHAR)i,
+ NtHandles,
+ MuxWait->WaitAll ? WaitAll : WaitAny,
+ TRUE,
+ NtTimeout
+ );
+ if (NT_SUCCESS( Status )) {
+ if (Status <= STATUS_WAIT_63) {
+ *UserValue = MuxWait->MuxWaitRecords[ (ULONG)(Status & 0x3F)
+ ].UserKey;
+ rc = NO_ERROR;
+ }
+ else
+ if (Status == STATUS_ABANDONED) {
+ rc = ERROR_SEM_OWNER_DIED;
+ }
+ else
+ if (Status == STATUS_TIMEOUT) {
+ rc = ERROR_TIMEOUT;
+ }
+ else
+ if (Status == STATUS_USER_APC || Status == STATUS_ALERTED) {
+ rc = ERROR_SS_RETRY;
+ }
+ else {
+ rc = Or2MapStatus( Status );
+ }
+ }
+ else {
+ rc = Or2MapStatus( Status );
+ }
+
+ Od2ThreadWaitingOnSemaphore( SemaphoreTable, Semaphore, FALSE );
+
+ if (rc == ERROR_SS_RETRY) {
+ goto retry;
+ }
+ }
+
+ return( rc );
+}
+
+
+APIRET
+DosAddMuxWaitSem(
+ IN HMUX MuxWaitHandle,
+ IN PSEMRECORD MuxWaitEntry
+ )
+{
+ OS2_API_MSG m, m1;
+ POS2_DOSADDMUXWAITSEM_MSG a = &m.u.DosAddMuxWaitSem;
+ POS2_ALERTMUXWAITER_MSG a1 = &m1.u.AlertMuxWaiter;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ POD2_THREAD Thread;
+ BOOLEAN SharedSem;
+ APIRET rc;
+
+
+ //
+ // probe MuxWaitEntry buffer
+ //
+
+ try {
+ Od2ProbeForRead(MuxWaitEntry,sizeof(SEMRECORD),1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( MuxWaitHandle,
+ &SharedSem,
+ &a->HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ a->HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is a MuxWait semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2MuxWaitSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ if (SharedSem) {
+ a->MuxWaitEntry.ulUser = MuxWaitEntry->ulUser;
+ rc = Od2ValidateSemaphoreHandle( MuxWaitEntry->hsemCur,
+ &SharedSem,
+ (PULONG)&a->MuxWaitEntry.hsemCur
+ );
+ if (rc == NO_ERROR && !SharedSem) {
+ rc = ERROR_WRONG_TYPE;
+ }
+
+ if (rc == NO_ERROR) {
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2AddMuxWaitSem,
+ sizeof( *a )
+ );
+ }
+ }
+ else {
+ rc = Od2AddMuxWait( Semaphore->u.MuxWait, MuxWaitEntry );
+ if (rc == NO_ERROR &&
+ (Thread = Od2SearchForWaitingThread( Semaphore ))
+ ) {
+ rc = Od2CallSubsystem( &m1,
+ NULL,
+ Oi2AlertMuxWaiter,
+ sizeof( *a1 )
+ );
+ }
+ }
+
+ ReleaseHandleTableLock( SemaphoreTable );
+
+ return( rc );
+}
+
+
+APIRET
+DosDeleteMuxWaitSem(
+ IN HMUX MuxWaitHandle,
+ IN HSEM MuxWaitEntrySem
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSDELETEMUXWAITSEM_MSG a = &m.u.DosDeleteMuxWaitSem;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ BOOLEAN SharedSem;
+ APIRET rc;
+
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( MuxWaitHandle,
+ &SharedSem,
+ &a->HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ a->HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is a MuxWait semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2MuxWaitSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ if (SharedSem) {
+ rc = Od2ValidateSemaphoreHandle( MuxWaitEntrySem,
+ &SharedSem,
+ &a->EntryHandleIndex
+ );
+ if (!SharedSem) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+
+ if (rc == NO_ERROR) {
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2DeleteMuxWaitSem,
+ sizeof( *a )
+ );
+ }
+ }
+ else {
+ rc = Od2DeleteMuxWait( Semaphore->u.MuxWait, 0, MuxWaitEntrySem );
+ }
+
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( rc );
+}
+
+
+APIRET
+DosQueryMuxWaitSem(
+ IN HMUX MuxWaitHandle,
+ IN OUT PULONG CountMuxWaitEntries,
+ OUT SEMRECORD MuxWaitEntries[],
+ OUT PULONG CreateAttributes
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSQUERYMUXWAITSEM_MSG a = &m.u.DosQueryMuxWaitSem;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ PSEMRECORD CapturedMuxWaitEntries;
+ POD2_MUXWAIT_SEMAPHORE MuxWait;
+ POD2_MUXWAIT_RECORD MuxWaitRecord;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ BOOLEAN SharedSem;
+ APIRET rc;
+ USHORT i;
+
+ //
+ // probe CreateAttributes, CountMuxWaitEntries, and MuxWaitEntries buffer
+ //
+
+ try {
+ Od2ProbeForWrite( CountMuxWaitEntries, sizeof( CountMuxWaitEntries ), 1 );
+ Od2ProbeForWrite( CreateAttributes, sizeof( CreateAttributes ), 1 );
+ Od2ProbeForWrite(MuxWaitEntries,*CountMuxWaitEntries * sizeof(SEMRECORD),1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( MuxWaitHandle,
+ &SharedSem,
+ &a->HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ a->HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is a MuxWait semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2MuxWaitSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ if (SharedSem) {
+ a->CountMuxWaitEntries = *CountMuxWaitEntries;
+ i = (USHORT)(((a->CountMuxWaitEntries * sizeof( SEMRECORD )) + 3) & ~3);
+
+ CaptureBuffer = Od2AllocateCaptureBuffer( 1, 0, i );
+ if (CaptureBuffer == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else {
+ Od2AllocateMessagePointer( CaptureBuffer,
+ i,
+ &(PVOID)(a->MuxWaitEntries)
+ );
+
+ rc = Od2CallSubsystem( &m,
+ CaptureBuffer,
+ Os2QueryMuxWaitSem,
+ sizeof( *a )
+ );
+ if (rc == NO_ERROR) {
+ *CreateAttributes = a->CreateAttributes;
+ *CountMuxWaitEntries = a->CountMuxWaitEntries;
+ CapturedMuxWaitEntries = a->MuxWaitEntries;
+ for (i=0; i<(USHORT)a->CountMuxWaitEntries; i++) {
+ MuxWaitEntries->hsemCur =
+ Od2ConstructSemaphoreHandle(
+ TRUE, (ULONG)CapturedMuxWaitEntries->hsemCur
+ );
+ MuxWaitEntries->ulUser = CapturedMuxWaitEntries->ulUser;
+ MuxWaitEntries++;
+ CapturedMuxWaitEntries++;
+ }
+ }
+ else
+ if (rc == ERROR_PARAM_TOO_SMALL) {
+ *CountMuxWaitEntries = a->CountMuxWaitEntries;
+ }
+
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ }
+ }
+ else {
+ MuxWait = Semaphore->u.MuxWait;
+ if (*CountMuxWaitEntries < (ULONG)MuxWait->CountMuxWaitRecords) {
+ rc = ERROR_PARAM_TOO_SMALL;
+ }
+ else {
+ *CreateAttributes =
+ (Semaphore->Shared ? DC_SEM_SHARED : 0) |
+ (MuxWait->WaitAll ? DCMW_WAIT_ALL : DCMW_WAIT_ANY);
+ MuxWaitRecord = &MuxWait->MuxWaitRecords[ 0 ];
+ for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
+ MuxWaitEntries->hsemCur = MuxWaitRecord->SemHandle;
+ MuxWaitEntries->ulUser = MuxWaitRecord->UserKey;
+ MuxWaitEntries++;
+ MuxWaitRecord++;
+ }
+
+ rc = NO_ERROR;
+ }
+
+ *CountMuxWaitEntries = (ULONG)MuxWait->CountMuxWaitRecords;
+ }
+
+ ReleaseHandleTableLock( SemaphoreTable );
+
+ return( rc );
+}
diff --git a/private/os2/client/dllname.c b/private/os2/client/dllname.c
new file mode 100644
index 000000000..a6b29c65c
--- /dev/null
+++ b/private/os2/client/dllname.c
@@ -0,0 +1,1862 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ name.c
+
+Abstract:
+
+ This module implements OS/2 V2.0 name processing
+
+Author:
+
+ Therese Stowell (thereses) 26-Sep-1989
+
+Revision History:
+
+ Yaron Shamir (YaronS) 7-June-91
+ Move Named Pipes from \OS2SS\DRIVES\NamedPipe to
+ \OS2SS\PIPE
+
+ Yaron Shamir (YaronS) 26-Aug-91
+ Support UNC. Link to \OS2SS\UNC
+
+ Beni Lavi (BeniL) 4-Mar-92
+ Support MAILSLOT. Link to \OS2SS\MAILSLOT
+
+--*/
+
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_QUEUES
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#ifdef DBCS
+// MSKK Oct.20.1993 V-AkihiS
+#include "conrqust.h"
+#include "os2win.h"
+#endif
+
+APIRET
+VerifyDriveExists(
+ IN ULONG DiskNumber
+ );
+
+#ifdef DBCS
+// MSKK Oct.27.1993 V-Akihis
+CHAR Od2InvalidCharacters[]= { '"',
+ '/',
+ (CHAR)OBJ_NAME_PATH_SEPARATOR,
+ ':',
+ '<',
+ '|',
+ '>',
+ '\0'
+ };
+
+CHAR Od2FatInvalidCharacters[]= { '"',
+ '/',
+ (CHAR)OBJ_NAME_PATH_SEPARATOR,
+ '[',
+ ']',
+ ':',
+ '<',
+ '|',
+ '>',
+ '+',
+ '=',
+ ';',
+ ',',
+ '\0'
+ };
+#else
+CHAR Od2InvalidCharacters[]= { '"',
+ '/',
+ (CHAR)OBJ_NAME_PATH_SEPARATOR,
+ '[',
+ ']',
+ ':',
+ '<',
+ '|',
+ '>',
+ '+',
+ '=',
+ ';',
+ ',',
+ '\0'
+ };
+#endif
+
+//character devices:
+// emulate existence of "default" devices
+// maintain list of installed devices. symbolic link to real name.
+//
+//question: what if device exists not in \DEV\ directory and process opens it?
+//
+//name processing
+//
+// - map all /s to \s
+// - process . and ..s
+// - prepend current directory to relative paths
+// - remove trailing blanks and dots
+// - detect UNC. compact multiple leading \s
+// - compact multiple \s
+// - detect pipe. disallow leading d:
+// - detect installed and "default" devices
+// - detect illegal chars?
+//
+//
+// detect device (in list of default/installed devices)
+// detect UNC (multiple leading \\s)
+// detect PIPE (leading \PIPE\)
+// if !(UNC || PIPE) && relative path
+// prepend current directory
+// process . and ..s
+// map all /s to \s
+// remove trailing blanks and dots
+//
+//
+
+BOOLEAN
+TestForPipe(
+ IN PSZ name
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether a filename is a pipe name.
+
+Arguments:
+
+ name - filename to test
+
+Return Value:
+
+ BOOLEAN - TRUE if the filename is a pipe name. FALSE
+ otherwise
+
+--*/
+
+{
+ while (ISSLASH(*name)) { // eat any extra slashes
+ name++;
+ }
+ if (_strnicmp(name,"pipe",4)) {
+ return FALSE;
+ }
+ if (!(ISSLASH(*(name+4)))) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOLEAN
+TestForMailslot(
+ IN PSZ name
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether a filename is a mailslot name.
+
+Arguments:
+
+ name - filename to test
+
+Return Value:
+
+ BOOLEAN - TRUE if the filename is a mailslot name. FALSE
+ otherwise
+
+--*/
+
+{
+ while (ISSLASH(*name)) { // eat any extra slashes
+ name++;
+ }
+ if (_strnicmp(name,"mailslot",8)) {
+ return FALSE;
+ }
+ if (!(ISSLASH(*(name+8)))) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+PSZ
+FindLastComponent(
+ IN PSZ String
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds the last component in a string. the string has not
+ been canonicalized.
+
+Arguments:
+
+ String - string to examine
+
+Return Value:
+
+ pointer to last component
+
+--*/
+
+{
+ PSZ LastComponent;
+
+#ifdef DBCS
+// MSKK Apr.11.1993 V-AkihiS
+ if ((!Ow2NlsIsDBCSLeadByte(String[COLON-1], SesGrp->DosCP)) && String[COLON] == ':') {
+#else
+ if (String[COLON] == ':') {
+#endif
+ LastComponent = String+FIRST_SLASH;
+ }
+ else {
+ LastComponent = String;
+ }
+ while (*String) {
+#ifdef DBCS
+// MSKK Apr.11.1993 V-AkihiS
+ if (Ow2NlsIsDBCSLeadByte(*String, SesGrp->DosCP)) {
+ String++;
+ if (*String) {
+ String++;
+ }
+ }
+ else {
+ if (ISSLASH(*String))
+ LastComponent = String;
+ String++;
+ }
+#else
+ if (ISSLASH(*String))
+ LastComponent = String;
+ String++; // BUGBUG make dbcs-correct
+#endif
+ }
+ if (ISSLASH(*LastComponent))
+ return LastComponent+1;
+ else
+ return LastComponent;
+}
+
+/*
+;*** DOSICANONICALIZE - Convert a path name into a standard format
+;
+; INTERNAL ONLY API. Used by a couple of dynamic link libraries.
+; The worker routine does NO error checking or memory protection
+; checks. It is possible to general an internal error if used
+; incorrectly. DO NOT PUBLISH.
+;
+; INVOKE PUSH@ ASCIIZ Source (2 words)
+; PUSH@ ASCIIZ Dest (2 words)
+; PUSH WORD BackupOffset (1 word)
+; PUSH WORD DestEnd (1 word)
+; PUSH WORD Flags (1 word)
+; call DOSICANONICALIZE
+;
+; RETURN (ax) = error code
+;
+*/
+void DosICanonicalize(PCHAR Source, PCHAR Dest, USHORT BackupOffset,
+ USHORT DestEnd, USHORT Flags)
+{
+ PCHAR SourcePtr,DestPtr;
+ char Buffer[256];
+ STRING tmpstr;
+
+ tmpstr.Length=0;
+ tmpstr.MaximumLength=256;
+ tmpstr.Buffer=Buffer;
+
+ SourcePtr = Source + BackupOffset;
+ DestPtr = Dest + BackupOffset;
+
+ Od2Canonicalize(
+ SourcePtr,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &tmpstr,
+ NULL, // OUT PHANDLE DirectoryHandle OPTIONAL,
+ NULL, // OUT PULONG ParseFlags OPTIONAL,
+ NULL // OUT PULONG FileType OPTIONAL
+ );
+ strncpy(DestPtr,tmpstr.Buffer,DestEnd-BackupOffset);
+}
+
+APIRET
+Od2Canonicalize(
+ IN PSZ Name,
+ IN ULONG ExpectedType,
+ OUT PSTRING CanonicalString,
+ OUT PHANDLE DirectoryHandle OPTIONAL,
+ OUT PULONG ParseFlags OPTIONAL,
+ OUT PULONG FileType OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine canonicalizes a filename and determines its type, based
+ on naming conventions.
+
+Arguments:
+
+ Name - Supplies a pointer to a null terminated path name that will be
+ parsed.
+
+ ExpectedType - Supplies the expected type of the path string that will be
+ parsed. Any of the following:
+
+ CANONICALIZE_FILE_DEV_OR_PIPE - the input path must refer to either
+ a local file or device name, a UNC file name, or a named pipe.
+
+ CANONICALIZE_FILE_OR_DEV - the input path must refer to either
+ a local file or device name, or a UNC file name. Named pipes
+ are treated as local files. Used by DosMove for renaming
+ files that begin with \pipe
+
+ CANONICALIZE_SHARED_MEMORY - the input path must refer to a shared
+ memory section. This means it must begin with \sharemem\
+
+ CANONICALIZE_SEMAPHORE - the input path must refer to a 32-bit
+ semaphore name. This means it must begin with \sem32\
+
+ CANONICALIZE_QUEUE - the input path must refer to a 32-bit queue
+ name. This means it must begin with \queues\
+
+ CANONICALIZE_MAILSLOT - the input path must refer to a mailslot
+ name. This means it must begin with \mailslot\ or \\*\mailslot\
+
+ CanonicalString - Supplies a pointer to a counted string that will be
+ set to point to a buffer containing the result of canonicalizing
+ the input path string. The space for the buffer is allocated
+ from the heap specified by the OutputHeap parameter or Od2Heap
+ if that parameter is not specified.
+
+ DirectoryHandle - Supplies an optional pointer to a place to store an
+ NT Directory handle if the output string can be expressed as a
+ relative path string, relative to a current directory. If this
+ parameter is not specified or if the returned directory handle is
+ NULL then the canonical path string placed in OutputString will
+ be a fully qualified path string.
+
+ ParseFlags - Supplies an optional pointer to flags will be used to
+ return information about the results of the parse.
+
+ This parameter is ignored if the ExpectedType parameter is
+ anything other than CANONICALIZE_FILE_DEV_OR_PIPE or
+ CANONICALIZE_FILE_OR_DEV.
+
+ Flag values set by this function:
+
+ CANONICALIZE_META_CHARS_FOUND - the path name contains either an
+ asterisk (*) and/or question marks (?) in the last component
+ of the output string.
+
+ CANONICALIZE_IS_ROOT_DIRECTORY - the output string specifies a root
+ directory (e.g. D:\).
+
+ FileType - Supplies an optional pointer to a place to store the type
+ of object the canonical path string describes. Possible values
+ are:
+
+ FILE_TYPE_FILE
+ FILE_TYPE_NMPIPE
+ FILE_TYPE_DEV
+ FILE_TYPE_PSDEV
+ FILE_TYPE_MAILSLOT
+
+ This parameter is ignored if the ExpectedType parameter is
+ anything other than CANONICALIZE_FILE_DEV_OR_PIPE,
+ CANONICALIZE_FILE_OR_DEV or CANONICALIZE_MAILSLOT.
+
+Return Value:
+
+ OS/2 Error Code
+
+Return Value:
+
+ ERROR_FILE_NOT_FOUND - the filename is invalid.
+
+Note:
+
+ This routine allocates a buffer to hold the canonicalized name. it
+ is the caller's responsibility to free this buffer.
+
+Pseudocode:
+ determine expected prefix
+ if (file_pipe_or_dev)
+ detect UNC - insert correct prefix
+ detect devices - insert correct prefix
+ insert drive letter if needed - insert correct prefix
+ insert current directory if needed
+ else
+ check for ///prefix/
+ insert correct prefix
+ copy string, removing . and .., checking for illegal characters,
+ detecting metacharacters
+
+Routine Description:
+
+ This function performs the OS/2 V2.0 Path Name canonicalization
+ function. It takes as input a pointer to a null terminated string
+ that is considered unprobed, along with flags that specify optional
+ behavior while parsing the path string. The output of this function
+ is a canonical path string that is in NT format. The OS/2 Subsystem
+ creates the following objects in the NT Object Name Space in order
+ to support the output of this function:
+
+ \OS2SS object directory
+ \OS2SS\DRIVES object directory
+ \OS2SS\DRIVES\A: symbolic link => \Device\Floppy0
+ \OS2SS\DRIVES\C: symbolic link => \Device\Harddisk0\Partition1
+ \OS2SS\DRIVES\D: symbolic link => \Device\Harddisk1\Partition1
+ \OS2SS\PIPE symbolic link => \DosDevices\PIPE
+ \OS2SS\UNC symbolic link => \DosDevices\UNC
+ \OS2SS\DEVICES object directory
+ \OS2SS\DEVICES\NUL symbolic link => @0
+ \OS2SS\DEVICES\CON symbolic link => @1
+ \OS2SS\DEVICES\AUX symbolic link => @2
+ \OS2SS\DEVICES\COM1 symbolic link => @2.0
+ \OS2SS\DEVICES\COM2 symbolic link => @2.1
+ \OS2SS\DEVICES\COM3 symbolic link => @2.2
+ \OS2SS\DEVICES\COM4 symbolic link => @2.3
+ \OS2SS\DEVICES\PRN symbolic link => @3
+ \OS2SS\DEVICES\LPT1 symbolic link => @3.0
+ \OS2SS\DEVICES\LPT2 symbolic link => @3.1
+ \OS2SS\DEVICES\LPT3 symbolic link => @3.2
+ \OS2SS\DEVICES\KBD$ symbolic link => @4
+ \OS2SS\DEVICES\MOUSE$ symbolic link => @5
+ \OS2SS\DEVICES\CLOCK$ symbolic link => @6
+ \OS2SS\DEVICES\SCREEN$ symbolic link => @7
+ \OS2SS\DEVICES\POINTER$ symbolic link => @8
+ \OS2SS\QUEUES object directory
+ \OS2SS\SHAREMEM object directory
+ \OS2SS\SEMAPHORES object directory
+
+ The actual drive letters that will be defined in the \OS2SS\DRIVES
+ object directory actually depend upon the hardware configuration you
+ are running on. The above is an example for a particular machine.
+ Also notice that the GlobalDFS link actually is the same as the
+ LocalDFS link, namely the redirector. This will be true until we
+ implement a real name service file system.
+
+ Listed below are some examples of OS/2 path strings and the desired
+ NT path string. These examples assume the current drive and
+ directory for the OS/2 application are C:\Os2\Dll
+
+ OS/2 Path NT Path
+
+ pmwin.dll \OS2SS\DRIVES\C:\Os2\Dll\pmwin.dll
+ c:pmwin.dll \OS2SS\DRIVES\C:\Os2\Dll\pmwin.dll
+ C:\os2\dll\pmwin.dll \OS2SS\DRIVES\C:\os2\dll\pmwin.dll
+ c:\DLL\..\pmwin.dll \OS2SS\DRIVES\C:\Os2\DLL\pmwin.dll
+ c:\OS2\.\DLL\..\..\pmwin.dll \OS2SS\DRIVES\C:\OS2\DLL\pmwin.dll
+ \\mach\shr\a\b\c \OS2SS\DRIVES\LocalDFS\mach\shr\a\b\c
+ \\\mach\shr\a\b\c \OS2SS\DRIVES\GlobalDFS\mach\shr\a\b\c
+ \pipe\a\b\c\pipe.C \OS2SS\DRIVES\PIPE/a/b/c/pipe.C
+ con @1 - internal pseudo device
+ c:clock$ @6 - internal pseudo device
+ \a\b\c\screen$ @7 - internal pseudo device
+ \queUES\a\b\c\..\..\..\que. \OS2SS\QUEUES\QUE
+ \shaREmem\a\b\c\.\mem.c \OS2SS\SHAREDMEMORY\A/B/C/MEM.C
+ \sem32\a\b\c\..\sem.b \OS2SS\SEMAPHORES\A/B/SEM.B
+
+ Notice that for the last three examples, the output string contains
+ forward slashes instead of the normal backslash path separator.
+ This allows the names to be stored in the NT Object Name Space
+ without having to create the implied directory structure. The
+ NamedPipes example also does this, although this can be changed
+ if the NamedPipe File System is integrated into the NT Pinball File
+ System.
+
+ Also for the first five examples, since each NT path begins with the
+ current drive and directory, the output path returned by this function
+ will be just the file name, pmwin.dll and the NT handle that points
+ to the current directory of C: (i.e. \OS2SS\DRIVES\C:\Os2\Dll). This
+ allows cheaper relative opens to be used for most opens of files.
+
+ What follows is a description of how this function parses the input
+ path string:
+
+ - first allocates a buffer from Od2Heap. The buffer is large
+ enough to contain the longest possible OS/2 path string, plus
+ the space implied by the length of the input path string.
+
+ - figures out what prefix to use based on expected file type.
+
+ - if a file system path is expected (file, pipe, unc, or device),
+ determines what type of path is input. the correct constant prefix is
+ copied to the beginning of the buffer. A UNC path is first detected
+ by checking for two leading slashes. If "\\" is found,
+ "\OS2SS\UNC" is copied to the buffer.
+ Then the server name is copied to the buffer. The end of the server name is the backup limit for
+ '..' processing. Then a pipe path is checked for by looking for the
+ "PIPE" prefix at the beginning of the path. If it is found,
+ "\OS2SS\PIPE" is copied into the buffer. Also
+ set a flag so that all backslash path separator characters in the
+ output string will be mapped to forward slashes. The end of the
+ \pipe\ prefix is the backup limit for ".." processing. If the
+ path is not UNC or pipe, a device path is checked for by doing the
+ following:
+
+ lookup the trailing component of the output path string in
+ the \OS2SS\DEVICES directory as a symbolic link. If found
+ then extract the target string of the symbolic link and
+ parse it as follows:
+
+ @n[.m] - specifies a pseudo-device that is builtin to
+ the OS/2 Emulation subsystem. n is a decimal, zero
+ based index into the pseudo-device table. The ".m" is
+ optional and if present, m is a decimal, zero based
+ number that represents the unit number. For devices
+ with unit numbers, if m is not present a default unit
+ number should be used (zero in most cases). In either
+ case the type returned is FILE_TYPE_PSDEV. The caller
+ should key off of this type to determine if it should
+ parse the contents of the canonical name string.
+
+ NT Path String - specifies a fully qualified name of a
+ physical device. The type returned is FILE_TYPE_DEV
+
+ If the path is not a device, it is assumed to be a file. The
+ drive letter and current directory are copied to buffer if needed.
+ The buffer will contain \OS2SS\DRIVES\d:\currentdir at this point.
+ The slash after the drive letter is the backup limit for ".."
+ processing.
+
+ The filetype is set according to the type of path found.
+
+ - if a non-file system path is expected, the expected prefix is
+ verified and the constant and expected prefixes are copied to the
+ buffer.
+
+ if the ExpectedType parameter is CANONICALIZE_QUEUES, then see
+ if the beginning of the input path string matches \QUEUES\
+ ignoring case. If they do not match, then the
+ ERROR_PATH_NOT_FOUND error code is returned from this
+ function. Also set a flag so that all backslash path
+ separator characters in the output string will be mapped
+ to forward slashes. If it does match then \OS2SS\QUEUES\QUEUES
+ is copied to the buffer. The end of the second QUEUES prefix
+ is the backup limit for ".." processing.
+
+ if the ExpectedType parameter is CANONICALIZE_SEMAPHORE, then
+ see if the beginning of the input path string matches \SEM32\
+ ignoring case. If they do not match, then the
+ ERROR_PATH_NOT_FOUND error code is returned from this
+ function. Also set a flag so that all backslash path
+ separator characters in the output string will be mapped to
+ forward slashes. If it does match then \OS2SS\SEMAPHORES\SEM32
+ is copied to the buffer. The end of the SEM32 prefix
+ is the backup limit for ".." processing.
+
+ if the ExpectedType parameter is CANONICALIZE_SHARED_MEMORY,
+ then see if the beginning of the input path string matches
+ \SHAREMEM\ ignoring case. If they do not match, then the
+ ERROR_PATH_NOT_FOUND error code is returned from this
+ function. Also set a flag so that all backslash path
+ separator characters in the output string will be mapped
+ to forward slashes. If it does match then
+ \OS2SS\SHAREDMEMORY\SHAREMEM is copied to the buffer. The end of
+ the SHAREMEM prefix is the backup limit for ".." processing.
+
+ - copies the unprobed remainder of the input path string to the
+ allocated buffer, performing the following logic for each character:
+
+ - if an access violation exception occurs when fetching a
+ character from the input path string, the ERROR_INVALID_ADDRESS
+ error code is returned as the value of this function.
+
+ - forward slash (/) path separators into are converted to the
+ NT path separator character (OBJ_NAME_PATH_SEPARATOR).
+
+ - meta characters (* and ?) are detected. If found before a
+ path separator then the ERROR_PATH_NOT_FOUND error code is
+ returned as the value of this function.
+
+ - if the ExpectedType parameter is neither of
+ CANONICALIZE_FILE_DEV_OR_PIPE or CANONICALIZE_FILE_OR_DEV,
+ then lower case letters are converted to upper case when
+ they are copied to the output buffer.
+
+ - if the ExpectedType parameter is neither of
+ CANONICALIZE_FILE_DEV_OR_PIPE or CANONICALIZE_FILE_OR_DEV and
+ meta characters are detected then the ERROR_PATH_NOT_FOUND error
+ code is returned as the value of this function.
+
+ - if the input string begins with a character followed by a
+ colon (:), then map the drive letter to upper case.
+
+ - sequences one or more adjacent backslashes
+ (OBJ_NAME_PATH_SEPARATOR) are converted to a single backslash.
+
+ - process '.' and '..' path components. '.' are removed. '..'
+ components cause the immediately previous component to be
+ removed. i.e. d:\foo\..\bar -> d:\bar. An error is returned
+ if there is no component to remove.
+
+ - If specified by the earlier logic, the trailing path separator
+ of each component is set to be a forward slash after the copy.
+ This basically maps any multiple component path string into a
+ single component name.
+
+ - After copying each path component, remove trailing blanks
+ and periods. If the last path component contained meta
+ characters then put a trailing period at the end of the last
+ component if it does contained one or more trailing periods
+ already.
+
+ - when unicode strings are put into the system, the code page to
+ unicode conversion will happen in this step.
+
+ - return the type of path via the FileType parameter, which
+ must be specified if the ExpectedType parameter is
+ CANONICALIZE_FILE_DEV_OR_PIPE or CANONICALIZE_FILE_OR_DEV.
+
+ - if this function returns an error code instead of NO_ERROR then
+ free the output buffer that was allocated. Otherwise set the
+ Length and Maximum length fields in the counted string pointed
+ to by the OutputString parameter.
+
+--*/
+
+{
+ PSZ Dest,
+ Src,
+ LastComponent,
+ BackUpLimit;
+ CHAR c;
+ ULONG Drive;
+ PSTRING CurrentDirectoryString;
+ HANDLE CurrentDirectoryHandle;
+ ULONG CurrentDirectoryLength;
+ PSZ NameBuffer;
+ ULONG NameBufferLength;
+ APIRET RetCode;
+ PSZ PipePrefix;
+ PSZ MailslotPrefix;
+ PSZ UNCPrefix;
+ PSZ ExpectedPrefix;
+ PSZ ConstantPrefix;
+ PSZ Os2Name;
+ int RemoveBlanksAndDots;
+ ULONG ExpectedPrefixLength;
+ BOOLEAN MetaCharactersAllowed;
+ BOOLEAN PreserveCase;
+ BOOLEAN MapToRootName;
+ BOOLEAN ValidateChars;
+ ULONG OutputFlags;
+ ULONG OutputType;
+ NTSTATUS Status;
+ HANDLE DeviceHandle;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ STRING DeviceName;
+ UNICODE_STRING DeviceName_U;
+ WCHAR DeviceNameBuffer[ CCHMAXPATH ];
+#ifdef DBCS
+// Oct.27.1993 V-AkihiS
+ CHAR *InvalidCharacters = Od2InvalidCharacters;
+#endif
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint( "Od2Canonicalize: entering with path %s\n", Name);
+ }
+#endif
+
+ PipePrefix = NULL;
+ MailslotPrefix = NULL;
+ UNCPrefix = NULL;
+ PreserveCase = FALSE;
+ MetaCharactersAllowed = FALSE;
+ MapToRootName = TRUE;
+ ValidateChars = TRUE;
+ OutputType = 0xFFFFFFFF;
+ OutputFlags = 0;
+ CurrentDirectoryString = NULL;
+ CurrentDirectoryHandle = NULL;
+ Os2Name = NULL;
+ RetCode = NO_ERROR;
+
+ //
+ // determine the expected and constant prefixes of the path,
+ // where the constant prefix is the
+ //
+
+ switch( ExpectedType ) {
+ case CANONICALIZE_FILE_DEV_OR_PIPE:
+ case CANONICALIZE_FILE_OR_DEV:
+ case CANONICALIZE_MAILSLOT:
+ PipePrefix = "\\PIPE\\";
+ UNCPrefix = "\\UNC\\";
+ ExpectedPrefix = NULL;
+ ConstantPrefix = "\\OS2SS\\DRIVES";
+ PreserveCase = TRUE;
+ MetaCharactersAllowed = TRUE;
+ MapToRootName = FALSE;
+ OutputType = FILE_TYPE_FILE;
+ MailslotPrefix = "\\MAILSLOT\\";
+ break;
+
+ case CANONICALIZE_SHARED_MEMORY:
+ ExpectedPrefix = DA_SHAREMEM_NAMEPREFIX;
+ ConstantPrefix = "\\OS2SS\\SHAREMEM";
+ break;
+
+ case CANONICALIZE_SEMAPHORE:
+ ExpectedPrefix = DC_SEM_NAMEPREFIX;
+ ConstantPrefix = "\\OS2SS\\SEMAPHORES";
+ break;
+
+ case CANONICALIZE_QUEUE:
+ ExpectedPrefix = DC_QUEUES_NAMEPREFIX;
+ ConstantPrefix = "\\OS2SS\\QUEUES";
+ break;
+
+ default:
+ return( ERROR_INVALID_FUNCTION );
+ }
+
+ if (ExpectedPrefix != NULL) {
+ ExpectedPrefixLength = strlen( ExpectedPrefix );
+ }
+
+ try {
+ if (*Name == '\0')
+ return ERROR_FILE_NOT_FOUND;
+
+ if (*Name == ' ' && *(Name+1) == '\0')
+ return ERROR_PATH_NOT_FOUND;
+
+ //
+ // initialize DirectoryHandle to indicate full path returned.
+ //
+
+ if (DirectoryHandle != NULL) {
+ *DirectoryHandle = NULL;
+ }
+
+ //
+ // allocate name buffer. make it big enough that we can't overrun the
+ // end of it.
+ //
+
+ NameBufferLength = CCHMAXPATH + strlen(Name)+ CANONICALIZE_MAX_PREFIX_LENGTH;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (( NameBuffer = RtlAllocateHeap(Od2Heap,0,NameBufferLength)) == NULL )
+ {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ Dest = NameBuffer;
+ Src = Name;
+
+
+
+ //
+ // if we're doing a canonicalization for an IO system API (a file, device,
+ // UNC, or pipe name is expected), we
+ // detect UNC - insert correct prefix
+ // detect devices - insert correct prefix
+ // insert drive letter if needed - insert correct prefix
+ // insert current directory if needed
+ //
+
+ if ((ExpectedType == CANONICALIZE_FILE_DEV_OR_PIPE) ||
+ (ExpectedType == CANONICALIZE_FILE_OR_DEV) ||
+ (ExpectedType == CANONICALIZE_MAILSLOT)
+ ) {
+
+ //
+ // detect UNC and pipe names
+ //
+ // NOTES on UNC naming conventions:
+ //
+ // Two or three leading slashes are OK, and unmodified.
+ //
+ // Four or more leading slashes are compressed to three
+ // leading slashes.
+ //
+ // Any number of slashes as a separator, in a local or UNC
+ // path, are compressed to a single slash.
+ //
+ // The \\ is a short hand for the 'current name space' whereas
+ // three slashes are the root of the world-wide name space.
+ //
+ //
+
+ CurrentDirectoryString = NULL;
+ if (ISSLASH(Src[0])) {
+ if (ISSLASH(Src[1])) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint( "processing UNC name\n");
+ }
+#endif
+ OutputType = FILE_TYPE_UNC;
+
+ //
+ // copy constant prefix to buffer
+ //
+ ConstantPrefix = "\\OS2SS";
+ while (*Dest++ = *ConstantPrefix++)
+ ;
+ Dest--;
+
+ Os2Name = Dest; // Os2Name points to beginning of OS/2 name
+
+ while (*Dest++ = *UNCPrefix++)
+ ;
+ Dest--;
+
+ Src += 2; // for the two slashes
+ if (ISSLASH(*Src)) {
+ RetCode = ERROR_BAD_NETPATH;
+ goto ErrorExit; // go free buffer(s) and return error
+ }
+
+ Os2Name = Dest-1; // Os2Name points to beginning of OS/2 name
+
+ /*
+ path is \OS2SS\UNC\
+ copy the server name.
+ */
+
+ while (!ISPATHSEP(*Src)) {
+ if ((*Src == '?') ||
+ ((*Src == '*') && (ExpectedType != CANONICALIZE_MAILSLOT))) {
+ RetCode = ERROR_BAD_NETPATH;
+ goto ErrorExit;
+ }
+#ifdef JAPAN
+// MSKK Feb.18.1993 V-AkihiS
+ if (Ow2NlsIsDBCSLeadByte(*Src, SesGrp->DosCP)) {
+ *Dest++ = *Src++;
+ if (*Src) {
+ //
+ // Check Trailing byte is valid or not.
+ //
+ if ((UCHAR)*Src < 0x40 || (UCHAR)*Src > 0xFC || (UCHAR)*Src == 0x7F) {
+ RetCode = ERROR_BAD_NETPATH;
+ goto ErrorExit;
+ } else {
+ *Dest++ = *Src++;
+ }
+ } else {
+ RetCode = ERROR_BAD_NETPATH;
+ goto ErrorExit;
+ }
+ }
+ else {
+ if (ValidateChars && ((UCHAR)*Src < (UCHAR)' ' ||
+ strchr( InvalidCharacters, *Src )
+ )
+ ) {
+ RetCode = ERROR_BAD_NETPATH;
+ goto ErrorExit;
+ }
+ *Dest++ = *Src++;
+ }
+#else
+ if (ValidateChars && ((UCHAR)*Src < (UCHAR)' ' ||
+ strchr( Od2InvalidCharacters, *Src )
+ )
+ ) {
+ RetCode = ERROR_BAD_NETPATH;
+ goto ErrorExit;
+ }
+ *Dest++ = *Src++;
+#endif
+ }
+ if (*Src == '\0') {
+ RetCode = ERROR_BAD_NETPATH;
+ goto ErrorExit; // go free buffer(s) and return error
+ }
+ *Dest++ = (CHAR)OBJ_NAME_PATH_SEPARATOR; // append '\'
+ Src++;
+ while (ISSLASH(*Src))
+ Src++;
+ BackUpLimit = Dest; // set up backup pointer. points after server name
+
+ /*
+ at this point, we have a UNC name composed of
+ \OS2SS\UNC\servername\
+ ^
+ |
+ dest
+
+ \\\\servername\\\sharepoint
+ ^
+ |
+ src
+ */
+ }
+ else if (TestForPipe(Src)) { // \PIPE\ ?
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint( "processing pipe name\n");
+ }
+#endif
+ OutputType = FILE_TYPE_NMPIPE;
+
+ //
+ // this code assumes that pipes are in \OS2SS
+ // copy \OS2SS\PIPE into buffer
+ //
+
+ //
+ // we can't use drives for pipes
+ // (see ..\server\srvname.c)
+ //
+ ConstantPrefix = "\\OS2SS";
+ while (*Dest++ = *ConstantPrefix++)
+ ;
+ Dest--;
+
+ Os2Name = Dest; // Os2Name points to beginning of OS/2 name
+
+ while (*Dest++ = *PipePrefix++)
+ ;
+ Dest--;
+
+ /*
+ update src pointer past \pipe\
+ */
+
+ while (ISSLASH(*Src)) // eat any extra slashes
+ Src++;
+ Src += 5;
+ while (ISSLASH(*Src)) // eat any extra slashes
+ Src++;
+ if (*Src == '\0') {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto ErrorExit; // go free buffer(s) and return error
+ }
+ ValidateChars = TRUE;
+ BackUpLimit = Dest; // set up backup pointer. points after "\pipe\"
+ }
+ else if (TestForMailslot(Src)) { // \MAILSLOT\ ?
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint( "processing mailslot name\n");
+ }
+#endif
+ OutputType = FILE_TYPE_MAILSLOT;
+
+ //
+ // this code assumes that mailslots are in \OS2SS
+ // copy \OS2SS\MAILSLOT into buffer
+ //
+
+ //
+ // we can't use drives for maislots
+ // (see ..\server\srvname.c)
+ //
+ ConstantPrefix = "\\OS2SS";
+ while (*Dest++ = *ConstantPrefix++)
+ ;
+ Dest--;
+
+ Os2Name = Dest; // Os2Name points to beginning of OS/2 name
+
+ while (*Dest++ = *MailslotPrefix++)
+ ;
+ Dest--;
+
+ /*
+ update src pointer past \mailslot\
+ */
+
+ while (ISSLASH(*Src)) // eat any extra slashes
+ Src++;
+ Src += 9;
+ while (ISSLASH(*Src)) // eat any extra slashes
+ Src++;
+ if (*Src == '\0') {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto ErrorExit; // go free buffer(s) and return error
+ }
+ ValidateChars = TRUE;
+ BackUpLimit = Dest; // set up backup pointer. points after "\pipe\"
+ }
+ }
+
+ // haven't detected pipe or UNC
+ if (OutputType == FILE_TYPE_FILE) {
+
+#ifdef DBCS
+// MSKK Oct.27.1993 V-AkihIS
+ InvalidCharacters = Od2FatInvalidCharacters;
+#endif
+ /*
+ detect devices here.
+ device names are recognized as follows:
+ installed/default devices are allowed in any d:\path
+ pseudochar devices must match exactly, starting with \DEV\
+ */
+
+ LastComponent = FindLastComponent(Src);
+
+ if (*LastComponent)
+ {
+ PWSTR DotPlace;
+ USHORT NewLen;
+
+ //
+ // Open as a symbolic link, relative to the OS/2 Device Directory in the
+ // object name space, the last component of the file path.
+ //
+
+ Od2InitMBString( &DeviceName, LastComponent );
+
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &DeviceName_U,
+ &DeviceName,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("Od2Canonicalize: no memory for Unicode Conversion\n");
+ }
+#endif
+ //return RetCode;
+ goto ErrorExit;
+ }
+
+ for (DotPlace = DeviceName_U.Buffer, NewLen = 0;
+ NewLen < DeviceName_U.Length;
+ DotPlace++, NewLen += sizeof(WCHAR)) {
+
+ if ((*DotPlace == L'.') || (*DotPlace == L' ')) {
+
+ DeviceName_U.Length = NewLen;
+ break;
+ }
+ }
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &DeviceName_U,
+ OBJ_CASE_INSENSITIVE,
+ Od2DeviceDirectory,
+ NULL
+ );
+
+ Status = NtOpenSymbolicLinkObject( &DeviceHandle,
+ SYMBOLIC_LINK_QUERY,
+ &ObjectAttributes
+ );
+ RtlFreeUnicodeString (&DeviceName_U);
+ if (NT_SUCCESS( Status )) {
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint( "processing device name\n");
+ }
+#endif
+ //
+ // Found a symbolic link in the OS/2 Device Directory whose
+ // name matches the last component of the file path. Query
+ // the target string from the symbolic link.
+ //
+
+ DeviceName_U.Length = 0;
+ DeviceName_U.MaximumLength = sizeof( DeviceNameBuffer );
+ DeviceName_U.Buffer = DeviceNameBuffer;
+ Status = NtQuerySymbolicLinkObject( DeviceHandle,
+ &DeviceName_U,
+ NULL
+ );
+ NtClose(DeviceHandle);
+ if (NT_SUCCESS( Status )) {
+ //
+ // Successfully queried the target string, so copy it as
+ // is to the output path buffer, obliterating what was there.
+ // Next determine the file type by examining the first
+ // character of the target string. @n is a pseudo-device
+ // builtin to the OS/2 subsystem. Otherwise it is a physical
+ // NT device path.
+ //
+
+ RetCode = Od2UnicodeStringToMBString( &DeviceName, &DeviceName_U, TRUE );
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS )
+ {
+ DbgPrint("Od2Canonicalize: no memory for Unicode Conversion-2\n");
+ }
+#endif
+ //return RetCode;
+ goto ErrorExit;
+ }
+
+ strncpy( Dest,
+ &DeviceName.Buffer[1],
+ DeviceName.Length - 1
+ );
+
+ *(Dest + DeviceName.Length - 1) = '\0'; // for debug printing
+
+ if (DeviceName.Buffer[0] == '@') {
+ OutputType = FILE_TYPE_PSDEV;
+ }
+ else if (DeviceName.Buffer[0] == '#') {
+ OutputType = FILE_TYPE_COM;
+ }
+ else {
+ OutputType = FILE_TYPE_DEV;
+ }
+ CanonicalString->MaximumLength = (USHORT) NameBufferLength;
+ CanonicalString->Length = DeviceName.Length - 1;
+ CanonicalString->Buffer = NameBuffer;
+ Od2FreeMBString( &DeviceName );
+ goto ErrorExit;
+ }
+ else {
+ RetCode = ERROR_PATH_NOT_FOUND; // FIX, FIX - Should never happen.
+ goto ErrorExit;
+ }
+ }
+ }
+ }
+
+ //
+ // if we didn't detect a device, we have a file. add a drive letter
+ // and current directory, if necessary.
+ //
+
+ if (OutputType == FILE_TYPE_FILE) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint( "processing file name\n");
+ }
+#endif
+
+ //
+ // A xxxx\ is not allowed
+ //
+#ifdef DBCS
+// MSKK Feb.26.1993 V-AkihiS
+ {
+ ULONG i = 0;
+ BOOLEAN LastSlashFlag = FALSE;
+ BOOLEAN ColonFlag = FALSE;
+
+ //
+ // Check last charater is '\' and privious character of last
+ // character is not ':'. If so(i.e. LastSlashFlag is true,
+ // when exiting while-loop), it is not allowed.
+ //
+ while (i < strlen(Name)) {
+ if (Ow2NlsIsDBCSLeadByte(Name[i], SesGrp->DosCP)) {
+ LastSlashFlag = ColonFlag = FALSE;
+ i++;
+ if (i < strlen(Name)) i ++;
+ } else {
+ if (Name[i] == ':') {
+ LastSlashFlag = FALSE;
+ ColonFlag = TRUE;
+ } else if (ISSLASH(Name[i])) {
+ if (ColonFlag) {
+ LastSlashFlag = FALSE;
+ } else {
+ LastSlashFlag = TRUE;
+ }
+ ColonFlag = FALSE;
+ } else {
+ LastSlashFlag = ColonFlag = FALSE;
+ }
+ i++;
+ }
+ }
+ if ( LastSlashFlag && (strlen(Name) > 1)) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint( "Canonicalize: filename is D:xxx\\, return ERROR_PATH_NOT_FOUND \n");
+ }
+#endif
+ return(ERROR_PATH_NOT_FOUND);
+ }
+
+ }
+#else
+ if ( ISSLASH(Name[strlen(Name)-1]) && (strlen(Name) > 1 )
+ && (Name[strlen(Name)-2] != ':') /* slash root is a fine name */ ) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint( "Canonicalize: filename is D:xxx\\, return ERROR_PATH_NOT_FOUND \n");
+ }
+#endif
+ return(ERROR_PATH_NOT_FOUND);
+ }
+#endif
+
+ //
+ // copy the constant prefix.
+ //
+
+ while (*Dest++ = *ConstantPrefix++)
+ ;
+ Dest--;
+ *Dest++ = (CHAR)OBJ_NAME_PATH_SEPARATOR;
+ Os2Name = Dest; // Os2Name points to beginning of OS/2 name
+#ifdef DBCS
+// MSKK Apr.11.1993 V-AkihiS
+ if (!(*(Src+1) == ':' && !IsDBCSLeadByte(*Src))) { // if no drive letter, get one
+#else
+ if (*(Src+1) != ':') { // if no drive letter, get one
+#endif
+ *Dest++ = CONVERTTOASCII(Od2CurrentDisk);
+ *Dest++ = ':';
+ Drive = Od2CurrentDisk;
+ }
+ else {
+
+ // figure out which zero-based drive to use
+
+ if (*Src > 'Z') {
+ Drive = *Src - 'a';
+ }
+ else {
+ Drive = *Src - 'A';
+ }
+ if (RetCode = VerifyDriveExists(Drive+1)){
+ return(RetCode);
+ }
+ *Dest++ = *Src++; // copy drive letter
+ *Dest++ = *Src++;
+ if (*Src == '\0') {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto ErrorExit; // go free buffer(s) and return error
+ }
+ }
+
+ //
+ // Buffer contains \\OS2SS\DRIVES\D:
+ // ^
+ // |
+ // dest
+ //
+ // d:\foo
+ // ^
+ // |
+ // src
+ //
+ // set up backup pointer
+
+ BackUpLimit = Dest; // set up backup pointer. points to first '\'
+
+ //
+ // prepend logondirectory here
+ //
+ // if (relative path)
+ // copy current directory;
+ // append '\';
+ // else
+ // copy first '\';
+ //
+
+ if (!ISSLASH(*Src)) { // if path not absolute
+
+ //
+ // if no current directory, append '\'
+ //
+
+ *Dest++ = (CHAR)OBJ_NAME_PATH_SEPARATOR;
+ RetCode = Od2GetCurrentDirectory(Drive,
+ &CurrentDirectoryString,
+ &CurrentDirectoryHandle,
+ &CurrentDirectoryLength,
+ FALSE
+ );
+ if (RetCode != NO_ERROR) {
+ goto ErrorExit; // go free buffer(s) and return error
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("GetCurrentDirectory returned %s\n",CurrentDirectoryString->Buffer);
+ }
+#endif
+ if (CurrentDirectoryHandle != NULL) { // if not root directory
+ CurrentDirectoryString->Length -= DRIVE_LETTER_SIZE + FILE_PREFIX_LENGTH;
+ CurrentDirectoryString->Buffer += DRIVE_LETTER_SIZE + FILE_PREFIX_LENGTH;
+ strncpy(Dest,
+ CurrentDirectoryString->Buffer,
+ CurrentDirectoryString->Length
+ );
+ Dest += CurrentDirectoryString->Length;
+ *Dest++ = (CHAR)OBJ_NAME_PATH_SEPARATOR;
+ }
+ }
+ else { // copy one '\' and eat any others
+ *Dest++ = (CHAR)OBJ_NAME_PATH_SEPARATOR;
+ Src++;
+ while (ISSLASH(*Src))
+ Src++;
+ }
+
+ /*
+ the buffer contains:
+ \OS2SS\DRIVES\D:\currentdir\
+ ^
+ |
+ dest
+ d:foo
+ ^
+ |
+ src
+ */
+ }
+ }
+
+ //
+ // we're doing canonicalization for a non IO system API - semaphores,
+ // queues, or shared memory. we check for the expected prefix and copy
+ // it to the buffer. there can be any number of slashes anywhere in
+ // the name. i.e. \\/\SEM32/////foo -> \SEM32\foo.
+ //
+
+ else {
+
+ //
+ // copy constant prefix to buffer
+ //
+
+ while (*Dest++ = *ConstantPrefix++)
+ ;
+ Dest--;
+
+ //
+ // verify that the expected prefix is there. advance Src past
+ // all leading slashes.
+ //
+
+ if (ISSLASH(*Src)) {
+ do {
+ Src++;
+ } while (ISSLASH(*Src));
+
+ //
+ // use the strnicmp to compare for the text part of the prefix and
+ // ISSLASH to compare for the trailing slash.
+ //
+
+#ifdef DBCS
+// MSKK Feb.26.1993 V-AkihiS
+ {
+ ULONG i = 0;
+ BOOLEAN SlashFlag = FALSE;
+
+ //
+ // verify whether the last character of the text part of
+ // the prefix is slash or not.
+ //
+ while (i < ExpectedPrefixLength - 1) {
+ if (Ow2NlsIsDBCSLeadByte(*(Src+i), SesGrp->DosCP)) {
+ SlashFlag = FALSE;
+ i++;
+ if (i < ExpectedPrefixLength - 1) {
+ i++;
+ }
+ } else {
+ if (ISSLASH(*(Src+i))) {
+ SlashFlag = TRUE;
+ } else {
+ SlashFlag = FALSE;
+ }
+ i++;
+ }
+ }
+
+ if (_strnicmp( Src, ExpectedPrefix+1, ExpectedPrefixLength-2 ) ||
+ !SlashFlag) {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ }
+ }
+#else
+ if (_strnicmp( Src, ExpectedPrefix+1 , ExpectedPrefixLength-2 ) ||
+ !(ISSLASH(*(Src+ExpectedPrefixLength-2)))) {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ }
+#endif
+
+ Os2Name = Dest; // Os2Name points to beginning of OS/2 name
+
+ //
+ // copy the expected prefix. Make sure terminating slash is
+ // the correct type.
+ //
+
+ while (c = *ExpectedPrefix++) {
+ if (c == (CHAR)OBJ_NAME_PATH_SEPARATOR && MapToRootName) {
+ c = '/';
+ }
+ *Dest++ = c;
+ }
+ BackUpLimit = Dest-1; // backup pointer. points to last '\'
+
+ //
+ // update the src pointer past the prefix and slashes
+ //
+
+ Src += ExpectedPrefixLength-1;
+ while (ISSLASH(*Src)) {
+ Src++;
+ }
+
+ //
+ // error if nothing after expected prefix
+ //
+
+ if (*Src == '\0') {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ }
+ }
+ else {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ }
+
+ if (RetCode) {
+ goto ErrorExit;
+ }
+
+ /* target
+ |
+ V
+ at this point, the target contains \OS2SS\xxx\xxx\
+ source
+ |
+ the source points after the expected prefix V
+ \SEM32\\
+ */
+
+ }
+
+ /*
+ copy user string
+
+ *Dest -> first char after d:\
+ *src -> first char after d:\
+
+ if we see a metacharacter, we verify that they're allowed. if there
+ is a metacharacter in any component other than the last, we return
+ an error.
+ */
+
+ LastComponent = Dest; // LastComponent points to first letter
+ while (*Src) {
+
+ //
+ // if we get here and meta characters have already been found, they
+ // aren't in the last component, so we return an error.
+ //
+
+ if (OutputFlags & CANONICALIZE_META_CHARS_FOUND) {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ goto ErrorExit;
+ }
+ RemoveBlanksAndDots=TRUE;
+
+ //
+ // if path is '.', copy . and don't remove dots
+ //
+
+ if ((*Src == '.') &&
+ (ISPATHSEP(Src[1]))) {
+ Src++;
+ Dest--;
+ RemoveBlanksAndDots=FALSE;
+ }
+
+ //
+ // else if path is '..', copy .. and don't remove dots
+ //
+
+ else if ((Src[0] == '.') &&
+ (Src[1] == '.') ) {
+ if (Src[2] == '.') {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ goto ErrorExit;
+ }
+ if (ISPATHSEP(Src[2])) {
+ Src += 2; // Src points past ..
+ Dest -= 2; // Dest points to char before last path sep
+#ifdef DBCS
+// MSKK Feb.28.1993 V-AkihiS
+ {
+ PSZ String, LastSlashPtr;
+
+ String = LastSlashPtr = NameBuffer;
+ while (String <= Dest) {
+ if (Ow2NlsIsDBCSLeadByte(*String, SesGrp->DosCP)) {
+ String++;
+ if (String <= Dest) {
+ String++;
+ }
+ } else {
+ if (ISSLASH(*String)) {
+ if (String >= BackUpLimit) {
+ LastSlashPtr = String;
+ }
+ }
+ String++;
+ }
+ }
+
+ if (ISSLASH(*LastSlashPtr)) {
+ Dest = LastSlashPtr;
+ } else {
+ Dest = BackUpLimit - 1;
+ RetCode = ERROR_PATH_NOT_FOUND;
+ goto ErrorExit; // go free buffer(s) and return error
+ }
+ }
+#else
+ while ((Dest >= BackUpLimit) && !(ISSLASH(*Dest))) { // have to use ISSLASH because of MapToRootName
+ Dest--; // BUGBUG make DBCS correct
+ }
+ if (!ISSLASH(*Dest)) {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ goto ErrorExit; // go free buffer(s) and return error
+ }
+#endif
+ RemoveBlanksAndDots=FALSE;
+ }
+ else {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto ErrorExit;
+ }
+ }
+
+ //
+ // else copy path
+ //
+
+ else {
+ while (!ISPATHSEP(*Src)) {
+ c = *Src++;
+ if ((c == '?') || (c == '*')) {
+ if (!MetaCharactersAllowed) {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ goto ErrorExit;
+ }
+ else {
+ OutputFlags |= CANONICALIZE_META_CHARS_FOUND;
+ }
+ }
+#ifdef DBCS
+// MSKK Apr.18.1993 V-AkihiS
+ if (Ow2NlsIsDBCSLeadByte(c, SesGrp->DosCP)) {
+ *Dest++ = c;
+ if (*Src) {
+ //
+ // Check Trailing byte is valid or not.
+ //
+ if ((UCHAR)*Src < 0x40 || (UCHAR)*Src > 0xFC || (UCHAR)*Src == 0x7F) {
+ RetCode = ERROR_INVALID_NAME;
+ goto ErrorExit;
+ } else {
+ *Dest++ = *Src++;
+ }
+ } else {
+ RetCode = ERROR_INVALID_NAME;
+ goto ErrorExit;
+ }
+ }
+ else {
+ if (ValidateChars && ((UCHAR)c < (UCHAR)' ' ||
+ strchr( InvalidCharacters, c )
+ )
+ ) {
+ RetCode = ERROR_INVALID_NAME;
+ goto ErrorExit;
+ }
+
+ if ((!PreserveCase) && (c >= 'a' && c <= 'z')) {
+ c = (CHAR) (c - 'a' + 'A');
+ }
+ *Dest++ = c;
+ }
+#else
+ if (ValidateChars && ((UCHAR)c < (UCHAR)' ' ||
+ strchr( Od2InvalidCharacters, c )
+ )
+ ) {
+ RetCode = ERROR_INVALID_NAME;
+ goto ErrorExit;
+ }
+
+ if ((!PreserveCase) && (c >= 'a' && c <= 'z')) {
+ c = (CHAR) (c - 'a' + 'A');
+ }
+ *Dest++ = c;
+#endif
+ }
+ }
+
+ //
+ // truncate trailing dots and blanks here. if there is a metacharacter
+ // in the name, we must leave one trailing dot, if there is one.
+ // DBCS correct because '.' and ' ' aren't valid trailing bytes
+ //
+
+ if (RemoveBlanksAndDots) {
+ if ((Dest > LastComponent) && ((*(Dest-1) == '.') || (*(Dest-1) == ' '))) {
+ do {
+ Dest--;
+ } while ((Dest > LastComponent) && ((*(Dest-1) == '.') || (*(Dest-1) == ' ')));
+ if (OutputFlags & CANONICALIZE_META_CHARS_FOUND) {
+ if (*Dest == '.') {
+ Dest++;
+ }
+ }
+ }
+ if (Dest <= LastComponent) {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto ErrorExit; // go free buffer(s) and return error
+ }
+ }
+
+ // *Src == '\' or '/'
+ if (ISSLASH(*Src)) {
+ if (MapToRootName) {
+ *Dest++ = '/';
+ }
+ else {
+ *Dest++ = (CHAR)OBJ_NAME_PATH_SEPARATOR;
+ }
+ LastComponent = Dest;
+
+ while (ISSLASH(*Src)) {
+ Src++; // eat up extra '\'s
+ }
+ }
+ }
+
+ //
+ // null terminate
+ //
+
+ *Dest = '\0';
+ if (OutputType != FILE_TYPE_FILE &&
+ OutputType != FILE_TYPE_DEV &&
+ OutputType != FILE_TYPE_PSDEV
+ ) {
+ if (Dest == LastComponent || Dest <= BackUpLimit) {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto ErrorExit; // go free buffer(s) and return error
+ }
+
+ if (OutputType == FILE_TYPE_NMPIPE && !TestForPipe(Os2Name)) {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto ErrorExit;
+ }
+ else if (OutputType == FILE_TYPE_MAILSLOT && !TestForMailslot(Os2Name)) {
+ RetCode = ERROR_FILE_NOT_FOUND;
+ goto ErrorExit;
+ }
+ }
+
+ //
+ // Enforce 260 max path length. remember that length does not include
+ // the terminating null. Remember the 260 limit includes the null byte.
+ //
+
+ ASSERT (Os2Name != NULL);
+ if (strlen(Os2Name) > CCHMAXPATH - 1) {
+ RetCode = ERROR_FILENAME_EXCED_RANGE;
+ goto ErrorExit;
+ }
+
+ //
+ // do some file-specific stuff.
+ //
+
+ if (OutputType == FILE_TYPE_FILE) {
+
+ //
+ // detect root directory
+ // test for "d:". if so, map to "d:\"
+ //
+
+ if (NameBuffer[FIRST_SLASH+FILE_PREFIX_LENGTH] == '\0') { // resulting path is d:
+ NameBuffer[FIRST_SLASH+FILE_PREFIX_LENGTH] = (CHAR)OBJ_NAME_PATH_SEPARATOR;
+ NameBuffer[ROOTDIRLENGTH+FILE_PREFIX_LENGTH] = '\0';
+ Dest++;
+ OutputFlags |= CANONICALIZE_IS_ROOT_DIRECTORY;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("path is root dir\n");
+ }
+#endif
+ }
+ else if (NameBuffer[FIRST_SLASH+FILE_PREFIX_LENGTH] == (CHAR)OBJ_NAME_PATH_SEPARATOR && NameBuffer[ROOTDIRLENGTH+FILE_PREFIX_LENGTH] == '\0') {
+ OutputFlags |= CANONICALIZE_IS_ROOT_DIRECTORY;
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("path is root dir\n");
+ }
+#endif
+ }
+
+ //
+ // test for "d:\pipe" or "d:\pipe\..." this is illegal unless
+ // CANONICALIZE_FILE_OR_DEV is specified. only DosMove sets this flag.
+ //
+
+ else if ((!(_strnicmp(NameBuffer+DRIVE_LETTER_SIZE+FILE_PREFIX_LENGTH,"PIPE",4))) &&
+ (((*(NameBuffer+DRIVE_LETTER_SIZE+FILE_PREFIX_LENGTH+PIPE_DIR_SIZE-2)) == 0) ||
+ ((*(NameBuffer+DRIVE_LETTER_SIZE+FILE_PREFIX_LENGTH+PIPE_DIR_SIZE-2)) == (CHAR)OBJ_NAME_PATH_SEPARATOR))) {
+ if (ExpectedType != CANONICALIZE_FILE_OR_DEV) {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ goto ErrorExit; // go free buffer(s) and return error
+ }
+ }
+
+ //
+ // optimize to use open handle to current directory if 1) the user doesn't
+ // need the full path (i.e. not for current directory operations) 2) we
+ // have the current directory (the user didn't specify a full path), and
+ // 3) current directory isn't root.
+ //
+
+ if ((ARGUMENT_PRESENT( DirectoryHandle )) &&
+ (CurrentDirectoryHandle != NULL) &&
+ (!_strnicmp(NameBuffer+DRIVE_LETTER_SIZE+FILE_PREFIX_LENGTH,
+ CurrentDirectoryString->Buffer,
+ CurrentDirectoryString->Length)) &&
+ (NameBuffer[DRIVE_LETTER_SIZE+FILE_PREFIX_LENGTH+
+ CurrentDirectoryString->Length] == '\\')
+ ) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Optimized relative path\n");
+ }
+#endif
+ *DirectoryHandle = CurrentDirectoryHandle;
+
+ //
+ // we have to return a pointer to the relative path. we can
+ // either allocate a second buffer and copy the name from
+ // the current directory on, or ripple copy the relative path
+ // over the full path. since the ripple copy is less work, we
+ // do it.
+ //
+ // if canonical path is "\os2ss\drives\a:\dir1\dir2" and current
+ // directory is "\os2ss\drives\a:\dir1", we want to copy "dir2"
+ // to the beginning of the buffer.
+ //
+
+ Src = NameBuffer+CurrentDirectoryString->Length+1+DRIVE_LETTER_SIZE+FILE_PREFIX_LENGTH;
+ Dest = NameBuffer;
+ while (*Dest++ = *Src++)
+ ;
+ Dest--;
+ }
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("got to here. name is %s\n",NameBuffer);
+ if (DirectoryHandle != NULL)
+ DbgPrint(" handle is %ld\n",*DirectoryHandle);
+ }
+#endif
+
+ CanonicalString->MaximumLength = (USHORT) NameBufferLength;
+ CanonicalString->Length = (USHORT) (Dest - NameBuffer);
+ CanonicalString->Buffer = NameBuffer;
+
+#if 0
+#ifndef DBCS // MSKK move max path length check
+ //
+ // Enforce 260 max path length. remember that length does not include
+ // the terminating null. Remember the 260 limit includes the null byte.
+ //
+
+ ASSERT (Os2Name != NULL);
+ if (CanonicalString->Length - (Os2Name - NameBuffer) >=
+ CCHMAXPATH) {
+ RetCode = ERROR_PATH_NOT_FOUND;
+ }
+#endif
+#endif // 0
+
+ErrorExit:
+ if (CurrentDirectoryString != NULL) {
+ RtlFreeHeap( Od2Heap, 0, CurrentDirectoryString );
+ }
+
+ if (RetCode != NO_ERROR) {
+ if (NameBuffer != NULL) {
+ RtlFreeHeap( Od2Heap, 0, NameBuffer );
+ }
+ }
+ else {
+ if (ARGUMENT_PRESENT( ParseFlags )) {
+ *ParseFlags = OutputFlags;
+ }
+
+ if (ExpectedPrefix == NULL && ARGUMENT_PRESENT( FileType )) {
+ *FileType = OutputType;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint( "Od2Canonicalize: returning path %s\n", NameBuffer);
+ }
+#endif
+ }
+
+ return( RetCode );
+}
+
+
+BOOLEAN
+Od2IsAbsolutePath(
+ IN PSZ Path
+ )
+{
+ CHAR c;
+
+ if (Path[ 0 ] && Path[ 1 ] != ':') {
+ while (c = *Path++) {
+ if (c == '/' || c == (CHAR)OBJ_NAME_PATH_SEPARATOR) {
+ return( TRUE );
+ }
+#ifdef DBCS
+// MSKK Apr.11.1993 V-AkihiS
+ if (Ow2NlsIsDBCSLeadByte(c, SesGrp->DosCP)) {
+ if (*Path) Path++;
+ }
+#endif
+ }
+
+ return( FALSE );
+ }
+ else {
+ return( TRUE );
+ }
+}
diff --git a/private/os2/client/dllnb.c b/private/os2/client/dllnb.c
new file mode 100644
index 000000000..a1c6c77b1
--- /dev/null
+++ b/private/os2/client/dllnb.c
@@ -0,0 +1,1827 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ netbios.c
+
+Abstract:
+
+ This is the component of netbios that runs in the user process
+ passing requests to \Device\Netbios.
+
+Author:
+
+ Colin Watson (ColinW) 15-Mar-91
+
+Revision History:
+
+ May 6th, 93 -- This Win32 netbios component file was copied and
+ adapted for the Os/2 subsystem. This was brought about by
+ the need to support subsystem-wide netbios name tables and
+ other netbios information. Opening a single instance of
+ \Device\Netbios, and passing handles around using duplication
+ allows for this.
+ The netbios debug code was integrated into this source file.
+
+--*/
+
+/*
+Notes:
+
+ +-----------+ +------------+ +------------+
+ | | | | | |
+ | User | | User | | Worker |
+ | Thread 1 | | Thread 2 | | thread in |
+ | | | | | a Post Rtn.|
+ +-----+-----+ +-----+------+ +------+-----+
+ |Netbios(pncb);|Netbios(pncb); |
+ v v |
+ +-----+--------------+-----------------+------+
+ | -----> Worker | NETAPI.DLL
+ | WorkQueue thread |
+ | -----> |
+ +--------------------+------------------------+
+ |
+ +---------+---------+
+ | |
+ | \Device\Netbios |
+ | |
+ +-------------------+
+
+The netbios Worker thread is created automatically by the Netbios call
+when it determines that the user threads are calling Netbios() with
+calls that use a callback routine (called a Post routine in the NetBIOS
+specification).
+
+When a worker thread has been created, all requests will be sent via
+the WorkQueue to the worker thread for submission to \Device\Netbios.
+This ensures that send requests go on the wire in the same
+order as the send ncb's are presented. Because the IO system cancels all
+a threads requests when it terminates, the use of the worker thread allows
+such a request inside \Device\Netbios to complete normally.
+
+All Post routines are executed by the Worker thread. This allows any Win32
+synchronization mechanisms to be used between the Post routine and the
+applications normal code.
+
+The Worker thread terminates when the process exits or when it gets
+an exception such as an access violation.
+
+In addition. If the worker thread gets an addname it will create an
+extra thread which will process the addname and then die. This solves
+the problem that the netbios driver will block the users thread during an
+addname (by calling NtCreateFile) even if the caller specified ASYNCH. The
+same code is also used for ASTAT which also creates handles and can take a
+long time now that we support remote adapter status.
+
+*/
+
+
+#include "netb.h"
+#if DBG
+#include <stdarg.h>
+#include <stdio.h>
+#endif
+
+
+static BOOL Initialized; // initialization flag
+static CRITICAL_SECTION Crit; // protects WorkQueue & initialization.
+static LIST_ENTRY WorkQueue; // queue to worker thread.
+static HANDLE Event; // doorbell used when WorkQueue added to.
+static HANDLE WorkerHandle; // Return value when thread created.
+static HANDLE NB; // This process's handle to \Device\Netbios.
+static HANDLE ReservedEvent; // Used for synchronous calls
+static LONG EventUse; // Prevents simultaneous use of ReservedEvent
+static HANDLE AddNameEvent; // Doorbell used when an AddName worker thread
+ // exits.
+static volatile LONG AddNameThreadCount;
+
+#if DBG
+ULONG NbDllDebug = 0L;
+#define NB_DLL_DEBUG_NCB 0x00000001 // print all NCB's submitted
+#define NB_DLL_DEBUG_NCB_BUFF 0x00000002 // print buffers for NCB's submitted
+
+static BOOL UseConsole = TRUE;
+static BOOL UseLogFile = FALSE;
+static HANDLE LogFile = INVALID_HANDLE_VALUE;
+#define LOGNAME (LPTSTR) TEXT("netbios.log")
+
+static LONG NbMaxDump = 128;
+
+// Macro used in DisplayNcb
+#define DISPLAY_COMMAND( cmd ) \
+ case cmd: NbPrintf(( #cmd )); break;
+
+#endif
+
+
+VOID
+SpinUpAddnameThread(
+ IN PNCBI pncb
+ );
+
+VOID
+AddNameThreadExit(
+ VOID
+ );
+
+DWORD
+SendAddNcbToDriver(
+ IN PVOID Context
+ );
+
+#if DBG
+
+VOID
+FormattedDump(
+ PCHAR far_p,
+ LONG len
+ );
+
+VOID
+HexDumpLine(
+ PCHAR pch,
+ ULONG len,
+ PCHAR s,
+ PCHAR t
+ );
+
+#endif
+
+
+#if DBG
+
+VOID
+DisplayNcb(
+ IN PNCBI pncbi
+ )
+/*++
+
+Routine Description:
+
+ This routine displays on the standard output stream the contents
+ of the Ncb.
+
+Arguments:
+
+ IN PNCBI - Supplies the NCB to be displayed.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ if ( (NbDllDebug & NB_DLL_DEBUG_NCB) == 0 ) {
+ return;
+ }
+
+ NbPrintf(( "PNCB %#010lx\n", pncbi));
+
+ NbPrintf(( "ncb_command %#04x ", pncbi->ncb_command));
+ switch ( pncbi->ncb_command & ~ASYNCH ) {
+ DISPLAY_COMMAND( NCBCALL );
+ DISPLAY_COMMAND( NCBLISTEN );
+ DISPLAY_COMMAND( NCBHANGUP );
+ DISPLAY_COMMAND( NCBSEND );
+ DISPLAY_COMMAND( NCBRECV );
+ DISPLAY_COMMAND( NCBRECVANY );
+ DISPLAY_COMMAND( NCBCHAINSEND );
+ DISPLAY_COMMAND( NCBDGSEND );
+ DISPLAY_COMMAND( NCBDGRECV );
+ DISPLAY_COMMAND( NCBDGSENDBC );
+ DISPLAY_COMMAND( NCBDGRECVBC );
+ DISPLAY_COMMAND( NCBADDNAME );
+ DISPLAY_COMMAND( NCBDELNAME );
+ DISPLAY_COMMAND( NCBRESET );
+ DISPLAY_COMMAND( NCBASTAT );
+ DISPLAY_COMMAND( NCBSSTAT );
+ DISPLAY_COMMAND( NCBCANCEL );
+ DISPLAY_COMMAND( NCBADDGRNAME );
+ DISPLAY_COMMAND( NCBENUM );
+ DISPLAY_COMMAND( NCBUNLINK );
+ DISPLAY_COMMAND( NCBSENDNA );
+ DISPLAY_COMMAND( NCBCHAINSENDNA );
+ DISPLAY_COMMAND( NCBLANSTALERT );
+ DISPLAY_COMMAND( NCBFINDNAME );
+
+ // Extensions
+ DISPLAY_COMMAND( NCALLNIU );
+ DISPLAY_COMMAND( NCBQUICKADDNAME );
+ DISPLAY_COMMAND( NCBQUICKADDGRNAME );
+ DISPLAY_COMMAND( NCBACTION );
+
+ default: NbPrintf(( " Unknown type")); break;
+ }
+ if ( pncbi->ncb_command & ASYNCH ) {
+ NbPrintf(( " | ASYNCH"));
+ }
+
+
+ NbPrintf(( "\nncb_retcode %#04x\n", pncbi->ncb_retcode));
+ NbPrintf(( "ncb_lsn %#04x\n", pncbi->ncb_lsn));
+ NbPrintf(( "ncb_num %#04x\n", pncbi->ncb_num));
+
+ NbPrintf(( "ncb_buffer %#010lx\n",pncbi->ncb_buffer));
+ NbPrintf(( "ncb_length %#06x\n", pncbi->ncb_length));
+
+ NbPrintf(( "\nncb_callname and ncb->name\n"));
+ FormattedDump( pncbi->cu.ncb_callname, NCBNAMSZ );
+ FormattedDump( pncbi->ncb_name, NCBNAMSZ );
+
+ if (((pncbi->ncb_command & ~ASYNCH) == NCBCHAINSEND) ||
+ ((pncbi->ncb_command & ~ASYNCH) == NCBCHAINSENDNA)) {
+ NbPrintf(( "ncb_length2 %#06x\n", pncbi->cu.ncb_chain.ncb_length2));
+ NbPrintf(( "ncb_buffer2 %#010lx\n",pncbi->cu.ncb_chain.ncb_buffer2));
+ }
+
+ NbPrintf(( "ncb_rto %#04x\n", pncbi->ncb_rto));
+ NbPrintf(( "ncb_sto %#04x\n", pncbi->ncb_sto));
+ NbPrintf(( "ncb_post %lx\n", pncbi->ncb_post));
+ NbPrintf(( "ncb_lana_num %#04x\n", pncbi->ncb_lana_num));
+ NbPrintf(( "ncb_cmd_cplt %#04x\n", pncbi->ncb_cmd_cplt));
+
+ NbPrintf(( "ncb_reserve\n"));
+ FormattedDump( ((PNCB)pncbi)->ncb_reserve, 14 );
+
+ NbPrintf(( "ncb_next\n"));
+ FormattedDump( (PCHAR)&pncbi->u.ncb_next, sizeof( LIST_ENTRY) );
+ NbPrintf(( "ncb_iosb\n"));
+ FormattedDump( (PCHAR)&pncbi->u.ncb_iosb, sizeof( IO_STATUS_BLOCK ) );
+ NbPrintf(( "ncb_event %#04x\n", pncbi->ncb_event));
+
+ if ( (NbDllDebug & NB_DLL_DEBUG_NCB_BUFF) == 0 ) {
+ NbPrintf(( "\n\n" ));
+ return;
+ }
+
+ switch ( pncbi->ncb_command & ~ASYNCH ) {
+ case NCBSEND:
+ case NCBCHAINSEND:
+ case NCBDGSEND:
+ case NCBSENDNA:
+ case NCBCHAINSENDNA:
+ if ( pncbi->ncb_retcode == NRC_PENDING ) {
+
+ //
+ // If pending then presumably we have not displayed the ncb
+ // before. After its been sent there isn't much point in displaying
+ // the buffer again.
+ //
+
+ NbPrintf(( "ncb_buffer contents:\n"));
+ FormattedDump( pncbi->ncb_buffer, pncbi->ncb_length );
+ }
+ break;
+
+ case NCBRECV:
+ case NCBRECVANY:
+ case NCBDGRECV:
+ case NCBDGSENDBC:
+ case NCBDGRECVBC:
+ case NCBENUM:
+ case NCBASTAT:
+ case NCBSSTAT:
+ case NCBFINDNAME:
+ if ( pncbi->ncb_retcode != NRC_PENDING ) {
+ // Buffer has been loaded with data
+ NbPrintf(( "ncb_buffer contents:\n"));
+ FormattedDump( pncbi->ncb_buffer, pncbi->ncb_length );
+ }
+ break;
+
+ case NCBCANCEL:
+ // Buffer has been loaded with the NCB to be cancelled
+ NbPrintf(( "ncb_buffer contents:\n"));
+ FormattedDump( pncbi->ncb_buffer, sizeof(NCB));
+ break;
+ }
+ NbPrintf(( "\n\n" ));
+}
+
+
+VOID
+NbPrint(
+ char *Format,
+ ...
+ )
+/*++
+
+Routine Description:
+
+ This routine is equivalent to printf with the output being directed to
+ stdout.
+
+Arguments:
+
+ IN char *Format - Supplies string to be output and describes following
+ (optional) parameters.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ va_list arglist;
+ char *OutputBuffer;
+ ULONG length;
+
+ if ( NbDllDebug == 0 ) {
+ return;
+ }
+
+ OutputBuffer = (char *) RtlAllocateHeap(
+ RtlProcessHeap(),
+ 0,
+ 1024);
+
+ if (OutputBuffer == NULL) {
+
+ //
+ // if not enough heap space -- skip printing
+ //
+
+ return;
+ }
+
+ va_start( arglist, Format );
+
+ vsprintf( OutputBuffer, Format, arglist );
+
+ va_end( arglist );
+
+ if ( UseConsole ) {
+ DbgPrint( "%s", OutputBuffer );
+ } else {
+ length = strlen( OutputBuffer );
+ if ( LogFile == INVALID_HANDLE_VALUE ) {
+ if ( UseLogFile ) {
+ LogFile = CreateFile( LOGNAME,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+ if ( LogFile == INVALID_HANDLE_VALUE ) {
+ // Could not access logfile so use stdout instead
+ UseLogFile = FALSE;
+ LogFile = GetStdHandle(STD_OUTPUT_HANDLE);
+ }
+ } else {
+ // Use the applications stdout file.
+ LogFile = GetStdHandle(STD_OUTPUT_HANDLE);
+ }
+ }
+
+ WriteFile( LogFile , (LPVOID )OutputBuffer, length, &length, NULL );
+ }
+
+ RtlFreeHeap(
+ RtlProcessHeap(),
+ 0,
+ OutputBuffer);
+
+} // NbPrint
+
+
+void
+FormattedDump(
+ PCHAR far_p,
+ LONG len
+ )
+/*++
+
+Routine Description:
+
+ This routine outputs a buffer in lines of text containing hex and
+ printable characters.
+
+Arguments:
+
+ IN far_p - Supplies buffer to be displayed.
+ IN len - Supplies the length of the buffer in bytes.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ ULONG l;
+ char s[80], t[80];
+
+ if ( len > NbMaxDump ) {
+ len = NbMaxDump;
+ }
+
+ while (len) {
+ l = len < 16 ? len : 16;
+
+ NbPrintf (("%lx ", far_p));
+ HexDumpLine (far_p, l, s, t);
+ NbPrintf (("%s%.*s%s\n", s, 1 + ((16 - l) * 3), "", t));
+
+ len -= l;
+ far_p += l;
+ }
+}
+
+
+VOID
+HexDumpLine(
+ PCHAR pch,
+ ULONG len,
+ PCHAR s,
+ PCHAR t
+ )
+/*++
+
+Routine Description:
+
+ This routine builds a line of text containing hex and printable characters.
+
+Arguments:
+
+ IN pch - Supplies buffer to be displayed.
+ IN len - Supplies the length of the buffer in bytes.
+ IN s - Supplies the start of the buffer to be loaded with the string
+ of hex characters.
+ IN t - Supplies the start of the buffer to be loaded with the string
+ of printable ascii characters.
+
+
+Return Value:
+
+ none.
+
+--*/
+{
+ static UCHAR rghex[] = "0123456789ABCDEF";
+
+ UCHAR c;
+ UCHAR *hex, *asc;
+
+
+ hex = s;
+ asc = t;
+
+ *(asc++) = '*';
+ while (len--) {
+ c = *(pch++);
+ *(hex++) = rghex [c >> 4] ;
+ *(hex++) = rghex [c & 0x0F];
+ *(hex++) = ' ';
+ *(asc++) = (c < ' ' || c > '~') ? (CHAR )'.' : c;
+ }
+ *(asc++) = '*';
+ *asc = 0;
+ *hex = 0;
+
+}
+
+#endif
+
+
+UCHAR
+Od2Netbios(
+ IN PNCB pncb,
+ IN HANDLE hDev,
+ OUT PBOOLEAN WillPost OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ This routine is the applications entry point into netapi.dll to support
+ netbios 3.0 conformant applications.
+
+Arguments:
+
+ IN PNCB pncb- Supplies the NCB to be processed. Contents of the NCB and
+ buffers pointed to by the NCB will be modified in conformance with
+ the netbios 3.0 specification.
+
+ IN HANDLE hDev - a handle to the netbios device driver. This parameter is
+ only used once -- during the first call to set the permanent handle.
+
+ OUT PBOOLEAN WillPost OPTIONAL -- On return, this will indicate if the post
+ routine is going to get called or not. Note that if the request is not
+ ASYNCH, this will always be FALSE.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+Notes:
+
+ The reserved field is used to hold the IO_STATUS_BLOCK.
+
+ Even if the application specifies ASYNCH, the thread may get blocked
+ for a period of time while we open transports, create worker threads
+ etc.
+
+--*/
+{
+ //
+ // pncbi saves doing lots of type casting. The internal form includes
+ // the use of the reserved fields.
+ //
+
+ PNCBI pncbi = (PNCBI) pncb;
+ NTSTATUS ntstatus;
+
+ //
+ // mark the default -- post routine won't be called
+ //
+
+ if (ARGUMENT_PRESENT(WillPost)) {
+ *WillPost = FALSE;
+ }
+
+ if ( ((ULONG)pncbi & 3) != 0) {
+ // NCB must be 32 bit aligned
+
+ pncbi->ncb_retcode = pncbi->ncb_cmd_cplt = NRC_BADDR;
+ return NRC_BADDR;
+ }
+
+ // Conform to Netbios 3.0 specification by flagging request in progress
+ pncbi->ncb_retcode = pncbi->ncb_cmd_cplt = NRC_PENDING;
+
+ DisplayNcb( pncbi );
+
+ if ( !Initialized ) {
+
+ EnterCriticalSection( &Crit );
+
+ //
+ // Check again to see if another thread got into the critical section
+ // and initialized the worker thread.
+ //
+
+ if ( !Initialized ) {
+#if 0 // taken out, handle is passed as param
+ IO_STATUS_BLOCK iosb;
+ OBJECT_ATTRIBUTES objattr;
+ UNICODE_STRING unicode;
+#endif
+
+ NbPrintf(( "The Netbios service is starting...\n" ));
+
+#if 0 // taken out, handle is passed as param
+ RtlInitUnicodeString( &unicode, NB_DEVICE_NAME);
+ InitializeObjectAttributes(
+ &objattr, // obj attr to initialize
+ &unicode, // string to use
+ OBJ_CASE_INSENSITIVE, // Attributes
+ NULL, // Root directory
+ NULL); // Security Descriptor
+
+ ntstatus = NtCreateFile(
+ &NB, // ptr to handle
+ GENERIC_READ // desired...
+ | GENERIC_WRITE, // ...access
+ &objattr, // name & attributes
+ &iosb, // I/O status block.
+ NULL, // alloc size.
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_DELETE // share...
+ | FILE_SHARE_READ
+ | FILE_SHARE_WRITE, // ...access
+ FILE_OPEN_IF, // create disposition
+ 0, // ...options
+ NULL, // EA buffer
+ 0L ); // Ea buffer len
+
+ if (! NT_SUCCESS(ntstatus)) {
+ NbPrintf(( "The Netbios service start failed: %X\n", ntstatus ));
+ pncbi->ncb_retcode = NRC_OPENERR;
+ pncbi->ncb_cmd_cplt = NRC_OPENERR;
+ NbPrintf(( "Netbios returning %lx\n", pncbi->ncb_cmd_cplt ));
+ LeaveCriticalSection( &Crit );
+ return pncbi->ncb_cmd_cplt;
+ }
+#else
+ NB = hDev;
+#endif
+
+ ntstatus = NtCreateEvent( &ReservedEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE );
+
+ if ( !NT_SUCCESS(ntstatus) ) {
+ NbPrintf(( "The Netbios service start failed: %X\n", ntstatus ));
+ pncbi->ncb_retcode = NRC_OPENERR;
+ pncbi->ncb_cmd_cplt = NRC_OPENERR;
+ NbPrintf(( "Netbios returning %lx\n", pncbi->ncb_cmd_cplt ));
+ LeaveCriticalSection( &Crit );
+ return pncbi->ncb_cmd_cplt;
+ }
+
+ EventUse = 1;
+
+ Initialized = TRUE;
+ }
+
+ LeaveCriticalSection( &Crit );
+
+ } else {
+
+ NbPrintf(( "The Netbios service is already started\n" ));
+
+ }
+
+ //
+ // Should we use this thread to make the request?
+ // Once we have a worker thread then requests must pass through it to
+ // maintain the ordering of requests.
+ //
+ // If the caller is using an ASYNCH request then we must use the worker
+ // thread because Win32 applications don't wait allertable ( user
+ // APC routines are only called when the thread is allertable).
+ //
+ // If the caller only uses ASYNCH=0 requests then the dll will wait
+ // allertable in the users thread while the operation completes. This
+ // allows the dll's post routines to fire.
+ //
+
+ if (( WorkerHandle != NULL ) ||
+ (( pncbi->ncb_command & ASYNCH) == ASYNCH) ) {
+
+ //
+ // Disallow simultaneous use of both event and callback routine.
+ // This will cut down the test cases by disallowing a weird feature.
+ //
+
+ if (((pncbi->ncb_command & ASYNCH) != 0) &&
+ (pncbi->ncb_event) &&
+ (pncbi->ncb_post )) {
+ pncbi->ncb_retcode = NRC_ILLCMD;
+ pncbi->ncb_cmd_cplt = NRC_ILLCMD;
+ NbPrintf(( "Netbios returning %lx\n", pncbi->ncb_cmd_cplt ));
+ return pncbi->ncb_cmd_cplt;
+ }
+
+ if ( WorkerHandle == NULL ) {
+
+ HANDLE Threadid;
+ NTSTATUS Status;
+ BOOL Flag;
+
+ // Make sure two threads don't simultaneously create worker thread
+
+ EnterCriticalSection( &Crit );
+
+ if ( WorkerHandle == NULL ) {
+
+ // Initialize shared datastructures
+
+ InitializeListHead( &WorkQueue );
+
+ Status = NtCreateEvent( &Event,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE );
+
+ if ( !NT_SUCCESS(Status) ) {
+ pncbi->ncb_retcode = NRC_SYSTEM;
+ pncbi->ncb_cmd_cplt = NRC_SYSTEM;
+ NbPrintf(( "Netbios returning %lx\n", pncbi->ncb_cmd_cplt ));
+ LeaveCriticalSection( &Crit );
+ return pncbi->ncb_cmd_cplt;
+ }
+
+ Status = NtCreateEvent( &AddNameEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ NotificationEvent,
+ FALSE );
+
+ if ( !NT_SUCCESS(Status) ) {
+ pncbi->ncb_retcode = NRC_SYSTEM;
+ pncbi->ncb_cmd_cplt = NRC_SYSTEM;
+ NbPrintf(( "Netbios returning %lx\n", pncbi->ncb_cmd_cplt ));
+ NtClose( Event );
+ LeaveCriticalSection( &Crit );
+ return pncbi->ncb_cmd_cplt;
+ }
+
+ // All initialization complete -- start worker thread.
+
+ WorkerHandle = CreateThread(
+ NULL, // Standard thread attributes
+ 0, // Use same size stack as users
+ // application
+ Worker,
+ // Routine to start in new thread
+ 0, // Parameter to thread
+ 0, // No special CreateFlags
+ (LPDWORD)&Threadid);
+
+ if ( WorkerHandle == NULL ) {
+ // Generate the best error we can...
+ pncbi->ncb_retcode = NRC_SYSTEM;
+ pncbi->ncb_cmd_cplt = NRC_SYSTEM;
+ NbPrintf(( "Netbios returning %lx\n", pncbi->ncb_cmd_cplt ));
+ LeaveCriticalSection( &Crit );
+ return pncbi->ncb_cmd_cplt;
+ }
+
+ Flag = SetThreadPriority(
+ WorkerHandle,
+ THREAD_PRIORITY_ABOVE_NORMAL );
+
+ ASSERT( Flag == TRUE );
+ if ( Flag != TRUE ) {
+ NbPrintf(( "Worker SetThreadPriority: %lx\n", GetLastError() ));
+ }
+ NbPrintf(( "Worker handle: %lx, threadid %lx\n", Worker, Threadid ));
+
+ AddNameThreadCount = 0;
+ }
+
+ LeaveCriticalSection( &Crit );
+
+ }
+
+ if ( (pncb->ncb_command & ASYNCH) == 0 ) {
+ NTSTATUS Status;
+ LONG EventOwned;
+
+ //
+ // Caller wants a synchronous call so ignore ncb_post and ncb_event.
+ //
+ // We need an event so that we can pause if STATUS_PENDING is returned.
+ //
+
+ EventOwned = InterlockedDecrement( &EventUse );
+
+ // If EventUse went from 1 to 0 then we obtained ReservedEvent
+ if ( EventOwned == 0) {
+ pncbi->ncb_event = ReservedEvent;
+ } else {
+ InterlockedIncrement( &EventUse );
+ Status = NtCreateEvent( &pncbi->ncb_event,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE );
+
+ if ( !NT_SUCCESS(Status) ) {
+ // Failed to create event
+ pncbi->ncb_retcode = NRC_SYSTEM;
+ pncbi->ncb_cmd_cplt = NRC_SYSTEM;
+ return NRC_SYSTEM;
+ }
+ }
+
+ QueueToWorker( pncbi );
+
+ //
+ // We must always wait to allow the Apc to fire
+ //
+
+ do {
+ ntstatus = NtWaitForSingleObject(
+ pncbi->ncb_event,
+ TRUE,
+ NULL );
+ } while ( ntstatus == STATUS_USER_APC );
+ if (! NT_SUCCESS(ntstatus)) {
+ NbPrintf(( "The Netbios NtWaitForSingleObject failed: %X\n", ntstatus ));
+ pncbi->ncb_retcode = NRC_SYSTEM;
+ pncbi->ncb_cmd_cplt = NRC_SYSTEM;
+ }
+
+ if ( EventOwned == 0) {
+ InterlockedIncrement( &EventUse );
+ } else {
+ NtClose( pncbi->ncb_event );
+ }
+
+ } else {
+
+ QueueToWorker( pncbi );
+ if (ARGUMENT_PRESENT(WillPost)) {
+ *WillPost = TRUE;
+ }
+
+ }
+
+ } else {
+
+ //
+ // Since we are not using the highly compliant callback interface
+ // we can submit the request using the callers thread. If the request
+ // is synchronous we do not even look at the callers event.
+ //
+
+ LONG EventOwned;
+ NTSTATUS Status;
+
+ ASSERT( (pncbi->ncb_command & ASYNCH) == 0 );
+ //
+ // Caller wants a synchronous call so ignore ncb_post and ncb_event.
+ //
+ // We need an event so that we can pause if STATUS_PENDING is returned.
+ //
+
+ EventOwned = InterlockedDecrement( &EventUse );
+
+ // If EventUse went from 1 to 0 then we obtained ReservedEvent
+ if ( EventOwned == 0) {
+ pncbi->ncb_event = ReservedEvent;
+ NtResetEvent( ReservedEvent, NULL );
+ } else {
+ InterlockedIncrement( &EventUse );
+ Status = NtCreateEvent( &pncbi->ncb_event,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE );
+
+ if ( !NT_SUCCESS(Status) ) {
+ // Failed to create event
+ pncbi->ncb_retcode = NRC_SYSTEM;
+ pncbi->ncb_cmd_cplt = NRC_SYSTEM;
+ return NRC_SYSTEM;
+ }
+ }
+
+ pncbi->ncb_post = NULL; // Since ASYNCH not set, post is undefined.
+
+ SendNcbToDriver( pncbi );
+
+ //
+ // We must always wait to allow the Apc to fire
+ //
+
+ do {
+ ntstatus = NtWaitForSingleObject(
+ pncbi->ncb_event,
+ TRUE,
+ NULL );
+ } while ( ntstatus == STATUS_USER_APC );
+
+ if (! NT_SUCCESS(ntstatus)) {
+ NbPrintf(( "The Netbios NtWaitForSingleObject failed: %X\n", ntstatus ));
+ pncbi->ncb_retcode = NRC_SYSTEM;
+ pncbi->ncb_cmd_cplt = NRC_SYSTEM;
+ }
+
+ if ( EventOwned == 0) {
+ InterlockedIncrement( &EventUse );
+ } else {
+ NtClose( pncbi->ncb_event );
+ }
+ }
+
+ NbPrintf(( "NCB being returned: %lx ncb_cmd_cplt: %lx\n", pncbi, pncbi->ncb_cmd_cplt ));
+ switch ( pncb->ncb_command & ~ASYNCH ) {
+ case NCBRECV:
+ case NCBRECVANY:
+ case NCBDGRECV:
+ case NCBDGSENDBC:
+ case NCBDGRECVBC:
+ case NCBENUM:
+ case NCBASTAT:
+ case NCBSSTAT:
+ case NCBCANCEL:
+ DisplayNcb( pncbi );
+ }
+
+ if ( pncbi->ncb_cmd_cplt == NRC_PENDING ) {
+ return NRC_GOODRET;
+ } else {
+ return pncbi->ncb_cmd_cplt;
+ }
+
+} // NetBios
+
+ VOID
+QueueToWorker(
+ IN PNCBI pncb
+ )
+/*++
+
+Routine Description:
+
+ This routine queues an ncb to the worker thread.
+
+Arguments:
+
+ IN PNCBI pncb - Supplies the NCB to be processed. Contents of the NCB and
+ buffers pointed to by the NCB will be modified in conformance with
+ the netbios 3.0 specification.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ if ( pncb->ncb_event != NULL ) {
+ NtResetEvent( pncb->ncb_event, NULL );
+ }
+
+ EnterCriticalSection( &Crit );
+
+ NbPrintf(( "Application thread critical\n"));
+
+ InsertTailList( &WorkQueue, &pncb->u.ncb_next );
+
+ LeaveCriticalSection( &Crit );
+
+ NbPrintf(( "Application thread not critical %X\n"));
+
+ // Make sure the worker is awake to perform the request
+ NtSetEvent(Event, NULL);
+}
+
+ DWORD
+Worker(
+ IN LPVOID Parameter
+ )
+/*++
+
+Routine Description:
+
+ This routine processes ASYNC requests made with the callback interface.
+ The reasons for using a seperate thread are:
+
+ 1) If a thread makes an async request and exits while the request
+ is outstanding then the request will be cancelled by the IO system.
+
+ 2) A seperate thread must be used so that the users POST routine
+ can use normal synchronization APIs to access shared data structures.
+ If the users thread is used then deadlock can and will happen.
+
+ The POST routine operates in the context of the worker thread. There are
+ no restrictions on what the POST routine can do. For example it can
+ submit another ASYNCH request if desired. It will add it to the queue
+ of work and set the event as normal.
+
+ The worker thread will die when the process terminates.
+
+Arguments:
+
+ IN PULONG Parameter - supplies an unused parameter.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ NbPrintf(( "Worker thread started\n" ));
+
+ while ( TRUE) {
+ NTSTATUS Status;
+
+ //
+ // Wait for a request to be placed onto the work queue.
+ //
+
+ // Must wait alertable so that the Apc (post) routine is called.
+
+ NbPrintf(( "Worker thread going to sleep\n" ));
+ Status = NtWaitForSingleObject( Event, TRUE, NULL );
+ NbPrintf(( "Worker thread awake, %X\n", Status));
+
+ EnterCriticalSection( &Crit );
+
+ NbPrintf(( "Worker thread critical\n"));
+
+ while (!IsListEmpty(&WorkQueue)) {
+
+ PLIST_ENTRY entry;
+ PNCBI pncb;
+
+ entry = RemoveHeadList(&WorkQueue);
+
+ LeaveCriticalSection( &Crit );
+
+ NbPrintf(( "Worker thread not critical\n"));
+
+ // Zero out reserved field again
+ entry->Flink = entry->Blink = 0;
+
+ pncb = CONTAINING_RECORD( entry, NCBI, u.ncb_next );
+
+ // Give ncb to the driver specifying the callers APC routine
+
+ NbPrintf(( "Worker thread processing ncb: %lx\n", pncb));
+
+ if ( (pncb->ncb_command & ~ASYNCH) == NCBRESET ) {
+
+ //
+ // We may have threads adding names. Wait until
+ // they are complete before submitting the reset.
+ // Addnames and resets are rare so this should rarely
+ // affect an application.
+ //
+
+ EnterCriticalSection( &Crit );
+ NtResetEvent( AddNameEvent, NULL );
+ while ( AddNameThreadCount != 0 ) {
+ LeaveCriticalSection( &Crit );
+ NtWaitForSingleObject(
+ AddNameEvent,
+ TRUE,
+ NULL );
+ EnterCriticalSection( &Crit );
+ NtResetEvent( AddNameEvent, NULL );
+ }
+ LeaveCriticalSection( &Crit );
+ }
+
+ //
+ // SendNcbToDriver must not be in a critical section since the
+ // request may block if its a non ASYNCH request.
+ //
+
+ if (( (pncb->ncb_command & ~ASYNCH) != NCBADDNAME ) &&
+ ( (pncb->ncb_command & ~ASYNCH) != NCBADDGRNAME ) &&
+ ( (pncb->ncb_command & ~ASYNCH) != NCBASTAT )) {
+ SendNcbToDriver( pncb );
+ } else {
+ SpinUpAddnameThread( pncb );
+ }
+
+ NbPrintf(( "Worker thread submitted ncb: %lx\n", pncb));
+
+ EnterCriticalSection( &Crit );
+
+ NbPrintf(( "Worker thread critical\n"));
+
+ }
+
+ LeaveCriticalSection( &Crit );
+ NbPrintf(( "Worker thread not critical\n"));
+
+ }
+
+ return 0;
+
+ UNREFERENCED_PARAMETER( Parameter );
+}
+
+
+
+ VOID
+SendNcbToDriver(
+ IN PNCBI pncb
+ )
+/*++
+
+Routine Description:
+
+ This routine determines the Device Ioctl code to be used to send the
+ ncb to \Device\Netbios and then does the call to send the request
+ to the driver.
+
+Arguments:
+
+ IN PNCBI pncb - supplies the NCB to be sent to the driver.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NTSTATUS ntstatus;
+
+ char * buffer;
+ unsigned short length;
+
+ // Use NULL for the buffer if only the NCB is to be passed.
+
+ switch ( pncb->ncb_command & ~ASYNCH ) {
+ case NCBSEND:
+ case NCBSENDNA:
+ case NCBRECV:
+ case NCBRECVANY:
+ case NCBDGSEND:
+ case NCBDGRECV:
+ case NCBDGSENDBC:
+ case NCBDGRECVBC:
+ case NCBASTAT:
+ case NCBFINDNAME:
+ case NCBSSTAT:
+ case NCBENUM:
+ case NCBACTION:
+ buffer = pncb->ncb_buffer;
+ length = pncb->ncb_length;
+ break;
+
+ case NCBCANCEL:
+ // The second buffer points to the NCB to be cancelled.
+ buffer = pncb->ncb_buffer;
+ length = sizeof(NCB);
+ NbPrintf(( "Attempting to cancel PNCB: %lx\n", buffer ));
+ DisplayNcb( (PNCBI)buffer );
+ break;
+
+ case NCBCHAINSEND:
+ case NCBCHAINSENDNA:
+ {
+ PUCHAR BigBuffer; // Points to the start of BigBuffer, not
+ // the start of user data.
+ PUCHAR FirstBuffer;
+
+ //
+ // There is nowhere in the NCB to save the address of BigBuffer.
+ // The address is needed to free BigBuffer when the transfer is
+ // complete. At the start of BigBuffer, 4 bytes are used to store
+ // the user supplied ncb_buffer value which is restored later.
+ //
+
+ BigBuffer = RtlAllocateHeap(
+ RtlProcessHeap(), 0,
+ sizeof(pncb->ncb_buffer) +
+ pncb->ncb_length +
+ pncb->cu.ncb_chain.ncb_length2);
+
+ if ( BigBuffer == NULL ) {
+
+ NbPrintf(( "The Netbios BigBuffer Allocation failed: %lx\n",
+ pncb->ncb_length + pncb->cu.ncb_chain.ncb_length2));
+ pncb->ncb_retcode = NRC_NORES;
+ pncb->ncb_cmd_cplt = NRC_NORES;
+ pncb->u.ncb_iosb.Status = 0L;
+ PostRoutineCaller( pncb, &pncb->u.ncb_iosb, 0);
+ return;
+ }
+
+ NbPrintf(( "BigBuffer Allocation: %lx\n", BigBuffer));
+
+ // Save users buffer address.
+ RtlMoveMemory(
+ BigBuffer,
+ &pncb->ncb_buffer,
+ sizeof(pncb->ncb_buffer));
+
+ FirstBuffer = pncb->ncb_buffer;
+
+ pncb->ncb_buffer = BigBuffer;
+
+ // Copy the user data.
+ try {
+
+ RtlMoveMemory(
+ sizeof(pncb->ncb_buffer) + BigBuffer,
+ &FirstBuffer[0],
+ pncb->ncb_length);
+
+ RtlMoveMemory(
+ sizeof(pncb->ncb_buffer) + BigBuffer + pncb->ncb_length,
+ &pncb->cu.ncb_chain.ncb_buffer2[0],
+ pncb->cu.ncb_chain.ncb_length2);
+
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ pncb->ncb_retcode = NRC_BUFLEN;
+ pncb->ncb_cmd_cplt = NRC_BUFLEN;
+ pncb->u.ncb_iosb.Status = 0L;
+ ChainSendPostRoutine( pncb, &pncb->u.ncb_iosb, 0);
+ return;
+ }
+
+ NbPrintf(( "Submit chain send pncb: %lx, event: %lx, post: %lx. \n",
+ pncb,
+ pncb->ncb_event,
+ pncb->ncb_post));
+
+ ntstatus = NtDeviceIoControlFile(
+ NB,
+ NULL,
+ ChainSendPostRoutine, // APC Routine
+ pncb, // APC Context
+ &pncb->u.ncb_iosb, // IO Status block
+ IOCTL_NB_NCB,
+ pncb, // InputBuffer
+ sizeof(NCB),
+ sizeof(pncb->ncb_buffer) + BigBuffer, // Outputbuffer
+ pncb->ncb_length + pncb->cu.ncb_chain.ncb_length2);
+
+ if ((ntstatus != STATUS_SUCCESS) &&
+ (ntstatus != STATUS_PENDING) &&
+ (ntstatus != STATUS_HANGUP_REQUIRED)) {
+ NbPrintf(( "The Netbios Chain Send failed: %X\n", ntstatus ));
+
+ if ( ntstatus == STATUS_ACCESS_VIOLATION ) {
+ pncb->ncb_retcode = NRC_BUFLEN;
+ } else {
+ pncb->ncb_retcode = NRC_SYSTEM;
+ }
+ ChainSendPostRoutine( pncb, &pncb->u.ncb_iosb, 0);
+ }
+
+ NbPrintf(( "PNCB: %lx completed, status:%lx, ncb_retcode: %#04x\n",
+ pncb,
+ ntstatus,
+ pncb->ncb_retcode ));
+
+ return;
+ }
+
+ default:
+ buffer = NULL;
+ length = 0;
+ break;
+ }
+
+ NbPrintf(( "Submit pncb: %lx, event: %lx, post: %lx. \n",
+ pncb,
+ pncb->ncb_event,
+ pncb->ncb_post));
+
+ ntstatus = NtDeviceIoControlFile(
+ NB,
+ NULL,
+ PostRoutineCaller, // APC Routine
+ pncb, // APC Context
+ &pncb->u.ncb_iosb, // IO Status block
+ IOCTL_NB_NCB,
+ pncb, // InputBuffer
+ sizeof(NCB),
+ buffer, // Outputbuffer
+ length );
+
+ if ((ntstatus != STATUS_SUCCESS) &&
+ (ntstatus != STATUS_PENDING) &&
+ (ntstatus != STATUS_HANGUP_REQUIRED)) {
+ NbPrintf(( "The Netbios NtDeviceIoControlFile failed: %X\n", ntstatus ));
+
+ if ( ntstatus == STATUS_ACCESS_VIOLATION ) {
+ pncb->ncb_retcode = NRC_BUFLEN;
+ } else {
+ pncb->ncb_retcode = NRC_SYSTEM;
+ }
+ PostRoutineCaller( pncb, &pncb->u.ncb_iosb, 0);
+ }
+
+ NbPrintf(( "PNCB: %lx completed, status:%lx, ncb_retcode: %#04x\n",
+ pncb,
+ ntstatus,
+ pncb->ncb_retcode ));
+
+ return;
+
+}
+
+ VOID
+SpinUpAddnameThread(
+ IN PNCBI pncb
+ )
+/*++
+
+Routine Description:
+
+ Spin up an another thread so that the worker thread does not block while
+ the blocking fsctl is being processed.
+
+Arguments:
+
+ IN PNCBI pncb - supplies the NCB to be sent to the driver.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ HANDLE Threadid;
+ HANDLE AddNameHandle;
+
+ NbPrintf(( "Worker thread create addname thread\n" ));
+
+ EnterCriticalSection( &Crit );
+ AddNameThreadCount++;
+ NtResetEvent( AddNameEvent, NULL );
+ LeaveCriticalSection( &Crit );
+
+ AddNameHandle = CreateThread(
+ NULL, // Standard thread attributes
+ 0, // Use same size stack as users
+ // application
+ SendAddNcbToDriver,
+ // Routine to start in new thread
+ pncb, // Parameter to thread
+ 0, // No special CreateFlags
+ (LPDWORD)&Threadid);
+
+ if ( AddNameHandle == NULL ) {
+ //
+ // Wait a couple of seconds just in case this is a burst
+ // of addnames and we have run out of resources creating
+ // threads. In a couple of seconds one of the other
+ // addname threads should complete.
+ //
+
+ Sleep(2000);
+
+ AddNameHandle = CreateThread(
+ NULL, // Standard thread attributes
+ 0, // Use same size stack as users
+ // application
+ SendAddNcbToDriver,
+ // Routine to start in new thread
+ pncb, // Parameter to thread
+ 0, // No special CreateFlags
+ (LPDWORD)&Threadid);
+
+ if ( AddNameHandle == NULL ) {
+
+ pncb->ncb_retcode = NRC_NORES;
+ NbPrintf(( "Create Addname Worker Thread failed\n" ));
+ pncb->u.ncb_iosb.Status = STATUS_SUCCESS;
+ PostRoutineCaller( pncb, &pncb->u.ncb_iosb, 0);
+ } else {
+ CloseHandle( AddNameHandle );
+ }
+ } else {
+ CloseHandle( AddNameHandle );
+ }
+}
+
+ VOID
+AddNameThreadExit(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Keep counts accurate so that any resets being processed by the main
+ worker thread block appropriately.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ EnterCriticalSection( &Crit );
+ AddNameThreadCount--;
+ if (AddNameThreadCount == 0) {
+ NtSetEvent(AddNameEvent, NULL);
+ }
+ LeaveCriticalSection( &Crit );
+}
+
+ DWORD
+SendAddNcbToDriver(
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to post an addname or adapter status ensuring
+ that the worker thread does not block.
+
+Arguments:
+
+ IN PVOID Context - supplies the NCB to be sent to the driver.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNCBI pncb = (PNCBI) Context;
+ void (CALLBACK *post)( struct _NCB * );
+ HANDLE event;
+ HANDLE LocalEvent;
+ UCHAR command;
+ NTSTATUS ntstatus;
+ char * buffer;
+ unsigned short length;
+
+ command = pncb->ncb_command;
+ post = pncb->ncb_post;
+ event = pncb->ncb_event;
+
+ ntstatus = NtCreateEvent( &LocalEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE );
+
+ if ( !NT_SUCCESS(ntstatus) ) {
+ pncb->ncb_retcode = NRC_NORES;
+ NbPrintf(( "Could not create event\n" ));
+ pncb->u.ncb_iosb.Status = STATUS_SUCCESS;
+ PostRoutineCaller( pncb, &pncb->u.ncb_iosb, 0);
+ AddNameThreadExit();
+ return 0;
+ }
+
+ //
+ // While the NCB is submitted the driver can modify the contents
+ // of the NCB. We will ensure that this thread waits until the addname
+ // completes before it exits.
+ //
+
+ pncb->ncb_command = pncb->ncb_command & ~ASYNCH;
+
+ if ( pncb->ncb_command == NCBASTAT ) {
+ buffer = pncb->ncb_buffer;
+ length = pncb->ncb_length;
+ } else {
+ ASSERT( (pncb->ncb_command == NCBADDNAME) ||
+ (pncb->ncb_command == NCBADDGRNAME) );
+ buffer = NULL;
+ length = 0;
+ }
+
+ NbPrintf(( "Addname/Astat Worker thread submitting %x\n", pncb));
+
+ ntstatus = NtDeviceIoControlFile(
+ NB,
+ LocalEvent,
+ NULL, // APC Routine
+ NULL, // APC Context
+ &pncb->u.ncb_iosb, // IO Status block
+ IOCTL_NB_NCB,
+ pncb, // InputBuffer
+ sizeof(NCB),
+ buffer, // Outputbuffer
+ length );
+
+ if ((ntstatus != STATUS_SUCCESS) &&
+ (ntstatus != STATUS_PENDING) &&
+ (ntstatus != STATUS_HANGUP_REQUIRED)) {
+ NbPrintf(( "The Netbios NtDeviceIoControlFile failed: %X\n", ntstatus ));
+
+ if ( ntstatus == STATUS_ACCESS_VIOLATION ) {
+ pncb->ncb_retcode = NRC_BUFLEN;
+ } else {
+ pncb->ncb_retcode = NRC_SYSTEM;
+ }
+ } else {
+ NtWaitForSingleObject(
+ LocalEvent,
+ TRUE,
+ NULL );
+ }
+ NbPrintf(( "Addname/Astat Worker thread returning %x, %x\n", pncb, pncb->ncb_cmd_cplt));
+
+ pncb->ncb_command = command;
+
+ // Set the flag that indicates that the NCB is now completed.
+ pncb->ncb_cmd_cplt = pncb->ncb_retcode;
+
+ // Allow application/worker thread to proceed.
+ if ( event != NULL ) {
+ NtSetEvent( event, NULL );
+ }
+
+ // If the user supplied a post routine then call it.
+ if (( post != NULL ) &&
+ ( (command & ASYNCH) != 0 )) {
+ (*(post))( (PNCB)pncb );
+ }
+
+ NtClose( LocalEvent );
+
+ AddNameThreadExit();
+
+ ExitThread(0);
+ return 0;
+}
+
+
+ VOID
+PostRoutineCaller(
+ PVOID Context,
+ PIO_STATUS_BLOCK Status,
+ ULONG Reserved
+ )
+/*++
+
+Routine Description:
+
+ This routine is supplied by SendNcbToDriver to the Io system when
+ a Post routine is to be called directly.
+
+Arguments:
+
+ IN PVOID Context - supplies the NCB post routine to be called.
+
+ IN PIO_STATUS_BLOCK Status.
+
+ IN ULONG Reserved.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ PNCBI pncbi = (PNCBI) Context;
+ void (CALLBACK *post)( struct _NCB * );
+ HANDLE event;
+ UCHAR command;
+
+ try {
+
+ NbPrintf(( "PostRoutineCaller PNCB: %lx, Status: %X\n", pncbi, Status->Status ));
+ DisplayNcb( pncbi );
+
+ if ( Status->Status == STATUS_HANGUP_REQUIRED ) {
+ HangupConnection( pncbi );
+ }
+
+ //
+ // Save the command, post routine and the handle to the event so that if the other thread is
+ // polling the cmd_cplt flag or the event awaiting completion and immediately trashes
+ // the NCB, we behave appropriately.
+ //
+ post = pncbi->ncb_post;
+ event = pncbi->ncb_event;
+ command = pncbi->ncb_command;
+
+ // Set the flag that indicates that the NCB is now completed.
+ pncbi->ncb_cmd_cplt = pncbi->ncb_retcode;
+
+ // Allow application/worker thread to proceed.
+ if ( event != NULL ) {
+ NtSetEvent( event, NULL );
+ }
+
+ // If the user supplied a post routine then call it.
+ if (( post != NULL ) &&
+ ( (command & ASYNCH) != 0 )) {
+ (*(post))( (PNCB)pncbi );
+ }
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ NbPrintf(( "Netbios: Access Violation post processing NCB %lx\n", pncbi ));
+ NbPrintf(( "Netbios: Probable application error\n" ));
+ }
+
+ UNREFERENCED_PARAMETER( Reserved );
+}
+
+ VOID
+ChainSendPostRoutine(
+ PVOID Context,
+ PIO_STATUS_BLOCK Status,
+ ULONG Reserved
+ )
+/*++
+
+Routine Description:
+
+ This routine is supplied by SendNcbToDriver to the Io system when
+ a chain send ncb is being processed. When the send is complete,
+ this routine deletes the BigBuffer used to hold the two parts of
+ the chain send. It then calls a post routine if the user supplied one.
+
+Arguments:
+
+ IN PVOID Context - supplies the NCB post routine to be called.
+
+ IN PIO_STATUS_BLOCK Status.
+
+ IN ULONG Reserved.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ PNCBI pncbi = (PNCBI) Context;
+ PUCHAR BigBuffer;
+ void (CALLBACK *post)( struct _NCB * );
+ HANDLE event;
+ UCHAR command;
+
+ BigBuffer = pncbi->ncb_buffer;
+
+ try {
+
+ // Restore the users NCB contents.
+ RtlMoveMemory(
+ &pncbi->ncb_buffer,
+ BigBuffer,
+ sizeof(pncbi->ncb_buffer));
+
+ NbPrintf(( "ChainSendPostRoutine PNCB: %lx, Status: %X\n", pncbi, Status->Status ));
+ DisplayNcb( pncbi );
+
+ NbPrintf(( "BigBuffer Free: %lx\n", BigBuffer));
+ RtlFreeHeap( RtlProcessHeap(), 0, BigBuffer);
+
+ if ( Status->Status == STATUS_HANGUP_REQUIRED ) {
+ HangupConnection( pncbi );
+ }
+
+ //
+ // Save the command, post routine and the handle to the event so that if the other thread is
+ // polling the cmd_cplt flag or the event awaiting completion and immediately trashes
+ // the NCB, we behave appropriately.
+ //
+ post = pncbi->ncb_post;
+ event = pncbi->ncb_event;
+ command = pncbi->ncb_command;
+
+ // Set the flag that indicates that the NCB is now completed.
+ pncbi->ncb_cmd_cplt = pncbi->ncb_retcode;
+
+ // Allow application/worker thread to proceed.
+ if ( event != NULL ) {
+ NtSetEvent(event, NULL);
+ }
+
+ // If the user supplied a post routine then call it.
+ if (( post != NULL ) &&
+ ( (command & ASYNCH) != 0 )) {
+ (*(post))( (PNCB)pncbi );
+ }
+
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ NbPrintf(( "Netbios: Access Violation post processing NCB %lx\n", pncbi ));
+ NbPrintf(( "Netbios: Probable application error\n" ));
+ }
+
+ UNREFERENCED_PARAMETER( Reserved );
+}
+
+ VOID
+HangupConnection(
+ PNCBI pUserNcb
+ )
+/*++
+
+Routine Description:
+
+ This routine generates a hangup for the connection. This allows orderly
+ cleanup of the connection block in the driver.
+
+ The return value from the hangup is not used. If the hangup overlaps with
+ a reset or a hangup then the hangup will have no effect.
+
+ The user application is unaware that this operation is being performed.
+
+Arguments:
+
+ IN PNCBI pUserNcb - Identifies the connection to be hung up.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ NCBI ncbi;
+ NTSTATUS Status;
+
+ RtlZeroMemory( &ncbi, sizeof (NCB) );
+ ncbi.ncb_command = NCBHANGUP;
+ ncbi.ncb_lsn = pUserNcb->ncb_lsn;
+ ncbi.ncb_lana_num = pUserNcb->ncb_lana_num;
+ ncbi.ncb_retcode = ncbi.ncb_cmd_cplt = NRC_PENDING;
+
+ Status = NtCreateEvent( &ncbi.ncb_event,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE );
+
+ if ( !NT_SUCCESS(Status) ) {
+ //
+ // Failed to create event. Cleanup of the Cb will have to wait until
+ // the user decides to do another request or exits.
+ //
+ NbPrintf(( "Hangup Session PNCBI: %lx failed to create event!\n" ));
+ return;
+ }
+
+ NbPrintf(( "Hangup Session PNCBI: %lx\n", pUserNcb ));
+
+ Status = NtDeviceIoControlFile(
+ NB,
+ ncbi.ncb_event,
+ NULL, // APC Routine
+ NULL, // APC Context
+ &ncbi.u.ncb_iosb, // IO Status block
+ IOCTL_NB_NCB,
+ &ncbi, // InputBuffer
+ sizeof(NCB),
+ NULL, // Outputbuffer
+ 0 );
+
+ //
+ // We must always wait to allow the Apc to fire
+ //
+
+ do {
+ Status = NtWaitForSingleObject(
+ ncbi.ncb_event,
+ TRUE,
+ NULL );
+ } while ( Status == STATUS_USER_APC );
+ if (! NT_SUCCESS(Status)) {
+ NbPrintf(( "The Netbios NtWaitForSingleObject failed: %X\n", Status ));
+ }
+
+ NtClose( ncbi.ncb_event );
+
+ NbPrintf(( "Hangup Session complete PNCBI: %lx\n", pUserNcb ));
+}
+
+
+VOID
+Od2NetbiosInitialize(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine is called each time a client starts up.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ extern RTL_CRITICAL_SECTION Od2NbSyncCrit;
+ extern BOOLEAN Od2Netbios2Initialized;
+
+ Initialized = FALSE;
+ Od2Netbios2Initialized = FALSE;
+ WorkerHandle = NULL;
+ InitializeCriticalSection( &Crit );
+ RtlInitializeCriticalSection(&Od2NbSyncCrit);
+}
+
+
+VOID
+Od2NetbiosDelete(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine is called each time a client Exits. It resets all lana
+ numbers that could have been used by this process. This will cause
+ all Irp's in the system to be completed because all the Connection
+ and Address handles will be closed tidily.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ extern RTL_CRITICAL_SECTION Od2NbSyncCrit;
+ extern BOOLEAN Od2Netbios2Initialized;
+ extern HANDLE Od2NbDev;
+ extern PVOID Od2Nb2Heap;
+
+ DeleteCriticalSection( &Crit );
+ RtlDeleteCriticalSection(&Od2NbSyncCrit);
+
+ if (Od2Netbios2Initialized) {
+
+ Initialized = FALSE;
+ NB = NULL;
+ Od2Netbios2Initialized = FALSE;
+ NtClose(Od2NbDev);
+ Od2NbDev = NULL;
+ RtlDestroyHeap(Od2Nb2Heap);
+ //
+ // We can call DosFreeMem() here, but it's better not to
+ // make a call to the server, which will clean up the
+ // shared mem anyway...
+ //
+ Od2Nb2Heap = NULL;
+ }
+}
+
diff --git a/private/os2/client/dllnet16.c b/private/os2/client/dllnet16.c
new file mode 100644
index 000000000..e6d972815
--- /dev/null
+++ b/private/os2/client/dllnet16.c
@@ -0,0 +1,5295 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ dllnet16.c
+
+Abstract:
+
+ This module implements 32 bit equivalents of OS/2 V1.21
+ LANMAN API Calls.
+ The APIs are called from 16->32 thunks (i386\doscalls.asm).
+
+Author:
+
+ Beni Lavi (BeniL) 15-Jan-1992
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_ERRORMSG
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_TASKING
+#define UNICODE 1
+#include <stdlib.h>
+#include "os2dll.h"
+#include "os2dll16.h"
+#define WIN32_ONLY
+#include "netrqust.h"
+#include "os2net16.h"
+#include <nb30.h>
+#include "nb30p.h"
+#define APINAMES
+#include <apinums.h> // API_W numbers
+// #include <rxp.h> // RxpTransactSmb
+
+#if DBG
+extern USHORT Os2DebugTID;
+#endif
+
+//
+// some constants
+//
+
+//
+// LanMan API related constants
+//
+
+#define LARGE_BUFFER_SIZE 16384 // used for copying large user buffer to internal buffer
+#define SMALL_BUFFER_SIZE 4096 // used for copying small user buffer to internal buffer
+#define PREFMAXLEN 8192 // parameter used to control internal LanMan buffer size
+
+//
+// Netbios API related constants
+//
+
+#define USERS_STACK_SIZE 4096 // stack size for user's Netbios 3.0 post routine
+#define NETBIOS2_SEMANTICS_SIGNATURE 0xF91E0873 // used as a special flag for Net16bios
+
+/*
+ We need a hard coded maximum parallel asynch ncbs limit for netbios 2
+ requests. The reason is a problem with the NT netbios driver -- Once
+ you fill up some maximal number (observed - 0xac) of ncbs, and run out
+ of memory, it is no longer possible to send even a cancel request for
+ those ncbs. On Os/2 it is still possible to cancel the pending requests.
+ Some programs try to test the driver's limits by issuing a lot of ncbs,
+ and when they get an error, they cancel them all. This will fail due to
+ the above reason. Limiting artificially to a smaller number will allow
+ the cancel ncbs to go through. Note that if more than one process fills
+ up the driver at the same time, this per-process limit will not do any good.
+ Let's hope this situation is unlikely.
+*/
+#define MAX_ASYNCH_NCBS 0x80L
+
+
+//
+// macro to probe string arguments passed to APIs
+//
+#define PROBE_STRING(s) ((VOID) ((s) == NULL ? 0 : strlen(s)))
+
+
+//
+// Extended NCB to be passed to Win32 Netbios API
+// It contains parameters that are needed by the ASYNCH processing
+//
+typedef struct _NCBX {
+ NCB n;
+ PNCB original_pncb; // Original Os/2 program NCB
+ ULONG original_ncb_post; // Os/2 program 16 bit far pointer post address
+ // or a semaphore handle to clear
+ HANDLE Net16BiosHasCompleted; // an event used to sync the post routine with Net16bios
+} NCBX, *PNCBX;
+
+
+//
+// some important service names for LanMan related APIs
+//
+static CHAR N_LanmanWorkstati[] = "LanmanWorkstati";
+static CHAR N_LanmanWorkstation[] = "LanmanWorkstation";
+static CHAR N_LanmanServer[] = "LanmanServer";
+static CHAR N_Workstation[] = "Workstation";
+static CHAR N_Server[] = "Server";
+
+
+//
+// netbios related global variables
+//
+
+BOOLEAN Od2Netbios2Initialized = FALSE; // netbios 2 initialization flag
+RTL_CRITICAL_SECTION Od2NbSyncCrit; // This CS is used to protect several data structures
+ // It's initialized/cleanedup from dllnb.c
+
+//
+// Od2LanaEnum holds the permanent enumeration of lana numbers (received from server)
+// Od2LanaState is a per-lana flag that has the following value:
+// bit 0 -- 1 if the lana is open/0 if the lana is closed
+// bit 1 -- 1 if the lana has been opened by this process before/0 if not (and therefore may need a reset thru the server)
+//
+static LANA_ENUM Od2LanaEnum;
+static UCHAR Od2LanaState[MAX_LANA];
+HANDLE Od2NbDev; // handle to NT netbios driver
+LONG Od2MaxAsynchNcbs; // a counter for implementing max asynch ncbs limit
+PVOID Od2Nb2Heap; // special heap for netbios 2 requests
+
+//
+// a flag indicating if we've already attached the win32 netbios worker thread to our subsystem
+//
+static BOOLEAN Od2WorkerThreadIsAttached = FALSE;
+static SEL Od2UserStackSel, // selector for netbios post routine user's stack
+ Od2UserStackAlias; // code alias for Od2UserStackSel
+
+
+// imports
+
+APIRET
+DosCreateCSAlias(
+ IN SEL selDS,
+ OUT PSEL pselCS
+ );
+
+APIRET
+GetSystemDirectoryW(
+ LPWSTR lpBuffer,
+ ULONG uSize
+ );
+
+VOID
+Od2JumpTo16NetBiosPostDispatcher(
+ IN PVOID pUsersPostRoutine, // CS:IP format
+ IN PVOID UserStackFlat, // Flat pointer to user stack
+ IN USHORT UserStackSize, // User stack size
+ IN SEL UserStackSel, // Data selector to user stack
+ IN SEL UserStackAlias, // Code selector to user stack
+ IN PVOID pNcb, // 16 bit SEG:OFF ptr to NCB
+ IN UCHAR NcbRetCode // return code from NCB
+ );
+
+APIRET
+Od2AttachWinThreadToOs2(VOID);
+
+UCHAR
+Od2Netbios(
+ IN PNCB pncb,
+ IN HANDLE hDev,
+ OUT PBOOLEAN WillPost OPTIONAL
+ );
+
+//
+// the following 2 are imported from win32
+//
+
+LONG
+InterlockedIncrement(
+ PLONG lpAddend
+ );
+
+LONG
+InterlockedDecrement(
+ PLONG lpAddend
+ );
+
+
+//
+// the following is from net\inc\rxp.h
+//
+APIRET
+RxpTransactSmb(
+ IN LPTSTR UncServerName,
+ IN LPTSTR TransportName,
+ IN LPVOID SendParmPtr,
+ IN DWORD SendParmSize,
+ IN LPVOID SendDataPtr OPTIONAL,
+ IN DWORD SendDataSize,
+ OUT LPVOID RetParmPtr OPTIONAL,
+ IN DWORD RetParmSize,
+ OUT LPVOID RetDataPtr OPTIONAL,
+ IN OUT LPDWORD RetDataSize,
+ IN BOOL NoPermissionRequired
+ );
+
+APIRET
+VrRemoteApi(
+ IN DWORD ApiNumber,
+ IN LPSTR ServerNamePointer,
+ IN LPSTR ParameterDescriptor,
+ IN LPSTR DataDescriptor,
+ IN LPSTR AuxDescriptor,
+ IN BOOL NullSessionFlag
+ );
+
+APIRET
+VrEncryptSES(
+ IN LPSTR ServerNamePointer,
+ IN LPSTR passwordPointer, // Input password (Not encripted)
+ IN LPSTR encryptedLmOwfPassword // output password (encripted)
+ );
+
+
+
+
+//*****************************************************************************
+//
+//Following are a number of Unicode conversion routines used in the LanMan APIs
+//
+//*****************************************************************************
+
+
+//
+// Get the length of a Unicode string (Adjusted)
+//
+ULONG
+UWstrlen(LPWSTR s)
+{
+ ULONG i = 0;
+
+ if (s == NULL) {
+ return(0);
+ }
+
+ while (*s++ != UNICODE_NULL) {
+ i++;
+ }
+ return(i);
+}
+
+
+ULONG
+UTstrlen(LPTSTR s)
+{
+ ULONG i = 0;
+
+ if (s == NULL) {
+ return(0);
+ }
+
+ while (*s++ != 0) {
+ i++;
+ }
+ return(i);
+}
+
+
+//
+// Copy a Unicode string to Ansi string
+//
+PCHAR
+UW2ANSIstrcpy(PCHAR d, LPWSTR s)
+{
+ ANSI_STRING str_a;
+ UNICODE_STRING str_u;
+
+ if (s == NULL) {
+ *d = '\0';
+ return(d);
+ }
+
+ RtlInitUnicodeString(&str_u, (PWSTR) s);
+
+ str_a.Buffer = d;
+ str_a.MaximumLength = 0xffff;
+
+ Od2UnicodeStringToMBString(&str_a, &str_u, FALSE);
+
+ d[str_a.Length] = '\0';
+
+ return(d);
+}
+
+
+PCHAR
+UT2ANSIstrcpy(PCHAR d, LPTSTR s)
+{
+ ANSI_STRING str_a;
+ UNICODE_STRING str_u;
+
+ if (s == NULL) {
+ *d = '\0';
+ return(d);
+ }
+
+ RtlInitUnicodeString(&str_u, (PWSTR) s);
+
+ str_a.Buffer = d;
+ str_a.MaximumLength = 0xffff;
+
+ Od2UnicodeStringToMBString(&str_a, &str_u, FALSE);
+
+ d[str_a.Length] = '\0';
+
+ return(d);
+}
+
+
+//
+// Copy a Unicode string to Ansi string with a limit on the # of copied chars
+//
+PCHAR
+UW2ANSIstrncpy(PCHAR d, LPWSTR s, ULONG Limit)
+{
+ ANSI_STRING str_a;
+ UNICODE_STRING str_u;
+
+ if (s == NULL) {
+ *d = '\0';
+ return(d);
+ }
+
+ RtlInitUnicodeString(&str_u, (PWSTR) s);
+
+ str_a.Buffer = d;
+ str_a.MaximumLength = (USHORT) Limit;
+
+ if (Od2UnicodeStringToMBString(&str_a, &str_u, FALSE) == NO_ERROR) {
+
+ if ((ULONG) str_a.Length < Limit) {
+ d[str_a.Length] = '\0';
+ }
+
+ } else {
+
+ if (Od2UnicodeStringToMBString(&str_a, &str_u, TRUE) == NO_ERROR) {
+
+ RtlMoveMemory(d, str_a.Buffer, Limit);
+ Od2FreeMBString(&str_a);
+
+ } else {
+ d[0] = '\0';
+ }
+ }
+
+ return(d);
+}
+
+
+PCHAR
+UT2ANSIstrncpy(PCHAR d, LPTSTR s, ULONG Limit)
+{
+ ANSI_STRING str_a;
+ UNICODE_STRING str_u;
+
+ if (s == NULL) {
+ *d = '\0';
+ return(d);
+ }
+
+ RtlInitUnicodeString(&str_u, (PWSTR) s);
+
+ str_a.Buffer = d;
+ str_a.MaximumLength = (USHORT) Limit;
+
+ if (Od2UnicodeStringToMBString(&str_a, &str_u, FALSE) == NO_ERROR) {
+
+ if ((ULONG) str_a.Length < Limit) {
+ d[str_a.Length] = '\0';
+ }
+
+ } else {
+
+ if (Od2UnicodeStringToMBString(&str_a, &str_u, TRUE) == NO_ERROR) {
+
+ RtlMoveMemory(d, str_a.Buffer, Limit);
+ Od2FreeMBString(&str_a);
+
+ } else {
+ d[0] = '\0';
+ }
+ }
+
+ return(d);
+}
+
+
+//
+// Copy an ANSI string to Unicode string
+//
+LPWSTR
+ANSI2UWstrcpy(LPWSTR d, PCHAR s)
+{
+ ANSI_STRING str_a;
+ UNICODE_STRING str_u;
+
+ if (s == NULL) {
+ *d = UNICODE_NULL;
+ return(d);
+ }
+
+ Od2InitMBString(&str_a, (PCSZ) s);
+
+ str_u.Buffer = (PWSTR) d;
+ str_u.MaximumLength = 0xffff;
+
+ Od2MBStringToUnicodeString(&str_u, &str_a, FALSE);
+
+ d[str_u.Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ return(d);
+}
+
+
+LPTSTR
+ANSI2UTstrcpy(LPTSTR d, PCHAR s)
+{
+ ANSI_STRING str_a;
+ UNICODE_STRING str_u;
+
+ if (s == NULL) {
+ *d = UNICODE_NULL;
+ return(d);
+ }
+
+ Od2InitMBString(&str_a, (PCSZ) s);
+
+ str_u.Buffer = (PWSTR) d;
+ str_u.MaximumLength = 0xffff;
+
+ Od2MBStringToUnicodeString(&str_u, &str_a, FALSE);
+
+ d[str_u.Length/sizeof(WCHAR)] = 0;
+
+ return(d);
+}
+
+
+//
+// Copy an Ansi string to a Unicode string with a limit on the # of copied chars
+//
+LPWSTR
+ANSI2UWstrncpy(LPWSTR d, PCHAR s, ULONG Limit)
+{
+ ANSI_STRING str_a;
+ UNICODE_STRING str_u;
+
+ if (s == NULL) {
+ *d = UNICODE_NULL;
+ return(d);
+ }
+
+ Od2InitMBString(&str_a, s);
+
+ str_u.Buffer = (PWSTR) d;
+ str_u.MaximumLength = (USHORT) (Limit * sizeof(WCHAR));
+
+ if (Od2MBStringToUnicodeString(&str_u, &str_a, FALSE) == NO_ERROR) {
+
+ if (str_u.Length < str_u.MaximumLength) {
+ d[str_u.Length/sizeof(WCHAR)] = UNICODE_NULL;
+ }
+
+ } else {
+
+ if (Od2MBStringToUnicodeString(&str_u, &str_a, TRUE) == NO_ERROR) {
+
+ RtlMoveMemory(d, str_u.Buffer, Limit * sizeof(WCHAR));
+ RtlFreeUnicodeString(&str_u);
+
+ } else {
+ d[0] = UNICODE_NULL;
+ }
+ }
+
+ return(d);
+}
+
+
+LPTSTR
+ANSI2UTstrncpy(LPTSTR d, PCHAR s, ULONG Limit)
+{
+ ANSI_STRING str_a;
+ UNICODE_STRING str_u;
+
+ if (s == NULL) {
+ *d = 0;
+ return(d);
+ }
+
+ Od2InitMBString(&str_a, s);
+
+ str_u.Buffer = (PWSTR) d;
+ str_u.MaximumLength = (USHORT) (Limit * sizeof(WCHAR));
+
+ if (Od2MBStringToUnicodeString(&str_u, &str_a, FALSE) == NO_ERROR) {
+
+ if (str_u.Length < str_u.MaximumLength) {
+ d[str_u.Length/sizeof(WCHAR)] = 0;
+ }
+
+ } else {
+
+ if (Od2MBStringToUnicodeString(&str_u, &str_a, TRUE) == NO_ERROR) {
+
+ RtlMoveMemory(d, str_u.Buffer, Limit * sizeof(WCHAR));
+ RtlFreeUnicodeString(&str_u);
+
+ } else {
+ d[0] = 0;
+ }
+ }
+
+ return(d);
+}
+
+
+LPTSTR
+ANSI2UTmemcpy(LPTSTR d, PCHAR s, ULONG count)
+{
+ ANSI_STRING str_a;
+ UNICODE_STRING str_u;
+
+ if (s == NULL) {
+ return(d);
+ }
+
+ str_a.Buffer = s;
+ str_a.MaximumLength = str_a.Length = (USHORT) count;
+
+ str_u.Buffer = (PWSTR) d;
+ str_u.MaximumLength = 0xffff;
+
+ Od2MBStringToUnicodeString(&str_u, &str_a, FALSE);
+
+ return(d);
+}
+
+
+
+//*****************************************************************************
+//
+//Following are the LanMan API
+//
+//*****************************************************************************
+
+// Most LanMan APIs are implemented with the following sequence:
+// copy input from user's buffer to internal buffer while convertine ansi to unicode
+// call win32 lanman api
+// copy output from lanman api internal buffer to user's buffer
+//
+// for Enum type APIs, a loop is used to get as much data as possible.
+
+
+
+// a small macro to copy a string from the internal net buffer to user's buffer
+#define CopyUW2ANSI(d, s) \
+ StringLen = UWstrlen(s) + 1; \
+ CurEndOfBuffer -= StringLen; \
+ d = (char *)FLATTOFARPTR(CurEndOfBuffer); \
+ UW2ANSIstrcpy(CurEndOfBuffer, s);
+
+
+APIRET
+Od2QueryNPHInfo(
+ HPIPE hpipe,
+ PULONG pCollectDataTime,
+ PULONG pMaxCollectionCount
+ )
+{
+ NTSTATUS Status;
+ APIRET RetCode;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PFILE_HANDLE hFileRecord;
+ FILE_PIPE_REMOTE_INFORMATION PipeRemoteInfoBuf;
+ LARGE_INTEGER LargeCollectDataTime;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "Od2QueryNPHInfo";
+ #endif
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+ RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE;
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("DosQueryPNHState: File Type != NMPIPE hpipe %d\n",
+ hpipe));
+ }
+#endif
+ return ERROR_BAD_PIPE;
+ }
+
+ Status = NtQueryInformationFile(hFileRecord->NtHandle,
+ &IoStatusBlock,
+ &PipeRemoteInfoBuf,
+ sizeof(FILE_PIPE_REMOTE_INFORMATION),
+ FilePipeRemoteInformation);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ KdPrint(("DosQueryPNHState: NtqueryInformation error: Status %ld\n",
+ Status));
+ }
+#endif
+ return ERROR_BAD_PIPE; // BUGBUG bogus
+ }
+
+ //
+ // Translate Information to OS/2 style values
+ //
+
+ LargeCollectDataTime = RtlExtendedLargeIntegerDivide(
+ PipeRemoteInfoBuf.CollectDataTime, 10000, NULL);
+ *pCollectDataTime = LargeCollectDataTime.LowPart;
+ *pMaxCollectionCount = PipeRemoteInfoBuf.MaximumCollectionCount;
+
+ return (NO_ERROR);
+}
+
+
+APIRET
+Net16GetDCName(
+ IN PCHAR pszServer,
+ IN PCHAR pszDomain,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer
+ )
+{
+ WCHAR Server[UNCLEN];
+ WCHAR Domain[DNLEN];
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+
+ try {
+ PROBE_STRING(pszServer);
+ PROBE_STRING(pszDomain);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ ANSI2UWstrncpy(Server, pszServer, UNCLEN);
+ ANSI2UWstrncpy(Domain, pszDomain, DNLEN);
+
+ rc = NetGetDCName(Server, Domain, &BufPtr);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ if (UWstrlen((LPWSTR) BufPtr) + 1 > cbBuffer) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ UW2ANSIstrcpy((PCHAR) pbBuffer, (LPWSTR) BufPtr);
+
+ NetApiBufferFree(BufPtr);
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+Net16HandleGetInfo(
+ IN HANDLE hHandle,
+ IN LONG sLevel,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ OUT PUSHORT pcbTotalAvail
+ )
+{
+ NET_API_STATUS rc;
+ struct handle_info_1 *pOs2Info1;
+ ULONG CharTime;
+ ULONG CharCount;
+
+ if (sLevel != 1) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ try {
+ Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ *pcbTotalAvail = sizeof(struct handle_info_1);
+ if (sizeof(struct handle_info_1) > cbBuffer) {
+ return(NERR_BufTooSmall);
+ }
+
+ rc = Od2QueryNPHInfo(hHandle, &CharTime, &CharCount);
+ if (rc != NO_ERROR) {
+ return (rc);
+ }
+ pOs2Info1 = (struct handle_info_1*)pbBuffer;
+ pOs2Info1->hdli1_chartime = CharTime;
+ pOs2Info1->hdli1_charcount = (unsigned short)CharCount;
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+Net16ServerDiskEnum(
+ IN PCHAR pszServer,
+ IN LONG sLevel,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ OUT PUSHORT pcEntriesRead,
+ OUT PUSHORT pcTotalAvail
+ )
+{
+ TCHAR Server[UNCLEN];
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+ PWCHAR pInfo;
+ PCHAR pOs2Info;
+ ULONG OutBufSize;
+ DWORD EntriesRead;
+ DWORD i;
+ DWORD ResumeHandle;
+ DWORD TotalEntries;
+ ULONG StringLen;
+ int TotalAvailNotSet = TRUE;
+
+ try {
+ PROBE_STRING(pszServer);
+ Od2ProbeForWrite(pcTotalAvail,sizeof(*pcTotalAvail),1);
+ Od2ProbeForWrite(pcEntriesRead,sizeof(*pcEntriesRead),1);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (sLevel != 0) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ OutBufSize = cbBuffer;
+ ResumeHandle = 0;
+ pOs2Info = (PCHAR)pbBuffer;
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+ rc = ERROR_MORE_DATA;
+
+ while (rc == ERROR_MORE_DATA) {
+
+ rc = NetServerDiskEnum(Server, 0, &BufPtr, PREFMAXLEN,
+ &EntriesRead, &TotalEntries, &ResumeHandle);
+
+ if ((rc != NO_ERROR) && (rc != ERROR_MORE_DATA)) {
+ return(rc);
+ }
+
+ if (TotalAvailNotSet) {
+ *pcTotalAvail = (USHORT) TotalEntries;
+ *pcEntriesRead = 0;
+ TotalAvailNotSet = FALSE;
+ }
+
+ pInfo = (PWCHAR) BufPtr;
+
+ for (i = 0; i < EntriesRead; i++) {
+
+ StringLen = UWstrlen(pInfo) + 1;
+
+ if ((StringLen + 1) > OutBufSize) {
+ if (cbBuffer > 0) { // if 0 length buffer, unable to return anything
+ *pOs2Info = '\0'; // The terminating NUL
+ }
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+ OutBufSize -= StringLen;
+
+ UW2ANSIstrcpy(pOs2Info, pInfo);
+
+ pOs2Info += strlen(pOs2Info) + 1;
+ pInfo += StringLen;
+
+ (*pcEntriesRead)++;
+ }
+ *pOs2Info = '\0'; // The terminating NUL
+ NetApiBufferFree(BufPtr);
+ }
+
+ return(rc);
+}
+
+
+APIRET
+Net16ServerEnum2(
+ IN PCHAR pszServer,
+ IN LONG sLevel,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ OUT PUSHORT pcEntriesRead,
+ OUT PUSHORT pcTotalAvail,
+ IN ULONG flServerType,
+ IN PCHAR pszDomain
+ )
+{
+ TCHAR Server[UNCLEN];
+ TCHAR Domain[CNLEN];
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+ PSERVER_INFO_101 pInfo101;
+ struct server_info_0 *pOs2Info0;
+ struct server_info_1 *pOs2Info1;
+ PCHAR pEndOfBuffer;
+ ULONG StringLen;
+ DWORD ResumeHandle;
+ ULONG OutBufSize;
+ DWORD EntriesRead;
+ DWORD TotalEntries;
+ DWORD i;
+ int TotalAvailNotSet = TRUE;
+
+ try {
+ PROBE_STRING(pszServer);
+ PROBE_STRING(pszDomain);
+ Od2ProbeForWrite(pcTotalAvail,sizeof(*pcTotalAvail),1);
+ Od2ProbeForWrite(pcEntriesRead,sizeof(*pcEntriesRead),1);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if ((sLevel != 0) && (sLevel != 1)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ pEndOfBuffer = pbBuffer + cbBuffer;
+ OutBufSize = cbBuffer;
+ ResumeHandle = 0;
+ pOs2Info0 = (struct server_info_0 *)pbBuffer;
+ pOs2Info1 = (struct server_info_1 *)pbBuffer;
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+ ANSI2UTstrncpy(Domain, pszDomain, CNLEN);
+ rc = ERROR_MORE_DATA;
+
+ while (rc == ERROR_MORE_DATA) {
+
+ rc = NetServerEnum(Server, 101L, &BufPtr, PREFMAXLEN,
+ &EntriesRead, &TotalEntries,
+ flServerType, Domain, &ResumeHandle);
+
+ if ((rc != NO_ERROR) && (rc != ERROR_MORE_DATA)) {
+ return(rc);
+ }
+
+ if (TotalAvailNotSet) {
+ *pcTotalAvail = (USHORT) TotalEntries;
+ *pcEntriesRead = 0;
+ TotalAvailNotSet = FALSE;
+ }
+
+ pInfo101 = (PSERVER_INFO_101) BufPtr;
+
+ for (i = 0; i < EntriesRead; i++) {
+ if (sLevel == 0) {
+ if (sizeof(struct server_info_0) > OutBufSize) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+ OutBufSize -= sizeof(struct server_info_0);
+
+ UT2ANSIstrncpy(pOs2Info0->sv0_name, (pInfo101 + i)->sv101_name, CNLEN_LM20);
+ pOs2Info0->sv0_name[CNLEN_LM20] = '\0';
+ pOs2Info0++;
+ }
+ else if (sLevel == 1) {
+ StringLen = UTstrlen((pInfo101 + i)->sv101_comment) + 1;
+ if ((sizeof(struct server_info_1) + StringLen) > OutBufSize) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+ OutBufSize -= sizeof(struct server_info_1) + StringLen;
+
+ UT2ANSIstrncpy(pOs2Info1->sv1_name, (pInfo101 + i)->sv101_name, CNLEN_LM20);
+ pOs2Info1->sv1_name[CNLEN_LM20] = '\0';
+ pEndOfBuffer -= StringLen;
+ UT2ANSIstrcpy(pEndOfBuffer, (pInfo101 + i)->sv101_comment);
+ pOs2Info1->sv1_comment = (char *)FLATTOFARPTR(pEndOfBuffer);
+
+ pOs2Info1->sv1_version_major = (unsigned char)(pInfo101 + i)->sv101_version_major;
+ pOs2Info1->sv1_version_minor = (unsigned char)(pInfo101 + i)->sv101_version_minor;
+ pOs2Info1->sv1_type = (pInfo101 + i)->sv101_type;
+ pOs2Info1++;
+ }
+ (*pcEntriesRead)++;
+ }
+
+ NetApiBufferFree(BufPtr);
+ }
+
+ return(rc);
+}
+
+
+APIRET
+Net16ServerGetInfo(
+ IN PCHAR pszServer,
+ IN LONG sLevel,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ OUT PUSHORT pcbTotalAvail
+ )
+{
+ TCHAR Server[UNCLEN];
+ LPBYTE BufPtr1;
+ LPBYTE BufPtr2;
+ NET_API_STATUS rc;
+ PSERVER_INFO_102 pInfo102;
+ PSERVER_INFO_502 pInfo502;
+ struct server_info_0 *pOs2Info0;
+ struct server_info_1 *pOs2Info1;
+ struct server_info_2 *pOs2Info2;
+ struct server_info_3 *pOs2Info3;
+ PCHAR pStrings;
+ PCHAR pEndOfBuffer;
+ ULONG StringLen;
+
+ try {
+ PROBE_STRING(pszServer);
+ Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (sLevel > 3) {
+#if DBG
+ KdPrint(("NetServerGetInfo: non supported sLevel %d\n", sLevel));
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+
+ rc = NetServerGetInfo(Server, 102L, &BufPtr1);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ rc = NetServerGetInfo(Server, 502L, &BufPtr2);
+
+ if (rc != NO_ERROR) {
+ NetApiBufferFree(BufPtr1);
+ return(rc);
+ }
+
+ RtlZeroMemory(pbBuffer, cbBuffer);
+ pInfo102 = (PSERVER_INFO_102) BufPtr1;
+ pInfo502 = (PSERVER_INFO_502) BufPtr2;
+ pEndOfBuffer = pbBuffer + cbBuffer;
+ pOs2Info0 = (struct server_info_0 *)pbBuffer;
+ pOs2Info1 = (struct server_info_1 *)pbBuffer;
+ pOs2Info2 = (struct server_info_2 *)pbBuffer;
+ pOs2Info3 = (struct server_info_3 *)pbBuffer;
+
+ switch (sLevel) {
+
+ case 0:
+
+ *pcbTotalAvail = (USHORT)(sizeof(struct server_info_0));
+ if (sizeof(struct server_info_0) > cbBuffer) {
+ NetApiBufferFree(BufPtr1);
+ NetApiBufferFree(BufPtr2);
+ return(NERR_BufTooSmall);
+ }
+ break;
+
+ case 1:
+
+ pStrings = pbBuffer + sizeof(struct server_info_1);
+
+ StringLen = UTstrlen(pInfo102->sv102_comment) + 1;
+ *pcbTotalAvail = (USHORT)(StringLen + sizeof(struct server_info_1));
+ if (pStrings + StringLen > pEndOfBuffer) {
+ NetApiBufferFree(BufPtr1);
+ NetApiBufferFree(BufPtr2);
+ return(NERR_BufTooSmall);
+ }
+ break;
+
+ case 2:
+
+ pStrings = pbBuffer + sizeof(struct server_info_2);
+
+ StringLen = UTstrlen(pInfo102->sv102_userpath) + 1;
+ *pcbTotalAvail = (USHORT)(StringLen + sizeof(struct server_info_2));
+ if (pStrings + StringLen > pEndOfBuffer) {
+ NetApiBufferFree(BufPtr1);
+ NetApiBufferFree(BufPtr2);
+ return(NERR_BufTooSmall);
+ }
+ break;
+
+ case 3:
+
+ pStrings = pbBuffer + sizeof(struct server_info_3);
+
+ StringLen = UTstrlen(pInfo102->sv102_userpath) + 1;
+ *pcbTotalAvail = (USHORT)(StringLen + sizeof(struct server_info_3));
+ if (pStrings + StringLen > pEndOfBuffer) {
+ NetApiBufferFree(BufPtr1);
+ NetApiBufferFree(BufPtr2);
+ return(NERR_BufTooSmall);
+ }
+ break;
+ }
+
+ switch (sLevel) {
+
+ case 3:
+
+ /*
+ pOs2Info3->sv3_auditedevents = pInfo403->sv403_auditedevents;
+ pOs2Info3->sv3_autoprofile = (unsigned short)pInfo403->sv403_autoprofile;
+
+ StringLen = UTstrlen(pInfo403->sv403_autopath) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo403->sv403_autopath);
+ pOs2Info3->sv3_autopath = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+ */
+
+ case 2:
+
+ /*
+ pOs2Info2->sv2_ulist_mtime = pInfo403->sv403_ulist_mtime;
+ pOs2Info2->sv2_glist_mtime = pInfo403->sv403_glist_mtime;
+ pOs2Info2->sv2_alist_mtime = pInfo403->sv403_alist_mtime;
+ */
+ pOs2Info2->sv2_users = (unsigned short)pInfo102->sv102_users;
+ pOs2Info2->sv2_disc = (unsigned short)pInfo102->sv102_disc;
+
+ /*
+ StringLen = UTstrlen(pInfo403->sv403_alerts) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo403->sv403_alerts);
+ pOs2Info2->sv2_alerts = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ pOs2Info2->sv2_security = (unsigned short)pInfo403->sv403_security;
+ pOs2Info2->sv2_auditing = 0;
+ pOs2Info2->sv2_numadmin = (unsigned short)pInfo403->sv403_numadmin;
+ pOs2Info2->sv2_lanmask = (unsigned short)pInfo403->sv403_lanmask;
+ */
+ pOs2Info2->sv2_hidden = (unsigned short)pInfo102->sv102_hidden;
+ pOs2Info2->sv2_announce = (unsigned short)pInfo102->sv102_announce;
+ pOs2Info2->sv2_anndelta = (unsigned short)pInfo102->sv102_anndelta;
+
+ /*
+ UT2ANSIstrncpy(pOs2Info2->sv2_guestacct, pInfo403->sv403_guestacct, UNLEN_LM20);
+ pOs2Info2->sv2_guestacct[UNLEN_LM20] = '\0';
+ */
+
+ StringLen = UTstrlen(pInfo102->sv102_userpath) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo102->sv102_userpath);
+ pOs2Info2->sv2_userpath = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+// PQPQ pOs2Info2->sv2_chdevs = (unsigned short)pInfo403->sv403_chdevs;
+ pOs2Info2->sv2_chdevs = 100;
+ /*
+ pOs2Info2->sv2_chdevq = (unsigned short)pInfo403->sv403_chdevq;
+ pOs2Info2->sv2_chdevjobs = (unsigned short)pInfo403->sv403_chdevjobs;
+ pOs2Info2->sv2_connections = (unsigned short)pInfo403->sv403_connections;
+ pOs2Info2->sv2_shares = (unsigned short)pInfo403->sv403_shares;
+ pOs2Info2->sv2_openfiles = (unsigned short)pInfo403->sv403_openfiles;
+ */
+ pOs2Info2->sv2_sessopens = (unsigned short)pInfo502->sv502_sessopens;
+ pOs2Info2->sv2_sessvcs = (unsigned short)pInfo502->sv502_sessvcs;
+ /*
+ pOs2Info2->sv2_sessreqs = (unsigned short)pInfo403->sv403_sessreqs;
+ */
+ pOs2Info2->sv2_opensearch = (unsigned short)pInfo502->sv502_opensearch;
+ /*
+ pOs2Info2->sv2_activelocks = (unsigned short)pInfo403->sv403_activelocks;
+ pOs2Info2->sv2_numreqbuf = (unsigned short)pInfo403->sv403_numreqbuf;
+ */
+ pOs2Info2->sv2_sizreqbuf = (unsigned short)pInfo502->sv502_sizreqbuf;
+ /*
+ pOs2Info2->sv2_numbigbuf = (unsigned short)pInfo403->sv403_numbigbuf;
+ pOs2Info2->sv2_numfiletasks= (unsigned short)pInfo403->sv403_numfiletasks;
+ pOs2Info2->sv2_alertsched = (unsigned short)pInfo403->sv403_alertsched;
+ pOs2Info2->sv2_erroralert = (unsigned short)pInfo403->sv403_erroralert;
+ pOs2Info2->sv2_logonalert = (unsigned short)pInfo403->sv403_logonalert;
+ pOs2Info2->sv2_accessalert = (unsigned short)pInfo403->sv403_accessalert;
+ pOs2Info2->sv2_diskalert = (unsigned short)pInfo403->sv403_diskalert;
+ pOs2Info2->sv2_netioalert = (unsigned short)pInfo403->sv403_netioalert;
+ pOs2Info2->sv2_maxauditsz = (unsigned short)pInfo403->sv403_maxauditsz;
+
+ StringLen = UTstrlen(pInfo403->sv403_srvheuristics) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo403->sv403_srvheuristics);
+ pOs2Info2->sv2_srvheuristics = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+ */
+
+ case 1:
+
+ StringLen = UTstrlen(pInfo102->sv102_comment) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo102->sv102_comment);
+ pOs2Info1->sv1_comment = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ pOs2Info1->sv1_version_major = (unsigned char)pInfo102->sv102_version_major;
+ pOs2Info1->sv1_version_minor = (unsigned char)pInfo102->sv102_version_minor;
+ pOs2Info1->sv1_type = (unsigned long)pInfo102->sv102_type;
+
+ case 0:
+
+ UT2ANSIstrncpy(pOs2Info0->sv0_name, pInfo102->sv102_name, CNLEN_LM20);
+ pOs2Info0->sv0_name[CNLEN_LM20] = '\0';
+ break;
+ }
+
+ NetApiBufferFree(BufPtr1);
+ NetApiBufferFree(BufPtr2);
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+Net16ServiceControl(
+ IN PCHAR pszServer,
+ IN PCHAR pszService,
+ IN ULONG fbOpCode,
+ IN ULONG fbArg,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer
+ )
+{
+ TCHAR Server[UNCLEN];
+ TCHAR Service[SNLEN];
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+ PSERVICE_INFO_2 pInfo2;
+ struct service_info_2 *pOs2Info2;
+
+ try {
+ PROBE_STRING(pszServer);
+ PROBE_STRING(pszService);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+
+ // OS/2 services are limited to 15 chars
+ // workaround an important NT service whose name is longer than 15 chars
+
+ if (!_stricmp(pszService, N_Workstation)) {
+ ANSI2UTstrcpy(Service, N_LanmanWorkstation);
+ }
+ if (!_stricmp(pszService, N_Server)) {
+ ANSI2UTstrcpy(Service, N_LanmanServer);
+ }
+ else {
+ ANSI2UTstrncpy(Service, pszService, SNLEN);
+ }
+
+ rc = NetServiceControl(Server, Service, fbOpCode, fbArg, &BufPtr);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ if (sizeof(struct service_info_2) > cbBuffer) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ pInfo2 = (PSERVICE_INFO_2) BufPtr;
+ pOs2Info2 = (struct service_info_2 *)pbBuffer;
+ UT2ANSIstrncpy(pOs2Info2->svci2_name, pInfo2->svci2_name, SNLEN_LM20);
+ pOs2Info2->svci2_name[SNLEN_LM20] = '\0';
+ if (!_stricmp(N_LanmanWorkstati, pOs2Info2->svci2_name)) {
+ strcpy(pOs2Info2->svci2_name, N_Workstation);
+ }
+ else if (!_stricmp(N_LanmanServer, pOs2Info2->svci2_name)) {
+ strcpy(pOs2Info2->svci2_name, N_Server);
+ }
+ UT2ANSIstrncpy(pOs2Info2->svci2_text, pInfo2->svci2_text, STXTLEN_LM20);
+ pOs2Info2->svci2_text[STXTLEN_LM20] = '\0';
+ pOs2Info2->svci2_status = (unsigned short)pInfo2->svci2_status;
+ pOs2Info2->svci2_code = (unsigned long)pInfo2->svci2_code;
+ pOs2Info2->svci2_pid = (unsigned short)pInfo2->svci2_pid;
+
+ NetApiBufferFree(BufPtr);
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+Net16ServiceEnum(
+ IN PCHAR pszServer,
+ IN LONG sLevel,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ OUT PUSHORT pcEntriesRead,
+ OUT PUSHORT pcTotalAvail
+ )
+{
+ TCHAR Server[UNCLEN];
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+ PSERVICE_INFO_0 pInfo0;
+ PSERVICE_INFO_1 pInfo1;
+ PSERVICE_INFO_2 pInfo2;
+ struct service_info_0 *pOs2Info0;
+ struct service_info_1 *pOs2Info1;
+ struct service_info_2 *pOs2Info2;
+ DWORD ResumeHandle;
+ ULONG OutBufSize;
+ DWORD EntriesRead;
+ DWORD TotalEntries;
+ DWORD i;
+ int TotalAvailNotSet = TRUE;
+
+ try {
+ PROBE_STRING(pszServer);
+ Od2ProbeForWrite(pcTotalAvail,sizeof(*pcTotalAvail),1);
+ Od2ProbeForWrite(pcEntriesRead,sizeof(*pcEntriesRead),1);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if ((sLevel != 0) && (sLevel != 1) && (sLevel != 2)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ OutBufSize = cbBuffer;
+ ResumeHandle = 0;
+ pOs2Info0 = (struct service_info_0 *)pbBuffer;
+ pOs2Info1 = (struct service_info_1 *)pbBuffer;
+ pOs2Info2 = (struct service_info_2 *)pbBuffer;
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+ rc = ERROR_MORE_DATA;
+
+ while (rc == ERROR_MORE_DATA) {
+
+ rc = NetServiceEnum(Server, sLevel, &BufPtr, PREFMAXLEN,
+ &EntriesRead, &TotalEntries, &ResumeHandle);
+
+ if ((rc != NO_ERROR) && (rc != ERROR_MORE_DATA)) {
+ return(rc);
+ }
+
+ if (TotalAvailNotSet) {
+ *pcTotalAvail = (USHORT) TotalEntries;
+ *pcEntriesRead = 0;
+ TotalAvailNotSet = FALSE;
+ }
+
+ for (i = 0; i < EntriesRead; i++) {
+ if (sLevel == 0) {
+ if (sizeof(struct service_info_0) > OutBufSize) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+ OutBufSize -= sizeof(struct service_info_0);
+
+ pInfo0 = (PSERVICE_INFO_0) BufPtr + i;
+ UT2ANSIstrncpy(pOs2Info0->svci0_name, pInfo0->svci0_name, SNLEN_LM20);
+ pOs2Info0->svci0_name[SNLEN_LM20] = '\0';
+ if (!_stricmp(N_LanmanWorkstati, pOs2Info0->svci0_name)) {
+ strcpy(pOs2Info0->svci0_name, N_Workstation);
+ }
+ else if (!_stricmp(N_LanmanServer, pOs2Info0->svci0_name)) {
+ strcpy(pOs2Info0->svci0_name, N_Server);
+ }
+
+ pOs2Info0++;
+ }
+ else if (sLevel == 1) {
+ if (sizeof(struct service_info_1) > OutBufSize) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+ OutBufSize -= sizeof(struct service_info_1);
+
+ pInfo1 = (PSERVICE_INFO_1) BufPtr + i;
+ UT2ANSIstrncpy(pOs2Info1->svci1_name, pInfo1->svci1_name, SNLEN_LM20);
+ pOs2Info1->svci1_name[SNLEN_LM20] = '\0';
+ if (!_stricmp(N_LanmanWorkstati, pOs2Info1->svci1_name)) {
+ strcpy(pOs2Info1->svci1_name, N_Workstation);
+ }
+ else if (!_stricmp(N_LanmanServer, pOs2Info1->svci1_name)) {
+ strcpy(pOs2Info1->svci1_name, N_Server);
+ }
+
+ pOs2Info1->svci1_status = (unsigned short)pInfo1->svci1_status;
+ pOs2Info1->svci1_code = (unsigned long)pInfo1->svci1_code;
+ pOs2Info1->svci1_pid = (unsigned short)pInfo1->svci1_pid;
+
+ pOs2Info1++;
+ }
+ else { /* sLevel == 2 */
+ if (sizeof(struct service_info_2) > OutBufSize) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+ OutBufSize -= sizeof(struct service_info_2);
+
+ pInfo2 = (PSERVICE_INFO_2) BufPtr + i;
+ UT2ANSIstrncpy(pOs2Info2->svci2_name, pInfo2->svci2_name, SNLEN_LM20);
+ pOs2Info2->svci2_name[SNLEN_LM20] = '\0';
+ if (!_stricmp(N_LanmanWorkstati, pOs2Info2->svci2_name)) {
+ strcpy(pOs2Info2->svci2_name, N_Workstation);
+ }
+ else if (!_stricmp(N_LanmanServer, pOs2Info2->svci2_name)) {
+ strcpy(pOs2Info2->svci2_name, N_Server);
+ }
+
+ pOs2Info2->svci2_status = (unsigned short)pInfo2->svci2_status;
+ pOs2Info2->svci2_code = (unsigned long)pInfo2->svci2_code;
+ pOs2Info2->svci2_pid = (unsigned short)pInfo2->svci2_pid;
+
+ UT2ANSIstrncpy(pOs2Info2->svci2_text, pInfo2->svci2_text, STXTLEN_LM20);
+ pOs2Info2->svci2_name[STXTLEN_LM20] = '\0';
+
+ pOs2Info2++;
+ }
+ (*pcEntriesRead)++;
+ }
+
+ NetApiBufferFree(BufPtr);
+ }
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+Net16ServiceGetInfo(
+ IN PCHAR pszServer,
+ IN PCHAR pszService,
+ IN LONG sLevel,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ OUT PUSHORT pcbTotalAvail
+ )
+{
+ TCHAR Server[UNCLEN];
+ TCHAR Service[SNLEN];
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+ PSERVICE_INFO_2 pInfo2;
+ struct service_info_2 *pOs2Info2;
+
+ try {
+ PROBE_STRING(pszServer);
+ PROBE_STRING(pszService);
+ Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if ((sLevel != 0) && (sLevel != 1) && (sLevel != 2)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+
+ // OS/2 services are limited to 15 chars
+ // workaround an important NT service whose name is longer than 15 chars
+
+ if (!_stricmp(pszService, N_Workstation)) {
+ ANSI2UTstrcpy(Service, N_LanmanWorkstation);
+ }
+ if (!_stricmp(pszService, N_Server)) {
+ ANSI2UTstrcpy(Service, N_LanmanServer);
+ }
+ else {
+ ANSI2UTstrncpy(Service, pszService, SNLEN);
+ }
+
+ rc = NetServiceGetInfo(Server, Service, 2L, &BufPtr);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ pOs2Info2 = (struct service_info_2 *)pbBuffer;
+ pInfo2 = (PSERVICE_INFO_2) BufPtr;
+
+ switch (sLevel) {
+ case 0:
+ *pcbTotalAvail = (USHORT)sizeof(struct service_info_0);
+ break;
+
+ case 1:
+ *pcbTotalAvail = (USHORT)sizeof(struct service_info_1);
+ break;
+
+ case 2:
+ *pcbTotalAvail = (USHORT)sizeof(struct service_info_2);
+ break;
+ }
+
+ if (sizeof(struct service_info_0) > cbBuffer) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ UT2ANSIstrncpy(pOs2Info2->svci2_name, pInfo2->svci2_name, SNLEN_LM20);
+ pOs2Info2->svci2_name[SNLEN_LM20] = '\0';
+ if (!_stricmp(N_LanmanWorkstati, pOs2Info2->svci2_name)) {
+ strcpy(pOs2Info2->svci2_name, N_Workstation);
+ }
+ else if (!_stricmp(N_LanmanServer, pOs2Info2->svci2_name)) {
+ strcpy(pOs2Info2->svci2_name, N_Server);
+ }
+
+ if (sLevel >= 1) {
+ if (sizeof(struct service_info_1) > cbBuffer) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ pOs2Info2->svci2_status = (unsigned short)pInfo2->svci2_status;
+ pOs2Info2->svci2_code = (unsigned long)pInfo2->svci2_code;
+ pOs2Info2->svci2_pid = (unsigned short)pInfo2->svci2_pid;
+ }
+
+ if (sLevel >= 2) {
+ if (sizeof(struct service_info_2) > cbBuffer) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ UT2ANSIstrncpy(pOs2Info2->svci2_text, pInfo2->svci2_text, STXTLEN_LM20);
+ pOs2Info2->svci2_text[STXTLEN_LM20] = '\0';
+ }
+
+ NetApiBufferFree(BufPtr);
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+Net16ServiceInstall(
+ IN PCHAR pszServer,
+ IN PCHAR pszService,
+ IN PCHAR pszCmdArgs,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer
+ )
+{
+ TCHAR Server[UNCLEN];
+ TCHAR Service[SNLEN];
+ TCHAR *CmdArgs;
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+ PSERVICE_INFO_2 pInfo2;
+ struct service_info_2 *pOs2Info2;
+ DWORD Argc;
+ DWORD TotalSizeOfStrings;
+ PCHAR pStrings;
+ PCHAR pszTmpCmdArgs;
+ LPTSTR StartOfString;
+ ULONG i;
+ LPTSTR Argv[64];
+
+
+ try {
+ PROBE_STRING(pszServer);
+ PROBE_STRING(pszService);
+ PROBE_STRING(pszCmdArgs);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (sizeof(struct service_info_2) > cbBuffer) {
+ return(NERR_BufTooSmall);
+ }
+
+ pOs2Info2 = (struct service_info_2 *)pbBuffer;
+
+ if (pszCmdArgs == NULL) {
+ pszTmpCmdArgs = "";
+ }
+ else {
+ pszTmpCmdArgs = pszCmdArgs;
+ }
+
+ Argc = 0;
+ pStrings = pszTmpCmdArgs;
+
+ while (*pStrings) {
+ pStrings += strlen(pStrings) + 1;
+ Argc++;
+ }
+ pStrings++; // for the terminating nul character
+
+ if (Argc > 64) {
+ return(ERROR_ACCESS_DENIED);
+ }
+
+ TotalSizeOfStrings = pStrings - pszTmpCmdArgs;
+
+ CmdArgs = (TCHAR *) RtlAllocateHeap(Od2Heap, 0, TotalSizeOfStrings * sizeof(TCHAR));
+
+ if (CmdArgs == NULL) {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+
+ // OS/2 services are limited to 15 chars
+ // workaround an important NT service whose name is longer than 15 chars
+
+ if (!_stricmp(pszService, N_Workstation)) {
+ ANSI2UTstrcpy(Service, N_LanmanWorkstation);
+ }
+ if (!_stricmp(pszService, N_Server)) {
+ ANSI2UTstrcpy(Service, N_LanmanServer);
+ }
+ else {
+ ANSI2UTstrncpy(Service, pszService, SNLEN);
+ }
+
+ ANSI2UTmemcpy(CmdArgs, pszTmpCmdArgs, TotalSizeOfStrings);
+
+ StartOfString = CmdArgs;
+ for (i = 0; i < Argc; i++) {
+ Argv[i] = StartOfString;
+ while (*StartOfString++ != L'\0') {
+ ;
+ }
+ }
+
+ rc = NetServiceInstall(Server, Service, Argc, Argv, &BufPtr);
+
+ RtlFreeHeap(Od2Heap, 0, CmdArgs);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ pInfo2 = (PSERVICE_INFO_2) BufPtr;
+
+ UT2ANSIstrncpy(pOs2Info2->svci2_name, pInfo2->svci2_name, SNLEN_LM20);
+ pOs2Info2->svci2_name[SNLEN_LM20] = '\0';
+ if (!_stricmp(N_LanmanWorkstati, pOs2Info2->svci2_name)) {
+ strcpy(pOs2Info2->svci2_name, N_Workstation);
+ }
+ else if (!_stricmp(N_LanmanServer, pOs2Info2->svci2_name)) {
+ strcpy(pOs2Info2->svci2_name, N_Server);
+ }
+ pOs2Info2->svci2_status = (unsigned short)pInfo2->svci2_status;
+ pOs2Info2->svci2_code = (unsigned long)pInfo2->svci2_code;
+ pOs2Info2->svci2_pid = (unsigned short)pInfo2->svci2_pid;
+ UT2ANSIstrncpy(pOs2Info2->svci2_text, pInfo2->svci2_text, STXTLEN_LM20);
+ pOs2Info2->svci2_text[STXTLEN_LM20] = '\0';
+
+ NetApiBufferFree(BufPtr);
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+Net16ShareEnum(
+ IN PCHAR pszServer,
+ IN LONG sLevel,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ OUT PUSHORT pcEntriesRead,
+ OUT PUSHORT pcTotalAvail
+ )
+{
+ TCHAR Server[UNCLEN];
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+ PSHARE_INFO_2 pInfo2;
+ struct share_info_0 *pOs2Info0;
+ struct share_info_1 *pOs2Info1;
+ struct share_info_2 *pOs2Info2;
+ PCHAR pEndOfBuffer;
+ ULONG StringLen;
+ DWORD ResumeHandle;
+ ULONG OutBufSize;
+ DWORD EntriesRead;
+ DWORD TotalEntries;
+ DWORD i;
+ int TotalAvailNotSet = TRUE;
+
+ try {
+ PROBE_STRING(pszServer);
+ Od2ProbeForWrite(pcTotalAvail,sizeof(*pcTotalAvail),1);
+ Od2ProbeForWrite(pcEntriesRead,sizeof(*pcEntriesRead),1);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if ((sLevel != 0) && (sLevel != 1) && (sLevel != 2)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ pEndOfBuffer = pbBuffer + cbBuffer;
+ OutBufSize = cbBuffer;
+ ResumeHandle = 0;
+ pOs2Info0 = (struct share_info_0 *)pbBuffer;
+ pOs2Info1 = (struct share_info_1 *)pbBuffer;
+ pOs2Info2 = (struct share_info_2 *)pbBuffer;
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+ rc = ERROR_MORE_DATA;
+
+ while (rc == ERROR_MORE_DATA) {
+
+ rc = NetShareEnum(Server, 2L, &BufPtr, PREFMAXLEN,
+ &EntriesRead, &TotalEntries, &ResumeHandle);
+
+ if ((rc != NO_ERROR) && (rc != ERROR_MORE_DATA)) {
+ return(rc);
+ }
+
+ if (TotalAvailNotSet) {
+ *pcTotalAvail = (USHORT) TotalEntries;
+ *pcEntriesRead = 0;
+ TotalAvailNotSet = FALSE;
+ }
+
+ for (i = 0; i < EntriesRead; i++) {
+ pInfo2 = (PSHARE_INFO_2) BufPtr + i;
+ if (sLevel == 0) {
+ if (sizeof(struct share_info_0) > OutBufSize) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+ OutBufSize -= sizeof(struct share_info_0);
+
+ UT2ANSIstrncpy(pOs2Info0->shi0_netname, pInfo2->shi2_netname, NNLEN_LM20);
+ pOs2Info0->shi0_netname[NNLEN_LM20] = '\0';
+ pOs2Info0++;
+ }
+ else if (sLevel == 1) {
+ StringLen = UTstrlen(pInfo2->shi2_remark) + 1;
+ if ((sizeof(struct share_info_1) + StringLen) > OutBufSize) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+ OutBufSize -= sizeof(struct share_info_1) + StringLen;
+
+ UT2ANSIstrncpy(pOs2Info1->shi1_netname, pInfo2->shi2_netname, NNLEN_LM20);
+ pOs2Info1->shi1_netname[NNLEN_LM20] = '\0';
+ pEndOfBuffer -= StringLen;
+ UT2ANSIstrcpy(pEndOfBuffer, pInfo2->shi2_remark);
+ pOs2Info1->shi1_remark = (char *)FLATTOFARPTR(pEndOfBuffer);
+
+ pOs2Info1->shi1_type = (unsigned short)pInfo2->shi2_type;
+ pOs2Info1++;
+ }
+ else {
+ StringLen = UTstrlen(pInfo2->shi2_remark) + 1 +
+ UTstrlen(pInfo2->shi2_path) + 1 ;
+ if ((sizeof(struct share_info_2) + StringLen) > OutBufSize) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+ OutBufSize -= sizeof(struct share_info_2) + StringLen;
+
+ UT2ANSIstrncpy(pOs2Info2->shi2_netname, pInfo2->shi2_netname, NNLEN_LM20);
+ pOs2Info2->shi2_netname[NNLEN_LM20] = '\0';
+ UT2ANSIstrncpy(pOs2Info2->shi2_passwd, pInfo2->shi2_passwd, SHPWLEN_LM20);
+ pOs2Info2->shi2_passwd[SHPWLEN_LM20] = '\0';
+ pEndOfBuffer -= UTstrlen(pInfo2->shi2_remark) + 1;
+ UT2ANSIstrcpy(pEndOfBuffer, pInfo2->shi2_remark);
+ pOs2Info2->shi2_remark = (char *)FLATTOFARPTR(pEndOfBuffer);
+ pEndOfBuffer -= UTstrlen(pInfo2->shi2_path) + 1;
+ UT2ANSIstrcpy(pEndOfBuffer, pInfo2->shi2_path);
+ pOs2Info2->shi2_path = (char *)FLATTOFARPTR(pEndOfBuffer);
+
+ pOs2Info2->shi2_type = (unsigned short)pInfo2->shi2_type;
+ pOs2Info2->shi2_permissions = (unsigned short)pInfo2->shi2_permissions;
+ pOs2Info2->shi2_max_uses = (unsigned short)pInfo2->shi2_max_uses;
+ pOs2Info2->shi2_current_uses = (unsigned short)pInfo2->shi2_current_uses;
+ pOs2Info2++;
+ }
+ (*pcEntriesRead)++;
+ }
+
+ NetApiBufferFree(BufPtr);
+ }
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+Net16ShareGetInfo(
+ IN PCHAR pszServer,
+ IN PCHAR pszNetName,
+ IN LONG sLevel,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ OUT PUSHORT pcbTotalAvail
+ )
+{
+ TCHAR Server[UNCLEN];
+ TCHAR NetName[NNLEN];
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+ PSHARE_INFO_2 pInfo2;
+ PCHAR pEndOfBuffer;
+ ULONG TotalStringLen;
+ ULONG StringLen;
+
+ try {
+ PROBE_STRING(pszServer);
+ PROBE_STRING(pszNetName);
+ Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if ((sLevel != 0) && (sLevel != 1) && (sLevel != 3)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+ ANSI2UTstrncpy(NetName, pszNetName, NNLEN);
+
+ rc = NetShareGetInfo(Server, NetName, 2L, &BufPtr);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ pEndOfBuffer = pbBuffer;
+ pInfo2 = (PSHARE_INFO_2) BufPtr;
+
+ if (sLevel == 0) {
+ struct share_info_0 *pOs2Info0;
+
+ *pcbTotalAvail = (USHORT)sizeof(struct share_info_0);
+ if (sizeof(struct share_info_0) > cbBuffer) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ pOs2Info0 = (struct share_info_0 *)pbBuffer;
+ UT2ANSIstrncpy(pOs2Info0->shi0_netname, pInfo2->shi2_netname, NNLEN_LM20);
+ pOs2Info0->shi0_netname[NNLEN_LM20] = '\0';
+ }
+ else if (sLevel == 1) {
+ struct share_info_1 *pOs2Info1;
+
+ TotalStringLen = UTstrlen(pInfo2->shi2_remark) + 1;
+ *pcbTotalAvail = (USHORT)(TotalStringLen + sizeof(struct share_info_1));
+ if ((sizeof(struct share_info_1) + TotalStringLen) > cbBuffer) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ pOs2Info1 = (struct share_info_1 *)pbBuffer;
+ UT2ANSIstrncpy(pOs2Info1->shi1_netname, pInfo2->shi2_netname, NNLEN_LM20);
+ pOs2Info1->shi1_netname[NNLEN_LM20] = '\0';
+ pEndOfBuffer += sizeof(struct share_info_1);
+ StringLen = UTstrlen(pInfo2->shi2_remark) + 1;
+ UT2ANSIstrcpy(pEndOfBuffer, pInfo2->shi2_remark);
+ pOs2Info1->shi1_remark = (char *)FLATTOFARPTR(pEndOfBuffer);
+ pEndOfBuffer += StringLen;
+
+ pOs2Info1->shi1_type = (unsigned short)pInfo2->shi2_type;
+ }
+ else {
+ struct share_info_2 *pOs2Info2;
+
+ TotalStringLen = UTstrlen(pInfo2->shi2_remark) + 1 +
+ UTstrlen(pInfo2->shi2_path) + 1 ;
+ *pcbTotalAvail = (USHORT)(TotalStringLen + sizeof(struct share_info_2));
+ if ((sizeof(struct share_info_2) + TotalStringLen) > cbBuffer) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ pOs2Info2 = (struct share_info_2 *)pbBuffer;
+ UT2ANSIstrncpy(pOs2Info2->shi2_netname, pInfo2->shi2_netname, NNLEN_LM20);
+ pOs2Info2->shi2_netname[NNLEN_LM20] = '\0';
+ UT2ANSIstrncpy(pOs2Info2->shi2_passwd, pInfo2->shi2_passwd, SHPWLEN_LM20);
+ pOs2Info2->shi2_passwd[SHPWLEN_LM20] = '\0';
+ pEndOfBuffer += sizeof(struct share_info_2);
+ StringLen = UTstrlen(pInfo2->shi2_remark) + 1;
+ UT2ANSIstrcpy(pEndOfBuffer, pInfo2->shi2_remark);
+ pOs2Info2->shi2_remark = (char *)FLATTOFARPTR(pEndOfBuffer);
+ pEndOfBuffer += StringLen;
+ StringLen = UTstrlen(pInfo2->shi2_path) + 1;
+ UT2ANSIstrcpy(pEndOfBuffer, pInfo2->shi2_path);
+ pOs2Info2->shi2_path = (char *)FLATTOFARPTR(pEndOfBuffer);
+ pEndOfBuffer += StringLen;
+
+ pOs2Info2->shi2_type = (unsigned short)pInfo2->shi2_type;
+ pOs2Info2->shi2_permissions = (unsigned short)pInfo2->shi2_permissions;
+ pOs2Info2->shi2_max_uses = (unsigned short)pInfo2->shi2_max_uses;
+ pOs2Info2->shi2_current_uses = (unsigned short)pInfo2->shi2_current_uses;
+ }
+
+ NetApiBufferFree(BufPtr);
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+Net16UseAdd(
+ IN PCHAR pszServer,
+ IN LONG sLevel,
+ IN PCHAR pbBuffer,
+ IN ULONG cbBuffer
+ )
+{
+ TCHAR Server[UNCLEN];
+ TCHAR Local[DEVLEN];
+ TCHAR Remote[RMLEN];
+ TCHAR Password[PWLEN];
+ USE_INFO_1 Info1;
+ struct use_info_1 *pInfo1;
+
+ try {
+ PROBE_STRING(pszServer);
+ Od2ProbeForRead(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (sLevel != 1) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ if (cbBuffer < sizeof(struct use_info_1)) {
+ return(NERR_BufTooSmall);
+ }
+
+ pInfo1 = (struct use_info_1 *) pbBuffer;
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+ ANSI2UTstrncpy(Local, pInfo1->ui1_local, DEVLEN);
+ Info1.ui1_local = Local;
+ ANSI2UTstrncpy(Remote, FARPTRTOFLAT(pInfo1->ui1_remote), RMLEN);
+ Info1.ui1_remote = Remote;
+
+ if (pInfo1->ui1_password == NULL) {
+ Info1.ui1_password = NULL;
+ }
+ else {
+ ANSI2UTstrncpy(Password, FARPTRTOFLAT(pInfo1->ui1_password), PWLEN);
+ Info1.ui1_password = Password;
+ }
+
+ Info1.ui1_status = pInfo1->ui1_status;
+ Info1.ui1_asg_type = pInfo1->ui1_asg_type;
+ Info1.ui1_refcount = pInfo1->ui1_refcount;
+ Info1.ui1_usecount = pInfo1->ui1_usecount;
+
+ return (NetUseAdd(Server, sLevel, (LPBYTE)&Info1, NULL));
+}
+
+
+APIRET
+Net16UseDel(
+ IN PCHAR pszServer,
+ IN PCHAR pszUseName,
+ IN ULONG usForce
+ )
+{
+ TCHAR Server[UNCLEN];
+ TCHAR UseName[RMLEN];
+
+ try {
+ PROBE_STRING(pszServer);
+ PROBE_STRING(pszUseName);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+ ANSI2UTstrncpy(UseName, pszUseName, RMLEN);
+
+ return (NetUseDel(Server, UseName, usForce));
+}
+
+
+APIRET
+Net16UseEnum(
+ IN PCHAR pszServer,
+ IN LONG sLevel,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ OUT PUSHORT pcEntriesRead,
+ OUT PUSHORT pcTotalAvail
+ )
+{
+ TCHAR Server[UNCLEN];
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+ struct use_info_0 *pOs2Info0;
+ struct use_info_1 *pOs2Info1;
+ PUSE_INFO_0 pInfo0;
+ PUSE_INFO_1 pInfo1;
+ DWORD EntriesRead;
+ DWORD ResumeHandle;
+ DWORD TotalAvail;
+ DWORD i;
+ ULONG RemoteNameLen;
+ ULONG PasswordNameLen;
+ PCHAR CurEndOfBuffer;
+ ULONG OutBufSize;
+ int TotalAvailNotSet = TRUE;
+
+ try {
+ PROBE_STRING(pszServer);
+ Od2ProbeForWrite(pcEntriesRead,sizeof(*pcEntriesRead),1);
+ Od2ProbeForWrite(pcTotalAvail,sizeof(*pcTotalAvail),1);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if ((sLevel != 0) && (sLevel != 1)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ OutBufSize = cbBuffer;
+ CurEndOfBuffer = pbBuffer + cbBuffer;
+ pOs2Info0 = (struct use_info_0 *)pbBuffer;
+ pOs2Info1 = (struct use_info_1 *)pbBuffer;
+
+ ResumeHandle = 0;
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+
+ rc = ERROR_MORE_DATA;
+
+ while (rc == ERROR_MORE_DATA) {
+
+ rc = NetUseEnum(Server, sLevel, &BufPtr, PREFMAXLEN,
+ &EntriesRead, &TotalAvail, &ResumeHandle);
+
+ if ((rc != NO_ERROR) && (rc != ERROR_MORE_DATA)) {
+ return(rc);
+ }
+
+ if (TotalAvailNotSet) {
+ *pcTotalAvail = (USHORT) TotalAvail;
+ *pcEntriesRead = 0;
+ TotalAvailNotSet = FALSE;
+ }
+
+ for (i = 0; i < EntriesRead; i++) {
+ if (sLevel == 0) {
+ pInfo0 = (PUSE_INFO_0) BufPtr + i;
+ RemoteNameLen = UTstrlen(pInfo0->ui0_remote) + 1;
+ if ((sizeof(struct use_info_0) + RemoteNameLen) > OutBufSize ) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+
+ OutBufSize -= sizeof(struct use_info_0) + RemoteNameLen;
+ UT2ANSIstrncpy(pOs2Info0->ui0_local, pInfo0->ui0_local, DEVLEN_LM20);
+ pOs2Info0->ui0_local[DEVLEN_LM20] = '\0';
+ CurEndOfBuffer -= RemoteNameLen;
+ UT2ANSIstrcpy(CurEndOfBuffer, pInfo0->ui0_remote);
+ pOs2Info0->ui0_remote = (char *)FLATTOFARPTR(CurEndOfBuffer);
+
+ pOs2Info0++;
+ }
+ else {
+ pInfo1 = (PUSE_INFO_1) BufPtr + i;
+ RemoteNameLen = UTstrlen(pInfo1->ui1_remote) + 1;
+ PasswordNameLen = UTstrlen(pInfo1->ui1_password) + 1;
+ if ((sizeof(struct use_info_1) + RemoteNameLen + PasswordNameLen) > OutBufSize ) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+
+ OutBufSize -= sizeof(struct use_info_1) + RemoteNameLen + PasswordNameLen;
+ UT2ANSIstrncpy(pOs2Info1->ui1_local, pInfo1->ui1_local, DEVLEN_LM20);
+ pOs2Info1->ui1_local[DEVLEN_LM20] = '\0';
+ CurEndOfBuffer -= RemoteNameLen;
+ UT2ANSIstrcpy(CurEndOfBuffer, pInfo1->ui1_remote);
+ pOs2Info1->ui1_remote = (char *)FLATTOFARPTR(CurEndOfBuffer);
+ CurEndOfBuffer -= PasswordNameLen;
+ UT2ANSIstrcpy(CurEndOfBuffer, pInfo1->ui1_password);
+ pOs2Info1->ui1_password = (char *)FLATTOFARPTR(CurEndOfBuffer);
+ pOs2Info1->ui1_status = (unsigned short)pInfo1->ui1_status;
+ pOs2Info1->ui1_asg_type = (short)pInfo1->ui1_asg_type;
+ pOs2Info1->ui1_refcount = (unsigned short)pInfo1->ui1_refcount;
+ pOs2Info1->ui1_usecount = (unsigned short)pInfo1->ui1_usecount;
+
+ pOs2Info1++;
+ }
+ (*pcEntriesRead)++;
+ }
+
+ NetApiBufferFree(BufPtr);
+ }
+
+ return(rc);
+}
+
+
+APIRET
+Net16UseGetInfo(
+ IN PCHAR pszServer,
+ IN PCHAR pszUseName,
+ IN LONG sLevel,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ OUT PUSHORT pcbTotalAvail
+ )
+{
+ TCHAR Server[UNCLEN];
+ TCHAR UseName[RMLEN];
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+ PCHAR pEndOfBuffer;
+ ULONG TotalStringLen;
+ ULONG StringLen;
+
+ try {
+ PROBE_STRING(pszServer);
+ PROBE_STRING(pszUseName);
+ Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if ((sLevel != 0) && (sLevel != 1)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+ ANSI2UTstrncpy(UseName, pszUseName, RMLEN);
+
+ rc = NetUseGetInfo(Server, UseName, sLevel, &BufPtr);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ pEndOfBuffer = pbBuffer;
+
+ if (sLevel == 0) {
+ PUSE_INFO_0 pInfo0 = (PUSE_INFO_0) BufPtr;
+ struct use_info_0 *pOs2Info0 = (struct use_info_0 *)pbBuffer;
+
+ TotalStringLen = UTstrlen(pInfo0->ui0_remote) + 1;
+ *pcbTotalAvail = (USHORT)(TotalStringLen + sizeof(struct use_info_0));
+ if ((ULONG) *pcbTotalAvail > cbBuffer) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ UT2ANSIstrncpy(pOs2Info0->ui0_local, pInfo0->ui0_local, DEVLEN_LM20);
+ pOs2Info0->ui0_local[DEVLEN_LM20] = '\0';
+ pEndOfBuffer += sizeof(struct use_info_0);
+ StringLen = TotalStringLen;
+ UT2ANSIstrcpy(pEndOfBuffer, pInfo0->ui0_remote);
+ pOs2Info0->ui0_remote = (char *)FLATTOFARPTR(pEndOfBuffer);
+ }
+ else {
+ PUSE_INFO_1 pInfo1 = (PUSE_INFO_1) BufPtr;
+ struct use_info_1 *pOs2Info1 = (struct use_info_1 *)pbBuffer;
+
+ TotalStringLen = UTstrlen(pInfo1->ui1_remote) + 1 +
+ UTstrlen(pInfo1->ui1_password) + 1;
+ *pcbTotalAvail = (USHORT)(TotalStringLen + sizeof(struct use_info_1));
+ if ((ULONG) *pcbTotalAvail > cbBuffer) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ UT2ANSIstrncpy(pOs2Info1->ui1_local, pInfo1->ui1_local, DEVLEN_LM20);
+ pOs2Info1->ui1_local[DEVLEN_LM20] = '\0';
+ pEndOfBuffer += sizeof(struct use_info_1);
+ StringLen = UTstrlen(pInfo1->ui1_remote) + 1;
+ UT2ANSIstrcpy(pEndOfBuffer, pInfo1->ui1_remote);
+ pOs2Info1->ui1_remote = (char *)FLATTOFARPTR(pEndOfBuffer);
+ pEndOfBuffer += StringLen;
+ StringLen = UTstrlen(pInfo1->ui1_password) + 1;
+ UT2ANSIstrcpy(pEndOfBuffer, pInfo1->ui1_password);
+ pOs2Info1->ui1_password = (char *)FLATTOFARPTR(pEndOfBuffer);
+ pEndOfBuffer += StringLen;
+
+ pOs2Info1->ui1_status = (unsigned short)pInfo1->ui1_status;
+ pOs2Info1->ui1_asg_type = (short)pInfo1->ui1_asg_type;
+ pOs2Info1->ui1_refcount = (unsigned short)pInfo1->ui1_refcount;
+ pOs2Info1->ui1_usecount = (unsigned short)pInfo1->ui1_usecount;
+ }
+
+ NetApiBufferFree(BufPtr);
+ return(rc);
+}
+
+
+APIRET
+Net16UserEnum(
+ IN PCHAR pszServer,
+ IN LONG sLevel,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ OUT PUSHORT pcEntriesRead,
+ OUT PUSHORT pcTotalAvail
+ )
+{
+ WCHAR Server[UNCLEN];
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+ struct user_info_0 *pOs2Info0;
+ struct user_info_1 *pOs2Info1;
+ struct user_info_2 *pOs2Info2;
+ struct user_info_10 *pOs2Info10;
+ PUSER_INFO_0 pInfo0;
+ PUSER_INFO_1 pInfo1;
+ PUSER_INFO_2 pInfo2;
+ PUSER_INFO_10 pInfo10;
+ PCHAR CurEndOfBuffer;
+ ULONG StringLen;
+ DWORD EntriesRead;
+ DWORD ResumeHandle;
+ DWORD TotalEntries;
+ ULONG OutBufSize;
+ int TotalAvailNotSet = TRUE;
+ DWORD i;
+
+ try {
+ PROBE_STRING(pszServer);
+ Od2ProbeForWrite(pcEntriesRead,sizeof(*pcEntriesRead),1);
+ Od2ProbeForWrite(pcTotalAvail,sizeof(*pcTotalAvail),1);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if ((sLevel != 0) && (sLevel != 1) && (sLevel != 2) &&
+ (sLevel != 10)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ OutBufSize = cbBuffer;
+ CurEndOfBuffer = pbBuffer + cbBuffer;
+ ResumeHandle = 0;
+ pOs2Info0 = (struct user_info_0 *)pbBuffer;
+ pOs2Info1 = (struct user_info_1 *)pbBuffer;
+ pOs2Info2 = (struct user_info_2 *)pbBuffer;
+ pOs2Info10 = (struct user_info_10 *)pbBuffer;
+
+
+ ANSI2UWstrncpy(Server, pszServer, UNCLEN);
+
+ rc = ERROR_MORE_DATA;
+
+ while (rc == ERROR_MORE_DATA) {
+
+ rc = NetUserEnum(Server, sLevel,
+ FILTER_TEMP_DUPLICATE_ACCOUNT | FILTER_NORMAL_ACCOUNT,
+ &BufPtr,
+ PREFMAXLEN,
+ &EntriesRead, &TotalEntries, &ResumeHandle);
+
+ if ((rc != NO_ERROR) && (rc != ERROR_MORE_DATA)) {
+ return(rc);
+ }
+
+ if (TotalAvailNotSet) {
+ *pcTotalAvail = (USHORT) TotalEntries;
+ *pcEntriesRead = 0;
+ TotalAvailNotSet = FALSE;
+ }
+
+ for (i = 0; i < EntriesRead; i++) {
+ if (sLevel == 0) {
+ pInfo0 = (PUSER_INFO_0) BufPtr + i;
+ if (sizeof(struct user_info_0) > OutBufSize ) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+
+ OutBufSize -= sizeof(struct user_info_0);
+ UW2ANSIstrncpy(pOs2Info0->usri0_name, pInfo0->usri0_name, UNLEN_LM20);
+ pOs2Info0->usri0_name[UNLEN_LM20] = '\0';
+
+ pOs2Info0++;
+ }
+ else if (sLevel == 1) {
+ pInfo1 = (PUSER_INFO_1) BufPtr + i;
+ StringLen = sizeof(struct user_info_1) +
+ UWstrlen(pInfo1->usri1_home_dir) + 1 +
+ UWstrlen(pInfo1->usri1_comment) + 1 +
+ UWstrlen(pInfo1->usri1_script_path) + 1;
+ if (StringLen > OutBufSize ) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+
+ OutBufSize -= StringLen;
+ UW2ANSIstrncpy(pOs2Info1->usri1_name, pInfo1->usri1_name, UNLEN_LM20);
+ pOs2Info1->usri1_name[UNLEN_LM20] = '\0';
+ UW2ANSIstrncpy(pOs2Info1->usri1_password, pInfo1->usri1_password, ENCRYPTED_PWLEN_LM20);
+ pOs2Info1->usri1_password[ENCRYPTED_PWLEN_LM20] = '\0';
+
+ pOs2Info1->usri1_password_age = (long)pInfo1->usri1_password_age;
+ pOs2Info1->usri1_priv = (unsigned short)pInfo1->usri1_priv;
+
+ CopyUW2ANSI(pOs2Info1->usri1_home_dir, pInfo1->usri1_home_dir);
+ CopyUW2ANSI(pOs2Info1->usri1_comment, pInfo1->usri1_comment);
+ CopyUW2ANSI(pOs2Info1->usri1_script_path, pInfo1->usri1_script_path);
+
+ pOs2Info1++;
+ }
+ else if (sLevel == 2) {
+ pInfo2 = (PUSER_INFO_2) BufPtr + i;
+ StringLen = sizeof(struct user_info_2) +
+ UWstrlen(pInfo2->usri2_home_dir) + 1 +
+ UWstrlen(pInfo2->usri2_comment) + 1 +
+ UWstrlen(pInfo2->usri2_script_path) + 1 +
+ UWstrlen(pInfo2->usri2_full_name) + 1 +
+ UWstrlen(pInfo2->usri2_usr_comment) + 1 +
+ UWstrlen(pInfo2->usri2_parms) + 1 +
+ UWstrlen(pInfo2->usri2_workstations) + 1 +
+ strlen(pInfo2->usri2_logon_hours) + 1 +
+ UWstrlen(pInfo2->usri2_logon_server) + 1;
+ if (StringLen > OutBufSize ) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+
+ OutBufSize -= StringLen;
+ UW2ANSIstrncpy(pOs2Info2->usri2_name, pInfo2->usri2_name, UNLEN_LM20);
+ pOs2Info2->usri2_name[UNLEN_LM20] = '\0';
+ UW2ANSIstrncpy(pOs2Info2->usri2_password, pInfo2->usri2_password, ENCRYPTED_PWLEN_LM20);
+ pOs2Info2->usri2_password[ENCRYPTED_PWLEN_LM20] = '\0';
+ pOs2Info2->usri2_password_age = (long)pInfo2->usri2_password_age;
+ pOs2Info2->usri2_priv = (unsigned short)pInfo2->usri2_priv;
+
+ CopyUW2ANSI(pOs2Info2->usri2_home_dir, pInfo2->usri2_home_dir);
+ CopyUW2ANSI(pOs2Info2->usri2_comment, pInfo2->usri2_comment);
+ CopyUW2ANSI(pOs2Info2->usri2_script_path, pInfo2->usri2_script_path);
+
+ pOs2Info2->usri2_auth_flags = (unsigned long)pInfo2->usri2_auth_flags;
+
+ CopyUW2ANSI(pOs2Info2->usri2_full_name, pInfo2->usri2_full_name);
+ CopyUW2ANSI(pOs2Info2->usri2_usr_comment, pInfo2->usri2_usr_comment);
+ CopyUW2ANSI(pOs2Info2->usri2_parms, pInfo2->usri2_parms);
+ CopyUW2ANSI(pOs2Info2->usri2_workstations, pInfo2->usri2_workstations);
+
+ pOs2Info2->usri2_last_logon = (long)pInfo2->usri2_last_logon;
+ pOs2Info2->usri2_last_logoff = (long)pInfo2->usri2_last_logoff;
+ pOs2Info2->usri2_acct_expires = (long)pInfo2->usri2_acct_expires;
+ pOs2Info2->usri2_max_storage = (unsigned long)pInfo2->usri2_max_storage;
+ pOs2Info2->usri2_units_per_week = (unsigned short)pInfo2->usri2_units_per_week;
+ StringLen = strlen(pInfo2->usri2_logon_hours) + 1;
+ CurEndOfBuffer -= StringLen;
+ pOs2Info2->usri2_logon_hours = (char *)FLATTOFARPTR(CurEndOfBuffer);
+ RtlMoveMemory(CurEndOfBuffer, pInfo2->usri2_logon_hours, StringLen);
+ pOs2Info2->usri2_bad_pw_count = (unsigned short)pInfo2->usri2_bad_pw_count;
+ pOs2Info2->usri2_num_logons = (unsigned short)pInfo2->usri2_num_logons;
+
+ CopyUW2ANSI(pOs2Info2->usri2_logon_server, pInfo2->usri2_logon_server);
+
+ pOs2Info2->usri2_country_code = (unsigned short)pInfo2->usri2_country_code;
+ pOs2Info2->usri2_code_page = (unsigned short)pInfo2->usri2_code_page;
+
+ pOs2Info2++;
+ }
+ else if (sLevel == 10) {
+ pInfo10 = (PUSER_INFO_10) BufPtr + i;
+ StringLen = sizeof(struct user_info_10) +
+ UWstrlen(pInfo10->usri10_comment) + 1 +
+ UWstrlen(pInfo10->usri10_usr_comment) + 1 +
+ UWstrlen(pInfo10->usri10_full_name) + 1;
+ if (StringLen > OutBufSize ) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+
+ OutBufSize -= StringLen;
+ UW2ANSIstrncpy(pOs2Info10->usri10_name, pInfo10->usri10_name, UNLEN_LM20);
+ pOs2Info10->usri10_name[UNLEN_LM20] = '\0';
+
+ CopyUW2ANSI(pOs2Info10->usri10_comment, pInfo10->usri10_comment);
+ CopyUW2ANSI(pOs2Info10->usri10_usr_comment, pInfo10->usri10_usr_comment);
+ CopyUW2ANSI(pOs2Info10->usri10_full_name, pInfo10->usri10_full_name);
+
+ pOs2Info10++;
+ }
+#if 0
+ else if (sLevel == 11) {
+ pInfo11 = (PUSER_INFO_11) BufPtr + i;
+ StringLen = sizeof(struct user_info_11) +
+ UWstrlen(pInfo11->usri11_comment) + 1 +
+ UWstrlen(pInfo11->usri11_usr_comment) + 1 +
+ UWstrlen(pInfo11->usri11_full_name) + 1 +
+ UWstrlen(pInfo11->usri11_home_dir) + 1 +
+ UWstrlen(pInfo11->usri11_parms) + 1 +
+ UWstrlen(pInfo11->usri11_logon_server) + 1 +
+ UWstrlen(pInfo11->usri11_workstations) + 1 +
+ strlen(pInfo11->usri11_logon_hours) + 1;
+ if (StringLen > OutBufSize ) {
+ NetApiBufferFree(BufPtr);
+ return(ERROR_MORE_DATA);
+ }
+
+ OutBufSize -= StringLen;
+ UW2ANSIstrncpy(pOs2Info11->usri11_name, pInfo11->usri11_name, UNLEN_LM20);
+ pOs2Info11->usri11_name[UNLEN_LM20] = '\0';
+
+ CopyUW2ANSI(pOs2Info11->usri11_comment, pInfo11->usri11_comment);
+ CopyUW2ANSI(pOs2Info11->usri11_usr_comment, pInfo11->usri11_usr_comment);
+ CopyUW2ANSI(pOs2Info11->usri11_full_name, pInfo11->usri11_full_name);
+
+ pOs2Info11->usri11_priv = (unsigned short)pInfo11->usri11_priv;
+ pOs2Info11->usri11_auth_flags = (unsigned long)pInfo11->usri11_auth_flags;
+ pOs2Info11->usri11_password_age = (long)pInfo11->usri11_password_age;
+
+ CopyUW2ANSI(pOs2Info11->usri11_home_dir, pInfo11->usri11_home_dir);
+ CopyUW2ANSI(pOs2Info11->usri11_parms, pInfo11->usri11_parms);
+
+ pOs2Info11->usri11_last_logon = (long)pInfo11->usri11_last_logon;
+ pOs2Info11->usri11_last_logoff = (long)pInfo11->usri11_last_logoff;
+ pOs2Info11->usri11_bad_pw_count = (unsigned short)pInfo11->usri11_bad_pw_count;
+ pOs2Info11->usri11_num_logons = (unsigned short)pInfo11->usri11_num_logons;
+
+ CopyUW2ANSI(pOs2Info11->usri11_logon_server, pInfo11->usri11_logon_server);
+
+ pOs2Info11->usri11_country_code = (unsigned short)pInfo11->usri11_country_code;
+
+ CopyUW2ANSI(pOs2Info11->usri11_workstations, pInfo11->usri11_workstations);
+
+ pOs2Info11->usri11_max_storage = (unsigned long)pInfo11->usri11_max_storage;
+ pOs2Info11->usri11_units_per_week = (unsigned short)pInfo11->usri11_units_per_week;
+
+ StringLen = strlen(pInfo11->usri11_logon_hours) + 1;
+ CurEndOfBuffer -= StringLen;
+ pOs2Info11->usri11_logon_hours = (char *)FLATTOFARPTR(CurEndOfBuffer);
+ RtlMoveMemory(CurEndOfBuffer, pInfo11->usri11_logon_hours, StringLen);
+
+ pOs2Info11->usri11_code_page = (unsigned short)pInfo11->usri11_code_page;
+
+ pOs2Info11++;
+ }
+#endif
+ (*pcEntriesRead)++;
+ }
+
+ NetApiBufferFree(BufPtr);
+ }
+
+ return(rc);
+}
+
+
+APIRET
+Net16WkstaGetInfo(
+ IN PCHAR pszServer,
+ IN LONG sLevel,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ OUT PUSHORT pcbTotalAvail
+ )
+{
+ TCHAR Server[UNCLEN];
+ LPBYTE BufPtr1;
+ LPBYTE BufPtr2;
+ NET_API_STATUS rc;
+ PWKSTA_INFO_101 pInfo101;
+ PWKSTA_USER_INFO_1 pInfo1;
+ struct wksta_info_0 *pOs2Info0;
+ struct wksta_info_1 *pOs2Info1;
+ struct wksta_info_10 *pOs2Info10;
+ PCHAR pStrings;
+ WCHAR LanRoot[CCHMAXPATH];
+ PCHAR pEndOfBuffer;
+ ULONG StringLen;
+ ULONG TotalStringLen;
+
+ try {
+ PROBE_STRING(pszServer);
+ Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if ((sLevel != 0) && (sLevel != 1) && (sLevel != 10)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+
+ rc = NetWkstaGetInfo(Server, 101L, &BufPtr1);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ rc = NetWkstaUserGetInfo(NULL, 1L, &BufPtr2);
+
+ if (rc != NO_ERROR) {
+ NetApiBufferFree(BufPtr1);
+ return(rc);
+ }
+
+ RtlZeroMemory(pbBuffer, cbBuffer);
+ pEndOfBuffer = pbBuffer + cbBuffer;
+ pInfo101 = (PWKSTA_INFO_101) BufPtr1;
+ pInfo1 = (PWKSTA_USER_INFO_1) BufPtr2;
+
+ if (sLevel == 0) {
+ pOs2Info0 = (struct wksta_info_0 *)pbBuffer;
+
+ //
+ // note about wkix_root - NT returns an empty field.
+ // We should return system directory
+ // in case of lacal machine, and NULL
+ // in case of remote call.
+ //
+ if ((pszServer == NULL) || (*pszServer == (CHAR) NULL)) {
+ StringLen = GetSystemDirectoryW(LanRoot, sizeof(LanRoot)) + 1;
+ LanRoot[StringLen] = UNICODE_NULL;
+ }
+ else {
+ StringLen = 1;
+ LanRoot[0] = UNICODE_NULL;
+ }
+ TotalStringLen = UTstrlen(LanRoot) + 1 +
+ UTstrlen(pInfo101->wki101_computername) + 1 +
+ UTstrlen(pInfo101->wki101_langroup) + 1 +
+ UTstrlen(pInfo1->wkui1_username) + 1 +
+ UTstrlen(pInfo1->wkui1_logon_server) + 1 + 2;
+ *pcbTotalAvail = (USHORT)(sizeof(struct wksta_info_0) + TotalStringLen);
+ pStrings = (PCHAR)(pOs2Info0 + 1);
+ if (pStrings + TotalStringLen > pEndOfBuffer) {
+ NetApiBufferFree(BufPtr1);
+ NetApiBufferFree(BufPtr2);
+ return(NERR_BufTooSmall);
+ }
+
+ UT2ANSIstrcpy(pStrings, LanRoot);
+ pOs2Info0->wki0_root = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ StringLen = UTstrlen(pInfo101->wki101_computername) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo101->wki101_computername);
+ pOs2Info0->wki0_computername = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ StringLen = UTstrlen(pInfo101->wki101_langroup) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo101->wki101_langroup);
+ pOs2Info0->wki0_langroup = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ pOs2Info0->wki0_ver_major = (unsigned char)pInfo101->wki101_ver_major;
+ pOs2Info0->wki0_ver_minor = (unsigned char)pInfo101->wki101_ver_minor;
+
+ StringLen = UTstrlen(pInfo1->wkui1_username) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo1->wkui1_username);
+ pOs2Info0->wki0_username = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ strcpy(pStrings, "\\\\");
+ StringLen = UTstrlen(pInfo1->wkui1_logon_server) + 1 + 2;
+ UT2ANSIstrcpy(pStrings + 2, pInfo1->wkui1_logon_server);
+ pOs2Info0->wki0_logon_server = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+ }
+ else if (sLevel == 1) {
+ pOs2Info1 = (struct wksta_info_1 *)pbBuffer;
+
+ //
+ // note about wkix_root - NT returns an empty field.
+ // We should return system directory
+ // in case of lacal machine, and NULL
+ // in case of remote call.
+ //
+ if ((pszServer == NULL) || (*pszServer == (CHAR) NULL)) {
+ StringLen = GetSystemDirectoryW(LanRoot, sizeof(LanRoot)) + 1;
+ LanRoot[StringLen] = UNICODE_NULL;
+ }
+ else {
+ StringLen = 1;
+ LanRoot[0] = UNICODE_NULL;
+ }
+ TotalStringLen = UTstrlen(LanRoot) + 1 +
+ UTstrlen(pInfo101->wki101_computername) + 1 +
+ UTstrlen(pInfo101->wki101_langroup) + 1 +
+ UTstrlen(pInfo1->wkui1_username) + 1 +
+ UTstrlen(pInfo1->wkui1_logon_server) + 1 + 2 +
+ UTstrlen(pInfo1->wkui1_logon_domain) + 1 +
+ UTstrlen(pInfo1->wkui1_oth_domains) + 1;
+ *pcbTotalAvail = (USHORT)(sizeof(struct wksta_info_1) + TotalStringLen);
+ pStrings = (PCHAR)(pOs2Info1 + 1);
+ if (pStrings + TotalStringLen > pEndOfBuffer) {
+ NetApiBufferFree(BufPtr1);
+ NetApiBufferFree(BufPtr2);
+ return(NERR_BufTooSmall);
+ }
+
+ UT2ANSIstrcpy(pStrings, LanRoot);
+ pOs2Info1->wki1_root = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ StringLen = UTstrlen(pInfo101->wki101_computername) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo101->wki101_computername);
+ pOs2Info1->wki1_computername = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ StringLen = UTstrlen(pInfo101->wki101_langroup) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo101->wki101_langroup);
+ pOs2Info1->wki1_langroup = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ pOs2Info1->wki1_ver_major = (unsigned char)pInfo101->wki101_ver_major;
+ pOs2Info1->wki1_ver_minor = (unsigned char)pInfo101->wki101_ver_minor;
+
+ StringLen = UTstrlen(pInfo1->wkui1_username) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo1->wkui1_username);
+ pOs2Info1->wki1_username = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ strcpy(pStrings, "\\\\");
+ StringLen = UTstrlen(pInfo1->wkui1_logon_server) + 1 + 2;
+ UT2ANSIstrcpy(pStrings + 2, pInfo1->wkui1_logon_server);
+ pOs2Info1->wki1_logon_server = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ StringLen = UTstrlen(pInfo1->wkui1_logon_domain) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo1->wkui1_logon_domain);
+ pOs2Info1->wki1_logon_domain = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ StringLen = UTstrlen(pInfo1->wkui1_oth_domains) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo1->wkui1_oth_domains);
+ pOs2Info1->wki1_oth_domains = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+ }
+ else if (sLevel == 10) {
+ pOs2Info10 = (struct wksta_info_10 *)pbBuffer;
+ TotalStringLen = UTstrlen(pInfo101->wki101_computername) + 1 +
+ UTstrlen(pInfo1->wkui1_username) + 1 +
+ UTstrlen(pInfo101->wki101_langroup) + 1 +
+ UTstrlen(pInfo1->wkui1_logon_domain) + 1 +
+ UTstrlen(pInfo1->wkui1_oth_domains) + 1;
+ *pcbTotalAvail = (USHORT)(sizeof(struct wksta_info_10) + TotalStringLen);
+ pStrings = (PCHAR)(pOs2Info10 + 1);
+ if (pStrings + TotalStringLen > pEndOfBuffer) {
+ NetApiBufferFree(BufPtr1);
+ NetApiBufferFree(BufPtr2);
+ return(NERR_BufTooSmall);
+ }
+
+ StringLen = UTstrlen(pInfo101->wki101_computername) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo101->wki101_computername);
+ pOs2Info10->wki10_computername = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ StringLen = UTstrlen(pInfo1->wkui1_username) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo1->wkui1_username);
+ pOs2Info10->wki10_username = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ StringLen = UTstrlen(pInfo101->wki101_langroup) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo101->wki101_langroup);
+ pOs2Info10->wki10_langroup = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ pOs2Info10->wki10_ver_major = (unsigned char)pInfo101->wki101_ver_major;
+ pOs2Info10->wki10_ver_minor = (unsigned char)pInfo101->wki101_ver_minor;
+
+ StringLen = UTstrlen(pInfo1->wkui1_logon_domain) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo1->wkui1_logon_domain);
+ pOs2Info10->wki10_logon_domain = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+
+ StringLen = UTstrlen(pInfo1->wkui1_oth_domains) + 1;
+ UT2ANSIstrcpy(pStrings, pInfo1->wkui1_oth_domains);
+ pOs2Info10->wki10_oth_domains = (char *)FLATTOFARPTR(pStrings);
+ pStrings += StringLen;
+ }
+
+ NetApiBufferFree(BufPtr1);
+ NetApiBufferFree(BufPtr2);
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+Net16AccessAdd(
+ IN PCHAR pszServer,
+ IN LONG sLevel,
+ IN PCHAR pbBuffer,
+ IN ULONG cbBuffer
+ )
+{
+ TCHAR Server[UNCLEN];
+ PCHAR Buffer;
+ PCHAR ResourceName;
+ LPTSTR pStrings;
+ ULONG StringLen;
+ PACCESS_INFO_1 pInfo1;
+ PACCESS_LIST pInfo;
+ struct access_info_1 *pOs2Info1;
+ struct access_list *pOs2Info;
+ int i;
+ NET_API_STATUS rc;
+
+ try {
+ PROBE_STRING(pszServer);
+ Od2ProbeForRead(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (sLevel != 1) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ Buffer = (PCHAR) RtlAllocateHeap(Od2Heap, 0, LARGE_BUFFER_SIZE);
+
+ if (Buffer == NULL) {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ pOs2Info1 = (struct access_info_1 *) pbBuffer;
+ pOs2Info = (struct access_list *) (pOs2Info1 + 1);
+ pInfo1 = (PACCESS_INFO_1) Buffer;
+ pInfo = (PACCESS_LIST) (pInfo1 + 1);
+ pStrings = (LPTSTR)(pInfo + (pOs2Info1->acc1_count * sizeof(ACCESS_LIST)));
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+
+ ResourceName = FARPTRTOFLAT(pOs2Info1->acc1_resource_name);
+ pInfo1->acc1_resource_name = pStrings;
+ StringLen = strlen(ResourceName) + 1;
+ ANSI2UTstrcpy(pStrings, ResourceName);
+ pStrings += StringLen;
+
+ pInfo1->acc1_attr = pOs2Info1->acc1_attr;
+ pInfo1->acc1_count = pOs2Info1->acc1_count;
+
+ for (i = 0; i < pOs2Info1->acc1_count; i++) {
+ pInfo->acl_access = pOs2Info->acl_access;
+ pInfo->acl_ugname = pStrings;
+ ANSI2UTstrcpy(pStrings, pOs2Info->acl_ugname);
+ pStrings += UNLEN_LM20+1;
+ pInfo++;
+ pOs2Info++;
+ }
+
+ rc = NetAccessAdd(Server, sLevel, Buffer, NULL);
+
+ RtlFreeHeap(Od2Heap, 0, Buffer);
+
+ return(rc);
+}
+
+
+APIRET
+Net16AccessSetInfo(
+ IN PCHAR pszServer,
+ IN PCHAR pszResource,
+ IN LONG sLevel,
+ IN PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ IN LONG sParmNum
+ )
+{
+ TCHAR Server[UNCLEN];
+ TCHAR Resource[NNLEN];
+ PCHAR Buffer = NULL;
+ NET_API_STATUS rc;
+ ACCESS_INFO_1002 AccessInfo1002;
+ PCHAR ResourceName;
+ LPTSTR pStrings;
+ ULONG StringLen;
+ PACCESS_INFO_1 pInfo1;
+ PACCESS_LIST pInfo;
+ struct access_info_1 *pOs2Info1;
+ struct access_list *pOs2Info;
+ int i;
+
+ try {
+ PROBE_STRING(pszServer);
+ PROBE_STRING(pszResource);
+ Od2ProbeForRead(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (sLevel != 1) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+ ANSI2UTstrncpy(Resource, pszResource, NNLEN);
+
+ if (sParmNum == ACCESS_ATTR_PARMNUM) {
+ AccessInfo1002.acc1002_attr = *(PSHORT) pbBuffer;
+ rc = NetAccessSetInfo(Server, Resource, (ULONG) 1002, (PCHAR) &AccessInfo1002, NULL);
+ } else {
+
+ Buffer = (PCHAR) RtlAllocateHeap(Od2Heap, 0, LARGE_BUFFER_SIZE);
+
+ if (Buffer == NULL) {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ pOs2Info1 = (struct access_info_1 *) pbBuffer;
+ pOs2Info = (struct access_list *) (pOs2Info1 + 1);
+ pInfo1 = (PACCESS_INFO_1) Buffer;
+ pInfo = (PACCESS_LIST) (pInfo1 + 1);
+ pStrings = (LPTSTR)(pInfo + (pOs2Info1->acc1_count * sizeof(ACCESS_LIST)));
+
+ ResourceName = FARPTRTOFLAT(pOs2Info1->acc1_resource_name);
+ pInfo1->acc1_resource_name = pStrings;
+ StringLen = strlen(ResourceName) + 1;
+ ANSI2UTstrcpy(pStrings, ResourceName);
+ pStrings += StringLen;
+
+ pInfo1->acc1_attr = pOs2Info1->acc1_attr;
+ pInfo1->acc1_count = pOs2Info1->acc1_count;
+
+ for (i = 0; i < pOs2Info1->acc1_count; i++) {
+ pInfo->acl_access = pOs2Info->acl_access;
+ pInfo->acl_ugname = pStrings;
+ ANSI2UTstrcpy(pStrings, pOs2Info->acl_ugname);
+ pStrings += UNLEN_LM20+1;
+ pInfo++;
+ pOs2Info++;
+ }
+ rc = NetAccessSetInfo(Server, Resource, sLevel, Buffer, NULL);
+
+ RtlFreeHeap(Od2Heap, 0, Buffer);
+ }
+
+ return(rc);
+}
+
+
+APIRET
+Net16AccessGetInfo(
+ IN PCHAR pszServer,
+ IN PCHAR pszResource,
+ IN LONG sLevel,
+ OUT PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ OUT PUSHORT pcbTotalAvail
+ )
+{
+ TCHAR Server[UNCLEN];
+ ANSI_STRING Str_MB;
+ UNICODE_STRING Str_U;
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+ APIRET RetCode;
+ PACCESS_INFO_0 pInfo0;
+ PACCESS_INFO_1 pInfo1;
+ PACCESS_LIST pInfo;
+ struct access_info_0 *pOs2Info0;
+ struct access_info_1 *pOs2Info1;
+ struct access_list *pOs2Info;
+ ULONG strucsize;
+ ULONG Length;
+ ULONG FullLength;
+ ULONG StringLen;
+ ULONG AclsThatFit;
+ ULONG Count;
+ PCHAR pScratch;
+
+ try {
+ PROBE_STRING(pszServer);
+ PROBE_STRING(pszResource);
+ Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if ((sLevel != 0) && (sLevel != 1)) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Net16AccessGetInfo: Invalid level = %d\n", sLevel));
+ }
+#endif
+ return(ERROR_INVALID_LEVEL);
+ }
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+
+ //
+ // Since Resource can be a very long string (up to PATHLEN), we allocate
+ // space for it on the heap instead of the stack, which might be too short
+ //
+
+ if (pszResource != NULL) {
+
+ Or2InitMBString(&Str_MB, pszResource);
+
+ if ((RetCode = Or2MBStringToUnicodeString(&Str_U, &Str_MB, TRUE)) != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Net16AccessGetInfo: Unicode converstion of Resource failed, RetCode = %x\n", RetCode));
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ Str_U.Buffer[Str_U.Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ } else {
+
+ Str_U.Buffer = NULL;
+ }
+
+ rc = NetAccessGetInfo(Server, (LPTSTR) Str_U.Buffer, sLevel, &BufPtr);
+
+ if (Str_U.Buffer != NULL) {
+ RtlFreeUnicodeString(&Str_U);
+ }
+
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Net16AccessGetInfo: System function returned %lx\n", rc));
+ }
+#endif
+ return((APIRET)rc);
+ }
+
+ if (sLevel == 0) {
+
+ strucsize = sizeof(struct access_info_0);
+ pInfo0 = (PACCESS_INFO_0) BufPtr;
+
+ RtlInitUnicodeString(&Str_U, pInfo0->acc0_resource_name);
+
+ if (Str_U.Buffer == NULL) {
+
+ StringLen = 0;
+
+ } else {
+
+ if ((RetCode = Or2UnicodeStringToMBString(&Str_MB, &Str_U, TRUE)) != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Net16AccessGetInfo: Unicode converstion of returned resource name failed, RetCode = %x\n", RetCode));
+ }
+#endif
+ NetApiBufferFree(BufPtr);
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ StringLen = Str_MB.Length + 1;
+ }
+
+ *pcbTotalAvail = (USHORT) (strucsize + StringLen);
+
+ if (cbBuffer < strucsize + StringLen) {
+ if (StringLen != 0) {
+ Or2FreeMBString(&Str_MB);
+ }
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ pOs2Info0 = (struct access_info_0 *) pbBuffer;
+
+ if (StringLen) {
+
+ pScratch = (PCHAR) (pOs2Info0 + 1);
+ pOs2Info0->acc0_resource_name = (PVOID) FLATTOFARPTR(pScratch);
+ RtlMoveMemory(pScratch, Str_MB.Buffer, StringLen);
+ Or2FreeMBString(&Str_MB);
+
+ } else {
+
+ pOs2Info0->acc0_resource_name = NULL;
+ }
+
+ } else { // sLevel == 1
+
+ strucsize = sizeof(struct access_info_1);
+ pInfo1 = (PACCESS_INFO_1) BufPtr;
+
+ RtlInitUnicodeString(&Str_U, pInfo1->acc1_resource_name);
+
+ if (Str_U.Buffer == NULL) {
+
+ StringLen = 0;
+
+ } else {
+
+ if ((RetCode = Or2UnicodeStringToMBString(&Str_MB, &Str_U, TRUE)) != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Net16AccessGetInfo: Unicode converstion of returned resource name failed, RetCode = %x\n", RetCode));
+ }
+#endif
+ NetApiBufferFree(BufPtr);
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ StringLen = Str_MB.Length + 1;
+ }
+
+ AclsThatFit = (ULONG) pInfo1->acc1_count;
+ FullLength = Length = AclsThatFit * sizeof(struct access_list);
+
+ *pcbTotalAvail = (USHORT) (strucsize + FullLength + StringLen);
+
+ if (cbBuffer < strucsize + StringLen) {
+ if (StringLen != 0) {
+ Or2FreeMBString(&Str_MB);
+ }
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ if (cbBuffer < strucsize + StringLen + Length) {
+
+ //
+ // Cut the info down to size...
+ //
+
+ AclsThatFit = (cbBuffer - strucsize - StringLen) / sizeof(struct access_list);
+
+ Length = AclsThatFit * sizeof(struct access_list);
+
+ rc = ERROR_MORE_DATA;
+ }
+
+ pOs2Info1 = (struct access_info_1 *) pbBuffer;
+
+ if (StringLen) {
+
+ pScratch = pbBuffer + strucsize + Length;
+ pOs2Info1->acc1_resource_name = (PVOID) FLATTOFARPTR(pScratch);
+ RtlMoveMemory(pScratch, Str_MB.Buffer, StringLen);
+ Or2FreeMBString(&Str_MB);
+
+ } else {
+
+ pOs2Info1->acc1_resource_name = NULL;
+ }
+
+ pOs2Info1->acc1_attr = (SHORT) pInfo1->acc1_attr;
+ pOs2Info1->acc1_count = (SHORT) AclsThatFit;
+
+ //
+ // Fill in the ACL structures
+ //
+
+ pInfo = (PACCESS_LIST) (pInfo1 + 1);
+ pOs2Info = (struct access_list *) (pOs2Info1 + 1);
+
+ for (Count = 0; Count < AclsThatFit; Count++) {
+
+ pOs2Info[Count].acl_access = (SHORT) pInfo[Count].acl_access;
+ UT2ANSIstrncpy(pOs2Info[Count].acl_ugname, pInfo[Count].acl_ugname, LM20_UNLEN);
+ pOs2Info[Count].acl_ugname[LM20_UNLEN] = '\0';
+ }
+
+ }
+
+ NetApiBufferFree(BufPtr);
+ return((APIRET)rc);
+}
+
+
+APIRET
+Net16AccessDel(
+ IN PCHAR pszServer,
+ IN PCHAR pszResource
+ )
+{
+ TCHAR Server[UNCLEN];
+ TCHAR Resource[NNLEN];
+
+ try {
+ PROBE_STRING(pszServer);
+ PROBE_STRING(pszResource);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+ ANSI2UTstrncpy(Resource, pszResource, NNLEN);
+
+ return (NetAccessDel(Server, Resource));
+}
+
+
+APIRET
+Net16ShareAdd(
+ IN PCHAR pszServer,
+ IN LONG sLevel,
+ IN PCHAR pbBuffer,
+ IN ULONG cbBuffer
+ )
+{
+ TCHAR Server[UNCLEN];
+ PCHAR Buffer;
+ NET_API_STATUS rc;
+ LPTSTR pStrings;
+ PSHARE_INFO_2 pInfo2;
+ struct share_info_2 *pOs2Info2;
+
+ try {
+ PROBE_STRING(pszServer);
+ Od2ProbeForRead(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (sLevel != 2) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ Buffer = (PCHAR) RtlAllocateHeap(Od2Heap, 0, SMALL_BUFFER_SIZE);
+
+ if (Buffer == NULL) {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ pOs2Info2 = (struct share_info_2 *) pbBuffer;
+ pInfo2 = (PSHARE_INFO_2) Buffer;
+ pStrings = (LPTSTR) (pInfo2 + 1);
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+
+ pInfo2->shi2_netname = pStrings;
+ ANSI2UTstrcpy(pStrings, pOs2Info2->shi2_netname);
+ pStrings += strlen(pOs2Info2->shi2_netname) + 1;
+
+ pInfo2->shi2_remark = pStrings;
+ ANSI2UTstrcpy(pStrings, FARPTRTOFLAT(pOs2Info2->shi2_remark));
+ pStrings += strlen(FARPTRTOFLAT(pOs2Info2->shi2_remark)) + 1;
+
+ pInfo2->shi2_path = pStrings;
+ ANSI2UTstrcpy(pStrings, FARPTRTOFLAT(pOs2Info2->shi2_path));
+ pStrings += strlen(FARPTRTOFLAT(pOs2Info2->shi2_path)) + 1;
+
+ pInfo2->shi2_passwd = pStrings;
+ ANSI2UTstrcpy(pStrings, pOs2Info2->shi2_passwd);
+ pStrings += strlen(pOs2Info2->shi2_passwd) + 1;
+
+ pInfo2->shi2_type = pOs2Info2->shi2_type;
+ pInfo2->shi2_permissions = pOs2Info2->shi2_permissions;
+ pInfo2->shi2_max_uses = pOs2Info2->shi2_max_uses;
+ pInfo2->shi2_current_uses = pOs2Info2->shi2_current_uses;
+
+ rc = NetShareAdd(Server, sLevel, Buffer, NULL);
+
+ RtlFreeHeap(Od2Heap, 0, Buffer);
+
+ return(rc);
+}
+
+
+APIRET
+Net16ShareDel(
+ IN PCHAR pszServer,
+ IN PCHAR pszNetName,
+ IN ULONG usReserved
+ )
+{
+ TCHAR Server[UNCLEN];
+ TCHAR NetName[NNLEN];
+
+ UNREFERENCED_PARAMETER(usReserved);
+
+ try {
+ PROBE_STRING(pszServer);
+ PROBE_STRING(pszNetName);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+ ANSI2UTstrncpy(NetName, pszNetName, NNLEN);
+
+ return (NetShareDel(Server, NetName, 0L));
+}
+
+
+APIRET
+Net16UserGetInfo(
+ IN PCHAR pszServer,
+ IN PCHAR pszUserName,
+ IN LONG sLevel,
+ IN PCHAR pbBuffer,
+ IN ULONG cbBuffer,
+ OUT PUSHORT pcbTotalAvail
+ )
+{
+ WCHAR Server[UNCLEN];
+ WCHAR UserName[UNLEN];
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+ PUSER_INFO_0 pInfo0;
+ PUSER_INFO_1 pInfo1;
+ PUSER_INFO_2 pInfo2;
+ PUSER_INFO_10 pInfo10;
+ PUSER_INFO_11 pInfo11;
+ struct user_info_0 *pOs2Info0;
+ struct user_info_1 *pOs2Info1;
+ struct user_info_2 *pOs2Info2;
+ struct user_info_10 *pOs2Info10;
+ struct user_info_11 *pOs2Info11;
+ PCHAR CurEndOfBuffer;
+ ULONG StringLen;
+ ULONG TotalStringLen;
+
+ try {
+ PROBE_STRING(pszServer);
+ PROBE_STRING(pszUserName);
+ Od2ProbeForWrite(pcbTotalAvail,sizeof(*pcbTotalAvail),1);
+ Od2ProbeForWrite(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if ((sLevel != 0) && (sLevel != 1) && (sLevel != 2) &&
+ (sLevel != 10) && (sLevel != 11)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ ANSI2UWstrncpy(Server, pszServer, UNCLEN);
+ ANSI2UWstrncpy(UserName, pszUserName, UNLEN);
+
+ rc = NetUserGetInfo(Server, UserName, sLevel, &BufPtr);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ CurEndOfBuffer = pbBuffer + cbBuffer;
+
+ if (sLevel == 0) {
+ pInfo0 = (PUSER_INFO_0) BufPtr;
+ pOs2Info0 = (struct user_info_0 *)pbBuffer;
+ *pcbTotalAvail = (USHORT)sizeof(struct user_info_0);
+ if ((ULONG)sizeof(struct user_info_0) > cbBuffer) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+ UW2ANSIstrncpy(pOs2Info0->usri0_name, pInfo0->usri0_name, UNLEN_LM20);
+ pOs2Info0->usri0_name[UNLEN_LM20] = '\0';
+ }
+ else if (sLevel == 1) {
+ pInfo1 = (PUSER_INFO_1) BufPtr;
+ pOs2Info1 = (struct user_info_1 *)pbBuffer;
+ TotalStringLen = sizeof(struct user_info_1) +
+ UWstrlen(pInfo1->usri1_home_dir) + 1 +
+ UWstrlen(pInfo1->usri1_comment) + 1 +
+ UWstrlen(pInfo1->usri1_script_path) + 1;
+ *pcbTotalAvail = (USHORT)TotalStringLen;
+ if (TotalStringLen > cbBuffer) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ UW2ANSIstrncpy(pOs2Info1->usri1_name, pInfo1->usri1_name, UNLEN_LM20);
+ pOs2Info1->usri1_name[UNLEN_LM20] = '\0';
+
+ UW2ANSIstrncpy(pOs2Info1->usri1_password, pInfo1->usri1_password, ENCRYPTED_PWLEN_LM20);
+ pOs2Info1->usri1_password[ENCRYPTED_PWLEN_LM20] = '\0';
+
+ CopyUW2ANSI(pOs2Info1->usri1_home_dir, pInfo1->usri1_home_dir);
+ CopyUW2ANSI(pOs2Info1->usri1_comment, pInfo1->usri1_comment);
+ CopyUW2ANSI(pOs2Info1->usri1_script_path, pInfo1->usri1_script_path);
+
+ pOs2Info1->usri1_password_age = (long)pInfo1->usri1_password_age;
+ pOs2Info1->usri1_priv = (unsigned short)pInfo1->usri1_priv;
+ pOs2Info1->usri1_flags = (unsigned short)pInfo1->usri1_flags;
+ }
+ else if (sLevel == 2) {
+ pInfo2 = (PUSER_INFO_2) BufPtr;
+ pOs2Info2 = (struct user_info_2 *)pbBuffer;
+ TotalStringLen = sizeof(struct user_info_2) +
+ UWstrlen(pInfo2->usri2_home_dir) + 1 +
+ UWstrlen(pInfo2->usri2_comment) + 1 +
+ UWstrlen(pInfo2->usri2_script_path) + 1 +
+ UWstrlen(pInfo2->usri2_full_name) + 1 +
+ UWstrlen(pInfo2->usri2_usr_comment) + 1 +
+ UWstrlen(pInfo2->usri2_parms) + 1 +
+ UWstrlen(pInfo2->usri2_workstations) + 1 +
+ strlen(pInfo2->usri2_logon_hours) +
+ UWstrlen(pInfo2->usri2_logon_server) + 1;
+ *pcbTotalAvail = (USHORT)TotalStringLen;
+ if (TotalStringLen > cbBuffer) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ UW2ANSIstrncpy(pOs2Info2->usri2_name, pInfo2->usri2_name, UNLEN_LM20);
+ pOs2Info2->usri2_name[UNLEN_LM20] = '\0';
+
+ UW2ANSIstrncpy(pOs2Info2->usri2_password, pInfo2->usri2_password, ENCRYPTED_PWLEN_LM20);
+ pOs2Info2->usri2_password[ENCRYPTED_PWLEN_LM20] = '\0';
+
+ CopyUW2ANSI(pOs2Info2->usri2_home_dir, pInfo2->usri2_home_dir);
+ CopyUW2ANSI(pOs2Info2->usri2_comment, pInfo2->usri2_comment);
+ CopyUW2ANSI(pOs2Info2->usri2_script_path, pInfo2->usri2_script_path);
+ CopyUW2ANSI(pOs2Info2->usri2_full_name, pInfo2->usri2_full_name);
+ CopyUW2ANSI(pOs2Info2->usri2_usr_comment, pInfo2->usri2_usr_comment);
+ CopyUW2ANSI(pOs2Info2->usri2_parms, pInfo2->usri2_parms);
+ CopyUW2ANSI(pOs2Info2->usri2_workstations, pInfo2->usri2_workstations);
+ CopyUW2ANSI(pOs2Info2->usri2_logon_server, pInfo2->usri2_logon_server);
+ StringLen = strlen(pInfo2->usri2_logon_hours) + 1;
+ CurEndOfBuffer -= StringLen;
+ pOs2Info2->usri2_logon_hours = (char *)FLATTOFARPTR(CurEndOfBuffer);
+ RtlMoveMemory(CurEndOfBuffer, pInfo2->usri2_logon_hours, StringLen);
+
+ pOs2Info2->usri2_password_age = (long)pInfo2->usri2_password_age;
+ pOs2Info2->usri2_priv = (unsigned short)pInfo2->usri2_priv;
+ pOs2Info2->usri2_flags = (unsigned short)pInfo2->usri2_flags;
+ pOs2Info2->usri2_auth_flags = (unsigned long)pInfo2->usri2_auth_flags;
+ pOs2Info2->usri2_last_logon = (long)pInfo2->usri2_last_logon;
+ pOs2Info2->usri2_last_logoff = (long)pInfo2->usri2_last_logoff;
+ pOs2Info2->usri2_acct_expires = (long)pInfo2->usri2_acct_expires;
+ pOs2Info2->usri2_max_storage = (unsigned long)pInfo2->usri2_max_storage;
+ pOs2Info2->usri2_units_per_week = (unsigned short)pInfo2->usri2_units_per_week;
+ pOs2Info2->usri2_bad_pw_count = (unsigned short)pInfo2->usri2_bad_pw_count;
+ pOs2Info2->usri2_num_logons = (unsigned short)pInfo2->usri2_num_logons;
+ pOs2Info2->usri2_country_code = (unsigned short)pInfo2->usri2_country_code;
+ pOs2Info2->usri2_code_page = (unsigned short)pInfo2->usri2_code_page;
+ }
+ else if (sLevel == 10) {
+ pInfo10 = (PUSER_INFO_10) BufPtr;
+ pOs2Info10 = (struct user_info_10 *)pbBuffer;
+ TotalStringLen = sizeof(struct user_info_10) +
+ UWstrlen(pInfo10->usri10_comment) + 1 +
+ UWstrlen(pInfo10->usri10_usr_comment) + 1 +
+ UWstrlen(pInfo10->usri10_full_name) + 1;
+ *pcbTotalAvail = (USHORT)TotalStringLen;
+ if (TotalStringLen > cbBuffer ) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ UW2ANSIstrncpy(pOs2Info10->usri10_name, pInfo10->usri10_name, UNLEN_LM20);
+ pOs2Info10->usri10_name[UNLEN_LM20] = '\0';
+
+ CopyUW2ANSI(pOs2Info10->usri10_comment, pInfo10->usri10_comment);
+ CopyUW2ANSI(pOs2Info10->usri10_usr_comment, pInfo10->usri10_usr_comment);
+ CopyUW2ANSI(pOs2Info10->usri10_full_name, pInfo10->usri10_full_name);
+ }
+ else if (sLevel == 11) {
+ pInfo11 = (PUSER_INFO_11) BufPtr;
+ pOs2Info11 = (struct user_info_11 *)pbBuffer;
+ TotalStringLen = sizeof(struct user_info_11) +
+ UWstrlen(pInfo11->usri11_comment) + 1 +
+ UWstrlen(pInfo11->usri11_usr_comment) + 1 +
+ UWstrlen(pInfo11->usri11_full_name) + 1 +
+ UWstrlen(pInfo11->usri11_home_dir) + 1 +
+ UWstrlen(pInfo11->usri11_parms) + 1 +
+ UWstrlen(pInfo11->usri11_logon_server) + 1 +
+ UWstrlen(pInfo11->usri11_workstations) + 1 +
+ strlen(pInfo11->usri11_logon_hours);
+ *pcbTotalAvail = (USHORT)TotalStringLen;
+ if (TotalStringLen > cbBuffer ) {
+ NetApiBufferFree(BufPtr);
+ return(NERR_BufTooSmall);
+ }
+
+ UW2ANSIstrncpy(pOs2Info11->usri11_name, pInfo11->usri11_name, UNLEN_LM20);
+ pOs2Info11->usri11_name[UNLEN_LM20] = '\0';
+
+ CopyUW2ANSI(pOs2Info11->usri11_comment, pInfo11->usri11_comment);
+ CopyUW2ANSI(pOs2Info11->usri11_usr_comment, pInfo11->usri11_usr_comment);
+ CopyUW2ANSI(pOs2Info11->usri11_full_name, pInfo11->usri11_full_name);
+
+ pOs2Info11->usri11_priv = (unsigned short)pInfo11->usri11_priv;
+ pOs2Info11->usri11_auth_flags = (unsigned long)pInfo11->usri11_auth_flags;
+ pOs2Info11->usri11_password_age = (long)pInfo11->usri11_password_age;
+
+ CopyUW2ANSI(pOs2Info11->usri11_home_dir, pInfo11->usri11_home_dir);
+ CopyUW2ANSI(pOs2Info11->usri11_parms, pInfo11->usri11_parms);
+
+ pOs2Info11->usri11_last_logon = (long)pInfo11->usri11_last_logon;
+ pOs2Info11->usri11_last_logoff = (long)pInfo11->usri11_last_logoff;
+ pOs2Info11->usri11_bad_pw_count = (unsigned short)pInfo11->usri11_bad_pw_count;
+ pOs2Info11->usri11_num_logons = (unsigned short)pInfo11->usri11_num_logons;
+
+ CopyUW2ANSI(pOs2Info11->usri11_logon_server, pInfo11->usri11_logon_server);
+
+ pOs2Info11->usri11_country_code = (unsigned short)pInfo11->usri11_country_code;
+
+ CopyUW2ANSI(pOs2Info11->usri11_workstations, pInfo11->usri11_workstations);
+
+ pOs2Info11->usri11_max_storage = (unsigned long)pInfo11->usri11_max_storage;
+ pOs2Info11->usri11_units_per_week = (unsigned short)pInfo11->usri11_units_per_week;
+
+ StringLen = strlen(pInfo11->usri11_logon_hours) + 1;
+ CurEndOfBuffer -= StringLen;
+ pOs2Info11->usri11_logon_hours = (char *)FLATTOFARPTR(CurEndOfBuffer);
+ RtlMoveMemory(CurEndOfBuffer, pInfo11->usri11_logon_hours, StringLen);
+
+ pOs2Info11->usri11_code_page = (unsigned short)pInfo11->usri11_code_page;
+ }
+
+
+ NetApiBufferFree(BufPtr);
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+Net16MessageBufferSend(
+ IN PSZ pszServer,
+ IN PSZ pszRecipient,
+ IN PBYTE pbBuffer,
+ IN ULONG cbBuffer
+ )
+{
+ TCHAR Server[UNCLEN];
+ TCHAR Recipient[CNLEN+1];
+ ANSI_STRING Tmp_MB;
+ UNICODE_STRING Tmp_U;
+ APIRET rc;
+
+ try {
+ PROBE_STRING(pszServer);
+ PROBE_STRING(pszRecipient);
+ Od2ProbeForRead(pbBuffer,cbBuffer,1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ ANSI2UTstrncpy(Server, pszServer, UNCLEN);
+ ANSI2UTstrncpy(Recipient, pszRecipient, CNLEN+1);
+
+ //
+ // We now need to convert the message buffer
+ // itself to unicode...
+ //
+
+ Tmp_MB.Buffer = (PCHAR) pbBuffer;
+ Tmp_MB.MaximumLength = Tmp_MB.Length = (USHORT) cbBuffer;
+
+ rc = Od2MBStringToUnicodeString(
+ &Tmp_U,
+ &Tmp_MB,
+ TRUE);
+
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Net16MessageBufferSend: Failed to convert buffer to unicode, rc = %lx\n", rc));
+ }
+#endif
+ return(rc);
+ }
+
+ rc = (APIRET) NetMessageBufferSend(Server, Recipient, NULL, (PBYTE) Tmp_U.Buffer, (ULONG) Tmp_U.Length);
+
+ RtlFreeUnicodeString(&Tmp_U);
+
+ return(rc);
+}
+
+
+//*****************************************************************************
+//
+//Following is the implementation of the Netbios APIs
+//
+//*****************************************************************************
+
+
+#if 1
+#if DBG
+// This is a small debug routine to dump a buffer
+static
+VOID
+Od2BufDbgPrint(
+ PBYTE p,
+ ULONG c
+ )
+{
+ ULONG i, m;
+
+ for (i=0; i < c; i++) {
+ m = i%16;
+
+ if (m == 0) {
+ KdPrint((" "));
+ }
+
+ KdPrint(("%2.2x ",p[i]));
+
+ if (m == 15) {
+ KdPrint(("\n"));
+ }
+ }
+
+ if (m != 15) {
+ KdPrint(("\n"));
+ }
+}
+
+// This is a small debug routine to print an NCB
+static
+VOID
+Od2NcbDbgPrint(
+ IN PNCB pNcb,
+ IN PNCB pOs2Ncb,
+ IN ULONG EntryPoint
+ )
+{
+ CHAR CallName[NCBNAMSZ+1];
+ CHAR Name[NCBNAMSZ+1];
+ UCHAR SynchCommand = pNcb->ncb_command & ~ASYNCH;
+ UCHAR Asynch = pNcb->ncb_command & ASYNCH;
+
+ switch (EntryPoint) {
+ case 1:
+ KdPrint(("BEFORE, User Ncb addr = %lx\n", (ULONG)pOs2Ncb));
+ break;
+ case 2:
+ KdPrint(("AFTER\n"));
+ break;
+ case 3:
+ KdPrint(("POST-END\n"));
+ break;
+ }
+
+ memcpy(CallName, pNcb->ncb_callname, NCBNAMSZ);
+ CallName[NCBNAMSZ] = '\0';
+ memcpy(Name, pNcb->ncb_name, NCBNAMSZ);
+ Name[NCBNAMSZ] = '\0';
+ KdPrint(("Netbios call frame:\n"));
+ KdPrint(("------------------\n"));
+ if (EntryPoint != 3) {
+ KdPrint(("TID : 0x%lx\n", NtCurrentTeb()->EnvironmentPointer ? Od2CurrentThreadId() : -1));
+ }
+ KdPrint(("Command: 0x%x\n", pNcb->ncb_command));
+ KdPrint(("Retcode: 0x%x\n", pNcb->ncb_retcode));
+ KdPrint(("LSN : 0x%x\n", pNcb->ncb_lsn));
+ KdPrint(("NUM : 0x%x\n", pNcb->ncb_num));
+ KdPrint(("LanaNum: 0x%x\n", pNcb->ncb_lana_num));
+ KdPrint(("Length : 0x%x\n", pNcb->ncb_length));
+ KdPrint(("Callnam: %s\n", CallName));
+ KdPrint(("Name : %s\n", Name));
+ if (EntryPoint == 1 && Asynch) {
+ KdPrint(("Post : 0x%lx\n", (ULONG)pOs2Ncb->ncb_post));
+ }
+
+ switch (EntryPoint) {
+ case 1:
+ if (SynchCommand != NCBSEND &&
+ SynchCommand != NCBCHAINSEND) {
+ return;
+ }
+ break;
+ case 2:
+ if (Asynch) {
+ return;
+ }
+ case 3:
+ if (SynchCommand != NCBRECV) {
+ return;
+ }
+ }
+
+ KdPrint(("Buffer : \n"));
+ Od2BufDbgPrint((PBYTE) pNcb->ncb_buffer, (ULONG) pNcb->ncb_length);
+ if (SynchCommand == NCBCHAINSEND ||
+ SynchCommand == NCBCHAINSENDNA) {
+
+ ULONG l = (ULONG) (*(PUSHORT)pNcb->ncb_callname);
+
+ KdPrint(("Length2: 0x%lx\n", l));
+ KdPrint(("Buffer2: \n"));
+
+ Od2BufDbgPrint(*(PBYTE *)&pNcb->ncb_callname[2], l);
+
+ }
+
+}
+#endif
+#endif
+
+
+// This routine transfers results from a completed internal NCB to the user's NCB
+static
+VOID
+Od2CopyNcbResults(
+ OUT PNCB Dest,
+ IN PNCB Src,
+ IN BOOLEAN Nb2Semantics
+ )
+{
+ UCHAR SynchCommand = Src->ncb_command & ~ASYNCH;
+
+ //
+ // For Netbios 3.0 just copy the NCB block
+ //
+ if (!Nb2Semantics) {
+ RtlMoveMemory(Dest, Src, sizeof(NCB));
+ return;
+ }
+
+ //
+ // Netbios 2.0
+
+ Dest->ncb_lsn = Src->ncb_lsn;
+ Dest->ncb_num = Src->ncb_num;
+ Dest->ncb_length = Src->ncb_length;
+ if (SynchCommand != NCBCHAINSEND && SynchCommand != NCBCHAINSENDNA) {
+ RtlMoveMemory(Dest->ncb_callname, Src->ncb_callname, NCBNAMSZ);
+ }
+ Dest->ncb_rto = Src->ncb_rto;
+ Dest->ncb_sto = Src->ncb_sto;
+
+ //
+ // Translate an error code in a special case where netbios 2
+ // doesn't return an error
+ //
+
+ if (SynchCommand == NCBHANGUP &&
+ Src->ncb_retcode == NRC_SNUMOUT) {
+
+ Dest->ncb_retcode = NRC_GOODRET;
+ Dest->ncb_cmd_cplt = NRC_GOODRET;
+ } else {
+ Dest->ncb_retcode = Src->ncb_retcode;
+ Dest->ncb_cmd_cplt = Src->ncb_cmd_cplt;
+ }
+}
+
+
+// This is the post routine which is used by NetBiosSubmit
+// It clears the user's semaphore (after doing the internal copy and cleanup)
+static
+VOID
+_stdcall
+Od2NetBiosSemaphoreClearPostRoutine(
+ IN PNCB pNcb
+ )
+{
+ // A user's command has completed. copy the result to his NCB and clear his semaphore.
+
+ PNCB pOs2Ncb = ((PNCBX)pNcb)->original_pncb; // get user's NCB
+ HSYSSEM hUsersSemaphore = (HSYSSEM) ((PNCBX)pNcb)->original_ncb_post; // and semaphore handle
+ HANDLE Net16BiosHasCompleted = ((PNCBX)pNcb)->Net16BiosHasCompleted; // and notification event
+ APIRET RetCode;
+
+ // Wait for Net16Bios to complete its job
+
+ (VOID) NtWaitForSingleObject(Net16BiosHasCompleted, FALSE, NULL);
+ (VOID) NtClose(Net16BiosHasCompleted);
+
+ (VOID) InterlockedIncrement(&Od2MaxAsynchNcbs);
+
+ // Check if user's NCB space is still valid
+
+ try {
+ Od2ProbeForWrite(pOs2Ncb, sizeof(NCB), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ // invalidate user's cancellation address
+ *(PNCB *)pOs2Ncb->ncb_reserve = NULL;
+
+ // copy the results to the user's NCB
+
+ Od2CopyNcbResults(pOs2Ncb, pNcb, TRUE);
+
+#if 1
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ Od2NcbDbgPrint(pNcb, pOs2Ncb, 3);
+ }
+#endif
+#endif
+
+ // free our internal NCB
+
+ RtlFreeHeap(Od2Nb2Heap, 0, pNcb);
+
+ if (hUsersSemaphore == NULL) {
+ return;
+ }
+
+ // clear user's semaphore
+
+ if ((RetCode = DosSemClear(FARPTRTOFLAT(hUsersSemaphore))) != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Od2NetBiosSemaphoreClearPostRoutine: Failed to Clear User Semaphore RetCode = %d\n", RetCode));
+ }
+#endif
+ }
+}
+
+
+// This is the post routine which is used by Netbios (= 3.0)
+// It calls the user's post routine (after doing the internal copy and cleanup)
+static
+VOID
+_stdcall
+Od2NetBiosPostRoutine(
+ IN PNCB pNcb
+ )
+{
+ //
+ // A user's command has completed. copy the result to his NCB and launch his post routine.
+ //
+
+ PNCB pOs2Ncb = ((PNCBX)pNcb)->original_pncb; // get user's NCB
+ PVOID pUsersPostRoutine = (PVOID) ((PNCBX)pNcb)->original_ncb_post; // and post routine address
+ HANDLE Net16BiosHasCompleted = ((PNCBX)pNcb)->Net16BiosHasCompleted; // and notification event
+ APIRET RetCode;
+ BOOLEAN SpecialThread; // used to indicate a special addname thread
+ SEL TmpUserStackSel; // selector for netbios post routine user's stack in addname threads
+ SEL TmpUserStackAlias; // code alias for TmpUserStackSel
+ UCHAR SynchCommand;
+
+ //
+ // Wait for Net16Bios to complete its job
+ //
+
+ (VOID) NtWaitForSingleObject(Net16BiosHasCompleted, FALSE, NULL);
+ (VOID) NtClose(Net16BiosHasCompleted);
+
+ //
+ // Grab the command for later
+ //
+
+ SynchCommand = pNcb->ncb_command & ~ASYNCH;
+
+ //
+ // Check if user's NCB space is still valid
+ //
+
+ try {
+ Od2ProbeForWrite(pOs2Ncb, sizeof(NCB), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // invalidate user's cancellation address
+ //
+
+ *(PNCB *)pOs2Ncb->ncb_reserve = NULL;
+
+ //
+ // copy the results to the user's NCB
+ //
+
+ Od2CopyNcbResults(pOs2Ncb, pNcb, FALSE);
+
+#if 1
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ Od2NcbDbgPrint(pNcb, pOs2Ncb, 3);
+ }
+#endif
+#endif
+
+ //
+ // free our internal NCB
+ //
+
+ RtlFreeHeap(Od2Heap, 0, pNcb);
+
+ if (pUsersPostRoutine == NULL) {
+ return;
+ }
+
+ //
+ // Figure out if this is a special netbios addname thread.
+ // It must be attached separatly. If the TEB already has
+ // an environment then this is the worker thread, and it
+ // has already been attached.
+ // It is possible that this is the worker thread even though
+ // it's an addname-type command (this happens in case the
+ // worker fails to create an addname thread). This is OK
+ // The worker will be attached and detached now, and later
+ // re-attached if needed.
+ //
+
+ if (NtCurrentTeb()->EnvironmentPointer == NULL &&
+ (SynchCommand == NCBADDNAME ||
+ SynchCommand == NCBADDGRNAME ||
+ SynchCommand == NCBASTAT)
+ ) {
+
+ SpecialThread = TRUE;
+
+ } else {
+
+ SpecialThread = FALSE;
+ }
+
+ if (SpecialThread ||
+ !Od2WorkerThreadIsAttached) {
+
+ //
+ // Do this only one time for worker thread, or
+ // once for every special addname thread
+ // This code adopts the thread and makes it
+ // an OS/2 thread.
+ //
+
+ //
+ // attach the thread to server tables
+ //
+
+ if ((RetCode = Od2AttachWinThreadToOs2()) != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Od2NetBiosPostRoutine: Failed to attach to Os2, RetCode = %d\n", RetCode));
+ }
+#endif
+ return;
+ }
+
+ //
+ // allocate a stack
+ //
+
+ if ((RetCode = DosAllocSeg(USERS_STACK_SIZE, &TmpUserStackSel, SEG_NONSHARED)) != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Od2NetBiosPostRoutine: Failed to allocate stack for user, unable to launch\n"));
+ KdPrint((" user's post routine. DosAllocSeg rc = %u\n", RetCode));
+ }
+#endif
+ (VOID) Od2DosExit(EXIT_THREAD, 0L, 0xF0000000L); // this detaches the thread
+ return;
+ }
+
+ if ((RetCode = DosCreateCSAlias(TmpUserStackSel, &TmpUserStackAlias)) != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Od2NetBiosPostRoutine: Failed to code alias user's stack, DosCreateCSAlias rc = %u\n", RetCode));
+ }
+#endif
+ (VOID) DosFreeSeg(TmpUserStackSel);
+ (VOID) Od2DosExit(EXIT_THREAD, 0L, 0xF0000000L); // this detaches the thread
+ return;
+ }
+
+ if (!SpecialThread) {
+
+ Od2UserStackSel = TmpUserStackSel;
+ Od2UserStackAlias = TmpUserStackAlias;
+ Od2WorkerThreadIsAttached = TRUE;
+ }
+
+ } else {
+
+ TmpUserStackSel = Od2UserStackSel;
+ TmpUserStackAlias = Od2UserStackAlias;
+ }
+
+ // set up and run user's post routine
+
+ Od2JumpTo16NetBiosPostDispatcher(pUsersPostRoutine, // 16-bit routine to jump to
+ SELTOFLAT(TmpUserStackSel), // flat ptr to user stack
+ USERS_STACK_SIZE, // stack size
+ TmpUserStackSel, // selector to user stack
+ TmpUserStackAlias, // code alias for user stack
+ (PVOID)FLATTOFARPTR(pOs2Ncb), // pointer to user's NCB
+ // pass it thru ES:BX
+ pOs2Ncb->ncb_retcode // pass through AX
+ );
+
+ if (SpecialThread) {
+
+ //
+ // Deallocate stack and detach thread.
+ // The worker thread always remains attached.
+ //
+
+ (VOID) DosFreeSeg(TmpUserStackAlias);
+ (VOID) DosFreeSeg(TmpUserStackSel);
+ (VOID) Od2DosExit(EXIT_THREAD, 0L, 0xF0000000L); // this only detaches the thread
+ }
+}
+
+
+
+// This is the master Netbios 3.0 API. It checks the user's parameters,
+// copies the NCB to an internal aligned NCB and calls win32 Netbios.
+// some internal paramaters are attached to the NCB (see NCBX) on async calls
+
+APIRET
+Net16bios(
+ IN PNCB pOs2Ncb
+ )
+{
+ PNCB pNcb;
+ PNCB pCancelNcb;
+ UCHAR rc;
+ UCHAR SynchCommand;
+ UCHAR Asynch;
+ HANDLE Net16BiosHasCompleted;
+ BOOLEAN Nb2Semantics;
+ BOOLEAN WillPost;
+ PVOID NbHeap;
+ NTSTATUS Status;
+
+ try {
+ Od2ProbeForWrite(pOs2Ncb, sizeof(NCB), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ pOs2Ncb->ncb_retcode = NRC_PENDING;
+ pOs2Ncb->ncb_cmd_cplt = NRC_PENDING;
+
+ SynchCommand = pOs2Ncb->ncb_command & ~ASYNCH;
+ Asynch = pOs2Ncb->ncb_command & ASYNCH;
+
+ if (*(PULONG)&pOs2Ncb->ncb_reserve[4] == NETBIOS2_SEMANTICS_SIGNATURE) {
+ *(PULONG)&pOs2Ncb->ncb_reserve[4] = 0;
+ Nb2Semantics = TRUE;
+ } else {
+ Nb2Semantics = FALSE;
+ }
+
+ //
+ // Allocate internal NCB
+ //
+
+ if (Nb2Semantics) {
+ NbHeap = Od2Nb2Heap;
+ } else {
+ NbHeap = Od2Heap;
+ }
+
+ pNcb = (PNCB) RtlAllocateHeap(NbHeap, 0, sizeof(NCBX));
+
+ ASSERT(((ULONG)pNcb & 3) == 0); // pointer must be DWORD aligned
+
+ if (pNcb == NULL) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Net16bios: Failed to RtlAllocateHeap internal NCB\n"));
+ }
+#endif
+ pOs2Ncb->ncb_retcode = NRC_NORES;
+ pOs2Ncb->ncb_cmd_cplt = NRC_NORES;
+ // BUGBUG: should call post routine here if asynch.
+ return(NRC_NORES);
+ }
+
+ RtlMoveMemory(pNcb, pOs2Ncb, sizeof(NCB));
+
+ //
+ // If it is a netbios 2 reset then modify the new NCB to the protect mode parameters
+ //
+ // Note: this is not currently used, since we allow open for NB_REGULAR only
+ //
+ if (Nb2Semantics &&
+ SynchCommand == NCBRESET) {
+ if (pNcb->ncb_lsn == 0) {
+ pNcb->ncb_callname[0] = 6;
+ } else {
+ pNcb->ncb_callname[0] = pNcb->ncb_lsn;
+ }
+ if (pNcb->ncb_num == 0) {
+ pNcb->ncb_callname[1] = 12;
+ } else {
+ pNcb->ncb_callname[1] = pNcb->ncb_num;
+ }
+ pNcb->ncb_callname[2] = 16;
+ pNcb->ncb_callname[3] = 1;
+ pNcb->ncb_lsn = 0;
+ }
+
+ // Check user's input
+
+ switch (SynchCommand) {
+ case NCBSEND:
+ case NCBSENDNA:
+ case NCBDGSEND:
+ case NCBDGSENDBC:
+
+ if (pNcb->ncb_buffer != NULL) {
+
+ pNcb->ncb_buffer = FARPTRTOFLAT(pNcb->ncb_buffer);
+
+ try {
+ Od2ProbeForRead(pNcb->ncb_buffer, pNcb->ncb_length, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ }
+ break;
+
+ case NCBCHAINSEND:
+ case NCBCHAINSENDNA:
+
+ if (pNcb->ncb_buffer != NULL) {
+
+ PCHAR TmpPtr;
+
+ pNcb->ncb_buffer = FARPTRTOFLAT(pNcb->ncb_buffer);
+
+ try {
+ Od2ProbeForRead(pNcb->ncb_buffer, pNcb->ncb_length, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if ((TmpPtr = *(PCHAR *)&pOs2Ncb->ncb_callname[2]) != NULL) {
+
+ TmpPtr = FARPTRTOFLAT(TmpPtr);
+
+ try {
+ Od2ProbeForRead(TmpPtr, *(PUSHORT)pNcb->ncb_callname, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ *(PCHAR *)&pNcb->ncb_callname[2] = TmpPtr;
+ }
+ }
+ break;
+
+ case NCBFINDNAME:
+ case NCBRECV:
+ case NCBRECVANY:
+ case NCBDGRECV:
+ case NCBDGRECVBC:
+ case NCBASTAT:
+ case NCBSSTAT:
+
+ if (pNcb->ncb_buffer != NULL) {
+
+ pNcb->ncb_buffer = FARPTRTOFLAT(pNcb->ncb_buffer);
+
+ try {
+ Od2ProbeForWrite(pNcb->ncb_buffer, pNcb->ncb_length, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ }
+ break;
+
+ case NCBCANCEL:
+
+ if (pNcb->ncb_buffer != NULL) {
+
+ //
+ // Note: no need to call post routine on error
+ // return from here, because the cancel command
+ // is not allowed to be asynch.
+ //
+
+ pCancelNcb = (PNCB) FARPTRTOFLAT(pNcb->ncb_buffer);
+
+ try {
+ Od2ProbeForWrite(pCancelNcb, sizeof(NCB), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (pCancelNcb->ncb_cmd_cplt != NRC_PENDING) { // is the command still pending?
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Net16bios: Got request to cancel a non-pending NCB, ignoring it\n"));
+ }
+#endif
+ RtlFreeHeap(NbHeap, 0, pNcb);
+ pOs2Ncb->ncb_retcode = NRC_CANCEL;
+ pOs2Ncb->ncb_cmd_cplt = NRC_CANCEL;
+ return(NRC_CANCEL);
+ }
+
+ pNcb->ncb_buffer = *(PUCHAR *)pCancelNcb->ncb_reserve;
+
+ if (pNcb->ncb_buffer == NULL) { // assume we've just completed it
+ // this is reasonable, since cmd_cplt == NRC_PENDING
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Net16bios: NCB completed during request to cancel\n"));
+ }
+#endif
+ RtlFreeHeap(NbHeap, 0, pNcb);
+ pOs2Ncb->ncb_retcode = NRC_CANOCCR;
+ pOs2Ncb->ncb_cmd_cplt = NRC_CANOCCR;
+ return(NRC_CANOCCR);
+ }
+
+ try {
+ Od2ProbeForWrite(pNcb->ncb_buffer, sizeof(NCBX), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+
+ //
+ // The user gave an invalid address
+ //
+
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Net16bios: Got an invalid NCB address to cancel, ignoring it\n"));
+ }
+#endif
+ RtlFreeHeap(NbHeap, 0, pNcb);
+ pOs2Ncb->ncb_retcode = NRC_BADDR;
+ pOs2Ncb->ncb_cmd_cplt = NRC_BADDR;
+ return(NRC_BADDR);
+ }
+ }
+ break;
+ }
+
+ RtlZeroMemory(pNcb->ncb_reserve, 14);
+
+ //
+ // Set up async processing
+ //
+
+ if (Asynch) {
+
+ Status = NtCreateEvent(&Net16BiosHasCompleted,
+ EVENT_ALL_ACCESS,
+ NULL,
+ NotificationEvent,
+ FALSE);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Net16Bios: Can't create an event for synchronization of post routine, rc = %X\n", Status));
+ }
+#endif
+ RtlFreeHeap(NbHeap, 0, pNcb);
+ pOs2Ncb->ncb_retcode = NRC_OSRESNOTAV;
+ pOs2Ncb->ncb_cmd_cplt = NRC_OSRESNOTAV;
+ // BUGBUG: should call post routine here.
+ return(NRC_OSRESNOTAV);
+ }
+
+ // BUGBUG: we must make sure the event is properly cleaned up if the thread terminates
+ // between here and the point it's signalled.
+
+ ((PNCBX)pNcb)->original_pncb = pOs2Ncb;
+ ((PNCBX)pNcb)->original_ncb_post = (ULONG) pNcb->ncb_post;
+ ((PNCBX)pNcb)->Net16BiosHasCompleted = Net16BiosHasCompleted;
+ *(PNCB *)pOs2Ncb->ncb_reserve = pNcb;
+
+ if (Nb2Semantics) {
+ pNcb->ncb_post = Od2NetBiosSemaphoreClearPostRoutine;
+ } else {
+ pNcb->ncb_post = Od2NetBiosPostRoutine;
+ }
+ } else {
+ pNcb->ncb_post = NULL;
+ }
+
+#if 1
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ Od2NcbDbgPrint(pNcb, pOs2Ncb, 1);
+ }
+#endif
+#endif
+
+ //
+ // and go do it
+ //
+
+ if (Nb2Semantics) {
+
+ rc = Od2Netbios(pNcb, Od2NbDev, &WillPost);
+
+ } else {
+
+ rc = Netbios(pNcb);
+
+ //
+ // The following are the cases where win32 netbios does not call
+ // the post routine when called asynch:
+ // 1) bad ncb alignment (NRC_BADDR) -- won't happen
+ // 2) ncb_event and ncb_post both given (NRC_ILLCMD) -- won't happen
+ // 3) returns NRC_OPENERR
+ // this happens when win32 can't open \device\netbios
+ // or can't create a reserved event for sync processing.
+ // 4) sometimes when returns NRC_SYSTEM
+ // if win32 returns -- no post routine
+ // this happens when can't create worker thread
+ // or when can't create related events
+ // (event, addnameevent)
+ // if driver returns -- will call post routine
+ // 5) an access violation after chain send ncb completion when copying
+ // BigBuffer back to user space, or accessing the ncb
+ // internals (post, event).
+ //
+ // The only case we can't be sure about is NRC_SYSTEM. In this
+ // case it is better to assume the post routine will get called.
+ // the only damage that can be incurred in this way is that the
+ // ncb remains left behind on NbHeap, and Net16BiosHasCompleted
+ // event is not deleted. this isn't too bad, assuming this is
+ // a rare problem.
+ //
+
+ if (Asynch && rc != NRC_OPENERR) {
+ WillPost = TRUE;
+ } else {
+ WillPost = FALSE;
+ }
+ }
+
+ // copy results from internal NCB to user's NCB
+
+ Od2CopyNcbResults(pOs2Ncb, pNcb, Nb2Semantics);
+
+#if 1
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ Od2NcbDbgPrint(pNcb, pOs2Ncb, 2);
+ KdPrint(("rc : %d\n", rc));
+ }
+#endif
+#endif
+
+// Note that if the command was a CANCEL, the post routine of the cancelled NCB still gets called,
+// and will clean up the cancelled NCB as needed
+
+ if (Asynch) {
+ if (WillPost) {
+ (VOID) NtSetEvent(Net16BiosHasCompleted, NULL);
+ } else {
+ (VOID) NtClose(Net16BiosHasCompleted);
+ RtlFreeHeap(NbHeap, 0, pNcb);
+ if (Nb2Semantics) {
+ (VOID) InterlockedIncrement(&Od2MaxAsynchNcbs);
+ }
+ }
+ } else {
+ RtlFreeHeap(NbHeap, 0, pNcb);
+ }
+
+ return((APIRET) rc);
+}
+
+
+//*******************
+// Following are old Netbios APIs (lanman 2.x). We create a fictional logical network
+// for each lan adapter in the system. This is done by using NCBENUM. NCBENUM gives
+// us a list of all valid lana numbers in the system. We assign NET1 to the 1st lana
+// NET2 to the 2nd lana and so on. The "default device" for NetBiosOpen and Submit is always
+// NET DEFAULT_NET.
+// The device handle which is used to operate a logical network is simply the NET
+// number + 1. Handle 0 is equivalent to the default net.
+//*******************
+
+
+ULONG
+Od2NetNumberToLanaIndex(
+ IN ULONG NetNumber
+ )
+{
+ if (NetNumber == 0L) { // use default net ?
+ if (Od2LanaEnum.length >= DEFAULT_NET) {
+ return((ULONG)(DEFAULT_NET - 1));
+ } else {
+ return(0L);
+ }
+ } else {
+ if ((ULONG)Od2LanaEnum.length >= NetNumber) {
+ return(NetNumber - 1);
+ } else {
+ return((ULONG)-1);
+ }
+ }
+}
+
+
+NTSTATUS
+Od2ActivateLana(
+ IN ULONG NetNumber,
+ OUT PULONG pLanaIndex OPTIONAL
+ )
+{
+ //
+ // This routine takes a net number, and makes sure netbios 2 is initialized
+ // and ready on that lana. overall netbios 2 initialization is done if necessary.
+ // if NetNumber is (-1), overall initialization is done, but not for a particular
+ // lana.
+ //
+
+ OS2_API_MSG m;
+ POS2_NETBIOS_MSG a = &m.u.Netbios2Request;
+ BOOLEAN InCrit = FALSE;
+ ULONG LanaIndex;
+ PVOID BaseAddress;
+ APIRET RetCode;
+ BOOLEAN RemoveLDTEntry = FALSE;
+
+ if (!Od2Netbios2Initialized) {
+
+ RtlEnterCriticalSection(&Od2NbSyncCrit);
+
+ if (!Od2Netbios2Initialized) { // check again in case we just did it
+
+ //
+ // allocate a special heap to hold the netbios 2 packets.
+ // we allocate this as a shared memory object in order that
+ // the heap have a unique address within each process. no
+ // sharing of memory is actually being done. the reason
+ // unique addresses are necessary is because the netbios
+ // driver gets confused about cancel requests when 2 processes
+ // have the same netbios packet address.
+ //
+
+ RetCode = DosAllocSharedMem(
+ &BaseAddress,
+ NULL, // no name
+ 0x10000L, // reserve 64K for the heap
+ OBJ_GIVEABLE | PAG_READ | PAG_WRITE,
+ FALSE // Don't create LDT entry
+ );
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Od2ActivateLana: DosAllocSharedMem failed, RetCode = %x\n", RetCode));
+ }
+#endif
+ RtlLeaveCriticalSection(&Od2NbSyncCrit);
+ return(STATUS_NO_MEMORY);
+ }
+
+ Od2Nb2Heap = RtlCreateHeap(
+ HEAP_GROWABLE,
+ BaseAddress,
+ 0x10000L, // initial reserved amount
+ 0L, // initial commit = 1 page
+ NULL, // standard lock
+ 0L); // reserved
+
+ if (Od2Nb2Heap == NULL) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Od2ActivateLana: RtlCreateHeap failed\n"));
+ }
+#endif
+ DosFreeMem(BaseAddress, &RemoveLDTEntry);
+ RtlLeaveCriticalSection(&Od2NbSyncCrit);
+ return(STATUS_NO_MEMORY);
+ }
+
+ //
+ // call server to get initial device handle, lana enumeration
+ // initialize internal lanastate
+ //
+
+ if (NetNumber == (ULONG)-1) {
+ a->RequestType = NB2_INIT;
+ } else {
+ a->RequestType = NB2_INIT_LANA;
+ a->NetNumber = (UCHAR) NetNumber;
+ }
+
+ m.ReturnedErrorValue = NO_ERROR;
+ Od2CallSubsystem(&m, NULL, Os2Netbios2Reqst, sizeof(*a));
+
+ if (!NT_SUCCESS(a->ReturnStatus)) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("Od2ActivateLana: Call to server for init failed, Status = %lx\n", a->ReturnStatus));
+ }
+#endif
+ RtlDestroyHeap(Od2Nb2Heap);
+ DosFreeMem(BaseAddress, &RemoveLDTEntry);
+ RtlLeaveCriticalSection(&Od2NbSyncCrit);
+ return(a->ReturnStatus);
+ }
+
+ Od2LanaEnum.length = a->LanaEnumLength;
+ RtlMoveMemory(Od2LanaEnum.lana, a->LanaEnum, MAX_LANA);
+ RtlZeroMemory(Od2LanaState, sizeof(Od2LanaState));
+ Od2NbDev = a->hDev;
+ Od2MaxAsynchNcbs = (LONG) MAX_ASYNCH_NCBS;
+
+ Od2Netbios2Initialized = TRUE;
+
+ if (NetNumber != (ULONG)-1) {
+ if (a->RetCode != NB2ERR_INVALID_LANA) {
+
+ LanaIndex = Od2NetNumberToLanaIndex(NetNumber);
+
+ Od2LanaState[LanaIndex] |= 0x1;
+
+ if (ARGUMENT_PRESENT(pLanaIndex)) {
+ *pLanaIndex = LanaIndex;
+ }
+ } else {
+ if (ARGUMENT_PRESENT(pLanaIndex)) {
+ *pLanaIndex = (ULONG) -1;
+ }
+ }
+ }
+
+ RtlLeaveCriticalSection(&Od2NbSyncCrit);
+ return(STATUS_SUCCESS);
+
+ }
+
+ InCrit = TRUE;
+ }
+
+ if (NetNumber == (ULONG)-1) {
+ if (InCrit) {
+ RtlLeaveCriticalSection(&Od2NbSyncCrit);
+ }
+ return(STATUS_SUCCESS);
+ }
+
+ LanaIndex = Od2NetNumberToLanaIndex(NetNumber);
+
+ if (LanaIndex == (ULONG)-1) {
+
+ if (ARGUMENT_PRESENT(pLanaIndex)) {
+ *pLanaIndex = (ULONG) -1;
+ }
+ if (InCrit) {
+ RtlLeaveCriticalSection(&Od2NbSyncCrit);
+ }
+ return(STATUS_SUCCESS);
+ }
+
+ if (!(Od2LanaState[LanaIndex] & 0x1)) {
+
+ if (!InCrit) {
+
+ RtlEnterCriticalSection(&Od2NbSyncCrit);
+ InCrit = TRUE;
+
+ if (Od2LanaState[LanaIndex] & 0x1) { // check again in case we just did it
+ goto Od2LanaNumGood;
+ }
+ }
+
+ //
+ // call server to init lana
+ //
+
+ if (Od2LanaState[LanaIndex] & 0x2) {
+ Od2LanaState[LanaIndex] &= ~0x2;
+ Od2LanaState[LanaIndex] |= 0x1;
+ goto Od2LanaNumGood;
+ }
+
+ a->RequestType = NB2_LANA;
+ a->NetNumber = (UCHAR) NetNumber;
+
+ m.ReturnedErrorValue = NO_ERROR;
+ Od2CallSubsystem(&m, NULL, Os2Netbios2Reqst, sizeof(*a));
+
+ if (!NT_SUCCESS(a->ReturnStatus)) {
+ RtlLeaveCriticalSection(&Od2NbSyncCrit);
+ return(a->ReturnStatus);
+ }
+
+ if (a->RetCode != NB2ERR_INVALID_LANA) {
+
+ Od2LanaState[LanaIndex] |= 0x1;
+ goto Od2LanaNumGood;
+
+ } else {
+ if (ARGUMENT_PRESENT(pLanaIndex)) {
+ *pLanaIndex = (ULONG) -1;
+ }
+ RtlLeaveCriticalSection(&Od2NbSyncCrit);
+ return(STATUS_SUCCESS);
+ }
+ }
+
+Od2LanaNumGood:
+
+ if (ARGUMENT_PRESENT(pLanaIndex)) {
+ *pLanaIndex = LanaIndex;
+ }
+
+ if (InCrit) {
+ RtlLeaveCriticalSection(&Od2NbSyncCrit);
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+
+APIRET
+Net16BiosClose(
+ ULONG hDevName
+ )
+{
+// NCB Ncb;
+ ULONG LanaIndex;
+
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosClose() called, hDevName = %lu\n", hDevName));
+ }
+#endif
+
+ if (hDevName == 0) {
+ return(NERR_Success); // dummy close for the "default handle"
+ }
+
+ if (!Od2Netbios2Initialized) { // we haven't been initialized at all
+ return(NERR_NetNotStarted);
+ }
+
+ LanaIndex = Od2NetNumberToLanaIndex(hDevName);
+
+ if (LanaIndex == (ULONG)-1) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosClose: invalid hDevName = %lu\n", hDevName));
+ }
+#endif
+ return(ERROR_INVALID_HANDLE);
+ }
+
+ //
+ // check if it's already closed...
+ //
+
+ if (!(Od2LanaState[LanaIndex] & 0x1)) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosClose: already closed hDevName = %lu\n", hDevName));
+ }
+#endif
+ return(ERROR_INVALID_HANDLE);
+ }
+
+ RtlEnterCriticalSection(&Od2NbSyncCrit);
+
+ //
+ // recheck in case we just closed it.
+ //
+
+ if (!(Od2LanaState[LanaIndex] & 0x1)) {
+ RtlLeaveCriticalSection(&Od2NbSyncCrit);
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosClose: already closed hDevName = %lu\n", hDevName));
+ }
+#endif
+ return(ERROR_INVALID_HANDLE);
+ }
+
+ //
+ // we mark the lana as pseudo-closed. It won't be used anymore
+ // until it's reopened.
+ //
+
+ Od2LanaState[LanaIndex] &= ~0x1;
+ Od2LanaState[LanaIndex] |= 0x2;
+
+
+ //
+ // BUGBUG: We can no longer reset the adapter in order to
+ // cancel all pending ncbs on a particular lana. Currently,
+ // there is no other way to do this, so we skip cancelling
+ // pending ncbs, and hope there won't be a problem.
+ //
+ // Note: a way to do this might be to issue an NtCancelIoFile()
+ // from the netbios worker thread. But this will cancel on all
+ // lana.
+ //
+
+#if 0
+ // Reset the corresponding adapter so all pending NCBs get cancelled
+
+ RtlZeroMemory(&Ncb, sizeof(NCB));
+ Ncb.ncb_command = NCBRESET;
+ Ncb.ncb_lana_num = Od2LanaEnum.lana[LanaIndex];
+
+ Net16bios(&Ncb);
+
+ if (Ncb.ncb_retcode != NRC_GOODRET) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosClose: Unable to reset adapter %lu, retcode = %x\n", (ULONG)Ncb.ncb_lana_num, (ULONG)Ncb.ncb_retcode));
+ }
+#endif
+ }
+#endif
+
+ RtlLeaveCriticalSection(&Od2NbSyncCrit);
+ return(NERR_Success);
+}
+
+
+APIRET
+Net16BiosEnum(
+ PCHAR pszServer,
+ LONG sLevel,
+ PCHAR pbBuffer,
+ ULONG cbBuffer,
+ PUSHORT pcEntriesRead,
+ PUSHORT pcTotalAvail
+ )
+{
+ NTSTATUS Status;
+ ULONG strucsiz;
+ UCHAR i;
+ struct netbios_info_0 nb0;
+ struct netbios_info_1 nb1;
+
+ try {
+ if ((pszServer != NULL) && (*pszServer != '\0')) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosEnum() for a remote server is not implemented yet\n"));
+ }
+#endif
+ return(ERROR_NOT_SUPPORTED);
+ }
+
+ Od2ProbeForWrite(pbBuffer, cbBuffer, 1);
+ Od2ProbeForWrite(pcEntriesRead, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pcTotalAvail, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (sLevel != 0 && sLevel != 1) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosEnum() Level %d not legal\n", sLevel));
+ }
+#endif
+ return(ERROR_INVALID_LEVEL);
+ }
+
+ Status = Od2ActivateLana(
+ (ULONG) -1,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosEnum() Od2ActivateLana failed, Status = %lx\n", Status));
+ }
+#endif
+ return(NERR_NetNotStarted);
+ }
+
+ *pcTotalAvail = (USHORT) Od2LanaEnum.length;
+ *pcEntriesRead = 0;
+
+ strucsiz = sLevel == 0 ? sizeof(nb0) : sizeof(nb1);
+
+ for (i = 0; i < Od2LanaEnum.length && cbBuffer >= strucsiz; i++) {
+ if (sLevel == 0) {
+ RtlZeroMemory(&nb0, strucsiz);
+ strcpy(nb0.nb0_net_name, "NET");
+ _itoa((int)i+1, &nb0.nb0_net_name[3], 10);
+ RtlMoveMemory(pbBuffer, &nb0, strucsiz);
+ } else { // sLevel == 1
+ RtlZeroMemory(&nb1, strucsiz);
+ strcpy(nb1.nb1_net_name, "NET");
+ _itoa((int)i+1, &nb1.nb1_net_name[3], 10);
+ strcpy(nb1.nb1_driver_name, "VrtWnNB$");
+ nb1.nb1_lana_num = Od2LanaEnum.lana[i];
+
+ // put some fictive information in it...
+
+ nb1.nb1_driver_type = NB_TYPE_NCB;
+ nb1.nb1_net_status = NB_OPEN_REGULAR|NB_LAN_MANAGED;
+ nb1.nb1_net_bandwidth = 10000000L;
+ nb1.nb1_max_sess = 255;
+ nb1.nb1_max_ncbs = 255;
+ nb1.nb1_max_names = 255;
+
+ RtlMoveMemory(pbBuffer, &nb1, strucsiz);
+ }
+ pbBuffer += strucsiz;
+ cbBuffer -= strucsiz;
+ (*pcEntriesRead)++;
+ }
+
+ if (*pcEntriesRead < (USHORT)Od2LanaEnum.length) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosEnum: returning ERROR_MORE_DATA\n"));
+ }
+#endif
+ return(ERROR_MORE_DATA);
+ }
+ return(NERR_Success);
+}
+
+
+APIRET
+Net16BiosGetInfo(
+ PCHAR pszServer,
+ PCHAR pszNetBiosName,
+ LONG sLevel,
+ PCHAR pbBuffer,
+ ULONG cbBuffer,
+ PUSHORT pcbTotalAvail
+ )
+{
+ NTSTATUS Status;
+ ULONG strucsiz;
+ ULONG NetNumber;
+ ULONG LanaIndex;
+ struct netbios_info_0 nb0;
+ struct netbios_info_1 nb1;
+
+ try {
+ if ((pszServer != NULL) && (*pszServer != '\0')) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosGetInfo() for a remote server is not implemented yet\n"));
+ }
+#endif
+ return(ERROR_NOT_SUPPORTED);
+ }
+
+ PROBE_STRING(pszNetBiosName);
+ Od2ProbeForWrite(pbBuffer, cbBuffer, 1);
+ Od2ProbeForWrite(pcbTotalAvail, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (sLevel != 0 && sLevel != 1) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosGetInfo() Level %d not legal\n", sLevel));
+ }
+#endif
+ return(ERROR_INVALID_LEVEL);
+ }
+
+ strucsiz = sLevel == 0 ? sizeof(nb0) : sizeof(nb1);
+
+ if (cbBuffer < strucsiz) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosGetInfo: user buffer too small\n"));
+ }
+#endif
+ return(NERR_BufTooSmall);
+ }
+
+ if (pszNetBiosName == NULL || *pszNetBiosName == '\0') {
+ NetNumber = 0;
+ } else {
+ if (_strnicmp(pszNetBiosName, "NET", 3)) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosGetInfo: Bad network name: %s\n", pszNetBiosName));
+ }
+#endif
+ return(ERROR_BAD_NETPATH);
+ }
+
+ NetNumber = atol(pszNetBiosName+3);
+ }
+
+ Status = Od2ActivateLana(
+ (ULONG) -1,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosGetInfo() Od2ActivateLana failed, Status = %lx\n", Status));
+ }
+#endif
+ return(NERR_NetNotStarted);
+ }
+
+ LanaIndex = Od2NetNumberToLanaIndex(NetNumber);
+
+ if (LanaIndex == (ULONG) -1) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosGetInfo: Bad network name: %s\n", pszNetBiosName));
+ }
+#endif
+ return(ERROR_BAD_NETPATH);
+ }
+
+ *pcbTotalAvail = (USHORT) strucsiz;
+
+ if (sLevel == 0) {
+ RtlZeroMemory(&nb0, strucsiz);
+ strcpy(nb0.nb0_net_name, pszNetBiosName);
+ RtlMoveMemory(pbBuffer, &nb0, strucsiz);
+ } else { // sLevel == 1
+ RtlZeroMemory(&nb1, strucsiz);
+ strcpy(nb1.nb1_net_name, pszNetBiosName);
+ strcpy(nb1.nb1_driver_name, "VrtWnNB$");
+ nb1.nb1_lana_num = Od2LanaEnum.lana[LanaIndex];
+
+ // put some fictive information in it...
+
+ nb1.nb1_driver_type = NB_TYPE_NCB;
+ nb1.nb1_net_status = NB_OPEN_REGULAR|NB_LAN_MANAGED;
+ nb1.nb1_net_bandwidth = 10000000L;
+ nb1.nb1_max_sess = 255;
+ nb1.nb1_max_ncbs = 255;
+ nb1.nb1_max_names = 255;
+
+ RtlMoveMemory(pbBuffer, &nb1, strucsiz);
+ }
+
+ return(NERR_Success);
+}
+
+
+APIRET
+Net16BiosOpen(
+ PCHAR pszDevName,
+ PCHAR pszReserved,
+ ULONG usOpenOpt,
+ PUSHORT phDevName
+ )
+{
+ NTSTATUS Status;
+ ULONG NetNumber;
+ ULONG LanaIndex;
+
+ UNREFERENCED_PARAMETER(pszReserved);
+
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosOpen() called\n"));
+ }
+#endif
+
+ try {
+ PROBE_STRING(pszDevName);
+ Od2ProbeForWrite(phDevName, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (usOpenOpt < NB_REGULAR ||
+ usOpenOpt > NB_EXCLUSIVE) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosOpen() illegal usOpenOpt = %lx\n", usOpenOpt));
+ }
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ if (usOpenOpt != NB_REGULAR) { // we only support NB_REGULAR for now
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosOpen() unsupported usOpenOpt = %lx\n", usOpenOpt));
+ }
+#endif
+ return(ERROR_ACCESS_DENIED);
+ }
+
+ if (pszDevName == NULL || *pszDevName == '\0') {
+ NetNumber = 0L;
+ } else {
+ if (_strnicmp(pszDevName, "NET", 3)) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosOpen: Bad network name: %s\n", pszDevName));
+ }
+#endif
+ return(ERROR_BAD_NETPATH);
+ }
+
+ NetNumber = atol(pszDevName+3);
+ }
+
+ if (NetNumber > 0xffL) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosOpen: Bad network name: %s\n", pszDevName));
+ }
+#endif
+ return(ERROR_BAD_NETPATH);
+ }
+
+ Status = Od2ActivateLana(
+ NetNumber,
+ &LanaIndex);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosOpen() Od2ActivateLana failed, Status = %lx\n", Status));
+ }
+#endif
+ return(NERR_NetNotStarted);
+ }
+
+ if (LanaIndex == (ULONG) -1) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosOpen: Bad network name: %s\n", pszDevName));
+ }
+#endif
+ return(ERROR_BAD_NETPATH);
+ }
+
+ if (NetNumber != 0) {
+ *phDevName = (USHORT) NetNumber;
+ } else {
+ if (Od2LanaEnum.length >= DEFAULT_NET) {
+ *phDevName = (USHORT) DEFAULT_NET;
+ } else {
+ *phDevName = (USHORT) 1;
+ }
+ }
+
+ return(NERR_Success);
+}
+
+
+// Old lanman NetBiosSubmit. Generally depends on the newer Netbios 3.0 (Net16bios)
+// however, this implements the following differences:
+//
+// - on async requests, a semaphore is cleared instead of calling a post routine
+// - implements the possiblity of NCB chaining which is unavailable with Net16bios
+// - does an automatic open of the default lana if necessary
+//
+
+APIRET
+Net16BiosSubmit(
+ IN ULONG hDevName,
+ IN ULONG NcbOpt,
+ IN OUT PVOID pNCB
+ )
+{
+ PNCB pNcb;
+ PCHAR OrigSegBase;
+ NTSTATUS Status;
+ ULONG LanaIndex;
+ BOOLEAN FirstRound;
+ BOOLEAN CancelChain;
+ USHORT Link;
+ UCHAR OrigLanaNum;
+ UCHAR SynchCommand;
+ UCHAR Asynch;
+ UCHAR rc;
+
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosSubmit() called\n"));
+ }
+#endif
+
+ if (NcbOpt > 3) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosSubmit called with an invalid NcbOpt = %lu\n", NcbOpt));
+ }
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ if (hDevName > 0xffL) {
+
+ LanaIndex = (ULONG)-1;
+
+ } else if (hDevName == 0L) { // use default net?
+
+ //
+ // do a default open of device handle 0
+ //
+
+ Status = Od2ActivateLana(
+ hDevName,
+ &LanaIndex);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosSubmit: Od2ActivateLana failed, Status= %lx\n", Status));
+ }
+#endif
+ return(NERR_NetNotStarted);
+ }
+
+ } else {
+
+ //
+ // Initialize, and check if the handle is open
+ //
+
+ Status = Od2ActivateLana(
+ (ULONG) -1,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosSubmit: Od2ActivateLana failed, Status= %lx\n", Status));
+ }
+#endif
+ return(NERR_NetNotStarted);
+ }
+
+ LanaIndex = Od2NetNumberToLanaIndex(hDevName);
+
+ if (LanaIndex != (ULONG) -1) {
+
+ if (!(Od2LanaState[LanaIndex] & 0x1)) { // lana closed?
+ LanaIndex = (ULONG) -1;
+ }
+ }
+
+ }
+
+ if (LanaIndex == (ULONG) -1) {
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosSubmit: Bad handle, hDevName = %lu\n", hDevName));
+ }
+#endif
+ return(ERROR_INVALID_HANDLE);
+ }
+
+ //
+ // NcbOpt == 1 implies that we should retry the NCB on some types of errors.
+ // Since the LanMan programmer's reference does not document which errors cause a
+ // retry, we shall not retry anything for the present
+ //
+
+ for (FirstRound = TRUE, CancelChain = FALSE; ; FirstRound = FALSE) {
+
+ if (NcbOpt > 1) {
+
+ if (FirstRound) {
+ OrigSegBase = SELTOFLAT(FLATTOSEL(pNCB));
+ }
+
+ try {
+ Link = *(PUSHORT)pNCB;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (Link == 0xffff) {
+ if (FirstRound) {
+ return(NERR_Success);
+ } else {
+ break;
+ }
+ }
+
+ pNcb = (PNCB)((PCHAR)pNCB+sizeof(USHORT));
+ pNCB = (PVOID)(OrigSegBase + Link);
+
+ try {
+ Od2ProbeForWrite(pNcb, sizeof(NCB), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (CancelChain) {
+ pNcb->ncb_retcode = NRC_CMDCAN;
+ pNcb->ncb_cmd_cplt = NRC_CMDCAN;
+ continue;
+ }
+ } else {
+ if (FirstRound) {
+ pNcb = (PNCB) pNCB;
+
+ try {
+ Od2ProbeForWrite(pNcb, sizeof(NCB), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ }
+ }
+
+ pNcb->ncb_retcode = NRC_PENDING;
+ pNcb->ncb_cmd_cplt = NRC_PENDING;
+
+ SynchCommand = pNcb->ncb_command & ~ASYNCH;
+ Asynch = pNcb->ncb_command & ASYNCH;
+
+ //
+ // If it is a netbios 2 reset - disallow, since we only allow open for NB_REGULAR.
+ //
+
+ if (SynchCommand == NCBRESET) {
+ pNcb->ncb_retcode = NRC_ILLCMD;
+ pNcb->ncb_cmd_cplt = NRC_ILLCMD;
+ rc = NRC_ILLCMD;
+ goto ErrorHandling;
+ }
+
+ if (Asynch) {
+
+ LONG Count;
+
+ Count = InterlockedDecrement(&Od2MaxAsynchNcbs);
+
+ if (Count < 0) {
+
+ (VOID) InterlockedIncrement(&Od2MaxAsynchNcbs);
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosSubmit: max asynch ncb count exceeded\n"));
+ }
+#endif
+ pNcb->ncb_retcode = NRC_NORES;
+ pNcb->ncb_cmd_cplt = NRC_NORES;
+ rc = NRC_NORES;
+ goto ErrorHandling;
+
+ }
+ }
+
+ //
+ // switch lananum to represent the "device driver"
+ // originally this was done only if the lananum is 0,
+ // but it is now done always
+ //
+
+ OrigLanaNum = pNcb->ncb_lana_num;
+ pNcb->ncb_lana_num = Od2LanaEnum.lana[LanaIndex];
+
+ //
+ // mark this as a netbios 2 ncb for special processing
+ //
+
+ *(PULONG)&pNcb->ncb_reserve[4] = NETBIOS2_SEMANTICS_SIGNATURE;
+
+ Net16bios(pNcb);
+
+ rc = pNcb->ncb_retcode;
+ pNcb->ncb_lana_num = OrigLanaNum;
+
+ErrorHandling:
+
+ if (NcbOpt == 0) {
+ break;
+ } else if (NcbOpt == 1) {
+
+ // for implementing error-retry on a single NCB, check the error code here
+ // and if it should be retried simply "continue" instead of "break"
+ break;
+
+ } else if (NcbOpt == 3) { // stop on error
+ CancelChain = TRUE;
+ }
+
+ // if proceed-on-error, continue the loop
+ }
+
+ switch (rc) {
+ case NRC_GOODRET:
+ case NRC_PENDING:
+ return(NERR_Success);
+
+ default:
+#if DBG
+ IF_OD2_DEBUG( NET ) {
+ KdPrint(("NetBiosSubmit: Final return code = %x\n", (ULONG)rc));
+ }
+#endif
+ return((APIRET)rc | 0x100);
+ }
+}
+
+APIRET
+DosINetTransaction(
+ IN LPSTR ServerName,
+ IN LPBYTE SendParmBuffer,
+ IN DWORD SendParmBufLen,
+ IN LPBYTE SendDataBuffer,
+ IN DWORD SendDataBufLen,
+ OUT LPBYTE ReceiveParmBuffer,
+ IN DWORD ReceiveParmBufLen,
+ IN LPBYTE ReceiveDataBuffer,
+ IN OUT LPDWORD ReceiveDataBufLen,
+ IN BOOL NullSessionFlag
+ )
+
+/*++
+
+Routine Description:
+
+ Sends a transaction request to a server and receives a response
+
+Arguments:
+
+ ServerName - to send request to
+ SendParmBuffer - send parameters
+ SendParmBufLen - length of send parameters
+ SendDataBuffer - send data
+ SendDataBufLen - length of send data
+ ReceiveParmBuffer - receive parameter buffer
+ ReceiveParmBufLen - length of receive parameter buffer
+ ReceiveDataBuffer - where to receive data
+ ReceiveDataBufLen - length of data buffer
+ NullSessionFlag - set if we are to use a null session
+
+Return Value:
+
+ APIRET
+ Success - NERR_Success
+ Failure -
+
+--*/
+
+{
+ APIRET status;
+
+ status = RxpTransactSmb((USHORT *)ServerName,
+
+ //
+ // BUGBUG - transport name?
+ //
+
+ (LPTSTR)NULL,
+ SendParmBuffer,
+ SendParmBufLen,
+ SendDataBuffer,
+ SendDataBufLen,
+ ReceiveParmBuffer,
+ ReceiveParmBufLen,
+ ReceiveDataBuffer,
+ ReceiveDataBufLen,
+ NullSessionFlag
+ );
+
+ return status;
+}
+
+
+APIRET
+DosIRemoteApi(
+ IN DWORD ApiNumber,
+ IN LPSTR ServerNamePointer,
+ IN LPSTR ParameterDescriptor,
+ IN LPSTR DataDescriptor,
+ IN LPSTR AuxDescriptor,
+ IN ULONG NullSessionFlag
+ )
+{
+ APIRET rc;
+
+#if DBG
+ USHORT tid, pid;
+
+ IF_OD2_DEBUG ( APIS ) {
+ pid = (USHORT)(Od2Process->Pib.ProcessId);
+ tid = (USHORT)(Od2CurrentThreadId());
+
+ if ((Os2DebugTID == 0) || (Os2DebugTID == tid))
+ {
+ KdPrint(("[PID %d: TID %d] %s\n",
+ pid, tid, Os2NetAPIName[ApiNumber]));
+ }
+ }
+#endif
+
+ rc = VrRemoteApi(
+ ApiNumber,
+ ServerNamePointer,
+ ParameterDescriptor,
+ DataDescriptor,
+ AuxDescriptor,
+ (UCHAR)NullSessionFlag
+ );
+ return rc;
+}
+
+APIRET
+ VrEncryptSES(
+ IN LPSTR ServerNamePointer,
+ IN LPSTR passwordPointer, // Input password (Not encripted)
+ IN LPSTR encryptedLmOwfPassword // output password (encripted)
+ );
+
+APIRET
+DosIEncryptSES(
+ IN LPSTR ServerNamePointer,
+ IN LPSTR passwordPointer, // Input password (Not encripted)
+ IN LPSTR encryptedLmOwfPassword // output password (encripted)
+ )
+{
+ APIRET rc;
+
+ rc = VrEncryptSES(ServerNamePointer, passwordPointer,
+ encryptedLmOwfPassword);
+ return(rc);
+}
+
+APIRET
+NetIWkstaGetUserInfo (LPBYTE UserName, LPBYTE LogonServer,
+ LPBYTE LogonDomain, LPBYTE OtherDomains, LPBYTE WsName)
+{
+ //TCHAR Server[UNCLEN];
+ LPBYTE BufPtr;
+ NET_API_STATUS rc;
+ PWKSTA_USER_INFO_1 pInfo1;
+ PWKSTA_INFO_100 pInfo2;
+
+ rc = NetWkstaUserGetInfo(NULL, 1L, &BufPtr);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ pInfo1 = (PWKSTA_USER_INFO_1) BufPtr;
+
+ UT2ANSIstrcpy(UserName, pInfo1->wkui1_username);
+
+ strcpy(LogonServer, "\\\\");
+ UT2ANSIstrcpy(LogonServer + 2, pInfo1->wkui1_logon_server);
+
+ UT2ANSIstrcpy(LogonDomain, pInfo1->wkui1_logon_domain);
+
+ UT2ANSIstrcpy(OtherDomains, pInfo1->wkui1_oth_domains);
+
+ NetApiBufferFree(BufPtr);
+
+ rc = NetWkstaGetInfo(0L, 100L, &BufPtr);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ pInfo2 = (PWKSTA_INFO_100) BufPtr;
+
+ UT2ANSIstrcpy(WsName, pInfo2->wki100_computername);
+
+ NetApiBufferFree(BufPtr);
+
+ return NO_ERROR;
+
+}
diff --git a/private/os2/client/dllnls.c b/private/os2/client/dllnls.c
new file mode 100644
index 000000000..884342fac
--- /dev/null
+++ b/private/os2/client/dllnls.c
@@ -0,0 +1,1116 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllnls.c
+
+Abstract:
+
+ This module implements the NLS OS/2 V2.0 API Calls
+
+Author:
+
+ Steve Wood (stevewo) 20-Sep-1989 (Adapted from URTL\alloc.c)
+
+Revision History:
+
+ 3/31/93 - MJarus - Moved the NLS string function for the OS2SS to ssrtl
+
+--*/
+
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_NLS
+#include "os2dll.h"
+#include "conrqust.h"
+#include "os2nls.h"
+#include "os2win.h"
+
+ULONG Or2ProcessCodePage;
+ULONG Or2CurrentCodePageIsOem;
+
+extern OD2_COUNTRY_ENTRY OD2_COUNTRY_TABLE[];
+extern OD2_CODEPAGE_ENTRY OD2_CODEPAGE_TABLE[];
+extern OD2_DBCS_VECTOR_ENTRY OD2_DBCS_VECTOR_TABLE[];
+extern OD2_COLLATE_CTRY_ENTRY OD2_COLLATE_CTRY_TABLE[];
+extern PUCHAR OD2_CASEMAP_TABLE[];
+extern PUCHAR OD2_COLLATE_CP_TABLE[];
+extern PUCHAR OD2_FIX_CASEMAP_TABLE[];
+extern UCHAR Od2BaseCaseMapTable[];
+extern UCHAR Od2BaseCollateTable[];
+
+
+
+APIRET
+DosQueryCtryInfo(
+ IN ULONG MaxCountryInfoLength,
+ IN PCOUNTRYCODE CountryCode,
+ OUT PCOUNTRYINFO CountryInfo,
+ OUT PULONG ActualCountryInfoLength
+ )
+{
+ COUNTRYINFO DefaultInformation;
+ APIRET RetCode;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosQueryCtryInfo";
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: Country %lu, CP %lu, (current Ctry %lu, CP %lu), Length %lu\n",
+ FuncName, CountryCode->country, CountryCode->codepage,
+ SesGrp->CountryCode, SesGrp->DosCP, MaxCountryInfoLength ));
+ }
+#endif
+
+ //
+ // zero buffer. probe parms.
+ //
+
+ try
+ {
+ RtlZeroMemory( (PVOID)CountryInfo, MaxCountryInfoLength );
+ Od2ProbeForRead (CountryCode, sizeof(COUNTRYCODE),1);
+ *ActualCountryInfoLength = 0;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = Od2GetCtryInfo(
+ CountryCode->country,
+ CountryCode->codepage,
+ &DefaultInformation
+ );
+
+ if ( !CountryCode->country && CountryCode->codepage)
+ {
+ CountryCode->country = SesGrp->CountryCode;
+ }
+
+ if ( RetCode )
+ {
+ return (RetCode);
+ }
+
+ if (MaxCountryInfoLength < sizeof( COUNTRYINFO ))
+ {
+#if DBG
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: Table trunc (%lu instead of %lu)\n",
+ FuncName, MaxCountryInfoLength, sizeof( COUNTRYINFO )));
+ }
+#endif
+ *ActualCountryInfoLength = MaxCountryInfoLength;
+ RetCode = ERROR_NLS_TABLE_TRUNCATED;
+ } else
+ {
+ *ActualCountryInfoLength = sizeof( COUNTRYINFO );
+ }
+
+ RtlMoveMemory( (PVOID)CountryInfo,
+ (PVOID)&DefaultInformation,
+ *ActualCountryInfoLength
+ );
+ return (RetCode);
+}
+
+
+APIRET
+DosQueryDBCSEnv(
+ IN ULONG MaxDBCSEvLength,
+ IN PCOUNTRYCODE CountryCode,
+ OUT PCHAR DBCSEv
+ )
+{
+ CHAR LocalDBCSEv[12];
+ APIRET RetCode;
+ ULONG BufLength;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosQueryDBCSEnv";
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: Country %lu, CP %lu, (current Ctry %lu, CP %lu), Length %lu\n",
+ FuncName, CountryCode->country, CountryCode->codepage,
+ SesGrp->CountryCode, SesGrp->DosCP, MaxDBCSEvLength ));
+ }
+#endif
+
+ //
+ // zero buffer. probe parms.
+ //
+
+ try
+ {
+ Od2ProbeForRead( CountryCode, sizeof(COUNTRYCODE), 1 );
+ RtlZeroMemory( (PVOID)DBCSEv, MaxDBCSEvLength );
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = Od2GetDBCSEv(
+ CountryCode->country,
+ CountryCode->codepage,
+ &LocalDBCSEv[0],
+ &BufLength
+ );
+
+ if ( !CountryCode->country && CountryCode->codepage)
+ {
+ CountryCode->country = SesGrp->CountryCode;
+ }
+
+ if ( RetCode )
+ {
+ return (RetCode);
+ }
+
+ if ( MaxDBCSEvLength < BufLength )
+ {
+#if DBG
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: Table trunc (%lu instead of %lu)\n",
+ FuncName, MaxDBCSEvLength, BufLength));
+ }
+#endif
+ BufLength = MaxDBCSEvLength;
+ RetCode = ERROR_NLS_TABLE_TRUNCATED;
+ }
+
+ RtlMoveMemory( (PVOID)DBCSEv,
+ (PVOID)LocalDBCSEv,
+ BufLength
+ );
+ return (RetCode);
+}
+
+
+APIRET
+DosMapCase(
+ IN ULONG StringLength,
+ IN PCOUNTRYCODE CountryCode,
+ IN OUT PUCHAR String
+ )
+{
+ UCHAR CaseMapTable[256];
+ ULONG CharNum;
+ APIRET RetCode;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosMapCase";
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: Country %lu, CP %lu, (current Ctry %lu, CP %lu), Length %lu, String %c...\n",
+ FuncName, CountryCode->country, CountryCode->codepage,
+ SesGrp->CountryCode, SesGrp->DosCP, StringLength, *String ));
+ }
+#endif
+
+ //
+ // probe parms.
+ //
+
+ try
+ {
+ Od2ProbeForRead (CountryCode, sizeof(COUNTRYCODE), 1);
+ Od2ProbeForWrite (String, StringLength, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = Od2GetCaseMapTable(
+ CountryCode->country,
+ CountryCode->codepage,
+ CaseMapTable);
+
+ if ( !CountryCode->country && CountryCode->codepage)
+ {
+ CountryCode->country = SesGrp->CountryCode;
+ }
+
+ if ( RetCode )
+ {
+ return (RetCode);
+ }
+
+ for ( CharNum = 0 ; CharNum < StringLength ; CharNum++ )
+ {
+#ifdef DBCS
+// MSKK Apr.18.1993 V-AkihiS
+// Support DBCS for DosCaseMap API.
+ if (IsDBCSLeadByte(String[CharNum]))
+ {
+ CharNum++;
+ } else
+ {
+ String[CharNum] = CaseMapTable[String[CharNum]];
+ }
+#else
+ String[CharNum] = CaseMapTable[String[CharNum]];
+#endif
+ }
+ return( NO_ERROR );
+}
+
+
+APIRET
+DosQueryCollate(
+ IN ULONG MaxCollateInfoLength,
+ IN PCOUNTRYCODE CountryCode,
+ OUT PUCHAR CollateInfo,
+ OUT PULONG ActualCollateInfoLength
+ )
+{
+ UCHAR CollateTable[256];
+ APIRET RetCode;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosQueryCollate";
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: Country %lu, CP %lu, (current Ctry %lu, CP %lu), Length %lu\n",
+ FuncName, CountryCode->country, CountryCode->codepage,
+ SesGrp->CountryCode, SesGrp->DosCP, MaxCollateInfoLength ));
+ }
+#endif
+
+ //
+ // probe parms.
+ //
+
+ try
+ {
+ Od2ProbeForRead (CountryCode, sizeof(COUNTRYCODE),1);
+ RtlZeroMemory(CollateInfo, MaxCollateInfoLength);
+ *ActualCollateInfoLength = 0;
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = Od2GetCollateTable(
+ CountryCode->country,
+ CountryCode->codepage,
+ CollateTable);
+
+ if ( !CountryCode->country && CountryCode->codepage)
+ {
+ CountryCode->country = SesGrp->CountryCode;
+ }
+
+ if ( RetCode )
+ {
+ return (RetCode);
+ }
+
+ if ( MaxCollateInfoLength > 256 )
+ {
+ MaxCollateInfoLength = 256;
+ }
+
+ memmove( CollateInfo, CollateTable, MaxCollateInfoLength);
+
+ *ActualCollateInfoLength = MaxCollateInfoLength;
+
+ if ( MaxCollateInfoLength < 256 )
+ {
+ return( ERROR_NLS_TABLE_TRUNCATED );
+ }
+
+ return( NO_ERROR );
+}
+
+
+APIRET
+DosSetProcessCp(
+ IN ULONG ulCodePage,
+ IN ULONG ulReserved
+ )
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosSetProcessCp";
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: CP %lu, Reserved %lu, (current %lu)\n",
+ FuncName, ulCodePage, ulReserved, SesGrp->DosCP));
+ }
+#endif
+
+ if ( ulReserved != 0 )
+ {
+ return (ERROR_INVALID_PARAMETER);
+ }
+
+ //
+ // Validate the CodePage parameter against the list of installed code
+ // pages.
+ //
+
+ if (( ulCodePage == 0 ) ||
+ (( ulCodePage != SesGrp->PrimaryCP ) &&
+ ( ulCodePage != SesGrp->SecondaryCP )))
+ {
+ return (ERROR_INVALID_CODE_PAGE);
+ }
+
+ //
+ // Store the code page in the process structure
+ //
+
+ Od2ProcessCodePage = ulCodePage;
+
+ if (Od2ProcessCodePage != SesGrp->Win32OEMCP)
+ {
+ Od2CurrentCodePageIsOem = FALSE;
+ } else
+ {
+ Od2CurrentCodePageIsOem = TRUE;
+ }
+
+ return( NO_ERROR );
+}
+
+
+APIRET
+DosQueryCp(
+ IN ULONG MaxLengthCodePageList,
+ OUT ULONG CodePages[],
+ OUT PULONG CountCodePages
+ )
+{
+ ULONG Count, TotalCount;
+ APIRET rc = NO_ERROR;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosQueryCp";
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: Length %lu, (current CP %lu)\n",
+ FuncName, MaxLengthCodePageList, SesGrp->DosCP));
+ }
+#endif
+
+ try
+ {
+ Od2ProbeForWrite( CountCodePages, sizeof( USHORT ), 1);
+ Od2ProbeForWrite( CodePages, MaxLengthCodePageList * sizeof( USHORT ), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if ( MaxLengthCodePageList < sizeof(ULONG) )
+ {
+ *CountCodePages = 0;
+ return (ERROR_CPLIST_TOO_SMALL);
+ }
+
+ //
+ // Determine the number of code pages to return. This is at least one
+ // for the code page associated with the current process, plus N for the
+ // N installed code pages.
+ //
+
+ Count = (SesGrp->SecondaryCP) ? 2 : 1;
+
+ //
+ // Determine the maximum number of code pages the caller can accept in
+ // their buffer. This is just the buffer length divided by sizeof( ULONG )
+ //
+
+ TotalCount = MaxLengthCodePageList / sizeof( ULONG ) - 1;
+
+ //
+ // Determine how many we will actually return and setup to return
+ // an error status if the list will be truncated.
+ //
+
+ if (Count > TotalCount)
+ {
+ Count = TotalCount;
+ rc = ERROR_CPLIST_TOO_SMALL;
+ }
+
+ //
+ // Return the actual length of code page information returned in the
+ // caller's buffer.
+ //
+
+ *CountCodePages = (Count + 1) * sizeof( ULONG );
+
+ //
+ // Return the code page for the process always.
+ //
+
+ *CodePages++ = Od2ProcessCodePage;
+
+ //
+ // Return the installed code pages.
+ //
+
+ RtlMoveMemory( CodePages, &SesGrp->PrimaryCP, Count * sizeof(ULONG) );
+
+ //
+ // Return success or error code.
+ //
+
+ return( rc );
+}
+
+
+
+APIRET
+Od2InitNls( IN ULONG CodePage,
+ IN BOOLEAN StartBySM)
+/*++
+
+Routine Description:
+
+ This routine initialize NLS parms
+
+Arguments:
+
+ CodePage - parent proess code-page identifier
+
+ StartBySm - flag indicates if start by SM (new session) or by
+ another process DosExecPgm
+
+Return Value:
+
+
+Note:
+ CodePage is relevamt only if (!StartBySM). Otherwise - codepage
+ is what os2.exe put in SesGrp->DosCp
+
+--*/
+
+{
+ if ( StartBySM )
+ {
+ Od2ProcessCodePage = SesGrp->DosCP;
+ } else
+ {
+ Od2ProcessCodePage = CodePage;
+ }
+
+ if (Od2ProcessCodePage != SesGrp->Win32OEMCP)
+ {
+ Od2CurrentCodePageIsOem = FALSE;
+ } else
+ {
+ Od2CurrentCodePageIsOem = TRUE;
+ }
+#if DBG
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("InitNLS: Code Page %lu (OEM flag %lu, StartBySM %lu, SesGrp->DosCp %lu, Arg CP %lu)\n",
+ Od2ProcessCodePage, Od2CurrentCodePageIsOem, StartBySM, SesGrp->DosCP, CodePage ));
+ }
+#endif
+
+ Od2SystemRoot = &SesGrp->SystemDirectory[0];
+
+ return (NO_ERROR);
+}
+
+
+CHAR Spain437CurrencyStr[] = "\236\0\0\0";
+CHAR Arabic864CurrencyStr[] = "\244\0\0\0";
+
+APIRET
+Od2GetCtryInfo( IN ULONG Country,
+ IN ULONG CodePage,
+ OUT PCOUNTRYINFO CountryInfo)
+/*++
+
+Routine Description:
+
+ This routine fill country info struct after checking the parms
+
+Arguments:
+
+ Country - country code ( 0 - current )
+
+ CodePage - code-page identifier ( 0 - current )
+
+ CountryInfo - where to store COUNTRYINFO
+
+
+Return Value:
+
+ ERROR_NLS_BAD_TYPE - ?
+ ERROR_NLS_NO_CTRY_CODE - ?
+ ERROR_NLS_TYPE_NOT_FOUND - ?
+ ( ERROR_NLS_TABLE_TRUNCATED - by DosGet/QueryCtryInfo )
+
+Note:
+
+--*/
+
+{
+ ULONG CountryIndex, CodePageIndex;
+ PCOUNTRYINFO SrcCountryInfo;
+ APIRET RetCode;
+ BOOLEAN FromOriginalTable = FALSE;
+ APIRET Rc;
+ COUNTRYINFO LocalCountryInfo;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "Od2GetCtryInfo";
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: Country %u, CodePage %u\n",
+ FuncName, Country, CodePage));
+ }
+#endif
+
+ RetCode = Od2GetCtryCp( &Country, &CodePage, &CountryIndex, &CodePageIndex );
+
+ if ((Country == SesGrp->CountryCode) &&
+ ((CodePage == SesGrp->PrimaryCP) || (CodePage == SesGrp->SecondaryCP)))
+ {
+ SrcCountryInfo = &SesGrp->CountryInfo;
+ } else if (RetCode)
+ {
+ Rc = Ow2NlsGetCtryInfo(
+ CodePage,
+ Country,
+ &LocalCountryInfo
+ );
+ if ( Rc )
+ {
+#if DBG
+ IF_OD2_DEBUG( NLS )
+ {
+ KdPrint(("%s: RetCode from LPC %lu\n", FuncName, Rc));
+ }
+#endif
+ return( RetCode );
+ }
+ SrcCountryInfo = &LocalCountryInfo;
+ } else
+ {
+ SrcCountryInfo = OD2_COUNTRY_TABLE[CountryIndex].pCtryInfo;
+ FromOriginalTable = TRUE;
+ }
+
+ RtlMoveMemory(CountryInfo,
+ SrcCountryInfo,
+ sizeof(COUNTRYINFO));
+
+ CountryInfo->codepage = CodePage;
+ CountryInfo->country = Country;
+
+ if (FromOriginalTable)
+ {
+ if ((Country == COUNTRY_SPAIN) &&
+ (CodePage == CODEPAGE_US))
+ {
+ RtlMoveMemory(CountryInfo->szCurrency,
+ Spain437CurrencyStr,
+ 5);
+ } else if ((Country == COUNTRY_ARABIC) &&
+ (CodePage == CODEPAGE_ARABIC))
+ {
+ RtlMoveMemory(CountryInfo->szCurrency,
+ Arabic864CurrencyStr,
+ 5);
+ }
+ }
+
+ return (NO_ERROR);
+}
+
+
+APIRET
+Od2GetDBCSEv( IN ULONG Country,
+ IN ULONG CodePage,
+ IN OUT PUCHAR DBCSEv,
+ OUT PULONG StringLength)
+/*++
+
+Routine Description:
+
+ This routine fill DBCS environment vector after checking the parms
+
+Arguments:
+
+ Country - country code ( 0 - current )
+
+ CodePage - code-page identifier ( 0 - current )
+
+ DBVSEv - where to store the vector
+
+ StringLength - where to retutn the actual length of the output vector
+
+
+Return Value:
+
+ ERROR_NLS_BAD_TYPE - ?
+ ERROR_NLS_NO_CTRY_CODE - ?
+ ERROR_NLS_TYPE_NOT_FOUND - ?
+ ( ERROR_NLS_NO_COUNTRY_FILE - we don't keep info in file )
+ ( ERROR_NLS_OPEN_FAILED - we don't keep info in file )
+ ( ERROR_NLS_TABLE_TRUNCATED - by DosGet/QueryDBCSEv )
+
+Note:
+
+--*/
+
+{
+ ULONG CountryIndex, CodePageIndex;
+ APIRET RetCode;
+ POD2_DBCS_VECTOR_ENTRY SrcDBCSVec;
+ OD2_DBCS_VECTOR_ENTRY LocalDBCSVec;
+ APIRET Rc;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "Od2GetDBCSEv";
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: Country %u, CodePage %u\n",
+ FuncName, Country, CodePage));
+ }
+#endif
+ RetCode = Od2GetCtryCp( &Country, &CodePage, &CountryIndex, &CodePageIndex );
+
+ if (((CodePage == SesGrp->PrimaryCP) || (CodePage == SesGrp->SecondaryCP)) &&
+ ((Country == SesGrp->CountryCode) || !RetCode))
+ {
+ if(CodePage == SesGrp->PrimaryCP)
+ {
+ SrcDBCSVec = &SesGrp->PriDBCSVec;
+ } else
+ {
+ SrcDBCSVec = &SesGrp->SecDBCSVec;
+ }
+ } else if (RetCode)
+ {
+#ifdef JAPAN
+// MSKK Jul.02.1993 V-AkihiS
+// Chechk country code, because Ow2NlsGetDBCSEn does not check country code.
+ if (Country != SesGrp->CountryCode)
+ {
+ return( RetCode );
+ }
+#endif
+ Rc = Ow2NlsGetDBCSEn(
+ CodePage,
+ &LocalDBCSVec
+ );
+ if ( Rc )
+ {
+#if DBG
+ IF_OD2_DEBUG( NLS )
+ {
+ KdPrint(("%s: RetCode from LPC %lu\n", FuncName, Rc));
+ }
+#endif
+ return( RetCode );
+ }
+ SrcDBCSVec = &LocalDBCSVec;
+ } else
+ {
+ SrcDBCSVec = &OD2_DBCS_VECTOR_TABLE[OD2_CODEPAGE_TABLE[CodePageIndex].DBCSVecIndex];
+ }
+
+ *StringLength = SrcDBCSVec->VectorSize;
+
+ RtlMoveMemory(DBCSEv,
+ SrcDBCSVec->Vector,
+ *StringLength);
+
+ return (NO_ERROR);
+}
+
+
+APIRET
+Od2GetCaseMapTable(
+ IN ULONG Country,
+ IN ULONG CodePage,
+ OUT PUCHAR CaseMapTable)
+/*++
+
+Routine Description:
+
+ This routine fill creates a case map table for the CP after
+ checking the parms
+
+Arguments:
+
+ Country - country code ( 0 - current )
+
+ CodePage - code-page identifier ( 0 - current )
+
+ CaseMapTable - where to store the case map table
+
+
+Return Value:
+
+ ERROR_NLS_BAD_TYPE - ?
+ ERROR_NLS_NO_CTRY_CODE - ?
+ ERROR_NLS_TYPE_NOT_FOUND - ?
+ ( ERROR_NLS_NO_COUNTRY_FILE - we don't keep info in file )
+ ( ERROR_NLS_OPEN_FAILED - we don't keep info in file )
+ ( ERROR_NLS_TABLE_TRUNCATED - by DosGet/QueryDBCSEv )
+
+Note:
+
+--*/
+
+{
+ ULONG CountryIndex, i, CodePageIndex;
+ PUCHAR SrcTable, CPFixTable = NULL, CtryFixTable = NULL;
+ APIRET RetCode;
+ UCHAR LocalTable[256];
+ APIRET Rc;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "Od2GetCaseMapTable";
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: Country %u, CodePage %u\n",
+ FuncName, Country, CodePage));
+ }
+#endif
+ RetCode = Od2GetCtryCp( &Country, &CodePage, &CountryIndex, &CodePageIndex );
+
+ if ((Country == SesGrp->CountryCode) &&
+ ((CodePage == SesGrp->PrimaryCP) || (CodePage == SesGrp->SecondaryCP)))
+ {
+ if(CodePage == SesGrp->PrimaryCP)
+ {
+ SrcTable = SesGrp->PriCaseMapTable;
+ } else
+ {
+ SrcTable = SesGrp->SecCaseMapTable;
+ }
+ } else
+ if (RetCode)
+ {
+ Rc = Ow2NlsGetCaseMapTable(
+ CodePage,
+ Country,
+ &LocalTable[0]
+ );
+ if ( Rc )
+ {
+#if DBG
+ IF_OD2_DEBUG( NLS )
+ {
+ KdPrint(("%s: RetCode from LPC %lu\n", FuncName, Rc));
+ }
+#endif
+ return( RetCode );
+ }
+ SrcTable = &LocalTable[0];
+ } else
+ {
+ SrcTable = Od2BaseCaseMapTable;
+ CPFixTable = OD2_CASEMAP_TABLE[OD2_CODEPAGE_TABLE[CodePageIndex].CaseMapIndex];
+ if (CodePage == 437)
+ {
+ CtryFixTable = OD2_FIX_CASEMAP_TABLE[OD2_COUNTRY_TABLE[CountryIndex].CaseMapFixTableIndex];
+ }
+ }
+
+ RtlMoveMemory(CaseMapTable,
+ SrcTable,
+ 256);
+
+ if (CPFixTable)
+ {
+ for ( i = 0 ; (CPFixTable[i] || CPFixTable[i + 1]) ; i += 2 )
+ {
+ CaseMapTable[CPFixTable[i]] = CPFixTable[i + 1];
+ }
+ }
+
+ if (CtryFixTable)
+ {
+ for ( i = 0 ; (CtryFixTable[i] || CtryFixTable[i + 1]) ; i += 2 )
+ {
+ CaseMapTable[CtryFixTable[i]] = CtryFixTable[i + 1];
+ }
+ }
+
+ return (NO_ERROR);
+}
+
+
+APIRET
+Od2GetCollateTable(
+ IN ULONG Country,
+ IN ULONG CodePage,
+ OUT PUCHAR CollateTable)
+/*++
+
+Routine Description:
+
+ This routine fill creates a Collate table for the CP after
+ checking the parms
+
+Arguments:
+
+ Country - country code ( 0 - current )
+
+ CodePage - code-page identifier ( 0 - current )
+
+ CollateTable - where to store the Collate table
+
+
+Return Value:
+
+ ERROR_NLS_BAD_TYPE - ?
+ ERROR_NLS_NO_CTRY_CODE - ?
+ ERROR_NLS_TYPE_NOT_FOUND - ?
+ ( ERROR_NLS_NO_COUNTRY_FILE - we don't keep info in file )
+ ( ERROR_NLS_OPEN_FAILED - we don't keep info in file )
+ ( ERROR_NLS_TABLE_TRUNCATED - by DosGet/QueryDBCSEv )
+
+Note:
+
+--*/
+
+{
+ ULONG CountryIndex, i, CodePageIndex;
+ PUCHAR SrcTable, CPFixTable = NULL, CtryFixTable = NULL;
+ APIRET RetCode;
+// UCHAR LocalTable[256];
+#if DBG
+ APIRET Rc=0;
+ PSZ FuncName;
+
+ FuncName = "Od2GetCollateTable";
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: Country %u, CodePage %u\n",
+ FuncName, Country, CodePage));
+ }
+#endif // DBG
+ RetCode = Od2GetCtryCp( &Country, &CodePage, &CountryIndex, &CodePageIndex );
+
+// if ((Country == SesGrp->CountryCode) &&
+// ((CodePage == SesGrp->PrimaryCP) || (CodePage == SesGrp->SecondaryCP)))
+// {
+// if(CodePage == SesGrp->PrimaryCP)
+// {
+// SrcTable = SesGrp->PriCollateTable;
+// } else
+// {
+// SrcTable = SesGrp->SecCollateTable;
+// }
+// } else
+ if (RetCode)
+ {
+// Rc = Ow2NlsGetCollateTable(
+// CodePage,
+// Country,
+// &LocalTable[0]
+// );
+// if ( Rc )
+// {
+#if DBG
+
+ // BUGBUG: debug statement below prints random Rc value
+ IF_OD2_DEBUG( NLS )
+ {
+ KdPrint(("%s: RetCode from LPC %lu\n", FuncName, Rc));
+ }
+#endif
+ return( RetCode );
+// }
+// SrcTable = &LocalTable[0];
+ } else
+ {
+ SrcTable = Od2BaseCollateTable;
+ CPFixTable = OD2_COLLATE_CP_TABLE[OD2_CODEPAGE_TABLE[CodePageIndex].CollateIndex];
+
+ for ( i = 0 ; OD2_COLLATE_CTRY_TABLE[i].Country ; i++ )
+ {
+ if ((OD2_COLLATE_CTRY_TABLE[i].Country == Country) &&
+ (OD2_COLLATE_CTRY_TABLE[i].CodePage == CodePage))
+ {
+ CtryFixTable = OD2_COLLATE_CTRY_TABLE[i].FixTable;
+ break;
+ }
+ }
+ }
+
+ RtlMoveMemory(CollateTable,
+ SrcTable,
+ 256);
+
+ if (CPFixTable)
+ {
+ for ( i = 0 ; (CPFixTable[i] || CPFixTable[i + 1]) ; i += 2 )
+ {
+ CollateTable[CPFixTable[i]] = CPFixTable[i + 1];
+ }
+ }
+
+ if (CtryFixTable)
+ {
+ for ( i = 0 ; (CtryFixTable[i] || CtryFixTable[i + 1]) ; i += 2 )
+ {
+ CollateTable[CtryFixTable[i]] = CtryFixTable[i + 1];
+ }
+ }
+
+ return (NO_ERROR);
+}
+
+
+APIRET
+Od2GetCtryCp( IN OUT PULONG Country,
+ IN OUT PULONG CodePage,
+ OUT PULONG CountryTableIndex,
+ OUT PULONG CodePageTableIndex)
+/*++
+
+Routine Description:
+
+ This routine checks the country and code-page parms.
+ If zero (default) it set them properly.
+ If exist in table, return index.
+
+Arguments:
+
+ Country - where to read from and update the country code ( 0 - current )
+
+ CodePage - where to read from and update the code-page identifier ( 0 - current )
+
+ CountryTableIndex - where to store the index for the language
+
+ CodePageTableIndex - where to store the index for the code page
+
+Return Value:
+
+ ERROR_NLS_BAD_TYPE - ?
+ ERROR_NLS_NO_CTRY_CODE - illegal country code or illegal code page
+ ERROR_NLS_TYPE_NOT_FOUND - ?
+ ( ERROR_NLS_NO_COUNTRY_FILE - we don't keep info in file )
+ ( ERROR_NLS_OPEN_FAILED - we don't keep info in file )
+ ( ERROR_NLS_TABLE_TRUNCATED - by DosGet/QueryCtryInfo )
+
+Note:
+
+--*/
+
+{
+ ULONG CountryIndex;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "Od2GetCtryCp";
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: enter\n", FuncName));
+ }
+#endif
+
+ if ( !*Country )
+ {
+ *Country = SesGrp->CountryCode;
+#if DBG
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: country set to current %lu\n",
+ FuncName, SesGrp->CountryCode));
+ }
+#endif
+ }
+
+ if ( !*CodePage )
+ {
+ *CodePage = Od2ProcessCodePage;
+#if DBG
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: code page set to current %lu\n",
+ FuncName, Od2ProcessCodePage));
+ }
+#endif
+ }
+
+ for ( CountryIndex = 0 ; ( OD2_COUNTRY_TABLE[CountryIndex].Country &&
+ ( OD2_COUNTRY_TABLE[CountryIndex].Country != *Country )) ;
+ CountryIndex++ );
+
+ if ( !OD2_COUNTRY_TABLE[CountryIndex].Country )
+ {
+#if DBG
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: no such country %lu\n",
+ FuncName, *Country));
+ }
+#endif
+ return (ERROR_NLS_NO_CTRY_CODE);
+ }
+
+ if ( *CodePage == OD2_CODEPAGE_TABLE[OD2_COUNTRY_TABLE[CountryIndex].CodePageIndex1].CodePage )
+ {
+ *CodePageTableIndex = OD2_COUNTRY_TABLE[CountryIndex].CodePageIndex1;
+ } else if ( *CodePage == OD2_CODEPAGE_TABLE[OD2_COUNTRY_TABLE[CountryIndex].CodePageIndex2].CodePage )
+ {
+ *CodePageTableIndex = OD2_COUNTRY_TABLE[CountryIndex].CodePageIndex2;
+#ifdef DBCS
+// MSKK Apr.19.1993 V-AkihiS
+// Support CodePage 850(CODEPAGE_MULTI)
+ } else if ( *CodePage == CODEPAGE_MULTI )
+ {
+ *CodePageTableIndex = INDEX_CODEPAGE_MULTI;
+#endif
+ } else
+ {
+#if DBG
+ IF_OD2_DEBUG(NLS)
+ {
+ KdPrint(("%s: no such code page %lu\n",
+ FuncName, *CodePage));
+ }
+#endif
+ return (ERROR_NLS_NO_CTRY_CODE);
+ }
+
+ /* In DBCS countries, when CP == US then info is according to USA. */
+
+ if ((( *Country == COUNTRY_JAPAN ) ||
+ ( *Country == COUNTRY_TAIWAN ) ||
+ ( *Country == COUNTRY_PRCHINA ) ||
+ ( *Country == COUNTRY_SOUTH_KOREA )) &&
+#ifdef DBCS
+// MSKK Apr.24.1993
+// Support CodePage 850(CODEPAGE_MULTI)
+ (( *CodePage == CODEPAGE_US ) || ( *CodePage == CODEPAGE_MULTI)))
+#else
+ ( *CodePage == CODEPAGE_US ))
+#endif
+ {
+ CountryIndex = 0; // US must be first in OD2_COUNTRY_TABLE
+ }
+
+ *CountryTableIndex = CountryIndex;
+
+ return (NO_ERROR);
+}
diff --git a/private/os2/client/dllnls16.c b/private/os2/client/dllnls16.c
new file mode 100644
index 000000000..0650fe3f6
--- /dev/null
+++ b/private/os2/client/dllnls16.c
@@ -0,0 +1,417 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllnls16.c
+
+Abstract:
+
+ This module implements 32 equivalents of NLS OS/2 V1.21
+ API Calls and 16b implementation service routines.
+ The APIs are called from 16->32 thunks (i386\doscalls.asm).
+
+Author:
+
+ Michael Jarus (mjarus) 15-Apr-1992
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_NLS
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "conrqust.h"
+#include "os2nls.h"
+
+
+
+APIRET
+DosSetCp(
+ IN ULONG ulCodePage,
+ IN ULONG ulReserved
+ )
+{
+ APIRET rc;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosSetCp";
+ IF_OD2_DEBUG(NLS)
+ {
+ DbgPrint("%s: CP %lu, Reserved %lu, (current %lu)\n",
+ FuncName, ulCodePage, ulReserved, SesGrp->DosCP);
+ }
+#endif
+
+ if ( rc = DosSetProcessCp(ulCodePage, ulReserved) )
+ {
+ return (rc);
+ }
+
+ if ( rc = VioSetCp(0, ulCodePage, 0) )
+ {
+ return (rc);
+ }
+
+ if( rc = KbdSetCp(0, ulCodePage, 0))
+ {
+ return (rc);
+ }
+
+ rc = KbdFlushBuffer(0);
+ return (rc);
+}
+
+
+APIRET
+DosSetProcCp(
+ IN ULONG ulCodePage,
+ IN ULONG ulReserved
+ )
+{
+ APIRET rc;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosSetProcCp";
+ IF_OD2_DEBUG(NLS)
+ {
+ DbgPrint("%s: CP %lu, Reserved %lu, (current %lu)\n",
+ FuncName, ulCodePage, ulReserved, SesGrp->DosCP);
+ }
+#endif
+
+ rc = DosSetProcessCp(ulCodePage, ulReserved);
+ return (rc);
+}
+
+
+APIRET
+DosGetCp(
+ IN ULONG MaxLengthCodePageList,
+ OUT USHORT CodePages[],
+ OUT PUSHORT CountCodePages
+ )
+{
+ ULONG Count, TotalCount, *pUl;
+ APIRET rc = NO_ERROR;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosGetCp";
+ IF_OD2_DEBUG(NLS)
+ {
+ DbgPrint("%s: Length %lu (current CP %lu)\n",
+ FuncName, MaxLengthCodePageList, SesGrp->DosCP);
+ }
+#endif
+
+ try
+ {
+ Od2ProbeForWrite( CountCodePages, sizeof( USHORT ), 1);
+ Od2ProbeForWrite( CodePages, MaxLengthCodePageList * sizeof( USHORT ), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if ( MaxLengthCodePageList < sizeof(USHORT) )
+ {
+ *CountCodePages = 0;
+ return (ERROR_CPLIST_TOO_SMALL);
+ }
+
+ //
+ // Determine the number of code pages to return. This is at least one
+ // for the code page associated with the current process, plus N for the
+ // N installed code pages.
+ //
+
+ Count = (SesGrp->SecondaryCP) ? 2 : 1;
+
+ //
+ // Determine the maximum number of code pages the caller can accept in
+ // their buffer. This is just the buffer length divided by sizeof( USHORT )
+ //
+
+ TotalCount = MaxLengthCodePageList / sizeof( USHORT ) - 1;
+
+ //
+ // Determine how many we will actually return and setup to return
+ // an error status if the list will be truncated.
+ //
+
+ if (Count > TotalCount)
+ {
+ Count = TotalCount;
+ rc = ERROR_CPLIST_TOO_SMALL;
+ }
+
+ //
+ // Return the actual length of code page information returned in the
+ // caller's buffer.
+ //
+
+ *CountCodePages = (USHORT)((Count + 1) * sizeof( USHORT ));
+
+ //
+ // Return the code page for the process always.
+ //
+
+ *CodePages++ = (USHORT)Od2ProcessCodePage;
+
+ //
+ // Return the installed code pages.
+ //
+
+ pUl = &SesGrp->PrimaryCP;
+
+ while (Count--)
+ {
+ *CodePages++ = (USHORT)*pUl++;
+ }
+
+ //
+ // Return success or error code.
+ //
+
+ return( rc );
+}
+
+
+APIRET
+DosCaseMap(
+ IN ULONG cbLength,
+ IN PCOUNTRYCODE16 CountryCode,
+ IN OUT PUCHAR pchString)
+{
+ COUNTRYCODE ctryc;
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosCaseMap";
+ IF_OD2_DEBUG(NLS)
+ {
+ DbgPrint("%s: Country %u, CP %u, (current Ctry %lu, CP %lu), Length %lu, String %c...\n",
+ FuncName, CountryCode->country, CountryCode->codepage,
+ SesGrp->CountryCode, SesGrp->DosCP, cbLength, *pchString );
+ }
+#endif
+
+ //
+ // probe parms.
+ //
+
+ try
+ {
+ ctryc.country = CountryCode->country;
+ ctryc.codepage = CountryCode->codepage;
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = DosMapCase(cbLength, &ctryc, pchString);
+
+ if ( !CountryCode->country && CountryCode->codepage)
+ {
+ CountryCode->country = (USHORT)SesGrp->CountryCode;
+ }
+
+ return (RetCode);
+}
+
+
+APIRET
+DosGetDBCSEv(
+ IN ULONG cbBuf,
+ IN PCOUNTRYCODE16 CountryCode,
+ IN OUT PCHAR pchString)
+{
+ COUNTRYCODE ctryc;
+ APIRET RetCode;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosGetDBCSEv";
+ IF_OD2_DEBUG(NLS)
+ {
+ DbgPrint("%s: Country %u, CP %u, (current Ctry %lu, CP %lu), Length %lu\n",
+ FuncName, CountryCode->country, CountryCode->codepage,
+ SesGrp->CountryCode, SesGrp->DosCP, cbBuf );
+ }
+#endif
+
+ //
+ // probe parms.
+ //
+
+ try
+ {
+ ctryc.country = CountryCode->country;
+ ctryc.codepage = CountryCode->codepage;
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = DosQueryDBCSEnv(cbBuf, &ctryc, pchString);
+
+ if ( !CountryCode->country && CountryCode->codepage)
+ {
+ CountryCode->country = (USHORT)SesGrp->CountryCode;
+ }
+
+ return (RetCode);
+}
+
+
+APIRET
+DosGetCtryInfo(
+ IN ULONG MaxCountryInfoLength,
+ IN PCOUNTRYCODE16 CountryCode,
+ OUT PCOUNTRYINFO16 CountryInfo,
+ OUT PUSHORT ActualCountryInfoLength
+ )
+{
+ COUNTRYINFO CountryInfo32;
+ COUNTRYINFO16 DefaultInformation;
+ APIRET RetCode;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosGetCtryInfo";
+ IF_OD2_DEBUG(NLS)
+ {
+ DbgPrint("%s: Country %lu, CP %u, (current Ctry %u, CP %lu), Length %lu\n",
+ FuncName, CountryCode->country, CountryCode->codepage,
+ SesGrp->CountryCode, SesGrp->DosCP, MaxCountryInfoLength );
+ }
+#endif
+
+ //
+ // zero buffer. probe parms.
+ //
+
+ try
+ {
+ RtlZeroMemory( (PVOID)CountryInfo, MaxCountryInfoLength );
+ Od2ProbeForRead (CountryCode, sizeof(COUNTRYCODE16),1);
+ *ActualCountryInfoLength = 0;
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = Od2GetCtryInfo((ULONG)CountryCode->country,
+ (ULONG)CountryCode->codepage,
+ &CountryInfo32);
+
+ if ( !CountryCode->country && CountryCode->codepage)
+ {
+ CountryCode->country = (USHORT)SesGrp->CountryCode;
+ }
+
+ if ( RetCode )
+ {
+ return (RetCode);
+ }
+
+ DefaultInformation.country = (USHORT)CountryInfo32.country;
+ DefaultInformation.codepage = (USHORT)CountryInfo32.codepage;
+ DefaultInformation.fsDateFmt = (USHORT)CountryInfo32.fsDateFmt;
+
+ RtlMoveMemory( (PVOID)&DefaultInformation.szCurrency[0],
+ (PVOID)&CountryInfo32.szCurrency[0],
+ sizeof( COUNTRYINFO16 ) - 3 * sizeof(USHORT));
+
+ if (MaxCountryInfoLength < sizeof( COUNTRYINFO16 ))
+ {
+ RtlMoveMemory( (PVOID)CountryInfo,
+ (PVOID)&DefaultInformation,
+ MaxCountryInfoLength
+ );
+ *ActualCountryInfoLength = (USHORT)MaxCountryInfoLength;
+#if DBG
+ IF_OD2_DEBUG(NLS)
+ {
+ DbgPrint("%s: Table trunc (%lu instead of %lu)\n",
+ FuncName, MaxCountryInfoLength, sizeof( COUNTRYINFO16 ));
+ }
+#endif
+ return( ERROR_NLS_TABLE_TRUNCATED );
+ } else
+ {
+ RtlMoveMemory( (PVOID)CountryInfo,
+ (PVOID)&DefaultInformation,
+ sizeof( COUNTRYINFO16 )
+ );
+ *ActualCountryInfoLength = sizeof( COUNTRYINFO16 );
+ return( NO_ERROR );
+ }
+}
+
+
+APIRET
+DosGetCollate(
+ IN ULONG cbLength,
+ IN PCOUNTRYCODE16 CountryCode,
+ IN OUT PUCHAR pchBuf,
+ OUT PUSHORT pcbTable
+ )
+{
+ COUNTRYCODE ctryc;
+ ULONG Count = 0;
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "DosGetCollate";
+ IF_OD2_DEBUG(NLS)
+ {
+ DbgPrint("%s: Country %u, CP %u, (current Ctry %lu, CP %lu), Length %lu\n",
+ FuncName, CountryCode->country, CountryCode->codepage,
+ SesGrp->CountryCode, SesGrp->DosCP, cbLength );
+ }
+#endif
+
+ //
+ // probe parms.
+ //
+
+ try
+ {
+ ctryc.country = CountryCode->country;
+ ctryc.codepage = CountryCode->codepage;
+ *pcbTable = 0;
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ RetCode = DosQueryCollate(cbLength,
+ &ctryc,
+ pchBuf,
+ &Count);
+
+ *pcbTable = (USHORT)Count;
+
+ if ( !CountryCode->country && CountryCode->codepage)
+ {
+ CountryCode->country = (USHORT)SesGrp->CountryCode;
+ }
+
+ return (RetCode);
+}
+
+
diff --git a/private/os2/client/dllnp.c b/private/os2/client/dllnp.c
new file mode 100644
index 000000000..d1d8d7cdc
--- /dev/null
+++ b/private/os2/client/dllnp.c
@@ -0,0 +1,2567 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllnp.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 Named Pipes API Calls
+
+
+Author:
+
+ Yaron Shamir (YaronS) 12-Apr-1991
+ (stubs only)
+
+Revision History:
+
+ Yaron Shamir (YaronS) 20-Jul-1991
+ All SQL consumed APIs are implemented
+
+
+--*/
+
+#define INCL_OS2V20_PIPES
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#define INCL_DOSNMPIPES
+#include "os2dll16.h"
+
+NTSTATUS
+Od2AlertableWaitForSingleObject(
+ IN HANDLE handle
+ );
+
+POS21X_SEM
+Od2LookupSem (
+ HSEM hsem
+ );
+
+APIRET
+DosCallNPipe(
+ PSZ pszName,
+ PBYTE pInBuf,
+ ULONG cbIn,
+ PBYTE pOutBuf,
+ ULONG cbOut,
+ PULONG pcbActual,
+ ULONG msec
+ )
+/*++
+
+Routine Description:
+
+ DosCallNPipe is equivalent to a series of calls to DosOpen, perhaps
+ DosWaitNPipe (if DosOpen can't open the pipe immediately),
+ DosSetNPHState, DosTransactNPipe, and DosClose. Refer to
+ the documentation for those APIs for more information.
+
+Arguments:
+
+ pszName - Supplies the name of the named pipe.
+
+ pInBuf - Supplies the buffer containing the data that is written to
+ the pipe.
+
+ cbIn - Supplies the size (in bytes) of the input buffer.
+
+ pOutBuf - Supplies the buffer that receives the data read from the pipe.
+
+ cbOut - Supplies the size (in bytes) of the output buffer.
+
+ pcbActual - Points to a ULONG that receives the number of bytes actually
+ read from the pipe.
+
+ msec - Gives a value (in milliseconds) that is the amount of time
+ this function should wait for the pipe to become available. (Note
+ that the function may take longer than that to execute, due to
+ various factors.)
+
+Return Value:
+
+ ERROR_FILE_NOT_FOUND - pipe name does not exist
+ ERROR_PIPE_NOT_CONNECTED - The client side has been forced off by DosDisconnectNPipe.
+ ERROR_BAD_FORMAT - The named pipe was not created as a message-mode pipe.
+ ERROR_ACCESS_DENIED - the pipe was not create full-duplex.
+ ERROR_BROKEN_PIPE - The server side of the named pipe no longer exists.
+ ERROR_MORE_DATA - The cbOut parameter was smaller than the size of the message.
+ ERROR_SEM_TIMEOUT - There was no available instance of the named pipe within msec milliscounds.
+ ERROR_INTERRUPT
+ ERROR_NETWORK_ACCESS_DENIED - no permission to access the named pipe.
+
+--*/
+{
+
+ BOOLEAN FirstChance = TRUE; // Allow only one chance at WaitNamedPipe
+ APIRET rc;
+ HPIPE hPipe;
+ ULONG ulAction;
+
+ while ( 1 ) {
+
+ rc = DosOpen (pszName,
+ &hPipe, // handle
+ &ulAction, // action taken
+ 0L, // create size
+ FILE_NORMAL, // attributes
+ FILE_OPEN, // open flags
+ OPEN_ACCESS_READWRITE|OPEN_SHARE_DENYNONE, // open mode
+ 0L // pEAs
+ );
+ if (rc && FirstChance) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosCallNpipe, PipeName=%s, rc at DosOpen=%d, FirstChance\n",
+ pszName, rc);
+ }
+#endif
+ }
+
+ if (rc == NO_ERROR) {
+ break; // Created a handle
+ }
+
+ if ( FirstChance == FALSE ) {
+ // Already called DosWaitNPipe once so give up.
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosCallNpipe, PipeName=%s, rc at DosOpen=%d, SecondChance\n",
+ pszName, rc);
+ }
+#endif
+ return ERROR_SEM_TIMEOUT;
+ }
+
+ rc = DosWaitNPipe(pszName, msec);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosCallNpipe, PipeName=%s, rc at DosWaitNPipe=%d\n",
+ pszName, rc);
+ }
+#endif
+ }
+
+ FirstChance = FALSE;
+ }
+
+
+ try {
+ ULONG ReadMode = NP_READMODE_MESSAGE | NP_WAIT;
+
+ // Default open is readmode byte stream- change to message mode.
+ rc = DosSetNPHState( hPipe, ReadMode);
+ if (rc != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosCallNpipe, PipeName=%s, hPipe=%d, rc at DosSetNPHState=%d\n",
+ pszName, hPipe, rc);
+ }
+#endif
+ }
+
+ if ( rc == NO_ERROR ) {
+ rc = DosTransactNPipe(
+ hPipe,
+ pInBuf,
+ cbIn,
+ pOutBuf,
+ cbOut,
+ pcbActual
+ );
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosCallNpipe, PipeName=%s, hPipe=%d, rc at DosTransactNPipe=%d\n",
+ pszName, hPipe, rc);
+ }
+#endif
+ }
+ }
+ finally {
+ DosClose( hPipe );
+ if (rc) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosCallNpipe, PipeName=%s, hPipe=%d, rc at DosClose=%d\n",
+ pszName, hPipe, rc);
+ }
+#endif
+ }
+ }
+
+ return rc;
+}
+
+APIRET
+DosConnectNPipe(
+ HPIPE hpipe
+ )
+{
+ APIRET RetCode;
+ NTSTATUS Status;
+ PFILE_HANDLE hFileRecord;
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_PIPE_INFORMATION PipeInfoBuf;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosConnentNPipe";
+ #endif
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+ RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosConnectNpipe: File Type != NMPIPE hpipe %d\n",
+ hpipe);
+ }
+#endif
+ return ERROR_INVALID_FUNCTION;
+// return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Query with FilePipeInformationFile to get blocking mode.
+ //
+ Status = NtQueryInformationFile(hFileRecord->NtHandle,
+ &IoStatusBlock,
+ &PipeInfoBuf,
+ sizeof(FILE_PIPE_INFORMATION),
+ FilePipeInformation);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosConnectNPipe: NtQueryInformationFile() error: Status %lx\n", Status);
+ }
+#endif
+ return ERROR_BAD_PIPE;
+ }
+
+ //
+ // Try to connect to the client end.
+ //
+ Status = NtFsControlFile(hFileRecord->NtHandle,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ FSCTL_PIPE_LISTEN,
+ 0,
+ 0,
+ 0,
+ 0);
+
+ if ((Status == STATUS_PENDING) &&
+ (PipeInfoBuf.CompletionMode == FILE_PIPE_COMPLETE_OPERATION)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosConnect, Pipe %d, ERROR_PIPE_NOT_CONNECTED\n", hpipe);
+ }
+#endif
+ return(ERROR_PIPE_NOT_CONNECTED);
+ }
+
+ if (Status == STATUS_PENDING) {
+ Status = Od2AlertableWaitForSingleObject(hFileRecord->NtHandle);
+ }
+
+ if (Status == STATUS_PIPE_LISTENING) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosConnect, Pipe %d, ERROR_PIPE_NOT_CONNECTED\n", hpipe);
+ }
+#endif
+ return(ERROR_PIPE_NOT_CONNECTED);
+ } else if (Status == STATUS_PIPE_CONNECTED) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosConnect, Pipe %d, STATUS_PIPE_CONNECTED\n", hpipe);
+ }
+#endif
+ return NO_ERROR;
+ } else if (Status == STATUS_PIPE_CLOSING) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosConnect, Pipe %d, STATUS_PIPE_CLOSING\n", hpipe);
+ }
+#endif
+ return ERROR_BROKEN_PIPE;
+ } else {
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosConnectNmPipe: Error %lx\n", Status);
+ }
+#endif
+ return (Or2MapStatus( Status ));
+ }
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosConnect, Pipe %d, NO_ERROR\n", hpipe);
+ }
+#endif
+ }
+
+ return NO_ERROR;
+}
+
+APIRET
+DosDisConnectNPipe(
+ HPIPE hpipe
+ )
+{
+ APIRET RetCode;
+ NTSTATUS Status;
+ PFILE_HANDLE hFileRecord;
+ IO_STATUS_BLOCK IoStatusBlock;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosDisConnentNPipe";
+ #endif
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosDisConnectNPipe called\n");
+ }
+#endif
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+ RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE;
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosDisConnectNPipe: File Type != NMPIPE hpipe %d\n",
+ hpipe);
+ }
+#endif
+ return ERROR_INVALID_FUNCTION;
+ return ERROR_BAD_PIPE;
+ }
+
+ Status = NtFsControlFile(hFileRecord->NtHandle,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ FSCTL_PIPE_DISCONNECT,
+ 0,
+ 0,
+ 0,
+ 0);
+
+ if (NT_SUCCESS(Status))
+ return NO_ERROR;
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosDisConnectNpipe: error return from NtFsControlFile %lx\n", Status);
+ }
+#endif
+ switch (Status) {
+ case STATUS_INVALID_PARAMETER:
+ return (ERROR_INVALID_PARAMETER);
+ case STATUS_ILLEGAL_FUNCTION:
+ return(ERROR_INVALID_FUNCTION);
+ default:
+ return ERROR_PATH_NOT_FOUND;
+ }
+}
+
+APIRET
+DosCreateNPipe(
+ IN PSZ pszName,
+ OUT PHPIPE phPipe,
+ ULONG fsOpenMode,
+ ULONG fsPipeMode,
+ ULONG cbOutBuf,
+ ULONG cbInBuf,
+ ULONG ulTimeOut
+ )
+
+/*++
+
+Parameters:
+
+ pszName --Supplies the pipe name Documented in OS/2 PRM.
+ This must be a local name.
+
+ fsOpenMode --Supplies the set of flags that define the mode which the
+ pipe is to be opened with. The open mode consists of access
+ flags (one of three values) logically ORed with a writethrough
+ flag (one of two values) and an overlapped flag (one of two
+ values), as described below.
+
+ fsOpenMode Flags:
+
+ NP_ACCESS_DUPLEX --Pipe is bidirectional. (This is
+ semantically equivalent to calling CreateFile with access
+ flags of GENERIC_READ | GENERIC_WRITE.)
+
+ NP_ACCESS_INBOUND --Data goes from client to server only.
+ (This is semantically equivalent to calling CreateFile with
+ access flags of GENERIC_READ.)
+
+ NP_ACCESS_OUTBOUND --Data goes from server to client only.
+ (This is semantically equivalent to calling CreateFile with
+ access flags of GENERIC_WRITE.)
+
+ NP_INHERIT --Pipe is inherited by any child created by using
+ DosExecPgm function.
+
+ NP_NOINHERIT --Pipe is not inherited on DosExecPgm.
+
+ NP_NOWRITEBEHIND --Write Behind to remote pipes is not allowed.
+
+ NP_WRITEBEHIND --Write Behind to remote pipes is allowed,
+ this speed up performance.
+
+ fsPipeMode --Supplies the pipe-specific modes (as flags) of the pipe.
+ This parameter is a combination of a read-mode flag, a type flag,
+ and a wait flag.
+
+ fsPipeMode Flags:
+
+ NP_WAIT --Blocking mode is to be used for this handle.
+
+ NP_NOWAIT --Nonblocking mode is to be used for this handle.
+
+ NP_READMODE_BYTE --Read pipe as a byte stream.
+
+ NP_READMODE_MESSAGE --Read pipe as a message stream. Note that
+ this is not allowed with NP_TYPE_BYTE.
+
+ NP_TYPE_BYTE --Pipe is a byte-stream pipe. Note that this is
+ not allowed with NP_READMODE_MESSAGE.
+
+ NP_TYPE_MESSAGE --Pipe is a message-stream pipe.
+
+ NP_UNLIMITED_INSTANCES --Unlimited instances of this pipe can
+ be created. NOTE: the value of this flag is actually the low
+ order byte of the pipe mode word. NP_UNLIMITED_INSTANCES
+ is FF. Any other number for this byte is taken as the
+ max number of pipe instances, ranges 1-254.
+
+ cbOutBuf --Specifies the number of bytes to
+ reserve for the outgoing buffer.
+
+ cbInBuf --Specifies the number of bytes to
+ reserve for the incoming buffer.
+
+ ulTimeOut -- Specifies the default timeout value that is to be used
+ at DosWaitNmPipe function on this pipe, if a timeout value is
+ not specified when calling the function.
+
+Return Value:
+
+ Returns one of the following:
+
+ ERROR_INVALID_PARAMETER
+ ERROR_NOT_ENOUGH_MEMORY
+ ERROR_OUT_OF_STRUCTURES
+ ERROR_PATH_NOT_FOUND
+ ERROR_PIPE_BUSY
+--*/
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES Obja;
+ HANDLE NtFileHandle;
+ HANDLE NtDirHandle;
+ STRING CanonicalNameString;
+ UNICODE_STRING CanonicalNameString_U;
+ ULONG FileType;
+ ULONG FileFlags;
+ ULONG HandleOpenMode;
+ IO_STATUS_BLOCK IoStatusBlock;
+ LARGE_INTEGER Timeout;
+ ULONG CreateFlags;
+ ULONG DesiredAccess;
+ ULONG ShareAccess;
+ ULONG nMaxInstances;
+ PFILE_HANDLE hFileRecord;
+ APIRET RetCode;
+ PSECURITY_DESCRIPTOR securityDescriptor;
+ CHAR localSecurityDescriptor[SECURITY_DESCRIPTOR_MIN_LENGTH];
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosCreateNPipe";
+ #endif
+
+
+ try {
+ Od2ProbeForWrite((PVOID)phPipe, sizeof(HPIPE), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if ( fsOpenMode & ~(NP_NOWRITEBEHIND | NP_NOINHERIT | NP_ACCESS_DUPLEX | NP_ACCESS_OUTBOUND ) ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ RetCode = Od2Canonicalize(pszName,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &CanonicalNameString,
+ &NtDirHandle,
+ &FileFlags,
+ &FileType
+ );
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosCreateNmPipe: error in Od2Canonicalize %d\n", RetCode);
+ }
+#endif
+ switch (RetCode) {
+
+ case ERROR_FILE_NOT_FOUND:
+ return(ERROR_INVALID_PARAMETER);
+
+ case ERROR_BAD_NETPATH:
+ return(ERROR_PATH_NOT_FOUND);
+
+ case ERROR_FILENAME_EXCED_RANGE:
+ return(ERROR_PATH_NOT_FOUND);
+ }
+ return RetCode;
+ }
+
+
+ if (FileFlags & CANONICALIZE_META_CHARS_FOUND) {
+ RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
+ return (ERROR_FILE_NOT_FOUND);
+ }
+
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &CanonicalNameString_U,
+ &CanonicalNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( PIPES )
+ {
+ DbgPrint("DosCreateNPipe: no memory for Unicode Conversion\n");
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
+ return RetCode;
+ }
+
+ Status = RtlCreateSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION );
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint("DosCreateNPipe: failes at RtlCreateSecurityDescriptor %x\n", Status);
+ ASSERT(FALSE);
+#endif
+ return ERROR_ACCESS_DENIED;
+ }
+
+ Status = RtlSetDaclSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ (BOOLEAN)TRUE,
+ (PACL) NULL,
+ (BOOLEAN)FALSE );
+
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint("DosCreateNPipe: failes at RtlSetDaclSecurityDescriptor %x\n", Status);
+ ASSERT(FALSE);
+#endif
+ return ERROR_ACCESS_DENIED;
+ }
+ securityDescriptor = (PSECURITY_DESCRIPTOR) &localSecurityDescriptor;
+ InitializeObjectAttributes( &Obja,
+ &CanonicalNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ NtDirHandle,
+ securityDescriptor
+ );
+
+ CreateFlags = (fsOpenMode & NP_NOWRITEBEHIND ? FILE_WRITE_THROUGH : 0 );
+
+ //
+ // Determine the timeout. Convert from milliseconds to an Nt delta time
+ //
+
+ switch (ulTimeOut) {
+ case 0:
+ Timeout = RtlEnlargedIntegerMultiply( -10 * 1000, 50 );
+ break;
+ case 0xFFFFFFFF:
+ Timeout = RtlConvertLongToLargeInteger(0x80000000);
+ break;
+ default:
+ Timeout = RtlEnlargedIntegerMultiply( -10 * 1000, ulTimeOut );
+ break;
+ }
+
+ //
+ // Translate the open mode into a sharemode to restrict the clients access
+ // and derive the appropriate local desired access.
+ //
+
+ //
+ // Nt Requires the following access to begin with i.e. to perform the
+ // non IO operations like Connect, SetNPHState etc
+ //
+ DesiredAccess = FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | FILE_READ_DATA;
+ switch ( fsOpenMode & 0x0000000F ) {
+ case NP_ACCESS_INBOUND:
+ ShareAccess = FILE_SHARE_WRITE;
+// DesiredAccess = GENERIC_READ;
+ DesiredAccess |= FILE_READ_DATA;
+ HandleOpenMode = OPEN_ACCESS_READONLY | OPEN_SHARE_DENYREAD;
+ break;
+
+ case NP_ACCESS_OUTBOUND:
+ ShareAccess = FILE_SHARE_READ;
+// ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
+// DesiredAccess = GENERIC_WRITE;
+ DesiredAccess |= FILE_WRITE_DATA;
+ HandleOpenMode = OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE;
+ break;
+
+ case NP_ACCESS_DUPLEX:
+ ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
+// DesiredAccess = GENERIC_READ | GENERIC_WRITE;
+ DesiredAccess |= FILE_WRITE_DATA | FILE_READ_DATA;
+ HandleOpenMode = OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE;
+ break;
+
+ default:
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosCreateNmPipe: unknown mode %d\n", fsOpenMode);
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
+ RtlFreeUnicodeString(&CanonicalNameString_U);
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (fsOpenMode & NP_NOINHERIT ) {
+ HandleOpenMode |= OPEN_FLAGS_NOINHERIT;
+ }
+ //
+ // nMaxInstances <- low order byte of fsPipeMode
+ //
+ nMaxInstances = fsPipeMode & (0x000000FF);
+ if (nMaxInstances == 0xFF)
+ nMaxInstances = 0xFFFFFFFF;
+ else if (nMaxInstances == 0) {
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosCreateNmPipe: Max Instances 0 is illegal\n");
+ }
+#endif
+ RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
+ RtlFreeUnicodeString(&CanonicalNameString_U);
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Allocate an Os2 Handle
+ //
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RetCode = AllocateHandle(phPipe);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (RetCode) {
+ RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
+ RtlFreeUnicodeString(&CanonicalNameString_U);
+ return RetCode;
+ }
+
+
+ Status = NtCreateNamedPipeFile (
+ &NtFileHandle,
+ DesiredAccess | SYNCHRONIZE | FILE_CREATE_PIPE_INSTANCE,
+ &Obja,
+ &IoStatusBlock,
+ ShareAccess,
+ FILE_OPEN_IF, // Create first instance or subsequent
+ CreateFlags, // Create Options
+ fsPipeMode & NP_TYPE_MESSAGE ?
+ FILE_PIPE_MESSAGE_TYPE : FILE_PIPE_BYTE_STREAM_TYPE,
+ fsPipeMode & NP_READMODE_MESSAGE ?
+ FILE_PIPE_MESSAGE_MODE : FILE_PIPE_BYTE_STREAM_MODE,
+ fsPipeMode & NP_NOWAIT ?
+ FILE_PIPE_COMPLETE_OPERATION : FILE_PIPE_QUEUE_OPERATION,
+ nMaxInstances, // Max instances
+ (cbInBuf*5)/4, // Inbound quota
+ (cbOutBuf*5)/4, // Outbound quota
+ (PLARGE_INTEGER)&Timeout
+ );
+
+ RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
+ RtlFreeUnicodeString(&CanonicalNameString_U);
+ if ( !NT_SUCCESS(Status) ) {
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ FreeHandle(*phPipe);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosCreateNpipe: error return from NtCreateNpipe %lx\n", Status);
+ }
+#endif
+ switch (Status) {
+ case STATUS_INVALID_DEVICE_REQUEST:
+ return ERROR_INVALID_NAME;
+
+ default:
+ return Or2MapNtStatusToOs2Error(Status, ERROR_PATH_NOT_FOUND);
+ }
+ }
+
+ AcquireFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ hFileRecord = DereferenceFileHandleNoCheck(*phPipe);
+ hFileRecord->Flags |= HandleOpenMode & QFHSTATE_FLAGS;
+ hFileRecord->NtHandle = NtFileHandle;
+ hFileRecord->FileType = FILE_TYPE_NMPIPE;
+ hFileRecord->IoVectorType = FileVectorType;
+
+ //
+ // validate file handle
+ //
+ ValidateHandle(hFileRecord);
+ ReleaseFileLockExclusive(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint(" DosCreateNPipe succeeded: File name: %s Os2Handle: %d \n\tPipe Read Mode is %s, \n\tPipe Type Mode is %s, \n\tPipe is %s\n",
+ pszName,
+ *phPipe,
+ ((fsPipeMode & NP_READMODE_MESSAGE) ? "READMODE_MESSAGE" : "READMODE_STREAM"),
+ ((fsPipeMode & NP_TYPE_MESSAGE) ? "TYPE_MESSAGE" : "TYPE_STREAM"),
+ ((fsPipeMode & NP_NOWAIT) ? "FILE_NONBLOCKING_MODE" : "FILE_BLOCKING_MODE")
+ );
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+APIRET
+DosPeekNPipe(
+ HPIPE hpipe,
+ PBYTE pBuf,
+ ULONG cbBuf,
+ PULONG pcbActual,
+ PULONG pcbMore,
+ PULONG pState
+ )
+{
+
+ NTSTATUS Status;
+ APIRET RetCode;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PFILE_HANDLE hFileRecord;
+ FILE_PIPE_PEEK_BUFFER *pPipePeekBuf;
+ PUSHORT pAvail = (PUSHORT)pcbMore;
+ ULONG HeapBufSize;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosPeekNPipe";
+ #endif
+ try {
+ if (cbBuf != 0) {
+ Od2ProbeForWrite(pBuf, sizeof(*pBuf), 1);
+ }
+ Od2ProbeForWrite(pcbActual, sizeof(*pcbActual), 1);
+ Od2ProbeForWrite(pcbMore, sizeof(*pcbMore), 1);
+ Od2ProbeForWrite(pState, sizeof(*pState), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+ RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE;
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosPeekNPipe: File Type != NMPIPE hpipe %d\n",
+ hpipe);
+ }
+#endif
+ return ERROR_INVALID_FUNCTION;
+ }
+
+ HeapBufSize = cbBuf + FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]);
+
+ pPipePeekBuf = (FILE_PIPE_PEEK_BUFFER *) RtlAllocateHeap (
+ Od2Heap, 0,
+ HeapBufSize
+ );
+ if (pPipePeekBuf == NULL) {
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosPeekNPipe: No memory to alloc from heap\n");
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ //
+ // Peek the NT Named Pipe Handle
+ //
+
+ Status = NtFsControlFile(hFileRecord->NtHandle,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ FSCTL_PIPE_PEEK,
+ 0,
+ 0,
+ pPipePeekBuf,
+ HeapBufSize
+ );
+ if (!NT_SUCCESS(Status)){
+ switch (Status) {
+ case STATUS_END_OF_FILE:
+ RetCode = NO_ERROR;
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosPeekNPipe: EOF\n");
+ }
+#endif
+ break;
+ case STATUS_BUFFER_OVERFLOW:
+ RetCode = NO_ERROR;
+ break;
+
+ case STATUS_PIPE_BROKEN:
+ *pState = NP_CLOSING;
+ *pcbActual = 0;
+ return NO_ERROR;
+ break;
+
+ default:
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosPeekNPipeSem: Error from NtFsControlFile %lx \n",
+ Status);
+ }
+#endif
+ RtlFreeHeap (
+ Od2Heap, 0,
+ pPipePeekBuf);
+ if (Status == STATUS_INVALID_PIPE_STATE) {
+ //
+ // under os/2, different results come back from
+ // the two sides of the pipe: the server-side
+ // gets NO_ERROR with state NP_DISCONNECTED
+ // the client would get
+ //
+ *pcbActual = 0;
+ *pState = NP_DISCONNECTED;
+ return(NO_ERROR);
+ } else {
+ return (Or2MapStatus( Status ));
+ }
+ } else {
+ RetCode = NO_ERROR;
+ }
+ }
+ }
+
+ //
+ // Actual Data Read
+ //
+ *pcbActual = IoStatusBlock.Information - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]);
+
+ //
+ // Move Bytes into user buffer
+ //
+ if (cbBuf != 0) {
+ if (*pcbActual) {
+ try {
+ RtlMoveMemory( pBuf,
+ &(pPipePeekBuf->Data),
+ (cbBuf > *pcbActual) ? cbBuf : *pcbActual
+ );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ }
+ }
+ //
+ // Now translate NT style info into OS/2 1.X style
+ //
+ switch (pPipePeekBuf->NamedPipeState) {
+ case FILE_PIPE_DISCONNECTED_STATE:
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("NPipePeek: DISCONNECTED_STATE\n");
+ }
+#endif
+ *pState = NP_DISCONNECTED;
+ break;
+ case FILE_PIPE_LISTENING_STATE:
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("NPipePeek: LISTENING_STATE\n");
+ }
+#endif
+ *pState = NP_LISTENING;
+ break;
+ case FILE_PIPE_CLOSING_STATE:
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("NPipePeek: CLOSING_STATE\n");
+ }
+#endif
+ *pState = NP_CLOSING;
+ break;
+ case FILE_PIPE_CONNECTED_STATE:
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("NPipePeek: CONNECTED_STATE\n");
+ }
+#endif
+ *pState = NP_CONNECTED;
+ break;
+ default:
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("NPipePeek: UKNOWN STATE %x\n",
+ pPipePeekBuf->NamedPipeState);
+ }
+#endif
+ ASSERT (FALSE); // bugbug
+ }
+
+
+ //
+ // Data Available
+ // In OS/2 it points to two words:
+ // Total bytes avail in pipe
+ // Bytes avail in first message
+ //
+
+ *pAvail = (USHORT)(pPipePeekBuf->ReadDataAvailable);
+ if (*pAvail && (pPipePeekBuf->NumberOfMessages != -1)){
+ *pAvail += (USHORT)(2*pPipePeekBuf->NumberOfMessages); // for message headers
+ }
+
+ pAvail++;
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosPeekNPipe called. Nt ReadDataAvailable %d\n",
+ pPipePeekBuf->ReadDataAvailable);
+ }
+#endif
+
+ *pAvail = (USHORT)(pPipePeekBuf->MessageLength);
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosPeekNPipe called. Nt MessageLength %d\n",
+ pPipePeekBuf->MessageLength);
+ DbgPrint("DosPeekNPipe called. Nt NumberOfMessages %d\n",
+ pPipePeekBuf->NumberOfMessages);
+ }
+#endif
+
+ RtlFreeHeap (
+ Od2Heap, 0,
+ pPipePeekBuf
+ );
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosPeekNPipe called. Handle %d, Bytes requested %d, Bytes returned %d\n",
+ hpipe, cbBuf, *pcbActual);
+ }
+#endif
+
+ return (RetCode);
+}
+
+APIRET
+DosQueryNPHState(
+ HPIPE hpipe,
+ PULONG pState
+ )
+{
+ NTSTATUS Status;
+ APIRET RetCode;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PFILE_HANDLE hFileRecord;
+ FILE_PIPE_LOCAL_INFORMATION PipeLocalInfoBuf;
+ FILE_PIPE_INFORMATION *pPipeInfoBuf;
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosQueryNPHState";
+ #endif
+
+ try {
+ Od2ProbeForWrite(pState, sizeof(*pState),1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+ RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE;
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("[%d,%d] DosQueryNPHState: File Type != NMPIPE hpipe %d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hpipe);
+ }
+#endif
+ return ERROR_INVALID_FUNCTION;
+ }
+
+ Status = NtQueryInformationFile(hFileRecord->NtHandle,
+ &IoStatusBlock,
+ &PipeLocalInfoBuf,
+ sizeof(FILE_PIPE_LOCAL_INFORMATION),
+ FilePipeLocalInformation);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosQueryNPHState: NtqueryInformation error: Status %lx\n",
+ Status);
+ }
+#endif
+ switch ( Status) {
+ case STATUS_BUFFER_TOO_SMALL:
+ break;
+ default:
+ return ERROR_BAD_PIPE; // BUGBUG bogus
+ }
+ }
+
+ //
+ // Translate Information to OS/2 style status
+ //
+
+ *pState = 0;
+ if (PipeLocalInfoBuf.NamedPipeEnd == FILE_PIPE_SERVER_END)
+ *pState = NP_SERVER;
+
+ if (PipeLocalInfoBuf.NamedPipeType == FILE_PIPE_MESSAGE_TYPE)
+ *pState |= NP_WMESG;
+
+ if (PipeLocalInfoBuf.MaximumInstances == -1)
+ *pState |= 0xFF ;
+ else
+ *pState |= (USHORT)(PipeLocalInfoBuf.MaximumInstances);
+
+ //
+ // Now query with FilePipeInformation to get Read mode
+ // and BLocking mode
+ //
+ pPipeInfoBuf = (PFILE_PIPE_INFORMATION)&PipeLocalInfoBuf;
+
+ Status = NtQueryInformationFile(hFileRecord->NtHandle,
+ &IoStatusBlock,
+ pPipeInfoBuf,
+ sizeof(FILE_PIPE_INFORMATION),
+ FilePipeInformation);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosQueryNPHState: NtqueryInformation error: Status %lx\n",
+ Status);
+ }
+#endif
+ return ERROR_BAD_PIPE; // BUGBUG bogus
+ }
+
+ if (pPipeInfoBuf->ReadMode == FILE_PIPE_MESSAGE_MODE)
+ *pState |= NP_RMESG;
+
+ if (pPipeInfoBuf->CompletionMode == FILE_PIPE_COMPLETE_OPERATION)
+ *pState |= NP_NBLK;
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("[%d,%d] DosQueryNPHState called Pipe %d State %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hpipe,
+ *pState);
+ }
+#endif
+ return (NO_ERROR);
+}
+
+APIRET
+DosQueryNPipeInfo(
+ HPIPE hpipe,
+ ULONG infolevel,
+ PBYTE pBuf,
+ ULONG cbBuf
+ )
+{
+
+ NTSTATUS Status;
+ APIRET RetCode;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PFILE_HANDLE hFileRecord;
+ FILE_PIPE_LOCAL_INFORMATION *pPipeLocalInfoBuf;
+ FILE_NAME_INFORMATION *pPipeNameBuf;
+ ULONG HeapBufSize;
+ STRING FileName;
+ UNICODE_STRING FileName_U;
+
+#if DBG
+ PSZ RoutineName;
+ RoutineName = "DosQueryNPipeState";
+#endif
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosQueryNPipeInfo called. pipe %d, infolevel %d cbBuf %d\n",
+ hpipe, infolevel, cbBuf);
+ }
+#endif
+
+ if (cbBuf == 0) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ if (infolevel != 1) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosQueryNPipeInfo: infolevel %d not supported yet\n",
+ infolevel);
+ }
+#endif
+ if (infolevel == 2){
+ //
+ // A bug in os2 1.21 -- it returns NO_ERROR,
+ // but the book says it should not!
+ //
+ return(NO_ERROR);
+ }
+
+ return (ERROR_INVALID_LEVEL);
+ }
+
+
+ try {
+ Od2ProbeForWrite( pBuf, cbBuf, 1 );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+ RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE;
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosQueryNPipeInfo: File Type != NMPIPE hpipe %d\n",
+ hpipe);
+ }
+#endif
+ return ERROR_INVALID_FUNCTION;
+ }
+ //
+ // Calculate the size of heap needed between the file name
+ // and the pipe info
+ //
+ if ( (sizeof(FILE_NAME_INFORMATION) + 2*cbBuf) > sizeof(FILE_PIPE_LOCAL_INFORMATION) )
+ HeapBufSize = sizeof(FILE_NAME_INFORMATION) + 2*cbBuf;
+ else
+ HeapBufSize = sizeof(FILE_PIPE_LOCAL_INFORMATION);
+
+
+ pPipeLocalInfoBuf = (PFILE_PIPE_LOCAL_INFORMATION) RtlAllocateHeap (
+ Od2Heap, 0,
+ HeapBufSize
+ );
+ if (pPipeLocalInfoBuf == NULL) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosQueryNPipeInfo: No memory to alloc from heap\n");
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ Status = NtQueryInformationFile(hFileRecord->NtHandle,
+ &IoStatusBlock,
+ pPipeLocalInfoBuf,
+ sizeof(FILE_PIPE_LOCAL_INFORMATION),
+ FilePipeLocalInformation);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosQueryNPipeInfo: NtqueryInformation error: Status %lx\n",
+ Status);
+ }
+#endif
+ RtlFreeHeap (
+ Od2Heap, 0,
+ pPipeLocalInfoBuf);
+ switch (Status) {
+ case STATUS_INVALID_PARAMETER:
+ return (ERROR_INVALID_PARAMETER);
+ break;
+ default:
+ return ERROR_BAD_PIPE;
+ }
+ }
+
+ //
+ // Translate Information to OS/2 style status
+ //
+
+ if (cbBuf >= sizeof(USHORT))
+ ((struct npi_data1 *)pBuf)->npi_obuflen = (USHORT)((pPipeLocalInfoBuf->OutboundQuota*4)/5);
+ if (cbBuf >= 2*sizeof(USHORT))
+ ((struct npi_data1 *)pBuf)->npi_ibuflen = (USHORT)((pPipeLocalInfoBuf->InboundQuota*4)/5);
+ if (cbBuf >= 3*sizeof(USHORT)) {
+ ((struct npi_data1 *)pBuf)->npi_maxicnt = (UCHAR)pPipeLocalInfoBuf->MaximumInstances;
+ ((struct npi_data1 *)pBuf)->npi_curicnt = (UCHAR)pPipeLocalInfoBuf->CurrentInstances;
+ }
+
+ //
+ // Check if cbBuf is enough to include filename
+ // if not, return ERROR_BUFFER_OVERFLOW
+ //
+ if (cbBuf < sizeof(struct npi_data1)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosQueryNPipeInfo: cbBuf too small to include info\n");
+ }
+#endif
+ RtlFreeHeap (
+ Od2Heap, 0,
+ pPipeLocalInfoBuf);
+ return ERROR_BUFFER_OVERFLOW;
+ }
+ pPipeNameBuf = (PFILE_NAME_INFORMATION)pPipeLocalInfoBuf;
+
+ Status = NtQueryInformationFile(hFileRecord->NtHandle,
+ &IoStatusBlock,
+ pPipeNameBuf,
+ //sizeof(FILE_NAME_INFORMATION),
+ HeapBufSize,
+ FileNameInformation);
+ //
+ // Buffer overflow is ok to have in OS/2
+ //
+ if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_OVERFLOW)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosQueryNPipeInfo: NtqueryInformation error: Status %lx\n",
+ Status);
+ }
+#endif
+ RtlFreeHeap (
+ Od2Heap, 0,
+ pPipeLocalInfoBuf);
+ switch (Status) {
+ case STATUS_INVALID_PARAMETER:
+ return (ERROR_INVALID_PARAMETER);
+ break;
+ default:
+ return ERROR_BAD_PIPE;
+ }
+ }
+
+
+ //
+ // What we get back from Nt is Unicode
+ //
+
+ //
+ // Zero Terminate unicode string
+ //
+ pPipeNameBuf->FileName[(pPipeNameBuf->FileNameLength)/2] = UNICODE_NULL;
+ RtlInitUnicodeString (&FileName_U,
+ pPipeNameBuf->FileName);
+ //
+ // Convert it to Ansi
+ //
+ RetCode = Od2UnicodeStringToMBString(
+ &FileName,
+ &FileName_U,
+ TRUE);
+ if ( RetCode ) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosQueryNPipeInfo: Can't allocate Ansi String: Status %lx\n",
+ RetCode);
+ }
+#endif
+ RtlFreeHeap (
+ Od2Heap, 0,
+ pPipeLocalInfoBuf);
+ return( RetCode );
+ }
+
+ //
+ // Copy FileName into the os2 buffer
+ //
+
+ if ( cbBuf < (FileName.Length + sizeof(struct npi_data1) - 1 + 6 /* for \pipe and psz */) ) {
+ ((struct npi_data1 *)pBuf)->npi_namlen = (UCHAR)(cbBuf - sizeof(struct npi_data1) + 1);
+ RetCode = ERROR_BUFFER_OVERFLOW;
+ }
+ else {
+ ((struct npi_data1 *)pBuf)->npi_namlen = (UCHAR)(FileName.Length + 6) /* for \pipe nad psz */;
+ RetCode = NO_ERROR;
+ }
+
+
+ try {
+ //
+ // prefix with \pipe
+ //
+ if (((struct npi_data1 *)pBuf)->npi_namlen < 5) {
+ RtlMoveMemory(((struct npi_data1 *)pBuf)->npi_name,"\\PIPE",
+ ((struct npi_data1 *)pBuf)->npi_namlen );
+// ((struct npi_data1 *)pBuf)->npi_name[((struct npi_data1 *)pBuf)->npi_namlen] = 0;
+
+ }
+ else {
+ RtlMoveMemory(((struct npi_data1 *)pBuf)->npi_name,"\\PIPE", 5);
+ //
+ // copy from NT
+ //
+ RtlMoveMemory(
+ &((struct npi_data1 *)pBuf)->npi_name[5],
+ FileName.Buffer,
+ ((struct npi_data1 *)pBuf)->npi_namlen - 5);
+ //
+ // zero terminate
+ //
+ ((struct npi_data1 *)pBuf)->npi_name[((struct npi_data1 *)pBuf)->npi_namlen] = 0;
+ }
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosQueryNPipeInfo: file name is \n\\pipe%s\n", FileName.Buffer);
+ }
+#endif
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ Od2FreeMBString (&FileName);
+ RtlFreeHeap (
+ Od2Heap, 0,
+ pPipeLocalInfoBuf);
+ return (RetCode);
+}
+
+APIRET
+DosQueryNPipeSemState(
+ HSEM hsem,
+ PBYTE pBuf,
+ ULONG cbBuf
+ )
+{
+ APIRET RetCode;
+ PCHAR RootName;
+ STRING RootNameString;
+ UNICODE_STRING RootNameString_U;
+ NTSTATUS Status;
+ HANDLE RootHandle;
+ HANDLE NtEventHandle;
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_PIPE_EVENT_BUFFER *pPipeInfoBuf, *pNtInfoBuf;
+ struct npss *pOs2PipeInfo;
+ ULONG HeapBufSize, RequestedEntries, ActualEntries, RemainingEntries;
+ PUSHORT putmp;
+ PFILE_HANDLE hFileRecord;
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosQueryNPipeSemState";
+ #endif
+
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosQueryNPipeSemState called. Semaphore Handle %lx \n", hsem);
+ }
+#endif
+
+ try {
+ Od2ProbeForWrite(pBuf, cbBuf, 1);
+ Od2ProbeForRead((PVOID)hsem, sizeof(HSYSSEM), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (cbBuf == 0)
+ return ERROR_INVALID_PARAMETER;
+
+ pOs2PipeInfo = (struct npss *)pBuf;
+
+ RootName = "\\OS2SS\\PIPE";
+
+ Od2InitMBString(&RootNameString,RootName);
+
+ //
+ // UNICODE conversion -
+ //
+
+ RetCode = Od2MBStringToUnicodeString(
+ &RootNameString_U,
+ &RootNameString,
+ TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG( PIPES )
+ {
+ DbgPrint("DosQueryNPipeSemState: no memory for Unicode Conversion\n");
+ }
+#endif
+ return RetCode;
+ }
+
+ InitializeObjectAttributes(
+ &Obja,
+ &RootNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(&RootHandle,
+ FILE_READ_ATTRIBUTES | FILE_READ_DATA | SYNCHRONIZE,
+ &Obja,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT
+ );
+
+ RtlFreeUnicodeString (&RootNameString_U);
+
+ if ( NT_SUCCESS(Status) ) {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("calling NtOpenFile with %s succeeded.\n",RootName);
+ }
+#endif
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("calling NtOpenFile with %s failed.\n",RootName);
+ DbgPrint("status is %X.\n",Status);
+ }
+#endif
+ }
+ if (!Od2LookupSem(hsem)) {
+ //
+ // Semaphore Not Opened/Created - RAM sem ->
+ // initialize sem, return EOI NO_ERROR
+ //
+ DosSemClear(hsem);
+ pOs2PipeInfo->npss_status = NPSS_EOI;
+ return(NO_ERROR);
+ }
+ //
+ // Get the Nt Event Handle to query on
+ //
+ RetCode = Od2GetSemNtEvent(hsem, &NtEventHandle);
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint (
+ "DosQueryNPipeSem: Error from Od2GetSemNtEvent %d \n",
+ RetCode
+ );
+ }
+#endif
+ NtClose(RootHandle);
+ return ERROR_SEM_NOT_FOUND;
+ }
+
+ //
+ // Allocate a buffer for the NT info
+ // Make it bigger than the user specified number,
+ // so we can detect BUFFER_OVERFLOW
+ //
+
+ RequestedEntries = (cbBuf / sizeof(struct npss));
+ if ((cbBuf == sizeof(struct npss)*RequestedEntries) &&
+ (cbBuf > sizeof(struct npss)) ) {
+ //
+ // Exact division, but more than one struct -
+ // need to spare an entry for EOI
+ //
+ RemainingEntries = RequestedEntries;
+ }
+ else
+ RemainingEntries = RequestedEntries+1;
+
+ HeapBufSize = (2 + RequestedEntries * 2) * sizeof(FILE_PIPE_EVENT_BUFFER);
+
+ pPipeInfoBuf = (FILE_PIPE_EVENT_BUFFER *) RtlAllocateHeap (
+ Od2Heap, 0,
+ HeapBufSize
+ );
+ if (pPipeInfoBuf == NULL) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosQueryNPipeSemState: No memory to alloc from heap\n");
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ //
+ // Query the Named Pipe FS
+ //
+ Status = NtFsControlFile(RootHandle,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ FSCTL_PIPE_QUERY_EVENT,
+ (PVOID)&NtEventHandle,
+ sizeof(HANDLE),
+ pPipeInfoBuf,
+ HeapBufSize
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosQueryNPipeSem: Error from NtFsControlFile %lx \n",
+ Status);
+ }
+#endif
+ NtClose(RootHandle);
+ RtlFreeHeap (
+ Od2Heap, 0,
+ pPipeInfoBuf);
+ switch (Status) {
+ case STATUS_INVALID_PARAMETER:
+ return (ERROR_INVALID_PARAMETER);
+ break;
+ default:
+ return ERROR_BAD_PIPE;
+ }
+ }
+
+ ActualEntries = IoStatusBlock.Information / sizeof(FILE_PIPE_EVENT_BUFFER);
+
+
+ //
+ // Now translate all NT style entries into OS/2 1.X style entries
+ // Leave one os2 entry for EOI (remainingentries>1 below)
+ //
+
+ for (pNtInfoBuf = pPipeInfoBuf; RemainingEntries > 1 && ActualEntries > 0;) {
+
+ if ( (pNtInfoBuf->NamedPipeState == FILE_PIPE_DISCONNECTED_STATE) ||
+ (pNtInfoBuf->NamedPipeState == FILE_PIPE_LISTENING_STATE) ) {
+ //
+ // Pipe data not available - OS/2 does NOT return entries
+ // for these, so skip
+ //
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("QueryNmPipeSemState: skip entry\n");
+ }
+#endif
+ pNtInfoBuf++;
+ ActualEntries--;
+ continue;
+ } else {
+
+ //
+ // Work around a NPFS bug, where too many records are avail
+ //
+ putmp = (PUSHORT)&(pNtInfoBuf->KeyValue);
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+ hFileRecord = DereferenceFileHandleNoCheck((HFILE)(*putmp));
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+
+ //
+ // Actual Data maybe available
+ //
+ if (pNtInfoBuf->EntryType == FILE_PIPE_READ_DATA) {
+ pOs2PipeInfo->npss_status = NPSS_RDATA;
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("QueryNmPipeSemState: npss->state NPSS_RDATA\n");
+ }
+#endif
+ }
+ else {
+ if ((hFileRecord->Flags & ACCESS_FLAGS) == OPEN_ACCESS_READONLY){
+ //
+ // skip this buggy record until NPFS is fixed
+ //
+ pNtInfoBuf++;
+ ActualEntries--;
+ continue;
+ }
+ pOs2PipeInfo->npss_status = NPSS_WSPACE;
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("QueryNmPipeSemState: npss->state NPSS_WSPACE\n");
+ }
+#endif
+ }
+
+ if (pNtInfoBuf->NamedPipeState == FILE_PIPE_CLOSING_STATE) {
+ pOs2PipeInfo->npss_status = NPSS_CLOSE;
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("QueryNmPipeSemState: FILE_PIPE_CLOSING_STATE\n");
+ }
+#endif
+ }
+
+ if (pNtInfoBuf->NumberRequests)
+ pOs2PipeInfo->npss_flag = NPSS_WAIT;
+ else
+ pOs2PipeInfo->npss_flag = 0;
+
+ pOs2PipeInfo->npss_avail = (USHORT)(pNtInfoBuf->ByteCount);
+ }
+
+ pOs2PipeInfo->npss_key = *(putmp+1);
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("QueryNmPipeSemState: Pipe %d\n",
+ pOs2PipeInfo->npss_key);
+
+ DbgPrint ("QueryNmPipeSemState: State %ld \n",
+ pNtInfoBuf->NamedPipeState);
+ DbgPrint ("QueryNmPipeSemState: %d Available Bytes \n",
+ pOs2PipeInfo->npss_avail);
+ DbgPrint ("QueryNmPipeSemState: %d Requests Pending \n",
+ pNtInfoBuf->NumberRequests);
+ }
+#endif
+ pNtInfoBuf++;
+ pOs2PipeInfo++;
+ ActualEntries--;
+ RemainingEntries--;
+ }
+
+
+ if ( ActualEntries > 0 ||
+ cbBuf < sizeof(struct npss) ||
+ ((ULONG) (pOs2PipeInfo) >= (ULONG)pBuf + cbBuf)) {
+
+ RetCode = ERROR_BUFFER_OVERFLOW;
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("QueryNmPipeSemState: returning ERROR_BUFFER_OVERFLOW\n");
+ }
+#endif
+ }
+ else {
+ //
+ // Mark the last record
+ //
+ pOs2PipeInfo->npss_status = NPSS_EOI;
+ }
+
+ NtClose(RootHandle);
+ RtlFreeHeap (
+ Od2Heap, 0,
+ pPipeInfoBuf
+ );
+
+ return RetCode;
+}
+
+APIRET
+DosSetNPHState(
+ HPIPE hpipe,
+ ULONG state
+ )
+{
+
+ NTSTATUS Status;
+ APIRET RetCode;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PFILE_HANDLE hFileRecord;
+ FILE_PIPE_INFORMATION PipeInfoBuf;
+ //
+ // hack to overcome incomptibility with blocking->non-blocking
+ //
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosSetNPHState";
+ #endif
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("[%d,%d] DosSetNPHState: hpipe %d state %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hpipe,
+ state);
+ }
+#endif
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ //
+ // Check for invalid handle.
+ //
+ RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE;
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosSetNPHState: File Type != NMPIPE hpipe %d\n", hpipe);
+ }
+#endif
+ return ERROR_INVALID_FUNCTION;
+ }
+
+ //
+ // Only the read mode and the blocking mode can be set
+ //
+
+ if (state & (~(NP_RMESG | NP_NBLK))) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ if (state & NP_RMESG)
+ PipeInfoBuf.ReadMode = FILE_PIPE_MESSAGE_MODE;
+ else
+ PipeInfoBuf.ReadMode = FILE_PIPE_BYTE_STREAM_MODE;
+
+ if (state & NP_NBLK)
+ PipeInfoBuf.CompletionMode = FILE_PIPE_COMPLETE_OPERATION;
+ else
+ PipeInfoBuf.CompletionMode = FILE_PIPE_QUEUE_OPERATION;
+
+
+ Status = NtSetInformationFile(hFileRecord->NtHandle,
+ &IoStatusBlock,
+ &PipeInfoBuf,
+ sizeof(FILE_PIPE_INFORMATION),
+ FilePipeInformation);
+ if (Status == STATUS_PIPE_BUSY) {
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosSetNPHState: STATUS_PIPE_BUSY, flush and retry\n");
+ }
+#endif
+ DosClose(hpipe);
+ return(ERROR_PIPE_BUSY);
+/* //
+ // OS/2 allows to change a blocking pipe to non-blocking
+ // even while an IO request is pending on the other end
+ // NT does not. The best we can do is Read that data to
+ // the Bit-Bucket and then switch
+ //
+
+ RetCode = DosPeekNPipe(hpipe, &tmpBuf, 1, &cbActual,&cbMore,&State);
+ while (cbMore)
+ {
+ RetCode = DosPeekNPipe(hpipe, &tmpBuf, 1, &cbActual,&cbMore,&State);
+ DbgPrint("cnMore == %d\n", (USHORT)cbMore);
+ ptmpBuf = RtlAllocateHeap(Od2Heap, 0,
+ (ULONG)(USHORT)cbMore);
+ RetCode = DosRead( hpipe,
+ ptmpBuf,
+ (ULONG)(USHORT)cbMore,
+ &cbtmpBuf);
+ RtlFreeHeap(Od2Heap, 0, ptmpBuf);
+ }
+
+ RetCode = DosWrite(hpipe, ptmpBuf, 18, &cbtmpBuf);
+
+ Status = NtSetInformationFile(hFileRecord->NtHandle,
+ &IoStatusBlock,
+ &PipeInfoBuf,
+ sizeof(FILE_PIPE_INFORMATION),
+ FilePipeInformation);
+*/
+ }
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosSetNPHState: NtSetInformationFile error: Status %lx\n",
+ Status);
+ }
+#endif
+ switch (Status) {
+ case STATUS_INVALID_PARAMETER:
+ return (ERROR_INVALID_PARAMETER);
+
+ default:
+ return (ERROR_BAD_PIPE); // BUGBUG bogus
+ }
+ }
+ return (NO_ERROR);
+}
+
+APIRET
+DosSetNPipeSem(
+ HPIPE hpipe,
+ HSEM hsem,
+ ULONG key
+ )
+{
+ NTSTATUS Status;
+ APIRET RetCode;
+ PFILE_HANDLE hFileRecord;
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_PIPE_ASSIGN_EVENT_BUFFER EventBuffer;
+ PUSHORT putmp;
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosSetNPipeSem";
+ #endif
+
+
+ try {
+ Od2ProbeForRead((PVOID)hsem, sizeof(HSYSSEM), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+
+ RetCode = DereferenceFileHandle(hpipe, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosSetNPipeSem: File Type != NMPIPE hpipe %d\n",
+ hpipe);
+ }
+#endif
+ return ERROR_INVALID_FUNCTION;
+ }
+
+ if (!Od2LookupSem(hsem))
+ //
+ // Semaphore Not Opened/Created
+ //
+ return ERROR_SEM_NOT_FOUND;
+
+ if (*(PULONG)hsem != (ULONG)hsem)
+ //
+ // RAM semaphore - illegal for DosSetNpipeSem
+ //
+ return ERROR_SEM_NOT_FOUND;
+
+ RetCode = Od2GetSemNtEvent(hsem, &EventBuffer.EventHandle);
+ if (RetCode != NO_ERROR)
+ return RetCode;
+
+ //
+ // in the NT style ULONG key, we put two shorts:
+ // o the os2 pipe handle
+ // o the user supplied key parameter
+ //
+ putmp = (PUSHORT)&(EventBuffer.KeyValue);
+ *putmp++ = (USHORT)hpipe;
+ *putmp = (USHORT)key;
+
+
+ Status = NtFsControlFile(hFileRecord->NtHandle,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ FSCTL_PIPE_ASSIGN_EVENT,
+ (PVOID)&EventBuffer,
+ sizeof(EventBuffer),
+ 0,
+ 0);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosSetNPipeSem: Error from NtFsControlFile %lx \n", Status);
+ }
+#endif
+ switch (Status) {
+ case STATUS_INVALID_PARAMETER:
+ return (ERROR_INVALID_PARAMETER);
+ case STATUS_PIPE_DISCONNECTED:
+ return (ERROR_PIPE_NOT_CONNECTED);
+ case STATUS_NOT_IMPLEMENTED:
+ return (ERROR_INVALID_FUNCTION);
+ default:
+ return ERROR_BAD_PIPE;
+ }
+ }
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosSetNPipeSem succeeded: hsem %lx, hpipe %d, key %x \n",
+ hsem, hpipe, key);
+ }
+#endif
+ return (NO_ERROR);
+}
+
+APIRET
+DosTransactNPipe(
+ HPIPE hNamedPipe,
+ PBYTE pInBuf,
+ ULONG cbIn,
+ PBYTE pOutBuf,
+ ULONG cbOut,
+ PULONG pcbRead
+ )
+
+/*++
+Routine Description:
+
+ The TransactNamedPipe function writes data to and reads data from a named
+ pipe. This function fails if the named pipe contains any unread data or if
+ the named pipe is not in message mode. A named pipe's blocking state has no
+ effect on the TransactNamedPipe function. This API does not complete until
+ data is written into the InBuffer buffer. The lpOverlapped parameter is
+ available to allow an application to continue processing while the operation
+ takes place.
+
+Arguments:
+ hNamedPipe - Supplies a handle to a named pipe.
+
+ pInBuf - Supplies the buffer containing the data that is written to
+ the pipe.
+
+ cbIn - Supplies the size (in bytes) of the output buffer.
+
+ pOutBuf - Supplies the buffer that receives the data read from the pipe.
+
+ cbOut - Supplies the size (in bytes) of the input buffer.
+
+ pcbRead - Points to a ULONG that receives the number of bytes actually
+ read from the pipe.
+--*/
+
+{
+
+ IO_STATUS_BLOCK Iosb;
+ APIRET RetCode;
+ NTSTATUS Status;
+ PFILE_HANDLE hFileRecord;
+ ULONG ReadMode;
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosTransactNPipe";
+ #endif
+
+ if (cbIn == 0 || cbOut == 0){
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Check for invalid handle.
+ //
+ RetCode = DereferenceFileHandle(hNamedPipe, &hFileRecord);
+ if (RetCode) {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return RetCode;
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if (hFileRecord->FileType != FILE_TYPE_NMPIPE) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosTransactNpipe: File Type != NMPIPE hNamedPipe %d\n",
+ hNamedPipe);
+ }
+#endif
+ return ERROR_INVALID_FUNCTION;
+ }
+
+ DosQueryNPHState(hNamedPipe, &ReadMode);
+ //
+ // if readmode byte stream- change to message mode.
+ // This is not according to the spec, or native os/2, but
+ // it is a special hack for sql setup.
+ if (!(ReadMode & NP_READMODE_MESSAGE)) {
+ RetCode = DosSetNPHState( hNamedPipe, (ReadMode & NP_NOWAIT) | NP_READMODE_MESSAGE);
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosTransactNpipe, hPipe=%d, ReadMode %x not NP_READMODE_MESSAGE\n",
+ hNamedPipe, ReadMode);
+ }
+#endif
+ return ERROR_BAD_FORMAT;
+ }
+ }
+
+ Status = NtFsControlFile(hFileRecord->NtHandle,
+ NULL,
+ NULL, // APC routine
+ NULL, // APC Context
+ &Iosb,
+ FSCTL_PIPE_TRANSCEIVE,// IoControlCode
+ pInBuf, // Buffer for data to the FS
+ cbIn,
+ pOutBuf, // OutputBuffer for data from the FS
+ cbOut // OutputBuffer Length
+ );
+
+ if ( Status == STATUS_PENDING) {
+ // Operation must complete before return & Iosb destroyed
+ Status = Od2AlertableWaitForSingleObject(hFileRecord->NtHandle);
+ if ( NT_SUCCESS(Status)) {
+ Status = Iosb.Status;
+ }
+ }
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosTransactNPipe: Error from NtFsControlFile %lx \n", Status);
+ }
+#endif
+ switch (Status) {
+ case STATUS_INVALID_PARAMETER:
+ return (ERROR_INVALID_PARAMETER);
+ case STATUS_INVALID_READ_MODE:
+ return (ERROR_BAD_FORMAT);
+ default:
+ return ERROR_BAD_PIPE;
+ }
+ }
+
+ *pcbRead = Iosb.Information;
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosTransactNPipe succeeded: Bytes Written %d, hNamedPipe %d, Bytes Read %d \n",
+ cbIn, hNamedPipe, *pcbRead);
+ }
+#endif
+
+ return (NO_ERROR);
+}
+
+APIRET
+DosWaitNPipe(
+ PSZ pszName,
+ ULONG ulTimeOut
+ )
+{
+ IO_STATUS_BLOCK Iosb;
+ OBJECT_ATTRIBUTES Obja;
+ NTSTATUS Status;
+ ULONG WaitPipeLength;
+ PFILE_PIPE_WAIT_FOR_BUFFER WaitPipe = NULL;
+ UNICODE_STRING PipeName = {0, 0, NULL };
+ ANSI_STRING APipeName;
+ PCHAR APipeNameBuffer;
+ HANDLE Handle = NULL;
+ APIRET rc;
+ ULONG FileType;
+ ULONG FileFlags;
+ STRING RootNameString;
+ UNICODE_STRING RootNameString_U = {0, 0, NULL };
+
+ rc = Od2Canonicalize(pszName,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &APipeName,
+ NULL,
+ &FileFlags,
+ &FileType
+ );
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosWaitNPipe: error in Od2Canonicalize %d\n", rc);
+ }
+#endif
+ if (rc == ERROR_FILE_NOT_FOUND){
+ return(ERROR_INVALID_PARAMETER);
+ }
+ return rc;
+ }
+
+ APipeNameBuffer = APipeName.Buffer;
+
+ __try {
+ if (FileFlags & CANONICALIZE_META_CHARS_FOUND) {
+ rc = ERROR_INVALID_PARAMETER;
+ __leave;
+ }
+
+ Od2InitMBString(&RootNameString, APipeName.Buffer);
+ RtlUpperString(&APipeName, &APipeName);
+
+ //
+ // Local:
+ // APipeName == \OS2SS\PIPE\<pipename>
+ // Remote:
+ // APipeName == \OS2SS\UNC\<servername>\PIPE\<pipename>
+ //
+
+ if (FileType == FILE_TYPE_UNC)
+ {
+ //
+ // A redirected pipe name - we will open the redir filesystem
+ // The root = \OS2SS\UNC\<servername>\PIPE\...
+ // The pipe = <pipename>
+ //
+ RootNameString.Length = 11 * sizeof(CHAR); // size of \OS2SS\UNC\...
+ APipeName.Buffer += 11;
+ APipeName.Length -= 11 * sizeof(CHAR);
+ while (APipeName.Length && !(ISSLASH(APipeName.Buffer[0]))) {
+ RootNameString.Length += sizeof(CHAR);
+ APipeName.Buffer++;
+ APipeName.Length -= sizeof(CHAR);
+ }
+
+ if (
+ (APipeName.Length < 6 * sizeof(CHAR)) || // size of \PIPE\...
+ (APipeName.Buffer[1] != 'P') ||
+ (APipeName.Buffer[2] != 'I') ||
+ (APipeName.Buffer[3] != 'P') ||
+ (APipeName.Buffer[4] != 'E') ||
+ (!ISSLASH(APipeName.Buffer[5]))
+ ) {
+ rc = ERROR_INVALID_NAME;
+ __leave;
+ }
+
+ RootNameString.Length += 5 * sizeof(CHAR);
+ APipeName.Buffer += 6;
+ APipeName.Length -= 6 * sizeof(CHAR);
+ }
+ else {
+ //
+ // A local pipe name - we will open the NPFS filesystem
+ // The root = \OS2SS\PIPE\...
+ // The pipe = <pipename>
+ //
+ APipeName.Buffer += 12; // size of \OS2SS\PIPE
+ APipeName.Length -= 12 * sizeof(CHAR);
+ RootNameString.Length = 12 * sizeof(CHAR);
+ }
+
+ //
+ // UNICODE conversion - File System Name
+ //
+
+ rc = Od2MBStringToUnicodeString(
+ &RootNameString_U,
+ &RootNameString,
+ TRUE
+ );
+
+ if (rc) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosWaitNmPipe: no memory for Unicode Conversion\n");
+ }
+#endif
+ __leave;
+ }
+
+ //
+ // UNICODE conversion - Pipe name
+ //
+
+ rc = Od2MBStringToUnicodeString(
+ &PipeName,
+ &APipeName,
+ TRUE
+ );
+
+ if (rc) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint("DosWaitNmPipe: no memory for Unicode Conversion-2\n");
+ }
+#endif
+ __leave;
+ }
+
+ InitializeObjectAttributes(
+ &Obja,
+ &RootNameString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ Status = NtOpenFile(
+ &Handle,
+ (ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
+ &Obja,
+ &Iosb,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT /*| FILE_DIRECTORY_FILE */
+ );
+
+ if ( !NT_SUCCESS(Status) ) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosWaitNmPipe: error opening root, status=%lx\n", Status);
+ }
+#endif
+ switch (Status) {
+ case STATUS_INVALID_PARAMETER:
+ rc = ERROR_INVALID_PARAMETER;
+ break;
+ default:
+ rc = ERROR_ACCESS_DENIED;
+ }
+ __leave;
+ }
+
+ WaitPipeLength = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) + PipeName.Length;
+ WaitPipe = RtlAllocateHeap(Od2Heap, 0, WaitPipeLength);
+ if (WaitPipe == NULL) {
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosWaitNPipe: No memory to alloc from heap\n");
+ }
+#endif
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ __leave;
+ }
+
+ if ( ulTimeOut == 0 ) {
+ //
+ // OS/2 convention to wait the default timeout specified
+ // to DosCreateNPipe
+ //
+ WaitPipe->TimeoutSpecified = FALSE;
+ }
+ else {
+ if (ulTimeOut != 0xFFFFFFFF)
+ WaitPipe->Timeout = RtlEnlargedIntegerMultiply( -10 * 1000, ulTimeOut );
+ else
+ WaitPipe->Timeout = RtlConvertLongToLargeInteger(0x80000000);
+ WaitPipe->TimeoutSpecified = TRUE;
+ }
+
+ WaitPipe->NameLength = PipeName.Length;
+
+ RtlMoveMemory(
+ WaitPipe->Name,
+ PipeName.Buffer,
+ PipeName.Length
+ );
+
+ Status = NtFsControlFile(
+ Handle,
+ NULL,
+ NULL, // APC routine
+ NULL, // APC Context
+ &Iosb,
+ FSCTL_PIPE_WAIT,// IoControlCode
+ WaitPipe, // Buffer for data to the FS
+ WaitPipeLength,
+ NULL, // OutputBuffer for data from the FS
+ 0 // OutputBuffer Length
+ );
+
+ if (Status == STATUS_PENDING) {
+ Status = Od2AlertableWaitForSingleObject(Handle);
+ if ( NT_SUCCESS(Status)) {
+ Status = Iosb.Status;
+ }
+ }
+ }
+ __finally {
+ if (Handle) {
+ NtClose(Handle);
+ }
+ if (WaitPipe) {
+ RtlFreeHeap(Od2Heap, 0,WaitPipe);
+ }
+ if (PipeName.Buffer) {
+ RtlFreeUnicodeString(&PipeName);
+ }
+ if (RootNameString_U.Buffer) {
+ RtlFreeUnicodeString(&RootNameString_U);
+ }
+ RtlFreeHeap(Od2Heap, 0, APipeNameBuffer);
+ }
+
+ if (rc != NO_ERROR) {
+ return rc;
+ }
+
+ if ( !NT_SUCCESS(Status) ) {
+ switch ( Status) {
+ case STATUS_IO_TIMEOUT:
+ return(ERROR_SEM_TIMEOUT);
+ break;
+ case (NTSTATUS)(0xC0010079L): // redirector didn't know to map server error
+ return(ERROR_SEM_TIMEOUT);
+ break;
+ case STATUS_ILLEGAL_FUNCTION:
+ rc = ERROR_BAD_PIPE;
+ break;
+ case STATUS_INVALID_PARAMETER:
+ return (ERROR_INVALID_PARAMETER);
+ break;
+ default:
+ rc = ERROR_ACCESS_DENIED; //BUGBUG - need complete mapping (YS)
+ break;
+ }
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosWaitNmPipe: error at NtFsControlFile %lx\n",
+ Status);
+ }
+#endif
+ return rc;
+ }
+
+ //
+ // Success
+ //
+
+#if DBG
+ IF_OD2_DEBUG( PIPES ) {
+ DbgPrint ("DosWaitNmPipe: Success. Status %lx PipeName %s\n",
+ Status, pszName);
+ }
+#endif
+
+ if (Status == STATUS_TIMEOUT) {
+ return ERROR_SEM_TIMEOUT;
+ }
+
+ return (NO_ERROR);
+}
diff --git a/private/os2/client/dllnp16.c b/private/os2/client/dllnp16.c
new file mode 100644
index 000000000..8b6cac3fb
--- /dev/null
+++ b/private/os2/client/dllnp16.c
@@ -0,0 +1,226 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllnp16.c
+
+Abstract:
+
+ This module implements 16 equivalents of OS/2 V1.21 Named Pipes
+ API Calls. These are called from 16->32 thunks (i386\doscalls.asm).
+
+Author:
+
+ Michael Jarus (mjarus) 24-Feb-1992
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_PIPES
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#define INCL_DOSNMPIPES
+#include "os2dll16.h"
+
+
+APIRET
+Dos16CallNPipe(
+ PSZ pszName,
+ PBYTE pInBuf,
+ ULONG cbIn,
+ PBYTE pOutBuf,
+ ULONG cbOut,
+ PUSHORT pcbActual,
+ ULONG msec
+ )
+{
+ ULONG Actual;
+ APIRET Rc;
+
+ try
+ {
+ Od2ProbeForWrite(pcbActual, sizeof(USHORT), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ Actual = (ULONG) *pcbActual;
+
+ Rc = DosCallNPipe(
+ pszName,
+ pInBuf,
+ cbIn,
+ pOutBuf,
+ cbOut,
+ &Actual,
+ msec
+ );
+
+ *pcbActual = (USHORT) Actual;
+
+ return (Rc);
+
+}
+
+
+APIRET
+Dos16CreateNPipe(
+ IN PSZ pszName,
+ OUT PUSHORT phPipe,
+ ULONG fsOpenMode,
+ ULONG fsPipeMode,
+ ULONG cbOutBuf,
+ ULONG cbInBuf,
+ ULONG ulTimeOut
+ )
+{
+ HPIPE hPipe;
+ APIRET Rc;
+
+ try
+ {
+ Od2ProbeForWrite(phPipe, sizeof(USHORT), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ hPipe = (HPIPE) *phPipe;
+
+ Rc = DosCreateNPipe(
+ pszName,
+ &hPipe,
+ fsOpenMode,
+ fsPipeMode,
+ cbOutBuf,
+ cbInBuf,
+ ulTimeOut
+ );
+
+ *phPipe = (USHORT) hPipe;
+
+ return (Rc);
+
+}
+
+
+APIRET
+Dos16PeekNPipe(
+ HPIPE hpipe,
+ PBYTE pBuf,
+ ULONG cbBuf,
+ PUSHORT pActual,
+ PUSHORT pcbMore,
+ PUSHORT pState
+ )
+{
+ ULONG Actual;
+ ULONG State;
+ APIRET Rc;
+
+ try
+ {
+ Od2ProbeForWrite(pActual, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pState, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pcbMore, sizeof(USHORT), 2);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP ();
+ }
+
+ Actual = (ULONG) *pActual;
+ State = (ULONG) *pState;
+
+ Rc = DosPeekNPipe(
+ hpipe,
+ pBuf,
+ cbBuf,
+ &Actual,
+ (PULONG)pcbMore,
+ &State
+ );
+
+ *pActual = (USHORT) Actual;
+ *pState = (USHORT) State;
+
+ return (Rc);
+}
+
+
+APIRET
+Dos16QueryNPHState(
+ HPIPE hpipe,
+ PUSHORT pState
+ )
+{
+ ULONG State;
+ APIRET Rc;
+
+ try
+ {
+ Od2ProbeForWrite(pState, sizeof(USHORT), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP ();
+ }
+
+ State = (ULONG) *pState;
+
+ Rc = DosQueryNPHState(
+ hpipe,
+ &State
+ );
+
+ *pState = (USHORT) State;
+
+ return (Rc);
+
+}
+
+APIRET
+Dos16TransactNPipe(
+ HPIPE hNamedPipe,
+ PBYTE pInBuf,
+ ULONG cbIn,
+ PBYTE pOutBuf,
+ ULONG cbOut,
+ PUSHORT pcbRead
+ )
+{
+ ULONG cbRead;
+ APIRET Rc;
+
+ try
+ {
+ Od2ProbeForWrite(pcbRead, sizeof(USHORT), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP ();
+ }
+
+ cbRead = (ULONG) *pcbRead;
+
+ Rc = DosTransactNPipe(
+ hNamedPipe,
+ pInBuf,
+ cbIn,
+ pOutBuf,
+ cbOut,
+ &cbRead
+ );
+
+ *pcbRead = (USHORT) cbRead;
+
+ return (Rc);
+
+}
diff --git a/private/os2/client/dllpip16.c b/private/os2/client/dllpip16.c
new file mode 100644
index 000000000..596518749
--- /dev/null
+++ b/private/os2/client/dllpip16.c
@@ -0,0 +1,66 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllpip16.c
+
+Abstract:
+
+ This module implements 16 equivalents of OS/2 V1.21 pipes
+ API Calls. These are called from 16->32 thunks (i386\doscalls.asm).
+
+Author:
+
+ Michael Jarus (mjarus) 24-Feb-1992
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_PIPES
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FILESYS
+#include "os2dll.h"
+#define INCL_DOSNMPIPES
+#include "os2dll16.h"
+
+
+APIRET
+Dos16CreatePipe(
+ OUT PUSHORT phfRead,
+ OUT PUSHORT phfWrite,
+ IN ULONG PipeSize
+ )
+{
+ APIRET Rc;
+ HFILE hfRead;
+ HFILE hfWrite;
+
+ try
+ {
+ Od2ProbeForWrite(phfRead, sizeof(USHORT), 1);
+ Od2ProbeForWrite(phfWrite, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ hfRead = (HFILE) *phfRead;
+ hfWrite = (HFILE) *phfWrite;
+
+ Rc = DosCreatePipe(
+ &hfRead,
+ &hfWrite,
+ PipeSize
+ );
+
+ *phfRead = (USHORT) hfRead;
+ *phfWrite = (USHORT) hfWrite;
+
+ return (Rc);
+}
+
+
+
diff --git a/private/os2/client/dllpipe.c b/private/os2/client/dllpipe.c
new file mode 100644
index 000000000..4a423cc5a
--- /dev/null
+++ b/private/os2/client/dllpipe.c
@@ -0,0 +1,157 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllpipe.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 DosCreatePipe() API.
+ It uses the Named Pipes implementation to get the desired functionality.
+
+Author:
+
+ Beni Lavi (BeniL) 29-Dec-1991
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_PIPES
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FILESYS
+#include "os2dll.h"
+#define INCL_DOSNMPIPES
+#include "os2dll16.h"
+
+ULONG PipeSerialNumber;
+#define OS2_SS_PIPE_NAME_STRING "\\pipe\\os2ss"
+
+APIRET
+DosCreatePipe(
+ OUT PHFILE phfRead,
+ OUT PHFILE phfWrite,
+ IN ULONG PipeSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an anonymous pipe.
+
+Arguments:
+
+ phfRead - read handle to pipe
+
+ phfWrite - write handle to pipe
+
+ PipeSize - size of pipe
+
+Return Value:
+
+ ERROR_TOO_MANY_OPEN_FILES - no free file handles.
+
+--*/
+
+{
+ APIRET RetCode;
+ HFILE ReadHandle, WriteHandle;
+ ULONG ActionTaken;
+ UCHAR PipeNameBuffer[ 32 ];
+ ULONG nSize;
+ char *p;
+ PFILE_HANDLE hFileRecord;
+
+ #if DBG
+ PSZ RoutineName;
+ RoutineName = "DosCreatePipe";
+ #endif
+
+
+ //
+ // probe user parameters
+ //
+
+ try {
+ *phfWrite = 0;
+ *phfRead = 0;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (PipeSize == 0) {
+ nSize = 4096;
+ }
+ else {
+ nSize = PipeSize;
+ }
+
+ //
+ // Generate a pipe name according to the OS/2 convensions
+ //
+
+ strcpy(PipeNameBuffer, OS2_SS_PIPE_NAME_STRING);
+ p = &PipeNameBuffer[strlen(PipeNameBuffer)];
+ RtlIntegerToChar((ULONG)NtCurrentTeb()->ClientId.UniqueProcess, 10, 8, p);
+ p = &PipeNameBuffer[strlen(PipeNameBuffer)];
+ *p++ = '.';
+ RtlIntegerToChar(PipeSerialNumber++, 10, 8, p);
+
+ RetCode = DosCreateNPipe(
+ PipeNameBuffer,
+ &ReadHandle,
+ NP_ACCESS_INBOUND | NP_INHERIT | NP_NOWRITEBEHIND,
+ NP_WAIT | NP_READMODE_BYTE | NP_TYPE_BYTE | 1,
+ nSize,
+ nSize,
+ (ULONG)((LONG)NP_INDEFINITE_WAIT)
+ );
+
+ if (RetCode != NO_ERROR) {
+ return(RetCode);
+ }
+
+ RetCode = DosOpen(
+ PipeNameBuffer,
+ &WriteHandle,
+ &ActionTaken,
+ 0, // FileSize
+ 0, // Created file attributes
+ FILE_OPEN,
+ OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYNONE | OPEN_FLAGS_WRITE_THROUGH,
+ 0
+ );
+
+ if (RetCode != NO_ERROR) {
+ return(RetCode);
+ }
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ //
+ // Mark Handles type PIPE.
+ //
+ RetCode = DereferenceFileHandle(ReadHandle, &hFileRecord);
+ hFileRecord->FileType = FILE_TYPE_PIPE;
+ RetCode = DereferenceFileHandle(WriteHandle, &hFileRecord);
+ hFileRecord->FileType = FILE_TYPE_PIPE;
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+
+ *phfWrite = WriteHandle;
+ *phfRead = ReadHandle;
+
+ return NO_ERROR;
+}
diff --git a/private/os2/client/dllpmnt.c b/private/os2/client/dllpmnt.c
new file mode 100644
index 000000000..384e60ada
--- /dev/null
+++ b/private/os2/client/dllpmnt.c
@@ -0,0 +1,1793 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllpmnt.c
+
+Abstract:
+
+ This module contains various calls needed internally for PM/NT
+
+Author:
+
+ Patrick Questembert (PatrickQ) 20-July-1992
+
+Revision History:
+
+ Patrick Questembert (PatrickQ) 13-Oct-1993:
+ Add support for 2nd frame buffer selector.
+
+--*/
+
+#if PMNT /* If not for PMNT build, yield just an empty file */
+
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "crt/stdio.h"
+#include "crt/stdlib.h"
+#include "os2sub.h"
+
+#define INCL_32BIT
+#include "pmnt.h"
+#include "os2win.h"
+#include "sesport.h"
+
+#include "os2crt.h"
+
+#include <ntexapi.h>
+
+extern APIRET DosSemRequest(HSEM hsem, LONG lTimeout);
+extern APIRET PMNTAllocLDTSelector(ULONG BaseAddress, ULONG cbSize, PSEL pSel);
+extern APIRET VioGetConfig(ULONG usConfigId,PVIOCONFIGINFO Config,ULONG hVio);
+extern APIRET VioGetCp(ULONG usReserved,PUSHORT pIdCodePage,ULONG hVio);
+extern APIRET PMNTIsSessionRoot(void);
+extern VOID PMNTRemoveCloseMenuItem(void); // os2ses\os2.c
+
+extern LONG ScreenX;
+extern LONG ScreenY;
+BOOLEAN PMNTRegisteredDisplayAdapter = FALSE;
+extern HANDLE Ow2ForegroundWindow;
+
+ULONG PMFlags = 0;
+ULONG PMSubprocSem32;
+
+HANDLE hPMNTDevice = NULL;
+
+BOOLEAN
+SetProcessShutdownParameters(
+ DWORD dwLevel,
+ DWORD dwFlags
+ );
+
+// Defined in public\sdk\inc\winuser.h
+#define SW_HIDE 0
+
+BOOLEAN
+ShowWindow(
+ HANDLE hWnd,
+ int nCmdShow);
+
+APIRET
+InitPMNTDevice()
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ STRING NameString;
+ UNICODE_STRING UnicodeString;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+
+ RtlInitString( &NameString, PMNTDD_DEVICE_NAME );
+
+ Status = RtlAnsiStringToUnicodeString(&UnicodeString,
+ &NameString,
+ TRUE );
+ ASSERT( NT_SUCCESS( Status ) );
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &UnicodeString,
+ 0,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile( &hPMNTDevice,
+ SYNCHRONIZE, // | FILE_READ_DATA | FILE_WRITE_DATA,
+// FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttributes,
+ &IoStatus,
+ 0,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+
+ RtlFreeUnicodeString( &UnicodeString );
+
+ if ( !NT_SUCCESS( Status ) )
+ {
+ KdPrint(("InitPMNTDevice: NtOpenFile failed, ret=%x\n", Status));
+ return (Status);
+ }
+
+ return( NO_ERROR );
+}
+
+APIRET
+PMNTRegisterDisplayAdapter(
+ PMNT_IOPM_DATA *pMemory,
+ PMNT_IOPM_DATA *pPorts,
+ ULONG col,
+ ULONG row)
+{
+ ULONG MemoryStructSize, PortsStructSize;
+ PVOID AdapterInfo;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+
+ ScreenX = (LONG)col;
+ ScreenY = (LONG)row;
+ PMNTRegisteredDisplayAdapter = TRUE;
+
+ MemoryStructSize = FIELD_OFFSET(PMNT_IOPM_DATA,Entry)
+ + sizeof(pMemory->Entry[0]) * pMemory->NumEntries;
+ PortsStructSize = FIELD_OFFSET(PMNT_IOPM_DATA,Entry)
+ + sizeof(pPorts->Entry[0]) * pPorts->NumEntries;
+
+ // Allocate room for both structures
+ AdapterInfo = (PVOID)RtlAllocateHeap(Od2Heap, 0,
+ MemoryStructSize + PortsStructSize);
+
+ if (AdapterInfo == NULL)
+ {
+#if DBG
+ DbgPrint("PMNTRegisterDisplayAdapter: failed to allocate memory for structure\n");
+ DbgPrint(" MemoryStructSize=%x, PortsStructSize=%x\n",
+ MemoryStructSize,
+ PortsStructSize);
+#endif
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //Copy memory structure
+ RtlMoveMemory(AdapterInfo,
+ pMemory,
+ MemoryStructSize);
+ //Copy ports structure
+ RtlMoveMemory((char *)AdapterInfo + MemoryStructSize,
+ pPorts,
+ PortsStructSize);
+
+ if (hPMNTDevice == NULL)
+ {
+ if (InitPMNTDevice() != NO_ERROR)
+ {
+#if DBG
+ DbgPrint("PMNTRegisterDisplayAdapter: failed to open PMNTDD.SYS\n");
+#endif
+
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ Status = NtDeviceIoControlFile( hPMNTDevice,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_PMNTDD_REGISTER_HARDWARE,
+ (void *)AdapterInfo, // input buffer
+ MemoryStructSize + PortsStructSize, // in buffer length
+ NULL, // out buffer
+ 0 // out buffer length
+ );
+
+ RtlFreeHeap(Od2Heap, 0, AdapterInfo);
+
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ DbgPrint("PMNTRegisterDisplayAdapter: failed to perform IOCTL, Status=%x\n",
+ Status);
+#endif
+ return ERROR_ACCESS_DENIED;
+ }
+
+ return NO_ERROR;
+}
+
+APIRET
+PMNTIOMap()
+{
+ ULONG DummyHandle = 0L;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+
+ if (hPMNTDevice == NULL)
+ {
+ if (InitPMNTDevice() != NO_ERROR)
+ {
+#if DBG
+ DbgPrint("PMNTRegisterDisplayAdapter: failed to open PMNTDD.SYS\n");
+#endif
+
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ Status = NtDeviceIoControlFile( hPMNTDevice,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_PMNTDD_IO_MAP,
+ (void *)&DummyHandle, // input buffer
+ sizeof(DummyHandle), // in buffer length
+ NULL, // out buffer
+ 0 // out buffer length
+ );
+
+ if (NT_SUCCESS(Status))
+ return NO_ERROR;
+ else
+ {
+#if DBG
+ DbgPrint("PMNTIOMap: NtDeviceIoControl failed, Status=%x\n",
+ Status);
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
+ }
+}
+
+// Remembers the screen selector returned by PMNTDD.SYS. If PMNTMemMap() is
+// called twice within the same process, the selector will be returned without
+// calling PMNTDD.SYS again
+SEL ScreenSelector = 0;
+
+APIRET
+PMNTMemMap(
+ PSEL pSel)
+{
+ ULONG RequestedVirtualAddresses[2];
+ PMNT_MEMMAP_RESULTS ResultVirtualAddresses[2];
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+
+ if (ScreenSelector != 0)
+ {
+ try
+ {
+ Od2ProbeForWrite(pSel, sizeof(SEL), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+#if DBG
+ DbgPrint("PMNTMemMap called 2nd time for process - returning saved selector %x\n",
+ ScreenSelector);
+#endif
+ *pSel = ScreenSelector;
+
+ return NO_ERROR;
+ }
+
+ // Specify 2 virtual addresses, in case the display adapter has 2 frame
+ // buffer sections instead of one. The resulting virtual addresses structure
+ // will indicate how many are actually needed (a 2nd virtual address of 0
+ // will indicate that only one is needed).
+ RequestedVirtualAddresses[0] = PMDISPLAY_BASE1;
+ RequestedVirtualAddresses[1] = PMDISPLAY_BASE2;
+
+ if (hPMNTDevice == NULL)
+ {
+ if (InitPMNTDevice() != NO_ERROR)
+ {
+#if DBG
+ DbgPrint("PMNT_IOCTL: failed to open PMNTDD\n");
+#endif
+
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ Status = NtDeviceIoControlFile( hPMNTDevice,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_PMNTDD_MEM_MAP,
+ (void *)&RequestedVirtualAddresses,// input buffer
+ sizeof(RequestedVirtualAddresses), // in buffer length
+ (void *)ResultVirtualAddresses, // out buffer
+ sizeof(ResultVirtualAddresses) // out buffer length
+ );
+
+ if NT_SUCCESS(Status)
+ {
+ APIRET rc;
+
+ try
+ {
+ Od2ProbeForWrite(pSel, sizeof(SEL), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ // Allocate a LDT selector for the first selector. It is expected that
+ // first VirtualAddress is PMDISPLAY_BASE1 (+ some offset if address
+ // wasn't 64K-aligned)
+
+ rc = PMNTAllocLDTSelector(
+ ResultVirtualAddresses[0].VirtualAddress,
+ ResultVirtualAddresses[0].Length,
+ pSel);
+ if (rc != NO_ERROR)
+ {
+#if DBG
+ DbgPrint("PMNTDDIoctl: Error, PMNTAllocLDTSelector#1 failed\n");
+#endif
+
+ return rc;
+ }
+ else
+ {
+ ScreenSelector = *pSel; // Remember for next time !
+ // Is there a 2nd selector to map ?
+ if (ResultVirtualAddresses[1].VirtualAddress != 0)
+ {
+ SEL DummySEL; // Just to keep PMNTAllocLDTSelector happy
+
+ // Allocate a LDT selector for the 2nd selector. It is expected
+ // that the 2nd VirtualAddress is PMDISPLAY_BASE2 (+ some
+ // offset if address wasn't 64K-aligned)
+
+ rc = PMNTAllocLDTSelector(
+ ResultVirtualAddresses[1].VirtualAddress,
+ ResultVirtualAddresses[1].Length,
+ &DummySEL);
+#if DBG
+ if (rc != NO_ERROR)
+ {
+ DbgPrint("PMNTDDIoctl: Error, PMNTAllocLDTSelector#2 failed\n");
+ }
+#endif
+
+ return rc;
+ }
+ else
+ return NO_ERROR;
+ }
+ }
+ else
+ {
+#if DBG
+ DbgPrint("PMNTMemMap: IOCTL to PMNTDD.SYS failed, Status=%x\n",
+ Status);
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
+ }
+}
+
+APIRET
+PMNTDDIoctl(
+ ULONG request,
+ PVOID input_buffer,
+ ULONG input_buffer_length,
+ PVOID output_buffer,
+ ULONG output_buffer_length
+ )
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+
+ if (hPMNTDevice == NULL)
+ {
+ if (InitPMNTDevice() != NO_ERROR)
+ {
+#if DBG
+ DbgPrint("PMNT_IOCTL: failed to open PMNTDD\n");
+#endif
+
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ Status = NtDeviceIoControlFile( hPMNTDevice,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ request,
+ input_buffer,
+ input_buffer_length,
+ output_buffer,
+ output_buffer_length
+ );
+
+ if NT_SUCCESS(Status)
+ {
+ return NO_ERROR;
+ }
+ else
+ {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
+ }
+}
+
+APIRET
+PMNTIoctl(
+ ULONG request,
+ PVOID input_pointer,
+ PVOID output_pointer
+ )
+{
+ PMNT_IOCTL_DD_IOCTL_PARAMS *ptr;
+
+ UNREFERENCED_PARAMETER(output_pointer);
+
+ switch (request)
+ {
+ //PatrickQ 12-29-95 Hook for the CBA to make WIN32 Console window invisible
+ case PMNT_IOCTL_HIDE_WIN32_WINDOW:
+ if (!ShowWindow(Ow2ForegroundWindow, SW_HIDE))
+ {
+#if DBG
+ DbgPrint("PMNTIoctl: ShowWindow(%x) failed\n", Ow2ForegroundWindow);
+#endif
+ }
+ break;
+ case PMNT_IOCTL_DD_IOCTL: /* PMNTDD IOCTL's */
+ ptr = (PMNT_IOCTL_DD_IOCTL_PARAMS *)input_pointer;
+ // BUGBUG - Check input & output pointers against advertised length
+ return (PMNTDDIoctl(
+ CTL_CODE((unsigned long)PMNTDD_DEVICE_TYPE, ptr->Request,, METHOD_BUFFERED, FILE_ANY_ACCESS), /* Request */
+ FARPTRTOFLAT(ptr->InputBuffer),
+ ptr->InputBufferLength,
+ FARPTRTOFLAT(ptr->OutputBuffer),
+ ptr->OutputBufferLength
+ ));
+
+#if DBG
+ case PMNT_IOCTL_DUMP_SEGMENT_TABLE:
+ {
+ OS2_API_MSG m;
+ P_LDRDUMPSEGMENTS_MSG a = &m.u.LdrDumpSegments;
+
+ Od2CallSubsystem( &m, NULL, Ol2LdrDumpSegments, sizeof( *a ) );
+ return NO_ERROR;
+ }
+#endif
+ default:
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //PatrickQ - so that break statements above don't return random return-code
+ return NO_ERROR;
+}
+
+VOID
+validate_user_str(
+ char **ptr)
+{
+ if (*ptr == NULL)
+ {
+ *ptr = "(null)";
+ return;
+ }
+
+ try
+ {
+ int tmp;
+ tmp = strlen(*ptr);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ DbgPrint("PMNTDbgPrint: warning - illegal string parameter - %x:%x\n",
+ FLATTOSEL(*ptr),
+ (ULONG)ptr & 0xFFFF);
+ *ptr = "(illegal string)";
+ return;
+ }
+}
+
+APIRET
+PMNTDbgPrompt(
+ PCHAR MessageStr,
+ PCHAR OutputStr,
+ ULONG Len
+ )
+{
+ try
+ {
+ if (MessageStr == NULL)
+ return (DbgPrompt("", OutputStr, Len));
+ else
+ return (DbgPrompt(MessageStr, OutputStr, Len));
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+ return NO_ERROR;
+}
+
+void
+PMNTDbgPrint(
+ char *str,
+ ULONG l1,
+ ULONG l2,
+ ULONG l3,
+ ULONG l4
+ )
+{
+ ULONG r1, r2, r3, r4;
+ char *ptr=str, percent=0;
+ int param=1, i, str_length;
+ char *print_buffer = NULL;
+ char tmp_buf[512];
+
+ //So that we can see what has been sprintf'ed before problem
+ for (i=0; i<512; i++) tmp_buf[i]='\0';
+
+ // Using sprintf() because richer in formats. Also, DbgPrint hits a break-
+ // point when called with bad pointer.
+
+ //Validate string itself
+ try
+ {
+ str_length = strlen(str);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ DbgPrint("PMNTDbgPrint: illegal string - %x:%x",
+ FLATTOSEL(str),
+ (ULONG)str & 0xFFFF);
+ return;
+ }
+
+ // Look for %s (need to xlate address if that's the case)
+ while (*ptr)
+ {
+ if (*ptr == '%')
+ {
+ percent = !percent;
+ }
+ else if (percent)
+ {
+ percent = 0;
+ if (*ptr == 's')
+ {
+ switch (param)
+ {
+ case 1:
+ r1 = (ULONG)FARPTRTOFLAT(l1);
+ validate_user_str(&(char *)r1);
+ break;
+ case 2:
+ r2 = (ULONG)FARPTRTOFLAT(l2);
+ validate_user_str(&(char *)r2);
+ break;
+ case 3:
+ r3 = (ULONG)FARPTRTOFLAT(l3);
+ validate_user_str(&(char *)r3);
+ break;
+ case 4:
+ r4 = (ULONG)FARPTRTOFLAT(l4);
+ validate_user_str(&(char *)r4);
+ break;
+ }
+ }
+ else
+ {
+ switch (param)
+ {
+ case 1:
+ r1 = l1;
+ break;
+ case 2:
+ r2 = l2;
+ break;
+ case 3:
+ r3 = l3;
+ break;
+ case 4:
+ r4 = l4;
+ break;
+ }
+ }
+ param++;
+ }
+ ptr++;
+ }
+
+ try
+ {
+ int i;
+
+ if (str_length >= 512)
+ {
+ print_buffer = RtlAllocateHeap(Od2Heap, 0, str_length + 1);
+ sprintf(print_buffer, str, r1, r2, r3, r4);
+ for (i=0; i<str_length;)
+ {
+ strncpy(tmp_buf, print_buffer + i, 256);
+ // strncpy() doesn't append a \0 when count is reached
+ tmp_buf[256] = '\0';
+ i += 256; // may be less at the end of the string but we just
+ // need to make i > str_length so that's fine
+ DbgPrint(tmp_buf);
+ }
+ RtlFreeHeap(Od2Heap, 0, print_buffer);
+ }
+ else
+ {
+ sprintf(tmp_buf, str, r1, r2, r3, r4);
+ DbgPrint(tmp_buf);
+ }
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ DbgPrint("PMNTDbgPrint: access violation calling sprintf()\n");
+ DbgPrint("str = %x:%x, l1=%x, l2=%x, l3=%x, l4=%x\n",
+ FLATTOSEL(str),
+ (ULONG)str & 0xFFFF,
+ l1,
+ l2,
+ l3,
+ l4);
+ DbgPrint("tmp_buf=%s, r1=%x, r2=%x, r3=%x, r4=%x\n",
+ tmp_buf,
+ r1,
+ r2,
+ r3,
+ r4);
+ if (print_buffer != NULL)
+ RtlFreeHeap(Od2Heap, 0, print_buffer);
+ return;
+ }
+}
+
+/* Just to resolve entry. This call is used by DISPLAY.DLL:
+ - called by pmdisp\egafam\egavga\egainit.asm, ring3_VioGetPSAddress()
+ - ring3_VioGetPSAddress() is called (indirectly, via a ring3_GetPSAddress()
+ ULONG variable) by pmdisp\egafam\cellblt.asm, DeviceSetAVIOFont2() routine
+*/
+ULONG
+VioGetPSAddress(void)
+{
+ KdPrint(("VioGetPSAddress: not implemented yet\n"));
+
+ return 0L;
+}
+
+VOID
+DosSetFgnd(
+ ULONG Level,
+ ULONG Tid
+ )
+{
+ UNREFERENCED_PARAMETER(Level);
+ UNREFERENCED_PARAMETER(Tid);
+
+// KdPrint(("DosSetFgnd(%d,%d): not implemented yet\n",
+// Level, Tid));
+ return;
+}
+
+VOID
+DosSystemService(void)
+{
+ KdPrint(("DosSystemService (DOSCALLS.88): not implemented yet\n"));
+ return;
+}
+
+APIRET
+VioRedrawSize(
+ PULONG pRedrawSize)
+{
+ try
+ {
+ *pRedrawSize = 0xFFFFFFFF;
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ return NO_ERROR;
+}
+
+APIRET
+PMNTGetPgmName(
+ PSZ Buffer,
+ ULONG BufferLength)
+{
+ Od2ProbeForWrite(Buffer,BufferLength,1);
+ if (BufferLength > 1)
+ {
+ strncpy(Buffer,Od2Process->ApplName,BufferLength);
+ Buffer[BufferLength-1]='\0';
+ }
+ else
+ {
+ if (BufferLength == 1) Buffer[0]='\0';
+ }
+
+ return NO_ERROR;
+}
+
+extern ULONG Ow2bNewSession;
+
+DECLARE_HANDLE(HKEY);
+typedef HKEY *PHKEY;
+#define HKEY_LOCAL_MACHINE (( HKEY ) 0x80000002 )
+typedef ACCESS_MASK REGSAM;
+
+LONG
+APIENTRY
+RegOpenKeyExA (
+ HKEY hKey,
+ LPCSTR lpSubKey,
+ DWORD ulOptions,
+ REGSAM samDesired,
+ PHKEY phkResult
+ );
+
+LONG
+APIENTRY
+RegQueryValueExA (
+ HKEY hKey,
+ LPCSTR lpValueName,
+ PULONG lpReserved,
+ PULONG lpType,
+ PBYTE lpData,
+ PULONG lpcbData
+ );
+
+LONG
+APIENTRY
+RegCloseKey (
+ HKEY hKey
+ );
+
+#define PMSHELL_TITLE_LEN 40
+
+APIRET
+PMNTSetConsoleTitle(
+ PSZ Buffer)
+{
+ CHAR BufferTmp[PMSHELL_TITLE_LEN];
+ DWORD cb;
+ DWORD type;
+ HKEY hkey;
+
+ try
+ {
+ Od2ProbeForRead(Buffer,1,1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+#if DBG
+ DbgPrint("PMNTSetConsoleTile: error, bad pointer parameter\n");
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ // Note that the code below also takes care that the Print Manager won't
+ // set the console title unless started independently because if PMSPOOL
+ // was started by PMShell, it won't be a new session
+
+ if (OS2SS_IS_NEW_SESSION( Ow2bNewSession )) {
+ if (ProcessIsPMShell()) {
+ if (!RegOpenKeyExA(
+ HKEY_LOCAL_MACHINE,
+ "SOFTWARE\\Microsoft\\OS/2 Subsystem for NT\\1.0\\PMSHELL",
+ 0,
+ KEY_QUERY_VALUE,
+ &hkey
+ ))
+ {
+ DWORD RemoveCloseMenuItem = 0;
+
+ // Found key SOFTWARE\Microsoft\OS/2 Subsystem for NT\1.0\PMSHELL
+ cb = PMSHELL_TITLE_LEN-1;
+ if (!RegQueryValueExA(
+ hkey,
+ "Title",
+ NULL,
+ &type,
+ BufferTmp,
+ &cb
+ ))
+ {
+ BufferTmp[cb] = '\0';
+ Buffer = BufferTmp;
+ }
+
+ cb = sizeof(DWORD);
+ if (!RegQueryValueExA(
+ hkey,
+ "RemoveCloseMenuItem",
+ NULL,
+ &type,
+ &RemoveCloseMenuItem,
+ &cb
+ ))
+ {
+ if (RemoveCloseMenuItem)
+ {
+ // PatrickQ 5/2/96.This option means we don't want to
+ // allow user to select the close system menu option
+ // on PMShell - Required by CBA
+ PMNTRemoveCloseMenuItem();
+ }
+ }
+
+ RegCloseKey(hkey);
+ }
+
+ if (Buffer != BufferTmp) {
+ Buffer = "PM Shell";
+ }
+ }
+
+
+ if (SetConsoleTitleA(Buffer))
+ return(NO_ERROR);
+ else
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ return NO_ERROR;
+}
+
+APIRET
+PMNTSetPMShellFlag()
+{
+
+ if (!ProcessIsPMShell())
+ {
+#if DBG
+ DbgPrint("PMNTSetPMShellFlag: internal error, flag wasn't set !!!\n");
+#endif
+ SetPMShellFlag();
+ }
+
+ // Let PMShell go down first on logoff/shutdown
+ // Default priority for apps is 0x280
+ SetProcessShutdownParameters(0x290L, 0);
+
+ return(NO_ERROR);
+}
+
+APIRET
+PMNTSetSubprocSem(HSEM hsem)
+{
+
+ PMSubprocSem32 = (ULONG)hsem;
+
+ return(NO_ERROR);
+}
+
+ULONG
+FindWindowA(
+ PSZ lpClassName ,
+ PSZ lpWindowName);
+
+ULONG
+PMNTGetOurWindow()
+{
+ DWORD SavedTitleLength = 0;
+ UCHAR SavedTitle[256];
+ NTSTATUS Status;
+ PROCESS_BASIC_INFORMATION ProcessInfo;
+ UCHAR UniqueTitle[256] = { 'O', 'S', '2' , 'S', 'S', ':', '\0' };
+ ULONG Hwnd = 0;
+ DWORD StartingMsec;
+
+ // No need to figure out our window handle for non-root OS/2 ss programs
+ if (!PMNTIsSessionRoot())
+ return (0);
+
+ /**********************************
+ * Save the current Console title *
+ **********************************/
+
+ SavedTitleLength = GetConsoleTitleA(SavedTitle,256);
+
+ if (SavedTitleLength == 0)
+ {
+#if DBG
+ DbgPrint("PMNTGetOurWindow: GetConsoleTitle failed, error=0x%x\n",
+ GetLastError());
+#endif
+ return (0);
+ }
+
+ SavedTitle[255]='\0';
+
+ Status = NtQueryInformationProcess(
+ NtCurrentProcess(),
+ ProcessBasicInformation,
+ (PVOID)(&ProcessInfo),
+ sizeof(ProcessInfo),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ DbgPrint("PMNTGetOurWindow: NtQueryInformationProcess failed, Status == %X\n",
+ Status);
+#endif // DBG
+ return (0);
+ }
+
+ // Make a string out of the PID
+ ltoa(ProcessInfo.UniqueProcessId,
+ UniqueTitle+strlen(UniqueTitle),
+ 16);
+
+ if (!SetConsoleTitleA(UniqueTitle))
+ {
+#if DBG
+ DbgPrint("PMNTGetOurWindow: SetConsoleTitle failed, error=0x%x\n",
+ GetLastError());
+#endif
+ return (0);
+ }
+
+ //PQPQ 12/28/95 - Just try to find the window once. If you fail, don't worry
+ // about it. The loop previously used to get the window handle created a
+ // problem with Yosef's fix for the CBA to allow turning DosStartSession
+ // calls into background execution in the same session. This happened
+ // because sibling processes reset the console title to other strings so we
+ // failed to find the temporary string among the existing windows.
+ Hwnd = (ULONG)FindWindowA("ConsoleWindowClass", UniqueTitle);
+
+
+#if 0 //PQPQ
+ StartingMsec = GetTickCount();
+ while (!(Hwnd = (ULONG)FindWindowA("ConsoleWindowClass", UniqueTitle)))
+ {
+ // Don't spend more than 60 seconds trying to get the window handle
+ if ((GetTickCount() - StartingMsec) > 60000)
+ {
+#if DBG
+ DbgPrint("PMNTGetOurWindow: giving up on trying to find our window handle, error=0x%x\n",
+ GetLastError());
+#endif
+ break;
+ }
+ }
+#endif //PQPQ
+
+ /*****************************
+ * Restore the Console title *
+ *****************************/
+
+ if (!SetConsoleTitleA(SavedTitle))
+ {
+#if DBG
+ DbgPrint("PMNTGetOurWindow: SetConsoleTitle(%s) failed, error=0x%x\n",
+ SavedTitle,
+ GetLastError());
+#endif
+ }
+ return (Hwnd);
+}
+
+APIRET
+PMNTQueryScreenSize(PUSHORT xRight, PUSHORT yTop)
+{
+ if (!PMNTRegisteredDisplayAdapter)
+ {
+#if DBG
+ DbgPrint("PMNTQueryScreenSize: ERROR, called before PMNTRegisterDisplayAdapter() !\n");
+#endif
+ return (ERROR_INVALID_PARAMETER);
+ }
+
+ try
+ {
+ *xRight = (USHORT)ScreenX;
+ *yTop = (USHORT)ScreenY;
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ return (ERROR_INVALID_PARAMETER);
+ }
+
+ return(NO_ERROR);
+}
+
+APIRET
+PMNTProcessIsPMShell()
+{
+ return(ProcessIsPMShell());
+}
+
+#pragma pack(1)
+// OS/2 structure => aligned to 1
+typedef struct _WHOISINFO { /* whois */
+ USHORT segNum;
+ USHORT mte;
+ char names[ 256 ];
+} WHOISINFO;
+#pragma pack()
+
+APIRET
+PMNTIdentifyCodeSelector(
+ SEL Sel,
+ WHOISINFO *pWhois)
+{
+ OS2_API_MSG m;
+ P_LDRIDENTIFYCODESELECTOR_MSG a = &m.u.LdrIdentifyCodeSelector;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+
+ try
+ {
+ Od2ProbeForWrite(pWhois, sizeof(WHOISINFO), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ CaptureBuffer = Od2AllocateCaptureBuffer(
+ 1,
+ 0,
+ 256
+ );
+
+ if (CaptureBuffer == NULL)
+ {
+#if DBG
+ DbgPrint("PMNTIdentifyCodeSelector: Od2AllocateCaptureBuffer failed\n");
+#endif
+ return NO_ERROR;
+ }
+
+ Od2CaptureMessageString( CaptureBuffer,
+ NULL,
+ 0,
+ 256,
+ &a->ModName
+ );
+
+ a->sel = Sel;
+
+ Od2CallSubsystem( &m, CaptureBuffer, Op2IdentifyCodeSelector, sizeof( *a ) );
+
+ pWhois->segNum = a->segNum;
+ pWhois->mte = a->mte;
+ // Do not exceed size of names field (256)
+ strncpy(pWhois->names, a->ModName.Buffer, 256);
+
+ Od2FreeCaptureBuffer( CaptureBuffer );
+
+ return NO_ERROR;
+}
+
+VOID
+PMNTGetSystemTime(
+ PULONG pTime)
+{
+ LARGE_INTEGER tm;
+ NTSTATUS Status;
+
+ Status = NtQuerySystemTime(
+ &tm
+ );
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ DbgPrint("PMNTGetSystemTime: failed, Status=%x\n", Status);
+#endif
+ *pTime = 0;
+ return;
+ }
+
+ *pTime = tm.LowPart / 10000L;
+}
+
+APIRET
+PMNTVioGetConfig( IN ULONG usConfigId, // this is no longer reserved value
+ IN OUT PVIOCONFIGINFO Config,
+ IN ULONG hVio)
+{
+ return(VioGetConfig(usConfigId,Config,hVio));
+}
+
+APIRET
+PMNTVioGetCp( IN ULONG usReserved,
+ OUT PUSHORT pIdCodePage,
+ IN ULONG hVio)
+{
+ return(VioGetCp(usReserved,pIdCodePage,hVio));
+}
+
+VOID
+DosSysTrace(void)
+{
+ KdPrint(("DosSysTrace (DOSCALLS.90): not implemented yet\n"));
+ return;
+}
+
+APIRET
+DosSMPause()
+{
+ KdPrint(("DosSMPause (SESMGR.26): not implemented yet\n"));
+
+ return(NO_ERROR);
+}
+
+APIRET
+MouInitReal(PSZ pszDriverName)
+{
+ UNREFERENCED_PARAMETER(pszDriverName);
+
+#if DBG
+ //
+ // bvscalls may call it from bvsdinit.c during VioShellInit()
+ // anyway as metioned in the programmer's reference:
+ // "The function is used only by the task manager"
+ // which we do not implement
+ //
+ if (!ProcessIsPMShell()) {
+ DbgPrint("MouInitReal (MOUCALLS.27): not implemented yet\n");
+ }
+#endif
+
+ return(NO_ERROR);
+}
+
+
+#if 0
+// Spring cleaning - APIs no longer needed
+VOID
+QHKeybdHandle(void)
+{
+ KdPrint(("QHKeybdHandle (SESMGR.34): not implemented yet\n"));
+ return;
+}
+
+VOID
+QHMouseHandle(void)
+{
+ KdPrint(("QHMouseHandle (SESMGR.35): not implemented yet\n"));
+ return;
+}
+
+VOID
+DosIRamSemWake(void)
+{
+ KdPrint(("DosIRamSemWake (DOSCALLS.125): not implemented yet\n"));
+ return;
+}
+
+// DOSCALLS.18
+APIRET
+DosISemRequest(
+ IN HSEM hsem,
+ IN LONG lTimeout
+ )
+{
+ return DosSemRequest(hsem, lTimeout);
+}
+
+VOID
+DosUnknownApi54(void)
+{
+ KdPrint(("DosUknownApi54 (DOSCALLS.54): not implemented yet\n"));
+ return;
+}
+
+VOID
+DosUnknownApi90(void)
+{
+ KdPrint(("DosUknownApi90 (DOSCALLS.90): not implemented yet\n"));
+ return;
+}
+
+VOID
+DosUnknownApi105(void)
+{
+ KdPrint(("DosUknownApi105 (DOSCALLS.105): not implemented yet\n"));
+ return;
+}
+
+VOID
+DosICopy(void)
+{
+ KdPrint(("DosICopy (DOSCALLS.200): not implemented yet\n"));
+ return;
+}
+
+VOID
+DosGiveSegList(void)
+{
+ KdPrint(("DosGiveSegList (DOSCALLS.209): not implemented yet\n"));
+ return;
+}
+
+VOID
+VioSSWSwitch(void)
+{
+ KdPrint(("VioSSWSwitch (VIOCALLS.36): not implemented yet\n"));
+ return;
+}
+
+/* MOUCALLS.10 */
+APIRET
+MouSetHotKey(
+ IN ULONG p1,
+ IN ULONG p2,
+ IN ULONG hMou)
+{
+ KdPrint(("MouSetHotKey (%x, %x, %x): not implemented yet\n", p1, p2, hMou));
+
+ return NO_ERROR;
+}
+
+APIRET
+KbdFree(
+ IN ULONG hkbd) //BUGBUG - not necessarily correct prototype, just a guess
+{
+ KdPrint(("KbdFree (%x): not implemented yet\n",hkbd));
+
+ return NO_ERROR;
+}
+
+APIRET
+MouFree(
+ IN ULONG hMou) //BUGBUG - not necessarily correct prototype, just a guess
+{
+ KdPrint(("MouFree (%x): not implemented yet\n",hMou));
+
+ return NO_ERROR;
+}
+
+APIRET
+VioFree(
+ IN ULONG hVio) //BUGBUG - not necessarily correct prototype, just a guess
+{
+ KdPrint(("VioFree (%x): not implemented yet\n",hVio));
+
+ return NO_ERROR;
+}
+
+/* DOSCALLS.55 */
+APIRET
+DosSGSwitchMe(
+ IN ULONG p1,
+ IN ULONG p2)
+{
+ KdPrint(("DosSGSwitchMe(%d,%d): not implemented yet\n", p1, p2));
+
+ return NO_ERROR;
+}
+
+VOID
+KbdSwitchFgnd(void)
+{
+ KdPrint(("KbdSwitchFgnd (KBDCALLS.19): not implemented yet\n"));
+ return;
+}
+
+/* MOUCALLS.5 */
+APIRET
+MouShellInit(void)
+{
+ KdPrint(("MouShellInit (MOUCALLS.5): not implemented yet\n"));
+
+ return NO_ERROR;
+}
+
+// VIOCALLS.54
+APIRET
+VioShellInit(
+ ULONG addr)
+{
+ KdPrint(("VioShellInit (%x): not implemented yet\n", addr));
+
+ return NO_ERROR;
+}
+
+VOID
+VioRestore(void)
+{
+ KdPrint(("VioRestore (VIOCALLS.41): not implemented yet\n"));
+ return;
+}
+
+VOID
+VioSave(void)
+{
+ KdPrint(("VioSave (VIOCALLS.20): not implemented yet\n"));
+ return;
+}
+
+VOID
+VioSRFunBlock(void)
+{
+ KdPrint(("VioSRFunBlock (VIOCALLS.16): not implemented yet\n"));
+ return;
+}
+
+VOID
+VioSRFBlock(void)
+{
+ KdPrint(("VioSRFBlock (VIOCALLS.17): not implemented yet\n"));
+ return;
+}
+
+#endif // 0
+
+#ifdef JAPAN // MSKK [ShigeO] Aug 10, 1993 Win32 font on PM/NT
+
+/***************************************************************\
+* FontHandles
+*
+* History:
+* Aug 11, 1993 ShigeO Created
+\***************************************************************/
+#define MAX_FONTS 32
+HANDLE ahFont[MAX_FONTS];
+ULONG ulFontCount;
+
+/***************************************************************\
+* GetFontHandle()
+*
+* History:
+* Aug 11, 1993 ShigeO Created
+\***************************************************************/
+HANDLE GetFontHandle(
+ ULONG ulFont)
+{
+ if(ulFont && (ulFont <= ulFontCount)) {
+ return ahFont[ulFont-1];
+ }
+ return (HANDLE)0;
+}
+
+/***************************************************************\
+* PutFontHandle()
+*
+* History:
+* Aug 10, 1993 ShigeO Created
+\***************************************************************/
+ULONG PutFontHandle(
+ HANDLE hFont)
+{
+ if(hFont && (ulFontCount < MAX_FONTS)) {
+ ahFont[ulFontCount++] = hFont;
+ return ulFontCount;
+ }
+ return 0L;
+}
+
+/***************************************************************\
+* GetFontID()
+*
+* History:
+* Aug 10, 1993 ShigeO Created
+\***************************************************************/
+ULONG GetFontID(
+ VOID)
+{
+ if(ulFontCount < MAX_FONTS) {
+ return ulFontCount+1;
+ }
+ return 0L;
+}
+
+/***************************************************************\
+* SelectFont()
+*
+* History:
+* Aug 10, 1993 ShigeO Created
+\***************************************************************/
+HANDLE
+SelectFont(
+ HANDLE hFont)
+{
+ static HANDLE hFontPrev = (HANDLE)0;
+ static HANDLE hDC = (HANDLE)0;
+ HANDLE hFontTmp;
+
+ if(hFont == hFontPrev) {
+ return hDC;
+ }
+ if(!hDC && (!(hDC = CreateDCA("DISPLAY", NULL, NULL, NULL)))) {
+ return (HANDLE)0;
+ }
+ hFontTmp = SelectObject(hDC, hFont);
+ if(!hFontTmp || hFontTmp == (HANDLE)0xFFFFFFFFL) {
+ return (HANDLE)0;
+ }
+ hFontPrev = hFont;
+ return hDC;
+}
+
+/***************************************************************\
+* PMNTCreateFontIndirect()
+*
+* History:
+* Aug 10, 1993 ShigeO Created
+\***************************************************************/
+ULONG
+PMNTCreateFontIndirect(
+ PVOID lplf)
+{
+ HANDLE hFont;
+
+ if(!GetFontID()) {
+ return 0L;
+ }
+ if(!(hFont = CreateFontIndirectA(lplf))) {
+ return 0L;
+ }
+ return PutFontHandle(hFont);
+}
+
+/***************************************************************\
+* PMNTGetTextMetrics()
+*
+* History:
+* Aug 10, 1993 ShigeO Created
+\***************************************************************/
+ULONG
+PMNTGetTextMetrics(
+ ULONG ulFont,
+ PVOID lptm)
+{
+ HANDLE hDC;
+ HANDLE hFont;
+
+ if(!(hFont = GetFontHandle(ulFont))) {
+ return 0L;
+ }
+ if(!(hDC = SelectFont(hFont))) {
+ return 0L;
+ }
+ if(!(GetTextMetricsA(hDC, lptm))) {
+ return 0L;
+ }
+ return 1L;
+}
+
+/***************************************************************\
+* PMNTGetFontBitmap()
+*
+* History:
+* Aug 10, 1993 ShigeO Created
+\***************************************************************/
+ULONG
+PMNTGetStringBitmap(
+ ULONG ulFont,
+ LPCSTR lpszStr,
+ UINT cbStr,
+ UINT cbData,
+ PVOID lpSB)
+{
+ HANDLE hDC;
+ HANDLE hFont;
+
+ if(!(hFont = GetFontHandle(ulFont))) {
+ return 0L;
+ }
+ if(!(hDC = SelectFont(hFont))) {
+ return 0L;
+ }
+ if(!(GetStringBitmapA(hDC, lpszStr, cbStr, cbData, lpSB))) {
+ return 0L;
+ }
+ return 1L;
+}
+
+#endif // JAPAN
+
+HANDLE hPMNTVDMEvent;
+#ifndef PMNT_DAYTONA
+HANDLE hPMNTVDMEvent1;
+HANDLE hPMNTVDMEventReady;
+#endif // not PMNT_DAYTONA
+
+HANDLE
+__stdcall
+CreateEventW(
+ PVOID lpEventAttributes,
+ BOOL bManualReset,
+ BOOL bInitialState,
+ PVOID lpName
+ );
+
+BOOLEAN
+Os2InitializeVDMEvents()
+{
+ //
+ // Create the global subsystem PMShell synchronization Nt event
+ // (create in the unsignalled state - when PMShell comes up, it will
+ // signal it)
+ //
+
+ hPMNTVDMEvent = CreateEventW(NULL,
+ FALSE,
+ FALSE,
+ NULL);
+
+#ifndef PMNT_DAYTONA
+
+ //
+ // Create the 2nd global subsystem PMShell synchronization Nt event
+ // (create in the unsignalled state - when PMShell comes up, it will
+ // signal it)
+ //
+
+ hPMNTVDMEvent1 = CreateEventW(NULL,
+ FALSE,
+ FALSE,
+ NULL);
+
+
+ hPMNTVDMEventReady = CreateEventW(NULL,
+ FALSE,
+ FALSE,
+ NULL);
+#endif // not PMNT_DAYTONA
+
+ if ((hPMNTVDMEvent == NULL)
+#ifndef PMNT_DAYTONA
+ || (hPMNTVDMEvent1 == NULL) || (hPMNTVDMEvent == NULL)
+#endif // not PMNT_DAYTONA
+ )
+ {
+#if DBG
+ DbgPrint("Os2InitializeVDMEvent: error at CreateEvent\n");
+#endif
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+Os2WaitForVDMThread(HANDLE hEvent)
+{
+ ULONG rc;
+ if (hEvent == 0)
+ hEvent = hPMNTVDMEvent; // Use default value
+
+ if(rc = WaitForSingleObject(hEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("Os2WaitForVDMThread: WaitForSingleObject(%x, INFINITE) failed, rc = %d\n",
+ hEvent, rc);
+#endif // DBG
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#ifndef PMNT_DAYTONA
+BOOLEAN
+Os2WaitForVDMThreadReady()
+{
+ ULONG rc;
+
+ if(rc = WaitForSingleObject(hPMNTVDMEventReady, INFINITE))
+ {
+#if DBG
+ DbgPrint("Os2WaitForVDMThread: WaitForSingleObject(hPMNTVDMEventReady, INFINITE) failed, rc = %d\n",
+ rc);
+#endif // DBG
+ return FALSE;
+ }
+ return TRUE;
+}
+#endif // not PMNT_DAYTONA
+
+extern HANDLE hStartHardwareEvent;
+extern HANDLE hEndHardwareEvent;
+
+BOOL
+__stdcall
+SetEvent(
+ HANDLE hEvent
+ );
+
+#ifndef PMNT_DAYTONA
+VOID
+Os2VDMGetStartThread(
+ IN PVOID Parameter
+ )
+{
+ ULONG rc;
+
+ // Notify the creator of this thread that we are alive and about to wait for
+ // the Console
+ if(!SetEvent(hPMNTVDMEventReady))
+ {
+#if DBG
+ DbgPrint("Os2VDMGetStartThread: SetEvent(hPMNTVDMEventReady) failed, error=%x\n",
+ GetLastError());
+#endif // DBG
+ ExitThread(1L);
+ }
+
+ // Wait for Console
+ if (rc = WaitForSingleObject(hStartHardwareEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("Os2VDMGetStartThread: WaitForSingleObject(hStartHardwareEvent, INFINITE) failed, rc = %d\n",
+ rc);
+#endif // DBG
+ ExitThread(rc);
+ }
+
+ // Release PMNTGetFullScreen
+ if (!SetEvent((Parameter == NULL) ? hPMNTVDMEvent:(HANDLE)Parameter))
+ {
+#if DBG
+ DbgPrint("Os2VDMGetStartThread: SetEvent(%x) failed, error=%x\n",
+ (Parameter == NULL) ? hPMNTVDMEvent:(HANDLE)Parameter,
+ GetLastError());
+#endif // DBG
+ ExitThread(1L);
+ }
+
+ ExitThread(0L);
+}
+#endif // not PMNT_DAYTONA
+
+/*****************************************************************************
+ * Os2VDMThread: *
+ * Created & used by PMNTSetFullScreen(). It will handle the handshake with *
+ * the Console for the first transaction which indicates we have received *
+ * the control of the screen, i.e. right after going full-screen. *
+ *****************************************************************************/
+VOID
+Os2VDMThread(
+ IN PVOID Parameter
+ )
+{
+ ULONG rc;
+#ifndef PMNT_DAYTONA
+ DWORD Status;
+ HANDLE ThreadHandle = NULL;
+ ULONG Tid;
+#endif // not PMNT_DAYTONA
+
+#if DBG
+ DbgPrint("Os2VDMThread: waiting for getting hardware\n");
+#endif // DBG
+
+ if (rc = WaitForSingleObject(hStartHardwareEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: WaitForSingleObject(hStartHardwareEvent, INFINITE) #1 failed, rc = %d\n",
+ rc);
+#endif // DBG
+ ExitThread(rc);
+ }
+
+#ifdef PMNT_DAYTONA
+ if (!SetEvent(hEndHardwareEvent))
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: SetEvent(hEndHardwareEvent) #1 failed, error=%x\n",
+ GetLastError());
+#endif // DBG
+ ExitThread(1L);
+ }
+
+ if (rc = WaitForSingleObject(hStartHardwareEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: WaitForSingleObject(hStartHardwareEvent, INFINITE) #2 failed, rc = %d\n",
+ rc);
+#endif // DBG
+ ExitThread(rc);
+ }
+ if (!SetEvent(hEndHardwareEvent))
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: SetEvent(hEndHardwareEvent) #2 failed, error=%x\n",
+ GetLastError());
+#endif // DBG
+ ExitThread(1L);
+ }
+#else // not PMNT_DAYTONA
+ // Create a thread that will wait on the StartHardware event before
+ // we release the Console. This will prevent the Console from
+ // setting the event twice without letting us sense it twice
+
+ ThreadHandle = CreateThread( NULL,
+ 0,
+ (PFNTHREAD)Os2VDMGetStartThread,
+ hPMNTVDMEvent1,
+ 0,
+ &Tid);
+
+ if (ThreadHandle)
+ {
+ // Free memory associated with the thread object
+ Status = NtClose(ThreadHandle);
+#if DBG
+ if (!(Status >= 0))
+ {
+ DbgPrint("Os2VDMThread: NtClose(%x) failed, status=%x\n",
+ ThreadHandle, Status);
+ }
+#endif // DBG
+
+ // Wait till Os2VDMGetStartThread has started and is just about to
+ // call WaitForSingleObject(hStartHardwareEvent, INFINITE)
+ if (!Os2WaitForVDMThreadReady())
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: Os2WaitForVDMThread isn't useful, ThreadHandle = NULL\n");
+#endif // DBG
+ ThreadHandle = NULL;
+ }
+#if DBG
+ else
+ DbgPrint("Os2VDMThread: Os2VDMGetStartThread is ready\n");
+#endif // DBG
+ }
+#if DBG
+ else
+ {
+ DbgPrint("Os2VDMThread: CreateThread for Os2VDMGetStartThread failed, error=%x\n",
+ GetLastError());
+ }
+#endif // DBG
+
+ // Now we can safely notify the Console
+ if (!SetEvent(hEndHardwareEvent))
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: SetEvent(hEndHardwareEvent) fail, error=%x\n",
+ GetLastError());
+#endif
+ ExitThread(1L);
+ }
+
+ if (ThreadHandle != NULL)
+ {
+#if DBG
+ DbgPrint("Os2VDMThread waiting for Os2VDMGetStartThread()\n");
+#endif
+ // Wait for Os2VDMGetStartThread() to get events from the
+ // Console signifying we went full-screen
+ if (!Os2WaitForVDMThread(hPMNTVDMEvent1))
+ {
+ ExitThread(1L);
+ }
+ }
+ else
+ {
+ if (rc = WaitForSingleObject(hStartHardwareEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: WaitForSingleObject(hStartHardwareEvent, INFINITE) #2 failed, rc = %d\n",
+ rc);
+#endif
+ ExitThread(1L);
+ }
+ }
+#endif // not PMNT_DAYTONA
+
+ // Release PMNTSetFullScreen
+ if (!SetEvent(hPMNTVDMEvent))
+ {
+#if DBG
+ DbgPrint("Os2VDMThread: SetEvent(hPMNTVDMEvent) fail, error=%x\n",
+ GetLastError());
+#endif
+ ExitThread(1L);
+ }
+
+#if DBG
+ DbgPrint("Os2VDMThread: wait for getting hardware done !\n");
+#endif
+
+ ExitThread(0L);
+}
+
+#endif /* PMNT */
diff --git a/private/os2/client/dllpmnt1.c b/private/os2/client/dllpmnt1.c
new file mode 100644
index 000000000..b560f5591
--- /dev/null
+++ b/private/os2/client/dllpmnt1.c
@@ -0,0 +1,2224 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ dllpmnt1.c
+
+Abstract:
+
+ This module contains various calls needed internally for PM/NT
+ These calls implement the following API's:
+ (all API's deal with groups and programs)
+ WinCreateGroup
+ WinAddProgram
+ WinChangeProgram
+ WinQueryProgramTitles
+ WinQueryDefinition
+ WinDestroyGroup
+ WinRemoveProgram
+ PrfCreateGroup
+ PrfAddProgram
+ PrfChangeProgram
+ PrfQueryProgramTitles
+ PrfQueryDefinition
+ PrfQueryProgramHandle
+ PrfDestroyGroup
+ PrfRemoveProgram
+
+Implementation:
+ PM makes profiling in order to manage groups and programs.
+ PMNT do not use a profile. Instead it connect PROGMAN (program manager)
+ in order to execute commands or request data.
+ The connection is done using the DDEML package:
+ where service=PROGMAN, topic=PROGMAN.
+ It is important to notice that when creaing or removing
+ programs, the respective group must be active, since there is
+ no parameter for the group.
+
+ OS2 uses handles, while NT uses groups' and programs' names.
+ An atom table implements the interface.
+ We couldn't use the Win32 API's of atoms because they lacked
+ the ability to rename an atom.
+
+
+Author:
+
+ Lior Moshaiov (LiorM) 9-June-1993
+
+Revision History:
+
+ Added Clipboard Module (LiorM) 10-Nov-1993
+
+ This module contains various calls needed internally for PM/NT
+ These calls implement the interface between PM & WIN32 clipboards:
+ (all API's deal with clipboard)
+ WinOpenClipbrd
+ WinEmptyClipbrd
+ WinCloseClipbrd
+ WinSetClipbrdData (text & bitmap)
+ WinQueryClipbrdData (text & bitmap)
+ WinQueryClipbrdFmtInfo (text & bitmap)
+
+--*/
+
+#if PMNT /* If not for PMNT build, yield just an empty file */
+
+// We need here both Win32 & Os2ss include files.
+// Since they interfere, the needed definitions of os2ss & pm
+// were inserted by hand.
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "ddeml.h"
+#include "os2tile.h"
+#include "os2nt.h"
+
+#include "os2crt.h"
+
+//The following definitions should be compatible with ntrtl.h
+
+PVOID
+NTAPI
+RtlAllocateHeap(
+ IN PVOID HeapHandle,
+ IN ULONG Flags,
+ IN ULONG Size
+ );
+BOOLEAN
+NTAPI
+RtlFreeHeap(
+ IN PVOID HeapHandle,
+ IN ULONG Flags,
+ IN PVOID BaseAddress
+ );
+//The following definitions should be compatible with os2dll.h
+
+#define CANONICALIZE_FILE_OR_DEV 0x00000001
+typedef struct _STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+#ifdef MIDL_PASS
+ [size_is(MaximumLength), length_is(Length) ]
+#endif // MIDL_PASS
+ PCHAR Buffer;
+} STRING;
+typedef STRING *PSTRING;
+
+#define APIRET ULONG
+APIRET
+Od2Canonicalize(
+ IN PSZ Path,
+ IN ULONG ExpectedType,
+ OUT PSTRING OutputString,
+ OUT PHANDLE OutputDirectory OPTIONAL,
+ OUT PULONG ParseFlags OPTIONAL,
+ OUT PULONG FileType OPTIONAL
+ );
+
+VOID
+Od2ProbeForWrite(
+ IN PVOID Address,
+ IN ULONG Length,
+ IN ULONG Alignment
+ );
+
+typedef unsigned short SEL;
+typedef SEL *PSEL;
+#define APIRET ULONG
+typedef HANDLE HSEM, *PHSEM;
+APIRET
+DosFreeSeg(
+ SEL Sel);
+APIRET
+DosAllocSeg(
+ IN USHORT cbSize,
+ OUT PSEL pSel,
+ IN USHORT fsAlloc);
+
+APIRET
+DosAllocHuge(
+ IN ULONG cSegs,
+ IN USHORT cbPartialSeg,
+ OUT PSEL pSel,
+ IN ULONG cMaxSegs,
+ IN USHORT fsAlloc
+ );
+
+APIRET
+DosSemClear(
+ IN HSEM hsem
+ );
+
+APIRET
+DosSemSet(
+ IN HSEM hsem
+ );
+
+APIRET
+DosSemWait(
+ IN HSEM hsem,
+ IN LONG lTimeOut
+ );
+
+
+#pragma pack (1)
+//The following definitions should be compatible with
+// pmnt\tiger\src\h\pmwin.h
+
+typedef struct _SWP { /* swp */
+ USHORT fs;
+ SHORT cy;
+ SHORT cx;
+ SHORT y;
+ SHORT x;
+ HWND hwndInsertBehind;
+ HWND hwnd;
+} SWP;
+typedef SWP FAR *PSWP;
+
+#define CFI_SELECTOR 0x0100
+#define CFI_HANDLE 0x0200
+
+
+//The following definitions should be compatible with
+// pmnt\tiger\src\h\pmshl.h
+
+#define MAXNAMEL 60
+
+/* window size structure */
+typedef struct _XYWINSIZE { /* xywin */
+ SHORT x;
+ SHORT y;
+ SHORT cx;
+ SHORT cy;
+ USHORT fsWindow;
+} XYWINSIZE;
+typedef XYWINSIZE FAR *PXYWINSIZE;
+
+/* Definitions for fsWindow */
+#define XYF_NOAUTOCLOSE 0x0008
+#define XYF_MINIMIZED 0x0004 /* D23914 */
+#define XYF_MAXIMIZED 0x0002 /* D23914 */
+#define XYF_INVISIBLE 0x0001
+#define XYF_NORMAL 0X0000
+
+/* program handle */
+typedef void far *LHANDLE; /* hprog */
+typedef LHANDLE HPROGRAM; /* hprog */
+
+/* maximum path length */
+#define MAXPATHL 128
+
+/* root group handle */
+#define SGH_ROOT (HPROGRAM) -1L
+
+typedef struct _HPROGARRAY { /* hpga */
+ HPROGRAM ahprog[1];
+} HPROGARRAY;
+typedef HPROGARRAY FAR *PHPROGARRAY;
+
+typedef CHAR PROGCATEGORY; /* progc */
+typedef PROGCATEGORY FAR *PPROGCATEGORY;
+
+/* values acceptable for PROGCATEGORY for PM groups */
+#define PROG_DEFAULT (PROGCATEGORY)0
+#define PROG_FULLSCREEN (PROGCATEGORY)1
+#define PROG_WINDOWABLEVIO (PROGCATEGORY)2
+#define PROG_PM (PROGCATEGORY)3
+#define PROG_GROUP (PROGCATEGORY)5
+#define PROG_REAL (PROGCATEGORY)4 /* was 7 */
+#define PROG_DLL (PROGCATEGORY)6
+#define PROG_RESERVED (PROGCATEGORY)255
+
+/* visibility flag for PROGTYPE structure */
+#define SHE_VISIBLE (BYTE)0x00
+#define SHE_INVISIBLE (BYTE)0x01
+#define SHE_RESERVED (BYTE)0xFF
+
+typedef struct _PROGTYPE { /* progt */
+ PROGCATEGORY progc;
+ UCHAR fbVisible;
+} PROGTYPE;
+typedef PROGTYPE FAR *PPROGTYPE;
+
+#pragma pack (1)
+typedef struct _PROGRAMENTRY { /* proge */
+ HPROGRAM hprog;
+ PROGTYPE progt;
+ CHAR szTitle[MAXNAMEL+1];
+} PROGRAMENTRY;
+typedef PROGRAMENTRY FAR *PPROGRAMENTRY;
+
+
+typedef struct _PIBSTRUCT { /* pib */
+ PROGTYPE progt;
+ CHAR szTitle[MAXNAMEL+1];
+ CHAR szIconFileName[MAXPATHL+1];
+ CHAR szExecutable[MAXPATHL+1];
+ CHAR szStartupDir[MAXPATHL+1];
+ XYWINSIZE xywinInitial;
+ USHORT res1;
+ LHANDLE res2;
+ USHORT cchEnvironmentVars;
+ PCH pchEnvironmentVars;
+ USHORT cchProgramParameter;
+ PCH pchProgramParameter;
+} PIBSTRUCT;
+typedef PIBSTRUCT FAR *PPIBSTRUCT;
+
+/******************************************************************************/
+/* */
+/* Structures associated with 'Prf' calls */
+/* */
+/******************************************************************************/
+
+typedef struct _PROGDETAILS { /* progde */
+ ULONG Length; /* set this to sizeof(PROGDETAILS) */
+ PROGTYPE progt;
+ USHORT pad1[3]; /* ready for 32-bit PROGTYPE */
+ PSZ pszTitle; /* any of the pointers can be NULL */
+ PSZ pszExecutable;
+ PSZ pszParameters;
+ PSZ pszStartupDir;
+ PSZ pszIcon;
+ PSZ pszEnvironment; /* this is terminated by /0/0 */
+ SWP swpInitial; /* this replaces XYWINSIZE */
+ USHORT pad2[5]; /* ready for 32-bit SWP */
+} PROGDETAILS;
+
+typedef PROGDETAILS FAR *PPROGDETAILS;
+
+typedef struct _PROGTITLE { /* progti */
+ HPROGRAM hprog;
+ PROGTYPE progt;
+ USHORT pad1[3]; /* padding ready for 32-bit PROGTYPE */
+ PSZ pszTitle;
+} PROGTITLE;
+typedef PROGTITLE FAR *PPROGTITLE;
+
+#pragma pack ()
+
+extern PVOID Od2Heap;
+#define MAXNAME (MAXNAMEL+1)
+
+// Atoms: There are atom tables of 256 entries each.
+// the 1st entry points to the next table.
+// all tables are allocated dynamically when needed.
+// each handle (32 bits) consists of 2 atoms(16 bits):
+// the most significant is the group atom (0 for the desktop),
+// and the least is the atom of the program.
+// the most significant byte of each atom is the table no. (1->255)
+// the least significant is the index in the table (1->255)
+//
+
+#define PMNT_TABLE_POWER 8
+#define PMNT_ATOMS_IN_TABLE (2<<(PMNT_TABLE_POWER-1))
+#define PMNT_HANDLE_TO_ATOM(a) ((a) & 0x0000ffff)
+#define PMNT_TABLE_OF_ATOM(a) (USHORT)(((a)>>PMNT_TABLE_POWER) & 0x000000ff)
+#define PMNT_INDEX_OF_ATOM(a) (USHORT)((a) & 0x000000ff)
+#define PMNT_INDEX_TO_ATOM(a,b) ((((a)<<PMNT_TABLE_POWER)|b) & 0x0000ffff)
+#define PMNT_ATOM_TO_HANDLE(a,b) (ULONG) (((a)<<(2*PMNT_TABLE_POWER)) | ((b) & 0x0000ffff))
+
+static USHORT pmnt_no_of_atom_tables = 0;
+static USHORT pmnt_atoms_in_last_table = 0;
+static char **pmnt_1st_atom_table=NULL;
+static char **pmnt_last_atom_table=NULL;
+
+
+PCHAR
+PMNTGetAtomEntry(ULONG hprog)
+{
+
+ USHORT table_no,index,i;
+ ULONG atom;
+ char **table;
+
+ atom = PMNT_HANDLE_TO_ATOM(hprog);
+ table_no = PMNT_TABLE_OF_ATOM (atom);
+ index= PMNT_INDEX_OF_ATOM (atom);
+
+ if (table_no > pmnt_no_of_atom_tables)
+ return(NULL);
+
+ if (table_no == pmnt_no_of_atom_tables && index > pmnt_atoms_in_last_table)
+ return(NULL);
+
+ if (!(table = pmnt_1st_atom_table))
+ return(NULL);
+
+ for (i=1;i<table_no;i++) {
+ if (!(table = (char **) table[0]))
+ return(NULL);
+ }
+ return (table[index]);
+
+}
+
+
+
+ULONG
+PMNTGetAtomName(ULONG hprog, char *szName, ULONG maxsize)
+{
+
+ ULONG len;
+ char *ptr_src,*ptr_dst;
+
+
+ if (!(ptr_src = PMNTGetAtomEntry(hprog))) {
+ return(0L);
+ }
+ ptr_dst = szName;
+ len=0;
+ while((len<maxsize)&&(*ptr_dst++ = *ptr_src++)) len++;
+ return(len);
+
+}
+
+
+BOOL
+PMNTRenameAtom(ULONG hprog, char *szNewName)
+{
+
+ char *ptr_src,*ptr_dst;
+
+
+ if (!(ptr_dst = PMNTGetAtomEntry(hprog))) {
+ return(FALSE);
+ }
+ RtlFreeHeap(Od2Heap, 0, ptr_dst);
+ ptr_dst = RtlAllocateHeap(Od2Heap, 0, (int) (strlen(szNewName)+1));
+ ptr_src = szNewName;
+ while(*ptr_dst++ = *ptr_src++);
+ return(TRUE);
+
+}
+
+
+
+ULONG
+PMNTExistAtom(char *szName)
+{
+ char **table;
+ USHORT i,j,no_entries;
+
+ if (!pmnt_no_of_atom_tables) {
+ return(0L);
+ }
+ if (!(table = pmnt_1st_atom_table))
+ return(0L);
+
+ no_entries = PMNT_ATOMS_IN_TABLE-1;
+ for (i=1;i<=pmnt_no_of_atom_tables;i++) {
+ if (i == pmnt_no_of_atom_tables)
+ no_entries = pmnt_atoms_in_last_table;
+ for(j=1;j<=no_entries;j++) {
+ if (!strncmp (szName,table[j],MAXNAME)) {
+ return(PMNT_INDEX_TO_ATOM(i,j));
+ }
+ }
+ if (i<pmnt_no_of_atom_tables) {
+ if (!(table = (char **) table[0]))
+ return(0L);
+ }
+ }
+ return(0L);
+}
+
+
+ULONG
+PMNTAddAtom(ULONG hParent,char *szName)
+{
+ char *buf;
+ ULONG atom;
+ char **table;
+
+
+
+
+ if (!(atom = PMNTExistAtom(szName))) {
+ //should be added
+ if (!pmnt_atoms_in_last_table ||
+ (pmnt_atoms_in_last_table == PMNT_ATOMS_IN_TABLE-1)) {
+ // a new table should be created
+ if(!(table =
+ RtlAllocateHeap(Od2Heap, 0, PMNT_ATOMS_IN_TABLE *sizeof(char *)))){
+ return(0L);
+ }
+ if (pmnt_no_of_atom_tables == 0) {
+ pmnt_last_atom_table = pmnt_1st_atom_table = table;
+ }
+ else {
+ pmnt_last_atom_table[0] = (void *) table;
+ pmnt_last_atom_table = table;
+ }
+ pmnt_no_of_atom_tables++;
+ pmnt_atoms_in_last_table = 0;
+ }
+ pmnt_atoms_in_last_table++;
+ if (! (pmnt_last_atom_table[pmnt_atoms_in_last_table]=buf=
+ RtlAllocateHeap(Od2Heap, 0, (int) (strlen(szName)+1)))){
+ return(0L);
+ }
+ strcpy(buf,szName);
+ atom = PMNT_INDEX_TO_ATOM(pmnt_no_of_atom_tables,pmnt_atoms_in_last_table);
+ }
+ return(PMNT_ATOM_TO_HANDLE(hParent,atom));
+}
+
+// These functions retrieve strings from text in CF_TEXT format.
+// The format is :
+// each line ends with a CR & LF (0x0d, 0x0a)
+// the thex ends with the NULL char ('\0')
+// 1. information about progman:
+// each line consists of group name.
+// 2. information about a group
+// 1st line contains information about the group
+// All the other lines contain information about programs in the group
+// (a line for each program)
+// "proram_name","command",startup_directory,icon_path,xPosition,yPosition,icon_index,Hotkey,Minimize
+//
+
+
+BOOL
+PMNTGetNextStart(
+ PCHAR *ptr_src)
+{
+ char *p1,*p2,*p3;
+
+ p1 = strchr (*ptr_src,(int)0x0d);
+ p2 = strchr (*ptr_src,',');
+ if (p2 && p2<p1) {
+ *ptr_src = ++p2;
+ p2 = strchr (*ptr_src,',');
+ p3 = strchr (*ptr_src,'"');
+ if (p3 && p3<p1 && ( !p2 || p3<p2)) {
+ *ptr_src = ++p3;
+ return(TRUE);
+ }
+ }
+ return(FALSE);
+}
+
+ULONG
+PMNTGetThisString(
+ PCHAR *ptr_src, char *buffer, ULONG maxbuf)
+{
+ char *ptr_Cf_Text,*ptr_buf;
+ ULONG i = 0;
+
+ ptr_Cf_Text = *ptr_src;
+ if (maxbuf) {
+ ptr_buf = buffer;
+ while((i<maxbuf) && (*ptr_buf++ = *ptr_Cf_Text++) != '"') i++;
+ *--ptr_buf = '\0';
+ }
+ else {
+ while(*ptr_Cf_Text++ != '"') i++;
+ }
+ *ptr_src = ptr_Cf_Text;
+ return(i);
+}
+
+ULONG
+PMNTGetThisString1(
+ PCHAR *ptr_src, char *buffer, ULONG maxbuf, ULONG *param)
+{
+ char *ptr_Cf_Text,*ptr_buf;
+ ULONG i = 0;
+
+ ptr_Cf_Text = *ptr_src;
+ if (maxbuf) {
+ ptr_buf = buffer;
+ while((i<maxbuf) && (*ptr_buf = *ptr_Cf_Text) != '"' && (*ptr_buf != ' ')) {
+ i++;
+ ptr_buf++;
+ ptr_Cf_Text++;
+ }
+ *ptr_buf = '\0';
+ }
+ else {
+ while(*ptr_Cf_Text != '"' && *ptr_Cf_Text != ' ') {
+ ptr_Cf_Text++;
+ i++;
+ }
+ }
+ if (*param = (*ptr_Cf_Text++ == ' '))
+ while (*ptr_Cf_Text == ' ') *ptr_Cf_Text++;
+ *ptr_src = ptr_Cf_Text;
+ return(i);
+}
+
+
+ULONG
+PMNTGetNextString(
+ PCHAR *ptr_src, char *buffer, ULONG maxbuf)
+{
+
+ if (!PMNTGetNextStart(ptr_src)) {
+ return(0L);
+ }
+ return(PMNTGetThisString(ptr_src,buffer,maxbuf));
+}
+
+ULONG
+PMNTGetNextString1(
+ PCHAR *ptr_src, char *buffer, ULONG maxbuf, ULONG *param)
+{
+
+ if (!PMNTGetNextStart(ptr_src)) {
+ return(0L);
+ }
+ return(PMNTGetThisString1(ptr_src,buffer,maxbuf,param));
+}
+
+ULONG
+PMNTGetNextString0(
+ PCHAR *ptr_src, char *buffer, ULONG maxbuf)
+{
+ char *ptr_Cf_Text,*ptr_buf;
+ ULONG i=0;
+
+ char *p1,*p2;
+
+ ptr_Cf_Text = *ptr_src;
+ p1 = strchr (ptr_Cf_Text,(int)0x0d);
+ p2 = strchr (ptr_Cf_Text,',');
+ if (p2 && p2<p1)
+ ptr_Cf_Text = ++p2;
+ else
+ return(0L);
+
+ if (maxbuf) {
+ ptr_buf = buffer;
+ while((i<maxbuf) && (*ptr_buf++ = *ptr_Cf_Text++) != ',') i++;
+ *--ptr_buf = '\0';
+ }
+ else {
+ while(*ptr_Cf_Text++ != ',') i++;
+ }
+ *ptr_src = ptr_Cf_Text;
+ return(i);
+}
+
+
+#define MYMAXBUF 512
+
+// retrieves canonicalized name of file from file name & starting directory
+
+ULONG
+PMNTGetFullPath(
+ char *file_name, char *st_dir, PSTRING canonic_name)
+{
+ LPCSTR *ptr;
+ ULONG len=0,FileFlags,FileType;
+ char buf[MYMAXBUF],path_name[MYMAXBUF];
+ short change_dir;
+
+ if (change_dir = (st_dir && *st_dir)) {
+ GetCurrentDirectory((DWORD)MYMAXBUF,(LPSTR)buf);
+ SetCurrentDirectory((LPSTR) st_dir);
+ }
+
+ do {
+ len = (ULONG)
+ SearchPath((LPCSTR) NULL,(LPCSTR) file_name, (LPCSTR) ".EXE", (DWORD) MYMAXBUF,
+ (LPSTR) path_name, (LPSTR *) &ptr);
+ if (!len || len > MYMAXBUF) {
+ KdPrint(("PMNTGetFullPath : SearchPath failed\n"));
+ len = 0;
+ break;
+ }
+ if (Od2Canonicalize(path_name,CANONICALIZE_FILE_OR_DEV,canonic_name,NULL,
+ &FileFlags,&FileType)) {
+ len = 0;
+ break;
+ }
+
+ } while (FALSE);
+ if (change_dir) {
+ SetCurrentDirectory((LPSTR) buf);
+ }
+ return(len);
+
+
+}
+
+
+// The following functions are a layer between the API's and DDEML
+// They are called after a connection with progman has been settled
+// and they get strings (instead of handles) as input
+// This layer is needed since some API's call the same DdeClientTransaction
+
+#define DDE_TIME_OUT 120000L // 2 minutes timeout
+
+BOOL
+PMNTCreateGrp (
+ HCONV hConv, char *GroupName)
+{
+ char buffer[256];
+ HDDEDATA rc;
+
+ strcpy (buffer,"[CreateGroup(");
+ strcat (buffer,GroupName);
+ strcat (buffer,",0)]");
+ rc = DdeClientTransaction((LPBYTE)buffer,strlen(buffer)+1,hConv,0L,0,
+ XTYP_EXECUTE,DDE_TIME_OUT,NULL);
+ if (!rc) {
+ KdPrint(("PMNTCreateGrp : transaction failed\n"));
+ return(FALSE);
+ }
+ DdeFreeDataHandle(rc);
+ return(TRUE);
+}
+
+
+BOOL
+PMNTAddItem(
+ HCONV hConv,PCHAR szTitle,PCHAR szExecutable,PCHAR szStartupDir,PCHAR szParameters)
+{
+
+
+ char buffer[256];
+ HDDEDATA rc;
+ char *ptr;
+
+ strcpy (buffer,"[AddItem(");
+ strcat (buffer,szExecutable);
+ if (szParameters && *szParameters) {
+ ptr = buffer + strlen(buffer);
+ *ptr++ = ' ';
+ strcpy(ptr,szParameters);
+ }
+ strcat (buffer,",");
+ strcat (buffer,szTitle);
+ strcat (buffer,",,,,,");
+ if (szStartupDir) {
+ strcat (buffer,szStartupDir);
+ }
+ strcat (buffer,")]");
+ rc = DdeClientTransaction((LPBYTE)buffer,strlen(buffer)+1,hConv,0L,0,
+ XTYP_EXECUTE,DDE_TIME_OUT,NULL);
+ if (!rc) {
+ KdPrint(("PMNTAddItem: transaction failed\n"));
+ return(FALSE);
+ }
+ DdeFreeDataHandle(rc);
+ return(TRUE);
+
+}
+
+
+BOOL
+PMNTDeleteItem (
+ HCONV hConv, ULONG del_rep, char *szName)
+{
+ char buffer[256];
+ HDDEDATA rc;
+
+
+ if (del_rep == 0)
+ strcpy (buffer,"[DeleteItem(");
+ else
+ strcpy (buffer,"[ReplaceItem(");
+ strcat (buffer,szName);
+ strcat (buffer,")]");
+ rc = DdeClientTransaction((LPBYTE)buffer,strlen(buffer)+1,hConv,0L,0,
+ XTYP_EXECUTE,DDE_TIME_OUT,NULL);
+ if (!rc) {
+ KdPrint(("PMNTDeleteItem: transaction failed\n"));
+ return(FALSE);
+ }
+ DdeFreeDataHandle(rc);
+ return(TRUE);
+}
+
+BOOL
+PMNTGetGrpText(
+ DWORD idInst, HCONV hConv, char *szName, HDDEDATA *phData, PCHAR *ptr_Cf_Text)
+{
+
+ DWORD cbData;
+ HSZ hszItem;
+
+
+ hszItem = DdeCreateStringHandle(idInst,szName,0);
+ *phData = DdeClientTransaction((LPBYTE)NULL,0,hConv,hszItem,CF_TEXT,
+ XTYP_REQUEST,DDE_TIME_OUT,NULL);
+ DdeFreeStringHandle(idInst,hszItem);
+ if (!(*phData)) {
+ KdPrint(("PMNTGetGrpText: transaction failed\n"));
+ return(FALSE);
+ }
+ if (!(*ptr_Cf_Text=DdeAccessData(*phData,&cbData))) {
+ KdPrint(("PMNTGetGrpText: access data failed\n"));
+ DdeFreeDataHandle(*phData);
+ return(FALSE);
+ }
+ return(TRUE);
+
+}
+
+
+
+BOOL
+PMNTGetGroupText(
+ DWORD idInst, HCONV hConv, LONG hGroup, HDDEDATA *phData, PCHAR *ptr_Cf_Text)
+{
+
+ char szGroupName[MAXNAME];
+
+ if (hGroup == (LONG) SGH_ROOT) {
+ strcpy(szGroupName,"PROGMAN");
+ }
+ else
+ if (!(PMNTGetAtomName(hGroup,szGroupName,MAXNAME))) {
+ KdPrint(("PMNTGetGroupText: PMNTGetAtomName failed\n"));
+ return(FALSE);
+ }
+
+ if (!PMNTGetGrpText(idInst,hConv,szGroupName,phData,ptr_Cf_Text)) {
+ return(FALSE);
+ }
+
+ return(TRUE);
+
+}
+
+ULONG
+PMNTChangePrg(
+ DWORD idInst, HCONV hConv, char *szGroup, char *szOldProg,
+ char *szNewProg,char *szExecutable,char *szStartupDir,char *szParameters)
+{
+ char *buffer,*ptr_c,*ptr_buf,*ptr_Cf_Text,szBuf[MAXNAME];
+ HDDEDATA hData,rc;
+ ULONG len;
+ short sucsess=FALSE;
+ short rtl_alloc=FALSE;
+
+
+
+ do {
+ if (!PMNTGetGrpText(idInst,hConv,szGroup,&hData,&ptr_Cf_Text)) {
+ return(FALSE);
+ }
+ if (!ptr_Cf_Text || !(*ptr_Cf_Text)) {
+ break;
+ }
+
+ // activate group
+ if (!PMNTCreateGrp(hConv,szGroup)) {
+ break;
+ }
+
+ // each line ends with CR LF,
+ // format is "name","command",startup dir,iconPath,xPos,yPos,iconindex,hotkey,minimize0x0d 0x0a
+ // 1st line consist the group name
+ // The order of parameters in AddItem is different
+ // "command","name",iconPath,iconIndex,xPos,yPos,startup dir,hotkey,minimize
+ while(*ptr_Cf_Text++ != 0x0a); //1st line
+
+ while (*ptr_Cf_Text) {
+ while (*ptr_Cf_Text++ != '"');
+ PMNTGetThisString(&ptr_Cf_Text,szBuf,MAXNAME);
+ if (!strncmp (szBuf,szOldProg,MAXNAME)) {
+ len = 10;
+ len+=strlen(szNewProg)+3;
+ len+=strlen(szExecutable)+3;
+ if (szParameters)
+ len+=strlen(szParameters)+1;
+ if (szStartupDir) {
+ len+=strlen(szStartupDir)+1;
+ }
+ else {
+ len++;
+ }
+ while (*ptr_Cf_Text++ != ',');
+ while (*ptr_Cf_Text++ != ',');
+ while (*ptr_Cf_Text++ != ',');
+ ptr_c = ptr_Cf_Text;
+ while (*ptr_c++ != 0x0d) len++;
+ len+=3;
+ buffer = RtlAllocateHeap(Od2Heap, 0, len);
+ rtl_alloc = TRUE;
+ strcpy(buffer,"[AddItem(");
+ strcat (buffer,szExecutable);
+ if (szParameters && *szParameters) {
+ ptr_buf = buffer + strlen(buffer);
+ *ptr_buf++ = ' ';
+ strcpy(ptr_buf,szParameters);
+ }
+ strcat (buffer,",");
+ strcat (buffer,szNewProg);
+ strcat (buffer,",");
+ ptr_buf = buffer + strlen(buffer);
+ // keep IconPath
+ while((*ptr_buf++ = *ptr_Cf_Text++) != ',');
+ // keep Icon Index
+ ptr_c = ptr_Cf_Text;
+ while(*ptr_c++ != ',');
+ while(*ptr_c++ != ',');
+ while((*ptr_buf++ = *ptr_c++) != ',');
+ // keep xPos,yPos
+ while((*ptr_buf++ = *ptr_Cf_Text++) != ',');
+ while((*ptr_buf++ = *ptr_Cf_Text++) != ',');
+ if (szStartupDir) {
+ strcpy(ptr_buf,szStartupDir);
+ }
+ ptr_buf += strlen(ptr_buf);
+ *ptr_buf++ = ',';
+ // keep HotKey, Minimize
+ ptr_Cf_Text = ptr_c;
+ while((*ptr_buf++ = *ptr_Cf_Text++) != 0x0d);
+ ptr_buf--;
+ strcpy(ptr_buf,")]");
+ if (!(PMNTDeleteItem(hConv,1L,szOldProg))) {
+ break;
+ }
+ //Add an Item
+ if (!(rc = DdeClientTransaction((LPBYTE)buffer,strlen(buffer)+1,hConv,0L,0,
+ XTYP_EXECUTE,DDE_TIME_OUT,NULL))) {
+ KdPrint(("PMNTChangePrg :transaction failed\n"));
+ break;
+ }
+ DdeFreeDataHandle(rc);
+ sucsess = TRUE;
+ break;
+ }
+ while (*ptr_Cf_Text++ != 0x0a);
+ }
+
+ } while (FALSE);
+
+ if (rtl_alloc) RtlFreeHeap(Od2Heap, 0, buffer);
+ DdeFreeDataHandle(hData);
+ return(sucsess);
+}
+
+
+
+BOOL
+PMNTChangeGrp(
+ DWORD idInst, HCONV hConv, char *szOldGroup, char *szNewGroup)
+{
+ char *buffer,*ptr_c,*ptr_buf,*ptr_Cf_Text,*ptr_xp;
+ HDDEDATA hData,rc;
+ ULONG len,maxbuf;
+ short sucsess=FALSE;
+ short rtl_alloc = FALSE;
+
+
+ do {
+ if (!PMNTGetGrpText(idInst,hConv,szOldGroup,&hData,&ptr_Cf_Text)) {
+ return(FALSE);
+ }
+ if (!ptr_Cf_Text || !(*ptr_Cf_Text)) {
+ break;
+ }
+
+ // create new group
+ if (!PMNTCreateGrp(hConv,szNewGroup)) {
+ break;
+ }
+
+ while(*ptr_Cf_Text++ != 0x0a); //1st line
+ ptr_c = ptr_Cf_Text;
+ maxbuf = 0;
+ while (*ptr_c) {
+ len = 0;
+ while (*ptr_c++ != 0x0a) len++;
+ if (len>maxbuf) maxbuf=len;
+ }
+ maxbuf+=12;
+ buffer = RtlAllocateHeap(Od2Heap, 0, maxbuf);
+ rtl_alloc= TRUE;
+ strcpy(buffer,"[AddItem(");
+
+ while (*ptr_Cf_Text) {
+ ptr_c = ptr_Cf_Text;
+ ptr_buf = buffer+9;
+ //copy cmd (2nd item)
+ while (*ptr_c++ != ',');
+ while ((*ptr_buf++ = *ptr_c++) != ',');
+ //copy name (1st item)
+ while ((*ptr_buf++ = *ptr_Cf_Text++) != ',');
+ ptr_Cf_Text = ptr_c; //both on end of 2nd item
+ //copy IconPath (4th item)
+ while (*ptr_c++ != ',');
+ while ((*ptr_buf++ = *ptr_c++) != ',');
+ ptr_xp = ptr_c; //start of xPosition
+ //copy IconIndex (7th item)
+ while (*ptr_c++ != ',');
+ while (*ptr_c++ != ',');
+ while ((*ptr_buf++ = *ptr_c++) != ',');
+ //copy xy position
+ while ((*ptr_buf++ = *ptr_xp++) != ',');
+ while ((*ptr_buf++ = *ptr_xp++) != ',');
+ //copy start directory
+ while ((*ptr_buf++ = *ptr_Cf_Text++) != ',');
+ //copy HotKey
+ while ((*ptr_buf++ = *ptr_c++) != ',');
+ //copy Minimize flag
+ while ((*ptr_buf++ = *ptr_c++) != 0x0d);
+ --ptr_buf;
+ ptr_Cf_Text = ptr_c;
+ while(*ptr_Cf_Text++ != 0x0a); //1st line
+ strcpy(ptr_buf,")]");
+ //Add an Item
+ if (!(rc = DdeClientTransaction((LPBYTE)buffer,strlen(buffer)+1,hConv,0L,0,
+ XTYP_EXECUTE,DDE_TIME_OUT,NULL))) {
+ KdPrint(("PMNTChangeGrp :transaction of add item failed\n"));
+ break;
+ }
+ DdeFreeDataHandle(rc);
+
+ ptr_Cf_Text = ptr_c;
+ while (*ptr_Cf_Text++ != 0x0a);
+ }
+
+ strcpy (buffer,"[DeleteGroup(");
+ strcat (buffer,szOldGroup);
+ strcat (buffer,",0)]");
+ if (!(rc = DdeClientTransaction((LPBYTE)buffer,strlen(buffer)+1,hConv,0L,0,
+ XTYP_EXECUTE,DDE_TIME_OUT,NULL))) {
+ KdPrint(("PMNTChangeGrp :transaction of delete group failed\n"));
+ break;
+ }
+ sucsess = TRUE;
+ DdeFreeDataHandle(rc);
+ } while (FALSE);
+
+ if (rtl_alloc) RtlFreeHeap(Od2Heap, 0, buffer);
+ DdeFreeDataHandle(hData);
+ return(sucsess);
+}
+
+
+ULONG
+PMNTWinQueryProgramTitles (
+ char *ptr_Cf_Text, LONG hGroup, PPROGRAMENTRY paproge, ULONG cbBuf, PULONG pcTitles)
+
+{
+ PPROGRAMENTRY ptr_proge;
+ char *ptr_Title;
+ ULONG entries;
+ USHORT i;
+
+
+ entries = cbBuf / sizeof(PPROGRAMENTRY);
+ if (!entries) {
+ // request only the no. of programs
+ while(*ptr_Cf_Text)
+ if (*ptr_Cf_Text++ == 0x0a) (*pcTitles)++;
+ if (hGroup != (LONG) SGH_ROOT) (*pcTitles)--;
+ }
+
+ else if (hGroup == (LONG) SGH_ROOT) {
+ // each line ends with CR LF, and consists of a group name
+ while(*pcTitles<entries) {
+ if (!(*ptr_Cf_Text)) break;
+ ptr_proge = &paproge[*pcTitles];
+ ptr_Title = ptr_proge->szTitle;
+ i=0;
+ while((i++<MAXNAME) && (*ptr_Title++ = *ptr_Cf_Text++) != 0x0d);
+ *--ptr_Title = '\0';
+ ptr_proge->hprog=
+ (HPROGRAM)PMNTAddAtom(0L,ptr_proge->szTitle);
+ ptr_proge->progt.progc=PROG_GROUP;
+ ptr_proge->progt.fbVisible=SHE_VISIBLE;
+ (*pcTitles)++;
+ ptr_Cf_Text++;
+ }
+ }
+ else {
+ // each line ends with CR LF,
+ // a program name in " " is in the beginning of each line
+ // followed by other parameters
+ // 1st line consist the group name
+ if (*ptr_Cf_Text) {
+ while(*ptr_Cf_Text++ != 0x0a); //1st line
+ while(*pcTitles<entries) {
+ if (!(*ptr_Cf_Text)) break;
+ ptr_proge = &paproge[*pcTitles];
+ ptr_Title = ptr_proge->szTitle;
+ while(*ptr_Cf_Text++ != '"');
+ i=0;
+ while((i++<MAXNAME) && ((*ptr_Title++=*ptr_Cf_Text++) != '"'));
+ *--ptr_Title = '\0';
+ ptr_proge->hprog=
+ (HPROGRAM)PMNTAddAtom((ULONG)hGroup,ptr_proge->szTitle);
+ ptr_proge->progt.progc=PROG_DEFAULT;
+ ptr_proge->progt.fbVisible=SHE_VISIBLE;
+ (*pcTitles)++;
+ while(*ptr_Cf_Text++ != 0x0a);
+ }
+ }
+ }
+ return(1L);
+}
+
+ULONG
+PMNTPrfQueryProgramTitles (
+ char *start_Cf_Text, LONG hGroup, PPROGTITLE paprogti, ULONG cbBuf, PULONG pcTitles)
+
+{
+ PPROGTITLE ptr_progti;
+ char *ptr_Title;
+ ULONG Length,i,uTitles;
+ char *ptr_Cf_Text,*st_Title;
+
+
+ *pcTitles=0;
+ Length=i=0;
+ ptr_Cf_Text = start_Cf_Text;
+
+
+ //calculate no. of items, and needed length
+ if (hGroup== (LONG) SGH_ROOT) {
+ // each line ends with CR LF,
+ while (*ptr_Cf_Text) {
+ while(*ptr_Cf_Text++ != 0x0d) i++;
+ (*pcTitles)++;
+ ptr_Cf_Text++;
+ }
+ }
+ else {
+
+ // each line ends with CR LF,
+ // a program name in " " is in the beginning of each line
+ // followed by other parameters
+ // 1st line consist the group name
+ if (*ptr_Cf_Text) {
+ while(*ptr_Cf_Text++ != 0x0a); //1st line
+ while (*ptr_Cf_Text) {
+ while(*ptr_Cf_Text++ != '"');
+ while(*ptr_Cf_Text++ != '"') i++;
+ (*pcTitles)++;
+ while(*ptr_Cf_Text++ != 0x0a);
+ }
+ }
+ }
+ Length = ((ULONG)(sizeof(PROGTITLE)+1) * (*pcTitles)) + i;
+
+ if (cbBuf) {
+ //the contents should be copied
+ if (Length > cbBuf) {
+ return(0L);
+ }
+ ptr_Title = (char *) &paprogti[*pcTitles];
+ ptr_Cf_Text = start_Cf_Text;
+ uTitles= 0;
+
+ if (hGroup == (LONG) SGH_ROOT) {
+ // each line ends with CR LF, and consists of a group name
+
+ while (*ptr_Cf_Text) {
+ st_Title = ptr_Title;
+ ptr_progti = &paprogti[uTitles++];
+ ptr_progti->pszTitle = (void *) FLATTOFARPTR(st_Title);
+ while((*ptr_Title++ = *ptr_Cf_Text++) != 0x0d);
+ *(ptr_Title-1) = '\0';
+ ptr_progti->hprog=
+ (HPROGRAM)PMNTAddAtom(0L,st_Title);
+ ptr_progti->progt.progc=PROG_GROUP;
+ ptr_progti->progt.fbVisible=SHE_VISIBLE;
+ ptr_Cf_Text++;
+ }
+ }
+ else {
+ // each line ends with CR LF,
+ // a program name in " " is in the beginning of each line
+ // followed by other parameters
+ // 1st line consist the group name
+ if (*ptr_Cf_Text) {
+ while(*ptr_Cf_Text++ != 0x0a); //1st line
+ while (*ptr_Cf_Text) {
+ st_Title = ptr_Title;
+ ptr_progti = &paprogti[uTitles++];
+ ptr_progti->pszTitle = (void *) FLATTOFARPTR(st_Title);
+ while(*ptr_Cf_Text++ != '"');
+ while((*ptr_Title++=*ptr_Cf_Text++) != '"');
+ *(ptr_Title-1) = '\0';
+ ptr_progti->hprog=
+ (HPROGRAM)PMNTAddAtom((ULONG)hGroup,st_Title);
+ ptr_progti->progt.progc=PROG_DEFAULT;
+ ptr_progti->progt.fbVisible=SHE_VISIBLE;
+ while(*ptr_Cf_Text++ != 0x0a);
+ }
+ }
+ }
+ }
+ return(Length);
+}
+
+ULONG
+PMNTWinQueryDefinition (
+ char *ptr_Cf_Text, char *szName, PPIBSTRUCT ppib, ULONG cbBuf)
+
+{
+ char szBuf[MAXNAME],*ptr_buf,*ptr_par;
+ ULONG Length = sizeof(PIBSTRUCT),len,maxbuf,param;
+
+
+
+ if (cbBuf) {
+ memset((char *)ppib,(int) 0,cbBuf);
+ ppib->progt.fbVisible=SHE_VISIBLE;
+ ppib->progt.progc= (ptr_Cf_Text) ? PROG_DEFAULT : PROG_GROUP;
+ strcpy(ppib->szTitle,szName);
+ }
+
+
+ if (ptr_Cf_Text) {
+ //if it is a program (and not a group)we should query other parameters
+ // each line ends with CR LF,
+ // format is "name","command",startup dir,iconPath,xPos,yPos,iconindex,hotkey,minimize0x0d 0x0a
+ // 1st line consist the group name
+ while(*ptr_Cf_Text++ != 0x0a); //1st line
+ while (*ptr_Cf_Text) {
+ while (*ptr_Cf_Text++ != '"');
+ PMNTGetThisString(&ptr_Cf_Text,szBuf,MAXNAME);
+ if (!strncmp (szBuf,szName,MAXNAME)) {
+ if (cbBuf) {
+ ptr_buf = ppib->szExecutable;
+ maxbuf = MAXPATHL+1;
+ ptr_par = (char *)ppib+Length;
+ ppib->pchProgramParameter = (void *) FLATTOFARPTR(ptr_par);
+ }
+ else {
+ ptr_buf = NULL;
+ maxbuf = 0;
+ }
+ Length++;
+ len = PMNTGetNextString1(&ptr_Cf_Text,ptr_buf,maxbuf,&param);
+ if (cbBuf) ptr_buf = ptr_par;
+ if (len && param) {
+ len = PMNTGetThisString(&ptr_Cf_Text,ptr_buf,maxbuf);
+ }
+ else
+ len = 0;
+ if (cbBuf) ppib->cchProgramParameter = (USHORT)(len+1);
+ Length += len;
+
+ if (cbBuf) {
+ PMNTGetNextString0(&ptr_Cf_Text,ppib->szStartupDir,maxbuf);
+ }
+ break;
+ }
+ }
+ }
+ return(Length+2);
+}
+
+
+ULONG
+PMNTPrfQueryDefinition (
+ char *ptr_Cf_Text, char *szName, PPROGDETAILS pprogde, ULONG cbBuf)
+
+{
+ char szBuf[MAXNAME],*ptr_st,*ptr_buf;
+ ULONG Length = sizeof(PROGDETAILS),len,maxbuf,param;
+
+
+
+ if (cbBuf) {
+ ptr_st = (char *) pprogde;
+ memset(ptr_st,(int) 0,cbBuf);
+ pprogde->Length = Length;
+ pprogde->progt.fbVisible=SHE_VISIBLE;
+ pprogde->progt.progc= (ptr_Cf_Text) ? PROG_DEFAULT : PROG_GROUP;
+ ptr_buf = ptr_st + Length;
+ pprogde->pszTitle= (void *) FLATTOFARPTR (ptr_buf);
+ strcpy(ptr_buf,szName);
+ }
+ Length += strlen(szName)+1;
+
+
+
+ if (ptr_Cf_Text) {
+ //if it is a program (and not a group)we should query other parameters
+ // each line ends with CR LF,
+ // format is "name","command",startup dir,iconPath,xPos,yPos,iconindex,hotkey,minimize0x0d 0x0a
+ // 1st line consist the group name
+ while(*ptr_Cf_Text++ != 0x0a); //1st line
+ while (*ptr_Cf_Text) {
+ while (*ptr_Cf_Text++ != '"');
+ PMNTGetThisString(&ptr_Cf_Text,szBuf,MAXNAME);
+ if (!strncmp (szBuf,szName,MAXNAME)) {
+ if (cbBuf) {
+ ptr_buf = ptr_st+Length;
+ pprogde->pszExecutable = (void *) FLATTOFARPTR(ptr_buf);
+ maxbuf = MAXPATHL+1;
+ }
+ else {
+ ptr_buf = NULL;
+ maxbuf = 0;
+ }
+ len = PMNTGetNextString1(&ptr_Cf_Text,ptr_buf,maxbuf,&param);
+ Length+= len+1;
+ if (cbBuf) {
+ ptr_buf = ptr_st+Length;
+ pprogde->pszParameters= (void *) FLATTOFARPTR(ptr_buf);
+ }
+ if (len && param) {
+ len = PMNTGetThisString(&ptr_Cf_Text,ptr_buf,maxbuf);
+ }
+ else
+ len = 0;
+ Length += len+1;
+
+ if (cbBuf) {
+ ptr_buf = ptr_st+Length;
+ pprogde->pszStartupDir= (void *) FLATTOFARPTR(ptr_buf);
+
+ }
+ len = PMNTGetNextString0(&ptr_Cf_Text,ptr_buf,maxbuf);
+ Length+=len+1;
+ if (cbBuf) {
+ ptr_buf = ptr_st+Length;
+ pprogde->pszIcon=(void *) FLATTOFARPTR(ptr_buf);
+ }
+ Length++;
+ break;
+ }
+ }
+ }
+ return(Length);
+}
+
+// This function establishes the connection with progman
+
+BOOL
+PMNTDdeConnect(
+ DWORD *pidInst, HCONV *phConv)
+{
+ HSZ hszService,hszTopic;
+
+ *pidInst = 0L;
+ if (DdeInitialize (pidInst,NULL,
+ APPCLASS_STANDARD|APPCMD_CLIENTONLY, 0L)) {
+
+ KdPrint(("PMNTDdeConnect : DdeInitialize failed\n"));
+ return(FALSE);
+ }
+
+ hszService = DdeCreateStringHandle(*pidInst,"PROGMAN",0);
+ hszTopic = DdeCreateStringHandle(*pidInst,"PROGMAN",0);
+ *phConv = DdeConnect(*pidInst,hszService,hszTopic,NULL);
+ DdeFreeStringHandle(*pidInst,hszService);
+ DdeFreeStringHandle(*pidInst,hszTopic);
+ if (*phConv == (HCONV) 0) {
+ KdPrint(("PMNTDdeConnect : DdeConnect failed\n"));
+ DdeUninitialize(*pidInst);
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+// The following API's are exported API's that implement PM API's.
+// The naming convention is: Win___, Prf___ are implemented by PMNT___
+
+
+ULONG
+PMNTCreateGroup(
+ PSZ GroupName, PULONG phGroup)
+{
+
+
+ DWORD idInst;
+ BOOL sucsess;
+ HCONV hConv;
+
+
+ *phGroup = 0L;
+ sucsess = FALSE;
+ if (!GroupName || !(*GroupName)) {
+ return(0L);
+ }
+
+ do {
+ if (!PMNTDdeConnect(&idInst,&hConv)) {
+ return(0L);
+ }
+ if (!(PMNTCreateGrp(hConv,GroupName))) {
+ break;
+ }
+ sucsess = (BOOL) (*phGroup = PMNTAddAtom(0L,GroupName));
+
+ } while (FALSE);
+
+
+ DdeDisconnect(hConv);
+ DdeUninitialize(idInst);
+ return(sucsess);
+
+}
+
+
+
+ULONG
+PMNTQueryProgramTitles(
+ ULONG win_prf, LONG hGroup, PVOID ProgTitles, ULONG cbBuf, PULONG pcTitles)
+{
+
+
+ DWORD idInst;
+ HCONV hConv;
+ HDDEDATA hData;
+ PCHAR ptr_Cf_Text;
+ ULONG Length;
+
+ *pcTitles=0;
+ Length=0;
+
+ do {
+ if (cbBuf) Od2ProbeForWrite(ProgTitles,1,1);
+ if (!PMNTDdeConnect(&idInst,&hConv)) {
+ return(0L);
+ }
+ if (!PMNTGetGroupText(idInst,hConv,hGroup,&hData,&ptr_Cf_Text)) {
+ break;
+ }
+
+ if (win_prf == 0L) {
+ Length = PMNTWinQueryProgramTitles(
+ ptr_Cf_Text,hGroup,ProgTitles,cbBuf,pcTitles);
+ }
+ else {
+ Length = PMNTPrfQueryProgramTitles(
+ ptr_Cf_Text,hGroup,ProgTitles,cbBuf,pcTitles);
+ }
+ DdeFreeDataHandle(hData);
+
+ } while (FALSE);
+
+
+ DdeDisconnect(hConv);
+ DdeUninitialize(idInst);
+ return(Length);
+
+}
+
+ULONG
+PMNTQueryDefinition(
+ ULONG win_prf, LONG hProg, PVOID ProgDefinition, ULONG cbBuf)
+{
+
+
+ DWORD idInst;
+ HCONV hConv;
+ HDDEDATA hData;
+ PCHAR ptr_Cf_Text;
+ ULONG Length;
+ LONG hGroup;
+ char szName[MAXNAME];
+
+ Length=0;
+ hData = 0;
+
+ do {
+ if (cbBuf) Od2ProbeForWrite(ProgDefinition,1,1);
+ if (!PMNTDdeConnect(&idInst,&hConv)) {
+ return(0L);
+ }
+
+ if (!(PMNTGetAtomName(hProg,szName,MAXNAME))) {
+ KdPrint(("PMNTQueryDefinition : PMNTGetAtomName failed\n"));
+ break;
+ }
+
+ ptr_Cf_Text = NULL;
+ if (hGroup = (hProg>>16)) {
+ if (!PMNTGetGroupText(idInst,hConv,hGroup,&hData,&ptr_Cf_Text)) {
+ break;
+ }
+ }
+
+ if (win_prf == 0L) {
+ Length = PMNTWinQueryDefinition(
+ ptr_Cf_Text,szName,ProgDefinition,cbBuf);
+ }
+ else {
+ Length = PMNTPrfQueryDefinition(
+ ptr_Cf_Text,szName,ProgDefinition,cbBuf);
+ }
+
+ if (hData) DdeFreeDataHandle(hData);
+ } while (FALSE);
+
+
+ DdeDisconnect(hConv);
+ DdeUninitialize(idInst);
+ return(Length);
+
+}
+
+
+ULONG
+PMNTQueryProgramHandle(
+ PCHAR PathNameOS2, PHPROGARRAY phpga, ULONG cb, PULONG pcHandles)
+{
+
+
+ DWORD idInst;
+ HCONV hConv;
+ HDDEDATA hDataG,hDataP;
+ ULONG Length;
+
+ ULONG len,entries,param,hGroup,hProg,i,FileFlags,FileType;
+ char GroupName[MYMAXBUF];
+ char ProgName[MYMAXBUF];
+ char FileNameNT[MYMAXBUF];
+ char StartDir[MYMAXBUF];
+ STRING CanonicNameNT,CanonicNameOS2;
+ char *ptr_Cf_Root,*ptr_Cf_Text,*ptr_grp;
+
+
+ *pcHandles=0;
+ Length=0;
+ entries = cb / sizeof(HPROGRAM);
+
+ do {
+ if (cb) Od2ProbeForWrite(phpga,1,1);
+ if (!PMNTDdeConnect(&idInst,&hConv)) {
+ return(0L);
+ }
+ if (!PMNTGetGroupText(idInst,hConv,(LONG)SGH_ROOT,&hDataG,&ptr_Cf_Root)) {
+ break;
+ }
+
+ while(*ptr_Cf_Root) {
+ // get group name
+ ptr_grp = GroupName;
+ i=0;
+ while((i++<MYMAXBUF) && ((*ptr_grp++ = *ptr_Cf_Root++) != 0x0d));
+ *--ptr_grp = '\0';
+ // get group programs
+ if (!PMNTGetGrpText(idInst,hConv,GroupName,&hDataP,&ptr_Cf_Text)) {
+ break;
+ }
+ while(*ptr_Cf_Text++ != 0x0a); // skip 1st line
+ while (*ptr_Cf_Text) {
+ while (*ptr_Cf_Text++ != '"');
+ PMNTGetThisString(&ptr_Cf_Text,ProgName,MYMAXBUF);
+ len = PMNTGetNextString1(&ptr_Cf_Text,FileNameNT,MYMAXBUF,&param);
+ if (len && param) {
+ PMNTGetThisString(&ptr_Cf_Text,NULL,0L);
+ }
+ PMNTGetNextString0(&ptr_Cf_Text,StartDir,MYMAXBUF);
+ while(*ptr_Cf_Text++ != 0x0a); // goto end of line of program
+ if (!PMNTGetFullPath(FileNameNT,StartDir,&CanonicNameNT)) {
+ break;
+ }
+ if (Od2Canonicalize(PathNameOS2,CANONICALIZE_FILE_OR_DEV
+ ,&CanonicNameOS2,NULL,&FileFlags,&FileType)) {
+ RtlFreeHeap(Od2Heap, 0, CanonicNameNT.Buffer);
+ break;
+ }
+ strupr(CanonicNameNT.Buffer);
+ strupr(CanonicNameOS2.Buffer);
+ if (!strcmp(CanonicNameOS2.Buffer,CanonicNameNT.Buffer)) {
+ if (*pcHandles < entries) {
+ hGroup = PMNTAddAtom(0L,GroupName);
+ hProg = PMNTAddAtom(hGroup,ProgName);
+ phpga->ahprog[*pcHandles] = (HPROGRAM) hProg;
+ }
+ else if (cb) {
+ // buffer is not large enough
+ *pcHandles = 0L;
+ return(0L);
+ }
+ Length += sizeof(HPROGRAM);
+ (*pcHandles)++;
+ }
+
+ RtlFreeHeap(Od2Heap, 0, CanonicNameNT.Buffer);
+ RtlFreeHeap(Od2Heap, 0, CanonicNameOS2.Buffer);
+ }
+ DdeFreeDataHandle(hDataP); // free data of ptr_Cf_Text
+ while(*ptr_Cf_Root++ != 0x0a); // goto end of line of group
+ }
+
+
+
+ DdeFreeDataHandle(hDataG);
+
+ } while (FALSE);
+
+
+ DdeDisconnect(hConv);
+ DdeUninitialize(idInst);
+ return(Length);
+
+}
+
+
+
+ULONG
+PMNTAddProgram(
+ ULONG hGroupHandle,PCHAR szTitle,PCHAR szExecutable,PCHAR szStartupDir,
+ PCHAR szParameters, PULONG phProg)
+{
+ DWORD idInst;
+ char szGroupName[MAXNAME];
+ short sucsess;
+ HCONV hConv;
+
+ *phProg = 0L;
+ sucsess = FALSE;
+ if (!(szTitle) || !(*szTitle)) {
+ return(0L);
+ }
+ if (!(szExecutable) || !(*szExecutable)) {
+ return(0L);
+ }
+
+ do {
+ if (!PMNTDdeConnect(&idInst,&hConv)) {
+ return(0L);
+ }
+
+ if (!(PMNTGetAtomName(hGroupHandle,szGroupName,MAXNAME))) {
+ break;
+ }
+ if (!(PMNTCreateGrp(hConv,szGroupName))) {
+ break;
+ }
+ if (!(PMNTAddItem(hConv,szTitle,szExecutable,szStartupDir,szParameters))) {
+ break;
+ }
+ sucsess = (BOOL) (*phProg = PMNTAddAtom(hGroupHandle,szTitle));
+
+ } while (FALSE);
+
+
+ DdeDisconnect(hConv);
+ DdeUninitialize(idInst);
+ return(sucsess);
+
+}
+
+
+
+ULONG
+PMNTChangeProgram(
+ ULONG hProg,PCHAR szTitle,PCHAR szExecutable,PCHAR szStartupDir,
+ PCHAR szParameters)
+{
+ DWORD idInst;
+ char szParentName[MAXNAME];
+ char szName[MAXNAME];
+ short sucsess,changed_name;
+ ULONG hParent;
+ HCONV hConv;
+ HDDEDATA hData = 0;
+
+
+ sucsess = FALSE;
+ if (!(szTitle) || !(*szTitle)) {
+ return(0L);
+ }
+ if (hParent = (hProg>>16)) {
+ if (!(szExecutable) || !(*szExecutable)) {
+ return(0L);
+ }
+ }
+
+ do {
+ if (!PMNTDdeConnect(&idInst,&hConv)) {
+ return(0L);
+ }
+
+ if (!(PMNTGetAtomName(hProg,szName,MAXNAME))) {
+ break;
+ }
+ changed_name = strncmp(szName,szTitle,MAXNAME);
+ if (hParent) {
+ // should change a program item
+ // make its group active
+ PMNTGetAtomName(hParent,szParentName,MAXNAME);
+ if (!PMNTChangePrg(idInst,hConv,szParentName,szName
+ ,szTitle,szExecutable,szStartupDir,szParameters)) {
+ break;
+ }
+ }
+ else {
+ // should change a group , the only thing we should care about is its name
+ if (changed_name) {
+ if (!PMNTChangeGrp(idInst,hConv,szName,szTitle)) {
+ break;
+ }
+ }
+ }
+ if (changed_name) {
+ PMNTRenameAtom(hProg,szTitle);
+ }
+ sucsess = TRUE;
+
+ } while (FALSE);
+
+
+ DdeDisconnect(hConv);
+ DdeUninitialize(idInst);
+ return(sucsess);
+
+}
+
+
+BOOL
+PMNTDestroyGroup(
+ LONG hGroupHandle)
+{
+
+
+ DWORD idInst;
+ char buffer[256];
+ char szGroupName[MAXNAME];
+ short sucsess;
+ HCONV hConv;
+ HDDEDATA rc;
+
+
+ sucsess = FALSE;
+
+ do {
+ if (!PMNTDdeConnect(&idInst,&hConv)) {
+ return(FALSE);
+ }
+
+ PMNTGetAtomName(hGroupHandle,szGroupName,MAXNAME);
+
+ strcpy (buffer,"[DeleteGroup(");
+ strcat (buffer,szGroupName);
+ strcat (buffer,",0)]");
+ rc = DdeClientTransaction((LPBYTE)buffer,strlen(buffer)+1,hConv,0L,0,
+ XTYP_EXECUTE,DDE_TIME_OUT,NULL);
+
+ if (!rc) {
+ KdPrint(("PMNTDestroyGroup : transaction failed\n"));
+ break;
+ }
+ DdeFreeDataHandle(rc);
+ sucsess = TRUE;
+
+ } while (FALSE);
+
+
+ DdeDisconnect(hConv);
+ DdeUninitialize(idInst);
+ return(sucsess);
+
+}
+
+
+
+BOOL
+PMNTRemoveProgram(
+ LONG hProg)
+{
+
+
+ DWORD idInst;
+ char szName[MAXNAME];
+ short sucsess;
+ HCONV hConv;
+ ULONG hGroup;
+
+
+ sucsess = FALSE;
+
+ do {
+ if (!PMNTDdeConnect(&idInst,&hConv)) {
+ return(FALSE);
+ }
+
+ hGroup = (hProg>>16);
+
+ PMNTGetAtomName(hGroup,szName,MAXNAME);
+
+ if (!(PMNTCreateGrp(hConv,szName))) {
+ break;
+ }
+
+ PMNTGetAtomName(hProg,szName,MAXNAME);
+
+ if (!(PMNTDeleteItem(hConv,0L,szName))) {
+ break;
+ }
+
+ sucsess = TRUE;
+
+ } while (FALSE);
+
+
+ DdeDisconnect(hConv);
+ DdeUninitialize(idInst);
+ return(sucsess);
+
+}
+
+/*****************************************/
+/* PM <-> WIN32 CLIPBOARD implementation */
+/*****************************************/
+
+#define PMNT_CF_TEXT 1
+#define PMNT_CF_BITMAP 2
+
+SEL QuerySel=0;
+
+ULONG
+PMNTOpenClipbrd(
+ IN HWND hwnd)
+{
+ return((ULONG) OpenClipboard(hwnd));
+}
+
+
+ULONG
+PMNTCloseClipbrd(
+ )
+{
+ if (QuerySel)
+ {
+ DosFreeSeg(QuerySel);
+ QuerySel=0;
+ }
+ return((ULONG) CloseClipboard());
+}
+
+
+ULONG
+PMNTEmptyClipbrd(
+ )
+{
+ return ((ULONG) EmptyClipboard());
+}
+
+
+ULONG
+PMNTSetClipbrdText(
+ IN ULONG ulData)
+{
+ HANDLE handle;
+ char *ptrData,*ptrCopy;
+ DWORD cb;
+ SEL sel;
+
+ if (ulData) {
+ sel = (SEL) ulData;
+ ptrData = SELTOFLAT(sel);
+ cb = strlen(ptrData) + 1;
+ if (!(handle = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE,cb))) {
+ return((ULONG) FALSE);
+ }
+ if (!(ptrCopy = GlobalLock(handle))) {
+ return((ULONG) FALSE);
+ }
+ while(*ptrCopy++=*ptrData++);
+ GlobalUnlock(handle);
+ }
+ else {
+ handle=NULL;
+ }
+
+ return ((SetClipboardData(CF_TEXT,handle)) ? (ULONG) TRUE : (ULONG) FALSE);
+
+}
+
+
+ULONG
+PMNTSetClipbrdBitmap(
+ IN PBITMAPCOREINFO pbmiPM, IN PVOID lpbInit)
+{
+ HBITMAP hbitmap;
+ HDC hdc;
+ USHORT no_of_colors,i;
+ PBITMAPINFO pbmi;
+ SEL selBitmapInfo;
+ USHORT cbBitmapInfo;
+ ULONG rc = FALSE;
+
+
+ if (! pbmiPM) {
+ return ((SetClipboardData(CF_BITMAP,NULL)) ? (ULONG) TRUE : (ULONG) FALSE);
+ }
+ no_of_colors = (pbmiPM->bmciHeader.bcBitCount <= 8)
+ ? (1 << pbmiPM->bmciHeader.bcBitCount) : 0;
+ cbBitmapInfo = sizeof(BITMAPINFO) + (sizeof(RGBQUAD) * (no_of_colors));
+
+ if (DosAllocSeg (cbBitmapInfo,&selBitmapInfo,0)) {
+ KdPrint(("PMNTSetClipbrdBitmap(): DosAllocSeg() failed\n"));
+ return(FALSE);
+ }
+
+ pbmi = SELTOFLAT(selBitmapInfo);
+ pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ pbmi->bmiHeader.biWidth = pbmiPM->bmciHeader.bcWidth;
+ pbmi->bmiHeader.biHeight = pbmiPM->bmciHeader.bcHeight;
+ pbmi->bmiHeader.biPlanes = 1;
+ pbmi->bmiHeader.biBitCount = pbmiPM->bmciHeader.bcBitCount;
+ pbmi->bmiHeader.biCompression = BI_RGB;
+ pbmi->bmiHeader.biSizeImage = 0;
+ pbmi->bmiHeader.biXPelsPerMeter = 0;
+ pbmi->bmiHeader.biYPelsPerMeter = 0;
+ pbmi->bmiHeader.biClrUsed = 0;
+ pbmi->bmiHeader.biClrImportant = 0;
+
+ for (i=0;i<no_of_colors;i++) {
+ pbmi->bmiColors[i].rgbBlue = pbmiPM->bmciColors[i].rgbtBlue;
+ pbmi->bmiColors[i].rgbGreen = pbmiPM->bmciColors[i].rgbtGreen;
+ pbmi->bmiColors[i].rgbRed = pbmiPM->bmciColors[i].rgbtRed;
+ pbmi->bmiColors[i].rgbReserved = 0;
+ }
+
+ if (! (hdc = CreateDC("DISPLAY",NULL,NULL,NULL))) {
+ KdPrint(("PMNTSetClipbrdBitmap: CreateDC() faild\n"));
+ goto exit_set_bitmap_1;
+ }
+ if (! ( hbitmap = CreateDIBitmap(hdc,&(pbmi->bmiHeader),CBM_INIT,lpbInit,pbmi,DIB_RGB_COLORS))){
+ KdPrint(("PMNTSetClipbrdBitmap: CreateDIBitmap() faild\n"));
+ goto exit_set_bitmap_2;
+ }
+
+ rc = (SetClipboardData(CF_BITMAP,(HANDLE)hbitmap)) ? (ULONG) TRUE : (ULONG) FALSE;
+
+exit_set_bitmap_2:
+ DeleteDC(hdc);
+exit_set_bitmap_1:
+ DosFreeSeg(selBitmapInfo);
+ return(rc);
+}
+
+
+void
+PMNTQueryClipbrdText(
+ OUT PULONG pulData)
+{
+ HANDLE handle;
+ char *ptrData,*ptrCopy;
+ USHORT cb;
+
+ *pulData=0;
+ if (!(handle = GetClipboardData(CF_TEXT))) {
+ return;
+ }
+ if (!(ptrData = GlobalLock(handle))) {
+ return;
+ }
+ cb = strlen(ptrData) + 1;
+ if (QuerySel) {
+ DosFreeSeg(QuerySel);
+ }
+ if (DosAllocSeg(cb,&QuerySel,0)) {
+ KdPrint(("PMNTQueryClipbrdData: cannot allocate memory\n"));
+ return;
+ }
+ *pulData = (ULONG) QuerySel;
+ if (ptrCopy = SELTOFLAT(QuerySel)) {
+ while(*ptrCopy++=*ptrData++);
+ }
+ GlobalUnlock(handle);
+
+}
+
+
+ULONG
+PMNTQueryClipbrdBitmap(
+ OUT PBITMAPCOREINFO *ppbmiPM, OUT PVOID *ppbBuffer)
+{
+ HBITMAP hbitmap;
+ HDC hdc;
+ USHORT no_of_colors,i;
+ BITMAPINFO bmi;
+ PBITMAPINFO pbmi;
+ SEL selBitmapInfo,selBuffer;
+ USHORT cbBitmapInfo;
+ ULONG cbBuffer;
+ USHORT absHeight,absWidth;
+ ULONG rc = (ULONG)FALSE;
+
+
+ *ppbmiPM = NULL;
+ *ppbBuffer = NULL;
+
+ if (!(hbitmap = (HBITMAP) GetClipboardData(CF_BITMAP))) {
+ return((ULONG) FALSE);
+ }
+ if (! (hdc = CreateDC("DISPLAY",NULL,NULL,NULL))) {
+ KdPrint(("PMNTQueryClipbrdBitmap: CreateDC() faild\n"));
+ return((ULONG) FALSE);
+ }
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biBitCount = 0;
+ GetDIBits(hdc,hbitmap,0,0,NULL,&bmi,DIB_RGB_COLORS);
+ absHeight = abs(bmi.bmiHeader.biHeight);
+ absWidth = abs(bmi.bmiHeader.biWidth);
+
+ if (bmi.bmiHeader.biHeight < 0) {
+ KdPrint(("PMNTQueryClipbrdBitmap: biHeight=%lx\n",bmi.bmiHeader.biHeight));
+ }
+ if (bmi.bmiHeader.biWidth < 0) {
+ KdPrint(("PMNTQueryClipbrdBitmap: biWidth=%lx\n",bmi.bmiHeader.biWidth));
+ }
+ if (bmi.bmiHeader.biPlanes != 1) {
+ KdPrint(("PMNTQueryClipbrdBitmap: biPlanes=%x\n",bmi.bmiHeader.biPlanes));
+ bmi.bmiHeader.biPlanes=1;
+ }
+ if (bmi.bmiHeader.biCompression) {
+ KdPrint(("PMNTQueryClipbrdBitmap: biCompression=%lx\n",bmi.bmiHeader.biCompression));
+ bmi.bmiHeader.biCompression = BI_RGB;
+ }
+ if (bmi.bmiHeader.biXPelsPerMeter) {
+ KdPrint(("PMNTQueryClipbrdBitmap: biXPelsPerMeter=%lx\n",bmi.bmiHeader.biXPelsPerMeter));
+ bmi.bmiHeader.biXPelsPerMeter = 0;
+ }
+ if (bmi.bmiHeader.biYPelsPerMeter) {
+ KdPrint(("PMNTQueryClipbrdBitmap: biYPelsPerMeter=%lx\n",bmi.bmiHeader.biYPelsPerMeter));
+ bmi.bmiHeader.biYPelsPerMeter = 0;
+ }
+ bmi.bmiHeader.biClrUsed = 0;
+ bmi.bmiHeader.biClrImportant = 0;
+
+ if (bmi.bmiHeader.biBitCount == 16 || bmi.bmiHeader.biBitCount == 32) {
+ KdPrint(("PMNTQueryClipbrdBitmap: BitCount = %x\n",bmi.bmiHeader.biBitCount));
+ bmi.bmiHeader.biBitCount = 24;
+ }
+
+ no_of_colors = (bmi.bmiHeader.biBitCount <= 8)
+ ? (1 << bmi.bmiHeader.biBitCount) : 0;
+ cbBitmapInfo = sizeof(BITMAPINFO) + (sizeof(RGBQUAD) * (no_of_colors));
+
+ if (DosAllocSeg (cbBitmapInfo,&selBitmapInfo,0)) {
+ KdPrint(("PMNTQueryClipbrdBitmap: 1st DosAllocSeg() failed\n"));
+ goto exit_query_bitmap;
+ }
+ pbmi = SELTOFLAT(selBitmapInfo);
+ pbmi->bmiHeader = bmi.bmiHeader;
+
+ cbBuffer = (((bmi.bmiHeader.biBitCount * absWidth) + 31)/32)
+ * 4 * absHeight;
+ if (cbBuffer <= _64K) {
+ if (DosAllocSeg ((USHORT)cbBuffer,&selBuffer,0)) {
+ KdPrint(("PMNTQueryClipbrdBitmap: 2nd DosAllocSeg() failed\n"));
+ goto exit_query_bitmap;
+ }
+ }
+ else {
+ if (DosAllocHuge(cbBuffer / _64K , (USHORT)(cbBuffer % _64K) , &selBuffer, 0L,0)) {
+ KdPrint(("PMNTQueryClipbrdBitmap: DosAllocHuge() failed\n"));
+ goto exit_query_bitmap;
+ }
+ }
+ *ppbBuffer = SELTOFLAT(selBuffer);
+
+
+ if (!(GetDIBits(hdc,hbitmap,0,absHeight,*ppbBuffer,pbmi,DIB_RGB_COLORS))){
+ KdPrint(("PMNTQueryClipbrdBitmap(): 2nd GetDiBits failed\n"));
+ goto exit_query_bitmap;
+ }
+
+ if (bmi.bmiHeader.biBitCount == 16 || bmi.bmiHeader.biBitCount == 32) {
+ KdPrint(("PMNTQueryClipbrdBitmap: BitCount = %x\n",bmi.bmiHeader.biBitCount));
+ bmi.bmiHeader.biBitCount = 24;
+ }
+
+ *ppbmiPM = (PBITMAPCOREINFO) pbmi;
+
+ (*ppbmiPM)->bmciHeader.bcSize = sizeof(BITMAPCOREHEADER);
+ (*ppbmiPM)->bmciHeader.bcWidth = absWidth;
+ (*ppbmiPM)->bmciHeader.bcHeight = absHeight;
+ (*ppbmiPM)->bmciHeader.bcPlanes = 1;
+ (*ppbmiPM)->bmciHeader.bcBitCount = bmi.bmiHeader.biBitCount;
+
+ for (i=0;i<no_of_colors;i++) {
+ (*ppbmiPM)->bmciColors[i].rgbtBlue = pbmi->bmiColors[i].rgbBlue;
+ (*ppbmiPM)->bmciColors[i].rgbtGreen = pbmi->bmiColors[i].rgbGreen;
+ (*ppbmiPM)->bmciColors[i].rgbtRed = pbmi->bmiColors[i].rgbRed;
+ }
+
+
+ *ppbmiPM = (void *) FLATTOFARPTR((*ppbmiPM));
+ *ppbBuffer = (void *) FLATTOFARPTR((*ppbBuffer));
+ rc = (ULONG) TRUE;
+
+exit_query_bitmap:
+ DeleteDC(hdc);
+ return(rc);
+
+}
+
+
+
+ULONG
+PMNTQueryClipbrdFmtInfo(
+ IN ULONG fmt, OUT PUSHORT pfsFmtInfo)
+{
+ ULONG exist_fmt;
+
+ exist_fmt = (*pfsFmtInfo) = 0;
+
+ if (fmt == PMNT_CF_TEXT) {
+ if (exist_fmt = (ULONG) IsClipboardFormatAvailable(CF_TEXT)) {
+ *pfsFmtInfo = CFI_SELECTOR;
+ }
+ }
+ else if (fmt == PMNT_CF_BITMAP) {
+ if (exist_fmt = (ULONG) IsClipboardFormatAvailable(CF_BITMAP)) {
+ *pfsFmtInfo = CFI_HANDLE;
+ }
+ }
+
+ return(exist_fmt);
+}
+
+
+
+long FAR PASCAL WndProc(HWND,UINT,WPARAM,LPARAM);
+typedef struct _CLIPBRDDATA {
+ ULONG SemPM;
+ ULONG SemWin32;
+ ULONG hwnd;
+ ULONG fempty;
+ USHORT QueryFmt;
+} CLIPBRDDATA;
+typedef CLIPBRDDATA FAR *PCLIPBRDDATA;
+PCLIPBRDDATA pClipbrdData=NULL;
+
+ULONG
+PMNTWin32Clipbrd(
+ IN PCLIPBRDDATA ptrdata)
+{
+ static char szAppName[]="PMNTClipboard";
+ MSG msg;
+ WNDCLASS wndclass;
+
+
+ pClipbrdData = ptrdata;
+
+ wndclass.style = 0;
+ wndclass.lpfnWndProc = WndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = NULL;
+ wndclass.hIcon = NULL;
+ wndclass.hCursor = NULL;
+ wndclass.hbrBackground = NULL;
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = szAppName;
+
+ RegisterClass(&wndclass);
+
+ pClipbrdData->hwnd = (ULONG) CreateWindow(szAppName,
+ "",
+ 0,
+ -1,
+ -1,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+
+ while (GetMessage (&msg,(HWND) pClipbrdData->hwnd,0,0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ return(msg.wParam);
+}
+
+long FAR PASCAL WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+
+{
+ HWND hOwner;
+
+ switch (msg) {
+
+ case WM_RENDERFORMAT:
+
+ if ((pClipbrdData->QueryFmt = (USHORT) wParam) == CF_TEXT
+ || pClipbrdData->QueryFmt == CF_BITMAP) {
+ DosSemSet(&(pClipbrdData->SemPM));
+ DosSemClear(&(pClipbrdData->SemWin32));
+ DosSemWait(&(pClipbrdData->SemPM),-1L);
+ }
+ return(0);
+
+ case WM_DESTROYCLIPBOARD:
+
+ hOwner = GetClipboardOwner();
+ if (hOwner != hwnd) {
+ // new owner is Win32 app, not PMNT app
+ pClipbrdData->fempty = TRUE;
+ DosSemSet(&(pClipbrdData->SemPM));
+ DosSemClear(&(pClipbrdData->SemWin32));
+ DosSemWait(&(pClipbrdData->SemPM),-1L);
+ pClipbrdData->fempty = FALSE;
+ }
+ return(0);
+ }
+ return(DefWindowProc(hwnd,msg,wParam,lParam));
+}
+
+#if 0 // We decided not to use the code below for now
+/******************************************************************************
+ * PMNTCloseRetryPopup: *
+ * Close the "Wait", "End Task", "Cancel" pop-up dialog opened by the Console*
+ * when closing a CMD window representing a PM app. *
+ * *
+ * Parameters: *
+ * *
+ * fClose: 0 - Simulate 'Cancel' *
+ * Otherwise, 'Wait' *
+ ******************************************************************************/
+
+ULONG
+PMNTCloseRetryPopup(
+ IN ULONG fClose)
+{
+ HWND hwndPopup, hwndParent;
+ HMODULE modulePopup;
+ HINSTANCE instancePopup;
+ USHORT TimeOut = 5;
+
+ if (fClose)
+ fClose = IDRETRY;
+ else
+ fClose = IDCANCEL;
+
+ hwndPopup = GetTopWindow(NULL); // Get handle of Retry popup
+ hwndParent = (HWND)GetWindowLong(hwndPopup, GWL_HWNDPARENT);
+ modulePopup = (HMODULE)GetClassLong(hwndPopup, GCL_HMODULE);
+ instancePopup = (HINSTANCE)GetWindowLong(hwndPopup, GWL_HINSTANCE);
+ // DbgPrint("Popup=%x, Parent=%x, Module=%x, instance=%x\n",hwndPopup, hwndParent, modulePopup, instancePopup);
+
+ // The pop-up dialog is identified by 3 conditions:
+ // - has no parent (hwndParent is NULL)
+ // - modulePopup is NULL
+ // - instancePopup is NULL (i.e. we got the first instance of this window
+ // class on the screen)
+ // WARNING: the present code & comments should be taken with caution since
+ // they are based on partial knowledge and mostly experimentation.
+ while (((hwndParent != NULL) || (modulePopup != 0) || (instancePopup != 0))
+ && TimeOut--)
+ {
+ Sleep(300L);
+ hwndPopup = GetTopWindow(NULL); // Get handle of Retry popup
+ hwndParent = (HWND)GetWindowLong(hwndPopup, GWL_HWNDPARENT);
+ modulePopup = (HMODULE)GetClassLong(hwndPopup, GCL_HMODULE);
+ instancePopup = (HINSTANCE)GetWindowLong(hwndPopup, GWL_HINSTANCE);
+ // DbgPrint("Popup=%x, Parent=%x, Module=%x, instance=%x\n",hwndPopup, hwndParent, modulePopup, instancePopup);
+ }
+
+ PostMessage(hwndPopup, WM_COMMAND, (WPARAM)fClose, (LPARAM)0);
+
+ return(NO_ERROR);
+}
+#endif //0
+
+#endif // PMNT
+
diff --git a/private/os2/client/dllpmsha.c b/private/os2/client/dllpmsha.c
new file mode 100644
index 000000000..0fbea5824
--- /dev/null
+++ b/private/os2/client/dllpmsha.c
@@ -0,0 +1,536 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllpmsha.c
+
+Abstract:
+
+ This module implements the PMSHAPI OS/2 V1.X API Calls
+
+Author:
+
+ Yaron Shamir (YaronS) 17-Jul-1991
+
+Revision History:
+
+ 17-Jul-1991: created, mainly stubs.
+ 5-Apr-1992: Implemented the APIs using the Registry mechanism (BeniL)
+
+--*/
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_NLS
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include <ntregapi.h>
+
+extern int atoi(PCHAR);
+
+static WCHAR FullOs2IniDirectory[] = L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\OS/2 Subsystem for NT\\1.0\\os2.ini";
+static WCHAR Os2Class[] = L"OS2SS";
+
+BOOLEAN
+Od2CreateKey(
+ OUT PHANDLE pKeyHandle,
+ IN PSZ pszAppName
+ )
+{
+ OBJECT_ATTRIBUTES Obja;
+ ANSI_STRING AppName_A;
+ UNICODE_STRING Class_U;
+ UNICODE_STRING FullOs2IniDirectory_U;
+ UNICODE_STRING AppName_U;
+ HANDLE Os2IniKeyHandle;
+ ULONG Disposition;
+ NTSTATUS Status;
+ APIRET RetCode;
+
+
+ RtlInitUnicodeString(&Class_U, Os2Class);
+
+ RtlInitUnicodeString(&FullOs2IniDirectory_U, FullOs2IniDirectory);
+ InitializeObjectAttributes(&Obja,
+ &FullOs2IniDirectory_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtCreateKey(&Os2IniKeyHandle,
+ KEY_CREATE_SUB_KEY,
+ &Obja,
+ 0,
+ &Class_U,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition
+ );
+ if (!NT_SUCCESS(Status)) {
+ return (FALSE);
+ }
+
+ Od2InitMBString(&AppName_A, pszAppName);
+ RetCode = Od2MBStringToUnicodeString(
+ &AppName_U,
+ &AppName_A,
+ (BOOLEAN)TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+// DbgPrint("Od2CreateKey: no memory for Unicode Conversion\n");
+#endif
+ NtClose(Os2IniKeyHandle);
+ //return RetCode;
+ return (FALSE);
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &AppName_U,
+ OBJ_CASE_INSENSITIVE,
+ Os2IniKeyHandle,
+ NULL);
+ Status = NtCreateKey(pKeyHandle,
+ DELETE | KEY_READ | KEY_WRITE,
+ &Obja,
+ 0,
+ &Class_U,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition
+ );
+ NtClose(Os2IniKeyHandle);
+ RtlFreeUnicodeString(&AppName_U);
+ if (!NT_SUCCESS(Status)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+BOOLEAN
+Od2OpenKey(
+ OUT PHANDLE pKeyHandle,
+ IN PSZ pszAppName
+ )
+{
+ OBJECT_ATTRIBUTES Obja;
+ ANSI_STRING AppName_A;
+ UNICODE_STRING Class_U;
+ UNICODE_STRING FullOs2IniDirectory_U;
+ UNICODE_STRING AppName_U;
+ NTSTATUS Status;
+ HANDLE FullKeyHandle;
+ APIRET RetCode;
+
+
+ RtlInitUnicodeString(&Class_U, Os2Class);
+
+ RtlInitUnicodeString(&FullOs2IniDirectory_U, FullOs2IniDirectory);
+ InitializeObjectAttributes(&Obja,
+ &FullOs2IniDirectory_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&FullKeyHandle,
+ KEY_CREATE_SUB_KEY,
+ &Obja
+ );
+ if (!NT_SUCCESS(Status)) {
+ return (FALSE);
+ }
+
+ Od2InitMBString(&AppName_A, pszAppName);
+ RetCode = Od2MBStringToUnicodeString(
+ &AppName_U,
+ &AppName_A,
+ (BOOLEAN)TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+// DbgPrint("Od2OpenKey: no memory for Unicode Conversion\n");
+#endif
+ NtClose(FullKeyHandle);
+ //return RetCode;
+ return (FALSE);
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &AppName_U,
+ OBJ_CASE_INSENSITIVE,
+ FullKeyHandle,
+ NULL);
+ Status = NtOpenKey(pKeyHandle,
+ DELETE | KEY_READ | KEY_WRITE,
+ &Obja
+ );
+ NtClose(FullKeyHandle);
+ RtlFreeUnicodeString(&AppName_U);
+ if (!NT_SUCCESS(Status)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+APIRET
+WinQueryProfileSize(
+ IN PSZ pszAppName,
+ IN PSZ pszKeyName,
+ OUT PUSHORT pcb
+ )
+
+{
+ HANDLE KeyHandle;
+ ANSI_STRING KeyName_A;
+ UNICODE_STRING KeyName_U;
+ BOOLEAN rc;
+ NTSTATUS Status;
+ ULONG ResultLength;
+ KEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
+ PKEY_VALUE_PARTIAL_INFORMATION pInfo;
+ ULONG RequiredMem;
+ APIRET RetCode;
+
+ try {
+ Od2ProbeForRead(pszAppName, sizeof(CHAR), 1);
+ if (pszKeyName != NULL) {
+ Od2ProbeForWrite(pcb, sizeof(USHORT), 1);
+ Od2ProbeForRead(pszKeyName, sizeof(CHAR), 1);
+ }
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ rc = Od2OpenKey(&KeyHandle, pszAppName);
+ if (!rc && (pszKeyName == NULL)) {
+ *pcb = 0;
+ return (0);
+ }
+ if (!rc) {
+ *pcb = 0;
+ return (1);
+ }
+ if (pszKeyName == NULL) {
+ Status = NtDeleteKey(KeyHandle);
+ NtClose(KeyHandle);
+ *pcb = 0;
+ if (!NT_SUCCESS(Status)) {
+ return (1);
+ }
+ else {
+ return (0);
+ }
+ }
+
+ Od2InitMBString(&KeyName_A, pszKeyName);
+ RetCode = Od2MBStringToUnicodeString(
+ &KeyName_U,
+ &KeyName_A,
+ (BOOLEAN)TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+// DbgPrint("WinQueryProfileSize: no memory for Unicode Conversion\n");
+#endif
+ NtClose(KeyHandle);
+ //return RetCode;
+ return (1);
+ }
+
+ Status = NtQueryValueKey(KeyHandle,
+ &KeyName_U,
+ KeyValuePartialInformation,
+ &ValuePartialInformation,
+ 0,
+ &ResultLength
+ );
+
+ if (Status != STATUS_BUFFER_TOO_SMALL) {
+ RtlFreeUnicodeString(&KeyName_U);
+ NtClose(KeyHandle);
+ return (1);
+ }
+
+ RequiredMem = ResultLength;
+ pInfo = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(Od2Heap, 0, RequiredMem);
+ if (pInfo == NULL) {
+ RtlFreeUnicodeString(&KeyName_U);
+ NtClose(KeyHandle);
+ *pcb = 0;
+ return (1);
+ }
+
+ Status = NtQueryValueKey(KeyHandle,
+ &KeyName_U,
+ KeyValuePartialInformation,
+ pInfo,
+ RequiredMem,
+ &ResultLength
+ );
+
+ NtClose(KeyHandle);
+ RtlFreeUnicodeString(&KeyName_U);
+ if (!NT_SUCCESS(Status)) {
+ RtlFreeHeap(Od2Heap, 0, pInfo);
+ *pcb = 0;
+ return (1);
+ }
+
+ *pcb = (USHORT)pInfo->DataLength;
+ RtlFreeHeap(Od2Heap, 0, pInfo);
+ return (0);
+}
+
+APIRET
+WinQueryProfileData(
+ IN PSZ pszAppName,
+ IN PSZ pszKeyName,
+ IN PVOID pvBuf,
+ IN OUT PUSHORT cbBuf
+ )
+
+{
+ BOOLEAN rc;
+ HANDLE KeyHandle;
+ ANSI_STRING KeyName_A;
+ UNICODE_STRING KeyName_U;
+ ULONG ResultLength;
+ KEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
+ PKEY_VALUE_PARTIAL_INFORMATION pInfo;
+ NTSTATUS Status;
+ ULONG RequiredMem;
+ APIRET RetCode;
+
+ try {
+ Od2ProbeForRead(pszAppName, sizeof(CHAR), 1);
+ if (pszKeyName != NULL) {
+ Od2ProbeForWrite(pvBuf, *cbBuf, 1);
+ Od2ProbeForRead(pszKeyName, sizeof(CHAR), 1);
+ }
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ rc = Od2OpenKey(&KeyHandle, pszAppName);
+ if (!rc && (pszKeyName == NULL)) {
+ *cbBuf = 0;
+ return (TRUE);
+ }
+ if (!rc) {
+ *cbBuf = 0;
+ return (FALSE);
+ }
+ if (pszKeyName == NULL) {
+ Status = NtDeleteKey(KeyHandle);
+ NtClose(KeyHandle);
+ *cbBuf = 0;
+ if (!NT_SUCCESS(Status)) {
+ return (FALSE);
+ }
+ else {
+ return (TRUE);
+ }
+ }
+
+ Od2InitMBString(&KeyName_A, pszKeyName);
+ RetCode = Od2MBStringToUnicodeString(
+ &KeyName_U,
+ &KeyName_A,
+ (BOOLEAN)TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+// DbgPrint("WinQueryProfileData: no memory for Unicode Conversion\n");
+#endif
+ NtClose(KeyHandle);
+ //return RetCode;
+ return (FALSE);
+ }
+
+ Status = NtQueryValueKey(KeyHandle,
+ &KeyName_U,
+ KeyValuePartialInformation,
+ &ValuePartialInformation,
+ 0,
+ &ResultLength
+ );
+
+ if (Status != STATUS_BUFFER_TOO_SMALL) {
+ RtlFreeUnicodeString(&KeyName_U);
+ NtClose(KeyHandle);
+ return (FALSE);
+ }
+
+ RequiredMem = ResultLength;
+ pInfo = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(Od2Heap, 0, RequiredMem);
+ if (pInfo == NULL) {
+ RtlFreeUnicodeString(&KeyName_U);
+ NtClose(KeyHandle);
+ return (FALSE);
+ }
+
+ Status = NtQueryValueKey(KeyHandle,
+ &KeyName_U,
+ KeyValuePartialInformation,
+ pInfo,
+ RequiredMem,
+ &ResultLength
+ );
+
+ NtClose(KeyHandle);
+ RtlFreeUnicodeString(&KeyName_U);
+ if (!NT_SUCCESS(Status) || (*cbBuf < (USHORT)pInfo->DataLength)) {
+ RtlFreeHeap(Od2Heap, 0, pInfo);
+ *cbBuf = 0;
+ return (FALSE);
+ }
+
+ RtlMoveMemory(pvBuf, (PCHAR)pInfo->Data, pInfo->DataLength);
+ *cbBuf = (USHORT)pInfo->DataLength;
+ RtlFreeHeap(Od2Heap, 0, pInfo);
+ return (TRUE);
+}
+
+APIRET
+WinQueryProfileString(
+ IN PSZ pszAppName,
+ IN PSZ pszKeyName,
+ IN PSZ pszError,
+ OUT PSZ pszBuf,
+ IN ULONG cchBuf
+ )
+
+{
+ BOOLEAN rc;
+ USHORT BufSize;
+
+ try {
+ Od2ProbeForWrite(pszBuf, cchBuf, 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ BufSize = (USHORT)cchBuf;
+ rc = (BOOLEAN)WinQueryProfileData(pszAppName, pszKeyName, pszBuf, &BufSize);
+ if (!rc || (pszKeyName == NULL)) {
+ if (cchBuf != 0) {
+ strncpy(pszBuf, pszError, cchBuf);
+ pszBuf[cchBuf - 1] = '\0';
+ BufSize = (USHORT)(strlen(pszBuf) + 1);
+ }
+ else {
+ BufSize = 0;
+ }
+ }
+ return (BufSize);
+}
+
+APIRET
+WinQueryProfileInt(
+ IN PSZ pszAppName,
+ IN PSZ pszKeyName,
+ IN LONG sError
+ )
+{
+ BOOLEAN rc;
+ CHAR Data[32];
+ USHORT BufferSize;
+ NTSTATUS Status;
+ ULONG Value;
+
+ BufferSize = (USHORT)sizeof(Data);
+ rc = (BOOLEAN)WinQueryProfileData(pszAppName, pszKeyName, Data, &BufferSize);
+ if (!rc || (pszKeyName == NULL)) {
+ return (sError);
+ }
+ Status = RtlCharToInteger(Data, 10, &Value);
+ if (!NT_SUCCESS(Status)) {
+ return (sError);
+ }
+ return (Value);
+}
+
+APIRET
+WinWriteProfileData(
+ IN PSZ pszAppName,
+ IN PSZ pszKeyName,
+ IN PVOID pchBinaryData,
+ IN ULONG cchData
+ )
+
+{
+ HANDLE KeyHandle;
+ BOOLEAN rc;
+ ANSI_STRING KeyName_A;
+ UNICODE_STRING KeyName_U;
+ NTSTATUS Status;
+ APIRET RetCode;
+
+ try {
+ Od2ProbeForRead(pchBinaryData, cchData, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ rc = Od2CreateKey(&KeyHandle, pszAppName);
+ if (!rc && (pszKeyName == NULL)) {
+ return (TRUE);
+ }
+ if (!rc) {
+ return (FALSE);
+ }
+ if (pszKeyName == NULL) {
+ NtDeleteKey(KeyHandle);
+ NtClose(KeyHandle);
+ return (TRUE);
+ }
+
+ Od2InitMBString(&KeyName_A, pszKeyName);
+ RetCode = Od2MBStringToUnicodeString(
+ &KeyName_U,
+ &KeyName_A,
+ (BOOLEAN)TRUE);
+
+ if (RetCode)
+ {
+#if DBG
+// DbgPrint("WinWriteProfileData: no memory for Unicode Conversion\n");
+#endif
+ NtClose(KeyHandle);
+ //return RetCode;
+ return (FALSE);
+ }
+
+ if (pchBinaryData == NULL) {
+ Status = NtDeleteValueKey(KeyHandle, &KeyName_U);
+ RtlFreeUnicodeString(&KeyName_U);
+ NtClose(KeyHandle);
+ return (TRUE);
+ }
+ Status = NtSetValueKey(KeyHandle, &KeyName_U, 0, REG_BINARY,
+ pchBinaryData, cchData);
+
+ RtlFreeUnicodeString(&KeyName_U);
+ NtClose(KeyHandle);
+ if (!NT_SUCCESS(Status)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+APIRET
+WinWriteProfileString(
+ IN PSZ pszAppName,
+ IN PSZ pszKeyName,
+ IN PSZ pszString
+ )
+{
+ return(WinWriteProfileData(pszAppName, pszKeyName,
+ pszString, strlen(pszString)+1));
+}
diff --git a/private/os2/client/dllpmwin.c b/private/os2/client/dllpmwin.c
new file mode 100644
index 000000000..e09538c23
--- /dev/null
+++ b/private/os2/client/dllpmwin.c
@@ -0,0 +1,91 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllpmwin.c
+
+Abstract:
+
+ This module implements the PMWIN OS/2 V2.0 API Calls
+
+Author:
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_NLS
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+
+APIRET
+WinCreateHeap(
+ ULONG selHeapBase,
+ ULONG cbHeap,
+ ULONG cbGrow,
+ ULONG cbMinDed,
+ ULONG cbMaxDeb,
+ ULONG fsOptions
+ )
+
+{
+ return( NO_ERROR );
+}
+
+
+APIRET
+WinDestroyHeap(
+ ULONG hHeap
+ )
+{
+#if DBG
+ KdPrint(("WinDestroyHeap called\n"));
+ DbgUserBreakPoint();
+#endif
+ return( NO_ERROR );
+}
+
+
+APIRET
+WinAllocMem(
+ ULONG hHeap,
+ ULONG cb
+ )
+{
+#if DBG
+ KdPrint(("WinAllocMem called\n"));
+ DbgUserBreakPoint();
+#endif
+ return( NO_ERROR );
+}
+
+
+APIRET
+WinFreeMem(
+ ULONG hHeap,
+ ULONG npMem,
+ ULONG cbMem
+ )
+{
+#if DBG
+ KdPrint(("WinFreeMem called\n"));
+ DbgUserBreakPoint();
+#endif
+ return( NO_ERROR );
+}
+
+
+APIRET
+WinGetLastError(
+ ULONG hab
+ )
+{
+#if DBG
+ KdPrint(("WinGetLastError called\n"));
+ DbgUserBreakPoint();
+#endif
+ return( NO_ERROR );
+}
diff --git a/private/os2/client/dllque.c b/private/os2/client/dllque.c
new file mode 100644
index 000000000..1a271f9d0
--- /dev/null
+++ b/private/os2/client/dllque.c
@@ -0,0 +1,940 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllque.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 Queue API Calls
+
+
+Author:
+
+ Mark Lucovsky (markl) 10-Jul-1990
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_QUEUES
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_TASKING
+#include "os2dll.h"
+#include "os2dll16.h"
+
+
+POR2_QHANDLE_TABLE
+Od2GetQueueTable(
+ BOOLEAN CreateOkay
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns a pointer to the processes OS/2 queue table.
+ The second parameter specifies if the table should be created and
+ initialized if it does not already exist for the current process.
+ Returns null if table does not exist and the second parameter is
+ FALSE or if the second parameter is TRUE and this function is unable
+ to create the table.
+
+ Queue tables are essentially handle tables. They are an array of
+ fixed size structures (OD2_QUEUE) indexed by the low order 16 bits
+ of an OS/2 queue handle.
+
+Arguments:
+
+ CreateOkay - If this parameter is TRUE, then an attempt is made to
+ create and initialize the queue table if it does not already
+ exist. Returns NULL if unable to create.
+
+Return Value:
+
+ Pointer to the requested semaphore table or NULL.
+
+--*/
+
+{
+ POR2_QHANDLE_TABLE *QueueTablePointer;
+ POR2_QHANDLE_TABLE QueueTable;
+
+ if (!CreateOkay) {
+ return( Od2Process->QueueTable );
+ }
+
+ //
+ // We are querying/modifying process state, so don't let others in while
+ // we are about it.
+ //
+
+ AcquireTaskLock();
+
+ //
+ // Compute pointer to the queue table pointer.
+ //
+
+ QueueTablePointer = &Od2Process->QueueTable;
+
+ //
+ // If the queue table has not been created yet, and the
+ // caller said it was okay to create it, then attempt to do so, using
+ // a default initial size of 2 entries.
+ //
+
+ if ((QueueTable = *QueueTablePointer) == NULL) {
+ QueueTable = Or2CreateQHandleTable( Od2Heap,
+ sizeof( OD2_QUEUE ),
+ 2
+ );
+ //
+ // Update the appropriate field in the process structure with the
+ // address of the newly created queue table, or NULL if the
+ // create failed.
+ //
+
+ *QueueTablePointer = QueueTable;
+ }
+
+ //
+ // Done mucking about, release the process structure lock.
+ //
+
+ ReleaseTaskLock();
+
+ return( QueueTable );
+}
+
+APIRET
+Od2ValidateQueueSemaphore(
+ IN HSEM EventHandle,
+ IN PULONG HandleIndex
+ )
+{
+ BOOLEAN SharedSem;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ APIRET rc;
+
+ rc = Od2ValidateSemaphoreHandle( EventHandle,
+ &SharedSem,
+ HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ *HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is an Event semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Od2EventSem) {
+ ReleaseHandleTableLock( SemaphoreTable );
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+
+ ReleaseHandleTableLock( SemaphoreTable );
+
+ return NO_ERROR;
+}
+
+VOID
+Od2QueueDestroyProcedure(
+ IN POD2_QUEUE Semaphore,
+ IN ULONG HandleIndex
+ )
+{
+ UNREFERENCED_PARAMETER(Semaphore);
+#if DBG
+ IF_OD2_DEBUG( CLEANUP ) {
+ DbgPrint( "OS2DLL: Pid: %lX - DosCloseQueue( %lX )\n",
+ Od2Process->Pib.ProcessId,
+ HandleIndex
+ );
+ }
+#endif
+
+ DosCloseQueue((HQUEUE)HandleIndex);
+}
+
+VOID
+Od2CloseAllQueues( VOID )
+{
+ if (Od2Process->QueueTable != NULL) {
+ Or2DestroyQHandleTable(
+ Od2Process->QueueTable,
+ (OR2_DESTROY_QHANDLE_ROUTINE)Od2QueueDestroyProcedure
+ );
+
+ Od2Process->QueueTable = NULL;
+ }
+
+}
+
+APIRET
+DosCreateQueue(
+ OUT PHQUEUE QueueHandle,
+ IN ULONG QueueType,
+ IN PSZ ObjectName
+ )
+
+{
+ OS2_API_MSG m;
+ POS2_DOSCREATEQUEUE_MSG a = &m.u.DosCreateQueue;
+ POS2_DOSCLOSEQUEUE_MSG a1 = &m.u.DosCloseQueue;
+ APIRET rc;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ POR2_QHANDLE_TABLE QueueTable;
+ OD2_QUEUE Queue;
+
+ switch (QueueType) {
+
+ case QUE_FIFO :
+ case QUE_LIFO :
+ case QUE_PRIORITY :
+ break;
+ default :
+ return( ERROR_QUE_INVALID_PRIORITY );
+ }
+
+ a->QueueType = QueueType;
+
+ //
+ // Probe the queue handle
+ //
+
+ try {
+ Od2ProbeForWrite((PVOID)QueueHandle,sizeof(*QueueHandle),1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ QueueTable = Od2GetQueueTable( TRUE );
+ if (!QueueTable) {
+ return( ERROR_QUE_NO_MEMORY );
+ }
+
+ rc = Od2CaptureObjectName( ObjectName,
+ CANONICALIZE_QUEUE,
+ 0,
+ &CaptureBuffer,
+ &a->QueueName
+ );
+ if (rc != NO_ERROR) {
+ return( ERROR_QUE_INVALID_NAME );
+ }
+
+ Od2CallSubsystem( &m, CaptureBuffer, Os2CreateQueue, sizeof( *a ) );
+
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ }
+
+ rc = m.ReturnedErrorValue;
+ if ( rc == NO_ERROR) {
+ Queue.OpenCount = 1;
+ Queue.OwnerProcessId = Od2Process->Pib.ProcessId;
+
+ if (!Or2CreateQHandle( QueueTable,
+ (PULONG)&a->QueueHandle,
+ (PVOID)&Queue
+ )
+ ) {
+
+ //
+ // Unable to create the entry. Just need to do a DosCloseQueue on
+ // the queue that the server has open.
+ //
+
+ a1->QueueHandle = a->QueueHandle;
+ a1->CloseCount = 1;
+ a1->OwnerProcessId = Od2Process->Pib.ProcessId;
+ Od2CallSubsystem( &m, NULL, Os2CloseQueue, sizeof( *a1 ) );
+ rc = ERROR_QUE_NO_MEMORY;
+ }
+ else {
+ *QueueHandle = a->QueueHandle;
+ }
+ }
+
+ return( rc );
+}
+
+APIRET
+DosOpenQueue(
+ OUT PPID OwnerProcessId,
+ OUT PHQUEUE QueueHandle,
+ IN PSZ ObjectName
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSOPENQUEUE_MSG a = &m.u.DosOpenQueue;
+ POS2_DOSCLOSEQUEUE_MSG a1 = &m.u.DosCloseQueue;
+ APIRET rc;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ POR2_QHANDLE_TABLE QueueTable;
+ OD2_QUEUE LQueue;
+ POD2_QUEUE Queue;
+
+ //
+ // Probe the queue handle and pid
+ //
+
+ try {
+ Od2ProbeForWrite((PVOID)QueueHandle,sizeof(*QueueHandle),1);
+ Od2ProbeForWrite((PVOID)OwnerProcessId,sizeof(*OwnerProcessId),1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ QueueTable = Od2GetQueueTable( TRUE );
+ if (!QueueTable) {
+ return( ERROR_QUE_NO_MEMORY );
+ }
+
+ rc = Od2CaptureObjectName( ObjectName,
+ CANONICALIZE_QUEUE,
+ 0,
+ &CaptureBuffer,
+ &a->QueueName
+ );
+ if (rc != NO_ERROR) {
+ return( ERROR_QUE_INVALID_NAME );
+ }
+
+ //
+ // Call subsystem to open the queue and return a queue handle. Then
+ // look in process table to see if caller already has a handle to the
+ // queue in which case he simply bumps the open count. Otherwise, create
+ // a new handle with an open count of 1.
+ //
+
+ Od2CallSubsystem( &m, CaptureBuffer, Os2OpenQueue, sizeof( *a ) );
+
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ }
+
+ rc = m.ReturnedErrorValue;
+
+ if ( rc == NO_ERROR) {
+
+ //
+ // Now lock the queue table
+ //
+
+ AcquireHandleTableLock( QueueTable );
+
+ //
+ // See if the queue handle maps to an allocated entry in the table.
+ //
+
+ Queue = (POD2_QUEUE)Or2MapQHandle( QueueTable,
+ (ULONG)a->QueueHandle,
+ TRUE
+ );
+
+ //
+ // If process does not have a handle to the queue
+ // then map fails. Create a queue handle using index
+ // from server.
+ //
+
+ if (Queue == NULL || Queue->OpenCount == 0) {
+
+ LQueue.OpenCount = 1;
+ LQueue.OwnerProcessId = a->OwnerProcessId;
+
+ if (!Or2CreateQHandle( QueueTable,
+ (PULONG)&a->QueueHandle,
+ (PVOID)&LQueue
+ )
+ ) {
+
+ //
+ // Unable to create the entry. Just need to do a
+ // DosCloseQueue on the queue that the server has open.
+ //
+
+ a1->QueueHandle = a->QueueHandle;
+ a1->CloseCount = 1;
+ a1->OwnerProcessId = a->OwnerProcessId;
+ Od2CallSubsystem( &m, NULL, Os2CloseQueue, sizeof( *a1 ) );
+ rc = ERROR_QUE_NO_MEMORY;
+ }
+ }
+ else {
+
+ Queue->OpenCount++;
+ }
+
+ ReleaseHandleTableLock( QueueTable );
+
+ }
+
+ if ( rc == NO_ERROR ) {
+ *OwnerProcessId = a->OwnerProcessId;
+ *QueueHandle = a->QueueHandle;
+ }
+
+ return( rc );
+
+}
+
+APIRET
+DosCloseQueue(
+ IN HQUEUE QueueHandle
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSCLOSEQUEUE_MSG a = &m.u.DosCloseQueue;
+ POR2_QHANDLE_TABLE QueueTable;
+ POD2_QUEUE Queue;
+ APIRET rc;
+
+ //
+ // Get the pointer to the queue table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ QueueTable = Od2GetQueueTable( FALSE );
+ if (!QueueTable) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+
+ //
+ // Map the queue handle into a pointer to the queue structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the queue table is left locked while we use the pointer.
+ //
+
+ a->QueueHandle = QueueHandle;
+ Queue = (POD2_QUEUE)Or2MapQHandle( QueueTable,
+ (ULONG)QueueHandle,
+ FALSE
+ );
+ if (Queue == NULL) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+ if (Queue->OpenCount == 0) {
+ ReleaseHandleTableLock( QueueTable );
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+
+ a->CloseCount = Queue->OpenCount;
+ a->OwnerProcessId = Queue->OwnerProcessId;
+ Queue->OpenCount = 0;
+
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2CloseQueue,
+ sizeof( *a )
+ );
+
+ Or2DestroyQHandle( QueueTable, (ULONG)(a->QueueHandle));
+
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
+
+APIRET
+DosPurgeQueue(
+ IN HQUEUE QueueHandle
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSPURGEQUEUE_MSG a = &m.u.DosPurgeQueue;
+ POR2_QHANDLE_TABLE QueueTable;
+ POD2_QUEUE Queue;
+ APIRET rc;
+
+ //
+ // Get the pointer to the queue table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ QueueTable = Od2GetQueueTable( FALSE );
+ if (!QueueTable) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+
+ //
+ // Map the queue handle into a pointer to the queue structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the queue table is left locked while we use the pointer.
+ //
+
+ a->QueueHandle = QueueHandle;
+
+ Queue = (POD2_QUEUE)Or2MapQHandle( QueueTable,
+ (ULONG)QueueHandle,
+ FALSE
+ );
+ if (Queue == NULL) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+ if (Queue->OpenCount == 0) {
+ ReleaseHandleTableLock( QueueTable );
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+ if (Queue->OwnerProcessId != Od2Process->Pib.ProcessId) {
+ ReleaseHandleTableLock( QueueTable );
+ return( ERROR_QUE_PROC_NOT_OWNED );
+ }
+
+ ReleaseHandleTableLock( QueueTable );
+
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2PurgeQueue,
+ sizeof( *a )
+ );
+
+ if (rc == ERROR_QUE_INVALID_HANDLE) {
+ AcquireHandleTableLock( QueueTable );
+ Or2DestroyQHandle( QueueTable, (ULONG)(a->QueueHandle));
+ }
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
+
+APIRET
+DosQueryQueue(
+ IN HQUEUE QueueHandle,
+ OUT PULONG CountQueuedElements
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSQUERYQUEUE_MSG a = &m.u.DosQueryQueue;
+ POR2_QHANDLE_TABLE QueueTable;
+ POD2_QUEUE Queue;
+ APIRET rc;
+
+
+ //
+ // Probe the element count
+ //
+
+ try {
+ Od2ProbeForWrite(CountQueuedElements,sizeof(*CountQueuedElements),1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ //
+ // Get the pointer to the queue table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ QueueTable = Od2GetQueueTable( FALSE );
+ if (!QueueTable) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+
+ //
+ // Map the queue handle into a pointer to the queue structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the queue table is left locked while we use the pointer.
+ //
+
+ a->QueueHandle = QueueHandle;
+
+ Queue = (POD2_QUEUE)Or2MapQHandle( QueueTable,
+ (ULONG)QueueHandle,
+ FALSE
+ );
+ if (Queue == NULL) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+ if (Queue->OpenCount == 0) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+
+ a->OwnerProcessId = Queue->OwnerProcessId;
+
+ ReleaseHandleTableLock( QueueTable );
+
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2QueryQueue,
+ sizeof( *a )
+ );
+
+ if (rc == ERROR_QUE_INVALID_HANDLE) {
+ AcquireHandleTableLock( QueueTable );
+ Or2DestroyQHandle( QueueTable, (ULONG)(a->QueueHandle));
+ }
+ if (rc == NO_ERROR) {
+ *CountQueuedElements = a->CountQueueElements;
+ }
+
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
+
+APIRET
+DosPeekQueue(
+ IN HQUEUE QueueHandle,
+ OUT PREQUESTDATA RequestInfo,
+ OUT PULONG DataLength,
+ OUT PULONG Data,
+ IN OUT PULONG ReadPosition,
+ IN BOOL32 NoWait,
+ OUT PBYTE ElementPriority,
+ IN HSEM SemHandle
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSPEEKQUEUE_MSG a = &m.u.DosPeekQueue;
+ POR2_QHANDLE_TABLE QueueTable;
+ POD2_QUEUE Queue;
+ APIRET rc;
+
+ //
+ // Probe all out parameters
+ //
+
+ try {
+ Od2ProbeForWrite(ReadPosition,sizeof(*ReadPosition),1);
+ Od2ProbeForWrite(RequestInfo,sizeof(*RequestInfo),1);
+ Od2ProbeForWrite(DataLength,sizeof(*DataLength),1);
+ Od2ProbeForWrite(Data,sizeof(*Data),1);
+ Od2ProbeForWrite(ElementPriority,sizeof(*ElementPriority),1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Capture and check NoWait flag
+ //
+
+ switch ((a->NoWait = NoWait)) {
+ case DCWW_WAIT :
+ case DCWW_NOWAIT :
+ break;
+ default:
+ return ERROR_QUE_INVALID_WAIT;
+ }
+
+ //
+ // Get the pointer to the queue table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ QueueTable = Od2GetQueueTable( FALSE );
+ if (!QueueTable) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+
+ //
+ // Map the queue handle into a pointer to the queue structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the queue table is left locked while we use the pointer.
+ //
+
+ a->QueueHandle = QueueHandle;
+ a->ReadPosition = *ReadPosition;
+
+ if ( SemHandle ) {
+ rc = Od2ValidateQueueSemaphore(SemHandle,&a->SemIndex);
+ if ( rc != NO_ERROR ) {
+ return rc;
+ }
+ a->SemIndex |= 0x80000000;
+ }
+ else {
+ a->SemIndex = 0;
+ }
+
+ Queue = (POD2_QUEUE)Or2MapQHandle( QueueTable,
+ (ULONG) a->QueueHandle,
+ FALSE
+ );
+ if (Queue == NULL) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+ if (Queue->OpenCount == 0) {
+ ReleaseHandleTableLock( QueueTable );
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+ if (Queue->OwnerProcessId != Od2Process->Pib.ProcessId) {
+ ReleaseHandleTableLock( QueueTable );
+ return( ERROR_QUE_PROC_NOT_OWNED );
+ }
+
+
+ ReleaseHandleTableLock( QueueTable );
+
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2PeekQueue,
+ sizeof( *a )
+ );
+
+ *RequestInfo = a->RequestInfo ;
+ *DataLength = a->DataLength;
+ *Data = (ULONG)a->Data;
+ *ElementPriority = a->ElementPriority;
+ *ReadPosition = a->ReadPosition;
+
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
+
+APIRET
+DosReadQueue(
+ IN HQUEUE QueueHandle,
+ OUT PREQUESTDATA RequestInfo,
+ OUT PULONG DataLength,
+ OUT PULONG Data,
+ IN ULONG ReadPosition,
+ IN BOOL32 NoWait,
+ OUT PBYTE ElementPriority,
+ IN HSEM SemHandle
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSREADQUEUE_MSG a = &m.u.DosReadQueue;
+ POR2_QHANDLE_TABLE QueueTable;
+ POD2_QUEUE Queue;
+ APIRET rc;
+
+ //
+ // Probe all out parameters
+ //
+
+ try {
+ Od2ProbeForWrite(RequestInfo,sizeof(*RequestInfo),1);
+ Od2ProbeForWrite(DataLength,sizeof(*DataLength),1);
+ Od2ProbeForWrite(Data,sizeof(*Data),1);
+ Od2ProbeForWrite(ElementPriority,sizeof(*ElementPriority),1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Capture and check NoWait flag
+ //
+
+ switch ((a->NoWait = NoWait)) {
+ case DCWW_WAIT :
+ case DCWW_NOWAIT :
+ break;
+ default:
+ return ERROR_QUE_INVALID_WAIT;
+ }
+
+ //
+ // Get the pointer to the queue table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ QueueTable = Od2GetQueueTable( FALSE );
+ if (!QueueTable) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+
+ //
+ // Map the queue handle into a pointer to the queue structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the queue table is left locked while we use the pointer.
+ //
+
+ a->QueueHandle = QueueHandle;
+ a->ReadPosition = ReadPosition;
+
+ if ( SemHandle ) {
+ rc = Od2ValidateQueueSemaphore(SemHandle,&a->SemIndex);
+ if ( rc != NO_ERROR ) {
+ return rc;
+ }
+ a->SemIndex |= 0x80000000;
+ }
+ else {
+ a->SemIndex = 0;
+ }
+
+ Queue = (POD2_QUEUE)Or2MapQHandle( QueueTable,
+ (ULONG) a->QueueHandle,
+ FALSE
+ );
+ if (Queue == NULL) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+ if (Queue->OpenCount == 0) {
+ ReleaseHandleTableLock( QueueTable );
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+ if (Queue->OwnerProcessId != Od2Process->Pib.ProcessId) {
+ ReleaseHandleTableLock( QueueTable );
+ return( ERROR_QUE_PROC_NOT_OWNED );
+ }
+
+ ReleaseHandleTableLock( QueueTable );
+
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2ReadQueue,
+ sizeof( *a )
+ );
+
+ *RequestInfo = a->RequestInfo ;
+ if (rc == 0 && (LONG)a->DataLength < 0) {
+ //
+ // This is the indication that we read from termination queue
+ //
+ SEL sel;
+ PUSHORT ptr;
+
+ rc = DosAllocSeg(4 * sizeof(USHORT), &sel, SEG_NONSHARED);
+ if (!rc) {
+ ptr = SELTOFLAT(sel);
+ ptr[0] = *(PUSHORT) &a->DataLength;
+ ptr[1] = *(PUSHORT) &a->Data;
+ ptr[2] = ptr[3] = 0;
+ *DataLength = 4 * sizeof(USHORT);
+ *Data = (ULONG) ptr;
+ }
+ else {
+ *DataLength = 0;
+ *Data = 0;
+ }
+ }
+ else {
+ *DataLength = a->DataLength;
+ *Data = (ULONG)a->Data;
+ }
+ *ElementPriority = a->ElementPriority;
+
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
+
+APIRET
+DosWriteQueue(
+ IN HQUEUE QueueHandle,
+ IN ULONG SenderData,
+ IN ULONG DataLength,
+ IN PBYTE Data,
+ IN ULONG ElementPriority
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSWRITEQUEUE_MSG a = &m.u.DosWriteQueue;
+ POR2_QHANDLE_TABLE QueueTable;
+ POD2_QUEUE Queue;
+ APIRET rc;
+
+ //
+ // Get the pointer to the queue table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ QueueTable = Od2GetQueueTable( FALSE );
+ if (!QueueTable) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+
+ //
+ // Map the queue handle into a pointer to the queue structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the queue table is left locked while we use the pointer.
+ //
+
+ Queue = (POD2_QUEUE)Or2MapQHandle( QueueTable,
+ (ULONG)QueueHandle,
+ FALSE
+ );
+ if (Queue == NULL) {
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+ if (Queue->OpenCount == 0) {
+ ReleaseHandleTableLock( QueueTable );
+ return( ERROR_QUE_INVALID_HANDLE );
+ }
+
+ //
+ // This field is checked by the server to verify that the queue
+ // is still valid for this handle. It is possible that the process
+ // that created the queue died and its handle number is reused by a
+ // new peocess while the current process tries to write to the queue
+ // without knowing anything about that.
+ //
+
+ a->OwnerProcessId = Queue->OwnerProcessId;
+
+ ReleaseHandleTableLock( QueueTable );
+
+ a->QueueHandle = QueueHandle;
+ a->SenderData = SenderData;
+ a->DataLength = DataLength;
+ a->Data = (PVOID) Data;
+ a->ElementPriority = (BYTE)ElementPriority;
+
+ rc = Od2CallSubsystem( &m,
+ NULL,
+ Os2WriteQueue,
+ sizeof( *a )
+ );
+
+ // Check if the queue was closed by the owning process
+
+ if (rc == ERROR_QUE_INVALID_HANDLE) {
+ Queue->OpenCount = 0;
+ }
+
+ //
+ // Return any error code to the caller.
+ //
+
+ return( rc );
+}
diff --git a/private/os2/client/dllque16.c b/private/os2/client/dllque16.c
new file mode 100644
index 000000000..57b7d2fc2
--- /dev/null
+++ b/private/os2/client/dllque16.c
@@ -0,0 +1,267 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllque16.c
+
+Abstract:
+
+ This module implements 32 equivalents of OS/2 V1.21 queues
+ API Calls. These are called from 16->32 thunks (i386\doscalls.asm).
+
+Author:
+
+ Beni Lavi (BeniL) 25-Nov-1991
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_QUEUES
+#include "os2dll.h"
+#include "os2dll16.h"
+
+typedef struct _REQUESTDATA16 {
+ PID16 pidProcess;
+ USHORT usEventCode;
+} REQUESTDATA16, *PREQUESTDATA16;
+
+APIRET
+Dos16ReadQueue(
+ IN HQUEUE QueueHandle,
+ OUT PREQUESTDATA16 RequestInfo,
+ OUT PUSHORT pDataLength,
+ OUT PULONG Data,
+ IN ULONG ReadPosition,
+ IN BOOL32 NoWait,
+ OUT PBYTE ElementPriority,
+ IN HSEM SemHandle
+ )
+{
+ APIRET rc;
+ REQUESTDATA lRequestInfo;
+ ULONG DataLogicalAddr;
+ POS21X_SEM pSem;
+ HSEM SemEvent;
+ BOOLEAN FirstTime;
+ ULONG DataLength;
+
+ try {
+ Od2ProbeForWrite(Data,sizeof(*Data),1);
+ Od2ProbeForWrite(pDataLength, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (SemHandle != 0) {
+ pSem = Od2LookupOrCreateSem (SemHandle, &FirstTime, 0);
+ if (pSem == NULL) {
+ return(ERROR_INVALID_HANDLE);
+ }
+ SemEvent = pSem->Event;
+ }
+ else {
+ SemEvent = 0;
+ }
+
+ *pDataLength = (USHORT) DataLength;
+
+ rc = DosReadQueue(QueueHandle, &lRequestInfo, &DataLength, &DataLogicalAddr,
+ ReadPosition, NoWait, ElementPriority, SemEvent);
+
+ *pDataLength = (USHORT) DataLength;
+
+ RequestInfo->pidProcess = (USHORT)lRequestInfo.SenderProcessId;
+ RequestInfo->usEventCode = (USHORT)lRequestInfo.SenderData;
+
+ if (DataLength != 0) {
+ *Data = FLATTOFARPTR(DataLogicalAddr);
+ }
+
+ return rc;
+}
+
+APIRET
+DosSemSet(
+ IN HSEM hsem
+ );
+
+APIRET
+Dos16PeekQueue(
+ IN HQUEUE QueueHandle,
+ OUT PREQUESTDATA16 RequestInfo,
+ OUT PUSHORT pDataLength,
+ OUT PULONG Data,
+ IN OUT PUSHORT pReadPosition,
+ IN BOOL32 NoWait,
+ OUT PBYTE ElementPriority,
+ IN HSEM SemHandle
+ )
+{
+ APIRET rc;
+ REQUESTDATA lRequestInfo;
+ ULONG DataLogicalAddr;
+ POS21X_SEM pSem;
+ HSEM SemEvent;
+ BOOLEAN FirstTime;
+ ULONG DataLength;
+ ULONG ReadPosition;
+
+ try {
+ Od2ProbeForWrite(Data, sizeof(*Data), 1);
+ Od2ProbeForWrite(pDataLength, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pReadPosition, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (SemHandle != 0) {
+
+ //
+ // DosPeekQueue should set the semaphore (test case approves this) [YosefD Jul 4 1995]
+ //
+ DosSemSet(SemHandle);
+
+ pSem = Od2LookupOrCreateSem (SemHandle, &FirstTime, 0);
+ if (pSem == NULL) {
+ return(ERROR_INVALID_HANDLE);
+ }
+ if (pSem->FlagsByte) {
+ //
+ // This is system semaphore.
+ // Special hack that marks the semaphore. Semaphore APIs will know that this
+ // semaphore was used by DosPeekQueue. In the case that DosSemRequest will
+ // be called to wait on this semaphore we will call to DosSemWait.
+ //
+ pSem->FlagsByte |= SYSSEM_QUEUE;
+ }
+ SemEvent = pSem->Event;
+ }
+ else {
+ SemEvent = 0;
+ }
+
+ DataLength = (ULONG) *pDataLength;
+ ReadPosition = (ULONG) *pReadPosition;
+
+ rc = DosPeekQueue(QueueHandle, &lRequestInfo, &DataLength, &DataLogicalAddr,
+ &ReadPosition, NoWait, ElementPriority, SemEvent);
+
+ *pDataLength = (USHORT) DataLength;
+ *pReadPosition = (USHORT) ReadPosition;
+
+ RequestInfo->pidProcess = (USHORT)lRequestInfo.SenderProcessId;
+ RequestInfo->usEventCode = (USHORT)lRequestInfo.SenderData;
+ *Data = FLATTOFARPTR(DataLogicalAddr);
+
+ return rc;
+}
+
+
+APIRET
+Dos16CreateQueue(
+ OUT PUSHORT pQueueHandle,
+ IN ULONG QueueType,
+ IN PSZ ObjectName
+ )
+
+{
+ HQUEUE QueueHandle;
+ APIRET Rc;
+
+ try
+ {
+ Od2ProbeForWrite(pQueueHandle, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ QueueHandle = (HQUEUE) *pQueueHandle;
+
+ Rc = DosCreateQueue(
+ &QueueHandle,
+ QueueType,
+ ObjectName
+ );
+
+ *pQueueHandle = (USHORT) QueueHandle;
+
+ return (Rc);
+
+}
+
+
+APIRET
+Dos16OpenQueue(
+ OUT PUSHORT pOwnerProcessId,
+ OUT PUSHORT pQueueHandle,
+ IN PSZ ObjectName
+ )
+
+{
+ PID OwnerProcessId;
+ HQUEUE QueueHandle;
+ APIRET Rc;
+
+ try
+ {
+ Od2ProbeForWrite(pOwnerProcessId, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pQueueHandle, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ OwnerProcessId = (PID) *pOwnerProcessId;
+ QueueHandle = (HQUEUE) *pQueueHandle;
+
+ Rc = DosOpenQueue(
+ &OwnerProcessId,
+ &QueueHandle,
+ ObjectName
+ );
+
+ *pOwnerProcessId = (USHORT) OwnerProcessId;
+ *pQueueHandle = (USHORT) QueueHandle;
+
+ return (Rc);
+
+}
+
+
+APIRET
+Dos16QueryQueue(
+ OUT HQUEUE QueueHandle,
+ OUT PUSHORT pCountQueueElements
+ )
+
+{
+ ULONG CountQueueElements;
+ APIRET Rc;
+
+ try
+ {
+ Od2ProbeForWrite(pCountQueueElements, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ CountQueueElements = (ULONG) *pCountQueueElements;
+
+ Rc = DosQueryQueue(
+ QueueHandle,
+ &CountQueueElements
+ );
+
+ *pCountQueueElements = (USHORT) CountQueueElements;
+
+ return (Rc);
+
+}
+
+
diff --git a/private/os2/client/dllremot.c b/private/os2/client/dllremot.c
new file mode 100644
index 000000000..1da126b1b
--- /dev/null
+++ b/private/os2/client/dllremot.c
@@ -0,0 +1,491 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllremote.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 file handle manipulation API calls
+ for file handles inherited from remote process (os2.exe)
+
+Author:
+
+ Avi Nathan (avin) 30-Sep-1991
+
+Revision History:
+
+--*/
+
+
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FILESYS
+#include "os2dll.h"
+#include "conrqust.h"
+#include "os2win.h"
+
+APIRET
+RemoteSetHandleStateRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ IN ULONG OpenMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the open mode for a pipe handle.
+
+Arguments:
+
+ hFileRecord - pointer to record of OS/2 pipe handle
+
+ OpenMode - open mode to set
+
+Return Value:
+
+ TBS
+
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(hFileRecord);
+ UNREFERENCED_PARAMETER(OpenMode);
+
+#if DBG
+ IF_OD2_DEBUG( ANY )
+ {
+ DbgPrint ("RemoteSetHandleStateRoutine: not supported yet\n");
+ }
+#endif
+ return NO_ERROR;
+}
+
+
+APIRET
+RemoteQueryHTypeRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PULONG HandleType,
+ OUT PULONG DeviceFlags
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the handle type of con
+
+Arguments:
+
+ hFileRecord - pointer to record of OS/2 con handle
+
+ HandleType - where to store the handle type
+
+ DeviceFlags - where to store the device flags
+
+Return Value:
+
+ none
+
+--*/
+
+{
+#if DBG
+ IF_OD2_DEBUG(ALL_VIO)
+ {
+ DbgPrint("RemoteQueryHTypeRoutine: Handle %p\n", hFileRecord );
+ }
+#endif
+
+ *DeviceFlags = hFileRecord->DeviceAttribute;
+ *HandleType = hFileRecord->FileType;
+ return NO_ERROR;
+
+}
+
+
+APIRET
+RemoteCloseRoutine(
+ IN PFILE_HANDLE hFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes an WIN handle of a remote device (from OS2.EXE).
+ The handle is not freed.
+
+Arguments:
+
+ hFileRecord - pointer to record of OS/2 handle to close.
+
+Return Value:
+
+ TBS
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ USHORT *Count = NULL, Flag;
+ APIRET RetCode;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "RemoteCloseRoutine";
+
+ IF_OD2_DEBUG(ALL_VIO)
+ {
+ DbgPrint("%s: Handle %p\n", FuncName, hFileRecord );
+ }
+#endif
+
+ InvalidateHandle(hFileRecord);
+
+ if (hFileRecord->NtHandle == SesGrp->StdIn)
+ {
+ Count = &SesGrp->StdInHandleCount;
+ Flag = SesGrp->StdInFlag;
+ } else if (hFileRecord->NtHandle == SesGrp->StdOut)
+ {
+ Count = &SesGrp->StdOutHandleCount;
+ Flag = SesGrp->StdOutFlag;
+ } else if (hFileRecord->NtHandle == SesGrp->StdErr)
+ {
+ Count = &SesGrp->StdErrHandleCount;
+ Flag = SesGrp->StdErrFlag;
+ }
+
+ if (Od2SigHandlingInProgress &&
+ Od2CurrentThreadId() == 1) {
+ //
+ // We don't want to be blocked inside a sig handler
+ // and if the count is one higher no harm
+ //
+ return NO_ERROR;
+
+ }
+
+#if DBG
+ AcquireStdHandleLock(FuncName);
+#else
+ AcquireStdHandleLock();
+#endif
+
+ if (Count && *Count) /* if legal and open */
+ {
+ (*Count)--; /* one less handle */
+
+ if ((!*Count) && !Flag)
+ { /* closing last copy of the handle if not console */
+
+#if DBG
+ ReleaseStdHandleLock(FuncName);
+#else
+ ReleaseStdHandleLock();
+#endif
+
+ RetCode = RemoteCloseHandle((HANDLE) hFileRecord->NtHandle);
+ return( RetCode );
+ }
+ }
+
+#if DBG
+ ReleaseStdHandleLock(FuncName);
+#else
+ ReleaseStdHandleLock();
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+RemoteDupHandleRoutine(
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine duplicates an OS/2 handle to a device.
+
+Arguments:
+
+ VectorType - device type
+
+ hOldFileRecord - pointer to OS/2 handle record to duplicate
+
+ hNewFileRecord - pointer to allocated new OS/2 handle record
+
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ exclusive File lock must be acquired BEFORE calling this routine
+
+--*/
+
+{
+ USHORT *Count = NULL;
+ APIRET Rc = NO_ERROR;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "RemoteDuoHandleRoutine";
+
+ IF_OD2_DEBUG(ALL_VIO)
+ {
+ DbgPrint("%s: Old %p, New %p\n",
+ FuncName, hOldFileRecord, hNewFileRecord );
+ }
+#endif
+
+ if (hOldFileRecord->NtHandle == SesGrp->StdIn)
+ {
+ Count = &SesGrp->StdInHandleCount;
+ } else if (hOldFileRecord->NtHandle == SesGrp->StdOut)
+ {
+ Count = &SesGrp->StdOutHandleCount;
+ } else if (hOldFileRecord->NtHandle == SesGrp->StdErr)
+ {
+ Count = &SesGrp->StdErrHandleCount;
+ }
+
+ if (!Od2SigHandlingInProgress ||
+ Od2CurrentThreadId() != 1) {
+ //
+ // We don't want to be blocked inside a sig handler
+ // and if the count is one higher no harm
+ //
+
+#if DBG
+ AcquireStdHandleLock(FuncName);
+#else
+ AcquireStdHandleLock();
+#endif
+
+ }
+
+ if (Count && *Count) /* if legal and open */
+ {
+ (*Count)++; /* one more handle */
+ hNewFileRecord->Flags = hOldFileRecord->Flags;
+ hNewFileRecord->NtHandle = hOldFileRecord->NtHandle;
+ hNewFileRecord->FileType = hOldFileRecord->FileType;
+ hNewFileRecord->IoVectorType = hOldFileRecord->IoVectorType;
+ ValidateHandle(hNewFileRecord);
+ } else
+ Rc = ERROR_INVALID_HANDLE; // BUGBUG bogus error value
+
+ if (!Od2SigHandlingInProgress ||
+ Od2CurrentThreadId() != 1) {
+
+#if DBG
+ ReleaseStdHandleLock(FuncName);
+#else
+ ReleaseStdHandleLock();
+#endif
+
+ }
+
+ return Rc;
+}
+
+
+APIRET
+RemoteReadRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads from con.
+
+Arguments:
+
+ hFileRecord - pointer to OS/2 file handle record to read from
+
+ Buffer - buffer to read data into
+
+ Length - length of buffer
+
+ BytesRead - where to store number of bytes read
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ This routine releases the filelock.
+
+--*/
+
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+ FuncName = "RemoteReadRoutine";
+
+ IF_OD2_DEBUG(ALL_VIO)
+ {
+ DbgPrint("RemoteReadRoutine: Length %lx, Handle %p\n",
+ Length, hFileRecord );
+ }
+#endif
+
+ if (hFileRecord->NtHandle != SesGrp->StdIn)
+ {
+ ReleaseFileLockShared(
+ #if DBG
+ FuncName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE; // BUGBUG bogus error value
+ }
+
+ if (SesGrp->StdInFlag)
+ {
+ //
+ // KbdRead calls ReleaseFileLockShared
+ //
+ RetCode = KbdRead(hFileRecord, Buffer, Length, BytesRead, KBDReadStdIn);
+ } else
+ {
+ RetCode = Ow2ConReadFile((HANDLE) hFileRecord->NtHandle,
+ Length,
+ Buffer,
+ BytesRead);
+
+ ReleaseFileLockShared(
+ #if DBG
+ FuncName
+ #endif
+ );
+ }
+
+ return(RetCode);
+}
+
+
+APIRET
+RemoteWriteRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ )
+
+/*++
+
+Routine Description:
+
+ This routine write to the con.
+
+Arguments:
+
+ hFileRecord - pointer to OS/2 pipe handle record to write to
+
+ Buffer - buffer to write data to
+
+ Length - length of buffer
+
+ BytesWritten - where to store number of bytes written
+
+Return Value:
+
+ TBS.
+
+Note:
+
+ This routine releases the filelock.
+
+--*/
+
+{
+ APIRET RetCode;
+ USHORT Flag;
+ VIOREQUESTNUMBER VioRequest;
+
+#if DBG
+ PSZ FuncName;
+ FuncName = "RemoteWriteRoutine";
+
+ IF_OD2_DEBUG(ALL_VIO)
+ {
+ DbgPrint("RemoteWriteRoutine: Length %lx, Handle %p\n",
+ Length, hFileRecord );
+ }
+#endif
+
+ if (hFileRecord->NtHandle == SesGrp->StdOut)
+ {
+ Flag = SesGrp->StdOutFlag;
+ VioRequest = VIOWrtStdOut;
+ } else if (hFileRecord->NtHandle == SesGrp->StdErr)
+ {
+ Flag = SesGrp->StdErrFlag;
+ VioRequest = VIOWrtStdErr;
+ } else {
+
+ ReleaseFileLockShared(
+ #if DBG
+ FuncName
+ #endif
+ );
+ return ERROR_INVALID_HANDLE;
+ }
+
+ if (Flag)
+ {
+ ReleaseFileLockShared(
+ #if DBG
+ FuncName
+ #endif
+ );
+
+ RetCode = VioWrite(hFileRecord, Buffer, Length, BytesWritten, VioRequest);
+
+ } else
+ {
+ RetCode = Ow2ConWriteFile((HANDLE) hFileRecord->NtHandle,
+ Length,
+ Buffer,
+ BytesWritten);
+
+ ReleaseFileLockShared(
+ #if DBG
+ FuncName
+ #endif
+ );
+ }
+
+ return(RetCode);
+
+}
+
+
+APIRET
+RemoteCloseHandle(HANDLE Handle)
+{
+ return( Ow2ConCloseHandle(Handle));
+}
diff --git a/private/os2/client/dllsem.c b/private/os2/client/dllsem.c
new file mode 100644
index 000000000..4f84bfa25
--- /dev/null
+++ b/private/os2/client/dllsem.c
@@ -0,0 +1,483 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllsem.c
+
+Abstract:
+
+ This module implements common routines to support the OS/2 V2.0
+ Semaphore API Calls. See dllevent.c, dllmutex.c and dllmuxwt.c for
+ the implementations of the API calls.
+
+Author:
+
+ Steve Wood (stevewo) 02-Nov-1989
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+
+POR2_HANDLE_TABLE
+Od2GetSemaphoreTable(
+ BOOLEAN SharedSem,
+ BOOLEAN CreateOkay
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns a pointer to the appropriate OS/2 Semaphore table,
+ either shared or private, based on the value of the first parameter. The
+ second parameter specifies if the table should be created and initialized
+ if it does not already exist for the current process. Returns null if
+ table does not exist and the second parameter is FALSE or if the second
+ parameter is TRUE and this function is unable to create the table.
+
+ Semaphore tables are essentially handle tables. They are an array of
+ fixed size structures (OD2_SEMAPHORE) indexed by the low order 16 bits
+ of an OS/2 semaphore handle.
+
+Arguments:
+
+ SharedSem - If this parameter is TRUE, then a pointer to shared semaphore
+ table is returned. Otherwise a pointer to the private semaphore
+ table is returned.
+
+ CreateOkay - If this parameter is TRUE, then an attempt is made to create
+ and initialize the requested semaphore table if it does not already
+ exist. Returns NULL if unable to create.
+
+Return Value:
+
+ Pointer to the requested semaphore table or NULL.
+
+--*/
+
+{
+ POR2_HANDLE_TABLE *SemaphoreTablePointer;
+ POR2_HANDLE_TABLE SemaphoreTable;
+
+ if (!CreateOkay) {
+ if (SharedSem) {
+ return( Od2Process->SharedSemaphoreTable );
+ }
+ else {
+ return( Od2Process->PrivateSemaphoreTable );
+ }
+ }
+
+ //
+ // We are querying/modifying process state, so don't let others in while
+ // we are about it.
+ //
+
+ AcquireTaskLock();
+
+ //
+ // Compute pointer to the requested semaphore table pointer.
+ //
+
+ if (SharedSem) {
+ SemaphoreTablePointer = &Od2Process->SharedSemaphoreTable;
+ }
+ else {
+ SemaphoreTablePointer = &Od2Process->PrivateSemaphoreTable;
+ }
+
+ //
+ // If the requested semaphore table has not been created yet, and the
+ // caller said it was okay to create it, then attempt to do so, using
+ // a default initial size of 5 entries.
+ //
+
+ if ((SemaphoreTable = *SemaphoreTablePointer) == NULL) {
+ SemaphoreTable = Or2CreateHandleTable( Od2Heap,
+ sizeof( OD2_SEMAPHORE ),
+ 5
+ );
+ //
+ // Update the appropriate field in the process structure with the
+ // address of the newly created semaphore table, or NULL if the
+ // create failed.
+ //
+
+ *SemaphoreTablePointer = SemaphoreTable;
+ }
+
+ //
+ // Done mucking about, release the process structure lock.
+ //
+
+ ReleaseTaskLock();
+
+ return( SemaphoreTable );
+}
+
+
+HSEM
+Od2ConstructSemaphoreHandle(
+ IN BOOLEAN SharedSem,
+ IN ULONG Index
+ )
+
+/*++
+
+Routine Description:
+
+ This function constructs an OS/2 Semaphore handle. The format of
+ an OS/2 2.0 Semaphore handle is:
+
+ 3322222222221111111111
+ 10987654321098765432109876543210
+
+ Ssssssssssssssssiiiiiiiiiiiiiiii
+
+ where:
+
+ S - Shared semaphore bit (DC_SEM_SHARED)
+
+ s - 15 bit semaphore signature field (DC_SEM_SIGBITS). For OS/2 2.0
+ these were always equal to 0x1 (DC_SEM_HANDLESIG). This allows
+ the kernel named pipe code distinguish between 16:16 system
+ semaphores and 32 bit event semaphores.
+
+ i - 16 bit index field.
+
+ None of this was documented to the ISV for OS/2 2.0, but we maintain it
+ just out of paranoia.
+
+Arguments:
+
+ SharedSem - If this parameter is set, then the S bit in the returned
+ handle is also set.
+
+ Index - The lower order 16 bits of this parameter are stored in the Index
+ field of the returned handle.
+
+
+Return Value:
+
+ An OS/2 2.0 Semaphore handle, in the same format as defined by the
+ implementation of OS/2 2.0. No error return is possible, since it is
+ assumed the the Index parameter does not exceed 16 bits of significance.
+
+--*/
+
+{
+ if (SharedSem) {
+ return( (HSEM)(SEM_SHARED | SEM_HANDLESIG | (Index & SEM_INDEX)) );
+ }
+ else {
+ return( (HSEM)(SEM_HANDLESIG | (Index & SEM_INDEX)) );
+ }
+}
+
+
+APIRET
+Od2ValidateSemaphoreHandle(
+ IN HSEM SemaphoreHandle,
+ OUT PBOOLEAN SharedSem,
+ OUT PULONG Index
+ )
+
+/*++
+
+Routine Description:
+
+ This function validates an OS/2 2.0 Semaphore handle and breaks it up
+ into its constituent parts.
+
+Arguments:
+
+ SemaphoreHandle - OS/2 2.0 32 bit semaphore handle. See description
+ of Od2ConstructSemaphoreHandle for format.
+
+ SharedSem - Pointer a boolean variable that is set to TRUE or FALSE
+ depending upon whether the S bit in the input handle it set or not.
+
+ Index - Pointer to a variable that is set to the contents of the Index
+ field of the input handle.
+
+Return Value:
+
+ OS/2 Error Code - one of the following:
+
+ NO_ERROR - success
+
+ ERROR_INVALID_HANDLE - if the signature field does not match the value
+ defined by the OS/2 2.0 implementation (SEM_HANDLESIG).
+
+--*/
+
+{
+ if (((ULONG)SemaphoreHandle & SEM_SIGBITS) != SEM_HANDLESIG) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ if (((ULONG)SemaphoreHandle & SEM_SHARED) != 0) {
+ *SharedSem = TRUE;
+ }
+ else {
+ *SharedSem = FALSE;
+ }
+
+ *Index = (ULONG)SemaphoreHandle & SEM_INDEX;
+ return( NO_ERROR );
+}
+
+
+POD2_SEMAPHORE
+Od2ReferenceSemaphore(
+ IN POD2_SEMAPHORE Semaphore
+ )
+{
+ Semaphore->PointerCount++;
+
+ return( Semaphore );
+}
+
+
+VOID
+Od2DereferenceSemaphore(
+ IN POD2_SEMAPHORE Semaphore
+ )
+{
+ Semaphore->PointerCount--;
+
+ return;
+}
+
+
+VOID
+Od2ThreadWaitingOnSemaphore(
+ IN POR2_HANDLE_TABLE SemaphoreTable,
+ IN POD2_SEMAPHORE Semaphore,
+ IN BOOLEAN AboutToWait
+ )
+{
+ PTEB Teb;
+ POD2_THREAD Thread;
+
+ Teb = NtCurrentTeb();
+ Thread = (POD2_THREAD)Teb->EnvironmentPointer;
+
+ if (AboutToWait) {
+ Thread->WaitingForSemaphore = Od2ReferenceSemaphore( Semaphore );
+ ReleaseHandleTableLock( SemaphoreTable );
+ }
+ else {
+ AcquireHandleTableLock( SemaphoreTable );
+ Thread->WaitingForSemaphore = NULL;
+ Od2DereferenceSemaphore( Semaphore );
+ ReleaseHandleTableLock( SemaphoreTable );
+ }
+}
+
+POD2_THREAD
+Od2SearchForWaitingThread(
+ IN POD2_SEMAPHORE Semaphore
+ )
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POD2_THREAD Thread;
+ POD2_MUXWAIT_SEMAPHORE MuxWait;
+ POD2_MUXWAIT_RECORD MuxWaitRecord;
+ USHORT i;
+
+ //
+ // If pointer count is zero then no waits can be outstanding.
+ //
+
+ if (Semaphore->PointerCount == 0) {
+ return( NULL );
+ }
+
+ //
+ // Walk the list of threads to see if any are waiting for the passed
+ // semaphore, either directly or indirectly via a MuxWait semaphore.
+ //
+
+ ListHead = &Od2Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OD2_THREAD, Link );
+ if (Thread->WaitingForSemaphore != NULL) {
+ if (Thread->WaitingForSemaphore == Semaphore) {
+ return( Thread );
+ }
+ else
+ if (Thread->WaitingForSemaphore->Type == Od2MuxWaitSem) {
+ MuxWait = Thread->WaitingForSemaphore->u.MuxWait;
+ if (MuxWait->Type == Semaphore->Type) {
+ MuxWaitRecord = &MuxWait->MuxWaitRecords[ 0 ];
+ for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
+ if (MuxWaitRecord->Semaphore == Semaphore) {
+ return( Thread );
+ }
+ MuxWaitRecord++;
+ }
+ }
+ }
+ }
+
+ ListNext = ListNext->Flink;
+ }
+
+ return( NULL );
+}
+
+
+VOID
+Od2SemaphoreDestroyProcedure(
+ IN POD2_SEMAPHORE Semaphore,
+ IN ULONG HandleIndex
+ )
+{
+ HSEM SemaphoreHandle;
+ APIRET rc;
+
+ SemaphoreHandle = Od2ConstructSemaphoreHandle( (BOOLEAN)Semaphore->Shared,
+ HandleIndex
+ );
+ rc = NO_ERROR;
+ while (rc == NO_ERROR && Semaphore->OpenCount != 0) {
+ switch ((ULONG)Semaphore->Type) {
+ case Od2EventSem:
+#if DBG
+ IF_OD2_DEBUG( CLEANUP ) {
+ DbgPrint( "OS2DLL: Pid: %lX - DosCloseEventSem( %lX )\n",
+ Od2Process->Pib.ProcessId,
+ SemaphoreHandle
+ );
+ }
+#endif
+ rc = DosCloseEventSem( SemaphoreHandle );
+ break;
+/*
+ case Od2MutexSem:
+#if DBG
+ IF_OD2_DEBUG( CLEANUP ) {
+ DbgPrint( "OS2DLL: Pid: %lX - DosCloseMutexSem( %lX )\n",
+ Od2Process->Pib.ProcessId,
+ SemaphoreHandle
+ );
+ }
+#endif
+ rc = DosCloseMutexSem( SemaphoreHandle );
+ break;
+
+ case Od2MuxWaitSem:
+#if DBG
+ IF_OD2_DEBUG( CLEANUP ) {
+ DbgPrint( "OS2DLL: Pid: %lX - DosCloseMuxWaitSem( %lX )\n",
+ Od2Process->Pib.ProcessId,
+ SemaphoreHandle
+ );
+ }
+#endif
+ rc = DosCloseMuxWaitSem( SemaphoreHandle );
+ break;
+*/
+ default:
+ return;
+ }
+ }
+
+ return;
+}
+
+
+
+VOID
+Od2CloseAllSemaphores( VOID )
+{
+ if (Od2Process->PrivateSemaphoreTable != NULL) {
+ Or2DestroyHandleTable(
+ Od2Process->PrivateSemaphoreTable,
+ (OR2_DESTROY_HANDLE_ROUTINE)Od2SemaphoreDestroyProcedure
+ );
+
+ Od2Process->PrivateSemaphoreTable = NULL;
+ }
+
+ if (Od2Process->SharedSemaphoreTable != NULL) {
+ Or2DestroyHandleTable(
+ Od2Process->SharedSemaphoreTable,
+ (OR2_DESTROY_HANDLE_ROUTINE)Od2SemaphoreDestroyProcedure
+ );
+
+ Od2Process->SharedSemaphoreTable = NULL;
+ }
+}
+
+
+#if DBG
+
+VOID
+Od2SemaphoreDumpProcedure(
+ IN POD2_SEMAPHORE Semaphore,
+ IN ULONG HandleIndex,
+ IN PVOID DumpParameter
+ )
+{
+ UNREFERENCED_PARAMETER(DumpParameter);
+ DbgPrint( " %3ld %2ld %4ld %4ld %8lx %s\n",
+ HandleIndex,
+ (ULONG)Semaphore->Type,
+ (ULONG)Semaphore->OpenCount,
+ (ULONG)Semaphore->PointerCount,
+ (ULONG)Semaphore->u.Value,
+ Semaphore->Shared ? "Yes" : "No"
+ );
+ return;
+}
+
+VOID
+Od2DumpAllSemaphores(
+ IN PCHAR Title
+ )
+{
+ ULONG n;
+
+ if (Od2Process->PrivateSemaphoreTable != NULL &&
+ (Od2Process->PrivateSemaphoreTable->CountEntries >
+ Od2Process->PrivateSemaphoreTable->CountFreeEntries
+ )
+ ) {
+ DbgPrint( "\nDump Of OS/2 Client Private Semaphore Table: %s\n", Title );
+ DbgPrint( "Index Type Ocnt Pcnt Value Shared\n" );
+ n = Or2DumpHandleTable(
+ Od2Process->PrivateSemaphoreTable,
+ (OR2_DUMP_HANDLE_ROUTINE)Od2SemaphoreDumpProcedure,
+ NULL
+ );
+
+ DbgPrint( "Total number of valid private semaphores: %ld\n", n );
+ }
+
+ if (Od2Process->SharedSemaphoreTable != NULL &&
+ (Od2Process->SharedSemaphoreTable->CountEntries >
+ Od2Process->SharedSemaphoreTable->CountFreeEntries
+ )
+ ) {
+ DbgPrint( "\nDump Of OS/2 Client Shared Semaphore Table: %s\n", Title );
+ DbgPrint( "Index Type Ocnt Pcnt Value Shared\n" );
+ n = Or2DumpHandleTable(
+ Od2Process->SharedSemaphoreTable,
+ (OR2_DUMP_HANDLE_ROUTINE)Od2SemaphoreDumpProcedure,
+ NULL
+ );
+
+ DbgPrint( "\nTotal number of valid shared semaphores: %ld\n", n );
+ }
+}
+
+#endif // DBG
diff --git a/private/os2/client/dllsem16.c b/private/os2/client/dllsem16.c
new file mode 100644
index 000000000..cdb82dc75
--- /dev/null
+++ b/private/os2/client/dllsem16.c
@@ -0,0 +1,4340 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllsem16.c
+
+Abstract:
+
+ This module implements 32 equivalents of OS/2 V1.21 Semaphore
+ API Calls. These are called from 16->32 thunks (i386\doscalls.asm).
+
+ NOTE: there is a semantic problem with os2 1.x Semaphores since
+ they are used in both a mutex manner (Request/Clear) and an event
+ manner (Wait/Clear). The manuals don't tell apps writers what will
+ happen if they use the same semaphore both ways.
+
+ The current implementation is: A semaphore is associated with
+ an Nt Semaphore object AND a Cruiser event. If Wait is called,
+ it blocks on the event. If a request is called, it blocks on the
+ Semaphore. A clear can be both a Release and a Post, depends on the
+ Wait/Request called.
+
+Author:
+
+ Yaron Shamir (YaronS) 12-Apr-1991 (stubs)
+
+ Yaron Shamir (YaronS) 28-May-1991 (implementation as described above)
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "os2win.h"
+#include "stdlib.h"
+
+#if DBG
+// Set the values as appropriate (with NTSD or at compile-time) to see all
+// semaphore operations relating to any of these 4 semaphores.
+// To disable this feature, leave the variables at 0.
+// WARNING: remember to use the flat address, not the 16-bit seg:off
+PVOID Os2DebugSem = (HSEM)0x0;
+PVOID Os2DebugSem1 = (HSEM)0x0;
+PVOID Os2DebugSem2 = (HSEM)0x0;
+PVOID Os2DebugSem3 = (HSEM)0x0;
+// Undef the 2 lines below to see print-out of failures to open this NT event
+//#define DBG_SEM_EVENT_STR "\\SEM\\HACKNT3C"
+//#define DBG_SEM_INDEX 0x3c
+#endif // DBG
+
+ //
+ // Owner Thread values:
+ //
+ // SEM_AT_INIT - semaphore initialized, used both for mutex and for event semanitcs
+ // SEM_MUTEX_NO_OWNER - mutex semaphore, not owned
+ // SEM_EVENT - event semaphore (sem/wait/clear)
+ // Other - mutex semaphore, owned
+ //
+#define SEM_DUAL -3
+#define SEM_AT_INIT -2
+#define SEM_MUTEX_NOT_OWNED -1
+#define SEM_EVENT 0
+
+#define OD2SEMTHRESHOLD 800
+ULONG Od2NumSemCreated = 0;
+ //
+ // The following support the hacky pm print driver usage of FS ram semaphore
+ // with cb == 12 instead of 14 as documented
+ //
+#define NUMOFPRINTDRIVERSEM 500
+PULONG pHackPrinterDriverSem;
+
+ //
+ // The following is used to sync RAM shared semaphores
+ //
+HANDLE Od2SyncSem;
+
+ //
+ // The following is used to sync when garbage collector is at work
+ //
+HANDLE Od2GarbageCollectSem;
+ //
+ // The following flag is used to optimized allocation
+ // of semaphores until no more space/reources, then we lock
+ // it all, clean and unlock
+ //
+BOOLEAN LockFlag = FALSE;
+
+ //
+ // The hint for the next index for shared RAM semaphore
+ //
+USHORT Od2SemIndexHint;
+
+ //
+ // Special Heap for tiled structrures - need to be in the 512M tiled area
+ //
+extern PVOID Od2TiledHeap;
+
+APIRET
+DosGetShrSeg(
+ IN PSZ pszSegName,
+ OUT PSEL pSel
+ );
+
+APIRET
+DosAllocShrSeg(
+ IN USHORT cbSize,
+ IN PSZ pszSegName,
+ OUT PSEL pSel
+ );
+
+APIRET
+DosHoldSignal(
+ ULONG fDisable,
+ ULONG pstack
+ );
+
+APIRET
+DosCloseSemNoRemove(
+ IN POS21X_SEM pRealSem,
+ IN BOOL FreeMem
+ );
+
+APIRET
+DosSemWait(
+ IN HSEM hsem,
+ IN LONG lTimeOut
+ );
+
+APIRET
+Od2CloseSem(
+ IN BOOL SyncFlag,
+ IN HSEM hsem
+ );
+
+// Alertable wait for single object. By enabling alert allow context change to be
+// done by server. But in the case that it wasn't done, continue to wait for the
+// object.
+
+NTSTATUS
+Od2AlertableWaitForSingleObject(
+ IN HANDLE handle
+ )
+{
+ NTSTATUS Status;
+
+ while (((Status =
+ NtWaitForSingleObject(
+ handle,
+ TRUE, // alertable
+ NULL)) == STATUS_ALERTED) || (Status == STATUS_USER_APC)) {
+#if DBG
+ if (Status == STATUS_USER_APC) {
+ DbgPrint("WARNING !!! Od2AlertableWaitForSingleObject was broken by APC\n");
+ }
+#endif
+ }
+ return Status;
+}
+
+NTSTATUS
+Od2AcquireMutant(
+ IN HANDLE handle
+ )
+{
+ if (Od2CurrentThreadId() == 1) {
+ DosHoldSignal(HLDSIG_DISABLE, 0);
+ }
+ return Od2AlertableWaitForSingleObject(handle);
+}
+
+NTSTATUS
+Od2ReleaseMutant(
+ IN HANDLE handle
+ )
+{
+ NTSTATUS Status;
+
+ Status = NtReleaseMutant(handle, NULL);
+ if (Od2CurrentThreadId() == 1) {
+ DosHoldSignal(HLDSIG_ENABLE, 0);
+ }
+ return Status;
+}
+
+// Acquire Sync Sem. Write the thread Id of the thread that started critical
+// semaphore processing. This will be used by server to allow to the thread
+// owner Sync to finish semaphores processing before termination.
+
+NTSTATUS
+Od2AcquireSync(VOID)
+{
+ NTSTATUS Status;
+
+ Status = Od2AcquireMutant(Od2SyncSem);
+ if (NT_SUCCESS(Status)) {
+ Od2Process->Pib.SyncOwner = Od2CurrentThreadId();
+ }
+ else
+ {
+#if DBG
+ DbgPrint("Od2AcquireSync: Wait for Sync, Status=%x\n", Status);
+ ASSERT(FALSE);
+#endif // DBG
+ }
+ return Status;
+}
+
+// Release Sync Sem. Before actual release, sign that the semaphore processing is
+// over.
+
+NTSTATUS
+Od2ReleaseSync(VOID)
+{
+ NTSTATUS Status;
+ Od2Process->Pib.SyncOwner = 0;
+ Status = Od2ReleaseMutant(Od2SyncSem);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("Od2AcquireSync: Relsease Sync, Status=%x\n", Status);
+ ASSERT(FALSE);
+ }
+#endif // DBG
+ return Status;
+}
+
+NTSTATUS Od2InitSem()
+{
+ NTSTATUS Status;
+ UNICODE_STRING SemString_U;
+ OBJECT_ATTRIBUTES Obja;
+
+ RtlInitUnicodeString( &SemString_U, OS2_SS_SYNCHRONIZATION_SEM);
+ InitializeObjectAttributes(
+ &Obja,
+ &SemString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ //
+ // Open the global subsystem synchronization Nt mutant
+ //
+ Status = NtOpenMutant(&Od2SyncSem,
+ MUTANT_ALL_ACCESS,
+ &Obja);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("Od2InitSem: error at NtopenSemaphore, Status %x\n", Status);
+ }
+#endif
+ }
+
+ //
+ // Create an Nt mutant that has one free unit, for garbage collect
+ // syncronization
+ //
+ Status = NtCreateMutant(
+ &Od2GarbageCollectSem,
+ MUTANT_ALL_ACCESS,
+ NULL,
+ FALSE);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("Od2InitSem: error at NtCreateSemaphore, Status %x\n", Status);
+ }
+#endif
+ }
+
+ // Initialize index hint for shared RAM semaphores. We assume that there will
+ // be no more than 256 processes permanently. We assume also that there are
+ // no more than 256 shared RAM semaphores will be initialized by each
+ // process. If this assumptions are TRUE, the hint will be always the index of
+ // the empty slot for each process.
+ // Just in the case that there is the process that has been created more then
+ // 256 shared RAM semaphores, the hint will point to the semaphores of the next
+ // process. But there is a good chance that the next process doesn't use
+ // shared RAM semaphores at all or uses semaphores of the processes that
+ // were started before, or uses a little number of semaphores.
+
+ Od2SemIndexHint = (((USHORT)Od2Process->Pib.ProcessId) << 8);
+
+ return(Status);
+}
+
+
+POS21X_SEM
+Od2LookupSem (
+ HSEM hsem
+ )
+{
+ POS21X_SEM pSem;
+ BOOLEAN TookTaskLock = FALSE;
+ NTSTATUS Status;
+
+ pSem = (POS21X_SEM)(*(PULONG)hsem & 0xFFFFFFFC);
+ if (((ULONG)pSem < (ULONG)Od2TiledHeap + OD2TILEDHEAP_SIZE) && ((ULONG)pSem >= (ULONG)Od2TiledHeap)) {
+ //
+ // No need for special support (RAM sem in shared memory hook)
+ // - the 4 bytes in user area contains
+ // bit: 31 1
+ // | pointer to prealsem in od2heap | 2bits for set/clear
+ //
+ if (pSem->pMyself == (PVOID)hsem) {
+ return pSem;
+ }
+#if DBG
+ else {
+ DbgPrint("[%d,%d]Od2LookupSem: Private RAM sem signature corrupted hsem=%x, *hsem=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ pSem
+ );
+ }
+#endif // DBG
+ }
+
+ if (LockFlag) {
+ TookTaskLock = TRUE;
+ Status = Od2AcquireMutant(Od2GarbageCollectSem);
+#if DBG
+ if (!NT_SUCCESS(Status) && Status != STATUS_SEMAPHORE_LIMIT_EXCEEDED) {
+ KdPrint(("Od2LookupSem: failed to NtWaitForSingleObject on garbage sem, Status=%x\n",
+ Status));
+ }
+ else if (Status != STATUS_SUCCESS) {
+ DbgPrint("[%d,%d] Od2LookupSem: WARNING !!! Wait on GarbageCollectSem, status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ }
+ //
+ // Special support for RAM semaphores in shared memory - we look
+ // them up in the linked list
+ //
+lookagain:
+ pSem = (POS21X_SEM)Od2Sem16ListHead;
+
+ try {
+ while (pSem != NULL) {
+
+ //
+ // Check if pMyself is equal to hsem
+ //
+ if (pSem->pMyself == (PVOID)hsem) {
+
+ //
+ // Special support for lousy apps like SQL1.11,
+ // that look for RAM sem being zero after clear
+ //
+ if (((*(PULONG)hsem & 0xFFFFFFFC) == 0) && (pSem->u.SharedRamSignature == 0)){
+ *(PULONG)hsem = (ULONG)pSem | (*(PULONG)hsem & 0x3);
+ }
+
+ if (TookTaskLock) {
+ Status = Od2ReleaseMutant(Od2GarbageCollectSem);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(("Od2LookupSem: failed to NtReleaseSemaphore on sync sem, Status=%x\n",
+ Status));
+ }
+#endif
+ }
+ return pSem;
+ }
+ pSem = (POS21X_SEM)(pSem->Next);
+ }
+ if (TookTaskLock) {
+ Status = Od2ReleaseMutant(Od2GarbageCollectSem);
+ #if DBG
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(("Od2LookupSem: failed to NtReleaseSemaphore on sync sem, Status=%x\n",
+ Status));
+ }
+ #endif
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+#if DBG
+ DbgPrint("Od2LookupSem: A Pointer became invalid while searching\n");
+#endif
+ Sleep(100);
+ goto lookagain;
+ }
+ return NULL;
+}
+
+APIRET
+Od2GetSemNtEvent(
+ IN HSEM hsem,
+ OUT PHANDLE pNtEventHandle
+ )
+{
+ APIRET rc = NO_ERROR;
+ POS21X_SEM pRealSem;
+ POR2_HANDLE_TABLE SemaphoreTable;
+ POD2_SEMAPHORE Semaphore;
+ BOOLEAN SharedSem;
+ ULONG HandleIndex;
+
+ pRealSem = Od2LookupSem (hsem);
+
+ if (pRealSem == NULL)
+ return ERROR_INVALID_HANDLE;
+
+ //
+ // Validate the passed OS/2 2.0 semaphore handle and extract the
+ // shared/private flag and the index field. Return an error if
+ // not a valid handle.
+ //
+
+ rc = Od2ValidateSemaphoreHandle( pRealSem->Event,
+ &SharedSem,
+ &HandleIndex
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Get the pointer to either the shared or private semaphore table.
+ // Table must exist. Return an error if it does not.
+ //
+
+ SemaphoreTable = Od2GetSemaphoreTable( SharedSem, FALSE );
+ if (!SemaphoreTable) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POD2_SEMAPHORE)Or2MapHandle( SemaphoreTable,
+ HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+
+ //
+ // Entry in semaphore table is for an Event semaphore, so extract the
+ // NT Event handle from the record and release the lock, so we are
+ // not holding the lock while we are doing the query.
+ //
+
+ *pNtEventHandle = Semaphore->u.EventHandle;
+ ReleaseHandleTableLock( SemaphoreTable );
+}
+
+POS21X_SEM
+SemWasCreatedByThisProcess(
+ IN PCHAR name)
+{
+ POS21X_SEM pSem;
+
+ for (pSem = (POS21X_SEM)Od2Sem16ListHead;
+ pSem != NULL;
+ pSem = (POS21X_SEM)(pSem->Next)) { // search list for a
+
+ if (pSem->pMyself == (PVOID)(&(pSem->pMyself)) && // System Semaphore
+ !strcmp(pSem->u.SysSemName,name)) { // with same name
+ return(pSem);
+ }
+ }
+ return(NULL);
+}
+
+APIRET
+Od2OpenSem(
+ IN HSEM UserSem,
+ OUT POS21X_SEM *ppRealSem,
+ IN PSZ pszSemName,
+ IN BOOL Insert
+ )
+{
+ APIRET rc = NO_ERROR;
+ NTSTATUS Status;
+ ULONG CreateAttributes = 0;
+ POS21X_SEM pRealSem;
+ PSZ eventname = NULL;
+ PSZ pszSrc, pszDst;
+ STRING CanonicalSemString, CanonicalEventString;
+ UNICODE_STRING CanonicalSemString_U;
+ OBJECT_ATTRIBUTES Obja;
+ BOOL KeepName=FALSE;
+
+ if (pszSemName == NULL)
+ return ERROR_INVALID_NAME;
+
+ //
+ // We support \sem\XXX by creating a named event \sem32\XXX
+ // and a NtSemaphore named \sem32\XXXNt16Sem
+ //
+
+ eventname = RtlAllocateHeap (Od2Heap, 0, CCHMAXPATH);
+ if (eventname == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ //
+ // first chars must be \sem\. We leave the rest for Od2Canonicalize
+ //
+
+ try {
+ if ( ((pszSemName[0] != '\\') && (pszSemName[0] != '/')) ||
+ ((pszSemName[1] != 's') && (pszSemName[1] != 'S')) ||
+ ((pszSemName[2] != 'e') && (pszSemName[2] != 'E')) ||
+ ((pszSemName[3] != 'm') && (pszSemName[3] != 'M')) ||
+ ((pszSemName[4] != '\\') && (pszSemName[4] != '/'))) {
+ return ERROR_INVALID_NAME;
+ }
+ else {
+ eventname[0] = '\\';
+ eventname[1] = 's';
+ eventname[2] = 'e';
+ eventname[3] = 'm';
+ eventname[4] = '3';
+ eventname[5] = '2';
+ eventname[6] = '\\';
+ //
+ // Copy rest of string
+ //
+ pszSrc = pszSemName + 5;
+ pszDst = eventname + 7;
+ while (*pszSrc) {
+ *pszDst++ = *pszSrc++;
+ if ((pszSrc - pszSemName) >= CCHMAXPATH) {
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ return ERROR_INVALID_NAME;
+ }
+ }
+ *pszDst = '\0';
+ }
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP ();
+ }
+ //
+ // Prepare the Nt Semaphore name, by
+ // Canonicalizing and appendint nt16sem
+ //
+ rc = Od2Canonicalize( eventname,
+ CANONICALIZE_SEMAPHORE,
+ &CanonicalEventString,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (rc) {
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ return(rc);
+ }
+
+ if (UserSem == NULL && Insert) {
+ if (pRealSem = SemWasCreatedByThisProcess(CanonicalEventString.Buffer)) {
+
+ //
+ // We tried to open a system semaphore which has already
+ // been created or opened by this process
+ // we just have to inc. the counter and return the same handle
+ //
+
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ RtlFreeHeap(Od2Heap, 0,CanonicalEventString.Buffer);
+
+ if (pRealSem->SysSemCount == 0xff) {
+ KdPrint(("Od2OpenSem: SysSemCount overflow\n"));
+ }
+ else {
+ pRealSem->SysSemCount++;
+ }
+ *ppRealSem = pRealSem;
+ return (NO_ERROR);
+ }
+ KeepName = TRUE;
+ }
+
+
+ CanonicalSemString.Buffer = RtlAllocateHeap (
+ Od2Heap, 0,
+ CanonicalEventString.Length+8 // 8 for Ntsem16
+ );
+
+ if (CanonicalSemString.Buffer == NULL) {
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ RtlFreeHeap(Od2Heap, 0,CanonicalEventString.Buffer);
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ strncpy( CanonicalSemString.Buffer,
+ CanonicalEventString.Buffer,
+ CanonicalEventString.Length
+ );
+ CanonicalSemString.Buffer[CanonicalEventString.Length] = '\0';
+ strcpy(&(CanonicalSemString.Buffer[CanonicalEventString.Length]),
+ "Nt16sem");
+ CanonicalSemString.Buffer[CanonicalEventString.Length + 7] = '\0';
+
+ if (! KeepName) {
+ RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
+ }
+
+ //
+ // Convert Nt Semaphore string to Unicode
+ //
+
+ Od2InitMBString(&CanonicalSemString, CanonicalSemString.Buffer);
+
+ //
+ // UNICODE conversion -
+ //
+ rc = Od2MBStringToUnicodeString(
+ &CanonicalSemString_U,
+ &CanonicalSemString,
+ TRUE);
+
+ RtlFreeHeap(Od2Heap, 0,CanonicalSemString.Buffer);
+
+ if (rc) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("Od2OpenSem: no memory for Unicode Conversion\n");
+ }
+#endif
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ if (KeepName) {
+ RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
+ }
+ return rc;
+ }
+
+ InitializeObjectAttributes(
+ &Obja,
+ &CanonicalSemString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+
+ pRealSem = (HSYSSEM)RtlAllocateHeap (Od2TiledHeap, 0, sizeof (OS21X_SEM));
+ if (pRealSem == NULL) {
+#if DBG
+ DbgPrint("Od2OpenSem: out of space on Od2TiledHeap\n");
+ ASSERT(FALSE);
+#endif
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ RtlFreeUnicodeString (&CanonicalSemString_U);
+ if (KeepName) {
+ RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
+ }
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ if (((ULONG)(pRealSem) > (ULONG)Od2TiledHeap + OD2TILEDHEAP_SIZE) && ((ULONG)(pRealSem) < (ULONG)Od2TiledHeap)) {
+ //
+ // Got out of the initial Heap, return error
+ //
+#if DBG
+ DbgPrint("Od2OpenSem: out of space on Od2TiledHeap\n");
+ ASSERT(FALSE);
+#endif
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ RtlFreeHeap (Od2TiledHeap, 0, pRealSem);
+ RtlFreeUnicodeString (&CanonicalSemString_U);
+ if (KeepName) {
+ RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
+ }
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlZeroMemory(pRealSem, sizeof (OS21X_SEM));
+
+ //
+ // Open an Nt semaphore
+ //
+ Status = NtOpenSemaphore(&(pRealSem->Mutex),
+ SEMAPHORE_ALL_ACCESS,
+ &Obja);
+
+ RtlFreeUnicodeString (&CanonicalSemString_U);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
+ DbgPrint("Od2OpenSem: error at NtopenSemaphore, Status %x\n", Status);
+ }
+#endif
+#if DBG
+ if (((Os2DebugSem != 0) && (UserSem == Os2DebugSem)) ||
+ ((Os2DebugSem3 != 0) && (UserSem == Os2DebugSem3)) ||
+ ((Os2DebugSem2 != 0) && (UserSem == Os2DebugSem2)) ||
+ ((Os2DebugSem1 != 0) && (UserSem == Os2DebugSem1)))
+ {
+ KdPrint(("[%d,%d] Od2OpenSem(%x,*=%x): failed to NtOpenSemaphore, eventname=%s, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ UserSem,
+ *(PULONG)UserSem,
+ eventname,
+ Status));
+ }
+#endif // DBG
+
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ RtlFreeHeap (Od2TiledHeap, 0, pRealSem);
+ if (KeepName) {
+ RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
+ }
+ return ERROR_SEM_NOT_FOUND;
+ }
+
+ rc = DosOpenEventSem(eventname,
+ &(pRealSem->Event));
+
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("Od2OpenSem: error at DosOpenEventSem, Status %d\n", rc);
+ }
+#endif
+#if DBG
+ if (((Os2DebugSem != 0) && (UserSem == Os2DebugSem)) ||
+ ((Os2DebugSem2 != 0) && (UserSem == Os2DebugSem2)) ||
+ ((Os2DebugSem3 != 0) && (UserSem == Os2DebugSem3)) ||
+ ((Os2DebugSem1 != 0) && (UserSem == Os2DebugSem1)))
+ {
+ KdPrint(("[%d,%d] Od2OpenSem(%x,*=%x): failed to DosOpenEventSem, rc=%d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ UserSem,
+ *(PULONG)UserSem,
+ rc));
+ }
+#endif // DBG
+
+ NtClose(pRealSem->Mutex);
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ RtlFreeHeap (Od2TiledHeap, 0, pRealSem);
+ if (KeepName) {
+ RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
+ }
+ return rc;
+ }
+
+ pRealSem->OwnerThread = (TID)SEM_AT_INIT;
+
+ //
+ // UserSem:
+ // if NULL - indicates sys semaphore
+ // if non NULL - this is the pointer to a RAM sem
+ // that resides in a shared mem
+ // the reason we open it is to get real handles between processes
+ //
+ if (UserSem == NULL) {
+ pRealSem->pMyself = (PVOID)(&(pRealSem->pMyself));
+ if (Insert) {
+ pRealSem->u.SysSemName = CanonicalEventString.Buffer;
+ pRealSem->SysSemCount = 1;
+ }
+ }
+ else {
+ pRealSem->pMyself = (PVOID)UserSem;
+ }
+
+
+ RtlFreeHeap (Od2Heap, 0, eventname);
+
+ if (Insert) {
+ //
+ // Link the new semaphore on the per-process semaphore
+ // list
+ //
+
+ Status = Od2AcquireMutant(Od2GarbageCollectSem);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(("Od2OpenSem: failed to NtWaitForSingleObject on garbage sem, Status=%x\n",
+ Status));
+ }
+ else if (Status != STATUS_SUCCESS) {
+ DbgPrint("[%d,%d] Od2OpenSem: WARNING !!! Wait on GarbageCollectSem, status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ pRealSem->Next = Od2Sem16ListHead;
+ Od2Sem16ListHead = (struct OS21X_SEM *)pRealSem;
+ Status = Od2ReleaseMutant(Od2GarbageCollectSem);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(("Od2OpenSem: failed to NtReleaseSemaphore on sync sem, Status=%x\n",
+ Status));
+ }
+#endif
+ }
+
+ //
+ // Now set the output pointer to the sem structure
+ //
+ *ppRealSem = pRealSem;
+
+ return (NO_ERROR);
+}
+
+
+APIRET
+Od2CreateSem(
+ IN HSEM UserSem,
+ IN USHORT fExclusive,
+ OUT POS21X_SEM *ppRealSem,
+ IN PSZ pszSemName
+ )
+{
+ APIRET rc = NO_ERROR;
+ NTSTATUS Status;
+ ULONG CreateAttributes = 0;
+ POS21X_SEM pRealSem;
+ PSZ eventname = NULL;
+ PSZ pszSrc, pszDst;
+ STRING CanonicalSemString, CanonicalEventString;
+ UNICODE_STRING CanonicalSemString_U;
+ OBJECT_ATTRIBUTES Obja, *pObja;
+ CHAR localSecurityDescriptor[SECURITY_DESCRIPTOR_MIN_LENGTH];
+
+ // If the least significant byte of the RAM semaphore isn't 0, it must
+ // be created as busy semaphore. That means that after setting the least
+ // significant byte of the RAM semaphore to non-zero and calling for
+ // DosSemRequest or DosSemWait, thread will wait until any other thread
+ // will clear this semaphore.
+
+ BOOLEAN MakeBusy = (UserSem != NULL) && (((*(PULONG)UserSem) & 0xff) != 0);
+
+ BOOLEAN MakeSys = FALSE, KeepName=FALSE;
+ ULONG RegionSize = 0x10000;
+ ULONG SharedFlag;
+ HSEM tmpsem;
+ char *pchtmp;
+
+ pObja = NULL;
+
+
+ //
+ // UserSem:
+ // if NULL - indicates we create a sys semaphore
+ // by calling DosCreateSem
+ // if non NULL - this is the pointer to a RAM sem
+ // given by the app.
+ //
+
+ if (UserSem == NULL) {
+
+ MakeSys = TRUE;
+
+ } else {
+
+ //
+ // Due to (somewhat awkward) 1.21 semantics, a RAM semaphore
+ // can be magically used by two processes, if happend to reside
+ // in a memory shared between them
+ //
+ rc = DosQueryMem(
+ (PVOID) UserSem,
+ &RegionSize,
+ &SharedFlag);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("Can't query shared mem %d\n", rc);
+ }
+#endif
+ }
+ if (SharedFlag & PAG_SHARED) {
+
+ MakeSys = TRUE;
+ //
+ // makeup a name from the air, to be used later.
+ //
+ pszSemName = "\\SEM\\HACKNT00000";
+ //
+ // try in a loop to open it, increment number until
+ // we succeed.
+ // Start from the hint, that possibly will be the index of
+ // the empty slot.
+ //
+ do
+ {
+ Od2SemIndexHint++;
+ // We don't use index 0
+ if (Od2SemIndexHint == 0) {
+ Od2SemIndexHint++;
+ }
+ //
+ // construct last 4 characters as the digits of i
+ //
+ pchtmp = _itoa (Od2SemIndexHint, &pszSemName[11], 16);
+ rc = Od2OpenSem(NULL, &(POS21X_SEM)tmpsem, pszSemName,TRUE);
+ if (rc != NO_ERROR) {
+
+ //
+ // does not exist - go for it
+ //
+ // HSEM is:
+ //
+ // bit: 31 19 17 1
+ // |magic number|iswait| 16b index | 2bits for set/clear
+
+ *(PULONG)UserSem = ((ULONG)Od2SemIndexHint << 2) | 0xCCC00000;
+
+#if DBG
+#ifdef DBG_SEM_INDEX
+ if (Od2SemIndexHint == DBG_SEM_INDEX) {
+ DbgPrint("[%d,%d] Od2LookUpOrCreateSem: looping for open, got rc=%x for index %x for hsem=%x, *=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ rc,
+ DBG_SEM_INDEX
+ UserSem,
+ *(PULONG)UserSem
+ );
+ }
+#endif // DBG_SEM_INDEX
+#endif // DBG
+ break;
+ }
+ Od2CloseSem(FALSE,tmpsem);
+ } while (TRUE);
+ }
+ }
+
+ if ((MakeSys) && (pszSemName != NULL)) {
+
+ pObja = &Obja;
+
+ //
+ // We support \sem\XXX by creating a named event \sem32\XXX
+ // and a NtSemaphore named \sem32\XXXNt16Sem
+ //
+
+ eventname = RtlAllocateHeap (Od2Heap, 0, CCHMAXPATH);
+ if (eventname == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ //
+ // first chars must be \sem\. We leave the rest for Od2Canonicalize
+ //
+
+ try {
+ if ( ((pszSemName[0] != '\\') && (pszSemName[0] != '/')) ||
+ ((pszSemName[1] != 's') && (pszSemName[1] != 'S')) ||
+ ((pszSemName[2] != 'e') && (pszSemName[2] != 'E')) ||
+ ((pszSemName[3] != 'm') && (pszSemName[3] != 'M')) ||
+ ((pszSemName[4] != '\\') && (pszSemName[4] != '/'))) {
+ return ERROR_INVALID_NAME;
+ }
+ else {
+ eventname[0] = '\\';
+ eventname[1] = 's';
+ eventname[2] = 'e';
+ eventname[3] = 'm';
+ eventname[4] = '3';
+ eventname[5] = '2';
+ eventname[6] = '\\';
+ //
+ // Copy rest of string
+ //
+ pszSrc = pszSemName + 5;
+ pszDst = eventname + 7;
+ while (*pszSrc) {
+ *pszDst++ = *pszSrc++;
+ if ((pszSrc - pszSemName) >= CCHMAXPATH) {
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ return ERROR_INVALID_NAME;
+ }
+ }
+ // Null terminate string
+ *pszDst = '\0';
+ }
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP ();
+ }
+ //
+ // Prepare the Nt Semaphore name, by
+ // Canonicalizing and appendint nt16sem
+ //
+ rc = Od2Canonicalize( eventname,
+ CANONICALIZE_SEMAPHORE,
+ &CanonicalEventString,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ if (rc) {
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ if (rc == ERROR_FILE_NOT_FOUND ||
+ rc == ERROR_PATH_NOT_FOUND ||
+ rc == ERROR_FILENAME_EXCED_RANGE) {
+ return(ERROR_INVALID_NAME);
+ }
+ return(rc);
+ }
+
+ KeepName = (UserSem == NULL);
+
+ CanonicalSemString.Buffer =
+ RtlAllocateHeap (Od2Heap, 0,
+ CanonicalEventString.Length+8 // 8 for Ntsem16
+ );
+
+ if (CanonicalSemString.Buffer == NULL) {
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ RtlFreeHeap(Od2Heap, 0,CanonicalEventString.Buffer);
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ strncpy( CanonicalSemString.Buffer,
+ CanonicalEventString.Buffer,
+ CanonicalEventString.Length
+ );
+ CanonicalSemString.Buffer[CanonicalEventString.Length] = '\0';
+ strcpy (&(CanonicalSemString.Buffer[strlen(CanonicalSemString.Buffer)]),
+ "Nt16sem");
+ CanonicalSemString.Buffer[CanonicalEventString.Length+7] = '\0';
+
+ if (!KeepName) {
+ RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
+ }
+
+ //
+ // Convert Nt Semaphore string to Unicode
+ //
+
+ Od2InitMBString(&CanonicalSemString, CanonicalSemString.Buffer);
+
+ //
+ // UNICODE conversion -
+ //
+
+ rc = Od2MBStringToUnicodeString(
+ &CanonicalSemString_U,
+ &CanonicalSemString,
+ TRUE);
+
+ RtlFreeHeap(Od2Heap, 0,CanonicalSemString.Buffer);
+
+ if (rc) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("Od2CreateSem: no memory for Unicode Conversion\n");
+ }
+#endif
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ if (KeepName) {
+ RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
+ }
+ return rc;
+ }
+
+ // PatrickQ: create and attach a security descriptor. This was missing
+ // till August 10, 1994 and caused a bug when one instance of OS2.EXE
+ // creates an event, then in another user context (e.g. when using AT)
+ // OS2.EXE attempts to open the existing event => gets access denied.
+ // Prevented PMSHELL from running as a service.
+
+ Status = RtlCreateSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION );
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ DbgPrint("OS2: Od2CreateSem, failed at RtlCreateSecurityDescriptor %x\n",
+ Status);
+#endif
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ if (KeepName)
+ {
+ RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
+ }
+ return ERROR_ACCESS_DENIED;
+ }
+
+ Status = RtlSetDaclSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ (BOOLEAN)TRUE,
+ (PACL) NULL,
+ (BOOLEAN)FALSE );
+
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ DbgPrint("OS2: Od2CreateSem, failed at RtlSetDaclSecurityDescriptor %x\n",
+ Status);
+#endif
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ if (KeepName)
+ {
+ RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
+ }
+ return ERROR_ACCESS_DENIED;
+ }
+
+ InitializeObjectAttributes(
+ &Obja,
+ &CanonicalSemString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ (PSECURITY_DESCRIPTOR) &localSecurityDescriptor);
+
+ }
+
+ pRealSem = (HSYSSEM)RtlAllocateHeap (Od2TiledHeap, 0, sizeof (OS21X_SEM));
+ if (pRealSem == NULL) {
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ if (eventname != NULL) {
+ RtlFreeUnicodeString (&CanonicalSemString_U);
+ }
+ if (KeepName) {
+ RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
+ }
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ if (((ULONG)(pRealSem) > (ULONG)Od2TiledHeap + OD2TILEDHEAP_SIZE) && ((ULONG)(pRealSem) < (ULONG)Od2TiledHeap)) {
+ //
+ // Got out of the initial Heap, return error
+ //
+#if DBG
+ DbgPrint("Od2CreateSem: out of space on Od2TiledHeap\n");
+ ASSERT(FALSE);
+#endif
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ RtlFreeHeap (Od2TiledHeap, 0, pRealSem);
+ RtlFreeUnicodeString (&CanonicalSemString_U);
+ if (KeepName) {
+ RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
+ }
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ RtlZeroMemory(pRealSem, sizeof (OS21X_SEM));
+
+ if (UserSem == NULL) {
+ if (fExclusive == CSEM_PUBLIC) {
+ CreateAttributes |= DC_SEM_SHARED;
+ pRealSem->FlagsByte |= SYSSEM_PUBLIC;
+ }
+ else {
+ pRealSem->FlagsByte |= SYSSEM_PRIVATE;
+ }
+ }
+
+ //
+ // Create an Nt semaphore that has one free unit
+ //
+ Status = NtCreateSemaphore(&(pRealSem->Mutex),
+ SEMAPHORE_ALL_ACCESS,
+ pObja,
+ 1,
+ 1);
+
+ if (eventname != NULL) {
+ //
+ // free the unicode allocated string
+ //
+ RtlFreeUnicodeString (&CanonicalSemString_U);
+ }
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("Od2CreateSem: error at NtCreateSemaphore, Status %x\n", Status);
+#endif
+ if (eventname != NULL) {
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ }
+ RtlFreeHeap (Od2TiledHeap, 0, pRealSem);
+ if (KeepName) {
+ RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
+ }
+ switch (Status) {
+ case STATUS_OBJECT_NAME_COLLISION:
+ return ERROR_ALREADY_EXISTS;
+ default:
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_TOO_MANY_SEMAPHORES));
+ }
+ }
+
+ pRealSem->OwnerThread = (TID)SEM_AT_INIT;
+
+ if (MakeBusy) {
+
+ // Busy semaphore will be created. It is created as a result of using
+ // DosSemRequest for the 1st time for the RAM semaphore that it's
+ // least significant byte wasn't zero.
+
+ NTSTATUS Status;
+ TIME Time = {0L, 0L};
+
+ // NT semaphore is free after creation. Take the semaphore
+ // (with timeout 0).
+
+ Status = NtWaitForSingleObject(
+ pRealSem->Mutex,
+ TRUE,
+ &Time);
+
+ // We must always get SUCCESS. The semaphore was just created and
+ // no one can get it, because this code is protected by Od2Sync.
+ // Just in the case ... print appropriate message.
+
+ if (Status != STATUS_SUCCESS) {
+#if DBG
+ DbgPrint("[%d,%d] ERROR !!! Od2CreateSem %x : *=%x NtWaitForSingleObject fail with %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(), UserSem, *(PULONG)UserSem, Status);
+#endif // DBG
+ }
+ else
+ {
+ // Print this message always. We will be prompted if apps
+ // use busy semaphores. Lotus Notes 3.0 is the only known app that
+ // do it.
+#if DBG
+ DbgPrint("[%d,%d] Od2CreateSem %x : *=%x make busy semaphore\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(), UserSem, *(PULONG)UserSem);
+#endif // DBG
+ }
+ }
+
+ // Make the event initially not signaled if the semaphore must be maked
+ // busy.
+
+ rc = DosCreateEventSem(eventname,
+ &(pRealSem->Event),
+ CreateAttributes,
+ !MakeBusy);
+
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("Od2CreateSem: error at DosCreateEventSem, Status %d\n", rc);
+ }
+#endif
+ NtClose(pRealSem->Mutex);
+ if (eventname != NULL)
+ RtlFreeHeap (Od2Heap, 0, eventname);
+ RtlFreeHeap (Od2TiledHeap, 0, pRealSem);
+ if (KeepName) {
+ RtlFreeHeap (Od2Heap, 0, CanonicalEventString.Buffer);
+ }
+ return rc;
+ }
+
+ //
+ // if a system semaphore:
+ // Make pRealSem->pMyself to point at itself
+ // Keep its name
+ //
+ // if a RAM semaphore:
+ // Make pRealSem->pMyself the initial pointer
+ // provided by the program
+ //
+
+ if (UserSem == NULL) {
+ pRealSem->pMyself = (PVOID)(&(pRealSem->pMyself));
+ if (pszSemName != NULL) {
+ pRealSem->u.SysSemName = CanonicalEventString.Buffer;
+ pRealSem->SysSemCount = 1;
+ }
+ }
+ else {
+ pRealSem->pMyself = (PVOID)UserSem;
+ }
+ //
+ // Link the new semaphore on the per-process semaphore
+ // list
+ //
+
+ Status = Od2AcquireMutant(Od2GarbageCollectSem);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(("Od2CreateSem: failed to NtWaitForSingleObject on garbage sem, Status=%x\n",
+ Status));
+ }
+ else if (Status != STATUS_SUCCESS) {
+ DbgPrint("[%d,%d] Od2CreateSem: WARNING !!! Wait on GarbageCollectSem, status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+
+ pRealSem->Next = Od2Sem16ListHead;
+ Od2Sem16ListHead = (struct OS21X_SEM *)pRealSem;
+ Status = Od2ReleaseMutant(Od2GarbageCollectSem);
+#if DBG
+ if (!NT_SUCCESS(Status) && Status != STATUS_SEMAPHORE_LIMIT_EXCEEDED) {
+ KdPrint(("Od2CreateSem: failed to NtReleaseSemaphore on sync sem, Status=%x\n",
+ Status));
+ }
+#endif
+
+ //
+ // Now set the output pointer to the sem structure
+ //
+ *ppRealSem = pRealSem;
+
+ if (eventname != NULL)
+ RtlFreeHeap (Od2Heap, 0, eventname);
+
+ return NO_ERROR;
+}
+
+BOOLEAN GarbageCollect(VOID)
+{
+
+ //
+ // This routine is called when Od2CreateSem is unable to create a new
+ // RAM semaphore. This can be caused by the fact that in OS/2 a RAM semaphore
+ // requires almost 0 resources, while in NT it is a OS21X_SEM strcuture, plus
+ // two objects - event and semaphore
+ //
+ // The algorithm is:
+ // raise the lockflag so subsequent calls to Od2LookupSem lock,
+ // lock the task lock
+ // go thru the list of RAM semaphores, find private RAM semaphores
+ // which are cleared, close them and free heap.
+ // release the task lock. Subsequent calls to the deleted semaphores will
+ // recreate them
+ // clear the lock flag
+ //
+
+ POS21X_SEM pPrevSem, pRealSem;
+ HSEM hsem;
+ NTSTATUS Status;
+ APIRET rc;
+ BOOLEAN DeletedSomeStuff = FALSE;
+ ULONG hsem_value;
+#if DBG
+ ULONG NumSem = 0, NumFreed = 0;
+#endif //DBG
+
+ LockFlag = TRUE;
+ Status = Od2AcquireMutant(Od2GarbageCollectSem);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(("Od2GarbageCollect: failed to NtWaitForSingleObject on garbage sem, Status=%x\n",
+ Status));
+ }
+ else if (Status != STATUS_SUCCESS) {
+ DbgPrint("[%d,%d] GarbageCollect: WARNING !!! Wait on GarbageCollectSem, status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ //
+ // Allow all threads in this process, which may got thru Od2LookupSem,
+ // and did not finish an API, to do so, before we gargage collect
+ // 1. Those that were waiting on a cleared semaphore, will get it
+ // 2. Those that were clearing a semaphore will clear it and free
+ // the threads in category 1.
+ // 3. Those waiting on a non-cleared semaphore, will keep waiting, however
+ // the garbage collector does not free these semaphores.
+ //
+ Sleep(2000);
+ for (pRealSem = pPrevSem = (POS21X_SEM)Od2Sem16ListHead;
+ pPrevSem->Next != NULL;) {
+
+#if DBG
+ NumSem++;
+#endif //DBG
+ //
+ // check if a private RAM sem
+ //
+ hsem = (HSEM)(pRealSem->pMyself);
+
+ // Validate validity of each semaphore in the list
+ try
+ {
+ hsem_value = *(PULONG)hsem;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+#if DBG
+ DbgPrint("[%d,%d] GarbageCollect: WARNING !!! can't access RAM semaphore %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem);
+#endif
+ //
+ // Can't access this semaphore - maybe memory was released !
+ // Remove this semaphore from the list and go to next by
+ // setting value to 0
+ hsem_value = 0;
+ }
+
+ if ((hsem_value != (ULONG)hsem) &&
+ ((hsem_value & 0xFFF00000) != 0xCCC00000)) {
+ //
+ // Private RAM Semaphore:
+ //
+ if (hsem_value == 0) {
+
+ LONG PreviousCount;
+
+ // defend against:DosSemClear already zeroed hsem but haven't
+ // released it yet
+
+ NtReleaseSemaphore (
+ pRealSem->Mutex,
+ 1,
+ &PreviousCount);
+
+ //
+ // It is cleared - delete it
+ //
+
+ Status = NtClose (pRealSem->Mutex);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("DosCloseSem: error at NtClose, Status %x\n", Status);
+ }
+#endif
+ }
+ else {
+ DeletedSomeStuff = TRUE;
+ }
+
+ // defend against:DosSemClear already zeroed hsem but haven't
+ // released it yet
+
+ DosPostEventSem (pRealSem->Event);
+
+ //
+ // delete it
+ //
+ rc = DosCloseEventSem (pRealSem->Event);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("DosCloseSem: error at DosCloseEventSem, Status %d\n", rc);
+ }
+#endif
+ }
+ else {
+ DeletedSomeStuff = TRUE;
+ }
+
+#if DBG
+ NumFreed++;
+#endif
+ //
+ // unlink it
+ //
+ if (pRealSem == (POS21X_SEM)Od2Sem16ListHead) {
+ //
+ // chop the head of the list, start from scratch
+ //
+ Od2Sem16ListHead = pRealSem->Next;
+ //
+ // Free sem structure from heap;
+ RtlFreeHeap(Od2TiledHeap, 0, pRealSem);
+ pRealSem = pPrevSem = (POS21X_SEM)Od2Sem16ListHead;
+ }
+ else {
+ pPrevSem->Next = pRealSem->Next;
+ //
+ // Free sem structure from heap;
+ RtlFreeHeap(Od2TiledHeap, 0, pRealSem);
+ pRealSem = (POS21X_SEM)(pPrevSem->Next);
+ }
+ Od2NumSemCreated = 0;
+ }
+ else {
+ //
+ // Semaphore is not clear - skip
+ //
+ pPrevSem = pRealSem;
+ pRealSem = (POS21X_SEM)(pPrevSem->Next);
+ }
+ }
+ else {
+ //
+ // Not A private RAM semaphore - skip
+ pPrevSem = pRealSem;
+ pRealSem = (POS21X_SEM)(pPrevSem->Next);
+ }
+ }
+ Status = Od2ReleaseMutant(Od2GarbageCollectSem);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(("Os2 - GarbageCollect: failed to NtReleaseSemaphore on sync sem, Status=%x\n",
+ Status));
+ }
+ KdPrint(("Os2 - GarbageCollect: found %d semaphores, deleted %d\n",
+ NumSem,NumFreed));
+#endif
+ LockFlag = FALSE;
+ return(DeletedSomeStuff);
+}
+
+//
+// The parameter CheckInitializationOfSem must be TRUE only if Od2LookupOrCreateSem was
+// called from DosSemRequest or DosSemWait. In this case busy semaphore might be created (only
+// if there is RAM semaphore that used for the 1st time). Busy semaphore, while
+// created cause until other thread will clear the semaphore by DosSemClear.
+//
+
+POS21X_SEM
+Od2LookupOrCreateSem (
+ HSEM hsem,
+ PBOOLEAN firsttime,
+ ULONG source
+ )
+{
+ APIRET rc = NO_ERROR;
+ POS21X_SEM pRealSem, pPrevSem;
+ ULONG tmp;
+ NTSTATUS Status;
+ BOOLEAN FlushSharedRamSem = FALSE;
+
+ PSZ pszSemName;
+ char *pchtmp;
+
+ pRealSem = Od2LookupSem(hsem);
+
+ if (pRealSem != NULL) {
+ if (pRealSem->u.SharedRamSignature &&
+ pRealSem->pMyself != (PVOID)(&(pRealSem->pMyself))) {
+
+ //
+ // if a RAM semaphore in shared memory, check that the
+ // actual signature in the pRealSem structure (per process)
+ // is identical to the signature in shared memory. If it
+ // is not, it means that this is a re-use of old sem, in
+ // which case we cleanup and use this structure for the new
+ // semaphore
+ //
+
+ if ((*(PULONG)hsem & 0x3FFFC) != (pRealSem->u.SharedRamSignature & 0x3FFFC)) {
+#if PMNT
+#if DBG
+ DbgPrint("[%d,%d] Od2LookupOrCreateSem: signature mismatch, hsem=%x, *=%x, signature=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem,
+ pRealSem->u.SharedRamSignature);
+#endif // DBG
+#endif // PMNT
+ FlushSharedRamSem = TRUE;
+ goto SyncLabel;
+ }
+ }
+
+ *firsttime = FALSE;
+ return(pRealSem);
+ }
+
+SyncLabel:
+ Status = Od2AcquireSync();
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DbgPrint("[%d,%d] Od2LookupOrCreateSem: FAILED to NtWaitForSingleObject on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+
+ pRealSem = Od2LookupSem(hsem);
+
+ if (FlushSharedRamSem) {
+ //
+ // see if another thread in this process did not fix it yet
+ //
+ if ((*(PULONG)hsem & 0x3FFFC) != (pRealSem->u.SharedRamSignature & 0x3FFFC)) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("FlushSharedRamSem: Flushing reference of *hsem %x, pRealSem at %x\n",
+ *(PULONG)hsem, pRealSem);
+ }
+#endif
+ if ((source & SEM_FROM_CLEAR) && ((*(PULONG)hsem & 0xFFF00000) != 0xCCC00000)) {
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] Od2LookupOrCreateSem (flashing skipped): failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ *firsttime = FALSE;
+ //
+ // *(PULONG)hsem &= 0xffffff00;
+ //
+ __asm
+ {
+ mov eax, hsem
+ lock and dword ptr [eax], 0xffffff00
+ }
+ return(pRealSem);
+ }
+
+#if PMNT
+#if DBG
+ DbgPrint("[%d,%d] FlushSharedRamSem: Flushing reference of hsem=%x, *=%x, signature=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem,
+ pRealSem->u.SharedRamSignature);
+#endif // DBG
+#endif // PMNT
+ //
+ // Need to flush and recreate the process copy of the
+ // shared RAM sem
+ //
+ // 1. close handles
+ // 2. unlink structure and free memory
+ // 3. let the algorithm below take care of it as a new
+ // shared RAM semaphore
+ //
+ Status = NtClose (pRealSem->Mutex);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("FlushShareRamSem: error at NtClose, Status %x\n", Status);
+ }
+#endif
+ }
+
+ rc = DosCloseEventSem (pRealSem->Event);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("FlushShareRamSem: error at DosCloseEventSem, Status %d\n", rc);
+ }
+#endif
+ }
+ //
+ // Now unlink it from the per-process semaphore list
+ // and free heap space allocated
+ //
+
+ Status = Od2AcquireMutant(Od2GarbageCollectSem);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(("FlushSharedRamSem: FAILED to NtWaitForSingleObject on garbage sem, Status=%x\n",
+ Status));
+ }
+ else if (Status != STATUS_SUCCESS) {
+ DbgPrint("[%d,%d] Od2LookupOrCreateSem: WARNING !!! Wait on GarbageCollectSem, status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ if (pRealSem == (POS21X_SEM)Od2Sem16ListHead) {
+ //
+ // Get rid of first on the list
+ //
+
+ Od2Sem16ListHead = pRealSem->Next;
+ RtlFreeHeap(Od2TiledHeap, 0, pRealSem);
+ }
+ else {
+ for (pPrevSem = (POS21X_SEM)Od2Sem16ListHead;
+ pPrevSem->Next != NULL;
+ pPrevSem = (POS21X_SEM)(pPrevSem->Next)) {
+
+ if ((POS21X_SEM)(pPrevSem->Next) == pRealSem) {
+
+ //
+ // Found our semaphore on the list
+ //
+
+ pPrevSem->Next = pRealSem->Next;
+ RtlFreeHeap(Od2TiledHeap, 0, pRealSem);
+ break;
+ }
+ }
+ }
+ //
+ // Shared RAM semaphore was closed.
+ //
+ Od2NumSemCreated--;
+
+ Status = Od2ReleaseMutant(Od2GarbageCollectSem);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(("FlushSharedRamSem: failed to NtReleaseSemaphore on sync sem, Status=%x\n",
+ Status));
+ }
+#endif
+ pRealSem = NULL;
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("FlushShareRamSem: Another thread in this process Flushed reference of *hsem %x, pRealSem at %x\n",
+ *(PULONG)hsem, pRealSem);
+ }
+#endif
+#if PMNT
+#if DBG
+ DbgPrint("[%d,%d] FlushShareRamSem: Another thread in this process flushed reference of hsem=%x, *=%x, signature=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem,
+ pRealSem->u.SharedRamSignature);
+#endif // DBG
+#endif // PMNT
+ }
+ }
+
+ if (pRealSem != NULL) {
+ *firsttime = FALSE;
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] Od2LookupOrCreateSem (semaphore was found): failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+
+ return(pRealSem);
+ }
+
+ //
+ // A RAM Semaphore first call in this process.
+ // Initialize an OS21X_SEM by a call to
+ // Od2CreateSem or Od2OpenSem
+ //
+ //
+ // check for a magic number that mark RAM semaphores
+ // that reside in shared memory
+ //
+
+ tmp = *(PULONG)hsem;
+ if ((tmp & 0xFFF00000) == 0xCCC00000) {
+ *firsttime = FALSE;
+
+ //
+ // makeup a name from the air, to be used later.
+ //
+ pszSemName = "\\SEM\\HACKNT00000";
+ //
+ // HSEM is:
+ //
+ // bit: 31 17 1
+ // |magic number | 16b index | 2bits for set/clear|
+ //
+ // extract the sem index out of sem handle
+ //
+ tmp = (tmp >> 2) & 0xFFFF;
+ //
+ // construct last 4 characters as the digits of i
+ //
+ pchtmp = _itoa (tmp, &pszSemName[11], 16);
+
+ //
+ // open the semaphore (RAM sem created previously in shared mem
+ //
+ rc = Od2OpenSem(
+ hsem,
+ &pRealSem,
+ pszSemName,
+ TRUE);
+
+ if (rc != NO_ERROR) {
+#if DBG
+ if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
+ ((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
+ ((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
+ ((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1)))
+ {
+ KdPrint(("[%d,%d] Od2LookupOrCreateSem(%x,*=%x): failed to Od2OpenSem on %s, rc=%d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem,
+ pszSemName,
+ rc));
+ }
+#endif // DBG
+
+ // Create semaphore.
+ //
+
+ if (!(source & SEM_FROM_REQUESTWAIT)) {
+
+ // Erase the least significat byte of the semaphore,
+ // so semaphore will not be created in busy state.
+
+ //
+ // *(PULONG)hsem &= 0xffffff00;
+ //
+ __asm
+ {
+ mov eax, hsem
+ lock and dword ptr [eax], 0xffffff00
+ }
+ }
+
+ *firsttime = TRUE;
+ //
+ // We failed to open - there was garbage in the user memory
+ // Create the semaphore
+ //
+ rc = Od2CreateSem(
+ hsem,
+ CSEM_PRIVATE,
+ &pRealSem,
+ NULL);
+#if DBG
+#ifdef DBG_SEM_INDEX
+ if ((*(PULONG)hsem & 0x3FFFC) == (DBG_SEM_INDEX << 2)) {
+ KdPrint(("[%d,%d] Od2LookupOrCreateSem: created (due to garbage) %x for hsem=%x, *=%x, rc=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ DBG_SEM_INDEX,
+ hsem,
+ *(PULONG)hsem,
+ rc
+ ));
+ }
+#endif // DBG_SEM_INDEX
+#endif // DBG
+ }
+#if DBG
+#ifdef DBG_SEM_INDEX
+ else {
+ //
+ // success opening
+ //
+ if (tmp == (DBG_SEM_INDEX << 2)) {
+ KdPrint(("[%d,%d] Od2LookupOrCreateSem: opened %x for hsem=%x, *=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ DBG_SEM_INDEX,
+ hsem,
+ *(PULONG)hsem
+ ));
+ }
+ }
+#endif // DBG_SEM_INDEX
+#endif // DBG
+ //
+ // record the signature of the ram sem for later checks
+ //
+ if (rc == NO_ERROR) {
+ pRealSem->u.SharedRamSignature = *(PULONG)hsem;
+ }
+ }
+ else {
+
+ if (!(source & SEM_FROM_REQUESTWAIT)) {
+
+ // Erase the least significat byte of the semaphore,
+ // so semaphore will not be created in busy state.
+
+ //
+ // *(PULONG)hsem &= 0xffffff00;
+ //
+ __asm
+ {
+ mov eax, hsem
+ lock and dword ptr [eax], 0xffffff00
+ }
+ }
+
+ *firsttime = TRUE;
+
+ //
+ // Create the semaphore (usual case)
+ //
+ rc = Od2CreateSem(
+ hsem,
+ CSEM_PRIVATE,
+ &pRealSem,
+ NULL);
+
+ if (rc == NO_ERROR) {
+ if ((*(PULONG)hsem & 0xFFF00000) == 0xCCC00000) {
+ //
+ // record the signature of the ram sem for later checks
+ //
+ pRealSem->u.SharedRamSignature = *(PULONG)hsem;
+#if DBG
+#if DBG_SEM_INDEX
+ if ((*(PULONG)hsem & 0x3FFFC) == (DBG_SEM_INDEX << 2)) {
+ KdPrint(("[%d,%d] Od2LookupOrCreateSem: created (new) %x for hsem=%x, *=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ DBG_SEM_INDEX,
+ hsem,
+ *(PULONG)hsem
+ ));
+ }
+#endif //DBG_SEM_INDEX
+#endif //DBG
+ }
+ }
+
+#ifdef PMNT
+#if DBG
+ if (FlushSharedRamSem) {
+ DbgPrint("[%d,%d] FlushShareRamSem: created new entry for hsem=%x, *=%x, signature=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem,
+ pRealSem->u.SharedRamSignature);
+ }
+#endif // DBG
+#endif // PMNT
+ }
+
+ Od2NumSemCreated++;
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] Od2LookupOrCreateSem (semaphore was created): failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+
+ if ((rc != NO_ERROR && rc != ERROR_ALREADY_EXISTS && rc != ERROR_DUPLICATE_NAME && rc != ERROR_INVALID_NAME) ||
+ (Od2NumSemCreated > OD2SEMTHRESHOLD)) {
+#if DBG
+ if (rc != NO_ERROR) {
+ DbgPrint ("Od2LookupOrCreate: error initializing a RAM sem %d, call GarbageCollect()\n", rc);
+ }
+ else {
+ DbgPrint ("Od2LookupOrCreate: low on RAM semaphores - call GarbageCollect\n");
+ }
+#endif
+ if (GarbageCollect()) {
+ //
+ // Succeeded to gain more resources, try again
+ //
+#if DBG
+ DbgPrint ("Od2LookupOrCreate: GarbageCollect freed some resource, try create again\n");
+#endif
+ // Call Od2LookupOrCreateSem with the same value for parameter "source"
+
+ return (Od2LookupOrCreateSem (hsem, firsttime, source));
+
+ }
+ //
+ // no resources - quit
+ //
+ if (rc != NO_ERROR) {
+#if DBG
+ DbgPrint ("OS2: GarbageCollect could not free resources, Exit Application\n");
+#endif
+ DosExit(EXIT_PROCESS, 0);
+ }
+
+#if DBG
+ DbgPrint("OS2: GarbageCollect could not free resources, return NULL\n");
+#endif
+ return NULL;
+ }
+ //
+ // expected errors - return NULL (the rest were checked above)
+ //
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("Od2LookupOrCreate: error initializing a RAM sem, %d\n", rc);
+ }
+#endif
+ return NULL;
+ }
+
+ return(pRealSem);
+}
+
+/*
+ This routine is called upon process exit clean-up.
+ The idea here is to go through the private list of semaphores and, for
+ each shared RAM semaphore, do:
+ - close the associated NT events
+ - if the signature matches the contents of the RAM semaphore:
+ - try to open the NT events
+ - if we get an error, this means we were the last to keep a handle to those
+ events, so we should clear the RAM semaphore so that the OS/2 ss won't
+ think later on (when/if this same RAM location is used as a shared RAM
+ semaphore) it is a RAM semaphore with a valid index.
+ NOTICE: we do not remove the entries from the Od2Sem16ListHead list. We
+ just close the handles stored there. This is based on the assumption
+ that nobody will need this list past this point and that the memory
+ used for the list will be freed soon when the process exits.
+*/
+VOID
+Od2CloseAllRAMSharedSemaphores( VOID)
+{
+
+ POS21X_SEM pSem;
+ HSEM hsem, tmpsem;
+ PSZ pszSemName, pchtmp;
+ ULONG index;
+ APIRET rc;
+ NTSTATUS Status;
+
+ pSem = (POS21X_SEM)Od2Sem16ListHead;
+
+ while (pSem != NULL) {
+
+ if (pSem->u.SharedRamSignature && // Shared
+ pSem->pMyself != (PVOID)(&(pSem->pMyself))) { // Ram
+
+ Status = Od2AcquireSync();
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DbgPrint("[%d,%d] Od2CloseAllRAMSharedSemaphores: FAILED to NtWaitForSingleObject on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+
+ if (DosCloseSemNoRemove(pSem,FALSE)) {
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] Od2CloseAllRAMSharedSemaphores (close fail): failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ continue;
+ }
+
+ hsem = pSem->pMyself;
+
+ try {
+ index = (*(PULONG)hsem & 0x3FFFF) >> 2;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ pSem = (POS21X_SEM)(pSem->Next);
+
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] Od2CloseAllRAMSharedSemaphores (exception handler): failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ continue;
+ }
+
+ if ((pSem->u.SharedRamSignature & 0x3FFFC) == (*(PULONG)hsem & 0x3FFFC)) {
+ //
+ // compose the name for the semaphore
+ //
+ pszSemName = "\\SEM\\HACKNT00000";
+ //
+ // construct last 4 characters as the digits of i
+ //
+ pchtmp = _itoa (index, &pszSemName[11], 16);
+ rc = Od2OpenSem(NULL, &(POS21X_SEM)tmpsem, pszSemName,FALSE);
+
+ if (rc == ERROR_SEM_NOT_FOUND) {
+ //
+ // This was the last open handle. The semaphore must flushed by other
+ // processes.
+ //
+ if ((*(PULONG)hsem & 0xFFF00000) == 0xCCC00000) {
+
+ //
+ // *(PULONG)hsem = 0xCCC00000;
+ //
+ // If the signature is used by app (it isn't 0xCCC?????) like PMSHELL
+ // that use the most significant word of the semaphore for managing
+ // list of free semaphores for reusing, don't write 0xCCC00000 signature.
+ // In this case the semaphore will be flushed as well.
+ // Unfortunately there is a small time window that the value that might
+ // be used by app was destroyed.
+ //
+ __asm {
+ mov eax, hsem
+ mov cx, 0xCCC0
+ xchg word ptr [eax+2], cx
+ mov dx, cx
+ and dx, 0xFFF0
+ cmp dx, 0xCCC0
+ je Od2CloseRamSemOk
+ xchg cx, word ptr [eax+2]
+ Od2CloseRamSemOk:
+ mov word ptr [eax], 0
+ }
+ }
+ }
+ else if (rc == NO_ERROR) {
+ DosCloseSemNoRemove(tmpsem,TRUE);
+ }
+#if DBG
+ else {
+ DbgPrint("[%d,%d] Od2CloseAllRAMSharedSemaphores: Fail to open. rc=%d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ rc);
+ }
+#endif // DBG
+ }
+
+ pSem = (POS21X_SEM)(pSem->Next);
+
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] Od2CloseAllRAMSharedSemaphores: failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ }
+ else {
+ pSem = (POS21X_SEM)(pSem->Next);
+ }
+ }
+
+ // The process is over and we used Od2Sync for the last time. This is the
+ // good opportunity to close it's handle.
+
+ Status = NtClose(Od2SyncSem);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] Od2CloseAllRAMSharedSemaphores: failed to NtClose sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif // DBG
+
+}
+
+APIRET
+DosCreateSem(
+ IN USHORT fExclusive,
+ OUT PHSYSSEM phSem,
+ IN PSZ pszSemName
+ )
+{
+ ULONG Sem;
+ APIRET rc = NO_ERROR;
+ POS21X_SEM pRealSem;
+ NTSTATUS Status;
+
+ try {
+ Od2ProbeForWrite( phSem, sizeof( HSYSSEM ), 1 );
+ Od2ProbeForRead( pszSemName, 2, 1 );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP ();
+ }
+
+ if (fExclusive != CSEM_PRIVATE && fExclusive != CSEM_PUBLIC){
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ Status = Od2AcquireSync();
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DbgPrint("[%d,%d] DosCreateSem: failed to NtWaitForSingleObject on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+
+ rc = Od2CreateSem(
+ NULL,
+ fExclusive,
+ &pRealSem,
+ pszSemName);
+
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] DosCreateSem: failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosCreateSem: error calling Od2CreateSem, %d\n", rc);
+ }
+#endif
+ return rc;
+ }
+
+ Sem = (ULONG) *phSem = (ULONG) pRealSem;
+ *phSem = (POS21X_SEM)(FLATTOFARPTR(Sem));
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+Od2CloseSem(
+ IN BOOL SyncFlag,
+ IN HSEM hsem
+ )
+{
+ APIRET rc = NO_ERROR;
+ NTSTATUS Status;
+ POS21X_SEM pRealSem, pPrevSem;
+
+ try {
+ Od2ProbeForWrite( (PVOID)hsem, sizeof( HSYSSEM ), 1 );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP ();
+ }
+
+ pRealSem = Od2LookupSem(hsem);
+
+ if (pRealSem == NULL) {
+ // not found or ram sem handle
+ return ERROR_INVALID_HANDLE;
+ }
+
+ //
+ // SyncFlag is true when called from DosCloseSem
+ // it is false when called from Od2OpenSem,
+ // where we have already issued Od2AcquireSync()
+ //
+ if (SyncFlag) {
+ Status = Od2AcquireSync();
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DbgPrint("[%d,%d] DosCloseSem: failed to NtWaitForSingleObject on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ }
+
+ if (pRealSem->SysSemCount > 1 ) {
+ //
+ // System semaphore was created/opened more than once
+ // we shouldn't close it yet
+ //
+ pRealSem->SysSemCount --;
+
+ if (SyncFlag) {
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] DosCloseSem: failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ }
+
+ return(NO_ERROR);
+ }
+
+ if (SyncFlag) {
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] DosCloseSem: failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ }
+ //
+ // On OS/2, a Set System Semaphore can not be closed
+ // perform a wait with no blocking, and if no_error
+ // close
+ //
+ if (pRealSem->FlagsByte != 0) {
+
+ rc = DosSemWait(
+ hsem,
+ 0);
+ if (rc != NO_ERROR){
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("DosCloseSem: error at DosSemWait, rc %d, return ERROR_SEM_IS_SET\n", rc);
+ }
+ DbgPrint("[%d,%d] DosCloseSem(%x): DosSemWait returned rc=%d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ rc);
+#endif
+ return (ERROR_SEM_IS_SET);
+ }
+ }
+
+ Status = NtClose (pRealSem->Mutex);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("DosCloseSem: error at NtClose, Status %x\n", Status);
+ }
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE));
+ }
+
+ rc = DosCloseEventSem (pRealSem->Event);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("DosCloseSem: error at DosCloseEventSem, Status %d\n", rc);
+ }
+#endif
+ return rc;
+ }
+ //
+ // Now unlink it from the per-process semaphore list
+ // and free heap space allocated
+ //
+
+ Status = Od2AcquireMutant(Od2GarbageCollectSem);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(("DosCloseSem: failed to NtWaitForSingleObject on garbage sem, Status=%x\n",
+ Status));
+ }
+ else if (Status != STATUS_SUCCESS) {
+ DbgPrint("[%d,%d] DosCloseSem: WARNING !!! Wait on GarbageCollectSem, status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+
+
+ if (pRealSem->pMyself == (PVOID)(&(pRealSem->pMyself)) && // System Semaphore
+ pRealSem->u.SysSemName ){
+ RtlFreeHeap(Od2Heap, 0, pRealSem->u.SysSemName);
+ }
+
+ if (pRealSem == (POS21X_SEM)Od2Sem16ListHead) {
+ //
+ // Get rid of first on the list
+ //
+
+ Od2Sem16ListHead = pRealSem->Next;
+ RtlFreeHeap(Od2TiledHeap, 0, pRealSem);
+ }
+ else {
+ for (pPrevSem = (POS21X_SEM)Od2Sem16ListHead;
+ pPrevSem->Next != NULL;
+ pPrevSem = (POS21X_SEM)(pPrevSem->Next)) {
+
+ if ((POS21X_SEM)(pPrevSem->Next) == pRealSem) {
+
+ //
+ // Found our semaphore on the list
+ //
+
+ pPrevSem->Next = pRealSem->Next;
+ RtlFreeHeap(Od2TiledHeap, 0, pRealSem);
+ break;
+ }
+ }
+ }
+
+ Status = Od2ReleaseMutant(Od2GarbageCollectSem);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(("DosCloseSem: failed to NtReleaseSemaphore on sync sem, Status=%x\n",
+ Status));
+ }
+#endif
+ return (NO_ERROR);
+}
+
+APIRET
+DosCloseSem(
+ IN HSEM hsem
+ )
+{
+ return (Od2CloseSem(TRUE, hsem));
+}
+
+
+
+APIRET
+DosCloseSemNoRemove(
+ IN POS21X_SEM pRealSem,
+ IN BOOL FreeMem
+ )
+{
+ APIRET rc;
+ NTSTATUS Status;
+ HSEM tmpMutex, tmpEvent;
+
+ tmpMutex = pRealSem->Mutex;
+ tmpEvent = pRealSem->Event;
+
+ if (FreeMem)
+ RtlFreeHeap(Od2TiledHeap, 0, pRealSem);
+
+ Status = NtClose (tmpMutex);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("DosCloseSemNoRemove: error at NtClose, Status %x\n", Status);
+ }
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE));
+ }
+
+ rc = DosCloseEventSem (tmpEvent);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("DosCloseSemNoRemove: error at DosCloseEventSem, Status %d\n", rc);
+ }
+#endif
+ return rc;
+ }
+ return (NO_ERROR);
+}
+
+APIRET
+DosSemClear(
+ IN HSEM hsem
+ )
+{
+ APIRET rc = NO_ERROR;
+ NTSTATUS Status;
+ POS21X_SEM pRealSem;
+ SEMAPHORE_BASIC_INFORMATION SemInfo;
+ BOOLEAN firsttime;
+ ULONG hsemValue;
+
+#if DBG
+ if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
+ ((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
+ ((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
+ ((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
+ KdPrint(("[%d,%d] DosSemClear(%x, *=%x): entering\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem));
+ }
+#endif // DBG
+
+ try {
+ Od2ProbeForWrite( (PVOID)hsem, sizeof( ULONG ), 1 );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP ();
+ }
+
+ // If the semaphore will be created in will be initially in not busy state.
+
+ pRealSem = Od2LookupOrCreateSem(hsem, &firsttime, SEM_FROM_CLEAR);
+
+ if (pRealSem == NULL)
+ return(ERROR_NOT_ENOUGH_MEMORY);
+
+ if (firsttime) {
+// if ((*(PULONG)hsem & 0xFFF00000) != 0xCCC00000) {
+ //
+ // private mem RAM sem: set value and return
+ //
+// *(PULONG)hsem = (ULONG)pRealSem;
+// }
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosSemClear 1st time succeeded: Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(), hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+
+ if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
+ ((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
+ ((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
+ ((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
+ KdPrint(("[%d,%d] DosSemClear(%x, *=%x): first time, exiting OK\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem));
+ }
+#endif // DBG
+ return NO_ERROR;
+ }
+
+ if (((hsemValue=*(PULONG)hsem) != (ULONG)hsem) &&
+ ((hsemValue & 0xFFF00000) != 0xCCC00000)) {
+ //
+ // Private RAM Semaphore:
+ // OS/2 1.X Apps (SQLQ 1.11 ) expects the semaphore location
+ // to be actually ZERO (undocumented)
+ //
+
+ // BUGBUG Maybe OS/2 clears only low word
+
+ *(PULONG)hsem = 0;
+ }
+
+ //
+ // since hsem=0 garbage colection might free pRealSem
+ // we enclose with try-except
+ //
+ // Note that after we will release the sem,
+ // by NtReleseSemaphore or DosPostEventSem
+ // we will not be sure that the user
+ // memory at *hsem will still be valid - would be freed by a thread
+ // waiting for this semaphore.
+ // instead of *hsem we will use local variable hsemValue.
+ //
+
+ try {
+
+ if ((pRealSem->OwnerThread != SEM_EVENT) && // This is not a private WAIT/CLEAR RAM semaphore
+ (((hsemValue & 0xFFFC0000) != 0xCCC40000)) ) { // This is not a shared WAIT/CLEAR RAM semaphore
+ //
+ // free a REQUEST - What we need to do is
+ // To NtReleaseSemaphore on the Semaphore
+ //
+ if (hsemValue != (ULONG)hsem ||
+ (pRealSem->FlagsByte & SYSSEM_PUBLIC)) {
+
+ //
+ // RAM sem and public sys sem - simply release
+ //
+
+ LONG PreviousCount;
+
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosSemClear about to Release Mutex: Sem %x, *Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(), hsem, hsemValue, pRealSem->Mutex,pRealSem->Event);
+ }
+#endif
+ Status = NtReleaseSemaphore (
+ pRealSem->Mutex,
+ 1,
+ &PreviousCount);
+ if ( !NT_SUCCESS(Status) && Status != STATUS_SEMAPHORE_LIMIT_EXCEEDED ) {
+#if DBG
+ DbgPrint ("DosSemClear: error NtReleaseSempahore , %lx\n", Status);
+#endif
+ rc = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE);
+ }
+ if (pRealSem->OwnerThread != (TID)SEM_AT_INIT &&
+ pRealSem->OwnerThread != (TID)SEM_DUAL &&
+ !(pRealSem->FlagsByte & SYSSEM_PUBLIC)) {
+ pRealSem->OwnerThread = (TID)SEM_MUTEX_NOT_OWNED;
+ }
+ }
+ else {
+ //
+ // EXCLUSIVE system semaphores - query before release, for ownership
+ //
+ // BUGBUG - EXCLUSIVE system semaphores need to be rewritten,
+ // because ownerthreadid is not shared. Also, tight sync is
+ // needed to get the right errors when the owner dies etc.
+ // for now - we sync every clear with the rest of the processes
+ //
+
+ Status = Od2AcquireSync();
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DbgPrint("[%d,%d] DosSemClear: FAILED to NtWaitForSingleObject on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ Status = NtQuerySemaphore(
+ pRealSem->Mutex,
+ SemaphoreBasicInformation,
+ (PVOID)(&SemInfo),
+ sizeof(SemInfo),
+ NULL);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosSemClear: error in NtQuerySemaphore, %lx\n", Status);
+ }
+#endif
+ rc = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE);
+ }
+ else {
+ if (SemInfo.CurrentCount == 0) {
+
+ //
+ // Sempahore is not signaled i.e. it is not clear
+ // so let's release it
+ //
+
+ if (pRealSem->RequestCount) {
+ //
+ // must be a system semaphore that was prevoiusly
+ // requested by the same thread more than once.
+ // don't really free the thread, just count
+ //
+ pRealSem->RequestCount--;
+ }
+ else if ((ULONG)pRealSem->OwnerThread > 0 &&
+ (ULONG)pRealSem->OwnerThread < _64K ){
+ //
+ // A thread has this semaphore, release it
+ //
+ Status = NtReleaseSemaphore (
+ pRealSem->Mutex,
+ 1,
+ NULL);
+ if ( !NT_SUCCESS(Status) && Status != STATUS_SEMAPHORE_LIMIT_EXCEEDED ) {
+#if DBG
+ DbgPrint ("DosSemClear: error NtReleaseSempahore , %lx\n", Status);
+#endif
+ rc = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE);
+ }
+ if (pRealSem->OwnerThread != (TID)SEM_AT_INIT &&
+ pRealSem->OwnerThread != (TID)SEM_DUAL) {
+ pRealSem->OwnerThread = (TID)SEM_MUTEX_NOT_OWNED;
+ }
+ }
+
+ }
+ }
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] DosSemClear: failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ }
+ }
+
+ //
+ // Post the Event if it is not a RAM semaphore
+ // of type REQUEST/CLEAR
+ //
+ if ( (pRealSem->OwnerThread == (TID)SEM_EVENT) || // WAIT/CLEAR private RAM SEM
+ (pRealSem->OwnerThread == (TID)SEM_AT_INIT) || // Initialized RAM SEM
+ (pRealSem->OwnerThread == (TID)SEM_DUAL) || // RAM SEM use for both mutext and event
+ (hsemValue == (ULONG)hsem) || // System Semaphore
+ ( ((hsemValue & 0xFFF00000) == 0xCCC00000) &&
+ ((hsemValue & 0xFFFC0000) != 0xCCC80000) ) ) { // This is not a shared REQUEST/CLEAR RAM semaphore
+
+
+ //
+ // This is a WAIT/CLEAR type semaphore - post the event
+ //
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosSemClear about to PostEvent: Sem %x, *Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(), hsem, hsemValue, pRealSem->Mutex,pRealSem->Event );
+ }
+#endif
+ rc = DosPostEventSem (pRealSem->Event);
+ if (rc != NO_ERROR) {
+ if (rc == ERROR_ALREADY_POSTED || rc == ERROR_TOO_MANY_POSTS) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosSemClear: Posting the Event, %d\n", rc);
+ }
+#endif
+ rc = NO_ERROR;
+ } else {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosSemClear: error Posting the Event, %d\n", rc);
+ }
+#endif
+ }
+ }
+
+ }
+
+ if (rc == NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosSemClear succeeded Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(),hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+#endif
+ }
+ }
+ except( EXCEPTION_EXECUTE_HANDLER) {
+#if DBG
+ DbgPrint ("DosSemClear - user freed Sem %x\n", hsem);
+#endif
+ }
+
+#if DBG
+ if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
+ ((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
+ ((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
+ ((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
+ KdPrint(("[%d,%d] DosSemClear(%x, *=%x): exiting, rc=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem,
+ rc));
+ }
+#endif // DBG
+
+ return rc;
+}
+
+APIRET
+DosSemSet(
+ IN HSEM hsem
+ )
+{
+ APIRET rc = NO_ERROR;
+ APIRET rc1 = NO_ERROR;
+ NTSTATUS Status = STATUS_SUCCESS;
+ POS21X_SEM pRealSem;
+ ULONG Dummy;
+ LARGE_INTEGER CapturedTimeout;
+ PLARGE_INTEGER NtTimeout;
+ BOOLEAN firsttime;
+
+#if DBG
+ if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
+ ((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
+ ((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
+ ((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
+ KdPrint(("[%d,%d] DosSemSet(%x, *=%x): entering\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem));
+ }
+#endif // DBG
+
+ try {
+ Od2ProbeForWrite( (PVOID)hsem, sizeof( ULONG ), 1 );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP ();
+ }
+
+ // If the semaphore will be created it will be initially in not busy state.
+
+ pRealSem = Od2LookupOrCreateSem(hsem, &firsttime, SEM_FROM_SET);
+
+ if (pRealSem == NULL)
+ return(ERROR_NOT_ENOUGH_MEMORY);
+
+ if (*(PULONG)hsem != (ULONG)hsem) {
+ //
+ // RAM semaphore:
+ // change state if needed
+ //
+ if (pRealSem->OwnerThread == (TID)SEM_AT_INIT) {
+ pRealSem->OwnerThread = (TID)SEM_EVENT; // mark it as a WAIT/CLEAR semaphore, no owner
+ }
+ if ((*(PULONG)hsem & 0xFFF00000) != 0xCCC00000) {
+ //
+ // private mem RAM sem: set value and return
+ //
+ // *(PULONG)hsem |= 1;
+ __asm
+ {
+ mov eax, hsem
+ lock or dword ptr [eax], 1
+ }
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosSemSet on shared mem RAM: Sem %x, *Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(),hsem, *(PULONG)hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+#endif
+ //
+ // *(PULONG)hsem |= 0x00040000;
+ //
+ __asm
+ {
+ mov eax, hsem
+ lock or dword ptr [eax], 0x00040000
+ }
+ }
+ }
+
+
+ //
+ // We Implement a Set by a WaitForSingleObject on the Nt
+ // Semaphore (effectively decrement count only if > 0 )
+ // and a Reset on the event
+ //
+
+
+ // RAM semaphore used for requests as well
+ if ( (pRealSem->OwnerThread != (TID)SEM_EVENT && (*(PULONG)hsem != (ULONG)hsem)) ||
+ // public system semaphore
+ ((*(PULONG)hsem == (ULONG)hsem) && (pRealSem->FlagsByte & SYSSEM_PUBLIC)) ){
+
+ //
+ // Capture the timeout value of zero and convert it into an
+ // NT timeout value.
+ //
+ NtTimeout = Od2CaptureTimeout( 0, (PLARGE_INTEGER)&CapturedTimeout );
+
+ Status = NtWaitForSingleObject(
+ pRealSem->Mutex,
+ TRUE, // Alertable
+ NtTimeout // Immediate return
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("[%d,%d]DosSemSet: ERROR at NtWaitForSingleObject, %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+#endif
+ rc1 = Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ }
+ }
+
+ //
+ // If it not a mutex, we Reset the event
+ //
+
+ if ((*(PULONG)hsem == (ULONG)hsem) || pRealSem->OwnerThread == (TID)SEM_EVENT || pRealSem->OwnerThread == (TID)SEM_DUAL) {
+
+ rc = DosResetEventSem (pRealSem->Event, &Dummy);
+
+ if (rc == ERROR_ALREADY_RESET)
+ rc = NO_ERROR;
+ }
+
+ if (rc == NO_ERROR && rc1 == NO_ERROR) {
+
+ if (*(PULONG)hsem != (ULONG)hsem) {
+ //
+ // RAM semaphore:
+ // OS/2 1.X apps expect sem location last two bits to be 1
+ //
+ // *(PULONG)hsem |= 1;
+ }
+ else {
+ pRealSem->OwnerThread = (TID)SEM_MUTEX_NOT_OWNED;
+ pRealSem->RequestCount = 0;
+ }
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ if (firsttime) {
+ DbgPrint ("[TID %x]: DosSemSet 1st time succeeded: Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(), hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+ else {
+ DbgPrint ("[TID %x]: DosSemSet succeeded Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(), hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+ }
+#endif
+
+#if DBG
+ if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
+ ((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
+ ((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
+ ((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
+ KdPrint(("[%d,%d] DosSemSet(%x, *=%x): exiting OK\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem));
+ }
+#endif // DBG
+ return NO_ERROR;
+ }
+
+ if (rc != NO_ERROR){
+
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosSemSet: error Resetting the Event, %d\n", rc);
+ }
+#endif
+
+ }
+ else {
+
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosSemSet: error Resetting the Mutex, %d\n", rc1);
+ }
+#endif
+ rc = rc1;
+ }
+
+#if DBG
+ if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
+ ((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
+ ((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
+ ((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
+ KdPrint(("[%d,%d] DosSemSet(%x, *=%x): exiting, rc=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem,
+ rc));
+ }
+#endif // DBG
+ return rc;
+}
+
+APIRET
+DosSemWait(
+ IN HSEM hsem,
+ IN LONG lTimeOut
+ )
+{
+ APIRET rc = NO_ERROR;
+ POS21X_SEM pRealSem;
+ BOOLEAN firsttime;
+ BOOLEAN CheckCurrentOwner = FALSE;
+ LARGE_INTEGER CapturedTimeout;
+ PLARGE_INTEGER NtTimeout;
+ LARGE_INTEGER StartTimeStamp;
+
+#if DBG
+ if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
+ ((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
+ ((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
+ ((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
+ KdPrint(("[%d,%d] DosSemWait(%x, *=%x): entering\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem));
+ }
+#endif // DBG
+
+ //
+ // If the least significant byte of RAM semaphore is 0, it is free (OS/2 native
+ // conmpartability).
+ // This fiture of OS/2 is used by Saros Mezzanine, that reuse memory that contain
+ // semaphores that were set. It is enough to zero this memory in OS/2 to free the
+ // semaphores.
+ //
+
+ if (((*(PULONG)hsem & 0xff) == 0) && (*(PULONG)hsem != (ULONG)hsem)) {
+ return NO_ERROR;
+ }
+
+ try {
+ Od2ProbeForWrite( (PVOID)hsem, sizeof( ULONG ), 1 );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP ();
+ }
+
+ // If the semaphore will be ckeated, will be checked if it must be created
+ // in initially busy state.
+
+ pRealSem = Od2LookupOrCreateSem(hsem, &firsttime, SEM_FROM_REQUESTWAIT);
+
+ if (pRealSem == NULL)
+ return(ERROR_NOT_ENOUGH_MEMORY);
+
+ if (*(PULONG)hsem != (ULONG)hsem) {
+ //
+ // RAM semaphore:
+ //
+
+ if (pRealSem->OwnerThread != (TID)SEM_DUAL && pRealSem->OwnerThread != (TID)SEM_EVENT) {
+ if (pRealSem->OwnerThread == (TID)SEM_AT_INIT) {
+ pRealSem->OwnerThread = (TID)SEM_EVENT; // mark it as a WAIT/CLEAR semaphore, no owner
+ }
+ else {
+ //
+ // This semaphore used to be a Request/Clear only, need to verify
+ // that we block if currently owned.
+ //
+ CheckCurrentOwner = TRUE;
+ pRealSem->OwnerThread = (TID)SEM_DUAL;
+ }
+ }
+
+ if (firsttime) {
+ if ((*(PULONG)hsem & 0xFFF00000) != 0xCCC00000) {
+ //
+ //
+ // private mem RAM sem: set value and return
+ //
+ *(PULONG)hsem = (ULONG)pRealSem;
+ }
+ else {
+ //
+ // *(PULONG)hsem |= 0x00040000;
+ //
+ __asm
+ {
+ mov eax, hsem
+ lock or dword ptr [eax], 0x00040000
+ }
+ }
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosSemWait 1st time succeeded: Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(),hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+#endif
+ // Os2 semaphore can be initialized as busy. In this case we
+ // must wait on it.
+ // return(NO_ERROR);
+ }
+
+ //
+ // We Implement a Wait by a Waiting on the Event part of
+ // the OS21X_SEM
+ //
+
+
+ //
+ // RAM semaphore:
+ // OS/2 1.X apps expect sem location last two bits to be 0
+ //
+
+ //
+ // *(PULONG) hsem &= 0xfffffffc;
+ //
+ __asm
+ {
+ mov eax, hsem
+ lock and dword ptr [eax], 0XFFFFFFFC
+ }
+
+ if ((*(PULONG)hsem & 0xFFF00000) == 0xCCC00000) {
+ //
+ // RAM sem in shared memory.
+ // make sure that subsequent sem clear will wake us
+ //
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosSemWait on shared mem RAM: Sem %x, *Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(),hsem, *(PULONG)hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+#endif
+ if ((*(PULONG)hsem & 0xFFFC0000) == 0xCCC80000) {
+ CheckCurrentOwner = TRUE;
+ }
+ // WAIT/CLEAR shared RAM sem
+ //
+ // *(PULONG) hsem |= 0x00040000;
+ //
+ __asm
+ {
+ mov eax, hsem
+ lock or dword ptr [eax], 0x00040000
+ }
+ }
+
+ if (CheckCurrentOwner) {
+ NTSTATUS Status;
+ //
+ // This semaphore used to be for Request/Clear only,
+ // we have to make sure that if someone owns it we block
+ // 1. Block on the mutex
+ // 2. Free the mutex (a wait does not block others)
+ //
+
+ //
+ // Capture the timeout value and convert it into an NT timeout value.
+ //
+ NtTimeout = Od2CaptureTimeout( lTimeOut, (PLARGE_INTEGER)&CapturedTimeout );
+
+ do {
+ if (NtTimeout) {
+ Od2StartTimeout(&StartTimeStamp);
+ }
+ Status = NtWaitForSingleObject(
+ pRealSem->Mutex,
+ TRUE, // Alertable
+ NtTimeout
+ );
+#if DBG
+ if (Status == STATUS_USER_APC) {
+ DbgPrint("[%d,%d] WARNING !!! DosSemRequest was broken by APC\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ );
+ }
+#endif
+ } while (Status == STATUS_USER_APC &&
+ (Status = Od2ContinueTimeout(&StartTimeStamp, NtTimeout)) == STATUS_SUCCESS
+ );
+
+ //
+ // BUGBUG: This code is a little strange. The status can be positive value,
+ // for example, STATUS_TIMEOUT. In this case rc will remain NO_ERROR too.
+ //
+ if (!NT_SUCCESS(Status)) {
+ rc = Or2MapNtStatusToOs2Error(Status, ERROR_SEM_TIMEOUT);
+#if DBG
+ DbgPrint ("[%d,%d] DosSemWait after Request: error Waiting for Mutex, %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+#endif
+ }
+
+ Status = NtReleaseSemaphore (
+ pRealSem->Mutex,
+ 1,
+ NULL);
+ if ( !NT_SUCCESS(Status) && Status != STATUS_SEMAPHORE_LIMIT_EXCEEDED ) {
+#if DBG
+ DbgPrint ("DosSemWait: error NtReleaseSempahore , %lx\n", Status);
+#endif
+ }
+ if (rc != NO_ERROR) {
+ goto NoWait;
+ }
+ }
+
+ }
+
+ rc = DosWaitEventSem (pRealSem->Event, lTimeOut);
+
+NoWait:
+ if (rc != NO_ERROR) {
+ if (rc == ERROR_TIMEOUT || rc == ERROR_SEM_TIMEOUT) {
+ rc = ERROR_SEM_TIMEOUT;
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosSemWait, timeout on Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(),hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+#endif
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosSemWait, Error %d on Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(),rc, hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+#endif
+ }
+ return rc;
+ }
+
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosSemWait succeeded Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(),hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+ if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
+ ((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
+ ((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
+ ((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
+ KdPrint(("[%d,%d] DosSemWait(%x, *=%x): exiting OK\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem));
+ }
+#endif // DBG
+
+ return NO_ERROR;
+}
+
+
+APIRET
+DosSemSetWait(
+ IN HSEM hsem,
+ IN LONG lTimeOut
+ )
+{
+ APIRET rc;
+
+ //
+ // we simply set and then Wait. Should be atomic
+ //
+ rc = DosSemSet (hsem);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosSemSetWait: error at DosSemSet, Status %d\n", rc);
+ }
+#endif
+ return rc;
+ }
+
+ rc = DosSemWait(hsem, lTimeOut);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosSemSetWait: error at DosSemWait, Status %d\n", rc);
+ }
+#endif
+ return rc;
+ }
+
+ return (NO_ERROR);
+}
+
+APIRET
+DosSemRequest(
+ IN HSEM hsem,
+ IN LONG lTimeOut
+ )
+{
+ APIRET rc = NO_ERROR;
+ NTSTATUS Status = STATUS_SUCCESS;
+ POS21X_SEM pRealSem;
+ ULONG Dummy;
+ LARGE_INTEGER CapturedTimeout;
+ PLARGE_INTEGER NtTimeout;
+ LARGE_INTEGER StartTimeStamp;
+ BOOLEAN firsttime;
+ BOOLEAN CheckIfClear = FALSE;
+
+ //
+ // BUGBUG: In OS/2 native the RAM semaphore that has zero least significant byte is
+ // treated free (see comment for DosSemWait).
+ //
+
+#if DBG
+ if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
+ ((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
+ ((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
+ ((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1)))
+ {
+ KdPrint(("[%d,%d] DosSemRequest(%x, *=%x): entering\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem));
+ }
+#endif // DBG
+
+ try {
+ Od2ProbeForWrite( (PVOID)hsem, sizeof( ULONG ), 1 );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP ();
+ }
+
+ // If the semaphore will be created, will be checked if it will be created
+ // initially busy semaphore.
+
+ pRealSem = Od2LookupOrCreateSem(hsem, &firsttime, SEM_FROM_REQUESTWAIT);
+
+ if (pRealSem == NULL)
+ return(ERROR_NOT_ENOUGH_MEMORY);
+
+ if (pRealSem->FlagsByte & SYSSEM_QUEUE) {
+ //
+ // If this is a system semaphore that was used by DosPeekQueue call to DosSemWait.
+ // This is special hack to work around bogus usage of semaphores with queues by
+ // ICL applications (see mail conversations with Thierry Tabard).
+ // [YosefD Jul-19-1995]
+ //
+ return DosSemWait(hsem, lTimeOut);
+ }
+
+ if (firsttime) {
+ pRealSem->OwnerThread = (TID)SEM_MUTEX_NOT_OWNED; // mark it as a REQUEST/CLEAR semaphore, no owner
+ if ((*(PULONG)hsem & 0xFFF00000) != 0xCCC00000) {
+ //
+ // private mem RAM sem: set value and return
+ //
+ *(PULONG)hsem = (ULONG)pRealSem | 1;
+ }
+ }
+
+
+ //
+ // Capture the timeout value and convert it into an NT timeout value.
+ //
+
+ NtTimeout = Od2CaptureTimeout( lTimeOut, (PLARGE_INTEGER)&CapturedTimeout );
+
+
+ if ((*(PULONG)hsem == (ULONG)hsem) && !(pRealSem->FlagsByte & SYSSEM_PUBLIC)) {
+ //
+ // take semaphore to examine state
+ //
+ Status = Od2AcquireSync();
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DbgPrint("[%d,%d] DosSemRequest: failed to NtWaitForSingleObject on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ if (pRealSem->OwnerThread == (TID)Od2CurrentThreadId()){
+ //
+ // must be a system semaphore that was prevoiusly
+ // requested by this thread.
+ //
+ pRealSem->RequestCount++;
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] DosSemRequest (nested): failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ Status = STATUS_SUCCESS;
+ goto no_wait;
+ }
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] DosSemRequest (not nested): failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ }
+
+ //
+ // Implement a Request by a WaitForSingleObject on the Nt
+ // Semaphore
+ //
+ //
+ // first watch for the ill case where someone used DosSemWait
+ // on this semaphore before. Set it to mutex so we get freed
+ //
+ if (pRealSem->OwnerThread == SEM_EVENT) {
+ //
+ // This semaphore used to be a Wait/Clear only, need to verify
+ // that we block if currently not clear.
+ //
+ CheckIfClear = TRUE;
+ pRealSem->OwnerThread = (TID)SEM_DUAL;
+ }
+
+ //
+ // shared RAM sem - make sure a subsequent sem clear will wake us
+ //
+ if ((*(PULONG)hsem & 0xFFF00000) == 0xCCC00000) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosSemRequest on shared mem RAM: Sem %x, *Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(),hsem, *(PULONG)hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+#endif
+ if ((*(PULONG)hsem & 0xFFFC0000) == 0xCCC40000) {
+ CheckIfClear = TRUE;
+ }
+ // REQUST/CLEAR shared RAM sem
+ //
+ // *(PULONG) hsem |= 0x00040000;
+ //
+ __asm
+ {
+ mov eax, hsem
+ lock or dword ptr [eax], 0x00080000
+ }
+ }
+
+ if (CheckIfClear) {
+
+ //
+ // This semaphore used to be for Wait/Clear only,
+ // we have to make sure that we block if not cleared
+ //
+
+ //
+ // Wait for the event, so next clear wakes us, or we have it
+ //
+ rc = DosWaitEventSem (pRealSem->Event, lTimeOut);
+ if (rc != NO_ERROR) {
+ if (rc == ERROR_TIMEOUT) {
+ rc = ERROR_SEM_TIMEOUT;
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosSemRequest on SEM_EVENT, timeout on Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(),hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+#endif
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosSemRequest on SEM_EVENT, Error %d on Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(),rc, hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+#endif
+ }
+ return rc;
+ }
+ }
+
+DosSemRequest_retry:
+ if (NtTimeout) {
+ Od2StartTimeout(&StartTimeStamp);
+ }
+ Status = NtWaitForSingleObject(
+ pRealSem->Mutex,
+ TRUE, // Alertable
+ NtTimeout
+ );
+
+ if (Status == STATUS_SUCCESS || Status == STATUS_ABANDONED) {
+
+ // The semaphore is owned only in the case that the status is
+ // STATUS_SUCCESS or STATUS_ABONDONED (if it was, for example,
+ // STATUS_TIMEOUT, that means that the semaphore wasn't actually
+ // owned.
+
+ if ((*(PULONG)hsem == (ULONG)hsem) &&
+ !(pRealSem->FlagsByte & SYSSEM_PUBLIC)) {
+ //
+ // Exclusive System Semaphore,
+ // Mark this semaphore 'owned'
+ //
+ //
+ // take semaphore to set state
+ //
+ Status = Od2AcquireSync();
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DbgPrint("[%d,%d] DosSemRequest (take it): failed to NtWaitForSingleObject on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ pRealSem->OwnerThread = (TID)Od2CurrentThreadId();
+ pRealSem->RequestCount = 0;
+
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] DosSemRequest (take it): failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ }
+ else {
+ if (pRealSem->OwnerThread != (TID)SEM_DUAL) {
+ pRealSem->OwnerThread = (TID)SEM_MUTEX_NOT_OWNED;
+ }
+ }
+ }
+
+no_wait:
+ if (Status == STATUS_SUCCESS) {
+
+ rc = NO_ERROR;
+ }
+ else {
+ if (NT_SUCCESS(Status) ) {
+ if (Status == STATUS_TIMEOUT) {
+ rc = ERROR_SEM_TIMEOUT;
+ }
+ else if (Status == STATUS_ABANDONED) {
+#if DBG
+ DbgPrint("[%d,%d] DosSemRequest NT semaphore status ABONDONED\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId());
+#endif // DBG
+ rc = ERROR_SEM_OWNER_DIED;
+ }
+ else if (Status == STATUS_USER_APC) {
+#if DBG
+ DbgPrint("[%d,%d] WARNING !!! DosSemRequest was broken by APC\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ );
+#endif
+ if (Od2ContinueTimeout(&StartTimeStamp, NtTimeout) == STATUS_SUCCESS) {
+ goto DosSemRequest_retry;
+ }
+ else {
+ rc = ERROR_TIMEOUT;
+ }
+ }
+ else if (Status == STATUS_ALERTED) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("[%d,%d] DosSemRequest ALERTED\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId());
+ }
+#endif
+ rc = ERROR_INTERRUPT;
+ }
+ else {
+ // This is some success status that we don't know about.
+ // To be more secure print the message.
+#if DBG
+ DbgPrint("[%d,%d] DosSemRequest BUGBUG Unknown success status = %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(), Status);
+#endif // DBG
+ rc = ERROR_INTERRUPT;
+ }
+ } else {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosSemRequest: error at NtWaitForSingleObject, %x\n",
+ Status);
+ }
+#endif
+ rc = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE);
+ }
+ }
+
+ //
+ // In the ill case where it used both as a mutex and as an event,
+ // we Reset the event too
+ //
+
+ if (pRealSem->OwnerThread == (TID)SEM_DUAL) {
+
+ APIRET rc1;
+
+ rc1 = DosResetEventSem (pRealSem->Event, &Dummy);
+
+ if (rc1 == ERROR_ALREADY_RESET)
+ rc1 = NO_ERROR;
+
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ if (rc1 != NO_ERROR) {
+ DbgPrint ("DosSemRequest: error at DosResetEvent %d\n",
+ rc1);
+ }
+ }
+#endif
+ if (rc == NO_ERROR && rc1 != NO_ERROR) {
+ rc = rc1;
+ }
+ }
+
+ if (rc == NO_ERROR) {
+
+ if (*(PULONG)hsem != (ULONG)hsem) {
+ //
+ // RAM Semaphore:
+ // OS/2 1.X Apps expects the semaphore location
+ // last two bits to be actually 1 (undocumented)
+ //
+ //
+ // *(PULONG) hsem |= 1;
+ //
+ __asm
+ {
+ mov eax,hsem
+ lock or dword ptr [eax], 1
+ }
+ }
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ if (firsttime) {
+ DbgPrint ("DosSemRequest 1st time succeeded: Sem %x, NtSem %lx, Event %lx\n",
+ hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+ else {
+ DbgPrint ("[TID %x]: DosSemRequest succeeded Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(),hsem, pRealSem->Mutex,pRealSem->Event );
+ }
+ }
+ if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
+ ((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
+ ((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
+ ((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
+ KdPrint(("[%d,%d] DosSemRequest(%x, *=%x): exiting OK\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem));
+ }
+#endif // DBG
+ return(NO_ERROR);
+ }
+
+#if DBG
+ if (((Os2DebugSem != 0) && (hsem == Os2DebugSem)) ||
+ ((Os2DebugSem3 != 0) && (hsem == Os2DebugSem3)) ||
+ ((Os2DebugSem2 != 0) && (hsem == Os2DebugSem2)) ||
+ ((Os2DebugSem1 != 0) && (hsem == Os2DebugSem1))) {
+ KdPrint(("[%d,%d] DosSemRequest(%x, *=%x): exiting, rc=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ hsem,
+ *(PULONG)hsem,
+ rc));
+ }
+#endif // DBG
+
+ return rc;
+}
+
+
+APIRET
+DosOpenSem(
+ OUT PHSYSSEM phSem,
+ IN PSZ pszSemName
+ )
+{
+ ULONG Sem;
+ APIRET rc = NO_ERROR;
+ POS21X_SEM pRealSem;
+ NTSTATUS Status;
+
+ try {
+ Od2ProbeForWrite( phSem, sizeof( HSYSSEM ), 1 );
+ Od2ProbeForRead( pszSemName, 2, 1 );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP ();
+ }
+
+ Status = Od2AcquireSync();
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DbgPrint("[%d,%d] DosOpenSem: failed to NtWaitForSingleObject on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+
+ rc = Od2OpenSem(
+ NULL,
+ &pRealSem,
+ pszSemName,
+ TRUE);
+
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosOpenSem: error calling Od2OpenSem, %d\n", rc);
+ }
+#endif
+
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] DosOpenSem: failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ return rc;
+ }
+
+ Sem = (ULONG) *phSem = (ULONG) pRealSem;
+ *phSem = (POS21X_SEM)(FLATTOFARPTR(Sem));
+ if (pRealSem->FlagsByte == 0) {
+ //
+ // This sys sem was not created by this process, and
+ // is opened the first time by this process, assume public syssem
+ // BUGBUG we need to reimplement exclusive sys sem to get the
+ // full OS/2 semantics across processes
+ //
+ pRealSem->FlagsByte |= SYSSEM_PUBLIC;
+ }
+
+ Status = Od2ReleaseSync();
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d] DosOpenSem: failed to NtReleaseMutant on sync sem, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ return(NO_ERROR);
+}
+
+APIRET
+DosMuxSemWait(
+ OUT PUSHORT pisemCleared,
+ IN PMUXSEMLIST pmsxl,
+ IN LONG lTimeOut
+ )
+{
+ APIRET rc = NO_ERROR;
+ NTSTATUS Status;
+ USHORT i;
+ HANDLE NtHandles[ 16 ]; // Handles to actually block on
+ LARGE_INTEGER CapturedTimeout;
+ PLARGE_INTEGER NtTimeout;
+ ULONG Sem;
+ HSEM FlatSem;
+ POS21X_SEM pRealSem;
+
+ BOOLEAN firsttime;
+ BOOLEAN CheckCurrentOwner = FALSE;
+ //
+ // Capture the timeout value and convert it into an NT timeout value.
+ //
+
+ NtTimeout = Od2CaptureTimeout( lTimeOut, (PLARGE_INTEGER)&CapturedTimeout );
+
+ //
+ // probe index pointer and pmsxl buffer
+ //
+
+ try {
+ Od2ProbeForWrite( pisemCleared, sizeof( USHORT ), 1 );
+
+ //
+ // probe count first, then actual array
+ //
+ Od2ProbeForRead(pmsxl, sizeof(USHORT),1);
+ Od2ProbeForRead(&pmsxl->amxs, sizeof(MUXSEM)*(pmsxl->cmxs),1);
+
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Go over the array of semaphores.
+ // for each semaphore check if it's event is posted.
+ // If posted - sempahore is clear, return index.
+ // If not posted, add to NtHandles array
+ //
+
+ for (i = 0; i < pmsxl->cmxs; i++,CheckCurrentOwner = FALSE) {
+ //
+ // Check validity of MUXSEM entry
+ //
+
+ if (pmsxl->amxs[i].zero != 0)
+ return ERROR_INVALID_PARAMETER;
+
+ Sem = (ULONG) (pmsxl->amxs[i].hsem);
+ FlatSem = FARPTRTOFLAT(Sem);
+ try {
+ Od2ProbeForWrite( (PVOID)FlatSem, sizeof( ULONG ), 1 );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP ();
+ }
+
+ // If the semaphore will be created, will be checked if it must be
+ // created in initially busy state.
+
+ pRealSem = Od2LookupOrCreateSem (FlatSem, &firsttime, SEM_FROM_REQUESTWAIT);
+
+ if (pRealSem == NULL)
+ return(ERROR_NOT_ENOUGH_MEMORY);
+
+ if (*(PULONG)FlatSem != (ULONG)FlatSem) {
+ if (pRealSem->OwnerThread != (TID)SEM_DUAL && pRealSem->OwnerThread != (TID)SEM_EVENT) {
+ if (pRealSem->OwnerThread == (TID)SEM_AT_INIT) {
+ pRealSem->OwnerThread = (TID)SEM_EVENT; // mark it as a WAIT/CLEAR semaphore, no owner
+ }
+ else {
+ //
+ // This semaphore used to be a Request/Clear only, need to verify
+ // that we block if currently owned.
+ //
+ CheckCurrentOwner = TRUE;
+ pRealSem->OwnerThread = (TID)SEM_DUAL;
+ }
+ }
+
+ if (firsttime) {
+ if ((*(PULONG)FlatSem & 0xFFF00000) != 0xCCC00000) {
+ //
+ // private mem RAM sem: set value and return
+ //
+ *(PULONG)FlatSem = (ULONG)pRealSem;
+ }
+ else {
+ *(PULONG)FlatSem |= 0x00040000; // WAIT/CLEAR shared RAM sem
+ }
+ *pisemCleared = i;
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosMuxSemWait: 1st time success. sem was cleared. Index %d, Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(),*pisemCleared, FlatSem, pRealSem->Mutex, pRealSem->Event);
+ }
+#endif
+ return(NO_ERROR);
+ }
+
+ //
+ // make sure that any subsequent semclear will post
+ // this semaphore's event
+ //
+ if ((*(PULONG)FlatSem & 0xFFF00000) == 0xCCC00000) {
+ //
+ // RAM sem in shared memory.
+ // make sure that subsequent sem clear will wake us
+ //
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosMuxSemWait on shared mem RAM: Index %d, Sem %x, *Sem %x, NtSem %lx, Event %lx\n",
+ *pisemCleared, FlatSem, *(PULONG)FlatSem, pRealSem->Mutex,pRealSem->Event );
+ }
+#endif
+ if ((*(PULONG)FlatSem & 0xFFFC0000) == 0xCCC80000) {
+ CheckCurrentOwner = TRUE;
+ }
+ *(PULONG)FlatSem |= 0x00040000; // WAIT/CLEAR shared RAM sem
+ }
+ }
+
+ if (CheckCurrentOwner) {
+ SEMAPHORE_BASIC_INFORMATION SemInfo;
+ ULONG Dummy;
+ NTSTATUS Status;
+ //
+ // This semaphore used to be for Request/Clear only,
+ // we have to make sure that if someone owns it we block
+ //
+
+ //
+ // query the mutex, to see if owned
+ //
+ Status = NtQuerySemaphore(
+ pRealSem->Mutex,
+ SemaphoreBasicInformation,
+ (PVOID)(&SemInfo),
+ sizeof(SemInfo),
+ NULL);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosMuxSemWait: error in NtQuerySemaphore, %lx\n", Status);
+ }
+#endif
+ }
+ else {
+ if (SemInfo.CurrentCount == 0) {
+
+ //
+ // Sempahore is not signaled i.e. it is not clear
+ // block ourselves by reset of event before wait
+ //
+ rc = DosResetEventSem (pRealSem->Event, &Dummy);
+
+ if (rc == ERROR_ALREADY_RESET)
+ rc = NO_ERROR;
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ if (rc != NO_ERROR) {
+ DbgPrint ("DosMuxSemWait: error at DosResetEvenSem, error %d\n",
+ rc);
+ }
+ }
+#endif
+
+ }
+ }
+ }
+/*
+ *
+ rc = DosQueryEventSem(pRealSem->Event, &PostCount);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("DosMuxSemWait: error in DosQueryEventSem %d \n", rc);
+ }
+#endif
+ return (rc);
+ }
+
+ if (PostCount != 0) {
+ //
+ // Found a posted semaphore:
+ // Perform DosWaitEventSem to lower post count
+ // and return
+ //
+ rc = DosWaitEventSem (pRealSem->Event, 0L);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosMuxSemWait: Unexpected error %d. Index %d\n",
+ Od2CurrentThreadId(),rc, *pisemCleared);
+ }
+#endif
+ return rc;
+ }
+ *pisemCleared = i;
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosMuxSemWait: success. sem was cleared. Index %d, Sem %x, NtSem %lx, Event %lx\n",
+ Od2CurrentThreadId(),*pisemCleared, FlatSem, pRealSem->Mutex, pRealSem->Event);
+ }
+#endif
+
+ return NO_ERROR;
+ }
+
+ *
+ */
+ rc = Od2GetSemNtEvent(
+ FlatSem,
+ &NtHandles[i]);
+ }
+
+ //
+ // Now, that we scanned the whole pmsxl structure and
+ // have a list of Nt Handles to block on, let's block
+ // on it
+ //
+
+retry:
+ Status = NtWaitForMultipleObjects(
+ (CHAR)i,
+ NtHandles,
+ WaitAny,
+ TRUE, // Alertable
+ NtTimeout
+ );
+ if (NT_SUCCESS( Status )) {
+ if (Status <= STATUS_WAIT_63) {
+ *pisemCleared = (USHORT)(Status & 0x3F);
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint ("[TID %x]: DosMuxSemWait: success at NtWait. Index %d\n",
+ Od2CurrentThreadId(),*pisemCleared);
+ }
+#endif
+ Sem = (ULONG) (pmsxl->amxs[*pisemCleared].hsem);
+ FlatSem = FARPTRTOFLAT(Sem);
+ if ((*(PULONG)FlatSem != (ULONG)FlatSem) &&
+ ((*(PULONG)FlatSem & 0xFFF00000) != 0xCCC00000)) {
+ //
+ // Private RAM semaphores:
+ // OS/2 1.X apps (SQL 1.11) expect sem location to be 0
+ //
+ *(PULONG)FlatSem = 0;
+ }
+ rc = NO_ERROR;
+ }
+ else
+ if (Status == STATUS_ABANDONED) {
+ rc = ERROR_SEM_OWNER_DIED;
+ }
+ else
+ if (Status == STATUS_TIMEOUT) {
+ rc = ERROR_SEM_TIMEOUT;
+ }
+ else
+ if (Status == STATUS_USER_APC) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("MuxSemWait Status STATUS_USER_APC\n");
+ }
+#endif
+ rc = ERROR_SS_RETRY;
+ }
+ else
+ if (Status == STATUS_ALERTED) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("MuxSemWait Status STATUS_ALERTED\n");
+ }
+#endif
+ rc = ERROR_SS_RETRY;
+ }
+ else {
+ rc = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE);
+ }
+ }
+ else {
+ rc = Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_HANDLE);
+ }
+
+ if (rc == ERROR_SS_RETRY) {
+ goto retry;
+ }
+
+ return rc;
+}
+
+
+APIRET
+DosFSRamSemRequest(
+ IN PDOSFSRSEM16 pdosfsrs,
+ IN LONG lTimeOut
+ )
+{
+ APIRET rc = NO_ERROR;
+ BOOLEAN HackPmPrintDrive = FALSE;
+ PULONG pSem;
+ PUSHORT puSemIndex;
+
+ //
+ // cb must be 14 (1.21 PRM)
+ //
+ try {
+ Od2ProbeForWrite( pdosfsrs, sizeof( DOSFRSEM16 ), 1 );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP ();
+ }
+ if (pdosfsrs->cb != 14) {
+ if (pdosfsrs->cb == 12) {
+ //
+ // special hack for some print drivers on OS/2,
+ // we have a shared segment with semaphores pointers,
+ // indexed by the USHORT left off pdosfsrs->sem
+ //
+ HackPmPrintDrive = TRUE;
+#if DBG
+ DbgPrint("DosFSRamSemRequest called with cb=12\n", rc);
+#endif
+ if (pHackPrinterDriverSem == 0) {
+ //
+ // No thread in this process used this hack yet -
+ // See if a previous process created it
+ //
+ USHORT sel;
+ APIRET rc = DosGetShrSeg("\\SHAREMEM\\OS2SSPRD", &sel);
+ if (rc != NO_ERROR) {
+ if (rc == ERROR_FILE_NOT_FOUND) {
+ //
+ // Create the segment with the semaphores pointers.
+ // The first ULONG is the index to the next available
+ // index
+ //
+ rc = DosAllocShrSeg((sizeof(ULONG)) * NUMOFPRINTDRIVERSEM,
+ "\\SHAREMEM\\OS2SSPRD",
+ &sel);
+ }
+ else {
+#if DBG
+ DbgPrint("DosFSRamSemRequest - internal error\n");
+#endif
+ return ERROR_INVALID_PARAMETER;
+ }
+ }
+ pHackPrinterDriverSem = (PULONG)(SELTOFLAT(sel));
+ *pHackPrinterDriverSem = 1;
+ }
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("DosFSRamSemRequest - invalid FSRSEM.cb %d\n", pdosfsrs->cb);
+ }
+#endif
+ return ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ if (HackPmPrintDrive) {
+ //
+ // Take the next available index
+ //
+ puSemIndex = (PUSHORT)(&pdosfsrs->sem);
+ if (*puSemIndex == 0){
+ //
+ // first time this FSR is used
+ //
+ if (*pHackPrinterDriverSem == NUMOFPRINTDRIVERSEM) {
+ //
+ // No More Slots
+ //
+#if DBG
+ DbgPrint("DosFSRamSemRequest - Not Enough Slots for PM Driver hack\n");
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ pSem = pHackPrinterDriverSem + sizeof(ULONG) * (*pHackPrinterDriverSem);
+ *puSemIndex = (USHORT)(*pHackPrinterDriverSem);
+ *pHackPrinterDriverSem = *pHackPrinterDriverSem + 1;
+ }
+ else {
+ //
+ // use the index stored in the sem value
+ //
+ pSem = pHackPrinterDriverSem + sizeof(ULONG) * (*puSemIndex);
+ }
+ }
+ else {
+ pSem = (PULONG)(&pdosfsrs->sem);
+ }
+
+ //
+ // if not owned - set to owned, use count 1
+ // and return
+ //
+
+ if (pdosfsrs->pid == 0) {
+ //
+ // Perform a Request on the semaphore, to ensure that
+ // other threads will now block
+ //
+ rc = DosSemRequest((HSEM)pSem, lTimeOut);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("DosFSRamSemRequest: Illegal error from DosSemRequest. %d\n", rc);
+ }
+#endif
+ }
+ else {
+ pdosfsrs->pid = (USHORT)Od2Process->Pib.ProcessId;
+ pdosfsrs->tid = (USHORT)(Od2CurrentThreadId());
+ pdosfsrs->cUsage = 1;
+ pdosfsrs->client = 0;
+ }
+ return(rc);
+ }
+ //
+ // if we are inside Exit List and the owner process is
+ // the caller's process, then force cUsage to 1 and
+ // thread to caller, else block.
+ //
+
+ if (Od2ExitListInProgress && (pdosfsrs->pid == (USHORT)Od2Process->Pib.ProcessId) ) {
+ rc = ERROR_SEM_OWNER_DIED;
+ pdosfsrs->tid = (USHORT)(Od2CurrentThreadId());
+ pdosfsrs->cUsage = 1;
+ return(rc);
+
+ }
+
+ //
+ // if owned by calling thread - increment cUsage
+ //
+ if (pdosfsrs->pid == (USHORT)Od2Process->Pib.ProcessId &&
+ pdosfsrs->tid == (USHORT)(Od2CurrentThreadId()) ) {
+ pdosfsrs->cUsage++;
+ return(NO_ERROR);
+ }
+
+ //
+ // now we have to block on the semaphore
+ //
+ rc = DosSemRequest((HSEM)pSem, lTimeOut);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("DosFSRamSemRequest: error from DosSemRequest. %d\n", rc);
+ }
+#endif
+ }
+ else {
+ pdosfsrs->pid = (USHORT)Od2Process->Pib.ProcessId;
+ pdosfsrs->tid = (USHORT)(Od2CurrentThreadId());
+ pdosfsrs->cUsage = 1;
+ }
+
+ return (rc);
+}
+
+
+APIRET
+DosFSRamSemClear(
+ IN PDOSFSRSEM16 pdosfsrs
+ )
+{
+ APIRET rc = NO_ERROR;
+ BOOLEAN HackPmPrintDrive = FALSE;
+ PULONG pSem;
+ PUSHORT puSemIndex;
+
+ try {
+ Od2ProbeForWrite( pdosfsrs, sizeof( DOSFRSEM16 ), 1 );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP ();
+ }
+ //
+ // cb must be 14 (1.21 PRM)
+ //
+ if (pdosfsrs->cb != 14) {
+ if (pdosfsrs->cb == 12) {
+ //
+ // special hack for some print drivers on OS/2,
+ // we have a shared segment with semaphores pointers,
+ // indexed by the USHORT left off pdosfsrs->sem
+ //
+ HackPmPrintDrive = TRUE;
+#if DBG
+ DbgPrint("DosFSRamSemClear - was called with cb=12\n", rc);
+#endif
+ if (pHackPrinterDriverSem == 0) {
+ //
+ // No thread in this process used this hack yet -
+ // See if a previous process created it
+ //
+ USHORT sel;
+ APIRET rc = DosGetShrSeg("\\SHAREMEM\\OS2SSPRD", &sel);
+ if (rc != NO_ERROR) {
+ if (rc == ERROR_FILE_NOT_FOUND) {
+ //
+ // Create the segment with the semaphores pointers.
+ // The first ULONG is the index to the next available
+ // index
+ //
+ rc = DosAllocShrSeg((sizeof(ULONG)) * NUMOFPRINTDRIVERSEM,
+ "\\SHAREMEM\\OS2SSPRD",
+ &sel);
+ }
+ else {
+#if DBG
+ DbgPrint("DosFSRamSemClear - internal error\n");
+#endif
+ return ERROR_INVALID_PARAMETER;
+ }
+ }
+ pHackPrinterDriverSem = (PULONG)(SELTOFLAT(sel));
+ *pHackPrinterDriverSem = 1;
+ }
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("DosFSRamSemClear - invalid FSRSEM. cb=%d\n", pdosfsrs->cb);
+ }
+#endif
+ return ERROR_INVALID_PARAMETER;
+ }
+ }
+ //
+ // if not owned - return
+ //
+
+ if (pdosfsrs->pid == 0) {
+ return(NO_ERROR);
+ }
+
+ if (HackPmPrintDrive) {
+ //
+ // Take the next available index
+ //
+ puSemIndex = (PUSHORT)(&pdosfsrs->sem);
+ if (*puSemIndex == 0){
+ //
+ // first time this FSR is used
+ //
+ if (*pHackPrinterDriverSem == NUMOFPRINTDRIVERSEM) {
+ //
+ // No More Slots
+ //
+#if DBG
+ DbgPrint("DosFSRamSemClear - Not Enough Slots for PM Driver hack\n");
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ pSem = pHackPrinterDriverSem + sizeof(ULONG) * (*pHackPrinterDriverSem);
+ *puSemIndex = (USHORT)*pHackPrinterDriverSem;
+ *pHackPrinterDriverSem = *pHackPrinterDriverSem + 1;
+ }
+ else {
+ //
+ // use the index stored in the sem value
+ //
+ pSem = pHackPrinterDriverSem + sizeof(ULONG) * (*puSemIndex);
+ }
+ }
+ else {
+ pSem = (PULONG)(&pdosfsrs->sem);
+ }
+ //
+ // if owned by calling thread - decrement cUsage.
+ // if reached 0 - clear semaphore
+ //
+ if (pdosfsrs->pid == (USHORT)Od2Process->Pib.ProcessId &&
+ pdosfsrs->tid == (USHORT)(Od2CurrentThreadId()) ) {
+ if (--(pdosfsrs->cUsage) == 0) {
+ //
+ // need to really clear - remove ownership before we release
+ // blocking threads
+ //
+ pdosfsrs->pid = 0;
+ pdosfsrs->tid = 0;
+ rc = DosSemClear((HSEM)pSem);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("DosFSRamSemClear: Illegal error from DosSemClear. %d\n", rc);
+ }
+#endif
+ return(rc);
+ }
+ return(NO_ERROR);
+ }
+ else {
+ return(NO_ERROR);
+ }
+ }
+
+ //
+ // FSRAM sem owned by another thread - return error
+ //
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("DosFSRamSemClear called by a thread. Sem owned by another thread\n");
+ }
+#endif
+
+ return ERROR_EXCL_SEM_ALREADY_OWNED ;
+}
diff --git a/private/os2/client/dllsig16.c b/private/os2/client/dllsig16.c
new file mode 100644
index 000000000..50c68d01d
--- /dev/null
+++ b/private/os2/client/dllsig16.c
@@ -0,0 +1,499 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllsig16.c
+
+Abstract:
+
+ This module implements 32 equivalents of OS/2 V1.21 Signal
+ API Calls. These are called from 16->32 thunks (i386\doscalls.asm).
+
+
+Author:
+
+ Yaron Shamir (YaronS) 30-May-1991
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+
+extern OD2_SIG_HANDLER_REC SigHandlerRec;
+extern POD2_VEC_HANDLER_REC pVecHandlerRec;
+extern PVOID __cdecl Od2JumpTo16SignalDispatch(ULONG address, ULONG regs,
+ ULONG usFlagNum, ULONG usFlagArg);
+extern BOOLEAN LDRIsLDTValid(SEL sel);
+extern APIRET DosFreeSeg(SEL sel);
+
+VOID
+Od2PrepareEnterToSignalHandler(
+ PCONTEXT pContext,
+ POD2_CONTEXT_SAVE_AREA pSaveArea
+ );
+
+VOID
+Od2MakeSignalHandlerContext(
+ POS2_REGISTER16_SIGNAL pContext16
+ );
+
+VOID
+Od2ExitFromSignalHandler(
+ PCONTEXT Context,
+ POD2_CONTEXT_SAVE_AREA pSaveArea
+ );
+
+APIRET
+DosFlagProcess(
+ ULONG pid,
+ ULONG fScope,
+ ULONG usFlagNum,
+ ULONG usFlagArg,
+ ULONG pstack
+ )
+
+{
+ OS2_API_MSG m;
+ POS2_DISPATCH16_SIGNAL a = &m.u.Dispatch16Signal;
+
+ if (usFlagNum > 2) {
+ return(ERROR_INVALID_FLAG_NUMBER);
+ }
+
+ if (pid == 0 || pid == 0xffff) {
+ return(ERROR_INVALID_FUNCTION);
+ }
+
+ if (fScope != FLGP_SUBTREE && fScope != FLGP_PID) {
+ return(ERROR_INVALID_FUNCTION);
+ }
+
+ if ((ULONG) Od2Process->Pib.ProcessId == pid
+ && Od2CurrentThreadId() == 1) {
+ Od2JumpTo16SignalDispatch(SigHandlerRec.sighandler[usFlagNum +
+ SIG_PFLG_A - 1],
+ pstack,
+ usFlagNum + SIG_PFLG_A,
+ usFlagArg);
+ return(NO_ERROR);
+ }
+
+ a->usFlagNum = (USHORT) (usFlagNum + SIG_PFLG_A);
+ a->usFlagArg = (USHORT) usFlagArg;
+ a->fscope = fScope;
+ a->pidProcess = (ULONG) pid;
+ a->routine = (ULONG) _Od2ProcessSignal16;
+ a->sighandleraddr = (ULONG) &SigHandlerRec;
+
+ if (Od2CallSubsystem( &m,
+ NULL,
+ Os2Dispatch16Signal,
+ sizeof( *a )
+ )) {
+ return( m.ReturnedErrorValue );
+ }
+
+ return(NO_ERROR);
+}
+
+APIRET
+DosHoldSignal(
+ ULONG fDisable,
+ ULONG pstack
+ )
+{
+ OS2_API_MSG m;
+ POS2_DISPATCH16_SIGNAL a = &m.u.Dispatch16Signal;
+ ULONG i;
+
+ UNREFERENCED_PARAMETER(pstack);
+
+ if (fDisable == HLDSIG_DISABLE) {
+ SigHandlerRec.fholdenable++;
+ return NO_ERROR;
+ }
+
+ if (fDisable == HLDSIG_ENABLE && SigHandlerRec.fholdenable > 0) {
+ SigHandlerRec.fholdenable--;
+ if (SigHandlerRec.fholdenable == 0) {
+ for (i = 0; i < 7; ++i) {
+ if (SigHandlerRec.outstandingsig[i].sighandleraddr != 0) {
+ a->usFlagNum = HOLD_SIGNAL_CLEARED;
+ a->usFlagArg = (USHORT) (i + 1);
+ a->fscope = 0;
+ a->pidProcess = (ULONG) Od2Process->Pib.ProcessId;
+ a->routine = (ULONG) _Od2ProcessSignal16;
+ a->sighandleraddr = (ULONG) &SigHandlerRec;
+ Od2CallSubsystem( &m,
+ NULL,
+ Os2Dispatch16Signal,
+ sizeof( *a ));
+ }
+
+ }
+ }
+ return NO_ERROR;
+ }
+
+ else {
+ return ERROR_INVALID_FUNCTION;
+ }
+}
+
+APIRET
+DosSendSignal(
+ ULONG idProcess,
+ ULONG usSigNumber,
+ ULONG pstack
+ )
+{
+ OS2_API_MSG m;
+ POS2_DISPATCH16_SIGNAL a = &m.u.Dispatch16Signal;
+
+ UNREFERENCED_PARAMETER(pstack);
+
+ if (usSigNumber != SIG_CTRLC && usSigNumber != SIG_CTRLBREAK)
+ return(ERROR_INVALID_FLAG_NUMBER);
+
+ a->usFlagNum = (USHORT) usSigNumber;
+ a->usFlagArg = 0;
+ a->fscope = 0;
+ a->pidProcess = (ULONG) idProcess;
+ a->routine = (ULONG) _Od2ProcessSignal16;
+ a->sighandleraddr = (ULONG) &SigHandlerRec;
+
+ if (Od2CallSubsystem( &m,
+ NULL,
+ Os2Dispatch16Signal,
+ sizeof( *a )
+ )) {
+ return( m.ReturnedErrorValue );
+ }
+
+ return (NO_ERROR);
+}
+
+APIRET
+DosSetSigHandler( PFNSIGHANDLER pfnSigHandler,
+ PFNSIGHANDLER *pfnPrev,
+ PUSHORT pfAction,
+ ULONG fAction,
+ ULONG usSigNum
+ )
+
+{
+ OS2_API_MSG m;
+ ULONG address;
+ POS2_REGISTER_HANDLER b = &m.u.DosRegisterCtrlHandler;
+ POS2_DISPATCH16_SIGNAL a = &m.u.Dispatch16Signal;
+
+ if (usSigNum < SIG_CTRLC || usSigNum >= SIG_CSIGNALS) {
+ return ERROR_INVALID_SIGNAL_NUMBER;
+ }
+
+ if (usSigNum == SIG_BROKENPIPE && fAction != SIGA_ACKNOWLEDGE) {
+ return ERROR_INVALID_SIGNAL_NUMBER;
+ }
+
+ if (fAction > SIGA_ACKNOWLEDGE || usSigNum >= SIG_CSIGNALS) {
+ return ERROR_INVALID_SIGNAL_NUMBER;
+ }
+
+// if (!LDRIsLDTValid(((FLATTOSEL((ULONG) pfnSigHandler) | 4 | 3)))) {
+// return ERROR_INVALID_STARTING_RING;
+// }
+
+ //
+ // Check if signal outstanding if so the next command from the user
+ // has to be an acknowledge
+ //
+ if (SigHandlerRec.action[usSigNum - 1] == SIGA_ACKNOWLEDGE &&
+ fAction != SIGA_ACKNOWLEDGE) {
+ return ERROR_SIGNAL_PENDING;
+ }
+
+
+ //
+ // If signal is acknowledge check to see if a signal is pending,
+ // process the pending signal then set to clear pending. This must be
+ // done while signal is being processed to permit the signal to be
+ // used again.
+ //
+ if (fAction == SIGA_ACKNOWLEDGE) {
+
+ if (SigHandlerRec.outstandingsig[usSigNum - 1].sighandleraddr != 0) {
+ SigHandlerRec.action[usSigNum - 1] = SIGA_ACKNOWLEDGE_AND_ACCEPT;
+ a->usFlagNum = HOLD_SIGNAL_CLEARED;
+ a->usFlagArg = (USHORT) usSigNum;
+ a->fscope = 0;
+ a->pidProcess = (ULONG) Od2Process->Pib.ProcessId;
+ a->routine = (ULONG) _Od2ProcessSignal16;
+ a->sighandleraddr = (ULONG) &SigHandlerRec;
+ Od2CallSubsystem( &m,
+ NULL,
+ Os2Dispatch16Signal,
+ sizeof( *a ));
+ return NO_ERROR;
+ }
+ SigHandlerRec.action[usSigNum - 1] = SIGA_ACCEPT;
+ return NO_ERROR;
+ }
+
+ if (pfnSigHandler == 0 && fAction != SIGA_IGNORE) {
+ //
+ // means set default handling
+ //
+ fAction = SIGA_KILL;
+ }
+
+ //
+ // Check to see if we should remove the signal
+ //
+ if (fAction == SIGA_KILL) {
+
+ //
+ // Reinstall default handler, same as done in \loader\loader.c
+ //
+ address = SigHandlerRec.doscallssel;
+ switch (usSigNum) {
+ case SIG_CTRLC:
+ SigHandlerRec.sighandler[SIG_CTRLC - 1] = (ULONG)
+ (address | ThunkOffsetExitProcessStub);
+ SigHandlerRec.action[SIG_CTRLC - 1] = SIGA_ACCEPT;
+ break;
+ case SIG_BROKENPIPE:
+ SigHandlerRec.sighandler[SIG_BROKENPIPE - 1] = (ULONG)
+ (address | ThunkOffsetDosReturn);
+ SigHandlerRec.action[SIG_BROKENPIPE - 1] = SIGA_IGNORE;
+ break;
+ case SIG_KILLPROCESS:
+ SigHandlerRec.sighandler[SIG_KILLPROCESS - 1] = (ULONG)
+ (address | ThunkOffsetExitProcessStub);
+ SigHandlerRec.action[SIG_KILLPROCESS - 1] = SIGA_ACCEPT;
+ break;
+ case SIG_CTRLBREAK:
+ SigHandlerRec.sighandler[SIG_CTRLBREAK - 1] = (ULONG)
+ (address | ThunkOffsetExitProcessStub);
+ SigHandlerRec.action[SIG_CTRLBREAK - 1] = SIGA_ACCEPT;
+ break;
+ case SIG_PFLG_A:
+ SigHandlerRec.sighandler[SIG_PFLG_A - 1] = (ULONG)
+ (address | ThunkOffsetDosReturn);
+ SigHandlerRec.action[SIG_PFLG_A - 1] = SIGA_ACCEPT;
+ break;
+ case SIG_PFLG_B:
+ SigHandlerRec.sighandler[SIG_PFLG_B - 1] = (ULONG)
+ (address | ThunkOffsetDosReturn);
+ SigHandlerRec.action[SIG_PFLG_B - 1] = SIGA_ACCEPT;
+ break;
+ case SIG_PFLG_C:
+ SigHandlerRec.sighandler[SIG_PFLG_C - 1] = (ULONG)
+ (address | ThunkOffsetDosReturn);
+ SigHandlerRec.action[SIG_PFLG_C - 1] = SIGA_ACCEPT;
+ break;
+ }
+ if (usSigNum == SIG_CTRLC || usSigNum == SIG_KILLPROCESS ||
+ usSigNum == SIG_CTRLBREAK) {
+ b->usFlagNum = usSigNum;
+ b->fAction = SIGA_KILL;
+ Od2CallSubsystem(&m,
+ NULL,
+ Os2RegisterCtrlHandler,
+ sizeof( *b ));
+ }
+ return NO_ERROR;
+ }
+
+ try {
+ if (pfnPrev != NULL) {
+ *pfnPrev = (PFNSIGHANDLER) SigHandlerRec.sighandler[usSigNum - 1];
+ }
+ if (pfAction != NULL) {
+ *pfAction = SigHandlerRec.action[usSigNum - 1];
+ }
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ return ERROR_INVALID_FUNCTION;
+ }
+
+ if (pfnSigHandler) {
+ //
+ // fAction is SIGA_IGNORE
+ //
+ SigHandlerRec.sighandler[usSigNum - 1] = (ULONG)(FLATTOFARPTR((ULONG)pfnSigHandler));
+ }
+ SigHandlerRec.action[usSigNum - 1] = (USHORT) fAction;
+
+ if (usSigNum == SIG_CTRLC || usSigNum == SIG_KILLPROCESS ||
+ usSigNum == SIG_CTRLBREAK) {
+ b->usFlagNum = usSigNum;
+ if (fAction == SIGA_IGNORE)
+ b->fAction = SIGA_IGNORE;
+ else
+ b->fAction = SIGA_ACCEPT;
+
+ Od2CallSubsystem(&m,
+ NULL,
+ Os2RegisterCtrlHandler,
+ sizeof( *b ));
+ }
+
+ return NO_ERROR;
+}
+
+VOID
+Od2ProcessSignal16 (
+ IN ULONG rEax, // The value of EAX during interrupt. It will be useful
+ // if this is the return code of any wait. The value of
+ // EAX was set after that the context was read.
+ IN POS2_REGISTER16_SIGNAL pa
+ )
+{
+
+ CONTEXT Context;
+ PCONTEXT pContext;
+ ULONG size;
+ ULONG address;
+ ULONG signum;
+ NTSTATUS Status;
+ OD2_CONTEXT_SAVE_AREA SaveArea;
+
+ pContext = (PCONTEXT) ((PCHAR) pa + sizeof(OS2_REGISTER16_SIGNAL));
+
+
+ Od2PrepareEnterToSignalHandler(pContext, &SaveArea);
+
+ Od2Process->Pib.SignalWasntDelivered = FALSE;
+
+ signum = pa->usFlagNum;
+
+ //
+ // Since the signal handler routine can not run on stack of the
+ // process which called DosFlagProcess get stack from process
+ // context and run on that. But check to see where the program
+ // was excuting, if the CS is = 0x1b "Flat CS" then it was in the client
+ // or server. So restore registers from pointer to 16-bit stack
+ // saved at thunk entry.
+ //
+ pContext->Eax = rEax; // Set the right value of EAX to the saved context
+
+ //
+ // Copy context of process we stopped on to stack so we can free the
+ // memory later which was allocated in the other process to pass the
+ // context
+ //
+ RtlMoveMemory(&Context, pContext, sizeof(Context));
+
+ if (SigHandlerRec.signature == 0xdead) {
+
+ Od2MakeSignalHandlerContext(pa);
+
+ if (SigHandlerRec.sighandler[signum - 1] != 0 ) {
+ Od2JumpTo16SignalDispatch(SigHandlerRec.sighandler[signum - 1],
+ (ULONG) pa,
+ signum,
+ (ULONG) pa->usFlagArg);
+ }
+ }
+
+ size = 0;
+ address = (ULONG) pa;
+ Status = NtFreeVirtualMemory(NtCurrentProcess(),
+ (PVOID *) &address,
+ &size,
+ MEM_RELEASE);
+
+ ASSERT(NT_SUCCESS(Status));
+
+ Od2ExitFromSignalHandler(&Context, &SaveArea);
+}
+
+
+APIRET
+DosSetVec(
+ ULONG usVecNum,
+ PFN pfnFun,
+ PFN* ppfnPrev
+ )
+{
+ ULONG index;
+ PFN fn;
+
+ try {
+ fn = *ppfnPrev;
+ fn = pfnFun;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ switch (usVecNum) {
+ case VECTOR_DIVIDE_BY_ZERO:
+ index = 0;
+ break;
+ case VECTOR_OVERFLOW:
+ index = 1;
+ break;
+ case VECTOR_OUTOFBOUNDS:
+ index = 2;
+ break;
+ case VECTOR_INVALIDOPCODE:
+ index = 3;
+ break;
+ case VECTOR_NO_EXTENSION:
+ index = 4;
+ break;
+ case VECTOR_EXTENSION_ERROR:
+ index = 5;
+ break;
+ default:
+ return ERROR_INVALID_FUNCTION;
+ }
+ if (fn == 0) {
+ if (pVecHandlerRec->VecHandler[index] ==
+ (ULONG) (pVecHandlerRec->doscallssel | ThunkOffsetDosReturn)) {
+ *ppfnPrev = 0;
+ }
+ else {
+ *ppfnPrev = (PFN) pVecHandlerRec->VecHandler[index];
+ }
+ pVecHandlerRec->VecHandler[index] =
+ (ULONG) (pVecHandlerRec->doscallssel | ThunkOffsetDosReturn);
+ }
+ else {
+ if (pVecHandlerRec->VecHandler[index] ==
+ (ULONG) (pVecHandlerRec->doscallssel | ThunkOffsetDosReturn)) {
+ *ppfnPrev = 0;
+ }
+ else {
+ *ppfnPrev = (PFN) pVecHandlerRec->VecHandler[index];
+ }
+ pVecHandlerRec->VecHandler[index] = (ULONG)(FLATTOFARPTR((ULONG)(pfnFun)));
+ }
+
+ return NO_ERROR;
+
+}
+
+
+VOID
+Od2EnableCtrlHandling()
+
+{
+ OS2_API_MSG m;
+ POS2_REGISTER_HANDLER b = &m.u.DosRegisterCtrlHandler;
+
+ b->usFlagNum = 0;
+ b->fAction = SIGA_ENABLE_HANDLING;
+ Od2CallSubsystem(&m,
+ NULL,
+ Os2RegisterCtrlHandler,
+ sizeof( *b ));
+}
diff --git a/private/os2/client/dllsm.c b/private/os2/client/dllsm.c
new file mode 100644
index 000000000..f52d067ee
--- /dev/null
+++ b/private/os2/client/dllsm.c
@@ -0,0 +1,814 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllsm.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 Session Management API Calls
+
+Author:
+
+ Steve Wood (stevewo) 20-Sep-1989
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_SESSIONMGR
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_QUEUES
+#include "os2dll.h"
+#include "os2win.h"
+
+
+
+extern HANDLE hOs2Srv;
+
+VOID
+Od2CloseSrvHandle(
+ IN ULONG HandleNumber,
+ IN HANDLE Handle1,
+ IN HANDLE Handle2,
+ IN HANDLE Handle3
+ );
+
+VOID
+Od2PrepareStdHandleRedirection(
+ IN ULONG EnableFlags,
+ OUT POS2_STDHANDLES StdStruc
+ );
+
+VOID
+Od2CleanupStdHandleRedirection(
+ IN POS2_STDHANDLES StdStruc
+ );
+
+APIRET
+DosShutdown(
+ ULONG ulReserved
+ )
+{
+ UNREFERENCED_PARAMETER(ulReserved);
+ return( ERROR_INVALID_FUNCTION );
+}
+
+
+APIRET
+DosStartSession(
+ IN PSTARTDATA StartData,
+ OUT PULONG SessionId,
+ OUT PPID ProcessId
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSEXECPGM_MSG a = &m.u.DosStartSession.ExecPgmInformation;
+ POS2_DOSSTARTSESSION_INFO b = &m.u.DosStartSession.StartSessionInformation;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ APIRET rc;
+ PID whocares;
+ PSZ TmpObjectBuffer;
+ ULONG TmpObjectBuffLen, Length, Flags = EXEC_ASYNCRESULT;
+ ULONG PgmLength, ArgLength = 0;
+ ULONG dwProcessId;
+ USHORT TmpInheritOpt;
+ PSZ PgmInput = NULL;
+ PSZ PgmName = NULL;
+ PSZ VariablesBuffer, ArgumentsBuffer;
+ PSZ ExecFileName;
+ NTSTATUS Status, ExePgmFileType;
+#if PMNT
+ ULONG IsPMApp;
+#endif // PMNT
+ HANDLE hThread, hProcess, hRedirectedFile;
+ THREAD_BASIC_INFORMATION ThreadInfo;
+ OS2_STDHANDLES StdStruc;
+ BOOLEAN bSuccess;
+#if DBG
+ PSZ RoutineName = "DosStartSession";
+#endif
+
+ try
+ {
+ Od2ProbeForWrite((PVOID)ProcessId, sizeof(PID), 1);
+ Od2ProbeForWrite(SessionId, sizeof(ULONG), 1);
+ Length = StartData->Length;
+ Od2ProbeForRead(StartData, Length, 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+#if DBG
+ IF_OD2_DEBUG( SESSIONMGR )
+ {
+ DbgPrint("%s: Pgm %s\n", RoutineName, StartData->PgmName);
+ }
+#endif
+
+ if (Length < 18)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (Length > 50)
+ {
+ TmpObjectBuffer = StartData->ObjectBuffer;
+ TmpObjectBuffLen = StartData->ObjectBuffLen;
+ }
+ else
+ {
+ TmpObjectBuffer = (PSZ)NULL;
+ TmpObjectBuffLen = 0;
+ }
+
+ if (Length > 24)
+ {
+ TmpInheritOpt = StartData->InheritOpt;
+ } else
+ {
+ TmpInheritOpt = 0;
+ }
+
+ if( (StartData->PgmName != NULL) && (*(StartData->PgmName) != 0) )
+ {
+ PgmLength = strlen(StartData->PgmName);
+ if (StartData->PgmInputs != NULL)
+ {
+ ArgLength = strlen(StartData->PgmInputs);
+ }
+
+ PgmInput = (PSZ) RtlAllocateHeap( Od2Heap, 0, ArgLength + PgmLength + 2);
+ if (PgmInput == NULL)
+ {
+#if DBG
+ IF_OD2_DEBUG( SESSIONMGR )
+ {
+ DbgPrint("%s cannot Allocate storage for PgmInput", RoutineName );
+ }
+#endif
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ RtlMoveMemory(PgmInput, StartData->PgmName, PgmLength);
+ PgmInput[PgmLength++] = ' ';
+ if (StartData->PgmInputs != NULL)
+ {
+ RtlMoveMemory(PgmInput + PgmLength, StartData->PgmInputs, ArgLength );
+ }
+ PgmInput[PgmLength + ArgLength] = '\0';
+ }
+ else
+ {
+ //
+ // default is "CMD.EXE"
+ //
+ PgmLength = strlen("CMD.EXE");
+ if (StartData->PgmInputs != NULL)
+ {
+ ArgLength = strlen(StartData->PgmInputs);
+ }
+
+ PgmInput = (PSZ) RtlAllocateHeap( Od2Heap, 0, ArgLength + PgmLength + 2);
+ if (PgmInput == NULL)
+ {
+#if DBG
+ IF_OD2_DEBUG( SESSIONMGR )
+ {
+ DbgPrint("%s cannot Allocate storage for PgmInput", RoutineName );
+ }
+#endif
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ RtlMoveMemory(PgmInput, "CMD.EXE", PgmLength);
+ PgmInput[PgmLength++] = ' ';
+ if (StartData->PgmInputs != NULL)
+ {
+ RtlMoveMemory(PgmInput + PgmLength, StartData->PgmInputs, ArgLength );
+ }
+ PgmInput[PgmLength + ArgLength] = '\0';
+ PgmName = "CMD.EXE";
+ }
+
+ VariablesBuffer = (PSZ)StartData->Environment;
+ ArgumentsBuffer = (PgmInput) ? (PSZ)PgmInput : (PSZ)StartData->PgmInputs;
+ ExecFileName = PgmName ? PgmName : StartData->PgmName;
+
+ if (StartData->TraceOpt){
+ Flags = EXEC_TRACETREE;
+ }
+ rc = Od2FormatExecPgmMessage( a,
+ &CaptureBuffer,
+ &ExePgmFileType,
+#if PMNT
+ &IsPMApp,
+#endif // PMNT
+ TmpObjectBuffer,
+ TmpObjectBuffLen,
+ Flags | 0x80000000,
+ &VariablesBuffer,
+ &ArgumentsBuffer,
+ &ExecFileName
+ );
+
+ if (PgmInput != NULL)
+ {
+ RtlFreeHeap( Od2Heap, 0, PgmInput );
+ }
+
+ if (rc != NO_ERROR)
+ {
+#if DBG
+ IF_OD2_DEBUG( SESSIONMGR )
+ {
+ DbgPrint("%s cannot FormatParms (%lu) for %s\n", RoutineName, rc, StartData->PgmName);
+ }
+#endif
+ return( rc );
+ }
+
+ b->QueueHandleIndex = 0;
+ b->SessionType = (USHORT)((Length > 30 ) ? StartData->SessionType : 0);
+
+ if ( StartData->Related )
+ {
+
+ //
+ // if term queue supplied, then open the queue and pass handle
+ // to server.
+ //
+
+ if ( StartData->TermQ && (*(StartData->TermQ) != '\0'))
+ {
+
+ //
+ // YaronS: BUGBUG - the line below looks sloppy, because
+ // the QueueHandle that is opened is ignored - check later
+ //
+ rc = DosOpenQueue(&whocares,(PHQUEUE)(&b->QueueHandleIndex),StartData->TermQ);
+ if ( rc != NO_ERROR )
+ {
+ RtlFreeHeap( Od2Heap, 0, ArgumentsBuffer );
+ RtlFreeHeap( Od2Heap, 0, VariablesBuffer );
+ RtlFreeHeap( Od2Heap, 0, ExecFileName );
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ NtClose(a->hRedirectedFile);
+ return ERROR_QUE_NAME_NOT_EXIST;
+ }
+
+ b->QueueHandleIndex |= 0x80000000;
+ }
+ }
+
+ //
+ // we don't want to make a copy of the file handle table so we don't
+ // have to lock it during the call to the server because the file handles
+ // could go away while we're trying to dup them.
+ //
+
+ AcquireFileLockShared(
+#if DBG
+ RoutineName
+#endif
+ );
+
+ a->FileSystemParameters.ParentHandleTable = HandleTable;
+ a->FileSystemParameters.ParentTableLength = HandleTableLength;
+ a->FileSystemParameters.CurrentDrive = Od2CurrentDisk;
+
+ //
+ // Create the Process, and wait to os2srv to get the results
+ // back to us by calling DosExecPgm
+ //
+
+ // ExePgmFileType comes from the call to Od2IsFileConsoleType (returned by Od2FormatExecPgmMessage)
+
+ if ((ExePgmFileType == STATUS_INVALID_IMAGE_NE_FORMAT) ||
+ (ExePgmFileType == STATUS_INVALID_IMAGE_FORMAT))
+ {
+ ExePgmFileType = STATUS_INVALID_IMAGE_NE_FORMAT;
+ } else if ((ExePgmFileType != STATUS_OBJECT_NAME_NOT_FOUND) &&
+ (ExePgmFileType != STATUS_OBJECT_PATH_NOT_FOUND))
+ {
+#if DBG
+ DbgPrint( "OS2: Loading a Win 32-bit session - %s\n",
+ ExecFileName);
+#endif
+ Flags |= EXEC_WINDOW_PROGRAM; // This bit set the CREATE_NEW_PROCESS_GROUP and does redirection
+
+ // set up redirection
+
+ if (a->hRedirectedFile) {
+ Od2PrepareStdHandleRedirection(STDFLAG_IN | STDFLAG_ERR, &StdStruc);
+ StdStruc.StdOut = a->hRedirectedFile;
+ StdStruc.Flags |= STDFLAG_OUT;
+ } else if (a->CmdLineFlag & REDIR_NUL) {
+ Od2PrepareStdHandleRedirection(STDFLAG_IN | STDFLAG_ERR, &StdStruc);
+ if ((StdStruc.StdOut = Ow2GetNulDeviceHandle()) != NULL) {
+ StdStruc.Flags |= STDFLAG_OUT;
+ }
+ } else {
+ Od2PrepareStdHandleRedirection(STDFLAG_ALL, &StdStruc);
+ }
+
+ } else
+ {
+ if (ExePgmFileType == STATUS_OBJECT_NAME_NOT_FOUND)
+ {
+#if DBG
+ DbgPrint( "OS2(StartSession): EXE file not found - %s\n",
+ ExecFileName);
+#endif
+ rc = ERROR_FILE_NOT_FOUND;
+ } else if (ExePgmFileType == STATUS_OBJECT_PATH_NOT_FOUND)
+ {
+#if DBG
+ DbgPrint( "OS2(StartSession): Path to EXE file not found - %s\n",
+ ExecFileName);
+#endif
+ rc = ERROR_PATH_NOT_FOUND;
+ } else
+ {
+#if DBG
+ DbgPrint( "OS2(StartSession): Program can not be executed %s (%lx)\n",
+ ExecFileName, ExePgmFileType);
+#endif
+ rc = Or2MapNtStatusToOs2Error(ExePgmFileType, ERROR_INVALID_PARAMETER);
+ }
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ RtlFreeHeap( Od2Heap, 0, ArgumentsBuffer );
+ RtlFreeHeap( Od2Heap, 0, VariablesBuffer );
+ RtlFreeHeap( Od2Heap, 0, ExecFileName );
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ if (b->QueueHandleIndex)
+ {
+ DosCloseQueue((HQUEUE)(b->QueueHandleIndex & ~0x80000000));
+ }
+ return(rc);
+ }
+
+ rc = Ow2ExecPgm(
+ Flags,
+ ArgumentsBuffer,
+ VariablesBuffer,
+ ExecFileName,
+#if PMNT
+ IsPMApp,
+#endif // PMNT
+ StartData,
+ &StdStruc, // will do the redirection if Win32 program
+ &hProcess,
+ &hThread,
+ &dwProcessId
+ );
+
+ //
+ // clean up redir stuff
+ //
+
+ if ((Flags & EXEC_WINDOW_PROGRAM) &&
+ (StdStruc.Flags & STDFLAG_CLOSEALL)) {
+ Od2CleanupStdHandleRedirection(&StdStruc);
+ }
+
+ RtlFreeHeap( Od2Heap, 0, ArgumentsBuffer );
+ RtlFreeHeap( Od2Heap, 0, VariablesBuffer );
+ RtlFreeHeap( Od2Heap, 0, ExecFileName );
+
+ if (rc != NO_ERROR)
+ {
+#if DBG
+ DbgPrint("DosStartSession: error returned from Ow2ExecPgm %d\n", rc);
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ if (b->QueueHandleIndex)
+ {
+ DosCloseQueue((HQUEUE)(b->QueueHandleIndex & ~0x80000000));
+ }
+ NtClose(a->hRedirectedFile);
+ return(rc);
+ }
+
+ //
+ // 16 bit OS/2 program - Ow2execpgm creates it,
+ // Then we call os2srv to complete the job
+ //
+
+
+ if (((Flags & EXEC_WINDOW_PROGRAM) == 0) && a->hRedirectedFile)
+ {
+ hRedirectedFile = a->hRedirectedFile;
+
+ if(!DuplicateHandle(
+ GetCurrentProcess(),
+ a->hRedirectedFile,
+ hProcess,
+ &a->hRedirectedFile,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS
+ ))
+ {
+#if DBG
+ DbgPrint( "DoStartSessionm: fail to duplicate Redirecd File %d\n",GetLastError());
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ NtClose(hProcess);
+ NtClose(hThread);
+ NtClose(hRedirectedFile);
+ if (b->QueueHandleIndex)
+ {
+ DosCloseQueue((HQUEUE)(b->QueueHandleIndex & ~0x80000000));
+ }
+ return(ERROR_ACCESS_DENIED);
+ }
+ }
+
+ if (a->hRedirectedFile) {
+ NtClose(a->hRedirectedFile);
+ }
+
+ //
+ // duplicate process and thread handles for os2srv
+ //
+ bSuccess = DuplicateHandle(
+ GetCurrentProcess(),
+ hProcess,
+ hOs2Srv,
+ &(a->hProcess),
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS
+ );
+ NtClose(hProcess);
+ if (!bSuccess)
+ {
+#if DBG
+ DbgPrint( "DoStartSessionm: fail to duplicate process %d\n",GetLastError());
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ NtClose(hThread);
+ if (b->QueueHandleIndex)
+ {
+ DosCloseQueue((HQUEUE)(b->QueueHandleIndex & ~0x80000000));
+ }
+ return(ERROR_ACCESS_DENIED);
+ }
+ if (!DuplicateHandle(
+ GetCurrentProcess(),
+ hThread,
+ hOs2Srv,
+ &(a->hThread),
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS
+ ))
+ {
+#if DBG
+ DbgPrint( "DoStartSessionm: fail to duplicate Thread %d\n",GetLastError());
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ NtClose(hThread);
+ if (b->QueueHandleIndex)
+ {
+ DosCloseQueue((HQUEUE)(b->QueueHandleIndex & ~0x80000000));
+ }
+ Od2CloseSrvHandle(1, a->hProcess, NULL, NULL);
+ return(ERROR_ACCESS_DENIED);
+ }
+
+ Status = NtQueryInformationThread(hThread,
+ ThreadBasicInformation,
+ (PVOID)(&ThreadInfo),
+ sizeof(ThreadInfo),
+ NULL
+ );
+ NtClose(hThread);
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ DbgPrint( "DoStartSessionm: fail to Query Information %lx\n",Status);
+#endif
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ if (b->QueueHandleIndex)
+ {
+ DosCloseQueue((HQUEUE)(b->QueueHandleIndex & ~0x80000000));
+ }
+ Od2CloseSrvHandle(2, a->hProcess, a->hThread, NULL);
+ return(Or2MapNtStatusToOs2Error(
+ Status,ERROR_ACCESS_DENIED));
+ }
+
+ a->ClientId = ThreadInfo.ClientId;
+ a->Flags = Flags;
+
+ b->Related = StartData->Related;
+ b->WinSession = (ExePgmFileType == STATUS_INVALID_IMAGE_NE_FORMAT) ? FALSE : TRUE;
+ b->FgBg = (BOOLEAN)StartData->FgBg;
+ b->dwProcessId = dwProcessId;
+ Od2CallSubsystem( &m, CaptureBuffer, Os2StartSession, sizeof( OS2_DOSSTARTSESSION_MSG ) );
+
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if ( StartData->Related )
+ {
+ *ProcessId = a->ResultProcessId;
+ *SessionId = b->ResultSessionId;
+ }
+
+ //if (m.ReturnedErrorValue == NO_ERROR)
+ //{
+ // *ResultCodes = a->ResultCodes;
+ //}
+
+ if (a->ErrorText.Length != 0)
+ {
+ if (((ULONG)(a->ErrorText.Length)) < StartData->ObjectBuffLen)
+ {
+ StartData->ObjectBuffLen = (ULONG)a->ErrorText.Length;
+ } else
+ {
+ StartData->ObjectBuffLen -= 1;
+ }
+
+ RtlMoveMemory( StartData->ObjectBuffer, a->ErrorText.Buffer, StartData->ObjectBuffLen );
+ StartData->ObjectBuffer[ StartData->ObjectBuffLen ] = '\0';
+ }
+
+ Od2FreeCaptureBuffer( CaptureBuffer );
+
+#if DBG
+ IF_OD2_DEBUG( SESSIONMGR )
+ {
+ DbgPrint("%s complete (%lu) for %s, Session %lu, Process %lu\n",
+ RoutineName, m.ReturnedErrorValue, StartData->PgmName,
+ *SessionId, *ProcessId);
+ }
+#endif
+
+ return( m.ReturnedErrorValue );
+}
+
+
+APIRET
+DosSetSession(
+ IN ULONG SessionId,
+ IN PSTATUSDATA SessionStatusData
+ )
+{
+ OS2_API_MSG m;
+#if DBG
+ PSZ RoutineName = "DosSetSession";
+
+ IF_OD2_DEBUG( SESSIONMGR )
+ {
+ DbgPrint("%s: SessionId %lu, Select %u, Bond %u\n",
+ RoutineName, SessionId, SessionStatusData->SelectInd,
+ SessionStatusData->BondInd);
+ }
+#endif
+
+ try
+ {
+ Od2ProbeForRead(SessionStatusData, sizeof(STATUSDATA), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if ( SessionStatusData->Length != sizeof(STATUSDATA) )
+ {
+ return ERROR_SMG_INVALID_DATA_LENGTH;
+ }
+
+ if ( SessionStatusData->SelectInd > TARGET_NOT_SELECTABLE )
+ {
+ return ERROR_SMG_INVALID_SELECT_OPT;
+ }
+
+ if ( SessionStatusData->BondInd > BOND_NONE )
+ {
+ return ERROR_SMG_INVALID_BOND_OPTION;
+ }
+
+ m.u.DosSetSession.SessionId = SessionId;
+ m.u.DosSetSession.StatusData = *SessionStatusData;
+
+ Od2CallSubsystem( &m, NULL, Os2SetSession, sizeof( m.u.DosSetSession ) );
+#if DBG
+ IF_OD2_DEBUG( SESSIONMGR )
+ {
+ DbgPrint("%s complete (%lu) for Session %lu\n",
+ RoutineName, m.ReturnedErrorValue, SessionId);
+ }
+#endif
+ return( m.ReturnedErrorValue );
+}
+
+
+APIRET
+DosSelectSession(
+ IN ULONG SessionId,
+ IN ULONG ulReserved
+ )
+{
+ OS2_API_MSG m;
+#if DBG
+ PSZ RoutineName = "DosSelectSession";
+
+ IF_OD2_DEBUG( SESSIONMGR )
+ {
+ DbgPrint("%s: SessionId %lu, Reserved %lu\n",
+ RoutineName, SessionId, ulReserved);
+ }
+#endif
+ if (ulReserved)
+ {
+ return ERROR_SMG_BAD_RESERVE;
+ }
+
+ m.u.DosSelectSession.SessionId = SessionId;
+
+ Od2CallSubsystem( &m, NULL, Os2SelectSession, sizeof( m.u.DosSelectSession ) );
+#if DBG
+ IF_OD2_DEBUG( SESSIONMGR )
+ {
+ DbgPrint("%s complete (%lu) for Session %lu\n",
+ RoutineName, m.ReturnedErrorValue, SessionId);
+ }
+#endif
+ return( m.ReturnedErrorValue );
+}
+
+
+APIRET
+DosStopSession(
+ IN ULONG StopTarget,
+ IN ULONG SessionId,
+ IN ULONG ulReserved
+ )
+{
+ OS2_API_MSG m;
+#if DBG
+ PSZ RoutineName = "DosStopSession";
+
+ IF_OD2_DEBUG( SESSIONMGR )
+ {
+ DbgPrint("%s: SessionId %lu, Target %lu, Reserved %lu\n",
+ RoutineName, SessionId, StopTarget, ulReserved);
+ }
+#endif
+ if (ulReserved)
+ {
+ return ERROR_SMG_BAD_RESERVE;
+ }
+
+ if (( StopTarget != DSS_SESSION ) && ( StopTarget != DSS_ALL_SESSIONS ))
+ {
+ return ERROR_SMG_INVALID_STOP_OPTION;
+ }
+
+ m.u.DosStopSession.SessionId = SessionId;
+ m.u.DosStopSession.fScope = StopTarget;
+
+ Od2CallSubsystem( &m, NULL, Os2StopSession, sizeof( m.u.DosStopSession ) );
+#if DBG
+ IF_OD2_DEBUG( SESSIONMGR )
+ {
+ DbgPrint("%s complete (%lu) for Session %lu\n",
+ RoutineName, m.ReturnedErrorValue, SessionId);
+ }
+#endif
+ return( m.ReturnedErrorValue );
+}
+
+
+APIRET
+DosSMSetTitle(
+ IN PCHAR Title
+ )
+{
+ ULONG Length;
+ APIRET RetCode = 0;
+ //OS2_API_MSG m;
+ //POS2_CAPTURE_HEADER CaptureBuffer;
+#if DBG
+ PSZ RoutineName = "DosSMSetTitle";
+#endif
+
+#if DBG
+ IF_OD2_DEBUG( SESSIONMGR )
+ {
+ DbgPrint("%s: Title, %s\n", Title);
+ }
+#endif
+ try
+ {
+ Length = strlen(Title);
+ // Od2ProbeForRead(Title, Length, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ //if ((CaptureBuffer = Od2AllocateCaptureBuffer( 1, 0, Length )) == NULL)
+ //{
+ // return( ERROR_NOT_ENOUGH_MEMORY );
+ //}
+ //
+ //Od2CaptureMessageString( CaptureBuffer,
+ // Title,
+ // Length,
+ // Length,
+ // &m.u.DosSmSetTitle.Title);
+ //
+ //Od2CallSubsystem( &m, CaptureBuffer, Os2SmSetTitle, sizeof( m.u.DosSmSetTitle ) );
+ //
+ //Od2FreeCaptureBuffer( CaptureBuffer );
+ //
+ //RetCode = m.ReturnedErrorValue;
+
+ if(!SetConsoleTitleA(Title))
+ {
+ RetCode = GetLastError();
+ }
+
+#if DBG
+ IF_OD2_DEBUG( SESSIONMGR )
+ {
+ DbgPrint("%s complete (%lu)\n",
+ RoutineName, RetCode);
+ }
+#endif
+ return(RetCode);
+}
+
+/* DosSMPMPresent and WinSetTitleAndIcon are stub APIs */
+
+APIRET
+DosSMPMPresent(
+ OUT USHORT *Flag
+ )
+{
+ try
+ {
+ *Flag = 0;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+ return(NO_ERROR);
+}
+
+#ifndef PMNT
+APIRET
+WinSetTitleAndIcon(
+ IN PSZ szTitle,
+ IN PSZ szIconFilePath
+ )
+{
+ UNREFERENCED_PARAMETER(szTitle);
+ UNREFERENCED_PARAMETER(szIconFilePath);
+
+ return(NO_ERROR);
+}
+#endif
diff --git a/private/os2/client/dllsm16.c b/private/os2/client/dllsm16.c
new file mode 100644
index 000000000..34b96d11d
--- /dev/null
+++ b/private/os2/client/dllsm16.c
@@ -0,0 +1,107 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllsm16.c
+
+Abstract:
+
+ This module implements the OS/2 V1.x Session Management API Calls
+
+Author:
+
+ Beni Lavi (BeniL) 18-Dec-1991
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_SESSIONMGR
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+
+
+APIRET
+Dos16StartSession(
+ IN PSTARTDATA pStartData,
+ OUT PUSHORT pSessionId,
+ OUT PUSHORT pProcessId
+ )
+{
+ ULONG SessionId = 0;
+ USHORT Length;
+ PID ProcessId = 0;
+ APIRET rc;
+ STARTDATA StartData;
+
+ try
+ {
+ if (pProcessId != NULL)
+ {
+ Od2ProbeForWrite(pProcessId, sizeof(USHORT), 1);
+ ProcessId = (PID) *pProcessId;
+ }
+ if (pSessionId != NULL)
+ {
+ Od2ProbeForWrite(pSessionId, sizeof(USHORT), 1);
+ SessionId = (ULONG) *pSessionId;
+ }
+ Length = pStartData->Length;
+ Od2ProbeForRead(pStartData, Length, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if (Length > 50)
+ {
+ Length = 50; // BUGBUG: ERROR_ ...
+ }
+
+ RtlZeroMemory(&StartData, sizeof(STARTDATA));
+ RtlMoveMemory(&StartData, pStartData, Length);
+
+ StartData.Length = Length;
+
+ if ((Length > 8) && (StartData.PgmTitle != NULL))
+ {
+ StartData.PgmTitle = FARPTRTOFLAT(StartData.PgmTitle);
+ }
+ if ((Length > 12) && (StartData.PgmName != NULL))
+ {
+ StartData.PgmName = FARPTRTOFLAT(StartData.PgmName);
+ }
+ if ((Length > 16) && (StartData.PgmInputs != NULL))
+ {
+ StartData.PgmInputs = FARPTRTOFLAT(StartData.PgmInputs);
+ }
+ if ((Length > 20) && (StartData.TermQ != NULL))
+ {
+ StartData.TermQ = FARPTRTOFLAT(StartData.TermQ);
+ }
+ if ((Length > 24) && (StartData.Environment != NULL))
+ {
+ StartData.Environment = FARPTRTOFLAT(StartData.Environment);
+ }
+ if ((Length > 30) && (StartData.IconFile != NULL))
+ {
+ StartData.IconFile = FARPTRTOFLAT(StartData.IconFile);
+ }
+
+ rc = DosStartSession(&StartData, &SessionId, &ProcessId);
+
+ if (pProcessId != NULL)
+ {
+ *pProcessId = (USHORT) ProcessId;
+ }
+ if (pSessionId != NULL)
+ {
+ *pSessionId = (USHORT) SessionId;
+ }
+
+ return(rc);
+}
diff --git a/private/os2/client/dllsub16.c b/private/os2/client/dllsub16.c
new file mode 100644
index 000000000..e01eb5cba
--- /dev/null
+++ b/private/os2/client/dllsub16.c
@@ -0,0 +1,430 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllsub16.c
+
+Abstract:
+
+ This module implements the OS/2 V1.x DosSub* API calls.
+
+Author:
+
+ Beni Lavi (BeniL) 11-Dec-1991
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+
+#define MinPoolSize (sizeof(PoolHeader) + sizeof(BufferHeader))
+#define MaxPoolSize (0x10000 - MinPoolSize)
+
+#define RoundUp4Mask 0x3
+#define RoundUp4(x) (((x) + RoundUp4Mask) & ~RoundUp4Mask)
+
+#pragma pack(1)
+typedef struct _PoolHeader {
+ USHORT FirstFreeBuffer;
+ USHORT Undefined; /* not used in this implementation */
+ USHORT PoolSize;
+ USHORT ReferenceCount; /* value is set, but not used */
+} PoolHeader, *PPoolHeader;
+
+typedef struct _BufferHeader {
+ USHORT NextFreeBuffer;
+ USHORT BufferSize;
+} BufferHeader, *PBufferHeader;
+#pragma pack()
+
+
+//
+// Od2FindAdjacentLowerFreeBuffer
+//
+// Return a pointer to a free buffer whose upper free byte is adjacent
+// to a specified offset
+//
+PBufferHeader
+Od2FindAdjacentLowerFreeBuffer(
+ PPoolHeader PoolPtr,
+ USHORT OffsetOfNewBuffer
+ )
+{
+ PBufferHeader BufferPtr;
+ USHORT Offset;
+
+ Offset = PoolPtr->FirstFreeBuffer;
+ while (Offset != 0) {
+ BufferPtr = (PBufferHeader)((PCHAR)PoolPtr + Offset);
+ if (((USHORT)(Offset + BufferPtr->BufferSize)) == OffsetOfNewBuffer) {
+ return(BufferPtr);
+ }
+ else {
+ Offset = BufferPtr->NextFreeBuffer;
+ }
+ }
+ return(NULL);
+}
+
+
+//
+// Od2FindFreeBufferAtOffset
+//
+// Return a pointer to a buffer whose first free byte is at the
+// specified offset
+//
+PBufferHeader
+Od2FindFreeBufferAtOffset(
+ PPoolHeader PoolPtr,
+ USHORT OffsetOfBuffer
+ )
+{
+ PBufferHeader BufferPtr;
+ USHORT Offset;
+
+ Offset = PoolPtr->FirstFreeBuffer;
+ while (Offset != 0) {
+ BufferPtr = (PBufferHeader)((PCHAR)PoolPtr + Offset);
+ if (Offset == OffsetOfBuffer) {
+ return(BufferPtr);
+ }
+ else {
+ Offset = BufferPtr->NextFreeBuffer;
+ }
+ }
+ return(NULL);
+}
+
+
+//
+// Od2FindPreviousFreeBuffer
+//
+// Return a pointer to a free buffer which preceeds the specified buffer
+// in the free buffers chain. The returned pointer may point to the
+// pool header instead of a buffer header if the specified buffer was
+// first in the list.
+//
+PBufferHeader
+Od2FindPreviousFreeBuffer(
+ PPoolHeader PoolPtr,
+ PBufferHeader CurrentBufferPtr
+ )
+{
+ PBufferHeader BufferPtr;
+ USHORT Offset;
+
+ if ((PBufferHeader)((PCHAR)PoolPtr + PoolPtr->FirstFreeBuffer) == CurrentBufferPtr) {
+ return((PBufferHeader)PoolPtr);
+ }
+ Offset = PoolPtr->FirstFreeBuffer;
+ while (Offset != 0) {
+ BufferPtr = (PBufferHeader)((PCHAR)PoolPtr + Offset);
+ if ((PBufferHeader)((PCHAR)PoolPtr + BufferPtr->NextFreeBuffer) == CurrentBufferPtr) {
+ return(BufferPtr);
+ }
+ Offset = BufferPtr->NextFreeBuffer;
+ }
+ return(NULL); /* Should not arrive here */
+}
+
+
+//
+// Od2LocateBufferInPool
+//
+// Return a pointer to a free buffer in the free buffers list whose size
+// is big enough to satisfy the required size. This routine does not
+// allow for remained buffer peaces to be less than the free buffer
+// header since these peaces cannot be processes.
+//
+PBufferHeader
+Od2LocateBufferInPool(
+ PPoolHeader PoolPtr,
+ USHORT BufSize
+ )
+{
+ PBufferHeader BufferPtr;
+ USHORT Offset;
+
+ Offset = PoolPtr->FirstFreeBuffer;
+ while (Offset != 0) {
+ BufferPtr = (PBufferHeader)((PCHAR)PoolPtr + Offset);
+ //
+ // Return only buffers which are identical in size
+ // to the requested size, or buffers who are big enough
+ // to contain a free header strcture after the requested
+ // size is extracted.
+ //
+ if ((BufferPtr->BufferSize == BufSize) ||
+ (BufferPtr->BufferSize > (USHORT)(BufSize + (USHORT)sizeof(BufferHeader)))) {
+ return(BufferPtr);
+ }
+ Offset = BufferPtr->NextFreeBuffer;
+ }
+ return(NULL);
+}
+
+
+//
+// Od2RemoveFreeBufferFromList
+//
+// Remove a free buffer from the list of free buffers
+//
+VOID
+Od2RemoveFreeBufferFromList(
+ PPoolHeader PoolPtr,
+ PBufferHeader BufferPtr
+ )
+{
+ PBufferHeader PrevBufferPtr;
+
+ PrevBufferPtr = Od2FindPreviousFreeBuffer(PoolPtr, BufferPtr);
+ if (PrevBufferPtr == (PBufferHeader)PoolPtr) {
+ PoolPtr->FirstFreeBuffer = BufferPtr->NextFreeBuffer;
+ }
+ else {
+ PrevBufferPtr->NextFreeBuffer = BufferPtr->NextFreeBuffer;
+ }
+}
+
+
+APIRET
+Dos16SubSet (
+ IN SEL Sel,
+ IN USHORT fFlags,
+ IN USHORT Size
+ )
+{
+ ULONG PoolSize;
+ USHORT OldPoolSize;
+ USHORT NewBufferAddedSize;
+ USHORT NewBufferOffset;
+ PPoolHeader PoolPtr;
+ PBufferHeader FirstBufferPtr, NewBufferPtr, BufferPtr;
+ PVOID BaseAddress;
+
+ if (Size == 0) {
+ PoolSize = 0x10000;
+ }
+ else {
+ PoolSize = Size;
+ }
+
+ if (PoolSize < MinPoolSize) {
+ return(ERROR_DOSSUB_SHRINK);
+ }
+
+ if ((fFlags != 0) && (fFlags != 1)) {
+ return(ERROR_DOSSUB_BADFLAG);
+ }
+
+ PoolSize = RoundUp4(PoolSize);
+ BaseAddress = SELTOFLAT(Sel);
+ PoolPtr = (PPoolHeader)BaseAddress;
+
+ AcquireTaskLock();
+
+ if (fFlags == 1) {
+ PoolPtr->FirstFreeBuffer = sizeof(PoolHeader);
+ PoolPtr->Undefined = 0;
+ PoolPtr->PoolSize = (USHORT)PoolSize - (USHORT)sizeof(PoolHeader);
+ PoolPtr->ReferenceCount = 0;
+
+ FirstBufferPtr = (PBufferHeader)((PCHAR)BaseAddress + sizeof(PoolHeader));
+ FirstBufferPtr->NextFreeBuffer = 0; /* end of list */
+ FirstBufferPtr->BufferSize = (USHORT)(PoolSize - sizeof(PoolHeader));
+ }
+ else /* fFlags == 0 */ {
+ OldPoolSize = PoolPtr->PoolSize + (USHORT)sizeof(PoolHeader);
+ if ((USHORT)PoolSize < OldPoolSize) {
+ ReleaseTaskLock();
+ return(ERROR_DOSSUB_SHRINK);
+ }
+ if ((OldPoolSize - (USHORT)PoolSize) < sizeof(BufferHeader)) {
+ ReleaseTaskLock();
+ return(ERROR_DOSSUB_BADSIZE);
+ }
+
+ NewBufferAddedSize = (USHORT)PoolSize - OldPoolSize;
+ NewBufferOffset = OldPoolSize;
+ NewBufferPtr = (PBufferHeader)((PCHAR)BaseAddress + NewBufferOffset);
+
+ BufferPtr = Od2FindAdjacentLowerFreeBuffer(
+ PoolPtr, NewBufferOffset);
+ if (BufferPtr == NULL) {
+ NewBufferPtr->NextFreeBuffer = PoolPtr->FirstFreeBuffer;
+ NewBufferPtr->BufferSize = NewBufferAddedSize;
+ PoolPtr->FirstFreeBuffer = NewBufferOffset;
+ }
+ else {
+ BufferPtr->BufferSize += NewBufferAddedSize;
+ }
+ PoolPtr->PoolSize += NewBufferAddedSize;
+
+ }
+
+ ReleaseTaskLock();
+
+ return(NO_ERROR);
+}
+
+APIRET
+Dos16SubFree (
+ IN SEL Sel,
+ IN USHORT offBlock,
+ IN USHORT cbBlock
+ )
+{
+ PPoolHeader PoolPtr;
+ PBufferHeader BufferPtr;
+ PBufferHeader PrevBufferPtr;
+ PBufferHeader CurrentBufferPtr;
+ USHORT BufferSize;
+ PVOID BaseAddress;
+ ULONG BufSize;
+ USHORT Offset;
+
+ if (cbBlock == 0) {
+ return(ERROR_DOSSUB_BADSIZE);
+ }
+
+ BufSize = RoundUp4(cbBlock);
+ if (BufSize > MaxPoolSize) {
+ return(ERROR_DOSSUB_BADSIZE);
+ }
+
+ BaseAddress = SELTOFLAT(Sel);
+ PoolPtr = (PPoolHeader)BaseAddress;
+ CurrentBufferPtr = (PBufferHeader)((PCHAR)BaseAddress + offBlock);
+
+ AcquireTaskLock();
+
+ //
+ // Verify that we are freeing a non overlapping section
+ //
+ if (((offBlock + BufSize) > (PoolPtr->PoolSize + sizeof(PoolHeader))) ||
+ (offBlock < sizeof(PoolHeader))
+ ) {
+ ReleaseTaskLock();
+ return(ERROR_DOSSUB_OVERLAP);
+ }
+ //
+ // loop over all free buffers and verify that the freed buffer is
+ // not contained within any of them
+ //
+ Offset = PoolPtr->FirstFreeBuffer;
+ while (Offset != 0) {
+ BufferPtr = (PBufferHeader)((PCHAR)PoolPtr + Offset);
+ if (((offBlock >= Offset) && (offBlock < (Offset + BufferPtr->BufferSize))) ||
+ ((Offset >= offBlock) && (Offset < (offBlock + BufSize)))
+ ) {
+ ReleaseTaskLock();
+ return(ERROR_DOSSUB_OVERLAP);
+ }
+ Offset = BufferPtr->NextFreeBuffer;
+ }
+
+ if ((BufferPtr = Od2FindAdjacentLowerFreeBuffer(PoolPtr, offBlock)) != NULL) {
+ BufferPtr->BufferSize += (USHORT)BufSize;
+ CurrentBufferPtr = BufferPtr;
+ //
+ // Try to merge the new free buffer with a free buffer which
+ // is adjacent in higher address.
+ //
+ if ((BufferPtr = Od2FindFreeBufferAtOffset(PoolPtr,
+ (USHORT)(((PCHAR)CurrentBufferPtr - (PCHAR)PoolPtr) + CurrentBufferPtr->BufferSize))) != NULL) {
+ BufferSize = BufferPtr->BufferSize;
+ Od2RemoveFreeBufferFromList(PoolPtr, BufferPtr);
+ CurrentBufferPtr->BufferSize += BufferSize;
+ }
+ }
+ else if ((BufferPtr = Od2FindFreeBufferAtOffset(PoolPtr, (USHORT)(offBlock + BufSize))) != NULL) {
+ PrevBufferPtr = Od2FindPreviousFreeBuffer(PoolPtr, BufferPtr);
+ if (PrevBufferPtr == (PBufferHeader)PoolPtr) {
+ PoolPtr->FirstFreeBuffer = offBlock;
+ CurrentBufferPtr->BufferSize = (USHORT)(BufSize + BufferPtr->BufferSize);
+ }
+ else {
+ PrevBufferPtr->NextFreeBuffer = offBlock;
+ CurrentBufferPtr->BufferSize = (USHORT)(BufSize + BufferPtr->BufferSize);
+ }
+ CurrentBufferPtr->NextFreeBuffer = BufferPtr->NextFreeBuffer;
+ }
+ else {
+ CurrentBufferPtr->NextFreeBuffer = PoolPtr->FirstFreeBuffer;
+ CurrentBufferPtr->BufferSize = (USHORT)BufSize;
+ PoolPtr->FirstFreeBuffer = offBlock;
+ }
+
+ ReleaseTaskLock();
+
+ PoolPtr->ReferenceCount++;
+ return(NO_ERROR);
+}
+
+
+APIRET
+Dos16SubAlloc (
+ IN SEL Sel,
+ OUT PUSHORT pusOffset,
+ IN USHORT cbBlock
+ )
+{
+ ULONG BufSize;
+ USHORT NewBufferOffset;
+ PPoolHeader PoolPtr;
+ PBufferHeader NewBufferPtr;
+ PBufferHeader BufferPtr;
+ PVOID BaseAddress;
+
+ if (cbBlock == 0) {
+ return(ERROR_DOSSUB_BADSIZE);
+ }
+
+ BufSize = RoundUp4(cbBlock);
+ if ((BufSize < sizeof(BufferHeader)) || (BufSize > MaxPoolSize)) {
+ return(ERROR_DOSSUB_BADSIZE);
+ }
+
+ try {
+ *pusOffset = 0;
+ }
+ except (EXCEPTION_EXECUTE_HANDLER) {
+ Od2ExitGP();
+ }
+
+ BaseAddress = SELTOFLAT(Sel);
+ PoolPtr = (PPoolHeader)BaseAddress;
+
+ AcquireTaskLock();
+
+ BufferPtr = Od2LocateBufferInPool(PoolPtr, (USHORT)BufSize);
+ if (BufferPtr == NULL) {
+ ReleaseTaskLock();
+ return(ERROR_DOSSUB_NOMEM);
+ }
+
+ if (BufferPtr->BufferSize == (USHORT)BufSize) {
+ Od2RemoveFreeBufferFromList(PoolPtr, BufferPtr);
+ NewBufferOffset = (USHORT)((PCHAR)BufferPtr - (PCHAR)PoolPtr);
+ }
+ else {
+ NewBufferPtr =
+ (PBufferHeader)((PCHAR)BufferPtr + BufferPtr->BufferSize - BufSize);
+ NewBufferOffset = (USHORT)((PCHAR)NewBufferPtr - (PCHAR)PoolPtr);
+ BufferPtr->BufferSize -= (USHORT)BufSize;
+ }
+
+ ReleaseTaskLock();
+
+ *pusOffset = NewBufferOffset;
+ PoolPtr->ReferenceCount++;
+
+ return(NO_ERROR);
+}
+
diff --git a/private/os2/client/dlltask.c b/private/os2/client/dlltask.c
new file mode 100644
index 000000000..3dd14f04e
--- /dev/null
+++ b/private/os2/client/dlltask.c
@@ -0,0 +1,5965 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dlltask.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 Tasking API Calls
+
+Author:
+
+ Steve Wood (stevewo) 20-Sep-1989 (Adapted from URTL\alloc.c)
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "os2win.h"
+#include "conrqust.h"
+#include <mi.h>
+#include <ldrxport.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#if PMNT
+#define INCL_32BIT
+#include "pmnt.h"
+#endif
+
+#ifdef DBCS
+// MSKK Apr.19.1993 V-AkihiS
+//
+// OS/2 internal multibyte string function.
+//
+#include "dlldbcs.h"
+#define strstr Od2MultiByteStrstr
+#endif
+
+extern PSZ Od216ApiTable[1];
+extern ULONG Od2SessionNumber;
+extern ULONG timing;
+extern ULONG Od2DosExitIsDone;
+extern ULONG Od2Saved16Stack;
+extern HANDLE Od2SyncSem;
+extern HANDLE Od2GarbageCollectSem;
+
+BOOLEAN Od2NeedToResumeThreads = FALSE;
+HANDLE Od2CritSecEvent;
+HANDLE Od2NewThreadSync;
+BOOLEAN Od2NewThreadDisabled = FALSE;
+
+VOID
+Od2JumpTo16ExitRoutine(
+ PFNEXITLIST ExitRoutine,
+ ULONG ExitReason);
+
+VOID
+Od2CloseSrvHandle(
+ IN ULONG HandleNumber,
+ IN HANDLE Handle1,
+ IN HANDLE Handle2,
+ IN HANDLE Handle3
+ );
+
+extern VOID __cdecl RestoreTebForThread1();
+extern VOID __cdecl MoveInfoSegintoTeb();
+extern VOID __cdecl RestoreTeb();
+
+extern PVOID __cdecl Od2JumpTo16SignalDispatch(ULONG address, ULONG regs,
+ ULONG usFlagNum, ULONG usFlagArg);
+
+VOID
+Od2JumpTo16SignalDispatchBorder(VOID);
+
+VOID
+Od2JumpTo16SignalDispatchEnd(VOID);
+
+VOID
+ExitFlatAreaBegin(VOID);
+
+VOID
+ExitFlatAreaEnd(VOID);
+
+VOID
+Od2ContinueStartBorder(VOID);
+
+VOID
+Od2ContinueEndBorder(VOID);
+
+VOID
+Od2SetSegmentRegisters(VOID);
+
+VOID
+Od2SetSegmentRegistersEnd(VOID);
+
+VOID
+SaveFSSeg(
+ LOCALINFOSEG* pTebBlock
+ );
+
+VOID
+RestoreFSSeg(
+ LOCALINFOSEG* pTebBlock
+ );
+
+VOID
+Od2Continue(PVOID pContext);
+
+APIRET
+SearchForPath(
+ IN ULONG SearchFlags,
+ IN PSZ PathName,
+ OUT PBYTE Buffer,
+ IN ULONG Length
+ );
+
+VOID
+Od2CloseAllTimers( VOID );
+
+
+VOID
+Od2CloseAllRAMSharedSemaphores( VOID );
+
+VOID
+Od2ExitListDispatcher( VOID );
+
+VOID
+Od2InfiniteSleep( VOID );
+
+VOID
+Ow2Exit(
+ IN ULONG StringCode,
+ IN PCHAR ErrorText,
+ IN ULONG ExitCode
+ );
+
+VOID
+Od2FinalProcessCleanup( VOID );
+
+BOOLEAN
+ldtCreateSelBitmap();
+
+NTSTATUS
+Od2AlertableWaitForSingleObject(
+ IN HANDLE handle
+ );
+
+NTSTATUS
+Od2AcquireMutant(
+ IN HANDLE handle
+ );
+
+NTSTATUS
+Od2ReleaseMutant(
+ IN HANDLE handle
+ );
+
+VOID
+Od2WaitOnCritSectOrSuspend(VOID);
+
+static CHAR ConfigSysString[] = "CONFIG.SYS";
+
+#define BLANK(ch) ((ch) == ' ' || (ch) == '\t')
+#define SEPARATOR(ch) (BLANK(ch) || (ch) == '"' || (ch) == '(' || (ch) == ')' || \
+ (ch) == '>' || (ch) == '<' || (ch) == '|' || (ch) == '&' || (ch) == '\0')
+
+extern ULONG Od2Start16Stack;
+extern ULONG Od2Start16DS;
+
+extern PSZ Od2ExecPgmErrorText;
+extern ULONG Od2ExecPgmErrorTextLength;
+
+extern HANDLE CtrlDataSemaphore;
+extern HANDLE hOs2Srv;
+
+extern HANDLE Od2SyncSem;
+extern HANDLE Od2GarbageCollectSem;
+
+#define NUMOF32ASYNCPROC 50
+
+struct
+{
+ HANDLE hProcess;
+ ULONG dwProcessId;
+ BOOLEAN CreateSync;
+} Od2AsyncProc[NUMOF32ASYNCPROC];
+
+ULONG Od2CritSectCounter = 0;
+ULONG Od2CritSectOwner = 0;
+BOOLEAN Od2SigHandAlreadyInProgress = FALSE;
+
+#pragma pack (1)
+typedef struct _PHARLAP_CONFIG {
+ UCHAR uchCopyRight[0x32];
+ USHORT usType;
+ USHORT usRsv1;
+ USHORT usRsv2;
+ USHORT usSign;
+} CONFIGPHARLAP, *PCONFIGPHARLAP;
+#pragma pack ()
+
+NTSTATUS
+AcquireTaskLock( VOID )
+{
+ if ((!Od2SigHandlingInProgress) || ((Od2CurrentThreadId()) != 1))
+ return Od2AcquireMutant(Od2Process->TaskLock);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+ReleaseTaskLock( VOID )
+{
+ if ((!Od2SigHandlingInProgress) || ((Od2CurrentThreadId()) != 1))
+ return Od2ReleaseMutant(Od2Process->TaskLock);
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+Od2InitializeTask( VOID )
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ Od2Process = RtlAllocateHeap( Od2Heap, 0, sizeof( *Od2Process ) );
+ ASSERT( Od2Process != NULL );
+ if (Od2Process == NULL) {
+ return(STATUS_NO_MEMORY);
+ }
+
+ RtlZeroMemory( Od2Process, sizeof( *Od2Process ) );
+
+ Status = NtCreateMutant(
+ &Od2Process->TaskLock,
+ MUTANT_ALL_ACCESS,
+ NULL,
+ FALSE);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("Od2InitSem: error at NtopenSemaphore, Status %x\n", Status);
+ }
+#endif
+ }
+ ASSERT( NT_SUCCESS( Status ) );
+ if (!NT_SUCCESS( Status )) {
+ return(Status);
+ }
+
+ RtlInitializeResource( &Od2Process->FileLock );
+
+ InitializeListHead( &Od2Process->ThreadList );
+ InitializeListHead( &Od2Process->ExitList );
+ InitializeListHead( &Od2Process->MsgFileList );
+
+ Od2Thread1 = RtlAllocateHeap( Od2Heap, 0, sizeof( *Od2Thread1 ) );
+ ASSERT( Od2Thread1 != NULL );
+ if (Od2Thread1 == NULL) {
+ return(STATUS_NO_MEMORY);
+ }
+
+ RtlZeroMemory( Od2Thread1, sizeof( *Od2Thread1 ) );
+ //
+ // Create event that will be used by DosSuspendThread and
+ // DosEnterCritSect APIs.
+ //
+ Status = NtCreateEvent(
+ &(Od2Thread1->Event),
+ EVENT_ALL_ACCESS,
+ NULL,
+ NotificationEvent,
+ FALSE);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("Od2InitializeTask fail to create thread event, status=%x\n",
+ Status);
+ ASSERT(FALSE);
+#endif // DBG
+ RtlFreeHeap(Od2Heap, 0, Od2Thread1);
+ return( STATUS_NO_MEMORY );
+ }
+
+ InsertTailList( &Od2Process->ThreadList, &Od2Thread1->Link );
+ //
+ // Duplicate our own thread handle for later suspension in critsec
+ //
+ if (!DuplicateHandle(
+ GetCurrentProcess(),
+ GetCurrentThread(),
+ GetCurrentProcess(),
+ &Od2Thread1->ThreadHandle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS
+ )){
+#if DBG
+ KdPrint(( "Od2InitializeTask: fail to duplicate thread %d\n",GetLastError()));
+#endif
+ return( STATUS_ACCESS_DENIED);
+ }
+
+ if (!ldtCreateSelBitmap()) {
+ return(STATUS_NO_MEMORY);
+ }
+ //
+ // Create an Nt event to be used for
+ // syncronization between a thread calling DosExitCritSec and
+ // threads that were in 32 bit api code when DosEnterCritSec was called
+ //
+ Status = NtCreateEvent(
+ &Od2CritSecEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ NotificationEvent,
+ FALSE);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("Od2InitSem: error at NtCreateSemaphore, Status %x\n", Status);
+ }
+#endif
+ }
+
+ // Mutant that will be used for new thread sincronzation with process
+ // termination.
+
+ Status = NtCreateMutant(
+ &Od2NewThreadSync,
+ MUTANT_ALL_ACCESS,
+ NULL,
+ FALSE);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("Od2InitializeTask: Fail to create mutant, Status=%x\n",
+ Status);
+#endif // DBG
+ }
+
+ return( STATUS_SUCCESS );
+}
+
+// Terminate thread if something goes wrong. Used during sturtup only from
+// Od2RegisterThread.
+
+VOID
+Od2AbortThread(
+ IN POD2_THREAD Thread
+ )
+{
+ NTSTATUS Status;
+
+ Status = NtReleaseMutant(Od2NewThreadSync, NULL);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("Od2AbortThread: Release NewThreadSync, Status=%x\n",
+ Status);
+ }
+#endif //DBG
+ NtClose(Thread->ThreadHandle);
+ RtlFreeHeap(Od2Heap, 0, Thread);
+ ExitThread(0);
+}
+
+// Call subsystem to register the new thread. But don't do anything in the case
+// that the process is going to terminate. For this reasone use the mutant
+// Od2NewThreadSync to syncronize with exit list processing. Before exit list
+// processing the flag Od2NewThreadDisabled will be set indicating that new thread
+// can't be created.
+
+NTSTATUS
+Od2RegisterThread(
+ IN POD2_THREAD Thread
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSCREATETHREAD_MSG a = &m.u.DosCreateThread;
+ THREAD_BASIC_INFORMATION ThreadInfo;
+ NTSTATUS Status;
+
+ Status = Od2AlertableWaitForSingleObject(Od2NewThreadSync);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("Od2RegisterThread: Wait for NewThreadSync, Status=%x\n",
+ Status);
+ }
+#endif // DBG
+
+ // If process is going to terminate, don't do anything, terminate yourself.
+ if (Od2NewThreadDisabled) {
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("Od2RegisterThread: No new threads\n");
+ }
+#endif //DBG
+ Od2AbortThread(Thread);
+ }
+
+ a->Flags = Thread->Flags;
+ a->ClientOs2Tib = &Thread->Os2Tib;
+
+ if (!DuplicateHandle(
+ GetCurrentProcess(),
+ GetCurrentThread(),
+ hOs2Srv,
+ &a->ThreadHandle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS
+ )){
+ ASSERT(FALSE);
+ Thread->rc = ERROR_ACCESS_DENIED;
+ Od2AbortThread(Thread);
+ }
+
+ Status = NtQueryInformationThread(GetCurrentThread(),
+ ThreadBasicInformation,
+ (PVOID)(&ThreadInfo),
+ sizeof(ThreadInfo),
+ NULL
+ );
+ if (!NT_SUCCESS(Status)){
+#if DBG
+ KdPrint(( "Od2RegisterThread: fail to Query Information %lx\n",Status));
+#endif
+ Thread->rc = Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED);
+ Od2CloseSrvHandle(1, a->ThreadHandle, NULL, NULL);
+ Od2AbortThread(Thread);
+ }
+
+ a->ClientId = ThreadInfo.ClientId;
+
+ Od2CallSubsystem( &m, NULL, Os2CreateThread, sizeof( *a ) );
+
+ if( Thread->rc = m.ReturnedErrorValue ) {
+ // If the return value is ERROR_INVALID_FUNCTION, thats means that the
+ // server perform exit processing for this process. It will know to close
+ // the handle.
+ if (Thread->rc != ERROR_INVALID_FUNCTION) {
+#if DBG
+ KdPrint(( "Od2RegisterThread: OS2Srv error return value %ld\n",m.ReturnedErrorValue));
+#endif // DBG
+ Od2CloseSrvHandle(1, a->ThreadHandle, NULL, NULL);
+ }
+ Od2AbortThread(Thread);
+ }
+
+ Status = NtReleaseMutant(Od2NewThreadSync, NULL);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("Od2RegisterThread: Release NewThreadSync, Status=%x\n",
+ Status);
+ }
+#endif //DBG
+
+ // The thread is known by the server.
+
+ AcquireTaskLock();
+ InsertTailList( &Od2Process->ThreadList, &Thread->Link );
+ ReleaseTaskLock();
+
+#if PMNT
+ // Force all PM threads to run on processor#1. Otherwise, PM Desktop
+ // locks-up
+ if (ProcessIsPMProcess())
+ {
+ DWORD Ret;
+
+ Ret = SetThreadAffinityMask(
+ GetCurrentThread(),
+ 0x1);
+#if DBG
+ if (Ret == 0)
+ {
+ DbgPrint("Od2RegisterThread: failed to SetThreadAffinityMask\n");
+ }
+ else if (Ret != 1)
+ {
+ DbgPrint("Od2RegisterThread: SetThreadAffinityMask returned %x (now set to 1)\n",
+ Ret);
+ }
+#endif // DBG
+ }
+#endif //PMNT
+
+ // Tell the thread that created us, that we are all right. Thread that called
+ // DosCreateThread will continue execution.
+
+ Status = NtSetEvent(Thread->Event, NULL);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("Od2RegisterThread: fail to set startup event, Status=%x\n",
+ Status);
+ ASSERT(FALSE);
+ }
+#endif // DBG
+
+ if ((Thread->Flags & DCT_SUSPENDED) != 0) {
+ // Suspend myself.
+ DosSuspendThread((TID)(Thread->Os2Tib.ThreadId));
+ }
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+Od2InitializeThread(
+ IN POD2_THREAD Thread
+ )
+{
+ PTEB Teb;
+ LINFOSEG *pLocalInfo;
+ ldrrei_t *pexecinfo;
+ NT_TIB *NtTib;
+
+ Teb = NtCurrentTeb();
+ Teb->EnvironmentPointer = (PVOID)Thread;
+ NtTib = &Teb->NtTib;
+
+ //
+ // Set Local Information Fields
+ //
+ pLocalInfo = (LINFOSEG *) &(Thread->Os2Tib.LInfoSeg),
+ pLocalInfo->pidCurrent = (USHORT)(Od2Process->Pib.ProcessId);
+ pLocalInfo->pidParent = (USHORT)(Od2Process->Pib.ParentProcessId);
+ pLocalInfo->prtyCurrent = (USHORT)(((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Os2Tib.Priority);
+#ifndef PMNT
+ pLocalInfo->sgCurrent = (USHORT)Od2SessionNumber; // What's a more appropriate value?
+#endif
+ pLocalInfo->rfProcStatus = 0; // What's a more appropriate value?
+ pLocalInfo->fForeground = TRUE;
+#ifndef PMNT
+ pLocalInfo->typeProcess = 0; // BUGBUG - BRIEF3.1 for Beta 1 YS. PT_WINDOWABLEVIO; // meaning windowed, protected mode
+#endif
+
+ if (Thread->Os2Tib.ThreadId != 1) {
+#ifdef PMNT
+ // we do not know whether a process is a PM Process
+ // until loading terminates
+ // 1st thread fields are determined in Od2UpdateLocalInfoAtStart()
+ // Note: PMSHELL has typeProcess & sgCurrent of a PM Process under PM\NT,
+ // but not under OS2 native
+ if (ProcessIsPMProcess()) {
+ pLocalInfo->sgCurrent = (USHORT)(32 + Od2SessionNumber); //PQ - see PMWIN\wininit1.c, this is SGID_PM
+ // and all PM processes have a session number
+ // above or equal to this number
+ pLocalInfo->typeProcess = 3; // Indicates a PM process
+ }
+ else {
+ pLocalInfo->sgCurrent = (USHORT)Od2SessionNumber; // What's a more appropriate value?
+ pLocalInfo->typeProcess = 0; // BUGBUG - BRIEF3.1 for Beta 1 YS. PT_WINDOWABLEVIO; // meaning windowed, protected mode
+ }
+#endif
+ pexecinfo = (PVOID) LDRExecInfo;
+ pLocalInfo->selEnvironment = pexecinfo->ei_envsel;
+ pLocalInfo->offCmdLine = pexecinfo->ei_comoff;
+ pLocalInfo->cbDataSegment = pexecinfo->ei_dgroupsize;
+ pLocalInfo->cbStack = pexecinfo->ei_stacksize;
+ pLocalInfo->cbHeap = pexecinfo->ei_heapsize;
+ pLocalInfo->hmod = pexecinfo->ei_hmod;
+ pLocalInfo->selDS = pexecinfo->ei_ds;
+ pLocalInfo->tidCurrent = (USHORT)(Od2CurrentThreadId());
+ Thread->Os2Tib.LInfoSeg.IsRealTEB = 0;
+ }
+
+ Thread->Os2Tib.LInfoSeg.tebptr = (ULONG)&(Thread->Os2Tib.TebBackupIn16Bit);
+
+ return( STATUS_SUCCESS );
+}
+
+
+VOID
+Od2UserThreadStartup(
+ IN POD2_THREAD Thread
+ )
+{
+ try {
+ Od2RegisterThread(Thread);
+ Od2InitializeThread( Thread );
+ DosExit( EXIT_THREAD, (*Thread->StartAddress)( Thread->Parameter ) );
+ }
+ //
+ // if Os2Debug is on, and ntsd is attached, it will get the second chance
+ //
+#if DBG
+ except( (Os2Debug ? Ow2FaultFilter(EXCEPTION_CONTINUE_SEARCH, GetExceptionInformation()):
+
+ Ow2FaultFilter(EXCEPTION_EXECUTE_HANDLER, GetExceptionInformation())) ) {
+#else
+ except( Ow2FaultFilter(EXCEPTION_EXECUTE_HANDLER, GetExceptionInformation()) ) {
+#endif
+#if DBG
+ KdPrint(("OS2: Internal error - Exception occured in 32bit os2ss code\n"));
+#endif
+ DosEnterCritSec();
+ Ow2DisplayExceptionInfo();
+
+ DosExit(EXIT_PROCESS, 13);
+ }
+ //
+ // If DosExit fails, then force an exception.
+ //
+
+#if DBG
+ KdPrint(( "OS2DLL: DosExit failed, about to generate a fault\n" ));
+ DbgBreakPoint();
+#endif
+}
+
+POD2_THREAD
+Od2FindOd2Thread(
+ POD2_THREAD refThread
+ )
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POD2_THREAD Thread;
+
+ ListHead = &Od2Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OD2_THREAD, Link );
+ if (Thread == refThread)
+ break;
+ ListNext = ListNext->Flink;
+ }
+ if (Thread != refThread) {
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d] Od2FindOd2Thread(#%x) - invalid thread\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ refThread);
+ }
+#endif // DBG
+ return NULL;
+ }
+ return Thread;
+}
+
+
+APIRET
+DosCreateThread(
+ OUT PTID ThreadId,
+ IN PFNTHREAD StartAddress,
+ IN ULONG Parameter,
+ IN ULONG Flags,
+ IN ULONG StackSize
+ )
+{
+ POD2_THREAD Thread;
+ ULONG Tid;
+ NTSTATUS Status;
+ APIRET rc;
+
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ KdPrint(("entering DosCreateThread\n"));
+ }
+#endif
+ StackSize = ROUND_UP_TO_PAGES( StackSize );
+#ifdef PMNT
+ if (StackSize == 0 || Flags & ~(DCT_SUSPENDED | DCT_RUNABLE_HIDDEN)) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+#else
+ if (StackSize == 0 || Flags & ~DCT_SUSPENDED) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+#endif
+
+ //
+ // probe parms
+ //
+
+ try {
+ Od2ProbeForWrite( (PVOID)ThreadId, sizeof( PTID ), 1 );
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (Od2Process->Pib.Status & PS_EXITLIST) {
+ return( ERROR_INVALID_FUNCTION );
+ }
+
+ Thread = RtlAllocateHeap( Od2Heap, 0, sizeof( *Thread ) );
+ if (!Thread) {
+#if DBG
+ KdPrint(("OS2: DosCreateThread out of heap memory, fail\n"));
+#endif
+ ASSERT( FALSE );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Create event that will notify to DosCreateThread that the thread was created.
+ // After it will be used by DosSuspendThread. The handle to this event will be
+ // closed upon DosExit with EXIT_THREAD parameter.
+ Status = NtCreateEvent(
+ &(Thread->Event),
+ EVENT_ALL_ACCESS,
+ NULL,
+ NotificationEvent,
+ FALSE);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("DosCreateThread fail to create thread event, status=%x\n",
+ Status);
+ ASSERT(FALSE);
+#endif // DBG
+ RtlFreeHeap(Od2Heap, 0, Thread);
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ Thread->StartAddress = StartAddress;
+ Thread->Parameter = Parameter;
+ Thread->Os2Tib.MustCompleteForceFlag = 0;
+ Thread->Flags = Flags;
+
+ Thread->ThreadHandle = CreateThread( NULL,
+ StackSize,
+ (PFNTHREAD)Od2UserThreadStartup,
+ (PVOID)Thread,
+ 0, // Create thread not suspended
+ &Tid);
+ if (!(Thread->ThreadHandle)){
+#if DBG
+ KdPrint(("DosCreateThread - fail at win32 CreateThread, %d\n",GetLastError()));
+#endif
+ RtlFreeHeap(Od2Heap, 0, Thread);
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ // Wait for notification from the thread that it has been initialized
+ Status = Od2AlertableWaitForSingleObject(Thread->Event);
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DbgPrint("DosCreateThread wait on startup event, Status=%x\n",
+ Status);
+ }
+#endif // DBG
+
+ //
+ // The thread is now running, need to acquire the lock so we
+ // can safely return the results
+ //
+ AcquireTaskLock();
+ if (Od2FindOd2Thread(Thread)) {
+
+ rc = Thread->rc;
+
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ KdPrint(("leaving DosCreateThread with rc %ld\n",rc));
+ }
+#endif
+
+ if (rc == ERROR_INVALID_FUNCTION) {
+ // The process is going to die. Wait for death.
+ ReleaseTaskLock();
+ Od2InfiniteSleep();
+ }
+
+ //
+ // This is the application address, so write only 16 bit
+ //
+ if (rc == NO_ERROR) {
+ *(PUSHORT)ThreadId = (USHORT) Thread->Os2Tib.ThreadId;
+ }
+ }
+ else
+ {
+ //
+ // The thread exited already, can't use the thread structure:
+ // set status to OK
+ //
+ rc = NO_ERROR;
+
+ // PatrickQ 1-9-96:
+ // Set ThreadID anyhow - _beginthread() uses thread ID for its
+ // return value and some applications might fail if they get an invalid
+ // thread ID (example: CBA application)
+
+ *(PUSHORT)ThreadId = 1; // dummy value but valid thread ID
+
+#if DBG
+ // Add debug message at this exit-point as well
+ IF_OD2_DEBUG( TASKING )
+ {
+ KdPrint(("leaving DosCreateThread with rc %ld (thread already exited)\n",rc));
+ }
+#endif
+ }
+ ReleaseTaskLock();
+ return(rc);
+}
+
+APIRET
+Od2AttachWinThreadToOs2(VOID)
+{
+ //
+ // This routine is called by a thread created by Win32, to enable it to use OS/2 APIs
+ // The current usage is for Async netBios (client\dllnet16.c)
+ //
+ // It:
+ // creates OD2_THREAD structure
+ // Initialize it with the Od2Process list
+ // Call os2srv so it will treat is as an Os/2 created thread
+ //
+ OS2_API_MSG m;
+ POS2_DOSCREATETHREAD_MSG a = &m.u.DosCreateThread;
+ POD2_THREAD Thread;
+ THREAD_BASIC_INFORMATION ThreadInfo;
+ NTSTATUS Status;
+
+ Thread = RtlAllocateHeap( Od2Heap, 0, sizeof( *Thread ) );
+ if (Thread == NULL) {
+#if DBG
+ KdPrint(( "OS2DLL: Od2AttachWinThreadToOs2 can't allocate from heap\n" ));
+ ASSERT(FALSE);
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ a->Flags = DCT_RUNABLE | DCT_ATTACHED;
+ a->ClientOs2Tib = &Thread->Os2Tib;
+
+ //
+ // Duplicate our own thread handle for os2srv
+ //
+ if (!DuplicateHandle(
+ GetCurrentProcess(),
+ GetCurrentThread(),
+ hOs2Srv,
+ &a->ThreadHandle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS
+ )){
+#if DBG
+ KdPrint(( "Od2AttachWinThreadtoOs2: fail to duplicate thread %d\n",GetLastError()));
+#endif
+ RtlFreeHeap(Od2Heap, 0, Thread);
+ return( ERROR_ACCESS_DENIED);
+ }
+
+ Status = NtQueryInformationThread(GetCurrentThread(),
+ ThreadBasicInformation,
+ (PVOID)(&ThreadInfo),
+ sizeof(ThreadInfo),
+ NULL
+ );
+ if (!NT_SUCCESS(Status)){
+#if DBG
+ KdPrint(( "Od2AttachWinThreadtoOs2: fail to Query Information %lx\n",Status));
+#endif
+ RtlFreeHeap(Od2Heap, 0, Thread);
+ Od2CloseSrvHandle(1, a->ThreadHandle, NULL, NULL);
+ return(Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
+ }
+
+ a->ClientId = ThreadInfo.ClientId;
+
+ Od2CallSubsystem( &m, NULL, Os2CreateThread, sizeof( *a ) );
+
+ if( m.ReturnedErrorValue ) {
+#if DBG
+ KdPrint(( "Od2AttachWinThreadtoOs2: OS2Srv error return value %ld\n",m.ReturnedErrorValue));
+#endif
+ RtlFreeHeap(Od2Heap, 0, Thread);
+ Od2CloseSrvHandle(1, a->ThreadHandle, NULL, NULL);
+ return(m.ReturnedErrorValue);
+ }
+ Od2InitializeThread( Thread );
+ AcquireTaskLock();
+ InsertTailList( &Od2Process->ThreadList, &Thread->Link );
+ ReleaseTaskLock();
+ return(NO_ERROR);
+}
+
+
+APIRET
+DosGetThreadInfo(
+ OUT PNT_TIB *ThreadInfo,
+ OUT PPIB *ProcessInfo
+ )
+{
+ PTEB Teb;
+
+ Teb = NtCurrentTeb();
+ try {
+ *ThreadInfo = &Teb->NtTib;
+ *ProcessInfo = &Od2Process->Pib;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return( NO_ERROR );
+}
+
+VOID
+Od2DosExit(
+ ULONG ExitAction,
+ ULONG ExitResult,
+ ULONG ExitReason
+ )
+
+{
+ OS2_API_MSG m;
+ POS2_DOSEXIT_MSG a = &m.u.DosExit;
+ ULONG CurrentTid = Od2CurrentThreadId();
+ NTSTATUS Status;
+
+ if (timing)
+ {
+ printf("Os2 time at start of Od2DosExit is %d\n", (GetTickCount()) - timing);
+ }
+
+ //
+ // An ExitReason of 0xF0000000L is a special flag that
+ // tells us this is a win32 process calling to detach
+ // itself from the os2ss. The server already knows this
+ // is a win32 attached process, so it'll detach it.
+ //
+
+ a->ExitAction = ExitAction;
+ a->ExitResult = ExitResult;
+ Od2Process->ResultCodes.ExitReason = ((ExitReason != 0xF0000000L) ? ExitReason : TC_EXIT);
+ Od2Process->ResultCodes.ExitResult = ExitResult;
+ //
+ // If a thread that owns a critsect exits, clean it up first
+ //
+ while (Od2CritSectCounter && Od2CritSectOwner == CurrentTid) {
+ DosExitCritSec();
+ }
+
+ if (ExitAction == EXIT_THREAD && CurrentTid != 1) {
+ AcquireTaskLock();
+ Status = NtClose(((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Event);
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DbgPrint("Od2DosExit fail to close thread event, Status=%x\n",
+ Status);
+ }
+#endif // DBG
+ RemoveEntryList( &((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Link );
+ NtClose(((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->ThreadHandle);
+ RtlFreeHeap(Od2Heap, 0, NtCurrentTeb()->EnvironmentPointer);
+ ReleaseTaskLock();
+ }
+ else {
+ if (ExitReason == EXIT_THREAD || ExitReason == EXIT_PROCESS) {
+ //
+ // Note that the server is going to remove this process
+ // state, for later use (os2ses\os2.c)
+ //
+ Od2DosExitIsDone = 1;
+ }
+ }
+
+ Od2CallSubsystem( &m, NULL, Os2Exit, sizeof( *a ) );
+
+ if (ExitReason == 0xF0000000L) {
+
+ //
+ // Special value that tells us we're detaching a win32 thread
+ //
+
+ NtCurrentTeb()->EnvironmentPointer = NULL;
+ return;
+ }
+
+ //
+ // For a thread exiting itself, win32 does not clean properly
+ // unless you call ExitThread()
+ //
+ if (ExitAction == EXIT_THREAD && CurrentTid != 1) {
+ ExitThread(0);
+ }
+
+ Od2InfiniteSleep();
+}
+
+VOID
+Od2ExitGP()
+{
+ OS2_API_MSG m;
+ POS2_DOSGP_MSG a = &m.u.DosExitGP;
+ ULONG ApiIndex, Length;
+
+ ApiIndex = ((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->ApiIndex/sizeof(PSZ);
+
+ Length = strlen(Od216ApiTable[ApiIndex]);
+ if (Length >= MAX_API_NAME_FOR_GP)
+ {
+ Length = MAX_API_NAME_FOR_GP - 1;
+ }
+ RtlMoveMemory(&a->ApiName[0], Od216ApiTable[ApiIndex], Length);
+ a->ApiName[Length] = '\0';
+ Od2Process->ResultCodes.ExitReason = TC_TRAP;
+ Od2Process->ResultCodes.ExitResult = 13;
+ Od2CallSubsystem( &m, NULL, Os2ExitGP, sizeof( *a ) );
+
+ Od2InfiniteSleep();
+
+#if DBG
+ KdPrint(("done with DosExitGP, still alive, commit suicide now\n"));
+#endif
+ NtTerminateThread(NtCurrentThread(), STATUS_SUCCESS);
+}
+
+
+VOID
+DosExit(
+ IN ULONG ExitAction,
+ IN ULONG ExitResult
+ )
+{
+ if (Od2Process->Pib.Status & PS_EXITLIST) {
+ DosExitList( EXLST_EXIT, NULL );
+ }
+
+ Od2DosExit(ExitAction,ExitResult,TC_EXIT);
+}
+
+
+APIRET
+DosWaitChild(
+ IN ULONG WaitTarget,
+ IN ULONG WaitOption,
+ OUT PRESULTCODES ResultCodes,
+ OUT PPID ResultProcessId,
+ IN PID ProcessId
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSWAITCHILD_MSG a = &m.u.DosWaitChild;
+ ULONG i;
+ ULONG ExitCode;
+ NTSTATUS Status;
+ HANDLE hProcess = (HANDLE)ProcessId;
+
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ KdPrint(("entering DosWaitChild\n"));
+ }
+#endif
+
+ if (WaitTarget > DCWA_PROCESSTREE) {
+ return( ERROR_INVALID_DATA );
+ }
+
+ if (WaitOption > DCWW_NOWAIT) {
+ return( ERROR_INVALID_DATA );
+ }
+
+ if (ProcessId != 0){
+ //
+ // see if this is a win32 process
+ //
+
+ for (i = 0;i<NUMOF32ASYNCPROC;i++){
+ if ((Od2AsyncProc[i].hProcess == hProcess) && !Od2AsyncProc[i].CreateSync){
+ Od2AsyncProc[i].hProcess = 0;
+ break;
+ }
+ }
+
+ if (i < NUMOF32ASYNCPROC){
+ //
+ // it is a win32 process we are waiting on -
+ // don't involve os2srv
+ //
+
+ //
+ // Wait for Completion and set Os/2 app parameters
+ //
+ Status = Od2AlertableWaitForSingleObject(hProcess);
+ if (!NT_SUCCESS(Status)){
+
+#if DBG
+ KdPrint(( "DosWaitChild: fail at WaitForSingleObject %lx\n",Status));
+#endif
+ NtClose(hProcess);
+ //BUGBUG: do we need to call Od2RemoveWin32ChildProcess();
+ return(Or2MapNtStatusToOs2Error(
+ Status,ERROR_ACCESS_DENIED));
+ }
+ GetExitCodeProcess(hProcess, &ExitCode);
+
+#if DBG
+ if (ExitCode != NO_ERROR){
+ KdPrint(("DosWaitChild: result of win32 process is %d\n",
+ ExitCode));
+ }
+#endif
+ Ow2WinExitCode2ResultCode(
+ ExitCode,
+ &ResultCodes->ExitResult,
+ &ResultCodes->ExitReason);
+
+ *ResultProcessId = ProcessId;
+ Od2RemoveWin32ChildProcess();
+
+ return(NO_ERROR);
+ }
+ }
+
+ a->WaitTarget = WaitTarget;
+ a->WaitOption = WaitOption;
+ a->ProcessId = ProcessId;
+ a->ResultCodes.ExitReason = 0;
+ a->ResultCodes.ExitResult = 0;
+ a->ResultProcessId = 0;
+
+ Od2CallSubsystem( &m, NULL, Os2WaitChild, sizeof( *a ) );
+
+ try {
+ *ResultCodes = a->ResultCodes;
+ *ResultProcessId = a->ResultProcessId;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ KdPrint(("leaving DosWaitChild with rc %ld\n",m.ReturnedErrorValue));
+ }
+#endif
+ return( m.ReturnedErrorValue );
+}
+
+
+APIRET
+DosWaitThread(
+ IN OUT PTID ThreadId,
+ IN ULONG WaitOption
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSWAITTHREAD_MSG a = &m.u.DosWaitThread;
+
+ if (WaitOption > DCWW_NOWAIT) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ try {
+ Od2ProbeForWrite( (PVOID)ThreadId, sizeof( PTID ), 1 );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ a->ThreadId = *ThreadId;
+ a->WaitOption = WaitOption;
+
+ Od2CallSubsystem( &m, NULL, Os2WaitThread, sizeof( *a ) );
+
+ *ThreadId = a->ThreadId;
+ return( m.ReturnedErrorValue );
+}
+
+APIRET
+Od2SuspendAllThreads( VOID )
+{
+ NTSTATUS Status;
+ PLIST_ENTRY ListHead, ListNext;
+ POD2_THREAD Thread;
+ ULONG CurrentTid = Od2CurrentThreadId();
+ ULONG SuspendCount;
+ APIRET rc = NO_ERROR;
+
+ AcquireTaskLock();
+ //
+ // Walk through the list of threads and suspend all but not the current
+ //
+ ListHead = &Od2Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OD2_THREAD, Link );
+ if (Thread->Os2Tib.ThreadId != CurrentTid) {
+
+ Status = NtSuspendThread (Thread->ThreadHandle, &SuspendCount);
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d]Od2SuspendAllThreads Suspend Thread #%d, SuspendCount %d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Thread->Os2Tib.ThreadId,
+ SuspendCount);
+ }
+#endif // DBG
+ if (!NT_SUCCESS(Status) && Status != STATUS_THREAD_IS_TERMINATING) {
+#if DBG
+ DbgPrint("[%d,%d]Od2SuspendAllThreads: Fail to suspend shread #%d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Thread->Os2Tib.ThreadId
+ );
+#endif // DBG
+ rc = ERROR_INVALID_PARAMETER;
+ }
+ }
+ ListNext = ListNext->Flink;
+ }
+ ReleaseTaskLock();
+
+ return(rc);
+}
+
+APIRET
+Od2ResumeAllThreads( VOID )
+{
+ NTSTATUS Status;
+ PLIST_ENTRY ListHead, ListNext;
+ POD2_THREAD Thread;
+ ULONG CurrentTid = Od2CurrentThreadId();
+ ULONG SuspendCount;
+ APIRET rc = NO_ERROR;
+
+ AcquireTaskLock();
+ //
+ // Walk through the list of threads and resume all but not the current
+ //
+ ListHead = &Od2Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OD2_THREAD, Link );
+ if (Thread->Os2Tib.ThreadId != CurrentTid) {
+
+ Status = NtResumeThread (Thread->ThreadHandle, &SuspendCount);
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d]Od2ResumeAllThreads Suspend Thread #%d, SuspendCount %d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Thread->Os2Tib.ThreadId,
+ SuspendCount);
+ }
+#endif // DBG
+ if (!NT_SUCCESS(Status) && Status != STATUS_THREAD_IS_TERMINATING) {
+#if DBG
+ DbgPrint("[%d,%d]Od2ResumeAllThreads: Fail to resume shread #%d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Thread->Os2Tib.ThreadId
+ );
+#endif // DBG
+ rc = ERROR_INVALID_PARAMETER;
+ }
+ }
+ ListNext = ListNext->Flink;
+ }
+ ReleaseTaskLock();
+
+ return(rc);
+}
+
+POD2_THREAD
+Od2FindThreadById(
+ ULONG ThreadId
+ )
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POD2_THREAD Thread;
+
+ ListHead = &Od2Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OD2_THREAD, Link );
+ if (Thread->Os2Tib.ThreadId == ThreadId)
+ break;
+ ListNext = ListNext->Flink;
+ }
+ if (Thread->Os2Tib.ThreadId != ThreadId) {
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d] Od2FindThreadById(#%d) - invalid thread id\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ ThreadId);
+ }
+#endif // DBG
+ return NULL;
+ }
+ return Thread;
+}
+
+APIRET
+DosSuspendThread(
+ IN TID ThreadId
+ )
+{
+ NTSTATUS Status;
+ POD2_THREAD Thread;
+ ULONG SuspendCount;
+ BOOLEAN Myself;
+
+ AcquireTaskLock();
+
+ // If the thread that must be suspended is the owner of
+ // critical section, wait until it will exit from critical section
+ // If the current thread is suspended, don't suspend another thread.
+ // Wait until the current thread will be resumed.
+
+ while (
+ (Od2CritSectOwner != 0 && Od2CritSectOwner == (ULONG)ThreadId) ||
+ (((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Os2Tib.
+ MustCompleteForceFlag & MCF_SUSPENDED)
+ )
+ {
+ ReleaseTaskLock();
+ Od2WaitOnCritSectOrSuspend();
+ AcquireTaskLock();
+ }
+
+ Thread = Od2FindThreadById((ULONG)ThreadId);
+ if (Thread == NULL) {
+ ReleaseTaskLock();
+ return ERROR_INVALID_THREADID;
+ }
+
+ if (Thread->Os2Tib.MustCompleteForceFlag & MCF_SUSPENDED) {
+ if (Thread->Os2Tib.MustCompleteForceFlag & MCF_FROZEN) {
+ Thread->Os2Tib.MustCompleteForceFlag |= MCF_SUSPENDED_AND_FROZEN;
+ }
+ // Already suspended
+ ReleaseTaskLock();
+ return NO_ERROR;
+ }
+
+ Status = NtResetEvent(Thread->Event, NULL);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d]DosSuspenThread(#%d): fail to reset event, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ ThreadId,
+ Status);
+ ASSERT(FALSE);
+ }
+#endif // DBG
+
+ // Thread is considered suspended
+ Thread->Os2Tib.MustCompleteForceFlag |= MCF_SUSPENDED;
+
+ //
+ // Don't suspend the current thread
+ //
+ if (!(Myself = (Thread->Os2Tib.ThreadId == Od2CurrentThreadId()))) {
+
+ Status = NtSuspendThread (Thread->ThreadHandle, &SuspendCount);
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d]DosSuspendThread(#%d), SuspendCount %x, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Thread->Os2Tib.ThreadId,
+ SuspendCount,
+ Status);
+ }
+ if (!NT_SUCCESS(Status)) {
+ ASSERT(FALSE);
+ }
+#endif // DBG
+ }
+#if DBG
+ else {
+ // The thread is going to suspend itself
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d]DosSuspendThread - myself\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId());
+ }
+ }
+#endif //DBG
+
+ //
+ // If the thread is in 32 bit don't suspend it immediately. It will wait
+ // for resuming upon return to 16 bit. If thread executes signal handler
+ // it will wait upon signal handler return to 16 bit.
+ //
+ if (Thread->Os2Tib.MustCompleteForceFlag & MCF_IN32BIT ||
+ (Od2Process->Pib.SigHandInProgress && ((ULONG)ThreadId == 1L))) {
+ //
+ // The thread is in 32 bit or during signal processing
+ //
+ // If API was called for self-suspend, the thread must not be resumed
+ // (it wasn't suspended, actually)
+ //
+ if (!Myself) {
+ Status = NtResumeThread (Thread->ThreadHandle, &SuspendCount);
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d]DosSuspendThread(#%d) Resuming Thread in 32bit, SuspendCount %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Thread->Os2Tib.ThreadId,
+ SuspendCount);
+ }
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d]DosSuspendThread(#%d) failed at NtResumeThread, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Thread->Os2Tib.ThreadId,
+ Status);
+ ASSERT(FALSE);
+ }
+#endif // DBG
+ }
+ }
+ ReleaseTaskLock();
+
+ if (Myself && !(Thread->Os2Tib.MustCompleteForceFlag & MCF_IN32BIT)) {
+ //
+ // This is possible
+ // - in the case that the thread is suspended during thread startup.
+ // - if the curent thread is frozen by debuggre process after
+ // breakpoint.
+ //
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d]DosSuspendThread: Frozen after breakpoint or in startup\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId());
+ }
+#endif
+ NtSuspendThread (NtCurrentThread(), NULL);
+ }
+ return(NO_ERROR);
+}
+
+APIRET
+DosResumeThread(
+ IN TID ThreadId
+ )
+{
+ NTSTATUS Status;
+ POD2_THREAD Thread;
+ ULONG SuspendCount;
+
+ AcquireTaskLock();
+
+ Thread = Od2FindThreadById((ULONG)ThreadId);
+ if (Thread == NULL) {
+ ReleaseTaskLock();
+ return ERROR_INVALID_THREADID;
+ }
+
+ if (!(Thread->Os2Tib.MustCompleteForceFlag & MCF_SUSPENDED)) {
+ // Already resumed
+ ReleaseTaskLock();
+ return NO_ERROR;
+ }
+
+ if (Thread->Os2Tib.MustCompleteForceFlag & MCF_FROZEN) {
+ Thread->Os2Tib.MustCompleteForceFlag &= ~MCF_SUSPENDED_AND_FROZEN;
+ ReleaseTaskLock();
+ return NO_ERROR;
+ }
+
+ // Thread is considered resumed
+ Thread->Os2Tib.MustCompleteForceFlag &= ~MCF_SUSPENDED;
+ //
+ // If the thread is resumed being in 32 bit, nothing must be done
+ //
+ if (!(Thread->Os2Tib.MustCompleteForceFlag & MCF_IN32BIT) &&
+ !(Od2Process->Pib.SigHandInProgress && ((ULONG)ThreadId == 1L))) {
+ //
+ // The thread was suspended in 16 bit. Just resume it.
+ //
+ Status = NtResumeThread (Thread->ThreadHandle, &SuspendCount);
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d]DosResumeThread(#%d), SuspendCount %x, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Thread->Os2Tib.ThreadId,
+ SuspendCount,
+ Status);
+ }
+#endif // DBG
+ }
+
+ Status = NtSetEvent(Thread->Event, NULL);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d]DosResumeThread(#%d): fail to set event, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ ThreadId,
+ Status);
+ ASSERT(FALSE);
+ }
+#endif // DBG
+
+ ReleaseTaskLock();
+ return(NO_ERROR);
+}
+
+
+APIRET
+DosEnterCritSec( VOID )
+{
+ NTSTATUS Status;
+ PLIST_ENTRY ListHead, ListNext;
+ POD2_THREAD Thread;
+ ULONG CurrentTid = Od2CurrentThreadId();
+ ULONG SuspendCount;
+
+
+ AcquireTaskLock();
+ // If other thread is the owner of critical section wait until it will release
+ // the critical section
+ // If the current thread was suspened, wait until it will be released
+ while (
+ (Od2CritSectOwner != 0 && Od2CritSectOwner != CurrentTid) ||
+ (((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Os2Tib.
+ MustCompleteForceFlag & MCF_SUSPENDED)
+ )
+ {
+ ReleaseTaskLock();
+ Od2WaitOnCritSectOrSuspend();
+ AcquireTaskLock();
+ }
+ // The current thread isn't suspended due to other thread critical section and
+ // it isn't suspended by DosSuspendThread.
+ Od2CritSectCounter++;
+ // Only if there is the 1st call to DosEnterCritSec proceed. If it is not,
+ // just increment the counter.
+ if (Od2CritSectCounter == 1) {
+ Od2CritSectOwner = CurrentTid;
+ //
+ // set flag for ExitCritSect
+ //
+ Od2NeedToResumeThreads = TRUE;
+ Status = NtResetEvent (
+ Od2CritSecEvent,
+ NULL);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d]DosEnterCritSec: failed at NtResetEvent, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ //
+ // Walk through the list of threads and suspend all but not the current
+ //
+ ListHead = &Od2Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OD2_THREAD, Link );
+ if (Thread->Os2Tib.ThreadId != CurrentTid) {
+
+ Status = NtSuspendThread (Thread->ThreadHandle, &SuspendCount);
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d]DosEnterCritSect Suspend Thread #%x, SuspendCount %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Thread->Os2Tib.ThreadId,
+ SuspendCount);
+ }
+ if (!NT_SUCCESS(Status) && Status != STATUS_THREAD_IS_TERMINATING) {
+ KdPrint(("DosEnterCritSect error: Status %lx Suspending Thread #%x, SuspendCount %x\n",
+ Status, Thread->Os2Tib.ThreadId, SuspendCount));
+ }
+#endif // DBG
+ //
+ // If the thread is in 32 bit don't suspend it immediately. It will wait
+ // for resuming upon return to 16 bit. If thread executes signal handler
+ // it will wait upon signal handler return to 16 bit.
+ //
+ if (Thread->Os2Tib.MustCompleteForceFlag & MCF_IN32BIT ||
+ (Od2Process->Pib.SigHandInProgress &&
+ (Thread->Os2Tib.ThreadId == 1L))) {
+ //
+ // The thread in 32 bit or during the signal processing
+ //
+ Status = NtResumeThread (Thread->ThreadHandle, &SuspendCount);
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d]DosEnterCritSect Resuming Thread in 32bit #%x in 32bit code, SuspendCount %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Thread->Os2Tib.ThreadId,
+ SuspendCount);
+ }
+#endif
+ if (!NT_SUCCESS(Status)){
+#if DBG
+ KdPrint(("DosEnterCritSect error: Status %lx Resuming Thread #%x, SuspendCount %x\n",
+ Status, Thread->Os2Tib.ThreadId, SuspendCount));
+#endif
+ }
+ }
+ }
+ ListNext = ListNext->Flink;
+ }
+ }
+ ReleaseTaskLock();
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+DosExitCritSec( VOID )
+{
+ NTSTATUS Status;
+ ULONG SuspendCount;
+ PLIST_ENTRY ListHead, ListNext;
+ POD2_THREAD Thread;
+ ULONG CurrentTid = Od2CurrentThreadId();
+
+ if (Od2CritSectCounter == 0) {
+#if DBG
+ KdPrint(("DosExitCritSec - critsect underflow\n"));
+#endif
+ return(ERROR_CRITSEC_UNDERFLOW);
+ }
+
+ AcquireTaskLock();
+ Od2CritSectCounter--;
+ if (Od2CritSectCounter == 0 && Od2NeedToResumeThreads) {
+ // The critical section is over
+ Od2CritSectOwner = 0;
+ //
+ // Walk through the list of threads and resume all threads that were
+ // in 16 bit while DosEnterCritSec was called.
+ // Threads that were in 32 bit, i.e. in an API, are
+ // released from the sync event, if they are waiting on it
+ //
+ ListHead = &Od2Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OD2_THREAD, Link );
+ if (Thread->Os2Tib.ThreadId != CurrentTid) {
+
+ if (!(Thread->Os2Tib.MustCompleteForceFlag & MCF_IN32BIT) &&
+ !(Od2Process->Pib.SigHandInProgress &&
+ ((ULONG)Thread->Os2Tib.ThreadId == 1L))) {
+ //
+ // This thread was in 16 bit when frozen by DosEnterCritSec
+ //
+ Status = NtResumeThread (Thread->ThreadHandle, &SuspendCount);
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d]DosExitCritSect Resuming Thread #%x, SuspendCount %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Thread->Os2Tib.ThreadId,
+ SuspendCount);
+ }
+#endif
+ if (!NT_SUCCESS(Status)){
+#if DBG
+ KdPrint(("DosExitCritSect error: Status %lx Resuming Thread #%x, SuspendCount %x\n",
+ Status, Thread->Os2Tib.ThreadId, SuspendCount));
+#endif
+ }
+ }
+ }
+ ListNext = ListNext->Flink;
+ }
+ Status = NtSetEvent (
+ Od2CritSecEvent,
+ NULL);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d,%d]DosExitCritSec: failed at NtSetEvent, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif
+ Od2NeedToResumeThreads = FALSE;
+ }
+
+ ReleaseTaskLock();
+ return(NO_ERROR);
+}
+
+VOID
+Od2WaitOnCritSectOrSuspend(VOID)
+{
+ if (Od2NeedToResumeThreads && Od2CritSectOwner != Od2CurrentThreadId()) {
+ //
+ // Another thread called DosEnterCritSect
+ //
+ Od2AlertableWaitForSingleObject(Od2CritSecEvent);
+ }
+ //
+ // Check if the thread must be suspended
+ //
+ if (((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Os2Tib.
+ MustCompleteForceFlag & MCF_SUSPENDED) {
+ //
+ // DosSuspendThread was called for the current thread
+ //
+ Od2AlertableWaitForSingleObject(
+ ((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Event);
+ }
+}
+
+//
+// The following routine is being called on the verge of going 32bit
+// to 16 bit. If EnterCritSect is in power, and other conditions are
+// met, the thread will wait on a semaphore, for DosExitCritSec to release
+// it.
+//
+
+VOID
+Od2CheckForCritSectOrSuspend(VOID)
+{
+ //
+ // During signal handling do nothing
+ //
+ if (!(Od2SigHandAlreadyInProgress && Od2CurrentThreadId() == 1)) {
+ // The thread is considered to be in 16bit now. If any other thread enter
+ // to critical section or calls DosSuspendThread for the current thread it
+ // will symply suspend it.
+ ((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Os2Tib.
+ MustCompleteForceFlag &= ~MCF_IN32BIT;
+ //
+ // We are not thread1 in signal handling, so wait if critical section or suspend
+ // events are in non-signaled state.
+ //
+ Od2WaitOnCritSectOrSuspend();
+ }
+}
+
+
+VOID
+Od2FreezeThread(
+ IN ULONG rEax,
+ IN PCONTEXT pContext
+ )
+{
+ NTSTATUS Status;
+ POD2_THREAD Thread;
+ LOCALINFOSEG Linfoseg;
+
+ //
+ // Save 40 bytes of area fs:0.
+ // In 16 bit this area is the local info segment, and in 32bit
+ // we restore the TEB.
+ //
+ SaveFSSeg(&Linfoseg);
+ RestoreTeb();
+
+ //
+ // Clear the flag of alert in kernel.
+ //
+ Status = NtTestAlert();
+
+ //
+ // We need to update the value of register Eax, for interrupted context,
+ // because it may be changed after the NtGetContextThread().
+ // This can happen if the thread was in kernel mode.
+ //
+ pContext->Eax = rEax;
+
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d]Od2FreezeThread\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId());
+ }
+#endif
+
+ AcquireTaskLock();
+ Thread = Od2FindThreadById(Od2CurrentThreadId());
+ ASSERT(Thread != NULL);
+
+ Thread->Os2Tib.MustCompleteForceFlag |= MCF_FROZEN;
+
+ if (Thread->Os2Tib.MustCompleteForceFlag & MCF_SUSPENDED) {
+ //
+ // The thread is already suspended. Just update its state.
+ //
+ Thread->Os2Tib.MustCompleteForceFlag |= MCF_SUSPENDED_AND_FROZEN;
+ ReleaseTaskLock();
+ }
+ else {
+ ReleaseTaskLock();
+ DosSuspendThread((TID)Od2CurrentThreadId());
+ }
+
+ RestoreFSSeg(&Linfoseg);
+
+ //
+ // Continue with the interrupted context.
+ //
+ NtContinue(pContext, FALSE);
+ ASSERT(FALSE);
+}
+
+VOID
+Od2UnfreezeThread(
+ IN ULONG rEax,
+ IN PCONTEXT pContext
+ )
+{
+ NTSTATUS Status;
+ POD2_THREAD Thread;
+ LOCALINFOSEG Linfoseg;
+
+ //
+ // Save 40 bytes of area fs:0.
+ // In 16 bit this area is the local info segment, and in 32bit
+ // we restore the TEB.
+ //
+ SaveFSSeg(&Linfoseg);
+ RestoreTeb();
+
+ //
+ // Clear the flag of alert in kernel.
+ //
+ Status = NtTestAlert();
+
+ //
+ // We need to update the value of register Eax, for interrupted context,
+ // because it may be changed after the NtGetContextThread().
+ // This can happen if the thread was in kernel mode.
+ //
+ pContext->Eax = rEax;
+
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d]Od2UnfreezeThread\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId());
+ }
+#endif
+
+ AcquireTaskLock();
+ Thread = Od2FindThreadById(Od2CurrentThreadId());
+ ASSERT(Thread != NULL);
+
+ Thread->Os2Tib.MustCompleteForceFlag &= ~MCF_FROZEN;
+
+ if (Thread->Os2Tib.MustCompleteForceFlag & MCF_SUSPENDED_AND_FROZEN) {
+ //
+ // The thread is suspended and frozen, so we should not resume it.
+ // Just update its state.
+ //
+ Thread->Os2Tib.MustCompleteForceFlag &= ~MCF_SUSPENDED_AND_FROZEN;
+ ReleaseTaskLock();
+ }
+ else {
+ ReleaseTaskLock();
+ DosResumeThread((TID)Od2CurrentThreadId());
+ }
+
+ RestoreFSSeg(&Linfoseg);
+
+ //
+ // Continue with the interrupted context.
+ //
+ NtContinue(pContext, FALSE);
+ ASSERT(FALSE);
+}
+
+//
+// IMPORTANT !!!
+// Changing the code below (Od2GetSegmentRegisters and Od2PrepareEnterToSignalHandler)
+// check the follows:
+// - Od2GetSegmentRegisters (dlltask.c)
+// - Entry flat and Exit flat (doscalls.asm)
+// - Od2Continue and Od2SetSegmentRegisters (dll16.asm)
+// - Os2SignalGetThreadContext (srvxcpt.c)
+//
+
+//
+// Function NtGetContextThread is not accurate with values of segment registers ES and DS
+// in the case that the code segment is 1b (flat). We need to find the proper values for
+// these registers.
+// The context of interrupted thread can be on of the follows:
+// - flat (CS==1b, SS==23)
+// - 16bit (CS!=1b, SS!=23)
+// - Entry flat (CS==1b, SS!=23)
+// - Exit flat (CS==1b, SS!=23)
+// - Od2JumpTo16SignalDispatch (CS==1b, SS!=23)
+// - Od2Continue (CS==1b, SS!=23)
+// For each one of this cases we know where to find the segment registers.
+// We may need these registers to execute the signal handler or to return to interrupted
+// context. The values we will use are not the same in this cases. For example, in the
+// case of Entry flat, we will use 16bit values of ES and DS for signal handler, but
+// we will return with 0x23 value for both registers.
+//
+
+VOID
+Od2GetSegmentRegisters(
+ PUSHORT pEsHandler,
+ PUSHORT pDsHandler,
+ PUSHORT pEsReturn,
+ PUSHORT pDsReturn,
+ PCONTEXT pContext
+ )
+{
+ //
+ // By default assume that the registers should be 0x23 -- flat
+ //
+ *pEsReturn = *pDsReturn = 0x23;
+
+ if (pContext->SegSs == 0x23) {
+ //
+ // Flat mode
+ //
+ *pEsHandler = *(PUSHORT)(Od2Saved16Stack+16);
+ *pDsHandler = *(PUSHORT)(Od2Saved16Stack+18);
+#if DBG
+ DbgPrint("Od2GetSegmentRegisters: This branch is implemented, but it mustn't be in use\n");
+ ASSERT(FALSE);
+#endif // DBG
+ return;
+ }
+ else if (pContext->SegCs == 0x1b) {
+ //
+ // Not a flat mode. May be 16bit or some kind of thunk
+ //
+ if (
+ //
+ // Exit flat thunk. The 16 bit segments were stored in the most significant parts
+ // of ECX and EDX. We need only the least significant word of registers upon
+ // returning to 16bit.
+ //
+ (pContext->Eip > (ULONG) ExitFlatAreaBegin &&
+ pContext->Eip < (ULONG) ExitFlatAreaEnd) ||
+ //
+ // Od2JumpTo16SignalDispatch thunk.
+ //
+ ((pContext->Eip > (ULONG) Od2JumpTo16SignalDispatch &&
+ pContext->Eip < (ULONG) Od2JumpTo16SignalDispatchEnd) ||
+ pContext->Eip == pContext->Ebp) ||
+
+ (pContext->Eip > (ULONG) Od2ContinueStartBorder &&
+ pContext->Eip < (ULONG) Od2ContinueEndBorder) ||
+
+ (pContext->Eip >= (ULONG) Od2SetSegmentRegisters &&
+ pContext->Eip < (ULONG) Od2SetSegmentRegistersEnd)
+ )
+ {
+ //
+ // Take ES and DS from the most significant parts of ECX and EDX
+ //
+ *pEsHandler = *(PUSHORT) ((PBYTE)&(pContext->Ecx) + 2);
+ *pDsHandler = *(PUSHORT) ((PBYTE)&(pContext->Edx) + 2);
+
+ //
+ // Check if we are still using flat data access. In this case return from
+ // signal with default values of segment registers.
+ //
+ if (pContext->Eip > (ULONG) Od2JumpTo16SignalDispatch &&
+ pContext->Eip < (ULONG) Od2JumpTo16SignalDispatchBorder) {
+ return;
+ }
+ }
+ else {
+ //
+ // Entry flat thunk. EBX point to 16bit stack frame. We will return back with
+ // 0x23 (flat) for both segment registers.
+ // It may be also Od2Continue thunk that return to Od2JumpTo16SignalDispatch
+ // before Od2JumpTo16SignalDispatchBorder.
+ //
+ *pEsHandler = *(PUSHORT) (pContext->Ebx + 16);
+ *pDsHandler = *(PUSHORT) (pContext->Ebx + 18);
+ return;
+ }
+ }
+ else
+ {
+ //
+ // 16bit
+ //
+ *pEsHandler = (USHORT) pContext->SegEs;
+ *pDsHandler = (USHORT) pContext->SegDs;
+ }
+
+ //
+ // Return with registers as they must to be in 16bit
+ //
+ *pEsReturn = *pEsHandler;
+ *pDsReturn = *pDsHandler;
+}
+
+//
+// This funtion must be called in the signal handler.
+//
+
+VOID
+Od2PrepareEnterToSignalHandler(
+ PCONTEXT pContext,
+ POD2_CONTEXT_SAVE_AREA pSaveArea
+ )
+{
+ NTSTATUS Status;
+
+ SaveFSSeg(&(pSaveArea->TebBlock)); // Save 40 bytes in TEB.
+ RestoreTebForThread1(); // Use TEB that it must be for thread1
+ Status = NtTestAlert(); // Clear alert flag of the thread
+#if DBG
+ IF_OD2_DEBUG( SIG ) {
+ DbgPrint("[%d]Od2PrepareEnterToSignalHandler: NtTestAlert() = %x\n",
+ Od2Process->Pib.ProcessId,
+ Status);
+ }
+ // There is thread1
+ ASSERT(((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Os2Tib.ThreadId == 1L);
+#endif // DBG
+
+ pSaveArea->SignalHandlingInProgress = Od2SigHandAlreadyInProgress;
+ //
+ // Thread1 executes signal handler, thus it will not be actually suspended
+ // neither by DosSuspendThread no by DosEnterCritSect. If needed the thread will
+ // be suspended after return to normal context.
+ //
+ Od2SigHandAlreadyInProgress = TRUE;
+
+ if (pContext->SegSs != 0x23) {
+ //
+ // If the thread was using 16bit stack while interrupted, make new stack frame in
+ // it's free area.
+ //
+ USHORT newSP =
+ *(PUSHORT) &(pContext->Esp)
+ - 20 // -20: the length of the new stack frame. We need it in the case that
+ // other signal will arive while the current signal handler is
+ // being executed in 32bit.
+ - 12; // -12: the area beyond the stack that is used by Od2Continue
+ USHORT SegEs, SegDs;
+
+ Od2GetSegmentRegisters(
+ &SegEs,
+ &SegDs,
+ &(pSaveArea->SegEs),
+ &(pSaveArea->SegDs),
+ pContext
+ );
+
+ Od2Saved16Stack =
+ // Flat address of the new current stack top
+ (ULONG) SELTOFLAT(pContext->SegSs) + newSP;
+
+ //
+ // Make new stack frame
+ //
+ *(PUSHORT)(Od2Saved16Stack) = newSP;
+ *(PUSHORT)(Od2Saved16Stack+2) = *(PUSHORT)&(pContext->SegSs);
+ *(PUSHORT)(Od2Saved16Stack+6) = *(PUSHORT)&(pContext->Edx);
+ *(PUSHORT)(Od2Saved16Stack+8) = *(PUSHORT)&(pContext->Ebx);
+ *(PUSHORT)(Od2Saved16Stack+10) = *(PUSHORT)&(pContext->Ecx);
+ *(PUSHORT)(Od2Saved16Stack+12) = *(PUSHORT)&(pContext->Esi);
+ *(PUSHORT)(Od2Saved16Stack+14) = *(PUSHORT)&(pContext->Edi);
+ *(PUSHORT)(Od2Saved16Stack+16) = SegEs;
+ *(PUSHORT)(Od2Saved16Stack+18) = SegDs;
+ }
+
+ //
+ // Od2Saved16Stack is set in each entry flat. It will be changed during 16bit signal
+ // handler processing. If the interrupted context was flat it will be restored to
+ // the original value.
+ //
+ pSaveArea->Saved16Stack = Od2Saved16Stack;
+
+#if DBG
+ IF_OD2_DEBUG( SIG ) {
+ DbgPrint("[%d]Od2PrepareEnterToSignalHandler: from %x:%x stack %x:%x ebp=%x\n",
+ Od2Process->Pib.ProcessId,
+ pContext->SegCs,
+ pContext->Eip,
+ pContext->SegSs,
+ pContext->Esp,
+ pContext->Ebp);
+ }
+#endif // DBG
+}
+
+VOID
+Od2MakeSignalHandlerContext(
+ POS2_REGISTER16_SIGNAL pContext16
+ )
+{
+ //
+ // Copy only registers from the stack frame. It is the context for executing 16bit
+ // signal handler. IP and CS aren't copied (we know the address of the 16bit handler)
+ //
+ RtlMoveMemory((PBYTE)pContext16, (PBYTE) Od2Saved16Stack, 20);
+
+#if DBG
+ IF_OD2_DEBUG( SIG ) {
+ DbgPrint("[%d]Make signal handler context:\nbx=%04x cx=%04x dx=%04x si=%04x di=%04x sp=%04x Ss=%04x Ds=%04x Es=%04x\n",
+ Od2Process->Pib.ProcessId,
+ pContext16->regBX,
+ pContext16->regCX,
+ pContext16->regDX,
+ pContext16->regSI,
+ pContext16->regDI,
+ pContext16->regSP,
+ pContext16->regSS,
+ pContext16->regDS,
+ pContext16->regES
+ );
+ }
+#endif // DBG
+}
+
+VOID
+Od2ExitFromSignalHandler(
+ PCONTEXT pContext,
+ POD2_CONTEXT_SAVE_AREA pSaveArea
+ )
+{
+
+ if (!(pSaveArea->SignalHandlingInProgress))
+ {
+ //
+ // The interruped context wasn't executing signal handler. We consider signal handler
+ // over.
+ //
+ Od2SigHandAlreadyInProgress = FALSE;
+ Od2Process->Pib.SigHandInProgress = FALSE;
+ //
+ // At this point the thread can be suspended by DosSuspendThread or DosEnterCritSec
+ // APIs (if the interrupted thread was permitted to be directly suspended).
+ // In the case that in the interrupted context thread was permitted to be suspended
+ // check if it must wait for release (or exit critical section). If it wasn't
+ // permitted it will check it upon exit from 32bit.
+ //
+ if(!(((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Os2Tib.
+ MustCompleteForceFlag & MCF_IN32BIT)) {
+ //
+ // The thread will wait here only in the case that critical section event or
+ // suspend event of the current thread are in the non-signaled state (that
+ // means that the thread must be suspended or other thread own critical
+ // section).
+ //
+ Od2WaitOnCritSectOrSuspend();
+ }
+ }
+
+ //
+ // The values for segment registers were fetched upon entry to signal handler
+ //
+ pContext->SegEs = pSaveArea->SegEs;
+ pContext->SegDs = pSaveArea->SegDs;
+ Od2Saved16Stack = pSaveArea->Saved16Stack;
+
+ //
+ // Restore 40 byte of TEB as they were in the interrupted context: TEB, Local infoseg or
+ // mix.
+ //
+ RestoreFSSeg(&(pSaveArea->TebBlock));
+
+#if DBG
+ IF_OD2_DEBUG( SIG ) {
+ DbgPrint("[%d]Exiting from signal handler\nEax=%08x Ebx=%08x Ecx=%08x Edx=%08x Esi=%08x Edi=%08x\nEip=%08x Esp=%08x Ebp=%08x Cs=%04x Ss=%04x Ds=%04x Es=%04x\n",
+ Od2Process->Pib.ProcessId,
+ pContext->Eax,
+ pContext->Ebx,
+ pContext->Ecx,
+ pContext->Edx,
+ pContext->Esi,
+ pContext->Edi,
+ pContext->Eip,
+ pContext->Esp,
+ pContext->Ebp,
+ pContext->SegCs,
+ pContext->SegSs,
+ pContext->SegDs,
+ pContext->SegEs
+ );
+ }
+#endif // DBG
+
+ //
+ // Continue to execute interrupted context. The argument is the pointer to part of
+ // the context structure starting from ES:
+ // ES, DS, EDI, ESI, EBX, EDX, ECX, EAX, EBP, EIP, CS, EFLAGS, ESP, SS.
+ // This function is used as substitute to NtContinue. NtContinue hasn't mutual
+ // exclusion for using context with NtGetContextThread and NtSetContextThread till
+ // build 717.
+ // This way seems to be safe enough.
+ //
+ Od2Continue(&(pContext->SegEs));
+ ASSERT(FALSE);
+}
+
+
+VOID
+Od2TranslateConfigSysInCommandLine(
+ IN OUT PSZ *ArgumentsBuffer
+ )
+//
+// This routine scans the command line for a WIN32 program looking for a reference to the
+// config.sys file. if it finds one, it reallocates the command line, replacing the name
+// by the name of os2conf.nt. os2conf.nt is created using Od2FileIsConfigSys();
+// It first attempts to create the file for writing, and if that fails, for reading.
+//
+
+{
+ PSZ Args = *ArgumentsBuffer;
+ BOOLEAN quoting1, quoting2;
+ CHAR ch, ch2;
+ PSZ CSPtr, LastSeparator, p, q;
+ STRING CanonicalString;
+ APIRET RetCode;
+ ULONG ParseFlags, FileType;
+ NTSTATUS Status;
+
+ if (Args == NULL) {
+ return;
+ }
+
+ CSPtr = ConfigSysString;
+ LastSeparator = Args - 1;
+ quoting1 = quoting2 = FALSE;
+
+ for (; (ch = *Args) != '\0'; Args++) {
+
+ if (!quoting1) {
+
+ if (ch == '^') {
+ if (!quoting2 || Args[1] == '"') {
+ quoting1 = TRUE;
+ continue;
+ }
+
+ } else if (ch == '"') {
+ quoting2 = !quoting2;
+ CSPtr = ConfigSysString;
+ LastSeparator = Args;
+ continue;
+
+ } else if (quoting2) {
+ continue;
+
+ } else if (SEPARATOR(ch)) {
+ CSPtr = ConfigSysString;
+ LastSeparator = Args;
+ continue;
+ }
+ }
+
+ quoting1 = FALSE;
+
+ ch = toupper((UCHAR)ch);
+
+ if (*CSPtr != ch) {
+ if (CSPtr == ConfigSysString) {
+ continue;
+ }
+
+ CSPtr = ConfigSysString;
+ }
+
+ if (*CSPtr == ch) {
+
+ CSPtr++;
+
+ if (*CSPtr == '\0') {
+
+ CSPtr = ConfigSysString;
+
+ ch2 = Args[1];
+
+ if (!SEPARATOR(ch2)) {
+ continue;
+ }
+
+ Args[1] = '\0';
+
+ RetCode = Od2Canonicalize(LastSeparator + 1,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &CanonicalString,
+ NULL,
+ &ParseFlags, // should return 0
+ &FileType // should return FILE_TYPE_FILE
+ );
+
+ Args[1] = ch2;
+
+ if (RetCode != NO_ERROR || ParseFlags != 0 || FileType != FILE_TYPE_FILE) {
+#if DBG
+ IF_OD2_DEBUG(MISC) {
+ KdPrint(("Od2TranslateConfigSysInCommandLine: Failed to canonicalize config.sys name, rc = %x, ParseFlags = %lx, FileType = %lx\n",
+ RetCode, ParseFlags, FileType));
+ }
+#endif
+ if (CanonicalString.Buffer != NULL) {
+ RtlFreeHeap(Od2Heap, 0, CanonicalString.Buffer);
+ }
+ continue;
+ }
+
+ if (!Od2FileIsConfigSys(&CanonicalString, OPEN_ACCESS_READWRITE, &Status)) {
+ RtlFreeHeap(Od2Heap, 0, CanonicalString.Buffer);
+ continue;
+ }
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG(MISC) {
+ KdPrint(("Od2TranslateConfigSysInCommandLine: Failed to create config.sys for READWRITE, Status = %lx\n",
+ Status));
+ }
+#endif
+
+ //
+ // Try opening for just reading
+ //
+
+ Od2FileIsConfigSys(&CanonicalString, OPEN_ACCESS_READONLY, &Status);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG(MISC) {
+ KdPrint(("Od2TranslateConfigSysInCommandLine: Failed to create config.sys for READONLY, Status = %lx\n",
+ Status));
+ }
+#endif
+
+ // note -- if Od2FileIsConfigSys failed to generate os2conf.nt for some reason, we
+ // leave the file name as config.sys so the caller has something.
+ // Is this correct?
+
+ RtlFreeHeap(Od2Heap, 0, CanonicalString.Buffer);
+ continue;
+ }
+ }
+
+ //
+ // now change the name from config.sys to os2conf.nt
+ //
+
+ p = RtlAllocateHeap(Od2Heap, 0, strlen(*ArgumentsBuffer) + CanonicalString.Length);
+
+ if (p == NULL) {
+#if DBG
+ IF_OD2_DEBUG(MISC) {
+ KdPrint(("Od2TranslateConfigSysInCommandLine: Failed to alloc space for new cmdline\n"));
+ }
+#endif
+
+ //
+ // We can't expand the name, drop it
+ //
+
+ RtlFreeHeap(Od2Heap, 0, CanonicalString.Buffer);
+ continue;
+ }
+
+ q = p; // save the start address
+
+
+ RtlMoveMemory(p, *ArgumentsBuffer, LastSeparator - (*ArgumentsBuffer) + 1);
+ p += LastSeparator - (*ArgumentsBuffer) + 1;
+
+ LastSeparator = p - 1;
+
+ RtlMoveMemory(p,
+ CanonicalString.Buffer + FILE_PREFIX_LENGTH,
+ CanonicalString.Length - FILE_PREFIX_LENGTH
+ );
+ p += CanonicalString.Length - FILE_PREFIX_LENGTH;
+
+ RtlMoveMemory(p,
+ Args + 1,
+ strlen(Args + 1) + 1
+ );
+
+ Args = p - 1; // readjust args
+
+ RtlFreeHeap(Od2Heap, 0, *ArgumentsBuffer);
+ *ArgumentsBuffer = q; // and ArgumentsBuffer
+
+ RtlFreeHeap(Od2Heap, 0, CanonicalString.Buffer);
+ }
+ }
+ }
+}
+
+
+HANDLE
+Od2DupHandleForRedirection(
+ HANDLE Handle
+ )
+{
+ HANDLE h;
+ NTSTATUS Status;
+
+ Status = NtDuplicateObject(
+ NtCurrentProcess(),
+ Handle,
+ NtCurrentProcess(),
+ &h,
+ (ACCESS_MASK) 0,
+ OBJ_INHERIT,
+ DUPLICATE_SAME_ACCESS);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("Od2DupHandleForRedirection: failed to dup handle, Status = %lx\n", Status));
+#endif
+ return(NULL);
+ }
+
+ return(h);
+}
+
+IO_VECTOR_TYPE
+Od2GetVectorTypeForRedirection(
+ IN PFILE_HANDLE pHand
+ )
+{
+ if (pHand->IoVectorType == ConVectorType) {
+ if ((pHand->Flags & ACCESS_FLAGS) == OPEN_ACCESS_READONLY) {
+ return KbdVectorType;
+ }
+ if ((pHand->Flags & ACCESS_FLAGS) == OPEN_ACCESS_WRITEONLY) {
+ return ScreenVectorType;
+ }
+#if DBG
+ DbgPrint("[%d] Wrong access flags (%x) for ConVectorType handle\n",
+ Od2Process->Pib.ProcessId,
+ pHand->Flags & ACCESS_FLAGS
+ );
+ ASSERT(FALSE);
+#endif // DBG
+ }
+ return pHand->IoVectorType;
+}
+
+
+VOID
+Od2PrepareStdHandleRedirection(
+ IN ULONG EnableFlags,
+ OUT POS2_STDHANDLES StdStruc
+ )
+
+//
+// This routine must be called with AcquireFileLockShared() in effect
+//
+
+{
+ PFILE_HANDLE pHand;
+ HANDLE hTmp;
+ IO_VECTOR_TYPE IoVectorType;
+
+ StdStruc->Flags = 0;
+
+ if (EnableFlags & STDFLAG_IN) {
+
+ pHand = &HandleTable[0];
+ IoVectorType = Od2GetVectorTypeForRedirection(pHand);
+
+ switch (IoVectorType) {
+
+ case RemoteVectorType:
+ if (pHand->NtHandle != SesGrp->StdIn) {
+ StdStruc->StdIn = pHand->NtHandle;
+ StdStruc->Flags |= STDFLAG_IN;
+ }
+ break;
+
+ case FileVectorType:
+ case PipeVectorType:
+ case DeviceVectorType:
+ case ComVectorType:
+ if ((hTmp = Od2DupHandleForRedirection(pHand->NtHandle)) != NULL) {
+ StdStruc->StdIn = hTmp;
+ StdStruc->Flags |= STDFLAG_IN | STDFLAG_CLOSEIN;
+ }
+ break;
+
+ case KbdVectorType:
+ if (SesGrp->hConsoleInput != SesGrp->StdIn) {
+ if ((hTmp = Od2DupHandleForRedirection(SesGrp->hConsoleInput)) != NULL) {
+ StdStruc->StdIn = hTmp;
+ StdStruc->Flags |= STDFLAG_IN | STDFLAG_CLOSEIN;
+ }
+ }
+ break;
+
+ case ScreenVectorType:
+ if (SesGrp->hConsoleOutput != SesGrp->StdOut) {
+ if ((hTmp = Od2DupHandleForRedirection(SesGrp->hConsoleOutput)) != NULL) {
+ StdStruc->StdIn = hTmp;
+ StdStruc->Flags |= STDFLAG_IN | STDFLAG_CLOSEIN;
+ }
+ } else {
+ StdStruc->StdIn = SesGrp->hConsoleOutput;
+ StdStruc->Flags |= STDFLAG_IN;
+ }
+ break;
+
+ case NulVectorType:
+ case LptVectorType:
+ case MouseVectorType:
+ case ClockVectorType:
+ case PointerVectorType:
+ case MonitorVectorType:
+ if ((hTmp = Ow2GetNulDeviceHandle()) != NULL) {
+ StdStruc->StdIn = hTmp;
+ StdStruc->Flags |= STDFLAG_IN;
+ }
+ break;
+ }
+ }
+
+ if (EnableFlags & STDFLAG_OUT) {
+
+ pHand = &HandleTable[1];
+ IoVectorType = Od2GetVectorTypeForRedirection(pHand);
+
+ switch (IoVectorType) {
+
+ case RemoteVectorType:
+ if (pHand->NtHandle != SesGrp->StdOut) {
+ StdStruc->StdOut = pHand->NtHandle;
+ StdStruc->Flags |= STDFLAG_OUT;
+ }
+ break;
+
+ case FileVectorType:
+ case PipeVectorType:
+ case DeviceVectorType:
+ case ComVectorType:
+ if ((hTmp = Od2DupHandleForRedirection(pHand->NtHandle)) != NULL) {
+ StdStruc->StdOut = hTmp;
+ StdStruc->Flags |= STDFLAG_OUT | STDFLAG_CLOSEOUT;
+ }
+ break;
+
+ case ScreenVectorType:
+ if (SesGrp->hConsoleOutput != SesGrp->StdOut) {
+ if ((hTmp = Od2DupHandleForRedirection(SesGrp->hConsoleOutput)) != NULL) {
+ StdStruc->StdOut = hTmp;
+ StdStruc->Flags |= STDFLAG_OUT | STDFLAG_CLOSEOUT;
+ }
+ }
+ break;
+
+ case KbdVectorType:
+ if (SesGrp->hConsoleInput != SesGrp->StdIn) {
+ if ((hTmp = Od2DupHandleForRedirection(SesGrp->hConsoleInput)) != NULL) {
+ StdStruc->StdOut = hTmp;
+ StdStruc->Flags |= STDFLAG_OUT | STDFLAG_CLOSEOUT;
+ }
+ } else {
+ StdStruc->StdOut = SesGrp->hConsoleInput;
+ StdStruc->Flags |= STDFLAG_OUT;
+ }
+ break;
+
+ case NulVectorType:
+ case LptVectorType:
+ case MouseVectorType:
+ case ClockVectorType:
+ case PointerVectorType:
+ case MonitorVectorType:
+ if ((hTmp = Ow2GetNulDeviceHandle()) != NULL) {
+ StdStruc->StdOut = hTmp;
+ StdStruc->Flags |= STDFLAG_OUT;
+ }
+ break;
+ }
+ }
+
+ if (EnableFlags & STDFLAG_ERR) {
+
+ pHand = &HandleTable[2];
+ IoVectorType = Od2GetVectorTypeForRedirection(pHand);
+
+ switch (IoVectorType) {
+
+ case RemoteVectorType:
+ if (pHand->NtHandle != SesGrp->StdErr) {
+ StdStruc->StdErr = pHand->NtHandle;
+ StdStruc->Flags |= STDFLAG_ERR;
+ }
+ break;
+
+ case FileVectorType:
+ case PipeVectorType:
+ case DeviceVectorType:
+ case ComVectorType:
+ if ((hTmp = Od2DupHandleForRedirection(pHand->NtHandle)) != NULL) {
+ StdStruc->StdErr = hTmp;
+ StdStruc->Flags |= STDFLAG_ERR | STDFLAG_CLOSEERR;
+ }
+ break;
+
+ case ScreenVectorType:
+ if (SesGrp->hConsoleOutput != SesGrp->StdOut) {
+ if ((hTmp = Od2DupHandleForRedirection(SesGrp->hConsoleOutput)) != NULL) {
+ StdStruc->StdErr = hTmp;
+ StdStruc->Flags |= STDFLAG_ERR | STDFLAG_CLOSEERR;
+ }
+ } else {
+ StdStruc->StdErr = SesGrp->hConsoleOutput;
+ StdStruc->Flags |= STDFLAG_ERR;
+ }
+ break;
+
+ case KbdVectorType:
+ if (SesGrp->hConsoleInput != SesGrp->StdIn) {
+ if ((hTmp = Od2DupHandleForRedirection(SesGrp->hConsoleInput)) != NULL) {
+ StdStruc->StdErr = hTmp;
+ StdStruc->Flags |= STDFLAG_ERR | STDFLAG_CLOSEERR;
+ }
+ } else {
+ StdStruc->StdErr = SesGrp->hConsoleInput;
+ StdStruc->Flags |= STDFLAG_ERR;
+ }
+ break;
+
+ case NulVectorType:
+ case LptVectorType:
+ case MouseVectorType:
+ case ClockVectorType:
+ case PointerVectorType:
+ case MonitorVectorType:
+ if ((hTmp = Ow2GetNulDeviceHandle()) != NULL) {
+ StdStruc->StdErr = hTmp;
+ StdStruc->Flags |= STDFLAG_ERR;
+ }
+ break;
+ }
+ }
+}
+
+
+VOID
+Od2CleanupStdHandleRedirection(
+ IN POS2_STDHANDLES StdStruc
+ )
+{
+ if (StdStruc->Flags & STDFLAG_CLOSEIN) {
+ NtClose(StdStruc->StdIn);
+ }
+
+ if (StdStruc->Flags & STDFLAG_CLOSEOUT) {
+ NtClose(StdStruc->StdOut);
+ }
+
+ if (StdStruc->Flags & STDFLAG_CLOSEERR) {
+ NtClose(StdStruc->StdErr);
+ }
+}
+
+
+NTSTATUS
+Od2IsFileConsoleType(
+ PSTRING NtImagePathName
+#if PMNT
+ ,
+ PULONG IsPMApp
+#endif // PMNT
+ )
+
+{
+ HANDLE FileHandle;
+ UNICODE_STRING Unicode;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PIO_STATUS_BLOCK pIoStatusBlock = &IoStatusBlock;
+ LARGE_INTEGER ByteOffset;
+ PVOID MemoryAddress;
+ ULONG RegionSize;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PIMAGE_DOS_HEADER pHeader;
+ PIMAGE_NT_HEADERS pPeHeader;
+ PCONFIGPHARLAP PharLapConfigured;
+ CONFIGPHARLAP PharLapBlockBuffer;
+ UCHAR String16stub[6];
+ UCHAR StringRational[36];
+ PUCHAR pb;
+ NTSTATUS Status;
+
+#if PMNT
+ *IsPMApp = 0;
+#endif // PMNT
+ Status = Or2MBStringToUnicodeString(&Unicode,
+ (PANSI_STRING)NtImagePathName,
+ (BOOLEAN)TRUE);
+ if (!NT_SUCCESS( Status )) {
+ goto thirdreturn;
+ }
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &Unicode,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(&FileHandle,
+ GENERIC_READ | FILE_READ_DATA | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ,
+ FILE_NON_DIRECTORY_FILE |
+ FILE_SYNCHRONOUS_IO_NONALERT);
+
+ if ( !NT_SUCCESS( Status ) ) {
+ goto thirdreturn;
+ }
+
+ MemoryAddress = 0;
+ RegionSize = 4*1024;
+ Status = NtAllocateVirtualMemory(NtCurrentProcess(),
+ &MemoryAddress,
+ 0,
+ &RegionSize,
+ MEM_RESERVE | MEM_COMMIT,
+ PAGE_READWRITE);
+
+ if ( !NT_SUCCESS( Status ) ) {
+ goto thirdreturn;
+ }
+
+
+ ByteOffset.LowPart = 0;
+ ByteOffset.HighPart = 0;
+ Status = NtReadFile(FileHandle,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ MemoryAddress,
+ 4*1024,
+ &ByteOffset,
+ 0);
+
+ if ( !NT_SUCCESS( Status ) ) {
+ goto secondreturn;;
+ }
+
+ pHeader = (PIMAGE_DOS_HEADER) MemoryAddress;
+
+ //
+ // The following EXE recognition code is adapted from ntos\mm\creasect.c
+ // Last updated on May 5th, 1993
+ //
+
+ if (pHeader->e_magic != IMAGE_DOS_SIGNATURE) {
+ Status = STATUS_INVALID_IMAGE_NOT_MZ;
+ goto firstreturn;
+ }
+
+ if (pHeader->e_lfarlc != (USHORT)0x40) {
+ Status = STATUS_INVALID_IMAGE_PROTECT;
+ goto firstreturn;
+ }
+
+ //
+ // Save the 6 bytes at Dosheader + 0x200 for a check later
+ //
+ RtlMoveMemory(&String16stub, (PUCHAR)pHeader + 0x200, 6);
+
+ //
+ // Save the 32 bytes at Dosheader + e_cparhdr << 4
+ //
+ if ((pb = (PUCHAR)((ULONG)pHeader + ((ULONG)pHeader->e_cparhdr << 4))) <
+ (PUCHAR)((ULONG)pHeader + 4*1024 - 0x30 - sizeof(USHORT)) ) {
+ pb += *(PUSHORT)(pb + 0x30);
+ if ((ULONG)pb < (ULONG)pHeader + 4*1024 - 36) {
+ RtlMoveMemory(&StringRational, pb, 36);
+ }
+ }
+
+ PharLapConfigured = (PCONFIGPHARLAP) ((ULONG)pHeader +
+ ((ULONG)pHeader->e_cparhdr << 4));
+
+ if ((ULONG)pHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS) > 4*1024) {
+
+ if ((ULONG)PharLapConfigured <
+ (ULONG)pHeader + 0x1000 - sizeof(CONFIGPHARLAP)) {
+ RtlMoveMemory(&PharLapBlockBuffer, PharLapConfigured, sizeof(CONFIGPHARLAP));
+ PharLapConfigured = &PharLapBlockBuffer;
+ } else {
+ PharLapConfigured = NULL;
+ }
+
+ ByteOffset.LowPart = (ULONG)pHeader->e_lfanew;
+ ByteOffset.HighPart = 0;
+ Status = NtReadFile(FileHandle,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ MemoryAddress,
+ 4*1024,
+ &ByteOffset,
+ 0);
+
+ if ( !NT_SUCCESS( Status ) ) {
+ Status = STATUS_INVALID_IMAGE_PROTECT;
+ goto firstreturn;
+ }
+ pPeHeader = (PIMAGE_NT_HEADERS) MemoryAddress;
+
+ }
+ else {
+
+ if ((ULONG)PharLapConfigured >=
+ (ULONG)pHeader + 0x1000 - sizeof(CONFIGPHARLAP)) {
+ PharLapConfigured = NULL;
+ }
+
+ pPeHeader = (PIMAGE_NT_HEADERS) ((ULONG) MemoryAddress +
+ (ULONG) pHeader->e_lfanew);
+ }
+
+ if (pPeHeader->Signature != IMAGE_NT_SIGNATURE) {
+
+ if ((USHORT)pPeHeader->Signature == (USHORT)IMAGE_OS2_SIGNATURE) {
+
+ if ((((PIMAGE_OS2_HEADER) pPeHeader)->ne_exetyp == 2) ||
+ ((((PIMAGE_OS2_HEADER) pPeHeader)->ne_exetyp == 0) &&
+ (((((PIMAGE_OS2_HEADER) pPeHeader)->ne_expver & 0xff00) ==
+ 0x200) ||
+ ((((PIMAGE_OS2_HEADER)pPeHeader)->ne_expver & 0xff00) ==
+ 0x300)))) {
+
+ Status = STATUS_INVALID_IMAGE_WIN_16;
+ goto firstreturn;
+ }
+
+ // This exetype is not documented anywhere, but exetype
+ // utility knows about it and tells us that exetype==5 means
+ // binary is for DOS4.0.....!!
+ // and an empty entry table also means DOS4.0
+ // so we give it to NTDOS.
+
+ if (((PIMAGE_OS2_HEADER)pPeHeader)->ne_exetyp == 5 ||
+ ((PIMAGE_OS2_HEADER)pPeHeader)->ne_enttab ==
+ ((PIMAGE_OS2_HEADER)pPeHeader)->ne_imptab )
+ {
+ Status = STATUS_INVALID_IMAGE_PROTECT;
+ goto firstreturn;
+ }
+
+ //
+ // Borland Dosx types: exe type 1
+ //
+ // - "new" Borland Dosx BP7.0
+ // exe type == 1
+ // DosHeader + 0x200 contains the string "16STUB"
+ // 0x200 happens to be e_parhdr*16
+ //
+
+ if (((PIMAGE_OS2_HEADER)pPeHeader)->ne_exetyp == 1 &&
+ RtlCompareMemory(String16stub, "16STUB", 6) == 6) {
+ Status = STATUS_INVALID_IMAGE_PROTECT;
+ goto firstreturn;
+
+ }
+
+
+ //
+ // Check for PharLap extended header which we run as a dos app.
+ // The PharLap config block is pointed to by the SizeofHeader
+ // field in the DosHdr.
+ // The following algorithm for detecting a pharlap exe
+ // was recommended by PharLap Software Inc.
+ //
+
+ if (PharLapConfigured != NULL) {
+
+ if (RtlCompareMemory(&PharLapConfigured->uchCopyRight[0x18],
+ "Phar Lap Software, Inc.", 24) == 24 &&
+ (PharLapConfigured->usSign == 0x4b50 || // stub loader type 2
+ PharLapConfigured->usSign == 0x4f50 || // bindable 286|DosExtender
+ PharLapConfigured->usSign == 0x5650 )) // bindable 286|DosExtender (Adv)
+ {
+ Status = STATUS_INVALID_IMAGE_PROTECT;
+ goto firstreturn;
+ }
+ }
+
+ //
+ // Check for Rational extended header which we run as a dos app.
+ // We look for the rational copyright at:
+ // wCopyRight = *(DosHeader->e_cparhdr*16 + 30h)
+ // pCopyRight = wCopyRight + DosHeader->e_cparhdr*16
+ // "Copyright (C) Rational Systems, Inc."
+ //
+
+ if (RtlCompareMemory(StringRational,
+ "Copyright (C) Rational Systems, Inc.",
+ 36) == 36 ) {
+ Status = STATUS_INVALID_IMAGE_PROTECT;
+ goto firstreturn;
+ }
+
+#if PMNT
+ if ((((PIMAGE_OS2_HEADER)pPeHeader)->ne_flags & 0x0300) == 0x0300) {
+ //
+ // Presentation manager application
+ //
+ *IsPMApp = 1;
+ }
+#endif //PMNT
+
+ Status = STATUS_INVALID_IMAGE_NE_FORMAT;
+ goto firstreturn;
+ }
+
+ if ((USHORT)pPeHeader->Signature == (USHORT)IMAGE_OS2_SIGNATURE_LE) {
+ Status = STATUS_INVALID_IMAGE_LE_FORMAT;
+ goto firstreturn;
+ }
+ } else {
+ if (pPeHeader->Signature == IMAGE_NT_SIGNATURE &&
+ pPeHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_OS2_CUI) {
+ Status = 0xdeadbeef;
+ } else {
+ Status = 0;
+ }
+ }
+
+firstreturn:
+ NtClose(FileHandle);
+
+secondreturn:
+ NtFreeVirtualMemory(NtCurrentProcess(),
+ &MemoryAddress,
+ &RegionSize,
+ MEM_RELEASE);
+
+thirdreturn:
+ RtlFreeUnicodeString(&Unicode);
+
+ return(Status);
+
+}
+
+VOID
+Od2FillErrorTextBuffer(
+ OUT PSZ ErrorText OPTIONAL,
+ IN LONG MaximumErrorTextLength,
+ IN PSZ Contents OPTIONAL
+ )
+{
+ if (ARGUMENT_PRESENT( ErrorText ) && MaximumErrorTextLength--){
+ if (ARGUMENT_PRESENT( Contents )) {
+ while (MaximumErrorTextLength--) {
+ if (*ErrorText = *Contents++) {
+ ErrorText++;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ *ErrorText = '\0';
+ }
+}
+
+
+APIRET
+Od2FormatPgmName(
+ OUT PSZ ErrorText OPTIONAL,
+ IN LONG MaximumErrorTextLength,
+ IN PCHAR *ImageFileName,
+ OUT PCHAR ImageFileBuffer
+ )
+{
+ APIRET rc = NO_ERROR;
+
+ if (!Od2IsAbsolutePath( *ImageFileName )) {
+ rc = DosSearchPath( SEARCH_CUR_DIRECTORY | SEARCH_ENVIRONMENT |
+ SEARCH_IGNORENETERRS,
+ "PATH",
+ *ImageFileName,
+ ImageFileBuffer,
+ CCHMAXPATH
+ );
+ if (rc != NO_ERROR) {
+ if (rc == ERROR_ENVVAR_NOT_FOUND) {
+ rc = ERROR_FILE_NOT_FOUND;
+ }
+
+ Od2FillErrorTextBuffer( ErrorText,
+ MaximumErrorTextLength,
+ *ImageFileName
+ );
+ }
+ else {
+ *ImageFileName = ImageFileBuffer;
+ }
+ }
+
+ return (rc);
+}
+
+#define SEARCH_FLAGS (SEARCH_CUR_DIRECTORY | SEARCH_ENVIRONMENT | SEARCH_IGNORENETERRS)
+
+APIRET
+DosAddExtensionAndSearchPath(
+// IN ULONG SearchFlags,
+// IN PSZ PathOrVariableName,
+ IN PSZ FileName,
+ OUT PBYTE Buffer
+// IN ULONG Length
+ )
+{
+ APIRET rc;
+ PSZ SearchPath;
+ PSZ PathName;
+ PSZ Path;
+ ULONG FileNameLen, PathLen;
+ CHAR FileBuf[4][ CCHMAXPATH+1 ];
+ int i;
+
+ for ( i = 0 ; i < 4 ; i++ )
+ {
+ strcpy(FileBuf[i], FileName);
+ }
+
+ strcat(FileBuf[0], ".com");
+ strcat(FileBuf[1], ".bat");
+ strcat(FileBuf[2], ".cmd");
+ strcat(FileBuf[3], ".exe");
+
+ //
+ // Validate the parameters
+ //
+
+// if (Length == 0) {
+// return( ERROR_BUFFER_OVERFLOW );
+// }
+//
+// if (SearchFlags & ~(SEARCH_CUR_DIRECTORY |
+// SEARCH_ENVIRONMENT |
+// SEARCH_IGNORENETERRS
+// )
+// ) {
+// return( ERROR_INVALID_PARAMETER );
+// }
+//
+// if (FileName == NULL) {
+// //
+// // Note that OS/2 does not check for this case until after the
+// // SEARCH_CUR_DIRECTORY logic, so OS/2 would GP fault if passed a null
+// // file name pointer and the SEARCH_CUR_DIRECTORY flag. Seems like a
+// // bug so we will check before we use the FileName pointer.
+// //
+//
+// return( ERROR_FILE_NOT_FOUND );
+// }
+
+ //
+ // Check the current directory first if requested.
+ // we pass Canonicalize the requested name.
+ //
+
+// if (SearchFlags & SEARCH_CUR_DIRECTORY) {
+// rc = SearchForPath( SearchFlags,
+// FileName,
+// Buffer,
+// Length
+// );
+//
+// if (rc != ERROR_SS_RETRY) {
+// return( rc );
+// }
+// }
+
+ for ( i = 0 ; i < 4 ; i++ )
+ {
+ rc = SearchForPath( SEARCH_FLAGS,
+ FileBuf[i],
+ Buffer,
+ CCHMAXPATH
+ );
+
+ if (rc != ERROR_SS_RETRY)
+ {
+ if (i == 3) // EXE only
+ {
+ return (rc);
+ } else
+ return( 1 );
+ }
+ }
+
+ if (Od2IsAbsolutePath( FileBuf[0] ))
+ {
+ return( 1 );
+ }
+
+ //
+ // If pass search path is an environment variable name, then get its
+ // value from the OS/2 Environment Block.
+ //
+
+// if (SearchFlags & SEARCH_ENVIRONMENT) {
+// rc = DosScanEnv( PathOrVariableName, &SearchPath );
+// if (rc != NO_ERROR) {
+// try {
+// *Buffer = '\0';
+// }
+// except( EXCEPTION_EXECUTE_HANDLER ) {
+// Od2ExitGP();
+// }
+// return( rc );
+// }
+// }
+// else {
+// SearchPath = PathOrVariableName;
+// }
+
+ rc = DosScanEnv( "PATH", &SearchPath );
+ if (rc != NO_ERROR)
+ {
+ return( rc );
+ }
+
+ //
+ // probe filename and path. figure out maximum length of combined
+ // filename and path
+ //
+
+ try {
+ FileNameLen = strlen( FileName ) + 4; // 4 for the extenstion (.exe)
+ PathLen = strlen( SearchPath );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // + 2 is for terminating nul and possible slash
+ //
+
+ PathName = RtlAllocateHeap( Od2Heap, 0, PathLen + FileNameLen + 2 );
+ if (!PathName) {
+#if DBG
+ KdPrint(("OS2: DosAddExtensionAndSearchPath out of heap memory, fail\n"));
+#endif
+ ASSERT( FALSE );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // for each element in search path, append filename and call FindFile.
+ //
+
+ while (*SearchPath) {
+
+#ifdef DBCS
+// MSKK Apr.09.1993 V-AkihiS
+ //
+ // find end of path element
+ //
+ Path = SearchPath;
+ while (*SearchPath && *SearchPath != ';') {
+ if (Ow2NlsIsDBCSLeadByte(*SearchPath, SesGrp->DosCP)) SearchPath++;
+ if (*SearchPath) SearchPath++;
+ }
+#else
+ // BUGBUG fix for DBCS
+ //
+ // find end of path element
+ //
+
+ for (Path = SearchPath;*SearchPath && *SearchPath != ';';SearchPath++) {
+ ;
+ }
+#endif
+ PathLen = SearchPath - Path;
+// if (PathLen != 0) {
+// RtlMoveMemory( PathName, Path, PathLen );
+// if (!ISSLASH( PathName[ PathLen-1 ] )) {
+// PathName[ PathLen ] = (CHAR)OBJ_NAME_PATH_SEPARATOR;
+//
+// //
+// // +1 is for terminating NUL
+// //
+//
+// RtlMoveMemory( PathName+PathLen+1, FileName, FileNameLen+1 );
+// }
+// else {
+//
+// //
+// // +1 is for terminating NUL
+// //
+//
+// RtlMoveMemory( PathName+PathLen, FileName, FileNameLen+1 );
+// }
+//
+// rc = SearchForPath( SearchFlags,
+// PathName,
+// Buffer,
+// Length
+// );
+//
+// if (rc != ERROR_SS_RETRY) {
+// return( rc );
+// }
+// }
+
+ if (PathLen != 0)
+ {
+ RtlMoveMemory( PathName, Path, PathLen );
+#ifdef DBCS
+// MSKK Apr.09.1993 V-AkihiS
+ //
+ // Determine whether the last char of PathName
+ // is slash or not.
+ //
+ {
+ ULONG i = 0;
+ BOOLEAN SlashFlag = FALSE;
+
+ while (i < PathLen) {
+ if (Ow2NlsIsDBCSLeadByte(PathName[i], SesGrp->DosCP)) {
+ SlashFlag = FALSE;
+ i++;
+ if (i < PathLen) {
+ i++;
+ }
+ } else {
+ if (ISSLASH(PathName[i])) {
+ SlashFlag = TRUE;
+ } else {
+ SlashFlag = FALSE;
+ }
+ i++;
+ }
+ }
+ if (!SlashFlag)
+ {
+ PathName[ PathLen++ ] = (CHAR)OBJ_NAME_PATH_SEPARATOR;
+ }
+ }
+#else
+ if (!ISSLASH( PathName[ PathLen-1 ] ))
+ {
+ PathName[ PathLen++ ] = (CHAR)OBJ_NAME_PATH_SEPARATOR;
+ }
+#endif
+
+ for ( i = 0 ; i < 4 ; i++ )
+ {
+ //
+ // +1 is for terminating NUL
+ //
+
+ RtlMoveMemory( PathName+PathLen, FileBuf[i], FileNameLen+1 );
+
+ rc = SearchForPath( SEARCH_FLAGS,
+ PathName,
+ Buffer,
+ CCHMAXPATH
+ );
+
+ if (rc != ERROR_SS_RETRY)
+ {
+ RtlFreeHeap( Od2Heap, 0, PathName );
+ if (i == 3) // EXE only
+ {
+ return (rc);
+ } else
+ return( 1 );
+ }
+ }
+ }
+
+ if (*SearchPath) { // point past ;
+ SearchPath++;
+ }
+ }
+
+ RtlFreeHeap( Od2Heap, 0, PathName );
+ return( ERROR_FILE_NOT_FOUND );
+}
+
+
+CHAR CmdStrUp[] = {"/C " };
+CHAR CmdStrLo[] = {"/c " };
+
+
+BOOLEAN
+Od2IsPgmCmd(
+ IN PSZ *ImageFileName,
+ IN PSZ Arguments OPTIONAL,
+ OUT PCHAR ImageFileBuffer,
+ OUT PSZ *CmdArguments,
+ OUT PHANDLE hRedirFile,
+ OUT PULONG RedirFileType,
+ OUT PULONG pRedirectionFlag,
+ IN ULONG SessionFlag,
+ OUT PSZ *CmdLineTruncationPoint
+ )
+{
+ CHAR CmdFileBuf[ CCHMAXPATH+1 ], *CmdFileName;
+ PSZ FileName = *ImageFileName;
+ CHAR c, *p, *p1, *NulPlace = NULL, *RedirFileName;
+ int i, ArgNum, CharNum;
+ BOOLEAN FindFullName;
+ ULONG RedirectionFlag = NO_REDIR, FileFlags;
+ APIRET rc;
+
+#if DBG
+ IF_OD2_DEBUG( TASKING )
+ {
+ KdPrint(("Od2IsPgmCmd: enter with File %s, Arg %s\n",
+ FileName, Arguments));
+ }
+#endif
+
+ *pRedirectionFlag = NO_REDIR;
+
+ /*
+ * 1. if no Arg - ignore
+ */
+
+ if (Arguments == NULL)
+ {
+ return( FALSE );
+ }
+
+ /*
+ * 2. if no FileName (NULL) - assume cmd (for StartSession)
+ * else
+ * ignore path and check if "cmd" or "cmd.exe"
+ */
+
+ if (FileName)
+ {
+ p = FileName;
+
+ while (c = *FileName++)
+ {
+ if (c == '/' || c == (CHAR)OBJ_NAME_PATH_SEPARATOR || c == ':')
+ {
+ p = FileName;
+ }
+ }
+
+ if(strnicmp(p, "cmd", 3) ||
+ (p[3] && (p[3] != ' ') && strnicmp(p+3, ".exe", 4)))
+ {
+ return( FALSE );
+ }
+ }
+
+ /*
+ * 3. check Arg: ignore 1st arg and check the 2nd to be "/c"
+ */
+
+ for ( p = Arguments, ArgNum = 0, CharNum = 0, c = *(p++); ; c = *(p++) )
+ {
+ if (!c && !p[0])
+ {
+ return( FALSE );
+ }
+
+ if (ArgNum == 1)
+ {
+ if ((c == CmdStrUp[CharNum]) || (c == CmdStrLo[CharNum]))
+ {
+ CharNum++;
+ if (CharNum == 3)
+ {
+ break;
+ }
+ } else
+ {
+ return( FALSE );
+ }
+ } else
+ {
+ if (!c || (c == ' ') || (c == '\t'))
+ {
+ ArgNum++ ;
+ }
+ }
+ }
+
+ /*
+ * 4. Arg: ignore more space's
+ * BUGBUG if Arg contains '"', '|', '&', '>', '<' or '^' - ignore
+ */
+
+ for ( c = *p ; (c == ' ') || (c == '\t') ; c = *(++p) );
+
+ if (c == '\0')
+ {
+ return( FALSE );
+ }
+
+ *CmdArguments = p ;
+
+ for ( ; c ; c = *(++p) )
+ {
+ if (( c == '|' ) || ( c == '&' ) ||
+ ( c == '<' ) || ( c == '^' ) || ( c == '"' ))
+ {
+ return( FALSE );
+ }
+
+ if ( c == '>' )
+ {
+ p1 = p;
+
+ /*
+ * skip over space's
+ */
+
+ for ( c = *(++p1) ; (c == ' ') || (c == '\t') ; c = *(++p1) );
+
+ if (!stricmp(p1, "NUL" ) && (p[-2] != '2'))
+ {
+ // found output redirected to NUL ( "> NUL" )
+
+ if(NulPlace != NULL)
+ {
+ // found one before
+
+ return ( FALSE );
+ }
+
+ NulPlace = p;
+
+ p1 += 3;
+
+ /*
+ * skip over space's
+ */
+
+ for ( c = *p1 ; (c == ' ') || (c == '\t') ; c = *(++p1) );
+
+ if (!c)
+ {
+ RedirectionFlag |= REDIR_NUL;
+ break;
+ } else
+ {
+ return ( FALSE );
+ }
+ } else
+ {
+ if(NulPlace != NULL)
+ {
+ return ( FALSE );
+ }
+
+ NulPlace = p;
+ RedirFileName = p1;
+ for ( c = *p1 ; c ; c = *(p1++) )
+ {
+ if (( c == '|' ) || ( c == '&' ) || ( c == '"' ) ||
+ ( c == '<' ) || ( c == '^' ) || ( c == '>' ))
+ {
+ return( FALSE );
+ }
+
+ if (( c == ' ' ) || ( c == '\t' ))
+ {
+ break;
+ }
+
+ if ( c == '\0' )
+ {
+ break;
+ }
+ }
+
+ for ( c = *p1 ; (c == ' ') || (c == ' ') ; c = *(++p1) );
+
+ if ( c != '\0')
+ {
+ return ( FALSE );
+ }
+
+ RedirectionFlag |= REDIR_FILE;
+ break;
+ }
+ }
+ }
+
+ /*
+ * 5. Arg: copy "new" filename to buffer
+ */
+
+ FindFullName = FALSE;
+
+ p = *CmdArguments;
+
+// // if the program name is quoted, remove them
+//
+// if (*p == '"')
+// {
+// p++ ;
+// }
+
+ for ( CharNum = 0, c = *p ;
+ (CharNum < CCHMAXPATH ) && (c != ' ') && (c != '\0') && (c != '\t') ;
+ CmdFileBuf[CharNum] = c, c = p[++CharNum] );
+
+ if (CharNum == CCHMAXPATH )
+ {
+ return( FALSE );
+ }
+
+// if (CmdFileBuf[CharNum - 1] == '"')
+// {
+// // if the program name is quoted, remove them
+//
+// CharNum-- ;
+// }
+
+ CmdFileBuf[CharNum] = '\0';
+
+ for ( i = CharNum ; i && (i > (CharNum - 4)) ; --i )
+ {
+ c = CmdFileBuf[i - 1];
+
+ if (c == '.')
+ {
+ FindFullName = TRUE;
+ break;
+ } else if (c == '/' || c == (CHAR)OBJ_NAME_PATH_SEPARATOR || c == ':')
+ {
+ break;
+ }
+ }
+
+ CmdFileName = CmdFileBuf;
+
+ if ( !FindFullName )
+ {
+// CmdFileBuf[CharNum++] = '.';
+// CmdFileBuf[CharNum++] = 'e';
+// CmdFileBuf[CharNum++] = 'x';
+// CmdFileBuf[CharNum++] = 'e';
+// CmdFileBuf[CharNum] = '\0';
+
+ if (DosAddExtensionAndSearchPath(
+ CmdFileName,
+ CmdFileBuf
+ ))
+ {
+ return( FALSE );
+ }
+ } else
+ {
+
+ if(Od2FormatPgmName(
+ NULL,
+ 0,
+ &CmdFileName,
+ CmdFileBuf))
+ {
+ return( FALSE );
+ }
+ }
+
+ if (RedirectionFlag & REDIR_FILE)
+ {
+ OBJECT_ATTRIBUTES Obja;
+ IO_STATUS_BLOCK IoStatus;
+ UNICODE_STRING NameString_U;
+ STRING NameString;
+ NTSTATUS Status;
+
+ rc = Od2Canonicalize(RedirFileName,
+ CANONICALIZE_FILE_DEV_OR_PIPE,
+ &NameString,
+ NULL,
+ &FileFlags,
+ RedirFileType
+ );
+
+ if ((rc != NO_ERROR)|| (FileFlags & CANONICALIZE_META_CHARS_FOUND))
+ {
+ if (rc == NO_ERROR && (FileFlags & CANONICALIZE_META_CHARS_FOUND))
+ {
+ RtlFreeHeap(Od2Heap, 0, NameString.Buffer);
+ }
+ return( FALSE );
+ }
+
+ //
+ // UNICODE conversion -
+ //
+
+ Status = Or2MBStringToUnicodeString(
+ &NameString_U,
+ &NameString,
+ (BOOLEAN)TRUE);
+
+ RtlFreeHeap(Od2Heap, 0, NameString.Buffer);
+
+ if (!NT_SUCCESS(Status))
+ {
+ return( FALSE );
+ }
+
+ InitializeObjectAttributes(&Obja,
+ &NameString_U,
+ OBJ_CASE_INSENSITIVE|OBJ_INHERIT,
+ NULL,
+ NULL);
+
+ Status = NtCreateFile(hRedirFile,
+ FILE_GENERIC_WRITE,
+ &Obja,
+ &IoStatus,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ,
+ FILE_OVERWRITE_IF,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE,
+ NULL,
+ 0L
+ );
+
+ RtlFreeUnicodeString (&NameString_U);
+
+ if (!NT_SUCCESS(Status))
+ {
+ return( FALSE );
+ }
+ }
+
+ strcpy(ImageFileBuffer, CmdFileName);
+ *ImageFileName = ImageFileBuffer;
+
+ if (RedirectionFlag != NO_REDIR)
+ {
+ //
+ // March 4 93 -- We used to truncate the the command line inside the user's
+ // buffer. This was wrong. Now, we record the truncation point instead,
+ // and truncate it later inside our own buffer.
+ //
+
+// *NulPlace++ = '\0';
+// *NulPlace = '\0';
+ *CmdLineTruncationPoint = NulPlace;
+
+ if (RedirectionFlag & REDIR_FILE)
+ {
+#if DBG
+ IF_OD2_DEBUG( TASKING )
+ {
+ KdPrint(("IsPgmCmd: found redirected file name %s\n",
+ RedirFileName));
+ }
+#endif
+ } else
+ {
+#if DBG
+ IF_OD2_DEBUG( TASKING )
+ {
+ KdPrint(("IsPgmCmd: found redirectd to NULL\n"));
+ }
+#endif
+ }
+ }
+
+#if DBG
+ IF_OD2_DEBUG( TASKING )
+ {
+ KdPrint(("Od2IsPgmCmd: exit with File %s, Arg %s\n",
+ CmdFileName, *CmdArguments));
+ }
+#endif
+
+ *pRedirectionFlag = RedirectionFlag;
+ return( TRUE );
+}
+
+APIRET
+Od2FormatExecPgmMessage(
+ OUT POS2_DOSEXECPGM_MSG a,
+ OUT POS2_CAPTURE_HEADER *CaptureBuffer,
+ OUT PNTSTATUS Od2IsConsoleTypeReturnStatus,
+#if PMNT
+ OUT PULONG IsPMApp,
+#endif // PMNT
+ OUT PSZ ErrorText OPTIONAL,
+ IN LONG MaximumErrorTextLength,
+ IN ULONG Flags,
+ IN OUT PSZ *VariablesBuffer,
+ IN OUT PSZ *ArgumentsBuffer,
+ IN PSZ *ImageFileName
+ )
+{
+ ULONG ArgumentsLength, VariablesLength, ImageNameLength;
+ ULONG MessageBufferPointers = 0;
+ ULONG AppVariablesLength;
+ ULONG ImageFileFlags, ImageFileType, RedirectedFileType;
+ ULONG RedirectionFlag = NO_REDIR, Win32CurDirsLength = 0;
+ ULONG Length, i, SessionFlag = Flags & 0x80000000;
+ PSZ s, stemp, CmdArguments, Win32CurDirs, Win32CurDirsStart;
+ PSZ CmdLineTruncationPoint = NULL;
+ STRING ImageFileString;
+ APIRET rc;
+ CHAR ImageFileBuffer[ CCHMAXPATH+1 ];
+ POS2_CAPTURE_HEADER LocalCaptureBuffer;
+ HANDLE hRedirFile = NULL;
+ BOOLEAN AddOs2LibPath;
+
+ Flags &= ~0x80000000;
+
+ //
+ // Call DosSearchPath if NOT absolute path spec.
+ //
+
+ ImageFileString.Length = 0;
+
+ rc = NO_ERROR;
+
+ try {
+ if(!(rc = Od2FormatPgmName(
+ ErrorText,
+ MaximumErrorTextLength,
+ ImageFileName,
+ ImageFileBuffer)))
+ {
+ if (Od2IsPgmCmd( ImageFileName,
+ *ArgumentsBuffer,
+ ImageFileBuffer,
+ &CmdArguments,
+ &hRedirFile,
+ &RedirectedFileType,
+ &RedirectionFlag,
+ SessionFlag,
+ &CmdLineTruncationPoint
+ ))
+ {
+ *ArgumentsBuffer = CmdArguments;
+ RedirectionFlag |= CMD_SHORTCUT;
+ } else
+ {
+
+ }
+ }
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ //
+ // Canonicalize image file name
+ //
+
+ rc = Od2Canonicalize( *ImageFileName,
+ CANONICALIZE_FILE_OR_DEV,
+ &ImageFileString,
+ NULL,
+ &ImageFileFlags,
+ &ImageFileType
+ );
+ if (rc != NO_ERROR) {
+ if (RedirectionFlag & REDIR_FILE)
+ {
+ NtClose(hRedirFile);
+ }
+ return( rc );
+ }
+
+ if (ImageFileType != FILE_TYPE_FILE && ImageFileType != FILE_TYPE_UNC) {
+ if (RedirectionFlag & REDIR_FILE)
+ {
+ NtClose(hRedirFile);
+ }
+ rc = ERROR_ACCESS_DENIED;
+ }
+ else
+ if (ImageFileFlags != 0) {
+ rc = ERROR_PATH_NOT_FOUND ;
+ }
+ else
+ if (Flags > EXEC_TRACETREE) {
+ rc = ERROR_INVALID_DATA;
+ }
+
+ if (rc != NO_ERROR) {
+ RtlFreeHeap( Od2Heap, 0, ImageFileString.Buffer );
+ if (RedirectionFlag & REDIR_FILE)
+ {
+ NtClose(hRedirFile);
+ }
+ return( rc );
+ }
+
+ RtlZeroMemory( a, sizeof( *a ) );
+
+ Length = (ULONG)ImageFileString.Length;
+#ifdef DBCS
+// MSKK Apr.12.1993 V-AkihiS
+ {
+ PSZ LastDelimiter;
+
+ stemp = LastDelimiter = &ImageFileString.Buffer[0];
+ i = 0;
+ while (i < Length) {
+ if (Ow2NlsIsDBCSLeadByte(*(stemp+i), SesGrp->DosCP)) {
+ i++;
+ if (i < Length) {
+ i++;
+ }
+ } else {
+ if ((*(stemp+i) == '\\') || (*(stemp+i) == '/') || (*(stemp+i) == ':')) {
+ LastDelimiter = stemp+i;
+ }
+ i++;
+ }
+ }
+
+ stemp = LastDelimiter;
+ if ((*stemp == '\\') || (*stemp == '/') || (*stemp == ':'))
+ {
+ stemp++;
+ }
+ }
+#else
+ stemp = &ImageFileString.Buffer[Length - 1];
+ for ( i = 0 ; i < Length ; i++, stemp-- )
+ {
+ if ((*stemp == '\\') || (*stemp == '/') || (*stemp == ':'))
+ {
+ stemp++;
+ break;
+ }
+ }
+#endif
+
+ if (i >= OS2_MAX_APPL_NAME)
+ {
+ i = OS2_MAX_APPL_NAME - 1;
+ }
+
+ strncpy(a->ApplName,
+ stemp,
+ i);
+
+ a->ApplName[i] = '\0';
+ a->ApplNameLength = i + 1;
+
+ a->CodePage = Od2ProcessCodePage;
+ a->Flags = Flags;
+ a->CurrentDrive = Od2CurrentDisk;
+ a->CmdLineFlag = RedirectionFlag;
+ if ( *VariablesBuffer == NULL ) {
+ *VariablesBuffer = Od2Environment;
+ }
+
+ Win32CurDirs = s = (PSZ)GetEnvironmentStrings();
+
+ //
+ // 1st measure the size of commitment needed, and commit it
+ //
+
+ //
+ // watch for the current directories (appear in environment
+ // in the form "=C:=C:\foo")
+ //
+
+
+ Win32CurDirsStart = NULL;
+ while (*s) {
+ if (*s == '=') {
+ Win32CurDirsStart = s;
+ break;
+ }
+ s++;
+ while (*s++) {
+ }
+ }
+
+ if (Win32CurDirsStart != NULL) {
+ while (*s) {
+ if (*s != '='){
+ Win32CurDirsLength = s - Win32CurDirsStart;
+ break;
+ }
+ s++;
+ while (*s++) {
+ }
+ }
+ if (Win32CurDirsLength == 0) {
+ Win32CurDirsLength = s - Win32CurDirsStart;
+ }
+ }
+
+ if (ErrorText == NULL || MaximumErrorTextLength == 0)
+ {
+ ErrorText = NULL;
+ MaximumErrorTextLength = 0;
+ } else
+ {
+ MessageBufferPointers += 1;
+ try {
+ RtlZeroMemory( ErrorText, MaximumErrorTextLength );
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ RtlFreeHeap( Od2Heap,0,ImageFileString.Buffer );
+ if (RedirectionFlag & REDIR_FILE)
+ {
+ NtClose(hRedirFile);
+ }
+ Od2ExitGP();
+ }
+ }
+
+ try {
+ s = *ArgumentsBuffer;
+
+ if (s != NULL) {
+ if (CmdLineTruncationPoint == NULL) {
+ if (SessionFlag)
+ {
+ // In session, copy till first NULL
+
+ while (*s) {
+ s++;
+ }
+ s++;
+ } else {
+ if (!*s){
+ s++;
+ }
+ while (*s) {
+ while (*s) {
+ s++;
+ }
+
+ s++;
+ }
+ s++;
+ }
+ } else {
+ s = CmdLineTruncationPoint + 2;
+ }
+ }
+ ArgumentsLength = s - *ArgumentsBuffer;
+
+ AddOs2LibPath = TRUE;
+
+ s = *VariablesBuffer;
+ if (s != NULL) {
+ while (*s) {
+
+ if (strnicmp(s, "OS2LIBPATH=", 11) == 0) {
+ AddOs2LibPath = FALSE;
+ }
+
+ while (*s) {
+ s++;
+ }
+ s++;
+ }
+ s++;
+ }
+ //
+ // add space for Os2LibPath=string0, and for Win32 CurrentDirectories
+ // e.g. =C:=C:\foo
+ //
+ AppVariablesLength = s - *VariablesBuffer;
+ VariablesLength = AppVariablesLength + Win32CurDirsLength;
+
+ if (AddOs2LibPath) {
+ VariablesLength += Od2LibPathLength + 11 + 1;
+ }
+
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ if (RedirectionFlag & REDIR_FILE)
+ {
+ NtClose(hRedirFile);
+ }
+ RtlFreeHeap(Od2Heap, 0,ImageFileString.Buffer);
+ Od2ExitGP();
+ }
+
+ LocalCaptureBuffer = Od2AllocateCaptureBuffer( MessageBufferPointers,
+ 0,
+ MaximumErrorTextLength
+ );
+ if (LocalCaptureBuffer == NULL) {
+ RtlFreeHeap( Od2Heap, 0, ImageFileString.Buffer );
+ RtlFreeHeap(RtlProcessHeap(), 0, Win32CurDirs);
+ if (RedirectionFlag & REDIR_FILE) {
+ NtClose(hRedirFile);
+ }
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ //
+ // prepare the FileName
+ //
+ ImageNameLength = ImageFileString.Length + 1;
+ stemp = ImageFileString.Buffer;
+ if ((*ImageFileName = RtlAllocateHeap(Od2Heap, 0, ImageNameLength)) == NULL)
+ {
+ Od2FreeCaptureBuffer( LocalCaptureBuffer );
+ RtlFreeHeap( Od2Heap, 0, ImageFileString.Buffer );
+ RtlFreeHeap(RtlProcessHeap(), 0, Win32CurDirs);
+ if (RedirectionFlag & REDIR_FILE) {
+ NtClose(hRedirFile);
+ }
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ if (ImageFileType == FILE_TYPE_UNC) {
+
+ stemp = ImageFileString.Buffer + 10; // skip over \OS2SS\UNC
+ ImageNameLength -= 10; // adjust length
+
+ **ImageFileName = '\\';
+
+ RtlMoveMemory((*ImageFileName) + 1,
+ stemp,
+ ImageNameLength
+ );
+ } else {
+ if ((s = strstr(ImageFileString.Buffer, ":")) != NULL)
+ {
+ s-- ;
+ ImageNameLength -= (s - ImageFileString.Buffer);
+ stemp = s;
+ }
+ RtlMoveMemory(*ImageFileName,
+ stemp,
+ ImageNameLength
+ );
+ }
+
+ *Od2IsConsoleTypeReturnStatus = Od2IsFileConsoleType(&ImageFileString
+#if PMNT
+ , IsPMApp
+#endif // PMNT
+ );
+
+ RtlFreeHeap( Od2Heap, 0, ImageFileString.Buffer );
+
+ //
+ // prepare the Arguments
+ //
+ if (ArgumentsLength)
+ {
+ if ((s = RtlAllocateHeap(Od2Heap, 0, ArgumentsLength)) == NULL)
+ {
+ Od2FreeCaptureBuffer( LocalCaptureBuffer );
+ RtlFreeHeap( Od2Heap, 0, *ImageFileName );
+ RtlFreeHeap(RtlProcessHeap(), 0, Win32CurDirs);
+ if (RedirectionFlag & REDIR_FILE) {
+ NtClose(hRedirFile);
+ }
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ RtlMoveMemory(
+ s,
+ *ArgumentsBuffer,
+ ArgumentsLength
+ );
+
+ if (CmdLineTruncationPoint != NULL) {
+ s[ArgumentsLength - 2] = '\0';
+ s[ArgumentsLength - 1] = '\0';
+ }
+
+ *ArgumentsBuffer = s;
+
+ //
+ // replace zeros in arguments with blanks, to be win32 like
+ // (if in session - then it's already blank, don't replace)
+
+ //
+ // changed on 6/12/92 -- truncates the command line at the second null.
+ // This was done because some programs (such as os/2 slick) don't
+ // put a double null at the end and leave some garbage there.
+ //
+
+ //
+ // look for '\0' (not at the end of the command line)
+ // and replace with space
+ //
+ if (!SessionFlag) {
+ while (*s) {
+ s++;
+ }
+
+ if (s[1] != '\0')
+ {
+ *s = ' ';
+ }
+ }
+
+ } else
+ {
+ *ArgumentsBuffer = NULL;
+ }
+
+ //
+ // prepare the Variables
+ //
+
+ if ((s = RtlAllocateHeap(Od2Heap, 0, VariablesLength)) == NULL)
+ {
+ RtlFreeHeap( Od2Heap, 0, *ArgumentsBuffer );
+ Od2FreeCaptureBuffer( LocalCaptureBuffer );
+ RtlFreeHeap(RtlProcessHeap(), 0, Win32CurDirs);
+ if (RedirectionFlag & REDIR_FILE) {
+ NtClose(hRedirFile);
+ }
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ stemp = *VariablesBuffer;
+ *VariablesBuffer = s;
+
+ //
+ // Start with Win32 CurrentDirectories (e.g. =C:=C:\foo)
+ //
+
+ if (Win32CurDirsStart != NULL) {
+ RtlMoveMemory(
+ s,
+ Win32CurDirsStart,
+ Win32CurDirsLength
+ );
+ s += Win32CurDirsLength;
+ }
+
+ //
+ // append app Variables
+ //
+
+ RtlMoveMemory(
+ s,
+ stemp,
+ AppVariablesLength
+ );
+
+ s += (AppVariablesLength - 1); // step on the last 0 of the variables
+
+ //
+ // append Os2LibPath=string0
+ //
+
+ if (AddOs2LibPath) {
+
+ //
+ // append os2libpath= to Variables
+ //
+ RtlMoveMemory(
+ s,
+ "Os2LibPath=",
+ 11);
+ s += 11;
+
+ //
+ // append the value of od2libpath
+ //
+ RtlMoveMemory(
+ s,
+ Od2LibPath,
+ Od2LibPathLength);
+ s+=Od2LibPathLength;
+ *s++=0;
+ *s=0;
+ }
+
+ if (ErrorText != NULL) {
+ Od2CaptureMessageString( LocalCaptureBuffer,
+ NULL,
+ 0,
+ MaximumErrorTextLength,
+ &a->ErrorText
+ );
+ }
+
+ if (RedirectionFlag & REDIR_FILE) {
+ a->hRedirectedFile = hRedirFile;
+ }
+
+ *CaptureBuffer = LocalCaptureBuffer;
+
+ switch (*Od2IsConsoleTypeReturnStatus) {
+ case STATUS_INVALID_IMAGE_NE_FORMAT:
+ case STATUS_INVALID_IMAGE_FORMAT:
+ case STATUS_OBJECT_NAME_NOT_FOUND:
+ case STATUS_OBJECT_PATH_NOT_FOUND:
+ break;
+
+ default:
+
+ // Executable is a Win32 program. We now look for config.sys on the command line and
+ // translate it to os2conf.nt if necessary
+
+ Od2TranslateConfigSysInCommandLine(ArgumentsBuffer);
+ }
+ RtlFreeHeap(RtlProcessHeap(), 0, Win32CurDirs);
+ return (NO_ERROR);
+}
+
+
+APIRET
+DosExecPgm(
+ OUT PSZ ErrorText OPTIONAL,
+ IN LONG MaximumErrorTextLength,
+ IN ULONG Flags,
+ IN PSZ Arguments OPTIONAL,
+ IN PSZ Variables OPTIONAL,
+ OUT PRESULTCODES ResultCodes,
+ IN PSZ ImageFileName
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSEXECPGM_MSG a = &m.u.DosExecPgm;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ THREAD_BASIC_INFORMATION ThreadInfo;
+ OS2_STDHANDLES StdStruc;
+ APIRET rc;
+ CHAR AlternateFileName[CCHMAXPATH];
+ HANDLE hThread, hProcess;
+ PSZ VariablesBuffer = Variables;
+ PSZ ArgumentsBuffer = Arguments;
+ PSZ ExecFileName = ImageFileName;
+ ULONG ExitCode;
+ ULONG dwProcessId;
+ ULONG i;
+ NTSTATUS Status;
+#if PMNT
+ ULONG IsPMApp;
+#endif // PMNT
+
+#if DBG
+ PSZ RoutineName;
+ RoutineName = "DosExecPgm";
+
+ IF_OD2_DEBUG( TASKING )
+ {
+ KdPrint(("%s: enter with File %s, Arg %s, Flag %lx\n",
+ RoutineName, ImageFileName, Arguments, Flags));
+ }
+#endif
+
+ if (SesGrp->PopUpFlag)
+ {
+#if DBG
+ KdPrint(("%s: illegal during POPUP\n", RoutineName));
+#endif
+ return( ERROR_VIO_ILLEGAL_DURING_POPUP );
+ }
+
+ try
+ {
+ if (!stricmp(ImageFileName, "C:\\OS2\\CMD.EXE"))
+ {
+ sprintf( AlternateFileName, "%s\\cmd.exe", Od2SystemRoot );
+#if DBG
+ KdPrint(("OS2SS: DosExecPgm convert c:\\os2\\cmd.exe to %s\n",
+ AlternateFileName));
+#endif
+ ImageFileName = AlternateFileName;
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER ){
+ Od2ExitGP();
+ }
+
+ if (Od2Process->Pib.Status & PS_EXITLIST) {
+ return( ERROR_INVALID_FUNCTION );
+ }
+
+ try {
+ Od2ProbeForWrite( (PVOID)ResultCodes, sizeof( *ResultCodes ), 1 );
+ } except( EXCEPTION_EXECUTE_HANDLER ){
+ Od2ExitGP();
+ }
+
+#if PMNT
+ if (ProcessIsPMShell() || ProcessIsPMShellChild())
+ {
+ // Make all sub-processes of PMSHELL run with no access to the
+ // Console. This way, they will not have the annoying "Wait",
+ // "End Task", "Cancel" pop-up
+ Flags = EXEC_BACKGROUND;
+ }
+#endif // PMNT
+
+ rc = Od2FormatExecPgmMessage( a,
+ &CaptureBuffer,
+ &Status,
+#if PMNT
+ &IsPMApp,
+#endif // PMNT
+ ErrorText,
+ MaximumErrorTextLength,
+ Flags,
+ &VariablesBuffer,
+ &ArgumentsBuffer,
+ &ExecFileName
+ );
+
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ // IMPORTANT -- don't modify Status between here and the next if
+
+ //
+ // we don't want to make a copy of the file handle table so we don't
+ // have to lock it during the call to the server because the file handles
+ // could go away while we're trying to dup them.
+ //
+
+ AcquireFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ a->FileSystemParameters.ParentHandleTable = HandleTable;
+ a->FileSystemParameters.ParentTableLength = HandleTableLength;
+ a->FileSystemParameters.CurrentDrive = Od2CurrentDisk;
+
+ //
+ // Create the Process, and wait to os2srv to get the results
+ // back to us by calling DosExecPgm
+ //
+
+ // Status comes from the call to Od2IsFileConsoleType (returned by Od2FormatExecPgmMessage)
+
+ if ((Status == STATUS_INVALID_IMAGE_NE_FORMAT) ||
+ (Status == STATUS_INVALID_IMAGE_FORMAT)) {
+ //
+ // 16 bit OS/2 program - Ow2execpgm creates it,
+ // Then we call os2srv to complete the job
+ //
+ rc = Ow2ExecPgm(
+ Flags,
+ ArgumentsBuffer,
+ VariablesBuffer,
+ ExecFileName,
+#if PMNT
+ IsPMApp,
+#endif // PMNT
+ NULL,
+ NULL,
+ &hProcess,
+ &hThread,
+ &dwProcessId
+ );
+
+ RtlFreeHeap( Od2Heap, 0, ArgumentsBuffer );
+ RtlFreeHeap( Od2Heap, 0, VariablesBuffer );
+ RtlFreeHeap( Od2Heap, 0, ExecFileName );
+
+ if (rc != NO_ERROR){
+#if DBG
+ KdPrint(("DosExecPgm: error returned from Ow2ExecPgm %d\n", rc));
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ NtClose(a->hRedirectedFile);
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ return(rc);
+ }
+
+ //
+ // duplicate process and thread handles for os2srv
+ //
+ if (!DuplicateHandle(
+ GetCurrentProcess(),
+ hProcess,
+ hOs2Srv,
+ &(a->hProcess),
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS
+ )){
+#if DBG
+ KdPrint(( "DosExecPgm: fail to duplicate process %d\n",GetLastError()));
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ NtClose(hProcess);
+ NtClose(hThread);
+ NtClose(a->hRedirectedFile);
+ return(ERROR_ACCESS_DENIED);
+ }
+ if (!DuplicateHandle(
+ GetCurrentProcess(),
+ hThread,
+ hOs2Srv,
+ &(a->hThread),
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS
+ )){
+#if DBG
+ KdPrint(( "DosExecPgm: fail to duplicate Thread %d\n",GetLastError()));
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ Od2CloseSrvHandle(1, a->hProcess, NULL, NULL);
+ NtClose(hProcess);
+ NtClose(hThread);
+ NtClose(a->hRedirectedFile);
+ return(ERROR_ACCESS_DENIED);
+ }
+
+ Status = NtQueryInformationThread(hThread,
+ ThreadBasicInformation,
+ (PVOID)(&ThreadInfo),
+ sizeof(ThreadInfo),
+ NULL
+ );
+ if (!NT_SUCCESS(Status)){
+#if DBG
+ KdPrint(( "DosExecPgm: fail to Query Information %lx\n",Status));
+#endif
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ Od2CloseSrvHandle(2, a->hProcess, a->hThread, NULL);
+ NtClose(hProcess);
+ NtClose(hThread);
+ NtClose(a->hRedirectedFile);
+ return(Or2MapNtStatusToOs2Error(
+ Status,ERROR_ACCESS_DENIED));
+ }
+
+ a->ClientId = ThreadInfo.ClientId;
+
+ if (a->hRedirectedFile)
+ {
+ HANDLE hRedirectedFile = a->hRedirectedFile;
+
+ if(!DuplicateHandle(
+ GetCurrentProcess(),
+ hRedirectedFile,
+ hProcess,
+ &a->hRedirectedFile,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS
+ )){
+#if DBG
+ KdPrint(( "DosExecPgm: fail to duplicate Redirecd File %d\n",GetLastError()));
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ Od2CloseSrvHandle(2, a->hProcess, a->hThread, NULL);
+ NtClose(hProcess);
+ NtClose(hThread);
+ NtClose(hRedirectedFile);
+ return(ERROR_ACCESS_DENIED);
+ }
+ NtClose(hRedirectedFile);
+ }
+
+ NtClose(hProcess);
+ NtClose(hThread);
+
+ a->Flags = Flags;
+ Od2CallSubsystem( &m, CaptureBuffer, Os2ExecPgm, sizeof( *a ) );
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ if (m.ReturnedErrorValue == NO_ERROR){
+ *ResultCodes = a->ResultCodes;
+ }
+
+ if (a->ErrorText.Length != 0) {
+ if ((LONG)(a->ErrorText.Length) < MaximumErrorTextLength) {
+ MaximumErrorTextLength = a->ErrorText.Length;
+ }
+ else {
+ MaximumErrorTextLength -= 1;
+ }
+
+ RtlMoveMemory( ErrorText, a->ErrorText.Buffer, MaximumErrorTextLength );
+ ErrorText[ MaximumErrorTextLength ] = '\0';
+ }
+
+ Od2FreeCaptureBuffer( CaptureBuffer );
+
+ return( m.ReturnedErrorValue );
+ }
+ else {
+ //
+ // Executable is NOT an os/2 16 bit program
+ //
+ if ((Status != STATUS_OBJECT_NAME_NOT_FOUND) &&
+ (Status != STATUS_OBJECT_PATH_NOT_FOUND)) {
+
+#if DBG
+ KdPrint(( "OS2: Loading a Win 32-bit program - %s\n", ExecFileName));
+#endif
+ switch( Flags ){
+ case EXEC_ASYNCRESULT:
+ // break;
+
+ case EXEC_BACKGROUND:
+ // break;
+
+ case EXEC_ASYNC:
+ // break;
+
+ case EXEC_SYNC:
+
+ //
+ // Let the win32 program have input
+ //
+ if (Flags == EXEC_SYNC){
+#if PMNT
+ if (! ProcessIsPMProcess()) {
+#endif
+ rc = Od2RemoveConsoleThread();
+ if (rc != NO_ERROR){
+#if DBG
+ KdPrint(("DosExecPgm: error returned from Od2RemoveConsoleThread %d\n", rc));
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ NtClose(a->hRedirectedFile);
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ RtlFreeHeap( Od2Heap, 0, ArgumentsBuffer );
+ RtlFreeHeap( Od2Heap, 0, VariablesBuffer );
+ RtlFreeHeap( Od2Heap, 0, ExecFileName );
+ return(rc);
+ }
+#if PMNT
+ } // endif !ProcessIsPMProcess()
+#endif
+ } else if (Flags == EXEC_ASYNCRESULT){
+
+ // add the info on the async Win32 child process
+
+ rc = Od2AddWin32ChildProcess();
+ if (rc != NO_ERROR){
+#if DBG
+ KdPrint(("DosExecPgm: error returned from Od2AddWin32ChildProcess %d\n", rc));
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ NtClose(a->hRedirectedFile);
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ RtlFreeHeap( Od2Heap, 0, ArgumentsBuffer );
+ RtlFreeHeap( Od2Heap, 0, VariablesBuffer );
+ RtlFreeHeap( Od2Heap, 0, ExecFileName );
+ return(rc);
+ }
+ }
+
+ if (a->hRedirectedFile) {
+ Od2PrepareStdHandleRedirection(STDFLAG_IN | STDFLAG_ERR, &StdStruc);
+ StdStruc.StdOut = a->hRedirectedFile;
+ StdStruc.Flags |= STDFLAG_OUT | STDFLAG_CLOSEOUT;
+ } else if (a->CmdLineFlag & REDIR_NUL) {
+ Od2PrepareStdHandleRedirection(STDFLAG_IN | STDFLAG_ERR, &StdStruc);
+ if ((StdStruc.StdOut = Ow2GetNulDeviceHandle()) != NULL) {
+ StdStruc.Flags |= STDFLAG_OUT;
+ }
+ } else {
+ Od2PrepareStdHandleRedirection(STDFLAG_ALL, &StdStruc);
+ }
+
+ rc = Ow2ExecPgm(
+ Flags | EXEC_WINDOW_PROGRAM, // This bit set the CREATE_NEW_PROCESS_GROUP and does redirection
+ ArgumentsBuffer,
+ VariablesBuffer,
+ ExecFileName,
+#if PMNT
+ 0, // Not PM app
+#endif // PMNT
+ NULL,
+ &StdStruc,
+ &hProcess,
+ &hThread,
+ &dwProcessId
+ );
+
+ //
+ // clean up redir stuff (will close a->hRedirectedFile if needed)
+ //
+
+ if (StdStruc.Flags & STDFLAG_CLOSEALL) {
+ Od2CleanupStdHandleRedirection(&StdStruc);
+ }
+
+ RtlFreeHeap( Od2Heap, 0, ArgumentsBuffer );
+ RtlFreeHeap( Od2Heap, 0, VariablesBuffer );
+ RtlFreeHeap( Od2Heap, 0, ExecFileName );
+ Od2FreeCaptureBuffer( CaptureBuffer );
+
+ if (rc != NO_ERROR){
+#if DBG
+ KdPrint(("DosExecPgm: error returned from Ow2ExecPgm %d\n", rc));
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ return(rc);
+ }
+ if (hThread)
+ {
+ if (ResumeThread( hThread) == (ULONG)-1)
+ {
+ rc = GetLastError();
+#if DBG
+ KdPrint(( "DosExecPgm: fail to Resume New Thread %l\n", rc));
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ NtClose(hProcess);
+ NtClose(hThread);
+ return(rc);
+ }
+ }
+
+ if (Flags != EXEC_SYNC){
+ //
+ // We need to return the PID to the caller at this point
+ //
+ ResultCodes->ExitReason = (ULONG)hProcess;
+
+ if (Flags == EXEC_ASYNCRESULT){
+ //
+ // remember the hprocess for DosWaitChild
+ //
+ for (i = 0;i<NUMOF32ASYNCPROC;i++){
+ if (Od2AsyncProc[i].hProcess == 0){
+ Od2AsyncProc[i].hProcess = hProcess;
+ Od2AsyncProc[i].dwProcessId = dwProcessId;
+ Od2AsyncProc[i].CreateSync = FALSE;
+ break;
+ }
+ }
+ if (i == NUMOF32ASYNCPROC ){
+#if DBG
+ KdPrint(( "DosExecPgm: Too many Async win32 processes\n"));
+ ASSERT(FALSE);
+#endif
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else rc = NO_ERROR;
+ }
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ NtClose(hThread);
+ return(rc);
+ }
+
+ for (i = 0;i<NUMOF32ASYNCPROC;i++)
+ {
+ if (Od2AsyncProc[i].hProcess == 0)
+ {
+ Od2AsyncProc[i].hProcess = hProcess;
+ Od2AsyncProc[i].dwProcessId = dwProcessId;
+ Od2AsyncProc[i].CreateSync = TRUE;
+ break;
+ }
+ }
+ if (i == NUMOF32ASYNCPROC ){
+#if DBG
+ ASSERT(FALSE);
+ KdPrint(( "DosExecPgm(Sync): Too many Async win32 processes\n"));
+#endif
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ //
+ // Wait for Completion and set Os/2 app parameters
+ //
+ do {
+ Status = NtWaitForSingleObject (
+ hProcess,
+ TRUE, // Alertable
+ NULL // Forever
+ );
+#if DBG
+ if (Status == STATUS_USER_APC) {
+ DbgPrint("[%d,%d] WARNING !!! DosExecPgm wait was broken by APC\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ );
+ }
+#endif
+ } while (Status == STATUS_USER_APC);
+ Od2AsyncProc[i].hProcess = 0;
+ if (!NT_SUCCESS(Status)){
+#if DBG
+ KdPrint(( "DosExecPgm: fail at WaitForSingleObject %lx\n",Status));
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ NtClose(hProcess);
+ NtClose(hThread);
+ return(Or2MapNtStatusToOs2Error(
+ Status,ERROR_ACCESS_DENIED));
+ }
+ GetExitCodeProcess(hProcess, &ExitCode);
+ Ow2WinExitCode2ResultCode(
+ ExitCode,
+ &ResultCodes->ExitResult,
+ &ResultCodes->ExitReason);
+
+ //
+ // Free the handles for the exec'ed process
+ //
+ NtClose(hProcess);
+ NtClose(hThread);
+
+#if DBG
+ if (ResultCodes->ExitResult != NO_ERROR){
+ KdPrint(("DosExecPgm: win32 process ExitCode %d => Result %d, Reason %d\n",
+ ExitCode, ResultCodes->ExitResult, ResultCodes->ExitReason));
+ }
+#endif
+#if PMNT
+ if (! ProcessIsPMProcess()) {
+#endif
+ //
+ // Restore session console mode
+ // A handle parameter is not needed
+ //
+ Status = Od2RestartConsoleThread();
+ if (!NT_SUCCESS(Status)){
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+#if DBG
+ KdPrint(( "DosExecPgm: fail to RestartConsoleThread %lx\n",Status));
+#endif
+ return(Or2MapNtStatusToOs2Error(Status,ERROR_ACCESS_DENIED));
+ }
+#if PMNT
+ }
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+
+ return(NO_ERROR);
+ break;
+
+ case EXEC_TRACETREE:
+ case EXEC_TRACE:
+ case EXEC_FROZEN:
+ default:
+
+#if DBG
+ ASSERT(FALSE);
+ KdPrint(("DosExecPgm with %s (%d) not supported\n",
+ (Flags == EXEC_TRACETREE) ? "EXEC_TRACETREE" :
+ (Flags == EXEC_TRACE) ? "EXEC_TRACE" :
+ (Flags == EXEC_FROZEN) ? "EXEC_FROZEN" :
+ "Unknown flag", Flags ));
+#endif
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ NtClose(a->hRedirectedFile);
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ RtlFreeHeap( Od2Heap, 0, ArgumentsBuffer );
+ RtlFreeHeap( Od2Heap, 0, VariablesBuffer );
+ RtlFreeHeap( Od2Heap, 0, ExecFileName );
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ }
+ else {
+ ReleaseFileLockShared(
+ #if DBG
+ RoutineName
+ #endif
+ );
+ NtClose(a->hRedirectedFile);
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ RtlFreeHeap( Od2Heap, 0, ArgumentsBuffer );
+ RtlFreeHeap( Od2Heap, 0, VariablesBuffer );
+ RtlFreeHeap( Od2Heap, 0, ExecFileName );
+
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
+#if DBG
+ KdPrint(( "OS2: EXE file not found - %s\n", ExecFileName));
+#endif
+ return(ERROR_FILE_NOT_FOUND);
+ } else if (Status == STATUS_OBJECT_PATH_NOT_FOUND) {
+#if DBG
+ KdPrint(( "OS2: Path to EXE file not found - %s\n", ExecFileName));
+#endif
+ return(ERROR_PATH_NOT_FOUND);
+ } else {
+#if DBG
+ KdPrint(( "OS2SRV: Program can not be executed %s\n",
+ ExecFileName));
+#endif
+ return(Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_PARAMETER));
+ }
+ }
+ }
+}
+
+VOID
+Od2DisableNewThread(VOID)
+{
+ NTSTATUS Status;
+
+ Status = Od2AlertableWaitForSingleObject(Od2NewThreadSync);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("ExitList: Wait for NewThreadSync, Status=%x\n",
+ Status);
+#endif // DBG
+ return;
+ }
+ Od2NewThreadDisabled = TRUE;
+ Status = NtReleaseMutant(
+ Od2NewThreadSync,
+ NULL);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("ExitList: Wait for NewThreadSync, Status=%x\n",
+ Status);
+ }
+#endif //DBG
+}
+
+//
+// Find address of TEB backup for thread1. We use it to restore TEB for
+// exit list dispatcher.
+//
+
+PVOID
+Od2GetThread1TebBackup(VOID)
+{
+ POD2_THREAD Thread;
+
+ Thread = Od2FindThreadById(1L);
+ if (Thread == NULL) {
+#if DBG
+ DbgPrint("Od2GetThread1Teb: Can't find thread1 in client\n");
+ ASSERT(FALSE);
+#endif // DBG
+ return NULL;
+ }
+ return (PVOID) &(Thread->Os2Tib.TebBackupIn16Bit);
+}
+
+
+VOID
+Od2ExitListDispatcher( VOID )
+{
+ ULONG i;
+ LARGE_INTEGER timeout;
+ NTSTATUS Status;
+
+#if DBG
+ IF_OD2_DEBUG( CLEANUP ) {
+ KdPrint(("ExitListDispatcher\n"));
+ }
+#endif
+
+ //
+ // See if we need to restore the real TEB (thread1 was caught in 16 bit
+ // when Exit has to happen). This check is part of RestoreTebForThread1 (fs:36).
+ // We can't use regulare RestoreTeb function, because it uses pointer to
+ // TEB backup that might be invalid already. We use that we know that we are
+ // in thread1, so we know the proper address of TEB backup.
+ //
+
+ RestoreTebForThread1();
+
+ ((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Os2Tib.LInfoSeg.rfProcStatus |= PS_EXITLIST;
+
+ if (!(Od2Process->Pib.Status & PS_EXITLIST)) {
+ Od2Process->Pib.Status |= PS_EXITLIST;
+ }
+ else {
+ //
+ // An exception happened while processing exitlist, cleanup
+ // and die
+ //
+ Od2FinalProcessCleanup();
+ Ow2Exit(306, NULL, 1); // 306 is IDS_INTERNAL_OS2_ERROR
+ }
+
+ //
+ // free locks so 16bit exit routines can
+ // call APIs that acquire the locks, in case this thread
+ // was holding the lock
+ //
+
+ // This var was used to tell sign that there is exit list processing
+ Od2SigHandlingInProgress = TRUE;
+ // This is the new var that really means that there is signal handle
+ // processing. DosSuspendThread and DosEnterCritSect will be actually
+ // disabled during exitlist processing.
+ Od2SigHandAlreadyInProgress = TRUE;
+ Od2Process->Pib.SigHandInProgress = TRUE;
+
+ //
+ // In we got a signal while having the garbage collection semaphore, free it
+ // so exitlist routines can call sem apis
+ //
+ (VOID)NtReleaseSemaphore (
+ Od2GarbageCollectSem,
+ 1,
+ NULL);
+
+ // Call to NtTestAlert to avoid ALERT on any wait that follows
+
+ Status = NtTestAlert();
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d] Od2ExitListDispatcher: NtTestAlert() = %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status);
+ }
+#endif // DBG
+
+ Od2DisableNewThread();
+
+ if (SesGrp->InTermination & 2)
+ {
+ for ( i = 0 ; i < NUMOF32ASYNCPROC ; i++ )
+ {
+ if (Od2AsyncProc[i].hProcess != 0)
+ {
+ GenerateConsoleCtrlEvent(
+ CTRL_BREAK_EVENT,
+ Od2AsyncProc[i].dwProcessId
+ );
+
+ NtTerminateProcess( Od2AsyncProc[i].hProcess, STATUS_SUCCESS );
+ timeout.LowPart = 0xf4240; // wait max 0.1 second for process to die
+ timeout.HighPart = 0;
+ NtWaitForSingleObject( Od2AsyncProc[i].hProcess, (BOOLEAN)TRUE, &timeout );
+ NtClose(Od2AsyncProc[i].hProcess);
+ Od2AsyncProc[i].hProcess = 0;
+
+ // BUGBUG: do we need to call Od2RemoveWin32ChildProcess for each one ??
+ }
+ }
+ }
+
+ DosExitList( EXLST_EXIT, NULL );
+}
+
+VOID
+Od2FinalProcessCleanup( VOID )
+{
+ if (timing)
+ {
+ printf("Os2 time at start of Od2FinalProcessCleanup is %d\n", (GetTickCount()) - timing);
+ }
+
+ //
+ // Stop all timer threads
+ //
+ Od2CloseAllTimers();
+
+ //
+ // Stop the Netbios component
+ //
+
+ Od2NetbiosDelete();
+
+ //
+ // Stop the Disk IoCtl component.
+ //
+
+ Od2DiskIOTerminate();
+
+
+ //
+ // Okay to release this as we must be the only client thread left
+ //
+
+ ReleaseTaskLock();
+
+ //
+ // Cleanup 16 bit RAM semaphores in shared memory
+ //
+
+ Od2CloseAllRAMSharedSemaphores();
+
+ //
+ // Close any open semaphpre handles
+ //
+
+ Od2CloseAllSemaphores();
+
+ //
+ // Close any open queue handles
+ //
+
+ Od2CloseAllQueues();
+
+
+ //
+ // Delete all the critical sections.
+ //
+
+ NtClose( Od2Process->TaskLock );
+ RtlDeleteResource( &Od2Process->FileLock );
+ RtlDestroyHeap( Od2Heap );
+ RtlDestroyHeap( Od2PortHeap );
+
+ if (timing)
+ {
+ printf("Os2 time at end of Od2FinalProcessCleanup is %d\n", (GetTickCount()) - timing);
+ }
+}
+
+
+APIRET
+Od2ExitList(
+ ULONG OrderCode,
+ PFNEXITLIST ExitRoutine,
+ BOOLEAN flag /* TRUE for 32-bit exit list routine */
+ )
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_EXITLISTENTRY ExitListEntry;
+ POS2_EXITLISTENTRY NewExitListEntry;
+ APIRET rc;
+ ULONG Order;
+ ULONG Action;
+ OS2_API_MSG m;
+ POS2_TERMINATEPROCESS_MSG a = &m.u.TerminateProcess;
+
+#if DBG
+ IF_OD2_DEBUG( CLEANUP ) {
+ KdPrint(("Od2ExitList\n"));
+ }
+#endif
+ //
+ // Format of the OrderCode is as follows:
+ //
+ // 33222222222211111111110000000000
+ // 10987654321098765432109876543210
+ //
+ // RRRRRRRRRRRRRRRRoooooooopRRRRRaa
+ //
+ // R = Reserver bit, must be zero
+ //
+ // aa = Action
+ // 0 - illegal
+ // 1 - add address to termination list
+ // 2 - remove address from termination list
+ // 3 - transfer to next address on termination list
+ //
+ // p = Position
+ // 0 - first // In native OS2 it is strongly the opposite.
+ // 1 - last // So :
+ // // 0 - last
+ // // 1 - first
+ // // [yosefd] 12/27/93
+ //
+ // oooooooo - Order within position
+ //
+
+ //
+ // Error if any of the reserved bits are set
+ //
+
+ //BUGBUG - Why disallow p bit set ??? if (OrderCode & 0xFFFF00FC)
+ if (OrderCode & 0xFFFF007C)
+ {
+ return( ERROR_INVALID_DATA );
+ }
+
+ //
+ // Isolate Action and Order components. Translate Position bit by
+ // adding x0100 to the 8 bit order code.
+ //
+
+ Action = OrderCode & 0x007F;
+ Order = (OrderCode & 0xFF00) >> 8;
+ if (Action == EXLST_ADD) {
+ if (!(OrderCode & 0x0080))
+ Order += 0x0100;
+ }
+ //
+ // Error if Order and/or Position specified and not adding an exit list
+ // routine.
+ //
+ else if (Order != 0) return( ERROR_INVALID_DATA );
+
+ //
+ // Now lock the process while we grovel the list of installed exit list
+ // handlers.
+ //
+
+#if DBG
+ IF_OD2_DEBUG( CLEANUP ) {
+ KdPrint(("Od2ExitList before task lock\n"));
+ }
+#endif
+ AcquireTaskLock();
+#if DBG
+ IF_OD2_DEBUG( CLEANUP ) {
+ KdPrint(("Od2ExitList after task lock\n"));
+ }
+#endif
+
+ ListHead = &Od2Process->ExitList;
+ ListNext = ListHead->Flink;
+ rc = NO_ERROR;
+ switch( Action ) {
+ case EXLST_ADD:
+ //
+ // Adding an exit list routine. Search the list of installed
+ // handlers to find out where to insert the new one. Return
+ // an error if the handler is already installed.
+ //
+
+ while (ListNext != ListHead) {
+ ExitListEntry = CONTAINING_RECORD( ListNext, OD2_EXITLISTENTRY, Link );
+ if (Order <= ExitListEntry->Order) {
+ if (ExitListEntry->Order == Order &&
+ ExitListEntry->ExitRoutine == ExitRoutine
+
+ ) {
+ rc = ERROR_ALREADY_EXISTS;
+ break;
+ }
+ else {
+ break;
+ }
+ }
+ ListNext = ListNext->Flink;
+ }
+
+ //
+ // If not a duplicate entry, then allocate the memory for a new
+ // entry and link it into the list.
+ //
+
+ if (rc == NO_ERROR) {
+ NewExitListEntry = RtlAllocateHeap( Od2Heap, 0,
+ sizeof( OD2_EXITLISTENTRY )
+ );
+ if (NewExitListEntry == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else {
+ NewExitListEntry->Order = Order;
+ NewExitListEntry->ExitRoutine = ExitRoutine;
+ NewExitListEntry->flag = flag;
+ InsertTailList( ListNext, &NewExitListEntry->Link );
+ }
+ }
+
+ break;
+
+ case EXLST_REMOVE:
+ //
+ // Deleting an exit list routine. Search the list for the
+ // routine. If found remove it from the list. Otherwise
+ // return an error.
+ //
+
+ while (ListNext != ListHead) {
+ ExitListEntry = CONTAINING_RECORD( ListNext, OD2_EXITLISTENTRY, Link );
+ if (ExitListEntry->ExitRoutine == ExitRoutine) {
+ RemoveEntryList( &ExitListEntry->Link );
+ ListNext = NULL;
+ break;
+ }
+
+ ListNext = ListNext->Flink;
+ }
+
+ if (ListNext != NULL) {
+ rc = ERROR_PROC_NOT_FOUND;
+ }
+ break;
+
+ case EXLST_EXIT:
+ //
+ // Calling the next entry in the exit list. Remove the head of
+ // the list, free the memory for the entry and then modify our
+ // return context so we return to the next exitlist routine
+ // Error if this function is called and the current process is
+ // NOT exiting.
+ //
+
+ if (Od2Process->Pib.Status & PS_EXITLIST) {
+#if PMNT
+ // Can the exit list routines in the case of PMSHELL. They hang
+ // and they probably aren't meant to be executed anyway under
+ // OS/2 since PMSHELL is not supposed to actually exit.
+ if ((ListNext == ListHead) ||
+ ProcessIsPMShell()) {
+#else
+ if (ListNext == ListHead) {
+#endif // not PMNT
+
+Really_lets_exit:
+ a->ExitResult = Od2Process->ResultCodes.ExitResult;
+ a->ExitReason = Od2Process->ResultCodes.ExitReason;
+
+ //
+ // All done, okay to exit. Need to do final process
+ // cleanup and call the server to have it nuke us.
+ //
+ Od2FinalProcessCleanup();
+
+ if (Od2ExecPgmErrorTextLength != 0) {
+ strncpy((PSZ) &a->ErrorText,
+ Od2ExecPgmErrorText,
+ Od2ExecPgmErrorTextLength);
+ }
+ a->ErrorText[Od2ExecPgmErrorTextLength] = '\0';
+
+#if DBG
+ IF_OD2_DEBUG( CLEANUP ) {
+ KdPrint(("Od2ExitList, calling InternalTerminateProcess\n"));
+ }
+#endif
+ // free process and thread
+ Od2CallSubsystem( &m,
+ NULL,
+ Oi2TerminateProcess,
+ sizeof( *a ) );
+
+ Od2InfiniteSleep();
+ }
+ else {
+ ListNext = RemoveHeadList( &Od2Process->ExitList );
+ ExitListEntry = CONTAINING_RECORD( ListNext, OD2_EXITLISTENTRY, Link );
+ ReleaseTaskLock();
+#if DBG
+ IF_OD2_DEBUG( CLEANUP ) {
+ KdPrint(("Od2ExitList, Going to jump to 16 bit exit list\n"));
+ }
+#endif
+ if (Od2Process->Pib.Killed) {
+ Od2Process->ResultCodes.ExitReason = TC_KILLPROCESS;
+ }
+
+ if (ExitListEntry->flag) {
+ Od2JumpToExitRoutine( ExitListEntry->ExitRoutine,
+ Od2Process->ResultCodes.ExitReason
+ );
+ }
+ else {
+ if (Od2Start16Stack && Od2Start16DS) {
+ Od2JumpTo16ExitRoutine(ExitListEntry->ExitRoutine,
+ Od2Process->ResultCodes.ExitReason
+ );
+ }
+ else {
+ //
+ // Loader failed, but C startup registered
+ // an ExitList rouine. Need to realy quit
+ //
+ goto Really_lets_exit;
+ ASSERT(FALSE); // Should never get here
+ }
+ }
+ }
+ }
+ else {
+ rc = ERROR_INVALID_FUNCTION;
+ }
+ break;
+
+ default:
+ rc = ERROR_INVALID_FUNCTION;
+ }
+
+ //
+ // Unlock the process and return the return code. Note that the code
+ // for the EXTLST_EXIT case will have modified the return address
+ // to point to the next exit list handler or to a stub that will
+ // really terminate the process.
+ //
+
+ ReleaseTaskLock();
+ return( rc );
+}
+
+APIRET
+DosExitList(
+ ULONG OrderCode,
+ PFNEXITLIST ExitRoutine
+ )
+{
+ return( Od2ExitList( OrderCode, ExitRoutine, (BOOLEAN)TRUE ) );
+}
+
+
+APIRET
+DosKillProcess(
+ IN ULONG KillTarget,
+ IN PID ProcessId
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSKILLPROCESS_MSG a = &m.u.DosKillProcess;
+ ULONG i;
+ HANDLE hProcess = (HANDLE)ProcessId;
+ LARGE_INTEGER timeout;
+ PLARGE_INTEGER ptimeout = &timeout;
+
+ if (KillTarget > DKP_PROCESS) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ if (ProcessId == 0) {
+ return( ERROR_INVALID_PROCID );
+ }
+ //
+ // see if this is a win32 process
+ //
+
+ for (i = 0;i<NUMOF32ASYNCPROC;i++){
+ //if ((Od2AsyncProc[i].hProcess == hProcess) && !Od2AsyncProc[i].CreateSync){
+ if (Od2AsyncProc[i].hProcess == hProcess){
+ Od2AsyncProc[i].hProcess = 0;
+ break;
+ }
+ }
+
+ if (i < NUMOF32ASYNCPROC){
+ //
+ // it is a win32 process -
+ // don't involve os2srv , just kill it
+ //
+
+ if ( KillTarget == DKP_PROCESSTREE )
+ {
+ // kill process tree - try to do it by issue GenerateConsoleCtrlEvent
+
+ GenerateConsoleCtrlEvent(
+ CTRL_BREAK_EVENT,
+ Od2AsyncProc[i].dwProcessId
+ );
+ }
+
+ NtTerminateProcess( hProcess, STATUS_SUCCESS );
+ timeout.LowPart = 0x989680; // wait max one second for process to die
+ timeout.HighPart = 0;
+ NtWaitForSingleObject( hProcess, (BOOLEAN)TRUE, ptimeout );
+ NtClose(hProcess);
+ Od2RemoveWin32ChildProcess();
+ return(NO_ERROR);
+ }
+
+ a->KillTarget = KillTarget;
+ a->ProcessId = ProcessId;
+
+ return( Od2CallSubsystem( &m, NULL, Os2KillProcess, sizeof( *a ) ) );
+}
+
+
+
+APIRET
+DosSetPriority(
+ IN ULONG Scope,
+ IN ULONG Class,
+ IN LONG Delta,
+ IN ULONG TargetId
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSSETPRIORITY_MSG a = &m.u.DosSetPriority;
+
+ if (Scope > PRTYS_THREAD) {
+ return( ERROR_INVALID_SCOPE );
+ }
+
+ if (Class > PRTYC_FOREGROUNDSERVER) {
+ return( ERROR_INVALID_PCLASS );
+ }
+
+ if (Delta < PRTYD_MINIMUM || Delta > PRTYD_MAXIMUM) {
+ return( ERROR_INVALID_PDELTA );
+ }
+
+ a->Scope = Scope;
+ a->Class = Class;
+ a->Delta = Delta;
+ a->TargetId = TargetId;
+
+ return( Od2CallSubsystem( &m, NULL, Os2SetPriority, sizeof( *a ) ) );
+}
+
+
+APIRET
+DosGetPriority(
+ IN ULONG Scope,
+ OUT PUSHORT Priority,
+ IN ULONG TargetId
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSGETPRIORITY_MSG a = &m.u.DosGetPriority;
+ APIRET rc;
+
+ if (Scope > PRTYS_THREAD) {
+ return( ERROR_INVALID_SCOPE );
+ }
+
+ try {
+ *Priority = 0;
+ }
+ except (EXCEPTION_EXECUTE_HANDLER) {
+ Od2ExitGP();
+ }
+
+ a->Scope = Scope;
+ a->TargetId = TargetId;
+
+ rc = Od2CallSubsystem( &m, NULL, Os2GetPriority, sizeof( *a ) );
+
+ if (rc == NO_ERROR) {
+ *Priority = (USHORT) a->Priority;
+ }
+ return(rc);
+}
+
+
+APIRET
+DosScanEnv(
+ IN PSZ VariableName,
+ OUT PSZ *VariableValue
+ )
+{
+ PCH s;
+ STRING SearchName;
+ STRING CurrentName;
+
+ //
+ // Get the address of the OS/2 Environment block from the OS/2
+ //
+ s = Od2Environment;
+ //
+ // Construct a counted string that describes the environment variable
+ // name we are looking for.
+ //
+
+ try {
+ RtlInitString( &SearchName, VariableName );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Loop over all of the null terminated strings in the environment
+ // block. A null character marks the end of the environment strings.
+ //
+ while (*s) {
+ //
+ // For each null terminated environment string, construct a counted
+ // string that describes the variable name portion (the part before
+ // the equal sign).
+ //
+
+ CurrentName.Buffer = s;
+ while (*s) {
+ if (*s == '=') {
+ CurrentName.Length = (USHORT) (s - CurrentName.Buffer);
+ CurrentName.MaximumLength = CurrentName.Length;
+
+ //
+ // Compare this variable name with what we are looking for,
+ // sensitive to case. If found, then return a pointer to
+ // value portion of the string which is the first character
+ // after the equal sign.
+ //
+
+ if (RtlEqualString( &CurrentName, &SearchName, (BOOLEAN)FALSE )) {
+ try {
+ *VariableValue = s + 1;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return( NO_ERROR );
+ }
+
+ //
+ // Move to the null character that terminates the variable
+ // value string. Then break out to the outer loop to find
+ // the next variable name.
+ //
+
+ while (*s) {
+ s++;
+ }
+
+ break;
+ }
+ else {
+ s++;
+ }
+ }
+
+ //
+ // Skip over the terminating null character for this string.
+ //
+
+ s++;
+ }
+
+ //
+ // If we get here, then we did not find the variable name we were looking
+ // for. Return the appropriate error code.
+ //
+
+ return( ERROR_ENVVAR_NOT_FOUND );
+}
+
+
+BOOLEAN
+CheckIfTerminalNetError(
+ IN APIRET ErrorCode,
+ IN ULONG SearchFlags
+ )
+{
+ if (ErrorCode == ERROR_FILE_NOT_FOUND ||
+ ErrorCode == ERROR_PATH_NOT_FOUND ||
+ ErrorCode == ERROR_NO_MORE_FILES ||
+ ErrorCode == ERROR_FILENAME_EXCED_RANGE
+ ) {
+ return( FALSE );
+ }
+
+ if (!(SearchFlags & SEARCH_IGNORENETERRS)) {
+ return( TRUE );
+ }
+
+ if (ErrorCode == ERROR_INVALID_ACCESS ||
+#if 0
+ ErrorCode == ERROR_NETWORK_BUSY ||
+ ErrorCode == ERROR_TOO_MANY_CMDS ||
+ ErrorCode == ERROR_ADAP_HDW_ERR ||
+ ErrorCode == ERROR_BAD_NET_RESP ||
+ ErrorCode == ERROR_UNEXP_NET_ERR ||
+ ErrorCode == ERROR_BAD_REM_ADAP ||
+ ErrorCode == ERROR_NETNAME_DELETED ||
+ ErrorCode == ERROR_BAD_DEV_TYPE ||
+ ErrorCode == ERROR_TOO_MANY_SESS ||
+ ErrorCode == ERROR_REQ_NOT_ACCEP ||
+#endif
+ ErrorCode == ERROR_INVALID_PASSWORD ||
+ ErrorCode == ERROR_VC_DISCONNECTED
+ ) {
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
+
+APIRET
+FindFile(
+ IN PSZ FileName
+ )
+{
+ APIRET rc;
+ HDIR SearchHandle;
+ FILEFINDBUF3 FindBuffer;
+ ULONG Entries;
+
+ Entries = 1;
+ SearchHandle = (HDIR) HDIR_CREATE; // allocate a new handle
+ rc = DosFindFirst( FileName,
+ &SearchHandle,
+ ATTR_ALL,
+ &FindBuffer,
+ sizeof(FindBuffer),
+ &Entries,
+ FIL_STANDARD
+ );
+ if (rc == NO_ERROR) {
+ DosFindClose(SearchHandle);
+ }
+
+ return( rc );
+}
+
+
+APIRET
+SearchForPath(
+ IN ULONG SearchFlags,
+ IN PSZ PathName,
+ OUT PBYTE Buffer,
+ IN ULONG Length
+ )
+{
+ APIRET rc;
+ STRING PathBuffer;
+ ULONG PathType;
+ ULONG PathFlags;
+ PCH src;
+ ULONG len;
+
+ rc = FindFile( PathName );
+ if (rc != NO_ERROR) {
+ if (CheckIfTerminalNetError( rc, SearchFlags )) {
+ try {
+ *Buffer = '\0';
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return( rc );
+ }
+ else {
+ rc = ERROR_SS_RETRY;
+ }
+ }
+ else {
+
+ //
+ // Canonicalize( filename)
+ //
+
+ rc = Od2Canonicalize( PathName,
+ CANONICALIZE_FILE_OR_DEV,
+ &PathBuffer,
+ NULL,
+ &PathFlags,
+ &PathType
+ );
+ if (rc == NO_ERROR) {
+ if (PathBuffer.Length >= (USHORT) Length) {
+ rc = ERROR_BUFFER_OVERFLOW;
+ }
+ else {
+ src = PathBuffer.Buffer;
+ len = PathBuffer.Length;
+ if (!strnicmp( src, "\\OS2SS\\DRIVES\\", 14 )) {
+ src += 14;
+ len -= 14;
+ }
+
+ try {
+ RtlMoveMemory( Buffer, src, len+1 );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ }
+
+ RtlFreeHeap(Od2Heap, 0, PathBuffer.Buffer);
+ }
+ else
+ if (rc == ERROR_PATH_NOT_FOUND) {
+ rc = ERROR_FILE_NOT_FOUND;
+ }
+ }
+
+ return( rc );
+}
+
+APIRET
+DosSearchPath(
+ IN ULONG SearchFlags,
+ IN PSZ PathOrVariableName,
+ IN PSZ FileName,
+ OUT PBYTE Buffer,
+ IN ULONG Length
+ )
+{
+ APIRET rc;
+ PSZ SearchPath;
+ PSZ PathName;
+ PSZ Path;
+ ULONG FileNameLen, PathLen;
+
+ //
+ // Validate the parameters
+ //
+
+ if (Length == 0) {
+ return( ERROR_BUFFER_OVERFLOW );
+ }
+
+ if (SearchFlags & ~(SEARCH_CUR_DIRECTORY |
+ SEARCH_ENVIRONMENT |
+ SEARCH_IGNORENETERRS
+ )
+ ) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ if (FileName == NULL) {
+ //
+ // Note that OS/2 does not check for this case until after the
+ // SEARCH_CUR_DIRECTORY logic, so OS/2 would GP fault if passed a null
+ // file name pointer and the SEARCH_CUR_DIRECTORY flag. Seems like a
+ // bug so we will check before we use the FileName pointer.
+ //
+
+ return( ERROR_FILE_NOT_FOUND );
+ }
+
+
+ //
+ // Check the current directory first if requested.
+ // we pass Canonicalize the requested name.
+ //
+
+ if (SearchFlags & SEARCH_CUR_DIRECTORY) {
+ rc = SearchForPath( SearchFlags,
+ FileName,
+ Buffer,
+ Length
+ );
+
+ if (rc != ERROR_SS_RETRY) {
+ return( rc );
+ }
+ }
+
+
+ //
+ // If pass search path is an environment variable name, then get its
+ // value from the OS/2 Environment Block.
+ //
+
+ if (SearchFlags & SEARCH_ENVIRONMENT) {
+ rc = DosScanEnv( PathOrVariableName, &SearchPath );
+ if (rc != NO_ERROR) {
+ try {
+ *Buffer = '\0';
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return( rc );
+ }
+ }
+ else {
+ SearchPath = PathOrVariableName;
+ }
+
+ //
+ // probe filename and path. figure out maximum length of combined
+ // filename and path
+ //
+
+ try {
+ FileNameLen = strlen( FileName );
+ PathLen = strlen( SearchPath );
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // + 2 is for terminating nul and possible slash
+ //
+
+ PathName = RtlAllocateHeap( Od2Heap, 0, PathLen + FileNameLen + 2 );
+ if (!PathName) {
+#if DBG
+ KdPrint(("OS2: DosSearchPath out of heap memory, fail\n"));
+#endif
+ ASSERT( FALSE );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+
+ //
+ // for each element in search path, append filename and call FindFile.
+ //
+
+ while (*SearchPath) {
+
+#ifdef DBCS
+// MSKK Apr.09.1993 V-AkihiS
+ //
+ // find end of path element
+ //
+ Path = SearchPath;
+ while (*SearchPath && *SearchPath != ';') {
+ if (Ow2NlsIsDBCSLeadByte(*SearchPath, SesGrp->DosCP)) SearchPath++;
+ if (*SearchPath) SearchPath++;
+ }
+#else
+ // BUGBUG fix for DBCS
+ //
+ // find end of path element
+ //
+
+ for (Path = SearchPath;*SearchPath && *SearchPath != ';';SearchPath++) {
+ ;
+ }
+#endif
+ PathLen = SearchPath - Path;
+ if (PathLen != 0) {
+ RtlMoveMemory( PathName, Path, PathLen );
+#ifdef DBCS
+// MSKK Apr.09.1993 V-AkihiS
+ {
+ ULONG i = 0;
+ BOOLEAN SlashFlag = FALSE;
+
+ while (i < PathLen) {
+ if (Ow2NlsIsDBCSLeadByte(PathName[i], SesGrp->DosCP)) {
+ SlashFlag = FALSE;
+ i++;
+ if (i <PathLen) {
+ i++;
+ }
+ } else {
+ if (ISSLASH(PathName[i])) {
+ SlashFlag = TRUE;
+ } else {
+ SlashFlag = FALSE;
+ }
+ i++;
+ }
+ }
+
+ if (!SlashFlag &&
+ !((PathLen == 2) && (PathName[PathLen-1] == ':'))
+ ) {
+ PathName[ PathLen ] = (CHAR)OBJ_NAME_PATH_SEPARATOR;
+
+ //
+ // +1 is for terminating NUL
+ //
+
+ RtlMoveMemory( PathName+PathLen+1, FileName, FileNameLen+1 );
+ }
+ else {
+
+ //
+ // +1 is for terminating NUL
+ //
+
+ RtlMoveMemory( PathName+PathLen, FileName, FileNameLen+1 );
+ }
+ }
+#else
+ if (!ISSLASH( PathName[ PathLen-1 ] ) &&
+ !((PathLen == 2) && (PathName[ PathLen-1] == ':')) // Path is X:
+ ) {
+ PathName[ PathLen ] = (CHAR)OBJ_NAME_PATH_SEPARATOR;
+
+ //
+ // +1 is for terminating NUL
+ //
+
+ RtlMoveMemory( PathName+PathLen+1, FileName, FileNameLen+1 );
+ }
+ else {
+
+ //
+ // +1 is for terminating NUL
+ //
+
+ RtlMoveMemory( PathName+PathLen, FileName, FileNameLen+1 );
+ }
+#endif
+
+ rc = SearchForPath( SearchFlags,
+ PathName,
+ Buffer,
+ Length
+ );
+
+ if (rc != ERROR_SS_RETRY) {
+ RtlFreeHeap( Od2Heap, 0, PathName );
+ return( rc );
+ }
+ }
+
+ if (*SearchPath) { // point past ;
+ SearchPath++;
+ }
+ }
+
+ RtlFreeHeap( Od2Heap, 0, PathName );
+ return( ERROR_FILE_NOT_FOUND );
+}
+
+
+VOID
+Od2CloseSrvHandle(
+ IN ULONG HandleNumber,
+ IN HANDLE Handle1,
+ IN HANDLE Handle2,
+ IN HANDLE Handle3
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSCLOSE_HANDLE_MSG a = &m.u.DosCloseHandle;
+
+ a->HandleNumber = HandleNumber;
+ a->HandleTable[0] = Handle1;
+ a->HandleTable[1] = Handle2;
+ a->HandleTable[2] = Handle3;
+
+ Od2CallSubsystem( &m, NULL, Os2CloseHandle, sizeof( *a ));
+ return;
+}
+
diff --git a/private/os2/client/dlltimer.c b/private/os2/client/dlltimer.c
new file mode 100644
index 000000000..f99d2978e
--- /dev/null
+++ b/private/os2/client/dlltimer.c
@@ -0,0 +1,1101 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dlltimer.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 Time and Timer API Calls
+
+Author:
+
+ Steve Wood (stevewo) 20-Sep-1989 (Adapted from URTL\alloc.c)
+
+Revision History:
+
+ Yaron Shamir 12-17-91 Implemented the timers completely different
+ and correctly (without using APC routines which break 16b
+ semaphores.
+
+ Yaron Shamir 12-19-91 Implemented DosTimerAsync. Use Recycled timer
+ handles.
+
+ Ofer Porat 10-28-92 Added inter-thread synchronization to timer
+ management. Corrected semaphore validity check. Slightly
+ improved timer accuracy. Corrected timer thread cleanup.
+
+ Michael Jarus 4-1-93. DosGetDateTime retrives its info from the Global
+ info segment. Only the first time after DosSetDateTime it gets the
+ info from the system.
+--*/
+
+#define INCL_OS2V20_TIMERS
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_SEMAPHORES
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "os2win.h"
+#include <stdio.h>
+
+
+APIRET DosSemClear( HSEM handle );
+PVOID Od2LookupSem( HSEM hsem );
+extern ULONG Od2GlobalInfoSeg;
+
+typedef struct _TIME_SEM {
+ ULONG TimerSlot;
+ HSEM Sem;
+ ULONG ulTime;
+ ULONG ulSysTime;
+ BOOLEAN RepeatingTimer;
+} TIME_SEM, *PTIME_SEM;
+
+#define TIMER_FREE (HANDLE) 0L // indicates a free timer slot
+#define TIMER_GRABBED (HANDLE) -1L // temproarily holds the slot until it's filled
+
+#define OD2_MAX_TIMERS 100 // maximal number of timers available to process
+
+#define STK_SIZE 0x1000 // timer thread stack size
+
+#define OP_CANCEL 0 // some operation codes...
+#define OP_DELETE 1
+#define OP_UDELETE 2
+
+typedef struct _Od2_TIMERS {
+ ULONG nexttimer; //
+ // indicates the highest used timer slot.
+ // if nexttimer == OD2_MAX_TIMER then slots
+ // must be recycled from free slots inside the array.
+ //
+ ULONG used; //
+ // indicates how many slots are actually in use.
+ //
+ HANDLE Timers[OD2_MAX_TIMERS];
+} OD2_TIMERS;
+
+static OD2_TIMERS Od2Timers = {0};
+
+// these are used to sync access to Od2Timers
+static RTL_CRITICAL_SECTION ProtectOd2Timers;
+static PRTL_CRITICAL_SECTION pProtectOd2Timers = NULL;
+BOOL Od2DosSetDateTimeDone; // after SteDateTime, reads info from system
+
+
+// Initialization routine for the Critical Section used to sync threads
+// Must be called during process startup.
+
+NTSTATUS
+Od2InitializeTimers(VOID)
+{
+ NTSTATUS Status;
+
+ Status = RtlInitializeCriticalSection(&ProtectOd2Timers);
+ if (NT_SUCCESS(Status)) {
+ pProtectOd2Timers = &ProtectOd2Timers;
+ }
+ return(Status);
+}
+
+
+APIRET
+DosGetDateTime(
+ OUT PDATETIME DateTime
+ )
+{
+ APIRET RetCode;
+ LARGE_INTEGER SystemTime;
+ LARGE_INTEGER LocalTime;
+ TIME_FIELDS NtDateTime;
+ SYSTEM_TIMEOFDAY_INFORMATION SystemInformation;
+ SHORT TimeZone;
+ GINFOSEG *pGlobalInfo = (GINFOSEG *) Od2GlobalInfoSeg;
+
+ if (!Od2DosSetDateTimeDone)
+ {
+ try
+ {
+ DateTime->year = pGlobalInfo->year;
+ DateTime->month = pGlobalInfo->month;
+ DateTime->day = pGlobalInfo->day;
+ DateTime->weekday = pGlobalInfo->weekday;
+ DateTime->hours = pGlobalInfo->hour;
+ DateTime->minutes = pGlobalInfo->minutes;
+ DateTime->seconds = pGlobalInfo->seconds;
+ DateTime->hundredths = pGlobalInfo->hundredths;
+ DateTime->weekday = pGlobalInfo->weekday ;
+ DateTime->timezone = pGlobalInfo->timezone;
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+ } else
+ {
+ Od2DosSetDateTimeDone = FALSE;
+
+ RetCode = Or2GetDateTimeInfo(
+ &SystemTime,
+ &LocalTime,
+ &NtDateTime,
+ (PVOID)&SystemInformation,
+ &TimeZone
+ );
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OD2_DEBUG ( TIMERS )
+ {
+ KdPrint(("DosGetDateTime: Or2GetDateTimeInfo rc %lu\n",
+ RetCode));
+ }
+#endif
+ return(RetCode);
+ }
+
+ try
+ {
+ DateTime->year = NtDateTime.Year;
+ DateTime->month = (UCHAR)(NtDateTime.Month);
+ DateTime->day = (UCHAR)(NtDateTime.Day);
+ DateTime->weekday = (UCHAR)(NtDateTime.Weekday);
+ DateTime->hours = (UCHAR)(NtDateTime.Hour);
+ DateTime->minutes = (UCHAR)(NtDateTime.Minute);
+ DateTime->seconds = (UCHAR)(NtDateTime.Second);
+ DateTime->hundredths = (UCHAR)(NtDateTime.Milliseconds / 10);
+ DateTime->weekday = (UCHAR)NtDateTime.Weekday;
+ DateTime->timezone = TimeZone;
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+ }
+
+#if DBG
+ IF_OD2_DEBUG ( TIMERS )
+ {
+ KdPrint(("DosGetDateTime: Time %u:%u:%u.%u, Day %u:%u:%u, TimeZone %i, WeekDay %u\n",
+ DateTime->hours, DateTime->minutes, DateTime->seconds,
+ DateTime->hundredths,
+ DateTime->month, DateTime->day, DateTime->year,
+ DateTime->timezone, DateTime->weekday));
+ }
+#endif
+ return( NO_ERROR );
+}
+
+
+// This routine sets the time zone given the bias
+NTSTATUS
+Od2SetTimeZoneFromBias(
+ IN LONG Bias,
+ OUT PRTL_TIME_ZONE_INFORMATION pOldTz OPTIONAL
+ )
+{
+ NTSTATUS Status;
+ RTL_TIME_ZONE_INFORMATION OldTz;
+ RTL_TIME_ZONE_INFORMATION NewTz;
+ WCHAR Sign;
+
+ Status = RtlQueryTimeZoneInformation(&OldTz);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint(("Od2SetTimeZoneFromBias: RtlQueryTimeZoneInformation rc %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+
+ if (ARGUMENT_PRESENT(pOldTz)) {
+ RtlMoveMemory(pOldTz, &OldTz, sizeof(OldTz));
+ }
+
+ if (Bias == -1 || OldTz.Bias == Bias) {
+ return(STATUS_SUCCESS);
+ }
+
+ RtlZeroMemory(&NewTz, sizeof(NewTz));
+
+ NewTz.Bias = Bias;
+
+ if (Bias <= 0) {
+ Sign = L'+';
+ Bias = -Bias;
+ } else {
+ Sign = L'-';
+ }
+
+ _snwprintf(NewTz.StandardName, 32, L"GMT %c %lu:%02lu", Sign, Bias/60, Bias%60);
+
+ RtlMoveMemory(NewTz.DaylightName, NewTz.StandardName, 32);
+
+ Status = RtlSetTimeZoneInformation(&NewTz);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint(("Od2SetTimeZoneFromBias: RtlSetTimeZoneInformation rc %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+
+ // refresh system time
+
+ Status = NtSetSystemTime(NULL,NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint(("Od2SetTimeZoneFromBias: NtSetSystemTime(NULL,NULL) rc %lx\n", Status));
+ }
+#endif
+ RtlSetTimeZoneInformation(&OldTz); // restore old info
+ NtSetSystemTime(NULL,NULL);
+ return(Status);
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+
+APIRET
+DosSetDateTime(
+ IN PDATETIME DateTime
+ )
+{
+ NTSTATUS Status, Status2;
+ LARGE_INTEGER SystemTime, LocalTime;
+ TIME_FIELDS NtDateTime;
+ RTL_TIME_ZONE_INFORMATION OldTz;
+ LONG ZoneTime;
+ HANDLE TokenHandle;
+
+ //
+ // The following structure is derived from TOKEN_PRIVILEGES
+ //
+
+ struct {
+ ULONG PrivilegeCount;
+ LUID_AND_ATTRIBUTES Privileges[1];
+ } Priv;
+
+
+#if DBG
+ IF_OD2_DEBUG ( TIMERS )
+ {
+ KdPrint(("DosSetDateTime: Time %u:%u:%u.%u, Day %u:%u:%u, TimeZone %i, WeekDay %u\n",
+ DateTime->hours, DateTime->minutes, DateTime->seconds,
+ DateTime->hundredths,
+ DateTime->month, DateTime->day, DateTime->year,
+ DateTime->timezone, DateTime->weekday));
+ }
+#endif
+ try {
+ NtDateTime.Year = DateTime->year;
+ NtDateTime.Month = DateTime->month;
+ NtDateTime.Day = DateTime->day;
+ NtDateTime.Hour = DateTime->hours;
+ NtDateTime.Minute = DateTime->minutes;
+ NtDateTime.Second = DateTime->seconds;
+ NtDateTime.Milliseconds = (CSHORT)(DateTime->hundredths * 10);
+ NtDateTime.Weekday = DateTime->weekday;
+ ZoneTime = (LONG)DateTime->timezone;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ if (( DateTime->year < 1980 ) || ( DateTime->year > 2079 ))
+ {
+#if DBG
+ IF_OD2_DEBUG ( TIMERS )
+ {
+ KdPrint(("DosSetDateTime: year %u out of range\n",
+ DateTime->year));
+ }
+#endif
+ return (ERROR_TS_DATETIME );
+ }
+
+ if (( ZoneTime < -12*60 ) || ( ZoneTime > 12*60 ))
+ {
+#if DBG
+ IF_OD2_DEBUG ( TIMERS )
+ {
+ KdPrint(("DosSetDateTime: timezone %d out of range\n",
+ DateTime->timezone));
+ }
+#endif
+ return (ERROR_TS_DATETIME );
+ }
+
+ if (!RtlTimeFieldsToTime( &NtDateTime, &LocalTime ))
+ {
+#if DBG
+ IF_OD2_DEBUG ( TIMERS )
+ {
+ KdPrint(("DosSetDateTime: RtlTimeFieldsToTime failed\n"));
+ }
+#endif
+ return (ERROR_TS_DATETIME );
+ }
+
+ // First set the time zone correctly
+
+ Status = Od2SetTimeZoneFromBias(ZoneTime, &OldTz);
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ IF_OD2_DEBUG ( TIMERS )
+ {
+ KdPrint(("DosSetDateTime: Od2SetTimeZoneFromBias rc %lx\n",
+ Status));
+ }
+#endif
+ if (Status == STATUS_INVALID_PARAMETER)
+ {
+ return (ERROR_TS_DATETIME );
+ } else
+ {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_TS_DATETIME ));
+ }
+ }
+
+ //
+ // Convert Local time to UTC
+ //
+
+ Status = RtlLocalTimeToSystemTime ( &LocalTime, &SystemTime);
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ IF_OD2_DEBUG ( TIMERS )
+ {
+ KdPrint(("DosSetDateTime: RtlLocalTileToSystemTime rc %lx\n",
+ Status));
+ }
+#endif
+ RtlSetTimeZoneInformation(&OldTz); // restore old timezone
+ NtSetSystemTime(NULL,NULL);
+ if (Status == STATUS_INVALID_PARAMETER)
+ {
+ return (ERROR_TS_DATETIME );
+ } else
+ {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_TS_DATETIME ));
+ }
+ }
+
+ Status = NtSetSystemTime( &SystemTime, NULL);
+
+ if (Status == STATUS_PRIVILEGE_NOT_HELD) {
+
+ //
+ // The process does not have the privilege.
+ // However, the user may be admin, so we try to grab the privilege.
+ //
+
+ do { // 1-time loop so we can break on error
+
+ Status2 = NtOpenProcessToken(NtCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES,
+ &TokenHandle);
+
+ if (!NT_SUCCESS(Status2)) {
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint(("DosSetDateTime: NtOpenProcessToken rc %lx\n",
+ Status2));
+ }
+#endif
+ break;
+ }
+
+ Priv.PrivilegeCount = 1L;
+ Priv.Privileges[0].Luid.LowPart = SE_SYSTEMTIME_PRIVILEGE;
+ Priv.Privileges[0].Luid.HighPart = 0;
+ Priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ Status2 = NtAdjustPrivilegesToken(TokenHandle,
+ FALSE,
+ (PTOKEN_PRIVILEGES) &Priv,
+ 0,
+ NULL,
+ 0);
+ NtClose(TokenHandle);
+
+ if (Status2 == STATUS_NOT_ALL_ASSIGNED || !NT_SUCCESS(Status2)) {
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint(("DosSetDateTime: NtAdjustTokenPrivileges rc %lx\n",
+ Status2));
+ }
+#endif
+ break;
+ }
+
+ Status = NtSetSystemTime( &SystemTime, NULL);
+
+ } while (FALSE);
+ }
+
+ if (!NT_SUCCESS( Status )) {
+
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint(("DosSetDateTime: NtSetSystemTime rc %lx\n",
+ Status));
+ }
+#endif
+
+ RtlSetTimeZoneInformation(&OldTz); // restore old timezone
+ NtSetSystemTime(NULL,NULL);
+ if (Status == STATUS_INVALID_PARAMETER)
+ {
+ return (ERROR_TS_DATETIME );
+ } else
+ {
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_TS_DATETIME ));
+ }
+ }
+
+ Od2DosSetDateTimeDone = TRUE; // Next time get time directly from
+ // system, instead from GInfoSeg
+ return(NO_ERROR);
+}
+
+
+APIRET
+DosSleep(
+ IN ULONG MilliSeconds
+ )
+{
+ NTSTATUS Status;
+ LARGE_INTEGER DelayIntervalValue;
+ PLARGE_INTEGER DelayInterval;
+ LARGE_INTEGER StartTimeStamp;
+
+ DelayInterval = Od2CaptureTimeout( MilliSeconds, &DelayIntervalValue );
+ if (DelayInterval == NULL) {
+
+ DelayIntervalValue.LowPart = 0x0;
+ DelayIntervalValue.HighPart = 0x80000000;
+ DelayInterval = &DelayIntervalValue;
+ }
+
+DosSleep_retry:
+ Od2StartTimeout(&StartTimeStamp);
+ Status = NtDelayExecution( TRUE, DelayInterval );
+
+ if ((Status == STATUS_SUCCESS) ||
+ (Status == STATUS_TIMEOUT)) {
+ return( NO_ERROR );
+ }
+ else
+ if (Status == STATUS_ALERTED) {
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint(("DosSleep - Error in NtDelayExecution STATUS_ALERTED\n"));
+ }
+#endif
+ return( ERROR_TS_WAKEUP );
+ }
+ else
+ if (Status == STATUS_USER_APC) {
+#if DBG
+ DbgPrint("[%d,%d] WARNING !!! DosSleep was broken by APC\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ );
+#endif
+ if (Od2ContinueTimeout(&StartTimeStamp, DelayInterval) == STATUS_SUCCESS) {
+ goto DosSleep_retry;
+ }
+ else {
+ return( NO_ERROR );
+ }
+ }
+ else {
+#if DBG
+ KdPrint(("DosSleep - Error in NtDelayExecution Status %lx\n", Status));
+#endif
+ return( Or2MapStatus( Status ) );
+ }
+}
+
+
+APIRET
+Od2AllocateTimerSlot(
+ OUT PULONG TimerSlot
+ )
+{
+ ULONG FreeSlot;
+
+ if (pProtectOd2Timers == NULL ||
+ !NT_SUCCESS(RtlEnterCriticalSection(pProtectOd2Timers))) {
+ return(ERROR_TS_NOTIMER);
+ }
+
+ if (Od2Timers.used == OD2_MAX_TIMERS) {
+ //
+ // out of timers
+ //
+ RtlLeaveCriticalSection(pProtectOd2Timers);
+ return(ERROR_TS_NOTIMER);
+ }
+
+ if (Od2Timers.nexttimer == OD2_MAX_TIMERS) {
+
+ //
+ // crawl thru used timers to find a free one
+ //
+ for (FreeSlot = 0; Od2Timers.Timers[FreeSlot] != TIMER_FREE;
+ FreeSlot++) {
+ }
+ } else {
+ FreeSlot = Od2Timers.nexttimer++;
+ }
+
+ Od2Timers.used++;
+ Od2Timers.Timers[FreeSlot] = TIMER_GRABBED;
+ *TimerSlot = FreeSlot;
+
+ RtlLeaveCriticalSection(pProtectOd2Timers);
+ return(NO_ERROR);
+}
+
+
+APIRET
+Od2DeallocateTimerSlot(
+ IN ULONG TimerSlot,
+ IN ULONG Op, // OP_CANCEL - cancel a grabbed slot
+ // OP_DELETE - delete an existing slot
+ // OP_UDELETE - validate slot number and delete
+
+ OUT PHANDLE pHandle OPTIONAL // optionally returns slot value
+ )
+{
+ HANDLE Handle;
+
+ if (Op == OP_UDELETE && (TimerSlot <0 || TimerSlot >= OD2_MAX_TIMERS)) {
+ return(ERROR_TS_HANDLE);
+ }
+
+ if (pProtectOd2Timers == NULL ||
+ !NT_SUCCESS(RtlEnterCriticalSection(pProtectOd2Timers))) {
+ return(ERROR_TS_HANDLE);
+ }
+
+ try {
+
+ Handle = Od2Timers.Timers[TimerSlot];
+
+ switch ((ULONG) Handle) {
+
+ case (ULONG) TIMER_FREE:
+ return(ERROR_TS_HANDLE);
+
+ case (ULONG) TIMER_GRABBED:
+ if (Op != OP_CANCEL) {
+ return(ERROR_TS_HANDLE);
+ }
+ break;
+
+ default:
+ if (Op == OP_CANCEL) {
+ return(ERROR_TS_HANDLE);
+ }
+ }
+
+ if (ARGUMENT_PRESENT(pHandle)) {
+ *pHandle = Handle;
+ }
+
+ Od2Timers.used--;
+ Od2Timers.Timers[TimerSlot] = TIMER_FREE;
+
+ if (TimerSlot == Od2Timers.nexttimer - 1) {
+ for (;TimerSlot != (ULONG) -1 &&
+ Od2Timers.Timers[TimerSlot] == TIMER_FREE; TimerSlot--) {
+ }
+ Od2Timers.nexttimer = TimerSlot + 1;
+ }
+
+ return(NO_ERROR);
+
+ } finally {
+ RtlLeaveCriticalSection(pProtectOd2Timers);
+ }
+}
+
+
+/* This function is omitted since it's only used for a certain synchronization
+ action below, and this sync action has been removed. See the comment
+ in DosAsyncTimer for an explanation why.
+
+APIRET
+Od2WriteTimerSlot(
+ IN ULONG TimerSlot, // assumes validity
+ IN HANDLE Handle
+ )
+{
+ if (pProtectOd2Timers == NULL ||
+ !NT_SUCCESS(RtlEnterCriticalSection(pProtectOd2Timers))) {
+ return(ERROR_TS_HANDLE);
+ }
+
+ Od2Timers.Timers[TimerSlot] = Handle;
+
+ RtlLeaveCriticalSection(pProtectOd2Timers);
+ return(NO_ERROR);
+}
+*/
+
+
+VOID
+Od2TimerThread(
+ PVOID param
+ )
+{
+ APIRET rc;
+ NTSTATUS Status;
+ HANDLE Handle;
+ ULONG Compensation;
+ PLARGE_INTEGER DelayInterval, RepeatDelayInterval;
+ LARGE_INTEGER DelayIntervalValue, RepeatDelayIntervalValue;
+ PTIME_SEM pTimeSem = (PTIME_SEM)(param);
+ GINFOSEG *pGlobalInfo;
+
+ pGlobalInfo = (GINFOSEG *) Od2GlobalInfoSeg;
+
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint(("Entering Timer Thread: TimerSlot %lu Time %d, Sem %lx\n",
+ pTimeSem->TimerSlot, pTimeSem->ulTime, pTimeSem->Sem));
+ KdPrint(("pTimeSem->SysTime = %d\n", pTimeSem->ulSysTime));
+ KdPrint(("Current Boot Time = %d\n", pGlobalInfo->msecs));
+ }
+#endif
+
+ if (NtTestAlert() == STATUS_ALERTED) {
+ goto FinishOff;
+ }
+
+ //
+ // First calculate the on-going delay time (no offset)
+ //
+ if (pTimeSem->RepeatingTimer) {
+ RepeatDelayInterval = Od2CaptureTimeout(
+ pTimeSem->ulTime,
+ &RepeatDelayIntervalValue);
+
+ if (RepeatDelayInterval == NULL) {
+ RepeatDelayIntervalValue.LowPart = 0x0;
+ RepeatDelayIntervalValue.HighPart = 0x80000000;
+ RepeatDelayInterval = &RepeatDelayIntervalValue;
+ }
+ }
+
+ //
+ // Now compensate for time passed between DosAsync/StartTimer and
+ // this moment
+ //
+ if (pTimeSem->ulTime == SEM_INDEFINITE_WAIT) {
+ DelayIntervalValue.LowPart = 0x0;
+ DelayIntervalValue.HighPart = 0x80000000;
+ DelayInterval = &DelayIntervalValue;
+ } else {
+ Compensation = pGlobalInfo->msecs - pTimeSem->ulSysTime;
+ if (pTimeSem->ulTime <= Compensation) {
+ goto NoFirstDelay;
+ }
+ DelayInterval = Od2CaptureTimeout(
+ pTimeSem->ulTime - Compensation,
+ &DelayIntervalValue );
+ }
+
+ Status = NtDelayExecution(TRUE, DelayInterval);
+
+ if (Status == STATUS_ALERTED) {
+ goto FinishOff;
+ }
+
+NoFirstDelay:
+#if DBG
+ IF_OD2_DEBUG ( APIS ) {
+ KdPrint(("[Od2TimerThread] DosSemClear\n"));
+ }
+#endif
+
+ rc = DosSemClear (pTimeSem->Sem);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint (("Od2TimerThread: error at DosSemClear %d, Sem %lx\n",
+ rc, pTimeSem->Sem));
+ }
+#endif
+ }
+ if (!pTimeSem->RepeatingTimer) {
+ //
+ // one time timer - exit
+ //
+ if (Od2DeallocateTimerSlot(pTimeSem->TimerSlot, OP_DELETE, &Handle)
+ == NO_ERROR) {
+ CloseHandle(Handle);
+ }
+ goto FinishOff;
+ }
+
+ for (;;) {
+
+ Status = NtDelayExecution(TRUE, RepeatDelayInterval);
+
+ if (Status == STATUS_ALERTED) {
+ goto FinishOff;
+ }
+
+#if DBG
+ IF_OD2_DEBUG ( APIS ) {
+ KdPrint(("[Od2TimerThread] DosSemClear\n"));
+ }
+#endif
+
+ rc = DosSemClear (pTimeSem->Sem);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint (("Od2TimerThread: error at DosSemClear %d, Sem %lx\n",
+ rc, pTimeSem->Sem));
+ }
+#endif
+ }
+ }
+
+FinishOff:
+ RtlFreeHeap(Od2Heap, 0, pTimeSem);
+ ExitThread(STATUS_SUCCESS);
+}
+
+
+APIRET
+DosAsyncTimer(
+ IN ULONG MilliSeconds,
+ IN HEV EventSem,
+ OUT PHTIMER TimerHandle
+ )
+{
+ GINFOSEG *pGlobalInfo;
+ ULONG TimeAnchor;
+ PTIME_SEM pTimeSem;
+ APIRET RetCode;
+ NTSTATUS Status=0;
+ HANDLE ThreadHandle;
+ ULONG FreeSlot;
+ ULONG Tid;
+ PUSHORT pTimerHandle = (PUSHORT)TimerHandle;
+
+ pGlobalInfo = (GINFOSEG *) Od2GlobalInfoSeg;
+ TimeAnchor = pGlobalInfo->msecs;
+
+ //
+ // Adjust the minimum delay to at least one processor clock tick (for compatibility with OS/2)
+ //
+
+ if (MilliSeconds < (ULONG) pGlobalInfo->cusecTimerInterval / 10L) {
+ MilliSeconds = (ULONG) pGlobalInfo->cusecTimerInterval / 10L;
+ }
+
+ //
+ // Validate Semaphore Handle
+ //
+ if (Od2LookupSem(EventSem) == NULL) {
+ Od2ExitGP();
+ }
+
+ if ((RetCode = Od2AllocateTimerSlot(&FreeSlot)) != NO_ERROR) {
+ return(RetCode);
+ }
+
+ try {
+ *pTimerHandle = (USHORT) (FreeSlot + 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Found a timer slot - value in FreeSlot
+ // now get the real work done
+ //
+ pTimeSem = RtlAllocateHeap( Od2Heap, 0, sizeof (TIME_SEM));
+ if (pTimeSem == NULL)
+ {
+ Od2DeallocateTimerSlot(FreeSlot, OP_CANCEL, NULL);
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint (("DosAsyncTimer: can't allocate heap for TIME_SEM\n"));
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ pTimeSem->ulSysTime = TimeAnchor;
+ pTimeSem->ulTime = MilliSeconds;
+ pTimeSem->TimerSlot = FreeSlot;
+ pTimeSem->Sem = (HSEM) EventSem;
+ pTimeSem->RepeatingTimer = FALSE;
+
+
+ //
+ // Create A thread dedicated to clear the semaphore periodically
+ // We stop it by alerting the thread
+ //
+
+ ThreadHandle = CreateThread(NULL,
+ STK_SIZE,
+ (PFNTHREAD) Od2TimerThread,
+ pTimeSem,
+ CREATE_SUSPENDED,
+ &Tid);
+
+ if (ThreadHandle == 0) {
+ RtlFreeHeap(Od2Heap, 0, pTimeSem);
+ Od2DeallocateTimerSlot(FreeSlot, OP_CANCEL, NULL);
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint (("DosAsyncTimer: can't Create timer thread %lx\n", Status));
+ }
+#endif
+ return ERROR_TS_NOTIMER;
+ }
+
+
+ // The following command should theoretically be synchronized by
+ // calling Od2WriteTimerSlot(FreeSlot, ThreadHandle);
+ // However, the only case where the non-synced version can interfere
+ // is when the assembly-level store instruction is split on a
+ // multi-processor system. Therefore, in the interest of efficiency
+ // it's implemented without sync. (A similar situation occurs in
+ // DosStartTimer below).
+
+ Od2Timers.Timers[FreeSlot] = ThreadHandle;
+
+
+ Status = ResumeThread(ThreadHandle);
+
+ if (Status == -1) {
+ RtlFreeHeap(Od2Heap, 0, pTimeSem);
+ TerminateThread(ThreadHandle, STATUS_SUCCESS);
+ WaitForSingleObject(ThreadHandle, (ULONG) SEM_INDEFINITE_WAIT);
+ CloseHandle(ThreadHandle);
+ Od2DeallocateTimerSlot(FreeSlot, OP_DELETE, NULL);
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint (("DosAsyncTimer: can't resume timer thread %lx\n", Status));
+ }
+#endif
+ return ERROR_TS_NOTIMER;
+ }
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+DosStartTimer(
+ IN ULONG MilliSeconds,
+ IN HEV EventSem,
+ OUT PHTIMER TimerHandle
+ )
+{
+ ULONG TimeAnchor;
+ PTIME_SEM pTimeSem;
+ APIRET RetCode;
+ NTSTATUS Status=0;
+ HANDLE ThreadHandle;
+ ULONG FreeSlot;
+ ULONG Tid;
+ PUSHORT pTimerHandle = (PUSHORT)TimerHandle;
+ GINFOSEG *pGlobalInfo;
+
+ pGlobalInfo = (GINFOSEG *) Od2GlobalInfoSeg;
+ TimeAnchor = pGlobalInfo->msecs;
+
+ //
+ // Adjust the minimum delay to at least one processor clock tick (for compatibility with OS/2)
+ //
+
+ if (MilliSeconds < (ULONG) pGlobalInfo->cusecTimerInterval / 10L) {
+ MilliSeconds = (ULONG) pGlobalInfo->cusecTimerInterval / 10L;
+ }
+
+ //
+ // Validate Semaphore Handle
+ //
+ if (Od2LookupSem(EventSem) == NULL) {
+ Od2ExitGP();
+ }
+
+ if ((RetCode = Od2AllocateTimerSlot(&FreeSlot)) != NO_ERROR) {
+ return(RetCode);
+ }
+
+ try {
+ *pTimerHandle = (USHORT) (FreeSlot + 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // Found a timer slot - value in FreeSlot
+ // now get the real work done
+ //
+ pTimeSem = RtlAllocateHeap( Od2Heap, 0, sizeof (TIME_SEM));
+ if (pTimeSem == NULL)
+ {
+ Od2DeallocateTimerSlot(FreeSlot, OP_CANCEL, NULL);
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint (("DosStartTimer: can't allocate heap for TIME_SEM\n"));
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ pTimeSem->ulSysTime = TimeAnchor;
+ pTimeSem->ulTime = MilliSeconds;
+ pTimeSem->TimerSlot = FreeSlot;
+ pTimeSem->Sem = (HSEM) EventSem;
+ pTimeSem->RepeatingTimer = TRUE;
+
+
+ //
+ // Create A thread dedicated to clear the semaphore periodically
+ // We stop it by alerting the thread
+ //
+
+ ThreadHandle = CreateThread(NULL,
+ STK_SIZE,
+ (PFNTHREAD) Od2TimerThread,
+ pTimeSem,
+ CREATE_SUSPENDED,
+ &Tid);
+
+ if (ThreadHandle == 0) {
+ RtlFreeHeap(Od2Heap, 0, pTimeSem);
+ Od2DeallocateTimerSlot(FreeSlot, OP_CANCEL, NULL);
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint (("DosStartTimer: can't Create timer thread %lx\n", Status));
+ }
+#endif
+ return ERROR_TS_NOTIMER;
+ }
+
+
+ // See the comment in DosAsyncTimer above regarding the synchronization
+ // of the following instruction.
+
+ Od2Timers.Timers[FreeSlot] = ThreadHandle;
+
+
+ Status = ResumeThread(ThreadHandle);
+
+ if (Status == -1) {
+ RtlFreeHeap(Od2Heap, 0, pTimeSem);
+ TerminateThread(ThreadHandle, STATUS_SUCCESS);
+ WaitForSingleObject(ThreadHandle, (ULONG) SEM_INDEFINITE_WAIT);
+ CloseHandle(ThreadHandle);
+ Od2DeallocateTimerSlot(FreeSlot, OP_DELETE, NULL);
+#if DBG
+ IF_OD2_DEBUG ( TIMERS ) {
+ KdPrint (("DosStartTimer: can't resume timer thread %lx\n", Status));
+ }
+#endif
+ return ERROR_TS_NOTIMER;
+ }
+
+ return(NO_ERROR);
+}
+
+
+APIRET
+DosStopTimer(
+ IN HTIMER TimerHandle
+ )
+{
+ APIRET RetCode;
+ NTSTATUS Status;
+ HANDLE ThreadHandle;
+
+ if ((RetCode = Od2DeallocateTimerSlot((ULONG) TimerHandle - 1, OP_UDELETE, &ThreadHandle))
+ != NO_ERROR) {
+ return(RetCode);
+ }
+
+ Status = NtAlertThread(ThreadHandle);
+
+ if(!NT_SUCCESS(Status)){
+#if DBG
+ KdPrint (("DosStopTimer: can't Alert timer thread %lx\n", Status));
+#endif
+ return(ERROR_TS_HANDLE);
+ }
+
+ WaitForSingleObject(ThreadHandle, INFINITE);
+
+ CloseHandle(ThreadHandle);
+
+ return(NO_ERROR);
+}
+
+
+VOID
+Od2CloseAllTimers(VOID)
+{
+ ULONG Slot;
+ HANDLE Handle;
+ PRTL_CRITICAL_SECTION Copy;
+
+ if (pProtectOd2Timers == NULL) {
+ return;
+ }
+
+ RtlEnterCriticalSection(pProtectOd2Timers);
+
+ Copy = pProtectOd2Timers;
+ pProtectOd2Timers = NULL; // invalidate the CritSec
+
+ for (Slot = 0; Od2Timers.used > 0; Slot++)
+ {
+ Handle = Od2Timers.Timers[Slot];
+
+ if (Handle == TIMER_FREE)
+ continue;
+
+ Od2Timers.used--;
+
+ if (Handle != TIMER_GRABBED)
+ {
+ TerminateThread(Handle, STATUS_SUCCESS);
+
+ // Technically, there should be a
+ // WaitForSingleObject(Handle, (ULONG) SEM_INDEFINITE_WAIT);
+ // right here in order to completely clean up the thread.
+ // However, since the process is being killed anyway the wait was
+ // omitted for a slight speed increase.
+
+ CloseHandle(Handle);
+ }
+ }
+
+ RtlLeaveCriticalSection(Copy);
+ RtlDeleteCriticalSection(Copy);
+}
diff --git a/private/os2/client/dlltsk16.c b/private/os2/client/dlltsk16.c
new file mode 100644
index 000000000..b95fa4890
--- /dev/null
+++ b/private/os2/client/dlltsk16.c
@@ -0,0 +1,164 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dlltsk16.c
+
+Abstract:
+
+ This module implements 32 equivalents of OS/2 V1.21 Thread/Task
+ API Calls. These are called from 16->32 thunks (i386\doscalls.asm).
+ Other related calls are in dllldr16.c.
+
+
+Author:
+
+ Yaron Shamir (YaronS) 30-May-1991
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+
+typedef struct _RESULTCODES16 {
+ USHORT ExitReason;
+ USHORT ExitResult;
+} RESULTCODES16, *PRESULTCODES16;
+
+APIRET
+DosGetPID(
+ PPIDINFO16 pidi
+ )
+{
+
+ pidi->pid = (USHORT)Od2Process->Pib.ProcessId;
+ pidi->tid = (USHORT)(Od2CurrentThreadId());
+ pidi->pidParent = (USHORT)Od2Process->Pib.ParentProcessId;
+ return (NO_ERROR);
+}
+
+APIRET
+DosGetPPID(
+ ULONG pidChild,
+ PUSHORT ppidParent
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSGETPPID_MSG a = &m.u.DosGetPPID;
+ APIRET rc;
+
+ try
+ {
+ Od2ProbeForWrite(ppidParent, sizeof(USHORT), 1);
+ }
+ except (EXCEPTION_EXECUTE_HANDLER) {
+ Od2ExitGP();
+ }
+
+ a->ChildPid = (PID)pidChild;
+
+ rc = Od2CallSubsystem( &m, NULL, Os2GetPPID, sizeof( *a ) );
+
+ if (rc == NO_ERROR) {
+ *ppidParent = (USHORT)a->ParentPid;
+ }
+ return(rc);
+}
+
+APIRET
+Dos16ExitList(
+ ULONG OrderCode,
+ PFNEXITLIST ExitRoutine
+ )
+{
+ return( Od2ExitList( OrderCode,
+ (PFNEXITLIST) (FLATTOFARPTR((ULONG)(ExitRoutine))),
+ FALSE ) );
+}
+
+APIRET
+Dos16ExecPgm(
+ OUT PSZ ErrorText OPTIONAL,
+ IN LONG MaximumErrorTextLength,
+ IN ULONG Flags,
+ IN PSZ Arguments OPTIONAL,
+ IN PSZ Variables OPTIONAL,
+ OUT PRESULTCODES16 pResultCodes16,
+ IN PSZ ImageFileName)
+{
+ RESULTCODES ResultCodes;
+ APIRET rc;
+
+ try
+ {
+ Od2ProbeForWrite(pResultCodes16, sizeof(PRESULTCODES16), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ ResultCodes.ExitReason = (ULONG)pResultCodes16->ExitReason;
+ ResultCodes.ExitResult = (ULONG)pResultCodes16->ExitResult;
+
+ rc = DosExecPgm(ErrorText,
+ MaximumErrorTextLength,
+ Flags,
+ Arguments,
+ Variables,
+ &ResultCodes,
+ ImageFileName);
+
+ pResultCodes16->ExitReason = (USHORT)ResultCodes.ExitReason;
+ pResultCodes16->ExitResult = (USHORT)ResultCodes.ExitResult;
+
+ return(rc);
+}
+
+APIRET
+Dos16WaitChild(
+ IN ULONG WaitTarget,
+ IN ULONG WaitOption,
+ OUT PRESULTCODES16 pResultCodes16,
+ OUT PPID16 pResultProcessId16,
+ IN PID ProcessId
+ )
+{
+ RESULTCODES ResultCodes;
+ PID ResultProcessId;
+ APIRET rc;
+
+ try
+ {
+ Od2ProbeForWrite(pResultCodes16, sizeof(PRESULTCODES16), 1);
+ Od2ProbeForWrite(pResultProcessId16, sizeof(PPID16), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ ResultProcessId = (PID) *pResultProcessId16;
+ ResultCodes.ExitReason = (ULONG)pResultCodes16->ExitReason;
+ ResultCodes.ExitResult = (ULONG)pResultCodes16->ExitResult;
+
+ rc = DosWaitChild( WaitTarget,
+ WaitOption,
+ &ResultCodes,
+ &ResultProcessId,
+ ProcessId);
+
+ pResultCodes16->ExitReason = (USHORT)ResultCodes.ExitReason;
+ pResultCodes16->ExitResult = (USHORT)ResultCodes.ExitResult;
+ *pResultProcessId16 = (PID16)ResultProcessId;
+
+ return(rc);
+}
+
+
diff --git a/private/os2/client/dllutil.c b/private/os2/client/dllutil.c
new file mode 100644
index 000000000..378a9d3cb
--- /dev/null
+++ b/private/os2/client/dllutil.c
@@ -0,0 +1,1533 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllutil.c
+
+Abstract:
+
+ This module contains utility procedures for the OS/2 Client DLL
+
+
+Author:
+
+ Steve Wood (stevewo) 02-Nov-1989
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+
+extern PSZ Od216ApiTable[1];
+BOOLEAN Od2DontReleaseFileLock;
+
+VOID TerminateSession(VOID);
+VOID
+Ow2Exit(
+ IN ULONG StringCode,
+ IN PCHAR ErrorText,
+ IN ULONG ExitCode
+ );
+VOID
+EventReleaseLPC(
+ IN ULONG ProcessId
+ );
+
+APIRET
+DosHoldSignal(
+ ULONG fDisable,
+ ULONG pstack
+ );
+
+APIRET
+Od2CallSubsystem(
+ IN OUT POS2_API_MSG m,
+ IN OUT POS2_CAPTURE_HEADER CaptureBuffer OPTIONAL,
+ IN OS2_API_NUMBER ApiNumber,
+ IN ULONG ArgLength
+ )
+
+/*++
+
+Routine Description:
+
+ This function sends an API request to the OS/2 Emulation Subsystem
+ Server and waits for a reply.
+
+Arguments:
+
+ m - Pointer to the API request message to send.
+
+ CaptureBuffer - Optional pointer to a capture buffer located in the
+ Port Memory section that contains additional data being sent
+ to the server. Since Port Memory is also visible to the server,
+ no data needs to be copied, but pointers to locations within the
+ capture buffer need to be converted into pointers valid in the
+ server's process context, since the server's view of the Port Memory
+ is not at the same virtual address as the client's view.
+
+ ApiNumber - Small integer that is the number of the API being called.
+
+ ArgLength - Length, in bytes, of the argument portion located at the
+ end of the request message. Used to calculate the length of the
+ request message.
+
+Return Value:
+
+ OS/2 Error Code returned from the OS/2 Server.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PULONG PointerOffsets;
+ ULONG CountPointers, Pointer;
+
+ //
+ // Initialize the header of the message.
+ //
+
+ ArgLength |= (ArgLength << 16);
+ ArgLength += ((sizeof( OS2_API_MSG ) - sizeof( m->u )) << 16) |
+ (FIELD_OFFSET( OS2_API_MSG, u ) - sizeof( m->h ));
+ m->h.u1.Length = ArgLength;
+ m->h.u2.ZeroInit = 0;
+ m->CaptureBuffer = NULL;
+ m->ApiNumber = ApiNumber;
+ m->PortType = 0;
+
+ //
+ // If the CaptureBuffer argument is present, then there is data located
+ // in the Port Memory section that is being passed to the server. All
+ // Port Memory pointers need to be converted so they are valid in the
+ // Server's view of the Port Memory.
+ //
+
+ if (ARGUMENT_PRESENT( CaptureBuffer )) {
+ //
+ // Store a pointer to the capture buffer in the message that is valid
+ // in the server process's context.
+ //
+
+ m->CaptureBuffer = (POS2_CAPTURE_HEADER)
+ ((PCHAR)CaptureBuffer + Od2PortMemoryRemoteDelta);
+
+ //
+ // Mark the fact that we are done allocating space from the end of
+ // the capture buffer.
+ //
+
+ CaptureBuffer->FreeSpace = NULL;
+
+ //
+ // Loop over all of the pointers to Port Memory within the message
+ // itself and convert them into server pointers. Also, convert
+ // the pointers to pointers into offsets.
+ //
+
+ PointerOffsets = CaptureBuffer->MessagePointerOffsets;
+ CaptureBuffer->MessagePointerOffsets = (PULONG)
+ ((PCHAR)CaptureBuffer->MessagePointerOffsets +
+ Od2PortMemoryRemoteDelta);
+ CountPointers = CaptureBuffer->CountMessagePointers;
+ while (CountPointers--) {
+ Pointer = *PointerOffsets++;
+ if (Pointer != 0) {
+ *(PULONG)Pointer += Od2PortMemoryRemoteDelta;
+ PointerOffsets[ -1 ] = Pointer - (ULONG)m;
+ }
+ }
+
+ //
+ // Loop over all of the pointers to Port Memory within the capture
+ // buffer and convert them into server pointers. Also, convert
+ // the pointers to pointers into offsets.
+ //
+
+ PointerOffsets = CaptureBuffer->CapturePointerOffsets;
+ CaptureBuffer->CapturePointerOffsets = (PULONG)
+ ((PCHAR)CaptureBuffer->CapturePointerOffsets +
+ Od2PortMemoryRemoteDelta);
+ CountPointers = CaptureBuffer->CountCapturePointers;
+ while (CountPointers--) {
+ Pointer = *PointerOffsets++;
+ if (Pointer != 0) {
+ *(PULONG)Pointer += Od2PortMemoryRemoteDelta;
+ PointerOffsets[ -1 ] = Pointer - (ULONG)CaptureBuffer;
+ }
+ }
+ }
+
+ if (m->ApiNumber == Os2Exit || m->ApiNumber == Os2ExitGP
+ || m->ApiNumber == Oi2TerminateProcess) {
+ Status = NtRequestPort(
+ Od2PortHandle,
+ (PPORT_MESSAGE) m);
+
+ if ( !NT_SUCCESS( Status )){
+#if DBG
+ KdPrint(( "OS2 (Od2CallSubsystem): *** NtRequestPort (%lu) failed - Status == %X\n",
+ ApiNumber, Status
+ ));
+ //
+ // Terminate the app - os2srv may be not available at this point
+ //
+ if (Status == STATUS_PORT_DISCONNECTED || Status == STATUS_INVALID_HANDLE){
+ PTEB Teb = NtCurrentTeb();
+ EventReleaseLPC((ULONG)(Teb->ClientId.UniqueProcess));
+ TerminateSession();
+ Ow2Exit(0, NULL, 15);
+ }
+#endif
+ }
+ }
+ else {
+ Status = NtRequestWaitReplyPort( Od2PortHandle,
+ (PPORT_MESSAGE)m,
+ (PPORT_MESSAGE)m
+ );
+ //
+ // Check for failed status and do something.
+ //
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(( "OS2 (Od2CallSubsystem): *** NtRequestWaitReplyPort (%lu) failed - Status == %X\n",
+ ApiNumber, Status
+ ));
+#endif
+ //
+ // Terminate the app - os2srv may be not available at this point
+ //
+ if (Status == STATUS_PORT_DISCONNECTED || Status == STATUS_INVALID_HANDLE){
+ TerminateSession();
+ Ow2Exit(0, NULL, 15);
+ }
+ }
+ }
+
+ //
+ // If the CaptureBuffer argument is present then reverse what we did
+ // to the pointers above so that the client side code can use them
+ // again.
+ //
+
+ if (ARGUMENT_PRESENT( CaptureBuffer )) {
+ //
+ // Convert the capture buffer pointer back to a client pointer.
+ //
+
+ m->CaptureBuffer = (POS2_CAPTURE_HEADER)
+ ((PCHAR)CaptureBuffer - Od2PortMemoryRemoteDelta);
+
+ //
+ // Loop over all of the pointers to Port Memory within the message
+ // itself and convert them into client pointers. Also, convert
+ // the offsets pointers to pointers into back into pointers
+ //
+
+ CaptureBuffer->MessagePointerOffsets = (PULONG)
+ ((PCHAR)CaptureBuffer->MessagePointerOffsets -
+ Od2PortMemoryRemoteDelta);
+ PointerOffsets = CaptureBuffer->MessagePointerOffsets;
+ CountPointers = CaptureBuffer->CountMessagePointers;
+ while (CountPointers--) {
+ Pointer = *PointerOffsets++;
+ if (Pointer != 0) {
+ Pointer += (ULONG)m;
+ PointerOffsets[ -1 ] = Pointer;
+ *(PULONG)Pointer -= Od2PortMemoryRemoteDelta;
+ }
+ }
+
+ //
+ // Loop over all of the pointers to Port Memory within the capture
+ // buffer and convert them into client pointers. Also, convert
+ // the offsets pointers to pointers into back into pointers
+ //
+
+ CaptureBuffer->CapturePointerOffsets = (PULONG)
+ ((PCHAR)CaptureBuffer->CapturePointerOffsets -
+ Od2PortMemoryRemoteDelta);
+ PointerOffsets = CaptureBuffer->CapturePointerOffsets;
+ CountPointers = CaptureBuffer->CountCapturePointers;
+ while (CountPointers--) {
+ Pointer = *PointerOffsets++;
+ if (Pointer != 0) {
+ Pointer += (ULONG)CaptureBuffer;
+ PointerOffsets[ -1 ] = Pointer;
+ *(PULONG)Pointer -= Od2PortMemoryRemoteDelta;
+ }
+ }
+ }
+
+ //
+ // The value of this function is whatever OS/2 error code the server
+ // returned.
+ //
+
+ return( m->ReturnedErrorValue );
+}
+
+
+POS2_CAPTURE_HEADER
+Od2AllocateCaptureBuffer(
+ IN ULONG CountMessagePointers,
+ IN ULONG CountCapturePointers,
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ This function allocates a buffer from the Port Memory section for
+ use by the client in capture arguments into Port Memory. In addition to
+ specifying the size of the data that needs to be captured, the caller
+ needs to specify how many pointers to captured data will be passed.
+ Pointers can be located in either the request message itself, and/or
+ the capture buffer.
+
+Arguments:
+
+ CountMessagePointers - Number of pointers within the request message
+ that will point to locations within the allocated capture buffer.
+
+ CountCapturePointers - Number of pointers within the capture buffer
+ that will point to ither locations within the allocated capture
+ buffer.
+
+ Size - Total size of the data that will be captured into the capture
+ buffer.
+
+Return Value:
+
+ A pointer to the capture buffer header.
+
+--*/
+
+{
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ ULONG CountPointers;
+
+ //
+ // Calculate the total number of pointers that will be passed
+ //
+
+ CountPointers = CountMessagePointers + CountCapturePointers;
+
+ //
+ // Calculate the total size of the capture buffer. This includes the
+ // header, the array of pointer offsets and the data length. We round
+ // the data length to a 32-bit boundary, assuming that each pointer
+ // points to data whose length is not aligned on a 32-bit boundary.
+ //
+
+ Size += sizeof( OS2_CAPTURE_HEADER ) + (CountPointers * sizeof( PVOID ));
+ Size = (Size + (3 * (CountPointers+1))) & ~3;
+
+ //
+ // Allocate the capture buffer from the Port Memory Heap.
+ //
+
+ try {
+ CaptureBuffer = RtlAllocateHeap( Od2PortHeap, 0, Size );
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+
+ //
+ // FIX, FIX - need to attempt the receive lost reply messages to
+ // to see if they contain CaptureBuffer pointers that can be freed.
+ //
+
+ return( NULL );
+ }
+ if (!CaptureBuffer) {
+#if DBG
+ KdPrint(("OS2: Od2CaptureBuffer out of heap memory, fail\n"));
+#endif
+ return NULL;
+ }
+
+ //
+ // Initialize the capture buffer header
+ //
+
+ CaptureBuffer->Length = Size;
+ CaptureBuffer->CountMessagePointers = 0;
+ CaptureBuffer->CountCapturePointers = 0;
+
+ //
+ // If there are pointers being passed then initialize the arrays of
+ // pointer offsets to zero. In either case set the free space pointer
+ // in the capture buffer header to point to the first 32-bit aligned
+ // location after the header, the arrays of pointer offsets are considered
+ // part of the header.
+ //
+
+ if (CountPointers != 0) {
+ CaptureBuffer->MessagePointerOffsets = (PULONG)(CaptureBuffer + 1);
+
+ CaptureBuffer->CapturePointerOffsets =
+ CaptureBuffer->MessagePointerOffsets + CountMessagePointers;
+
+ RtlZeroMemory( CaptureBuffer->MessagePointerOffsets,
+ CountPointers * sizeof( ULONG )
+ );
+
+ CaptureBuffer->FreeSpace = (PCHAR)
+ (CaptureBuffer->CapturePointerOffsets + CountCapturePointers);
+ }
+ else {
+ CaptureBuffer->MessagePointerOffsets = NULL;
+ CaptureBuffer->CapturePointerOffsets = NULL;
+ CaptureBuffer->FreeSpace = (PCHAR)(CaptureBuffer + 1);
+ }
+
+ //
+ // Returned the address of the capture buffer.
+ //
+
+ return( CaptureBuffer );
+}
+
+
+VOID
+Od2FreeCaptureBuffer(
+ IN POS2_CAPTURE_HEADER CaptureBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This function frees a capture buffer allocated by Od2AllocateCaptureBuffer.
+
+Arguments:
+
+ CaptureBuffer - Pointer to a capture buffer allocated by
+ Od2AllocateCaptureBuffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Free the capture buffer back to the Port Memory heap.
+ //
+
+ RtlFreeHeap( Od2PortHeap, 0, CaptureBuffer );
+}
+
+
+ULONG
+Od2AllocateMessagePointer(
+ IN OUT POS2_CAPTURE_HEADER CaptureBuffer,
+ IN ULONG Length,
+ OUT PVOID *Pointer
+ )
+
+/*++
+
+Routine Description:
+
+ This function allocates space from the capture buffer along with a
+ pointer to point to it. The pointer is presumed to be located in
+ the request message structure.
+
+Arguments:
+
+ CaptureBuffer - Pointer to a capture buffer allocated by
+ Od2AllocateCaptureBuffer.
+
+ Length - Size of data being allocated from the capture buffer.
+
+ Pointer - Address of the pointer within the request message that
+ is to point to the space allocated out of the capture buffer.
+
+Return Value:
+
+ The actual length of the buffer allocated, after it has been rounded
+ up to a multiple of 4.
+
+--*/
+
+{
+ if (Length == 0) {
+ *Pointer = NULL;
+ }
+
+ else {
+
+ //
+ // Set the returned pointer value to point to the next free byte in
+ // the capture buffer.
+ //
+
+ *Pointer = CaptureBuffer->FreeSpace;
+
+ //
+ // Round the length up to a multiple of 4
+ //
+
+ Length = (Length + 3) & ~3;
+
+ //
+ // Update the free space pointer to point to the next available byte
+ // in the capture buffer.
+ //
+
+ CaptureBuffer->FreeSpace += Length;
+ }
+
+
+ //
+ // Remember the location of this pointer so that Od2CallSubsystem can
+ // convert it into a server pointer prior to sending the request to
+ // the server.
+ //
+
+ CaptureBuffer->MessagePointerOffsets[ CaptureBuffer->CountMessagePointers++ ] =
+ (ULONG)Pointer;
+
+ //
+ // Returned the actual length allocated.
+ //
+
+ return( Length );
+}
+
+
+ULONG
+Od2AllocateCapturePointer(
+ IN OUT POS2_CAPTURE_HEADER CaptureBuffer,
+ IN ULONG Length,
+ OUT PVOID *Pointer
+ )
+/*++
+
+Routine Description:
+
+ This function allocates space from the capture buffer along with a
+ pointer to point to it. The pointer is presumed to be located within
+ the capture buffer itself.
+
+Arguments:
+
+ CaptureBuffer - Pointer to a capture buffer allocated by
+ Od2AllocateCaptureBuffer.
+
+ Length - Size of data being allocated from the capture buffer.
+
+ Pointer - Address of the pointer within the capture buffer that
+ is to point to the space allocated out of the capture buffer.
+
+Return Value:
+
+ The actual length of the buffer allocated, after it has been rounded
+ up to a multiple of 4.
+
+--*/
+
+{
+ //
+ // Set the returned pointer value to point to the next free byte in
+ // the capture buffer.
+ //
+
+ *Pointer = CaptureBuffer->FreeSpace;
+
+ //
+ // Round the length up to a multiple of 4
+ //
+
+ Length = (Length + 3) & ~3;
+
+ //
+ // Update the free space pointer to point to the next available byte in the
+ // capture buffer.
+ //
+
+ CaptureBuffer->FreeSpace += Length;
+
+ //
+ // Remember the location of this pointer so that Od2CallSubsystem can
+ // convert it into a server pointer prior to sending the request to
+ // the server.
+ //
+
+ CaptureBuffer->CapturePointerOffsets[ CaptureBuffer->CountCapturePointers++ ] =
+ (ULONG)Pointer;
+
+ //
+ // Returned the actual length allocated.
+ //
+
+ return( Length );
+}
+
+
+VOID
+Od2CaptureMessageString(
+ IN OUT POS2_CAPTURE_HEADER CaptureBuffer,
+ IN PCHAR String OPTIONAL,
+ IN ULONG Length,
+ IN ULONG MaximumLength,
+ OUT PSTRING CapturedString
+ )
+
+/*++
+
+Routine Description:
+
+ This function captures an ASCII string into a counted string data
+ structure located in an API request message.
+
+Arguments:
+
+ CaptureBuffer - Pointer to a capture buffer allocated by
+ Od2AllocateCaptureBuffer.
+
+ String - Optional pointer to the ASCII string. If this parameter is
+ not present, then the counted string data structure is set to
+ the null string and no space is allocated from the capture
+ buffer.
+
+ Length - Length of the ASCII string.
+
+ MaximumLength - Maximum length of the string. Different for null
+ terminated strings, where Length does not include the null and
+ MaximumLength does.
+
+ CaptureString - Pointer to the counted string data structure that will
+ be filled in to point to the capture ASCII string.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // If String parameter is not present, then set the captured string
+ // to be the null string and returned.
+ //
+
+ if (!ARGUMENT_PRESENT( String )) {
+ CapturedString->Length = 0;
+ CapturedString->MaximumLength = (USHORT)MaximumLength;
+ Od2AllocateMessagePointer( CaptureBuffer,
+ MaximumLength,
+ (PVOID *)&CapturedString->Buffer
+ );
+ return;
+ }
+
+ //
+ // Set the length fields of the captured string structure and allocated
+ // the MaximumLength for the string from the capture buffer.
+ //
+
+ CapturedString->Length = (USHORT)Length;
+ CapturedString->MaximumLength = (USHORT)
+ Od2AllocateMessagePointer( CaptureBuffer,
+ MaximumLength,
+ (PVOID *)&CapturedString->Buffer
+ );
+ //
+ // If the Length of the ASCII string is non-zero then move it to the
+ // capture area.
+ //
+
+ if (Length != 0) {
+ RtlMoveMemory( CapturedString->Buffer, String, MaximumLength );
+ }
+
+ return;
+}
+
+void
+Od2StartTimeout(
+ PLARGE_INTEGER StartTimeStamp
+ )
+{
+ NTSTATUS Status;
+
+ Status = NtQuerySystemTime(StartTimeStamp);
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DbgPrint("ERROR !!! NtQuerySystemTime: Status = %X\n", Status);
+ }
+#endif
+}
+
+NTSTATUS
+Od2ContinueTimeout(
+ PLARGE_INTEGER StartTimeStamp,
+ PLARGE_INTEGER Timeout
+ )
+{
+ NTSTATUS Status;
+ LONGLONG time;
+
+ if (Timeout == NULL) {
+#if DBG
+ IF_OD2_DEBUG( TIMERS ) {
+ DbgPrint("Od2ContinueTimeout: Indefinite wait\n");
+ }
+#endif
+ return STATUS_SUCCESS;
+ }
+
+ Status = NtQuerySystemTime((PLARGE_INTEGER)&time);
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DbgPrint("ERROR !!! NtQuerySystemTime: Status = %X\n", Status);
+ }
+#endif
+ time -= *(PLONGLONG)StartTimeStamp;
+#if DBG
+ IF_OD2_DEBUG( TIMERS ) {
+ DbgPrint("Od2ContinueTimeout: Timeout=0x%08X%08X, Expired time=0x%08X%08X\n",
+ Timeout->HighPart,
+ Timeout->LowPart,
+ ((PLARGE_INTEGER)&time)->HighPart,
+ ((PLARGE_INTEGER)&time)->LowPart
+ );
+ }
+#endif
+ time += *(PLONGLONG)Timeout;
+ if (time < 0) {
+ *(PLONGLONG)Timeout = time;
+#if DBG
+ IF_OD2_DEBUG( TIMERS ) {
+ DbgPrint("Od2ContinueTimeout: New timeout=0x%08X%08X\n",
+ Timeout->HighPart,
+ Timeout->LowPart
+ );
+ }
+#endif
+ return STATUS_SUCCESS;
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG( TIMERS ) {
+ DbgPrint("Od2ContinueTimeout: Timeout Expired\n");
+ }
+#endif
+ return STATUS_TIMEOUT;
+ }
+}
+
+PLARGE_INTEGER
+Od2CaptureTimeout(
+ IN ULONG MilliSeconds,
+ OUT PLARGE_INTEGER Timeout
+ )
+{
+ if (MilliSeconds == SEM_INDEFINITE_WAIT) {
+ return( NULL );
+ }
+ else {
+ *Timeout = RtlEnlargedIntegerMultiply( MilliSeconds, -10000 );
+ return( (PLARGE_INTEGER)Timeout );
+ }
+}
+
+VOID
+Od2ProbeForWrite(
+ IN PVOID Address,
+ IN ULONG Length,
+ IN ULONG Alignment
+ )
+
+/*++
+
+Routine Description:
+
+ This function probes a structure for read accessibility.
+ If the structure is not accessible, then an exception is raised.
+
+Arguments:
+
+ Address - Supplies a pointer to the structure to be probed.
+
+ Length - Supplies the length of the structure.
+
+ Alignment - Supplies the required alignment of the structure expressed
+ as the number of bytes in the primitive datatype (e.g., 1 for char,
+ 2 for short, 4 for long, and 8 for quad).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHAR volatile *StartAddress;
+ CHAR volatile *EndAddress;
+ volatile CHAR Temp;
+
+ //
+ // If the structure has zero length, then do not probe the structure for
+ // write accessibility or alignment.
+ //
+
+ if (Length != 0) {
+
+ //
+ // If the structure is not properly aligned, then raise a data
+ // misalignment exception.
+ //
+
+ ASSERT((Alignment == 1) || (Alignment == 2) ||
+ (Alignment == 4) || (Alignment == 8));
+ StartAddress = (volatile CHAR *)Address;
+
+ if (((ULONG)StartAddress & (Alignment - 1)) != 0) {
+ RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
+ } else {
+ //
+ // BUG, BUG - this should not be necessary once the 386 kernel
+ // makes system space inaccessable to user mode.
+ //
+ if ((ULONG)StartAddress > Od2NtSysInfo.MaximumUserModeAddress) {
+ RtlRaiseStatus(STATUS_ACCESS_VIOLATION);
+ }
+
+ Temp = *StartAddress;
+ *StartAddress = Temp;
+ EndAddress = StartAddress + Length - 1;
+ Temp = *EndAddress;
+ *EndAddress = Temp;
+ }
+ }
+}
+
+VOID
+Od2ProbeForRead(
+ IN PVOID Address,
+ IN ULONG Length,
+ IN ULONG Alignment
+ )
+
+/*++
+
+Routine Description:
+
+ This function probes a structure for read accessibility.
+ If the structure is not accessible, then an exception is raised.
+
+Arguments:
+
+ Address - Supplies a pointer to the structure to be probed.
+
+ Length - Supplies the length of the structure.
+
+ Alignment - Supplies the required alignment of the structure expressed
+ as the number of bytes in the primitive datatype (e.g., 1 for char,
+ 2 for short, 4 for long, and 8 for quad).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHAR volatile *StartAddress;
+ CHAR volatile *EndAddress;
+ volatile CHAR Temp;
+
+ //
+ // If the structure has zero length, then do not probe the structure for
+ // read accessibility or alignment.
+ //
+
+ if (Length != 0) {
+
+ //
+ // If the structure is not properly aligned, then raise a data
+ // misalignment exception.
+ //
+
+ ASSERT((Alignment == 1) || (Alignment == 2) ||
+ (Alignment == 4) || (Alignment == 8));
+ StartAddress = (volatile CHAR *)Address;
+
+ if (((ULONG)StartAddress & (Alignment - 1)) != 0) {
+ RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
+ } else {
+ Temp = *StartAddress;
+ EndAddress = StartAddress + Length - 1;
+ Temp = *EndAddress;
+ }
+ }
+}
+
+
+APIRET
+Od2CaptureObjectName(
+ IN PSZ ObjectName,
+ IN ULONG ObjectType,
+ IN ULONG ExtraCaptureBufferLength OPTIONAL,
+ OUT POS2_CAPTURE_HEADER *CaptureBuffer,
+ OUT PSTRING CapturedObjectName
+ )
+
+/*++
+
+Routine Description:
+
+ This function checks to see if an OS/2 Object name (queue, sem...) is
+ present. If not present, then it sets the output parameter to the
+ null string and returned.
+
+ If a name is present then it validates that the name does not exceed
+ the maximum length of OS/2 object name and that the specified string
+ begins with the correct prefix string. The prefix
+ comparison is case insensitive, in keeping with OS/2 conventions.
+
+ If the name is valid, then this function allocates a capture buffer
+ if not already allocated and captures the fully qualified NT object
+ name string. The NT string has been mapped to all upper case and
+ all path separator characters have been
+
+Arguments:
+
+ ObjectName - Pointer to a null terminated string that contains an OS/2
+ queue. Must be less than DC_SEM_MAXNAMEL in length
+ and being with the string defined by DC_SEM_NAMEPREFIX.
+
+ ObjectType - Expected type of object. Must be one of the following:
+
+ CANONICALIZE_SHARED_MEMORY - the input path must refer to a
+ shared memory section. This means it must begin with \sharemem\
+ For example: \sharemem\ObjectName\a.b is mapped to an NT
+ object name of the form:
+
+ \OS2SS\SHAREDMEMORY\OBJECTNAME/A.B
+
+ CANONICALIZE_SEMAPHORE - the input path must refer to a 32-bit
+ semaphore name. This means it must begin with \sem32\
+ For example: \sem32\ObjectName\a.b is mapped to an NT object
+ name of the form:
+
+ \OS2SS\SEMAPHORES\OBJECTNAME/A.B
+
+ CANONICALIZE_QUEUE - the input path must refer to a 32-bit queue
+ name. This means it must begin with \queues\
+ For example: \queues\ObjectName\a.b is mapped to an NT
+ object name of the form:
+
+ \OS2SS\QUEUES\OBJECTNAME/A.B
+
+ ExtraCaptureBufferLength - Optional parameter that allows an additional
+ capture pointer to be allocated in the capture buffer.
+
+ CaptureBuffer - Pointer to the variable to receive the address of the
+ capture buffer allocated by this function for the captured name.
+
+ CapturedObjectName - Pointer to a STRING variable that is to point
+ to the captured text. The length does not include the trailing
+ null byte.
+
+Return Value:
+
+ OS/2 Error Code - one of the following:
+
+ NO_ERROR - success
+
+ ERROR_INVALID_NAME - name is too long or does not begin with the
+ correct prefix.
+
+ ERROR_NOT_ENOUGH_MEMORY - no memory to hold the captured name.
+
+--*/
+
+{
+ APIRET rc;
+ ULONG ObjectNameLength, CaptureBufferLength, MessageBufferPointers;
+ STRING CanonicalObjectName;
+
+ //
+ // If no memory name present, then set the output string to the NULL
+ // string, and set the capture buffer pointer to NULL. Return success.
+ //
+
+ if (ObjectName == NULL) {
+ *CaptureBuffer = NULL;
+ CapturedObjectName->Buffer = NULL;
+ CapturedObjectName->Length = 0;
+ CapturedObjectName->MaximumLength = 0;
+ return( NO_ERROR );
+ }
+
+ rc = Od2Canonicalize( ObjectName,
+ ObjectType,
+ &CanonicalObjectName,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ if (rc != NO_ERROR) {
+ if (rc == ERROR_FILE_NOT_FOUND || rc == ERROR_PATH_NOT_FOUND) {
+ if (ObjectType == CANONICALIZE_QUEUE) {
+ return( ERROR_QUE_INVALID_NAME );
+ }
+ else {
+ return( ERROR_INVALID_NAME );
+ }
+ }
+ else
+ if (rc == ERROR_NOT_ENOUGH_MEMORY && ObjectType == CANONICALIZE_QUEUE) {
+ return( ERROR_QUE_NO_MEMORY );
+ }
+ else
+ if (rc == ERROR_FILENAME_EXCED_RANGE) {
+ if (ObjectType == CANONICALIZE_QUEUE) {
+ return( ERROR_QUE_INVALID_NAME );
+ }
+ else {
+ return( ERROR_INVALID_NAME );
+ }
+ }
+ else {
+ return( rc );
+ }
+ }
+
+ ObjectNameLength = CanonicalObjectName.Length;
+
+ //
+ // Allocate a capture buffer big enough to hold the object name.
+ // If the caller specified additional capture buffer length, then include
+ // that in the size of the capture buffer and allocate two pointers field
+ // in the capture buffer. Otherwise just allocate one pointer field in
+ // the capture buffer. Return an error if not enough memory to allocate
+ // the buffer.
+ //
+
+ CaptureBufferLength = (ObjectNameLength + 3) & ~3;
+ MessageBufferPointers = 1;
+
+ if (ARGUMENT_PRESENT( ExtraCaptureBufferLength )) {
+ CaptureBufferLength += (ExtraCaptureBufferLength + 3) & ~3;
+ MessageBufferPointers += 1;
+ }
+
+ *CaptureBuffer = Od2AllocateCaptureBuffer( MessageBufferPointers,
+ 0,
+ CaptureBufferLength
+ );
+ if (*CaptureBuffer == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ else {
+ //
+ // Capture the string into the passed counted string variable.
+ //
+
+ Od2CaptureMessageString( *CaptureBuffer,
+ CanonicalObjectName.Buffer,
+ ObjectNameLength,
+ ObjectNameLength,
+ CapturedObjectName
+ );
+ }
+
+ //
+ // Now free the copy of the string allocated by Od2Canonicalize.
+ //
+
+ RtlFreeHeap( Od2Heap, 0, CanonicalObjectName.Buffer );
+
+ //
+ // Return success.
+ //
+
+ return( rc );
+}
+
+#if DBG
+VOID
+AcquireFileLockShared(
+ IN PSZ CallingRoutine
+ )
+{
+ PTEB Teb;
+
+ Teb = NtCurrentTeb();
+
+ if (Teb->EnvironmentPointer != NULL && Od2CurrentThreadId() == 1) {
+ DosHoldSignal(HLDSIG_DISABLE, 0);
+ }
+
+ IF_OD2_DEBUG( FILESYSLOCK ) {
+ Teb = NtCurrentTeb();
+#if DBG
+ KdPrint(("entering AcquireFileLock for client id %ld%ld in %s\n",
+ Teb->ClientId.UniqueProcess,
+ Teb->ClientId.UniqueThread,
+ CallingRoutine));
+#endif
+ (VOID)RtlAcquireResourceShared( &Od2Process->FileLock, TRUE );
+#if DBG
+ KdPrint(("leaving AcquireFileLock for client id %ld%ld in %s\n",
+ Teb->ClientId.UniqueProcess,
+ Teb->ClientId.UniqueThread,
+ CallingRoutine));
+#endif
+ }
+ else {
+ (VOID)RtlAcquireResourceShared( &Od2Process->FileLock, TRUE );
+ }
+}
+
+VOID
+ReleaseFileLockShared(
+ IN PSZ CallingRoutine
+ )
+{
+ PTEB Teb;
+
+ Teb = NtCurrentTeb();
+
+ IF_OD2_DEBUG( FILESYSLOCK ) {
+#if DBG
+ KdPrint(("entering ReleaseFileLockShared for client id %ld%ld in %s\n",
+ Teb->ClientId.UniqueProcess,
+ Teb->ClientId.UniqueThread,
+ CallingRoutine));
+#endif
+ RtlReleaseResource( &Od2Process->FileLock );
+#if DBG
+ KdPrint(("leaving ReleaseFileLockShared for client id %ld%ld in %s\n",
+ Teb->ClientId.UniqueProcess,
+ Teb->ClientId.UniqueThread,
+ CallingRoutine));
+#endif
+ }
+ else {
+ RtlReleaseResource( &Od2Process->FileLock );
+ }
+
+ if (Teb->EnvironmentPointer != NULL && Od2CurrentThreadId() == 1) {
+ DosHoldSignal(HLDSIG_ENABLE, 0);
+ }
+}
+
+VOID
+PromoteFileLocktoExclusive(
+ IN PSZ CallingRoutine
+ )
+{
+ PTEB Teb;
+
+ IF_OD2_DEBUG( FILESYSLOCK ) {
+ Teb = NtCurrentTeb();
+#if DBG
+ KdPrint(("entering PromoteFileLocktoExclusive for client id %ld%ld in %s\n",
+ Teb->ClientId.UniqueProcess,
+ Teb->ClientId.UniqueThread,
+ CallingRoutine));
+#endif
+ RtlConvertSharedToExclusive( &Od2Process->FileLock );
+#if DBG
+ KdPrint(("leaving PromoteFileLocktoExclusive for client id %ld%ld in %s\n",
+ Teb->ClientId.UniqueProcess,
+ Teb->ClientId.UniqueThread,
+ CallingRoutine));
+#endif
+ }
+ else {
+ RtlConvertSharedToExclusive( &Od2Process->FileLock );
+ }
+}
+
+VOID
+AcquireFileLockExclusive(
+ IN PSZ CallingRoutine
+ )
+{
+ PTEB Teb;
+
+ Teb = NtCurrentTeb();
+
+ if (Teb->EnvironmentPointer != NULL && Od2CurrentThreadId() == 1) {
+ DosHoldSignal(HLDSIG_DISABLE, 0);
+ }
+
+ IF_OD2_DEBUG( FILESYSLOCK ) {
+#if DBG
+ KdPrint(("entering AcquireFileLockExclusive for client id %ld%ld in %s\n",
+ Teb->ClientId.UniqueProcess,
+ Teb->ClientId.UniqueThread,
+ CallingRoutine));
+#endif
+ if (Od2SigHandlingInProgress &&
+ Od2CurrentThreadId() == 1) {
+ //
+ // We have to be carefull not to acquire exclusive right
+ // in case we already have shared access
+ //
+ if (!RtlAcquireResourceExclusive( &Od2Process->FileLock, FALSE )) {
+ Od2DontReleaseFileLock = TRUE;
+ }
+
+ }
+ else
+ (VOID)RtlAcquireResourceExclusive( &Od2Process->FileLock, TRUE );
+#if DBG
+ KdPrint(("leaving AcquireFileLockExclusive for client id %ld%ld in %s\n",
+ Teb->ClientId.UniqueProcess,
+ Teb->ClientId.UniqueThread,
+ CallingRoutine));
+#endif
+ }
+ else {
+ if (Od2SigHandlingInProgress &&
+ Od2CurrentThreadId() == 1) {
+ //
+ // We have to be carefull not to acquire exclusive right
+ // in case we already have shared access
+ //
+ if (!RtlAcquireResourceExclusive( &Od2Process->FileLock, FALSE )) {
+ Od2DontReleaseFileLock = TRUE;
+ }
+
+ }
+ else
+ (VOID)RtlAcquireResourceExclusive( &Od2Process->FileLock, TRUE );
+ }
+}
+
+VOID
+ReleaseFileLockExclusive(
+ IN PSZ CallingRoutine
+ )
+{
+ PTEB Teb;
+
+ Teb = NtCurrentTeb();
+
+ IF_OD2_DEBUG( FILESYSLOCK ) {
+#if DBG
+ KdPrint(("entering ReleaseFileLockExclusive for client id %ld%ld in %s\n",
+ Teb->ClientId.UniqueProcess,
+ Teb->ClientId.UniqueThread,
+ CallingRoutine));
+#endif
+ if (Od2SigHandlingInProgress &&
+ Od2CurrentThreadId() == 1) {
+ if (Od2DontReleaseFileLock)
+ Od2DontReleaseFileLock = FALSE;
+
+ }
+ else
+ RtlReleaseResource( &Od2Process->FileLock );
+#if DBG
+ KdPrint(("leaving ReleaseFileLockExclusive for client id %ld%ld in %s\n",
+ Teb->ClientId.UniqueProcess,
+ Teb->ClientId.UniqueThread,
+ CallingRoutine));
+#endif
+ }
+ else {
+ if (Od2SigHandlingInProgress &&
+ Od2CurrentThreadId() == 1) {
+ if (Od2DontReleaseFileLock)
+ Od2DontReleaseFileLock = FALSE;
+
+ }
+ else {
+ RtlReleaseResource( &Od2Process->FileLock );
+ }
+ }
+
+ if (Teb->EnvironmentPointer != NULL && Od2CurrentThreadId() == 1) {
+ DosHoldSignal(HLDSIG_ENABLE, 0);
+ }
+}
+#else // DBG
+
+VOID
+AcquireFileLockShared()
+{
+ PTEB Teb;
+
+ Teb = NtCurrentTeb();
+
+ if (Teb->EnvironmentPointer != NULL && Od2CurrentThreadId() == 1) {
+ DosHoldSignal(HLDSIG_DISABLE, 0);
+ }
+
+ (VOID)RtlAcquireResourceShared( &Od2Process->FileLock, TRUE );
+}
+
+VOID
+ReleaseFileLockShared()
+{
+ PTEB Teb;
+
+ Teb = NtCurrentTeb();
+
+ RtlReleaseResource( &Od2Process->FileLock );
+
+ if (Teb->EnvironmentPointer != NULL && Od2CurrentThreadId() == 1) {
+ DosHoldSignal(HLDSIG_ENABLE, 0);
+ }
+}
+
+VOID
+AcquireFileLockExclusive()
+{
+
+ if (Od2CurrentThreadId() == 1) {
+
+ DosHoldSignal(HLDSIG_DISABLE, 0);
+
+ if (Od2SigHandlingInProgress) {
+ //
+ // API called while handling a signal or exit list:
+ // We have to be carefull not to acquire exclusive right
+ // in case we already have shared access
+ //
+ if (!RtlAcquireResourceExclusive( &Od2Process->FileLock, FALSE )) {
+ Od2DontReleaseFileLock = TRUE;
+ }
+ return;
+ }
+ }
+
+ (VOID)RtlAcquireResourceExclusive( &Od2Process->FileLock, TRUE );
+}
+
+VOID
+ReleaseFileLockExclusive()
+{
+ if (Od2SigHandlingInProgress &&
+ Od2CurrentThreadId() == 1) {
+ if (Od2DontReleaseFileLock)
+ Od2DontReleaseFileLock = FALSE;
+
+ }
+ else
+ RtlReleaseResource( &Od2Process->FileLock );
+
+ if (Od2CurrentThreadId() == 1) {
+ DosHoldSignal(HLDSIG_ENABLE, 0);
+ }
+}
+#endif // DBG
+
+/*++
+
+Routine description:
+
+ Copies a C string to a wide-string (WSTR, in which each char takes 2 bytes).
+ Allocates space for the PWSTR if NULL.
+
+Return value:
+
+ Pointer to the WSTR.
+
+--*/
+
+PWSTR Od2CopyStrToWstr(
+ IN OUT PWSTR wstr OPTIONAL,
+ IN PSZ str
+ )
+{
+ if (wstr == NULL)
+ wstr = (PWSTR)RtlAllocateHeap(Od2Heap, 0, (strlen(str) + 1)*sizeof(WCHAR));
+
+ if (!wstr) {
+#if DBG
+ KdPrint(("OS2: Od2CopyStrToWstr out of heap memory, fail\n"));
+#endif
+ return NULL;
+ }
+
+ for ( ; *str; str++, wstr++)
+ {
+ *wstr = (WCHAR)((unsigned char)*str);
+ }
+ *wstr = 0;
+
+ return wstr;
+}
+
+/*++
+
+Routine description:
+
+ Computes the size (in bytes) of a wide string (2-bytes chars).
+
+Return value:
+
+ Size (in bytes) of the wide string.
+
+--*/
+
+int Od2WstrSize(
+ IN PWSTR pwstr
+ )
+{
+ int i;
+
+ for (i=0; *(pwstr + i) != 0; i++);
+
+ return sizeof(WCHAR)*(i + 1); /* Include the terminating \0 */
+}
+
+/*++
+
+Routine description:
+
+ Copies a wide-string (WSTR, in which each char takes 2 bytes) to a C string.
+ Allocates space for the C string if NULL.
+
+Return value:
+
+ Pointer to the C string.
+
+--*/
+
+PSZ Od2CopyWstrToStr(
+ IN OUT PSZ str OPTIONAL,
+ IN PWSTR wstr
+ )
+{
+ if (str == NULL)
+ str = (PSZ)RtlAllocateHeap(Od2Heap, 0, Od2WstrSize(wstr)
+ / sizeof(WCHAR)
+ * sizeof(CHAR));
+
+ if (!str) {
+#if DBG
+ KdPrint(("OS2: Od2CopyWtrToStr out of heap memory, fail\n"));
+#endif
+ return NULL;
+ }
+
+ for ( ; *wstr; str++,wstr++)
+ {
+ *str = *(unsigned char *)wstr;
+ }
+ *str = '\0';
+
+ return str;
+}
+
+/*++
+
+Routine description:
+
+ Copies n chars of up to the first NULL (whichever comes first) from a
+ wide-string (WSTR, in which each char takes 2 bytes) to a C string.
+ Allocates space for the C string if NULL.
+ Warning: Unlike strncpy(), the resulting C string gets a \0 at its end (which
+ means the target string will have n non-zero chars + 1 \0), even
+ if we stopped after n chars. Also, if the source string terminates before n
+ chars, we do not pad the target string with 0's.
+
+Parameters:
+
+ str - target C string.
+ wstr - source wide string.
+ n - length, in characters, of the resulting C string (of length of the WSTR
+ divided by 2).
+
+Return value:
+
+ Pointer to the C string.
+
+--*/
+
+PSZ Od2nCopyWstrToStr(
+ IN OUT PSZ str OPTIONAL,
+ IN PWSTR wstr,
+ IN int n
+ )
+{
+ int i;
+
+ if (str == NULL)
+ str = (PSZ)RtlAllocateHeap(Od2Heap, 0, Od2WstrSize(wstr)
+ / sizeof(WCHAR)
+ * sizeof(CHAR));
+ if (!str) {
+#if DBG
+ KdPrint(("OS2: Od2nCopyWtrToStr out of heap memory, fail\n"));
+#endif
+ return NULL;
+ }
+
+ for (i=0; (*wstr) && (i<n); str++, wstr++, i++)
+ {
+ *str = *(unsigned char *)wstr;
+ }
+ *str = '\0';
+
+ return str;
+}
+
+/* Utility routines for manipulations of EA's */
+
+APIRET Od2FixFEA2List(
+ IN FEA2LIST *fpFEA2List)
+{
+ FEA2 *pFEA2;
+ ULONG FEA2_total_size;
+
+ for (pFEA2=&(fpFEA2List->list[0]), FEA2_total_size=sizeof(ULONG);
+ pFEA2->oNextEntryOffset != 0;
+ pFEA2=(FEA2 *)((PBYTE)pFEA2
+ + pFEA2->oNextEntryOffset))
+ {
+ FEA2_total_size += pFEA2->oNextEntryOffset;
+ /* Fix .fEA field */
+ /* BUGBUG - following some RAID bug reports, NT .FEA were set
+ correctly starting around end of May 92. Therefore, this
+ workaround below should be removed sometime after NT Beta
+ */
+ if (pFEA2->cbValue != 0)
+ pFEA2->fEA = FEA_NEEDEA;
+ else
+ pFEA2->fEA = 0;
+ }
+
+ /* Account for last entry */
+ FEA2_total_size += sizeof(ULONG)
+ + sizeof(BYTE)
+ + sizeof(BYTE)
+ + sizeof(USHORT)
+ + pFEA2->cbName + 1
+ + pFEA2->cbValue;
+ /* Fix .fEA field */
+ /* BUGBUG - following some RAID bug reports, NT .FEA were set
+ correctly starting around end of May 92. Therefore, this
+ workaround below should be removed sometime after NT Beta
+ */
+ if (pFEA2->cbValue != 0)
+ pFEA2->fEA = FEA_NEEDEA;
+ else
+ pFEA2->fEA = 0;
+
+ fpFEA2List->cbList = FEA2_total_size;
+
+ return NO_ERROR;
+}
diff --git a/private/os2/client/dllvio.c b/private/os2/client/dllvio.c
new file mode 100644
index 000000000..1c23c631e
--- /dev/null
+++ b/private/os2/client/dllvio.c
@@ -0,0 +1,2422 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllvio.c
+
+Abstract:
+
+ This module implements the VIOCALLS OS/2 V2.0 API Calls
+
+Author:
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_NLS
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+#include "conrqust.h"
+#include "os2nls.h"
+#include "os2win.h"
+#include <stdio.h>
+
+#if DBG
+#define EXCEPTION_IN_VIO() \
+ { \
+ KdPrint(("%s: GP Exception\n", FuncName)); \
+ Od2ExitGP(); \
+ }
+
+#else
+#define EXCEPTION_IN_VIO() \
+ Od2ExitGP();
+#endif
+
+#define SET_SCROLL_PARMS() \
+ Scroll.ScrollRect.Left = (SHORT)ulLeftCol; \
+ Scroll.ScrollRect.Top = (SHORT)ulTopRow; \
+ Scroll.ScrollRect.Right = (SHORT)ulRightCol; \
+ Scroll.ScrollRect.Bottom = (SHORT)ulBotRow; \
+ Scroll.cbLines = (SHORT)cbLines; \
+ try \
+ { \
+ RtlMoveMemory( &Scroll.Cell[0], \
+ pbCell, \
+ SesGrp->BytesPerCell); \
+ } except( EXCEPTION_EXECUTE_HANDLER ) \
+ { \
+ EXCEPTION_IN_VIO() \
+ }
+
+#if DBG
+#define TEST_HVIO_NON_AVIO() \
+ if (hVio != 0) \
+ { \
+ KdPrint(("%s: hVio non NULL - AVIO not supported yet\n", \
+ FuncName)); \
+ return ERROR_VIO_INVALID_HANDLE; \
+ }
+#else
+#define TEST_HVIO_NON_AVIO() \
+ if (hVio != 0) \
+ { \
+ return ERROR_VIO_INVALID_HANDLE; \
+ }
+#endif
+
+#if DBG
+#define CHECK_RETURN_STATUS() \
+ if ( RetCode ) \
+ { \
+ IF_OD2_DEBUG( VIO ) \
+ KdPrint(("%s: status %lu\n", FuncName, RetCode)); \
+ return(RetCode); \
+ }
+#else
+#define CHECK_RETURN_STATUS() \
+ if ( RetCode ) \
+ { \
+ return(RetCode); \
+ }
+#endif
+
+#if DBG
+#define CHECK_POPUP_EXIST() \
+ if (SesGrp->PopUpFlag && \
+ (SesGrp->PopUpProcess == (HANDLE)(Od2Process->Pib.ProcessId))) \
+ { \
+ IF_OD2_DEBUG( VIO ) \
+ KdPrint(("%s: illegal call when PopUp exist\n", FuncName )); \
+ return( ERROR_VIO_ILLEGAL_DURING_POPUP ); \
+ }
+#else
+#define CHECK_POPUP_EXIST() \
+ if (SesGrp->PopUpFlag && \
+ (SesGrp->PopUpProcess == (HANDLE)(Od2Process->Pib.ProcessId))) \
+ { \
+ return( ERROR_VIO_ILLEGAL_DURING_POPUP ); \
+ }
+#endif
+
+APIRET
+Od2VioCheckPopupAndPause(
+ IN BOOLEAN AllowedInPopup,
+ IN BOOLEAN Wait
+#if DBG
+ ,IN PSZ FuncName
+#endif
+ );
+
+
+/*
+ * Each API is composed of the following steps:
+ *
+ * 1. Dump to the debugger the func name and some parms
+ * (protected by "#if DBG" and "IF_OD2_DEBUG( VIO )"
+ * 2A. Testing for non AVIO (hVio zero)
+ * 2B. Test other parm legalty
+ * 2C. Probe address parmeters
+ * 2D. Check popup and pause
+ * 3. Call Ow2Xxxx API (from os2ses\viorqust.c)
+ * 4. CHECK_RETURN_STATUS()
+ * 5. Update return parms
+ * 6. Return Rc
+ */
+
+
+
+APIRET
+VioWrtTTY(IN PCH string,
+ IN ULONG Length,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioWrtTTY";
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Len %lu, 0x%x...\n",
+ FuncName, hVio, Length, (ULONG)(UCHAR)*string));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ Od2ProbeForRead(string, Length, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioWriteTTYStr(
+ string,
+ Length,
+ (ULONG)VIOWrtTTY
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioWrtCellStr(IN PCH CellStr,
+ IN ULONG Length,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioWrtCellStr";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Len %lu, Row %lu, Col %lu, CellString 0x%x:0x%x...\n",
+ FuncName, hVio, Length ,Row, Col,
+ (ULONG)(UCHAR)CellStr[0],(ULONG)(UCHAR)CellStr[1]));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ //try
+ //{
+ // Od2ProbeForRead(CellStr, Length, 1);
+ //} except( EXCEPTION_EXECUTE_HANDLER )
+ //{
+ // EXCEPTION_IN_VIO()
+ //}
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ Length &= SesGrp->VioLengthMask; /* length should be even */
+
+ RetCode = Ow2VioWriteCellStr(
+ Length,
+ Row,
+ Col,
+ CellStr
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioWrtCharStr(IN PCH CharStr,
+ IN ULONG Length,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioWrtCharStr";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Len %lu, Row %lu, Col %lu, 0x%x...\n",
+ FuncName, hVio, Length, Row, Col, (ULONG)(UCHAR)*CharStr));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ //try
+ //{
+ // Od2ProbeForRead(CharStr, Length, 1);
+ //} except( EXCEPTION_EXECUTE_HANDLER )
+ //{
+ // EXCEPTION_IN_VIO()
+ //}
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioWriteCharStr(
+ Length,
+ Row,
+ Col,
+ CharStr
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioWrtCharStrAtt(IN PCH CharStr,
+ IN ULONG Length,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PBYTE Attr,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioWrtCharStrAtt";
+
+ IF_OD2_DEBUG(VIO)
+ {
+#if 0
+ UCHAR Buffer[256], *Ptr = CharStr, *Ptr1;
+ ULONG Count = Length, CurCount, i, j;
+#endif
+ KdPrint(("%s: hVio %lx, Len %lu, Row %lu, Col %lu, Attr %x, 0x%x...\n",
+ FuncName, hVio, Length, Row, Col, (ULONG)(UCHAR)*Attr,
+ (ULONG)(UCHAR)*CharStr));
+
+#if 0
+ for ( j = 0 ; Count ; Count -= CurCount, Ptr += CurCount, j++ )
+ {
+ CurCount = ( Count > 16 ) ? 16 : Count;
+
+ sprintf(Buffer, " %2.2x. %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x = ",
+ j,
+ Ptr[0], Ptr[1], Ptr[2], Ptr[3], Ptr[4], Ptr[5], Ptr[6], Ptr[7],
+ Ptr[8], Ptr[9], Ptr[10], Ptr[11], Ptr[12], Ptr[13], Ptr[14], Ptr[15]
+ );
+
+ Ptr1 = &Buffer[59];
+ for ( i = 0 ; i < 16 ; i++ )
+ {
+ if ( i >= CurCount )
+ {
+ Buffer[8 + i * 3] = Buffer[9 + i * 3] = Buffer[10 + i * 3] = ' ';
+ } else if ((Ptr[i] < 0x20) || (Ptr[i] > 0x7E))
+ {
+ *Ptr1++ = '?';
+ } else
+ {
+ *Ptr1++ = Ptr[i];
+ }
+ }
+
+ *Ptr1++ = '\n';
+ *Ptr1 = '\0';
+
+ KdPrint((Buffer));
+ }
+#endif
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ // Od2ProbeForRead(CharStr, Length, 1);
+ Od2ProbeForRead(Attr, SesGrp->BytesPerCell - 1, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioWriteCharStrAtt(
+ Length,
+ Row,
+ Col,
+ CharStr,
+ Attr
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioWrtNCell(IN PBYTE Cell,
+ IN ULONG Number,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioWrtNCell";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Num %lu, Cell %x:%x, Row %lu, Col %lu\n",
+ FuncName, hVio, Number, (ULONG)(UCHAR)Cell[0],
+ (ULONG)(UCHAR)Cell[1], Row, Col));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+#ifdef DBCS
+// MSKK Jan.13.1993 V-AkihiS
+// MSKK Oct.11.1993 V-AkihiS
+ if (Ow2NlsIsDBCSLeadByte(*Cell, SesGrp->VioCP)) {
+ Od2ProbeForRead(Cell, SesGrp->BytesPerCell * 2, 1);
+ } else {
+ Od2ProbeForRead(Cell, SesGrp->BytesPerCell, 1);
+ }
+#else
+ Od2ProbeForRead(Cell, SesGrp->BytesPerCell, 1);
+#endif
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ RetCode = Ow2VioFillNCell(
+ Number,
+ Row,
+ Col,
+ Cell
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioWrtNAttr(IN PBYTE Attr,
+ IN ULONG Number,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioWrtNAttr";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Num %lu, Attr %x, Row %lu, Col %lu\n",
+ FuncName, hVio, Number, (ULONG)(UCHAR)*Attr, Row, Col));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ Od2ProbeForRead(Attr, SesGrp->BytesPerCell - 1, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ RetCode = Ow2VioFillNAttr(
+ Number,
+ Row,
+ Col,
+ Attr
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioWrtNChar(IN PBYTE Char,
+ IN ULONG Number,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioWrtNChar";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Num %lu, Char %x, Row %lu, Col %lu\n",
+ FuncName, hVio, Number, (ULONG)(UCHAR)*Char, Row, Col));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+#ifdef DBCS
+// MSKK Jan.13.1993 V-AkihiS
+// MSKK Oct.11.1993 V-AkihiS
+ if (Ow2NlsIsDBCSLeadByte(*Char, SesGrp->VioCP)) {
+ Od2ProbeForRead(Char, 2, 1);
+ } else {
+ Od2ProbeForRead(Char, 1, 1);
+ }
+#else
+ Od2ProbeForRead(Char, 1, 1);
+#endif
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ RetCode = Ow2VioFillNChar(
+ Number,
+ Row,
+ Col,
+ Char
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioReadCellStr(OUT PCH CellStr,
+ IN OUT PUSHORT Length,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+ ULONG VioLength;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioReadCellStr";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Len %u, Row %lu, Col %lu\n",
+ FuncName, hVio, (ULONG)*Length, Row, Col));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ Od2ProbeForWrite(Length, sizeof(USHORT), 1);
+ // Od2ProbeForWrite(CellStr, *Length, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ VioLength = *Length & SesGrp->VioLengthMask; /* length should be even */
+
+ RetCode = Ow2VioReadCellStr(
+ &VioLength,
+ Row,
+ Col,
+ CellStr
+ );
+
+ CHECK_RETURN_STATUS()
+
+ *Length = (USHORT)VioLength;
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioReadCharStr(OUT PCH CharStr,
+ IN OUT PUSHORT Length,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+ ULONG VioLength;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioReadCharStr";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Len %u, Row %lu, Col %lu\n",
+ FuncName, hVio, (ULONG)*Length, Row, Col));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ Od2ProbeForWrite(Length, sizeof(USHORT), 1);
+ // Od2ProbeForWrite(CharStr, *Length, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ VioLength = *Length;
+
+ RetCode = Ow2VioReadCharStr(
+ &VioLength,
+ Row,
+ Col,
+ CharStr
+ );
+
+ CHECK_RETURN_STATUS()
+
+ *Length = (USHORT)VioLength;
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioScrollDn(IN ULONG ulTopRow,
+ IN ULONG ulLeftCol,
+ IN ULONG ulBotRow,
+ IN ULONG ulRightCol,
+ IN ULONG cbLines,
+ IN PBYTE pbCell,
+ IN ULONG hVio)
+{
+ VIOSCROLL Scroll;
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioScrollDown";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, # %lu, at %lu:%lu:%lu:%lu, %x:%x\n",
+ FuncName, hVio, cbLines, ulTopRow, ulLeftCol, ulBotRow, ulRightCol,
+ (ULONG)*pbCell, (ULONG)pbCell[1]));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ SET_SCROLL_PARMS()
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioScroll(
+ (PVOID)&Scroll,
+ 1
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioScrollLf(IN ULONG ulTopRow,
+ IN ULONG ulLeftCol,
+ IN ULONG ulBotRow,
+ IN ULONG ulRightCol,
+ IN ULONG cbLines,
+ IN PBYTE pbCell,
+ IN ULONG hVio)
+{
+ VIOSCROLL Scroll;
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioScrollLeft";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, # %lu, at %lu:%lu:%lu:%lu, %x:%x\n",
+ FuncName, hVio, cbLines, ulTopRow, ulLeftCol, ulBotRow, ulRightCol,
+ (ULONG)*pbCell, (ULONG)pbCell[1]));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ SET_SCROLL_PARMS()
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioScroll(
+ (PVOID)&Scroll,
+ 4
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return( NO_ERROR );
+}
+
+
+APIRET
+VioScrollRt(IN ULONG ulTopRow,
+ IN ULONG ulLeftCol,
+ IN ULONG ulBotRow,
+ IN ULONG ulRightCol,
+ IN ULONG cbLines,
+ IN PBYTE pbCell,
+ IN ULONG hVio)
+{
+ VIOSCROLL Scroll;
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioScrollRight";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, # %lu, at %lu:%lu:%lu:%lu, %x:%x\n",
+ FuncName, hVio, cbLines, ulTopRow, ulLeftCol, ulBotRow, ulRightCol,
+ (ULONG)*pbCell, (ULONG)pbCell[1]));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ SET_SCROLL_PARMS()
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioScroll(
+ (PVOID)&Scroll,
+ 2
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return( NO_ERROR );
+}
+
+
+APIRET
+VioScrollUp(IN ULONG ulTopRow,
+ IN ULONG ulLeftCol,
+ IN ULONG ulBotRow,
+ IN ULONG ulRightCol,
+ IN ULONG cbLines,
+ IN PBYTE pbCell,
+ IN ULONG hVio)
+{
+ VIOSCROLL Scroll;
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioScrollUp";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, # %lu, at %lu:%lu:%lu:%lu, %x:%x\n",
+ FuncName, hVio, cbLines, ulTopRow, ulLeftCol, ulBotRow, ulRightCol,
+ (ULONG)*pbCell, (ULONG)pbCell[1]));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ SET_SCROLL_PARMS()
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioScroll(
+ (PVOID)&Scroll,
+ 3
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return( NO_ERROR );
+}
+
+
+APIRET
+VioGetAnsi( OUT PUSHORT pfAnsi,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioGetAnsi";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ Od2ProbeForWrite(pfAnsi, 2, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ *pfAnsi = (USHORT)SesGrp->AnsiMode;
+
+#if DBG
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Ansi %u\n", FuncName, hVio, (ULONG)*pfAnsi));
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioSetAnsi( IN ULONG fAnsi,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioSetAnsi";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Ansi %lu\n", FuncName, hVio, fAnsi));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ FALSE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ if ((fAnsi!= ANSI_ON) && (fAnsi!=ANSI_OFF))
+ {
+ return(ERROR_VIO_INVALID_PARMS);
+ }
+
+ SesGrp->AnsiMode = fAnsi;
+ return NO_ERROR;
+}
+
+
+APIRET
+VioGetConfig( IN ULONG usConfigId, // this is no longer reserved value
+ IN OUT PVIOCONFIGINFO Config,
+ IN ULONG hVio)
+{
+ APIRET RetCode = NO_ERROR;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioGetConfig";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, size %u\n",
+ FuncName, hVio, (ULONG)Config->cb));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ if (usConfigId > VIO_CONFIG_PRIMARY) // it's not CURRENT/PRIMARY
+ {
+ return(ERROR_VIO_INVALID_PARMS);
+ }
+
+ try
+ {
+ if ((Config->cb != sizeof(VIOCONFIGINFO)) &&
+ (Config->cb != 10))
+ {
+#if DBG
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: illegal length(cb) %u\n",
+ FuncName, Config->cb));
+ }
+#endif
+ RetCode = ERROR_VIO_INVALID_LENGTH;
+ }
+
+ Od2ProbeForWrite(Config, Config->cb, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (RetCode)
+ {
+ return(RetCode);
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioGetConfig(
+ (PVOID)Config
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioGetCp( IN ULONG usReserved,
+ OUT PUSHORT pIdCodePage,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioGetCp";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ if (usReserved)
+ {
+ return(ERROR_VIO_INVALID_PARMS);
+ }
+
+ try
+ {
+ Od2ProbeForWrite(pIdCodePage, 2, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ *pIdCodePage = (USHORT)SesGrp->VioCP;
+
+#if DBG
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Cp %u\n", FuncName, hVio, (ULONG)*pIdCodePage));
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioSetCp( IN ULONG usReserved,
+ IN ULONG idCodePage,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioSetCp";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Cp %lu\n", FuncName, hVio, idCodePage));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ if (usReserved)
+ {
+ return(ERROR_VIO_INVALID_PARMS);
+ }
+
+#ifdef DBCS
+// MSKK Apr.15.1993 V-AkihiS
+// allow code page = 0
+ if (( idCodePage != 0 ) &&
+ ( idCodePage != SesGrp->PrimaryCP ) &&
+ ( idCodePage != SesGrp->SecondaryCP ))
+#else
+ if (( idCodePage == 0 ) ||
+ (( idCodePage != SesGrp->PrimaryCP ) &&
+ ( idCodePage != SesGrp->SecondaryCP )))
+#endif
+ {
+#if DBG
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: invalid CP %lu\n", idCodePage));
+ }
+#endif
+ return (ERROR_INVALID_CODE_PAGE);
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioSetNewCp(
+ idCodePage
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioGetCurPos( OUT PUSHORT pusRow,
+ OUT PUSHORT pusColumn,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioGetCurPos";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ Od2ProbeForWrite(pusRow, sizeof(USHORT), 1);
+ Od2ProbeForWrite(pusColumn, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioGetCurPos(
+ pusRow,
+ pusColumn
+ );
+
+ CHECK_RETURN_STATUS()
+
+#if DBG
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Row %u, Col %u\n",
+ FuncName, hVio, (ULONG)*pusRow, (ULONG)*pusColumn));
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioSetCurPos( IN ULONG usRow,
+ IN ULONG usColumn,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioSetCurPos";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Row %lu, Col %lu\n",
+ FuncName, hVio, usRow, usColumn));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioSetCurPos(
+ usRow,
+ usColumn
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioGetCurType( OUT PVIOCURSORINFO pCurType,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioGetCurType";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ Od2ProbeForWrite(pCurType, sizeof(PVIOCURSORINFO), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioGetCurType(
+ (PVOID)pCurType
+ );
+
+ CHECK_RETURN_STATUS()
+
+#if DBG
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: yStart %u, cEnd %u, cx %u, %sVisible (attr %u)\n",
+ FuncName, (ULONG)pCurType->yStart, (ULONG)pCurType->cEnd,
+ (ULONG)pCurType->cx, (pCurType->attr == 0xffff) ? "no " : "",
+ (ULONG)pCurType->attr));
+ }
+#endif
+ return NO_ERROR;
+}
+
+
+APIRET
+VioSetCurType( OUT PVIOCURSORINFO pCurType,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioSetCurType";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, yStart %u, cEnd %u, cx %u, %sVisible (attr %u)\n",
+ FuncName, hVio, (ULONG)pCurType->yStart, (ULONG)pCurType->cEnd,
+ (ULONG)pCurType->cx, (pCurType->attr == 0xffff) ? "no " : "",
+ (ULONG)pCurType->attr));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ Od2ProbeForRead(pCurType, sizeof(PVIOCURSORINFO), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioSetCurType(
+ (PVOID)pCurType
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioGetMode( IN OUT PVIOMODEINFO Mode,
+ IN ULONG hVio)
+{
+ APIRET RetCode = NO_ERROR;
+ USHORT Length;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioGetMode";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, size %u\n", FuncName, hVio, (ULONG)Mode->cb));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ if (Mode->cb < 2 )
+ {
+ RetCode = ERROR_VIO_INVALID_LENGTH;
+ } else
+ {
+ Length = Mode->cb;
+ if (Length > sizeof(VIOMODEINFO))
+ {
+ Mode->cb = 12;
+ } else if ((Length > 4) && (Length < 12) && (Length & 1))
+ {
+ Mode->cb &= 0xFFFE;
+ //} else if ((Length > 12) && (Length < 34) && (Length & 3))
+ //{
+ // Mode->cb &= 0xFFFC;
+ }
+ Od2ProbeForWrite(Mode, Mode->cb, 1);
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (RetCode)
+ {
+ return(RetCode);
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioGetMode(
+ (PVOID)Mode
+ );
+
+ CHECK_RETURN_STATUS()
+
+#if DBG
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Type %u, Color %u, Row %u, Col %u\n",
+ FuncName, hVio, (ULONG)Mode->fbType, (ULONG)Mode->color,
+ (ULONG)Mode->row, (ULONG)Mode->col));
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioSetMode( IN OUT PVIOMODEINFO Mode,
+ IN ULONG hVio)
+{
+ APIRET RetCode = NO_ERROR;
+ VIOMODEINFO LocalMode;
+ register USHORT Length;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioSetMode";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Type %u, Color %u, Row %u, Col %u\n",
+ FuncName, hVio, (ULONG)Mode->fbType, (ULONG)Mode->color,
+ (ULONG)Mode->row, (ULONG)Mode->col));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ RtlZeroMemory(&LocalMode, sizeof(VIOMODEINFO));
+
+ try
+ {
+ Length = Mode->cb;
+ if (Length < 2 )
+ {
+ RetCode = ERROR_VIO_INVALID_LENGTH;
+ } else
+ {
+ if (Length > sizeof(VIOMODEINFO))
+ {
+ Length = sizeof(VIOMODEINFO);
+ } else if ((Length > 4) && (Length < 12) && (Length & 1))
+ {
+ Length &= 0xFFFE;
+ } else if ((Length > 14) && (Length < 34) && (Length & 3))
+ {
+ Length &= 0xFFFC;
+ }
+ RtlMoveMemory(&LocalMode, Mode, Length);
+ LocalMode.cb = Length;
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (RetCode)
+ {
+ return(RetCode);
+ }
+
+ if (LocalMode.fbType > 1)
+ {
+ return (ERROR_VIO_MODE);
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ FALSE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioSetMode(
+ (PVOID)&LocalMode
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioDeRegister()
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioDeRegister";
+#endif
+
+ CHECK_POPUP_EXIST()
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+VioRegister(IN PSZ pszModuleName,
+ IN PSZ pszEntryName,
+ IN ULONG flFunction1,
+ IN ULONG flFunction2)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioRegister";
+#endif
+ UNREFERENCED_PARAMETER(pszModuleName);
+ UNREFERENCED_PARAMETER(pszEntryName);
+ UNREFERENCED_PARAMETER(flFunction1);
+ UNREFERENCED_PARAMETER(flFunction2);
+
+ CHECK_POPUP_EXIST()
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+VioPopUp(IN PUSHORT pWait,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+ LARGE_INTEGER TimeOut;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioPopUp";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Wait %s-%u\n",
+ FuncName, hVio, (*pWait & VP_WAIT) ? "Yes" : "No", (ULONG)*pWait));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ Od2ProbeForRead(pWait, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ /*
+ * catch PopUp semaphore
+ */
+
+ TimeOut.LowPart = 0L;
+ TimeOut.HighPart = 0L;
+
+ RetCode = Od2WaitForSingleObject(PopUpSemaphore,
+ TRUE,
+ (*pWait & VP_WAIT) ? NULL : &TimeOut);
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ KdPrint(("%s: can't get PopUp semaphore\n", FuncName ));
+#endif
+ return( ERROR_VIO_EXISTING_POPUP );
+ }
+
+ SesGrp->PopUpProcess = (HANDLE)(Od2Process->Pib.ProcessId);
+
+ RetCode = Ow2VioPopUp(
+ (ULONG)*pWait,
+ &Od2Process->ApplName[0]
+ );
+
+ if ( RetCode )
+ {
+ NtReleaseSemaphore( PopUpSemaphore,
+ 1,
+ NULL);
+
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ KdPrint(("%s: status %lx\n", FuncName, RetCode));
+#endif
+
+ return(RetCode);
+ }
+
+ SesGrp->PopUpFlag = TRUE;
+ return NO_ERROR;
+}
+
+
+APIRET
+VioEndPopUp(IN ULONG hVio)
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioEndPopUp";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ if ((!SesGrp->PopUpFlag) ||
+ (SesGrp->PopUpProcess != (HANDLE)(Od2Process->Pib.ProcessId)))
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ KdPrint(("%s: PopUp does not exist\n", FuncName ));
+#endif
+
+ return( ERROR_VIO_NO_POPUP );
+ }
+
+ RetCode = Ow2VioEndPopUp();
+
+ CHECK_RETURN_STATUS()
+
+ NtReleaseSemaphore( PopUpSemaphore,
+ 1,
+ NULL);
+
+ SesGrp->PopUpFlag = FALSE;
+ return( NO_ERROR );
+}
+
+
+APIRET
+VioGetBuf( OUT PULONG pulLVB,
+ OUT PUSHORT pcbLVB,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+ ULONG Length = SesGrp->LVBsize;
+ BOOLEAN FirstTime = FALSE;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioGetBuf";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ Od2ProbeForWrite(pulLVB, sizeof(ULONG), 1);
+ Od2ProbeForWrite(pcbLVB, sizeof(USHORT), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (VioBuff == NULL)
+ {
+ if (OpenLVBsection())
+ {
+#if DBG
+ KdPrint(("%s: unable to OpenLvbSection\n", FuncName));
+#endif
+ return(ERROR_VIO_RETURN);
+ }
+
+ FirstTime = TRUE;
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ FALSE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ if (FirstTime)
+ {
+ RetCode = Ow2VioGetLVBBuf(
+ &Length
+ );
+
+ CHECK_RETURN_STATUS()
+ }
+
+ *pcbLVB = (USHORT)Length;
+ *pulLVB = (ULONG) (FLATTOFARPTR((ULONG)VioBuff));
+
+#if DBG
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, buff %p, address 0x%lx, length %u\n",
+ FuncName, hVio, VioBuff, *pulLVB, (ULONG)*pcbLVB));
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioShowBuf( IN ULONG offLVB,
+ IN ULONG cbOutput,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioShowBuf";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, buff %p, offset 0x%lx, length 0x%lx\n",
+ FuncName, hVio, VioBuff, offLVB, cbOutput));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ FALSE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ if (offLVB >= SesGrp->LVBsize)
+ {
+ offLVB = SesGrp->LVBsize - 1;
+ }
+
+ RetCode = Ow2VioShowLVBBuf(
+ cbOutput,
+ offLVB
+ );
+
+ CHECK_RETURN_STATUS()
+
+ return NO_ERROR;
+}
+
+
+APIRET
+VioGetFont( IN OUT PVIOFONTINFO Font,
+ IN ULONG hVio)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioGetFont";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ if (Font->cb != sizeof(VIOFONTINFO))
+ {
+ return(ERROR_VIO_INVALID_LENGTH);
+ }
+
+ Od2ProbeForWrite(Font, sizeof(VIOFONTINFO), 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+VioSetFont( IN PVIOFONTINFO Font,
+ IN ULONG hVio)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioSetFont";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ if (Font->cb != sizeof(VIOFONTINFO))
+ {
+ return(ERROR_VIO_INVALID_LENGTH);
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+VioGetState( IN OUT PVOID State,
+ IN ULONG hVio)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioGetState";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ UNREFERENCED_PARAMETER(State);
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+VioSetState( IN PVOID State,
+ IN ULONG hVio)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioSetState";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ UNREFERENCED_PARAMETER(State);
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+VioGetPhysBuf( PVOID pviopb, ULONG Resr)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioGetPhysBuf";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: called\n", FuncName));
+ }
+
+#endif
+
+ UNREFERENCED_PARAMETER(pviopb);
+ UNREFERENCED_PARAMETER(Resr);
+
+ CHECK_POPUP_EXIST()
+
+// UNSUPPORTED_API()
+#if DBG
+ KdPrint(("%s called but isn't supported\n", FuncName));
+#endif
+ return (ERROR_VIO_IN_BG);
+}
+
+
+APIRET
+VioModeUndo(IN ULONG fRelinqush,
+ IN ULONG fTerminate,
+ IN ULONG hVio)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioModeUndo";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ UNREFERENCED_PARAMETER(fRelinqush);
+ UNREFERENCED_PARAMETER(fTerminate);
+
+ CHECK_POPUP_EXIST()
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+VioModeWait(IN ULONG fEvent,
+ OUT PUSHORT pfNotify,
+ IN ULONG hVio)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioModeWait";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ UNREFERENCED_PARAMETER(fEvent);
+ UNREFERENCED_PARAMETER(pfNotify);
+
+ CHECK_POPUP_EXIST()
+
+ DosSleep( (ULONG)SEM_INDEFINITE_WAIT );
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+VioSavRedrawUndo(IN ULONG fRelinqush,
+ IN ULONG fTerminate,
+ IN ULONG hVio)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioSavRedrawUndo";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ UNREFERENCED_PARAMETER(fRelinqush);
+ UNREFERENCED_PARAMETER(fTerminate);
+
+ CHECK_POPUP_EXIST()
+
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+VioSavRedrawWait( IN ULONG fEvent,
+ OUT PUSHORT pfNotify,
+ IN ULONG Resr)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioSavRedrawWait";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: called\n", FuncName));
+ }
+
+#endif
+
+ UNREFERENCED_PARAMETER(fEvent);
+ UNREFERENCED_PARAMETER(pfNotify);
+ UNREFERENCED_PARAMETER(Resr);
+
+ CHECK_POPUP_EXIST()
+
+ DosSleep( (ULONG)SEM_INDEFINITE_WAIT );
+ UNSUPPORTED_API()
+}
+
+
+APIRET
+VioScrLock(IN ULONG fWait,
+ OUT PBYTE pfNotLocked,
+ IN ULONG hVio)
+{
+ LARGE_INTEGER TimeOut;
+ APIRET RetCode;
+ BOOLEAN Wait;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioScrLock";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Wait %s-%lu\n",
+ FuncName, hVio, ( fWait == LOCKIO_WAIT ) ? "Yes" : "No", fWait));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ *pfNotLocked = LOCK_FAIL;
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (( fWait != LOCKIO_WAIT ) && ( fWait != LOCKIO_NOWAIT ))
+ {
+ return (ERROR_VIO_WAIT_FLAG);
+ }
+
+ Wait = (fWait == LOCKIO_WAIT) ? TRUE : FALSE;
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ FALSE,
+ Wait
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+
+ /*
+ * catch ScreenLock semaphore
+ */
+
+ TimeOut.LowPart = 0L;
+ TimeOut.HighPart = 0L;
+
+ RetCode = Od2WaitForSingleObject(ScreenLockSemaphore,
+ TRUE,
+ (fWait & LOCKIO_WAIT) ? NULL : &TimeOut);
+
+ if ( RetCode )
+ {
+ return( ERROR_VIO_LOCK );
+ }
+
+ SesGrp->LockProcess = (HANDLE)(Od2Process->Pib.ProcessId);
+
+ *pfNotLocked = LOCK_SUCCESS;
+
+ return (NO_ERROR);
+}
+
+
+APIRET
+VioScrUnLock(IN ULONG hVio)
+{
+ APIRET RetCode;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioScrUnLock";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio ));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ FALSE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+
+ if ( SesGrp->LockProcess != (HANDLE)(Od2Process->Pib.ProcessId) )
+ {
+ return( ERROR_VIO_UNLOCK );
+ }
+
+ NtReleaseSemaphore( ScreenLockSemaphore,
+ 1,
+ NULL);
+
+ SesGrp->LockProcess = (HANDLE) NULL;
+
+ return (NO_ERROR);
+}
+
+
+APIRET
+VioPrtSc(IN ULONG hVio)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioPrtSc";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ return (ERROR_VIO_SMG_ONLY);
+}
+
+
+APIRET
+VioPrtScToggle(IN ULONG hVio)
+{
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioPrtScToggle";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx\n", FuncName, hVio));
+ }
+#endif
+
+ TEST_HVIO_NON_AVIO()
+
+ return (ERROR_VIO_SMG_ONLY);
+}
+
+
+APIRET
+VioWrite(IN PFILE_HANDLE hFileRecord,
+ IN PCH Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten,
+ IN VIOREQUESTNUMBER RequestType)
+{
+ APIRET RetCode;
+
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioWrite";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: entering with %lx, Len %lu, 0x%x...\n",
+ FuncName, hFileRecord, Length, (ULONG)*Buffer));
+ }
+
+#endif
+
+ //Request.d.Vio.hVio = hFileRecord->NtHandle;
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioWriteTTYStr(
+ Buffer,
+ Length,
+ (ULONG)RequestType
+ );
+
+ CHECK_RETURN_STATUS()
+
+ *BytesWritten = Length;
+
+ return NO_ERROR;
+
+}
+
+#ifdef DBCS
+// MSKK Jun.23.1992 KazuM
+// MSKK Jan.13.1993 V-AkihiS
+// MSKK Apr.20.1993 V-AkihiS
+APIRET
+VioCheckCharType(OUT PUSHORT pchType,
+ IN ULONG usRow,
+ IN ULONG usColumn,
+ IN ULONG hVio)
+{
+ APIRET RetCode;
+ DWORD chType;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "VioCheckCharType";
+
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Row %lu, Col %lu\n",
+ FuncName, hVio, usRow, usColumn));
+ }
+#endif
+ TEST_HVIO_NON_AVIO()
+
+ try
+ {
+ Od2ProbeForWrite(pchType, sizeof(USHORT), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ EXCEPTION_IN_VIO()
+ }
+
+ if (RetCode = Od2VioCheckPopupAndPause(
+ TRUE,
+ TRUE
+#if DBG
+ ,FuncName
+#endif
+ ))
+ {
+ return(RetCode);
+ }
+
+ RetCode = Ow2VioCheckCharType(
+ (PVOID)&chType,
+ usRow,
+ usColumn
+ );
+
+ CHECK_RETURN_STATUS()
+
+#if DBG
+ IF_OD2_DEBUG(VIO)
+ {
+ KdPrint(("%s: hVio %lx, Char %u\n", FuncName, hVio, *pchType));
+ }
+#endif
+
+ *pchType = (USHORT)chType;
+
+ return NO_ERROR;
+}
+#endif
+
+APIRET
+Od2VioCheckPopupAndPause(
+ IN BOOLEAN AllowedInPopup,
+ IN BOOLEAN Wait
+#if DBG
+ ,IN PSZ FuncName
+#endif
+ )
+{
+ APIRET RetCode;
+ LARGE_INTEGER TimeOut, *pTimeOut = NULL;
+
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("Od2VioCheckPopupAndPause (PID-TID %d:%d): Popup %s and Wait %s for %s\n",
+ (USHORT)(Od2Process->Pib.ProcessId), (USHORT)(Od2CurrentThreadId()),
+ (AllowedInPopup) ? "ALLOWED" : "NOT PERMITTED",
+ (Wait) ? "ON" : "OFF", FuncName ));
+ }
+#endif
+ if (!Wait)
+ {
+ TimeOut.LowPart = 0L;
+ TimeOut.HighPart = 0L;
+ pTimeOut = &TimeOut;
+ }
+ if ( SesGrp->PopUpFlag )
+ {
+ if (AllowedInPopup)
+ {
+ if ( SesGrp->PopUpProcess != (HANDLE)(Od2Process->Pib.ProcessId) )
+ {
+ if ( RetCode = Od2WaitForSingleObject(PopUpSemaphore, TRUE, pTimeOut) )
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("%s: failed to wait (%lu) for PopUp to terminate\n",
+ FuncName, RetCode ));
+ }
+#endif
+ return(ERROR_VIO_EXISTING_POPUP);
+ } else
+ {
+ // Don't catch the semaphore. Just make sure it's free
+ // (the popup had ended), and release it.
+
+ NtReleaseSemaphore( PopUpSemaphore, 1, NULL);
+ }
+ }
+
+ } else
+ {
+ if (SesGrp->PopUpProcess == (HANDLE)(Od2Process->Pib.ProcessId))
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("%s: illegal call when PopUp exist\n",
+ FuncName ));
+ }
+#endif
+ return( ERROR_VIO_ILLEGAL_DURING_POPUP );
+ }
+ }
+ }
+
+ if ( SesGrp->PauseScreenUpdate )
+ {
+ RetCode = Od2WaitForSingleObject(PauseEvent, TRUE, pTimeOut);
+
+ if ( RetCode )
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("%s: wait for PauseEvent failed %lu\n",
+ FuncName, RetCode ));
+ }
+#endif
+ return(ERROR_VIO_INVALID_HANDLE); /* =>BUGBUG fix the error code */
+ } else
+ {
+ NtSetEvent(PauseEvent, NULL);
+ }
+ }
+ return(NO_ERROR);
+}
+
+
diff --git a/private/os2/client/dllvm.c b/private/os2/client/dllvm.c
new file mode 100644
index 000000000..278e8ac1d
--- /dev/null
+++ b/private/os2/client/dllvm.c
@@ -0,0 +1,636 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dllvm.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 Memory Management API Calls
+
+
+Author:
+
+ Steve Wood (stevewo) 02-Nov-1989
+
+Revision History:
+
+ YaronS 18-APR-1991 - modified DosAllocMem such that all allocations
+ are confined to a 512M address space. (set zero bits to 3 when
+ call NtAllocateVirtualMemory.
+
+ YaronS 6-SEP-1992 - flexible base 512M
+
+--*/
+
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+
+APIRET
+DosAllocMem(
+ OUT PVOID *BaseAddress,
+ IN ULONG RegionSize,
+ IN ULONG Flags
+ )
+{
+ NTSTATUS Status;
+ // PVOID MemoryAddress;
+ APIRET rc;
+ ULONG AllocationType, Protect;
+ ULONG Bits;
+ // PVOID FirstSharedBaseAddress;
+
+ if (RegionSize == 0 || (Flags & ~(fALLOC|PAG_GUARD))) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ rc = Or2MapFlagsToProtection( Flags, &Protect );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ if (Flags & PAG_COMMIT) {
+ AllocationType = MEM_COMMIT;
+ }
+ else {
+ AllocationType = MEM_RESERVE;
+ }
+
+ //
+ // probe address pointer.
+ //
+ try {
+ Od2ProbeForWrite(BaseAddress, sizeof(ULONG), 1);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ if (Flags & OBJ_TILE)
+ Bits = 1;
+ else
+ Bits = 0;
+
+ Status = NtAllocateVirtualMemory( NtCurrentProcess(),
+ BaseAddress,
+ Bits,
+ &RegionSize,
+ AllocationType,
+ Protect
+ );
+ if (!NT_SUCCESS( Status )) {
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ return( NO_ERROR );
+}
+
+
+BOOLEAN
+Od2ValidateBaseAddress(
+ PVOID BaseAddress,
+ PMEMORY_BASIC_INFORMATION MemoryInformation
+ )
+{
+ NTSTATUS Status;
+
+ //
+ // If BaseAddress is within the first 64K of memory then it is not
+ // a valid address.
+ //
+
+ if (((ULONG)BaseAddress & ~Od2NtSysInfo.AllocationGranularity) == 0) {
+ return( FALSE );
+ }
+
+ Status = NtQueryVirtualMemory( NtCurrentProcess(),
+ BaseAddress,
+ MemoryBasicInformation,
+ MemoryInformation,
+ sizeof( *MemoryInformation ),
+ NULL
+ );
+ if (!NT_SUCCESS( Status ) || BaseAddress != MemoryInformation->BaseAddress) {
+ return( FALSE );
+ }
+ else {
+ return( TRUE );
+ }
+}
+
+// The parameter pRemoveLDTEntry is the pointer to boolean variable. It has
+// the value "LDT entry wasn't removed yet".
+// So on the entry of the function it will have value TRUE only in the case
+// that LDT entry must be removed. On the exit it will be TRUE only in the
+// case that LDT entry wasn't removed.
+
+APIRET
+DosFreeMem(
+ PVOID BaseAddress,
+ PBOOLEAN pRemoveLDTEntry
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSFREEMEM_MSG a = &m.u.DosFreeMem;
+ ULONG RegionSize = 0;
+ NTSTATUS Status;
+
+ Status = NtFreeVirtualMemory( NtCurrentProcess(),
+ &BaseAddress,
+ &RegionSize,
+ MEM_RELEASE
+ );
+ if (NT_SUCCESS( Status )) {
+ return( NO_ERROR );
+ }
+ else
+ if ((Status == STATUS_UNABLE_TO_FREE_VM) ||
+ (Status == STATUS_UNABLE_TO_DELETE_SECTION)) {
+
+ // Shared memory.
+
+ APIRET rc;
+
+ a->BaseAddress = BaseAddress;
+
+ // If LDT entry must be removed by the server.
+
+ a->RemoveLDTEntry = *pRemoveLDTEntry;
+
+ rc = Od2CallSubsystem( &m, NULL, Os2FreeMem, sizeof( *a ) );
+ if (rc == NO_ERROR) {
+
+ // If server succeeded to remove LDT entry, sign that it must not
+ // be removed any more.
+
+ *pRemoveLDTEntry = FALSE;
+ }
+ return(rc);
+ }
+ else {
+ return( ERROR_INVALID_ADDRESS );
+ }
+}
+
+
+APIRET
+DosSetMem(
+ IN PVOID BaseAddress,
+ IN ULONG RegionSize,
+ IN ULONG Flags
+ )
+{
+ OS2_API_MSG m;
+ POS2_QUERYVIRTUALMEMORY_MSG a = &m.u.QueryVirtualMemory;
+ ULONG Protect, OldProtect;
+ APIRET rc;
+ MEMORY_BASIC_INFORMATION MemoryInformation;
+ NTSTATUS Status;
+
+ if (RegionSize == 0) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ if (Flags != PAG_DECOMMIT
+ && (((Flags & (fPERM | PAG_DEFAULT)) == 0) ||
+ ((Flags & (~(fSET|PAG_GUARD) | PAG_DECOMMIT)) != 0) ||
+ ((Flags & (fPERM|PAG_GUARD)) && (Flags & PAG_DEFAULT))
+ )
+ ) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ if (Flags == PAG_DECOMMIT) {
+ Status = NtFreeVirtualMemory( NtCurrentProcess(),
+ &BaseAddress,
+ &RegionSize,
+ MEM_DECOMMIT
+ );
+ //
+ // The STATUS_UNABLE_TO_FREE_VM status is returned when trying
+ // to decommit pages of mapped sections. This error should
+ // not be reported to the user program.
+ //
+ if ((Status == STATUS_UNABLE_TO_FREE_VM) ||
+ (Status == STATUS_UNABLE_TO_DELETE_SECTION)) {
+ //BUGBUG - aren't there cases where the process is the last one
+ // to use this memory ? If so, why do we get this error
+ // from NT (maybe os2srv is holding the section by error).
+ Status = STATUS_SUCCESS;
+ }
+ else
+ if (Status == STATUS_UNABLE_TO_DECOMMIT_VM) {
+ return( ERROR_ACCESS_DENIED );
+ }
+ }
+ else {
+ if (Flags & PAG_DEFAULT) {
+ a->BaseAddress = BaseAddress;
+ if (Od2CallSubsystem( &m,
+ NULL,
+ Oi2QueryVirtualMemory,
+ sizeof( *a )
+ )
+ ) {
+ return( m.ReturnedErrorValue );
+ }
+
+ if (!a->SharedMemory) {
+ Status = NtQueryVirtualMemory( NtCurrentProcess(),
+ BaseAddress,
+ MemoryBasicInformation,
+ &MemoryInformation,
+ sizeof( MemoryInformation ),
+ NULL
+ );
+
+ if (MemoryInformation.State == MEM_FREE) {
+ return( ERROR_INVALID_ADDRESS );
+ }
+
+ Protect = MemoryInformation.AllocationProtect;
+ }
+ else {
+ rc = Or2MapFlagsToProtection( a->AllocationFlags, &Protect );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+ }
+ }
+ else {
+ rc = Or2MapFlagsToProtection( Flags, &Protect );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+ }
+
+ if (Flags & PAG_COMMIT) {
+ Status = NtAllocateVirtualMemory( NtCurrentProcess(),
+ &BaseAddress,
+ 1,
+ &RegionSize,
+ MEM_COMMIT,
+ Protect
+ );
+ if (Status == STATUS_ALREADY_COMMITTED) {
+ Status = STATUS_SUCCESS;
+ }
+ }
+ else {
+ Status = NtProtectVirtualMemory( NtCurrentProcess(),
+ &BaseAddress,
+ &RegionSize,
+ Protect,
+ &OldProtect
+ );
+
+ if (Status == STATUS_NOT_COMMITTED) {
+ return( ERROR_ACCESS_DENIED );
+ }
+ }
+ }
+
+ if (NT_SUCCESS( Status )) {
+ return( NO_ERROR );
+ }
+ else
+ if (Status == STATUS_INVALID_PARAMETER) {
+ return( ERROR_INVALID_ADDRESS );
+ }
+ else {
+ return( Or2MapNtStatusToOs2Error( Status, ERROR_INVALID_ADDRESS ) );
+ }
+}
+
+
+APIRET
+DosGiveSharedMem(
+ IN PVOID BaseAddress,
+ IN PID ProcessId,
+ IN ULONG Flags
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSGIVESHAREDMEM_MSG a = &m.u.DosGiveSharedMem;
+ MEMORY_BASIC_INFORMATION MemoryInformation;
+ APIRET rc;
+
+ if (!Od2ValidateBaseAddress( BaseAddress, &MemoryInformation )) {
+ return( ERROR_INVALID_ADDRESS );
+ }
+
+ if ((Flags & fPERM) == 0 || (Flags & ~(fGIVESHR|PAG_GUARD))) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ if (MemoryInformation.State == MEM_PRIVATE) {
+ return( ERROR_ACCESS_DENIED );
+ }
+
+ if (ProcessId == 0) {
+ return( ERROR_INVALID_PROCID );
+ }
+
+ rc = Or2MapFlagsToProtection( a->Flags = Flags, &a->PageProtection );
+
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ a->BaseAddress = BaseAddress;
+ a->ProcessId = ProcessId;
+
+ Od2CallSubsystem( &m, NULL, Os2GiveSharedMem, sizeof( *a ) );
+
+ return(m.ReturnedErrorValue);
+}
+
+APIRET
+DosGetSharedMem(
+ IN PVOID BaseAddress,
+ IN ULONG Flags
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSGETSHAREDMEM_MSG a = &m.u.DosGetSharedMem;
+ APIRET rc;
+
+ if ((Flags & fPERM) == 0 || (Flags & ~(fGETSHR|PAG_GUARD))) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ rc = Or2MapFlagsToProtection( a->Flags = Flags, &a->PageProtection );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ a->BaseAddress = BaseAddress;
+
+ Od2CallSubsystem( &m, NULL, Os2GetSharedMem, sizeof( *a ) );
+
+ return(m.ReturnedErrorValue);
+}
+
+APIRET
+DosGetNamedSharedMem(
+ OUT PVOID *BaseAddress,
+ IN PSZ ObjectName,
+ IN ULONG Flags
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSGETNAMEDSHAREDMEM_MSG a = &m.u.DosGetNamedSharedMem;
+ APIRET rc;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+
+ if ((Flags & fPERM) == 0 || (Flags & ~(fGETNMSHR|PAG_GUARD))) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ rc = Or2MapFlagsToProtection( a->Flags = Flags, &a->PageProtection );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ a->BaseAddress = NULL;
+
+ //
+ // probe address pointer.
+ //
+
+ try {
+ *BaseAddress = 0;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+
+ rc = Od2CaptureObjectName( ObjectName,
+ CANONICALIZE_SHARED_MEMORY,
+ 0,
+ &CaptureBuffer,
+ &a->ObjectName
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+ Od2CallSubsystem( &m, CaptureBuffer, Os2GetNamedSharedMem, sizeof( *a ) );
+
+ if (m.ReturnedErrorValue == NO_ERROR) {
+ *BaseAddress = a->BaseAddress;
+ }
+
+ Od2FreeCaptureBuffer( CaptureBuffer );
+
+ return( m.ReturnedErrorValue );
+}
+
+APIRET
+DosAllocSharedMem(
+ OUT PVOID *BaseAddress,
+ IN PSZ ObjectName,
+ IN ULONG RegionSize,
+ IN ULONG Flags,
+ IN BOOLEAN CreateLDTEntry // Create LDT entry in the server.
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSALLOCSHAREDMEM_MSG a = &m.u.DosAllocSharedMem;
+ APIRET rc;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+
+ if (RegionSize == 0
+ || (Flags & ~(fALLOCSHR|PAG_GUARD))
+ || ((Flags & PAG_COMMIT) && (Flags & fPERM) == 0)
+ || (ObjectName != NULL) && (Flags & (OBJ_GETTABLE|OBJ_GIVEABLE))
+ || (ObjectName == NULL) && (Flags & (OBJ_GETTABLE|OBJ_GIVEABLE)) == 0
+ ) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ rc = Or2MapFlagsToProtection( a->Flags = Flags, &a->PageProtection );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ a->BaseAddress = NULL;
+ a->RegionSize = RegionSize;
+ a->CreateLDTEntry = CreateLDTEntry; // Server will create LDT entry.
+
+ //
+ // probe address pointer.
+ //
+
+ try {
+ *BaseAddress = 0;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ rc = Od2CaptureObjectName( ObjectName,
+ CANONICALIZE_SHARED_MEMORY,
+ 0,
+ &CaptureBuffer,
+ &a->ObjectName
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+ Od2CallSubsystem( &m, CaptureBuffer, Os2AllocSharedMem, sizeof( *a ) );
+
+ if (m.ReturnedErrorValue == NO_ERROR) {
+ *BaseAddress = a->BaseAddress;
+ }
+
+ if (CaptureBuffer != NULL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ }
+
+ return( m.ReturnedErrorValue );
+}
+
+
+APIRET
+DosQueryMem(
+ IN PVOID BaseAddress,
+ IN OUT PULONG RegionSize,
+ OUT PULONG Flags
+ )
+{
+ NTSTATUS Status;
+ MEMORY_BASIC_INFORMATION MemoryInformation;
+ ULONG MemFlags, OriginalBaseAddress, OldEndAddress, NewEndAddress;
+ ULONG Protection;
+ SEL sel;
+ POS21X_CSALIAS pCSAlias;
+ BOOLEAN SelIsCSADS;
+
+ OriginalBaseAddress = (ULONG)BaseAddress;
+ sel = FLATTOSEL(BaseAddress);
+
+ BaseAddress = (PVOID)((ULONG)BaseAddress & ~(Od2NtSysInfo.PageSize - 1));
+ Status = NtQueryVirtualMemory( NtCurrentProcess(),
+ BaseAddress,
+ MemoryBasicInformation,
+ &MemoryInformation,
+ sizeof( MemoryInformation ),
+ NULL
+ );
+ if (!NT_SUCCESS( Status )) {
+ return( ERROR_INVALID_ADDRESS );
+ }
+
+ MemFlags = 0;
+ Protection = MemoryInformation.Protect;
+
+ if (MemoryInformation.State == MEM_COMMIT) {
+ MemFlags |= PAG_COMMIT;
+ }
+ else
+ if (MemoryInformation.State == MEM_FREE) {
+ MemFlags |= PAG_FREE;
+ }
+ else
+ if (MemoryInformation.State == MEM_RESERVE) {
+ Protection = MemoryInformation.AllocationProtect;
+ }
+
+ // Check if this is a Data Segment of a CSAlias Only for "Pseudo shared"
+ // READ/WRITE Data Segments
+ // This is done since when creating a CSAlias we change the DS page
+ // protection from PAGE_EXECUTE_WRITE_COPY TO PAGE_READ_WRITE since it is
+ // mapped twice (once to the DS and once to the CS)
+
+ SelIsCSADS = FALSE;
+ if (MemoryInformation.AllocationProtect == PAGE_READWRITE)
+ {
+ AcquireTaskLock();
+ if (Od2CSAliasListHead != 0)
+ {
+ for (pCSAlias = (POS21X_CSALIAS) Od2CSAliasListHead;
+ pCSAlias != NULL;
+ pCSAlias = (POS21X_CSALIAS) (pCSAlias->Next))
+ {
+ if (pCSAlias->selDS == sel)
+ {
+ SelIsCSADS = TRUE;
+ break;
+ }
+ }
+ }
+ ReleaseTaskLock();
+ }
+
+ if ((MemoryInformation.Type != MEM_PRIVATE) &&
+ (MemoryInformation.AllocationProtect != PAGE_EXECUTE_WRITECOPY) &&
+ (sel >= FIRST_SHARED_SELECTOR) &&
+ (!SelIsCSADS))
+ {
+ MemFlags |= PAG_SHARED;
+ }
+
+ if (MemoryInformation.State != MEM_FREE &&
+ MemoryInformation.AllocationBase == MemoryInformation.BaseAddress
+ ) {
+ MemFlags |= PAG_BASE;
+ }
+
+ switch( Protection & 0xFF) {
+ case PAGE_NOACCESS : break;
+ case PAGE_READONLY : MemFlags |= PAG_READ; break;
+ case PAGE_READWRITE : MemFlags |= PAG_READ | PAG_WRITE; break;
+ case PAGE_WRITECOPY : MemFlags |= PAG_READ | PAG_WRITE; break;
+ case PAGE_EXECUTE : MemFlags |= PAG_EXECUTE; break;
+ case PAGE_EXECUTE_READ : MemFlags |= PAG_EXECUTE | PAG_READ; break;
+ case PAGE_EXECUTE_READWRITE : MemFlags |= PAG_EXECUTE | PAG_READ | PAG_WRITE; break;
+ case PAGE_EXECUTE_WRITECOPY : MemFlags |= PAG_EXECUTE | PAG_READ | PAG_WRITE; break;
+ }
+
+ if (Protection & PAGE_GUARD) {
+ MemFlags |= PAG_GUARD;
+ }
+
+ try {
+ //
+ // Must specify a non-zero region size to begin with
+ //
+
+ if (*RegionSize == 0) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // See if the specified region size is too large. Either because
+ // the base address was not the actual base address or the region
+ // size given was greater than the actual region size.
+ //
+
+ OldEndAddress = OriginalBaseAddress + *RegionSize;
+ NewEndAddress = (ULONG)MemoryInformation.BaseAddress +
+ MemoryInformation.RegionSize;
+
+ if (OldEndAddress > NewEndAddress) {
+ *RegionSize = NewEndAddress - OriginalBaseAddress;
+ }
+ else
+ if (*RegionSize > MemoryInformation.RegionSize) {
+ *RegionSize = MemoryInformation.RegionSize;
+ }
+
+ //
+ // Return the calculated flags for the region.
+ //
+
+ *Flags = MemFlags;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return( NO_ERROR );
+}
diff --git a/private/os2/client/dllvm16.c b/private/os2/client/dllvm16.c
new file mode 100644
index 000000000..c0a6dc2ea
--- /dev/null
+++ b/private/os2/client/dllvm16.c
@@ -0,0 +1,3240 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dllvm16.c
+
+Abstract:
+
+ This module implements 32 equivalents of OS/2 V1.21 Memory Management
+ API Calls. These are called from 16->32 thunks (i386\doscalls.asm).
+
+
+Author:
+
+ Yaron Shamir (YaronS) 12-Apr-1991
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_ERRORS
+#include "os2dll.h"
+#include "os2dll16.h"
+
+APIRET
+Od2SuspendAllThreads( VOID );
+
+APIRET
+Od2ResumeAllThreads( VOID );
+
+VOID
+DosExit(
+ IN ULONG ExitAction,
+ IN ULONG ExitResult
+ );
+
+APIRET
+DosHoldSignal(
+ ULONG fDisable,
+ ULONG pstack
+ );
+
+#if DBG
+// Set the values as appropriate (with NTSD or at compile-time) to see all
+// APIs which allocate/free memory and affect this selector.
+// To disable this feature, leave the variable at 0.
+USHORT Os2DebugSel = 0x0;
+#endif
+
+//
+// Masks used to determine the correct action to be taken
+// for DosReallocHuge()
+//
+#define H_NEW_PARTIAL 1
+#define H_CUR_PARTIAL 2
+#define H_SEG_INC 4
+#define H_SEG_DEC 8
+#define H_SAME_SEG_NO_PARTIAL 0
+#define H_SAME_SEG_NEW_PARTIAL H_NEW_PARTIAL
+#define H_SAME_SEG_DEL_PARTIAL H_CUR_PARTIAL
+#define H_SAME_SEG_CHG_PARTIAL (H_NEW_PARTIAL | H_CUR_PARTIAL)
+#define H_INC_SEG_NO_PARTIAL H_SEG_INC
+#define H_INC_SEG_NEW_PARTIAL (H_SEG_INC | H_NEW_PARTIAL)
+#define H_INC_SEG_DEL_PARTIAL (H_SEG_INC | H_CUR_PARTIAL)
+#define H_INC_SEG_CHG_PARTIAL (H_SEG_INC | H_NEW_PARTIAL | H_CUR_PARTIAL)
+#define H_DEC_SEG_NO_PARTIAL H_SEG_DEC
+#define H_DEC_SEG_NEW_PARTIAL (H_SEG_DEC | H_NEW_PARTIAL)
+#define H_DEC_SEG_DEL_PARTIAL (H_SEG_DEC | H_CUR_PARTIAL)
+#define H_DEC_SEG_CHG_PARTIAL (H_SEG_DEC | H_NEW_PARTIAL | H_CUR_PARTIAL)
+
+
+#define LDT_NUMBER_OF_PRIVATE_SEGMENTS (0x2000 - LDT_DISJOINT_ENTRIES)
+ //
+ // segment 0 is illegal in Os/2, skip it.
+ //
+PVOID Od2MemoryAllocationBase = (PVOID)(BASE_TILE + _64K);
+
+static PVOID ldtBMHeap;
+static RTL_BITMAP ldtBitMapHeader;
+//
+// The ResourceUsage[] array is used to keep track of the number of times
+// A segment containing a resource was allocated using the DosGetResource()
+// and DosGetResource2() APIs. This prevents DosFreeSeg() and DosFreeResource()
+// from freeing the segment until the use count becomes 0.
+//
+CHAR ResourceUsage[LDT_DISJOINT_ENTRIES];
+
+BOOLEAN
+ldtCreateSelBitmap(
+ )
+{
+
+ ldtBMHeap = RtlAllocateHeap(Od2Heap, 0, (LDT_NUMBER_OF_PRIVATE_SEGMENTS + 7) / 8);
+ if (ldtBMHeap == NULL) {
+ return(FALSE);
+ }
+
+/*
+ ldtBMHeap = RtlCreateHeap( HEAP_GROWABLE,
+ NULL,
+ (LDT_NUMBER_OF_PRIVATE_SEGMENTS + 7) / 8, // 8 bits per byte
+ (LDT_NUMBER_OF_PRIVATE_SEGMENTS + 7) / 8, // 8 bits per byte
+ NULL,
+ 0
+ );
+ if (ldtBMHeap == NULL) {
+ return(FALSE);
+ }
+*/
+ RtlInitializeBitMap(&ldtBitMapHeader ,ldtBMHeap, LDT_NUMBER_OF_PRIVATE_SEGMENTS);
+ RtlClearAllBits(&ldtBitMapHeader);
+ RtlSetBits (&ldtBitMapHeader,0,1); // selector 0 never freed.
+ return(TRUE);
+}
+
+ULONG
+ldtAllocateSelectors(
+ ULONG NumberOfSel,
+ ULONG Index
+ )
+{
+ ULONG LocalIndex = Index;
+ if (Index > (LDT_NUMBER_OF_PRIVATE_SEGMENTS - NumberOfSel)) {
+#if DBG
+ DbgPrint("Os2: ldt bitmap overflow\n");
+#endif
+ LocalIndex = 1;
+ }
+ if((RtlFindClearBitsAndSet( &ldtBitMapHeader,
+ NumberOfSel,
+ LocalIndex
+ )) == 0xffffffff) {
+ //
+ // Not found above Local Index
+ //
+ if (LocalIndex == 1){
+ //
+ // No slot available
+ //
+ return(0xffffffff);
+ }
+ else {
+ //
+ // try to search from ground up
+ //
+ return(RtlFindClearBitsAndSet( &ldtBitMapHeader,
+ NumberOfSel,
+ LocalIndex));
+ }
+ }
+}
+
+VOID
+ldtFreeSelectors(
+ ULONG Index,
+ ULONG NumberOfSel
+ )
+{
+ if (Index > (LDT_NUMBER_OF_PRIVATE_SEGMENTS - NumberOfSel)) {
+ return;
+ }
+ RtlClearBits( &ldtBitMapHeader,
+ Index,
+ NumberOfSel
+ );
+}
+
+//
+// A utility routine to verify a segment for write.
+// returns:
+// 1 if segment reachable
+// 0 if segment not reachable
+// Implemented using inline i386 VERW instruction
+//
+
+extern int _cdecl IsLegalSelector(unsigned short aSelector);
+
+//
+// A utility routine to encapsulate the NT support for LDT mgmt
+//
+NTSTATUS
+Nt386GetDescriptorLDT
+ (
+ HANDLE LDT,
+ ULONG Sel,
+ I386DESCRIPTOR *Desc
+ )
+{
+ /* Descriptor definition */
+
+ struct desctab {
+ USHORT d_limit; /* Segment limit */
+ USHORT d_loaddr; /* Low word of physical address */
+ UCHAR d_hiaddr; /* High byte of physical address */
+ UCHAR d_access; /* Access byte */
+ UCHAR d_attr; /* Attributes/extended limit */
+ UCHAR d_extaddr; /* Extended physical address byte */
+ } *LDTDesc;
+ ULONG TmpAddress;
+ PROCESS_LDT_INFORMATION LdtInformation;
+ NTSTATUS Status;
+
+ UNREFERENCED_PARAMETER(LDT);
+
+ //
+ // adjust LDTDesc by the LDT base and the index of this selector
+ //
+
+ LdtInformation.Length = sizeof(LDT_ENTRY);
+ LdtInformation.Start = Sel & 0xfffffff8;
+ LDTDesc = (struct desctab *)(&LdtInformation.LdtEntries[0]);
+
+ Status = NtQueryInformationProcess( NtCurrentProcess(),
+ ProcessLdtInformation,
+ &LdtInformation,
+ sizeof(PROCESS_LDT_INFORMATION),
+ NULL);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("Nt386GetDescriptorLDT: Invalid request\n");
+#endif
+ return (STATUS_INVALID_PARAMETER);
+ }
+
+ Desc->Limit = (ULONG)(LDTDesc->d_limit);
+ TmpAddress = ((((ULONG)(LDTDesc->d_extaddr)) << 8) +
+ ((ULONG)(LDTDesc->d_hiaddr))) << 16;
+ TmpAddress += ((ULONG)(LDTDesc->d_loaddr));
+ Desc->BaseAddress = TmpAddress;
+ if (TmpAddress == 0) {
+#if DBG
+ DbgPrint ("Nt386GetDescriptorLDT: Invalid Descriptor for Sel %x\n", Sel );
+#endif
+ return (STATUS_INVALID_PARAMETER);
+ }
+
+ return (STATUS_SUCCESS);
+}
+
+NTSTATUS
+Nt386SetDescriptorLDT
+ (
+ HANDLE LDT,
+ ULONG Sel,
+ I386DESCRIPTOR Desc
+ )
+{
+ /* Descriptor definition */
+
+ struct desctab {
+ USHORT d_limit; /* Segment limit */
+ USHORT d_loaddr; /* Low word of physical address */
+ UCHAR d_hiaddr; /* High byte of physical address */
+ UCHAR d_access; /* Access byte */
+ UCHAR d_attr; /* Attributes/extended limit */
+ UCHAR d_extaddr; /* Extended physical address byte */
+ } *LDTDesc;
+ PULONG tmp;
+ PROCESS_LDT_INFORMATION LdtInformation;
+ NTSTATUS Status;
+
+ UNREFERENCED_PARAMETER(LDT);
+
+
+ LDTDesc = (struct desctab *)(&LdtInformation.LdtEntries[0]);
+ tmp = (PULONG)(LDTDesc);
+ //
+ // zero the descriptor
+ //
+ *tmp++ = 0;
+ *tmp = 0;
+
+ switch (Desc.Type) {
+
+ case INVALID:
+ break;
+
+ case READ_WRITE_DATA:
+ LDTDesc->d_access = 0xf3; // read/write, present, ring 3
+ LDTDesc->d_limit = (USHORT)(Desc.Limit);
+ LDTDesc->d_loaddr = (USHORT)(Desc.BaseAddress & 0xffff);
+ LDTDesc->d_hiaddr = (UCHAR)((Desc.BaseAddress >> 16) & 0xff);
+ LDTDesc->d_extaddr = (UCHAR)((Desc.BaseAddress >> 24) & 0xff);
+ break;
+
+ case READ_DATA:
+ LDTDesc->d_access = 0xf1; // read only, present, ring 3
+ LDTDesc->d_limit = (USHORT)(Desc.Limit);
+ LDTDesc->d_loaddr = (USHORT)(Desc.BaseAddress & 0xffff);
+ LDTDesc->d_hiaddr = (UCHAR)((Desc.BaseAddress >> 16) & 0xff);
+ LDTDesc->d_extaddr = (UCHAR)((Desc.BaseAddress >> 24) & 0xff);
+ break;
+
+ case EXECUTE_READ_CODE:
+ LDTDesc->d_access = 0xfb; // read/exec, present, ring 3
+ LDTDesc->d_limit = (USHORT)(Desc.Limit);
+ LDTDesc->d_loaddr = (USHORT)(Desc.BaseAddress & 0xffff);
+ LDTDesc->d_hiaddr = (UCHAR)((Desc.BaseAddress >> 16) & 0xff);
+ LDTDesc->d_extaddr = (UCHAR)((Desc.BaseAddress >> 24) & 0xff);
+ break;
+ case EXECUTE_CODE:
+ default:
+ {
+#if DBG
+ DbgPrint ("Nt386SetDescriptorLDT: Invalid type request\n");
+#endif
+ return (STATUS_INVALID_PARAMETER);
+ }
+ }
+ //
+ // adjust LDTDesc by the LDT base and the index of this selector
+ //
+
+ LdtInformation.Length = sizeof(LDT_ENTRY);
+ LdtInformation.Start = Sel & 0xfffffff8;
+ Status = NtSetInformationProcess( NtCurrentProcess(),
+ ProcessLdtInformation,
+ &LdtInformation,
+ sizeof(PROCESS_LDT_INFORMATION)
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("Nt386SetDescriptorLDT: Invalid request\n");
+#endif
+ return (STATUS_INVALID_PARAMETER);
+ }
+
+ return (STATUS_SUCCESS);
+}
+
+#if PMNT
+
+APIRET
+PMNTAllocLDTSelector(
+ ULONG BaseAddress,
+ ULONG cbSize,
+ OUT PSEL pSel
+)
+/*++
+
+Parameters:
+
+ BaseAddress - 32-bit virtual address for which to create an LDT entry.
+
+ cbSize - Size of segment for which an LDT entry is required.
+
+ pSel - Variable for storing the resulting selector.
+
+--*/
+{
+ I386DESCRIPTOR Desc;
+ NTSTATUS Status;
+ SEL Sel;
+
+ //
+ // Set A Data segment selector in the LDT
+ //
+
+ Desc.BaseAddress = BaseAddress;
+ Desc.Limit = cbSize-1;
+ Desc.Type = READ_WRITE_DATA;
+
+ //
+ // Apply tiling scheme
+ //
+ Sel = (SEL)FLATTOSEL((Desc.BaseAddress));
+
+ Status = Nt386SetDescriptorLDT (
+ NULL,
+ Sel,
+ Desc);
+ if (!NT_SUCCESS( Status ))
+ {
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ *pSel = (USHORT) Sel;
+
+ return (NO_ERROR);
+}
+
+#endif /* PMNT */
+
+APIRET
+DosAllocSeg(
+ IN USHORT cbSize,
+ OUT PSEL pSel,
+ IN USHORT fsAlloc
+ )
+{
+ NTSTATUS Status;
+ PVOID BaseAddress;
+ APIRET rc;
+ ULONG Size, flags;
+ ULONG Index;
+ BOOLEAN PrivateSeg;
+
+ //
+ // probe pSel pointer.
+ //
+
+ try {
+ *pSel = 0;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // check validity of fsAlloc
+ //
+ if (fsAlloc & ~(SEG_GIVEABLE | SEG_GETTABLE | SEG_DISCARDABLE | SEG_SIZEABLE)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ //
+ // OS2 1.X treats a 0 size request as (64k -1)
+ //
+ if (cbSize == 0)
+ Size = _64K;
+ else
+ Size = cbSize;
+
+ //
+ // First we reserve 64K, then we commit the size
+ // requested, rounded up to page granularity, by DosSetMem.
+ //
+ if ((fsAlloc == SEG_NONSHARED) || (fsAlloc == SEG_DISCARDABLE)) {
+ PrivateSeg = TRUE;
+ Index = ((ULONG)Od2MemoryAllocationBase - BASE_TILE) / _64K;
+ Index = ldtAllocateSelectors(
+ 1, // NumberOfSel
+ Index // StartOfMark
+ );
+
+ if (Index == 0xffffffff){
+ //
+ // not found - no memory
+ //
+ Od2MemoryAllocationBase = (PVOID)(BASE_TILE + _64K);
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ Od2MemoryAllocationBase = BaseAddress = (PVOID)((Index * _64K) + BASE_TILE);
+
+ flags = fALLOC - PAG_GUARD;
+ rc = DosAllocMem(
+ &BaseAddress,
+ _64K,
+ (flags - PAG_COMMIT));
+ }
+ else {
+ PrivateSeg = FALSE;
+ //
+ // we ignore discardable, and make it givable and gettable
+ // (see DosAllocSharedMem).
+ //
+
+ // we use page execute to mark that the data segments is
+ // sizeable
+
+ if (fsAlloc & SEG_SIZEABLE)
+ flags = fALLOCSHR - PAG_GUARD;
+ else
+ flags = fALLOCSHR - PAG_GUARD - PAG_EXECUTE;
+
+ rc = DosAllocSharedMem(
+ &BaseAddress,
+ NULL,
+ Size, // The real size of the segment will be used to
+ // create proper LDT entry. In any case 64K will
+ // be reserved.
+ (flags - PAG_COMMIT),
+ TRUE // Create LDT entry of shared, non huge, unnamed
+ // segment.
+ );
+ }
+
+ if (rc != NO_ERROR) {
+ if (PrivateSeg) {
+ ldtFreeSelectors(Index, 1);
+ }
+ return (rc);
+ }
+
+ rc = DosSetMem(
+ BaseAddress,
+ Size,
+ flags & ~(OBJ_GETTABLE | OBJ_GIVEABLE));
+
+ if (rc != NO_ERROR){
+ BOOLEAN RemoveLDTEntry = TRUE;
+
+ DosFreeMem(BaseAddress, &RemoveLDTEntry);
+ if (PrivateSeg) {
+ ldtFreeSelectors(Index, 1);
+ }
+ return (rc);
+ }
+
+ if (PrivateSeg) {
+
+ SEL Sel;
+ I386DESCRIPTOR Desc;
+ //
+ // Set A Data segment selector in the LDT
+ //
+ Desc.BaseAddress = (ULONG) BaseAddress;
+ Desc.Limit = cbSize-1;
+ Desc.Type = READ_WRITE_DATA;
+
+ //
+ // Apply tiling scheme
+ //
+ Sel = (SEL)FLATTOSEL((Desc.BaseAddress));
+
+ Status = Nt386SetDescriptorLDT (
+ NULL,
+ Sel,
+ Desc);
+ if (!NT_SUCCESS( Status )) {
+ BOOLEAN RemoveLDTEntry = FALSE;
+
+ DosFreeMem(BaseAddress, &RemoveLDTEntry);
+ ldtFreeSelectors(Index, 1);
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ }
+
+ *pSel = FLATTOSEL(BaseAddress);
+
+#if DBG
+ if ((Os2DebugSel != 0) && (*pSel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosAllocSeg returning sel=%x (size=%x, fsAlloc=%x)\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ *pSel,
+ cbSize,
+ fsAlloc);
+ }
+#endif
+ return (NO_ERROR);
+}
+
+APIRET
+DosFreeSeg(
+ IN SEL sel
+ )
+{
+ NTSTATUS Status;
+ PVOID BaseAddress;
+ APIRET rc;
+ I386DESCRIPTOR Desc;
+ PHUGE_SEG_RECORD pHuge, pHugePrev;
+ ULONG i;
+ SEL Sel;
+ USHORT SelIndex;
+ ULONG ActualSegs = 1;
+ BOOLEAN RemoveLDTEntry = TRUE; // Initially ask to remove LDT entry
+ BOOLEAN ResourceFree = FALSE; // Initially consider that the segment
+ // isn't a resource
+
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosFreeSeg called on sel=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel);
+ }
+#endif
+
+ //
+ // check for an obviously invalid selector
+ //
+
+ if (((sel & 0x7) != 0x7) ||
+ ((sel & 0xfff8) == 0)) {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosFreeSeg: Invalid selector: %x\n", sel);
+ }
+#endif
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosFreeSeg called on sel=%x, returning ACCESS_DENIED\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel);
+ }
+#endif
+ return(ERROR_ACCESS_DENIED);
+ }
+
+ //
+ // Calculate base address (tiling)
+ //
+ BaseAddress = SELTOFLAT(sel);
+
+
+ //
+ // Now Free Descriptors:
+ // o lookup for a huge segment
+ // if not huge - free one segment
+ // else
+ // if in the middle - return error.
+ // free all segments
+ // free huge record and unlink
+ //
+ Desc.Type = INVALID;
+
+ //
+ // Make sure other threads don't muck with HugeSeg list
+ //
+ AcquireTaskLock();
+
+ //
+ // Check if we are freeing a resource
+ //
+ SelIndex = (USHORT)sel >> 3;
+ if ((SelIndex >= LDT_NUMBER_OF_PRIVATE_SEGMENTS) &&
+ (ResourceUsage[SelIndex - LDT_NUMBER_OF_PRIVATE_SEGMENTS] > 0)
+ ) {
+ ResourceUsage[SelIndex - LDT_NUMBER_OF_PRIVATE_SEGMENTS]--;
+ if (ResourceUsage[SelIndex - LDT_NUMBER_OF_PRIVATE_SEGMENTS] > 0) {
+ ReleaseTaskLock();
+ return(NO_ERROR);
+ }
+ ResourceFree = TRUE; // This segment is resource and it will be freed
+ // For resources critical section must be longer
+ // to avoid incosistancy with ResourceUsage array
+ }
+ for (pHuge = pHugeSegHead;
+ pHuge != NULL;
+ pHugePrev = pHuge, pHuge = (PHUGE_SEG_RECORD)(pHuge->Next)) {
+ if (pHuge->BaseSelector == (ULONG)(sel)) {
+ ActualSegs = pHuge->cNumSeg;
+ if (pHuge->PartialSeg != 0) {
+ ActualSegs++;
+ }
+ for (i = 0, Sel = sel; i < ActualSegs; i++, Sel += 8) {
+
+ Status = Nt386SetDescriptorLDT (
+ NULL,
+ Sel,
+ Desc);
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint ("DosFreeSeg fails to set descriptor\n");
+#endif
+ ReleaseTaskLock();
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosFreeSeg called on sel=%x, returning ACCESS_DENIED\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel);
+
+ }
+#endif
+ return( ERROR_ACCESS_DENIED );
+ }
+ }
+ //
+ // After descriptors are freed,
+ // Unlink and free Huge Seg structure.
+ //
+ if (pHuge == pHugeSegHead)
+ //
+ // Get rid of first on the list
+ //
+ pHugeSegHead = (PHUGE_SEG_RECORD)(pHuge->Next);
+ else
+ pHugePrev->Next = pHuge->Next;
+ RtlFreeHeap(Od2Heap, 0,pHuge);
+ RemoveLDTEntry = FALSE; // LDT entries were removed for huge
+ // segments. Sign that they must not
+ // be removed any more.
+ break;
+ }
+ //
+ // Look for a selector in the middle of a DosHugeAlloc
+ // Alloction
+ //
+ else if ( (sel > (SEL)(pHuge->BaseSelector)) &&
+ (sel < (SEL)(pHuge->BaseSelector + 8 * ActualSegs)) ) {
+
+ ReleaseTaskLock();
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosFreeSeg called on sel=%x, returning INVALID_ADDRESS\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel);
+ }
+#endif
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ if (!ResourceFree)
+ ReleaseTaskLock(); // For resources, critical section will be longer.
+ //
+ // Free the memory
+ //
+ rc = DosFreeMem (BaseAddress, &RemoveLDTEntry); // Free memory and LDT entry
+ // if it is needed
+ if (rc != NO_ERROR) {
+ if (rc == ERROR_INVALID_ADDRESS) {
+
+ //
+ // try to see if this is a CSAlias (see CreateCsAlias)
+ // in this case, we unmap the view
+ //
+
+ POS21X_CSALIAS pCSAlias, pCSAliasPrev;
+ POS21X_CS pCS, pCSPrev;
+
+ if (!ResourceFree)
+ AcquireTaskLock();
+ if (Od2CSAliasListHead != 0) {
+ for (pCSAlias = (POS21X_CSALIAS) Od2CSAliasListHead;
+ pCSAlias != NULL;
+ pCSAliasPrev = pCSAlias, pCSAlias = (POS21X_CSALIAS) (pCSAlias->Next)
+ ) {
+ if (pCSAlias->selDS == sel) {
+ //
+ // Trying to free the base DS, to which the aliases
+ // were mapped
+ //
+ if (pCSAlias->pCSList == NULL) {
+ //
+ // No aliases left, close section and free everything
+ //
+ NtClose(pCSAlias->SectionHandle);
+ if (pCSAlias == (POS21X_CSALIAS)Od2CSAliasListHead) {
+
+ //
+ // Get rid of first on the list
+ //
+ Od2CSAliasListHead = pCSAlias->Next;
+ }
+ else {
+ pCSAliasPrev->Next = pCSAlias->Next;
+ }
+ RtlFreeHeap(Od2Heap, 0, pCSAlias);
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosFreeSeg: Freeing the DS of a CSAlias, with the section. selDS %x \n",
+ sel);
+ }
+#endif
+ }
+ else {
+ //
+ // The DS base of an alias section was freed, but some CSs
+ // exist (legal in OS/2). Change the selDS field
+ // to NULL, so subsequent CreateCSAlias will fail
+ // to find it
+ //
+ pCSAlias->selDS = (SEL)NULL;
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosFreeSeg: Freeing the DS of a CSAlias. code segemnt are still around selDS %x \n",
+ sel);
+ }
+#endif
+ }
+
+ break;
+ }
+ else {
+ //
+ // walk thru the CS aliases of this section, see if
+ // we are freeing one of the code segments
+ //
+
+ BOOLEAN CSFound;
+
+ for ( CSFound = FALSE, pCS = (POS21X_CS) pCSAlias->pCSList;
+ pCS != NULL ;
+ pCSPrev = pCS, pCS = (POS21X_CS)pCS->Next) {
+
+ if (pCS->selCS == sel) {
+ //
+ // found it - unlink from CSList and free
+ //
+ if (pCS == pCSAlias->pCSList) {
+
+ //
+ // Get rid of first on the list
+ //
+ pCSAlias->pCSList = (POS21X_CS)(pCS->Next);
+ if (pCSAlias->pCSList == NULL) {
+ //
+ // just removed the last one,
+ // see if the DS is still alive, and if
+ // not - remove the structure
+ //
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosFreeSeg: Freed the last CSAlias. selDS is %x. selCS is %x \n",
+ pCSAlias->selDS, sel);
+ }
+#endif
+ if (pCSAlias->selDS == (SEL)NULL) {
+ NtClose(pCSAlias->SectionHandle);
+ RtlFreeHeap(Od2Heap, 0, pCSAlias);
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosFreeSeg: Freed Section and heap for CSAlias last CSAlias. selCS is %x\n",
+ sel);
+ }
+#endif
+ }
+ }
+ }
+ else {
+ pCSPrev->Next = pCS->Next;
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosFreeSeg: Freeing a CSAlias. selDS is %x. selCS is %x\n",
+ pCSAlias->selDS, sel);
+ }
+#endif
+ }
+
+ CSFound = TRUE;
+ RtlFreeHeap(Od2Heap, 0, pCS);
+ break;
+ }
+ }
+ if (CSFound) {
+ //
+ // break out of the lookup for csalias
+ //
+ break;
+ }
+ }
+ }
+ }
+ if (!ResourceFree)
+ ReleaseTaskLock();
+
+ Status = NtUnmapViewOfSection(NtCurrentProcess(),
+ BaseAddress
+ );
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosFreeSeg: Can't UnmapView, Status=%lx\n", Status);
+ }
+#endif
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosFreeSeg called on sel=%x, returning INVALID_ADDRESS\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel);
+ }
+#endif
+ if (ResourceFree)
+ ReleaseTaskLock();
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+ else {
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosFreeSeg called on sel=%x, returning rc=%d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel,
+ rc);
+ }
+#endif
+ if (ResourceFree)
+ ReleaseTaskLock();
+ return(rc);
+ }
+ }
+
+ if (RemoveLDTEntry) {
+
+ // LDT entry wasn't removed yet. It is TRUE for private segments
+ // and for the named shared segments and for aliases.
+
+ Status = Nt386SetDescriptorLDT (
+ NULL,
+ sel,
+ Desc);
+
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint ("DosFreeSeg fails to set descriptor\n");
+#endif
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosFreeSeg called on sel=%x, returning ACCESS_DENIED\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel);
+ }
+#endif
+ if (ResourceFree)
+ ReleaseTaskLock();
+ return( ERROR_ACCESS_DENIED );
+ }
+ }
+
+ if (ResourceFree)
+ ReleaseTaskLock();
+
+ ldtFreeSelectors(
+ (sel >> 3), // Index,
+ ActualSegs // Numofbits
+ );
+
+ //
+ // Update the base segment for allocation of segments
+ //
+ if (Od2MemoryAllocationBase > BaseAddress)
+ Od2MemoryAllocationBase = BaseAddress;
+
+ return (NO_ERROR);
+}
+
+APIRET
+DosGetSeg(
+ IN SEL InSel
+ )
+{
+ OS2_API_MSG m;
+ POS2_GETSEG_MSG a = &m.u.DosGetSeg;
+
+ a->Selector = InSel;
+ Od2CallSubsystem( &m, NULL, Os2GetSeg, sizeof( *a ) );
+
+#if DBG
+ if ((Os2DebugSel != 0) && (InSel == Os2DebugSel))
+ {
+ if (m.ReturnedErrorValue == NO_ERROR)
+ DbgPrint("[%x,%x] DosGetSeg called on sel=%x (successfull)\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ InSel);
+ else
+ DbgPrint("[%x,%x] DosGetSeg called on sel=%x, rc=%d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ InSel,
+ m.ReturnedErrorValue);
+ }
+#endif
+
+ return(m.ReturnedErrorValue);
+}
+
+
+APIRET
+DosGiveSeg(
+ IN SEL sel,
+ IN PID pid,
+ OUT PSEL pSelRecipient
+ )
+{
+ OS2_API_MSG m;
+ POS2_GIVESEG_MSG a = &m.u.DosGiveSeg;
+
+ try {
+ *pSelRecipient = 0;
+ }
+ except (EXCEPTION_EXECUTE_HANDLER) {
+ Od2ExitGP();
+ }
+
+ *pSelRecipient = sel;
+
+ a->Selector = sel;
+ a->TargetPid = pid;
+
+ Od2CallSubsystem( &m, NULL, Os2GiveSeg, sizeof( *a ) );
+
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ if (m.ReturnedErrorValue == NO_ERROR)
+ DbgPrint("[%x,%x] DosGetSeg called on sel=%x (successfull)\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel);
+ else
+ DbgPrint("[%x,%x] DosGetSeg called on sel=%x, rc=%d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel,
+ m.ReturnedErrorValue);
+ }
+#endif
+
+ return(m.ReturnedErrorValue);
+}
+
+APIRET ResizeSharedMemory(
+ HANDLE ProcessHandle,
+ PVOID AllocFreeBaseAddress, // start address of new allocation / free
+ ULONG Index,
+ ULONG CurrentSize, // ldt limit rounded to pages
+ USHORT NewLdtLimit, // New segment size in bytes
+ ULONG NewRegionSize, // New segment size rounded to pages
+ ULONG Flags // Flags of new allocated memory
+)
+{
+ PVOID TmpAllocFreeBaseAddress;
+ PROCESS_LDT_INFORMATION LdtInfo;
+ struct desctab {
+ USHORT d_limit; /* Segment limit */
+ USHORT d_loaddr; /* Low word of physical address */
+ UCHAR d_hiaddr; /* High byte of physical address */
+ UCHAR d_access; /* Access byte */
+ UCHAR d_attr; /* Attributes/extended limit */
+ UCHAR d_extaddr; /* Extended physical address byte */
+ } *LDTDesc;
+ ULONG RegionSize;
+ NTSTATUS Status;
+ APIRET rc;
+ rc = NO_ERROR;
+ // acording to the new size allocate / free memory
+
+ // get current LDT entry
+ LdtInfo.Length = sizeof(LDT_ENTRY);
+ LdtInfo.Start = Index & 0xfffffff8;
+ LDTDesc = (struct desctab *)(&LdtInfo.LdtEntries[0]);
+ Status = NtQueryInformationProcess(
+ ProcessHandle,
+ ProcessLdtInformation,
+ &LdtInfo,
+ sizeof(PROCESS_LDT_INFORMATION),
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("Os2DosReallocSharedMem NtQueryInformationProcess failed. \n");
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+ if ((LDTDesc->d_access & 0x80) == 0) {
+ return(ERROR_INVALID_SEGMENT_NUMBER); // This is an internal error code
+ // passed to the caller of this
+ // procedure to notify that the
+ // segment was not updated since
+ // it was not in use.
+ }
+
+
+ // Update The Segment Size in LDT
+
+ if (LDTDesc->d_limit != NewLdtLimit) {
+ LDTDesc->d_limit = NewLdtLimit;
+ LdtInfo.Length = sizeof(LDT_ENTRY);
+ LdtInfo.Start = Index & 0xfffffff8;
+ Status = NtSetInformationProcess(
+ ProcessHandle,
+ ProcessLdtInformation,
+ &LdtInfo,
+ sizeof(PROCESS_LDT_INFORMATION)
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("Os2DosReallocSharedMem NtSetInformationProcess failed. %lx\n",
+ Status);
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+ }
+ else
+ return(NO_ERROR);
+
+ if (CurrentSize < NewRegionSize) {
+ // alloc mem
+ RegionSize = NewRegionSize - CurrentSize;
+ TmpAllocFreeBaseAddress = AllocFreeBaseAddress;
+ Status = NtAllocateVirtualMemory(
+ ProcessHandle,
+ &TmpAllocFreeBaseAddress,
+ 1,
+ &RegionSize,
+ MEM_COMMIT,
+ Flags
+ );
+ if (NT_SUCCESS(Status) || (Status == STATUS_ALREADY_COMMITTED)) {
+ rc = NO_ERROR;
+ }
+ else if (Status == STATUS_CONFLICTING_ADDRESSES) {
+
+ MEMORY_BASIC_INFORMATION MemoryInformation;
+ PVOID AllocationBase = (PVOID) ((ULONG)AllocFreeBaseAddress & 0xffff0000);
+ PBYTE pSegmentCopy;
+
+ Status = NtQueryVirtualMemory(
+ ProcessHandle,
+ (PVOID)((ULONG)AllocationBase + NewRegionSize - 1),
+ MemoryBasicInformation,
+ &MemoryInformation,
+ sizeof( MemoryInformation ),
+ NULL
+ );
+ if (!NT_SUCCESS(Status) || MemoryInformation.State != MEM_FREE) {
+#if DBG
+ DbgPrint("[%d,%d] DosReallocSeg fail with STATUS_CONFLICTING_ADDRESSES, State=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ MemoryInformation.State
+ );
+#endif // DBG
+ return (ERROR_ACCESS_DENIED);
+ }
+
+ pSegmentCopy = RtlAllocateHeap(Od2Heap, 0, CurrentSize);
+ if (pSegmentCopy == NULL) {
+#if DBG
+ DbgPrint("[%d,%d] DosReallocSeg fail to allocate from local heap\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId()
+ );
+#endif // DBG
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ DosHoldSignal(HLDSIG_DISABLE, 0);
+ Od2SuspendAllThreads();
+
+ RtlCopyMemory(pSegmentCopy, (PBYTE)AllocationBase, CurrentSize);
+
+ Status = NtUnmapViewOfSection(
+ ProcessHandle,
+ AllocationBase
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("[%d,%d] DosReallocSeg fail on NtUnmapViewOfSection, Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status
+ );
+ ASSERT(FALSE);
+#endif // DBG
+ Od2ResumeAllThreads();
+ DosHoldSignal(HLDSIG_ENABLE, 0);
+ RtlFreeHeap(Od2Heap, 0, pSegmentCopy);
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ RegionSize = _64K;
+
+ Status = NtAllocateVirtualMemory(
+ ProcessHandle,
+ &AllocationBase,
+ 1,
+ &RegionSize,
+ MEM_RESERVE,
+ PAGE_EXECUTE_READWRITE
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("[%d,%d] DosReallocSeg fail on NtAllocateVirtualMemory (RESERVE), Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status
+ );
+ ASSERT(FALSE);
+#endif // DBG
+ DosExit(EXIT_PROCESS, ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ RegionSize = NewRegionSize;
+
+ Status = NtAllocateVirtualMemory(
+ ProcessHandle,
+ &AllocationBase,
+ 1,
+ &RegionSize,
+ MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE
+ );
+ if (NT_SUCCESS(Status)) {
+ RtlCopyMemory(AllocationBase, pSegmentCopy, CurrentSize);
+ rc = NO_ERROR;
+ }
+ else {
+#if DBG
+ DbgPrint("[%d,%d] DosReallocSeg fail on NtAllocateVirtualMemory (COMMIT), Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status
+ );
+#endif // DBG
+ DosExit(EXIT_PROCESS, ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ Od2ResumeAllThreads();
+ DosHoldSignal(HLDSIG_ENABLE, 0);
+ RtlFreeHeap(Od2Heap, 0, pSegmentCopy);
+#if DBG
+ IF_OD2_DEBUG( MEMORY ) {
+ Status = NtQueryVirtualMemory(
+ ProcessHandle,
+ AllocationBase,
+ MemoryBasicInformation,
+ &MemoryInformation,
+ sizeof( MemoryInformation ),
+ NULL
+ );
+ DbgPrint("[%d,%d]Reallocation of the private data segment:\n\tBaseAddress=%x\n\tAllocationBase=%x\n\tAllocationProtect=%x\n\tRegionSize=%x\n\tState=%x\n\tProtect=%x\n\tType=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ MemoryInformation.BaseAddress,
+ MemoryInformation.AllocationBase,
+ MemoryInformation.AllocationProtect,
+ MemoryInformation.RegionSize,
+ MemoryInformation.State,
+ MemoryInformation.Protect,
+ MemoryInformation.Type
+ );
+ Status = NtQueryVirtualMemory(
+ ProcessHandle,
+ (PVOID)((ULONG)AllocationBase+RegionSize),
+ MemoryBasicInformation,
+ &MemoryInformation,
+ sizeof( MemoryInformation ),
+ NULL
+ );
+ DbgPrint("\n\tBaseAddress=%x\n\tAllocationBase=%x\n\tAllocationProtect=%x\n\tRegionSize=%x\n\tState=%x\n\tProtect=%x\n\tType=%x\n",
+ MemoryInformation.BaseAddress,
+ MemoryInformation.AllocationBase,
+ MemoryInformation.AllocationProtect,
+ MemoryInformation.RegionSize,
+ MemoryInformation.State,
+ MemoryInformation.Protect,
+ MemoryInformation.Type
+ );
+ }
+#endif
+ }
+ else {
+#if DBG
+ DbgPrint("[%d,%d] DosReallocSeg fail on NtAllocateVirtualMemory with Status=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ Status
+ );
+#endif // DBG
+ rc = ERROR_ACCESS_DENIED;
+ }
+ }
+ else
+ {
+ if (CurrentSize > NewRegionSize) {
+ // freemem
+ RegionSize = CurrentSize - NewRegionSize;
+ TmpAllocFreeBaseAddress =
+ (PVOID)((long)AllocFreeBaseAddress - (long)RegionSize);
+ Status = NtFreeVirtualMemory(
+ ProcessHandle,
+ &TmpAllocFreeBaseAddress,
+ &RegionSize,
+ MEM_DECOMMIT
+ );
+ //
+ // The STATUS_UNABLE_TO_FREE_VM status is returned when
+ // trying to decommit pages of mapped sections. This error
+ // should not be reported to the user program.
+ //
+ if (NT_SUCCESS(Status) ||
+ (Status == STATUS_UNABLE_TO_FREE_VM) ||
+ (Status == STATUS_UNABLE_TO_DELETE_SECTION))
+ rc = NO_ERROR;
+ else
+ rc = ERROR_ACCESS_DENIED;
+ }
+ }
+ return(rc);
+}
+
+
+
+APIRET
+DosReallocSeg(
+ IN USHORT cbNewSize,
+ IN SEL sel
+ )
+{
+ NTSTATUS Status;
+ PVOID BaseAddress;
+ APIRET rc = NO_ERROR;
+ ULONG Size, CurrentSize;
+ I386DESCRIPTOR Desc;
+ MEMORY_BASIC_INFORMATION MemoryInformation;
+ OS2_API_MSG m;
+ POS2_REALLOCSHAREDMEM_MSG a = &m.u.ReallocSharedMem;
+ ULONG Index;
+ POS21X_CSALIAS pCSAlias;
+ BOOLEAN SelIsCSADS;
+
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosReallocSeg called on sel=%x, new size=%d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel,
+ cbNewSize);
+ }
+#endif
+ //
+ // OS2 1.X treats a 0 size request as (64k -1)
+ //
+ if (cbNewSize == 0)
+ Size = _64K;
+ else
+ Size = ROUND_UP_TO_PAGES(cbNewSize);
+
+
+ if (!IsLegalSelector(sel)){
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosReallocSeg called on sel=%x, returning ACCES_DENIED\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel);
+ }
+#endif
+ return( ERROR_ACCESS_DENIED );
+ }
+ //
+ // Calculate base address (tiling)
+ //
+ BaseAddress = SELTOFLAT(sel);
+
+ //
+ // Get the current LDT setting
+ //
+ Status = Nt386GetDescriptorLDT (
+ NULL,
+ sel,
+ &Desc);
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint ("DosReallocSeg fails to get descriptor info\n");
+#endif
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("DosReallocSeg called on sel=%x, returning INVALID_PARAMETER\n",
+ sel);
+ }
+#endif
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ Status = NtQueryVirtualMemory(
+ NtCurrentProcess(),
+ BaseAddress,
+ MemoryBasicInformation,
+ &MemoryInformation,
+ sizeof( MemoryInformation ),
+ NULL
+ );
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint ("DosReallocSeg fails to QueryVirtualMemory\n");
+
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosReallocSeg called on sel=%x, returning INVALID_PARAMETER\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel);
+ }
+#endif
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ CurrentSize = ROUND_UP_TO_PAGES(Desc.Limit + 1);
+
+ // Check if this is a Data Segment of a CSAlias Only for "Pseodo shared
+ // READ/WRITE Data Segments
+ // This is done since when creating a CSAlias we change the DS page
+ // protection from PAGE_EXECUTE_WRITE_COPY TO PAGE_READ_WRITE since it is
+ // mapped tweice (once to the DS and once to the CS)
+
+ SelIsCSADS = FALSE;
+ if (MemoryInformation.AllocationProtect == PAGE_READWRITE) {
+ AcquireTaskLock();
+ if (Od2CSAliasListHead != 0) {
+ for (pCSAlias = (POS21X_CSALIAS) Od2CSAliasListHead;
+ pCSAlias != NULL;
+ pCSAlias = (POS21X_CSALIAS) (pCSAlias->Next)) {
+ if (pCSAlias->selDS == sel) {
+ SelIsCSADS = TRUE;
+ break;
+ }
+ }
+ }
+ ReleaseTaskLock();
+ }
+
+ if ((sel < FIRST_SHARED_SELECTOR) ||
+ (MemoryInformation.AllocationProtect == PAGE_EXECUTE_WRITECOPY) ||
+ SelIsCSADS ||
+ (MemoryInformation.Type == MEM_PRIVATE))
+ { // This is a non shared segment
+
+ Index = FLATTOSEL(BaseAddress);
+
+ rc = ResizeSharedMemory(
+ NtCurrentProcess(),
+ (PVOID)(((ULONG)BaseAddress)+CurrentSize),
+ Index,
+ CurrentSize,
+ (USHORT)(cbNewSize-1),
+ Size,
+ MemoryInformation.AllocationProtect
+ );
+ }
+ else
+ { // this is a shared segment
+
+ a->BaseAddress = (PVOID) BaseAddress;
+ a->NewRegionSize = Size;
+ a->AllocFreeBaseAddress = (PVOID)(((ULONG)BaseAddress)+CurrentSize);
+ a->NewLdtLimit = cbNewSize-1;
+ a->Flags = MemoryInformation.AllocationProtect;
+ a->CurrentSize = CurrentSize;
+ if ( Desc.Limit <= (ULONG)(cbNewSize-1)) {
+
+ Od2CallSubsystem( &m, NULL, Os2ReallocSharedMem, sizeof( *a ) );
+ rc = m.ReturnedErrorValue ;
+ }
+ else {
+ switch (MemoryInformation.AllocationProtect) {
+ case PAGE_EXECUTE_READWRITE :
+
+// if ( Size < CurrentSize ) {
+ Od2CallSubsystem( &m, NULL,
+ Os2ReallocSharedMem, sizeof( *a ) );
+ rc = m.ReturnedErrorValue ;
+// }
+ break;
+ case PAGE_READONLY :
+ case PAGE_READWRITE :
+ case PAGE_WRITECOPY :
+ case PAGE_EXECUTE :
+ case PAGE_EXECUTE_READ :
+ rc = ERROR_ACCESS_DENIED;
+ break;
+ default:
+ rc = ERROR_ACCESS_DENIED;
+ break;
+ }
+ }
+ }
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel) && (rc != NO_ERROR))
+ {
+ DbgPrint("[%x,%x] DosReallocSeg called on sel=%x, returning rc=%d\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel, rc);
+ }
+#endif
+
+ return (rc);
+}
+
+APIRET
+DosAllocHuge(
+ IN ULONG cSegs,
+ IN USHORT cbPartialSeg,
+ OUT PSEL pSel,
+ IN ULONG cMaxSegs,
+ IN USHORT fsAlloc
+ )
+{
+ NTSTATUS Status;
+ PVOID BaseAddress;
+ APIRET rc;
+ SEL Sel;
+ ULONG ReservedSize, flags, CommittedSize, cMax, i;
+ I386DESCRIPTOR Desc;
+ PHUGE_SEG_RECORD pHuge;
+ BOOLEAN PartialSeg = FALSE;
+ ULONG Index;
+ OS2_API_MSG m;
+ POS2_MARKSHAREDMEMASHUGE_MSG a = &m.u.MarkSharedMemAsHuge;
+ BOOLEAN HugeSegIsShared = FALSE;
+ BOOLEAN HugeSegIsSizeable = FALSE;
+
+ //
+ // probe pSel pointer.
+ //
+
+ try {
+ *pSel = 0;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // calculate how many segments to actually allocate
+ //
+ if (cbPartialSeg) {
+ PartialSeg = TRUE;
+ }
+
+ //
+ // cMaxSegs==0 means it can't grow
+ //
+ if (cMaxSegs == 0) {
+ cMax = cSegs;
+ if (PartialSeg) {
+ cMax++;
+ }
+ }
+ else {
+ cMax = cMaxSegs;
+ }
+
+ //
+ // check the parameters
+ //
+ if (cSegs == 0 && !PartialSeg) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+ if ((cSegs > cMax) || ((cSegs == cMax) && PartialSeg)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+ if (fsAlloc & ~(SEG_GIVEABLE | SEG_GETTABLE | SEG_DISCARDABLE | SEG_SIZEABLE)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ ReservedSize = cMax * _64K;
+
+ CommittedSize = cSegs * _64K + cbPartialSeg;
+
+ pHuge = RtlAllocateHeap( Od2Heap, 0, sizeof( HUGE_SEG_RECORD) );
+ if (pHuge == NULL) {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ Index = ((ULONG)Od2MemoryAllocationBase - BASE_TILE) / _64K;
+ Index = ldtAllocateSelectors(
+ cMax, // NumberOfSel
+ Index // StartOfMark
+ );
+
+ if (Index == 0xffffffff){
+ //
+ // not found - no memory
+ //
+ Od2MemoryAllocationBase = (PVOID)(BASE_TILE + _64K);
+ RtlFreeHeap(Od2Heap, 0, pHuge);
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ BaseAddress = Od2MemoryAllocationBase = (PVOID)((Index * _64K) + BASE_TILE);
+ //
+ // First we reserve (64K gran), then we commit the size
+ // requested, rounded up to page granularity, by DosSetMem.
+ //
+
+ if ((fsAlloc == SEG_NONSHARED) || (fsAlloc == SEG_DISCARDABLE)) {
+ flags = fALLOC - PAG_GUARD;
+ rc = DosAllocMem(
+ &BaseAddress,
+ ReservedSize,
+ (flags - PAG_COMMIT));
+ }
+ else {
+ HugeSegIsShared = TRUE;
+ //
+ // we ignore discardable, and make it givable and gettable
+ // (see DosAllocSharedMem).
+ //
+ flags = fALLOCSHR - (PAG_GUARD | OBJ_GETTABLE | OBJ_GIVEABLE);
+
+ // we use page execute to mark that the data segments is
+ // sizeable
+
+ if ((fsAlloc & SEG_SIZEABLE) == 0) {
+ flags &= ~PAG_EXECUTE;
+ }
+ else {
+ HugeSegIsSizeable = TRUE;
+ }
+
+ rc = DosAllocSharedMem(
+ &BaseAddress,
+ NULL,
+ ReservedSize,
+ ((flags - PAG_COMMIT) | OBJ_GETTABLE | OBJ_GIVEABLE),
+ FALSE // Don't create LDT entry for huge segments.
+ );
+ }
+
+ if (rc != NO_ERROR) {
+ ldtFreeSelectors(Index, cMax);
+ RtlFreeHeap(Od2Heap, 0, pHuge);
+ return (rc);
+ }
+
+ rc = DosSetMem(
+ BaseAddress,
+ CommittedSize,
+ flags);
+
+ if (rc != NO_ERROR){
+ BOOLEAN RemoveLDTEntry = FALSE;
+
+ DosFreeMem (BaseAddress, &RemoveLDTEntry);
+ ldtFreeSelectors(Index, cMax);
+ RtlFreeHeap(Od2Heap, 0, pHuge);
+ return (rc);
+ }
+
+ //
+ // Set Data segments in the LDT
+ //
+ //
+ // first do the full 64k segments
+ //
+ Desc.Limit = _64K - 1;
+ Desc.Type = READ_WRITE_DATA;
+ Desc.BaseAddress = (ULONG) BaseAddress;
+
+ Sel = (SEL)(FLATTOSEL(Desc.BaseAddress));
+ for (i = 0;
+ i < cSegs;
+ i++, Sel += 8, Desc.BaseAddress += _64K) {
+
+ Status = Nt386SetDescriptorLDT (
+ NULL,
+ Sel,
+ Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ }
+
+ //
+ // Do the partial seg
+ //
+ if (PartialSeg) {
+ Desc.Limit = cbPartialSeg - 1;
+
+ Status = Nt386SetDescriptorLDT (
+ NULL,
+ Sel,
+ Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ }
+
+ //
+ // Mark at the server the allocated memory as huge memory
+ //
+ if ((fsAlloc & SEG_GETTABLE) || (fsAlloc & SEG_GIVEABLE)) {
+ a->BaseAddress = BaseAddress;
+ a->MaxSegments = cMax;
+ a->NumOfSegments = cSegs;
+ a->SizeOfPartialSeg = cbPartialSeg;
+ a->Sizeable = (fsAlloc & SEG_SIZEABLE) ? TRUE : FALSE;
+ Od2CallSubsystem( &m, NULL, Oi2MarkSharedMemAsHuge, sizeof( *a ) );
+ }
+
+ //
+ // Return the Selector of the allocation base
+ //
+
+ *pSel = FLATTOSEL(((ULONG)BaseAddress));
+
+ //
+ // Now we record that this segment
+ // is Huge so we free and realloc accordingly
+ //
+ AcquireTaskLock();
+ pHuge->Next = (struct HUGE_SEG_RECORD *)pHugeSegHead;
+ pHuge->MaxNumSeg = cMax;
+ pHuge->BaseSelector = *pSel;
+ pHuge->cNumSeg = cSegs;
+ pHuge->PartialSeg = cbPartialSeg;
+ pHuge->fShared = HugeSegIsShared;
+ pHuge->fSizeable = HugeSegIsSizeable;
+
+ pHugeSegHead = pHuge;
+ ReleaseTaskLock();
+
+ return (NO_ERROR);
+}
+
+
+APIRET
+DosReallocHuge(
+ IN USHORT cSegs,
+ IN USHORT cbPartialSeg,
+ IN SEL sel
+ )
+{
+ OS2_API_MSG m;
+ POS2_QUERYVIRTUALMEMORY_MSG a = &m.u.QueryVirtualMemory;
+ POS2_REALLOCSHAREDHUGE_MSG b = &m.u.ReallocSharedHuge;
+ NTSTATUS Status;
+ PVOID BaseAddress;
+ APIRET rc;
+ SEL Sel = 0;
+ ULONG CommitSize;
+ ULONG DecommitSize;
+ I386DESCRIPTOR Desc;
+ PHUGE_SEG_RECORD pHuge;
+ ULONG i, cNewSegs, cDelSegs, SegSize;
+ ULONG Op = 0;
+
+ //
+ // Make sure other threads don't muck with HugeSeg list while we
+ // scan it
+ //
+ AcquireTaskLock();
+ //
+ // lookup the HugeSeg list to find out if sel is a valid Huge memory
+ //
+ for (pHuge = pHugeSegHead;
+ pHuge != NULL;
+ pHuge = (PHUGE_SEG_RECORD)(pHuge->Next)) {
+ if (pHuge->BaseSelector == (ULONG)(sel)) {
+ break;
+ }
+ }
+
+ if (pHuge == NULL) {
+
+ //
+ // Did not find a Huge Seg that starts with sel
+ //
+ //
+ // The huge seg may be a shared huge seg which was allocated
+ // by another process. Sync with the huge seg info which is
+ // kept in the server
+ //
+ a->BaseAddress = SELTOFLAT(sel);
+ Od2CallSubsystem( &m, NULL, Oi2QueryVirtualMemory, sizeof( *a ));
+ if (a->SharedMemory && a->IsHuge) {
+ pHuge = RtlAllocateHeap( Od2Heap, 0, sizeof( HUGE_SEG_RECORD) );
+ if (pHuge == NULL) {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ pHuge->Next = (struct HUGE_SEG_RECORD *)pHugeSegHead;
+ pHuge->MaxNumSeg = a->MaxSegments;
+ pHuge->BaseSelector = sel;
+ pHuge->cNumSeg = a->NumOfSegments;
+ pHuge->PartialSeg = a->SizeOfPartialSeg;
+ pHuge->fShared = TRUE;
+ pHuge->fSizeable = a->Sizeable;
+
+ pHugeSegHead = pHuge;
+ }
+ else {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: selector is not a base of HugeSeg\n");
+ }
+#endif
+ ReleaseTaskLock();
+ return(ERROR_INVALID_PARAMETER);
+ }
+ }
+
+ //
+ // found! validate that size is within limits, then
+ // alloc or free accordingly
+ //
+ if (((ULONG)cSegs > pHuge->MaxNumSeg) ||
+ (((ULONG)cSegs == pHuge->MaxNumSeg) && (cbPartialSeg != 0))
+ ) {
+ ReleaseTaskLock();
+ return(ERROR_INVALID_PARAMETER);
+ }
+ //
+ // Verify, for shared segments that are reduced in size that the
+ // SEG_SIZEABLE flag is set.
+ //
+ if (pHuge->fShared
+ &&
+ (((ULONG)cSegs < pHuge->cNumSeg) ||
+ (((ULONG)cSegs == pHuge->cNumSeg) && (cbPartialSeg < pHuge->PartialSeg))
+ )
+ &&
+ !pHuge->fSizeable
+ ) {
+ ReleaseTaskLock();
+ return(ERROR_ACCESS_DENIED);
+ }
+
+ //
+ // If the huge segment is a shared segment, pass the work to the server
+ //
+ if (pHuge->fShared) {
+ b->BaseAddress = SELTOFLAT(sel);
+ b->NumOfSegments = cSegs;
+ b->SizeOfPartialSeg = cbPartialSeg;
+ rc = Od2CallSubsystem( &m, NULL, Oi2ReallocSharedHuge, sizeof( *a ));
+ if (rc == NO_ERROR) {
+ pHuge->cNumSeg = cSegs;
+ pHuge->PartialSeg = cbPartialSeg;
+ }
+ ReleaseTaskLock();
+ return(rc);
+ }
+
+ if (pHuge->PartialSeg != 0) {
+ Op |= H_CUR_PARTIAL;
+ }
+ if (cbPartialSeg != 0) {
+ Op |= H_NEW_PARTIAL;
+ }
+ if ((ULONG)(cSegs) > pHuge->cNumSeg) {
+ Op |= H_SEG_INC;
+ }
+ else if ((ULONG)(cSegs) < pHuge->cNumSeg) {
+ Op |= H_SEG_DEC;
+ }
+
+ switch (Op) {
+ case H_SAME_SEG_NO_PARTIAL:
+
+ ReleaseTaskLock();
+ break;
+
+ case H_SAME_SEG_NEW_PARTIAL:
+
+ Sel = sel + (SEL)(8*cSegs);
+ BaseAddress = SELTOFLAT(Sel);
+ rc = DosSetMem(BaseAddress, cbPartialSeg,
+ (fPERM + PAG_COMMIT - PAG_GUARD));
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ ReleaseTaskLock();
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ pHuge->PartialSeg = cbPartialSeg;
+ ReleaseTaskLock();
+ //
+ // Set LDT entry
+ //
+ Desc.Limit = cbPartialSeg - 1;
+ Desc.Type = READ_WRITE_DATA;
+ Desc.BaseAddress = (ULONG)BaseAddress;
+ Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ break;
+
+ case H_SAME_SEG_DEL_PARTIAL:
+
+ Sel = sel + (SEL)(8*cSegs);
+ BaseAddress = SELTOFLAT(Sel);
+ rc = DosSizeSeg(Sel, &SegSize);
+ if (rc != NO_ERROR){
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't DosGetSize, rc=%d\n", rc);
+ }
+#endif
+ ReleaseTaskLock();
+ return (ERROR_INVALID_PARAMETER);
+ }
+ rc = DosSetMem(BaseAddress, SegSize, PAG_DECOMMIT);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't Decommit, rc=%d\n", rc);
+ }
+#endif
+ ReleaseTaskLock();
+ return(ERROR_INVALID_PARAMETER);
+ }
+ pHuge->PartialSeg = 0;
+ ReleaseTaskLock();
+ //
+ // Set LDT entry
+ //
+ Desc.Type = INVALID;
+ Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ break;
+
+ case H_SAME_SEG_CHG_PARTIAL:
+
+ Sel = sel + (SEL)(8*cSegs);
+ rc = DosReallocSeg(cbPartialSeg, Sel);
+ if (rc == NO_ERROR) {
+ pHuge->PartialSeg = cbPartialSeg;
+ }
+ ReleaseTaskLock();
+ return(rc);
+
+ case H_INC_SEG_NO_PARTIAL:
+
+ Sel = sel + (SEL)(8*pHuge->cNumSeg);
+ BaseAddress = SELTOFLAT(Sel);
+ cNewSegs = cSegs - pHuge->cNumSeg;
+ CommitSize = cNewSegs * _64K;
+ rc = DosSetMem(BaseAddress, CommitSize,
+ fPERM + PAG_COMMIT - PAG_GUARD);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ ReleaseTaskLock();
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ pHuge->cNumSeg = cSegs;
+ ReleaseTaskLock();
+ Desc.Limit = _64K - 1;
+ Desc.Type = READ_WRITE_DATA;
+ Desc.BaseAddress = (ULONG)BaseAddress;
+ for (i = 0; i < cNewSegs; i++, Sel += 8, Desc.BaseAddress += _64K) {
+ Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ }
+ break;
+
+ case H_INC_SEG_NEW_PARTIAL:
+
+ Sel = sel + (SEL)(8*pHuge->cNumSeg);
+ BaseAddress = SELTOFLAT(Sel);
+ cNewSegs = cSegs - pHuge->cNumSeg;
+ CommitSize = (cNewSegs * _64K) + cbPartialSeg;
+ rc = DosSetMem(BaseAddress, CommitSize,
+ fPERM + PAG_COMMIT - PAG_GUARD);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ ReleaseTaskLock();
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ pHuge->cNumSeg = cSegs;
+ pHuge->PartialSeg = cbPartialSeg;
+ ReleaseTaskLock();
+ Desc.Limit = _64K - 1;
+ Desc.Type = READ_WRITE_DATA;
+ Desc.BaseAddress = (ULONG)BaseAddress;
+ for (i = 0; i < cNewSegs; i++, Sel += 8, Desc.BaseAddress += _64K) {
+ Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ }
+ Desc.Limit = cbPartialSeg - 1;
+ Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ break;
+
+ case H_INC_SEG_DEL_PARTIAL:
+
+ Sel = sel + (SEL)(8*pHuge->cNumSeg);
+ rc = DosReallocSeg(0, Sel);
+ if (rc != NO_ERROR){
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't DosReallocSeg, rc=%d\n", rc);
+ }
+#endif
+ ReleaseTaskLock();
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ }
+ cNewSegs = cSegs - (pHuge->cNumSeg + 1);
+ if (cNewSegs == 0) {
+ pHuge->cNumSeg += 1;
+ pHuge->PartialSeg = 0;
+ ReleaseTaskLock();
+ return(NO_ERROR);
+ }
+ Sel += 8;
+ BaseAddress = SELTOFLAT(Sel);
+ CommitSize = cNewSegs * _64K;
+ rc = DosSetMem(BaseAddress, CommitSize,
+ fPERM + PAG_COMMIT - PAG_GUARD);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ pHuge->cNumSeg += 1;
+ pHuge->PartialSeg = 0;
+ ReleaseTaskLock();
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ pHuge->cNumSeg = cSegs;
+ pHuge->PartialSeg = 0;
+ ReleaseTaskLock();
+ Desc.Limit = _64K - 1;
+ Desc.Type = READ_WRITE_DATA;
+ Desc.BaseAddress = (ULONG)BaseAddress;
+ for (i = 0; i < cNewSegs; i++, Sel += 8, Desc.BaseAddress += _64K) {
+ Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ }
+ break;
+
+ case H_INC_SEG_CHG_PARTIAL:
+
+ Sel = sel + (SEL)(8*pHuge->cNumSeg);
+ rc = DosReallocSeg(0, Sel);
+ if (rc != NO_ERROR){
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't DosReallocSeg, rc=%d\n", rc);
+ }
+#endif
+ ReleaseTaskLock();
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ }
+ cNewSegs = cSegs - (pHuge->cNumSeg + 1);
+ Sel += 8;
+ BaseAddress = SELTOFLAT(Sel);
+ CommitSize = (cNewSegs * _64K) + cbPartialSeg;
+ rc = DosSetMem(BaseAddress, CommitSize,
+ fPERM + PAG_COMMIT - PAG_GUARD);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ pHuge->cNumSeg += 1;
+ pHuge->PartialSeg = 0;
+ ReleaseTaskLock();
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ pHuge->cNumSeg = cSegs;
+ pHuge->PartialSeg = cbPartialSeg;
+ ReleaseTaskLock();
+ Desc.Limit = _64K - 1;
+ Desc.Type = READ_WRITE_DATA;
+ Desc.BaseAddress = (ULONG)BaseAddress;
+ for (i = 0; i < cNewSegs; i++, Sel += 8, Desc.BaseAddress += _64K) {
+ Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ }
+ //
+ // Set LDT entry for the partial seg
+ //
+ Desc.Limit = cbPartialSeg - 1;
+ Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ break;
+
+ case H_DEC_SEG_NO_PARTIAL:
+
+ Sel = sel + (SEL)(8*cSegs);
+ BaseAddress = SELTOFLAT(Sel);
+ cDelSegs = pHuge->cNumSeg - cSegs;
+ DecommitSize = cDelSegs * _64K;
+ rc = DosSetMem(BaseAddress, DecommitSize, PAG_DECOMMIT);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ ReleaseTaskLock();
+ return(ERROR_INVALID_PARAMETER);
+ }
+ pHuge->cNumSeg = cSegs;
+ ReleaseTaskLock();
+ Desc.Type = INVALID;
+ for (i = 0; i < cDelSegs; i++, Sel += 8) {
+ Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ }
+ break;
+
+ case H_DEC_SEG_NEW_PARTIAL:
+
+ Sel = sel + (SEL)(8*(cSegs + 1));
+ BaseAddress = SELTOFLAT(Sel);
+ cDelSegs = pHuge->cNumSeg - (cSegs + 1);
+ if (cDelSegs != 0) {
+ DecommitSize = cDelSegs * _64K;
+ rc = DosSetMem(BaseAddress, DecommitSize, PAG_DECOMMIT);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't Decommit, rc=%d\n", rc);
+ }
+#endif
+ ReleaseTaskLock();
+ return(ERROR_INVALID_PARAMETER);
+ }
+ Desc.Type = INVALID;
+ for (i = 0; i < cDelSegs; i++, Sel += 8) {
+ Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ }
+ }
+ Sel = sel + (SEL)(8*cSegs);
+ rc = DosReallocSeg(cbPartialSeg, Sel);
+ if (rc != NO_ERROR) {
+ pHuge->cNumSeg = cSegs + 1;
+ pHuge->PartialSeg = 0;
+ ReleaseTaskLock();
+ return(ERROR_INVALID_PARAMETER);
+ }
+ pHuge->cNumSeg = cSegs;
+ pHuge->PartialSeg = cbPartialSeg;
+ ReleaseTaskLock();
+ break;
+
+ case H_DEC_SEG_DEL_PARTIAL:
+
+ Sel = sel + (SEL)(8*cSegs);
+ BaseAddress = SELTOFLAT(Sel);
+ cDelSegs = pHuge->cNumSeg - cSegs;
+ rc = DosSizeSeg((SEL)(sel + (SEL)(8*pHuge->cNumSeg)), &SegSize);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't DosGetSize, rc=%d\n", rc);
+ }
+#endif
+ ReleaseTaskLock();
+ return(ERROR_INVALID_PARAMETER);
+ }
+ DecommitSize = (cDelSegs * _64K) + SegSize;
+ rc = DosSetMem(BaseAddress, DecommitSize, PAG_DECOMMIT);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't Decommit, rc=%d\n", rc);
+ }
+#endif
+ ReleaseTaskLock();
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ pHuge->cNumSeg = cSegs;
+ pHuge->PartialSeg = 0;
+ ReleaseTaskLock();
+ Desc.Type = INVALID;
+ for (i = 0; i <= cDelSegs; i++, Sel += 8) {
+ Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ }
+ break;
+
+ case H_DEC_SEG_CHG_PARTIAL:
+
+ Sel = sel + (SEL)(8*(cSegs + 1));
+ BaseAddress = SELTOFLAT(Sel);
+ cDelSegs = pHuge->cNumSeg - (cSegs + 1);
+ rc = DosSizeSeg((SEL)(sel + (SEL)(8*pHuge->cNumSeg)), &SegSize);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't DosGetSize, rc=%d\n", rc);
+ }
+#endif
+ ReleaseTaskLock();
+ return(ERROR_INVALID_PARAMETER);
+ }
+ DecommitSize = (cDelSegs * _64K) + SegSize;
+ rc = DosSetMem(BaseAddress, DecommitSize, PAG_DECOMMIT);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't Decommit, rc=%d\n", rc);
+ }
+#endif
+ ReleaseTaskLock();
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ Desc.Type = INVALID;
+ for (i = 0; i <= cDelSegs; i++, Sel += 8) {
+ Status = Nt386SetDescriptorLDT (NULL, Sel, Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ }
+ Sel = sel + (SEL)(8*cSegs);
+ rc = DosReallocSeg(cbPartialSeg, Sel);
+ if (rc != NO_ERROR){
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosReallocHuge: Can't DosReallocSeg, rc=%d\n", rc);
+ }
+#endif
+ pHuge->cNumSeg = cSegs + 1;
+ pHuge->PartialSeg = 0;
+ ReleaseTaskLock();
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ }
+ pHuge->cNumSeg = cSegs;
+ pHuge->PartialSeg = cbPartialSeg;
+ ReleaseTaskLock();
+ break;
+ }
+ return(NO_ERROR);
+}
+
+
+APIRET
+DosGetHugeShift(
+ OUT PUSHORT pusShiftCount
+ )
+{
+ try {
+ *pusShiftCount = 3;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ return (NO_ERROR);
+}
+
+
+APIRET
+DosAllocShrSeg(
+ IN USHORT cbSize,
+ IN PSZ pszSegName,
+ OUT PSEL pSel
+ )
+{
+ PVOID BaseAddress;
+ APIRET rc;
+ ULONG Size, flags;
+
+ //
+ // probe pSel pointer.
+ //
+
+ try {
+ *pSel = 0;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // OS2 1.X treats a 0 size request as (64k -1)
+ //
+
+ if (cbSize == 0)
+ Size = _64K;
+ else
+ Size = cbSize;
+
+ //
+ // First we reserve 64K, then we commit the size
+ // requested, rounded up to page granularity, by DosSetMem.
+ //
+
+ //
+ // we make it givable and gettable
+ // (see DosAllocSharedMem).
+ //
+
+ flags = fALLOCSHR - (PAG_GUARD | OBJ_GETTABLE | OBJ_GIVEABLE);
+ if (pszSegName == NULL)
+ {
+ flags |= (OBJ_GETTABLE | OBJ_GIVEABLE);
+ }
+ rc = DosAllocSharedMem(
+ &BaseAddress,
+ pszSegName,
+ Size,
+ (flags - (PAG_COMMIT | PAG_EXECUTE)),
+ TRUE // Create LDT entry
+ );
+
+ if (rc != NO_ERROR) {
+ if (rc == ERROR_DISK_FULL)
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ return (rc);
+ }
+
+ rc = DosSetMem(
+ BaseAddress,
+ Size,
+ (flags - PAG_EXECUTE));
+
+ if (rc != NO_ERROR){
+ BOOLEAN RemoveLDTEntry = TRUE;
+ DosFreeMem (BaseAddress, &RemoveLDTEntry);
+ if (rc == ERROR_DISK_FULL)
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ return (rc);
+ }
+
+ *pSel = FLATTOSEL(BaseAddress);
+
+#if DBG
+ if ((Os2DebugSel != 0) && (*pSel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosAllocShrSeg returning sel=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ *pSel);
+ }
+#endif
+ return (NO_ERROR);
+}
+
+#if PMNT
+
+// Lotus Notes 3.0 patch for $lib.dll
+
+#include <stdio.h>
+
+#pragma pack(1)
+
+APIRET
+DosQueryModuleHandleNE(
+ IN PSZ pszModName,
+ OUT PUSHORT phMod
+ );
+
+APIRET
+DosGetProcAddrNE(
+ IN ULONG hMod,
+ IN PSZ pszProcName,
+ OUT PULONG pProcAddr
+ );
+
+APIRET
+DosSemRequest(
+ IN HSEM hsem,
+ IN LONG lTimeOut
+ );
+
+APIRET
+DosSemClear(
+ IN HSEM hsem
+ );
+
+typedef struct _od2_context16 {
+ USHORT junk;
+ USHORT rSS;
+ USHORT rBP;
+ USHORT rDX;
+ USHORT rBX;
+ USHORT rCX;
+ USHORT rSI;
+ USHORT rDI;
+ USHORT rES;
+ USHORT rDS;
+ USHORT rIP;
+ USHORT rCS;
+} OD2_CONTEXT16, *POD2_CONTEXT16;
+
+typedef struct _lnotes_descriptor {
+ UCHAR junk1[10];
+ USHORT selector;
+ UCHAR junk2[16];
+ SHORT usage;
+ ULONG semaphore;
+} LNOTES_DESCRIPTOR, *PLNOTES_DESCRIPTOR;
+
+BOOLEAN LNotesPatchEnabled = TRUE;
+BOOLEAN LNotesPatchChecked = FALSE;
+ULONG LNotesPatchCodeSegment;
+
+PLNOTES_DESCRIPTOR LNotesPatchCheck(POD2_CONTEXT16 pContext)
+{
+ ULONG hMod;
+ ULONG pOSMEMALLOC;
+ PUSHORT pDescriptorSegment;
+ PLNOTES_DESCRIPTOR pDescriptor;
+ FILE *file;
+ APIRET rc;
+
+ if (!LNotesPatchEnabled) return FALSE;
+ if (!LNotesPatchChecked) {
+ LNotesPatchChecked = TRUE;
+ if (rc = DosQueryModuleHandleNE("$LIB", (PUSHORT) &hMod)) {
+//#if DBG
+// DbgPrint("[%d] This is not Lotus Notes process (rc=%d)\n",
+// Od2Process->Pib.ProcessId, rc);
+//#endif // DBG
+ LNotesPatchEnabled = FALSE;
+ return NULL;
+ }
+#if DBG
+ DbgPrint("[%d] This process belongs to Lotus Notes\n",
+ Od2Process->Pib.ProcessId);
+#endif // DBG
+ file = fopen("c:\\os2\\pmnt.pth", "r");
+ if (file == NULL) {
+ file = fopen("c:\\os2\\pmnt.pth", "w");
+ }
+ else
+ {
+ fclose(file);
+ file = NULL;
+ }
+ if (rc = DosGetProcAddrNE(hMod, "OSMEMALLOC", &pOSMEMALLOC)) {
+#if DBG
+ DbgPrint("[%d] Lotus Notes patch. OSMEMALLOC doesn't exist (rc=%d)\n",
+ Od2Process->Pib.ProcessId, rc);
+#endif // DBG
+ if (file) {
+ fprintf(file, "[%d] Lotus Notes patch. OSMEMALLOC doesn't exist (rc=%d)\n",
+ Od2Process->Pib.ProcessId, rc);
+ fclose(file);
+ }
+ LNotesPatchEnabled = FALSE;
+ return NULL;
+ }
+ if ((pOSMEMALLOC & 0xFFFF) != 0x6C0) {
+#if DBG
+ DbgPrint("[%d] Lotus Notes patch. OSMEMALLOC offset = %x\n",
+ Od2Process->Pib.ProcessId, pOSMEMALLOC & 0xFFFF);
+#endif // DBG
+ if (file) {
+ fprintf(file, "[%d] Lotus Notes patch. OSMEMALLOC offset = %x\n",
+ Od2Process->Pib.ProcessId, pOSMEMALLOC & 0xFFFF);
+ fclose(file);
+ }
+ LNotesPatchEnabled = FALSE;
+ return NULL;
+ }
+ LNotesPatchCodeSegment = ((pOSMEMALLOC & 0xFFFF0000) >> 16);
+ }
+
+ if ((ULONG)(pContext->rCS) != LNotesPatchCodeSegment) {
+#if DBG
+ DbgPrint("[%d,%d] Lotus Notes patch from %04x:%04X. OSMEMALLOC segment = %04X\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ pContext->rCS,
+ pContext->rIP,
+ (pOSMEMALLOC & 0xFFFF) >> 16);
+#endif // DBG
+ return NULL;
+ }
+
+ if (pContext->rIP == 0x33E ||
+ pContext->rIP == 0x3DD ||
+ pContext->rIP == 0x37E) {
+
+ pDescriptorSegment = (PUSHORT)
+ ((PUCHAR)SELTOFLAT(pContext->rSS) + pContext->rBP - 6);
+ pDescriptor = (PLNOTES_DESCRIPTOR)
+ ((PUCHAR)SELTOFLAT(*pDescriptorSegment) + pContext->rSI);
+
+ return pDescriptor;
+ }
+ return NULL;
+}
+
+void LNotesPatchLock(POD2_CONTEXT16 pContext)
+{
+ PLNOTES_DESCRIPTOR pDescriptor;
+
+ if (pDescriptor = LNotesPatchCheck(pContext)) {
+ pDescriptor->usage++;
+ if (pDescriptor->usage > 0) {
+ DosSemRequest(&(pDescriptor->semaphore), -1L);
+#if DBG
+ DbgPrint("[%d,%d] LNotes lock from %04x:%04x sel=%x sem=%d:%08x at %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ pContext->rCS,
+ pContext->rIP,
+ pDescriptor->selector,
+ pDescriptor->usage,
+ pDescriptor->semaphore,
+ &(pDescriptor->semaphore));
+#endif // DBG
+ }
+ }
+}
+
+void LNotesPatchUnlock(POD2_CONTEXT16 pContext)
+{
+ PLNOTES_DESCRIPTOR pDescriptor;
+
+ if (pDescriptor = LNotesPatchCheck(pContext)) {
+ pDescriptor->usage--;
+ if (pDescriptor->usage >= 0) {
+ DosSemClear(&(pDescriptor->semaphore));
+#if DBG
+ DbgPrint("[%d,%d] LNotes unlock from %04x:%04x sel=%x sem=%d:%x at %x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ pContext->rCS,
+ pContext->rIP,
+ pDescriptor->selector,
+ pDescriptor->usage,
+ pDescriptor->semaphore,
+ &(pDescriptor->semaphore));
+#endif // DBG
+ }
+ }
+}
+
+#pragma pack()
+
+#endif // PMNT
+
+APIRET
+#if PMNT
+PMNT_DosLockSeg(
+#else
+DosLockSeg(
+#endif // PMNT
+ IN SEL sel
+ )
+{
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosLockSeg called on sel=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel);
+ }
+#endif
+
+ if (!IsLegalSelector(sel)){
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosLockSeg called on sel=%x, returning ACCES_DENIED\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel);
+ }
+#endif
+ return( ERROR_ACCESS_DENIED );
+ }
+ return (NO_ERROR);
+}
+
+APIRET
+#if PMNT
+PMNT_DosUnlockSeg(
+#else
+DosUnlockSeg(
+#endif // PMNT
+ IN SEL sel
+ )
+{
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosUnlockSeg called on sel=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel);
+ }
+#endif
+
+ if (!IsLegalSelector(sel)){
+#if DBG
+ if ((Os2DebugSel != 0) && (sel == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosUnlockSeg called on sel=%x, returning ACCES_DENIED\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ sel);
+ }
+#endif
+ return( ERROR_ACCESS_DENIED );
+ }
+
+ return (NO_ERROR);
+}
+
+APIRET
+DosGetShrSeg(
+ IN PSZ pszSegName,
+ OUT PSEL pSel
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSGETSHRSEG_MSG a = &m.u.DosGetShrSeg;
+ APIRET rc;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ //
+ // probe pSel pointer.
+ //
+ try {
+ *pSel = 0;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ rc = Od2CaptureObjectName( pszSegName,
+ CANONICALIZE_SHARED_MEMORY,
+ 0,
+ &CaptureBuffer,
+ &a->ObjectName
+ );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+ Od2CallSubsystem( &m, CaptureBuffer, Os2GetShrSeg, sizeof( *a ) );
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ if (m.ReturnedErrorValue == NO_ERROR) {
+ *pSel = (SEL)(a->Selector);
+ }
+ return( m.ReturnedErrorValue );
+}
+
+
+APIRET
+DosMemAvail(
+ OUT PULONG pcbFree
+ )
+{
+ try {
+ *pcbFree = 64512;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+#if DBG
+ DbgPrint ("DosMemAvail: Returning bogus value\n");
+#endif
+ return (NO_ERROR);
+}
+
+APIRET
+DosCreateCSAlias(
+ IN SEL selDS,
+ OUT PSEL pselCS
+ )
+{
+ NTSTATUS Status;
+ PVOID BaseAddress;
+ APIRET rc = NO_ERROR;
+ ULONG usSize;
+ I386DESCRIPTOR dsDesc,csDesc;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE SectionHandle;
+ ULONG AllocationAttributes;
+ LARGE_INTEGER SectionSize;
+ ULONG RegionSize = 0;
+ POS21X_CS pCS;
+ POS21X_CSALIAS pCSAlias;
+ BOOLEAN SectionExists = FALSE;
+ MEMORY_BASIC_INFORMATION MemoryBasicInfo;
+ ULONG ReturnedLength;
+ ULONG Index;
+
+ //
+ // We have a problem with tiling, so we need to make the
+ // CS memory area and the data memory area mapped to
+ // each other.
+ //
+ // What we do for CSAlias is:
+ // - Create a section object.
+ // - Map the section and make the map out CS area
+ // - WriteVirtualMemory from datasegment to codesegment
+ // - Free DataSeg
+ // - MapView the code area back into the data area
+ // - get a selctor for the code area
+ //
+
+ try {
+ *pselCS = 0;
+ }
+
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+#if DBG
+ if ((Os2DebugSel != 0) && (selDS == Os2DebugSel))
+ {
+ DbgPrint("[%x,%x] DosCreateCsAlias DS sel=%x\n",
+ Od2Process->Pib.ProcessId,
+ Od2CurrentThreadId(),
+ selDS);
+ }
+#endif
+
+ //
+ // Query the size of the Data Segment
+ //
+ Status = Nt386GetDescriptorLDT (
+ NULL,
+ selDS,
+ &dsDesc);
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint ("DosCreateCSAlias fails to get descriptor info\n");
+#endif
+ return( ERROR_INVALID_PARAMETER );
+ }
+ usSize = dsDesc.Limit+1;
+
+ InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
+
+ AllocationAttributes = SEC_RESERVE;
+
+ //
+ // Lookup if this DS was already aliased before
+ // Leave task Locked if not, then alias and free lock
+ //
+ AcquireTaskLock();
+ if (Od2CSAliasListHead != 0) {
+ for (pCSAlias = (POS21X_CSALIAS) Od2CSAliasListHead;
+ pCSAlias != NULL;
+ pCSAlias = (POS21X_CSALIAS) (pCSAlias->Next)) {
+ if (pCSAlias->selDS == selDS) {
+ SectionHandle = pCSAlias->SectionHandle;
+ SectionExists = TRUE;
+ break;
+ }
+ }
+ }
+ //
+ // The task is locked (see above)
+ // this is to prevent races
+ // with two threads doing CSAlias the
+ // same time.
+ //
+
+ if (!(SectionExists)) {
+
+ //
+ // We need to reserve 64K, then commit usSize
+ //
+ SectionSize.LowPart = _64K;
+ SectionSize.HighPart = 0;
+ Status = NtCreateSection( &SectionHandle,
+ SECTION_ALL_ACCESS,
+ &ObjectAttributes,
+ &SectionSize,
+ PAGE_EXECUTE_READWRITE,
+ AllocationAttributes,
+ NULL
+ );
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint ("DosCreateCSAlias fails to CreateSection\n");
+#endif
+ ReleaseTaskLock();
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ }
+ Index = ((ULONG)Od2MemoryAllocationBase - BASE_TILE) / _64K;
+ Index = ldtAllocateSelectors(
+ 1, // NumberOfSel
+ Index // StartOfMark
+ );
+
+ if (Index == 0xffffffff){
+ //
+ // not found - no memory
+ //
+ Od2MemoryAllocationBase = (PVOID)(BASE_TILE + _64K);
+ if (!SectionExists) {
+ NtClose (SectionHandle);
+ }
+ ReleaseTaskLock();
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ Od2MemoryAllocationBase = BaseAddress = (PVOID)((Index * _64K) + BASE_TILE);
+
+ Status = NtMapViewOfSection( SectionHandle,
+ NtCurrentProcess(),
+ &BaseAddress,
+ BASE_TILE_ZERO_BITS,
+ usSize,
+ NULL,
+ &RegionSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE
+ );
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint ("DosCreateCSAlias fails to MapViewSection to CS\n Error: %x\n", Status);
+#endif
+ if (!SectionExists) {
+ NtClose (SectionHandle);
+ }
+ ReleaseTaskLock();
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ csDesc.BaseAddress = (ULONG) BaseAddress;
+ csDesc.Limit = usSize-1;
+ csDesc.Type = EXECUTE_READ_CODE;
+ *pselCS = FLATTOSEL(csDesc.BaseAddress);
+
+ Status = Nt386SetDescriptorLDT (
+ NULL,
+ *pselCS,
+ csDesc);
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint ("DosCSAlias fails to set CS descriptor\n");
+#endif
+ *pselCS = 0;
+ if (!SectionExists) {
+ NtUnmapViewOfSection(NtCurrentProcess(),
+ (PVOID)csDesc.BaseAddress
+ );
+ NtClose (SectionHandle);
+ }
+ ReleaseTaskLock();
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ if (SectionExists) {
+ pCS = (POS21X_CS) RtlAllocateHeap(Od2Heap, 0, sizeof(OS21X_CS));
+ if (!pCS){
+ #if DBG
+ DbgPrint ("DosCreateCSAlias fails to allocate from heap OS21X_CS\n",
+ Status);
+ #endif
+ csDesc.Type = INVALID;
+ Nt386SetDescriptorLDT (
+ NULL,
+ *pselCS,
+ csDesc);
+ NtUnmapViewOfSection(NtCurrentProcess(),
+ (PVOID)csDesc.BaseAddress
+ );
+ ReleaseTaskLock();
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ //
+ // link the new CS into the CSList of the CSAlias Section
+ //
+ pCS->Next = (struct OS21X_CS *)(pCSAlias->pCSList);
+ pCSAlias->pCSList = (POS21X_CS) pCS;
+ pCS->selCS = *pselCS;
+ ReleaseTaskLock();
+ return(NO_ERROR);
+ }
+
+ //
+ // Copy the data into the code segment
+ //
+ try {
+ RtlCopyMemory (
+ (PUCHAR)(csDesc.BaseAddress),
+ (PUCHAR)(dsDesc.BaseAddress),
+ usSize);
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+#if DBG
+ DbgPrint ("Exception in DosCSAlias, RtlMoveMemory\n");
+#endif
+
+ csDesc.Type = INVALID;
+ Nt386SetDescriptorLDT (
+ NULL,
+ *pselCS,
+ csDesc);
+ NtUnmapViewOfSection(NtCurrentProcess(),
+ (PVOID)csDesc.BaseAddress
+ );
+ NtClose (SectionHandle);
+ ReleaseTaskLock();
+ Od2ExitGP();
+ }
+
+ //
+ // Check the type of the aliased data segment.
+ // If it was a private segment then do NtFreeVirtualMemory()
+ // If it was a shared segment then do NtUnmapVieOfSection
+ //
+
+ Status = NtQueryVirtualMemory( NtCurrentProcess(),
+ (PVOID)dsDesc.BaseAddress,
+ MemoryBasicInformation,
+ &MemoryBasicInfo,
+ sizeof(MEMORY_BASIC_INFORMATION),
+ &ReturnedLength
+ );
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint ("DosCSAlias fails to NtQueryVirtualMemory(), Status %lx\n", Status);
+#endif
+ ASSERT(NT_SUCCESS(Status));
+ csDesc.Type = INVALID;
+ Nt386SetDescriptorLDT (
+ NULL,
+ *pselCS,
+ csDesc);
+ NtUnmapViewOfSection(NtCurrentProcess(),
+ (PVOID)csDesc.BaseAddress
+ );
+ NtClose (SectionHandle);
+ ReleaseTaskLock();
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+#if 0
+ DbgPrint("*** Mem=%x\n"
+ "*** ReturnedLength=%x, sizeof=%x\n"
+ "*** BaesAddr=%x, AllocationBase=%x\n"
+ "*** AllocProtect = %lx, RegionSize=%x, State=%x, Protect = %lx\n",
+ dsDesc.BaseAddress,
+ ReturnedLength, sizeof(MEMORY_BASIC_INFORMATION),
+ MemoryBasicInfo.BaseAddress, MemoryBasicInfo.AllocationBase,
+ MemoryBasicInfo.AllocationProtect, MemoryBasicInfo.RegionSize,
+ MemoryBasicInfo.State, MemoryBasicInfo.Protect);
+#endif
+
+ if ((MemoryBasicInfo.Type & MEM_PRIVATE) != 0) {
+ //
+ // Now Free the data segment and
+ // MapView it from the new section
+ //
+ BaseAddress = (PVOID)(dsDesc.BaseAddress);
+ RegionSize = 0;
+ Status = NtFreeVirtualMemory( NtCurrentProcess(),
+ &BaseAddress,
+ &RegionSize,
+ MEM_RELEASE
+ );
+#if DBG
+ if (!NT_SUCCESS( Status )) {
+ DbgPrint ("DosCSAlias fails to NtFreeVirtualMemory, Status %lx\n", Status);
+ }
+#endif
+ }
+ else if ((MemoryBasicInfo.Type & MEM_MAPPED) != 0) {
+ if ((MemoryBasicInfo.AllocationProtect & PAGE_EXECUTE_WRITECOPY) != 0) {
+ //
+ // This is a data segment mapped by the loader but it is not global
+ //
+ Status = NtUnmapViewOfSection( NtCurrentProcess(),
+ (PVOID)dsDesc.BaseAddress
+ );
+#if DBG
+ if (!NT_SUCCESS( Status )) {
+ DbgPrint ("DosCSAlias fails to NtUnmapViewOfSection, Status %lx\n", Status);
+ }
+#endif
+ }
+ else {
+#if DBG
+ DbgPrint ("DosCSAlias: Trying to alias Shared memory\n");
+#endif
+ csDesc.Type = INVALID;
+ Nt386SetDescriptorLDT (
+ NULL,
+ *pselCS,
+ csDesc);
+ NtUnmapViewOfSection(NtCurrentProcess(),
+ (PVOID)csDesc.BaseAddress
+ );
+ NtClose (SectionHandle);
+ ReleaseTaskLock();
+ return( ERROR_ACCESS_DENIED );
+ }
+ }
+ else {
+#if DBG
+ DbgPrint ("DosCSAlias: Illegal type of aliased data, Status %lx\n", Status);
+#endif
+ csDesc.Type = INVALID;
+ Nt386SetDescriptorLDT (
+ NULL,
+ *pselCS,
+ csDesc);
+ NtUnmapViewOfSection(NtCurrentProcess(),
+ (PVOID)csDesc.BaseAddress
+ );
+ NtClose (SectionHandle);
+ ReleaseTaskLock();
+ return( ERROR_ACCESS_DENIED );
+ }
+
+ if (!NT_SUCCESS( Status )) {
+ ASSERT(NT_SUCCESS(Status));
+ csDesc.Type = INVALID;
+ Nt386SetDescriptorLDT (
+ NULL,
+ *pselCS,
+ csDesc);
+ NtUnmapViewOfSection(NtCurrentProcess(),
+ (PVOID)csDesc.BaseAddress
+ );
+ NtClose (SectionHandle);
+ ReleaseTaskLock();
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ RegionSize = 0;
+ Status = NtMapViewOfSection( SectionHandle,
+ NtCurrentProcess(),
+ &(PVOID)(dsDesc.BaseAddress),
+ BASE_TILE_ZERO_BITS,
+ usSize,
+ NULL,
+ &RegionSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE
+ );
+
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint ("DosCreateCSAlias fails at MapViewSection DS\n Error: %x\n",
+ Status);
+#endif
+ dsDesc.Type = INVALID;
+ Nt386SetDescriptorLDT (
+ NULL,
+ selDS,
+ dsDesc);
+ csDesc.Type = INVALID;
+ Nt386SetDescriptorLDT (
+ NULL,
+ *pselCS,
+ csDesc);
+ NtUnmapViewOfSection(NtCurrentProcess(),
+ (PVOID)csDesc.BaseAddress
+ );
+ NtClose (SectionHandle);
+ ReleaseTaskLock();
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ pCS = (POS21X_CS) RtlAllocateHeap(Od2Heap, 0, sizeof(OS21X_CS));
+ if (!pCS){
+#if DBG
+ DbgPrint ("DosCreateCSAlias fails to allocate from heap OS21X_CS\n",
+ Status);
+#endif
+ dsDesc.Type = INVALID;
+ Nt386SetDescriptorLDT (
+ NULL,
+ selDS,
+ dsDesc);
+ csDesc.Type = INVALID;
+ Nt386SetDescriptorLDT (
+ NULL,
+ *pselCS,
+ csDesc);
+ NtUnmapViewOfSection(NtCurrentProcess(),
+ (PVOID)csDesc.BaseAddress
+ );
+ NtUnmapViewOfSection(NtCurrentProcess(),
+ (PVOID)dsDesc.BaseAddress
+ );
+ NtClose (SectionHandle);
+ ReleaseTaskLock();
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ pCSAlias = (POS21X_CSALIAS) RtlAllocateHeap(Od2Heap, 0, sizeof(OS21X_CSALIAS));
+ if (!pCSAlias){
+#if DBG
+ DbgPrint ("DosCreateCSAlias fails to allocate from heap OS21X_CSAlias\n",
+ Status);
+#endif
+ dsDesc.Type = INVALID;
+ Nt386SetDescriptorLDT (
+ NULL,
+ selDS,
+ dsDesc);
+ csDesc.Type = INVALID;
+ Nt386SetDescriptorLDT (
+ NULL,
+ *pselCS,
+ csDesc);
+ NtUnmapViewOfSection(NtCurrentProcess(),
+ (PVOID)csDesc.BaseAddress
+ );
+ NtUnmapViewOfSection(NtCurrentProcess(),
+ (PVOID)dsDesc.BaseAddress
+ );
+ RtlFreeHeap(Od2Heap, 0,pCS);
+
+ NtClose (SectionHandle);
+ ReleaseTaskLock();
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ //
+ // link the new CS into the CSList of the CSAlias Section
+ //
+ pCS->Next = NULL;
+ pCS->selCS = *pselCS;
+ pCSAlias->pCSList = pCS;
+ //
+ // Set rest of the fields
+ //
+ pCSAlias->selDS = selDS;
+ pCSAlias->SectionHandle = SectionHandle;
+ pCSAlias->Next = Od2CSAliasListHead;
+ Od2CSAliasListHead = (struct OS21X_CSALIAS *) pCSAlias;
+ ReleaseTaskLock();
+#if DBG
+ IF_OD2_DEBUG ( MEMORY ) {
+ DbgPrint ("DosCreateCSAlias: selDS %x is mapped to selCS %x\n",
+ selDS, *pselCS);
+ }
+#endif
+ return (NO_ERROR);
+}
+
+
+APIRET
+DosSizeSeg(
+ IN SEL sel,
+ PULONG pcbSize
+ )
+{
+ NTSTATUS Status;
+ I386DESCRIPTOR Desc;
+ OS2_API_MSG m;
+ POS2_QUERYVIRTUALMEMORY_MSG a = &m.u.QueryVirtualMemory;
+ PHUGE_SEG_RECORD pHuge;
+
+ //
+ // lookup the HugeSeg list to find out if sel is a valid Huge memory
+ //
+ for (pHuge = pHugeSegHead;
+ pHuge != NULL;
+ pHuge = (PHUGE_SEG_RECORD)(pHuge->Next)) {
+ if (pHuge->BaseSelector == (ULONG)(sel)) {
+ break;
+ }
+ }
+
+ if (pHuge == NULL) {
+
+ //
+ // Did not find a Huge Seg that starts with sel
+ //
+ //
+ // The huge seg may be a shared huge seg which was allocated
+ // by another process. Sync with the huge seg info which is
+ // kept in the server
+ //
+ a->BaseAddress = SELTOFLAT(sel);
+ Od2CallSubsystem( &m, NULL, Oi2QueryVirtualMemory, sizeof( *a ));
+ if (a->SharedMemory && a->IsHuge) {
+ pHuge = RtlAllocateHeap( Od2Heap, 0, sizeof( HUGE_SEG_RECORD) );
+ if (pHuge == NULL) {
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ pHuge->Next = (struct HUGE_SEG_RECORD *)pHugeSegHead;
+ pHuge->MaxNumSeg = a->MaxSegments;
+ pHuge->BaseSelector = sel;
+ pHuge->cNumSeg = a->NumOfSegments;
+ pHuge->PartialSeg = a->SizeOfPartialSeg;
+ pHuge->fShared = TRUE;
+ pHuge->fSizeable = a->Sizeable;
+
+ pHugeSegHead = pHuge;
+ }
+ else { // This selector is not for huge memory block.
+ //
+ // Query for the current setting in LDT
+ //
+
+ Status = Nt386GetDescriptorLDT (
+ NULL,
+ sel,
+ &Desc);
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint ("DosSizeSeg: Error %d; Sel %x\n",
+ ERROR_INVALID_PARAMETER, sel);
+#endif
+ return( ERROR_INVALID_PARAMETER );
+ }
+
+ try {
+ *pcbSize = Desc.Limit + 1;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ return (NO_ERROR);
+ }
+ }
+
+ //
+ // Calculate huge memory block size
+ //
+ try {
+ *pcbSize = pHuge->cNumSeg * _64K + pHuge->PartialSeg;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ return (NO_ERROR);
+}
+
+APIRET
+DosR2StackRealloc(
+ USHORT NewSize
+ )
+{
+ PR2StackEntry pStackEntry;
+ APIRET rc;
+
+ pStackEntry = (PR2StackEntry)R2STACKS_BASE;
+ pStackEntry += Od2CurrentThreadId();
+ if (pStackEntry->R2StackSel == 0) {
+ rc = DosAllocSeg(NewSize, (PSEL)&pStackEntry->R2StackSel, 0);
+ }
+ else {
+ rc = DosReallocSeg(NewSize, (SEL)pStackEntry->R2StackSel);
+ }
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+ pStackEntry->R2StackSize = NewSize;
+
+ return NO_ERROR;
+}
diff --git a/private/os2/client/dllwin32.c b/private/os2/client/dllwin32.c
new file mode 100644
index 000000000..951d10c03
--- /dev/null
+++ b/private/os2/client/dllwin32.c
@@ -0,0 +1,302 @@
+#include <os2ssrtl.h>
+#include <os2tile.h>
+#include <os2dbg.h>
+#include <os2err.h>
+
+ULONG
+LoadLibraryA(PSZ);
+
+ULONG
+GetProcAddress(HANDLE, PSZ);
+
+ULONG
+GetLastError(VOID);
+
+ULONG
+FreeLibrary(HANDLE);
+
+VOID
+Od2ProbeForRead(
+ IN PVOID Address,
+ IN ULONG Length,
+ IN ULONG Alignment
+ );
+
+VOID
+Od2ProbeForWrite(
+ IN PVOID Address,
+ IN ULONG Length,
+ IN ULONG Alignment
+ );
+
+VOID
+Od2ExitGP();
+
+typedef (*func) (PVOID);
+
+
+//
+// Dos32LoadModule -
+//
+// Purpose : Load a win32 thunk DLL that will intermediate between an OS/2
+// app and win32 APIs.
+//
+// Returns : If NO_ERROR is returned, the value pointed by pDllHandle
+// is used for other win32 thunk APIs. It is invalid for usage
+// with regular OS/2 APIs. If ERROR_MOD_NOT_FOUND is returned,
+// the value pointed by pDllHandle is undefined.
+//
+APIRET
+Dos32LoadModule(
+ IN PSZ DllName,
+ OUT PULONG pDllHandle
+ )
+{
+ try {
+ Od2ProbeForRead((PVOID)DllName, sizeof(ULONG), 1);
+ Od2ProbeForWrite( pDllHandle, sizeof(ULONG), 1 );
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ *pDllHandle = (ULONG) LoadLibraryA(DllName);
+
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("Dos32LoadModule: DllName - %s\n", DllName);
+ DbgPrint(" DllHandle - 0x%lx\n", *pDllHandle);
+ }
+#endif
+
+ if (*pDllHandle == (ULONG)NULL) {
+ return(ERROR_MOD_NOT_FOUND);
+ }
+ return(NO_ERROR);
+}
+
+
+
+//
+// Dos32GetProcAddr -
+//
+// Purpose : Get a cookie (flat pointer) to a routine in a win32 thunk DLL,
+// previously opened by Dos32LoadModule. For example, if the OS/2
+// app wants to call the WinSocketFoo API, it builds a win32
+// intermediate DLL, named MySock.DLL, that export WinSocketFoo.
+// The app calls Dos32LoadModule with "MySock" and then
+// Dos32GetProcAddr with pszProcName of value "WinSoketFoo". If no
+// error is returned, it can use the value pointed by pWin32Thunk
+// in a later call to Dos32Dispatch, for calling the WinSocketFoo
+// routine, which in turn will call a real Win32.
+//
+// Returns : NO_ERROR if the pszProcName is exported by the win32 intermediate
+// DLL which relates to DllHandle. If ERROR_PROC_NOT_FOUND or
+// ERROR_INVALID_HANDLE are returned, the value pointed by
+// pWin32Thunk is undefined.
+//
+APIRET
+Dos32GetProcAddr(
+ IN HANDLE DllHandle,
+ IN PSZ pszProcName,
+ OUT PULONG pWin32Thunk
+ )
+{
+ try {
+ Od2ProbeForRead((PVOID)pszProcName, sizeof(ULONG), 1);
+ Od2ProbeForWrite( pWin32Thunk, sizeof(ULONG), 1 );
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ *pWin32Thunk = (ULONG) GetProcAddress(DllHandle, pszProcName);
+
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("Dos32GetProcAddr: DllHandle - 0x%lx\n", DllHandle);
+ DbgPrint(" ProcName - %s\n", pszProcName);
+ DbgPrint(" Win32Thunk - 0x%lx\n", *pWin32Thunk);
+ }
+#endif
+
+ if (*pWin32Thunk == (ULONG)NULL) {
+ if (GetLastError() == 6 /* ERROR_INVALID_HANDLE */) {
+ return(ERROR_INVALID_HANDLE);
+ }
+ return(ERROR_PROC_NOT_FOUND);
+ }
+ return(NO_ERROR);
+}
+
+
+
+//
+// Dos32Dispatch -
+//
+// Purpose : Dos32Dispatch calls the 32bit thunk routine Win32Thunk,
+// previosly obtained by Dos32GetProcAddr. It returns the error
+// code returned by Win32Thunk in pRetCode. It translates the
+// pArguments 16:16 pointer to a flat pointer and passes it to the
+// Win32Thunk call. The structure pointed by pArguments, and the
+// values of pRetCode are app specific and are not interpreted
+// or modified by the OS/2 subsystem.
+//
+// The Win32Thunk has to by defined as following:
+//
+// ULONG WinSocketFoo(
+// PVIOD pFlatArg
+// );
+//
+// Returns : NO_ERROR if the Win32Thunk argument is a valid pointer and no
+// exception occured in the call to it.
+//
+APIRET
+Dos32Dispatch(
+ IN ULONG Win32Thunk,
+ IN PVOID pArguments,
+ OUT PULONG pRetCode
+ )
+{
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("Dos32Dispatch: Win32Thunk - 0x%lx\n", Win32Thunk);
+ }
+#endif
+
+ try {
+ *pRetCode = (*(func)Win32Thunk) (pArguments);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ return(NO_ERROR);
+}
+
+
+
+//
+// Dos32FreeModule -
+//
+// Purpose : Unload a win32 thunk DLL that intermediates between an OS/2 app
+// and win32 APIs.
+//
+// Returns : If NO_ERROR is returnd, the DllHandle is used for other win32
+// thunk APIs. It is invalid for usage with regular OS/2 APIs.
+// If ERROR_INVALID_HANDLE is returned, DllHandle is undefined.
+//
+APIRET
+Dos32FreeModule(
+ IN HANDLE DllHandle
+ )
+{
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("Dos32FreeMudule: DllHandle - 0x%lx\n", DllHandle);
+ }
+#endif
+
+ if (FreeLibrary(DllHandle)) {
+ return(NO_ERROR);
+ }
+ return(ERROR_INVALID_HANDLE);
+}
+
+
+
+//
+// FarPtr2FlatPtr -
+//
+// Purpose : Translates the segmented pointer FarPtr to a flat pointer
+// pointed by pFlatPtr.
+//
+// Returns : NO_ERROR if the FarPtr is a valid 16:16 pointer. In this
+// case pFlatPtr contains a valid 32 bit flat pointer to be used
+// by win32 code. If ERROR_INVALID_PARAMETER is returned then
+// the 16:16 pointer is not valid and the value pointed by pFlatPtr
+// is undefined.
+//
+APIRET
+FarPtr2FlatPtr(
+ IN ULONG FarPtr,
+ OUT PULONG pFlatPtr
+ )
+{
+ try {
+ Od2ProbeForWrite( pFlatPtr, sizeof( ULONG ), 1 );
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ try {
+ Od2ProbeForRead((PVOID)*pFlatPtr = FARPTRTOFLAT(FarPtr),
+ sizeof(ULONG),
+ 1);
+ } except( EXCEPTION_CONTINUE_EXECUTION ) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ if ((*pFlatPtr < BASE_TILE) || (*pFlatPtr >= BASE_TILE + _512M)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("FarPtr2FlatPtr: FarPtr - 0x%lx\n", FarPtr);
+ DbgPrint(" FlatPtr - 0x%lx\n", *pFlatPtr);
+ }
+#endif
+
+ return(NO_ERROR);
+}
+
+
+
+//
+// FlatPtr2FarPtr -
+//
+// Purpose : Translates the flat pointer FlatPtr to a far pointer pFarPtr.
+//
+// Returns : NO_ERROR if the FlatPtr has a valid 16:16 pointer in the
+// 16 bit app context. In this case pFarPtr contains a valid 16:16
+// segmented pointer to by used by the 16 bit OS/2 code.
+// If ERROR_INVALID_PARAMETER is returned then the pFarPtr is
+// undefined.
+//
+APIRET
+FlatPtr2FarPtr(
+ IN ULONG FlatPtr,
+ OUT PULONG pFarPtr
+ )
+{
+ if ((FlatPtr < BASE_TILE) || (FlatPtr >= BASE_TILE + _512M)) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ try {
+ Od2ProbeForWrite( pFarPtr, sizeof( ULONG ), 1 );
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("FlatPtr2FarPtr: FlatPtr - 0x%lx\n", FlatPtr);
+ }
+#endif
+
+ try {
+ Od2ProbeForRead( (PVOID) FlatPtr, 1, 1 );
+ } except (EXCEPTION_CONTINUE_EXECUTION ) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+
+ *pFarPtr = FLATTOFARPTR(FlatPtr);
+
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint(" FarPtr - 0x%lx\n", *pFarPtr);
+ }
+#endif
+
+ return(NO_ERROR);
+}
diff --git a/private/os2/client/dllxcpt.c b/private/os2/client/dllxcpt.c
new file mode 100644
index 000000000..9534fee6a
--- /dev/null
+++ b/private/os2/client/dllxcpt.c
@@ -0,0 +1,508 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dllxcpt.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 exception handling API calls
+
+Author:
+
+ Therese Stowell (thereses) 10-June-1990
+
+Revision History:
+
+--*/
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_EXCEPTIONS
+
+#include "os2dll.h"
+#include "os2dll16.h"
+#ifdef MIPS
+#define CONDITION_HANDLING 0
+#endif
+
+extern OD2_SIG_HANDLER_REC SigHandlerRec;
+extern ULONG Od2Saved16Stack;
+extern PVOID __cdecl Od2JumpTo16SignalDispatch(ULONG address, ULONG regs,
+ ULONG usFlagNum, ULONG usFlagArg);
+
+VOID
+Od2PrepareEnterToSignalHandler(
+ PCONTEXT Context,
+ POD2_CONTEXT_SAVE_AREA pSaveArea
+ );
+VOID
+Od2ExitFromSignalHandler(
+ PCONTEXT Context,
+ POD2_CONTEXT_SAVE_AREA pSaveArea
+ );
+
+VOID
+Od2MakeSignalHandlerContext(
+ POS2_REGISTER16_SIGNAL pContext16
+ );
+
+APIRET
+DosSetSigHandler( PFNSIGHANDLER pfnSigHandler,
+ PFNSIGHANDLER *pfnPrev,
+ PUSHORT pfAction,
+ ULONG fAction,
+ ULONG usSigNum
+ );
+
+APIRET
+DosEnterMustComplete(
+ OUT PULONG NestingLevel
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the DosEnterMustComplete API.
+
+Arguments:
+
+ NestingLevel - the number of times DosEnterMustComplete has been
+ called minus the number of times DosExitMustComplete has been called.
+
+Return Value:
+
+ ERROR_INVALID_PARAMETER - a parameter contains an invalid pointer.
+
+--*/
+
+{
+ OS2_API_MSG m;
+ POS2_DOSENTERMUSTCOMPLETE_MSG a = &m.u.DosEnterMustComplete;
+
+ try {
+ *NestingLevel = 0;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ Od2CallSubsystem( &m, NULL, Os2EnterMustComplete, sizeof( *a ) );
+ if (m.ReturnedErrorValue != NO_ERROR) {
+ return m.ReturnedErrorValue;
+ }
+ *NestingLevel = a->NestingLevel;
+ return NO_ERROR;
+}
+
+APIRET
+DosExitMustComplete(
+ OUT PULONG NestingLevel
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the DosExitMustComplete API.
+
+Arguments:
+
+ NestingLevel - the number of times DosEnterMustComplete has been
+ called minus the number of times DosExitMustComplete has been called.
+
+Return Value:
+
+ ERROR_INVALID_PARAMETER - a parameter contains an invalid pointer.
+
+--*/
+
+{
+ OS2_API_MSG m;
+ POS2_DOSEXITMUSTCOMPLETE_MSG a = &m.u.DosExitMustComplete;
+
+ try {
+ *NestingLevel = 0;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+ Od2CallSubsystem( &m, NULL, Os2ExitMustComplete, sizeof( *a ) );
+ if (m.ReturnedErrorValue != NO_ERROR) {
+ return m.ReturnedErrorValue;
+ }
+ *NestingLevel = a->NestingLevel;
+ return NO_ERROR;
+}
+
+APIRET
+DosRaiseException(
+ IN PEXCEPTIONREPORTRECORD ExceptionReportRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the DosRaiseException API.
+
+Arguments:
+
+ ExceptionReportRecord - the exception to generate
+
+Return Value:
+
+ ERROR_INVALID_PARAMETER - a parameter contains an invalid pointer.
+
+--*/
+
+{
+
+ //
+ // probe exception record
+ //
+
+ try {
+ Od2ProbeForRead(ExceptionReportRecord,
+ FIELD_OFFSET(EXCEPTIONREPORTRECORD,ExceptionInfo) +
+ (ExceptionReportRecord->cParameters * sizeof(ULONG)),
+ 4);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // raise exception
+ //
+
+#if CONDITION_HANDLING
+ RtlRaiseException((PEXCEPTION_RECORD) ExceptionReportRecord);
+#endif
+ return NO_ERROR;
+}
+
+APIRET
+DosUnwindException(
+ IN PEXCEPTIONREGISTRATIONRECORD ExceptionHandler,
+ IN PVOID TargetIP,
+ IN PEXCEPTIONREPORTRECORD ExceptionReportRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the DosUnwindException API.
+
+Arguments:
+
+ ExceptionHandler - call frame that is target of the unwind
+
+ TargetIP - continuation address
+
+ ExceptionReportRecord - the exception record to pass to handlers during
+ unwind.
+
+Return Value:
+
+ ERROR_INVALID_PARAMETER - a parameter contains an invalid pointer.
+
+--*/
+
+{
+#if DBG
+ IF_OD2_DEBUG( EXCEPTIONS ) {
+ DbgPrint("entering DosUnwindException\n");
+ }
+#endif
+ //
+ // probe exception record
+ //
+
+ try {
+ Od2ProbeForRead(ExceptionReportRecord,
+ FIELD_OFFSET(EXCEPTIONREPORTRECORD,ExceptionInfo) +
+ (ExceptionReportRecord->cParameters * sizeof(ULONG)),
+ 4);
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ Od2ExitGP();
+ }
+
+ //
+ // raise exception
+ //
+
+#if CONDITION_HANDLING
+
+ RtlUnwind(ExceptionHandler,
+ TargetIP,
+ (PEXCEPTION_RECORD) ExceptionReportRecord, 0);
+
+#endif
+
+#if DBG
+ IF_OD2_DEBUG( EXCEPTIONS ) {
+ DbgPrint("leaving DosUnwindException\n");
+ }
+#endif
+
+ return NO_ERROR;
+}
+
+APIRET
+Od2AcknowledgeSignalException(
+ IN ULONG SignalNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls the server to acknowledge a signal exception.
+
+Arguments:
+
+ SignalNumber - number of signal to acknowledge
+
+Return Value:
+
+
+--*/
+
+{
+ OS2_API_MSG m;
+ POS2_DOSACKNOWLEDGESIGNALEXCEPTION_MSG a = &m.u.DosAcknowledgeSignalException;
+ a->SignalNumber = SignalNumber;
+ Od2CallSubsystem( &m, NULL, Os2AcknowledgeSignalException, sizeof( *a ) );
+ return m.ReturnedErrorValue;
+}
+
+APIRET
+DosAcknowledgeSignalException(
+ IN ULONG SignalNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine acknowledges a signal exception.
+
+Arguments:
+
+ SignalNumber - number of signal to acknowledge
+
+Return Value:
+
+ ERROR_INVALID_SIGNAL_NUMBER - an invalid signal number was specified
+
+--*/
+
+{
+ switch (SignalNumber) {
+ case XCPT_SIGNAL_INTR:
+ case XCPT_SIGNAL_KILLPROC:
+ case XCPT_SIGNAL_BREAK:
+ return Od2AcknowledgeSignalException(SignalNumber);
+ break;
+
+ default:
+ return(ERROR_INVALID_SIGNAL_NUMBER);
+ }
+}
+
+APIRET
+DosSetSignalExceptionFocus(
+ IN BOOL32 Flag,
+ OUT PULONG NestingLevel
+ )
+
+/*++
+
+Routine Description:
+
+ This routine specifies that a particular process should or should not
+ receive signals.
+
+Arguments:
+
+ Flag - whet
+
+ NestingLevel - the number of times this API has been called with
+ Flag == set
+ called minus the number of times DosExitMustComplete has been called.
+
+Return Value:
+
+ ERROR_INVALID_SIGNAL_NUMBER - an invalid signal number was specified
+
+--*/
+
+{
+ OS2_API_MSG m;
+ POS2_DOSSETSIGNALEXCEPTIONFOCUS_MSG a = &m.u.DosSetSignalExceptionFocus;
+
+ try {
+ *NestingLevel = 0;
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ if (Flag > SIG_SETFOCUS) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ a->Flag = Flag;
+ Od2CallSubsystem( &m, NULL, Os2SetSignalExceptionFocus, sizeof( *a ) );
+ if (m.ReturnedErrorValue != NO_ERROR) {
+ return m.ReturnedErrorValue;
+ }
+ *NestingLevel = a->NestingLevel;
+ return(NO_ERROR);
+
+}
+
+APIRET
+DosSendSignalException(
+ IN PID ProcessId,
+ IN ULONG Exception
+ )
+{
+ OS2_API_MSG m;
+ POS2_DOSSENDSIGNALEXCEPTION_MSG a = &m.u.DosSendSignalException;
+
+ switch (Exception) {
+ case XCPT_SIGNAL_INTR:
+ case XCPT_SIGNAL_BREAK:
+
+ a->Exception = Exception;
+ a->ProcessId = ProcessId;
+ Od2CallSubsystem( &m, NULL, Os2SendSignalException, sizeof( *a ) );
+ return m.ReturnedErrorValue;
+ break;
+
+ default:
+ return(ERROR_INVALID_FUNCTION);
+ }
+}
+
+
+
+VOID
+Od2RaiseStackException( VOID )
+{
+ EXCEPTION_RECORD ExceptionRecord;
+
+ ExceptionRecord.ExceptionFlags = 0;
+ ExceptionRecord.ExceptionCode = XCPT_UNABLE_TO_GROW_STACK;
+ ExceptionRecord.ExceptionRecord = (PEXCEPTION_RECORD) NULL;
+ ExceptionRecord.NumberParameters = 0;
+#if CONDITION_HANDLING
+ RtlRaiseException(&ExceptionRecord);
+#endif
+}
+
+VOID
+Od2SignalDeliverer (
+ IN PCONTEXT pContext,
+ IN int Signal
+ )
+{
+ OS2_REGISTER16_SIGNAL stack;
+ ULONG sig;
+ NTSTATUS Status;
+ OD2_CONTEXT_SAVE_AREA SaveArea;
+
+ Od2PrepareEnterToSignalHandler(pContext, &SaveArea);
+
+#if DBG
+ IF_OD2_DEBUG( EXCEPTIONS ) {
+ DbgPrint("[%d]entering Od2SignalDeliverer with Signal %ld\n",
+ Od2Process->Pib.ProcessId,
+ Signal);
+ }
+#endif
+
+ switch (Signal) {
+
+ case XCPT_SIGNAL_INTR:
+ sig = SIG_CTRLC;
+ break;
+ case XCPT_SIGNAL_KILLPROC:
+ sig = SIG_KILLPROCESS;
+ break;
+ case XCPT_SIGNAL_BREAK:
+ sig = SIG_CTRLBREAK;
+ break;
+ default:
+#if DBG
+ DbgPrint("OS2: Od2SignalDeliverer() received unexpected signal %d\n", Signal);
+ ASSERT(FALSE);
+#endif // DBG
+ Od2Process->Pib.SignalWasntDelivered = FALSE;
+ Od2ExitFromSignalHandler(pContext, &SaveArea);
+ }
+
+ if (SigHandlerRec.sighandler[sig - 1] !=
+ (SigHandlerRec.doscallssel | ThunkOffsetExitProcessStub)) {
+ //
+ // If previous signal has not been acknowledged
+ // Or if the flag to hold signals to this process is enabled
+ //
+ //
+ // Since we can not return error back to caller don't hold
+ // unacknowledged signals
+ //
+ if (SigHandlerRec.signature != 0xdead) {
+ //
+ // Not ready yet for signal handling, let the loader complete
+ // loading
+ //
+ DosExit(0, 0);
+ }
+ }
+
+ if (SigHandlerRec.action[sig - 1] == SIGA_ACKNOWLEDGE ||
+ SigHandlerRec.fholdenable) {
+ //
+ // See if we already are holding an unacknowleged signal or a hold
+ // signal
+ //
+ if (SigHandlerRec.outstandingsig[sig - 1].sighandleraddr != 0) {
+ Od2Process->Pib.SignalWasntDelivered = FALSE;
+ Od2ExitFromSignalHandler(pContext, &SaveArea);
+ }
+ //
+ // Save this signal till other is processed
+ //
+ SigHandlerRec.outstandingsig[sig - 1].usFlagNum = (USHORT) sig;
+ SigHandlerRec.outstandingsig[sig - 1].usFlagArg = 0;
+ SigHandlerRec.outstandingsig[sig - 1].pidProcess =
+ (ULONG) Od2Process->Pib.ProcessId;
+ SigHandlerRec.outstandingsig[sig - 1].routine =
+ (ULONG) _Od2ProcessSignal16;
+ SigHandlerRec.outstandingsig[sig - 1].sighandleraddr =
+ (ULONG) &SigHandlerRec;
+ Od2Process->Pib.SignalWasntDelivered = FALSE;
+ Od2ExitFromSignalHandler(pContext, &SaveArea);
+ }
+
+ //
+ // Disable this signal till we get a SIGA_ACKNOWLEDGE
+ //
+ SigHandlerRec.action[sig - 1] = SIGA_ACKNOWLEDGE;
+
+ Od2Process->Pib.SignalWasntDelivered = FALSE;
+ Od2MakeSignalHandlerContext(&stack);
+
+ stack.usFlagNum = (USHORT)sig;
+ stack.usFlagArg = 0;
+
+ Od2JumpTo16SignalDispatch(SigHandlerRec.sighandler[sig - 1],
+ (ULONG) &stack,
+ sig,
+ 0);
+#if DBG
+ DbgPrint("Os2: after execution of 16bit signal\n");
+#endif
+ Od2ExitFromSignalHandler(pContext, &SaveArea);
+ ASSERT(FALSE);
+}
diff --git a/private/os2/client/fileinit.c b/private/os2/client/fileinit.c
new file mode 100644
index 000000000..5f786f0b0
--- /dev/null
+++ b/private/os2/client/fileinit.c
@@ -0,0 +1,1066 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ fileinit.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 file system initialization
+
+Author:
+
+ Therese Stowell (thereses) 14-Dec-1989
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_TASKING
+#include "os2dll.h"
+#include "conrqust.h"
+#include "os2win.h"
+#include <direct.h>
+#include <stdlib.h>
+
+/* When GetEnvironmentVariableW will return the correct mapping
+ uncomment the following line (and remove the code) */
+//#define OS2SS_WIN32_GET_ENV_IN_UNICODE 1
+
+DWORD
+GetCurrentDirectoryW(
+ DWORD nBufferLength,
+ LPWSTR lpBuffer
+ );
+
+BOOL
+SetCurrentDirectoryW(
+ LPWSTR lpPathName
+ );
+
+DWORD
+GetEnvironmentVariableW(
+ LPWSTR lpName,
+ LPWSTR lpBuffer,
+ DWORD nSize
+ );
+
+VOID
+AllocateCurrentDirectory(
+ PSTRING CurrentDirectoryString,
+ HANDLE CurrentDirectoryHandle
+ );
+
+NTSTATUS
+Od2InitializeSessionDrives(
+ OUT PULONG CurrentDisk
+ );
+
+ULONG
+Od2Oem_getcwd(
+ LPSTR lpBuffer,
+ DWORD nBufferLength
+ )
+/*++
+
+Routine Description:
+
+ This routine return the current directory ("Drv:\...").
+
+Arguments:
+
+ lpBuffer - buffer pointer for the output.
+
+ nBufferLength - buffer length.
+
+Return Value:
+
+ 0 - OK.
+ non-zero - the require buffer size.
+
+Note:
+
+ Like _getcwd(lpBuffer, nBufferLength).
+
+--*/
+
+{
+ ULONG Length, Rc = NO_ERROR;
+ WCHAR wBuffer[260];
+ UNICODE_STRING Buffer_U;
+ ANSI_STRING Buffer_A;
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2Oem_getcwd: (drive %ld), Length %d\n",
+ Od2CurrentDisk, nBufferLength);
+ }
+#endif
+ if (nBufferLength > 260)
+ {
+ nBufferLength = 260;
+ }
+
+ if (nBufferLength < 4)
+ {
+ Rc = ERROR_NOT_ENOUGH_MEMORY;
+ } else
+ {
+ if (!(Length = GetCurrentDirectoryW(nBufferLength, wBuffer)) ||
+ (Length >= nBufferLength))
+ {
+ if (Length)
+ {
+ Rc = ERROR_NOT_ENOUGH_MEMORY;
+ } else
+ {
+ ASSERT(FALSE);
+ Rc = GetLastError();
+ }
+ } else
+ {
+
+ if (wBuffer[0] >= L'a' && wBuffer[0] <= L'z') {
+ //
+ // upcase the drive letter
+ //
+ wBuffer[0] = wBuffer[0] - (L'a' - L'A');
+ }
+
+ RtlInitUnicodeString( &Buffer_U, wBuffer );
+// RtlUpcaseUnicodeString( &Buffer_U, &Buffer_U, FALSE );
+ Buffer_A.Buffer = lpBuffer;
+ Buffer_A.Length = 0;
+ Buffer_A.MaximumLength = (USHORT)nBufferLength;
+ Or2UnicodeStringToMBString (&Buffer_A, &Buffer_U, FALSE);
+ }
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2Oem_getcwd: return %ld\n", Rc );
+ }
+#endif
+ return(Rc);
+}
+
+
+ULONG
+Od2Oem_getdcwd(
+ ULONG DiskNumber,
+ LPSTR lpBuffer,
+ DWORD nBufferLength
+ )
+/*++
+
+Routine Description:
+
+ This routine return the current directory ("Drv:\...") for specified drive.
+
+Arguments:
+
+ DiskNumber- Disk drive (1=A, 2=B, ...)
+
+ lpBuffer - buffer pointer for the output.
+
+ nBufferLength - buffer length.
+
+Return Value:
+
+ 0 - OK.
+ non-zero - the require buffer size.
+
+Note:
+
+ Like _getdcwd(DiskNumber, lpBuffer, nBufferLength).
+
+--*/
+
+{
+ ULONG Length, LogicalDrivesMap, Rc = NO_ERROR;
+#if OS2SS_WIN32_GET_ENV_IN_UNICODE
+ WCHAR wBuffer[300];
+ UNICODE_STRING Buffer_U;
+ ANSI_STRING Buffer_A;
+ WCHAR lpDriveName[] = L"=@:";
+#else
+ CHAR lpDriveName[] = "=@:";
+#endif
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2Oem_getdcwd: for drive %ld, (drive %ld), Length %d\n",
+ DiskNumber, Od2CurrentDisk, nBufferLength);
+ }
+#endif
+ if (nBufferLength < 4)
+ {
+ Rc = ERROR_NOT_ENOUGH_MEMORY;
+ } else if (!(LogicalDrivesMap = GetLogicalDrives()) ||
+ !(LogicalDrivesMap & (1 << DiskNumber - 1 )))
+ {
+ Rc = ERROR_INVALID_DRIVE;
+ } else
+ {
+ lpBuffer[0] = '@' + (CHAR)DiskNumber;
+ lpBuffer[1] = ':';
+ lpBuffer[2] = '\\';
+ lpBuffer[3] = '\0';
+
+#if OS2SS_WIN32_GET_ENV_IN_UNICODE
+ if (nBufferLength > 300)
+ {
+ nBufferLength = 300;
+ }
+ lpDriveName[1] += (WCHAR)DiskNumber;
+ if (!(Length = GetEnvironmentVariableW(lpDriveName, wBuffer, nBufferLength)) ||
+ (Length >= nBufferLength))
+ {
+ if (Length)
+ {
+ Rc = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ } else
+ {
+ RtlInitUnicodeString( &Buffer_U, wBuffer );
+ Buffer_A.Buffer = lpBuffer;
+ Buffer_A.Length = 0;
+ Buffer_A.MaximumLength = (USHORT)nBufferLength;
+ Or2UnicodeStringToMBString (&Buffer_A, &Buffer_U, FALSE);
+ }
+#else
+ lpDriveName[1] += (CHAR)DiskNumber;
+ if ((Length = GetEnvironmentVariableA(lpDriveName, lpBuffer, nBufferLength)) >= nBufferLength)
+ {
+ Rc = ERROR_NOT_ENOUGH_MEMORY;
+ }
+#endif
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2Oem_getdcwd: return %ld\n", Rc );
+ }
+#endif
+ return(Rc);
+}
+
+
+ULONG
+Od2Oem_chdrive(
+ ULONG DiskNumber
+ )
+/*++
+
+Routine Description:
+
+ This routine changes the current working drive
+
+Arguments:
+
+ DiskNumber- Disk drive (1=A, 2=B, ...)
+
+Return Value:
+
+ 0 - OK.
+ non-zero - error.
+
+Note:
+
+ Like : _chdrive(lpBuffer[0] - '@')
+
+--*/
+
+{
+ ULONG Length, LogicalDrivesMap, Rc = NO_ERROR;
+ UNICODE_STRING Buffer_U;
+#if OS2SS_WIN32_GET_ENV_IN_UNICODE
+ WCHAR wBuffer[300];
+ WCHAR lpDriveName[] = L"=@:";
+#else
+ CHAR lpDriveName[] = "=@:";
+ CHAR lpBuffer[300];
+ BOOL bRc = FALSE;
+#endif
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2Oem_chdrive: for drive %ld, (drive %ld)\n",
+ DiskNumber, Od2CurrentDisk);
+ }
+#endif
+ if (!(LogicalDrivesMap = GetLogicalDrives()) ||
+ !(LogicalDrivesMap & (1 << DiskNumber - 1)))
+ {
+ Rc = ERROR_INVALID_DRIVE;
+ } else
+ {
+#if OS2SS_WIN32_GET_ENV_IN_UNICODE
+ wBuffer[0] = L'@' + (WCHAR)DiskNumber;
+ wBuffer[1] = L':';
+ wBuffer[2] = L'\\';
+ wBuffer[3] = L'\0';
+
+ lpDriveName[1] += (WCHAR)DiskNumber;
+ if ((Length = GetEnvironmentVariableW(lpDriveName, wBuffer, 300)) >= 300)
+ {
+ Rc = ERROR_NOT_ENOUGH_MEMORY;
+ } else
+ {
+ bRc = !SetCurrentDirectoryW(wBuffer);
+#else
+ lpBuffer[0] = '@' + (CHAR)DiskNumber;
+ lpBuffer[1] = ':';
+ lpBuffer[2] = '\\';
+ lpBuffer[3] = '\0';
+
+ lpDriveName[1] += (CHAR)DiskNumber;
+ if ((Length = GetEnvironmentVariableA(lpDriveName, lpBuffer, 300)) >= 300)
+ {
+ Rc = ERROR_NOT_ENOUGH_MEMORY;
+ } else
+ {
+ if (!Od2CreateUnicodeStringFromMBz(&Buffer_U, lpBuffer))
+ {
+ Rc = ERROR_NOT_ENOUGH_MEMORY;
+ } else
+ {
+ Buffer_U.Buffer[Buffer_U.Length/sizeof(WCHAR)] = L'\0';
+ bRc = !SetCurrentDirectoryW(Buffer_U.Buffer);
+ }
+#endif
+ }
+ }
+
+ if (bRc)
+ {
+ if ((Rc = GetLastError()) == ERROR_NO_MEDIA_IN_DRIVE)
+ {
+ Rc = ERROR_NOT_READY;
+ }
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2Oem_chdrive: return %ld\n", Rc );
+ }
+#endif
+ return(Rc);
+}
+
+
+ULONG
+Od2Oem_chdir_chdrive(
+ LPSTR lpBuffer
+ )
+/*++
+
+Routine Description:
+
+ This routine changes the current working directory and the current drive
+
+Arguments:
+
+ lpBuffer - path name of new working directory.
+
+Return Value:
+
+ 0 - OK.
+ non-zero - error.
+
+Note:
+
+ Like : _chdrive(lpBuffer[0] - '@'); _chdir(lpBuffer);
+ If the directory is different from the current, it's set to the new one.
+ If the drive is different from the current, it's set to the new one.
+
+--*/
+
+{
+ UNICODE_STRING Buffer_U;
+ ANSI_STRING Buffer_A;
+ BOOL bRc;
+ ULONG Length, Rc = ERROR_NOT_ENOUGH_MEMORY;
+ WCHAR wBuffer[260];
+#if OS2SS_WIN32_GET_ENV_IN_UNICODE
+ WCHAR lpDriveName[] = L"=@:";
+#else
+ CHAR lpDriveName[] = "=@:";
+#endif
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2Oem_chdir_chdrive: for drive %c, (drive %ld), dir %s\n",
+ lpBuffer[0], Od2CurrentDisk, lpBuffer);
+ }
+#endif
+ Or2InitMBString( &Buffer_A, lpBuffer);
+ if (!Or2MBStringToUnicodeString(&Buffer_U, &Buffer_A, TRUE))
+ {
+ Buffer_U.Buffer[Buffer_U.Length/sizeof(WCHAR)] = L'\0';
+ bRc = SetCurrentDirectoryW(Buffer_U.Buffer);
+ RtlFreeUnicodeString(&Buffer_U);
+ if (bRc)
+ {
+ if (!(Length = GetCurrentDirectoryW(260, wBuffer)) ||
+ (Length >= 260))
+ {
+ if (Length)
+ {
+ Rc = ERROR_NOT_ENOUGH_MEMORY;
+ } else
+ {
+ ASSERT(FALSE);
+ Rc = GetLastError();
+ }
+ } else
+ {
+#if OS2SS_WIN32_GET_ENV_IN_UNICODE
+ lpDriveName[1] = wBuffer[0];
+ SetEnvironmentVariableW(lpDriveName, Buffer_U.Buffer);
+#else
+ RtlInitUnicodeString( &Buffer_U, wBuffer );
+ Or2UnicodeStringToMBString (&Buffer_A, &Buffer_U, TRUE);
+ lpDriveName[1] = Buffer_A.Buffer[0];
+ SetEnvironmentVariableA(lpDriveName, Buffer_A.Buffer);
+ Or2FreeMBString(&Buffer_A);
+#endif
+ }
+ Rc = 0;
+ } else
+ {
+ Rc = GetLastError();
+ }
+ }
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2Oem_chdir_chdrive: return %ld\n", Rc );
+ }
+#endif
+ return(Rc);
+}
+
+
+VOID
+Od2InitializeSearchHandleTable(
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the search handle table. Since it is not
+ inherited from the parent, we just mark each handle table entry free.
+ The table is initially statically allocated in the process's space.
+ If the number of find handles exceeds the space in the table, we allocate
+ a new table off the heap and copy the old one over.
+
+ The handle table is an array of pointers to search records.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG i;
+
+ SearchHandleTable = SmallSearchHandleTable;
+ SearchHandleTableLength = INITIAL_SEARCH_HANDLES;
+ for (i=0;i<SearchHandleTableLength;i++) {
+ SearchHandleTable[i] = SEARCH_HANDLE_FREE;
+ }
+}
+
+
+APIRET
+Od2InitializeFileSystemForExec(
+ ULONG ParentTableLength,
+ ULONG CurrentDrive
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the file system for an execpgm. This involves
+ allocating space and copying the file handle table and current directory
+ table from the parent process.
+
+Arguments:
+
+ ParentTableLength - length of parent's file handle table. (number of entries)
+
+ CurrentDrive - parent's current drive
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ OS2_API_MSG m;
+ POS2_COPYHANDLETABLE_MSG a = &m.u.CopyHandleTable;
+ PSTRING CurrentDirectoryString;
+ HANDLE CurDirHandle;
+ ULONG Length, i;
+ APIRET RetCode;
+ USHORT *Count;
+ PSZ RoutineName;
+
+ RoutineName = "Od2InitializeFileSystemForExec";
+ //
+ // initialize search handle table.
+ //
+
+ Od2InitializeSearchHandleTable();
+
+ //
+ // initialize current drive from parent value.
+ //
+
+ RetCode = Od2GetCurrentDirectory(CurrentDrive,
+ &CurrentDirectoryString,
+ &CurDirHandle,
+ &Length,
+ (BOOLEAN)FALSE
+ );
+ //
+ // since the process will die, we don't have to free any allocated
+ // heap space.
+ //
+
+ if (RetCode) {
+ return RetCode;
+ }
+ Od2CurrentDisk = CurrentDrive;
+ AllocateCurrentDirectory(CurrentDirectoryString,CurDirHandle);
+ RtlFreeHeap(Od2Heap,0,CurrentDirectoryString);
+
+ //
+ // if (table size != initial size)
+ // allocate heap
+ //
+ HandleTableLength = ParentTableLength;
+ if (HandleTableLength != INITIALFILEHANDLES) {
+ // allocate from child process's heap
+ HandleTable = RtlAllocateHeap(Od2Heap,0,HandleTableLength * sizeof(FILE_HANDLE));
+ }
+ else {
+ HandleTable = SmallHandleTable;
+ }
+ if (!HandleTable) {
+#if DBG
+ KdPrint(("OS2: Od2InitializeFileSystemForExec out of heap memory, fail\n"));
+#endif
+ ASSERT( FALSE );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // read table into memory
+
+ a->ChildHandleTable = HandleTable;
+ a->ChildTableLength = HandleTableLength;
+ RetCode = Od2CallSubsystem( &m, NULL, Oi2CopyHandleTable, sizeof( *a ) );
+ if (RetCode) {
+ return RetCode;
+ }
+
+ VerifyFlag = FALSE;
+
+#if DBG
+ AcquireStdHandleLock(RoutineName);
+#else
+ AcquireStdHandleLock();
+#endif
+
+ for (i=0;i<HandleTableLength;i++)
+ {
+ if ((HandleTable[i].Flags & FILE_HANDLE_ALLOCATED) &&
+ (!(HandleTable[i].Flags & OPEN_FLAGS_NOINHERIT)))
+ {
+ if (HandleTable[i].IoVectorType == MonitorVectorType)
+ {
+ HandleTable[i].Flags = FILE_HANDLE_FREE;
+ } else if (HandleTable[i].IoVectorType == RemoteVectorType)
+ {
+ if (HandleTable[i].NtHandle == SesGrp->StdIn)
+ {
+ Count = &SesGrp->StdInHandleCount;
+ } else if (HandleTable[i].NtHandle == SesGrp->StdOut)
+ {
+ Count = &SesGrp->StdOutHandleCount;
+ } else if (HandleTable[i].NtHandle == SesGrp->StdErr)
+ {
+ Count = &SesGrp->StdErrHandleCount;
+ } else
+ Count = NULL;
+
+ if (Count && *Count) /* if legal and open */
+ {
+ (*Count)++; /* one more handle */
+ }
+ } else if (HandleTable[i].IoVectorType == MouseVectorType)
+ {
+ if (DevMouOpen(&(HandleTable[i].NtHandle)))
+ {
+ HandleTable[i].Flags = FILE_HANDLE_FREE;
+ }
+ }
+ else if ((HandleTable[i].IoVectorType == KbdVectorType) &&
+ !(HandleTable[i].DeviceAttribute & DEVICE_ATTRIBUTE_GENIOCTL))
+ {
+ // Logical KBD
+ KbdDupLogHandle(HandleTable[i].NtHandle);
+ }
+// else if ((HandleTable[i].IoVectorType == ConVectorType) ||
+// (HandleTable[i].IoVectorType == ScreenVectorType))
+// {
+// }
+ }
+ }
+
+#if DBG
+ ReleaseStdHandleLock(RoutineName);
+#else
+ ReleaseStdHandleLock();
+#endif
+
+ return( m.ReturnedErrorValue );
+}
+
+
+NTSTATUS
+GetFileAccess(
+ IN HFILE FileHandle,
+ IN OUT PULONG Access
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the file access of a particular file
+
+Arguments:
+
+ FileHandle - file handle of file to retrieve file access of
+
+ Access - where to store file access
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ FILE_ACCESS_INFORMATION AccessInfo;
+
+ // this call requires no access
+
+ Status = NtQueryInformationFile(FileHandle,
+ &IoStatus,
+ &AccessInfo,
+ sizeof (AccessInfo),
+ FileAccessInformation);
+ if (!(NT_SUCCESS(Status))) {
+ return Status;
+ }
+ if (AccessInfo.AccessFlags & FILE_WRITE_DATA) {
+ if (AccessInfo.AccessFlags & FILE_READ_DATA) {
+ *Access |= OPEN_ACCESS_READWRITE;
+ }
+ else
+ *Access |= OPEN_ACCESS_WRITEONLY;
+ }
+ else
+ *Access |= OPEN_ACCESS_READONLY;
+ return STATUS_SUCCESS;
+}
+
+
+APIRET
+Od2InitializeFileSystemForSM(
+ IN ULONG DefaultDrive,
+ IN HANDLE StandardInput,
+ IN HANDLE StandardOutput,
+ IN HANDLE StandardError
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the file system for the first time (when called
+ from the session manager). We initialize the file system variables -
+ the file handle table, current directory table, and verify flag and
+ set up handles 0-2 (stdin, stdout, stderr).
+
+Arguments:
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ int i;
+ NTSTATUS Status;
+
+ UNREFERENCED_PARAMETER(StandardInput);
+ UNREFERENCED_PARAMETER(StandardOutput);
+ UNREFERENCED_PARAMETER(StandardError);
+
+ //
+ // initialize search handle table.
+ //
+
+ Od2InitializeSearchHandleTable();
+
+ //
+ // initialize current disk to boot drive and current directory to
+ // root.
+
+ Status = Od2InitializeSessionDrives(
+ &Od2CurrentDisk
+ );
+ if ( !NT_SUCCESS( Status ) ) {
+ Od2CurrentDisk = DefaultDrive;
+ Od2CurrentDirectory.pCurDir = NULL;
+ Od2DirHandles[Od2CurrentDisk] = NULL;
+ Od2DirHandlesIsValid[Od2CurrentDisk] = TRUE;
+ }
+
+
+ // initialize file handle table.
+
+ HandleTable = SmallHandleTable;
+ HandleTableLength= INITIALFILEHANDLES;
+ for (i=0;i<INITIALFILEHANDLES;i++) {
+ HandleTable[i].Flags = FILE_HANDLE_FREE;
+ }
+
+
+ HandleTable[0].Flags = FILE_HANDLE_VALID | FILE_HANDLE_ALLOCATED | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY;
+ HandleTable[0].IoVectorType = RemoteVectorType;
+ HandleTable[0].NtHandle = SesGrp->StdIn;
+ HandleTable[0].DeviceAttribute = DEVICE_ATTRIBUTE_STDIN | DEVICE_ATTRIBUTE_STDOUT | DEVICE_ATTRIBUTE_CHAR | 0x80;
+ HandleTable[0].FileType = SesGrp->StdInFileType;
+ HandleTable[1].Flags = FILE_HANDLE_VALID | FILE_HANDLE_ALLOCATED | OPEN_SHARE_DENYNONE | OPEN_ACCESS_WRITEONLY;;
+ HandleTable[1].IoVectorType = RemoteVectorType;
+ HandleTable[1].NtHandle = SesGrp->StdOut;
+ HandleTable[1].DeviceAttribute = DEVICE_ATTRIBUTE_STDIN | DEVICE_ATTRIBUTE_STDOUT | DEVICE_ATTRIBUTE_CHAR | 0x80;
+ HandleTable[1].FileType = SesGrp->StdOutFileType;
+ HandleTable[2].Flags = FILE_HANDLE_VALID | FILE_HANDLE_ALLOCATED | OPEN_SHARE_DENYNONE | OPEN_ACCESS_WRITEONLY;;
+ HandleTable[2].IoVectorType = RemoteVectorType;
+ HandleTable[2].NtHandle = SesGrp->StdErr;
+ HandleTable[2].DeviceAttribute = DEVICE_ATTRIBUTE_STDIN | DEVICE_ATTRIBUTE_STDOUT | DEVICE_ATTRIBUTE_CHAR | 0x80;
+ HandleTable[2].FileType = SesGrp->StdErrFileType;
+
+ if (!SesGrp->StdInFlag)
+ {
+ HandleTable[0].DeviceAttribute = 0;
+ }
+
+ if (!SesGrp->StdOutFlag)
+ {
+ HandleTable[1].DeviceAttribute = 1;
+ }
+
+ if (!SesGrp->StdErrFlag)
+ {
+ HandleTable[2].DeviceAttribute = 2;
+ }
+ VerifyFlag = FALSE;
+ return NO_ERROR;
+}
+
+NTSTATUS
+Od2InitializeSessionDrives(
+ OUT PULONG CurrentDisk
+ )
+{
+ APIRET Rc = NO_ERROR;
+ CHAR S[260];
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2InitializeSessionDrives: disk %lu\n", *CurrentDisk);
+ }
+#endif
+ if (Od2Oem_getcwd(S, 260))
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2InitializeSessionDrives: Od2Oem_getcwd failed, Rc %lu\n",
+ Rc);
+ }
+#endif
+ *CurrentDisk = '\0';
+ } else
+ {
+ *CurrentDisk = (ULONG)(*S - 'A');
+ Rc = DosSetCurrentDir( S );
+ if (Rc)
+ {
+#if DBG
+ ASSERT(FALSE);
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2InitializeSessionDrives: DosSetCurrentDrive failed, Rc %lu\n",
+ Rc);
+ }
+#endif
+ }
+ }
+
+ return( Rc );
+}
+
+
+APIRET
+Od2InitCurrentDir(
+ IN ULONG CurrentDisk
+ )
+{
+ APIRET Rc;
+ CHAR S[260];
+ ULONG DefaultDrive;
+
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2InitCurrentDir: disk # %ld, Current %ld\n",
+ CurrentDisk, Od2CurrentDisk);
+ }
+#endif
+ Od2Oem_getcwd(S, 260);
+ DefaultDrive = S[0] - '@';
+ if (!(Rc = Od2Oem_chdrive(CurrentDisk + 1)))
+ {
+ Rc = Od2Oem_getcwd(S, 260);
+ if (!Rc)
+ {
+ // There is a drive with valid directory name
+ Rc = DosSetCurrentDir( S );
+ } else
+ {
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2InitCurrentDir: Od2Oem_getcwd failed, Rc %lu\n",
+ Rc);
+ }
+#endif
+ Rc = ERROR_NOT_READY;
+ }
+ Od2Oem_chdrive(DefaultDrive);
+ }
+#if DBG
+ IF_OD2_DEBUG( FILESYS ) {
+ DbgPrint("Od2InitCurrentDir: return Rc %lu\n",
+ Rc);
+ }
+#endif
+ return( Rc );
+}
+
+
+
+APIRET
+Od2InitializeFileSystemForChildSM(
+ ULONG ParentTableLength,
+ ULONG CurrentDrive
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the file system for an execpgm. This involves
+ allocating space and copying the file handle table and current directory
+ table from the parent process.
+
+Arguments:
+
+ ParentTableLength - length of parent's file handle table. (number of entries)
+
+ CurrentDrive - parent's current drive
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ OS2_API_MSG m;
+ POS2_COPYHANDLETABLE_MSG a = &m.u.CopyHandleTable;
+ PSTRING CurrentDirectoryString;
+ HANDLE CurDirHandle;
+ ULONG Length, i;
+ APIRET RetCode;
+ USHORT *Count;
+ PSZ RoutineName;
+
+ RoutineName = "Od2InitializeFileSystemForChildSM";
+ //
+ // initialize search handle table.
+ //
+
+ Od2InitializeSearchHandleTable();
+
+ //
+ // initialize current drive from parent value.
+ //
+
+ Od2CurrentDisk = CurrentDrive+1;
+
+ //
+ // initialize current directory on current drive by calling server to
+ // retrieve it.
+ //
+ // we force GetCurrentDirectory to retrieve the currentdirectory from
+ // the server by passing in a drive guaranteed not to be the current drive -
+ // Od2CurrentDisk+1.
+ //
+
+ RetCode = Od2GetCurrentDirectory(CurrentDrive,
+ &CurrentDirectoryString,
+ &CurDirHandle,
+ &Length,
+ (BOOLEAN)FALSE
+ );
+ //
+ // since the process will die, we don't have to free any allocated
+ // heap space.
+ //
+
+ if (RetCode) {
+ return RetCode;
+ }
+
+ Od2CurrentDisk = CurrentDrive;
+ AllocateCurrentDirectory(CurrentDirectoryString,CurDirHandle);
+ RtlFreeHeap(Od2Heap,0,CurrentDirectoryString);
+
+ //
+ // if (table size != initial size)
+ // allocate heap
+ //
+ HandleTableLength = ParentTableLength;
+ if (HandleTableLength != INITIALFILEHANDLES) {
+ // allocate from child process's heap
+ HandleTable = RtlAllocateHeap(Od2Heap,0,HandleTableLength * sizeof(FILE_HANDLE));
+ }
+ else {
+ HandleTable = SmallHandleTable;
+ }
+
+ if (!HandleTable) {
+#if DBG
+ KdPrint(("OS2: Od2InitializeFileSystemForChildSm out of heap memory, fail\n"));
+#endif
+ ASSERT( FALSE );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // read table into memory
+
+ a->ChildHandleTable = HandleTable;
+ a->ChildTableLength = HandleTableLength;
+ RetCode = Od2CallSubsystem( &m, NULL, Oi2CopyHandleTable, sizeof( *a ) );
+ if (RetCode) {
+ return RetCode;
+ }
+
+ VerifyFlag = FALSE;
+
+ for (i=0;i<HandleTableLength;i++)
+ {
+ if ((HandleTable[i].Flags & FILE_HANDLE_ALLOCATED) &&
+ (!(HandleTable[i].Flags & OPEN_FLAGS_NOINHERIT)))
+ {
+ if (HandleTable[i].IoVectorType == MonitorVectorType)
+ {
+ HandleTable[i].Flags = FILE_HANDLE_FREE;
+ } else if (HandleTable[i].IoVectorType == RemoteVectorType)
+ {
+ if (HandleTable[i].NtHandle == SesGrp->StdIn)
+ {
+ Count = &SesGrp->StdInHandleCount;
+ } else if (HandleTable[i].NtHandle == SesGrp->StdOut)
+ {
+ Count = &SesGrp->StdOutHandleCount;
+ } else if (HandleTable[i].NtHandle == SesGrp->StdErr)
+ {
+ Count = &SesGrp->StdErrHandleCount;
+ } else
+ Count = NULL;
+
+ if (Count && *Count) /* if legal and open */
+ {
+ (*Count)++; /* one more handle */
+ }
+ } else if (HandleTable[i].IoVectorType == MouseVectorType)
+ {
+ if (DevMouOpen(&(HandleTable[i].NtHandle)))
+ {
+ HandleTable[i].Flags = FILE_HANDLE_FREE;
+ }
+ }
+ else if (HandleTable[i].IoVectorType == KbdVectorType)
+ {
+ if (!(HandleTable[i].DeviceAttribute & DEVICE_ATTRIBUTE_GENIOCTL))
+ {
+ // Physical Keybaord
+
+ HandleTable[i].NtHandle = (HANDLE)SesGrp->PhyKbd;
+ } else
+ {
+ // Logical KBD
+
+ if (KbdOpenLogHandle(&HandleTable[i].NtHandle))
+ HandleTable[i].Flags = FILE_HANDLE_FREE;
+ }
+ }
+// else if ((HandleTable[i].IoVectorType == ConVectorType) ||
+// (HandleTable[i].IoVectorType == ScreenVectorType))
+// {
+// }
+ }
+ }
+
+ /*
+ * if count=1, no one use this handle so it may be close
+ */
+
+ if ((SesGrp->StdInHandleCount == 1) && !SesGrp->StdInFlag)
+ {
+ RemoteCloseHandle(SesGrp->StdIn);
+ }
+ if ((SesGrp->StdOutHandleCount == 1) && !SesGrp->StdOutFlag)
+ {
+ RemoteCloseHandle(SesGrp->StdOut);
+ }
+ if ((SesGrp->StdErrHandleCount == 1) && !SesGrp->StdErrFlag)
+ {
+ RemoteCloseHandle(SesGrp->StdErr);
+ }
+
+ return( m.ReturnedErrorValue );
+}
+
diff --git a/private/os2/client/i386/dll16.asm b/private/os2/client/i386/dll16.asm
new file mode 100644
index 000000000..cddcddb02
--- /dev/null
+++ b/private/os2/client/i386/dll16.asm
@@ -0,0 +1,1121 @@
+
+ title "OS/2 16B asm special routines"
+;++
+;
+; Copyright (c) 1991 Microsoft Corporation
+;
+; Module Name:
+;
+; dll16.asm
+;
+; Abstract:
+;
+; This module contains callbacks and dispatchers that help implementing
+; some of the 16b OS2 1.X APIs that cannot be done by C code.
+;
+; Author:
+;
+; Yaron Shamir (YaronS) 30-May-1991
+;
+; Revision History:
+;
+;--
+
+DCT_RUNABLE equ 0 ; Create thread in a runable state
+DCT_RUNABLE_HIDDEN equ 2 ; Create thread in a runable state but with
+ ; a high number (see os2v20.h)
+.386p
+
+EXTRN _Save32Esp@4:PROC
+EXTRN _DosCreateThread@20:PROC
+EXTRN _LDRDoscallsSel:WORD
+EXTRN _DosExit@8:PROC
+EXTRN _DosExitList@8:PROC
+EXTRN _Od2Start16Stack:DWORD
+EXTRN _Od2ExitListInProgress:DWORD
+EXTRN _Od2Start16DS:DWORD
+EXTRN _DosFlagProcess@20:PROC
+EXTRN _DosSendSignal@12:PROC
+EXTRN _DosHoldSignal@8:PROC
+EXTRN _Od2GetTebInfoSeg@0:PROC
+EXTRN _Od2CheckForCritSectOrSuspend@0:PROC
+EXTRN _Od2GetInfoSegWasCalled:DWORD
+EXTRN _Od2GetThread1TebBackup@0:PROC
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;
+; The Thread Starter is dispatched from the os2 server
+; It get us to the 16b code, stack, DS and ES of the new thread.
+; It takes as a parameter (ebp+8) a pointer to the 16 stack frame as
+; created by the 16b thunk of DosCreateThread (doscalls.asm)
+;
+ public _Od2ThreadStarter16
+_Od2ThreadStarter16 proc
+
+;
+; Save the esp for later use by the thread when it will call APIs
+;
+ mov eax, esp
+ push eax
+ call _Save32Esp@4
+ call _MoveInfoSegintoTeb
+;
+; Put selector of doscalls into AX
+;
+ mov ax,_LDRDoscallsSel; Selector to Doscalls
+
+; Now fetch the 16b context frame from the new stack
+; the stack frame is created by Dos16CreateThread below
+;
+ mov ebx, [esp+4]
+;
+; ebx points at
+; IP:CS (of the user's start procedure)
+; ES:DS
+; SP:SS (they inturn point to ES)
+;
+ lss sp, [ebx - 26]
+
+;
+; Restore 16-bit registers
+;
+ db 066h ; force two byte pop
+ pop di
+ db 066h ; force two byte pop
+ pop si
+ db 066h ; force two byte pop
+ pop cx
+ db 066h ; force two byte pop
+ pop bx
+ db 066h ; force two byte pop
+ pop dx
+ ;
+ ; For segment registers ES, DS, we need to verify
+ ; selectors before we fix them
+ ;
+ mov bp,ax ; save ax (doscalls selector)
+ db 066H ; force two byte pop
+ pop ax ; ax<-saved ES
+ verr ax ; see if the value is still valid!
+ jz SetES
+ xor ax,ax
+SetES:
+ mov es,ax
+;
+ db 066H ; force two byte pop
+ pop ax ; ax<-saved DS
+ verr ax ; see if the value is still valid!
+ jz SetDS
+ xor ax,ax
+SetDS:
+ mov ds,ax
+;
+;
+; Before we return to the new thread, we need to setup
+; That if it returns (instead of calling DosExit) -
+; it goes into DosExitStub Thunk which will call
+; DosExit (EXIT_THREAD, 0)
+;
+
+ mov ax,bp
+ mov bp,sp
+ mov [bp+6],ax ; Segment
+ xor ax, ax
+ mov [bp+4],ax ; offset 0 in Doscalls.dll
+ xor ebp,ebp
+
+;
+; Now jump by far return
+;
+ db 66h, 0cah ; 16-bit retf
+ dw 0 ; no params
+
+
+_Od2ThreadStarter16 endp
+
+;
+; Dos16CreateThread copies relevant info from the saved 16b frame
+; as was setup in the thunk to DosCreateThread, then
+; calls DosCreateThread (the 32 bit version, dlltask.c) with &TID.
+;
+; APIRET
+; Dos16CreateThread(
+; PFNTHREAD pfnFunction(VOID),
+; PTID16 ptidThread,
+; PCHAR pbThrdStack)
+;
+;
+ public _Dos16CreateThread@12
+_Dos16CreateThread@12 proc
+
+;
+; 16 bit segmented params pushed by apps
+;
+; ebx+40 pfnFun
+; ebx+36 pTid
+; ebx+32 pbStack
+;
+; 16 bit seg registers pushed by thunk
+;
+; ebx+24 ES
+; ebx+26 DS
+;
+
+ push ebp
+ mov ebp,esp
+
+;
+; now also (flat parameters called by the thunk)
+;
+; ebp+8 pfnFun
+; ebp+12 pTid
+; ebp+16 pbStack
+;
+
+;
+; makeup a 16 bit saved state for ThreadStarter16
+; we must put this on the new stack, otherwise it can
+; be washed out if the calling thread is scheduled before
+; the new thread
+;
+ cmp word ptr[ebp+16],0 ; check for 64K stack (offset = 0)
+ jnz @F
+ inc word ptr[ebp+18] ; sel++ to prevent underflow
+@@:
+ push ecx
+ mov eax, [ebp+16]
+
+ sub eax,4 ; save space on stack for DosExit return
+ sub eax,2
+ mov cx, [ebx+34] ; new thread's CS
+ mov [eax], cx
+ sub eax,2
+ mov cx, [ebx+32] ; new thread's IP
+ mov [eax], cx
+ sub eax,2
+ mov cx, [ebx+18] ; new thread's DS
+ mov [eax], cx
+ sub eax,2
+ mov cx, [ebx+16] ; new thread's ES
+ mov [eax], cx
+ sub eax,2
+ mov cx, [ebx+6] ; new thread's DX
+ mov [eax], cx
+ sub eax, 2
+ mov cx, [ebx+8] ; new thread's BX
+ mov [eax], cx
+ sub eax, 2
+ mov cx, [ebx+10] ; new thread's CX
+ mov [eax], cx
+ sub eax, 2
+ mov cx, [ebx+12] ; new thread's SI
+ mov [eax], cx
+ sub eax, 2
+ mov cx, [ebx+14] ; new thread's DI
+ mov [eax], cx
+ sub eax, 2
+ mov cx, [ebx+26] ; new thread's SS
+ mov [eax], cx
+ sub eax,2
+ mov cx, [ebx+24]
+ sub cx,22 ; for DI:SI:CX:BX:DX:ES:DS:IP:CS:DOSEXIT
+ mov [eax], cx ; new thread's SP
+ pop ecx
+
+;
+; Now call DosCreateThread (32b)
+; The 'ThreadParameter' parameter is setup to point to the frame above
+;
+
+; StackSize - set to default (4K for now)
+;
+
+ push 1 ; will be rounded up
+
+; Flags - set to be runnable immediately
+;
+ push DCT_RUNABLE
+
+; Thread Parameter
+;
+ push dword ptr [ebp+16] ; the new 16 bit stack
+
+; pfnFun
+;
+ push offset FLAT:_Od2ThreadStarter16
+
+; pTid
+;
+ push dword ptr [ebp+12]
+
+ call _DosCreateThread@20 ; call 32-bit version
+
+ leave
+ ret 12 ; return to thunk
+
+_Dos16CreateThread@12 endp
+
+;
+; PMNT16CreateThread copies relevant info from the saved 16b frame
+; as was setup in the thunk to PMNTCreateThread, then
+; calls DosCreateThread (the 32 bit version, dlltask.c) with &TID.
+; The diffrence betwin PMNT16CreateThread and Dos16CreateThread is that
+; PMNT16Create thread pushes DCT_RUNABLE_HIDDEN and Dos16CreateThread pushes
+; DCT_RUNABLE
+;
+; APIRET
+; PMNT16CreateThread(
+; PFNTHREAD pfnFunction(VOID),
+; PTID16 ptidThread,
+; PCHAR pbThrdStack)
+;
+;
+ public _PMNT16CreateThread@12
+_PMNT16CreateThread@12 proc
+
+;
+; 16 bit segmented params pushed by apps
+;
+; ebx+40 pfnFun
+; ebx+36 pTid
+; ebx+32 pbStack
+;
+; 16 bit seg registers pushed by thunk
+;
+; ebx+24 ES
+; ebx+26 DS
+;
+
+ push ebp
+ mov ebp,esp
+
+;
+; now also (flat parameters called by the thunk)
+;
+; ebp+8 pfnFun
+; ebp+12 pTid
+; ebp+16 pbStack
+;
+
+;
+; makeup a 16 bit saved state for ThreadStarter16
+; we must put this on the new stack, otherwise it can
+; be washed out if the calling thread is scheduled before
+; the new thread
+;
+ push ecx
+ mov eax, [ebp+16]
+
+ sub eax,4 ; save space on stack for DosExit return
+ sub eax,2
+ mov cx, [ebx+34] ; new thread's CS
+ mov [eax], cx
+ sub eax,2
+ mov cx, [ebx+32] ; new thread's IP
+ mov [eax], cx
+ sub eax,2
+ mov cx, [ebx+18] ; new thread's DS
+ mov [eax], cx
+ sub eax,2
+ mov cx, [ebx+16] ; new thread's ES
+ mov [eax], cx
+ sub eax,2
+ mov cx, [ebx+6] ; new thread's DX
+ mov [eax], cx
+ sub eax, 2
+ mov cx, [ebx+8] ; new thread's BX
+ mov [eax], cx
+ sub eax, 2
+ mov cx, [ebx+10] ; new thread's CX
+ mov [eax], cx
+ sub eax, 2
+ mov cx, [ebx+12] ; new thread's SI
+ mov [eax], cx
+ sub eax, 2
+ mov cx, [ebx+14] ; new thread's DI
+ mov [eax], cx
+ sub eax, 2
+ mov cx, [ebx+26] ; new thread's SS
+ mov [eax], cx
+ sub eax,2
+ mov cx, [ebx+24]
+ sub cx,22 ; for DI:SI:CX:BX:DX:ES:DS:IP:CS:DOSEXIT
+ mov [eax], cx ; new thread's SP
+ pop ecx
+
+;
+; Now call DosCreateThread (32b)
+; The 'ThreadParameter' parameter is setup to point to the frame above
+;
+
+; StackSize - set to default (4K for now)
+;
+
+ push 1 ; will be rounded up
+
+; Flags - set to be runnable immediately
+;
+ push DCT_RUNABLE_HIDDEN
+
+; Thread Parameter
+;
+ push dword ptr [ebp+16] ; the new 16 bit stack
+
+; pfnFun
+;
+ push offset FLAT:_Od2ThreadStarter16
+
+; pTid
+;
+ push dword ptr [ebp+12]
+
+ call _DosCreateThread@20 ; call 32-bit version
+
+ leave
+ ret 12 ; return to thunk
+
+_PMNT16CreateThread@12 endp
+
+
+ public _DosExitStub@0
+_DosExitStub@0 proc
+
+ push 0
+ push 0
+ call _DosExit@8
+ leave
+ ret 0
+
+_DosExitStub@0 endp
+
+ public _DosExitProcessStub@0
+_DosExitProcessStub@0 proc
+
+ push 0
+ push 1
+ call _DosExit@8
+
+ leave
+ ret 0
+
+_DosExitProcessStub@0 endp
+
+ public _Od2JumpTo16ExitRoutine@8
+_Od2JumpTo16ExitRoutine@8 proc
+
+ mov bx, [esp+6]
+ lsl ax,bx ;// see if the value is still valid!
+ jz GoodRoutine
+
+ ;
+ ; The CS of the exit routine had become invalid, call DosExitList
+ ; to skip this routine
+ ;
+ pop eax ;// Return addresss (ignore)
+ pop eax ;// ExitRoutine address (ignore)
+ pop eax ;// ExitReason code (ignore)
+
+ ;// push now parameters for DosExitList
+ push 0 ;//
+ push 3 ;// EXLST_EXIT
+ call _DosExitList@8
+
+GoodRoutine:
+ mov _Od2ExitListInProgress, 1
+ call _MoveInfoSegintoTeb
+ pop ecx ;// Return addresss (ignore)
+ pop ecx ;// ExitRoutine address
+ pop edx ;// ExitReason code
+ xor ebp,ebp
+ lss sp,_Od2Start16Stack
+ mov eax,_Od2Start16DS
+ mov ds,ax
+ push dx ;// call (ExitRoutine)(ExitReason)
+ push 0 ; Force GP if returning from the ExitList routine
+ push ecx
+ db 066h, 0cbh ;// do a 16-bit retf
+
+_Od2JumpTo16ExitRoutine@8 endp
+
+
+; Entry point for 16-bit DosFlagProcess
+; Setup call to C code by passing parameters plus pointer to 16-bit registers
+;
+; APIRET
+; DosFlagProcess(
+; ULONG pid,
+; ULONG fScope,
+; ULONG usFlagNum,
+; ULONG usFlagArg)
+;
+; ebp+8 pid
+; ebp+12 fScope
+; ebp+16 usFlagNum
+; ebp+20 usFlagArg
+
+ public DosFlagProcess16@16
+DosFlagProcess16@16 proc
+
+ push ebp
+ mov ebp,esp
+ push ebx ; pointer to 16-bit stack
+ push dword ptr [ebp+20] ; usFlagArg
+ push dword ptr [ebp+16] ; usFlagNum
+ push dword ptr [ebp+12] ; fScope
+ push dword ptr [ebp+8] ; pid
+ call _DosFlagProcess@20
+ pop ebp
+ ret 16
+
+DosFlagProcess16@16 endp
+
+; Entry point for 16-bit DosSendSignal
+; Setup call to C code by passing parameters plus pointer to 16-bit registers
+;
+; APIRET
+; DosSendSignal(
+; ULONG pid,
+; ULONG usSigNumber
+; )
+;
+; ebp+8 pid
+; ebp+12 usSigNumber
+
+ public DosSendSignal16@8
+DosSendSignal16@8 proc
+
+ push ebp
+ mov ebp,esp
+ push ebx ; pointer to 16-bit stack
+ push dword ptr [ebp+12] ; usSigNumber
+ push dword ptr [ebp+8] ; pid
+ call _DosSendSignal@12
+ pop ebp
+ ret 8
+
+DosSendSignal16@8 endp
+
+; Entry point for 16-bit DosHoldSignal
+; Setup call to C code by passing parameters plus pointer to 16-bit registers
+;
+; APIRET
+; DosHoldSignal(
+; ULONG fDisable
+; )
+;
+; ebp+8 fDisable
+
+ public DosHoldSignal16@4
+DosHoldSignal16@4 proc
+
+ push ebp
+ mov ebp,esp
+ push ebx ; pointer to 16-bit stack
+ push dword ptr [ebp+8] ; fDisable
+ call _DosHoldSignal@8
+ pop ebp
+ ret 4
+
+DosHoldSignal16@4 endp
+
+ public _SaveFSSeg@4
+_SaveFSSeg@4 proc
+ push edi
+ mov edi, [esp+8]
+ mov eax,dword ptr fs:0
+ mov dword ptr [edi],eax
+ mov eax,dword ptr fs:4
+ mov dword ptr [edi+4],eax
+ mov eax,dword ptr fs:8
+ mov dword ptr [edi+8],eax
+ mov eax,dword ptr fs:12
+ mov dword ptr [edi+12],eax
+ mov eax,dword ptr fs:16
+ mov dword ptr [edi+16],eax
+ mov eax,dword ptr fs:20
+ mov dword ptr [edi+20],eax
+ mov eax,dword ptr fs:24
+ mov dword ptr [edi+24],eax
+ mov eax,dword ptr fs:28
+ mov dword ptr [edi+28],eax
+ mov eax,dword ptr fs:32
+ mov dword ptr [edi+32],eax
+ mov eax,dword ptr fs:36
+ mov dword ptr [edi+36],eax
+ pop edi
+ ret 4
+_SaveFSSeg@4 endp
+
+ public _RestoreFSSeg@4
+_RestoreFSSeg@4 proc
+ push esi
+ mov esi, [esp+8]
+ mov eax, dword ptr [esi+36]
+ mov dword ptr fs:36, eax
+ mov eax, dword ptr [esi]
+ mov dword ptr fs:0, eax
+ mov eax, dword ptr [esi+4]
+ mov dword ptr fs:4, eax
+ mov eax, dword ptr [esi+8]
+ mov dword ptr fs:8, eax
+ mov eax, dword ptr [esi+12]
+ mov dword ptr fs:12, eax
+ mov eax, dword ptr [esi+16]
+ mov dword ptr fs:16, eax
+ mov eax, dword ptr [esi+20]
+ mov dword ptr fs:20, eax
+ mov eax, dword ptr [esi+24]
+ mov dword ptr fs:24, eax
+ mov eax, dword ptr [esi+28]
+ mov dword ptr fs:28, eax
+ mov eax, dword ptr [esi+32]
+ mov dword ptr fs:32, eax
+ pop esi
+ ret 4
+_RestoreFSSeg@4 endp
+
+ public _MoveInfoSegintoTeb
+_MoveInfoSegintoTeb proc
+
+ ;
+ ; We are using this entry point
+ ; to suspend threads going to 16
+ ; bit when DosEnterCritSect is
+ ; in power, and no signal processing
+ ;
+ push ebp
+ mov ebp, esp
+ push eax
+ push ebx
+ push ecx
+ push edx
+ call _Od2CheckForCritSectOrSuspend@0
+ cmp _Od2GetInfoSegWasCalled, 0
+ je minfo2
+
+ call _Od2GetTebInfoSeg@0 ; eax contains pointer to InfoSeg
+ cmp dword ptr [eax+36],0
+ jnz minfo2 ; We are already in 16 bit
+
+ push eax
+ add eax,40
+
+
+ push eax
+ call _SaveFSSeg@4 ;Save TEB backup copy
+
+ call _RestoreFSSeg@4
+
+minfo2:
+ pop edx
+ pop ecx
+ pop ebx
+ pop eax
+ pop ebp
+ ret
+
+_MoveInfoSegintoTeb endp
+
+;
+; IMORTANT !!!
+; This routine is used in thunk. EBX register must not be used inside it. This
+; value will be used by signal handler as pointer to 16bit stack in the case that
+; it will interrupt thread1 in thunk entry.
+;
+ public _RestoreTeb
+_RestoreTeb proc
+
+ cmp _Od2GetInfoSegWasCalled, 0
+ je rteb2
+ cmp dword ptr fs:36,0
+ jnz rteb2 ; We are already in 32 bit
+
+ push eax
+ push esi
+rtebContinue1:
+ mov esi, dword ptr fs:32
+rtebContinue2:
+
+ mov eax, dword ptr [esi]
+ mov dword ptr fs:0, eax
+ mov eax, dword ptr [esi+4]
+ mov dword ptr fs:4, eax
+ mov eax, dword ptr [esi+8]
+ mov dword ptr fs:8, eax
+ mov eax, dword ptr [esi+12]
+ mov dword ptr fs:12, eax
+ mov eax, dword ptr [esi+16]
+ mov dword ptr fs:16, eax
+ mov eax, dword ptr [esi+20]
+ mov dword ptr fs:20, eax
+ mov eax, dword ptr [esi+24]
+ mov dword ptr fs:24, eax
+ mov eax, dword ptr [esi+28]
+ mov dword ptr fs:28, eax
+ mov eax, dword ptr [esi+32]
+ mov dword ptr fs:32, eax
+ mov eax, dword ptr [esi+36]
+ mov dword ptr fs:36, eax
+
+ pop esi
+ pop eax
+rteb2:
+ ret
+
+_RestoreTeb endp
+
+; Restore TEB for exit list dispatcher. The address of TEB backup will be taken
+; from thread1 structure.
+; This function is the spouse of RestoreTeb and it is similar. The only difference that
+; we try to get TEB save block directly from the thread structure.
+
+ public _RestoreTebForThread1
+_RestoreTebForThread1 proc
+
+ cmp _Od2GetInfoSegWasCalled, 0
+ je rteb2
+ cmp dword ptr fs:36, 0 ;CID thread in TEB
+ jnz rteb2
+
+ push eax
+ push esi
+ push ebx
+ push ecx
+ push edx
+ call _Od2GetThread1TebBackup@0 ;fs:32 can be overwritten with
+ ;enviroment pointer
+ pop edx
+ pop ecx
+ pop ebx
+ test eax, eax
+ jz rtebContinue1 ;we failed to find thread1, use
+ ;the saved pointer.
+ mov esi, eax
+ jmp rtebContinue2
+_RestoreTebForThread1 endp
+
+ public _Od2GetFSSelector@0
+_Od2GetFSSelector@0 proc
+
+ mov ax, fs
+ ret
+
+_Od2GetFSSelector@0 endp
+
+;
+;VOID
+;Od2JumpTo16NetBiosPostDispatcher(
+; IN PVOID pUsersPostRoutine, // CS:IP format EBP+8
+; IN PVOID UserStackFlat, // Flat pointer to user stack EBP+12
+; IN USHORT UserStackSize, // User stack size EBP+16
+; IN SEL UserStackSel, // Data selector to user stack EBP+20
+; IN SEL UserStackAlias, // Code selector to user stack EBP+24
+; IN PVOID pNcb, // 16 bit SEG:OFF ptr to NCB EBP+28
+; IN UCHAR NcbRetCode // return code from NCB EBP+32
+; );
+;
+; This routine is used to call a user's 16 bit net bios post routine.
+; It thunks to the 16 bit code, and thunks back on user's return.
+;
+; Parameters:
+; pUsersPostRoutine -- 16 bit far ptr to user's routine (which should end with a far return)
+; UserStackFlat -- a 32 bit flat pointer to a 16-bit stack for the user to use
+; UserStackSize -- a 16 bit value specifying the size of the stack
+; UserStackSel -- a 16 bit selector to the segment containing the stack
+; UserStackAlias -- a 16 bit code selector alias for the stack selector
+; pNcb -- a 16 bit far ptr to be passed to user's routine in ES:BX
+; NcbRetCode -- a byte to be passed to user's routine in AL (with AH = 0)
+;
+; Operation:
+;
+; On the top of the user's stack it prepares a 24 byte area that looks like this:
+;
+; A. 8 bytes -- a 32 bit far jump instruction to NetBiosDispatcherReturnPoint.
+; this will be used by the user to return.
+; B. 8 bytes -- an aligned 48 bit pointer saving the current 32 bit stack pointer
+; prior to entry into the user's stack and routine
+; C. 4 bytes -- a 16 bit far pointer to the point in the stack designated by A above.
+; This is the return address prepared for the user. When he RETF's on this
+; address he will jump to area A which contains a jump instruction back to
+; our code. Note that the selector in this pointer is a code alias for the
+; stack segment.
+; D. 4 bytes -- The pointer pUsersPostRoutine. We RETF on this pointer in order to jump to
+; the user's routine.
+;
+; When the stack is ready, it loads the registers and the new stackpointer, and then does a far
+; return to jump to the user's routine.
+; On return from the user's routine, the stack is restored back to its original state, we clean
+; up, and return.
+;
+
+
+ public _Od2JumpTo16NetBiosPostDispatcher@28
+_Od2JumpTo16NetBiosPostDispatcher@28 proc
+
+ push ebp
+ mov ebp, esp
+
+; save registers
+
+ push esi
+ push edi
+ push ebx
+ push es
+ push ds
+
+;
+; Save the esp for later use by the thread when it will call APIs
+;
+ mov eax, esp
+ push eax
+ call _Save32Esp@4
+ call _MoveInfoSegintoTeb
+
+; get esi to point to end of user's stack
+
+ mov esi, dword ptr [ebp+12]
+ mov word ptr [ebp+18], 0
+ add esi, dword ptr [ebp+16]
+
+; put a 32 bit far jmp NetBiosDispatcherReturnPoint on user's stack
+
+ mov word ptr [esi-8], 0ea66h
+ mov dword ptr [esi-6], offset NetBiosDispatcherReturnPoint
+ mov word ptr [esi-2], cs
+
+; save my own stack pointer
+
+ mov dword ptr [esi-16], esp
+ mov word ptr [esi-12], ss
+
+; set up return address for user
+
+ mov ax, word ptr [ebp+24]
+ mov word ptr [esi-18], ax
+ mov ax, word ptr [ebp+16]
+ sub ax, 8
+ mov word ptr [esi-20], ax
+
+; set up user's post routine address on user stack so we can RET to it
+
+ mov eax, dword ptr [ebp+8]
+ mov dword ptr [esi-24], eax
+
+; set up ES:BX and AX for user
+
+ les bx, dword ptr [ebp+28]
+ movzx ax, byte ptr [ebp+32]
+
+; set up stack pointer for user
+
+ sub word ptr [ebp+16], 24
+ lss esp, [ebp+16]
+
+; jump to user's routine (with a 16 bit far return)
+
+ dw 0cb66h
+
+NetBiosDispatcherReturnPoint:
+
+; comes here after user routine finishes (returns with 16 bit far ret)
+
+; start off by restoring my original stack pointer
+
+ movzx ebp, sp
+ lss esp, [ebp]
+ pop ds
+ pop es
+
+;
+
+ call _RestoreTeb
+
+; restore original registers, and return to caller
+
+ pop ebx
+ pop edi
+ pop esi
+
+ pop ebp
+ ret 28
+
+_Od2JumpTo16NetBiosPostDispatcher@28 endp
+
+;
+; A utility routine to verify a segment for write.
+; returns:
+; 1 if segment reachable
+; 0 if segment not reachable
+; Implemented using inline i386 VERW instruction
+;
+; int
+; IsLegalSelector(
+; unsigned short aSelector)
+;
+PUBLIC _IsLegalSelector
+_IsLegalSelector PROC
+ push ebp
+ mov ebp, esp
+ mov eax, 1 ; assume Selector is reachable
+ verw WORD PTR [ebp+8] ; verify the selector
+ je addr_ok ; exit if reachable
+ mov eax, 0 ; address not reachable
+addr_ok:
+ leave
+ ret
+_IsLegalSelector ENDP
+
+;
+; IMPORTANT !!!
+; Changing the code below (Od2SetSegmentRegisters and Od2Continue) check the follows:
+; - Od2GetSegmentRegisters (dlltask.c)
+; - Od2PrepareEnterToSignalHandler (dlltask.c)
+; - Od2JumpTo16SignalDispatch (ldrstart.asm)
+; - Entry flat and Exit flat (doscalls.asm)
+; - Os2SignalGetThreadContext (srvxcpt.c)
+;
+
+ public _Od2SetSegmentRegisters@0
+_Od2SetSegmentRegisters@0 proc
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES
+ mov es,ax
+ jmp ESFixed
+FixES:
+ xor ax,ax
+ mov es,ax
+ESFixed:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS
+ mov ds,ax
+ jmp DSFixed
+FixDS:
+ xor ax,ax
+ mov ds,ax
+DSFixed:
+ ret
+ public _Od2SetSegmentRegistersEnd@0
+_Od2SetSegmentRegistersEnd@0:
+_Od2SetSegmentRegisters@0 endp
+
+;
+; The susbstitute for NtContinue. Return to the interrupted context.
+; Parameter : pContext <- esp+4
+; ret <- esp
+; pContext :
+; ES ;0
+; DS ;4
+; EDI ;8
+; ESI ;12
+; EBX ;16
+; EDX ;20
+; ECX ;24
+; EAX ;28
+; EBP ;32
+; EIP ;36
+; CS ;40
+; EFLAGS ;44
+; ESP ;48
+; SS ;52
+; There are 3 types of context:
+; - 32bit stack, 32bit code (32bit)
+; - 16bit stack, 16bit code (16bit)
+; - 16bit stack, 32bit code (thunk)
+;
+public _Od2Continue@4
+_Od2Continue@4 proc
+
+ mov eax,dword ptr [esp+4] ;eax - pointer to context
+ ;
+ ; restore registers that we will never use more
+ ;
+ mov ebp,dword ptr [eax+32] ;EBP
+ mov edi,dword ptr [eax+8] ;EDI
+ mov esi,dword ptr [eax+12] ;ESI
+
+ ;
+ ; check if the interrupted context is 32bit
+ ;
+ cmp word ptr [eax+52],23H ;SS
+ jne Od2Continue16bit
+
+ ;
+ ; 32bit
+ ;
+ ; | |
+ ; --------- <- ESP of interrupted context
+ ; | EIP |
+ ; | EAX |
+ ; ---------
+ ;
+ mov ebx,dword ptr [eax+16] ;EBX
+
+ sub dword ptr [eax+48],8 ;ESP-8
+ mov edx,dword ptr [eax+48] ;ESP
+ mov ecx,dword ptr [eax+28] ;EAX
+ mov dword ptr [edx], ecx
+ mov ecx,dword ptr [eax+36] ;EIP
+ mov dword ptr [edx+4],ecx
+
+ mov edx,dword ptr [eax+20] ;EDX
+ mov ecx,dword ptr [eax+24] ;ECX
+ push dword ptr [eax+44] ;EFlags
+ popfd
+
+ mov esp,dword ptr [eax+48] ;ESP
+
+ pop eax
+ ret
+ ;
+ ; 16bit or thunk
+ ;
+ ; 16 bytes of the 16bit stack beyond it's top will be used:
+ ; | |
+ ; ------------- <- SP of interrupted context
+ ; | ret address |
+ ; | EAX |
+ ; | EFlags |
+ ; ------------- <- temprorary stack top (EDX)
+Od2Continue16bit:
+ sub word ptr [eax+48],12 ;SP - substruct 12 bytes
+ ;
+ ; calculate the flat address of the temprorary stack top
+ ;
+ mov ebx,dword ptr [eax+52] ;SS
+ shr bx,3
+ add bx,3800H
+ shl ebx,16
+ mov bx,word ptr [eax+48] ;EBX == temprorary stack top
+
+ ;
+ ; Set the values of EAX, DS and ES to 16bit stack
+ ;
+ mov ecx,dword ptr [eax+28] ;EAX
+ mov dword ptr [ebx+4],ecx
+ mov ecx,dword ptr [eax+44] ;EFlags
+ mov dword ptr [ebx],ecx
+ mov dx,word ptr [eax+4] ;DS
+ cmp dx,23H
+ je Od2ContinueThunkFlat
+ shl edx,16
+ mov cx,word ptr [eax] ;ES
+ cmp dx,23H
+ je Od2ContinueThunkFlat
+ shl ecx,16
+
+ ;
+ ; check if the interrupted context was 16bit or thunk
+ ;
+ cmp word ptr [eax+40],1bH ;CS
+ je Od2ContinueThunk
+
+ ;
+ ; 16 bit
+ ;
+ ;
+ ; Copy CS:IP to the 16bit stack
+ ;
+ mov cx,word ptr [eax+40] ;CS
+ mov word ptr [ebx+10],cx
+ mov cx,word ptr [eax+36] ;IP
+ mov word ptr [ebx+8],cx
+
+ mov ebx,dword ptr [eax+16] ;EBX
+ mov cx,word ptr [eax+24] ;ECX
+ mov dx,word ptr [eax+20] ;EDX
+
+ public _Od2ContinueStartBorder@0
+_Od2ContinueStartBorder@0:
+ lss esp,[eax+48] ;ESP:SS
+ call _Od2SetSegmentRegisters@0
+ popfd
+ pop eax
+ db 66h, 0cah ; 16-bit retf
+ dw 0 ; 16-bit parameters
+
+Od2ContinueThunk:
+
+ ;
+ ; Thunk to 16 bit
+ ;
+ ;
+ ; Copy EIP to the 16bit stack
+ ;
+ mov ecx,dword ptr [eax+36] ;EIP
+ mov dword ptr [ebx+8],ecx
+
+ mov ebx,dword ptr [eax+16] ;EBX
+ mov cx,word ptr [eax+24] ;ECX
+ mov dx,word ptr [eax+20] ;EDX
+
+ lss esp,[eax+48] ;ESP:SS
+ call _Od2SetSegmentRegisters@0
+ popfd
+ pop eax
+ ret
+public _Od2ContinueEndBorder@0
+_Od2ContinueEndBorder@0:
+
+Od2ContinueThunkFlat:
+
+ ;
+ ; Return to Thunk that use flat registers (or Entry flat or part of JumpTo16)
+ ;
+ ;
+ ; Copy EIP to the 16bit stack
+ ;
+ mov ecx,dword ptr [eax+36] ;EIP
+ mov dword ptr [ebx+8],ecx
+
+ mov ebx,dword ptr [eax+16] ;EBX
+ mov ecx,dword ptr [eax+24] ;ECX
+ mov edx,dword ptr [eax+20] ;EDX
+
+ lss esp,[eax+48] ;ESP:SS
+ popfd
+ pop eax
+ ret
+_Od2Continue@4 endp
+
+IFDEF PMNT
+
+EXTRN _PMNT_DosLockSeg@4:PROC
+EXTRN _PMNT_DosUnlockSeg@4:PROC
+EXTRN _LNotesPatchLock@4:PROC
+EXTRN _LNotesPatchUnlock@4:PROC
+
+ public _DosLockSeg@4
+_DosLockSeg@4 proc
+ push ebx
+ push dword ptr [esp+8]
+ call _PMNT_DosLockSeg@4
+ test eax,eax
+ jnz DosLockSegExit_1
+ call _LNotesPatchLock@4
+ xor eax,eax
+ ret 4
+DosLockSegExit_1:
+ pop ebx
+ ret 4
+_DosLockSeg@4 endp
+
+ public _DosUnlockSeg@4
+_DosUnlockSeg@4 proc
+ push dword ptr [esp+4]
+ push ebx
+ call _LNotesPatchUnlock@4
+ call _PMNT_DosUnlockSeg@4
+ ret 4
+_DosUnlockSeg@4 endp
+
+ENDIF
+
+_TEXT ends
+ end
+
diff --git a/private/os2/client/i386/dllthunk.asm b/private/os2/client/i386/dllthunk.asm
new file mode 100644
index 000000000..534208916
--- /dev/null
+++ b/private/os2/client/i386/dllthunk.asm
@@ -0,0 +1,111 @@
+ title "OS/2 Client Thunks"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; dllthunk.asm
+;
+; Abstract:
+;
+; This module contains callback stubs that allow the OS/2 Emulation
+; Subsystem Server.
+;
+; Author:
+;
+; Steve Wood (stevewo) 20-Oct-1989
+;
+; Revision History:
+;
+;--
+
+.386p
+ .xlist
+include ks386.inc
+ .list
+
+ extrn _NtCurrentTeb@0:PROC
+ extrn _Od2ExitListDispatcher@0:PROC
+ extrn _Od2InfiniteSleep@0:PROC
+ extrn _Od2SignalDeliverer@8:PROC
+ extrn _Od2ProcessSignal16@8:PROC
+ extrn _Od2FreezeThread@8:PROC
+ extrn _Od2UnfreezeThread@8:PROC
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ public __Od2ExitListDispatcher@0
+__Od2ExitListDispatcher@0 proc
+
+ call _Od2ExitListDispatcher@0
+
+__Od2ExitListDispatcher@0 endp
+
+public __Od2InfiniteSleep@0
+__Od2InfiniteSleep@0 proc
+
+ call _Od2InfiniteSleep@0
+
+__Od2InfiniteSleep@0 endp
+
+ public _Od2JumpToExitRoutine@8
+_Od2JumpToExitRoutine@8 proc
+
+ call _NtCurrentTeb@0
+ pop ecx ;// Return addresss (ignore)
+ pop ecx ;// ExitRoutine address
+ pop edx ;// ExitReason code
+ mov esp,TbStackBase[eax] ;// Reset stack
+ xor ebp,ebp
+ push edx ;// call (ExitRoutine)(ExitReason)
+ call ecx
+
+_Od2JumpToExitRoutine@8 endp
+
+;
+; stack looks like this:
+;
+; Context
+; pContext
+; signal
+; rc <- esp
+;
+
+ public __Od2SignalDeliverer@8
+__Od2SignalDeliverer@8 proc
+
+ mov [esp+8].CsEax,eax
+ call _Od2SignalDeliverer@8
+ ret ; just in case
+
+__Od2SignalDeliverer@8 endp
+
+ public __Od2ProcessSignal16@4
+__Od2ProcessSignal16@4 proc
+
+ push eax ; The right value of EAX
+ call _Od2ProcessSignal16@8
+ ret ; just in case
+
+__Od2ProcessSignal16@4 endp
+
+ public __Od2FreezeThread@4
+__Od2FreezeThread@4 proc
+ push eax
+ call _Od2FreezeThread@8
+ ret
+__Od2FreezeThread@4 endp
+
+ public __Od2UnfreezeThread@4
+__Od2UnfreezeThread@4 proc
+ push eax
+ call _Od2UnfreezeThread@8
+ ret
+__Od2UnfreezeThread@4 endp
+
+
+_TEXT ends
+ end
+ \ No newline at end of file
diff --git a/private/os2/client/i386/doscalls.asm b/private/os2/client/i386/doscalls.asm
new file mode 100644
index 000000000..e5c5d5926
--- /dev/null
+++ b/private/os2/client/i386/doscalls.asm
@@ -0,0 +1,19738 @@
+ page ,132
+
+;Thunk Compiler Version 2.06 Jul 18 1994 14:16:10
+;File Compiled Mon Jul 18 14:18:44 1994
+
+;Command Line: .\thunkcom\thunk -y -z -NA THUNK32 -NC THUNK16 doscalls.i
+
+ TITLE $doscalls.asm
+
+ .386p
+IFDEF GEN16
+IFDEF GEN32
+%out command line error: you can't specify both -DGEN16 and -DGEN32
+.err
+ENDIF
+
+ OPTION SEGMENT:USE16
+ .model LARGE,PASCAL
+
+externDef DOSEXITSTUB:far16
+externDef LDRLIBIRETURN:far16
+externDef DOSEXITPROCESSSTUB:far16
+externDef DOSRETURN:far16
+externDef DOSEXIT:far16
+externDef DOSCWAIT:far16
+externDef DOSBEEP:far16
+externDef DOSPHYSICALDISK:far16
+externDef DOSGETCP:far16
+externDef DOSSETCP:far16
+externDef DOSSETPROCCP:far16
+externDef DOSGETCTRYINFO:far16
+externDef DOSGETDBCSEV:far16
+externDef DOSCASEMAP:far16
+externDef DOSGETCOLLATE:far16
+externDef DOSSLEEP:far16
+externDef DOSDEVCONFIG:far16
+externDef DOSGETDATETIME:far16
+externDef DOSSETDATETIME:far16
+externDef DOSEXECPGM:far16
+externDef DOSENTERCRITSEC:far16
+externDef DOSEXITCRITSEC:far16
+externDef DOSKILLPROCESS:far16
+externDef DOSSETPRTY:far16
+externDef DOSRESUMETHREAD:far16
+externDef DOSSUSPENDTHREAD:far16
+externDef DOSMAKEPIPE:far16
+externDef DOSCREATEQUEUE:far16
+externDef DOSOPENQUEUE:far16
+externDef DOSCLOSEQUEUE:far16
+externDef DOSPEEKQUEUE:far16
+externDef DOSREADQUEUE:far16
+externDef DOSPURGEQUEUE:far16
+externDef DOSQUERYQUEUE:far16
+externDef DOSWRITEQUEUE:far16
+externDef DOSCALLNMPIPE:far16
+externDef DOSCONNECTNMPIPE:far16
+externDef DOSDISCONNECTNMPIPE:far16
+externDef DOSMAKENMPIPE:far16
+externDef DOSPEEKNMPIPE:far16
+externDef DOSQNMPHANDSTATE:far16
+externDef DOSQNMPIPEINFO:far16
+externDef DOSQNMPIPESEMSTATE:far16
+externDef DOSSETNMPHANDSTATE:far16
+externDef DOSSETNMPIPESEM:far16
+externDef DOSTRANSACTNMPIPE:far16
+externDef DOSWAITNMPIPE:far16
+externDef DOSBUFRESET:far16
+externDef DOSCHDIR:far16
+externDef DOSCHGFILEPTR:far16
+externDef DOSCLOSE:far16
+externDef DOSCOPY:far16
+externDef DOSICOPY:far16
+externDef DOSDELETE:far16
+externDef DOSDEVIOCTL:far16
+externDef DOSDUPHANDLE:far16
+externDef DOSEDITNAME:far16
+externDef DOSFILEIO:far16
+externDef DOSFINDCLOSE:far16
+externDef DOSFSATTACH:far16
+externDef DOSFSCTL:far16
+externDef DOSMOVE:far16
+externDef DOSNEWSIZE:far16
+externDef DOSQCURDIR:far16
+externDef DOSQCURDISK:far16
+externDef DOSQFHANDSTATE:far16
+externDef DOSSETFHANDSTATE:far16
+externDef DOSQFSATTACH:far16
+externDef DOSQFSINFO:far16
+externDef DOSQHANDTYPE:far16
+externDef DOSQVERIFY:far16
+externDef DOSRMDIR:far16
+externDef DOSSEARCHPATH:far16
+externDef DOSSELECTDISK:far16
+externDef DOSSETFSINFO:far16
+externDef DOSSETMAXFH:far16
+externDef DOSSETVERIFY:far16
+externDef DOSERRCLASS:far16
+externDef DOSERROR:far16
+externDef DOSLOADMODULE:far16
+externDef DOSFREEMODULE:far16
+externDef DOSGETMODHANDLE:far16
+externDef DOSGETMODNAME:far16
+externDef DOSGETRESOURCE:far16
+externDef DOSGETRESOURCE2:far16
+externDef DOSFREERESOURCE:far16
+externDef DOSQAPPTYPE:far16
+externDef DOSSHUTDOWN:far16
+externDef DOSCREATETHREAD:far16
+externDef DOSEXITLIST:far16
+externDef DOSGETINFOSEG:far16
+externDef DOSOPEN:far16
+externDef DOSOPEN2:far16
+externDef DOSREAD:far16
+externDef DOSWRITE:far16
+externDef DOSFINDFIRST:far16
+externDef DOSFINDFIRST2:far16
+externDef DOSENUMATTRIBUTE:far16
+externDef DOSQFILEMODE:far16
+externDef DOSQFILEINFO:far16
+externDef DOSALLOCSEG:far16
+externDef DOSFREESEG:far16
+externDef DOSGETSEG:far16
+externDef DOSGIVESEG:far16
+externDef DOSREALLOCSEG:far16
+externDef DOSSIZESEG:far16
+externDef DOSALLOCHUGE:far16
+externDef DOSREALLOCHUGE:far16
+externDef DOSGETHUGESHIFT:far16
+externDef DOSALLOCSHRSEG:far16
+externDef DOSLOCKSEG:far16
+externDef DOSUNLOCKSEG:far16
+externDef DOSGETSHRSEG:far16
+externDef DOSMEMAVAIL:far16
+externDef DOSCREATECSALIAS:far16
+externDef DOSSEMCLEAR:far16
+externDef DOSSEMSET:far16
+externDef DOSSEMWAIT:far16
+externDef DOSSEMSETWAIT:far16
+externDef DOSSEMREQUEST:far16
+externDef DOSCREATESEM:far16
+externDef DOSOPENSEM:far16
+externDef DOSCLOSESEM:far16
+externDef DOSMUXSEMWAIT:far16
+externDef DOSFSRAMSEMREQUEST:far16
+externDef DOSFSRAMSEMCLEAR:far16
+externDef DOSTIMERASYNC:far16
+externDef DOSTIMERSTART:far16
+externDef DOSTIMERSTOP:far16
+externDef DOSGETPROCADDR:far16
+externDef DOSQUERYPROCTYPE:far16
+externDef DOSQUERYRESOURCESIZE:far16
+externDef DOSSETSIGHANDLER:far16
+externDef DOSFLAGPROCESS:far16
+externDef DOSHOLDSIGNAL:far16
+externDef DOSSENDSIGNAL:far16
+externDef DOSSETVEC:far16
+externDef DOSGETENV:far16
+externDef DOSGETVERSION:far16
+externDef DOSGETMACHINEMODE:far16
+externDef DOSFINDNEXT:far16
+externDef DOSGETPID:far16
+externDef DOSGETPPID:far16
+externDef DOSMKDIR:far16
+externDef DOSMKDIR2:far16
+externDef DOSSETFILEMODE:far16
+externDef DOSSETFILEINFO:far16
+externDef DOSTRUEGETMESSAGE:far16
+externDef DOSSCANENV:far16
+externDef DOSPTRACE:far16
+externDef DOSINSMESSAGE:far16
+externDef DOSPUTMESSAGE:far16
+externDef DOSSUBSET:far16
+externDef DOSSUBALLOC:far16
+externDef DOSSUBFREE:far16
+externDef DOSSTARTSESSION:far16
+externDef DOSSTOPSESSION:far16
+externDef DOSSETSESSION:far16
+externDef DOSSELECTSESSION:far16
+externDef DOSSMSETTITLE:far16
+externDef DOSSMPMPRESENT:far16
+externDef WINSETTITLEANDICON:far16
+externDef DOSGETPRTY:far16
+externDef DOSQSYSINFO:far16
+externDef DOSDEVIOCTL2:far16
+externDef DOSICANONICALIZE:far16
+externDef DOSREADASYNC:far16
+externDef DOSWRITEASYNC:far16
+externDef DOSFINDNOTIFYCLOSE:far16
+externDef DOSFINDNOTIFYFIRST:far16
+externDef DOSFINDNOTIFYNEXT:far16
+externDef DOSFILELOCKS:far16
+externDef DOSQPATHINFO:far16
+externDef DOSSETPATHINFO:far16
+externDef DOSPORTACCESS:far16
+externDef DOSCLIACCESS:far16
+externDef WINQUERYPROFILESTRING:far16
+externDef WINQUERYPROFILESIZE:far16
+externDef WINQUERYPROFILEDATA:far16
+externDef WINQUERYPROFILEINT:far16
+externDef WINWRITEPROFILEDATA:far16
+externDef WINWRITEPROFILESTRING:far16
+externDef WINCREATEHEAP:far16
+externDef WINDESTROYHEAP:far16
+externDef WINALLOCMEM:far16
+externDef WINFREEMEM:far16
+externDef WINGETLASTERROR:far16
+externDef VIOSCROLLUP:far16
+externDef VIOGETCURPOS:far16
+externDef VIOSETCURPOS:far16
+externDef VIOWRTTTY:far16
+externDef VIOGETMODE:far16
+externDef VIOREADCELLSTR:far16
+externDef VIOSCROLLLF:far16
+externDef VIOREADCHARSTR:far16
+externDef VIOWRTCHARSTRATT:far16
+externDef VIOWRTCELLSTR:far16
+externDef VIOWRTCHARSTR:far16
+externDef VIOWRTNCELL:far16
+externDef VIOWRTNATTR:far16
+externDef VIOWRTNCHAR:far16
+externDef VIOSCROLLDN:far16
+externDef VIOSCROLLRT:far16
+externDef VIOGETANSI:far16
+externDef VIOSETANSI:far16
+externDef VIOGETCONFIG:far16
+externDef VIOGETCP:far16
+externDef VIOSETCP:far16
+externDef VIOGETCURTYPE:far16
+externDef VIOSETCURTYPE:far16
+externDef VIOSETMODE:far16
+externDef VIODEREGISTER:far16
+externDef VIOREGISTER:far16
+externDef VIOPOPUP:far16
+externDef VIOENDPOPUP:far16
+externDef VIOGETBUF:far16
+externDef VIOSHOWBUF:far16
+externDef VIOGETFONT:far16
+externDef VIOSETFONT:far16
+externDef VIOGETSTATE:far16
+externDef VIOSETSTATE:far16
+externDef VIOGETPHYSBUF:far16
+externDef VIOMODEUNDO:far16
+externDef VIOMODEWAIT:far16
+externDef VIOSAVREDRAWWAIT:far16
+externDef VIOSAVREDRAWUNDO:far16
+externDef VIOSCRLOCK:far16
+externDef VIOSCRUNLOCK:far16
+externDef VIOPRTSC:far16
+externDef VIOPRTSCTOGGLE:far16
+externDef KBDFLUSHBUFFER:far16
+externDef KBDGETSTATUS:far16
+externDef KBDSETSTATUS:far16
+externDef KBDPEEK:far16
+externDef KBDCHARIN:far16
+externDef KBDSTRINGIN:far16
+externDef KBDGETFOCUS:far16
+externDef KBDFREEFOCUS:far16
+externDef KBDCLOSE:far16
+externDef KBDOPEN:far16
+externDef KBDDEREGISTER:far16
+externDef KBDREGISTER:far16
+externDef KBDGETCP:far16
+externDef KBDSETCP:far16
+externDef KBDSETCUSTXT:far16
+externDef KBDXLATE:far16
+externDef KBDGETHWID:far16
+externDef KBDSETFGND:far16
+externDef KBDSYNCH:far16
+externDef KBDSHELLINIT:far16
+externDef MOUCLOSE:far16
+externDef MOUDEREGISTER:far16
+externDef MOUDRAWPTR:far16
+externDef MOUFLUSHQUE:far16
+externDef MOUGETDEVSTATUS:far16
+externDef MOUGETEVENTMASK:far16
+externDef MOUGETNUMBUTTONS:far16
+externDef MOUGETNUMMICKEYS:far16
+externDef MOUGETNUMQUEEL:far16
+externDef MOUGETPTRPOS:far16
+externDef MOUGETPTRSHAPE:far16
+externDef MOUGETSCALEFACT:far16
+externDef MOUOPEN:far16
+externDef MOUREADEVENTQUE:far16
+externDef MOUREGISTER:far16
+externDef MOUREMOVEPTR:far16
+externDef MOUSETDEVSTATUS:far16
+externDef MOUSETEVENTMASK:far16
+externDef MOUSETPTRPOS:far16
+externDef MOUSETPTRSHAPE:far16
+externDef MOUSETSCALEFACT:far16
+externDef MOUSYNCH:far16
+externDef DOSMONOPEN:far16
+externDef DOSMONCLOSE:far16
+externDef DOSMONREAD:far16
+externDef DOSMONREG:far16
+externDef DOSMONWRITE:far16
+externDef NETGETDCNAME:far16
+externDef NETHANDLEGETINFO:far16
+externDef NETSERVERDISKENUM:far16
+externDef NETSERVERENUM2:far16
+externDef NETSERVERGETINFO:far16
+externDef NETSERVICECONTROL:far16
+externDef NETSERVICEENUM:far16
+externDef NETSERVICEGETINFO:far16
+externDef NETSERVICEINSTALL:far16
+externDef NETSHAREENUM:far16
+externDef NETSHAREGETINFO:far16
+externDef NETUSEADD:far16
+externDef NETUSEDEL:far16
+externDef NETUSEENUM:far16
+externDef NETUSEGETINFO:far16
+externDef NETUSERENUM:far16
+externDef NETWKSTAGETINFO:far16
+externDef NETACCESSADD:far16
+externDef NETACCESSSETINFO:far16
+externDef NETACCESSGETINFO:far16
+externDef NETACCESSDEL:far16
+externDef NETSHAREADD:far16
+externDef NETSHAREDEL:far16
+externDef NETUSERGETINFO:far16
+externDef NETMESSAGEBUFFERSEND:far16
+externDef NETBIOS:far16
+externDef NETBIOSCLOSE:far16
+externDef NETBIOSENUM:far16
+externDef NETBIOSGETINFO:far16
+externDef NETBIOSOPEN:far16
+externDef NETBIOSSUBMIT:far16
+externDef DOSMAKEMAILSLOT:far16
+externDef DOSDELETEMAILSLOT:far16
+externDef DOSMAILSLOTINFO:far16
+externDef DOSPEEKMAILSLOT:far16
+externDef DOSREADMAILSLOT:far16
+externDef DOSWRITEMAILSLOT:far16
+externDef DOSIREMOTEAPI:far16
+externDef NETIWKSTAGETUSERINFO:far16
+externDef NETIUSERPASSWORDSET:far16
+externDef DOSIENCRYPTSES:far16
+externDef DOS32LOADMODULE:far16
+externDef DOS32GETPROCADDR:far16
+externDef DOS32DISPATCH:far16
+externDef DOS32FREEMODULE:far16
+externDef FARPTR2FLATPTR:far16
+externDef FLATPTR2FARPTR:far16
+externDef _EntryFlat@0:far32
+
+ .code THUNK16
+
+;===========================================================================
+; This is the table of 16-bit entry points.
+; It must be at the beginning of its segment.
+; The entries are each 4 bytes apart, and the effect of the
+; call instruction is to push the offset (+4) into the flat
+; thunk table, used after the jump to 32-bit-land.
+
+DOSEXITSTUB label far16
+ nop
+ call EntryCommon16
+
+LDRLIBIRETURN label far16
+ nop
+ call EntryCommon16
+
+DOSEXITPROCESSSTUB label far16
+ nop
+ call EntryCommon16
+
+DOSRETURN label far16
+ nop
+ call EntryCommon16
+
+DOSEXIT label far16
+ nop
+ call EntryCommon16
+
+DOSCWAIT label far16
+ nop
+ call EntryCommon16
+
+DOSBEEP label far16
+ nop
+ call EntryCommon16
+
+DOSPHYSICALDISK label far16
+ nop
+ call EntryCommon16
+
+DOSGETCP label far16
+ nop
+ call EntryCommon16
+
+DOSSETCP label far16
+ nop
+ call EntryCommon16
+
+DOSSETPROCCP label far16
+ nop
+ call EntryCommon16
+
+DOSGETCTRYINFO label far16
+ nop
+ call EntryCommon16
+
+DOSGETDBCSEV label far16
+ nop
+ call EntryCommon16
+
+DOSCASEMAP label far16
+ nop
+ call EntryCommon16
+
+DOSGETCOLLATE label far16
+ nop
+ call EntryCommon16
+
+DOSSLEEP label far16
+ nop
+ call EntryCommon16
+
+DOSDEVCONFIG label far16
+ nop
+ call EntryCommon16
+
+DOSGETDATETIME label far16
+ nop
+ call EntryCommon16
+
+DOSSETDATETIME label far16
+ nop
+ call EntryCommon16
+
+DOSEXECPGM label far16
+ nop
+ call EntryCommon16
+
+DOSENTERCRITSEC label far16
+ nop
+ call EntryCommon16
+
+DOSEXITCRITSEC label far16
+ nop
+ call EntryCommon16
+
+DOSKILLPROCESS label far16
+ nop
+ call EntryCommon16
+
+DOSSETPRTY label far16
+ nop
+ call EntryCommon16
+
+DOSRESUMETHREAD label far16
+ nop
+ call EntryCommon16
+
+DOSSUSPENDTHREAD label far16
+ nop
+ call EntryCommon16
+
+DOSMAKEPIPE label far16
+ nop
+ call EntryCommon16
+
+DOSCREATEQUEUE label far16
+ nop
+ call EntryCommon16
+
+DOSOPENQUEUE label far16
+ nop
+ call EntryCommon16
+
+DOSCLOSEQUEUE label far16
+ nop
+ call EntryCommon16
+
+DOSPEEKQUEUE label far16
+ nop
+ call EntryCommon16
+
+DOSREADQUEUE label far16
+ nop
+ call EntryCommon16
+
+DOSPURGEQUEUE label far16
+ nop
+ call EntryCommon16
+
+DOSQUERYQUEUE label far16
+ nop
+ call EntryCommon16
+
+DOSWRITEQUEUE label far16
+ nop
+ call EntryCommon16
+
+DOSCALLNMPIPE label far16
+ nop
+ call EntryCommon16
+
+DOSCONNECTNMPIPE label far16
+ nop
+ call EntryCommon16
+
+DOSDISCONNECTNMPIPE label far16
+ nop
+ call EntryCommon16
+
+DOSMAKENMPIPE label far16
+ nop
+ call EntryCommon16
+
+DOSPEEKNMPIPE label far16
+ nop
+ call EntryCommon16
+
+DOSQNMPHANDSTATE label far16
+ nop
+ call EntryCommon16
+
+DOSQNMPIPEINFO label far16
+ nop
+ call EntryCommon16
+
+DOSQNMPIPESEMSTATE label far16
+ nop
+ call EntryCommon16
+
+DOSSETNMPHANDSTATE label far16
+ nop
+ call EntryCommon16
+
+DOSSETNMPIPESEM label far16
+ nop
+ call EntryCommon16
+
+DOSTRANSACTNMPIPE label far16
+ nop
+ call EntryCommon16
+
+DOSWAITNMPIPE label far16
+ nop
+ call EntryCommon16
+
+DOSBUFRESET label far16
+ nop
+ call EntryCommon16
+
+DOSCHDIR label far16
+ nop
+ call EntryCommon16
+
+DOSCHGFILEPTR label far16
+ nop
+ call EntryCommon16
+
+DOSCLOSE label far16
+ nop
+ call EntryCommon16
+
+DOSCOPY label far16
+ nop
+ call EntryCommon16
+
+DOSICOPY label far16
+ nop
+ call EntryCommon16
+
+DOSDELETE label far16
+ nop
+ call EntryCommon16
+
+DOSDEVIOCTL label far16
+ nop
+ call EntryCommon16
+
+DOSDUPHANDLE label far16
+ nop
+ call EntryCommon16
+
+DOSEDITNAME label far16
+ nop
+ call EntryCommon16
+
+DOSFILEIO label far16
+ nop
+ call EntryCommon16
+
+DOSFINDCLOSE label far16
+ nop
+ call EntryCommon16
+
+DOSFSATTACH label far16
+ nop
+ call EntryCommon16
+
+DOSFSCTL label far16
+ nop
+ call EntryCommon16
+
+DOSMOVE label far16
+ nop
+ call EntryCommon16
+
+DOSNEWSIZE label far16
+ nop
+ call EntryCommon16
+
+DOSQCURDIR label far16
+ nop
+ call EntryCommon16
+
+DOSQCURDISK label far16
+ nop
+ call EntryCommon16
+
+DOSQFHANDSTATE label far16
+ nop
+ call EntryCommon16
+
+DOSSETFHANDSTATE label far16
+ nop
+ call EntryCommon16
+
+DOSQFSATTACH label far16
+ nop
+ call EntryCommon16
+
+DOSQFSINFO label far16
+ nop
+ call EntryCommon16
+
+DOSQHANDTYPE label far16
+ nop
+ call EntryCommon16
+
+DOSQVERIFY label far16
+ nop
+ call EntryCommon16
+
+DOSRMDIR label far16
+ nop
+ call EntryCommon16
+
+DOSSEARCHPATH label far16
+ nop
+ call EntryCommon16
+
+DOSSELECTDISK label far16
+ nop
+ call EntryCommon16
+
+DOSSETFSINFO label far16
+ nop
+ call EntryCommon16
+
+DOSSETMAXFH label far16
+ nop
+ call EntryCommon16
+
+DOSSETVERIFY label far16
+ nop
+ call EntryCommon16
+
+DOSERRCLASS label far16
+ nop
+ call EntryCommon16
+
+DOSERROR label far16
+ nop
+ call EntryCommon16
+
+DOSLOADMODULE label far16
+ nop
+ call EntryCommon16
+
+DOSFREEMODULE label far16
+ nop
+ call EntryCommon16
+
+DOSGETMODHANDLE label far16
+ nop
+ call EntryCommon16
+
+DOSGETMODNAME label far16
+ nop
+ call EntryCommon16
+
+DOSGETRESOURCE label far16
+ nop
+ call EntryCommon16
+
+DOSGETRESOURCE2 label far16
+ nop
+ call EntryCommon16
+
+DOSFREERESOURCE label far16
+ nop
+ call EntryCommon16
+
+DOSQAPPTYPE label far16
+ nop
+ call EntryCommon16
+
+DOSSHUTDOWN label far16
+ nop
+ call EntryCommon16
+
+DOSCREATETHREAD label far16
+ nop
+ call EntryCommon16
+
+DOSEXITLIST label far16
+ nop
+ call EntryCommon16
+
+DOSGETINFOSEG label far16
+ nop
+ call EntryCommon16
+
+DOSOPEN label far16
+ nop
+ call EntryCommon16
+
+DOSOPEN2 label far16
+ nop
+ call EntryCommon16
+
+DOSREAD label far16
+ nop
+ call EntryCommon16
+
+DOSWRITE label far16
+ nop
+ call EntryCommon16
+
+DOSFINDFIRST label far16
+ nop
+ call EntryCommon16
+
+DOSFINDFIRST2 label far16
+ nop
+ call EntryCommon16
+
+DOSENUMATTRIBUTE label far16
+ nop
+ call EntryCommon16
+
+DOSQFILEMODE label far16
+ nop
+ call EntryCommon16
+
+DOSQFILEINFO label far16
+ nop
+ call EntryCommon16
+
+DOSALLOCSEG label far16
+ nop
+ call EntryCommon16
+
+DOSFREESEG label far16
+ nop
+ call EntryCommon16
+
+DOSGETSEG label far16
+ nop
+ call EntryCommon16
+
+DOSGIVESEG label far16
+ nop
+ call EntryCommon16
+
+DOSREALLOCSEG label far16
+ nop
+ call EntryCommon16
+
+DOSSIZESEG label far16
+ nop
+ call EntryCommon16
+
+DOSALLOCHUGE label far16
+ nop
+ call EntryCommon16
+
+DOSREALLOCHUGE label far16
+ nop
+ call EntryCommon16
+
+DOSGETHUGESHIFT label far16
+ nop
+ call EntryCommon16
+
+DOSALLOCSHRSEG label far16
+ nop
+ call EntryCommon16
+
+DOSLOCKSEG label far16
+ nop
+ call EntryCommon16
+
+DOSUNLOCKSEG label far16
+ nop
+ call EntryCommon16
+
+DOSGETSHRSEG label far16
+ nop
+ call EntryCommon16
+
+DOSMEMAVAIL label far16
+ nop
+ call EntryCommon16
+
+DOSCREATECSALIAS label far16
+ nop
+ call EntryCommon16
+
+DOSSEMCLEAR label far16
+ nop
+ call EntryCommon16
+
+DOSSEMSET label far16
+ nop
+ call EntryCommon16
+
+DOSSEMWAIT label far16
+ nop
+ call EntryCommon16
+
+DOSSEMSETWAIT label far16
+ nop
+ call EntryCommon16
+
+DOSSEMREQUEST label far16
+ nop
+ call EntryCommon16
+
+DOSCREATESEM label far16
+ nop
+ call EntryCommon16
+
+DOSOPENSEM label far16
+ nop
+ call EntryCommon16
+
+DOSCLOSESEM label far16
+ nop
+ call EntryCommon16
+
+DOSMUXSEMWAIT label far16
+ nop
+ call EntryCommon16
+
+DOSFSRAMSEMREQUEST label far16
+ nop
+ call EntryCommon16
+
+DOSFSRAMSEMCLEAR label far16
+ nop
+ call EntryCommon16
+
+DOSTIMERASYNC label far16
+ nop
+ call EntryCommon16
+
+DOSTIMERSTART label far16
+ nop
+ call EntryCommon16
+
+DOSTIMERSTOP label far16
+ nop
+ call EntryCommon16
+
+DOSGETPROCADDR label far16
+ nop
+ call EntryCommon16
+
+DOSQUERYPROCTYPE label far16
+ nop
+ call EntryCommon16
+
+DOSQUERYRESOURCESIZE label far16
+ nop
+ call EntryCommon16
+
+DOSSETSIGHANDLER label far16
+ nop
+ call EntryCommon16
+
+DOSFLAGPROCESS label far16
+ nop
+ call EntryCommon16
+
+DOSHOLDSIGNAL label far16
+ nop
+ call EntryCommon16
+
+DOSSENDSIGNAL label far16
+ nop
+ call EntryCommon16
+
+DOSSETVEC label far16
+ nop
+ call EntryCommon16
+
+DOSGETENV label far16
+ nop
+ call EntryCommon16
+
+DOSGETVERSION label far16
+ nop
+ call EntryCommon16
+
+DOSGETMACHINEMODE label far16
+ nop
+ call EntryCommon16
+
+DOSFINDNEXT label far16
+ nop
+ call EntryCommon16
+
+DOSGETPID label far16
+ nop
+ call EntryCommon16
+
+DOSGETPPID label far16
+ nop
+ call EntryCommon16
+
+DOSMKDIR label far16
+ nop
+ call EntryCommon16
+
+DOSMKDIR2 label far16
+ nop
+ call EntryCommon16
+
+DOSSETFILEMODE label far16
+ nop
+ call EntryCommon16
+
+DOSSETFILEINFO label far16
+ nop
+ call EntryCommon16
+
+DOSTRUEGETMESSAGE label far16
+ nop
+ call EntryCommon16
+
+DOSSCANENV label far16
+ nop
+ call EntryCommon16
+
+DOSPTRACE label far16
+ nop
+ call EntryCommon16
+
+DOSINSMESSAGE label far16
+ nop
+ call EntryCommon16
+
+DOSPUTMESSAGE label far16
+ nop
+ call EntryCommon16
+
+DOSSUBSET label far16
+ nop
+ call EntryCommon16
+
+DOSSUBALLOC label far16
+ nop
+ call EntryCommon16
+
+DOSSUBFREE label far16
+ nop
+ call EntryCommon16
+
+DOSSTARTSESSION label far16
+ nop
+ call EntryCommon16
+
+DOSSTOPSESSION label far16
+ nop
+ call EntryCommon16
+
+DOSSETSESSION label far16
+ nop
+ call EntryCommon16
+
+DOSSELECTSESSION label far16
+ nop
+ call EntryCommon16
+
+DOSSMSETTITLE label far16
+ nop
+ call EntryCommon16
+
+DOSSMPMPRESENT label far16
+ nop
+ call EntryCommon16
+
+WINSETTITLEANDICON label far16
+ nop
+ call EntryCommon16
+
+DOSGETPRTY label far16
+ nop
+ call EntryCommon16
+
+DOSQSYSINFO label far16
+ nop
+ call EntryCommon16
+
+DOSDEVIOCTL2 label far16
+ nop
+ call EntryCommon16
+
+DOSICANONICALIZE label far16
+ nop
+ call EntryCommon16
+
+DOSREADASYNC label far16
+ nop
+ call EntryCommon16
+
+DOSWRITEASYNC label far16
+ nop
+ call EntryCommon16
+
+DOSFINDNOTIFYCLOSE label far16
+ nop
+ call EntryCommon16
+
+DOSFINDNOTIFYFIRST label far16
+ nop
+ call EntryCommon16
+
+DOSFINDNOTIFYNEXT label far16
+ nop
+ call EntryCommon16
+
+DOSFILELOCKS label far16
+ nop
+ call EntryCommon16
+
+DOSQPATHINFO label far16
+ nop
+ call EntryCommon16
+
+DOSSETPATHINFO label far16
+ nop
+ call EntryCommon16
+
+DOSPORTACCESS label far16
+ nop
+ call EntryCommon16
+
+DOSCLIACCESS label far16
+ nop
+ call EntryCommon16
+
+WINQUERYPROFILESTRING label far16
+ nop
+ call EntryCommon16
+
+WINQUERYPROFILESIZE label far16
+ nop
+ call EntryCommon16
+
+WINQUERYPROFILEDATA label far16
+ nop
+ call EntryCommon16
+
+WINQUERYPROFILEINT label far16
+ nop
+ call EntryCommon16
+
+WINWRITEPROFILEDATA label far16
+ nop
+ call EntryCommon16
+
+WINWRITEPROFILESTRING label far16
+ nop
+ call EntryCommon16
+
+WINCREATEHEAP label far16
+ nop
+ call EntryCommon16
+
+WINDESTROYHEAP label far16
+ nop
+ call EntryCommon16
+
+WINALLOCMEM label far16
+ nop
+ call EntryCommon16
+
+WINFREEMEM label far16
+ nop
+ call EntryCommon16
+
+WINGETLASTERROR label far16
+ nop
+ call EntryCommon16
+
+VIOSCROLLUP label far16
+ nop
+ call EntryCommon16
+
+VIOGETCURPOS label far16
+ nop
+ call EntryCommon16
+
+VIOSETCURPOS label far16
+ nop
+ call EntryCommon16
+
+VIOWRTTTY label far16
+ nop
+ call EntryCommon16
+
+VIOGETMODE label far16
+ nop
+ call EntryCommon16
+
+VIOREADCELLSTR label far16
+ nop
+ call EntryCommon16
+
+VIOSCROLLLF label far16
+ nop
+ call EntryCommon16
+
+VIOREADCHARSTR label far16
+ nop
+ call EntryCommon16
+
+VIOWRTCHARSTRATT label far16
+ nop
+ call EntryCommon16
+
+VIOWRTCELLSTR label far16
+ nop
+ call EntryCommon16
+
+VIOWRTCHARSTR label far16
+ nop
+ call EntryCommon16
+
+VIOWRTNCELL label far16
+ nop
+ call EntryCommon16
+
+VIOWRTNATTR label far16
+ nop
+ call EntryCommon16
+
+VIOWRTNCHAR label far16
+ nop
+ call EntryCommon16
+
+VIOSCROLLDN label far16
+ nop
+ call EntryCommon16
+
+VIOSCROLLRT label far16
+ nop
+ call EntryCommon16
+
+VIOGETANSI label far16
+ nop
+ call EntryCommon16
+
+VIOSETANSI label far16
+ nop
+ call EntryCommon16
+
+VIOGETCONFIG label far16
+ nop
+ call EntryCommon16
+
+VIOGETCP label far16
+ nop
+ call EntryCommon16
+
+VIOSETCP label far16
+ nop
+ call EntryCommon16
+
+VIOGETCURTYPE label far16
+ nop
+ call EntryCommon16
+
+VIOSETCURTYPE label far16
+ nop
+ call EntryCommon16
+
+VIOSETMODE label far16
+ nop
+ call EntryCommon16
+
+VIODEREGISTER label far16
+ nop
+ call EntryCommon16
+
+VIOREGISTER label far16
+ nop
+ call EntryCommon16
+
+VIOPOPUP label far16
+ nop
+ call EntryCommon16
+
+VIOENDPOPUP label far16
+ nop
+ call EntryCommon16
+
+VIOGETBUF label far16
+ nop
+ call EntryCommon16
+
+VIOSHOWBUF label far16
+ nop
+ call EntryCommon16
+
+VIOGETFONT label far16
+ nop
+ call EntryCommon16
+
+VIOSETFONT label far16
+ nop
+ call EntryCommon16
+
+VIOGETSTATE label far16
+ nop
+ call EntryCommon16
+
+VIOSETSTATE label far16
+ nop
+ call EntryCommon16
+
+VIOGETPHYSBUF label far16
+ nop
+ call EntryCommon16
+
+VIOMODEUNDO label far16
+ nop
+ call EntryCommon16
+
+VIOMODEWAIT label far16
+ nop
+ call EntryCommon16
+
+VIOSAVREDRAWWAIT label far16
+ nop
+ call EntryCommon16
+
+VIOSAVREDRAWUNDO label far16
+ nop
+ call EntryCommon16
+
+VIOSCRLOCK label far16
+ nop
+ call EntryCommon16
+
+VIOSCRUNLOCK label far16
+ nop
+ call EntryCommon16
+
+VIOPRTSC label far16
+ nop
+ call EntryCommon16
+
+VIOPRTSCTOGGLE label far16
+ nop
+ call EntryCommon16
+
+KBDFLUSHBUFFER label far16
+ nop
+ call EntryCommon16
+
+KBDGETSTATUS label far16
+ nop
+ call EntryCommon16
+
+KBDSETSTATUS label far16
+ nop
+ call EntryCommon16
+
+KBDPEEK label far16
+ nop
+ call EntryCommon16
+
+KBDCHARIN label far16
+ nop
+ call EntryCommon16
+
+KBDSTRINGIN label far16
+ nop
+ call EntryCommon16
+
+KBDGETFOCUS label far16
+ nop
+ call EntryCommon16
+
+KBDFREEFOCUS label far16
+ nop
+ call EntryCommon16
+
+KBDCLOSE label far16
+ nop
+ call EntryCommon16
+
+KBDOPEN label far16
+ nop
+ call EntryCommon16
+
+KBDDEREGISTER label far16
+ nop
+ call EntryCommon16
+
+KBDREGISTER label far16
+ nop
+ call EntryCommon16
+
+KBDGETCP label far16
+ nop
+ call EntryCommon16
+
+KBDSETCP label far16
+ nop
+ call EntryCommon16
+
+KBDSETCUSTXT label far16
+ nop
+ call EntryCommon16
+
+KBDXLATE label far16
+ nop
+ call EntryCommon16
+
+KBDGETHWID label far16
+ nop
+ call EntryCommon16
+
+KBDSETFGND label far16
+ nop
+ call EntryCommon16
+
+KBDSYNCH label far16
+ nop
+ call EntryCommon16
+
+KBDSHELLINIT label far16
+ nop
+ call EntryCommon16
+
+MOUCLOSE label far16
+ nop
+ call EntryCommon16
+
+MOUDEREGISTER label far16
+ nop
+ call EntryCommon16
+
+MOUDRAWPTR label far16
+ nop
+ call EntryCommon16
+
+MOUFLUSHQUE label far16
+ nop
+ call EntryCommon16
+
+MOUGETDEVSTATUS label far16
+ nop
+ call EntryCommon16
+
+MOUGETEVENTMASK label far16
+ nop
+ call EntryCommon16
+
+MOUGETNUMBUTTONS label far16
+ nop
+ call EntryCommon16
+
+MOUGETNUMMICKEYS label far16
+ nop
+ call EntryCommon16
+
+MOUGETNUMQUEEL label far16
+ nop
+ call EntryCommon16
+
+MOUGETPTRPOS label far16
+ nop
+ call EntryCommon16
+
+MOUGETPTRSHAPE label far16
+ nop
+ call EntryCommon16
+
+MOUGETSCALEFACT label far16
+ nop
+ call EntryCommon16
+
+MOUOPEN label far16
+ nop
+ call EntryCommon16
+
+MOUREADEVENTQUE label far16
+ nop
+ call EntryCommon16
+
+MOUREGISTER label far16
+ nop
+ call EntryCommon16
+
+MOUREMOVEPTR label far16
+ nop
+ call EntryCommon16
+
+MOUSETDEVSTATUS label far16
+ nop
+ call EntryCommon16
+
+MOUSETEVENTMASK label far16
+ nop
+ call EntryCommon16
+
+MOUSETPTRPOS label far16
+ nop
+ call EntryCommon16
+
+MOUSETPTRSHAPE label far16
+ nop
+ call EntryCommon16
+
+MOUSETSCALEFACT label far16
+ nop
+ call EntryCommon16
+
+MOUSYNCH label far16
+ nop
+ call EntryCommon16
+
+DOSMONOPEN label far16
+ nop
+ call EntryCommon16
+
+DOSMONCLOSE label far16
+ nop
+ call EntryCommon16
+
+DOSMONREAD label far16
+ nop
+ call EntryCommon16
+
+DOSMONREG label far16
+ nop
+ call EntryCommon16
+
+DOSMONWRITE label far16
+ nop
+ call EntryCommon16
+
+NETGETDCNAME label far16
+ nop
+ call EntryCommon16
+
+NETHANDLEGETINFO label far16
+ nop
+ call EntryCommon16
+
+NETSERVERDISKENUM label far16
+ nop
+ call EntryCommon16
+
+NETSERVERENUM2 label far16
+ nop
+ call EntryCommon16
+
+NETSERVERGETINFO label far16
+ nop
+ call EntryCommon16
+
+NETSERVICECONTROL label far16
+ nop
+ call EntryCommon16
+
+NETSERVICEENUM label far16
+ nop
+ call EntryCommon16
+
+NETSERVICEGETINFO label far16
+ nop
+ call EntryCommon16
+
+NETSERVICEINSTALL label far16
+ nop
+ call EntryCommon16
+
+NETSHAREENUM label far16
+ nop
+ call EntryCommon16
+
+NETSHAREGETINFO label far16
+ nop
+ call EntryCommon16
+
+NETUSEADD label far16
+ nop
+ call EntryCommon16
+
+NETUSEDEL label far16
+ nop
+ call EntryCommon16
+
+NETUSEENUM label far16
+ nop
+ call EntryCommon16
+
+NETUSEGETINFO label far16
+ nop
+ call EntryCommon16
+
+NETUSERENUM label far16
+ nop
+ call EntryCommon16
+
+NETWKSTAGETINFO label far16
+ nop
+ call EntryCommon16
+
+NETACCESSADD label far16
+ nop
+ call EntryCommon16
+
+NETACCESSSETINFO label far16
+ nop
+ call EntryCommon16
+
+NETACCESSGETINFO label far16
+ nop
+ call EntryCommon16
+
+NETACCESSDEL label far16
+ nop
+ call EntryCommon16
+
+NETSHAREADD label far16
+ nop
+ call EntryCommon16
+
+NETSHAREDEL label far16
+ nop
+ call EntryCommon16
+
+NETUSERGETINFO label far16
+ nop
+ call EntryCommon16
+
+NETMESSAGEBUFFERSEND label far16
+ nop
+ call EntryCommon16
+
+NETBIOS label far16
+ nop
+ call EntryCommon16
+
+NETBIOSCLOSE label far16
+ nop
+ call EntryCommon16
+
+NETBIOSENUM label far16
+ nop
+ call EntryCommon16
+
+NETBIOSGETINFO label far16
+ nop
+ call EntryCommon16
+
+NETBIOSOPEN label far16
+ nop
+ call EntryCommon16
+
+NETBIOSSUBMIT label far16
+ nop
+ call EntryCommon16
+
+DOSMAKEMAILSLOT label far16
+ nop
+ call EntryCommon16
+
+DOSDELETEMAILSLOT label far16
+ nop
+ call EntryCommon16
+
+DOSMAILSLOTINFO label far16
+ nop
+ call EntryCommon16
+
+DOSPEEKMAILSLOT label far16
+ nop
+ call EntryCommon16
+
+DOSREADMAILSLOT label far16
+ nop
+ call EntryCommon16
+
+DOSWRITEMAILSLOT label far16
+ nop
+ call EntryCommon16
+
+DOSIREMOTEAPI label far16
+ nop
+ call EntryCommon16
+
+NETIWKSTAGETUSERINFO label far16
+ nop
+ call EntryCommon16
+
+NETIUSERPASSWORDSET label far16
+ nop
+ call EntryCommon16
+
+DOSIENCRYPTSES label far16
+ nop
+ call EntryCommon16
+
+DOS32LOADMODULE label far16
+ nop
+ call EntryCommon16
+
+DOS32GETPROCADDR label far16
+ nop
+ call EntryCommon16
+
+DOS32DISPATCH label far16
+ nop
+ call EntryCommon16
+
+DOS32FREEMODULE label far16
+ nop
+ call EntryCommon16
+
+FARPTR2FLATPTR label far16
+ nop
+ call EntryCommon16
+
+FLATPTR2FARPTR label far16
+ nop
+ call EntryCommon16
+
+
+; These are two global variables exported by doscalls
+
+public DOSHUGEINCR
+DOSHUGEINCR equ 8
+public DOSHUGESHIFT
+DOSHUGESHIFT equ 3
+
+;===========================================================================
+; This is the common setup code for 16=>32 thunks. It:
+; 1. retrieves the 32-bit jump table offset from the stack
+; 2. saves registers
+; 3. saves ss:sp
+; 4. jumps to 32-bit code
+;
+; Entry: flat jump table offset (+4) is on top of stack
+; AX contains the DLL init routine ret value for the
+; LDRLIBIRETURN entry, VOID otherwise.
+;
+; Exit: (eax[15-0]) == flat jump table offset (+4)
+; (eax[31-16]) == return value of DLL init routine for LDRLIBIRETURN
+; (ebx) == new esp
+
+EntryCommon16:
+ shl eax,16 ; 16 MSB of eax contain the DLL init ret value
+ pop ax ; 16 LSB of eax contain the offset in jump table
+
+ push ds ; save ds
+ push es ; save es
+ push di
+ push si
+ push cx
+ push bx
+ push dx
+ push bp
+
+ mov bx,sp ; save current ss:sp
+ push ss
+ push bx
+
+; compute flat esp
+; NOTE - we implement FARPTRTOFLAT by arith
+
+ mov bx,ss
+ shr bx,3
+ add bx,3800H
+ shl ebx,16
+ mov bx,sp ; (ebx) == FLAT esp
+
+;force a long, far jump into 32 bit thunks, where EntryFlat resides
+;jmp 1b:063023D80h
+
+ db 066h, 0eah, 0ddh, 01fh, 090h, 090h, 01bh, 00h
+
+ELSE ; GEN32
+extrn _DosExitStub@0:PROC
+extrn _LDRLibiReturn@0:PROC
+extrn _DosExitProcessStub@0:PROC
+extrn _DosReturn@8:PROC
+extrn _DosExit@8:PROC
+extrn _Dos16WaitChild@20:PROC
+extrn _DosBeep@8:PROC
+extrn _DosPhysicalDisk@20:PROC
+extrn _DosGetCp@12:PROC
+extrn _DosSetCp@8:PROC
+extrn _DosSetProcCp@8:PROC
+extrn _DosGetCtryInfo@16:PROC
+extrn _DosGetDBCSEv@12:PROC
+extrn _DosCaseMap@12:PROC
+extrn _DosGetCollate@16:PROC
+extrn _DosSleep@4:PROC
+extrn _DosDevConfig@8:PROC
+extrn _DosGetDateTime@4:PROC
+extrn _DosSetDateTime@4:PROC
+extrn _Dos16ExecPgm@28:PROC
+extrn _DosEnterCritSec@0:PROC
+extrn _DosExitCritSec@0:PROC
+extrn _DosKillProcess@8:PROC
+extrn _DosSetPriority@16:PROC
+extrn _DosResumeThread@4:PROC
+extrn _DosSuspendThread@4:PROC
+extrn _Dos16CreatePipe@12:PROC
+extrn _Dos16CreateQueue@12:PROC
+extrn _Dos16OpenQueue@12:PROC
+extrn _DosCloseQueue@4:PROC
+extrn _Dos16PeekQueue@32:PROC
+extrn _Dos16ReadQueue@32:PROC
+extrn _DosPurgeQueue@4:PROC
+extrn _Dos16QueryQueue@8:PROC
+extrn _DosWriteQueue@20:PROC
+extrn _Dos16CallNPipe@28:PROC
+extrn _DosConnectNPipe@4:PROC
+extrn _DosDisConnectNPipe@4:PROC
+extrn _Dos16CreateNPipe@28:PROC
+extrn _Dos16PeekNPipe@24:PROC
+extrn _Dos16QueryNPHState@8:PROC
+extrn _DosQueryNPipeInfo@16:PROC
+extrn _DosQueryNPipeSemState@12:PROC
+extrn _DosSetNPHState@8:PROC
+extrn _DosSetNPipeSem@12:PROC
+extrn _Dos16TransactNPipe@24:PROC
+extrn _DosWaitNPipe@8:PROC
+extrn _DosResetBuffer@4:PROC
+extrn _DosSetCurrentDir@4:PROC
+extrn _DosSetFilePtr@16:PROC
+extrn _DosClose@4:PROC
+extrn _DosCopy@12:PROC
+extrn _DosICopy@12:PROC
+extrn _DosDelete@4:PROC
+extrn _DosDevIOCtl@20:PROC
+extrn _Dos16DupHandle@8:PROC
+extrn _DosEditName@20:PROC
+extrn _DosFileIO@16:PROC
+extrn _DosFindClose@4:PROC
+extrn _DosFSAttach@20:PROC
+extrn _Dos16FSCtl@40:PROC
+extrn _DosMove@8:PROC
+extrn _DosSetFileSize@8:PROC
+extrn _Dos16QueryCurrentDir@12:PROC
+extrn _Dos16QueryCurrentDisk@8:PROC
+extrn _Dos16QueryFHState@8:PROC
+extrn _DosSetFHState@8:PROC
+extrn _Dos16QFSAttach@24:PROC
+extrn _DosQueryFSInfo@16:PROC
+extrn _Dos16QueryHType@12:PROC
+extrn _Dos16QueryVerify@4:PROC
+extrn _DosDeleteDir@4:PROC
+extrn _DosSearchPath@20:PROC
+extrn _DosSetDefaultDisk@4:PROC
+extrn _DosSetFSInfo@16:PROC
+extrn _DosSetMaxFH@4:PROC
+extrn _DosSetVerify@4:PROC
+extrn _Dos16ErrClass@16:PROC
+extrn _DosError@4:PROC
+extrn _DosLoadModuleNE@16:PROC
+extrn _DosFreeModuleNE@4:PROC
+extrn _DosQueryModuleHandleNE@8:PROC
+extrn _DosQueryModuleNameNE@12:PROC
+extrn _DosGetResourceNE@16:PROC
+extrn _DosGetResource2NE@16:PROC
+extrn _DosFreeResourceNE@4:PROC
+extrn _DosQueryAppTypeNE@8:PROC
+extrn _DosShutdown@4:PROC
+extrn _Dos16CreateThread@12:PROC
+extrn _Dos16ExitList@8:PROC
+extrn _DosGetInfoSeg@8:PROC
+extrn _Dos16Open@32:PROC
+extrn _Dos16Open2@36:PROC
+extrn _Dos16Read@16:PROC
+extrn _Dos16Write@16:PROC
+extrn _Dos16FindFirst@28:PROC
+extrn _Dos16FindFirst2@32:PROC
+extrn _Dos16EnumAttribute@32:PROC
+extrn _DosQFileMode@12:PROC
+extrn _DosQFileInfo@16:PROC
+extrn _DosAllocSeg@12:PROC
+extrn _DosFreeSeg@4:PROC
+extrn _DosGetSeg@4:PROC
+extrn _DosGiveSeg@12:PROC
+extrn _DosReallocSeg@8:PROC
+extrn _DosSizeSeg@8:PROC
+extrn _DosAllocHuge@20:PROC
+extrn _DosReallocHuge@12:PROC
+extrn _DosGetHugeShift@4:PROC
+extrn _DosAllocShrSeg@12:PROC
+extrn _DosLockSeg@4:PROC
+extrn _DosUnlockSeg@4:PROC
+extrn _DosGetShrSeg@8:PROC
+extrn _DosMemAvail@4:PROC
+extrn _DosCreateCSAlias@8:PROC
+extrn _DosSemClear@4:PROC
+extrn _DosSemSet@4:PROC
+extrn _DosSemWait@8:PROC
+extrn _DosSemSetWait@8:PROC
+extrn _DosSemRequest@8:PROC
+extrn _DosCreateSem@12:PROC
+extrn _DosOpenSem@8:PROC
+extrn _DosCloseSem@4:PROC
+extrn _DosMuxSemWait@12:PROC
+extrn _DosFSRamSemRequest@8:PROC
+extrn _DosFSRamSemClear@4:PROC
+extrn _DosAsyncTimer@12:PROC
+extrn _DosStartTimer@12:PROC
+extrn _DosStopTimer@4:PROC
+extrn _DosGetProcAddrNE@12:PROC
+extrn _DosQueryProcType@16:PROC
+extrn _DosQueryResourceSize@16:PROC
+extrn _DosSetSigHandler@20:PROC
+extrn DosFlagProcess16@16:PROC
+extrn DosHoldSignal16@4:PROC
+extrn DosSendSignal16@8:PROC
+extrn _DosSetVec@12:PROC
+extrn _DosGetEnv@8:PROC
+extrn _DosGetVersion@4:PROC
+extrn _DosGetMachineMode@4:PROC
+extrn _Dos16FindNext@16:PROC
+extrn _DosGetPID@4:PROC
+extrn _DosGetPPID@8:PROC
+extrn _Dos16MkDir@8:PROC
+extrn _Dos16MkDir2@12:PROC
+extrn _DosSetFileMode@12:PROC
+extrn _Dos16SetFileInfo@16:PROC
+extrn _DosTrueGetMessage@32:PROC
+extrn _DosScanEnvNE@8:PROC
+extrn _DosPTrace@4:PROC
+extrn _DosInsMessage@28:PROC
+extrn _DosPutMessage@12:PROC
+extrn _Dos16SubSet@12:PROC
+extrn _Dos16SubAlloc@12:PROC
+extrn _Dos16SubFree@12:PROC
+extrn _Dos16StartSession@12:PROC
+extrn _DosStopSession@12:PROC
+extrn _DosSetSession@8:PROC
+extrn _DosSelectSession@8:PROC
+extrn _DosSMSetTitle@4:PROC
+extrn _DosSMPMPresent@4:PROC
+extrn _WinSetTitleAndIcon@8:PROC
+extrn _DosGetPriority@12:PROC
+extrn _DosQSysInfo@12:PROC
+extrn _DosDevIOCtl2@28:PROC
+extrn _DosICanonicalize@20:PROC
+extrn _DosReadAsync@24:PROC
+extrn _DosWriteAsync@24:PROC
+extrn _DosFindNotifyClose@0:PROC
+extrn _DosFindNotifyFirst@0:PROC
+extrn _DosFindNotifyNext@0:PROC
+extrn _DosFileLocks@12:PROC
+extrn _Dos16QPathInfo@20:PROC
+extrn _Dos16SetPathInfo@24:PROC
+extrn _DosPortAccess@16:PROC
+extrn _DosCLIAccess@0:PROC
+extrn _WinQueryProfileString@20:PROC
+extrn _WinQueryProfileSize@12:PROC
+extrn _WinQueryProfileData@16:PROC
+extrn _WinQueryProfileInt@12:PROC
+extrn _WinWriteProfileData@16:PROC
+extrn _WinWriteProfileString@12:PROC
+extrn _WinCreateHeap@24:PROC
+extrn _WinDestroyHeap@4:PROC
+extrn _WinAllocMem@8:PROC
+extrn _WinFreeMem@12:PROC
+extrn _WinGetLastError@4:PROC
+extrn _VioScrollUp@28:PROC
+extrn _VioGetCurPos@12:PROC
+extrn _VioSetCurPos@12:PROC
+extrn _VioWrtTTY@12:PROC
+extrn _VioGetMode@8:PROC
+extrn _VioReadCellStr@20:PROC
+extrn _VioScrollLf@28:PROC
+extrn _VioReadCharStr@20:PROC
+extrn _VioWrtCharStrAtt@24:PROC
+extrn _VioWrtCellStr@20:PROC
+extrn _VioWrtCharStr@20:PROC
+extrn _VioWrtNCell@20:PROC
+extrn _VioWrtNAttr@20:PROC
+extrn _VioWrtNChar@20:PROC
+extrn _VioScrollDn@28:PROC
+extrn _VioScrollRt@28:PROC
+extrn _VioGetAnsi@8:PROC
+extrn _VioSetAnsi@8:PROC
+extrn _VioGetConfig@12:PROC
+extrn _VioGetCp@12:PROC
+extrn _VioSetCp@12:PROC
+extrn _VioGetCurType@8:PROC
+extrn _VioSetCurType@8:PROC
+extrn _VioSetMode@8:PROC
+extrn _VioDeRegister@0:PROC
+extrn _VioRegister@16:PROC
+extrn _VioPopUp@8:PROC
+extrn _VioEndPopUp@4:PROC
+extrn _VioGetBuf@12:PROC
+extrn _VioShowBuf@12:PROC
+extrn _VioGetFont@8:PROC
+extrn _VioSetFont@8:PROC
+extrn _VioGetState@8:PROC
+extrn _VioSetState@8:PROC
+extrn _VioGetPhysBuf@8:PROC
+extrn _VioModeUndo@12:PROC
+extrn _VioModeWait@12:PROC
+extrn _VioSavRedrawWait@12:PROC
+extrn _VioSavRedrawUndo@12:PROC
+extrn _VioScrLock@12:PROC
+extrn _VioScrUnLock@4:PROC
+extrn _VioPrtSc@4:PROC
+extrn _VioPrtScToggle@4:PROC
+extrn _KbdFlushBuffer@4:PROC
+extrn _KbdGetStatus@8:PROC
+extrn _KbdSetStatus@8:PROC
+extrn _KbdPeek@8:PROC
+extrn _KbdCharIn@12:PROC
+extrn _KbdStringIn@16:PROC
+extrn _KbdGetFocus@8:PROC
+extrn _KbdFreeFocus@4:PROC
+extrn _KbdClose@4:PROC
+extrn _KbdOpen@4:PROC
+extrn _KbdDeRegister@0:PROC
+extrn _KbdRegister@12:PROC
+extrn _KbdGetCp@12:PROC
+extrn _KbdSetCp@12:PROC
+extrn _KbdSetCustXt@8:PROC
+extrn _KbdXlate@8:PROC
+extrn _KbdGetHWID@8:PROC
+extrn _KbdSetFgnd@4:PROC
+extrn _KbdSynch@4:PROC
+extrn _KbdShellInit@0:PROC
+extrn _MouClose@4:PROC
+extrn _MouDeRegister@0:PROC
+extrn _MouDrawPtr@4:PROC
+extrn _MouFlushQue@4:PROC
+extrn _MouGetDevStatus@8:PROC
+extrn _MouGetEventMask@8:PROC
+extrn _MouGetNumButtons@8:PROC
+extrn _MouGetNumMickeys@8:PROC
+extrn _MouGetNumQueEl@8:PROC
+extrn _MouGetPtrPos@8:PROC
+extrn _MouGetPtrShape@12:PROC
+extrn _MouGetScaleFact@8:PROC
+extrn _MouOpen@8:PROC
+extrn _MouReadEventQue@12:PROC
+extrn _MouRegister@12:PROC
+extrn _MouRemovePtr@8:PROC
+extrn _MouSetDevStatus@8:PROC
+extrn _MouSetEventMask@8:PROC
+extrn _MouSetPtrPos@8:PROC
+extrn _MouSetPtrShape@12:PROC
+extrn _MouSetScaleFact@8:PROC
+extrn _MouSynch@4:PROC
+extrn _DosMonOpen@8:PROC
+extrn _DosMonClose@4:PROC
+extrn _DosMonRead@16:PROC
+extrn _DosMonReg@20:PROC
+extrn _DosMonWrite@12:PROC
+extrn _Net16GetDCName@16:PROC
+extrn _Net16HandleGetInfo@20:PROC
+extrn _Net16ServerDiskEnum@24:PROC
+extrn _Net16ServerEnum2@32:PROC
+extrn _Net16ServerGetInfo@20:PROC
+extrn _Net16ServiceControl@24:PROC
+extrn _Net16ServiceEnum@24:PROC
+extrn _Net16ServiceGetInfo@24:PROC
+extrn _Net16ServiceInstall@20:PROC
+extrn _Net16ShareEnum@24:PROC
+extrn _Net16ShareGetInfo@24:PROC
+extrn _Net16UseAdd@16:PROC
+extrn _Net16UseDel@12:PROC
+extrn _Net16UseEnum@24:PROC
+extrn _Net16UseGetInfo@24:PROC
+extrn _Net16UserEnum@24:PROC
+extrn _Net16WkstaGetInfo@20:PROC
+extrn _Net16AccessAdd@16:PROC
+extrn _Net16AccessSetInfo@24:PROC
+extrn _Net16AccessGetInfo@24:PROC
+extrn _Net16AccessDel@8:PROC
+extrn _Net16ShareAdd@16:PROC
+extrn _Net16ShareDel@12:PROC
+extrn _Net16UserGetInfo@24:PROC
+extrn _Net16MessageBufferSend@16:PROC
+extrn _Net16bios@4:PROC
+extrn _Net16BiosClose@4:PROC
+extrn _Net16BiosEnum@24:PROC
+extrn _Net16BiosGetInfo@24:PROC
+extrn _Net16BiosOpen@16:PROC
+extrn _Net16BiosSubmit@12:PROC
+extrn _Dos16MakeMailslot@16:PROC
+extrn _Dos16DeleteMailslot@4:PROC
+extrn _Dos16MailslotInfo@24:PROC
+extrn _Dos16PeekMailslot@20:PROC
+extrn _Dos16ReadMailslot@24:PROC
+extrn _Dos16WriteMailslot@24:PROC
+extrn _DosIRemoteApi@24:PROC
+extrn _NetIWkstaGetUserInfo@20:PROC
+extrn _NetIUserPasswordSet@16:PROC
+extrn _DosIEncryptSES@12:PROC
+extrn _Dos32LoadModule@8:PROC
+extrn _Dos32GetProcAddr@12:PROC
+extrn _Dos32Dispatch@12:PROC
+extrn _Dos32FreeModule@4:PROC
+extrn _FarPtr2FlatPtr@8:PROC
+extrn _FlatPtr2FarPtr@8:PROC
+extrn _GetSaved32Esp@0:PROC
+extrn _Save16Esp@0:PROC
+extrn _Od216ApiPrint@4:PROC
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+;===========================================================================
+; This is the common flat entry point for 16=>32 thunks. It:
+; 1. makes ds, es, ss FLAT
+; 2. saves esp in ebx
+; 3. dword-aligns the stack
+; 4. jumps to the API-specific thunk code indicated in ax
+;
+; Entry: (ax) == flat jump table offset (+4)
+; (ebx) == flat esp
+
+ public _EntryFlat@0
+ extrn _Od2Saved16Stack:DWORD
+ extrn _MoveInfoSegintoTeb:PROC
+ extrn _RestoreTeb:PROC
+
+_EntryFlat@0 proc
+
+ mov dx,023H
+ mov ds,dx ; FLAT ds
+ mov es,dx ; FLAT es
+
+ push eax
+ call _RestoreTeb
+
+ ; 16bit stack must be saved to allow proper signal handler execution
+ call _Save16Esp@0
+ or al,al
+ jz EntryFlat1
+ mov _Od2Saved16Stack,ebx ; Save 16-bit stack
+
+EntryFlat1:
+ call _GetSaved32Esp@0
+ pop ecx ; restore the thunk index/LDRLIBIRETURN ret value
+
+ and eax,0fffffffcH ; dword-align the 32bit stack pointer
+ mov dx,23H
+ push dx ; flat SS
+ push eax ; flat ESP
+ lss esp,[ebx-6] ; switch to 32bit stack
+
+ push ecx
+ and ecx,0ffffH ; clear hi word
+ push ecx
+
+ call _Od216ApiPrint@4
+ pop ecx
+
+ mov eax,ecx
+ shr eax,16 ; (eax) contains the LDRLIBIRETURN ret value
+ and ecx,0ffffH
+ mov ebp,esp ; Compiler assumes this for ebp elimination
+ jmp dword ptr FlatTable[ecx-4] ; select specific thunk
+_EntryFlat@0 endp
+
+;===========================================================================
+; Common routines to restore the stack and registers
+; and return to 16-bit code. There is one for each
+; size of 16-bit parameter list in this script.
+
+ public _ExitFlatAreaBegin@0
+_ExitFlatAreaBegin@0:
+
+ExitFlat_0:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_0
+ mov es,ax
+ jmp ESFixed_0
+FixES_0:
+ xor ax,ax
+ mov es,ax
+ESFixed_0:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_0
+ mov ds,ax
+ jmp DSFixed_0
+FixDS_0:
+ xor ax,ax
+ mov ds,ax
+DSFixed_0:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 0 ; 16-bit parameters
+
+ExitFlat_2:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_2
+ mov es,ax
+ jmp ESFixed_2
+FixES_2:
+ xor ax,ax
+ mov es,ax
+ESFixed_2:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_2
+ mov ds,ax
+ jmp DSFixed_2
+FixDS_2:
+ xor ax,ax
+ mov ds,ax
+DSFixed_2:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 2 ; 16-bit parameters
+
+ExitFlat_4:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_4
+ mov es,ax
+ jmp ESFixed_4
+FixES_4:
+ xor ax,ax
+ mov es,ax
+ESFixed_4:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_4
+ mov ds,ax
+ jmp DSFixed_4
+FixDS_4:
+ xor ax,ax
+ mov ds,ax
+DSFixed_4:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 4 ; 16-bit parameters
+
+ExitFlat_6:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_6
+ mov es,ax
+ jmp ESFixed_6
+FixES_6:
+ xor ax,ax
+ mov es,ax
+ESFixed_6:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_6
+ mov ds,ax
+ jmp DSFixed_6
+FixDS_6:
+ xor ax,ax
+ mov ds,ax
+DSFixed_6:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 6 ; 16-bit parameters
+
+ExitFlat_8:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_8
+ mov es,ax
+ jmp ESFixed_8
+FixES_8:
+ xor ax,ax
+ mov es,ax
+ESFixed_8:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_8
+ mov ds,ax
+ jmp DSFixed_8
+FixDS_8:
+ xor ax,ax
+ mov ds,ax
+DSFixed_8:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 8 ; 16-bit parameters
+
+ExitFlat_10:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_10
+ mov es,ax
+ jmp ESFixed_10
+FixES_10:
+ xor ax,ax
+ mov es,ax
+ESFixed_10:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_10
+ mov ds,ax
+ jmp DSFixed_10
+FixDS_10:
+ xor ax,ax
+ mov ds,ax
+DSFixed_10:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 10 ; 16-bit parameters
+
+ExitFlat_12:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_12
+ mov es,ax
+ jmp ESFixed_12
+FixES_12:
+ xor ax,ax
+ mov es,ax
+ESFixed_12:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_12
+ mov ds,ax
+ jmp DSFixed_12
+FixDS_12:
+ xor ax,ax
+ mov ds,ax
+DSFixed_12:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 12 ; 16-bit parameters
+
+ExitFlat_14:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_14
+ mov es,ax
+ jmp ESFixed_14
+FixES_14:
+ xor ax,ax
+ mov es,ax
+ESFixed_14:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_14
+ mov ds,ax
+ jmp DSFixed_14
+FixDS_14:
+ xor ax,ax
+ mov ds,ax
+DSFixed_14:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 14 ; 16-bit parameters
+
+ExitFlat_16:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_16
+ mov es,ax
+ jmp ESFixed_16
+FixES_16:
+ xor ax,ax
+ mov es,ax
+ESFixed_16:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_16
+ mov ds,ax
+ jmp DSFixed_16
+FixDS_16:
+ xor ax,ax
+ mov ds,ax
+DSFixed_16:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 16 ; 16-bit parameters
+
+ExitFlat_18:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_18
+ mov es,ax
+ jmp ESFixed_18
+FixES_18:
+ xor ax,ax
+ mov es,ax
+ESFixed_18:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_18
+ mov ds,ax
+ jmp DSFixed_18
+FixDS_18:
+ xor ax,ax
+ mov ds,ax
+DSFixed_18:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 18 ; 16-bit parameters
+
+ExitFlat_20:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_20
+ mov es,ax
+ jmp ESFixed_20
+FixES_20:
+ xor ax,ax
+ mov es,ax
+ESFixed_20:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_20
+ mov ds,ax
+ jmp DSFixed_20
+FixDS_20:
+ xor ax,ax
+ mov ds,ax
+DSFixed_20:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 20 ; 16-bit parameters
+
+ExitFlat_22:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_22
+ mov es,ax
+ jmp ESFixed_22
+FixES_22:
+ xor ax,ax
+ mov es,ax
+ESFixed_22:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_22
+ mov ds,ax
+ jmp DSFixed_22
+FixDS_22:
+ xor ax,ax
+ mov ds,ax
+DSFixed_22:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 22 ; 16-bit parameters
+
+ExitFlat_24:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_24
+ mov es,ax
+ jmp ESFixed_24
+FixES_24:
+ xor ax,ax
+ mov es,ax
+ESFixed_24:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_24
+ mov ds,ax
+ jmp DSFixed_24
+FixDS_24:
+ xor ax,ax
+ mov ds,ax
+DSFixed_24:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 24 ; 16-bit parameters
+
+ExitFlat_26:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_26
+ mov es,ax
+ jmp ESFixed_26
+FixES_26:
+ xor ax,ax
+ mov es,ax
+ESFixed_26:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_26
+ mov ds,ax
+ jmp DSFixed_26
+FixDS_26:
+ xor ax,ax
+ mov ds,ax
+DSFixed_26:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 26 ; 16-bit parameters
+
+ExitFlat_28:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_28
+ mov es,ax
+ jmp ESFixed_28
+FixES_28:
+ xor ax,ax
+ mov es,ax
+ESFixed_28:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_28
+ mov ds,ax
+ jmp DSFixed_28
+FixDS_28:
+ xor ax,ax
+ mov ds,ax
+DSFixed_28:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 28 ; 16-bit parameters
+
+ExitFlat_30:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_30
+ mov es,ax
+ jmp ESFixed_30
+FixES_30:
+ xor ax,ax
+ mov es,ax
+ESFixed_30:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_30
+ mov ds,ax
+ jmp DSFixed_30
+FixDS_30:
+ xor ax,ax
+ mov ds,ax
+DSFixed_30:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 30 ; 16-bit parameters
+
+ExitFlat_32:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_32
+ mov es,ax
+ jmp ESFixed_32
+FixES_32:
+ xor ax,ax
+ mov es,ax
+ESFixed_32:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_32
+ mov ds,ax
+ jmp DSFixed_32
+FixDS_32:
+ xor ax,ax
+ mov ds,ax
+DSFixed_32:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 32 ; 16-bit parameters
+
+ExitFlat_34:
+ call _MoveInfoSegintoTeb
+
+ mov cx,word ptr [ebx+16] ; ES
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; DS
+ shl edx,16
+ lss sp,[ebx] ; restore 16-bit ss:sp
+
+ pop bp
+ pop dx
+ pop bx
+ pop cx
+ pop si
+ pop di
+;
+; Performance HIT BUGBUG
+;
+ push eax
+ mov eax,ecx
+ shr eax,16 ; ES
+ verr ax ; see if the value is still valid!
+ jnz FixES_34
+ mov es,ax
+ jmp ESFixed_34
+FixES_34:
+ xor ax,ax
+ mov es,ax
+ESFixed_34:
+ mov eax,edx
+ shr eax,16 ; DS
+ verr ax ; see if the value is still valid!
+ jnz FixDS_34
+ mov ds,ax
+ jmp DSFixed_34
+FixDS_34:
+ xor ax,ax
+ mov ds,ax
+DSFixed_34:
+;
+;Now restore ax & di, and clean the stack
+ pop eax
+ add sp,4 ; es/ds are 2 byte each on the stack
+ db 66h, 0cah ; 16-bit retf
+ dw 34 ; 16-bit parameters
+
+ public _ExitFlatAreaEnd@0
+_ExitFlatAreaEnd@0:
+
+;===========================================================================
+; This is a jump table to API-specific flat thunk code.
+; Each entry is a dword.
+
+FlatTable label near
+ dd offset _TEXT:T__DosExitStub
+ dd offset _TEXT:T__LDRLibiReturn
+ dd offset _TEXT:T__DosExitProcessStub
+ dd offset _TEXT:T__DosReturn
+ dd offset _TEXT:T__DosExit
+ dd offset _TEXT:T__Dos16WaitChild
+ dd offset _TEXT:T__DosBeep
+ dd offset _TEXT:T__DosPhysicalDisk
+ dd offset _TEXT:T__DosGetCp
+ dd offset _TEXT:T__DosSetCp
+ dd offset _TEXT:T__DosSetProcCp
+ dd offset _TEXT:T__DosGetCtryInfo
+ dd offset _TEXT:T__DosGetDBCSEv
+ dd offset _TEXT:T__DosCaseMap
+ dd offset _TEXT:T__DosGetCollate
+ dd offset _TEXT:T__DosSleep
+ dd offset _TEXT:T__DosDevConfig
+ dd offset _TEXT:T__DosGetDateTime
+ dd offset _TEXT:T__DosSetDateTime
+ dd offset _TEXT:T__Dos16ExecPgm
+ dd offset _TEXT:T__DosEnterCritSec
+ dd offset _TEXT:T__DosExitCritSec
+ dd offset _TEXT:T__DosKillProcess
+ dd offset _TEXT:T__DosSetPriority
+ dd offset _TEXT:T__DosResumeThread
+ dd offset _TEXT:T__DosSuspendThread
+ dd offset _TEXT:T__Dos16CreatePipe
+ dd offset _TEXT:T__Dos16CreateQueue
+ dd offset _TEXT:T__Dos16OpenQueue
+ dd offset _TEXT:T__DosCloseQueue
+ dd offset _TEXT:T__Dos16PeekQueue
+ dd offset _TEXT:T__Dos16ReadQueue
+ dd offset _TEXT:T__DosPurgeQueue
+ dd offset _TEXT:T__Dos16QueryQueue
+ dd offset _TEXT:T__DosWriteQueue
+ dd offset _TEXT:T__Dos16CallNPipe
+ dd offset _TEXT:T__DosConnectNPipe
+ dd offset _TEXT:T__DosDisConnectNPipe
+ dd offset _TEXT:T__Dos16CreateNPipe
+ dd offset _TEXT:T__Dos16PeekNPipe
+ dd offset _TEXT:T__Dos16QueryNPHState
+ dd offset _TEXT:T__DosQueryNPipeInfo
+ dd offset _TEXT:T__DosQueryNPipeSemState
+ dd offset _TEXT:T__DosSetNPHState
+ dd offset _TEXT:T__DosSetNPipeSem
+ dd offset _TEXT:T__Dos16TransactNPipe
+ dd offset _TEXT:T__DosWaitNPipe
+ dd offset _TEXT:T__DosResetBuffer
+ dd offset _TEXT:T__DosSetCurrentDir
+ dd offset _TEXT:T__DosSetFilePtr
+ dd offset _TEXT:T__DosClose
+ dd offset _TEXT:T__DosCopy
+ dd offset _TEXT:T__DosICopy
+ dd offset _TEXT:T__DosDelete
+ dd offset _TEXT:T__DosDevIOCtl
+ dd offset _TEXT:T__Dos16DupHandle
+ dd offset _TEXT:T__DosEditName
+ dd offset _TEXT:T__DosFileIO
+ dd offset _TEXT:T__DosFindClose
+ dd offset _TEXT:T__DosFSAttach
+ dd offset _TEXT:T__Dos16FSCtl
+ dd offset _TEXT:T__DosMove
+ dd offset _TEXT:T__DosSetFileSize
+ dd offset _TEXT:T__Dos16QueryCurrentDir
+ dd offset _TEXT:T__Dos16QueryCurrentDisk
+ dd offset _TEXT:T__Dos16QueryFHState
+ dd offset _TEXT:T__DosSetFHState
+ dd offset _TEXT:T__Dos16QFSAttach
+ dd offset _TEXT:T__DosQueryFSInfo
+ dd offset _TEXT:T__Dos16QueryHType
+ dd offset _TEXT:T__Dos16QueryVerify
+ dd offset _TEXT:T__DosDeleteDir
+ dd offset _TEXT:T__DosSearchPath
+ dd offset _TEXT:T__DosSetDefaultDisk
+ dd offset _TEXT:T__DosSetFSInfo
+ dd offset _TEXT:T__DosSetMaxFH
+ dd offset _TEXT:T__DosSetVerify
+ dd offset _TEXT:T__Dos16ErrClass
+ dd offset _TEXT:T__DosError
+ dd offset _TEXT:T__DosLoadModuleNE
+ dd offset _TEXT:T__DosFreeModuleNE
+ dd offset _TEXT:T__DosQueryModuleHandleNE
+ dd offset _TEXT:T__DosQueryModuleNameNE
+ dd offset _TEXT:T__DosGetResourceNE
+ dd offset _TEXT:T__DosGetResource2NE
+ dd offset _TEXT:T__DosFreeResourceNE
+ dd offset _TEXT:T__DosQueryAppTypeNE
+ dd offset _TEXT:T__DosShutdown
+ dd offset _TEXT:T__Dos16CreateThread
+ dd offset _TEXT:T__Dos16ExitList
+ dd offset _TEXT:T__DosGetInfoSeg
+ dd offset _TEXT:T__Dos16Open
+ dd offset _TEXT:T__Dos16Open2
+ dd offset _TEXT:T__Dos16Read
+ dd offset _TEXT:T__Dos16Write
+ dd offset _TEXT:T__Dos16FindFirst
+ dd offset _TEXT:T__Dos16FindFirst2
+ dd offset _TEXT:T__Dos16EnumAttribute
+ dd offset _TEXT:T__DosQFileMode
+ dd offset _TEXT:T__DosQFileInfo
+ dd offset _TEXT:T__DosAllocSeg
+ dd offset _TEXT:T__DosFreeSeg
+ dd offset _TEXT:T__DosGetSeg
+ dd offset _TEXT:T__DosGiveSeg
+ dd offset _TEXT:T__DosReallocSeg
+ dd offset _TEXT:T__DosSizeSeg
+ dd offset _TEXT:T__DosAllocHuge
+ dd offset _TEXT:T__DosReallocHuge
+ dd offset _TEXT:T__DosGetHugeShift
+ dd offset _TEXT:T__DosAllocShrSeg
+ dd offset _TEXT:T__DosLockSeg
+ dd offset _TEXT:T__DosUnlockSeg
+ dd offset _TEXT:T__DosGetShrSeg
+ dd offset _TEXT:T__DosMemAvail
+ dd offset _TEXT:T__DosCreateCSAlias
+ dd offset _TEXT:T__DosSemClear
+ dd offset _TEXT:T__DosSemSet
+ dd offset _TEXT:T__DosSemWait
+ dd offset _TEXT:T__DosSemSetWait
+ dd offset _TEXT:T__DosSemRequest
+ dd offset _TEXT:T__DosCreateSem
+ dd offset _TEXT:T__DosOpenSem
+ dd offset _TEXT:T__DosCloseSem
+ dd offset _TEXT:T__DosMuxSemWait
+ dd offset _TEXT:T__DosFSRamSemRequest
+ dd offset _TEXT:T__DosFSRamSemClear
+ dd offset _TEXT:T__DosAsyncTimer
+ dd offset _TEXT:T__DosStartTimer
+ dd offset _TEXT:T__DosStopTimer
+ dd offset _TEXT:T__DosGetProcAddrNE
+ dd offset _TEXT:T__DosQueryProcType
+ dd offset _TEXT:T__DosQueryResourceSize
+ dd offset _TEXT:T__DosSetSigHandler
+ dd offset _TEXT:T_DosFlagProcess16
+ dd offset _TEXT:T_DosHoldSignal16
+ dd offset _TEXT:T_DosSendSignal16
+ dd offset _TEXT:T__DosSetVec
+ dd offset _TEXT:T__DosGetEnv
+ dd offset _TEXT:T__DosGetVersion
+ dd offset _TEXT:T__DosGetMachineMode
+ dd offset _TEXT:T__Dos16FindNext
+ dd offset _TEXT:T__DosGetPID
+ dd offset _TEXT:T__DosGetPPID
+ dd offset _TEXT:T__Dos16MkDir
+ dd offset _TEXT:T__Dos16MkDir2
+ dd offset _TEXT:T__DosSetFileMode
+ dd offset _TEXT:T__Dos16SetFileInfo
+ dd offset _TEXT:T__DosTrueGetMessage
+ dd offset _TEXT:T__DosScanEnvNE
+ dd offset _TEXT:T__DosPTrace
+ dd offset _TEXT:T__DosInsMessage
+ dd offset _TEXT:T__DosPutMessage
+ dd offset _TEXT:T__Dos16SubSet
+ dd offset _TEXT:T__Dos16SubAlloc
+ dd offset _TEXT:T__Dos16SubFree
+ dd offset _TEXT:T__Dos16StartSession
+ dd offset _TEXT:T__DosStopSession
+ dd offset _TEXT:T__DosSetSession
+ dd offset _TEXT:T__DosSelectSession
+ dd offset _TEXT:T__DosSMSetTitle
+ dd offset _TEXT:T__DosSMPMPresent
+ dd offset _TEXT:T__WinSetTitleAndIcon
+ dd offset _TEXT:T__DosGetPriority
+ dd offset _TEXT:T__DosQSysInfo
+ dd offset _TEXT:T__DosDevIOCtl2
+ dd offset _TEXT:T__DosICanonicalize
+ dd offset _TEXT:T__DosReadAsync
+ dd offset _TEXT:T__DosWriteAsync
+ dd offset _TEXT:T__DosFindNotifyClose
+ dd offset _TEXT:T__DosFindNotifyFirst
+ dd offset _TEXT:T__DosFindNotifyNext
+ dd offset _TEXT:T__DosFileLocks
+ dd offset _TEXT:T__Dos16QPathInfo
+ dd offset _TEXT:T__Dos16SetPathInfo
+ dd offset _TEXT:T__DosPortAccess
+ dd offset _TEXT:T__DosCLIAccess
+ dd offset _TEXT:T__WinQueryProfileString
+ dd offset _TEXT:T__WinQueryProfileSize
+ dd offset _TEXT:T__WinQueryProfileData
+ dd offset _TEXT:T__WinQueryProfileInt
+ dd offset _TEXT:T__WinWriteProfileData
+ dd offset _TEXT:T__WinWriteProfileString
+ dd offset _TEXT:T__WinCreateHeap
+ dd offset _TEXT:T__WinDestroyHeap
+ dd offset _TEXT:T__WinAllocMem
+ dd offset _TEXT:T__WinFreeMem
+ dd offset _TEXT:T__WinGetLastError
+ dd offset _TEXT:T__VioScrollUp
+ dd offset _TEXT:T__VioGetCurPos
+ dd offset _TEXT:T__VioSetCurPos
+ dd offset _TEXT:T__VioWrtTTY
+ dd offset _TEXT:T__VioGetMode
+ dd offset _TEXT:T__VioReadCellStr
+ dd offset _TEXT:T__VioScrollLf
+ dd offset _TEXT:T__VioReadCharStr
+ dd offset _TEXT:T__VioWrtCharStrAtt
+ dd offset _TEXT:T__VioWrtCellStr
+ dd offset _TEXT:T__VioWrtCharStr
+ dd offset _TEXT:T__VioWrtNCell
+ dd offset _TEXT:T__VioWrtNAttr
+ dd offset _TEXT:T__VioWrtNChar
+ dd offset _TEXT:T__VioScrollDn
+ dd offset _TEXT:T__VioScrollRt
+ dd offset _TEXT:T__VioGetAnsi
+ dd offset _TEXT:T__VioSetAnsi
+ dd offset _TEXT:T__VioGetConfig
+ dd offset _TEXT:T__VioGetCp
+ dd offset _TEXT:T__VioSetCp
+ dd offset _TEXT:T__VioGetCurType
+ dd offset _TEXT:T__VioSetCurType
+ dd offset _TEXT:T__VioSetMode
+ dd offset _TEXT:T__VioDeRegister
+ dd offset _TEXT:T__VioRegister
+ dd offset _TEXT:T__VioPopUp
+ dd offset _TEXT:T__VioEndPopUp
+ dd offset _TEXT:T__VioGetBuf
+ dd offset _TEXT:T__VioShowBuf
+ dd offset _TEXT:T__VioGetFont
+ dd offset _TEXT:T__VioSetFont
+ dd offset _TEXT:T__VioGetState
+ dd offset _TEXT:T__VioSetState
+ dd offset _TEXT:T__VioGetPhysBuf
+ dd offset _TEXT:T__VioModeUndo
+ dd offset _TEXT:T__VioModeWait
+ dd offset _TEXT:T__VioSavRedrawWait
+ dd offset _TEXT:T__VioSavRedrawUndo
+ dd offset _TEXT:T__VioScrLock
+ dd offset _TEXT:T__VioScrUnLock
+ dd offset _TEXT:T__VioPrtSc
+ dd offset _TEXT:T__VioPrtScToggle
+ dd offset _TEXT:T__KbdFlushBuffer
+ dd offset _TEXT:T__KbdGetStatus
+ dd offset _TEXT:T__KbdSetStatus
+ dd offset _TEXT:T__KbdPeek
+ dd offset _TEXT:T__KbdCharIn
+ dd offset _TEXT:T__KbdStringIn
+ dd offset _TEXT:T__KbdGetFocus
+ dd offset _TEXT:T__KbdFreeFocus
+ dd offset _TEXT:T__KbdClose
+ dd offset _TEXT:T__KbdOpen
+ dd offset _TEXT:T__KbdDeRegister
+ dd offset _TEXT:T__KbdRegister
+ dd offset _TEXT:T__KbdGetCp
+ dd offset _TEXT:T__KbdSetCp
+ dd offset _TEXT:T__KbdSetCustXt
+ dd offset _TEXT:T__KbdXlate
+ dd offset _TEXT:T__KbdGetHWID
+ dd offset _TEXT:T__KbdSetFgnd
+ dd offset _TEXT:T__KbdSynch
+ dd offset _TEXT:T__KbdShellInit
+ dd offset _TEXT:T__MouClose
+ dd offset _TEXT:T__MouDeRegister
+ dd offset _TEXT:T__MouDrawPtr
+ dd offset _TEXT:T__MouFlushQue
+ dd offset _TEXT:T__MouGetDevStatus
+ dd offset _TEXT:T__MouGetEventMask
+ dd offset _TEXT:T__MouGetNumButtons
+ dd offset _TEXT:T__MouGetNumMickeys
+ dd offset _TEXT:T__MouGetNumQueEl
+ dd offset _TEXT:T__MouGetPtrPos
+ dd offset _TEXT:T__MouGetPtrShape
+ dd offset _TEXT:T__MouGetScaleFact
+ dd offset _TEXT:T__MouOpen
+ dd offset _TEXT:T__MouReadEventQue
+ dd offset _TEXT:T__MouRegister
+ dd offset _TEXT:T__MouRemovePtr
+ dd offset _TEXT:T__MouSetDevStatus
+ dd offset _TEXT:T__MouSetEventMask
+ dd offset _TEXT:T__MouSetPtrPos
+ dd offset _TEXT:T__MouSetPtrShape
+ dd offset _TEXT:T__MouSetScaleFact
+ dd offset _TEXT:T__MouSynch
+ dd offset _TEXT:T__DosMonOpen
+ dd offset _TEXT:T__DosMonClose
+ dd offset _TEXT:T__DosMonRead
+ dd offset _TEXT:T__DosMonReg
+ dd offset _TEXT:T__DosMonWrite
+ dd offset _TEXT:T__Net16GetDCName
+ dd offset _TEXT:T__Net16HandleGetInfo
+ dd offset _TEXT:T__Net16ServerDiskEnum
+ dd offset _TEXT:T__Net16ServerEnum2
+ dd offset _TEXT:T__Net16ServerGetInfo
+ dd offset _TEXT:T__Net16ServiceControl
+ dd offset _TEXT:T__Net16ServiceEnum
+ dd offset _TEXT:T__Net16ServiceGetInfo
+ dd offset _TEXT:T__Net16ServiceInstall
+ dd offset _TEXT:T__Net16ShareEnum
+ dd offset _TEXT:T__Net16ShareGetInfo
+ dd offset _TEXT:T__Net16UseAdd
+ dd offset _TEXT:T__Net16UseDel
+ dd offset _TEXT:T__Net16UseEnum
+ dd offset _TEXT:T__Net16UseGetInfo
+ dd offset _TEXT:T__Net16UserEnum
+ dd offset _TEXT:T__Net16WkstaGetInfo
+ dd offset _TEXT:T__Net16AccessAdd
+ dd offset _TEXT:T__Net16AccessSetInfo
+ dd offset _TEXT:T__Net16AccessGetInfo
+ dd offset _TEXT:T__Net16AccessDel
+ dd offset _TEXT:T__Net16ShareAdd
+ dd offset _TEXT:T__Net16ShareDel
+ dd offset _TEXT:T__Net16UserGetInfo
+ dd offset _TEXT:T__Net16MessageBufferSend
+ dd offset _TEXT:T__Net16bios
+ dd offset _TEXT:T__Net16BiosClose
+ dd offset _TEXT:T__Net16BiosEnum
+ dd offset _TEXT:T__Net16BiosGetInfo
+ dd offset _TEXT:T__Net16BiosOpen
+ dd offset _TEXT:T__Net16BiosSubmit
+ dd offset _TEXT:T__Dos16MakeMailslot
+ dd offset _TEXT:T__Dos16DeleteMailslot
+ dd offset _TEXT:T__Dos16MailslotInfo
+ dd offset _TEXT:T__Dos16PeekMailslot
+ dd offset _TEXT:T__Dos16ReadMailslot
+ dd offset _TEXT:T__Dos16WriteMailslot
+ dd offset _TEXT:T__DosIRemoteApi
+ dd offset _TEXT:T__NetIWkstaGetUserInfo
+ dd offset _TEXT:T__NetIUserPasswordSet
+ dd offset _TEXT:T__DosIEncryptSES
+ dd offset _TEXT:T__Dos32LoadModule
+ dd offset _TEXT:T__Dos32GetProcAddr
+ dd offset _TEXT:T__Dos32Dispatch
+ dd offset _TEXT:T__Dos32FreeModule
+ dd offset _TEXT:T__FarPtr2FlatPtr
+ dd offset _TEXT:T__FlatPtr2FarPtr
+
+;---- SelToFlat Macro ----
+; On Entry: eax==Sel:Off
+; On Exit: eax==Flat Offset
+SelToFlat macro
+ push ecx
+xor ecx,ecx
+mov cx,ax ; ecx<-offset in segment
+shr eax,3
+xor ax,ax ; eax now contains segment base
+ add eax,ecx ; eax <- flat offset
+ add eax,38000000H
+ pop ecx
+endm
+
+;===========================================================================
+T__DosExitStub label near
+
+
+;-------------------------------------
+; create new call frame and make the call
+
+ call _DosExitStub@0 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_0
+
+;===========================================================================
+T__LDRLibiReturn label near
+
+
+;-------------------------------------
+; create new call frame and make the call
+
+ call _LDRLibiReturn@0 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_0
+
+;===========================================================================
+T__DosExitProcessStub label near
+
+
+;-------------------------------------
+; create new call frame and make the call
+
+ call _DosExitProcessStub@0 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_0
+
+;===========================================================================
+T__DosReturn label near
+
+; ebx+26 param1
+; ebx+24 param2
+
+;-------------------------------------
+; create new call frame and make the call
+
+; param2 from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; param1 from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+ call _DosReturn@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosExit label near
+
+; ebx+26
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+ call _DosExit@8 ; call 32-bit version
+
+; return code void --> void
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__Dos16WaitChild label near
+
+; ebx+36
+; ebx+34
+; ebx+30 prescResults
+; ebx+26 ppidProcess
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 prescResults
+ push eax ; ptr param #2 ppidProcess
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; prescResults
+; pointer void --> void
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L0 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L0:
+
+; ppidProcess
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L1 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L1:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; ppidProcess from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; prescResults from: void
+ push dword ptr [esp+12] ; to: void
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+ call _Dos16WaitChild@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__DosBeep label near
+
+; ebx+26
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+ call _DosBeep@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosPhysicalDisk label near
+
+; ebx+36
+; ebx+32 pbOutBuf
+; ebx+30 cbOutBuf
+; ebx+26 pbParamBuf
+; ebx+24 cbParamBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pbOutBuf
+ push eax ; ptr param #2 pbParamBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pbOutBuf
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L2 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L2:
+
+; pbParamBuf
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L3 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L3:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbParamBuf from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbParamBuf from: char
+ push dword ptr [esp+4] ; to: char
+
+; cbOutBuf from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; pbOutBuf from: char
+ push dword ptr [esp+16] ; to: char
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+ call _DosPhysicalDisk@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__DosGetCp label near
+
+; ebx+32 cbBuf
+; ebx+28 pBuf
+; ebx+24 pcbCodePgLst
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pBuf
+ push eax ; ptr param #2 pcbCodePgLst
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pBuf
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L4 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L4:
+
+; pcbCodePgLst
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L5 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L5:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbCodePgLst from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pBuf from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _DosGetCp@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__DosSetCp label near
+
+; ebx+26 usCodePage
+; ebx+24 ulReserved
+
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; usCodePage from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+ call _DosSetCp@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosSetProcCp label near
+
+; ebx+26 usCodePage
+; ebx+24 ulReserved
+
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; usCodePage from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+ call _DosSetProcCp@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosGetCtryInfo label near
+
+; ebx+36 cbBuf
+; ebx+32 pctryc
+; ebx+28 pctryi
+; ebx+24 pcbCtryInfo
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pctryc
+ push eax ; ptr param #2 pctryi
+ push eax ; ptr param #3 pcbCtryInfo
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pctryc
+; pointer void --> void
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L6 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L6:
+
+; pctryi
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L7 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L7:
+
+; pcbCtryInfo
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L8 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L8:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbCtryInfo from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pctryi from: void
+ push dword ptr [esp+8] ; to: void
+
+; pctryc from: void
+ push dword ptr [esp+16] ; to: void
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+ call _DosGetCtryInfo@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__DosGetDBCSEv label near
+
+; ebx+32 cbBuf
+; ebx+28 pcrtyc
+; ebx+24 pchBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pcrtyc
+ push eax ; ptr param #2 pchBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pcrtyc
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L9 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L9:
+
+; pchBuf
+; pointer char --> char
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L10 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L10:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pchBuf from: char
+ push dword ptr [esp+0] ; to: char
+
+; pcrtyc from: void
+ push dword ptr [esp+8] ; to: void
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _DosGetDBCSEv@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__DosCaseMap label near
+
+; ebx+32 usLen
+; ebx+28 pctryc
+; ebx+24 pchStr
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pctryc
+ push eax ; ptr param #2 pchStr
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pctryc
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L11 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L11:
+
+; pchStr
+; pointer char --> char
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L12 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L12:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pchStr from: char
+ push dword ptr [esp+0] ; to: char
+
+; pctryc from: void
+ push dword ptr [esp+8] ; to: void
+
+; usLen from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _DosCaseMap@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__DosGetCollate label near
+
+; ebx+36 cbBuf
+; ebx+32 pctryc
+; ebx+28 pchBuf
+; ebx+24 pcbTable
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pctryc
+ push eax ; ptr param #2 pchBuf
+ push eax ; ptr param #3 pcbTable
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pctryc
+; pointer void --> void
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L13 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L13:
+
+; pchBuf
+; pointer char --> char
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L14 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L14:
+
+; pcbTable
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L15 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L15:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbTable from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pchBuf from: char
+ push dword ptr [esp+8] ; to: char
+
+; pctryc from: void
+ push dword ptr [esp+16] ; to: void
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+ call _DosGetCollate@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__DosSleep label near
+
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+ call _DosSleep@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosDevConfig label near
+
+; ebx+28 DevInfo
+; ebx+26 item
+; ebx+24 reserved
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 DevInfo
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; DevInfo
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L16 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L16:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; item from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; DevInfo from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _DosDevConfig@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosGetDateTime label near
+
+; ebx+24 pDT
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pDT
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pDT
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L17 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L17:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pDT from: void
+ push dword ptr [esp+0] ; to: void
+
+ call _DosGetDateTime@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosSetDateTime label near
+
+; ebx+24 pDT
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pDT
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pDT
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L18 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L18:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pDT from: void
+ push dword ptr [esp+0] ; to: void
+
+ call _DosSetDateTime@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__Dos16ExecPgm label near
+
+; ebx+44 pchFailName
+; ebx+42 cbFailName
+; ebx+40
+; ebx+36
+; ebx+32
+; ebx+28 prescResults
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pchFailName
+ push eax ; ptr param #2
+ push eax ; ptr param #3
+ push eax ; ptr param #4 prescResults
+ push eax ; ptr param #5
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pchFailName
+; pointer char --> char
+ mov eax,[ebx+44] ; base address
+ or eax,eax
+ jz L19 ; skip if null
+
+ SelToFlat
+ mov [esp+16],eax
+L19:
+
+; pointer string --> string
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L20 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L20:
+
+; pointer string --> string
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L21 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L21:
+
+; prescResults
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L22 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L22:
+
+; pointer string --> string
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L23 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L23:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: string
+ push dword ptr [esp+0] ; to: string
+
+; prescResults from: void
+ push dword ptr [esp+8] ; to: void
+
+; from: string
+ push dword ptr [esp+16] ; to: string
+
+; from: string
+ push dword ptr [esp+24] ; to: string
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+40]
+ push eax ; to: unsigned long
+
+; cbFailName from: unsigned short
+ movzx eax,word ptr [ebx+42]
+ push eax ; to: unsigned long
+
+; pchFailName from: char
+ push dword ptr [esp+40] ; to: char
+
+ call _Dos16ExecPgm@28 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_24
+
+;===========================================================================
+T__DosEnterCritSec label near
+
+
+;-------------------------------------
+; create new call frame and make the call
+
+ call _DosEnterCritSec@0 ; call 32-bit version
+
+; return code void --> void
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_0
+
+;===========================================================================
+T__DosExitCritSec label near
+
+
+;-------------------------------------
+; create new call frame and make the call
+
+ call _DosExitCritSec@0 ; call 32-bit version
+
+; return code void --> void
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_0
+
+;===========================================================================
+T__DosKillProcess label near
+
+; ebx+26
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+ call _DosKillProcess@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosSetPriority label near
+
+; ebx+30
+; ebx+28
+; ebx+26
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; from: short
+ movsx eax,word ptr [ebx+26]
+ push eax ; to: long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _DosSetPriority@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosResumeThread label near
+
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosResumeThread@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosSuspendThread label near
+
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosSuspendThread@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__Dos16CreatePipe label near
+
+; ebx+30 phfRead
+; ebx+26 phfWrite
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 phfRead
+ push eax ; ptr param #2 phfWrite
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; phfRead
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L24 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L24:
+
+; phfWrite
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L25 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L25:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; phfWrite from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; phfRead from: unsigned short
+ push dword ptr [esp+12] ; to: unsigned short
+
+ call _Dos16CreatePipe@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__Dos16CreateQueue label near
+
+; ebx+30 phqueue
+; ebx+28
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 phqueue
+ push eax ; ptr param #2
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; phqueue
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L26 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L26:
+
+; pointer string --> string
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L27 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L27:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: string
+ push dword ptr [esp+0] ; to: string
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; phqueue from: unsigned short
+ push dword ptr [esp+12] ; to: unsigned short
+
+ call _Dos16CreateQueue@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__Dos16OpenQueue label near
+
+; ebx+32 ppidOwner
+; ebx+28 phqueue
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 ppidOwner
+ push eax ; ptr param #2 phqueue
+ push eax ; ptr param #3
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; ppidOwner
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L28 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L28:
+
+; phqueue
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L29 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L29:
+
+; pointer string --> string
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L30 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L30:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: string
+ push dword ptr [esp+0] ; to: string
+
+; phqueue from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; ppidOwner from: unsigned short
+ push dword ptr [esp+16] ; to: unsigned short
+
+ call _Dos16OpenQueue@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__DosCloseQueue label near
+
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosCloseQueue@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__Dos16PeekQueue label near
+
+; ebx+50
+; ebx+46 pulResult
+; ebx+42 pusDataLength
+; ebx+38 pulDataAddr
+; ebx+34 pusElementCode
+; ebx+32
+; ebx+28 pbElemPrty
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pulResult
+ push eax ; ptr param #2 pusDataLength
+ push eax ; ptr param #3 pulDataAddr
+ push eax ; ptr param #4 pusElementCode
+ push eax ; ptr param #5 pbElemPrty
+ push eax ; ptr param #6
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pulResult
+; pointer void --> void
+ mov eax,[ebx+46] ; base address
+ or eax,eax
+ jz L31 ; skip if null
+
+ SelToFlat
+ mov [esp+20],eax
+L31:
+
+; pusDataLength
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+42] ; base address
+ or eax,eax
+ jz L32 ; skip if null
+
+ SelToFlat
+ mov [esp+16],eax
+L32:
+
+; pulDataAddr
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+38] ; base address
+ or eax,eax
+ jz L33 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L33:
+
+; pusElementCode
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L34 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L34:
+
+; pbElemPrty
+; pointer char --> char
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L35 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L35:
+
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L36 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L36:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: void
+ push dword ptr [esp+0] ; to: void
+
+; pbElemPrty from: char
+ push dword ptr [esp+8] ; to: char
+
+; from: unsigned char
+ movzx eax,byte ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; pusElementCode from: unsigned short
+ push dword ptr [esp+20] ; to: unsigned short
+
+; pulDataAddr from: unsigned long
+ push dword ptr [esp+28] ; to: unsigned long
+
+; pusDataLength from: unsigned short
+ push dword ptr [esp+36] ; to: unsigned short
+
+; pulResult from: void
+ push dword ptr [esp+44] ; to: void
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+50]
+ push eax ; to: unsigned long
+
+ call _Dos16PeekQueue@32 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_28
+
+;===========================================================================
+T__Dos16ReadQueue label near
+
+; ebx+48
+; ebx+44 pulResult
+; ebx+40 pusDataLength
+; ebx+36 pulDataAddr
+; ebx+34
+; ebx+32
+; ebx+28 pbElemPrty
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pulResult
+ push eax ; ptr param #2 pusDataLength
+ push eax ; ptr param #3 pulDataAddr
+ push eax ; ptr param #4 pbElemPrty
+ push eax ; ptr param #5
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pulResult
+; pointer void --> void
+ mov eax,[ebx+44] ; base address
+ or eax,eax
+ jz L37 ; skip if null
+
+ SelToFlat
+ mov [esp+16],eax
+L37:
+
+; pusDataLength
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L38 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L38:
+
+; pulDataAddr
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L39 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L39:
+
+; pbElemPrty
+; pointer char --> char
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L40 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L40:
+
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L41 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L41:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: void
+ push dword ptr [esp+0] ; to: void
+
+; pbElemPrty from: char
+ push dword ptr [esp+8] ; to: char
+
+; from: unsigned char
+ movzx eax,byte ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+; pulDataAddr from: unsigned long
+ push dword ptr [esp+24] ; to: unsigned long
+
+; pusDataLength from: unsigned short
+ push dword ptr [esp+32] ; to: unsigned short
+
+; pulResult from: void
+ push dword ptr [esp+40] ; to: void
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+48]
+ push eax ; to: unsigned long
+
+ call _Dos16ReadQueue@32 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_26
+
+;===========================================================================
+T__DosPurgeQueue label near
+
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosPurgeQueue@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__Dos16QueryQueue label near
+
+; ebx+28
+; ebx+24 pusElemCount
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pusElemCount
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pusElemCount
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L42 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L42:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pusElemCount from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _Dos16QueryQueue@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__DosWriteQueue label near
+
+; ebx+34
+; ebx+32
+; ebx+30 cbBuf
+; ebx+26 pbBuf
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pbBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pbBuf
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L43 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L43:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned char
+ movzx eax,byte ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbBuf from: char
+ push dword ptr [esp+4] ; to: char
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+ call _DosWriteQueue@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__Dos16CallNPipe label near
+
+; ebx+44
+; ebx+40 pbInBuf
+; ebx+38 cbInBuf
+; ebx+34 pbOutBuf
+; ebx+32 cbOutBuf
+; ebx+28 pcbRead
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+ push eax ; ptr param #2 pbInBuf
+ push eax ; ptr param #3 pbOutBuf
+ push eax ; ptr param #4 pcbRead
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer string --> string
+ mov eax,[ebx+44] ; base address
+ or eax,eax
+ jz L44 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L44:
+
+; pbInBuf
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L45 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L45:
+
+; pbOutBuf
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L46 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L46:
+
+; pcbRead
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L47 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L47:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; pcbRead from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; cbOutBuf from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; pbOutBuf from: char
+ push dword ptr [esp+16] ; to: char
+
+; cbInBuf from: unsigned short
+ movzx eax,word ptr [ebx+38]
+ push eax ; to: unsigned long
+
+; pbInBuf from: char
+ push dword ptr [esp+28] ; to: char
+
+; from: string
+ push dword ptr [esp+36] ; to: string
+
+ call _Dos16CallNPipe@28 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_24
+
+;===========================================================================
+T__DosConnectNPipe label near
+
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosConnectNPipe@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosDisConnectNPipe label near
+
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosDisConnectNPipe@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__Dos16CreateNPipe label near
+
+; ebx+40
+; ebx+36 pHandle
+; ebx+34
+; ebx+32
+; ebx+30
+; ebx+28
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+ push eax ; ptr param #2 pHandle
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer string --> string
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L48 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L48:
+
+; pHandle
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L49 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L49:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+; pHandle from: unsigned short
+ push dword ptr [esp+20] ; to: unsigned short
+
+; from: string
+ push dword ptr [esp+28] ; to: string
+
+ call _Dos16CreateNPipe@28 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Dos16PeekNPipe label near
+
+; ebx+42
+; ebx+38 pbBuf
+; ebx+36 cbBuf
+; ebx+32 pcbRead
+; ebx+28 pcbAvail
+; ebx+24 pfsState
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pbBuf
+ push eax ; ptr param #2 pcbRead
+ push eax ; ptr param #3 pcbAvail
+ push eax ; ptr param #4 pfsState
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pbBuf
+; pointer char --> char
+ mov eax,[ebx+38] ; base address
+ or eax,eax
+ jz L50 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L50:
+
+; pcbRead
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L51 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L51:
+
+; pcbAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L52 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L52:
+
+; pfsState
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L53 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L53:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pfsState from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pcbAvail from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; pcbRead from: unsigned short
+ push dword ptr [esp+16] ; to: unsigned short
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+; pbBuf from: char
+ push dword ptr [esp+28] ; to: char
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+42]
+ push eax ; to: unsigned long
+
+ call _Dos16PeekNPipe@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Dos16QueryNPHState label near
+
+; ebx+28
+; ebx+24 pfsState
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pfsState
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pfsState
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L54 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L54:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pfsState from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _Dos16QueryNPHState@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__DosQueryNPipeInfo label near
+
+; ebx+32
+; ebx+30
+; ebx+26 pbBuf
+; ebx+24 cbBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pbBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pbBuf
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L55 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L55:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbBuf from: char
+ push dword ptr [esp+4] ; to: char
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _DosQueryNPipeInfo@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__DosQueryNPipeSemState label near
+
+; ebx+30
+; ebx+26 pbBuf
+; ebx+24 cbBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+ push eax ; ptr param #2 pbBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer void --> void
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L56 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L56:
+
+; pbBuf
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L57 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L57:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbBuf from: char
+ push dword ptr [esp+4] ; to: char
+
+; from: void
+ push dword ptr [esp+12] ; to: void
+
+ call _DosQueryNPipeSemState@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__DosSetNPHState label near
+
+; ebx+26
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+ call _DosSetNPHState@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosSetNPipeSem label near
+
+; ebx+30
+; ebx+26
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L58 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L58:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; from: void
+ push dword ptr [esp+4] ; to: void
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _DosSetNPipeSem@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__Dos16TransactNPipe label near
+
+; ebx+40
+; ebx+36 pbInBuf
+; ebx+34 cbInBuf
+; ebx+30 pbOutBuf
+; ebx+28 cbOutBuf
+; ebx+24 pcbRead
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pbInBuf
+ push eax ; ptr param #2 pbOutBuf
+ push eax ; ptr param #3 pcbRead
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pbInBuf
+; pointer char --> char
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L59 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L59:
+
+; pbOutBuf
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L60 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L60:
+
+; pcbRead
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L61 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L61:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbRead from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbOutBuf from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pbOutBuf from: char
+ push dword ptr [esp+12] ; to: char
+
+; cbInBuf from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+; pbInBuf from: char
+ push dword ptr [esp+24] ; to: char
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+40]
+ push eax ; to: unsigned long
+
+ call _Dos16TransactNPipe@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_18
+
+;===========================================================================
+T__DosWaitNPipe label near
+
+; ebx+28
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L62 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L62:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; from: string
+ push dword ptr [esp+4] ; to: string
+
+ call _DosWaitNPipe@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosResetBuffer label near
+
+; ebx+24 hand
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hand from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosResetBuffer@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosSetCurrentDir label near
+
+; ebx+28
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L63 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L63:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: string
+ push dword ptr [esp+0] ; to: string
+
+ call _DosSetCurrentDir@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosSetFilePtr label near
+
+; ebx+34
+; ebx+30
+; ebx+28
+; ebx+24 pulNewPtr
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pulNewPtr
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pulNewPtr
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L64 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L64:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pulNewPtr from: unsigned long
+ push dword ptr [esp+0] ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; from: long
+ push dword ptr [ebx+30] ; to long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+ call _DosSetFilePtr@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__DosClose label near
+
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosClose@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosCopy label near
+
+; ebx+34
+; ebx+30
+; ebx+28
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+ push eax ; ptr param #2
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer string --> string
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L65 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L65:
+
+; pointer string --> string
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L66 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L66:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; from: string
+ push dword ptr [esp+4] ; to: string
+
+; from: string
+ push dword ptr [esp+12] ; to: string
+
+ call _DosCopy@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__DosICopy label near
+
+; ebx+34
+; ebx+30
+; ebx+28
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+ push eax ; ptr param #2
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer string --> string
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L67 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L67:
+
+; pointer string --> string
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L68 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L68:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; from: string
+ push dword ptr [esp+4] ; to: string
+
+; from: string
+ push dword ptr [esp+12] ; to: string
+
+ call _DosICopy@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__DosDelete label near
+
+; ebx+28
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L69 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L69:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: string
+ push dword ptr [esp+0] ; to: string
+
+ call _DosDelete@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosDevIOCtl label near
+
+; ebx+34 pvData
+; ebx+30 pvParms
+; ebx+28 Function
+; ebx+26 Category
+; ebx+24 hDev
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pvData
+ push eax ; ptr param #2 pvParms
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pvData
+; pointer void --> void
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L70 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L70:
+
+; pvParms
+; pointer void --> void
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L71 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L71:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hDev from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; Category from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; Function from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pvParms from: void
+ push dword ptr [esp+12] ; to: void
+
+; pvData from: void
+ push dword ptr [esp+20] ; to: void
+
+ call _DosDevIOCtl@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__Dos16DupHandle label near
+
+; ebx+28
+; ebx+24 phfNew
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 phfNew
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; phfNew
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L72 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L72:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; phfNew from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _Dos16DupHandle@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__DosEditName label near
+
+; ebx+38
+; ebx+34
+; ebx+30
+; ebx+26 pszTargetBuf
+; ebx+24 cbTargetBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+ push eax ; ptr param #2
+ push eax ; ptr param #3 pszTargetBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer string --> string
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L73 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L73:
+
+; pointer string --> string
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L74 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L74:
+
+; pszTargetBuf
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L75 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L75:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbTargetBuf from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pszTargetBuf from: char
+ push dword ptr [esp+4] ; to: char
+
+; from: string
+ push dword ptr [esp+12] ; to: string
+
+; from: string
+ push dword ptr [esp+20] ; to: string
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+38]
+ push eax ; to: unsigned long
+
+ call _DosEditName@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T__DosFileIO label near
+
+; ebx+34
+; ebx+30 buf
+; ebx+28 cbBuf
+; ebx+24 usErr
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 buf
+ push eax ; ptr param #2 usErr
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; buf
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L76 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L76:
+
+; usErr
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L77 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L77:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; usErr from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; buf from: char
+ push dword ptr [esp+12] ; to: char
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+ call _DosFileIO@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__DosFindClose label near
+
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosFindClose@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosFSAttach label near
+
+; ebx+40
+; ebx+36
+; ebx+32 pbBuf
+; ebx+30 cbBuf
+; ebx+28
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+ push eax ; ptr param #2
+ push eax ; ptr param #3 pbBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer string --> string
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L78 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L78:
+
+; pointer string --> string
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L79 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L79:
+
+; pbBuf
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L80 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L80:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; pbBuf from: char
+ push dword ptr [esp+8] ; to: char
+
+; from: string
+ push dword ptr [esp+16] ; to: string
+
+; from: string
+ push dword ptr [esp+24] ; to: string
+
+ call _DosFSAttach@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Dos16FSCtl label near
+
+; ebx+54 pData
+; ebx+52 cbData
+; ebx+48 pcbData
+; ebx+44 pParms
+; ebx+42 cbParms
+; ebx+38 pcbParms
+; ebx+36
+; ebx+32
+; ebx+30 hfRoute
+; ebx+28
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pData
+ push eax ; ptr param #2 pcbData
+ push eax ; ptr param #3 pParms
+ push eax ; ptr param #4 pcbParms
+ push eax ; ptr param #5
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pData
+; pointer char --> char
+ mov eax,[ebx+54] ; base address
+ or eax,eax
+ jz L81 ; skip if null
+
+ SelToFlat
+ mov [esp+16],eax
+L81:
+
+; pcbData
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+48] ; base address
+ or eax,eax
+ jz L82 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L82:
+
+; pParms
+; pointer char --> char
+ mov eax,[ebx+44] ; base address
+ or eax,eax
+ jz L83 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L83:
+
+; pcbParms
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+38] ; base address
+ or eax,eax
+ jz L84 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L84:
+
+; pointer string --> string
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L85 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L85:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; hfRoute from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; from: string
+ push dword ptr [esp+8] ; to: string
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+; pcbParms from: unsigned short
+ push dword ptr [esp+20] ; to: unsigned short
+
+; cbParms from: unsigned short
+ movzx eax,word ptr [ebx+42]
+ push eax ; to: unsigned long
+
+; pParms from: char
+ push dword ptr [esp+32] ; to: char
+
+; pcbData from: unsigned short
+ push dword ptr [esp+40] ; to: unsigned short
+
+; cbData from: unsigned short
+ movzx eax,word ptr [ebx+52]
+ push eax ; to: unsigned long
+
+; pData from: char
+ push dword ptr [esp+52] ; to: char
+
+ call _Dos16FSCtl@40 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_34
+
+;===========================================================================
+T__DosMove label near
+
+; ebx+32
+; ebx+28
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+ push eax ; ptr param #2
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer string --> string
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L86 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L86:
+
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L87 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L87:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: string
+ push dword ptr [esp+0] ; to: string
+
+; from: string
+ push dword ptr [esp+8] ; to: string
+
+ call _DosMove@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__DosSetFileSize label near
+
+; ebx+28
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _DosSetFileSize@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__Dos16QueryCurrentDir label near
+
+; ebx+32
+; ebx+28 pszPathBuf
+; ebx+24 pcbPathBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszPathBuf
+ push eax ; ptr param #2 pcbPathBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszPathBuf
+; pointer char --> char
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L88 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L88:
+
+; pcbPathBuf
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L89 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L89:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbPathBuf from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pszPathBuf from: char
+ push dword ptr [esp+8] ; to: char
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _Dos16QueryCurrentDir@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__Dos16QueryCurrentDisk label near
+
+; ebx+28 pusDriveNumber
+; ebx+24 pulLogicalDrives
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pusDriveNumber
+ push eax ; ptr param #2 pulLogicalDrives
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pusDriveNumber
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L90 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L90:
+
+; pulLogicalDrives
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L91 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L91:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pulLogicalDrives from: unsigned long
+ push dword ptr [esp+0] ; to: unsigned long
+
+; pusDriveNumber from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+ call _Dos16QueryCurrentDisk@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__Dos16QueryFHState label near
+
+; ebx+28
+; ebx+24 pfsStateFlags
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pfsStateFlags
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pfsStateFlags
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L92 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L92:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pfsStateFlags from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _Dos16QueryFHState@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__DosSetFHState label near
+
+; ebx+26 hf
+; ebx+24 fsState
+
+;-------------------------------------
+; create new call frame and make the call
+
+; fsState from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; hf from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+ call _DosSetFHState@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__Dos16QFSAttach label near
+
+; ebx+40 pszDev
+; ebx+38 usOrdinal
+; ebx+36 usInfoLevel
+; ebx+32 pFSAttBuf
+; ebx+28 pcbAttBuf
+; ebx+24 ulReserved
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszDev
+ push eax ; ptr param #2 pFSAttBuf
+ push eax ; ptr param #3 pcbAttBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszDev
+; pointer string --> string
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L93 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L93:
+
+; pFSAttBuf
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L94 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L94:
+
+; pcbAttBuf
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L95 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L95:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; pcbAttBuf from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; pFSAttBuf from: char
+ push dword ptr [esp+12] ; to: char
+
+; usInfoLevel from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+; usOrdinal from: unsigned short
+ movzx eax,word ptr [ebx+38]
+ push eax ; to: unsigned long
+
+; pszDev from: string
+ push dword ptr [esp+28] ; to: string
+
+ call _Dos16QFSAttach@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__DosQueryFSInfo label near
+
+; ebx+32
+; ebx+30
+; ebx+26 pbInfo
+; ebx+24 cbInfo
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pbInfo
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pbInfo
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L96 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L96:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbInfo from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbInfo from: char
+ push dword ptr [esp+4] ; to: char
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _DosQueryFSInfo@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__Dos16QueryHType label near
+
+; ebx+32
+; ebx+28 pusHandType
+; ebx+24 pusDeviceAttr
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pusHandType
+ push eax ; ptr param #2 pusDeviceAttr
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pusHandType
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L97 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L97:
+
+; pusDeviceAttr
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L98 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L98:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pusDeviceAttr from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pusHandType from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _Dos16QueryHType@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__Dos16QueryVerify label near
+
+; ebx+24 fVerifyOn
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 fVerifyOn
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; fVerifyOn
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L99 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L99:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; fVerifyOn from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+ call _Dos16QueryVerify@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosDeleteDir label near
+
+; ebx+28
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L100 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L100:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: string
+ push dword ptr [esp+0] ; to: string
+
+ call _DosDeleteDir@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosSearchPath label near
+
+; ebx+38
+; ebx+34
+; ebx+30
+; ebx+26 pbBuf
+; ebx+24 cbBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+ push eax ; ptr param #2
+ push eax ; ptr param #3 pbBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer string --> string
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L101 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L101:
+
+; pointer string --> string
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L102 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L102:
+
+; pbBuf
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L103 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L103:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbBuf from: char
+ push dword ptr [esp+4] ; to: char
+
+; from: string
+ push dword ptr [esp+12] ; to: string
+
+; from: string
+ push dword ptr [esp+20] ; to: string
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+38]
+ push eax ; to: unsigned long
+
+ call _DosSearchPath@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T__DosSetDefaultDisk label near
+
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosSetDefaultDisk@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosSetFSInfo label near
+
+; ebx+32
+; ebx+30
+; ebx+26 pbBuf
+; ebx+24 cbBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pbBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pbBuf
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L104 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L104:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbBuf from: char
+ push dword ptr [esp+4] ; to: char
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _DosSetFSInfo@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__DosSetMaxFH label near
+
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosSetMaxFH@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosSetVerify label near
+
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosSetVerify@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__Dos16ErrClass label near
+
+; ebx+36
+; ebx+32 pusClass
+; ebx+28 pfsAction
+; ebx+24 pusLocus
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pusClass
+ push eax ; ptr param #2 pfsAction
+ push eax ; ptr param #3 pusLocus
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pusClass
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L105 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L105:
+
+; pfsAction
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L106 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L106:
+
+; pusLocus
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L107 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L107:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pusLocus from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pfsAction from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; pusClass from: unsigned short
+ push dword ptr [esp+16] ; to: unsigned short
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+ call _Dos16ErrClass@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__DosError label near
+
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosError@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosLoadModuleNE label near
+
+; ebx+34 pszFailName
+; ebx+32 cbFileName
+; ebx+28
+; ebx+24 phmod
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszFailName
+ push eax ; ptr param #2
+ push eax ; ptr param #3 phmod
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszFailName
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L108 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L108:
+
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L109 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L109:
+
+; phmod
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L110 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L110:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; phmod from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; from: string
+ push dword ptr [esp+8] ; to: string
+
+; cbFileName from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; pszFailName from: char
+ push dword ptr [esp+20] ; to: char
+
+ call _DosLoadModuleNE@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__DosFreeModuleNE label near
+
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosFreeModuleNE@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosQueryModuleHandleNE label near
+
+; ebx+28
+; ebx+24 phMod
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+ push eax ; ptr param #2 phMod
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L111 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L111:
+
+; phMod
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L112 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L112:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; phMod from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; from: string
+ push dword ptr [esp+8] ; to: string
+
+ call _DosQueryModuleHandleNE@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosQueryModuleNameNE label near
+
+; ebx+30
+; ebx+28 cbBuf
+; ebx+24 pchBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pchBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pchBuf
+; pointer char --> char
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L113 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L113:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pchBuf from: char
+ push dword ptr [esp+0] ; to: char
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _DosQueryModuleNameNE@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosGetResourceNE label near
+
+; ebx+32
+; ebx+30
+; ebx+28
+; ebx+24 psel
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 psel
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; psel
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L114 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L114:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; psel from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _DosGetResourceNE@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__DosGetResource2NE label near
+
+; ebx+32 hmod
+; ebx+30 idType
+; ebx+28 idName
+; ebx+24 ppData
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 ppData
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; ppData
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L115 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L115:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ppData from: void
+ push dword ptr [esp+0] ; to: void
+
+; idName from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; idType from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; hmod from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _DosGetResource2NE@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__DosFreeResourceNE label near
+
+; ebx+24 pData
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pData
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pData
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L116 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L116:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pData from: void
+ push dword ptr [esp+0] ; to: void
+
+ call _DosFreeResourceNE@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosQueryAppTypeNE label near
+
+; ebx+28
+; ebx+24 pusType
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1
+ push eax ; ptr param #2 pusType
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L117 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L117:
+
+; pusType
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L118 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L118:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pusType from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; from: string
+ push dword ptr [esp+8] ; to: string
+
+ call _DosQueryAppTypeNE@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosShutdown label near
+
+; ebx+24 pSdPacket
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pSdPacket
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pSdPacket
+; pointer struct SDPACKET --> struct SDPACKET
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L119 ; skip if null
+
+
+; structures are identical
+; structures have pointers
+
+ SelToFlat
+ mov [esp+0],eax
+L119:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pSdPacket from: struct SDPACKET
+ push dword ptr [esp+0] ; to: struct SDPACKET
+
+ call _DosShutdown@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__Dos16CreateThread label near
+
+; ebx+32 pfnFun
+; ebx+28 pTid
+; ebx+24 pbStack
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pfnFun
+ push eax ; ptr param #2 pTid
+ push eax ; ptr param #3 pbStack
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pfnFun
+; pointer void --> void
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L120 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L120:
+
+; pTid
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L121 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L121:
+
+; pbStack
+; pointer char --> char
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L122 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L122:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pbStack from: char
+ push dword ptr [esp+0] ; to: char
+
+; pTid from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; pfnFun from: void
+ push dword ptr [esp+16] ; to: void
+
+ call _Dos16CreateThread@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__Dos16ExitList label near
+
+; ebx+28 fFnCode
+; ebx+24 pfnFunction
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pfnFunction
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pfnFunction
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L123 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L123:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pfnFunction from: void
+ push dword ptr [esp+0] ; to: void
+
+; fFnCode from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _Dos16ExitList@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__DosGetInfoSeg label near
+
+; ebx+28 pselGlobal
+; ebx+24 pselLocal
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pselGlobal
+ push eax ; ptr param #2 pselLocal
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pselGlobal
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L124 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L124:
+
+; pselLocal
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L125 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L125:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pselLocal from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pselGlobal from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+ call _DosGetInfoSeg@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__Dos16Open label near
+
+; ebx+46 pszFname
+; ebx+42 phfOpen
+; ebx+38 pusAction
+; ebx+34 ulFSize
+; ebx+32 usAttr
+; ebx+30 fsOpenFlags
+; ebx+28 fsOpenMode
+; ebx+24 ulReserved
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszFname
+ push eax ; ptr param #2 phfOpen
+ push eax ; ptr param #3 pusAction
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszFname
+; pointer string --> string
+ mov eax,[ebx+46] ; base address
+ or eax,eax
+ jz L126 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L126:
+
+; phfOpen
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+42] ; base address
+ or eax,eax
+ jz L127 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L127:
+
+; pusAction
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+38] ; base address
+ or eax,eax
+ jz L128 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L128:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; fsOpenMode from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; fsOpenFlags from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; usAttr from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; ulFSize from: unsigned long
+ push dword ptr [ebx+34] ; to unsigned long
+
+; pusAction from: unsigned short
+ push dword ptr [esp+20] ; to: unsigned short
+
+; phfOpen from: unsigned short
+ push dword ptr [esp+28] ; to: unsigned short
+
+; pszFname from: string
+ push dword ptr [esp+36] ; to: string
+
+ call _Dos16Open@32 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_26
+
+;===========================================================================
+T__Dos16Open2 label near
+
+; ebx+52 pszFileName
+; ebx+48 phfOpen
+; ebx+44 pusAction
+; ebx+40 ulFSize
+; ebx+38 usAttr
+; ebx+36 usOpenFlags
+; ebx+32 flOpenMode
+; ebx+28 pEAOBuf
+; ebx+24 ulReserved
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszFileName
+ push eax ; ptr param #2 phfOpen
+ push eax ; ptr param #3 pusAction
+ push eax ; ptr param #4 pEAOBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszFileName
+; pointer string --> string
+ mov eax,[ebx+52] ; base address
+ or eax,eax
+ jz L129 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L129:
+
+; phfOpen
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+48] ; base address
+ or eax,eax
+ jz L130 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L130:
+
+; pusAction
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+44] ; base address
+ or eax,eax
+ jz L131 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L131:
+
+; pEAOBuf
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L132 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L132:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; pEAOBuf from: void
+ push dword ptr [esp+4] ; to: void
+
+; flOpenMode from: unsigned long
+ push dword ptr [ebx+32] ; to unsigned long
+
+; usOpenFlags from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+; usAttr from: unsigned short
+ movzx eax,word ptr [ebx+38]
+ push eax ; to: unsigned long
+
+; ulFSize from: unsigned long
+ push dword ptr [ebx+40] ; to unsigned long
+
+; pusAction from: unsigned short
+ push dword ptr [esp+28] ; to: unsigned short
+
+; phfOpen from: unsigned short
+ push dword ptr [esp+36] ; to: unsigned short
+
+; pszFileName from: string
+ push dword ptr [esp+44] ; to: string
+
+ call _Dos16Open2@36 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_32
+
+;===========================================================================
+T__Dos16Read label near
+
+; ebx+34 hf
+; ebx+30 pBuf
+; ebx+28 cbBuf
+; ebx+24 pcbBytesRead
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pBuf
+ push eax ; ptr param #2 pcbBytesRead
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pBuf
+; pointer void --> void
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L133 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L133:
+
+; pcbBytesRead
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L134 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L134:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbBytesRead from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pBuf from: void
+ push dword ptr [esp+12] ; to: void
+
+; hf from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+ call _Dos16Read@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__Dos16Write label near
+
+; ebx+34 hf
+; ebx+30 bBuf
+; ebx+28 cbBuf
+; ebx+24 pcbBytesWritten
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 bBuf
+ push eax ; ptr param #2 pcbBytesWritten
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; bBuf
+; pointer void --> void
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L135 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L135:
+
+; pcbBytesWritten
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L136 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L136:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbBytesWritten from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; bBuf from: void
+ push dword ptr [esp+12] ; to: void
+
+; hf from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+ call _Dos16Write@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__Dos16FindFirst label near
+
+; ebx+44 pszFSpec
+; ebx+40 phdir
+; ebx+38 usAttr
+; ebx+34 pffb
+; ebx+32 cbBuf
+; ebx+28 pcSearch
+; ebx+24 ulReserved
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszFSpec
+ push eax ; ptr param #2 phdir
+ push eax ; ptr param #3 pffb
+ push eax ; ptr param #4 pcSearch
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszFSpec
+; pointer string --> string
+ mov eax,[ebx+44] ; base address
+ or eax,eax
+ jz L137 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L137:
+
+; phdir
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L138 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L138:
+
+; pffb
+; pointer void --> void
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L139 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L139:
+
+; pcSearch
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L140 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L140:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; pcSearch from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; pffb from: void
+ push dword ptr [esp+16] ; to: void
+
+; usAttr from: unsigned short
+ movzx eax,word ptr [ebx+38]
+ push eax ; to: unsigned long
+
+; phdir from: unsigned short
+ push dword ptr [esp+28] ; to: unsigned short
+
+; pszFSpec from: string
+ push dword ptr [esp+36] ; to: string
+
+ call _Dos16FindFirst@28 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_24
+
+;===========================================================================
+T__Dos16FindFirst2 label near
+
+; ebx+46 pszFSpec
+; ebx+42 phdir
+; ebx+40 usAttr
+; ebx+36 pffb
+; ebx+34 cbBuf
+; ebx+30 pcSearch
+; ebx+28 infolevel
+; ebx+24 ulReserved
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszFSpec
+ push eax ; ptr param #2 phdir
+ push eax ; ptr param #3 pffb
+ push eax ; ptr param #4 pcSearch
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszFSpec
+; pointer string --> string
+ mov eax,[ebx+46] ; base address
+ or eax,eax
+ jz L141 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L141:
+
+; phdir
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+42] ; base address
+ or eax,eax
+ jz L142 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L142:
+
+; pffb
+; pointer void --> void
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L143 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L143:
+
+; pcSearch
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L144 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L144:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; infolevel from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pcSearch from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+; pffb from: void
+ push dword ptr [esp+20] ; to: void
+
+; usAttr from: unsigned short
+ movzx eax,word ptr [ebx+40]
+ push eax ; to: unsigned long
+
+; phdir from: unsigned short
+ push dword ptr [esp+32] ; to: unsigned short
+
+; pszFSpec from: string
+ push dword ptr [esp+40] ; to: string
+
+ call _Dos16FindFirst2@32 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_26
+
+;===========================================================================
+T__Dos16EnumAttribute label near
+
+; ebx+52 fRefType
+; ebx+48 pFileRef
+; ebx+44 iStartEntry
+; ebx+40 pEnumBuf
+; ebx+36 cbBuf
+; ebx+32 pcbActual
+; ebx+28 infoLevel
+; ebx+24 reserved
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pFileRef
+ push eax ; ptr param #2 pEnumBuf
+ push eax ; ptr param #3 pcbActual
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pFileRef
+; pointer void --> void
+ mov eax,[ebx+48] ; base address
+ or eax,eax
+ jz L145 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L145:
+
+; pEnumBuf
+; pointer void --> void
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L146 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L146:
+
+; pcbActual
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L147 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L147:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; reserved from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; infoLevel from: unsigned long
+ push dword ptr [ebx+28] ; to unsigned long
+
+; pcbActual from: unsigned long
+ push dword ptr [esp+8] ; to: unsigned long
+
+; cbBuf from: unsigned long
+ push dword ptr [ebx+36] ; to unsigned long
+
+; pEnumBuf from: void
+ push dword ptr [esp+20] ; to: void
+
+; iStartEntry from: unsigned long
+ push dword ptr [ebx+44] ; to unsigned long
+
+; pFileRef from: void
+ push dword ptr [esp+32] ; to: void
+
+; fRefType from: unsigned short
+ movzx eax,word ptr [ebx+52]
+ push eax ; to: unsigned long
+
+ call _Dos16EnumAttribute@32 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_30
+
+;===========================================================================
+T__DosQFileMode label near
+
+; ebx+32 pszFName
+; ebx+28 pusAttr
+; ebx+24 ulReserved
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszFName
+ push eax ; ptr param #2 pusAttr
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszFName
+; pointer string --> string
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L148 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L148:
+
+; pusAttr
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L149 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L149:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; pusAttr from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; pszFName from: string
+ push dword ptr [esp+12] ; to: string
+
+ call _DosQFileMode@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__DosQFileInfo label near
+
+; ebx+32 hf
+; ebx+30 usInfoLevel
+; ebx+26 pInfoBuf
+; ebx+24 cbInfoBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pInfoBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pInfoBuf
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L150 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L150:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbInfoBuf from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pInfoBuf from: void
+ push dword ptr [esp+4] ; to: void
+
+; usInfoLevel from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; hf from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _DosQFileInfo@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__DosAllocSeg label near
+
+; ebx+30 cbSize
+; ebx+26 pSel
+; ebx+24 fsAlloc
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pSel
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pSel
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L151 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L151:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; fsAlloc from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pSel from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; cbSize from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _DosAllocSeg@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosFreeSeg label near
+
+; ebx+24 sel
+
+;-------------------------------------
+; create new call frame and make the call
+
+; sel from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosFreeSeg@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosGetSeg label near
+
+; ebx+24 sel
+
+;-------------------------------------
+; create new call frame and make the call
+
+; sel from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosGetSeg@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosGiveSeg label near
+
+; ebx+30 sel
+; ebx+28 pid
+; ebx+24 pSelRecipient
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pSelRecipient
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pSelRecipient
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L152 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L152:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pSelRecipient from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pid from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; sel from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _DosGiveSeg@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosReallocSeg label near
+
+; ebx+26 cbNewSize
+; ebx+24 sel
+
+;-------------------------------------
+; create new call frame and make the call
+
+; sel from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; cbNewSize from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+ call _DosReallocSeg@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosSizeSeg label near
+
+; ebx+28 sel
+; ebx+24 pcbSize
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pcbSize
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pcbSize
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L153 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L153:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbSize from: unsigned long
+ push dword ptr [esp+0] ; to: unsigned long
+
+; sel from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _DosSizeSeg@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__DosAllocHuge label near
+
+; ebx+34 cSegs
+; ebx+32 cbPartialSeg
+; ebx+28 psel
+; ebx+26 cMaxSegs
+; ebx+24 fsAlloc
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 psel
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; psel
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L154 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L154:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; fsAlloc from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; cMaxSegs from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; psel from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; cbPartialSeg from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; cSegs from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+ call _DosAllocHuge@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__DosReallocHuge label near
+
+; ebx+28 cSegs
+; ebx+26 cbPartialSeg
+; ebx+24 sel
+
+;-------------------------------------
+; create new call frame and make the call
+
+; sel from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; cbPartialSeg from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; cSegs from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _DosReallocHuge@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__DosGetHugeShift label near
+
+; ebx+24 pusShiftCount
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pusShiftCount
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pusShiftCount
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L155 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L155:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pusShiftCount from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+ call _DosGetHugeShift@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosAllocShrSeg label near
+
+; ebx+32 cbSeg
+; ebx+28 pszSegName
+; ebx+24 psel
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszSegName
+ push eax ; ptr param #2 psel
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszSegName
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L156 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L156:
+
+; psel
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L157 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L157:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; psel from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pszSegName from: string
+ push dword ptr [esp+8] ; to: string
+
+; cbSeg from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _DosAllocShrSeg@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__DosLockSeg label near
+
+; ebx+24 sel
+
+;-------------------------------------
+; create new call frame and make the call
+
+; sel from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosLockSeg@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosUnlockSeg label near
+
+; ebx+24 sel
+
+;-------------------------------------
+; create new call frame and make the call
+
+; sel from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosUnlockSeg@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosGetShrSeg label near
+
+; ebx+28 pszSegName
+; ebx+24 psel
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszSegName
+ push eax ; ptr param #2 psel
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszSegName
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L158 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L158:
+
+; psel
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L159 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L159:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; psel from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pszSegName from: string
+ push dword ptr [esp+8] ; to: string
+
+ call _DosGetShrSeg@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosMemAvail label near
+
+; ebx+24 pcbFree
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pcbFree
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pcbFree
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L160 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L160:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbFree from: unsigned long
+ push dword ptr [esp+0] ; to: unsigned long
+
+ call _DosMemAvail@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosCreateCSAlias label near
+
+; ebx+28 selDS
+; ebx+24 pselCS
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pselCS
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pselCS
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L161 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L161:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pselCS from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; selDS from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _DosCreateCSAlias@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__DosSemClear label near
+
+; ebx+24 hsem
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 hsem
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; hsem
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L162 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L162:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hsem from: void
+ push dword ptr [esp+0] ; to: void
+
+ call _DosSemClear@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosSemSet label near
+
+; ebx+24 hsem
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 hsem
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; hsem
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L163 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L163:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hsem from: void
+ push dword ptr [esp+0] ; to: void
+
+ call _DosSemSet@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosSemWait label near
+
+; ebx+28 hsem
+; ebx+24 lTimeOut
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 hsem
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; hsem
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L164 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L164:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; lTimeOut from: long
+ push dword ptr [ebx+24] ; to long
+
+; hsem from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _DosSemWait@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosSemSetWait label near
+
+; ebx+28 hsem
+; ebx+24 lTimeOut
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 hsem
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; hsem
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L165 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L165:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; lTimeOut from: long
+ push dword ptr [ebx+24] ; to long
+
+; hsem from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _DosSemSetWait@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosSemRequest label near
+
+; ebx+28 hsem
+; ebx+24 lTimeOut
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 hsem
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; hsem
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L166 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L166:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; lTimeOut from: long
+ push dword ptr [ebx+24] ; to long
+
+; hsem from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _DosSemRequest@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosCreateSem label near
+
+; ebx+32 fExclusive
+; ebx+28 phsem
+; ebx+24 pszSemName
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 phsem
+ push eax ; ptr param #2 pszSemName
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; phsem
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L167 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L167:
+
+; pszSemName
+; pointer string --> string
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L168 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L168:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pszSemName from: string
+ push dword ptr [esp+0] ; to: string
+
+; phsem from: void
+ push dword ptr [esp+8] ; to: void
+
+; fExclusive from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _DosCreateSem@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__DosOpenSem label near
+
+; ebx+28 phsem
+; ebx+24 pszSemName
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 phsem
+ push eax ; ptr param #2 pszSemName
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; phsem
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L169 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L169:
+
+; pszSemName
+; pointer string --> string
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L170 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L170:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pszSemName from: string
+ push dword ptr [esp+0] ; to: string
+
+; phsem from: void
+ push dword ptr [esp+8] ; to: void
+
+ call _DosOpenSem@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosCloseSem label near
+
+; ebx+24 hsem
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 hsem
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; hsem
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L171 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L171:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hsem from: void
+ push dword ptr [esp+0] ; to: void
+
+ call _DosCloseSem@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosMuxSemWait label near
+
+; ebx+32 pisemCleared
+; ebx+28 pmsxl
+; ebx+24 lTimeOut
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pisemCleared
+ push eax ; ptr param #2 pmsxl
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pisemCleared
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L172 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L172:
+
+; pmsxl
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L173 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L173:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; lTimeOut from: long
+ push dword ptr [ebx+24] ; to long
+
+; pmsxl from: void
+ push dword ptr [esp+4] ; to: void
+
+; pisemCleared from: unsigned short
+ push dword ptr [esp+12] ; to: unsigned short
+
+ call _DosMuxSemWait@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__DosFSRamSemRequest label near
+
+; ebx+28 pdosfsrs
+; ebx+24 lTimeOut
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pdosfsrs
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pdosfsrs
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L174 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L174:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; lTimeOut from: long
+ push dword ptr [ebx+24] ; to long
+
+; pdosfsrs from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _DosFSRamSemRequest@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosFSRamSemClear label near
+
+; ebx+24 pdosfsrs
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pdosfsrs
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pdosfsrs
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L175 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L175:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pdosfsrs from: void
+ push dword ptr [esp+0] ; to: void
+
+ call _DosFSRamSemClear@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosAsyncTimer label near
+
+; ebx+32 ulTime
+; ebx+28 hsem
+; ebx+24 phtimer
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 hsem
+ push eax ; ptr param #2 phtimer
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; hsem
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L176 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L176:
+
+; phtimer
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L177 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L177:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; phtimer from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; hsem from: void
+ push dword ptr [esp+8] ; to: void
+
+; ulTime from: unsigned long
+ push dword ptr [ebx+32] ; to unsigned long
+
+ call _DosAsyncTimer@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__DosStartTimer label near
+
+; ebx+32 ulTime
+; ebx+28 hsem
+; ebx+24 phtimer
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 hsem
+ push eax ; ptr param #2 phtimer
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; hsem
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L178 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L178:
+
+; phtimer
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L179 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L179:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; phtimer from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; hsem from: void
+ push dword ptr [esp+8] ; to: void
+
+; ulTime from: unsigned long
+ push dword ptr [ebx+32] ; to unsigned long
+
+ call _DosStartTimer@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__DosStopTimer label near
+
+; ebx+24 htimer
+
+;-------------------------------------
+; create new call frame and make the call
+
+; htimer from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosStopTimer@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosGetProcAddrNE label near
+
+; ebx+32 hmod
+; ebx+28 pszProcName
+; ebx+24 ppfnProcAddr
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszProcName
+ push eax ; ptr param #2 ppfnProcAddr
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszProcName
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L180 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L180:
+
+; ppfnProcAddr
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L181 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L181:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ppfnProcAddr from: void
+ push dword ptr [esp+0] ; to: void
+
+; pszProcName from: string
+ push dword ptr [esp+8] ; to: string
+
+; hmod from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _DosGetProcAddrNE@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__DosQueryProcType label near
+
+; ebx+36 hmod
+; ebx+32 ordinal
+; ebx+28 pszName
+; ebx+24 pulproctype
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszName
+ push eax ; ptr param #2 pulproctype
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszName
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L182 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L182:
+
+; pulproctype
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L183 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L183:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pulproctype from: unsigned long
+ push dword ptr [esp+0] ; to: unsigned long
+
+; pszName from: string
+ push dword ptr [esp+8] ; to: string
+
+; ordinal from: unsigned long
+ push dword ptr [ebx+32] ; to unsigned long
+
+; hmod from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+ call _DosQueryProcType@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__DosQueryResourceSize label near
+
+; ebx+36 hmod
+; ebx+32 idt
+; ebx+28 idn
+; ebx+24 pulsize
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pulsize
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pulsize
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L184 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L184:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pulsize from: unsigned long
+ push dword ptr [esp+0] ; to: unsigned long
+
+; idn from: unsigned long
+ push dword ptr [ebx+28] ; to unsigned long
+
+; idt from: unsigned long
+ push dword ptr [ebx+32] ; to unsigned long
+
+; hmod from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+ call _DosQueryResourceSize@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__DosSetSigHandler label near
+
+; ebx+36 pfnSigHandler
+; ebx+32 ppfnPrev
+; ebx+28 pfAction
+; ebx+26 fAction
+; ebx+24 usSigNum
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pfnSigHandler
+ push eax ; ptr param #2 ppfnPrev
+ push eax ; ptr param #3 pfAction
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pfnSigHandler
+; pointer void --> void
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L185 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L185:
+
+; ppfnPrev
+; pointer void --> void
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L186 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L186:
+
+; pfAction
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L187 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L187:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; usSigNum from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; fAction from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; pfAction from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; ppfnPrev from: void
+ push dword ptr [esp+16] ; to: void
+
+; pfnSigHandler from: void
+ push dword ptr [esp+24] ; to: void
+
+ call _DosSetSigHandler@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T_DosFlagProcess16 label near
+
+; ebx+30 pid
+; ebx+28 fScope
+; ebx+26 usFlagNum
+; ebx+24 usFlagArg
+
+;-------------------------------------
+; create new call frame and make the call
+
+; usFlagArg from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; usFlagNum from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; fScope from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pid from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call DosFlagProcess16@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T_DosHoldSignal16 label near
+
+; ebx+24 fDisable
+
+;-------------------------------------
+; create new call frame and make the call
+
+; fDisable from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call DosHoldSignal16@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T_DosSendSignal16 label near
+
+; ebx+26 idProcess
+; ebx+24 usSigNumber
+
+;-------------------------------------
+; create new call frame and make the call
+
+; usSigNumber from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; idProcess from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+ call DosSendSignal16@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosSetVec label near
+
+; ebx+32 usVecNum
+; ebx+28 pfnFun
+; ebx+24 ppfnPrev
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pfnFun
+ push eax ; ptr param #2 ppfnPrev
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pfnFun
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L188 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L188:
+
+; ppfnPrev
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L189 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L189:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ppfnPrev from: void
+ push dword ptr [esp+0] ; to: void
+
+; pfnFun from: void
+ push dword ptr [esp+8] ; to: void
+
+; usVecNum from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _DosSetVec@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__DosGetEnv label near
+
+; ebx+28 pselEnv
+; ebx+24 pOffsetCmd
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pselEnv
+ push eax ; ptr param #2 pOffsetCmd
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pselEnv
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L190 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L190:
+
+; pOffsetCmd
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L191 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L191:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pOffsetCmd from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pselEnv from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+ call _DosGetEnv@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosGetVersion label near
+
+; ebx+24 pVer
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pVer
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pVer
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L192 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L192:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pVer from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+ call _DosGetVersion@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosGetMachineMode label near
+
+; ebx+24 pMachMode
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pMachMode
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pMachMode
+; pointer char --> char
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L193 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L193:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pMachMode from: char
+ push dword ptr [esp+0] ; to: char
+
+ call _DosGetMachineMode@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__Dos16FindNext label near
+
+; ebx+34 hdir
+; ebx+30 pffb
+; ebx+28 cbBuf
+; ebx+24 pcSearch
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pffb
+ push eax ; ptr param #2 pcSearch
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pffb
+; pointer void --> void
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L194 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L194:
+
+; pcSearch
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L195 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L195:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcSearch from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pffb from: void
+ push dword ptr [esp+12] ; to: void
+
+; hdir from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+ call _Dos16FindNext@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__DosGetPID label near
+
+; ebx+24 ppidInfo
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 ppidInfo
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; ppidInfo
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L196 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L196:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ppidInfo from: void
+ push dword ptr [esp+0] ; to: void
+
+ call _DosGetPID@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosGetPPID label near
+
+; ebx+28 pidChild
+; ebx+24 ppidParent
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 ppidParent
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; ppidParent
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L197 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L197:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ppidParent from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pidChild from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _DosGetPPID@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__Dos16MkDir label near
+
+; ebx+28 pszDirName
+; ebx+24 ulReserved
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszDirName
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszDirName
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L198 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L198:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; pszDirName from: string
+ push dword ptr [esp+4] ; to: string
+
+ call _Dos16MkDir@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__Dos16MkDir2 label near
+
+; ebx+32 pszDir
+; ebx+28 peaop
+; ebx+24 ulReserved
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszDir
+ push eax ; ptr param #2 peaop
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszDir
+; pointer string --> string
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L199 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L199:
+
+; peaop
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L200 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L200:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; peaop from: void
+ push dword ptr [esp+4] ; to: void
+
+; pszDir from: string
+ push dword ptr [esp+12] ; to: string
+
+ call _Dos16MkDir2@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__DosSetFileMode label near
+
+; ebx+30 pszFName
+; ebx+28 usAttr
+; ebx+24 ulReserved
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszFName
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszFName
+; pointer string --> string
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L201 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L201:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; usAttr from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pszFName from: string
+ push dword ptr [esp+8] ; to: string
+
+ call _DosSetFileMode@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__Dos16SetFileInfo label near
+
+; ebx+32 hf
+; ebx+30 usInfoLevel
+; ebx+26 pInfoBuf
+; ebx+24 cbInfoBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pInfoBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pInfoBuf
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L202 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L202:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbInfoBuf from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pInfoBuf from: void
+ push dword ptr [esp+4] ; to: void
+
+; usInfoLevel from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; hf from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _Dos16SetFileInfo@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__DosTrueGetMessage label near
+
+; ebx+46 ppchVTable
+; ebx+44 usVCount
+; ebx+40 pchBuf
+; ebx+38 cbBuf
+; ebx+36 usMsgNum
+; ebx+32 pszFileName
+; ebx+28 pcbMsg
+; ebx+24 pMsgSeg
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 ppchVTable
+ push eax ; ptr param #2 pchBuf
+ push eax ; ptr param #3 pszFileName
+ push eax ; ptr param #4 pcbMsg
+ push eax ; ptr param #5 pMsgSeg
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; ppchVTable
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+46] ; base address
+ or eax,eax
+ jz L203 ; skip if null
+
+ SelToFlat
+ mov [esp+16],eax
+L203:
+
+; pchBuf
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L204 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L204:
+
+; pszFileName
+; pointer string --> string
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L205 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L205:
+
+; pcbMsg
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L206 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L206:
+
+; pMsgSeg
+; pointer char --> char
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L207 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L207:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pMsgSeg from: char
+ push dword ptr [esp+0] ; to: char
+
+; pcbMsg from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; pszFileName from: string
+ push dword ptr [esp+16] ; to: string
+
+; usMsgNum from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+38]
+ push eax ; to: unsigned long
+
+; pchBuf from: char
+ push dword ptr [esp+32] ; to: char
+
+; usVCount from: unsigned short
+ movzx eax,word ptr [ebx+44]
+ push eax ; to: unsigned long
+
+; ppchVTable from: unsigned long
+ push dword ptr [esp+44] ; to: unsigned long
+
+ call _DosTrueGetMessage@32 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_26
+
+;===========================================================================
+T__DosScanEnvNE label near
+
+; ebx+28 pszValName
+; ebx+24 ppszResult
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszValName
+ push eax ; ptr param #2 ppszResult
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszValName
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L208 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L208:
+
+; ppszResult
+; pointer char --> char
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L209 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L209:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ppszResult from: char
+ push dword ptr [esp+0] ; to: char
+
+; pszValName from: string
+ push dword ptr [esp+8] ; to: string
+
+ call _DosScanEnvNE@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosPTrace label near
+
+; ebx+24 pvTraceBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pvTraceBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pvTraceBuf
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L210 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L210:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pvTraceBuf from: void
+ push dword ptr [esp+0] ; to: void
+
+ call _DosPTrace@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosInsMessage label near
+
+; ebx+42 ppchVTable
+; ebx+40 usVCount
+; ebx+36 pszMsg
+; ebx+34 cbMsg
+; ebx+30 pchBuf
+; ebx+28 cbBuf
+; ebx+24 pcbMsg
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 ppchVTable
+ push eax ; ptr param #2 pszMsg
+ push eax ; ptr param #3 pchBuf
+ push eax ; ptr param #4 pcbMsg
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; ppchVTable
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+42] ; base address
+ or eax,eax
+ jz L211 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L211:
+
+; pszMsg
+; pointer string --> string
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L212 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L212:
+
+; pchBuf
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L213 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L213:
+
+; pcbMsg
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L214 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L214:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbMsg from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pchBuf from: char
+ push dword ptr [esp+12] ; to: char
+
+; cbMsg from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+; pszMsg from: string
+ push dword ptr [esp+24] ; to: string
+
+; usVCount from: unsigned short
+ movzx eax,word ptr [ebx+40]
+ push eax ; to: unsigned long
+
+; ppchVTable from: unsigned long
+ push dword ptr [esp+36] ; to: unsigned long
+
+ call _DosInsMessage@28 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_22
+
+;===========================================================================
+T__DosPutMessage label near
+
+; ebx+30 hf
+; ebx+28 cbMsg
+; ebx+24 pchMsg
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pchMsg
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pchMsg
+; pointer char --> char
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L215 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L215:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pchMsg from: char
+ push dword ptr [esp+0] ; to: char
+
+; cbMsg from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; hf from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _DosPutMessage@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__Dos16SubSet label near
+
+; ebx+28
+; ebx+26
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _Dos16SubSet@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__Dos16SubAlloc label near
+
+; ebx+30
+; ebx+26 pusOffset
+; ebx+24
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pusOffset
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pusOffset
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L216 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L216:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pusOffset from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _Dos16SubAlloc@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__Dos16SubFree label near
+
+; ebx+28
+; ebx+26
+; ebx+24
+
+;-------------------------------------
+; create new call frame and make the call
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _Dos16SubFree@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__Dos16StartSession label near
+
+; ebx+32 pstdata
+; ebx+28 pidSession
+; ebx+24 ppid
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pstdata
+ push eax ; ptr param #2 pidSession
+ push eax ; ptr param #3 ppid
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pstdata
+; pointer void --> void
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L217 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L217:
+
+; pidSession
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L218 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L218:
+
+; ppid
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L219 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L219:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ppid from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pidSession from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; pstdata from: void
+ push dword ptr [esp+16] ; to: void
+
+ call _Dos16StartSession@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__DosStopSession label near
+
+; ebx+30 fScope
+; ebx+28 idSession
+; ebx+24 ulReserved
+
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; idSession from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; fScope from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _DosStopSession@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosSetSession label near
+
+; ebx+28 idSession
+; ebx+24 pstsdata
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pstsdata
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pstsdata
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L220 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L220:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pstsdata from: void
+ push dword ptr [esp+0] ; to: void
+
+; idSession from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _DosSetSession@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__DosSelectSession label near
+
+; ebx+28 idSession
+; ebx+24 ulReserved
+
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; idSession from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _DosSelectSession@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__DosSMSetTitle label near
+
+; ebx+24 pszTitle
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszTitle
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszTitle
+; pointer string --> string
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L221 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L221:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pszTitle from: string
+ push dword ptr [esp+0] ; to: string
+
+ call _DosSMSetTitle@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__DosSMPMPresent label near
+
+; ebx+24 Flag
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 Flag
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; Flag
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L222 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L222:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; Flag from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+ call _DosSMPMPresent@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__WinSetTitleAndIcon label near
+
+; ebx+28 szTitle
+; ebx+24 szIconFilePath
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 szTitle
+ push eax ; ptr param #2 szIconFilePath
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; szTitle
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L223 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L223:
+
+; szIconFilePath
+; pointer string --> string
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L224 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L224:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; szIconFilePath from: string
+ push dword ptr [esp+0] ; to: string
+
+; szTitle from: string
+ push dword ptr [esp+8] ; to: string
+
+ call _WinSetTitleAndIcon@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosGetPriority label near
+
+; ebx+30 usScope
+; ebx+26 pusPriority
+; ebx+24 pid
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pusPriority
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pusPriority
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L225 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L225:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pid from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pusPriority from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; usScope from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _DosGetPriority@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosQSysInfo label near
+
+; ebx+30 index
+; ebx+26 pBuf
+; ebx+24 cbBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pBuf
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L226 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L226:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pBuf from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; index from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _DosQSysInfo@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosDevIOCtl2 label near
+
+; ebx+38 pvData
+; ebx+36 cbData
+; ebx+32 pvParms
+; ebx+30 cbParms
+; ebx+28 Function
+; ebx+26 Category
+; ebx+24 hDev
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pvData
+ push eax ; ptr param #2 pvParms
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pvData
+; pointer void --> void
+ mov eax,[ebx+38] ; base address
+ or eax,eax
+ jz L227 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L227:
+
+; pvParms
+; pointer void --> void
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L228 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L228:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hDev from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; Category from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; Function from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; cbParms from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; pvParms from: void
+ push dword ptr [esp+16] ; to: void
+
+; cbData from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+; pvData from: void
+ push dword ptr [esp+28] ; to: void
+
+ call _DosDevIOCtl2@28 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_18
+
+;===========================================================================
+T__DosICanonicalize label near
+
+; ebx+34 Source
+; ebx+30 Dest
+; ebx+28 BackupOffset
+; ebx+26 DestEnd
+; ebx+24 Flags
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 Source
+ push eax ; ptr param #2 Dest
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; Source
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L229 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L229:
+
+; Dest
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L230 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L230:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; Flags from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; DestEnd from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; BackupOffset from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; Dest from: char
+ push dword ptr [esp+12] ; to: char
+
+; Source from: char
+ push dword ptr [esp+20] ; to: char
+
+ call _DosICanonicalize@20 ; call 32-bit version
+
+; return code void --> void
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__DosReadAsync label near
+
+; ebx+42 hf
+; ebx+38 hsemRam
+; ebx+34 pusErrCode
+; ebx+30 pvBuf
+; ebx+28 cbBuf
+; ebx+24 pcbBytesRead
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 hsemRam
+ push eax ; ptr param #2 pusErrCode
+ push eax ; ptr param #3 pvBuf
+ push eax ; ptr param #4 pcbBytesRead
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; hsemRam
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+38] ; base address
+ or eax,eax
+ jz L231 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L231:
+
+; pusErrCode
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L232 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L232:
+
+; pvBuf
+; pointer void --> void
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L233 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L233:
+
+; pcbBytesRead
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L234 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L234:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbBytesRead from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pvBuf from: void
+ push dword ptr [esp+12] ; to: void
+
+; pusErrCode from: unsigned short
+ push dword ptr [esp+20] ; to: unsigned short
+
+; hsemRam from: unsigned long
+ push dword ptr [esp+28] ; to: unsigned long
+
+; hf from: unsigned short
+ movzx eax,word ptr [ebx+42]
+ push eax ; to: unsigned long
+
+ call _DosReadAsync@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__DosWriteAsync label near
+
+; ebx+42 hf
+; ebx+38 hsemRam
+; ebx+34 pusErrCode
+; ebx+30 pvBuf
+; ebx+28 cbBuf
+; ebx+24 pcbBytesRead
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 hsemRam
+ push eax ; ptr param #2 pusErrCode
+ push eax ; ptr param #3 pvBuf
+ push eax ; ptr param #4 pcbBytesRead
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; hsemRam
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+38] ; base address
+ or eax,eax
+ jz L235 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L235:
+
+; pusErrCode
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L236 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L236:
+
+; pvBuf
+; pointer void --> void
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L237 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L237:
+
+; pcbBytesRead
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L238 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L238:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbBytesRead from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuf from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pvBuf from: void
+ push dword ptr [esp+12] ; to: void
+
+; pusErrCode from: unsigned short
+ push dword ptr [esp+20] ; to: unsigned short
+
+; hsemRam from: unsigned long
+ push dword ptr [esp+28] ; to: unsigned long
+
+; hf from: unsigned short
+ movzx eax,word ptr [ebx+42]
+ push eax ; to: unsigned long
+
+ call _DosWriteAsync@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__DosFindNotifyClose label near
+
+
+;-------------------------------------
+; create new call frame and make the call
+
+ call _DosFindNotifyClose@0 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_0
+
+;===========================================================================
+T__DosFindNotifyFirst label near
+
+
+;-------------------------------------
+; create new call frame and make the call
+
+ call _DosFindNotifyFirst@0 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_0
+
+;===========================================================================
+T__DosFindNotifyNext label near
+
+
+;-------------------------------------
+; create new call frame and make the call
+
+ call _DosFindNotifyNext@0 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_0
+
+;===========================================================================
+T__DosFileLocks label near
+
+; ebx+32 hf
+; ebx+28 pfUnLock
+; ebx+24 pfLock
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pfUnLock
+ push eax ; ptr param #2 pfLock
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pfUnLock
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L239 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L239:
+
+; pfLock
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L240 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L240:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pfLock from: void
+ push dword ptr [esp+0] ; to: void
+
+; pfUnLock from: void
+ push dword ptr [esp+8] ; to: void
+
+; hf from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+ call _DosFileLocks@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__Dos16QPathInfo label near
+
+; ebx+36 pszPath
+; ebx+34 usInfoLevel
+; ebx+30 pInfoBuf
+; ebx+28 cbInfoBuf
+; ebx+24 ulReserved
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszPath
+ push eax ; ptr param #2 pInfoBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszPath
+; pointer string --> string
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L241 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L241:
+
+; pInfoBuf
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L242 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L242:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; cbInfoBuf from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pInfoBuf from: char
+ push dword ptr [esp+8] ; to: char
+
+; usInfoLevel from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+; pszPath from: string
+ push dword ptr [esp+20] ; to: string
+
+ call _Dos16QPathInfo@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T__Dos16SetPathInfo label near
+
+; ebx+38 pszPath
+; ebx+36 usInfoLevel
+; ebx+32 pInfoBuf
+; ebx+30 cbInfoBuf
+; ebx+28 fsOptions
+; ebx+24 ulReserved
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszPath
+ push eax ; ptr param #2 pInfoBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszPath
+; pointer string --> string
+ mov eax,[ebx+38] ; base address
+ or eax,eax
+ jz L243 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L243:
+
+; pInfoBuf
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L244 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L244:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; ulReserved from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; fsOptions from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; cbInfoBuf from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; pInfoBuf from: char
+ push dword ptr [esp+12] ; to: char
+
+; usInfoLevel from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+; pszPath from: string
+ push dword ptr [esp+24] ; to: string
+
+ call _Dos16SetPathInfo@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_18
+
+;===========================================================================
+T__DosPortAccess label near
+
+; ebx+30 usReserved
+; ebx+28 fRelease
+; ebx+26 usFirstPort
+; ebx+24 usLastPort
+
+;-------------------------------------
+; create new call frame and make the call
+
+; usLastPort from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; usFirstPort from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; fRelease from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; usReserved from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _DosPortAccess@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosCLIAccess label near
+
+
+;-------------------------------------
+; create new call frame and make the call
+
+ call _DosCLIAccess@0 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_0
+
+;===========================================================================
+T__WinQueryProfileString label near
+
+; ebx+42 hab
+; ebx+38 pszAppName
+; ebx+34 pszKeyName
+; ebx+30 pszError
+; ebx+26 pszBuf
+; ebx+24 cchBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszAppName
+ push eax ; ptr param #2 pszKeyName
+ push eax ; ptr param #3 pszError
+ push eax ; ptr param #4 pszBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszAppName
+; pointer string --> string
+ mov eax,[ebx+38] ; base address
+ or eax,eax
+ jz L245 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L245:
+
+; pszKeyName
+; pointer string --> string
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L246 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L246:
+
+; pszError
+; pointer string --> string
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L247 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L247:
+
+; pszBuf
+; pointer string --> string
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L248 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L248:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cchBuf from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pszBuf from: string
+ push dword ptr [esp+4] ; to: string
+
+; pszError from: string
+ push dword ptr [esp+12] ; to: string
+
+; pszKeyName from: string
+ push dword ptr [esp+20] ; to: string
+
+; pszAppName from: string
+ push dword ptr [esp+28] ; to: string
+
+ call _WinQueryProfileString@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_22
+
+;===========================================================================
+T__WinQueryProfileSize label near
+
+; ebx+36 hab
+; ebx+32 pszAppName
+; ebx+28 pszKeyName
+; ebx+24 pcb
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszAppName
+ push eax ; ptr param #2 pszKeyName
+ push eax ; ptr param #3 pcb
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszAppName
+; pointer string --> string
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L249 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L249:
+
+; pszKeyName
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L250 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L250:
+
+; pcb
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L251 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L251:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcb from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pszKeyName from: string
+ push dword ptr [esp+8] ; to: string
+
+; pszAppName from: string
+ push dword ptr [esp+16] ; to: string
+
+ call _WinQueryProfileSize@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T__WinQueryProfileData label near
+
+; ebx+40 hab
+; ebx+36 pszAppName
+; ebx+32 pszKeyName
+; ebx+28 pvBuf
+; ebx+24 pcbBuf
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszAppName
+ push eax ; ptr param #2 pszKeyName
+ push eax ; ptr param #3 pvBuf
+ push eax ; ptr param #4 pcbBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszAppName
+; pointer string --> string
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L252 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L252:
+
+; pszKeyName
+; pointer string --> string
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L253 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L253:
+
+; pvBuf
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L254 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L254:
+
+; pcbBuf
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L255 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L255:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbBuf from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pvBuf from: void
+ push dword ptr [esp+8] ; to: void
+
+; pszKeyName from: string
+ push dword ptr [esp+16] ; to: string
+
+; pszAppName from: string
+ push dword ptr [esp+24] ; to: string
+
+ call _WinQueryProfileData@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__WinQueryProfileInt label near
+
+; ebx+34 hab
+; ebx+30 pszAppName
+; ebx+26 pszKeyName
+; ebx+24 sError
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszAppName
+ push eax ; ptr param #2 pszKeyName
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszAppName
+; pointer string --> string
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L256 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L256:
+
+; pszKeyName
+; pointer string --> string
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L257 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L257:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; sError from: short
+ movsx eax,word ptr [ebx+24]
+ push eax ; to: long
+
+; pszKeyName from: string
+ push dword ptr [esp+4] ; to: string
+
+; pszAppName from: string
+ push dword ptr [esp+12] ; to: string
+
+ call _WinQueryProfileInt@12 ; call 32-bit version
+
+; return code long --> short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__WinWriteProfileData label near
+
+; ebx+38 hab
+; ebx+34 pszAppName
+; ebx+30 pszKeyName
+; ebx+26 pcbBinaryData
+; ebx+24 cchData
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszAppName
+ push eax ; ptr param #2 pszKeyName
+ push eax ; ptr param #3 pcbBinaryData
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszAppName
+; pointer string --> string
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L258 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L258:
+
+; pszKeyName
+; pointer string --> string
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L259 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L259:
+
+; pcbBinaryData
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L260 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L260:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cchData from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pcbBinaryData from: void
+ push dword ptr [esp+4] ; to: void
+
+; pszKeyName from: string
+ push dword ptr [esp+12] ; to: string
+
+; pszAppName from: string
+ push dword ptr [esp+20] ; to: string
+
+ call _WinWriteProfileData@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_18
+
+;===========================================================================
+T__WinWriteProfileString label near
+
+; ebx+36 hab
+; ebx+32 pszAppName
+; ebx+28 pszKeyName
+; ebx+24 pszString
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszAppName
+ push eax ; ptr param #2 pszKeyName
+ push eax ; ptr param #3 pszString
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszAppName
+; pointer string --> string
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L261 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L261:
+
+; pszKeyName
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L262 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L262:
+
+; pszString
+; pointer string --> string
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L263 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L263:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pszString from: string
+ push dword ptr [esp+0] ; to: string
+
+; pszKeyName from: string
+ push dword ptr [esp+8] ; to: string
+
+; pszAppName from: string
+ push dword ptr [esp+16] ; to: string
+
+ call _WinWriteProfileString@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T__WinCreateHeap label near
+
+; ebx+34 selHeapBase
+; ebx+32 cbHeap
+; ebx+30 cbGrow
+; ebx+28 cbMinDed
+; ebx+26 cbMaxDeb
+; ebx+24 fsOptions
+
+;-------------------------------------
+; create new call frame and make the call
+
+; fsOptions from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; cbMaxDeb from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; cbMinDed from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; cbGrow from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; cbHeap from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; selHeapBase from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+ call _WinCreateHeap@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__WinDestroyHeap label near
+
+; ebx+24 hHeap
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hHeap from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _WinDestroyHeap@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__WinAllocMem label near
+
+; ebx+26 hHeap
+; ebx+24 cb
+
+;-------------------------------------
+; create new call frame and make the call
+
+; cb from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; hHeap from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+ call _WinAllocMem@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__WinFreeMem label near
+
+; ebx+28 hHeap
+; ebx+26 npMem
+; ebx+24 cbMem
+
+;-------------------------------------
+; create new call frame and make the call
+
+; cbMem from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; npMem from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; hHeap from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _WinFreeMem@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__WinGetLastError label near
+
+; ebx+24 hab
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hab from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _WinGetLastError@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__VioScrollUp label near
+
+; ebx+38 ulTopRow
+; ebx+36 ulLeftCol
+; ebx+34 ulBotRow
+; ebx+32 ulRightCol
+; ebx+30 cbLines
+; ebx+26 pbCell
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pbCell
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pbCell
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L264 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L264:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbCell from: char
+ push dword ptr [esp+4] ; to: char
+
+; cbLines from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; ulRightCol from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; ulBotRow from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+; ulLeftCol from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+; ulTopRow from: unsigned short
+ movzx eax,word ptr [ebx+38]
+ push eax ; to: unsigned long
+
+ call _VioScrollUp@28 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T__VioGetCurPos label near
+
+; ebx+30 pusRow
+; ebx+26 pusColumn
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pusRow
+ push eax ; ptr param #2 pusColumn
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pusRow
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L265 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L265:
+
+; pusColumn
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L266 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L266:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pusColumn from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; pusRow from: unsigned short
+ push dword ptr [esp+12] ; to: unsigned short
+
+ call _VioGetCurPos@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__VioSetCurPos label near
+
+; ebx+28 usRow
+; ebx+26 usColumn
+; ebx+24 hVio
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; usColumn from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; usRow from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _VioSetCurPos@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioWrtTTY label near
+
+; ebx+28 pchString
+; ebx+26 cbString
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pchString
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pchString
+; pointer char --> char
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L267 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L267:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; cbString from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; pchString from: char
+ push dword ptr [esp+8] ; to: char
+
+ call _VioWrtTTY@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__VioGetMode label near
+
+; ebx+26 pviomi
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pviomi
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pviomi
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L268 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L268:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pviomi from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _VioGetMode@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioReadCellStr label near
+
+; ebx+34 pchCellString
+; ebx+30 pcb
+; ebx+28 usRow
+; ebx+26 usColumn
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pchCellString
+ push eax ; ptr param #2 pcb
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pchCellString
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L269 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L269:
+
+; pcb
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L270 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L270:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; usColumn from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; usRow from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pcb from: unsigned short
+ push dword ptr [esp+12] ; to: unsigned short
+
+; pchCellString from: char
+ push dword ptr [esp+20] ; to: char
+
+ call _VioReadCellStr@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__VioScrollLf label near
+
+; ebx+38 ulTopRow
+; ebx+36 ulLeftCol
+; ebx+34 ulBotRow
+; ebx+32 ulRightCol
+; ebx+30 cbLines
+; ebx+26 pbCell
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pbCell
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pbCell
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L271 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L271:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbCell from: char
+ push dword ptr [esp+4] ; to: char
+
+; cbLines from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; ulRightCol from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; ulBotRow from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+; ulLeftCol from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+; ulTopRow from: unsigned short
+ movzx eax,word ptr [ebx+38]
+ push eax ; to: unsigned long
+
+ call _VioScrollLf@28 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T__VioReadCharStr label near
+
+; ebx+34 pchCellString
+; ebx+30 pcb
+; ebx+28 usRow
+; ebx+26 usColumn
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pchCellString
+ push eax ; ptr param #2 pcb
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pchCellString
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L272 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L272:
+
+; pcb
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L273 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L273:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; usColumn from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; usRow from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pcb from: unsigned short
+ push dword ptr [esp+12] ; to: unsigned short
+
+; pchCellString from: char
+ push dword ptr [esp+20] ; to: char
+
+ call _VioReadCharStr@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__VioWrtCharStrAtt label near
+
+; ebx+36 pchString
+; ebx+34 cbString
+; ebx+32 usRow
+; ebx+30 usColumn
+; ebx+26 pbAttr
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pchString
+ push eax ; ptr param #2 pbAttr
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pchString
+; pointer char --> char
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L274 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L274:
+
+; pbAttr
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L275 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L275:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbAttr from: char
+ push dword ptr [esp+4] ; to: char
+
+; usColumn from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; usRow from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; cbString from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+; pchString from: char
+ push dword ptr [esp+24] ; to: char
+
+ call _VioWrtCharStrAtt@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T__VioWrtCellStr label near
+
+; ebx+32 CellStr
+; ebx+30 Length
+; ebx+28 Row
+; ebx+26 Col
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 CellStr
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; CellStr
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L276 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L276:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; Col from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; Row from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; Length from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; CellStr from: char
+ push dword ptr [esp+16] ; to: char
+
+ call _VioWrtCellStr@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__VioWrtCharStr label near
+
+; ebx+32 CharStr
+; ebx+30 Length
+; ebx+28 Row
+; ebx+26 Col
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 CharStr
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; CharStr
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L277 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L277:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; Col from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; Row from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; Length from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; CharStr from: char
+ push dword ptr [esp+16] ; to: char
+
+ call _VioWrtCharStr@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__VioWrtNCell label near
+
+; ebx+32 Cell
+; ebx+30 Number
+; ebx+28 Row
+; ebx+26 Col
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 Cell
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; Cell
+; pointer void --> void
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L278 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L278:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; Col from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; Row from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; Number from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; Cell from: void
+ push dword ptr [esp+16] ; to: void
+
+ call _VioWrtNCell@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__VioWrtNAttr label near
+
+; ebx+32 Attr
+; ebx+30 Number
+; ebx+28 Row
+; ebx+26 Col
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 Attr
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; Attr
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L279 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L279:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; Col from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; Row from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; Number from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; Attr from: char
+ push dword ptr [esp+16] ; to: char
+
+ call _VioWrtNAttr@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__VioWrtNChar label near
+
+; ebx+32 Char
+; ebx+30 Number
+; ebx+28 Row
+; ebx+26 Col
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 Char
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; Char
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L280 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L280:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; Col from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; Row from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; Number from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; Char from: char
+ push dword ptr [esp+16] ; to: char
+
+ call _VioWrtNChar@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__VioScrollDn label near
+
+; ebx+38 ulTopRow
+; ebx+36 ulLeftCol
+; ebx+34 ulBotRow
+; ebx+32 ulRightCol
+; ebx+30 cbLines
+; ebx+26 pbCell
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pbCell
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pbCell
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L281 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L281:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbCell from: char
+ push dword ptr [esp+4] ; to: char
+
+; cbLines from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; ulRightCol from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; ulBotRow from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+; ulLeftCol from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+; ulTopRow from: unsigned short
+ movzx eax,word ptr [ebx+38]
+ push eax ; to: unsigned long
+
+ call _VioScrollDn@28 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T__VioScrollRt label near
+
+; ebx+38 ulTopRow
+; ebx+36 ulLeftCol
+; ebx+34 ulBotRow
+; ebx+32 ulRightCol
+; ebx+30 cbLines
+; ebx+26 pbCell
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pbCell
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pbCell
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L282 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L282:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbCell from: char
+ push dword ptr [esp+4] ; to: char
+
+; cbLines from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; ulRightCol from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; ulBotRow from: unsigned short
+ movzx eax,word ptr [ebx+34]
+ push eax ; to: unsigned long
+
+; ulLeftCol from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+; ulTopRow from: unsigned short
+ movzx eax,word ptr [ebx+38]
+ push eax ; to: unsigned long
+
+ call _VioScrollRt@28 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T__VioGetAnsi label near
+
+; ebx+26 pfAnsi
+; ebx+24 hvio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pfAnsi
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pfAnsi
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L283 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L283:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hvio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pfAnsi from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+ call _VioGetAnsi@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioSetAnsi label near
+
+; ebx+26 fAnsi
+; ebx+24 hVio
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; fAnsi from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+ call _VioSetAnsi@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__VioGetConfig label near
+
+; ebx+30 usReserved
+; ebx+26 Config
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 Config
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; Config
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L284 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L284:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; Config from: void
+ push dword ptr [esp+4] ; to: void
+
+; usReserved from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _VioGetConfig@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__VioGetCp label near
+
+; ebx+30 usReserved
+; ebx+26 pIdCodePage
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pIdCodePage
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pIdCodePage
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L285 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L285:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pIdCodePage from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; usReserved from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _VioGetCp@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__VioSetCp label near
+
+; ebx+28 usReserved
+; ebx+26 idCodePage
+; ebx+24 hVio
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; idCodePage from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; usReserved from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _VioSetCp@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioGetCurType label near
+
+; ebx+26 pCurType
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pCurType
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pCurType
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L286 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L286:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pCurType from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _VioGetCurType@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioSetCurType label near
+
+; ebx+26 pCurType
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pCurType
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pCurType
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L287 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L287:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pCurType from: unsigned long
+ push dword ptr [esp+4] ; to: unsigned long
+
+ call _VioSetCurType@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioSetMode label near
+
+; ebx+26 Mode
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 Mode
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; Mode
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L288 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L288:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; Mode from: unsigned long
+ push dword ptr [esp+4] ; to: unsigned long
+
+ call _VioSetMode@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioDeRegister label near
+
+
+;-------------------------------------
+; create new call frame and make the call
+
+ call _VioDeRegister@0 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_0
+
+;===========================================================================
+T__VioRegister label near
+
+; ebx+36 pszModuleName
+; ebx+32 pszEntryName
+; ebx+28 flFunction1
+; ebx+24 flFunction2
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszModuleName
+ push eax ; ptr param #2 pszEntryName
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszModuleName
+; pointer string --> string
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L289 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L289:
+
+; pszEntryName
+; pointer string --> string
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L290 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L290:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; flFunction2 from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; flFunction1 from: unsigned long
+ push dword ptr [ebx+28] ; to unsigned long
+
+; pszEntryName from: string
+ push dword ptr [esp+8] ; to: string
+
+; pszModuleName from: string
+ push dword ptr [esp+16] ; to: string
+
+ call _VioRegister@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T__VioPopUp label near
+
+; ebx+26 pWait
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pWait
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pWait
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L291 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L291:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pWait from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+ call _VioPopUp@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioEndPopUp label near
+
+; ebx+24 hVio
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _VioEndPopUp@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__VioGetBuf label near
+
+; ebx+30 pulLVB
+; ebx+26 pcbLVB
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pulLVB
+ push eax ; ptr param #2 pcbLVB
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pulLVB
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L292 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L292:
+
+; pcbLVB
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L293 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L293:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pcbLVB from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; pulLVB from: unsigned long
+ push dword ptr [esp+12] ; to: unsigned long
+
+ call _VioGetBuf@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__VioShowBuf label near
+
+; ebx+28 offLVB
+; ebx+26 cbOutput
+; ebx+24 hVio
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; cbOutput from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; offLVB from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _VioShowBuf@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioGetFont label near
+
+; ebx+26 Font
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 Font
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; Font
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L294 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L294:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; Font from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _VioGetFont@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioSetFont label near
+
+; ebx+26 Font
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 Font
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; Font
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L295 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L295:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; Font from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _VioSetFont@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioGetState label near
+
+; ebx+26 State
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 State
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; State
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L296 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L296:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; State from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _VioGetState@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioSetState label near
+
+; ebx+26 State
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 State
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; State
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L297 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L297:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; State from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _VioSetState@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioGetPhysBuf label near
+
+; ebx+26 pviopb
+; ebx+24 Resr
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pviopb
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pviopb
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L298 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L298:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; Resr from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pviopb from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _VioGetPhysBuf@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioModeUndo label near
+
+; ebx+28 fRelinqush
+; ebx+26 fTerminate
+; ebx+24 hVio
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; fTerminate from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; fRelinqush from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _VioModeUndo@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioModeWait label near
+
+; ebx+30 fEvent
+; ebx+26 pfNotify
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pfNotify
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pfNotify
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L299 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L299:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pfNotify from: void
+ push dword ptr [esp+4] ; to: void
+
+; fEvent from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _VioModeWait@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__VioSavRedrawWait label near
+
+; ebx+30 fEvent
+; ebx+26 pfNotify
+; ebx+24 Resr
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pfNotify
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pfNotify
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L300 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L300:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; Resr from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pfNotify from: void
+ push dword ptr [esp+4] ; to: void
+
+; fEvent from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _VioSavRedrawWait@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__VioSavRedrawUndo label near
+
+; ebx+28 fRelinqush
+; ebx+26 fTerminate
+; ebx+24 hVio
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; fTerminate from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; fRelinqush from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _VioSavRedrawUndo@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__VioScrLock label near
+
+; ebx+30 fWait
+; ebx+26 pfNotLocked
+; ebx+24 hVio
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pfNotLocked
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pfNotLocked
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L301 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L301:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pfNotLocked from: void
+ push dword ptr [esp+4] ; to: void
+
+; fWait from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _VioScrLock@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__VioScrUnLock label near
+
+; ebx+24 hVio
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _VioScrUnLock@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__VioPrtSc label near
+
+; ebx+24 hVio
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _VioPrtSc@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__VioPrtScToggle label near
+
+; ebx+24 hVio
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hVio from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _VioPrtScToggle@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__KbdFlushBuffer label near
+
+; ebx+24 hKbd
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _KbdFlushBuffer@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__KbdGetStatus label near
+
+; ebx+26 pkbstKbdInfo
+; ebx+24 hKbd
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pkbstKbdInfo
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pkbstKbdInfo
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L302 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L302:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pkbstKbdInfo from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _KbdGetStatus@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__KbdSetStatus label near
+
+; ebx+26 pkbstKbdInfo
+; ebx+24 hKbd
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pkbstKbdInfo
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pkbstKbdInfo
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L303 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L303:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pkbstKbdInfo from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _KbdSetStatus@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__KbdPeek label near
+
+; ebx+26 pkbci
+; ebx+24 hKbd
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pkbci
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pkbci
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L304 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L304:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pkbci from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _KbdPeek@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__KbdCharIn label near
+
+; ebx+28 pkbci
+; ebx+26 fwait
+; ebx+24 hKbd
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pkbci
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pkbci
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L305 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L305:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; fwait from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; pkbci from: void
+ push dword ptr [esp+8] ; to: void
+
+ call _KbdCharIn@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__KbdStringIn label near
+
+; ebx+32 pchBuffer
+; ebx+28 psibLength
+; ebx+26 fwait
+; ebx+24 hKbd
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pchBuffer
+ push eax ; ptr param #2 psibLength
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pchBuffer
+; pointer void --> void
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L306 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L306:
+
+; psibLength
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L307 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L307:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; fwait from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; psibLength from: void
+ push dword ptr [esp+8] ; to: void
+
+; pchBuffer from: void
+ push dword ptr [esp+16] ; to: void
+
+ call _KbdStringIn@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__KbdGetFocus label near
+
+; ebx+26 Wait
+; ebx+24 hKbd
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; Wait from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+ call _KbdGetFocus@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__KbdFreeFocus label near
+
+; ebx+24 hKbd
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _KbdFreeFocus@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__KbdClose label near
+
+; ebx+24 hKbd
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _KbdClose@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__KbdOpen label near
+
+; ebx+24 hKbd
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 hKbd
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; hKbd
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L308 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L308:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+ call _KbdOpen@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__KbdDeRegister label near
+
+
+;-------------------------------------
+; create new call frame and make the call
+
+ call _KbdDeRegister@0 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_0
+
+;===========================================================================
+T__KbdRegister label near
+
+; ebx+32 pszModuleName
+; ebx+28 pszEntryName
+; ebx+24 fFunctions
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszModuleName
+ push eax ; ptr param #2 pszEntryName
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszModuleName
+; pointer string --> string
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L309 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L309:
+
+; pszEntryName
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L310 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L310:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; fFunctions from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; pszEntryName from: string
+ push dword ptr [esp+4] ; to: string
+
+; pszModuleName from: string
+ push dword ptr [esp+12] ; to: string
+
+ call _KbdRegister@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__KbdGetCp label near
+
+; ebx+30 usReserved
+; ebx+26 pIdCodePage
+; ebx+24 hKbd
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pIdCodePage
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pIdCodePage
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L311 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L311:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pIdCodePage from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; usReserved from: unsigned long
+ push dword ptr [ebx+30] ; to unsigned long
+
+ call _KbdGetCp@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__KbdSetCp label near
+
+; ebx+28 usReserved
+; ebx+26 idCodePage
+; ebx+24 hKbd
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; idCodePage from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; usReserved from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+ call _KbdSetCp@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__KbdSetCustXt label near
+
+; ebx+26 pusTransTbl
+; ebx+24 hKbd
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pusTransTbl
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pusTransTbl
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L312 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L312:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pusTransTbl from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _KbdSetCustXt@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__KbdXlate label near
+
+; ebx+26 pkbxlKeyStroke
+; ebx+24 hKbd
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pkbxlKeyStroke
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pkbxlKeyStroke
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L313 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L313:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pkbxlKeyStroke from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _KbdXlate@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__KbdGetHWID label near
+
+; ebx+26 pkbdhwid
+; ebx+24 hKbd
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pkbdhwid
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pkbdhwid
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L314 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L314:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pkbdhwid from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _KbdGetHWID@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__KbdSetFgnd label near
+
+; ebx+24 hKbd
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hKbd from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _KbdSetFgnd@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__KbdSynch label near
+
+; ebx+24 fWait
+
+;-------------------------------------
+; create new call frame and make the call
+
+; fWait from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _KbdSynch@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__KbdShellInit label near
+
+
+;-------------------------------------
+; create new call frame and make the call
+
+ call _KbdShellInit@0 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_0
+
+;===========================================================================
+T__MouClose label near
+
+; ebx+24 hMou
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _MouClose@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__MouDeRegister label near
+
+
+;-------------------------------------
+; create new call frame and make the call
+
+ call _MouDeRegister@0 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_0
+
+;===========================================================================
+T__MouDrawPtr label near
+
+; ebx+24 hMou
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _MouDrawPtr@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__MouFlushQue label near
+
+; ebx+24 hMou
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _MouFlushQue@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__MouGetDevStatus label near
+
+; ebx+26 DevStatus
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 DevStatus
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; DevStatus
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L315 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L315:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; DevStatus from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+ call _MouGetDevStatus@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__MouGetEventMask label near
+
+; ebx+26 EventMask
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 EventMask
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; EventMask
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L316 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L316:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; EventMask from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+ call _MouGetEventMask@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__MouGetNumButtons label near
+
+; ebx+26 NumButtons
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 NumButtons
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; NumButtons
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L317 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L317:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; NumButtons from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+ call _MouGetNumButtons@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__MouGetNumMickeys label near
+
+; ebx+26 NumMickeys
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 NumMickeys
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; NumMickeys
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L318 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L318:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; NumMickeys from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+ call _MouGetNumMickeys@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__MouGetNumQueEl label near
+
+; ebx+26 NumQueEl
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 NumQueEl
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; NumQueEl
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L319 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L319:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; NumQueEl from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _MouGetNumQueEl@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__MouGetPtrPos label near
+
+; ebx+26 PtrPos
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 PtrPos
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; PtrPos
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L320 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L320:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; PtrPos from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _MouGetPtrPos@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__MouGetPtrShape label near
+
+; ebx+30 PtrMask
+; ebx+26 PtrShape
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 PtrMask
+ push eax ; ptr param #2 PtrShape
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; PtrMask
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L321 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L321:
+
+; PtrShape
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L322 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L322:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; PtrShape from: void
+ push dword ptr [esp+4] ; to: void
+
+; PtrMask from: char
+ push dword ptr [esp+12] ; to: char
+
+ call _MouGetPtrShape@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__MouGetScaleFact label near
+
+; ebx+26 ScaleFact
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 ScaleFact
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; ScaleFact
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L323 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L323:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; ScaleFact from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _MouGetScaleFact@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__MouOpen label near
+
+; ebx+28 DriveName
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 DriveName
+ push eax ; ptr param #2 hMou
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; DriveName
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L324 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L324:
+
+; hMou
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L325 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L325:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; DriveName from: string
+ push dword ptr [esp+8] ; to: string
+
+ call _MouOpen@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__MouReadEventQue label near
+
+; ebx+30 MouEvent
+; ebx+26 Wait
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 MouEvent
+ push eax ; ptr param #2 Wait
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; MouEvent
+; pointer void --> void
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L326 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L326:
+
+; Wait
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L327 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L327:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; Wait from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; MouEvent from: void
+ push dword ptr [esp+12] ; to: void
+
+ call _MouReadEventQue@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__MouRegister label near
+
+; ebx+32 pszModuleName
+; ebx+28 pszEntryName
+; ebx+24 fFunctions
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszModuleName
+ push eax ; ptr param #2 pszEntryName
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszModuleName
+; pointer string --> string
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L328 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L328:
+
+; pszEntryName
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L329 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L329:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; fFunctions from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+; pszEntryName from: string
+ push dword ptr [esp+4] ; to: string
+
+; pszModuleName from: string
+ push dword ptr [esp+12] ; to: string
+
+ call _MouRegister@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__MouRemovePtr label near
+
+; ebx+26 Rect
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 Rect
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; Rect
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L330 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L330:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; Rect from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _MouRemovePtr@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__MouSetDevStatus label near
+
+; ebx+26 DevStatus
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 DevStatus
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; DevStatus
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L331 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L331:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; DevStatus from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+ call _MouSetDevStatus@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__MouSetEventMask label near
+
+; ebx+26 EventMask
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 EventMask
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; EventMask
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L332 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L332:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; EventMask from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+ call _MouSetEventMask@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__MouSetPtrPos label near
+
+; ebx+26 PtrPos
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 PtrPos
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; PtrPos
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L333 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L333:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; PtrPos from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _MouSetPtrPos@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__MouSetPtrShape label near
+
+; ebx+30 PtrMask
+; ebx+26 PtrShape
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 PtrMask
+ push eax ; ptr param #2 PtrShape
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; PtrMask
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L334 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L334:
+
+; PtrShape
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L335 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L335:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; PtrShape from: void
+ push dword ptr [esp+4] ; to: void
+
+; PtrMask from: char
+ push dword ptr [esp+12] ; to: char
+
+ call _MouSetPtrShape@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__MouSetScaleFact label near
+
+; ebx+26 ScaleFact
+; ebx+24 hMou
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 ScaleFact
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; ScaleFact
+; pointer void --> void
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L336 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L336:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; hMou from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; ScaleFact from: void
+ push dword ptr [esp+4] ; to: void
+
+ call _MouSetScaleFact@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_6
+
+;===========================================================================
+T__MouSynch label near
+
+; ebx+24 fWait
+
+;-------------------------------------
+; create new call frame and make the call
+
+; fWait from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _MouSynch@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosMonOpen label near
+
+; ebx+28 pDevName
+; ebx+24 phMon
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pDevName
+ push eax ; ptr param #2 phMon
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pDevName
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L337 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L337:
+
+; phMon
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L338 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L338:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; phMon from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pDevName from: string
+ push dword ptr [esp+8] ; to: string
+
+ call _DosMonOpen@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__DosMonClose label near
+
+; ebx+24 hMon
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hMon from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _DosMonClose@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__DosMonRead label near
+
+; ebx+34 pInBuffer
+; ebx+32 fWait
+; ebx+28 pDataBuf
+; ebx+24 pcbDataSize
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pInBuffer
+ push eax ; ptr param #2 pDataBuf
+ push eax ; ptr param #3 pcbDataSize
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pInBuffer
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L339 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L339:
+
+; pDataBuf
+; pointer char --> char
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L340 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L340:
+
+; pcbDataSize
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L341 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L341:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbDataSize from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pDataBuf from: char
+ push dword ptr [esp+8] ; to: char
+
+; fWait from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; pInBuffer from: char
+ push dword ptr [esp+20] ; to: char
+
+ call _DosMonRead@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__DosMonReg label near
+
+; ebx+36 hMon
+; ebx+32 pInBuffer
+; ebx+28 pOutBuffer
+; ebx+26 fPosition
+; ebx+24 usIndex
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pInBuffer
+ push eax ; ptr param #2 pOutBuffer
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pInBuffer
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L342 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L342:
+
+; pOutBuffer
+; pointer char --> char
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L343 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L343:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; usIndex from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; fPosition from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; pOutBuffer from: char
+ push dword ptr [esp+8] ; to: char
+
+; pInBuffer from: char
+ push dword ptr [esp+16] ; to: char
+
+; hMon from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+ call _DosMonReg@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__DosMonWrite label near
+
+; ebx+30 pOutBuffer
+; ebx+26 pDataBuf
+; ebx+24 cbDataSize
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pOutBuffer
+ push eax ; ptr param #2 pDataBuf
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pOutBuffer
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L344 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L344:
+
+; pDataBuf
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L345 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L345:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbDataSize from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pDataBuf from: char
+ push dword ptr [esp+4] ; to: char
+
+; pOutBuffer from: char
+ push dword ptr [esp+12] ; to: char
+
+ call _DosMonWrite@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__Net16GetDCName label near
+
+; ebx+34 pszServer
+; ebx+30 pszDomain
+; ebx+26 pbBuffer
+; ebx+24 cbBuffer
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszDomain
+ push eax ; ptr param #3 pbBuffer
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L346 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L346:
+
+; pszDomain
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L347 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L347:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L348 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L348:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+4] ; to: char
+
+; pszDomain from: char
+ push dword ptr [esp+12] ; to: char
+
+; pszServer from: char
+ push dword ptr [esp+20] ; to: char
+
+ call _Net16GetDCName@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__Net16HandleGetInfo label near
+
+; ebx+36 hHandle
+; ebx+34 sLevel
+; ebx+30 pbBuffer
+; ebx+28 cbBuffer
+; ebx+24 pcbTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pbBuffer
+ push eax ; ptr param #2 pcbTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L349 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L349:
+
+; pcbTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L350 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L350:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+12] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+34]
+ push eax ; to: long
+
+; hHandle from: unsigned short
+ movzx eax,word ptr [ebx+36]
+ push eax ; to: unsigned long
+
+ call _Net16HandleGetInfo@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__Net16ServerDiskEnum label near
+
+; ebx+40 pszServer
+; ebx+38 sLevel
+; ebx+34 pbBuffer
+; ebx+32 cbBuffer
+; ebx+28 pcEntriesRead
+; ebx+24 pcTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pbBuffer
+ push eax ; ptr param #3 pcEntriesRead
+ push eax ; ptr param #4 pcTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L351 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L351:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L352 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L352:
+
+; pcEntriesRead
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L353 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L353:
+
+; pcTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L354 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L354:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pcEntriesRead from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+20] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+38]
+ push eax ; to: long
+
+; pszServer from: char
+ push dword ptr [esp+32] ; to: char
+
+ call _Net16ServerDiskEnum@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Net16ServerEnum2 label near
+
+; ebx+48 pszServer
+; ebx+46 sLevel
+; ebx+42 pbBuffer
+; ebx+40 cbBuffer
+; ebx+36 pcEntriesRead
+; ebx+32 pcTotalAvail
+; ebx+28 flServerType
+; ebx+24 pszDomain
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pbBuffer
+ push eax ; ptr param #3 pcEntriesRead
+ push eax ; ptr param #4 pcTotalAvail
+ push eax ; ptr param #5 pszDomain
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+48] ; base address
+ or eax,eax
+ jz L355 ; skip if null
+
+ SelToFlat
+ mov [esp+16],eax
+L355:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+42] ; base address
+ or eax,eax
+ jz L356 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L356:
+
+; pcEntriesRead
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L357 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L357:
+
+; pcTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L358 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L358:
+
+; pszDomain
+; pointer char --> char
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L359 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L359:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pszDomain from: char
+ push dword ptr [esp+0] ; to: char
+
+; flServerType from: unsigned long
+ push dword ptr [ebx+28] ; to unsigned long
+
+; pcTotalAvail from: unsigned short
+ push dword ptr [esp+12] ; to: unsigned short
+
+; pcEntriesRead from: unsigned short
+ push dword ptr [esp+20] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+40]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+32] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+46]
+ push eax ; to: long
+
+; pszServer from: char
+ push dword ptr [esp+44] ; to: char
+
+ call _Net16ServerEnum2@32 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_28
+
+;===========================================================================
+T__Net16ServerGetInfo label near
+
+; ebx+36 pszServer
+; ebx+34 sLevel
+; ebx+30 pbBuffer
+; ebx+28 cbBuffer
+; ebx+24 pcbTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pbBuffer
+ push eax ; ptr param #3 pcbTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L360 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L360:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L361 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L361:
+
+; pcbTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L362 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L362:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+12] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+34]
+ push eax ; to: long
+
+; pszServer from: char
+ push dword ptr [esp+24] ; to: char
+
+ call _Net16ServerGetInfo@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T__Net16ServiceControl label near
+
+; ebx+38 pszServer
+; ebx+34 pszService
+; ebx+32 fbOpCode
+; ebx+30 fbArg
+; ebx+26 pbBuffer
+; ebx+24 cbBuffer
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszService
+ push eax ; ptr param #3 pbBuffer
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+38] ; base address
+ or eax,eax
+ jz L363 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L363:
+
+; pszService
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L364 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L364:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L365 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L365:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+4] ; to: char
+
+; fbArg from: unsigned char
+ movzx eax,byte ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; fbOpCode from: unsigned char
+ movzx eax,byte ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; pszService from: char
+ push dword ptr [esp+20] ; to: char
+
+; pszServer from: char
+ push dword ptr [esp+28] ; to: char
+
+ call _Net16ServiceControl@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_18
+
+;===========================================================================
+T__Net16ServiceEnum label near
+
+; ebx+40 pszServer
+; ebx+38 sLevel
+; ebx+34 pbBuffer
+; ebx+32 cbBuffer
+; ebx+28 pcEntriesRead
+; ebx+24 pcTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pbBuffer
+ push eax ; ptr param #3 pcEntriesRead
+ push eax ; ptr param #4 pcTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L366 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L366:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L367 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L367:
+
+; pcEntriesRead
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L368 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L368:
+
+; pcTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L369 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L369:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pcEntriesRead from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+20] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+38]
+ push eax ; to: long
+
+; pszServer from: char
+ push dword ptr [esp+32] ; to: char
+
+ call _Net16ServiceEnum@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Net16ServiceGetInfo label near
+
+; ebx+40 pszServer
+; ebx+36 pszService
+; ebx+34 sLevel
+; ebx+30 pbBuffer
+; ebx+28 cbBuffer
+; ebx+24 pcbTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszService
+ push eax ; ptr param #3 pbBuffer
+ push eax ; ptr param #4 pcbTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L370 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L370:
+
+; pszService
+; pointer char --> char
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L371 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L371:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L372 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L372:
+
+; pcbTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L373 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L373:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+12] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+34]
+ push eax ; to: long
+
+; pszService from: char
+ push dword ptr [esp+24] ; to: char
+
+; pszServer from: char
+ push dword ptr [esp+32] ; to: char
+
+ call _Net16ServiceGetInfo@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Net16ServiceInstall label near
+
+; ebx+38 pszServer
+; ebx+34 pszService
+; ebx+30 pszCmdArgs
+; ebx+26 pbBuffer
+; ebx+24 cbBuffer
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszService
+ push eax ; ptr param #3 pszCmdArgs
+ push eax ; ptr param #4 pbBuffer
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+38] ; base address
+ or eax,eax
+ jz L374 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L374:
+
+; pszService
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L375 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L375:
+
+; pszCmdArgs
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L376 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L376:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L377 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L377:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+4] ; to: char
+
+; pszCmdArgs from: char
+ push dword ptr [esp+12] ; to: char
+
+; pszService from: char
+ push dword ptr [esp+20] ; to: char
+
+; pszServer from: char
+ push dword ptr [esp+28] ; to: char
+
+ call _Net16ServiceInstall@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_18
+
+;===========================================================================
+T__Net16ShareEnum label near
+
+; ebx+40 pszServer
+; ebx+38 sLevel
+; ebx+34 pbBuffer
+; ebx+32 cbBuffer
+; ebx+28 pcEntriesRead
+; ebx+24 pcTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pbBuffer
+ push eax ; ptr param #3 pcEntriesRead
+ push eax ; ptr param #4 pcTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L378 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L378:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L379 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L379:
+
+; pcEntriesRead
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L380 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L380:
+
+; pcTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L381 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L381:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pcEntriesRead from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+20] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+38]
+ push eax ; to: long
+
+; pszServer from: char
+ push dword ptr [esp+32] ; to: char
+
+ call _Net16ShareEnum@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Net16ShareGetInfo label near
+
+; ebx+40 pszServer
+; ebx+36 pszNetName
+; ebx+34 sLevel
+; ebx+30 pbBuffer
+; ebx+28 cbBuffer
+; ebx+24 pcbTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszNetName
+ push eax ; ptr param #3 pbBuffer
+ push eax ; ptr param #4 pcbTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L382 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L382:
+
+; pszNetName
+; pointer char --> char
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L383 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L383:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L384 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L384:
+
+; pcbTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L385 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L385:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+12] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+34]
+ push eax ; to: long
+
+; pszNetName from: char
+ push dword ptr [esp+24] ; to: char
+
+; pszServer from: char
+ push dword ptr [esp+32] ; to: char
+
+ call _Net16ShareGetInfo@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Net16UseAdd label near
+
+; ebx+32 pszServer
+; ebx+30 sLevel
+; ebx+26 pbBuffer
+; ebx+24 cbBuffer
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pbBuffer
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L386 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L386:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L387 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L387:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+4] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+30]
+ push eax ; to: long
+
+; pszServer from: char
+ push dword ptr [esp+16] ; to: char
+
+ call _Net16UseAdd@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__Net16UseDel label near
+
+; ebx+30 pszServer
+; ebx+26 pszUseName
+; ebx+24 usForce
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszUseName
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L388 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L388:
+
+; pszUseName
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L389 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L389:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; usForce from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pszUseName from: char
+ push dword ptr [esp+4] ; to: char
+
+; pszServer from: char
+ push dword ptr [esp+12] ; to: char
+
+ call _Net16UseDel@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__Net16UseEnum label near
+
+; ebx+40 pszServer
+; ebx+38 sLevel
+; ebx+34 pbBuffer
+; ebx+32 cbBuffer
+; ebx+28 pcEntriesRead
+; ebx+24 pcTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pbBuffer
+ push eax ; ptr param #3 pcEntriesRead
+ push eax ; ptr param #4 pcTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L390 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L390:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L391 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L391:
+
+; pcEntriesRead
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L392 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L392:
+
+; pcTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L393 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L393:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pcEntriesRead from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+20] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+38]
+ push eax ; to: long
+
+; pszServer from: char
+ push dword ptr [esp+32] ; to: char
+
+ call _Net16UseEnum@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Net16UseGetInfo label near
+
+; ebx+40 pszServer
+; ebx+36 pszUseName
+; ebx+34 sLevel
+; ebx+30 pbBuffer
+; ebx+28 cbBuffer
+; ebx+24 pcbTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszUseName
+ push eax ; ptr param #3 pbBuffer
+ push eax ; ptr param #4 pcbTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L394 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L394:
+
+; pszUseName
+; pointer char --> char
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L395 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L395:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L396 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L396:
+
+; pcbTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L397 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L397:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+12] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+34]
+ push eax ; to: long
+
+; pszUseName from: char
+ push dword ptr [esp+24] ; to: char
+
+; pszServer from: char
+ push dword ptr [esp+32] ; to: char
+
+ call _Net16UseGetInfo@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Net16UserEnum label near
+
+; ebx+40 pszServer
+; ebx+38 sLevel
+; ebx+34 pbBuffer
+; ebx+32 cbBuffer
+; ebx+28 pcEntriesRead
+; ebx+24 pcTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pbBuffer
+ push eax ; ptr param #3 pcEntriesRead
+ push eax ; ptr param #4 pcTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L398 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L398:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L399 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L399:
+
+; pcEntriesRead
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L400 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L400:
+
+; pcTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L401 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L401:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pcEntriesRead from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+20] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+38]
+ push eax ; to: long
+
+; pszServer from: char
+ push dword ptr [esp+32] ; to: char
+
+ call _Net16UserEnum@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Net16WkstaGetInfo label near
+
+; ebx+36 pszServer
+; ebx+34 sLevel
+; ebx+30 pbBuffer
+; ebx+28 cbBuffer
+; ebx+24 pcbTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pbBuffer
+ push eax ; ptr param #3 pcbTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L402 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L402:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L403 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L403:
+
+; pcbTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L404 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L404:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+12] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+34]
+ push eax ; to: long
+
+; pszServer from: char
+ push dword ptr [esp+24] ; to: char
+
+ call _Net16WkstaGetInfo@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T__Net16AccessAdd label near
+
+; ebx+32 pszServer
+; ebx+30 sLevel
+; ebx+26 pbBuffer
+; ebx+24 cbBUffer
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pbBuffer
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L405 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L405:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L406 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L406:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbBUffer from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+4] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+30]
+ push eax ; to: long
+
+; pszServer from: char
+ push dword ptr [esp+16] ; to: char
+
+ call _Net16AccessAdd@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__Net16AccessSetInfo label near
+
+; ebx+38 pszServer
+; ebx+34 pszResource
+; ebx+32 sLevel
+; ebx+28 pbBuffer
+; ebx+26 cbBuffer
+; ebx+24 sParmNum
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszResource
+ push eax ; ptr param #3 pbBuffer
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+38] ; base address
+ or eax,eax
+ jz L407 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L407:
+
+; pszResource
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L408 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L408:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L409 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L409:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; sParmNum from: short
+ movsx eax,word ptr [ebx+24]
+ push eax ; to: long
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+8] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+32]
+ push eax ; to: long
+
+; pszResource from: char
+ push dword ptr [esp+20] ; to: char
+
+; pszServer from: char
+ push dword ptr [esp+28] ; to: char
+
+ call _Net16AccessSetInfo@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_18
+
+;===========================================================================
+T__Net16AccessGetInfo label near
+
+; ebx+40 pszServer
+; ebx+36 pszResource
+; ebx+34 sLevel
+; ebx+30 pbBuffer
+; ebx+28 cbBuffer
+; ebx+24 pcbTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszResource
+ push eax ; ptr param #3 pbBuffer
+ push eax ; ptr param #4 pcbTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L410 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L410:
+
+; pszResource
+; pointer char --> char
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L411 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L411:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L412 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L412:
+
+; pcbTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L413 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L413:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+12] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+34]
+ push eax ; to: long
+
+; pszResource from: char
+ push dword ptr [esp+24] ; to: char
+
+; pszServer from: char
+ push dword ptr [esp+32] ; to: char
+
+ call _Net16AccessGetInfo@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Net16AccessDel label near
+
+; ebx+28 pszServer
+; ebx+24 pszResource
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszResource
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L414 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L414:
+
+; pszResource
+; pointer char --> char
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L415 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L415:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pszResource from: char
+ push dword ptr [esp+0] ; to: char
+
+; pszServer from: char
+ push dword ptr [esp+8] ; to: char
+
+ call _Net16AccessDel@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__Net16ShareAdd label near
+
+; ebx+32 pszServer
+; ebx+30 sLevel
+; ebx+26 pbBuffer
+; ebx+24 cbBUffer
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pbBuffer
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L416 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L416:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L417 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L417:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbBUffer from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+4] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+30]
+ push eax ; to: long
+
+; pszServer from: char
+ push dword ptr [esp+16] ; to: char
+
+ call _Net16ShareAdd@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__Net16ShareDel label near
+
+; ebx+30 pszServer
+; ebx+26 pszNetName
+; ebx+24 usReserved
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszNetName
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L418 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L418:
+
+; pszNetName
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L419 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L419:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; usReserved from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pszNetName from: char
+ push dword ptr [esp+4] ; to: char
+
+; pszServer from: char
+ push dword ptr [esp+12] ; to: char
+
+ call _Net16ShareDel@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_10
+
+;===========================================================================
+T__Net16UserGetInfo label near
+
+; ebx+40 pszServer
+; ebx+36 pszUserName
+; ebx+34 sLevel
+; ebx+30 pbBuffer
+; ebx+28 cbBUffer
+; ebx+24 pcbTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszUserName
+ push eax ; ptr param #3 pbBuffer
+ push eax ; ptr param #4 pcbTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L420 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L420:
+
+; pszUserName
+; pointer char --> char
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L421 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L421:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L422 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L422:
+
+; pcbTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L423 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L423:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBUffer from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+12] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+34]
+ push eax ; to: long
+
+; pszUserName from: char
+ push dword ptr [esp+24] ; to: char
+
+; pszServer from: char
+ push dword ptr [esp+32] ; to: char
+
+ call _Net16UserGetInfo@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Net16MessageBufferSend label near
+
+; ebx+34 pszServer
+; ebx+30 pszRecipient
+; ebx+26 pbBuffer
+; ebx+24 cbBuffer
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszRecipient
+ push eax ; ptr param #3 pbBuffer
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer string --> string
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L424 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L424:
+
+; pszRecipient
+; pointer string --> string
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L425 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L425:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L426 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L426:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+4] ; to: char
+
+; pszRecipient from: string
+ push dword ptr [esp+12] ; to: string
+
+; pszServer from: string
+ push dword ptr [esp+20] ; to: string
+
+ call _Net16MessageBufferSend@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__Net16bios label near
+
+; ebx+24 pNCB
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pNCB
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pNCB
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L427 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L427:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pNCB from: void
+ push dword ptr [esp+0] ; to: void
+
+ call _Net16bios@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__Net16BiosClose label near
+
+; ebx+26 hDevName
+; ebx+24 usReserved
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hDevName from: unsigned short
+ movzx eax,word ptr [ebx+26]
+ push eax ; to: unsigned long
+
+ call _Net16BiosClose@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__Net16BiosEnum label near
+
+; ebx+40 pszServer
+; ebx+38 sLevel
+; ebx+34 pbBuffer
+; ebx+32 cbBuffer
+; ebx+28 pcEntriesRead
+; ebx+24 pcTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pbBuffer
+ push eax ; ptr param #3 pcEntriesRead
+ push eax ; ptr param #4 pcTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L428 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L428:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L429 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L429:
+
+; pcEntriesRead
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L430 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L430:
+
+; pcTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L431 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L431:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pcEntriesRead from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+20] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+38]
+ push eax ; to: long
+
+; pszServer from: char
+ push dword ptr [esp+32] ; to: char
+
+ call _Net16BiosEnum@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Net16BiosGetInfo label near
+
+; ebx+40 pszServer
+; ebx+36 pszNetBiosName
+; ebx+34 sLevel
+; ebx+30 pbBuffer
+; ebx+28 cbBuffer
+; ebx+24 pcbTotalAvail
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszNetBiosName
+ push eax ; ptr param #3 pbBuffer
+ push eax ; ptr param #4 pcbTotalAvail
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L432 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L432:
+
+; pszNetBiosName
+; pointer char --> char
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L433 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L433:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L434 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L434:
+
+; pcbTotalAvail
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L435 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L435:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcbTotalAvail from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+12] ; to: char
+
+; sLevel from: short
+ movsx eax,word ptr [ebx+34]
+ push eax ; to: long
+
+; pszNetBiosName from: char
+ push dword ptr [esp+24] ; to: char
+
+; pszServer from: char
+ push dword ptr [esp+32] ; to: char
+
+ call _Net16BiosGetInfo@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__Net16BiosOpen label near
+
+; ebx+34 pszServer
+; ebx+30 pszReserved
+; ebx+28 usOpenOpt
+; ebx+24 phDevName
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszServer
+ push eax ; ptr param #2 pszReserved
+ push eax ; ptr param #3 phDevName
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszServer
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L436 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L436:
+
+; pszReserved
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L437 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L437:
+
+; phDevName
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L438 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L438:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; phDevName from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; usOpenOpt from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; pszReserved from: char
+ push dword ptr [esp+12] ; to: char
+
+; pszServer from: char
+ push dword ptr [esp+20] ; to: char
+
+ call _Net16BiosOpen@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_14
+
+;===========================================================================
+T__Net16BiosSubmit label near
+
+; ebx+30 hDevName
+; ebx+28 usNcbOpt
+; ebx+24 pNCB
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pNCB
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pNCB
+; pointer void --> void
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L439 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L439:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pNCB from: void
+ push dword ptr [esp+0] ; to: void
+
+; usNcbOpt from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; hDevName from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+ call _Net16BiosSubmit@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__Dos16MakeMailslot label near
+
+; ebx+32 pszName
+; ebx+30 cbMessageSize
+; ebx+28 cbMailslotSize
+; ebx+24 phMailslot
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszName
+ push eax ; ptr param #2 phMailslot
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszName
+; pointer string --> string
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L440 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L440:
+
+; phMailslot
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L441 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L441:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; phMailslot from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; cbMailslotSize from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; cbMessageSize from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; pszName from: string
+ push dword ptr [esp+16] ; to: string
+
+ call _Dos16MakeMailslot@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__Dos16DeleteMailslot label near
+
+; ebx+24 hMailslot
+
+;-------------------------------------
+; create new call frame and make the call
+
+; hMailslot from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+ call _Dos16DeleteMailslot@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_2
+
+;===========================================================================
+T__Dos16MailslotInfo label near
+
+; ebx+44 hMailslot
+; ebx+40 pcbMessageSize
+; ebx+36 pcbMailslotSize
+; ebx+32 pcbNextSize
+; ebx+28 pusNextPriority
+; ebx+24 pcMessages
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pcbMessageSize
+ push eax ; ptr param #2 pcbMailslotSize
+ push eax ; ptr param #3 pcbNextSize
+ push eax ; ptr param #4 pusNextPriority
+ push eax ; ptr param #5 pcMessages
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pcbMessageSize
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L442 ; skip if null
+
+ SelToFlat
+ mov [esp+16],eax
+L442:
+
+; pcbMailslotSize
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L443 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L443:
+
+; pcbNextSize
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L444 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L444:
+
+; pusNextPriority
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L445 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L445:
+
+; pcMessages
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L446 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L446:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pcMessages from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pusNextPriority from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; pcbNextSize from: unsigned short
+ push dword ptr [esp+16] ; to: unsigned short
+
+; pcbMailslotSize from: unsigned short
+ push dword ptr [esp+24] ; to: unsigned short
+
+; pcbMessageSize from: unsigned short
+ push dword ptr [esp+32] ; to: unsigned short
+
+; hMailslot from: unsigned short
+ movzx eax,word ptr [ebx+44]
+ push eax ; to: unsigned long
+
+ call _Dos16MailslotInfo@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_22
+
+;===========================================================================
+T__Dos16PeekMailslot label near
+
+; ebx+40 hMailslot
+; ebx+36 pbBuffer
+; ebx+32 pcbReturned
+; ebx+28 pcbNextSize
+; ebx+24 pusNextPriority
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pbBuffer
+ push eax ; ptr param #2 pcbReturned
+ push eax ; ptr param #3 pcbNextSize
+ push eax ; ptr param #4 pusNextPriority
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L447 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L447:
+
+; pcbReturned
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L448 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L448:
+
+; pcbNextSize
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L449 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L449:
+
+; pusNextPriority
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L450 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L450:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pusNextPriority from: unsigned short
+ push dword ptr [esp+0] ; to: unsigned short
+
+; pcbNextSize from: unsigned short
+ push dword ptr [esp+8] ; to: unsigned short
+
+; pcbReturned from: unsigned short
+ push dword ptr [esp+16] ; to: unsigned short
+
+; pbBuffer from: char
+ push dword ptr [esp+24] ; to: char
+
+; hMailslot from: unsigned short
+ movzx eax,word ptr [ebx+40]
+ push eax ; to: unsigned long
+
+ call _Dos16PeekMailslot@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_18
+
+;===========================================================================
+T__Dos16ReadMailslot label near
+
+; ebx+44 hMailslot
+; ebx+40 pbBuffer
+; ebx+36 pcbReturned
+; ebx+32 pcbNextSize
+; ebx+28 pusNextPriority
+; ebx+24 cTimeout
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pbBuffer
+ push eax ; ptr param #2 pcbReturned
+ push eax ; ptr param #3 pcbNextSize
+ push eax ; ptr param #4 pusNextPriority
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L451 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L451:
+
+; pcbReturned
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L452 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L452:
+
+; pcbNextSize
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L453 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L453:
+
+; pusNextPriority
+; pointer unsigned short --> unsigned short
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L454 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L454:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cTimeout from: long
+ push dword ptr [ebx+24] ; to long
+
+; pusNextPriority from: unsigned short
+ push dword ptr [esp+4] ; to: unsigned short
+
+; pcbNextSize from: unsigned short
+ push dword ptr [esp+12] ; to: unsigned short
+
+; pcbReturned from: unsigned short
+ push dword ptr [esp+20] ; to: unsigned short
+
+; pbBuffer from: char
+ push dword ptr [esp+28] ; to: char
+
+; hMailslot from: unsigned short
+ movzx eax,word ptr [ebx+44]
+ push eax ; to: unsigned long
+
+ call _Dos16ReadMailslot@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_22
+
+;===========================================================================
+T__Dos16WriteMailslot label near
+
+; ebx+38 pszName
+; ebx+34 pbBuffer
+; ebx+32 cbBuffer
+; ebx+30 usPriority
+; ebx+28 usClass
+; ebx+24 cTimeout
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszName
+ push eax ; ptr param #2 pbBuffer
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszName
+; pointer string --> string
+ mov eax,[ebx+38] ; base address
+ or eax,eax
+ jz L455 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L455:
+
+; pbBuffer
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L456 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L456:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; cTimeout from: long
+ push dword ptr [ebx+24] ; to long
+
+; usClass from: unsigned short
+ movzx eax,word ptr [ebx+28]
+ push eax ; to: unsigned long
+
+; usPriority from: unsigned short
+ movzx eax,word ptr [ebx+30]
+ push eax ; to: unsigned long
+
+; cbBuffer from: unsigned short
+ movzx eax,word ptr [ebx+32]
+ push eax ; to: unsigned long
+
+; pbBuffer from: char
+ push dword ptr [esp+16] ; to: char
+
+; pszName from: string
+ push dword ptr [esp+24] ; to: string
+
+ call _Dos16WriteMailslot@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_18
+
+;===========================================================================
+T__DosIRemoteApi label near
+
+; ebx+42 ApiNumber
+; ebx+38 ServerNamePointer
+; ebx+34 ParameterDescriptor
+; ebx+30 DataDescriptor
+; ebx+26 AuxDescriptor
+; ebx+24 NullSessionFlag
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 ServerNamePointer
+ push eax ; ptr param #2 ParameterDescriptor
+ push eax ; ptr param #3 DataDescriptor
+ push eax ; ptr param #4 AuxDescriptor
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; ServerNamePointer
+; pointer char --> char
+ mov eax,[ebx+38] ; base address
+ or eax,eax
+ jz L457 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L457:
+
+; ParameterDescriptor
+; pointer char --> char
+ mov eax,[ebx+34] ; base address
+ or eax,eax
+ jz L458 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L458:
+
+; DataDescriptor
+; pointer char --> char
+ mov eax,[ebx+30] ; base address
+ or eax,eax
+ jz L459 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L459:
+
+; AuxDescriptor
+; pointer char --> char
+ mov eax,[ebx+26] ; base address
+ or eax,eax
+ jz L460 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L460:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; NullSessionFlag from: unsigned short
+ movzx eax,word ptr [ebx+24]
+ push eax ; to: unsigned long
+
+; AuxDescriptor from: char
+ push dword ptr [esp+4] ; to: char
+
+; DataDescriptor from: char
+ push dword ptr [esp+12] ; to: char
+
+; ParameterDescriptor from: char
+ push dword ptr [esp+20] ; to: char
+
+; ServerNamePointer from: char
+ push dword ptr [esp+28] ; to: char
+
+; ApiNumber from: unsigned short
+ movzx eax,word ptr [ebx+42]
+ push eax ; to: unsigned long
+
+ call _DosIRemoteApi@24 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__NetIWkstaGetUserInfo label near
+
+; ebx+40 UserName
+; ebx+36 logonServer
+; ebx+32 LogonDomain
+; ebx+28 OtherDomains
+; ebx+24 WsName
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 UserName
+ push eax ; ptr param #2 logonServer
+ push eax ; ptr param #3 LogonDomain
+ push eax ; ptr param #4 OtherDomains
+ push eax ; ptr param #5 WsName
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; UserName
+; pointer char --> char
+ mov eax,[ebx+40] ; base address
+ or eax,eax
+ jz L461 ; skip if null
+
+ SelToFlat
+ mov [esp+16],eax
+L461:
+
+; logonServer
+; pointer char --> char
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L462 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L462:
+
+; LogonDomain
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L463 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L463:
+
+; OtherDomains
+; pointer char --> char
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L464 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L464:
+
+; WsName
+; pointer char --> char
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L465 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L465:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; WsName from: char
+ push dword ptr [esp+0] ; to: char
+
+; OtherDomains from: char
+ push dword ptr [esp+8] ; to: char
+
+; LogonDomain from: char
+ push dword ptr [esp+16] ; to: char
+
+; logonServer from: char
+ push dword ptr [esp+24] ; to: char
+
+; UserName from: char
+ push dword ptr [esp+32] ; to: char
+
+ call _NetIWkstaGetUserInfo@20 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_20
+
+;===========================================================================
+T__NetIUserPasswordSet label near
+
+; ebx+36 ServerNamePointer
+; ebx+32 UserNamePointer
+; ebx+28 OldPasswordPointer
+; ebx+24 NewPasswordPointer
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 ServerNamePointer
+ push eax ; ptr param #2 UserNamePointer
+ push eax ; ptr param #3 OldPasswordPointer
+ push eax ; ptr param #4 NewPasswordPointer
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; ServerNamePointer
+; pointer char --> char
+ mov eax,[ebx+36] ; base address
+ or eax,eax
+ jz L466 ; skip if null
+
+ SelToFlat
+ mov [esp+12],eax
+L466:
+
+; UserNamePointer
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L467 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L467:
+
+; OldPasswordPointer
+; pointer char --> char
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L468 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L468:
+
+; NewPasswordPointer
+; pointer char --> char
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L469 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L469:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; NewPasswordPointer from: char
+ push dword ptr [esp+0] ; to: char
+
+; OldPasswordPointer from: char
+ push dword ptr [esp+8] ; to: char
+
+; UserNamePointer from: char
+ push dword ptr [esp+16] ; to: char
+
+; ServerNamePointer from: char
+ push dword ptr [esp+24] ; to: char
+
+ call _NetIUserPasswordSet@16 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_16
+
+;===========================================================================
+T__DosIEncryptSES label near
+
+; ebx+32 ServerNamePointer
+; ebx+28 passwordPointer
+; ebx+24 encryptedLmOwfPassword
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 ServerNamePointer
+ push eax ; ptr param #2 passwordPointer
+ push eax ; ptr param #3 encryptedLmOwfPassword
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; ServerNamePointer
+; pointer char --> char
+ mov eax,[ebx+32] ; base address
+ or eax,eax
+ jz L470 ; skip if null
+
+ SelToFlat
+ mov [esp+8],eax
+L470:
+
+; passwordPointer
+; pointer char --> char
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L471 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L471:
+
+; encryptedLmOwfPassword
+; pointer char --> char
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L472 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L472:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; encryptedLmOwfPassword from: char
+ push dword ptr [esp+0] ; to: char
+
+; passwordPointer from: char
+ push dword ptr [esp+8] ; to: char
+
+; ServerNamePointer from: char
+ push dword ptr [esp+16] ; to: char
+
+ call _DosIEncryptSES@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__Dos32LoadModule label near
+
+; ebx+28 DllName
+; ebx+24 pDllHandle
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 DllName
+ push eax ; ptr param #2 pDllHandle
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; DllName
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L473 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L473:
+
+; pDllHandle
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L474 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L474:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pDllHandle from: unsigned long
+ push dword ptr [esp+0] ; to: unsigned long
+
+; DllName from: string
+ push dword ptr [esp+8] ; to: string
+
+ call _Dos32LoadModule@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__Dos32GetProcAddr label near
+
+; ebx+32 Handle
+; ebx+28 pszProcName
+; ebx+24 pWin32Thunk
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pszProcName
+ push eax ; ptr param #2 pWin32Thunk
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pszProcName
+; pointer string --> string
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L475 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L475:
+
+; pWin32Thunk
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L476 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L476:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pWin32Thunk from: unsigned long
+ push dword ptr [esp+0] ; to: unsigned long
+
+; pszProcName from: string
+ push dword ptr [esp+8] ; to: string
+
+; Handle from: unsigned long
+ push dword ptr [ebx+32] ; to unsigned long
+
+ call _Dos32GetProcAddr@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__Dos32Dispatch label near
+
+; ebx+32 Win32Thunk
+; ebx+28 pArguments
+; ebx+24 pRetCode
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pArguments
+ push eax ; ptr param #2 pRetCode
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pArguments
+; pointer void --> void
+ mov eax,[ebx+28] ; base address
+ or eax,eax
+ jz L477 ; skip if null
+
+ SelToFlat
+ mov [esp+4],eax
+L477:
+
+; pRetCode
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L478 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L478:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pRetCode from: unsigned long
+ push dword ptr [esp+0] ; to: unsigned long
+
+; pArguments from: void
+ push dword ptr [esp+8] ; to: void
+
+; Win32Thunk from: unsigned long
+ push dword ptr [ebx+32] ; to unsigned long
+
+ call _Dos32Dispatch@12 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_12
+
+;===========================================================================
+T__Dos32FreeModule label near
+
+; ebx+24 DllHandle
+
+;-------------------------------------
+; create new call frame and make the call
+
+; DllHandle from: unsigned long
+ push dword ptr [ebx+24] ; to unsigned long
+
+ call _Dos32FreeModule@4 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_4
+
+;===========================================================================
+T__FarPtr2FlatPtr label near
+
+; ebx+28 FarPtr
+; ebx+24 pFlarPtr
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pFlarPtr
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pFlarPtr
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L479 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L479:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pFlarPtr from: unsigned long
+ push dword ptr [esp+0] ; to: unsigned long
+
+; FarPtr from: unsigned long
+ push dword ptr [ebx+28] ; to unsigned long
+
+ call _FarPtr2FlatPtr@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+;===========================================================================
+T__FlatPtr2FarPtr label near
+
+; ebx+28 FlatPtr
+; ebx+24 pFarPtr
+
+;-------------------------------------
+; temp storage
+
+ xor eax,eax
+ push eax ; ptr param #1 pFarPtr
+;-------------------------------------
+; *** BEGIN parameter packing
+
+; pFarPtr
+; pointer unsigned long --> unsigned long
+ mov eax,[ebx+24] ; base address
+ or eax,eax
+ jz L480 ; skip if null
+
+ SelToFlat
+ mov [esp+0],eax
+L480:
+
+; *** END parameter packing
+;-------------------------------------
+; create new call frame and make the call
+
+; pFarPtr from: unsigned long
+ push dword ptr [esp+0] ; to: unsigned long
+
+; FlatPtr from: unsigned long
+ push dword ptr [ebx+28] ; to unsigned long
+
+ call _FlatPtr2FarPtr@8 ; call 32-bit version
+
+; return code unsigned long --> unsigned short
+; no conversion needed
+
+;-------------------------------------
+ jmp ExitFlat_8
+
+_TEXT ends
+ENDIF
+ end
diff --git a/private/os2/client/i386/ldrstart.asm b/private/os2/client/i386/ldrstart.asm
new file mode 100644
index 000000000..59f80694a
--- /dev/null
+++ b/private/os2/client/i386/ldrstart.asm
@@ -0,0 +1,263 @@
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; ldrstart.asm
+;
+; Abstract:
+;
+;
+; Author:
+;
+;
+; Revision History:
+;
+;--
+
+.386p
+
+EXTRN _Save32Esp@4:PROC
+EXTRN _GetSaved32Esp@0:PROC
+EXTRN _LDRDoscallsSel:WORD
+EXTRN _Od2SigHandlingInProgress:DWORD
+EXTRN _MoveInfoSegintoTeb:PROC
+EXTRN _Od2SetSegmentRegisters@0:PROC
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+_DATA ENDS
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ public _ldrstart@4
+_ldrstart@4 proc
+
+ mov edx,[esp+4]
+ xor ax,ax
+ mov es,ax ; (ES) = 0
+
+ mov ebp,0 ; (BP) = 0
+ mov eax, esp
+ push edx
+ push eax
+ call _Save32Esp@4 ;
+ call _MoveInfoSegintoTeb
+ pop edx
+ mov esi, esp ; put the jump instructions in
+ ; scratch stack space, use esi
+ ; to point at it
+ sub esi, 8
+ mov ax, 0ea00h ; far jmp instruction to 16:16
+ mov [esi], ax
+ mov ax,word ptr [edx] ; ip
+ mov [esi+2],ax
+ mov ax, 0
+ mov [esi+4], ax
+ mov ax,word ptr [edx+2] ; cs
+ mov [esi+6],ax
+
+ mov ss,[edx+6] ; (SS:SP) = stack
+ mov sp,[edx+4]
+ movzx eax,word ptr [edx+16] ; (AX) = selector to environment
+ movzx ebx,word ptr [edx+18] ; (BX) = Offset to command line
+ movzx ecx,word ptr [edx+10] ; (CX) = size of dgroup
+ mov ds,[edx+8] ; (DS)
+
+ add esi, 1
+ jmp esi ; jmp to 16 bit program entry point
+ ret
+
+_ldrstart@4 endp
+
+ public _ldrLibiInit
+
+_ldrLibiInit proc
+
+ push ebp
+ mov ebp,esp
+ push ds
+ push es
+ push edi
+ push esi
+ push ebx
+
+ call _GetSaved32Esp@0
+ push eax ; store the previos value of
+ ; 32bit stack top
+ mov eax, esp
+ push eax
+ call _Save32Esp@4
+ call _MoveInfoSegintoTeb
+
+ mov edx,[ebp+8] ; (EDX) = pointer to libi info
+ mov ecx,[ebp+12] ; (ECX) = pointer to exec info
+
+ mov ebp, esp ; put the jump instructions in
+ ; scratch stack space. use ebp
+ sub ebp, 8 ; to point to it
+
+ mov ax, 0ea00h ; far jmp instruction to 16:16
+ mov [ebp], ax
+ mov ax,word ptr [edx+4] ; ip
+ mov [ebp+2],ax
+ mov ax, 0
+ mov [ebp+4], ax
+ mov ax,word ptr [edx+6] ; cs
+ mov [ebp+6],ax
+
+ mov ax,[edx+10] ; (SS) from libi info
+ cmp ax,0 ; if SS==0 load (SS:SP) from the exec_info
+ je ldrss
+ mov ss,ax
+ mov sp,[edx+8] ; (SP) from libi
+ jmp label1
+
+ldrss:
+ mov ss,[ecx+6] ; (SS:SP) = stack
+ mov sp,[ecx+4]
+
+label1:
+ movzx eax,word ptr [edx+16] ; (AX) = module handle
+ movzx edi,word ptr [edx+16] ; (DI) = module handle
+ movzx esi,word ptr [edx+14] ; (SI) = heap size
+ movzx ebx,word ptr [edx+12] ; (DS)
+ cmp bx,0
+ jne ldrds
+ mov bx,[ecx+8]
+ldrds:
+
+; Setup return to LDRLibiReturn thunk in Doscalls.dll
+ movzx ecx,word ptr _ldrDoscallsSel
+ shl ecx,16
+ mov cx,4 ; 4 is offset of LDRLibiReturn in Doscalls.dll
+ push ecx ; Return to LDRLibiReturn
+
+ mov ds,bx
+
+ add ebp, 1
+ jmp ebp ; Jump to 16 bit entry point
+
+
+ public _LDRLibiReturn@0
+_LDRLibiReturn@0 label near
+ mov ebx,eax ; save temporarily return value
+ call _GetSaved32Esp@0
+ mov esp,eax
+ call _Save32Esp@4 ; restore old value of
+ ; 32bit stack top
+ mov eax,ebx ; restore return value
+ pop ebx
+ pop esi
+ pop edi
+ pop es
+ pop ds
+ pop ebp
+ ret
+
+_ldrLibiInit endp
+
+;
+; IMPORTANT !!!
+; Changing the code below (Od2JumpTo16SignalDispatch) check the follows:
+; - Od2GetSegmentRegisters (dlltask.c)
+; - Entry flat and Exit flat (doscalls.asm)
+; - Od2Continue and Od2SetSegmentRegisters (dll16.asm)
+;
+
+ public _Od2JumpTo16SignalDispatch
+; On entry ss:esp is:
+;
+; ebp+8 routine address to dispatch to
+; ebp+12 pointer to 16-bit registers pushed by thunk
+; ebp+16 usFlagNum
+; ebp+20 usFlagArg
+;
+
+_Od2JumpTo16SignalDispatch proc
+
+ push ebp
+ mov ebp,esp
+ push ds
+ push es
+ push edi
+ push esi
+ push ebx
+ call _GetSaved32Esp@0
+ push eax ; store the previous value of
+ ; 32bit stack top
+ mov eax, esp
+ push eax
+ call _Save32Esp@4
+ call _MoveInfoSegintoTeb
+
+ sub esp,8 ; 8 bytes will be used to put
+ ; jump instruction
+
+ mov ebx,[ebp+12] ; (EBX) = pstack
+
+ mov cx,word ptr [ebx+16] ; (ES)
+ shl ecx,16
+ mov dx,word ptr [ebx+18] ; (DS)
+ shl edx,16
+
+ mov cx,word ptr [ebp+16] ; (CX) = usSigNum
+ mov dx,word ptr [ebp+20] ; (DX) = usSigArg
+
+ mov esi,[ebp+8] ; (ESI) = dispatch address
+
+ mov ebp, esp
+
+ mov di,0ea00h ; far jmp instruction to 16:16
+ mov [ebp], di
+ mov [ebp+2],si ; offset
+ mov di,0
+ mov [ebp+4], di
+ shr esi, 16
+ mov [ebp+6],si ; cs
+
+; Setup return to LDRLibiReturn thunk in Doscalls.dll
+ movzx eax,word ptr _ldrDoscallsSel
+ shl eax,16
+; 4 is offset of LDRLibiReturn in Doscalls.dll
+ mov ax,4 ; (EBX) = return to LDRLibiReturn
+ mov esi,dword ptr [ebx] ; Save SS:SP
+
+ lss sp,[ebx] ; (SS:SP)
+ push esi ; Restore SS:SP to 16-bit stack
+ push dx ; place usSigArg on stack
+ push cx ; place usSigNum on stack
+ push eax ; place return to LDRLibiReturn
+
+; Setup 16-bit registers to dispatch to user signal handler
+
+ mov si,word ptr [ebx+12] ; (SI)
+ mov di,word ptr [ebx+14] ; (DI)
+ mov cx,word ptr [ebx+10] ; (CX)
+ mov dx,word ptr [ebx+6] ; (DX)
+ mov ax,word ptr [ebx+8] ; (BX)
+
+public _Od2JumpTo16SignalDispatchBorder@0
+_Od2JumpTo16SignalDispatchBorder@0:
+ mov bx,ax
+ call _Od2SetSegmentRegisters@0
+ add ebp, 1
+ jmp ebp ; Jump to 16 bit entry point
+ public _Od2JumpTo16SignalDispatchEnd@0
+_Od2JumpTo16SignalDispatchEnd@0:
+ ret
+
+_Od2JumpTo16SignalDispatch endp
+
+ public _GetFlatAddrOf16BitStack@0
+_GetFlatAddrOf16BitStack@0 proc
+
+ mov eax,ebx
+ ret
+
+_GetFlatAddrOf16BitStack@0 endp
+
+_TEXT ends
+ end
diff --git a/private/os2/client/makefile b/private/os2/client/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/os2/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/os2/client/mips/dllthunk.s b/private/os2/client/mips/dllthunk.s
new file mode 100644
index 000000000..c97e22207
--- /dev/null
+++ b/private/os2/client/mips/dllthunk.s
@@ -0,0 +1,117 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dllthunk.s
+
+Abstract:
+
+ This module contains callback stubs that allow the OS/2 Emulation
+ Subsystem Server.
+
+Author:
+
+ David N. Cutler (davec) 12-Oct-1990
+
+Revision History:
+
+--*/
+
+#include "ksmips.h"
+
+ SBTTL("OS/2 Subsystem Remote Call Linkage Routines")
+//++
+//
+// The following code is never executed. Its purpose is to support unwinding
+// and exception dispatching through the OS/2 Subsystem Remote Call linkage
+// routines.
+//
+//--
+
+ NESTED_ENTRY(Od2Dispatcher, ContextFrameLength, zero);
+
+ .set noreorder
+ .set noat
+ sw sp,CxIntSp(sp) // save stack pointer
+ sw ra,CxIntRa(sp) // save return address
+ sw ra,CxFir(sp) // save return address
+ sw s8,CxIntS8(sp) // save integer register s8
+ sw gp,CxIntGp(sp) // save integer register gp
+ sw s0,CxIntS0(sp) // save integer registers s0 - s7
+ sw s1,CxIntS1(sp) //
+ sw s2,CxIntS2(sp) //
+ sw s3,CxIntS3(sp) //
+ sw s4,CxIntS4(sp) //
+ sw s5,CxIntS5(sp) //
+ sw s6,CxIntS6(sp) //
+ sw s7,CxIntS7(sp) //
+ swc1 f20,CxFltF20(sp) // store floating registers f20 - f31
+ swc1 f21,CxFltF21(sp) //
+ swc1 f22,CxFltF22(sp) //
+ swc1 f23,CxFltF23(sp) //
+ swc1 f24,CxFltF24(sp) //
+ swc1 f25,CxFltF25(sp) //
+ swc1 f26,CxFltF26(sp) //
+ swc1 f27,CxFltF27(sp) //
+ swc1 f28,CxFltF28(sp) //
+ swc1 f29,CxFltF29(sp) //
+ swc1 f30,CxFltF30(sp) //
+ swc1 f31,CxFltF31(sp) //
+ .set at
+ .set reorder
+
+ PROLOGUE_END
+
+//++
+//
+// Routine Description:
+//
+// The following routines provide linkage to OS/2 client routines to perform
+// exit list handling and signal delivery. There is no return from these
+// routines expected. If a return occurs, then an exception is raised.
+//
+// Arguments:
+//
+// s0 - s7 - Supply parameter values.
+//
+// sp - Supplies the address of a context record.
+//
+// Return Value:
+//
+// There is no return from these routines.
+//
+//--
+
+ ALTERNATE_ENTRY(_Od2ExitListDispatcher)
+
+ jal Od2ExitListDispatcher // call exit list dispatcher
+ li a0,0 // *****
+ jal RtlRaiseStatus // raise exception
+
+ ALTERNATE_ENTRY(_Od2SignalDeliverer)
+
+ move a0,sp // set address of context record
+ move a1,s0 // set signal value
+ jal Od2SignalDeliverer // deliver signal to OS/2 client
+ li a0,0 // ******
+ jal RtlRaiseStatus // raise exception
+10: b 10b // dummy instruction for routine end
+
+ .end Od2Dispatcher
+
+ LEAF_ENTRY(Od2JumpToExitRoutine)
+
+ lw t0,UsPcr+PcTeb(zero)
+ lw sp,TeStackBase(t0)
+ move s8,zero
+ move t0,a0
+ move a0,a1
+ j t0
+
+ .end _Od2JumpToExitRoutine
+
+ LEAF_ENTRY(main)
+
+ .end main
diff --git a/private/os2/client/nlstable.c b/private/os2/client/nlstable.c
new file mode 100644
index 000000000..37efcc5ab
--- /dev/null
+++ b/private/os2/client/nlstable.c
@@ -0,0 +1,2938 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ nls.c
+
+Abstract:
+
+ This module implements includes the OS/2 V1.21 NLS tables.
+
+Author:
+
+ Michael Jarus (mjarus) 15-Apr-1992
+
+Revision History:
+
+--*/
+
+#include <windows.h>
+#include "os2nls.h"
+
+
+COUNTRYINFO USCtryInfo =
+ {
+ CTRY_UNITED_STATES,
+ CODEPAGE_US,
+ DATEFMT_MM_DD_YY,
+ "$\0\0\0",
+ ",",
+ ".",
+ "-",
+ ":",
+ 0 /* BUGBUG?? CURRENCY_DECIMAL*/,
+ 2,
+ TIMEFMT_12_HOUR,
+ { 0, 0 },
+ ",",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO CanadaCtryInfo =
+ {
+ CTRY_CANADA,
+ CODEPAGE_CANADIAN,
+ DATEFMT_YY_MM_DD,
+ "$\0\0\0",
+ " ",
+ ",",
+ "-",
+ ":",
+ CURRENCY_FOLLOW | CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO LatinAmCtryInfo =
+ {
+ COUNTRY_LATIN_AMERICA,
+ CODEPAGE_US,
+ DATEFMT_DD_MM_YY,
+ "$\0\0\0",
+ ",",
+ ".",
+ "/",
+ ":",
+ CURRENCY_FOLLOW | CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO DutchCtryInfo =
+ {
+ CTRY_NETHERLANDS,
+ CODEPAGE_MULTI,
+ DATEFMT_DD_MM_YY,
+ "\237\0\0\0",
+ ".",
+ ",",
+ "-",
+ ":",
+ CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO BelgiunCtryInfo =
+ {
+ CTRY_BELGIUM,
+ CODEPAGE_MULTI,
+ DATEFMT_DD_MM_YY,
+ "BEF\0",
+ ".",
+ ",",
+ "/",
+ ":",
+ CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO FranceCtryInfo =
+ {
+ CTRY_FRANCE,
+ CODEPAGE_US,
+ DATEFMT_DD_MM_YY,
+ "F\0\0\0",
+ " ",
+ ",",
+ "/",
+ ":",
+ CURRENCY_FOLLOW | CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO SpainCtryInfo =
+ {
+ CTRY_SPAIN,
+ CODEPAGE_MULTI,
+ DATEFMT_DD_MM_YY,
+ "Pts\0",
+ ".",
+ ",",
+ "/",
+ ":",
+ CURRENCY_FOLLOW | CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO ItalyCtryInfo =
+ {
+ CTRY_ITALY,
+ CODEPAGE_US,
+ DATEFMT_DD_MM_YY,
+ "L.\0\0",
+ ".",
+ ",",
+ "/",
+ ":",
+ 0,
+ 0,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO SwitzCtryInfo =
+ {
+ CTRY_SWITZERLAND,
+ CODEPAGE_MULTI,
+ DATEFMT_DD_MM_YY,
+ "Fr\0\0",
+ "'",
+ ".",
+ ".",
+ ".",
+ CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ",",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO AustriaCtryInfo =
+ {
+ CTRY_GERMANY,
+ CODEPAGE_US,
+ DATEFMT_DD_MM_YY,
+ "DM\0\0",
+ ".",
+ ",",
+ ".",
+ ".",
+ CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO UKCtryInfo =
+ {
+ CTRY_UNITED_KINGDOM,
+ CODEPAGE_US,
+ DATEFMT_DD_MM_YY,
+ "\234\0\0\0",
+ ",",
+ ".",
+ "-",
+ ":",
+ 0,
+ 2,
+ TIMEFMT_12_HOUR,
+ { 0, 0 },
+ ",",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO DenmarkCtryInfo =
+ {
+ CTRY_DENMARK,
+ CODEPAGE_MULTI,
+ DATEFMT_DD_MM_YY,
+ "kr\0\0",
+ ".",
+ ",",
+ "-",
+ ".",
+ CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO SwedenCtryInfo =
+ {
+ CTRY_SWEDEN,
+ CODEPAGE_US,
+ DATEFMT_YY_MM_DD,
+ "SEK\0",
+ ".",
+ ",",
+ "-",
+ ".",
+ CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO NorwayCtryInfo =
+ {
+ CTRY_NORWAY,
+ CODEPAGE_MULTI,
+ DATEFMT_DD_MM_YY,
+ "Kr\0\0",
+ ".",
+ ",",
+ ".",
+ ".",
+ CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO GermanyCtryInfo =
+ {
+ CTRY_GERMANY,
+ CODEPAGE_US,
+ DATEFMT_DD_MM_YY,
+ "DM\0\0",
+ ".",
+ ",",
+ ".",
+ ".",
+ CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO MexicoCtryInfo =
+ {
+ CTRY_MEXICO,
+ CODEPAGE_US,
+ DATEFMT_DD_MM_YY,
+ "$\0\0\0",
+ ",",
+ ".",
+ "/",
+ ":",
+ CURRENCY_FOLLOW | CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO BrazilCtryInfo =
+ {
+ CTRY_BRAZIL,
+ CODEPAGE_US,
+ DATEFMT_DD_MM_YY,
+ "$\0\0\0",
+ ",",
+ ".",
+ "/",
+ ":",
+ CURRENCY_FOLLOW | CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO AustraliaCtryInfo =
+ {
+ CTRY_AUSTRALIA,
+ CODEPAGE_US,
+ DATEFMT_DD_MM_YY,
+ "$\0\0\0",
+ ",",
+ ".",
+ "-",
+ ":",
+ 0,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ",",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO NewZelandCtryInfo =
+ {
+ CTRY_NEW_ZEALAND,
+ CODEPAGE_US,
+ DATEFMT_DD_MM_YY,
+ "$\0\0\0",
+ ",",
+ ".",
+ "-",
+ ":",
+ 0,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ",",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO PortugalCtryInfo =
+ {
+ CTRY_PORTUGAL,
+ CODEPAGE_PORTUGESE,
+ DATEFMT_DD_MM_YY,
+ "$\0\0\0",
+ ".",
+ ",",
+ "/",
+ ":",
+ CURRENCY_DECIMAL,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO IrelandCtryInfo =
+ {
+ CTRY_IRELAND,
+ CODEPAGE_US,
+ DATEFMT_DD_MM_YY,
+ "\234\0\0\0",
+ ",",
+ ".",
+ "-",
+ ":",
+ 0,
+ 2,
+ TIMEFMT_12_HOUR,
+ { 0, 0 },
+ ",",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO IcelandCtryInfo =
+ {
+ CTRY_ICELAND,
+ CODEPAGE_MULTI,
+ DATEFMT_DD_MM_YY,
+ "Kr\0\0",
+ ".",
+ ",",
+ ".",
+ ".",
+ CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO FinlandCtryInfo =
+ {
+ CTRY_FINLAND,
+ CODEPAGE_MULTI,
+ DATEFMT_DD_MM_YY,
+ "mk\0\0",
+ " ",
+ ",",
+ ".",
+ ".",
+ CURRENCY_FOLLOW | CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO JapanCtryInfo =
+ {
+ CTRY_JAPAN,
+ CODEPAGE_JAPAN,
+ DATEFMT_YY_MM_DD,
+ "\\\0\0\0",
+ ",",
+ ".",
+ "-",
+ ":",
+ 0,
+ 0,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ",",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO KoreaCtryInfo =
+ {
+ CTRY_SOUTH_KOREA,
+ CODEPAGE_KOREA,
+ DATEFMT_YY_MM_DD,
+ "\\\0\0\0",
+ ",",
+ ".",
+ "-",
+ ":",
+ 0,
+ 0,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ",",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO TaiwanCtryInfo =
+ {
+ CTRY_TAIWAN,
+ CODEPAGE_TAIWAN,
+ DATEFMT_MM_DD_YY,
+ "NT$\0",
+ ",",
+ ".",
+ "-",
+ ":",
+ 0,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ",",
+ { 0, 0, 0, 0, 0 }
+ };
+
+COUNTRYINFO Taiwan2CtryInfo =
+ {
+ COUNTRY_TAIWAN,
+ CODEPAGE_TAIWAN,
+ DATEFMT_MM_DD_YY,
+ "NT$\0",
+ ",",
+ ".",
+ "-",
+ ":",
+ 0,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ",",
+ { 0, 0, 0, 0, 0 }
+ };
+
+//#ifdef OS2SS_INCLUDE_HEBREW
+COUNTRYINFO HebrewCtryInfo =
+ {
+ COUNTRY_HEBREW,
+ CODEPAGE_HEBREW,
+ DATEFMT_DD_MM_YY,
+ "\231\0\0\0",
+ ",",
+ ".",
+ " ",
+ ":",
+ CURRENCY_SPACE,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ",",
+ { 0, 0, 0, 0, 0 }
+ };
+//#endif
+
+//#ifdef OS2SS_INCLUDE_ARABIC
+COUNTRYINFO ArabicCtryInfo =
+ {
+ COUNTRY_ARABIC,
+ CODEPAGE_ARABIC,
+ DATEFMT_DD_MM_YY,
+ "\317\0\0\0",
+ ".",
+ ",",
+ "/",
+ ":",
+ CURRENCY_FOLLOW | CURRENCY_SPACE,
+ 3,
+ TIMEFMT_12_HOUR,
+ { 0, 0 },
+ ";",
+ { 0, 0, 0, 0, 0 }
+ };
+//#endif
+
+//#ifdef OS2SS_INCLUDE_PRCHINA
+COUNTRYINFO ChinaCtryInfo =
+ {
+ CTRY_PRCHINA,
+ CODEPAGE_PRC,
+ DATEFMT_YY_MM_DD,
+ "\\\0\0\0",
+ ",",
+ ".",
+ "-",
+ ":",
+ 0,
+ 2,
+ TIMEFMT_24_HOUR,
+ { 0, 0 },
+ ",",
+ { 0, 0, 0, 0, 0 }
+ };
+//#endif
+
+OD2_COUNTRY_ENTRY OD2_COUNTRY_TABLE[] =
+ {
+ { /* United States */
+
+ CTRY_UNITED_STATES,
+ LANG_ENGLISH,
+ SUBLANG_ENGLISH_US,
+ &USCtryInfo,
+ INDEX_CODEPAGE_US,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_UNITED_STATES
+ },
+ { /* Canadian-French */
+
+ CTRY_CANADA,
+ LANG_FRENCH,
+ SUBLANG_FRENCH_CANADIAN,
+ &CanadaCtryInfo,
+ INDEX_CODEPAGE_CANADIAN,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_CANADA
+ },
+ { /* Latin-America */
+
+ COUNTRY_LATIN_AMERICA,
+ LANG_SPANISH,
+ SUBLANG_SPANISH_MEXICAN,
+ &LatinAmCtryInfo,
+ INDEX_CODEPAGE_US,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_LATIN_AMERICA
+ },
+ { /* Netherlands */
+
+ CTRY_NETHERLANDS,
+ LANG_DUTCH,
+ SUBLANG_DUTCH,
+ &DutchCtryInfo,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_CODEPAGE_US, /* INDEX_CODEPAGE_PORTUGESE */
+ INDEX_FIX_CASE_NETHERLANDS
+ },
+ { /* Belgiun */
+
+ CTRY_BELGIUM,
+ LANG_FRENCH,
+ SUBLANG_FRENCH_BELGIAN,
+ &BelgiunCtryInfo,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_CODEPAGE_US,
+ INDEX_FIX_CASE_BELGIUM
+ },
+ { /* France */
+
+ CTRY_FRANCE,
+ LANG_FRENCH,
+ SUBLANG_FRENCH,
+ &FranceCtryInfo,
+ INDEX_CODEPAGE_US,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_FRANCE
+ },
+ { /* Spain */
+
+ CTRY_SPAIN,
+ LANG_SPANISH,
+ SUBLANG_SPANISH,
+ &SpainCtryInfo,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_CODEPAGE_US,
+ INDEX_FIX_CASE_SPAIN
+ },
+ { /* Italy */
+
+ CTRY_ITALY,
+ LANG_ITALIAN,
+ SUBLANG_ITALIAN,
+ &ItalyCtryInfo,
+ INDEX_CODEPAGE_US,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_ITALY
+ },
+ { /* Switzerland */
+
+ CTRY_SWITZERLAND,
+ LANG_FRENCH,
+ SUBLANG_FRENCH_SWISS,
+ &SwitzCtryInfo,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_CODEPAGE_US,
+ INDEX_FIX_CASE_SWITZERLAND
+ },
+ { /* Austria */
+
+ CTRY_AUSTRIA,
+ LANG_GERMAN,
+ SUBLANG_GERMAN,
+ &AustriaCtryInfo,
+ INDEX_CODEPAGE_US,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_AUSTRIA
+ },
+ { /* United Kingdom */
+
+ CTRY_UNITED_KINGDOM,
+ LANG_ENGLISH,
+ SUBLANG_ENGLISH_UK,
+ &UKCtryInfo,
+ INDEX_CODEPAGE_US,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_UNITED_KINGDOM
+ },
+ { /* Denmark */
+
+ CTRY_DENMARK,
+ LANG_DANISH,
+ SUBLANG_NEUTRAL,
+ &DenmarkCtryInfo,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_CODEPAGE_NORDIC,
+ INDEX_FIX_CASE_DENMARK
+ },
+ { /* Sweden */
+
+ CTRY_SWEDEN,
+ LANG_SWEDISH,
+ SUBLANG_NEUTRAL,
+ &SwedenCtryInfo,
+ INDEX_CODEPAGE_US,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_SWEDEN
+ },
+ { /* Norway */
+
+ CTRY_NORWAY,
+ LANG_NORWEGIAN,
+ SUBLANG_NORWEGIAN_BOKMAL, /* or SUBLANG_NORWEGIAN_NYNORSK */
+ &NorwayCtryInfo,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_CODEPAGE_NORDIC,
+ INDEX_FIX_CASE_NORWAY
+ },
+ { /* Germany */
+
+ CTRY_GERMANY,
+ LANG_GERMAN,
+ SUBLANG_GERMAN,
+ &GermanyCtryInfo,
+ INDEX_CODEPAGE_US,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_GERMANY
+ },
+ { /* Mexico */
+
+ CTRY_MEXICO,
+ LANG_SPANISH,
+ SUBLANG_SPANISH_MEXICAN,
+ &MexicoCtryInfo,
+ INDEX_CODEPAGE_US,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_MEXICO
+ },
+ { /* Brazil */
+
+ CTRY_BRAZIL,
+ LANG_SPANISH,
+ SUBLANG_SPANISH_MEXICAN,
+ &BrazilCtryInfo,
+ INDEX_CODEPAGE_US,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_BRAZIL
+ },
+ { /* Australia */
+
+ CTRY_AUSTRALIA,
+ LANG_ENGLISH,
+ SUBLANG_ENGLISH_AUS,
+ &AustraliaCtryInfo,
+ INDEX_CODEPAGE_US,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_AUSTRALIA
+ },
+ { /* New-Zeland */
+
+ CTRY_NEW_ZEALAND,
+ LANG_ENGLISH,
+ SUBLANG_ENGLISH_AUS,
+ &NewZelandCtryInfo,
+ INDEX_CODEPAGE_US,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_NEW_ZEALAND
+ },
+ { /* Portugal */
+
+ CTRY_PORTUGAL,
+ LANG_PORTUGUESE,
+ SUBLANG_PORTUGUESE,
+ &PortugalCtryInfo,
+ INDEX_CODEPAGE_PORTUGESE,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_PORTUGAL
+ },
+ { /* Ireland */
+
+ CTRY_IRELAND,
+ LANG_ENGLISH,
+ SUBLANG_ENGLISH_UK,
+ &IrelandCtryInfo,
+ INDEX_CODEPAGE_US,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_FIX_CASE_IRELAND
+ },
+ { /* Iceland */
+
+ CTRY_ICELAND,
+ LANG_NORWEGIAN,
+ SUBLANG_NORWEGIAN_BOKMAL, /* or SUBLANG_NORWEGIAN_NYNORSK */
+ &IcelandCtryInfo,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_CODEPAGE_NORDIC,
+ INDEX_FIX_CASE_ICELAND
+ },
+ { /* Finland */
+
+ CTRY_FINLAND,
+ LANG_FINNISH,
+ SUBLANG_NEUTRAL,
+ &FinlandCtryInfo,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_CODEPAGE_US,
+ INDEX_FIX_CASE_FINLAND
+ },
+ { /* Japan */
+
+ CTRY_JAPAN,
+ LANG_JAPANESE,
+ SUBLANG_NEUTRAL,
+ &JapanCtryInfo,
+ INDEX_CODEPAGE_JAPAN,
+ INDEX_CODEPAGE_US,
+ INDEX_FIX_CASE_JAPAN
+ },
+ { /* Korea */
+
+ CTRY_SOUTH_KOREA,
+ LANG_KOREAN,
+ SUBLANG_NEUTRAL,
+ &KoreaCtryInfo,
+ INDEX_CODEPAGE_KOREA,
+ INDEX_CODEPAGE_US,
+ INDEX_FIX_CASE_SOUTH_KOREA
+ },
+#if 0
+ { /* Taiwan */
+
+ CTRY_TAIWAN,
+ LANG_THAI,
+ SUBLANG_NEUTRAL,
+ &TaiwanCtryInfo,
+ INDEX_CODEPAGE_TAIWAN,
+ INDEX_CODEPAGE_US,
+ INDEX_FIX_CASE_TAIWAN
+ },
+ { /* Taiwan (old) */
+
+ COUNTRY_TAIWAN,
+ LANG_THAI,
+ SUBLANG_NEUTRAL,
+ &Taiwan2CtryInfo,
+ INDEX_CODEPAGE_TAIWAN,
+ INDEX_CODEPAGE_US,
+ INDEX_FIX_CASE_TAIWAN
+ },
+//#ifdef OS2SS_INCLUDE_HEBREW
+ { /* Hebrew speaking */
+
+ COUNTRY_HEBREW,
+ LANG_HEBREW,
+ SUBLANG_NEUTRAL,
+ &HebrewCtryInfo,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_CODEPAGE_HEBREW,
+ INDEX_FIX_CASE_HEBREW
+ },
+//#endif
+//#ifdef OS2SS_INCLUDE_ARABIC
+ { /* Arabic speaking */
+
+ COUNTRY_ARABIC,
+ LANG_ARABIC,
+ SUBLANG_NEUTRAL,
+ &ArabicCtryInfo,
+ INDEX_CODEPAGE_MULTI,
+ INDEX_CODEPAGE_ARABIC,
+ INDEX_FIX_CASE_ARABIC
+ },
+#endif
+//#endif
+//#ifdef OS2SS_INCLUDE_PRCHINA
+ { /* Peoples Republic of China */
+
+ CTRY_PRCHINA,
+ LANG_CHINESE,
+ SUBLANG_NEUTRAL,
+ &ChinaCtryInfo,
+ INDEX_CODEPAGE_PRC,
+ INDEX_CODEPAGE_US,
+ INDEX_FIX_CASE_PRCHINA
+ },
+//#endif
+ { /* End of Table */
+
+ 0,
+ 0,
+ 0,
+ NULL,
+ 0,
+ 0
+ }
+ };
+
+
+OD2_CODEPAGE_ENTRY OD2_CODEPAGE_TABLE[] =
+ {
+ {
+ 437,
+ INDEX_COLLATE_437,
+ INDEX_CASEMAP_437,
+ INDEX_DBCS_437
+ },
+ {
+ 850,
+ INDEX_COLLATE_850,
+ INDEX_CASEMAP_850,
+ INDEX_DBCS_850
+ },
+ {
+ 860,
+ INDEX_COLLATE_860,
+ INDEX_CASEMAP_860,
+ INDEX_DBCS_860
+ },
+ {
+ 863,
+ INDEX_COLLATE_863,
+ INDEX_CASEMAP_863,
+ INDEX_DBCS_863
+ },
+ {
+ 865,
+ INDEX_COLLATE_865,
+ INDEX_CASEMAP_865,
+ INDEX_DBCS_865
+ },
+ {
+ 932,
+ INDEX_COLLATE_932,
+ INDEX_CASEMAP_932,
+ INDEX_DBCS_932
+ },
+ {
+ 934,
+ INDEX_COLLATE_934,
+ INDEX_CASEMAP_934,
+ INDEX_DBCS_934
+ },
+ {
+ 938,
+ INDEX_COLLATE_938,
+ INDEX_CASEMAP_938,
+ INDEX_DBCS_938
+ },
+//#ifdef OS2SS_INCLUDE_HEBREW
+ {
+ 862,
+ INDEX_COLLATE_862,
+ INDEX_CASEMAP_862,
+ INDEX_DBCS_862
+ },
+//#endif
+//#ifdef OS2SS_INCLUDE_ARABIC
+ {
+ 864,
+ INDEX_COLLATE_864,
+ INDEX_CASEMAP_864,
+ INDEX_DBCS_864
+ },
+//#endif
+//#ifdef OS2SS_INCLUDE_PRCHINA
+ {
+ 936,
+ INDEX_COLLATE_936,
+ INDEX_CASEMAP_936,
+ INDEX_DBCS_936
+ },
+//#endif
+ {
+ 0,
+ 0,
+ 0,
+ 0
+ }
+ };
+
+
+
+OD2_DBCS_VECTOR_ENTRY OD2_DBCS_VECTOR_TABLE[] =
+ {
+ {
+ /* SBCS DBCS EV */
+
+ 2,
+ { 0, 0 }
+ },
+ {
+ /* Japanese DBCS EV */
+
+ 6,
+ { 0x81, 0x9F, 0xE0, 0xFC, 0, 0 }
+ },
+ {
+ /* Korean DBCS EV */
+
+ 4,
+ { 0x81, 0xBF, 0, 0 }
+ },
+ {
+ /* Taiwan DBCS EV */
+
+ 4,
+ { 0x81, 0xFC, 0, 0 }
+ },
+//#ifdef OS2SS_INCLUDE_PRCHINA
+ {
+ /* PRC DBCS EV */
+
+ 4,
+ { 0x81, 0xFC, 0, 0 }
+ },
+//#endif
+ {
+ /* End of Table */
+
+ 2,
+ { 0, 0 }
+ },
+ };
+
+/*
+ * It shows the diff between char offset and its case map
+ *
+
+UCHAR CollateUpdate_437[] =
+ {
+ 0x00, 0x00
+ };
+*/
+UCHAR CollateUpdate_850[] =
+ {
+ 0x9B, 0x4F,
+ 0x9D, 0x4F,
+ 0x9E, 0x9E,
+ 0xB5, 0x41,
+ 0xB6, 0x41,
+ 0xB7, 0x41,
+ 0xBD, 0x24,
+ 0xBE, 0x24,
+ 0xC6, 0x41,
+ 0xC7, 0x41,
+ 0xCF, 0x24,
+ 0xD0, 0x44,
+ 0xD1, 0x44,
+ 0xD2, 0x45,
+ 0xD3, 0x45,
+ 0xD4, 0x45,
+ 0xD5, 0x49,
+ 0xD6, 0x49,
+ 0xD7, 0x49,
+ 0xD8, 0x49,
+ 0xDE, 0x49,
+ 0xE0, 0x4F,
+ 0xE2, 0x4f,
+ 0xE3, 0x4f,
+ 0xE4, 0x4f,
+ 0xE5, 0x4f,
+ 0xE7, 0xE8,
+ 0xE9, 0x55,
+ 0xEA, 0x55,
+ 0xEB, 0x55,
+ 0xEC, 0x59,
+ 0xED, 0x59,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_860[] =
+ {
+ 0x8C, 0x4F,
+ 0x92, 0x45,
+ 0x98, 0x49,
+ 0x9D, 0x55,
+ 0x9F, 0x4F,
+ 0xA6, 0x41,
+ 0xA7, 0x4F,
+ 0xA9, 0x4F,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_863[] =
+ {
+ 0x86, 0x86,
+ 0x8D, 0x8D,
+ 0x8F, 0x8F,
+ 0x91, 0x45,
+ 0x92, 0x45,
+ 0x94, 0x45,
+ 0x95, 0x49,
+ 0x98, 0x98,
+ 0x9B, 0x9B,
+ 0x9C, 0x9C,
+ 0x9D, 0x55,
+ 0x9E, 0x55,
+ 0x9F, 0x9F,
+ 0xA0, 0xA0,
+ 0xA1, 0xA1,
+ 0xA4, 0xA4,
+ 0xA5, 0xA5,
+ 0xA8, 0x49,
+ 0xAD, 0xAD,
+ 0xAE, 0xAE,
+ 0xAF, 0xAF,
+ 0xE1, 0xE1,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_865[] =
+ {
+ 0x5B, 0x28,
+ 0x5C, 0x2F,
+ 0x5D, 0x29,
+ 0x7B, 0x28,
+ 0x7C, 0x2F,
+ 0x7D, 0x29,
+ 0x81, 0x59,
+ 0x84, 0x5B,
+ 0x86, 0x5D,
+ 0x8E, 0x5B,
+ 0x8F, 0x5D,
+ 0x91, 0x5B,
+ 0x92, 0x5B,
+ 0x94, 0x5C,
+ 0x99, 0x5C,
+ 0x9A, 0x59,
+ 0x9B, 0x5C,
+ 0x9D, 0x5C,
+ 0xA6, 0x41,
+ 0xA7, 0x4F,
+ 0xAF, 0x24,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_932[] =
+ {
+ 0x80, 0x80,
+ 0x81, 0xC1,
+ 0x82, 0xC2,
+ 0x83, 0xC3,
+ 0x84, 0xC4,
+ 0x85, 0xC5,
+ 0x86, 0xC6,
+ 0x87, 0xC7,
+ 0x88, 0xC8,
+ 0x89, 0xC9,
+ 0x8A, 0xCA,
+ 0x8B, 0xCB,
+ 0x8C, 0xCC,
+ 0x8D, 0xCD,
+ 0x8E, 0xCE,
+ 0x8F, 0xCF,
+ 0x90, 0xD0,
+ 0x91, 0xD1,
+ 0x92, 0xD2,
+ 0x93, 0xD3,
+ 0x94, 0xD4,
+ 0x95, 0xD5,
+ 0x96, 0xD6,
+ 0x97, 0xD7,
+ 0x98, 0xD8,
+ 0x99, 0xD9,
+ 0x9A, 0xDA,
+ 0x9B, 0xDB,
+ 0x9C, 0xDC,
+ 0x9D, 0xDD,
+ 0x9E, 0xDE,
+ 0x9F, 0xDF,
+ 0xA0, 0x81,
+ 0xA1, 0x82,
+ 0xA2, 0x83,
+ 0xA3, 0x84,
+ 0xA4, 0x85,
+ 0xA5, 0xBD,
+ 0xA6, 0x86,
+ 0xA7, 0x87,
+ 0xA8, 0x88,
+ 0xA9, 0x89,
+ 0xAA, 0x8A,
+ 0xAB, 0x8B,
+ 0xAC, 0x8C,
+ 0xAD, 0x8D,
+ 0xAE, 0x8E,
+ 0xAF, 0x8F,
+ 0xB0, 0x90,
+ 0xB1, 0x91,
+ 0xB2, 0x92,
+ 0xB3, 0x93,
+ 0xB4, 0x94,
+ 0xB5, 0x95,
+ 0xB6, 0x96,
+ 0xB7, 0x97,
+ 0xB8, 0x98,
+ 0xB9, 0x99,
+ 0xBA, 0x9A,
+ 0xBB, 0x9B,
+ 0xBC, 0x9C,
+ 0xBD, 0x9D,
+ 0xBE, 0x9E,
+ 0xBF, 0x9F,
+ 0xC0, 0xA0,
+ 0xC1, 0xA1,
+ 0xC2, 0xA2,
+ 0xC3, 0xA3,
+ 0xC4, 0xA4,
+ 0xC5, 0xA5,
+ 0xC6, 0xA6,
+ 0xC7, 0xA7,
+ 0xC8, 0xA8,
+ 0xC9, 0xA9,
+ 0xCA, 0xAA,
+ 0xCB, 0xAB,
+ 0xCC, 0xAC,
+ 0xCD, 0xAD,
+ 0xCE, 0xAE,
+ 0xCF, 0xAF,
+ 0xD0, 0xB0,
+ 0xD1, 0xB1,
+ 0xD2, 0xB2,
+ 0xD3, 0xB3,
+ 0xD4, 0xB4,
+ 0xD5, 0xB5,
+ 0xD6, 0xB6,
+ 0xD7, 0xB7,
+ 0xD8, 0xB8,
+ 0xD9, 0xB9,
+ 0xDA, 0xBA,
+ 0xDB, 0xBB,
+ 0xDC, 0xBC,
+ 0xDD, 0xBE,
+ 0xDE, 0xBF,
+ 0xDF, 0xC0,
+ 0xE1, 0xE1,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_934[] =
+ {
+ 0x80, 0x80,
+ 0x81, 0xBE,
+ 0x82, 0xBF,
+ 0x83, 0xC0,
+ 0x84, 0xC1,
+ 0x85, 0xC2,
+ 0x86, 0xC3,
+ 0x87, 0xC4,
+ 0x88, 0xC5,
+ 0x89, 0xC6,
+ 0x8A, 0xC7,
+ 0x8B, 0xC8,
+ 0x8C, 0xC9,
+ 0x8D, 0xCA,
+ 0x8E, 0xCB,
+ 0x8F, 0xCC,
+ 0x90, 0xCD,
+ 0x91, 0xCE,
+ 0x92, 0xCF,
+ 0x93, 0xD0,
+ 0x94, 0xD1,
+ 0x95, 0xD2,
+ 0x96, 0xD3,
+ 0x97, 0xD4,
+ 0x98, 0xD5,
+ 0x99, 0xD6,
+ 0x9A, 0xD7,
+ 0x9B, 0xD8,
+ 0x9C, 0xD9,
+ 0x9D, 0xDA,
+ 0x9E, 0xDB,
+ 0x9F, 0xDC,
+ 0xA0, 0xDD,
+ 0xA1, 0xDE,
+ 0xA2, 0xDF,
+ 0xA3, 0xE0,
+ 0xA4, 0xE1,
+ 0xA5, 0xE2,
+ 0xA6, 0xE3,
+ 0xA7, 0xE4,
+ 0xA8, 0xE5,
+ 0xA9, 0xE6,
+ 0xAA, 0xE7,
+ 0xAB, 0xE8,
+ 0xAC, 0xE9,
+ 0xAD, 0xEA,
+ 0xAE, 0xEB,
+ 0xAF, 0xEC,
+ 0xB0, 0xED,
+ 0xB1, 0xEE,
+ 0xB2, 0xEF,
+ 0xB3, 0xF0,
+ 0xB4, 0xF1,
+ 0xB5, 0xF2,
+ 0xB6, 0xF3,
+ 0xB7, 0xF4,
+ 0xB8, 0xF5,
+ 0xB9, 0xF6,
+ 0xBA, 0xF7,
+ 0xBB, 0xF8,
+ 0xBC, 0xF9,
+ 0xBD, 0xFA,
+ 0xBE, 0xFB,
+ 0xBF, 0xFC,
+ 0xC0, 0x81,
+ 0xC1, 0x82,
+ 0xC2, 0x83,
+ 0xC3, 0x84,
+ 0xC4, 0x85,
+ 0xC5, 0x86,
+ 0xC6, 0x87,
+ 0xC7, 0x88,
+ 0xC8, 0x89,
+ 0xC9, 0x8A,
+ 0xCA, 0x8B,
+ 0xCB, 0x8C,
+ 0xCC, 0x8D,
+ 0xCD, 0x8E,
+ 0xCE, 0x8F,
+ 0xCF, 0x90,
+ 0xD0, 0x91,
+ 0xD1, 0x92,
+ 0xD2, 0x93,
+ 0xD3, 0x94,
+ 0xD4, 0x95,
+ 0xD5, 0x96,
+ 0xD6, 0x97,
+ 0xD7, 0x98,
+ 0xD8, 0x99,
+ 0xD9, 0x9A,
+ 0xDA, 0x9B,
+ 0xDB, 0x9C,
+ 0xDC, 0x9D,
+ 0xDD, 0x9E,
+ 0xDE, 0x9F,
+ 0xDF, 0xA0,
+ 0xE0, 0xA1,
+ 0xE1, 0xA2,
+ 0xE2, 0xA3,
+ 0xE3, 0xA4,
+ 0xE4, 0xA5,
+ 0xE5, 0xA6,
+ 0xE6, 0xA7,
+ 0xE7, 0xA8,
+ 0xE8, 0xA9,
+ 0xE9, 0xAA,
+ 0xEA, 0xAB,
+ 0xEB, 0xAC,
+ 0xEC, 0xAD,
+ 0xED, 0xAE,
+ 0xEE, 0xAF,
+ 0xEF, 0xB0,
+ 0xF0, 0xB1,
+ 0xF1, 0xB2,
+ 0xF2, 0xB3,
+ 0xF3, 0xB4,
+ 0xF4, 0xB5,
+ 0xF5, 0xB6,
+ 0xF6, 0xB7,
+ 0xF7, 0xB8,
+ 0xF8, 0xB9,
+ 0xF9, 0xBA,
+ 0xFA, 0xBB,
+ 0xFB, 0xBC,
+ 0xFC, 0xBD,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_938[] =
+ {
+ 0x80, 0x80,
+ 0x81, 0x81,
+ 0x82, 0x82,
+ 0x83, 0x83,
+ 0x84, 0x84,
+ 0x85, 0x85,
+ 0x86, 0x86,
+ 0x87, 0x87,
+ 0x88, 0x88,
+ 0x89, 0x89,
+ 0x8A, 0x8A,
+ 0x8B, 0x8B,
+ 0x8C, 0x8C,
+ 0x8D, 0x8D,
+ 0x8E, 0x8E,
+ 0x8F, 0x8F,
+ 0x90, 0x90,
+ 0x91, 0x91,
+ 0x92, 0x92,
+ 0x93, 0x93,
+ 0x94, 0x94,
+ 0x95, 0x95,
+ 0x96, 0x96,
+ 0x97, 0x97,
+ 0x98, 0x98,
+ 0x99, 0x99,
+ 0x9A, 0x9A,
+ 0x9B, 0x9B,
+ 0x9C, 0x9C,
+ 0x9D, 0x9D,
+ 0x9E, 0x9E,
+ 0x9F, 0x9F,
+ 0xA0, 0xA0,
+ 0xA1, 0xA1,
+ 0xA2, 0xA2,
+ 0xA3, 0xA3,
+ 0xA4, 0xA4,
+ 0xA5, 0xA5,
+ 0xA8, 0xA8,
+ 0xAD, 0xAD,
+ 0xAE, 0xAE,
+ 0xAF, 0xAF,
+ 0xE1, 0xE1,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_862[] =
+ {
+ 0x80, 0x80,
+ 0x81, 0x81,
+ 0x82, 0x82,
+ 0x83, 0x83,
+ 0x84, 0x84,
+ 0x85, 0x85,
+ 0x86, 0x86,
+ 0x87, 0x87,
+ 0x88, 0x88,
+ 0x89, 0x89,
+ 0x8A, 0x8A,
+ 0x8B, 0x8B,
+ 0x8C, 0x8C,
+ 0x8D, 0x8D,
+ 0x8E, 0x8E,
+ 0x8F, 0x8F,
+ 0x90, 0x90,
+ 0x91, 0x91,
+ 0x92, 0x92,
+ 0x93, 0x93,
+ 0x94, 0x94,
+ 0x95, 0x95,
+ 0x96, 0x96,
+ 0x97, 0x97,
+ 0x98, 0x98,
+ 0x99, 0x99,
+ 0x9A, 0x9A,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_864[] =
+ {
+ 0x80, 0x80,
+ 0x81, 0x81,
+ 0x82, 0x82,
+ 0x83, 0x83,
+ 0x84, 0x84,
+ 0x85, 0x85,
+ 0x86, 0x86,
+ 0x87, 0x87,
+ 0x88, 0x88,
+ 0x89, 0x89,
+ 0x8A, 0x8A,
+ 0x8B, 0x8B,
+ 0x8C, 0x8C,
+ 0x8D, 0x8D,
+ 0x8E, 0x8E,
+ 0x8F, 0x8F,
+ 0x90, 0x90,
+ 0x91, 0x91,
+ 0x92, 0x92,
+ 0x93, 0x93,
+ 0x94, 0x94,
+ 0x95, 0x95,
+ 0x96, 0x96,
+ 0x97, 0x97,
+ 0x98, 0x98,
+ 0x99, 0xE9,
+ 0x9A, 0xEA,
+ 0x9B, 0xFB,
+ 0x9C, 0xFF,
+ 0x9D, 0xEB,
+ 0x9E, 0xEC,
+ 0x9F, 0xB3,
+ 0xA0, 0x99,
+ 0xA1, 0x9A,
+ 0xA2, 0xB6,
+ 0xA3, 0x9B,
+ 0xA4, 0x9C,
+ 0xA5, 0xB8,
+ 0xA6, 0xFD,
+ 0xA7, 0xFE,
+ 0xA8, 0xBC,
+ 0xA9, 0xBD,
+ 0xAA, 0xC0,
+ 0xAB, 0xC2,
+ 0xAC, 0xA3,
+ 0xAD, 0xC4,
+ 0xAE, 0xC6,
+ 0xAF, 0xC8,
+ 0xB0, 0xA4,
+ 0xB1, 0xA5,
+ 0xB2, 0xA6,
+ 0xB3, 0xA7,
+ 0xB4, 0xA8,
+ 0xB5, 0xA9,
+ 0xB6, 0xAA,
+ 0xB7, 0xAB,
+ 0xB8, 0xAC,
+ 0xB9, 0xAD,
+ 0xBA, 0xE0,
+ 0xBB, 0xAE,
+ 0xBC, 0xCE,
+ 0xBD, 0xD0,
+ 0xBE, 0xD2,
+ 0xBF, 0xAF,
+ 0xC0, 0x9D,
+ 0xC1, 0xB4,
+ 0xC2, 0xB5,
+ 0xC3, 0xB7,
+ 0xC4, 0xB9,
+ 0xC5, 0xD9,
+ 0xC6, 0xBA,
+ 0xC7, 0xBB,
+ 0xC8, 0xBE,
+ 0xC9, 0xBF,
+ 0xCA, 0xC1,
+ 0xCB, 0xC3,
+ 0xCC, 0xC5,
+ 0xCD, 0xC7,
+ 0xCE, 0xC9,
+ 0xCF, 0xCA,
+ 0xD0, 0xCB,
+ 0xD1, 0xCC,
+ 0xD2, 0xCD,
+ 0xD3, 0xCF,
+ 0xD4, 0xD1,
+ 0xD5, 0xD3,
+ 0xD6, 0xD5,
+ 0xD7, 0xD6,
+ 0xD8, 0xD7,
+ 0xD9, 0xDA,
+ 0xDA, 0xDE,
+ 0xDB, 0x9E,
+ 0xDC, 0x9F,
+ 0xDD, 0xA0,
+ 0xDE, 0xA1,
+ 0xDF, 0xD8,
+ 0xE0, 0xB2,
+ 0xE1, 0xE1,
+ 0xE2, 0xE3,
+ 0xE3, 0xE5,
+ 0xE4, 0xED,
+ 0xE5, 0xEF,
+ 0xE6, 0xF1,
+ 0xE7, 0xF3,
+ 0xE8, 0xF5,
+ 0xE9, 0xF6,
+ 0xEA, 0xFA,
+ 0xEB, 0xD4,
+ 0xEC, 0xDB,
+ 0xED, 0xDD,
+ 0xEE, 0xDC,
+ 0xEF, 0xEE,
+ 0xF0, 0xB1,
+ 0xF1, 0xB0,
+ 0xF2, 0xF0,
+ 0xF3, 0xF2,
+ 0xF5, 0xF7,
+ 0xF6, 0xF9,
+ 0xF7, 0xDF,
+ 0xF8, 0xE2,
+ 0xF9, 0xE7,
+ 0xFA, 0xE8,
+ 0xFB, 0xE6,
+ 0xFC, 0xE4,
+ 0xFD, 0xF8,
+ 0xFE, 0xA2,
+ 0x00, 0x00
+ };
+
+PUCHAR OD2_COLLATE_CP_TABLE[] =
+ {
+ NULL, /* CollateUpdate_437, */
+ CollateUpdate_850,
+ CollateUpdate_860,
+ CollateUpdate_863,
+ CollateUpdate_865,
+ CollateUpdate_932,
+ CollateUpdate_934,
+ CollateUpdate_938,
+//#ifdef OS2SS_INCLUDE_HEBREW
+ CollateUpdate_862,
+//#endif
+//#ifdef OS2SS_INCLUDE_ARABIC
+ CollateUpdate_864,
+//#endif
+//#ifdef OS2SS_INCLUDE_PRCHINA
+ CollateUpdate_938,
+//#endif
+ NULL
+ };
+
+UCHAR CollateUpdate_437LatAm[] =
+ {
+ 0x80, 0x80,
+ 0x87, 0x80,
+ 0xA4, 0xA5,
+ 0xA5, 0xA5,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_850Dutch[] =
+ {
+ 0x86, 0x8F,
+ 0x8F, 0x8F,
+ 0x91, 0x92,
+ 0x92, 0x92,
+ 0x98, 0x98,
+ 0x9C, 0x9C,
+ 0x9F, 0x9F,
+ 0xA4, 0xA5,
+ 0xA5, 0xA5,
+ 0xA8, 0xA8,
+ 0xAD, 0xAD,
+ 0xAE, 0xAE,
+ 0xAF, 0xAF,
+ 0xBD, 0xBD,
+ 0xBE, 0xBE,
+ 0xCF, 0xCF,
+ 0xD0, 0xD1,
+ 0xD1, 0xD1,
+ 0xE1, 0xE1,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_437Dutch[] =
+ {
+ 0x80, 0x80,
+ 0x81, 0x9A,
+ 0x82, 0x90,
+ 0x84, 0x8E,
+ 0x86, 0x8F,
+ 0x87, 0x80,
+ 0x8E, 0x8E,
+ 0x8F, 0x8F,
+ 0x90, 0x90,
+ 0x91, 0x92,
+ 0x92, 0x92,
+ 0x98, 0x98,
+ 0x9B, 0x9B,
+ 0x9C, 0x9C,
+ 0x9D, 0x9D,
+ 0x9E, 0x9E,
+ 0x9F, 0x9F,
+ 0xA4, 0xA5,
+ 0xA5, 0xA5,
+ 0xA8, 0xA8,
+ 0xAD, 0xAD,
+ 0xAE, 0xAE,
+ 0xAF, 0xAF,
+ 0xE1, 0xE1,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_850Belg[] =
+ {
+ 0x00, 0xFF,
+ 0x01, 0xFF,
+ 0x02, 0xFF,
+ 0x03, 0xFF,
+ 0x04, 0xFF,
+ 0x05, 0xFF,
+ 0x06, 0xFF,
+ 0x07, 0xFF,
+ 0x08, 0xFF,
+ 0x09, 0xFF,
+ 0x0A, 0xFF,
+ 0x0B, 0xFF,
+ 0x0C, 0xFF,
+ 0x0D, 0xFF,
+ 0x0E, 0xFF,
+ 0x0F, 0xFF,
+ 0x10, 0xFF,
+ 0x11, 0xFF,
+ 0x12, 0xFF,
+ 0x13, 0xFF,
+ 0x14, 0xFF,
+ 0x15, 0xFF,
+ 0x16, 0xFF,
+ 0x17, 0xFF,
+ 0x18, 0xFF,
+ 0x19, 0xFF,
+ 0x1A, 0xFF,
+ 0x1B, 0xFF,
+ 0x1C, 0xFF,
+ 0x1D, 0xFF,
+ 0x1E, 0xFF,
+ 0x1F, 0xFF,
+ 0x20, 0xFF,
+ 0x27, 0xFF,
+ 0x2D, 0xFF,
+ 0x9C, 0x9C,
+ 0x9F, 0x9F,
+ 0xA5, 0xA4,
+ 0xA8, 0xA8,
+ 0xAD, 0xAD,
+ 0xAE, 0xAE,
+ 0xAF, 0xAF,
+ 0xB0, 0xFF,
+ 0xB1, 0xFF,
+ 0xB2, 0xFF,
+ 0xB3, 0xFF,
+ 0xB4, 0xFF,
+ 0xB9, 0xFF,
+ 0xBA, 0xFF,
+ 0xBB, 0xFF,
+ 0xBC, 0xFF,
+ 0xBD, 0xBD,
+ 0xBE, 0xBE,
+ 0xBF, 0xFF,
+ 0xC0, 0xFF,
+ 0xC1, 0xFF,
+ 0xC2, 0xFF,
+ 0xC3, 0xFF,
+ 0xC4, 0xFF,
+ 0xC5, 0xFF,
+ 0xC8, 0xFF,
+ 0xC9, 0xFF,
+ 0xCA, 0xFF,
+ 0xCB, 0xFF,
+ 0xCC, 0xFF,
+ 0xCD, 0xFF,
+ 0xCE, 0xFF,
+ 0xCF, 0xCF,
+ 0xD9, 0xFF,
+ 0xDA, 0xFF,
+ 0xDB, 0xFF,
+ 0xDC, 0xFF,
+ 0xDF, 0xFF,
+ 0xE7, 0x54,
+ 0xE8, 0x54,
+ 0xF0, 0xFF,
+ 0xFE, 0xFF,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_437Belg[] =
+ {
+ 0x00, 0xFF,
+ 0x01, 0xFF,
+ 0x02, 0xFF,
+ 0x03, 0xFF,
+ 0x04, 0xFF,
+ 0x05, 0xFF,
+ 0x06, 0xFF,
+ 0x07, 0xFF,
+ 0x08, 0xFF,
+ 0x09, 0xFF,
+ 0x0A, 0xFF,
+ 0x0B, 0xFF,
+ 0x0C, 0xFF,
+ 0x0D, 0xFF,
+ 0x0E, 0xFF,
+ 0x0F, 0xFF,
+ 0x10, 0xFF,
+ 0x11, 0xFF,
+ 0x12, 0xFF,
+ 0x13, 0xFF,
+ 0x14, 0xFF,
+ 0x15, 0xFF,
+ 0x16, 0xFF,
+ 0x17, 0xFF,
+ 0x18, 0xFF,
+ 0x19, 0xFF,
+ 0x1A, 0xFF,
+ 0x1B, 0xFF,
+ 0x1C, 0xFF,
+ 0x1D, 0xFF,
+ 0x1E, 0xFF,
+ 0x1F, 0xFF,
+ 0x20, 0xFF,
+ 0x27, 0xFF,
+ 0x2D, 0xFF,
+ 0x9B, 0x9B,
+ 0x9C, 0x9C,
+ 0x9D, 0x9D,
+ 0x9E, 0x9E,
+ 0x9F, 0x9F,
+ 0xA8, 0xA8,
+ 0xAD, 0xAD,
+ 0xAE, 0xAE,
+ 0xAF, 0xAF,
+ 0xB0, 0xFF,
+ 0xB1, 0xFF,
+ 0xB2, 0xFF,
+ 0xB3, 0xFF,
+ 0xB4, 0xFF,
+ 0xB5, 0xFF,
+ 0xB6, 0xFF,
+ 0xB7, 0xFF,
+ 0xB8, 0xFF,
+ 0xB9, 0xFF,
+ 0xBA, 0xFF,
+ 0xBB, 0xFF,
+ 0xBC, 0xFF,
+ 0xBD, 0xFF,
+ 0xBE, 0xFF,
+ 0xBF, 0xFF,
+ 0xC0, 0xFF,
+ 0xC1, 0xFF,
+ 0xC2, 0xFF,
+ 0xC3, 0xFF,
+ 0xC4, 0xFF,
+ 0xC5, 0xFF,
+ 0xC6, 0xFF,
+ 0xC7, 0xFF,
+ 0xC8, 0xFF,
+ 0xC9, 0xFF,
+ 0xCA, 0xFF,
+ 0xCB, 0xFF,
+ 0xCC, 0xFF,
+ 0xCD, 0xFF,
+ 0xCE, 0xFF,
+ 0xCF, 0xFF,
+ 0xD0, 0xFF,
+ 0xD1, 0xFF,
+ 0xD2, 0xFF,
+ 0xD3, 0xFF,
+ 0xD4, 0xFF,
+ 0xD5, 0xFF,
+ 0xD6, 0xFF,
+ 0xD7, 0xFF,
+ 0xD8, 0xFF,
+ 0xD9, 0xFF,
+ 0xDA, 0xFF,
+ 0xDB, 0xFF,
+ 0xDC, 0xFF,
+ 0xDD, 0xFF,
+ 0xDE, 0xFF,
+ 0xDF, 0xFF,
+ 0xFE, 0xFF,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_850Swis[] =
+ {
+ 0x00, 0xE0,
+ 0x01, 0xE1,
+ 0x02, 0xE2,
+ 0x03, 0xE3,
+ 0x04, 0xE4,
+ 0x05, 0xE5,
+ 0x06, 0xE6,
+ 0x07, 0xE7,
+ 0x08, 0xE8,
+ 0x09, 0xE9,
+ 0x0A, 0xEA,
+ 0x0B, 0xEB,
+ 0x0C, 0xEC,
+ 0x0D, 0xED,
+ 0x0E, 0xEE,
+ 0x0F, 0xEF,
+ 0x10, 0xF0,
+ 0x11, 0xF1,
+ 0x12, 0xF2,
+ 0x13, 0xF3,
+ 0x14, 0xF4,
+ 0x15, 0xF5,
+ 0x16, 0xF6,
+ 0x17, 0xF7,
+ 0x18, 0xF8,
+ 0x19, 0xF9,
+ 0x1A, 0xFA,
+ 0x1B, 0xFB,
+ 0x1C, 0xFC,
+ 0x1D, 0xFD,
+ 0x1E, 0xFE,
+ 0x1F, 0xFF,
+ 0x20, 0x00,
+ 0x21, 0xA5,
+ 0x22, 0xA8,
+ 0x23, 0x85,
+ 0x24, 0xB9,
+ 0x25, 0x86,
+ 0x26, 0x87,
+ 0x27, 0xA9,
+ 0x28, 0xAA,
+ 0x29, 0xAB,
+ 0x2A, 0x88,
+ 0x2B, 0x9E,
+ 0x2C, 0xAC,
+ 0x2D, 0xAE,
+ 0x2E, 0xAF,
+ 0x2F, 0xB0,
+ 0x30, 0x75,
+ 0x31, 0x76,
+ 0x32, 0x78,
+ 0x33, 0x7A,
+ 0x34, 0x7C,
+ 0x35, 0x7D,
+ 0x36, 0x7E,
+ 0x37, 0x7F,
+ 0x38, 0x80,
+ 0x39, 0x81,
+ 0x3A, 0xB1,
+ 0x3B, 0xB2,
+ 0x3C, 0xA0,
+ 0x3D, 0xA1,
+ 0x3E, 0xA2,
+ 0x3F, 0xB3,
+ 0x40, 0x89,
+ 0x41, 0x02,
+ 0x42, 0x12,
+ 0x43, 0x14,
+ 0x44, 0x18,
+ 0x45, 0x1C,
+ 0x46, 0x26,
+ 0x47, 0x28,
+ 0x48, 0x2A,
+ 0x49, 0x2C,
+ 0x4A, 0x37,
+ 0x4B, 0x39,
+ 0x4C, 0x3B,
+ 0x4D, 0x3D,
+ 0x4E, 0x3F,
+ 0x4F, 0x43,
+ 0x50, 0x51,
+ 0x51, 0x53,
+ 0x52, 0x55,
+ 0x53, 0x57,
+ 0x54, 0x5A,
+ 0x55, 0x5E,
+ 0x56, 0x68,
+ 0x57, 0x6A,
+ 0x58, 0x6C,
+ 0x59, 0x6E,
+ 0x5A, 0x73,
+ 0x5B, 0x8A,
+ 0x5C, 0x8B,
+ 0x5D, 0x8C,
+ 0x5E, 0xBF,
+ 0x5F, 0xAD,
+ 0x60, 0xBE,
+ 0x61, 0x03,
+ 0x62, 0x13,
+ 0x63, 0x15,
+ 0x64, 0x19,
+ 0x65, 0x1D,
+ 0x66, 0x27,
+ 0x67, 0x29,
+ 0x68, 0x2B,
+ 0x69, 0x38,
+ 0x6A, 0x2D,
+ 0x6B, 0x3A,
+ 0x6C, 0x3C,
+ 0x6D, 0x3E,
+ 0x6E, 0x40,
+ 0x6F, 0x44,
+ 0x70, 0x52,
+ 0x71, 0x54,
+ 0x72, 0x56,
+ 0x73, 0x58,
+ 0x74, 0x5B,
+ 0x75, 0x5F,
+ 0x76, 0x69,
+ 0x77, 0x6B,
+ 0x78, 0x6D,
+ 0x79, 0x6F,
+ 0x7A, 0x74,
+ 0x7B, 0x8E,
+ 0x7C, 0x8F,
+ 0x7D, 0x90,
+ 0x7E, 0xC1,
+ 0x7F, 0x9D,
+ 0x80, 0x16,
+ 0x81, 0x67,
+ 0x82, 0x1F,
+ 0x83, 0x09,
+ 0x84, 0x0B,
+ 0x85, 0x07,
+ 0x86, 0x0F,
+ 0x87, 0x17,
+ 0x88, 0x23,
+ 0x89, 0x25,
+ 0x8A, 0x21,
+ 0x8B, 0x35,
+ 0x8C, 0x33,
+ 0x8D, 0x31,
+ 0x8E, 0x0A,
+ 0x8F, 0x0E,
+ 0x90, 0x1E,
+ 0x91, 0x11,
+ 0x92, 0x10,
+ 0x93, 0x4A,
+ 0x94, 0x4C,
+ 0x95, 0x48,
+ 0x96, 0x65,
+ 0x97, 0x63,
+ 0x98, 0x72,
+ 0x99, 0x4B,
+ 0x9A, 0x66,
+ 0x9B, 0x50,
+ 0x9C, 0xB8,
+ 0x9E, 0xA4,
+ 0x9F, 0xBC,
+ 0xA0, 0x05,
+ 0xA1, 0x2F,
+ 0xA2, 0x46,
+ 0xA3, 0x61,
+ 0xA4, 0x42,
+ 0xA5, 0x41,
+ 0xA6, 0x95,
+ 0xA7, 0x94,
+ 0xA8, 0xB4,
+ 0xA9, 0x9A,
+ 0xAA, 0x9C,
+ 0xAB, 0x83,
+ 0xAC, 0x82,
+ 0xAD, 0xA6,
+ 0xAE, 0xB5,
+ 0xAF, 0xB6,
+ 0xB0, 0xCF,
+ 0xB1, 0xD0,
+ 0xB2, 0xD1,
+ 0xB3, 0xCE,
+ 0xB4, 0xCC,
+ 0xB5, 0x04,
+ 0xB6, 0x08,
+ 0xB7, 0x06,
+ 0xB8, 0x99,
+ 0xB9, 0xD2,
+ 0xBA, 0xD3,
+ 0xBB, 0xD4,
+ 0xBC, 0xD5,
+ 0xBD, 0xBA,
+ 0xBE, 0xBB,
+ 0xBF, 0xC6,
+ 0xC0, 0xC5,
+ 0xC1, 0xCA,
+ 0xC2, 0xC9,
+ 0xC3, 0xCB,
+ 0xC4, 0xCD,
+ 0xC5, 0xC8,
+ 0xC6, 0x0D,
+ 0xC7, 0x0C,
+ 0xC8, 0xD6,
+ 0xC9, 0xD7,
+ 0xCA, 0xD8,
+ 0xCB, 0xD9,
+ 0xCC, 0xDA,
+ 0xCD, 0xDB,
+ 0xCE, 0xDC,
+ 0xCF, 0xB7,
+ 0xD0, 0x1B,
+ 0xD1, 0x1A,
+ 0xD2, 0x22,
+ 0xD3, 0x24,
+ 0xD4, 0x20,
+ 0xD5, 0x36,
+ 0xD6, 0x2E,
+ 0xD7, 0x32,
+ 0xD8, 0x34,
+ 0xD9, 0xC7,
+ 0xDA, 0xC4,
+ 0xDB, 0xDF,
+ 0xDC, 0xDD,
+ 0xDD, 0x9B,
+ 0xDE, 0x30,
+ 0xDF, 0xDE,
+ 0xE0, 0x45,
+ 0xE1, 0x59,
+ 0xE2, 0x49,
+ 0xE3, 0x47,
+ 0xE4, 0x4E,
+ 0xE5, 0x4D,
+ 0xE6, 0x92,
+ 0xE7, 0x5C,
+ 0xE8, 0x5D,
+ 0xE9, 0x60,
+ 0xEA, 0x64,
+ 0xEB, 0x62,
+ 0xEC, 0x71,
+ 0xED, 0x70,
+ 0xEE, 0x91,
+ 0xEF, 0xBD,
+ 0xF0, 0xA7,
+ 0xF1, 0x9F,
+ 0xF2, 0x8D,
+ 0xF3, 0x84,
+ 0xF4, 0x97,
+ 0xF5, 0x96,
+ 0xF6, 0xA3,
+ 0xF7, 0xC2,
+ 0xF8, 0x93,
+ 0xF9, 0xC0,
+ 0xFA, 0xC3,
+ 0xFB, 0x77,
+ 0xFC, 0x7B,
+ 0xFD, 0x79,
+ 0xFE, 0x98,
+ 0xFF, 0x01,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_437Swis[] =
+ {
+ 0x00, 0x01,
+ 0x01, 0xC8,
+ 0x02, 0xC9,
+ 0x03, 0xCA,
+ 0x04, 0xCB,
+ 0x05, 0xCC,
+ 0x06, 0xCD,
+ 0x07, 0xCE,
+ 0x08, 0xCF,
+ 0x09, 0xD0,
+ 0x0A, 0xD1,
+ 0x0B, 0xD2,
+ 0x0C, 0xD3,
+ 0x0D, 0xD4,
+ 0x0E, 0xD5,
+ 0x0F, 0xD6,
+ 0x10, 0xD7,
+ 0x11, 0xD8,
+ 0x12, 0xD9,
+ 0x13, 0xDA,
+ 0x14, 0x8C,
+ 0x15, 0x8D,
+ 0x16, 0xDB,
+ 0x17, 0xDC,
+ 0x18, 0xDD,
+ 0x19, 0xDE,
+ 0x1A, 0xDF,
+ 0x1B, 0xE0,
+ 0x1C, 0xE1,
+ 0x1D, 0xE2,
+ 0x1E, 0xE3,
+ 0x1F, 0xE4,
+ 0x20, 0x01,
+ 0x21, 0x3C,
+ 0x22, 0x3D,
+ 0x23, 0x3E,
+ 0x24, 0x3F,
+ 0x25, 0x40,
+ 0x26, 0x41,
+ 0x27, 0x42,
+ 0x28, 0x43,
+ 0x29, 0x44,
+ 0x2A, 0x45,
+ 0x2B, 0x46,
+ 0x2C, 0x47,
+ 0x2D, 0x48,
+ 0x2E, 0x49,
+ 0x2F, 0x4A,
+ 0x30, 0x20,
+ 0x31, 0x21,
+ 0x32, 0x22,
+ 0x33, 0x23,
+ 0x34, 0x24,
+ 0x35, 0x25,
+ 0x36, 0x26,
+ 0x37, 0x27,
+ 0x38, 0x28,
+ 0x39, 0x29,
+ 0x3A, 0x4B,
+ 0x3B, 0x4C,
+ 0x3C, 0x4D,
+ 0x3D, 0x4E,
+ 0x3E, 0x4F,
+ 0x3F, 0x50,
+ 0x40, 0x51,
+ 0x41, 0x02,
+ 0x42, 0x03,
+ 0x43, 0x04,
+ 0x44, 0x05,
+ 0x45, 0x07,
+ 0x46, 0x08,
+ 0x47, 0x09,
+ 0x48, 0x0A,
+ 0x49, 0x0B,
+ 0x4A, 0x0C,
+ 0x4B, 0x0D,
+ 0x4C, 0x0E,
+ 0x4D, 0x0F,
+ 0x4E, 0x10,
+ 0x4F, 0x12,
+ 0x50, 0x13,
+ 0x51, 0x14,
+ 0x52, 0x15,
+ 0x53, 0x16,
+ 0x54, 0x18,
+ 0x55, 0x1A,
+ 0x56, 0x1B,
+ 0x57, 0x1C,
+ 0x58, 0x1D,
+ 0x59, 0x1E,
+ 0x5A, 0x1F,
+ 0x5B, 0x52,
+ 0x5C, 0x53,
+ 0x5D, 0x54,
+ 0x5E, 0x34,
+ 0x5F, 0x55,
+ 0x60, 0x33,
+ 0x61, 0x02,
+ 0x62, 0x03,
+ 0x63, 0x04,
+ 0x64, 0x05,
+ 0x65, 0x07,
+ 0x66, 0x08,
+ 0x67, 0x09,
+ 0x68, 0x0A,
+ 0x69, 0x0B,
+ 0x6A, 0x0C,
+ 0x6B, 0x0D,
+ 0x6C, 0x0E,
+ 0x6D, 0x0F,
+ 0x6E, 0x10,
+ 0x6F, 0x12,
+ 0x70, 0x13,
+ 0x71, 0x14,
+ 0x72, 0x15,
+ 0x73, 0x16,
+ 0x74, 0x18,
+ 0x75, 0x1A,
+ 0x76, 0x1B,
+ 0x77, 0x1C,
+ 0x78, 0x1D,
+ 0x79, 0x1E,
+ 0x7A, 0x1F,
+ 0x7B, 0x56,
+ 0x7C, 0x57,
+ 0x7D, 0x58,
+ 0x7E, 0x36,
+ 0x7F, 0x59,
+ 0x80, 0x04,
+ 0x81, 0x1A,
+ 0x82, 0x07,
+ 0x83, 0x02,
+ 0x84, 0x02,
+ 0x85, 0x02,
+ 0x86, 0x02,
+ 0x87, 0x04,
+ 0x88, 0x07,
+ 0x89, 0x07,
+ 0x8A, 0x07,
+ 0x8B, 0x0B,
+ 0x8C, 0x0B,
+ 0x8D, 0x0B,
+ 0x8E, 0x02,
+ 0x8F, 0x02,
+ 0x90, 0x07,
+ 0x91, 0x02,
+ 0x92, 0x02,
+ 0x93, 0x12,
+ 0x94, 0x12,
+ 0x95, 0x12,
+ 0x96, 0x1A,
+ 0x97, 0x1A,
+ 0x98, 0x1E,
+ 0x99, 0x12,
+ 0x9A, 0x1A,
+ 0x9B, 0x6F,
+ 0x9C, 0x5A,
+ 0x9D, 0x70,
+ 0x9E, 0x96,
+ 0x9F, 0x5C,
+ 0xA0, 0x02,
+ 0xA1, 0x0B,
+ 0xA2, 0x12,
+ 0xA3, 0x1A,
+ 0xA4, 0x11,
+ 0xA5, 0x11,
+ 0xA6, 0x02,
+ 0xA7, 0x12,
+ 0xA8, 0x5D,
+ 0xA9, 0x97,
+ 0xAA, 0x5F,
+ 0xAB, 0x60,
+ 0xAC, 0x61,
+ 0xAD, 0x62,
+ 0xAE, 0x63,
+ 0xAF, 0x64,
+ 0xB0, 0x65,
+ 0xB1, 0x66,
+ 0xB2, 0x67,
+ 0xB3, 0x68,
+ 0xB4, 0x69,
+ 0xB5, 0x98,
+ 0xB6, 0x99,
+ 0xB7, 0x9A,
+ 0xB8, 0x9B,
+ 0xB9, 0x6B,
+ 0xBA, 0x6C,
+ 0xBB, 0x6D,
+ 0xBC, 0x6E,
+ 0xBD, 0x9C,
+ 0xBE, 0x9D,
+ 0xBF, 0x71,
+ 0xC0, 0x72,
+ 0xC1, 0x73,
+ 0xC2, 0x74,
+ 0xC3, 0x75,
+ 0xC4, 0x76,
+ 0xC5, 0x77,
+ 0xC6, 0x9E,
+ 0xC7, 0x9F,
+ 0xC8, 0x78,
+ 0xC9, 0x79,
+ 0xCA, 0x7A,
+ 0xCB, 0x7B,
+ 0xCC, 0x7C,
+ 0xCD, 0x7D,
+ 0xCE, 0x7E,
+ 0xCF, 0xA0,
+ 0xD0, 0xA1,
+ 0xD1, 0xA2,
+ 0xD2, 0xA3,
+ 0xD3, 0xA4,
+ 0xD4, 0xA5,
+ 0xD5, 0xA6,
+ 0xD6, 0xA7,
+ 0xD7, 0xA8,
+ 0xD8, 0xA9,
+ 0xD9, 0x80,
+ 0xDA, 0x81,
+ 0xDB, 0x82,
+ 0xDC, 0x83,
+ 0xDD, 0xAA,
+ 0xDE, 0xAB,
+ 0xDF, 0x85,
+ 0xE0, 0xAC,
+ 0xE1, 0x17,
+ 0xE2, 0xAD,
+ 0xE3, 0xAE,
+ 0xE4, 0xAF,
+ 0xE5, 0xB0,
+ 0xE6, 0x86,
+ 0xE7, 0xB1,
+ 0xE8, 0xB2,
+ 0xE9, 0xB3,
+ 0xEA, 0xB4,
+ 0xEB, 0xB5,
+ 0xEC, 0xB6,
+ 0xED, 0xB7,
+ 0xEE, 0xB8,
+ 0xEF, 0xB9,
+ 0xF0, 0xBA,
+ 0xF1, 0x89,
+ 0xF2, 0xBB,
+ 0xF3, 0xBC,
+ 0xF4, 0xBD,
+ 0xF5, 0xBE,
+ 0xF6, 0x8E,
+ 0xF7, 0xBF,
+ 0xF8, 0x8F,
+ 0xF9, 0xC0,
+ 0xFA, 0x90,
+ 0xFB, 0xC1,
+ 0xFC, 0xC2,
+ 0xFD, 0x93,
+ 0xFE, 0x94,
+ 0xFF, 0x01,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_850Denm[] =
+ {
+ 0x5B, 0x28,
+ 0x5C, 0x2F,
+ 0x5D, 0x29,
+ 0x7B, 0x28,
+ 0x7C, 0x2F,
+ 0x7D, 0x29,
+ 0x81, 0x59,
+ 0x84, 0x5B,
+ 0x86, 0x5D,
+ 0x8E, 0x5B,
+ 0x8F, 0x5D,
+ 0x91, 0x5B,
+ 0x92, 0x5B,
+ 0x94, 0x5C,
+ 0x99, 0x5C,
+ 0x9A, 0x59,
+ 0x9B, 0x5C,
+ 0x9D, 0x5C,
+ 0xA6, 0x41,
+ 0xA7, 0x4F,
+ 0xE7, 0x50,
+ 0xE8, 0x50,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_850Swed[] =
+ {
+ 0x81, 0x59,
+ 0x84, 0x5C,
+ 0x86, 0x5B,
+ 0x8E, 0x5C,
+ 0x8F, 0x5B,
+ 0x91, 0x5C,
+ 0x92, 0x5C,
+ 0x94, 0x5D,
+ 0x99, 0x5D,
+ 0x9A, 0x59,
+ 0x9B, 0x5D,
+ 0x9D, 0x5D,
+ 0xE4, 0x5D,
+ 0xE5, 0x5D,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_437Swed[] =
+ {
+ 0x81, 0x59,
+ 0x84, 0x5C,
+ 0x86, 0x5B,
+ 0x8E, 0x5C,
+ 0x8F, 0x5B,
+ 0x91, 0x5C,
+ 0x92, 0x5C,
+ 0x94, 0x5D,
+ 0x99, 0x5D,
+ 0x9A, 0x59,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_850Norw[] =
+ {
+ 0x84, 0x5B,
+ 0x86, 0x5D,
+ 0x8E, 0x5B,
+ 0x8F, 0x5D,
+ 0x91, 0x5B,
+ 0x92, 0x5B,
+ 0x94, 0x5C,
+ 0x99, 0x5C,
+ 0x9A, 0x59,
+ 0x9B, 0x5C,
+ 0x9D, 0x5C,
+ 0xA6, 0x41,
+ 0xA7, 0x4F,
+ 0xE7, 0x50,
+ 0xE8, 0x50,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_865Norw[] =
+ {
+ 0x5B, 0x5B,
+ 0x5C, 0x5C,
+ 0x5D, 0x5D,
+ 0x7B, 0x7B,
+ 0x7C, 0x7C,
+ 0x7D, 0x7D,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_850Finl[] =
+ {
+ 0x81, 0x59,
+ 0x84, 0x5C,
+ 0x86, 0x5B,
+ 0x8E, 0x5C,
+ 0x8F, 0x5B,
+ 0x91, 0x5C,
+ 0x92, 0x5C,
+ 0x94, 0x5D,
+ 0x99, 0x5D,
+ 0x9A, 0x59,
+ 0x9B, 0x5D,
+ 0x9D, 0x5D,
+ 0x00, 0x00
+ };
+
+UCHAR CollateUpdate_437Finl[] =
+ {
+ 0x81, 0x59,
+ 0x84, 0x5C,
+ 0x86, 0x5B,
+ 0x8E, 0x5C,
+ 0x8F, 0x5B,
+ 0x91, 0x5C,
+ 0x92, 0x5C,
+ 0x94, 0x5D,
+ 0x99, 0x5D,
+ 0x9A, 0x59,
+ 0x00, 0x00
+ };
+
+OD2_COLLATE_CTRY_ENTRY OD2_COLLATE_CTRY_TABLE[] =
+ {
+ {
+ COUNTRY_LATIN_AMERICA,
+ CODEPAGE_US,
+ CollateUpdate_437LatAm
+ },
+ {
+ CTRY_MEXICO,
+ CODEPAGE_US,
+ CollateUpdate_437LatAm
+ },
+ {
+ CTRY_NETHERLANDS,
+ CODEPAGE_MULTI,
+ CollateUpdate_850Dutch
+ },
+ {
+ CTRY_NETHERLANDS,
+ CODEPAGE_US,
+ CollateUpdate_437Dutch
+ },
+ {
+ CTRY_BELGIUM,
+ CODEPAGE_MULTI,
+ CollateUpdate_850Belg
+ },
+ {
+ CTRY_BELGIUM,
+ CODEPAGE_US,
+ CollateUpdate_437Belg
+ },
+ {
+ CTRY_SPAIN,
+ CODEPAGE_US,
+ CollateUpdate_437LatAm
+ },
+ {
+ CTRY_SWITZERLAND,
+ CODEPAGE_MULTI,
+ CollateUpdate_850Swis
+ },
+ {
+ CTRY_SWITZERLAND,
+ CODEPAGE_US,
+ CollateUpdate_437Swis
+ },
+ {
+ CTRY_DENMARK,
+ CODEPAGE_MULTI,
+ CollateUpdate_850Denm
+ },
+ {
+ CTRY_SWEDEN,
+ CODEPAGE_MULTI,
+ CollateUpdate_850Swed
+ },
+ {
+ CTRY_SWEDEN,
+ CODEPAGE_US,
+ CollateUpdate_437Swed
+ },
+ {
+ CTRY_NORWAY,
+ CODEPAGE_MULTI,
+ CollateUpdate_850Norw
+ },
+ {
+ CTRY_NORWAY,
+ CODEPAGE_NORDIC,
+ CollateUpdate_865Norw
+ },
+ {
+ CTRY_FINLAND,
+ CODEPAGE_MULTI,
+ CollateUpdate_850Finl
+ },
+ {
+ CTRY_FINLAND,
+ CODEPAGE_US,
+ CollateUpdate_437Finl
+ },
+ {
+ 0,
+ 0,
+ NULL
+ }
+ };
+
+
+UCHAR Od2BaseCollateTable[256] =
+ {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+ 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+ 0x43, 0x55, 0x45, 0x41, 0x41, 0x41, 0x41, 0x43,
+ 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x41, 0x41,
+ 0x45, 0x41, 0x41, 0x4F, 0x4F, 0x4F, 0x55, 0x55,
+ 0x59, 0x4F, 0x55, 0x24, 0x24, 0x24, 0x24, 0x24,
+ 0x41, 0x49, 0x4F, 0x55, 0x4E, 0x4E, 0xA6, 0xA7,
+ 0x3F, 0xA9, 0xAA, 0xAB, 0xAC, 0x21, 0x22, 0x22,
+ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+ 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0x53, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
+ };
+
+
+UCHAR Od2BaseCaseMapTable[256] =
+ {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0X10, 0X11, 0X12, 0X13, 0X14, 0X15, 0X16, 0X17,
+ 0X18, 0X19, 0X1A, 0X1B, 0X1C, 0X1D, 0X1E, 0X1F,
+ 0X20, 0X21, 0X22, 0X23, 0X24, 0X25, 0X26, 0X27,
+ 0X28, 0X29, 0X2A, 0X2B, 0X2C, 0X2D, 0X2E, 0X2F,
+ 0X30, 0X31, 0X32, 0X33, 0X34, 0X35, 0X36, 0X37,
+ 0X38, 0X39, 0X3A, 0X3B, 0X3C, 0X3D, 0X3E, 0X3F,
+ 0X40, 0X41, 0X42, 0X43, 0X44, 0X45, 0X46, 0X47,
+ 0X48, 0X49, 0X4A, 0X4B, 0X4C, 0X4D, 0X4E, 0X4F,
+ 0X50, 0X51, 0X52, 0X53, 0X54, 0X55, 0X56, 0X57,
+ 0X58, 0X59, 0X5A, 0X5B, 0X5C, 0X5D, 0X5E, 0X5F,
+ 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0X7B, 0X7C, 0X7D, 0X7E, 0X7F,
+ 0X80, 0X9A, 0X45, 0X41, 0X8E, 0X41, 0X8F, 0X80,
+ 0X45, 0X45, 0X45, 0X49, 0X49, 0X49, 0X8E, 0X8F,
+ 0X90, 0X92, 0X92, 0X4F, 0X99, 0X4F, 0X55, 0X55,
+ 0X59, 0X99, 0X9A, 0X9B, 0X9C, 0X9D, 0X9E, 0X9F,
+ 0X41, 0X49, 0X4F, 0X55, 0XA5, 0XA5, 0XA6, 0XA7,
+// 0X60, 0X61, 0X62, 0X63, 0X64, 0X65, 0X66, 0X67,
+// 0X68, 0X69, 0X6A, 0X6B, 0X6C, 0X6D, 0X6E, 0X6F,
+// 0X70, 0X71, 0X72, 0X73, 0X74, 0X75, 0X76, 0X77,
+// 0X78, 0X79, 0X7A, 0X7B, 0X7C, 0X7D, 0X7E, 0X7F,
+// 0X80, 0X81, 0X82, 0X83, 0X84, 0X85, 0X86, 0X87,
+// 0X88, 0X89, 0X8A, 0X8B, 0X8C, 0X8D, 0X8E, 0X8F,
+// 0X90, 0X91, 0X92, 0X93, 0X94, 0X95, 0X96, 0X97,
+// 0X98, 0X99, 0X9A, 0X9B, 0X9C, 0X9D, 0X9E, 0X9F,
+// 0XA0, 0XA1, 0XA2, 0XA3, 0XA4, 0XA5, 0XA6, 0XA7,
+ 0XA8, 0XA9, 0XAA, 0XAB, 0XAC, 0XAD, 0XAE, 0XAF,
+ 0XB0, 0XB1, 0XB2, 0XB3, 0XB4, 0XB5, 0XB6, 0XB7,
+ 0XB8, 0XB9, 0XBA, 0XBB, 0XBC, 0XBD, 0XBE, 0XBF,
+ 0XC0, 0XC1, 0XC2, 0XC3, 0XC4, 0XC5, 0XC6, 0XC7,
+ 0XC8, 0XC9, 0XCA, 0XCB, 0XCC, 0XCD, 0XCE, 0XCF,
+ 0XD0, 0XD1, 0XD2, 0XD3, 0XD4, 0XD5, 0XD6, 0XD7,
+ 0XD8, 0XD9, 0XDA, 0XDB, 0XDC, 0XDD, 0XDE, 0XDF,
+ 0XE0, 0XE1, 0XE2, 0XE3, 0XE4, 0XE5, 0XE6, 0XE7,
+ 0XE8, 0XE9, 0XEA, 0XEB, 0XEC, 0XED, 0XEE, 0XEF,
+ 0XF0, 0XF1, 0XF2, 0XF3, 0XF4, 0XF5, 0XF6, 0XF7,
+ 0XF8, 0XF9, 0XFA, 0XFB, 0XFC, 0XFD, 0XFE, 0XFF,
+ };
+
+/*
+ * It shows the diff between char offset and its case map
+ *
+
+UCHAR CaseMapUpdate_437[] =
+ {
+ 0X61, 0x41,
+ 0X62, 0x42,
+ 0X63, 0x43,
+ 0X64, 0x44,
+ 0X65, 0x45,
+ 0X66, 0x46,
+ 0X67, 0x47,
+ 0X68, 0x48,
+ 0X69, 0x49,
+ 0X6A, 0x4A,
+ 0X6B, 0x4B,
+ 0X6C, 0x4C,
+ 0X6D, 0x4D,
+ 0X6E, 0x4E,
+ 0X6F, 0x4F,
+ 0X70, 0x50,
+ 0X71, 0x51,
+ 0X72, 0x52,
+ 0X73, 0x53,
+ 0X74, 0x54,
+ 0X75, 0x55,
+ 0X76, 0x56,
+ 0X77, 0x57,
+ 0X78, 0x58,
+ 0X79, 0x59,
+ 0X7A, 0x5A,
+ 0X81, 0X9A,
+ 0X82, 0X45,
+ 0X83, 0X41,
+ 0X84, 0X8E,
+ 0X85, 0X41,
+ 0X86, 0X8F,
+ 0X87, 0X80,
+ 0X88, 0X45,
+ 0X89, 0X45,
+ 0X8A, 0X45,
+ 0X8B, 0X49,
+ 0X8C, 0X49,
+ 0X8D, 0X49,
+ 0X93, 0X4F,
+ 0X94, 0X99,
+ 0X95, 0X4F,
+ 0X96, 0X55,
+ 0X97, 0X55,
+ 0X98, 0X59,
+ 0XA0, 0X41,
+ 0XA1, 0X49,
+ 0XA2, 0X4F,
+ 0XA3, 0X55,
+ 0XA4, 0XA5,
+ 0x00, 0x00
+ };
+*/
+
+UCHAR CaseMapUpdate_850[] =
+ {
+ 0x82, 0x90,
+ 0x83, 0xB6,
+ 0x85, 0xB7,
+ 0x88, 0xD2,
+ 0x89, 0xD3,
+ 0x8A, 0xD4,
+ 0x8B, 0xD8,
+ 0x8C, 0xD7,
+ 0x8D, 0xDE,
+ 0x93, 0xE2,
+ 0x95, 0xE3,
+ 0x96, 0xEA,
+ 0x97, 0xEB,
+ 0x9B, 0x9D,
+ 0xA0, 0xB5,
+ 0xA1, 0xD6,
+ 0xA2, 0xE0,
+ 0xA3, 0xE9,
+ 0xC6, 0xC7,
+ 0xD0, 0xD1,
+ 0xD5, 0x49,
+ 0xE4, 0xE5,
+ 0xE7, 0xE8,
+ 0xEC, 0xED,
+ 0x00, 0x00
+ };
+
+UCHAR CaseMapUpdate_860[] =
+ {
+ 0x82, 0x90,
+ 0x83, 0x8F,
+ 0x85, 0x91,
+ 0x86, 0x86,
+ 0x88, 0x89,
+ 0x89, 0x89,
+ 0x8A, 0x92,
+ 0x8B, 0x8B,
+ 0x8C, 0x8C,
+ 0x8D, 0x98,
+ 0x91, 0x91,
+ 0x93, 0x8C,
+ 0x95, 0xA9,
+ 0x96, 0x96,
+ 0x97, 0x9D,
+ 0x98, 0x98,
+ 0xA0, 0x86,
+ 0xA1, 0x8B,
+ 0xA2, 0x9F,
+ 0xA3, 0x96,
+ 0x00, 0x00
+ };
+
+UCHAR CaseMapUpdate_863[] =
+ {
+ 0x80, 0x43,
+ 0x81, 0x55,
+ 0x84, 0x41,
+ 0x86, 0x86,
+ 0x87, 0x43,
+ 0x8D, 0x8D,
+ 0x8E, 0x41,
+ 0x90, 0x45,
+ 0x91, 0x45,
+ 0x92, 0x45,
+ 0x94, 0x45,
+ 0x95, 0x49,
+ 0x98, 0x98,
+ 0x99, 0x4F,
+ 0x9A, 0x55,
+ 0x9D, 0x55,
+ 0x9E, 0x55,
+ 0xA0, 0xA0,
+ 0xA1, 0xA1,
+ 0xA4, 0xA4,
+ 0xA8, 0x49,
+ 0x00, 0x00
+ };
+
+UCHAR CaseMapUpdate_865[] =
+ {
+ 0x81, 0x9A,
+ 0x82, 0x90,
+ 0x83, 0x41,
+ 0x84, 0x8E,
+ 0x85, 0x41,
+ 0x86, 0x8F,
+ 0x87, 0x80,
+ 0x88, 0x45,
+ 0x89, 0x45,
+ 0x8A, 0x45,
+ 0x8B, 0x49,
+ 0x8C, 0x49,
+ 0x8D, 0x49,
+ 0x91, 0x92,
+ 0x93, 0x4F,
+ 0x94, 0x99,
+ 0x95, 0x4F,
+ 0x96, 0x55,
+ 0x97, 0x55,
+ 0x98, 0x59,
+ 0x9B, 0x9D,
+ 0xA0, 0x41,
+ 0xA1, 0x49,
+ 0xA2, 0x4F,
+ 0xA3, 0x55,
+ 0xA4, 0xA5,
+ 0x00, 0x00
+ };
+
+UCHAR CaseMapUpdate_DBCS[] =
+ {
+ 0X81, 0X81,
+ 0X82, 0X82,
+ 0X83, 0X83,
+ 0X84, 0X84,
+ 0X85, 0X85,
+ 0X86, 0X86,
+ 0X87, 0X87,
+ 0X88, 0X88,
+ 0X89, 0X89,
+ 0X8A, 0X8A,
+ 0X8B, 0X8B,
+ 0X8C, 0X8C,
+ 0X8D, 0X8D,
+ 0X91, 0X91,
+ 0X93, 0X93,
+ 0X94, 0X94,
+ 0X95, 0X95,
+ 0X96, 0X96,
+ 0X97, 0X97,
+ 0X98, 0X98,
+ 0XA0, 0XA0,
+ 0XA1, 0XA1,
+ 0XA2, 0XA2,
+ 0XA3, 0XA3,
+ 0XA4, 0XA4,
+ 0x00, 0x00
+ };
+
+UCHAR CaseMapUpdate_862[] =
+ {
+ 0x81, 0x81,
+ 0x82, 0x82,
+ 0x83, 0x83,
+ 0x84, 0x84,
+ 0x85, 0x85,
+ 0x86, 0x86,
+ 0x87, 0x87,
+ 0x88, 0x88,
+ 0x89, 0x89,
+ 0x8A, 0x8A,
+ 0x8B, 0x8B,
+ 0x8C, 0x8C,
+ 0x8D, 0x8D,
+ 0x91, 0x91,
+ 0x93, 0x93,
+ 0x94, 0x94,
+ 0x95, 0x95,
+ 0x96, 0x96,
+ 0x97, 0x97,
+ 0x98, 0x98,
+ 0x00, 0x00
+ };
+
+UCHAR CaseMapUpdate_864[] =
+ {
+ 0x00, 0x00
+ };
+
+PUCHAR OD2_CASEMAP_TABLE[] =
+ {
+ NULL, /* CaseMapUpdate_437, */
+ CaseMapUpdate_850,
+ CaseMapUpdate_860,
+ CaseMapUpdate_863,
+ CaseMapUpdate_865,
+ CaseMapUpdate_DBCS,
+ CaseMapUpdate_DBCS,
+ CaseMapUpdate_DBCS,
+//#ifdef OS2SS_INCLUDE_HEBREW
+ CaseMapUpdate_862,
+//#endif
+//#ifdef OS2SS_INCLUDE_ARABIC
+ CaseMapUpdate_864,
+//#endif
+//#ifdef OS2SS_INCLUDE_PRCHINA
+ CaseMapUpdate_DBCS,
+//#endif
+ NULL
+ };
+
+UCHAR CaseMapUpdate_US[] =
+ {
+ 0x00, 0x00
+ };
+
+UCHAR CaseMapUpdate_Belg[] =
+ {
+ 0x82, 0x90,
+ 0x00, 0x00
+ };
+
+UCHAR CaseMapUpdate_Dutch[] =
+ {
+ 0x81, 0x55,
+ 0x84, 0x41,
+ 0x8E, 0x41,
+ 0x90, 0x45,
+ 0x94, 0x4F,
+ 0x98, 0x98,
+ 0x99, 0x4F,
+ 0x9A, 0x55,
+ 0x00, 0x00
+ };
+
+PUCHAR OD2_FIX_CASEMAP_TABLE[] =
+ {
+ NULL, /* CaseMapUpdate_US, */
+ CaseMapUpdate_Belg,
+ CaseMapUpdate_Dutch,
+ NULL
+ };
diff --git a/private/os2/client/os2dir.c b/private/os2/client/os2dir.c
new file mode 100644
index 000000000..0c80c5086
--- /dev/null
+++ b/private/os2/client/os2dir.c
@@ -0,0 +1,329 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2file.c
+
+Abstract:
+
+ This is a test OS/2 application to test the file system component of OS/2
+
+Author:
+
+ Therese Stowell (thereses) 24-Oct-1989
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define OS2_API32
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_TASKING
+#include <os2.h>
+
+
+int
+main(
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+ int i;
+ APIRET rc;
+ ULONG DiskNumber,
+ LogicalDrives;
+ char DirectoryName[50];
+ ULONG DirectoryNameLength=50;
+ HFILE FileHandle;
+ ULONG ActionTaken;
+
+ DbgPrint( "*** Entering OS/2 File System Test Application\n" );
+
+ DbgPrint( "argc: %ld\n", argc );
+ for (i=0; i<argc; i++) {
+ DbgPrint( "argv[ %ld ]: %s\n", i, argv[ i ] );
+ }
+
+ // set current disk to a:
+ // curdir is a:\
+
+ rc = DosSetDefaultDisk(1L);
+ if (rc) {
+ DbgPrint( "*** DosSetCurDisk returned an error code = %ld\n", rc );
+ return 1;
+ }
+ else
+ DbgPrint( "*** DosSetCurDisk(1) was successful\n");
+
+ // query current dir
+ // curdir is a:\
+
+ DirectoryNameLength=50;
+ rc = DosQueryCurrentDir(0,DirectoryName,&DirectoryNameLength);
+ if (rc) {
+ DbgPrint( "*** DosQCurDir %ld returned an error code = %ld\n", 0, rc );
+ return 1;
+ }
+ else {
+ if (DirectoryNameLength == 0) {
+ DbgPrint( "*** DosQCurDir %ld returned %s\n", 0, "a:\\" );
+ }
+ else {
+ DbgPrint( "*** DosQCurDir %ld returned %s\n", 0, DirectoryName );
+ DbgPrint( "*** NameLength = %ld\n", DirectoryNameLength);
+ return 1;
+ }
+ }
+
+
+ // make a:\dir1
+ // curdir is a:\
+
+ rc = DosCreateDir("a:\\dir1",0L);
+ if (rc) {
+ DbgPrint( "*** DosMkDir returned an error code = %ld\n", rc );
+ return 1;
+ }
+ else
+ DbgPrint( "*** DosMkDir(a:\\dir1) was successful\n");
+
+ // cd to a:\dir1
+ // curdir is a:\
+
+ rc = DosSetCurrentDir("a:\\dir1");
+ if (rc) {
+ DbgPrint( "*** DosChDir returned an error code = %ld\n", rc );
+ return 1;
+ }
+ else
+ DbgPrint( "*** DosChDir(a:\\dir1) was successful\n");
+
+ // query the current directory
+ // curdir is a:\dir1
+
+ DirectoryNameLength=50;
+ rc = DosQueryCurrentDir(0,DirectoryName,&DirectoryNameLength);
+ if (rc) {
+ DbgPrint( "*** DosQCurDir %ld returned an error code = %ld\n", 0, rc );
+ return 1;
+ }
+ else {
+ DbgPrint( "*** DosQCurDir %ld returned %s\n", 0, DirectoryName );
+ DbgPrint( "*** NameLength = %ld\n", DirectoryNameLength);
+ if (strcmp(DirectoryName,"dir1"))
+ return 1;
+ }
+
+ // make a:\dir1\dir2
+ // curdir is a:\dir1
+
+ rc = DosCreateDir("dir2",0L);
+ if (rc) {
+ DbgPrint( "*** DosMkDir returned an error code = %ld\n", rc );
+ return 1;
+ }
+ else
+ DbgPrint( "*** DosMkDir(a:\\dir2) was successful\n");
+
+ // cd to a:\dir1\dir2
+ // curdir is a:\
+
+ rc = DosSetCurrentDir("dir2");
+ if (rc) {
+ DbgPrint( "*** DosChDir returned an error code = %ld\n", rc );
+ return 1;
+ }
+ else
+ DbgPrint( "*** DosChDir(a:\\dir1\\dir2) was successful\n");
+
+ // query current dir
+ // curdir is a:\dir1\dir2
+
+ DirectoryNameLength=50;
+ rc = DosQueryCurrentDir(0,DirectoryName,&DirectoryNameLength);
+ if (rc) {
+ DbgPrint( "*** DosQCurDir %ld returned an error code = %ld\n", 0, rc );
+ return 1;
+ }
+ else {
+ DbgPrint( "*** DosQCurDir %ld returned %s\n", 0, DirectoryName );
+ DbgPrint( "*** NameLength = %ld\n", DirectoryNameLength);
+ if (strcmp(DirectoryName,"dir1\\dir2"))
+ return 1;
+ }
+
+ // create a:\dir1\dir2\file1
+ // curdir is a:\dir1\dir2
+
+ rc = DosOpen("..\\dir2\\.\\file1",
+ &FileHandle,
+ &ActionTaken,
+ 0L,
+ FILE_SYSTEM, // system attribute
+ OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
+ OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE,
+ 0L
+ );
+ if (rc) {
+ DbgPrint( "*** DosOpen a:\\dir1\\dir2\\file1 returned an error code = %ld\n", rc );
+ return 1;
+ }
+ else {
+ DbgPrint( "*** DosOpen a:\\dir1\\dir2\\file1 was successful\n");
+ }
+ DosClose(FileHandle);
+
+ // try to mkdir a:\dir1\dir2\file1. should fail
+ // curdir is a:\dir1\dir2
+
+ rc = DosCreateDir("file1",0L);
+ if (rc) {
+ DbgPrint( "*** DosMkDir returned an error code = %ld, as expected\n", rc );
+ }
+ else {
+ DbgPrint( "*** DosMkDir(file1) was successful. it should have failed.\n");
+ return 1;
+ }
+
+ // try to delete a:\dir1\dir2. should fail
+ // curdir is a:\dir1\dir2
+
+ rc = DosDeleteDir("..");
+ if (rc) {
+ DbgPrint( "*** DosRmDir returned an error code = %ld, as expected\n", rc );
+ }
+ else {
+ DbgPrint( "*** DosRmDir(dir2) was successful. it should have failed.\n");
+ return 1;
+ }
+
+ // delete a:\dir1\dir2\file1
+ // curdir is a:\dir1\dir2
+
+ rc = DosDelete("file1");
+ if (rc) {
+ DbgPrint( "*** DosDelete returned an error code = %ld\n", rc );
+ return 1;
+ }
+ else {
+ DbgPrint( "*** DosDelete(file1) was successful\n");
+ }
+
+ // query current disk
+ // curdir is a:\dir1\dir2
+ // current disk is a:
+
+ rc = DosQueryCurrentDisk(&DiskNumber,&LogicalDrives);
+ if (rc) {
+ DbgPrint( "*** DosQCurDisk returned an error code = %ld\n", rc );
+ return 1;
+ }
+ else {
+ DbgPrint( "*** DosQCurDisk returned DiskNumber = %ld\n", DiskNumber );
+ DbgPrint( "*** LogicalDrives = %lX\n", LogicalDrives);
+ }
+
+ // set current disk to c:
+ // curdir is a:\dir1\dir2
+
+ rc = DosSetDefaultDisk(3L);
+ if (rc) {
+ DbgPrint( "*** DosSetCurDisk returned an error code = %ld\n", rc );
+ return 1;
+ }
+ else {
+ DbgPrint( "*** DosSetCurDisk(1) was successful\n");
+ }
+
+ // set current dir to a:\dir1
+ // curdir is a:\dir1\dir2
+
+ rc = DosSetCurrentDir("a:..");
+ if (rc) {
+ DbgPrint( "*** DosChDir returned an error code = %ld\n", rc );
+ return 1;
+ }
+ else
+ DbgPrint( "*** DosChDir(a:..) was successful\n");
+
+ // query current dir
+ // curdir is a:\dir1
+
+ DirectoryNameLength=50;
+ rc = DosQueryCurrentDir(1,DirectoryName,&DirectoryNameLength);
+ if (rc) {
+ DbgPrint( "*** DosQCurDir a: returned an error code = %ld\n", rc );
+ return 1;
+ }
+ else {
+ DbgPrint( "*** DosQCurDir a: returned %s\n", DirectoryName );
+ DbgPrint( "*** NameLength = %ld\n", DirectoryNameLength);
+ if (strcmp(DirectoryName,"dir1"))
+ return 1;
+ }
+
+ // rmdir a:\dir1\dir2
+ // curdir is a:\dir1
+
+ rc = DosDeleteDir("a:dir2");
+ if (rc) {
+ DbgPrint( "*** DosRmDir returned an error code = %ld\n", rc );
+ return 1;
+ }
+ else
+ DbgPrint( "*** DosRmDir(a:\\dir1\\dir2) was successful\n");
+
+ // cd to a:\
+ // curdir is a:\dir1
+
+ rc = DosSetCurrentDir("A:\\");
+ if (rc) {
+ DbgPrint( "*** DosSetCurDir a:\\ returned an error code = %ld\n", rc );
+ return 1;
+ }
+ else {
+ DbgPrint( "*** DosSetCurDir a:\\ was successful\n");
+ }
+
+ // query current dir
+ // curdir is a:\
+
+ DirectoryNameLength=50;
+ rc = DosQueryCurrentDir(1,DirectoryName,&DirectoryNameLength);
+ if (rc) {
+ DbgPrint( "*** DosQCurDir %ld returned an error code = %ld\n", 0, rc );
+ return 1;
+ }
+ else {
+ if (DirectoryNameLength == 0) {
+ DbgPrint( "*** DosQCurDir %ld returned %s\n", 0, "a:\\" );
+ }
+ else {
+ DbgPrint( "*** DosQCurDir %ld returned %s\n", 0, DirectoryName );
+ DbgPrint( "*** NameLength = %ld\n", DirectoryNameLength);
+ return 1;
+ }
+ }
+
+ // rmdir a:\dir1
+ // curdir is a:\
+
+ rc = DosDeleteDir("a:\\dir1");
+ if (rc) {
+ DbgPrint( "*** DosRmDir returned an error code = %ld\n", rc );
+ return 1;
+ }
+ else
+ DbgPrint( "*** DosRmDir(a:\\dir1) was successful\n");
+
+ DbgPrint( "*** Exiting OS/2 Test Application\n" );
+ return( 0 );
+}
diff --git a/private/os2/client/os2dll.def b/private/os2/client/os2dll.def
new file mode 100644
index 000000000..8321277b8
--- /dev/null
+++ b/private/os2/client/os2dll.def
@@ -0,0 +1,177 @@
+LIBRARY OS2DLL
+
+DESCRIPTION 'OS/2 Emulation Subsystem - Client Stubs'
+
+EXPORTS
+ Od2Canonicalize
+ Od2EnableCtrlHandling
+ DosNullApiCall
+ DosSetMaxFH
+ DosSetVerify
+ DosErrClass
+ DosError
+ DosSetFileInfo
+ DosSetPathInfo
+ DosSetDefaultDisk
+ DosSetFHState
+ DosSetFSInfo
+ DosQueryPathInfo
+ DosQueryHType
+ DosQueryVerify
+ DosDeleteDir
+ DosScanEnv
+ DosSearchPath
+ DosSleep
+ DosGetDateTime
+ DosDevConfig
+ DosEnterCritSec
+ DosExitCritSec
+ DosExit
+ DosKillProcess
+ DosSetPriority
+ DosResumeThread
+ DosSuspendThread
+ DosCreatePipe
+ DosResetBuffer
+ DosSetCurrentDir
+ DosSetFilePtr
+ DosClose
+ DosCopy
+ DosDelete
+ DosDupHandle
+ DosEditName
+ DosSetFileLocks
+ DosFindClose
+ DosFindFirst
+ DosFindNext
+ DosFSAttach
+ DosCreateDir
+ DosMove
+ DosSetFileSize
+; DosFileIO
+ DosEnumAttribute
+ DosOpen
+ DosQueryCurrentDir
+ DosQueryCurrentDisk
+ DosQueryFHState
+ DosQueryFSAttach
+ DosQueryFSInfo
+ DosQueryFileInfo
+ DosWaitChild
+ DosRead
+ DosWrite
+ DosExecPgm
+; DosDevIOCtl
+ DosFSCtl
+ DosBeep
+; DosPhysicalDisk
+; DosSetCp
+ DosSetProcessCp
+ DosStopTimer
+ DosQueryCp
+ DosSetDateTime
+ DosExitList
+; DosAllocProtectedMem
+; DosAliasMem
+ DosAllocMem
+ DosAllocSharedMem
+ DosGetNamedSharedMem
+ DosGetSharedMem
+ DosGiveSharedMem
+ DosFreeMem
+ DosSetMem
+ DosQueryMem
+ DosCreateThread
+ DosGetThreadInfo
+; DosGetProcessInfo
+ DosLoadModule
+ DosQueryModuleHandle
+ DosQueryModuleName
+ DosQueryProcAddr
+ DosQueryProcType
+ DosFreeModule
+ DosQueryAppType
+ DosCreateEventSem
+ DosOpenEventSem
+ DosCloseEventSem
+ DosResetEventSem
+ DosPostEventSem
+ DosWaitEventSem
+ DosQueryEventSem
+ DosCreateMutexSem
+ DosOpenMutexSem
+ DosCloseMutexSem
+ DosRequestMutexSem
+ DosReleaseMutexSem
+ DosQueryMutexSem
+ DosCreateMuxWaitSem
+ DosOpenMuxWaitSem
+ DosCloseMuxWaitSem
+ DosWaitMuxWaitSem
+ DosAddMuxWaitSem
+ DosDeleteMuxWaitSem
+ DosQueryMuxWaitSem
+; DosSubSet
+; DosSubAlloc
+; DosSubFree
+; DosSubUnset
+ DosQuerySysInfo
+ DosWaitThread
+ DosAsyncTimer
+ DosStartTimer
+ DosGetResource
+ DosQueryResourceSize
+; DosFreeResource
+ DosQueryCtryInfo
+ DosQueryDBCSEnv
+ DosMapCase
+ DosQueryCollate
+ DosGetMessage
+ DosInsertMessage
+ DosPutMessage
+ DosQueryMessageCP
+ DosStartSession
+ DosSetSession
+ DosSelectSession
+ DosStopSession
+ DosCreateQueue
+ DosOpenQueue
+ DosCloseQueue
+ DosPurgeQueue
+ DosQueryQueue
+ DosPeekQueue
+ DosReadQueue
+ DosWriteQueue
+ DosEnterMustComplete
+ DosExitMustComplete
+ DosAcknowledgeSignalException
+ DosSetSignalExceptionFocus
+ DosSendSignalException
+ DosRaiseException
+ DosUnwindException
+ DosCreateNPipe
+ DosCallNPipe
+ DosConnectNPipe
+ DosDisConnectNPipe
+ DosPeekNPipe
+ DosTransactNPipe
+ DosWaitNPipe
+ DosQueryNPHState
+ DosSetNPHState
+ DosQueryNPipeInfo
+ DosQueryNPipeSemState
+ DosSetNPipeSem
+ Allocate16BHandle
+ Od2UpdateLocalInfoAtStart
+ MoveInfoSegintoTeb
+ EntryFlat constant
+ Od2LibPath constant
+ Od2Start16Stack constant
+ Od2Start16DS constant
+ Od2Debug constant
+ pSigHandlerRec constant
+ pVecHandlerRec constant
+ Od2Heap constant
+ Od2ExecPgmErrorText constant
+ Od2ExecPgmErrorTextLength constant
+ Od2Environment constant
diff --git a/private/os2/client/os2file.c b/private/os2/client/os2file.c
new file mode 100644
index 000000000..c2a61ca21
--- /dev/null
+++ b/private/os2/client/os2file.c
@@ -0,0 +1,214 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2file.c
+
+Abstract:
+
+ This is a test OS/2 application to test the file system component of OS/2
+
+Author:
+
+ Therese Stowell (thereses) 24-Oct-1989
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define OS2_API32
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_TASKING
+#include <os2.h>
+
+#define NEWMAXFH 25
+#define SECONDNEWMAXFH 27
+
+// create file
+// query handle type
+// set file size
+// set file pointer
+// write
+// read
+// open 21 handles
+// test sharing, open directory, open for write code
+// setmaxfh to 23
+// open 3 more handles
+// set verify
+// query verify
+// set fhstate
+// query fhstate
+// dup handle
+// close 1 handle
+// open 1 handle
+
+int
+main(
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+ int i;
+ APIRET rc;
+ HFILE FileHandle;
+ HFILE HandleArray[NEWMAXFH];
+ ULONG ActionTaken;
+ ULONG DiskNumber,
+ LogicalDrives;
+ char DirectoryName[30];
+ ULONG DirectoryNameLength=30;
+
+ DbgPrint( "*** Entering OS/2 File System Test Application\n" );
+
+ DbgPrint( "argc: %ld\n", argc );
+ for (i=0; i<argc; i++) {
+ DbgPrint( "argv[ %ld ]: %s\n", i, argv[ i ] );
+ }
+
+// create new file
+
+ rc = DosOpen("a:\\newfile3",
+ &FileHandle,
+ &ActionTaken,
+ 0L,
+ FILE_SYSTEM, // system attribute
+ FILE_CREATE_NEW_FILE,
+ OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE,
+ 0L
+ );
+ if (rc) {
+ DbgPrint( "*** DosOpen returned an error code = %ld\n", rc );
+ }
+ else {
+ DbgPrint( "*** DosOpen(a:\\newfile3) was successful\n");
+ DbgPrint( "*** file handle is %ld\n",FileHandle);
+ DbgPrint( "*** action taken is %ld\n",ActionTaken);
+ rc = DosClose(FileHandle);
+ if (rc) {
+ DbgPrint( "*** DosClose returned an error code = %ld\n", rc );
+ }
+ }
+// open existing file
+
+ rc = DosOpen("a:\\newfile3",
+ &FileHandle,
+ &ActionTaken,
+ 0L,
+ FILE_SYSTEM, // system attribute
+ FILE_OPEN_EXISTING_FILE,
+ OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE,
+ 0L
+ );
+ if (rc) {
+ DbgPrint( "*** DosOpen returned an error code = %ld\n", rc );
+ }
+ else {
+ DbgPrint( "*** DosOpen(a:\\newfile3) was successful\n");
+ DbgPrint( "*** file handle is %ld\n",FileHandle);
+ DbgPrint( "*** action taken is %ld\n",ActionTaken);
+ }
+
+// close handle past end of table
+
+ rc = DosClose((HFILE)21);
+ if (rc) {
+ DbgPrint( "*** DosClose returned an error code = %ld\n", rc );
+ }
+
+// close unopen handle
+
+ rc = DosClose((HFILE)1);
+ if (rc) {
+ DbgPrint( "*** DosClose returned an error code = %ld\n", rc );
+ }
+
+// set new max file handles
+
+// pass bad value
+
+ rc = DosSetMaxFH(10L);
+ if (!rc) {
+ DbgPrint( "*** DosSetMaxFH should have failed and did not\n");
+ }
+
+ rc = DosSetMaxFH(NEWMAXFH);
+ if (rc) {
+ DbgPrint( "*** DosSetMaxFH returned an error code = %ld\n", rc );
+ }
+
+ for (i=0; i<NEWMAXFH-1; i++) {
+ rc = DosOpen("a:\\newfile3",
+ &(HandleArray[i]),
+ &ActionTaken,
+ 0L,
+ FILE_SYSTEM, // system attribute
+ FILE_OPEN_EXISTING_FILE,
+ OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE,
+ 0L
+ );
+ if (rc) {
+ DbgPrint( "*** DosOpen returned an error code = %ld\n", rc );
+ }
+ else {
+ DbgPrint( "*** DosOpen returned handle %ld\n",HandleArray[i]);
+ }
+ }
+
+// shouldn't be any handles left
+
+ rc = DosOpen("a:\\newfile3",
+ &(HandleArray[i]),
+ &ActionTaken,
+ 0L,
+ FILE_SYSTEM, // system attribute
+ FILE_OPEN_EXISTING_FILE,
+ OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE,
+ 0L
+ );
+ if (rc==ERROR_TOO_MANY_OPEN_FILES) {
+ DbgPrint( "*** DosOpen returned correct error code\n");
+ }
+ else {
+ DbgPrint( "*** DosOpen returned wrong error code = %ld\n", rc );
+ DbgPrint( "*** it should have returned ERROR_TOO_MANY_OPEN_FILES\n");
+ }
+
+// close handle that should have been copied from original handle table
+
+ rc = DosClose(FileHandle);
+ if (rc) {
+ DbgPrint( "*** DosClose returned an error code = %ld\n", rc );
+ }
+
+// close last handle in table
+
+ rc = DosClose(HandleArray[NEWMAXFH-2]);
+ if (rc) {
+ DbgPrint( "*** DosClose returned an error code = %ld\n", rc );
+ }
+
+// set max fh again (2 more)
+
+ rc = DosSetMaxFH(SECONDNEWMAXFH);
+ if (rc) {
+ DbgPrint( "*** DosSetMaxFH returned an error code = %ld\n", rc );
+ }
+
+// make sure this handle got copied
+
+ rc = DosClose(HandleArray[0]);
+ if (rc) {
+ DbgPrint( "*** DosClose returned an error code = %ld\n", rc );
+ }
+
+ DbgPrint( "*** Exiting OS/2 Test Application\n" );
+ return( 0 );
+}
diff --git a/private/os2/client/os2misc.c b/private/os2/client/os2misc.c
new file mode 100644
index 000000000..0b830fddc
--- /dev/null
+++ b/private/os2/client/os2misc.c
@@ -0,0 +1,341 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2misc.c
+
+Abstract:
+
+ This is a test OS/2 application to test the miscellaneous API calls of OS/2
+ such as:
+
+ DosBeep
+ DosDevConfig
+ DosQuerySysInfo
+ DosError
+ DosErrClass
+ DosGetMessage
+ DosInsertMessage
+ DosPutMessage
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define OS2_API32
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_ERRORMSG
+#define INCL_OS2V20_DEVICE_SUPPORT
+#include <os2.h>
+
+PPIB Pib;
+PTIB Tib;
+
+VOID
+ExitRoutine(
+ ULONG ExitReason
+ );
+
+VOID
+TestThread(
+ IN PCH ThreadName
+ );
+
+VOID
+TestMiscellaneous( VOID );
+
+VOID
+TestError( VOID );
+
+VOID
+TestMessage( VOID );
+
+int
+main(
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+ APIRET rc;
+
+ DbgPrint( "*** Entering OS/2 Miscellaneous Test Application\n" );
+ DbgBreakPoint();
+
+ rc = DosGetThreadInfo( &Tib, &Pib );
+
+ rc = DosExitList( EXLST_ADD | 0x3000, ExitRoutine );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_ADD) failed - rc == %lX\n",
+ rc
+ );
+ }
+
+ DbgPrint( "*** Entering OS/2 Miscellaneous Test\n" );
+ TestMiscellaneous();
+ DbgPrint( "*** Exiting OS/2 Miscellaneous Test\n" );
+
+ DbgPrint( "*** Entering OS/2 Message Test\n" );
+ TestMessage();
+ DbgPrint( "*** Exiting OS/2 Message Test\n" );
+
+ DbgPrint( "*** Entering OS/2 Error Test\n" );
+ TestError();
+ DbgPrint( "*** Exiting OS/2 Error Test\n" );
+
+ DbgPrint( "*** Exiting OS/2 Miscellaneous Test Application\n" );
+ return( 0 );
+}
+
+VOID
+ExitRoutine(
+ ULONG ExitReason
+ )
+{
+ DbgPrint( "*** ExitRoutine( %lX ) called\n", ExitReason );
+ DosExitList( EXLST_EXIT, NULL );
+}
+
+VOID
+TestThread(
+ IN PCH ThreadName
+ )
+{
+ APIRET rc;
+ PPIB Pib;
+ PTIB Tib;
+
+ DbgPrint( "*** Entering OS/2 Thread %s\n", ThreadName );
+
+ rc = DosGetThreadInfo( &Tib, &Pib );
+
+ DbgPrint( "*** Leaveing OS/2 Thread %s\n", ThreadName );
+}
+
+ULONG SysInfoFieldIndexes[] = {
+ QSV_MAX_PATH_LENGTH,
+ QSV_MAX_TEXT_SESSIONS,
+ QSV_MAX_PM_SESSIONS,
+ QSV_MAX_VDM_SESSIONS,
+ QSV_BOOT_DRIVE,
+ QSV_DYN_PRI_VARIATION,
+ QSV_MAX_WAIT,
+ QSV_MIN_SLICE,
+ QSV_MAX_SLICE,
+ QSV_PAGE_SIZE,
+ QSV_VERSION_MAJOR,
+ QSV_VERSION_MINOR,
+ QSV_VERSION_REVISION,
+ 100,
+ -1
+};
+
+char *SysInfoFieldNames[] = {
+ "MAX_PATH_LENGTH",
+ "MAX_TEXT_SESSIONS",
+ "MAX_PM_SESSIONS",
+ "MAX_VDM_SESSIONS",
+ "BOOT_DRIVE",
+ "DYN_PRI_VARIATION",
+ "MAX_WAIT",
+ "MIN_SLICE",
+ "MAX_SLICE",
+ "PAGE_SIZE",
+ "VERSION_MAJOR",
+ "VERSION_MINOR",
+ "VERSION_REVISION",
+ "*** INVALID SYSINFO INDEX ***"
+};
+
+
+ULONG DevConfigFieldIndexes[] = {
+ DDC_NUMBER_PRINTERS,
+ DDC_NUMBER_RS232_PORTS,
+ DDC_NUMBER_DISKETTE_DRIVES,
+ DDC_MATH_COPROCESSOR,
+ DDC_PC_SUBMODEL_TYPE,
+ DDC_PC_MODEL_TYPE,
+ DDC_PRIMARY_DISPLAY_TYPE,
+ DDC_COPROCESSORTYPE,
+ 100,
+ -1,
+ -1
+};
+
+ULONG DevConfigFieldSize[] = {
+ sizeof( USHORT ),
+ sizeof( USHORT ),
+ sizeof( USHORT ),
+ sizeof( BYTE ),
+ sizeof( BYTE ),
+ sizeof( BYTE ),
+ sizeof( BYTE ),
+ sizeof( BYTE )
+};
+
+char *DevConfigFieldNames[] = {
+ "DDC_NUMBER_PRINTERS",
+ "DDC_NUMBER_RS232_PORTS",
+ "DDC_NUMBER_DISKETTE_DRIVES",
+ "DDC_MATH_COPROCESSOR",
+ "DDC_PC_SUBMODEL_TYPE",
+ "DDC_PC_MODEL_TYPE",
+ "DDC_PRIMARY_DISPLAY_TYPE",
+ "DDC_COPROCESSORTYPE",
+ "*** INVALID DEVCONFIG INDEX ***"
+};
+
+VOID
+TestMiscellaneous( VOID )
+{
+ ULONG i;
+ ULONG Value, Values[2];
+ APIRET rc;
+
+ for (i=0; i<1000; i += 1000) {
+ DbgPrint( "Calling DosBeep( %lX, %lX )\n", i, i );
+ rc = DosBeep( i, i );
+ if (rc != NO_ERROR) {
+ DbgPrint( "DosBeep( %lX, %lX ) failed - rc == %lX\n", i, i, rc );
+ }
+ }
+
+ for (i=0; SysInfoFieldIndexes[i] != -1; i+=2) {
+ Values[ 0 ] = 0;
+ Values[ 1 ] = 0;
+ rc = DosQuerySysInfo( SysInfoFieldIndexes[i],
+ SysInfoFieldIndexes[i+1],
+ (PBYTE)&Values,
+ 2*sizeof(ULONG)
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "DosQuerySysInfo( %s - %s ) failed - rc == %lX\n",
+ SysInfoFieldNames[i],
+ SysInfoFieldNames[i+1],
+ rc
+ );
+ }
+ else {
+ DbgPrint( "DosQuerySysInfo( %s - %s ) returned %lX, %lX\n",
+ SysInfoFieldNames[i],
+ SysInfoFieldNames[i+1],
+ Values[ 0 ],
+ Values[ 1 ]
+ );
+ }
+ }
+
+ for (i=0; DevConfigFieldIndexes[i] != -1; i++) {
+ Value = 0;
+ rc = DosDevConfig( (PVOID)&Value,
+ DevConfigFieldIndexes[i]
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "DosDevConfig( %s ) failed - rc == %lX\n",
+ DevConfigFieldNames[i],
+ rc
+ );
+ }
+ else {
+ DbgPrint( "DosDevConfig( %s ) returned %lX\n",
+ DevConfigFieldNames[i],
+ Value
+ );
+ }
+ }
+}
+
+
+VOID
+TestError( VOID )
+{
+ APIRET rc;
+ ULONG i;
+
+ for (i=0; i<5; i++) {
+ rc = DosError( i );
+ if (rc != NO_ERROR) {
+ DbgPrint( "DosError( %lX ) failed - rc == %lX\n", i, rc );
+ }
+ }
+}
+
+char MessageString[] =
+"This is a test message with 10 insert strings in a row, so lets see if the \
+message is wrapped correctly. %1 %2 %3 %4 %5 %6 %7 %8 %9 %0 %% %a\n";
+
+char *InsertStrings[] = {
+ "<Insert String 1>",
+ "<Insert String 2>",
+ "<Insert String 3>",
+ "<Insert String 4>",
+ "<Insert String 5>",
+ "<Insert String 6>",
+ "<Insert String 7>",
+ "<Insert String 8>",
+ "<Insert String 9>",
+ NULL
+};
+
+VOID
+TestMessage( VOID )
+{
+ APIRET rc;
+ ULONG i, MessageLength;
+ char MessageBuffer[ 1024 ];
+ PCH Variables[ 1 ];
+
+ Variables[ 0 ] = "(32 bit)";
+ rc = DosGetMessage( Variables,
+ 1,
+ MessageBuffer,
+ sizeof( MessageBuffer ),
+ 1047,
+ "OSO001.MSG",
+ &MessageLength
+ );
+ rc = DosPutMessage( (HFILE)1, MessageLength, MessageBuffer );
+
+ rc = DosGetMessage( NULL,
+ 0,
+ MessageBuffer,
+ sizeof( MessageBuffer ),
+ 1041,
+ "OSO001.MSG",
+ &MessageLength
+ );
+ rc = DosPutMessage( (HFILE)1, MessageLength, MessageBuffer );
+
+ for (i=0; i<=10; i++) {
+ rc = DosInsertMessage( InsertStrings,
+ i,
+ MessageString,
+ sizeof( MessageString ) - 1,
+ MessageBuffer,
+ sizeof( MessageBuffer ),
+ &MessageLength
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "DosInsertMessage( %lX ) failed - rc == %lX\n", i, rc );
+ }
+ else {
+ DbgPrint( ">DosPutMessage( %lX ) output:\n", i );
+ rc = DosPutMessage( (HFILE)1, MessageLength, MessageBuffer );
+ DbgPrint( "<End of DosPutMessage output\n" );
+ if (rc != NO_ERROR) {
+ DbgPrint( "DosPutMessage failed - rc == %lX\n", rc );
+ }
+ }
+ }
+}
diff --git a/private/os2/client/os2null.c b/private/os2/client/os2null.c
new file mode 100644
index 000000000..c64143108
--- /dev/null
+++ b/private/os2/client/os2null.c
@@ -0,0 +1,174 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2null.c
+
+Abstract:
+
+ This is a test OS/2 application to test the LPC overhead for calling
+ the OS/2 Emulation Subsystem
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define OS2_API32
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_QUEUES
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_TASKING
+#include <os2.h>
+
+APIRET
+Od2Canonicalize(
+ IN PSZ Path,
+ IN ULONG ExpectedType,
+ OUT PSTRING OutputString,
+ OUT PHANDLE OutputDirectory OPTIONAL,
+ OUT PULONG ParseFlags OPTIONAL,
+ OUT PULONG FileType OPTIONAL
+ );
+
+#define CANONICALIZE_FILE_DEV_OR_PIPE 0x00000000
+#define CANONICALIZE_FILE_OR_DEV 0x00000001
+#define CANONICALIZE_SHARED_MEMORY 0x00000002
+#define CANONICALIZE_SEMAPHORE 0x00000003
+#define CANONICALIZE_QUEUE 0x00000004
+
+
+PCHAR NullApiArguments[] = {
+ "String Number One",
+ "String Number Two",
+ "String Number Three",
+ NULL
+};
+
+#define EXP_SUCCESS (BOOLEAN)1
+#define EXP_FAILURE (BOOLEAN)0
+
+struct _TEST_PATHS {
+ char *Path;
+ ULONG ExpectedType;
+ BOOLEAN Success;
+} TestPaths[] = {
+ ".", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "\\sharemem\\a\\", CANONICALIZE_SHARED_MEMORY, EXP_FAILURE, // bad name
+ "\\sharemem\\a/", CANONICALIZE_SHARED_MEMORY, EXP_FAILURE, // bad name
+ "\\sharemem\\.", CANONICALIZE_SHARED_MEMORY, EXP_FAILURE, // bad name
+ "\\sharemem\\..", CANONICALIZE_SHARED_MEMORY, EXP_FAILURE, // bad name
+ "pmwin.dll", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "c:pmwin.dll", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "c:.\\pmwin.dll", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "\\pmwin.dll", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ ".\\pmwin.dll", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "DLL\\..\\pmwin.dll", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "C:\\nt\\dll\\pmwin.dll", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "c:..\\DLL\\pmwin.dll", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_FAILURE, // back up too far
+ "c:..\\..\\NT\\.\\DLL\\pmwin.dll", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_FAILURE, // back up too far
+ "c:\\DLL\\..\\..\\pmwin.dll", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_FAILURE, // back up too far
+ "c:\\DLL\\..\\pmwin<dll", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_FAILURE, // invalid char
+ "c:\\DLL\\..\\pmwin.dll.bak", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "c:\\DLL\\..\\.pmwin", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "c:\\\\DLL\\\\..\\\\pmwin", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "c:\\012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\
+0123456789\\12345", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "c:\\012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\
+0123456789\\123456", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_FAILURE, // too long
+ "\\\\mach\\shr\\a\\b\\c", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "\\\\\\mach\\shr\\a\\b\\c", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "\\\\\\mach\\..\\shr\\a\\b\\c", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_FAILURE, // back up too far
+ "con", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "c:kbd$", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "\\a\\b\\c\\clock$", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "C:\\a\\b\\c\\screen$", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "\\pipe\\a\\b\\c\\pipe.C", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "c:\\pipe\\a\\b\\c\\pipe.C", CANONICALIZE_FILE_OR_DEV, EXP_SUCCESS,
+ "\\pipe\\a\\b\\c\\pipe.C", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_SUCCESS,
+ "C:\\pipe\\a\\b\\c\\pipe.C", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_FAILURE, // pipe in path
+ "C:\\pipe\\?a\\b\\c\\pipe.C", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_FAILURE, // metas
+ "C:\\pipe\\a\\b\\c\\p?ipe.C", CANONICALIZE_FILE_DEV_OR_PIPE, EXP_FAILURE, // metas
+ "\\queUES\\a\\b\\c\\..\\..\\..\\que.*", CANONICALIZE_QUEUE, EXP_FAILURE, // metas
+ "\\queUES\\a\\b\\c\\..\\..\\..\\que.", CANONICALIZE_QUEUE, EXP_SUCCESS,
+ "\\queUES\\..\\a\\b\\c\\..\\..\\..\\que.", CANONICALIZE_QUEUE, EXP_FAILURE, // back up too far
+ "\\shaREmem\\..\\a\\b\\c\\.\\mem.c", CANONICALIZE_SHARED_MEMORY, EXP_FAILURE, // back up too far
+ "\\shaREmem\\a\\b\\c\\.\\mem.c", CANONICALIZE_SHARED_MEMORY, EXP_SUCCESS,
+ "\\sharemem/aaaaa\\.\\..\\xxx. ", CANONICALIZE_SHARED_MEMORY, EXP_SUCCESS,
+ "\\sharemem/aaaaa\\xxx", CANONICALIZE_SHARED_MEMORY, EXP_SUCCESS,
+ "\\sem32\\..\\a\\b\\c\\..\\sem.b", CANONICALIZE_SEMAPHORE, EXP_FAILURE, // back up too far
+ "\\sem32\\a\\b\\c\\..\\sem.b", CANONICALIZE_SEMAPHORE, EXP_SUCCESS,
+ "\\queues\\a\\b\\c\\..\\sem.b", CANONICALIZE_SEMAPHORE, EXP_FAILURE, // incorrect prefix
+ "/sem32/a", CANONICALIZE_SEMAPHORE, EXP_SUCCESS,
+ "/sem32/a|b", CANONICALIZE_SEMAPHORE, EXP_FAILURE, // invalid char
+ NULL, 0, 0
+};
+
+int
+main(
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+ APIRET rc;
+ PSZ Path;
+ ULONG i, ParseFlags, FileType;
+ STRING OutputString;
+ HFILE ReadHandle, WriteHandle;
+
+ DbgPrint( "*** Entering OS/2 Null Application\n" );
+
+ i = 0;
+ while( Path = TestPaths[ i ].Path ) {
+ FileType = -1;
+ rc = Od2Canonicalize( Path,
+ TestPaths[ i ].ExpectedType,
+ &OutputString,
+ NULL,
+ &ParseFlags,
+ &FileType
+ );
+
+ if (rc != NO_ERROR) {
+ if (TestPaths[ i ].Success) {
+ DbgPrint("FAILURE: Od2Canonicalize( %s ) failed - rc = %ld\n",
+ Path, rc
+ );
+ }
+ else {
+ DbgPrint("NT_SUCCESS: Od2Canonicalize( %s ) failed - rc = %ld\n",
+ Path, rc
+ );
+ }
+ }
+ else {
+ if (TestPaths[ i ].Success) {
+ DbgPrint( "NT_SUCCESS: Od2Canonicalize( %s ) success", Path );
+ }
+ else {
+ DbgPrint( "FAILURE: Od2Canonicalize( %s ) success", Path );
+ }
+ if (FileType != -1) {
+ DbgPrint( " - type = %lX", FileType );
+ }
+
+ DbgPrint( "\n String = %Z\n\n", &OutputString );
+ }
+
+ i++;
+ }
+
+ DbgPrint( "*** Exiting OS/2 Null Application\n" );
+ return( 0 );
+}
diff --git a/private/os2/client/os2que.c b/private/os2/client/os2que.c
new file mode 100644
index 000000000..d5f6d8793
--- /dev/null
+++ b/private/os2/client/os2que.c
@@ -0,0 +1,631 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2que.c
+
+Abstract:
+
+ This is a test OS/2 application to test the Queue component of OS/2
+
+Author:
+
+ Mark Lucovsky (markl) 10-Jul-1990
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define OS2_API32
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_QUEUES
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_SEMAPHORES
+#include <os2.h>
+
+BOOLEAN
+Queue1()
+
+{
+ APIRET rc;
+ HQUEUE Queue1,Queue2,Queue3;
+ PID Owner;
+ PNT_TIB NtTib;
+ PPIB Pib;
+
+ DbgPrint( "*** Queue1 ***\n" );
+
+
+ rc = DosGetThreadInfo(&NtTib,&Pib);
+ ASSERT(rc == NO_ERROR);
+
+ //
+ // Good create
+ //
+
+ DbgPrint( "(1)\n" );
+ rc = DosCreateQueue(&Queue1,QUE_FIFO,"\\queues\\testq");
+ ASSERT(rc == NO_ERROR);
+
+ //
+ // Create Duplicate
+ //
+
+ DbgPrint( "(2)\n" );
+ rc = DosCreateQueue(&Queue2,QUE_FIFO,"\\queues\\testq");
+ ASSERT(rc == ERROR_QUE_DUPLICATE);
+
+ //
+ // invalid prefix
+ //
+
+ DbgPrint( "(3)\n" );
+ rc = DosCreateQueue(&Queue2,QUE_FIFO,"\\xqueues\\testq");
+ ASSERT(rc == ERROR_QUE_INVALID_NAME);
+
+ //
+ // invalid priority
+ //
+
+ DbgPrint( "(4)\n" );
+ rc = DosCreateQueue(&Queue2,4,"\\queues\\xue");
+ ASSERT(rc == ERROR_QUE_INVALID_PRIORITY);
+
+ //
+ // bad address for queue handle
+ //
+
+ DbgPrint( "(5)\n" );
+ rc = DosCreateQueue((PHQUEUE)1,QUE_FIFO,"\\queues\\xue");
+ ASSERT(rc == ERROR_INVALID_PARAMETER);
+
+ //
+ // bad address for queue name
+ //
+
+ DbgPrint( "(6)\n" );
+ rc = DosCreateQueue(&Queue2,QUE_FIFO,(PSZ) 1);
+ ASSERT(rc == ERROR_QUE_INVALID_NAME);
+
+ //
+ // open of previous good queue
+ //
+
+ DbgPrint( "(7)\n" );
+ rc = DosOpenQueue(&Owner,&Queue3,"\\queues\\testq");
+ ASSERT(rc == NO_ERROR);
+ ASSERT(Queue1 == Queue3);
+ ASSERT(Owner == Pib->ProcessId);
+
+ //
+ // open of non-existent queue
+ //
+
+ DbgPrint( "(8)\n" );
+ rc = DosOpenQueue(&Owner,&Queue2,"\\queues\\xx");
+ ASSERT(rc == ERROR_QUE_NAME_NOT_EXIST);
+
+ //
+ // re-open of good queue
+ //
+
+ DbgPrint( "(9)\n" );
+ Queue3 = NULL;
+ Owner = 0;
+ rc = DosOpenQueue(&Owner,&Queue3,"\\queues\\testq");
+ ASSERT(rc == NO_ERROR);
+ ASSERT(Queue1 == Queue3);
+ ASSERT(Owner == Pib->ProcessId);
+
+ //
+ // Good close. Should do this 3 times...
+ //
+
+ DbgPrint( "(10)\n" );
+ rc = DosCloseQueue(Queue3);
+ ASSERT(rc == NO_ERROR);
+ DbgPrint( "(10a)\n" );
+ rc = DosOpenQueue(&Owner,&Queue2,"\\queues\\testq");
+ ASSERT(rc == ERROR_QUE_NAME_NOT_EXIST);
+
+ //
+ // Close bad handle
+ //
+
+ rc = DosCloseQueue((HQUEUE)0x10000);
+ ASSERT(rc == ERROR_QUE_INVALID_HANDLE);
+
+ DbgPrint( "*** Exiting Queue1 ***\n" );
+ return( TRUE );
+}
+
+BOOLEAN
+Queue2()
+
+{
+ APIRET rc;
+ HQUEUE Queue1,Queue2;
+ PID Owner;
+ ULONG QueryCount;
+ PNT_TIB NtTib;
+ PPIB Pib;
+
+ DbgPrint( "*** Queue2 ***\n" );
+
+
+ rc = DosGetThreadInfo(&NtTib,&Pib);
+ ASSERT(rc == NO_ERROR);
+
+ //
+ // Good create
+ //
+
+ DbgPrint( "(1)\n" );
+ rc = DosCreateQueue(&Queue1,QUE_FIFO,"\\queues\\testq");
+ ASSERT(rc == NO_ERROR);
+
+
+ //
+ // Good Write
+ //
+
+ DbgPrint( "(2)\n" );
+ rc = DosWriteQueue(Queue1,1,0x00001111,(PVOID)0x11110001,0x0);
+ ASSERT(rc == NO_ERROR);
+
+ //
+ // Query should be 1
+ //
+
+ DbgPrint( "(3)\n" );
+ rc = DosQueryQueue(Queue1,&QueryCount);
+ ASSERT(rc == NO_ERROR);
+ ASSERT(QueryCount == 1);
+
+ //
+ // Good Write
+ //
+
+ DbgPrint( "(4)\n" );
+ rc = DosWriteQueue(Queue1,1,0x00002222,(PVOID)0x22220001,0x0);
+ ASSERT(rc == NO_ERROR);
+ rc = DosWriteQueue(Queue1,1,0x00003333,(PVOID)0x33330001,0x0);
+ ASSERT(rc == NO_ERROR);
+
+ //
+ // Query should be 3
+ //
+
+ DbgPrint( "(5)\n" );
+ rc = DosQueryQueue(Queue1,&QueryCount);
+ ASSERT(rc == NO_ERROR);
+ ASSERT(QueryCount == 3);
+
+ //
+ // Purge and then check query. Should be 0
+ //
+
+ DbgPrint( "(6)\n" );
+ rc = DosPurgeQueue(Queue1);
+ ASSERT(rc == NO_ERROR);
+ rc = DosQueryQueue(Queue1,&QueryCount);
+ ASSERT(rc == NO_ERROR);
+ ASSERT(QueryCount == 0);
+ rc = DosCloseQueue(Queue1);
+ ASSERT(rc == NO_ERROR);
+
+ DbgPrint( "*** Exiting Queue2 ***\n" );
+ return( TRUE );
+}
+
+BOOLEAN
+Queue3()
+
+{
+ APIRET rc;
+ HQUEUE Queue1;
+ ULONG QueryCount;
+ REQUESTDATA RequestInfo;
+ ULONG DataLength;
+ ULONG Data;
+ ULONG ReadPosition;
+ BOOL32 NoWait;
+ BYTE ElementPriority;
+
+ DbgPrint( "*** Queue3 ***\n" );
+
+
+ //
+ // Good create
+ //
+
+ DbgPrint( "(1)\n" );
+ rc = DosCreateQueue(&Queue1,QUE_FIFO,"\\queues\\testq");
+ ASSERT(rc == NO_ERROR);
+
+
+ //
+ // Good Write
+ //
+
+ DbgPrint( "(2)\n" );
+ rc = DosWriteQueue(Queue1,1,0x00001111,(PVOID)0x11110001,0x3);
+ ASSERT(rc == NO_ERROR);
+
+ //
+ // Good Read
+ //
+
+ DbgPrint( "(3)\n" );
+ rc = DosReadQueue(
+ Queue1,
+ &RequestInfo,
+ &DataLength,
+ &Data,
+ 0,
+ DCWW_NOWAIT,
+ &ElementPriority,
+ NULL
+ );
+ ASSERT( rc == NO_ERROR );
+ ASSERT( DataLength == 0x00001111);
+ ASSERT( Data == 0x11110001);
+ ASSERT( ElementPriority == 0x0);
+ DbgPrint( "(3a)\n" );
+ rc = DosQueryQueue(Queue1,&QueryCount);
+ ASSERT(rc == NO_ERROR);
+ ASSERT(QueryCount == 0);
+
+ //
+ // Good Write
+ //
+
+ DbgPrint( "(4)\n" );
+ rc = DosWriteQueue(Queue1,1,0x00001111,(PVOID)0x11110001,0x3);
+ ASSERT(rc == NO_ERROR);
+ rc = DosWriteQueue(Queue1,1,0x00002222,(PVOID)0x22220001,0x4);
+ ASSERT(rc == NO_ERROR);
+ rc = DosWriteQueue(Queue1,1,0x00003333,(PVOID)0x33330001,0x5);
+ ASSERT(rc == NO_ERROR);
+
+ //
+ // Good Read using element number
+ //
+
+ DbgPrint( "(4a)\n" );
+ rc = DosReadQueue(
+ Queue1,
+ &RequestInfo,
+ &DataLength,
+ &Data,
+ 3,
+ DCWW_NOWAIT,
+ &ElementPriority,
+ NULL
+ );
+ ASSERT( rc == NO_ERROR );
+ ASSERT( DataLength == 0x00002222);
+ ASSERT( Data == 0x22220001);
+ ASSERT( ElementPriority == 0x0);
+ DbgPrint( "(4b)\n" );
+ rc = DosReadQueue(
+ Queue1,
+ &RequestInfo,
+ &DataLength,
+ &Data,
+ 4,
+ DCWW_NOWAIT,
+ &ElementPriority,
+ NULL
+ );
+ ASSERT( rc == NO_ERROR );
+ ASSERT( DataLength == 0x00003333);
+ ASSERT( Data == 0x33330001);
+ ASSERT( ElementPriority == 0x0);
+ DbgPrint( "(4c)\n" );
+ rc = DosReadQueue(
+ Queue1,
+ &RequestInfo,
+ &DataLength,
+ &Data,
+ 2,
+ DCWW_NOWAIT,
+ &ElementPriority,
+ NULL
+ );
+ ASSERT( rc == NO_ERROR );
+ ASSERT( DataLength == 0x00001111);
+ ASSERT( Data == 0x11110001);
+ ASSERT( ElementPriority == 0x0);
+
+ rc = DosCloseQueue(Queue1);
+ ASSERT( rc == NO_ERROR);
+
+ DbgPrint( "*** Exiting Queue3 ***\n" );
+ return( TRUE );
+}
+
+VOID
+Queue4Reader( IN ULONG QueueHandle )
+{
+ APIRET rc;
+ REQUESTDATA RequestInfo;
+ ULONG DataLength;
+ ULONG Data;
+ BYTE ElementPriority;
+ PNT_TIB NtTib;
+ POS2_TIB Tib;
+ PPIB Pib;
+
+ rc = DosGetThreadInfo(&NtTib,&Pib);
+ ASSERT(rc == NO_ERROR);
+ Tib = (POS2_TIB)NtTib->SubSystemTib;
+
+ DbgPrint( "++Queue4Reader++ %d\n",Tib->ThreadId );
+ rc = DosReadQueue(
+ (HQUEUE) QueueHandle,
+ &RequestInfo,
+ &DataLength,
+ &Data,
+ 0,
+ DCWW_WAIT,
+ &ElementPriority,
+ NULL
+ );
+ ASSERT( rc == NO_ERROR );
+ ASSERT( DataLength == 0x00001111);
+ ASSERT( Data == (ULONG)(Tib->ThreadId));
+ ASSERT( ElementPriority == 0x0);
+ DbgPrint( "--Queue4Reader-- %d\n",Tib->ThreadId );
+ DosExit( EXIT_THREAD, rc );
+}
+
+BOOLEAN
+Queue4()
+
+{
+ APIRET rc;
+ HQUEUE Queue1;
+ ULONG QueryCount;
+ REQUESTDATA RequestInfo;
+ ULONG DataLength;
+ ULONG Data;
+ ULONG ReadPosition;
+ BOOL32 NoWait;
+ BYTE ElementPriority;
+ TID Tid1,Tid2;
+
+ DbgPrint( "*** Queue4 ***\n" );
+
+
+ //
+ // Good create
+ //
+
+ DbgPrint( "(1)\n" );
+ rc = DosCreateQueue(&Queue1,QUE_FIFO,"\\queues\\testq");
+ ASSERT(rc == NO_ERROR);
+
+ rc = DosQueryQueue(Queue1,&QueryCount);
+ ASSERT(rc == NO_ERROR);
+ ASSERT(QueryCount == 0);
+
+ rc = DosCreateThread(&Tid1,Queue4Reader,(ULONG)Queue1,FALSE,1);
+ ASSERT( rc == NO_ERROR );
+
+ DosSleep(1000);
+
+ rc = DosQueryQueue(Queue1,&QueryCount);
+ ASSERT(rc == NO_ERROR);
+ ASSERT(QueryCount == 0);
+NtPartyByNumber(6,1);
+ //
+ // Good Write
+ //
+
+ DbgPrint( "(3)\n" );
+ rc = DosWriteQueue(Queue1,1,0x00001111,(PVOID)Tid1,0x3);
+ ASSERT(rc == NO_ERROR);
+ DbgPrint( "(3a)\n" );
+ rc = DosWaitThread(&Tid1,DCWW_WAIT);
+ ASSERT( rc == NO_ERROR || rc == ERROR_INVALID_THREADID );
+ DbgPrint( "(3b)\n" );
+
+ rc = DosQueryQueue(Queue1,&QueryCount);
+ ASSERT(rc == NO_ERROR);
+ ASSERT(QueryCount == 0);
+
+ rc = DosCreateThread(&Tid1,Queue4Reader,(ULONG)Queue1,FALSE,1);
+ ASSERT( rc == NO_ERROR );
+ rc = DosCreateThread(&Tid2,Queue4Reader,(ULONG)Queue1,FALSE,1);
+ ASSERT( rc == NO_ERROR );
+
+ DosSleep(1000);
+
+ //
+ // Good Write
+ //
+
+ rc = DosQueryQueue(Queue1,&QueryCount);
+ ASSERT(rc == NO_ERROR);
+ ASSERT(QueryCount == 0);
+
+ DbgPrint( "(4)\n" );
+ rc = DosWriteQueue(Queue1,1,0x00001111,(PVOID)Tid1,0x3);
+ ASSERT(rc == NO_ERROR);
+ rc = DosWriteQueue(Queue1,2,0x00001111,(PVOID)Tid2,0x3);
+ ASSERT(rc == NO_ERROR);
+ DbgPrint( "(4a)\n" );
+ rc = DosWaitThread(&Tid1,DCWW_WAIT);
+ ASSERT( rc == NO_ERROR || rc == ERROR_INVALID_THREADID );
+ DbgPrint( "(4b)\n" );
+ rc = DosWaitThread(&Tid2,DCWW_WAIT);
+ ASSERT( rc == NO_ERROR || rc == ERROR_INVALID_THREADID );
+
+
+
+ rc = DosCloseQueue(Queue1);
+ ASSERT( rc == NO_ERROR);
+
+ DbgPrint( "*** Exiting Queue4 ***\n" );
+ return( TRUE );
+}
+
+
+VOID
+Queue5Writer( IN ULONG QueueHandle )
+{
+ APIRET rc;
+ REQUESTDATA RequestInfo;
+ ULONG DataLength;
+ ULONG Data;
+ BYTE ElementPriority;
+ PNT_TIB NtTib;
+ PPIB Pib;
+ POS2_TIB Tib;
+
+
+ rc = DosGetThreadInfo(&NtTib,&Pib);
+ ASSERT(rc == NO_ERROR);
+ Tib = (POS2_TIB)NtTib->SubSystemTib;
+
+ DbgPrint( "++Queue5Writer++ %d\n",Tib->ThreadId );
+ DosSleep(1000);
+ rc = DosWriteQueue((HQUEUE)QueueHandle,1,0x00001111,
+ (PVOID)Tib->ThreadId,0x3);
+ ASSERT(rc == NO_ERROR);
+ DbgPrint( "--Queue5Writer-- %d\n",Tib->ThreadId );
+ DosExit( EXIT_THREAD, rc );
+}
+
+BOOLEAN
+Queue5()
+
+{
+ APIRET rc;
+ HQUEUE Queue1;
+ HSEM Sem;
+ ULONG QueryCount;
+ REQUESTDATA RequestInfo;
+ ULONG DataLength;
+ ULONG Data;
+ ULONG ReadPosition;
+ BOOL32 NoWait;
+ BYTE ElementPriority;
+ TID Tid1,Tid2;
+
+ DbgPrint( "*** Queue5 ***\n" );
+
+
+ //
+ // Good create
+ //
+
+ DbgPrint( "(1)\n" );
+ rc = DosCreateQueue(&Queue1,QUE_FIFO,"\\queues\\testq");
+ ASSERT(rc == NO_ERROR);
+ DbgPrint( "(1a)\n" );
+ rc = DosCreateEventSem(NULL,&Sem,DC_SEM_SHARED,FALSE);
+ ASSERT(rc == NO_ERROR);
+
+ //
+ // Create a writer thread
+ //
+
+ DbgPrint( "(1b)\n" );
+ rc = DosCreateThread(&Tid1,Queue5Writer,(ULONG)Queue1,FALSE,1);
+ ASSERT( rc == NO_ERROR );
+
+ //
+ // Issue a no wait read with a semaphore handle
+ //
+
+ DbgPrint( "(1c)\n" );
+ rc = DosReadQueue(
+ Queue1,
+ &RequestInfo,
+ &DataLength,
+ &Data,
+ 0,
+ DCWW_NOWAIT,
+ &ElementPriority,
+ Sem
+ );
+ ASSERT( rc == ERROR_QUE_EMPTY );
+
+ //
+ // Wait on the semaphore and then read again
+ //
+
+ DbgPrint( "(1d)\n" );
+ rc = DosWaitEventSem(Sem,SEM_INDEFINITE_WAIT);
+ ASSERT(rc == NO_ERROR);
+
+ DbgPrint( "(1e)\n" );
+ rc = DosReadQueue(
+ Queue1,
+ &RequestInfo,
+ &DataLength,
+ &Data,
+ 0,
+ DCWW_WAIT,
+ &ElementPriority,
+ NULL
+ );
+ ASSERT(rc == NO_ERROR);
+ ASSERT( DataLength == 0x00001111);
+ ASSERT( Data == (ULONG)Tid1);
+ ASSERT( ElementPriority == 0x0);
+
+ DbgPrint( "(1f)\n" );
+ rc = DosWaitThread(&Tid1,DCWW_WAIT);
+ ASSERT( rc == NO_ERROR || rc == ERROR_INVALID_THREADID );
+
+ DbgPrint( "*** Exiting Queue5 ***\n" );
+ return( TRUE );
+}
+
+
+
+
+
+
+int
+main(
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+
+ BOOLEAN ret;
+
+ DbgPrint( "*** Entering OS/2 Queue Test Application\n" );
+#ifndef MIPS
+NtPartyByNumber(6,8);
+
+ ret = Queue1();
+ ASSERT(ret);
+
+ ret = Queue2();
+ ASSERT(ret);
+
+ ret = Queue3();
+ ASSERT(ret);
+
+ ret = Queue4();
+ ASSERT(ret);
+
+ ret = Queue5();
+ ASSERT(ret);
+#endif // MIPS
+ DbgPrint( "*** Exiting OS/2 Queues Test Application\n" );
+ return( 0 );
+}
diff --git a/private/os2/client/os2sem.c b/private/os2/client/os2sem.c
new file mode 100644
index 000000000..14389d76b
--- /dev/null
+++ b/private/os2/client/os2sem.c
@@ -0,0 +1,1043 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2sem.c
+
+Abstract:
+
+ This is a test OS/2 application to test the Semaphore component of OS/2
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define OS2_API32
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_SEMAPHORES
+#include <os2.h>
+
+PPIB Pib;
+PNT_TIB NtTib;
+
+VOID
+TestMisc( VOID );
+
+VOID
+TestProcess( VOID );
+
+VOID
+TestHandles( VOID );
+
+VOID
+TestEvent( VOID );
+
+VOID
+TestMutex( VOID );
+
+VOID
+TestMuxWait( VOID );
+
+VOID
+ExitRoutine(
+ ULONG ExitReason
+ );
+
+VOID
+TestThread(
+ IN PCH ThreadName
+ );
+
+int
+main(
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+ APIRET rc;
+
+ DbgPrint( "*** Entering OS/2 Semaphore Test Application\n" );
+
+ rc = DosGetThreadInfo( &NtTib, &Pib );
+
+ rc = DosExitList( EXLST_ADD | 0x3000, ExitRoutine );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_ADD) failed - rc == %ld\n",
+ rc
+ );
+ }
+
+ TestMisc();
+
+ TestProcess();
+
+#if 1
+ DbgPrint( "*** Entering OS/2 Handle Semaphore Test\n" );
+ TestHandles();
+ DbgPrint( "*** Exiting OS/2 Handle Semaphore Test\n" );
+#endif
+
+ DbgPrint( "*** Entering OS/2 Event Semaphore Test\n" );
+ TestEvent();
+ DbgPrint( "*** Exiting OS/2 Event Semaphore Test\n" );
+
+ DbgPrint( "*** Entering OS/2 Mutex Semaphore Test\n" );
+ TestMutex();
+ DbgPrint( "*** Exiting OS/2 Mutex Semaphore Test\n" );
+
+ DbgPrint( "*** Entering OS/2 MuxWait Semaphore Test\n" );
+ TestMuxWait();
+ DbgPrint( "*** Exiting OS/2 MuxWait Semaphore Test\n" );
+
+ DbgPrint( "*** Exiting OS/2 Semaphore Test Application\n" );
+ return( 0 );
+}
+
+VOID
+ExitRoutine(
+ ULONG ExitReason
+ )
+{
+ DbgPrint( "*** ExitRoutine( %lX ) called\n", ExitReason );
+ DosExitList( EXLST_EXIT, NULL );
+}
+
+VOID
+TestThread(
+ IN PCH ThreadName
+ )
+{
+ APIRET rc;
+ PPIB Pib;
+ PNT_TIB NtTib;
+
+ DbgPrint( "*** Entering OS/2 Thread %s\n", ThreadName );
+
+ rc = DosGetThreadInfo( &NtTib, &Pib );
+
+ DbgPrint( "*** Leaveing OS/2 Thread %s\n", ThreadName );
+}
+
+
+VOID
+CloneTest( PPID ChildPid );
+
+BOOLEAN
+IsClonedTest( VOID );
+
+VOID
+CloneTest(
+ PPID ChildPid
+ )
+{
+ PPIB Pib;
+ PNT_TIB NtTib;
+ APIRET rc;
+ PCH src, Variables, ImageFileName, CommandLine;
+ CHAR ErrorBuffer[ 32 ];
+ RESULTCODES ResultCodes;
+
+ rc = DosGetThreadInfo( &NtTib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ return;
+ }
+
+ src = Pib->Environment;
+ Variables = src;
+ while (*src) {
+ while (*src) {
+ src++;
+ }
+ src++;
+ }
+ src++;
+ ImageFileName = src;
+ CommandLine = "CLONETEST\000";
+ rc = DosExecPgm( ErrorBuffer,
+ sizeof( ErrorBuffer ),
+ ChildPid == NULL ? EXEC_SYNC : EXEC_ASYNC,
+ CommandLine,
+ Variables,
+ &ResultCodes,
+ ImageFileName
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExecPgm( %s, %s failed - rc == %ld\n",
+ ImageFileName, CommandLine, rc
+ );
+ }
+ else {
+ if (ChildPid != NULL) {
+ *ChildPid = (PID)ResultCodes.ExitReason;
+ }
+ }
+}
+
+
+BOOLEAN
+IsClonedTest( VOID )
+{
+ PPIB Pib;
+ PNT_TIB NtTib;
+ APIRET rc;
+
+ rc = DosGetThreadInfo( &NtTib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ return( FALSE );
+ }
+
+ if (!strcmp( Pib->CommandLine, "CLONETEST" )) {
+ return( TRUE );
+ }
+ else {
+ return( FALSE );
+ }
+}
+
+
+#define SEM_SHIFT 16
+#define MAX_SEM_REC 64
+
+VOID
+TestMisc( VOID )
+{
+ APIRET rc;
+ SEMRECORD EventHandles[ 64 ];
+ SEMRECORD MutexHandles[ 64 ];
+ SEMRECORD srMtxPrivate[ 64 ];
+ SEMRECORD srMtxShared[ 64 ];
+ HMUX MuxWaitHandle;
+ ULONG i, PostCount, UserValue;
+
+ for (i=0; i<64; i++) {
+ rc = DosCreateMutexSem( NULL,
+ (PHMTX)&MutexHandles[ i ].hsemCur,
+ NULL,
+ TRUE
+ );
+ MutexHandles[ i ].ulUser = 0;
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateMutexSem( %d ) failed - rc == %d\n",
+ i, rc
+ );
+ return;
+ }
+ else {
+ DbgPrint( "MutexSem[ %d ] == %X\n", i, MutexHandles[ i ].hsemCur );
+ }
+ }
+
+ DbgBreakPoint();
+ rc = DosCreateMuxWaitSem( NULL,
+ &MuxWaitHandle,
+ 64,
+ (PSEMRECORD)MutexHandles,
+ DCMW_WAIT_ALL
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateMuxWaitSem failed - rc == %d\n", rc );
+ }
+ else {
+ rc = DosWaitMuxWaitSem( MuxWaitHandle, SEM_INDEFINITE_WAIT, &UserValue );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitMuxWaitSem failed - rc == %d\n", rc );
+ }
+ rc = DosCloseMuxWaitSem( MuxWaitHandle );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCloseMuxWaitSem failed - rc == %d\n", rc );
+ }
+ }
+
+ for (i=0; i<64; i++) {
+ rc = DosReleaseMutexSem( (HMTX)MutexHandles[ i ].hsemCur );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosReleaseMutexSem( %d ) failed - rc == %d\n",
+ i, rc
+ );
+ }
+
+ rc = DosCloseMutexSem( (HMTX)MutexHandles[ i ].hsemCur );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCloseMutexSem( %d ) failed - rc == %d\n",
+ i, rc
+ );
+ }
+ }
+
+ for (i = 0; i < MAX_SEM_REC + 1; i++) {
+ rc=DosCreateMutexSem (NULL, &srMtxPrivate[i].hsemCur, 0, TRUE);
+ DbgPrint("\n rc from DoCrMutx %u", rc);
+ srMtxPrivate[i].ulUser = ((ULONG)srMtxPrivate[i].hsemCur << SEM_SHIFT) + i;
+ }
+
+ DbgPrint("\n TESTING MtxPrivate Wait all\n");
+ rc = DosCreateMuxWaitSem (NULL, &MuxWaitHandle, 32,(PSEMRECORD)srMtxPrivate, DCMW_WAIT_ALL);
+ DbgPrint("\n rc from DoCrMuxWait %u", rc);
+
+ rc = DosWaitMuxWaitSem (MuxWaitHandle, 10000, &UserValue); /* rc coming here is 6 */
+ DbgPrint("\n rc from DoWtMutx %u\n", rc);
+
+
+ DbgPrint("\n TESTING MtxPrivate Wait any\n");
+ rc = DosCreateMuxWaitSem (NULL, &MuxWaitHandle, 32,
+ (PSEMRECORD)srMtxPrivate, DCMW_WAIT_ANY);
+ DbgPrint("\n rc from DoCrMuxWait %u", rc);
+ rc = DosWaitMuxWaitSem (MuxWaitHandle,
+ 10000, &UserValue); /* rc coming here is 6 */
+ DbgPrint("\n rc from DoWtMutx %u\n", rc);
+
+
+/* Testing for mutex shared sem */
+ for (i = 0; i < MAX_SEM_REC + 1; i++) {
+ rc=DosCreateMutexSem (NULL, &srMtxShared[i].hsemCur, DC_SEM_SHARED, TRUE);
+ DbgPrint("\n rc from DoCrMutx %u", rc);
+ srMtxShared[i].ulUser = ((ULONG)srMtxShared[i].hsemCur << SEM_SHIFT) + i;
+ }
+
+ DbgPrint("\n TESTING MtxShared Wait all\n");
+ rc = DosCreateMuxWaitSem (NULL, &MuxWaitHandle, 32,
+ (PSEMRECORD)srMtxShared, DCMW_WAIT_ALL);
+ DbgPrint("\n rc from DoCrMuxWait %u", rc);
+
+ rc = DosWaitMuxWaitSem (MuxWaitHandle,
+ 10000, &UserValue); /* rc coming here is 6 */
+ DbgPrint("\n rc from DoWtMutx %u\n", rc);
+
+ DbgPrint("\n TESTING MtxShared Wait any\n");
+ rc = DosCreateMuxWaitSem (NULL, &MuxWaitHandle, 32,
+ (PSEMRECORD)srMtxShared, DCMW_WAIT_ANY);
+ DbgPrint("\n rc from DoCrMuxWait %u", rc);
+ rc = DosWaitMuxWaitSem (MuxWaitHandle,10000, &UserValue);/* rc coming here is 6 */
+ DbgPrint("\n rc from DoWtMutx %u\n", rc);
+
+ return;
+}
+
+VOID
+TestProcess( VOID )
+{
+ APIRET rc;
+ PID Pid;
+ HEV EventHandle1, EventHandle2, EventHandle3, EventHandles[ 4 ];
+ ULONG i, PostCount;
+ RESULTCODES ResultCodes;
+
+ if (IsClonedTest()) {
+ EventHandle1 = NULL;
+ rc = DosOpenEventSem( "\\SEM32\\sem1", &EventHandle1 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosOpenEventSem( \\SEM32\\sem1 ) failed - rc == %ld\n", rc );
+ }
+ else {
+ DosPostEventSem( EventHandle1 );
+ DosCloseEventSem( EventHandle1 );
+ }
+
+ EventHandle2 = NULL;
+ rc = DosOpenEventSem( "\\SEM32\\sem2", &EventHandle2 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosOpenEventSem( \\SEM32\\sem2 ) failed - rc == %ld\n", rc );
+ }
+ else {
+ DosPostEventSem( EventHandle2 );
+ DosCloseEventSem( EventHandle2 );
+ }
+
+ DosExit( EXIT_PROCESS, 0 );
+ }
+ else {
+ for (i=0; i<4; i++) {
+ rc = DosCreateEventSem( NULL,
+ &EventHandles[ i ],
+ DC_SEM_SHARED,
+ FALSE
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem( shared ) failed - rc == %ld\n", rc );
+ }
+ }
+ for (i=0; i<4; i++) {
+ DosCloseEventSem( EventHandles[ i ] );
+ }
+
+ rc = DosCreateEventSem( "\\SEM32\\sem1",
+ &EventHandle1,
+ 0,
+ FALSE
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem( \\SEM32\\sem1 ) failed - rc == %ld\n", rc );
+ }
+
+ rc = DosCreateEventSem( "\\SEM32\\sem2",
+ &EventHandle2,
+ 0,
+ FALSE
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem( \\SEM32\\sem2 ) failed - rc == %ld\n", rc );
+ }
+
+ DosResetEventSem( EventHandle1, &PostCount );
+ CloneTest( &Pid );
+ DosWaitEventSem( EventHandle1, SEM_INDEFINITE_WAIT );
+ DosCloseEventSem( EventHandle1 );
+ DosWaitEventSem( EventHandle2, SEM_INDEFINITE_WAIT );
+ DosCloseEventSem( EventHandle2 );
+ DosWaitChild( DCWA_PROCESS, DCWW_WAIT, &ResultCodes, &Pid, Pid );
+
+ rc = DosCreateEventSem( "\\SEM32\\sem3",
+ &EventHandle3,
+ 0,
+ FALSE
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem( \\SEM32\\sem3 ) failed - rc == %ld\n", rc );
+ }
+
+ rc = DosCreateEventSem( "\\SEM32\\sem4",
+ (PHEV)0,
+ 0,
+ FALSE
+ );
+ if (rc != ERROR_INVALID_ADDRESS) {
+ DbgPrint( "*** DosCreateEventSem( \\SEM32\\sem4, (hEv == NULL) ) failed - rc == %ld\n", rc );
+ }
+
+ DbgBreakPoint();
+ rc = DosCreateEventSem( "\\SEM32\\sem4",
+ (PHEV)0xFFFF0000,
+ 0,
+ FALSE
+ );
+ if (rc != ERROR_INVALID_ADDRESS) {
+ DbgPrint( "*** DosCreateEventSem( \\SEM32\\sem4, (hEv == 0xFFFF0000) ) failed - rc == %ld\n", rc );
+ }
+ }
+}
+
+
+VOID
+TestHandles( VOID )
+{
+ PVOID HandleBuffer;
+ PHEV EventHandles;
+ ULONG MaxCountHandles, i, j;
+ APIRET rc;
+
+ HandleBuffer = NULL;
+ MaxCountHandles = (64*1024) / sizeof( HEV );
+ rc = DosAllocMem( &HandleBuffer,
+ MaxCountHandles * sizeof( HEV ),
+ PAG_COMMIT | PAG_READ | PAG_WRITE
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosAllocMem failed - rc == %ld\n", rc );
+ return;
+ }
+ EventHandles = (PHEV)HandleBuffer;
+ for (i=0; i<MaxCountHandles; i++) {
+ rc = DosCreateEventSem( NULL, EventHandles, 0, FALSE );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem( %ld ) failed - rc == %ld\n",
+ i,
+ rc
+ );
+ break;
+ }
+ else {
+ EventHandles++;
+ }
+ }
+
+ DbgPrint( "%ld private Event handles created\n", i );
+
+ EventHandles = (PHEV)HandleBuffer;
+ for (j=0; j<i; j++) {
+ rc = DosCloseEventSem( *EventHandles );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCloseEventSem( %lX ) failed - rc == %ld\n",
+ *EventHandles, rc
+ );
+ }
+
+ EventHandles++;
+ }
+
+ rc = DosFreeMem( HandleBuffer );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosFreeMem failed - rc == %ld\n", rc );
+ }
+}
+
+
+PSZ SemaphoreNames[ 8 ] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "\\SEM32\\TestSemaphore1",
+ "\\sem32\\TestSemaphore2",
+ NULL,
+ NULL
+};
+
+VOID
+TestEvent( VOID )
+{
+ APIRET rc;
+ HEV EventHandle[ 8 ];
+ HEV NewEventHandle;
+ ULONG PostCount;
+ int i, j;
+
+ for (i=0; i<8; i++) {
+ rc = DosCreateEventSem( SemaphoreNames[i],
+ &EventHandle[i],
+ i < 5 ? 0 : DC_SEM_SHARED,
+ FALSE
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem( %s ) failed - rc == %ld\n",
+ i < 4 ? "private" : (i < 6 ? SemaphoreNames[i] : "shared"),
+ rc
+ );
+ EventHandle[i] = (HEV)-1;
+ }
+ else {
+ DbgPrint( "*** DosCreateEventSem( %s ) success - Handle == %lX\n",
+ i < 4 ? "private" : (i < 6 ? SemaphoreNames[i] : "shared"),
+ EventHandle[i]
+ );
+ }
+ }
+
+ for (i=0; i<8; i++) {
+ if (SemaphoreNames[i] != NULL) {
+ NewEventHandle = (HEV)NULL;
+ }
+ else {
+ NewEventHandle = EventHandle[i];
+ }
+ rc = DosOpenEventSem( SemaphoreNames[i],
+ &NewEventHandle
+ );
+ if (rc != NO_ERROR || NewEventHandle != EventHandle[i]) {
+ DbgPrint( "*** DosOpenEventSem( %s, %lX ) failed - rc == %ld\n",
+ i < 4 ? "private" : (i < 6 ? SemaphoreNames[i] : "shared"),
+ NewEventHandle, rc
+ );
+ }
+ else {
+ DbgPrint( "*** DosOpenEventSem( %s ) success - Handle == %lX\n",
+ i < 4 ? "private" : (i < 6 ? SemaphoreNames[i] : "shared"),
+ NewEventHandle
+ );
+
+ for (j=0; j<i; j++) {
+ rc = DosPostEventSem( EventHandle[ i ] );
+ if (rc != NO_ERROR && rc != ERROR_ALREADY_POSTED) {
+ DbgPrint( "*** DosPostEventSem( %lX ) failed - rc == %ld\n",
+ EventHandle[ i ], rc
+ );
+ }
+ }
+
+ PostCount = -1;
+ rc = DosResetEventSem( EventHandle[ i ], &PostCount );
+ if (rc != NO_ERROR && rc != ERROR_ALREADY_RESET) {
+ DbgPrint( "*** DosResetEventSem( %lX ) failed - rc == %ld\n",
+ EventHandle[ i ], rc
+ );
+ }
+ else {
+ DbgPrint( "*** DosResetEventSem( %lX ) - PostCount == %lX\n",
+ EventHandle[ i ], PostCount
+ );
+ }
+ }
+ }
+
+
+ for (i=0; i<8; i++) {
+ rc = DosQueryEventSem( EventHandle[ i ], &PostCount );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosQueryEventSem( %lX ) failed - rc == %ld\n",
+ EventHandle[ i ], rc
+ );
+ }
+ else {
+ DbgPrint( "*** DosQueryEventSem( %lX ) - PostCount == %lX\n",
+ EventHandle[ i ], PostCount
+ );
+ }
+
+ rc = DosCloseEventSem( EventHandle[ i ] );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCloseEventSem( %lX ) failed - rc == %ld\n",
+ EventHandle[ i ], rc
+ );
+ }
+ }
+
+ for (i=0; i<8; i++) {
+ rc = DosCloseEventSem( EventHandle[ i ] );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCloseEventSem( %lX ) failed - rc == %ld\n",
+ EventHandle[ i ], rc
+ );
+ }
+ }
+}
+
+VOID
+TestMutex( VOID )
+{
+ APIRET rc;
+ HMTX MutexHandle[ 8 ];
+ HMTX NewMutexHandle;
+ PID OwningPid;
+ TID OwningTid;
+ ULONG RequestCount;
+ int i, j;
+
+ for (i=0; i<8; i++) {
+ rc = DosCreateMutexSem( SemaphoreNames[i],
+ &MutexHandle[i],
+ i < 5 ? 0 : DC_SEM_SHARED,
+ FALSE
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateMutexSem( %s ) failed - rc == %ld\n",
+ i < 4 ? "private" : (i < 6 ? SemaphoreNames[i] : "shared"),
+ rc
+ );
+ MutexHandle[i] = (HMTX)-1;
+ }
+ else {
+ DbgPrint( "*** DosCreateMutexSem( %s ) success - Handle == %lX\n",
+ i < 4 ? "private" : (i < 6 ? SemaphoreNames[i] : "shared"),
+ MutexHandle[i]
+ );
+ }
+ }
+
+ for (i=0; i<8; i++) {
+ if (SemaphoreNames[i] != NULL) {
+ NewMutexHandle = (HMTX)NULL;
+ }
+ else {
+ NewMutexHandle = MutexHandle[i];
+ }
+ rc = DosOpenMutexSem( SemaphoreNames[i],
+ &NewMutexHandle
+ );
+ if (rc != NO_ERROR || NewMutexHandle != MutexHandle[i]) {
+ DbgPrint( "*** DosOpenMutexSem( %s, %lX ) failed - rc == %ld\n",
+ i < 4 ? "private" : (i < 6 ? SemaphoreNames[i] : "shared"),
+ NewMutexHandle, rc
+ );
+ }
+ else {
+ DbgPrint( "*** DosOpenMutexSem( %s ) success - Handle == %lX\n",
+ i < 4 ? "private" : (i < 6 ? SemaphoreNames[i] : "shared"),
+ NewMutexHandle
+ );
+
+ rc = DosReleaseMutexSem( MutexHandle[ i ] );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosReleaseMutexSem( %lX ) failed - rc == %ld\n",
+ MutexHandle[ i ], rc
+ );
+ }
+ }
+ }
+
+
+ for (i=0; i<8; i++) {
+ rc = DosQueryMutexSem( MutexHandle[ i ],
+ &OwningPid,
+ &OwningTid,
+ &RequestCount
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosQueryMutexSem( %lX ) failed - rc == %ld\n",
+ MutexHandle[ i ], rc
+ );
+ }
+ else {
+ DbgPrint( "*** DosQueryMutexSem( %lX ) - Owner == %lX.%lX RequestCount == %lX\n",
+ MutexHandle[ i ], OwningPid, OwningTid, RequestCount
+ );
+ }
+
+ rc = DosCloseMutexSem( MutexHandle[ i ] );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCloseMutexSem( %lX ) failed - rc == %ld\n",
+ MutexHandle[ i ], rc
+ );
+ }
+ }
+
+ for (i=0; i<8; i++) {
+ rc = DosCloseMutexSem( MutexHandle[ i ] );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCloseMutexSem( %lX ) failed - rc == %ld\n",
+ MutexHandle[ i ], rc
+ );
+ }
+ }
+}
+
+
+VOID
+TestThread1(
+ IN HMUX hMux
+ )
+{
+ APIRET rc;
+ ULONG i, UserValue;
+ ULONG CountMuxWaitEntries, CreateAttributes;
+ SEMRECORD MuxWaitEntries[ 8 ];
+
+ CountMuxWaitEntries = 8;
+ rc = DosQueryMuxWaitSem( hMux,
+ &CountMuxWaitEntries,
+ MuxWaitEntries,
+ &CreateAttributes
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosQueryMuxWaitSem( %lX ) failed - rc == %ld\n",
+ hMux, rc
+ );
+ }
+ else {
+ DbgPrint( "*** DosQueryMuxWaitSem( %lX ) - CountMuxWaitEntries == %lX Attributes == %lX\n",
+ hMux, CountMuxWaitEntries, CreateAttributes
+ );
+ for (i=0; i<CountMuxWaitEntries; i++) {
+ DbgPrint( " MuxWaitEntry[ %ld ]: hSem == %lX, user: %lX\n",
+ i,
+ MuxWaitEntries[ i ].hsemCur,
+ MuxWaitEntries[ i ].ulUser
+ );
+ }
+ }
+
+ rc = DosWaitMuxWaitSem( hMux, SEM_INDEFINITE_WAIT, &UserValue );
+
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitMuxWaitSem( %lX ) failed - rc == %ld\n",
+ hMux, rc
+ );
+ }
+ else {
+ DbgPrint( "*** DosWaitMuxWaitSem( %lX ) success - UserValue == %lX\n",
+ hMux, UserValue
+ );
+ }
+}
+
+
+VOID
+TestMuxWait( VOID )
+{
+ APIRET rc;
+ TID Thread1Id;
+ HMUX MuxWaitAllHandle;
+ HMUX MuxWaitAnyHandle;
+ HMUX MuxWaitHandle[ 8 ];
+ HMUX NewMuxWaitHandle;
+ ULONG CreateAttributes;
+ ULONG OldPostCount;
+ ULONG UserValue;
+ int i, j;
+ ULONG CountMuxWaitEntries;
+ SEMRECORD MaximumMuxWaitRecords[ 65 ];
+ SEMRECORD PrivateMuxWaitRecords[ 8 ];
+ SEMRECORD SharedMuxWaitRecords[ 8 ];
+ SEMRECORD MixedMuxWaitRecords[ 8 ];
+ SEMRECORD MuxWaitEntries[ 8 ];
+ PSEMRECORD MuxWaitRecords;
+
+ for (i=0; i<65; i++) {
+ rc = DosCreateEventSem( NULL,
+ (PHEV)&MaximumMuxWaitRecords[i].hsemCur,
+ 0,
+ TRUE
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem for MaximumMuxWait test failed - rc == %ld\n",
+ rc
+ );
+ MaximumMuxWaitRecords[i].hsemCur = (HSEM)-1;
+ MaximumMuxWaitRecords[i].ulUser = -1;
+ }
+ else {
+ MaximumMuxWaitRecords[i].ulUser = i;
+ }
+ }
+
+ rc = DosCreateMuxWaitSem( NULL,
+ &MuxWaitAllHandle,
+ 32,
+ MaximumMuxWaitRecords,
+ DCMW_WAIT_ALL
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateMuxWaitSem( 32, WaitAll ) failed - rc == %ld\n",
+ rc
+ );
+ MuxWaitAllHandle = (HMUX)-1;
+ }
+ else {
+ DbgPrint( "*** DosCreateMuxWaitSem( 32, WaitAll ) success - Handle == %lX\n",
+ MuxWaitAllHandle
+ );
+ }
+
+ rc = DosCreateMuxWaitSem( NULL,
+ &MuxWaitAnyHandle,
+ 32,
+ MaximumMuxWaitRecords,
+ DCMW_WAIT_ANY
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateMuxWaitSem( 32, WaitAny ) failed - rc == %ld\n",
+ rc
+ );
+ MuxWaitAnyHandle = (HMUX)-1;
+ }
+ else {
+ DbgPrint( "*** DosCreateMuxWaitSem( 32, WaitAny ) success - Handle == %lX\n",
+ MuxWaitAnyHandle
+ );
+ }
+
+
+ rc = DosWaitMuxWaitSem( MuxWaitAllHandle, 10000, &UserValue );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitMuxWaitSem( %lX ) failed - rc == %ld\n",
+ MuxWaitAllHandle, rc
+ );
+ }
+ else {
+ DbgPrint( "*** DosWaitMuxWaitSem( %lX ) success - UserValue == %lX\n",
+ MuxWaitAllHandle, UserValue
+ );
+ }
+
+ rc = DosWaitMuxWaitSem( MuxWaitAnyHandle, 10000, &UserValue );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitMuxWaitSem( %lX ) failed - rc == %ld\n",
+ MuxWaitAnyHandle, rc
+ );
+ }
+ else {
+ DbgPrint( "*** DosWaitMuxWaitSem( %lX ) success - UserValue == %lX\n",
+ MuxWaitAnyHandle, UserValue
+ );
+ }
+
+
+ for (i=0; i<8; i++) {
+ rc = DosCreateEventSem( NULL,
+ (PHEV)&PrivateMuxWaitRecords[i].hsemCur,
+ 0,
+ FALSE
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem for PrivateMuxWait test failed - rc == %ld\n",
+ rc
+ );
+ PrivateMuxWaitRecords[i].hsemCur = (HSEM)-1;
+ PrivateMuxWaitRecords[i].ulUser = -1;
+ }
+ else {
+ PrivateMuxWaitRecords[i].ulUser = i;
+ }
+ }
+
+ for (i=0; i<8; i++) {
+ rc = DosCreateEventSem( NULL,
+ (PHEV)&SharedMuxWaitRecords[i].hsemCur,
+ DC_SEM_SHARED,
+ FALSE
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem for SharedMuxWait test failed - rc == %ld\n",
+ rc
+ );
+ SharedMuxWaitRecords[i].hsemCur = (HSEM)-1;
+ SharedMuxWaitRecords[i].ulUser = -1;
+ }
+ else {
+ SharedMuxWaitRecords[i].ulUser = i | DC_SEM_SHARED;
+ }
+ }
+
+ for (i=0; i<8; i++) {
+ rc = DosCreateEventSem( NULL,
+ (PHEV)&MixedMuxWaitRecords[i].hsemCur,
+ DC_SEM_SHARED,
+ FALSE
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem for MixedMuxWait test failed - rc == %ld\n",
+ rc
+ );
+ MixedMuxWaitRecords[i].hsemCur = (HSEM)-1;
+ MixedMuxWaitRecords[i].ulUser = -1;
+ }
+ else {
+ MixedMuxWaitRecords[i].ulUser = -i;
+ }
+ }
+
+ for (i=0; i<8; i++) {
+ rc = DosCreateMuxWaitSem( SemaphoreNames[i],
+ &MuxWaitHandle[i],
+ 8,
+ i < 4 ? PrivateMuxWaitRecords : i < 6 ?
+ MixedMuxWaitRecords :
+ SharedMuxWaitRecords,
+ (i < 5 ? 0 : DC_SEM_SHARED) |
+ DCMW_WAIT_ANY & i ? DCMW_WAIT_ANY :
+ DCMW_WAIT_ALL
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateMuxWaitSem( %s ) failed - rc == %ld\n",
+ i < 4 ? "private" : (i < 6 ? SemaphoreNames[i] : "shared"),
+ rc
+ );
+ MuxWaitHandle[i] = (HMUX)-1;
+ }
+ else {
+ DbgPrint( "*** DosCreateMuxWaitSem( %s ) success - Handle == %lX\n",
+ i < 4 ? "private" : (i < 6 ? SemaphoreNames[i] : "shared"),
+ MuxWaitHandle[i]
+ );
+ }
+ }
+
+ for (i=0; i<8; i++) {
+ if (SemaphoreNames[i] != NULL) {
+ NewMuxWaitHandle = (HMUX)NULL;
+ }
+ else {
+ NewMuxWaitHandle = MuxWaitHandle[i];
+ }
+ rc = DosOpenMuxWaitSem( SemaphoreNames[i],
+ &NewMuxWaitHandle
+ );
+ if (rc != NO_ERROR || NewMuxWaitHandle != MuxWaitHandle[i]) {
+ DbgPrint( "*** DosOpenMuxWaitSem( %s, %lX ) failed - rc == %ld\n",
+ i < 4 ? "private" : (i < 6 ? SemaphoreNames[i] : "shared"),
+ NewMuxWaitHandle, rc
+ );
+ }
+ else {
+ DbgPrint( "*** DosOpenMuxWaitSem( %s ) success - Handle == %lX\n",
+ i < 4 ? "private" : (i < 6 ? SemaphoreNames[i] : "shared"),
+ NewMuxWaitHandle
+ );
+ }
+ }
+
+
+ for (i=0; i<8; i++) {
+ CountMuxWaitEntries = 8;
+ rc = DosQueryMuxWaitSem( MuxWaitHandle[ i ],
+ &CountMuxWaitEntries,
+ MuxWaitEntries,
+ &CreateAttributes
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosQueryMuxWaitSem( %lX ) failed - rc == %ld\n",
+ MuxWaitHandle[ i ], rc
+ );
+ }
+ else {
+ DbgPrint( "*** DosQueryMuxWaitSem( %lX ) - CountMuxWaitEntries == %lX Attributes == %lX\n",
+ MuxWaitHandle[ i ], CountMuxWaitEntries, CreateAttributes
+ );
+ }
+ }
+
+ for (i=0; i<8; i++) {
+ DbgPrint( "*** Thread to DosWaitMuxWaitSem( %lX ) - %s, %s\n",
+ MuxWaitHandle[ i ],
+ i < 4 ? "Private" : i < 6 ? "Mixed" : "Shared",
+ i & DCMW_WAIT_ANY ? "WaitAny" : "WaitAll"
+ );
+
+ rc = DosCreateThread( &Thread1Id,
+ (PFNTHREAD)TestThread1,
+ (ULONG)(MuxWaitHandle[ i ]),
+ DCT_SUSPENDED,
+ 0x10000
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateThread failed - rc == %ld\n",
+ rc
+ );
+ return;
+ }
+
+ rc = DosResumeThread( Thread1Id );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosResumeThread failed - rc == %ld\n", rc );
+ }
+
+ DosSleep( 1000 );
+
+ MuxWaitRecords = i < 4 ? PrivateMuxWaitRecords : i < 6 ?
+ MixedMuxWaitRecords :
+ SharedMuxWaitRecords;
+
+ if (i & DCMW_WAIT_ANY) {
+ DbgPrint( "*** Posting hEv == %lX\n", MuxWaitRecords[ i ].hsemCur );
+ DosPostEventSem( MuxWaitRecords[ i ].hsemCur );
+ // DosResetEventSem( MuxWaitRecords[ i ].hsemCur, &OldPostCount );
+ }
+ else {
+ for (j=0; j<8; j++) {
+ DbgPrint( "*** Posting hEv == %lX\n", MuxWaitRecords[ j ].hsemCur );
+ DosPostEventSem( MuxWaitRecords[ j ].hsemCur );
+ // DosResetEventSem( MuxWaitRecords[ j ].hsemCur, &OldPostCount );
+ }
+ }
+
+ DosWaitThread( &Thread1Id, DCWW_WAIT );
+ }
+
+ for (i=0; i<8; i++) {
+ rc = DosCloseMuxWaitSem( MuxWaitHandle[ i ] );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCloseMuxWaitSem( %lX ) failed - rc == %ld\n",
+ MuxWaitHandle[ i ], rc
+ );
+ }
+ }
+
+ for (i=0; i<8; i++) {
+ DosCloseEventSem( PrivateMuxWaitRecords[i].hsemCur );
+ DosCloseEventSem( SharedMuxWaitRecords[i].hsemCur );
+ DosCloseEventSem( MixedMuxWaitRecords[i].hsemCur );
+ }
+}
diff --git a/private/os2/client/os2sig.c b/private/os2/client/os2sig.c
new file mode 100644
index 000000000..9038238ee
--- /dev/null
+++ b/private/os2/client/os2sig.c
@@ -0,0 +1,875 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2xcpt.c
+
+Abstract:
+
+ This is a test OS/2 application to test the exception/signal component
+ of OS/2
+
+Author:
+
+ Therese Stowell (thereses) 17-July-1990
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+
+#define OS2_API32
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_EXCEPTIONS
+#include <os2.h>
+#include "excpt.h"
+
+PCHAR NullApiArguments[] = {
+ "String Number One",
+ "String Number Two",
+ "String Number Three",
+ NULL
+};
+
+
+VOID
+SigFocusTest( VOID );
+
+VOID
+MustCompleteTest( VOID );
+
+VOID
+KillProcessTest( VOID );
+
+VOID
+KillProcess2( VOID );
+
+VOID
+WaitBlockTest( VOID );
+
+VOID
+ExitTest( VOID );
+
+int
+main(
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+ DbgPrint( "*** Entering OS/2 Test Application\n" );
+
+// ExitTest();
+// SigFocusTest();
+// MustCompleteTest();
+// KillProcessTest();
+ KillProcess2();
+// WaitBlockTest();
+
+ DbgPrint( "*** Exiting OS/2 Test Application\n" );
+ return( 0 );
+}
+
+
+ULONG
+PrintExceptionCode(
+ IN PEXCEPTION_POINTERS ExceptionInfo,
+ IN CHAR Process,
+ IN ULONG RetCode
+ )
+{
+ DbgPrint("In PrintExceptionCode. Exception is %lx.\n",ExceptionInfo->ExceptionRecord->ExceptionCode);
+ DbgPrint(" Signal is %ld.\n",ExceptionInfo->ExceptionRecord->ExceptionInformation[0]);
+ DbgPrint(" Signal should be %ld.\n",XCPT_SIGNAL_INTR);
+ DbgPrint(" Process is %c\n",Process);
+ return RetCode;
+}
+
+VOID
+TestThread0(
+ IN UCHAR ThreadChar
+ )
+{
+ CHAR ThreadName[2];
+
+ ThreadName[0] = ThreadChar;
+ ThreadName[1] = '\0';
+
+ DbgPrint( "*** Entering OS/2 Thread%s\n", (PCH)ThreadName );
+ try {
+ while (TRUE)
+ ;
+ }
+ except( PrintExceptionCode(GetExceptionInformation(),'B',XCPT_CONTINUE_SEARCH ) ) {
+ ASSERT (FALSE); // we should never get here
+ }
+ DbgPrint( "*** Exiting OS/2 Thread%s\n", (PCH)ThreadName );
+}
+
+VOID
+KillProcess2( VOID )
+
+//
+// This tests the DosExit API.
+//
+
+{
+ PPIB Pib;
+ PNT_TIB Tib;
+ APIRET rc;
+ PCH ImageFileName, CommandLine;
+ RESULTCODES ResultCodes;
+ CHAR ErrorBuffer[ 32 ];
+ HEV SemHandle, SemHandle2;
+
+ rc = DosGetThreadInfo( &Tib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ return;
+ }
+
+ ImageFileName = "c:\\nt\\bin\\os2sig.exe";
+ DbgPrint("CommandLine is %s\n",Pib->CommandLine);
+ if (Pib->CommandLine[1] != 0) {
+ CommandLine = "A\000";
+ rc = DosExecPgm( ErrorBuffer,
+ sizeof( ErrorBuffer ),
+ EXEC_ASYNC,
+ CommandLine,
+ NULL,
+ &ResultCodes,
+ ImageFileName
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExecPgm( %s, %s ) failed - rc == %ld\n",
+ ImageFileName, CommandLine, rc
+ );
+ }
+ else {
+ rc = DosCreateEventSem("\\SEM32\\SIGSEM", // wait for the other processes to be created
+ &SemHandle,
+ 0,
+ FALSE);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem failed - rc == %ld\n",rc);
+ return;
+ }
+ rc = DosWaitEventSem(SemHandle,-1);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitEventSem failed - rc == %ld\n",rc);
+ return;
+ }
+ DbgPrint("calling DosKillProcess\n");
+ rc = DosKillProcess(DKP_PROCESSTREE,
+ (PID)ResultCodes.ExitReason);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosKillProcess( %ld, %ld ) failed - rc == %ld\n",
+ ResultCodes.ExitReason,XCPT_SIGNAL_INTR, rc
+ );
+ return;
+ }
+ }
+ }
+ else {
+ Pib->CommandLine[0] += 1;
+ if (Pib->CommandLine[0] < 'E') {
+ CommandLine = Pib->CommandLine;
+ rc = DosExecPgm( ErrorBuffer,
+ sizeof( ErrorBuffer ),
+ EXEC_ASYNC,
+ CommandLine,
+ NULL,
+ &ResultCodes,
+ ImageFileName
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExecPgm( %s, %s ) failed - rc == %ld\n",
+ ImageFileName, CommandLine, rc
+ );
+ return;
+ }
+ }
+ if (Pib->CommandLine[0] == 'E') {
+ SemHandle2 = NULL;
+ rc = DosOpenEventSem("\\SEM32\\SIGSEM",
+ &SemHandle2);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosOpenEventSem failed - rc == %ld\n",rc);
+ }
+ DbgPrint("posting event\n");
+ rc = DosPostEventSem(SemHandle2);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosPostEventSem failed - rc == %ld\n",rc);
+ }
+ }
+ try {
+ while (TRUE)
+ DbgPrint("looping in %c\n",Pib->CommandLine[0]);
+ } except( PrintExceptionCode(GetExceptionInformation(),Pib->CommandLine[0],XCPT_CONTINUE_SEARCH ) ) {
+ DbgPrint("in exception handler\n");
+ ASSERT ( FALSE );
+ }
+ }
+}
+
+
+VOID
+KillProcessTest( VOID )
+
+//
+// This tests the DosKillProcess API.
+//
+
+{
+ PPIB Pib;
+ PNT_TIB Tib;
+ APIRET rc;
+ PCH ImageFileName, CommandLine;
+ RESULTCODES ResultCodes;
+ ULONG NestingLevel;
+ CHAR ErrorBuffer[ 32 ];
+ HEV SemHandle;
+ PID Pid;
+ TID ThreadAId;
+
+ rc = DosGetThreadInfo( &Tib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ return;
+ }
+
+ ImageFileName = "c:\\nt\\bin\\os2sig.exe";
+ DbgPrint("CommandLine is %s\n",Pib->CommandLine);
+ if (Pib->CommandLine[1] != 0) {
+ CommandLine = "A\000";
+ rc = DosExecPgm( ErrorBuffer,
+ sizeof( ErrorBuffer ),
+ EXEC_ASYNC,
+ CommandLine,
+ NULL,
+ &ResultCodes,
+ ImageFileName
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExecPgm( %s, %s ) failed - rc == %ld\n",
+ ImageFileName, CommandLine, rc
+ );
+ return;
+ }
+ else {
+ rc = DosCreateEventSem("\\SEM32\\SIGSEM",
+ &SemHandle,
+ 0,
+ FALSE);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem failed - rc == %ld\n",rc);
+ return;
+ }
+ rc = DosWaitEventSem(SemHandle,-1);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitEventSem failed - rc == %ld\n",rc);
+ return;
+ }
+ DbgPrint("calling DosKillProcess\n");
+ rc = DosKillProcess(DKP_PROCESS,
+ (PID)ResultCodes.ExitReason);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosKillProcess( %ld, %ld ) failed - rc == %ld\n",
+ ResultCodes.ExitReason,XCPT_SIGNAL_INTR, rc
+ );
+ return;
+ }
+ }
+ rc = DosWaitChild(DCWA_PROCESS,
+ DCWW_WAIT,
+ &ResultCodes,
+ &Pid,
+ (PID)ResultCodes.ExitReason);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitChild failed - rc == %ld\n",rc);
+ return;
+ }
+
+ }
+ else {
+ DbgPrint("entering MustComplete\n");
+ rc = DosEnterMustComplete(&NestingLevel);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosEnterMustComplete failed - rc == %ld\n",rc);
+ }
+ DbgPrint("NestingLevel is %ld\n",NestingLevel);
+ rc = DosSetSignalExceptionFocus(TRUE,
+ &NestingLevel);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosSetSignalExceptionFocus failed - rc == %ld\n",rc);
+ return;
+ }
+ DbgPrint("NestingLevel is %ld\n",NestingLevel);
+ rc = DosCreateThread( &ThreadAId,
+ (PFNTHREAD)TestThread0,
+ (ULONG)'a',
+ DCT_SUSPENDED,
+ 0x10000
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateThread( ThreadA ) failed - rc == %ld\n",
+ rc
+ );
+ return;
+ }
+ rc = DosResumeThread( ThreadAId );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosResumeThread( ThreadA ) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosOpenEventSem("\\SEM32\\SIGSEM",
+ &SemHandle);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosOpenEventSem failed - rc == %ld\n",rc);
+ }
+ DbgPrint("posting event\n");
+ rc = DosPostEventSem(SemHandle);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosPostEventSem failed - rc == %ld\n",rc);
+ }
+ DosSleep( 10000 ); // wait for signal to be sent
+ DbgPrint("leaving MustComplete\n");
+ rc = DosExitMustComplete(&NestingLevel);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitMustComplete failed - rc == %ld\n",rc);
+ }
+ DbgPrint("NestingLevel is %ld\n",NestingLevel);
+ while (TRUE)
+ ;
+ }
+}
+VOID
+MustCompleteTest( VOID )
+
+//
+// This tests the Dos*MustComplete API.
+//
+
+{
+ PPIB Pib;
+ PNT_TIB Tib;
+ APIRET rc;
+ PCH ImageFileName, CommandLine;
+ RESULTCODES ResultCodes;
+ ULONG NestingLevel;
+ CHAR ErrorBuffer[ 32 ];
+ HEV SemHandle;
+ PID Pid;
+
+ rc = DosGetThreadInfo( &Tib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ return;
+ }
+
+ ImageFileName = "c:\\nt\\bin\\os2sig.exe";
+ DbgPrint("CommandLine is %s\n",Pib->CommandLine);
+ if (Pib->CommandLine[1] != 0) {
+ CommandLine = "A\000";
+ rc = DosExecPgm( ErrorBuffer,
+ sizeof( ErrorBuffer ),
+ EXEC_ASYNC,
+ CommandLine,
+ NULL,
+ &ResultCodes,
+ ImageFileName
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExecPgm( %s, %s ) failed - rc == %ld\n",
+ ImageFileName, CommandLine, rc
+ );
+ return;
+ }
+ else {
+ rc = DosCreateEventSem("\\SEM32\\SIGSEM",
+ &SemHandle,
+ 0,
+ FALSE);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem failed - rc == %ld\n",rc);
+ return;
+ }
+ rc = DosWaitEventSem(SemHandle,-1);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitEventSem failed - rc == %ld\n",rc);
+ return;
+ }
+ DbgPrint("calling DosSendSignalException\n");
+ rc = DosSendSignalException((PID)ResultCodes.ExitReason,
+ XCPT_SIGNAL_INTR);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosSendSignalException( %ld, %ld ) failed - rc == %ld\n",
+ ResultCodes.ExitReason,XCPT_SIGNAL_INTR, rc
+ );
+ return;
+ }
+ }
+ rc = DosWaitChild(DCWA_PROCESS,
+ DCWW_WAIT,
+ &ResultCodes,
+ &Pid,
+ (PID)ResultCodes.ExitReason);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitChild failed - rc == %ld\n",rc);
+ return;
+ }
+
+ }
+ else {
+ DbgPrint("entering MustComplete\n");
+ rc = DosEnterMustComplete(&NestingLevel);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosEnterMustComplete failed - rc == %ld\n",rc);
+ }
+ DbgPrint("NestingLevel is %ld\n",NestingLevel);
+ rc = DosSetSignalExceptionFocus(TRUE,
+ &NestingLevel);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosSetSignalExceptionFocus failed - rc == %ld\n",rc);
+ return;
+ }
+ DbgPrint("NestingLevel is %ld\n",NestingLevel);
+ rc = DosOpenEventSem("\\SEM32\\SIGSEM",
+ &SemHandle);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosOpenEventSem failed - rc == %ld\n",rc);
+ }
+ DbgPrint("posting event\n");
+ rc = DosPostEventSem(SemHandle);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosPostEventSem failed - rc == %ld\n",rc);
+ }
+ DosSleep( 10000 ); // wait for signal to be sent
+ DbgPrint("leaving MustComplete\n");
+ rc = DosExitMustComplete(&NestingLevel);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitMustComplete failed - rc == %ld\n",rc);
+ }
+ DbgPrint("NestingLevel is %ld\n",NestingLevel);
+ }
+}
+
+VOID
+ExceptionTest( VOID )
+
+//
+// This tests the DosRaiseException API.
+//
+
+{
+ APIRET rc;
+ EXCEPTIONREPORTRECORD ExceptionRecord;
+
+ try {
+ ExceptionRecord.ExceptionNum = XCPT_PROCESS_TERMINATE;
+ ExceptionRecord.fHandlerFlags = 0;
+ ExceptionRecord.NestedExceptionReportRecord = (PEXCEPTIONREPORTRECORD) NULL;
+ ExceptionRecord.cParameters = 0;
+ rc = DosRaiseException(&ExceptionRecord);
+ }
+ except( PrintExceptionCode(GetExceptionInformation(),'A',XCPT_CONTINUE_EXECUTION ) ) {
+ ASSERT (FALSE); // we should never get here
+ }
+}
+
+VOID
+ExitTest( VOID )
+
+//
+// This tests the DosExit API.
+//
+
+{
+ PPIB Pib;
+ PNT_TIB Tib;
+ APIRET rc;
+ PCH ImageFileName, CommandLine;
+ RESULTCODES ResultCodes;
+ CHAR ErrorBuffer[ 32 ];
+ HEV SemHandle;
+
+ rc = DosGetThreadInfo( &Tib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ return;
+ }
+
+ ImageFileName = "c:\\nt\\bin\\os2sig.exe";
+ DbgPrint("CommandLine is %s\n",Pib->CommandLine);
+ if (Pib->CommandLine[1] != 0) {
+ CommandLine = "A\000";
+ rc = DosExecPgm( ErrorBuffer,
+ sizeof( ErrorBuffer ),
+ EXEC_ASYNC,
+ CommandLine,
+ NULL,
+ &ResultCodes,
+ ImageFileName
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExecPgm( %s, %s ) failed - rc == %ld\n",
+ ImageFileName, CommandLine, rc
+ );
+ }
+ else {
+ rc = DosCreateEventSem("\\SEM32\\SIGSEM", // wait for the other processes to be created
+ &SemHandle,
+ 0,
+ FALSE);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem failed - rc == %ld\n",rc);
+ return;
+ }
+ rc = DosWaitEventSem(SemHandle,-1);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitEventSem failed - rc == %ld\n",rc);
+ return;
+ }
+ DbgPrint("calling DosExit\n");
+ DosExit(EXIT_PROCESS,0xA5A5);
+ }
+ }
+ else {
+ Pib->CommandLine[0] += 1;
+ if (Pib->CommandLine[0] < 'E') {
+ CommandLine = Pib->CommandLine;
+ rc = DosExecPgm( ErrorBuffer,
+ sizeof( ErrorBuffer ),
+ EXEC_ASYNC,
+ CommandLine,
+ NULL,
+ &ResultCodes,
+ ImageFileName
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExecPgm( %s, %s ) failed - rc == %ld\n",
+ ImageFileName, CommandLine, rc
+ );
+ return;
+ }
+ }
+ if (Pib->CommandLine[0] == 'E') {
+ rc = DosOpenEventSem("\\SEM32\\SIGSEM",
+ &SemHandle);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosOpenEventSem failed - rc == %ld\n",rc);
+ }
+ DbgPrint("posting event\n");
+ rc = DosPostEventSem(SemHandle);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosPostEventSem failed - rc == %ld\n",rc);
+ }
+ }
+ try {
+ while (TRUE)
+ DbgPrint("looping in %c\n",Pib->CommandLine[0]);
+ } except( PrintExceptionCode(GetExceptionInformation(),Pib->CommandLine[0],XCPT_CONTINUE_SEARCH ) ) {
+ DbgPrint("in exception handler\n");
+ ASSERT ( FALSE );
+ }
+ }
+}
+
+
+VOID
+SigFocusTest( VOID )
+
+//
+// This tests the DosSetSignalExceptionFocus and DosSendSignalException API.
+//
+
+{
+ PPIB Pib;
+ PNT_TIB Tib;
+ APIRET rc;
+ PCH ImageFileName, CommandLine;
+ RESULTCODES ResultCodes;
+ ULONG NestingLevel;
+ CHAR ErrorBuffer[ 32 ];
+ PID Pid;
+ HEV SemHandle;
+ PID ChildPid;
+
+ rc = DosGetThreadInfo( &Tib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ return;
+ }
+
+ ImageFileName = "c:\\nt\\bin\\os2sig.exe";
+ DbgPrint("CommandLine is %s\n",Pib->CommandLine);
+ if (Pib->CommandLine[1] != 0) {
+ CommandLine = "A\000";
+ rc = DosExecPgm( ErrorBuffer,
+ sizeof( ErrorBuffer ),
+ EXEC_ASYNC,
+ CommandLine,
+ NULL,
+ &ResultCodes,
+ ImageFileName
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExecPgm( %s, %s ) failed - rc == %ld\n",
+ ImageFileName, CommandLine, rc
+ );
+ }
+ else {
+ rc = DosCreateEventSem("\\SEM32\\SIGSEM", // wait for the other processes to be created
+ &SemHandle,
+ 0,
+ FALSE);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem failed - rc == %ld\n",rc);
+ return;
+ }
+ rc = DosWaitEventSem(SemHandle,-1);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitEventSem failed - rc == %ld\n",rc);
+ return;
+ }
+ DbgPrint("calling DosSendSignalException\n");
+ ChildPid = (PID)ResultCodes.ExitReason;
+ while (TRUE) {
+ rc = DosSendSignalException(ChildPid,
+ XCPT_SIGNAL_INTR);
+
+ if (rc) {
+ DbgPrint( "*** DosSendSignalException( %ld, %ld ) failed - rc == %ld\n",
+ ResultCodes.ExitReason,XCPT_SIGNAL_INTR, rc
+ );
+ break;
+ }
+ rc = DosWaitChild(DCWA_PROCESS,
+ DCWW_WAIT,
+ &ResultCodes,
+ &Pid,
+ (PID)0); // wait for any child
+ if (rc) {
+ DbgPrint( "*** DosWaitChild failed - rc == %ld\n",rc);
+ break;
+ }
+ else {
+ DbgPrint("returned from DosWaitChild successfully\n");
+ }
+ }
+ }
+ }
+ else {
+ Pib->CommandLine[0] += 1;
+ if (Pib->CommandLine[0] < 'E') {
+ CommandLine = Pib->CommandLine;
+ rc = DosExecPgm( ErrorBuffer,
+ sizeof( ErrorBuffer ),
+ EXEC_ASYNC,
+ CommandLine,
+ NULL,
+ &ResultCodes,
+ ImageFileName
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExecPgm( %s, %s ) failed - rc == %ld\n",
+ ImageFileName, CommandLine, rc
+ );
+ return;
+ }
+ }
+ rc = DosSetSignalExceptionFocus(TRUE,
+ &NestingLevel);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosSetSignalExceptionFocus failed - rc == %ld\n",rc);
+ return;
+ }
+ DbgPrint("NestingLevel is %ld\n",NestingLevel);
+ if (Pib->CommandLine[0] == 'E') {
+ rc = DosOpenEventSem("\\SEM32\\SIGSEM",
+ &SemHandle);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosOpenEventSem failed - rc == %ld\n",rc);
+ }
+ DbgPrint("posting event\n");
+ rc = DosPostEventSem(SemHandle);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosPostEventSem failed - rc == %ld\n",rc);
+ }
+ }
+ try {
+ while (TRUE)
+ DbgPrint("looping in %c\n",Pib->CommandLine[0]);
+ } except( PrintExceptionCode(GetExceptionInformation(),Pib->CommandLine[0],XCPT_CONTINUE_SEARCH ) ) {
+ DbgPrint("in exception handler\n");
+ ASSERT ( FALSE );
+ }
+ }
+}
+
+VOID
+TestWaitThread0(
+ IN UCHAR ThreadChar
+ )
+{
+ CHAR ThreadName[2];
+ APIRET rc;
+ HEV SemHandle;
+
+ ThreadName[0] = ThreadChar;
+ ThreadName[1] = '\0';
+
+ DbgPrint( "*** Entering OS/2 Thread%s\n", (PCH)ThreadName );
+ rc = DosOpenEventSem("\\SEM32\\SIGSEM",
+ &SemHandle);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosOpenEventSem failed - rc == %ld\n",rc);
+ return;
+ }
+ DbgPrint("posting event\n");
+ rc = DosPostEventSem(SemHandle);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosPostEventSem failed - rc == %ld\n",rc);
+ return;
+ }
+ while (TRUE)
+ ;
+
+ DbgPrint( "*** Exiting OS/2 Thread%s\n", (PCH)ThreadName );
+}
+
+VOID
+WaitBlockTest( VOID )
+
+//
+// This tests the wait block functions in the server
+//
+
+{
+ PPIB Pib;
+ PNT_TIB Tib;
+ APIRET rc;
+ PCH ImageFileName, CommandLine;
+ RESULTCODES ResultCodes;
+ ULONG NestingLevel;
+ CHAR ErrorBuffer[ 32 ];
+ PID Pid;
+ HEV SemHandle;
+ PID ChildPid;
+ TID ThreadAId;
+
+ rc = DosGetThreadInfo( &Tib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ return;
+ }
+
+ ImageFileName = "c:\\nt\\bin\\os2sig.exe";
+ DbgPrint("CommandLine is %s\n",Pib->CommandLine);
+ if (Pib->CommandLine[1] != 0) {
+ CommandLine = "A\000";
+ rc = DosExecPgm( ErrorBuffer,
+ sizeof( ErrorBuffer ),
+ EXEC_ASYNC,
+ CommandLine,
+ NULL,
+ &ResultCodes,
+ ImageFileName
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExecPgm( %s, %s ) failed - rc == %ld\n",
+ ImageFileName, CommandLine, rc
+ );
+ }
+ else {
+ rc = DosCreateEventSem("\\SEM32\\SIGSEM", // wait for the other processes to be created
+ &SemHandle,
+ 0,
+ FALSE);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem failed - rc == %ld\n",rc);
+ return;
+ }
+ rc = DosWaitEventSem(SemHandle,-1);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitEventSem failed - rc == %ld\n",rc);
+ return;
+ }
+ DbgPrint("calling DosSendSignalException\n");
+ ChildPid = (PID)ResultCodes.ExitReason;
+ rc = DosSendSignalException(ChildPid,
+ XCPT_SIGNAL_INTR);
+
+ if (rc) {
+ DbgPrint( "*** DosSendSignalException( %ld, %ld ) failed - rc == %ld\n",
+ ResultCodes.ExitReason,XCPT_SIGNAL_INTR, rc
+ );
+ return;
+ }
+ rc = DosWaitChild(DCWA_PROCESS,
+ DCWW_WAIT,
+ &ResultCodes,
+ &Pid,
+ (PID)0); // wait for any child
+ if (rc) {
+ DbgPrint( "*** DosWaitChild failed - rc == %ld\n",rc);
+ return;
+ }
+ else {
+ DbgPrint("returned from DosWaitChild successfully\n");
+ }
+
+ }
+ }
+ else {
+ rc = DosSetSignalExceptionFocus(TRUE,
+ &NestingLevel);
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosSetSignalExceptionFocus failed - rc == %ld\n",rc);
+ return;
+ }
+ DbgPrint("NestingLevel is %ld\n",NestingLevel);
+ rc = DosCreateThread( &ThreadAId,
+ (PFNTHREAD)TestWaitThread0,
+ (ULONG)'a',
+ DCT_SUSPENDED,
+ 0x10000
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateThread( ThreadA ) failed - rc == %ld\n",
+ rc
+ );
+ return;
+ }
+ rc = DosResumeThread( ThreadAId );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosResumeThread( ThreadA ) failed - rc == %ld\n",
+ rc
+ );
+ }
+ try {
+ rc = DosWaitThread( &ThreadAId, DCWW_WAIT );
+ if (rc != ERROR_INTERRUPT) {
+ DbgPrint( "*** DosWaitThread( ThreadA ) failed - rc == %ld\n",
+ rc
+ );
+ DbgPrint( " ERROR_INTERRUPT expected.\n");
+ }
+ else {
+ DbgPrint("returned from DosWaitThread successfully\n");
+ }
+ } except ( PrintExceptionCode(GetExceptionInformation(),'B',XCPT_CONTINUE_EXECUTION ) ) {
+ ASSERT (FALSE);
+ }
+ }
+}
diff --git a/private/os2/client/os2task.c b/private/os2/client/os2task.c
new file mode 100644
index 000000000..d090d8818
--- /dev/null
+++ b/private/os2/client/os2task.c
@@ -0,0 +1,870 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2task.c
+
+Abstract:
+
+ This is a test OS/2 application to test the Tasking component of OS/2
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define OS2_API32
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_SEMAPHORES
+#include <os2.h>
+
+PCHAR NullApiArguments[] = {
+ "String Number One",
+ "String Number Two",
+ "String Number Three",
+ NULL
+};
+
+PCH ImageFileName;
+
+PSZ
+DumpPib(
+ PPIB Pib,
+ int argc,
+ char *argv[],
+ char *envp[]
+ );
+
+VOID
+TestTask(
+ int argc,
+ char *argv[],
+ char *envp[]
+ );
+
+int
+main(
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+ int i;
+
+ DbgPrint( "*** Entering OS/2 Test Application\n" );
+
+ TestTask( argc, argv, envp );
+
+ DbgPrint( "*** Exiting OS/2 Test Application\n" );
+ return( 0 );
+}
+
+VOID
+ExitRoutine1(
+ ULONG ExitReason
+ )
+{
+ DbgPrint( "*** ExitRoutine1( %lX ) called\n", ExitReason );
+ DosExitList( EXLST_EXIT, NULL );
+}
+
+VOID
+ExitRoutine2(
+ ULONG ExitReason
+ )
+{
+ DbgPrint( "*** ExitRoutine2( %lX ) called\n", ExitReason );
+ DosExitList( EXLST_EXIT, NULL );
+}
+
+VOID
+ExitRoutine3(
+ ULONG ExitReason
+ )
+{
+ DbgPrint( "*** ExitRoutine3( %lX ) called\n", ExitReason );
+ DosExitList( EXLST_EXIT, NULL );
+}
+
+VOID
+TestThread0(
+ IN UCHAR ThreadChar
+ )
+{
+ CHAR ThreadName[2];
+
+ ThreadName[0] = ThreadChar;
+ ThreadName[1] = '\0';
+
+ DbgPrint( "*** Entering OS/2 Thread%s\n", (PCH)ThreadName );
+ if (ThreadChar == 'b') {
+ DosSleep( 1000 );
+ }
+ else
+ if (ThreadChar == 'd') {
+ DosEnterCritSec();
+ }
+
+ DbgPrint( "*** Exiting OS/2 Thread%s\n", (PCH)ThreadName );
+}
+
+
+VOID
+TestThread1(
+ IN PCH ThreadName
+ )
+{
+ APIRET rc;
+ PPIB Pib;
+ PNT_TIB NtTib;
+
+ DbgPrint( "*** Entering OS/2 Thread %s\n", ThreadName );
+
+ rc = DosGetThreadInfo( &NtTib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ }
+ else {
+ DbgPrint( " OS/2 Thread Information Block (NtTib) at %lX\n", NtTib );
+ DbgPrint( " ExceptionList: %lX\n", NtTib->ExceptionList );
+ DbgPrint( " StackBase: %lX\n", NtTib->StackBase );
+ DbgPrint( " StackLimit: %lX\n", NtTib->StackLimit );
+ DbgPrint( " Os2Tib ptr: %lx\n", NtTib->SubSystemTib );
+ DbgPrint( " Version: %lx\n", NtTib->Version );
+ DbgPrint( " UserPointer: %lx\n", NtTib->ArbitraryUserPointer );
+ DbgPrint( " Os2Tib part of TIB (Os2Tib) at %lx\n", NtTib->SubSystemTib );
+ DbgPrint( " ThreadId: %lX\n",
+ ((POS2_TIB)(NtTib->SubSystemTib))->ThreadId );
+ DbgPrint( " Priority: %lX\n",
+ ((POS2_TIB)(NtTib->SubSystemTib))->Priority );
+ DbgPrint( " Version: %lX\n",
+ ((POS2_TIB)(NtTib->SubSystemTib))->Version );
+ DbgPrint( " MustCompleteCount: %lX\n",
+ ((POS2_TIB)(NtTib->SubSystemTib))->MustCompleteCount );
+ DbgPrint( " MustCompleteForceFlag: %lX\n",
+ ((POS2_TIB)(NtTib->SubSystemTib))->MustCompleteForceFlag );
+ }
+
+ DbgPrint( "*** Exiting OS/2 Thread %s\n", ThreadName );
+}
+
+HEV TerminateEventHandle;
+TID ThreadIds[ 512 ];
+
+VOID
+TestThread2(
+ IN ULONG ThreadIndex
+ )
+{
+ APIRET rc;
+
+ rc = DosWaitEventSem( TerminateEventHandle, -1 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitEventSem( %lX ) failed - rc == %d\n",
+ TerminateEventHandle,
+ rc
+ );
+ }
+
+ DosExit( EXIT_THREAD, 0 );
+}
+
+
+PID
+CloneTest( ULONG ExecFlags );
+
+BOOLEAN
+IsClonedTest( VOID );
+
+PID
+CloneTest( ULONG ExecFlags )
+{
+ APIRET rc;
+ PCH CommandLine;
+ CHAR ErrorBuffer[ 32 ];
+ RESULTCODES ResultCodes;
+
+ CommandLine = "CLONETEST\000";
+ rc = DosExecPgm( ErrorBuffer,
+ sizeof( ErrorBuffer ),
+ ExecFlags,
+ CommandLine,
+ NULL,
+ &ResultCodes,
+ ImageFileName
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExecPgm( %s, %s ) failed - rc == %ld\n",
+ ImageFileName, CommandLine, rc
+ );
+ }
+ else
+ if (ExecFlags == EXEC_SYNC) {
+ if (ResultCodes.ExitResult != 0xA5A5) {
+ DbgPrint( "*** DosExecPgm( %s, %s ) return reason == %ld, rc == %ld\n",
+ ImageFileName, CommandLine,
+ ResultCodes.ExitReason,
+ ResultCodes.ExitResult
+ );
+ }
+ }
+ else {
+ DbgPrint( "*** DosExecPgm( %s, %s ) Flags == %ld, PID == %lx\n",
+ ImageFileName, CommandLine,
+ ExecFlags,
+ ResultCodes.ExitReason
+ );
+ return( (PID)ResultCodes.ExitReason );
+ }
+
+ return( NULL );
+}
+
+
+BOOLEAN
+IsClonedTest( VOID )
+{
+ PPIB Pib;
+ PNT_TIB NtTib;
+ APIRET rc;
+
+ rc = DosGetThreadInfo( &NtTib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ return( FALSE );
+ }
+
+ if (!strcmp( Pib->CommandLine, "CLONETEST" )) {
+ return( TRUE );
+ }
+ else {
+ return( FALSE );
+ }
+}
+
+
+VOID
+TestTask(
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+ APIRET rc;
+ PPIB Pib;
+ PNT_TIB NtTib;
+ BOOL32 Verify;
+ PUCHAR src, dst;
+ PSZ VariableName, VariableValue, PathVariableValue;
+ int i;
+ PID Pid;
+ PID WaitPid;
+ TID Thread1Id;
+ TID Thread2Id;
+ TID ThreadAId;
+ TID ThreadBId;
+ TID ThreadCId;
+ TID ThreadDId;
+ TID ThreadXId;
+ RESULTCODES ResultCodes;
+ PCH Variables, CommandLine;
+ CHAR ErrorBuffer[ 32 ];
+ CHAR CharBuffer[ 256+32 ];
+
+ rc = DosExitList( -1, ExitRoutine1 );
+ if (rc != ERROR_INVALID_DATA) {
+ DbgPrint( "*** DosExitList(-1) failed incorrectly and returned (%lX)\n",
+ rc
+ );
+ }
+
+ rc = DosExitList( EXLST_EXIT, NULL );
+ if (rc != ERROR_INVALID_FUNCTION) {
+ DbgPrint( "*** DosExitList(EXLST_EXIT) failed incorrectly and returned (%lX)\n",
+ rc
+ );
+ }
+
+ rc = DosExitList( EXLST_ADD | 0x3000, ExitRoutine1 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_ADD) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosExitList( EXLST_ADD | 0x3000, ExitRoutine2 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_ADD) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosExitList( EXLST_ADD | 0xFF00, ExitRoutine3 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_ADD) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosExitList( EXLST_REMOVE, ExitRoutine1 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_REMOVE) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosExitList( EXLST_REMOVE, ExitRoutine2 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_REMOVE) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosExitList( EXLST_REMOVE, ExitRoutine3 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_REMOVE) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosExitList( EXLST_REMOVE, NULL );
+ if (rc != ERROR_PROC_NOT_FOUND) {
+ DbgPrint( "*** DosExitList(EXLST_REMOVE,NULL) failed incorrectly and returned (%lX)\n",
+ rc
+ );
+ }
+ rc = DosExitList( EXLST_ADD | 0x3000, ExitRoutine1 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_ADD) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosExitList( EXLST_ADD | 0x3000, ExitRoutine2 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_ADD) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosExitList( EXLST_ADD | 0xFF00, ExitRoutine3 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_ADD) failed - rc == %ld\n",
+ rc
+ );
+ }
+
+ rc = DosExecPgm( NULL,
+ 0,
+ EXEC_SYNC,
+ NULL,
+ NULL,
+ -1,
+ NULL
+ );
+ if (rc != ERROR_INVALID_ADDRESS) {
+ DbgPrint( "*** DosExecPgm( -1, NULL ) return incorrect rc == %ld\n",
+ rc
+ );
+ }
+
+ rc = DosGetThreadInfo( &NtTib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ }
+ else {
+ DbgPrint( " OS/2 Thread Information Block (NtTib) at %lX\n", NtTib );
+ DbgPrint( " ExceptionList: %lX\n", NtTib->ExceptionList );
+ DbgPrint( " StackBase: %lX\n", NtTib->StackBase );
+ DbgPrint( " StackLimit: %lX\n", NtTib->StackLimit );
+ DbgPrint( " Os2Tib ptr: %lx\n", NtTib->SubSystemTib );
+ DbgPrint( " Version: %lx\n", NtTib->Version );
+ DbgPrint( " UserPointer: %lx\n", NtTib->ArbitraryUserPointer );
+ DbgPrint( " Os2Tib part of TIB (Os2Tib) at %lx\n", NtTib->SubSystemTib );
+ DbgPrint( " ThreadId: %lX\n",
+ ((POS2_TIB)(NtTib->SubSystemTib))->ThreadId );
+ DbgPrint( " Priority: %lX\n",
+ ((POS2_TIB)(NtTib->SubSystemTib))->Priority );
+ DbgPrint( " Version: %lX\n",
+ ((POS2_TIB)(NtTib->SubSystemTib))->Version );
+ DbgPrint( " MustCompleteCount: %lX\n",
+ ((POS2_TIB)(NtTib->SubSystemTib))->MustCompleteCount );
+ DbgPrint( " MustCompleteForceFlag: %lX\n",
+ ((POS2_TIB)(NtTib->SubSystemTib))->MustCompleteForceFlag );
+ }
+
+ rc = DosQueryVerify( &Verify );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosQueryVerify failed - rc == %ld\n", rc );
+ }
+ else {
+ DbgPrint( " Verify Flag: %ld\n", Verify );
+ }
+
+ PathVariableValue = DumpPib( Pib, argc, argv, envp );
+
+ if (IsClonedTest()) {
+ rc = DosCreateEventSem( NULL, &TerminateEventHandle, 0, FALSE );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateEventSem failed - rc == %ld\n", rc );
+ }
+ else {
+ i = 0;
+ while (TRUE) {
+ rc = DosCreateThread( &ThreadIds[ i ],
+ (PFNTHREAD)TestThread2,
+ i,
+ DCT_RUNABLE,
+ 0x10000
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateThread failed - rc == %ld\n",
+ rc
+ );
+ break;
+ }
+
+ i++;
+ }
+
+ DbgPrint( "%ld threads created - signaling them to terminate\n", i );
+ rc = DosPostEventSem( TerminateEventHandle );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosPostEventSem( %X ) failed - rc == %ld\n",
+ TerminateEventHandle,
+ rc
+ );
+ }
+ }
+
+ while (TRUE) {
+ Thread2Id = 0;
+ rc = DosWaitThread( &Thread2Id, DCWW_WAIT );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitThread( Thread2 ) failed - rc == %ld\n",
+ rc
+ );
+ break;
+ }
+ }
+
+ DbgPrint( "*** Exiting OS/2 Test Application (CLONETEST)\n" );
+ DosExit( EXIT_THREAD, 0xA5A5 );
+ return;
+ }
+
+ CommandLine = strcpy( CharBuffer, "CLONETEST" );
+ src = CommandLine;
+ while (*src++) {
+ ;
+ }
+
+ Variables = src;
+ i = 256;
+ while (i--) {
+ *src++ = (UCHAR)i;
+ }
+ *src = '\0';
+
+ rc = DosExecPgm( ErrorBuffer,
+ sizeof( ErrorBuffer ),
+ EXEC_SYNC,
+ CommandLine,
+ Variables,
+ &ResultCodes,
+ ImageFileName
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExecPgm( %s, %s ) failed - rc == %ld\n",
+ ImageFileName, CommandLine, rc
+ );
+ }
+
+ rc = DosWaitChild( DCWA_PROCESSTREE,
+ DCWW_WAIT,
+ &ResultCodes,
+ &WaitPid,
+ 0
+ );
+ if (rc != ERROR_WAIT_NO_CHILDREN) {
+ DbgPrint( "*** DosWaitChild failed - rc == %ld\n",
+ rc
+ );
+ }
+
+
+ rc = DosCreateThread( &Thread1Id,
+ (PFNTHREAD)TestThread1,
+ (ULONG)((PSZ)"Test Thread 1"),
+ 0,
+ 0
+ );
+ if (rc != ERROR_INVALID_PARAMETER) {
+ DbgPrint( "*** DosCreateThread failed incorrectly - rc == %ld\n",
+ rc
+ );
+ }
+
+ rc = DosCreateThread( &Thread1Id,
+ (PFNTHREAD)TestThread1,
+ (ULONG)((PSZ)"Test Thread 1"),
+ 0x80000000,
+ 0x10000
+ );
+ if (rc != ERROR_INVALID_PARAMETER) {
+ DbgPrint( "*** DosCreateThread failed incorrectly - rc == %ld\n",
+ rc
+ );
+ }
+
+ rc = DosCreateThread( &ThreadAId,
+ (PFNTHREAD)TestThread0,
+ (ULONG)'a',
+ DCT_SUSPENDED,
+ 0x10000
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateThread( ThreadA ) failed - rc == %ld\n",
+ rc
+ );
+ }
+
+ rc = DosCreateThread( &ThreadBId,
+ (PFNTHREAD)TestThread0,
+ (ULONG)'b',
+ DCT_SUSPENDED,
+ 0x10000
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateThread( ThreadB ) failed - rc == %ld\n",
+ rc
+ );
+ }
+
+ rc = DosCreateThread( &ThreadCId,
+ (PFNTHREAD)TestThread0,
+ (ULONG)'c',
+ DCT_SUSPENDED,
+ 0x10000
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateThread( ThreadC ) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosResumeThread( ThreadAId );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosResumeThread( ThreadA ) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosWaitThread( &ThreadAId, DCWW_WAIT );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitThread( ThreadA ) failed - rc == %ld\n",
+ rc
+ );
+ }
+
+ rc = DosResumeThread( ThreadBId );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosResumeThread( ThreadB ) failed - rc == %ld\n",
+ rc
+ );
+ }
+ ThreadXId = 0;
+ rc = DosWaitThread( &ThreadXId, DCWW_WAIT );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitThread( ThreadB ) failed - rc == %ld\n",
+ rc
+ );
+ }
+
+ rc = DosResumeThread( ThreadCId );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosResumeThread( ThreadC ) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosWaitThread( &ThreadCId, DCWW_WAIT );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosWaitThread( ThreadC ) failed - rc == %ld\n",
+ rc
+ );
+ }
+
+ rc = DosCreateThread( &ThreadDId,
+ (PFNTHREAD)TestThread0,
+ (ULONG)'d',
+ DCT_SUSPENDED,
+ 0x10000
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateThread( ThreadD ) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosResumeThread( ThreadDId );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosResumeThread( ThreadD ) failed - rc == %ld\n",
+ rc
+ );
+ }
+
+ DosSleep( 1000 ); // Let ThreadD run so it grabs CritSec and exits
+
+ rc = DosWaitThread( &ThreadDId, DCWW_WAIT );
+ if (rc != ERROR_INVALID_THREADID) {
+ DbgPrint( "*** DosWaitThread( ThreadD ) failed - rc == %ld\n",
+ rc
+ );
+ }
+
+ rc = DosCreateThread( &Thread1Id,
+ (PFNTHREAD)TestThread1,
+ (ULONG)((PSZ)"Test Thread 1"),
+ DCT_SUSPENDED,
+ 0x10000
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateThread failed - rc == %ld\n",
+ rc
+ );
+ }
+
+ rc = DosSetPriority( PRTYS_PROCESS,
+ PRTYC_REGULAR,
+ 16,
+ (ULONG)Pib->ProcessId
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosSetPriority( PROCESS ) failed - rc == %ld\n", rc );
+ }
+ DbgPrint( ">>> Priority: %lX\n",
+ ((POS2_TIB)(NtTib->SubSystemTib))->Priority );
+
+ rc = DosSetPriority( PRTYS_PROCESSTREE,
+ PRTYC_REGULAR,
+ 24,
+ 0
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosSetPriority( PROCESSTREE ) failed - rc == %ld\n", rc );
+ }
+ DbgPrint( ">>> Priority: %lX\n",
+ ((POS2_TIB)(NtTib->SubSystemTib))->Priority );
+
+ rc = DosSetPriority( PRTYS_THREAD,
+ PRTYC_TIMECRITICAL,
+ 16,
+ (ULONG)Thread1Id
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosSetPriority( THREAD ) failed - rc == %ld\n", rc );
+ }
+
+ rc = DosResumeThread( Thread1Id );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosResumeThread failed - rc == %ld\n", rc );
+ }
+
+ rc = DosSleep( 2000 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosSleep failed - rc == %ld\n", rc );
+ }
+
+
+ dst = NULL;
+ VariableName = "PATH";
+ rc = DosScanEnv( VariableName, &dst );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosScanEnv( %s ) failed - rc == %ld\n",
+ VariableName,
+ rc
+ );
+ }
+ else
+ if (dst != PathVariableValue) {
+ DbgPrint( "*** DosScanEnv( %s ) returned (%lX)%s\n", VariableName, dst );
+ DbgPrint( " instead of (%lX)%s\n", PathVariableValue );
+ }
+
+ src = "FOOBARBAZ";
+ dst = NULL;
+ rc = DosScanEnv( src, &dst );
+ if (rc == NO_ERROR) {
+ DbgPrint( "*** DosScanEnv( %s) did not fail and returned (%lX)%s\n",
+ src,
+ dst
+ );
+ }
+
+ CloneTest( EXEC_SYNC );
+
+ Pid = CloneTest( EXEC_ASYNC );
+ DosSleep( 10000 );
+ rc = DosWaitChild( DCWA_PROCESSTREE,
+ DCWW_WAIT,
+ &ResultCodes,
+ &WaitPid,
+ Pid
+ );
+ if (rc != ERROR_WAIT_NO_CHILDREN) {
+ DbgPrint( "*** DosWaitChild( %lx ) failed - rc == %ld\n",
+ Pid, rc
+ );
+ }
+
+ Pid = CloneTest( EXEC_ASYNCRESULT );
+ DosSleep( 10000 );
+ rc = DosWaitChild( DCWA_PROCESSTREE,
+ DCWW_WAIT,
+ &ResultCodes,
+ &WaitPid,
+ Pid
+ );
+ if (rc != NO_ERROR ||
+ ResultCodes.ExitResult != 0xA5A5 ||
+ Pid != WaitPid
+ ) {
+ DbgPrint( "*** DosWaitChild( %lx ) failed - rc == %ld (ExitResult == %lx, ResultPid == %lx)\n",
+ Pid, rc, ResultCodes.ExitResult, WaitPid
+ );
+ }
+
+ Pid = CloneTest( EXEC_ASYNC );
+ rc = DosWaitChild( DCWA_PROCESSTREE,
+ DCWW_WAIT,
+ &ResultCodes,
+ &WaitPid,
+ Pid
+ );
+ if (rc != NO_ERROR ||
+ ResultCodes.ExitResult != 0xA5A5 ||
+ Pid != WaitPid
+ ) {
+ DbgPrint( "*** DosWaitChild( %lx ) failed - rc == %ld (ExitResult == %lx, ResultPid == %lx)\n",
+ Pid, rc, ResultCodes.ExitResult, WaitPid
+ );
+ }
+}
+
+
+PSZ
+DumpPib(
+ PPIB Pib,
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+ ULONG i;
+ PUCHAR src, dst;
+ PSZ VariableName, VariableValue, PathVariableValue, RestoreEqualChar;
+
+ DbgPrint( " OS/2 Process Information Block (PIB) at %lX\n", Pib );
+ DbgPrint( " ProcessId: %lX\n", Pib->ProcessId );
+ DbgPrint( " ParentProcessId: %lX\n", Pib->ParentProcessId );
+ DbgPrint( " ImageFileHandle: %lX\n", Pib->ImageFileHandle );
+ DbgPrint( " CommandLine: %lX\n", Pib->CommandLine );
+ DbgPrint( " Environment: %lX\n", Pib->Environment );
+ DbgPrint( " Status: %lX\n", Pib->Status );
+ DbgPrint( " Type: %lX\n", Pib->Type );
+
+ PathVariableValue = NULL;
+
+ i = 0;
+ src = Pib->Environment;
+ while (*src) {
+ VariableName = src;
+ VariableValue = "(*** undefined ***)";
+ RestoreEqualChar = NULL;
+ while (*src) {
+ if (*src == '=') {
+ RestoreEqualChar = src;
+ *src++ = '\0';
+ if (!_stricmp( VariableName, "PATH" )) {
+ PathVariableValue = src;
+ }
+ VariableValue = src;
+ while (*src) {
+ if (*src < ' ' || *src > 0x7F) {
+ VariableValue = "(*** unprintable value ***)";
+ }
+
+ src++;
+ }
+
+ break;
+ }
+ else {
+ if (*src < ' ' || *src > 0x7F) {
+ VariableName = "(*** unprintable name ***)";
+ }
+
+ src++;
+ }
+ }
+
+ DbgPrint( " Env[ %ld ] - %s = %s\n",
+ i,
+ VariableName,
+ VariableValue
+ );
+ i++;
+ src++;
+ if (RestoreEqualChar) {
+ *RestoreEqualChar = '=';
+ }
+ }
+ src++;
+
+ ImageFileName = src;
+ DbgPrint( " ImagePathName: %s\n", ImageFileName );
+ while (*src) {
+ src++;
+ }
+ src++;
+
+ if (src != Pib->CommandLine) {
+ DbgPrint( " CommandLine at %lX, not %lX\n",
+ src,
+ Pib->CommandLine
+ );
+ }
+
+ i = 0;
+ while (*src) {
+ VariableValue = src;
+ while (*src) {
+ if (*src < ' ' || *src > 0x7F) {
+ VariableValue = "(*** unprintable argument ***)";
+ }
+ src++;
+ }
+
+ DbgPrint( " Arg[ %ld ] - %s\n", i, VariableValue );
+ i++;
+ src++;
+ }
+
+ DbgPrint( " C Runtime parameters passed to main()\n" );
+ DbgPrint( " argc: %d\n", argc );
+ i = 0;
+ while (argc--) {
+ DbgPrint( " argv[ %d ]: %s\n", i, *argv );
+ i++;
+ argv++;
+ }
+
+ i = 0;
+ while (src = *envp++) {
+ DbgPrint( " envp[ %d ]: %s\n", i, *envp );
+ i++;
+ envp++;
+ }
+
+ return( PathVariableValue );
+}
diff --git a/private/os2/client/os2test.c b/private/os2/client/os2test.c
new file mode 100644
index 000000000..690e9273b
--- /dev/null
+++ b/private/os2/client/os2test.c
@@ -0,0 +1,117 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2test.c
+
+Abstract:
+
+ This is a test OS/2 application
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define OS2_API32
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_TASKING
+#include <os2.h>
+
+VOID
+CloneTest( PPID ChildPid );
+
+BOOLEAN
+IsClonedTest( VOID );
+
+VOID
+CloneTest(
+ PPID ChildPid
+ )
+{
+ PPIB Pib;
+ PNT_TIB NtTib;
+ APIRET rc;
+ PCH src, Variables, ImageFileName, CommandLine;
+ CHAR ErrorBuffer[ 32 ];
+ RESULTCODES ResultCodes;
+
+ rc = DosGetThreadInfo( &NtTib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ return;
+ }
+
+ src = Pib->Environment;
+ Variables = src;
+ while (*src) {
+ while (*src) {
+ src++;
+ }
+ src++;
+ }
+ src++;
+ ImageFileName = src;
+ CommandLine = "CLONETEST\000";
+ rc = DosExecPgm( ErrorBuffer,
+ sizeof( ErrorBuffer ),
+ ChildPid == NULL ? EXEC_SYNC : EXEC_ASYNC,
+ CommandLine,
+ Variables,
+ &ResultCodes,
+ ImageFileName
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExecPgm( %s, %s failed - rc == %ld\n",
+ ImageFileName, CommandLine, rc
+ );
+ }
+ else {
+ if (ChildPid != NULL) {
+ *ChildPid = (PID)ResultCodes.ExitReason;
+ }
+ }
+}
+
+
+BOOLEAN
+IsClonedTest( VOID )
+{
+ PPIB Pib;
+ PNT_TIB NtTib;
+ APIRET rc;
+
+ rc = DosGetThreadInfo( &NtTib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ return( FALSE );
+ }
+
+ if (!strcmp( Pib->CommandLine, "CLONETEST" )) {
+ return( TRUE );
+ }
+ else {
+ return( FALSE );
+ }
+}
+
+
+int
+main(
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+ return( 0 );
+}
diff --git a/private/os2/client/os2vm.c b/private/os2/client/os2vm.c
new file mode 100644
index 000000000..ba4c756e6
--- /dev/null
+++ b/private/os2/client/os2vm.c
@@ -0,0 +1,507 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2vm.c
+
+Abstract:
+
+ This is a test OS/2 application to test the Virtual Memory component of OS/2
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define OS2_API32
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_MEMORY
+#include <os2.h>
+
+PPIB Pib;
+PNT_TIB NtTib;
+PSZ ImageFileName;
+
+PSZ
+DumpPib(
+ PPIB Pib,
+ int argc,
+ char *argv[],
+ char *envp[]
+ );
+
+VOID
+TestMemory( VOID );
+
+VOID
+ExitRoutine(
+ ULONG ExitReason
+ );
+
+VOID
+TestThread(
+ IN PCH ThreadName
+ );
+
+int
+main(
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+ APIRET rc;
+
+ DbgPrint( "*** Entering OS/2 Virtual Memory Test Application\n" );
+
+ rc = DosGetThreadInfo( &NtTib, &Pib );
+
+ DumpPib( Pib, argc, argv, envp );
+
+ rc = DosExitList( EXLST_ADD | 0x3000, ExitRoutine );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_ADD) failed - rc == %lX\n",
+ rc
+ );
+ }
+
+ TestMemory();
+
+ DbgPrint( "*** Exiting OS/2 Virtual Memory Test Application\n" );
+ return( 0 );
+}
+
+VOID
+ExitRoutine(
+ ULONG ExitReason
+ )
+{
+ DbgPrint( "*** ExitRoutine( %lX ) called\n", ExitReason );
+ DosExitList( EXLST_EXIT, NULL );
+}
+
+VOID
+TestThread(
+ IN PCH ThreadName
+ )
+{
+ APIRET rc;
+ PPIB Pib;
+ PNT_TIB NtTib;
+
+ DbgPrint( "*** Entering OS/2 Thread %s\n", ThreadName );
+
+ rc = DosGetThreadInfo( &NtTib, &Pib );
+
+ DbgPrint( "*** Leaveing OS/2 Thread %s\n", ThreadName );
+}
+
+
+VOID
+CloneTest( VOID );
+
+BOOLEAN
+IsClonedTest( VOID );
+
+VOID
+CloneTest( VOID )
+{
+ PPIB Pib;
+ PNT_TIB NtTib;
+ APIRET rc;
+ PCH src, Variables, ImageFileName, CommandLine;
+ CHAR ErrorBuffer[ 32 ];
+ RESULTCODES ResultCodes;
+
+ rc = DosGetThreadInfo( &NtTib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ return;
+ }
+
+ src = Pib->Environment;
+ Variables = src;
+ while (*src) {
+ while (*src) {
+ src++;
+ }
+ src++;
+ }
+ src++;
+ ImageFileName = src;
+ CommandLine = "CLONETEST\000";
+ rc = DosExecPgm( ErrorBuffer,
+ sizeof( ErrorBuffer ),
+ EXEC_SYNC,
+ CommandLine,
+ Variables,
+ &ResultCodes,
+ ImageFileName
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExecPgm( %s, %s failed - rc == %ld\n",
+ ImageFileName, CommandLine, rc
+ );
+ }
+}
+
+
+BOOLEAN
+IsClonedTest( VOID )
+{
+ PPIB Pib;
+ PNT_TIB NtTib;
+ APIRET rc;
+
+ rc = DosGetThreadInfo( &NtTib, &Pib );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetThreadInfo failed - rc == %ld\n", rc );
+ return( FALSE );
+ }
+
+ if (!strcmp( Pib->CommandLine, "CLONETEST" )) {
+ return( TRUE );
+ }
+ else {
+ return( FALSE );
+ }
+}
+
+
+PSZ MemoryNames[ 8 ] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "\\SHAREMEM\\Shared\\Memory\\1",
+ "\\sharemem\\Shared\\Memory\\2",
+ NULL,
+ NULL
+};
+
+ULONG MemoryFlags[ 8 ] = {
+ PAG_READ,
+ PAG_READ | PAG_WRITE,
+ PAG_COMMIT | PAG_READ,
+ PAG_COMMIT | PAG_READ | PAG_WRITE,
+ PAG_READ,
+ PAG_READ | PAG_WRITE,
+ PAG_COMMIT | PAG_READ | OBJ_GIVEABLE | OBJ_GETTABLE,
+ PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_GIVEABLE | OBJ_GETTABLE,
+};
+
+PSZ BadMemoryNames[] = {
+ "\\SHAREMEM\\a\\",
+#ifdef MIPS
+ NULL
+#else
+ "\\SHAREMEM\\a/",
+// 123456789012345678901234567890123456789012345678901234567890
+ "\\SHAREMEM\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaa", // 259 bytes long
+ "\\SHAREMEM\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaa", // 260 bytes long
+ "\\SHAREMEM\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaa", // 261 bytes long
+ "\\SHAREMEM\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
+aaaaaaaaaaaaaaaaaaaaaa", // 262 bytes long
+ NULL
+#endif // MIPS
+};
+
+VOID
+TestMemory( VOID )
+{
+ APIRET rc;
+ PVOID BaseAddress[ 8 ];
+ ULONG PostCount;
+ int i, j;
+ PCH s, s1;
+ ULONG cb;
+ PULONG p;
+
+ s = "\\sharemem\\a";
+ cb = 4*1024;
+
+ if (IsClonedTest()) {
+ rc = DosGetNamedSharedMem( &BaseAddress[ 0 ],
+ s,
+ PAG_READ
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGetNamedSharedMem( %s ) failed - rc == %ld\n",
+ s, rc
+ );
+ }
+ else {
+ p = (PULONG)BaseAddress[ 0 ];
+ for (i=0; i<(cb / sizeof( ULONG )); i++ ) {
+ if (*p != i) {
+ DbgPrint( "*** @%lX == %lX != %lX\n", p, *p, i );
+ break;
+ }
+
+ p++;
+ }
+ }
+
+ return;
+ }
+
+ for (i=0; s1=BadMemoryNames[i]; i++) {
+ rc = DosAllocSharedMem( &BaseAddress[ 0 ],
+ s1,
+ 0x1000,
+ PAG_COMMIT | PAG_READ | PAG_WRITE
+ );
+ if (rc == NO_ERROR && strlen( s1 ) <= CCHMAXPATH) {
+ DosFreeMem( BaseAddress[ 0 ] );
+ }
+ else
+ if (rc != ERROR_INVALID_NAME) {
+ DbgPrint( "*** DosAllocSharedMem( %s ) returned incorrect rc == %ld\n",
+ s1, rc
+ );
+
+ if (rc == NO_ERROR) {
+ DosFreeMem( BaseAddress[ 0 ] );
+ }
+ }
+ }
+
+ rc = DosAllocSharedMem( &BaseAddress[ 0 ],
+ s,
+ cb,
+ PAG_READ
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosAllocSharedMem( %s, %ld ) failed - rc == %ld\n",
+ s, cb, rc
+ );
+ return;
+ }
+
+ rc = DosGiveSharedMem( BaseAddress[ 0 ], Pib->ProcessId, PAG_WRITE );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosGiveSharedMem( %X, PAG_WRITE ) failed - rc == %ld\n",
+ BaseAddress[ 0 ], rc
+ );
+ return;
+ }
+
+ rc = DosSetMem( BaseAddress[ 0 ], cb, PAG_DEFAULT | PAG_COMMIT );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosSetMem( %X, PAG_DEFAULT | PAG_COMMIT ) failed - rc == %ld\n",
+ BaseAddress[ 0 ], rc
+ );
+ return;
+ }
+
+ p = (PULONG)BaseAddress[ 0 ];
+ for (i=0; i<(cb / sizeof( ULONG )); i++ ) {
+ try {
+ *p++ = i;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER ) {
+ DbgPrint( "*** [%X] = %d - failed, Status = %X\n",
+ p, i, GetExceptionCode()
+ );
+ return;
+ }
+ }
+
+ CloneTest();
+
+ DosFreeMem( BaseAddress[ 0 ] );
+ rc = DosAllocSharedMem( &BaseAddress[ 0 ],
+ s,
+ cb,
+ PAG_COMMIT | PAG_READ | PAG_WRITE
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** 2nd DosAllocSharedMem( %s, %ld ) failed - rc == %ld\n",
+ s, cb, rc
+ );
+ }
+
+ for (i=0; i<8; i++) {
+ if (i < 4) {
+ rc = DosAllocMem( &BaseAddress[i],
+ 64*1024,
+ MemoryFlags[i]
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosAllocMem( %ld ) failed - rc == %lX\n",
+ 64*1024, rc
+ );
+ BaseAddress[i] = (PVOID)0;
+ }
+ else {
+ DbgPrint( "*** DosAllocMem( %ld ) success - Address == %lX\n",
+ 64*1024, BaseAddress[i]
+ );
+ }
+ }
+ else {
+ rc = DosAllocSharedMem( &BaseAddress[i],
+ MemoryNames[i],
+ 64*1024,
+ MemoryFlags[i]
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosAllocSharedMem( %s, %ld ) failed - rc == %lX\n",
+ MemoryNames[i] ? MemoryNames[i] : "shared",
+ 64*1024
+ );
+ BaseAddress[i] = (PVOID)0;
+ }
+ else {
+ DbgPrint( "*** DosAllocSharedMem( %s, %ld ) success - Address == %lX\n",
+ MemoryNames[i] ? MemoryNames[i] : "shared",
+ 64*1024,
+ BaseAddress[i]
+ );
+ }
+ }
+ }
+}
+
+
+PSZ
+DumpPib(
+ PPIB Pib,
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+ ULONG i;
+ PUCHAR src, dst;
+ PSZ VariableName, VariableValue, PathVariableValue, RestoreEqualChar;
+
+ DbgPrint( " OS/2 Process Information Block (PIB) at %lX\n", Pib );
+ DbgPrint( " ProcessId: %lX\n", Pib->ProcessId );
+ DbgPrint( " ParentProcessId: %lX\n", Pib->ParentProcessId );
+ DbgPrint( " ImageFileHandle: %lX\n", Pib->ImageFileHandle );
+ DbgPrint( " CommandLine: %lX\n", Pib->CommandLine );
+ DbgPrint( " Environment: %lX\n", Pib->Environment );
+ DbgPrint( " Status: %lX\n", Pib->Status );
+ DbgPrint( " Type: %lX\n", Pib->Type );
+
+ PathVariableValue = NULL;
+
+ i = 0;
+ src = Pib->Environment;
+ while (*src) {
+ VariableName = src;
+ VariableValue = "(*** undefined ***)";
+ RestoreEqualChar = NULL;
+ while (*src) {
+ if (*src == '=') {
+ RestoreEqualChar = src;
+ *src++ = '\0';
+ if (!_stricmp( VariableName, "PATH" )) {
+ PathVariableValue = src;
+ }
+ VariableValue = src;
+ while (*src) {
+ if (*src < ' ' || *src > 0x7F) {
+ VariableValue = "(*** unprintable value ***)";
+ }
+
+ src++;
+ }
+
+ break;
+ }
+ else {
+ if (*src < ' ' || *src > 0x7F) {
+ VariableName = "(*** unprintable name ***)";
+ }
+
+ src++;
+ }
+ }
+
+ DbgPrint( " Env[ %ld ] - %s = %s\n",
+ i,
+ VariableName,
+ VariableValue
+ );
+ i++;
+ src++;
+ if (RestoreEqualChar) {
+ *RestoreEqualChar = '=';
+ }
+ }
+ src++;
+
+ ImageFileName = src;
+ DbgPrint( " ImagePathName: %s\n", ImageFileName );
+ while (*src) {
+ src++;
+ }
+ src++;
+
+ if (src != Pib->CommandLine) {
+ DbgPrint( " CommandLine at %lX, not %lX\n",
+ src,
+ Pib->CommandLine
+ );
+ }
+
+ i = 0;
+ while (*src) {
+ VariableValue = src;
+ while (*src) {
+ if (*src < ' ' || *src > 0x7F) {
+ VariableValue = "(*** unprintable argument ***)";
+ }
+ src++;
+ }
+
+ DbgPrint( " Arg[ %ld ] - %s\n", i, VariableValue );
+ i++;
+ src++;
+ }
+
+ DbgPrint( " C Runtime parameters passed to main()\n" );
+ DbgPrint( " argc: %d\n", argc );
+ i = 0;
+ while (argc--) {
+ DbgPrint( " argv[ %d ]: %s\n", i, *argv );
+ i++;
+ argv++;
+ }
+
+ i = 0;
+ while (src = *envp++) {
+ DbgPrint( " envp[ %d ]: %s\n", i, *envp );
+ i++;
+ envp++;
+ }
+
+ return( PathVariableValue );
+}
diff --git a/private/os2/client/os2xcpt.c b/private/os2/client/os2xcpt.c
new file mode 100644
index 000000000..1c266ec7b
--- /dev/null
+++ b/private/os2/client/os2xcpt.c
@@ -0,0 +1,188 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2xcpt.c
+
+Abstract:
+
+ This is a test OS/2 application to test the exception/signal component
+ of OS/2
+
+Author:
+
+ Therese Stowell (thereses) 17-July-1990
+
+Environment:
+
+ User Mode Only.
+
+ This test must be run under the session manager or cmd.exe so that
+ the user's process has an exception port set up.
+
+Revision History:
+
+--*/
+
+#define OS2_API32
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_EXCEPTIONS
+#include <os2.h>
+
+PCHAR NullApiArguments[] = {
+ "String Number One",
+ "String Number Two",
+ "String Number Three",
+ NULL
+};
+
+VOID
+ExceedStackTest( VOID );
+
+VOID
+TestExit( VOID );
+
+int
+main(
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+ int i;
+
+ DbgPrint( "*** Entering OS/2 Test Application\n" );
+
+ //TestExit();
+ ExceedStackTest();
+
+ DbgPrint( "*** Exiting OS/2 Test Application\n" );
+ return( 0 );
+}
+
+VOID
+ExitRoutine1(
+ ULONG ExitReason
+ )
+{
+ DbgPrint( "*** ExitRoutine1( %lX ) called\n", ExitReason );
+ DosExitList( EXLST_EXIT, NULL );
+}
+
+VOID
+ExitRoutine2(
+ ULONG ExitReason
+ )
+{
+ DbgPrint( "*** ExitRoutine2( %lX ) called\n", ExitReason );
+ DosExitList( EXLST_EXIT, NULL );
+}
+
+VOID
+ExitRoutine3(
+ ULONG ExitReason
+ )
+{
+ DbgPrint( "*** ExitRoutine3( %lX ) called\n", ExitReason );
+ DosExitList( EXLST_EXIT, NULL );
+}
+
+VOID
+TestThread0(
+ IN UCHAR ThreadChar
+ )
+{
+ CHAR ThreadName[2];
+
+ ThreadName[0] = ThreadChar;
+ ThreadName[1] = '\0';
+
+ DbgPrint( "*** Entering OS/2 Thread%s\n", (PCH)ThreadName );
+ while (TRUE)
+ ;
+
+ DbgPrint( "*** Exiting OS/2 Thread%s\n", (PCH)ThreadName );
+}
+
+
+VOID
+ExceedStack(
+ ULONG Depth
+ )
+{
+ UCHAR BigArray[3000];
+
+ if (Depth < 1000) {
+ DbgPrint("Depth is %ld\n",Depth);
+ ExceedStack(Depth+1);
+ }
+}
+
+
+VOID
+ExceedStackTest( VOID )
+
+//
+// This tests the handling of a guard page fault on the stack. this and
+// the can't grow stack are the only non-fatal exceptions.
+//
+
+{
+ ExceedStack(0);
+}
+
+VOID
+TestExit( VOID )
+
+//
+// This tests synchronization of exiting between threads.
+//
+
+{
+ TID ThreadAId;
+ APIRET rc;
+
+ rc = DosExitList( EXLST_ADD | 0x3000, ExitRoutine1 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_ADD) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosExitList( EXLST_ADD | 0x3000, ExitRoutine2 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_ADD) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosExitList( EXLST_ADD | 0xFF00, ExitRoutine3 );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosExitList(EXLST_ADD) failed - rc == %ld\n",
+ rc
+ );
+ }
+ rc = DosCreateThread( &ThreadAId,
+ (PFNTHREAD)TestThread0,
+ (ULONG)'a',
+ DCT_SUSPENDED,
+ 0x10000
+ );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosCreateThread( ThreadA ) failed - rc == %ld\n",
+ rc
+ );
+ }
+
+ rc = DosResumeThread( ThreadAId );
+ if (rc != NO_ERROR) {
+ DbgPrint( "*** DosResumeThread( ThreadA ) failed - rc == %ld\n",
+ rc
+ );
+ }
+
+ DbgPrint("Exiting thread 1\n");
+ DosExit( EXIT_PROCESS, 0xA5A5 );
+}
diff --git a/private/os2/client/packoff.h b/private/os2/client/packoff.h
new file mode 100644
index 000000000..0e0e2f4b2
--- /dev/null
+++ b/private/os2/client/packoff.h
@@ -0,0 +1,34 @@
+/*++
+
+Copyright (c) 1990,91 Microsoft Corporation
+
+Module Name:
+
+ packoff.h
+
+Abstract:
+
+ This file turns packing of structures off. (That is, it enables
+ automatic alignment of structure fields.) An include file is needed
+ because various compilers do this in different ways.
+
+ packoff.h is the complement to packon.h. An inclusion of packoff.h
+ MUST ALWAYS be preceded by an inclusion of packon.h, in one-to-one
+ correspondence.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 4-Mar-1990
+
+Revision History:
+
+ 15-Apr-1991 JohnRo
+ Created lint-able variant.
+--*/
+
+#if ! (defined(lint) || defined(_lint))
+#if ( _MSC_VER >= 800 )
+#pragma warning(disable:4103)
+#endif
+#pragma pack()
+#endif // ! (defined(lint) || defined(_lint))
diff --git a/private/os2/client/packon.h b/private/os2/client/packon.h
new file mode 100644
index 000000000..e42281399
--- /dev/null
+++ b/private/os2/client/packon.h
@@ -0,0 +1,32 @@
+/*++
+
+Copyright (c) 1990,91 Microsoft Corporation
+
+Module Name:
+
+ packon.h
+
+Abstract:
+
+ This file turns packing of structures on. (That is, it disables
+ automatic alignment of structure fields.) An include file is needed
+ because various compilers do this in different ways.
+
+ The file packoff.h is the complement to this file.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 4-Mar-1990
+
+Revision History:
+
+ 15-Apr-1991 JohnRo
+ Created lint-able variant.
+--*/
+
+#if ! (defined(lint) || defined(_lint))
+#if ( _MSC_VER >= 800 )
+#pragma warning(disable:4103)
+#endif
+#pragma pack(1) // x86, MS compiler; MIPS, MIPS compiler
+#endif // ! (defined(lint) || defined(_lint))
diff --git a/private/os2/client/rap.h b/private/os2/client/rap.h
new file mode 100644
index 000000000..5f6ab3b47
--- /dev/null
+++ b/private/os2/client/rap.h
@@ -0,0 +1,376 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ Rap.h
+
+Abstract:
+
+ This header file contains procedure prototypes for Remote Admin Protocol
+ (RAP) routines. These routines are shared between XactSrv and RpcXlate.
+
+Author:
+
+ David Treadwell (davidtr) 08-Jan-1991
+ Shanku Niyogi (w-shanku)
+ John Rogers (JohnRo)
+
+Environment:
+
+ Portable to any flat, 32-bit environment. (Uses Win32 typedefs.)
+ Requires ANSI C extensions: slash-slash comments, long external names.
+
+Revision History:
+
+ 05-Mar-1991 JohnRo
+ Extracted Rap routines from XactSrv (Xs) code.
+ 26-Mar-1991 JohnRo
+ Added FORMAT_LPDESC (for debugging). Include <ctype.h>.
+ 21-Apr-1991 JohnRo
+ Added RapIsValidDescriptorSmb(). Reduced recompiles.
+ Make it clear that RapAsciiToDecimal updates the pointer it is given.
+ RapConvertSingleEntry's BytesRequired is not OPTIONAL.
+ Clarify that OutStructure is OUT, not IN.
+ 06-May-1991 JohnRo
+ Added DESC_CHAR typedef.
+ 14-May-1991 JohnRo
+ Added DESCLEN() and FORMAT_DESC_CHAR macros.
+ 15-May-1991 JohnRo
+ Added conversion mode handling. Added native vs. RAP handling.
+ 05-Jun-1991 JohnRo
+ Added RapTotalSize(). Make output structure OPTIONAL for convert
+ single entry; this will be used by RapTotalSize().
+ 10-Jul-1991 JohnRo
+ Added RapStructureAlignment() for use by RxpConvertDataStructures().
+ 22-Jul-1991 RFirth
+ Added MAX_DESC_SUBSTRING
+ 19-Aug-1991 JohnRo
+ Added DESC_CHAR_IS_DIGIT() macro (to improve UNICODE conversion).
+ 10-Sep-1991 JohnRo
+ Added DESC_DIGIT_TO_NUM(), to support changes suggested by PC-LINT.
+ 07-Oct-1991 JohnRo
+ Correct MAX_DESC_SUBSTRING.
+ Use DESC_CHAR_IS_DIGIT() in t-JamesW's new macros.
+ 07-Feb-1992 JohnRo
+ Added RapCharSize() macro.
+ 06-May-1993 JohnRo
+ RAID 8849: Export RxRemoteApi for DEC and others.
+
+--*/
+
+#ifndef _RAP_
+#define _RAP_
+
+
+// These must be included first:
+
+#include <windef.h> // BOOL, CHAR, DWORD, IN, LPBYTE, etc.
+#include <lmcons.h> // NET_API_STATUS
+
+// These may be included in any order:
+
+#include <lmremutl.h> // DESC_CHAR and LPDESC_CHAR typedefs.
+
+
+#ifndef DESC_CHAR_UNICODE
+
+#include <ctype.h> // isdigit().
+#include <string.h> // strlen() (only needed for DESCLEN()).
+
+//
+// The descriptor strings are really ASCIIZ strings, and are not expected to
+// be translated into Unicode. So, let's define a type for them just to
+// make this clearer. (That'll also make it easier to change to Unicode later
+// if I'm wrong. --JR)
+//
+
+//typedef CHAR DESC_CHAR;
+
+// DESCLEN(desc): return number of characters (not including null) in desc:
+#define DESCLEN(desc) strlen(desc)
+
+// DESC_CHAR_IS_DIGIT(descchar): return nonzero iff descchar is a digit.
+#define DESC_CHAR_IS_DIGIT(descchar) isdigit(descchar)
+
+// DESC_DIGIT_TO_NUM(descchar): return integer value of descchar.
+#define DESC_DIGIT_TO_NUM(descchar) \
+ ( (DWORD) ( ((int)(descchar)) - ((int) '0') ) )
+
+//
+// Format strings for NetpDbgPrint use (see NetDebug.h). Note that
+// FORMAT_LPDESC_CHAR will go away one of these days.
+//
+#define FORMAT_DESC_CHAR "%c"
+#define FORMAT_LPDESC "%s"
+#define FORMAT_LPDESC_CHAR "%c"
+
+#else // DESC_CHAR_UNICODE is defined
+
+//
+// The descriptor strings are really ASCIIZ strings, and are not expected to
+// be translated into Unicode. So, let's define a type for them just to
+// make this clearer. (That'll also make it easier to change to Unicode later
+// if I'm wrong. --JR)
+//
+
+#include <wchar.h> // iswdigit(), wcslen().
+
+//typedef WCHAR DESC_CHAR;
+
+// DESCLEN(desc): return number of characters (not including null) in desc:
+#define DESCLEN(desc) wcslen(desc)
+
+// DESC_CHAR_IS_DIGIT(descchar): return nonzero iff descchar is a digit.
+#define DESC_CHAR_IS_DIGIT(descchar) iswdigit(descchar)
+
+// DESC_DIGIT_TO_NUM(descchar): return integer value of descchar.
+#define DESC_DIGIT_TO_NUM(descchar) \
+ ( (DWORD) ( ((int)(descchar)) - ((int) L'0') ) )
+
+//
+// Format strings for NetpDbgPrint use (see NetDebug.h). Note that
+// FORMAT_LPDESC_CHAR will go away one of these days.
+//
+#define FORMAT_DESC_CHAR "%wc"
+#define FORMAT_LPDESC "%ws"
+#define FORMAT_LPDESC_CHAR "%wc"
+
+#endif // DESC_CHAR_UNICODE is defined
+
+//typedef DESC_CHAR * LPDESC;
+
+//
+// MAX_DESC_SUBSTRING - the maximum number of consecutive characters in a
+// descriptor string which can describe a single field in a structure - for
+// example "B21" in "B21BWWWzWB9B". So far, largest is "B120".
+//
+
+#define MAX_DESC_SUBSTRING 4
+
+//
+// Some routines need to know whether a given item is part of a request,
+// a response, or both:
+//
+
+typedef enum _RAP_TRANSMISSION_MODE {
+ Request, // only part of request (in)
+ Response, // only part of response (out)
+ Both // both (in out).
+} RAP_TRANSMISSION_MODE, *LPRAP_TRANSMISSION_MODE;
+
+typedef enum _RAP_CONVERSION_MODE {
+ NativeToRap, // native format to RAP
+ RapToNative, // RAP format to native
+ NativeToNative, // native to native
+ RapToRap // RAP to RAP
+} RAP_CONVERSION_MODE, *LPRAP_CONVERSION_MODE;
+
+//
+// The value returned by RapLastPointerOffset for a descriptor string
+// which indicates that the structure has no pointers. A very high
+// value is returned instead of 0, in order to distinguish between
+// a structure with no pointers, such as share_info_0, and a structure
+// with only one pointer, at offset 0.
+//
+
+#define NO_POINTER_IN_STRUCTURE 0xFFFFFFFF
+
+//
+// The value returned by RapAuxDataCount when there is no
+// auxiliary data. This will be indicated by the lack of an auxiliary
+// data count character in the descriptor string.
+//
+
+#define NO_AUX_DATA 0xFFFFFFFF
+
+//
+// Helper subroutines and macros.
+//
+
+DWORD
+RapArrayLength(
+ IN LPDESC Descriptor,
+ IN OUT LPDESC * UpdatedDescriptorPtr,
+ IN RAP_TRANSMISSION_MODE TransmissionMode
+ );
+
+DWORD
+RapAsciiToDecimal (
+ IN OUT LPDESC *Number
+ );
+
+DWORD
+RapAuxDataCountOffset (
+ IN LPDESC Descriptor,
+ IN RAP_TRANSMISSION_MODE TransmissionMode,
+ IN BOOL Native
+ );
+
+DWORD
+RapAuxDataCount (
+ IN LPBYTE Buffer,
+ IN LPDESC Descriptor,
+ IN RAP_TRANSMISSION_MODE TransmissionMode,
+ IN BOOL Native
+ );
+
+// RapCharSize(native): return character size (in bytes) for characters of a
+// given format.
+//
+// DWORD
+// RapCharSize(Native)
+// IN BOOL Native
+// );
+//
+#define RapCharSize(Native) \
+ ( (DWORD) ( (Native) ? sizeof(TCHAR) : sizeof(CHAR) ) )
+
+NET_API_STATUS
+RapConvertSingleEntry (
+ IN LPBYTE InStructure,
+ IN LPDESC InStructureDesc,
+ IN BOOL MeaninglessInputPointers,
+ IN LPBYTE OutBufferStart OPTIONAL,
+ OUT LPBYTE OutStructure OPTIONAL,
+ IN LPDESC OutStructureDesc,
+ IN BOOL SetOffsets,
+ IN OUT LPBYTE *StringLocation OPTIONAL,
+ IN OUT LPDWORD BytesRequired,
+ IN RAP_TRANSMISSION_MODE TransmissionMode,
+ IN RAP_CONVERSION_MODE ConversionMode
+ );
+
+//
+//
+// RapDescArrayLength(Descriptor) - return the array length if the descriptor
+// data has numeric characters, or return default length of 1.
+//
+// DWORD
+// RapDescArrayLength(
+// IN OUT LPDESC Descriptor
+// );
+//
+
+#define RapDescArrayLength( Descriptor ) \
+ ( ( DESC_CHAR_IS_DIGIT( *(Descriptor) )) ? RapAsciiToDecimal( &(Descriptor) ) : 1 )
+
+//
+// RapDescStringLength(Descriptor) - return the array length if the descriptor
+// data has numeric characters, or return default length of 0, which indicates
+// that there is no limit.
+//
+// DWORD
+// RapDescStringLength(
+// IN OUT LPDESC Descriptor
+// );
+
+#define RapDescStringLength( Descriptor ) \
+ ( ( DESC_CHAR_IS_DIGIT( *(Descriptor) )) ? RapAsciiToDecimal( &(Descriptor) ) : 0 )
+
+VOID
+RapExamineDescriptor (
+ IN LPDESC DescriptorString,
+ IN LPDWORD ParmNum OPTIONAL,
+ OUT LPDWORD StructureSize OPTIONAL,
+ OUT LPDWORD LastPointerOffset OPTIONAL,
+ OUT LPDWORD AuxDataCountOffset OPTIONAL,
+ OUT LPDESC * ParmNumDescriptor OPTIONAL,
+ OUT LPDWORD StructureAlignment OPTIONAL,
+ IN RAP_TRANSMISSION_MODE TransmissionMode,
+ IN BOOL Native
+ );
+
+DWORD
+RapGetFieldSize(
+ IN LPDESC TypePointer,
+ IN OUT LPDESC * TypePointerAddress,
+ IN RAP_TRANSMISSION_MODE TransmissionMode
+ );
+
+//
+// BOOL
+// RapIsPointer(
+// IN CHAR DescChar
+// );
+//
+
+#define RapIsPointer(c) ( ((c) > 'Z') ? TRUE : FALSE )
+
+BOOL
+RapIsValidDescriptorSmb (
+ IN LPDESC Desc
+ );
+
+DWORD
+RapLastPointerOffset (
+ IN LPDESC Descriptor,
+ IN RAP_TRANSMISSION_MODE TransmissionMode,
+ IN BOOL Native
+ );
+
+LPDESC
+RapParmNumDescriptor(
+ IN LPDESC Descriptor,
+ IN DWORD ParmNum,
+ IN RAP_TRANSMISSION_MODE TransmissionMode,
+ IN BOOL Native
+ );
+
+// LPVOID
+// RapPossiblyAlignCount(
+// IN DWORD Count,
+// IN DWORD Pow2,
+// IN BOOL Native
+// );
+#define RapPossiblyAlignCount(count,pow2,native) \
+ ( (!(native)) ? (count) : (ROUND_UP_COUNT( (count), (pow2) )) )
+
+// LPVOID
+// RapPossiblyAlignPointer(
+// IN LPVOID Ptr,
+// IN DWORD Pow2,
+// IN BOOL Native
+// );
+#define RapPossiblyAlignPointer(ptr,pow2,native) \
+ ( (!(native)) ? (ptr) : (ROUND_UP_POINTER( (ptr), (pow2) )) )
+
+DWORD
+RapStructureAlignment (
+ IN LPDESC Descriptor,
+ IN RAP_TRANSMISSION_MODE TransmissionMode,
+ IN BOOL Native
+ );
+
+DWORD
+RapStructureSize (
+ IN LPDESC Descriptor,
+ IN RAP_TRANSMISSION_MODE TransmissionMode,
+ IN BOOL Native
+ );
+
+DWORD
+RapTotalSize (
+ IN LPBYTE InStructure,
+ IN LPDESC InStructureDesc,
+ IN LPDESC OutStructureDesc,
+ IN BOOL MeaninglessInputPointers,
+ IN RAP_TRANSMISSION_MODE TransmissionMode,
+ IN RAP_CONVERSION_MODE ConversionMode
+ );
+
+//
+// RapValueWouldBeTruncated(n): return TRUE if n would lose bits when we try
+// to store it in 16 bits.
+//
+// BOOL
+// RapValueWouldBeTruncated(
+// IN DWORD Value
+// );
+//
+
+#define RapValueWouldBeTruncated(n) \
+ ( ( (n) != (DWORD) (WORD) (n)) ? TRUE : FALSE )
+
+#endif // ndef _RAP_
diff --git a/private/os2/client/remtypes.h b/private/os2/client/remtypes.h
new file mode 100644
index 000000000..cc02d6d53
--- /dev/null
+++ b/private/os2/client/remtypes.h
@@ -0,0 +1,176 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ RemTypes.h
+
+Abstract:
+
+ This header file defines character values used in descriptor strings in
+ Remote Admin Protocol.
+
+ NOTES - All pointer types are lower case, except for buffer pointers,
+ and the null pointer.
+
+ - REM_BYTE should not be used for parameters, since data is
+ never placed on the stack as individual bytes.
+
+ - REM_NULL_PTR is never specified in the call, but may be
+ used to replace a pointer type if the pointer itself is NULL.
+
+ - In some cases as indicated below, a descriptor character
+ can indicate an array of data items, if followed by an
+ ASCII representation of the number of items. For pointer
+ types, this is a count of the data items themselves, not
+ the pointers. For example, 'b12' describes a pointer
+ to 12 bytes of data, not 12 pointers to byte values.
+
+Author:
+
+ LanMan 2.x people.
+
+Environment:
+
+ Portable to any flat, 32-bit environment. (Uses Win32 typedefs.)
+ Requires ANSI C extensions: slash-slash comments, long external names.
+
+Revision History:
+
+ 15-Mar-1991 Shanku Niyogi (w-shanku)
+ Ported to NT format, and added special 32-bit descriptor characters.
+
+ 21-Aug-1991 Jim Waters (t-jamesw)
+ Added REM_ASCIZ_COMMENT.
+ 16-Aug-1992 JohnRo
+ RAID 2920: Support UTC timezone in net code.
+--*/
+
+#ifndef _REMTYPES_
+#define _REMTYPES_
+
+//
+// Data types.
+//
+
+#define REM_BYTE 'B' // Byte (s)
+#define REM_WORD 'W' // Word (s)
+#define REM_DWORD 'D' // DWord (s)
+#define REM_DATE_TIME 'C' // Date time field
+#define REM_FILL_BYTES 'F' // Pad field
+
+//
+// Pointer types.
+//
+
+//
+// For internal use, the count following a REM_ASCIZ may specify the maximum
+// string length. On the network no count may be present.
+//
+// In RapConvertSingleEntry, attempting to copy a REM_ASCIZ into a buffer too
+// small to hold it will result in an error. Use REM_ASCIZ_TRUNCATABLE
+// for strings which can be truncated.
+//
+#define REM_ASCIZ 'z' // Far pointer to asciz string
+
+#define REM_BYTE_PTR 'b' // Far pointer to byte(s)
+#define REM_WORD_PTR 'w' // Far pointer to word(s)
+#define REM_DWORD_PTR 'd' // Far pointer to dword(s)
+
+#define REM_RCV_BYTE_PTR 'g' // Far pointer to rcv byte(s)
+#define REM_RCV_WORD_PTR 'h' // Far pointer to rcv word(s)
+#define REM_RCV_DWORD_PTR 'i' // Far pointer to rcv dword(s)
+
+#define REM_NULL_PTR 'O' // NULL pointer
+
+//
+// Buffer pointer and length types.
+//
+
+#define REM_RCV_BUF_PTR 'r' // Far pointer to receive data buffer
+#define REM_RCV_BUF_LEN 'L' // Word length of receive buffer
+
+#define REM_SEND_BUF_PTR 's' // Far pointer to send data buffer
+#define REM_SEND_BUF_LEN 'T' // Word length of send buffer
+
+//
+// Other special types.
+//
+
+#define REM_AUX_NUM 'N' // !!! Temporary - for compatibility
+
+#define REM_PARMNUM 'P' // parameter number word
+
+#define REM_ENTRIES_READ 'e' // Far pointer to entries read word
+
+#define REM_DATA_BLOCK 'K' // Unstructured data block
+
+#define REM_SEND_LENBUF 'l' // Far pointer to send data buffer,
+ // where first word in buffer is the
+ // length of the buffer.
+
+
+//
+// Items from here on are "internal use only", and should never actually
+// appear on the network.
+//
+
+//
+// The following is used in the MVDM driver to get various API support
+//
+
+#define REM_WORD_LINEAR 'a' // Far linear pointer to word(s)
+
+//
+// The following is used while processing 32-bit APIs and 16-bit APIs with
+// different padding requirements or info levels with ignored fields.
+//
+
+#define REM_IGNORE 'Q' // Ignore this field (16->32 or
+ // 32->16 conversions).
+
+//
+// A dword version of the auxiliary structure count (for 32-bit data).
+//
+
+#define REM_AUX_NUM_DWORD 'A' // 32-bit dword count of aux structures
+
+//
+// Sign extended dword - for 16->32 bit conversion where the 16-bit
+// quantity may represent signed negative quantities which need
+// to be extended over 32 bits.
+//
+
+#define REM_SIGNED_DWORD 'X' // 32-bit signed dword(s)
+
+#define REM_SIGNED_DWORD_PTR 'x' // Far pointer to signed dword(s)
+
+//
+// Truncatable asciz string - If a count is specified, the field only
+// accepts strings up to the specified length. In
+// RapConvertSingleEntry, if a REM_ASCIZ_TRUNCATABLE is too long to
+// fit in the destination field, the string will be truncated to fit.
+// Use REM_ASCIZ for fields which cannot accept truncated strings.
+//
+
+#define REM_ASCIZ_TRUNCATABLE 'c' // Far pointer to asciz comment
+ // Count signifies maximum length.
+
+// Time and date in seconds since 1970 (GMT). In POSIX, this is usually
+// called "seconds since the epoch".
+
+#define REM_EPOCH_TIME_GMT 'G' // 32-bit unsigned num of seconds.
+
+// Time and date in seconds since 1970 (local time zone).
+
+#define REM_EPOCH_TIME_LOCAL 'J' // 32-bit unsigned num of seconds.
+
+//
+// Unsupported fields - for set info calls. A 'U' indicates that a parameter
+// cannot be changed.
+//
+
+#define REM_UNSUPPORTED_FIELD 'U' // Unsupported field
+
+#endif // ndef _REMTYPES_
diff --git a/private/os2/client/rxp.h b/private/os2/client/rxp.h
new file mode 100644
index 000000000..7f9600e55
--- /dev/null
+++ b/private/os2/client/rxp.h
@@ -0,0 +1,402 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ RxP.h
+
+Abstract:
+
+ This is the private header file for the NT version of RpcXlate.
+
+Author:
+
+ John Rogers (JohnRo) 25-Mar-1991
+
+Environment:
+
+ Portable to any flat, 32-bit environment. (Uses Win32 typedefs.)
+ Requires ANSI C extensions: slash-slash comments, long external names.
+
+Revision History:
+
+ 25-Mar-1991 JohnRo
+ Created.
+ 03-May-1991 JohnRo
+ RxpStartBuildingTransaction's data descriptor is SMB version (no Q's
+ or U's). RxpConvertBlock needs 2 versions of data descriptor.
+ RcvDataPtrPtr and RcvDataPresent are redundant for RxpConvertArguments
+ and RxpConvertBlock. RxpTransactSmb now gets UNC server name.
+ Fixed receive buffer size problem. Use LPTSTR.
+ Added stuff to allow runtime debug on/off changes.
+ Clarify that RxpStartBuildingTransaction uses buffer as OUT.
+ Reduced recompile hits from header files.
+ 06-May-1991 JohnRo
+ Added RxpComputeRequestBufferSize().
+ 13-May-1991 JohnRo
+ Added print Q and print job APIs support.
+ 14-May-1991 JohnRo
+ Pass 2 aux descriptors to RxpConvertBlock. Clarify other types of
+ aux descriptors.
+ 18-May-1991 JohnRo
+ Handle array of aux structs.
+ 19-May-1991 JohnRo
+ Added DBGSTATIC definition. Pass ResourceName to RxpSetField().
+ Fixed RxpAddAscii().
+ 20-May-1991 JohnRo
+ Make data descriptors OPTIONAL for RxpConvertBlock.
+ 29-May-1991 JohnRo
+ RxpConvertArgs must return SendDataPtr16 and SendDataSize16.
+ 05-Jun-1991 JohnRo
+ Added setfield debug output.
+ 11-Jun-1991 rfirth
+ Added SmbRcvByteLen parameter to RxpConvertBlock
+ Changed RetDataSize parameter to RxpTransactSmb to IN OUT LPDWORD
+ 12-Jun-1991 JohnRo
+ Moved DBGSTATIC to <NetDebug.h>.
+ 13-Jun-1991 JohnRo
+ RxpPackSendBuffer and RxpConvertArgs both need DataDesc16.
+ 15-Jul-1991 JohnRo
+ Added FieldIndex parameter to RxpSetField.
+ Changed RxpConvertDataStructures to allow ERROR_MORE_DATA, e.g. for
+ print APIs. Added debug flag for the same routine.
+ 16-Jul-1991 JohnRo
+ Estimate bytes needed for print APIs.
+ 17-Jul-1991 JohnRo
+ Extracted RxpDebug.h from Rxp.h.
+ 19-Aug-1991 rfirth
+ Added Flags parameter to RxpConvert{Args|Block}
+ 04-Oct-1991 JohnRo
+ Handle ERROR_BAD_NET_NAME (e.g. IPC$ not shared) to fix NetShareEnum.
+ More work toward UNICODE. (Added RxpAddTStr().)
+ 07-Oct-1991 JohnRo
+ Made changes suggested by PC-LINT.
+ 24-Oct-1991 JohnRo
+ Added RxpCopyStrArrayToTStrArray for remote config and disk enum.
+ 29-Oct-1991 JohnRo
+ RxpFatalErrorCode() should be paranoid.
+ 13-Nov-1991 JohnRo
+ OK, RxpFatalErrorCode() was too paranoid. It should allow
+ ERROR_MORE_DATA or all the enum APIs break.
+ 31-Mar-1992 JohnRo
+ Prevent too large size requests.
+ 05-Jun-1992 JohnRo
+ RAID 11253: NetConfigGetAll fails when remoted to downlevel.
+ 26-Jun-1992 JohnRo
+ RAID 9933: ALIGN_WORST should be 8 for x86 builds.
+ 04-May-1993 JohnRo
+ RAID 6167: avoid access violation or assert with WFW print server.
+ Made changes suggested by PC-LINT 5.0
+ 18-May-1993 JohnRo
+ DosPrintQGetInfoW underestimates number of bytes needed.
+
+--*/
+
+#ifndef _RXP_
+#define _RXP_
+
+// These must be included first:
+
+#include <windef.h> // IN, LPTSTR, LPVOID, etc.
+#include <lmcons.h> // NET_API_STATUS.
+
+// These may be included in any order:
+
+#include <rap.h> // LPDESC, RapStructureSize(), etc.
+// Don't complain about "unneeded" includes of these files:
+/*lint -efile(764,rxp.h,smbgtpt.h,stdarg.h,tstr.h,tstring.h) */
+/*lint -efile(766,rxp.h,smbgtpt.h,stdarg.h,tstr.h,tstring.h) */
+#include <smbgtpt.h> // SmbPutUshort() (needed by macros below).
+#include <stdarg.h> // va_list, etc.
+#include <tstring.h> // NetpCopyTStrToStr().
+
+
+// Maximum sizes (in bytes) supported by the transact SMB.
+#define MAX_TRANSACT_RET_DATA_SIZE ((DWORD) 0x0000FFFF)
+#define MAX_TRANSACT_RET_PARM_SIZE ((DWORD) 0x0000FFFF)
+#define MAX_TRANSACT_SEND_DATA_SIZE ((DWORD) 0x0000FFFF)
+#define MAX_TRANSACT_SEND_PARM_SIZE ((DWORD) 0x0000FFFF)
+
+
+// Note: IF_DEBUG() and so on are now in Net/Inc/RxpDebug.h.
+
+DWORD
+RxpComputeRequestBufferSize(
+ IN LPDESC ParmDesc,
+ IN LPDESC DataDescSmb OPTIONAL,
+ IN DWORD DataSize
+ );
+
+NET_API_STATUS
+RxpConvertArgs(
+ IN LPDESC ParmDescriptorString,
+ IN LPDESC DataDesc16 OPTIONAL,
+ IN LPDESC DataDesc32 OPTIONAL,
+ IN LPDESC DataDescSmb OPTIONAL,
+ IN LPDESC AuxDesc16 OPTIONAL,
+ IN LPDESC AuxDesc32 OPTIONAL,
+ IN LPDESC AuxDescSmb OPTIONAL,
+ IN DWORD MaximumInputBlockSize,
+ IN DWORD MaximumOutputBlockSize,
+ IN OUT LPDWORD CurrentInputBlockSizePtr,
+ IN OUT LPDWORD CurrentOutputBlockSizePtr,
+ IN OUT LPBYTE * CurrentOutputBlockPtrPtr,
+ IN va_list * FirstArgumentPtr, // rest of API's arguments (after
+ // server name)
+ OUT LPDWORD SendDataSizePtr16,
+ OUT LPBYTE * SendDataPtrPtr16,
+ OUT LPDWORD RcvDataSizePtr,
+ OUT LPBYTE * RcvDataPtrPtr,
+ IN DWORD Flags
+ );
+
+NET_API_STATUS
+RxpConvertBlock(
+ IN DWORD ApiNumber,
+ IN LPBYTE ResponseBlockPtr,
+ IN LPDESC ParmDescriptorString,
+ IN LPDESC DataDescriptor16 OPTIONAL,
+ IN LPDESC DataDescriptor32 OPTIONAL,
+ IN LPDESC AuxDesc16 OPTIONAL,
+ IN LPDESC AuxDesc32 OPTIONAL,
+ IN va_list* FirstArgumentPtr, // rest of API's arguments
+ IN LPBYTE SmbRcvBuffer OPTIONAL,
+ IN DWORD SmbRcvByteLen,
+ OUT LPBYTE RcvDataPtr OPTIONAL,
+ IN DWORD RcvDataSize,
+ IN DWORD Flags
+ );
+
+// DWORD
+// RxpEstimateBytesNeeded(
+// IN DWORD BytesNeeded16
+// );
+//
+// Worst case: BOOL or CHAR might be padded to DWORD.
+#define RxpEstimateBytesNeeded(Size16) \
+ ( (Size16) * 4 )
+
+//
+// Estimate bytes needed for an audit log or error log array.
+//
+NET_API_STATUS
+RxpEstimateLogSize(
+ IN DWORD DownlevelFixedEntrySize,
+ IN DWORD InputArraySize,
+ IN BOOL DoingErrorLog, // TRUE for error log, FALSE for audit log
+ OUT LPDWORD OutputArraySize
+ );
+
+// BOOL
+// RxpFatalErrorCode(
+// IN NET_API_STATUS Status
+// );
+//
+#define RxpFatalErrorCode( Status ) \
+ ( ( ((Status) != NERR_Success) \
+ && ((Status) != ERROR_MORE_DATA) ) \
+ ? TRUE : FALSE )
+
+NET_API_STATUS
+RxpPackSendBuffer(
+ IN OUT LPVOID * SendBufferPtrPtr,
+ IN OUT LPDWORD SendBufferSizePtr,
+ OUT LPBOOL AllocFlagPtr,
+ IN LPDESC DataDesc16,
+ IN LPDESC AuxDesc16,
+ IN DWORD FixedSize16,
+ IN DWORD AuxOffset,
+ IN DWORD AuxSize,
+ IN BOOL SetInfo
+ );
+
+NET_API_STATUS
+RxpReceiveBufferConvert(
+ IN OUT LPVOID RcvDataPtr,
+ IN DWORD RcvDataSize,
+ IN DWORD Converter,
+ IN DWORD NumberOfStructures,
+ IN LPDESC DataDescriptorString,
+ IN LPDESC AuxDescriptorString,
+ OUT LPDWORD NumAuxStructs
+ );
+
+NET_API_STATUS
+RxpSetField (
+ IN DWORD ApiNumber,
+ IN LPTSTR UncServerName,
+ IN LPDESC ObjectDesc OPTIONAL,
+ IN LPVOID ObjectToSet OPTIONAL,
+ IN LPDESC ParmDesc,
+ IN LPDESC DataDesc16,
+ IN LPDESC DataDesc32,
+ IN LPDESC DataDescSmb,
+ IN LPVOID NativeInfoBuffer,
+ IN DWORD ParmNumToSend,
+ IN DWORD FieldIndex,
+ IN DWORD Level
+ );
+
+NET_API_STATUS
+RxpStartBuildingTransaction(
+ OUT LPVOID Buffer,
+ IN DWORD BufferSize,
+ IN DWORD ApiNumber,
+ IN LPDESC ParmDesc,
+ IN LPDESC DataDescSmb OPTIONAL,
+ OUT LPVOID * RovingOutputPtr,
+ OUT LPDWORD SizeSoFarPtr,
+ OUT LPVOID * LastStringPtr OPTIONAL,
+ OUT LPDESC * ParmDescCopyPtr OPTIONAL
+ );
+
+NET_API_STATUS
+RxpTransactSmb(
+ IN LPTSTR UncServerName,
+ IN LPTSTR TransportName,
+ IN LPVOID SendParmPtr,
+ IN DWORD SendParmSize,
+ IN LPVOID SendDataPtr OPTIONAL,
+ IN DWORD SendDataSize,
+ OUT LPVOID RetParmPtr OPTIONAL,
+ IN DWORD RetParmSize,
+ OUT LPVOID RetDataPtr OPTIONAL,
+ IN OUT LPDWORD RetDataSize,
+ IN BOOL NoPermissionRequired
+ );
+
+NET_API_STATUS
+RxpConvertDataStructures(
+ IN LPDESC InputDescriptor,
+ IN LPDESC OutputDescriptor,
+ IN LPDESC InputAuxDescriptor OPTIONAL,
+ IN LPDESC OutputAuxDescriptor OPTIONAL,
+ IN LPBYTE InputBuffer,
+ OUT LPBYTE OutputBuffer,
+ IN DWORD OutputBufferSize,
+ IN DWORD PrimaryCount,
+ OUT LPDWORD EntriesConverted OPTIONAL,
+ IN RAP_TRANSMISSION_MODE TransmissionMode,
+ IN RAP_CONVERSION_MODE ConversionMode
+ );
+
+
+
+// BUGBUG: For the macros below, does it matter whether we store pointer or
+// offset in buffer?
+
+// VOID
+// RxpAddPointer(
+// IN LPVOID Input,
+// IN OUT LPBYTE * CurPtrPtr,
+// IN OUT LPDWORD CurSizePtr
+// );
+//
+#define RxpAddPointer(Input,CurPtrPtr,CurSizePtr) \
+ { \
+ SmbPutUlong( (LPDWORD) *(CurPtrPtr), (DWORD) (Input)); \
+ *(CurPtrPtr) += sizeof(LPBYTE); \
+ *(CurSizePtr) = (*(CurSizePtr)) + sizeof(LPBYTE); \
+ }
+
+// RxpAddVariableSize: Add a variable length item to string space at end of
+// buffer. Store pointer to it in buffer; update current buffer pointer and
+// Size; update string space pointer.
+// BUGBUG: Check for overflow!
+//
+// VOID
+// RxpAddVariableSize(
+// IN LPBYTE Input,
+// IN DWORD InputSize,
+// IN OUT LPBYTE * CurPtrPtr,
+// IN OUT LPBYTE * StrPtrPtr,
+// IN OUT LPDWORD CurSizePtr
+// );
+//
+#define RxpAddVariableSize(Input,InputSize,CurPtrPtr,StrPtrPtr,CurSizePtr) \
+ { \
+ *(StrPtrPtr) -= (InputSize); \
+ RxpAddPointer( *(StrPtrPtr), (CurPtrPtr), (CurSizePtr)); \
+ NetpMoveMemory( *((StrPtrPtr)), (Input), (InputSize)); \
+ }
+
+// RxpAddAscii: Add an ASCII string to string space at end of buffer;
+// store pointer to it in buffer; update current buffer pointer and Size;
+// update string space pointer.
+// BUGBUG: Check for overflow!
+//
+// VOID
+// RxpAddAscii(
+// IN LPTSTR Input,
+// IN OUT LPBYTE * CurPtrPtr,
+// IN OUT LPBYTE * StrPtrPtr,
+// IN OUT LPDWORD CurSizePtr
+// );
+//
+#define RxpAddAscii(Input,CurPtrPtr,StrPtrPtr,CurSizePtr) \
+ { \
+ DWORD len = strlen((Input))+1; \
+ RxpAddVariableSize( \
+ (Input), len, \
+ (CurPtrPtr), (StrPtrPtr), (CurSizePtr)); \
+ }
+
+// RxpAddTStr: Add a LPTSTR string to string space at end of buffer;
+// store pointer to it in buffer; update current buffer pointer and Size;
+// update string space pointer.
+// BUGBUG: Check for overflow!
+//
+// VOID
+// RxpAddTStr(
+// IN LPTSTR Input,
+// IN OUT LPBYTE * CurPtrPtr,
+// IN OUT LPBYTE * StrPtrPtr,
+// IN OUT LPDWORD CurSizePtr
+// );
+//
+#define RxpAddTStr(Input,CurPtrPtr,StrPtrPtr,CurSizePtr) \
+ { \
+ DWORD size = STRLEN((Input))+1; \
+ *(StrPtrPtr) -= size; \
+ RxpAddPointer( *(StrPtrPtr), (CurPtrPtr), (CurSizePtr)); \
+ NetpCopyTStrToStr( *((StrPtrPtr)), (Input) ); \
+ }
+
+// VOID
+// RxpAddWord(
+// IN WORD Input,
+// IN OUT LPBYTE * CurPtrPtr,
+// IN OUT LPDWORD CurSizePtr
+// );
+//
+#define RxpAddWord(Input,CurPtrPtr,CurSizePtr) \
+ { \
+ SmbPutUshort( (LPWORD) (*(CurPtrPtr)), (WORD) (Input)); \
+ *(CurPtrPtr) += sizeof(WORD); \
+ *(CurSizePtr) = (*(CurSizePtr)) + sizeof(WORD); \
+ }
+
+//
+// MAKE_PARMNUM_PAIR() - packs a parmnum and a field index into a DWORD. We
+// have to do this because there are (many) cases where we cannot assume
+// correspondence between a parmnum and a field index
+//
+
+#define MAKE_PARMNUM_PAIR(parmnum, field_index) ((DWORD)((((DWORD)(field_index)) << 16) | (DWORD)(parmnum)))
+
+//
+// FIELD_INDEX_FROM_PARMNUM_PAIR() - retrieve the field index from the pair
+// conjoined by MAKE_PARMNUM_PAIR()
+//
+
+#define FIELD_INDEX_FROM_PARMNUM_PAIR(pair) ((DWORD)((pair) >> 16))
+
+//
+// PARMNUM_FROM_PARMNUM_PAIR() - retrieve the parmnum from the pair conjoined
+// by MAKE_PARMNUM_PAIR()
+//
+
+#define PARMNUM_FROM_PARMNUM_PAIR(pair) ((DWORD)((pair) & 0x0000ffff))
+
+#endif // ndef _RXP_
diff --git a/private/os2/client/rxuser.h b/private/os2/client/rxuser.h
new file mode 100644
index 000000000..ab78ac89a
--- /dev/null
+++ b/private/os2/client/rxuser.h
@@ -0,0 +1,115 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ rxuser.h
+
+Abstract:
+
+ Prototypes for down-level remoted RxNetUser... routines
+
+Author:
+
+ Richard Firth (rfirth) 28-May-1991
+
+Revision History:
+
+ 28-May-1991 RFirth
+ Created
+
+--*/
+
+NET_API_STATUS
+RxNetUserAdd(
+ IN LPTSTR ServerName,
+ IN DWORD Level,
+ IN LPBYTE Buffer,
+ OUT LPDWORD ParmError OPTIONAL
+ );
+
+NET_API_STATUS
+RxNetUserDel(
+ IN LPTSTR ServerName,
+ IN LPTSTR UserName
+ );
+
+NET_API_STATUS
+RxNetUserEnum(
+ IN LPTSTR ServerName,
+ IN DWORD Level,
+ OUT LPBYTE* Buffer,
+ IN DWORD PrefMaxLen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD EntriesLeft,
+ IN OUT LPDWORD ResumeHandle OPTIONAL
+ );
+
+NET_API_STATUS
+RxNetUserGetGroups(
+ IN LPTSTR ServerName,
+ IN LPTSTR UserName,
+ IN DWORD Level,
+ OUT LPBYTE* Buffer,
+ IN DWORD PrefMaxLen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD EntriesLeft
+ );
+
+NET_API_STATUS
+RxNetUserGetInfo(
+ IN LPTSTR ServerName,
+ IN LPTSTR UserName,
+ IN DWORD Level,
+ OUT LPBYTE* Buffer
+ );
+
+NET_API_STATUS
+RxNetUserModalsGet(
+ IN LPTSTR ServerName,
+ IN DWORD Level,
+ OUT LPBYTE* Buffer
+ );
+
+NET_API_STATUS
+RxNetUserModalsSet(
+ IN LPTSTR ServerName,
+ IN DWORD Level,
+ IN LPBYTE Buffer,
+ OUT LPDWORD ParmError OPTIONAL
+ );
+
+NET_API_STATUS
+RxNetUserPasswordSet(
+ IN LPTSTR ServerName,
+ IN LPTSTR UserName,
+ IN LPTSTR OldPassword,
+ IN LPTSTR NewPassword
+ );
+
+NET_API_STATUS
+RxNetUserSetGroups(
+ IN LPTSTR ServerName,
+ IN LPTSTR UserName,
+ IN DWORD Level,
+ IN LPBYTE Buffer,
+ IN DWORD Entries
+ );
+
+NET_API_STATUS
+RxNetUserSetInfo(
+ IN LPTSTR ServerName,
+ IN LPTSTR UserName,
+ IN DWORD Level,
+ IN LPBYTE Buffer,
+ OUT LPDWORD ParmError OPTIONAL
+ );
+
+
+//NET_API_STATUS
+//RxNetUserValidate2
+// /** CANNOT BE REMOTED **/
+//{
+//
+//}
diff --git a/private/os2/client/smbgtpt.h b/private/os2/client/smbgtpt.h
new file mode 100644
index 000000000..dc8f9b44c
--- /dev/null
+++ b/private/os2/client/smbgtpt.h
@@ -0,0 +1,920 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ smbgtpt.h
+
+Abstract:
+
+ This module defines macros for retrieving and storing SMB data.
+ The macros account for the misaligned nature of the SMB protocol.
+ They also translate from the little-endian SMB format into
+ big-endian format, when necessary.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 2-Mar-90
+ David Treadwell (davditr)
+
+Revision History:
+
+ 15-Apr-1991 JohnRo
+ Include <smbtypes.h>, to define SMBDBG etc.
+--*/
+
+#ifndef _OS2SSSMBGTPT_
+#define _OS2SSSMBGTPT_
+
+
+
+#define SMB_USE_UNALIGNED 1
+
+
+#include <smbtypes.h>
+//#include <smb.h>
+
+//
+// The following macros store and retrieve USHORTS and ULONGS from
+// potentially unaligned addresses, avoiding alignment faults. They
+// would best be written as inline assembly code.
+//
+// The macros are designed to be used for accessing SMB fields. Such
+// fields are always stored in little-endian byte order, so these macros
+// do byte swapping when compiled for a big-endian machine.
+//
+// !!! Not yet.
+//
+
+#if !OS2SSSMBDBG
+
+#define BYTE_0_MASK 0xFF
+
+#define BYTE_0(Value) (UCHAR)( (Value) & BYTE_0_MASK)
+#define BYTE_1(Value) (UCHAR)( ((Value) >> 8) & BYTE_0_MASK)
+#define BYTE_2(Value) (UCHAR)( ((Value) >> 16) & BYTE_0_MASK)
+#define BYTE_3(Value) (UCHAR)( ((Value) >> 24) & BYTE_0_MASK)
+
+#endif
+
+//++
+//
+// USHORT
+// SmbGetUshort (
+// IN PSMB_USHORT SrcAddress
+// )
+//
+// Routine Description:
+//
+// This macro retrieves a USHORT value from the possibly misaligned
+// source address, avoiding alignment faults.
+//
+// Arguments:
+//
+// SrcAddress - where to retrieve USHORT value from
+//
+// Return Value:
+//
+// USHORT - the value retrieved. The target must be aligned.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if !OS2SSSMBDBG1
+#if SMB_USE_UNALIGNED
+#define SmbGetUshort(SrcAddress) *(PSMB_USHORT)(SrcAddress)
+#else
+#define SmbGetUshort(SrcAddress) (USHORT)( \
+ ( ( (PUCHAR)(SrcAddress) )[0] ) | \
+ ( ( (PUCHAR)(SrcAddress) )[1] << 8 ) \
+ )
+#endif
+#else
+#define SmbGetUshort(SrcAddress) (USHORT)( \
+ ( ( (PUCHAR)(SrcAddress ## S) )[0] ) | \
+ ( ( (PUCHAR)(SrcAddress ## S) )[1] << 8 ) \
+ )
+#endif
+
+#else
+
+USHORT
+SmbGetUshort (
+ IN PSMB_USHORT SrcAddress
+ );
+
+#endif
+
+//++
+//
+// USHORT
+// SmbGetAlignedUshort (
+// IN PUSHORT SrcAddress
+// )
+//
+// Routine Description:
+//
+// This macro retrieves a USHORT value from the source address,
+// correcting for the endian characteristics of the server if
+// necessary.
+//
+// Arguments:
+//
+// SrcAddress - where to retrieve USHORT value from; must be aligned.
+//
+// Return Value:
+//
+// USHORT - the value retrieved. The target must be aligned.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if !OS2SSSMBDBG1
+#define SmbGetAlignedUshort(SrcAddress) *(SrcAddress)
+#else
+#define SmbGetAlignedUshort(SrcAddress) *(SrcAddress ## S)
+#endif
+
+#else
+
+USHORT
+SmbGetAlignedUshort (
+ IN PUSHORT SrcAddress
+ );
+
+#endif
+
+//++
+//
+// VOID
+// SmbPutUshort (
+// OUT PSMB_USHORT DestAddress,
+// IN USHORT Value
+// )
+//
+// Routine Description:
+//
+// This macro stores a USHORT value at the possibly misaligned
+// destination address, avoiding alignment faults.
+//
+// Arguments:
+//
+// DestAddress - where to store USHORT value. Address may be
+// misaligned.
+//
+// Value - USHORT to store. Value must be a constant or an aligned
+// field.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if !OS2SSSMBDBG1
+#if SMB_USE_UNALIGNED
+#define SmbPutUshort(SrcAddress, Value) \
+ *(PSMB_USHORT)(SrcAddress) = (Value)
+#else
+#define SmbPutUshort(DestAddress,Value) { \
+ ( (PUCHAR)(DestAddress) )[0] = BYTE_0(Value); \
+ ( (PUCHAR)(DestAddress) )[1] = BYTE_1(Value); \
+ }
+#endif
+#else
+#define SmbPutUshort(DestAddress,Value) { \
+ ( (PUCHAR)(DestAddress ## S) )[0] = BYTE_0(Value); \
+ ( (PUCHAR)(DestAddress ## S) )[1] = BYTE_1(Value); \
+ }
+#endif
+
+#else
+
+VOID
+SmbPutUshort (
+ OUT PSMB_USHORT DestAddress,
+ IN USHORT Value
+ );
+
+#endif
+
+//++
+//
+// VOID
+// SmbPutAlignedUshort (
+// OUT PUSHORT DestAddres,
+// IN USHORT Value
+// )
+//
+// Routine Description:
+//
+// This macro stores a USHORT value from the source address,
+// correcting for the endian characteristics of the server if
+// necessary.
+//
+// Arguments:
+//
+// DestAddress - where to store USHORT value. Address may not be
+// misaligned.
+//
+// Value - USHORT to store. Value must be a constant or an aligned
+// field.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if !OS2SSSMBDBG1
+#define SmbPutAlignedUshort(DestAddress,Value) *(DestAddress) = (Value)
+#else
+#define SmbPutAlignedUshort(DestAddress,Value) *(DestAddress ## S) = (Value)
+#endif
+
+#else
+
+VOID
+SmbPutAlignedUshort (
+ OUT PUSHORT DestAddress,
+ IN USHORT Value
+ );
+
+#endif
+
+//++
+//
+// VOID
+// SmbMoveUshort (
+// OUT PSMB_USHORT DestAddress
+// IN PSMB_USHORT SrcAddress
+// )
+//
+// Routine Description:
+//
+// This macro moves a USHORT value from the possibly misaligned
+// source address to the possibly misaligned destination address,
+// avoiding alignment faults.
+//
+// Arguments:
+//
+// DestAddress - where to store USHORT value
+//
+// SrcAddress - where to retrieve USHORT value from
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if !OS2SSSMBDBG1
+#if SMB_USE_UNALIGNED
+#define SmbMoveUshort(DestAddress, SrcAddress) \
+ *(PSMB_USHORT)(DestAddress) = *(PSMB_USHORT)(SrcAddress)
+#else
+#define SmbMoveUshort(DestAddress,SrcAddress) { \
+ ( (PUCHAR)(DestAddress) )[0] = ( (PUCHAR)(SrcAddress) )[0]; \
+ ( (PUCHAR)(DestAddress) )[1] = ( (PUCHAR)(SrcAddress) )[1]; \
+ }
+#endif
+#else
+#define SmbMoveUshort(DestAddress,SrcAddress) { \
+ ( (PUCHAR)(DestAddress ## S) )[0] = ( (PUCHAR)(SrcAddress ## S) )[0]; \
+ ( (PUCHAR)(DestAddress ## S) )[1] = ( (PUCHAR)(SrcAddress ## S) )[1]; \
+ }
+#endif
+
+#else
+
+VOID
+SmbMoveUshort (
+ OUT PSMB_USHORT DestAddress,
+ IN PSMB_USHORT SrcAddress
+ );
+
+#endif
+
+//++
+//
+// ULONG
+// SmbGetUlong (
+// IN PSMB_ULONG SrcAddress
+// )
+//
+// Routine Description:
+//
+// This macro retrieves a ULONG value from the possibly misaligned
+// source address, avoiding alignment faults.
+//
+// Arguments:
+//
+// SrcAddress - where to retrieve ULONG value from
+//
+// Return Value:
+//
+// ULONG - the value retrieved. The target must be aligned.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if !OS2SSSMBDBG1
+#if SMB_USE_UNALIGNED
+#define SmbGetUlong(SrcAddress) *(PSMB_ULONG)(SrcAddress)
+#else
+#define SmbGetUlong(SrcAddress) (ULONG)( \
+ ( ( (PUCHAR)(SrcAddress) )[0] ) | \
+ ( ( (PUCHAR)(SrcAddress) )[1] << 8 ) | \
+ ( ( (PUCHAR)(SrcAddress) )[2] << 16 ) | \
+ ( ( (PUCHAR)(SrcAddress) )[3] << 24 ) \
+ )
+#endif
+#else
+#define SmbGetUlong(SrcAddress) (ULONG)( \
+ ( ( (PUCHAR)(SrcAddress ## L) )[0] ) | \
+ ( ( (PUCHAR)(SrcAddress ## L) )[1] << 8 ) | \
+ ( ( (PUCHAR)(SrcAddress ## L) )[2] << 16 ) | \
+ ( ( (PUCHAR)(SrcAddress ## L) )[3] << 24 ) \
+ )
+#endif
+
+#else
+
+ULONG
+SmbGetUlong (
+ IN PSMB_ULONG SrcAddress
+ );
+
+#endif
+
+//++
+//
+// USHORT
+// SmbGetAlignedUlong (
+// IN PULONG SrcAddress
+// )
+//
+// Routine Description:
+//
+// This macro retrieves a ULONG value from the source address,
+// correcting for the endian characteristics of the server if
+// necessary.
+//
+// Arguments:
+//
+// SrcAddress - where to retrieve ULONG value from; must be aligned.
+//
+// Return Value:
+//
+// ULONG - the value retrieved. The target must be aligned.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if !OS2SSSMBDBG1
+#define SmbGetAlignedUlong(SrcAddress) *(SrcAddress)
+#else
+#define SmbGetAlignedUlong(SrcAddress) *(SrcAddress ## L)
+#endif
+
+#else
+
+ULONG
+SmbGetAlignedUlong (
+ IN PULONG SrcAddress
+ );
+
+#endif
+
+//++
+//
+// VOID
+// SmbPutUlong (
+// OUT PSMB_ULONG DestAddress,
+// IN ULONG Value
+// )
+//
+// Routine Description:
+//
+// This macro stores a ULONG value at the possibly misaligned
+// destination address, avoiding alignment faults.
+//
+// Arguments:
+//
+// DestAddress - where to store ULONG value
+//
+// Value - ULONG to store. Value must be a constant or an aligned
+// field.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if !OS2SSSMBDBG1
+#if SMB_USE_UNALIGNED
+#define SmbPutUlong(SrcAddress, Value) *(PSMB_ULONG)(SrcAddress) = Value
+#else
+#define SmbPutUlong(DestAddress,Value) { \
+ ( (PUCHAR)(DestAddress) )[0] = BYTE_0(Value); \
+ ( (PUCHAR)(DestAddress) )[1] = BYTE_1(Value); \
+ ( (PUCHAR)(DestAddress) )[2] = BYTE_2(Value); \
+ ( (PUCHAR)(DestAddress) )[3] = BYTE_3(Value); \
+ }
+#endif
+#else
+#define SmbPutUlong(DestAddress,Value) { \
+ ( (PUCHAR)(DestAddress ## L) )[0] = BYTE_0(Value); \
+ ( (PUCHAR)(DestAddress ## L) )[1] = BYTE_1(Value); \
+ ( (PUCHAR)(DestAddress ## L) )[2] = BYTE_2(Value); \
+ ( (PUCHAR)(DestAddress ## L) )[3] = BYTE_3(Value); \
+ }
+#endif
+
+#else
+
+VOID
+SmbPutUlong (
+ OUT PSMB_ULONG DestAddress,
+ IN ULONG Value
+ );
+
+#endif
+
+//++
+//
+// VOID
+// SmbPutAlignedUlong (
+// OUT PULONG DestAddres,
+// IN ULONG Value
+// )
+//
+// Routine Description:
+//
+// This macro stores a ULONG value from the source address,
+// correcting for the endian characteristics of the server if
+// necessary.
+//
+// Arguments:
+//
+// DestAddress - where to store ULONG value. Address may not be
+// misaligned.
+//
+// Value - ULONG to store. Value must be a constant or an aligned
+// field.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if !OS2SSSMBDBG1
+#define SmbPutAlignedUlong(DestAddress,Value) *(DestAddress) = (Value)
+#else
+#define SmbPutAlignedUlong(DestAddress,Value) *(DestAddress ## L) = (Value)
+#endif
+
+#else
+
+VOID
+SmbPutAlignedUlong (
+ OUT PULONG DestAddress,
+ IN ULONG Value
+ );
+
+#endif
+
+//++
+//
+// VOID
+// SmbMoveUlong (
+// OUT PSMB_ULONG DestAddress,
+// IN PSMB_ULONG SrcAddress
+// )
+//
+// Routine Description:
+//
+// This macro moves a ULONG value from the possibly misaligned
+// source address to the possible misaligned destination address,
+// avoiding alignment faults.
+//
+// Arguments:
+//
+// DestAddress - where to store ULONG value
+//
+// SrcAddress - where to retrieve ULONG value from
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if !OS2SSSMBDBG1
+#if SMB_USE_UNALIGNED
+#define SmbMoveUlong(DestAddress,SrcAddress) \
+ *(PSMB_ULONG)(DestAddress) = *(PSMB_ULONG)(SrcAddress)
+#else
+#define SmbMoveUlong(DestAddress,SrcAddress) { \
+ ( (PUCHAR)(DestAddress) )[0] = ( (PUCHAR)(SrcAddress) )[0]; \
+ ( (PUCHAR)(DestAddress) )[1] = ( (PUCHAR)(SrcAddress) )[1]; \
+ ( (PUCHAR)(DestAddress) )[2] = ( (PUCHAR)(SrcAddress) )[2]; \
+ ( (PUCHAR)(DestAddress) )[3] = ( (PUCHAR)(SrcAddress) )[3]; \
+ }
+#endif
+#else
+#define SmbMoveUlong(DestAddress,SrcAddress) { \
+ ( (PUCHAR)(DestAddress ## L) )[0] = ( (PUCHAR)(SrcAddress ## L) )[0]; \
+ ( (PUCHAR)(DestAddress ## L) )[1] = ( (PUCHAR)(SrcAddress ## L) )[1]; \
+ ( (PUCHAR)(DestAddress ## L) )[2] = ( (PUCHAR)(SrcAddress ## L) )[2]; \
+ ( (PUCHAR)(DestAddress ## L) )[3] = ( (PUCHAR)(SrcAddress ## L) )[3]; \
+ }
+#endif
+
+#else
+
+VOID
+SmbMoveUlong (
+ OUT PSMB_ULONG DestAddress,
+ IN PSMB_ULONG SrcAddress
+ );
+
+#endif
+
+//++
+//
+// VOID
+// SmbPutDate (
+// OUT PSMB_DATE DestAddress,
+// IN SMB_DATE Value
+// )
+//
+// Routine Description:
+//
+// This macro stores an SMB_DATE value at the possibly misaligned
+// destination address, avoiding alignment faults. This macro
+// is different from SmbPutUshort in order to be able to handle
+// funny bitfield / big-endian interactions.
+//
+// Arguments:
+//
+// DestAddress - where to store SMB_DATE value
+//
+// Value - SMB_DATE to store. Value must be a constant or an
+// aligned field.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if SMB_USE_UNALIGNED
+#define SmbPutDate(DestAddress,Value) (DestAddress)->Ushort = (Value).Ushort
+#else
+#define SmbPutDate(DestAddress,Value) { \
+ ( (PUCHAR)&(DestAddress)->Ushort )[0] = BYTE_0((Value).Ushort); \
+ ( (PUCHAR)&(DestAddress)->Ushort )[1] = BYTE_1((Value).Ushort); \
+ }
+#endif
+
+#else
+
+VOID
+SmbPutDate (
+ OUT PSMB_DATE DestAddress,
+ IN SMB_DATE Value
+ );
+
+#endif
+
+//++
+//
+// VOID
+// SmbMoveDate (
+// OUT PSMB_DATE DestAddress,
+// IN PSMB_DATE SrcAddress
+// )
+//
+// Routine Description:
+//
+// This macro copies an SMB_DATE value from the possibly misaligned
+// source address, avoiding alignment faults. This macro is
+// different from SmbGetUshort in order to be able to handle funny
+// bitfield / big-endian interactions.
+//
+// Note that there is no SmbGetDate because of the way SMB_DATE is
+// defined. It is a union containing a USHORT and a bitfield
+// struct. The caller of an SmbGetDate macro would have to
+// explicitly use one part of the union.
+//
+// Arguments:
+//
+// DestAddress - where to store SMB_DATE value. MUST BE ALIGNED!
+//
+// SrcAddress - where to retrieve SMB_DATE value from
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if SMB_USE_UNALIGNED
+#define SmbMoveDate(DestAddress,SrcAddress) \
+ (DestAddress)->Ushort = (SrcAddress)->Ushort
+#else
+#define SmbMoveDate(DestAddress,SrcAddress) \
+ (DestAddress)->Ushort = \
+ ( ( (PUCHAR)&(SrcAddress)->Ushort )[0] ) | \
+ ( ( (PUCHAR)&(SrcAddress)->Ushort )[1] << 8 )
+#endif
+
+#else
+
+VOID
+SmbMoveDate (
+ OUT PSMB_DATE DestAddress,
+ IN PSMB_DATE SrcAddress
+ );
+
+#endif
+
+//++
+//
+// VOID
+// SmbZeroDate (
+// IN PSMB_DATE Date
+// )
+//
+// Routine Description:
+//
+// This macro zeroes a possibly misaligned SMB_DATE field.
+//
+// Arguments:
+//
+// Date - Pointer to SMB_DATE field to zero.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if SMB_USE_UNALIGNED
+#define SmbZeroDate(Date) (Date)->Ushort = 0
+#else
+#define SmbZeroDate(Date) { \
+ ( (PUCHAR)&(Date)->Ushort )[0] = 0; \
+ ( (PUCHAR)&(Date)->Ushort )[1] = 0; \
+ }
+#endif
+
+#else
+
+VOID
+SmbZeroDate (
+ IN PSMB_DATE Date
+ );
+
+#endif
+
+//++
+//
+// BOOLEAN
+// SmbIsDateZero (
+// IN PSMB_DATE Date
+// )
+//
+// Routine Description:
+//
+// This macro returns TRUE if the supplied SMB_DATE value is zero.
+//
+// Arguments:
+//
+// Date - Pointer to SMB_DATE value to check. MUST BE ALIGNED!
+//
+// Return Value:
+//
+// BOOLEAN - TRUE if Date is zero, else FALSE.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#define SmbIsDateZero(Date) ( (Date)->Ushort == 0 )
+
+#else
+
+BOOLEAN
+SmbIsDateZero (
+ IN PSMB_DATE Date
+ );
+
+#endif
+
+//++
+//
+// VOID
+// SmbPutTime (
+// OUT PSMB_TIME DestAddress,
+// IN SMB_TIME Value
+// )
+//
+// Routine Description:
+//
+// This macro stores an SMB_TIME value at the possibly misaligned
+// destination address, avoiding alignment faults. This macro
+// is different from SmbPutUshort in order to be able to handle
+// funny bitfield / big-endian interactions.
+//
+// Arguments:
+//
+// DestAddress - where to store SMB_TIME value
+//
+// Value - SMB_TIME to store. Value must be a constant or an
+// aligned field.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if SMB_USE_UNALIGNED
+#define SmbPutTime(DestAddress,Value) (DestAddress)->Ushort = (Value).Ushort
+#else
+#define SmbPutTime(DestAddress,Value) { \
+ ( (PUCHAR)&(DestAddress)->Ushort )[0] = BYTE_0((Value).Ushort); \
+ ( (PUCHAR)&(DestAddress)->Ushort )[1] = BYTE_1((Value).Ushort); \
+ }
+#endif
+
+#else
+
+VOID
+SmbPutTime (
+ OUT PSMB_TIME DestAddress,
+ IN SMB_TIME Value
+ );
+
+#endif
+
+//++
+//
+// VOID
+// SmbMoveTime (
+// OUT PSMB_TIME DestAddress,
+// IN PSMB_TIME SrcAddress
+// )
+//
+// Routine Description:
+//
+// This macro copies an SMB_TIME value from the possibly
+// misaligned source address, avoiding alignment faults. This macro
+// is different from SmbGetUshort in order to be able to handle
+// funny bitfield / big-endian interactions.
+//
+// Note that there is no SmbGetTime because of the way SMB_TIME is
+// defined. It is a union containing a USHORT and a bitfield
+// struct. The caller of an SmbGetTime macro would have to
+// explicitly use one part of the union.
+//
+// Arguments:
+//
+// DestAddress - where to store SMB_TIME value. MUST BE ALIGNED!
+//
+// SrcAddress - where to retrieve SMB_TIME value from
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if SMB_USE_UNALIGNED
+#define SmbMoveTime(DestAddress,SrcAddress) \
+ (DestAddress)->Ushort = (SrcAddress)->Ushort
+#else
+#define SmbMoveTime(DestAddress,SrcAddress) \
+ (DestAddress)->Ushort = \
+ ( ( (PUCHAR)&(SrcAddress)->Ushort )[0] ) | \
+ ( ( (PUCHAR)&(SrcAddress)->Ushort )[1] << 8 )
+#endif
+
+#else
+
+VOID
+SmbMoveTime (
+ OUT PSMB_TIME DestAddress,
+ IN PSMB_TIME SrcAddress
+ );
+
+#endif
+
+//++
+//
+// VOID
+// SmbZeroTime (
+// IN PSMB_TIME Time
+// )
+//
+// Routine Description:
+//
+// This macro zeroes a possibly misaligned SMB_TIME field.
+//
+// Arguments:
+//
+// Time - Pointer to SMB_TIME field to zero.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#if SMB_USE_UNALIGNED
+#define SmbZeroTime(Time) (Time)->Ushort = 0
+#else
+#define SmbZeroTime(Time) { \
+ ( (PUCHAR)&(Time)->Ushort )[0] = 0; \
+ ( (PUCHAR)&(Time)->Ushort )[1] = 0; \
+ }
+#endif
+
+#else
+
+VOID
+SmbZeroTime (
+ IN PSMB_TIME Time
+ );
+
+#endif
+
+//++
+//
+// BOOLEAN
+// SmbIsTimeZero (
+// IN PSMB_TIME Time
+// )
+//
+// Routine Description:
+//
+// This macro returns TRUE if the supplied SMB_TIME value is zero.
+//
+// Arguments:
+//
+// Time - Pointer to SMB_TIME value to check. Must be aligned and
+// in native format!
+//
+// Return Value:
+//
+// BOOLEAN - TRUE if Time is zero, else FALSE.
+//
+//--
+
+#if !OS2SSSMBDBG
+
+#define SmbIsTimeZero(Time) ( (Time)->Ushort == 0 )
+
+#else
+
+BOOLEAN
+SmbIsTimeZero (
+ IN PSMB_TIME Time
+ );
+
+#endif
+
+#endif // def _OS2SSSMBGTPT_
diff --git a/private/os2/client/smbtypes.h b/private/os2/client/smbtypes.h
new file mode 100644
index 000000000..52787a602
--- /dev/null
+++ b/private/os2/client/smbtypes.h
@@ -0,0 +1,360 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ smbtypes.h
+
+Abstract:
+
+ This module defines types related to SMB processing.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 1-Dec-1989
+ David Treadwell (davidtr)
+Revision History:
+
+--*/
+
+#ifndef _SMBTYPES_
+#define _SMBTYPES_
+
+//#include <nt.h>
+
+//
+// SMBDBG determines whether the get/put macros (in smbgtpt.h) are
+// instead defined as function calls. (This is used to more reliably
+// find char/short/long mismatches.
+//
+
+#ifndef SMBDBG
+#define SMBDBG 0
+#endif
+
+//
+// SMBDBG1 determines whether the names of short and long fields in SMB
+// structures have an extra character appended. This is used to ensure
+// that these fields are only accessed via the get/put macros. SMBDBG1
+// must be disabled when SMBDBG is enabled.
+//
+
+#ifndef SMBDBG1
+#define SMBDBG1 0
+#endif
+
+#if SMBDBG && SMBDBG1
+#undef SMBDBG1
+#define SMBDBG1 0
+#endif
+
+//
+// If __unaligned support is available, or if we're compiling for a
+// machine that handles unaligned accesses in hardware, then define
+// SMB_USE_UNALIGNED as 1 (TRUE). Otherwise, define it as 0 (FALSE).
+// If SMB_USE_UNALIGNED is FALSE, then the macros below use byte
+// accesses to build up word and longword accesses to unaligned fields.
+//
+// Currently, the machines we build for all have SMB_USE_UNALIGNED as
+// TRUE. x86 supports unaligned accesses in hardware, while the MIPS
+// compiler supports the __unaligned keyword.
+//
+// Note that if SMB_USE_UNALIGNED is predefined, we use that definition.
+// Also, if SMB_NO_UNALIGNED is defined as TRUE, it forces
+// SMB_USE_ALIGNED off. This allows us to force, for testing purposes,
+// use of byte accesses in the macros.
+//
+
+#ifndef SMB_NO_UNALIGNED
+#define SMB_NO_UNALIGNED 0
+#endif
+
+#ifndef SMB_USE_UNALIGNED
+#if SMB_NO_UNALIGNED
+#define SMB_USE_UNALIGNED 0
+#else
+#define SMB_USE_UNALIGNED 1
+#endif
+#endif
+
+//
+// ntdef.h defines UNALIGNED as "__unaligned" or "", depending on
+// whether we're building for MIPS or x86, respectively. Because we
+// want to be able to disable use of __unaligned, we define
+// SMB_UNALIGNED as "UNALIGNED" or "", depending on whether
+// SMB_USE_UNALIGNED is TRUE or FALSE, respectively.
+//
+
+#if SMB_USE_UNALIGNED
+#define SMB_UNALIGNED UNALIGNED
+#else
+#define SMB_UNALIGNED
+#endif
+
+//
+// For ease of use, we define types for unaligned pointers to shorts
+// and longs in SMBs. Note that "PUSHORT UNALIGNED" doesn't work.
+//
+
+typedef unsigned short SMB_UNALIGNED *PSMB_USHORT;
+typedef unsigned long SMB_UNALIGNED *PSMB_ULONG;
+
+//
+// Macros for renaming short and long SMB fields.
+//
+
+#if SMBDBG1
+
+#define _USHORT( field ) USHORT field ## S
+#define _ULONG( field ) ULONG field ## L
+
+#else
+
+#define _USHORT( field ) USHORT field
+#define _ULONG( field ) ULONG field
+
+#endif
+
+//
+// Force misalignment of the following structures
+//
+
+#ifndef NO_PACKING
+#include <packon.h>
+#endif // ndef NO_PACKING
+
+
+//
+// The SMB_DIALECT type corresponds to the different SMB dialects
+// that the server can speak. Associated with it is the DialectStrings[]
+// array that holds information about the ASCIIZ strings that are passed
+// in the Negotiate SMB.s
+//
+// These are listed in order from highest preference to lowest preference.
+// The assigned numbers correspond to the array SrvClientTypes[] in the
+// server module srvdata.c.
+//
+
+typedef enum _SMB_DIALECT {
+ SmbDialectNtLanMan = 0, // NT LAN Man
+ SmbDialectLanMan21 = 1, // OS/2 Lanman 2.1
+ SmbDialectDosLanMan21 = 2, // DOS Lanman 2.1
+ SmbDialectLanMan20 = 3, // OS/2 1.2 LanMan 2.0
+ SmbDialectDosLanMan20 = 4, // DOS LanMan 2.0
+ SmbDialectLanMan10 = 5, // 1st version of full LanMan extensions
+ SmbDialectMsNet30 = 6, // Larger subset of LanMan extensions
+ SmbDialectMsNet103 = 7, // Limited subset of LanMan extensions
+ SmbDialectPcLan10 = 8, // Alternate original protocol
+ SmbDialectPcNet10 = 9, // Original protocol
+ SmbDialectIllegal = 10
+} SMB_DIALECT, *PSMB_DIALECT;
+
+#define FIRST_DIALECT SmbDialectNtLanMan
+#define LAST_DIALECT SmbDialectIllegal
+#define IS_DOS_DIALECT(dialect) \
+ ( (BOOLEAN)( (dialect) == SmbDialectDosLanMan21 || \
+ (dialect) == SmbDialectDosLanMan20 || \
+ (dialect) > SmbDialectLanMan10 ) )
+#define IS_OS2_DIALECT(dialect) ( (BOOLEAN)!IS_DOS_DIALECT(dialect) )
+#define DIALECT_HONORS_UID(dialect) \
+ ( (BOOLEAN)(dialect <= SmbDialectDosLanMan20 ) )
+
+
+//
+// Date and time structures that conform to MS-DOS standard used in
+// some SMBs.
+//
+// !!! These structures are not portable--they depend on a little-endian
+// machine (TwoSeconds in lowest bits, etc.)
+//
+
+typedef union _SMB_DATE {
+ USHORT Ushort;
+ struct {
+ USHORT Day : 5;
+ USHORT Month : 4;
+ USHORT Year : 7;
+ } Struct;
+} SMB_DATE;
+typedef SMB_DATE SMB_UNALIGNED *PSMB_DATE;
+
+typedef union _SMB_TIME {
+ USHORT Ushort;
+ struct {
+ USHORT TwoSeconds : 5;
+ USHORT Minutes : 6;
+ USHORT Hours : 5;
+ } Struct;
+} SMB_TIME;
+typedef SMB_TIME SMB_UNALIGNED *PSMB_TIME;
+
+
+//
+// The SMB_FIND_BUFFER and SMB_FIND_BUFFER2 structures are used in the
+// Transaction2 Find protocols to return files matching the requested
+// specifications. They are identical except for the EaSize field
+// in SMB_FIND_BUFFER2.
+//
+
+typedef struct _SMB_FIND_BUFFER {
+ SMB_DATE CreationDate;
+ SMB_TIME CreationTime;
+ SMB_DATE LastAccessDate;
+ SMB_TIME LastAccessTime;
+ SMB_DATE LastWriteDate;
+ SMB_TIME LastWriteTime;
+ _ULONG( DataSize );
+ _ULONG( AllocationSize );
+ _USHORT( Attributes );
+ UCHAR FileNameLength;
+ CHAR FileName[1];
+} SMB_FIND_BUFFER;
+typedef SMB_FIND_BUFFER SMB_UNALIGNED *PSMB_FIND_BUFFER;
+
+typedef struct _SMB_FIND_BUFFER2 {
+ SMB_DATE CreationDate;
+ SMB_TIME CreationTime;
+ SMB_DATE LastAccessDate;
+ SMB_TIME LastAccessTime;
+ SMB_DATE LastWriteDate;
+ SMB_TIME LastWriteTime;
+ _ULONG( DataSize );
+ _ULONG( AllocationSize );
+ _USHORT( Attributes );
+ _ULONG( EaSize ); // this field intentionally misaligned!
+ UCHAR FileNameLength;
+ CHAR FileName[1];
+} SMB_FIND_BUFFER2;
+typedef SMB_FIND_BUFFER2 SMB_UNALIGNED *PSMB_FIND_BUFFER2;
+
+
+//
+// The following structures are used in OS/2 1.2 for extended attributes
+// (EAs). OS/2 2.0 uses the same structures as NT. See the OS/2
+// Programmer's Reference, Volume 4, Chapter 4 for more information.
+//
+// The FEA structure holds a single EA's name and value and is the
+// equivalent ofthe NT structure FILE_FULL_EA_INFORMATION.
+//
+
+typedef struct _FEA {
+ UCHAR fEA;
+ UCHAR cbName;
+ _USHORT( cbValue );
+} FEA;
+typedef FEA SMB_UNALIGNED *PFEA;
+
+//
+// The only legal bit in fEA is FEA_NEEDEA.
+//
+
+#define FEA_NEEDEA 0x80
+
+//
+// The FEALIST structure holds the names and values of multiple EAs
+// NT has no direct equivalent but rather strings together
+// FILE_FULL_EA_INFORMATION structures.
+//
+
+typedef struct _FEALIST {
+ _ULONG( cbList );
+ FEA list[1];
+} FEALIST;
+typedef FEALIST SMB_UNALIGNED *PFEALIST;
+
+//
+// The GEA structure holds the name of a single EA. It is used to
+// request the value of that EA in OS/2 API functions. The NT
+// equivalent is FILE_GET_EA_INFORMATION.
+//
+
+typedef struct _GEA {
+ UCHAR cbName;
+ CHAR szName[1];
+} GEA;
+typedef GEA SMB_UNALIGNED *PGEA;
+
+//
+// The GEALIST structure holds the names of multiple EAs. NT has no
+// direct equivalent but rather strings together FILE_GET_EA_INFORMATION
+// structures.
+//
+
+typedef struct _GEALIST {
+ _ULONG( cbList );
+ GEA list[1];
+} GEALIST;
+typedef GEALIST SMB_UNALIGNED *PGEALIST;
+
+//
+// The EAOP structure holds EA information needed by API calls. It has
+// no NT equivalent.
+//
+
+typedef struct _EAOP {
+ PGEALIST fpGEAList;
+ PFEALIST fpFEAList;
+ ULONG oError;
+} EAOP;
+typedef EAOP SMB_UNALIGNED *PEAOP;
+
+//
+// FSALLOCATE contains information about a disk returned by
+// SrvSmbQueryFsInfo.
+//
+
+typedef struct _FSALLOCATE {
+ _ULONG( idFileSystem );
+ _ULONG( cSectorUnit );
+ _ULONG( cUnit );
+ _ULONG( cUnitAvail );
+ _USHORT( cbSector );
+} FSALLOCATE, *PFSALLOCATE; // *** NOT SMB_UNALIGNED!
+
+//
+// VOLUMELABEL contains information about a volume label returned by
+// SrvSmbQueryFsInformation.
+//
+
+typedef struct _VOLUMELABEL {
+ UCHAR cch;
+ CHAR szVolLabel[12];
+} VOLUMELABEL, *PVOLUMELABEL; // *** NOT SMB_UNALIGNED!
+
+//
+// FSINFO holds information about a volume returned by
+// SrvSmbQueryFsInformation.
+//
+
+typedef struct _FSINFO {
+ _ULONG( ulVsn );
+ VOLUMELABEL vol;
+} FSINFO, *PFSINFO; // *** NOT SMB_UNALIGNED!
+
+//
+// File types (returned by OpenAndX and Transact2_Open)
+// FileTypeIPC is a private definition for the NT redirector and
+// is not in the smb protocol.
+//
+
+typedef enum _FILE_TYPE {
+ FileTypeDisk = 0,
+ FileTypeByteModePipe = 1,
+ FileTypeMessageModePipe = 2,
+ FileTypePrinter = 3,
+ FileTypeCommDevice = 4,
+ FileTypeIPC = 0xFFFE,
+ FileTypeUnknown = 0xFFFF
+} FILE_TYPE;
+
+//
+// Turn structure packing back off
+//
+
+#ifndef NO_PACKING
+#include <packoff.h>
+#endif // ndef NO_PACKING
+
+#endif // def _SMBTYPES_
+
diff --git a/private/os2/client/sources b/private/os2/client/sources
new file mode 100644
index 000000000..1fde2a2cb
--- /dev/null
+++ b/private/os2/client/sources
@@ -0,0 +1,123 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+!ENDIF
+
+MAJORCOMP=os2
+MINORCOMP=client
+
+TARGETNAME=os2dll
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=..\inc
+
+WIMPYMASM=1
+
+NO_READONLY_STRINGS=1
+
+SOURCES=dllcopy.c \
+ nlstable.c \
+ dlldir.c \
+ dllea.c \
+ dllerror.c \
+ dllevent.c \
+ dllfile.c \
+ dllfind.c \
+ dllfsd.c \
+ dllhandl.c \
+ dllremot.c \
+ dllinit.c \
+ dllcnfg.c \
+ dllname.c \
+ dllloadr.c \
+ dllmisc.c \
+ dllmsg.c \
+ dllnls.c \
+ dllpipe.c \
+ dllque.c \
+ dllsm.c \
+ dllsem.c \
+ dlltask.c \
+ dlltimer.c \
+ dllutil.c \
+ dllvm.c \
+ dllxcpt.c \
+ dllnp.c \
+ dllnls16.c \
+ fileinit.c \
+ dllvm16.c \
+ dlltsk16.c \
+ dllsig16.c \
+ dllfs16.c \
+ dllmsc16.c \
+ dllsem16.c \
+ dllkbd.c \
+ dllmou.c \
+ dllmon.c \
+ dllmsg16.c \
+ dllldr16.c \
+ dllque16.c \
+ dllpmwin.c \
+ dllpmsha.c \
+ dllvio.c \
+ coninit.c \
+ dllsub16.c \
+ dllsm16.c \
+ dllnp16.c \
+ dllpip16.c \
+ dllnet16.c \
+ dllmsl16.c \
+ dllioctl.c \
+ dllpmnt.c \
+ dllpmnt1.c \
+ conrqust.c \
+ dllnb.c \
+ dllflopy.c \
+ dllimmon.c \
+ dlldbcs.c \
+ vrremote.c \
+ dllwin32.c
+
+i386_SOURCES=i386\doscalls.asm i386\dllthunk.asm i386\dll16.asm i386\ldrstart.asm
+
+mips_SOURCES=mips\dllthunk.s
+
+
+!IFDEF PMNT
+
+ASM_DEFINES=-DPMNT=1
+C_DEFINES=-DOS2_CLIENT -DPMNT
+
+!ELSE
+
+C_DEFINES=-DOS2_CLIENT
+
+!ENDIF
+
+USE_CRTDLL=1
+
+# dllmutex.c
+# dllmuxwt.c
+#UMTYPE=nt
+#UMTEST=os2vm*os2sem*os2null*os2task
+#OPTIONAL_UMTEST=os2vm*os2sem*os2task*os2misc*os2test*os2null*os2que
+#OPTIONAL_UMTEST=os2dir*os2file*testpath*testdup*testwrit*testseek
+#OPTIONAL_UMTEST=tstfsize*tstreset*testexec*testpipe*teststd*testcopy
diff --git a/private/os2/client/thunk/acsnetb.def b/private/os2/client/thunk/acsnetb.def
new file mode 100644
index 000000000..126f07319
--- /dev/null
+++ b/private/os2/client/thunk/acsnetb.def
@@ -0,0 +1,12 @@
+LIBRARY ACSNETB
+PROTMODE
+
+;Note that IMPORTing is not necessary since we 'know' how to get to the
+; 32 bit, NT side, by magic (see nls.asm).
+;
+;All EXPORTS should have 1.0-compatible ordinals and "RESIDENTNAME"
+;EXPORTS usually get put in DOSCALLS.LIB; see LIB/MAKEFILE to make them private
+;EXPORTS DOSMONOPEN @4 RESIDENTNAME
+EXPORTS
+ NETBIOS @1 RESIDENTNAME
+
diff --git a/private/os2/client/thunk/all.cmd b/private/os2/client/thunk/all.cmd
new file mode 100644
index 000000000..9934a9231
--- /dev/null
+++ b/private/os2/client/thunk/all.cmd
@@ -0,0 +1,30 @@
+@echo ***********************************************************************
+@echo *
+@echo * In order to run this script you must check out the following files:
+@echo *
+@echo * doscalls.dll
+@echo * apilist.c
+@echo * ..\..\inc\ldrtabs.h
+@echo * ..\i386\doscalls.asm
+@echo *
+@echo ***********************************************************************
+@REM Save PATH
+@set ALL_PATH=%PATH%
+@PATH .\thunkcom;%PATH%
+@
+@if "%1"=="clean" goto clean
+@if "%1"=="dbcs" goto dbcs
+@
+nmake
+@goto end
+:dbcs
+nmake -i DBCS=1
+@goto end
+:clean
+nmake -i clean
+@
+:end
+@REM Restore PATH
+@set PATH=%ALL_PATH%
+@set ALL_PATH=
+
diff --git a/private/os2/client/thunk/apilist.awk b/private/os2/client/thunk/apilist.awk
new file mode 100644
index 000000000..63d13d4d9
--- /dev/null
+++ b/private/os2/client/thunk/apilist.awk
@@ -0,0 +1,20 @@
+BEGIN {
+ NLINES=0
+}
+
+{
+ if ($2 == "=>")
+ {
+ NLINES = NLINES + 1
+ line[NLINES] = $1
+ }
+}
+
+END {
+ print "PSZ Od216ApiTable[ " NLINES+1 " ] = {"
+ for (i = 1; i <= NLINES; i++)
+ print " \"" line[i] "\","
+ print " 0"
+ print "};"
+}
+
diff --git a/private/os2/client/thunk/apilist.c b/private/os2/client/thunk/apilist.c
new file mode 100644
index 000000000..462c06c0e
--- /dev/null
+++ b/private/os2/client/thunk/apilist.c
@@ -0,0 +1,327 @@
+PSZ Od216ApiTable[ 325 ] = {
+ "DosExitStub",
+ "LDRLibiReturn",
+ "DosExitProcessStub",
+ "DosReturn",
+ "DosExit",
+ "DosCWait",
+ "DosBeep",
+ "DosPhysicalDisk",
+ "DosGetCp",
+ "DosSetCp",
+ "DosSetProcCp",
+ "DosGetCtryInfo",
+ "DosGetDBCSEv",
+ "DosCaseMap",
+ "DosGetCollate",
+ "DosSleep",
+ "DosDevConfig",
+ "DosGetDateTime",
+ "DosSetDateTime",
+ "DosExecPgm",
+ "DosEnterCritSec",
+ "DosExitCritSec",
+ "DosKillProcess",
+ "DosSetPrty",
+ "DosResumeThread",
+ "DosSuspendThread",
+ "DosMakePipe",
+ "DosCreateQueue",
+ "DosOpenQueue",
+ "DosCloseQueue",
+ "DosPeekQueue",
+ "DosReadQueue",
+ "DosPurgeQueue",
+ "DosQueryQueue",
+ "DosWriteQueue",
+ "DosCallNmPipe",
+ "DosConnectNmPipe",
+ "DosDisConnectNmPipe",
+ "DosMakeNmPipe",
+ "DosPeekNmPipe",
+ "DosQNmPHandState",
+ "DosQNmPipeInfo",
+ "DosQNmPipeSemState",
+ "DosSetNmPHandState",
+ "DosSetNmPipeSem",
+ "DosTransactNmPipe",
+ "DosWaitNmPipe",
+ "DosBufReset",
+ "DosChdir",
+ "DosChgFilePtr",
+ "DosClose",
+ "DosCopy",
+ "DosICopy",
+ "DosDelete",
+ "DosDevIOCtl",
+ "DosDupHandle",
+ "DosEditName",
+ "DosFileIO",
+ "DosFindClose",
+ "DosFSAttach",
+ "DosFSCtl",
+ "DosMove",
+ "DosNewSize",
+ "DosQCurDir",
+ "DosQCurDisk",
+ "DosQFHandState",
+ "DosSetFHandState",
+ "DosQFSAttach",
+ "DosQFSInfo",
+ "DosQHandType",
+ "DosQVerify",
+ "DosRmDir",
+ "DosSearchPath",
+ "DosSelectDisk",
+ "DosSetFSInfo",
+ "DosSetMaxFH",
+ "DosSetVerify",
+ "DosErrClass",
+ "DosError",
+ "DosLoadModule",
+ "DosFreeModule",
+ "DosGetModHandle",
+ "DosGetModName",
+ "DosGetResource",
+ "DosGetResource2",
+ "DosFreeResource",
+ "DosQAppType",
+ "DosShutdown",
+ "DosCreateThread",
+ "DosExitList",
+ "DosGetInfoSeg",
+ "DosOpen",
+ "DosOpen2",
+ "DosRead",
+ "DosWrite",
+ "DosFindFirst",
+ "DosFindFirst2",
+ "DosEnumAttribute",
+ "DosQFileMode",
+ "DosQFileInfo",
+ "DosAllocSeg",
+ "DosFreeSeg",
+ "DosGetSeg",
+ "DosGiveSeg",
+ "DosReallocSeg",
+ "DosSizeSeg",
+ "DosAllocHuge",
+ "DosReallocHuge",
+ "DosGetHugeShift",
+ "DosAllocShrSeg",
+ "DosLockSeg",
+ "DosUnlockSeg",
+ "DosGetShrSeg",
+ "DosMemAvail",
+ "DosCreateCSAlias",
+ "DosSemClear",
+ "DosSemSet",
+ "DosSemWait",
+ "DosSemSetWait",
+ "DosSemRequest",
+ "DosCreateSem",
+ "DosOpenSem",
+ "DosCloseSem",
+ "DosMuxSemWait",
+ "DosFSRamSemRequest",
+ "DosFSRamSemClear",
+ "DosTimerAsync",
+ "DosTimerStart",
+ "DosTimerStop",
+ "DosGetProcAddr",
+ "DosQueryProcType",
+ "DosQueryResourceSize",
+ "DosSetSigHandler",
+ "DosFlagProcess",
+ "DosHoldSignal",
+ "DosSendSignal",
+ "DosSetVec",
+ "DosGetEnv",
+ "DosGetVersion",
+ "DosGetMachineMode",
+ "DosFindNext",
+ "DosGetPID",
+ "DosGetPPID",
+ "DosMkDir",
+ "DosMkDir2",
+ "DosSetFileMode",
+ "DosSetFileInfo",
+ "DosTrueGetMessage",
+ "DosScanEnv",
+ "DosPTrace",
+ "DosInsMessage",
+ "DosPutMessage",
+ "DosSubSet",
+ "DosSubAlloc",
+ "DosSubFree",
+ "DosStartSession",
+ "DosStopSession",
+ "DosSetSession",
+ "DosSelectSession",
+ "DosSMSetTitle",
+ "DosSMPMPresent",
+ "WinSetTitleAndIcon",
+ "DosGetPrty",
+ "DosQSysInfo",
+ "DosDevIOCtl2",
+ "DosICanonicalize",
+ "DosReadAsync",
+ "DosWriteAsync",
+ "DosFindNotifyClose",
+ "DosFindNotifyFirst",
+ "DosFindNotifyNext",
+ "DosFileLocks",
+ "DosQPathInfo",
+ "DosSetPathInfo",
+ "DosPortAccess",
+ "DosCLIAccess",
+ "WinQueryProfileString",
+ "WinQueryProfileSize",
+ "WinQueryProfileData",
+ "WinQueryProfileInt",
+ "WinWriteProfileData",
+ "WinWriteProfileString",
+ "WinCreateHeap",
+ "WinDestroyHeap",
+ "WinAllocMem",
+ "WinFreeMem",
+ "WinGetLastError",
+ "VioScrollUp",
+ "VioGetCurPos",
+ "VioSetCurPos",
+ "VioWrtTTY",
+ "VioGetMode",
+ "VioReadCellStr",
+ "VioScrollLf",
+ "VioReadCharStr",
+ "VioWrtCharStrAtt",
+ "VioWrtCellStr",
+ "VioWrtCharStr",
+ "VioWrtNCell",
+ "VioWrtNAttr",
+ "VioWrtNChar",
+ "VioScrollDn",
+ "VioScrollRt",
+ "VioGetAnsi",
+ "VioSetAnsi",
+ "VioGetConfig",
+ "VioGetCp",
+ "VioSetCp",
+ "VioGetCurType",
+ "VioSetCurType",
+ "VioSetMode",
+ "VioDeRegister",
+ "VioRegister",
+ "VioPopUp",
+ "VioEndPopUp",
+ "VioGetBuf",
+ "VioShowBuf",
+ "VioGetFont",
+ "VioSetFont",
+ "VioGetState",
+ "VioSetState",
+ "VioGetPhysBuf",
+ "VioModeUndo",
+ "VioModeWait",
+ "VioSavRedrawWait",
+ "VioSavRedrawUndo",
+ "VioScrLock",
+ "VioScrUnLock",
+ "VioPrtSc",
+ "VioPrtScToggle",
+ "KbdFlushBuffer",
+ "KbdGetStatus",
+ "KbdSetStatus",
+ "KbdPeek",
+ "KbdCharIn",
+ "KbdStringIn",
+ "KbdGetFocus",
+ "KbdFreeFocus",
+ "KbdClose",
+ "KbdOpen",
+ "KbdDeRegister",
+ "KbdRegister",
+ "KbdGetCp",
+ "KbdSetCp",
+ "KbdSetCustXt",
+ "KbdXlate",
+ "KbdGetHWID",
+ "KbdSetFgnd",
+ "KbdSynch",
+ "KbdShellInit",
+ "MouClose",
+ "MouDeRegister",
+ "MouDrawPtr",
+ "MouFlushQue",
+ "MouGetDevStatus",
+ "MouGetEventMask",
+ "MouGetNumButtons",
+ "MouGetNumMickeys",
+ "MouGetNumQueEl",
+ "MouGetPtrPos",
+ "MouGetPtrShape",
+ "MouGetScaleFact",
+ "MouOpen",
+ "MouReadEventQue",
+ "MouRegister",
+ "MouRemovePtr",
+ "MouSetDevStatus",
+ "MouSetEventMask",
+ "MouSetPtrPos",
+ "MouSetPtrShape",
+ "MouSetScaleFact",
+ "MouSynch",
+ "DosMonOpen",
+ "DosMonClose",
+ "DosMonRead",
+ "DosMonReg",
+ "DosMonWrite",
+ "NetGetDCName",
+ "NetHandleGetInfo",
+ "NetServerDiskEnum",
+ "NetServerEnum2",
+ "NetServerGetInfo",
+ "NetServiceControl",
+ "NetServiceEnum",
+ "NetServiceGetInfo",
+ "NetServiceInstall",
+ "NetShareEnum",
+ "NetShareGetInfo",
+ "NetUseAdd",
+ "NetUseDel",
+ "NetUseEnum",
+ "NetUseGetInfo",
+ "NetUserEnum",
+ "NetWkstaGetInfo",
+ "NetAccessAdd",
+ "NetAccessSetInfo",
+ "NetAccessGetInfo",
+ "NetAccessDel",
+ "NetShareAdd",
+ "NetShareDel",
+ "NetUserGetInfo",
+ "NetMessageBufferSend",
+ "Netbios",
+ "NetBiosClose",
+ "NetBiosEnum",
+ "NetBiosGetInfo",
+ "NetBiosOpen",
+ "NetBiosSubmit",
+ "DosMakeMailslot",
+ "DosDeleteMailslot",
+ "DosMailslotInfo",
+ "DosPeekMailslot",
+ "DosReadMailslot",
+ "DosWriteMailslot",
+ "DosIRemoteApi",
+ "NetIWkstaGetUserInfo",
+ "NetIUserPasswordSet",
+ "DosIEncryptSES",
+ "Dos32LoadModule",
+ "Dos32GetProcAddr",
+ "Dos32Dispatch",
+ "Dos32FreeModule",
+ "FarPtr2FlatPtr",
+ "FlatPtr2FarPtr",
+ 0
+};
diff --git a/private/os2/client/thunk/doscalls.def b/private/os2/client/thunk/doscalls.def
new file mode 100644
index 000000000..c717ecb68
--- /dev/null
+++ b/private/os2/client/thunk/doscalls.def
@@ -0,0 +1,179 @@
+LIBRARY DOSCALLS
+PROTMODE
+DATA MULTIPLE
+;SEGMENTS DOSMON_CODE PURE IOPL CONFORMING
+;SEGMENTS DosMon_DATA CLASS 'DATA' IMPURE
+
+;Note that IMPORTing is not necessary since we 'know' how to get to the
+; 32 bit, NT side, by magic (see doscalls.asm).
+;
+;All EXPORTS should have 1.0-compatible ordinals and "RESIDENTNAME"
+;EXPORTS usually get put in DOSCALLS.LIB; see LIB/MAKEFILE to make them private
+;EXPORTS DOSMONOPEN @4 RESIDENTNAME
+EXPORTS
+ DOSCWAIT @2
+ DOSENTERCRITSEC @3
+ DOSEXIT @5
+ DOSEXITCRITSEC @6
+ DOSEXITLIST @7
+ DOSGETINFOSEG @8
+ DOSGETPRTY @9
+ DOSKILLPROCESS @10
+ DOSSETPRTY @11
+ DOSPTRACE @12
+ DOSHOLDSIGNAL @13
+ DOSSETSIGHANDLER @14
+ DOSFLAGPROCESS @15
+ DOSMAKEPIPE @16
+ DOSSEMSETWAIT @20
+ DOSMUXSEMWAIT @22
+ DOSCLOSESEM @23
+ DOSCREATESEM @24
+ DOSOPENSEM @25
+ DOSRESUMETHREAD @26
+ DOSSUSPENDTHREAD @27
+ DOSSETDATETIME @28
+ DOSTIMERASYNC @29
+ DOSTIMERSTART @30
+ DOSTIMERSTOP @31
+ DOSSLEEP @32
+ DOSGETDATETIME @33
+ DOSALLOCSEG @34
+ DOSALLOCSHRSEG @35
+ DOSGETSHRSEG @36
+ DOSGIVESEG @37
+ DOSREALLOCSEG @38
+ DOSFREESEG @39
+ DOSALLOCHUGE @40
+ DOSGETHUGESHIFT @41
+ DOSREALLOCHUGE @42
+ DOSCREATECSALIAS @43
+ DOSLOADMODULE @44
+ DOSGETPROCADDR @45
+ DOSFREEMODULE @46
+ DOSGETMODHANDLE @47
+ DOSGETMODNAME @48
+ DOSGETMACHINEMODE @49
+ DOSBEEP @50
+ DOSCLIACCESS @51
+ DOSDEVCONFIG @52
+ DOSDEVIOCTL @53
+;#if PMNT
+; DOSSGSWITCHME @55
+;#endif
+ DOSBUFRESET @56
+ DOSCHDIR @57
+ DOSCHGFILEPTR @58
+ DOSCLOSE @59
+ DOSDELETE @60
+ DOSDUPHANDLE @61
+ DOSFILELOCKS @62
+ DOSFINDCLOSE @63
+ DOSFINDFIRST @64
+ DOSFINDNEXT @65
+ DOSMKDIR @66
+ DOSMOVE @67
+ DOSNEWSIZE @68
+ DOSPORTACCESS @69
+ DOSOPEN @70
+ DOSQCURDIR @71
+ DOSQCURDISK @72
+ DOSQFHANDSTATE @73
+ DOSQFILEINFO @74
+ DOSQFILEMODE @75
+ DOSQFSINFO @76
+ DOSQHANDTYPE @77
+ DOSQVERIFY @78
+ DOSRMDIR @80
+ DOSSELECTDISK @81
+ DOSSETFHANDSTATE @82
+ DOSSETFILEINFO @83
+ DOSSETFILEMODE @84
+ DOSSETMAXFH @85
+ DOSSETVERIFY @86
+ DOSSETVEC @89
+ DOSGETENV @91
+ DOSGETVERSION @92
+ DOSGETPID @94
+ DOSOPEN2 @95
+ DOSSETFSINFO @97
+ DOSQPATHINFO @98
+ DOSDEVIOCTL2 @99
+ DOSICANONICALIZE @100
+ DOSSETPATHINFO @104
+ DOSERROR @120
+ DOSGETSEG @121
+ DOSLOCKSEG @122
+ DOSUNLOCKSEG @123
+ DOSSIZESEG @126
+ DOSMEMAVAIL @127
+ DOSPHYSICALDISK @129
+ DOSGETCP @130
+ DOSSENDSIGNAL @134
+ DOSHUGESHIFT @135
+ DOSHUGEINCR @136
+ DOSREAD @137
+ DOSWRITE @138
+ DOSERRCLASS @139
+ DOSSEMREQUEST @140
+ DOSSEMCLEAR @141
+ DOSSEMWAIT @142
+ DOSSEMSET @143
+ DOSEXECPGM @144
+ DOSCREATETHREAD @145
+ DOSSUBSET @146
+ DOSSUBALLOC @147
+ DOSSUBFREE @148
+ DOSREADASYNC @149
+ DOSWRITEASYNC @150
+ DOSSEARCHPATH @151
+ DOSSCANENV @152
+ DOSSETCP @153
+ DOSGETRESOURCE @155
+ DOSGETPPID @156
+ DOSFSRAMSEMREQUEST @161
+ DOSFSRAMSEMCLEAR @162
+ DOSQAPPTYPE @163
+ DOSSETPROCCP @164
+ DOSQSYSINFO @166
+ DOSFSATTACH @181
+ DOSQFSATTACH @182
+ DOSFSCTL @183
+ DOSFINDFIRST2 @184
+ DOSMKDIR2 @185
+ DOSFILEIO @186
+ DOSFINDNOTIFYCLOSE @187
+ DOSFINDNOTIFYFIRST @188
+ DOSFINDNOTIFYNEXT @189
+ DOSEDITNAME @191
+ DOSCOPY @201
+ DOSENUMATTRIBUTE @204
+ DOSSHUTDOWN @206
+ DOSGETRESOURCE2 @207
+ DOSFREERESOURCE @208
+ DOSQUERYRESOURCESIZE @573
+ DOSQUERYPROCTYPE @587
+ DOSCALLBACK @157
+
+#if PMNT
+; DOSISEMREQUEST @18
+; DOSUNKNOWNAPI54 @54
+ DOSSYSTEMSERVICE @88
+ DOSSYSTRACE @90
+ DOSSETFGND @101
+; DOSUNKNOWNAPI105 @105
+; DOSIRAMSEMWAKE @125
+ DOSR2STACKREALLOC @160
+ DOSICOPY @200
+; DOSGIVESEGLIST @209
+#endif
+
+ DOSIREMOTEAPI @653
+ DOSIENCRYPTSES @654
+ NETIUSERPASSWORDSET @655
+ DOS32LOADMODULE
+ DOS32GETPROCADDR
+ DOS32DISPATCH
+ DOS32FREEMODULE
+ FARPTR2FLATPTR
+ FLATPTR2FARPTR
diff --git a/private/os2/client/thunk/doscalls.mif b/private/os2/client/thunk/doscalls.mif
new file mode 100644
index 000000000..ea83dae3c
--- /dev/null
+++ b/private/os2/client/thunk/doscalls.mif
@@ -0,0 +1,2370 @@
+/*** doscalls.mif - Dos script file for the thunk compiler
+ *
+ * History:
+ * 9-Apr-91 YaronS moved over from os2 2.0. Redefine PUSHORT and
+ * PULONGS to pointers to structures, (PSUS, PSUL),
+ * such that the compiler will transform them correctly.
+ * Also - added missing thunks to complete all base apis.
+ *
+ * 25-Feb-92 MichaelJ (mjarus) removed all PSUS-PSUL & inout;
+ */
+
+/****
+ The following line tells the thunk compiler that ES will be
+ preserved by the system when called.
+****/
+
+
+syscall = true;
+inline = false;
+
+
+#include "os2def.tif"
+#include "dosthk.tif"
+
+ /*
+ * DosCreateThread differ in parameter order etc between
+ * 1.X and 2.0, so we just go to 32 flat, and then do
+ * what necessary (see client\i386\dll16.asm)
+ */
+USHORT DosCreateThread(PVOID pfnFun, PUSHORT pTid, PBYTE pbStack)=
+ULONG _Dos16CreateThread(PVOID pfnFun, PUSHORT pTid, PBYTE pbStack)
+{
+ pbStack = input;
+}
+
+USHORT DosExitList(USHORT fFnCode, PVOID pfnFunction)=
+ULONG _Dos16ExitList(ULONG fFnCode, PVOID pfnFunction)
+{}
+
+
+USHORT DosGetPID(PVOID ppidInfo)=
+ULONG _DosGetPID(PVOID ppidInfo)
+{
+}
+
+USHORT DosGetPPID(USHORT pidChild, PUSHORT ppidParent)=
+ULONG _DosGetPPID(ULONG pidChild, PUSHORT ppidParent)
+{
+}
+
+USHORT DosGetPrty(USHORT usScope, PUSHORT pusPriority, USHORT pid)=
+ULONG _DosGetPriority(ULONG ulScope, PUSHORT pusPriority, ULONG pid)
+{
+}
+
+USHORT DosGetInfoSeg(PSEL pselGlobal, PSEL pselLocal)=
+ULONG _DosGetInfoSeg(PSEL pselGlobal, PSEL pselLocal)
+{
+}
+
+
+
+/*
+ * File System APIs
+*/
+
+/* for _DosOpen we ignore the peop2 */
+USHORT DosOpen(PSZ pszFname, PUSHORT phfOpen, PUSHORT pusAction,
+ ULONG ulFSize, USHORT usAttr, USHORT fsOpenFlags,
+ USHORT fsOpenMode, ULONG ulReserved)=
+ULONG _Dos16Open(PSZ pszFileName, PUSHORT phf, PUSHORT pulAction,
+ ULONG cbFile, ULONG ulAttribute, ULONG fsOpenFlags,
+ ULONG fsOpenMode, ULONG ulReserved)
+{
+}
+
+USHORT DosOpen2(PSZ pszFileName, PUSHORT phfOpen, PUSHORT pusAction,
+ ULONG ulFSize, USHORT usAttr, USHORT usOpenFlags,
+ ULONG flOpenMode, PVOID pEAOBuf, ULONG ulReserved) =
+ULONG _Dos16Open2(PSZ pszFname, PUSHORT phf, PUSHORT pulAction,
+ ULONG ulFSize, ULONG ulAttr, ULONG ulOpenFlags,
+ ULONG ulOpenMode, PVOID pEAOP, ULONG ulReserved)
+{
+}
+
+USHORT DosRead(HFILE hf, PVOID pBuf, USHORT cbBuf, PUSHORT pcbBytesRead)=
+ULONG _Dos16Read(ULONG hFile, PVOID pBuffer, ULONG cbRead, PUSHORT pcbActual)
+{
+}
+
+USHORT DosWrite(HFILE hf, PVOID bBuf, USHORT cbBuf, PUSHORT pcbBytesWritten)=
+ULONG _Dos16Write(ULONG hFile, PVOID pBuffer, ULONG cbWrite, PUSHORT pcbActual)
+{
+}
+
+USHORT DosMkDir(PSZ pszDirName, ULONG ulReserved)=
+ULONG _Dos16MkDir(PSZ pszDirName, ULONG ulReserved)
+{
+}
+
+USHORT DosMkDir2(PSZ pszDir, PVOID peaop, ULONG ulReserved)=
+ULONG _Dos16MkDir2(PSZ pszDir, PVOID peaop, ULONG ulReserved)
+{
+}
+
+USHORT DosFindFirst(PSZ pszFSpec, PUSHORT phdir, USHORT usAttr,
+ PVOID pffb, USHORT cbBuf, PUSHORT pcSearch,
+ ULONG ulReserved)=
+ULONG _Dos16FindFirst(PSZ pszFileSpec, PUSHORT phdir, ULONG flAttribute,
+ PVOID pfindbuf, ULONG cbBuf, PUSHORT pcFileNames,
+ ULONG ulInfoLevel )
+{
+}
+
+USHORT DosFindFirst2(PSZ pszFSpec, PUSHORT phdir, USHORT usAttr,
+ PVOID pffb, USHORT cbBuf, PUSHORT pcSearch,
+ USHORT infolevel, ULONG ulReserved)=
+ULONG _Dos16FindFirst2(PSZ pszFileSpec, PUSHORT phdir, ULONG flAttribute,
+ PVOID pfindbuf, ULONG cbBuf, PUSHORT pcFileNames,
+ ULONG ulInfoLevel, ULONG ulReserved)
+{
+}
+
+USHORT DosQFileMode(PSZ pszFName, PUSHORT pusAttr, ULONG ulReserved)=
+ULONG _DosQFileMode(PSZ pszFName, PUSHORT pusAttr, ULONG ulReserved)
+{
+}
+
+USHORT DosSetFileMode(PSZ pszFName, USHORT usAttr, ULONG ulReserved)=
+ULONG _DosSetFileMode(PSZ pszFName, ULONG usAttr, ULONG ulReserved)
+{
+}
+
+USHORT DosSetFileInfo(HFILE hf, USHORT usInfoLevel, PVOID pInfoBuf,
+ USHORT cbInfoBuf)=
+ULONG _Dos16SetFileInfo(ULONG hf, ULONG usInfoLevel, PVOID pInfoBuf,
+ ULONG cbInfoBuf)
+{
+}
+
+USHORT DosSetFHandState(HFILE hf, USHORT fsState)=
+ULONG _DosSetFHState(ULONG hf, ULONG fsState)
+{
+}
+
+USHORT DosFindNext(HDIR hdir, /*PFILEFINDBUF*/ PVOID pffb, USHORT cbBuf,
+ PUSHORT pcSearch)=
+ULONG _Dos16FindNext(ULONG hdir, /*PFILEFINDBUF*/ PVOID pffb, ULONG cbBuf,
+ PUSHORT pcSearch)
+{
+}
+
+USHORT DosQFileInfo(HFILE hf, USHORT usInfoLevel, PVOID pInfoBuf,
+ USHORT cbInfoBuf)=
+ULONG _DosQFileInfo(ULONG hf, ULONG usInfoLevel, PVOID pInfoBuf,
+ ULONG cbInfoBuf)
+{
+}
+
+/*
+ * pick up the following apis later
+ */
+/**************
+APIRET APIENTRY DosFindNotifyFirst(PSZ pszPath, PHDIR hdir, USHORT usAttr,
+ PVOID pBuf, USHORT cbBuf, PUSHORT pcChg,
+ USHORT usInfoLevel, ULONG ulTimeOut,
+ ULONG ulReserved);
+APIRET APIENTRY DosFindNotifyNext(HDIR hDir, PVOID pBuf, USHORT cbBuf,
+ PUSHORT pcChg, ULONG ulTimeOut);
+APIRET APIENTRY DosFindNotifyClose(HDIR hDir);
+
+**************/
+
+USHORT DosEnumAttribute(USHORT fRefType, PVOID pFileRef, ULONG iStartEntry,
+ PVOID pEnumBuf, ULONG cbBuf,
+ PULONG pcbActual, ULONG infoLevel, ULONG reserved)=
+ULONG _Dos16EnumAttribute(ULONG fRefType, PVOID pFileRef, ULONG iStartEntry,
+ PVOID pEnumBuf, ULONG cbBuf,
+ PULONG pcbActual, ULONG infoLevel, ULONG reserved)
+{
+}
+
+/*
+ * 16 bit Memory management
+ */
+
+USHORT DosAllocSeg(USHORT cbSize, PSEL pSel, USHORT fsAlloc)=
+ULONG _DosAllocSeg(ULONG cbSize, PSEL pSel, ULONG fsAlloc)
+{
+}
+USHORT DosFreeSeg(SEL sel)=
+ULONG _DosFreeSeg(ULONG sel)
+{}
+
+USHORT DosGetSeg(SEL sel)=
+ULONG _DosGetSeg(ULONG sel)
+{}
+USHORT DosGiveSeg(SEL sel, PID pid, PSEL pSelRecipient)=
+ULONG _DosGiveSeg(ULONG sel, ULONG pid, PSEL pSelRecipient)
+{
+}
+
+USHORT DosReallocSeg(USHORT cbNewSize, SEL sel)=
+ULONG _DosReallocSeg(ULONG cbNewSize, ULONG sel)
+{}
+
+USHORT DosSizeSeg(SEL sel, PULONG pcbSize)=
+ULONG _DosSizeSeg(ULONG sel, PULONG pcbSize)
+{
+}
+
+USHORT DosAllocHuge(USHORT cSegs, USHORT cbPartialSeg, PSEL psel,
+ USHORT cMaxSegs, USHORT fsAlloc)=
+ULONG _DosAllocHuge(ULONG cSegs, ULONG cbPartialSeg, PSEL psel,
+ ULONG cMaxSegs, ULONG fsAlloc)
+{
+}
+USHORT DosReallocHuge(USHORT cSegs, USHORT cbPartialSeg, SEL sel)=
+ULONG _DosReallocHuge(ULONG cSegs, ULONG cbPartialSeg, ULONG sel)
+{}
+
+USHORT DosGetHugeShift(PUSHORT pusShiftCount)=
+ULONG _DosGetHugeShift(PUSHORT pusShiftCount)
+{
+}
+USHORT DosAllocShrSeg(USHORT cbSeg, PSZ pszSegName, PSEL psel)=
+ULONG _DosAllocShrSeg(ULONG cbSeg, PSZ pszSegName, PSEL psel)
+{
+}
+USHORT DosLockSeg(SEL sel)=
+ULONG _DosLockSeg(ULONG sel)
+{}
+USHORT DosUnlockSeg(SEL sel)=
+ULONG _DosUnlockSeg(ULONG sel)
+{}
+USHORT DosGetShrSeg(PSZ pszSegName, PSEL psel)=
+ULONG _DosGetShrSeg(PSZ pszSegName, PSEL psel)
+{
+}
+USHORT DosMemAvail(PULONG pcbFree)=
+ULONG _DosMemAvail(PULONG pcbFree)
+{
+}
+USHORT DosCreateCSAlias(SEL selDS, PSEL pselCS)=
+ULONG _DosCreateCSAlias(ULONG selDS, PSEL pselCS)
+{
+}
+
+/*** 16 bit Semaphore support */
+USHORT DosSemClear(HSEM hsem)=
+ULONG _DosSemClear(HSEM hsem)
+{}
+USHORT DosSemSet(HSEM hsem)=
+ULONG _DosSemSet(HSEM hsem)
+{}
+USHORT DosSemWait(HSEM hsem, LONG lTimeOut)=
+ULONG _DosSemWait(HSEM hsem, LONG lTimeOut)
+{}
+USHORT DosSemSetWait(HSEM hsem, LONG lTimeOut)=
+ULONG _DosSemSetWait(HSEM hsem, LONG lTimeOut)
+{}
+USHORT DosSemRequest(HSEM hsem, LONG lTimeOut)=
+ULONG _DosSemRequest(HSEM hsem, LONG lTimeOut)
+{}
+
+USHORT DosCreateSem(USHORT fExclusive,PHSYSSEM phsem,PSZ pszSemName)=
+ULONG _DosCreateSem(ULONG fExclusive,PHSYSSEM phsem,PSZ pszSemName)
+{
+}
+USHORT DosOpenSem(PHSEM phsem, PSZ pszSemName)=
+ULONG _DosOpenSem(PHSEM phsem, PSZ pszSemName)
+{
+}
+USHORT DosCloseSem(HSEM hsem)=
+ULONG _DosCloseSem(HSEM hsem)
+{}
+USHORT DosMuxSemWait(PUSHORT pisemCleared,PVOID pmsxl,LONG lTimeOut)=
+ULONG _DosMuxSemWait(PUSHORT pisemCleared,PVOID pmsxl,LONG lTimeOut)
+{
+}
+USHORT DosFSRamSemRequest(PVOID pdosfsrs, LONG lTimeOut)=
+ULONG _DosFSRamSemRequest(PVOID pdosfsrs, LONG lTimeOut)
+{}
+USHORT DosFSRamSemClear(PVOID pdosfsrs)=
+ULONG _DosFSRamSemClear(PVOID pdosfsrs)
+{}
+
+ /* timers have actual Cruiser equivalents */
+USHORT DosTimerAsync(ULONG ulTime, HSEM hsem, PHTIMER phtimer)=
+ULONG _DosAsyncTimer(ULONG ulTime, HSEM hsem, PHTIMER phtimer)
+{
+}
+
+USHORT DosTimerStart(ULONG ulTime, HSEM hsem, PHTIMER phtimer)=
+ULONG _DosStartTimer(ULONG ulTime, HSEM hsem, PHTIMER phtimer)
+{
+}
+
+USHORT DosTimerStop(HTIMER htimer)=
+ULONG _DosStopTimer(ULONG htimer)
+{}
+
+
+USHORT DosGetProcAddr(HMODULE hmod,
+ PSZ pszProcName, PFN* ppfnProcAddr)=
+ULONG _DosGetProcAddrNE(ULONG hmod,
+ PSZ pszName,PFN* ppfn)
+{
+}
+
+USHORT DosQueryProcType(HMODULE hmod, ULONG ordinal,
+ PSZ pszName, PULONG pulproctype)=
+ULONG _DosQueryProcType(ULONG hmod, ULONG ordinal,
+ PSZ pszName, PULONG pulproctype)
+{
+}
+
+USHORT DosGetResource2(HMODULE hmod, USHORT idType, USHORT idName,
+ PVOID ppData)=
+ULONG _DosGetResource2NE(ULONG, ULONG, ULONG, PVOID ppData)
+{}
+
+USHORT DosFreeResource(PVOID pData)=
+ULONG _DosFreeResourceNE(PVOID pb)
+{}
+
+USHORT DosQueryResourceSize(HMODULE hmod, ULONG idt, ULONG idn,
+ PULONG pulsize)=
+ULONG _DosQueryResourceSize(ULONG hmod, ULONG idt, ULONG idn,
+ PULONG pulsize)
+{
+}
+
+/*** NLS Support */
+
+USHORT DosCaseMap(USHORT usLen, PVOID pctryc, PCHAR pchStr)=
+ULONG _DosCaseMap(ULONG usLen, PVOID pctryc, PCHAR pchStr)
+{}
+
+USHORT DosGetCollate(USHORT cbBuf, PVOID pctryc, PCHAR pchBuf,
+ PUSHORT pcbTable)=
+ULONG _DosGetCollate(ULONG cbBuf, PVOID pctryc, PCHAR pchBuf,
+ PUSHORT pcbTable)
+{}
+
+USHORT DosGetCtryInfo(USHORT cbBuf, PVOID pctryc,
+ PVOID pctryi, PUSHORT pcbCtryInfo)=
+ULONG _DosGetCtryInfo(ULONG cbBuf, PVOID pctryc,
+ PVOID pctryi, PUSHORT pcbCtryInfo)
+{}
+
+USHORT DosGetCp(USHORT cbBuf, PUSHORT pBuf, PUSHORT pcbCodePgLst)=
+ULONG _DosGetCp(ULONG cbBuf, PUSHORT pBuf, PUSHORT pcbCodePgLst)
+{}
+
+USHORT DosSetCp(USHORT usCodePage,USHORT ulReserved) =
+ULONG _DosSetCp(ULONG usCodePage,ULONG ulReserved)
+{}
+
+USHORT DosSetProcCp(USHORT usCodePage,USHORT ulReserved) =
+ULONG _DosSetProcCp(ULONG usCodePage,ULONG ulReserved)
+{}
+
+USHORT DosGetDBCSEv(USHORT cbBuf, PVOID pcrtyc, PCHAR pchBuf)=
+ULONG _DosGetDBCSEv(ULONG cbBuf, PVOID pcrtyc, PCHAR pchBuf)
+{
+}
+
+/*** 16 bit Signal support */
+
+USHORT DosSetSigHandler(PVOID pfnSigHandler,
+ PVOID ppfnPrev, PUSHORT pfAction,
+ USHORT fAction, USHORT usSigNum)=
+ULONG _DosSetSigHandler(PVOID pfnSigHandler,
+ PVOID ppfnPrev, PUSHORT pfAction,
+ ULONG fAction, ULONG usSigNum)
+{
+}
+USHORT DosFlagProcess(PID pid, USHORT fScope, USHORT usFlagNum,
+ USHORT usFlagArg)=
+ULONG DosFlagProcess16(ULONG pid, ULONG fScope, ULONG usFlagNum,
+ ULONG usFlagArg)
+{}
+USHORT DosHoldSignal(USHORT fDisable)=
+ULONG DosHoldSignal16(ULONG fDisable)
+{}
+USHORT DosSendSignal(USHORT idProcess, USHORT usSigNumber)=
+ULONG DosSendSignal16(ULONG idProcess, ULONG usSigNumber)
+{}
+
+
+USHORT DosSetVec(USHORT usVecNum, PFN pfnFun, PFN* ppfnPrev)=
+ULONG _DosSetVec(ULONG usVecNum, PFN pfnFun, PFN* ppfnPrev)
+{
+}
+
+USHORT DosPortAccess(USHORT usReserved, USHORT fRelease, USHORT usFirstPort, USHORT usLastPort)=
+ULONG _DosPortAccess(ULONG ulReserved, ULONG fRelease, ULONG ulFirstPort, ULONG ulLastPort)
+{}
+
+USHORT DosCLIAccess()=
+ULONG _DosCLIAccess()
+{}
+
+USHORT DosPTrace(PVOID pvTraceBuf)=
+ULONG _DosPTrace(PVOID pvTraceBuf)
+{
+}
+
+USHORT DosTrueGetMessage(PULONG ppchVTable, USHORT usVCount,
+ PCHAR pchBuf, USHORT cbBuf, USHORT usMsgNum,
+ PSZ pszFileName, PUSHORT pcbMsg, PBYTE pMsgSeg)=
+ULONG _DosTrueGetMessage(PULONG ppchVTable, ULONG usVCount,
+ PCHAR pchBuf, ULONG cbBuf, ULONG usMsgNum,
+ PSZ pszFileName, PUSHORT pcbMsg, PBYTE pMsgSeg)
+{
+}
+
+USHORT DosInsMessage(PULONG ppchVTable, USHORT usVCount,
+ PSZ pszMsg, USHORT cbMsg, PCHAR pchBuf,
+ USHORT cbBuf, PUSHORT pcbMsg)=
+ULONG _DosInsMessage(PULONG ppchVTable, ULONG usVCount,
+ PSZ pszMsg, ULONG cbMsg, PCHAR pchBuf,
+ ULONG cbBuf, PUSHORT pcbMsg)
+{
+}
+
+USHORT DosPutMessage(HFILE hf, USHORT cbMsg, PCHAR pchMsg)=
+ULONG _DosPutMessage(ULONG hf, ULONG cbMsg, PCHAR pchMsg)
+{
+}
+
+/* pick up later
+USHORT DosQueryMessageCP(PCHAR pb, USHORT cb, PSZ pszFilename,
+ PUSHORT cbBuf);
+USHORT DosSysTrace(USHORT, USHORT, USHORT, PCHAR);
+USHORT DosDynamicTrace(USHORT, PBYTE, PBYTE);
+*/
+
+USHORT DosQSysInfo(USHORT index, PUSHORT pBuf, USHORT cbBuf)=
+ULONG _DosQSysInfo(ULONG index, PUSHORT pBuf, ULONG cbBuf)
+{
+}
+
+USHORT DosGetEnv(PSEL pselEnv, PUSHORT pOffsetCmd)=
+ULONG _DosGetEnv(PSEL pselEnv, PUSHORT pOffsetCmd)
+{
+}
+
+USHORT DosGetVersion(PUSHORT pVer)=
+ULONG _DosGetVersion(PUSHORT pVer)
+{
+}
+USHORT DosGetMachineMode(PBYTE pMachMode)=
+ULONG _DosGetMachineMode(PBYTE pMachMode)
+{
+}
+
+
+/* session manager */
+
+/* pick up later
+USHORT DosSMRegisterDD(PVOID);
+*/
+
+USHORT DosSelectSession(USHORT idSession, ULONG ulReserved)=
+ULONG _DosSelectSession(ULONG idSession, ULONG ulReserved)
+{
+}
+
+USHORT DosSetSession(USHORT idSession, PVOID pstsdata)=
+ULONG _DosSetSession(ULONG idSession, PVOID pstsdata)
+{
+}
+
+USHORT DosStartSession(PVOID pstdata, PUSHORT pidSession,PUSHORT ppid)=
+ULONG _Dos16StartSession(PVOID pstdata, PUSHORT pidSession,PUSHORT ppid)
+{
+}
+
+USHORT DosStopSession(USHORT fScope, USHORT idSession,ULONG ulReserved)=
+ULONG _DosStopSession(ULONG fScope, ULONG idSession,ULONG ulReserved)
+{}
+
+/*
+ DosSMSetTitle is not part of the exposed API. Added here because the VI
+ editor references this function and VI is one of the apps used for
+ testing the VIO functions
+*/
+
+USHORT DosSMSetTitle(PSZ pszTitle)=
+ULONG _DosSMSetTitle(PSZ pszTitle)
+{}
+
+/*
+ DosSMPMPresent and WinSetTitleAndIcon were added to support
+ Hamilton C Shell
+*/
+
+USHORT DosSMPMPresent(PUSHORT Flag)=
+ULONG _DosSMPMPresent(PUSHORT Flag)
+{
+}
+
+#ifndef PMNT
+
+USHORT WinSetTitleAndIcon(PSZ szTitle, PSZ szIconFilePath)=
+ULONG _WinSetTitleAndIcon(PSZ szTitle, PSZ szIconFilePath)
+{
+}
+
+#endif
+
+/*** DosProfile API support */
+/* pick later
+USHORT DosTmrQueryFreq(PULONG pulTmrFreq);
+USHORT DosTmrQueryTime(PQWORD pqwTmrTime);
+USHORT DosRegisterPerfCtrs(PBYTE pbDataBlk, PBYTE pbTextBlk, ULONG flFlags);
+*/
+
+USHORT DosCWait(USHORT, USHORT, PVOID prescResults, PUSHORT ppidProcess, PID)=
+ULONG _Dos16WaitChild(ULONG, ULONG, PVOID prescResults, PUSHORT ppidProcess, ULONG)
+{
+}
+
+
+USHORT DosBeep(USHORT,USHORT)=
+ULONG _DosBeep(ULONG,ULONG)
+{}
+
+USHORT DosPhysicalDisk(USHORT,PBYTE pbOutBuf,USHORT cbOutBuf,PBYTE pbParamBuf,USHORT cbParamBuf) =
+ULONG _DosPhysicalDisk(ULONG,PBYTE pbOutBuf,ULONG cbOutBuf,PBYTE pbParamBuf,ULONG cbParamBuf)
+{
+}
+
+USHORT DosSleep(ULONG)=
+ULONG _DosSleep(ULONG)
+{}
+
+USHORT DosGetDateTime(PVOID pDT) =
+ULONG _DosGetDateTime(PVOID pDT)
+{
+}
+
+USHORT DosSetDateTime(PVOID pDT) =
+ULONG _DosSetDateTime(PVOID pDT)
+{
+}
+
+USHORT DosDevConfig(PVOID DevInfo, USHORT item, USHORT reserved) =
+ULONG _DosDevConfig(PVOID DevInfo, ULONG item, USHORT reserved deleted 0)
+{
+}
+
+USHORT DosExecPgm(PCHAR pchFailName, USHORT cbFailName, USHORT, PSZ, PSZ, PVOID prescResults, PSZ)=
+ULONG _Dos16ExecPgm(PCHAR pchFailName, ULONG cbFailName, ULONG, PSZ, PSZ, PVOID prescResults, PSZ)
+{
+}
+
+void DosEnterCritSec()=
+void _DosEnterCritSec()
+{}
+
+void DosExitCritSec()=
+void _DosExitCritSec()
+{}
+
+void DosExit(USHORT, USHORT)=
+void _DosExit(ULONG, ULONG)
+{}
+
+
+USHORT DosKillProcess(USHORT, PID)=
+ULONG _DosKillProcess(ULONG, ULONG)
+{}
+
+USHORT DosSetPrty(USHORT, USHORT, short, USHORT)=
+ULONG _DosSetPriority(ULONG, ULONG, long, ULONG)
+{}
+
+
+USHORT DosResumeThread(TID)=
+ULONG _DosResumeThread(ULONG)
+{}
+
+USHORT DosSuspendThread(TID)=
+ULONG _DosSuspendThread(ULONG)
+{}
+
+
+USHORT DosMakePipe(PUSHORT phfRead, PUSHORT phfWrite, USHORT)=
+ULONG _Dos16CreatePipe(PUSHORT phfRead, PUSHORT phfWrite, ULONG)
+{
+}
+
+
+USHORT DosCreateQueue(PUSHORT phqueue, USHORT, PSZ)=
+ULONG _Dos16CreateQueue(PUSHORT phqueue, ULONG, PSZ)
+{
+}
+
+
+USHORT DosOpenQueue(PUSHORT ppidOwner, PUSHORT phqueue, PSZ)=
+ULONG _Dos16OpenQueue(PUSHORT ppidOwner, PUSHORT phqueue, PSZ)
+{
+}
+
+USHORT DosCloseQueue(HQUEUE)=
+ULONG _DosCloseQueue(ULONG)
+{}
+
+USHORT DosPeekQueue(HQUEUE, PVOID pulResult, PUSHORT pusDataLength, PULONG pulDataAddr, PUSHORT pusElementCode, UCHAR, PBYTE pbElemPrty, HSEM)=
+ULONG _Dos16PeekQueue(ULONG, PVOID pulResult, PUSHORT pusDataLength, PULONG pulDataAddr, PUSHORT pusElementCode, ULONG, PBYTE pbElemPrty, HSEM)
+{
+}
+
+USHORT DosReadQueue(HQUEUE, PVOID pulResult, PUSHORT pusDataLength, PULONG pulDataAddr, USHORT, UCHAR, PBYTE pbElemPrty, HSEM)=
+ULONG _Dos16ReadQueue(ULONG, PVOID pulResult, PUSHORT pusDataLength, PULONG pulDataAddr, ULONG, ULONG, PBYTE pbElemPrty, HSEM)
+{
+}
+
+USHORT DosPurgeQueue(HQUEUE)=
+ULONG _DosPurgeQueue(ULONG)
+{}
+
+USHORT DosQueryQueue(HQUEUE, PUSHORT pusElemCount)=
+ULONG _Dos16QueryQueue(ULONG, PUSHORT pusElemCount)
+{
+}
+
+
+USHORT DosWriteQueue(HQUEUE, USHORT, USHORT cbBuf, PBYTE pbBuf, UCHAR)=
+ULONG _DosWriteQueue(ULONG, ULONG, ULONG cbBuf, PBYTE pbBuf, ULONG)
+{
+ cbBuf = sizeof pbBuf;
+}
+
+
+USHORT DosSubAlloc(SEL, PUSHORT pusOffset, USHORT)=
+ULONG _Dos16SubAlloc(ULONG, PUSHORT pusOffset, ULONG)
+{
+}
+
+USHORT DosSubFree(SEL, USHORT, USHORT)=
+ULONG _Dos16SubFree(ULONG, ULONG, ULONG)
+{}
+
+USHORT DosSubSet(SEL, USHORT, USHORT)=
+ULONG _Dos16SubSet(ULONG, ULONG, ULONG)
+{}
+
+USHORT DosCallNmPipe(PSZ, PBYTE pbInBuf, USHORT cbInBuf, PBYTE pbOutBuf, USHORT cbOutBuf, PUSHORT pcbRead, ULONG)=
+ULONG _Dos16CallNPipe(PSZ, PBYTE pbInBuf, ULONG cbInBuf, PBYTE pbOutBuf, ULONG cbOutBuf, PUSHORT pcbRead, ULONG)
+{
+}
+
+
+USHORT DosConnectNmPipe(HPIPE)=
+ULONG _DosConnectNPipe(ULONG)
+{}
+
+USHORT DosDisConnectNmPipe(HPIPE)=
+ULONG _DosDisConnectNPipe(ULONG)
+{}
+
+
+USHORT DosMakeNmPipe(PSZ, PUSHORT pHandle, USHORT, USHORT, USHORT, USHORT,ULONG)=
+ULONG _Dos16CreateNPipe(PSZ, PUSHORT, ULONG, ULONG, ULONG, ULONG, ULONG)
+{
+}
+
+
+USHORT DosPeekNmPipe(HPIPE, PBYTE pbBuf, USHORT cbBuf, PUSHORT pcbRead, PUSHORT pcbAvail, PUSHORT pfsState)=
+ULONG _Dos16PeekNPipe(ULONG, PBYTE pbBuf, ULONG cbBuf, PUSHORT pcbRead, PUSHORT pcbAvail, PUSHORT pfsState)
+{
+}
+
+
+USHORT DosQNmPHandState(HPIPE, PUSHORT pfsState)=
+ULONG _Dos16QueryNPHState(ULONG, PUSHORT pfsState)
+{
+}
+
+USHORT DosQNmPipeInfo(HPIPE, USHORT, PBYTE pbBuf, USHORT cbBuf)=
+ULONG _DosQueryNPipeInfo(ULONG, ULONG, PBYTE pbBuf, ULONG cbBuf)
+{
+}
+
+USHORT DosQNmPipeSemState(HSEM, PBYTE pbBuf, USHORT cbBuf)=
+ULONG _DosQueryNPipeSemState(HSEM, PBYTE pbBuf, ULONG cbBuf)
+{
+}
+
+/*
+USHORT DosRawReadNmPipe(USHORT, PBYTE pbBuf, USHORT cbBuf, PUSHORT pcbBytesRead)=
+ULONG _DosRawReadNPipe(ULONG, PBYTE pbBuf, ULONG cbBuf, PUSHORT pcbBytesRead)
+{
+}
+
+USHORT DosRawWriteNmPipe(USHORT, PBYTE pbBuf, USHORT cbBuf, PUSHORT pcbBytesWritten)=
+ULONG _DosRawWriteNPipe(ULONG, PBYTE pbBuf, ULONG cbBuf, PUSHORT)
+{
+}
+*/
+
+
+USHORT DosSetNmPHandState(HPIPE, USHORT)=
+ULONG _DosSetNPHState(ULONG, ULONG)
+{}
+
+USHORT DosSetNmPipeSem(HPIPE, HSEM, USHORT)=
+ULONG _DosSetNPipeSem(ULONG, HSEM, ULONG)
+{}
+
+
+USHORT DosTransactNmPipe(HPIPE, PBYTE pbInBuf, USHORT cbInBuf, PBYTE pbOutBuf, USHORT cbOutBuf, PUSHORT pcbRead)=
+ULONG _Dos16TransactNPipe(ULONG, PBYTE pbInBuf, ULONG cbInBuf, PBYTE pbOutBuf, ULONG cbOutBuf, PUSHORT pcbRead)
+{
+}
+
+USHORT DosWaitNmPipe(PSZ, ULONG)=
+ULONG _DosWaitNPipe(PSZ, ULONG)
+{}
+
+
+/**** File I/O *****/
+
+USHORT DosBufReset(HFILE hand)=
+ULONG _DosResetBuffer(ULONG)
+{
+}
+
+USHORT DosChdir(PSZ, ULONG)=
+ULONG _DosSetCurrentDir(PSZ, ULONG deleted 0)
+{}
+
+USHORT DosChgFilePtr(HFILE, long, USHORT, PULONG pulNewPtr)=
+ULONG _DosSetFilePtr(ULONG, long, ULONG, PULONG pulNewPtr)
+{
+}
+
+USHORT DosClose(HFILE)=
+ULONG _DosClose(ULONG)
+{}
+
+USHORT DosCopy(PSZ,PSZ,USHORT,ULONG)=
+ULONG _DosCopy(PSZ,PSZ,ULONG,ULONG deleted)
+{}
+
+/* Unpublished API (DOSCALLS.200). */
+USHORT DosICopy(PSZ,PSZ,USHORT,ULONG)=
+ULONG _DosICopy(PSZ,PSZ,ULONG,ULONG deleted)
+{
+}
+
+USHORT DosDelete(PSZ, ULONG)=
+ULONG _DosDelete(PSZ, ULONG deleted)
+{}
+
+USHORT DosDevIOCtl(PVOID pvData, PVOID pvParms, USHORT Function,
+ USHORT Category, HFILE hDev)=
+ULONG _DosDevIOCtl(PVOID pvData, PVOID pvParms, ULONG Function,
+ ULONG Category, ULONG hDev)
+{
+}
+
+USHORT DosDevIOCtl2(PVOID pvData, USHORT cbData, PVOID pvParms, USHORT cbParms,
+ USHORT Function, USHORT Category, HFILE hDev)=
+ULONG _DosDevIOCtl2(PVOID pvData, ULONG cbData, PVOID pvParms, ULONG cbParms,
+ ULONG Function, ULONG Category, ULONG hDev)
+{
+}
+
+/* Unpublished API DosICanonicalize(DOSCALLS.100) */
+/*
+;*** DOSICANONICALIZE - Convert a path name into a standard format
+;
+; INTERNAL ONLY API. Used by a couple of dynamic link libraries.
+; The worker routine does NO error checking or memory protection
+; checks. It is possible to general an internal error if used
+; incorrectly. DO NOT PUBLISH.
+;
+; INVOKE PUSH@ ASCIIZ Source (2 words)
+; PUSH@ ASCIIZ Dest (2 words)
+; PUSH WORD BackupOffset (1 word)
+; PUSH WORD DestEnd (1 word)
+; PUSH WORD Flags (1 word)
+; call DOSICANONICALIZE
+;
+; RETURN (ax) = error code
+;
+*/
+void DosICanonicalize(PCHAR Source, PCHAR Dest, USHORT BackupOffset,
+ USHORT DestEnd, USHORT Flags)=
+void _DosICanonicalize(PCHAR Source, PCHAR Dest, ULONG BackupOffset,
+ ULONG DestEnd, ULONG Flags)
+{
+}
+
+USHORT DosDupHandle(HFILE, PUSHORT phfNew)=
+ULONG _Dos16DupHandle(ULONG, PUSHORT phfNew)
+{
+}
+
+
+USHORT DosEditName(USHORT, PSZ, PSZ, PCHAR pszTargetBuf, USHORT cbTargetBuf)=
+ULONG _DosEditName(ULONG, PSZ, PSZ, PCHAR pszTargetBuf, ULONG cbTargetBuf)
+{
+}
+
+
+USHORT DosFileIO(HFILE,PBYTE buf,USHORT cbBuf,PUSHORT usErr) =
+ULONG _DosFileIO(ULONG,PBYTE buf,ULONG cbBuf,PUSHORT usErr)
+{
+}
+
+/* USHORT DosISetFileLocks(HFILE, PFILELOCK, PFILELOCK, ULONG usTimeout, ULONG usFlags)=
+ULONG _DosSetFileLocks(ULONG, PFILELOCK, PFILELOCK, ULONG ulTimeout, ULONG ulFlags)
+{}
+*/
+
+USHORT DosFindClose(HDIR)=
+ULONG _DosFindClose(ULONG)
+{
+}
+
+
+
+USHORT DosFSAttach(PSZ, PSZ, PBYTE pbBuf, USHORT cbBuf, USHORT, ULONG)=
+ULONG _DosFSAttach(PSZ, PSZ, PBYTE pbBuf, ULONG cbBuf, ULONG, ULONG deleted 0)
+{
+}
+
+
+USHORT DosFSCtl(PBYTE pData, USHORT cbData, PUSHORT pcbData, PBYTE pParms, USHORT cbParms, PUSHORT pcbParms, USHORT, PSZ, HFILE hfRoute, USHORT, ULONG)=
+ULONG _Dos16FSCtl(PBYTE pData, ULONG cbData, PUSHORT pcbData, PBYTE pParms, ULONG cbParms, PUSHORT pcbParms, ULONG, PSZ, ULONG, ULONG, ULONG deleted 0)
+{
+}
+
+USHORT DosMove(PSZ, PSZ, ULONG)=
+ULONG _DosMove(PSZ, PSZ, ULONG deleted 0)
+{}
+
+
+USHORT DosNewSize(HFILE, ULONG)=
+ULONG _DosSetFileSize(ULONG, ULONG)
+{}
+
+
+USHORT DosQCurDir(USHORT, PBYTE pszPathBuf, PUSHORT pcbPathBuf)=
+ULONG _Dos16QueryCurrentDir(ULONG, PBYTE pszPathBuf, PUSHORT pcbPathBuf)
+{
+}
+
+USHORT DosQCurDisk(PUSHORT pusDriveNumber, PULONG pulLogicalDrives)=
+ULONG _Dos16QueryCurrentDisk(PUSHORT pusDriveNumber, PULONG pulLogicalDrives)
+{
+}
+
+USHORT DosQFHandState(HFILE, PUSHORT pfsStateFlags)=
+ULONG _Dos16QueryFHState(ULONG, PUSHORT pfsStateFlags)
+{
+}
+
+
+/*
+ PQ
+ USHORT DosQFSAttach(PSZ, USHORT, USHORT, PBYTE pbBuf, PUSHORT cbBuf, ULONG)=
+ ULONG _DosPQueryFSAttach(PSZ, ULONG, ULONG, PBYTE pbBuf, PUSHORT cbBuf, ULONG deleted 0)
+ {
+ pbBuf = output;
+ }
+*/
+
+USHORT DosQFSAttach(PSZ pszDev, USHORT usOrdinal, USHORT usInfoLevel, PBYTE pFSAttBuf, PUSHORT pcbAttBuf, ULONG ulReserved)=
+ULONG _Dos16QFSAttach(PSZ pszDev, ULONG usOrdinal, ULONG usInfoLevel, PBYTE pFSAttBuf, PUSHORT pcbAttBuf, ULONG ulReserved)
+{
+}
+
+USHORT DosQFSInfo(USHORT, USHORT, PBYTE pbInfo, USHORT cbInfo)=
+ULONG _DosQueryFSInfo(ULONG, ULONG, PBYTE pbInfo, ULONG cbInfo)
+{
+}
+
+
+USHORT DosQHandType(HFILE, PUSHORT pusHandType, PUSHORT pusDeviceAttr)=
+ULONG _Dos16QueryHType(ULONG, PUSHORT pusHandType, PUSHORT pusDeviceAttr)
+{
+}
+
+
+USHORT DosQVerify(PUSHORT fVerifyOn)=
+ULONG _Dos16QueryVerify(PUSHORT fVerifyOn)
+{
+}
+
+
+USHORT DosRmDir(PSZ, ULONG)=
+ULONG _DosDeleteDir(PSZ, ULONG deleted)
+{}
+
+USHORT DosSearchPath(USHORT, PSZ, PSZ, PBYTE pbBuf, USHORT cbBuf)=
+ULONG _DosSearchPath(ULONG, PSZ, PSZ, PBYTE pbBuf, ULONG cbBuf)
+{
+}
+
+USHORT DosSelectDisk(USHORT)=
+ULONG _DosSetDefaultDisk(ULONG)
+{}
+
+USHORT DosSetFSInfo(USHORT, USHORT, PBYTE pbBuf, USHORT cbBuf)=
+ULONG _DosSetFSInfo(ULONG, ULONG, PBYTE pbBuf, ULONG cbBuf)
+{
+ cbBuf = sizeof pbBuf;
+}
+
+USHORT DosSetMaxFH(USHORT)=
+ULONG _DosSetMaxFH(ULONG)
+{}
+
+USHORT DosISetRelMaxFH(PLONG ReqCount, PULONG CurMaxFH)=
+ULONG _DosSetRelMaxFH(PLONG ReqCount, PULONG CurMaxFH)
+{
+}
+
+USHORT DosSetVerify(USHORT)=
+ULONG _DosSetVerify(ULONG)
+{
+}
+
+USHORT DosErrClass(USHORT, PUSHORT pusClass, PUSHORT pfsAction, PUSHORT pusLocus)=
+ULONG _Dos16ErrClass(ULONG, PUSHORT pusClass, PUSHORT pfsAction, PUSHORT pusLocus)
+{
+}
+
+USHORT DosError(USHORT)=
+ULONG _DosError(ULONG)
+{
+}
+
+USHORT DosFreeModule(HMODULE)=
+ULONG _DosFreeModuleNE(ULONG)
+{}
+
+USHORT DosGetModHandle(PSZ, PUSHORT phMod)=
+ULONG _DosQueryModuleHandleNE(PSZ, PUSHORT phMod)
+{
+}
+
+USHORT DosGetModName(HMODULE, USHORT cbBuf, PCHAR pchBuf)=
+ULONG _DosQueryModuleNameNE(ULONG, ULONG cbBuf, PCHAR pchBuf)
+{
+}
+
+USHORT DosGetResource(HMODULE, USHORT, USHORT, PSEL psel)=
+ULONG _DosGetResourceNE(ULONG, ULONG, ULONG, PSEL psel)
+{
+}
+
+
+USHORT DosLoadModule(PCHAR pszFailName, USHORT cbFileName, PSZ, PUSHORT phmod)=
+ULONG _DosLoadModuleNE(PCHAR pszFailName, ULONG cbFileName, PSZ, PUSHORT phmod)
+{
+}
+
+
+USHORT DosQAppType(PSZ, PUSHORT pusType)=
+ULONG _DosQueryAppTypeNE(PSZ, PUSHORT pusType)
+{
+}
+
+USHORT DosShutdown(PSDPACKET pSdPacket)=
+ULONG _DosShutdown(PSDPACKET pSdPacket)
+{
+}
+
+USHORT DosScanEnv(PSZ pszValName, PPCHAR ppszResult)=
+ULONG _DosScanEnvNE(PSZ pszValName, PPCHAR ppszResult)
+{
+}
+
+USHORT DosReadAsync(HFILE hf, PULONG hsemRam, PUSHORT pusErrCode,
+ PVOID pvBuf, USHORT cbBuf, PUSHORT pcbBytesRead)=
+ULONG _DosReadAsync(ULONG hf, PULONG hsemRam, PUSHORT pusErrCode,
+ PVOID pvBuf, ULONG cbBuf, PUSHORT pcbBytesRead)
+{
+}
+
+USHORT DosWriteAsync(HFILE hf, PULONG hsemRam, PUSHORT pusErrCode,
+ PVOID pvBuf, USHORT cbBuf, PUSHORT pcbBytesRead)=
+ULONG _DosWriteAsync(ULONG hf, PULONG hsemRam, PUSHORT pusErrCode,
+ PVOID pvBuf, ULONG cbBuf, PUSHORT pcbBytesRead)
+{
+}
+
+USHORT DosFindNotifyClose()=
+ULONG _DosFindNotifyClose()
+{
+}
+
+USHORT DosFindNotifyFirst()=
+ULONG _DosFindNotifyFirst()
+{
+}
+
+USHORT DosFindNotifyNext()=
+ULONG _DosFindNotifyNext()
+{
+}
+
+USHORT DosFileLocks(HFILE hf, PVOID pfUnLock, PVOID pfLock)=
+ULONG _DosFileLocks(ULONG hf, PVOID pfUnLock, PVOID pfLock)
+{
+}
+
+USHORT DosQPathInfo(PSZ pszPath, USHORT usInfoLevel, PBYTE pInfoBuf,
+ USHORT cbInfoBuf, ULONG ulReserved)=
+ULONG _Dos16QPathInfo(PSZ pszPath, ULONG ulInfoLevel, PBYTE pInfoBuf,
+ ULONG cbInfoBuf, ULONG ulReserved)
+{
+}
+
+USHORT DosSetPathInfo(PSZ pszPath, USHORT usInfoLevel, PBYTE pInfoBuf,
+ USHORT cbInfoBuf, USHORT fsOptions, ULONG ulReserved)=
+ULONG _Dos16SetPathInfo(PSZ pszPath, ULONG usInfoLevel, PBYTE pInfoBuf,
+ ULONG cbInfoBuf, ULONG fsOptions, ULONG ulReserved)
+{
+}
+
+#ifndef PMNT
+
+USHORT WinCreateHeap(USHORT selHeapBase, USHORT cbHeap, USHORT cbGrow,
+ USHORT cbMinDed, USHORT cbMaxDeb, USHORT fsOptions)=
+ULONG _WinCreateHeap(ULONG selHeapBase, ULONG cbHeap, ULONG cbGrow,
+ ULONG cbMinDed, ULONG cbMaxDeb, ULONG fsOptions)
+{
+}
+
+USHORT WinDestroyHeap(USHORT hHeap)=
+ULONG _WinDestroyHeap(ULONG hHeap)
+{
+}
+
+USHORT WinAllocMem(USHORT hHeap, USHORT cb)=
+ULONG _WinAllocMem(ULONG hHeap, ULONG cb)
+{
+}
+
+USHORT WinFreeMem(USHORT hHeap, USHORT npMem, USHORT cbMem)=
+ULONG _WinFreeMem(ULONG hHeap, ULONG npMem, ULONG cbMem)
+{
+}
+
+USHORT WinGetLastError(USHORT hab)=
+ULONG _WinGetLastError(ULONG hab)
+{
+}
+
+USHORT WinQueryProfileSize(ULONG hab, PSZ pszAppName, PSZ pszKeyName,
+ PUSHORT pcb)=
+ULONG _WinQueryProfileSize(ULONG hab deleted, PSZ pszAppName, PSZ pszKeyName,
+ PUSHORT pcb)
+{
+}
+
+USHORT WinQueryProfileString(ULONG hab, PSZ pszAppName, PSZ pszKeyName,
+ PSZ pszError, PSZ pszBuf,
+ USHORT cchBuf)=
+ULONG _WinQueryProfileString(ULONG hab deleted, PSZ pszAppName, PSZ pszKeyName,
+ PSZ pszError, PSZ pszBuf,
+ ULONG cchBuf)
+{
+}
+
+USHORT WinQueryProfileData(ULONG hab, PSZ pszAppName, PSZ pszKeyName,
+ PVOID pvBuf, PUSHORT pcbBuf)=
+ULONG _WinQueryProfileData(ULONG hab deleted, PSZ pszAppName, PSZ pszKeyName,
+ PVOID pvBuf, PUSHORT pcbBuf)
+{
+}
+
+SHORT WinQueryProfileInt(ULONG hab, PSZ pszAppName, PSZ pszKeyName,
+ SHORT sError)=
+LONG _WinQueryProfileInt(ULONG hab deleted, PSZ pszAppName, PSZ pszKeyName,
+ LONG sError)
+{
+}
+
+USHORT WinWriteProfileData(ULONG hab, PSZ pszAppName, PSZ pszKeyName,
+ PVOID pcbBinaryData, USHORT cchData)=
+ULONG _WinWriteProfileData(ULONG hab deleted, PSZ pszAppName, PSZ pszKeyName,
+ PVOID pcbBinaryData, ULONG cchData)
+{
+}
+
+USHORT WinWriteProfileString(ULONG hab, PSZ pszAppName, PSZ pszKeyName,
+ PSZ pszString)=
+ULONG _WinWriteProfileString(ULONG hab deleted, PSZ pszAppName, PSZ pszKeyName,
+ PSZ pszString)
+{
+}
+
+#endif
+
+USHORT LDRLibiReturn()=
+ULONG _LDRLibiReturn()
+{
+}
+
+USHORT DosExitStub()=
+ULONG _DosExitStub()
+{
+}
+
+USHORT DosExitProcessStub()=
+ULONG _DosExitProcessStub()
+{
+}
+
+USHORT DosReturn(USHORT param1, USHORT param2)=
+ULONG _DosReturn(ULONG param1, ULONG param2)
+{
+}
+
+USHORT VioWrtTTY(PCH pchString, USHORT cbString, USHORT hVio)=
+ULONG _VioWrtTTY(PCH pchString, ULONG cbString, ULONG hVio)
+{
+}
+
+USHORT VioWrtCellStr( PCH CellStr, USHORT Length, USHORT Row, USHORT Col,
+ USHORT hVio)=
+ULONG _VioWrtCellStr( PCH CellStr, ULONG Length, ULONG Row, ULONG Col,
+ ULONG hVio)
+{
+}
+
+USHORT VioWrtCharStr( PCH CharStr, USHORT Length, USHORT Row, USHORT Col,
+ USHORT hVio)=
+ULONG _VioWrtCharStr( PCH CharStr, ULONG Length, ULONG Row, ULONG Col,
+ ULONG hVio)
+{
+}
+
+USHORT VioWrtCharStrAtt(PCH pchString, USHORT cbString, USHORT usRow,
+ USHORT usColumn, PBYTE pbAttr, USHORT hVio)=
+ULONG _VioWrtCharStrAtt(PCH pchString, ULONG cbString, ULONG usRow,
+ ULONG usColumn, PBYTE pbAttr, ULONG hVio)
+{
+}
+
+USHORT VioWrtNCell( PVOID Cell, USHORT Number, USHORT Row, USHORT Col,
+ USHORT hVio)=
+ULONG _VioWrtNCell( PVOID Cell, ULONG Number, ULONG Row, ULONG Col,
+ ULONG hVio)
+{
+}
+
+USHORT VioWrtNAttr( PBYTE Attr, USHORT Number, USHORT Row, USHORT Col,
+ USHORT hVio)=
+ULONG _VioWrtNAttr( PBYTE Attr, ULONG Number, ULONG Row, ULONG Col,
+ ULONG hVio)
+{
+}
+
+USHORT VioWrtNChar( PBYTE Char, USHORT Number, USHORT Row, USHORT Col,
+ USHORT hVio)=
+ULONG _VioWrtNChar( PBYTE Char, ULONG Number, ULONG Row, ULONG Col,
+ ULONG hVio)
+{
+}
+
+USHORT VioReadCellStr(PCH pchCellString, PUSHORT pcb, USHORT usRow,
+ USHORT usColumn, USHORT hVio)=
+ULONG _VioReadCellStr(PCH pchCellString, PUSHORT pcb, ULONG usRow,
+ ULONG usColumn, ULONG hVio)
+{
+}
+
+USHORT VioReadCharStr(PCH pchCellString, PUSHORT pcb, USHORT usRow,
+ USHORT usColumn, USHORT hVio)=
+ULONG _VioReadCharStr(PCH pchCellString, PUSHORT pcb, ULONG usRow,
+ ULONG usColumn, ULONG hVio)
+{
+}
+
+USHORT VioScrollDn( USHORT ulTopRow, USHORT ulLeftCol, USHORT ulBotRow,
+ USHORT ulRightCol, USHORT cbLines, PBYTE pbCell, USHORT hVio)=
+ULONG _VioScrollDn( ULONG ulTopRow, ULONG ulLeftCol, ULONG ulBotRow,
+ ULONG ulRightCol, ULONG cbLines, PBYTE pbCell, ULONG hVio)
+{
+}
+
+USHORT VioGetAnsi(PUSHORT pfAnsi, USHORT hvio)=
+ULONG _VioGetAnsi(PUSHORT pfAnsi, ULONG hvio)
+{
+}
+
+USHORT VioScrollLf( USHORT ulTopRow, USHORT ulLeftCol, USHORT ulBotRow,
+ USHORT ulRightCol, USHORT cbLines, PBYTE pbCell, USHORT hVio)=
+ULONG _VioScrollLf( ULONG ulTopRow, ULONG ulLeftCol, ULONG ulBotRow,
+ ULONG ulRightCol, ULONG cbLines, PBYTE pbCell, ULONG hVio)
+{
+}
+
+USHORT VioScrollRt( USHORT ulTopRow, USHORT ulLeftCol, USHORT ulBotRow,
+ USHORT ulRightCol, USHORT cbLines, PBYTE pbCell, USHORT hVio)=
+ULONG _VioScrollRt( ULONG ulTopRow, ULONG ulLeftCol, ULONG ulBotRow,
+ ULONG ulRightCol, ULONG cbLines, PBYTE pbCell, ULONG hVio)
+{
+}
+
+USHORT VioScrollUp( USHORT ulTopRow, USHORT ulLeftCol, USHORT ulBotRow,
+ USHORT ulRightCol, USHORT cbLines, PBYTE pbCell, USHORT hVio)=
+ULONG _VioScrollUp( ULONG ulTopRow, ULONG ulLeftCol, ULONG ulBotRow,
+ ULONG ulRightCol, ULONG cbLines, PBYTE pbCell, ULONG hVio)
+{
+}
+
+USHORT VioSetAnsi( USHORT fAnsi, USHORT hVio)=
+ULONG _VioSetAnsi( ULONG fAnsi, ULONG hVio)
+{
+}
+
+USHORT VioGetConfig( USHORT usReserved, PVOID Config, USHORT hVio)=
+ULONG _VioGetConfig( ULONG usReserved, PVOID Config, ULONG hVio)
+{
+}
+
+USHORT VioGetCp( USHORT usReserved, PUSHORT pIdCodePage, USHORT hVio)=
+ULONG _VioGetCp( ULONG usReserved, PUSHORT pIdCodePage, ULONG hVio)
+{
+}
+
+USHORT VioSetCp( USHORT usReserved, USHORT idCodePage, USHORT hVio)=
+ULONG _VioSetCp( ULONG usReserved, ULONG idCodePage, ULONG hVio)
+{
+}
+
+USHORT VioGetCurPos(PUSHORT pusRow, PUSHORT pusColumn, USHORT hVio)=
+ULONG _VioGetCurPos(PUSHORT pusRow, PUSHORT pusColumn, ULONG hVio)
+{
+}
+
+USHORT VioSetCurPos(USHORT usRow, USHORT usColumn, USHORT hVio)=
+ULONG _VioSetCurPos(ULONG usRow, ULONG usColumn, ULONG hVio)
+{
+}
+
+USHORT VioGetCurType( PVOID pCurType, USHORT hVio)=
+ULONG _VioGetCurType( PVOID pCurType, ULONG hVio)
+{
+}
+
+USHORT VioSetCurType( PULONG pCurType, USHORT hVio)=
+ULONG _VioSetCurType( PULONG pCurType, ULONG hVio)
+{
+}
+
+USHORT VioGetMode(PVOID pviomi, USHORT hVio)=
+ULONG _VioGetMode(PVOID pviomi, ULONG hVio)
+{
+}
+
+USHORT VioSetMode( PULONG Mode, USHORT hVio)=
+ULONG _VioSetMode( PULONG Mode, ULONG hVio)
+{
+}
+
+USHORT VioDeRegister()=
+ULONG _VioDeRegister()
+{
+}
+
+USHORT VioRegister( PSZ pszModuleName, PSZ pszEntryName, ULONG flFunction1,
+ ULONG flFunction2)=
+ULONG _VioRegister( PSZ pszModuleName, PSZ pszEntryName, ULONG flFunction1,
+ ULONG flFunction2)
+{
+}
+
+USHORT VioPopUp( PUSHORT pWait, USHORT hVio)=
+ULONG _VioPopUp( PUSHORT pWait, ULONG hVio)
+{
+}
+
+USHORT VioEndPopUp( USHORT hVio)=
+ULONG _VioEndPopUp( ULONG hVio)
+{
+}
+
+USHORT VioGetBuf( PULONG pulLVB, PUSHORT pcbLVB, USHORT hVio)=
+ULONG _VioGetBuf( PULONG pulLVB, PUSHORT pcbLVB, ULONG hVio)
+{
+}
+
+USHORT VioShowBuf( USHORT offLVB, USHORT cbOutput, USHORT hVio)=
+ULONG _VioShowBuf( ULONG offLVB, ULONG cbOutput, ULONG hVio)
+{
+}
+
+USHORT VioGetFont( PVOID Font, USHORT hVio)=
+ULONG _VioGetFont( PVOID Font, ULONG hVio)
+{
+}
+
+USHORT VioSetFont( PVOID Font, USHORT hVio)=
+ULONG _VioSetFont( PVOID Font, ULONG hVio)
+{
+}
+
+USHORT VioGetState( PVOID State, USHORT hVio)=
+ULONG _VioGetState( PVOID State, ULONG hVio)
+{
+}
+
+USHORT VioSetState( PVOID State, USHORT hVio)=
+ULONG _VioSetState( PVOID State, ULONG hVio)
+{
+}
+
+USHORT VioGetPhysBuf( PVOID pviopb, USHORT Resr)=
+ULONG _VioGetPhysBuf( PVOID pviopb, ULONG Resr)
+{
+}
+
+USHORT VioModeUndo( USHORT fRelinqush, USHORT fTerminate, USHORT hVio)=
+ULONG _VioModeUndo( ULONG fRelinqush, ULONG fTerminate, ULONG hVio)
+{
+}
+
+USHORT VioModeWait( USHORT fEvent, PVOID pfNotify, USHORT hVio)=
+ULONG _VioModeWait( ULONG fEvent, PVOID pfNotify, ULONG hVio)
+{
+}
+
+USHORT VioSavRedrawUndo( USHORT fRelinqush, USHORT fTerminate, USHORT hVio)=
+ULONG _VioSavRedrawUndo( ULONG fRelinqush, ULONG fTerminate, ULONG hVio)
+{
+}
+
+USHORT VioSavRedrawWait( USHORT fEvent, PVOID pfNotify, USHORT Resr)=
+ULONG _VioSavRedrawWait( ULONG fEvent, PVOID pfNotify, ULONG Resr)
+{
+}
+
+USHORT VioScrLock(USHORT fWait, PVOID pfNotLocked, USHORT hVio)=
+ULONG _VioScrLock(ULONG fWait, PVOID pfNotLocked, ULONG hVio)
+{
+}
+
+USHORT VioScrUnLock(USHORT hVio)=
+ULONG _VioScrUnLock(ULONG hVio)
+{
+}
+
+USHORT VioPrtSc(USHORT hVio)=
+ULONG _VioPrtSc(ULONG hVio)
+{
+}
+
+USHORT VioPrtScToggle(USHORT hVio)=
+ULONG _VioPrtScToggle(ULONG hVio)
+{
+}
+
+#ifdef DBCS
+/*MSKK Begin KazuM -Jun.23.1992-*/
+USHORT VioCheckCharType(PUSHORT pchType, USHORT usRow, USHORT usColumn,
+ USHORT hVio)=
+ULONG _VioCheckCharType(PUSHORT pchType, ULONG usRow, ULONG usColumn,
+ ULONG hVio)
+{
+}
+/*MSKK End KazuM -Jun.23.1992-*/
+#endif
+
+USHORT KbdCharIn(PVOID pkbci, USHORT fwait, USHORT hKbd)=
+ULONG _KbdCharIn(PVOID pkbci, ULONG fwait, ULONG hKbd)
+{
+}
+
+USHORT KbdPeek(PVOID pkbci, USHORT hKbd)=
+ULONG _KbdPeek(PVOID pkbci, ULONG hKbd)
+{
+}
+
+USHORT KbdStringIn(PVOID pchBuffer, PVOID psibLength, USHORT fwait, USHORT hKbd)=
+ULONG _KbdStringIn(PVOID pchBuffer, PVOID psibLength, ULONG fwait, ULONG hKbd)
+{
+}
+
+USHORT KbdFlushBuffer(USHORT hKbd)=
+ULONG _KbdFlushBuffer(ULONG hKbd)
+{
+}
+
+USHORT KbdGetStatus(PVOID pkbstKbdInfo, USHORT hKbd)=
+ULONG _KbdGetStatus(PVOID pkbstKbdInfo, ULONG hKbd)
+{
+}
+
+USHORT KbdSetStatus(PVOID pkbstKbdInfo, USHORT hKbd)=
+ULONG _KbdSetStatus(PVOID pkbstKbdInfo, ULONG hKbd)
+{
+}
+
+USHORT KbdGetFocus(USHORT Wait, USHORT hKbd)=
+ULONG _KbdGetFocus(ULONG Wait, ULONG hKbd)
+{
+}
+
+USHORT KbdFreeFocus(USHORT hKbd)=
+ULONG _KbdFreeFocus(ULONG hKbd)
+{
+}
+
+USHORT KbdClose(USHORT hKbd)=
+ULONG _KbdClose(ULONG hKbd)
+{
+}
+
+USHORT KbdOpen(PUSHORT hKbd)=
+ULONG _KbdOpen(PUSHORT hKbd)
+{
+}
+
+USHORT KbdDeRegister()=
+ULONG _KbdDeRegister()
+{
+}
+
+USHORT KbdRegister( PSZ pszModuleName, PSZ pszEntryName, ULONG fFunctions)=
+ULONG _KbdRegister( PSZ pszModuleName, PSZ pszEntryName, ULONG fFunctions)
+{
+}
+
+USHORT KbdGetCp( ULONG usReserved, PUSHORT pIdCodePage, USHORT hKbd)=
+ULONG _KbdGetCp( ULONG usReserved, PUSHORT pIdCodePage, ULONG hKbd)
+{
+}
+
+USHORT KbdSetCp( USHORT usReserved, USHORT idCodePage, USHORT hKbd)=
+ULONG _KbdSetCp( ULONG usReserved, ULONG idCodePage, ULONG hKbd)
+{
+}
+
+USHORT KbdSetCustXt( PVOID pusTransTbl, USHORT hKbd)=
+ULONG _KbdSetCustXt( PVOID pusTransTbl, ULONG hKbd)
+{
+}
+
+USHORT KbdXlate( PVOID pkbxlKeyStroke, USHORT hKbd)=
+ULONG _KbdXlate( PVOID pkbxlKeyStroke, ULONG hKbd)
+{
+}
+
+USHORT KbdGetHWID( PVOID pkbdhwid, USHORT hKbd)=
+ULONG _KbdGetHWID( PVOID pkbdhwid, ULONG hKbd)
+{
+}
+
+USHORT KbdSetFgnd(USHORT hKbd)=
+ULONG _KbdSetFgnd(ULONG hKbd)
+{
+}
+
+USHORT KbdSynch(USHORT fWait)=
+ULONG _KbdSynch(ULONG fWait)
+{
+}
+
+USHORT KbdShellInit()=
+ULONG _KbdShellInit()
+{
+}
+
+USHORT MouClose(USHORT hMou)=
+ULONG _MouClose(ULONG hMou)
+{
+}
+
+USHORT MouDeRegister()=
+ULONG _MouDeRegister()
+{
+}
+
+USHORT MouDrawPtr(USHORT hMou)=
+ULONG _MouDrawPtr(ULONG hMou)
+{
+}
+
+USHORT MouFlushQue(USHORT hMou)=
+ULONG _MouFlushQue(ULONG hMou)
+{
+}
+
+USHORT MouGetDevStatus(PUSHORT DevStatus, USHORT hMou)=
+ULONG _MouGetDevStatus(PUSHORT DevStatus, ULONG hMou)
+{
+}
+
+USHORT MouGetEventMask(PUSHORT EventMask, USHORT hMou)=
+ULONG _MouGetEventMask(PUSHORT EventMask, ULONG hMou)
+{
+}
+
+USHORT MouGetNumButtons(PUSHORT NumButtons, USHORT hMou)=
+ULONG _MouGetNumButtons(PUSHORT NumButtons, ULONG hMou)
+{
+}
+
+USHORT MouGetNumMickeys(PUSHORT NumMickeys, USHORT hMou)=
+ULONG _MouGetNumMickeys(PUSHORT NumMickeys, ULONG hMou)
+{
+}
+
+USHORT MouGetNumQueEl(PVOID NumQueEl, USHORT hMou)=
+ULONG _MouGetNumQueEl(PVOID NumQueEl, ULONG hMou)
+{
+}
+
+USHORT MouGetPtrPos(PVOID PtrPos, USHORT hMou)=
+ULONG _MouGetPtrPos(PVOID PtrPos, ULONG hMou)
+{
+}
+
+USHORT MouGetPtrShape(PBYTE PtrMask, PVOID PtrShape, USHORT hMou)=
+ULONG _MouGetPtrShape(PBYTE PtrMask, PVOID PtrShape, ULONG hMou)
+{
+}
+
+USHORT MouGetScaleFact(PVOID ScaleFact, USHORT hMou)=
+ULONG _MouGetScaleFact(PVOID ScaleFact, ULONG hMou)
+{
+}
+
+USHORT MouOpen(PSZ DriveName, PUSHORT hMou)=
+ULONG _MouOpen(PSZ DriveName, PUSHORT hMou)
+{
+}
+
+USHORT MouReadEventQue(PVOID MouEvent, PUSHORT Wait, USHORT hMou)=
+ULONG _MouReadEventQue(PVOID MouEvent, PUSHORT Wait, ULONG hMou)
+{
+}
+
+USHORT MouRegister( PSZ pszModuleName, PSZ pszEntryName, ULONG fFunctions)=
+ULONG _MouRegister( PSZ pszModuleName, PSZ pszEntryName, ULONG fFunctions)
+{
+}
+
+USHORT MouRemovePtr(PVOID Rect, USHORT hMou)=
+ULONG _MouRemovePtr(PVOID Rect, ULONG hMou)
+{
+}
+
+USHORT MouSetDevStatus(PUSHORT DevStatus, USHORT hMou)=
+ULONG _MouSetDevStatus(PUSHORT DevStatus, ULONG hMou)
+{
+}
+
+USHORT MouSetEventMask(PUSHORT EventMask, USHORT hMou)=
+ULONG _MouSetEventMask(PUSHORT EventMask, ULONG hMou)
+{
+}
+
+USHORT MouSetPtrPos(PVOID PtrPos, USHORT hMou)=
+ULONG _MouSetPtrPos(PVOID PtrPos, ULONG hMou)
+{
+}
+
+USHORT MouSetPtrShape(PBYTE PtrMask, PVOID PtrShape, USHORT hMou)=
+ULONG _MouSetPtrShape(PBYTE PtrMask, PVOID PtrShape, ULONG hMou)
+{
+}
+
+USHORT MouSetScaleFact(PVOID ScaleFact, USHORT hMou)=
+ULONG _MouSetScaleFact(PVOID ScaleFact, ULONG hMou)
+{
+}
+
+USHORT MouSynch(USHORT fWait)=
+ULONG _MouSynch(ULONG fWait)
+{
+}
+
+USHORT DosMonOpen(PSZ pDevName, PUSHORT phMon)=
+ULONG _DosMonOpen(PSZ pDevName, PUSHORT phMon)
+{
+}
+
+USHORT DosMonClose(USHORT hMon)=
+ULONG _DosMonClose(ULONG hMon)
+{
+}
+
+USHORT DosMonRead(PBYTE pInBuffer, USHORT fWait, PBYTE pDataBuf, PUSHORT pcbDataSize)=
+ULONG _DosMonRead(PBYTE pInBuffer, ULONG fWait, PBYTE pDataBuf, PUSHORT pcbDataSize)
+{
+}
+
+USHORT DosMonReg( USHORT hMon, PBYTE pInBuffer, PBYTE pOutBuffer, USHORT fPosition, USHORT usIndex)=
+ULONG _DosMonReg( ULONG hMon, PBYTE pInBuffer, PBYTE pOutBuffer, ULONG fPosition, ULONG usIndex)
+{
+}
+
+USHORT DosMonWrite(PBYTE pOutBuffer, PBYTE pDataBuf, USHORT cbDataSize)=
+ULONG _DosMonWrite(PBYTE pOutBuffer, PBYTE pDataBuf, ULONG cbDataSize)
+{
+}
+
+USHORT NetGetDCName(PCHAR pszServer, PCHAR pszDomain, PCHAR pbBuffer,
+ USHORT cbBuffer)=
+ULONG _Net16GetDCName(PCHAR pszServer, PCHAR pszDomain, PCHAR pbBuffer,
+ ULONG cbBuffer)
+{
+}
+
+USHORT NetHandleGetInfo(USHORT hHandle, SHORT sLevel,
+ PCHAR pbBuffer, USHORT cbBuffer, PUSHORT pcbTotalAvail)=
+ULONG _Net16HandleGetInfo(ULONG hHandle, LONG sLevel,
+ PCHAR pbBuffer, ULONG cbBuffer, PUSHORT pcbTotalAvail)
+{
+}
+
+USHORT NetServerDiskEnum(PCHAR pszServer, SHORT sLevel, PCHAR pbBuffer,
+ USHORT cbBuffer, PUSHORT pcEntriesRead, PUSHORT pcTotalAvail)=
+ULONG _Net16ServerDiskEnum(PCHAR pszServer, LONG sLevel, PCHAR pbBuffer,
+ ULONG cbBuffer, PUSHORT pcEntriesRead, PUSHORT pcTotalAvail)
+{
+}
+
+USHORT NetServerEnum2(PCHAR pszServer, SHORT sLevel, PCHAR pbBuffer,
+ USHORT cbBuffer, PUSHORT pcEntriesRead, PUSHORT pcTotalAvail,
+ ULONG flServerType, PCHAR pszDomain)=
+ULONG _Net16ServerEnum2(PCHAR pszServer, LONG sLevel, PCHAR pbBuffer,
+ ULONG cbBuffer, PUSHORT pcEntriesRead, PUSHORT pcTotalAvail,
+ ULONG flServerType, PCHAR pszDomain)
+{
+}
+
+USHORT NetServerGetInfo(PCHAR pszServer, SHORT sLevel, PCHAR pbBuffer,
+ USHORT cbBuffer, PUSHORT pcbTotalAvail)=
+ULONG _Net16ServerGetInfo(PCHAR pszServer, LONG sLevel, PCHAR pbBuffer,
+ ULONG cbBuffer, PUSHORT pcbTotalAvail)
+{
+}
+
+USHORT NetServiceControl(PCHAR pszServer, PCHAR pszService, UCHAR fbOpCode,
+ UCHAR fbArg, PCHAR pbBuffer, USHORT cbBuffer)=
+ULONG _Net16ServiceControl(PCHAR pszServer, PCHAR pszService, ULONG fbOpCode,
+ ULONG fbArg, PCHAR pbBuffer, ULONG cbBuffer)
+{
+}
+
+USHORT NetServiceEnum(PCHAR pszServer, SHORT sLevel, PCHAR pbBuffer,
+ USHORT cbBuffer, PUSHORT pcEntriesRead, PUSHORT pcTotalAvail)=
+ULONG _Net16ServiceEnum(PCHAR pszServer, LONG sLevel, PCHAR pbBuffer,
+ ULONG cbBuffer, PUSHORT pcEntriesRead, PUSHORT pcTotalAvail)
+{
+}
+
+USHORT NetServiceGetInfo(PCHAR pszServer, PCHAR pszService, SHORT sLevel,
+ PCHAR pbBuffer, USHORT cbBuffer, PUSHORT pcbTotalAvail)=
+ULONG _Net16ServiceGetInfo(PCHAR pszServer, PCHAR pszService, LONG sLevel,
+ PCHAR pbBuffer, ULONG cbBuffer, PUSHORT pcbTotalAvail)
+{
+}
+
+USHORT NetServiceInstall(PCHAR pszServer, PCHAR pszService, PCHAR pszCmdArgs,
+ PCHAR pbBuffer, USHORT cbBuffer)=
+ULONG _Net16ServiceInstall(PCHAR pszServer, PCHAR pszService, PCHAR pszCmdArgs,
+ PCHAR pbBuffer, ULONG cbBuffer)
+{
+}
+
+USHORT NetShareEnum(PCHAR pszServer, SHORT sLevel, PCHAR pbBuffer,
+ USHORT cbBuffer, PUSHORT pcEntriesRead, PUSHORT pcTotalAvail)=
+ULONG _Net16ShareEnum(PCHAR pszServer, LONG sLevel, PCHAR pbBuffer,
+ ULONG cbBuffer, PUSHORT pcEntriesRead, PUSHORT pcTotalAvail)
+{
+}
+
+USHORT NetShareGetInfo(PCHAR pszServer, PCHAR pszNetName, SHORT sLevel,
+ PCHAR pbBuffer, USHORT cbBuffer, PUSHORT pcbTotalAvail)=
+ULONG _Net16ShareGetInfo(PCHAR pszServer, PCHAR pszNetName, LONG sLevel,
+ PCHAR pbBuffer, ULONG cbBuffer, PUSHORT pcbTotalAvail)
+{
+}
+
+USHORT NetUseAdd(PCHAR pszServer, SHORT sLevel, PCHAR pbBuffer, USHORT cbBuffer)=
+ULONG _Net16UseAdd(PCHAR pszServer, LONG sLevel, PCHAR pbBuffer, ULONG cbBuffer)
+{
+}
+
+USHORT NetUseDel(PCHAR pszServer, PCHAR pszUseName, USHORT usForce)=
+ULONG _Net16UseDel(PCHAR pszServer, PCHAR pszUseName, ULONG usForce)
+{
+}
+
+USHORT NetUseEnum(PCHAR pszServer, SHORT sLevel, PCHAR pbBuffer,
+ USHORT cbBuffer, PUSHORT pcEntriesRead, PUSHORT pcTotalAvail)=
+ULONG _Net16UseEnum(PCHAR pszServer, LONG sLevel, PCHAR pbBuffer,
+ ULONG cbBuffer, PUSHORT pcEntriesRead, PUSHORT pcTotalAvail)
+{
+}
+
+USHORT NetUseGetInfo(PCHAR pszServer, PCHAR pszUseName, SHORT sLevel,
+ PCHAR pbBuffer, USHORT cbBuffer, PUSHORT pcbTotalAvail)=
+ULONG _Net16UseGetInfo(PCHAR pszServer, PCHAR pszUseName, LONG sLevel,
+ PCHAR pbBuffer, ULONG cbBuffer, PUSHORT pcbTotalAvail)
+{
+}
+
+USHORT NetUserEnum(PCHAR pszServer, SHORT sLevel, PCHAR pbBuffer,
+ USHORT cbBuffer, PUSHORT pcEntriesRead, PUSHORT pcTotalAvail)=
+ULONG _Net16UserEnum(PCHAR pszServer, LONG sLevel, PCHAR pbBuffer,
+ ULONG cbBuffer, PUSHORT pcEntriesRead, PUSHORT pcTotalAvail)
+{
+}
+
+USHORT NetWkstaGetInfo(PCHAR pszServer, SHORT sLevel, PCHAR pbBuffer,
+ USHORT cbBuffer, PUSHORT pcbTotalAvail)=
+ULONG _Net16WkstaGetInfo(PCHAR pszServer, LONG sLevel, PCHAR pbBuffer,
+ ULONG cbBuffer, PUSHORT pcbTotalAvail)
+{
+}
+
+USHORT NetAccessAdd(PCHAR pszServer, SHORT sLevel, PCHAR pbBuffer,
+ USHORT cbBUffer)=
+ULONG _Net16AccessAdd(PCHAR pszServer, LONG sLevel, PCHAR pbBuffer,
+ ULONG cbBUffer)
+{
+}
+
+USHORT NetAccessSetInfo(PCHAR pszServer, PCHAR pszResource, SHORT sLevel,
+ PCHAR pbBuffer, USHORT cbBuffer, SHORT sParmNum)=
+ULONG _Net16AccessSetInfo(PCHAR pszServer, PCHAR pszResource, LONG sLevel,
+ PCHAR pbBuffer, ULONG cbBuffer, LONG sParmNum)
+{
+}
+
+USHORT NetAccessGetInfo(PCHAR pszServer, PCHAR pszResource, SHORT sLevel,
+ PCHAR pbBuffer, USHORT cbBuffer, PUSHORT pcbTotalAvail)=
+ULONG _Net16AccessGetInfo(PCHAR pszServer, PCHAR pszResource, LONG sLevel,
+ PCHAR pbBuffer, ULONG cbBuffer, PUSHORT pcbTotalAvail)
+{
+}
+
+USHORT NetAccessDel(PCHAR pszServer, PCHAR pszResource)=
+ULONG _Net16AccessDel(PCHAR pszServer, PCHAR pszResource)
+{
+}
+
+USHORT NetShareAdd(PCHAR pszServer, SHORT sLevel, PCHAR pbBuffer,
+ USHORT cbBUffer)=
+ULONG _Net16ShareAdd(PCHAR pszServer, LONG sLevel, PCHAR pbBuffer,
+ ULONG cbBUffer)
+{
+}
+
+USHORT NetShareDel(PCHAR pszServer, PCHAR pszNetName, USHORT usReserved)=
+ULONG _Net16ShareDel(PCHAR pszServer, PCHAR pszNetName, ULONG usReserved)
+{
+}
+
+USHORT NetUserGetInfo(PCHAR pszServer, PCHAR pszUserName, SHORT sLevel,
+ PCHAR pbBuffer, USHORT cbBUffer, PUSHORT pcbTotalAvail)=
+ULONG _Net16UserGetInfo(PCHAR pszServer, PCHAR pszUserName, LONG sLevel,
+ PCHAR pbBuffer, ULONG cbBUffer, PUSHORT pcbTotalAvail)
+{
+}
+
+USHORT NetMessageBufferSend(PSZ pszServer, PSZ pszRecipient, PBYTE pbBuffer, USHORT cbBuffer)=
+ULONG _Net16MessageBufferSend(PSZ pszServer, PSZ pszRecipient, PBYTE pbBuffer, ULONG cbBuffer)
+{
+}
+
+USHORT Netbios(PVOID pNCB)=
+ULONG _Net16bios(PVOID pNCB)
+{
+}
+
+USHORT NetBiosClose(USHORT hDevName, USHORT usReserved)=
+ULONG _Net16BiosClose(ULONG hDevName, USHORT reserved deleted 0)
+{
+}
+
+USHORT NetBiosEnum(PCHAR pszServer, SHORT sLevel,
+ PCHAR pbBuffer, USHORT cbBuffer,
+ PUSHORT pcEntriesRead, PUSHORT pcTotalAvail)=
+ULONG _Net16BiosEnum(PCHAR pszServer, LONG sLevel,
+ PCHAR pbBuffer, ULONG cbBuffer,
+ PUSHORT pcEntriesRead, PUSHORT pcTotalAvail)
+{
+}
+
+USHORT NetBiosGetInfo(PCHAR pszServer, PCHAR pszNetBiosName, SHORT sLevel,
+ PCHAR pbBuffer, USHORT cbBuffer,
+ PUSHORT pcbTotalAvail)=
+ULONG _Net16BiosGetInfo(PCHAR pszServer, PCHAR pszNetBiosName, LONG sLevel,
+ PCHAR pbBuffer, ULONG cbBuffer,
+ PUSHORT pcbTotalAvail)
+{
+}
+
+USHORT NetBiosOpen(PCHAR pszServer, PCHAR pszReserved,
+ USHORT usOpenOpt, PUSHORT phDevName)=
+ULONG _Net16BiosOpen(PCHAR pszServer, PCHAR pszReserved,
+ ULONG usOpenOpt, PUSHORT phDevName)
+{
+}
+
+USHORT NetBiosSubmit(USHORT hDevName, USHORT usNcbOpt, PVOID pNCB)=
+ULONG _Net16BiosSubmit(ULONG hDevName, ULONG usNcbOpt, PVOID pNCB)
+{
+}
+
+USHORT DosMakeMailslot(PSZ pszName, USHORT cbMessageSize,
+ USHORT cbMailslotSize, PUSHORT phMailslot)=
+ULONG _Dos16MakeMailslot(PSZ pszName, ULONG cbMessageSize,
+ ULONG cbMailslotSize, PUSHORT phMailslot)
+{
+}
+
+USHORT DosDeleteMailslot(USHORT hMailslot)=
+ULONG _Dos16DeleteMailslot(ULONG hMailslot)
+{
+}
+
+USHORT DosMailslotInfo(USHORT hMailslot, PUSHORT pcbMessageSize,
+ PUSHORT pcbMailslotSize, PUSHORT pcbNextSize,
+ PUSHORT pusNextPriority, PUSHORT pcMessages)=
+ULONG _Dos16MailslotInfo(ULONG hMailslot, PUSHORT pcbMessageSize,
+ PUSHORT pcbMailslotSize, PUSHORT pcbNextSize,
+ PUSHORT pusNextPriority, PUSHORT pcMessages)
+{
+}
+
+USHORT DosPeekMailslot(USHORT hMailslot, PCHAR pbBuffer, PUSHORT pcbReturned,
+ PUSHORT pcbNextSize, PUSHORT pusNextPriority)=
+ULONG _Dos16PeekMailslot(ULONG hMailslot, PCHAR pbBuffer, PUSHORT pcbReturned,
+ PUSHORT pcbNextSize, PUSHORT pusNextPriority)
+{
+}
+
+USHORT DosReadMailslot(USHORT hMailslot, PCHAR pbBuffer, PUSHORT pcbReturned,
+ PUSHORT pcbNextSize, PUSHORT pusNextPriority,
+ LONG cTimeout)=
+ULONG _Dos16ReadMailslot(ULONG hMailslot, PCHAR pbBuffer, PUSHORT pcbReturned,
+ PUSHORT pcbNextSize, PUSHORT pusNextPriority,
+ LONG cTimeout)
+{
+}
+
+USHORT DosWriteMailslot(PSZ pszName, PCHAR pbBuffer, USHORT cbBuffer,
+ USHORT usPriority, USHORT usClass, LONG cTimeout)=
+ULONG _Dos16WriteMailslot(PSZ pszName, PCHAR pbBuffer, ULONG cbBuffer,
+ ULONG usPriority, ULONG usClass, LONG cTimeout)
+{
+}
+
+
+
+#ifdef PMNT
+
+/* Unpublished API (DOSCALLS.101) */
+void DosSetFgnd(USHORT usLevel, USHORT usTid)=
+void _DosSetFgnd(ULONG ulLevel, ULONG ulTid)
+{
+}
+
+/* DOSCALLS.160 */
+USHORT DosR2StackRealloc(USHORT NewSizeU)=
+ULONG _DosR2StackRealloc(ULONG NewSize)
+{
+}
+
+/* Unpublished API (DOSCALLS.88). Incorrect prototype - just to resolve entry */
+void DosSystemService()=
+void _DosSystemService()
+{
+}
+
+/* VIOCALLS.69 */
+/* BUGBUG - Required by VioSavRedrawWait, ie may no longer be needed later on */
+USHORT VioRedrawSize(PULONG RedrawSize)=
+ULONG _VioRedrawSize(PULONG RedrawSize)
+{
+}
+
+/* Just to resolve entry. This call is used by DISPLAY.DLL:
+ - called by pmdisp\egafam\egavga\egainit.asm, ring3_VioGetPSAddress()
+ - ring3_VioGetPSAddress() is called (indirectly, via a ring3_GetPSAddress()
+ ULONG variable) by pmdisp\egafam\cellblt.asm, DeviceSetAVIOFont2() routine
+*/
+ULONG VioGetPSAddress()=
+ULONG _VioGetPSAddress()
+{
+}
+
+/* PMNT calls */
+
+USHORT PMNTCreateHiddenThread(PVOID pfnFun, PUSHORT pTid, PBYTE pbStack)=
+ULONG _PMNT16CreateThread(PVOID pfnFun, PUSHORT pTid, PBYTE pbStack)
+{
+ pbStack = input;
+}
+
+USHORT PMNTIoctl(USHORT request, PVOID in_ptr, PVOID out_ptr)=
+ULONG _PMNTIoctl(ULONG request, PVOID in_ptr, PVOID out_ptr)
+{
+}
+
+void PMNTDbgPrint(PSZ str, ULONG l1, ULONG l2, ULONG l3, ULONG l4)=
+void _PMNTDbgPrint(PSZ str, ULONG l1, ULONG l2, ULONG l3, ULONG l4)
+{
+}
+
+void PMNTGetNextEvent(PVOID pPMNTInputRec)=
+void _PMNTGetNextEvent(PVOID pPMNTInputRec)
+{
+}
+
+USHORT PMNTMemMap(PUSHORT pSel)=
+ULONG _PMNTMemMap(PUSHORT pSel)
+{
+}
+
+USHORT PMNTGetPgmName(PSZ Buffer, USHORT BufferLength)=
+ULONG _PMNTGetPgmName(PSZ Buffer, ULONG BufferLength)
+{
+}
+
+USHORT PMNTSetConsoleTitle(PSZ Buffer)=
+ULONG _PMNTSetConsoleTitle(PSZ Buffer)
+{
+}
+
+USHORT PMNTCreateGroup(PSZ Buffer, PULONG hGroup)=
+ULONG _PMNTCreateGroup(PSZ Buffer, PULONG hGroup)
+{
+}
+
+USHORT PMNTAddProgram(LONG hGroupHandle, PCHAR szTitle,PCHAR szExecutable,PCHAR szStartupDir,
+ PCHAR pchProgramParameter, PULONG hProg)=
+ULONG _PMNTAddProgram(LONG hGroupHandle, PCHAR szTitle,PCHAR szExecutable,PCHAR szStartupDir,
+ PCHAR szProgramParameter, PULONG hProg)
+{
+}
+
+USHORT PMNTChangeProgram(LONG hGroupHandle, PCHAR szTitle,PCHAR szExecutable,PCHAR szStartupDir,
+ PCHAR pchProgramParameter)=
+ULONG _PMNTChangeProgram(LONG hGroupHandle, PCHAR szTitle,PCHAR szExecutable,PCHAR szStartupDir,
+ PCHAR szProgramParameter)
+{
+}
+
+USHORT PMNTQueryProgramTitles(ULONG win_prf, LONG hGroup, PVOID paproge, ULONG cbBuf, PULONG pcTitles)=
+ULONG _PMNTQueryProgramTitles(ULONG win_prf, LONG hGroup, PVOID paproge, ULONG cbBuf, PULONG pcTitles)
+{
+}
+
+USHORT PMNTQueryDefinition(ULONG win_prf, LONG hGroup, PVOID paproge, ULONG cbBuf)=
+ULONG _PMNTQueryDefinition(ULONG win_prf, LONG hGroup, PVOID paproge, ULONG cbBuf)
+{
+}
+
+USHORT PMNTQueryProgramHandle(PCHAR PathNameOs2, PVOID phpga, ULONG cb, PULONG pcHandles)=
+ULONG _PMNTQueryProgramHandle(PCHAR PathNameOs2, PVOID phpga, ULONG cb, PULONG pcHandles)
+{
+}
+
+USHORT PMNTDestroyGroup(LONG hGroup)=
+ULONG _PMNTDestroyGroup(LONG hGroup)
+{
+}
+
+USHORT PMNTRemoveProgram(LONG hGroup)=
+ULONG _PMNTRemoveProgram(LONG hGroup)
+{
+}
+
+void PMNTSetFullScreen(USHORT Register)=
+void _PMNTSetFullScreen(ULONG Register)
+{
+}
+
+USHORT PMNTGetWin32Hwnd(PULONG pHwnd)=
+ULONG _PMNTGetWin32Hwnd(PULONG pHwnd)
+{
+}
+
+USHORT PMNTSetFocus(ULONG Hwnd)=
+ULONG _PMNTSetFocus(ULONG Hwnd)
+{
+}
+
+USHORT PMNTCloseWindow()=
+ULONG _PMNTCloseWindow()
+{
+}
+
+USHORT PMNTGetFullScreen(ULONG Operation)=
+ULONG _PMNTGetFullScreen(ULONG Operation)
+{
+}
+
+USHORT PMNTSetPMShellFlag()=
+ULONG _PMNTSetPMShellFlag()
+{
+}
+
+USHORT PMNTRegisterDisplayAdapter(PVOID pMemory, PVOID pPorts, USHORT col, USHORT row) =
+ULONG _PMNTRegisterDisplayAdapter(PVOID pMemory, PVOID pPorts, ULONG col, ULONG row)
+{
+}
+
+USHORT PMNTIOMap() =
+ULONG _PMNTIOMap()
+{
+}
+
+void PMNTGetSystemTime(PULONG pTime)=
+void _PMNTGetSystemTime(PULONG pTime)
+{
+}
+
+USHORT PMNTIsSessionRoot() =
+ULONG _PMNTIsSessionRoot()
+{
+}
+
+/* DOSCALLS.90. Incorrect prototype - just to resolve entry */
+void DosSysTrace()=
+void _DosSysTrace()
+{
+}
+
+/* SESMGR.26. Incorrect prototype - just to resolve entry */
+USHORT DosSMPause()=
+ULONG _DosSMPause()
+{
+}
+
+#ifdef DBCS
+/* MSKK [ShigeO] Aug 26, 1993 */
+USHORT PMNTCreateFontIndirect(PVOID lplf) =
+ULONG _PMNTCreateFontIndirect(PVOID lplf)
+{
+}
+
+USHORT PMNTGetTextMetrics(ULONG ulFont, PVOID lptm) =
+ULONG _PMNTGetTextMetrics(ULONG ulFont, PVOID lptm)
+{
+}
+
+USHORT PMNTGetStringBitmap(ULONG ulFont, PSZ lpszStr, ULONG cbStr, ULONG cbData, PVOID lpSB) =
+ULONG _PMNTGetStringBitmap(ULONG ulFont, PSZ lpszStr, ULONG cbStr, ULONG cbData, PVOID lpSB)
+{
+}
+#endif // DBCS
+
+USHORT PMNTDbgPrompt(PVOID MessageStr, PVOID ResultStr, USHORT Len) =
+ULONG _PMNTDbgPrompt(PVOID MessageStr, PVOID ResultStr, ULONG Len)
+{
+}
+
+USHORT PMNTOpenClipbrd(ULONG hwnd) =
+ULONG _PMNTOpenClipbrd(ULONG hwnd)
+{
+}
+
+USHORT PMNTCloseClipbrd() =
+ULONG _PMNTCloseClipbrd()
+{
+}
+
+USHORT PMNTEmptyClipbrd() =
+ULONG _PMNTEmptyClipbrd()
+{
+}
+
+USHORT PMNTSetClipbrdText(ULONG ulData) =
+ULONG _PMNTSetClipbrdText(ULONG ulData)
+{
+}
+
+USHORT PMNTSetClipbrdBitmap(PVOID pbmi, PVOID pbBuffer) =
+ULONG _PMNTSetClipbrdBitmap(PVOID pbmi, PVOID pbBuffer)
+{
+}
+
+USHORT PMNTQueryClipbrdText(PULONG phandle) =
+ULONG _PMNTQueryClipbrdText(PULONG phandle)
+{
+}
+
+USHORT PMNTQueryClipbrdBitmap(PVOID ppbmi, PVOID ppbBuffer) =
+ULONG _PMNTQueryClipbrdBitmap(PVOID ppbmi, PVOID ppbBuffer)
+{
+}
+
+USHORT PMNTQueryClipbrdFmtInfo(USHORT fmt, PUSHORT pfsFmtInfo) =
+ULONG _PMNTQueryClipbrdFmtInfo(ULONG fmt, PUSHORT pfsFmtInfo)
+{
+}
+
+USHORT PMNTWin32Clipbrd(PVOID pSem) =
+ULONG _PMNTWin32Clipbrd(PVOID pSem)
+{
+}
+
+USHORT PMNTIdentifyCodeSelector(USHORT Sel, PVOID pWhoisInfo) =
+ULONG _PMNTIdentifyCodeSelector(ULONG Sel, PVOID pWhoisInfo)
+{
+}
+
+USHORT PMNTVioGetConfig( USHORT usReserved, PVOID Config, USHORT hVio)=
+ULONG _PMNTVioGetConfig( ULONG usReserved, PVOID Config, ULONG hVio)
+{
+}
+
+USHORT PMNTVioGetCp( USHORT usReserved, PUSHORT pIdCodePage, USHORT hVio)=
+ULONG _PMNTVioGetCp( ULONG usReserved, PUSHORT pIdCodePage, ULONG hVio)
+{
+}
+
+USHORT PMNTProcessIsPMShell()=
+ULONG _PMNTProcessIsPMShell()
+{
+}
+
+USHORT PMNTQueryScreenSize(PUSHORT xRight, PUSHORT yTop)=
+ULONG _PMNTQueryScreenSize(PUSHORT xRight, PUSHORT yTop)
+{
+}
+
+USHORT MouInitReal( PSZ pszDriveName)=
+ULONG _MouInitReal( PSZ pszDriveName)
+{
+}
+
+USHORT PMNTSetShutdownPriority(ULONG NewPriority, USHORT Disable)=
+ULONG _PMNTSetShutdownPriority(ULONG NewPriority, ULONG Disable)
+{
+}
+
+USHORT PMNTSetSubprocSem(HSEM hsem)=
+ULONG _PMNTSetSubprocSem(HSEM hsem)
+{
+}
+
+#if 0
+/* Spring cleaning - APIs no longer needed */
+/* SESMGR.34. Incorrect prototype - just to resolve entry */
+void QHKeybdHandle()=
+void _QHKeybdHandle()
+{
+}
+
+/* SESMGR.35. Incorrect prototype - just to resolve entry */
+void QHMouseHandle()=
+void _QHMouseHandle()
+{
+}
+
+/* Unpublished API (DOSCALLS.125). Incorrect prototype */
+void DosIRamSemWake()=
+void _DosIRamSemWake()
+{
+}
+
+/* Unpublished API (DOSCALLS.18) */
+USHORT DosISemRequest(HSEM hsem, LONG lTimeOut)=
+ULONG _DosISemRequest(HSEM hsem, LONG lTimeOut)
+{
+}
+
+/* DOSCALLS.54 - unknown at this point. Incorrect prototype */
+void DosUnknownApi54()=
+void _DosUnknownApi54()
+{
+}
+
+/* DOSCALLS.105 - unknown at this point. Incorrect prototype */
+void DosUnknownApi105()=
+void _DosUnknownApi105()
+{
+}
+
+/* DOSCALLS.209. Incorrect prototype */
+void DosGiveSegList()=
+void _DosGiveSegList()
+{
+}
+
+/* VIOCALLS.36. Incorrect prototype */
+void VioSSWSwitch()=
+void _VioSSWSwitch()
+{
+}
+
+/* MOUCALLS.10 */
+USHORT MouSetHotKey(USHORT p1, USHORT p2, USHORT hMou)=
+ULONG _MouSetHotKey(ULONG p1, ULONG p2, ULONG hMou)
+{
+}
+
+/* Possibly incorrect prototype */
+USHORT KbdFree(USHORT hKbd)=
+ULONG _KbdFree(ULONG hKbd)
+{
+}
+
+/* Possibly incorrect prototype */
+USHORT MouFree(USHORT hMou)=
+ULONG _MouFree(ULONG hMou)
+{
+}
+
+/* Possibly incorrect prototype */
+USHORT VioFree(USHORT hVio)=
+ULONG _VioFree(ULONG hVio)
+{
+}
+
+/* DOSCALLS.55 */
+void DosSGSwitchMe(USHORT p1, USHORT p2)=
+void _DosSGSwitchMe(ULONG p1l, ULONG p2l)
+{
+}
+
+/* KBDCALLS.19. Incorrect prototype */
+void KbdSwitchFgnd()=
+void _KbdSwitchFgnd()
+{
+}
+
+/* MOUCALLS.5. */
+USHORT MouShellInit()=
+ULONG _MouShellInit()
+{
+}
+
+/* Incorrect prototype - just to resolve entry */
+void VioRestore()=
+void _VioRestore()
+{
+}
+
+/* VIOCALLS.20. Incorrect prototype */
+void VioSave()=
+void _VioSave()
+{
+}
+
+/* Incorrect prototype - just to resolve entry */
+void VioSRFunBlock()=
+void _VioSRFunBlock()
+{
+}
+
+/* Incorrect prototype - just to resolve entry */
+void VioSRFBlock()=
+void _VioSRFBlock()
+{
+}
+
+#endif // 0
+
+#endif // PMNT
+
+#ifdef DBCS
+/* MSKK Jan.13.1993 V-AkihiS */
+/* IMMON API Support */
+USHORT IMMonInstall(PVOID pMonInsBlk)=
+ULONG _IMMonInstall(PVOID pMonInsBlk)
+{
+}
+
+USHORT IMMonDeinstall(ULONG ulReserved)=
+ULONG _IMMonDeinstall(ULONG ulReserved)
+{
+}
+
+USHORT IMMonStatus(PVOID pStatBlk)=
+ULONG _IMMonStatus(PVOID pStatBlk)
+{
+}
+
+USHORT IMMonActive(ULONG ulReserved)=
+ULONG _IMMonActive(ULONG ulReserved)
+{
+}
+
+USHORT IMMonInactive(ULONG ulReserved)=
+ULONG _IMMonInactive(ULONG ulReserved)
+{
+}
+#endif
+
+/* Internal API to enable tranasact SMB from 16 bit OS2 NETAPI.DLL to
+ NT Transact server XACTSRV */
+USHORT DosIRemoteApi(USHORT ApiNumber, PCHAR ServerNamePointer, PCHAR ParameterDescriptor,
+ PCHAR DataDescriptor, PCHAR AuxDescriptor,
+ USHORT NullSessionFlag)=
+ULONG _DosIRemoteApi(ULONG ApiNumber, PCHAR ServerNamePointer, PCHAR ParameterDescriptor,
+ PCHAR DataDescriptor, PCHAR AuxDescriptor,
+ ULONG NullSessionFlag)
+{
+}
+
+USHORT DosIEncryptSES(PCHAR ServerNamePointer,PCHAR passwordPointer,
+ PCHAR encryptedLmOwfPassword)=
+ULONG _DosIEncryptSES(PCHAR ServerNamePointer,PCHAR passwordPointer,
+ PCHAR encryptedLmOwfPassword)
+{
+}
+
+USHORT NetIWkstaGetUserInfo(PCHAR UserName, PCHAR logonServer,
+ PCHAR LogonDomain, PCHAR OtherDomains,
+ PCHAR WsName)=
+ULONG _NetIWkstaGetUserInfo(PCHAR UserName, PCHAR logonServer,
+ PCHAR LogonDomain, PCHAR OtherDomains,
+ PCHAR WsName)
+
+{
+}
+USHORT NetIUserPasswordSet(PCHAR ServerNamePointer,
+ PCHAR UserNamePointer,
+ PCHAR OldPasswordPointer,
+ PCHAR NewPasswordPointer)=
+ULONG _NetIUserPasswordSet(PCHAR ServerNamePointer,
+ PCHAR UserNamePointer,
+ PCHAR OldPasswordPointer,
+ PCHAR NewPasswordPointer)
+{
+}
+
+/* os2ss win32 thunk apis */
+USHORT Dos32LoadModule(PSZ DllName, PULONG pDllHandle)=
+ULONG _Dos32LoadModule(PSZ DllName, PULONG pDllHandle)
+{
+}
+
+USHORT Dos32GetProcAddr(ULONG Handle, PSZ pszProcName, PULONG pWin32Thunk)=
+ULONG _Dos32GetProcAddr(ULONG Handle, PSZ pszProcName, PULONG pWin32Thunk)
+{
+}
+
+USHORT Dos32Dispatch(ULONG Win32Thunk, PVOID pArguments, PULONG pRetCode)=
+ULONG _Dos32Dispatch(ULONG Win32Thunk, PVOID pArguments, PULONG pRetCode)
+{
+}
+
+USHORT Dos32FreeModule(ULONG DllHandle)=
+ULONG _Dos32FreeModule(ULONG DllHandle)
+{
+}
+
+USHORT FarPtr2FlatPtr(ULONG FarPtr, PULONG pFlarPtr)=
+ULONG _FarPtr2FlatPtr(ULONG FarPtr, PULONG pFlarPtr)
+{
+}
+
+USHORT FlatPtr2FarPtr(ULONG FlatPtr, PULONG pFarPtr)=
+ULONG _FlatPtr2FarPtr(ULONG FlatPtr, PULONG pFarPtr)
+{
+}
diff --git a/private/os2/client/thunk/doscalls.thk b/private/os2/client/thunk/doscalls.thk
new file mode 100644
index 000000000..a6dcd7a09
--- /dev/null
+++ b/private/os2/client/thunk/doscalls.thk
@@ -0,0 +1,453 @@
+/*--
+
+ Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Doscalls.thk - mapping of 16bit OS2 1.x calls to thunks
+ that call OS2/NT subsystem APIs
+
+Author:
+
+ Yaron Shamir (YaronS) 12-Apr-1991
+
+Revision History:
+
+--*/
+
+#include "doscalls.mif"
+
+/*
+ * DON'T CHANGE THE ORDER
+ * The following down to the next comment line have to stay in this order
+ * so that we can use them as entry points from user code
+ */
+
+DosExitStub => _DosExitStub; /* must start at offset 0 */
+LDRLibiReturn => _LDRLibiReturn; /* must start at offset 4 */
+DosExitProcessStub => _DosExitProcessStub;/* must start at offset 8 */
+DosReturn => _DosReturn; /* must start at offset 12 */
+
+/********************************************************/
+DosExit => _DosExit;
+DosCWait => _Dos16WaitChild;
+DosBeep => _DosBeep;
+DosPhysicalDisk => _DosPhysicalDisk;
+DosGetCp => _DosGetCp;
+DosSetCp => _DosSetCp;
+DosSetProcCp => _DosSetProcCp;
+DosGetCtryInfo => _DosGetCtryInfo;
+DosGetDBCSEv => _DosGetDBCSEv;
+DosCaseMap => _DosCaseMap;
+DosGetCollate => _DosGetCollate;
+DosSleep => _DosSleep;
+DosDevConfig => _DosDevConfig;
+DosGetDateTime => _DosGetDateTime;
+DosSetDateTime => _DosSetDateTime;
+DosExecPgm => _Dos16ExecPgm;
+DosEnterCritSec => _DosEnterCritSec;
+DosExitCritSec => _DosExitCritSec;
+DosKillProcess => _DosKillProcess;
+DosSetPrty => _DosSetPriority;
+DosResumeThread => _DosResumeThread;
+DosSuspendThread => _DosSuspendThread;
+DosMakePipe => _Dos16CreatePipe;
+DosCreateQueue => _Dos16CreateQueue;
+DosOpenQueue => _Dos16OpenQueue;
+DosCloseQueue => _DosCloseQueue;
+DosPeekQueue => _Dos16PeekQueue;
+DosReadQueue => _Dos16ReadQueue;
+DosPurgeQueue => _DosPurgeQueue;
+DosQueryQueue => _Dos16QueryQueue;
+DosWriteQueue => _DosWriteQueue;
+DosCallNmPipe => _Dos16CallNPipe;
+DosConnectNmPipe => _DosConnectNPipe;
+DosDisConnectNmPipe => _DosDisConnectNPipe;
+DosMakeNmPipe => _Dos16CreateNPipe;
+DosPeekNmPipe => _Dos16PeekNPipe;
+DosQNmPHandState => _Dos16QueryNPHState;
+/* DosRawReadNmPipe => _DosRawReadNPipe; */
+/* DosRawWriteNmPipe => _DosRawWriteNPipe; */
+DosQNmPipeInfo => _DosQueryNPipeInfo;
+DosQNmPipeSemState => _DosQueryNPipeSemState;
+DosSetNmPHandState => _DosSetNPHState;
+DosSetNmPipeSem => _DosSetNPipeSem;
+DosTransactNmPipe => _Dos16TransactNPipe;
+DosWaitNmPipe => _DosWaitNPipe;
+DosBufReset => _DosResetBuffer;
+DosChdir => _DosSetCurrentDir;
+DosChgFilePtr => _DosSetFilePtr;
+DosClose => _DosClose;
+DosCopy => _DosCopy;
+DosICopy => _DosICopy;
+DosDelete => _DosDelete;
+DosDevIOCtl => _DosDevIOCtl;
+DosDupHandle => _Dos16DupHandle;
+DosEditName => _DosEditName;
+DosFileIO => _DosFileIO;
+DosFindClose => _DosFindClose;
+DosFSAttach => _DosFSAttach;
+DosFSCtl => _Dos16FSCtl;
+DosMove => _DosMove;
+DosNewSize => _DosSetFileSize;
+DosQCurDir => _Dos16QueryCurrentDir;
+DosQCurDisk => _Dos16QueryCurrentDisk;
+DosQFHandState => _Dos16QueryFHState;
+DosSetFHandState => _DosSetFHState;
+DosQFSAttach => _Dos16QFSAttach;
+DosQFSInfo => _DosQueryFSInfo;
+DosQHandType => _Dos16QueryHType;
+DosQVerify => _Dos16QueryVerify;
+DosRmDir => _DosDeleteDir;
+DosSearchPath => _DosSearchPath;
+DosSelectDisk => _DosSetDefaultDisk;
+DosSetFSInfo => _DosSetFSInfo;
+DosSetMaxFH => _DosSetMaxFH;
+DosSetVerify => _DosSetVerify;
+DosErrClass => _Dos16ErrClass;
+DosError => _DosError;
+DosLoadModule => _DosLoadModuleNE;
+DosFreeModule => _DosFreeModuleNE;
+DosGetModHandle => _DosQueryModuleHandleNE;
+DosGetModName => _DosQueryModuleNameNE;
+DosGetResource => _DosGetResourceNE;
+DosGetResource2 => _DosGetResource2NE;
+DosFreeResource => _DosFreeResourceNE;
+DosQAppType => _DosQueryAppTypeNE;
+DosShutdown => _DosShutdown;
+
+DosCreateThread => _Dos16CreateThread;
+DosExitList => _Dos16ExitList;
+DosGetInfoSeg => _DosGetInfoSeg;
+DosOpen => _Dos16Open;
+DosOpen2 => _Dos16Open2;
+DosRead => _Dos16Read;
+DosWrite => _Dos16Write;
+DosFindFirst => _Dos16FindFirst;
+DosFindFirst2 => _Dos16FindFirst2;
+DosEnumAttribute => _Dos16EnumAttribute;
+DosQFileMode => _DosQFileMode;
+DosQFileInfo => _DosQFileInfo;
+DosAllocSeg => _DosAllocSeg;
+DosFreeSeg => _DosFreeSeg;
+DosGetSeg => _DosGetSeg;
+DosGiveSeg => _DosGiveSeg;
+DosReallocSeg => _DosReallocSeg;
+DosSizeSeg => _DosSizeSeg;
+DosAllocHuge => _DosAllocHuge;
+DosReallocHuge => _DosReallocHuge;
+DosGetHugeShift => _DosGetHugeShift;
+DosAllocShrSeg => _DosAllocShrSeg;
+DosLockSeg => _DosLockSeg;
+DosUnlockSeg => _DosUnlockSeg;
+DosGetShrSeg => _DosGetShrSeg;
+DosMemAvail => _DosMemAvail;
+DosCreateCSAlias => _DosCreateCSAlias;
+DosSemClear => _DosSemClear;
+DosSemSet => _DosSemSet;
+DosSemWait => _DosSemWait;
+DosSemSetWait => _DosSemSetWait;
+DosSemRequest => _DosSemRequest;
+DosCreateSem => _DosCreateSem;
+DosOpenSem => _DosOpenSem;
+DosCloseSem => _DosCloseSem;
+DosMuxSemWait => _DosMuxSemWait;
+DosFSRamSemRequest => _DosFSRamSemRequest;
+DosFSRamSemClear => _DosFSRamSemClear;
+DosTimerAsync => _DosAsyncTimer;
+DosTimerStart => _DosStartTimer;
+DosTimerStop => _DosStopTimer;
+DosGetProcAddr => _DosGetProcAddrNE;
+DosQueryProcType => _DosQueryProcType;
+DosQueryResourceSize => _DosQueryResourceSize;
+DosSetSigHandler => _DosSetSigHandler;
+DosFlagProcess => DosFlagProcess16;
+DosHoldSignal => DosHoldSignal16;
+DosSendSignal => DosSendSignal16;
+DosSetVec => _DosSetVec;
+DosGetEnv => _DosGetEnv;
+DosGetVersion => _DosGetVersion;
+DosGetMachineMode => _DosGetMachineMode;
+DosFindNext => _Dos16FindNext;
+DosGetPID => _DosGetPID;
+DosGetPPID => _DosGetPPID;
+DosMkDir => _Dos16MkDir;
+DosMkDir2 => _Dos16MkDir2;
+DosSetFileMode => _DosSetFileMode;
+DosSetFileInfo => _Dos16SetFileInfo;
+DosTrueGetMessage => _DosTrueGetMessage;
+DosScanEnv => _DosScanEnvNE;
+DosPTrace => _DosPTrace;
+DosInsMessage => _DosInsMessage;
+DosPutMessage => _DosPutMessage;
+DosSubSet => _Dos16SubSet;
+DosSubAlloc => _Dos16SubAlloc;
+DosSubFree => _Dos16SubFree;
+DosStartSession => _Dos16StartSession;
+DosStopSession => _DosStopSession;
+DosSetSession => _DosSetSession;
+DosSelectSession => _DosSelectSession;
+DosSMSetTitle => _DosSMSetTitle;
+DosSMPMPresent => _DosSMPMPresent;
+#ifndef PMNT
+WinSetTitleAndIcon => _WinSetTitleAndIcon;
+#endif
+DosGetPrty => _DosGetPriority;
+DosQSysInfo => _DosQSysInfo;
+DosDevIOCtl2 => _DosDevIOCtl2;
+DosICanonicalize => _DosICanonicalize;
+DosReadAsync => _DosReadAsync;
+DosWriteAsync => _DosWriteAsync;
+DosFindNotifyClose => _DosFindNotifyClose;
+DosFindNotifyFirst => _DosFindNotifyFirst;
+DosFindNotifyNext => _DosFindNotifyNext;
+DosFileLocks => _DosFileLocks;
+DosQPathInfo => _Dos16QPathInfo;
+DosSetPathInfo => _Dos16SetPathInfo;
+DosPortAccess => _DosPortAccess;
+DosCLIAccess => _DosCLIAccess;
+#ifndef PMNT
+WinQueryProfileString => _WinQueryProfileString;
+WinQueryProfileSize => _WinQueryProfileSize;
+WinQueryProfileData => _WinQueryProfileData;
+WinQueryProfileInt => _WinQueryProfileInt;
+WinWriteProfileData => _WinWriteProfileData;
+WinWriteProfileString => _WinWriteProfileString;
+WinCreateHeap => _WinCreateHeap;
+WinDestroyHeap => _WinDestroyHeap;
+WinAllocMem => _WinAllocMem;
+WinFreeMem => _WinFreeMem;
+WinGetLastError => _WinGetLastError;
+#endif
+VioScrollUp => _VioScrollUp;
+VioGetCurPos => _VioGetCurPos;
+VioSetCurPos => _VioSetCurPos;
+VioWrtTTY => _VioWrtTTY;
+VioGetMode => _VioGetMode;
+VioReadCellStr => _VioReadCellStr;
+VioScrollLf => _VioScrollLf;
+VioReadCharStr => _VioReadCharStr;
+VioWrtCharStrAtt => _VioWrtCharStrAtt;
+VioWrtCellStr => _VioWrtCellStr;
+VioWrtCharStr => _VioWrtCharStr;
+VioWrtNCell => _VioWrtNCell;
+VioWrtNAttr => _VioWrtNAttr;
+VioWrtNChar => _VioWrtNChar;
+VioScrollDn => _VioScrollDn;
+VioScrollRt => _VioScrollRt;
+VioGetAnsi => _VioGetAnsi;
+VioSetAnsi => _VioSetAnsi;
+VioGetConfig => _VioGetConfig;
+VioGetCp => _VioGetCp;
+VioSetCp => _VioSetCp;
+VioGetCurType => _VioGetCurType;
+VioSetCurType => _VioSetCurType;
+VioSetMode => _VioSetMode;
+VioDeRegister => _VioDeRegister;
+VioRegister => _VioRegister;
+VioPopUp => _VioPopUp;
+VioEndPopUp => _VioEndPopUp;
+VioGetBuf => _VioGetBuf;
+VioShowBuf => _VioShowBuf;
+VioGetFont => _VioGetFont;
+VioSetFont => _VioSetFont;
+VioGetState => _VioGetState;
+VioSetState => _VioSetState;
+VioGetPhysBuf => _VioGetPhysBuf;
+VioModeUndo => _VioModeUndo;
+VioModeWait => _VioModeWait;
+VioSavRedrawWait => _VioSavRedrawWait;
+VioSavRedrawUndo => _VioSavRedrawUndo;
+VioScrLock => _VioScrLock;
+VioScrUnLock => _VioScrUnLock;
+VioPrtSc => _VioPrtSc;
+VioPrtScToggle => _VioPrtScToggle;
+#ifdef DBCS
+/*MSKK Begin KazuM -Jun.22.1992-*/
+VioCheckCharType => _VioCheckCharType;
+/*MSKK End KazuM -Jun.22.1992-*/
+#endif
+KbdFlushBuffer => _KbdFlushBuffer;
+KbdGetStatus => _KbdGetStatus;
+KbdSetStatus => _KbdSetStatus;
+KbdPeek => _KbdPeek;
+KbdCharIn => _KbdCharIn;
+KbdStringIn => _KbdStringIn;
+KbdGetFocus => _KbdGetFocus;
+KbdFreeFocus => _KbdFreeFocus;
+KbdClose => _KbdClose;
+KbdOpen => _KbdOpen;
+KbdDeRegister => _KbdDeRegister;
+KbdRegister => _KbdRegister;
+KbdGetCp => _KbdGetCp;
+KbdSetCp => _KbdSetCp;
+KbdSetCustXt => _KbdSetCustXt;
+KbdXlate => _KbdXlate;
+KbdGetHWID => _KbdGetHWID;
+KbdSetFgnd => _KbdSetFgnd;
+KbdSynch => _KbdSynch;
+KbdShellInit => _KbdShellInit;
+MouClose => _MouClose;
+MouDeRegister => _MouDeRegister;
+MouDrawPtr => _MouDrawPtr;
+MouFlushQue => _MouFlushQue;
+MouGetDevStatus => _MouGetDevStatus;
+MouGetEventMask => _MouGetEventMask;
+MouGetNumButtons => _MouGetNumButtons;
+MouGetNumMickeys => _MouGetNumMickeys;
+MouGetNumQueEl => _MouGetNumQueEl;
+MouGetPtrPos => _MouGetPtrPos;
+MouGetPtrShape => _MouGetPtrShape;
+MouGetScaleFact => _MouGetScaleFact;
+MouOpen => _MouOpen;
+MouReadEventQue => _MouReadEventQue;
+MouRegister => _MouRegister;
+MouRemovePtr => _MouRemovePtr;
+MouSetDevStatus => _MouSetDevStatus;
+MouSetEventMask => _MouSetEventMask;
+MouSetPtrPos => _MouSetPtrPos;
+MouSetPtrShape => _MouSetPtrShape;
+MouSetScaleFact => _MouSetScaleFact;
+MouSynch => _MouSynch;
+DosMonOpen => _DosMonOpen;
+DosMonClose => _DosMonClose;
+DosMonRead => _DosMonRead;
+DosMonReg => _DosMonReg;
+DosMonWrite => _DosMonWrite;
+NetGetDCName => _Net16GetDCName;
+NetHandleGetInfo => _Net16HandleGetInfo;
+NetServerDiskEnum => _Net16ServerDiskEnum;
+NetServerEnum2 => _Net16ServerEnum2;
+NetServerGetInfo => _Net16ServerGetInfo;
+NetServiceControl => _Net16ServiceControl;
+NetServiceEnum => _Net16ServiceEnum;
+NetServiceGetInfo => _Net16ServiceGetInfo;
+NetServiceInstall => _Net16ServiceInstall;
+NetShareEnum => _Net16ShareEnum;
+NetShareGetInfo => _Net16ShareGetInfo;
+NetUseAdd => _Net16UseAdd;
+NetUseDel => _Net16UseDel;
+NetUseEnum => _Net16UseEnum;
+NetUseGetInfo => _Net16UseGetInfo;
+NetUserEnum => _Net16UserEnum;
+NetWkstaGetInfo => _Net16WkstaGetInfo;
+NetAccessAdd => _Net16AccessAdd;
+NetAccessSetInfo => _Net16AccessSetInfo;
+NetAccessGetInfo => _Net16AccessGetInfo;
+NetAccessDel => _Net16AccessDel;
+NetShareAdd => _Net16ShareAdd;
+NetShareDel => _Net16ShareDel;
+NetUserGetInfo => _Net16UserGetInfo;
+NetMessageBufferSend => _Net16MessageBufferSend;
+Netbios => _Net16bios;
+NetBiosClose => _Net16BiosClose;
+NetBiosEnum => _Net16BiosEnum;
+NetBiosGetInfo => _Net16BiosGetInfo;
+NetBiosOpen => _Net16BiosOpen;
+NetBiosSubmit => _Net16BiosSubmit;
+DosMakeMailslot => _Dos16MakeMailslot;
+DosDeleteMailslot => _Dos16DeleteMailslot;
+DosMailslotInfo => _Dos16MailslotInfo;
+DosPeekMailslot => _Dos16PeekMailslot;
+DosReadMailslot => _Dos16ReadMailslot;
+DosWriteMailslot => _Dos16WriteMailslot;
+#ifdef PMNT
+DosSetFgnd => _DosSetFgnd;
+DosR2StackRealloc => _DosR2StackRealloc;
+DosSystemService => _DosSystemService;
+VioRedrawSize => _VioRedrawSize;
+VioGetPSAddress => _VioGetPSAddress;
+PMNTCreateHiddenThread => _PMNT16CreateThread;
+PMNTIoctl => _PMNTIoctl;
+PMNTDbgPrint => _PMNTDbgPrint;
+PMNTGetNextEvent => _PMNTGetNextEvent;
+PMNTMemMap => _PMNTMemMap;
+PMNTGetPgmName => _PMNTGetPgmName;
+PMNTSetConsoleTitle => _PMNTSetConsoleTitle;
+PMNTCreateGroup => _PMNTCreateGroup;
+PMNTAddProgram => _PMNTAddProgram;
+PMNTChangeProgram => _PMNTChangeProgram;
+PMNTQueryProgramTitles => _PMNTQueryProgramTitles;
+PMNTQueryDefinition => _PMNTQueryDefinition;
+PMNTQueryProgramHandle => _PMNTQueryProgramHandle;
+PMNTDestroyGroup => _PMNTDestroyGroup;
+PMNTRemoveProgram => _PMNTRemoveProgram;
+PMNTSetFullScreen => _PMNTSetFullScreen;
+PMNTGetWin32Hwnd => _PMNTGetWin32Hwnd;
+PMNTSetFocus => _PMNTSetFocus;
+PMNTCloseWindow => _PMNTCloseWindow;
+PMNTGetFullScreen => _PMNTGetFullScreen;
+PMNTSetPMShellFlag => _PMNTSetPMShellFlag;
+PMNTRegisterDisplayAdapter => _PMNTRegisterDisplayAdapter;
+PMNTIOMap => _PMNTIOMap;
+PMNTGetSystemTime => _PMNTGetSystemTime;
+PMNTIsSessionRoot => _PMNTIsSessionRoot;
+DosSysTrace => _DosSysTrace;
+DosSMPause => _DosSMPause;
+#ifdef DBCS
+/* MSKK [ShigeO] Aug 26, 1993 */
+PMNTCreateFontIndirect => _PMNTCreateFontIndirect;
+PMNTGetTextMetrics => _PMNTGetTextMetrics;
+PMNTGetStringBitmap => _PMNTGetStringBitmap;
+#endif
+/* MSKK */
+PMNTDbgPrompt => _PMNTDbgPrompt;
+PMNTOpenClipbrd => _PMNTOpenClipbrd;
+PMNTCloseClipbrd => _PMNTCloseClipbrd;
+PMNTEmptyClipbrd => _PMNTEmptyClipbrd;
+PMNTSetClipbrdText => _PMNTSetClipbrdText;
+PMNTSetClipbrdBitmap => _PMNTSetClipbrdBitmap;
+PMNTQueryClipbrdText => _PMNTQueryClipbrdText;
+PMNTQueryClipbrdBitmap => _PMNTQueryClipbrdBitmap;
+PMNTQueryClipbrdFmtInfo => _PMNTQueryClipbrdFmtInfo;
+PMNTWin32Clipbrd => _PMNTWin32Clipbrd;
+PMNTIdentifyCodeSelector => _PMNTIdentifyCodeSelector;
+PMNTVioGetConfig => _PMNTVioGetConfig;
+PMNTVioGetCp => _PMNTVioGetCp;
+PMNTProcessIsPMShell => _PMNTProcessIsPMShell;
+PMNTQueryScreenSize => _PMNTQueryScreenSize;
+MouInitReal => _MouInitReal;
+PMNTSetShutdownPriority => _PMNTSetShutdownPriority;
+PMNTSetSubprocSem => _PMNTSetSubprocSem;
+#if 0
+// Spring cleaning - APIs no longer needed
+QHKeybdHandle => _QHKeybdHandle;
+QHMouseHandle => _QHMouseHandle;
+DosIRamSemWake => _DosIRamSemWake;
+DosISemRequest => _DosISemRequest;
+DosUnknownApi54 => _DosUnknownApi54;
+DosUnknownApi105 => _DosUnknownApi105;
+DosGiveSegList => _DosGiveSegList;
+VioSSWSwitch => _VioSSWSwitch;
+MouSetHotKey => _MouSetHotKey;
+KbdFree => _KbdFree;
+MouFree => _MouFree;
+VioFree => _VioFree;
+DosSGSwitchMe => _DosSGSwitchMe;
+KbdSwitchFgnd => _KbdSwitchFgnd;
+MouShellInit => _MouShellInit;
+VioRestore => _VioRestore;
+VioSave => _VioSave;
+VioSRFunBlock => _VioSRFunBlock;
+VioSRFBlock => _VioSRFBlock;
+#endif // 0
+#endif // PMNT
+#ifdef DBCS
+/*MSKK Begin V-AkihiS -Dec.14.1992-*/
+IMMonInstall => _IMMonInstall;
+IMMonDeinstall => _IMMonDeinstall;
+IMMonStatus => _IMMonStatus;
+IMMonActive => _IMMonActive;
+IMMonInactive => _IMMonInactive;
+/*MSKK End V-AkihiS -Dec.14.1992-*/
+#endif
+DosIRemoteApi => _DosIRemoteApi;
+NetIWkstaGetUserInfo => _NetIWkstaGetUserInfo;
+NetIUserPasswordSet => _NetIUserPasswordSet;
+DosIEncryptSES => _DosIEncryptSES;
+Dos32LoadModule => _Dos32LoadModule;
+Dos32GetProcAddr => _Dos32GetProcAddr;
+Dos32Dispatch => _Dos32Dispatch;
+Dos32FreeModule => _Dos32FreeModule;
+FarPtr2FlatPtr => _FarPtr2FlatPtr;
+FlatPtr2FarPtr => _FlatPtr2FarPtr;
diff --git a/private/os2/client/thunk/dosthk.tif b/private/os2/client/thunk/dosthk.tif
new file mode 100644
index 000000000..bfdb70595
--- /dev/null
+++ b/private/os2/client/thunk/dosthk.tif
@@ -0,0 +1,299 @@
+/* SCCSID = @(#)dosthk.tif 1.5 90/05/18 */
+
+/*** dosthk.tif - Header file for the thunk compiler's Dos script files
+ *
+ * These are the typedefs for the scripts for the Dos apientry routines.
+ * The typedefs in this file are only used in the base api routines.
+ *
+ * History:
+ * 30-Jan-1989 JulieB Created it.
+ */
+
+
+typedef struct _PIDINFO {
+ PID pid;
+ TID tid;
+ PID pidParent;
+} PIDINFO;
+
+typedef PIDINFO *PPIDINFO;
+
+/**** The result codes structure is different between 0:32 and 16:16 **/
+/**** This structure was changed to use UINT to produce the correct size **/
+
+typedef struct _RESULTCODES {
+ UINT codeTerminate;
+ UINT codeResult;
+} RESULTCODES;
+
+typedef RESULTCODES *PRESULTCODES;
+
+/**** The queue result structure is different between 0:32 and 16:16 **/
+/**** This structure was changed to use UINT to produce the correct size **/
+
+typedef struct _QUEUERESULT {
+ UINT pidProcess;
+ UINT EventCode;
+} QUEUERESULT;
+
+typedef QUEUERESULT *PQUEUERESULT;
+
+typedef struct _GINFOSEG {
+ ULONG time;
+ ULONG msecs;
+ UCHAR hour;
+ UCHAR minutes;
+ UCHAR seconds;
+ UCHAR hundredths;
+ USHORT timezone;
+ USHORT cusecTimerInterval;
+ UCHAR day;
+ UCHAR month;
+ USHORT year;
+ UCHAR weekday;
+ UCHAR uchMajorVersion;
+ UCHAR uchMinorVersion;
+ UCHAR chRevisionLetter;
+ UCHAR sgCurrent;
+ UCHAR sgMax;
+ UCHAR cHugeShift;
+ UCHAR fProtectModeOnly;
+ USHORT pidForeground;
+ UCHAR fDynamicSched;
+ UCHAR csecMaxWait;
+ USHORT cmsecMinSlice;
+ USHORT cmsecMaxSlice;
+ USHORT bootdrive;
+ UCHAR amecRAS[32];
+} GINFOSEG;
+
+typedef GINFOSEG *PGINFOSEG;
+
+typedef struct _LINFOSEG {
+ PID pidCurrent;
+ PID pidParent;
+ USHORT prtyCurrent;
+ TID tidCurrent;
+ USHORT sgCurrent;
+ USHORT sgSub;
+ BOOL fForeground;
+} LINFOSEG;
+
+typedef LINFOSEG *PLINFOSEG;
+
+typedef struct _FILESTATUS {
+ FDATE fdateCreation;
+ FTIME ftimeCreation;
+ FDATE fdateLastAccess;
+ FTIME ftimeLastAccess;
+ FDATE fdateLastWrite;
+ FTIME ftimeLastWrite;
+ ULONG cbFile;
+ ULONG cbFileAlloc;
+ USHORT attrFile;
+} FILESTATUS;
+
+typedef FILESTATUS *PFILESTATUS;
+
+
+
+typedef struct _FILESTATUS2 {
+ FDATE fdateCreation;
+ FTIME ftimeCreation;
+ FDATE fdateLastAccess;
+ FTIME ftimeLastAccess;
+ FDATE fdateLastWrite;
+ FTIME ftimeLastWrite;
+ ULONG cbFile;
+ ULONG cbFileAlloc;
+ USHORT attrFile;
+ ULONG cbList;
+} FILESTATUS2;
+
+typedef FILESTATUS2 *PFILESTATUS2;
+
+
+
+
+typedef struct _FSALLOCATE {
+ ULONG idFileSystem;
+ ULONG cSectorUnit;
+ ULONG cUnit;
+ ULONG cUnitAvail;
+ USHORT cbSector;
+} FSALLOCATE;
+
+typedef FSALLOCATE *PFSALLOCATE;
+
+typedef SHANDLE HDIR;
+
+typedef HDIR *PHDIR;
+
+typedef LHANDLE HSYSSEM;
+
+typedef HSYSSEM *PHSYSSEM;
+
+typedef struct _MUXSEM {
+ USHORT zero;
+ HSEM hsem;
+} MUXSEM;
+
+typedef MUXSEM *PMUXSEM;
+
+typedef struct _MUXSEMLIST {
+ USHORT cmxs;
+ MUXSEM amxs[16];
+} MUXSEMLIST;
+
+typedef MUXSEMLIST *PMUXSEMLIST;
+
+typedef struct _DATETIME {
+ UCHAR hours;
+ UCHAR minutes;
+ UCHAR seconds;
+ UCHAR hundredths;
+ UCHAR day;
+ UCHAR month;
+ USHORT year;
+ SHORT timezone;
+ UCHAR weekday;
+} DATETIME;
+
+typedef DATETIME *PDATETIME;
+
+typedef struct _COUNTRYCODE {
+ USHORT country;
+ USHORT codepage;
+} COUNTRYCODE;
+
+typedef COUNTRYCODE *PCOUNTRYCODE;
+
+typedef struct _COUNTRYINFO {
+ USHORT country;
+ USHORT codepage;
+ USHORT fsDateFmt;
+ char szCurrency[5];
+ char szThousandsSeparator[2];
+ char szDecimal[2];
+ char szDateSeparator[2];
+ char szTimeSeparator[2];
+ UCHAR fsCurrencyFmt;
+ UCHAR cDecimalPlace;
+ UCHAR fsTimeFmt;
+ USHORT abReserved1[2];
+ char szDataSeparator[2];
+ USHORT abReserved2[5];
+} COUNTRYINFO;
+
+typedef COUNTRYINFO *PCOUNTRYINFO;
+
+typedef SHANDLE HMONITOR;
+
+typedef HMONITOR *PHMONITOR;
+
+typedef SHANDLE HQUEUE;
+
+typedef HQUEUE *PHQUEUE;
+
+typedef struct _STARTDATA {
+ USHORT cb;
+ USHORT Related;
+ USHORT FgBg;
+ USHORT TraceOpt;
+ PSZ PgmTitle;
+ PSZ PgmName;
+ PBYTE PgmInputs;
+ PBYTE TermQ;
+} STARTDATA;
+
+typedef STARTDATA *PSTARTDATA;
+
+typedef struct _STATUSDATA {
+ USHORT cb;
+ USHORT SelectInd;
+ USHORT BindInd;
+} STATUSDATA;
+
+typedef STATUSDATA *PSTATUSDATA;
+
+typedef SHANDLE HPIPE;
+
+typedef HPIPE *PHPIPE;
+
+typedef struct _DOSFSRSEM {
+ USHORT cb;
+ PID pid;
+ TID tid;
+ USHORT cUsage;
+ USHORT client;
+ ULONG sem;
+} DOSFSRSEM;
+
+typedef DOSFSRSEM *PDOSFSRSEM;
+
+typedef struct _FEA {
+ char fea_reserved;
+ char fea_cbName;
+ unsigned short fea_cbValue;
+} FEA;
+
+typedef struct _FEAList {
+ unsigned long feal_cbList;
+ FEA feal_list[1];
+} FEAList;
+
+typedef FEAList *PFEAList;
+
+typedef struct _GEA {
+ char gea_cbName;
+ char gea_szName[1];
+} GEA;
+
+typedef struct _GEAList {
+ unsigned long geal_cbList;
+ GEA geal_list[1];
+} GEAList;
+
+typedef GEAList *PGEAList;
+
+typedef struct _EAOP {
+ PGEAList fpGEAList;
+ PFEAList fpFEAList;
+ unsigned long offError;
+} EAOP;
+
+typedef EAOP *PEAOP;
+
+
+/*** FileLock is used by the FileLocks API.
+ ***
+ *** Created: KevinRo 3-APR-89
+ ***/
+
+typedef struct _FileLock {
+ ULONG Offset;
+ ULONG RangeLen;
+ } FILELOCK;
+
+typedef FILELOCK *PFILELOCK;
+
+
+/*
+ * For DosShutdown.
+ *
+ * The 3rd field (pchArgument) should really be a PSZ. However,
+ * in order to allow the thunk layer to pass an invalid pointer
+ * onto the kernel without trapping, it was made a PCHAR. This
+ * way the kernel worker can deal appropriately with the invalid
+ * pointer to the pchArgument.
+ *
+ * 02-May-1990 JulieB Added it.
+ */
+
+typedef struct _SDPACKET {
+ ULONG reserved;
+ ULONG errcode;
+ PCHAR pchArgument;
+} SDPACKET;
+typedef SDPACKET *PSDPACKET;
+
diff --git a/private/os2/client/thunk/include/assert.h b/private/os2/client/thunk/include/assert.h
new file mode 100644
index 000000000..984adb0b2
--- /dev/null
+++ b/private/os2/client/thunk/include/assert.h
@@ -0,0 +1,34 @@
+/***
+*assert.h - define the assert macro
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Defines the assert(exp) macro.
+* [ANSI/System V]
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+#undef assert
+
+#ifdef NDEBUG
+
+#define assert(exp) ((void)0)
+
+#else
+
+void _FAR_ _cdecl _assert(void _FAR_ *, void _FAR_ *, unsigned);
+#define assert(exp) \
+ ( (exp) ? (void) 0 : _assert(#exp, __FILE__, __LINE__) )
+
+#endif /* NDEBUG */
diff --git a/private/os2/client/thunk/include/bios.h b/private/os2/client/thunk/include/bios.h
new file mode 100644
index 000000000..102d50927
--- /dev/null
+++ b/private/os2/client/thunk/include/bios.h
@@ -0,0 +1,175 @@
+/***
+*bios.h - declarations for bios interface functions and supporting definitions
+*
+* Copyright (c) 1987-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file declares the constants, structures, and functions
+* used for accessing and using various BIOS interfaces.
+*
+****/
+
+#ifndef _MT
+
+/* manifest constants for BIOS serial communications (RS-232) support */
+
+/* serial port services */
+
+#define _COM_INIT 0 /* init serial port */
+#define _COM_SEND 1 /* send character */
+#define _COM_RECEIVE 2 /* receive character */
+#define _COM_STATUS 3 /* get serial port status */
+
+/* serial port initializers. One and only one constant from each of the
+ * following four groups - character size, stop bit, parity, and baud rate -
+ * must be specified in the initialization byte.
+ */
+
+/* character size initializers */
+
+#define _COM_CHR7 2 /* 7 bits characters */
+#define _COM_CHR8 3 /* 8 bits characters */
+
+/* stop bit values - on or off */
+
+#define _COM_STOP1 0 /* 1 stop bit */
+#define _COM_STOP2 4 /* 2 stop bits */
+
+/* parity initializers */
+
+#define _COM_NOPARITY 0 /* no parity */
+#define _COM_ODDPARITY 8 /* odd parity */
+#define _COM_EVENPARITY 24 /* even parity */
+
+/* baud rate initializers */
+
+#define _COM_110 0 /* 110 baud */
+#define _COM_150 32 /* 150 baud */
+#define _COM_300 64 /* 300 baud */
+#define _COM_600 96 /* 600 baud */
+#define _COM_1200 128 /* 1200 baud */
+#define _COM_2400 160 /* 2400 baud */
+#define _COM_4800 192 /* 4800 baud */
+#define _COM_9600 224 /* 9600 baud */
+
+
+/* manifest constants for BIOS disk support */
+
+/* disk services */
+
+#define _DISK_RESET 0 /* reset disk controller */
+#define _DISK_STATUS 1 /* get disk status */
+#define _DISK_READ 2 /* read disk sectors */
+#define _DISK_WRITE 3 /* write disk sectors */
+#define _DISK_VERIFY 4 /* verify disk sectors */
+#define _DISK_FORMAT 5 /* format disk track */
+
+/* struct used to send/receive information to/from the BIOS disk services */
+
+#ifndef _DISKINFO_T_DEFINED
+
+struct diskinfo_t {
+ unsigned drive;
+ unsigned head;
+ unsigned track;
+ unsigned sector;
+ unsigned nsectors;
+ void _far *buffer;
+ };
+
+#define _DISKINFO_T_DEFINED
+
+#endif
+
+
+/* manifest constants for BIOS keyboard support */
+
+/* keyboard services */
+
+#define _KEYBRD_READ 0 /* read next character from keyboard */
+#define _KEYBRD_READY 1 /* check for keystroke */
+#define _KEYBRD_SHIFTSTATUS 2 /* get current shift key status */
+
+/* services for enhanced keyboards */
+
+#define _NKEYBRD_READ 0x10 /* read next character from keyboard */
+#define _NKEYBRD_READY 0x11 /* check for keystroke */
+#define _NKEYBRD_SHIFTSTATUS 0x12 /* get current shift key status */
+
+
+/* manifest constants for BIOS printer support */
+
+/* printer services */
+
+#define _PRINTER_WRITE 0 /* write character to printer */
+#define _PRINTER_INIT 1 /* intialize printer */
+#define _PRINTER_STATUS 2 /* get printer status */
+
+
+/* manifest constants for BIOS time of day support */
+
+/* time of day services */
+
+#define _TIME_GETCLOCK 0 /* get current clock count */
+#define _TIME_SETCLOCK 1 /* set current clock count */
+
+
+#ifndef _REGS_DEFINED
+
+/* word registers */
+
+struct WORDREGS {
+ unsigned int ax;
+ unsigned int bx;
+ unsigned int cx;
+ unsigned int dx;
+ unsigned int si;
+ unsigned int di;
+ unsigned int cflag;
+ };
+
+/* byte registers */
+
+struct BYTEREGS {
+ unsigned char al, ah;
+ unsigned char bl, bh;
+ unsigned char cl, ch;
+ unsigned char dl, dh;
+ };
+
+/* general purpose registers union -
+ * overlays the corresponding word and byte registers.
+ */
+
+union REGS {
+ struct WORDREGS x;
+ struct BYTEREGS h;
+ };
+
+/* segment registers */
+
+struct SREGS {
+ unsigned int es;
+ unsigned int cs;
+ unsigned int ss;
+ unsigned int ds;
+ };
+
+#define _REGS_DEFINED
+
+#endif /* _REGS_DEFINED */
+
+
+/* function prototypes */
+
+unsigned _cdecl _bios_disk(unsigned, struct diskinfo_t *);
+unsigned _cdecl _bios_equiplist(void);
+unsigned _cdecl _bios_keybrd(unsigned);
+unsigned _cdecl _bios_memsize(void);
+unsigned _cdecl _bios_printer(unsigned, unsigned, unsigned);
+unsigned _cdecl _bios_serialcom(unsigned, unsigned, unsigned);
+unsigned _cdecl _bios_timeofday(unsigned, long *);
+int _cdecl int86(int, union REGS *, union REGS *);
+int _cdecl int86x(int, union REGS *, union REGS *, struct SREGS *);
+
+#endif /* _MT */
diff --git a/private/os2/client/thunk/include/cmacros.inc b/private/os2/client/thunk/include/cmacros.inc
new file mode 100644
index 000000000..b1e219627
--- /dev/null
+++ b/private/os2/client/thunk/include/cmacros.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 _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/os2/client/thunk/include/conio.h b/private/os2/client/thunk/include/conio.h
new file mode 100644
index 000000000..7cab66f0d
--- /dev/null
+++ b/private/os2/client/thunk/include/conio.h
@@ -0,0 +1,36 @@
+/***
+*conio.h - console and port I/O declarations
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This include file contains the function declarations for
+* the MS C V2.03 compatible console and port I/O routines.
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+/* function prototypes */
+
+char _FAR_ * _FAR_ _cdecl cgets(char _FAR_ *);
+int _FAR_ _cdecl cprintf(const char _FAR_ *, ...);
+int _FAR_ _cdecl cputs(const char _FAR_ *);
+int _FAR_ _cdecl cscanf(const char _FAR_ *, ...);
+int _FAR_ _cdecl getch(void);
+int _FAR_ _cdecl getche(void);
+int _FAR_ _cdecl inp(unsigned);
+unsigned _FAR_ _cdecl inpw(unsigned);
+int _FAR_ _cdecl kbhit(void);
+int _FAR_ _cdecl outp(unsigned, int);
+unsigned _FAR_ _cdecl outpw(unsigned, unsigned);
+int _FAR_ _cdecl putch(int);
+int _FAR_ _cdecl ungetch(int);
diff --git a/private/os2/client/thunk/include/ctype.h b/private/os2/client/thunk/include/ctype.h
new file mode 100644
index 000000000..3978ab6a8
--- /dev/null
+++ b/private/os2/client/thunk/include/ctype.h
@@ -0,0 +1,96 @@
+/***
+*ctype.h - character conversion macros and ctype macros
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Defines macros for character classification/conversion.
+* [ANSI/System V]
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+
+/*
+ * This declaration allows the user access to the ctype look-up
+ * array _ctype defined in ctype.obj by simply including ctype.h
+ */
+
+#ifdef _DLL
+extern unsigned char _FAR_ _cdecl _ctype[];
+#else
+extern unsigned char _near _cdecl _ctype[];
+#endif
+
+/* set bit masks for the possible character types */
+
+#define _UPPER 0x1 /* upper case letter */
+#define _LOWER 0x2 /* lower case letter */
+#define _DIGIT 0x4 /* digit[0-9] */
+#define _SPACE 0x8 /* tab, carriage return, newline, */
+ /* vertical tab or form feed */
+#define _PUNCT 0x10 /* punctuation character */
+#define _CONTROL 0x20 /* control character */
+#define _BLANK 0x40 /* space char */
+#define _HEX 0x80 /* hexadecimal digit */
+
+/* character classification function prototypes */
+
+#ifndef _CTYPE_DEFINED
+int _FAR_ _cdecl isalpha(int);
+int _FAR_ _cdecl isupper(int);
+int _FAR_ _cdecl islower(int);
+int _FAR_ _cdecl isdigit(int);
+int _FAR_ _cdecl isxdigit(int);
+int _FAR_ _cdecl isspace(int);
+int _FAR_ _cdecl ispunct(int);
+int _FAR_ _cdecl isalnum(int);
+int _FAR_ _cdecl isprint(int);
+int _FAR_ _cdecl isgraph(int);
+int _FAR_ _cdecl iscntrl(int);
+int _FAR_ _cdecl toupper(int);
+int _FAR_ _cdecl tolower(int);
+int _FAR_ _cdecl _tolower(int);
+int _FAR_ _cdecl _toupper(int);
+int _FAR_ _cdecl isascii(int);
+int _FAR_ _cdecl toascii(int);
+int _FAR_ _cdecl iscsymf(int);
+int _FAR_ _cdecl iscsym(int);
+#define _CTYPE_DEFINED
+#endif
+
+/* the character classification macro definitions */
+
+#define isalpha(_c) ( (_ctype+1)[_c] & (_UPPER|_LOWER) )
+#define isupper(_c) ( (_ctype+1)[_c] & _UPPER )
+#define islower(_c) ( (_ctype+1)[_c] & _LOWER )
+#define isdigit(_c) ( (_ctype+1)[_c] & _DIGIT )
+#define isxdigit(_c) ( (_ctype+1)[_c] & _HEX )
+#define isspace(_c) ( (_ctype+1)[_c] & _SPACE )
+#define ispunct(_c) ( (_ctype+1)[_c] & _PUNCT )
+#define isalnum(_c) ( (_ctype+1)[_c] & (_UPPER|_LOWER|_DIGIT) )
+#define isprint(_c) ( (_ctype+1)[_c] & (_BLANK|_PUNCT|_UPPER|_LOWER|_DIGIT) )
+#define isgraph(_c) ( (_ctype+1)[_c] & (_PUNCT|_UPPER|_LOWER|_DIGIT) )
+#define iscntrl(_c) ( (_ctype+1)[_c] & _CONTROL )
+#ifndef NO_EXT_KEYS
+#define toupper(_c) ( (islower(_c)) ? _toupper(_c) : (_c) )
+#define tolower(_c) ( (isupper(_c)) ? _tolower(_c) : (_c) )
+#endif
+#define _tolower(_c) ( (_c)-'A'+'a' )
+#define _toupper(_c) ( (_c)-'a'+'A' )
+#define isascii(_c) ( (unsigned)(_c) < 0x80 )
+#define toascii(_c) ( (_c) & 0x7f )
+
+/* MS C version 2.0 extended ctype macros */
+
+#define iscsymf(_c) (isalpha(_c) || ((_c) == '_'))
+#define iscsym(_c) (isalnum(_c) || ((_c) == '_'))
diff --git a/private/os2/client/thunk/include/custcntl.h b/private/os2/client/thunk/include/custcntl.h
new file mode 100644
index 000000000..73eb03cd8
--- /dev/null
+++ b/private/os2/client/thunk/include/custcntl.h
@@ -0,0 +1,82 @@
+/*
+ * CUSTOM CONTROL LIBRARY - HEADER FILE
+ *
+ */
+
+/* general size definitions */
+#define CTLTYPES 12 /* number of control types */
+#define CTLDESCR 22 /* size of control menu name */
+#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 {
+ WORD wX; /* x origin of control */
+ WORD wY; /* y origin of control */
+ WORD wCx; /* width of control */
+ WORD wCy; /* height of control */
+ WORD 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 enquiring 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
+ * could be either in pixels or in rc coordinates. If it is in pixel,
+ * the most sigificant bit(MSB) is on. If the MSB is off, it is in rc
+ * coordinates.
+ *
+ * The cursor and bitmap handles reference objects which can be
+ * used by the dialog editor in the placement and definition of
+ * new, user-defined control classes. However, dialog editor in win30
+ * does not use these fields.
+ *
+ */
+
+typedef struct {
+ WORD wType; /* type style */
+ WORD wWidth; /* suggested width */
+ WORD wHeight; /* suggested height */
+ DWORD dwStyle; /* default style */
+ char szDescr[CTLDESCR]; /* menu name */
+} CTLTYPE;
+
+typedef struct {
+ WORD wVersion; /* control version */
+ WORD 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 dialog editor */
+typedef DWORD (FAR PASCAL *LPFNSTRTOID)( LPSTR );
+typedef WORD (FAR PASCAL *LPFNIDTOSTR)( WORD, LPSTR, WORD );
+
diff --git a/private/os2/client/thunk/include/dde.h b/private/os2/client/thunk/include/dde.h
new file mode 100644
index 000000000..a131ccdc1
--- /dev/null
+++ b/private/os2/client/thunk/include/dde.h
@@ -0,0 +1,115 @@
+
+/* 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 {
+ unsigned bAppReturnCode:8,
+ reserved:6,
+ fBusy:1,
+ fAck:1;
+} DDEACK;
+
+
+/*----------------------------------------------------------------------------
+| DDEADVISE structure
+|
+| WM_DDE_ADVISE parameter structure for hOptions (LOWORD(lParam))
+|
+----------------------------------------------------------------------------*/
+
+typedef struct {
+ unsigned reserved:14,
+ fDeferUpd:1,
+ fAckReq:1;
+ int 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 {
+ unsigned unused:12,
+ fResponse:1,
+ fRelease:1,
+ reserved:1,
+ fAckReq:1;
+ int 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 {
+ unsigned unused:13, /* Earlier versions of DDE.H incorrectly */
+ /* 12 unused bits. */
+ fRelease:1,
+ fReserved:2;
+ int 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 {
+ unsigned unused:13,
+ fRelease:1,
+ fDeferUpd:1,
+ fAckReq:1;
+ int cfFormat;
+} DDELN;
+
+typedef struct {
+ unsigned unused:12,
+ fAck:1,
+ fRelease:1,
+ fReserved:1,
+ fAckReq:1;
+ int cfFormat;
+ BYTE rgb[1];
+} DDEUP;
+
diff --git a/private/os2/client/thunk/include/debug.inc b/private/os2/client/thunk/include/debug.inc
new file mode 100644
index 000000000..3066877d2
--- /dev/null
+++ b/private/os2/client/thunk/include/debug.inc
@@ -0,0 +1,274 @@
+;******************************************************************************
+;
+; (C) Copyright MICROSOFT Corp. 1989-1990
+;
+;******************************************************************************
+
+;******************************************************************************
+;
+; Assumes_Fall_Through
+;
+; DESCRIPTION:
+; Used for debugging purposes only. It will generate an error if
+; the IP <> the specified label.
+;
+; PARAMETERS:
+; Label_Name = Name of label to fall-through to
+;
+;------------------------------------------------------------------------------
+
+Assumes_Fall_Through MACRO L
+IF2
+IF (L - $) GT 3
+%OUT ERROR: Fall through to &L invalid
+.ERR
+ENDIF
+ENDIF
+ ENDM
+
+
+;******************************************************************************
+;
+; Assert_VM_Handle
+;
+; PARAMETERS:
+; Handle_Register = Register that contains a VM handle
+;
+; ASSUMES:
+; Debug_Test_Valid_Handle does not destroy any registers or flags
+;
+; EXIT:
+; NOTHING MODIFIED (not even flags)
+;
+;------------------------------------------------------------------------------
+
+Assert_VM_Handle MACRO R
+IFDEF DEBUG
+ push ebx
+ mov ebx, R
+ VMMcall Debug_Test_Valid_Handle
+ pop ebx
+ENDIF
+ ENDM
+
+
+
+
+;******************************************************************************
+;
+; Trace_Out
+;
+;------------------------------------------------------------------------------
+
+Trace_Out MACRO S, nocrlf
+ LOCAL Str_Off
+IFDEF DEBUG
+_LDATA SEGMENT
+Str_Off db S
+IFB <nocrlf>
+ db 0Ah,0Dh
+ENDIF
+ db 0
+_LDATA ENDS
+
+ pushfd
+ pushad
+ mov esi, OFFSET32 Str_Off
+ VMMcall Out_Debug_String
+ popad
+ popfd
+ENDIF
+ ENDM
+
+
+;******************************************************************************
+;
+; Debug_Out
+;
+;------------------------------------------------------------------------------
+
+Debug_Out MACRO S
+ LOCAL Skip_Int1
+IFDEF DEBUG
+ pushfd
+ Trace_Out <S>
+ VMMcall Test_Debug_Installed
+ jz SHORT Skip_Int1
+ int 1
+Skip_Int1:
+ popfd
+ENDIF
+ ENDM
+
+
+;******************************************************************************
+;
+; Queue_Out
+;
+;------------------------------------------------------------------------------
+
+Queue_Out MACRO S, V1, V2
+ LOCAL Str_Off
+IFDEF DEBUG
+
+_LDATA SEGMENT
+Str_Off db S, 0Ah,0Dh, 0
+_LDATA ENDS
+
+ pushfd
+ push esi
+IFNB <V1>
+ IF TYPE V1 GT 0
+ push dword ptr V1
+ ELSE
+ push V1
+ ENDIF
+ELSE
+ push eax ; dummy value1
+ENDIF
+IFNB <V2>
+ IF TYPE V2 GT 0
+ push dword ptr V2
+ ELSE
+ push V2
+ ENDIF
+ELSE
+ push ebx ; dummy value2
+ENDIF
+ mov esi, OFFSET32 Str_Off
+ VMMcall Queue_Debug_String
+ pop esi
+ popfd
+ENDIF
+ ENDM
+
+
+
+
+
+
+;******************************************************************************
+;
+; Assert_Ints_Disabled
+;
+;------------------------------------------------------------------------------
+
+Assert_Ints_Disabled MACRO
+ LOCAL OK
+
+IFDEF DEBUG
+ pushfd
+ test WORD PTR [esp], IF_Mask
+ jz SHORT OK
+ Debug_Out "ERROR: Ints enabled at Assert_Ints_Disabled"
+ Fatal_Error
+OK:
+ popfd
+ENDIF
+
+ ENDM
+
+
+;******************************************************************************
+;
+; Assert_Ints_Enabled
+;
+;------------------------------------------------------------------------------
+
+Assert_Ints_Enabled MACRO
+ LOCAL OK
+
+IFDEF DEBUG
+ pushfd
+ test WORD PTR [esp], IF_Mask
+ jnz SHORT OK
+ Debug_Out "ERROR: Ints disabled at Assert_Ints_Enabled"
+ Fatal_Error
+OK:
+ popfd
+ENDIF
+
+ ENDM
+
+
+;******************************************************************************
+;
+; Assert_Cur_VM_Handle (Register)
+;
+; DESCRIPTION:
+;
+; ENTRY:
+;
+; EXIT:
+;
+; USES:
+;
+;==============================================================================
+
+Assert_Cur_VM_Handle MACRO R
+ LOCAL OK
+IFDEF DEBUG
+ push ebx
+ mov ebx, R
+ VMMcall Debug_Test_Cur_VM
+ pop ebx
+ENDIF
+ ENDM
+
+
+
+
+Assert_Client_Ptr MACRO Reg
+
+IFDEF DEBUG
+ push ebp
+ mov ebp, Reg
+ VMMcall Validate_Client_Ptr
+ pop ebp
+ENDIF
+
+ ENDM
+
+
+
+
+;******************************************************************************
+
+
+Dump_Struc_Head MACRO
+IFDEF DEBUG
+ Trace_Out " Base Address Offs Value Field name"
+ENDIF
+ ENDM
+
+Dump_Struc MACRO Base, X
+IFDEF DEBUG
+ pushfd
+ pushad
+ lea esi, [Base]
+ mov ecx, X
+ lea edx, [esi+ecx]
+
+IF SIZE X EQ 6
+ mov bx, WORD PTR [edx+4]
+ mov eax, DWORD PTR [edx]
+ Trace_Out "#ESI #EDX #CX #BX:#EAX &X"
+ELSE
+IF SIZE X EQ 4
+ mov eax, DWORD PTR [edx]
+ Trace_Out "#ESI #EDX #CX #EAX &X"
+ELSE
+IF SIZE X EQ 2
+ mov ax, WORD PTR [edx]
+ Trace_Out "#ESI #EDX #CX #AX &X"
+ELSE
+ mov al, BYTE PTR [edx]
+ Trace_Out "#ESI #EDX #CX #AL &X"
+ENDIF
+ENDIF
+ENDIF
+
+ popad
+ popfd
+ENDIF
+ ENDM
diff --git a/private/os2/client/thunk/include/debugsys.inc b/private/os2/client/thunk/include/debugsys.inc
new file mode 100644
index 000000000..ff25b708c
--- /dev/null
+++ b/private/os2/client/thunk/include/debugsys.inc
@@ -0,0 +1,442 @@
+;******************************************************************************
+;
+; (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_Identify equ 43h ; returns debugger identification, if debugger
+ ; loaded
+D386_Id equ 0F386h
+
+
+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_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 & selector
+ ; 41h - data segment & selector
+ ; 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_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.
+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
+
+;
+; common services
+;
+
+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
+
+
+;
+; services available only through Debug_Serv_Int for non-ring 0 clients
+;
+
+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_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: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.
+ ; 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
+
+;
+; services available only through Debug_Ring0_Serv_Int for ring 0 clients
+;
+
+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
+
+;
+; 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 0, of
+ ; INT 46h & func 47h 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_CRO 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 ?
+SaveRegs_Struc ENDS
diff --git a/private/os2/client/thunk/include/direct.h b/private/os2/client/thunk/include/direct.h
new file mode 100644
index 000000000..694c632d8
--- /dev/null
+++ b/private/os2/client/thunk/include/direct.h
@@ -0,0 +1,36 @@
+/***
+*direct.h - function declarations for directory handling/creation
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This include file contains the function declarations for the library
+* functions related to directory handling and creation.
+*
+****/
+
+#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 */
+
+int _FAR_ _cdecl chdir(const char _FAR_ *);
+int _FAR_ _cdecl _chdrive(int);
+char _FAR_ * _FAR_ _cdecl getcwd(char _FAR_ *, int);
+char _FAR_ * _FAR_ _cdecl _getdcwd(int, char _FAR_ *, int);
+int _FAR_ _cdecl _getdrive(void);
+int _FAR_ _cdecl mkdir(const char _FAR_ *);
+int _FAR_ _cdecl rmdir(const char _FAR_ *);
diff --git a/private/os2/client/thunk/include/dos.h b/private/os2/client/thunk/include/dos.h
new file mode 100644
index 000000000..029bb3559
--- /dev/null
+++ b/private/os2/client/thunk/include/dos.h
@@ -0,0 +1,209 @@
+/***
+*dos.h - definitions for MS-DOS interface routines
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Defines the structs and unions used for the direct DOS interface
+* routines; includes macros to access the segment and offset
+* values of far pointers, so that they may be used by the routines; and
+* provides function prototypes for direct DOS interface functions.
+*
+****/
+
+
+#ifndef _REGS_DEFINED
+
+/* word registers */
+
+struct WORDREGS {
+ unsigned int ax;
+ unsigned int bx;
+ unsigned int cx;
+ unsigned int dx;
+ unsigned int si;
+ unsigned int di;
+ unsigned int cflag;
+ };
+
+
+/* byte registers */
+
+struct BYTEREGS {
+ unsigned char al, ah;
+ unsigned char bl, bh;
+ unsigned char cl, ch;
+ unsigned char dl, dh;
+ };
+
+
+/* general purpose registers union -
+ * overlays the corresponding word and byte registers.
+ */
+
+union REGS {
+ struct WORDREGS x;
+ struct BYTEREGS h;
+ };
+
+
+/* segment registers */
+
+struct SREGS {
+ unsigned int es;
+ unsigned int cs;
+ unsigned int ss;
+ unsigned int ds;
+ };
+
+#define _REGS_DEFINED
+
+#endif
+
+
+/* dosexterror structure */
+
+#ifndef _DOSERROR_DEFINED
+
+struct DOSERROR {
+ int exterror;
+ char class;
+ char action;
+ char locus;
+ };
+
+#define _DOSERROR_DEFINED
+
+#endif
+
+
+/* _dos_findfirst structure */
+
+#ifndef _FIND_T_DEFINED
+
+struct find_t {
+ char reserved[21];
+ char attrib;
+ unsigned wr_time;
+ unsigned wr_date;
+ long size;
+ char name[13];
+ };
+
+#define _FIND_T_DEFINED
+
+#endif
+
+
+/* _dos_getdate/_dossetdate and _dos_gettime/_dos_settime structures */
+
+#ifndef _DATETIME_T_DEFINED
+
+struct dosdate_t {
+ unsigned char day; /* 1-31 */
+ unsigned char month; /* 1-12 */
+ unsigned int year; /* 1980-2099 */
+ unsigned char dayofweek; /* 0-6, 0=Sunday */
+ };
+
+struct dostime_t {
+ unsigned char hour; /* 0-23 */
+ unsigned char minute; /* 0-59 */
+ unsigned char second; /* 0-59 */
+ unsigned char hsecond; /* 0-99 */
+ };
+
+#define _DATETIME_T_DEFINED
+
+#endif
+
+
+/* _dos_getdiskfree structure */
+
+#ifndef _DISKFREE_T_DEFINED
+
+struct diskfree_t {
+ unsigned total_clusters;
+ unsigned avail_clusters;
+ unsigned sectors_per_cluster;
+ unsigned bytes_per_sector;
+ };
+
+#define _DISKFREE_T_DEFINED
+
+#endif
+
+
+/* manifest constants for _hardresume result parameter */
+
+#define _HARDERR_IGNORE 0 /* Ignore the error */
+#define _HARDERR_RETRY 1 /* Retry the operation */
+#define _HARDERR_ABORT 2 /* Abort program issuing Interrupt 23h */
+#define _HARDERR_FAIL 3 /* Fail the system call in progress */
+ /* _HARDERR_FAIL is not supported on DOS 2.x */
+
+/* File attribute constants */
+
+#define _A_NORMAL 0x00 /* Normal file - No read/write restrictions */
+#define _A_RDONLY 0x01 /* Read only file */
+#define _A_HIDDEN 0x02 /* Hidden file */
+#define _A_SYSTEM 0x04 /* System file */
+#define _A_VOLID 0x08 /* Volume ID file */
+#define _A_SUBDIR 0x10 /* Subdirectory */
+#define _A_ARCH 0x20 /* Archive file */
+
+/* macros to break C "far" pointers into their segment and offset components
+ */
+
+#define FP_SEG(fp) (*((unsigned _far *)&(fp)+1))
+#define FP_OFF(fp) (*((unsigned _far *)&(fp)))
+
+
+/* external variable declarations */
+
+extern unsigned int _near _cdecl _osversion;
+
+
+/* function prototypes */
+
+#ifndef _MT
+int _cdecl bdos(int, unsigned int, unsigned int);
+void _cdecl _chain_intr(void (_cdecl _interrupt _far *)());
+void _cdecl _disable(void);
+unsigned _cdecl _dos_allocmem(unsigned, unsigned *);
+unsigned _cdecl _dos_close(int);
+unsigned _cdecl _dos_creat(const char *, unsigned, int *);
+unsigned _cdecl _dos_creatnew(const char *, unsigned, int *);
+unsigned _cdecl _dos_findfirst(const char *, unsigned, struct find_t *);
+unsigned _cdecl _dos_findnext(struct find_t *);
+unsigned _cdecl _dos_freemem(unsigned);
+void _cdecl _dos_getdate(struct dosdate_t *);
+void _cdecl _dos_getdrive(unsigned *);
+unsigned _cdecl _dos_getdiskfree(unsigned, struct diskfree_t *);
+unsigned _cdecl _dos_getfileattr(const char *, unsigned *);
+unsigned _cdecl _dos_getftime(int, unsigned *, unsigned *);
+void _cdecl _dos_gettime(struct dostime_t *);
+void (_cdecl _interrupt _far * _cdecl _dos_getvect(unsigned))();
+void _cdecl _dos_keep(unsigned, unsigned);
+unsigned _cdecl _dos_open(const char *, unsigned, int *);
+unsigned _cdecl _dos_read(int, void _far *, unsigned, unsigned *);
+unsigned _cdecl _dos_setblock(unsigned, unsigned, unsigned *);
+unsigned _cdecl _dos_setdate(struct dosdate_t *);
+void _cdecl _dos_setdrive(unsigned, unsigned *);
+unsigned _cdecl _dos_setfileattr(const char *, unsigned);
+unsigned _cdecl _dos_setftime(int, unsigned, unsigned);
+unsigned _cdecl _dos_settime(struct dostime_t *);
+void _cdecl _dos_setvect(unsigned, void (_cdecl _interrupt _far *)());
+unsigned _cdecl _dos_write(int, const void _far *, unsigned, unsigned *);
+int _cdecl dosexterr(struct DOSERROR *);
+void _cdecl _enable(void);
+void _cdecl _harderr(void (_far *)());
+void _cdecl _hardresume(int);
+void _cdecl _hardretn(int);
+int _cdecl intdos(union REGS *, union REGS *);
+int _cdecl intdosx(union REGS *, union REGS *, struct SREGS *);
+int _cdecl int86(int, union REGS *, union REGS *);
+int _cdecl int86x(int, union REGS *, union REGS *, struct SREGS *);
+#endif /* _MT */
+
+void _cdecl segread(struct SREGS *);
diff --git a/private/os2/client/thunk/include/dosx.inc b/private/os2/client/thunk/include/dosx.inc
new file mode 100644
index 000000000..4fab86669
--- /dev/null
+++ b/private/os2/client/thunk/include/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/os2/client/thunk/include/drivinit.h b/private/os2/client/thunk/include/drivinit.h
new file mode 100644
index 000000000..fb634e06a
--- /dev/null
+++ b/private/os2/client/thunk/include/drivinit.h
@@ -0,0 +1,157 @@
+/*
+ * drivinit.h
+ *
+ * Header file for printer driver initialization using ExtDeviceModeEx()
+ * and DeviceCapabilitiesEx().
+ *
+ */
+
+/* size of a device name string */
+#define CCHDEVICENAME 32
+
+/* current version of specification */
+#define DM_SPECVERSION 0x300
+
+/* 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
+
+/* orientation selections */
+#define DMORIENT_PORTRAIT 1
+#define DMORIENT_LANDSCAPE 2
+
+/* paper selections */
+#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/2 x 10 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_LAST DMPAPER_ESHEET
+
+#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
+
+typedef struct _devicemode {
+ char dmDeviceName[CCHDEVICENAME];
+ WORD dmSpecVersion;
+ WORD dmDriverVersion;
+ WORD dmSize;
+ WORD dmDriverExtra;
+ DWORD dmFields;
+ short dmOrientation;
+ short dmPaperSize;
+ short dmPaperLength;
+ short dmPaperWidth;
+ short dmScale;
+ short dmCopies;
+ short dmDefaultSource;
+ short dmPrintQuality;
+ short dmColor;
+ short dmDuplex;
+} 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
+
+/* export ordinal definitions */
+#define PROC_EXTDEVICEMODE MAKEINTRESOURCE(90)
+#define PROC_DEVICECAPABILITIES MAKEINTRESOURCE(91)
+#define PROC_OLDDEVICEMODE MAKEINTRESOURCE(13)
+
+/* define types of pointers to ExtDeviceModeEx() and DeviceCapabilitiesEx()
+ * functions
+ */
+typedef WORD FAR PASCAL FNDEVMODE(HWND, HANDLE, LPDEVMODE, LPSTR, LPSTR,
+ LPDEVMODE, LPSTR, WORD);
+
+typedef FNDEVMODE FAR * LPFNDEVMODE;
+
+typedef DWORD FAR PASCAL FNDEVCAPS(LPSTR, LPSTR, WORD, LPSTR, LPDEVMODE);
+
+typedef FNDEVCAPS FAR * LPFNDEVCAPS;
diff --git a/private/os2/client/thunk/include/errno.h b/private/os2/client/thunk/include/errno.h
new file mode 100644
index 000000000..59af54c60
--- /dev/null
+++ b/private/os2/client/thunk/include/errno.h
@@ -0,0 +1,71 @@
+/***
+*errno.h - system wide error numbers (set by system calls)
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file defines the system-wide error numbers (set by
+* system calls). Conforms to the XENIX standard. Extended
+* for compatibility with Uniforum standard.
+* [ANSI/System V]
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+/* declare reference to errno */
+
+#ifdef _MT
+extern int _far * _cdecl _far volatile _errno(void);
+#define errno (*_errno())
+#else
+extern int _near _cdecl volatile errno;
+#endif
+
+/* Error Codes */
+
+#define EZERO 0
+#define EPERM 1
+#define ENOENT 2
+#define ESRCH 3
+#define EINTR 4
+#define EIO 5
+#define ENXIO 6
+#define E2BIG 7
+#define ENOEXEC 8
+#define EBADF 9
+#define ECHILD 10
+#define EAGAIN 11
+#define ENOMEM 12
+#define EACCES 13
+#define EFAULT 14
+#define ENOTBLK 15
+#define EBUSY 16
+#define EEXIST 17
+#define EXDEV 18
+#define ENODEV 19
+#define ENOTDIR 20
+#define EISDIR 21
+#define EINVAL 22
+#define ENFILE 23
+#define EMFILE 24
+#define ENOTTY 25
+#define ETXTBSY 26
+#define EFBIG 27
+#define ENOSPC 28
+#define ESPIPE 29
+#define EROFS 30
+#define EMLINK 31
+#define EPIPE 32
+#define EDOM 33
+#define ERANGE 34
+#define EUCLEAN 35
+#define EDEADLOCK 36
diff --git a/private/os2/client/thunk/include/exe386.h b/private/os2/client/thunk/include/exe386.h
new file mode 100644
index 000000000..25bb998da
--- /dev/null
+++ b/private/os2/client/thunk/include/exe386.h
@@ -0,0 +1,603 @@
+/*static char *SCCSID = "@(#)exe386.h 13.14 90/04/17";*/
+
+/*
+ * Title
+ *
+ * exe386.h
+ * Wieslaw Kalkus
+ * (C) Copyright Microsoft Corp 1988
+ * 5 August 1988
+ *
+ * Description
+ *
+ * Data structure definitions for the OS/2
+ * executable file format (flat model).
+ *
+ * Modification History
+ *
+ * 88/08/05 Wieslaw Kalkus Initial version
+ */
+
+
+
+ /*_________________________________________________________________*
+ | |
+ | |
+ | OS/2 .EXE FILE HEADER DEFINITION - 386 version 0:32 |
+ | |
+ |_________________________________________________________________|
+ * */
+
+
+#define BITPERWORD 16
+#define BITPERBYTE 8
+#define OBJPAGELEN 4096
+#define E32MAGIC1 'L' /* New magic number "LE" */
+#define E32MAGIC2 'E' /* New magic number "LE" */
+#define E32MAGIC 0x454c /* New magic number "LE" */
+#define E32RESBYTES1 0 /* First bytes reserved */
+#define E32RESBYTES2 0 /* Second bytes reserved */
+#define E32RESBYTES3 24 /* Third bytes reserved */
+#define E32LEBO 0x00 /* Little Endian Byte Order */
+#define E32BEBO 0x01 /* Big Endian Byte Order */
+#define E32LEWO 0x00 /* Little Endian Word Order */
+#define E32BEWO 0x01 /* Big Endian Word Order */
+#define E32LEVEL 0L /* 32-bit EXE format level */
+#define E32CPU286 0x001 /* Intel 80286 or upwardly compatibile */
+#define E32CPU386 0x002 /* Intel 80386 or upwardly compatibile */
+#define E32CPU486 0x003 /* Intel 80486 or upwardly compatibile */
+
+
+
+struct e32_exe /* New 32-bit .EXE header */
+{
+ unsigned char e32_magic[2]; /* Magic number E32_MAGIC */
+ unsigned char e32_border; /* The byte ordering for the .EXE */
+ unsigned char e32_worder; /* The word ordering for the .EXE */
+ unsigned long e32_level; /* The EXE format level for now = 0 */
+ unsigned short e32_cpu; /* The CPU type */
+ unsigned short e32_os; /* The OS type */
+ unsigned long e32_ver; /* Module version */
+ unsigned long e32_mflags; /* Module flags */
+ unsigned long e32_mpages; /* Module # pages */
+ unsigned long e32_startobj; /* Object # for instruction pointer */
+ unsigned long e32_eip; /* Extended instruction pointer */
+ unsigned long e32_stackobj; /* Object # for stack pointer */
+ unsigned long e32_esp; /* Extended stack pointer */
+ unsigned long e32_pagesize; /* .EXE page size */
+ unsigned long e32_lastpagesize;/* Last page size in .EXE */
+ unsigned long e32_fixupsize; /* Fixup section size */
+ unsigned long e32_fixupsum; /* Fixup section checksum */
+ unsigned long e32_ldrsize; /* Loader section size */
+ unsigned long e32_ldrsum; /* Loader section checksum */
+ unsigned long e32_objtab; /* Object table offset */
+ unsigned long e32_objcnt; /* Number of objects in module */
+ unsigned long e32_objmap; /* Object page map offset */
+ unsigned long e32_itermap; /* Object iterated data map offset */
+ unsigned long e32_rsrctab; /* Offset of Resource Table */
+ unsigned long e32_rsrccnt; /* Number of resource entries */
+ unsigned long e32_restab; /* Offset of resident name table */
+ unsigned long e32_enttab; /* Offset of Entry Table */
+ unsigned long e32_dirtab; /* Offset of Module Directive Table */
+ unsigned long e32_dircnt; /* Number of module directives */
+ unsigned long e32_fpagetab; /* Offset of Fixup Page Table */
+ unsigned long e32_frectab; /* Offset of Fixup Record Table */
+ unsigned long e32_impmod; /* Offset of Import Module Name Table */
+ unsigned long e32_impmodcnt; /* Number of entries in Import Module Name Table */
+ unsigned long e32_impproc; /* Offset of Import Procedure Name Table */
+ unsigned long e32_pagesum; /* Offset of Per-Page Checksum Table */
+ unsigned long e32_datapage; /* Offset of Enumerated Data Pages */
+ unsigned long e32_preload; /* Number of preload pages */
+ unsigned long e32_nrestab; /* Offset of Non-resident Names Table */
+ unsigned long e32_cbnrestab; /* Size of Non-resident Name Table */
+ unsigned long e32_nressum; /* Non-resident Name Table Checksum */
+ unsigned long e32_autodata; /* Object # for automatic data object */
+ unsigned long e32_debuginfo; /* Offset of the debugging information */
+ unsigned long e32_debuglen; /* The length of the debugging info. in bytes */
+ unsigned long e32_instpreload;/* Number of instance pages in preload section of .EXE file */
+ unsigned long e32_instdemand; /* Number of instance pages in demand load section of .EXE file */
+ unsigned long e32_heapsize; /* Size of heap - for 16-bit apps */
+ unsigned char e32_res3[E32RESBYTES3];
+ /* Pad structure to 196 bytes */
+ };
+
+
+
+#define E32_MAGIC1(x) (x).e32_magic[0]
+#define E32_MAGIC2(x) (x).e32_magic[1]
+#define E32_BORDER(x) (x).e32_border
+#define E32_WORDER(x) (x).e32_worder
+#define E32_LEVEL(x) (x).e32_level
+#define E32_CPU(x) (x).e32_cpu
+#define E32_OS(x) (x).e32_os
+#define E32_VER(x) (x).e32_ver
+#define E32_MFLAGS(x) (x).e32_mflags
+#define E32_MPAGES(x) (x).e32_mpages
+#define E32_STARTOBJ(x) (x).e32_startobj
+#define E32_EIP(x) (x).e32_eip
+#define E32_STACKOBJ(x) (x).e32_stackobj
+#define E32_ESP(x) (x).e32_esp
+#define E32_PAGESIZE(x) (x).e32_pagesize
+#define E32_LASTPAGESIZE(x) (x).e32_lastpagesize
+#define E32_FIXUPSIZE(x) (x).e32_fixupsize
+#define E32_FIXUPSUM(x) (x).e32_fixupsum
+#define E32_LDRSIZE(x) (x).e32_ldrsize
+#define E32_LDRSUM(x) (x).e32_ldrsum
+#define E32_OBJTAB(x) (x).e32_objtab
+#define E32_OBJCNT(x) (x).e32_objcnt
+#define E32_OBJMAP(x) (x).e32_objmap
+#define E32_ITERMAP(x) (x).e32_itermap
+#define E32_RSRCTAB(x) (x).e32_rsrctab
+#define E32_RSRCCNT(x) (x).e32_rsrccnt
+#define E32_RESTAB(x) (x).e32_restab
+#define E32_ENTTAB(x) (x).e32_enttab
+#define E32_DIRTAB(x) (x).e32_dirtab
+#define E32_DIRCNT(x) (x).e32_dircnt
+#define E32_FPAGETAB(x) (x).e32_fpagetab
+#define E32_FRECTAB(x) (x).e32_frectab
+#define E32_IMPMOD(x) (x).e32_impmod
+#define E32_IMPMODCNT(x) (x).e32_impmodcnt
+#define E32_IMPPROC(x) (x).e32_impproc
+#define E32_PAGESUM(x) (x).e32_pagesum
+#define E32_DATAPAGE(x) (x).e32_datapage
+#define E32_PRELOAD(x) (x).e32_preload
+#define E32_NRESTAB(x) (x).e32_nrestab
+#define E32_CBNRESTAB(x) (x).e32_cbnrestab
+#define E32_NRESSUM(x) (x).e32_nressum
+#define E32_AUTODATA(x) (x).e32_autodata
+#define E32_DEBUGINFO(x) (x).e32_debuginfo
+#define E32_DEBUGLEN(x) (x).e32_debuglen
+#define E32_INSTPRELOAD(x) (x).e32_instpreload
+#define E32_INSTDEMAND(x) (x).e32_instdemand
+#define E32_HEAPSIZE(x) (x).e32_heapsize
+
+
+
+/*
+ * Format of E32_MFLAGS(x):
+ *
+ * Low word has the following format:
+ *
+ * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - bit no
+ * | | | | | | | |
+ * | | | | | | | +------- Per-Process Library Initialization
+ * | | | | | | +----------- No Internal Fixups for Module in .EXE
+ * | | | | | +------------- No External Fixups for Module in .EXE
+ * | | | | +------------------- Incompatible with PM Windowing
+ * | | | +--------------------- Compatible with PM Windowing
+ * | | +----------------------- Uses PM Windowing API
+ * | +-------------------------------- Module not Loadable
+ * +-------------------------------------- Library Module
+ */
+
+
+#define E32NOTP 0x8000L /* Library Module - used as NENOTP */
+#define E32NOLOAD 0x2000L /* Module not Loadable */
+#define E32PMAPI 0x0300L /* Uses PM Windowing API */
+#define E32PMW 0x0200L /* Compatible with PM Windowing */
+#define E32NOPMW 0x0100L /* Incompatible with PM Windowing */
+#define E32NOEXTFIX 0x0020L /* NO External Fixups in .EXE */
+#define E32NOINTFIX 0x0010L /* NO Internal Fixups in .EXE */
+#define E32LIBINIT 0x0004L /* Per-Process Library Initialization */
+#define E32APPMASK 0x0700L /* Aplication Type Mask */
+
+
+/*
+ * Format of E32_MFLAGS(x):
+ *
+ * High word has the following format:
+ *
+ * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - bit no
+ * | |
+ * | +--- Protected memory library module
+ * +----- Device driver
+ */
+
+#define E32PROTDLL 0x10000L // Protected memory library module
+#define E32DEVICE 0x20000L // Device driver
+#define E32MODEXE 0x00000L // .EXE module
+#define E32MODDLL 0x08000L // .DLL module
+#define E32MODPROTDLL 0x18000L // Protected memory library module
+#define E32MODPDEV 0x20000L // Physical device driver
+#define E32MODVDEV 0x28000L // Virtual device driver
+#define E32MODMASK 0x38000L // Module type mask
+
+/*
+ * RELOCATION DEFINITIONS - RUN-TIME FIXUPS
+ */
+
+
+#pragma pack(1) /* This data must be packed */
+
+
+typedef union _offset
+{
+ unsigned short offset16;
+ unsigned long offset32;
+}
+ offset; /* 16-bit or 32-bit offset */
+
+
+/***ET+ r32_rlc - Relocation item */
+
+struct r32_rlc /* Relocation item */
+{
+ unsigned char nr_stype; /* Source type - field shared with new_rlc */
+ unsigned char nr_flags; /* Flag byte - field shared with new_rlc */
+ short r32_soff; /* Source offset */
+ unsigned short r32_objmod; /* Target object number or Module ordinal */
+
+ union targetid
+ {
+ offset intref; /* Internal fixup */
+
+ union extfixup
+ {
+ offset proc; /* Procedure name offset */
+ unsigned long ord; /* Procedure odrinal */
+ }
+ extref; /* External fixup */
+
+ struct addfixup
+ {
+ unsigned short entry; /* Entry ordinal */
+ offset addval; /* Value added to the address */
+ }
+ addfix; /* Additive fixup */
+ }
+ r32_target; /* Target data */
+ unsigned short r32_srccount; /* Number of chained fixup records */
+ unsigned short r32_chain; /* Chain head */
+};
+
+
+#pragma pack() /* Stop packing */
+
+
+/*
+ * In 32-bit .EXE file run-time relocations are written as varying size
+ * records, so we need many size definitions.
+ */
+
+#define RINTSIZE16 8
+#define RINTSIZE32 10
+#define RORDSIZE 8
+#define RNAMSIZE16 8
+#define RNAMSIZE32 10
+#define RADDSIZE16 10
+#define RADDSIZE32 12
+
+
+
+#if FALSE
+/*
+ * Access macros defined in NEWEXE.H !!!
+ */
+#define NR_STYPE(x) (x).nr_stype
+#define NR_FLAGS(x) (x).nr_flags
+#endif
+
+#define R32_SOFF(x) (x).r32_soff
+#define R32_OBJNO(x) (x).r32_objmod
+#define R32_MODORD(x) (x).r32_objmod
+#define R32_OFFSET16(x) (x).r32_target.intref.offset16
+#define R32_OFFSET32(x) (x).r32_target.intref.offset32
+#define R32_PROCOFF16(x) (x).r32_target.extref.proc.offset16
+#define R32_PROCOFF32(x) (x).r32_target.extref.proc.offset32
+#define R32_PROCORD(x) (x).r32_target.extref.ord
+#define R32_ENTRY(x) (x).r32_target.addfix.entry
+#define R32_ADDVAL16(x) (x).r32_target.addfix.addval.offset16
+#define R32_ADDVAL32(x) (x).r32_target.addfix.addval.offset32
+#define R32_SRCCNT(x) (x).r32_srccount
+#define R32_CHAIN(x) (x).r32_chain
+
+
+
+/*
+ * Format of NR_STYPE(x)
+ *
+ * 7 6 5 4 3 2 1 0 - bit no
+ * | | | | | |
+ * | | +-+-+-+--- Source type
+ * | +----------- Fixup to 16:16 alias
+ * +------------- List of source offset follows fixup record
+ */
+
+#if FALSE
+
+ /* DEFINED in newexe.h !!! */
+
+#define NRSTYP 0x0f /* Source type mask */
+#define NRSBYT 0x00 /* lo byte (8-bits)*/
+#define NRSSEG 0x02 /* 16-bit segment (16-bits) */
+#define NRSPTR 0x03 /* 16:16 pointer (32-bits) */
+#define NRSOFF 0x05 /* 16-bit offset (16-bits) */
+#define NRPTR48 0x06 /* 16:32 pointer (48-bits) */
+#define NROFF32 0x07 /* 32-bit offset (32-bits) */
+#define NRSOFF32 0x08 /* 32-bit self-relative offset (32-bits) */
+#endif
+
+
+#define NRSRCMASK 0x0f /* Source type mask */
+#define NRALIAS 0x10 /* Fixup to alias */
+#define NRCHAIN 0x20 /* List of source offset follows */
+ /* fixup record, source offset field */
+ /* in fixup record contains number */
+ /* of elements in list */
+
+/*
+ * Format of NR_FLAGS(x) and R32_FLAGS(x):
+ *
+ * 7 6 5 4 3 2 1 0 - bit no
+ * | | | | | | |
+ * | | | | | +-+--- Reference type
+ * | | | | +------- Additive fixup
+ * | | | +----------- 32-bit Target Offset Flag (1 - 32-bit; 0 - 16-bit)
+ * | | +------------- 32-bit Additive Flag (1 - 32-bit; 0 - 16-bit)
+ * | +--------------- 16-bit Object/Module ordinal (1 - 16-bit; 0 - 8-bit)
+ * +----------------- 8-bit import ordinal (1 - 8-bit;
+ * 0 - NR32BITOFF toggles
+ * between 16 and 32 bit
+ * ordinal)
+ */
+
+#if FALSE
+
+ /* DEFINED in newexe.h !!! */
+
+#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 */
+#endif
+
+#define NRRENT 0x03 /* Internal entry table fixup */
+
+#define NR32BITOFF 0x10 /* 32-bit Target Offset */
+#define NR32BITADD 0x20 /* 32-bit Additive fixup */
+#define NR16OBJMOD 0x40 /* 16-bit Object/Module ordinal */
+#define NR8BITORD 0x80 /* 8-bit import ordinal */
+/*end*/
+
+/*
+ * Data structures for storing run-time fixups in linker virtual memory.
+ *
+ * Each object has a list of Object Page Directories which specify
+ * fixups for given page. Each page has its own hash table which is
+ * used to detect fixups to the same target.
+ */
+
+#define PAGEPERDIR 62
+#define LG2DIR 7
+
+
+typedef struct _OBJPAGEDIR
+{
+ unsigned long next; /* Virtual pointer to next dir on list */
+ unsigned short ht[PAGEPERDIR]; /* Pointers to individual hash tables */
+}
+ OBJPAGEDIR;
+
+
+
+/*
+ * OBJECT TABLE
+ */
+
+/***ET+ o32_obj Object Table Entry */
+
+struct o32_obj /* Flat .EXE object table entry */
+{
+ unsigned long o32_size; /* Object virtual size */
+ unsigned long o32_base; /* Object base virtual address */
+ unsigned long o32_flags; /* Attribute flags */
+ unsigned long o32_pagemap; /* Object page map index */
+ unsigned long o32_mapsize; /* Number of entries in object page map */
+ unsigned long o32_reserved; /* Reserved */
+};
+
+
+#define O32_SIZE(x) (x).o32_size
+#define O32_BASE(x) (x).o32_base
+#define O32_FLAGS(x) (x).o32_flags
+#define O32_PAGEMAP(x) (x).o32_pagemap
+#define O32_MAPSIZE(x) (x).o32_mapsize
+#define O32_RESERVED(x) (x).o32_reserved
+
+
+
+/*
+ * Format of O32_FLAGS(x)
+ *
+ * High word of dword flag field is not used for now.
+ * Low word has the following format:
+ *
+ * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - bit no
+ * | | | | | | | | | | | | | | |
+ * | | | | | | | | | | | | | | +--- Readable Object
+ * | | | | | | | | | | | | | +----- Writeable Object
+ * | | | | | | | | | | | | +------- Executable Object
+ * | | | | | | | | | | | +--------- Resource Object
+ * | | | | | | | | | | +----------- Object is Discardable
+ * | | | | | | | | | +------------- Object is Shared
+ * | | | | | | | | +--------------- Object has preload pages
+ * | | | | | | | +----------------- Object has invalid pages
+ * | | | | | | +------------------- Object is permanent and swappable
+ * | | | | | +--------------------- Object is permanent and resident
+ * | | | | +----------------------- Object is permanent and long lockable
+ * | | | +----------------------------- 16:16 alias required (80x86 specific)
+ * | | +-------------------------------- Big/Default bit setting (80x86 specific)
+ * | +----------------------------------- Object is conforming for code (80x86 specific)
+ * +-------------------------------------- Object I/O privilege level (80x86 specific)
+ *
+ */
+
+#define OBJREAD 0x0001L /* Readable Object */
+#define OBJWRITE 0x0002L /* Writeable Object */
+#define OBJRSRC 0x0008L /* Resource Object */
+#define OBJINVALID 0x0080L /* Object has invalid pages */
+#define OBJNONPERM 0x0000L /* Object is nonpermanent */
+#define OBJPERM 0x0100L /* Object is permanent and swappable */
+#define OBJRESIDENT 0x0200L /* Object is permanent and resident */
+#define OBJCONTIG 0x0300L /* Object is resident and contiguous */
+#define OBJDYNAMIC 0x0400L /* Object is permanent and long locable */
+#define OBJTYPEMASK 0x0700L /* Object type mask */
+#define OBJALIAS16 0x1000L /* 16:16 alias required (80x86 specific) */
+#define OBJBIGDEF 0x2000L /* Big/Default bit setting (80x86 specific) */
+#define OBJIOPL 0x8000L /* Object I/O privilege level (80x86 specific) */
+#ifdef FOR_EXEHDR
+/*
+ * Name these flags differently for EXEHDR.EXE - avoid conflicts with 286 version
+ */
+#define OBJDISCARD 0x0010L /* Object is Discardable */
+#define OBJSHARED 0x0020L /* Object is Shared */
+#define OBJPRELOAD 0x0040L /* Object has preload pages */
+#define OBJEXEC 0x0004L /* Executable Object */
+#define OBJCONFORM 0x4000L /* Object is conforming for code (80x86 specific) */
+#else
+/*
+ * Life will be easier, if we keep the same names for the following flags:
+ */
+#define NSDISCARD 0x0010L /* Object is Discardable */
+#define NSMOVE NSDISCARD /* Moveable object is for sure Discardable */
+#define NSSHARED 0x0020L /* Object is Shared */
+#define NSPRELOAD 0x0040L /* Object has preload pages */
+#define NSEXRD 0x0004L /* Executable Object */
+#define NSCONFORM 0x4000L /* Object is conforming for code (80x86 specific) */
+#endif
+/*end*/
+
+/***ET+ o32_map - Object Page Map entry */
+
+struct o32_map /* Object Page Map entry */
+{
+ unsigned char o32_pageidx[3]; /* 24-bit page # in .EXE file */
+ unsigned char o32_pageflags; /* Per-Page attributes */
+};
+
+
+#define GETPAGEIDX(x) ((((unsigned long)((x).o32_pageidx[0])) << BITPERWORD) + \
+ (((x).o32_pageidx[1]) << BITPERBYTE) + \
+ (x).o32_pageidx[2])
+
+#define PUTPAGEIDX(x,i) ((x).o32_pageidx[0] = (unsigned char) ((unsigned long)(i) >> BITPERWORD), \
+ (x).o32_pageidx[1] = (unsigned char) ((i) >> BITPERBYTE), \
+ (x).o32_pageidx[2] = (unsigned char) ((i) & 0xff))
+
+#define PAGEFLAGS(x) (x).o32_pageflags
+
+
+#define VALID 0x00 /* Valid Physical Page in .EXE */
+#define ITERDATA 0x01 /* Iterated Data Page */
+#define INVALID 0x02 /* Invalid Page */
+#define ZEROED 0x03 /* Zero Filled Page */
+#define RANGE 0x04 /* Range of pages */
+/*end*/
+
+/*
+ * RESOURCE TABLE
+ */
+
+/***ET+ rsrc32 - Resource Table Entry */
+
+struct rsrc32 /* Resource Table Entry */
+{
+ unsigned short type; /* Resource type */
+ unsigned short name; /* Resource name */
+ unsigned long cb; /* Resource size */
+ unsigned short obj; /* Object number */
+ unsigned long offset; /* Offset within object */
+};
+/*end*/
+
+
+#pragma pack(1) /* This data must be packed */
+
+/*
+ * ENTRY TABLE DEFINITIONS
+ */
+
+/***ET+ b32_bundle - Entry Table */
+
+struct b32_bundle
+{
+ unsigned char b32_cnt; /* Number of entries in this bundle */
+ unsigned char b32_type; /* Bundle type */
+ unsigned short b32_obj; /* Object number */
+}; /* Follows entry types */
+
+struct e32_entry
+{
+ unsigned char e32_flags; /* Entry point flags */
+ union entrykind
+ {
+ offset e32_offset; /* 16-bit/32-bit offset entry */
+ struct callgate
+ {
+ unsigned short offset; /* Offset in segment */
+ unsigned short callgate; /* Callgate selector */
+ }
+ e32_callgate; /* 286 (16-bit) call gate */
+ struct fwd
+ {
+ unsigned short modord; /* Module ordinal number */
+ unsigned long value; /* Proc name offset or ordinal */
+ }
+ e32_fwd; /* Forwarder */
+ }
+ e32_variant; /* Entry variant */
+};
+
+#pragma pack() /* Stop packing */
+
+
+#define B32_CNT(x) (x).b32_cnt
+#define B32_TYPE(x) (x).b32_type
+#define B32_OBJ(x) (x).b32_obj
+
+#define E32_EFLAGS(x) (x).e32_flags
+#define E32_OFFSET16(x) (x).e32_variant.e32_offset.offset16
+#define E32_OFFSET32(x) (x).e32_variant.e32_offset.offset32
+#define E32_GATEOFF(x) (x).e32_variant.e32_callgate.offset
+#define E32_GATE(x) (x).e32_variant.e32_callgate.callgate
+#define E32_MODORD(x) (x).e32_variant.e32_fwd.modord
+#define E32_VALUE(x) (x).e32_variant.e32_fwd.value
+
+#define FIXENT16 3
+#define FIXENT32 5
+#define GATEENT16 5
+#define FWDENT 7
+
+/*
+ * BUNDLE TYPES
+ */
+
+#define EMPTY 0x00 /* Empty bundle */
+#define ENTRY16 0x01 /* 16-bit offset entry point */
+#define GATE16 0x02 /* 286 call gate (16-bit IOPL) */
+#define ENTRY32 0x03 /* 32-bit offset entry point */
+#define ENTRYFWD 0x04 /* Forwarder entry point */
+#define TYPEINFO 0x80 /* Typing information present flag */
+
+
+/*
+ * Format for E32_EFLAGS(x)
+ *
+ * 7 6 5 4 3 2 1 0 - bit no
+ * | | | | | | | |
+ * | | | | | | | +--- exported entry
+ * | | | | | | +----- uses shared data
+ * +-+-+-+-+-+------- parameter word count
+ */
+
+#define E32EXPORT 0x01 /* Exported entry */
+#define E32SHARED 0x02 /* Uses shared data */
+#define E32PARAMS 0xf8 /* Parameter word count mask */
+
+/*
+ * Flags for forwarders only:
+ */
+
+#define FWD_ORDINAL 0x01 /* Imported by ordinal */
+/*end*/
diff --git a/private/os2/client/thunk/include/exe386pe.h b/private/os2/client/thunk/include/exe386pe.h
new file mode 100644
index 000000000..1af51c6c7
--- /dev/null
+++ b/private/os2/client/thunk/include/exe386pe.h
@@ -0,0 +1,870 @@
+/*
+ * Title
+ *
+ * exe386.h
+ * (C) Copyright Microsoft Corp 1988-1990
+ *
+ * Description
+ *
+ * Data structure definitions for the OS/2
+ * executable file format (flat model).
+ *
+ * Modification History
+ *
+ * 90/07/30 Wieslaw Kalkus Modified linear-executable
+ * 88/08/05 Wieslaw Kalkus Initial version
+ */
+
+
+
+ /*_________________________________________________________________*
+ | |
+ | |
+ | OS/2 .EXE FILE HEADER DEFINITION - 386 version 0:32 |
+ | |
+ |_________________________________________________________________|
+ * */
+
+#define BITPERBYTE 8 /* Should never change */
+#define BITPERWORD 16 /* I'm not sure about this one */
+#define OBJPAGELEN 4096 /* Memory page size in bytes */
+#define E32RESBYTES1 1 /* First bytes reserved */
+#define E32RESBYTES2 4 /* Second bytes reserved */
+#define E32RESBYTES3 8 /* Third bytes reserved */
+#define E32RESBYTES4 28 /* Forth bytes reserved */
+#define STD_EXTRA 7 /* Standard number of extra information*/
+ /* units palced in the header; this */
+ /* includes the following tables: */
+ /* - export, import, resource, */
+ /* exception, security, fixup and */
+ /* debug information */
+#define EXP 0 /* Export table position */
+#define IMP 1 /* Import table position */
+#define RES 2 /* Resource table position */
+#define EXC 3 /* Exception table position */
+#define SEC 4 /* Security table position */
+#define FIX 5 /* Fixup table position */
+#define DEB 6 /* Debug table position */
+
+struct info /* Extra information header block */
+{
+ unsigned long rva; /* Virtual relative address of info */
+ unsigned long size; /* Size of information block */
+};
+
+
+struct e32_exe /* LE 32-bit .EXE header */
+{
+ unsigned char e32_magic[4]; /* Magic number E32_MAGIC */
+ unsigned char e32_bworder; /* The byte/word ordering for the .EXE */
+ unsigned char e32_res1[E32RESBYTES1];
+ /* Reserved bytes - must be zero */
+ unsigned short e32_cpu; /* The CPU type */
+ unsigned short e32_os; /* The OS type */
+ unsigned short e32_subsys; /* The subsystem type */
+ unsigned short e32_osmajor; /* The operating system major ver. no. */
+ unsigned short e32_osminor; /* The operating system minor ver. no. */
+ unsigned short e32_linkmajor; /* The linker major version number */
+ unsigned short e32_linkminor; /* The linker minor version number */
+ unsigned short e32_usermajor; /* The user major version number */
+ unsigned short e32_userminor; /* The user minor version number */
+ unsigned long e32_mflags; /* Module flags */
+ unsigned char e32_res2[E32RESBYTES2];
+ /* Reserved bytes - must be zero */
+ unsigned long e32_filechksum; /* Checksum for entire file */
+ unsigned long e32_entryrva; /* Relative virt. addr. of entry point */
+
+ unsigned long e32_vbase; /* Virtual base address of module */
+ unsigned long e32_vsize; /* Virtual size of the entire image */
+ unsigned long e32_hdrsize; /* Header information size */
+ unsigned long e32_filealign; /* Alignment factor used to */
+ /* align/truncate image pages */
+ unsigned long e32_pagesize; /* The size of one page for this module*/
+ unsigned long e32_timestamp; /* Time the .EXE file was created/modified*/
+ unsigned long e32_stackmax; /* Maximum stack size */
+ unsigned long e32_stackinit; /* Initial committed stack size */
+ unsigned long e32_heapmax; /* Maximum heap size */
+ unsigned long e32_heapinit; /* Initial committed heap size */
+ unsigned long e32_objcnt; /* Number of memory objects */
+ unsigned long e32_objtab; /* Object table offset */
+ unsigned long e32_dircnt; /* Number of module directives */
+ unsigned long e32_dirtab; /* Module format directives table off */
+ unsigned char e32_res3[E32RESBYTES3];
+ /* Reserved bytes - must be zero */
+ unsigned long e32_rescnt; /* Number of resources */
+ unsigned long e32_hdrextra; /* Number of extra info units in header*/
+ struct info e32_unit[STD_EXTRA];
+ /* Array of extra info units */
+ unsigned char e32_res4[E32RESBYTES4];
+ /* Pad structure to 196 bytes */
+};
+
+
+#define E32HDR_SIZE sizeof(struct e32_exe)
+
+#define E32_MAGIC(x) ((unsigned short)((x).e32_magic[0]<<BITPERBYTE)|(x).e32_magic[1])
+#define E32_MAGIC1(x) (x).e32_magic[0]
+#define E32_MAGIC2(x) (x).e32_magic[1]
+#define E32_BWORDER(x) (x).e32_bworder
+#define E32_CPU(x) (x).e32_cpu
+#define E32_OS(x) (x).e32_os
+#define E32_SUBSYS(x) (x).e32_subsys
+#define E32_OSMAJOR(x) (x).e32_osmajor
+#define E32_OSMINOR(x) (x).e32_osminor
+#define E32_LINKMAJOR(x) (x).e32_linkmajor
+#define E32_LINKMINOR(x) (x).e32_linkminor
+#define E32_USERMAJOR(x) (x).e32_usermajor
+#define E32_USERMINOR(x) (x).e32_userminor
+#define E32_MFLAGS(x) (x).e32_mflags
+#define E32_FILECHKSUM(x) (x).e32_filechksum
+#define E32_ENTRYRVA(x) (x).e32_entryrva
+#define E32_VBASE(x) (x).e32_vbase
+#define E32_VSIZE(x) (x).e32_vsize
+#define E32_HDRSIZE(x) (x).e32_hdrsize
+#define E32_FILEALIGN(x) (x).e32_filealign
+#define E32_PAGESIZE(x) (x).e32_pagesize
+#define E32_TIMESTAMP(x) (x).e32_timestamp
+#define E32_STACKMAX(x) (x).e32_stackmax
+#define E32_STACKINIT(x) (x).e32_stackinit
+#define E32_HEAPMAX(x) (x).e32_heapmax
+#define E32_HEAPINIT(x) (x).e32_heapinit
+#define E32_OBJCNT(x) (x).e32_objcnt
+#define E32_OBJTAB(x) (x).e32_objtab
+#define E32_DIRCNT(x) (x).e32_dircnt
+#define E32_DIRTAB(x) (x).e32_dirtab
+#define E32_RESCNT(x) (x).e32_rescnt
+#define E32_HDREXTRA(x) (x).e32_hdrextra
+#define E32_EXPTAB(x) (x).e32_unit[EXP].rva
+#define E32_EXPSIZ(x) (x).e32_unit[EXP].size
+#define E32_IMPTAB(x) (x).e32_unit[IMP].rva
+#define E32_IMPSIZ(x) (x).e32_unit[IMP].size
+#define E32_RESTAB(x) (x).e32_unit[RES].rva
+#define E32_RESSIZ(x) (x).e32_unit[RES].size
+#define E32_EXCTAB(x) (x).e32_unit[EXC].rva
+#define E32_EXCSIZ(x) (x).e32_unit[EXC].size
+#define E32_SECTAB(x) (x).e32_unit[SEC].rva
+#define E32_SECSIZ(x) (x).e32_unit[SEC].size
+#define E32_FIXTAB(x) (x).e32_unit[FIX].rva
+#define E32_FIXSIZ(x) (x).e32_unit[FIX].size
+#define E32_DEBTAB(x) (x).e32_unit[DEB].rva
+#define E32_DEBSIZ(x) (x).e32_unit[DEB].size
+
+
+
+/*
+ * Valid linear-executable signature:
+ */
+
+#define E32MAGIC1 'L' /* New magic number "LE" */
+#define E32MAGIC2 'E' /* New magic number "LE" */
+#define E32MAGIC 0x454c /* New magic number "LE" */
+
+/*
+ * Format of E32_BWORDER(x):
+ *
+ * 7 6 5 4 3 2 1 0 - bit no
+ * | |
+ * | +--- Big Endian Byte Ordering (else Little Endian)
+ * +----- Big Endian Word Ordering (else Little Endian)
+ */
+
+#define E32LEBO 0x00 /* Little Endian Byte Order */
+#define E32BEBO 0x01 /* Big Endian Byte Order */
+#define E32LEWO 0x00 /* Little Endian Word Order */
+#define E32BEWO 0x02 /* Big Endian Word Order */
+
+/*
+ * Valid CPU types:
+ */
+
+#define E32CPUUNKNOWN 0x000 /* Unknown CPU */
+#define E32CPU286 0x001 /* Intel 80286 or upwardly compatibile */
+#define E32CPU386 0x002 /* Intel 80386 or upwardly compatibile */
+#define E32CPU486 0x003 /* Intel 80486 or upwardly compatibile */
+#define E32CPU586 0x004 /* Intel 80586 or upwardly compatibile */
+#define E32CPUi860 0x020 /* Intel i860 or upwardly compatibile */
+#define E32CPUixxx 0x021 /* Intel i??? or upwardly compatibile */
+#define E32CPUMIPS_I 0x040 /* MIPS Mark I (R2000, R3000) */
+#define E32CPUMIPS_II 0x041 /* MIPS Mark II (R6000) */
+#define E32CPUMIPS_III 0x042 /* MIPS Mark II (R4000) */
+
+/*
+ * Target operating systems
+ */
+
+#define E32_UNKNOWN NE_UNKNOWN /* Unknown (any "new-format" OS) */
+#define E32_OS2 NE_OS2 /* Microsoft/IBM OS/2 (default) */
+#define E32_WINDOWS NE_WINDOWS /* Microsoft Windows */
+#define E32_DOS NE_DOS4 /* Microsoft MS-DOS */
+#define E32_NT 0x4 /* NT */
+#define E32_UNIX 0x5 /* UNIX */
+
+
+#if FALSE
+
+/* DEFINED in the newexe.h !!!!! */
+
+#define NE_UNKNOWN 0x0 /* Unknown (any "new-format" OS) */
+#define NE_OS2 0x1 /* Microsoft/IBM OS/2 (default) */
+#define NE_WINDOWS 0x2 /* Microsoft Windows */
+#define NE_DOS4 0x3 /* Microsoft MS-DOS 4.x */
+#define NE_DEV386 0x4 /* Microsoft Windows 386 */
+#endif
+
+/*
+ * Target subsystems required to run module
+ */
+
+#define E32_SUB_UNKNOWN 0x0 /* Unknown subsystem */
+#define E32_SUB_OS2 0x1 /* OS/2 subsystem */
+#define E32_SUB_WINDOWS 0x2 /* Windows subsystem */
+#define E32_SUB_NATIVE 0x4 /* NT native subsystem */
+#define E32_SUB_POSIX 0x5 /* POSIX subsystem */
+
+
+/*
+ * Format of E32_MFLAGS(x):
+ *
+ * 31 25 24 16 15 8 7 0
+ * #### #### | #### #### | #### #### | #### #### - bit no
+ * |||| |||| |||| |||| |||| |||| |||| ||||
+ * |||| |||| |||| |||| |||| |||| |||| ||++-- Reserved - must be zero
+ * |||| |||| |||| |||| |||| |||| |||| |+---- Per-Process Library Initialization
+ * |||| |||| |||| |||| |||| |||| |||| +----- Reserved - must be zero
+ * |||| |||| |||| |||| |||| |||| |||+------- Resolved fixups have been removed
+ * |||| |||| |||| |||| |||| |||| +++-------- Reserved - must be zero
+ * |||| |||| |||| |||| |||| |+++-------------- Application type
+ * |||| |||| |||| |||| |||+-+----------------- Reserved - must be zero
+ * |||| |||| |||| |||| ||+-------------------- Module not Loadable
+ * |||| |||| |||| |||| |+--------------------- Reserved - must be zero
+ * |||| |||| |||| ||++---+---------------------- Module type
+ * ||++-++++---++++-++---------------------------- Reserved - must be zero
+ * |+--------------------------------------------- Per-Process Library Termination
+ * +---------------------------------------------- Reserved - must be zero
+ *
+ */
+
+
+#define E32_LIBINIT 0x0004L /* Per-Process Library Initialization */
+#define E32_NOINTFIX 0x0010L /* Resolved fixups have been removed */
+
+/*
+ * Application types:
+ *
+ * 0x000 - Illegal - reserved for future use
+ * 0x100 - Incompatible with PM windowing
+ * 0x200 - Compatible with PM windowing
+ * 0x300 - Uses PM windowing API
+ * 0x400 - Illegal - reserved for future use
+ * 0x500 - Illegal - reserved for future use
+ * 0x600 - Illegal - reserved for future use
+ * 0x700 - Illegal - reserved for future use
+ */
+
+#define E32_NOPMW 0x0100L /* Incompatible with PM Windowing */
+#define E32_PMW 0x0200L /* Compatible with PM Windowing */
+#define E32_PMAPI 0x0300L /* Uses PM Windowing API */
+#define E32_APPMASK 0x0700L /* Aplication Type Mask */
+
+#define E32_NOLOAD 0x2000L /* Module not Loadable */
+
+/*
+ * Module types:
+ *
+ * 0x00000 - Program module
+ * 0x08000 - Dynamic-Link Library module
+ * 0x10000 - Illegal - reserved for future use
+ * 0x18000 - Illegal - reserved for future use
+ * 0x20000 - Physical Device Driver module
+ * 0x28000 - Virtual Device Driver module
+ * 0x30000 - Illegal - reserved for future use
+ * 0x38000 - Illegal - reserved for future use
+ */
+
+#define E32_MODEXE 0x00000L /* Program module */
+#define E32_MODDLL 0x08000L /* Library Module - used as NENOTP */
+#define E32_MODPDEV 0x20000L /* Physical device driver */
+#define E32_MODVDEV 0x28000L /* Virtual device driver */
+#define E32_MODMASK 0x38000L /* Module type mask */
+
+#define E32_NOFIXUPS 0x20000000L /* Image has no fixups that reference the IAT or EAT */
+#define E32_LIBTERM 0x40000000L /* Per-Process library termination */
+#define E32_PURE32 0x80000000L /* Image is pure 32 bit */
+
+#define IsINSTINIT(x) ((x)&E32_LIBINIT)
+#define IsNOTRELOC(x) ((x)&E32_NOINTFIX)
+#define IsNOTGUI(x) (((x)&E32_APPMASK)==E32_NOPMW)
+#define IsGUICOMPAT(x) (((x)&E32_APPMASK)==E32_PMW)
+#define IsGUI(x) (((x)&E32_APPMASK)==E32_PMAPI)
+#define IsLOADABLE(x) (!((x)&E32_NOLOAD))
+#define IsAPLIPROG(x) (((x)&E32_MODMASK)==E32_MODEXE)
+#define IsDLL(x) (((x)&E32_MODMASK)==E32_MODDLL)
+#define IsPDEVICE(x) (((x)&E32_MODMASK)==E32_MODPDEV)
+#define IsVDEVICE(x) (((x)&E32_MODMASK)==E32_MODVDEV)
+#define NoFIXUPS(x) ((x)&E32_NOFIXUPS)
+#define IsINSTTERM(x) ((x)&E32_LIBTERM)
+#define IsPURE32(x) ((x)&E32_PURE32)
+
+#define SetINSTINIT(x) ((x)|=E32_LIBINIT)
+#define SetNOTRELOC(x) ((x)|=E32_NOINTFIX)
+#define SetNOTGUI(x) ((x)=((x)&~E32_APPMASK)|E32_NOPMW)
+#define SetGUICOMPAT(x) ((x)=((x)&~E32_APPMASK)|E32_PMW)
+#define SetGUI(x) ((x)=((x)&~E32_APPMASK)|E32_PMAPI)
+#define SetNOTLOADABLE(x) (((x)|=E32_NOLOAD))
+#define SetAPLIPROG(x) ((x)=((x)&~E32_MODMASK)|E32_MODEXE)
+#define SetDLL(x) ((x)=((x)&~E32_MODMASK)|E32_MODDLL)
+#define SetPDEVICE(x) ((x)=((x)&~E32_MODMASK)|E32_MODPDEV)
+#define SetVDEVICE(x) ((x)=((x)&~E32_MODMASK)|E32_MODVDEV)
+#define SetNOFIXUPS(x) ((x)|=E32_NOFIXUPS)
+#define SetINSTTERM(x) ((x)|=E32_LIBTERM)
+#define SetPURE32(x) ((x)|=E32_PURE32)
+
+
+/*
+ * OBJECT TABLE
+ */
+
+/***ET+ o32_obj Object Table Entry */
+
+struct o32_obj /* .EXE memory object table entry */
+{
+ unsigned long o32_rva; /* Object relative virtual address */
+ unsigned long o32_vsize; /* Virtual memory size */
+ unsigned long o32_pages; /* Image pages offset */
+ unsigned long o32_psize; /* Physical file size of init. data*/
+ unsigned long o32_flags; /* Attribute flags for the object */
+ unsigned long o32_reserved;
+};
+
+#define O32_OBJSIZE sizeof(struct o32_obj)
+
+#define O32_RVA(x) (x).o32_rva
+#define O32_VSIZE(x) (x).o32_vsize
+#define O32_PAGES(x) (x).o32_pages
+#define O32_PSIZE(x) (x).o32_psize
+#define O32_FLAGS(x) (x).o32_flags
+
+
+/*
+ * Format of O32_FLAGS(x)
+ *
+ * 31 25 24 16 15 8 7 0
+ * #### #### | #### #### | #### #### | #### #### - bit no
+ * |||| |||| |||| |||| |||| |||| |||| ||||
+ * |||| |||| |||| |||| |||| |||| |||| |||+-- Readable object
+ * |||| |||| |||| |||| |||| |||| |||| ||+--- Writable object
+ * |||| |||| |||| |||| |||| |||| |||| |+---- Executable object
+ * |||| |||| |||| |||| |||| |||| |||| +----- Resource object
+ * |||| |||| |||| |||| |||| |||| |||+------- Discardable object
+ * |||| |||| |||| |||| |||| |||| ||+-------- Shared object
+ * |||| |||| |||| |||| |||| |||| |+--------- Reserved - must be zero
+ * |||| |||| |||| |||| |||| |||| +---------- Trailing pages are invalid
+ * |||| |||| |||| |||| |||| ++++-------------- Object type
+ * |||| |||| |||| |||| |||+------------------- 16:16 Alias required
+ * |||| |||| |||| |||| ||+-------------------- Big/Default bit setting
+ * |||| |||| |||| |||| |+--------------------- Object is conformin for code
+ * |||| |||| |||| |||| +---------------------- Object has I/O privilege level
+ * |||| |||| |||| |||+-------------------------- Object must not be cached
+ * |||| |||| |||| ||+--------------------------- Debug object
+ * ++++-++++---++++-+++--------------------------- Reserved - must be zero
+ *
+ */
+
+#define OBJ_READ 0x0001L /* Readable Object */
+#define OBJ_WRITE 0x0002L /* Writeable Object */
+#define OBJ_EXEC 0x0004L /* Executable Object */
+#define OBJ_RSRC 0x0008L /* Resource Object */
+
+#define OBJ_DISCARD 0x0010L /* Object is Discardable */
+#define OBJ_SHARED 0x0020L /* Object is Shared */
+#define OBJ_INVALID 0x0080L /* Object has trailing invalid pages */
+
+/*
+ * Object types:
+ *
+ * 0x0000 - object is nonpermanent or normal EXE, DLL object
+ * 0x0100 - object is permanent (FDSs, VDDs, PDDs only)
+ * 0x0200 - object is resident (FDSs, VDDs, PDDs only)
+ * 0x0300 - object is contiguous (FDSs, VDDs, PDDs only)
+ * 0x0400 - object is dynamic (FDSs, VDDs, PDDs only)
+ * 0x0500 - illegal - reserved for future use
+ * 0x0600 - illegal - reserved for future use
+ * 0x0700 - illegal - reserved for future use
+ * 0x0800 - object reserves space for call-gates
+ * 0x0900 - illegal - reserved for future use
+ * 0x0a00 - illegal - reserved for future use
+ * 0x0b00 - illegal - reserved for future use
+ * 0x0c00 - illegal - reserved for future use
+ * 0x0d00 - illegal - reserved for future use
+ * 0x0e00 - illegal - reserved for future use
+ * 0x0f00 - illegal - reserved for future use
+ *
+ */
+
+#define OBJ_NONPERM 0x0000L /* Object is nonpermanent */
+#define OBJ_PERM 0x0100L /* Object is permanent and swappable */
+#define OBJ_RESIDENT 0x0200L /* Object is permanent and resident */
+#define OBJ_CONTIG 0x0300L /* Object is resident and contiguous */
+#define OBJ_DYNAMIC 0x0400L /* Object is dynamic */
+#define OBJ_GATE 0x0800L /* Object reserves space for call-gates */
+#define OBJ_TYPEMASK 0x0f00L /* Object type mask */
+
+
+#define OBJ_ALIAS16 0x1000L /* 16:16 alias required (80x86 specific) */
+#define OBJ_BIGDEF 0x2000L /* Big/Default bit setting (80x86 specific) */
+#define OBJ_CONFORM 0x4000L /* Object is conforming for code (80x86 specific) */
+#define OBJ_IOPL 0x8000L /* Object I/O privilege level (80x86 specific) */
+#define OBJ_CACHE 0x10000L /* Object must be cached */
+#define OBJ_DEBUG 0x20000L /* Object describes debugger information */
+
+#define IsREADABLE(x) ((x)&OBJ_READ)
+#define IsWRITEABLE(x) ((x)&OBJ_WRITE)
+#define IsEXECUTABLE(x) ((x)&OBJ_EXEC)
+#define IsRESOURCE(x) ((x)&OBJ_RSRC)
+#define IsDISCARDABLE(x) ((x)&OBJ_DISCARD)
+#define IsSHARED(x) ((x)&OBJ_SHARED)
+#define IsINVALID(x) ((x)&OBJ_INVALID)
+#define IsNONPERM(x) (((x)&OBJ_TYPEMASK)==OBJ_NONPERM)
+#define IsPERMANENT(x) (((x)&OBJ_TYPEMASK)==OBJ_PERM)
+#define IsRESIDENT(x) (((x)&OBJ_TYPEMASK)==OBJ_RESIDENT)
+#define IsCONTIG(x) (((x)&OBJ_TYPEMASK)==OBJ_CONTIG)
+#define IsDYNAMIC(x) (((x)&OBJ_TYPEMASK)==OBJ_DYNAMIC)
+#define IsGATERESERV(x) (((x)&OBJ_TYPEMASK)==OBJ_GATE)
+#define ObjTYPE(x) ((x)&OBJ_TYPEMASK)
+#define IsALIAS16(x) ((x)&OBJ_ALIAS16)
+#define IsBIGDEF(x) ((x)&OBJ_BIGDEF)
+#define IsCONFORMING(x) ((x)&OBJ_CONFORM)
+#define IsIOPL(x) ((x)&OBJ_IOPL)
+#define IsCACHED(x) ((x)&OBJ_CACHE)
+#define IsDEBUG(x) ((x)&OBJ_DEBUG)
+
+#define SetREADABLE(x) ((x)|=OBJ_READ)
+#define SetWRITABLE(x) ((x)|=OBJ_WRITE)
+#define SetEXECUTABLE(x) ((x)|=OBJ_EXEC)
+#define SetRESOURCE(x) ((x)|=OBJ_RSRC)
+#define SetDISCARABLE(x) ((x)|=OBJ_DISCARD)
+#define SetSHARED(x) ((x)|=OBJ_SHARED)
+#define SetINVALID(x) ((x)|=OBJ_INVALID)
+#define SetNONPERM(x) ((x)=((x)&~OBJ_TYPEMASK)|OBJ_NONPERM)
+#define SetPERMANENT(x) ((x)=((x)&~OBJ_TYPEMASK)|OBJ_PERM)
+#define SetRESIDENT(x) ((x)=((x)&~OBJ_TYPEMASK)|OBJ_RESIDENT)
+#define SetCONTIG(x) ((x)=((x)&~OBJ_TYPEMASK)|OBJ_CONTIG)
+#define SetDYNAMIC(x) ((x)=((x)&~OBJ_TYPEMASK)|OBJ_DYNAMIC)
+#define SetGATERESERV(x) ((x)=((x)&~OBJ_TYPEMASK)|OBJ_GATE)
+#define SetALIAS16(x) ((x)|=OBJ_ALIAS16)
+#define SetBIGDEF(x) ((x)|=OBJ_BIGDEF)
+#define SetCONFORMING(x) ((x)|=OBJ_CONFORM)
+#define SetIOPL(x) ((x)|=OBJ_IOPL)
+#define SetCACHED(x) ((x)|=OBJ_CACHE)
+#define SetDEBUG(x) ((x)|=OBJ_DEBUG)
+
+/*
+ * MODULE FORMAT DIRECTIVES TABLE
+ */
+
+struct FmtDir
+{
+ unsigned short dir; /* Directive number */
+ unsigned short reserved;
+ unsigned long offset; /* Directive data offset */
+ unsigned long length; /* Directive data length */
+};
+
+#define FMTDIR_SIZE sizeof(struct FmtDir)
+
+#define DIRECTIVE(x) (x).dir
+#define DIR_OFF(x) (x).offset
+#define DIR_LEN(x) (x).length
+
+/*
+ * Directive numbers
+ */
+
+#define OS2LDR16 0x200
+#define OS2RSRCNT 0x300
+
+struct ComDir
+{
+ unsigned long stackobj;
+ unsigned long autods;
+};
+
+#define COMDIR_SIZE sizeof(struct ComDir)
+
+
+/*
+ * EXPORT ADDRESS TABLE - Previously called entry table
+ */
+
+struct ExpHdr /* Export directory table */
+{
+ unsigned long exp_flags; /* Export table flags */
+ unsigned long exp_ver; /* Version stamp */
+ unsigned long exp_size; /* Export table size */
+ unsigned long exp_dllname; /* Offset to the DLL name */
+ unsigned long exp_ordbase; /* First valid ordinal */
+ unsigned long exp_eatcnt; /* Number of EAT entries */
+ unsigned long exp_namecnt; /* Number of exported names */
+ unsigned long exp_eat; /* Export Address Table offset */
+ unsigned long exp_name; /* Export name pointers table off */
+ unsigned long exp_ordinal; /* Export ordinals table offset */
+};
+
+#define EXPHDR_SIZE sizeof(struct ExpHdr)
+
+#define EXP_FLAGS(x) (x).exp_flags
+#define EXP_DLLNAME(x) (x).exp_dllname
+#define EXP_VER(x) (x).exp_ver
+#define EXP_SIZE(x) (x).exp_size
+#define EXP_ORDBASE(x) (x).exp_ordbase
+#define EXP_EATCNT(x) (x).exp_eatcnt
+#define EXP_NAMECNT(x) (x).exp_namecnt
+#define EXP_EAT(x) (x).exp_eat
+#define EXP_NAME(x) (x).exp_name
+#define EXP_ORDINAL(x) (x).exp_ordinal
+
+/*
+ * EXPORT ADDRESS TABLE MASKS
+ */
+
+#define ESCAPE_BIT 0x80000000L /* Escape bit in export address */
+#define ADDR_MASK 0x7fffffffL /* Export address mask */
+#define VALUE_MASK 0x3fffffffL /* Value mask */
+
+/*
+ * ENTRY TYPES - TT field values
+ */
+
+#define AUX_DATA 0x40000000L /* Auxiliary data present */
+
+#define IsESCAPED(x) ((x)&ESCAPE_BIT)
+#define IsAUXDATA(x) ((x)&AUX_DATA)
+
+#define SetESCAPE(x) ((x)|=ESCAPE_BIT)
+#define SetAUXDATA(x) ((x)|=AUX_DATA)
+#define SetVALUE(x,v) ((x)|=((v)&VALUE_MASK))
+
+/*
+ * AUXILIARY DATA TYPES
+ */
+
+#define ABS_DATA 0x00
+#define INT_GATE 0x01
+#define EXT_GATE 0x02
+#define FORWARDER 0x03
+
+/*
+ * AUXILIARY DATA ENTRIES
+ */
+
+#pragma pack(1)
+
+struct AuxData
+{
+ unsigned char dataType;
+ unsigned char reserved;
+ union
+ {
+ struct AbsData
+ {
+ unsigned short reserved;
+ unsigned long val;
+ }
+ abs;
+ struct GateData
+ {
+ unsigned char obj;
+ unsigned char parm;
+ unsigned short off;
+ unsigned short sel;
+ }
+ gate;
+ struct FwdData
+ {
+ unsigned short idx;
+ unsigned long iat;
+ }
+ fwd;
+ }
+ data;
+};
+
+#pragma pack()
+
+#define DATA_TYP(x) (x).dataType
+#define ABS_VAL(x) (x).data.abs.val
+#define GATE_OBJ(x) (x).data.gate.obj
+#define GATE_PARM(x) (x).data.gate.parm
+#define GATE_OFF(x) (x).data.gate.off
+#define GATE_SEL(x) (x).data.gate.sel
+#define FWD_IDX(x) (x).data.fwd.idx
+#define FWD_IAT(x) (x).data.fwd.iat
+
+
+/*
+ * IMPORT MODULE DESCRIPTOR TABLE
+ */
+
+struct ImpHdr /* Import directory table */
+{
+ unsigned long imp_flags; /* Import table flags */
+ unsigned long imp_ver; /* Version stamp */
+ unsigned long imp_reserved;
+ unsigned long imp_dllname; /* Offset to the DLL name */
+ unsigned long imp_address; /* Import address table offset */
+};
+
+#define IMPHDR_SIZE sizeof(struct ImpHdr)
+
+#define IMP_FLAGS(x) (x).imp_flags
+#define IMP_VER(x) (x).imp_ver
+#define IMP_DLLNAME(x) (x).imp_dllname
+#define IMP_ADDRESS(x) (x).imp_address
+
+/*
+ * Format of IMP_FLAGS(x)
+ *
+ * 31 25 24 16 15 8 7 0
+ * #### #### | #### #### | #### #### | #### #### - bit no
+ * |||| |||| |||| |||| |||| |||| |||| ||||
+ * |||| |||| |||| |||| |||| |||| |||| |||+-- Copy of the IAT in header
+ * ++++-++++---++++-++++---++++-++++---++++-+++--- Reserved - must be zero
+ *
+ */
+
+#define HDRIAT 0x01
+
+#define IsHDRIAT(x) ((x)&HDRIAT)
+
+#define SetHDRIAT(x) ((x)|=HDRIAT)
+
+
+struct ImpMod
+{
+ unsigned long im_offset; /* Imported module name table offset */
+ unsigned long im_vaddr; /* Import Address table virtual address */
+};
+
+#define IMPMOD_SIZE sizeof(struct ImpMod)
+
+#define IM_OFFSET(x) (x).im_offset
+#define IM_VADDR(x) (x).im_vaddr
+
+/*
+ * IMPORT PROCEDURE NAME TABLE
+ */
+
+struct ImpProc
+{
+ unsigned short ip_hint; /* Hint value */
+ char ip_name[1]; /* Zero terminated imported procedure name */
+};
+
+#define IP_HINT(x) (x).ip_hint;
+
+/*
+ * IMPORT ADDRESS TABLE
+ */
+
+/*
+ * Valid import address types:
+ *
+ * 0x00000000 - 0:32 Offset - Flat offset
+ * 0x20000000 - 16:16 non-FLAT, non-gate pointer
+ * 0x40000000 - 16:16 gate pointer - Callgate needed if used
+ * 0x60000000 - Illegal - reserved for future use
+ *
+ */
+
+#define IMPORD_MASK 0x1fffffffL /* Ordinal number mask */
+#define IMPOFF_MASK 0x1fffffffL /* Import data offset mask */
+#define IMPTYPE_MASK 0x60000000L /* Import address type mask */
+#define ORD_BIT 0x80000000L /* Import by ordinal bit */
+
+#define IMP_FLATOFF 0x00000000L /* FLAT offset */
+#define IMP_ALIAS 0x20000000L /* 16:16 non-FLAT, non-gate pointer */
+#define IMP_GATE 0x40000000L /* 16:16 gate pointer */
+
+#define IsIMPBYORD(x) ((x)&ORD_BIT)
+#define IsFLATIMP(x) (!((x)&IMPTYPE_MASK))
+#define IsALIASIMP(x) (((x)&IMPTYPE_MASK)==IMP_ALIAS)
+#define IsGATEIMP(x) (((x)&IMPTYPE_MASK)==IMP_GATE)
+
+/*
+ * RESOURCE TABLE
+ */
+
+/***ET+ rsrc32 - Resource Table Entry */
+
+struct ResDir
+{
+ unsigned long dir_flags;
+ unsigned long dir_ver;
+ unsigned long dir_size;
+ unsigned short dir_namecnt;
+ unsigned short dir_idcnt;
+};
+
+
+struct ResDirEntry
+{
+ unsigned long dir_name;
+ unsigned long dir_data;
+};
+
+struct ResDirStrEntry
+{
+ unsigned short str_len;
+ char ast_ascii[1];
+};
+
+struct ResData
+{
+ unsigned long res_data;
+ unsigned long res_size;
+ unsigned long res_codepage;
+ unsigned long res_reserved;
+};
+
+/*end*/
+
+
+/*
+ * RELOCATION DEFINITIONS - RUN-TIME FIXUPS
+ */
+
+
+/***ET+ r32_rlc - Relocation item */
+
+struct r32_rlc
+{
+ unsigned short flags;
+ unsigned char cnt;
+ unsigned char obj;
+};
+
+
+#define R32_FLAGS(x) (x).flags
+#define R32_CNT(x) (x).cnt
+#define R32_OBJ(x) (x).obj
+
+
+/*
+ * Format of R32_FLAGS - relocation flags
+ *
+ * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - bit no
+ * | | | | | | | | | | | | | | | |
+ * | | | | | | | | | | | | +-+-+-+--- Source type
+ * | | | | | | | | | | | +----------- Fixup to 16:16 alias
+ * | | | | | | | | | | +------------- Reserved - must be zero
+ * | | | | | | | | | +--------------- Fixup data present
+ * | | | | | | | | +----------------- Reserved - must be zero
+ * | | | | | | +-+------------------- Reference type
+ * | | | | | +----------------------- Target has IOPL - valid only for non-aliased selector fixups
+ * | | | | +-------------------------- Target is CODE (else DATA) - valid only for non-aliased selector fixups
+ * | +--+--+----------------------------- Reserved - must be zero
+ * +-------------------------------------- Escaped fixup
+ */
+
+/*
+ * Valid source types:
+ *
+ * 0x00 - Byte fixup (8-bits)
+ * 0x01 - Align fixup - nop used to skip 2 bytes
+ * 0x02 - 16-bit Selector fixup (16-bits)
+ * 0x03 - 16:16 Pointer fixup (32-bits)
+ * 0x04 - Illegal - reserved for future use
+ * 0x05 - 16-bit Offset fixup (16-bits)
+ * 0x06 - 16:32 Pointer fixup (48-bits)
+ * 0x07 - 32-bit Offset fixup (32-bits)
+ * 0x08 - 32-bit Self-relative offset fixup (32-bits)
+ * 0x09 - Illegal - reserved for future use
+ * 0x0a - Illegal - reserved for future use
+ * 0x0b - Illegal - reserved for future use
+ * 0x0c - Illegal - reserved for future use
+ * 0x0d - Illegal - reserved for future use
+ * 0x0e - Illegal - reserved for future use
+ * 0x0f - Illegal - reserved for future use
+ */
+
+
+#define R32_BYTE 0x0000
+#define R32_ALIGN 0x0001
+#define R32_SEL 0x0002
+#define R32_PTR32 0x0003
+#define R32_OFF16 0x0005
+#define R32_PTR48 0x0006
+#define R32_OFF32 0x0007
+#define R32_SOFF32 0x0008
+#define R32_SRCMASK 0x000f
+
+#define IsBYTE(x) (((x)&R32_SRCMASK)==R32_BYTE)
+#define IsALIGN(x) (((x)&R32_SRCMASK)==R32_ALIGN)
+#define IsSEL(x) (((x)&R32_SRCMASK)==R32_SEL)
+#define IsPTR32(x) (((x)&R32_SRCMASK)==R32_PTR32)
+#define IsOFF16(x) (((x)&R32_SRCMASK)==R32_OFF16)
+#define IsPTR48(x) (((x)&R32_SRCMASK)==R32_PTR48)
+#define IsOFF32(x) (((x)&R32_SRCMASK)==R32_OFF32)
+#define IsSOFF32(x) (((x)&R32_SRCMASK)==R32_SOFF32)
+
+#define R32_ALIAS 0x0010 /* Fixup to alias */
+#define R32_FIXDATA 0x0040 /* Fixup data present */
+#define R32_IOPL 0x0080 /* Fixup Source has IOPL and is not conforming */
+
+
+#define IsALIAS(x) ((x)&R32_ALIAS)
+#define IsFIXDATA(x) ((x)&R32_FIXDATA)
+#define IsSRCIOPL(x) ((x)&R32_IOPL)
+
+/*
+ * Reference types:
+ *
+ * 0x0000 - internal reference
+ * 0x0100 - Imported reference by ordinal or name
+ * 0x0200 - Illegal - reserved for future use
+ * 0x0300 - Internal reference via export address table
+ *
+ */
+
+#define R32_INTER 0x0000 /* Internal reference */
+#define R32_IMPORT 0x0100 /* Imported reference */
+#define R32_ENTRY 0x0300 /* Internal entry table fixup */
+#define R32_REFMASK 0x0300 /* Reference type mask */
+
+#define IsINTERNAL(x) (((x)&R32_REFMASK)==R32_INTER)
+#define IsIMPORT(x) (((x)&R32_REFMASK)==R32_IMPORT)
+#define IsENTRY(x) (((x)&R32_REFMASK)==R32_ENTRY)
+
+#define TGT_IOPL 0x0400 /* Target has IOPL */
+#define TGT_CODE 0x0800 /* Target is CODE */
+
+#define IsTGTIOPL(x) ((x)&TGT_IOPL)
+#define IsTGTCODE(x) ((x)&TGT_CODE)
+
+#define R32_ESCAPE 0x8000
+#define IsESCAPEFIX(x) ((x)&R32_ESCAPE)
+
+/*end*/
+
+
+/*
+ * DEBUG INFORMATION
+ */
+
+struct DbgDir
+{
+ unsigned long dbg_flags;
+ unsigned long dbg_ver;
+ unsigned long dbg_size;
+ unsigned long dbg_type;
+ unsigned long dbg_lva;
+ unsigned long dbg_seek;
+};
+
+#define DBG_FLAGS(x) (x).dbg_flags
+#define DBG_TYPE(x) (x).dbg_type
+#define DBG_VER(x) (x).dbg_ver
+#define DBG_LVA(x) (x).dbg_lva
+#define DBG_SIZE(x) (x).dbg_size
+#define DBG_SEEK(x) (x).dbg_seek
+#define DBGDIR_SIZE sizeof(struct DbgDir)
diff --git a/private/os2/client/thunk/include/fcntl.h b/private/os2/client/thunk/include/fcntl.h
new file mode 100644
index 000000000..586b4c7b5
--- /dev/null
+++ b/private/os2/client/thunk/include/fcntl.h
@@ -0,0 +1,35 @@
+/***
+*fcntl.h - file control options used by open()
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file defines constants for the file control options used
+* by the open() function.
+* [System V]
+*
+****/
+
+#define O_RDONLY 0x0000 /* open for reading only */
+#define O_WRONLY 0x0001 /* open for writing only */
+#define O_RDWR 0x0002 /* open for reading and writing */
+#define O_APPEND 0x0008 /* writes done at eof */
+
+#define O_CREAT 0x0100 /* create and open file */
+#define O_TRUNC 0x0200 /* open and truncate */
+#define O_EXCL 0x0400 /* open only if file doesn't already exist */
+
+/* O_TEXT files have <cr><lf> sequences translated to <lf> on read()'s,
+** and <lf> sequences translated to <cr><lf> on write()'s
+*/
+
+#define O_TEXT 0x4000 /* file mode is text (translated) */
+#define O_BINARY 0x8000 /* file mode is binary (untranslated) */
+
+/* macro to translate the C 2.0 name used to force binary mode for files */
+
+#define O_RAW O_BINARY
+
+/* Open handle inherit bit */
+
+#define O_NOINHERIT 0x0080 /* child process doesn't inherit file */
diff --git a/private/os2/client/thunk/include/float.h b/private/os2/client/thunk/include/float.h
new file mode 100644
index 000000000..7abef4662
--- /dev/null
+++ b/private/os2/client/thunk/include/float.h
@@ -0,0 +1,140 @@
+/***
+*float.h - constants for floating point values
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file contains defines for a number of implementation dependent
+* values which are commonly used by sophisticated numerical (floating
+* point) programs.
+* [ANSI]
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+#define DBL_DIG 15 /* # of decimal digits of precision */
+#define DBL_EPSILON 2.2204460492503131e-016 /* smallest such that 1.0+DBL_EPSILON != 1.0 */
+#define DBL_MANT_DIG 53 /* # of bits in mantissa */
+#define DBL_MAX 1.7976931348623158e+308 /* max value */
+#define DBL_MAX_10_EXP 308 /* max decimal exponent */
+#define DBL_MAX_EXP 1024 /* max binary exponent */
+#define DBL_MIN 2.2250738585072014e-308 /* min positive value */
+#define DBL_MIN_10_EXP (-307) /* min decimal exponent */
+#define DBL_MIN_EXP (-1021) /* min binary exponent */
+#define DBL_RADIX 2 /* exponent radix */
+#define DBL_ROUNDS 1 /* addition rounding: near */
+
+#define FLT_DIG 7 /* # of decimal digits of precision */
+#define FLT_EPSILON 1.192092896e-07F /* smallest such that 1.0+FLT_EPSILON != 1.0 */
+#define FLT_GUARD 0
+#define FLT_MANT_DIG 24 /* # of bits in mantissa */
+#define FLT_MAX 3.402823466e+38F /* max value */
+#define FLT_MAX_10_EXP 38 /* max decimal exponent */
+#define FLT_MAX_EXP 128 /* max binary exponent */
+#define FLT_MIN 1.175494351e-38F /* min positive value */
+#define FLT_MIN_10_EXP (-37) /* min decimal exponent */
+#define FLT_MIN_EXP (-125) /* min binary exponent */
+#define FLT_NORMALIZE 0
+#define FLT_RADIX 2 /* exponent radix */
+#define FLT_ROUNDS 1 /* addition rounding: near */
+
+#define LDBL_DIG 19 /* # of decimal digits of precision */
+#define LDBL_EPSILON 5.4210108624275221706e-020 /* smallest such that 1.0+LDBL_EPSILON != 1.0 */
+#define LDBL_MANT_DIG 64 /* # of bits in mantissa */
+#define LDBL_MAX 1.189731495357231765e+4932L /* max value */
+#define LDBL_MAX_10_EXP 4932 /* max decimal exponent */
+#define LDBL_MAX_EXP 16384 /* max binary exponent */
+#define LDBL_MIN 3.3621031431120935063e-4932L /* min positive value */
+#define LDBL_MIN_10_EXP (-4931) /* min decimal exponent */
+#define LDBL_MIN_EXP (-16381) /* min binary exponent */
+#define LDBL_RADIX 2 /* exponent radix */
+#define LDBL_ROUNDS 1 /* addition rounding: near */
+
+
+/*
+ * 8087/80287 math control information
+ */
+
+
+/* User Control Word Mask and bit definitions.
+ * These definitions match the 8087/80287
+ */
+
+#define MCW_EM 0x003f /* interrupt Exception Masks */
+#define EM_INVALID 0x0001 /* invalid */
+#define EM_DENORMAL 0x0002 /* denormal */
+#define EM_ZERODIVIDE 0x0004 /* zero divide */
+#define EM_OVERFLOW 0x0008 /* overflow */
+#define EM_UNDERFLOW 0x0010 /* underflow */
+#define EM_INEXACT 0x0020 /* inexact (precision) */
+
+#define MCW_IC 0x1000 /* Infinity Control */
+#define IC_AFFINE 0x1000 /* affine */
+#define IC_PROJECTIVE 0x0000 /* projective */
+
+#define MCW_RC 0x0c00 /* Rounding Control */
+#define RC_CHOP 0x0c00 /* chop */
+#define RC_UP 0x0800 /* up */
+#define RC_DOWN 0x0400 /* down */
+#define RC_NEAR 0x0000 /* near */
+
+#define MCW_PC 0x0300 /* Precision Control */
+#define PC_24 0x0000 /* 24 bits */
+#define PC_53 0x0200 /* 53 bits */
+#define PC_64 0x0300 /* 64 bits */
+
+
+/* initial Control Word value */
+
+#define CW_DEFAULT ( IC_AFFINE + RC_NEAR + PC_64 + EM_DENORMAL + EM_UNDERFLOW + EM_INEXACT )
+
+
+/* user Status Word bit definitions */
+
+#define SW_INVALID 0x0001 /* invalid */
+#define SW_DENORMAL 0x0002 /* denormal */
+#define SW_ZERODIVIDE 0x0004 /* zero divide */
+#define SW_OVERFLOW 0x0008 /* overflow */
+#define SW_UNDERFLOW 0x0010 /* underflow */
+#define SW_INEXACT 0x0020 /* inexact (precision) */
+
+
+/* invalid subconditions (SW_INVALID also set) */
+
+#define SW_UNEMULATED 0x0040 /* unemulated instruction */
+#define SW_SQRTNEG 0x0080 /* square root of a neg number */
+#define SW_STACKOVERFLOW 0x0200 /* FP stack overflow */
+#define SW_STACKUNDERFLOW 0x0400 /* FP stack underflow */
+
+
+/* Floating point error signals and return codes */
+
+#define FPE_INVALID 0x81
+#define FPE_DENORMAL 0x82
+#define FPE_ZERODIVIDE 0x83
+#define FPE_OVERFLOW 0x84
+#define FPE_UNDERFLOW 0x85
+#define FPE_INEXACT 0x86
+
+#define FPE_UNEMULATED 0x87
+#define FPE_SQRTNEG 0x88
+#define FPE_STACKOVERFLOW 0x8a
+#define FPE_STACKUNDERFLOW 0x8b
+
+#define FPE_EXPLICITGEN 0x8c /* raise( SIGFPE ); */
+
+/* function prototypes */
+
+unsigned int _FAR_ _cdecl _clear87(void);
+unsigned int _FAR_ _cdecl _control87(unsigned int, unsigned int);
+void _FAR_ _cdecl _fpreset(void);
+unsigned int _FAR_ _cdecl _status87(void);
diff --git a/private/os2/client/thunk/include/gdidefs.inc b/private/os2/client/thunk/include/gdidefs.inc
new file mode 100644
index 000000000..196dc3351
--- /dev/null
+++ b/private/os2/client/thunk/include/gdidefs.inc
@@ -0,0 +1,1200 @@
+;/*
+;***************************************************************************
+; *
+; 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
+
+/*
+ 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 (OBJ_PEN + 1)
+#define OBJ_FONT (OBJ_BRUSH + 1)
+/*
+ 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
+
+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 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
+
+CLIP_DEFAULT_PRECIS equ 0
+CLIP_CHARACTER_PRECIS equ 1
+CLIP_STROKE_PRECIS equ 2
+
+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
+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 CLIP_DEFAULT_PRECIS 0
+#define CLIP_CHARACTER_PRECIS 1
+#define CLIP_STROKE_PRECIS 2
+
+#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 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
+ResetDevice = 00000010b ;Reset Device 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
+
+
+; 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
+
+; 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
+
+
+
+ if 0
+*/
+
+#define InquireInfo 0x01 /* Inquire Device GDI Info */
+#define EnableDevice 0x00 /* Enable Device */
+#define InfoContext 0x8000 /* Inquire/Enable for info context */
+#define ResetDevice 0x02 /* Reset Device 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 */
+
+/* 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 */
+
+/*
+ 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; /*
+ dw 0 ;Reserved for future use ;*/ short int futureuse3; /*
+ dw 0 ;*/ short int futureuse4; /*
+ dw 0 ;*/ short int futureuse5; /*
+ 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; /*
+
+
+
+
+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
+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
+SETENDCAP 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
+GETEXTENDEDTEXTMETRICS equ 256
+GETEXTENTTABLE equ 257
+GETPAIRKERNTABLE equ 258
+GETTRACKKERNTABLE equ 259
+EXTTEXTOUT equ 512
+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 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 SETENDCAP 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 GETEXTENDEDTEXTMETRICS 256
+#define GETEXTENTTABLE 257
+#define GETPAIRKERNTABLE 258
+#define GETTRACKKERNTABLE 259
+#define EXTTEXTOUT 512
+#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
+
+/*
+ endif
+
+
+
+ endif
+ endif
+;*/
+
diff --git a/private/os2/client/thunk/include/graph.h b/private/os2/client/thunk/include/graph.h
new file mode 100644
index 000000000..6469809bf
--- /dev/null
+++ b/private/os2/client/thunk/include/graph.h
@@ -0,0 +1,427 @@
+/***
+*graph.h - declare constants, functions, and macros for graphics library
+*
+* Copyright (c) 1987 - 1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file declares the graphics library functions and the
+* structures and manifest constants that are used with them.
+*
+***************************************************************************/
+
+
+/* force word packing to avoid possible -Zp override */
+#pragma pack(2)
+
+/* user-visible declarations for Quick-C Graphics Library */
+
+#ifndef _VIDEOCONFIG_DEFINED
+/* structure for _getvideoconfig() as visible to user */
+struct videoconfig {
+ short numxpixels; /* number of pixels on X axis */
+ short numypixels; /* number of pixels on Y axis */
+ short numtextcols; /* number of text columns available */
+ short numtextrows; /* number of text rows available */
+ short numcolors; /* number of actual colors */
+ short bitsperpixel; /* number of bits per pixel */
+ short numvideopages; /* number of available video pages */
+ short mode; /* current video mode */
+ short adapter; /* active display adapter */
+ short monitor; /* active display monitor */
+ short memory; /* adapter video memory in K bytes */
+};
+#define _VIDEOCONFIG_DEFINED
+#endif
+
+
+#ifndef _XYCOORD_DEFINED
+/* return value of _setvieworg(), etc. */
+struct xycoord {
+ short xcoord;
+ short ycoord;
+};
+#define _XYCOORD_DEFINED
+#endif
+
+
+/* structure for text position */
+#ifndef _RCCOORD_DEFINED
+struct rccoord {
+ short row;
+ short col;
+};
+#define _RCCOORD_DEFINED
+#endif
+
+
+
+/* ERROR HANDLING */
+short _far _cdecl _grstatus(void);
+
+/* Error Status Information returned by _grstatus() */
+
+/* successful */
+#define _GROK 0
+
+/* errors */
+#define _GRERROR (-1)
+#define _GRMODENOTSUPPORTED (-2)
+#define _GRNOTINPROPERMODE (-3)
+#define _GRINVALIDPARAMETER (-4)
+#define _GRFONTFILENOTFOUND (-5)
+#define _GRINVALIDFONTFILE (-6)
+#define _GRCORRUPTEDFONTFILE (-7)
+#define _GRINSUFFICIENTMEMORY (-8)
+#define _GRINVALIDIMAGEBUFFER (-9)
+
+/* warnings */
+#define _GRNOOUTPUT 1
+#define _GRCLIPPED 2
+#define _GRPARAMETERALTERED 3
+
+
+/* SETUP AND CONFIGURATION */
+
+short _far _cdecl _setvideomode(short);
+short _far _cdecl _setvideomoderows(short,short); /* return rows; 0 if error */
+
+/* arguments to _setvideomode() */
+#define _MAXRESMODE (-3) /* graphics mode with highest resolution */
+#define _MAXCOLORMODE (-2) /* graphics mode with most colors */
+#define _DEFAULTMODE (-1) /* restore screen to original mode */
+#define _TEXTBW40 0 /* 40-column text, 16 grey */
+#define _TEXTC40 1 /* 40-column text, 16/8 color */
+#define _TEXTBW80 2 /* 80-column text, 16 grey */
+#define _TEXTC80 3 /* 80-column text, 16/8 color */
+#define _MRES4COLOR 4 /* 320 x 200, 4 color */
+#define _MRESNOCOLOR 5 /* 320 x 200, 4 grey */
+#define _HRESBW 6 /* 640 x 200, BW */
+#define _TEXTMONO 7 /* 80-column text, BW */
+#define _HERCMONO 8 /* 720 x 348, BW for HGC */
+#define _MRES16COLOR 13 /* 320 x 200, 16 color */
+#define _HRES16COLOR 14 /* 640 x 200, 16 color */
+#define _ERESNOCOLOR 15 /* 640 x 350, BW */
+#define _ERESCOLOR 16 /* 640 x 350, 4 or 16 color */
+#define _VRES2COLOR 17 /* 640 x 480, BW */
+#define _VRES16COLOR 18 /* 640 x 480, 16 color */
+#define _MRES256COLOR 19 /* 320 x 200, 256 color */
+#define _ORESCOLOR 64 /* 640 x 400, 1 of 16 colors (Olivetti) */
+
+short _far _cdecl _setactivepage(short);
+short _far _cdecl _setvisualpage(short);
+short _far _cdecl _getactivepage(void);
+short _far _cdecl _getvisualpage(void);
+
+/* videoconfig adapter values */
+/* these manifest constants can be used to determine the type of the active */
+/* adapter, using either simple comparisons or the bitwise-AND operator (&) */
+#define _MDPA 0x0001 /* Monochrome Display Adapter (MDPA) */
+#define _CGA 0x0002 /* Color Graphics Adapter (CGA) */
+#define _EGA 0x0004 /* Enhanced Graphics Adapter (EGA) */
+#define _VGA 0x0008 /* Video Graphics Array (VGA) */
+#define _MCGA 0x0010 /* MultiColor Graphics Array (MCGA) */
+#define _HGC 0x0020 /* Hercules Graphics Card (HGC) */
+#define _OCGA 0x0042 /* Olivetti Color Graphics Adapter (OCGA) */
+#define _OEGA 0x0044 /* Olivetti Enhanced Graphics Adapter (OEGA) */
+#define _OVGA 0x0048 /* Olivetti Video Graphics Array (OVGA) */
+
+/* videoconfig monitor values */
+/* these manifest constants can be used to determine the type of monitor in */
+/* use, using either simple comparisons or the bitwise-AND operator (&) */
+#define _MONO 0x0001 /* Monochrome */
+#define _COLOR 0x0002 /* Color (or Enhanced emulating color) */
+#define _ENHCOLOR 0x0004 /* Enhanced Color */
+#define _ANALOGMONO 0x0008 /* Analog Monochrome only */
+#define _ANALOGCOLOR 0x0010 /* Analog Color only */
+#define _ANALOG 0x0018 /* Analog Monochrome and Color modes */
+
+struct videoconfig _far * _far _cdecl _getvideoconfig(struct videoconfig _far *);
+
+
+
+/* COORDINATE SYSTEMS */
+
+struct xycoord _far _cdecl _setvieworg(short, short);
+#define _setlogorg _setvieworg /* obsolescent */
+
+struct xycoord _far _cdecl _getviewcoord(short, short);
+#define _getlogcoord _getviewcoord /* obsolescent */
+
+struct xycoord _far _cdecl _getphyscoord(short, short);
+
+void _far _cdecl _setcliprgn(short, short, short, short);
+void _far _cdecl _setviewport(short, short, short, short);
+
+
+/* OUTPUT ROUTINES */
+
+/* control parameters for _ellipse, _rectangle, _pie and _polygon */
+#define _GBORDER 2 /* draw outline only */
+#define _GFILLINTERIOR 3 /* fill using current fill mask */
+
+/* parameters for _clearscreen */
+#define _GCLEARSCREEN 0
+#define _GVIEWPORT 1
+#define _GWINDOW 2
+
+void _far _cdecl _clearscreen(short);
+
+struct xycoord _far _cdecl _moveto(short, short);
+struct xycoord _far _cdecl _getcurrentposition(void);
+
+short _far _cdecl _lineto(short, short);
+short _far _cdecl _rectangle(short, short, short, short, short);
+short _far _cdecl _polygon(short, const struct xycoord _far *, short);
+short _far _cdecl _arc(short, short, short, short, short, short, short, short);
+short _far _cdecl _ellipse(short, short, short, short, short);
+short _far _cdecl _pie(short, short, short, short, short, short, short, short, short);
+
+short _far _cdecl _getarcinfo(struct xycoord _far *, struct xycoord _far *, struct xycoord _far *);
+
+short _far _cdecl _setpixel(short, short);
+short _far _cdecl _getpixel(short, short);
+short _far _cdecl _floodfill(short, short, short);
+
+
+/* PEN COLOR, LINE STYLE, WRITE MODE, FILL PATTERN */
+
+short _far _cdecl _setcolor(short);
+short _far _cdecl _getcolor(void);
+
+void _far _cdecl _setlinestyle(unsigned short);
+unsigned short _far _cdecl _getlinestyle(void);
+
+short _far _cdecl _setwritemode(short);
+short _far _cdecl _getwritemode(void);
+
+void _far _cdecl _setfillmask(const unsigned char _far *);
+unsigned char _far * _far _cdecl _getfillmask(unsigned char _far *);
+
+/* COLOR SELECTION */
+
+long _far _cdecl _setbkcolor(long);
+long _far _cdecl _getbkcolor(void);
+
+long _far _cdecl _remappalette(short, long);
+short _far _cdecl _remapallpalette(const long _far *);
+short _far _cdecl _selectpalette(short);
+
+
+/* TEXT */
+/* parameters for _displaycursor */
+#define _GCURSOROFF 0
+#define _GCURSORON 1
+
+/* parameters for _wrapon */
+#define _GWRAPOFF 0
+#define _GWRAPON 1
+
+
+/* direction parameters for _scrolltextwindow */
+#define _GSCROLLUP 1
+#define _GSCROLLDOWN (-1)
+
+/* request maximum number of rows in _settextrows and _setvideomoderows */
+#define _MAXTEXTROWS (-1)
+
+short _far _cdecl _settextrows(short); /* returns # rows set; 0 if error */
+void _far _cdecl _settextwindow(short, short, short, short);
+void _far _cdecl _gettextwindow(short _far *, short _far *, short _far *, short _far *);
+void _far _cdecl _scrolltextwindow(short);
+void _far _cdecl _outmem(const unsigned char _far *, short);
+void _far _cdecl _outtext(const unsigned char _far *);
+short _far _cdecl _wrapon(short);
+
+short _far _cdecl _displaycursor(short);
+short _far _cdecl _settextcursor(short);
+short _far _cdecl _gettextcursor(void);
+
+struct rccoord _far _cdecl _settextposition(short, short);
+struct rccoord _far _cdecl _gettextposition(void);
+
+short _far _cdecl _settextcolor(short);
+short _far _cdecl _gettextcolor(void);
+
+
+/* SCREEN IMAGES */
+
+void _far _cdecl _getimage(short, short, short, short, char _huge *);
+void _far _cdecl _putimage(short, short, char _huge *, short);
+long _far _cdecl _imagesize(short, short, short, short);
+
+/* "action verbs" for _putimage() and _setwritemode() */
+#define _GPSET 3
+#define _GPRESET 2
+#define _GAND 1
+#define _GOR 0
+#define _GXOR 4
+
+
+/* Color values are used with _setbkcolor in graphics modes and also by
+ _remappalette and _remapallpalette. Also known as palette colors.
+ Not to be confused with color indices (aka. color attributes). */
+
+/* universal color values (all color modes): */
+#define _BLACK 0x000000L
+#define _BLUE 0x2a0000L
+#define _GREEN 0x002a00L
+#define _CYAN 0x2a2a00L
+#define _RED 0x00002aL
+#define _MAGENTA 0x2a002aL
+#define _BROWN 0x00152aL
+#define _WHITE 0x2a2a2aL
+#define _GRAY 0x151515L
+#define _LIGHTBLUE 0x3F1515L
+#define _LIGHTGREEN 0x153f15L
+#define _LIGHTCYAN 0x3f3f15L
+#define _LIGHTRED 0x15153fL
+#define _LIGHTMAGENTA 0x3f153fL
+#define _YELLOW 0x153f3fL
+#define _BRIGHTWHITE 0x3f3f3fL
+
+/* the following is obsolescent and defined only for backward compatibility */
+#define _LIGHTYELLOW _YELLOW
+
+/* mono mode F (_ERESNOCOLOR) color values: */
+#define _MODEFOFF 0L
+#define _MODEFOFFTOON 1L
+#define _MODEFOFFTOHI 2L
+#define _MODEFONTOOFF 3L
+#define _MODEFON 4L
+#define _MODEFONTOHI 5L
+#define _MODEFHITOOFF 6L
+#define _MODEFHITOON 7L
+#define _MODEFHI 8L
+
+/* mono mode 7 (_TEXTMONO) color values: */
+#define _MODE7OFF 0L
+#define _MODE7ON 1L
+#define _MODE7HI 2L
+
+
+/* Warning: these '_xy' entrypoints are undocumented.
+ They may or may not be supported in future versions. */
+struct xycoord _far _cdecl _moveto_xy(struct xycoord);
+short _far _cdecl _lineto_xy(struct xycoord);
+short _far _cdecl _rectangle_xy(short,struct xycoord,struct xycoord);
+short _far _cdecl _arc_xy(struct xycoord, struct xycoord, struct xycoord, struct xycoord);
+short _far _cdecl _ellipse_xy(short, struct xycoord, struct xycoord);
+short _far _cdecl _pie_xy(short, struct xycoord, struct xycoord, struct xycoord, struct xycoord);
+short _far _cdecl _getpixel_xy(struct xycoord);
+short _far _cdecl _setpixel_xy(struct xycoord);
+short _far _cdecl _floodfill_xy(struct xycoord, short);
+void _far _cdecl _getimage_xy(struct xycoord,struct xycoord, char _huge *);
+long _far _cdecl _imagesize_xy(struct xycoord,struct xycoord);
+void _far _cdecl _putimage_xy(struct xycoord, char _huge *, short);
+
+
+/* WINDOW COORDINATE SYSTEM */
+
+#ifndef _WXYCOORD_DEFINED
+/* structure for window coordinate pair */
+struct _wxycoord {
+ double wx; /* window x coordinate */
+ double wy; /* window y coordinate */
+ };
+#define _WXYCOORD_DEFINED
+#endif
+
+
+/* define real coordinate window - returns non-zero if successful */
+short _far _cdecl _setwindow(short,double,double,double,double);
+
+/* convert from view to window coordinates */
+struct _wxycoord _far _cdecl _getwindowcoord(short,short);
+struct _wxycoord _far _cdecl _getwindowcoord_xy(struct xycoord);
+
+/* convert from window to view coordinates */
+struct xycoord _far _cdecl _getviewcoord_w(double,double);
+struct xycoord _far _cdecl _getviewcoord_wxy(const struct _wxycoord _far *);
+
+/* return the window coordinates of the current graphics output
+ position as an _wxycoord structure. no error return. */
+struct _wxycoord _far _cdecl _getcurrentposition_w(void);
+
+
+/* window coordinate entry points for graphics output routines */
+
+/* returns nonzero if successful; otherwise 0 */
+short _far _cdecl _arc_w(double, double, double, double, double, double, double, double);
+short _far _cdecl _arc_wxy(const struct _wxycoord _far *, const struct _wxycoord _far *, const struct _wxycoord _far *, const struct _wxycoord _far *);
+
+/* returns nonzero if successful; otherwise 0 */
+short _far _cdecl _ellipse_w(short, double, double, double, double);
+short _far _cdecl _ellipse_wxy(short, const struct _wxycoord _far *, const struct _wxycoord _far *);
+
+/* returns nonzero if successful; otherwise 0 */
+short _far _cdecl _floodfill_w(double, double, short);
+
+/* returns pixel value at given point; -1 if unsuccessful. */
+short _far _cdecl _getpixel_w(double, double);
+
+/* returns nonzero if successful; otherwise 0 */
+short _far _cdecl _lineto_w(double, double);
+
+/* returns the view coordinates of the previous output
+ position as an _xycoord structure. no error return */
+struct _wxycoord _far _cdecl _moveto_w(double, double);
+
+/* returns nonzero if successful; otherwise 0 */
+short _far _cdecl _pie_w(short, double, double, double, double, double, double, double, double);
+short _far _cdecl _pie_wxy(short, const struct _wxycoord _far *, const struct _wxycoord _far *, const struct _wxycoord _far *, const struct _wxycoord _far *);
+
+/* returns nonzero if successful; otherwise 0 */
+short _far _cdecl _rectangle_w(short, double, double, double, double);
+short _far _cdecl _rectangle_wxy(short, const struct _wxycoord _far *, const struct _wxycoord _far *);
+
+/* returns nonzero if successful; otherwise 0 */
+short _far _cdecl _polygon_w(short, const double _far *, short);
+short _far _cdecl _polygon_wxy(short, const struct _wxycoord _far *, short);
+
+/* returns previous color; -1 if unsuccessful */
+short _far _cdecl _setpixel_w(double, double);
+
+
+/* window coordinate image routines */
+
+/* no return value */
+void _far _cdecl _getimage_w(double, double, double, double, char _huge *);
+void _far _cdecl _getimage_wxy(const struct _wxycoord _far *, const struct _wxycoord _far *, char _huge *);
+
+/* returns the image's storage size in bytes */
+long _far _cdecl _imagesize_w(double, double, double, double);
+long _far _cdecl _imagesize_wxy(const struct _wxycoord _far *, const struct _wxycoord _far *);
+
+/* no return value */
+void _far _cdecl _putimage_w(double, double ,char _huge * ,short);
+
+
+/* FONTS */
+
+#ifndef _FONTINFO_DEFINED
+/* structure for _getfontinfo() */
+struct _fontinfo {
+ int type; /* b0 set = vector,clear = bit map */
+ int ascent; /* pix dist from top to baseline */
+ int pixwidth; /* character width in pixels, 0=prop */
+ int pixheight; /* character height in pixels */
+ int avgwidth; /* average character width in pixels */
+ char filename[81]; /* file name including path */
+ char facename[32]; /* font name */
+};
+#define _FONTINFO_DEFINED
+#endif
+
+
+/* font function prototypes */
+short _far _cdecl _registerfonts( const unsigned char _far *);
+void _far _cdecl _unregisterfonts( void );
+short _far _cdecl _setfont( const unsigned char _far * );
+short _far _cdecl _getfontinfo( struct _fontinfo _far * );
+void _far _cdecl _outgtext( const unsigned char _far * );
+short _far _cdecl _getgtextextent( const unsigned char _far * );
+struct xycoord _far _cdecl _setgtextvector( short, short );
+struct xycoord _far _cdecl _getgtextvector(void);
+
+/* restore default packing */
+#pragma pack()
diff --git a/private/os2/client/thunk/include/int2fapi.inc b/private/os2/client/thunk/include/int2fapi.inc
new file mode 100644
index 000000000..0e827a37b
--- /dev/null
+++ b/private/os2/client/thunk/include/int2fapi.inc
@@ -0,0 +1,85 @@
+;******************************************************************************
+;
+; (C) Copyright MICROSOFT Corp., 1989-1990
+;
+; Title: INT2FAPI.INC - Windows/386 V86 Application Program Interface
+;
+; Version: 3.00
+;
+; Date: 10-Mar-1989
+;
+; Author: RAL
+;
+;------------------------------------------------------------------------------
+;
+; Change log:
+;
+; DATE REV DESCRIPTION
+; ----------- --- -----------------------------------------------------------
+; 10-Mar-1989 RAL Original for 3.0
+; 07-Apr-1989 RAL Added device broadcast equate
+;
+;==============================================================================
+;
+; For inforamtion on these APIs please refer to the Windows/386 DDK
+; appendix on the Int 2Fh Application Program Interface.
+;
+;------------------------------------------------------------------------------
+
+;
+; Interrupt 2Fh is used for Windows/386 API calls.
+;
+W386_API_Int EQU 2Fh
+
+;
+; All Windows/386 API Int 2Fh calls must be issued with AH = 16h
+;
+W386_Int_Multiplex EQU 16h
+
+;
+; Values for AL for all Windows/386 API calls
+;
+W386_Get_Version EQU 00h ; Install check/Get version
+W386_Old_Get_VMID_API EQU 02h ; Version 2.xx get VMID API call
+W386_Startup EQU 05h ; Broadcast when Win386 starting
+W386_Exit EQU 06h ; Broadcast when Win386 exited
+W386_Device_Broadcast EQU 07h ; Broadcast by virtual device
+W386_Startup_Complete EQU 08h ; Broadcast when Win386 start is complete
+W386_Begin_Exit EQU 09h ; Broadcast when Win386 is starting
+ ; a NORMAL exit sequence
+W386_Release_Time EQU 80h ; Release cur VM's time-slice
+W386_Begin_Critical EQU 81h ; Begin critical section
+W386_End_Critical EQU 82h ; End critical section
+W386_Get_Cur_VMID EQU 83h ; Returns BX = ID of current VM
+W386_Get_Device_API EQU 84h ; Returns ES:DI -> Device API
+W386_Switch_And_Call EQU 85h ; Change VMs and call-back
+W386_Test_Int31_Avail EQU 86h ; Returns AX=0 if Int 31 avail
+W386_Get_PM_Switch_Addr EQU 87h ; Get call-back addr for PM
+W386_Get_LDT_Base_Sel EQU 88h ; Get selector to LDT
+W386_Win_Kernel_Idle EQU 89h ; Windows kernel idle call
+
+;
+; Structure for real mode device initialization API.
+;
+Win386_Startup_Info_Struc STRUC
+SIS_Version db 3, 0 ; Structure version
+SIS_Next_Ptr dd ? ; Seg:Off of next dev in list
+SIS_Virt_Dev_File_Ptr dd 0 ; Ptr to ASCIZ file name to load
+SIS_Reference_Data dd ? ; Data to be passed to device
+SIS_Instance_Data_Ptr dd 0 ; Ptr to instance data list
+Win386_Startup_Info_Struc ENDS
+
+;
+; Structure for instance data list. (List terminated with 0 dword).
+;
+Instance_Item_Struc STRUC
+IIS_Ptr dd ? ; Seg:Off of instance item
+IIS_Size dw ? ; Size of instance item in bytes
+Instance_Item_Struc ENDS
+
+;
+; Flags passed to the Win_Kernel_Idle call to indicate state of Windows
+; in the BX register.
+;
+Win_Idle_Mouse_Busy EQU 00000001b
+Win_Idle_Mouse_Busy_Bit EQU 0
diff --git a/private/os2/client/thunk/include/int31.inc b/private/os2/client/thunk/include/int31.inc
new file mode 100644
index 000000000..83eca01d7
--- /dev/null
+++ b/private/os2/client/thunk/include/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/os2/client/thunk/include/io.h b/private/os2/client/thunk/include/io.h
new file mode 100644
index 000000000..17771c35e
--- /dev/null
+++ b/private/os2/client/thunk/include/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/os2/client/thunk/include/krnl32.h b/private/os2/client/thunk/include/krnl32.h
new file mode 100644
index 000000000..3e2c215a8
--- /dev/null
+++ b/private/os2/client/thunk/include/krnl32.h
@@ -0,0 +1,132 @@
+/* Win32 kernel prototypes
+ *
+ * 11.27.90 KevinR wrote it
+ * 12.21.90 KevinR added SYSTEM, KEYBOARD, MOUSE thunks
+ * 01.28.91 KevinR added UnlockResource() macro
+ *
+ */
+
+#define APIENTRY pascal
+
+
+/* The following APIs are called from the C runtimes. They are aliased
+ * because the 32=>16 thunks must export them with "32" in the name so
+ * as to avoid colliding with the 16-bit API names used by the CRT.
+ */
+#define LocalAlloc LocalAlloc32
+#define LocalFree LocalFree32
+#define LocalReAlloc LocalReAlloc32
+#define GlobalAlloc GlobalAlloc32
+#define GlobalFree GlobalFree32
+#define GlobalReAlloc GlobalReAlloc32
+#define FatalExit FatalExit32
+#define FatalAppExit FatalAppExit32
+#define InitTask InitTask32
+#define WaitEvent WaitEvent32
+#define LockSegment LockSegment32
+#define UnlockSegment UnlockSegment32
+#define OutputDebugString OutputDebugString32
+
+
+#define UnlockResource(h) GlobalUnlock(h)
+
+typedef unsigned short USHORT;
+typedef unsigned long ULONG;
+typedef long LONG;
+typedef unsigned long HANDLE;
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+typedef WORD ATOM;
+typedef char *LPSTR;
+typedef char *LPVOID;
+typedef USHORT SEL;
+typedef int INT;
+typedef int BOOL;
+typedef unsigned char BYTE;
+
+typedef LONG FARPROC;
+
+SEL APIENTRY AllocSelector( SEL selector);
+ULONG APIENTRY GetSelectorBase( SEL selector);
+SEL APIENTRY SetSelectorBase( SEL selector, ULONG selbase);
+SEL APIENTRY SetSelectorLimit( SEL selector, ULONG sellimit);
+SEL APIENTRY SelectorAccessRights( SEL selector, USHORT getselflag,
+ USHORT selrights);
+
+
+ATOM APIENTRY AddAtom( LPSTR lpString);
+ATOM APIENTRY DeleteAtom( ATOM nAtom);
+ATOM APIENTRY FindAtom( LPSTR lpString);
+WORD APIENTRY GetAtomName( ATOM nAtom, LPSTR lpBuffer, LONG nSize);
+
+HANDLE APIENTRY LocalAlloc( ULONG fFlags, ULONG cBytes);
+HANDLE APIENTRY LocalFree( HANDLE hMem);
+HANDLE APIENTRY LocalReAlloc( HANDLE hMem, ULONG fFlags, ULONG cBytes);
+ULONG APIENTRY LocalSize( HANDLE hMem);
+
+HANDLE APIENTRY GlobalAlloc( ULONG fFlags, ULONG cBytes);
+HANDLE APIENTRY GlobalFree( HANDLE hMem);
+HANDLE APIENTRY GlobalReAlloc( HANDLE hMem, ULONG fFlags, ULONG cBytes);
+ULONG APIENTRY GlobalSize( HANDLE hMem);
+LPSTR APIENTRY GlobalLock( HANDLE hMem);
+BOOL APIENTRY GlobalUnlock( HANDLE hMem);
+
+
+HANDLE APIENTRY LoadResource( HANDLE hInstance, HANDLE hResInfo);
+HANDLE APIENTRY FindResource( HANDLE hInstance, LPSTR lpName, LPSTR lpType);
+BOOL APIENTRY FreeResource32( HANDLE hResData);
+LPSTR APIENTRY LockResource32( HANDLE hResData);
+HANDLE APIENTRY LoadLibrary( LPSTR lpLibFileName);
+void APIENTRY FreeLibrary( HANDLE hLibModule);
+
+LONG APIENTRY GetPrivateProfileString( LPSTR pszAppName, LPSTR pszKeyName,
+ LPSTR pszDefault, LPSTR pchReturned,
+ LONG nSize, LPSTR pszFileName);
+WORD APIENTRY GetProfileInt( LPSTR pszAppName, LPSTR pszKeyName,
+ LONG nDefault);
+LONG APIENTRY GetProfileString( LPSTR pszAppName, LPSTR pszKeyName,
+ LPSTR pszDefault, LPSTR pchReturned, LONG nSize);
+
+HANDLE APIENTRY GetModuleHandle( LPSTR lpName);
+FARPROC APIENTRY GetProcAddress( HANDLE hModule, LPSTR lpProcName);
+
+void APIENTRY OutputDebugString( LPSTR lpString);
+void APIENTRY FatalExit( INT iCode);
+
+/***************************************************************************
+ * system
+ *
+ */
+
+/* void APIENTRY CreateSystemTimer( LONG, FARPROC); */
+LONG APIENTRY InquireSystem( LONG, LONG);
+void APIENTRY EnableSystemTimers( void);
+void APIENTRY DisableSystemTimers( void);
+long APIENTRY GetSystemMsecCount( void);
+HANDLE APIENTRY DestroySystemTimer( HANDLE hSysTimer);
+
+
+/***************************************************************************
+ * keyboard
+ *
+ */
+
+LONG APIENTRY EnableKeyboard( FARPROC, LPSTR);
+LONG APIENTRY InquireKeyboard( LPSTR);
+void APIENTRY DisableKeyboard( void);
+LONG APIENTRY SetSpeed( WORD);
+LONG APIENTRY AnsiToOem( LPSTR, LPSTR);
+BOOL APIENTRY OemToAnsi( LPSTR, LPSTR);
+void APIENTRY AnsiToOemBuff( LPSTR, LPSTR, LONG);
+void APIENTRY OemToAnsiBuff( LPSTR, LPSTR, LONG);
+LONG APIENTRY ToAscii( WORD wVirtKey, WORD wScanCode, LPSTR lpKeyState, LPVOID lpChar, WORD wFlags);
+
+
+/***************************************************************************
+ * mouse
+ *
+ */
+
+LONG APIENTRY EnableMouse( FARPROC);
+LONG APIENTRY InquireMouse( LPSTR);
+void APIENTRY DisableMouse( void);
diff --git a/private/os2/client/thunk/include/limits.h b/private/os2/client/thunk/include/limits.h
new file mode 100644
index 000000000..0e924762e
--- /dev/null
+++ b/private/os2/client/thunk/include/limits.h
@@ -0,0 +1,33 @@
+/***
+*limits.h - implementation dependent values
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Contains defines for a number of implementation dependent values
+* which are commonly used in C programs.
+* [ANSI]
+*
+****/
+
+#define CHAR_BIT 8 /* number of bits in a char */
+#define SCHAR_MIN (-127) /* minimum signed char value */
+#define SCHAR_MAX 127 /* maximum signed char value */
+#define UCHAR_MAX 0xff /* maximum unsigned char value */
+#ifndef _CHAR_UNSIGNED
+#define CHAR_MIN SCHAR_MIN /* mimimum char value */
+#define CHAR_MAX SCHAR_MAX /* maximum char value */
+#else
+#define CHAR_MIN 0
+#define CHAR_MAX UCHAR_MAX
+#endif
+#define MB_LEN_MAX 1 /* max. # bytes in multibyte char */
+#define SHRT_MIN (-32767) /* minimum (signed) short value */
+#define SHRT_MAX 32767 /* maximum (signed) short value */
+#define USHRT_MAX 0xffff /* maximum unsigned short value */
+#define INT_MIN (-32767) /* minimum (signed) int value */
+#define INT_MAX 32767 /* maximum (signed) int value */
+#define UINT_MAX 0xffff /* maximum unsigned int value */
+#define LONG_MIN (-2147483647) /* minimum (signed) long value */
+#define LONG_MAX 2147483647 /* maximum (signed) long value */
+#define ULONG_MAX 0xffffffff /* maximum unsigned long value */
diff --git a/private/os2/client/thunk/include/locale.h b/private/os2/client/thunk/include/locale.h
new file mode 100644
index 000000000..1e1de7500
--- /dev/null
+++ b/private/os2/client/thunk/include/locale.h
@@ -0,0 +1,78 @@
+/***
+*locale.h - definitions/declarations for localization routines
+*
+* Copyright (c) 1988-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file defines the structures, values, macros, and functions
+* used by the localization routines.
+* [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
+
+
+/* Locale categories */
+
+#define LC_ALL 0
+#define LC_COLLATE 1
+#define LC_CTYPE 2
+#define LC_MONETARY 3
+#define LC_NUMERIC 4
+#define LC_TIME 5
+
+#define LC_MIN LC_ALL
+#define LC_MAX LC_TIME
+
+
+/* Locale convention structure */
+
+#ifndef _LCONV_DEFINED
+struct lconv {
+ char *decimal_point;
+ char *thousands_sep;
+ char *grouping;
+ char *int_curr_symbol;
+ char *currency_symbol;
+ char *mon_decimal_point;
+ char *mon_thousands_sep;
+ char *mon_grouping;
+ char *positive_sign;
+ char *negative_sign;
+ char int_frac_digits;
+ char frac_digits;
+ char p_cs_precedes;
+ char p_sep_by_space;
+ char n_cs_precedes;
+ char n_sep_by_space;
+ char p_sign_posn;
+ char n_sign_posn;
+ };
+#define _LCONV_DEFINED
+#endif
+
+/* function prototypes */
+
+char _FAR_ * _FAR_ _cdecl setlocale(int, const char _FAR_ *);
+struct lconv _FAR_ * _FAR_ _cdecl localeconv(void);
diff --git a/private/os2/client/thunk/include/malloc.h b/private/os2/client/thunk/include/malloc.h
new file mode 100644
index 000000000..156c3fe38
--- /dev/null
+++ b/private/os2/client/thunk/include/malloc.h
@@ -0,0 +1,136 @@
+/***
+*malloc.h - declarations and definitions for memory allocation functions
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Contains the function declarations for memory allocation functions;
+* also defines manifest constants and types used by the heap routines.
+* [System V]
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+
+/* constants for based heap routines */
+
+#if (_MSC_VER >= 600)
+#define _NULLSEG ((_segment)0)
+#define _NULLOFF ((void _based(void) *)0xffff)
+#endif
+
+
+/* constants for _heapchk/_heapset/_heapwalk routines */
+
+#define _HEAPEMPTY (-1)
+#define _HEAPOK (-2)
+#define _HEAPBADBEGIN (-3)
+#define _HEAPBADNODE (-4)
+#define _HEAPEND (-5)
+#define _HEAPBADPTR (-6)
+#define _FREEENTRY 0
+#define _USEDENTRY 1
+
+
+/* maximum heap request that can ever be honored */
+
+#define _HEAP_MAXREQ 0xFFE8
+
+
+/* types and structures */
+
+#ifndef _SIZE_T_DEFINED
+typedef unsigned int size_t;
+#define _SIZE_T_DEFINED
+#endif
+
+
+#ifndef _HEAPINFO_DEFINED
+typedef struct _heapinfo {
+ int _far * _pentry;
+ size_t _size;
+ int _useflag;
+ } _HEAPINFO;
+#define _HEAPINFO_DEFINED
+#endif
+
+
+/* external variable declarations */
+
+#ifdef _DLL
+extern unsigned int _FAR_ _cdecl _amblksiz;
+#else
+extern unsigned int _near _cdecl _amblksiz;
+#endif
+
+
+/* based heap function prototypes */
+
+#if (_MSC_VER >= 600)
+void _based(void) * _FAR_ _cdecl _bcalloc(_segment, size_t, size_t);
+void _based(void) * _FAR_ _cdecl _bexpand(_segment,
+ void _based(void) *, size_t);
+void _FAR_ _cdecl _bfree(_segment, void _based(void) *);
+int _FAR_ _cdecl _bfreeseg(_segment);
+int _FAR_ _cdecl _bheapadd(_segment, void _based(void) *, size_t);
+int _FAR_ _cdecl _bheapchk(_segment);
+int _FAR_ _cdecl _bheapmin(_segment);
+_segment _FAR_ _cdecl _bheapseg(size_t);
+int _FAR_ _cdecl _bheapset(_segment, unsigned int);
+int _FAR_ _cdecl _bheapwalk(_segment, _HEAPINFO *);
+void _based(void) * _FAR_ _cdecl _bmalloc(_segment, size_t);
+size_t _FAR_ _cdecl _bmsize(_segment, void _based(void) *);
+void _based(void) * _FAR_ _cdecl _brealloc(_segment,
+ void _based(void) *, size_t);
+#endif
+
+
+/* function prototypes */
+
+void _FAR_ * _FAR_ _cdecl alloca(size_t);
+void _FAR_ * _FAR_ _cdecl calloc(size_t, size_t);
+void _FAR_ * _FAR_ _cdecl _expand(void _FAR_ *, size_t);
+void _far * _FAR_ _cdecl _fcalloc(size_t, size_t);
+void _far * _FAR_ _cdecl _fexpand(void _far *, size_t);
+void _FAR_ _cdecl _ffree(void _far *);
+int _FAR_ _cdecl _fheapchk(void);
+int _FAR_ _cdecl _fheapmin(void);
+int _FAR_ _cdecl _fheapset(unsigned int);
+int _FAR_ _cdecl _fheapwalk(_HEAPINFO _FAR_ *);
+void _far * _FAR_ _cdecl _fmalloc(size_t);
+size_t _FAR_ _cdecl _fmsize(void _far *);
+void _far * _FAR_ _cdecl _frealloc(void _far *, size_t);
+unsigned int _FAR_ _cdecl _freect(size_t);
+void _FAR_ _cdecl free(void _FAR_ *);
+void _huge * _FAR_ _cdecl halloc(long, size_t);
+void _FAR_ _cdecl hfree(void _huge *);
+int _FAR_ _cdecl _heapadd(void _far *, size_t);
+int _FAR_ _cdecl _heapchk(void);
+int _FAR_ _cdecl _heapmin(void);
+int _FAR_ _cdecl _heapset(unsigned int);
+int _FAR_ _cdecl _heapwalk(_HEAPINFO _FAR_ *);
+void _FAR_ * _FAR_ _cdecl malloc(size_t);
+size_t _FAR_ _cdecl _memavl(void);
+size_t _FAR_ _cdecl _memmax(void);
+size_t _FAR_ _cdecl _msize(void _FAR_ *);
+void _near * _FAR_ _cdecl _ncalloc(size_t, size_t);
+void _near * _FAR_ _cdecl _nexpand(void _near *, size_t);
+void _FAR_ _cdecl _nfree(void _near *);
+int _FAR_ _cdecl _nheapchk(void);
+int _FAR_ _cdecl _nheapmin(void);
+int _FAR_ _cdecl _nheapset(unsigned int);
+int _FAR_ _cdecl _nheapwalk(_HEAPINFO _FAR_ *);
+void _near * _FAR_ _cdecl _nmalloc(size_t);
+size_t _FAR_ _cdecl _nmsize(void _near *);
+void _near * _FAR_ _cdecl _nrealloc(void _near *, size_t);
+void _FAR_ * _FAR_ _cdecl realloc(void _FAR_ *, size_t);
+size_t _FAR_ _cdecl stackavail(void);
diff --git a/private/os2/client/thunk/include/math.h b/private/os2/client/thunk/include/math.h
new file mode 100644
index 000000000..05219ff78
--- /dev/null
+++ b/private/os2/client/thunk/include/math.h
@@ -0,0 +1,235 @@
+/***
+*math.h - definitions and declarations for math library
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file contains constant definitions and external subroutine
+* declarations for the math subroutine library.
+* [ANSI/System V]
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+
+/* definition of exception struct - this struct is passed to the matherr
+ * routine when a floating point exception is detected
+ */
+
+#ifndef _EXCEPTION_DEFINED
+struct exception {
+ int type; /* exception type - see below */
+ char _FAR_ *name; /* name of function where error occured */
+ double arg1; /* first argument to function */
+ double arg2; /* second argument (if any) to function */
+ double retval; /* value to be returned by function */
+ } ;
+#define _EXCEPTION_DEFINED
+#endif
+
+
+/* definition of a complex struct to be used by those who use cabs and
+ * want type checking on their argument
+ */
+
+#ifndef _COMPLEX_DEFINED
+struct complex {
+ double x,y; /* real and imaginary parts */
+ } ;
+#define _COMPLEX_DEFINED
+#endif
+
+
+/* Constant definitions for the exception type passed in the exception struct
+ */
+
+#define DOMAIN 1 /* argument domain error */
+#define SING 2 /* argument singularity */
+#define OVERFLOW 3 /* overflow range error */
+#define UNDERFLOW 4 /* underflow range error */
+#define TLOSS 5 /* total loss of precision */
+#define PLOSS 6 /* partial loss of precision */
+
+#define EDOM 33
+#define ERANGE 34
+
+
+/* definitions of HUGE and HUGE_VAL - respectively the XENIX and ANSI names
+ * for a value returned in case of error by a number of the floating point
+ * math routines
+ */
+
+#ifndef _DLL
+extern double _near _cdecl HUGE;
+#define HUGE_VAL HUGE
+
+#else /* _DLL */
+extern double _FAR_ _cdecl HUGE;
+#define HUGE_VAL HUGE
+
+#endif /* _DLL */
+
+
+/* function prototypes */
+
+#ifdef _MT /* function prototypes for _MT version */
+int _FAR_ _cdecl abs(int);
+double _FAR_ _pascal acos(double);
+double _FAR_ _pascal asin(double);
+double _FAR_ _pascal atan(double);
+double _FAR_ _pascal atan2(double, double);
+double _FAR_ _pascal atof(const char _FAR_ *);
+double _FAR_ _pascal cabs(struct complex);
+double _FAR_ _pascal ceil(double);
+double _FAR_ _pascal cos(double);
+double _FAR_ _pascal cosh(double);
+int _FAR_ _cdecl dieeetomsbin(double _FAR_ *, double _FAR_ *);
+int _FAR_ _cdecl dmsbintoieee(double _FAR_ *, double _FAR_ *);
+double _FAR_ _pascal exp(double);
+double _FAR_ _pascal fabs(double);
+int _FAR_ _cdecl fieeetomsbin(float _FAR_ *, float _FAR_ *);
+double _FAR_ _pascal floor(double);
+double _FAR_ _pascal fmod(double, double);
+int _FAR_ _cdecl fmsbintoieee(float _FAR_ *, float _FAR_ *);
+double _FAR_ _pascal frexp(double, int _FAR_ *);
+double _FAR_ _pascal hypot(double, double);
+double _FAR_ _pascal j0(double);
+double _FAR_ _pascal j1(double);
+double _FAR_ _pascal jn(int, double);
+long _FAR_ _cdecl labs(long);
+double _FAR_ _pascal ldexp(double, int);
+double _FAR_ _pascal log(double);
+double _FAR_ _pascal log10(double);
+int _FAR_ _cdecl matherr(struct exception _FAR_ *);
+double _FAR_ _pascal modf(double, double _FAR_ *);
+double _FAR_ _pascal pow(double, double);
+double _FAR_ _pascal sin(double);
+double _FAR_ _pascal sinh(double);
+double _FAR_ _pascal sqrt(double);
+double _FAR_ _pascal tan(double);
+double _FAR_ _pascal tanh(double);
+double _FAR_ _pascal y0(double);
+double _FAR_ _pascal y1(double);
+double _FAR_ _pascal yn(int, double);
+
+#else /* function prototypes for non _MT version */
+int _FAR_ _cdecl abs(int);
+double _FAR_ _cdecl acos(double);
+double _FAR_ _cdecl asin(double);
+double _FAR_ _cdecl atan(double);
+double _FAR_ _cdecl atan2(double, double);
+double _FAR_ _cdecl atof(const char _FAR_ *);
+double _FAR_ _cdecl cabs(struct complex);
+double _FAR_ _cdecl ceil(double);
+double _FAR_ _cdecl cos(double);
+double _FAR_ _cdecl cosh(double);
+int _FAR_ _cdecl dieeetomsbin(double _FAR_ *, double _FAR_ *);
+int _FAR_ _cdecl dmsbintoieee(double _FAR_ *, double _FAR_ *);
+double _FAR_ _cdecl exp(double);
+double _FAR_ _cdecl fabs(double);
+int _FAR_ _cdecl fieeetomsbin(float _FAR_ *, float _FAR_ *);
+double _FAR_ _cdecl floor(double);
+double _FAR_ _cdecl fmod(double, double);
+int _FAR_ _cdecl fmsbintoieee(float _FAR_ *, float _FAR_ *);
+double _FAR_ _cdecl frexp(double, int _FAR_ *);
+double _FAR_ _cdecl hypot(double, double);
+double _FAR_ _cdecl j0(double);
+double _FAR_ _cdecl j1(double);
+double _FAR_ _cdecl jn(int, double);
+long _FAR_ _cdecl labs(long);
+double _FAR_ _cdecl ldexp(double, int);
+double _FAR_ _cdecl log(double);
+double _FAR_ _cdecl log10(double);
+int _FAR_ _cdecl matherr(struct exception _FAR_ *);
+double _FAR_ _cdecl modf(double, double _FAR_ *);
+double _FAR_ _cdecl pow(double, double);
+double _FAR_ _cdecl sin(double);
+double _FAR_ _cdecl sinh(double);
+double _FAR_ _cdecl sqrt(double);
+double _FAR_ _cdecl tan(double);
+double _FAR_ _cdecl tanh(double);
+double _FAR_ _cdecl y0(double);
+double _FAR_ _cdecl y1(double);
+double _FAR_ _cdecl yn(int, double);
+#endif
+
+
+/* definition of _exceptionl struct - this struct is passed to the _matherrl
+ * routine when a floating point exception is detected in a long double routine
+ */
+
+#ifndef _LD_EXCEPTION_DEFINED
+struct _exceptionl {
+ int type; /* exception type - see below */
+ char _FAR_ *name; /* name of function where error occured */
+ long double arg1; /* first argument to function */
+ long double arg2; /* second argument (if any) to function */
+ long double retval; /* value to be returned by function */
+ } ;
+#define _LD_EXCEPTION_DEFINED
+#endif
+
+
+/* definition of a _complexl struct to be used by those who use _cabsl and
+ * want type checking on their argument
+ */
+
+#ifndef _LD_COMPLEX_DEFINED
+struct _complexl {
+ long double x,y; /* real and imaginary parts */
+ } ;
+#define _LD_COMPLEX_DEFINED
+#endif
+
+
+#ifndef _DLL
+extern long double _near _cdecl _LHUGE;
+#define _LHUGE_VAL _LHUGE
+
+#else /* _DLL */
+extern long double _FAR_ _cdecl _LHUGE;
+#define _LHUGE_VAL _LHUGE
+
+#endif /* _DLL */
+
+long double _FAR_ _cdecl acosl(long double);
+long double _FAR_ _cdecl asinl(long double);
+long double _FAR_ _cdecl atanl(long double);
+long double _FAR_ _cdecl atan2l(long double, long double);
+long double _FAR_ _cdecl _atold(const char _FAR_ *);
+long double _FAR_ _cdecl cabsl(struct _complexl);
+long double _FAR_ _cdecl ceill(long double);
+long double _FAR_ _cdecl cosl(long double);
+long double _FAR_ _cdecl coshl(long double);
+long double _FAR_ _cdecl expl(long double);
+long double _FAR_ _cdecl fabsl(long double);
+long double _FAR_ _cdecl floorl(long double);
+long double _FAR_ _cdecl fmodl(long double, long double);
+long double _FAR_ _cdecl frexpl(long double, int _FAR_ *);
+long double _FAR_ _cdecl hypotl(long double, long double);
+long double _FAR_ _cdecl _j0l(long double);
+long double _FAR_ _cdecl _j1l(long double);
+long double _FAR_ _cdecl _jnl(int, long double);
+long double _FAR_ _cdecl ldexpl(long double, int);
+long double _FAR_ _cdecl logl(long double);
+long double _FAR_ _cdecl log10l(long double);
+int _FAR_ _cdecl _matherrl(struct _exceptionl _FAR_ *);
+long double _FAR_ _cdecl modfl(long double, long double _FAR_ *);
+long double _FAR_ _cdecl powl(long double, long double);
+long double _FAR_ _cdecl sinl(long double);
+long double _FAR_ _cdecl sinhl(long double);
+long double _FAR_ _cdecl sqrtl(long double);
+long double _FAR_ _cdecl tanl(long double);
+long double _FAR_ _cdecl tanhl(long double);
+long double _FAR_ _cdecl _y0l(long double);
+long double _FAR_ _cdecl _y1l(long double);
+long double _FAR_ _cdecl _ynl(int, long double);
diff --git a/private/os2/client/thunk/include/memory.h b/private/os2/client/thunk/include/memory.h
new file mode 100644
index 000000000..4729feee8
--- /dev/null
+++ b/private/os2/client/thunk/include/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/os2/client/thunk/include/newexe.h b/private/os2/client/thunk/include/newexe.h
new file mode 100644
index 000000000..e2292ce79
--- /dev/null
+++ b/private/os2/client/thunk/include/newexe.h
@@ -0,0 +1,363 @@
+/*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 */
+
+ unsigned short int ne_psegcsum; /* offset to segment chksums */
+ 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_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 */
+
+/* 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
diff --git a/private/os2/client/thunk/include/newexe.inc b/private/os2/client/thunk/include/newexe.inc
new file mode 100644
index 000000000..ab72c915f
--- /dev/null
+++ b/private/os2/client/thunk/include/newexe.inc
@@ -0,0 +1,321 @@
+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)
+
+;
+; 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 = 1
+NEINFONT = 2 ; WIN30 - 2.x app runs in 3.x prot mode
+NEINPROT = 4 ; WIN30 - 2.x app gets proportional font
+NEGANGLOAD = 8 ; WIN30 - Contains gangload area
+
+
+; 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
+
+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
+
+RNUNUSED = 0EF8Bh ; 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/os2/client/thunk/include/pgchart.h b/private/os2/client/thunk/include/pgchart.h
new file mode 100644
index 000000000..52d38b02e
--- /dev/null
+++ b/private/os2/client/thunk/include/pgchart.h
@@ -0,0 +1,219 @@
+/***
+*pgchart.h - Declare constants, functions and macros for charting library.
+*
+* Copyright (c) 1988-1990, Microsoft Corporation, All rights reserved.
+*
+*Purpose:
+* This file declares the presentation graphics library functions and
+* the structures and manifest constants that are used with them.
+*
+***************************************************************************/
+
+/* Force word alignment to avoid possible -Zp override */
+#pragma pack(2)
+
+/* Required for the missing value definition */
+#define FLT_MAX 3.402823466e+38F /* max value */
+
+#define _PG_PALETTELEN 16 /* Number of entries in internal palette */
+#define _PG_MAXCHARTTYPE 5 /* Maximum available chart type */
+#define _PG_MAXCHARTSTYLE 2 /* Maximum chart style */
+#define _PG_TITLELEN 70 /* Maximum title text length */
+
+#define _PG_LEFT 1 /* Positions used for titles and legends */
+#define _PG_CENTER 2
+#define _PG_RIGHT 3
+#define _PG_BOTTOM 4
+#define _PG_OVERLAY 5
+
+#define _PG_LINEARAXIS 1 /* Used to specify axis types */
+#define _PG_LOGAXIS 2
+
+#define _PG_DECFORMAT 1 /* Used to specify tic mark label format */
+#define _PG_EXPFORMAT 2
+
+#define _PG_BARCHART 1 /* Charttype for a bar chart */
+#define _PG_COLUMNCHART 2 /* Charttype for a column chart */
+#define _PG_PLAINBARS 1 /* Styles for bar and column charts */
+#define _PG_STACKEDBARS 2
+
+#define _PG_LINECHART 3 /* Charttype for a line chart */
+#define _PG_SCATTERCHART 4 /* Charttype for a scatter chart */
+#define _PG_POINTANDLINE 1 /* Styles for line and scatter charts */
+#define _PG_POINTONLY 2
+
+#define _PG_PIECHART 5 /* Charttype for pie chart */
+#define _PG_PERCENT 1 /* Styles for pie charts */
+#define _PG_NOPERCENT 2
+
+#define _PG_MISSINGVALUE -FLT_MAX /* Indicates missing data values */
+
+/* Error codes */
+
+/* Numbers greater than 100 will terminate chart routine, others will cause
+ * default values to be used
+ */
+#define _PG_NOTINITIALIZED 102 /* If library not initialized */
+#define _PG_BADSCREENMODE 103 /* Graphics mode not set before charting */
+#define _PG_BADCHARTSTYLE 04 /* Chart style invalid */
+#define _PG_BADCHARTTYPE 104 /* Chart type invalid */
+#define _PG_BADLEGENDWINDOW 105 /* Invalid legend window specified */
+#define _PG_BADCHARTWINDOW 07 /* x1=x2 or y1=y2 in chart window spec. */
+#define _PG_BADDATAWINDOW 107 /* If chart window is too small */
+#define _PG_NOMEMORY 108 /* Not enough memory for data arrays */
+#define _PG_BADLOGBASE 05 /* Log base <= 0 */
+#define _PG_BADSCALEFACTOR 06 /* Scale factor = 0 */
+#define _PG_TOOSMALLN 109 /* Number of data points <= 0 */
+#define _PG_TOOFEWSERIES 110 /* Number of series <= 0 */
+
+/* Typedefs */
+
+/* Typedef for chart title */
+#ifndef _TITLETYPE_DEFINED
+typedef struct {
+ char title[_PG_TITLELEN]; /* Title text */
+ short titlecolor; /* Internal palette color for title text */
+ short justify; /* _PG_LEFT, _PG_CENTER, _PG_RIGHT */
+} titletype;
+#define _TITLETYPE_DEFINED
+#endif
+
+/* Typedef for chart axes */
+#ifndef _AXISTYPE_DEFINED
+typedef struct {
+ short grid; /* TRUE=grid lines drawn; FALSE no lines */
+ short gridstyle; /* Style number from style pool for grid lines */
+ titletype axistitle; /* Title definition for axis */
+ short axiscolor; /* Color for axis */
+ short labeled; /* TRUE=tic marks and titles drawn */
+ short rangetype; /* _PG_LINEARAXIS, _PG_LOGAXIS */
+ float logbase; /* Base used if log axis */
+ short autoscale; /* TRUE=next 7 values calculated by system */
+ float scalemin; /* Minimum value of scale */
+ float scalemax; /* Maximum value of scale */
+ float scalefactor; /* Scale factor for data on this axis */
+ titletype scaletitle; /* Title definition for scaling factor */
+ float ticinterval; /* Distance between tic marks (world coord.) */
+ short ticformat; /* _PG_EXPFORMAT or _PG_DECFORMAT for tic labels */
+ short ticdecimals; /* Number of decimals for tic labels (max=9)*/
+} axistype;
+#define _AXISTYPE_DEFINED
+#endif
+
+/* Typedef used for defining chart and data windows */
+#ifndef _WINDOWTYPE_DEFINED
+typedef struct {
+ short x1; /* Left edge of window in pixels */
+ short y1; /* Top edge of window in pixels */
+ short x2; /* Right edge of window in pixels */
+ short y2; /* Bottom edge of window in pixels */
+ short border; /* TRUE for border, FALSE otherwise */
+ short background; /* Internal palette color for window bgnd */
+ short borderstyle; /* Style bytes for window border */
+ short bordercolor; /* Internal palette color for window border */
+} windowtype;
+#define _WINDOWTYPE_DEFINED
+#endif
+
+/* Typedef for legend definition */
+#ifndef _LEGENDTYPE_DEFINED
+typedef struct {
+ short legend; /* TRUE=draw legend; FALSE=no legend */
+ short place; /* _PG_RIGHT, _PG_BOTTOM, _PG_OVERLAY */
+ short textcolor; /* Internal palette color for text */
+ short autosize; /* TRUE=system calculates size */
+ windowtype legendwindow; /* Window definition for legend */
+} legendtype;
+#define _LEGENDTYPE_DEFINED
+#endif
+
+/* Typedef for legend definition */
+#ifndef _CHARTENV_DEFINED
+typedef struct {
+ short charttype; /* _PG_BAR, _PG_COLUMN, _PG_LINE, _PG_SCATTER, _PG_PIE */
+ short chartstyle; /* Style for selected chart type */
+ windowtype chartwindow; /* Window definition for overall chart */
+ windowtype datawindow; /* Window definition for data part of chart */
+ titletype maintitle; /* Main chart title */
+ titletype subtitle; /* Chart sub-title */
+ axistype xaxis; /* Definition for X-axis */
+ axistype yaxis; /* Definition for Y-axis */
+ legendtype legend; /* Definition for legend */
+} chartenv;
+#define _CHARTENV_DEFINED
+#endif
+
+/* Typedef for character bitmap */
+#ifndef _CHARMAP_DEFINED
+typedef unsigned char charmap[8];
+#define _CHARMAP_DEFINED
+#endif
+
+/* Typedef for pattern bitmap */
+#ifndef _FILLMAP_DEFINED
+typedef unsigned char fillmap[8];
+#define _FILLMAP_DEFINED
+#endif
+
+/* Typedef for palette entry definition */
+#ifndef _PALETTEENTRY_DEFINED
+typedef struct {
+ unsigned short color;
+ unsigned short style;
+ fillmap fill;
+ char plotchar;
+} paletteentry;
+#define _PALETTEENTRY_DEFINED
+#endif
+
+/* Typedef for palette definition */
+#ifndef _PALETTETYPE_DEFINED
+typedef paletteentry palettetype[_PG_PALETTELEN];
+#define _PALETTETYPE_DEFINED
+#endif
+
+/* Typedef for style sets */
+#ifndef _STYLESET_DEFINED
+typedef unsigned short styleset[_PG_PALETTELEN];
+#define _STYLESET_DEFINED
+#endif
+
+/* Function prototypes for charting routines */
+
+short _far _cdecl _pg_initchart(void);
+short _far _cdecl _pg_defaultchart(chartenv _far *, short, short);
+
+short _far _cdecl _pg_chart(chartenv _far *, char _far * _far *, float _far *, short);
+short _far _cdecl _pg_chartms(chartenv _far *, char _far * _far *, float _far *, short, short, short, char _far * _far *);
+
+short _far _cdecl _pg_chartscatter(chartenv _far *, float _far *, float _far *, short);
+short _far _cdecl _pg_chartscatterms(chartenv _far *, float _far *, float _far *, short, short, short, char _far * _far *);
+
+short _far _cdecl _pg_chartpie(chartenv _far *, char _far * _far *, float _far *, short _far *, short);
+
+/* Function prototypes for support routines */
+
+short _far _cdecl _pg_hlabelchart(chartenv _far *, short, short, short, char _far *);
+short _far _cdecl _pg_vlabelchart(chartenv _far *, short, short, short, char _far *);
+
+short _far _cdecl _pg_analyzechart(chartenv _far *, char _far * _far *, float _far *, short);
+short _far _cdecl _pg_analyzechartms(chartenv _far *, char _far * _far *, float _far *, short, short, short, char _far * _far *);
+
+short _far _cdecl _pg_analyzescatter(chartenv _far *, float _far *, float _far *, short);
+short _far _cdecl _pg_analyzescatterms(chartenv _far *, float _far *, float _far *, short, short, short, char _far * _far *);
+
+short _far _cdecl _pg_analyzepie(chartenv _far *, char _far * _far *, float _far *, short _far *, short);
+
+short _far _cdecl _pg_getpalette(paletteentry _far *);
+short _far _cdecl _pg_setpalette(paletteentry _far *);
+short _far _cdecl _pg_resetpalette(void);
+
+void _far _cdecl _pg_getstyleset(unsigned short _far *);
+void _far _cdecl _pg_setstyleset(unsigned short _far *);
+void _far _cdecl _pg_resetstyleset(void);
+
+short _far _cdecl _pg_getchardef(short, unsigned char _far *);
+short _far _cdecl _pg_setchardef(short, unsigned char _far *);
+
+/* Restore default packing */
+#pragma pack()
diff --git a/private/os2/client/thunk/include/prd.inc b/private/os2/client/thunk/include/prd.inc
new file mode 100644
index 000000000..c85c5c385
--- /dev/null
+++ b/private/os2/client/thunk/include/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/os2/client/thunk/include/printer.h b/private/os2/client/thunk/include/printer.h
new file mode 100644
index 000000000..276828f6c
--- /dev/null
+++ b/private/os2/client/thunk/include/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
+#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/os2/client/thunk/include/process.h b/private/os2/client/thunk/include/process.h
new file mode 100644
index 000000000..2bb18fddc
--- /dev/null
+++ b/private/os2/client/thunk/include/process.h
@@ -0,0 +1,91 @@
+/***
+*process.h - definition and declarations for process control functions
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file contains the declarations and definitions for the
+* spawnxx, execxx, and various other process control routines.
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+/* mode values for spawnxx routines
+ * (only P_WAIT and P_OVERLAY are supported on MS-DOS)
+ */
+
+#ifndef _MT
+extern int _near _cdecl _p_overlay;
+#endif
+
+#define P_WAIT 0
+#define P_NOWAIT 1
+#ifdef _MT
+#define P_OVERLAY 2
+#else
+#define P_OVERLAY _p_overlay
+#endif
+#define OLD_P_OVERLAY 2
+#define P_NOWAITO 3
+#define P_DETACH 4
+
+
+/* action codes used with cwait() */
+
+#define WAIT_CHILD 0
+#define WAIT_GRANDCHILD 1
+
+
+/* function prototypes */
+
+#ifdef _MT
+int _FAR_ _cdecl _beginthread(void(_cdecl _FAR_ *)(void _FAR_ *),
+ void _FAR_ *, unsigned, void _FAR_ *);
+void _FAR_ _cdecl _endthread(void);
+#endif
+void _FAR_ _cdecl abort(void);
+void _FAR_ _cdecl _cexit(void);
+void _FAR_ _cdecl _c_exit(void);
+int _FAR_ _cdecl cwait(int _FAR_ *, int, int);
+int _FAR_ _cdecl execl(const char _FAR_ *, const char _FAR_ *, ...);
+int _FAR_ _cdecl execle(const char _FAR_ *, const char _FAR_ *, ...);
+int _FAR_ _cdecl execlp(const char _FAR_ *, const char _FAR_ *, ...);
+int _FAR_ _cdecl execlpe(const char _FAR_ *, const char _FAR_ *, ...);
+int _FAR_ _cdecl execv(const char _FAR_ *,
+ const char _FAR_ * const _FAR_ *);
+int _FAR_ _cdecl execve(const char _FAR_ *,
+ const char _FAR_ * const _FAR_ *, const char _FAR_ * const _FAR_ *);
+int _FAR_ _cdecl execvp(const char _FAR_ *,
+ const char _FAR_ * const _FAR_ *);
+int _FAR_ _cdecl execvpe(const char _FAR_ *,
+ const char _FAR_ * const _FAR_ *, const char _FAR_ * const _FAR_ *);
+void _FAR_ _cdecl exit(int);
+void _FAR_ _cdecl _exit(int);
+int _FAR_ _cdecl getpid(void);
+int _FAR_ _cdecl spawnl(int, const char _FAR_ *, const char _FAR_ *,
+ ...);
+int _FAR_ _cdecl spawnle(int, const char _FAR_ *, const char _FAR_ *,
+ ...);
+int _FAR_ _cdecl spawnlp(int, const char _FAR_ *, const char _FAR_ *,
+ ...);
+int _FAR_ _cdecl spawnlpe(int, const char _FAR_ *, const char _FAR_ *,
+ ...);
+int _FAR_ _cdecl spawnv(int, const char _FAR_ *,
+ const char _FAR_ * const _FAR_ *);
+int _FAR_ _cdecl spawnve(int, const char _FAR_ *,
+ const char _FAR_ * const _FAR_ *, const char _FAR_ * const _FAR_ *);
+int _FAR_ _cdecl spawnvp(int, const char _FAR_ *,
+ const char _FAR_ * const _FAR_ *);
+int _FAR_ _cdecl spawnvpe(int, const char _FAR_ *,
+ const char _FAR_ * const _FAR_ *, const char _FAR_ * const _FAR_ *);
+int _FAR_ _cdecl system(const char _FAR_ *);
+int _FAR_ _cdecl wait(int _FAR_ *);
diff --git a/private/os2/client/thunk/include/search.h b/private/os2/client/thunk/include/search.h
new file mode 100644
index 000000000..ec94cd80d
--- /dev/null
+++ b/private/os2/client/thunk/include/search.h
@@ -0,0 +1,41 @@
+/***
+*search.h - declarations for searcing/sorting routines
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file contains the declarations for the sorting and
+* searching 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 lsearch(const void _FAR_ *, void _FAR_ *,
+ unsigned int _FAR_ *, unsigned int, int (_FAR_ _cdecl *)
+ (const void _FAR_ *, const void _FAR_ *));
+void _FAR_ * _FAR_ _cdecl lfind(const void _FAR_ *, const void _FAR_ *,
+ unsigned int _FAR_ *, unsigned int, int (_FAR_ _cdecl *)
+ (const void _FAR_ *, const void _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_ _cdecl qsort(void _FAR_ *, size_t, size_t, int (_FAR_ _cdecl *)
+ (const void _FAR_ *, const void _FAR_ *));
diff --git a/private/os2/client/thunk/include/setjmp.h b/private/os2/client/thunk/include/setjmp.h
new file mode 100644
index 000000000..43c3d08e8
--- /dev/null
+++ b/private/os2/client/thunk/include/setjmp.h
@@ -0,0 +1,37 @@
+/***
+*setjmp.h - definitions/declarations for setjmp/longjmp routines
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file defines the machine-dependent buffer used by
+* setjmp/longjmp to save and restore the program state, and
+* declarations for those 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
+
+/* define the buffer type for holding the state information */
+
+#define _JBLEN 9 /* bp, di, si, sp, ret addr, ds */
+
+#ifndef _JMP_BUF_DEFINED
+typedef int jmp_buf[_JBLEN];
+#define _JMP_BUF_DEFINED
+#endif
+
+
+/* function prototypes */
+
+int _FAR_ _cdecl setjmp(jmp_buf);
+void _FAR_ _cdecl longjmp(jmp_buf, int);
diff --git a/private/os2/client/thunk/include/share.h b/private/os2/client/thunk/include/share.h
new file mode 100644
index 000000000..c333ca5fb
--- /dev/null
+++ b/private/os2/client/thunk/include/share.h
@@ -0,0 +1,15 @@
+/***
+*share.h - defines file sharing modes for sopen
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file defines the file sharing modes for sopen().
+*
+****/
+
+#define SH_COMPAT 0x00 /* compatibility mode */
+#define SH_DENYRW 0x10 /* deny read/write mode */
+#define SH_DENYWR 0x20 /* deny write mode */
+#define SH_DENYRD 0x30 /* deny read mode */
+#define SH_DENYNO 0x40 /* deny none mode */
diff --git a/private/os2/client/thunk/include/signal.h b/private/os2/client/thunk/include/signal.h
new file mode 100644
index 000000000..233960928
--- /dev/null
+++ b/private/os2/client/thunk/include/signal.h
@@ -0,0 +1,71 @@
+/***
+*signal.h - defines signal values and routines
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file defines the signal values and declares the signal 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
+
+#ifdef _DLL
+#define _LOADDS_ _loadds
+#else
+#define _LOADDS_
+#endif
+
+#ifndef _SIG_ATOMIC_T_DEFINED
+typedef int sig_atomic_t;
+#define _SIG_ATOMIC_T_DEFINED
+#endif
+
+
+#define NSIG 23 /* maximum signal number + 1 */
+
+/* signal types */
+/* SIGINT, SIGFPE, SIGILL, SIGSEGV, and SIGABRT are recognized on DOS 3.x */
+
+#define SIGINT 2 /* interrupt - corresponds to DOS 3.x int 23H */
+#define SIGILL 4 /* illegal instruction - invalid function image */
+#define SIGFPE 8 /* floating point exception */
+#define SIGSEGV 11 /* segment violation */
+#define SIGTERM 15 /* Software termination signal from kill */
+#define SIGUSR1 16 /* User defined signal 1 */
+#define SIGUSR2 17 /* User defined signal 2 */
+#define SIGUSR3 20 /* User defined signal 3 */
+#define SIGBREAK 21 /* Ctrl-Break sequence */
+#define SIGABRT 22 /* abnormal termination triggered by abort call */
+
+
+/* signal action codes */
+/* SIG_DFL and SIG_IGN are recognized on DOS 3.x */
+
+#define SIG_DFL (void (_FAR_ _cdecl _LOADDS_ *)())0 /* default signal action */
+#define SIG_IGN (void (_FAR_ _cdecl _LOADDS_ *)())1 /* ignore */
+#define SIG_SGE (void (_FAR_ _cdecl _LOADDS_ *)())3 /* signal gets error */
+#define SIG_ACK (void (_FAR_ _cdecl _LOADDS_ *)())4 /* error if handler not setup */
+
+
+/* signal error value (returned by signal call on error) */
+
+#define SIG_ERR (void (_FAR_ _cdecl _LOADDS_ *)())-1 /* signal error value */
+
+
+/* function prototypes */
+
+void (_FAR_ _cdecl _LOADDS_ * _FAR_ _cdecl signal(int,
+ void (_FAR_ _cdecl _LOADDS_ *)()))();
+#ifndef _MT
+int _FAR_ _cdecl raise(int);
+#endif
diff --git a/private/os2/client/thunk/include/spool.h b/private/os2/client/thunk/include/spool.h
new file mode 100644
index 000000000..9b82a5a8f
--- /dev/null
+++ b/private/os2/client/thunk/include/spool.h
@@ -0,0 +1,174 @@
+#define LWORD(x) ((short)((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 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_ISPORTFREE 0x1005
+#define SP_CHANGEPORT 0x1006
+
+/* in /windows/oem/printer.h */
+#define SP_QUERYDISKAVAIL 0x1004
+
+
+/* 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_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 {
+ short type; /* type of dialog. This will tell whether it is */
+ /* call back function or pure dialog etc */
+ short size; /* size of special function data */
+ short 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 10 /* allow 10 ports to be listed under win.ini */
+#define MAXPORT MAXPORTLIST
+#define MAXSPOOL 20
+#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 {
+ short pnum;
+ short printeratom;
+ long txtimeout;
+ long dnstimeout;
+}JCBQ;
+
+typedef struct jcb {
+ unsigned type;
+ short pagecnt;
+ short maxpage;
+ short portnum;
+ HANDLE hDC;
+ short chBuf;
+ long timeSpooled;
+ char buffer[JCBBUF_LEN];
+ unsigned long size;
+ char jobName[NAME_LEN];
+ short page[MAXPAGE];
+}JCB;
+
+typedef struct page {
+ short 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
+
+typedef struct
+{
+ short type;
+ short fn;
+ long retry; /* system timer on first error */
+} PORT;
+
+#ifdef library
+
+/* _SPOOL library routines */
+
+JCB FAR * NEAR PASCAL IsJobValid(HANDLE);
+void NEAR PASCAL NameSpoolFile(LPSTR, short, short);
+short NEAR PASCAL WriteFile(JCB far *, PAGE far *, LPSTR, short);
+void NEAR PASCAL lstrncpy(LPSTR, LPSTR, short);
+short NEAR PASCAL FreeAll(HANDLE, JCB far *);
+short FAR PASCAL OutOfDiskHandler(HANDLE, LPSTR, short, short);
+short FAR PASCAL FindAllPorts();
+
+/* job queue control routines */
+
+FAR removecolon(LPSTR, LPSTR);
+FAR ValidPort(LPSTR);
+
+short FAR FindAtom(LPSTR);
+short FAR AddAtom(LPSTR);
+short FAR GetAtomName(short, LPSTR, short);
+short FAR PASCAL FindPort(short);
+FAR FindPrinterNames(LPSTR);
+
+#endif
+
+/* exported routines */
+LONG FAR PASCAL GetSpoolJob(short, long);
+char FAR PASCAL GetSpoolTempDrive();
diff --git a/private/os2/client/thunk/include/stdarg.h b/private/os2/client/thunk/include/stdarg.h
new file mode 100644
index 000000000..0bad49596
--- /dev/null
+++ b/private/os2/client/thunk/include/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/os2/client/thunk/include/stddef.h b/private/os2/client/thunk/include/stddef.h
new file mode 100644
index 000000000..7ef8eeed3
--- /dev/null
+++ b/private/os2/client/thunk/include/stddef.h
@@ -0,0 +1,65 @@
+/***
+*stddef.h - definitions/declarations for common constants, types, variables
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file contains definitions and declarations for some commonly
+* used constants, types, and variables.
+* [ANSI]
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+/* define the NULL pointer value and the offsetof() macro */
+
+#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
+
+#define offsetof(s,m) (size_t)&(((s *)0)->m)
+
+
+/* declare reference to errno */
+
+#ifdef _MT
+extern int _far * _cdecl _far volatile _errno(void);
+#define errno (*_errno())
+#else
+extern int _near _cdecl volatile errno;
+#endif
+
+
+/* define the implementation dependent size types */
+
+#ifndef _PTRDIFF_T_DEFINED
+typedef int ptrdiff_t;
+#define _PTRDIFF_T_DEFINED
+#endif
+
+#ifndef _SIZE_T_DEFINED
+typedef unsigned int size_t;
+#define _SIZE_T_DEFINED
+#endif
+
+
+#ifdef _MT
+/* define pointer to thread id value */
+
+extern int _far *_threadid;
+#endif
diff --git a/private/os2/client/thunk/include/stdio.h b/private/os2/client/thunk/include/stdio.h
new file mode 100644
index 000000000..dc8cf8c61
--- /dev/null
+++ b/private/os2/client/thunk/include/stdio.h
@@ -0,0 +1,224 @@
+/***
+*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 */
+
+#define stdin (&_iob[0])
+#define stdout (&_iob[1])
+#define stderr (&_iob[2])
+#define stdaux (&_iob[3])
+#define stdprn (&_iob[4])
+
+
+#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_ *);
+int _FAR_ _cdecl fgetchar(void);
+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_ *);
+int _FAR_ _cdecl fprintf(FILE _FAR_ *, const char _FAR_ *, ...);
+int _FAR_ _cdecl fputc(int, FILE _FAR_ *);
+int _FAR_ _cdecl fputchar(int);
+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_ *);
+int _FAR_ _cdecl fscanf(FILE _FAR_ *, const char _FAR_ *, ...);
+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_ *);
+int _FAR_ _cdecl getchar(void);
+char _FAR_ * _FAR_ _cdecl gets(char _FAR_ *);
+int _FAR_ _cdecl getw(FILE _FAR_ *);
+void _FAR_ _cdecl perror(const char _FAR_ *);
+int _FAR_ _cdecl _pclose(FILE _FAR_ *);
+FILE _FAR_ * _FAR_ _cdecl _popen(const char _FAR_ *,
+ const char _FAR_ *);
+int _FAR_ _cdecl printf(const char _FAR_ *, ...);
+int _FAR_ _cdecl putc(int, FILE _FAR_ *);
+int _FAR_ _cdecl putchar(int);
+int _FAR_ _cdecl puts(const char _FAR_ *);
+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);
+int _FAR_ _cdecl scanf(const char _FAR_ *, ...);
+void _FAR_ _cdecl setbuf(FILE _FAR_ *, char _FAR_ *);
+int _FAR_ _cdecl setvbuf(FILE _FAR_ *, char _FAR_ *, int, size_t);
+int _FAR_ _cdecl sprintf(char _FAR_ *, const char _FAR_ *, ...);
+int _FAR_ _cdecl sscanf(const char _FAR_ *, const char _FAR_ *, ...);
+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_ *);
+int _FAR_ _cdecl vfprintf(FILE _FAR_ *, const char _FAR_ *, va_list);
+int _FAR_ _cdecl vprintf(const char _FAR_ *, va_list);
+int _FAR_ _cdecl vsprintf(char _FAR_ *, const char _FAR_ *, va_list);
+#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)))
+#define getchar() getc(stdin)
+#define putchar(_c) putc((_c),stdout)
+
+#ifdef _MT
+#undef getc
+#undef putc
+#undef getchar
+#undef putchar
+#endif
diff --git a/private/os2/client/thunk/include/stdlib.h b/private/os2/client/thunk/include/stdlib.h
new file mode 100644
index 000000000..fce135fe2
--- /dev/null
+++ b/private/os2/client/thunk/include/stdlib.h
@@ -0,0 +1,204 @@
+/***
+*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 */
+
+extern unsigned char _near _cdecl _osmajor;
+extern unsigned char _near _cdecl _osminor;
+
+#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);
+char _FAR_ * _FAR_ _cdecl gcvt(double, int, char _FAR_ *);
+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);
+void _FAR_ _cdecl perror(const char _FAR_ *);
+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);
+int _FAR_ _cdecl system(const char _FAR_ *);
+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/os2/client/thunk/include/string.h b/private/os2/client/thunk/include/string.h
new file mode 100644
index 000000000..2c39b8d91
--- /dev/null
+++ b/private/os2/client/thunk/include/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/os2/client/thunk/include/style.h b/private/os2/client/thunk/include/style.h
new file mode 100644
index 000000000..0e5bbd7fe
--- /dev/null
+++ b/private/os2/client/thunk/include/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/os2/client/thunk/include/sys/locking.h b/private/os2/client/thunk/include/sys/locking.h
new file mode 100644
index 000000000..fc097cb3b
--- /dev/null
+++ b/private/os2/client/thunk/include/sys/locking.h
@@ -0,0 +1,16 @@
+/***
+*sys\locking.h - flags for locking() function
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file defines the flags for the locking() function.
+* [System V]
+*
+****/
+
+#define LK_UNLCK 0 /* unlock the file region */
+#define LK_LOCK 1 /* lock the file region */
+#define LK_NBLCK 2 /* non-blocking lock */
+#define LK_RLCK 3 /* lock for writing */
+#define LK_NBRLCK 4 /* non-blocking lock for writing */
diff --git a/private/os2/client/thunk/include/sys/stat.h b/private/os2/client/thunk/include/sys/stat.h
new file mode 100644
index 000000000..61d4f3575
--- /dev/null
+++ b/private/os2/client/thunk/include/sys/stat.h
@@ -0,0 +1,59 @@
+/***
+*sys\stat.h - defines structure used by stat() and fstat()
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file defines the structure used by the stat() and fstat()
+* 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 _TIME_T_DEFINED
+typedef long time_t;
+#define _TIME_T_DEFINED
+#endif
+
+/* define structure for returning status information */
+
+#ifndef _STAT_DEFINED
+struct stat {
+ dev_t st_dev;
+ ino_t st_ino;
+ unsigned short st_mode;
+ short st_nlink;
+ short st_uid;
+ short st_gid;
+ dev_t st_rdev;
+ off_t st_size;
+ time_t st_atime;
+ time_t st_mtime;
+ time_t st_ctime;
+ };
+#define _STAT_DEFINED
+#endif
+
+#define S_IFMT 0170000 /* file type mask */
+#define S_IFDIR 0040000 /* directory */
+#define S_IFCHR 0020000 /* character special */
+#define S_IFREG 0100000 /* regular */
+#define S_IREAD 0000400 /* read permission, owner */
+#define S_IWRITE 0000200 /* write permission, owner */
+#define S_IEXEC 0000100 /* execute/search permission, owner */
+
+
+/* function prototypes */
+
+int _FAR_ _cdecl fstat(int, struct stat _FAR_ *);
+int _FAR_ _cdecl stat(char _FAR_ *, struct stat _FAR_ *);
diff --git a/private/os2/client/thunk/include/sys/timeb.h b/private/os2/client/thunk/include/sys/timeb.h
new file mode 100644
index 000000000..8b84fd1ce
--- /dev/null
+++ b/private/os2/client/thunk/include/sys/timeb.h
@@ -0,0 +1,42 @@
+/***
+*sys\timeb.h - definition/declarations for ftime()
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file define the ftime() function and the types it uses.
+* [System V]
+*
+*******************************************************************************/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+#ifndef _TIME_T_DEFINED
+typedef long time_t;
+#define _TIME_T_DEFINED
+#endif
+
+/* structure returned by ftime system call */
+
+#ifndef _TIMEB_DEFINED
+struct timeb {
+ time_t time;
+ unsigned short millitm;
+ short timezone;
+ short dstflag;
+ };
+#define _TIMEB_DEFINED
+#endif
+
+
+/* function prototypes */
+
+void _FAR_ _cdecl ftime(struct timeb _FAR_ *);
diff --git a/private/os2/client/thunk/include/sys/types.h b/private/os2/client/thunk/include/sys/types.h
new file mode 100644
index 000000000..87041cdc2
--- /dev/null
+++ b/private/os2/client/thunk/include/sys/types.h
@@ -0,0 +1,31 @@
+/***
+*sys\types.h - types returned by system level calls for file and time info
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file defines types used in defining values returned by system
+* level calls for file status and time information.
+* [System V]
+*
+****/
+
+#ifndef _INO_T_DEFINED
+typedef unsigned short ino_t; /* i-node number (not used on DOS) */
+#define _INO_T_DEFINED
+#endif
+
+#ifndef _TIME_T_DEFINED
+typedef long time_t;
+#define _TIME_T_DEFINED
+#endif
+
+#ifndef _DEV_T_DEFINED
+typedef short dev_t; /* device code */
+#define _DEV_T_DEFINED
+#endif
+
+#ifndef _OFF_T_DEFINED
+typedef long off_t; /* file offset value */
+#define _OFF_T_DEFINED
+#endif
diff --git a/private/os2/client/thunk/include/sys/utime.h b/private/os2/client/thunk/include/sys/utime.h
new file mode 100644
index 000000000..60acf8177
--- /dev/null
+++ b/private/os2/client/thunk/include/sys/utime.h
@@ -0,0 +1,43 @@
+/***
+*sys\utime.h - definitions/declarations for utime()
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file defines the structure used by the utime routine to set
+* new file access and modification times. NOTE - MS-DOS
+* does not recognize access time, so this field will
+* always be ignored and the modification time field will be
+* used to set the new time.
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+#ifndef _TIME_T_DEFINED
+typedef long time_t;
+#define _TIME_T_DEFINED
+#endif
+
+/* define struct used by utime() function */
+
+#ifndef _UTIMBUF_DEFINED
+struct utimbuf {
+ time_t actime; /* access time */
+ time_t modtime; /* modification time */
+ };
+#define _UTIMBUF_DEFINED
+#endif
+
+
+/* function prototypes */
+
+int _FAR_ _cdecl utime(char _FAR_ *, struct utimbuf _FAR_ *);
diff --git a/private/os2/client/thunk/include/sysinfo.inc b/private/os2/client/thunk/include/sysinfo.inc
new file mode 100644
index 000000000..31d999879
--- /dev/null
+++ b/private/os2/client/thunk/include/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/os2/client/thunk/include/tdb.inc b/private/os2/client/thunk/include/tdb.inc
new file mode 100644
index 000000000..638a8510e
--- /dev/null
+++ b/private/os2/client/thunk/include/tdb.inc
@@ -0,0 +1,208 @@
+;
+; 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
+
+THUNKELEM EQU 8 ; (62*8) = 512-16 (low arena overhead)
+THUNKSIZE EQU 8
+
+; Task data structure
+
+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
+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.
+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
+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.
+
+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/os2/client/thunk/include/testing.h b/private/os2/client/thunk/include/testing.h
new file mode 100644
index 000000000..ab1a9ea3a
--- /dev/null
+++ b/private/os2/client/thunk/include/testing.h
@@ -0,0 +1,43 @@
+/*---------------------------------------------------------*\
+| |
+| 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 FAR PASCAL UserSeeUserDo(WORD wMsg, WORD wParam, LONG lParam);
+LONG FAR PASCAL 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
+ */
diff --git a/private/os2/client/thunk/include/time.h b/private/os2/client/thunk/include/time.h
new file mode 100644
index 000000000..a078c7006
--- /dev/null
+++ b/private/os2/client/thunk/include/time.h
@@ -0,0 +1,114 @@
+/***
+*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_ *);
+clock_t _FAR_ _cdecl clock(void);
+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_ *);
+size_t _FAR_ _cdecl strftime(char _FAR_ *, size_t, const char _FAR_ *,
+ const struct tm _FAR_ *);
+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/os2/client/thunk/include/userproc.h b/private/os2/client/thunk/include/userproc.h
new file mode 100644
index 000000000..523b6d663
--- /dev/null
+++ b/private/os2/client/thunk/include/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;
+ DWORD dwData;
+ POINT ptDrop;
+ DWORD 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);
+
+DWORD FAR PASCAL DragObject(HWND hwndParent, HWND hwndFrom, WORD wFmt,
+ DWORD 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/os2/client/thunk/include/varargs.h b/private/os2/client/thunk/include/varargs.h
new file mode 100644
index 000000000..8fd73ba43
--- /dev/null
+++ b/private/os2/client/thunk/include/varargs.h
@@ -0,0 +1,43 @@
+/***
+*varargs.h - XENIX style macros for variable argument functions
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file defines XENIX style macros for accessing arguments of a
+* function which takes a variable number of arguments.
+* [System V]
+*
+****/
+
+#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_dcl va_list va_alist;
+#define va_start(ap) ap = (va_list)&va_alist
+#define va_arg(ap,t) ((t _FAR_ *)(ap += sizeof(t)))[-1]
+#define va_end(ap) ap = NULL
diff --git a/private/os2/client/thunk/include/vdmad.inc b/private/os2/client/thunk/include/vdmad.inc
new file mode 100644
index 000000000..d6379f0ac
--- /dev/null
+++ b/private/os2/client/thunk/include/vdmad.inc
@@ -0,0 +1,143 @@
+;******************************************************************************
+;
+; (C) Copyright MICROSOFT Corp. 1986-1990
+;
+; Title: VDMAD.INC - includes for Virtual DMA driver
+;
+; Version: 2.00
+;
+; Date: 28-Nov-1988
+;
+; Author: RAP
+;
+;******************************************************************************
+;
+; Change log:
+;
+; DATE REVISION DESCRIPTION
+; -------- -------- -------------------------------------------------------
+; 12/16/86 Original
+;
+; 28-Nov-1988 RAP v 2.0
+;
+;==============================================================================
+
+IFNDEF Not_VxD
+
+Begin_Service_Table VDMAD
+
+VDMAD_Service VDMAD_Get_Version, LOCAL
+VDMAD_Service VDMAD_Virtualize_Channel, LOCAL
+VDMAD_Service VDMAD_Get_Region_Info, LOCAL
+VDMAD_Service VDMAD_Set_Region_Info, LOCAL
+VDMAD_Service VDMAD_Get_Virt_State, LOCAL
+VDMAD_Service VDMAD_Set_Virt_State, LOCAL
+VDMAD_Service VDMAD_Set_Phys_State, LOCAL
+VDMAD_Service VDMAD_Mask_Channel, LOCAL
+VDMAD_Service VDMAD_UnMask_Channel, LOCAL
+VDMAD_Service VDMAD_Lock_DMA_Region, LOCAL
+VDMAD_Service VDMAD_Unlock_DMA_Region, LOCAL
+VDMAD_Service VDMAD_Scatter_Lock, LOCAL
+VDMAD_Service VDMAD_Scatter_Unlock, LOCAL
+VDMAD_Service VDMAD_Reserve_Buffer_Space, LOCAL
+VDMAD_Service VDMAD_Request_Buffer, LOCAL
+VDMAD_Service VDMAD_Release_Buffer, LOCAL
+VDMAD_Service VDMAD_Copy_To_Buffer, LOCAL
+VDMAD_Service VDMAD_Copy_From_Buffer, LOCAL
+VDMAD_Service VDMAD_Default_Handler, LOCAL
+VDMAD_Service VDMAD_Disable_Translation, LOCAL
+VDMAD_Service VDMAD_Enable_Translation, LOCAL
+VDMAD_Service VDMAD_Get_EISA_Adr_Mode, LOCAL
+VDMAD_Service VDMAD_Set_EISA_Adr_Mode, LOCAL
+
+End_Service_Table VDMAD
+
+
+Function_Mask equ 0F0h
+Channel_Mask equ 07h
+
+;
+; mode bits
+;
+
+DMA_type_verify equ 00000000b
+DMA_type_write equ 00000100b
+DMA_type_read equ 00001000b
+DMA_AutoInit equ 00010000b
+DMA_AdrDec equ 00100000b
+
+DMA_demand_mode equ 00000000b
+DMA_single_mode equ 01000000b
+DMA_block_mode equ 10000000b
+DMA_cascade equ 11000000b
+
+DMA_mode_mask equ 11000000b ; mask to isolate controller mode bits (above)
+
+DMA_chan_sel equ 00000011b
+
+; state flag bits (overlay the unused channel selection bits)
+DMA_masked equ 00000001b
+DMA_masked_bit equ 0
+DMA_requested equ 00000010b
+DMA_req_bit equ 1
+
+
+; extended mode bits
+Programmed_IO equ 00000001b
+Transfer_Data equ 00000100b
+Write_Mem equ 00001000b
+_16_bit_xfer equ 01000000b
+_16_bit_xfer_bit equ 6
+
+ENDIF
+
+DMA_Descriptor_Struc STRUC
+DDS_size dd ?
+DDS_linear dd ?
+DDS_seg dw ?
+DDS_bufferID dw ?
+DDS_physical dd ?
+DMA_Descriptor_Struc ENDS
+
+DDS_sel equ word ptr [DDS_seg]
+
+Extended_DDS_Struc STRUC
+ dd ? ; DDS_size
+ dd ? ; DDS_linear
+ dw ? ; DDS_seg
+ dw ? ; reserved
+DDS_avail dw ?
+DDS_used dw ?
+Extended_DDS_Struc ENDS
+
+
+DMA_Buf_Copy equ 0000000000000010b ; set in copy into/out of buffer
+DMA_Buf_Copy_bit equ 1 ; required in lock or unlock
+DMA_No_Alloc_Buf equ 0000000000000100b ; set if buffer should not be
+DMA_No_Alloc_Buf_bit equ 2 ; alloc'ed if lock not possible
+DMA_Align_64K equ 0000000000010000b ; set if lock must not cross
+DMA_Align_64K_bit equ 4 ; 64k page boundary
+DMA_Align_128K equ 0000000000100000b ; set if lock must not cross
+DMA_Align_128K_bit equ 5 ; 128k page boundary
+DMA_Get_PgTable equ 0000000001000000b ; set if page table copy for
+DMA_Get_PgTable_bit equ 6 ; scatter/gather lock
+DMA_Allow_NPs equ 0000000010000000b ; set if not present pages are
+DMA_Allow_NPs_bit equ 7 ; allowed in scatter/gather lock
+ ; when bit 6 also set
+
+DMA_Not_Contiguous equ 01h
+DMA_Not_Aligned equ 02h
+DMA_Lock_Failed equ 03h
+DMA_No_Buffer equ 04h
+DMA_Buffer_Too_Small equ 05h
+DMA_Buffer_In_Use equ 06h
+DMA_Invalid_Region equ 07h
+DMA_Region_Not_Locked equ 08h
+DMA_Table_Too_Small equ 09h
+DMA_Invalid_Buffer equ 0Ah
+DMA_Copy_Out_Range equ 0Bh
+DMA_Invalid_Channel equ 0Ch
+DMA_Disable_Cnt_Overflow equ 0Dh
+DMA_Disable_Cnt_Underflow equ 0Eh
+DMA_Func_Not_Supported equ 0Fh
+DMA_NonZero_Reserved_Flags equ 10h
diff --git a/private/os2/client/thunk/include/version.h b/private/os2/client/thunk/include/version.h
new file mode 100644
index 000000000..41f493190
--- /dev/null
+++ b/private/os2/client/thunk/include/version.h
@@ -0,0 +1 @@
+#define VERSION "3.1.004"
diff --git a/private/os2/client/thunk/include/vkd.inc b/private/os2/client/thunk/include/vkd.inc
new file mode 100644
index 000000000..a44f024cb
--- /dev/null
+++ b/private/os2/client/thunk/include/vkd.inc
@@ -0,0 +1,172 @@
+;******************************************************************************
+;
+; (C) Copyright MICROSOFT Corp., 1988-1990
+;
+; Title: vkd.inc -
+;
+; Version: 1.00
+;
+; Date: 10-Aug-1988
+;
+; Author: RAP
+;
+;------------------------------------------------------------------------------
+;
+; Change log:
+;
+; DATE REV DESCRIPTION
+; ----------- --- -----------------------------------------------------------
+; 10-Aug-1988 RAP started re-write of VKD
+; 03-Nov-1988 RAP separated internal stuff out into VKDSYS.INC
+;
+;==============================================================================
+
+
+Begin_Service_Table VKD
+
+VKD_Service VKD_Get_Version, LOCAL
+VKD_Service VKD_Define_Hot_Key, LOCAL
+VKD_Service VKD_Remove_Hot_Key, LOCAL
+VKD_Service VKD_Local_Enable_Hot_Key, LOCAL
+VKD_Service VKD_Local_Disable_Hot_Key, LOCAL
+VKD_Service VKD_Reflect_Hot_Key, LOCAL
+VKD_Service VKD_Cancel_Hot_Key_State, LOCAL
+VKD_Service VKD_Force_Keys, LOCAL
+VKD_Service VKD_Get_Kbd_Owner, LOCAL
+VKD_Service VKD_Define_Paste_Mode, LOCAL
+VKD_Service VKD_Start_Paste, LOCAL
+VKD_Service VKD_Cancel_Paste, LOCAL
+VKD_Service VKD_Get_Msg_Key, LOCAL
+VKD_Service VKD_Peek_Msg_Key, LOCAL
+VKD_Service VKD_Flush_Msg_Key_Queue, LOCAL
+
+End_Service_Table VKD
+
+
+VKD_Version equ 200h
+
+
+;******************************************************************************
+;
+; shift state bits for both global & local shift states
+;
+ ;;5432109876543210
+SS_Shift equ 0000000000000001b ; left or right
+SS_LShift equ 0000000000000010b
+SS_RShift equ 0000001000000000b
+SS_Ctrl equ 0000000010000000b ; left or right
+SS_LCtrl equ 0000000000000100b
+SS_RCtrl equ 0000010000000000b
+SS_Alt equ 0000000100000000b ; left or right
+SS_LAlt equ 0000000000001000b
+SS_RAlt equ 0000100000000000b
+SS_CapLock equ 0000000001000000b
+SS_NumLock equ 0000000000100000b
+SS_ScrlLock equ 0000000000010000b
+SS_CapLock_Dn equ 0100000000000000b ; SS_CapLock shl 8
+SS_NumLock_Dn equ 0010000000000000b ; SS_NumLock shl 8
+SS_ScrlLock_Dn equ 0001000000000000b ; SS_ScrlLock shl 8
+SS_Unused equ 1000000000000000b
+
+SS_Toggle_mask equ SS_CapLock + SS_NumLock + SS_ScrlLock
+SS_Toggle_Dn_mask equ SS_CapLock_Dn + SS_NumLock_Dn + SS_ScrlLock_Dn
+SS_LShift_mask equ SS_LShift + SS_LCtrl + SS_LAlt
+SS_Shift_mask equ SS_LShift_mask + SS_RShift + SS_RCtrl + SS_RAlt
+
+SS_Either_Shift equ SS_LShift + SS_RShift
+SS_Either_Ctrl equ SS_LCtrl + SS_RCtrl
+SS_Either_Alt equ SS_LAlt + SS_RAlt
+
+
+; LED state bits
+LED_ScLok equ 1 ; Scroll Lock
+LED_NmLok equ 2 ; Num Lock
+LED_CpLok equ 4 ; Caps Lock
+Toggle_To_LED equ 4 ; "state shr Toggle_To_LED" converts
+ ; state bits into kybd LED bits
+
+
+; VKD_Define_Hot_Key equates & macro
+
+ExtendedKey_B equ 1
+ExtendedKey equ 100h
+AllowExtended_B equ 0FFh
+AllowExtended equ 0FF00h
+
+
+;VKD_Define_Hot_Key flags:
+
+CallOnPress equ 1 ; Call call-back when key press is detected
+CallOnRelease equ 2 ; Call call-back when key release is detected
+ ; (keyboard may still be in hot-key hold state)
+CallOnRepeat equ 4 ; Call call-back when repeated press is detected
+CallOnComplete equ 8 ; Call call-back when the hot key state is
+ ; ended (all shift modifier keys are released)
+ ; or when a different hot key is entered
+ ; (i.e. pressing ALT 1 2, if both ALT-1
+ ; and ALT-2 are defined hot keys, then ALT-1's
+ ; call back will be called before ALT-2's to
+ ; indicate that the ALT-1 is complete even
+ ; though the ALT key is still down)
+CallOnUpDwn equ CallOnPress + CallOnRelease
+ ; Call call-back on both press and release
+CallOnAll equ 0 ; Call call-back on press, release, auto-repeat
+ ; and complete
+PriorityNotify equ 10h ; notification calls to the call-back can only
+ ; happen when interrupts are enabled and
+ ; the critical section is un-owned
+Local_Key equ 80h ; key can be locally enabled/disabled
+
+Hot_Key_Pressed equ 0
+Hot_Key_Released equ 1
+Hot_Key_Repeated equ 2
+Hot_Key_Completed equ 3
+
+Hot_Key_SysVM_Notify equ 80h
+Hot_Key_SysVM_Notify_bit equ 7
+
+BeginDoc
+;******************************************************************************
+;
+; ShiftState
+;
+; DESCRIPTION: Macro to aid in setting EBX with the shift state mask and
+; shift state compare value for calling VKD_Define_Hot_Key.
+;
+; USAGE: ShiftState mask, compare
+;
+; The mask specifies the shift state bits that should be
+; excluded before the compare is done.
+;
+;==============================================================================
+EndDoc
+ShiftState MACRO mask, compare
+ mov ebx, ((NOT mask) SHL 16) + compare
+ ENDM
+
+; common shift states
+
+HKSS_Shift equ (NOT (SS_Either_Shift + SS_Toggle_mask)) SHL 16 + SS_Shift
+HKSS_Ctrl equ (NOT (SS_Either_Ctrl + SS_Toggle_mask)) SHL 16 + SS_Ctrl
+HKSS_Alt equ (NOT (SS_Either_Alt + SS_Toggle_mask)) SHL 16 + SS_Alt
+
+
+; include structure of entries in paste buffer
+
+include VKDpaste.INC
+
+
+; paste completion flags passed to the paste call-back
+
+Paste_Complete equ 0 ; paste successful
+Paste_Aborted equ 1 ; paste aborted by user
+Paste_VM_Term equ 2 ; paste aborted because VM terminated
+
+;
+; Modifier byte for Message Keys, retrieved with services VKD_Get_Msg_Key and
+; VKD_Peek_Msg_Key
+;
+MK_Shift equ 00000010b
+MK_Ctrl equ 00000100b
+MK_Alt equ 00001000b
+MK_Extended equ 10000000b
diff --git a/private/os2/client/thunk/include/vmm.inc b/private/os2/client/thunk/include/vmm.inc
new file mode 100644
index 000000000..47fd7a736
--- /dev/null
+++ b/private/os2/client/thunk/include/vmm.inc
@@ -0,0 +1,2234 @@
+;******************************************************************************
+;
+; (C) Copyright MICROSOFT Corp., 1988-1990
+;
+; Title: VMM.INC - Include file for Virtual Machine Manager
+;
+; Version: 1.00
+;
+; Date: 05-May-1988
+;
+; Author: RAL
+;
+;------------------------------------------------------------------------------
+;
+; Change log:
+;
+; DATE REV DESCRIPTION
+; ----------- --- -----------------------------------------------------------
+; 05-May-1988 RAL Original
+;
+;==============================================================================
+
+
+; NON Windows/386 Virtual Device sources can include this file to get some
+; useful equates by declaring the symbol "Not_VxD" If this symbol is defined,
+; then everything that has to do with the specifics of the 32 bit environment
+; for virtual devices is removed. Useful equates include: device ID's, pushad
+; structure, BeginDoc/EndDoc/BeginMsg/EndMsg equates, page table equates, etc.
+
+
+
+False EQU 0
+True EQU NOT False
+
+;
+; These null macros are recognized by a utility program that produces
+; documentation files.
+;
+BeginDoc EQU <>
+EndDoc EQU <>
+
+BeginMsg EQU <>
+EndMsg EQU <>
+
+
+BeginDoc
+;******************************************************************************
+;
+; EQUATES FOR REQUIRED DEVICES
+;
+; Device ID formulation note:
+;
+; Device ID's are a combination of OEM # and device # in the form:
+;
+; xOOOOOOOOOODDDDD
+;
+; The high bit of the device ID is reserved for future use. The next
+; 10 bits are the OEM # which is assigned by Microsoft. The last 5 bits
+; are the device #. This allows each OEM to create 32 unique devices.
+; If an OEM is creating a replacement for a standard device, then it
+; should re-use the standard ID listed below. Microsoft reserves the
+; first 16 OEM #'s (0 thru 0Fh)
+;
+;==============================================================================
+
+Undefined_Device_ID EQU 00000h
+VMM_Device_ID EQU 00001h ; Used for dynalink table
+Debug_Device_ID EQU 00002h
+VPICD_Device_ID EQU 00003h
+VDMAD_Device_ID EQU 00004h
+VTD_Device_ID EQU 00005h
+V86MMGR_Device_ID EQU 00006h
+PageSwap_Device_ID EQU 00007h
+Parity_Device_ID EQU 00008h
+Reboot_Device_ID EQU 00009h
+VDD_Device_ID EQU 0000Ah
+VSD_Device_ID EQU 0000Bh
+VMD_Device_ID EQU 0000Ch
+VKD_Device_ID EQU 0000Dh
+VCD_Device_ID EQU 0000Eh
+VPD_Device_ID EQU 0000Fh
+VHD_Device_ID EQU 00010h
+VMCPD_Device_ID EQU 00011h
+EBIOS_Device_ID EQU 00012h
+BIOSXlat_Device_ID EQU 00013h
+VNETBIOS_Device_ID EQU 00014h
+DOSMGR_Device_ID EQU 00015h
+WINLOAD_Device_ID EQU 00016h
+SHELL_Device_ID EQU 00017h
+VMPoll_Device_ID EQU 00018h
+VPROD_Device_ID EQU 00019h
+DOSNET_Device_ID EQU 0001Ah
+VFD_Device_ID EQU 0001Bh
+VDD2_Device_ID EQU 0001Ch ; Secondary display adapter
+WINDEBUG_Device_ID EQU 0001Dh
+TSRLoad_Device_ID EQU 0001Eh ; TSR instance utility ID
+
+;
+; Initialization order equates. Devices are initialized in order from
+; LOWEST to HIGHEST. If 2 or more devices have the same initialization
+; order value, then they are initialized in order of occurance, so a
+; specific order is not guaranteed. Holes have been left to allow maximum
+; flexibility in ordering devices.
+;
+
+VMM_Init_Order EQU 000000000h
+Debug_Init_Order EQU 004000000h
+VPROD_Init_Order EQU 008000000h
+VPICD_Init_Order EQU 00C000000h
+VTD_Init_Order EQU 014000000h
+PageSwap_Init_Order EQU 01C000000h
+Parity_Init_Order EQU 020000000h
+Reboot_Init_Order EQU 024000000h
+EBIOS_Init_Order EQU 026000000h
+VDD_Init_Order EQU 028000000h
+VSD_Init_Order EQU 02C000000h
+VCD_Init_Order EQU 030000000h
+VMD_Init_Order EQU 034000000h
+VKD_Init_Order EQU 038000000h
+VPD_Init_Order EQU 03C000000h
+VHD_Init_Order EQU 040000000h
+VFD_Init_Order EQU 044000000h
+VMCPD_Init_Order EQU 048000000h
+BIOSXlat_Init_Order EQU 050000000h
+VNETBIOS_Init_Order EQU 054000000h
+DOSMGR_Init_Order EQU 058000000h
+DOSNET_Init_Order EQU 05C000000h
+WINLOAD_Init_Order EQU 060000000h
+VMPoll_Init_Order EQU 064000000h
+
+Undefined_Init_Order EQU 080000000h
+
+WINDEBUG_Init_Order EQU 081000000h
+VDMAD_Init_Order EQU 090000000h
+V86MMGR_Init_Order EQU 0A0000000h
+SHELL_Init_Order EQU 0B0000000h
+EndDoc
+
+;******************************************************************************
+;
+; Macro to cause a delay in between I/O accesses to the same device.
+;
+;------------------------------------------------------------------------------
+
+IO_Delay macro
+jmp $+2
+ENDM
+
+Pushad_Struc STRUC
+Pushad_EDI dd ? ; Client's EDI
+Pushad_ESI dd ? ; Client's ESI
+Pushad_EBP dd ? ; Client's EBP
+Pushad_ESP dd ? ; ESP at pushall
+Pushad_EBX dd ? ; Client's EBX
+Pushad_EDX dd ? ; Client's EDX
+Pushad_ECX dd ? ; Client's ECX
+Pushad_EAX dd ? ; Client's EAX
+Pushad_Struc ENDS
+
+
+
+IFNDEF Not_VxD
+
+??_CUR_CODE_SEG = 0
+
+
+??_CODE = 1
+??_ICODE = 2
+??_LCODE = 3
+??_RCODE = 4
+
+?_CODE equ <(??_CUR_CODE_SEG MOD 8) - ??_CODE>
+?_ICODE equ <(??_CUR_CODE_SEG MOD 8) - ??_ICODE>
+?_LCODE equ <(??_CUR_CODE_SEG MOD 8) - ??_LCODE>
+?_RCODE equ <(??_CUR_CODE_SEG MOD 8) - ??_RCODE>
+
+;
+; SEGMENT definitions and order
+;
+
+;* 32 Bit locked code
+_LTEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+_LTEXT ENDS
+
+;* 32 Bit code
+_TEXT SEGMENT DWORD USE32 PUBLIC 'PCODE'
+_TEXT ENDS
+
+;* 32 Bit initialization code
+_ITEXT SEGMENT DWORD USE32 PUBLIC 'ICODE'
+_ITEXT ENDS
+
+;* Contains 32 Bit locked data
+_LDATA SEGMENT DWORD PUBLIC 'CODE'
+_LDATA ENDS
+
+;* Contains 32 Bit data
+_DATA SEGMENT DWORD PUBLIC 'PCODE'
+_DATA ENDS
+
+;* Contains 32 Bit initialization data
+_IDATA SEGMENT DWORD PUBLIC 'ICODE'
+_IDATA ENDS
+
+;* Real Mode initialization code/data for devices
+_RCODE SEGMENT WORD USE16 PUBLIC 'RCODE'
+_RCODE ENDS
+
+
+_LGROUP GROUP _LTEXT, _LDATA
+_PGROUP GROUP _TEXT, _DATA
+_IGROUP GROUP _ITEXT, _IDATA
+
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:FLAT
+
+
+OFFSET32 EQU <OFFSET FLAT:>
+
+
+BeginDoc
+;==============================================================================
+; The following macros are used in defining the routines
+; in a VxD which are going to be registered with VMM as callable entry
+; points. Once registered, the entry points can be called by any other
+; devices via the "VxDCall" macro, defined below. In the comments below,
+; replace "VxD" with the appropriate device name.
+;
+;*******
+; In the VxD.INC file, put the following lines, replacing <function_name>
+; with an appropriate name describing the function of the routine.
+;
+; Begin_Service_Table VxD[,<segname>]
+; VxD_Service <function_name>[,<local segname>]
+; VxD_Service <function_name>[,<local segname>]
+; . . .
+; VxD_Service <function_name>[,<local segname>]
+; End_Service_Table VxD[,<segname>]
+;
+; Note that <segname> is an optional argument and, if specified, the
+; table is put in the segment defined by the macro "yyy_Data_Seg",
+; where yyy=segname. Otherwise the segment is defined by the
+; "VxD_Data_Seg" macro, defined below.
+; Note that <local segname> is an optional argument and, if specified,
+; the procedure's segment is defined by the macro "zzz_Code_Seg",
+; where zzz=segname. Otherwise the segment is defined by the
+; "VxD_Code_Seg" macro, defined below.
+;
+;*******
+; One VxD module should have the following in order to define the entry points:
+;Create_VxD_Service_Table = 1 ; Only in module where table is
+; INCLUDE VxD.INC ; Include the table definition
+;
+;*******
+; All modules that want to call the services defined in the table should include
+; VxD.INC, but not define the label "Create_VxD_Service_Table". This
+; will define the service names to be used with the VxDCall macro.
+;
+EndDoc
+
+Begin_Service_Table MACRO Device_Name, Def_Segment
+IFB <Def_Segment>
+ BST2 Device_Name, VxD
+ELSE
+ BST2 Device_Name, Def_Segment
+ENDIF
+ ENDM
+
+
+BST2 MACRO Device_Name, Def_Segment
+
+Num_&Device_Name&_Services = 0
+
+IFDEF Create_&Device_Name&_Service_Table
+Def_Segment&_LOCKED_DATA_SEG
+Device_Name&_Service_Table LABEL DWORD
+
+Device_Name&_Service MACRO Procedure, Local_Seg
+ PUBLIC $&&Procedure
+ IF1
+ $&&Procedure LABEL DWORD
+ ENDIF
+ IFDIFI <Local_Seg>, <LOCAL>
+ IFNB <Local_Seg>
+Local_Seg&&_SEG
+ ELSE
+Def_Segment&_CODE_SEG
+ ENDIF
+ EXTRN @&&Procedure:NEAR
+ IFNB <Local_Seg>
+Local_Seg&&_ENDS
+ ELSE
+Def_Segment&_CODE_ENDS
+ ENDIF
+ ENDIF
+ dd OFFSET32 @&&Procedure
+ Procedure = (Device_Name&_Device_ID SHL 16) + Num_&Device_Name&_Services
+ Num_&Device_Name&_Services = Num_&Device_Name&_Services + 1
+ ENDM
+
+ELSE
+
+Device_Name&_Service MACRO Procedure
+ Procedure = (Device_Name&_Device_ID SHL 16) + Num_&Device_Name&_Services
+ Num_&Device_Name&_Services = Num_&Device_Name&_Services + 1
+ ENDM
+
+ENDIF
+
+ ENDM
+
+;------------------------------------------------------------------------------
+
+End_Service_Table MACRO Device_Name, Def_Segment
+
+ PURGE Device_Name&_Service
+
+IFDEF Create_&Device_Name&_Service_Table
+IFB <Def_Segment>
+VxD_LOCKED_DATA_ENDS
+ELSE
+Def_Segment&_LOCKED_DATA_ENDS
+ENDIF
+ENDIF
+
+ ENDM
+
+
+;******************************************************************************
+;
+; Dword_Align -- Aligns code to dword boundry by inserting nops
+;
+;------------------------------------------------------------------------------
+
+Dword_Align MACRO Seg_Name
+ LOCAL segn
+IFNB <Seg_Name>
+ segn equ Seg_Name
+ELSE
+IFE ?_CODE
+ segn equ <_TEXT>
+ELSE
+IFE ?_ICODE
+ segn equ <_ITEXT>
+ELSE
+IFE ?_LCODE
+ segn equ <_LTEXT>
+ELSE
+.err Dword_Align not supported
+ENDIF
+ENDIF
+ENDIF
+ENDIF
+IF (($-OFFSET segn:0) MOD 4)
+db 4 - (($-OFFSET segn:0) MOD 4) DUP (90h)
+ENDIF
+ ENDM
+
+
+BeginDoc
+;******************************************************************************
+;
+; Fatal_Error
+;
+; DESCRIPTION:
+; This macro is used to crash Windows/386 when an unrecoverable error
+; is detected. If Msg_Ptr is ommitted then no error message will be
+; displayed, otherwise Msg_Ptr is the address
+; when the
+;
+; PARAMETERS:
+; Msg_Ptr (OPTIONAL) - Points to an ASCIIZ string to display.
+;
+; EXIT:
+; To DOS (hopefully). This macro never returns.
+;
+;==============================================================================
+EndDoc
+
+Fatal_Error MACRO Msg_Ptr, Exit_Flags
+ pushad
+IFB <Msg_Ptr>
+ xor esi, esi
+ELSE
+ mov esi, Msg_Ptr
+IFB <Exit_Flags>
+ xor eax, eax
+ELSE
+ mov eax, Exit_Flags
+ENDIF
+ENDIF
+ VMMcall Fatal_Error_Handler
+ ENDM
+
+EF_Hang_On_Exit EQU 1h
+
+
+;******************************************************************************
+;==============================================================================
+;------------------------------------------------------------------------------
+
+BeginDoc
+;******************************************************************************
+; The following are control block offsets of items that can be of interest
+; to VxDs.
+;*******
+; VM status indicates globally interesting VM states
+CB_VM_Status EQU DWORD PTR 00h
+
+VMStat_Exclusive EQU 000000000000000000001b ; VM is exclusive mode
+VMStat_Exclusive_Bit EQU 0
+VMStat_Background EQU 000000000000000000010b ; VM runs in background
+VMStat_Background_Bit EQU 1
+VMStat_Creating EQU 000000000000000000100b ; In process of creating
+VMStat_Creating_Bit EQU 2
+VMStat_Suspended EQU 000000000000000001000b ; VM not scheduled
+VMStat_Suspended_Bit EQU 3
+VMStat_Not_Executeable EQU 000000000000000010000b ; VM partially destroyed
+VMStat_Not_Executeable_Bit EQU 4
+VMStat_PM_Exec EQU 000000000000000100000b ; Currently in PM app
+VMStat_PM_Exec_Bit EQU 5
+VMStat_PM_App EQU 000000000000001000000b ; PM app present in VM
+VMStat_PM_App_Bit EQU 6
+VMStat_PM_Use32 EQU 000000000000010000000b ; PM app is 32-bit
+VMStat_PM_Use32_Bit EQU 7
+VMStat_VxD_Exec EQU 000000000000100000000b ; Call from VxD
+VMStat_VxD_Exec_Bit EQU 8
+VMStat_High_Pri_Back EQU 000000000001000000000b ; High pri background
+VMStat_High_Pri_Back_Bit EQU 9
+VMStat_Blocked EQU 000000000010000000000b ; Blocked on semaphore
+VMStat_Blocked_Bit EQU 0Ah
+VMStat_Awakening EQU 000000000100000000000b ; Woke up after blocked
+VMStat_Awakening_Bit EQU 0Bh
+VMStat_PageableV86 EQU 000000001000000000000b ; part of V86 is pageable (PM app)
+VMStat_PageableV86Bit EQU 0Ch
+VMStat_V86IntsLocked EQU 000000010000000000000b ; Rest of V86 is locked
+VMStat_V86IntsLockedBit EQU 0Dh ; regardless of pager type
+VMStat_TS_Sched EQU 000000100000000000000b ; Scheduled by time-slicer
+VMStat_TS_Sched_Bit EQU 0Eh
+VMStat_Idle EQU 000001000000000000000b ; VM has released time
+VMStat_Idle_Bit EQU 0Fh ; slice
+
+VMStat_Use32_Mask EQU VMStat_PM_Use32 OR VMStat_VxD_Exec
+
+
+;*******
+; Add this value to a V86 linear address to get address of VM's memory in
+; the VMM linear address space
+CB_High_Linear EQU DWORD PTR 04h
+
+;*******
+CB_Client_Pointer EQU DWORD PTR 08h
+
+CB_VMID EQU DWORD PTR 0Ch
+
+;
+; Equates for protected mode application control blocks
+;
+PMCB_Flags EQU DWORD PTR 00h
+PMCB_Parent EQU DWORD PTR 04h
+EndDoc
+
+;******************************************************************************
+; V M M S E R V I C E S
+;******************************************************************************
+
+Begin_Service_Table VMM, VMM
+
+VMM_Service Get_VMM_Version, LOCAL ; MUST REMAIN SERVICE 0!
+
+VMM_Service Get_Cur_VM_Handle
+VMM_Service Test_Cur_VM_Handle
+VMM_Service Get_Sys_VM_Handle
+VMM_Service Test_Sys_VM_Handle
+VMM_Service Validate_VM_Handle
+
+VMM_Service Get_VMM_Reenter_Count, LOCAL
+VMM_Service Begin_Reentrant_Execution, LOCAL
+VMM_Service End_Reentrant_Execution, LOCAL
+
+VMM_Service Install_V86_Break_Point
+VMM_Service Remove_V86_Break_Point
+VMM_Service Allocate_V86_Call_Back
+VMM_Service Allocate_PM_Call_Back
+
+VMM_Service Call_When_VM_Returns
+
+
+VMM_Service Schedule_Global_Event
+VMM_Service Schedule_VM_Event
+VMM_Service Call_Global_Event
+VMM_Service Call_VM_Event
+VMM_Service Cancel_Global_Event
+VMM_Service Cancel_VM_Event
+VMM_Service Call_Priority_VM_Event
+VMM_Service Cancel_Priority_VM_Event
+
+VMM_Service Get_NMI_Handler_Addr, LOCAL
+VMM_Service Set_NMI_Handler_Addr, LOCAL
+VMM_Service Hook_NMI_Event
+
+VMM_Service Call_When_VM_Ints_Enabled
+VMM_Service Enable_VM_Ints
+VMM_Service Disable_VM_Ints
+
+VMM_Service Map_Flat
+VMM_Service Map_Lin_To_VM_Addr
+
+;
+; Scheduler services
+;
+VMM_Service Adjust_Exec_Priority
+VMM_Service Begin_Critical_Section
+VMM_Service End_Critical_Section
+VMM_Service End_Crit_And_Suspend
+VMM_Service Claim_Critical_Section
+VMM_Service Release_Critical_Section
+VMM_Service Call_When_Not_Critical
+VMM_Service Create_Semaphore
+VMM_Service Destroy_Semaphore
+VMM_Service Wait_Semaphore
+VMM_Service Signal_Semaphore
+VMM_Service Get_Crit_Section_Status
+VMM_Service Call_When_Task_Switched
+VMM_Service Suspend_VM
+VMM_Service Resume_VM
+VMM_Service No_Fail_Resume_VM
+VMM_Service Nuke_VM
+VMM_Service Crash_Cur_VM
+
+VMM_Service Get_Execution_Focus
+VMM_Service Set_Execution_Focus
+VMM_Service Get_Time_Slice_Priority
+VMM_Service Set_Time_Slice_Priority
+VMM_Service Get_Time_Slice_Granularity
+VMM_Service Set_Time_Slice_Granularity
+VMM_Service Get_Time_Slice_Info
+VMM_Service Adjust_Execution_Time
+VMM_Service Release_Time_Slice
+VMM_Service Wake_Up_VM
+VMM_Service Call_When_Idle
+
+VMM_Service Get_Next_VM_Handle
+
+;
+; Time-out and system timer services
+;
+VMM_Service Set_Global_Time_Out
+VMM_Service Set_VM_Time_Out
+VMM_Service Cancel_Time_Out
+VMM_Service Get_System_Time
+VMM_Service Get_VM_Exec_Time
+
+VMM_Service Hook_V86_Int_Chain
+VMM_Service Get_V86_Int_Vector
+VMM_Service Set_V86_Int_Vector
+VMM_Service Get_PM_Int_Vector
+VMM_Service Set_PM_Int_Vector
+
+VMM_Service Simulate_Int
+VMM_Service Simulate_Iret
+VMM_Service Simulate_Far_Call
+VMM_Service Simulate_Far_Jmp
+VMM_Service Simulate_Far_Ret
+VMM_Service Simulate_Far_Ret_N
+VMM_Service Build_Int_Stack_Frame
+
+VMM_Service Simulate_Push
+VMM_Service Simulate_Pop
+
+;
+; Heap Manager
+;
+VMM_Service _HeapAllocate
+VMM_Service _HeapReAllocate
+VMM_Service _HeapFree
+VMM_Service _HeapGetSize
+
+; ---------------------------------------------------
+;
+; Flags for heap allocator calls
+;
+; ---------------------------------------------------
+
+
+HeapZeroInit equ 00000000000000000000000000000001B
+HeapZeroReInit equ 00000000000000000000000000000010B
+HeapNoCopy equ 00000000000000000000000000000100B
+
+; NOTE: HIGH 8 BITS (bits 24-31) are reserved
+
+
+;
+; Page Manager
+;
+VMM_Service _PageAllocate
+VMM_Service _PageReAllocate
+VMM_Service _PageFree
+VMM_Service _PageLock
+VMM_Service _PageUnLock
+VMM_Service _PageGetSizeAddr
+VMM_Service _PageGetAllocInfo
+VMM_Service _GetFreePageCount
+VMM_Service _GetSysPageCount
+VMM_Service _GetVMPgCount
+VMM_Service _MapIntoV86
+VMM_Service _PhysIntoV86
+VMM_Service _TestGlobalV86Mem
+VMM_Service _ModifyPageBits
+VMM_Service _CopyPageTable
+VMM_Service _LinMapIntoV86
+VMM_Service _LinPageLock
+VMM_Service _LinPageUnLock
+VMM_Service _SetResetV86Pageable
+VMM_Service _GetV86PageableArray
+VMM_Service _PageCheckLinRange
+VMM_Service _PageOutDirtyPages
+VMM_Service _PageDiscardPages
+
+; ---------------------------------------------------
+;
+; Flags for other page allocator calls
+;
+; ---------------------------------------------------
+PageZeroInit equ 00000000000000000000000000000001B
+PageUseAlign equ 00000000000000000000000000000010B
+PageContig equ 00000000000000000000000000000100B
+PageFixed equ 00000000000000000000000000001000B
+PageDEBUGNulFault equ 00000000000000000000000000010000B
+PageZeroReInit equ 00000000000000000000000000100000B
+PageNoCopy equ 00000000000000000000000001000000B
+PageLocked equ 00000000000000000000000010000000B
+PageLockedIfDP equ 00000000000000000000000100000000B
+PageSetV86Pageable equ 00000000000000000000001000000000B
+PageClearV86Pageable equ 00000000000000000000010000000000B
+PageSetV86IntsLocked equ 00000000000000000000100000000000B
+PageClearV86IntsLocked equ 00000000000000000001000000000000B
+PageMarkPageOut equ 00000000000000000010000000000000B
+PagePDPSetBase equ 00000000000000000100000000000000B
+PagePDPClearBase equ 00000000000000001000000000000000B
+PageDiscard equ 00000000000000010000000000000000B
+PagePDPQueryDirty equ 00000000000000100000000000000000B
+
+; NOTE: HIGH 8 BITS (bits 24-31) are reserved
+
+;
+; Informational services
+;
+VMM_Service _GetNulPageHandle
+VMM_Service _GetFirstV86Page
+VMM_Service _MapPhysToLinear
+VMM_Service _GetAppFlatDSAlias
+VMM_Service _SelectorMapFlat
+VMM_Service _GetDemandPageInfo
+;
+; Data structure for _GetDemandPageInfo
+;
+DemandInfoStruc struc
+DILin_Total_Count dd ? ; # pages in linear address space
+DIPhys_Count dd ? ; Count of phys pages
+DIFree_Count dd ? ; Count of free phys pages
+DIUnlock_Count dd ? ; Count of unlocked Phys Pages
+DILinear_Base_Addr dd ? ; Base of pageable address space
+DILin_Total_Free dd ? ; Total Count of free linear pages
+DIReserved dd 10 dup (?) ; Resvd for expansion
+DemandInfoStruc ends
+
+VMM_Service _GetSetPageOutCount
+;
+; Flags bits for _GetSetPageOutCount
+;
+GSPOC_F_Get equ 00000000000000000000000000000001B
+
+;
+; Device VM page manager
+;
+VMM_Service Hook_V86_Page
+VMM_Service _Assign_Device_V86_Pages
+VMM_Service _DeAssign_Device_V86_Pages
+VMM_Service _Get_Device_V86_Pages_Array
+VMM_Service MMGR_SetNULPageAddr
+
+;
+; GDT/LDT management
+;
+VMM_Service _Allocate_GDT_Selector
+VMM_Service _Free_GDT_Selector
+VMM_Service _Allocate_LDT_Selector
+VMM_Service _Free_LDT_Selector
+VMM_Service _BuildDescriptorDWORDs
+;
+; Flag equates for _BuildDescriptorDWORDs
+;
+BDDExplicitDPL EQU 00000000000000000000000000000001B
+;
+; Flag equates for _Allocate_LDT_Selector
+;
+ALDTSpecSel EQU 00000000000000000000000000000001B
+
+VMM_Service _GetDescriptor
+VMM_Service _SetDescriptor
+
+
+VMM_Service _MMGR_Toggle_HMA
+;
+; Flag equates for _MMGR_Toggle_HMA
+;
+MMGRHMAPhysical EQU 00000000000000000000000000000001B
+MMGRHMAEnable EQU 00000000000000000000000000000010B
+MMGRHMADisable EQU 00000000000000000000000000000100B
+MMGRHMAQuery EQU 00000000000000000000000000001000B
+
+
+VMM_Service Get_Fault_Hook_Addrs, LOCAL
+VMM_Service Hook_V86_Fault, LOCAL
+VMM_Service Hook_PM_Fault, LOCAL
+VMM_Service Hook_VMM_Fault, LOCAL
+
+VMM_Service Begin_Nest_V86_Exec
+VMM_Service Begin_Nest_Exec
+VMM_Service Exec_Int
+VMM_Service Resume_Exec
+VMM_Service End_Nest_Exec
+
+VMM_Service Allocate_PM_App_CB_Area, VMM_ICODE
+VMM_Service Get_Cur_PM_App_CB
+
+VMM_Service Set_V86_Exec_Mode
+VMM_Service Set_PM_Exec_Mode
+
+VMM_Service Begin_Use_Locked_PM_Stack
+VMM_Service End_Use_Locked_PM_Stack
+
+VMM_Service Save_Client_State
+VMM_Service Restore_Client_State
+
+VMM_Service Exec_VxD_Int
+
+VMM_Service Hook_Device_Service, LOCAL
+
+VMM_Service Hook_Device_V86_API
+VMM_Service Hook_Device_PM_API
+
+VMM_Service System_Control
+
+;
+; I/O and software interrupt hooks
+;
+VMM_Service Simulate_IO
+VMM_Service Install_Mult_IO_Handlers
+VMM_Service Install_IO_Handler
+VMM_Service Enable_Global_Trapping
+VMM_Service Enable_Local_Trapping
+VMM_Service Disable_Global_Trapping
+VMM_Service Disable_Local_Trapping
+
+
+;
+; Linked List Abstract Data Type Services
+;
+VMM_Service List_Create
+VMM_Service List_Destroy
+VMM_Service List_Allocate
+VMM_Service List_Attach
+VMM_Service List_Attach_Tail
+VMM_Service List_Insert
+VMM_Service List_Remove
+VMM_Service List_Deallocate
+VMM_Service List_Get_First
+VMM_Service List_Get_Next
+VMM_Service List_Remove_First
+
+;
+; Flags used by List_Create
+;
+LF_Async EQU 00000001b
+LF_Async_Bit EQU 0
+LF_Use_Heap EQU 00000010b
+LF_Use_Heap_Bit EQU 1
+LF_Alloc_Error EQU 00000100b
+LF_Alloc_Error_Bit EQU 2
+
+
+;==============================================================================
+; I N I T I A L I Z A T I O N P R O C E D U R E S
+;------------------------------------------------------------------------------
+
+
+;
+; Instance data manager
+;
+VMM_Service _AddInstanceItem
+;
+; Data structure for _AddInstanceItem
+;
+InstDataStruc struc
+InstLinkF dd 0 ; RESERVED SET TO 0
+InstLinkB dd 0 ; RESERVED SET TO 0
+InstLinAddr dd ? ; Linear address of start of block
+InstSize dd ? ; Size of block in bytes
+InstType dd ? ; Type of block
+InstDataStruc ends
+;
+; Values for InstType
+;
+INDOS_Field equ 100h ; Bit indicating INDOS switch requirements
+ALWAYS_Field equ 200h ; Bit indicating ALWAYS switch requirements
+
+;
+; System structure data manager
+;
+VMM_Service _Allocate_Device_CB_Area, VMM_ICODE
+VMM_Service _Allocate_Global_V86_Data_Area, VMM_ICODE
+VMM_Service _Allocate_Temp_V86_Data_Area, VMM_ICODE
+VMM_Service _Free_Temp_V86_Data_Area, VMM_ICODE
+
+;
+; Flag bits for _Allocate_Global_VM_Data_Area
+;
+GVDAWordAlign EQU 00000000000000000000000000000001B
+GVDADWordAlign EQU 00000000000000000000000000000010B
+GVDAParaAlign EQU 00000000000000000000000000000100B
+GVDAPageAlign EQU 00000000000000000000000000001000B
+GVDAInstance EQU 00000000000000000000000100000000B
+GVDAZeroInit EQU 00000000000000000000001000000000B
+GVDAReclaim EQU 00000000000000000000010000000000B
+
+;
+; Initialization information calls (win.ini and environment parameters)
+;
+VMM_Service Get_Profile_Decimal_Int, VMM_ICODE
+VMM_Service Convert_Decimal_String, VMM_ICODE
+VMM_Service Get_Profile_Fixed_Point, VMM_ICODE
+VMM_Service Convert_Fixed_Point_String, VMM_ICODE
+VMM_Service Get_Profile_Hex_Int, VMM_ICODE
+VMM_Service Convert_Hex_String, VMM_ICODE
+VMM_Service Get_Profile_Boolean, VMM_ICODE
+VMM_Service Convert_Boolean_String, VMM_ICODE
+VMM_Service Get_Profile_String, VMM_ICODE
+VMM_Service Get_Next_Profile_String, VMM_ICODE
+VMM_Service Get_Environment_String, VMM_ICODE
+VMM_Service Get_Exec_Path, VMM_ICODE
+VMM_Service Get_Config_Directory, VMM_ICODE
+VMM_Service OpenFile, VMM_ICODE
+VMM_Service Get_PSP_Segment, VMM_ICODE
+VMM_Service GetDOSVectors, VMM_ICODE
+VMM_Service Get_Machine_Info
+
+GMIF_80486 EQU 00010000h
+GMIF_80486_Bit EQU 10h
+GMIF_PCXT EQU 00020000h
+GMIF_PCXT_Bit EQU 11h
+GMIF_MCA EQU 00040000h
+GMIF_MCA_Bit EQU 12h
+GMIF_EISA EQU 00080000h
+GMIF_EISA_Bit EQU 13h
+
+
+;
+; Following service is not restricted to initialization
+;
+VMM_Service GetSet_HMA_Info
+VMM_Service Set_System_Exit_Code
+
+VMM_Service Fatal_Error_Handler
+VMM_Service Fatal_Memory_Error
+
+;
+; Called by VTD only
+;
+VMM_Service Update_System_Clock
+
+;==============================================================================
+; D E B U G G I N G E X T E R N S
+;==============================================================================
+
+VMM_Service Test_Debug_Installed ; Valid call in retail also
+
+VMM_Service Out_Debug_String ; Valid in DEBLEVEL=1
+VMM_Service Out_Debug_Chr
+VMM_Service In_Debug_Chr
+VMM_Service Debug_Convert_Hex_Binary
+VMM_Service Debug_Convert_Hex_Decimal
+
+VMM_Service Debug_Test_Valid_Handle
+VMM_Service Validate_Client_Ptr
+VMM_Service Test_Reenter
+VMM_Service Queue_Debug_String
+VMM_Service Log_Proc_Call
+VMM_Service Debug_Test_Cur_VM
+
+.errnz Debug_Test_Cur_VM - 100CCh ; VMM service table changed above this service
+
+VMM_Service Get_PM_Int_Type
+VMM_Service Set_PM_Int_Type
+
+VMM_Service Get_Last_Updated_System_Time
+VMM_Service Get_Last_Updated_VM_Exec_Time
+
+End_Service_Table VMM, VMM
+
+
+
+;******************************************************************************
+
+IFDEF DEBUG
+DebFar EQU NEAR PTR
+ELSE
+DebFar EQU SHORT
+ENDIF
+
+BeginDoc
+
+;******************************************************************************
+;
+; EQUATES FOR SYSTEM_CONTROL CALLS
+;
+;==============================================================================
+
+;
+; Sys_Critical_Init is a device init call. Devices that have a critical
+; function that needs initializing before interrupts are enabled should
+; do it at Sys_Critical_Init. Devices which REQUIRE a certain range of
+; V86 pages to operate (such as the VDD video memory) should claim them
+; at Sys_Critical_Init. SYS VM Simulate_Int, Exec_Int ACTIVITY IS NOT
+; ALLOWED. Returning carry aborts device load only.
+;
+Sys_Critical_Init EQU 0000h ; Devices required for virt mode
+;
+; Device init is where most devices do the bulk of their initialization.
+; SYS VM Simulate_Int, Exec_Int activity is allowed. Returning carry
+; aborts device load only.
+;
+Device_Init EQU 0001h ; All other devices init
+;
+; Init_Complete is the final phase of device init called just before the
+; WIN386 INIT pages are released and the Instance snapshot is taken.
+; Devices which wish to search for a region of V86 pages >= A0h to use
+; should do it at Init_Complete.
+; SYS VM Simulate_Int, Exec_Int activity is allowed. Returning carry
+; aborts device load only.
+;
+Init_Complete EQU 0002h ; All devices have initialized
+
+;----------------- INITIALIZATION CODE AND DATA DISCARDED ---------------------
+
+;
+; Same as VM_Init, except for SYS VM.
+;
+Sys_VM_Init EQU 0003h ; Execute the system VM (Win86)
+;
+; Same as VM_Terminate, except for SYS VM (Normal WIN386 exit ONLY, on a crash
+; exit this call is not made). SYS VM Simulate_Int, Exec_Int activity is
+; allowed.
+;
+Sys_VM_Terminate EQU 0004h ; System VM terminted (exiting)
+
+;------------------------------------------------------------------------------
+
+;
+; System_Exit call is made when WIN386 is exiting either normally or via
+; a crash. INTERRUPS ARE ENABLED. Instance snapshot has been restored.
+; SYS VM Simulate_Int, Exec_Int ACTIVITY IS NOT ALLOWED.
+;
+System_Exit EQU 0005h ; Devices prepare to exit
+;
+; System_Exit call is made when WIN386 is exiting either normally or via
+; a crash. INTERRUPS ARE DISABLED. SYS VM Simulate_Int, Exec_Int ACTIVITY
+; IS NOT ALLOWED.
+;
+Sys_Critical_Exit EQU 0006h ; System critical devices reset
+
+;
+; Create_VM creates a new VM. EBX = VM handle of new VM. Returning Carry will
+; fail the Create_VM.
+;
+Create_VM EQU 0007h
+;
+; Second phase of Create_VM. EBX = VM handle of new VM. Returning Carry will
+; cause the VM to go Not_Executeable, then be destroyed. VM Simulate_Int,
+; Exec_Int activity is NOT allowed.
+;
+VM_Critical_Init EQU 0008h
+;
+; Third phase of Create_VM. EBX = VM handle of new VM. Returning Carry will
+; cause the VM to go Not_Executeable, then be destroyed. VM Simulate_Int,
+; Exec_Int activity is allowed.
+;
+VM_Init EQU 0009h
+
+;
+; NORMAL (First phase) of Destroy_VM. EBX = VM Hanlde. This occurs on normal
+; termination of the VM. Call cannot be failed. VM Simulate_Int, Exec_Int
+; activity is allowed.
+;
+VM_Terminate EQU 000Ah ; Still in VM -- About to die
+;
+; Second phase of Destroy_VM. EBX = VM Handle, EDX = Flags (see below). Note
+; that in the case of destroying a running VM, this is the first call made
+; (VM_Terminate call does not occur). Call cannot be failed. VM Simulate_Int,
+; Exec_Int activity is NOT allowed.
+;
+VM_Not_Executeable EQU 000Bh ; Most devices die (except VDD)
+;
+; Final phase of Destroy_VM. EBX = VM Handle. Note that considerable time
+; can elaps between the VM_Not_Executeable call and this call. Call cannot
+; be failed. VM Simulate_Int, Exec_Int activity is NOT allowed.
+;
+Destroy_VM EQU 000Ch ; VM's control block about to go
+
+;
+; Flags for VM_Not_Executeable control call (passed in EDX)
+;
+VNE_Crashed EQU 0000000000000000000000001b
+VNE_Crashed_Bit EQU 0 ; VM was crashed
+VNE_Nuked EQU 0000000000000000000000010b
+VNE_Nuked_Bit EQU 1 ; VM was destroyed while active
+VNE_CreateFail EQU 0000000000000000000000100b
+VNE_CreateFail_Bit EQU 2 ; Some device failed Create_VM
+VNE_CrInitFail EQU 0000000000000000000001000b
+VNE_CrInitFail_Bit EQU 3 ; Some device failed VM_Critical_Init
+VNE_InitFail EQU 0000000000000000000010000b
+VNE_InitFail_Bit EQU 4 ; Some device failed VM_Init
+
+;------------------------------------------------------------------------------
+
+;
+; EBX = VM Handle. Call cannot be failed.
+;
+VM_Suspend EQU 000Dh ; VM not runnable until resume
+;
+; EBX = VM Handle. Returning carry fails and backs out the resume.
+;
+VM_Resume EQU 000Eh ; VM is leaving suspended state
+
+;------------------------------------------------------------------------------
+
+;
+; EBX = VM Handle to set device focus to. EDX = Device ID if device specific
+; setfocus. == 0 if device critical setfocus (all devices). THIS CALL CANNOT
+; BE FAILED.
+;
+; NOTE: In case where EDX == 0, ESI is a FLAG word that indicates special
+; functions. Currently Bit 0 being set indicates that this Device
+; critical set focus is also "VM critical". It means that we do not
+; want some other VM to take the focus from this app now. This is
+; primarily used when doing a device critical set focus to Windows
+; (the SYS VM) it is interpreted by the SHELL to mean "if an old app
+; currently has the Windows activation, set the activation to the
+; Windows Shell, not back to the old app". ALSO in the case where
+; Bit 0 is set, EDI = The VM handle of the VM that is "having trouble".
+; Set this to 0 if there is no specific VM associated with the problem.
+;
+Set_Device_Focus EQU 000Fh
+
+;------------------------------------------------------------------------------
+
+;
+; EBX = VM Handle going into message mode. THIS CALL CANNOT BE FAILED.
+;
+Begin_Message_Mode EQU 0010h
+;
+; EBX = VM Handle leaving message mode. THIS CALL CANNOT BE FAILED.
+;
+End_Message_Mode EQU 0011h
+
+;------------------------- SPECIAL CONTROL CALLS ------------------------------
+
+;
+; Request for reboot. Call cannot be failed.
+;
+Reboot_Processor EQU 0012h ; Request a machine reboot
+;
+; Query_Destroy is an information call made by the SHELL device before an
+; attempt is made to initiate a destroy VM sequence on a running VM which
+; has not exited normally. EBX = VM Handle. Returning carry indicates that
+; a device "has a problem" with allowing this. THE DESTROY SEQUENCE CANNOT
+; BE ABORTED HOWEVER, this decision is up to the user. All this does is
+; indicate that there is a "problem" with allowing the destroy. The device
+; which returns carry should call the SHELL_Message service to post an
+; informational dialog about the reason for the problem.
+;
+Query_Destroy EQU 0013h ; OK to destroy running VM?
+
+;------------------------- DEBUGGING CONTROL CALL -----------------------------
+
+;
+; Special call for device specific DEBUG information display and activity.
+;
+Debug_Query EQU 0014h
+
+;---------- CALLS FOR BEGIN/END OF PROTECTED MODE VM EXECUTION ----------------
+
+;
+; About to run a protected mode application.
+; EBX = Current VM handle.
+; EDX = Flags
+; EDI -> Application Control Block
+; Returning with carry set fails the call.
+;
+Begin_PM_App EQU 0015h
+
+;
+; Flags for Begin_PM_App (passed in EDX)
+;
+BPA_32_Bit EQU 00000001b
+BPA_32_Bit_Flag EQU 1
+
+;
+; Protected mode application is terminating.
+; EBX = Current VM handle. THIS CALL CAN NOT FAIL.
+; EDI -> Application Control Block
+;
+End_PM_App EQU 0016h
+
+EndDoc
+
+BeginDoc
+;******************************************************************************
+; BeginProc is a macro for defining entry points to routines in VMM and in the
+; VxDs. It correctly defines the procedure name for VxD services(it prepends
+; a "@" to the procedure name), DWORD aligns the procedure, takes care of
+; public declaration and does some calling verification for debug versions
+; of the software. EndProc is a macro which defines the end of the procedure.
+;
+; Valid parameters to the BeginProc macro are:
+; PUBLIC ; Routine used outside this module
+; HIGH_FREQ ; DWORD align procedure
+; SERVICE ; Routine is called via VxDCall
+; ASYNC_SERVICE ; Same as "SERVICE" plus routine can
+; ; be called under interrupt.
+; After the routine header in which the routine entry conditions, exit
+; conditions, side affects and functionality are specified, the BeginProc
+; macro should be used to define the routine's entry point. It has up to
+; four parameters as specified below. For example:
+;
+;BeginProc <Function_Name>,PUBLIC, HIGH_FREQ, ASYNC_SERVICE
+;
+; <code>
+;
+;EndProc <Function_Name>
+;==============================================================================
+EndDoc
+
+BeginProc MACRO Name, P1, P2, P3, P4
+ LOCAL Profile_Data, Skip_Data
+
+IF ?_RCODE
+
+Process_Param MACRO P
+IFNB <P>
+IFIDNI <P>, <HIGH_FREQ>
+Dword_Align
+ELSE
+IFIDNI <P>, <SERVICE>
+??_SERVICE = 1
+ELSE
+IFIDNI <P>, <ASYNC_SERVICE>
+??_ASYNC_SERVICE = 1
+IF ?_LCODE
+%OUT ERROR: ASYNC_SERVICE's must be in LOCKED code
+;;.err
+ENDIF
+ELSE
+IFIDNI <P>, <NO_LOG>
+??_NO_LOG = 1
+ELSE
+IFDIFI <P>, <PUBLIC>
+%OUT ERROR: Bad para "&P" to BeginProc
+.ERR
+ENDIF
+ENDIF
+ENDIF
+ENDIF
+ENDIF
+ENDIF
+ ENDM
+
+
+??_SERVICE = 0
+??_ASYNC_SERVICE = 0
+??_NO_LOG = 0
+
+Process_Param P1
+Process_Param P2
+Process_Param P3
+Process_Param P4
+
+
+IFE ??_SERVICE + ??_ASYNC_SERVICE
+
+PUBLIC Name
+Name PROC NEAR
+IFDEF DEBUG
+IFE ??_NO_LOG
+IFNDEF VMMSYS
+ VMMcall Log_Proc_Call
+ENDIF
+ENDIF
+ENDIF
+
+ELSE
+
+IFDEF DEBUG
+ jmp SHORT Skip_Data
+Profile_Data LABEL DWORD
+ dd 0
+Skip_Data:
+ENDIF
+
+PUBLIC @&Name
+@&Name PROC NEAR
+
+IFDEF DEBUG
+IFE ??_NO_LOG
+;;;;IFNDEF VMMSYS
+ VMMcall Log_Proc_Call
+;;;;ENDIF
+ENDIF
+ pushfd
+ inc [Profile_Data]
+IFE ??_ASYNC_SERVICE
+ VMMcall Test_Reenter
+ENDIF
+ popfd
+ENDIF
+ENDIF
+
+ELSE
+IFIDNI <P1>, <PUBLIC>
+PUBLIC Name
+ENDIF
+Name PROC NEAR
+ENDIF
+
+
+ ENDM
+
+
+
+EndProc MACRO Name
+IFDEF @&Name
+@&Name ENDP
+ELSE
+IFDEF Name
+Name ENDP
+ELSE
+.ERR
+%OUT EndProc for &Name does not match BeginProc
+ENDIF
+ENDIF
+ ENDM
+
+
+;******************************************************************************
+; S C H E D U L E R B O O S T V A L U E S
+;==============================================================================
+
+Reserved_Low_Boost EQU 00000000000000000000000000000001b
+Cur_Run_VM_Boost EQU 00000000000000000000000000000100b
+Low_Pri_Device_Boost EQU 00000000000000000000000000010000b
+High_Pri_Device_Boost EQU 00000000000000000001000000000000b
+Critical_Section_Boost EQU 00000000000100000000000000000000b
+Time_Critical_Boost EQU 00000000010000000000000000000000b
+Reserved_High_Boost EQU 01000000000000000000000000000000b
+
+
+;******************************************************************************
+; F L A G S F O R C A L L _ P R I O R I T Y _ V M _ E V E N T
+;==============================================================================
+
+PEF_Wait_For_STI EQU 0000001b
+PEF_Wait_For_STI_Bit EQU 0
+PEF_Wait_Not_Crit EQU 0000010b
+PEF_Wait_Not_Crit_Bit EQU 1
+PEF_Dont_Unboost EQU 0000100b
+PEF_Dont_Unboost_Bit EQU 2
+PEF_Always_Sched EQU 0001000b
+PEF_Always_Sched_Bit EQU 3
+
+
+;******************************************************************************
+; F L A G S F O R B E G I N _ C R I T I C A L _ S E C T I O N
+; A N D W A I T _ S E M A P H O R E
+;==============================================================================
+
+Block_Svc_Ints EQU 0000001b
+Block_Svc_Ints_Bit EQU 0
+Block_Svc_If_Ints_Locked EQU 0000010b
+Block_Svc_If_Ints_Locked_Bit EQU 1
+Block_Enable_Ints EQU 0000100b
+Block_Enable_Ints_Bit EQU 2
+
+
+
+BeginDoc
+;******************************************************************************
+; The following structures are pointed to by EBP when VxD routines are entered,
+; both for VxD control calls and traps(I/O traps, software INT traps, etc.).
+; The first structure as DWORD values, the second WORD values and the last
+; has BYTE values.
+;
+Client_Reg_Struc struc
+Client_EDI dd ? ; Client's EDI
+Client_ESI dd ? ; Client's ESI
+Client_EBP dd ? ; Client's EBP
+ dd ? ; ESP at pushall
+Client_EBX dd ? ; Client's EBX
+Client_EDX dd ? ; Client's EDX
+Client_ECX dd ? ; Client's ECX
+Client_EAX dd ? ; Client's EAX
+Client_Error dd ? ; Dword error code
+Client_EIP dd ? ; EIP
+Client_CS dw ? ; CS
+ dw ? ; (padding)
+Client_EFlags dd ? ; EFLAGS
+Client_ESP dd ? ; ESP
+Client_SS dw ? ; SS
+ dw ? ; (padding)
+Client_ES dw ? ; ES
+ dw ? ; (padding)
+Client_DS dw ? ; DS
+ dw ? ; (padding)
+Client_FS dw ? ; FS
+ dw ? ; (padding)
+Client_GS dw ? ; GS
+ dw ? ; (padding)
+Client_Alt_EIP dd ?
+Client_Alt_CS dw ?
+ dw ?
+Client_Alt_EFlags dd ?
+Client_Alt_ESP dd ?
+Client_Alt_SS dw ?
+ dw ?
+Client_Alt_ES dw ?
+ dw ?
+Client_Alt_DS dw ?
+ dw ?
+Client_Alt_FS dw ?
+ dw ?
+Client_Alt_GS dw ?
+ dw ?
+Client_Reg_Struc ends
+
+
+Client_Word_Reg_Struc struc
+Client_DI dw ? ; Client's DI
+ dw ? ; (padding)
+Client_SI dw ? ; Client's SI
+ dw ? ; (padding)
+Client_BP dw ? ; Client's BP
+ dw ? ; (padding)
+ dd ? ; ESP at pushall
+Client_BX dw ? ; Client's BX
+ dw ? ; (padding)
+Client_DX dw ? ; Client's DX
+ dw ? ; (padding)
+Client_CX dw ? ; Client's CX
+ dw ? ; (padding)
+Client_AX dw ? ; Client's AX
+ dw ? ; (padding)
+ dd ? ; Dword error code
+Client_IP dw ? ; Client's IP
+ dw ? ; (padding)
+ dd ? ; CS
+Client_Flags dw ? ; Client's flags (low)
+ dw ? ; (padding)
+Client_SP dw ? ; SP
+ dw ?
+ dd 5 dup (?)
+Client_Alt_IP dw ?
+ dw ?
+ dd ?
+Client_Alt_Flags dw ?
+ dw ?
+Client_Alt_SP dw ?
+Client_Word_Reg_Struc ends
+
+
+
+Client_Byte_Reg_Struc struc
+ dd 4 dup (?) ; EDI, ESI, EBP, ESP at pushall
+Client_BL db ? ; Client's BL
+Client_BH db ? ; Client's BH
+ dw ? ; (padding)
+Client_DL db ? ; Client's DL
+Client_DH db ? ; Client's DH
+ dw ? ; (padding)
+Client_CL db ? ; Client's CL
+Client_CH db ? ; Client's CH
+ dw ? ; (padding)
+Client_AL db ? ; Client's AL
+Client_AH db ? ; Client's AH
+Client_Byte_Reg_Struc ends
+
+;==============================================================================
+EndDoc
+
+.ERRNZ Client_SP - Client_ESP
+.ERRNZ Client_AL - Client_EAX
+
+
+
+PushCParams MACRO P1, P2, P3, P4, P5, P6, P7, P8, P9, P10
+ IRP Param, <P10, P9, P8, P7, P6, P5, P4, P3, P2, P1>
+ IFNB <Param>
+ push Param
+ ENDIF
+ ENDM
+ ENDM
+
+ClearCParams MACRO Count, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10
+IFNB <P1>
+ ClearCParams %(Count+1), <P2>, <P3>, <P4>, <P5>, <P6>, <P7>, <P8>, <P9>, <P10>
+ELSE
+IF Count
+ add esp, Count*4
+ENDIF
+ENDIF
+ ENDM
+
+
+
+Dyna_Link_Int EQU 20h
+
+;
+;
+BeginDoc
+;******************************************************************************
+; The VMMCall and VxDCall macros provide a dynamic link to the VMM and VxD
+; service routines. For example:
+;
+; VMMCall Enable_VM_Ints ; Equivalent to STI in VM code
+;
+; mov eax,[My_IRQ_Handle]
+; VxDCall VPICD_Set_Int_Request ; Set IRQ for my device's interrupt
+;
+; Note that Enable_VM_Ints is defined in VMM.INC and VPICD_Set_Int_Request is
+; defined in VPICD.INC
+;
+;==============================================================================
+EndDoc
+
+
+BeginDoc
+;******************************************************************************
+; VxDCall
+;==============================================================================
+EndDoc
+VxDcall MACRO P, Param
+ PushCParams Param
+ int Dyna_Link_Int
+ dd P
+ ClearCParams 0, Param
+ ENDM
+
+VxDjmp MACRO P, Param
+IFNB <Param>
+%OUT ERROR: Parameters may not be passed to VxDjmp or VMMjmp macros
+.ERR
+ENDIF
+ int Dyna_Link_Int
+IFDEF DEBUG
+ dd P
+ ret
+ELSE
+ dd P OR DL_Jmp_Mask
+ENDIF
+ ENDM
+
+DL_Jmp_Mask EQU 8000h
+DL_Jmp_Bit EQU 0Fh
+
+
+VMMcall MACRO P, Param
+ .ERRNZ (P SHR 16) - VMM_Device_ID
+ VxDcall <P>, <Param>
+ ENDM
+
+VMMjmp MACRO P, Param
+ .ERRNZ (P SHR 16) - VMM_Device_ID
+ VxDjmp <P>, <Param>
+ ENDM
+
+cCall MACRO P, Param
+ PushCParams Param
+ call P
+ ClearCParams 0, Param
+ ENDM
+
+
+BeginDoc
+;******************************************************************************
+; Segment definition macros
+;
+; The segment definition macros are a convenience used in defining the
+; segments used by the device driver. They are:
+;VxD_ICODE_SEG defines start of initialization code segment
+;VxD_ICODE_ENDS defines end of initialization code segment
+;VxD_IDATA_SEG defines start of initialization data segment
+;VxD_IDATA_ENDS defines end of initialization data segment
+;VxD_CODE_SEG defines start of always present code segment
+;VxD_CODE_ENDS defines end of always present code segment
+;VxD_DATA_SEG defines start of always present data segment
+;VxD_DATA_ENDS defines end of always present data segment
+;==============================================================================
+EndDoc
+
+
+; Protected mode code
+VxD_CODE_SEG EQU <VxD_LOCKED_CODE_SEG>
+VxD_CODE_ENDS EQU <VxD_LOCKED_CODE_ENDS>
+
+
+VxD_LOCKED_CODE_SEG MACRO
+_LTEXT SEGMENT
+??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHL 3 + ??_LCODE
+ ASSUME cs:FLAT, ds:FLAT, es:FLAT, ss:FLAT
+ ENDM
+
+VxD_LOCKED_CODE_ENDS MACRO
+??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHR 3
+_LTEXT ENDS
+ ENDM
+
+
+
+; Protected mode initialization code
+VxD_ICODE_SEG MACRO
+_ITEXT SEGMENT
+??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHL 3 + ??_ICODE
+ ASSUME cs:FLAT, ds:FLAT, es:FLAT, ss:FLAT
+ ENDM
+
+VxD_ICODE_ENDS MACRO
+??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHR 3
+_ITEXT ENDS
+ ENDM
+
+
+; Protected mode data
+VxD_DATA_SEG EQU <VxD_LOCKED_DATA_SEG>
+VxD_DATA_ENDS EQU <VxD_LOCKED_DATA_ENDS>
+
+
+
+VxD_LOCKED_DATA_SEG MACRO NO_ALIGN
+_LDATA SEGMENT
+IFB <NO_ALIGN>
+ ALIGN 4
+ENDIF
+ ENDM
+
+VxD_LOCKED_DATA_ENDS MACRO
+_LDATA ENDS
+ ENDM
+
+
+
+
+; Protected mode initialization data
+VxD_IDATA_SEG MACRO
+_IDATA SEGMENT
+ ENDM
+VxD_IDATA_ENDS MACRO
+_IDATA ENDS
+ ENDM
+
+VxD_REAL_INIT_SEG MACRO
+_RCODE SEGMENT
+ASSUME CS:_RCODE, DS:_RCODE, ES:_RCODE, SS:_RCODE
+??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHL 3 + ??_RCODE
+ ENDM
+
+VxD_REAL_INIT_ENDS MACRO
+??_CUR_CODE_SEG = ??_CUR_CODE_SEG SHR 3
+_RCODE ENDS
+ ENDM
+
+ENDIF
+
+DDK_Version equ 300h
+
+VxD_Desc_Block STRUC
+DDB_Next dd ? ; VMM RESERVED FIELD
+DDB_SDK_Version dw DDK_Version ; VMM RESERVED FIELD
+DDB_Req_Device_Number dw Undefined_Device_ID ; Required device number
+DDB_Dev_Major_Version db 0 ; Major device number
+DDB_Dev_Minor_Version db 0 ; Minor device number
+DDB_Flags dw 0 ; Flags for init calls complete
+DDB_Name db " " ; Device name
+DDB_Init_Order dd Undefined_Init_Order; Initialization Order
+DDB_Control_Proc dd ? ; Offset of control procedure
+DDB_V86_API_Proc dd 0 ; Offset of API procedure (or 0)
+DDB_PM_API_Proc dd 0 ; Offset of API procedure (or 0)
+DDB_V86_API_CSIP dd 0 ; CS:IP of API entry point
+DDB_PM_API_CSIP dd 0 ; CS:IP of API entry point
+DDB_Reference_Data dd ? ; Reference data from real mode
+DDB_Service_Table_Ptr dd 0 ; Pointer to service table
+DDB_Service_Table_Size dd 0 ; Number of services
+VxD_Desc_Block ENDS
+
+
+IFNDEF Not_VxD
+
+; flag values for DDB_Flags
+
+DDB_Sys_Crit_Init_Done EQU 00000001b
+DDB_Sys_Crit_Init_Done_Bit EQU 0
+DDB_Device_Init_Done EQU 00000010b
+DDB_Device_Init_Done_Bit EQU 1
+
+BeginDoc
+;******************************************************************************
+;
+; Declare_Virtual_Device macro
+;
+; ???? Write something here ????
+;
+;==============================================================================
+EndDoc
+Declare_Virtual_Device MACRO Name, Major_Ver, Minor_Ver, Ctrl_Proc, Device_Num, Init_Order, V86_Proc, PM_Proc
+ LOCAL V86_API_Offset, PM_API_Offset, Serv_Tab_Offset, Serv_Tab_Len
+
+dev_id_err MACRO
+%OUT Device ID required when providing services
+.ERR
+ ENDM
+
+IFB <V86_Proc>
+ V86_API_Offset EQU 0
+ELSE
+IFB <Device_Num>
+ dev_id_err
+ENDIF
+ V86_API_Offset EQU <OFFSET32 V86_Proc>
+ENDIF
+IFB <PM_Proc>
+ PM_API_Offset EQU 0
+ELSE
+IFB <Device_Num>
+ dev_id_err
+ENDIF
+ PM_API_Offset EQU <OFFSET32 PM_Proc>
+ENDIF
+IFDEF Name&_Service_Table
+IFB <Device_Num>
+ dev_id_err
+ELSE
+IFE Device_Num - Undefined_Device_ID
+ dev_id_err
+ENDIF
+ENDIF
+ Serv_Tab_Offset EQU <OFFSET32 Name&_Service_Table>
+ Serv_Tab_Len EQU Num_&Name&_Services
+ELSE
+ Serv_Tab_Offset EQU 0
+ Serv_Tab_Len EQU 0
+ENDIF
+
+
+VxD_LOCKED_DATA_SEG
+PUBLIC Name&_DDB
+Name&_DDB VxD_Desc_Block <,,Device_Num,Major_Ver,Minor_Ver,,"&Name",Init_Order,\
+ OFFSET32 Ctrl_Proc, V86_API_Offset, PM_API_Offset, \
+ ,,,Serv_Tab_Offset, Serv_Tab_Len>
+VxD_LOCKED_DATA_ENDS
+ ENDM
+
+
+BeginDoc
+;******************************************************************************
+; The Begin_Control_Dispatch macro is used for building a table for dispatching
+; messages passed to the VxD_Control procedure. It is used with
+; Control_Dispatch and End_Control_Dispatch. The only parameter is used to
+; contruct the procedure label by adding "_Control" to the end (normally the
+; device name is used i.e. VKD results in creating the procedure VKD_Control,
+; this created procedure label must be included in Declare_Virtual_Device)
+;
+; An example of building a complete dispatch table:
+;
+; Begin_Control_Dispatch MyDevice
+; Control_Dispatch Device_Init, MyDeviceInitProcedure
+; Control_Dispatch Sys_VM_Init, MyDeviceSysInitProcedure
+; Control_Dispatch Create_VM, MyDeviceCreateVMProcedure
+; End_Control_Dispatch MyDevice
+;
+; (NOTE: Control_Dispatch can be used without Begin_Control_Dispatch, but
+; then it is the programmer's responsibility for declaring a procedure
+; in locked code (VxD_LOCKED_CODE_SEG) and returning Carry clear for
+; any messages not processed. The advantage in using
+; Begin_Control_Dispatch is when a large # of messages are processed by
+; a device, because a jump table is built which will usually require
+; less code space then the compares and jumps that are done when
+; Control_Dispatch is used alone.
+;
+;==============================================================================
+EndDoc
+Begin_Control_Dispatch MACRO VxD_Name
+??_cd_low = 0FFFFFFFFh
+??_cd_high = 0
+
+BeginProc VxD_Name&_Control
+ENDM
+
+End_Control_Dispatch MACRO VxD_Name
+ LOCAL ignore, table
+
+jmpproc MACRO num
+ jmp ??_cd_&&num
+ENDM
+
+procoff MACRO num
+IFDEF ??_cd_&&num
+ dd OFFSET32 ??_cd_&&num
+ELSE
+ dd OFFSET32 ignore
+ENDIF
+ENDM
+
+IF ??_cd_low EQ ??_cd_high
+ cmp eax, ??_cd_low
+ jne short ignore
+ jmpproc %(??_cd_low)
+ignore:
+ clc
+ ret
+ELSE
+ cmp eax, ??_cd_high
+ ja short ignore
+ sub eax, ??_cd_low
+ jb short ignore
+ jmp cs:[eax*4+table]
+ignore:
+ clc
+ ret
+
+table label dword
+ REPT ??_cd_high - ??_cd_low + 1
+ procoff %(??_cd_low)
+ ??_cd_low = ??_cd_low + 1
+ ENDM
+ENDIF
+
+EndProc VxD_Name&_Control
+
+PURGE jmpproc
+PURGE procoff
+PURGE Begin_Control_Dispatch
+PURGE Control_Dispatch
+PURGE End_Control_Dispatch
+ENDM
+
+BeginDoc
+;******************************************************************************
+; The Control_Dispatch macro is used for dispatching based on message
+; passed to the VxD_Control procedure. E.G.:
+;
+; Control_Dispatch Device_Init, MyDeviceInitProcedure
+;
+; (NOTE: Control_Dispatch can be used with Begin_Control_Dispatch and
+; End_Control_Dispatch to create a jump table for dispatching messages,
+; when a large # of messages are processed.)
+;
+;==============================================================================
+EndDoc
+Control_Dispatch MACRO Service, Procedure
+ LOCAL Skip_Interseg_Jump
+
+IFE ?_lcode
+IFDEF ??_cd_low
+Equate_Service MACRO Serv
+??_cd_&&Serv equ Procedure
+ENDM
+
+Equate_Service %(Service)
+
+IF Service LT ??_cd_low
+??_cd_low = Service
+ENDIF
+IF Service GT ??_cd_high
+??_cd_high = Service
+ENDIF
+
+PURGE Equate_Service
+
+ELSE
+ cmp eax, Service
+ jne SHORT Skip_Interseg_Jump
+ jmp Procedure
+Skip_Interseg_Jump:
+ENDIF
+ELSE
+%OUT ERROR: The Control proc should be in LOCKED code.
+%OUT Control_Dispatch can only be used inside of VxD_LOCKED_CODE_SEG.
+.err
+ENDIF
+ ENDM
+
+
+BeginDoc
+;******************************************************************************
+; The following are the definitions for the "type of I/O" parameter passed
+; to a I/O trap routine
+Byte_Input EQU 000h
+Byte_Output EQU 004h
+Word_Input EQU 008h
+Word_Output EQU 00Ch
+Dword_Input EQU 010h
+Dword_Output EQU 014h
+
+Output EQU 0000000000000100b
+Output_Bit EQU 2
+Word_IO EQU 0000000000001000b
+Word_IO_Bit EQU 3
+Dword_IO EQU 0000000000010000b
+Dword_IO_Bit EQU 4
+
+String_IO EQU 00000020h
+String_IO_Bit EQU 5
+Rep_IO EQU 00000040h
+Rep_IO_Bit EQU 6
+Addr_32_IO EQU 00000080h
+Addr_32_IO_Bit EQU 7
+Reverse_IO EQU 00000100h
+Reverse_IO_Bit EQU 8
+
+IO_Seg_Mask EQU 0FFFF0000h ; Use these bits to get segment
+IO_Seg_Shift EQU 10h ; Must shift right this many
+
+;==============================================================================
+EndDoc
+
+BeginDoc
+;******************************************************************************
+;
+; Dispatch_Byte_IO macro
+;
+; Dispatch_Byte_IO Byte_In_Proc, Byte_Out_Proc
+;==============================================================================
+EndDoc
+Dispatch_Byte_IO MACRO In_Proc, Out_Proc
+ LOCAL Byte_IO
+ cmp ecx, Byte_Output
+ jbe SHORT Byte_IO
+ VMMjmp Simulate_IO
+Byte_IO:
+IFIDNI <In_Proc>, <Fall_Through>
+ je Out_Proc
+ELSE
+IFIDNI <Out_Proc>, <Fall_Through>
+ jb In_Proc
+ELSE
+ je Out_Proc
+ jmp In_Proc
+ENDIF
+ENDIF
+ ENDM
+
+BeginDoc
+;******************************************************************************
+;
+; Emulate_Non_Byte_IO
+;
+; Emulate_Non_Byte_IO
+;
+;==============================================================================
+EndDoc
+Emulate_Non_Byte_IO MACRO
+ LOCAL Byte_IO
+ cmp ecx, Byte_Output
+ jbe SHORT Byte_IO
+ VMMjmp Simulate_IO
+Byte_IO:
+ ENDM
+
+
+VxD_IOT_Hdr STRUC
+VxD_IO_Ports dw ?
+VxD_IOT_Hdr ENDS
+
+VxD_IO_Struc STRUC
+VxD_IO_Port dw ?
+VxD_IO_Proc dd ?
+VxD_IO_Struc ENDS
+
+
+BeginDoc
+;******************************************************************************
+;
+; Begin_VxD_IO_Table
+;
+; Example:
+; Begin_VxD_IO_Table MyTableName
+;
+;==============================================================================
+EndDoc
+.ERRNZ SIZE VxD_IOT_Hdr - 2 ; Begin_VxD_IO_Table creates a 1 word count hdr
+Begin_VxD_IO_Table MACRO Table_Name
+PUBLIC Table_Name
+Table_Name LABEL WORD
+IF2
+IFNDEF Table_Name&_Entries
+%OUT ERROR: No End_VxD_IO_Table for &Table_Name
+.ERR
+ENDIF
+ dw Table_Name&_Entries
+ELSE
+ dw ?
+ENDIF
+
+ ENDM
+
+.ERRNZ SIZE VxD_IO_Struc - 6 ; VxD_IO creates 6 byte I/O port entries
+VxD_IO MACRO Port, Proc_Name
+ dw Port
+ dd OFFSET32 Proc_Name
+ ENDM
+
+End_VxD_IO_Table MACRO Table_Name
+
+IFNDEF Table_Name
+%OUT ERROR: No Begin_VxD_IO_Table for &Table_Name
+.ERR
+ELSE
+ Table_Name&_Entries EQU (($-Table_Name)-2) / (SIZE VxD_IO_Struc)
+IF Table_Name&_Entries LE 0
+%OUT ERROR: Invalid number of port traps in &Table_Name
+.ERR
+ENDIF
+ENDIF
+ ENDM
+
+
+;******************************************************************************
+;******************************************************************************
+
+Push_Client_State MACRO
+ sub esp, SIZE Client_Reg_Struc
+ push edi
+ lea edi, [esp+4]
+ VMMcall Save_Client_State
+ pop edi
+ ENDM
+
+Pop_Client_State MACRO
+ push esi
+ lea esi, [esp+4]
+ VMMcall Restore_Client_State
+ pop esi
+ add esp, SIZE Client_Reg_Struc
+ ENDM
+
+BeginDoc
+;******************************************************************************
+;
+; CallRet -- Call procedure and return. For debugging purposes only.
+; If compiled with debugging then this will generate a call
+; followed by a return. If non-debugging version then the
+; specified label will be jumped to.
+;
+; PARAMETERS:
+; Label_Name = Procedure to be called
+;
+; EXIT:
+; Return from current procedure
+;
+;------------------------------------------------------------------------------
+EndDoc
+
+CallRet MACRO P1, P2
+IFDEF DEBUG
+IFIDNI <P1>, <SHORT>
+ call P2
+ELSE
+ call P1
+ENDIF
+ ret
+ELSE
+ jmp P1 P2
+ENDIF
+ ENDM
+
+
+; ebp offsets to segments pushed by PMode_Fault in Fault_Dispatch
+PClient_DS equ WORD PTR -4
+PClient_ES equ WORD PTR -8
+PClient_FS equ WORD PTR -12
+PClient_GS equ WORD PTR -16
+
+
+Client_Ptr_Flat MACRO Reg_32, Cli_Seg, Cli_Off
+
+IFDIFI <Reg_32>, <EAX>
+ push eax
+ENDIF
+IFB <Cli_Off>
+ mov ax, (Client_&Cli_Seg * 100h) + 0FFh
+ELSE
+ mov ax, (Client_&Cli_Seg * 100h) + Client_&Cli_Off
+ENDIF
+ VMMcall Map_Flat
+
+IFDIFI <Reg_32>, <EAX>
+ mov Reg_32, eax
+ pop eax
+ENDIF
+
+ ENDM
+
+;------------------------------------------------------------------------------
+
+VxDint MACRO Int_Number
+ push DWORD PTR Int_Number
+ VMMcall Exec_VxD_Int
+ ENDM
+
+
+ENDIF ; Not_VxD
+
+
+BeginDoc
+;******************************************************************************
+;
+; The following equates are for flags sent to the real mode
+; initialization portion of a device driver:
+;
+Duplicate_Device_ID equ 0000000000000001b ; duplicate device ID already
+Duplicate_Device_ID_Bit equ 0 ; loaded
+Duplicate_From_INT2F equ 0000000000000010b ; duplicate device ID already
+Duplicate_From_INT2F_Bit equ 1 ; loaded as part of INT 2F
+ ; device list
+Loading_From_INT2F equ 0000000000000100b ; this device was specified
+Loading_From_INT2F_Bit equ 2 ; in the INT 2F device list
+
+EndDoc
+
+BeginDoc
+;******************************************************************************
+;
+; The following equates are used to indicate the result of the real mode
+; initialization portion of a device driver:
+;
+
+Device_Load_Ok equ 0 ; protected mode portion of device
+ ; should be loaded
+Abort_Device_Load equ 1 ; don't load any protected mode portion
+ ; of this device, but continue loading
+ ; the rest of the devices
+Abort_Win386_Load equ 2 ; fatal-error: abort the load of Win386
+
+No_Fail_Message equ 8000h ; The high bit is set in the return
+No_Fail_Message_Bit equ 15 ; code, if the loader should not print
+ ; any message for results
+ ; Abort_Device_Load or Abort_Win386_Load
+;==============================================================================
+EndDoc
+
+
+;==============================================================================
+
+; CR0 bit assignments
+PE_Mask EQU 0001h ; 1 = Protected Mode
+PE_Bit EQU 0
+MP_Mask EQU 0002h ; 1 = Monitor Coprocessor
+MP_Bit EQU 1
+EM_Mask EQU 0004h ; 1 = Emulate Math Coprocessor
+EM_Bit EQU 2
+TS_Mask EQU 0008h ; 1 = Task Switch occured
+TS_Bit EQU 3
+ET_Mask EQU 0010h ; 1 = 387 present, 0 = 287 present
+ET_Bit EQU 4
+PG_Mask EQU 80000000h ; 1 = paging enabled, 0 = paging disabled
+PG_Bit EQU 31
+
+; EFLAGs bit assignments
+CF_Mask EQU 000000000000000001b ; Carry flag
+CF_Bit EQU 0
+PF_Mask EQU 000000000000000100b ; Parity flag
+PF_Bit EQU 2
+AF_Mask EQU 000000000000010000b ; Aux flag
+AF_Bit EQU 4
+ZF_Mask EQU 000000000001000000b ; Zero flag
+ZF_Bit EQU 6
+SF_Mask EQU 000000000010000000b ; Sign flag
+SF_Bit EQU 7
+TF_Mask EQU 000000000100000000b ; Trace flag
+TF_Bit EQU 8
+IF_Mask EQU 000000001000000000b ; Int flag
+IF_Bit EQU 9
+DF_Mask EQU 000000010000000000b ; Direction flag
+DB_Bit EQU 10
+OF_Mask EQU 000000100000000000b ; Overflow flag
+OF_Bit EQU 11
+IOPL_Mask EQU 000011000000000000b ; IOPL flags
+IOPL_Bit0 EQU 12
+IOPL_Bit1 EQU 13
+NT_Mask EQU 000100000000000000b ; Nested task flag
+NT_Bit EQU 14
+RF_Mask EQU 010000000000000000b ; Resume flag
+RF_Bit EQU 16
+VM_Mask EQU 100000000000000000b ; Virtual Mode flag
+VM_Bit EQU 17
+
+
+;------------------------------------------------------------------------------
+;
+; Temporary MASM macros (to be removed when supported by MASM)
+;
+;------------------------------------------------------------------------------
+
+loopd EQU <loop>
+loopde EQU <loope>
+loopdne EQU <loopne>
+loopdz EQU <loopz>
+loopdnz EQU <loopnz>
+
+
+;******************************************************************************
+; PAGE TABLE EQUATES
+;******************************************************************************
+
+
+P_SIZE equ 1000h ; page size
+
+; ---------------------------------------------------
+;
+; Page table entry bits
+;
+; ---------------------------------------------------
+
+P_PRES equ 01h ; page present bit
+P_WRITE equ 02h ; write access bit
+P_USER equ 04h ; access bit for User mode
+P_ACC equ 20h ; page accessed bit
+P_DIRTY equ 40h ; page dirty bit
+
+P_AVAIL equ (P_PRES+P_WRITE+P_USER) ; avail to everyone & present
+
+; ---------------------------------------------------
+;
+; Page types - definition of the OS reserved bits in the page table
+; entry.
+; ---------------------------------------------------
+
+PG_TYPE equ 0E00h ; TYPE bits in PTE
+
+; ---------------------------------------------------
+;
+; Page types for page allocator calls
+;
+; ---------------------------------------------------
+PG_VM equ 0
+PG_SYS equ 1
+PG_RESERVED1 equ 2
+PG_PRIVATE equ 3
+PG_RESERVED2 equ 4
+PG_RELOCK equ 5 ; PRIVATE to MMGR
+PG_INSTANCE equ 6
+PG_HOOKED equ 7
+PG_IGNORE equ 0FFFFFFFFh
+
+
+; ---------------------------------------------------
+;
+; Types for page table entries
+;
+; ---------------------------------------------------
+PgT_VM equ PG_VM SHL 9
+PgT_SYS equ PG_SYS SHL 9
+PgT_RESERVED1 equ PG_RESERVED1 SHL 9
+PgT_PRIVATE equ PG_PRIVATE SHL 9
+PgT_RESERVED2 equ PG_RESERVED2 SHL 9
+PgT_RELOCK equ PG_RELOCK SHL 9
+PgT_INSTANCE equ PG_INSTANCE SHL 9
+PgT_HOOKED equ PG_HOOKED SHL 9
+
+
+
+;******************************************************************************
+
+; ---------------------------------------------------
+;
+; Definitions for the access byte in a descriptor
+;
+; ---------------------------------------------------
+
+
+; Following fields are common to segment and control descriptors
+
+D_PRES equ 080h ; present in memory
+D_NOTPRES equ 0 ; not present in memory
+
+D_DPL0 equ 0 ; Ring 0
+D_DPL1 equ 020h ; Ring 1
+D_DPL2 equ 040h ; Ring 2
+D_DPL3 equ 060h ; Ring 3
+
+D_SEG equ 010h ; Segment descriptor
+D_CTRL equ 0 ; Control descriptor
+
+D_GRAN_BYTE equ 000h ; Segment length is byte granular
+D_GRAN_PAGE equ 080h ; Segment length is page granular
+D_DEF16 equ 000h ; Default operation size is 16 bits
+D_DEF32 equ 040h ; Default operation size is 32 bits
+
+
+; Following fields are specific to segment descriptors
+
+D_CODE equ 08h ; code
+D_DATA equ 0 ; data
+
+D_RX equ 02h ; if code, readable
+D_X equ 0 ; if code, exec only
+D_W equ 02h ; if data, writable
+D_R equ 0 ; if data, read only
+
+D_ACCESSED equ 1 ; segment accessed bit
+
+
+; Useful combination access rights bytes
+
+RW_Data_Type equ (D_PRES+D_SEG+D_DATA+D_W)
+R_Data_Type equ (D_PRES+D_SEG+D_DATA+D_R)
+Code_Type equ (D_PRES+D_SEG+D_CODE+D_RX)
+
+D_PAGE32 equ (D_GRAN_PAGE+D_DEF32) ; 32 bit Page granular
+
+; Masks for selector fields
+
+SELECTOR_MASK equ 0fff8h ; selector index
+SEL_LOW_MASK equ 0f8h ; mask for low byte of sel indx
+TABLE_MASK equ 04h ; table bit
+RPL_MASK equ 03h ; privilige bits
+RPL_CLR equ not 03h ; clear ring bits
diff --git a/private/os2/client/thunk/include/vpicd.inc b/private/os2/client/thunk/include/vpicd.inc
new file mode 100644
index 000000000..586232065
--- /dev/null
+++ b/private/os2/client/thunk/include/vpicd.inc
@@ -0,0 +1,86 @@
+;******************************************************************************
+;
+; (C) Copyright MICROSOFT Corp., 1988-1990
+;
+; Title: VPICD.INC - Include file for Virtual PIC Device
+;
+; Version: 3.00
+;
+; Date: 13-Apr-1988
+;
+; Author: RAL
+;
+;------------------------------------------------------------------------------
+;
+; Change log:
+;
+; DATE REV DESCRIPTION
+; ----------- --- -----------------------------------------------------------
+; 13-Apr-1988 RAL Rewrite
+; 20-Oct-1988 RAL Added VPICD_Test_Phys_Request service
+;
+;==============================================================================
+
+;
+; Equates for result from VPICD_Get_Status
+;
+VPICD_Stat_IRET_Pending EQU 00000001b
+VPICD_Stat_IRET_Pending_Bit EQU 0
+VPICD_Stat_In_Service EQU 00000010b
+VPICD_Stat_In_Service_Bit EQU 1
+VPICD_Stat_Phys_Mask EQU 00000100b
+VPICD_Stat_Phys_Mask_Bit EQU 2
+VPICD_Stat_Phys_In_Serv EQU 00001000b
+VPICD_Stat_Phys_In_Serv_Bit EQU 3
+VPICD_Stat_Virt_Mask EQU 00010000b
+VPICD_Stat_Virt_Mask_Bit EQU 4
+VPICD_Stat_Virt_Req EQU 00100000b
+VPICD_Stat_Virt_Req_Bit EQU 5
+VPICD_Stat_Phys_Req EQU 01000000b
+VPICD_Stat_Phys_Req_Bit EQU 6
+VPICD_Stat_Virt_Dev_Req EQU 10000000b
+VPICD_Stat_Virt_Dev_Req_Bit EQU 7
+
+;
+; Equates for options in IRQ Descriptor
+;
+VPICD_Opt_Read_Hw_IRR EQU 00000001b
+VPICD_Opt_Read_Hw_IRR_Bit EQU 0
+VPICD_Opt_Can_Share EQU 00000010b
+VPICD_Opt_Can_Share_Bit EQU 1
+
+
+VPICD_IRQ_Descriptor STRUC
+VID_IRQ_Number dw ?
+VID_Options dw 0
+VID_Hw_Int_Proc dd ?
+VID_Virt_Int_Proc dd 0
+VID_EOI_Proc dd 0
+VID_Mask_Change_Proc dd 0
+VID_IRET_Proc dd 0
+VID_IRET_Time_Out dd 500
+VPICD_IRQ_Descriptor ENDS
+
+
+Begin_Service_Table VPICD
+
+VPICD_Service VPICD_Get_Version, VxD_LOCKED_CODE
+VPICD_Service VPICD_Virtualize_IRQ, VxD_LOCKED_CODE
+VPICD_Service VPICD_Set_Int_Request, VxD_LOCKED_CODE
+VPICD_Service VPICD_Clear_Int_Request, VxD_LOCKED_CODE
+VPICD_Service VPICD_Phys_EOI, VxD_LOCKED_CODE
+VPICD_Service VPICD_Get_Complete_Status, VxD_LOCKED_CODE
+VPICD_Service VPICD_Get_Status, VxD_LOCKED_CODE
+VPICD_Service VPICD_Test_Phys_Request, VxD_LOCKED_CODE
+VPICD_Service VPICD_Physically_Mask, VxD_LOCKED_CODE
+VPICD_Service VPICD_Physically_Unmask, VxD_LOCKED_CODE
+VPICD_Service VPICD_Set_Auto_Masking, VxD_LOCKED_CODE
+VPICD_Service VPICD_Get_IRQ_Complete_Status, VxD_LOCKED_CODE
+VPICD_Service VPICD_Convert_Handle_To_IRQ, VxD_LOCKED_CODE
+VPICD_Service VPICD_Convert_IRQ_To_Int, VxD_LOCKED_CODE
+VPICD_Service VPICD_Convert_Int_To_IRQ, VxD_LOCKED_CODE
+VPICD_Service VPICD_Call_When_Hw_Int, VxD_LOCKED_CODE
+VPICD_Service VPICD_Force_Default_Owner, VxD_LOCKED_CODE
+VPICD_Service VPICD_Force_Default_Behavior, VxD_LOCKED_CODE
+
+End_Service_Table VPICD
diff --git a/private/os2/client/thunk/include/vtd.inc b/private/os2/client/thunk/include/vtd.inc
new file mode 100644
index 000000000..518b8c324
--- /dev/null
+++ b/private/os2/client/thunk/include/vtd.inc
@@ -0,0 +1,35 @@
+;******************************************************************************
+;
+; (C) Copyright MICROSOFT Corp., 1988-1990
+;
+; Title: VTD.INC -
+;
+; Version: 1.00
+;
+; Date: 10-Aug-1988
+;
+; Author: RAL
+;
+;------------------------------------------------------------------------------
+;
+; Change log:
+;
+; DATE REV DESCRIPTION
+; ----------- --- -----------------------------------------------------------
+; 10-Aug-1988 RAL Original
+; 12-Oct-1988 RAL Converted to VxD_Service_Table macros
+;
+;==============================================================================
+
+
+Begin_Service_Table VTD
+
+VTD_Service VTD_Get_Version, LOCAL
+VTD_Service VTD_Update_System_Clock, LOCAL
+VTD_Service VTD_Get_Interrupt_Period, LOCAL
+VTD_Service VTD_Begin_Min_Int_Period, LOCAL
+VTD_Service VTD_End_Min_Int_Period, LOCAL
+VTD_Service VTD_Disable_Trapping, LOCAL
+VTD_Service VTD_Enable_Trapping, LOCAL
+
+End_Service_Table VTD
diff --git a/private/os2/client/thunk/include/win32.h b/private/os2/client/thunk/include/win32.h
new file mode 100644
index 000000000..6033f2228
--- /dev/null
+++ b/private/os2/client/thunk/include/win32.h
@@ -0,0 +1,90 @@
+/***************************************************************************\
+* Module Name: WINDOWS.H
+*
+* Copyright (c) 1985-91, Microsoft Corporation
+*
+* Master include file for Windows applications.
+*
+\***************************************************************************/
+
+#ifndef _WINDOWS_
+#define _WINDOWS_
+
+/* If defined, the following flags inhibit definition
+ * of the indicated items.
+ *
+ * NOGDICAPMASKS - CC_*, LC_*, PC_*, CP_*, TC_*, RC_
+ * NOVIRTUALKEYCODES - VK_*
+ * NOWINMESSAGES - WM_*, EM_*, LB_*, CB_*
+ * NOWINSTYLES - WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
+ * NOSYSMETRICS - SM_*
+ * NOMENUS - MF_*
+ * NOICONS - IDI_*
+ * NOKEYSTATES - MK_*
+ * NOSYSCOMMANDS - SC_*
+ * NORASTEROPS - Binary and Tertiary raster ops
+ * NOSHOWWINDOW - SW_*
+ * OEMRESOURCE - OEM Resource values
+ * NOATOM - Atom Manager routines
+ * NOCLIPBOARD - Clipboard routines
+ * NOCOLOR - Screen colors
+ * NOCTLMGR - Control and Dialog routines
+ * NODRAWTEXT - DrawText() and DT_*
+ * NOGDI - All GDI defines and routines
+ * NOKERNEL - All KERNEL defines and routines
+ * NOUSER - All USER defines and routines
+ * NOMB - MB_* and MessageBox()
+ * NOMEMMGR - GMEM_*, LMEM_*, GHND, LHND, associated routines
+ * NOMETAFILE - typedef METAFILEPICT
+ * NOMINMAX - Macros min(a,b) and max(a,b)
+ * NOMSG - typedef MSG and associated routines
+ * NOOPENFILE - OpenFile(), OemToAnsi, AnsiToOem, and OF_*
+ * NOSCROLL - SB_* and scrolling routines
+ * NOSOUND - Sound driver routines
+ * NOTEXTMETRIC - typedef TEXTMETRIC and associated routines
+ * NOWH - SetWindowsHook and WH_*
+ * NOWINOFFSETS - GWL_*, GCL_*, associated routines
+ * NOCOMM - COMM driver routines
+ * NOKANJI - Kanji support stuff.
+ * NOHELP - Help engine interface.
+ * NOPROFILER - Profiler interface.
+ * NODEFERWINDOWPOS - DeferWindowPos routines
+ */
+
+
+#define DOSWIN32
+#define i386
+
+#ifdef RC_INVOKED
+
+/* Turn off a bunch of stuff to ensure that RC files compile OK. */
+#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 NOCOMM
+#define NOKANJI
+
+#endif /* RC_INVOKED */
+
+#include <windef.h>
+#include <winbase.h>
+#include <wincon.h>
+#include <wingdi.h>
+#include <winuser.h>
+// #include <excpt.h>
+#include <winmm.h>
+
+LPSTR APIENTRY
+HeapReAlloc(HANDLE hHeap, LPSTR pmem, DWORD dwBytes, DWORD flags);
+
+#endif // _WINDOWS_
diff --git a/private/os2/client/thunk/include/winbase.h b/private/os2/client/thunk/include/winbase.h
new file mode 100644
index 000000000..981105e82
--- /dev/null
+++ b/private/os2/client/thunk/include/winbase.h
@@ -0,0 +1,2224 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ winbase.h
+
+Abstract:
+
+ This module defines the 32-Bit Windows Base APIs
+
+Author:
+
+ Mark Lucovsky (markl) 18-Sep-1990
+
+Revision History:
+
+--*/
+
+#ifndef _WINBASE_
+#define _WINBASE_
+
+/*
+ * Compatability macros
+ */
+
+#define DefineHandleTable(w) ((w),TRUE)
+#define LimitEmsPages(dw)
+#define LockSegment(w) (HANDLE)(w)
+#define SetSwapAreaSize(w)
+#define UnlockSegment(w) (HANDLE)(w)
+
+#define INVALID_HANDLE_VALUE (HANDLE)-1
+#define FILE_BEGIN 0
+#define FILE_CURRENT 1
+#define FILE_END 2
+#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
+
+#define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 )
+
+#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 )
+#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 )
+
+#define WAIT_TIMEOUT STATUS_TIMEOUT
+#define STILL_ACTIVE STATUS_PENDING
+#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION
+#define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT
+#define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT
+#define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP
+
+//
+// File creation flags must start in second byte since they
+// are combined with the attributes
+//
+
+#define FILE_FLAG_WRITE_THROUGH 0x00000100
+#define FILE_FLAG_OVERLAPPED 0x00000200
+
+#define CREATE_NEW 1
+#define CREATE_ALWAYS 2
+#define OPEN_EXISTING 3
+#define OPEN_ALWAYS 4
+#define TRUNCATE_EXISTING 5
+
+//
+// Define the NamedPipe definitions
+//
+
+
+//
+// Define the dwOpenMode values for CreateNamedPipe
+//
+
+#define PIPE_ACCESS_INBOUND 0x00000000
+#define PIPE_ACCESS_OUTBOUND 0x00000001
+#define PIPE_ACCESS_DUPLEX 0x00000002
+
+//
+// Define the Named Pipe End flags for GetNamedPipeInfo
+//
+
+#define PIPE_CLIENT_END 0x00000000
+#define PIPE_SERVER_END 0x00000001
+
+//
+// Define the dwPipeMode values for CreateNamedPipe
+//
+
+#define PIPE_WAIT 0x00000000
+#define PIPE_NOWAIT 0x00000001
+#define PIPE_READMODE_BYTE 0x00000000
+#define PIPE_READMODE_MESSAGE 0x00000002
+#define PIPE_TYPE_BYTE 0x00000000
+#define PIPE_TYPE_MESSAGE 0x00000004
+
+//
+// Define the well known values for CreateNamedPipe nMaxInstances
+//
+
+#define PIPE_UNLIMITED_INSTANCES 255
+
+//
+// File structures
+//
+
+typedef struct _OVERLAPPED {
+ DWORD Internal;
+ DWORD InternalHigh;
+ DWORD Offset;
+ DWORD OffsetHigh;
+ HANDLE hEvent;
+} OVERLAPPED;
+typedef OVERLAPPED *LPOVERLAPPED;
+
+typedef PHANDLE LPHANDLE;
+
+typedef struct _SECURITY_ATTRIBUTES {
+ DWORD nLength;
+ LPVOID lpSecurityDescriptor;
+ BOOL bInheritHandle;
+} SECURITY_ATTRIBUTES;
+typedef SECURITY_ATTRIBUTES *PSECURITY_ATTRIBUTES;
+typedef SECURITY_ATTRIBUTES *LPSECURITY_ATTRIBUTES;
+
+typedef struct _PROCESS_INFORMATION {
+ HANDLE hProcess;
+ HANDLE hThread;
+ DWORD dwProcessId;
+ DWORD dwThreadId;
+} PROCESS_INFORMATION;
+typedef PROCESS_INFORMATION *PPROCESS_INFORMATION;
+typedef PROCESS_INFORMATION *LPPROCESS_INFORMATION;
+
+//
+// File System time stamps are represented with the following structure:
+//
+
+typedef struct _FILETIME {
+ DWORD dwLowDateTime;
+ DWORD dwHighDateTime;
+} FILETIME;
+typedef FILETIME *PFILETIME;
+typedef FILETIME *LPFILETIME;
+
+//
+// System time is represented with the following structure:
+//
+
+typedef struct _SYSTEMTIME {
+ WORD wYear;
+ WORD wMonth;
+ WORD wDayOfWeek;
+ WORD wDay;
+ WORD wHour;
+ WORD wMinute;
+ WORD wSecond;
+ WORD wMilliseconds;
+} SYSTEMTIME;
+typedef SYSTEMTIME *PSYSTEMTIME;
+typedef SYSTEMTIME *LPSYSTEMTIME;
+
+typedef struct _WIN32_FIND_DATA {
+ DWORD dwFileAttributes;
+ FILETIME ftCreationTime;
+ FILETIME ftLastAccessTime;
+ FILETIME ftLastWriteTime;
+ DWORD nFileSizeHigh;
+ DWORD nFileSizeLow;
+ BYTE cFileName[ MAX_PATH ];
+} WIN32_FIND_DATA;
+typedef WIN32_FIND_DATA *PWIN32_FIND_DATA;
+typedef WIN32_FIND_DATA *LPWIN32_FIND_DATA;
+
+typedef DWORD (*PTHREAD_START_ROUTINE)(
+ LPVOID lpThreadParameter
+ );
+typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE;
+
+typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
+typedef PRTL_CRITICAL_SECTION PCRITICAL_SECTION;
+typedef PRTL_CRITICAL_SECTION LPCRITICAL_SECTION;
+
+#define MUTEX_MODIFY_STATE MUTANT_QUERY_STATE
+#define MUTEX_ALL_ACCESS MUTANT_ALL_ACCESS
+
+typedef struct _COMSTAT {
+ DWORD fCtsHold : 1;
+ DWORD fDsrHold : 1;
+ DWORD fRlsdHold : 1;
+ DWORD fXoffHold : 1;
+ DWORD fXoffSent : 1;
+ DWORD fEof : 1;
+ DWORD fTxim : 1;
+ DWORD fReserved : 17;
+ DWORD cbInQue;
+ DWORD cbOutQue;
+} COMSTAT;
+typedef COMSTAT *LPCOMSTAT;
+
+typedef struct _DCB {
+ BYTE Id; /* Internal Device ID */
+ BYTE ByteSize; /* Number of bits/byte, 4-8 */
+ BYTE Parity; /* 0-4=None,Odd,Even,Mark,Space */
+ BYTE StopBits; /* 0,1,2 = 1, 1.5, 2 */
+ WORD BaudRate; /* Baudrate at which runing */
+ WORD RlsTimeout; /* Timeout for RLSD to be set */
+ WORD CtsTimeout; /* Timeout for CTS to be set */
+ WORD DsrTimeout; /* Timeout for DSR to be set */
+
+ DWORD fBinary: 1; /* Binary Mode (skip EOF check */
+ DWORD fRtsDisable:1; /* Don't assert RTS at init time */
+ DWORD fParity: 1; /* Enable parity checking */
+ DWORD fOutxCtsFlow:1; /* CTS handshaking on output */
+ DWORD fOutxDsrFlow:1; /* DSR handshaking on output */
+ DWORD fDummy: 2; /* Reserved */
+ DWORD fDtrDisable:1; /* Don't assert DTR at init time */
+
+ DWORD fOutX: 1; /* Enable output X-ON/X-OFF */
+ DWORD fInX: 1; /* Enable input X-ON/X-OFF */
+ DWORD fPeChar: 1; /* Enable Parity Err Replacement */
+ DWORD fNull: 1; /* Enable Null stripping */
+ DWORD fChEvt: 1; /* Enable Rx character event. */
+ DWORD fDtrflow: 1; /* DTR handshake on input */
+ DWORD fRtsflow: 1; /* RTS handshake on input */
+ DWORD fDummy2: 1;
+
+ char XonChar; /* Tx and Rx X-ON character */
+ char XoffChar; /* Tx and Rx X-OFF character */
+ WORD XonLim; /* Transmit X-ON threshold */
+ WORD XoffLim; /* Transmit X-OFF threshold */
+ char PeChar; /* Parity error replacement char */
+ char EofChar; /* End of Input character */
+ char EvtChar; /* Recieved Event character */
+ WORD TxDelay; /* Amount of time between chars */
+} DCB;
+typedef DCB *LPDCB;
+
+
+HANDLE
+APIENTRY
+LoadLibrary(
+ LPSTR lpLibFileName
+ );
+
+BOOL
+APIENTRY
+FreeLibrary(
+ HANDLE hLibModule
+ );
+
+#define FreeModule(hLibModule) FreeLibrary((hLibModule))
+#define MakeProcInstance(lpProc,hInstance) (lpProc)
+#define FreeProcInstance(lpProc)
+
+DWORD
+APIENTRY
+GetModuleFileName(
+ HANDLE hModule,
+ LPSTR lpFilename,
+ DWORD nSize
+ );
+
+HANDLE
+APIENTRY
+GetModuleHandle(
+ LPSTR lpModuleName
+ );
+
+FARPROC
+APIENTRY
+GetProcAddress(
+ HANDLE hModule,
+ LPSTR lpProcName
+ );
+
+DWORD
+APIENTRY
+GetVersion( VOID );
+
+/* 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)
+
+HANDLE
+APIENTRY
+GlobalAlloc(
+ DWORD dwFlags,
+ DWORD dwBytes
+ );
+
+HANDLE
+APIENTRY
+GlobalReAlloc(
+ HANDLE hMem,
+ DWORD dwBytes,
+ DWORD dwFlags
+ );
+
+DWORD
+APIENTRY
+GlobalSize(
+ HANDLE hMem
+ );
+
+DWORD
+APIENTRY
+GlobalFlags(
+ HANDLE hMem
+ );
+
+LPVOID
+APIENTRY
+GlobalFree(
+ HANDLE hMem
+ );
+
+#define GlobalLock( h ) (LPSTR)(h)
+#define GlobalUnlock( h ) ((h), FALSE)
+#define GlobalDiscard( h ) (HANDLE)(h)
+#define GlobalLRUNewest( h ) (HANDLE)(h)
+#define GlobalLRUOldest( h ) (HANDLE)(h)
+#define GlobalNotify( lpfn ) ((lpfn), TRUE)
+#define GlobalCompact( dw ) (0x100000L)
+#define GlobalFix( h )
+#define GlobalUnfix( h ) (0)
+#define GlobalUnWire( h ) (TRUE)
+#define GlobalWire( h ) (LPSTR)(h)
+
+typedef struct _MEMORYSTATUS {
+ DWORD dwLength;
+ DWORD dwMemoryLoad;
+ DWORD dwTotalPhys;
+ DWORD dwAvailPhys;
+ DWORD dwTotalPageFile;
+ DWORD dwAvailPageFile;
+ DWORD dwTotalVirtual;
+ DWORD dwAvailVirtual;
+} MEMORYSTATUS;
+typedef MEMORYSTATUS *LPMEMORYSTATUS;
+
+VOID
+APIENTRY
+GlobalMemoryStatus(
+ LPMEMORYSTATUS lpBuffer
+ );
+
+/* Local Memory Flags */
+#define LMEM_FIXED 0x0000
+#define LMEM_MOVEABLE 0x0002
+#define LMEM_ZEROINIT 0x0040
+
+#define LHND (LMEM_MOVEABLE | LMEM_ZEROINIT)
+#define LPTR (LMEM_FIXED | LMEM_ZEROINIT)
+
+#define NONZEROLHND (LMEM_MOVEABLE)
+#define NONZEROLPTR (LMEM_FIXED)
+
+BOOL
+APIENTRY
+LocalInit(
+ LPVOID lpMem,
+ LPSTR pStart,
+ LPSTR pEnd
+ );
+
+HANDLE
+APIENTRY
+LocalAlloc(
+ DWORD dwFlags,
+ DWORD dwBytes
+ );
+
+HANDLE
+APIENTRY
+LocalReAlloc(
+ HANDLE hMem,
+ DWORD dwBytes,
+ DWORD dwFlags
+ );
+
+LPSTR
+APIENTRY
+LocalLock(
+ HANDLE hMem
+ );
+
+
+HANDLE
+APIENTRY
+LocalUnlock(
+ HANDLE hMem
+ );
+
+DWORD
+APIENTRY
+LocalSize(
+ HANDLE hMem
+ );
+
+HANDLE
+APIENTRY
+LocalFree(
+ HANDLE hMem
+ );
+
+#define LocalShrink( h, n ) (0x10000)
+#define LocalCompact( h ) (0x10000)
+#define LocalDiscard( h ) (NULL)
+#define LocalFlags( h ) ((h), 0)
+#define LocalHandle( h ) (h)
+
+LPVOID
+APIENTRY
+VirtualAlloc(
+ LPVOID lpAddress,
+ DWORD dwSize,
+ DWORD flAllocationType,
+ DWORD flProtect
+ );
+
+BOOL
+APIENTRY
+VirtualFree(
+ LPVOID lpAddress,
+ DWORD dwSize,
+ DWORD dwFreeType
+ );
+
+BOOL
+APIENTRY
+VirtualProtect(
+ LPVOID lpAddress,
+ DWORD dwSize,
+ DWORD flNewProtect,
+ PDWORD lpflOldProtect
+ );
+
+DWORD
+APIENTRY
+VirtualQuery(
+ LPVOID lpAddress,
+ PMEMORY_BASIC_INFORMATION lpBuffer,
+ DWORD dwLength
+ );
+
+HANDLE
+APIENTRY
+HeapCreate(
+ DWORD flOptions,
+ DWORD dwInitialSize,
+ DWORD dwMaximumSize
+ );
+
+#define HEAP_SERIALIZE 0x00000001
+
+
+BOOL
+APIENTRY
+HeapDestroy(
+ HANDLE hHeap
+ );
+
+LPSTR
+APIENTRY
+HeapAlloc(
+ HANDLE hHeap,
+ DWORD dwBytes
+ );
+
+BOOL
+APIENTRY
+HeapFree(
+ HANDLE hHeap,
+ LPSTR lpMem
+ );
+
+DWORD
+APIENTRY
+HeapSize(
+ HANDLE hHeap,
+ LPSTR lpMem
+ );
+
+typedef struct _STARTUPINFO {
+ DWORD cb;
+ LPSTR lpReserved;
+ LPSTR lpDesktop;
+ LPSTR lpTitle;
+ DWORD dwX;
+ DWORD dwY;
+ DWORD dwXSize;
+ DWORD dwYSize;
+ DWORD dwFlags;
+ WORD wShowWindow;
+ WORD cbReserved2;
+ LPBYTE lpReserved2;
+} STARTUPINFO;
+typedef STARTUPINFO *LPSTARTUPINFO;
+
+//
+// dwCreationFlag values
+//
+
+#define DEBUG_PROCESS 0x00000001
+#define DEBUG_ONLY_THIS_PROCESS 0x00000002
+
+#define PROFILE_USER 0x10000000
+#define PROFILE_KERNEL 0x20000000
+#define PROFILE_SERVER 0x40000000
+
+BOOL
+APIENTRY
+CreateProcess(
+ LPSTR lpApplicationName,
+ LPSTR lpCommandLine,
+ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ BOOL bInheritHandles,
+ DWORD dwCreationFlags,
+ LPVOID lpEnvironment,
+ LPSTR lpCurrentDirectory,
+ LPSTARTUPINFO lpStartupInfo,
+ LPPROCESS_INFORMATION lpProcessInformation
+ );
+
+HANDLE
+APIENTRY
+OpenProcess(
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ DWORD dwProcessId
+ );
+
+HANDLE
+APIENTRY
+GetCurrentProcess(
+ VOID
+ );
+
+DWORD
+APIENTRY
+GetCurrentProcessId(
+ VOID
+ );
+
+VOID
+APIENTRY
+ExitProcess(
+ DWORD dwExitCode
+ );
+
+BOOL
+APIENTRY
+TerminateProcess(
+ HANDLE hProcess,
+ DWORD dwExitCode
+ );
+
+BOOL
+APIENTRY
+GetExitCodeProcess(
+ HANDLE hProcess,
+ LPDWORD lpExitCode
+ );
+
+VOID
+APIENTRY
+GetStartupInfo(
+ LPSTARTUPINFO lpStartupInfo
+ );
+
+VOID
+APIENTRY
+FatalAppExit(
+ WORD wAction,
+ LPSTR lpMessageText
+ );
+
+VOID
+APIENTRY
+FatalExit(
+ DWORD dwExitCode
+ );
+
+
+LPSTR
+APIENTRY
+GetCommandLine(
+ VOID
+ );
+
+LPVOID
+APIENTRY
+GetEnvironmentStrings(
+ VOID
+ );
+
+DWORD
+APIENTRY
+GetEnvironmentVariable(
+ LPSTR lpName,
+ LPSTR lpBuffer,
+ DWORD nSize
+ );
+
+BOOL
+APIENTRY
+SetEnvironmentVariable(
+ LPSTR lpName,
+ LPSTR lpValue
+ );
+
+HANDLE
+APIENTRY
+CreateThread(
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ DWORD dwStackSize,
+ LPTHREAD_START_ROUTINE lpStartAddress,
+ LPVOID lpParameter,
+ DWORD dwCreationFlags,
+ LPDWORD lpThreadId
+ );
+
+HANDLE
+APIENTRY
+GetCurrentThread(
+ VOID
+ );
+
+DWORD
+APIENTRY
+GetCurrentThreadId(
+ VOID
+ );
+
+BOOL
+APIENTRY
+SetThreadPriority(
+ HANDLE hThread,
+ int nPriority
+ );
+
+#define THREAD_PRIORITY_LOWEST THREAD_BASE_PRIORITY_MIN
+#define THREAD_PRIORITY_BELOW_NORMAL (THREAD_PRIORITY_LOWEST+1)
+#define THREAD_PRIORITY_NORMAL 0
+#define THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX
+#define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST-1)
+#define THREAD_PRIORITY_ERROR_RETURN (MAXLONG)
+
+int
+APIENTRY
+GetThreadPriority(
+ HANDLE hThread
+ );
+
+VOID
+APIENTRY
+ExitThread(
+ DWORD dwExitCode
+ );
+
+BOOL
+APIENTRY
+TerminateThread(
+ HANDLE hThread,
+ DWORD dwExitCode
+ );
+
+BOOL
+APIENTRY
+GetExitCodeThread(
+ HANDLE hThread,
+ LPDWORD lpExitCode
+ );
+
+DWORD
+APIENTRY
+GetLastError(
+ VOID
+ );
+
+VOID
+APIENTRY
+SetLastError(
+ DWORD dwErrCode
+ );
+
+BOOL
+APIENTRY
+GetOverlappedResult(
+ HANDLE hFile,
+ LPOVERLAPPED lpOverlapped,
+ LPDWORD lpNumberOfBytesTransferred,
+ BOOL bWait
+ );
+
+BOOL
+APIENTRY
+SetErrorMode(
+ BOOL bMode
+ );
+
+//
+// Debug APIs
+//
+#define EXCEPTION_DEBUG_EVENT 1
+#define CREATE_THREAD_DEBUG_EVENT 2
+#define CREATE_PROCESS_DEBUG_EVENT 3
+#define EXIT_THREAD_DEBUG_EVENT 4
+#define EXIT_PROCESS_DEBUG_EVENT 5
+#define LOAD_DLL_DEBUG_EVENT 6
+#define UNLOAD_DLL_DEBUG_EVENT 7
+#define OUTPUT_DEBUG_STRING_EVENT 8
+
+typedef struct _EXCEPTION_DEBUG_INFO {
+ EXCEPTION_RECORD ExceptionRecord;
+ DWORD dwFirstChance;
+} EXCEPTION_DEBUG_INFO, *LPEXCEPTION_DEBUG_INFO;
+
+typedef struct _CREATE_THREAD_DEBUG_INFO {
+ HANDLE hThread;
+ LPTHREAD_START_ROUTINE lpStartAddress;
+} CREATE_THREAD_DEBUG_INFO, *LPCREATE_THREAD_DEBUG_INFO;
+
+typedef struct _CREATE_PROCESS_DEBUG_INFO {
+ HANDLE hFile;
+ HANDLE hProcess;
+ HANDLE hThread;
+ LPVOID lpBaseOfImage;
+ DWORD dwDebugInfoFileOffset;
+ DWORD nDebugInfoSize;
+ LPTHREAD_START_ROUTINE lpStartAddress;
+} CREATE_PROCESS_DEBUG_INFO, *LPCREATE_PROCESS_DEBUG_INFO;
+
+typedef struct _EXIT_THREAD_DEBUG_INFO {
+ DWORD dwExitCode;
+} EXIT_THREAD_DEBUG_INFO, *LPEXIT_THREAD_DEBUG_INFO;
+
+typedef struct _EXIT_PROCESS_DEBUG_INFO {
+ DWORD dwExitCode;
+} EXIT_PROCESS_DEBUG_INFO, *LPEXIT_PROCESS_DEBUG_INFO;
+
+typedef struct _LOAD_DLL_DEBUG_INFO {
+ HANDLE hFile;
+ LPVOID lpBaseOfDll;
+ DWORD dwDebugInfoFileOffset;
+ DWORD nDebugInfoSize;
+} LOAD_DLL_DEBUG_INFO, *LPLOAD_DLL_DEBUG_INFO;
+
+typedef struct _UNLOAD_DLL_DEBUG_INFO {
+ LPVOID lpBaseOfDll;
+} UNLOAD_DLL_DEBUG_INFO, *LPUNLOAD_DLL_DEBUG_INFO;
+
+typedef struct _OUTPUT_DEBUG_STRING_INFO {
+ LPSTR lpDebugStringData;
+ WORD fUnicode;
+ WORD nDebugStringLength;
+} OUTPUT_DEBUG_STRING_INFO, *LPOUTPUT_DEBUG_STRING_INFO;
+
+typedef struct _DEBUG_EVENT {
+ DWORD dwDebugEventCode;
+ DWORD dwProcessId;
+ DWORD dwThreadId;
+ union {
+ EXCEPTION_DEBUG_INFO Exception;
+ CREATE_THREAD_DEBUG_INFO CreateThread;
+ CREATE_PROCESS_DEBUG_INFO CreateProcess;
+ EXIT_THREAD_DEBUG_INFO ExitThread;
+ EXIT_THREAD_DEBUG_INFO ExitProcess;
+ LOAD_DLL_DEBUG_INFO LoadDll;
+ UNLOAD_DLL_DEBUG_INFO UnloadDll;
+ OUTPUT_DEBUG_STRING_INFO OutputDebugString;
+ } u;
+} DEBUG_EVENT;
+typedef DEBUG_EVENT *LPDEBUG_EVENT;
+
+typedef PCONTEXT LPCONTEXT;
+
+BOOL
+APIENTRY
+ReadProcessMemory(
+ HANDLE hProcess,
+ LPVOID lpBaseAddress,
+ LPVOID lpBuffer,
+ DWORD nSize,
+ LPDWORD lpNumberOfBytesRead
+ );
+
+BOOL
+APIENTRY
+WriteProcessMemory(
+ HANDLE hProcess,
+ LPVOID lpBaseAddress,
+ LPVOID lpBuffer,
+ DWORD nSize,
+ LPDWORD lpNumberOfBytesWritten
+ );
+
+BOOL
+APIENTRY
+GetThreadContext(
+ HANDLE hThread,
+ LPCONTEXT lpContext
+ );
+
+BOOL
+APIENTRY
+SetThreadContext(
+ HANDLE hThread,
+ LPCONTEXT lpContext
+ );
+
+DWORD
+APIENTRY
+SuspendThread(
+ HANDLE hThread
+ );
+
+DWORD
+APIENTRY
+ResumeThread(
+ IN HANDLE hThread
+ );
+
+VOID
+APIENTRY
+DebugBreak(
+ VOID
+ );
+
+VOID
+APIENTRY
+OutputDebugString(
+ LPSTR lpOutputString
+ );
+
+BOOL
+APIENTRY
+WaitForDebugEvent(
+ LPDEBUG_EVENT lpDebugEvent
+ );
+
+BOOL
+APIENTRY
+ContinueDebugEvent(
+ DWORD dwProcessId,
+ DWORD dwThreadId,
+ DWORD dwContinueStatus
+ );
+
+VOID
+APIENTRY
+InitializeCriticalSection(
+ LPCRITICAL_SECTION lpCriticalSection
+ );
+
+VOID
+APIENTRY
+EnterCriticalSection(
+ LPCRITICAL_SECTION lpCriticalSection
+ );
+
+VOID
+APIENTRY
+LeaveCriticalSection(
+ LPCRITICAL_SECTION lpCriticalSection
+ );
+
+VOID
+APIENTRY
+DeleteCriticalSection(
+ LPCRITICAL_SECTION lpCriticalSection
+ );
+
+HANDLE
+APIENTRY
+CreateEvent(
+ LPSECURITY_ATTRIBUTES lpEventAttributes,
+ BOOL bManualReset,
+ BOOL bInitialState
+ );
+
+BOOL
+APIENTRY
+SetEvent(
+ HANDLE hEvent
+ );
+
+BOOL
+APIENTRY
+ResetEvent(
+ HANDLE hEvent
+ );
+
+BOOL
+APIENTRY
+PulseEvent(
+ HANDLE hEvent
+ );
+
+HANDLE
+APIENTRY
+CreateSemaphore(
+ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ LONG lInitialCount,
+ LONG lMaximumCount
+ );
+
+BOOL
+APIENTRY
+ReleaseSemaphore(
+ HANDLE hSemaphore,
+ LONG lReleaseCount,
+ LPLONG lpPreviousCount
+ );
+
+HANDLE
+APIENTRY
+CreateMutex(
+ LPSECURITY_ATTRIBUTES lpMutexAttributes,
+ BOOL bInitialOwner
+ );
+
+BOOL
+APIENTRY
+ReleaseMutex(
+ HANDLE hMutex
+ );
+
+DWORD
+APIENTRY
+WaitForSingleObject(
+ HANDLE hHandle,
+ DWORD dwMilliseconds
+ );
+
+DWORD
+APIENTRY
+WaitForMultipleObjects(
+ DWORD nCount,
+ LPHANDLE lpHandles,
+ BOOL bWaitAll,
+ DWORD dwMilliseconds
+ );
+
+VOID
+APIENTRY
+Sleep(
+ DWORD dwMilliseconds
+ );
+
+HANDLE
+APIENTRY
+FindResource(
+ HANDLE hModule,
+ LPSTR lpName,
+ LPSTR lpType
+ );
+
+HANDLE
+APIENTRY
+LoadResource(
+ HANDLE hModule,
+ HANDLE hResInfo
+ );
+
+DWORD
+APIENTRY
+SizeofResource(
+ HANDLE hModule,
+ HANDLE hResInfo
+ );
+
+#ifdef DOSWIN32
+
+BOOL
+APIENTRY
+FreeResource(
+ HANDLE hResData
+ );
+
+LPSTR
+APIENTRY
+LockResource(
+ HANDLE hResData
+ );
+
+#else
+#define FreeResource(hResData) ((hResData), TRUE)
+#define LockResource(hResData) ((LPSTR)hResData)
+#endif
+
+#define UnlockResource(hResData) ((hResData), 0)
+#define MAXINTATOM 0xC000
+
+ATOM
+APIENTRY
+GlobalAddAtom(
+ LPSTR lpString
+ );
+
+ATOM
+APIENTRY
+GlobalFindAtom(
+ LPSTR lpString
+ );
+
+DWORD
+APIENTRY
+GlobalGetAtomName(
+ ATOM nAtom,
+ LPSTR lpBuffer,
+ DWORD nSize
+ );
+
+ATOM
+APIENTRY
+GlobalDeleteAtom(
+ ATOM nAtom
+ );
+
+BOOL
+APIENTRY
+InitAtomTable(
+ DWORD nSize
+ );
+
+ATOM
+APIENTRY
+AddAtom(
+ LPSTR lpString
+ );
+
+ATOM
+APIENTRY
+FindAtom(
+ LPSTR lpString
+ );
+
+ATOM
+APIENTRY
+DeleteAtom(
+ ATOM nAtom
+ );
+
+DWORD
+APIENTRY
+GetAtomName(
+ ATOM nAtom,
+ LPSTR lpBuffer,
+ DWORD nSize
+ );
+
+DWORD
+APIENTRY
+GetProfileInt(
+ LPSTR lpAppName,
+ LPSTR lpKeyName,
+ DWORD nDefault
+ );
+
+DWORD
+APIENTRY
+GetProfileString(
+ LPSTR lpAppName,
+ LPSTR lpKeyName,
+ LPSTR lpDefault,
+ LPSTR lpReturnedString,
+ DWORD nSize
+ );
+
+BOOL
+APIENTRY
+WriteProfileString(
+ LPSTR lpAppName,
+ LPSTR lpKeyName,
+ LPSTR lpString
+ );
+
+DWORD
+APIENTRY
+GetProfileSection(
+ LPSTR lpAppName,
+ LPSTR lpReturnedString,
+ DWORD nSize
+ );
+
+DWORD
+APIENTRY
+WriteProfileSection(
+ LPSTR lpAppName,
+ LPSTR lpString
+ );
+
+DWORD
+APIENTRY
+GetPrivateProfileInt(
+ LPSTR lpAppName,
+ LPSTR lpKeyName,
+ DWORD nDefault,
+ LPSTR lpFileName
+ );
+
+DWORD
+APIENTRY
+GetPrivateProfileString(
+ LPSTR lpAppName,
+ LPSTR lpKeyName,
+ LPSTR lpDefault,
+ LPSTR lpReturnedString,
+ DWORD nSize,
+ LPSTR lpFileName
+ );
+
+BOOL
+APIENTRY
+WritePrivateProfileString(
+ LPSTR lpAppName,
+ LPSTR lpKeyName,
+ LPSTR lpString,
+ LPSTR lpFileName
+ );
+
+DWORD
+APIENTRY
+GetPrivateProfileSection(
+ LPSTR lpAppName,
+ LPSTR lpReturnedString,
+ DWORD nSize,
+ LPSTR lpFileName
+ );
+
+DWORD
+APIENTRY
+WritePrivateProfileSection(
+ LPSTR lpAppName,
+ LPSTR lpString,
+ LPSTR lpFileName
+ );
+
+#define DRIVE_REMOVABLE 2
+#define DRIVE_FIXED 3
+#define DRIVE_REMOTE 4
+#define DRIVE_CDROM 5
+#define DRIVE_RAMDISK 6
+
+DWORD
+APIENTRY
+GetDriveType(
+ LPSTR lpRootPathName
+ );
+
+DWORD
+APIENTRY
+GetSystemDirectory(
+ LPSTR lpBuffer,
+ DWORD nSize
+ );
+
+DWORD
+APIENTRY
+GetTempPath(
+ DWORD nBufferLength,
+ LPSTR lpBuffer
+ );
+
+WORD
+APIENTRY
+GetTempFileName(
+ LPSTR lpPathName,
+ LPSTR lpPrefixString,
+ WORD wUnique,
+ LPSTR lpTempFileName
+ );
+
+DWORD
+APIENTRY
+GetWindowsDirectory(
+ LPSTR lpBuffer,
+ DWORD nSize
+ );
+
+DWORD
+APIENTRY
+SetHandleCount(
+ DWORD dwNumber
+ );
+
+DWORD
+APIENTRY
+GetLogicalDrives(
+ VOID
+ );
+
+BOOL
+APIENTRY
+SetCurrentDirectory(
+ LPSTR lpPathName
+ );
+
+DWORD
+APIENTRY
+GetCurrentDirectory(
+ DWORD nBufferLength,
+ LPSTR lpBuffer
+ );
+
+BOOL
+APIENTRY
+GetDiskFreeSpace(
+ LPSTR lpRootPathName,
+ LPDWORD lpSectorsPerCluster,
+ LPDWORD lpBytesPerSector,
+ LPDWORD lpNumberOfFreeClusters,
+ LPDWORD lpTotalNumberOfClusters
+ );
+
+#define GetFreeSpace(w) (0x100000L)
+
+BOOL
+APIENTRY
+LockFile(
+ HANDLE hFile,
+ DWORD dwFileOffset,
+ DWORD nNumberOfBytesToLock
+ );
+
+BOOL
+APIENTRY
+UnlockFile(
+ HANDLE hFile,
+ DWORD dwFileOffset,
+ DWORD nNumberOfBytesToUnlock
+ );
+
+BOOL
+APIENTRY
+CreateDirectory(
+ LPSTR lpPathName,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes
+ );
+
+BOOL
+APIENTRY
+RemoveDirectory(
+ LPSTR lpPathName
+ );
+
+DWORD
+APIENTRY
+GetFileType(
+ HANDLE hFile
+ );
+
+#define FILE_TYPE_UNKNOWN 0x0000
+#define FILE_TYPE_DISK 0x0001
+#define FILE_TYPE_CHAR 0x0002
+#define FILE_TYPE_PIPE 0x0003
+#define FILE_TYPE_REMOTE 0x8000
+
+DWORD
+APIENTRY
+GetFullPathName(
+ LPSTR lpFileName,
+ DWORD nBufferLength,
+ LPSTR lpBuffer,
+ LPSTR *lpFilePart
+ );
+
+HANDLE
+APIENTRY
+CreateFile(
+ LPSTR lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile
+ );
+
+#define STD_INPUT_HANDLE (DWORD)-10
+#define STD_OUTPUT_HANDLE (DWORD)-11
+#define STD_ERROR_HANDLE (DWORD)-12
+
+HANDLE
+APIENTRY
+GetStdHandle(
+ DWORD nStdHandle
+ );
+
+BOOL
+APIENTRY
+SetStdHandle(
+ DWORD nStdHandle,
+ HANDLE hHandle
+ );
+
+BOOL
+APIENTRY
+WriteFile(
+ HANDLE hFile,
+ LPVOID lpBuffer,
+ DWORD nNumberOfBytesToWrite,
+ LPDWORD lpNumberOfBytesWritten,
+ LPOVERLAPPED lpOverlapped
+ );
+
+BOOL
+APIENTRY
+ReadFile(
+ HANDLE hFile,
+ LPVOID lpBuffer,
+ DWORD nNumberOfBytesToRead,
+ LPDWORD lpNumberOfBytesRead,
+ LPOVERLAPPED lpOverlapped
+ );
+
+BOOL
+APIENTRY
+FlushFileBuffers(
+ HANDLE hFile
+ );
+
+BOOL
+APIENTRY
+SetEndOfFile(
+ HANDLE hFile
+ );
+
+DWORD
+APIENTRY
+SetFilePointer(
+ HANDLE hFile,
+ LONG lDistanceToMove,
+ PLONG lpDistanceToMoveHigh,
+ DWORD dwMoveMethod
+ );
+
+BOOL
+APIENTRY
+SetFileAttributes(
+ LPSTR lpFileName,
+ DWORD dwFileAttributes
+ );
+
+DWORD
+APIENTRY
+GetFileAttributes(
+ LPSTR lpFileName
+ );
+
+BOOL
+APIENTRY
+DeleteFile(
+ LPSTR lpFileName
+ );
+
+HANDLE
+APIENTRY
+FindFirstFile(
+ LPSTR lpFileName,
+ LPWIN32_FIND_DATA lpFindFileData
+ );
+
+BOOL
+APIENTRY
+FindNextFile(
+ HANDLE hFindFile,
+ LPWIN32_FIND_DATA lpFindFileData
+ );
+
+BOOL
+APIENTRY
+FindClose(
+ HANDLE hFindFile
+ );
+
+DWORD
+APIENTRY
+SearchPath(
+ LPSTR lpPath,
+ LPSTR lpFileName,
+ LPSTR lpExtension,
+ DWORD nBufferLength,
+ LPSTR lpBuffer,
+ LPSTR *lpFilePart
+ );
+
+BOOL
+APIENTRY
+CopyFile(
+ LPSTR lpExistingFileName,
+ LPSTR lpNewFileName,
+ BOOL bFailIfExists
+ );
+
+BOOL
+APIENTRY
+MoveFile(
+ LPSTR lpExistingFileName,
+ LPSTR lpNewFileName
+ );
+
+BOOL
+APIENTRY
+GetFileTime(
+ HANDLE hFile,
+ LPFILETIME lpCreationTime,
+ LPFILETIME lpLastAccessTime,
+ LPFILETIME lpLastWriteTime
+ );
+
+BOOL
+APIENTRY
+SetFileTime(
+ HANDLE hFile,
+ LPFILETIME lpCreationTime,
+ LPFILETIME lpLastAccessTime,
+ LPFILETIME lpLastWriteTime
+ );
+
+BOOL
+APIENTRY
+CloseHandle(
+ HANDLE hObject
+ );
+
+BOOL
+APIENTRY
+DuplicateHandle(
+ HANDLE hSourceProcessHandle,
+ HANDLE hSourceHandle,
+ HANDLE hTargetProcessHandle,
+ LPHANDLE lpTargetHandle,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ DWORD dwOptions
+ );
+
+DWORD
+APIENTRY
+LoadModule(
+ LPSTR lpModuleName,
+ LPVOID lpParameterBlock
+ );
+
+DWORD
+APIENTRY
+WinExec(
+ LPSTR lpCmdLine,
+ WORD nCmdShow
+ );
+
+//
+// Commands to pass WinHelp()
+//
+
+#define HELP_CONTEXT 0x0001 /* Display topic in ulTopic */
+#define HELP_QUIT 0x0002 /* Terminate help */
+#define HELP_INDEX 0x0003 /* Display index */
+#define HELP_HELPONHELP 0x0004 /* Display help on using help */
+#define HELP_SETINDEX 0x0005 /* Set the current Index for multi index help */
+#define HELP_KEY 0x0101 /* Display topic for keyword in offabData */
+#define HELP_MULTIKEY 0x0201
+
+BOOL
+APIENTRY
+WinHelp(
+ HANDLE hwndMain,
+ LPSTR lpszHelp,
+ DWORD dwCommand,
+ DWORD dwData
+ );
+
+#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 0xFFFFFFFF // Infinite timeout
+
+//
+// Error Flags
+//
+
+#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_BREAK 0x0010 // Break Detected
+#define CE_CTSTO 0x0020 // CTS Timeout
+#define CE_DSRTO 0x0040 // DSR Timeout
+#define CE_RLSDTO 0x0080 // RLSD Timeout
+#define CE_TXFULL 0x0100 // TX Queue is full
+#define CE_PTO 0x0200 // LPTx Timeout
+#define CE_IOE 0x0400 // LPTx I/O Error
+#define CE_DNS 0x0800 // LPTx Device not selected
+#define CE_OOP 0x1000 // LPTx Out-Of-Paper
+#define CE_MODE 0x8000 // Requested mode unsupported
+
+#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
+
+//
+// Events
+//
+
+#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 // Printer error occured
+
+//
+// Escape Functions
+//
+
+#define SETXOFF 1 // Simulate XOFF received
+#define SETXON 2 // Simulate XON received
+#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
+
+#define LPTx 0x80 // Set if ID is for LPT device
+
+HANDLE
+APIENTRY
+OpenComm(
+ LPSTR lpComName,
+ DWORD dwInQueue,
+ DWORD dwOutQueue
+ );
+
+HANDLE
+APIENTRY
+CloseComm(
+ HANDLE hCid
+ );
+
+DWORD
+APIENTRY
+ReadComm(
+ HANDLE hCid,
+ LPSTR lpBuf,
+ DWORD nSize
+ );
+
+DWORD
+APIENTRY
+WriteComm(
+ HANDLE hCid,
+ LPSTR lpBuf,
+ DWORD nSize
+ );
+
+DWORD
+APIENTRY
+UngetCommChar(
+ HANDLE hCid,
+ CHAR cChar
+ );
+
+DWORD
+APIENTRY
+TransmitCommChar(
+ HANDLE hCid,
+ char cChar
+ );
+
+DWORD
+APIENTRY
+EscapeCommFunction(
+ HANDLE hCid,
+ DWORD nFunc
+ );
+
+DWORD
+APIENTRY
+FlushComm(
+ HANDLE hCid,
+ DWORD nQueue
+ );
+
+DWORD
+APIENTRY
+GetCommError(
+ HANDLE hCid,
+ LPCOMSTAT lpStat
+ );
+
+DWORD
+APIENTRY
+GetCommEventMask(
+ HANDLE hCid,
+ DWORD nEvtMask
+ );
+
+LPDWORD
+APIENTRY
+SetCommEventMask(
+ HANDLE hCid,
+ DWORD nEvtMask
+ );
+
+DWORD
+APIENTRY
+BuildCommDCB(
+ LPSTR lpDef,
+ LPDCB lpDCB
+ );
+
+DWORD
+APIENTRY
+GetCommState(
+ HANDLE hCid,
+ LPDCB lpDCB
+ );
+
+DWORD
+APIENTRY
+SetCommState(
+ LPDCB lpDCB
+ );
+
+DWORD
+APIENTRY
+SetCommBreak(
+ HANDLE hCid
+ );
+
+DWORD
+APIENTRY
+ClearCommBreak(
+ HANDLE hCid
+ );
+
+//
+// WaitSoundState() Constants
+//
+
+#define S_QUEUEEMPTY 0
+#define S_THRESHOLD 1
+#define S_ALLTHRESHOLD 2
+
+//
+// Accent Modes
+//
+
+#define S_NORMAL 0
+#define S_LEGATO 1
+#define S_STACCATO 2
+
+//
+// SetSoundNoise() Sources
+//
+
+#define S_PERIOD512 0 // Freq = N/512 high pitch, less coarse hiss
+#define S_PERIOD1024 1 // Freq = N/1024
+#define S_PERIOD2048 2 // Freq = N/2048 low pitch, more coarse hiss
+#define S_PERIODVOICE 3 // Source is frequency from voice channel (3)
+#define S_WHITE512 4 // Freq = N/512 high pitch, less coarse hiss
+#define S_WHITE1024 5 // Freq = N/1024
+#define S_WHITE2048 6 // Freq = N/2048 low pitch, more coarse hiss
+#define S_WHITEVOICE 7 // Source is frequency from voice channel (3)
+
+#define S_SERDVNA (-1) // Device not available
+#define S_SEROFM (-2) // Out of memory
+#define S_SERMACT (-3) // Music active
+#define S_SERQFUL (-4) // Queue full
+#define S_SERBDNT (-5) // Invalid note
+#define S_SERDLN (-6) // Invalid note length
+#define S_SERDCC (-7) // Invalid note count
+#define S_SERDTP (-8) // Invalid tempo
+#define S_SERDVL (-9) // Invalid volume
+#define S_SERDMD (-10) // Invalid mode
+#define S_SERDSH (-11) // Invalid shape
+#define S_SERDPT (-12) // Invalid pitch
+#define S_SERDFQ (-13) // Invalid frequency
+#define S_SERDDR (-14) // Invalid duration
+#define S_SERDSR (-15) // Invalid source
+#define S_SERDST (-16) // Invalid state
+
+VOID
+APIENTRY
+OpenSound(
+ VOID
+ );
+
+VOID
+APIENTRY
+CloseSound(
+ VOID
+ );
+
+VOID
+APIENTRY
+StartSound(
+ VOID
+ );
+
+VOID
+APIENTRY
+StopSound(
+ VOID
+ );
+
+DWORD
+APIENTRY
+WaitSoundState(
+ DWORD nState
+ );
+
+DWORD
+APIENTRY
+SyncAllVoices(
+ VOID
+ );
+
+DWORD
+APIENTRY
+CountVoiceNotes(
+ DWORD nVoice
+ );
+
+LPDWORD
+APIENTRY
+GetThresholdEvent(
+ VOID
+ );
+
+DWORD
+APIENTRY
+GetThresholdStatus(
+ VOID
+ );
+
+DWORD
+APIENTRY
+SetSoundNoise(
+ DWORD nSource,
+ DWORD nDuration
+ );
+
+DWORD
+APIENTRY
+SetVoiceAccent(
+ DWORD nVoice,
+ DWORD nTempo,
+ DWORD nVolume,
+ DWORD nMode,
+ DWORD nPitch
+ );
+
+DWORD
+APIENTRY
+SetVoiceEnvelope(
+ DWORD nVoice,
+ DWORD nShape,
+ DWORD nRepeat
+ );
+
+DWORD
+APIENTRY
+SetVoiceNote(
+ DWORD nVoice,
+ DWORD nValue,
+ DWORD nLength,
+ DWORD nCdots
+ );
+
+DWORD
+APIENTRY
+SetVoiceQueueSize(
+ DWORD nVoice,
+ DWORD nBytes
+ );
+
+DWORD
+APIENTRY
+SetVoiceSound(
+ DWORD nVoice,
+ LONG lFrequency,
+ DWORD nDuration
+ );
+
+DWORD
+APIENTRY
+SetVoiceThreshold(
+ DWORD nVoice,
+ DWORD nNotes
+ );
+
+int
+APIENTRY
+MulDiv(
+ int nNumber,
+ int nNumerator,
+ int nDenominator
+ );
+
+VOID
+APIENTRY
+GetSystemTime(
+ LPSYSTEMTIME lpSystemTime
+ );
+
+BOOL
+APIENTRY
+SetSystemTime(
+ LPSYSTEMTIME lpSystemTime
+ );
+
+//
+// Routines to convert back and forth between system time and file time
+//
+
+BOOL
+APIENTRY
+SystemTimeToFileTime(
+ LPSYSTEMTIME lpSystemTime,
+ LPFILETIME lpFileTime
+ );
+
+BOOL
+APIENTRY
+FileTimeToSystemTime(
+ LPFILETIME lpFileTime,
+ LPSYSTEMTIME lpSystemTime
+ );
+
+LONG
+APIENTRY
+CompareFileTime(
+ LPFILETIME lpFileTime1,
+ LPFILETIME lpFileTime2
+ );
+
+BOOL
+APIENTRY
+FileTimeToDosDateTime(
+ LPFILETIME lpFileTime,
+ LPWORD lpFatDate,
+ LPWORD lpFatTime
+ );
+
+BOOL
+APIENTRY
+DosDateTimeToFileTime(
+ WORD wFatDate,
+ WORD wFatTime,
+ LPFILETIME lpFileTime
+ );
+
+DWORD
+APIENTRY
+GetTickCount(
+ VOID
+ );
+
+//
+// DOS and OS/2 Compatible Error Code definitions returned by the Win32 Base
+// API functions.
+//
+
+#define NO_ERROR 0
+
+#include "winerror.h"
+
+/* Abnormal termination codes */
+
+#define TC_NORMAL 0
+#define TC_HARDERR 1
+#define TC_GP_TRAP 2
+#define TC_SIGNAL 3
+
+DWORD
+#ifdef DOSWIN32
+/*
+ * This is here to get rid of warnings in the DOS build enviroment. Since
+ * the DOS build uses the PASCAL calling convention as a default, the
+ * compiler complains about this proto type. This will go away when NT and
+ * NTDOS get together on calling conventions (STDCALL). 2/15/91 - Mikehar
+ */
+_cdecl
+#else
+APIENTRY
+#endif
+FormatMessage(
+ HANDLE hModule,
+ DWORD dwMessageId,
+ LPSTR lpBuffer,
+ DWORD nSize,
+ ...
+ );
+
+DWORD
+APIENTRY
+FormatMessageV(
+ HANDLE hModule,
+ DWORD dwMessageId,
+ LPSTR lpBuffer,
+ DWORD nSize,
+ LPVOID lpArguments
+ );
+
+BOOL
+APIENTRY
+CreatePipe(
+ OUT PHANDLE hReadPipe,
+ OUT PHANDLE hWritePipe,
+ IN LPSECURITY_ATTRIBUTES lpPipeAttributes,
+ IN DWORD nSize
+ );
+
+HANDLE
+APIENTRY
+CreateNamedPipe(
+ LPSTR lpName,
+ DWORD dwOpenMode,
+ DWORD dwPipeMode,
+ DWORD nMaxInstances,
+ DWORD nOutBufferSize,
+ DWORD nInBufferSize,
+ DWORD nDefaultTimeOut,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes
+ );
+
+BOOL
+APIENTRY
+ConnectNamedPipe(
+ HANDLE hNamedPipe,
+ LPOVERLAPPED lpOverlapped
+ );
+
+BOOL
+APIENTRY
+DisconnectNamedPipe(
+ HANDLE hNamedPipe
+ );
+
+BOOL
+APIENTRY
+GetNamedPipeHandleState(
+ HANDLE hNamedPipe,
+ LPDWORD lpState,
+ LPDWORD lpCurInstances,
+ LPDWORD lpMaxCollectionCount,
+ LPDWORD lpCollectDataTimeout,
+ LPSTR lpUserName,
+ DWORD nMaxUserNameSize
+ );
+
+BOOL
+APIENTRY
+SetNamedPipeHandleState(
+ HANDLE hNamedPipe,
+ LPDWORD dwMode,
+ LPDWORD lpMaxCollectionCount,
+ LPDWORD lpCollectDataTimeout
+ );
+
+BOOL
+APIENTRY
+GetNamedPipeInfo(
+ HANDLE hNamedPipe,
+ LPDWORD lpFlags,
+ LPDWORD lpOutBufferSize,
+ LPDWORD lpInBufferSize,
+ LPDWORD lpMaxInstances
+ );
+
+BOOL
+APIENTRY
+PeekNamedPipe(
+ HANDLE hNamedPipe,
+ LPVOID lpBuffer,
+ DWORD nBufferSize,
+ LPDWORD lpBytesRead,
+ LPDWORD lpTotalBytesAvail,
+ LPDWORD lpBytesLeftThisMessage
+ );
+
+BOOL
+APIENTRY
+TransactNamedPipe(
+ HANDLE hNamedPipe,
+ LPVOID lpInBuffer,
+ DWORD nInBufferSize,
+ LPVOID lpOutBuffer,
+ DWORD nOutBufferSize,
+ LPDWORD lpBytesRead,
+ LPOVERLAPPED lpOverlapped
+ );
+
+BOOL
+APIENTRY
+CallNamedPipe(
+ LPSTR lpNamedPipeName,
+ LPVOID lpInBuffer,
+ DWORD nInBufferSize,
+ LPVOID lpOutBuffer,
+ DWORD nOutBufferSize,
+ LPDWORD lpBytesRead,
+ DWORD nTimeOut
+ );
+
+BOOL
+APIENTRY
+WaitNamedPipe(
+ LPSTR lpNamedPipeName,
+ DWORD nTimeOut,
+ LPOVERLAPPED lpOverlapped
+ );
+
+#define NMPWAIT_WAIT_FOREVER 0xffffffff
+#define NMPWAIT_NOWAIT 0x00000001
+#define NMPWAIT_USE_DEFAULT_WAIT 0x00000000
+
+#define FS_CASE_IS_PRESERVED FILE_CASE_PRESERVED_NAMES
+#define FS_CASE_SENSITIVE FILE_CASE_SENSITIVE_SEARCH
+#define FS_UNICODE_STORED_ON_DISK FILE_UNICODE_ON_DISK
+
+BOOL
+APIENTRY
+GetVolumeInformation(
+ LPSTR lpRootPathName,
+ LPSTR lpVolumeNameBuffer,
+ DWORD nVolumeNameSize,
+ LPDWORD lpVolumeSerialNumber,
+ LPDWORD lpMaximumComponentLength,
+ LPDWORD lpFileSystemFlags,
+ LPSTR lpFileSystemNameBuffer,
+ DWORD nFileSystemNameSize
+ );
+
+#define FILE_MAP_WRITE SECTION_MAP_WRITE
+#define FILE_MAP_READ SECTION_MAP_READ
+#define FILE_MAP_ALL_ACCESS SECTION_ALL_ACCESS
+
+HANDLE
+APIENTRY
+CreateFileMapping(
+ HANDLE hFile,
+ LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
+ DWORD flProtect,
+ DWORD dwMaximumSizeHigh,
+ DWORD dwMaximumSizeLow
+ );
+
+LPVOID
+APIENTRY
+MapViewOfFile(
+ HANDLE hFileMappingObject,
+ DWORD dwDesiredAccess,
+ DWORD dwFileOffsetHigh,
+ DWORD dwFileOffsetLow,
+ DWORD dwNumberOfBytesToMap
+ );
+
+BOOL
+APIENTRY
+FlushViewOfFile(
+ LPVOID lpBaseAddress,
+ DWORD dwNumberOfBytesToFlush
+ );
+
+BOOL
+APIENTRY
+UnmapViewOfFile(
+ LPVOID lpBaseAddress
+ );
+
+//
+// _l Compat Functions
+//
+
+int
+APIENTRY
+lstrcmp(
+ LPSTR lpString1,
+ LPSTR lpString2
+ );
+
+int
+APIENTRY
+lstrcmpi(
+ LPSTR lpString1,
+ LPSTR lpString2
+ );
+
+LPSTR
+APIENTRY
+lstrcpy(
+ LPSTR lpString1,
+ LPSTR lpString2
+ );
+
+LPSTR
+APIENTRY
+lstrcat(
+ LPSTR lpString1,
+ LPSTR lpString2
+ );
+
+int
+APIENTRY
+lstrlen(
+ LPSTR lpString
+ );
+
+#define OF_READ 0x00000000
+#define OF_WRITE 0x00000001
+#define OF_READWRITE 0x00000002
+#define OF_SHARE_COMPAT 0x00000000
+#define OF_SHARE_EXCLUSIVE 0x00000010
+#define OF_SHARE_DENY_WRITE 0x00000020
+#define OF_SHARE_DENY_READ 0x00000030
+#define OF_SHARE_DENY_NONE 0x00000040
+#define OF_PARSE 0x00000100
+#define OF_DELETE 0x00000200
+#define OF_VERIFY 0x00000400
+#define OF_CANCEL 0x00000800
+#define OF_CREATE 0x00001000
+#define OF_PROMPT 0x00002000
+#define OF_EXIST 0x00004000
+#define OF_REOPEN 0x00008000
+
+typedef struct _OFSTRUCT {
+ BYTE cBytes;
+ BYTE fFixedDisk;
+ WORD nErrCode;
+ WORD Reserved1;
+ WORD Reserved2;
+ BYTE szPathName[120];
+} OFSTRUCT;
+typedef OFSTRUCT *LPOFSTRUCT;
+
+int
+APIENTRY
+OpenFile(
+ LPSTR lpFileName,
+ LPOFSTRUCT lpReOpenBuff,
+ WORD wStyle
+ );
+
+int
+APIENTRY
+_lopen(
+ LPSTR lpPathName,
+ int iReadWrite
+ );
+
+int
+APIENTRY
+_lcreat(
+ LPSTR lpPathName,
+ WORD iAttribute
+ );
+
+int
+APIENTRY
+_lread(
+ int hFile,
+ LPSTR lpBuffer,
+ DWORD dwBytes
+ );
+
+int
+APIENTRY
+_lwrite(
+ int hFile,
+ LPSTR lpBuffer,
+ DWORD dwBytes
+ );
+
+int
+APIENTRY
+_lclose(
+ int hFile
+ );
+
+int
+APIENTRY
+_llseek(
+ int hFile,
+ int lOffset,
+ int iOrigin
+ );
+
+#endif // _WINBASE_
diff --git a/private/os2/client/thunk/include/wincon.h b/private/os2/client/thunk/include/wincon.h
new file mode 100644
index 000000000..cd4123ccf
--- /dev/null
+++ b/private/os2/client/thunk/include/wincon.h
@@ -0,0 +1,458 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ console.h
+
+Abstract:
+
+ This module contains the public data structures, data types,
+ and procedures exported by the NT console subsystem.
+
+Author:
+
+ Therese Stowell (thereses) 26-Oct-1990
+
+Revision History:
+
+--*/
+
+
+typedef struct _COORD {
+ SHORT X;
+ SHORT Y;
+} COORD, *PCOORD;
+
+typedef struct _SMALL_RECT {
+ SHORT Left;
+ SHORT Top;
+ SHORT Right;
+ SHORT Bottom;
+} SMALL_RECT;
+typedef SMALL_RECT *PSMALL_RECT;
+
+typedef struct _KEY_EVENT_RECORD {
+ BOOL bKeyDown;
+ WORD wVirtualKeyCode;
+ WORD wVirtualScanCode;
+ union {
+ WCHAR UnicodeChar;
+ CHAR AsciiChar;
+ } uChar;
+ DWORD dwControlKeyState;
+} KEY_EVENT_RECORD;
+typedef KEY_EVENT_RECORD *PKEY_EVENT_RECORD;
+
+//
+// ControlKeyState flags
+//
+
+#define RIGHT_ALT_PRESSED 0x0001 // the right alt key is pressed.
+#define LEFT_ALT_PRESSED 0x0002 // the left alt key is pressed.
+#define RIGHT_CTRL_PRESSED 0x0004 // the right ctrl key is pressed.
+#define LEFT_CTRL_PRESSED 0x0008 // the left ctrl key is pressed.
+#define SHIFT_PRESSED 0x0010 // the shift key is pressed.
+#define NUMLOCK_ON 0x0020 // the numlock light is on.
+#define SCROLLLOCK_ON 0x0040 // the scrolllock light is on.
+#define CAPSLOCK_ON 0x0080 // the capslock light is on.
+#define ENHANCED_KEY 0x0100 // the key is enhanced.
+
+typedef struct _MOUSE_EVENT_RECORD {
+ COORD dwMousePosition;
+ DWORD dwButtonState;
+ DWORD dwControlKeyState;
+ DWORD dwEventFlags;
+} MOUSE_EVENT_RECORD;
+typedef MOUSE_EVENT_RECORD *PMOUSE_EVENT_RECORD;
+
+//
+// ButtonState flags
+//
+
+#define FROM_LEFT_1ST_BUTTON_PRESSED 0x0001
+#define RIGHTMOST_BUTTON_PRESSED 0x0002
+#define FROM_LEFT_2ND_BUTTON_PRESSED 0x0004
+#define FROM_LEFT_3RD_BUTTON_PRESSED 0x0008
+#define FROM_LEFT_4TH_BUTTON_PRESSED 0x0010
+
+//
+// EventFlags
+//
+
+#define MOUSE_MOVED 0x0001
+#define DOUBLE_CLICK 0x0002
+
+typedef struct _WINDOW_SIZE_RECORD {
+ COORD NewWindowSize;
+} WINDOW_SIZE_RECORD, *PWINDOW_SIZE_RECORD;
+
+typedef struct _INPUT_RECORD {
+ WORD EventType;
+ union {
+ KEY_EVENT_RECORD KeyEvent;
+ MOUSE_EVENT_RECORD MouseEvent;
+ WINDOW_SIZE_RECORD WindowSizeEvent;
+ } Event;
+} INPUT_RECORD;
+typedef INPUT_RECORD *PINPUT_RECORD;
+
+//
+// EventType flags:
+//
+
+#define KEY_EVENT 0x0001 // Event contains key event record
+#define MOUSE_EVENT 0x0002 // Event contains mouse event record
+#define WINDOW_SIZE_EVENT 0x0004 // Event contains window size event record
+
+typedef struct _CHAR_INFO {
+ union {
+ WCHAR UnicodeChar;
+ CHAR AsciiChar;
+ } Char;
+ WORD Attributes;
+} CHAR_INFO;
+typedef CHAR_INFO *PCHAR_INFO;
+
+//
+// Attributes flags:
+//
+
+#define FOREGROUND_BLUE 0x0001 // text color contains blue.
+#define FOREGROUND_GREEN 0x0002 // text color contains green.
+#define FOREGROUND_RED 0x0004 // text color contains red.
+#define FOREGROUND_INTENSITY 0x0008 // text color is intensified.
+#define BACKGROUND_BLUE 0x0010 // background color contains blue.
+#define BACKGROUND_GREEN 0x0020 // background color contains green.
+#define BACKGROUND_RED 0x0040 // background color contains red.
+#define BACKGROUND_INTENSITY 0x0080 // background color is intensified.
+
+
+typedef struct _CONSOLE_SCREEN_BUFFER_INFO {
+ COORD dwSize;
+ COORD dwCursorPosition;
+ COORD dwScrollPosition;
+ WORD wAttributes;
+ COORD dwCurrentWindowSize;
+ COORD dwMaximumWindowSize;
+} CONSOLE_SCREEN_BUFFER_INFO;
+typedef CONSOLE_SCREEN_BUFFER_INFO *PCONSOLE_SCREEN_BUFFER_INFO;
+
+typedef struct _CONSOLE_MOUSE_INFO {
+ DWORD nNumberOfButtons;
+} CONSOLE_MOUSE_INFO;
+typedef CONSOLE_MOUSE_INFO *PCONSOLE_MOUSE_INFO;
+
+typedef struct _CONSOLE_CURSOR_INFO {
+ DWORD dwSize;
+ BOOL bVisible;
+} CONSOLE_CURSOR_INFO;
+typedef CONSOLE_CURSOR_INFO *PCONSOLE_CURSOR_INFO;
+
+typedef struct _CONSOLE_WINDOW_ORIGIN {
+ BOOL bAbsolute;
+ COORD dwWindowOrigin;
+} CONSOLE_WINDOW_ORIGIN;
+typedef CONSOLE_WINDOW_ORIGIN *PCONSOLE_WINDOW_ORIGIN;
+
+typedef struct _CONSOLE_SCROLL_INFO {
+ SMALL_RECT ScrollRectangle;
+ COORD dwDestinationOrigin;
+ CHAR_INFO Fill;
+} CONSOLE_SCROLL_INFO;
+typedef CONSOLE_SCROLL_INFO *PCONSOLE_SCROLL_INFO;
+
+//
+// typedef for ctrl-c handler routines
+//
+
+typedef
+VOID
+(*PHANDLER_ROUTINE)( VOID );
+
+
+//
+// Input Mode flags:
+//
+
+#define ENABLE_LINE_INPUT 0x0001
+#define ENABLE_ECHO_INPUT 0x0002
+#define ENABLE_WINDOW_INPUT 0x0004
+#define ENABLE_MOUSE_INPUT 0x0008
+
+//
+// Output Mode flags:
+//
+
+#define ENABLE_LINE_OUTPUT 0x0001
+#define ENABLE_WRAP_AT_EOL_OUTPUT 0x0002
+
+//
+// direct API definitions.
+//
+
+DWORD
+PeekConsoleInput(
+ HANDLE hConsoleInput,
+ PINPUT_RECORD lpBuffer,
+ DWORD nLength
+ );
+
+DWORD
+UPeekConsoleInput(
+ HANDLE hConsoleInput,
+ PINPUT_RECORD lpBuffer,
+ DWORD nLength
+ );
+
+DWORD
+ReadConsoleInput(
+ HANDLE hConsoleInput,
+ PINPUT_RECORD lpBuffer,
+ DWORD nLength
+ );
+
+DWORD
+UReadConsoleInput(
+ HANDLE hConsoleInput,
+ PINPUT_RECORD lpBuffer,
+ DWORD nLength
+ );
+
+DWORD
+WriteConsoleInput(
+ HANDLE hConsoleInput,
+ PINPUT_RECORD lpBuffer,
+ DWORD nLength
+ );
+
+DWORD
+UWriteConsoleInput(
+ HANDLE hConsoleInput,
+ PINPUT_RECORD lpBuffer,
+ DWORD nLength
+ );
+
+BOOL
+ReadConsoleOutput(
+ HANDLE hConsoleOutput,
+ PCHAR_INFO lpBuffer,
+ COORD dwBufferSize,
+ COORD dwBufferCoord,
+ PSMALL_RECT lpReadRegion
+ );
+
+BOOL
+UReadConsoleOutput(
+ HANDLE hConsoleOutput,
+ PCHAR_INFO lpBuffer,
+ COORD dwBufferSize,
+ COORD dwBufferCoord,
+ PSMALL_RECT lpReadRegion
+ );
+
+BOOL
+WriteConsoleOutput(
+ HANDLE hConsoleOutput,
+ PCHAR_INFO lpBuffer,
+ COORD dwBufferSize,
+ COORD dwBufferCoord,
+ PSMALL_RECT lpWriteRegion
+ );
+
+BOOL
+UWriteConsoleOutput(
+ HANDLE hConsoleOutput,
+ PCHAR_INFO lpBuffer,
+ COORD dwBufferSize,
+ COORD dwBufferCoord,
+ PSMALL_RECT lpWriteRegion
+ );
+
+DWORD
+ReadConsoleOutputCharacter(
+ HANDLE hConsoleOutput,
+ LPSTR lpCharacter,
+ DWORD nLength,
+ COORD dwReadCoord
+ );
+
+DWORD
+UReadConsoleOutputCharacter(
+ HANDLE hConsoleOutput,
+ LPSTR lpCharacter,
+ DWORD nLength,
+ COORD dwReadCoord
+ );
+
+DWORD
+ReadConsoleOutputAttribute(
+ HANDLE hConsoleOutput,
+ LPSTR lpAttribute,
+ DWORD nLength,
+ COORD dwReadCoord
+ );
+
+DWORD
+UReadConsoleOutputAttribute(
+ HANDLE hConsoleOutput,
+ LPSTR lpAttribute,
+ DWORD nLength,
+ COORD dwReadCoord
+ );
+
+DWORD
+WriteConsoleOutputCharacter(
+ HANDLE hConsoleOutput,
+ LPSTR lpCharacter,
+ DWORD nLength,
+ COORD dwWriteCoord
+ );
+
+DWORD
+UWriteConsoleOutputCharacter(
+ HANDLE hConsoleOutput,
+ LPSTR lpCharacter,
+ DWORD nLength,
+ COORD dwWriteCoord
+ );
+
+DWORD
+WriteConsoleOutputAttribute(
+ HANDLE hConsoleOutput,
+ LPSTR lpAttribute,
+ DWORD nLength,
+ COORD dwWriteCoord
+ );
+
+DWORD
+UWriteConsoleOutputAttribute(
+ HANDLE hConsoleOutput,
+ LPSTR lpAttribute,
+ DWORD nLength,
+ COORD dwWriteCoord
+ );
+
+DWORD
+FillConsoleOutputCharacter(
+ HANDLE hConsoleOutput,
+ CHAR cCharacter,
+ DWORD nLength,
+ COORD dwWriteCoord
+ );
+
+DWORD
+UFillConsoleOutputCharacter(
+ HANDLE hConsoleOutput,
+ WCHAR wcCharacter,
+ DWORD nLength,
+ COORD dwWriteCoord
+ );
+
+DWORD
+FillConsoleOutputAttribute(
+ HANDLE hConsoleOutput,
+ WORD wAttribute,
+ DWORD nLength,
+ COORD dwWriteCoord
+ );
+
+BOOL
+GetConsoleMode(
+ HANDLE hConsoleHandle,
+ LPDWORD lpMode
+ );
+
+DWORD
+GetNumberOfConsoleInputEvents(
+ HANDLE hConsoleInput
+ );
+
+BOOL
+GetConsoleScreenBufferInfo(
+ HANDLE hConsoleOutput,
+ PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo
+ );
+
+BOOL
+GetConsoleCursorInfo(
+ HANDLE hConsoleOutput,
+ PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
+ );
+
+BOOL
+GetConsoleMouseInfo(
+ HANDLE hConsoleInput,
+ PCONSOLE_MOUSE_INFO lpConsoleMouseInfo
+ );
+
+BOOL
+SetConsoleMode(
+ HANDLE hConsoleHandle,
+ DWORD dwMode
+ );
+
+BOOL
+SetConsoleActiveScreenBuffer(
+ HANDLE hConsoleOutput
+ );
+
+BOOL
+FlushConsoleInputBuffer(
+ HANDLE hConsoleInput
+ );
+
+BOOL
+SetConsoleScreenBufferSize(
+ HANDLE hConsoleOutput,
+ COORD dwSize
+ );
+
+BOOL
+SetConsoleCursorPosition(
+ HANDLE hConsoleOutput,
+ COORD dwCursorPosition
+ );
+
+BOOL
+SetConsoleCursorInfo(
+ HANDLE hConsoleOutput,
+ PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
+ );
+
+BOOL
+SetConsoleWindowOrigin(
+ HANDLE hConsoleOutput,
+ PCONSOLE_WINDOW_ORIGIN lpConsoleWindowOrigin
+ );
+
+BOOL
+ScrollConsoleScreenBuffer(
+ HANDLE hConsoleOutput,
+ PCONSOLE_SCROLL_INFO lpConsoleScrollInfo
+ );
+
+BOOL
+SetConsoleWindowSize(
+ HANDLE hConsoleOutput,
+ COORD WindowSize
+ );
+
+BOOL
+SetConsoleTextAttribute(
+ HANDLE hConsoleOutput,
+ WORD wAttributes
+ );
+
+BOOL
+SetConsoleCtrlCHandler(
+ IN PHANDLER_ROUTINE HandlerRoutine,
+ IN BOOL Add
+ );
+
+BOOL
+AddAlias(
+ PCHAR Source,
+ PCHAR Target
+ );
diff --git a/private/os2/client/thunk/include/windef.h b/private/os2/client/thunk/include/windef.h
new file mode 100644
index 000000000..675e2c70d
--- /dev/null
+++ b/private/os2/client/thunk/include/windef.h
@@ -0,0 +1,248 @@
+/***************************************************************************\
+* Module Name: windef.h
+*
+* Copyright (c) 1985-91, Microsoft Corporation
+*
+* Type definitions for Windows' basic types.
+*
+\***************************************************************************/
+
+#ifndef _WINDEF_
+#define _WINDEF_
+
+// BASETYPES is defined in ntdef.h if these types are already defined
+
+#ifndef BASETYPES
+#define BASETYPES
+typedef unsigned long ULONG;
+typedef ULONG *PULONG;
+typedef unsigned short USHORT;
+typedef USHORT *PUSHORT;
+typedef unsigned char UCHAR;
+typedef UCHAR *PUCHAR;
+typedef char *PSZ;
+typedef char *PCHAR;
+
+#ifndef THANKS
+#define IN
+#define OUT
+#define OPTIONAL
+#define CRITICAL
+#endif // !THANKS
+
+/*
+ * UNICODE Base types
+ */
+#ifndef WCHAR
+typedef unsigned short WCHAR; // wc, 16-bit UNICODE character
+typedef WCHAR *LPWCH; // pwc
+typedef WCHAR *LPWSTR; // pwsz, 0x0000 terminated UNICODE strings only
+#endif
+
+#endif // !BASETYPES
+
+/*
+ * Portable UNICODE types and macros
+ */
+#ifdef UNICODE
+typedef WCHAR TCHAR;
+// LATER IanJa (when we have compiler support) #define TEXT(a) L#a
+// Use TXTTXTZ for static variable initialization.
+// Use TEXT for automatic variable initialization.
+#define QUOTE(txt) #txt
+#define TXTTXTZ(txt) QUOTE(txt##txt##\0)
+#define TEXT(txt) ToWsz(TXTTXTZ(txt))
+#else // !UNICODE
+typedef char TCHAR;
+#define TEXT(a) #a
+#endif // !UNICODE
+typedef TCHAR *LPTSTR;
+
+#define MAX_PATH 260
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#define far
+#define near
+#define pascal pascal
+#ifdef DOSWIN32
+#define cdecl _cdecl
+#else
+#define cdecl
+#endif
+#define APIENTRY pascal
+
+#define FAR far
+#define NEAR near
+#define PASCAL pascal
+
+typedef unsigned long DWORD;
+typedef int BOOL;
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef float FLOAT;
+typedef BOOL near *PBOOL;
+typedef BOOL far *LPBOOL;
+typedef char near *PSTR;
+typedef char near *NPSTR;
+typedef BOOL near *PBOOL;
+typedef BOOL far *LPBOOL;
+typedef char far *LPSTR;
+typedef BOOL near *PBOOL;
+typedef BOOL far *LPBOOL;
+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;
+
+#ifndef NT_INCLUDED
+#include <winnt.h>
+#endif // NT_INCLUDED
+
+#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 */
+
+#define MAKELONG(a, b) ((LONG)(((WORD)(a)) | ((DWORD)((WORD)(b))) << 16))
+#define LOWORD(l) ((WORD)(l))
+#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
+#define LOBYTE(w) ((BYTE)(w))
+#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))
+
+
+#ifndef WIN_INTERNAL
+typedef HANDLE HWND;
+typedef HANDLE HHOOK;
+#endif
+
+typedef WORD ATOM;
+
+typedef HANDLE *PHANDLE;
+
+typedef HANDLE NEAR *SPHANDLE;
+typedef HANDLE FAR *LPHANDLE;
+typedef HANDLE GLOBALHANDLE;
+typedef HANDLE LOCALHANDLE;
+typedef int (FAR APIENTRY *FARPROC)(); // should be removed some day!!!
+typedef int (NEAR APIENTRY *NEARPROC)();
+typedef int (APIENTRY *PROC)(); // new 32-bit version
+
+typedef HANDLE HSTR;
+typedef HANDLE HICON;
+typedef HANDLE HDC;
+typedef HANDLE HWINSTA;
+typedef HANDLE HDESK;
+typedef HANDLE HMENU;
+typedef HANDLE HPEN;
+typedef HANDLE HFONT;
+typedef HANDLE HBRUSH;
+typedef HANDLE HBITMAP;
+typedef HANDLE HCURSOR;
+typedef HANDLE HRGN;
+typedef HANDLE HPALETTE;
+typedef HANDLE HMODULE;
+typedef HANDLE HMF;
+
+typedef DWORD COLORREF;
+
+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;
+
+typedef struct _POINTL /* ptl */
+{
+ LONG x;
+ LONG y;
+} POINTL;
+
+typedef POINTL *PPOINTL;
+
+typedef struct tagSIZE
+ {
+ LONG cx;
+ LONG cy;
+ } SIZE;
+
+typedef SIZE *PSIZE;
+typedef SIZE SIZEL;
+typedef SIZE *PSIZEL;
+
+typedef struct tagPOINTS
+ {
+ short int x;
+ short int y;
+ } POINTS;
+
+typedef POINTS *PPOINTS;
+typedef POINTS *LPPOINTS;
+
+
+/* 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
+
+
+#endif // _WINDEF_
diff --git a/private/os2/client/thunk/include/windefs.inc b/private/os2/client/thunk/include/windefs.inc
new file mode 100644
index 000000000..1f0a7c26a
--- /dev/null
+++ b/private/os2/client/thunk/include/windefs.inc
@@ -0,0 +1,122 @@
+;***************************************************************************
+; *
+; 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.
+
+
+EnterCrit MACRO
+ pushf
+ cli
+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
+ sti
+@@:
+else
+ push bp
+ mov bp, sp
+ test byte ptr [bp+3], 2
+ jz @f
+ sti
+@@:
+ 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/os2/client/thunk/include/windows.h b/private/os2/client/thunk/include/windows.h
new file mode 100644
index 000000000..565f70476
--- /dev/null
+++ b/private/os2/client/thunk/include/windows.h
@@ -0,0 +1,3479 @@
+/****************************************************************************/
+/* */
+/* WINDOWS.H - */
+/* */
+/* Include file for Windows 3.0 applications */
+/* */
+/****************************************************************************/
+
+/* If defined, the following flags inhibit definition
+ * of the indicated items.
+ *
+ * NOGDICAPMASKS - CC_*, LC_*, PC_*, CP_*, TC_*, RC_
+ * NOVIRTUALKEYCODES - VK_*
+ * NOWINMESSAGES - WM_*, EM_*, LB_*, CB_*
+ * NOWINSTYLES - WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
+ * NOSYSMETRICS - SM_*
+ * NOMENUS - MF_*
+ * NOICONS - IDI_*
+ * NOKEYSTATES - MK_*
+ * NOSYSCOMMANDS - SC_*
+ * NORASTEROPS - Binary and Tertiary raster ops
+ * NOSHOWWINDOW - SW_*
+ * OEMRESOURCE - OEM Resource values
+ * NOATOM - Atom Manager routines
+ * NOCLIPBOARD - Clipboard routines
+ * NOCOLOR - Screen colors
+ * NOCTLMGR - Control and Dialog routines
+ * NODRAWTEXT - DrawText() and DT_*
+ * NOGDI - All GDI defines and routines
+ * NOKERNEL - All KERNEL defines and routines
+ * NOUSER - All USER defines and routines
+ * NOMB - MB_* and MessageBox()
+ * NOMEMMGR - GMEM_*, LMEM_*, GHND, LHND, associated routines
+ * NOMETAFILE - typedef METAFILEPICT
+ * NOMINMAX - Macros min(a,b) and max(a,b)
+ * NOMSG - typedef MSG and associated routines
+ * NOOPENFILE - OpenFile(), OemToAnsi, AnsiToOem, and OF_*
+ * NOSCROLL - SB_* and scrolling routines
+ * NOSOUND - Sound driver routines
+ * NOTEXTMETRIC - typedef TEXTMETRIC and associated routines
+ * NOWH - SetWindowsHook and WH_*
+ * NOWINOFFSETS - GWL_*, GCL_*, associated routines
+ * NOCOMM - COMM driver routines
+ * NOHELP - Help engine interface.
+ * NOPROFILER - Profiler interface.
+ * NODEFERWINDOWPOS - DeferWindowPos routines
+ * NODRIVERS - Installable driver defines
+ * NODBCS - DBCS support stuff.
+ */
+
+#ifdef RC_INVOKED
+
+/* Turn off a bunch of stuff to ensure that RC files compile OK. */
+#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 NOCOMM
+#define NODBCS
+
+#endif /* RC_INVOKED */
+
+
+/*--------------------------------------------------------------------------*/
+/* General Purpose Defines */
+/*--------------------------------------------------------------------------*/
+
+#define NULL 0
+#define FALSE 0
+#define TRUE 1
+
+#define FAR far
+#define NEAR near
+#define LONG long
+#define VOID void
+#define PASCAL pascal
+
+#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 */
+
+#define MAKELONG(a, b) ((LONG)(((WORD)(a)) | ((DWORD)((WORD)(b))) << 16))
+#define LOWORD(l) ((WORD)(l))
+#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
+#define LOBYTE(w) ((BYTE)(w))
+#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))
+
+typedef int BOOL;
+typedef unsigned char BYTE;
+typedef unsigned int WORD;
+typedef unsigned long DWORD;
+typedef char near *PSTR;
+typedef char near *NPSTR;
+typedef char far *LPSTR;
+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;
+
+#ifndef WIN_INTERNAL
+typedef WORD HANDLE;
+typedef HANDLE HWND;
+#endif
+
+typedef HANDLE *PHANDLE;
+typedef HANDLE NEAR *SPHANDLE;
+typedef HANDLE FAR *LPHANDLE;
+typedef HANDLE GLOBALHANDLE;
+typedef HANDLE LOCALHANDLE;
+typedef int (FAR PASCAL *FARPROC)();
+typedef int (NEAR PASCAL *NEARPROC)();
+
+typedef HANDLE HSTR;
+typedef HANDLE HICON;
+typedef HANDLE HDC;
+typedef HANDLE HMENU;
+typedef HANDLE HPEN;
+typedef HANDLE HFONT;
+typedef HANDLE HBRUSH;
+typedef HANDLE HBITMAP;
+typedef HANDLE HCURSOR;
+typedef HANDLE HRGN;
+typedef HANDLE HPALETTE;
+
+typedef DWORD COLORREF;
+
+#ifndef WIN_INTERNAL
+typedef struct tagRECT
+ {
+ int left;
+ int top;
+ int right;
+ int bottom;
+ } RECT;
+#endif
+
+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;
+
+
+/*--------------------------------------------------------------------------*/
+/* KERNEL Section */
+/*--------------------------------------------------------------------------*/
+
+#ifndef NOKERNEL
+
+/* Loader Routines */
+WORD FAR PASCAL GetVersion(void);
+WORD FAR PASCAL GetNumTasks(void);
+HANDLE FAR PASCAL GetCodeHandle(FARPROC);
+void FAR PASCAL GetCodeInfo(FARPROC lpProc, LPVOID lpSegInfo);
+HANDLE FAR PASCAL GetModuleHandle(LPSTR);
+int FAR PASCAL GetModuleUsage(HANDLE);
+int FAR PASCAL GetModuleFileName(HANDLE, LPSTR, int);
+int FAR PASCAL GetInstanceData(HANDLE, NPSTR, int);
+FARPROC FAR PASCAL GetProcAddress(HANDLE, LPSTR);
+FARPROC FAR PASCAL MakeProcInstance(FARPROC, HANDLE);
+void FAR PASCAL FreeProcInstance(FARPROC);
+HANDLE FAR PASCAL LoadLibrary(LPSTR);
+HANDLE FAR PASCAL LoadModule(LPSTR, LPVOID);
+BOOL FAR PASCAL FreeModule(HANDLE);
+void FAR PASCAL FreeLibrary(HANDLE);
+DWORD FAR PASCAL GetFreeSpace(WORD);
+WORD FAR PASCAL WinExec(LPSTR, WORD);
+void FAR PASCAL DebugBreak(void);
+void FAR PASCAL OutputDebugString(LPSTR);
+void FAR PASCAL SwitchStackBack(void);
+void FAR PASCAL SwitchStackTo(WORD, WORD, WORD);
+WORD FAR PASCAL GetCurrentPDB(void);
+
+#ifndef NOOPENFILE
+
+/* OpenFile() Structure */
+typedef struct tagOFSTRUCT
+ {
+ BYTE cBytes;
+ BYTE fFixedDisk;
+ WORD nErrCode;
+ BYTE reserved[4];
+ BYTE 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
+#define OF_CANCEL 0x0800
+#define OF_CREATE 0x1000
+#define OF_PROMPT 0x2000
+#define OF_EXIST 0x4000
+#define OF_REOPEN 0x8000
+
+int FAR PASCAL OpenFile(LPSTR, LPOFSTRUCT, WORD);
+
+/* GetTempFileName() Flags */
+#define TF_FORCEDRIVE (BYTE)0x80
+
+BYTE FAR PASCAL GetTempDrive(BYTE);
+int FAR PASCAL GetTempFileName(BYTE, LPSTR, WORD, LPSTR);
+WORD FAR PASCAL SetHandleCount(WORD);
+
+WORD FAR PASCAL GetDriveType(int);
+/* GetDriveType return values */
+#define DRIVE_REMOVABLE 2
+#define DRIVE_FIXED 3
+#define DRIVE_REMOTE 4
+
+#endif /* NOOPENFILE */
+
+#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)
+
+HANDLE FAR PASCAL GlobalAlloc(WORD, DWORD);
+DWORD FAR PASCAL GlobalCompact(DWORD);
+HANDLE FAR PASCAL GlobalFree(HANDLE);
+DWORD FAR PASCAL GlobalHandle(WORD);
+LPSTR FAR PASCAL GlobalLock(HANDLE);
+HANDLE FAR PASCAL GlobalReAlloc(HANDLE, DWORD, WORD);
+DWORD FAR PASCAL GlobalSize(HANDLE);
+BOOL FAR PASCAL GlobalUnlock(HANDLE);
+WORD FAR PASCAL GlobalFlags(HANDLE);
+LPSTR FAR PASCAL GlobalWire(HANDLE);
+BOOL FAR PASCAL GlobalUnWire(HANDLE);
+BOOL FAR PASCAL GlobalUnlock(HANDLE);
+HANDLE FAR PASCAL GlobalLRUNewest(HANDLE);
+HANDLE FAR PASCAL GlobalLRUOldest(HANDLE);
+VOID FAR PASCAL GlobalNotify(FARPROC);
+WORD FAR PASCAL GlobalPageLock(HANDLE);
+WORD FAR PASCAL GlobalPageUnlock(HANDLE);
+VOID FAR PASCAL GlobalFix(HANDLE);
+BOOL FAR PASCAL GlobalUnfix(HANDLE);
+
+/* Flags returned by GlobalFlags (in addition to GMEM_DISCARDABLE) */
+#define GMEM_DISCARDED 0x4000
+#define GMEM_LOCKCOUNT 0x00FF
+
+#define LockData(dummy) LockSegment(0xFFFF)
+#define UnlockData(dummy) UnlockSegment(0xFFFF)
+
+HANDLE FAR PASCAL LockSegment(WORD);
+HANDLE FAR PASCAL UnlockSegment(WORD);
+
+/* 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)
+
+#define LNOTIFY_OUTOFMEM 0
+#define LNOTIFY_MOVE 1
+#define LNOTIFY_DISCARD 2
+
+WORD NEAR * PASCAL pLocalHeap;
+
+#define LocalDiscard(h) LocalReAlloc(h, 0, LMEM_MOVEABLE)
+#define LocalFreeze(dummy) (*(pLocalHeap+1) += 1) /* ;Internal */
+#define LocalHandleDelta(d) ((d) ? (*(pLocalHeap+9) = (d)) : *(pLocalHeap+9)) /* ;Internal */
+#define LocalMelt(dummy) (*(pLocalHeap+1) -= 1) /* ;Internal */
+
+HANDLE FAR PASCAL LocalAlloc(WORD, WORD);
+WORD FAR PASCAL LocalCompact(WORD);
+HANDLE FAR PASCAL LocalFree(HANDLE);
+HANDLE FAR PASCAL LocalHandle(WORD);
+BOOL FAR PASCAL LocalInit( WORD, WORD, WORD);
+char NEAR * FAR PASCAL LocalLock(HANDLE);
+FARPROC FAR PASCAL LocalNotify(FARPROC);
+HANDLE FAR PASCAL LocalReAlloc(HANDLE, WORD, WORD);
+WORD FAR PASCAL LocalSize(HANDLE);
+BOOL FAR PASCAL LocalUnlock(HANDLE);
+WORD FAR PASCAL LocalFlags(HANDLE);
+WORD FAR PASCAL LocalShrink(HANDLE, WORD);
+
+/* Flags returned by LocalFlags (in addition to LMEM_DISCARDABLE) */
+#define LMEM_DISCARDED 0x4000
+#define LMEM_LOCKCOUNT 0x00FF
+
+#endif /* NOMEMMGR */
+
+LONG FAR PASCAL SetSwapAreaSize(WORD);
+LPSTR FAR PASCAL ValidateFreeSpaces(void);
+VOID FAR PASCAL LimitEmsPages(DWORD);
+BOOL FAR PASCAL SetErrorMode(WORD);
+VOID FAR PASCAL ValidateCodeSegments(void);
+
+#define UnlockResource(h) GlobalUnlock(h)
+
+HANDLE FAR PASCAL FindResource(HANDLE, LPSTR, LPSTR);
+HANDLE FAR PASCAL LoadResource(HANDLE, HANDLE);
+BOOL FAR PASCAL FreeResource(HANDLE);
+LPSTR 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)((DWORD)((WORD)(i)))
+
+#ifndef NORESOURCE
+
+#define DIFFERENCE 11
+
+/* 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)
+/* 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
+*/
+#define RT_GROUP_CURSOR (RT_CURSOR + DIFFERENCE)
+/* The value 13 is intentionally unused */
+#define RT_GROUP_ICON (RT_ICON + DIFFERENCE)
+
+
+#endif /* NORESOURCE */
+
+void FAR PASCAL Yield(void);
+HANDLE FAR PASCAL GetCurrentTask(void);
+int FAR PASCAL SetPriority(HANDLE, int); /* ;Internal */
+
+#ifndef NOATOM
+typedef WORD ATOM;
+
+#define MAKEINTATOM(i) (LPSTR)((DWORD)((WORD)(i)))
+
+BOOL FAR PASCAL InitAtomTable(int);
+ATOM FAR PASCAL AddAtom(LPSTR);
+ATOM FAR PASCAL DeleteAtom(ATOM);
+ATOM FAR PASCAL FindAtom(LPSTR);
+WORD FAR PASCAL GetAtomName(ATOM, LPSTR, int);
+ATOM FAR PASCAL GlobalAddAtom(LPSTR);
+ATOM FAR PASCAL GlobalDeleteAtom(ATOM);
+ATOM FAR PASCAL GlobalFindAtom(LPSTR);
+WORD FAR PASCAL GlobalGetAtomName(ATOM, LPSTR, int);
+HANDLE FAR PASCAL GetAtomHandle(ATOM);
+
+#endif /* NOATOM */
+
+/* User Profile Routines */
+WORD FAR PASCAL GetProfileInt(LPSTR, LPSTR, int);
+int FAR PASCAL GetProfileString(LPSTR, LPSTR, LPSTR, LPSTR, int);
+BOOL FAR PASCAL WriteProfileString(LPSTR, LPSTR, LPSTR);
+WORD FAR PASCAL GetPrivateProfileInt(LPSTR, LPSTR, int, LPSTR);
+int FAR PASCAL GetPrivateProfileString(LPSTR, LPSTR, LPSTR, LPSTR, int, LPSTR);
+BOOL FAR PASCAL WritePrivateProfileString(LPSTR, LPSTR, LPSTR, LPSTR);
+
+WORD FAR PASCAL GetWindowsDirectory(LPSTR,WORD);
+WORD FAR PASCAL GetSystemDirectory(LPSTR,WORD);
+
+/* Catch() and Throw() */
+typedef int CATCHBUF[9];
+typedef int FAR *LPCATCHBUF;
+
+int FAR PASCAL Catch(LPCATCHBUF);
+void FAR PASCAL Throw(LPCATCHBUF, int);
+
+void FAR PASCAL FatalExit(int);
+void FAR PASCAL FatalAppExit(WORD, LPSTR);
+
+void FAR PASCAL SwapRecording(WORD);
+
+/* Character Translation Routines */
+int FAR PASCAL AnsiToOem(LPSTR, LPSTR);
+BOOL FAR PASCAL OemToAnsi(LPSTR, LPSTR);
+void FAR PASCAL AnsiToOemBuff(LPSTR, LPSTR, int);
+void FAR PASCAL OemToAnsiBuff(LPSTR, LPSTR, int);
+LPSTR FAR PASCAL AnsiUpper(LPSTR);
+WORD FAR PASCAL AnsiUpperBuff(LPSTR, WORD);
+LPSTR FAR PASCAL AnsiLower(LPSTR);
+WORD FAR PASCAL AnsiLowerBuff(LPSTR, WORD);
+LPSTR FAR PASCAL AnsiNext(LPSTR);
+LPSTR FAR PASCAL AnsiPrev(LPSTR, LPSTR);
+
+/* Keyboard Information Routines */
+#ifndef NOKEYBOARDINFO
+DWORD FAR PASCAL OemKeyScan(WORD);
+WORD FAR PASCAL VkKeyScan(WORD);
+int FAR PASCAL GetKeyboardType(int);
+WORD FAR PASCAL MapVirtualKey(WORD, WORD); /* ;Internal */
+int FAR PASCAL GetKBCodePage(void);
+int FAR PASCAL GetKeyNameText(LONG, LPSTR, int);
+int FAR PASCAL ToAscii(WORD wVirtKey, WORD wScanCode, LPSTR lpKeyState, LPVOID lpChar, WORD wFlags);
+#endif
+
+#ifndef NOLANGUAGE
+/* Language dependent Routines */
+BOOL FAR PASCAL IsCharAlpha(char);
+BOOL FAR PASCAL IsCharAlphaNumeric(char);
+BOOL FAR PASCAL IsCharUpper(char);
+BOOL FAR PASCAL IsCharLower(char);
+#endif
+
+LONG FAR PASCAL 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_SMALLFRAME 0x0200
+#define WF_80x87 0x0400
+
+/* WEP fSystemExit flag values */
+#define WEP_SYSTEM_EXIT 1
+#define WEP_FREE_DLL 0
+
+
+#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
+
+#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 */
+
+#endif /* NOKERNEL */
+
+
+/*--------------------------------------------------------------------------*/
+/* GDI Section */
+/*--------------------------------------------------------------------------*/
+
+#ifndef NOGDI
+
+#ifndef NORASTEROPS
+
+/* Binary raster ops */
+#define R2_BLACK 1 /* 0 */
+#define R2_NOTMERGEPEN 2 /* DPon */
+#define R2_MASKNOTPEN 3 /* DPna */
+#define R2_NOTCOPYPEN 4 /* PN */
+#define R2_MASKPENNOT 5 /* PDna */
+#define R2_NOT 6 /* Dn */
+#define R2_XORPEN 7 /* DPx */
+#define R2_NOTMASKPEN 8 /* DPan */
+#define R2_MASKPEN 9 /* DPa */
+#define R2_NOTXORPEN 10 /* DPxn */
+#define R2_NOP 11 /* D */
+#define R2_MERGENOTPEN 12 /* DPno */
+#define R2_COPYPEN 13 /* P */
+#define R2_MERGEPENNOT 14 /* PDno */
+#define R2_MERGEPEN 15 /* DPo */
+#define R2_WHITE 16 /* 1 */
+
+/* Ternary raster operations */
+#define SRCCOPY (DWORD)0x00CC0020 /* dest = source */
+#define SRCPAINT (DWORD)0x00EE0086 /* dest = source OR dest */
+#define SRCAND (DWORD)0x008800C6 /* dest = source AND dest */
+#define SRCINVERT (DWORD)0x00660046 /* dest = source XOR dest */
+#define SRCERASE (DWORD)0x00440328 /* dest = source AND (NOT dest ) */
+#define NOTSRCCOPY (DWORD)0x00330008 /* dest = (NOT source) */
+#define NOTSRCERASE (DWORD)0x001100A6 /* dest = (NOT src) AND (NOT dest) */
+#define MERGECOPY (DWORD)0x00C000CA /* dest = (source AND pattern) */
+#define MERGEPAINT (DWORD)0x00BB0226 /* dest = (NOT source) OR dest */
+#define PATCOPY (DWORD)0x00F00021 /* dest = pattern */
+#define PATPAINT (DWORD)0x00FB0A09 /* dest = DPSnoo */
+#define PATINVERT (DWORD)0x005A0049 /* dest = pattern XOR dest */
+#define DSTINVERT (DWORD)0x00550009 /* dest = (NOT dest) */
+#define BLACKNESS (DWORD)0x00000042 /* dest = BLACK */
+#define WHITENESS (DWORD)0x00FF0062 /* dest = WHITE */
+
+#endif /* NORASTEROPS */
+
+/* StretchBlt() Modes */
+#define BLACKONWHITE 1
+#define WHITEONBLACK 2
+#define COLORONCOLOR 3
+
+/* PolyFill() Modes */
+#define ALTERNATE 1
+#define WINDING 2
+
+/* Text Alignment Options */
+#define TA_NOUPDATECP 0
+#define TA_UPDATECP 1
+
+#define TA_LEFT 0
+#define TA_RIGHT 2
+#define TA_CENTER 6
+
+#define TA_TOP 0
+#define TA_BOTTOM 8
+#define TA_BASELINE 24
+
+#define ETO_GRAYED 1
+#define ETO_OPAQUE 2
+#define ETO_CLIPPED 4
+
+#define ASPECT_FILTERING 0x0001
+
+#ifndef NOMETAFILE
+
+/* 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 0x0400
+#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_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
+
+#endif /* NOMETAFILE */
+
+/* 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 SETENDCAP 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 GETEXTENDEDTEXTMETRICS 256
+#define GETEXTENTTABLE 257
+#define GETPAIRKERNTABLE 258
+#define GETTRACKKERNTABLE 259
+#define EXTTEXTOUT 512
+#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
+
+/* 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
+
+/* Object Definitions for EnumObjects() */
+#define OBJ_PEN 1
+#define OBJ_BRUSH 2
+
+/* Bitmap Header Definition */
+typedef struct tagBITMAP
+ {
+ int bmType;
+ int bmWidth;
+ int bmHeight;
+ int bmWidthBytes;
+ BYTE bmPlanes;
+ BYTE bmBitsPixel;
+ LPSTR bmBits;
+ } BITMAP;
+typedef BITMAP *PBITMAP;
+typedef BITMAP NEAR *NPBITMAP;
+typedef BITMAP FAR *LPBITMAP;
+
+typedef struct tagRGBTRIPLE {
+ BYTE rgbtBlue;
+ BYTE rgbtGreen;
+ BYTE rgbtRed;
+} RGBTRIPLE;
+
+typedef struct tagRGBQUAD {
+ BYTE rgbBlue;
+ BYTE rgbGreen;
+ BYTE rgbRed;
+ BYTE rgbReserved;
+} RGBQUAD;
+
+/* structures for defining DIBs */
+typedef struct tagBITMAPCOREHEADER {
+ DWORD bcSize; /* used to get to color table */
+ WORD bcWidth;
+ WORD bcHeight;
+ WORD bcPlanes;
+ WORD bcBitCount;
+} BITMAPCOREHEADER;
+typedef BITMAPCOREHEADER FAR *LPBITMAPCOREHEADER;
+typedef BITMAPCOREHEADER *PBITMAPCOREHEADER;
+
+
+typedef struct tagBITMAPINFOHEADER{
+ 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;
+
+/* 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 FAR *LPBITMAPINFO;
+typedef BITMAPINFO *PBITMAPINFO;
+
+typedef struct tagBITMAPCOREINFO {
+ BITMAPCOREHEADER bmciHeader;
+ RGBTRIPLE bmciColors[1];
+} BITMAPCOREINFO;
+typedef BITMAPCOREINFO FAR *LPBITMAPCOREINFO;
+typedef BITMAPCOREINFO *PBITMAPCOREINFO;
+
+typedef struct tagBITMAPFILEHEADER {
+ WORD bfType;
+ DWORD bfSize;
+ WORD bfReserved1;
+ WORD bfReserved2;
+ DWORD bfOffBits;
+} BITMAPFILEHEADER;
+typedef BITMAPFILEHEADER FAR *LPBITMAPFILEHEADER;
+typedef BITMAPFILEHEADER *PBITMAPFILEHEADER;
+
+
+#define MAKEPOINT(l) (*((POINT FAR *)&(l)))
+
+#ifndef NOMETAFILE
+
+/* Clipboard Metafile Picture Structure */
+typedef struct tagHANDLETABLE
+ {
+ HANDLE objectHandle[1];
+ } HANDLETABLE;
+typedef HANDLETABLE *PHANDLETABLE;
+typedef HANDLETABLE FAR *LPHANDLETABLE;
+
+typedef struct tagMETARECORD
+ {
+ DWORD rdSize;
+ WORD rdFunction;
+ WORD rdParm[1];
+ } METARECORD;
+typedef METARECORD *PMETARECORD;
+typedef METARECORD FAR *LPMETARECORD;
+
+typedef struct tagMETAFILEPICT
+ {
+ int mm;
+ int xExt;
+ int yExt;
+ HANDLE hMF;
+ } METAFILEPICT;
+typedef METAFILEPICT FAR *LPMETAFILEPICT;
+
+typedef struct tagMETAHEADER
+{
+ WORD mtType;
+ WORD mtHeaderSize;
+ WORD mtVersion;
+ DWORD mtSize;
+ WORD mtNoObjects;
+ DWORD mtMaxRecord;
+ WORD mtNoParameters;
+} METAHEADER;
+
+#endif /* NOMETAFILE */
+
+#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;
+
+#endif /* NOTEXTMETRIC */
+
+/* GDI Logical Objects: */
+
+/* Pel Array */
+typedef struct tagPELARRAY
+ {
+ int paXCount;
+ int paYCount;
+ int paXExt;
+ int paYExt;
+ BYTE paRGBs;
+ } PELARRAY;
+typedef PELARRAY *PPELARRAY;
+typedef PELARRAY NEAR *NPPELARRAY;
+typedef PELARRAY FAR *LPPELARRAY;
+
+/* Logical Brush (or Pattern) */
+typedef struct tagLOGBRUSH
+ {
+ WORD lbStyle;
+ DWORD 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;
+
+/* Logical Pen */
+typedef struct tagLOGPEN
+ {
+ WORD lopnStyle;
+ POINT lopnWidth;
+ DWORD lopnColor;
+ } LOGPEN;
+typedef LOGPEN *PLOGPEN;
+typedef LOGPEN NEAR *NPLOGPEN;
+typedef LOGPEN FAR *LPLOGPEN;
+
+
+
+typedef struct tagPALETTEENTRY {
+ BYTE peRed;
+ BYTE peGreen;
+ BYTE peBlue;
+ BYTE peFlags;
+} PALETTEENTRY;
+typedef PALETTEENTRY FAR *LPPALETTEENTRY;
+
+/* Logical Palette */
+typedef struct tagLOGPALETTE {
+ WORD palVersion;
+ WORD palNumEntries;
+ PALETTEENTRY palPalEntry[1];
+} LOGPALETTE;
+typedef LOGPALETTE *PLOGPALETTE;
+typedef LOGPALETTE NEAR *NPLOGPALETTE;
+typedef LOGPALETTE FAR *LPLOGPALETTE;
+
+
+/* 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;
+ BYTE lfFaceName[LF_FACESIZE];
+ } LOGFONT;
+typedef LOGFONT *PLOGFONT;
+typedef LOGFONT NEAR *NPLOGFONT;
+typedef LOGFONT FAR *LPLOGFONT;
+
+#define OUT_DEFAULT_PRECIS 0
+#define OUT_STRING_PRECIS 1
+#define OUT_CHARACTER_PRECIS 2
+#define OUT_STROKE_PRECIS 3
+
+#define CLIP_DEFAULT_PRECIS 0
+#define CLIP_CHARACTER_PRECIS 1
+#define CLIP_STROKE_PRECIS 2
+
+#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 SYMBOL_CHARSET 2
+#define SHIFTJIS_CHARSET 128
+#define OEM_CHARSET 255
+
+/* 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 */
+#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
+
+/* EnumFonts Masks */
+#define RASTER_FONTTYPE 0x0001
+#define DEVICE_FONTTYPE 0X0002
+
+#define RGB(r,g,b) ((DWORD)(((BYTE)(r)|((WORD)(g)<<8))|(((DWORD)(BYTE)(b))<<16)))
+#define PALETTERGB(r,g,b) (0x02000000 | RGB(r,g,b))
+#define PALETTEINDEX(i) ((DWORD)(0x01000000 | (WORD)(i)))
+
+#define GetRValue(rgb) ((BYTE)(rgb))
+#define GetGValue(rgb) ((BYTE)(((WORD)(rgb)) >> 8))
+#define GetBValue(rgb) ((BYTE)((rgb)>>16))
+
+/* Background Modes */
+#define TRANSPARENT 1
+#define OPAQUE 2
+
+/* Mapping 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
+
+/* Coordinate Modes */
+#define ABSOLUTE 1
+#define RELATIVE 2
+
+/* Stock Logical Objects */
+#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
+#define WHITE_PEN 6
+#define BLACK_PEN 7
+#define NULL_PEN 8
+#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
+
+/* 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 /* xxxxx */
+
+/* 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
+
+/* Device Parameters for GetDeviceCaps() */
+#define DRIVERVERSION 0 /* Device driver version */
+#define TECHNOLOGY 2 /* Device classification */
+#define HORZSIZE 4 /* Horizontal size in millimeters */
+#define VERTSIZE 6 /* Vertical size in millimeters */
+#define HORZRES 8 /* Horizontal width in pixels */
+#define VERTRES 10 /* Vertical width in pixels */
+#define BITSPIXEL 12 /* Number of bits per pixel */
+#define PLANES 14 /* Number of planes */
+#define NUMBRUSHES 16 /* Number of brushes the device has */
+#define NUMPENS 18 /* Number of pens the device has */
+#define NUMMARKERS 20 /* Number of markers the device has */
+#define NUMFONTS 22 /* Number of fonts the device has */
+#define NUMCOLORS 24 /* Number of colors the device supports */
+#define PDEVICESIZE 26 /* Size required for device descriptor */
+#define CURVECAPS 28 /* Curve capabilities */
+#define LINECAPS 30 /* Line capabilities */
+#define POLYGONALCAPS 32 /* Polygonal capabilities */
+#define TEXTCAPS 34 /* Text capabilities */
+#define CLIPCAPS 36 /* Clipping capabilities */
+#define RASTERCAPS 38 /* Bitblt capabilities */
+#define ASPECTX 40 /* Length of the X leg */
+#define ASPECTY 42 /* Length of the Y leg */
+#define ASPECTXY 44 /* Length of the hypotenuse */
+
+#define LOGPIXELSX 88 /* Logical pixels/inch in X */
+#define LOGPIXELSY 90 /* Logical pixels/inch in Y */
+
+#define SIZEPALETTE 104 /* Number of entries in physical palette */
+#define NUMRESERVED 106 /* Number of reserved entries in palette */
+#define COLORRES 108 /* Actual color resolution */
+
+#ifndef NOGDICAPMASKS
+
+/* Device Capability Masks: */
+
+/* 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 0 /* Curves not supported */
+#define CC_CIRCLES 1 /* Can do circles */
+#define CC_PIE 2 /* Can do pie wedges */
+#define CC_CHORD 4 /* Can do chord arcs */
+#define CC_ELLIPSES 8 /* Can do ellipese */
+#define CC_WIDE 16 /* Can do wide lines */
+#define CC_STYLED 32 /* Can do styled lines */
+#define CC_WIDESTYLED 64 /* Can do wide styled lines */
+#define CC_INTERIORS 128 /* Can do interiors */
+
+/* Line Capabilities */
+#define LC_NONE 0 /* Lines not supported */
+#define LC_POLYLINE 2 /* Can do polylines */
+#define LC_MARKER 4 /* Can do markers */
+#define LC_POLYMARKER 8 /* Can do polymarkers */
+#define LC_WIDE 16 /* Can do wide lines */
+#define LC_STYLED 32 /* Can do styled lines */
+#define LC_WIDESTYLED 64 /* Can do wide styled lines */
+#define LC_INTERIORS 128 /* Can do interiors */
+
+/* Polygonal Capabilities */
+#define PC_NONE 0 /* Polygonals not supported */
+#define PC_POLYGON 1 /* Can do polygons */
+#define PC_RECTANGLE 2 /* Can do rectangles */
+#define PC_WINDPOLYGON 4 /* Can do winding polygons */
+#define PC_TRAPEZOID 4 /* Can do trapezoids */
+#define PC_SCANLINE 8 /* Can do scanlines */
+#define PC_WIDE 16 /* Can do wide borders */
+#define PC_STYLED 32 /* Can do styled borders */
+#define PC_WIDESTYLED 64 /* Can do wide styled borders */
+#define PC_INTERIORS 128 /* Can do interiors */
+
+/* Polygonal Capabilities */
+#define CP_NONE 0 /* No clipping of output */
+#define CP_RECTANGLE 1 /* Output clipped to rects */
+
+/* Text Capabilities */
+#define TC_OP_CHARACTER 0x0001 /* Can do OutputPrecision CHARACTER */
+#define TC_OP_STROKE 0x0002 /* Can do OutputPrecision STROKE */
+#define TC_CP_STROKE 0x0004 /* Can do ClipPrecision STROKE */
+#define TC_CR_90 0x0008 /* Can do CharRotAbility 90 */
+#define TC_CR_ANY 0x0010 /* Can do CharRotAbility ANY */
+#define TC_SF_X_YINDEP 0x0020 /* Can do ScaleFreedom X_YINDEPENDENT */
+#define TC_SA_DOUBLE 0x0040 /* Can do ScaleAbility DOUBLE */
+#define TC_SA_INTEGER 0x0080 /* Can do ScaleAbility INTEGER */
+#define TC_SA_CONTIN 0x0100 /* Can do ScaleAbility CONTINUOUS */
+#define TC_EA_DOUBLE 0x0200 /* Can do EmboldenAbility DOUBLE */
+#define TC_IA_ABLE 0x0400 /* Can do ItalisizeAbility ABLE */
+#define TC_UA_ABLE 0x0800 /* Can do UnderlineAbility ABLE */
+#define TC_SO_ABLE 0x1000 /* Can do StrikeOutAbility ABLE */
+#define TC_RA_ABLE 0x2000 /* Can do RasterFontAble ABLE */
+#define TC_VA_ABLE 0x4000 /* Can do VectorFontAble ABLE */
+#define TC_RESERVED 0x8000
+
+#endif /* NOGDICAPMASKS */
+
+/* Raster Capabilities */
+#define RC_BITBLT 1 /* Can do standard BLT. */
+#define RC_BANDING 2 /* Device requires banding support */
+#define RC_SCALING 4 /* Device requires scaling support */
+#define RC_BITMAP64 8 /* Device can support >64K bitmap */
+#define RC_GDI20_OUTPUT 0x0010 /* has 2.0 output calls */
+#define RC_DI_BITMAP 0x0080 /* supports DIB to memory */
+#define RC_PALETTE 0x0100 /* supports a palette */
+#define RC_DIBTODEV 0x0200 /* supports DIBitsToDevice */
+#define RC_BIGFONT 0x0400 /* supports >64K fonts */
+#define RC_STRETCHBLT 0x0800 /* supports StretchBlt */
+#define RC_FLOODFILL 0x1000 /* supports FloodFill */
+#define RC_STRETCHDIB 0x2000 /* supports StretchDIBits */
+
+
+/* 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 */
+
+/* DIB color table identifiers */
+
+#define DIB_RGB_COLORS 0 /* color table in RGBTriples */
+#define DIB_PAL_COLORS 1 /* color table in palette indices */
+
+/* constants for Get/SetSystemPaletteUse() */
+
+#define SYSPAL_STATIC 1
+#define SYSPAL_NOSTATIC 2
+
+/* constants for CreateDIBitmap */
+#define CBM_INIT 0x04L /* initialize bitmap */
+
+#ifndef NODRAWTEXT
+
+/* DrawText() Format Flags */
+#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
+
+int FAR PASCAL DrawText(HDC, LPSTR, int, LPRECT, WORD);
+BOOL FAR PASCAL DrawIcon(HDC, int, int, HICON);
+
+#endif /* NODRAWTEXT */
+
+/* ExtFloodFill style flags */
+#define FLOODFILLBORDER 0
+#define FLOODFILLSURFACE 1
+
+HDC FAR PASCAL GetWindowDC(HWND);
+HDC FAR PASCAL GetDC(HWND);
+int FAR PASCAL ReleaseDC(HWND, HDC);
+HDC FAR PASCAL CreateDC(LPSTR, LPSTR, LPSTR, LPSTR);
+HDC FAR PASCAL CreateIC(LPSTR, LPSTR, LPSTR, LPSTR);
+HDC FAR PASCAL CreateCompatibleDC(HDC);
+BOOL FAR PASCAL DeleteDC(HDC);
+int FAR PASCAL SaveDC(HDC);
+BOOL FAR PASCAL RestoreDC(HDC, int);
+DWORD FAR PASCAL MoveToEx(HDC, int, int);
+DWORD FAR PASCAL GetCurrentPositionEx(HDC);
+BOOL FAR PASCAL LineTo(HDC, int, int);
+DWORD FAR PASCAL GetDCOrg(HDC);
+
+int FAR PASCAL MulDiv(int, int, int);
+
+BOOL FAR PASCAL ExtTextOut(HDC, int, int, WORD, LPRECT, LPSTR, WORD, LPINT);
+BOOL FAR PASCAL FastWindowFrame(HDC, LPRECT, WORD, WORD, DWORD); /* ;Internal */
+
+BOOL FAR PASCAL Polyline(HDC, LPPOINT, int);
+BOOL FAR PASCAL Polygon(HDC, LPPOINT, int);
+BOOL FAR PASCAL PolyPolygon(HDC, LPPOINT, LPINT, int);
+
+BOOL FAR PASCAL Rectangle(HDC, int, int, int, int);
+BOOL FAR PASCAL RoundRect(HDC, int, int, int, int, int, int);
+BOOL FAR PASCAL Ellipse(HDC, int, int, int, int);
+BOOL FAR PASCAL Arc(HDC, int, int, int, int, int, int, int, int);
+BOOL FAR PASCAL Chord(HDC, int, int, int, int, int, int, int, int);
+BOOL FAR PASCAL Pie(HDC, int, int, int, int, int, int, int, int);
+BOOL FAR PASCAL PatBlt(HDC, int, int, int, int, DWORD);
+BOOL FAR PASCAL BitBlt(HDC, int, int, int, int, HDC, int, int, DWORD);
+BOOL FAR PASCAL StretchBlt(HDC, int, int, int, int, HDC, int, int, int, int, DWORD);
+BOOL FAR PASCAL TextOut(HDC, int, int, LPSTR, int);
+LONG FAR PASCAL TabbedTextOut(HDC, int, int, LPSTR, int, int, LPINT, int);
+BOOL FAR PASCAL GetCharWidth(HDC, WORD, WORD, LPINT);
+DWORD FAR PASCAL SetPixel( HDC, int, int, DWORD);
+DWORD FAR PASCAL GetPixel( HDC, int, int);
+BOOL FAR PASCAL FloodFill( HDC, int, int, DWORD);
+BOOL FAR PASCAL ExtFloodFill(HDC, int, int, DWORD, WORD);
+void FAR PASCAL LineDDA(int, int, int, int, FARPROC, LPSTR);
+
+HANDLE FAR PASCAL GetStockObject(int);
+
+HPEN FAR PASCAL CreatePen(int, int, DWORD);
+HPEN FAR PASCAL CreatePenIndirect(LOGPEN FAR *);
+
+HBRUSH FAR PASCAL CreateSolidBrush(DWORD);
+HBRUSH FAR PASCAL CreateHatchBrush(int,DWORD);
+DWORD FAR PASCAL SetBrushOrg(HDC, int, int);
+DWORD FAR PASCAL GetBrushOrgEx(HDC);
+HBRUSH FAR PASCAL CreatePatternBrush(HBITMAP);
+HBRUSH FAR PASCAL CreateBrushIndirect(LOGBRUSH FAR *);
+
+HBITMAP FAR PASCAL CreateBitmap(int, int, BYTE, BYTE, LPSTR);
+HBITMAP FAR PASCAL CreateBitmapIndirect(BITMAP FAR *);
+HBITMAP FAR PASCAL CreateCompatibleBitmap(HDC, int, int);
+HBITMAP FAR PASCAL CreateDiscardableBitmap(HDC, int, int);
+
+LONG FAR PASCAL SetBitmapBits(HBITMAP, DWORD, LPSTR);
+LONG FAR PASCAL GetBitmapBits(HBITMAP, LONG, LPSTR);
+DWORD FAR PASCAL SetBitmapDimensionEx(HBITMAP, int, int);
+DWORD FAR PASCAL GetBitmapDimensionEx(HBITMAP);
+
+HFONT FAR PASCAL CreateFont(int, int, int, int, int, BYTE, BYTE, BYTE, BYTE, BYTE, BYTE, BYTE, BYTE, LPSTR);
+HFONT FAR PASCAL CreateFontIndirect(LOGFONT FAR *);
+
+int FAR PASCAL SelectClipRgn(HDC, HRGN);
+HRGN FAR PASCAL CreateRectRgn(int, int, int, int);
+void FAR PASCAL SetRectRgn(HRGN, int, int, int, int);
+HRGN FAR PASCAL CreateRectRgnIndirect(LPRECT);
+HRGN FAR PASCAL CreateEllipticRgnIndirect(LPRECT);
+HRGN FAR PASCAL CreateEllipticRgn(int, int, int, int);
+HRGN FAR PASCAL CreatePolygonRgn(LPPOINT, int, int);
+HRGN FAR PASCAL CreatePolyPolygonRgn(LPPOINT, LPINT, int, int);
+HRGN FAR PASCAL CreateRoundRectRgn(int, int, int, int, int, int);
+
+int FAR PASCAL GetObject(HANDLE, int, LPSTR);
+BOOL FAR PASCAL DeleteObject(HANDLE);
+HANDLE FAR PASCAL SelectObject(HDC, HANDLE);
+BOOL FAR PASCAL UnrealizeObject(HBRUSH);
+
+int FAR PASCAL SetRelAbs(HDC, int); /* ;Internal */
+int FAR PASCAL GetRelAbs(HDC); /* ;Internal */
+DWORD FAR PASCAL SetBkColor(HDC, DWORD);
+DWORD FAR PASCAL GetBkColor(HDC);
+int FAR PASCAL SetBkMode(HDC, int);
+int FAR PASCAL GetBkMode(HDC);
+DWORD FAR PASCAL SetTextColor(HDC, DWORD);
+DWORD FAR PASCAL GetTextColor(HDC);
+WORD FAR PASCAL SetTextAlign(HDC, WORD);
+WORD FAR PASCAL GetTextAlign(HDC);
+DWORD FAR PASCAL SetMapperFlags(HDC, DWORD);
+DWORD FAR PASCAL GetAspectRatioFilterEx(HDC);
+DWORD FAR PASCAL GetNearestColor(HDC, DWORD);
+int FAR PASCAL SetROP2(HDC, int);
+int FAR PASCAL GetROP2(HDC);
+int FAR PASCAL SetStretchBltMode(HDC, int);
+int FAR PASCAL GetStretchBltMode(HDC);
+int FAR PASCAL SetPolyFillMode(HDC, int);
+int FAR PASCAL GetPolyFillMode(HDC);
+int FAR PASCAL SetMapMode(HDC, int);
+int FAR PASCAL GetMapMode(HDC);
+DWORD FAR PASCAL SetWindowOrgEx(HDC, int, int);
+DWORD FAR PASCAL GetWindowOrgEx(HDC);
+DWORD FAR PASCAL SetWindowExtEx(HDC, int, int);
+DWORD FAR PASCAL GetWindowExtEx(HDC);
+DWORD FAR PASCAL SetViewportOrgEx(HDC, int, int);
+DWORD FAR PASCAL GetViewportOrgEx(HDC);
+DWORD FAR PASCAL SetViewportExtEx(HDC, int, int);
+DWORD FAR PASCAL GetViewportExtEx(HDC);
+DWORD FAR PASCAL OffsetViewportOrgEx(HDC, int, int);
+DWORD FAR PASCAL ScaleViewportExtEx(HDC, int, int, int, int);
+DWORD FAR PASCAL OffsetWindowOrgEx(HDC, int, int);
+DWORD FAR PASCAL ScaleWindowExtEx(HDC, int, int, int, int);
+
+int FAR PASCAL GetClipBox(HDC, LPRECT);
+int FAR PASCAL IntersectClipRect(HDC, int, int, int, int);
+int FAR PASCAL OffsetClipRgn(HDC, int, int);
+int FAR PASCAL ExcludeClipRect(HDC, int, int, int, int);
+BOOL FAR PASCAL PtVisible(HDC, int, int);
+int FAR PASCAL CombineRgn(HRGN, HRGN, HRGN, int);
+BOOL FAR PASCAL EqualRgn(HRGN, HRGN);
+int FAR PASCAL OffsetRgn(HRGN, int, int);
+int FAR PASCAL GetRgnBox(HRGN, LPRECT);
+
+int FAR PASCAL SetTextJustification(HDC, int, int);
+DWORD FAR PASCAL GetTextExtentPoint(HDC, LPSTR, int);
+DWORD FAR PASCAL GetTabbedTextExtent(HDC, LPSTR, int, int, LPINT);
+int FAR PASCAL SetTextCharacterExtra(HDC, int);
+int FAR PASCAL GetTextCharacterExtra(HDC);
+
+HANDLE FAR PASCAL GetMetaFile(LPSTR);
+BOOL FAR PASCAL DeleteMetaFile(HANDLE);
+HANDLE FAR PASCAL CopyMetaFile(HANDLE, LPSTR);
+
+#ifndef NOMETAFILE
+void FAR PASCAL PlayMetaFileRecord(HDC, LPHANDLETABLE, LPMETARECORD, WORD);
+BOOL FAR PASCAL EnumMetaFile(HDC, LOCALHANDLE, FARPROC, BYTE FAR *);
+#endif
+
+BOOL FAR PASCAL PlayMetaFile(HDC, HANDLE);
+int FAR PASCAL Escape(HDC, int, int, LPSTR, LPSTR);
+int FAR PASCAL EnumFonts(HDC, LPSTR, FARPROC, LPSTR);
+int FAR PASCAL EnumObjects(HDC, int, FARPROC, LPSTR);
+int FAR PASCAL GetTextFace(HDC, int, LPSTR);
+
+#ifndef NOTEXTMETRIC
+BOOL FAR PASCAL GetTextMetrics(HDC, LPTEXTMETRIC );
+#endif
+
+int FAR PASCAL GetDeviceCaps(HDC, int);
+
+int FAR PASCAL SetEnvironment(LPSTR, LPSTR, WORD);
+int FAR PASCAL GetEnvironment(LPSTR, LPSTR, WORD);
+
+BOOL FAR PASCAL DPtoLP(HDC, LPPOINT, int);
+BOOL FAR PASCAL LPtoDP(HDC, LPPOINT, int);
+
+HANDLE FAR PASCAL CreateMetaFile(LPSTR);
+HANDLE FAR PASCAL CloseMetaFile(HANDLE);
+HANDLE FAR PASCAL GetMetaFileBitsEx(HANDLE);
+HANDLE FAR PASCAL SetMetaFileBitsEx(HANDLE);
+
+int FAR PASCAL SetDIBits(HDC,HANDLE,WORD,WORD,LPSTR,LPBITMAPINFO,WORD);
+int FAR PASCAL GetDIBits(HDC,HANDLE,WORD,WORD,LPSTR,LPBITMAPINFO,WORD);
+int FAR PASCAL SetDIBitsToDevice(HDC,WORD,WORD,WORD,WORD,
+ WORD,WORD,WORD,WORD,
+ LPSTR,LPBITMAPINFO,WORD);
+HBITMAP FAR PASCAL CreateDIBitmap(HDC,LPBITMAPINFOHEADER,DWORD,LPSTR,
+ LPBITMAPINFO,WORD);
+HBRUSH FAR PASCAL CreateDIBPatternBrush(HANDLE,WORD);
+int FAR PASCAL StretchDIBits(HDC, WORD, WORD, WORD, WORD, WORD,
+ WORD, WORD, WORD, LPSTR, LPBITMAPINFO, WORD, DWORD);
+
+HPALETTE FAR PASCAL CreatePalette (LPLOGPALETTE);
+HPALETTE FAR PASCAL SelectPalette (HDC,HPALETTE, BOOL) ;
+WORD FAR PASCAL RealizePalette (HDC) ;
+int FAR PASCAL UpdateColors (HDC) ;
+void FAR PASCAL AnimatePalette(HPALETTE, WORD, WORD, LPPALETTEENTRY);
+WORD FAR PASCAL SetPaletteEntries(HPALETTE,WORD,WORD,LPPALETTEENTRY);
+WORD FAR PASCAL GetPaletteEntries(HPALETTE,WORD,WORD,LPPALETTEENTRY);
+WORD FAR PASCAL GetNearestPaletteIndex(HPALETTE, DWORD);
+BOOL FAR PASCAL ResizePalette(HPALETTE, WORD);
+
+WORD FAR PASCAL GetSystemPaletteEntries(HDC,WORD,WORD,LPPALETTEENTRY);
+WORD FAR PASCAL GetSystemPaletteUse(HDC, WORD);
+WORD FAR PASCAL SetSystemPaletteUse(HDC, WORD);
+#endif /* NOGDI */
+
+
+/*--------------------------------------------------------------------------*/
+/* USER Section */
+/*--------------------------------------------------------------------------*/
+
+#ifndef NOUSER
+
+int FAR PASCAL wvsprintf(LPSTR,LPSTR,LPSTR);
+int FAR cdecl wsprintf(LPSTR,LPSTR,...);
+
+#ifndef NOSCROLL
+
+/* Scroll Bar Constants */
+#define SB_HORZ 0
+#define SB_VERT 1
+#define SB_CTL 2
+#define SB_BOTH 3
+
+/* Scroll Bar Commands */
+#define SB_LINEUP 0
+#define SB_LINEDOWN 1
+#define SB_PAGEUP 2
+#define SB_PAGEDOWN 3
+#define SB_THUMBPOSITION 4
+#define SB_THUMBTRACK 5
+#define SB_TOP 6
+#define SB_BOTTOM 7
+#define SB_ENDSCROLL 8
+
+#endif /* NOSCROLL */
+
+#ifndef NOSHOWWINDOW
+
+/* ShowWindow() Commands */
+#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
+
+/* Old ShowWindow() Commands */
+#define HIDE_WINDOW 0
+#define SHOW_OPENWINDOW 1
+#define SHOW_ICONWINDOW 2
+#define SHOW_FULLSCREEN 3
+#define SHOW_OPENNOACTIVATE 4
+
+/* Identifiers for the WM_SHOWWINDOW message */
+#define SW_PARENTCLOSING 1
+#define SW_OTHERZOOM 2
+#define SW_PARENTOPENING 3
+#define SW_OTHERUNZOOM 4
+
+#endif /* NOSHOWWINDOW */
+
+/* Region Flags */
+#define ERROR 0
+#define NULLREGION 1
+#define SIMPLEREGION 2
+#define COMPLEXREGION 3
+
+/* CombineRgn() Styles */
+#define RGN_AND 1
+#define RGN_OR 2
+#define RGN_XOR 3
+#define RGN_DIFF 4
+#define RGN_COPY 5
+
+#ifndef NOVIRTUALKEYCODES
+
+/* 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
+#define VK_SELECT 0x29
+#define VK_PRINT 0x2A
+#define VK_EXECUTE 0x2B
+#define VK_SNAPSHOT 0x2C
+/* #define VK_COPY 0x2C not used by keyboards. */
+#define VK_INSERT 0x2D
+#define VK_DELETE 0x2E
+#define VK_HELP 0x2F
+
+/* 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_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_NUMLOCK 0x90
+#define VK_SCROLL 0x91
+
+#endif /* NOVIRTUALKEYCODES */
+
+#ifndef NOWH
+
+/* SetWindowsHook() codes */
+#define WH_MSGFILTER (-1)
+#define WH_JOURNALRECORD 0
+#define WH_JOURNALPLAYBACK 1
+#define WH_KEYBOARD 2
+#define WH_GETMESSAGE 3
+#define WH_CALLWNDPROC 4
+#define WH_CBT 5
+#define WH_SYSMSGFILTER 6
+#define WH_MOUSE 7
+#define WH_HARDWARE 8
+#define WH_DEBUG 9
+
+/* Hook Codes */
+#define HC_GETLPLPFN (-3)
+#define HC_LPLPFNNEXT (-2)
+#define HC_LPFNNEXT (-1)
+#define HC_ACTION 0
+#define HC_GETNEXT 1
+#define HC_SKIP 2
+#define HC_NOREM 3
+#define HC_NOREMOVE 3
+#define HC_SYSMODALON 4
+#define HC_SYSMODALOFF 5
+
+/* CBT Hook Codes */
+#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
+
+/* WH_MSGFILTER Filter Proc 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
+
+/* Window Manager Hook Codes */
+#define WC_INIT 1
+#define WC_SWP 2
+#define WC_DEFWINDOWPROC 3
+#define WC_MINMAX 4
+#define WC_MOVE 5
+#define WC_SIZE 6
+#define WC_DRAWCAPTION 7
+
+/* Message Structure used in Journaling */
+typedef struct tagEVENTMSG
+ {
+ WORD message;
+ WORD paramL;
+ WORD paramH;
+ DWORD time;
+ } EVENTMSG;
+typedef EVENTMSG *PEVENTMSGMSG;
+typedef EVENTMSG NEAR *NPEVENTMSGMSG;
+typedef EVENTMSG FAR *LPEVENTMSGMSG;
+
+#endif /* NOWH */
+
+typedef struct tagWNDCLASS
+ {
+ WORD style;
+ LONG (FAR PASCAL *lpfnWndProc)();
+ int cbClsExtra;
+ int cbWndExtra;
+ HANDLE hInstance;
+ HICON hIcon;
+ HCURSOR hCursor;
+ HBRUSH hbrBackground;
+ LPSTR lpszMenuName;
+ LPSTR lpszClassName;
+ } WNDCLASS;
+typedef WNDCLASS *PWNDCLASS;
+typedef WNDCLASS NEAR *NPWNDCLASS;
+typedef WNDCLASS FAR *LPWNDCLASS;
+
+#ifndef NOMSG
+
+/* Message structure */
+typedef struct tagMSG
+ {
+ HWND hwnd;
+ WORD message;
+ WORD wParam;
+ LONG lParam;
+ DWORD time;
+ POINT pt;
+ } MSG;
+typedef MSG *PMSG;
+typedef MSG NEAR *NPMSG;
+typedef MSG FAR *LPMSG;
+
+#endif /* NOMSG */
+
+#ifndef NOWINOFFSETS
+
+/* Window field offsets for GetWindowLong() and GetWindowWord() */
+#define GWL_WNDPROC (-4)
+#define GWW_HINSTANCE (-6)
+#define GWW_HWNDPARENT (-8)
+#define GWW_ID (-12)
+#define GWL_STYLE (-16)
+#define GWL_EXSTYLE (-20)
+
+/* 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)
+
+#endif /* NOWINOFFSETS */
+
+#ifndef NOWINMESSAGES
+
+/* Window Messages */
+#define WM_NULL 0x0000
+#define WM_CREATE 0x0001
+#define WM_DESTROY 0x0002
+#define WM_MOVE 0x0003
+#define WM_SIZEWAIT 0x0004 /* ;Internal */
+#define WM_SIZE 0x0005
+#define WM_ACTIVATE 0x0006
+#define WM_SETFOCUS 0x0007
+#define WM_KILLFOCUS 0x0008
+#define WM_SETVISIBLE 0x0009 /* ;Internal */
+#define WM_ENABLE 0x000A
+#define WM_SETREDRAW 0x000B
+#define WM_SETTEXT 0x000C
+#define WM_GETTEXT 0x000D
+#define WM_GETTEXTLENGTH 0x000E
+#define WM_PAINT 0x000F
+#define WM_CLOSE 0x0010
+#define WM_QUERYENDSESSION 0x0011
+#define WM_QUIT 0x0012
+#define WM_QUERYOPEN 0x0013
+#define WM_ERASEBKGND 0x0014
+#define WM_SYSCOLORCHANGE 0x0015
+#define WM_ENDSESSION 0x0016
+#define WM_SYSTEMERROR 0x0017 /* ;Internal */
+#define WM_SHOWWINDOW 0x0018
+#define WM_CTLCOLOR 0x0019
+#define WM_WININICHANGE 0x001A
+#define WM_DEVMODECHANGE 0x001B
+#define WM_ACTIVATEAPP 0x001C
+#define WM_FONTCHANGE 0x001D
+#define WM_TIMECHANGE 0x001E
+#define WM_CANCELMODE 0x001F
+#define WM_SETCURSOR 0x0020
+#define WM_MOUSEACTIVATE 0x0021
+#define WM_CHILDACTIVATE 0x0022
+#define WM_QUEUESYNC 0x0023
+#define WM_GETMINMAXINFO 0x0024
+#define WM_PAINTICON 0x0026
+#define WM_ICONERASEBKGND 0x0027
+#define WM_NEXTDLGCTL 0x0028
+#define WM_ALTTABACTIVE 0x0029 /* ;Internal */
+#define WM_SPOOLERSTATUS 0x002A
+#define WM_DRAWITEM 0x002B
+#define WM_MEASUREITEM 0x002C
+#define WM_DELETEITEM 0x002D
+#define WM_VKEYTOITEM 0x002E
+#define WM_CHARTOITEM 0x002F
+#define WM_SETFONT 0x0030
+#define WM_GETFONT 0x0031
+#define WM_SETHOTKEY 0x0032
+#define WM_GETHOTKEY 0x0033
+#define WM_FILESYSCHANGE 0x0034 /* ;Internal */
+#define WM_ISACTIVEICON 0x0035 /* ;Internal */
+#define WM_QUERYPARKICON 0x0036 /* ;Internal */
+#define WM_QUERYDRAGICON 0x0037
+
+#define WM_COMPAREITEM 0x0039
+#define WM_TESTING 0x0040 /* ;Internal */
+#define WM_COMPACTING 0x0041
+#define WM_OTHERWINDOWCREATED 0x0042
+#define WM_OTHERWINDOWDESTROYED 0x0043
+
+#define WM_NCCREATE 0x0081
+#define WM_NCDESTROY 0x0082
+#define WM_NCCALCSIZE 0x0083
+#define WM_NCHITTEST 0x0084
+#define WM_NCPAINT 0x0085
+#define WM_NCACTIVATE 0x0086
+#define WM_GETDLGCODE 0x0087
+#define WM_SYNCPAINT 0x0088 /* ;Internal */
+#define WM_SYNCTASK 0x0089 /* ;Internal */
+#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
+
+#define WM_KEYFIRST 0x0100
+#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 /* ;Internal */
+#define WM_KEYLAST 0x0108
+
+#define WM_CONVERTREQUEST 0x010A /* ;Internal */
+#define WM_CONVERTRESULT 0x010B /* ;Internal */
+#define WM_INITDIALOG 0x0110
+#define WM_COMMAND 0x0111
+#define WM_SYSCOMMAND 0x0112
+#define WM_TIMER 0x0113
+#define WM_HSCROLL 0x0114
+#define WM_VSCROLL 0x0115
+#define WM_INITMENU 0x0116
+#define WM_INITMENUPOPUP 0x0117
+#define WM_SYSTIMER 0x0118 /* ;Internal */
+#define WM_MENUSELECT 0x011F
+#define WM_MENUCHAR 0x0120
+#define WM_ENTERIDLE 0x0121
+
+#define WM_LBTRACKPOINT 0x0131 /* ;Internal */
+
+#define WM_MOUSEFIRST 0x0200
+#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
+#define WM_MOUSELAST 0x0209
+
+#define WM_PARENTNOTIFY 0x0210
+#define WM_ENTERMENULOOP 0x0211 /* ;Internal */
+#define WM_EXITMENULOOP 0x0212 /* ;Internal */
+#define WM_NEXTMENU 0x0213 /* ;Internal */
+#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_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_MDISETMENU 0x0230
+#define WM_ENTERSIZEMOVE 0x0231 /* ;Internal */
+#define WM_EXITSIZEMOVE 0x0232 /* ;Internal */
+
+#define WM_KANJIFIRST 0x0280 /* ;Internal */
+#define WM_KANJILAST 0x029F /* ;Internal */
+
+#define WM_CUT 0x0300
+#define WM_COPY 0x0301
+#define WM_PASTE 0x0302
+#define WM_CLEAR 0x0303
+#define WM_UNDO 0x0304
+#define WM_RENDERFORMAT 0x0305
+#define WM_RENDERALLFORMATS 0x0306
+#define WM_DESTROYCLIPBOARD 0x0307
+#define WM_DRAWCLIPBOARD 0x0308
+#define WM_PAINTCLIPBOARD 0x0309
+#define WM_VSCROLLCLIPBOARD 0x030A
+#define WM_SIZECLIPBOARD 0x030B
+#define WM_ASKCBFORMATNAME 0x030C
+#define WM_CHANGECBCHAIN 0x030D
+#define WM_HSCROLLCLIPBOARD 0x030E
+#define WM_QUERYNEWPALETTE 0x030F
+#define WM_PALETTEGONNACHANGE 0x0310 /* ;Internal */
+#define WM_PALETTEISCHANGING 0x0310
+#define WM_CHANGEPALETTE 0x0311 /* ;Internal */
+#define WM_PALETTECHANGED 0x0311
+
+#define WM_INTERNAL_COALESCE_FIRST 0x03A0 /* ;Internal */
+
+#define WM_COALESCE_FIRST 0x03A0
+#define WM_COALESCE_LAST 0x03AF
+
+/* The following message range reserved */ /* ;Internal */
+/* for multi-media */ /* ;Internal */
+#define WM_MM_RESERVED_FIRST 0x03B0 /* ;Internal */
+#define WM_MM_RESERVED_LAST 0x03EF /* ;Internal */
+
+#define WM_INTERNAL_COALESCE_LAST WM_MM_RESERVED_LAST /* ;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 */
+
+
+/* NOTE: All Message Numbers below 0x0400 are RESERVED. */
+
+/* Private Window Messages Start Here: */
+#define WM_USER 0x0400
+
+#ifndef NONCMESSAGES
+
+/* WM_SYNCTASK Commands */
+#define ST_BEGINSWP 0
+#define ST_ENDSWP 1
+
+/* WinWhere() Area Codes */
+#define HTERROR (-2)
+#define HTTRANSPARENT (-1)
+#define HTNOWHERE 0
+#define HTCLIENT 1
+#define HTCAPTION 2
+#define HTSYSMENU 3
+#define HTGROWBOX 4
+#define HTSIZE HTGROWBOX
+#define HTMENU 5
+#define HTHSCROLL 6
+#define HTVSCROLL 7
+#define HTREDUCE 8
+#define HTZOOM 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 HTSIZEFIRST HTLEFT
+#define HTSIZELAST HTBOTTOMRIGHT
+
+#endif /* NONCMESSAGES */
+
+/* WM_MOUSEACTIVATE Return Codes */
+#define MA_ACTIVATE 1
+#define MA_ACTIVATEANDEAT 2
+#define MA_NOACTIVATE 3
+
+WORD FAR PASCAL RegisterWindowMessage(LPSTR);
+
+/* Size Message Commands */
+#define SIZENORMAL 0
+#define SIZEICONIC 1
+#define SIZEFULLSCREEN 2
+#define SIZEZOOMSHOW 3
+#define SIZEZOOMHIDE 4
+
+#ifndef NOKEYSTATES
+
+/* Key State Masks for Mouse Messages */
+#define MK_LBUTTON 0x0001
+#define MK_RBUTTON 0x0002
+#define MK_SHIFT 0x0004
+#define MK_CONTROL 0x0008
+#define MK_MBUTTON 0x0010
+
+#endif /* NOKEYSTATES */
+
+#endif /* NOWINMESSAGES */
+
+#ifndef NOWINSTYLES
+
+/* Window Styles */
+#define WS_OVERLAPPED 0x00000000L
+#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_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_GROUP 0x00020000L
+#define WS_TABSTOP 0x00010000L
+
+#define WS_MINIMIZEBOX 0x00020000L
+#define WS_MAXIMIZEBOX 0x00010000L
+
+#define WS_TILED WS_OVERLAPPED
+#define WS_ICONIC WS_MINIMIZE
+#define WS_SIZEBOX WS_THICKFRAME
+
+/* 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)
+
+#define WS_TILEDWINDOW (WS_OVERLAPPEDWINDOW)
+
+/* Extended Window Styles */
+#define WS_EX_DLGMODALFRAME 0x00000001L
+#define WS_EX_DRAGOBJECT 0x00000002L /* ;Internal */
+#define WS_EX_NOPARENTNOTIFY 0x00000004L
+#define WS_EX_TOPMOST 0x00000008L
+
+/* Class styles */
+#define CS_VREDRAW 0x0001
+#define CS_HREDRAW 0x0002
+#define CS_KEYCVTWINDOW 0x0004
+#define CS_DBLCLKS 0x0008
+ /* 0x0010 -- no longer used */
+#define CS_OWNDC 0x0020
+#define CS_CLASSDC 0x0040
+#define CS_PARENTDC 0x0080
+#define CS_NOKEYCVT 0x0100
+#define CS_NOCLOSE 0x0200
+#define CS_SAVEBITS 0x0800
+#define CS_BYTEALIGNCLIENT 0x1000
+#define CS_BYTEALIGNWINDOW 0x2000
+#define CS_GLOBALCLASS 0x4000 /* Global window class */
+
+#endif /* NOWINSTYLES */
+
+#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_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
+
+#endif /* NOCLIPBOARD */
+
+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;
+
+typedef struct tagCREATESTRUCT
+ {
+ LPSTR lpCreateParams;
+ HANDLE hInstance;
+ HANDLE hMenu;
+ HWND hwndParent;
+ int cy;
+ int cx;
+ int y;
+ int x;
+ LONG style;
+ LPSTR lpszName;
+ LPSTR lpszClass;
+ DWORD dwExStyle;
+ } CREATESTRUCT;
+typedef CREATESTRUCT FAR *LPCREATESTRUCT;
+
+
+/* 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
+
+/* MEASUREITEMSTRUCT for ownerdraw */
+typedef struct tagMEASUREITEMSTRUCT
+ {
+ WORD CtlType;
+ WORD CtlID;
+ WORD itemID;
+ WORD itemWidth;
+ WORD itemHeight;
+ DWORD itemData;
+ } MEASUREITEMSTRUCT;
+typedef MEASUREITEMSTRUCT NEAR *PMEASUREITEMSTRUCT;
+typedef MEASUREITEMSTRUCT FAR *LPMEASUREITEMSTRUCT;
+
+
+/* DRAWITEMSTRUCT for ownerdraw */
+typedef struct tagDRAWITEMSTRUCT
+ {
+ WORD CtlType;
+ WORD CtlID;
+ WORD itemID;
+ WORD itemAction;
+ WORD itemState;
+ HWND hwndItem;
+ HDC hDC;
+ RECT rcItem;
+ DWORD itemData;
+ } DRAWITEMSTRUCT;
+typedef DRAWITEMSTRUCT NEAR *PDRAWITEMSTRUCT;
+typedef DRAWITEMSTRUCT FAR *LPDRAWITEMSTRUCT;
+
+/* DELETEITEMSTRUCT for ownerdraw */
+typedef struct tagDELETEITEMSTRUCT
+ {
+ WORD CtlType;
+ WORD CtlID;
+ WORD itemID;
+ HWND hwndItem;
+ DWORD itemData;
+ } DELETEITEMSTRUCT;
+typedef DELETEITEMSTRUCT NEAR *PDELETEITEMSTRUCT;
+typedef DELETEITEMSTRUCT FAR *LPDELETEITEMSTRUCT;
+
+/* COMPAREITEMSTUCT for ownerdraw sorting */
+typedef struct tagCOMPAREITEMSTRUCT
+ {
+ WORD CtlType;
+ WORD CtlID;
+ HWND hwndItem;
+ WORD itemID1;
+ DWORD itemData1;
+ WORD itemID2;
+ DWORD itemData2;
+ } COMPAREITEMSTRUCT;
+typedef COMPAREITEMSTRUCT NEAR *PCOMPAREITEMSTRUCT;
+typedef COMPAREITEMSTRUCT FAR *LPCOMPAREITEMSTRUCT;
+
+#ifndef NOMSG
+
+/* Message Function Templates */
+BOOL FAR PASCAL GetMessage(LPMSG, HWND, WORD, WORD);
+BOOL FAR PASCAL TranslateMessage(LPMSG);
+LONG FAR PASCAL DispatchMessage(LPMSG);
+BOOL FAR PASCAL PeekMessage(LPMSG, HWND, WORD, WORD, WORD);
+
+/* PeekMessage() Options */
+#define PM_NOREMOVE 0x0000
+#define PM_REMOVE 0x0001
+#define PM_NOYIELD 0x0002
+
+#endif /* NOMSG */
+
+#ifdef WIN_INTERNAL
+ #ifndef LSTRING
+ #define NOLSTRING
+ #endif
+ #ifndef LFILEIO
+ #define NOLFILEIO
+ #endif
+#endif
+
+#ifndef NOLSTRING
+int FAR PASCAL lstrcmp( LPSTR, LPSTR );
+int FAR PASCAL lstrcmpi( LPSTR, LPSTR );
+LPSTR FAR PASCAL lstrcpy( LPSTR, LPSTR );
+LPSTR FAR PASCAL lstrcat( LPSTR, LPSTR );
+int FAR PASCAL lstrlen( LPSTR );
+#endif /* NOLSTRING */
+
+#ifndef NOLFILEIO
+int FAR PASCAL _lopen( LPSTR, int );
+int 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 );
+WORD FAR PASCAL DeletePathname(LPSTR); /* ;Internal */
+
+#define READ 0 /* Flags for _lopen */
+#define WRITE 1
+#define READ_WRITE 2
+#endif /* NOLFILEIO */
+
+BOOL FAR PASCAL ExitWindows(DWORD dwReserved, WORD wReturnCode);
+
+BOOL FAR PASCAL SwapMouseButton(BOOL);
+DWORD FAR PASCAL GetMessagePos(void);
+LONG FAR PASCAL GetMessageTime(void);
+
+HWND FAR PASCAL GetSysModalWindow(void);
+HWND FAR PASCAL SetSysModalWindow(HWND);
+
+LONG FAR PASCAL SendMessage(HWND, WORD, WORD, LONG);
+BOOL FAR PASCAL PostMessage(HWND, WORD, WORD, LONG);
+BOOL FAR PASCAL PostAppMessage(HANDLE, WORD, WORD, LONG);
+void FAR PASCAL ReplyMessage(LONG);
+void FAR PASCAL WaitMessage(void);
+LONG FAR PASCAL DefWindowProc(HWND, WORD, WORD, LONG);
+void FAR PASCAL PostQuitMessage(int);
+LONG FAR PASCAL CallWindowProc(FARPROC, HWND, WORD, WORD, LONG);
+BOOL FAR PASCAL InSendMessage(void);
+
+WORD FAR PASCAL GetDoubleClickTime(void);
+void FAR PASCAL SetDoubleClickTime(WORD);
+
+BOOL FAR PASCAL RegisterClass(LPWNDCLASS);
+BOOL FAR PASCAL UnregisterClass(LPSTR, HANDLE);
+BOOL FAR PASCAL GetClassInfo(HANDLE, LPSTR, LPWNDCLASS);
+DWORD FAR PASCAL GetIconValue(WORD, WORD); /* ;Internal */
+LONG FAR PASCAL GetExpWinVer(HANDLE); /* ;Internal */
+
+BOOL FAR PASCAL SetMessageQueue(int);
+HWND FAR PASCAL GetNextQueueWindow(HWND, int); /* ;Internal */
+
+#define CW_USEDEFAULT ((int)0x8000)
+HWND FAR PASCAL CreateWindow(LPSTR, LPSTR, DWORD, int, int, int, int, HWND, HMENU, HANDLE, LPSTR);
+HWND FAR PASCAL CreateWindowEx(DWORD, LPSTR, LPSTR, DWORD, int, int, int, int, HWND, HMENU, HANDLE, LPSTR);
+
+BOOL FAR PASCAL IsWindow(HWND);
+BOOL FAR PASCAL IsChild(HWND, HWND);
+BOOL FAR PASCAL DestroyWindow(HWND);
+
+BOOL FAR PASCAL ShowWindow(HWND, int);
+BOOL FAR PASCAL FlashWindow(HWND, BOOL);
+void FAR PASCAL ShowOwnedPopups(HWND, BOOL);
+
+BOOL FAR PASCAL OpenIcon(HWND);
+void FAR PASCAL CloseWindow(HWND);
+void FAR PASCAL MoveWindow(HWND, int, int, int, int, BOOL);
+void FAR PASCAL SetWindowPos(HWND, HWND, int, int, int, int, WORD);
+
+#ifndef NODEFERWINDOWPOS
+
+HANDLE FAR PASCAL BeginDeferWindowPos(int nNumWindows);
+HANDLE FAR PASCAL DeferWindowPos(HANDLE hWinPosInfo, HWND hWnd, HWND hWndInsertAfter, int x, int y, int cx, int cy, WORD wFlags);
+void FAR PASCAL EndDeferWindowPos(HANDLE hWinPosInfo);
+
+#endif /* NODEFERWINDOWPOS */
+
+BOOL FAR PASCAL IsWindowVisible(HWND);
+BOOL FAR PASCAL IsIconic(HWND);
+BOOL FAR PASCAL AnyPopup(void);
+void FAR PASCAL BringWindowToTop(HWND);
+BOOL FAR PASCAL IsZoomed(HWND);
+
+/* SetWindowPos Flags */
+#define SWP_NOSIZE 0x0001
+#define SWP_NOMOVE 0x0002
+#define SWP_NOZORDER 0x0004
+#define SWP_NOREDRAW 0x0008
+#define SWP_NOACTIVATE 0x0010
+#define SWP_DRAWFRAME 0x0020
+#define SWP_SHOWWINDOW 0x0040
+#define SWP_HIDEWINDOW 0x0080
+#define SWP_NOCOPYBITS 0x0100
+#define SWP_NOREPOSITION 0x0200
+
+#ifndef NOCTLMGR
+
+HWND FAR PASCAL CreateDialog(HANDLE, LPSTR, HWND, FARPROC);
+HWND FAR PASCAL CreateDialogIndirect(HANDLE, LPSTR, HWND, FARPROC);
+HWND FAR PASCAL CreateDialogParam(HANDLE, LPSTR, HWND, FARPROC, LONG);
+HWND FAR PASCAL CreateDialogIndirectParam(HANDLE, LPSTR, HWND, FARPROC, LONG);
+int FAR PASCAL DialogBox(HANDLE, LPSTR, HWND, FARPROC);
+int FAR PASCAL DialogBoxIndirect(HANDLE, HANDLE, HWND, FARPROC);
+int FAR PASCAL DialogBoxParam(HANDLE, LPSTR, HWND, FARPROC, LONG);
+int FAR PASCAL DialogBoxIndirectParam(HANDLE, HANDLE, HWND, FARPROC, LONG);
+void FAR PASCAL EndDialog(HWND, int);
+HWND FAR PASCAL GetDlgItem(HWND, int);
+void FAR PASCAL SetDlgItemInt(HWND, int, WORD, BOOL);
+WORD FAR PASCAL GetDlgItemInt(HWND, int, BOOL FAR *, BOOL);
+void FAR PASCAL SetDlgItemText(HWND, int, LPSTR);
+int FAR PASCAL GetDlgItemText(HWND, int, LPSTR, int);
+void FAR PASCAL CheckDlgButton(HWND, int, WORD);
+void FAR PASCAL CheckRadioButton(HWND, int, int, int);
+WORD FAR PASCAL IsDlgButtonChecked(HWND, int);
+LONG FAR PASCAL SendDlgItemMessage(HWND, int, WORD, WORD, LONG);
+HWND FAR PASCAL GetNextDlgGroupItem(HWND, HWND, BOOL);
+HWND FAR PASCAL GetNextDlgTabItem(HWND, HWND, BOOL);
+int FAR PASCAL GetDlgCtrlID(HWND);
+long FAR PASCAL GetDialogBaseUnits(void);
+LONG FAR PASCAL DefDlgProc(HWND, WORD, WORD, LONG);
+#define DLGWINDOWEXTRA 30 /* Window extra byted needed for private dialog classes */
+
+#endif /* NOCTLMGR */
+
+#ifndef NOMSG
+BOOL FAR PASCAL CallMsgFilter(LPMSG, int);
+#endif
+
+#ifndef NOCLIPBOARD
+
+/* Clipboard Manager Functions */
+BOOL FAR PASCAL OpenClipboard(HWND);
+BOOL FAR PASCAL CloseClipboard(void);
+HWND FAR PASCAL GetClipboardOwner(void);
+HWND FAR PASCAL SetClipboardViewer(HWND);
+HWND FAR PASCAL GetClipboardViewer(void);
+BOOL FAR PASCAL ChangeClipboardChain(HWND, HWND);
+HANDLE FAR PASCAL SetClipboardData(WORD, HANDLE);
+HANDLE FAR PASCAL GetClipboardData(WORD);
+WORD FAR PASCAL RegisterClipboardFormat(LPSTR);
+int FAR PASCAL CountClipboardFormats(void);
+WORD FAR PASCAL EnumClipboardFormats(WORD);
+int FAR PASCAL GetClipboardFormatName(WORD, LPSTR, int);
+BOOL FAR PASCAL EmptyClipboard(void);
+BOOL FAR PASCAL IsClipboardFormatAvailable(WORD);
+int FAR PASCAL GetPriorityClipboardFormat(WORD FAR *, int);
+
+#endif /* NOCLIPBOARD */
+
+HWND FAR PASCAL SetFocus(HWND);
+HWND FAR PASCAL GetFocus(void);
+HWND FAR PASCAL GetActiveWindow(void);
+int FAR PASCAL GetKeyState(int);
+int FAR PASCAL GetAsyncKeyState(int);
+void FAR PASCAL GetKeyboardState(BYTE FAR *);
+void FAR PASCAL SetKeyboardState(BYTE FAR *);
+BOOL FAR PASCAL EnableHardwareInput(BOOL);
+BOOL FAR PASCAL GetInputState(void);
+HWND FAR PASCAL GetCapture(void);
+HWND FAR PASCAL SetCapture(HWND);
+void FAR PASCAL ReleaseCapture(void);
+
+/* Windows Functions */
+WORD FAR PASCAL SetTimer(HWND, int, WORD, FARPROC);
+BOOL FAR PASCAL KillTimer(HWND, int);
+
+BOOL FAR PASCAL EnableWindow(HWND,BOOL);
+BOOL FAR PASCAL IsWindowEnabled(HWND);
+
+HANDLE FAR PASCAL LoadAccelerators(HANDLE, LPSTR);
+
+#ifndef NOMSG
+int FAR PASCAL TranslateAccelerator(HWND, HANDLE, LPMSG);
+#endif
+
+#ifndef NOSYSMETRICS
+
+/* 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
+#define SM_CMETRICS 36
+
+int FAR PASCAL GetSystemMetrics(int);
+
+#endif /* NOSYSMETRICS */
+
+#ifndef NOMENUS
+
+HMENU FAR PASCAL LoadMenu(HANDLE, LPSTR);
+HMENU FAR PASCAL LoadMenuIndirect(LPSTR);
+HMENU FAR PASCAL GetMenu(HWND);
+BOOL FAR PASCAL SetMenu(HWND, HMENU);
+BOOL FAR PASCAL ChangeMenu(HMENU, WORD, LPSTR, WORD, WORD);
+BOOL FAR PASCAL HiliteMenuItem(HWND, HMENU, WORD, WORD);
+int FAR PASCAL GetMenuString(HMENU, WORD, LPSTR, int, WORD);
+WORD FAR PASCAL GetMenuState(HMENU, WORD, WORD);
+void FAR PASCAL DrawMenuBar(HWND);
+HMENU FAR PASCAL GetSystemMenu(HWND, BOOL);
+BOOL FAR PASCAL SetSystemMenu(HWND, HMENU); /* ;Internal */
+HMENU FAR PASCAL CreateMenu(void);
+HMENU FAR PASCAL CreatePopupMenu(void);
+BOOL FAR PASCAL DestroyMenu(HMENU);
+BOOL FAR PASCAL CheckMenuItem(HMENU, WORD, WORD);
+BOOL FAR PASCAL EnableMenuItem(HMENU, WORD, WORD);
+HMENU FAR PASCAL GetSubMenu(HMENU, int);
+WORD FAR PASCAL GetMenuItemID(HMENU, int);
+WORD FAR PASCAL GetMenuItemCount(HMENU);
+
+BOOL FAR PASCAL InsertMenu(HMENU, WORD, WORD, WORD, LPSTR);
+BOOL FAR PASCAL AppendMenu(HMENU, WORD, WORD, LPSTR);
+BOOL FAR PASCAL ModifyMenu(HMENU, WORD, WORD, WORD, LPSTR);
+BOOL FAR PASCAL RemoveMenu(HMENU, WORD, WORD);
+BOOL FAR PASCAL DeleteMenu(HMENU, WORD, WORD);
+BOOL FAR PASCAL SetMenuItemBitmaps(HMENU, WORD, WORD, HBITMAP, HBITMAP);
+LONG FAR PASCAL GetMenuCheckMarkDimensions(void);
+
+BOOL FAR PASCAL TrackPopupMenu(HMENU, WORD, int, int, int, HWND, LPRECT);
+/* Flags for TrackPopupMenu */
+#define TPM_RIGHTBUTTON 0x0002
+
+
+#endif /* NOMENUS */
+
+BOOL FAR PASCAL GrayString(HDC, HBRUSH, FARPROC, DWORD, int, int, int, int, int);
+void FAR PASCAL UpdateWindow(HWND);
+HWND FAR PASCAL SetActiveWindow(HWND);
+
+HDC FAR PASCAL BeginPaint(HWND, LPPAINTSTRUCT);
+void FAR PASCAL EndPaint(HWND, LPPAINTSTRUCT);
+BOOL FAR PASCAL GetUpdateRect(HWND, LPRECT, BOOL);
+int FAR PASCAL GetUpdateRgn(HWND, HRGN, BOOL);
+
+int FAR PASCAL ExcludeUpdateRgn(HDC, HWND);
+
+void FAR PASCAL InvalidateRect(HWND, LPRECT, BOOL);
+void FAR PASCAL ValidateRect(HWND, LPRECT);
+
+void FAR PASCAL InvalidateRgn(HWND, HRGN, BOOL);
+void FAR PASCAL ValidateRgn(HWND, HRGN);
+
+void FAR PASCAL ScrollWindow(HWND, int, int, LPRECT, LPRECT);
+BOOL FAR PASCAL ScrollDC(HDC, int, int, LPRECT, LPRECT, HRGN, LPRECT);
+
+#ifndef NOSCROLL
+int FAR PASCAL SetScrollPos(HWND, int, int, BOOL);
+int FAR PASCAL GetScrollPos(HWND, int);
+void FAR PASCAL SetScrollRange(HWND, int, int, int, BOOL);
+void FAR PASCAL GetScrollRange(HWND, int, LPINT, LPINT);
+void FAR PASCAL ShowScrollBar(HWND, WORD, BOOL);
+#endif
+
+BOOL FAR PASCAL SetProp(HWND, LPSTR, HANDLE);
+HANDLE FAR PASCAL GetProp(HWND, LPSTR);
+HANDLE FAR PASCAL RemoveProp(HWND, LPSTR);
+int FAR PASCAL EnumProps(HWND, FARPROC);
+void FAR PASCAL SetWindowText(HWND, LPSTR);
+int FAR PASCAL GetWindowText(HWND, LPSTR, int);
+int FAR PASCAL GetWindowTextLength(HWND);
+
+void FAR PASCAL GetClientRect(HWND, LPRECT);
+void FAR PASCAL GetWindowRect(HWND, LPRECT);
+void FAR PASCAL AdjustWindowRect(LPRECT, LONG, BOOL);
+void FAR PASCAL AdjustWindowRectEx(LPRECT, LONG, BOOL, DWORD);
+
+#ifndef NOMB
+
+/* 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
+
+int FAR PASCAL MessageBox(HWND, LPSTR, LPSTR, WORD);
+void FAR PASCAL MessageBeep(WORD);
+
+#endif /* NOMB */
+
+int FAR PASCAL ShowCursor(BOOL);
+void FAR PASCAL SetCursorPos(int, int);
+HCURSOR FAR PASCAL SetCursor(HCURSOR);
+void FAR PASCAL GetCursorPos(LPPOINT);
+void FAR PASCAL ClipCursor(LPRECT);
+
+void FAR PASCAL CreateCaret(HWND, HBITMAP, int, int);
+WORD FAR PASCAL GetCaretBlinkTime(void);
+void FAR PASCAL SetCaretBlinkTime(WORD);
+void FAR PASCAL DestroyCaret(void);
+void FAR PASCAL HideCaret(HWND);
+void FAR PASCAL ShowCaret(HWND);
+void FAR PASCAL SetCaretPos(int, int);
+void FAR PASCAL GetCaretPos(LPPOINT);
+
+void FAR PASCAL ClientToScreen(HWND, LPPOINT);
+void FAR PASCAL ScreenToClient(HWND, LPPOINT);
+HWND FAR PASCAL WindowFromPoint(POINT);
+HWND FAR PASCAL ChildWindowFromPoint(HWND, POINT);
+
+#ifndef NOCOLOR
+
+/* Color Types */
+#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 /* three bits max */
+
+#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
+#define COLOR_ENDCOLORS COLOR_BTNTEXT
+
+DWORD FAR PASCAL GetSysColor(int);
+void FAR PASCAL SetSysColors(int, LPINT, LONG FAR *);
+
+#endif /* NOCOLOR */
+
+BOOL FAR PASCAL FillRgn(HDC, HRGN, HBRUSH);
+BOOL FAR PASCAL FrameRgn(HDC, HRGN, HBRUSH, int, int);
+BOOL FAR PASCAL InvertRgn(HDC, HRGN);
+BOOL FAR PASCAL PaintRgn(HDC, HRGN);
+BOOL FAR PASCAL PtInRegion(HRGN, int, int);
+
+void FAR PASCAL DrawFocusRect(HDC, LPRECT);
+int FAR PASCAL FillRect(HDC, LPRECT, HBRUSH);
+int FAR PASCAL FrameRect(HDC, LPRECT, HBRUSH);
+void FAR PASCAL InvertRect(HDC, LPRECT);
+void FAR PASCAL SetRect(LPRECT, int, int, int, int);
+void FAR PASCAL SetRectEmpty(LPRECT);
+int FAR PASCAL CopyRect(LPRECT, LPRECT);
+void FAR PASCAL InflateRect(LPRECT, int, int);
+int FAR PASCAL IntersectRect(LPRECT, LPRECT, LPRECT);
+int FAR PASCAL UnionRect(LPRECT, LPRECT, LPRECT);
+void FAR PASCAL OffsetRect(LPRECT, int, int);
+BOOL FAR PASCAL IsRectEmpty(LPRECT);
+BOOL FAR PASCAL EqualRect(LPRECT, LPRECT);
+BOOL FAR PASCAL PtInRect(LPRECT, POINT);
+BOOL FAR PASCAL RectVisible(HDC, LPRECT);
+BOOL FAR PASCAL RectInRegion(HRGN, LPRECT);
+
+DWORD FAR PASCAL GetCurrentTime(void);
+DWORD FAR PASCAL GetTickCount(void);
+DWORD FAR PASCAL GetTimerResolution(void); /* ;Internal */
+
+#ifndef NOWINOFFSETS
+
+WORD FAR PASCAL GetWindowWord(HWND, int);
+WORD FAR PASCAL SetWindowWord(HWND, int, WORD);
+LONG FAR PASCAL GetWindowLong(HWND, int);
+LONG FAR PASCAL SetWindowLong(HWND, int, LONG);
+WORD FAR PASCAL GetClassWord(HWND, int);
+WORD FAR PASCAL SetClassWord(HWND, int, WORD);
+LONG FAR PASCAL GetClassLong(HWND, int);
+LONG FAR PASCAL SetClassLong(HWND, int, LONG);
+HWND FAR PASCAL GetDesktopHwnd(void);
+HWND FAR PASCAL GetDesktopWindow(void);
+
+#endif /* NOWINOFFSETS */
+
+HWND FAR PASCAL GetParent(HWND);
+HWND FAR PASCAL SetParent(HWND, HWND);
+BOOL FAR PASCAL EnumChildWindows(HWND, FARPROC, LONG);
+HWND FAR PASCAL FindWindow(LPSTR, LPSTR);
+BOOL FAR PASCAL EnumWindows(FARPROC, LONG);
+BOOL FAR PASCAL EnumTaskWindows(HANDLE, FARPROC, LONG);
+int FAR PASCAL GetClassName(HWND, LPSTR, int);
+HWND FAR PASCAL GetTopWindow(HWND);
+HWND FAR PASCAL GetNextWindow(HWND, WORD);
+HANDLE FAR PASCAL GetWindowTask(HWND);
+HWND FAR PASCAL GetLastActivePopup(HWND);
+
+/* 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
+
+HWND FAR PASCAL GetWindow(HWND, WORD);
+
+#ifndef NOWH
+FARPROC FAR PASCAL SetWindowsHook(int, FARPROC);
+BOOL FAR PASCAL UnhookWindowsHook(int, FARPROC);
+DWORD FAR PASCAL DefHookProc(int, WORD, DWORD, FARPROC FAR *);
+#endif
+
+#ifndef NOMENUS
+
+/* Menu flags for Add/Check/EnableMenuItem() */
+#define MF_INSERT 0x0000
+#define MF_CHANGE 0x0080
+#define MF_APPEND 0x0100
+#define MF_DELETE 0x0200
+#define MF_REMOVE 0x1000
+
+#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
+
+/* Menu item resource format */
+typedef struct
+ {
+ WORD versionNumber;
+ WORD offset;
+ } MENUITEMTEMPLATEHEADER;
+
+typedef struct
+ {
+ WORD mtOption;
+ WORD mtID;
+ LPSTR mtString;
+ } MENUITEMTEMPLATE;
+
+#define MF_END 0x0080
+
+#endif /* NOMENUS */
+
+#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
+
+#define SC_ICON SC_MINIMIZE
+#define SC_ZOOM SC_MAXIMIZE
+
+#endif /* NOSYSCOMMANDS */
+
+/* Resource Loading Routines */
+HBITMAP FAR PASCAL LoadBitmap(HANDLE, LPSTR);
+HCURSOR FAR PASCAL LoadCursor(HANDLE, LPSTR);
+HCURSOR FAR PASCAL CreateCursor(HANDLE, int, int, int, int, LPSTR, LPSTR);
+BOOL FAR PASCAL DestroyCursor(HCURSOR);
+
+/* Standard Cursor 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)
+
+HICON FAR PASCAL LoadIcon(HANDLE, LPSTR);
+HICON FAR PASCAL CreateIcon(HANDLE, int, int, BYTE, BYTE, LPSTR, LPSTR);
+BOOL FAR PASCAL DestroyIcon(HICON);
+
+
+#define ORD_LANGDRIVER 1 /* The ordinal number for the entry point of
+ ** language drivers.
+ */
+
+#ifndef NOICONS
+
+/* Standard Icon 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 */
+
+int FAR PASCAL LoadString(HANDLE, WORD, LPSTR, int);
+
+int FAR PASCAL AddFontResource(LPSTR);
+BOOL FAR PASCAL RemoveFontResource(LPSTR);
+
+
+/* Key Conversion Window */
+BOOL FAR PASCAL IsTwoByteCharPrefix(char);
+
+/* Dialog Box Command IDs */
+#define IDOK 1
+#define IDCANCEL 2
+#define IDABORT 3
+#define IDRETRY 4
+#define IDIGNORE 5
+#define IDYES 6
+#define IDNO 7
+
+#ifndef NOCTLMGR
+
+/* Control Manager Structures and Definitions */
+
+#ifndef NOWINSTYLES
+
+/* 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
+
+
+#endif /* NOWINSTYLES */
+
+/* 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
+
+#ifndef NOWINMESSAGES
+
+/* Edit Control Messages */
+#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)
+#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)
+#define EM_LINELENGTH (WM_USER+17)
+#define EM_REPLACESEL (WM_USER+18)
+#define EM_SETFONT (WM_USER+19)
+#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)
+#define EM_SETTABSTOPS (WM_USER+27)
+#define EM_SETPASSWORDCHAR (WM_USER+28)
+#define EM_EMPTYUNDOBUFFER (WM_USER+29)
+#define EM_GETFIRSTVISIBLE (WM_USER+30)
+#define EM_MSGMAX (WM_USER+31)
+
+#endif /* NOWINMESSAGES */
+
+/* Button Control Styles */
+#define BS_PUSHBUTTON 0x00L
+#define BS_DEFPUSHBUTTON 0x01L
+#define BS_CHECKBOX 0x02L
+#define BS_AUTOCHECKBOX 0x03L
+#define BS_RADIOBUTTON 0x04L
+#define BS_3STATE 0x05L
+#define BS_AUTO3STATE 0x06L
+#define BS_GROUPBOX 0x07L
+#define BS_USERBUTTON 0x08L
+#define BS_AUTORADIOBUTTON 0x09L
+#define BS_PUSHBOX 0x0AL
+#define BS_OWNERDRAW 0x0BL
+#define BS_LEFTTEXT 0x20L
+
+
+/* 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
+
+/* 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)
+
+/* Static Control Constants */
+#define SS_LEFT 0x00L
+#define SS_CENTER 0x01L
+#define SS_RIGHT 0x02L
+#define SS_ICON 0x03L
+#define SS_BLACKRECT 0x04L
+#define SS_GRAYRECT 0x05L
+#define SS_WHITERECT 0x06L
+#define SS_BLACKFRAME 0x07L
+#define SS_GRAYFRAME 0x08L
+#define SS_WHITEFRAME 0x09L
+#define SS_USERITEM 0x0AL
+#define SS_SIMPLE 0x0BL
+#define SS_LEFTNOWORDWRAP 0x0CL
+#define SS_NOPREFIX 0x80L /* Don't do "&" character translation */
+
+/* Dialog Manager Routines */
+
+#ifndef NOMSG
+BOOL FAR PASCAL IsDialogMessage(HWND, LPMSG);
+#endif
+
+void FAR PASCAL MapDialogRect(HWND, LPRECT);
+
+int FAR PASCAL DlgDirList(HWND, LPSTR, int, int, WORD);
+BOOL FAR PASCAL DlgDirSelectEx(HWND, LPSTR, int);
+int FAR PASCAL DlgDirListComboBox(HWND, LPSTR, int, int, WORD);
+BOOL FAR PASCAL DlgDirSelectComboBoxEx(HWND, LPSTR, int);
+
+
+/* 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 */
+
+#define DM_GETDEFID (WM_USER+0)
+#define DM_SETDEFID (WM_USER+1)
+#define DC_HASDEFID 0x534B
+
+/* Dialog Codes */
+#define DLGC_WANTARROWS 0x0001 /* Control wants arrow keys */
+#define DLGC_WANTTAB 0x0002 /* Control wants tab keys */
+#define DLGC_WANTALLKEYS 0x0004 /* Control wants all keys */
+#define DLGC_WANTMESSAGE 0x0004 /* Pass message to control */
+#define DLGC_HASSETSEL 0x0008 /* Understands EM_SETSEL message */
+#define DLGC_DEFPUSHBUTTON 0x0010 /* Default pushbutton */
+#define DLGC_UNDEFPUSHBUTTON 0x0020 /* Non-default pushbutton */
+#define DLGC_RADIOBUTTON 0x0040 /* Radio button */
+#define DLGC_WANTCHARS 0x0080 /* Want WM_CHAR messages */
+#define DLGC_STATIC 0x0100 /* Static item: don't include */
+#define DLGC_BUTTON 0x2000 /* Button item: can be checked */
+
+#define LB_CTLCODE 0L
+
+/* Listbox Return Values */
+#define LB_OKAY 0
+#define LB_ERR (-1)
+#define LB_ERRSPACE (-2)
+
+/*
+** The idStaticPath parameter to DlgDirList can have the following values
+** ORed if the list box should show other details of the files along with
+** the name of the files;
+*/
+#define LBD_UPPERCASE 0x8001 /* Should the file name be in upper case */ /* ;Internal */
+#define LBD_SIZE 0x8002 /* Should the file size be shown */ /* ;Internal */
+#define LBD_DATE 0x8004 /* Date stamp of the file to be shown ? */ /* ;Internal */
+#define LBD_TIME 0x8008 /* Time stamp of the file to be shown ? */ /* ;Internal */
+#define LBD_ATTRIBUTE 0x8010 /* The dos attributes of the file ? */ /* ;Internal */
+#define LBD_FULLDETAILS 0x801E /* Name, size, date and time */ /* ;Internal */
+#define LBD_SENDDETAILS 0x8020 /* In DlgDirSelectEx(), along with file name */ /* ;Internal */
+ /* all other details also will be returned */
+
+
+/* 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
+
+
+
+#ifndef NOWINMESSAGES
+
+/* Listbox messages */
+#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)
+#define LB_SETITEMHEIGHT (WM_USER+33)
+#define LB_GETITEMHEIGHT (WM_USER+34)
+#define LB_MSGMAX (WM_USER+35)
+
+#endif /* NOWINMESSAGES */
+
+#ifndef NOWINSTYLES
+
+/* Listbox Styles */
+#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)
+
+#endif /* NOWINSTYLES */
+
+
+/* Combo Box return Values */
+#define CB_OKAY 0
+#define CB_ERR (-1)
+#define CB_ERRSPACE (-2)
+
+
+/* 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
+
+/* 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
+#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)
+#define CB_GETDROPPEDCONTROLRECT (WM_USER+18)
+#define CB_MSGMAX (WM_USER+19)
+#endif /* NOWINMESSAGES */
+
+
+
+#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 */
+
+#ifndef NOSOUND
+
+int FAR PASCAL OpenSound(void);
+void FAR PASCAL CloseSound(void);
+int FAR PASCAL SetVoiceQueueSize(int, int);
+int FAR PASCAL SetVoiceNote(int, int, int, int);
+int FAR PASCAL SetVoiceAccent(int, int, int, int, int);
+int FAR PASCAL SetVoiceEnvelope(int, int, int);
+int FAR PASCAL SetSoundNoise(int, int);
+int FAR PASCAL SetVoiceSound(int, LONG, int);
+int FAR PASCAL StartSound(void);
+int FAR PASCAL StopSound(void);
+int FAR PASCAL WaitSoundState(int);
+int FAR PASCAL SyncAllVoices(void);
+int FAR PASCAL CountVoiceNotes(int);
+LPINT FAR PASCAL GetThresholdEvent(void);
+int FAR PASCAL GetThresholdStatus(void);
+int FAR PASCAL SetVoiceThreshold(int, int);
+
+/* WaitSoundState() Constants */
+#define S_QUEUEEMPTY 0
+#define S_THRESHOLD 1
+#define S_ALLTHRESHOLD 2
+
+/* Accent Modes */
+#define S_NORMAL 0
+#define S_LEGATO 1
+#define S_STACCATO 2
+
+/* SetSoundNoise() Sources */
+#define S_PERIOD512 0 /* Freq = N/512 high pitch, less coarse hiss */
+#define S_PERIOD1024 1 /* Freq = N/1024 */
+#define S_PERIOD2048 2 /* Freq = N/2048 low pitch, more coarse hiss */
+#define S_PERIODVOICE 3 /* Source is frequency from voice channel (3) */
+#define S_WHITE512 4 /* Freq = N/512 high pitch, less coarse hiss */
+#define S_WHITE1024 5 /* Freq = N/1024 */
+#define S_WHITE2048 6 /* Freq = N/2048 low pitch, more coarse hiss */
+#define S_WHITEVOICE 7 /* Source is frequency from voice channel (3) */
+
+#define S_SERDVNA (-1) /* Device not available */
+#define S_SEROFM (-2) /* Out of memory */
+#define S_SERMACT (-3) /* Music active */
+#define S_SERQFUL (-4) /* Queue full */
+#define S_SERBDNT (-5) /* Invalid note */
+#define S_SERDLN (-6) /* Invalid note length */
+#define S_SERDCC (-7) /* Invalid note count */
+#define S_SERDTP (-8) /* Invalid tempo */
+#define S_SERDVL (-9) /* Invalid volume */
+#define S_SERDMD (-10) /* Invalid mode */
+#define S_SERDSH (-11) /* Invalid shape */
+#define S_SERDPT (-12) /* Invalid pitch */
+#define S_SERDFQ (-13) /* Invalid frequency */
+#define S_SERDDR (-14) /* Invalid duration */
+#define S_SERDSR (-15) /* Invalid source */
+#define S_SERDST (-16) /* Invalid state */
+
+#endif /* NOSOUND */
+
+#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 /* Ignore signal */
+#define INFINITE 0xFFFF /* Infinite timeout */
+
+/* Error Flags */
+#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_BREAK 0x0010 /* Break Detected */
+#define CE_CTSTO 0x0020 /* CTS Timeout */
+#define CE_DSRTO 0x0040 /* DSR Timeout */
+#define CE_RLSDTO 0x0080 /* RLSD Timeout */
+#define CE_TXFULL 0x0100 /* TX Queue is full */
+#define CE_PTO 0x0200 /* LPTx Timeout */
+#define CE_IOE 0x0400 /* LPTx I/O Error */
+#define CE_DNS 0x0800 /* LPTx Device not selected */
+#define CE_OOP 0x1000 /* LPTx Out-Of-Paper */
+#define CE_MODE 0x8000 /* Requested mode unsupported */
+
+#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 */
+
+/* Events */
+#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 /* Printer error occured */
+
+/* Escape Functions */
+#define SETXOFF 1 /* Simulate XOFF received */
+#define SETXON 2 /* Simulate XON received */
+#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 */
+
+#define LPTx 0x80 /* Set if ID is for LPT device */
+
+typedef struct tagDCB
+ {
+ BYTE Id; /* Internal Device ID */
+ WORD BaudRate; /* Baudrate at which runing */
+ BYTE ByteSize; /* Number of bits/byte, 4-8 */
+ BYTE Parity; /* 0-4=None,Odd,Even,Mark,Space */
+ BYTE StopBits; /* 0,1,2 = 1, 1.5, 2 */
+ WORD RlsTimeout; /* Timeout for RLSD to be set */
+ WORD CtsTimeout; /* Timeout for CTS to be set */
+ WORD DsrTimeout; /* Timeout for DSR to be set */
+
+ 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 */
+
+ 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;
+
+ char XonChar; /* Tx and Rx X-ON character */
+ char XoffChar; /* Tx and Rx X-OFF character */
+ WORD XonLim; /* Transmit X-ON threshold */
+ WORD XoffLim; /* Transmit X-OFF threshold */
+ char PeChar; /* Parity error replacement char */
+ char EofChar; /* End of Input character */
+ char EvtChar; /* Recieved Event character */
+ WORD TxDelay; /* Amount of time between chars */
+ } DCB;
+
+typedef struct tagCOMSTAT
+ {
+ 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 */
+ WORD cbInQue; /* count of characters in Rx Queue */
+ WORD cbOutQue; /* count of characters in Tx Queue */
+ } COMSTAT;
+
+int FAR PASCAL OpenComm(LPSTR, WORD, WORD);
+int FAR PASCAL SetCommState(DCB FAR *);
+int FAR PASCAL GetCommState(int, DCB FAR *);
+int FAR PASCAL ReadComm(int, LPSTR, int);
+int FAR PASCAL UngetCommChar(int, char);
+int FAR PASCAL WriteComm(int, LPSTR, int);
+int FAR PASCAL CloseComm(int);
+int FAR PASCAL GetCommError(int, COMSTAT FAR *);
+int FAR PASCAL BuildCommDCB(LPSTR, DCB FAR *);
+int FAR PASCAL TransmitCommChar(int, char);
+WORD FAR * FAR PASCAL SetCommEventMask(int, WORD);
+WORD FAR PASCAL GetCommEventMask(int, int);
+int FAR PASCAL SetCommBreak(int);
+int FAR PASCAL ClearCommBreak(int);
+int FAR PASCAL FlushComm(int, int);
+int FAR PASCAL EscapeCommFunction(int, int);
+
+#endif /* NOCOMM */
+
+
+#ifndef NODRIVERS
+#define DRV_LOAD 0x0001
+#define DRV_ENABLE 0x0002
+#define DRV_OPEN 0x0003
+#define DRV_CLOSE 0x0004
+#define DRV_DISABLE 0x0005
+#define DRV_FREE 0x0006
+
+LONG FAR PASCAL LoadDriver(LPSTR, LONG);
+LONG FAR PASCAL FreeDriver(HANDLE, LONG, LONG);
+LONG FAR PASCAL SendDriverMessage(HANDLE, WORD, LONG, LONG);
+HANDLE FAR PASCAL OpenDriver(LPSTR, LONG);
+LONG FAR PASCAL CloseDriver(HANDLE, LONG, LONG);
+#endif
+
+
+#ifndef NOMDI
+
+typedef struct tagMDICREATESTRUCT
+ {
+ LPSTR szClass;
+ LPSTR szTitle;
+ HANDLE hOwner;
+ int x,y;
+ int cx,cy;
+ LONG style;
+ LONG lParam; /* app-defined stuff */
+ } MDICREATESTRUCT;
+
+typedef MDICREATESTRUCT FAR * LPMDICREATESTRUCT;
+
+typedef struct tagCLIENTCREATESTRUCT
+ {
+ HANDLE hWindowMenu;
+ WORD idFirstChild;
+ } CLIENTCREATESTRUCT;
+
+typedef CLIENTCREATESTRUCT FAR * LPCLIENTCREATESTRUCT;
+
+LONG FAR PASCAL DefFrameProc(HWND,HWND,WORD,WORD,LONG);
+LONG FAR PASCAL DefMDIChildProc(HWND,WORD,WORD,LONG);
+
+#ifndef NOMSG
+BOOL FAR PASCAL TranslateMDISysAccel(HWND,LPMSG);
+#endif
+
+WORD FAR PASCAL ArrangeIconicWindows(HWND);
+
+#endif /* NOMDI */
+
+#endif /* NOUSER */
+
+#ifndef NOHELP
+
+/* Help engine section. */
+
+/* Commands to pass WinHelp() */
+#define HELP_CONTEXT 0x0001 /* Display topic in ulTopic */
+#define HELP_QUIT 0x0002 /* Terminate help */
+#define HELP_INDEX 0x0003 /* Display index */
+#define HELP_HELPONHELP 0x0004 /* Display help on using help */
+#define HELP_SETINDEX 0x0005 /* Set the current Index for multi index help */
+#define HELP_KEY 0x0101 /* Display topic for keyword in offabData */
+#define HELP_MULTIKEY 0x0201
+
+BOOL FAR PASCAL WinHelp(HWND hwndMain, LPSTR lpszHelp, WORD usCommand, DWORD ulData);
+
+typedef struct tagMULTIKEYHELP
+ {
+ WORD mkSize;
+ BYTE mkKeylist;
+ BYTE szKeyphrase[1];
+ } MULTIKEYHELP;
+
+#endif /* NOHELP */
+
+#ifndef NOPROFILER
+
+/* function declarations for profiler routines contained in Windows libraries */
+int far pascal ProfInsChk(void);
+void far pascal ProfSetup(int,int);
+void far pascal ProfSampRate(int,int);
+void far pascal ProfStart(void);
+void far pascal ProfStop(void);
+void far pascal ProfClear(void);
+void far pascal ProfFlush(void);
+void far pascal ProfFinish(void);
+
+#endif /* NOPROFILER */
+
+#ifndef NODBCS
+
+BOOL FAR PASCAL IsDBCSLeadByte( BYTE );
+
+#endif /* NODBCS */
diff --git a/private/os2/client/thunk/include/windows.inc b/private/os2/client/thunk/include/windows.inc
new file mode 100644
index 000000000..ed2959e2b
--- /dev/null
+++ b/private/os2/client/thunk/include/windows.inc
@@ -0,0 +1,2190 @@
+;*************************************************************************
+;
+; 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_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
+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
+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
+
+; 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
+
+; WEP fSystemExit flag values
+WEP_SYSTEM_EXIT = 1
+WEP_FREE_DLL = 0
+
+; 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_NUMLOCK = 90H
+VK_SCROLL = 91H
+ENDIF
+
+IFNDEF NOWH
+
+; 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_MOUSE = 7
+WH_HARDWARE = 8
+WH_DEBUG = 9
+;
+; 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
+
+;
+; 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
+;
+; 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
+
+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 ;Internal
+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
+WM_GETHOTKEY = 0033h
+WM_FILESYSCHANGE = 0034h ;Internal
+WM_ISACTIVEICON = 0035h ;Internal
+WM_QUERYPARKICON = 0036h ;Internal
+WM_QUERYDRAGICON = 0037h
+WM_COMPAREITEM = 0039h
+WM_TESTING = 0040h ;Internal
+WM_COMPACTING = 0041h
+WM_OTHERWINDOWCREATED = 0042h
+WM_OTHERWINDOWDESTROYED= 0043h
+
+
+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_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
+
+WM_INTERNAL_COALESCE_FIRST equ 03A0h ; Internal
+
+WM_COALESCE_FIRST equ 03A0h
+WM_COALESCE_LAST equ 03AFh
+
+; The following message range reserved ;Internal
+; for multi-media ;Internal
+
+WM_MM_RESERVED_FIRST equ 03B0h ;Internal
+WM_MM_RESERVED_LAST equ 03EFh ;Internal
+
+WM_INTERNAL_COALESCE_LAST equ WM_MM_RESERVED_LAST ;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_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)
+LB_SETITEMHEIGHT = (WM_USER+33)
+LB_GETITEMHEIGHT = (WM_USER+34)
+LB_MSGMAX = (WM_USER+35)
+
+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
+
+; 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)
+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)
+EM_GETFIRSTVISIBLE = (WM_USER+30)
+EM_MSGMAX = (WM_USER+31)
+
+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
+
+; 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
+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)
+CB_GETDROPPEDCONTROLRECT = (WM_USER+18)
+CB_MSGMAX = (WM_USER+19)
+
+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
+SS_SIMPLE = 0Bh
+SS_LEFTNOWORDWRAP = 0Ch
+SS_NOPREFIX = 80h ; Don't do "&" character translation
+
+; 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
+SM_CMETRICS = 36
+
+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
+
+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 */
+
+; 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 */
+
+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
+ \ No newline at end of file
diff --git a/private/os2/client/thunk/include/winerror.h b/private/os2/client/thunk/include/winerror.h
new file mode 100644
index 000000000..5a58eb694
--- /dev/null
+++ b/private/os2/client/thunk/include/winerror.h
@@ -0,0 +1,1778 @@
+//
+//Copyright (c) 1990 Microsoft Corporation
+//
+//Module Name:
+//
+// winerror.h
+//
+//Abstract:
+//
+// This file contains the error code definitions for the Win32 API
+// functions.
+//
+//Author:
+//
+// Steve Wood (stevewo) 25-Jan-1991
+//
+//Notes:
+//
+// This file is generated by the GENMSG tool from the winerror.txt file.
+//
+//Revision History:
+//
+//
+
+//
+// MessageId: ERROR_INVALID_FUNCTION
+//
+// MessageText:
+//
+// Incorrect function
+//
+#define ERROR_INVALID_FUNCTION 1
+
+
+//
+// MessageId: ERROR_FILE_NOT_FOUND
+//
+// MessageText:
+//
+// The system cannot find the file specified.
+//
+#define ERROR_FILE_NOT_FOUND 2
+
+
+//
+// MessageId: ERROR_PATH_NOT_FOUND
+//
+// MessageText:
+//
+// The system cannot find the path specified.
+//
+#define ERROR_PATH_NOT_FOUND 3
+
+
+//
+// MessageId: ERROR_TOO_MANY_OPEN_FILES
+//
+// MessageText:
+//
+// The system cannot open the file.
+//
+#define ERROR_TOO_MANY_OPEN_FILES 4
+
+
+//
+// MessageId: ERROR_ACCESS_DENIED
+//
+// MessageText:
+//
+// Access Denied.
+//
+#define ERROR_ACCESS_DENIED 5
+
+
+//
+// MessageId: ERROR_INVALID_HANDLE
+//
+// MessageText:
+//
+// Incorrect internal file identifier.
+//
+#define ERROR_INVALID_HANDLE 6
+
+
+//
+// MessageId: ERROR_ARENA_TRASHED
+//
+// MessageText:
+//
+// The storage control blocks were destroyed.
+//
+#define ERROR_ARENA_TRASHED 7
+
+
+//
+// MessageId: ERROR_NOT_ENOUGH_MEMORY
+//
+// MessageText:
+//
+// Not enough storage is available to
+// process this command.
+//
+#define ERROR_NOT_ENOUGH_MEMORY 8
+
+
+//
+// MessageId: ERROR_INVALID_BLOCK
+//
+// MessageText:
+//
+// The storage control block address is invalid.
+//
+#define ERROR_INVALID_BLOCK 9
+
+
+//
+// MessageId: ERROR_BAD_ENVIRONMENT
+//
+// MessageText:
+//
+// The environment is incorrect.
+//
+#define ERROR_BAD_ENVIRONMENT 10
+
+
+//
+// MessageId: ERROR_BAD_FORMAT
+//
+// MessageText:
+//
+// An attempt was made to load a program with an
+// incorrect format.
+//
+#define ERROR_BAD_FORMAT 11
+
+
+//
+// MessageId: ERROR_INVALID_ACCESS
+//
+// MessageText:
+//
+// The access code is invalid.
+//
+#define ERROR_INVALID_ACCESS 12
+
+
+//
+// MessageId: ERROR_INVALID_DATA
+//
+// MessageText:
+//
+// The data is invalid.
+//
+#define ERROR_INVALID_DATA 13
+
+
+//
+// MessageId: ERROR_INVALID_DRIVE
+//
+// MessageText:
+//
+// The system cannot find the drive specified.
+//
+#define ERROR_INVALID_DRIVE 15
+
+
+//
+// MessageId: ERROR_CURRENT_DIRECTORY
+//
+// MessageText:
+//
+// The directory cannot be removed.
+//
+#define ERROR_CURRENT_DIRECTORY 16
+
+
+//
+// MessageId: ERROR_NOT_SAME_DEVICE
+//
+// MessageText:
+//
+// The system cannot move the file
+// to a different disk drive.
+//
+#define ERROR_NOT_SAME_DEVICE 17
+
+
+//
+// MessageId: ERROR_NO_MORE_FILES
+//
+// MessageText:
+//
+// There are no more files.
+//
+#define ERROR_NO_MORE_FILES 18
+
+
+//
+// MessageId: ERROR_WRITE_PROTECT
+//
+// MessageText:
+//
+// The diskette is write protected.
+//
+#define ERROR_WRITE_PROTECT 19
+
+
+//
+// MessageId: ERROR_BAD_UNIT
+//
+// MessageText:
+//
+// The system cannot find the device specified.
+//
+#define ERROR_BAD_UNIT 20
+
+
+//
+// MessageId: ERROR_NOT_READY
+//
+// MessageText:
+//
+// The drive is not ready.
+//
+#define ERROR_NOT_READY 21
+
+
+//
+// MessageId: ERROR_BAD_COMMAND
+//
+// MessageText:
+//
+// The device does not recognize the command.
+//
+#define ERROR_BAD_COMMAND 22
+
+
+//
+// MessageId: ERROR_CRC
+//
+// MessageText:
+//
+// Data error (cyclic redundancy check)
+//
+#define ERROR_CRC 23
+
+
+//
+// MessageId: ERROR_BAD_LENGTH
+//
+// MessageText:
+//
+// The program issued a command but the
+// command length is incorrect.
+//
+#define ERROR_BAD_LENGTH 24
+
+
+//
+// MessageId: ERROR_SEEK
+//
+// MessageText:
+//
+// The drive cannot locate a specific
+// area or track on the disk.
+//
+#define ERROR_SEEK 25
+
+
+//
+// MessageId: ERROR_NOT_DOS_DISK
+//
+// MessageText:
+//
+// The specified disk or diskette cannot be accessed.
+//
+#define ERROR_NOT_DOS_DISK 26
+
+
+//
+// MessageId: ERROR_SECTOR_NOT_FOUND
+//
+// MessageText:
+//
+// The drive cannot find the sector requested.
+//
+#define ERROR_SECTOR_NOT_FOUND 27
+
+
+//
+// MessageId: ERROR_OUT_OF_PAPER
+//
+// MessageText:
+//
+// The printer is out of paper.
+//
+#define ERROR_OUT_OF_PAPER 28
+
+
+//
+// MessageId: ERROR_WRITE_FAULT
+//
+// MessageText:
+//
+// The system cannot write to the specified device.
+//
+#define ERROR_WRITE_FAULT 29
+
+
+//
+// MessageId: ERROR_READ_FAULT
+//
+// MessageText:
+//
+// The system cannot read from the specified device.
+//
+#define ERROR_READ_FAULT 30
+
+
+//
+// MessageId: ERROR_GEN_FAILURE
+//
+// MessageText:
+//
+// A device attached to the system is not functioning.
+//
+#define ERROR_GEN_FAILURE 31
+
+
+//
+// MessageId: ERROR_SHARING_VIOLATION
+//
+// MessageText:
+//
+// The process cannot access the file because
+// it is being used by another process.
+//
+#define ERROR_SHARING_VIOLATION 32
+
+
+//
+// MessageId: ERROR_LOCK_VIOLATION
+//
+// MessageText:
+//
+// The process cannot access the file because
+// another process has locked a portion of the file.
+//
+#define ERROR_LOCK_VIOLATION 33
+
+
+//
+// MessageId: ERROR_WRONG_DISK
+//
+// MessageText:
+//
+// The wrong diskette is in the drive.
+// Insert %2 (Volume Serial Number: %3)
+// into drive %1.
+//
+#define ERROR_WRONG_DISK 34
+
+
+//
+// MessageId: ERROR_HANDLE_EOF
+//
+// MessageText:
+//
+// Reached End of File.
+//
+#define ERROR_HANDLE_EOF 38
+
+
+//
+// MessageId: ERROR_HANDLE_DISK_FULL
+//
+// MessageText:
+//
+// The disk is full.
+//
+#define ERROR_HANDLE_DISK_FULL 39
+
+
+//
+// MessageId: ERROR_NOT_SUPPORTED
+//
+// MessageText:
+//
+// The network request is not supported.
+//
+#define ERROR_NOT_SUPPORTED 50
+
+
+//
+// MessageId: ERROR_REM_NOT_LIST
+//
+// MessageText:
+//
+// The remote computer is not available.
+//
+#define ERROR_REM_NOT_LIST 51
+
+
+//
+// MessageId: ERROR_DUP_NAME
+//
+// MessageText:
+//
+// A duplicate name exists on the network.
+//
+#define ERROR_DUP_NAME 52
+
+
+//
+// MessageId: ERROR_BAD_NETPATH
+//
+// MessageText:
+//
+// The network path was not found.
+//
+#define ERROR_BAD_NETPATH 53
+
+
+//
+// MessageId: ERROR_NETWORK_BUSY
+//
+// MessageText:
+//
+// The network is busy.
+//
+#define ERROR_NETWORK_BUSY 54
+
+
+//
+// MessageId: ERROR_DEV_NOT_EXIST
+//
+// MessageText:
+//
+// The specified network resource is no longer
+// available.
+//
+#define ERROR_DEV_NOT_EXIST 55
+
+
+//
+// MessageId: ERROR_TOO_MANY_CMDS
+//
+// MessageText:
+//
+// The network BIOS command limit has been reached.
+//
+#define ERROR_TOO_MANY_CMDS 56
+
+
+//
+// MessageId: ERROR_ADAP_HDW_ERR
+//
+// MessageText:
+//
+// A network adapter hardware error occurred.
+//
+#define ERROR_ADAP_HDW_ERR 57
+
+
+//
+// MessageId: ERROR_BAD_NET_RESP
+//
+// MessageText:
+//
+// The specified server cannot perform the requested
+// operation.
+//
+#define ERROR_BAD_NET_RESP 58
+
+
+//
+// MessageId: ERROR_UNEXP_NET_ERR
+//
+// MessageText:
+//
+// An unexpected network error occurred.
+//
+#define ERROR_UNEXP_NET_ERR 59
+
+
+//
+// MessageId: ERROR_BAD_REM_ADAP
+//
+// MessageText:
+//
+// The remote adapter is not compatible.
+//
+#define ERROR_BAD_REM_ADAP 60
+
+
+//
+// MessageId: ERROR_PRINTQ_FULL
+//
+// MessageText:
+//
+// The printer queue is full.
+//
+#define ERROR_PRINTQ_FULL 61
+
+
+//
+// MessageId: ERROR_NO_SPOOL_SPACE
+//
+// MessageText:
+//
+// Space to store the file waiting to be printed is
+// not available on the server.
+//
+#define ERROR_NO_SPOOL_SPACE 62
+
+
+//
+// MessageId: ERROR_PRINT_CANCELLED
+//
+// MessageText:
+//
+// Your file waiting to be printed was deleted.
+//
+#define ERROR_PRINT_CANCELLED 63
+
+
+//
+// MessageId: ERROR_NETNAME_DELETED
+//
+// MessageText:
+//
+// The specified network name is no longer available.
+//
+#define ERROR_NETNAME_DELETED 64
+
+
+//
+// MessageId: ERROR_NETWORK_ACCESS_DENIED
+//
+// MessageText:
+//
+// Network access is denied.
+//
+#define ERROR_NETWORK_ACCESS_DENIED 65
+
+
+//
+// MessageId: ERROR_BAD_DEV_TYPE
+//
+// MessageText:
+//
+// The network resource type is not correct.
+//
+#define ERROR_BAD_DEV_TYPE 66
+
+
+//
+// MessageId: ERROR_BAD_NET_NAME
+//
+// MessageText:
+//
+// The network name cannot be found.
+//
+#define ERROR_BAD_NET_NAME 67
+
+
+//
+// MessageId: ERROR_TOO_MANY_NAMES
+//
+// MessageText:
+//
+// The name limit for the local computer network
+// adapter card was exceeded.
+//
+#define ERROR_TOO_MANY_NAMES 68
+
+
+//
+// MessageId: ERROR_TOO_MANY_SESS
+//
+// MessageText:
+//
+// The network BIOS session limit was exceeded.
+//
+#define ERROR_TOO_MANY_SESS 69
+
+
+//
+// MessageId: ERROR_SHARING_PAUSED
+//
+// MessageText:
+//
+// The remote server has been paused or is in the
+// process of being started.
+//
+#define ERROR_SHARING_PAUSED 70
+
+
+//
+// MessageId: ERROR_REQ_NOT_ACCEP
+//
+// MessageText:
+//
+// The network request was not accepted.
+//
+#define ERROR_REQ_NOT_ACCEP 71
+
+
+//
+// MessageId: ERROR_REDIR_PAUSED
+//
+// MessageText:
+//
+// The specified printer or disk device has been paused.
+//
+#define ERROR_REDIR_PAUSED 72
+
+
+//
+// MessageId: ERROR_FILE_EXISTS
+//
+// MessageText:
+//
+// The file exists.
+//
+#define ERROR_FILE_EXISTS 80
+
+
+//
+// MessageId: ERROR_CANNOT_MAKE
+//
+// MessageText:
+//
+// The directory or file cannot be created.
+//
+#define ERROR_CANNOT_MAKE 82
+
+
+//
+// MessageId: ERROR_FAIL_I24
+//
+// MessageText:
+//
+// Fail on INT 24
+//
+#define ERROR_FAIL_I24 83
+
+
+//
+// MessageId: ERROR_OUT_OF_STRUCTURES
+//
+// MessageText:
+//
+// Storage to process this request is not available.
+//
+#define ERROR_OUT_OF_STRUCTURES 84
+
+
+//
+// MessageId: ERROR_ALREADY_ASSIGNED
+//
+// MessageText:
+//
+// The local device name is already in use.
+//
+#define ERROR_ALREADY_ASSIGNED 85
+
+
+//
+// MessageId: ERROR_INVALID_PASSWORD
+//
+// MessageText:
+//
+// The specified network password is not correct.
+//
+#define ERROR_INVALID_PASSWORD 86
+
+
+//
+// MessageId: ERROR_INVALID_PARAMETER
+//
+// MessageText:
+//
+// The parameter is incorrect.
+//
+#define ERROR_INVALID_PARAMETER 87
+
+
+//
+// MessageId: ERROR_NET_WRITE_FAULT
+//
+// MessageText:
+//
+// A write fault occurred on the network.
+//
+#define ERROR_NET_WRITE_FAULT 88
+
+
+//
+// MessageId: ERROR_NO_PROC_SLOTS
+//
+// MessageText:
+//
+// The system cannot start another process at
+// this time.
+//
+#define ERROR_NO_PROC_SLOTS 89
+
+
+//
+// MessageId: ERROR_TOO_MANY_SEMAPHORES
+//
+// MessageText:
+//
+// Cannot create another system semaphore.
+//
+#define ERROR_TOO_MANY_SEMAPHORES 100
+
+
+//
+// MessageId: ERROR_EXCL_SEM_ALREADY_OWNED
+//
+// MessageText:
+//
+// The exclusive semaphore is owned by another process.
+//
+#define ERROR_EXCL_SEM_ALREADY_OWNED 101
+
+
+//
+// MessageId: ERROR_SEM_IS_SET
+//
+// MessageText:
+//
+// The semaphore is set and cannot be closed.
+//
+#define ERROR_SEM_IS_SET 102
+
+
+//
+// MessageId: ERROR_TOO_MANY_SEM_REQUESTS
+//
+// MessageText:
+//
+// The semaphore cannot be set again.
+//
+#define ERROR_TOO_MANY_SEM_REQUESTS 103
+
+
+//
+// MessageId: ERROR_INVALID_AT_INTERRUPT_TIME
+//
+// MessageText:
+//
+// Cannot request exclusive semaphores at interrupt time.
+//
+#define ERROR_INVALID_AT_INTERRUPT_TIME 104
+
+
+//
+// MessageId: ERROR_SEM_OWNER_DIED
+//
+// MessageText:
+//
+// The previous ownership of this semaphore has ended.
+//
+#define ERROR_SEM_OWNER_DIED 105
+
+
+//
+// MessageId: ERROR_SEM_USER_LIMIT
+//
+// MessageText:
+//
+// Insert the diskette for drive %1.
+//
+#define ERROR_SEM_USER_LIMIT 106
+
+
+//
+// MessageId: ERROR_DISK_CHANGE
+//
+// MessageText:
+//
+// Program stopped because alternate diskette was not inserted.
+//
+#define ERROR_DISK_CHANGE 107
+
+
+//
+// MessageId: ERROR_DRIVE_LOCKED
+//
+// MessageText:
+//
+// The disk is in use or locked by
+// another process.
+//
+#define ERROR_DRIVE_LOCKED 108
+
+
+//
+// MessageId: ERROR_BROKEN_PIPE
+//
+// MessageText:
+//
+// The pipe has been ended.
+//
+#define ERROR_BROKEN_PIPE 109
+
+
+//
+// MessageId: ERROR_OPEN_FAILED
+//
+// MessageText:
+//
+// The system cannot open the
+// device or file specified.
+//
+#define ERROR_OPEN_FAILED 110
+
+
+//
+// MessageId: ERROR_BUFFER_OVERFLOW
+//
+// MessageText:
+//
+// The file name is too long.
+//
+#define ERROR_BUFFER_OVERFLOW 111
+
+
+//
+// MessageId: ERROR_DISK_FULL
+//
+// MessageText:
+//
+// There is not enough space on the disk.
+//
+#define ERROR_DISK_FULL 112
+
+
+//
+// MessageId: ERROR_NO_MORE_SEARCH_HANDLES
+//
+// MessageText:
+//
+// No more internal file identifiers available.
+//
+#define ERROR_NO_MORE_SEARCH_HANDLES 113
+
+
+//
+// MessageId: ERROR_INVALID_TARGET_HANDLE
+//
+// MessageText:
+//
+// The target internal file identifier is incorrect.
+//
+#define ERROR_INVALID_TARGET_HANDLE 114
+
+
+//
+// MessageId: ERROR_INVALID_CATEGORY
+//
+// MessageText:
+//
+// The IOCTL call made by the application program is
+// not correct.
+//
+#define ERROR_INVALID_CATEGORY 117
+
+
+//
+// MessageId: ERROR_INVALID_VERIFY_SWITCH
+//
+// MessageText:
+//
+// The verify-on-write switch parameter value is not
+// correct.
+//
+#define ERROR_INVALID_VERIFY_SWITCH 118
+
+
+//
+// MessageId: ERROR_BAD_DRIVER_LEVEL
+//
+// MessageText:
+//
+// The system does not support the command requested.
+//
+#define ERROR_BAD_DRIVER_LEVEL 119
+
+
+//
+// MessageId: ERROR_CALL_NOT_IMPLEMENTED
+//
+// MessageText:
+//
+// The Application Program Interface (API) entered
+// will only work in OS/2 mode.
+//
+#define ERROR_CALL_NOT_IMPLEMENTED 120
+
+
+//
+// MessageId: ERROR_SEM_TIMEOUT
+//
+// MessageText:
+//
+// The semaphore timeout period has expired.
+//
+#define ERROR_SEM_TIMEOUT 121
+
+
+//
+// MessageId: ERROR_INSUFFICIENT_BUFFER
+//
+// MessageText:
+//
+// The data area passed to a system call is too
+// small.
+//
+#define ERROR_INSUFFICIENT_BUFFER 122
+
+
+//
+// MessageId: ERROR_INVALID_NAME
+//
+// MessageText:
+//
+// A file name or volume label contains an incorrect character.
+//
+#define ERROR_INVALID_NAME 123
+
+
+//
+// MessageId: ERROR_INVALID_LEVEL
+//
+// MessageText:
+//
+// The system call level is not correct.
+//
+#define ERROR_INVALID_LEVEL 124
+
+
+//
+// MessageId: ERROR_NO_VOLUME_LABEL
+//
+// MessageText:
+//
+// The disk has no volume label.
+//
+#define ERROR_NO_VOLUME_LABEL 125
+
+
+//
+// MessageId: ERROR_MOD_NOT_FOUND
+//
+// MessageText:
+//
+// The specified module could not be found.
+//
+#define ERROR_MOD_NOT_FOUND 126
+
+
+//
+// MessageId: ERROR_PROC_NOT_FOUND
+//
+// MessageText:
+//
+// The specified procedure could not be found.
+//
+#define ERROR_PROC_NOT_FOUND 127
+
+
+//
+// MessageId: ERROR_CHILD_NOT_COMPLETE
+//
+// MessageText:
+//
+// The %1 application cannot be run in Windows mode.
+//
+#define ERROR_CHILD_NOT_COMPLETE 129
+
+
+//
+// MessageId: ERROR_DIRECT_ACCESS_HANDLE
+//
+// MessageText:
+//
+// BUGBUG - message text missing.
+//
+#define ERROR_DIRECT_ACCESS_HANDLE 130
+
+
+//
+// MessageId: ERROR_NEGATIVE_SEEK
+//
+// MessageText:
+//
+// BUGBUG - message text missing.
+//
+#define ERROR_NEGATIVE_SEEK 131
+
+
+//
+// MessageId: ERROR_SEEK_ON_DEVICE
+//
+// MessageText:
+//
+// BUGBUG - message text missing.
+//
+#define ERROR_SEEK_ON_DEVICE 132
+
+
+//
+// MessageId: ERROR_IS_JOIN_TARGET
+//
+// MessageText:
+//
+// A JOIN or SUBST command
+// cannot be used for a drive that
+// contains previously joined drives.
+//
+#define ERROR_IS_JOIN_TARGET 133
+
+
+//
+// MessageId: ERROR_IS_JOINED
+//
+// MessageText:
+//
+// An attempt was made to use a
+// JOIN or SUBST command on a drive that has
+// already been joined.
+//
+#define ERROR_IS_JOINED 134
+
+
+//
+// MessageId: ERROR_IS_SUBSTED
+//
+// MessageText:
+//
+// An attempt was made to use a
+// JOIN or SUBST command on a drive that has
+// already been substituted.
+//
+#define ERROR_IS_SUBSTED 135
+
+
+//
+// MessageId: ERROR_NOT_JOINED
+//
+// MessageText:
+//
+// The system tried to delete
+// the JOIN of a drive that is not joined.
+//
+#define ERROR_NOT_JOINED 136
+
+
+//
+// MessageId: ERROR_NOT_SUBSTED
+//
+// MessageText:
+//
+// The system tried to delete the
+// substitution of a drive that is not substituted.
+//
+#define ERROR_NOT_SUBSTED 137
+
+
+//
+// MessageId: ERROR_JOIN_TO_JOIN
+//
+// MessageText:
+//
+// The system tried to join a drive
+// to a directory on a joined drive.
+//
+#define ERROR_JOIN_TO_JOIN 138
+
+
+//
+// MessageId: ERROR_SUBST_TO_SUBST
+//
+// MessageText:
+//
+// The system tried to substitute a
+// drive to a directory on a substituted drive.
+//
+#define ERROR_SUBST_TO_SUBST 139
+
+
+//
+// MessageId: ERROR_JOIN_TO_SUBST
+//
+// MessageText:
+//
+// The system tried to join a drive to
+// a directory on a substituted drive.
+//
+#define ERROR_JOIN_TO_SUBST 140
+
+
+//
+// MessageId: ERROR_SUBST_TO_JOIN
+//
+// MessageText:
+//
+// The system tried to SUBST a drive
+// to a directory on a joined drive.
+//
+#define ERROR_SUBST_TO_JOIN 141
+
+
+//
+// MessageId: ERROR_BUSY_DRIVE
+//
+// MessageText:
+//
+// The system cannot perform a JOIN or SUBST at this time.
+//
+#define ERROR_BUSY_DRIVE 142
+
+
+//
+// MessageId: ERROR_SAME_DRIVE
+//
+// MessageText:
+//
+// The system cannot join or substitute a
+// drive to or for a directory on the same drive.
+//
+#define ERROR_SAME_DRIVE 143
+
+
+//
+// MessageId: ERROR_DIR_NOT_ROOT
+//
+// MessageText:
+//
+// The directory is not a subdirectory of the root directory.
+//
+#define ERROR_DIR_NOT_ROOT 144
+
+
+//
+// MessageId: ERROR_DIR_NOT_EMPTY
+//
+// MessageText:
+//
+// The directory is not empty.
+//
+#define ERROR_DIR_NOT_EMPTY 145
+
+
+//
+// MessageId: ERROR_IS_SUBST_PATH
+//
+// MessageText:
+//
+// The path specified is being used in
+// a substitute.
+//
+#define ERROR_IS_SUBST_PATH 146
+
+
+//
+// MessageId: ERROR_IS_JOIN_PATH
+//
+// MessageText:
+//
+// Not enough resources are available to
+// process this command.
+//
+#define ERROR_IS_JOIN_PATH 147
+
+
+//
+// MessageId: ERROR_PATH_BUSY
+//
+// MessageText:
+//
+// The path specified cannot be used at this time.
+//
+#define ERROR_PATH_BUSY 148
+
+
+//
+// MessageId: ERROR_IS_SUBST_TARGET
+//
+// MessageText:
+//
+// An attempt was made to join
+// or substitute a drive for which a directory
+// on the drive is the target of a previous
+// substitute.
+//
+#define ERROR_IS_SUBST_TARGET 149
+
+
+//
+// MessageId: ERROR_SYSTEM_TRACE
+//
+// MessageText:
+//
+// System trace information was not specified in your
+// CONFIG.SYS file, or tracing is disallowed.
+//
+#define ERROR_SYSTEM_TRACE 150
+
+
+//
+// MessageId: ERROR_INVALID_EVENT_COUNT
+//
+// MessageText:
+//
+// The number of specified semaphore events for
+// DosMuxSemWait is not correct.
+//
+#define ERROR_INVALID_EVENT_COUNT 151
+
+
+//
+// MessageId: ERROR_TOO_MANY_MUXWAITERS
+//
+// MessageText:
+//
+// DosMuxSemWait did not execute; too many semaphores
+// are already set.
+//
+#define ERROR_TOO_MANY_MUXWAITERS 152
+
+
+//
+// MessageId: ERROR_INVALID_LIST_FORMAT
+//
+// MessageText:
+//
+// The DosMuxSemWait list is not correct.
+//
+#define ERROR_INVALID_LIST_FORMAT 153
+
+
+//
+// MessageId: ERROR_LABEL_TOO_LONG
+//
+// MessageText:
+//
+// The volume label you entered exceeds the
+// 11 character limit. The first 11 characters were written
+// to disk. Any characters that exceeded the 11 character limit
+// were automatically deleted.
+//
+#define ERROR_LABEL_TOO_LONG 154
+
+
+//
+// MessageId: ERROR_TOO_MANY_TCBS
+//
+// MessageText:
+//
+// Cannot create another thread.
+//
+#define ERROR_TOO_MANY_TCBS 155
+
+
+//
+// MessageId: ERROR_SIGNAL_REFUSED
+//
+// MessageText:
+//
+// The recipient process has refused the signal.
+//
+#define ERROR_SIGNAL_REFUSED 156
+
+
+//
+// MessageId: ERROR_DISCARDED
+//
+// MessageText:
+//
+// The segment is already discarded and cannot be locked.
+//
+#define ERROR_DISCARDED 157
+
+
+//
+// MessageId: ERROR_NOT_LOCKED
+//
+// MessageText:
+//
+// The segment is already unlocked.
+//
+#define ERROR_NOT_LOCKED 158
+
+
+//
+// MessageId: ERROR_BAD_THREADID_ADDR
+//
+// MessageText:
+//
+// The address for the thread ID is not correct.
+//
+#define ERROR_BAD_THREADID_ADDR 159
+
+
+//
+// MessageId: ERROR_BAD_ARGUMENTS
+//
+// MessageText:
+//
+// The argument string passed to DosExecPgm is not correct.
+//
+#define ERROR_BAD_ARGUMENTS 160
+
+
+//
+// MessageId: ERROR_BAD_PATHNAME
+//
+// MessageText:
+//
+// Invalid path name specified.
+//
+#define ERROR_BAD_PATHNAME 161
+
+
+//
+// MessageId: ERROR_SIGNAL_PENDING
+//
+// MessageText:
+//
+// A signal is already pending.
+//
+#define ERROR_SIGNAL_PENDING 162
+
+
+//
+// MessageId: ERROR_MAX_THRDS_REACHED
+//
+// MessageText:
+//
+// No more threads can be created in the system.
+//
+#define ERROR_MAX_THRDS_REACHED 164
+
+
+//
+// MessageId: ERROR_LOCK_FAILED
+//
+// MessageText:
+//
+// Attempt to lock a region of a file failed.
+//
+#define ERROR_LOCK_FAILED 167
+
+
+//
+// MessageId: ERROR_BUSY
+//
+// MessageText:
+//
+// The requested resource is in use.
+//
+#define ERROR_BUSY 170
+
+
+//
+// MessageId: ERROR_INVALID_SEGMENT_NUMBER
+//
+// MessageText:
+//
+// The system detected a segment number that was not correct.
+//
+#define ERROR_INVALID_SEGMENT_NUMBER 180
+
+
+//
+// MessageId: ERROR_INVALID_ORDINAL
+//
+// MessageText:
+//
+// The operating system cannot run %1.
+//
+#define ERROR_INVALID_ORDINAL 182
+
+
+//
+// MessageId: ERROR_ALREADY_EXISTS
+//
+// MessageText:
+//
+// Attempt to create file that already exists.
+//
+#define ERROR_ALREADY_EXISTS 183
+
+
+//
+// MessageId: ERROR_INVALID_FLAG_NUMBER
+//
+// MessageText:
+//
+// The flag passed is not correct.
+//
+#define ERROR_INVALID_FLAG_NUMBER 186
+
+
+//
+// MessageId: ERROR_SEM_NOT_FOUND
+//
+// MessageText:
+//
+// The specified system semaphore name was not found.
+//
+#define ERROR_SEM_NOT_FOUND 187
+
+
+//
+// MessageId: ERROR_INVALID_STARTING_CODESEG
+//
+// MessageText:
+//
+// The operating system cannot run %1.
+//
+#define ERROR_INVALID_STARTING_CODESEG 188
+
+
+//
+// MessageId: ERROR_INVALID_STACKSEG
+//
+// MessageText:
+//
+// The operating system cannot run %1.
+//
+#define ERROR_INVALID_STACKSEG 189
+
+
+//
+// MessageId: ERROR_INVALID_MODULETYPE
+//
+// MessageText:
+//
+// The operating system cannot run %1.
+//
+#define ERROR_INVALID_MODULETYPE 190
+
+
+//
+// MessageId: ERROR_INVALID_EXE_SIGNATURE
+//
+// MessageText:
+//
+// %1 cannot be run in OS/2 mode.
+//
+#define ERROR_INVALID_EXE_SIGNATURE 191
+
+
+//
+// MessageId: ERROR_EXE_MARKED_INVALID
+//
+// MessageText:
+//
+// The operating system cannot run %1.
+//
+#define ERROR_EXE_MARKED_INVALID 192
+
+
+//
+// MessageId: ERROR_BAD_EXE_FORMAT
+//
+// MessageText:
+//
+// %1 is not a valid Windows application.
+//
+#define ERROR_BAD_EXE_FORMAT 193
+
+
+//
+// MessageId: ERROR_ITERATED_DATA_EXCEEDS_64k
+//
+// MessageText:
+//
+// The operating system cannot run %1.
+//
+#define ERROR_ITERATED_DATA_EXCEEDS_64k 194
+
+
+//
+// MessageId: ERROR_INVALID_MINALLOCSIZE
+//
+// MessageText:
+//
+// The operating system cannot run %1.
+//
+#define ERROR_INVALID_MINALLOCSIZE 195
+
+
+//
+// MessageId: ERROR_DYNLINK_FROM_INVALID_RING
+//
+// MessageText:
+//
+// The operating system cannot run this
+// application program.
+//
+#define ERROR_DYNLINK_FROM_INVALID_RING 196
+
+
+//
+// MessageId: ERROR_IOPL_NOT_ENABLED
+//
+// MessageText:
+//
+// The operating system is not presently
+// configured to run this application.
+//
+#define ERROR_IOPL_NOT_ENABLED 197
+
+
+//
+// MessageId: ERROR_INVALID_SEGDPL
+//
+// MessageText:
+//
+// The operating system cannot run %1.
+//
+#define ERROR_INVALID_SEGDPL 198
+
+
+//
+// MessageId: ERROR_AUTODATASEG_EXCEEDS_64k
+//
+// MessageText:
+//
+// The operating system cannot run this
+// application program.
+//
+#define ERROR_AUTODATASEG_EXCEEDS_64k 199
+
+
+//
+// MessageId: ERROR_RING2SEG_MUST_BE_MOVABLE
+//
+// MessageText:
+//
+// The code segment cannot be greater than or equal to 64KB.
+//
+#define ERROR_RING2SEG_MUST_BE_MOVABLE 200
+
+
+//
+// MessageId: ERROR_RELOC_CHAIN_XEEDS_SEGLIM
+//
+// MessageText:
+//
+// The operating system cannot run %1.
+//
+#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201
+
+
+//
+// MessageId: ERROR_INFLOOP_IN_RELOC_CHAIN
+//
+// MessageText:
+//
+// The operating system cannot run %1.
+//
+#define ERROR_INFLOOP_IN_RELOC_CHAIN 202
+
+
+//
+// MessageId: ERROR_ENVVAR_NOT_FOUND
+//
+// MessageText:
+//
+// The system could not find the environment
+// option that was entered.
+//
+#define ERROR_ENVVAR_NOT_FOUND 203
+
+
+//
+// MessageId: ERROR_NO_SIGNAL_SENT
+//
+// MessageText:
+//
+// No process in the command subtree has a
+// signal handler.
+//
+#define ERROR_NO_SIGNAL_SENT 205
+
+
+//
+// MessageId: ERROR_FILENAME_EXCED_RANGE
+//
+// MessageText:
+//
+// The file name or extension is too long.
+//
+#define ERROR_FILENAME_EXCED_RANGE 206
+
+
+//
+// MessageId: ERROR_RING2_STACK_IN_USE
+//
+// MessageText:
+//
+// The ring 2 stack is in use.
+//
+#define ERROR_RING2_STACK_IN_USE 207
+
+
+//
+// MessageId: ERROR_META_EXPANSION_TOO_LONG
+//
+// MessageText:
+//
+// The global file name characters, * or ? are entered
+// incorrectly or too many global file name characters are specified.
+//
+#define ERROR_META_EXPANSION_TOO_LONG 208
+
+
+//
+// MessageId: ERROR_INVALID_SIGNAL_NUMBER
+//
+// MessageText:
+//
+// The signal being posted is not correct.
+//
+#define ERROR_INVALID_SIGNAL_NUMBER 209
+
+
+//
+// MessageId: ERROR_THREAD_1_INACTIVE
+//
+// MessageText:
+//
+// The signal handler cannot be set.
+//
+#define ERROR_THREAD_1_INACTIVE 210
+
+
+//
+// MessageId: ERROR_LOCKED
+//
+// MessageText:
+//
+// The segment is locked and cannot be reallocated.
+//
+#define ERROR_LOCKED 212
+
+
+//
+// MessageId: ERROR_TOO_MANY_MODULES
+//
+// MessageText:
+//
+// Too many dynamic link modules are attached to this
+// program or dynamic link module.
+//
+#define ERROR_TOO_MANY_MODULES 214
+
+
+//
+// MessageId: ERROR_MORE_DATA
+//
+// MessageText:
+//
+// More data is available.
+//
+#define ERROR_MORE_DATA 234
+
+
+//
+// MessageId: ERROR_NO_MORE_ITEMS
+//
+// MessageText:
+//
+// No more data is available.
+//
+#define ERROR_NO_MORE_ITEMS 259
+
+
+
+//
+// MessageId: ERROR_DIRECTORY
+//
+// MessageText:
+//
+// Invalid directory name.
+//
+#define ERROR_DIRECTORY 267
+
+
+//
+// MessageId: ERROR_EAS_NOT_SUPPORTED
+//
+// MessageText:
+//
+// The mounted file system does not support extended attributes.
+//
+#define ERROR_EAS_NOT_SUPPORTED 282
+
+
+//
+// MessageId: ERROR_NOT_OWNER
+//
+// MessageText:
+//
+// Attempt to release mutex not owned by caller.
+//
+#define ERROR_NOT_OWNER 288
+
+
+//
+// MessageId: ERROR_TOO_MANY_POSTS
+//
+// MessageText:
+//
+// Too many posts were made to a semaphore.
+//
+#define ERROR_TOO_MANY_POSTS 298
+
+
+//
+// MessageId: ERROR_MR_MID_NOT_FOUND
+//
+// MessageText:
+//
+// The system cannot find message for message number 0x%1
+// in message file for %2.
+//
+#define ERROR_MR_MID_NOT_FOUND 317
+
+
+//
+// MessageId: ERROR_INVALID_ADDRESS
+//
+// MessageText:
+//
+// Attempt to access invalid address.
+//
+#define ERROR_INVALID_ADDRESS 487
+
+
+//
+// MessageId: ERROR_ARITHMETIC_OVERFLOW
+//
+// MessageText:
+//
+// Arithmatic result exceeded 32-bits.
+//
+#define ERROR_ARITHMETIC_OVERFLOW 534
+
+
+
+//
+// MessageId: ERROR_NOACCESS
+//
+// MessageText:
+//
+// Invalid access to memory location.
+//
+#define ERROR_NOACCESS 998
+
+
+//
+// MessageId: ERROR_SWAPERROR
+//
+// MessageText:
+//
+// Error accessing paging file.
+//
+#define ERROR_SWAPERROR 999
+
diff --git a/private/os2/client/thunk/include/winexp.h b/private/os2/client/thunk/include/winexp.h
new file mode 100644
index 000000000..04bc0533a
--- /dev/null
+++ b/private/os2/client/thunk/include/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 FAR PASCAL lstrbscan(LPSTR, LPSTR);
+LPSTR FAR PASCAL lstrbskip(LPSTR, LPSTR);
+
+int FAR PASCAL OpenPathName(LPSTR, int);
+int FAR PASCAL DeletePathName(LPSTR);
+WORD FAR PASCAL _ldup(int);
+
+
+/* scheduler things that the world knows not */
+BOOL far PASCAL WaitEvent( HANDLE );
+BOOL far PASCAL PostEvent( HANDLE );
+BOOL far PASCAL KillTask( HANDLE );
+
+/* print screen hooks */
+BOOL FAR PASCAL SetPrtScHook(FARPROC);
+FARPROC FAR PASCAL 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
+
+/* module stuff */
+HANDLE FAR PASCAL GetDSModule( WORD );
+HANDLE FAR PASCAL GetDSInstance( WORD );
+
+
diff --git a/private/os2/client/thunk/include/wingdi.h b/private/os2/client/thunk/include/wingdi.h
new file mode 100644
index 000000000..82f6f4aaf
--- /dev/null
+++ b/private/os2/client/thunk/include/wingdi.h
@@ -0,0 +1,1030 @@
+/****************************** Module Header ******************************\
+* Module Name: wingdi.h
+*
+* Copyright (c) 1985-91, Microsoft Corporation
+*
+* Procedure declarations, constant definitions and macros for the GDI
+* component.
+*
+* History:
+* 09-20-90 DarrinM Created.
+\***************************************************************************/
+
+#ifndef _WINGDI_
+#define _WINGDI_
+
+#ifndef NOGDI
+
+#ifndef NORASTEROPS
+
+/* Binary raster ops */
+#define R2_BLACK 1 /* 0 */
+#define R2_NOTMERGEPEN 2 /* DPon */
+#define R2_MASKNOTPEN 3 /* DPna */
+#define R2_NOTCOPYPEN 4 /* PN */
+#define R2_MASKPENNOT 5 /* PDna */
+#define R2_NOT 6 /* Dn */
+#define R2_XORPEN 7 /* DPx */
+#define R2_NOTMASKPEN 8 /* DPan */
+#define R2_MASKPEN 9 /* DPa */
+#define R2_NOTXORPEN 10 /* DPxn */
+#define R2_NOP 11 /* D */
+#define R2_MERGENOTPEN 12 /* DPno */
+#define R2_COPYPEN 13 /* P */
+#define R2_MERGEPENNOT 14 /* PDno */
+#define R2_MERGEPEN 15 /* DPo */
+#define R2_WHITE 16 /* 1 */
+
+/* Ternary raster operations */
+#define SRCCOPY (DWORD)0x00CC0020 /* dest = source */
+#define SRCPAINT (DWORD)0x00EE0086 /* dest = source OR dest */
+#define SRCAND (DWORD)0x008800C6 /* dest = source AND dest */
+#define SRCINVERT (DWORD)0x00660046 /* dest = source XOR dest */
+#define SRCERASE (DWORD)0x00440328 /* dest = source AND (NOT dest ) */
+#define NOTSRCCOPY (DWORD)0x00330008 /* dest = (NOT source) */
+#define NOTSRCERASE (DWORD)0x001100A6 /* dest = (NOT src) AND (NOT dest) */
+#define MERGECOPY (DWORD)0x00C000CA /* dest = (source AND pattern) */
+#define MERGEPAINT (DWORD)0x00BB0226 /* dest = (NOT source) OR dest */
+#define PATCOPY (DWORD)0x00F00021 /* dest = pattern */
+#define PATPAINT (DWORD)0x00FB0A09 /* dest = DPSnoo */
+#define PATINVERT (DWORD)0x005A0049 /* dest = pattern XOR dest */
+#define DSTINVERT (DWORD)0x00550009 /* dest = (NOT dest) */
+#define BLACKNESS (DWORD)0x00000042 /* dest = BLACK */
+#define WHITENESS (DWORD)0x00FF0062 /* dest = WHITE */
+#endif /* NORASTEROPS */
+
+/* Region Flags */
+#define ERROR 0
+#define NULLREGION 1
+#define SIMPLEREGION 2
+#define COMPLEXREGION 3
+
+/* CombineRgn() Styles */
+#define RGN_AND 1
+#define RGN_OR 2
+#define RGN_XOR 3
+#define RGN_DIFF 4
+#define RGN_COPY 5
+
+/* StretchBlt() Modes */
+#define BLACKONWHITE 0
+#define WHITEONBLACK 1
+#define COLORONCOLOR 2
+#define BLEND 3
+#define HALFTONE 4
+#define MAXSTRETCHBLTMODE 4
+
+/* PolyFill() Modes */
+#define ALTERNATE 1
+#define WINDING 2
+
+/* Text Alignment Options */
+#define TA_NOUPDATECP 0
+#define TA_UPDATECP 1
+
+#define TA_LEFT 0
+#define TA_RIGHT 2
+#define TA_CENTER 6
+
+#define TA_TOP 0
+#define TA_BOTTOM 8
+#define TA_BASELINE 24
+
+#define ETO_GRAYED 1
+#define ETO_OPAQUE 2
+#define ETO_CLIPPED 4
+
+#define ASPECT_FILTERING 0x0001
+
+#ifndef NOMETAFILE
+
+/* 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 0x0400
+#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_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
+
+#endif /* NOMETAFILE */
+
+/* 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 SETENDCAP 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 GETEXTENDEDTEXTMETRICS 256
+#define GETEXTENTTABLE 257
+#define GETPAIRKERNTABLE 258
+#define GETTRACKKERNTABLE 259
+#define EXTTEXTOUT 512
+#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
+#define SET_MIRROR_MODE 4110
+
+/* 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
+
+/* Object Definitions for EnumObjects() */
+#define OBJ_PEN 1
+#define OBJ_BRUSH 2
+
+/* xform stuff */
+#define MWT_IDENTITY 1
+#define MWT_LEFTMULTIPLY 2
+#define MWT_RIGHTMULTIPLY 3
+
+typedef struct tagXFORM
+ {
+ FLOAT eM11;
+ FLOAT eM12;
+ FLOAT eM21;
+ FLOAT eM22;
+ FLOAT eDx;
+ FLOAT eDy;
+ } XFORM;
+typedef XFORM *PXFORM;
+
+/* Bitmap Header Definition */
+typedef struct tagBITMAP
+ {
+ DWORD bmType;
+ DWORD bmWidth;
+ DWORD bmHeight;
+ DWORD bmWidthBytes;
+ LPSTR bmBits;
+ BYTE bmPlanes;
+ BYTE bmBitsPixel;
+ } BITMAP;
+
+typedef BITMAP *PBITMAP;
+typedef BITMAP NEAR *NPBITMAP;
+typedef BITMAP FAR *LPBITMAP;
+
+typedef struct tagRGBTRIPLE {
+ BYTE rgbtBlue;
+ BYTE rgbtGreen;
+ BYTE rgbtRed;
+} RGBTRIPLE;
+
+typedef struct tagRGBQUAD {
+ BYTE rgbBlue;
+ BYTE rgbGreen;
+ BYTE rgbRed;
+ BYTE rgbReserved;
+} RGBQUAD;
+
+/* structures for defining DIBs */
+typedef struct tagBITMAPCOREHEADER {
+ DWORD bcSize; /* used to get to color table */
+ WORD bcWidth;
+ WORD bcHeight;
+ WORD bcPlanes;
+ WORD bcBitCount;
+} BITMAPCOREHEADER;
+typedef BITMAPCOREHEADER FAR *LPBITMAPCOREHEADER;
+typedef BITMAPCOREHEADER *PBITMAPCOREHEADER;
+
+
+typedef struct tagBITMAPINFOHEADER{
+ 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;
+
+/* 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 FAR *LPBITMAPINFO;
+typedef BITMAPINFO *PBITMAPINFO;
+
+typedef struct tagBITMAPCOREINFO {
+ BITMAPCOREHEADER bmciHeader;
+ RGBTRIPLE bmciColors[1];
+} BITMAPCOREINFO;
+typedef BITMAPCOREINFO FAR *LPBITMAPCOREINFO;
+typedef BITMAPCOREINFO *PBITMAPCOREINFO;
+
+typedef struct tagBITMAPFILEHEADER {
+ WORD bfType;
+ DWORD bfSize;
+ WORD bfReserved1;
+ WORD bfReserved2;
+ DWORD bfOffBits;
+} BITMAPFILEHEADER;
+typedef BITMAPFILEHEADER FAR *LPBITMAPFILEHEADER;
+typedef BITMAPFILEHEADER *PBITMAPFILEHEADER;
+
+
+#define MAKEPOINT(l) (*((POINT FAR *)&(l)))
+#define MAKEPOINTS(l) (*((POINTS FAR *)&(l)))
+
+#ifndef NOMETAFILE
+
+/* Clipboard Metafile Picture Structure */
+typedef struct tagHANDLETABLE
+ {
+ HANDLE objectHandle[1];
+ } HANDLETABLE;
+typedef HANDLETABLE *PHANDLETABLE;
+typedef HANDLETABLE FAR *LPHANDLETABLE;
+
+typedef struct tagMETARECORD
+ {
+ DWORD rdSize;
+ WORD rdFunction;
+ WORD rdParm[1];
+ } METARECORD;
+typedef METARECORD *PMETARECORD;
+typedef METARECORD FAR *LPMETARECORD;
+
+typedef struct tagMETAFILEPICT
+ {
+ DWORD mm;
+ DWORD xExt;
+ DWORD yExt;
+ HANDLE hMF;
+ } METAFILEPICT;
+typedef METAFILEPICT FAR *LPMETAFILEPICT;
+
+typedef struct tagMETAHEADER
+{
+ WORD mtType;
+ WORD mtHeaderSize;
+ WORD mtVersion;
+ DWORD mtSize;
+ WORD mtNoObjects;
+ DWORD mtMaxRecord;
+ WORD mtNoParameters;
+} METAHEADER;
+
+#endif /* NOMETAFILE */
+
+#ifndef NOTEXTMETRIC
+
+typedef struct tagTEXTMETRIC
+ {
+ DWORD tmHeight;
+ DWORD tmAscent;
+ DWORD tmDescent;
+ DWORD tmInternalLeading;
+ DWORD tmExternalLeading;
+ DWORD tmAveCharWidth;
+ DWORD tmMaxCharWidth;
+ DWORD tmWeight;
+ DWORD tmOverhang;
+ DWORD tmDigitizedAspectX;
+ DWORD tmDigitizedAspectY;
+ BYTE tmItalic;
+ BYTE tmUnderlined;
+ BYTE tmStruckOut;
+ BYTE tmFirstChar;
+ BYTE tmLastChar;
+ BYTE tmDefaultChar;
+ BYTE tmBreakChar;
+ BYTE tmPitchAndFamily;
+ BYTE tmCharSet;
+ } TEXTMETRIC;
+typedef TEXTMETRIC *PTEXTMETRIC;
+typedef TEXTMETRIC NEAR *NPTEXTMETRIC;
+typedef TEXTMETRIC FAR *LPTEXTMETRIC;
+
+#endif /* NOTEXTMETRIC */
+
+/* GDI Logical Objects: */
+
+/* Pel Array */
+typedef struct tagPELARRAY
+ {
+ DWORD paXCount;
+ DWORD paYCount;
+ DWORD paXExt;
+ DWORD paYExt;
+ BYTE paRGBs;
+ } PELARRAY;
+typedef PELARRAY *PPELARRAY;
+typedef PELARRAY NEAR *NPPELARRAY;
+typedef PELARRAY FAR *LPPELARRAY;
+
+/* Logical Brush (or Pattern) */
+typedef struct tagLOGBRUSH
+ {
+ DWORD lbStyle;
+ DWORD lbColor;
+ DWORD 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;
+
+/* Logical Pen */
+typedef struct tagLOGPEN
+ {
+ DWORD lopnStyle;
+ POINT lopnWidth;
+ DWORD lopnColor;
+ } LOGPEN;
+typedef LOGPEN *PLOGPEN;
+typedef LOGPEN NEAR *NPLOGPEN;
+typedef LOGPEN FAR *LPLOGPEN;
+
+typedef struct tagPALETTEENTRY {
+ BYTE peRed;
+ BYTE peGreen;
+ BYTE peBlue;
+ BYTE peFlags;
+} PALETTEENTRY;
+
+typedef PALETTEENTRY *PPALETTEENTRY;
+typedef PALETTEENTRY FAR *LPPALETTEENTRY;
+
+/* Logical Palette */
+typedef struct tagLOGPALETTE {
+ WORD palVersion;
+ WORD palNumEntries;
+ PALETTEENTRY palPalEntry[1];
+} LOGPALETTE;
+typedef LOGPALETTE *PLOGPALETTE;
+typedef LOGPALETTE NEAR *NPLOGPALETTE;
+typedef LOGPALETTE FAR *LPLOGPALETTE;
+
+
+/* Logical Font */
+#define LF_FACESIZE 32
+
+typedef struct tagLOGFONT
+ {
+ SHORT lfHeight;
+ SHORT lfWidth;
+ SHORT lfEscapement;
+ SHORT lfOrientation;
+ SHORT lfWeight;
+ BYTE lfItalic;
+ BYTE lfUnderline;
+ BYTE lfStrikeOut;
+ BYTE lfCharSet;
+ BYTE lfOutPrecision;
+ BYTE lfClipPrecision;
+ BYTE lfQuality;
+ BYTE lfPitchAndFamily;
+ BYTE lfFaceName[LF_FACESIZE];
+ } LOGFONT;
+typedef LOGFONT *PLOGFONT;
+typedef LOGFONT NEAR *NPLOGFONT;
+typedef LOGFONT FAR *LPLOGFONT;
+
+#define OUT_DEFAULT_PRECIS 0
+#define OUT_STRING_PRECIS 1
+#define OUT_CHARACTER_PRECIS 2
+#define OUT_STROKE_PRECIS 3
+
+#define CLIP_DEFAULT_PRECIS 0
+#define CLIP_CHARACTER_PRECIS 1
+#define CLIP_STROKE_PRECIS 2
+
+#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 SYMBOL_CHARSET 2
+#define SHIFTJIS_CHARSET 128
+#define OEM_CHARSET 255
+
+/* 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 */
+#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
+
+/* EnumFonts Masks */
+#define RASTER_FONTTYPE 0x0001
+#define DEVICE_FONTTYPE 0X0002
+
+#define RGB(r,g,b) ((DWORD)(((BYTE)(r)|((WORD)(g)<<8))|(((DWORD)(BYTE)(b))<<16)))
+#define PALETTERGB(r,g,b) (0x04000000 | RGB(r,g,b))
+#define PALETTEINDEX(i) ((DWORD)(0x02000000 | (WORD)(i)))
+
+/* 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 0x10 /* do not match color to system palette */
+
+#define GetRValue(rgb) ((BYTE)(rgb))
+#define GetGValue(rgb) ((BYTE)(((WORD)(rgb)) >> 8))
+#define GetBValue(rgb) ((BYTE)((rgb)>>16))
+
+/* Background Modes */
+#define TRANSPARENT 1
+#define OPAQUE 2
+
+/* Mapping 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
+
+/* Coordinate Modes */
+#define ABSOLUTE 1
+#define RELATIVE 2
+
+/* Stock Logical Objects */
+#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
+#define WHITE_PEN 6
+#define BLACK_PEN 7
+#define NULL_PEN 8
+#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
+
+#define CLR_INVALID 0x80000000
+
+/* 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 /* xxxxx */
+
+/* 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
+
+/* Device Parameters for GetDeviceCaps() */
+#define DRIVERVERSION 0 /* Device driver version */
+#define TECHNOLOGY 2 /* Device classification */
+#define HORZSIZE 4 /* Horizontal size in millimeters */
+#define VERTSIZE 6 /* Vertical size in millimeters */
+#define HORZRES 8 /* Horizontal width in pixels */
+#define VERTRES 10 /* Vertical width in pixels */
+#define BITSPIXEL 12 /* Number of bits per pixel */
+#define PLANES 14 /* Number of planes */
+#define NUMBRUSHES 16 /* Number of brushes the device has */
+#define NUMPENS 18 /* Number of pens the device has */
+#define NUMMARKERS 20 /* Number of markers the device has */
+#define NUMFONTS 22 /* Number of fonts the device has */
+#define NUMCOLORS 24 /* Number of colors the device supports */
+#define PDEVICESIZE 26 /* Size required for device descriptor */
+#define CURVECAPS 28 /* Curve capabilities */
+#define LINECAPS 30 /* Line capabilities */
+#define POLYGONALCAPS 32 /* Polygonal capabilities */
+#define TEXTCAPS 34 /* Text capabilities */
+#define CLIPCAPS 36 /* Clipping capabilities */
+#define RASTERCAPS 38 /* Bitblt capabilities */
+#define ASPECTX 40 /* Length of the X leg */
+#define ASPECTY 42 /* Length of the Y leg */
+#define ASPECTXY 44 /* Length of the hypotenuse */
+
+#define LOGPIXELSX 88 /* Logical pixels/inch in X */
+#define LOGPIXELSY 90 /* Logical pixels/inch in Y */
+
+#define SIZEPALETTE 104 /* Number of entries in physical palette */
+#define NUMRESERVED 106 /* Number of reserved entries in palette */
+#define COLORRES 108 /* Actual color resolution */
+
+#ifndef NOGDICAPMASKS
+
+/* Device Capability Masks: */
+
+/* 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 0 /* Curves not supported */
+#define CC_CIRCLES 1 /* Can do circles */
+#define CC_PIE 2 /* Can do pie wedges */
+#define CC_CHORD 4 /* Can do chord arcs */
+#define CC_ELLIPSES 8 /* Can do ellipese */
+#define CC_WIDE 16 /* Can do wide lines */
+#define CC_STYLED 32 /* Can do styled lines */
+#define CC_WIDESTYLED 64 /* Can do wide styled lines */
+#define CC_INTERIORS 128 /* Can do interiors */
+
+/* Line Capabilities */
+#define LC_NONE 0 /* Lines not supported */
+#define LC_POLYLINE 2 /* Can do polylines */
+#define LC_MARKER 4 /* Can do markers */
+#define LC_POLYMARKER 8 /* Can do polymarkers */
+#define LC_WIDE 16 /* Can do wide lines */
+#define LC_STYLED 32 /* Can do styled lines */
+#define LC_WIDESTYLED 64 /* Can do wide styled lines */
+#define LC_INTERIORS 128 /* Can do interiors */
+
+/* Polygonal Capabilities */
+#define PC_NONE 0 /* Polygonals not supported */
+#define PC_POLYGON 1 /* Can do polygons */
+#define PC_RECTANGLE 2 /* Can do rectangles */
+#define PC_WINDPOLYGON 4 /* Can do winding polygons */
+#define PC_TRAPEZOID 4 /* Can do trapezoids */
+#define PC_SCANLINE 8 /* Can do scanlines */
+#define PC_WIDE 16 /* Can do wide borders */
+#define PC_STYLED 32 /* Can do styled borders */
+#define PC_WIDESTYLED 64 /* Can do wide styled borders */
+#define PC_INTERIORS 128 /* Can do interiors */
+
+/* Polygonal Capabilities */
+#define CP_NONE 0 /* No clipping of output */
+#define CP_RECTANGLE 1 /* Output clipped to rects */
+
+/* Text Capabilities */
+#define TC_OP_CHARACTER 0x0001 /* Can do OutputPrecision CHARACTER */
+#define TC_OP_STROKE 0x0002 /* Can do OutputPrecision STROKE */
+#define TC_CP_STROKE 0x0004 /* Can do ClipPrecision STROKE */
+#define TC_CR_90 0x0008 /* Can do CharRotAbility 90 */
+#define TC_CR_ANY 0x0010 /* Can do CharRotAbility ANY */
+#define TC_SF_X_YINDEP 0x0020 /* Can do ScaleFreedom X_YINDEPENDENT */
+#define TC_SA_DOUBLE 0x0040 /* Can do ScaleAbility DOUBLE */
+#define TC_SA_INTEGER 0x0080 /* Can do ScaleAbility INTEGER */
+#define TC_SA_CONTIN 0x0100 /* Can do ScaleAbility CONTINUOUS */
+#define TC_EA_DOUBLE 0x0200 /* Can do EmboldenAbility DOUBLE */
+#define TC_IA_ABLE 0x0400 /* Can do ItalisizeAbility ABLE */
+#define TC_UA_ABLE 0x0800 /* Can do UnderlineAbility ABLE */
+#define TC_SO_ABLE 0x1000 /* Can do StrikeOutAbility ABLE */
+#define TC_RA_ABLE 0x2000 /* Can do RasterFontAble ABLE */
+#define TC_VA_ABLE 0x4000 /* Can do VectorFontAble ABLE */
+#define TC_RESERVED 0x8000
+
+#endif /* NOGDICAPMASKS */
+
+/* Raster Capabilities */
+#define RC_BITBLT 1 /* Can do standard BLT. */
+#define RC_BANDING 2 /* Device requires banding support */
+#define RC_SCALING 4 /* Device requires scaling support */
+#define RC_BITMAP64 8 /* Device can support >64K bitmap */
+#define RC_GDI20_OUTPUT 0x0010 /* has 2.0 output calls */
+#define RC_DI_BITMAP 0x0080 /* supports DIB to memory */
+#define RC_PALETTE 0x0100 /* supports a palette */
+#define RC_DIBTODEV 0x0200 /* supports DIBitsToDevice */
+#define RC_BIGFONT 0x0400 /* supports >64K fonts */
+#define RC_STRETCHBLT 0x0800 /* supports StretchBlt */
+#define RC_FLOODFILL 0x1000 /* supports FloodFill */
+#define RC_STRETCHDIB 0x2000 /* supports StretchDIBits */
+
+/* DIB color table identifiers */
+
+#define DIB_RGB_COLORS 0 /* color table in RGBTriples */
+#define DIB_PAL_COLORS 1 /* color table in palette indices */
+#define DIB_PAL_INDICES 2 /* no color table, the indices are in */
+ /* the DC the bitmap will be selected into */
+
+
+/* constants for Get/SetSystemPaletteUse() */
+
+#define SYSPAL_STATIC 1
+#define SYSPAL_NOSTATIC 2
+
+/* constants for CreateDIBitmap */
+#define CBM_INIT 0x04L /* initialize bitmap */
+
+#ifndef NODRAWTEXT
+
+/* DrawText() Format Flags */
+#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
+
+#endif /* NODRAWTEXT */
+
+/* ExtFloodFill style flags */
+#define FLOODFILLBORDER 0
+#define FLOODFILLSURFACE 1
+
+typedef struct _devicemode {
+ char dmDeviceName[32];
+ WORD dmSpecVersion;
+ WORD dmDriverVersion;
+ WORD dmSize;
+ WORD dmDriverExtra;
+ DWORD dmFields;
+ short dmOrientation;
+ short dmPaperSize;
+ short dmPaperLength;
+ short dmPaperWidth;
+ short dmScale;
+ short dmCopies;
+ short dmDefaultSource;
+ short dmPrintQuality;
+ short dmColor;
+ short dmDuplex;
+} DEVMODE, *PDEVMODE, *NPDEVMODE, *LPDEVMODE;
+
+int APIENTRY AddFontResource(IN LPSTR);
+int APIENTRY AddFontModule(IN HMODULE);
+BOOL APIENTRY AnimatePalette(IN HPALETTE, IN DWORD, IN DWORD, IN LPPALETTEENTRY);
+BOOL APIENTRY Arc(IN HDC, IN int, IN int, IN int, IN int, IN int, IN int, IN int, IN int);
+BOOL APIENTRY BitBlt(IN HDC, IN int, IN int, IN DWORD, IN DWORD, IN HDC, IN int, IN int, IN DWORD);
+
+BOOL APIENTRY Chord(IN HDC, IN int, IN int, IN int, IN int, IN int, IN int, IN int, IN int);
+HMF APIENTRY CloseMetaFile(IN HDC);
+int APIENTRY CombineRgn(IN HRGN, IN HRGN, IN HRGN, IN int);
+HMF APIENTRY CopyMetaFile(IN HMF, IN LPSTR);
+HBITMAP APIENTRY CreateBitmap(IN DWORD, IN DWORD, IN WORD, IN WORD, IN LPBYTE);
+HBITMAP APIENTRY CreateBitmapIndirect(IN LPBITMAP);
+HBRUSH APIENTRY CreateBrushIndirect(IN LPLOGBRUSH);
+HBITMAP APIENTRY CreateCompatibleBitmap(IN HDC, IN DWORD, IN DWORD);
+HDC APIENTRY CreateCompatibleDC(IN HDC);
+HDC APIENTRY CreateDC(IN LPSTR, IN LPSTR, IN LPSTR, IN LPDEVMODE);
+HBITMAP APIENTRY CreateDIBitmap(IN HDC, IN LPBITMAPINFOHEADER, IN DWORD, IN LPBYTE, IN LPBITMAPINFO, IN DWORD);
+HBRUSH APIENTRY CreateDIBPatternBrush(IN GLOBALHANDLE, IN DWORD);
+HBRUSH APIENTRY CreateDIBPatternBrushPt(IN LPVOID, IN DWORD);
+HRGN APIENTRY CreateEllipticRgn(IN int, IN int, IN int, IN int);
+HRGN APIENTRY CreateEllipticRgnIndirect(IN LPRECT);
+HFONT APIENTRY CreateFontIndirect(IN LPLOGFONT);
+HFONT APIENTRY CreateFont(IN int, IN DWORD, IN int, IN int, IN DWORD, IN DWORD, IN DWORD, IN DWORD, IN DWORD, IN DWORD, IN DWORD, IN DWORD, IN DWORD, IN LPSTR);
+HBRUSH APIENTRY CreateHatchBrush(IN DWORD, IN COLORREF);
+HDC APIENTRY CreateIC(IN LPSTR, IN LPSTR, IN LPSTR, IN LPDEVMODE);
+HMF APIENTRY CreateMetaFile(IN LPSTR);
+HPALETTE APIENTRY CreatePalette(IN LPLOGPALETTE);
+HPEN APIENTRY CreatePen(IN DWORD, IN DWORD, IN COLORREF);
+HPEN APIENTRY CreatePenIndirect(IN LPLOGPEN);
+HRGN APIENTRY CreatePolygonRgn(IN LPPOINT, IN DWORD, IN DWORD);
+HRGN APIENTRY CreatePolyPolygonRgn(IN LPPOINT, IN LPINT, IN DWORD, IN DWORD);
+HBRUSH APIENTRY CreatePatternBrush(IN HBITMAP);
+HRGN APIENTRY CreateRectRgn(IN int, IN int, IN int, IN int);
+HRGN APIENTRY CreateRectRgnIndirect(IN LPRECT);
+HRGN APIENTRY CreateRoundRectRgn(IN int, IN int, IN int, IN int, IN int, IN int);
+HBRUSH APIENTRY CreateSolidBrush(IN COLORREF);
+
+BOOL APIENTRY DeleteDC(IN HDC);
+BOOL APIENTRY DeleteMetaFile(IN HMF);
+BOOL APIENTRY DeleteObject(IN HANDLE);
+int APIENTRY DeviceCapabilitiesEx(IN LPSTR, IN LPSTR, IN LPSTR, IN DWORD, OUT LPSTR, IN LPDEVMODE);
+BOOL APIENTRY DeviceModeEx(IN HWND, IN LPSTR, IN LPSTR, IN LPSTR);
+BOOL APIENTRY DPtoLP(IN HDC, IN OUT LPPOINT, IN DWORD);
+
+BOOL APIENTRY Ellipse(IN HDC, IN int, IN int, IN int, IN int);
+int APIENTRY EnumFonts(IN HDC, IN LPSTR, IN PROC, IN LPVOID);
+int APIENTRY EnumObjects(IN HDC, IN int, IN PROC, IN LPVOID);
+BOOL APIENTRY EqualRgn(IN HRGN, IN HRGN);
+int APIENTRY Escape(IN HDC,IN int,IN int,IN LPSTR,OUT LPSTR); /*!!! This will change */
+int APIENTRY ExcludeClipRect(IN HDC, IN int, IN int, IN int, IN int);
+LONG APIENTRY ExtDeviceModeEx(IN HWND, IN LPSTR, OUT LPDEVMODE, IN LPSTR, IN LPSTR, IN LPDEVMODE, IN LPSTR, IN DWORD);
+BOOL APIENTRY ExtFloodFill(IN HDC, IN int, IN int, IN COLORREF, IN DWORD);
+BOOL APIENTRY ExtTextOut(IN HDC, IN int, IN int, IN DWORD, IN LPRECT, IN LPSTR, IN DWORD, IN LPDWORD);
+
+BOOL APIENTRY FillRgn(IN HDC, IN HRGN, IN HBRUSH);
+BOOL APIENTRY FloodFill(IN HDC, IN int, IN int, IN COLORREF);
+BOOL APIENTRY FrameRgn(IN HDC, IN HRGN, IN HBRUSH, IN DWORD, IN DWORD);
+DWORD APIENTRY GetROP2(IN HDC);
+BOOL APIENTRY GetAspectRatioFilterEx(IN HDC, OUT PSIZE);
+COLORREF APIENTRY GetBkColor(IN HDC);
+DWORD APIENTRY GetBkMode(IN HDC);
+DWORD APIENTRY GetBitmapBits(IN HBITMAP, IN DWORD, OUT LPBYTE);
+BOOL APIENTRY GetBitmapDimensionEx(IN HBITMAP, OUT PSIZE);
+BOOL APIENTRY GetBrushOrgEx(IN HDC, OUT LPPOINT);
+BOOL APIENTRY GetCharWidth(IN HDC, IN DWORD, IN DWORD, OUT LPINT);
+int APIENTRY GetClipBox(IN HDC, OUT LPRECT);
+BOOL APIENTRY GetCurrentPositionEx(IN HDC, OUT LPPOINT);
+int APIENTRY GetDeviceCaps(IN HDC, IN int);
+BOOL APIENTRY GetDIBits(IN HDC, IN HBITMAP, IN DWORD, IN DWORD, OUT LPBYTE, IN LPBITMAPINFO, IN DWORD);
+BOOL APIENTRY GetDIBitsExt(HBITMAP, DWORD, DWORD, LPBYTE, LPBITMAPINFO, DWORD);
+DWORD APIENTRY GetMapMode(IN HDC);
+DWORD APIENTRY GetMetaFileBitsEx(IN HMF, IN DWORD, OUT LPBYTE);
+HMF APIENTRY GetMetaFile(IN LPSTR);
+COLORREF APIENTRY GetNearestColor(IN HDC, IN COLORREF);
+int APIENTRY GetNearestPaletteIndex(IN HPALETTE, IN COLORREF);
+DWORD APIENTRY GetObject(IN HANDLE, IN DWORD, OUT LPVOID);
+DWORD APIENTRY GetPaletteEntries(IN HPALETTE, IN DWORD, IN DWORD, OUT LPPALETTEENTRY);
+DWORD APIENTRY GetPixel(IN HDC, IN int, IN int);
+DWORD APIENTRY GetPolyFillMode(IN HDC);
+DWORD APIENTRY GetRgnBox(IN HRGN, OUT LPRECT);
+HANDLE APIENTRY GetStockObject(IN DWORD);
+DWORD APIENTRY GetStretchBltMode(IN HDC);
+DWORD APIENTRY GetSystemPaletteEntries(IN HDC, IN DWORD, IN DWORD, OUT LPPALETTEENTRY);
+DWORD APIENTRY GetSystemPaletteUse(IN HDC);
+int APIENTRY GetTextCharacterExtra(IN HDC);
+DWORD APIENTRY GetTextFace(IN HDC, IN DWORD, OUT LPSTR);
+DWORD APIENTRY GetTextAlign(IN HDC);
+COLORREF APIENTRY GetTextColor(IN HDC);
+BOOL APIENTRY GetTextExtentPoint(IN HDC, IN LPSTR, IN DWORD, OUT PSIZE);
+BOOL APIENTRY GetViewportExtEx(IN HDC, OUT PSIZE);
+BOOL APIENTRY GetViewportOrgEx(IN HDC, OUT LPPOINT);
+BOOL APIENTRY GetWindowExtEx(IN HDC, OUT PSIZE);
+BOOL APIENTRY GetWindowOrgEx(IN HDC, OUT LPPOINT);
+
+int APIENTRY IntersectClipRect(IN HDC, IN int, IN int, IN int, IN int);
+BOOL APIENTRY InvertRgn(IN HDC, IN HRGN);
+BOOL APIENTRY LineDDA(IN int, IN int, IN int, IN int, IN PROC, IN LPVOID);
+BOOL APIENTRY LineTo(IN HDC, IN int, IN int);
+BOOL APIENTRY LPtoDP(IN HDC, IN OUT LPPOINT, IN DWORD);
+BOOL APIENTRY MoveToEx(IN HDC, IN int, IN int, OUT LPPOINT);
+
+int APIENTRY OffsetClipRgn(IN HDC, IN int, IN int);
+int APIENTRY OffsetRgn(IN HRGN, IN int, IN int);
+BOOL APIENTRY OffsetViewportOrgEx(IN HDC, IN int, IN int, OUT LPPOINT);
+BOOL APIENTRY OffsetWindowOrgEx(IN HDC, IN int, IN int, OUT LPPOINT);
+BOOL APIENTRY PatBlt(IN HDC, IN int, IN int, IN DWORD, IN DWORD, IN DWORD);
+BOOL APIENTRY Pie(IN HDC, IN int, IN int, IN int, IN int, IN int, IN int, IN int, IN int);
+BOOL APIENTRY PlayMetaFile(IN HDC, IN HMF);
+BOOL APIENTRY PaintRgn(IN HDC, IN HRGN);
+BOOL APIENTRY Polygon(IN HDC, IN LPPOINT, IN DWORD);
+BOOL APIENTRY Polyline(IN HDC, IN LPPOINT, IN DWORD);
+BOOL APIENTRY PolyPolygon(IN HDC, IN LPPOINT, IN LPDWORD, IN DWORD);
+BOOL APIENTRY PtInRegion(IN HRGN, IN int, IN int);
+BOOL APIENTRY PtVisible(IN HDC, IN int, IN int);
+
+BOOL APIENTRY RectInRegion(IN HRGN, IN LPRECT);
+BOOL APIENTRY RectVisible(IN HDC, IN LPRECT);
+BOOL APIENTRY Rectangle(IN HDC, IN int, IN int, IN int, IN int);
+BOOL APIENTRY RestoreDC(IN HDC, IN int);
+int APIENTRY RealizePalette(IN HDC);
+BOOL APIENTRY RemoveFontModule(IN HMODULE);
+BOOL APIENTRY RemoveFontResource(IN LPSTR);
+BOOL APIENTRY RoundRect(IN HDC, IN int, IN int, IN int, IN int, IN int, IN int);
+BOOL APIENTRY ResizePalette(IN HPALETTE, IN DWORD);
+
+int APIENTRY SaveDC(IN HDC);
+BOOL APIENTRY ScaleViewportExtEx(IN HDC, IN int, IN int, IN int, IN int, OUT PSIZE);
+BOOL APIENTRY ScaleWindowExtEx(IN HDC, IN int, IN int, IN int, IN int, OUT PSIZE);
+int APIENTRY SelectClipRgn(IN HDC, IN HRGN);
+HANDLE APIENTRY SelectObject(IN HDC, IN HANDLE);
+HPALETTE APIENTRY SelectPalette(IN HDC, IN HPALETTE, IN BOOL);
+COLORREF APIENTRY SetBkColor(IN HDC, IN COLORREF);
+DWORD APIENTRY SetBkMode(IN HDC, IN DWORD);
+int APIENTRY SetBitmapBits(IN HBITMAP, IN DWORD, IN LPBYTE);
+DWORD APIENTRY SetBitmapDimensionEx(IN HBITMAP, IN DWORD, IN DWORD, OUT PSIZE);
+BOOL APIENTRY SetBrushOrg(IN HDC, IN int, IN int, OUT LPPOINT);
+DWORD APIENTRY SetDIBits(IN HDC, IN HBITMAP, IN DWORD, IN DWORD, IN LPBYTE, IN LPBITMAPINFO, IN DWORD);
+int APIENTRY SetDIBitsToDevice(IN HDC, IN int, IN int, IN DWORD, IN DWORD, IN int, IN int, IN DWORD, IN DWORD, IN LPBYTE, IN LPBITMAPINFO, IN DWORD);
+DWORD APIENTRY SetMapperFlags(IN HDC, IN DWORD);
+DWORD APIENTRY SetMapMode(IN HDC, IN DWORD);
+HMF APIENTRY SetMetaFileBitsEx(IN DWORD, IN LPBYTE);
+DWORD APIENTRY SetPaletteEntries(IN HPALETTE, IN DWORD, IN DWORD, IN LPPALETTEENTRY);
+COLORREF APIENTRY SetPixel(IN HDC, IN int, IN int, IN COLORREF);
+DWORD APIENTRY SetPolyFillMode(IN HDC, IN DWORD);
+BOOL APIENTRY StretchBlt(IN HDC, IN int, IN int, IN int, IN int, IN HDC, IN int, IN int, IN int, IN int, IN int);
+BOOL APIENTRY SetRectRgn(IN HRGN, IN int, IN int, IN int, IN int);
+int APIENTRY StretchDIBits(IN HDC, IN int, IN int, IN int, IN int, IN int, IN int, IN int, IN int, IN LPBYTE, IN LPBITMAPINFO, IN DWORD, IN int);
+DWORD APIENTRY SetROP2(IN HDC, IN DWORD);
+DWORD APIENTRY SetStretchBltMode(IN HDC, IN DWORD);
+DWORD APIENTRY SetSystemPaletteUse(IN HDC, IN DWORD);
+int APIENTRY SetTextCharacterExtra(IN HDC, IN int);
+COLORREF APIENTRY SetTextColor(IN HDC, IN COLORREF);
+DWORD APIENTRY SetTextAlign(IN HDC, IN DWORD);
+BOOL APIENTRY SetTextJustification(IN HDC, IN int, IN DWORD);
+BOOL APIENTRY SetViewportExtEx(IN HDC, IN int, IN int, OUT PSIZE);
+BOOL APIENTRY SetViewportOrgEx(IN HDC, IN int, IN int, OUT LPPOINT);
+BOOL APIENTRY SetWindowExtEx(IN HDC, IN int, IN int, OUT PSIZE);
+BOOL APIENTRY SetWindowOrgEx(IN HDC, IN int, IN int, OUT LPPOINT);
+BOOL APIENTRY TextOut(IN HDC, IN int, IN int, IN LPSTR, IN DWORD);
+BOOL APIENTRY UpdateColors(IN HDC);
+
+#ifndef NOMETAFILE
+BOOL APIENTRY PlayMetaFileRecord(IN HDC, IN LPHANDLETABLE, IN LPMETARECORD, IN DWORD);
+BOOL APIENTRY EnumMetaFile(IN HDC, IN HMF, IN PROC, IN LPVOID);
+#endif
+
+#ifndef NOTEXTMETRIC
+BOOL APIENTRY GetTextMetrics(IN HDC, OUT LPTEXTMETRIC );
+#endif
+
+/* new GDI */
+BOOL APIENTRY AngleArc(IN HDC, IN int, IN int, IN DWORD, IN FLOAT, IN FLOAT);
+BOOL APIENTRY GetWorldTransform(IN HDC, OUT PXFORM);
+BOOL APIENTRY PolyBezier(IN HDC, IN LPPOINT, IN DWORD);
+BOOL APIENTRY PolyBezierTo(IN HDC, IN LPPOINT, IN DWORD);
+BOOL APIENTRY PolylineTo(IN HDC, IN LPPOINT, IN DWORD);
+BOOL APIENTRY PolyPolyline(IN HDC, IN LPPOINT, IN LPDWORD, IN DWORD);
+BOOL APIENTRY SetWorldTransform(IN HDC, IN PXFORM);
+BOOL APIENTRY ModifyWorldTransform(IN HDC, IN PXFORM, IN DWORD);
+
+#endif /* NOGDI */
+
+#ifdef LATER
+/*
+ * JimA - 11/30/90
+ * gdidelta.doc lists these as obsolete
+ */
+DWORD APIENTRY GetDCOrg(HDC);
+#endif /* LATER */
+
+#endif // _WINGDI_
diff --git a/private/os2/client/thunk/include/winkern.inc b/private/os2/client/thunk/include/winkern.inc
new file mode 100644
index 000000000..300dff04f
--- /dev/null
+++ b/private/os2/client/thunk/include/winkern.inc
@@ -0,0 +1,441 @@
+MASTER_OBJECT_SIZE equ 512
+
+LOCALHEAP_SIG EQU 'HL'
+GLOBALHEAP_SIG EQU 'HG'
+
+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.
+;
+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
+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
+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)
+
+if PMODE
+GA_INTFLAGS = GA_ALLOCHIGH+GA_SEGTYPE or (GA_CODE_DATA+GA_ALLOC_DOS) shl 8
+else
+GA_INTFLAGS = GA_ALLOCHIGH+GA_SEGTYPE
+endif
+
+; 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
+ife PMODE
+GA_ALLOC_EMS EQU 80h ; Alloc in EMS land if LIM 4.0 around.
+else
+GA_ALLOC_DOS EQU 80h ; Alloc in DOS land if protected mode
+endif
+
+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
+ife PMODE
+GAH_INEMS EQU 80h ; This is out in EMS
+else
+GAH_FIXED EQU 80h
+endif
+
+; 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
+GlobalInfo ENDS
+gi_cmpflags = byte ptr hi_dislevel ; Flags to control gcompact
+gi_disfence_lo = word ptr gi_disfence
+
+GIF_INT2 EQU 01h
+
+CMP_FLAGS EQU GA_NODISCARD or GA_NOCOMPACT or GA_DISCCODE
+
+BOOT_COMPACT EQU 80h
+COMPACT_ALLOC EQU 40h ; Fast abort in gcompact for allocations
+
+; 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
+
+fhCacheLen = 14 ; Number of file handles cached
+
+ife PMODE
+
+CMLEN = 10 ; Number of entries in Cache Map
+NewEMSLEN = 20 ; Number of entries in EMM Map
+
+free_map struc ; Free Map Description
+ fm_start dw ? ; List of used entries
+ fm_free dw ? ; List of free entries
+ fm_compact dw ? ; Routine to compact this map
+ fm_align dw 0 ; Alignment == pagesize - 1
+free_map ends
+
+fme struc ; Free map entry structure
+ fme_next dw 0 ; Link to next entry
+ fme_start dw ? ; Start of this free block
+ fme_len dw ? ; Length of this block
+fme ends
+
+endif ; PMODE
+
+FIRST_HMA_SEG = 0FFF9h ; Segment used to access HMA
+
+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
diff --git a/private/os2/client/thunk/include/winmm.h b/private/os2/client/thunk/include/winmm.h
new file mode 100644
index 000000000..a9f29be5e
--- /dev/null
+++ b/private/os2/client/thunk/include/winmm.h
@@ -0,0 +1,41 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ media.h
+
+Abstract:
+
+ This include file defines all the support for Multimedia applications.
+
+Author:
+
+ Nigel Thompson (NigelT) 20-Mar-91
+
+Revision History:
+
+--*/
+
+#ifndef _WINMM_
+#define _WINMM_
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif // _WINMM_
diff --git a/private/os2/client/thunk/include/winnet.h b/private/os2/client/thunk/include/winnet.h
new file mode 100644
index 000000000..ca14ffc77
--- /dev/null
+++ b/private/os2/client/thunk/include/winnet.h
@@ -0,0 +1,78 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ winnet.h
+
+Abstract:
+
+ This module defines the 32-Bit Windows Network APIs
+
+Author:
+
+ Manny Weiser (mannyw) 5-Mar-1991
+
+Revision History:
+
+--*/
+
+#ifndef _WINNET_
+#define _WINNET_
+
+//
+// Special values for mailslot information.
+//
+
+//
+// Special value for NextMessageSize to indicate that there is no next
+// message.
+//
+
+#define MAILSLOT_NO_MESSAGE -1
+
+//
+// Special value for mailslot size creation to indicate that the system
+// should choose the size of the mailslot buffer.
+//
+
+#define MAILSLOT_SIZE_AUTO 0
+
+//
+// Special value for read timeout to indicate that mailslot reads should
+// never timeout.
+//
+
+#define MAILSLOT_WAIT_FOREVER -1
+
+BOOL
+APIENTRY
+CreateMailslot(
+ IN LPSTR lpName,
+ IN DWORD nMaxMessageSize,
+ IN DWORD nMailslotSize,
+ IN DWORD lReadTimeout,
+ OUT LPHANDLE lpMailslotHandle,
+ IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL
+ );
+
+BOOL
+APIENTRY
+GetMailslotInfo(
+ IN HANDLE hMailslot,
+ OUT LPDWORD lpMaxMessageSize OPTIONAL,
+ OUT LPDWORD lpMailslotSize OPTIONAL,
+ OUT LPDWORD lpNextSize OPTIONAL,
+ OUT LPDWORD lpMessageCount OPTIONAL,
+ OUT LPDWORD lpReadTimeout OPTIONAL
+ );
+
+BOOL
+APIENTRY
+SetMailslotInfo(
+ IN HANDLE hMailslot,
+ IN DWORD lReadTimeout
+ );
+
+#endif // _WINNET_
diff --git a/private/os2/client/thunk/include/winnt.h b/private/os2/client/thunk/include/winnt.h
new file mode 100644
index 000000000..0bb5eb965
--- /dev/null
+++ b/private/os2/client/thunk/include/winnt.h
@@ -0,0 +1,532 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ winnt.h
+
+Abstract:
+
+ This module defines the 32-Bit Windows types and constants that are
+ defined by NT, but exposed through the Win32 API.
+
+Author:
+
+ Mark Lucovsky (markl) 18-Sep-1990
+
+Revision History:
+
+--*/
+
+#ifndef _WINNT_
+#define _WINNT_
+
+typedef void *PVOID;
+
+//
+// Basics
+//
+
+#ifndef VOID
+#define VOID void
+typedef char CHAR;
+typedef short SHORT;
+typedef long LONG;
+#endif
+
+//
+// UNICODE
+//
+
+#ifndef WCHAR
+typedef unsigned short WCHAR; // wc, 16-bit UNICODE character
+typedef WCHAR *LPWCH; // pwc
+typedef WCHAR *LPWSTR; // pwsz, 0x0000 terminated UNICODE strings only
+#endif
+
+typedef PVOID HANDLE;
+#define MAXLONG 0x7fffffff
+#define STATUS_WAIT_0 ((DWORD )0x00000000L)
+#define STATUS_ABANDONED_WAIT_0 ((DWORD )0x00000080L)
+#define STATUS_TIMEOUT ((DWORD )0x00000103L)
+#define STATUS_PENDING ((DWORD )0x00000104L)
+#define STATUS_DATATYPE_MISALIGNMENT ((DWORD )0x80000002L)
+#define STATUS_BREAKPOINT ((DWORD )0x80000003L)
+#define STATUS_SINGLE_STEP ((DWORD )0x80000004L)
+#define STATUS_ACCESS_VIOLATION ((DWORD )0xC0000005L)
+#define MAXIMUM_WAIT_OBJECTS 64 // Maximum number of wait objects
+
+#define MAXIMUM_SUSPEND_COUNT MAXCHAR // Maximum times thread can be suspended
+typedef DWORD *KSPIN_LOCK;
+
+#ifdef i386
+
+//
+// Define the size of the 80387 save area, which is in the context frame.
+//
+
+#define SIZE_OF_80387_ENVIRONMENT 108
+#define SIZE_OF_80387_REGISTERS 80
+
+//
+// The following flags control the contents of the CONTEXT structure.
+//
+
+#define CONTEXT_i386 0x00010000 // this assumes that i386 and
+#define CONTEXT_i486 0x00010000 // i486 have identical context records
+
+#define CONTEXT_CONTROL (CONTEXT_i386 | 0x00000001L) // SS:SP, CS:IP, FLAGS, BP
+#define CONTEXT_INTEGER (CONTEXT_i386 | 0x00000002L) // AX, BX, CX, DX, SI, DI
+#define CONTEXT_SEGMENTS (CONTEXT_i386 | 0x00000004L) // DS, ES, FS, GS
+#define CONTEXT_FLOATING_POINT (CONTEXT_i386 | 0x00000008L) // 387 state
+#define CONTEXT_DEBUG_REGISTERS (CONTEXT_i386 | 0x00000010L) // DB 0-3,6,7
+
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER |\
+ CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT)
+
+typedef struct _FLOATING_SAVE_AREA {
+ DWORD ControlWord;
+ DWORD StatusWord;
+ DWORD TagWord;
+ DWORD ErrorOffset;
+ DWORD ErrorSelector;
+ DWORD DataOffset;
+ DWORD DataSelector;
+ BYTE RegisterArea[SIZE_OF_80387_REGISTERS];
+} FLOATING_SAVE_AREA;
+
+typedef FLOATING_SAVE_AREA *PFLOATING_SAVE_AREA;
+
+//
+// Context Frame
+//
+// This frame has a several purposes: 1) it is used as an argument to
+// NtContinue, 2) is is used to constuct a call frame for APC delivery,
+// and 3) it is used in the user level thread creation routines.
+//
+// The layout of the record conforms to a standard call frame.
+//
+
+typedef struct _CONTEXT {
+
+ //
+ // The flags values within this flag control the contents of
+ // a CONTEXT record.
+ //
+ // If the context record is used as an input parameter, then
+ // for each portion of the context record controlled by a flag
+ // whose value is set, it is assumed that that portion of the
+ // context record contains valid context. If the context record
+ // is being used to modify a threads context, then only that
+ // portion of the threads context will be modified.
+ //
+ // If the context record is used as an IN OUT parameter to capture
+ // the context of a thread, then only those portions of the thread's
+ // context corresponding to set flags will be returned.
+ //
+ // The context record is never used as an OUT only parameter.
+ //
+
+ DWORD ContextFlags;
+
+ //
+ // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
+ // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
+ // included in CONTEXT_FULL.
+ //
+
+ DWORD Dr0;
+ DWORD Dr1;
+ DWORD Dr2;
+ DWORD Dr3;
+ DWORD Dr6;
+ DWORD Dr7;
+
+ //
+ // This section is specified/returned if the
+ // ContextFlags word contians the flag CONTEXT_FLOATING_POINT.
+ //
+
+ FLOATING_SAVE_AREA FloatSave;
+
+ //
+ // This section is specified/returned if the
+ // ContextFlags word contians the flag CONTEXT_SEGMENTS.
+ //
+
+ DWORD SegGs;
+ DWORD SegFs;
+ DWORD SegEs;
+ DWORD SegDs;
+
+ //
+ // This section is specified/returned if the
+ // ContextFlags word contians the flag CONTEXT_INTEGER.
+ //
+
+ DWORD Edi;
+ DWORD Esi;
+ DWORD Ebx;
+ DWORD Edx;
+ DWORD Ecx;
+ DWORD Eax;
+
+ //
+ // This section is specified/returned if the
+ // ContextFlags word contians the flag CONTEXT_CONTROL.
+ //
+
+ DWORD Ebp;
+ DWORD Eip;
+ DWORD SegCs; // MUST BE SANITIZED
+ DWORD EFlags; // MUST BE SANITIZED
+ DWORD Esp;
+ DWORD SegSs;
+
+} CONTEXT;
+
+
+
+typedef CONTEXT *PCONTEXT;
+
+#endif // i386
+
+#ifdef MIPS
+
+//
+// The following flags control the contents of the CONTEXT structure.
+//
+
+#define CONTEXT_R3000 0x00010000 // this assumes that r3000 and
+#define CONTEXT_R4000 0x00010000 // r4000 have identical context records
+
+#define CONTEXT_CONTROL (CONTEXT_R3000 | 0x00000001L)
+#define CONTEXT_FLOATING_POINT (CONTEXT_R3000 | 0x00000002L)
+#define CONTEXT_INTEGER (CONTEXT_R3000 | 0x00000004L)
+
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER)
+
+//
+// Context Frame
+//
+// N.B. This frame must be exactly a multiple of 16 bytes in length.
+//
+// This frame has a several purposes: 1) it is used as an argument to
+// NtContinue, 2) it is used to constuct a call frame for APC delivery,
+// 3) it is used to construct a call frame for exception dispatching
+// in user mode, and 4) it is used in the user level thread creation
+// routines.
+//
+// The layout of the record conforms to a standard call frame.
+//
+
+typedef struct _CONTEXT {
+
+ //
+ // This section is always present and is used as an argument build
+ // area.
+ //
+
+ DWORD Argument[4];
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_FLOATING_POINT.
+ //
+
+ DWORD FltF0;
+ DWORD FltF1;
+ DWORD FltF2;
+ DWORD FltF3;
+ DWORD FltF4;
+ DWORD FltF5;
+ DWORD FltF6;
+ DWORD FltF7;
+ DWORD FltF8;
+ DWORD FltF9;
+ DWORD FltF10;
+ DWORD FltF11;
+ DWORD FltF12;
+ DWORD FltF13;
+ DWORD FltF14;
+ DWORD FltF15;
+ DWORD FltF16;
+ DWORD FltF17;
+ DWORD FltF18;
+ DWORD FltF19;
+ DWORD FltF20;
+ DWORD FltF21;
+ DWORD FltF22;
+ DWORD FltF23;
+ DWORD FltF24;
+ DWORD FltF25;
+ DWORD FltF26;
+ DWORD FltF27;
+ DWORD FltF28;
+ DWORD FltF29;
+ DWORD FltF30;
+ DWORD FltF31;
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_INTEGER.
+ //
+ // N.B. The registers gp, sp, and ra are defined in this section, but are
+ // considered part of the control context rather than part of the integer
+ // context.
+ //
+ // N.B. Register zero is not stored in the frame.
+ //
+
+ DWORD IntZero;
+ DWORD IntAt;
+ DWORD IntV0;
+ DWORD IntV1;
+ DWORD IntA0;
+ DWORD IntA1;
+ DWORD IntA2;
+ DWORD IntA3;
+ DWORD IntT0;
+ DWORD IntT1;
+ DWORD IntT2;
+ DWORD IntT3;
+ DWORD IntT4;
+ DWORD IntT5;
+ DWORD IntT6;
+ DWORD IntT7;
+ DWORD IntS0;
+ DWORD IntS1;
+ DWORD IntS2;
+ DWORD IntS3;
+ DWORD IntS4;
+ DWORD IntS5;
+ DWORD IntS6;
+ DWORD IntS7;
+ DWORD IntT8;
+ DWORD IntT9;
+ DWORD IntK0;
+ DWORD IntK1;
+ DWORD IntGp;
+ DWORD IntSp;
+ DWORD IntS8;
+ DWORD IntRa;
+ DWORD IntLo;
+ DWORD IntHi;
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_FLOATING_POINT.
+ //
+
+ DWORD Fsr;
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_CONTROL.
+ //
+ // N.B. The registers gp, sp, and ra are defined in the integer section,
+ // but are considered part of the control context rather than part of
+ // the integer context.
+ //
+
+ DWORD Fir;
+ DWORD Psr;
+
+ //
+ // The flags values within this flag control the contents of
+ // a CONTEXT record.
+ //
+ // If the context record is used as an input parameter, then
+ // for each portion of the context record controlled by a flag
+ // whose value is set, it is assumed that that portion of the
+ // context record contains valid context. If the context record
+ // is being used to modify a thread's context, then only that
+ // portion of the threads context will be modified.
+ //
+ // If the context record is used as an IN OUT parameter to capture
+ // the context of a thread, then only those portions of the thread's
+ // context corresponding to set flags will be returned.
+ //
+ // The context record is never used as an OUT only parameter.
+ //
+
+ DWORD ContextFlags;
+
+ DWORD Fill[2];
+} CONTEXT, *PCONTEXT;
+
+#endif // MIPS
+
+#define EXCEPTION_NONCONTINUABLE 0x1 // Noncontinuable exception
+#define EXCEPTION_MAXIMUM_PARAMETERS 4 // maximum number of exception parameters
+
+//
+// Exception record definition.
+//
+
+typedef struct _EXCEPTION_RECORD {
+ DWORD ExceptionCode;
+ DWORD ExceptionFlags;
+ struct _EXCEPTION_RECORD *ExceptionRecord;
+ PVOID ExceptionAddress;
+ DWORD NumberParameters;
+ DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
+ } EXCEPTION_RECORD;
+
+typedef EXCEPTION_RECORD *PEXCEPTION_RECORD;
+
+//
+// Typedef for pointer returned by exception_info()
+//
+
+typedef struct _EXCEPTION_POINTERS {
+ PEXCEPTION_RECORD ExceptionRecord;
+ PCONTEXT ContextRecord;
+} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS, *Exception_info_ptr;
+#define PROCESS_TERMINATE (0x0001)
+#define PROCESS_VM_READ (0x0010)
+#define PROCESS_VM_WRITE (0x0020)
+#define PROCESS_DUP_HANDLE (0x0040)
+#define PROCESS_CREATE_PROCESS (0x0080)
+#define PROCESS_SET_INFORMATION (0x0200)
+#define PROCESS_QUERY_INFORMATION (0x0400)
+#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
+ 0xFFF)
+#define THREAD_TERMINATE (0x0001)
+#define THREAD_SUSPEND_RESUME (0x0002)
+#define THREAD_GET_CONTEXT (0x0008)
+#define THREAD_SET_CONTEXT (0x0010)
+#define THREAD_SET_INFORMATION (0x0020)
+#define THREAD_QUERY_INFORMATION (0x0040)
+#define THREAD_SET_THREAD_TOKEN (0x0080)
+#define THREAD_IMPERSONATE (0x0100)
+#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
+ 0x1FF)
+#define THREAD_BASE_PRIORITY_MAX 2 // maximum thread base priority boost
+#define THREAD_BASE_PRIORITY_MIN -2 // minimum thread base priority boost
+#define EVENT_MODIFY_STATE 0x0002
+#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3)
+#define MUTANT_QUERY_STATE 0x0001
+
+#define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|\
+ MUTANT_QUERY_STATE)
+#define SEMAPHORE_MODIFY_STATE 0x0002
+#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3)
+typedef struct _MEMORY_BASIC_INFORMATION {
+ PVOID BaseAddress;
+ PVOID AllocationBase;
+ DWORD AllocationProtect;
+ DWORD RegionSize;
+ DWORD State;
+ DWORD Protect;
+ DWORD Type;
+} MEMORY_BASIC_INFORMATION;
+typedef MEMORY_BASIC_INFORMATION *PMEMORY_BASIC_INFORMATION;
+#define SECTION_MAP_WRITE 0x0002
+#define SECTION_MAP_READ 0x0004
+#define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|\
+ SECTION_MAP_WRITE | \
+ SECTION_MAP_READ | \
+ SECTION_MAP_EXECUTE | \
+ SECTION_EXTEND_SIZE)
+#define PAGE_NOACCESS 0x01
+#define PAGE_READONLY 0x02
+#define PAGE_READWRITE 0x04
+#define MEM_COMMIT 0x1000
+#define MEM_RESERVE 0x2000
+#define MEM_DECOMMIT 0x4000
+#define MEM_RELEASE 0x8000
+#define MEM_FREE 0x10000
+#define MEM_PRIVATE 0x20000
+#define FILE_SHARE_READ 0x00000001
+#define FILE_SHARE_WRITE 0x00000002
+#define FILE_ATTRIBUTE_READONLY 0x00000001
+#define FILE_ATTRIBUTE_HIDDEN 0x00000002
+#define FILE_ATTRIBUTE_SYSTEM 0x00000004
+#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
+#define FILE_ATTRIBUTE_NORMAL 0x00000080
+#define FILE_CASE_SENSITIVE_SEARCH 0x00000001
+#define FILE_CASE_PRESERVED_NAMES 0x00000002
+#define FILE_UNICODE_ON_DISK 0x00000004
+#define DUPLICATE_CLOSE_SOURCE 0x00000001
+#define DUPLICATE_SAME_ACCESS 0x00000002
+typedef PVOID PSECURITY_DESCRIPTOR;
+typedef DWORD ACCESS_MASK;
+#define DELETE 0x00010000
+#define READ_CONTROL 0x00020000
+#define WRITE_DAC 0x00040000
+#define WRITE_OWNER 0x00080000
+#define SYNCHRONIZE 0x00100000
+
+#define STANDARD_RIGHTS_REQUIRED 0x000F0000
+
+#define STANDARD_RIGHTS_READ (READ_CONTROL)
+#define STANDARD_RIGHTS_WRITE (READ_CONTROL)
+#define STANDARD_RIGHTS_EXECUTE (READ_CONTROL)
+
+#define STANDARD_RIGHTS_ALL 0x001F0000
+
+#define SPECIFIC_RIGHTS_ALL 0x0000FFFF
+
+//
+// AccessSystemAcl access type
+//
+
+#define ACCESS_SYSTEM_SECURITY 0x01000000
+
+//
+// MaximumAllowed access type
+//
+
+#define MAXIMUM_ALLOWED 0x02000000
+
+//
+// These are the generic rights.
+//
+
+#define GENERIC_READ 0x80000000
+#define GENERIC_WRITE 0x40000000
+#define GENERIC_EXECUTE 0x20000000
+#define GENERIC_ALL 0x10000000
+typedef struct _SECURITY_INFORMATION {
+ DWORD Owner :1;
+ DWORD Group :1;
+ DWORD Dacl :1;
+ DWORD Sacl :1;
+ DWORD Reserved :28;
+ } SECURITY_INFORMATION;
+typedef SECURITY_INFORMATION *PSECURITY_INFORMATION;
+
+#define OWNER_SECURITY_INFORMATION 0X00000001
+#define GROUP_SECURITY_INFORMATION 0X00000002
+#define DACL_SECURITY_INFORMATION 0X00000004
+#define SACL_SECURITY_INFORMATION 0X00000008
+typedef struct _RTL_CRITICAL_SECTION {
+
+#if DBG
+ PVOID CallingAddress;
+ PVOID CallersCaller;
+#endif // DBG
+
+ //
+ // The following three fields control entering and exiting the critical
+ // section for the resource
+ //
+
+ LONG LockCount;
+ LONG RecursionCount;
+ HANDLE OwningThread; // from the thread's ClientId->UniqueThread
+ HANDLE LockSemaphore;
+ KSPIN_LOCK SpinLock;
+
+} RTL_CRITICAL_SECTION;
+typedef RTL_CRITICAL_SECTION *PRTL_CRITICAL_SECTION;
+#define DBG_CONTINUE ((DWORD )0x00010002L)
+#define DBG_TERMINATE_THREAD ((DWORD )0x40010003L)
+#define DBG_TERMINATE_PROCESS ((DWORD )0x40010004L)
+#define DBG_CONTROL_C ((DWORD )0x40010005L)
+#define DBG_DLLS_LOADED ((DWORD )0x40010006L)
+#define DBG_EXCEPTION_NOT_HANDLED ((DWORD )0x80010001L)
+
+#endif // _WINNT_
diff --git a/private/os2/client/thunk/include/winuser.h b/private/os2/client/thunk/include/winuser.h
new file mode 100644
index 000000000..dc4f4a7fc
--- /dev/null
+++ b/private/os2/client/thunk/include/winuser.h
@@ -0,0 +1,2075 @@
+/***************************************************************************\
+* Module Name: winuser.h
+*
+* Copyright (c) 1985-91, Microsoft Corporation
+*
+* Procedure declarations, constant definitions and macros for the User
+* component.
+*
+\***************************************************************************/
+
+#ifndef _WINUSER_
+#define _WINUSER_
+
+#ifndef NOUSER
+
+typedef LONG (APIENTRY *WNDPROC)(HWND, WORD, DWORD, LONG);
+
+#define MAKEINTRESOURCE(i) (LPSTR)((DWORD)((WORD)(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)
+#define RT_MESSAGETABLE MAKEINTRESOURCE(11)
+
+#endif /* NORESOURCE */
+
+int APIENTRY wvsprintf(LPSTR, LPSTR, LPSTR);
+int cdecl wsprintf(LPSTR, LPSTR, ...);
+
+#ifndef NOSCROLL
+
+/* Scroll Bar Constants */
+#define SB_HORZ 0
+#define SB_VERT 1
+#define SB_CTL 2
+#define SB_BOTH 3
+
+/* Scroll Bar Commands */
+#define SB_LINEUP 0
+#define SB_LINEDOWN 1
+#define SB_PAGEUP 2
+#define SB_PAGEDOWN 3
+#define SB_THUMBPOSITION 4
+#define SB_THUMBTRACK 5
+#define SB_TOP 6
+#define SB_BOTTOM 7
+#define SB_ENDSCROLL 8
+
+#endif /* NOSCROLL */
+
+#ifndef NOSHOWWINDOW
+
+/* ShowWindow() Commands */
+#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
+
+/* Old ShowWindow() Commands */
+#define HIDE_WINDOW 0
+#define SHOW_OPENWINDOW 1
+#define SHOW_ICONWINDOW 2
+#define SHOW_FULLSCREEN 3
+#define SHOW_OPENNOACTIVATE 4
+
+/* Identifiers for the WM_SHOWWINDOW message */
+#define SW_PARENTCLOSING 1
+#define SW_OTHERZOOM 2
+#define SW_PARENTOPENING 3
+#define SW_OTHERUNZOOM 4
+
+#endif /* NOSHOWWINDOW */
+
+#ifndef NOVIRTUALKEYCODES
+
+/* 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
+#define VK_SELECT 0x29
+#define VK_PRINT 0x2A
+#define VK_EXECUTE 0x2B
+#define VK_SNAPSHOT 0x2C
+/* #define VK_COPY 0x2C not used by keyboards. */
+#define VK_INSERT 0x2D
+#define VK_DELETE 0x2E
+#define VK_HELP 0x2F
+
+/* 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 '9' */
+
+#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_NUMLOCK 0x90
+
+#endif /* NOVIRTUALKEYCODES */
+
+#ifndef NOWH
+
+/* SetWindowsHook() codes */
+#define WH_MSGFILTER (-1)
+#define WH_JOURNALRECORD 0
+#define WH_JOURNALPLAYBACK 1
+#define WH_KEYBOARD 2
+#define WH_GETMESSAGE 3
+#define WH_CALLWNDPROC 4
+#define WH_CBT 5
+#define WH_SYSMSGFILTER 6
+#define WH_MOUSE 7
+#define WH_HARDWARE 8
+#define WH_DEBUG 9
+
+
+/* Hook Codes */
+#define HC_LPLPFNNEXT (-2)
+#define HC_LPFNNEXT (-1)
+#define HC_ACTION 0
+#define HC_GETNEXT 1
+#define HC_SKIP 2
+#define HC_NOREM 3
+#define HC_NOREMOVE 3
+#define HC_SYSMODALON 4
+#define HC_SYSMODALOFF 5
+
+/* CBT Hook Codes */
+#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
+
+/* WH_MSGFILTER Filter Proc Codes */
+#define MSGF_DIALOGBOX 0
+#define MSGF_MESSAGEBOX 1
+#define MSGF_MENU 2
+#define MSGF_MOVE 3
+#define MSGF_SIZE 4
+#define MSGF_SCROLLBAR 5
+#define MSGF_NEXTWINDOW 6
+
+/* Window Manager Hook Codes */
+#define WC_INIT 1
+#define WC_SWP 2
+#define WC_DEFWINDOWPROC 3
+#define WC_MINMAX 4
+#define WC_MOVE 5
+#define WC_SIZE 6
+#define WC_DRAWCAPTION 7
+
+/* Message Structure used in Journaling */
+typedef struct tagEVENTMSG
+ {
+ WORD message;
+ WORD paramL;
+ WORD paramH;
+ DWORD time;
+ } EVENTMSG;
+typedef EVENTMSG *PEVENTMSGMSG;
+typedef EVENTMSG NEAR *NPEVENTMSGMSG;
+typedef EVENTMSG FAR *LPEVENTMSGMSG;
+
+/* Message structure used by WH_CALLWNDPROC */
+typedef struct tagCWPSTRUCT
+ {
+ HWND hwnd;
+ WORD message;
+ DWORD wParam;
+ LONG lParam;
+ } CWPSTRUCT;
+typedef CWPSTRUCT *PCWPSTRUCT;
+typedef CWPSTRUCT NEAR *NPCWPSTRUCT;
+typedef CWPSTRUCT FAR *LPCWPSTRUCT;
+
+/* Structure used by WH_DEBUG */
+typedef struct tagDEBUGHOOKSTRUCT
+ {
+ DWORD idThread;
+ DWORD reserved;
+ DWORD lParam;
+ DWORD wParam;
+ int nCode;
+ } DEBUGHOOKSTRUCT;
+typedef DEBUGHOOKSTRUCT *PDEBUGHOOKSTRUCT;
+typedef DEBUGHOOKSTRUCT NEAR *NPDEBUGHOOKSTRUCT;
+typedef DEBUGHOOKSTRUCT FAR *LPDEBUGHOOKSTRUCT;
+
+typedef struct tagMOUSEHOOKSTRUCT
+ {
+ POINT point;
+ HWND hWnd;
+ WORD wHitTestCode;
+ DWORD dwExtraInfo;
+ } MOUSEHOOKSTRUCT;
+typedef MOUSEHOOKSTRUCT FAR *LPMOUSEHOOKSTRUCT;
+typedef MOUSEHOOKSTRUCT *PMOUSEHOOKSTRUCT;
+#endif /* NOWH */
+
+#ifndef NODESKTOP
+
+/*
+ * Desktop-specific access flags
+ */
+#define DESKTOP_ENUMWINDOWS 0x0001L
+#define DESKTOP_CREATEWINDOW 0x0002L
+#define DESKTOP_CREATEMENU 0x0004L
+#define DESKTOP_HOOKCONTROL 0x0008L
+#define DESKTOP_JOURNALRECORD 0x0010L
+#define DESKTOP_JOURNALPLAYBACK 0x0020L
+#define DESKTOP_ENUMERATE 0x0040L
+
+/*
+ * Desktop flags
+ */
+#define DESKF_SAVEBITS 0x0001L
+#define DESKF_TEXTMODE 0x0002L
+
+typedef struct _DESKATTRS {
+ DWORD cb;
+ DWORD cx;
+ DWORD cy;
+ DWORD cBitsPixel;
+ DWORD dwFlags;
+} DESKATTRS;
+typedef DESKATTRS *PDESKATTRS;
+typedef DESKATTRS NEAR *NPDESKATTRS;
+typedef DESKATTRS FAR *LPDESKATTRS;
+
+BOOL APIENTRY CRITICAL CreateDesktop(IN LPSTR, IN LPSTR, IN LPDESKATTRS);
+HDESK APIENTRY CRITICAL OpenDesktop(IN LPSTR, IN DWORD);
+BOOL APIENTRY CRITICAL SwitchDesktop(IN HDESK);
+BOOL APIENTRY CRITICAL SetThreadDesktop(IN HDESK);
+HDESK APIENTRY CRITICAL GetThreadDesktop(IN DWORD);
+HDESK APIENTRY CRITICAL GetInputDesktop(VOID);
+BOOL APIENTRY CRITICAL CloseDesktop(IN HDESK);
+BOOL APIENTRY CRITICAL EnumDesktops(IN FARPROC, IN LONG);
+WORD APIENTRY CRITICAL GetDesktopAttrs(IN HDESK, IN LPSTR, IN WORD, OUT LPDESKATTRS);
+WORD APIENTRY CRITICAL GetDesktopTypes(IN LPSTR, OUT LPDESKATTRS, IN WORD);
+BOOL APIENTRY CRITICAL EnumDisplayDevices(IN FARPROC, IN LONG);
+
+#endif /* NODESKTOP */
+
+#ifndef NOWINDOWSTATION
+
+/*
+ * Windowstation-specific access flags
+ */
+#define WINSTA_ENUMDESKTOPS 0x0001L
+#define WINSTA_READATTRIBUTES 0x0002L
+#define WINSTA_ACCESSCLIPBOARD 0x0004L
+#define WINSTA_CREATEDESKTOP 0x0008L
+#define WINSTA_WRITEATTRIBUTES 0x0010L
+#define WINSTA_ACCESSGLOBALATOMS 0x0020L
+#define WINSTA_EXITWINDOWS 0x0040L
+#define WINSTA_ENUMERATE 0x0100L
+#define WINSTA_READSCREEN 0x0200L
+
+typedef struct _WINSTAATTRS
+ {
+ DWORD cb;
+ } WINSTAATTRS;
+typedef WINSTAATTRS *PWINSTAATTRS;
+typedef WINSTAATTRS NEAR *NPWINSTAATTRS;
+typedef WINSTAATTRS FAR *LPWINSTAATTRS;
+
+HWINSTA APIENTRY CRITICAL OpenWindowStation(IN LPSTR, IN DWORD);
+BOOL APIENTRY CRITICAL SetProcessWindowStation(IN HWINSTA);
+HWINSTA APIENTRY CRITICAL GetProcessWindowStation(VOID);
+BOOL APIENTRY CRITICAL CloseWindowStation(IN HWINSTA);
+BOOL APIENTRY CRITICAL EnumWindowStations(IN FARPROC, IN LONG);
+WORD APIENTRY CRITICAL GetWindowStationAttrs(IN HWINSTA, OUT LPSTR, IN WORD,
+ OUT LPWINSTAATTRS);
+
+#endif /* NOWINDOWSTATION */
+
+#ifndef NOSECURITY
+
+/*
+ * window-specific access flags
+ */
+#define WIN_ACCESSWINDOW 0x0001L
+#define WIN_ENUMERATE 0x0002L
+
+/*
+ * menu-specific access flags
+ */
+#define MENU_ACCESSMENU 0x0001L
+
+/*
+ * dde-specific access flags
+ */
+#define DDE_ADVISE 0x0001L
+#define DDE_EXECUTE 0x0002L
+#define DDE_POKE 0x0004L
+#define DDE_REQUEST 0x0008L
+
+BOOL APIENTRY CRITICAL SetObjectSecurity(IN HANDLE, IN PSECURITY_INFORMATION,
+ IN PSECURITY_DESCRIPTOR);
+BOOL APIENTRY CRITICAL GetObjectSecurity(IN HANDLE, IN PSECURITY_INFORMATION,
+ OUT PSECURITY_DESCRIPTOR, IN WORD, OUT LPWORD);
+
+#endif /* NOSECURITY */
+
+typedef struct tagWNDCLASS
+ {
+ WORD style;
+ WNDPROC lpfnWndProc;
+ //!!! LONG (APIENTRY *lpfnWndProc)();
+ int cbClsExtra;
+ int cbWndExtra;
+ HANDLE hInstance;
+ HICON hIcon;
+ HCURSOR hCursor;
+ HBRUSH hbrBackground;
+ LPSTR lpszMenuName;
+ LPSTR lpszClassName;
+ } WNDCLASS;
+typedef WNDCLASS *PWNDCLASS;
+typedef WNDCLASS NEAR *NPWNDCLASS;
+typedef WNDCLASS FAR *LPWNDCLASS;
+
+#ifndef NOMSG
+
+/* Message structure */
+typedef struct tagMSG
+ {
+ HWND hwnd;
+ WORD message;
+ DWORD wParam;
+ LONG lParam;
+ DWORD time;
+ POINT pt;
+ } MSG;
+typedef MSG *PMSG;
+typedef MSG NEAR *NPMSG;
+typedef MSG FAR *LPMSG;
+
+#define POINTSTOPOINT(pt,pts) {(pt).x = (SHORT)LOWORD(pts); \
+ (pt).y = (SHORT)HIWORD(pts);}
+#define POINTTOPOINTS(pt) (MAKELONG((short)((pt).x), (short)((pt).y)))
+
+
+#endif /* NOMSG */
+
+#ifndef NOWINOFFSETS
+
+/* Window field offsets for GetWindowLong() and GetWindowWord() */
+#define GWL_WNDPROC (-4)
+#define GWW_HINSTANCE (-6)
+#define GWW_HWNDPARENT (-8)
+#define GWW_ID (-12)
+#define GWL_STYLE (-16)
+#define GWL_EXSTYLE (-20)
+#define GWL_USERDATA (-21)
+
+/* 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)
+
+#endif /* NOWINOFFSETS */
+
+#ifndef NOWINMESSAGES
+
+/* Window Messages */
+#define WM_NULL 0x0000
+#define WM_CREATE 0x0001
+#define WM_DESTROY 0x0002
+#define WM_MOVE 0x0003
+#define WM_SIZE 0x0005
+#define WM_ACTIVATE 0x0006
+#define WM_SETFOCUS 0x0007
+#define WM_KILLFOCUS 0x0008
+#define WM_ENABLE 0x000A
+#define WM_SETREDRAW 0x000B
+#define WM_SETTEXT 0x000C
+#define WM_GETTEXT 0x000D
+#define WM_GETTEXTLENGTH 0x000E
+#define WM_PAINT 0x000F
+#define WM_CLOSE 0x0010
+#define WM_QUERYENDSESSION 0x0011
+#define WM_QUIT 0x0012
+#define WM_QUERYOPEN 0x0013
+#define WM_ERASEBKGND 0x0014
+#define WM_SYSCOLORCHANGE 0x0015
+#define WM_ENDSESSION 0x0016
+#define WM_SHOWWINDOW 0x0018
+#define WM_CTLCOLOR 0x0019
+#define WM_WININICHANGE 0x001A
+#define WM_DEVMODECHANGE 0x001B
+#define WM_ACTIVATEAPP 0x001C
+#define WM_FONTCHANGE 0x001D
+#define WM_TIMECHANGE 0x001E
+#define WM_CANCELMODE 0x001F
+#define WM_SETCURSOR 0x0020
+#define WM_MOUSEACTIVATE 0x0021
+#define WM_CHILDACTIVATE 0x0022
+#define WM_QUEUESYNC 0x0023
+#define WM_GETMINMAXINFO 0x0024
+#define WM_PAINTICON 0x0026
+#define WM_ICONERASEBKGND 0x0027
+#define WM_NEXTDLGCTL 0x0028
+#define WM_SPOOLERSTATUS 0x002A
+#define WM_DRAWITEM 0x002B
+#define WM_MEASUREITEM 0x002C
+#define WM_DELETEITEM 0x002D
+#define WM_VKEYTOITEM 0x002E
+#define WM_CHARTOITEM 0x002F
+#define WM_SETFONT 0x0030
+#define WM_GETFONT 0x0031
+
+
+#define WM_QUERYDRAGICON 0x0037
+
+#define WM_COMPAREITEM 0x0039
+#define WM_COMPACTING 0x0041
+
+#define WM_NCCREATE 0x0081
+#define WM_NCDESTROY 0x0082
+#define WM_NCCALCSIZE 0x0083
+#define WM_NCHITTEST 0x0084
+#define WM_NCPAINT 0x0085
+#define WM_NCACTIVATE 0x0086
+#define WM_GETDLGCODE 0x0087
+#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
+
+#define WM_KEYFIRST 0x0100
+#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_KEYLAST 0x0108
+
+#define WM_INITDIALOG 0x0110
+#define WM_COMMAND 0x0111
+#define WM_SYSCOMMAND 0x0112
+#define WM_TIMER 0x0113
+#define WM_HSCROLL 0x0114
+#define WM_VSCROLL 0x0115
+#define WM_INITMENU 0x0116
+#define WM_INITMENUPOPUP 0x0117
+#define WM_MENUSELECT 0x011F
+#define WM_MENUCHAR 0x0120
+#define WM_ENTERIDLE 0x0121
+
+#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
+
+#define WM_MOUSEFIRST 0x0200
+#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
+#define WM_MOUSELAST 0x0209
+
+#define WM_PARENTNOTIFY 0x0210
+#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
+
+
+#define WM_CUT 0x0300
+#define WM_COPY 0x0301
+#define WM_PASTE 0x0302
+#define WM_CLEAR 0x0303
+#define WM_UNDO 0x0304
+#define WM_RENDERFORMAT 0x0305
+#define WM_RENDERALLFORMATS 0x0306
+#define WM_DESTROYCLIPBOARD 0x0307
+#define WM_DRAWCLIPBOARD 0x0308
+#define WM_PAINTCLIPBOARD 0x0309
+#define WM_VSCROLLCLIPBOARD 0x030A
+#define WM_SIZECLIPBOARD 0x030B
+#define WM_ASKCBFORMATNAME 0x030C
+#define WM_CHANGECBCHAIN 0x030D
+#define WM_HSCROLLCLIPBOARD 0x030E
+#define WM_QUERYNEWPALETTE 0x030F
+#define WM_PALETTEISCHANGING 0x0310
+#define WM_PALETTECHANGED 0x0311
+#define WM_HOTKEY 0x0312
+
+
+
+/* NOTE: All Message Numbers below 0x0400 are RESERVED. */
+
+/* Private Window Messages Start Here: */
+#define WM_USER 0x0400
+
+#ifndef NONCMESSAGES
+
+/* WM_SYNCTASK Commands */
+#define ST_BEGINSWP 0
+#define ST_ENDSWP 1
+
+/* WinWhere() Area Codes */
+#define HTERROR (-2)
+#define HTTRANSPARENT (-1)
+#define HTNOWHERE 0
+#define HTCLIENT 1
+#define HTCAPTION 2
+#define HTSYSMENU 3
+#define HTGROWBOX 4
+#define HTSIZE HTGROWBOX
+#define HTMENU 5
+#define HTHSCROLL 6
+#define HTVSCROLL 7
+#define HTREDUCE 8
+#define HTZOOM 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 HTSIZEFIRST HTLEFT
+#define HTSIZELAST HTBOTTOMRIGHT
+
+#endif /* NONCMESSAGES */
+
+/* WM_MOUSEACTIVATE Return Codes */
+#define MA_ACTIVATE 1
+#define MA_ACTIVATEANDEAT 2
+#define MA_NOACTIVATE 3
+
+WORD APIENTRY RegisterWindowMessage(IN LPSTR lpString);
+
+/* Size Message Commands */
+#define SIZENORMAL 0
+#define SIZEICONIC 1
+#define SIZEFULLSCREEN 2
+#define SIZEZOOMSHOW 3
+#define SIZEZOOMHIDE 4
+
+#ifndef NOKEYSTATES
+
+/* Key State Masks for Mouse Messages */
+#define MK_LBUTTON 0x0001
+#define MK_RBUTTON 0x0002
+#define MK_SHIFT 0x0004
+#define MK_CONTROL 0x0008
+#define MK_MBUTTON 0x0010
+
+#endif /* NOKEYSTATES */
+
+#endif /* NOWINMESSAGES */
+
+#ifndef NOWINSTYLES
+
+/* Window Styles */
+#define WS_OVERLAPPED 0x00000000L
+#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_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_GROUP 0x00020000L
+#define WS_TABSTOP 0x00010000L
+
+#define WS_MINIMIZEBOX 0x00020000L
+#define WS_MAXIMIZEBOX 0x00010000L
+
+#define WS_TILED WS_OVERLAPPED
+#define WS_ICONIC WS_MINIMIZE
+#define WS_SIZEBOX WS_THICKFRAME
+
+/* 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)
+
+#define WS_TILEDWINDOW (WS_OVERLAPPEDWINDOW)
+
+/* Extended Window Styles */
+#define WS_EX_DLGMODALFRAME 0x00000001L
+#define WS_EX_NOPARENTNOTIFY 0x00000004L
+
+/* Class styles */
+#define CS_VREDRAW 0x0001
+#define CS_HREDRAW 0x0002
+#define CS_KEYCVTWINDOW 0x0004
+#define CS_DBLCLKS 0x0008
+ /* 0x0010 - reserved (see user\server\macro.h) */
+#define CS_OWNDC 0x0020
+#define CS_CLASSDC 0x0040
+#define CS_PARENTDC 0x0080
+#define CS_NOKEYCVT 0x0100
+#define CS_NOCLOSE 0x0200
+#define CS_SAVEBITS 0x0800
+#define CS_BYTEALIGNCLIENT 0x1000
+#define CS_BYTEALIGNWINDOW 0x2000
+#define CS_GLOBALCLASS 0x4000 /* Global window class */
+
+#endif /* NOWINSTYLES */
+
+#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_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
+
+#endif /* NOCLIPBOARD */
+
+/*
+ * Defines for the fVirt field of the Accelerator table structure.
+ */
+#define FVIRTKEY TRUE /* Assumed to be == TRUE */
+#define FNOINVERT 0x02
+#define FSHIFT 0x04
+#define FCONTROL 0x08
+#define FALT 0x10
+
+typedef struct tagACCEL {
+ BYTE fVirt; /* Also called the flags field */
+ WORD key;
+ WORD cmd;
+} ACCEL;
+typedef ACCEL *PACCEL;
+
+typedef struct tagPAINTSTRUCT
+ {
+ HDC hdc;
+ BOOL fErase;
+ RECT rcPaint;
+ BOOL fRestore;
+ BOOL fIncUpdate;
+ BYTE rgbReserved[32];
+ } PAINTSTRUCT;
+typedef PAINTSTRUCT *PPAINTSTRUCT;
+typedef PAINTSTRUCT NEAR *NPPAINTSTRUCT;
+typedef PAINTSTRUCT FAR *LPPAINTSTRUCT;
+
+typedef struct tagCREATESTRUCT
+ {
+ LPSTR lpCreateParams;
+ HANDLE hInstance;
+ HANDLE hMenu;
+ HWND hwndParent;
+ int cy;
+ int cx;
+ int y;
+ int x;
+ LONG style;
+ LPSTR lpszName;
+ LPSTR lpszClass;
+ DWORD dwExStyle;
+ } CREATESTRUCT;
+typedef CREATESTRUCT FAR *LPCREATESTRUCT;
+
+
+/* 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
+
+/* MEASUREITEMSTRUCT for ownerdraw */
+typedef struct tagMEASUREITEMSTRUCT
+ {
+ WORD CtlType;
+ WORD CtlID;
+ WORD itemID;
+ WORD itemWidth;
+ WORD itemHeight;
+ DWORD itemData;
+ } MEASUREITEMSTRUCT;
+typedef MEASUREITEMSTRUCT NEAR *PMEASUREITEMSTRUCT;
+typedef MEASUREITEMSTRUCT FAR *LPMEASUREITEMSTRUCT;
+
+
+/* DRAWITEMSTRUCT for ownerdraw */
+typedef struct tagDRAWITEMSTRUCT
+ {
+ WORD CtlType;
+ WORD CtlID;
+ WORD itemID;
+ WORD itemAction;
+ WORD itemState;
+ HWND hwndItem;
+ HDC hDC;
+ RECT rcItem;
+ DWORD itemData;
+ } DRAWITEMSTRUCT;
+typedef DRAWITEMSTRUCT NEAR *PDRAWITEMSTRUCT;
+typedef DRAWITEMSTRUCT FAR *LPDRAWITEMSTRUCT;
+
+/* DELETEITEMSTRUCT for ownerdraw */
+typedef struct tagDELETEITEMSTRUCT
+ {
+ WORD CtlType;
+ WORD CtlID;
+ WORD itemID;
+ HWND hwndItem;
+ DWORD itemData;
+ } DELETEITEMSTRUCT;
+typedef DELETEITEMSTRUCT NEAR *PDELETEITEMSTRUCT;
+typedef DELETEITEMSTRUCT FAR *LPDELETEITEMSTRUCT;
+
+/* COMPAREITEMSTUCT for ownerdraw sorting */
+typedef struct tagCOMPAREITEMSTRUCT
+ {
+ WORD CtlType;
+ WORD CtlID;
+ HWND hwndItem;
+ WORD itemID1;
+ DWORD itemData1;
+ WORD itemID2;
+ DWORD itemData2;
+ } COMPAREITEMSTRUCT;
+typedef COMPAREITEMSTRUCT NEAR *PCOMPAREITEMSTRUCT;
+typedef COMPAREITEMSTRUCT FAR *LPCOMPAREITEMSTRUCT;
+
+#ifndef NOMSG
+
+/* Message Function Templates */
+BOOL APIENTRY CRITICAL GetMessage(OUT LPMSG lpMsg, IN HWND hWnd, IN WORD wMsgFilterMin, IN WORD wMsgFilterMax);
+BOOL APIENTRY CRITICAL TranslateMessage(IN LPMSG lpMsg);
+LONG APIENTRY CRITICAL DispatchMessage(IN LPMSG lpMsg);
+BOOL APIENTRY CRITICAL PeekMessage(OUT LPMSG lpMsg, IN HWND hWnd, IN WORD wMsgFilterMin, IN WORD wMsgFilterMax, IN WORD wRemoveMsg);
+
+/* PeekMessage() Options */
+#define PM_NOREMOVE 0x0000
+#define PM_REMOVE 0x0001
+#define PM_NOYIELD 0x0002
+
+#endif /* NOMSG */
+
+BOOL APIENTRY CRITICAL RegisterHotKey(IN HWND hwnd, IN int id, IN WORD fsModifiers, IN WORD vk);
+BOOL APIENTRY CRITICAL UnregisterHotKey(IN HWND hwnd, IN int id);
+
+#define MOD_ALT 0x0001
+#define MOD_CONTROL 0x0002
+#define MOD_SHIFT 0x0004
+
+#define IDHOT_SNAPWINDOW (-1) /* SHIFT-PRINTSCRN */
+#define IDHOT_SNAPDESKTOP (-2) /* PRINTSCRN */
+
+#ifdef WIN_INTERNAL
+ #ifndef LSTRING
+ #define NOLSTRING
+ #endif
+ #ifndef LFILEIO
+ #define NOLFILEIO
+ #endif
+#endif
+
+
+BOOL APIENTRY CRITICAL ExitWindows(IN DWORD dwReserved, IN WORD wReturnCode);
+
+BOOL APIENTRY CRITICAL SwapMouseButton(IN BOOL);
+DWORD APIENTRY CRITICAL GetMessagePos(void);
+LONG APIENTRY CRITICAL GetMessageTime(void);
+
+LONG APIENTRY CRITICAL SendMessage(IN HWND hWnd, IN WORD wMsg, IN DWORD wParam, IN LONG lParam);
+BOOL APIENTRY CRITICAL SendNotifyMessage(IN HWND hwnd, IN WORD wMsg, IN DWORD wParam, IN LONG lParam);
+BOOL APIENTRY CRITICAL PostMessage(IN HWND hWnd, IN WORD wMsg, IN DWORD wParam, IN LONG lParam);
+BOOL APIENTRY CRITICAL PostAppMessage(IN DWORD hTask, IN WORD wMsg, IN DWORD wParam, IN LONG lParam);
+BOOL APIENTRY ReplyMessage(IN LONG);
+void APIENTRY WaitMessage(void);
+LONG APIENTRY CRITICAL DefWindowProc(IN HWND hWnd, IN WORD wMsg, IN DWORD wParam, IN LONG lParam);
+void APIENTRY PostQuitMessage(IN int nExitCode);
+LONG APIENTRY CRITICAL CallWindowProc(IN WNDPROC lpPrevWndFunc, IN HWND hWnd, IN WORD wMsg, IN DWORD wParam, IN LONG lParam);
+BOOL APIENTRY InSendMessage(void);
+
+WORD APIENTRY CRITICAL GetDoubleClickTime(void);
+void APIENTRY CRITICAL SetDoubleClickTime(IN WORD);
+
+BOOL APIENTRY CRITICAL RegisterClass(IN LPWNDCLASS lpWndClass);
+BOOL APIENTRY CRITICAL UnregisterClass(IN LPSTR lpClassName, IN HANDLE hInstance);
+BOOL APIENTRY CRITICAL GetClassInfo(IN HANDLE hInstance, IN LPSTR lpClassName,
+ OUT LPWNDCLASS lpWndClass);
+
+BOOL APIENTRY SetMessageQueue(int);
+
+#define CW_USEDEFAULT ((int)0x8000)
+HWND APIENTRY CRITICAL CreateWindow(IN LPSTR lpClassName, IN LPSTR lpWindowName, IN DWORD dwStyle, IN int X, IN int Y, IN int nWidth, IN int nHeight, IN HWND hwndParent, IN HMENU hMenu, IN HANDLE hInstance, IN LPSTR lpParam);
+HWND APIENTRY CRITICAL CreateWindowEx(IN DWORD dwExStyle, IN LPSTR lpClassName, IN LPSTR lpWindowName, IN DWORD dwStyle, IN int X, IN int Y, IN int nWidth, IN int nHeight, IN HWND hWndParent, IN HMENU hMenu, IN HANDLE hInstance, IN LPSTR lpParam);
+
+BOOL APIENTRY CRITICAL IsWindow(IN HWND hWnd);
+BOOL APIENTRY CRITICAL IsChild(IN HWND hWndParent, IN HWND hWnd);
+BOOL APIENTRY CRITICAL DestroyWindow(IN HWND hWnd);
+
+BOOL APIENTRY CRITICAL ShowWindow(IN HWND hWnd, IN int nCmdShow);
+BOOL APIENTRY CRITICAL FlashWindow(IN HWND hWnd, IN BOOL bInvert);
+void APIENTRY CRITICAL ShowOwnedPopups(IN HWND hWnd, IN BOOL fShow);
+
+BOOL APIENTRY CRITICAL OpenIcon(IN HWND hWnd);
+void APIENTRY CRITICAL CloseWindow(IN HWND hWnd);
+void APIENTRY CRITICAL MoveWindow(IN HWND hWnd, IN int X, IN int Y, IN int nWidth, IN int nHeight, IN BOOL bRepaint);
+void APIENTRY CRITICAL SetWindowPos(IN HWND hWnd, IN HWND hWndInsertAfter, IN int X, IN int Y, IN int cx, IN int cy, IN WORD wFlags);
+
+#ifndef NODEFERWINDOWPOS
+
+HANDLE APIENTRY CRITICAL BeginDeferWindowPos(IN int nNumWindows);
+HANDLE APIENTRY CRITICAL DeferWindowPos(IN HANDLE hWinPosInfo, IN HWND hWnd, IN HWND hWndInsertAfter, IN int x, IN int y, IN int cx, IN int cy, IN DWORD wFlags);
+void APIENTRY CRITICAL EndDeferWindowPos(IN HANDLE hWinPosInfo);
+
+#endif /* NODEFERWINDOWPOS */
+
+BOOL APIENTRY CRITICAL IsWindowVisible(IN HWND hWnd);
+BOOL APIENTRY CRITICAL IsIconic(IN HWND hWnd);
+BOOL APIENTRY CRITICAL AnyPopup(void);
+void APIENTRY CRITICAL BringWindowToTop(IN HWND hWnd);
+BOOL APIENTRY CRITICAL IsZoomed(IN HWND hWnd);
+
+/* SetWindowPos Flags */
+#define SWP_NOSIZE 0x0001
+#define SWP_NOMOVE 0x0002
+#define SWP_NOZORDER 0x0004
+#define SWP_NOREDRAW 0x0008
+#define SWP_NOACTIVATE 0x0010
+#define SWP_DRAWFRAME 0x0020
+#define SWP_SHOWWINDOW 0x0040
+#define SWP_HIDEWINDOW 0x0080
+#define SWP_NOCOPYBITS 0x0100
+#define SWP_NOREPOSITION 0x0200
+
+#ifndef NOCTLMGR
+
+HWND APIENTRY CRITICAL CreateDialog(IN HANDLE hInstance, IN LPSTR lpTemplateName, IN HWND hWndParent, IN WNDPROC lpDialogFunc);
+HWND APIENTRY CRITICAL CreateDialogIndirect(IN HANDLE hInstance, IN LPSTR lpTemplate, IN HWND hWndParent, IN WNDPROC lpDialogFunc);
+HWND APIENTRY CRITICAL CreateDialogParam(IN HANDLE hInstance, IN LPSTR lpTemplateName, IN HWND hWndParent, IN WNDPROC lpDialogFunc, IN LONG dwInitParam);
+HWND APIENTRY CRITICAL CreateDialogIndirectParam(IN HANDLE hInstance, IN LPSTR lpTemplate, IN HWND hWndParent, IN WNDPROC lpDialogFunc, IN LONG dwInitParam);
+int APIENTRY CRITICAL DialogBox(IN HANDLE hInstance, IN LPSTR lpTemplateName, IN HWND hWndParent, IN WNDPROC lpDialogFunc);
+int APIENTRY CRITICAL DialogBoxIndirect(IN HANDLE hInstance, IN HANDLE hDialogTemplate, IN HWND hWndParent, IN WNDPROC lpDialogFunc);
+int APIENTRY CRITICAL DialogBoxParam(IN HANDLE hInstance, IN LPSTR lpTemplateName, IN HWND hWndParent, IN WNDPROC lpDialogFunc, IN LONG dwInitParam);
+int APIENTRY CRITICAL DialogBoxIndirectParam(IN HANDLE hInstance, IN HANDLE hDialogTemplate, IN HWND hWndParent, IN WNDPROC lpDialogFunc, IN LONG dwInitParam);
+void APIENTRY CRITICAL EndDialog(IN HWND hDlg, IN int nResult);
+HWND APIENTRY CRITICAL GetDlgItem(IN HWND hDlg, IN int nIDDlgItem);
+void APIENTRY CRITICAL SetDlgItemInt(IN HWND hDlg, IN int nIDDlgItem, IN int wValue, IN BOOL bSigned);
+int APIENTRY CRITICAL GetDlgItemInt(IN HWND hDlg, IN int nIDDlgItem, OUT BOOL * lpTranslated, IN BOOL bSigned);
+void APIENTRY CRITICAL SetDlgItemText(IN HWND hDlg, IN int nIDDlgItem, IN LPSTR lpString);
+int APIENTRY CRITICAL GetDlgItemText(IN HWND hDlg, IN int nIDDlgItem, OUT LPSTR lpString, IN int nMaxCount);
+void APIENTRY CRITICAL CheckDlgButton(IN HWND hDlg, IN int nIDButton, IN WORD wCheck);
+void APIENTRY CRITICAL CheckRadioButton(IN HWND hDlg, IN int nIDFirstButton, IN int nIDLastButton, IN int nIDCheckButton);
+WORD APIENTRY CRITICAL IsDlgButtonChecked(IN HWND hDlg, IN int nIDButton);
+LONG APIENTRY CRITICAL SendDlgItemMessage(IN HWND hDlg, IN int nIDDlgItem, IN WORD wMsg, IN DWORD wParam, IN LONG lParam);
+HWND APIENTRY CRITICAL GetNextDlgGroupItem(IN HWND hDlg, IN HWND hCtl, IN BOOL bPrevious);
+HWND APIENTRY CRITICAL GetNextDlgTabItem(IN HWND hDlg, IN HWND hCtl, IN BOOL bPrevious);
+int APIENTRY CRITICAL GetDlgCtrlID(IN HWND hWnd);
+long APIENTRY CRITICAL GetDialogBaseUnits(void);
+LONG APIENTRY CRITICAL DefDlgProc(IN HWND hDlg, IN WORD wMsg, IN DWORD wParam, IN LONG lParam);
+
+#define DLGWINDOWEXTRA 30 /* Window extra byted needed for private dialog classes */
+
+#endif /* NOCTLMGR */
+
+#ifndef NOMSG
+BOOL APIENTRY CallMsgFilter(IN LPMSG lpMsg, IN int nCode);
+#endif
+
+#ifndef NOCLIPBOARD
+
+/* Clipboard Manager Functions */
+BOOL APIENTRY CRITICAL OpenClipboard(IN HWND hWnd);
+BOOL APIENTRY CRITICAL CloseClipboard(void);
+HWND APIENTRY CRITICAL GetClipboardOwner(void);
+HWND APIENTRY CRITICAL SetClipboardViewer(IN HWND);
+HWND APIENTRY CRITICAL GetClipboardViewer(void);
+BOOL APIENTRY CRITICAL ChangeClipboardChain(IN HWND, IN HWND);
+HANDLE APIENTRY CRITICAL SetClipboardData(IN WORD wFormat, IN HANDLE hMem);
+HANDLE APIENTRY CRITICAL GetClipboardData(IN WORD wFormat);
+WORD APIENTRY CRITICAL RegisterClipboardFormat(IN LPSTR);
+int APIENTRY CRITICAL CountClipboardFormats(void);
+WORD APIENTRY CRITICAL EnumClipboardFormats(IN WORD);
+int APIENTRY CRITICAL GetClipboardFormatName(IN WORD, IN LPSTR, IN int);
+BOOL APIENTRY CRITICAL EmptyClipboard(void);
+BOOL APIENTRY CRITICAL IsClipboardFormatAvailable(IN WORD);
+int APIENTRY CRITICAL GetPriorityClipboardFormat(IN WORD *, IN int);
+
+#endif /* NOCLIPBOARD */
+
+HWND APIENTRY CRITICAL SetFocus(IN HWND hWnd);
+HWND APIENTRY CRITICAL GetFocus(void);
+HWND APIENTRY CRITICAL GetActiveWindow(void);
+SHORT APIENTRY GetKeyState(IN int nVirtKey);
+SHORT APIENTRY GetAsyncKeyState(IN int vKey);
+void APIENTRY GetKeyboardState(IN BYTE *);
+void APIENTRY SetKeyboardState(IN BYTE *);
+BOOL APIENTRY EnableHardwareInput(IN BOOL);
+BOOL APIENTRY GetInputState(void);
+DWORD APIENTRY GetQueueStatus(void);
+HWND APIENTRY CRITICAL GetCapture(void);
+HWND APIENTRY CRITICAL SetCapture(IN HWND hWnd);
+void APIENTRY CRITICAL ReleaseCapture(void);
+DWORD APIENTRY CRITICAL MsgWaitForMultipleObjects(IN DWORD, IN LPHANDLE,
+ IN BOOL, IN DWORD, IN DWORD);
+
+/* Queue status flags for GetQueueStatus() and MsgWaitForMultipleObjects() */
+#define QS_MOUSEBUTTON 0x01
+#define QS_MOUSEMOVE 0x02
+#define QS_KEYBOARD 0x04
+#define QS_POSTMSG 0x08
+#define QS_TIMER 0x10
+#define QS_PAINT 0x20
+#define QS_SENDMSG 0x80
+#define QS_HOTKEY 0x100
+#define QS_INPUT (QS_MOUSEBUTTON | QS_MOUSEMOVE | QS_KEYBOARD)
+#define QS_ALLEVENTS (QS_INPUT | QS_POSTMSG | QS_TIMER | QS_PAINT | QS_HOTKEY)
+
+
+/* Windows Functions */
+WORD APIENTRY CRITICAL SetTimer(IN HWND hWnd, IN int nIDEvent, IN WORD wElapse, IN WNDPROC lpTimerFunc);
+BOOL APIENTRY CRITICAL KillTimer(IN HWND hWnd, IN int nIDEvent);
+
+BOOL APIENTRY CRITICAL EnableWindow(IN HWND hWnd, IN BOOL bEnable);
+BOOL APIENTRY CRITICAL IsWindowEnabled(IN HWND hWnd);
+
+HANDLE APIENTRY CRITICAL LoadAccelerators(IN HANDLE hInstance, IN LPSTR lpTableName);
+HANDLE APIENTRY CRITICAL CreateAcceleratorTable(IN PACCEL, IN int);
+BOOL APIENTRY DestroyAcceleratorTable(HANDLE);
+int APIENTRY CopyAcceleratorTable(HANDLE, PACCEL, int);
+
+#ifndef NOMSG
+int APIENTRY CRITICAL TranslateAccelerator(IN HWND hWnd, IN HANDLE hAccTable, IN LPMSG lpMsg);
+#endif
+
+#ifndef NOSYSMETRICS
+
+/* 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
+#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_CMETRICS 42
+
+int APIENTRY CRITICAL GetSystemMetrics(IN int nIndex);
+
+#endif /* NOSYSMETRICS */
+
+#ifndef NOMENUS
+
+HMENU APIENTRY CRITICAL LoadMenu(IN HANDLE hInstance, IN LPSTR lpMenuName);
+HMENU APIENTRY CRITICAL LoadMenuIndirect(IN LPSTR lpMenuTemplate);
+HMENU APIENTRY CRITICAL GetMenu(IN HWND hWnd);
+BOOL APIENTRY CRITICAL SetMenu(IN HWND hWnd, IN HMENU hMenu);
+BOOL APIENTRY CRITICAL ChangeMenu(IN HMENU, IN WORD, IN LPSTR, IN DWORD, IN WORD);
+BOOL APIENTRY CRITICAL HiliteMenuItem(IN HWND hWnd, IN HMENU hMenu, IN WORD wIDHiliteItem, IN WORD wHilite);
+int APIENTRY CRITICAL GetMenuString(IN HMENU hMenu, IN WORD wIDItem, OUT LPSTR lpString, IN int nMaxCount, IN WORD wFlag);
+DWORD APIENTRY CRITICAL GetMenuState(IN HMENU hMenu, IN WORD wId, IN WORD wFlags);
+void APIENTRY CRITICAL DrawMenuBar(IN HWND hWnd);
+HMENU APIENTRY CRITICAL GetSystemMenu(IN HWND hWnd, IN BOOL bRevert);
+HMENU APIENTRY CRITICAL CreateMenu(void);
+HMENU APIENTRY CRITICAL CreatePopupMenu(void);
+BOOL APIENTRY CRITICAL DestroyMenu(IN HMENU hMenu);
+DWORD APIENTRY CRITICAL CheckMenuItem(IN HMENU hMenu, IN WORD wIDCheckItem, IN DWORD wCheck);
+DWORD APIENTRY CRITICAL EnableMenuItem(IN HMENU hMenu, IN WORD wIDEnableItem, IN DWORD wEnable);
+HMENU APIENTRY CRITICAL GetSubMenu(IN HMENU hMenu, IN int nPos);
+WORD APIENTRY CRITICAL GetMenuItemID(IN HMENU hMenu, IN int nPos);
+WORD APIENTRY CRITICAL GetMenuItemCount(IN HMENU hMenu);
+
+BOOL APIENTRY CRITICAL InsertMenu(IN HMENU hMenu, IN WORD nPosition, IN DWORD wFlags, IN DWORD wIDNewItem, IN LPSTR lpNewItem);
+BOOL APIENTRY CRITICAL AppendMenu(IN HMENU hMenu, IN DWORD wFlags, IN DWORD wIDNewItem, IN LPSTR lpNewItem);
+BOOL APIENTRY CRITICAL ModifyMenu(IN HMENU hMenu, IN WORD nPosition, IN DWORD wFlags, IN DWORD wIDNewItem, IN LPSTR lpNewItem);
+BOOL APIENTRY CRITICAL RemoveMenu(IN HMENU hMenu, IN WORD nPosition, IN WORD wFlags);
+BOOL APIENTRY CRITICAL DeleteMenu(IN HMENU hMenu, IN WORD nPosition, IN WORD wFlags);
+BOOL APIENTRY CRITICAL SetMenuItemBitmaps(IN HMENU hMenu, IN WORD nPosition, IN WORD wFlags, IN HBITMAP hBitmapUnchecked, IN HBITMAP hBitmapChecked);
+DWORD APIENTRY CRITICAL GetMenuCheckMarkDimensions(void);
+BOOL APIENTRY CRITICAL TrackPopupMenu(IN HMENU hMenu, IN WORD wFlags, IN int x, IN int y, IN int nReserved, IN HWND hWnd, IN LPRECT lpRect);
+
+#endif /* NOMENUS */
+
+BOOL APIENTRY DrawIcon(HDC, int, int, HICON);
+int APIENTRY DrawText(IN HDC hDC, IN LPSTR lpString, IN int nCount, IN LPRECT lpRect, IN WORD wFormat);
+BOOL APIENTRY GrayString(IN HDC hDC, IN HBRUSH hBrush, IN FARPROC lpOutputFunc, IN DWORD lpData, IN int nCount, IN int X, IN int Y, IN int nWidth, IN int nHeight);
+LONG APIENTRY TabbedTextOut(IN HDC hDC, IN int X, IN int Y, IN LPSTR lpString, IN int nCount, IN int nTabPositions, IN LPINT lpnTabStopPositions, IN int nTabOrigin);
+DWORD APIENTRY GetTabbedTextExtent(IN HDC hDC, IN LPSTR lpString, IN int nCount, IN int nTabPositions, IN LPINT lpnTabStopPositions);
+
+void APIENTRY CRITICAL UpdateWindow(IN HWND hWnd);
+HWND APIENTRY CRITICAL SetActiveWindow(IN HWND hWnd);
+
+HDC APIENTRY CRITICAL GetDC(IN HWND hWnd);
+HDC APIENTRY CRITICAL GetWindowDC(IN HWND hWnd);
+int APIENTRY CRITICAL ReleaseDC(IN HWND hWnd, IN HDC hDC);
+
+HDC APIENTRY CRITICAL BeginPaint(IN HWND hWnd, OUT LPPAINTSTRUCT lpPaint);
+void APIENTRY CRITICAL EndPaint(IN HWND hWnd, IN LPPAINTSTRUCT lpPaint);
+BOOL APIENTRY CRITICAL GetUpdateRect(IN HWND hWnd, OUT LPRECT lpRect, IN BOOL bErase);
+int APIENTRY CRITICAL GetUpdateRgn(IN HWND hWnd, IN HRGN hRgn, IN BOOL bErase);
+
+int APIENTRY CRITICAL ExcludeUpdateRgn(IN HDC hDC, IN HWND hWnd);
+
+void APIENTRY CRITICAL InvalidateRect(IN HWND hWnd, IN LPRECT lpRect, IN BOOL bErase);
+void APIENTRY CRITICAL ValidateRect(IN HWND hWnd, IN LPRECT lpRect);
+
+void APIENTRY CRITICAL InvalidateRgn(IN HWND hWnd, IN HRGN hRgn, IN BOOL bErase);
+void APIENTRY CRITICAL ValidateRgn(IN HWND hWnd, IN HRGN hRgn);
+
+void APIENTRY CRITICAL ScrollWindow(IN HWND hWnd, IN int XAmount, IN int YAmount, IN LPRECT lpRect, IN LPRECT lpClipRect);
+BOOL APIENTRY CRITICAL ScrollDC(IN HDC hDC, IN int dx, IN int dy, IN LPRECT lprcScroll, IN LPRECT lprcClip, IN HRGN hrgnUpdate, OUT LPRECT lprcUpdate);
+
+#ifndef NOSCROLL
+int APIENTRY CRITICAL SetScrollPos(IN HWND hWnd, IN int nBar, IN int nPos, IN BOOL bRedraw);
+int APIENTRY CRITICAL GetScrollPos(IN HWND hWnd, IN int nBar);
+void APIENTRY CRITICAL SetScrollRange(IN HWND hWnd, IN int nBar, IN int nMinPos, IN int nMaxPos, IN BOOL bRedraw);
+void APIENTRY CRITICAL GetScrollRange(IN HWND hWnd, IN int nBar, OUT LPINT lpMinPos, OUT LPINT lpMaxPos);
+void APIENTRY CRITICAL ShowScrollBar(IN HWND hWnd, IN WORD wBar, IN BOOL bShow);
+#endif
+
+BOOL APIENTRY CRITICAL SetProp(IN HWND hWnd, IN LPSTR lpString, IN HANDLE hData);
+HANDLE APIENTRY CRITICAL GetProp(IN HWND hWnd, IN LPSTR lpString);
+HANDLE APIENTRY CRITICAL RemoveProp(IN HWND hWnd, IN LPSTR lpString);
+int APIENTRY CRITICAL EnumProps(IN HWND hWnd, IN FARPROC lpEnumFunc);
+void APIENTRY CRITICAL SetWindowText(IN HWND hWnd, IN LPSTR lpString);
+int APIENTRY CRITICAL GetWindowText(IN HWND hWnd, OUT LPSTR lpString, IN int nMaxCount);
+int APIENTRY CRITICAL GetWindowTextLength(IN HWND hWnd);
+
+void APIENTRY CRITICAL GetClientRect(IN HWND hWnd, OUT LPRECT lpRect);
+void APIENTRY CRITICAL GetWindowRect(IN HWND hWnd, OUT LPRECT lpRect);
+void APIENTRY CRITICAL AdjustWindowRect(IN LPRECT lpRect, IN LONG dwStyle, IN BOOL bMenu);
+void APIENTRY CRITICAL AdjustWindowRectEx(IN LPRECT lpRect, IN LONG dwStyle, IN BOOL bMenu, IN DWORD dwExStyle);
+
+#ifndef NOMB
+
+/* 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
+
+int APIENTRY CRITICAL MessageBox(IN HWND hWnd, IN LPSTR lpText, IN LPSTR lpCaption, IN WORD wType);
+void APIENTRY MessageBeep(IN WORD wType);
+
+#endif /* NOMB */
+
+int APIENTRY CRITICAL ShowCursor(IN BOOL bShow);
+void APIENTRY CRITICAL SetCursorPos(IN int X, IN int Y);
+HCURSOR APIENTRY CRITICAL SetCursor(IN HCURSOR hCursor);
+void APIENTRY CRITICAL GetCursorPos(OUT LPPOINT lpPoint);
+void APIENTRY CRITICAL ClipCursor(IN LPRECT lpRect);
+
+void APIENTRY CRITICAL CreateCaret(IN HWND hWnd, IN HBITMAP hBitmap, IN int nWidth, IN int nHeight);
+WORD APIENTRY CRITICAL GetCaretBlinkTime(void);
+void APIENTRY CRITICAL SetCaretBlinkTime(IN WORD wMSeconds);
+void APIENTRY CRITICAL DestroyCaret(void);
+void APIENTRY CRITICAL HideCaret(IN HWND hWnd);
+void APIENTRY CRITICAL ShowCaret(IN HWND hWnd);
+void APIENTRY CRITICAL SetCaretPos(IN int X, IN int Y);
+void APIENTRY CRITICAL GetCaretPos(OUT LPPOINT lpPoint);
+
+void APIENTRY CRITICAL ClientToScreen(IN HWND hWnd, IN OUT LPPOINT lpPoint);
+void APIENTRY CRITICAL ScreenToClient(IN HWND hWnd, IN OUT LPPOINT lpPoint);
+HWND APIENTRY CRITICAL WindowFromPoint(IN POINT Point);
+HWND APIENTRY CRITICAL ChildWindowFromPoint(IN HWND hWndParent, IN POINT Point);
+
+#ifndef NOCOLOR
+
+/* Color Types */
+#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 /* three bits max */
+
+#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
+#define COLOR_ENDCOLORS COLOR_BTNTEXT
+
+DWORD APIENTRY CRITICAL GetSysColor(IN int nIndex);
+void APIENTRY CRITICAL SetSysColors(int, LPINT, LONG *);
+
+#endif /* NOCOLOR */
+
+void APIENTRY DrawFocusRect(HDC, LPRECT);
+int APIENTRY FillRect(HDC, LPRECT, HBRUSH);
+int APIENTRY FrameRect(HDC, LPRECT, HBRUSH);
+void APIENTRY InvertRect(HDC, LPRECT);
+void APIENTRY SetRect(LPRECT, int, int, int, int);
+void APIENTRY SetRectEmpty(LPRECT);
+int APIENTRY CopyRect(LPRECT, LPRECT);
+void APIENTRY InflateRect(LPRECT, int, int);
+int APIENTRY IntersectRect(LPRECT, LPRECT, LPRECT);
+int APIENTRY UnionRect(LPRECT, LPRECT, LPRECT);
+void APIENTRY OffsetRect(LPRECT, int, int);
+BOOL APIENTRY IsRectEmpty(LPRECT);
+BOOL APIENTRY EqualRect(LPRECT, LPRECT);
+BOOL APIENTRY PtInRect(LPRECT, POINT);
+DWORD APIENTRY GetCurrentTime(void);
+
+#ifndef NOWINOFFSETS
+
+DWORD APIENTRY CRITICAL GetWindowWord(IN HWND hWnd, IN int nIndex);
+DWORD APIENTRY CRITICAL SetWindowWord(IN HWND hWnd, IN int nIndex, IN DWORD wNewWord);
+LONG APIENTRY CRITICAL GetWindowLong(IN HWND hWnd, IN int nIndex);
+LONG APIENTRY CRITICAL SetWindowLong(IN HWND hWnd, IN int nIndex, IN LONG dwNewLong);
+DWORD APIENTRY CRITICAL GetClassWord(IN HWND hWnd, IN int nIndex);
+DWORD APIENTRY CRITICAL SetClassWord(IN HWND hWnd, IN int nIndex, IN DWORD wNewWord);
+DWORD APIENTRY CRITICAL GetClassLong(IN HWND hWnd, IN int nIndex);
+DWORD APIENTRY CRITICAL SetClassLong(IN HWND hWnd, IN int nIndex, IN DWORD dwNewLong);
+HWND APIENTRY CRITICAL GetDesktopWindow(void);
+
+#endif /* NOWINOFFSETS */
+
+HWND APIENTRY CRITICAL GetParent(IN HWND hWnd);
+HWND APIENTRY CRITICAL SetParent(IN HWND hWndChild, IN HWND hWndNewParent);
+BOOL APIENTRY CRITICAL EnumChildWindows(IN HWND hWndParent, IN FARPROC lpEnumFunc, IN LONG lParam);
+HWND APIENTRY CRITICAL FindWindow(IN LPSTR lpClassName, IN LPSTR lpWindowName);
+BOOL APIENTRY CRITICAL EnumWindows(IN FARPROC lpEnumFunc, IN LONG lParam);
+BOOL APIENTRY CRITICAL EnumTaskWindows(IN HANDLE hTask, IN FARPROC lpEnumFunc, IN LONG lParam);
+int APIENTRY CRITICAL GetClassName(IN HWND hWnd, OUT LPSTR lpClassName, IN int nMaxCount);
+HWND APIENTRY CRITICAL GetTopWindow(IN HWND hWnd);
+//HWND APIENTRY CRITICAL GetNextWindow(HWND, WORD);
+#define GetNextWindow(hwnd, wCmd) GetWindow(hwnd, wCmd)
+#define GetSysModalWindow() (NULL)
+#define SetSysModalWindow(hwnd) (NULL)
+HANDLE APIENTRY CRITICAL GetWindowTask(IN HWND hWnd);
+HWND APIENTRY CRITICAL GetLastActivePopup(IN HWND hWnd);
+
+/* 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
+
+HWND APIENTRY CRITICAL GetWindow(IN HWND hWnd, IN WORD wCmd);
+
+#ifndef NOWH
+PROC APIENTRY CRITICAL SetWindowsHook(IN int nFilterType, IN PROC pfnFilterProc);
+BOOL APIENTRY CRITICAL UnhookWindowsHook(IN int nCode, IN PROC pfnFilterProc);
+HHOOK APIENTRY CRITICAL SetWindowsHookEx(IN HANDLE hmod, IN DWORD dwThreadId,
+ IN int nFilterType, IN PROC pfnFilterProc);
+BOOL APIENTRY CRITICAL UnhookWindowsHookEx(IN HHOOK hhk);
+DWORD APIENTRY CRITICAL CallNextHookProc(IN HHOOK hhk, IN int nCode,
+ IN DWORD wParam, IN DWORD lParam);
+
+/*
+ * Macros for source-level compatibility with old functions.
+ */
+#define DefHookProc(nCode, wParam, lParam, ppfnNextHook)\
+ CallNextHookProc(*(HHOOK *)ppfnNextHook, nCode, wParam, lParam)
+#endif
+
+#ifndef NOMENUS
+
+/* Menu flags for Add/Check/EnableMenuItem() */
+#define MF_INSERT 0x0000
+#define MF_CHANGE 0x0080
+#define MF_APPEND 0x0100
+#define MF_DELETE 0x0200
+#define MF_REMOVE 0x1000
+
+#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
+
+/* Menu item resource format */
+typedef struct
+ {
+ WORD versionNumber;
+ WORD offset;
+ } MENUITEMTEMPLATEHEADER;
+
+typedef struct
+ {
+ WORD mtOption;
+ WORD mtID;
+ char mtString[1];
+ } MENUITEMTEMPLATE;
+
+#define MF_END 0x0080
+
+#endif /* NOMENUS */
+
+#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_ICON SC_MINIMIZE
+#define SC_ZOOM SC_MAXIMIZE
+
+#endif /* NOSYSCOMMANDS */
+
+/* Resource Loading Routines */
+HBITMAP APIENTRY LoadBitmap(IN HANDLE hInstance, IN LPSTR lpBitmapName);
+HCURSOR APIENTRY CRITICAL LoadCursor(IN HANDLE hInstance, IN LPSTR lpCursorName);
+HCURSOR APIENTRY CRITICAL CreateCursor(HANDLE, int, int, int, int, LPSTR, LPSTR);
+BOOL APIENTRY CRITICAL DestroyCursor(HCURSOR);
+
+/* Standard Cursor 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)
+
+HICON APIENTRY CRITICAL LoadIcon(IN HANDLE hInstance, IN LPSTR lpIconName);
+HICON APIENTRY CRITICAL CreateIcon(HANDLE, int, int, BYTE, BYTE, LPSTR, LPSTR);
+BOOL APIENTRY CRITICAL DestroyIcon(HICON);
+
+#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
+
+#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 */
+
+#define ORD_LANGDRIVER 1 /* The ordinal number for the entry point of
+ ** language drivers.
+ */
+
+#ifndef NOICONS
+
+/* Standard Icon 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 */
+
+int APIENTRY LoadString(IN HANDLE hInstance, IN WORD wID, OUT LPSTR lpBuffer, IN int nBufferMax);
+
+#ifndef NOKANJI
+
+#define CP_HWND 0
+#define CP_OPEN 1
+#define CP_DIRECT 2
+
+/* VK from the keyboard driver */
+#define VK_KANA 0x15
+#define VK_ROMAJI 0x16
+#define VK_ZENKAKU 0x17
+#define VK_HIRAGANA 0x18
+#define VK_KANJI 0x19
+
+/* VK to send to Applications */
+#define VK_CONVERT 0x1C
+#define VK_NONCONVERT 0x1D
+#define VK_ACCEPT 0x1E
+#define VK_MODECHANGE 0x1F
+
+/* Conversion function numbers */
+#define KNJ_START 0x01
+#define KNJ_END 0x02
+#define KNJ_QUERY 0x03
+
+#define KNJ_LEARN_MODE 0x10
+#define KNJ_GETMODE 0x11
+#define KNJ_SETMODE 0x12
+
+#define KNJ_CODECONVERT 0x20
+#define KNJ_CONVERT 0x21
+#define KNJ_NEXT 0x22
+#define KNJ_PREVIOUS 0x23
+#define KNJ_ACCEPT 0x24
+
+#define KNJ_LEARN 0x30
+#define KNJ_REGISTER 0x31
+#define KNJ_REMOVE 0x32
+#define KNJ_CHANGE_UDIC 0x33
+
+/* NOTE: DEFAULT = 0
+ * JIS1 = 1
+ * JIS2 = 2
+ * SJIS2 = 3
+ * JIS1KATAKANA = 4
+ * SJIS2HIRAGANA = 5
+ * SJIS2KATAKANA = 6
+ * OEM = F
+ */
+
+#define KNJ_JIS1toJIS1KATAKANA 0x14
+#define KNJ_JIS1toSJIS2 0x13
+#define KNJ_JIS1toSJIS2HIRAGANA 0x15
+#define KNJ_JIS1toSJIS2KATAKANA 0x16
+#define KNJ_JIS1toDEFAULT 0x10
+#define KNJ_JIS1toSJIS2OEM 0x1F
+#define KNJ_JIS2toSJIS2 0x23
+#define KNJ_SJIS2toJIS2 0x32
+
+#define KNJ_MD_ALPHA 0x01
+#define KNJ_MD_HIRAGANA 0x02
+#define KNJ_MD_HALF 0x04
+#define KNJ_MD_JIS 0x08
+#define KNJ_MD_SPECIAL 0x10
+
+#define KNJ_CVT_NEXT 0x01
+#define KNJ_CVT_PREV 0x02
+#define KNJ_CVT_KATAKANA 0x03
+#define KNJ_CVT_HIRAGANA 0x04
+#define KNJ_CVT_JIS1 0x05
+#define KNJ_CVT_SJIS2 0x06
+#define KNJ_CVT_DEFAULT 0x07
+#define KNJ_CVT_TYPED 0x08
+
+typedef struct
+{
+ int fnc;
+ int wParam;
+ LPSTR lpSource;
+ LPSTR lpDest;
+ int wCount;
+ LPSTR lpReserved1;
+ LPSTR lpReserved2;
+} KANJISTRUCT, FAR *LPKANJISTRUCT;
+
+int APIENTRY ConvertRequest(HWND, LPKANJISTRUCT);
+BOOL APIENTRY SetConvertParams(int, int);
+VOID APIENTRY SetConvertHook(BOOL);
+
+#endif
+
+/* Key Conversion Window */
+BOOL APIENTRY IsTwoByteCharPrefix(char);
+
+/* Dialog Box Command IDs */
+#define IDOK 1
+#define IDCANCEL 2
+#define IDABORT 3
+#define IDRETRY 4
+#define IDIGNORE 5
+#define IDYES 6
+#define IDNO 7
+
+#ifndef NOCTLMGR
+
+/* Control Manager Structures and Definitions */
+
+#ifndef NOWINSTYLES
+
+/* 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
+
+
+#endif /* NOWINSTYLES */
+
+/* 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
+
+#ifndef NOWINMESSAGES
+
+/* Edit Control Messages */
+#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)
+#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)
+#define EM_LINELENGTH (WM_USER+17)
+#define EM_REPLACESEL (WM_USER+18)
+#define EM_SETFONT (WM_USER+19)
+#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)
+#define EM_SETTABSTOPS (WM_USER+27)
+#define EM_SETPASSWORDCHAR (WM_USER+28)
+#define EM_EMPTYUNDOBUFFER (WM_USER+29)
+#define EM_MSGMAX (WM_USER+30)
+
+#endif /* NOWINMESSAGES */
+
+/* Button Control Styles */
+#define BS_PUSHBUTTON 0x00L
+#define BS_DEFPUSHBUTTON 0x01L
+#define BS_CHECKBOX 0x02L
+#define BS_AUTOCHECKBOX 0x03L
+#define BS_RADIOBUTTON 0x04L
+#define BS_3STATE 0x05L
+#define BS_AUTO3STATE 0x06L
+#define BS_GROUPBOX 0x07L
+#define BS_USERBUTTON 0x08L
+#define BS_AUTORADIOBUTTON 0x09L
+#define BS_PUSHBOX 0x0AL
+#define BS_OWNERDRAW 0x0BL
+#define BS_LEFTTEXT 0x20L
+
+
+/* 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
+
+/* 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)
+
+/* Static Control Constants */
+#define SS_LEFT 0x00L
+#define SS_CENTER 0x01L
+#define SS_RIGHT 0x02L
+#define SS_ICON 0x03L
+#define SS_BLACKRECT 0x04L
+#define SS_GRAYRECT 0x05L
+#define SS_WHITERECT 0x06L
+#define SS_BLACKFRAME 0x07L
+#define SS_GRAYFRAME 0x08L
+#define SS_WHITEFRAME 0x09L
+#define SS_USERITEM 0x0AL
+#define SS_SIMPLE 0x0BL
+#define SS_LEFTNOWORDWRAP 0x0CL
+#define SS_NOPREFIX 0x80L /* Don't do "&" character translation */
+
+/* Dialog Manager Routines */
+
+#ifndef NOMSG
+BOOL APIENTRY CRITICAL IsDialogMessage(IN HWND hDlg, IN LPMSG lpMsg);
+#endif
+
+void APIENTRY CRITICAL MapDialogRect(IN HWND hDlg, IN OUT LPRECT lpRect);
+
+int APIENTRY CRITICAL DlgDirList(IN HWND hDlg, IN LPSTR lpPathSpec, IN int nIDListBox, IN int nIDStaticPath, IN WORD wFileType);
+BOOL APIENTRY CRITICAL DlgDirSelectEx(IN HWND hDlg, OUT LPSTR lpString, IN int nIDListBox);
+int APIENTRY CRITICAL DlgDirListComboBox(IN HWND hDlg, IN LPSTR lpPathSpec, IN int nIDComboBox, IN int nIDStaticPath, IN WORD wFiletype);
+BOOL APIENTRY CRITICAL DlgDirSelectComboBoxEx(IN HWND hDlg, OUT LPSTR lpString, IN int nIDComboBox);
+
+
+/* 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 */
+
+#define DM_GETDEFID (WM_USER+0)
+#define DM_SETDEFID (WM_USER+1)
+#define DC_HASDEFID 0x534B
+
+/* Dialog Codes */
+#define DLGC_WANTARROWS 0x0001 /* Control wants arrow keys */
+#define DLGC_WANTTAB 0x0002 /* Control wants tab keys */
+#define DLGC_WANTALLKEYS 0x0004 /* Control wants all keys */
+#define DLGC_WANTMESSAGE 0x0004 /* Pass message to control */
+#define DLGC_HASSETSEL 0x0008 /* Understands EM_SETSEL message */
+#define DLGC_DEFPUSHBUTTON 0x0010 /* Default pushbutton */
+#define DLGC_UNDEFPUSHBUTTON 0x0020 /* Non-default pushbutton */
+#define DLGC_RADIOBUTTON 0x0040 /* Radio button */
+#define DLGC_WANTCHARS 0x0080 /* Want WM_CHAR messages */
+#define DLGC_STATIC 0x0100 /* Static item: don't include */
+#define DLGC_BUTTON 0x2000 /* Button item: can be checked */
+
+#define LB_CTLCODE 0L
+
+/* Listbox Return Values */
+#define LB_OKAY 0
+#define LB_ERR (-1)
+#define LB_ERRSPACE (-2)
+
+/*
+** The idStaticPath parameter to DlgDirList can have the following values
+** ORed if the list box should show other details of the files along with
+** the name of the files;
+*/
+ /* all other details also will be returned */
+
+
+/* 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
+
+
+
+#ifndef NOWINMESSAGES
+
+/* Listbox messages */
+#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_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_MSGMAX (WM_USER+33)
+
+#endif /* NOWINMESSAGES */
+
+#ifndef NOWINSTYLES
+
+/* Listbox Styles */
+#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)
+
+#endif /* NOWINSTYLES */
+
+
+/* Combo Box return Values */
+#define CB_OKAY 0
+#define CB_ERR (-1)
+#define CB_ERRSPACE (-2)
+
+
+/* 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
+
+/* 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
+#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)
+#define CB_GETDROPPEDCONTROLRECT (WM_USER+18)
+#define CB_MSGMAX (WM_USER+19)
+#endif /* NOWINMESSAGES */
+
+
+
+#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 */
+
+#ifndef NOMDI
+
+typedef struct tagMDICREATESTRUCT
+ {
+ LPSTR szClass;
+ LPSTR szTitle;
+ HANDLE hOwner;
+ int x;
+ int y;
+ int cx;
+ int cy;
+ LONG style;
+ LONG lParam; /* app-defined stuff */
+ } MDICREATESTRUCT;
+
+typedef MDICREATESTRUCT * LPMDICREATESTRUCT;
+
+typedef struct tagCLIENTCREATESTRUCT
+ {
+ HANDLE hWindowMenu;
+ WORD idFirstChild;
+ } CLIENTCREATESTRUCT;
+
+typedef CLIENTCREATESTRUCT * LPCLIENTCREATESTRUCT;
+
+LONG APIENTRY CRITICAL DefFrameProc(IN HWND hWnd, IN HWND hWndMDIClient, IN WORD wMsg, IN LONG wParam, IN LONG lParam);
+LONG APIENTRY CRITICAL DefMDIChildProc(IN HWND hWnd, IN WORD wMsg, IN LONG wParam, IN LONG lParam);
+
+#ifndef NOMSG
+BOOL APIENTRY CRITICAL TranslateMDISysAccel(IN HWND hWndClient, IN LPMSG lpMsg);
+#endif
+
+WORD APIENTRY CRITICAL ArrangeIconicWindows(IN HWND hWnd);
+
+#endif /* NOMDI */
+
+#endif /* NOUSER */
+
+#ifndef NOHELP
+
+/* Help engine section. */
+
+/* Commands to pass WinHelp() */
+#define HELP_CONTEXT 0x0001 /* Display topic in ulTopic */
+#define HELP_QUIT 0x0002 /* Terminate help */
+#define HELP_INDEX 0x0003 /* Display index */
+#define HELP_HELPONHELP 0x0004 /* Display help on using help */
+#define HELP_SETINDEX 0x0005 /* Set the current Index for multi index help */
+#define HELP_KEY 0x0101 /* Display topic for keyword in offabData */
+#define HELP_MULTIKEY 0x0201
+
+typedef struct tagMULTIKEYHELP
+ {
+ WORD mkSize;
+ BYTE mkKeylist;
+ BYTE szKeyphrase[1];
+ } MULTIKEYHELP;
+
+#endif /* NOHELP */
+
+#ifndef NOPROFILER
+
+/* function declarations for profiler routines contained in Windows libraries */
+int APIENTRY ProfInsChk(void);
+void APIENTRY ProfSetup(int,int);
+void APIENTRY ProfSampRate(int,int);
+void APIENTRY ProfStart(void);
+void APIENTRY ProfStop(void);
+void APIENTRY ProfClear(void);
+void APIENTRY ProfFlush(void);
+void APIENTRY ProfFinish(void);
+
+#endif /* NOPROFILER */
+
+#ifndef NOSYSPARAMSINFO
+/* Parameter for SystemParametersInfo() */
+
+#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
+#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
+
+
+void CRITICAL SystemParametersInfo(WORD, WORD, LONG, WORD);
+
+/* Flags */
+#define SPIF_UPDATEINIFILE 0x0001
+#define SPIF_SENDWININICHANGE 0x0002
+
+#endif /* NOSYSPARAMSINFO */
+
+#endif // _WINUSER_
diff --git a/private/os2/client/thunk/inetapi.def b/private/os2/client/thunk/inetapi.def
new file mode 100644
index 000000000..1245bdb63
--- /dev/null
+++ b/private/os2/client/thunk/inetapi.def
@@ -0,0 +1,64 @@
+LIBRARY INETAPI
+PROTMODE
+;SEGMENTS DOSMON_CODE PURE IOPL CONFORMING
+;SEGMENTS DosMon_DATA CLASS 'DATA' IMPURE
+
+;Note that IMPORTing is not necessary since we 'know' how to get to the
+; 32 bit, NT side, by magic (see nls.asm).
+;
+;All EXPORTS should have 1.0-compatible ordinals and "RESIDENTNAME"
+;EXPORTS usually get put in DOSCALLS.LIB; see LIB/MAKEFILE to make them private
+;EXPORTS DOSMONOPEN @4 RESIDENTNAME
+EXPORTS
+ NETGETDCNAME @189 RESIDENTNAME
+ NETHANDLEGETINFO @174 RESIDENTNAME
+ NETSERVERDISKENUM @54 RESIDENTNAME
+ NETSERVERGETINFO @55 RESIDENTNAME
+ NETSERVICECONTROL @57 RESIDENTNAME
+ NETSERVICEENUM @58 RESIDENTNAME
+ NETSERVICEGETINFO @116 RESIDENTNAME
+ NETSERVICEINSTALL @59 RESIDENTNAME
+ NETSHAREENUM @67 RESIDENTNAME
+ NETSHAREGETINFO @68 RESIDENTNAME
+ NETUSEADD @73 RESIDENTNAME
+ NETUSEDEL @74 RESIDENTNAME
+ NETUSEENUM @75 RESIDENTNAME
+ NETUSEGETINFO @76 RESIDENTNAME
+ NETUSERENUM @79 RESIDENTNAME
+ NETWKSTAGETINFO @84 RESIDENTNAME
+ NETACCESSADD @1 RESIDENTNAME
+ NETACCESSSETINFO @5 RESIDENTNAME
+ NETACCESSGETINFO @4 RESIDENTNAME
+ NETACCESSDEL @2 RESIDENTNAME
+ NETSHAREADD @64 RESIDENTNAME
+ NETSHAREDEL @66 RESIDENTNAME
+ NETUSERGETINFO @81 RESIDENTNAME
+ NETMESSAGEBUFFERSEND @525 RESIDENTNAME
+ NETSERVERENUM2 @528 RESIDENTNAME
+
+ NETBIOSCLOSE @13 RESIDENTNAME
+ NETBIOSENUM @14 RESIDENTNAME
+ NETBIOSGETINFO @15 RESIDENTNAME
+ NETBIOSOPEN @16 RESIDENTNAME
+ NETBIOSSUBMIT @17 RESIDENTNAME
+
+ NETIWKSTAGETUSERINFO @636 RESIDENTNAME
+
+ DOSMAKENMPIPE @530 RESIDENTNAME
+ DOSQNMPIPEINFO @537 RESIDENTNAME
+ DOSCONNECTNMPIPE @531 RESIDENTNAME
+ DOSDISCONNECTNMPIPE @532 RESIDENTNAME
+ DOSQNMPHANDSTATE @536 RESIDENTNAME
+ DOSSETNMPHANDSTATE @533 RESIDENTNAME
+ DOSPEEKNMPIPE @538 RESIDENTNAME
+ DOSWAITNMPIPE @534 RESIDENTNAME
+ DOSTRANSACTNMPIPE @535 RESIDENTNAME
+ DOSCALLNMPIPE @539 RESIDENTNAME
+
+ DOSMAKEMAILSLOT @503 RESIDENTNAME
+ DOSDELETEMAILSLOT @501 RESIDENTNAME
+ DOSMAILSLOTINFO @502 RESIDENTNAME
+ DOSPEEKMAILSLOT @504 RESIDENTNAME
+ DOSREADMAILSLOT @523 RESIDENTNAME
+ DOSWRITEMAILSLOT @524 RESIDENTNAME
+
diff --git a/private/os2/client/thunk/kbdcalls.def b/private/os2/client/thunk/kbdcalls.def
new file mode 100644
index 000000000..d715f810e
--- /dev/null
+++ b/private/os2/client/thunk/kbdcalls.def
@@ -0,0 +1,41 @@
+LIBRARY KBDCALLS
+PROTMODE
+;SEGMENTS DOSMON_CODE PURE IOPL CONFORMING
+;SEGMENTS DosMon_DATA CLASS 'DATA' IMPURE
+
+;Note that IMPORTing is not necessary since we 'know' how to get to the
+; 32 bit, NT side, by magic (see nls.asm).
+;
+;All EXPORTS should have 1.0-compatible ordinals and "RESIDENTNAME"
+;EXPORTS usually get put in DOSCALLS.LIB; see LIB/MAKEFILE to make them private
+;EXPORTS DOSMONOPEN @4 RESIDENTNAME
+EXPORTS
+ KBDSETCUSTXT @1 RESIDENTNAME
+; KBDPROCESSINIT @2 RESIDENTNAME
+ KBDGETCP @3 RESIDENTNAME
+ KBDCHARIN @4 RESIDENTNAME
+ KBDSETCP @5 RESIDENTNAME
+; KBDLOADINSTANCE @6 RESIDENTNAME
+ KBDSYNCH @7 RESIDENTNAME
+ KBDREGISTER @8 RESIDENTNAME
+ KBDSTRINGIN @9 RESIDENTNAME
+ KBDGETSTATUS @10 RESIDENTNAME
+ KBDSETSTATUS @11 RESIDENTNAME
+ KBDGETFOCUS @12 RESIDENTNAME
+ KBDFLUSHBUFFER @13 RESIDENTNAME
+ KBDXLATE @14 RESIDENTNAME
+;#if PMNT
+; KBDSWITCHFGND @15 RESIDENTNAME
+;#endif
+ KBDSHELLINIT @16 RESIDENTNAME
+ KBDCLOSE @17 RESIDENTNAME
+ KBDFREEFOCUS @18 RESIDENTNAME
+;#if PMNT
+; KBDFREE @19 RESIDENTNAME
+;#endif
+ KBDDEREGISTER @20 RESIDENTNAME
+ KBDSETFGND @21 RESIDENTNAME
+ KBDPEEK @22 RESIDENTNAME
+ KBDOPEN @23 RESIDENTNAME
+ KBDGETHWID @24 RESIDENTNAME
+; KBDSETHWID @25 RESIDENTNAME
diff --git a/private/os2/client/thunk/ldrtabs/dump.cmd b/private/os2/client/thunk/ldrtabs/dump.cmd
new file mode 100644
index 000000000..0b6e11bdf
--- /dev/null
+++ b/private/os2/client/thunk/ldrtabs/dump.cmd
@@ -0,0 +1,151 @@
+@echo *
+@echo * This command file is used to build the needed data structures so we no
+@echo * longer need to have any other system dll's than doscalls.dll.
+@echo *
+@echo * IMPORTANT: If the .def files in the thunk directory are changed then
+@echo * this command file must be run and the output file
+@echo * ..\..\..\inc\ldrtabs.h must be checked-in since the build
+@echo * group will need it for building ldr\ldrinit.c.
+@echo * If a new dll is added then this command file must be changed
+@echo * also.
+@echo *
+
+del ..\..\..\inc\ldrtabs.h
+
+copy ..\ACSNETB.DLL acsnetb.dll
+copy ..\KBDCALLS.DLL kbdcalls.dll
+copy ..\MAILSLOT.DLL mailslot.dll
+copy ..\MONCALLS.DLL moncalls.dll
+copy ..\MOUCALLS.DLL moucalls.dll
+copy ..\MSG.DLL msg.dll
+copy ..\NAMPIPES.DLL nampipes.dll
+copy ..\INETAPI.DLL api.dll
+copy ..\NETOEM.DLL oem.dll
+copy ..\NLS.DLL nls.dll
+@
+@ REM pmshapi.dll, pmwin.dll & os2sm.dll must be provided by PM
+@ REM when running PM/NT
+@
+@if not "%PMNT%"=="" goto skip_1
+copy ..\PMSHAPI.DLL pmshapi.dll
+copy ..\PMWIN.DLL pmwin.dll
+copy ..\OS2SM.DLL os2sm.dll
+:skip_1
+copy ..\SESMGR.DLL sesmgr.dll
+copy ..\QUECALLS.DLL quecalls.dll
+copy ..\VIOCALLS.DLL viocalls.dll
+
+@ REM MSKK Dec.15.1992 V-AkihiS
+@
+@ REM imdaemon.dll must be provided for supporting IMMON API
+@
+@if "%DBCS%"=="" goto skip_im1
+copy ..\IMDAEMON.DLL imdaemon.dll
+:skip_im1
+
+nedump acsnetb.dll
+type acsent >> ..\..\..\inc\ldrtabs.h
+type acsres >> ..\..\..\inc\ldrtabs.h
+type acsnres >> ..\..\..\inc\ldrtabs.h
+del acs*
+nedump kbdcalls.dll
+type kbdent >> ..\..\..\inc\ldrtabs.h
+type kbdres >> ..\..\..\inc\ldrtabs.h
+type kbdnres >> ..\..\..\inc\ldrtabs.h
+del kbd*
+nedump mailslot.dll
+type maient >> ..\..\..\inc\ldrtabs.h
+type maires >> ..\..\..\inc\ldrtabs.h
+type mainres >> ..\..\..\inc\ldrtabs.h
+del mai*
+nedump moncalls.dll
+type monent >> ..\..\..\inc\ldrtabs.h
+type monres >> ..\..\..\inc\ldrtabs.h
+type monnres >> ..\..\..\inc\ldrtabs.h
+del mon*
+nedump moucalls.dll
+type mouent >> ..\..\..\inc\ldrtabs.h
+type moures >> ..\..\..\inc\ldrtabs.h
+type mounres >> ..\..\..\inc\ldrtabs.h
+del mou*
+nedump msg.dll
+type msgent >> ..\..\..\inc\ldrtabs.h
+type msgres >> ..\..\..\inc\ldrtabs.h
+type msgnres >> ..\..\..\inc\ldrtabs.h
+del msg*
+nedump nampipes.dll
+type nament >> ..\..\..\inc\ldrtabs.h
+type namres >> ..\..\..\inc\ldrtabs.h
+type namnres >> ..\..\..\inc\ldrtabs.h
+del nam*
+nedump api.dll
+type apient >> ..\..\..\inc\ldrtabs.h
+type apires >> ..\..\..\inc\ldrtabs.h
+type apinres >> ..\..\..\inc\ldrtabs.h
+del api*
+nedump oem.dll
+type oement >> ..\..\..\inc\ldrtabs.h
+type oemres >> ..\..\..\inc\ldrtabs.h
+type oemnres >> ..\..\..\inc\ldrtabs.h
+del oem*
+nedump nls.dll
+type nlsent >> ..\..\..\inc\ldrtabs.h
+type nlsres >> ..\..\..\inc\ldrtabs.h
+type nlsnres >> ..\..\..\inc\ldrtabs.h
+del nls*
+@if not "%PMNT%"=="" goto skip_2
+nedump pmshapi.dll
+type pmsent >> ..\..\..\inc\ldrtabs.h
+type pmsres >> ..\..\..\inc\ldrtabs.h
+type pmsnres >> ..\..\..\inc\ldrtabs.h
+del pms*
+nedump pmwin.dll
+type pmwent >> ..\..\..\inc\ldrtabs.h
+type pmwres >> ..\..\..\inc\ldrtabs.h
+type pmwnres >> ..\..\..\inc\ldrtabs.h
+del pmw*
+nedump os2sm.dll
+type os2ent >> ..\..\..\inc\ldrtabs.h
+type os2res >> ..\..\..\inc\ldrtabs.h
+type os2nres >> ..\..\..\inc\ldrtabs.h
+del os2*
+:skip_2
+nedump sesmgr.dll
+type sesent >> ..\..\..\inc\ldrtabs.h
+type sesres >> ..\..\..\inc\ldrtabs.h
+type sesnres >> ..\..\..\inc\ldrtabs.h
+del ses*
+nedump quecalls.dll
+type queent >> ..\..\..\inc\ldrtabs.h
+type queres >> ..\..\..\inc\ldrtabs.h
+type quenres >> ..\..\..\inc\ldrtabs.h
+del que*
+@if "%PMNT%" == "" goto skip_3
+copy ..\PMNT.DLL pmnt.dll
+nedump pmnt.dll
+type pmnent >> ..\..\..\inc\ldrtabs.h
+type pmnres >> ..\..\..\inc\ldrtabs.h
+type pmnnres >> ..\..\..\inc\ldrtabs.h
+del pmn*
+
+:skip_3
+nedump viocalls.dll
+type vioent >> ..\..\..\inc\ldrtabs.h
+type viores >> ..\..\..\inc\ldrtabs.h
+type vionres >> ..\..\..\inc\ldrtabs.h
+del vio*
+
+@ REM MSKK Dec.15.1992 V-AkihiS
+@
+@ REM imdaemon.dll must be provided for supporting IMMON API
+@
+@if "%DBCS%" == "" goto skip_im2
+
+nedump imdaemon.dll
+type imdent >> ..\..\..\inc\ldrtabs.h
+type imdres >> ..\..\..\inc\ldrtabs.h
+type imdnres >> ..\..\..\inc\ldrtabs.h
+del imd*
+
+:skip_im2
+
diff --git a/private/os2/client/thunk/ldrtabs/nedump.c b/private/os2/client/thunk/ldrtabs/nedump.c
new file mode 100644
index 000000000..6175ac118
--- /dev/null
+++ b/private/os2/client/thunk/ldrtabs/nedump.c
@@ -0,0 +1,228 @@
+#include <stdio.h>
+#include <ctype.h>
+#include "newexe.h"
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+FILE *fp;
+FILE *fp2;
+unsigned char buffer[512];
+unsigned char tables[1024];
+unsigned long lfanew;
+unsigned short enttabsize;
+unsigned short restabsize;
+unsigned short nrestabsize;
+struct exe_hdr *pmz;
+struct new_exe *pne;
+char enttab[] = " ent";
+char restab[] = " res";
+char nrestab[] = " nres";
+char *arg;
+long i;
+
+ //
+ // The command usage is nedump <dll name>
+ //
+ if (argc != 2) {
+ printf("Usage: nedump file\n");
+ return 1;
+ }
+
+ if ((fp = fopen(argv[1], "rb")) == NULL) {
+ printf("nedump: can't open %s\n", argv[1]);
+ return 1;
+ }
+
+ fread(buffer, 1, 512, fp);
+
+ if (ferror(fp)) {
+ printf("nedump: read of file failed\n");
+ return 1;
+ }
+
+ pmz = (struct exe_hdr *) buffer;
+
+ //
+ // Check for MZ
+ //
+ if (pmz->e_magic != EMAGIC) {
+ printf("nedump: ERROR_INVALID_EXE_SIGNATURE\n");
+ return 1;
+ }
+
+ if ((lfanew = pmz->e_lfanew) > 512) {
+ printf("nedump: ERROR_BOUND_APP\n");
+ return 1;
+ }
+
+ if (fseek(fp, lfanew, SEEK_SET)) {
+ printf("nedump: ERROR_SEEK_FAILED\n");
+ return 1;
+ }
+
+ fread(buffer, 1, 512, fp);
+
+ if (ferror(fp)) {
+ printf("nedump: read of file failed\n");
+ return 1;
+ }
+
+ pne = (struct new_exe *) buffer;
+
+ //
+ // Check for NE
+ //
+ if (pne->ne_magic != NEMAGIC) {
+ printf("nedump: ERROR_INVALID_EXE_SIGNATURE\n");
+ }
+
+ //
+ // Compute size of entry table
+ //
+ if ((enttabsize = pne->ne_nrestab - lfanew - pne->ne_enttab) > 1024) {
+ printf("nedump: Entry table bigger than 1024 bytes\n");
+ return 1;
+ }
+
+ if (fseek(fp, lfanew + pne->ne_enttab, SEEK_SET)) {
+ printf("nedump: ERROR_SEEK_FAILED\n");
+ return 1;
+ }
+
+ //
+ // Create output file names
+ //
+ arg = argv[1];
+ enttab[0] = restab[0] = nrestab[0] = *arg++;
+ enttab[1] = restab[1] = nrestab[1] = *arg++;
+ enttab[2] = restab[2] = nrestab[2] = *arg++;
+
+ //
+ // Read entry table
+ //
+ fread(tables, 1, 1024, fp);
+
+ if (ferror(fp)) {
+ printf("nedump: read of file failed\n");
+ return 1;
+ }
+
+
+ //
+ // Create Entry table
+ //
+ if ((fp2 = fopen(enttab, "w")) == NULL) {
+ printf("nedump: can't open %s\n", enttab);
+ return 1;
+ }
+
+ fprintf(fp2, "UCHAR %stab[]= \n", enttab);
+ fprintf(fp2, "{\n");
+ for (i=0; i<enttabsize; i++) {
+ fprintf(fp2, "0x%x", tables[i]);
+ if (i != enttabsize - 1) {
+ fprintf(fp2, ",");
+ }
+ else {
+ fprintf(fp2, "\n");
+ }
+ if (i != 0 && i % 17 == 0) {
+ fprintf(fp2, "\n");
+ }
+ }
+
+ fprintf(fp2, "};\n");
+
+ fclose(fp2);
+
+ //
+ // Compute resident name table size
+ //
+ if ((restabsize = pne->ne_modtab - pne->ne_restab) > 1024) {
+ printf("nedump: Resident name table bigger than 1024 bytes\n");
+ return 1;
+ }
+
+ if (fseek(fp, lfanew + pne->ne_restab, SEEK_SET)) {
+ printf("nedump: ERROR_SEEK_FAILED\n");
+ return 1;
+ }
+
+ fread(tables, 1, 1024, fp);
+
+ if (ferror(fp)) {
+ printf("nedump: read of file failed\n");
+ return 1;
+ }
+ if ((fp2 = fopen(restab, "w")) == NULL) {
+ printf("nedump: can't open %s\n", restab);
+ return 1;
+ }
+
+ fprintf(fp2, "UCHAR %stab[]= \n", restab);
+ fprintf(fp2, "{\n");
+
+ for (i=0; i<restabsize; i++) {
+ fprintf(fp2, "0x%x", tables[i]);
+ if (i != restabsize - 1) {
+ fprintf(fp2, ",");
+ }
+ else {
+ fprintf(fp2, "\n");
+ }
+ if (i != 0 && i % 15 == 0) {
+ fprintf(fp2, "\n");
+ }
+ }
+
+ fprintf(fp2, "};\n");
+
+ fclose(fp2);
+
+ //
+ // Compute nonresident name table
+ //
+ if ((nrestabsize = pne->ne_cbnrestab) > 1024) {
+ printf("nedump: NonResident name table bigger than 1024 bytes\n");
+ return 1;
+ }
+
+ if (fseek(fp, pne->ne_nrestab, SEEK_SET)) {
+ printf("nedump: ERROR_SEEK_FAILED\n");
+ return 1;
+ }
+
+ fread(tables, 1, 1024, fp);
+
+ if (ferror(fp)) {
+ printf("nedump: read of file failed\n");
+ return 1;
+ }
+ if ((fp2 = fopen(nrestab, "w")) == NULL) {
+ printf("nedump: can't open %s\n", restab);
+ return 1;
+ }
+
+ fprintf(fp2, "UCHAR %stab[]= \n", nrestab);
+ fprintf(fp2, "{\n");
+
+ for (i=0; i<nrestabsize; i++) {
+ fprintf(fp2, "0x%x", tables[i]);
+ if (i != nrestabsize - 1) {
+ fprintf(fp2, ",");
+ }
+ else {
+ fprintf(fp2, "\n");
+ }
+ if (i != 0 && i % 15 == 0) {
+ fprintf(fp2, "\n");
+ }
+ }
+
+ fprintf(fp2, "};\n");
+
+ printf("nedump completed\n");
+ return 0;
+}
diff --git a/private/os2/client/thunk/mailslot.def b/private/os2/client/thunk/mailslot.def
new file mode 100644
index 000000000..05f896961
--- /dev/null
+++ b/private/os2/client/thunk/mailslot.def
@@ -0,0 +1,19 @@
+LIBRARY MAILSLOT
+PROTMODE
+;SEGMENTS DOSMON_CODE PURE IOPL CONFORMING
+;SEGMENTS DosMon_DATA CLASS 'DATA' IMPURE
+
+;Note that IMPORTing is not necessary since we 'know' how to get to the
+; 32 bit, NT side, by magic (see nls.asm).
+;
+;All EXPORTS should have 1.0-compatible ordinals and "RESIDENTNAME"
+;EXPORTS usually get put in DOSCALLS.LIB; see LIB/MAKEFILE to make them private
+;EXPORTS DOSMONOPEN @4 RESIDENTNAME
+EXPORTS
+ DOSMAKEMAILSLOT @1 RESIDENTNAME
+ DOSDELETEMAILSLOT @2 RESIDENTNAME
+ DOSMAILSLOTINFO @3 RESIDENTNAME
+ DOSPEEKMAILSLOT @5 RESIDENTNAME
+ DOSREADMAILSLOT @4 RESIDENTNAME
+ DOSWRITEMAILSLOT @6 RESIDENTNAME
+
diff --git a/private/os2/client/thunk/makefile b/private/os2/client/thunk/makefile
new file mode 100644
index 000000000..8fffd490b
--- /dev/null
+++ b/private/os2/client/thunk/makefile
@@ -0,0 +1,294 @@
+# OS2NT 16=>32 thunks make file
+#
+# Apr 15 1991 YaronS
+#
+#
+
+LFLAGS= /CO /NOD /NOP
+#
+# compile
+#
+MASM = ml -c -Fl$*.lst -Fo$*.obj
+
+#
+# thunk
+#
+# switches (eg. -ycex)
+# e - INT 3 at entry16
+# c - INT 3 before call32
+# x - INT 3 after call32
+#
+
+!IFDEF PMNT
+THUNK = .\thunkcom\thunkpm -y -z -NA THUNK32 -NC THUNK16
+!ELSE
+THUNK = .\thunkcom\thunk -y -z -NA THUNK32 -NC THUNK16
+!ENDIF
+
+
+#
+# libraries
+#
+
+#
+# objects
+#
+OBJS = doscal16.obj
+
+##############################################################################
+# inference rules
+
+.asm.obj:
+ $(MASM) $*.asm
+
+##############################################################################
+
+!IFDEF PMNT
+
+# Difference is: - pmwin.dll, - pmshapi.dll, - os2sm.dll, + pmnt.dll
+
+!IFDEF DBCS
+# MSKK Jun.15.1993 V-AkihiS
+DLLS = doscalls.dll nls.dll kbdcalls.dll msg.dll nampipes.dll \
+ viocalls.dll quecalls.dll sesmgr.dll moucalls.dll \
+ moncalls.dll inetapi.dll netoem.dll mailslot.dll acsnetb.dll pmnt.dll \
+ imdaemon.dll
+!ELSE
+DLLS = doscalls.dll nls.dll kbdcalls.dll msg.dll nampipes.dll \
+ viocalls.dll quecalls.dll sesmgr.dll moucalls.dll \
+ moncalls.dll inetapi.dll netoem.dll mailslot.dll acsnetb.dll pmnt.dll
+!ENDIF
+
+!ELSE
+
+!IFDEF DBCS
+# MSKK Jun.15.1993 V-AkihiS
+DLLS = doscalls.dll nls.dll kbdcalls.dll msg.dll nampipes.dll pmwin.dll \
+ viocalls.dll pmshapi.dll os2sm.dll quecalls.dll sesmgr.dll moucalls.dll \
+ moncalls.dll inetapi.dll netoem.dll mailslot.dll acsnetb.dll \
+ imdaemon.dll
+!ELSE
+DLLS = doscalls.dll nls.dll kbdcalls.dll msg.dll nampipes.dll pmwin.dll \
+ viocalls.dll pmshapi.dll os2sm.dll quecalls.dll sesmgr.dll moucalls.dll \
+ moncalls.dll inetapi.dll netoem.dll mailslot.dll acsnetb.dll
+!ENDIF
+
+!ENDIF
+
+all: $(DLLS) apilist.c ..\..\inc\ldrtabs.h
+
+clean:
+ -del doscalls.i apilist.c ..\..\inc\ldrtabs.h *.dll doscal16.obj \
+!IFDEF PMNT
+# MSKK [ShigeO] Aug 26, 1993
+ doscalls.d viocalls.d kbdcalls.d moucalls.d sesmgr.d pmnt.d
+!ELSE
+ doscalls.d viocalls.d kbdcalls.d moucalls.d sesmgr.d
+!ENDIF
+
+..\..\inc\ldrtabs.h: $(DLLS)
+ cd ldrtabs
+ dump
+ cd ..
+ -del ..\..\ldr\obj\i386\ldrinit.obj
+ @echo *********************** IMPORTANT *************************************
+ @echo * *
+ @echo * You must now check-in ..\..\inc\ldrtabs.h (for ldr\ldrinit.c). *
+ @echo * + build os2\ldr (i.e. LDRDLL.DLL) *
+ @echo * *
+ @echo ***********************************************************************
+
+doscalls.d: doscalls.def
+ copy doscalls.def foo.tmp
+!IFDEF PMNT
+ cl /EP /P /DPMNT foo.tmp
+!ELSE
+ cl /EP /P foo.tmp
+!ENDIF
+ mv foo.i doscalls.d
+ del foo.tmp
+
+doscalls.dll: doscalls.d doscal16.obj r2xfer.obj
+ link $(LFLAGS) doscal16.obj+r2xfer.obj,$@,,,$*.d;
+
+nls.dll: nls.def doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.def;
+
+kbdcalls.dll: kbdcalls.d doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.d;
+
+msg.dll: msg.def doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.def;
+
+nampipes.dll: nampipes.def doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.def;
+
+!IFNDEF PMNT
+pmwin.dll: pmwin.def doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.def;
+!ENDIF
+
+viocalls.d: viocalls.def
+ copy viocalls.def foo.tmp
+!IFDEF PMNT
+!IFDEF DBCS
+# MSKK Feb.19.1993 V-AkihiS
+ cl /EP /P /DPMNT /DDBCS foo.tmp
+!ELSE
+ cl /EP /P /DPMNT foo.tmp
+!ENDIF
+!ELSE
+!IFDEF DBCS
+# MSKK Feb.19.1993 V-AkihiS
+ cl /EP /P /DDBCS foo.tmp
+!ELSE
+ cl /EP /P foo.tmp
+!ENDIF
+!ENDIF
+ mv foo.i viocalls.d
+ del foo.tmp
+
+kbdcalls.d: kbdcalls.def
+ copy kbdcalls.def foo.tmp
+!IFDEF PMNT
+ cl /EP /P /DPMNT foo.tmp
+!ELSE
+ cl /EP /P foo.tmp
+!ENDIF
+ mv foo.i kbdcalls.d
+ del foo.tmp
+
+viocalls.dll: viocalls.d doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.d;
+
+!IFNDEF PMNT
+pmshapi.dll: pmshapi.def doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.def;
+!ENDIF
+
+quecalls.dll: quecalls.def doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.def;
+
+sesmgr.d: sesmgr.def
+ copy sesmgr.def foo.tmp
+!IFDEF PMNT
+ cl /EP /P /DPMNT foo.tmp
+!ELSE
+ cl /EP /P foo.tmp
+!ENDIF
+ mv foo.i sesmgr.d
+ del foo.tmp
+
+moucalls.d: moucalls.def
+ copy moucalls.def foo.tmp
+!IFDEF PMNT
+ cl /EP /P /DPMNT foo.tmp
+!ELSE
+ cl /EP /P foo.tmp
+!ENDIF
+ mv foo.i moucalls.d
+ del foo.tmp
+
+sesmgr.dll: sesmgr.d doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.d;
+
+moucalls.dll: moucalls.d doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.d;
+
+moncalls.dll: moncalls.def doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.def;
+
+inetapi.dll: inetapi.def doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.def;
+
+netoem.dll: netoem.def doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.def;
+
+mailslot.dll: mailslot.def doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.def;
+
+acsnetb.dll: acsnetb.def doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.def;
+
+!IFNDEF PMNT
+os2sm.dll: os2sm.def doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.def;
+!ELSE
+# MSKK [ShigeO] Aug 26, 1993
+pmnt.d: pmnt.def
+ copy pmnt.def foo.tmp
+!IFDEF DBCS
+ cl /EP /P /DDBCS foo.tmp
+!ELSE
+ cl /EP /P foo.tmp
+!ENDIF
+ mv foo.i pmnt.d
+ del foo.tmp
+
+pmnt.dll: pmnt.d doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.d;
+!ENDIF
+
+!IFDEF DBCS
+# MSKK Dec.14.1992 V-AkihiS
+imdaemon.dll: imdaemon.def doscal16.obj
+ link $(LFLAGS) doscal16.obj,$@,,,$*.def;
+
+!ENDIF
+
+#
+# thunk files
+#
+
+# To allow #ifdef (for PMNT for example)
+doscalls.i: doscalls.thk doscalls.mif
+# Throw out C comments
+!IFDEF PMNT
+!IFDEF DBCS
+# MSKK Dec.14.1992 V-AkihiS
+ cl /EP /P /DPMNT /DDBCS doscalls.thk
+!ELSE
+ cl /EP /P /DPMNT doscalls.thk
+!ENDIF
+!ELSE
+!IFDEF DBCS
+# MSKK Dec.14.1992 V-AkihiS
+ cl /EP /P /DDBCS doscalls.thk
+!ELSE
+ cl /EP /P doscalls.thk
+!ENDIF
+!ENDIF
+
+!IFDEF PMNT
+doscalls.asm : $*.i $*.mif .\thunkcom\thunkpm.exe
+!ELSE
+doscalls.asm : $*.i $*.mif .\thunkcom\thunk.exe
+!ENDIF
+ $(THUNK) $*.i
+ copy doscalls.asm ..\i386\doscalls.asm
+
+#
+# File for client\dllmsc16.c
+#
+
+apilist.c: doscalls.i
+ awk -f apilist.awk < doscalls.i > apilist.c
+# To force recompilation of DLLMSC16.C which #includes APILIST.C
+ -del ..\obj\i386\dllmsc16.obj
+ @echo *********************** IMPORTANT *************************************
+ @echo * *
+ @echo * You must now check-in apilist.c (for client\dllmsc16.c) *
+ @echo * + build os2\client (i.e. OS2DLL.DLL) *
+ @echo * *
+ @echo ***********************************************************************
+
+#
+# asm files
+#
+
+doscal16.obj : doscalls.asm
+ $(MASM) -DGEN16 -DDBG=1 doscalls.asm
+
+r2xfer.obj:
+
+
diff --git a/private/os2/client/thunk/moncalls.def b/private/os2/client/thunk/moncalls.def
new file mode 100644
index 000000000..8e56897c1
--- /dev/null
+++ b/private/os2/client/thunk/moncalls.def
@@ -0,0 +1,18 @@
+LIBRARY MONCALLS
+PROTMODE
+;SEGMENTS DOSMON_CODE PURE IOPL CONFORMING
+;SEGMENTS DosMon_DATA CLASS 'DATA' IMPURE
+
+;Note that IMPORTing is not necessary since we 'know' how to get to the
+; 32 bit, NT side, by magic (see nls.asm).
+;
+;All EXPORTS should have 1.0-compatible ordinals and "RESIDENTNAME"
+;EXPORTS usually get put in DOSCALLS.LIB; see LIB/MAKEFILE to make them private
+;EXPORTS DOSMONOPEN @4 RESIDENTNAME
+EXPORTS
+ DOSMONWRITE @1 RESIDENTNAME
+ DOSMONREAD @2 RESIDENTNAME
+ DOSMONCLOSE @3 RESIDENTNAME
+ DOSMONOPEN @4 RESIDENTNAME
+ DOSMONREG @5 RESIDENTNAME
+
diff --git a/private/os2/client/thunk/moucalls.def b/private/os2/client/thunk/moucalls.def
new file mode 100644
index 000000000..87bec1076
--- /dev/null
+++ b/private/os2/client/thunk/moucalls.def
@@ -0,0 +1,40 @@
+LIBRARY MOUCALLS
+PROTMODE
+
+EXPORTS
+ MOUGETPTRSHAPE @1 RESIDENTNAME
+ MOUSETPTRSHAPE @2 RESIDENTNAME
+ MOUGETNUMMICKEYS @3 RESIDENTNAME
+; MOUGETTHRESHOLD @4 RESIDENTNAME
+;#if PMNT
+; MOUSHELLINIT @5 RESIDENTNAME
+;#endif
+ MOUGETSCALEFACT @6 RESIDENTNAME
+ MOUFLUSHQUE @7 RESIDENTNAME
+ MOUGETNUMBUTTONS @8 RESIDENTNAME
+ MOUCLOSE @9 RESIDENTNAME
+;#if PMNT
+; MOUSETHOTKEY @10 RESIDENTNAME
+;#endif
+ MOUSETSCALEFACT @11 RESIDENTNAME
+;#if PMNT
+; MOUFREE @12 RESIDENTNAME
+;#endif
+ MOUGETNUMQUEEL @13 RESIDENTNAME
+ MOUDEREGISTER @14 RESIDENTNAME
+ MOUGETEVENTMASK @15 RESIDENTNAME
+ MOUSETEVENTMASK @16 RESIDENTNAME
+ MOUOPEN @17 RESIDENTNAME
+ MOUREMOVEPTR @18 RESIDENTNAME
+ MOUGETPTRPOS @19 RESIDENTNAME
+ MOUREADEVENTQUE @20 RESIDENTNAME
+ MOUSETPTRPOS @21 RESIDENTNAME
+ MOUGETDEVSTATUS @22 RESIDENTNAME
+ MOUSYNCH @23 RESIDENTNAME
+ MOUREGISTER @24 RESIDENTNAME
+ MOUSETDEVSTATUS @25 RESIDENTNAME
+ MOUDRAWPTR @26 RESIDENTNAME
+#if PMNT
+ MOUINITREAL @27 RESIDENTNAME
+#endif
+
diff --git a/private/os2/client/thunk/msg.def b/private/os2/client/thunk/msg.def
new file mode 100644
index 000000000..214cd07cb
--- /dev/null
+++ b/private/os2/client/thunk/msg.def
@@ -0,0 +1,20 @@
+LIBRARY MSG
+PROTMODE
+;SEGMENTS DOSMON_CODE PURE IOPL CONFORMING
+;SEGMENTS DosMon_DATA CLASS 'DATA' IMPURE
+
+;Note that IMPORTing is not necessary since we 'know' how to get to the
+; 32 bit, NT side, by magic (see nls.asm).
+;
+;All EXPORTS should have 1.0-compatible ordinals and "RESIDENTNAME"
+;EXPORTS usually get put in DOSCALLS.LIB; see LIB/MAKEFILE to make them private
+;EXPORTS DOSMONOPEN @4 RESIDENTNAME
+EXPORTS
+ DOSPUTMESSAGE @1 RESIDENTNAME
+ DOSTRUEGETMESSAGE @2 RESIDENTNAME
+ DOSINSMESSAGE @3 RESIDENTNAME
+; DOS32INSERTMESSAGE @4 RESIDENTNAME
+; DOS32PUTMESSAGE @5 RESIDENTNAME
+; DOS32TRUEGETMESSAGE @6 RESIDENTNAME
+; DOSIQUERYMESSAGECP @7 RESIDENTNAME
+; DOS32IQUERYMESSAGECP @8 RESIDENTNAME
diff --git a/private/os2/client/thunk/nampipes.def b/private/os2/client/thunk/nampipes.def
new file mode 100644
index 000000000..c14b23868
--- /dev/null
+++ b/private/os2/client/thunk/nampipes.def
@@ -0,0 +1,26 @@
+LIBRARY NAMPIPES
+PROTMODE
+;SEGMENTS DOSMON_CODE PURE IOPL CONFORMING
+;SEGMENTS DosMon_DATA CLASS 'DATA' IMPURE
+
+;Note that IMPORTing is not necessary since we 'know' how to get to the
+; 32 bit, NT side, by magic (see doscalls.asm).
+;
+;All EXPORTS should have 1.0-compatible ordinals and "RESIDENTNAME"
+;EXPORTS usually get put in DOSCALLS.LIB; see LIB/MAKEFILE to make them private
+;EXPORTS DOSMONOPEN @4 RESIDENTNAME
+EXPORTS
+ DOSMAKENMPIPE @1 RESIDENTNAME
+ DOSQNMPIPEINFO @2 RESIDENTNAME
+ DOSCONNECTNMPIPE @3 RESIDENTNAME
+ DOSDISCONNECTNMPIPE @4 RESIDENTNAME
+ DOSQNMPHANDSTATE @5 RESIDENTNAME
+ DOSSETNMPHANDSTATE @6 RESIDENTNAME
+ DOSPEEKNMPIPE @7 RESIDENTNAME
+ DOSWAITNMPIPE @8 RESIDENTNAME
+ DOSTRANSACTNMPIPE @9 RESIDENTNAME
+ DOSCALLNMPIPE @10 RESIDENTNAME
+; DOSRAWREADNMPIPE @11 RESIDENTNAME
+; DOSRAWWRITENMPIPE @12 RESIDENTNAME
+ DOSSETNMPIPESEM @13 RESIDENTNAME
+ DOSQNMPIPESEMSTATE @14 RESIDENTNAME
diff --git a/private/os2/client/thunk/netapi.os2 b/private/os2/client/thunk/netapi.os2
new file mode 100644
index 000000000..0a1d8ac46
--- /dev/null
+++ b/private/os2/client/thunk/netapi.os2
Binary files differ
diff --git a/private/os2/client/thunk/netoem.def b/private/os2/client/thunk/netoem.def
new file mode 100644
index 000000000..23dc7a022
--- /dev/null
+++ b/private/os2/client/thunk/netoem.def
@@ -0,0 +1,15 @@
+LIBRARY NETOEM
+PROTMODE
+;SEGMENTS DOSMON_CODE PURE IOPL CONFORMING
+;SEGMENTS DosMon_DATA CLASS 'DATA' IMPURE
+
+;Note that IMPORTing is not necessary since we 'know' how to get to the
+; 32 bit, NT side, by magic (see nls.asm).
+;
+;All EXPORTS should have 1.0-compatible ordinals and "RESIDENTNAME"
+;EXPORTS usually get put in DOSCALLS.LIB; see LIB/MAKEFILE to make them private
+;EXPORTS DOSMONOPEN @4 RESIDENTNAME
+EXPORTS
+
+ NETMESSAGEBUFFERSEND @5 RESIDENTNAME
+ NETSERVERENUM2 @11 RESIDENTNAME
diff --git a/private/os2/client/thunk/nls.def b/private/os2/client/thunk/nls.def
new file mode 100644
index 000000000..c5f051d94
--- /dev/null
+++ b/private/os2/client/thunk/nls.def
@@ -0,0 +1,21 @@
+LIBRARY NLS
+PROTMODE
+;SEGMENTS DOSMON_CODE PURE IOPL CONFORMING
+;SEGMENTS DosMon_DATA CLASS 'DATA' IMPURE
+
+;Note that IMPORTing is not necessary since we 'know' how to get to the
+; 32 bit, NT side, by magic (see nls.asm).
+;
+;All EXPORTS should have 1.0-compatible ordinals and "RESIDENTNAME"
+;EXPORTS usually get put in DOSCALLS.LIB; see LIB/MAKEFILE to make them private
+;EXPORTS DOSMONOPEN @4 RESIDENTNAME
+EXPORTS
+ DOSCASEMAP @1 RESIDENTNAME
+ DOSGETCOLLATE @2 RESIDENTNAME
+ DOSGETCTRYINFO @3 RESIDENTNAME
+ DOSGETDBCSEV @4 RESIDENTNAME
+; DOS32QUERYCTRYINFO @5 RESIDENTNAME
+; DOS32QUERYDBCSENV @6 RESIDENTNAME
+; DOS32MAPCASE @7 RESIDENTNAME
+; DOS32QUERYCOLLATE @8 RESIDENTNAME
+
diff --git a/private/os2/client/thunk/os2def.tif b/private/os2/client/thunk/os2def.tif
new file mode 100644
index 000000000..68132bbf9
--- /dev/null
+++ b/private/os2/client/thunk/os2def.tif
@@ -0,0 +1,318 @@
+/* SCCSID = @(#)os2def.tif 1.3 89/05/11 */
+
+/*** os2def.tif - Header file for the thunk compiler's Dos script files
+*
+* These are the typedefs for the scripts for the Dos and the PM
+* apientry routines. The typedefs in this file are used by both
+* sets of calls, following the standard set by the os2def.h file.
+*
+* History:
+* 30-Jan-1989 JulieB Created it.
+*/
+
+
+typedef unsigned short SHANDLE;
+
+typedef void *LHANDLE;
+
+typedef unsigned char UCHAR;
+
+typedef char CHAR;
+
+typedef unsigned short USHORT;
+
+typedef short SHORT;
+
+typedef unsigned long ULONG;
+
+typedef long LONG;
+
+typedef unsigned int UINT;
+
+typedef char BYTE;
+
+typedef string *PSZ;
+
+typedef string *NPSZ;
+
+typedef char *PCH;
+
+typedef char *NPCH;
+
+typedef BYTE *PBYTE;
+
+typedef BYTE *NPBYTE;
+
+typedef char *PCHAR;
+
+typedef PCHAR *PPCHAR;
+
+typedef short *PSHORT;
+
+typedef long *PLONG;
+
+typedef int *PINT;
+
+typedef UCHAR *PUCHAR;
+
+typedef USHORT *PUSHORT;
+
+typedef ULONG *PULONG;
+
+typedef UINT *PUINT;
+
+typedef void *PVOID;
+
+typedef unsigned short BOOL;
+
+typedef BOOL *PBOOL;
+
+typedef unsigned short SEL;
+
+typedef SEL *PSEL;
+
+typedef SHANDLE HFILE;
+
+typedef HFILE *PHFILE;
+
+typedef void *HSEM;
+
+typedef HSEM *PHSEM;
+
+typedef ULONG ERRORID;
+
+typedef ERRORID *PERRORID;
+
+typedef USHORT HMODULE;
+
+typedef HMODULE *PHMODULE;
+
+typedef USHORT PID;
+
+typedef PID *PPID;
+
+typedef USHORT TID;
+
+typedef TID *PTID;
+
+typedef LHANDLE HAB;
+
+typedef HAB *PHAB;
+
+typedef LHANDLE HPS;
+
+typedef HPS *PHPS;
+
+typedef LHANDLE HDC;
+
+typedef HDC *PHDC;
+
+typedef LHANDLE HRGN;
+
+typedef HRGN *PHRGN;
+
+typedef LHANDLE HBITMAP;
+
+typedef HBITMAP *PHBITMAP;
+
+typedef LHANDLE HMF;
+
+typedef HMF *PHMF;
+
+typedef ULONG COLOR;
+
+typedef COLOR *PCOLOR;
+
+typedef struct _POINTL {
+ long x;
+ long y;
+} POINTL;
+
+typedef POINTL *PPOINTL;
+
+typedef struct _POINTS {
+ short x;
+ short y;
+} POINTS;
+typedef POINTS *PPOINTS;
+
+typedef struct _RECTL {
+ long xLeft;
+ long yBottom;
+ long xRight;
+ long yTop;
+} RECTL;
+
+typedef RECTL *PRECTL;
+
+typedef struct _FTIME {
+ short time;
+} FTIME;
+
+typedef FTIME *PFTIME;
+
+typedef struct _FDATE {
+ short date;
+} FDATE;
+
+typedef FDATE *PFDATE;
+
+typedef struct _FILEFINDBUF {
+ FDATE fdateCreation;
+ FTIME ftimeCreation;
+ FDATE fdateLastAccess;
+ FTIME ftimeLastAccess;
+ FDATE fdateLastWrite;
+ FTIME ftimeLastWrite;
+ ULONG cbFile;
+ ULONG cbFileAlloc;
+ USHORT attrFile;
+ UCHAR cchName;
+ char achName[13];
+} FILEFINDBUF;
+
+typedef FILEFINDBUF *PFILEFINDBUF;
+
+typedef LHANDLE HWND;
+
+typedef HWND *PHWND;
+
+typedef struct _WRECT {
+ short xLeft;
+ short dummy1;
+ short yBottom;
+ short dummy2;
+ short xRight;
+ short dummy3;
+ short yTop;
+ short dummy4;
+} WRECT;
+
+typedef WRECT *PWRECT;
+
+typedef struct _WPOINT {
+ short x;
+ short dummy1;
+ short y;
+ short dummy2;
+} WPOINT;
+
+typedef WPOINT *PWPOINT;
+
+ /* Start Additions YaronS */
+typedef struct _SUS {
+ USHORT x;
+} SUS;
+
+typedef SUS *PSUS;
+typedef struct _SUL {
+ ULONG x;
+} SUL;
+typedef SUL *PSUL;
+
+typedef SHANDLE HTIMER;
+typedef HTIMER *PHTIMER;
+
+typedef void *PFN;
+typedef void *PFNTHREAD;
+typedef void *PFNEXITLIST;
+typedef void *PFN32EXITLIST;
+
+
+typedef struct _FIOLOCKCMD { /* FLC FileLockCmd prefix */
+ USHORT usCmd; /* Cmd = FIO_LOCK */
+ USHORT cLockCnt; /* Lock records that follow */
+ ULONG cTimeOut; /* in Msec */
+} FIOLOCKCMD;
+typedef FIOLOCKCMD *PFIOLOCKCMD;
+
+
+typedef struct _FIOLOCKREC { /* FLR FileLockRecord */
+ USHORT fShare; /* FIO_NOSHARE or FIO_SHAREREAD */
+ ULONG cbStart; /* Starting offset for lock region */
+ ULONG cbLength; /* Length of lock region */
+} FIOLOCKREC;
+typedef FIOLOCKREC *PFIOLOCKREC;
+
+
+typedef struct _FIOUNLOCKCMD { /* FUC FileUnlockCmd prefix */
+ USHORT usCmd; /* Cmd = FIO_UNLOCK */
+ USHORT cUnlockCnt; /* Unlock records that follow */
+} FIOUNLOCKCMD;
+typedef FIOUNLOCKCMD *PFIOUNLOCKCMD;
+
+
+typedef struct _FIOUNLOCKREC { /* FUR FileUnlockRecord */
+ ULONG cbStart; /* Starting offset for unlock region */
+ ULONG cbLength; /* Length of unlock region */
+} FIOUNLOCKREC;
+typedef FIOUNLOCKREC *PFIOUNLOCKREC;
+
+
+typedef struct _FIOSEEKCMD { /* FSC Seek command structure */
+ USHORT usCmd; /* Cmd = FIO_SEEK */
+ USHORT fsMethod; /* One of&gml FPM_BEGINNING, FPM_CURRENT, */
+ /* or FPM_END */
+ ULONG cbDistance; /* Byte offset for seek */
+ ULONG cbNewPosition; /* Bytes from start of file after seek */
+} FIOSEEKCMD;
+typedef FIOSEEKCMD *PFIOSEEKCMD;
+
+
+typedef struct _FIOREADWRITE { /* RWC Read&Write command structure */
+ USHORT usCmd; /* Cmd = FIO_READ or FIO_WRITE */
+ PVOID pbBuffer; /* Pointer to data buffer */
+ USHORT cbBufferLen; /* Bytes in buffer or max size */
+ USHORT cbActualLen; /* Bytes actually read/written */
+} FIOREADWRITE;
+typedef FIOREADWRITE *PFIOREADWRITE;
+
+typedef struct _FSQBUFFER { /* fsqbuf Data structure for QFSAttach*/
+ USHORT iType; /* Item type */
+ USHORT cbName; /* Length of item name, sans NULL */
+ UCHAR szName[1]; /* ASCIIZ item name */
+ USHORT cbFSDName; /* Length of FSD name, sans NULL */
+ UCHAR szFSDName[1]; /* ASCIIZ FSD name */
+ USHORT cbFSAData; /* Length of FSD Attach data returned */
+ UCHAR rgFSAData[1]; /* FSD Attach data from FSD */
+} FSQBUFFER;
+typedef FSQBUFFER *PFSQBUFFER;
+
+typedef struct _FILEFINDBUF2 { /* findbuf2 */
+ FDATE fdateCreation;
+ FTIME ftimeCreation;
+ FDATE fdateLastAccess;
+ FTIME ftimeLastAccess;
+ FDATE fdateLastWrite;
+ FTIME ftimeLastWrite;
+ ULONG cbFile;
+ ULONG cbFileAlloc;
+ USHORT attrFile;
+ ULONG cbList;
+ UCHAR cchName;
+ UCHAR achName[256];
+} FILEFINDBUF2;
+typedef FILEFINDBUF2 *PFILEFINDBUF2;
+
+typedef struct _VOLUMELABEL { /* vol */
+ BYTE cch;
+ UCHAR szVolLabel[12];
+} VOLUMELABEL;
+typedef VOLUMELABEL *PVOLUMELABEL;
+
+typedef struct _FSINFO { /* fsinf */
+ FDATE fdateCreation;
+ FTIME ftimeCreation;
+ VOLUMELABEL vol;
+} FSINFO;
+typedef FSINFO *PFSINFO;
+
+typedef void *PFNSIGHANDLER;
+
+typedef struct _REGISTERDATA { /* regdata */
+ USHORT Length;
+ USHORT NotifType;
+ PSZ DDName;
+} REGISTERDATA;
+typedef REGISTERDATA *PREGISTERDATA;
+
diff --git a/private/os2/client/thunk/os2sm.def b/private/os2/client/thunk/os2sm.def
new file mode 100644
index 000000000..6de9de26c
--- /dev/null
+++ b/private/os2/client/thunk/os2sm.def
@@ -0,0 +1,13 @@
+LIBRARY OS2SM
+PROTMODE
+;SEGMENTS DOSMON_CODE PURE IOPL CONFORMING
+;SEGMENTS DosMon_DATA CLASS 'DATA' IMPURE
+
+;Note that IMPORTing is not necessary since we 'know' how to get to the
+; 32 bit, NT side, by magic (see nls.asm).
+;
+;All EXPORTS should have 1.0-compatible ordinals and "RESIDENTNAME"
+;EXPORTS usually get put in DOSCALLS.LIB; see LIB/MAKEFILE to make them private
+;EXPORTS DOSMONOPEN @4 RESIDENTNAME
+EXPORTS
+ WINSETTITLEANDICON @47 RESIDENTNAME
diff --git a/private/os2/client/thunk/pmnt.def b/private/os2/client/thunk/pmnt.def
new file mode 100644
index 000000000..8919dc10c
--- /dev/null
+++ b/private/os2/client/thunk/pmnt.def
@@ -0,0 +1,67 @@
+;
+; PMNT.DEF - Def file for undocumented services needed by 16-bit PM/NT DLL's
+;
+; Author:
+;
+; Patrick Questembert (PatrickQ) 20-Jul-1992
+;
+
+LIBRARY PMNT
+PROTMODE
+
+;Note that IMPORTing is not necessary since we 'know' how to get to the
+; 32 bit, NT side, by magic (see nls.asm).
+;
+;EXPORTS usually get put in DOSCALLS.LIB; see LIB/MAKEFILE to make them private
+EXPORTS
+ PMNTIOCTL @1 RESIDENTNAME
+ PMNTDBGPRINT @2 RESIDENTNAME
+ PMNTGETNEXTEVENT @3 RESIDENTNAME
+ PMNTMEMMAP @4 RESIDENTNAME
+ PMNTGETPGMNAME @5 RESIDENTNAME
+; 6 is PMNTGETCONSOLETITLE unused
+ PMNTSETCONSOLETITLE @7 RESIDENTNAME
+ PMNTSETFULLSCREEN @8 RESIDENTNAME
+ PMNTGETWIN32HWND @9 RESIDENTNAME
+ PMNTSETFOCUS @10 RESIDENTNAME
+ PMNTGETFULLSCREEN @11 RESIDENTNAME
+ PMNTSETPMSHELLFLAG @12 RESIDENTNAME
+ PMNTGETSYSTEMTIME @13 RESIDENTNAME
+ PMNTCREATEGROUP @14 RESIDENTNAME
+ PMNTADDPROGRAM @15 RESIDENTNAME
+ PMNTCHANGEPROGRAM @16 RESIDENTNAME
+ PMNTQUERYPROGRAMTITLES @17 RESIDENTNAME
+ PMNTQUERYDEFINITION @18 RESIDENTNAME
+ PMNTQUERYPROGRAMHANDLE @19 RESIDENTNAME
+ PMNTDESTROYGROUP @20 RESIDENTNAME
+ PMNTREMOVEPROGRAM @21 RESIDENTNAME
+ PMNTREGISTERDISPLAYADAPTER @22 RESIDENTNAME
+ PMNTIOMAP @23 RESIDENTNAME
+ PMNTISSESSIONROOT @24 RESIDENTNAME
+ PMNTCLOSEWINDOW @25 RESIDENTNAME
+ ; 26-28 are used for DBCS build (should be checked-in soon)
+#if DBCS
+; MSKK [ShigeO] Aug 26, 1993
+ PMNTCREATEFONTINDIRECT @26 RESIDENTNAME
+ PMNTGETTEXTMETRICS @27 RESIDENTNAME
+ PMNTGETSTRINGBITMAP @28 RESIDENTNAME
+#endif
+ PMNTDBGPROMPT @29 RESIDENTNAME
+ PMNTOPENCLIPBRD @30 RESIDENTNAME
+ PMNTCLOSECLIPBRD @31 RESIDENTNAME
+ PMNTEMPTYCLIPBRD @32 RESIDENTNAME
+ PMNTSETCLIPBRDTEXT @33 RESIDENTNAME
+ PMNTSETCLIPBRDBITMAP @34 RESIDENTNAME
+ PMNTQUERYCLIPBRDTEXT @35 RESIDENTNAME
+ PMNTQUERYCLIPBRDBITMAP @36 RESIDENTNAME
+ PMNTQUERYCLIPBRDFMTINFO @37 RESIDENTNAME
+ PMNTIDENTIFYCODESELECTOR @38 RESIDENTNAME
+ PMNTCREATEHIDDENTHREAD @39 RESIDENTNAME
+ PMNTWIN32CLIPBRD @40 RESIDENTNAME
+ PMNTVIOGETCONFIG @41 RESIDENTNAME
+ PMNTVIOGETCP @42 RESIDENTNAME
+ PMNTPROCESSISPMSHELL @45 RESIDENTNAME
+ PMNTQUERYSCREENSIZE @46 RESIDENTNAME
+; 47 is for PMNTDisableIME (MSKK)
+ PMNTSETSHUTDOWNPRIORITY @48 RESIDENTNAME
+ PMNTSETSUBPROCSEM @49 RESIDENTNAME
diff --git a/private/os2/client/thunk/pmshapi.def b/private/os2/client/thunk/pmshapi.def
new file mode 100644
index 000000000..b92c6af36
--- /dev/null
+++ b/private/os2/client/thunk/pmshapi.def
@@ -0,0 +1,10 @@
+LIBRARY PMSHAPI
+PROTMODE
+
+EXPORTS
+ WINQUERYPROFILEINT @2 RESIDENTNAME
+ WINQUERYPROFILESTRING @3 RESIDENTNAME
+ WINWRITEPROFILESTRING @4 RESIDENTNAME
+ WINQUERYPROFILESIZE @5 RESIDENTNAME
+ WINQUERYPROFILEDATA @6 RESIDENTNAME
+ WINWRITEPROFILEDATA @7 RESIDENTNAME
diff --git a/private/os2/client/thunk/pmwin.def b/private/os2/client/thunk/pmwin.def
new file mode 100644
index 000000000..30b80eb57
--- /dev/null
+++ b/private/os2/client/thunk/pmwin.def
@@ -0,0 +1,9 @@
+LIBRARY PMWIN
+PROTMODE
+
+EXPORTS
+ WINCREATEHEAP @225 RESIDENTNAME
+ WINDESTROYHEAP @226 RESIDENTNAME
+ WINALLOCMEM @228 RESIDENTNAME
+ WINFREEMEM @230 RESIDENTNAME
+ WINGETLASTERROR @243 RESIDENTNAME
diff --git a/private/os2/client/thunk/quecalls.def b/private/os2/client/thunk/quecalls.def
new file mode 100644
index 000000000..a510a7454
--- /dev/null
+++ b/private/os2/client/thunk/quecalls.def
@@ -0,0 +1,12 @@
+LIBRARY QUECALLS
+PROTMODE
+
+EXPORTS
+ DOSREADQUEUE @1 RESIDENTNAME
+ DOSPURGEQUEUE @2 RESIDENTNAME
+ DOSCLOSEQUEUE @3 RESIDENTNAME
+ DOSQUERYQUEUE @4 RESIDENTNAME
+ DOSPEEKQUEUE @5 RESIDENTNAME
+ DOSWRITEQUEUE @6 RESIDENTNAME
+ DOSOPENQUEUE @7 RESIDENTNAME
+ DOSCREATEQUEUE @8 RESIDENTNAME
diff --git a/private/os2/client/thunk/r2xfer.asm b/private/os2/client/thunk/r2xfer.asm
new file mode 100644
index 000000000..7415f4ca4
--- /dev/null
+++ b/private/os2/client/thunk/r2xfer.asm
@@ -0,0 +1,555 @@
+ TITLE r2xfer.asm
+
+ .386P
+
+ OPTION SEGMENT:USE16
+ .MODEL LARGE
+
+
+COMMENT $
+
+This file contains code and data that handles the case where a R3 code
+contains a call to a R2 entry point.
+
+In OS/2, only the selector part (call gate) of the call destination is
+meaningful.
+The OS/2 SS replaces the original call with a call to a jump table
+entry in the R2XFER code segment (which is the second code segment of
+DOSCALLS.DLL).
+
+The R2XFER code segment contains code that emulates the stack changing
+when transferring protection rings. The size of this code is limited to a
+predefined size since it is followed by other data structures which are
+set at run time by the loader. The limit is currently set to 0x200
+(which can be changed anytime later if it is found that 0x200 is not
+sufficient to handle the ring transfer emulation code).
+
+The code generated by this file is followed in memory by an array of Ring 2
+info which is prepared by the OS/2 SS loader.
+The array is variable length and each entry contains the following
+information:
+
+struct _R2CallInfo {
+ UCHAR R2CallNearInst; // Opcode of the call relative near inst (0xE8)
+ USHORT R2CommonEntry; // This field will contain the relative offset to 0H
+ UCHAR R2BytesToCopy; // Total size of proc parameters to copy between stacks
+ USHORT R2EntryPointOff; // Offset of entry address of R2 routine
+ USHORT R2EntryPointSel; // Selector of entry address of R2 routine
+} R2CallInfo;
+
+When a ring 3 routine calls a ring 2 routine (which the OS/2 SS loader
+changes to a call to the appropriate R2CallInfo entry, which does another
+call to the CommonR2Xfer routine) the R3 stack looks upon entry to
+CommonR2Xfer:
+
+param1
+param2
+param3
+return-addr-r3 CS
+ IP
+return-addr-r2 IP <- SP
+
+We want to start the R2 code with an R2 stack in the following format:
+
+ <- TOS
+<16 bytes free> These free bytes are a local work-around for the PMNTPrint()
+ accesses to the stack.
+Old SS
+Old SP
+0 These 2 zeroes are used to catch (by trap) any access
+0 of the ring 2 code to the ring 3 stack
+param1
+param2
+param3
+return-addr-r3 CS
+ IP <- SS:SP
+
+This file also defines a data segment that is used to hold information of the
+OS/2 SS ring 2 stacks. This data segment is the 3'rd segment of DOSCALLS.DLL
+The data is organized as an array with each entry representing the ring 2
+stack of the appropriate thread.
+
+Each entry in the array has the following format:
+
+struct _R2Stacks {
+ USHORT R2StackSize;
+ SEL R2StackSel;
+} R2Stacks[256];
+
+Entry 0 is not used since there is no thread 0.
+OS/2 supports 255 threads so this array contains enough entries.
+An entry of the array is initialized when the CommonR2Xfer routine
+is called by an OS/2 thread for the first time, with same ThreadID as
+the index of the enrty.
+OS/2 allocates 512 bytes as the initial size of the R2 stack and so
+do we.
+
+$
+
+R2Stacks STRUCT 1
+R2InitSP WORD 512 ; 0:512 indicates that no R2 stack exists
+R2StackSel WORD 0
+R2Stacks ENDS
+
+R2CallInfo STRUCT 1
+R2bytesToCopy BYTE ?
+R2EntryPoint DWORD ?
+R2CallInfo ENDS
+
+EXTERN DosAllocSeg:FAR
+
+ .CODE
+ PUBLIC CommonR2Xfer
+CommonR2Xfer PROC FAR
+
+; Push all registered involved in the emulation. The order of the push
+; was selected to allow easy exchange of stacks.
+
+ push BP
+ mov BP,SP
+ push AX
+ push ES
+ push DI
+ push SI
+ push BX
+ push CX
+ push DX
+
+; The stack of the calling process is now:
+;
+; param1 SP+26 BP+12
+; param2 SP+24 BP+10
+; param3 SP+22 BP+8
+; return-addr-r3 CS SP+20 BP+6
+; IP SP+18 BP+4
+; return-addr-r2 IP SP+16 BP+2
+; BP SP+14 BP
+; AX SP+12 BP-2
+; ES SP+10 BP-4
+; DI SP+8 BP-6
+; SI SP+6 BP-8
+; BX SP+4 BP-10
+; CX SP+2 BP-12
+; DX SP BP-14
+
+ mov BX,FS:6 ; Get current thread ID. FS points to the LINFOSEG
+ shl BX,2 ;
+ add BX,2 ; BX points now to SEL part of the R2 TOS (Top Of Stack)
+ mov AX,SEG R2StacksInfo
+ mov ES,AX ;
+ mov AX,ES:[BX] ; AX contains the SEL of the R2 TOS
+ or AX,AX ; Verify that the thread has a R2 stack
+ jnz R2CheckIfCalledFromR2; If yes, skip creation of R2 Stack
+ ;
+ ; Create R2 Stack
+ ;
+ push 512 ; Allocate stack with size of 512 bytes (same as OS/2)
+ push ES ; ES:BX contain the address of the Stack entry
+ push BX ;
+ push 0 ; Flags for SEG_NONSHARED
+ call DosAllocSeg ; Allocate a R2 stack segment
+ or AX,AX ; Check if the allocation succeeded
+ jz R2StackExists ; Yes.
+ pop DX ; No. What to do? Restore all registers and return...
+ pop CX ;
+ pop BX ;
+ pop SI ;
+ pop DI ;
+ pop ES ;
+ pop AX ;
+ pop BP ;
+ add SP,2 ; Ignore the return to the R2CallInfo entry
+ retf ; Just return...
+ ;
+ ; Check if we call a ring 2 function from within ring 2.
+ ; If yes, no need to change stacks.
+ ; AX contains the ring 2 stack selector
+ ;
+R2CheckIfCalledFromR2:
+ mov CX,SS ; Get current Stack Segment
+ cmp CX,AX ; Compare with the R2 SS
+ jne R2StackExists ; Not the same. Change stacks.
+ mov SI,[BP+2] ; SI contains a pointer to the R2BytesToCopy field
+ ; in the call table entry
+ mov EAX,CS:[SI].R2CallInfo.R2EntryPoint ; EAX contains the Address of the R2 destination
+ pop DX ; Restore registers.
+ pop CX ;
+ pop BX ;
+ pop SI ;
+ pop DI ;
+ pop ES ;
+ push word ptr [BP] ; The old BP is going to be overwritten...
+ mov [BP],EAX ; Old BP and return-addr-r2 are overwritten.
+ pop BP ; Retsore Old BP from Stack
+ pop AX ;
+ retf ; return to the R2 code
+ ;
+ ; A R2 stack exists or was created
+ ;
+R2StackExists:
+ ;
+ ; The calls to DosXXX preserve all registers except AX,
+ ; so BX was not changed and we can use it
+ ;
+ les DI,ES:[BX-2] ; ES:DI points to the top of the R2 stack
+ sub DI,4+4+16 ; allocate place for old SS:SP, 2 zeroes and 16 free bytes
+ mov ES:[DI+6],SS ; Save old SS
+ mov BX,BP ;
+ add BX,4 ; 8-4 (the 4 in the R3 stack is used to move there
+ ; the return address to the function in R3 that
+ ; called the R2 routine).
+ mov SI,[BP+2] ; SI contains a pointer to the R2BytesToCopy field
+ ; in the call table entry
+ mov EDX,CS:[SI].R2CallInfo.R2EntryPoint ; EDX contains the Address of the R2 destination
+ movzx CX,CS:[SI].R2CallInfo.R2BytesToCopy ; CX contains the # of bytes to copy
+ jcxz no_params
+ mov AX,CX ; save a copy of the number of parameters
+ add BX,CX ; Assume as if the R3 params were removed
+ mov ES:[DI+4],BX ; Save old sp
+ mov word ptr ES:[DI],0 ; Clear the R3 access trap catch bytes
+ mov word ptr ES:[DI+2],0 ;
+ sub DI,CX ; DI points to lowest address for parameters of
+ ; the R2 stack
+ lea SI,[BP+8] ; source of the copy in the R3 stack
+ cld ;
+ shr CX,1
+ rep movs word ptr ES:[DI],SS:[SI] ; copy all the arguments
+ sub DI,AX ; DI now points to the begining of the lowest R2
+ ; arguments
+ jmp short params_copied
+
+no_params:
+ xor AX,AX ; Remember number of parameters
+ mov ES:[DI+4],BX ; Save old sp (no need to add CX)
+ mov word ptr ES:[DI],0 ; Clear the R3 access trap catch bytes
+ mov word ptr ES:[DI+2],0 ;
+;
+; The R2 stack looks now like this:
+;
+; <16 free bytes>
+; Old SS
+; Old SP
+; 0
+; 0
+; param1
+; param2
+; param3 <- ES:DI
+;
+params_copied:
+ sub DI,16 ; DI points at the lowest parameter on the R2 stack
+ mov ES:[DI+14],CS ; save return address from R2 procedure to this code
+ mov ES:[DI+12], OFFSET R2CodeRet
+ mov ES:[DI+8],EDX ; put on the R2 stack the address of the R2 procedure
+;
+; The R2 stack looks now like this:
+;
+; <16 free bytes>
+; Old SS
+; Old SP
+; 0
+; 0
+; param1
+; param2
+; param3
+; CS of this code DI+14
+; Offset of R2CodeRet DI+12
+; ring-2-entry CS DI+10
+; IP DI+8
+; free DI+6
+; free DI+4
+; free DI+2
+; free <- ES:DI
+;
+ ;
+ ; copy the R3 return address over the first parameter pushed onto the R3 stack
+ ;
+ mov EDX,[BP+4] ; old CS:IP
+ mov BX,BP ;
+ add BX,AX ; Add # of parameter bytes
+ mov SS:[BX+4],EDX ; save return address over first parameters
+;
+; The R3 stacks looks now like this:
+;
+; return-addr-r3 CS SP+26 BP+12
+; return-addr-r3 IP SP+24 BP+10
+; param3 SP+22 BP+8
+; return-addr-r3 CS SP+20 BP+6
+; IP SP+18 BP+4
+; return-addr-r2 IP SP+16 BP+2
+; BP SP+14 BP
+; AX SP+12 BP-2
+; ES SP+10 BP-4
+; DI SP+8 BP-6
+; SI SP+6 BP-8
+; BX SP+4 BP-10
+; CX SP+2 BP-12
+; DX SP BP-14
+;
+ pop DX ;
+ pop CX ;
+ pop BX ;
+ pop SI ;
+ mov EAX,[BP-2] ; EAX contains original BP:AX
+ mov ES:[DI+4],EAX ;
+ mov EAX,[BP-6] ; EAX contains original ES:DI
+ mov ES:[DI],EAX ;
+;
+; The R2 stack looks now like this:
+;
+; <16 free bytes>
+; Old SS
+; Old SP
+; 0
+; 0
+; param1
+; param2
+; param3
+; free
+; free
+; ring-2-entry CS
+; IP
+; original BP
+; original AX
+; original ES
+; original DI <- ES:DI
+;
+ mov SP,DI ; exchange the stack to the R2 stack
+ mov AX,ES ;
+ mov SS,AX ;
+ pop DI ; Restore all registers
+ pop ES ;
+ pop AX ;
+ pop BP ;
+;
+; The R2 stack looks now like this:
+;
+; <16 free bytes>
+; Old SS
+; Old SP
+; 0
+; 0
+; param1
+; param2
+; param3
+; CS of this code
+; Offset of R2CodeRet from beginning of segment
+; ring-2-entry CS
+; IP <- SS:ESP
+;
+
+ retf ; call the R2 actual code
+
+ ;
+ ; Here we return from the R2 code
+ ;
+R2CodeRet:
+ push BP
+ mov BP,SP
+ push AX
+ push ES
+ push DI
+ mov DI,FS:6 ; Index of thread
+ shl DI,2
+ mov AX, SEG R2StacksInfo
+ mov ES,AX
+ les DI,ES:[DI] ; ES:DI point to Top of R2 stack
+ les DI,ES:[DI-(4+16)] ; ES:DI contain the current R3 stack pointer
+ sub DI,8 ; DI points below return address to R3
+ mov EAX,[BP-2] ; move using EAX old BP:AX from R2 stack to R3 stack
+ mov ES:[DI+4],EAX ;
+ mov EAX,[BP-6] ; move using EAX ES:DI from R2 stack to R3 stack
+ mov ES:[DI],EAX ;
+ mov [BP],ES ;
+ mov [BP-2],DI ;
+ lss SP,[BP-2] ;
+ pop DI ;
+ pop ES ;
+ pop AX ;
+ pop BP ;
+ retf
+
+IF ($-CommonR2Xfer) GT 200H
+;
+; The size of the code segment exceeds 200H
+; The ldr assumes that it is not greater than 200H
+; If you have reached here and increased the value above 200H
+; you have to modify also the OS/2 SS file ldr\ldrinit.c
+;
+.ERR SizeOfSegmentExceeds200H
+ENDIF
+
+CommonR2Xfer ENDP
+
+;
+; Next statement is used to make the size of the segment exactly 64K
+; It causes the linker to issue warning L4020:
+;
+; segment: code segment size exceeds 64K-36
+;
+; Ignore the warning!
+;
+
+ ORG 0FFFFH ; This statement causes the linker to create
+ ; a segment virtual size of 64K
+
+ .DATA
+
+R2StacksInfo R2Stacks 256 DUP (<>)
+
+ .CODE THUNK16
+
+ PUBLIC DOSCALLBACK
+DOSCALLBACK PROC FAR
+
+; The ring 2 stack upon entry:
+;
+; Target Callee (segment)
+; Target Callee (offset)
+; Ret Address (segment)
+; Ret Address (offset) <- SP
+;
+
+;
+; Move to ring 3 and change the stack to ring 3 stack
+;
+
+ ; Preserve reDIsters accross the call
+
+ push BP
+ mov BP,SP
+ push AX
+ push ES
+ push DI
+ push DS
+ push SI
+
+; R2 stack is now:
+;
+; Target Callee (segment) BP+8
+; Target Callee (offset) BP+6
+; Ret Address (segment) BP+4
+; Ret Address (offset) BP+2
+; old BP <- BP
+; AX
+; ES
+; DI
+; DS
+; SI <- SP
+
+ mov DI,FS:6 ; Get current thread ID. FS points to the LINFOSEG
+ shl DI,2 ; DI points now to SEL:OFF of the R2 TOS (Top Of Stack)
+ mov AX,SEG R2StacksInfo
+ mov ES,AX ;
+ lds SI,ES:[DI] ; DS:SI contain the R2 TOS
+
+ mov AX,SS
+ cmp AX,DS:[SI-18] ; Check if we are on the R3 ring
+ jne doscallback_R2
+
+ ; The current ring is R3
+
+ pop SI
+ pop DS
+ pop DI
+ pop ES
+ pop AX
+
+ call dword ptr [BP+6]
+
+ pop BP
+ retf 4
+
+doscallback_R2:
+
+ push SI ; Save OS2 TOS
+ lds SI,DS:[SI-20] ; DS:SI contain the R3 current stack
+
+ mov ES:[DI],BP ; Set a new ring 2 TOS for ring 3 -> ring 2
+ add word ptr ES:[DI],4 ; transitions.
+
+ ;
+ ; set a return address to the DosRetForward() API
+ ;
+
+ sub SI,10 ; Allocate space on the ring 3 stack
+ mov AX, SEG DosRetForward
+ mov DS:[SI+8],AX
+ mov AX,OFFSET DosRetForward
+ mov DS:[SI+6],AX
+
+ mov AX,[BP+8] ; Target Callee (segment)
+ mov DS:[SI+4],AX ;
+ mov AX,[BP+6] ; Target Callee (offset)
+ mov DS:[SI+2],AX ;
+ mov AX,[BP] ; old BP
+ mov DS:[SI],AX ;
+ ;
+ ; move the R2 return address to a new location on the R2 stack
+ ; so that we can return back to the R2 function that called DosCallBack()
+ ;
+ mov AX,[BP+4] ; Ret address (segment)
+ mov [BP+8],AX ;
+ mov AX,[BP+2] ; Ret address (offset)
+ mov [BP+6],AX ;
+ ;
+ ; Save old R2 TOS in the R2 stacks data structure
+ ;
+ pop word ptr [BP+4]
+ ;
+ ; save ring 3 SS:SP for task switch (done by the LSS instruction below)
+ ;
+ mov [BP],SI
+ mov [BP+2],DS
+
+ pop SI ; Restore saved reDIster
+ pop DS
+ pop DI
+ pop ES
+ pop AX
+ lss SP,[BP] ; switch stacks
+ pop BP
+
+ retf ; perform call to user routine in ring 3
+
+DOSCALLBACK ENDP
+
+DOSRETFORWARD PROC FAR
+
+ sub SP,2 ; allocate space on the ring 3 stack
+ push BP
+ mov BP,SP
+ push AX
+ push ES
+ push DI
+ push DS
+ push SI
+
+ mov DI,FS:6 ; Get current thread ID. FS points to the LINFOSEG
+ shl DI,2 ; DI points now to SEL:OFF of the R2 TOS (Top Of Stack)
+ mov AX,SEG R2StacksInfo
+ mov ES,AX ;
+ lds SI,ES:[DI] ; DS:SI contain the R2 TOS
+ mov AX,DS:[SI] ; ring 2 prev TOS
+ mov ES:[DI],AX
+
+ mov AX,[BP] ; Get old BP and save it on the ring 2 stack
+ mov DS:[SI],AX
+ ;
+ ; save ring 2 SS:SP for task switch (done by the LSS instruction below)
+ ;
+ mov [BP+2],DS
+ mov [BP],SI
+
+ pop SI
+ pop DS
+ pop DI
+ pop ES
+ pop AX
+ lss SP,[BP]
+ pop BP
+
+ retf ; return to the ring 2 routine that called DosCallBack()
+
+DOSRETFORWARD ENDP
+ END
+
diff --git a/private/os2/client/thunk/sesmgr.def b/private/os2/client/thunk/sesmgr.def
new file mode 100644
index 000000000..07ce7d2ba
--- /dev/null
+++ b/private/os2/client/thunk/sesmgr.def
@@ -0,0 +1,52 @@
+LIBRARY SESMGR
+PROTMODE
+;SEGMENTS DOSMON_CODE PURE IOPL CONFORMING
+;SEGMENTS DosMon_DATA CLASS 'DATA' IMPURE
+
+;Note that IMPORTing is not necessary since we 'know' how to get to the
+; 32 bit, NT side, by magic (see nls.asm).
+;
+;All EXPORTS should have 1.0-compatible ordinals and "RESIDENTNAME"
+;EXPORTS usually get put in DOSCALLS.LIB; see LIB/MAKEFILE to make them private
+;EXPORTS DOSMONOPEN @4 RESIDENTNAME
+EXPORTS
+; DOSSMSGDOPOPUP @1 RESIDENTNAME
+; DOSSMSWITCH @2 RESIDENTNAME
+; DOSSMSERVEAPPREQ @3 RESIDENTNAME
+; DOSGETTIMES @4 RESIDENTNAME
+ DOSSMSETTITLE @5 RESIDENTNAME
+; DOSSCRUNLOCK @6 RESIDENTNAME
+; DOSSMDOAPPREQ @7 RESIDENTNAME
+ DOSSTOPSESSION @8 RESIDENTNAME
+ DOSSELECTSESSION @9 RESIDENTNAME
+; DOSSCRLOCK @10 RESIDENTNAME
+; DOSSAVREDRAWWAIT @11 RESIDENTNAME
+; DOSSAVREDRAWUNDO @12 RESIDENTNAME
+; DOSSMSGENDPOPUP @13 RESIDENTNAME
+ DOSSETSESSION @14 RESIDENTNAME
+; DOSSETMNLOCKTIME @15 RESIDENTNAME
+; DOSMODEUNDO @16 RESIDENTNAME
+ DOSSTARTSESSION @17 RESIDENTNAME
+; DOSSMGETSTATUS @18 RESIDENTNAME
+; DOSMODEWAIT @19 RESIDENTNAME
+; DOSSMTERMINATE @20 RESIDENTNAME
+; DOSSMGETAPPREQ @21 RESIDENTNAME
+; DOSSMINITIALIZE @23 RESIDENTNAME
+; DOSSMSTART @24 RESIDENTNAME
+; DOSSMPARENTSWITCH @25 RESIDENTNAME
+#if PMNT
+ DOSSMPAUSE @26 RESIDENTNAME
+#endif
+; DOSSMHDEINIT @27 RESIDENTNAME
+ DOSSMPMPRESENT @28 RESIDENTNAME
+; DOSSMREGISTERDD @29 RESIDENTNAME
+; DOSSMSYSINIT @30 RESIDENTNAME
+; DOSSMNOTIFYDD @31 RESIDENTNAME
+; DOSSMNOTIFYDD2 @32 RESIDENTNAME
+; DOSSMOPENDD @33 RESIDENTNAME
+; DOSSMSETSESSIONTYPE @36 RESIDENTNAME
+; DOS32STARTSESSION @37 RESIDENTNAME
+; DOS32SELECTSESSION @38 RESIDENTNAME
+; DOS32SETSESSION @39 RESIDENTNAME
+; DOS32STOPSESSION @40 RESIDENTNAME
+
diff --git a/private/os2/client/thunk/thunkcom/cod1632.c b/private/os2/client/thunk/thunkcom/cod1632.c
new file mode 100644
index 000000000..94815f243
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/cod1632.c
@@ -0,0 +1,1482 @@
+/*
+ * Thunk Compiler - Routines for Code Generator (16=>32).
+ *
+ * This is a OS2/16 on NT specific file
+ * Microsoft Confidential
+ *
+ * Copyright (c) Microsoft Corporation 1991
+ *
+ * All Rights Reserved
+ *
+ * 04.11.91 YaronS Took from KevinR (WIN4), and Adopt for OS216/NT
+ * (many changes: calling convention, register usage)
+ * 8 Sep 92 PatrickQ Added support for PMNT
+ */
+
+#include <stdio.h>
+#include "error.h"
+#include "thunk.h"
+#include "types.h"
+#include "symtab.h"
+#include "codegen.h"
+#include "globals.h"
+#include "..\..\..\inc\os2tile.h"
+
+extern FILE *StdDbg;
+
+
+/*******************************************************************************
+ * cod16_EnableMapDirect()
+ *
+ * This routine
+ *
+ * Entry:
+ *
+ * Exit:
+ *
+ * PCode:
+ *
+ * History:
+ * 21mar91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_EnableMapDirect( INT iCallTypeFrom, INT iCallTypeTo)
+{
+ PFUNCTIONNODE pfnnFrom, pfnnTo;
+
+ for( pfnnFrom = FunctionTable;
+ pfnnFrom;
+ pfnnFrom = pfnnFrom->pNextFunctionNode) {
+
+ pfnnTo = pfnnFrom->pMapsToFunction;
+ if( (pfnnFrom->iCallType == iCallTypeFrom) &&
+ (pfnnTo->iCallType == iCallTypeTo)) {
+
+ if( sym_FindFMapping( MapTable, pfnnFrom->pchFunctionName,
+ pfnnTo->pchFunctionName)) {
+ error( "A mapping %s <=> %s already defined",
+ pfnnFrom->pchFunctionName, pfnnTo->pchFunctionName);
+ } else {
+ sym_AddFMapping( &MapTable, pfnnFrom, pfnnTo);
+ }
+ }
+ }
+}
+
+
+/*******************************************************************************
+ * cod16_Handle16()
+ *
+ * This routine generates the 32-bit side of a 16=>32 thunk.
+ *
+ * Entry: pmnFirst is a pointer to the list of mapping nodes.
+ *
+ * Exit: code was emitted
+ *
+ * PCode:
+ * Traverse Parameter lists of both functions
+ * - Determine stack offsets of each parameter
+ * - Determine offsets for each structure field
+ * - Generate the thunk assembly code
+ *
+ * History:
+ * 20feb91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_Handle16( PMAPNODE pmnFirst)
+{
+ PMAPNODE pmn;
+
+/* YaronS - omit this line
+ * printf("\tOPTION READONLY\n");
+ */
+/*
+* YaronS simplify - if GEN16 is not defined, then do GEN32
+* printf("IFNDEF GEN16\n");
+* printf("IFNDEF GEN32\n");
+* printf("%sout command line error: specify one of -DGEN16 -DGEN32\n", "%");
+* printf(".err\n");
+* printf("ENDIF\n");
+* printf("ENDIF\n");
+*/
+ printf("IFDEF GEN16\n");
+ printf("IFDEF GEN32\n");
+ printf("%sout command line error: you can't specify both "
+ "-DGEN16 and -DGEN32\n", "%");
+ printf(".err\n");
+ printf("ENDIF\n\n");
+
+ printf("\tOPTION SEGMENT:USE16\n");
+ printf("\t.model LARGE,PASCAL\n\n");
+
+ for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping) {
+ printf("externDef %s:far16\n", pmn->pFromNode->pchFunctionName);
+ }
+
+ printf("externDef _EntryFlat@0:far32\n\n");
+ printf("\t.code %s\n\n", CODE16_NAME);
+
+ BIG_DIVIDE;
+ printf("; This is the table of 16-bit entry points.\n");
+ printf("; It must be at the beginning of its segment.\n");
+ printf("; The entries are each 4 bytes apart, and the effect of the\n");
+ printf("; call instruction is to push the offset (+4) into the flat\n");
+ printf("; thunk table, used after the jump to 32-bit-land.\n\n");
+
+ for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping) {
+ printf("%s label far16\n", pmn->pFromNode->pchFunctionName);
+ printf("\t%s\n", fBPEntry ? "int\t3" : "nop");
+ printf("\tcall\tEntryCommon16\n\n");
+ }
+ printf("\n; These are two global variables exported by doscalls\n\n");
+ printf("public DOSHUGEINCR\n");
+ printf("DOSHUGEINCR\tequ\t8\n");
+ printf("public DOSHUGESHIFT\n");
+ printf("DOSHUGESHIFT\tequ\t3\n\n");
+
+ BIG_DIVIDE;
+ printf("; This is the common setup code for 16=>32 thunks. It:\n");
+ printf("; 1. retrieves the 32-bit jump table offset from the stack\n");
+ printf("; 2. saves registers\n");
+ printf("; 3. saves ss:sp\n");
+ printf("; 4. jumps to 32-bit code\n");
+ printf(";\n");
+ printf("; Entry: flat jump table offset (+4) is on top of stack\n");
+ printf("; AX contains the DLL init routine ret value for the\n");
+ printf("; LDRLIBIRETURN entry, VOID otherwise.\n");
+ printf(";\n");
+ printf("; Exit: (eax[15-0]) == flat jump table offset (+4)\n");
+ printf("; (eax[31-16]) == return value of DLL init routine for LDRLIBIRETURN\n");
+ printf("; (ebx) == new esp\n\n");
+
+ printf("EntryCommon16:\n");
+ printf("\tshl\teax,16\t\t; 16 MSB of eax contain the DLL init ret value\n");
+ printf("\tpop\tax\t\t; 16 LSB of eax contain the offset in jump table\n\n");
+
+ printf("\tpush\tds\t\t; save ds\n");
+ printf("\tpush\tes\t\t; save es\n");
+ printf("\tpush\tdi\n");
+ printf("\tpush\tsi\n");
+ printf("\tpush\tcx\n");
+ printf("\tpush\tbx\n");
+ printf("\tpush\tdx\n");
+ printf("\tpush\tbp\n\n");
+
+ printf("\tmov\tbx,sp\t\t; save current ss:sp\n");
+ printf("\tpush\tss\n");
+ printf("\tpush\tbx\n\n");
+
+/* YaronS - we do arithmetic instead of GetSelctorBase
+ *
+ */
+ printf("; compute flat esp\n");
+ printf("; NOTE - we implement FARPTRTOFLAT by arith\n\n");
+ printf("\tmov\tbx,ss\n");
+ printf("\tshr\tbx,3\n");
+ printf("\tadd\tbx,%xH\n", (unsigned short)(BASE_TILE >> 16));
+ printf("\tshl\tebx,16\n");
+ printf("\tmov\tbx,sp\t\t; (ebx) == FLAT esp\n\n");
+
+/*
+ * YaronS - Hardwire the jump address to the
+ * the NT OS2DLL.DLL place
+ */
+ printf(";force a long, far jump into 32 bit thunks, where EntryFlat resides\n");
+ printf(";jmp\t1b:063023D80h\n\n");
+ printf("\tdb\t066h, 0eah, 0ddh, 01fh, 090h, 090h, 01bh, 00h\n\n");
+
+}
+
+/*******************************************************************************
+ * cod16_Prolog32()
+ *
+ * This routine generates the 32-bit prolog for 16=>32 thunks.
+ *
+ * Entry: pmnFirst is a pointer to the list of mapping nodes.
+ *
+ * Exit: code was emitted
+ *
+ * PCode:
+ *
+ * History:
+ * 21feb91 KevinR wrote it
+ * 11Apr91 YaronS Adapt to OS2/NT. we assemble it with a
+ * different assembler, different code seg etc.
+ *
+ ******************************************************************************/
+
+void cod16_Prolog32( PMAPNODE pmnFirst)
+{
+ PMAPNODE pmn;
+ PSZ psz;
+ INT i;
+ USHORT icStackFrame;
+
+
+ printf("ELSE\t; GEN32\n");
+
+/* YaronS - for 32 bit we don't use externDef (NT asm doesn't understand) */
+
+ for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping) {
+ icStackFrame = cod_CountParameterBytes(pmn->pToNode->ParamList,
+ DWORD_SIZE);
+ printf("extrn %s@%u:PROC\n", pmn->pToNode->pchFunctionName,
+ icStackFrame);
+ }
+
+ printf("extrn _GetSaved32Esp@0:PROC\n");
+ printf("extrn _Save16Esp@0:PROC\n");
+// printf("IF DBG\n");
+ printf("extrn _Od216ApiPrint@4:PROC\n");
+// printf("ENDIF DBG\n");
+
+ printf("\n_TEXT\tSEGMENT DWORD USE32 PUBLIC 'CODE'\n");
+ printf("\tASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING\n");
+
+ BIG_DIVIDE;
+ printf("; This is the common flat entry point for 16=>32 thunks. It:\n");
+ printf("; 1. makes ds, es, ss FLAT\n");
+ printf("; 2. saves esp in ebx\n");
+ printf("; 3. dword-aligns the stack\n");
+ printf("; 4. jumps to the API-specific thunk code indicated in ax\n");
+ printf(";\n");
+ printf("; Entry: (ax) == flat jump table offset (+4)\n");
+ printf("; (ebx) == flat esp\n\n");
+
+ printf("\tpublic\t_EntryFlat@0\n");
+ printf("\textrn\t_Od2Saved16Stack:DWORD\n");
+ printf("\textrn\t_MoveInfoSegintoTeb:PROC\n");
+ printf("\textrn\t_RestoreTeb:PROC\n\n");
+
+ printf("_EntryFlat@0\tproc\n\n");
+
+ printf("\tmov\tdx,023H\n");
+ printf("\tmov\tds,dx\t\t\t; FLAT ds\n");
+ printf("\tmov\tes,dx\t\t\t; FLAT es\n\n");
+ printf("\tpush\teax\n");
+ printf("\tcall\t_RestoreTeb\n\n");
+
+ printf("\t; 16bit stack must be saved to allow proper signal handler execution\n");
+ printf("\tcall\t_Save16Esp@0\n");
+ printf("\tor\tal,al\n");
+ printf("\tjz\tEntryFlat1\n");
+ printf("\tmov\t_Od2Saved16Stack,ebx\t; Save 16-bit stack\n\n");
+
+ printf("EntryFlat1:\n");
+ printf("\tcall\t_GetSaved32Esp@0\n");
+ printf("\tpop\tecx\t\t\t; restore the thunk index/LDRLIBIRETURN ret value\n\n");
+
+ printf("\tand\teax,0fffffffcH\t\t; dword-align the 32bit stack pointer\n");
+ printf("\tmov\tdx,23H\n");
+ printf("\tpush\tdx\t\t\t; flat SS\n");
+ printf("\tpush\teax\t\t\t; flat ESP\n");
+ printf("\tlss\tesp,[ebx-6]\t\t; switch to 32bit stack\n\n");
+
+ if( fUser) {
+ printf("\tsub\tesp,4\t\t\t; make room for old SS16\n");
+ printf("\tpush\teax\n");
+ printf("\tcall\tQuerySS16\n");
+ printf("\tmov\t[ebx-4],eax\t\t; old SS16\n");
+ printf("\tpush\t[ebx+2]\t\t\t; 16-bit SS\n");
+ printf("\tcall\tSetSS16\n");
+ printf("\tpop\teax\n\n");
+ }
+
+// printf("IF DBG\n");
+ printf("\tpush\tecx\n");
+ printf("\tand\tecx,0ffffH\t\t; clear hi word\n");
+ printf("\tpush\tecx\n\n");
+
+ printf("\tcall\t_Od216ApiPrint@4\n");
+ printf("\tpop\tecx\n\n");
+// printf("ENDIF DBG\n");
+
+ printf("\tmov\teax,ecx\n");
+ printf("\tshr\teax,16\t\t\t; (eax) contains the LDRLIBIRETURN ret value\n");
+ printf("\tand\tecx,0ffffH\n");
+ printf("\tmov\tebp,esp\t\t\t; Compiler assumes this for ebp elimination\n");
+ printf("\tjmp\tdword ptr FlatTable[ecx-4]\t; select specific thunk\n");
+ printf("_EntryFlat@0\tendp\n\n");
+
+ BIG_DIVIDE;
+ printf("; Common routines to restore the stack and registers\n");
+ printf("; and return to 16-bit code. There is one for each\n");
+ printf("; size of 16-bit parameter list in this script.\n\n");
+
+ printf("\tpublic _ExitFlatAreaBegin@0\n");
+ printf("_ExitFlatAreaBegin@0:\n\n");
+
+ for( i=0; i < sizeof( afFromNodeBytesUsed); i++)
+ afFromNodeBytesUsed[ i] = FALSE;
+
+ for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping) {
+ cod_CalcStructOffsets( pmn->pFromNode->ParamList, WORD_SIZE);
+ cod_CalcStructOffsets( pmn->pToNode->ParamList, iPackingSize);
+ cod_CalcOffset( pmn->pFromNode->ParamList, 24, WORD_SIZE, PUSH_LEFT);
+
+ afFromNodeBytesUsed[ cod_CountParameterBytes( pmn->pFromNode->ParamList,
+ WORD_SIZE)
+ / WORD_SIZE] = TRUE;
+ }
+
+ for( i=0; i < sizeof( afFromNodeBytesUsed); i++) {
+ if( afFromNodeBytesUsed[ i]) {
+ printf("ExitFlat_%u:\n", i * WORD_SIZE);
+ printf("\tcall\t_MoveInfoSegintoTeb\n\n");
+ printf("\tmov\tcx,word ptr [ebx+16]\t; ES\n");
+ printf("\tshl\tecx,16\n");
+ printf("\tmov\tdx,word ptr [ebx+18]\t; DS\n");
+ printf("\tshl\tedx,16\n");
+ cod16_GenRet16( i * WORD_SIZE, TRUE, TRUE);
+ }
+ }
+
+ printf("\tpublic _ExitFlatAreaEnd@0\n");
+ printf("_ExitFlatAreaEnd@0:\n\n");
+
+ BIG_DIVIDE;
+ printf("; This is a jump table to API-specific flat thunk code.\n");
+ printf("; Each entry is a dword.\n\n");
+ printf("FlatTable label near\n");
+
+ for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping)
+ printf("\tdd\toffset _TEXT:T_%s\n", pmn->pToNode->pchFunctionName);
+ printf("\n");
+
+/*
+ * YaronS - the following is a macro that replaces SelToFlat,
+ * since we can do tiling
+ */
+ printf(";---- SelToFlat Macro ----\n");
+ printf(";\t On Entry:\t eax==Sel:Off\n");
+ printf(";\t On Exit:\t eax==Flat Offset\n");
+ printf("SelToFlat macro\n");
+ printf("\tpush\tecx\n");
+ printf("xor\tecx,ecx\n");
+ printf("mov\tcx,ax\t; ecx<-offset in segment\n");
+ printf("shr\teax,3\t\n");
+ printf("xor\tax,ax\t; eax now contains segment base\n");
+ printf("\tadd\teax,ecx\t; eax <- flat offset\n");
+ printf("\tadd\teax,%lxH\n", BASE_TILE);
+ printf("\tpop\tecx\n");
+ printf("endm\n\n");
+
+}
+
+/*****************************************************************************
+ * cod16_Epilog32()
+ *
+ * This routine generates the 32-bit epilog for 16=>32 thunks.
+ *
+ * Entry: pmnFirst is a pointer to the list of mapping nodes.
+ *
+ * Exit: code was emitted
+ *
+ * PCode:
+ *
+ * History:
+ * 21feb91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_Epilog32( PMAPNODE pmnFirst)
+{
+ printf("_TEXT ends\n");
+ printf("ENDIF\n");
+ printf("\tend\n");
+}
+
+/*******************************************************************************
+ * cod16_Handle32()
+ *
+ * This routine generates the 32-bit side of a 16=>32 thunk.
+ *
+ * Entry: pmn is a pointer to a MapNode.
+ *
+ * Exit: code was emitted
+ *
+ * PCode:
+ * Traverse Parameter lists of both functions
+ * - Determine stack offsets of each parameter
+ * - Determine offsets for each structure field
+ * - Generate the thunk assembly code
+ *
+ * History:
+ * 20feb91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_Handle32( PMAPNODE pmn)
+{
+ iStackCurrent = 0;
+
+ cod16_Entry( pmn);
+ cod16_TempStorage( pmn);
+ cod16_PackParams( pmn);
+ cod16_CallFrame( pmn);
+ cod16_Return( pmn);
+ cod16_UnpackParams( pmn);
+ cod16_Exit( pmn, TRUE, TRUE);
+}
+
+/*******************************************************************************
+ * cod16_Entry()
+ *
+ * This routine will generate the entry code for one thunk.
+ *
+ * Entry: pmn is a pointer to a MapNode.
+ *
+ * Exit: Entry code will have been written to the output file.
+ *
+ * PCode: gen label
+ *
+ * History:
+ * 21feb91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_Entry( PMAPNODE pmn)
+{
+ PTYPENODE ptn;
+
+ BIG_DIVIDE;
+
+ printf("T_%s label near\n\n", pmn->pToNode->pchFunctionName);
+ for( ptn = pmn->pFromNode->ParamList; ptn; ptn = ptn->pNextNode)
+ if( !ptn->iDeleted)
+ printf("; ebx+%-3u %s\n",
+ ptn->iOffset, typ_NonNull( ptn->pchIdent));
+ printf("\n");
+}
+
+/*******************************************************************************
+ * cod16_TempStorage()
+ *
+ * This routine will generate temporary storage code.
+ *
+ * Entry: pmn is a pointer to a MapNode.
+ *
+ * Exit: Temporary storage code will have been written to the output file.
+ *
+ * PCode:
+ *
+ * History:
+ * 21feb91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_TempStorage( PMAPNODE pmn)
+{
+ INT i=1;
+ PTYPENODE ptn, ptnFirst;
+
+ if( ptnFirst = typ_FindFirstPointer( pmn->pFromNode->ParamList, TRUE)) {
+
+ SML_DIVIDE;
+ printf("; temp storage\n\n");
+
+ printf("\txor\teax,eax\n");
+
+ for( ptn=ptnFirst, i=1; ptn; ptn=typ_FindNextPointer( ptn, TRUE), i++) {
+ printf("\tpush\teax\t\t\t; ptr param #%u %s\n", i,
+ typ_NonNull( ptn->pchIdent));
+ ptn->iTempOffset = (iStackCurrent += DWORD_SIZE);
+ }
+ }
+
+ pmn->pToNode->iPointerCount = pmn->pFromNode->iPointerCount = i-1;
+}
+
+/*******************************************************************************
+ * cod16_PackParams()
+ *
+ * This routine will generate parameter packing code.
+ *
+ * Entry: pmn is a pointer to a MapNode.
+ *
+ * Exit: Parameter packing code will have been written to the output file.
+ *
+ * PCode:
+ *
+ * History:
+ * 21feb91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_PackParams( PMAPNODE pmn)
+{
+ PTYPENODE ptnFrom, ptnTo;
+ INT iBufferSize;
+ BOOL fDirectionFlagClear=FALSE;
+
+ if( ptnFrom = typ_FindFirstPointer( pmn->pFromNode->ParamList, FALSE)) {
+ SML_DIVIDE;
+ printf("; *** BEGIN parameter packing\n\n");
+
+ for( ptnTo = typ_FindFirstPointer( pmn->pToNode->ParamList, FALSE);
+ ptnFrom;
+ ptnFrom = typ_FindNextPointer( ptnFrom, FALSE),
+ ptnTo = typ_FindNextPointer( ptnTo, FALSE)) {
+
+ if( ptnFrom->fSemantics & SEMANTIC_SPECIAL) {
+ if( cod16_PackParamSpecial( pmn, ptnFrom, ptnTo))
+ continue;
+ }
+
+ if( (ptnTo->fSemantics & SEMANTIC_MAPTORETVAL) ||
+ (!typ_TypeIdentical( ptnFrom, ptnTo) &&
+ (ptnFrom->iBaseType == TYPE_STRUCT)
+ )) {
+
+ /*
+ * We only need to cld when we see the first structure
+ * needing repacking.
+ */
+ if( (ptnFrom->fSemantics & SEMANTIC_INPUT) &&
+ !fDirectionFlagClear &&
+ !(ptnTo->fSemantics & SEMANTIC_MAPTORETVAL)) {
+ fDirectionFlagClear = TRUE;
+ printf("\tcld\t\t\t\t; esi, edi will increment\n\n");
+ }
+
+ iBufferSize = ROUND_UP_MOD( ptnTo->iBaseDataSize, DWORD_SIZE);
+ printf("\tsub\tesp,%u\t\t\t; %s alloc space on stack\n\n",
+ iBufferSize, typ_NonNull( ptnTo->pchIdent));
+ iStackCurrent += iBufferSize;
+ }
+ if( ptnTo->fSemantics & SEMANTIC_MAPTORETVAL) {
+ ptnTo->iTempOffset = iStackCurrent;
+ } else {
+ cod16_PackPointer( ptnFrom, ptnTo);
+ }
+ }
+
+ printf("; *** END parameter packing\n");
+ }
+}
+
+/*******************************************************************************
+ * cod16_PackPointer()
+ *
+ * This routine will generate pointer-handling code.
+ *
+ * Entry: ptnFrom - parameter input to thunk
+ * ptnTo - parameter output from thunk
+ *
+ * Exit: pointer-handling code was emitted
+ *
+ * PCode:
+ *
+ * History:
+ * 22feb91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_PackPointer( PTYPENODE ptnFrom, PTYPENODE ptnTo)
+{
+ UINT uiNullLabel, uiStoreLabel;
+ BOOL fSameType, fEmbeddedPtr, fAddressSaved=FALSE;
+ CHAR *pch;
+ INT iSemanticMask;
+
+ fSameType = typ_TypeIdentical( ptnFrom, ptnTo);
+ fEmbeddedPtr = cod_CountPointerParameters( ptnFrom->pStructElems, FALSE);
+
+ if( strcmp( (pch = typ_NonNull( ptnFrom->pchIdent)), ""))
+ printf("; %s\n", pch);
+ printf("; pointer %s --> %s\n",
+ typ_NonNull( ptnFrom->pchBaseTypeName),
+ typ_NonNull( ptnTo->pchBaseTypeName));
+ printf("\tmov\teax,[ebx+%u]\t\t; base address\n", ptnFrom->iOffset);
+ printf("\tor\teax,eax\n");
+ printf("\tjz\tL%u\t\t\t; skip if null\n\n",
+ uiNullLabel = uiGenLabel++);
+
+ iSemanticMask = SEMANTIC_PASSIFHINULL | SEMANTIC_INPUT;
+ if( (ptnFrom->fSemantics & iSemanticMask) == iSemanticMask) {
+ printf("; special case of polymorphic parameter\n");
+ printf("; do no conversion if the high word is null\n");
+ printf("\trol\teax,16\n");
+ printf("\tor\tax,ax\n");
+ printf("\trol\teax,16\t\t\t; return eax to original state\n");
+ printf("\tjz\tL%u\t\t\t; no change if hi word null\n\n",
+ uiStoreLabel = uiGenLabel++);
+ }
+
+ if( ptnFrom->iBaseType == TYPE_STRUCT) {
+ printf("\n; structures are%s identical\n",
+ fSameType ? "" : " not");
+ printf("; structures %shave pointers\n\n",
+ fEmbeddedPtr ? "" : "don't ");
+
+ if( ptnFrom->iArraySize > 1) {
+ cod_NotHandled( "structure array");
+ } else if( fSameType) {
+ cod16_SelToFlat();
+ } else {
+ printf("\tmov\t[esp+%u],esp\t\t; save pointer to buffer\n\n",
+ iStackCurrent - ptnFrom->iTempOffset);
+ fAddressSaved = TRUE;
+ if( ptnFrom->fSemantics & SEMANTIC_INPUT) {
+ cod16_StructureRepack( ptnFrom, ptnTo);
+ }
+ }
+ } else if( fSameType) {
+ if( ptnFrom->iArraySize == 1) {
+ if( ptnFrom->iBaseType == TYPE_NULLTYPE) {
+ printf( "\t.err *** NULLTYPE ***\n");
+ } else {
+ cod16_SelToFlat();
+ }
+ } else {
+ if( ptnFrom->iBaseType == TYPE_CHAR) {
+ cod16_SelToFlat();
+ } else {
+ cod_NotHandled( "non-char buffer");
+ }
+ }
+ } else {
+ cod_NotHandled( "pointer to different non-structs");
+ }
+
+ if( ptnFrom->fSemantics & SEMANTIC_PASSIFHINULL)
+ printf("L%u:\n", uiStoreLabel);
+
+ if( !fAddressSaved)
+ printf("\tmov\t[esp+%u],eax\n", iStackCurrent - ptnFrom->iTempOffset);
+
+ printf("L%u:\n\n", uiNullLabel);
+}
+
+/*******************************************************************************
+ * cod16_SelToFlat()
+ *
+ * This routine will generate code to convert a 16:16 address to a 0:32 address
+ *
+ * Entry: in emitted code, (eax) == 16:16 address
+ *
+ * Exit: in emitted code, (eax) == 0:32 address
+ *
+ * PCode:
+ *
+ * History:
+ * 26feb91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_SelToFlat( void)
+{
+/* YaronS */
+/*
+ printf("\tcall\tSelToFlat\n");
+*/
+ printf("\tSelToFlat\n");
+}
+
+/*******************************************************************************
+ * cod16_StructureRepack()
+ *
+ * This routine will generate structure repacking code.
+ *
+ * Entry: ptnFrom - parameter input to thunk
+ * ptnTo - parameter output from thunk
+ *
+ * Exit: structure repacking code was emitted
+ *
+ * PCode:
+ *
+ * History:
+ * 22feb91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_StructureRepack( PTYPENODE ptnFrom, PTYPENODE ptnTo)
+{
+ cod16_SelToFlat();
+ printf("\tmov\tesi,eax\t\t\t; source flat address\n");
+ printf("\tmov\tedi,esp\t\t\t; destination flat address\n\n");
+
+ cod16_RepackElems( ptnFrom->pStructElems, ptnTo->pStructElems);
+}
+
+/*******************************************************************************
+ * cod16_RepackElems()
+ *
+ * This routine will generate repacking code for the elems of a structure.
+ *
+ * Entry: ptnFrom - first elem of from struct
+ * ptnTo - first elem of to struct
+ *
+ * Exit: structure repacking code was emitted
+ *
+ * PCode:
+ *
+ * History:
+ * 07mar91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_RepackElems( PTYPENODE ptnFrom, PTYPENODE ptnTo)
+{
+ UINT uiStoreLabel;
+ PTYPENODE ptnElemFrom, ptnElemTo;
+ ULONG fl;
+
+ for( ptnElemFrom = ptnFrom, ptnElemTo = ptnTo;
+ ptnElemFrom;
+ ptnElemFrom = ptnElemFrom->pNextNode,
+ ptnElemTo = ptnElemTo->pNextNode) {
+
+ printf("; %s\n", typ_NonNull( ptnElemFrom->pchIdent));
+
+ if( ptnElemFrom->iPointerType) {
+
+ printf("; pointer %s --> %s\n", ptnElemFrom->pchBaseTypeName,
+ ptnElemTo->pchBaseTypeName);
+
+ if( ptnElemFrom->iPointerType == ptnElemTo->iPointerType) {
+ printf("\tmovsd\t\t\t\t; no conversion\n\n");
+
+ } else if( (ptnElemFrom->iPointerType == TYPE_FAR16) &&
+ (ptnElemTo->iPointerType == TYPE_NEAR32)) {
+
+ printf("\tlodsd\n");
+ printf("\tor\teax,eax\n");
+ printf("\tjz\tL%u\n", uiStoreLabel = uiGenLabel++);
+
+ if( ptnElemFrom->fSemantics & SEMANTIC_PASSIFHINULL) {
+ printf("; no conversion if high word null\n");
+ printf("\trol\teax,16\n");
+ printf("\tor\tax,ax\n");
+ printf("\trol\teax,16\t\t\t; restore eax\n");
+ printf("\tjz\tL%u\n", uiStoreLabel);
+ }
+
+ cod16_SelToFlat();
+ printf("L%u:\n", uiStoreLabel);
+ printf("\tstosd\n\n");
+
+ } else {
+ cod_NotHandled( "cod16_RepackElems: unequal pointer types,"
+ " not 16:16 --> 0:32");
+ }
+ } else if( ptnElemFrom->iArraySize <= 1) {
+ printf("; %s --> %s\n", ptnElemFrom->pchBaseTypeName,
+ ptnElemTo->pchBaseTypeName);
+
+ if( ptnElemFrom->iBaseType == ptnElemTo->iBaseType) {
+ switch( ptnElemFrom->iBaseType) {
+ case TYPE_STRUCT:
+ cod16_RepackElems( ptnElemFrom->pStructElems,
+ ptnElemTo->pStructElems);
+ break;
+
+ case TYPE_LONG:
+ case TYPE_ULONG:
+ printf("\tmovsd\t\t\t\t; no conversion\n\n");
+ break;
+
+ case TYPE_SHORT:
+ case TYPE_USHORT:
+ /* Check for 2 contiguous WORDs mapping to WORDs */
+ if( typ_WordToWord( ptnElemFrom->pNextNode,
+ ptnElemTo->pNextNode)) {
+ ptnElemFrom = ptnElemFrom->pNextNode;
+ ptnElemTo = ptnElemTo->pNextNode;
+ printf("; %s --> %s\n",
+ ptnElemFrom->pchBaseTypeName,
+ ptnElemTo->pchBaseTypeName);
+ printf("\tmovsd\t\t\t\t; 2 words at once\n\n");
+ } else {
+ printf("\tlodsw\n");
+ printf("\tstosd\t\t\t\t; ignore hi word\n\n");
+ }
+ break;
+
+ case TYPE_CHAR:
+ case TYPE_UCHAR:
+ /* BUGBUG does not handle multiple contiguous bytes */
+ if( typ_ByteToByte( ptnElemFrom->pNextNode,
+ ptnElemTo->pNextNode)) {
+ cod_NotHandled( "cod16_RepackElems: contiguous BYTES");
+ } else if( typ_WordToWord( ptnElemFrom->pNextNode,
+ ptnElemTo->pNextNode)) {
+ ptnElemFrom = ptnElemFrom->pNextNode;
+ ptnElemTo = ptnElemTo->pNextNode;
+ printf("; %s --> %s\n",
+ ptnElemFrom->pchBaseTypeName,
+ ptnElemTo->pchBaseTypeName);
+ printf("\tmovsd\t\t\t\t; 1 byte + 1 word at once\n\n");
+ } else {
+ printf("\tlodsb\n");
+ printf("\tstosd\t\t\t\t; ignore hi 3 bytes\n\n");
+ }
+ break;
+
+ default:
+ cod_NotHandled( "structure repack, not word or dword");
+ fatal( "cod16_RepackElems: unexpected base type %s\n",
+ ptnElemFrom->pchBaseTypeName);
+ break;
+ }
+ } else {
+ switch( ptnElemFrom->iBaseType) {
+ case TYPE_SHORT: /* SHORT --> LONG */
+ printf("\tlodsw\n");
+ printf("\tcwde\n");
+ printf("\tstosd\n\n");
+ break;
+
+ case TYPE_USHORT: /* USHORT --> ULONG */
+ if( fl = ptnElemFrom->flHandleType) {
+ printf("\tlodsw\n");
+ printf("\tcall\tGetHandle32\t\t; %s\n",
+ typ_GetHandleTypeName( fl));
+ printf("\tstosd\n\n");
+ } else {
+ printf("\txor\teax,eax\n");
+ printf("\tlodsw\n");
+ printf("\tstosd\n\n");
+ }
+ break;
+
+ case TYPE_LONG: /* LONG --> SHORT */
+ case TYPE_ULONG: /* ULONG --> USHORT */
+ printf("\tlodsd\n");
+ printf("\tstosw\n\n");
+ break;
+
+ default:
+ cod_NotHandled( "structure repack, not (U)SHORT or (U)LONG");
+ fatal( "cod16_RepackElems: unexpected base type %s\n",
+ ptnElemFrom->pchBaseTypeName);
+ break;
+ }
+ }
+ } else {
+ printf("; %s[%u] --> %s[%u]\n",
+ ptnElemFrom->pchBaseTypeName, ptnElemFrom->iArraySize,
+ ptnElemTo->pchBaseTypeName, ptnElemTo->iArraySize);
+
+ if( ptnElemFrom->iArraySize != ptnElemTo->iArraySize) {
+ cod_NotHandled( "FromArraySize != ToArraySize");
+ break;
+ }
+
+ if( ptnElemFrom->iBaseType == ptnElemTo->iBaseType) {
+ switch( ptnElemFrom->iBaseType) {
+ case TYPE_CHAR:
+ case TYPE_UCHAR:
+ cod16_CopyFixedBlock( ptnElemFrom->iArraySize);
+ break;
+
+ default:
+ cod_NotHandled( "non-BYTE array in struct");
+ break;
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ * cod16_CopyFixedBlock()
+ *
+ * This routine will generate code to copy a fixed-sized block.
+ *
+ * Entry: uiSize = the number of bytes to copy.
+ * esi = source address
+ * edi = destination address
+ *
+ * Exit: Copy code will have been written to the output file.
+ *
+ * PCode:
+ *
+ * History:
+ * 07mar91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_CopyFixedBlock( UINT uiSize)
+{
+ UINT uiBytesLeft=uiSize;
+
+ if( uiSize < 3*DWORD_SIZE) {
+ for( ; uiBytesLeft >= DWORD_SIZE; uiBytesLeft -= DWORD_SIZE)
+ printf("\tmovsd\n");
+ } else {
+ printf("\tmov\tecx,%u\n", uiSize / DWORD_SIZE);
+ printf("\trep\tmovsd\n");
+ uiBytesLeft %= DWORD_SIZE;
+ }
+
+ for( ; uiBytesLeft >= WORD_SIZE; uiBytesLeft -= WORD_SIZE)
+ printf("\tmovsw\n");
+
+ for( ; uiBytesLeft >= BYTE_SIZE; uiBytesLeft -= BYTE_SIZE)
+ printf("\tmovsb\n");
+
+ printf("\n");
+}
+
+/*******************************************************************************
+ * cod16_CallFrameWorker()
+ *
+ * This worker routine is invented to reverse the parameter order for, to
+ * match NT calling convention. It is recursive, and called only from
+ * cod16_CallFrame.
+ *
+ * Entry: ptnFrom ,ptnTo, &fDirectionFlagClear, pmn
+ * (see cod16_CallFrame for desciption)
+ *
+ *
+ * Exit: none
+ *
+ * PCode:
+ * if ptnFrom == NULL
+ * process parameter (eventually printf "push ...")
+ * else
+ * call cod16_CallFrameWorker with next couple on the chain.
+ *
+ * History:
+ * 01may91 YaronS wrote it
+ *
+ ******************************************************************************/
+
+void cod16_CallFrameWorker(
+ PTYPENODE ptnFrom,
+ PTYPENODE ptnTo,
+ BOOL *pfDirectionFlagClear,
+ PMAPNODE pmn
+ )
+{
+ CHAR *pch;
+ ULONG fl;
+ INT iBufferSize;
+
+
+ //
+ // call recursive only if we are not the last
+ //
+
+ if (ptnFrom->pNextNode){
+ cod16_CallFrameWorker (
+ ptnFrom->pNextNode,
+ ptnTo->pNextNode,
+ pfDirectionFlagClear,
+ pmn);
+ }
+
+ //
+ // Now all links ahead were already processed,
+ // Go do the work for this parameter
+ //
+
+ if( ptnFrom->fSemantics & SEMANTIC_SPECIAL) {
+ if( cod16_PushParamSpecial( pmn, ptnFrom, ptnTo))
+ return;
+ }
+
+ if( ptnFrom->iDeleted) {
+ if( strcmp( (pch = typ_NonNull( ptnFrom->pchIdent)), ""))
+ printf("; %s\n", pch);
+ if( ptnTo->fSemantics & SEMANTIC_MAPTORETVAL) {
+
+ printf("\tlea\teax,[esp+%u]\n",
+ iStackCurrent - ptnTo->iTempOffset);
+ printf("\tpush\teax\t\t\t; output %s\n\n",
+ ptnTo->pchBaseTypeName);
+ iStackCurrent += DWORD_SIZE;
+ fPackedPointReturned = TRUE;
+ if( ptnTo->fSemantics & SEMANTIC_REVERSERC) {
+ iYRCTempOffset = ptnTo->iTempOffset;
+ iXRCTempOffset = ptnTo->iTempOffset - DWORD_SIZE;
+ } else {
+ iYRCTempOffset = ptnTo->iTempOffset - DWORD_SIZE;
+ iXRCTempOffset = ptnTo->iTempOffset;
+ }
+
+ } else if( ptnTo->iBaseDataSize == DWORD_SIZE) {
+ printf("\tpush\tdword ptr 0%lxh\t; extra parameter\n\n",
+ ptnFrom->iFillValue);
+ iStackCurrent += DWORD_SIZE;
+ } else {
+ printf("\tpush\tword ptr 0%xh\t\t; extra parameter\n\n",
+ ptnFrom->iFillValue);
+ iStackCurrent += WORD_SIZE;
+ }
+ return;
+ }
+
+ if( ptnTo->iDeleted)
+ return;
+ if( strcmp( (pch = typ_NonNull( ptnFrom->pchIdent)), ""))
+ printf("; %s from: %s\n",
+ pch, typ_NonNull( ptnFrom->pchBaseTypeName));
+ else
+ printf("; from: %s\n", typ_NonNull( ptnFrom->pchBaseTypeName));
+
+ switch( ptnFrom->iPointerType) {
+ case TYPE_NEAR32:
+ case TYPE_FAR16:
+
+ printf("\tpush\tdword ptr [esp+%u]\t; to: %s\n\n",
+ iStackCurrent - ptnFrom->iTempOffset,
+ typ_NonNull( ptnTo->pchBaseTypeName));
+ iStackCurrent += DWORD_SIZE;
+ break;
+
+ case 0:
+ if( ptnFrom->iBaseType == TYPE_STRUCT) {
+ /*
+ * The struct is on the stack. Repack it on the fly.
+ * We only need to cld when we see the first structure
+ * needing repacking.
+ */
+ if( !*pfDirectionFlagClear) {
+ *pfDirectionFlagClear = TRUE;
+ printf("\tcld\t\t\t\t; esi, edi will increment\n\n");
+ }
+ iBufferSize = ROUND_UP_MOD( ptnTo->iBaseDataSize, DWORD_SIZE);
+ printf("\tsub\tesp,%u\n", iBufferSize);
+ iStackCurrent += iBufferSize;
+
+ printf("\tlea\tesi,[ebx+%u]\t\t; source flat address\n",
+ ptnFrom->iOffset);
+ printf("\tmov\tedi,esp\t\t\t; destination flat address\n\n");
+
+ cod16_RepackElems( ptnFrom->pStructElems, ptnTo->pStructElems);
+
+ } else if( ptnFrom->iBaseType == ptnTo->iBaseType) {
+ printf("\tpush\t%s ptr [ebx+%u]\t; to %s\n\n",
+ ptnFrom->iBaseDataSize <= WORD_SIZE ? "word" : "dword",
+ ptnFrom->iOffset,
+ typ_NonNull( ptnTo->pchBaseTypeName));
+ iStackCurrent += ptnFrom->iBaseDataSize <= WORD_SIZE ?
+ WORD_SIZE : DWORD_SIZE;
+ } else {
+ if( fl = ptnFrom->flHandleType) {
+ printf("\tmov\teax,[ebx+%u]\n", ptnFrom->iOffset);
+ printf("\tcall\tGetHandle32\t\t; %s\n",
+ typ_GetHandleTypeName( fl));
+ } else if (ptnFrom->iBaseType == TYPE_UCHAR) {
+ printf("\tmovzx\teax,byte ptr [ebx+%u]\n", ptnFrom->iOffset);
+ } else {
+ printf("\t%s\teax,word ptr [ebx+%u]\n",
+ ptnFrom->iBaseType == TYPE_SHORT ? "movsx" : "movzx",
+ ptnFrom->iOffset);
+ }
+ printf("\tpush\teax\t\t\t; to: %s\n\n",
+ typ_NonNull( ptnTo->pchBaseTypeName));
+ iStackCurrent += DWORD_SIZE;
+ }
+ break;
+
+ default:
+ fatal( "unknown pointer type %u in mapping %s=>%s",
+ ptnFrom->iPointerType,
+ pmn->pFromNode->pchFunctionName,
+ pmn->pToNode->pchFunctionName);
+ }
+}
+/*******************************************************************************
+ * cod16_CallFrame()
+ *
+ * This routine will generate call frame code.
+ *
+ * Entry: pmn is a pointer to a MapNode.
+ *
+ * Exit: Call frame code will have been written to the output file.
+ *
+ * PCode:
+ *
+ * History:
+ * 21feb91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_CallFrame( PMAPNODE pmn)
+{
+ PTYPENODE ptnFrom, ptnTo;
+ CHAR *pch;
+ ULONG fl;
+ INT iBufferSize;
+ BOOL fDirectionFlagClear=FALSE;
+ USHORT icStackFrame;
+
+ SML_DIVIDE;
+ printf("; create new call frame and make the call\n\n");
+
+ fPackedPointReturned = FALSE;
+
+/*
+ * Instead of looping (commented, we call a recursive function,
+ * since we need the parameters printed in reverse
+ *
+ * for( ptnFrom = pmn->pFromNode->ParamList, ptnTo = pmn->pToNode->ParamList;
+ * ptnFrom;
+ * ptnFrom = ptnFrom->pNextNode, ptnTo = ptnTo->pNextNode) {
+ */
+ ptnFrom = pmn->pFromNode->ParamList;
+ ptnTo = pmn->pToNode->ParamList;
+ if (ptnFrom)
+
+ //
+ // here is where all will be done
+ //
+
+ cod16_CallFrameWorker(ptnFrom, ptnTo, &fDirectionFlagClear, pmn);
+
+ if( fBPCall)
+ printf("\tint\t3\n");
+ icStackFrame = cod_CountParameterBytes( pmn->pToNode->ParamList,
+ DWORD_SIZE);
+ printf("\tcall\t%s@%u\t\t; call 32-bit version\n\n",
+ pmn->pToNode->pchFunctionName, icStackFrame);
+ iStackCurrent -= icStackFrame;
+ if( fBPExit)
+ printf("\tint\t3\n\n");
+}
+
+/*******************************************************************************
+ * cod16_Return()
+ *
+ * This routine will generate return code handling code.
+ *
+ * Entry: pmn is a pointer to a MapNode.
+ *
+ * Exit: code was emitted
+ *
+ * PCode:
+ *
+ * History:
+ * 20mar91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_Return( PMAPNODE pmn)
+{
+ fSaveEAX = fSaveEDX = FALSE;
+
+ if( pmn->pFromNode->ReturnType->fSemantics & SEMANTIC_SPECIAL) {
+ if( cod16_ReturnSpecial( pmn))
+ return;
+ }
+
+ if( fPackedPointReturned) {
+ printf("; pack point into return code, ignoring 32-bit rc\n");
+ printf("\tmov\tedx,[esp+%u]\n",iStackCurrent - iYRCTempOffset);
+ printf("\tmov\teax,[esp+%u]\n\n",iStackCurrent - iXRCTempOffset);
+ fSaveEAX = TRUE;
+ fSaveEDX = TRUE;
+
+ } else if( pmn->pFromNode->ReturnType->flHandleType) {
+ printf("\tcall\tGetHandle16\t\t; convert handle\n\n");
+ fSaveEAX = TRUE;
+
+ } else if( pmn->pFromNode->ReturnType->iPointerType) {
+ cod_NotHandled( "cod16_Return: pointer return code");
+
+ } else if( typ_TypeIdentical( pmn->pFromNode->ReturnType,
+ pmn->pToNode->ReturnType)) {
+ printf("; return code %s --> %s\n",
+ pmn->pToNode->ReturnType->pchBaseTypeName,
+ pmn->pFromNode->ReturnType->pchBaseTypeName);
+
+ switch( pmn->pFromNode->ReturnType->iBaseType) {
+ case TYPE_LONG:
+ case TYPE_ULONG:
+ printf("\tmov\tedx,eax\n");
+ printf("\trol\tedx,16\n\n");
+ fSaveEAX = TRUE;
+ fSaveEDX = TRUE;
+ break;
+
+ case TYPE_SHORT:
+ case TYPE_USHORT:
+ fSaveEAX = TRUE;
+ printf("; no conversion needed\n\n");
+ break;
+
+ case TYPE_VOID:
+ printf("; no conversion needed\n\n");
+ break;
+
+ default:
+ cod_NotHandled( "cod16_Return: unknown same base type");
+ }
+ } else {
+ printf("; return code %s --> %s\n",
+ pmn->pToNode->ReturnType->pchBaseTypeName,
+ pmn->pFromNode->ReturnType->pchBaseTypeName);
+
+ switch( pmn->pFromNode->ReturnType->iBaseType) {
+ case TYPE_SHORT: /* LONG --> SHORT */
+ case TYPE_USHORT: /* ULONG --> USHORT */
+ /* BUGBUG no check for truncation */
+ printf("; no conversion needed\n\n");
+ fSaveEAX = TRUE;
+ break;
+
+ default:
+ cod_NotHandled( "cod16_Return: unknown different base type");
+ }
+ }
+}
+
+/*******************************************************************************
+ * cod16_UnpackParams()
+ *
+ * This routine will generate parameter unpacking code.
+ *
+ * Entry: pmn is a pointer to a MapNode.
+ *
+ * Exit: Parameter unpacking code will have been written to the output file.
+ *
+ * PCode:
+ *
+ * History:
+ * 21feb91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_UnpackParams( PMAPNODE pmn)
+{
+ PTYPENODE ptnFrom, ptnTo;
+ BOOL fDirectionFlagClear=FALSE;
+
+ if( typ_QuerySemanticsUsed( pmn, SEMANTIC_OUTPUT) ||
+ typ_QuerySemanticsUsed( pmn, SEMANTIC_SPECIAL)) {
+ SML_DIVIDE;
+ printf("; *** BEGIN parameter unpacking\n\n");
+
+ if( fSaveEAX){
+ printf("\tpush\teax\t\t\t; save return code\n");
+// YaronS fix bug, not counting for the above push
+ iStackCurrent+=4; // count for this push!
+ }
+ if( fSaveEDX){
+ printf("\tpush\tedx\t\t\t; save return code\n");
+// YaronS fix bug, not counting for the above push
+ iStackCurrent+=4; // count for this push!
+ }
+ if( fSaveEAX || fSaveEDX)
+ printf("\n");
+
+ for( ptnFrom = typ_FindFirstPointer( pmn->pFromNode->ParamList, TRUE),
+ ptnTo = typ_FindFirstPointer( pmn->pToNode->ParamList, TRUE);
+ ptnFrom;
+ ptnFrom = typ_FindNextPointer( ptnFrom, TRUE),
+ ptnTo = typ_FindNextPointer( ptnTo, TRUE)) {
+
+ if( ptnFrom->fSemantics & SEMANTIC_SPECIAL) {
+ if( cod16_UnpackParamSpecial( pmn, ptnFrom, ptnTo))
+ continue;
+ }
+
+ if( ptnFrom->fSemantics & SEMANTIC_OUTPUT) {
+
+ if( !typ_TypeIdentical( ptnFrom, ptnTo) &&
+ (ptnFrom->iBaseType == TYPE_STRUCT) &&
+ !fDirectionFlagClear) {
+ fDirectionFlagClear = TRUE;
+ printf("\tcld\t\t\t\t; esi, edi will increment\n\n");
+ }
+
+ cod16_UnpackPointer( ptnFrom, ptnTo);
+ }
+ }
+
+ if( fSaveEDX)
+ printf("\tpop\tedx\t\t\t; restore return code\n");
+ if( fSaveEAX)
+ printf("\tpop\teax\t\t\t; restore return code\n");
+ if( fSaveEAX || fSaveEDX)
+ printf("\n");
+
+ printf("; *** END parameter packing\n");
+ }
+}
+
+/*******************************************************************************
+ * cod16_UnpackPointer()
+ *
+ * This routine will generate pointer-unpacking code.
+ *
+ * Entry: ptnFrom - parameter output from thunk
+ * ptnTo - parameter input to thunk
+ *
+ * Exit: pointer-unpacking code was emitted
+ *
+ * PCode:
+ *
+ * History:
+ * 07mar91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_UnpackPointer( PTYPENODE ptnFrom, PTYPENODE ptnTo)
+{
+ UINT uiNullLabel;
+ BOOL fSameType, fEmbeddedPtr;
+ CHAR *pch;
+
+ fSameType = typ_TypeIdentical( ptnFrom, ptnTo);
+ fEmbeddedPtr = cod_CountPointerParameters( ptnFrom->pStructElems, FALSE);
+
+ if( strcmp( (pch = typ_NonNull( ptnFrom->pchIdent)), ""))
+ printf("; %s\n", pch);
+ printf("; pointer %s --> %s\n",
+ typ_NonNull( ptnTo->pchBaseTypeName),
+ typ_NonNull( ptnFrom->pchBaseTypeName));
+ printf("\tmov\teax,[ebx+%u]\t\t; base address\n", ptnFrom->iOffset);
+ printf("\tor\teax,eax\n");
+ printf("\tjz\tL%u\t\t\t; skip if null\n\n", uiNullLabel = uiGenLabel++);
+
+ if( ptnFrom->iBaseType == TYPE_STRUCT) {
+ printf("\n; structures are%s identical\n",
+ fSameType ? "" : " not");
+ printf("; structures %shave pointers\n\n",
+ fEmbeddedPtr ? "" : "don't ");
+
+ if( ptnFrom->pSizeParam && (!fSameType)) {
+ cod_NotHandled( "structure buffer");
+ } else if( !fSameType) {
+ cod16_StructureUnpack( ptnFrom, ptnTo);
+ }
+ } else if( !fSameType) {
+ cod_NotHandled( "output pointer to different non-structs");
+ }
+
+ printf("L%u:\n\n", uiNullLabel);
+}
+
+/*******************************************************************************
+ * cod16_StructureUnpack()
+ *
+ * This routine will generate structure unpacking code.
+ *
+ * Entry: ptnFrom - parameter output from thunk
+ * ptnTo - parameter input to thunk
+ *
+ * Exit: structure unpacking code was emitted
+ *
+ * PCode:
+ *
+ * History:
+ * 22feb91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_StructureUnpack( PTYPENODE ptnFrom, PTYPENODE ptnTo)
+{
+ UINT uiStoreLabel;
+ INT iBufferSize;
+ ULONG fl;
+
+ cod16_SelToFlat();
+ printf("\tmov\tedi,eax\t\t\t; destination flat address\n");
+ printf("\tmov\tesi,[esp+%u]\t\t; source flat address\n\n",
+ iStackCurrent - ptnFrom->iTempOffset);
+
+ cod16_RepackElems( ptnTo->pStructElems, ptnFrom->pStructElems);
+}
+
+/*******************************************************************************
+ * cod16_Exit()
+ *
+ * This routine will generate the exit code for one thunk.
+ *
+ * Entry: pmn is a pointer to a MapNode.
+ *
+ * Exit: Exit code will have been written to the output file.
+ *
+ * PCode:
+ *
+ * History:
+ * 21feb91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_Exit( PMAPNODE pmn, BOOL fUseDI, BOOL fUseSI)
+{
+ SML_DIVIDE;
+
+ printf("\tjmp\tExitFlat_%u\n\n",
+ cod_CountParameterBytes( pmn->pFromNode->ParamList, WORD_SIZE));
+}
+
+/*******************************************************************************
+ * cod16_GenRet16()
+ *
+ * This routine will generate the code to restore the stack & registers and ret
+ *
+ * Entry: uiParameterBytes is the number of paramater bytes to clear
+ *
+ * Exit: Exit code will have been written to the output file.
+ *
+ * PCode:
+ *
+ * History:
+ * 16mar91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_GenRet16( UINT uiParameterBytes, BOOL fUseDI, BOOL fUseSI)
+{
+ if( fUser) {
+ printf("\txchg\teax,esi\t\t\t; save return code\n");
+ printf("\tpush\t[ebx-4]\t\t\t; old SS16\n");
+ printf("\tcall\tSetSS16\n");
+ printf("\txchg\teax,esi\t\t\t; restore return code\n\n");
+ }
+
+ printf("\tlss\tsp,[ebx]\t\t; restore 16-bit ss:sp\n\n");
+
+ printf("\tpop\tbp\n");
+ printf("\tpop\tdx\n");
+ printf("\tpop\tbx\n");
+ printf("\tpop\tcx\n");
+ if( fUseSI)
+ printf("\tpop\tsi\n");
+ if( fUseDI)
+ printf("\tpop\tdi\n");
+
+ printf(";\n; Performance HIT BUGBUG \n;\n");
+ printf("\tpush\teax\n");
+ printf("\tmov\teax,ecx\n");
+ printf("\tshr\teax,16\t\t; ES\n");
+ printf("\tverr\tax\t\t; see if the value is still valid!\n");
+ printf("\tjnz\tFixES_%u\n", uiParameterBytes);
+ printf("\tmov\tes,ax\n");
+ printf("\tjmp\tESFixed_%u\n", uiParameterBytes);
+
+ printf("FixES_%u:\n", uiParameterBytes);
+ printf("\txor\tax,ax\n");
+ printf("\tmov\tes,ax\n");
+
+ printf("ESFixed_%u:\n", uiParameterBytes);
+
+ printf("\tmov\teax,edx\n");
+ printf("\tshr\teax,16\t\t; DS\n");
+ printf("\tverr\tax\t\t; see if the value is still valid!\n");
+ printf("\tjnz\tFixDS_%u\n", uiParameterBytes);
+ printf("\tmov\tds,ax\n");
+ printf("\tjmp\tDSFixed_%u\n", uiParameterBytes);
+
+ printf("FixDS_%u:\n", uiParameterBytes);
+ printf("\txor\tax,ax\n");
+ printf("\tmov\tds,ax\n");
+
+
+ printf("DSFixed_%u:\n", uiParameterBytes);
+
+ printf(";\n;Now restore ax & di, and clean the stack\n");
+ printf("\tpop\teax\n");
+ printf("\tadd\tsp,4\t; es/ds are 2 byte each on the stack\n");
+
+ printf("\tdb\t66h, 0cah\t\t; 16-bit retf\n");
+ printf("\tdw\t%u\t\t\t; 16-bit parameters\n\n", uiParameterBytes);
+}
diff --git a/private/os2/client/thunk/thunkcom/cod1632b.c b/private/os2/client/thunk/thunkcom/cod1632b.c
new file mode 100644
index 000000000..1ebceb97e
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/cod1632b.c
@@ -0,0 +1,245 @@
+/*
+ * Thunk Compiler - Special Routines for Code Generator (16=>32).
+ *
+ * This is a Win32 specific file
+ * Microsoft Confidential
+ *
+ * Copyright (c) Microsoft Corporation 1991
+ *
+ * All Rights Reserved
+ *
+ * 03.19.91 KevinR wrote it
+ *
+ */
+
+
+#include <stdio.h>
+#include "error.h"
+#include "thunk.h"
+#include "types.h"
+#include "symtab.h"
+#include "codegen.h"
+#include "globals.h"
+#include "cod1632b.h"
+
+extern FILE *StdDbg;
+
+/*
+ * LATER: The search routines in this module all use a linear search,
+ * because it is quick to implement. A slower-growth algorithm
+ * should be used if performance becomes a problem.
+ *
+ */
+
+
+
+/*******************************************************************************
+ * cod16_PackParamSpecial( pmn, ptnFrom, ptnTo)
+ *
+ * This routine generates special parameter packing code.
+ *
+ * Entry:
+ *
+ * Exit: code was emitted
+ *
+ * PCode:
+ *
+ * History:
+ * 19Mar91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+BOOL cod16_PackParamSpecial( PMAPNODE pmn, PTYPENODE ptnFrom, PTYPENODE ptnTo)
+{
+ UINT uiNullLabel, uiLoopLabel;
+ PSZ pszFunc=pmn->pFromName, pszParam=ptnFrom->pchIdent;
+
+ if( !pszParam) {
+ fatal( "cod16_PackParamSpecial: %s has null special param name",
+ pszFunc);
+ return TRUE;
+ }
+
+ if( !stricmp( pszFunc, "SetSysColors16")) {
+ if( !stricmp( pszParam, "lpSysColor")) {
+ printf("; %s\n", pszParam);
+ printf("\tmov\teax,[ebx+%u]\t\t; base address\n", ptnFrom->iOffset);
+ printf("\tor\teax,eax\n");
+ printf("\tjz\tL%u\t\t\t; skip if null\n\n",
+ uiNullLabel = uiGenLabel++);
+
+ cod16_SelToFlat();
+ printf("\tmov\tesi,eax\n\n");
+
+ printf("\tmovsx\tecx,word ptr [ebx+%u]\t; %s == size\n",
+ ptnFrom->pSizeParam->iOffset,
+ ptnFrom->pSizeParam->pchIdent);
+ printf("\tor\tecx,ecx\n");
+ printf("\tjs\tL%u\t\t\t; skip if count negative\n\n", uiNullLabel);
+
+ cod16_AllocBlock( 0, DWORD_SIZE);
+ printf("\tmov\tedi,eax\n");
+ printf("\tmov\t[esp+%u],eax\n",
+ iStackCurrent - ptnFrom->iTempOffset);
+
+ printf("L%u:\n", uiLoopLabel = uiGenLabel++);
+ printf("\tjecxz\tL%u\n", uiNullLabel);
+ printf("\tdec\tecx\n\n");
+
+ printf("\tlodsw\n");
+ printf("\tcwde\n");
+ printf("\tstosd\n\n");
+
+ printf("\tjmp\tL%u\n", uiLoopLabel);
+ printf("L%u:\n\n", uiNullLabel);
+
+ } else {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*******************************************************************************
+ * cod16_PushParamSpecial( pmn, ptnFrom, ptnTo)
+ *
+ * This routine generates special call frame code.
+ *
+ * Entry:
+ *
+ * Exit: code was emitted
+ *
+ * PCode:
+ *
+ * History:
+ * 19Mar91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+BOOL cod16_PushParamSpecial( PMAPNODE pmn, PTYPENODE ptnFrom, PTYPENODE ptnTo)
+{
+ PSZ pszFunc=pmn->pFromName, pszParam=ptnFrom->pchIdent;
+
+ if( !pszParam) {
+ fatal( "cod16_PushParamSpecial: %s has null special param name",
+ pszFunc);
+ return TRUE;
+ }
+
+ if( !stricmp( pszFunc, "foo")) {
+ if( !stricmp( pszParam, "foo")) {
+
+ } else {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*******************************************************************************
+ * cod16_ReturnSpecial( pmn)
+ *
+ * This routine generates special return code handling code.
+ *
+ * Entry:
+ *
+ * Exit: code was emitted
+ *
+ * PCode:
+ *
+ * History:
+ * 20Mar91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+BOOL cod16_ReturnSpecial( PMAPNODE pmn)
+{
+ PSZ pszFunc=pmn->pFromName;
+
+ if( !pszFunc) {
+ fatal( "cod16_ReturnSpecial: null function name");
+ return TRUE;
+ }
+
+ if( !stricmp( pszFunc, "foo")) {
+ } else {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*******************************************************************************
+ * cod16_UnpackParamSpecial( pmn, ptnFrom, ptnTo)
+ *
+ * This routine generates special parameter unpacking code.
+ *
+ * Entry:
+ *
+ * Exit: code was emitted
+ *
+ * PCode:
+ *
+ * History:
+ * 19Mar91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+BOOL cod16_UnpackParamSpecial( PMAPNODE pmn, PTYPENODE ptnFrom, PTYPENODE ptnTo)
+{
+ PSZ pszFunc=pmn->pFromName, pszParam=ptnFrom->pchIdent;
+
+ if( !pszParam) {
+ fatal( "cod16_UnpackParamSpecial: %s has null special param name",
+ pszFunc);
+ return TRUE;
+ }
+
+ if( !stricmp( pszFunc, "SetSysColors16")) {
+ if( !stricmp( pszParam, "lpSysColor")) {
+ printf("; %s\n", pszParam);
+ printf("\tpush\tdword ptr [esp+%u]\n",
+ iStackCurrent - ptnFrom->iTempOffset);
+ printf("\tcall\tLocalFree\n\n");
+
+ } else {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*******************************************************************************
+ * cod16_AllocBlock( flFlags, ulUnitSize)
+ *
+ * This routine generates block allocation code.
+ *
+ * Entry: ecx = count of <ulUnitSize>
+ *
+ * Exit: code was emitted
+ *
+ * PCode:
+ *
+ * History:
+ * 20Mar91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+void cod16_AllocBlock( ULONG flFlags, ULONG ulUnitSize)
+{
+ if( flFlags) {
+ printf("\tmov\teax,%u\n", flFlags);
+ } else {
+ printf("\txor\teax,eax\t\t\t; alloc fixed\n");
+ }
+
+ printf("\tpush\teax\n");
+ printf("\tlea\teax,[ecx*%u]\n", ulUnitSize);
+ printf("\tpush\teax\n");
+ printf("\tcall\tLocalAlloc\n");
+}
diff --git a/private/os2/client/thunk/thunkcom/cod1632b.h b/private/os2/client/thunk/thunkcom/cod1632b.h
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/cod1632b.h
@@ -0,0 +1 @@
+
diff --git a/private/os2/client/thunk/thunkcom/cod3216.c b/private/os2/client/thunk/thunkcom/cod3216.c
new file mode 100644
index 000000000..cebea98f8
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/cod3216.c
@@ -0,0 +1,2563 @@
+/*
+ * Thunk Compiler - Routines for Code Generator (32->16).
+ *
+ * This is a Win32 specific file
+ * Microsoft Confidential
+ *
+ * Copyright (c) Microsoft Corporation 1987, 1988, 1989, 1990
+ *
+ * All Rights Reserved
+ *
+ * Created 11/28/88 by Julie Bennett
+ * Revised 12/03/88 by Kevin Ross
+ * Adapted to Win32 by Kevin Ruddell 10/30/90
+ */
+
+
+#include <stdio.h>
+#include "error.h"
+#include "thunk.h"
+#include "types.h"
+#include "symtab.h"
+#include "codegen.h"
+#include "cod3216.h"
+
+
+extern BOOL fMapTo16Used;
+extern BOOL fGDIAllocUsed;
+extern BOOL fLocalHeapUsed;
+
+unsigned int gEDI, gESI;
+unsigned int gTransferBytes = 0;
+CHAR *pszGDISemName = "GDISERIAL";
+
+FunctionNode *pGlobal_To, *pGlobal_From;
+
+int fReAlignmentNeeded = 0;
+int fCombined = 0,iCombinedOffset=0;
+
+extern void cod_Entry32(MapNode *);
+extern void cod32_HandleStructureBuffer(TypeNode *,TypeNode *);
+extern void cod32_StructureRepack(TypeNode *,TypeNode *);
+extern void cod32_HandleBoundaryCross(unsigned int,TypeNode *,unsigned int);
+extern void cod32_HandleFixedSize(unsigned int,TypeNode *);
+extern void cod32_CopyConvert(TypeNode *,TypeNode *);
+extern void cod32_TransferBlock(int);
+
+
+/*** cod_Handle3216()
+ *
+ * This routine will generate a thunk FROM a 0:32 routine to a 16:16
+ * routine.
+ *
+ * Entry: pMNode is a pointer to a MapNode.
+ *
+ * Exit: The thunk will have been written to the output file.
+ *
+ * PCode: Traverse Parameter lists of both functions
+ * - Determine stack offsets of each parameter
+ * - Determine offsets for each structure field
+ * - Generate the thunk assembly code
+ *
+ * History:
+ * 29-Nov-1988 JulieB Changed parms. Added code gen routines.
+ */
+
+void
+cod_Handle3216(MapNode *pMNode)
+
+{
+ pGlobal_To = TONODE(pMNode);
+ pGlobal_From = FRNODE(pMNode);
+
+ fCombined = pMNode->pFamily != NULL;
+
+ cod_Entry32(pMNode);
+
+ if (FRNODE(pMNode)->iPointerCount > 32)
+ {
+ printf(".err Mapping %s => %s not generated\n",
+ FRNODE(pMNode)->pchFunctionName,
+ TONODE(pMNode)->pchFunctionName);
+
+ fprintf(stderr, "Mapping %s => %s not generated\n",
+ FRNODE(pMNode)->pchFunctionName,
+ TONODE(pMNode)->pchFunctionName);
+ return;
+ }
+
+ cod_CalcOffset(FRNODE(pMNode)->ParamList, 2 * DWORD_SIZE, DWORD_SIZE,
+ PUSH_LEFT);
+ cod_CalcOffset(TONODE(pMNode)->ParamList, 0, // beware: 0 !!!!!!!
+ WORD_SIZE,
+ PUSH_LEFT);
+ cod_CalcTempOffset(FRNODE(pMNode)->ParamList, iStackOverhead);
+ cod_CalcStructOffsets(TONODE(pMNode)->ParamList, WORD_SIZE);
+ cod_CalcStructOffsets(FRNODE(pMNode)->ParamList, iPackingSize);
+
+ /*
+ * Generate the thunk assembly code for the function.
+ */
+ cod_PointerHandler32(pMNode);
+ cod_CallFrame32(pMNode);
+ //cod_UnpackStruct32(pMNode);
+ cod32_UnpackStructGDI(pMNode);
+
+ cod_Return32(pMNode);
+ cod_CallStub32(pMNode);
+
+ /*
+ * Dump the type nodes to the screen - used for debugging.
+ */
+ if (DumpTables)
+ {
+ cod_DumpTypes(FRNODE(pMNode));
+ cod_DumpStructures(FRNODE(pMNode)->ParamList);
+ cod_DumpTypes(TONODE(pMNode));
+ cod_DumpStructures(TONODE(pMNode)->ParamList);
+ }
+}
+
+
+/*** cod_Entry32
+ *
+ * This function prints out the entry assembly code for the 32-bit
+ * routine.
+ *
+ * Entry: pMNode is the pointer to a MapNode.
+ *
+ * Exit: entry code is generated.
+ *
+ * History:
+ * 28-Nov-1988 JulieB Created it.
+ * 26-Dec-1988 KevinRo Saved pointer count in FNode
+ * Added temp storage for return code when
+ * pointers exist.
+ */
+
+void
+cod_Entry32(MapNode *pMNode)
+
+{
+ int iNumPtrs; /* number of pointer parameters */
+ register int i; /* loop counter */
+
+
+ /*
+ * Count the number of pointer parameters in the FromNode.
+ */
+ iNumPtrs = cod_CountPointerParameters(pMNode->pFromNode->ParamList, FALSE);
+ pMNode->pToNode->iPointerCount = pMNode->pFromNode->iPointerCount = iNumPtrs;
+
+ if (iNumPtrs > 32)
+ return ;
+
+ /*
+ * Open a dummy label.
+ */
+ printf("\n;Create a dummy label to trick MASM into correct fixups\n");
+ printf("\n%s\tSEGMENT\n\n",CODE16_NAME);
+ printf("T_%s\tLABEL FAR\n\n", pMNode->pToNode->pchFunctionName);
+ printf("%s\tENDS\n\n",CODE16_NAME);
+
+ printf("\n%s\tSEGMENT\n",CODE32_NAME);
+ printf("\tASSUME CS:FLAT\n");
+ //printf("\tASSUME DS:DGROUP,ES:nothing,SS:DGROUP\n");
+ printf("\tASSUME DS:FLAT,ES:FLAT\n");
+
+ /*
+ * Open procedure.
+ */
+ printf("%s PROC\n\n", pMNode->pFromNode->pchFunctionName);
+
+ if (fCombined) {
+ printf("\txor\teax,eax\n");
+ printf("\nC_%s:\n\n", pMNode->pFromNode->pchFunctionName);
+ }
+
+ if (fBPEntry)
+ printf("\n\n;******* Break Point\n\n\tint\t3\n\n\n");
+
+#if 0
+ printf( "\txor\tedx,edx\t\t\t;attempt to claim semaphore\n");
+ printf( "\tinc\tedx\n");
+ printf( "\txchg\tedx,%s\n", pszGDISemName);
+ printf( "\tor\tedx,edx\n");
+ printf( "\tjnz\tSEMEXIT_%s\n\n", pMNode->pFromNode->pchFunctionName);
+#endif
+
+ printf("\tpush\tebp\n");
+ printf("\tmov\tebp,esp\n\n");
+
+ /*
+ * Allocate temporary storage on stack.
+ */
+ iStackOverhead = 0;
+ iErrorOffset = iStackOverhead;
+
+ if (fCombined) {
+ printf("\tpush\teax\t\t;Save call number\n\n");
+ iStackOverhead += DWORD_SIZE;
+ iCombinedOffset = iStackOverhead;
+ }
+
+ if (iNumPtrs)
+ {
+ printf("\n\tcld\t\t\t;Assume direction flag clear\n");
+ printf("\txor\teax,eax\n");
+
+ iStackOverhead += DWORD_SIZE;
+ printf("\tpush\teax\t\t; temp storage for return value\n");
+ iReturnValOffset = iStackOverhead;
+
+ iStackOverhead += DWORD_SIZE;
+ printf("\tpush\tesi\n");
+
+ iStackOverhead += DWORD_SIZE;
+ printf("\tpush\tedi\n");
+
+ iSavedRegOffset = iStackOverhead;
+
+ iStackOverhead += DWORD_SIZE;
+ printf("\tpush\teax\t\t; temp storage \n");
+ iTempStoreOffset = iStackOverhead;
+
+ iStackOverhead += DWORD_SIZE;
+ printf("\tpush\teax\t\t; pointer thunk id\n");
+ iPtrThunkIDOffset = iStackOverhead;
+
+ //iStackOverhead += DWORD_SIZE;
+ //printf("\tpush\teax\t\t;Error flag for cleanup\n");
+ //iErrorOffset = iStackOverhead;
+ iErrorOffset = 0;
+
+ //iStackOverhead += DWORD_SIZE;
+ //printf("\tpush\teax\t\t; temp storage for Stack Allocation Flags\n");
+ //iAllocOffset = iStackOverhead;
+ iAllocOffset = 0;
+
+ //iStackOverhead += DWORD_SIZE;
+ //printf("\tpush\teax\t\t; temp storage for BMP Flags\n");
+ //iBMPOffset = iStackOverhead;
+ iBMPOffset = 0;
+
+ //iStackOverhead += DWORD_SIZE;
+ //printf("\tpush\teax\t\t; temp storage for Alias Flags\n");
+ //iAliasOffset = iStackOverhead;
+ iAliasOffset = 0;
+ }
+
+ iStackOverhead += DWORD_SIZE;
+ printf("\tpush\teax\t\t; stack thunk id\n");
+ iStackThunkIDOffset = iStackOverhead;
+
+ iStackOverhead += DWORD_SIZE;
+
+ for (i = 0; i < iNumPtrs; i++)
+ printf("\tpush\teax\t\t; temp storage for ptr param #%u\n", i + 1);
+
+ if (iNumPtrs)
+ {
+ printf( "\n\tcall\tGetThunkID32\n");
+ printf( "\tmov\t[ebp-%u],eax\t\t; pointer thunk id\n",
+ iPtrThunkIDOffset);
+ }
+}
+
+
+/*** cod_PointerHandler32
+ *
+ * This function traverses the list of parameters in the from node of the
+ * mapping, and emits code for boundary checking and structure repacking
+ * of pointer parameters.
+ *
+ * Entry: pMNode is the pointer to a MapNode.
+ *
+ * Exit: assembly code is emitted.
+ *
+ * History:
+ * 28-Nov-1988 JulieB Created it.
+ */
+
+cod_PointerHandler32(MapNode *pMNode)
+
+{
+ TypeNode *pFromList, *pToList;
+
+ fGDIAllocUsed = FALSE;
+ fMapTo16Used = FALSE;
+
+ printf("\n; ****> BEGIN Pointer/Structure Section\n\n");
+ pFromList = pMNode->pFromNode->ParamList;
+ pToList = pMNode->pToNode->ParamList;
+ while (pFromList && pToList) {
+ if (pFromList->iPointerType) {
+ ///*
+ // * Load source address into esi.
+ // */
+ //printf("\n\n\tmov\tesi,[ebp+%u]\t\t;%s base address\n",
+ // pFrom->iOffset, typ_NonNull(pFrom->pchIdent));
+ //cod32_HandlePointer(pFromList, pToList);
+ cod32_HandlePointerGDI( pFromList, pToList);
+ }
+ pFromList = pFromList->pNextNode;
+ pToList = pToList->pNextNode;
+ }
+ printf("\n; ****> END Pointer/Structure Section\n\n");
+}
+
+
+/*** cod32_HandlePointer(pFrom,pTo)
+ *
+ * This function will act on the two pointers accordingly.
+ * Structures will be repacked if needed, and buffers will be ensured
+ * not to cross 64k boundaries.
+ *
+ * Entry: pFromList - Parameter input to thunk.
+ * pToList - Parameter output from thunk.
+ * esi must be set up.
+ *
+ * Exit: pointers are handled and code is generated.
+ *
+ */
+
+int cod32_HandlePointer(TypeNode *pFrom,
+ TypeNode *pTo)
+
+{
+ int iItemSize = -1;
+ TypeNode * pSizeP;
+ int NullLabel;
+ unsigned int JumpLabel;
+ unsigned int AllowLabel;
+ unsigned int SizeOkLabel;
+ unsigned int iTemp1, iTemp2;
+
+
+ printf("\n;Pointer %s --> %s\n",
+ typ_NonNull(pFrom->pchIdent), typ_NonNull(pTo->pchIdent));
+
+ printf("\tor\tesi,esi\n");
+ printf("\tjz\tL%u\n\n", NullLabel = gen_LabelCount++);
+ printf("\tmov\t[ebp-%u],esi\n", pFrom->iTempOffset);
+
+ /*
+ * If structures and (not identical or contain pointers), call
+ * structure repacking routine.
+ */
+ iTemp1 = typ_TypeIdentical(pFrom, pTo);
+ iTemp2 = cod_CountPointerParameters(pFrom->pStructElems, FALSE);
+
+ if (pFrom->iBaseType == TYPE_STRUCT)
+ {
+ printf("\n;Structures %s Identical\n", (iTemp1) ? "are" : "are not");
+ printf(";Structures %s pointers\n\n", (iTemp2) ? "have" : "don't have");
+ }
+
+ gTransferBytes = 0;
+
+ if ((pFrom->iBaseType == TYPE_STRUCT) && (!iTemp1 || iTemp2))
+ {
+ if (pFrom->pSizeParam)
+ cod32_HandleStructureBuffer(pFrom,pTo);
+ else
+ cod32_StructureRepack(pFrom, pTo);
+
+ } else if (pFrom->iBaseType != pTo->iBaseType) {
+ /*
+ * If the types are not equal, then they must be shorts or longs.
+ * Call a routine suitable for copying and converting the buffer
+ *
+ * If there is no size parameter, then we are passing a long or a
+ * short. If the conversion is LONG to SHORT, then we can just use
+ * the existing long value as the buffer for the short. We will need
+ * to ensure that the copy out routine correctly extends the value.
+ */
+ if ((pFrom->pSizeParam) || (pFrom->iArraySize > 1) ||
+ (pFrom->iBaseDataSize < pTo->iBaseDataSize))
+
+ cod32_CopyConvertBuffer(pFrom, pTo);
+
+ else {
+ unsigned int CheckLabel;
+
+ printf("\n;Have PU/LONG, want PU/SHORT\n");
+ printf(";Use the LONG as buffer, only if it doesn't\n");
+ printf(";cross boundary\n");
+ printf("\n;Check Boundary Crossing - fixed size item\n");
+
+ CheckLabel = gen_LabelCount++;
+
+ if (pFrom->fSemantics & SEMANTIC_INPUT) {
+ printf("\tmov\teax,[esi]\n");
+ printf("\tcmp\tsi,%lu\n",
+ (long)(0xffffL - (long)(typ_FullSize(pFrom) - 1)));
+ printf("\tjbe\tL%u\t\t\t;Enough room\n\n", CheckLabel);
+
+ } else {
+ printf("\tcmp\tsi,%lu\n",
+ (long)(0xffffL - (long)(typ_FullSize(pFrom) - 1)));
+ printf("\tjbe\tL%u\t\t\t;Enough room\n\n", NullLabel);
+ }
+
+ printf("; Allocate space on stack\n");
+ printf("\tsub\tesp,%u\t\t\t;Alloc Mem\n", typ_FullSize(pTo));
+ printf("\tand\tesp,0FFFFFFFCh\t\t;DWORD align\n");
+ printf("\tmov\tedi,esp\t\t\t;Points to new data area\n");
+
+ if (pFrom->fSemantics & SEMANTIC_INPUT)
+ printf("\tmov\t[edi],ax\n");
+
+ /*
+ * We have allocated space on the stack for the copy of the
+ * buffer. If the item is input only, then we don't need to
+ * deal with the buffer on output. In this special case, we
+ * can eliminate saving the new pointer, since we will never
+ * use it again anyway.
+ */
+ if (pFrom->fSemantics & SEMANTIC_OUTPUT)
+ printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
+ else {
+ printf("\n;Item is input only. Not saving new pointer\n");
+ printf(";Deallocated implicitly\n");
+ }
+
+ if (pFrom->fSemantics & SEMANTIC_INPUT) {
+ printf("\nL%u:\n",CheckLabel);
+ if (pFrom->AllowList) {
+ AllowLabel = gen_LabelCount++;
+ cod32_HandleAllowList(pFrom->AllowList,AllowLabel);
+ }
+ switch (pFrom->iBaseType)
+ {
+ case TYPE_ULONG:
+ printf("\tcmp\teax,0ffffh\n");
+ printf("\tja\tINVP_%s\t\t;Jmp on large value\n\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ break;
+ case TYPE_LONG:
+ printf("\tmovsx\tecx,ax\n");
+ printf("\tcmp\teax,ecx\n");
+ printf("\tjne\tINVP_%s\t\t;\n\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ break;
+ default:
+ fatal("cod32_HandlePointer: Type assertion failed");
+ }
+ if (pFrom->AllowList)
+ printf("L%u:",AllowLabel);
+ }
+ }
+ }
+
+ /*
+ * If not a structure, or structure requires no repacking, then consider
+ * all other instances of pointers as buffers. If a pointer type has a
+ * Size Parameter, which is defined in a semantic block, then the size
+ * parameter will either be the size in bytes, or a count of the number
+ * items. If it is the count, then the size will be determined by
+ * multiplying the count by the size of the item.
+ */
+ else {
+ if (pFrom->iBaseType == TYPE_STRUCT)
+ printf(";Treat structure same as buffer\n");
+
+ SizeOkLabel = NullLabel;
+
+ if (pSizeP = pFrom->pSizeParam)
+ {
+ printf("\tmov\tecx,[ebp+%u]\t\t;Get Size Parameter\n", pSizeP->iOffset);
+ if (pSizeP->iPointerType)
+ printf("\n;Check for NULL pointer\n");
+
+ printf("\tor\tecx,ecx\n");
+ printf("\tjz\tL%u\t\t;Nothing to check\n", NullLabel);
+
+ if (pSizeP->iPointerType)
+ {
+ printf("\t\t\t\t;ecx has pointer to size\n");
+ if (pSizeP->iBaseDataSize == WORD_SIZE)
+ printf("\tmovzx\tecx,WORD PTR [ecx]\t\t;Get Size\n");
+ else
+ printf("\tmov\tecx,[ecx]\t\t;Get Size\n");
+ printf("\tor\tecx,ecx\n");
+ printf("\tjz\tL%u\t\t;Nothing to check\n", NullLabel);
+ }
+
+ if ((pSizeP->iBaseDataSize == DWORD_SIZE) &&
+ (pTo->pSizeParam->iBaseDataSize < DWORD_SIZE)) {
+
+ printf("\n;DWORD --> WORD sized length. Error if Size > 64k\n");
+ if (pGlobal_From->fSemantics & SEMANTIC_TRUNC) {
+ printf("\tcmp\tecx,10000h\n");
+ printf("\tjae\tINVP_%s\t\t\t;jmp if too long\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ }
+ }
+
+ if (pSizeP->fSemantics & SEMANTIC_SIZE)
+ printf(";ECX holds size in bytes\n");
+ else if (pSizeP->fSemantics & SEMANTIC_COUNT) {
+ if (typ_FullSize(pFrom) > 1) {
+ printf(";ECX holds count of items\n");
+ printf("\tmov\teax,%d\t\t;Size of target data type\n",
+ typ_FullSize(pFrom));
+ printf("\tmul\tcx\n");
+ if (pGlobal_From->fSemantics & SEMANTIC_TRUNC) {
+ printf("\tjc\tINVP_%s\t\t\t;jmp if too long\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ }
+ printf("\tmovzx\tecx,ax\n\n");
+ }
+ else
+ printf("\n;The data size = 1, so the count == size of buf\n");
+ }
+ else
+ fatal("Internal Error: Size semantic not sizeof or countof");
+
+ printf("\n;Check Boundary Crossing\n");
+ printf("\tmov\teax,esi\n");
+ printf("\tneg\tax\n");
+
+ printf("\tjz\tL%u\t\t\t;0=full 64k of room\n\n", SizeOkLabel);
+ printf("\tcmp\tax,cx\n");
+ printf("\tjae\tL%u\t\t\t;Enough room\n\n", SizeOkLabel);
+
+ cod32_HandleBoundaryCross(SIZE_VARIABLE, pFrom, 0);
+ }
+ else {
+ /*
+ * No size parameter, assume fixed size parameter.
+ */
+ switch (pFrom->iBaseType)
+ {
+ case TYPE_STRING:
+ printf(";Handle String Parameters\n");
+ printf("\n\tpush\t%d\t\t;Alias flag offset\n",
+ -iAliasOffset);
+ printf("\tpush\t%lu\t\t;Flag Mask\n",
+ (long)((long) 1 << pFrom->iPointerNumber));
+ printf("\tpop\tedx\n");
+ printf("\tcall\tTHK32HANDLESTRING\n");
+ printf("\tjc\tERR_%s\t\t\t;jmp if too long\n",
+ pGlobal_From->pchFunctionName);
+ printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
+ break;
+
+ default:
+ /*
+ * Static size.
+ */
+ printf("\n;Check Boundary Crossing - fixed size item\n");
+ printf("\tcmp\tsi,%lu\n",
+ (long)(0xffffL - (typ_FullSize(pFrom) - 1)) );
+ printf("\tjbe\tL%u\t\t\t;Enough room\n\n", SizeOkLabel);
+ cod32_HandleBoundaryCross(SIZE_FIXED, pFrom,
+ typ_FullSize(pFrom));
+ }
+ }
+ }
+ printf("\nL%u:\n", NullLabel);
+}
+
+
+/*** cod32_HandleStructureBuffer(pFrom,pTo)
+ *
+ * This routine handles a buffer full of structures. The buffer has a
+ * variable length size which is given by either a sizeof semantic or
+ * by a countof semantic. This routine will convert the structure.
+ *
+ * This routine is only called when the structures are not identical,
+ * and therefore the buffer needs conversion.
+ *
+ * Entry: pFrom and pTo are the two type nodes to use.
+ *
+ * Exit: buffer is converted.
+ */
+
+void
+cod32_HandleStructureBuffer(TypeNode *pFrom,
+ TypeNode *pTo)
+
+{
+ TypeNode *pSizeP;
+ FixupRec *pFixupList = NULL;
+ unsigned int NullLabel;
+ unsigned int LoopLabel;
+ unsigned int iESI,iEDI;
+
+
+ iESI = gESI = 0;
+ iEDI = gEDI = 0;
+
+ pSizeP = pFrom->pSizeParam;
+
+ printf("\n;Parameter has size semantics. This is a buffer of structs\n");
+
+ /*
+ * The fact that we are in this routine means that there is a size
+ * parameter. Now the job is to figure out what type of size parameter
+ * it is, and calculate the appropriate buffer size.
+ */
+ printf("\tmov\teax,[ebp+%u]\t\t;Get Size Parameter\n",
+ pSizeP->iOffset);
+
+ if (pSizeP->iPointerType)
+ printf("\n;Check for NULL pointer\n");
+
+ /* At this point, we know that the previous label handles the case
+ * where the buffer was empty (or pointer was NULL).
+ * Therefore, if we set out NullLabel to current -1, we get the
+ * correct fixup.
+ */
+ NullLabel = gen_LabelCount - 1;
+
+ printf("\tor\teax,eax\n");
+ printf("\tjz\tL%u\t\t;Nothing to check\n", NullLabel);
+
+ if (pSizeP->iPointerType) {
+ printf("\t\t\t\t;eax has pointer to size\n");
+ if (pSizeP->iBaseDataSize == WORD_SIZE)
+ printf("\tmovzx\teax,WORD PTR [eax]\t\t;Get Size\n");
+ else
+ printf("\tmov\teax,[eax]\t\t;Get Size\n");
+ printf("\tor\teax,eax\n");
+ printf("\tjz\tL%u\t\t;Nothing to check\n", NullLabel);
+ }
+
+ if ((pSizeP->iBaseDataSize == DWORD_SIZE) &&
+ (pTo->pSizeParam->iBaseDataSize < DWORD_SIZE))
+ {
+ printf("\n;DWORD --> WORD sized length. Error if Size > 64k\n");
+
+ printf("\tcmp\teax,10000h\n");
+ printf("\tjae\tINVP_%s\t\t\t;jmp if too long\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ }
+
+ if (pSizeP->fSemantics & SEMANTIC_SIZE) {
+ printf(";ECX holds size in bytes\n");
+ printf(";We need to figure out the number of structures\n");
+ printf(";that will fit\n");
+
+ printf("\txor\tedx,edx\n");
+ printf("\tmov\tecx,%u\t\t;Source struct size\n",typ_FullSize(pFrom));
+ printf("\tdiv\tecx\n");
+ printf("\tmov\t[ebp-%u],eax\t;Save the count\n",iTempStoreOffset);
+ printf("\tmov\tcx,%u\t\t;target struct size\n",typ_FullSize(pTo));
+ printf("\tmul\tcx\t\t;Results in target buffer needed\n");
+ printf("\tjc\tINVP_%s\t\t;jmp if too long\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ }
+ else if (pSizeP->fSemantics & SEMANTIC_COUNT) {
+ printf(";EAX holds count of items\n");
+ printf("\n\ttest\teax,0ffff0000h\t;Must be < 64k\n");
+ printf("\tjnz\tINVP_%s\t\t;jmp if too many items\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+
+ printf("\tmov\t[ebp-%u],eax\t\t;Save count\n",iTempStoreOffset);
+ printf("\tmov\tcx,%u\t\t;target struct size\n",typ_FullSize(pTo));
+ printf("\tmul\tcx\n");
+ printf("\tjc\tINVP_%s\t\t;jmp if too long\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ }
+ else
+ fatal("cod32_HandleStructureBuffer: Size semantic not sizeof|countof");
+
+ printf("\n\tmov\tecx,eax\t\t;Move size into ecx\n");
+
+ cod32_AllocateVariableSize(pFrom,0);
+
+ printf("\tmov\t[ebp-%u],edi\t\t;store new ptr\n",
+ pFrom->iTempOffset);
+
+ /*
+ * If semantics are not input, then don't emit copy in code.
+ */
+ if (!(pFrom->fSemantics & SEMANTIC_INPUT))
+ return;
+
+ printf("\tmov\tecx,[ebp-%u]\t\t;restore count\n",iTempStoreOffset);
+
+ /*
+ * At this point, we know the following facts:
+ * 1 - The structures in this buffer contain no pointers
+ * and therefore will require no internal fixups.
+ * 2 - ESI holds the source address, EDI holds the destination
+ * 3 - ECX holds the count of structures to be converted
+ */
+ gTransferBytes = 0;
+
+ LoopLabel = gen_LabelCount++;
+ printf("\n;Array of structures\n");
+
+ printf("\nL%u:\n", LoopLabel);
+ printf("\tpush\tecx\t\t;Save array count\n");
+
+ cod32_RepackElements(pFrom,pTo,
+ pFrom->pStructElems,
+ pTo->pStructElems, &pFixupList);
+
+ iESI = gESI;
+ iEDI = gEDI;
+
+ cod_AdjustReg("esi", &iESI, pFrom->iStructOffset + pFrom->iBaseDataSize);
+ cod_AdjustReg("edi", &iEDI, pTo->iStructOffset + pTo->iBaseDataSize);
+
+ printf("\n\tpop\tecx\t\t;Restore array count\n");
+ printf("\n\tloop\tL%u\n", LoopLabel);
+ gESI = pFrom->iStructOffset + typ_FullSize(pFrom);
+ gEDI = pTo->iStructOffset + typ_FullSize(pTo);
+}
+
+
+/*** cod32_HandleAllowList(AllowList,AllowLabel);
+ *
+ * This routine searches down the allowlist, printing out the
+ * appropriate assembler code for each entry.
+ *
+ * Entry: AllowList is the list to search.
+ * AllowLabel is the label to jump to.
+ *
+ * Exit: code for each entry in allowlist is generated.
+ */
+
+cod32_HandleAllowList(AllowNode *AllowList,
+ int AllowLabel)
+
+{
+ if (AllowList)
+ printf("\n;Allowable Value List\n\n");
+
+ while (AllowList) {
+ printf("\n\tcmp\teax,0%lxh\n",AllowList->ulValue);
+ printf("\tje\tL%u\n",AllowLabel);
+ AllowList = AllowList->Next;
+ }
+ printf("\n");
+}
+
+
+/*** cod32_HandleRestricted(pFrom)
+ *
+ * This routine checks the from node for the restricted semantic.
+ * If the restricted semantic is set, then it will print out the
+ * allow list.
+ *
+ * Entry: pFrom is the typenode to check.
+ *
+ * Exit: allowlist code is generated if restricted semantic is set.
+ */
+
+cod32_HandleRestricted(TypeNode *pFrom)
+
+{
+ unsigned int AllowLabel;
+
+
+ if (pFrom->fSemantics & SEMANTIC_RESTRICT) {
+ printf("\n\n;*** Parameter is restricted! ***\n");
+ printf("\n;Check for restricted values\n");
+ AllowLabel = gen_LabelCount++;
+ cod32_HandleAllowList(pFrom->AllowList,AllowLabel);
+
+ printf("\tjmp\tINVP_%s\t\t;Illegal value found\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+
+ printf("\nL%u:\n",AllowLabel);
+ }
+}
+
+
+/*** cod32_CopyConvertBuffer(pFrom,pTo)
+ *
+ * This function will perform a copy/convert of a buffer.
+ * The buffer is presumed to be in the formal parameter list of the
+ * API declaration.
+ *
+ * Entry: pFrom and pTo are the typenodes to use.
+ *
+ * Exit: buffer is copied/converted.
+ */
+
+cod32_CopyConvertBuffer(TypeNode *pFrom,
+ TypeNode *pTo)
+
+{
+ TypeNode * pSizeP;
+ unsigned int JumpLabel;
+ unsigned int NullLabel;
+
+
+ /*
+ * If there is a size parameter, then the buffer size is determined at
+ * run time. Otherwise, the buffer size is static.
+ */
+ NullLabel = gen_LabelCount;
+ NullLabel--; /** The previous label handles NULL and zero lens **/
+
+ if (pSizeP = pFrom->pSizeParam) { /* Runtime */
+ printf("\tmov\tecx,[ebp+%u]\t\t;Get Size Parameter\n", pSizeP->iOffset);
+ if (pSizeP->iPointerType)
+ printf("\n;Check for NULL pointer\n");
+ printf("\tor\tecx,ecx\n");
+ printf("\tjz\tL%u\t\t;Nothing to check\n", NullLabel);
+
+ if (pSizeP->iPointerType)
+ {
+ printf("\t\t\t\t;ecx has pointer to size\n");
+ if (pSizeP->iBaseDataSize == WORD_SIZE)
+ printf("\tmovzx\tecx,WORD PTR [ecx]\t\t;Get Size\n");
+ else
+ printf("\tmov\tecx,[ecx]\t\t;Get Size\n");
+ printf("\tor\tecx,ecx\n");
+ printf("\tjz\tL%u\t\t;Nothing to check\n", NullLabel);
+ }
+
+ if ((pSizeP->iBaseDataSize == DWORD_SIZE) &&
+ (pTo->pSizeParam->iBaseDataSize < DWORD_SIZE) &&
+ pGlobal_From->fSemantics & SEMANTIC_TRUNC)
+ {
+ printf("\n;DWORD-->WORD sized length. Error if Size > 64k\n");
+ printf("\tcmp\tecx,10000h\n");
+ printf("\tjae\tINVP_%s\t\t\t;jmp if too long\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ }
+
+ if (pSizeP->fSemantics & SEMANTIC_SIZE)
+ {
+ printf(";ECX holds size in bytes\n");
+ printf(";We need to figure out the number of elements\n");
+ printf(";that will fit\n");
+
+ printf("\n\tmov\teax,ecx\n");
+ printf("\txor\tedx,edx\n");
+ printf("\tmov\tecx,%u\t\t;Source size\n",typ_FullSize(pFrom));
+ printf("\tdiv\tcx\n");
+ printf("\tmov\t[ebp-%u],eax\t;Save the count\n",iTempStoreOffset);
+ printf("\tmov\tcx,%u\t\t;target buffer size\n",typ_FullSize(pTo));
+ printf("\tmul\tcx\t\t;Results in target buffer needed\n");
+ printf("\tjc\tINVP_%s\t\t;jmp if too long\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ }
+
+ if (pSizeP->fSemantics & SEMANTIC_COUNT) {
+ if (typ_FullSize(pTo) > 1) {
+ printf(";ECX holds count of items\n");
+ printf(";Save count of items for later use\n");
+ printf("\n\tmov\t[ebp-%u],ecx\t\t;Temporary Storage\n",
+ iTempStoreOffset);
+ printf("\tmov\teax,%d\t\t;Size of target data type\n",
+ typ_FullSize(pTo));
+ printf("\tmul\tcx\n");
+ printf("\tjc\tINVP_%s\t;jmp if too long\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ }
+ else
+ printf("\n;The data size = 1, so the count == size of buf\n");
+ }
+ printf("\tmovzx\tecx,ax\n\n");
+
+ cod32_AllocateVariableSize(pFrom, 0);
+
+ printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
+
+ if (pFrom->fSemantics & SEMANTIC_INPUT) {
+ printf("\n\tmov\tecx,[ebp-%u]\t\t;Temporary Storage\n",
+ iTempStoreOffset);
+
+ gEDI = 0;
+ gESI = 0;
+
+ JumpLabel = gen_LabelCount++;
+ printf("\nL%u:\n", JumpLabel);
+
+ switch (pFrom->iBaseType)
+ {
+ case TYPE_UCHAR: /* UCHAR --> ULONG */
+ printf("\n;UCHAR --> ULONG\n\n");
+ printf("\tmovzx\teax,BYTE PTR[esi]\n");
+ printf("\tmov\t[edi],eax\n");
+ break;
+ case TYPE_SHORT: /* SHORT --> LONG */
+ printf("\n;SHORT --> LONG\n\n");
+ printf("\tmovsx\teax,WORD PTR[esi]\n");
+ printf("\tmov\t[edi],eax\n");
+ break;
+ case TYPE_USHORT: /* USHORT --> ULONG */
+ printf("\n;USHORT --> ULONG\n\n");
+ printf("\tmovzx\teax,WORD PTR[esi]\n");
+ printf("\tmov\t[edi],eax\n");
+ break;
+ case TYPE_LONG: /* LONG --> SHORT */
+ case TYPE_ULONG: /* ULONG --> USHORT */
+ printf("\n;U/LONG --> U/SHORT\n\n");
+ printf("\tmov\teax,DWORD PTR [esi]\n");
+ printf("\tmov\tWORD PTR [edi],ax\n");
+ break;
+ default:
+ fatal("cod32_CopyConvertBuffer: Tried converted %d to %d",
+ pFrom->iBaseType, pTo->iBaseType);
+ }
+ printf("\tadd\tesi,%u\n", pFrom->iBaseDataSize);
+ printf("\tadd\tedi,%u\n", pTo->iBaseDataSize);
+ printf("\tloop\tL%u\n", JumpLabel);
+
+ } else
+ printf("\n;Data item does not have input semantics\n");
+ }
+ else { /* Static */
+ cod32_AllocFixedSize(typ_FullSize(pTo), pFrom);
+
+ if (pFrom->fSemantics & SEMANTIC_INPUT) {
+ gEDI = 0;
+ gESI = 0;
+ cod32_CopyConvert(pFrom, pTo);
+ }
+ else
+ printf("\n;Data item does not have input semantics\n");
+ }
+}
+
+
+/*** cod32_StructureRepack(pFrom,pTo)
+ *
+ * This function generates the code that converts one structure
+ * to another structure.
+ *
+ * Entry: pFrom - pointer to the 32-bit structure.
+ * pTo - pointer to the 16-bit structure.
+ *
+ * Exit: structure repack code is generated.
+ *
+ * History:
+ * 23-Dec-1988 KevinRo Created It
+ */
+
+void
+cod32_StructureRepack(TypeNode *pBaseFrom,
+ TypeNode *pBaseTo)
+
+{
+ FixupRec *pFixupList = NULL, *pCurrent;
+ TypeNode *pFrom, *pTo;
+ TypeNode *ptFrom, *ptTo;
+
+
+ pFrom = pBaseFrom->pStructElems;
+ pTo = pBaseTo->pStructElems;
+
+ cod32_AllocFixedSize(typ_FullSize(pBaseTo), pBaseFrom);
+
+ gEDI = 0;
+ gESI = 0;
+
+ /*
+ * If the structure is not marked with the input semantic, then the
+ * structure does not contain any useful information. Therefore,
+ * we will assume that any substructures to this structure are
+ * not interesting, and may not actually exist.
+ */
+ if (!(pBaseFrom->fSemantics & SEMANTIC_INPUT))
+ return;
+
+ printf(";Copy structure to new area\n\n");
+ cod32_RepackElements(pBaseFrom, pBaseTo, pFrom, pTo, &pFixupList);
+
+ /*
+ * Now, handle the fixups.
+ */
+ while (pCurrent = cod_GetFixupRecord(&pFixupList)) {
+ printf("\n\n;Fixup imbedded pointer %s\n\n",
+ typ_NonNull(pCurrent->pFrom->pchIdent));
+ printf("\tmov\tesi,[ebp-%u]\t\t;Get parents pointer\n",
+ pCurrent->pParentFrom->iTempOffset);
+ printf("\tmov\tesi,[esi+%u]\t\t;Get Fixups pointer\n",
+ pCurrent->pTo->iStructOffset);
+
+ cod32_HandlePointer(pCurrent->pFrom, pCurrent->pTo);
+
+ printf("\n;Patch in new pointer value\n");
+ printf("\tmov\tedi,[ebp-%u]\t\t;Get parents pointer\n",
+ pCurrent->pParentFrom->iTempOffset);
+ printf("\tmov\tesi,[ebp-%u]\t\t;Get Fixups new pointer\n",
+ pCurrent->pFrom->iTempOffset);
+
+ if (pCurrent->pFrom->iPointerType != pCurrent->pTo->iPointerType) {
+ switch (pCurrent->pFrom->iPointerType)
+ {
+ case TYPE_FAR16:
+ printf(";Convert 16:16 --> 0:32\n");
+ printf("\tor\tesi,esi\n");
+ printf("\tjz\tshort L%u\n",gen_LabelCount);
+ printf("\tror\tesi,16\n");
+ printf("\tshr\tsi,3\n");
+ printf("\trol\tesi,16\n");
+ printf("L%u:\n",gen_LabelCount++);
+ break;
+ case TYPE_NEAR32:
+ printf(";Convert 0:32 --> 16:16\n");
+ printf("\tor\tesi,esi\n");
+ printf("\tjz\tshort L%u\n",gen_LabelCount);
+ printf("\tror\tesi,16\n");
+ printf("\tshl\tsi,3\n");
+ printf("\tmov\teax,ss\n");
+ printf("\tand\teax,3\n");
+ printf("\tor\tal,4\n");
+ printf("\tor\tsi,ax\n");
+ printf("\trol\tesi,16\n");
+ printf("L%u:\n",gen_LabelCount++);
+ break;
+ default:
+ fatal("Structure Repack: Unknown pointer type");
+ }
+ }
+ printf("\tmov\t[edi+%u],esi\t\t;Put Fixups pointer\n",
+ pCurrent->pTo->iStructOffset);
+ free(pCurrent);
+ }
+}
+
+
+/*** cod32_RepackElements(pParent,pFrom,pTo,pFixupList)
+ *
+ *
+ *
+ * Entry:
+ *
+ * Exit:
+ */
+
+cod32_RepackElements(TypeNode *pParentFrom,
+ TypeNode *pParentTo,
+ TypeNode *pFrom,
+ TypeNode *pTo,
+ FixupRec **pFixupList)
+
+{
+ TypeNode * pToNode, *pFromNode;
+ unsigned int iEDI, iESI;
+ unsigned int JumpLabel;
+
+
+ fReAlignmentNeeded = 0;
+
+ for (pToNode = pTo, pFromNode = pFrom;
+ pFromNode;
+ pToNode = pToNode->pNextNode, pFromNode = pFromNode->pNextNode)
+ {
+ printf("\n;Element %s --> %s\n", typ_NonNull(pFromNode->pchIdent),
+ typ_NonNull(pToNode->pchIdent));
+ /*
+ * If the fReAlignmentNeeded flag is set, then the previous operation
+ * was a CopyConvert. The adjustment of the registers in that routine
+ * was moved here to optimize the increment of the registers.
+ * At the end of a CopyConvert, we only want to increment the
+ * registers in the cases when there are more elements in the
+ * structure. The fact that we have reached this statement implies
+ * that there are more elements in the structure.
+ */
+ if (fReAlignmentNeeded) {
+ if (gTransferBytes)
+ fatal("RepackElements: gTransferBytes = %u", gTransferBytes);
+
+ printf("\n;Adjust registers after conversion\n");
+ cod_AdjustReg("esi", &gESI, pFromNode->iStructOffset);
+ cod_AdjustReg("edi", &gEDI, pToNode->iStructOffset);
+
+ fReAlignmentNeeded = 0;
+ }
+
+ /*
+ * This assignment optimizes the way that bytes are transferred,
+ * so that we don't need adjustments when bytes items precede
+ * larger sized items. This statement only has effect when a
+ * realignment is about to occur. This value is reset again a
+ * few lines down.
+ */
+ gTransferBytes = MIN((pFromNode->iStructOffset - gESI),
+ pToNode->iStructOffset - gEDI);
+
+ /*
+ * If either the TO or FROM node is deleted, then we need to
+ * realign ESI and EDI.
+ */
+ if ( (pFromNode->iDeleted) || (pToNode->iDeleted)) {
+ printf(";Deleted structure element\n");
+
+ if (gTransferBytes) {
+ printf(";Alignment Change\n");
+ cod32_TransferBlock(gTransferBytes);
+ gTransferBytes = 0;
+ printf("\n;ReAlignment\n");
+ }
+
+ if (pFromNode->iDeleted) {
+ printf(";Source element is deleted\n");
+ printf("\tmov\teax,%u\n",pFromNode->iFillValue);
+
+ switch (pToNode->iBaseType)
+ {
+ case TYPE_UCHAR:
+ printf(";Need a 8-bit value\n");
+ printf("\tstosb\n");
+ break;
+ case TYPE_USHORT:
+ case TYPE_SHORT:
+ printf(";Need a 16-bit value\n");
+ printf("\tstosw\n");
+ break;
+ case TYPE_LONG:
+ case TYPE_ULONG:
+ printf(";Need a 32-bit value\n");
+ printf("\tstosd\n");
+ break;
+ default:
+ fatal("Bad type for deleted struct element\n");
+ }
+ }
+ else {
+ /*
+ * In this case, the To node is deleted. This means that
+ * we don't want to copy the current element.
+ */
+ switch (pFromNode->iBaseType)
+ {
+ case TYPE_UCHAR:
+ printf(";Deleting a 8-bit value\n");
+ break;
+ case TYPE_USHORT:
+ case TYPE_SHORT:
+ printf(";Deleting a 16-bit value\n");
+ break;
+ case TYPE_LONG:
+ case TYPE_ULONG:
+ printf(";Deleting a 32-bit value\n");
+ break;
+ default:
+ fatal("Bad type for deleted struct element\n");
+ }
+ }
+ goto DoneWithNodes; /** Avoid the rest of this loop **/
+ }
+
+ /*
+ * If the alignment is going to shift, then execute a block transfer,
+ * and realign ESI and EDI.
+ */
+ if ((pFromNode->iStructOffset - gESI) != (pToNode->iStructOffset - gEDI)) {
+ if (gTransferBytes) {
+ printf(";Alignment Change\n");
+ cod32_TransferBlock(gTransferBytes);
+ gTransferBytes = 0;
+ printf("\n;ReAlignment\n");
+ }
+ cod_AdjustReg("esi", &gESI, pFromNode->iStructOffset);
+ cod_AdjustReg("edi", &gEDI, pToNode->iStructOffset);
+ }
+
+ switch (pFromNode->iPointerType)
+ {
+ /*
+ * If we find a pointer type, then it is an imbedded pointer.
+ * The data can be included into a block copy, since we are
+ * going to handle it later.
+ */
+ case TYPE_NEAR32:
+ case TYPE_FAR16:
+ printf(";Pointer converted later\n");
+ cod_AddFixupRecord(pFixupList,
+ cod_MakeFixupRecord(pParentFrom, pParentTo,
+ pFromNode, pToNode));
+ gTransferBytes += DWORD_SIZE;
+ break;
+
+ /*
+ * If it wasn't one of the pointer types above, then it must be a
+ * non pointer parameter. Thus, it will be a long, short, ulong,
+ * ushort, or char.
+ */
+ default:
+ if (pFromNode->iBaseType == TYPE_STRUCT) {
+ unsigned int LoopLabel;
+ unsigned int iESI = gESI, iEDI = gEDI;
+
+ if (pFromNode->iArraySize > 1) {
+ cod32_TransferBlock(gTransferBytes);
+
+ gTransferBytes = 0;
+
+ cod_AdjustReg("esi", &gESI, pFromNode->iStructOffset);
+ cod_AdjustReg("edi", &gEDI, pToNode->iStructOffset);
+
+ LoopLabel = gen_LabelCount++;
+ printf("\n;Array of structures\n");
+ printf("\n\tmov\tecx,%u\n", pFromNode->iArraySize);
+ printf("\nL%u:\n", LoopLabel);
+ printf("\tpush\tecx\t\t;Save array count\n");
+ }
+ cod32_RepackElements(pParentFrom, pParentTo,
+ pFromNode->pStructElems,
+ pToNode->pStructElems, pFixupList);
+ iESI = gESI;
+ iEDI = gEDI;
+
+ if (pFromNode->iArraySize > 1) {
+ cod_AdjustReg("esi", &iESI, pFromNode->iStructOffset +
+ pFromNode->iBaseDataSize);
+ cod_AdjustReg("edi", &iEDI, pToNode->iStructOffset +
+ pToNode->iBaseDataSize);
+ printf("\n\tpop\tecx\t\t;Restore array count\n");
+ printf("\n\tloop\tL%u\n", LoopLabel);
+ gESI = pFromNode->iStructOffset +
+ typ_FullSize(pFromNode);
+ gEDI = pToNode->iStructOffset + typ_FullSize(pToNode);
+ }
+ }
+ else {
+ fReAlignmentNeeded = 0;
+ cod32_CopyConvert(pFromNode, pToNode);
+ }
+ }
+
+DoneWithNodes:
+ if ((pToNode->pNextNode == NULL) && (pParentTo->iPointerType)) {
+ cod32_TransferBlock(gTransferBytes);
+ gTransferBytes = 0;
+ }
+ }
+}
+
+
+/*** cod32_HandleBoundaryCross(fSize,pFrom,iSize)
+ *
+ * Emits code to handle boundary crossing of pFrom. This code assumes
+ * that esi holds the source address.
+ *
+ * Entry: fSize - either SIZE_FIXED or SIZE_VARIABLE.
+ * pFrom - typenode for From pointer.
+ * iSize - size of item with SIZE_FIXED, or maximum length of
+ * item when SIZE_VARIABLE.
+ *
+ * Notes:
+ * If fSize == SIZE_VARIABLE then the size of the data item is
+ * assumed to be in ECX.
+ *
+ * Exit: Code to allocate the appropriate amount of memory will be
+ * emitted, along with appropriate code to copy the data to
+ * the new location. Code to set the appropriate flags will
+ * also be set.
+ */
+
+unsigned int iCopyLabel;
+unsigned int iNoCopyLabel, iNextSize;
+
+void
+cod32_HandleBoundaryCross(unsigned int fSize,
+ TypeNode *pFrom,
+ unsigned int iSize)
+
+{
+ iCopyLabel = gen_LabelCount++;
+ iNoCopyLabel = gen_LabelCount++;
+
+ if (fSize == SIZE_FIXED) {
+ cod32_HandleFixedSize(iSize, pFrom);
+ return;
+ }
+ else {
+ if (!pGlobal_To->fInlineCode) {
+ printf("\tcall\tThk32HandleBoundary\n");
+ printf("\tor\teax,eax\n");
+ printf("\tjnz\tNOMEM_%s\t\t\t;\n", pGlobal_From->pchFunctionName);
+ printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
+ printf("\tor\tedx,edx\n");
+ printf("\tjs\tshort L%u\t\t;Alloced Mem \n", iCopyLabel);
+ printf("\tor\t%s PTR [ebp+(edx*4)-%u],%lu\t\t;Set Flag\n",
+ (pFrom->iPointerNumber > 7)?"DWORD":"BYTE",iAliasOffset,
+ (long) 1 << pFrom->iPointerNumber);
+
+ /*
+ * Don't need jump if semantics are not input. There will be no
+ * copy code output if semantics are input.
+ */
+ if (pFrom->fSemantics & SEMANTIC_INPUT) {
+ printf("\tdec\tedx\n");
+ printf("\tjs\tshort L%u\t\t;Aliases not copied\n",
+ iNoCopyLabel);
+ }
+ }
+ else {
+ if (iSize == 0)
+ iSize--; /** Make iSize huge **/
+
+ pFrom->fTempAlloc |= ALLOC_STACK; /* Eligable for stack alloc */
+ printf("\tcmp\tecx,%u\n", SMALL_ITEM);
+
+ if (iSize >= MEDIUM_ITEM)
+ printf("\tja\tshort L%u\n\n", iNextSize = gen_LabelCount++);
+ else {
+ printf("\tja\tINVP_%s\t\t\t;jmp if too long\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ }
+ printf("; Allocate space on stack\n");
+ printf("\tsub\tesp,ecx\t\t\t;Alloc Mem\n");
+ printf("\tand\tesp,0FFFFFFFCh\t\t;DWORD align\n");
+ printf("\tmov\tedi,esp\t\t\t;Points to new data area\n");
+ printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
+ printf("\tmov\tesi,[ebp+%u]\n", pFrom->iOffset);
+
+ printf("\tor\t%s PTR [ebp-%u],%lu\t\t;Set Stack Alloc Flag\n",
+ (pFrom->iPointerNumber >7)?"DWORD":"BYTE",
+ iAllocOffset, (long) 1 << pFrom->iPointerNumber);
+
+ if (iSize >= MEDIUM_ITEM) {
+ printf("\tjmp\tshort L%u\n", iCopyLabel);
+
+ printf("\nL%u:\n", iNextSize);
+ printf("\tcmp\tecx,%u\n", MEDIUM_ITEM);
+ if (iSize >= LARGE_ITEM)
+ printf("\tja\tshort L%u\n\n", iNextSize = gen_LabelCount++);
+ else {
+ printf("\tja\tINVP_%s\t\t\t;jmp if too long\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ }
+
+ printf("; Allocate space in BMP area\n");
+ printf("\tcall\tThk32AllocBlock\n");
+
+ pFrom->fTempAlloc |= ALLOC_BMP; /* Eligable for BMP alloc*/
+ printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
+ printf("\tor\t%s PTR [ebp-%u],%lu\t\t;Set BMP Alloc Flag\n",
+ (pFrom->iPointerNumber >7)?"DWORD":"BYTE",
+ iBMPOffset, (long) 1 << pFrom->iPointerNumber);
+ }
+ if (iSize >= LARGE_ITEM) {
+ printf("\tjmp\tshort L%u\n\n", iCopyLabel);
+ printf("\nL%u:\n", iNextSize);
+
+ printf("\n;Ensure item spans 16 pages or less.\n");
+
+ printf("\tmov\teax,esi\n");
+ printf("\tand\teax,0fffh\n");
+ printf("\tmov\tedx,10000h\n");
+ printf("\tsub\tedx,eax\n");
+ printf("\tcmp\tecx,edx\n");
+
+ if (iSize > LARGE_ITEM)
+ printf("\tja\tshort L%u\n\n", iNextSize = gen_LabelCount++);
+ else {
+ printf("\tja\tINVP_%s\t\t\t;jmp if too long\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ }
+ printf(";Create Linear Alias to item\n");
+ printf("\tlea\tedi,[ebp-%u]\t\t;Temp storage\n",
+ pFrom->iTempOffset);
+ printf("\tcall\tThk32AliasMem\n");
+ printf("\tor\teax,eax\n");
+ printf("\tjnz\tNOMEM_%s\n\n",
+ pGlobal_From->pchFunctionName);
+
+ /*
+ * Eligable for linear alias.
+ */
+ pFrom->fTempAlloc |= ALLOC_ALIAS;
+ printf("\tor\t%s PTR[ebp-%u],%lu\t\t;Set Alias Flag\n",
+ (pFrom->iPointerNumber >7)?"DWORD":"BYTE",
+ iAliasOffset, (long) 1 << pFrom->iPointerNumber);
+ printf("\tmov\tedi,[ebp-%u]\n", pFrom->iTempOffset);
+ printf("\tjmp\tshort L%u\n", iNoCopyLabel);
+ }
+ if (iSize > LARGE_ITEM) {
+ printf("\nL%u:\n", iNextSize);
+ printf(";Allocate Buffer to copy Data\n");
+ printf("\tlea\teax,[ebp-%u]\t\t;Buffer for address\n",
+ pFrom->iTempOffset);
+ printf("\tpush\teax\n");
+ printf("\tpush\tecx\n");
+ printf("\tpush\t%u\t\t;Allocation Flags\n",
+ gDosAllocFlags);
+ printf("\tcall\tDos32AllocMem\n");
+ printf("\tadd\tesp,12\n");
+ printf("\tor\teax,eax\n");
+ printf("\tjnz\tNOMEM_%s\n\n",
+ pGlobal_From->pchFunctionName);
+
+ pFrom->fTempAlloc |= ALLOC_MEMORY; /* Eligable for memory */
+ }
+ }
+ printf("\nL%u:\t\t\t;Variable Length Copy\n", iCopyLabel);
+
+ if (pFrom->fSemantics & SEMANTIC_INPUT)
+ cod32_VariableLengthCopy();
+ else
+ printf("\n;Item semantics are NOT input\n");
+
+ printf("\nL%u:\t\t\t;Variable Length No Copy\n", iNoCopyLabel);
+ }
+}
+
+
+/*** cod32_HandleFixedSize(iSize,pFrom)
+ *
+ * This worker routine to HandleBoundaryCrossing will output code
+ * to handle fixed size items that cross boundaries.
+ *
+ * Entry: iSize is the size of the item.
+ * pFrom is the typenode.
+ *
+ * Exit: boundary crossing code is generated.
+ */
+
+void
+cod32_HandleFixedSize(unsigned int iSize,
+ TypeNode *pFrom)
+
+{
+ if (!iSize)
+ fatal("cod32_HandleFixedSize: iSize = 0 \n");
+
+ if (iSize <= SMALL_ITEM) {
+ pFrom->fTempAlloc |= ALLOC_STACK; /* Eligable for stack alloc*/
+
+ printf("; Allocate space on stack\n");
+ printf("\tsub\tesp,%u\t\t\t;Alloc Mem\n", typ_FullSize(pFrom));
+ printf("\tand\tesp,0FFFFFFFCh\t\t;DWORD align\n");
+ printf("\tmov\tedi,esp\t\t\t;Points to new data area\n");
+
+ printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
+ }
+ else if (iSize <= MEDIUM_ITEM) {
+ printf("; Allocate space in BMP area\n");
+ printf(";Need block allocation\n");
+
+ printf(";Generate Allocation Call\n");
+ printf("\tcall\tThk32AllocBlock\n");
+
+ printf("\tor\teax,eax\n");
+ printf("\tjnz\tNOMEM_%s\n\n",
+ pGlobal_From->pchFunctionName);
+ printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
+ }
+ else if (iSize <= LARGE_ITEM) {
+ printf(";Create Linear Alias to item\n");
+ printf("\tlea\tedi,[ebp-%u]\t\t;Temp storage\n",
+ pFrom->iTempOffset);
+ printf("\tmov\tecx,%u\t\t;Length\n", typ_FullSize(pFrom));
+ printf("\tcall\tThk32AliasMem\n");
+ printf("\tor\teax,eax\n");
+ printf("\tjnz\tNOMEM_%s\n\n",
+ pGlobal_From->pchFunctionName);
+
+ /*
+ * If the item was aliased, then we return here to avoid the copy
+ * code at the end of this routine.
+ */
+ printf(";Aliased: no copy required\n");
+ return;
+ }
+ else {
+ fprintf(stderr, "Fixed sized item > 60k\n");
+ printf(".err Fixed sized item > 60k\n");
+ }
+
+ if (pFrom->fSemantics & SEMANTIC_INPUT)
+ cod32_TransferBlock(iSize);
+ else
+ printf("\n;Semantics are NOT input\n");
+}
+
+
+/*** cod32_AllocateVariableSize(pFrom,iSize)
+ *
+ * This routine generates the code to allocate memory based
+ * on the size of the item.
+ *
+ * Entry: pFrom is the typenode.
+ * iSize is the size of the item.
+ *
+ * Exit: memory allocation code is generated.
+ */
+
+cod32_AllocateVariableSize(TypeNode *pFrom,
+ unsigned int iSize)
+
+{
+ unsigned int templabel;
+
+
+ if (pGlobal_To->fInlineCode) {
+ if (iSize == 0)
+ iSize--; /** Make iSize huge **/
+ printf("\n;Variable Size Memory Allocator\n");
+ printf(";Allocate ECX bytes of memory\n");
+ printf("\tcmp\tecx,%u\n", SMALL_ITEM);
+
+ if (iSize >= MEDIUM_ITEM)
+ printf("\tja\tshort L%u\n\n", iNextSize = gen_LabelCount++);
+ else {
+ printf("\tja\tINVP_%s\t\t\t;jmp if too long\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ }
+ printf("; Allocate space on stack\n");
+ pFrom->fTempAlloc |= ALLOC_STACK; /* Eligable for stack alloc */
+
+ printf("\tsub\tesp,ecx\t\t\t;Alloc Mem\n");
+ printf("\tand\tesp,0FFFFFFFCh\t\t;DWORD align\n");
+ printf("\tmov\tedi,esp\t\t\t;Points to new data area\n");
+
+ printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
+ printf("\tor\t%s PTR [ebp-%u],%lu\t\t;Set Stack Alloc Flag\n",
+ (pFrom->iPointerNumber >7)?"DWORD":"BYTE",
+ iAllocOffset, (long) 1 << pFrom->iPointerNumber);
+
+ if (iSize >= MEDIUM_ITEM)
+ {
+ iCopyLabel = gen_LabelCount++;
+ printf("\tjmp\tshort L%u\n", iCopyLabel);
+
+ printf("\nL%u:\n", iNextSize);
+ printf("\tcmp\tecx,%u\n", MEDIUM_ITEM);
+ if (iSize >= LARGE_ITEM)
+ printf("\tja\tshort L%u\n\n", iNextSize = gen_LabelCount++);
+ else {
+ printf("\tja\tINVP_%s\t\t\t;jmp if too long\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ }
+ printf("; Allocate space in BMP area\n");
+ printf("\tcall\tThk32AllocBlock\n\n");
+ pFrom->fTempAlloc |= ALLOC_BMP; /* Eligable for BMP alloc*/
+ printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
+ printf("\tor\t%s PTR [ebp-%u],%lu\t\t;Set BMP Alloc Flag\n",
+ (pFrom->iPointerNumber >7)?"DWORD":"BYTE",
+ iBMPOffset, (long) 1 << pFrom->iPointerNumber);
+ }
+ if (iSize >= LARGE_ITEM) {
+ printf("\tjmp\tshort L%u\n\n", iCopyLabel);
+ printf("\nL%u:\n", iNextSize);
+ printf(";Allocate Buffer to copy Data\n");
+ printf("\tlea\teax,[ebp-%u]\t\t;Buffer for address\n",
+ pFrom->iTempOffset);
+ printf("\tpush\teax\n");
+ printf("\tpush\tecx\n");
+
+ printf("\tpush\t%u\t\t;Allocation Flags\n", gDosAllocFlags);
+ printf("\tcall\tDos32AllocMem\n");
+ printf("\tadd\tesp,12\n");
+ printf("\tor\teax,eax\n");
+ printf("\tjnz\tNOMEM_%s\n\n",
+ pGlobal_From->pchFunctionName);
+
+ pFrom->fTempAlloc |= ALLOC_MEMORY;/* Eligable for memory */
+ }
+
+ if (iSize >= MEDIUM_ITEM)
+ printf("\nL%u:\n", iCopyLabel);
+ }
+ else {
+ /*
+ * Generate a call to do the allocation. This calls a routine
+ * in the thunk runtime code.
+ */
+ printf("\n;Generate call to allocate ECX bytes\n");
+ printf("\n\tcall\tThk32AllocVarLen\n");
+
+ templabel = gen_LabelCount++;
+
+ printf("\tor\teax,eax\t\t;Test error condition\n");
+ printf("\tjnz\tNOMEM_%s\n\n",
+ pGlobal_From->pchFunctionName);
+
+ printf("\n\tor\tedx,edx\n");
+ printf("\tjb\tshort L%u\t\t;Jump if DosAllocMem\n\n",templabel);
+
+ printf("\tlea\teax,[ebp-%u]\n", iBMPOffset);
+
+ printf("\tor\t%s PTR[eax+edx*4],%lu\t\t;Set alloc flag\n",
+ (pFrom->iPointerNumber >7)?"DWORD":"BYTE",
+ (long) 1 << pFrom->iPointerNumber );
+
+ printf("\nL%u:\n\n", templabel);
+ }
+}
+
+
+/*** cod32_AllocFixedSize(iSize)
+ *
+ * Emits code that allocates a fixed size buffer.
+ *
+ * The rule shall be:
+ * size <= SMALL_ITEM Allocate space on stack
+ * size <= MEDIUM_ITEM Allocate a block from BMP package
+ * size <= LARGE_ITEM Allocate an object using DosAllocMem
+ * size > LARGE_ITEM Error case: Not handled.
+ *
+ * Entry: iSize is length of buffer needed.
+ *
+ * Exit: Code will put address of new buffer in edi.
+ */
+
+cod32_AllocFixedSize(unsigned int iSize,
+ TypeNode *pFrom)
+
+{
+ pFrom->fTempAlloc |= ALLOC_FIXED; /* Always allocates a fixed size item */
+ if (iSize <= SMALL_ITEM) {
+ printf( "; Allocate space on stack\n");
+ printf( "\tsub\tesp,%u\t\t\t;Alloc Mem\n", iSize);
+ printf( "\tand\tesp,0FFFFFFFCh\t\t;DWORD align\n");
+ printf( "\tmov\tedi,esp\t\t\t;Points to new data area\n");
+ printf( "\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
+ printf( "\tmov\tesi,[ebp+%u]\n", pFrom->iOffset);
+ } else if (iSize <= MEDIUM_ITEM) {
+ printf( ";Need block allocation\n");
+ printf( ";Generate Allocation Call\n");
+ //printf("\tcall\tThk32AllocBlock\n");
+ printf( "\tmov\tecx,%u\n", iSize);
+ printf( "\tcall\tAllocBuff\n");
+ //printf("\tor\teax,eax\n");
+ //printf("\tjnz\tNOMEM_%s\n\n", pGlobal_From->pchFunctionName);
+ printf( "\tmov\t[ebp-%u],eax\t\t;16:16 address\n", pFrom->iTempOffset);
+ printf( "\tmov\tedi,edx\t\t;32-bit address\n");
+ printf( "\tmov\tesi,DWORD PTR [ebp+%u]\t\t;parameter\n", pFrom->iOffset);
+ } else {
+ cod_NotHandled( "Very Large Static Buffer Needed");
+ }
+#if 0
+ else if (iSize <= LARGE_ITEM) {
+ printf(";Allocate memory using system call\n\n");
+ printf("\tpush\t%u\t\t;Allocation Flags\n", gDosAllocFlags);
+ printf("\tpush\t%u\t\t;# of bytes to allocate\n", iSize);
+ printf("\tlea\teax,[ebp-%u]\t\t;Buffer for address\n",
+ pFrom->iTempOffset);
+ printf("\tpush\teax\n");
+ printf("\tcall\tDos32AllocMem\n");
+ printf("\tadd\tesp,12\n");
+ printf("\tor\teax,eax\n");
+ printf("\tjnz\tNOMEM_%s\n\n", pGlobal_From->pchFunctionName);
+ printf("\tmov\tedi,[ebp-%u]\n", pFrom->iTempOffset);
+ }
+ else {
+ printf(".err ***** Very Large Static Buffer Needed *****\n\n");
+ fprintf(stderr, "warning: Very Large Static Buffer Needed *****\n\n");
+ }
+#endif
+}
+
+
+/*** cod32_DeAllocFixedSize(iSize)
+ *
+ * Emits code the deallocates a fixed size buffer.
+ *
+ * The rule shall be:
+ * size <= SMALL_ITEM Deallocate space on stack
+ * size <= MEDIUM_ITEM Deallocate a block from BMP package
+ * size <= LARGE_ITEM Deallocate an object using DosAllocMem
+ * size > LARGE_ITEM Error case: Not handled.
+ *
+ * Entry: iSize is length of buffer to deallocate
+ * edi assumed to have address of allocated memory
+ *
+ * Exit: Code will put address of new buffer in edi.
+ */
+
+cod32_DeAllocFixedSize(unsigned int iSize,
+ TypeNode *pFromNode)
+
+{
+ if (iSize <= SMALL_ITEM) {
+ printf("\n;Stack allocated memory deallocated implicitly\n");
+ }
+ else if (iSize <= MEDIUM_ITEM) {
+ printf(";Need block dallocation\n");
+ printf("\tmov\tesi,[ebp-%u]\n", pFromNode->iTempOffset);
+ printf("\tcall\tThk32FreeBlock\n\n");
+ }
+ else if (iSize <= LARGE_ITEM) {
+ printf(";Deallocate memory using system call\n\n");
+ printf("\tpush\tDWORD PTR [ebp-%u]\n", pFromNode->iTempOffset);
+ printf("\tcall\tDos32FreeMem\n");
+ printf("\tadd\tesp,4\n\n");
+ }
+ else {
+ printf(".err ***** Very Large Static Buffer dealloc *****\n\n");
+ fprintf(stderr, "warning: Very Large Static Buffer dealloc *****\n\n");
+ }
+}
+
+
+/*** cod32_CopyConvert(pFrom,pTo)
+ *
+ * This routine generates the copy and conversion code.
+ *
+ * Entry: pFrom and pTo are the typenodes to use.
+ *
+ * Exit: copy/convert code is generated.
+ */
+
+void
+cod32_CopyConvert(TypeNode *pFromNode,
+ TypeNode *pToNode)
+
+{
+ unsigned int iEDI, iESI;
+ unsigned int JumpLabel;
+
+
+ /*
+ * If it is a NULL type, then complete transfer, output a NULL
+ * type error, and realign the data pointers after the NULLTYPES.
+ */
+ if (pFromNode->iBaseType == TYPE_NULLTYPE) {
+ /*
+ * Terminate Transfer Block.
+ */
+ cod32_TransferBlock(gTransferBytes);
+ gTransferBytes = 0;
+
+ printf("\n;%d NULLTYPE(S)\n", pFromNode->iArraySize);
+ printf("\n\t.err **** NULLTYPE ****\n\n");
+ printf("\n\n;Move registers past NULLTYPE\n");
+ cod_AdjustReg("esi", &gESI, pFromNode->iStructOffset + typ_FullSize(pFromNode));
+ cod_AdjustReg("edi", &gEDI, pToNode->iStructOffset + typ_FullSize(pToNode));
+
+ return;
+ }
+
+ /*
+ * If types are equal, then no conversion needed.
+ * If no conversion is needed, then the bytes from the source can be copied
+ * directly to the destination. Therefore, we just collect the bytes into
+ * a 'pseudo buffer'. When we finally reach the point where a conversion
+ * is needed, or we run off the end of the base structure, we will emit
+ * a block copy of the appropriate number of bytes.
+ */
+ if (pToNode->iBaseType == pFromNode->iBaseType) {
+ printf(";Add %u bytes of %s to transfer\n",
+ typ_FullSize(pToNode), pToNode->pchBaseTypeName);
+ gTransferBytes += typ_FullSize(pToNode);
+ return;
+ }
+
+ /*
+ * Here, we have determined that the two types are not compatible.
+ * Therefore, we are going to do a conversion.
+ *
+ * Complete pending transfer.
+ */
+ cod32_TransferBlock(gTransferBytes);
+ gTransferBytes = 0;
+
+ /*
+ * Sanity check: offsets must be correct.
+ */
+ if ((pFromNode->iStructOffset != gESI) ||
+ (pToNode->iStructOffset != gEDI))
+ {
+ fprintf(stderr, "cod_CopyConvert: Incorrect offset\n");
+ printf(".err cod_CopyConvert: Incorrect offset\n");
+ }
+
+ /*
+ * If item is an array, then setup loop.
+ */
+ if (pFromNode->iArraySize > 1) {
+ JumpLabel = gen_LabelCount++;
+ printf("\n\tmov\tecx,%u\n", pFromNode->iArraySize);
+ printf("\nL%u:\n", JumpLabel);
+ }
+
+ /*
+ * Convert for specific types.
+ */
+ switch (pFromNode->iBaseType)
+ {
+ case TYPE_UCHAR: /* USHORT --> ULONG */
+ printf("\n;UCHAR --> ULONG\n\n");
+ printf("\tmovzx\teax,BYTE PTR[esi]\n");
+ printf("\tmov\t[edi],eax\n");
+ break;
+ case TYPE_SHORT: /* SHORT --> LONG */
+ printf("\n;SHORT --> LONG\n\n");
+ printf("\tmovsx\teax,WORD PTR[esi]\n");
+ printf("\tmov\t[edi],eax\n");
+ break;
+ case TYPE_USHORT: /* USHORT --> ULONG */
+ printf("\n;USHORT --> ULONG\n\n");
+ printf("\tmovzx\teax,WORD PTR[esi]\n");
+ printf("\tmov\t[edi],eax\n");
+ break;
+ case TYPE_LONG: /* LONG --> SHORT */
+ printf("\n;LONG --> SHORT\n\n");
+ printf("\tmov\teax,DWORD PTR [esi]\n");
+ printf("\tmov\tWORD PTR [edi],ax\n");
+ break;
+ case TYPE_ULONG: /* ULONG --> USHORT */
+ printf("\n;ULONG --> USHORT\n\n");
+ printf("\tmov\teax,DWORD PTR [esi]\n");
+ if (pGlobal_From->fSemantics & SEMANTIC_TRUNC) {
+ printf("\tcmp\teax,0ffffh\n");
+ printf("\tja\tINVP_%s\n\n", pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ }
+ printf("\tmov\tWORD PTR [edi],ax\n");
+ break;
+ default:
+ fatal("cod32_CopyConvert: Tried converted %d to %d",
+ pFromNode->iBaseType, pToNode->iBaseType);
+ }
+
+ /*
+ * If data types is array, finish off loop.
+ */
+ if (pFromNode->iArraySize > 1) {
+ iESI = gESI;
+ iEDI = gEDI;
+ cod_AdjustReg("esi", &iESI, gESI + pFromNode->iBaseDataSize);
+ cod_AdjustReg("edi", &iEDI, gEDI + pToNode->iBaseDataSize);
+ printf("\tloop\tL%u\n\n", JumpLabel);
+ gESI += typ_FullSize(pFromNode);
+ gEDI += typ_FullSize(pToNode);
+ }
+ else {
+
+ /*
+ * Adjust registers.
+ *
+ * When CopyConvert is done as part of a structure copy, then there
+ * are times when we can skip the adjustment of the registers in
+ * this case. The only other time CopyConvert is called is during
+ * a buffer transfer, in which case we don't really care about the
+ * registers after the copy convert is complete. Therefore, this
+ * code has been commented out, and moved into the RepackElements
+ * routine. This enables the Repack routine to adjust the registers
+ * only when needed.
+ *
+ * The fReAlignmentNeeded flag will indicate to the RepackElements
+ * routine that the current register values are incorrect, and need
+ * to be updated.
+ */
+ fReAlignmentNeeded = 1;
+ }
+}
+
+
+/*** cod32_TransferBlock(Count)
+ *
+ * This routine will emit code for copying Count bytes of data from
+ * the current ESI to the current EDI. ESI and EDI will be adjusted to
+ * the first byte after the copy. This copy routine will produce a
+ * fixed size copy routine that has been optimized for speed.
+ *
+ * Entry: ESI and EDI must be setup to have the source and destination
+ * addresses.
+ * Count is the umber of bytes to copy.
+ *
+ * Exit: gESI and gEDI will be incremented by Count.
+ * Code for copy will be written.
+ *
+ * Note:
+ * If Count is 0, this routine returns without changing anything.
+ */
+
+void
+cod32_TransferBlock(int Count)
+
+{
+ int iRep;
+
+ if (!Count)
+ return;
+
+ printf("\n;Transfer %u bytes\n", Count);
+ iRep = Count / 4;
+ if (iRep > 1) {
+ printf("\n\tmov\tecx,%u\n", iRep);
+ printf("\trep");
+ }
+ if (iRep)
+ printf("\tmovsd\n");
+
+ iRep = Count % 4;
+ if (iRep > 1) {
+ printf("\tmovsw\n");
+ iRep -= 2;
+ }
+ if (iRep)
+ printf("\tmovsb\n");
+ gEDI += Count;
+ gESI += Count;
+}
+
+
+/*** cod32_VariableLengthCopy()
+ *
+ * Emits code for a variable length copy. Assumes that the source address
+ * is loaded into ESI, destination into EDI, and count of bytes into ECX
+ *
+ * Entry: none
+ *
+ * Exit: variable length copy code is generated.
+ */
+
+cod32_VariableLengthCopy()
+
+{
+ if (pGlobal_To->fInlineCode) {
+ printf("\n; Copy ECX bytes from ESI to EDI\n");
+ printf("\tmov\teax,3\n");
+ printf("\tand\teax,ecx\n");
+ printf("\tshr\tecx,2\n");
+ printf("\trep movsd\n");
+ printf("\tmov\tecx,eax\n");
+ printf("\trep movsb\n\n");
+ }
+ else {
+ printf("\n; Copy ECX bytes from ESI to EDI\n");
+ printf("\tcall\tTHK32COPYBLOCK\n");
+ }
+}
+
+
+/*** cod_CallFrame32
+ *
+ * This function prints out the call frame assembly code for the 32-bit
+ * routine.
+ *
+ * Entry: pMNode is the pointer to a MapNode.
+ *
+ * Exit: call frame code is generated.
+ *
+ * History:
+ * 28-Nov-1988 JulieB Created it.
+ */
+
+cod_CallFrame32(MapNode *pMNode)
+
+{
+ int i;
+ TypeNode *pFrom, *pTo;
+ unsigned int uiRetLabel;
+
+
+ pFrom = pMNode->pFromNode->ReturnType;
+ pTo = pMNode->pToNode->ReturnType;
+
+ if (fBPFrame)
+ printf("\n\n;******* Break Point\n\n\tint\t3\n\n\n");
+
+ /*
+ * Save the stack.
+ */
+ printf(";* Create new call frame, using 16-bit semantics.\n\n");
+
+ if( typ_QuerySemanticsUsed( pMNode, SEMANTIC_LOCALHEAP)) {
+ printf( "\n\tpush\tds\t\t\t;16-bit will use local heap\n");
+ }
+
+ /*
+ * If SysCall, then the ToNode follows the System calling convention
+ * of saving ES. Therefore, we can skip the save.
+ */
+ if (!pMNode->pToNode->fSysCall) {
+ printf("\tpush\tes\n");
+ printf("\tpush\tebx\n");
+ }
+
+ printf("\tpush\tebp\t\t\t; save ebp\n");
+ printf("\tmov\teax,esp\t\t\t; save current esp\n");
+ printf("\tpush\tss\n");
+ printf("\tpush\teax\n\n");
+
+ /*
+ * Convert and push all parameters as needed.
+ */
+ //cod_PushParameters32( pMNode->pFromNode->ParamList,
+ // pMNode->pToNode->ParamList);
+ cod32_PushParametersGDI( pMNode->pFromNode->ParamList,
+ pMNode->pToNode->ParamList);
+
+ //if (fCombined) {
+ // printf("\n\t\t\t;Generic Routine: get function number into ecx\n");
+ // printf("\tmov\tecx,[ebp-%u]\n",iCombinedOffset);
+ //}
+
+ /*
+ * Convert SS:ESP to 16-bit SS:SP.
+ */
+ printf("\n;* Convert SS:ESP to 16-bit SS:SP.\n\n");
+#if 0
+ printf("\tmov\tax,WORD PTR STACK16SELECTOR\n");
+ printf("\tpush\tax\n");
+ printf("\tmov\teax,esp\n");
+ printf("\tsub\teax,DWORD PTR STACK16INITIALOFFSET\n");
+ printf("\tpush\teax\n");
+ printf("\tcall\tSETSELECTORBASE32\n\n");
+#endif
+#if 0
+ printf( "\tmov\tbx,WORD PTR STACK16SELECTOR\n");
+ printf( "\tmov\teax,esp\n");
+ printf( "\tsub\teax,DWORD PTR STACK16INITIALOFFSET\n");
+ printf( "\tmov\tecx,eax\n");
+ printf( "\tcall\tSetSelBase32\n\n");
+ //LATER: test for error
+#endif
+
+
+ if (fCombined) {
+ printf( "\tmov\tecx,[ebp-%u]\t;Generic Routine: "
+ "get function number into ecx\n\n", iCombinedOffset);
+ }
+
+ printf( "\tpush\tesp\n");
+ printf( "\tlea\teax,[ebp-%u]\n", iStackThunkIDOffset);
+ printf( "\tpush\teax\t\t\t;address of stack thunk id\n");
+ printf( "\tcall\tGetStack32\n");
+ printf( "\tmov\tedx,eax\n");
+ printf( "\tror\tedx,16\n");
+ printf( "\tmov\tss,dx\n");
+ printf( "\tmov\tsp,ax\n");
+
+#if 0
+ printf("\tmov\tax,WORD PTR STACK16SELECTOR\n");
+ printf("\tpush\tax\n");
+ printf("\tmov\teax,DWORD PTR STACK16INITIALOFFSET\n");
+ printf("\tpush\tax\n");
+ printf("\tlss\tsp,[esp]\n");
+#endif
+
+ if( typ_QuerySemanticsUsed( pMNode, SEMANTIC_LOCALHEAP)) {
+ printf( "\tmov\tds,DS16LOCALHEAPSELECTOR\t\t;ds for local heap\n");
+ }
+
+ if (fBPCall)
+ printf("\n\n;******* Break Point\n\n\tint\t3\n\n\n");
+
+ /*
+ * Jump to 16-bit segment to issue call.
+ */
+ printf("\n;* Jump to 16-bit segment to issue call");
+ printf(" (so that 16-bit API can RETF).\n");
+ printf(";* The following two lines are the same as:\n");
+ printf("; \tjmp\tFAR PTR T_%s\n", pMNode->pToNode->pchFunctionName);
+ printf("; but they trick masm into not generating nops.\n\n");
+ printf("\tdb\t66h,0eah\n");
+ printf("\tdw\toffset T_%s, seg T_%s\n\n",
+ pMNode->pToNode->pchFunctionName, pMNode->pToNode->pchFunctionName);
+
+ if (fCombined) {
+ MapNode *combnode;
+ combnode = pMNode->pFamily;
+ i = 1;
+
+ printf("\n;The following are entry points for routines that");
+ printf("\n;have the same semantics and parameters.\n\n");
+
+ for (;combnode;combnode=combnode->pNextMapping) {
+ printf("%s:\n", combnode->pFromNode->pchFunctionName);
+ //printf("\tpush\t%u\n",i++);
+ //printf("\tpop\teax\n");
+ printf("\tmov\teax,%u\n",i++);
+ printf("\tjmp\tC_%s\n\n", pMNode->pFromNode->pchFunctionName);
+ }
+ }
+
+ uiRetLabel = gen_LabelCount++;
+
+ /*
+ * Only print out the invalid parameter code if it was used.
+ * The fInvalidParam flag is set if the label is needed.
+ */
+ if (pMNode->pFromNode->fInvalidParam) {
+ printf("\nINVP_%s:\n", pMNode->pFromNode->pchFunctionName);
+
+ if (fBPCall)
+ printf("\n\n;******* Break Point\n\n\tint\t3\n\n\n");
+
+ if( pMNode->pFromNode->ulErrBadParam) {
+ printf("\tmov\teax,%lu\n",pMNode->pFromNode->ulErrBadParam);
+ //printf("\tpush\tDWORD PTR %lu\n",pMNode->pFromNode->ulErrBadParam);
+ //printf("\tpop\teax\n");
+ } else {
+ printf("\txor\teax,eax\n");
+ }
+
+ /*
+ * If iErrorOffset is zero, then there was no space allocated for it.
+ * Therefore, only set the error flag if iErrorOffset != 0
+ */
+ if (iErrorOffset)
+ printf("\tmov\tBYTE PTR [ebp-%u],1\t\t;Set flag\n", iErrorOffset);
+
+ printf("\tjmp\tshort L%u\n", uiRetLabel);
+ }
+
+#if 0
+ if (pMNode->pFromNode->iPointerCount) {
+ if (pMNode->pFromNode->fErrUnknown) {
+ printf("\nERR_%s:\n", pMNode->pFromNode->pchFunctionName);
+ printf("\tmov\teax,%lu\n",pMNode->pFromNode->fErrUnknown);
+ printf("\tjmp\tshort L%u\n", gen_LabelCount);
+ }
+
+ printf("\nNOMEM_%s:\n", pMNode->pFromNode->pchFunctionName);
+ if (fBPCall)
+ printf("\n\n;******* Break Point\n\n\tint\t3\n\n\n");
+ printf("\tpush\t%lu\n",pMNode->pFromNode->ulErrNoMem);
+ printf("\tpop\teax\n");
+
+ if (!pMNode->pFromNode->fErrUnknown)
+ printf("\nERR_%s:\n", pMNode->pFromNode->pchFunctionName);
+
+ printf("\tmov\tBYTE PTR [ebp-%u],1\t\t;Set flag\n", iErrorOffset);
+ printf("\tjmp\tshort L%u\n", gen_LabelCount);
+ }
+#endif
+
+ printf("\nR_%s:\t\t\t\t; label defining return jmp location\n",
+ pMNode->pToNode->pchFunctionName);
+
+ if (fBPCall)
+ printf("\n\n;******* Break Point\n\n\tint\t3\n\n\n");
+
+ /*
+ * Restore 32-bit SS:ESP.
+ */
+ printf("\n\n;* Restore 32-bit SS:ESP - it is on top of stack.\n\n");
+ printf("\tmovzx\tebx,sp\t\t\t;esp may have garbage in hi word\n");
+ printf("\tlss\tesp,ss:[ebx]\n");
+ printf("\tpop\tebp\n");
+
+ if (!pMNode->pToNode->fSysCall) {
+ printf("\tpop\tebx\n");
+ printf("\tpop\tes\n\n");
+ }
+
+ if( typ_QuerySemanticsUsed( pMNode, SEMANTIC_LOCALHEAP)) {
+ printf( "\tpop\tds\n");
+ }
+
+ /*
+ * Convert return code into proper value to be returned in EAX.
+ */
+ printf("\n;Convert Return Code\n");
+
+ /*
+ * If the return code is a pointer, then convert the pointer to
+ * 0:32 on the way out.
+ */
+ if (pFrom->iPointerType) {
+ printf(";Return type is a pointer\n");
+ printf(";Convert 16:16 to 0:32\n\n");
+ printf("\trol\teax,16\n");
+ printf("\tmov\tax,dx\n");
+ printf("\trol\teax,16\n");
+ printf("\tcall\tSelToFlat\n");
+ }
+ else {
+ switch (pFrom->iBaseType)
+ {
+ case TYPE_LONG:
+ switch (pTo->iBaseType)
+ {
+ case TYPE_LONG:
+ printf(";LONG --> LONG\n");
+ printf("\trol\teax,16\n");
+ printf("\tmov\tax,dx\n");
+ printf("\trol\teax,16\n");
+ break;
+ case TYPE_SHORT:
+ printf(";SHORT --> LONG\n");
+ printf("\tmovsx\teax,ax\n");
+ break;
+ }
+ break;
+ case TYPE_ULONG:
+ switch (pTo->iBaseType)
+ {
+ case TYPE_ULONG:
+ printf(";ULONG --> ULONG\n");
+ printf("\trol\teax,16\n");
+ printf("\tmov\tax,dx\n");
+ printf("\trol\teax,16\n");
+ break;
+ case TYPE_USHORT:
+ printf(";USHORT --> ULONG\n");
+ printf("\tmovzx\teax,ax\n");
+ break;
+ case TYPE_UCHAR:
+ printf(";UCHAR --> ULONG\n");
+ printf("\tmovzx\teax,al\n");
+ break;
+ }
+ if( pTo->fSemantics & SEMANTIC_LOCALHEAP) {
+ printf( "\tor\teax,eax\n");
+ printf( "\tjz\tL%u\t\t;skip conversion if null\n",
+ uiRetLabel);
+ printf( "\tadd\teax,DS16LOCALHEAPBASE\n");
+ }
+ break;
+ default:
+ printf("\n;Return type maps directly.\n");
+ }
+ }
+ printf("L%u:\n", uiRetLabel);
+
+ if (pMNode->pFromNode->iPointerCount) {
+ printf(";Functions contain pointers, save return code\n");
+ printf("\tmov\t[ebp-%u],eax\t\t;Save return code\n", iReturnValOffset);
+ }
+}
+
+
+/*** cod_PushParameters32
+ *
+ * This function generates the code that pushes the 32-bit parameters
+ * onto the stack.
+ *
+ * Entry: pFromNode - pointer to the 32-bit function's parameter list.
+ * pToNode - pointer to the 16-bit function's parameter list.
+ *
+ * Exit: generates the code that pushes the 32-bit parameters.
+ *
+ * History:
+ * 29-Nov-1988 JulieB Created it.
+ */
+
+cod_PushParameters32(TypeNode *pFromNode,
+ TypeNode *pToNode)
+
+{
+ int iStackOffset = DWORD_SIZE; /* offset to temp storage on stack */
+ unsigned int AllowLabel;
+ int fRestricted;
+
+
+ /*
+ * For each parameter, convert and push as needed.
+ */
+ while (pFromNode) {
+ fRestricted = (pFromNode->fSemantics & SEMANTIC_RESTRICT);
+
+ printf("\n\n\t;From Name: %s Type: %s\n",
+ typ_NonNull(pFromNode->pchIdent),
+ typ_NonNull(pFromNode->pchBaseTypeName));
+ if (pFromNode->iBaseType == TYPE_NULLTYPE)
+ printf("\n\t.err **** NULLTYPE ****\n\n");
+
+ else if (pFromNode->iDeleted) {
+
+ /* If the iDeleted flag is set in the pFromNode, then this
+ * parameter does not exist in the original call frame.
+ * Therefore, we need to push a zero of the appropriate length.
+ */
+ printf("\n;Extra parameter needed: Push a zero\n");
+
+ switch (pToNode->iBaseType)
+ {
+ case TYPE_UCHAR:
+ printf("\tpush\tBYTE PTR %u\t\t;Push u/byte\n",
+ pFromNode->iFillValue);
+ break;
+
+ case TYPE_SHORT:
+ case TYPE_USHORT:
+ printf("\tpush\tWORD PTR %u\t\t;Push u/short\n",
+ pFromNode->iFillValue);
+ break;
+
+ case TYPE_LONG:
+ case TYPE_ULONG:
+ printf("\tpush\t%u\t\t;Push U/LONG\n",
+ pFromNode->iFillValue);
+ break;
+
+ default:
+ fprintf(stderr, "\nInvalid type for DELETED\n");
+ printf("\n.err Invalid type for DELETED\n");
+ }
+ }
+ else if (pToNode->iDeleted) {
+ printf("\n;Parameter not needed in callee\n");
+
+ if (fRestricted)
+ cod32_HandleRestricted(pFromNode);
+ }
+ else {
+ switch (pFromNode->iPointerType)
+ {
+ case TYPE_NEAR32:
+ if (pToNode->iPointerType == TYPE_FAR16) {
+ printf("\tmov\teax,DWORD PTR [ebp-%u]\n",
+ pFromNode->iTempOffset);
+ printf("\tor\teax,eax\n");
+ printf("\tjz\tshort L%u\t\t\t;NULL pointer\n\n",
+ gen_LabelCount);
+ printf("\tror\teax,16\t\t\t; CRMA on structure pointer\n");
+ printf("\tshl\tax,3\n");
+ printf("\tor\tal,dl\n");
+ printf("\trol\teax,16\n");
+ printf("L%u:\tpush\teax\n\n", gen_LabelCount++);
+ }
+ else
+ printf("\tpush\tDWORD PTR [ebp-%u]\n", pFromNode->iTempOffset);
+ break;
+
+ case TYPE_FAR16:
+ if (pToNode->iPointerType == TYPE_NEAR32) {
+ printf("\tmov\teax,DWORD PTR [ebp-%u]\n",
+ pFromNode->iTempOffset);
+ printf("\tor\teax,eax\n");
+ printf("\tjz\tshort L%u\t\t\t;NULL pointer\n\n",
+ gen_LabelCount);
+ printf("\tror\teax,16\t\t\t; CRMA on structure pointer\n");
+ printf("\tshr\tax,3\n");
+ printf("\trol\teax,16\n");
+ printf("L%u:\tpush\teax\n\n", gen_LabelCount++);
+ }
+ else
+ printf("\tpush\tDWORD PTR [ebp-%u]\n", pFromNode->iTempOffset);
+ break;
+
+ /* If it wasn't one of the pointer types above, then it must
+ * be a non pointer parameter. Thus, it will be a long,
+ * short, ulong, ushort, or char.
+ */
+ default:
+
+ /* If types are equal, then no conversion needed.
+ * If no conversion is needed, then just push the item
+ * onto new call frame. If conversion is needed, then
+ * use switch statement to emit the correct conversion.
+ */
+ if (pToNode->iBaseType == pFromNode->iBaseType) {
+ if (pFromNode->iBaseDataSize <= WORD_SIZE) {
+ if (fRestricted) {
+ printf("\tmovzx\teax,WORD PTR [ebp+%u]\t; To: %s\n",
+ pFromNode->iOffset, pToNode->pchBaseTypeName);
+ cod32_HandleRestricted(pFromNode);
+ printf("\n\tpush\tax\n");
+ } else {
+ printf("\tpush\tWORD PTR [ebp+%u]\t; To: %s\n",
+ pFromNode->iOffset, pToNode->pchBaseTypeName);
+ }
+ }
+ else {
+ if (fRestricted) {
+ printf("\tmov\teax,[ebp+%u]\t; To: %s\n",
+ pFromNode->iOffset, pToNode->pchBaseTypeName);
+ cod32_HandleRestricted(pFromNode);
+ printf("\n\tpush\teax\n");
+ }
+ else {
+ printf("\tpush\tDWORD PTR [ebp+%u]\t; To: %s\n",
+ pFromNode->iOffset, pToNode->pchBaseTypeName);
+ }
+ }
+ }
+ else {
+ switch (pFromNode->iBaseType)
+ {
+ case TYPE_UCHAR: /* UCHAR --> ULONG */
+ printf("\tmovzx\teax,BYTE PTR[ebp+%u]\t;",
+ pFromNode->iOffset);
+ cod32_HandleRestricted(pFromNode);
+ printf("To: %s\n", pToNode->pchBaseTypeName);
+ printf("\tpush\teax\n");
+ break;
+ case TYPE_SHORT: /* SHORT --> LONG */
+ printf("\tmovsx\teax,WORD PTR[ebp+%u]\t;",
+ pFromNode->iOffset);
+ cod32_HandleRestricted(pFromNode);
+ printf("To: %s\n", pToNode->pchBaseTypeName);
+ printf("\tpush\teax\n");
+ break;
+ case TYPE_USHORT: /* USHORT --> ULONG */
+ printf("\tmovzx\teax,WORD PTR[ebp+%u]\t;",
+ pFromNode->iOffset);
+ cod32_HandleRestricted(pFromNode);
+ printf("To: %s\n", pToNode->pchBaseTypeName);
+ printf("\tpush\teax\n");
+ break;
+ case TYPE_LONG: /* LONG --> SHORT */
+ printf("\tmov\teax,[ebp+%u]\n", pFromNode->iOffset);
+
+ if (fRestricted) {
+ cod32_HandleRestricted(pFromNode);
+ }
+ else {
+ if (pGlobal_From->fSemantics & SEMANTIC_TRUNC) {
+ if (pFromNode->AllowList) {
+ AllowLabel = gen_LabelCount++;
+ cod32_HandleAllowList(pFromNode->AllowList,
+ AllowLabel);
+ }
+ printf("\tmovsx\tecx,ax\n");
+ printf("\tcmp\teax,ecx\n");
+ printf("\tjne\tINVP_%s\t\t;\n\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ if (pFromNode->AllowList)
+ printf("L%u:",AllowLabel);
+ }
+ }
+ printf("\tpush\tax\t;To:%s\n",pToNode->pchBaseTypeName);
+ break;
+
+ case TYPE_ULONG: /* ULONG --> USHORT */
+ printf("\tmov\teax,[ebp+%u]\n", pFromNode->iOffset);
+
+ if (fRestricted) {
+ cod32_HandleRestricted(pFromNode);
+ }
+ else {
+ if (pGlobal_From->fSemantics & SEMANTIC_TRUNC) {
+ if (pFromNode->AllowList) {
+ AllowLabel = gen_LabelCount++;
+ cod32_HandleAllowList(pFromNode->AllowList,
+ AllowLabel);
+ }
+
+ printf("\tcmp\teax,0ffffh\n");
+ printf("\tja\tINVP_%s\n\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ if (pFromNode->AllowList)
+ printf("L%u:",AllowLabel);
+ }
+ }
+ printf("\tpush\tax\t\t;To:%s\n",pToNode->pchBaseTypeName);
+ break;
+ default:
+ fatal("cod_PushParameters32: Tried converted %d to %d",
+ pFromNode->iBaseType, pToNode->iBaseType);
+ }
+ }
+ }
+ }
+ pToNode = pToNode->pNextNode;
+ pFromNode = pFromNode->pNextNode;
+ }
+}
+
+
+/*** cod_Return32
+ *
+ * This function prints out the return assembly code for the 32-bit
+ * routine.
+ *
+ * Entry: pMNode is the pointer to a MapNode.
+ *
+ * Exit: 32-bit routine code is generated.
+ *
+ * History:
+ * 28-Nov-1988 JulieB Created it.
+ */
+
+cod_Return32(MapNode *pMNode)
+
+{
+ /*
+ * Exit the routine.
+ */
+ printf(";* 32-bit return code.\n\n");
+
+ if (fBPExit)
+ printf("\n\n;******* Break Point\n\n\tint\t3\n\n\n");
+
+ if (pMNode->pFromNode->iPointerCount) {
+ printf("\tlea\tesp,[ebp-%u]\n", iSavedRegOffset);
+ printf("\tpop\tedi\n");
+ printf("\tpop\tesi\n");
+ printf("\tpop\teax\t\t\t;Pop saved return code\n");
+ }
+
+ printf("\tleave\t\t\t\t; Remove local variables\n\n");
+
+#if 0
+ printf( "\txor\tedx,edx\n");
+ printf( "\txchg\tedx,%s\t\t;release semaphore\n", pszGDISemName);
+ printf( "SEMEXIT_%s:\n\n", pMNode->pFromNode->pchFunctionName);
+#endif
+ printf( "\tret\t%d\t\t\t; Remove parameters\n\n",
+ cod_CountParameterBytes( pMNode->pFromNode->ParamList, DWORD_SIZE));
+
+ printf("%s endp\n\n", pMNode->pFromNode->pchFunctionName);
+ printf("%s\tENDS\n\n",CODE32_NAME);
+}
+
+
+/*** cod_CallStub32
+ *
+ * This function prints out the code16 segment assembly code stub for
+ * the 32-bit routine. This is the part of the assembly code that
+ * actually makes the call to the real function.
+ *
+ * Entry: pMNode is the pointer to a MapNode.
+ *
+ * Exit: call stub code is generated.
+ *
+ * History:
+ * 28-Nov-1988 JulieB Created it.
+ */
+
+cod_CallStub32(MapNode *pMNode)
+
+{
+ unsigned int iJumpTarget;
+ MapNode *Diver;
+
+
+ printf(";* 16-bit code to make API call.\n\n");
+ printf("%s\tSEGMENT\n\n",CODE16_NAME);
+ printf("\tASSUME CS:%s\n",CODE16_NAME);
+ printf("\t.errnz ($ - T_%s)\n\n", pMNode->pToNode->pchFunctionName,
+ pMNode->pToNode->pchFunctionName);
+
+ if (fCombined) {
+ iJumpTarget = gen_LabelCount++;
+ printf("\n\n;Target is at L%u + (cx * 4)\n",iJumpTarget);
+ printf("\n\tmov\tdx,offset L%u\n",iJumpTarget);
+ printf("\tmovzx\tedx,dx\n");
+ printf("\n\tlea\tedx,[edx+(ecx*4)]\n");
+ printf("\tcall\tDWORD PTR CS:[EDX]\n");
+ printf("\tjmp\tFAR PTR FLAT:R_%s\t\t; jump back\n\n",
+ pMNode->pToNode->pchFunctionName);
+
+ printf("\nL%u:\n",iJumpTarget);
+ printf("\n\n;Jump table for thunk routine\n");
+ printf("\tdw\tOFFSET %s\n",pMNode->pToNode->pchFunctionName);
+ printf("\tdw\tSEG %s\n",pMNode->pToNode->pchFunctionName);
+
+ Diver = pMNode->pFamily;
+
+ for (;Diver;Diver=Diver->pNextMapping) {
+ printf("\tdw\tOFFSET %s\n",Diver->pToNode->pchFunctionName);
+ printf("\tdw\tSEG %s\n",Diver->pToNode->pchFunctionName);
+ }
+ }
+ else {
+ printf("\tcall\tFAR PTR %s\t\t; call 16-bit version\n",
+ pMNode->pToNode->pchFunctionName);
+ printf("\tjmp\tFAR PTR FLAT:R_%s\t\t; jump back\n\n",
+ pMNode->pToNode->pchFunctionName);
+ }
+ printf("%s\tENDS\n\n",CODE16_NAME);
+}
diff --git a/private/os2/client/thunk/thunkcom/cod3216.h b/private/os2/client/thunk/thunkcom/cod3216.h
new file mode 100644
index 000000000..44ff54671
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/cod3216.h
@@ -0,0 +1,20 @@
+/* SCCSID = @(#)cod3216.h 13.7 90/08/28 */
+
+/*
+ * Thunk Compiler Code Generator 32->16 Definitions
+ *
+ * Copyright (c) 1988 Microsoft Corp. All rights reserved.
+ */
+
+
+
+#define FRNODE(x) x->pFromNode
+#define TONODE(x) x->pToNode
+
+#define DEFAULT_STRING_SIZE (0x10000 - 1)
+#define DEFAULT_BUFFER_SIZE (0x10000 - 1)
+
+
+/* cod_Movable is true when any flag besides the alias is set */
+
+#define cod_Moveable(type) (type->fSemantics & (ALLOC_ALL & ~ALLOC_ALIAS))
diff --git a/private/os2/client/thunk/thunkcom/cod3216b.c b/private/os2/client/thunk/thunkcom/cod3216b.c
new file mode 100644
index 000000000..03e7c0a3b
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/cod3216b.c
@@ -0,0 +1,1015 @@
+#define SCCSID "@(#)cod3216b.c 13.21 90/08/28"
+
+/*
+ * Thunk Compiler - Routines for Dealing with Types.
+ *
+ * This is a Win32 specific file
+ * Microsoft Confidential
+ *
+ * Copyright (c) Microsoft Corporation 1987, 1988, 1989, 1990
+ *
+ * All Rights Reserved
+ *
+ * Written 12/03/88 by Kevin Ross for OS/2 2.x
+ * 11.06.90 Kevin Ruddell adapted to Win32
+ */
+
+
+#include <stdio.h>
+#include "error.h"
+#include "thunk.h"
+#include "types.h"
+#include "symtab.h"
+#include "codegen.h"
+#include "cod3216.h"
+
+
+unsigned int fgOutputFlag = 0;
+
+unsigned int gEDI,gESI;
+unsigned int iTransferBytes = 0;
+
+extern int fReAlignmentNeeded;
+
+extern void cod32_UnHandleBoundaryCross(unsigned int, TypeNode *, unsigned int);
+extern void cod32_UnHandleFixedSize(unsigned int,TypeNode *);
+
+
+/*** cod_UnpackStruct32(pMNode)
+ *
+ * This function will unwind any pointer manipulation done to make
+ * the call.
+ *
+ * Entry: pMNode - pointer to a MapNode.
+ *
+ * Exit: generates code to unpack structures.
+ *
+ * History:
+ * 28-Nov-1988 JulieB Created it.
+ */
+
+cod_UnpackStruct32(MapNode *pMNode)
+
+{
+ unsigned int NullLabel;
+ TypeNode *pFromList, *pToList;
+
+
+ printf("\n; ****> BEGIN Pointer/Structure Unpack Section\n\n");
+ pFromList = pMNode->pFromNode->ParamList;
+ pToList = pMNode->pToNode->ParamList;
+
+ while (pFromList && pToList) {
+ if (pFromList->iPointerType) {
+ fgOutputFlag = pFromList->fSemantics & SEMANTIC_OUTPUT;
+
+ printf("\n;Undo Pointer %s --> %s\n",
+ typ_NonNull(pFromList->pchIdent),typ_NonNull(pToList->pchIdent));
+
+ /*
+ * Load source address into esi.
+ */
+ printf("\n\n\tmov\tesi,[ebp-%u]\t\t;%s temp address\n",
+ pFromList->iTempOffset,typ_NonNull(pFromList->pchIdent));
+ printf("\tor\tesi,esi\n");
+ printf("\tjz\tL%u\n\n",NullLabel=gen_LabelCount++);
+
+ /*
+ * Load destination address into edi.
+ */
+ printf("\n\n\tmov\tedi,[ebp+%u]\t\t;%s original address\n",
+ pFromList->iOffset,typ_NonNull(pFromList->pchIdent));
+
+ cod32_UnHandlePointer(pFromList,pToList);
+ printf("\nL%u:\t\t;No action required\n",NullLabel);
+ }
+ pFromList = pFromList->pNextNode;
+ pToList = pToList->pNextNode;
+ }
+ printf("\n; ****> END Pointer/Structure Unpack Section\n\n");
+}
+
+
+/*** cod32_UnHandlePointer(pFrom, pTo)
+ *
+ * This function generates code for unhandling the pointers.
+ *
+ * Entry: pFrom and pTo are the type nodes.
+ *
+ * Exit: unhandle pointer code is generated.
+ */
+
+int cod32_UnHandlePointer(TypeNode *pFrom,
+ TypeNode *pTo)
+
+{
+ int iItemSize = -1;
+ TypeNode *pSizeP;
+ unsigned int NullLabel;
+ unsigned int ErrorLabel;
+ unsigned int AliasedLabel;
+ unsigned int JumpLabel;
+ unsigned int SizeOkLabel;
+ unsigned int iTemp1, iTemp2;
+
+
+ iTemp1 = typ_TypeIdentical(pFrom,pTo);
+ iTemp2 = cod_CountPointerParameters(pFrom->pStructElems,FALSE);
+
+ if (pFrom->iBaseType == TYPE_STRUCT) {
+ printf("\n;Structures %s Identical\n",(iTemp1)?"are":"are not");
+ printf(";Structures %s pointers\n",(iTemp2)?"have":"don't have");
+ printf(";Structure %s output semantics\n",
+ (fgOutputFlag)?"has":"doesn't have");
+ }
+
+ if ((pFrom->iBaseType == TYPE_STRUCT) && (!iTemp1 || iTemp2)) {
+ if (pFrom->pSizeParam)
+ cod32_UnHandleStructureBuffer(pFrom,pTo);
+ else
+ cod32_UnStructureRepack(pFrom, pTo);
+ }
+ else if (pFrom->iBaseType != pTo->iBaseType) {
+ /*
+ * If there is no size parameter, then we are passing a long or a
+ * short. If the conversion is LONG to SHORT, then we can just use
+ * the existing long value as the buffer for the short. We will
+ * need to insure that the copy out routine correctly extends the
+ * value.
+ */
+ if ((pFrom->pSizeParam) || (pFrom->iArraySize > 1) ||
+ (pFrom->iBaseDataSize < pTo->iBaseDataSize))
+ cod32_UnCopyConvertBuffer(pFrom,pTo);
+ else {
+ printf("\n;This item is either on the stack, or is still\n");
+ printf(";in its original position.\n");
+
+ if (pFrom->fSemantics & SEMANTIC_OUTPUT) {
+ printf(";Output semantics convert in place\n\n");
+ switch(pFrom->iBaseType)
+ {
+ case TYPE_ULONG:
+ printf("\tmovzx\teax,WORD PTR[esi]\n");
+ printf("\tmov\t[edi],eax\n");
+ break;
+ case TYPE_LONG:
+ printf("\tmovsx\teax,WORD PTR[esi]\n");
+ printf("\tmov\t[edi],eax\n");
+ break;
+ default:
+ fatal("cod32_UnHandlePointer: Type assertion failed");
+ }
+ }
+
+ }
+ }
+ else {
+ /*
+ * If not a structure, or structure requires no repacking, then
+ * consider all other instances of pointers as buffers. If a
+ * pointer type has a Size Parameter, which is defined in a
+ * semantic block, then the size parameter will either be the
+ * size in bytes, or a count of the number items. If it is the
+ * count, then the size will be determined by multiplying the
+ * count by the size of the item.
+ */
+ if (pFrom->iBaseType == TYPE_STRUCT)
+ printf(";Treat structure same as buffer\n");
+ printf(";Types are identical and no imbedded pointers exist\n");
+ printf(";This means that we treated the pointer as a buffer\n");
+ printf(";If temp address == original address then no work required\n");
+ printf("\tcmp\tesi,edi\n");
+ printf("\tje\tL%u\n",gen_LabelCount-1);
+
+ if (pSizeP = pFrom->pSizeParam) {
+ if (fgOutputFlag) {
+ ErrorLabel = gen_LabelCount++;
+ printf("\n\ttest\tBYTE PTR[ebp-%u],1\t\t;Check for errors A\n",
+ iErrorOffset);
+ printf("\tjnz\tL%u\t\t\t;No copy if error\n",ErrorLabel);
+ printf("\n;Get size for copy out\n");
+
+ if (pSizeP->iPointerType) {
+ /*
+ * The original size parameter pointer is not null. This
+ * is implicit in the fact that the address of the
+ * temporary pointer is different than the original
+ * pointer. This also implies that the original size
+ * is non zero.
+ */
+ printf("\n;Size was referenced by a pointer.\n");
+ printf(";Since only shorts/longs are used as sizeof\n");
+ printf(";parameters, the space allocated for the temporary\n");
+ printf(";location is on the stack. It still exists, so it\n");
+ printf(";is still safe to use the temporary pointer\n\n");
+ printf("\tmov\tecx,[ebp-%u]\t\t;Get Size Pointer\n",
+ pSizeP->iTempOffset);
+
+ if (pSizeP->iBaseDataSize == WORD_SIZE)
+ printf("\tmovzx\tecx,WORD PTR [ecx]\t\t;Get Size\n");
+ else
+ printf("\tmov\tecx,[ecx]\t\t;Get Size\n");
+ }
+ else
+ printf("\tmov\tecx,[ebp+%u]\t\t;Get Size \n",
+ pSizeP->iOffset);
+
+ if (pSizeP->fSemantics & SEMANTIC_SIZE)
+ printf(";ECX holds size in bytes\n");
+ else if (pSizeP->fSemantics & SEMANTIC_COUNT) {
+ printf(";ECX holds count of items\n");
+ printf("\tmov\teax,%d\t\t;Size of target data type\n",
+ typ_FullSize(pFrom));
+ printf("\tmul\tcx\n");
+ printf("\tmovzx\tecx,ax\n\n");
+ }
+ else
+ fatal("Internal Error: Size semantic not sizeof or countof");
+ }
+ /*
+ * Do a deallocate for variable sized data.
+ */
+ cod32_UnHandleBoundaryCross(SIZE_VARIABLE,pFrom,0);
+ if (fgOutputFlag)
+ printf("\n\nL%u:\t\t\t;ErrorLabel A\n",ErrorLabel);
+ }
+ else {
+ /*
+ * No size parameter, assume fixed size parameter.
+ */
+ switch(pFrom->iBaseType)
+ {
+ case TYPE_STRING:
+ printf(";Handle String Parameters\n");
+ printf(";Strings are never copied out\n");
+
+ /*
+ * Ensure that we don't try to copy out a string.
+ */
+ iTemp1 = fgOutputFlag;
+ fgOutputFlag = FALSE;
+
+ cod32_UnHandleBoundaryCross(SIZE_VARIABLE,pFrom,0);
+
+ fgOutputFlag = iTemp1;
+ break;
+ default:
+ /*
+ * Static size.
+ */
+ printf("\n;Item is fixed size\n");
+ cod32_UnHandleBoundaryCross(SIZE_FIXED,pFrom,typ_FullSize(pFrom));
+ }
+ }
+ }
+}
+
+
+/*** cod32_HandleStructureBuffer(pFrom,pTo)
+ *
+ * This routine handles a buffer full of structures. The buffer has a
+ * variable length size which is given by either a sizeof semantic or
+ * by a countof semantic. This routine will convert the structure.
+ *
+ * This routine is only called when the structures are not identical,
+ * and therefore the buffer needs conversion.
+ *
+ * Entry: pFrom and pTo are the type nodes.
+ *
+ * Exit: structure is converted.
+ */
+
+cod32_UnHandleStructureBuffer(TypeNode *pFrom,
+ TypeNode *pTo)
+
+{
+ TypeNode *pSizeP;
+ FixupRec *pFixupList = NULL;
+ unsigned int NullLabel;
+ unsigned int LoopLabel;
+ unsigned int iESI,iEDI;
+
+
+ iESI = gESI = 0;
+ iEDI = gEDI = 0;
+
+ pSizeP = pFrom->pSizeParam;
+
+ if (pFrom->fSemantics & SEMANTIC_OUTPUT) {
+ /*
+ * At this point, we know that the previous label handles the case
+ * where the buffer was empty (or pointer was NULL).
+ * Therefore, if we set out NullLabel to current -1, we get the
+ * correct fixup.
+ */
+ NullLabel = gen_LabelCount - 1;
+
+ printf("\n;Parameter has size semantics. This is a buffer of structs.\n");
+ printf(";If temp address == original address then no work required\n");
+ printf("\tcmp\tesi,edi\t\t\t;if temp address == original address\n");
+ printf("\tje\tL%u\t\t\t; skip deallocation\n",NullLabel);
+
+ /*
+ * The fact that we are in this routine means that there is a size
+ * parameter. Now the job is to figure out what type of size
+ * parameter it is, and calculate the appropriate buffer size.
+ */
+ printf("\tmov\teax,[ebp+%u]\t\t;Get Size Parameter\n", pSizeP->iOffset);
+
+ if (pSizeP->iPointerType)
+ printf("\n;Check for NULL pointer\n");
+
+ printf("\tor\teax,eax\n");
+ printf("\tjz\tL%u\t\t;Nothing to check\n", NullLabel);
+
+ if (pSizeP->iPointerType) {
+ printf("\t\t\t\t;eax has pointer to size\n");
+ if (pSizeP->iBaseDataSize == WORD_SIZE)
+ printf("\tmovzx\teax,WORD PTR [eax]\t\t;Get Size\n");
+ else
+ printf("\tmov\teax,[eax]\t\t;Get Size\n");
+ printf("\tor\teax,eax\n");
+ printf("\tjz\tL%u\t\t;Nothing to check\n", NullLabel);
+ }
+
+ if (pSizeP->fSemantics & SEMANTIC_SIZE) {
+ printf(";EAX holds size in bytes\n");
+ printf(";We need to figure out the number of structures\n");
+ printf(";that will fit\n");
+ printf("\txor\tedx,edx\n");
+ printf("\tmov\tecx,%u\t\t;Source struct size\n",typ_FullSize(pFrom));
+ printf("\tdiv\tecx\n");
+ }
+ else if (pSizeP->fSemantics & SEMANTIC_COUNT)
+ printf(";EAX holds count of items\n");
+ else
+ fatal("cod32_UnHandleStructureBuffer: Size semantic not sizeof|countof");
+
+ printf("\n\tmov\tecx,eax\t\t;Move count into ecx\n");
+
+ /*
+ * At this point, we know the following facts:
+ * 1 - The structures in this buffer contain no pointers
+ * and therefore will require no internal fixups.
+ * 2 - ESI holds the source address, EDI holds the destination.
+ * 3 - ECX holds the count of structures to be converted.
+ */
+
+ gTransferBytes = 0;
+
+ LoopLabel = gen_LabelCount++;
+ printf("\n;Array of structures\n");
+ printf("\nL%u:\n", LoopLabel);
+ printf("\tpush\tecx\t\t;Save array count\n");
+
+ cod32_UnRepackElements(pFrom,pTo, pFrom->pStructElems,
+ pTo->pStructElems, &pFixupList);
+
+ iESI = gESI;
+ iEDI = gEDI;
+
+ cod_AdjustReg("edi", &iEDI, pFrom->iStructOffset + pFrom->iBaseDataSize);
+ cod_AdjustReg("esi", &iESI, pTo->iStructOffset + pTo->iBaseDataSize);
+
+ printf("\n\tpop\tecx\t\t;Restore array count\n");
+ printf("\n\tloop\tL%u\n", LoopLabel);
+ gEDI = pFrom->iStructOffset + typ_FullSize(pFrom);
+ gESI = pTo->iStructOffset + typ_FullSize(pTo);
+
+ printf("\n\tmov\tesi,[ebp-%u]\n",pFrom->iTempOffset);
+ }
+ printf("\tpush\t%d\t\t;Alloc Flag Offset\n", - iAliasOffset);
+ printf("\tmov\tedx,%lu\n",(long)1<<pFrom->iPointerNumber);
+ printf("\n\tcall\tTHK32DEALLOC\n\n");
+}
+
+
+/*** cod32_UnHandleBoundaryCross(fSize,pFrom,iSize)
+ *
+ * Emits code to unhandle boundary crossing of pFrom.
+ *
+ * Entry: fSize - either SIZE_FIXED or SIZE_VARIABLE.
+ * pFrom - typenode for From pointer.
+ * iSize - size of item with SIZE_FIXED, or maximum length of
+ * item when SIZE_VARIABLE.
+ *
+ * Exit: unhandle boundary crossing code is generated.
+ */
+
+extern unsigned int iCopyLabel;
+extern unsigned int iNoCopyLabel,iNextSize;
+
+void
+cod32_UnHandleBoundaryCross(unsigned int fSize,
+ TypeNode *pFrom,
+ unsigned int iSize)
+
+{
+ unsigned int DoneLabel, AliasedLabel;
+
+
+ AliasedLabel = gen_LabelCount++;
+ DoneLabel = gen_LabelCount++;
+ iCopyLabel = gen_LabelCount++;
+
+ /*
+ * If iSize = 0, then assume largest possible size.
+ */
+ if (iSize == 0)
+ iSize = iSize - 1;
+
+ if (fSize == SIZE_FIXED) {
+ cod32_UnHandleFixedSize(iSize,pFrom);
+ return;
+ }
+ else {
+ if (fgOutputFlag) {
+ if (iSize > (unsigned short) MEDIUM_ITEM) {
+ printf("\n;If aliased, then skip over possible copyout\n");
+ printf("\ttest\t%s PTR[ebp-%u],%lu\t\t;Test Alias Flag\n",
+ (pFrom->iPointerNumber >7)?"DWORD":"BYTE",
+ iAliasOffset, (long) 1 << pFrom->iPointerNumber);
+ printf("\tjnz\tL%u",AliasedLabel);
+ }
+ printf("\n;Copy out ecx bytes\n");
+ printf("\tpush\tesi\t\t;Save ptr to temp object\n");
+ cod32_VariableLengthCopy();
+ printf("\tpop\tesi\t\t;Get ptr to temp object\n");
+ }
+ if (iSize == 0) /* Make iSize huge */
+ iSize--;
+
+ if (pGlobal_To->fInlineCode) {
+ printf("\ttest\t%s PTR[ebp-%u],%lu\t\t;Test Stack Alloc Flag\n",
+ (pFrom->iPointerNumber >7)?"DWORD":"BYTE",
+ iAllocOffset, (long) 1 << pFrom->iPointerNumber);
+ printf("\n; DeAllocate space on stack: Done implicitly\n");
+ printf("\tjnz\tL%u\n\n",DoneLabel);
+
+ if (iSize >= MEDIUM_ITEM) {
+ printf("\ttest\t%s PTR [ebp-%u],%lu\t\t;Test BMP Flag\n",
+ (pFrom->iPointerNumber >7)?"DWORD":"BYTE",
+ iBMPOffset,(long) 1 << pFrom->iPointerNumber);
+
+ if (iSize >= LARGE_ITEM) {
+ iNextSize=gen_LabelCount++;
+ printf("\tjz\tL%u\n\n",iNextSize);
+ }
+ else
+ printf("\tjz\tL%u\n\n",DoneLabel);
+
+ printf("; DeAllocate space in BMP area\n");
+ printf("; ESI holds address of block\n");
+ printf("\tcall\tThk32FreeBlock\n");
+
+ if (iSize >= LARGE_ITEM)
+ printf("\tjmp\tL%u\n\n",DoneLabel);
+ }
+ /*
+ * The operation of freeing a linear alias is the same as
+ * freeing a large buffer allocated for a huge (> 60k) copy.
+ */
+ if (iSize >= LARGE_ITEM) {
+ if (fgOutputFlag)
+ printf("L%u:\t\t\t;Aliased Label\n",AliasedLabel);
+
+ printf("L%u:\n",iNextSize);
+ printf(";Free Linear Alias/ Large Buffer \n");
+ printf("\tcall\tThk32FreeAlias\n");
+ }
+ printf("\nL%u:\t\t;Deallocation Done Label\n\n",DoneLabel);
+ }
+ else {
+ if (fgOutputFlag && (iSize > (unsigned short) MEDIUM_ITEM))
+ printf("L%u:\t\t\t;Aliased Label\n",AliasedLabel);
+
+ printf("\tpush\t%d\t\t;Alloc Flag Offset\n", - iAliasOffset);
+ printf("\tmov\tedx,%lu\n",(long)1<<pFrom->iPointerNumber);
+ printf("\n\tcall\tTHK32DEALLOC\n\n");
+ }
+ }
+}
+
+
+/*** cod32_UnHandleFixedSize(iSize,pFrom)
+ *
+ * This worker routine to HandleBoundaryCrossing will output code
+ * to handle fixed size items that cross boundaries.
+ *
+ * Entry: iSize - fixed size of item.
+ * pFrom - pointer to type node.
+ *
+ * Exit: generates code for fixed size item boundary crossing.
+ */
+
+void
+cod32_UnHandleFixedSize(unsigned int iSize,
+ TypeNode *pFrom)
+
+{
+ unsigned int ErrorLabel;
+
+
+ if (fgOutputFlag) {
+ ErrorLabel = gen_LabelCount++;
+ printf("\n\ttest\tBYTE PTR[ebp-%u],1\t\t;Check for errors C\n",iErrorOffset);
+ printf("\tjnz\tL%u\t\t\t;No copy if error\n",ErrorLabel);
+ }
+
+ if (! iSize)
+ fatal("cod32_UnHandleFixedSize: iSize = 0 \n");
+
+ if ((iSize <= SMALL_ITEM) && fgOutputFlag) {
+ printf("\n;Space was allocated on stack\n");
+ cod32_TransferBlock(iSize);
+ }
+ else if (fgOutputFlag && (iSize <= MEDIUM_ITEM)) {
+ printf("\n;Copy out ecx bytes\n");
+ printf("\tpush\tesi\t\t;Save ptr to temp object\n");
+ cod32_TransferBlock(iSize);
+ printf("\tpop\tesi\t\t;Get ptr to temp object\n");
+ }
+
+ if (fgOutputFlag)
+ printf("\nL%u:\t\t\t;ErrorLabel C\n",ErrorLabel);
+
+ if (iSize <= SMALL_ITEM)
+ printf(";stack deallocated implicitly\n");
+ else if(iSize <= MEDIUM_ITEM) {
+ printf("; DeAllocate space in BMP area\n");
+ printf("; ESI holds address of block\n");
+ printf("\tcall\tThk32FreeBlock\n");
+ }
+ else if (iSize <= LARGE_ITEM) {
+ printf(";Free Linear Alias\n");
+ printf("; ESI holds address of block\n");
+ printf("\tcall\tThk32FreeAlias\n");
+ return;
+ }
+ else {
+ fprintf(stderr,"Fixed sized item > 60k\n");
+ printf(".err Fixed sized item > 60k\n");
+ }
+}
+
+
+/*** cod32_UnStructureRepack(pFrom,pTo)
+ *
+ * This function generates the code that converts one structure
+ * to another structure. Specifically, it unpacks structures back to
+ * their original positions.
+ *
+ * Entry: pFrom - pointer to the 32-bit structure
+ * pTo - pointer to the 16-bit structure
+ *
+ * Exit: structure unpacking code is generated.
+ *
+ * History:
+ * 10-Jan-1989 KevinRo Created It.
+ */
+
+int cod32_UnStructureRepack(TypeNode *pBaseFrom,
+ TypeNode *pBaseTo)
+
+{
+ unsigned int NullLabel;
+ unsigned int ErrorLabel;
+ FixupRec *pFixupList = NULL, *pCurrent;
+ TypeNode *pFrom,*pTo;
+ TypeNode *ptFrom,*ptTo;
+
+
+ pFrom = pBaseFrom->pStructElems;
+ pTo = pBaseTo->pStructElems;
+
+ gEDI = 0;
+ gESI = 0;
+
+ printf(";Return structure to original area\n\n");
+
+ if (fgOutputFlag) {
+ ErrorLabel = gen_LabelCount++;
+ printf("\n\ttest\tBYTE PTR[ebp-%u],1\t\t;Check for errors D\n",iErrorOffset);
+ printf("\tjnz\tL%u\t\t\t;No copy if error\n",ErrorLabel);
+ }
+
+ cod32_UnRepackElements(pBaseFrom,pBaseTo,pFrom,pTo,&pFixupList);
+
+ if (fgOutputFlag)
+ printf("\nL%u:\t\t\t;ErrorLabel D\n",ErrorLabel);
+
+ /*
+ * Now, handle the fixups.
+ */
+ while (pCurrent = cod_GetFixupRecord(&pFixupList)) {
+ printf("\n\n;Unpack imbedded pointer %s\n\n",
+ typ_NonNull(pCurrent->pFrom->pchIdent));
+ printf("\tmov\tesi,[ebp-%u]\t\t;Get pointer to temporary\n",
+ pCurrent->pFrom->iTempOffset);
+ printf("\tor\tesi,esi\t\t;Ignore if NULL\n");
+ printf("\tjz\tL%u\n\n",NullLabel=gen_LabelCount++);
+ printf("\tmov\tedi,[ebp+%u]\t\t;Get parents original pointer\n",
+ pCurrent->pParentFrom->iOffset);
+ printf("\tmov\tedi,[edi+%u]\t\t;Get Fixups original address\n",
+ pCurrent->pFrom->iStructOffset);
+
+ cod32_UnHandlePointer(pCurrent->pFrom,pCurrent->pTo);
+
+ printf("L%u:\n\n",NullLabel);
+ free(pCurrent);
+ }
+ printf(";Deallocate Temporary Structure \n\n");
+ cod32_DeAllocFixedSize(typ_FullSize(pBaseTo),pBaseFrom);
+}
+
+
+/*** cod32_UnRepackElements(pParentFrom,pParentTo,pFrom,pTo,pFixupList)
+ *
+ * This function generates the code that undoes the repacking of
+ * the elements.
+ *
+ * Entry: pParentFrom - pointer to parent of 'from' node.
+ * pParentTo - pointer to parent of 'to' node.
+ * pFrom - pointer to 'from' node.
+ * pTo - pointer to 'to' node.
+ * pFixupList - pointer to fixup record list.
+ *
+ * Exit: code for undoing repacking of elements is generated.
+ */
+
+cod32_UnRepackElements(TypeNode *pParentFrom,
+ TypeNode *pParentTo,
+ TypeNode *pFrom,
+ TypeNode *pTo,
+ FixupRec **pFixupList)
+
+{
+ TypeNode *pToNode,*pFromNode;
+ unsigned int iEDI,iESI;
+ unsigned int JumpLabel;
+
+
+ pToNode = pTo;
+ pFromNode = pFrom;
+
+ fReAlignmentNeeded = 0;
+
+ if (!fgOutputFlag) {
+ while (pFromNode) {
+ if (pFromNode->iPointerType) {
+ cod_AddFixupRecord(pFixupList,
+ cod_MakeFixupRecord(pParentFrom,pParentTo,
+ pFromNode,pToNode));
+ }
+ else if (pFromNode->iBaseType == TYPE_STRUCT) {
+ cod32_UnRepackElements(pParentFrom,pParentTo,
+ pFromNode->pStructElems,
+ pToNode->pStructElems,pFixupList);
+ }
+ pFromNode = pFromNode->pNextNode;
+ pToNode = pToNode->pNextNode;
+ }
+ }
+ else {
+ while (pFromNode) {
+ printf("\n;Element %s --> %s\n", typ_NonNull(pToNode->pchIdent),
+ typ_NonNull(pFromNode->pchIdent));
+ /*
+ * If the fReAlignmentNeeded flag is set, then the previous
+ * operation was a CopyConvert. The adjustment of the registers
+ * in that routine was moved here to optimize the increment of
+ * the registers. At the end of a CopyConvert, we only want to
+ * increment the registers in the cases when there are more
+ * elements in the structure. The fact that we have reached
+ * this statement implies that there are more elements in the
+ * structure.
+ */
+ if (fReAlignmentNeeded) {
+ if (gTransferBytes)
+ fatal("RepackElements: gTransferBytes = %u",gTransferBytes);
+
+ printf("\n;Adjust registers after conversion\n");
+ cod_AdjustReg("esi",&gESI,pToNode->iStructOffset);
+ cod_AdjustReg("edi",&gEDI,pFromNode->iStructOffset);
+
+ fReAlignmentNeeded = 0;
+ }
+ /*
+ * This assignment optimizes the way that bytes are transferred,
+ * so that we don't need adjustments when bytes items preceed
+ * larger sized items. This statement only has effect when a
+ * realignment is about to occur. This value is reset again a
+ * few lines down.
+ */
+ gTransferBytes = MIN((pFromNode->iStructOffset - gEDI),
+ pToNode->iStructOffset - gESI);
+
+ /*
+ * If either the TO or FROM node is deleted, then we need to
+ * realign ESI and EDI.
+ */
+ if ( (pFromNode->iDeleted) || (pToNode->iDeleted)) {
+ printf(";Deleted structure element\n");
+ if (gTransferBytes) {
+ printf(";Alignment Change\n");
+ cod32_TransferBlock(gTransferBytes);
+ gTransferBytes = 0;
+ printf("\n;ReAlignment\n");
+ }
+
+ if (pToNode->iDeleted) {
+ printf(";Source element is deleted\n");
+ switch(pToNode->fSemantics & SEMANTIC_INOUT)
+ {
+ case SEMANTIC_INOUT:
+ case SEMANTIC_INPUT:
+ printf(";Parameter had input semantic\n");
+ printf(";Do not copy it out.\n");
+ break;
+ case SEMANTIC_OUTPUT:
+ printf(";\n");
+ printf("\tmov\teax,%u",pToNode->iFillValue);
+ switch (pFromNode->iBaseType) {
+ case TYPE_USHORT:
+ case TYPE_SHORT:
+ printf("\t\t;Need a 16-bit value\n");
+ printf("\tstosw\n");
+ break;
+ case TYPE_LONG:
+ case TYPE_ULONG:
+ printf("\t\t;Need a 32-bit value\n");
+ printf("\tstosd\n");
+ break;
+ default:
+ fatal("Bad type for deleted struct element\n");
+ }
+ }
+ }
+ else {
+ /* In this case, the To node is deleted. This means
+ * that we don't want to copy the current element.
+ */
+ switch (pToNode->iBaseType) {
+ case TYPE_USHORT:
+ case TYPE_SHORT:
+ printf(";Deleting a 16-bit value\n");
+ break;
+ case TYPE_LONG:
+ case TYPE_ULONG:
+ printf(";Deleting a 32-bit value\n");
+ break;
+ default:
+ fatal("Bad type for deleted struct element\n");
+ }
+ }
+ goto DoneWithNodes; /** Avoid the rest of this loop **/
+ }
+
+ /*
+ * If the alignment is going to shift, then execute a block
+ * transfer, and realign ESI and EDI. Alignment here will
+ * always shift when a pointer is encountered.
+ */
+ if ((pFromNode->iStructOffset - gEDI) !=
+ (pToNode->iStructOffset - gESI) ||
+ (pFromNode->iPointerType)) {
+
+ if (gTransferBytes) {
+ printf(";Alignment Change\n");
+ cod32_TransferBlock(gTransferBytes);
+ gTransferBytes = 0;
+ printf("\n;ReAlignment\n");
+ }
+ cod_AdjustReg("esi",&gESI,pToNode->iStructOffset);
+ cod_AdjustReg("edi",&gEDI,pFromNode->iStructOffset);
+ }
+ switch (pFromNode->iPointerType)
+ {
+ /*
+ * If we find a pointer type, then it is an imbedded pointer.
+ * The data can be included into a block copy, since we are
+ * going to handle it later.
+ */
+ case TYPE_NEAR32:
+ case TYPE_FAR16:
+ printf(";Pointer elements not copied out\n");
+ cod32_TransferBlock(gTransferBytes);
+ gTransferBytes = 0;
+ cod_AdjustReg("esi",&gESI,pToNode->iStructOffset + DWORD_SIZE);
+ cod_AdjustReg("edi",&gEDI,pFromNode->iStructOffset + DWORD_SIZE);
+ cod_AddFixupRecord(pFixupList,
+ cod_MakeFixupRecord(pParentFrom,pParentTo,pFromNode,pToNode));
+ break;
+ default:
+ /*
+ * If it wasn't one of the pointer types above, then it
+ * must be a non pointer parameter. Thus, it will be a
+ * long, short, ulong, ushort, or char
+ */
+ if (pFromNode->iBaseType == TYPE_STRUCT) {
+ unsigned int LoopLabel;
+ unsigned int iESI=gESI,iEDI=gEDI;
+
+ if (pFromNode->iArraySize > 1) {
+ cod32_TransferBlock(gTransferBytes);
+ gTransferBytes = 0;
+
+ cod_AdjustReg("esi",&gESI,pToNode->iStructOffset);
+ cod_AdjustReg("edi",&gEDI,pFromNode->iStructOffset);
+
+ LoopLabel = gen_LabelCount++;
+
+ printf("\n;Array of structures\n");
+ printf("\n\tmov\tecx,%u\n",pFromNode->iArraySize);
+ printf("\nL%u:\n",LoopLabel);
+ printf("\tpush\tecx\t\t;Save array count\n");
+ }
+ cod32_UnRepackElements(pParentFrom,pParentTo,
+ pFromNode->pStructElems,
+ pToNode->pStructElems,pFixupList);
+ iESI = gESI;
+ iEDI = gEDI;
+
+ if (pFromNode->iArraySize > 1) {
+ cod_AdjustReg("esi",&iESI,
+ pToNode->iStructOffset +
+ pToNode->iBaseDataSize);
+ cod_AdjustReg("edi",&iEDI,
+ pFromNode->iStructOffset +
+ pFromNode->iBaseDataSize);
+
+ printf("\n\tpop\tecx\t\t;Restore array count\n");
+ printf("\n\tloop\tL%u\n",LoopLabel);
+ gESI = pToNode->iStructOffset +
+ typ_FullSize(pToNode);
+ gEDI = pFromNode->iStructOffset +
+ typ_FullSize(pFromNode);
+ }
+ }
+ else {
+ fReAlignmentNeeded = 0;
+ /*
+ * Reversing the parameters allows CopyConvert to
+ * be used for both pack and repack.
+ */
+ cod32_CopyConvert(pToNode,pFromNode);
+ }
+ }
+
+DoneWithNodes:
+ if (pToNode->pNextNode == NULL) {
+ cod32_TransferBlock(gTransferBytes);
+ gTransferBytes = 0;
+ }
+ pToNode = pToNode->pNextNode;
+ pFromNode = pFromNode->pNextNode;
+ }
+ }
+}
+
+
+/*** cod32_UnCopyConvertBuffer(pFrom,pTo)
+ *
+ * This function will perform a copy/convert of a buffer.
+ * The buffer is presumed to be in the formal parameter list of the
+ * API declaration.
+ *
+ * Entry: pFrom and pTo are the type nodes.
+ *
+ * Exit: copy/convert of a buffer is performed.
+ */
+
+cod32_UnCopyConvertBuffer(TypeNode *pFrom,
+ TypeNode *pTo)
+
+{
+ TypeNode *pSizeP;
+ unsigned int JumpLabel;
+ unsigned int NullLabel;
+ unsigned int ErrorLabel;
+ unsigned int DoneLabel;
+ unsigned int iNextSize;
+
+
+ /*
+ * If there is a size parameter, then the buffer size is determined at
+ * run time. Otherwise, the buffer size is static.
+ */
+ NullLabel = gen_LabelCount;
+
+ /*
+ * The previous label handles NULL and zero lens.
+ */
+ NullLabel--;
+
+ printf("\n;We have two buffers with different types in them\n");
+ printf("\n;If the buffer was output, then we need to copy out\n");
+
+ if (pSizeP = pFrom->pSizeParam) { /* Runtime */
+ if (fgOutputFlag) {
+ ErrorLabel = gen_LabelCount++;
+ printf("\n\ttest\tBYTE PTR[ebp-%u],1\t\t;Check for errors E\n",iErrorOffset);
+ printf("\tjnz\tL%u\t\t\t;No copy if error\n",ErrorLabel);
+ }
+ if (pSizeP->iPointerType) {
+ /*
+ * The original size parameter pointer is not null. This is
+ * implicit in the fact that the address of the temporary
+ * pointer is different than the original pointer. This also
+ * implies that the original size is non zero.
+ */
+ printf("\n;Size was referenced by a pointer.\n");
+ printf(";Since only shorts/longs are used as sizeof\n");
+ printf(";parameters, the space allocated for the temporary\n");
+ printf(";location is on the stack. It still exists, so it is\n");
+ printf(";still safe to use the temporary pointer\n\n");
+
+ printf("\tmov\tecx,[ebp-%u]\t\t;Get Size Pointer\n",
+ pSizeP->iTempOffset);
+
+ if (pSizeP->iBaseDataSize == WORD_SIZE)
+ printf("\tmovzx\tecx,WORD PTR [ecx]\t\t;Get Size\n");
+ else
+ printf("\tmov\tecx,[ecx]\t\t;Get Size\n");
+ }
+ else
+ printf("\tmov\tecx,[ebp+%u]\t\t;Get Size \n",pSizeP->iOffset);
+
+ if (pSizeP->fSemantics & SEMANTIC_SIZE) {
+ printf(";ECX holds size in bytes\n");
+ printf(";We need to figure out the number of elements\n");
+ printf(";that will fit\n");
+
+ printf("\n\tmov\teax,ecx\n");
+ printf("\txor\tedx,edx\n");
+ printf("\tmov\tecx,%u\t\t;Source size\n",typ_FullSize(pFrom));
+ printf("\tdiv\tcx\n");
+ printf("\tmov\tecx,eax\t;The count\n",iTempStoreOffset);
+ }
+
+ if (pSizeP->fSemantics & SEMANTIC_COUNT)
+ printf(";ECX holds count of items\n");
+
+ gEDI = 0;
+ gESI = 0;
+
+ JumpLabel = gen_LabelCount++;
+ printf("\nL%u:\n",JumpLabel);
+
+ switch (pTo->iBaseType)
+ {
+ case TYPE_SHORT: /* SHORT --> LONG */
+ printf("\n;SHORT --> LONG\n\n");
+ printf("\tmovsx\teax,WORD PTR[esi]\n");
+ printf("\tmov\t[edi],eax\n");
+ break;
+ case TYPE_USHORT: /* USHORT --> ULONG */
+ printf("\n;USHORT --> ULONG\n\n");
+ printf("\tmovzx\teax,WORD PTR[esi]\n");
+ printf("\tmov\t[edi],eax\n");
+ break;
+ case TYPE_LONG: /* LONG --> SHORT */
+ case TYPE_ULONG: /* ULONG --> USHORT */
+ printf("\n;U/LONG --> U/SHORT\n\n");
+ printf("\tmov\teax,DWORD PTR [esi]\n");
+ printf("\tmov\tWORD PTR [edi],ax\n");
+ break;
+ default:
+ fatal("cod32_CopyConvertBuffer: Tried converted %d to %d",
+ pTo->iBaseType,pFrom->iBaseType);
+ }
+
+ printf("\tadd\tesi,%u\n",pTo->iBaseDataSize);
+ printf("\tadd\tedi,%u\n",pFrom->iBaseDataSize);
+ printf("\tloop\tL%u\n",JumpLabel);
+
+ if (fgOutputFlag)
+ printf("\n\nL%u:\t\t\t;ErrorLabel E\n",ErrorLabel);
+
+ printf("\n\n;Deallocate Variable Size Block\n");
+ printf("\tmov\tesi,[ebp-%u]\n",pFrom->iTempOffset);
+ printf("\tpush\t%d\t\t;Alloc Flag Offset\n", - iAliasOffset);
+ printf("\tmov\tedx,%lu\n",(long)1<<pFrom->iPointerNumber);
+ printf("\n\tcall\tTHK32DEALLOC\n\n");
+ }
+ else { /* Static */
+ gEDI = 0;
+ gESI = 0;
+
+ /*
+ * Reversing the order for a CopyConvert is OK.
+ */
+ if (fgOutputFlag) {
+ ErrorLabel = gen_LabelCount++;
+ printf("\n\ttest\tBYTE PTR[ebp-%u],1\t\t;Check for errors F\n",iErrorOffset);
+ printf("\tjnz\tL%u\t\t\t;No copy if error\n",ErrorLabel);
+ }
+
+ cod32_CopyConvert(pTo,pFrom);
+
+ if (fgOutputFlag)
+ printf("\n\nL%u:\t\t\t;ErrorLabel F\n",ErrorLabel);
+
+ cod32_DeAllocFixedSize(typ_FullSize(pTo),pFrom);
+ }
+}
diff --git a/private/os2/client/thunk/thunkcom/cod3216g.c b/private/os2/client/thunk/thunkcom/cod3216g.c
new file mode 100644
index 000000000..106766ad9
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/cod3216g.c
@@ -0,0 +1,598 @@
+/*
+ * Thunk Compiler - Routines for Code Generator (32->16).
+ * GDI-specific hacks
+ *
+ * This is a Win32 specific file
+ * Microsoft Confidential
+ *
+ * Copyright (c) Microsoft Corporation 1987, 1988, 1989, 1990
+ *
+ * All Rights Reserved
+ *
+ * Created by Kevin Ruddell 11/06/90
+ */
+
+
+#include <stdio.h>
+#include "error.h"
+#include "thunk.h"
+#include "types.h"
+#include "symtab.h"
+#include "codegen.h"
+#include "cod3216.h"
+
+extern BOOL fGDIAllocUsed;
+extern BOOL fMapTo16Used;
+extern BOOL fLocalHeapUsed;
+extern unsigned int fgOutputFlag;
+
+/*** cod32_HandlePointerGDI(ptnFrom,ptnTo)
+ *
+ * This function will act on the two pointers accordingly.
+ * Structures will be repacked if needed.
+ *
+ * Entry: ptnFrom - Parameter input to thunk.
+ * ptnTo - Parameter output from thunk.
+ *
+ * Exit: pointers are handled and code is generated.
+ *
+ *
+ * This is a GDI-specific hack. It assumes that there is
+ * only 1 thread at a time in the thunk layer and it does not
+ * handle any embedded pointers.
+ */
+
+void cod32_HandlePointerGDI(PTYPENODE ptnFrom, //Parameter input to thunk
+ PTYPENODE ptnTo) //Parameter output from thunk
+{
+ int iNullLabel, iStoreLabel;
+ BOOL fSameType, fEmbeddedPtr;
+ BOOL fOutputOK = FALSE;
+ ULONG ulObjectSize;
+
+ printf("\n;Pointer %s --> %s\n",
+ typ_NonNull( ptnFrom->pchIdent), typ_NonNull( ptnTo->pchIdent));
+
+ /*
+ * If structures and (not identical or contain pointers), call
+ * structure repacking routine.
+ */
+ fSameType = typ_TypeIdentical( ptnFrom, ptnTo);
+ fEmbeddedPtr = cod_CountPointerParameters( ptnFrom->pStructElems, FALSE);
+
+ if( (ptnFrom->fSemantics & SEMANTIC_OUTPUT) && fSameType &&
+ (ptnFrom->pSizeParam) && (ptnFrom->iBaseType == TYPE_CHAR)) {
+ fOutputOK = TRUE;
+ fMapTo16Used = TRUE;
+ }
+
+ if( !(ptnFrom->fSemantics & SEMANTIC_INPUT) && !fOutputOK) {
+ cod_NotHandled( "unsupported non-input pointer");
+ return;
+ }
+
+ printf( "\n\n\tmov\teax,[ebp+%u]\t\t;%s base address\n",
+ ptnFrom->iOffset, typ_NonNull( ptnFrom->pchIdent));
+ printf( "\tor\teax,eax\n");
+ printf( "\tjz\tL%u\n\n", iNullLabel = gen_LabelCount++);
+
+ if( ptnFrom->fSemantics & SEMANTIC_PASSIFHINULL) {
+ printf( ";special case of polymorphic parameter\n");
+ printf( ";do no conversion if the high word is null\n");
+ printf( "\trol\teax,16\n");
+ printf( "\tor\tax,ax\n");
+ printf( "\trol\teax,16\t\t\t;return eax to original state\n");
+ printf( "\tjz\tL%u\t\t\t;skip if hi word null\n\n",
+ iStoreLabel = gen_LabelCount++);
+ }
+
+ if( ptnFrom->iBaseType == TYPE_STRUCT) {
+ printf("\n;Structures are%s identical\n", fSameType ? "" : " not");
+ printf(";Structures %shave pointers\n\n", fEmbeddedPtr ? "" : "don't ");
+
+ if( fEmbeddedPtr) {
+ cod_NotHandled( "embedded pointer");
+ } else if( ptnFrom->pSizeParam) {
+ cod_NotHandled( "structure buffer");
+ } else if( !fSameType) {
+ cod32_StructureRepackGDI( ptnFrom, ptnTo);
+ } else {
+ printf( "\tmov\tecx,%u\t\t\t;struct size\n", ptnFrom->iBaseDataSize);
+ fMapTo16Used = TRUE;
+ }
+ } else if( fSameType) {
+ if( !ptnFrom->pSizeParam) {
+ if( ptnFrom->iBaseType == TYPE_NULLTYPE) {
+ printf( "\t.err *** NULLTYPE ***\n");
+ } else if( ptnFrom->iBaseType == TYPE_STRING) {
+ printf( "\tmov\tecx,%u\t\t;default string size\n",
+ DEFAULT_STRING_SIZE);
+ fMapTo16Used = TRUE;
+ } else {
+ printf( "\tmov\tecx,%u\t\t;default buffer size\n",
+ DEFAULT_BUFFER_SIZE);
+ fMapTo16Used = TRUE;
+ //cod_NotHandled( "non-string, non-struct, non-sized pointer");
+ }
+ } else {
+ if( ptnFrom->iBaseType == TYPE_CHAR) {
+ printf( "\tmov\tecx,[ebp+%u]\t\t;buffer size\n",
+ ptnFrom->pSizeParam->iOffset);
+ fMapTo16Used = TRUE;
+ } else {
+ cod_NotHandled( "non-char buffer");
+ }
+ }
+ } else {
+ cod_NotHandled( "pointer to different non-structs");
+ }
+
+ if( fMapTo16Used) {
+ printf( "\tpush\teax\t\t\t;base address\n", ptnFrom->iOffset);
+ printf( "\tpush\tecx\t\t\t;object size\n", ulObjectSize);
+ printf( "\tpush\tdword ptr [ebp-%u]\t;thunk ID\n", iPtrThunkIDOffset);
+ printf( "\tcall\tMapLS32\t\t\t;exit: (eax)==16:16 address\n");
+ if( ptnFrom->fSemantics & SEMANTIC_PASSIFHINULL)
+ printf( "L%u:\n", iStoreLabel);
+ printf( "\tmov\tDWORD PTR [ebp-%u],eax\t;value to push\n",
+ ptnFrom->iTempOffset);
+ }
+
+ printf( "\nL%u:\n", iNullLabel);
+}
+
+
+
+
+
+/*** cod32_PushParametersGDI
+ *
+ * This function generates the code that pushes the 32-bit parameters
+ * onto the stack.
+ *
+ * Entry: pFromNode - pointer to the 32-bit function's parameter list.
+ * pToNode - pointer to the 16-bit function's parameter list.
+ *
+ * Exit: generates the code that pushes the 32-bit parameters.
+ *
+ * History:
+ * 29-Nov-1988 JulieB Created it.
+ */
+
+cod32_PushParametersGDI(TypeNode *pFromNode,
+ TypeNode *pToNode)
+
+{
+ int iStackOffset = DWORD_SIZE; /* offset to temp storage on stack */
+ unsigned int AllowLabel;
+ int fRestricted;
+ BOOL fSameType, fEmbeddedPtr;
+ BOOL fOutputOK = FALSE;
+
+
+ /*
+ * For each parameter, convert and push as needed.
+ */
+ while (pFromNode) {
+ fRestricted = (pFromNode->fSemantics & SEMANTIC_RESTRICT);
+
+ printf("\n\n\t;From Name: %s Type: %s\n",
+ typ_NonNull(pFromNode->pchIdent),
+ typ_NonNull(pFromNode->pchBaseTypeName));
+ if (pFromNode->iBaseType == TYPE_NULLTYPE)
+ printf("\n\t.err **** NULLTYPE ****\n\n");
+
+ else if (pFromNode->iDeleted) {
+
+ /* If the iDeleted flag is set in the pFromNode, then this
+ * parameter does not exist in the original call frame.
+ * Therefore, we need to push a zero of the appropriate length.
+ */
+ printf("\n;Extra parameter needed: Push a zero\n");
+
+ switch (pToNode->iBaseType)
+ {
+ case TYPE_UCHAR:
+ printf("\tpush\tBYTE PTR %u\t\t;Push u/byte\n",
+ pFromNode->iFillValue);
+ break;
+
+ case TYPE_SHORT:
+ case TYPE_USHORT:
+ printf("\tpush\tWORD PTR %u\t\t;Push u/short\n",
+ pFromNode->iFillValue);
+ break;
+
+ case TYPE_LONG:
+ case TYPE_ULONG:
+ printf("\tpush\t%u\t\t;Push U/LONG\n",
+ pFromNode->iFillValue);
+ break;
+
+ default:
+ fprintf(stderr, "\nInvalid type for DELETED\n");
+ printf("\n.err Invalid type for DELETED\n");
+ }
+ }
+ else if (pToNode->iDeleted) {
+ printf("\t;Parameter not needed in callee\n");
+
+ if (fRestricted)
+ cod32_HandleRestricted(pFromNode);
+ }
+ else {
+ switch (pFromNode->iPointerType)
+ {
+ case TYPE_NEAR32:
+ fSameType = typ_TypeIdentical( pFromNode, pToNode);
+ fEmbeddedPtr = cod_CountPointerParameters(
+ pFromNode->pStructElems, FALSE);
+
+ if( pFromNode->iBaseType == TYPE_STRUCT) {
+ if( (pFromNode->pSizeParam) || fEmbeddedPtr) {
+ printf( "\t.err\t\t\t;struct buffer or embedded ptrs\n");
+ } else if( fSameType) {
+ printf( "\tpush\tDWORD PTR [ebp-%u]\n",
+ pFromNode->iTempOffset);
+ } else {
+ printf( ";compute 16:16 address on stack\n");
+ printf( "\tmov\teax,[ebp-%u]\n",
+ pFromNode->iTempOffset);
+ printf( "\tsub\teax,esp\n");
+ printf( "\tadd\teax,DWORD PTR STACK16INITIALOFFSET\n");
+ printf( "\tadd\teax,%u\n",
+ DWORD_SIZE + pToNode->iOffset);
+ printf( "\tpush\teax\n");
+ }
+ } else {
+ printf( "\tpush\tDWORD PTR [ebp-%u]\n",
+ pFromNode->iTempOffset);
+ }
+ break;
+
+#if 0
+ if( pFromNode->iBaseType == TYPE_STRING) {
+ printf( "\tpush\tDWORD PTR [ebp-%u]\n",
+ pFromNode->iTempOffset);
+ } else {
+ printf( "\tmov\teax,[ebp-%u]\n",
+ pFromNode->iTempOffset);
+ printf( "\tsub\teax,esp\n");
+ printf( "\tadd\teax,DWORD PTR STACK16INITIALOFFSET\n");
+ printf( "\tadd\teax,%u\n",
+ DWORD_SIZE + pToNode->iOffset);
+ printf( "\tpush\teax\n");
+ }
+ break;
+#endif
+ case TYPE_FAR16:
+ printf( "\tpush\tDWORD PTR [ebp-%u]\n",
+ pFromNode->iTempOffset);
+ break;
+
+ /* If it wasn't one of the pointer types above, then it must
+ * be a non pointer parameter. Thus, it will be a long,
+ * short, ulong, ushort, or char.
+ */
+ default:
+
+ /* If types are equal, then no conversion needed.
+ * If no conversion is needed, then just push the item
+ * onto new call frame. If conversion is needed, then
+ * use switch statement to emit the correct conversion.
+ */
+ if (pToNode->iBaseType == pFromNode->iBaseType) {
+ if (pFromNode->iBaseDataSize <= WORD_SIZE) {
+ if (fRestricted) {
+ printf("\tmovzx\teax,WORD PTR [ebp+%u]\t; To: %s\n",
+ pFromNode->iOffset, pToNode->pchBaseTypeName);
+ cod32_HandleRestricted(pFromNode);
+ printf("\n\tpush\tax\n");
+ } else {
+ printf("\tpush\tWORD PTR [ebp+%u]\t; To: %s\n",
+ pFromNode->iOffset, pToNode->pchBaseTypeName);
+ }
+ }
+ else {
+ if (fRestricted) {
+ printf("\tmov\teax,[ebp+%u]\t; To: %s\n",
+ pFromNode->iOffset, pToNode->pchBaseTypeName);
+ cod32_HandleRestricted(pFromNode);
+ printf("\n\tpush\teax\n");
+ }
+ else {
+ printf("\tpush\tDWORD PTR [ebp+%u]\t; To: %s\n",
+ pFromNode->iOffset, pToNode->pchBaseTypeName);
+ }
+ }
+ }
+ else {
+ switch (pFromNode->iBaseType)
+ {
+ case TYPE_UCHAR: /* UCHAR --> ULONG */
+ printf("\tmovzx\teax,BYTE PTR[ebp+%u]\t;",
+ pFromNode->iOffset);
+ cod32_HandleRestricted(pFromNode);
+ printf("To: %s\n", pToNode->pchBaseTypeName);
+ printf("\tpush\teax\n");
+ break;
+ case TYPE_SHORT: /* SHORT --> LONG */
+ printf("\tmovsx\teax,WORD PTR[ebp+%u]\t;",
+ pFromNode->iOffset);
+ cod32_HandleRestricted(pFromNode);
+ printf("To: %s\n", pToNode->pchBaseTypeName);
+ printf("\tpush\teax\n");
+ break;
+ case TYPE_USHORT: /* USHORT --> ULONG */
+ printf("\tmovzx\teax,WORD PTR[ebp+%u]\t;",
+ pFromNode->iOffset);
+ cod32_HandleRestricted(pFromNode);
+ printf("To: %s\n", pToNode->pchBaseTypeName);
+ printf("\tpush\teax\n");
+ break;
+ case TYPE_LONG: /* LONG --> SHORT */
+ printf("\tmov\teax,[ebp+%u]\n", pFromNode->iOffset);
+
+ if (fRestricted) {
+ cod32_HandleRestricted(pFromNode);
+ }
+ else {
+ if (pGlobal_From->fSemantics & SEMANTIC_TRUNC) {
+ if (pFromNode->AllowList) {
+ AllowLabel = gen_LabelCount++;
+ cod32_HandleAllowList(pFromNode->AllowList,
+ AllowLabel);
+ }
+ printf("\tmovsx\tecx,ax\n");
+ printf("\tcmp\teax,ecx\n");
+ printf("\tjne\tINVP_%s\t\t;\n\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ if (pFromNode->AllowList)
+ printf("L%u:",AllowLabel);
+ }
+ }
+ printf("\tpush\tax\t;To:%s\n",pToNode->pchBaseTypeName);
+ break;
+
+ case TYPE_ULONG: /* ULONG --> USHORT */
+ printf("\tmov\teax,[ebp+%u]\n", pFromNode->iOffset);
+
+ if( (pFromNode->fSemantics & SEMANTIC_LOCALHEAP) &&
+ (pFromNode->fSemantics & SEMANTIC_INPUT)) {
+ printf( "\tsub\teax,DS16LOCALHEAPBASE\t\t;local heap\n");
+ printf( "\tcmp\teax,0ffffh\n");
+ printf( "\tja\tINVP_%s\n\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ } else if( fRestricted) {
+ cod32_HandleRestricted(pFromNode);
+ }
+ else {
+ if (pGlobal_From->fSemantics & SEMANTIC_TRUNC) {
+ if (pFromNode->AllowList) {
+ AllowLabel = gen_LabelCount++;
+ cod32_HandleAllowList(pFromNode->AllowList,
+ AllowLabel);
+ }
+
+ printf("\tcmp\teax,0ffffh\n");
+ printf("\tja\tINVP_%s\n\n",
+ pGlobal_From->pchFunctionName);
+ pGlobal_From->fInvalidParam = 1;
+ if (pFromNode->AllowList)
+ printf("L%u:",AllowLabel);
+ }
+ }
+ printf("\tpush\tax\t\t;To:%s\n",pToNode->pchBaseTypeName);
+ break;
+ default:
+ fatal("cod_PushParameters32: Tried converted %d to %d",
+ pFromNode->iBaseType, pToNode->iBaseType);
+ }
+ }
+ }
+ }
+ pToNode = pToNode->pNextNode;
+ pFromNode = pFromNode->pNextNode;
+ }
+}
+
+
+/*** cod32_StructureRepackGDI( ptnBaseFrom, ptnBaseTo)
+ *
+ * This function generates the code that converts one structure
+ * to another structure.
+ *
+ * Entry: pBaseFrom - pointer to the 32-bit structure.
+ * pBaseTo - pointer to the 16-bit structure.
+ *
+ * Exit: structure repack code is generated.
+ *
+ * History:
+ * 06-Nov-1990 KevinR Wrote it
+ */
+
+void
+cod32_StructureRepackGDI(PTYPENODE ptnBaseFrom,
+ PTYPENODE ptnBaseTo)
+
+{
+ FixupRec *pFixupList = NULL, *pCurrent;
+ PTYPENODE ptnFrom, ptnTo;
+
+
+ ptnFrom = ptnBaseFrom->pStructElems;
+ ptnTo = ptnBaseTo->pStructElems;
+
+ cod32_AllocFixedSize(typ_FullSize(ptnBaseTo), ptnBaseFrom);
+
+ gEDI = 0;
+ gESI = 0;
+
+ /*
+ * If the structure is not marked with the input semantic, then the
+ * structure does not contain any useful information. Therefore,
+ * we will assume that any substructures to this structure are
+ * not interesting, and may not actually exist.
+ */
+ if (!(ptnBaseFrom->fSemantics & SEMANTIC_INPUT))
+ return;
+
+ printf(";Copy structure to new area\n\n");
+ cod32_RepackElements(ptnBaseFrom, ptnBaseTo, ptnFrom, ptnTo, &pFixupList);
+
+ /*
+ * Now, handle the fixups.
+ */
+ while (pCurrent = cod_GetFixupRecord(&pFixupList)) {
+ printf("\n\n;Fixup imbedded pointer %s\n\n",
+ typ_NonNull(pCurrent->pFrom->pchIdent));
+ printf("\tmov\tesi,[ebp-%u]\t\t;Get parents pointer\n",
+ pCurrent->pParentFrom->iTempOffset);
+ printf("\tmov\tesi,[esi+%u]\t\t;Get Fixups pointer\n",
+ pCurrent->pTo->iStructOffset);
+
+ cod32_HandlePointer(pCurrent->pFrom, pCurrent->pTo);
+
+ printf("\n;Patch in new pointer value\n");
+ printf("\tmov\tedi,[ebp-%u]\t\t;Get parents pointer\n",
+ pCurrent->pParentFrom->iTempOffset);
+ printf("\tmov\tesi,[ebp-%u]\t\t;Get Fixups new pointer\n",
+ pCurrent->pFrom->iTempOffset);
+
+ if (pCurrent->pFrom->iPointerType != pCurrent->pTo->iPointerType) {
+ switch (pCurrent->pFrom->iPointerType)
+ {
+ case TYPE_FAR16:
+ printf(";Convert 16:16 --> 0:32\n");
+ printf("\tor\tesi,esi\n");
+ printf("\tjz\tshort L%u\n",gen_LabelCount);
+ printf("\tror\tesi,16\n");
+ printf("\tshr\tsi,3\n");
+ printf("\trol\tesi,16\n");
+ printf("L%u:\n",gen_LabelCount++);
+ break;
+ case TYPE_NEAR32:
+ printf(";Convert 0:32 --> 16:16\n");
+ printf("\tor\tesi,esi\n");
+ printf("\tjz\tshort L%u\n",gen_LabelCount);
+ printf("\tror\tesi,16\n");
+ printf("\tshl\tsi,3\n");
+ printf("\tmov\teax,ss\n");
+ printf("\tand\teax,3\n");
+ printf("\tor\tal,4\n");
+ printf("\tor\tsi,ax\n");
+ printf("\trol\tesi,16\n");
+ printf("L%u:\n",gen_LabelCount++);
+ break;
+ default:
+ fatal("Structure Repack: Unknown pointer type");
+ }
+ }
+ printf("\tmov\t[edi+%u],esi\t\t;Put Fixups pointer\n",
+ pCurrent->pTo->iStructOffset);
+ free(pCurrent);
+ }
+}
+
+
+
+/*** cod32_UnpackStructGDI( pMNode)
+ *
+ * This function will unwind any pointer manipulation done to make
+ * the call.
+ *
+ * Entry: pMNode - pointer to a MapNode.
+ *
+ * Exit: generates code to unpack structures.
+ *
+ * History:
+ * 28-Nov-1988 JulieB Created it.
+ * 06-Nov-1990 KevinR GDI hacks
+ */
+
+cod32_UnpackStructGDI( MapNode *pMNode)
+
+{
+ int iNullLabel;
+ PTYPENODE ptnFrom, ptnTo;
+
+
+ printf("\n; ****> BEGIN Pointer/Structure Unpack Section\n\n");
+
+ printf( "\tpush\teax\t\t\t; save return code\n");
+
+ if( fMapTo16Used) {
+ printf( "\tpush\tdword ptr [ebp-%u]\t\t; ptr thunk id\n",
+ iPtrThunkIDOffset);
+ printf( "\tcall\tUnmapLS32\n");
+ }
+
+ printf( "\tpush\tdword ptr [ebp-%u]\t\t;stack thunk id\n",
+ iStackThunkIDOffset);
+ printf( "\tcall\tReleaseStack32\n");
+
+ printf( "\tpop\teax\t\t\t; restore return code\n");
+
+#if 0
+ ptnFrom = pMNode->pFromNode->ParamList;
+ ptnTo = pMNode->pToNode->ParamList;
+
+ while (ptnFrom && ptnTo) {
+ if( (ptnFrom->fSemantics & SEMANTIC_OUTPUT) &&
+ typ_TypeIdentical( ptnFrom, ptnTo) &&
+ (ptnFrom->pSizeParam) && (ptnFrom->iBaseType == TYPE_CHAR)) {
+
+ printf( "\n;output buffer %s --> %s\n",
+ typ_NonNull( ptnFrom->pchIdent),
+ typ_NonNull( ptnTo->pchIdent));
+ printf( "\tmov\tecx,DWORD PTR [ebp+%u]\t\t;get size param\n",
+ ptnFrom->pSizeParam->iOffset);
+ printf( "\tmov\tesi,DWORD PTR [ebp-%u]\t\t;32-bit buffer address\n",
+ ptnFrom->iTempOffset);
+ printf( "\tmov\tedi,DWORD PTR [ebp+%u]\n", ptnFrom->iOffset);
+ printf( "\trep\tmovsb\n");
+ }
+ ptnFrom = ptnFrom->pNextNode;
+ ptnTo = ptnTo->pNextNode;
+ }
+
+ if( fGDIAllocUsed)
+ printf( "\tcall\tReleaseBuff\n");
+#endif
+
+#if 0
+ pFromList = pMNode->pFromNode->ParamList;
+ pToList = pMNode->pToNode->ParamList;
+
+ while (pFromList && pToList) {
+ if (pFromList->iPointerType) {
+ fgOutputFlag = pFromList->fSemantics & SEMANTIC_OUTPUT;
+
+ printf("\n;Undo Pointer %s --> %s\n",
+ typ_NonNull(pFromList->pchIdent),typ_NonNull(pToList->pchIdent));
+
+ /*
+ * Load source address into esi.
+ */
+ printf("\n\n\tmov\tesi,[ebp-%u]\t\t;%s temp address\n",
+ pFromList->iTempOffset,typ_NonNull(pFromList->pchIdent));
+ printf("\tor\tesi,esi\n");
+ printf("\tjz\tL%u\n\n",NullLabel=gen_LabelCount++);
+
+ /*
+ * Load destination address into edi.
+ */
+ printf("\n\n\tmov\tedi,[ebp+%u]\t\t;%s original address\n",
+ pFromList->iOffset,typ_NonNull(pFromList->pchIdent));
+
+ cod32_UnHandlePointer(pFromList,pToList);
+ printf("\nL%u:\t\t;No action required\n",NullLabel);
+ }
+ pFromList = pFromList->pNextNode;
+ pToList = pToList->pNextNode;
+ }
+#endif
+ printf("\n; ****> END Pointer/Structure Unpack Section\n\n");
+}
diff --git a/private/os2/client/thunk/thunkcom/codegen.c b/private/os2/client/thunk/thunkcom/codegen.c
new file mode 100644
index 000000000..44c5dea20
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/codegen.c
@@ -0,0 +1,1000 @@
+#define SCCSID "@(#)codegen.c 13.26 90/08/28"
+
+/*
+ * Thunk Compiler - Code Generator.
+ *
+ * This is a Windows 3.2 specific file
+ * Microsoft Confidential
+ *
+ * Copyright (c) Microsoft Corporation 1987, 1988, 1989
+ *
+ * All Rights Reserved
+ *
+ * Written 10/15/88 by Kevin Ross [for OS/2 2.x]
+ * 10.16.90 Kevin Ruddell ported to Windows 3.2, 16=>32
+ * 02.20.91 Kevin Ruddell re-wrote 16=>32 code
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "error.h"
+#include "thunk.h"
+#include "types.h"
+#include "symtab.h"
+#include "codegen.h"
+
+extern CHAR *pszGDISemName;
+extern BOOL fLocalHeapUsed;
+
+static FixupRec *FixUps = NULL;
+unsigned int iStackOverhead;
+unsigned int iAllocOffset,iBMPOffset,iAliasOffset,iTempStoreOffset,
+ iReturnValOffset,iSavedRegOffset,iErrorOffset,
+ iStackThunkIDOffset, iPtrThunkIDOffset;
+
+
+/*** cod_GenerateCode(pmnFirst)
+ *
+ * This function generates the appropriate code for all of the
+ * given mappings.
+ *
+ * Entry: pmnFirst - a pointer to a list of mapping nodes.
+ *
+ * Exit: code is generated for all mappings.
+ *
+ * PCode:
+ * Scan list and convert names where needed
+ * Output Assembler File Prolog
+ * - Define all segments, and groups
+ * For (each function mapping in pMT) {
+ * switch (mapping type) {
+ * case 16 -> 32: gen_Handle1632(pMT);
+ * break;
+ * case 32 -> 16: gen_Handle3216(pMT);
+ * break;
+ * default: fatal("unknown mapping type");
+ * }
+ * }
+ *
+ * History:
+ * 29-Nov-1988 JulieB Restructured FOR loop for cod_Handle routines
+ * 28-Nov-1988 JulieB Init gen_LabelCount. Added inline comments.
+ * 04-Apr-1989 KevinRo Added Undercase/Underscore routine
+ */
+
+void cod_GenerateCode( PMAPNODE pmnFirst)
+{
+ PMAPNODE pmn;
+ BOOL fExistsTo16, fExistsTo32;
+
+ fExistsTo16 = cod_ExistsToType( pmnFirst, TYPE_API16);
+ fExistsTo32 = cod_ExistsToType( pmnFirst, TYPE_API32);
+
+ if( (fExistsTo16 = cod_ExistsToType( pmnFirst, TYPE_API16)) &&
+ (fExistsTo32 = cod_ExistsToType( pmnFirst, TYPE_API32))) {
+ cod_NotHandled( "both 16=>32 and 32=>16 thunks in same script");
+ return;
+ }
+
+ cod_ConvertNames( pmnFirst); /* Fixup changes in names */
+
+ if( fExistsTo16) {
+//
+// YaronS - take this out to reduce size
+//
+ ;
+/*
+* cod_OutputProlog( pmnFirst);
+*
+* if( fGlobalCombine)
+* cod_CombineFunctions( pmnFirst);
+*
+* if( DumpTables)
+* cod_DumpMapTable( pmnFirst);
+*
+* for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping)
+* cod_Handle3216( pmn);
+*
+* cod_OutputEpilog( pmn);
+*/
+ } else if( fExistsTo32) {
+
+ cod16_Handle16( pmnFirst);
+
+ cod16_Prolog32( pmnFirst);
+
+ for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping)
+ cod16_Handle32( pmn);
+
+ cod16_Epilog32( pmnFirst);
+ }
+}
+
+
+/*** cod_ConvertNames(pMN)
+ *
+ *
+ *
+ * Entry:
+ *
+ * Exit:
+ */
+
+void cod_ConvertNames( MapNode *pMT)
+
+{
+ for( ; pMT; pMT = pMT->pNextMapping) {
+ /*
+ * If fUnderScore32 is set true, then prefix an underscore to the
+ * 32-bit function name.
+ */
+ if (fUnderScore32) {
+ cod_PrefixUnderscore((pMT->pFromNode->iCallType==TYPE_API32) ?
+ pMT->pFromNode : pMT->pToNode);
+ }
+
+ /*
+ * If fUpperCase16 is set true, then force the 16bit function to
+ * be all upper case.
+ */
+ if (fUpperCase16) {
+ cod_ToUpper((pMT->pFromNode->iCallType==TYPE_API16) ?
+ pMT->pFromNode->pchFunctionName :
+ pMT->pToNode->pchFunctionName);
+ }
+
+ /*
+ * If fUpperCase32 is set, then force the 32 bit name to be
+ * uppercase.
+ */
+ if (fUpperCase32) {
+ cod_ToUpper((pMT->pFromNode->iCallType==TYPE_API32) ?
+ pMT->pFromNode->pchFunctionName :
+ pMT->pToNode->pchFunctionName);
+ }
+ }
+}
+
+
+/*** cod_StructOffset()
+ *
+ * This routine will traverse the StructElems of a typenode,
+ * calculating both the offset and size of each element of the
+ * structure. Size is only calculated for elements that are structures.
+ *
+ * Entry: pTNode - pointer to the structure element list.
+ * iPrev - the offset of any previous elements in element list.
+ * iAlign - the alignment value for the structure. Either
+ * 1,2 or 4, determines the packing for calculating
+ * offsets.
+ *
+ * Exit: Each element in the structure will have its StructOffset
+ * field set correctly.
+ *
+ * Returns the size of the structure as defined in 'C'.
+ *
+ * PCode:
+ * For (Each element in element list) {
+ * If (Element is a pointer type) {
+ * Element offset Aligned Offset
+ * Next offset = current + 4 * Array size
+ * If (Element type is structure)
+ * StructOffset(Element,Zero offset,Current Alignment)
+ * } Else if (Element is a structure) {
+ * Save previous offset
+ * Current offset =
+ * StructOffset(Element,Current offset,Current Alignment)
+ * Struct size = Current offset - Previous offset
+ * } Else {
+ * Align current offset according to data size
+ * Struct offset = current offset
+ * Current offset+= Datasize * ArraySize
+ * }
+ * }
+ * return (CurrentOffset which is same as structure size)
+ */
+
+int cod_StructOffset(TypeNode *pTNode,
+ int iPrev,
+ int iAlign)
+
+{
+ TypeNode *pTN;
+ int iSize=0;
+ int iLargest;
+ int tmpAlign;
+
+ /*
+ * Preset the alignment for the first item in structure.
+ */
+ iLargest = cod_FindLargestSize(pTNode);
+ tmpAlign = MIN(iLargest,iAlign);
+ iPrev = Align(iPrev,tmpAlign);
+
+ for (pTN = pTNode; pTN; pTN = pTN->pNextNode) {
+ if (pTN->iDeleted) {
+ pTN->iStructOffset = iPrev;
+ } else if (pTN->iPointerType) {
+ iPrev = Align(iPrev,tmpAlign);
+ pTN->iStructOffset = iPrev;
+ iPrev += DWORD_SIZE * pTN->iArraySize;
+
+ if (pTN->iBaseType == TYPE_STRUCT) {
+ pTN->iBaseDataSize = cod_StructOffset(pTN->pStructElems,0,iAlign);
+ }
+ } else if (pTN->iBaseType == TYPE_STRUCT) {
+ iSize = iPrev;
+ pTN->iStructOffset = iPrev;
+ iPrev = cod_StructOffset(pTN->pStructElems,iPrev,tmpAlign);
+
+ if (pTN->pStructElems) {
+ pTN->iStructOffset = pTN->pStructElems->iStructOffset;
+ }
+
+ pTN->iBaseDataSize = (iPrev - pTN->iStructOffset) ;
+ iPrev += pTN->iBaseDataSize * (pTN->iArraySize - 1);
+ } else {
+ switch(pTN->iBaseDataSize)
+ {
+ case 1:
+ /*
+ * Byte size items are always Byte aligned.
+ */
+ break;
+ case 2:
+ if (tmpAlign >= 2) {
+ /*
+ * Word size items are always WORD aligned.
+ */
+ iPrev = Align(iPrev,WORD_SIZE);
+ }
+ break;
+ case 4:
+ iPrev = Align(iPrev,tmpAlign);
+ break;
+ default:
+ fatal("cod_StructOffset: iBaseDataSize = %d",
+ pTN->iBaseDataSize);
+ }
+ pTN->iStructOffset = iPrev;
+ iPrev += pTN->iBaseDataSize * pTN->iArraySize;
+ }
+ }
+ iPrev = Align( iPrev, tmpAlign);
+ return (iPrev);
+}
+
+
+/*** cod_FindLargestSize(pTN)
+ *
+ * This little routine returns the size of the largest item in the
+ * TypeNode list pTN. The largest size refers to the largest
+ * value in iBaseDataSize. A pointer is considered the largest, at
+ * 4 bytes. If an item of 4 byte size is found, this routine returns
+ * 4 immediately.
+ *
+ * This routine is used by StructOffset as a worker routine.
+ *
+ * Entry: pTN - pointer to the type node.
+ *
+ * Exit: returns the size of the largest item in pTN.
+ */
+
+int cod_FindLargestSize(TypeNode *pTN)
+
+{
+ int maxsize = 0;
+
+
+ if (!pTN)
+ fatal("cod_FindLargestItem(pTN) Null Parameter");
+
+ for (; pTN; pTN = pTN->pNextNode) {
+ /*
+ * If item is deleted, then ignore it.
+ */
+ if (pTN->iDeleted)
+ continue;
+
+ /*
+ * Pointers are the largest items of interest. If we find one, then
+ * cut the search off, and return its size. Pointers are always DWORDs.
+ */
+ if (pTN->iPointerType)
+ return DWORD_SIZE;
+
+ if (pTN->iBaseType == TYPE_STRUCT) {
+ maxsize = MAX(maxsize,cod_FindLargestSize(pTN->pStructElems));
+ }
+ maxsize = MAX( maxsize, (int)(pTN->iBaseDataSize));
+ }
+ return (maxsize);
+}
+
+
+/*** cod_CalcStructOffsets()
+ *
+ * Entry: pTNode - List of parameters from a function node.
+ * iAlign - Alignment default value.
+ *
+ * Exit: structure offsets are calculated.
+ *
+ * PCode:
+ * For (Each parameter in list) {
+ * If (Parameter is a structure) {
+ * If (Alignment < 1)
+ * Assign default alignment to parameter
+ * ParameterSize = StructOffset(StructElems,0,Struct Align)
+ * }
+ * }
+ */
+
+void cod_CalcStructOffsets( TypeNode *pTNode, int iAlign)
+
+{
+ for( ; pTNode; pTNode = pTNode->pNextNode) {
+ if( pTNode->iBaseType == TYPE_STRUCT) {
+ if( pTNode->iAlignment < 1)
+ pTNode->iAlignment = iAlign;
+ pTNode->iBaseDataSize =
+ cod_StructOffset( pTNode->pStructElems, 0, pTNode->iAlignment);
+ }
+ }
+}
+
+
+/*** cod_CalcTempOffset(pTL, iStart)
+ *
+ * This routine will traverse a list of formal parameters, pTL,
+ * and calculate the stack offset for each temporary pointer.
+ * Temporary pointers will be assigned for every pointer in the
+ * type list, including pointers imbedded in structures.
+ *
+ * Entry: pTL - typeNode pointing to remainder of parameter list.
+ * iStart - the first available place for the temp pointers on
+ * the stack
+ *
+ * Exit: Each node in the pTL list will have its iTempOffset field
+ * filled in with the offset from eBP on the stack. The value
+ * returned by this function is the next available position
+ * on the stack.
+ *
+ * History:
+ * 26-Dec-1988 KevinRo Created
+ */
+
+int cod_CalcTempOffset(TypeNode *pTL,
+ unsigned int iStart)
+
+{
+ while (pTL) {
+ if (pTL->iPointerType) {
+ pTL->iTempOffset = iStart;
+ iStart += DWORD_SIZE;
+ }
+ if (pTL->iBaseType == TYPE_STRUCT) {
+ iStart = cod_CalcTempOffset(pTL->pStructElems,iStart);
+ }
+ pTL = pTL->pNextNode;
+ }
+ return (iStart);
+}
+
+
+/*** cod_CalcOffset(pTL, start, iPSize, fPushDir)
+ *
+ * This routine will traverse a list of formal parameters, pTL,
+ * and calculate the stack offset for each parameter. This routine
+ * will handle the calculation for stack offsets regardless of
+ * push direction (left to right, or right to left).
+ *
+ * Entry: pTL - typenode pointing to remainder of parameter list.
+ * start - bytes between top of stack and first parameter.
+ * iPSize - default size of parameters on stack. 16:16 routines
+ * pass WORD parameters, 0:32 DWORD parameters.
+ * fPushDir - direction of push (PUSH_LEFT = left to right).
+ *
+ * Exit: Each node in the pTL list will have its iOffset field filled
+ * in with the offset from eBP on the stack.
+ *
+ * PCode: (This routine is recursive)
+ * If (push left to right) { // push left to right
+ * If (pTL not NULL) {
+ * Current offset = return from CalcOffset of next parameter in list
+ * return Current Offset + size of current parameter
+ * } Else {
+ * return starting offset.
+ * }
+ * } Else { // push right to left
+ * If (pTL) {
+ * Current Offset = starting offset
+ * starting offset += Size of parameter on stack
+ * CalcOffset rest of list, using new starting offset
+ * }
+ * }
+ *
+ * History:
+ * 30-Nov-1988 JulieB Added use of MAX macro.
+ */
+
+int cod_CalcOffset(TypeNode *pTL,
+ int start,
+ int iPSize,
+ int fPushDir)
+
+{
+ if (fPushDir == PUSH_LEFT) {
+ if (pTL) {
+ start = pTL->iOffset
+ = cod_CalcOffset( pTL->pNextNode, start, iPSize, fPushDir);
+ /*
+ * If the parameter is flagged as deleted, then don't add
+ * its size to the offset.
+ */
+ if( !(pTL->iDeleted)) {
+ start += (pTL->iPointerType) ?
+ 4 :
+ MAX( (int)(pTL->iBaseDataSize), iPSize);
+ }
+ }
+ return start;
+ } else {
+ if (pTL) {
+ pTL->iOffset = start;
+ /*
+ * If the parameter is flagged as deleted, then don't add
+ * its size to the offset.
+ */
+ if( !pTL->iDeleted) {
+ start += (pTL->iPointerType) ?
+ 4 :
+ MAX( (int)(pTL->iBaseDataSize), iPSize);
+ }
+ cod_CalcOffset( pTL->pNextNode, start, iPSize, fPushDir);
+ }
+ }
+}
+
+
+/*** cod_OutputProlog( pmnFirst)
+ *
+ * This routine will output a masm header.
+ *
+ * Entry: pmnFirst - linked lists of mapping nodes.
+ *
+ * Exit:
+ *
+ * PCode:
+ * Output masm header
+ * For (each entry point)
+ * Declare symbol as public
+ * Open segment
+ * For (each called routine)
+ * If (routine is 32 bit)
+ * Output external
+ */
+
+static void
+cod_OutputProlog( MapNode *pmnFirst)
+
+{
+ register MapNode *pmn;
+ FunctionNode *pFNode;
+ BOOL fExistsTo16, fExistsTo32;
+
+ fExistsTo16 = cod_ExistsToType( pmnFirst, TYPE_API16);
+ fExistsTo32 = cod_ExistsToType( pmnFirst, TYPE_API32);
+
+ for( pmn = pmnFirst, fLocalHeapUsed = FALSE; pmn; pmn = pmn->pNextMapping)
+ if( typ_QuerySemanticsUsed( pmn, SEMANTIC_LOCALHEAP))
+ fLocalHeapUsed = TRUE;
+
+ for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping)
+ printf( "PUBLIC\t%s\n", pmn->pFromNode->pchFunctionName);
+
+ //printf( "\nDGROUP\tGROUP\t_DATA\n");
+
+ printf( "\n%s\tSEGMENT\tDWORD USE32 PUBLIC '%s'\n",
+ CODE32_NAME, CODE32_CLASS);
+ for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping) {
+ pFNode = pmn->pToNode;
+ if( pFNode->iCallType == TYPE_API32)
+ printf( "EXTRN\t%s:NEAR\n", pFNode->pchFunctionName);
+ }
+ printf( "EXTRN\tSELTOFLAT:NEAR\n");
+ if( fExistsTo16) {
+ printf( "EXTRN\tGETTHUNKID32:NEAR\n");
+ printf( "EXTRN\tMAPLS32:NEAR\n");
+ printf( "EXTRN\tUNMAPLS32:NEAR\n");
+ printf( "EXTRN\tGETSTACK32:NEAR\n");
+ printf( "EXTRN\tRELEASESTACK32:NEAR\n");
+ }
+ printf( "%s\tENDS\n\n", CODE32_NAME);
+
+ printf( "%s\tSEGMENT\tDWORD USE32 PUBLIC '%s'\n",DATA32_NAME, DATA32_CLASS);
+ if( fExistsTo16) {
+ printf( "EXTRN\tSTACK16SELECTOR:WORD\n");
+ printf( "EXTRN\tSTACK16INITIALOFFSET:DWORD\n");
+ //printf( "EXTRN\t%s:DWORD\n", pszGDISemName);
+ }
+ if( fLocalHeapUsed) {
+ printf( "EXTRN\tDS16LOCALHEAPSELECTOR:WORD\n");
+ printf( "EXTRN\tDS16LOCALHEAPBASE:DWORD\n");
+
+ }
+ printf( "%s\tENDS\n\n",DATA32_NAME);
+
+ printf( "%s\tSEGMENT\tWORD USE16 PUBLIC '%s'\n",CODE16_NAME,CODE16_CLASS);
+ for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping) {
+ pFNode = pmn->pToNode;
+ if( pFNode->iCallType == TYPE_API16)
+ printf( "EXTRN\t%s:FAR\n", pFNode->pchFunctionName);
+ }
+ printf( "%s\tENDS\n\n", CODE16_NAME);
+}
+
+
+/*** cod_OutputEpilog(pMT)
+ *
+ * Outputs any code that belongs at the end of the source file.
+ *
+ * Entry: pMT - pointer to the list of mapnodes.
+ *
+ * Exit: code for end of source file is generated.
+ */
+
+void cod_OutputEpilog( MapNode *pMT)
+
+{
+ printf("\n\n\tEND\n");
+}
+
+
+/*** cod_ExistsToType
+ *
+ * This function returns TRUE iff one of the mapnodes in the list
+ * has a ToNode of the indicated type.
+ *
+ */
+
+BOOL
+cod_ExistsToType( MapNode *pmnFirst, // pointer to the list of mapnodes
+ int iCallType) // type of sought ToNode
+{
+ register MapNode *pmn;
+
+ for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping) {
+ if( pmn->pToNode->iCallType == iCallType)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+
+/*** cod_CountPointerParameters
+ *
+ * This function returns the number of pointers in a procedure. If the
+ * fStructOnly is set, it will only return the number of pointers to
+ * structures.
+ *
+ * Entry: pTT - pointer to the first TypeNode in the type table.
+ * fStructOnly - 1 = only count structure pointers.
+ * 0 = count all pointers.
+ *
+ * Exit: returns the number of pointers in a procedure.
+ *
+ * History:
+ * 28-Nov-1988 JulieB Created it.
+ * 14-Dec-1988 Kevinro Added recursion to include imbedded pointers
+ * 02-Feb-1989 Kevinro Added structure flag
+ */
+
+int cod_CountPointerParameters(TypeNode *pTT,
+ int fStructOnly)
+
+{
+ register TypeNode *pTNode; /* pointer to a TypeNode */
+ register int iNumPtrs = 0; /* number of pointer parameters */
+
+
+ for (pTNode = pTT; pTNode != NULL; pTNode = pTNode->pNextNode) {
+ if (pTNode->iPointerType) {
+ if (!fStructOnly) {
+ pTNode->iPointerNumber=iNumPtrs++;
+ }
+ else if (pTNode->iBaseType == TYPE_STRUCT) {
+ pTNode->iPointerNumber=iNumPtrs++;
+ }
+ }
+ if (pTNode->iBaseType == TYPE_STRUCT) {
+ iNumPtrs +=
+ cod_CountPointerParameters(pTNode->pStructElems,fStructOnly);
+ }
+ if (iNumPtrs > 32) {
+ fprintf(stderr,"Too many pointer parameters - limit is 32\n");
+ break;
+ }
+ }
+ return (iNumPtrs);
+}
+
+
+/*** cod_CountParameterBytes(pTT, iDefSize)
+ *
+ * This function returns the number of bytes in a parameter list.
+ *
+ * Entry: pTT - pointer to the first TypeNode in the type table.
+ * DefSize - parameter default size - based on whether API16 (2)
+ * or API32 (4).
+ *
+ * Exit: returns number of bytes in parameter list.
+ *
+ * History:
+ * 28-Nov-1988 JulieB Created it.
+ * 08-Mar-1991 KevinR skip deleted nodes
+ */
+
+unsigned int cod_CountParameterBytes( TypeNode *pTT, unsigned int uiDefSize)
+
+{
+ register TypeNode *pTNode; /* pointer to a TypeNode */
+ register unsigned int uiNumBytes = 0; /* number of parameter bytes */
+
+
+ for (pTNode = pTT; pTNode; pTNode = pTNode->pNextNode) {
+ if( !pTNode->iDeleted) {
+ uiNumBytes += pTNode->iPointerType ?
+ DWORD_SIZE :
+ MAX( pTNode->iBaseDataSize, uiDefSize);
+ }
+ }
+ return uiNumBytes;
+}
+
+
+/*** cod_MakeFixupRecord(pParent,pFrom,pTo)
+ *
+ * This function will allocate and fill in a FixupRec. It will then
+ * return a pointer to the new record.
+ *
+ * Entry: pParent - Parent Node
+ * pFrom - From node
+ * pTo - To Node
+ *
+ * Exit: Returns the pointer to the new fixup record.
+ */
+
+FixupRec *cod_MakeFixupRecord(TypeNode *pParentFrom,
+ TypeNode *pParentTo,
+ TypeNode *pFrom,
+ TypeNode *pTo)
+
+{
+ FixupRec *temp = NULL;
+
+
+ temp = (FixupRec *) malloc(sizeof(FixupRec));
+ if (temp) {
+ temp->pParentFrom = pParentFrom;
+ temp->pParentTo = pParentTo;
+ temp->pFrom = pFrom;
+ temp->pTo = pTo;
+ temp->pNextRec = NULL;
+ } else {
+ fatal("cod_MakeFixupRecord failed memory allocation");
+ }
+ return (temp);
+}
+
+
+/*** cod_AddFixupRecord(ppList, pFR)
+ *
+ * This routine will add the fixup record pFR to the end of the current
+ * fixup record list.
+ *
+ * Entry: ppList - points to the address of a fixup record list.
+ * pFR - points to an allocated fixup record.
+ *
+ * Exit: pFR - will be appended to the end of the static list FixUps.
+ */
+
+void cod_AddFixupRecord( FixupRec **ppList, FixupRec *pFR)
+
+{
+ FixupRec *index = *ppList;
+
+
+ pFR->pNextRec = NULL;
+
+ if (index == NULL) {
+ *ppList = pFR;
+ }
+ else {
+ while (index->pNextRec)
+ index = index->pNextRec;
+ index->pNextRec = pFR;
+ }
+}
+
+
+/*** cod_GetFixupRecord(ppList)
+ *
+ * This function removes and returns the head of the ppList list.
+ *
+ * Entry: ppList - pointer to address of fixup record list.
+ *
+ * Exit: returns the pointer to the node removed from ppList. If
+ * list was empty, then it returns NULL.
+ */
+
+FixupRec * cod_GetFixupRecord( FixupRec **ppList)
+
+{
+ FixupRec *index = *ppList;
+
+
+ if (index)
+ *ppList = (*ppList)->pNextRec;
+ return (index);
+}
+
+
+/*** cod_AdjustReg(pchReg,iCurrent,iWanted)
+ *
+ * This routine will emit code that will ensure that the register named in
+ * pchReg will have the value in iWanted, based on the current value in
+ * iCurrent. This includes the ability to add or subtract from pchReg.
+ *
+ * Entry: pchReg - register name.
+ * iCurrent - pointer to current value.
+ * iWanted - value to be placed in iCurrent.
+ *
+ * Exit: generates code to adjust registers.
+ */
+
+void
+cod_AdjustReg(char *pchReg,
+ int *iCurrent,
+ int iWanted)
+
+{
+ int Delta;
+
+
+ if (*iCurrent == iWanted)
+ return;
+
+ Delta = iWanted - *iCurrent;
+ if (Delta < 0) {
+ if (Delta == -1)
+ printf("\tdec\t%s\n",pchReg);
+ else
+ printf("\tsub\t%s,%d\n",pchReg,-Delta);
+ }
+ else {
+ if (Delta == 1)
+ printf("\tinc\t%s\n",pchReg);
+ else
+ printf("\tadd\t%s,%d\n",pchReg,Delta);
+ }
+ *iCurrent = iWanted;
+}
+
+
+/*** cod_ToUpper(s)
+ *
+ * Convert string s to all upper case.
+ *
+ * Entry: s == string to convert.
+ *
+ * Exit: s == converted string.
+ */
+
+void cod_ToUpper(char *s)
+
+{
+ for( ; *s; s++)
+ *s = (char)toupper(*s);
+}
+
+
+/*** cod_PrefixUnderscore(F)
+ *
+ * Insert an underscore in front of node name.
+ *
+ * Entry: F - function node to change.
+ *
+ * Exit: underscore is inserted in front of node name.
+ */
+
+void cod_PrefixUnderscore(FunctionNode *F)
+
+{
+ char *temp;
+
+
+ if (!F)
+ fatal("cod_PrefixUnderscore(F): F is NULL");
+ temp = (char *) malloc(strlen(F->pchFunctionName) + 3);
+ sprintf(temp,"_%s",F->pchFunctionName);
+ free(F->pchFunctionName);
+ F->pchFunctionName = temp;
+}
+
+
+/*** cod_NotHandled(CHAR *pszMessage)
+ *
+ * Warn that a case is not handled by the thunk compiler.
+ * Output to stderr and the asm file.
+ *
+ * Entry: pszMessage - null-terminated message.
+ *
+ * Exit: the warning has been emitted.
+ */
+
+void cod_NotHandled(CHAR *pszMessage)
+
+{
+ fprintf( stderr, "%s, not handled\n", pszMessage);
+ printf( "\t.err\t\t\t;%s, not handled\n", pszMessage);
+}
+
+
+
+/***************************************************************************/
+/* Debugging routines */
+/***************************************************************************/
+
+
+/*** cod_DumpAllowNodes(A)
+ *
+ * This function dumps the allow node list.
+ *
+ * Entry: A - pointer to allow node.
+ *
+ * Exit: allow nodes are dumped.
+ */
+
+void cod_DumpAllowNodes(AllowNode *A)
+
+{
+ if (!A)
+ return;
+ fprintf(StdDbg,"AV: ");
+ while (A) {
+ fprintf(StdDbg,"%lxh, ",A->ulValue);
+ A = A->Next;
+ }
+}
+
+
+/*** cod_DumpTNode(T)
+ *
+ * This function dumps a type node.
+ *
+ * Entry: T - pointer to type node.
+ *
+ * Exit: type node is dumped.
+ */
+
+void cod_DumpTNode(TypeNode *T)
+
+{
+ fprintf(StdDbg,"\n%s",T->pchBaseTypeName);
+ if (T->pchIdent)
+ fprintf(StdDbg,"\t%s", T->pchIdent);
+ if (T->iArraySize > 1)
+ fprintf(StdDbg,"[%u]",T->iArraySize);
+ fprintf(StdDbg,"\tStructOffset = %u",T->iStructOffset);
+ if (T->iBaseType == TYPE_STRUCT)
+ cod_DumpTNodeList(T->pStructElems);
+ if (T->fSemantics != SEMANTIC_INPUT)
+ fprintf(StdDbg, "\tfSemantics = 0x%x", T->fSemantics);
+}
+
+
+/*** cod_DumpTNodeList(T)
+ *
+ * This function dumps the list of type nodes.
+ *
+ * Entry: T - pointer to type node list.
+ *
+ * Exit: type nodes are dumped.
+ */
+
+void cod_DumpTNodeList(TypeNode *T)
+
+{
+ while (T) {
+ cod_DumpTNode(T);
+ T = T->pNextNode;
+ }
+}
+
+
+/*** cod_DumpStructures(T)
+ *
+ * This function dumps the structures of a given type node.
+ *
+ * Entry: T - pointer to type node.
+ *
+ * Exit: type node structures are dumped.
+ */
+
+void cod_DumpStructures(TypeNode *T)
+
+{
+ sym_DumpTNodeList(T);
+}
+
+
+/*** cod_DumpTypes(F)
+ *
+ * This function dumps all types associated with function node.
+ *
+ * Entry: F - pointer to function node.
+ *
+ * Exit: type nodes associated with given function node are dumped.
+ */
+
+void cod_DumpTypes(FunctionNode *F)
+
+{
+ TypeNode *t;
+
+
+ fprintf(StdDbg,"\n\ncod_DumpTypes for function %s\n\n",F->pchFunctionName);
+
+ t = F->ParamList;
+ while (t) {
+ fprintf(StdDbg,"%s offset = %u",typ_NonNull(t->pchIdent),t->iOffset);
+ if (t->iPointerType)
+ fprintf(StdDbg,"\ttemp offset = %u ",t->iTempOffset);
+ fprintf(StdDbg,"\tiBaseDataSize = %u",t->iBaseDataSize);
+ fprintf(StdDbg,"\t%s",t->iDeleted?"DELETED\t":"");
+ cod_DumpAllowNodes(t->AllowList);
+ t = t->pNextNode;
+ }
+ fprintf(StdDbg,"\n");
+}
+
+
+/*** cod_DumpMapTable(pMT)
+ *
+ * This function dumps the map table.
+ *
+ * Entry: pMT - pointer to map table.
+ *
+ * Exit: map table is dumped.
+ */
+
+void cod_DumpMapTable(MapNode *pMT)
+
+{
+ MapNode *Diver;
+
+
+ fprintf(StdDbg,"\n\nDump of Mapping Table\n");
+
+ for (; pMT; pMT = pMT->pNextMapping) {
+ fprintf(StdDbg,"\nParent %s => %s\n",
+ pMT->pFromNode->pchFunctionName,
+ pMT->pToNode->pchFunctionName);
+
+ Diver = pMT->pFamily;
+
+ for (; Diver; Diver = Diver->pNextMapping) {
+ fprintf(StdDbg,"\tChild %s => %s\n",
+ Diver->pFromNode->pchFunctionName,
+ Diver->pToNode->pchFunctionName);
+
+ if (Diver->pFamily) {
+ fprintf(StdDbg,"**** Error: Child has children *****");
+ cod_DumpMapTable(Diver->pFamily);
+ fprintf(StdDbg,"**** End Error Message *****");
+ }
+ }
+ }
+}
diff --git a/private/os2/client/thunk/thunkcom/codegen.h b/private/os2/client/thunk/thunkcom/codegen.h
new file mode 100644
index 000000000..4a0634500
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/codegen.h
@@ -0,0 +1,99 @@
+/* SCCSID = @(#)codegen.h 13.13 90/08/28 */
+
+/*
+ * Thunk Compiler Code Generator Declarations
+ *
+ * Written 10/15/88 by Kevin Ross
+ * Copyright (c) 1988 Microsoft Corp. All rights reserved.
+ *
+ * History:
+ * 28-Nov-1988 JulieB Added gen_LabelCount and MAX macro.
+ */
+
+
+
+/*
+ * Fixup Record structure.
+ */
+typedef struct _FixupRec {
+
+ TypeNode *pParentFrom,
+ *pParentTo,
+ *pFrom,
+ *pTo;
+ struct _FixupRec *pNextRec;
+
+} FixupRec;
+
+
+/*
+ * Extern Declarations.
+ */
+extern void gen_GenerateCode();
+extern int DumpTables;
+extern unsigned int gEDI,gESI;
+extern unsigned int gTransferBytes;
+
+extern FunctionNode *pGlobal_To,*pGlobal_From;
+
+extern unsigned int gen_LabelCount;
+
+extern FixupRec * cod_MakeFixupRecord();
+extern FixupRec * cod_GetFixupRecord();
+
+extern unsigned int iStackOverhead;
+extern unsigned int iAllocOffset,iBMPOffset,iAliasOffset,iTempStoreOffset,
+ iReturnValOffset,iSavedRegOffset,iErrorOffset,
+ iStackThunkIDOffset, iPtrThunkIDOffset;
+extern FILE *StdDbg;
+
+
+/*
+ * Definitions.
+ */
+#define PUSH_LEFT 0
+#define PUSH_RIGHT 1
+
+#define BYTE_SIZE 1
+#define WORD_SIZE 2
+#define DWORD_SIZE 4
+
+#define SIZE_TINY 1 /* Tiny items pushed on stack */
+#define SIZE_SMALL 2 /* small items use block allocation */
+#define SIZE_MEDIUM 3 /* medium items use aliasing */
+#define SIZE_LARGE 4 /* large items may need copying */
+
+#define SIZE_FIXED 100 /* Flags used in boundary crossing code */
+#define SIZE_VARIABLE 101
+
+#define SMALL_ITEM 32 /* 32 bytes or less */
+#define MEDIUM_ITEM 128 /* 128 bytes or less */
+#define LARGE_ITEM 61439 /* 60k-1 or less */
+
+#define DIVIDE_COMMENT( cond, comment) { \
+ if( cond) \
+ printf( "\n;--------------------------------------\n"); \
+ printf( "; " comment "\n\n"); \
+}
+
+
+#define BIG_DIVIDE printf( ";=====================================" \
+ "======================================\n");
+
+#define MED_DIVIDE printf( ";-------------------------------------" \
+ "--------------------------------------\n");
+
+#define SML_DIVIDE printf( ";-------------------------------------\n");
+
+
+/* only works for arg>0 */
+#define ROUND_UP_MOD( arg, mod) (arg + mod - 1 - ((arg + mod - 1) % mod))
+
+
+
+
+#define gDosAllocFlags 0x053 /* COMMIT & TILE & READ & WRITE */
+
+#define Align(Address,Boundary) ((Address % Boundary) ? \
+ Address + (Boundary - (Address % Boundary)): \
+ Address)
diff --git a/private/os2/client/thunk/thunkcom/combine.c b/private/os2/client/thunk/thunkcom/combine.c
new file mode 100644
index 000000000..45b189ea5
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/combine.c
@@ -0,0 +1,209 @@
+/*
+ * Thunk Compiler - Combine Common Functions.
+ *
+ * This is an OS/2 2.x specific file
+ * Microsoft Confidential
+ *
+ * Copyright (c) Microsoft Corporation 1987, 1988, 1989
+ *
+ * All Rights Reserved
+ *
+ * Written 06/22/89 by Kevin Ross
+ */
+
+
+#include <stdio.h>
+#include "error.h"
+#include "thunk.h"
+#include "types.h"
+#include "symtab.h"
+#include "codegen.h"
+
+
+/*** cod_CombineFunctions(pMT)
+ *
+ * This function will traverse the MappingTable pMT and rearrange it so
+ * that all functions that are compatible will be grouped together.
+ *
+ * This will optimize the way that code is generated.
+ *
+ * Entry: pMt is the pointer to the map table.
+ *
+ * Exit: all compatible functions are grouped.
+ */
+
+void cod_CombineFunctions(MapNode *pMT)
+
+{
+ MapNode *pCurrentMt = NULL,
+ *pCheckMt = NULL,
+ *pPrevMt = NULL;
+
+
+ pCurrentMt = pMT;
+ for( ;pCurrentMt; pCurrentMt=pCurrentMt->pNextMapping) {
+ pCheckMt = pCurrentMt->pNextMapping;
+ pPrevMt = pCurrentMt;
+ for (; pCheckMt; pPrevMt=pCheckMt,pCheckMt=pCheckMt->pNextMapping) {
+ if (cod_CombinePossible(pCurrentMt,pCheckMt)) {
+ pPrevMt->pNextMapping = pCheckMt->pNextMapping;
+ pCheckMt->pNextMapping = pCurrentMt->pFamily;
+ pCurrentMt->pFamily = pCheckMt;
+ pCheckMt = pPrevMt;
+ }
+ }
+ }
+}
+
+
+/*** cod_CombinePossible(pCurrentMt, pCheckMt)
+ *
+ * This function returns whether or not the two mappings are
+ * compatible.
+ *
+ * Entry: pCurrentMt is the pointer to the current map table.
+ * pCheckMt is the pointer to map table to check.
+ *
+ * Exit: Return 0 IFF functions are NOT compatible.
+ * Return 1 IFF functions ARE compatible.
+ */
+
+int cod_CombinePossible(MapNode *pCurrentMt,
+ MapNode *pCheckMt)
+
+{
+ return cod_FunctionCompatible(pCurrentMt->pFromNode,pCheckMt->pFromNode) &&
+ cod_FunctionCompatible(pCurrentMt->pToNode,pCheckMt->pToNode);
+}
+
+
+/*** cod_AllowListCheck(pA, pB)
+ *
+ * This function checks the allow list.
+ *
+ * Entry: pA and pB are the two allow nodes.
+ *
+ * Exit: Return 0 IFF allownodes are NOT equal.
+ * Return 1 IFF allownodes ARE equal.
+ */
+
+int cod_AllowListCheck(AllowNode *pA,
+ AllowNode *pB)
+
+{
+ while ((pA && pB) && (pA->ulValue == pB->ulValue)) {
+ pA = pA->Next;
+ pB = pB->Next;
+ }
+ return (pA == pB);
+}
+
+
+/*** cod_AllowListCompat(pA, pB)
+ *
+ * This function checks to see that the allow lists for the
+ * parameters are compatible.
+ *
+ * Entry: pA and pB are the two function nodes.
+ *
+ * Exit: Return 0 IFF typenodes are NOT equal.
+ * Return 1 IFF typenodes ARE equal.
+ */
+
+int cod_AllowListCompat(FunctionNode *pA,
+ FunctionNode *pB)
+
+{
+ TypeNode *ptA,*ptB;
+
+
+ ptA = pA->ParamList;
+ ptB = pB->ParamList;
+
+ while (ptA && ptB) {
+ if (ptA->AllowList && ptB->AllowList) {
+ if (! cod_AllowListCheck(ptA->AllowList,ptB->AllowList))
+ return 0;
+ }
+ else if (ptA->AllowList != ptB->AllowList)
+ return 0;
+
+ ptA = ptA->pNextNode;
+ ptB = ptB->pNextNode;
+ }
+ return (ptA == ptB);
+}
+
+
+/*** cod_FunctionCompatible(pA, pB)
+ *
+ * This function checks to see that the return types, the parameter
+ * list types and the allow lists are compatible.
+ *
+ * Entry: pA and pB are the two function nodes.
+ *
+ * Exit: Return 0 IFF types and allow lists are NOT equal.
+ * Return 1 IFF types and allow lists ARE equal.
+ */
+
+int cod_FunctionCompatible(FunctionNode *pA,
+ FunctionNode *pB)
+
+{
+ if ( (pA->iCallType != pB->iCallType) ||
+ (pA->fSysCall != pB->fSysCall) ||
+ (pA->iMinStack != pB->iMinStack) ||
+ (pA->fSemantics != pB->fSemantics) ||
+ (pA->ulErrNoMem != pB->ulErrNoMem) ||
+ (pA->ulErrBadParam != pB->ulErrBadParam) ||
+ (pA->fInlineCode != pB->fInlineCode) )
+ return (0);
+
+ return ( cod_TypesCompatible(pA->ReturnType,pB->ReturnType) &&
+ cod_TypesCompatible(pA->ParamList,pB->ParamList) &&
+ cod_AllowListCompat(pA,pB) );
+}
+
+
+/*** cod_TypesCompatible(pA, pB)
+ *
+ * This function checks to see that the types and structures
+ * are compatible.
+ *
+ * Entry: pA and pB are the two type nodes.
+ *
+ * Exit: Return 0 IFF types are NOT compatible.
+ * Return 1 IFF types ARE compatible.
+ */
+
+int cod_TypesCompatible(TypeNode *pF,
+ TypeNode *pT)
+
+{
+ if (!pF && !pT)
+ return 1;
+
+ if (!pF || !pT)
+ return 0;
+
+ if ( (pF->iBaseType != pT->iBaseType) ||
+ ((pF->iBaseType == TYPE_STRUCT) &&
+ (pF->iAlignment != pT->iAlignment)) ||
+ (pF->iArraySize != pT->iArraySize) ||
+ (pF->iDeleted != pT->iDeleted) ||
+ ((pF->iDeleted) && (pF->iFillValue != pT->iFillValue)) ||
+ (pF->fSemantics != pT->fSemantics) ||
+ (pF->iPointerType != pT->iPointerType) ||
+ ((pF->pSizeParam || pT->pSizeParam) &&
+ !(pF->pSizeParam && pT->pSizeParam)))
+ return 0;
+
+ if (!cod_TypesCompatible(pF->pNextNode,pT->pNextNode))
+ return 0;
+
+ if (pF->iBaseType == TYPE_STRUCT)
+ if (!cod_TypesCompatible(pF->pStructElems,pT->pStructElems))
+ return 0;
+
+ return 1;
+}
diff --git a/private/os2/client/thunk/thunkcom/error.c b/private/os2/client/thunk/thunkcom/error.c
new file mode 100644
index 000000000..00086fb2f
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/error.c
@@ -0,0 +1,105 @@
+/*
+ * Thunk Compiler - Routines to Print Out Error Messages.
+ *
+ * ABSTRACT:
+ * Routines to print out error messages.
+ * Exports variables;
+ * errors - the total number of errors encountered
+ * Exports routines:
+ * fatal, warn, error, unix_error_string, set_program_name
+ *
+ * $Header: error.c,v 1.4 87/08/03 13:13:18 mach Exp $
+ *
+ * HISTORY:
+ * 28-May-87 Rich Draves @ Carnegie Mellon Created.
+ *
+ * 07-Oct-88 Kevin Ross @ Microsoft Corp
+ * Modified to use System V varargs.h routines.
+ * 17-Oct-90 Kevin Ruddell @ Microsoft Corp
+ * Modified to use ANSI stdarg.h routines.
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "thunk.h"
+#include "error.h"
+
+
+static char *program;
+int errors = 0;
+
+/*ARGSUSED*/
+/*VARARGS1*/
+void fatal( char *format, ...)
+{
+ va_list marker;
+
+ va_start( marker, format);
+
+ fprintf( stderr, "%s: fatal: ", program);
+ vfprintf( stderr, format, marker);
+ fprintf( stderr, "\n\n");
+
+ va_end( marker);
+
+ exit( 1);
+}
+
+/*ARGSUSED*/
+/*VARARGS1*/
+void warn( char *format, ...)
+{
+ va_list marker;
+
+ va_start( marker, format);
+ if (!BeQuiet && (errors == 0)) {
+ fprintf( stderr, "%s(%d): warning: ", yyinname, yylineno-1);
+ vfprintf( stderr, format, marker);
+ fprintf( stderr, "\n");
+ }
+ va_end( marker);
+}
+
+/*ARGSUSED*/
+/*VARARGS1*/
+void error( char *format, ...)
+{
+ va_list marker;
+
+ va_start( marker, format);
+ fprintf( stderr, "%s(%d): error: ", yyinname, yylineno-1);
+ vfprintf( stderr, format, marker);
+ fprintf( stderr, "\n");
+
+ va_end( marker);
+ errors++;
+}
+
+#if 0
+char *
+unix_error_string(errno)
+ int errno;
+{
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ static char buffer[256];
+ char *error_mess;
+
+ if ((0 <= errno) && (errno < sys_nerr))
+ error_mess = sys_errlist[errno];
+ else
+ error_mess = "strange errno";
+
+ sprintf(buffer, "%s (%d)", error_mess, errno);
+ return buffer;
+}
+#endif
+
+void set_program_name( char *name)
+{
+ program = name;
+}
diff --git a/private/os2/client/thunk/thunkcom/error.h b/private/os2/client/thunk/thunkcom/error.h
new file mode 100644
index 000000000..df6b3f57a
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/error.h
@@ -0,0 +1,23 @@
+/*
+ * Thunk Compiler Error Declarations
+ *
+ * Copyright (c) 1988, 1989, 1990 Microsoft Corp. All rights reserved.
+ */
+
+
+
+#ifndef _ERROR_
+#define _ERROR_
+
+extern int errors;
+#if 0
+extern int errno;
+
+extern void fatal( char *format, va_list);
+extern void warn( char *format, va_list);
+extern void error( char *format, va_list);
+extern char *unix_error_string( int);
+extern void set_program_name( char *name);
+#endif
+
+#endif
diff --git a/private/os2/client/thunk/thunkcom/fprot.h b/private/os2/client/thunk/thunkcom/fprot.h
new file mode 100644
index 000000000..f7bf48a66
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/fprot.h
@@ -0,0 +1,173 @@
+// mtcpars.c
+void yyerror(char *s);
+int yyparse(void);
+//
+// mtclex.c
+int yylex(void);
+void PushInclude(char *yyFile);
+void LookNormal(void);
+int yywrap(void);
+int yylook(void);
+int yyback(int *p,int m);
+int yyinput(void);
+void yyoutput(int c);
+void yyunput(int c);
+//
+// codegen.c
+void cod_GenerateCode(struct _MapNode *pmnFirst);
+void cod_ConvertNames(struct _MapNode *pMT);
+int cod_StructOffset(struct _TypeNode *pTNode,int iPrev,int iAlign);
+int cod_FindLargestSize(struct _TypeNode *pTN);
+void cod_CalcStructOffsets(struct _TypeNode *pTNode,int iAlign);
+int cod_CalcTempOffset(struct _TypeNode *pTL,unsigned int iStart);
+int cod_CalcOffset(struct _TypeNode *pTL,int start,int iPSize,int fPushDir);
+static void cod_OutputProlog(struct _MapNode *pmnFirst);
+void cod_OutputEpilog(struct _MapNode *pMT);
+unsigned short cod_ExistsToType(struct _MapNode *pmnFirst,int iCallType);
+int cod_CountPointerParameters(struct _TypeNode *pTT,int fStructOnly);
+unsigned int cod_CountParameterBytes(struct _TypeNode *pTT,unsigned int uiDefSize);
+struct _FixupRec *cod_MakeFixupRecord(struct _TypeNode *pParentFrom,struct _TypeNode *pParentTo,struct _TypeNode *pFrom,struct _TypeNode *pTo);
+void cod_AddFixupRecord(struct _FixupRec * *ppList,struct _FixupRec *pFR);
+struct _FixupRec *cod_GetFixupRecord(struct _FixupRec * *ppList);
+void cod_AdjustReg(char *pchReg,int *iCurrent,int iWanted);
+void cod_ToUpper(char *s);
+void cod_PrefixUnderscore(struct _Fnode *F);
+void cod_NotHandled(char *pszMessage);
+void cod_DumpAllowNodes(struct _AllowNode *A);
+void cod_DumpTNode(struct _TypeNode *T);
+void cod_DumpTNodeList(struct _TypeNode *T);
+void cod_DumpStructures(struct _TypeNode *T);
+void cod_DumpTypes(struct _Fnode *F);
+void cod_DumpMapTable(struct _MapNode *pMT);
+//
+// cod1632.c
+void cod16_EnableMapDirect(int iCallTypeFrom,int iCallTypeTo);
+void cod16_Handle16(struct _MapNode *pmnFirst);
+void cod16_Prolog32(struct _MapNode *pmnFirst);
+void cod16_Epilog32(struct _MapNode *pmnFirst);
+void cod16_Handle32(struct _MapNode *pmn);
+void cod16_Entry(struct _MapNode *pmn);
+void cod16_TempStorage(struct _MapNode *pmn);
+void cod16_PackParams(struct _MapNode *pmn);
+void cod16_PackPointer(struct _TypeNode *ptnFrom,struct _TypeNode *ptnTo);
+void cod16_SelToFlat(void);
+void cod16_StructureRepack(struct _TypeNode *ptnFrom,struct _TypeNode *ptnTo);
+void cod16_RepackElems(struct _TypeNode *ptnFrom,struct _TypeNode *ptnTo);
+void cod16_CopyFixedBlock(unsigned int uiSize);
+void cod16_CallFrame(struct _MapNode *pmn);
+void cod16_Return(struct _MapNode *pmn);
+void cod16_UnpackParams(struct _MapNode *pmn);
+void cod16_UnpackPointer(struct _TypeNode *ptnFrom,struct _TypeNode *ptnTo);
+void cod16_StructureUnpack(struct _TypeNode *ptnFrom,struct _TypeNode *ptnTo);
+void cod16_Exit(struct _MapNode *pmn,unsigned short fUseDI,unsigned short fUseSI);
+void cod16_GenRet16(unsigned int uiParameterBytes,unsigned short fUseDI,unsigned short fUseSI);
+//
+// cod1632b.c
+unsigned short cod16_PackParamSpecial(struct _MapNode *pmn,struct _TypeNode *ptnFrom,struct _TypeNode *ptnTo);
+unsigned short cod16_PushParamSpecial(struct _MapNode *pmn,struct _TypeNode *ptnFrom,struct _TypeNode *ptnTo);
+unsigned short cod16_ReturnSpecial(struct _MapNode *pmn);
+unsigned short cod16_UnpackParamSpecial(struct _MapNode *pmn,struct _TypeNode *ptnFrom,struct _TypeNode *ptnTo);
+void cod16_AllocBlock(unsigned long flFlags,unsigned long ulUnitSize);
+//
+// thunk.c
+static void parseArgs(int *argcPtr,char * * *argvPtr);
+void Usage(void);
+void main(int argc,char * *argv);
+//
+// types.c
+struct _TypeNode *typ_MakeTypeNode(int BT);
+struct _AllowNode *typ_MakeAllowNode(unsigned long Val);
+struct _TypeNode *typ_CopyTypeNode(struct _TypeNode *N);
+struct _TypeNode *typ_CopyStructNode(struct _TypeNode *pOldNode);
+struct _Fnode *typ_MakeFunctionNode(int CT,struct _TypeNode *RT,char *Name,struct _TypeNode *PL);
+int typ_CountParams(struct _TypeNode *T);
+int typ_StructsCanMap(struct _TypeNode *T1,struct _TypeNode *T2);
+int typ_TypesCanMap(struct _TypeNode *T1,struct _TypeNode *T2);
+int typ_FunctionsCanMap(struct _Fnode *F1,struct _Fnode *F2);
+void typ_CheckDefaultTypes(struct _TypeNode *T1,struct _TypeNode *T2,int CT1,int CT2);
+void typ_CheckIntType(struct _TypeNode *T1,int CT1);
+int typ_TypesIdentical(struct _TypeNode *T1,struct _TypeNode *T2);
+int typ_TypeIdentical(struct _TypeNode *T1,struct _TypeNode *T2);
+int typ_CheckSemantics(struct _TypeNode *T1,struct _TypeNode *T2);
+int typ_CheckRestrict(struct _TypeNode *T1,struct _TypeNode *T2);
+void typ_InheritSemantics(struct _TypeNode *T1,struct _TypeNode *T2,int fSems);
+unsigned short typ_QuerySemanticsUsed(struct _MapNode *pmn,int fSems);
+int typ_StructHasPointers(struct _TypeNode *T1,struct _TypeNode *T2);
+struct _TypeNode *typ_FindFirstPointer(struct _TypeNode *ptn,unsigned short fSkipDeleted);
+struct _TypeNode *typ_FindNextPointer(struct _TypeNode *ptn,unsigned short fSkipDeleted);
+void typ_EvalHandleType(struct _TypeNode *ptn);
+char *typ_GetHandleTypeName(unsigned long flHandleType);
+unsigned short typ_ByteToByte(struct _TypeNode *ptnFrom,struct _TypeNode *ptnTo);
+unsigned short typ_WordToWord(struct _TypeNode *ptnFrom,struct _TypeNode *ptnTo);
+//
+// error.c
+void fatal(char *format,...);
+void warn(char *format,...);
+void error(char *format,...);
+void set_program_name(char *name);
+//
+// symtab.c
+void sym_SymTabInit(void);
+struct _TypeNode *sym_FindSymbolTypeNode(struct _TypeNode *pTab,char *pchSym);
+int sym_FindSymbolTypeNodePair(struct _TypeNode *pTab1,struct _TypeNode *pTab2,struct _TypeNode * *ppT1,struct _TypeNode * *ppT2,char *pchSym);
+struct _Fnode *sym_FindSymbolFunctionNode(struct _Fnode *pTab,char *pchSym);
+void sym_InsertTypeNode(struct _TypeNode * *ppTab,struct _TypeNode *pNode);
+void sym_InsertFunctionNode(struct _Fnode * *ppTab,struct _Fnode *pFNode);
+struct _TypeNode *sym_ReverseTypeList(struct _TypeNode *pOld);
+struct _MapNode *sym_FindFMapping(struct _MapNode *pMapTab,char *pSymA,char *pSymB);
+struct _MapNode *sym_AddFMapping(struct _MapNode * *ppMapTab,struct _Fnode *pFuncA,struct _Fnode *pFuncB);
+void sym_DumpFNode(struct _Fnode *F);
+void sym_DumpFNodeList(struct _Fnode *F);
+void sym_DumpTNode(struct _TypeNode *T);
+void sym_DumpTNodeList(struct _TypeNode *T);
+void sym_DumpSemantics(struct _TypeNode *T);
+void sym_DumpFMappingList(struct _MapNode *M);
+//
+// cod3216.c
+void cod_Handle3216(struct _MapNode *pMNode);
+void cod_Entry32(struct _MapNode *pMNode);
+int cod_PointerHandler32(struct _MapNode *pMNode);
+int cod32_HandlePointer(struct _TypeNode *pFrom,struct _TypeNode *pTo);
+void cod32_HandleStructureBuffer(struct _TypeNode *pFrom,struct _TypeNode *pTo);
+int cod32_HandleAllowList(struct _AllowNode *AllowList,int AllowLabel);
+int cod32_HandleRestricted(struct _TypeNode *pFrom);
+int cod32_CopyConvertBuffer(struct _TypeNode *pFrom,struct _TypeNode *pTo);
+void cod32_StructureRepack(struct _TypeNode *pBaseFrom,struct _TypeNode *pBaseTo);
+int cod32_RepackElements(struct _TypeNode *pParentFrom,struct _TypeNode *pParentTo,struct _TypeNode *pFrom,struct _TypeNode *pTo,struct _FixupRec * *pFixupList);
+void cod32_HandleBoundaryCross(unsigned int fSize,struct _TypeNode *pFrom,unsigned int iSize);
+void cod32_HandleFixedSize(unsigned int iSize,struct _TypeNode *pFrom);
+int cod32_AllocateVariableSize(struct _TypeNode *pFrom,unsigned int iSize);
+int cod32_AllocFixedSize(unsigned int iSize,struct _TypeNode *pFrom);
+int cod32_DeAllocFixedSize(unsigned int iSize,struct _TypeNode *pFromNode);
+void cod32_CopyConvert(struct _TypeNode *pFromNode,struct _TypeNode *pToNode);
+void cod32_TransferBlock(int Count);
+int cod32_VariableLengthCopy(void);
+int cod_CallFrame32(struct _MapNode *pMNode);
+int cod_PushParameters32(struct _TypeNode *pFromNode,struct _TypeNode *pToNode);
+int cod_Return32(struct _MapNode *pMNode);
+int cod_CallStub32(struct _MapNode *pMNode);
+//
+// cod3216b.c
+int cod_UnpackStruct32(struct _MapNode *pMNode);
+int cod32_UnHandlePointer(struct _TypeNode *pFrom,struct _TypeNode *pTo);
+int cod32_UnHandleStructureBuffer(struct _TypeNode *pFrom,struct _TypeNode *pTo);
+void cod32_UnHandleBoundaryCross(unsigned int fSize,struct _TypeNode *pFrom,unsigned int iSize);
+void cod32_UnHandleFixedSize(unsigned int iSize,struct _TypeNode *pFrom);
+int cod32_UnStructureRepack(struct _TypeNode *pBaseFrom,struct _TypeNode *pBaseTo);
+int cod32_UnRepackElements(struct _TypeNode *pParentFrom,struct _TypeNode *pParentTo,struct _TypeNode *pFrom,struct _TypeNode *pTo,struct _FixupRec * *pFixupList);
+int cod32_UnCopyConvertBuffer(struct _TypeNode *pFrom,struct _TypeNode *pTo);
+//
+// cod3216g.c
+void cod32_HandlePointerGDI(struct _TypeNode *ptnFrom,struct _TypeNode *ptnTo);
+int cod32_PushParametersGDI(struct _TypeNode *pFromNode,struct _TypeNode *pToNode);
+void cod32_StructureRepackGDI(struct _TypeNode *ptnBaseFrom,struct _TypeNode *ptnBaseTo);
+int cod32_UnpackStructGDI(struct _MapNode *pMNode);
+//
+// combine.c
+void cod_CombineFunctions(struct _MapNode *pMT);
+int cod_CombinePossible(struct _MapNode *pCurrentMt,struct _MapNode *pCheckMt);
+int cod_AllowListCheck(struct _AllowNode *pA,struct _AllowNode *pB);
+int cod_AllowListCompat(struct _Fnode *pA,struct _Fnode *pB);
+int cod_FunctionCompatible(struct _Fnode *pA,struct _Fnode *pB);
+int cod_TypesCompatible(struct _TypeNode *pF,struct _TypeNode *pT);
+//
diff --git a/private/os2/client/thunk/thunkcom/globals.c b/private/os2/client/thunk/thunkcom/globals.c
new file mode 100644
index 000000000..eb815fa4e
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/globals.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+#include "error.h"
+#include "thunk.h"
+#include "types.h"
+#include "symtab.h"
+
+
+
+BOOL fGDIAllocUsed;
+BOOL fMapTo16Used;
+BOOL fLocalHeapUsed;
+
+// 16=>32
+INT iStackCurrent;
+UINT uiGenLabel = 0;
+BOOL afFromNodeBytesUsed[ 200];
+BOOL fPackedPointReturned;
+BOOL fSaveEAX;
+BOOL fSaveEDX;
+INT iXRCTempOffset, iYRCTempOffset;
+BOOL fEnableMapDirect1632=FALSE;
+BOOL fUser=FALSE;
+BOOL fGdi=FALSE;
+BOOL fKernel=FALSE;
diff --git a/private/os2/client/thunk/thunkcom/globals.h b/private/os2/client/thunk/thunkcom/globals.h
new file mode 100644
index 000000000..465d5513f
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/globals.h
@@ -0,0 +1,16 @@
+extern BOOL fGDIAllocUsed;
+extern BOOL fMapTo16Used;
+extern BOOL fLocalHeapUsed;
+
+// 16=>32
+extern INT iStackCurrent;
+extern UINT uiGenLabel;
+extern BOOL afFromNodeBytesUsed[ 200];
+extern BOOL fPackedPointReturned;
+extern BOOL fSaveEAX;
+extern BOOL fSaveEDX;
+extern INT iXRCTempOffset, iYRCTempOffset;
+extern BOOL fEnableMapDirect1632;
+extern BOOL fUser;
+extern BOOL fGdi;
+extern BOOL fKernel;
diff --git a/private/os2/client/thunk/thunkcom/htotdl.c b/private/os2/client/thunk/thunkcom/htotdl.c
new file mode 100644
index 000000000..fb214dbf8
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/htotdl.c
@@ -0,0 +1,251 @@
+/*
+ * Thunk Compiler - H File to Thunk Description Language.
+ *
+ * This is an OS/2 2.x specific file
+ * Microsoft Confidential
+ *
+ * Copyright (c) Microsoft Corporation 1987-1991
+ *
+ * All Rights Reserved
+ *
+ * Written 12/09/88 by Kevin Ross
+ */
+
+
+/*
+ * This little program is a hack used to create thunk description
+ * language files from existing 'C' include files. It is basically a
+ * filter which is designed to read the output of the 'C' compiler when
+ * the /EP switch is used.
+ *
+ * To make this work, use the command line:
+ *
+ * cl /EP proto.c | sed s/"pascal far"// | htotdl > output.fil
+ *
+ *
+ * Where proto.c is a small file that simply includes .h files which
+ * contain the function prototypes needed to be thunked.
+ * To generate prototypes for BASE and PM, try
+ *
+ * #define INCL_BASE
+ * #define INCL_PM
+ * #include <os2.h>
+ * main() {};
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#define LINELEN 4096
+
+char API16Line[LINELEN];
+char API32Line[LINELEN];
+char InputLine[LINELEN];
+
+int InputLineIndex=0,API16Index=0,API32Index=0;
+
+
+/*** FindRightCurly()
+ *
+ * This function takes the input from the command line and looks for
+ * the right curly brace. Once the right curly brace is received, it
+ * returns success. If the end of the file is hit first, then it
+ * return error.
+ *
+ * Entry: none
+ *
+ * Exit: Return 0 IFF right curly brace is found.
+ * Return -1 IFF end of file is found.
+ */
+
+int FindRightCurly()
+
+{
+ char c;
+
+ while (1) {
+ c = getchar();
+ InputLine[InputLineIndex++] = c;
+ if (c == EOF) return -1;
+ if (c == '}') return 0;
+ }
+}
+
+
+/*** DoReplace()
+ *
+ *
+ *
+ *
+ * Entry:
+ *
+ * Exit: string is changed.
+ */
+
+DoReplace( char *pszInStart, char *pszOld, char *pszNew)
+{
+
+ char achBuffer[ LINELEN];
+ char *pszInSame, *pszInDiff, *pszOut;
+ int i, iOldLen=strlen( pszOld), iNewLen=strlen( pszNew);
+
+ if( strcmp( pszOld, pszNew)) {
+ for( pszInSame = pszInDiff = pszInStart, pszOut = achBuffer;
+ pszInDiff = strstr( pszInSame, pszOld);
+ pszInSame = pszInDiff + iOldLen) {
+ strncpy( pszOut, pszInSame, pszInDiff - pszInSame);
+ pszOut += pszInDiff - pszInSame;
+ strncpy( pszOut, pszNew, iNewLen);
+ pszOut += iNewLen;
+ }
+ strcpy( pszOut, pszInSame);
+ strcpy( pszInStart, achBuffer);
+ }
+}
+
+
+/*** SubUshort(s)
+ *
+ * This function looks for the word "ushort" in the string s.
+ * If "ushort" is not found, then "ulong " is copied to the string.
+ *
+ * Entry: s is the string.
+ *
+ * Exit: string is searched.
+ */
+
+SubUshort(char *s)
+
+{
+ while (*s) {
+ if (*s == 'U') {
+ if (!strncmp(s,"USHORT",6)) {
+ strncpy(s,"ULONG ",6);
+ }
+ }
+ s++;
+ }
+}
+
+
+/*** FillInputLine()
+ *
+ * This function fills in the buffer for the command input line.
+ *
+ * Entry: none
+ *
+ * Exit: buffer is filled in with the input line.
+ */
+
+int FillInputLine()
+
+{
+ char c;
+
+
+ InputLineIndex = 0;
+
+ while (isspace(c = getchar()));
+ if (c == EOF) return -1;
+
+ while (1) {
+ InputLine[InputLineIndex++] = c;
+ switch (c)
+ {
+ case ';': InputLine[InputLineIndex++] = '\0';
+ return (0);
+ break;
+ case '{': if (FindRightCurly())
+ return (-1);
+ break;
+ }
+ if (InputLineIndex >= LINELEN) {
+ fprintf(stderr,"Out of string space");
+ exit(1);
+ }
+ c = getchar();
+ if (c == EOF) return -1;
+ }
+}
+
+
+/*** main()
+ *
+ * This is the main driver.
+ *
+ * Entry: none
+ *
+ * Exit: thunk description language main driver is complete.
+ */
+
+main()
+
+{
+ char *cPtr;
+ int Index;
+
+
+ while (!FillInputLine()) {
+ /*
+ * If the first word on line is a typedef, then just spit it back out.
+ */
+ if (!strncmp(InputLine,"typedef",7)) {
+ printf("%s\n\n",InputLine);
+ }
+ else if (!strncmp(InputLine,"struct",6)) {
+ /*
+ * If the first word is struct, then it is supposed to be a
+ * typedef, so output a typedef, then spit out the struct
+ * definition.
+ */
+ printf("typedef %s\n\n",InputLine);
+ }
+ else {
+ /*
+ * If it isn't a typedef, then it must be a function prototype.
+ */
+ strcpy( API16Line, InputLine);
+ DoReplace( API16Line, "int", "INT");
+ DoReplace( API16Line, ";", " =");
+ DoReplace( API16Line, "(", "16(");
+ printf("%s\n",API16Line);
+
+ strcpy( API32Line, InputLine);
+ DoReplace( API32Line, "int", "INT");
+ DoReplace( API32Line, "WORD", "DWORD");
+ DoReplace( API16Line, ";", "");
+ DoReplace( API32Line, "(", "( ");
+ printf("%s\n{}\n\n",API32Line);
+
+#if 0
+ cPtr = strrchr(API16Line,';');
+ *cPtr = '=';
+ printf("%s\n",API16Line);
+
+ cPtr = strchr(InputLine,' ');
+
+ while (isspace(*cPtr))
+ cPtr++;
+
+ Index = cPtr - InputLine;
+
+ strncpy(API32Line,InputLine,Index);
+ API32Line[Index] = '\0';
+
+ strncat(API32Line,cPtr,3);
+
+ Index += 3;
+ cPtr = &InputLine[Index];
+ strcat(API32Line,"32");
+ strcat(API32Line,cPtr);
+
+ SubUshort(API32Line);
+ cPtr = strrchr(API32Line,';');
+ cPtr = '\0';
+ printf("%s\n{}\n\n",API32Line);
+#endif
+ }
+ }
+}
diff --git a/private/os2/client/thunk/thunkcom/makefile b/private/os2/client/thunk/thunkcom/makefile
new file mode 100644
index 000000000..e4e7a2ea5
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/makefile
@@ -0,0 +1,97 @@
+# Make file for thunk compiler for Win32
+#
+# 10.11.90 KevinR brought over from OS/2 2.0
+# 8 Sep 92 PatrickQ Added support for PMNT
+
+!IFDEF PMNT
+CFLAGS= /c /Zi /AL /G2s /I..\include /DPMNT
+!ELSE
+CFLAGS= /c /Zi /AL /G2s /I..\include
+!ENDIF
+LFLAGS= /CO /NOD
+CLIBS= llibcep os2286
+
+
+INCLUDES= thunk.h types.h symtab.h thunk.h error.h
+OBJS = thunk.obj types.obj error.obj symtab.obj mtcpars.obj mtclex.obj \
+ codegen.obj \
+#cod3216.obj cod3216b.obj cod3216g.obj \
+ combine.obj globals.obj cod1632.obj cod1632b.obj
+
+.c.obj:
+# cl $(CFLAGS) /W3 $*.c
+ cl $(CFLAGS) $*.c
+
+
+!IFDEF PMNT
+thunk: thunkpm.exe
+!ELSE
+thunk: thunk.exe
+!ENDIF
+
+all: thunk.exe sample16.obj sample32.obj
+
+
+!IFDEF PMNT
+thunkpm.exe: $(OBJS)
+!ELSE
+thunk.exe: $(OBJS)
+!ENDIF
+ link $(LFLAGS) $(OBJS),$@,,$(CLIBS),thunk.def;
+
+hello.exe: hello.obj
+ link $(LFLAGS) hello.obj,$@,,$(CLIBS),$*.def;
+tmp.exe: tmp.obj
+ link $(LFLAGS) tmp.obj,$@,,$(CLIBS),$*.def;
+!IFDEF copyexe
+ copy $@ ..\..\binp
+!ENDIF
+
+thunk.obj: thunk.c thunk.h
+
+error.obj: error.c error.h thunk.h
+
+types.obj: types.c types.h error.h
+
+symtab.obj: symtab.c symtab.h types.h thunk.h
+
+codegen.obj: codegen.c codegen.h $(INCLUDES)
+
+combine.obj: combine.c $(INCLUDES)
+
+globals.obj: globals.c $(INCLUDES)
+
+cod3216.obj: cod3216.c $(INCLUDES)
+
+cod3216b.obj: cod3216b.c $(INCLUDES)
+
+cod3216g.obj: cod3216g.c $(INCLUDES)
+
+cod1632.obj: cod1632.c $(INCLUDES) codegen.h globals.h
+
+cod1632b.obj: cod1632b.c $(INCLUDES) codegen.h globals.h cod1632b.h
+
+mtcpars.obj: mtcpars.c $(INCLUDES)
+ cl $(CFLAGS) /W2 $*.c
+
+mtclex.obj: mtclex.c mtcpars.c
+ cl $(CFLAGS) $*.c
+
+mtcpars.c: mtcpars.y
+ yaccp -h mtcpars.y
+
+mtclex.c: mtclex.l
+ lex -t mtclex.l > mtclex.c
+
+hello.obj: hello.c
+
+tmp.obj: tmp.c
+
+sample.asm: sample.thk
+ thunk -y -NA THUNK32 -NC THUNK16 $*.thk
+
+sample16.obj: sample.asm
+ ml -W3 -c -Fl$*.lst -Fo$*.obj -DGEN16 sample.asm
+
+sample32.obj: sample.asm
+ ml -W3 -c -Fl$*.lst -Fo$*.obj -DGEN32 sample.asm
diff --git a/private/os2/client/thunk/thunkcom/makfprot.cmd b/private/os2/client/thunk/thunkcom/makfprot.cmd
new file mode 100644
index 000000000..d453a2f1d
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/makfprot.cmd
@@ -0,0 +1,60 @@
+@echo off
+if "%1"=="" goto all
+cl -DMAKFPROT -Zg %1
+goto end
+
+:all
+@echo on
+echo // mtcpars.c > fprot.h
+cl -DMAKFPROT -Zg mtcpars.c >> fprot.h
+echo // >> fprot.h
+
+echo // mtclex.c >> fprot.h
+cl -DMAKFPROT -Zg mtclex.c >> fprot.h
+echo // >> fprot.h
+
+echo // codegen.c >> fprot.h
+cl -DMAKFPROT -Zg codegen.c >> fprot.h
+echo // >> fprot.h
+
+echo // cod1632.c >> fprot.h
+cl -DMAKFPROT -Zg cod1632.c >> fprot.h
+echo // >> fprot.h
+
+echo // cod1632b.c >> fprot.h
+cl -DMAKFPROT -Zg cod1632b.c >> fprot.h
+echo // >> fprot.h
+
+echo // thunk.c >> fprot.h
+cl -DMAKFPROT -Zg thunk.c >> fprot.h
+echo // >> fprot.h
+
+echo // types.c >> fprot.h
+cl -DMAKFPROT -Zg types.c >> fprot.h
+echo // >> fprot.h
+
+echo // error.c >> fprot.h
+cl -DMAKFPROT -Zg error.c >> fprot.h
+echo // >> fprot.h
+
+echo // symtab.c >> fprot.h
+cl -DMAKFPROT -Zg symtab.c >> fprot.h
+echo // >> fprot.h
+
+echo // cod3216.c >> fprot.h
+cl -DMAKFPROT -Zg cod3216.c >> fprot.h
+echo // >> fprot.h
+
+echo // cod3216b.c >> fprot.h
+cl -DMAKFPROT -Zg cod3216b.c >> fprot.h
+echo // >> fprot.h
+
+echo // cod3216g.c >> fprot.h
+cl -DMAKFPROT -Zg cod3216g.c >> fprot.h
+echo // >> fprot.h
+
+echo // combine.c >> fprot.h
+cl -DMAKFPROT -Zg combine.c >> fprot.h
+echo // >> fprot.h
+
+:end
diff --git a/private/os2/client/thunk/thunkcom/mkhthk.cmd b/private/os2/client/thunk/thunkcom/mkhthk.cmd
new file mode 100644
index 000000000..2f3ad2ae4
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/mkhthk.cmd
@@ -0,0 +1,2 @@
+cl -c -G2s -AL htotdl.c
+link htotdl,,,llibcep os2286 /NOD;
diff --git a/private/os2/client/thunk/thunkcom/ml.err b/private/os2/client/thunk/thunkcom/ml.err
new file mode 100644
index 000000000..2d845bc51
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/ml.err
@@ -0,0 +1,258 @@
+FATAL
+cannot open file
+I/O error closing file
+I/O error writing file
+I/O error reading file
+out of far memory
+assembler limit : macro parameter name table full
+invalid command-line option
+nesting level too deep
+unmatched macro nesting
+line too long
+unmatched block nesting
+directive must be in control block
+error count exceeds 100; stopping assembly
+invalid numerical command-line argument
+too many arguments
+statement too complex
+out of virtual memory
+out of near memory
+missing source filename
+invocation failed : retry command line with /VM option
+SEVERE
+memory operand not allowed in context
+immediate operand not allowed
+cannot have more than one ELSE clause per IF block
+extra characters after statement
+symbol type conflict
+symbol redefinition
+undefined symbol
+non-benign record redefinition
+syntax error
+syntax error in expression
+invalid type expression
+distance invalid for word size of current segment
+PROC, MACRO, or macro repeat directive must precede LOCAL
+.MODEL must precede this directive
+cannot define as public or external
+segment attributes cannot change
+expression expected
+operator expected
+invalid use of external symbol
+operand must be RECORD type or field
+identifier not a record
+record constants may not span line breaks
+instruction operands must be the same size
+instruction operand must have size
+invalid operand size for instruction
+operands must be in same segment
+constant expected
+operand must be a memory expression
+expression must be a code address
+multiple base registers not allowed
+multiple index registers not allowed
+must be index or base register
+invalid use of register
+invalid INVOKE argument
+must be in segment block
+DUP too complex
+too many initial values for structure
+statement not allowed inside structure definition
+missing operand for macro operator
+line too long
+segment register not allowed in context
+string or text literal too long
+statement too complex
+identifier too long
+invalid character in file
+missing angle bracket or brace in literal
+missing single or double quotation mark in string
+empty (null) string
+nondigit in number
+syntax error in floating-point constant
+real or BCD number not allowed
+text item required
+forced error
+forced error : value equal to 0
+forced error : value not equal to 0
+forced error : symbol not defined
+forced error : symbol defined
+forced error : string blank
+forced error : string not blank
+forced error : strings equal
+forced error : strings not equal
+[ELSE]IF2/.ERR2 not allowed : single-pass assembler
+expression too complex for .UNTILCXZ
+can ALIGN only to power of 2
+structure alignment must be 1, 2, or 4
+expected
+incompatable CPU mode and segment size
+LOCK must be followed by a memory operation
+instruction prefix not allowed
+no operands allowed for this instruction
+invalid instruction operands
+initializer magnitude too large for specified size
+cannot access symbol in given segment or group
+operands have different frames
+cannot access label through segment registers
+jump destination too far
+jump destination must specify a label
+instruction does not allow NEAR indirect addressing
+instruction does not allow FAR indirect addressing
+instruction does not allow FAR direct addressing
+jump distance not possible in current CPU mode
+missing operand after unary operator
+cannot mix 16- and 32-bit registers
+invalid scale value
+constant value too large
+instruction or register not accepted in current CPU mode
+reserved word expected
+instruction form requires 80386/486
+END directive required at end of file
+too many bits in RECORD
+positive value expected
+index value past end of string
+count must be positive or zero
+count value too large
+operand must be relocatable
+constant or relocatable label expected
+segment, group, or segment register expected
+segment expected
+invalid operand for OFFSET
+invalid use of external absolute
+segment or group not allowed
+cannot add two relocatable labels
+cannot add memory expression and code label
+segment exceeds 64K limit
+invalid type for a data declaration
+HIGH and LOW require immediate operands
+N/A
+cannot have implicit far jump or call to near label
+use of register assumed to ERROR
+only white space or comment can follow backslash
+COMMENT delimiter expected
+conflicting parameter definition
+PROC and prototype calling conventions conflict
+invalid radix tag
+INVOKE argument type mismatch : argument
+invalid coprocessor register
+instructions and initialized data not allowed in AT segments
+/AT switch requires the TINY memory model
+cannot have segment address references with TINY model
+language type must be specified
+PROLOGUE must be macro function
+EPILOGUE must be macro procedure
+alternate identifier not allowed with EXTERNDEF
+text macro nesting level too deep
+N/A
+missing macro argument
+EXITM used inconsistently
+macro function argument list too long
+N/A
+VARARG parameter must be last parameter
+VARARG parameter not allowed with LOCAL
+VARARG parameter requires C calling convention
+ORG needs a constant or local offset
+register value overwritten by INVOKE
+structure too large to pass with INVOKE : argument
+N/A
+too many arguments to INVOKE
+too few arguments to INVOKE
+invalid data initializer
+N/A
+RET operand too large
+too many operands to instruction
+cannot have more than one .ELSE clause per .IF block
+expected data label
+cannot nest procedures
+EXPORT must be FAR
+procedure declared with two visibility attributes
+macro label not defined
+invalid symbol type in expression
+byte register cannot be first operand
+word register cannot be first operand
+special register cannot be first operand
+coprocessor register cannot be first operand
+cannot change size of expression computations
+syntax error in control-flow directive
+cannot use 16-bit register with a 32-bit address
+constant value out of range
+missing right parenthesis
+type is wrong size for register
+structure cannot be instanced
+non-benign structure redefinition: label incorrect
+non-benign structure redefinition: too few labels
+OLDSTRUCTS/NOOLDSTRUCTS state cannot be changed
+non-benign structure redefinition: incorrect initializers
+non-benign structure redefinition: too few initializers
+non-benign structure redefinition: label has incorrect offset
+structure field expected
+unexpected literal found in expression
+N/A
+divide by zero in expression
+directive must appear inside a macro
+cannot expand macro function
+too few bits in RECORD
+macro function cannot redefine itself
+N/A
+invalid qualified type
+floating-point initializer on an integer variable
+nested structure improperly initialized
+invalid use of FLAT
+structure improperly initialized
+improper list initialization
+initializer must be a string or single item
+initializer must be a single item
+initializer must be a single byte
+improper use of list initializer
+improper literal initialization
+extra characters in literal initialization
+must use floating-point initializer
+cannot use .EXIT for OS_OS2 with .8086
+invalid combination with segment alignment
+INVOKE requires prototype for procedure
+cannot include structure in self
+symbol language attribute conflict
+non-benign COMM redefinition
+COMM variable exceeds 64K
+parameter or local cannot have void type
+cannot use TINY model with OS_OS2
+expression size must be 32 bits
+.EXIT does not work with 32-bit segments
+.STARTUP does not work with 32-bit segments
+ORG directive not allowed in unions
+D/T
+illegal use of segment register
+cannot declare scoped code label as PUBLIC
+.MSFLOAT directive is obsolete : .MSFLOAT ignored
+ESC instruction is obsolete : ESC ignored
+LEVEL 1
+cannot modify READONLY segment
+N/A
+non-unique STRUCT/UNION field used without qualification
+start address on END directive ignored with .STARTUP
+cannot ASSUME CS
+unknown default prologue argument
+too many arguments in macro call
+option untranslated, directive required
+invalid command-line option value, default is used
+virtual memory not available : /VM ignored
+insufficent memory for /EP : /EP ignored
+expected '>' on text literal
+multiple .MODEL directives found : .MODEL ignored
+line number information for segment without class 'CODE'
+instructions and initialized data not supported in AT segments
+LEVEL 2
+@@: label defined but not referenced
+expression expected, assume value 0
+EXTERNDEF previously assumed to be external
+length of symbol previously assumed to be different
+symbol previously assumed to not be in a group
+types are different
+LEVEL 3
+N/A
+no return from procedure
+N/A
+conditional jump lengthened
+procedure argument or local not referenced
+IF condition may be pass-dependent
diff --git a/private/os2/client/thunk/thunkcom/mtclex.c b/private/os2/client/thunk/thunkcom/mtclex.c
new file mode 100644
index 000000000..2625681ee
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/mtclex.c
@@ -0,0 +1,2115 @@
+# include "stdio.h"
+# define U(x) x
+# define NLSTATE yyprevious=YYNEWLINE
+# define BEGIN yybgin = yysvec + 1 +
+# define INITIAL 0
+# define YYLERR yysvec
+# define YYSTATE (yyestate-yysvec-1)
+# define YYOPTIM 1
+# define YYLMAX 200
+# define output(c) putc(c,yyout)
+# define input() (((yytchar=yysptr>yysbuf?U(*--yysptr):getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar)
+# define unput(c) {yytchar= (c);if(yytchar=='\n')yylineno--;*yysptr++=yytchar;}
+# define yymore() (yymorfg=1)
+# define ECHO fprintf(yyout, "%s",yytext)
+# define REJECT { nstr = yyreject(); goto yyfussy;}
+int yyleng; extern char yytext[];
+int yymorfg;
+extern char *yysptr, yysbuf[];
+int yytchar;
+FILE *yyin = {stdin}, *yyout = {stdout};
+extern int yylineno;
+struct yysvf {
+ struct yywork *yystoff;
+ struct yysvf *yyother;
+ int *yystops;};
+struct yysvf *yyestate;
+extern struct yysvf yysvec[], *yybgin;
+#include <stdlib.h>
+#include "types.h"
+#include "symtab.h"
+#include "mtcpars.h"
+#include "thunk.h"
+
+typedef struct _FR {
+ int LineNo;
+ FILE *pfhFile;
+ char *pszFileName;
+ struct _FR *pPreviousFile;
+} FileRecord;
+
+FileRecord *FileList = NULL;
+
+static iCommentNesting = 0;
+
+# define Normal 2
+# define EatComment 4
+# define LookFilename 6
+# define HexNum 8
+# define YYNEWLINE 10
+yylex(){
+int nstr; extern int yyprevious;
+while((nstr = yylook()) >= 0)
+yyfussy: switch(nstr){
+case 0:
+if(yywrap()) return(0); break;
+case 1:
+ return(syFar16);
+break;
+case 2:
+ return(syNear32);
+break;
+case 3:
+ return(syPtr);
+break;
+case 4:
+ return(syAPI16);
+break;
+case 5:
+ return(syAPI32);
+break;
+case 6:
+ return(syUnsigned);
+break;
+case 7:
+ return(sySigned);
+break;
+case 8:
+ return(syLong);
+break;
+case 9:
+ return(syShort);
+break;
+case 10:
+ return(syInt);
+break;
+case 11:
+ return(syTypeDef);
+break;
+case 12:
+ return(syMakeThunk);
+break;
+case 13:
+ return(sySizeOf);
+break;
+case 14:
+ return(syCountOf);
+break;
+case 15:
+ return(syInput);
+break;
+case 16:
+ return(syInOut);
+break;
+case 17:
+ return(syOutput);
+break;
+case 18:
+ return(syStruct);
+break;
+case 19:
+ return(syString);
+break;
+case 20:
+ return(syPassIfHiNull);
+break;
+case 21:
+ return(sySpecial);
+break;
+case 22:
+ return(syMapToRetval);
+break;
+case 23:
+ return(syReverseRC);
+break;
+case 24:
+ return(syLocalHeap);
+break;
+case 25:
+ return(syVoid);
+break;
+case 26:
+ return(syChar);
+break;
+case 27:
+ return(syNullType);
+break;
+case 28:
+ return(syNewElem);
+break;
+case 29:
+ return(syErrNoMem);
+break;
+case 30:
+ return(syErrBadParam);
+break;
+case 31:
+ return(syErrUnknown);
+break;
+case 32:
+ return(syTrue);
+break;
+case 33:
+ return(syFalse);
+break;
+case 34:
+ return(syStack);
+break;
+case 35:
+ return(syInline);
+break;
+case 36:
+ return(syTruncation);
+break;
+case 37:
+ return(syEnableMapDirect1632);
+break;
+case 38:
+ return(syUser);
+break;
+case 39:
+ return(syGdi);
+break;
+case 40:
+ return(syKernel);
+break;
+case 41:
+ return(sySysCall);
+break;
+case 42:
+ return(syConforming);
+break;
+case 43:
+ return(syByte);
+break;
+case 44:
+ return(syWord);
+break;
+case 45:
+ return(syDWord);
+break;
+case 46:
+ return(syAligned);
+break;
+case 47:
+ return(syDeleted);
+break;
+case 48:
+ return(syAllow);
+break;
+case 49:
+ return(syRestrict);
+break;
+case 50:
+ return(syMapDirect);
+break;
+case 51:
+ return(syEqual);
+break;
+case 52:
+ return(syLParen);
+break;
+case 53:
+ return(syRParen);
+break;
+case 54:
+ return(sySemi);
+break;
+case 55:
+ return(syPlus);
+break;
+case 56:
+ return(syMinus);
+break;
+case 57:
+ return(syDiv);
+break;
+case 58:
+ return(syComma);
+break;
+case 59:
+ return(syLBrace);
+break;
+case 60:
+ return(syRBrace);
+break;
+case 61:
+ return(syLBrack);
+break;
+case 62:
+ return(syRBrack);
+break;
+case 63:
+ {
+ BEGIN LookFilename;
+ }
+break;
+case 64:
+ {
+ yylval.ident = typ_DupString(yytext);
+ return(syIdent);
+ }
+break;
+case 65:
+ {
+ BEGIN HexNum;
+ }
+break;
+case 66:
+ {
+ sscanf(yytext,"%lx",&yylval.longval);
+ BEGIN Normal;
+ return(syNumber);
+ }
+break;
+case 67:
+ {
+ return(syError);
+ }
+break;
+case 68:
+ {
+ yylval.longval = atoi(yytext);
+ return(syNumber);
+ }
+break;
+case 69:
+ ;
+break;
+case 70:
+ {
+ iCommentNesting++;
+
+ BEGIN EatComment;
+ }
+break;
+case 71:
+ {
+ iCommentNesting++;
+
+
+ }
+break;
+case 72:
+ {
+ if(--iCommentNesting == 0) BEGIN Normal;
+ }
+break;
+case 73:
+ ;
+break;
+case 74:
+ ;
+break;
+case 75:
+{
+ PushInclude(yytext);
+ BEGIN Normal;
+ }
+break;
+case 76:
+{
+
+ }
+break;
+case -1:
+break;
+default:
+fprintf(yyout,"bad switch yylook %d",nstr);
+} return(0); }
+/* end of yylex */
+
+void PushInclude( char *yyFile)
+{
+ FILE *filePtr;
+ FileRecord *pTemp;
+
+ yyFile[yyleng-1] = '\0'; /* Remove Ending quote */
+ yyFile++; /* Skip first quote */
+
+
+ if(pTemp = (FileRecord *) malloc(sizeof(FileRecord))) {
+
+ pTemp->LineNo = yylineno;
+ pTemp->pfhFile = yyin;
+/*
+
+ if((pTemp->fhFile=dup(0)) < 0)
+ fatal("PushInclude: Out of file handles");
+*/
+
+ pTemp->pszFileName = yyinname;
+
+/*
+ if(close(0)) fatal("PushInclude close 0 failed");
+*/
+
+ pTemp->pPreviousFile = FileList;
+ FileList = pTemp;
+
+ } else {
+ fatal("PushInclude malloc failure");
+ }
+
+
+
+ filePtr = fopen(yyFile, "r");
+
+ if (filePtr == NULL) {
+ fatal("fopen(%s): Could not open file ",yyFile);
+ }
+ yyin = filePtr;
+
+ yylineno = 0;
+ yyinname = typ_DupString(yyFile);
+}
+
+
+
+void LookNormal( void)
+{
+ BEGIN Normal;
+}
+
+int yywrap( void)
+{
+ FileRecord *pTemp;
+
+ if(!FileList)
+ return 1;
+
+ /* Close current file */
+ if( fclose( yyin))
+ fatal( "yywrap close yyin failed");
+
+
+/*****
+ if(dup2(FileList->fhFile,0))
+ fatal( "yywrap dup failure");
+ if(close(FileList->fhFile))
+ fatal( "yywrap close %d failure", FileList->fhFile);
+*****/
+
+ yyin = FileList->pfhFile;
+
+ yylineno = FileList->LineNo;
+
+
+
+ yyinname = FileList->pszFileName;
+
+ pTemp= FileList;
+
+ FileList = FileList->pPreviousFile;
+
+ free( pTemp);
+
+ return 0;
+}
+int yyvstop[] = {
+0,
+
+69,
+0,
+
+52,
+0,
+
+53,
+0,
+
+3,
+0,
+
+55,
+0,
+
+58,
+0,
+
+56,
+0,
+
+57,
+0,
+
+68,
+0,
+
+68,
+0,
+
+54,
+0,
+
+51,
+0,
+
+64,
+0,
+
+64,
+0,
+
+61,
+0,
+
+62,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+59,
+0,
+
+60,
+0,
+
+74,
+0,
+
+73,
+74,
+0,
+
+73,
+0,
+
+74,
+0,
+
+74,
+0,
+
+67,
+0,
+
+66,
+67,
+0,
+
+70,
+0,
+
+65,
+0,
+
+50,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+72,
+0,
+
+71,
+0,
+
+75,
+0,
+
+76,
+0,
+
+66,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+39,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+10,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+43,
+64,
+0,
+
+26,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+8,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+32,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+38,
+64,
+0,
+
+25,
+64,
+0,
+
+44,
+64,
+0,
+
+4,
+64,
+0,
+
+5,
+64,
+0,
+
+64,
+0,
+
+48,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+45,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+33,
+64,
+0,
+
+1,
+64,
+0,
+
+64,
+0,
+
+16,
+64,
+0,
+
+15,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+9,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+34,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+12,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+35,
+64,
+0,
+
+40,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+2,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+17,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+7,
+64,
+0,
+
+13,
+64,
+0,
+
+64,
+0,
+
+19,
+64,
+0,
+
+18,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+46,
+64,
+0,
+
+64,
+0,
+
+14,
+64,
+0,
+
+47,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+28,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+21,
+64,
+0,
+
+41,
+64,
+0,
+
+64,
+0,
+
+11,
+64,
+0,
+
+64,
+0,
+
+63,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+29,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+27,
+64,
+0,
+
+64,
+0,
+
+49,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+6,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+24,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+23,
+64,
+0,
+
+64,
+0,
+
+42,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+31,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+36,
+64,
+0,
+
+64,
+0,
+
+30,
+64,
+0,
+
+22,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+20,
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+64,
+0,
+
+37,
+64,
+0,
+0};
+# define YYTYPE int
+struct yywork { YYTYPE verify, advance; } yycrank[] = {
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 3,11, 3,11,
+10,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 3,11, 0,0, 7,55,
+3,12, 0,0, 0,0, 0,0,
+0,0, 3,13, 3,14, 3,15,
+3,16, 3,17, 3,18, 19,60,
+3,19, 3,20, 3,21, 3,21,
+3,21, 3,21, 3,21, 3,21,
+3,21, 3,21, 3,21, 6,53,
+3,22, 7,56, 3,23, 0,0,
+6,54, 23,62, 3,24, 3,25,
+3,25, 3,25, 3,25, 3,25,
+3,25, 3,25, 3,25, 3,25,
+3,25, 3,25, 3,25, 3,25,
+3,25, 3,25, 3,25, 3,25,
+3,25, 3,25, 3,25, 3,25,
+3,25, 3,25, 3,25, 3,25,
+3,26, 25,25, 3,27, 53,95,
+3,25, 54,96, 3,28, 3,29,
+3,30, 3,31, 3,32, 3,33,
+3,34, 3,25, 3,35, 3,25,
+3,36, 3,37, 3,38, 3,39,
+3,40, 3,41, 3,25, 3,42,
+3,43, 3,44, 3,45, 3,46,
+3,47, 3,25, 3,25, 3,25,
+3,48, 5,50, 3,49, 9,57,
+12,59, 28,25, 40,25, 32,25,
+29,25, 5,51, 5,52, 9,57,
+9,0, 20,21, 20,21, 20,21,
+20,21, 20,21, 20,21, 20,21,
+20,21, 20,21, 20,21, 21,21,
+21,21, 21,21, 21,21, 21,21,
+21,21, 21,21, 21,21, 21,21,
+21,21, 28,64, 5,50, 30,25,
+9,57, 32,70, 33,25, 35,25,
+34,25, 32,71, 5,53, 40,80,
+38,25, 59,100, 100,144, 5,54,
+5,50, 29,65, 9,58, 31,25,
+114,25, 41,25, 118,25, 33,72,
+37,25, 46,25, 144,191, 30,66,
+34,73, 38,77, 5,50, 36,25,
+9,57, 5,50, 30,67, 9,58,
+42,25, 35,74, 41,81, 5,50,
+31,68, 9,57, 24,25, 24,25,
+24,25, 24,25, 24,25, 24,25,
+24,25, 24,25, 24,25, 24,25,
+36,75, 20,61, 47,25, 37,76,
+46,93, 42,82, 31,69, 24,25,
+24,25, 24,25, 24,25, 24,25,
+24,25, 24,25, 24,25, 24,25,
+24,25, 24,25, 24,25, 24,25,
+24,25, 24,25, 24,63, 24,25,
+24,25, 24,25, 24,25, 24,25,
+24,25, 24,25, 24,25, 24,25,
+24,25, 47,94, 149,25, 150,25,
+65,25, 24,25, 45,25, 24,25,
+24,25, 24,25, 24,25, 24,25,
+24,25, 24,25, 24,25, 24,25,
+24,25, 24,25, 24,25, 24,25,
+24,25, 24,25, 24,25, 24,25,
+24,25, 24,25, 24,25, 24,25,
+24,25, 24,25, 24,25, 24,25,
+24,25, 39,25, 44,25, 43,25,
+45,91, 64,25, 63,101, 55,55,
+65,104, 45,92, 88,25, 67,25,
+56,56, 63,25, 66,25, 55,55,
+55,0, 70,25, 68,25, 69,25,
+56,56, 56,0, 39,78, 71,25,
+72,25, 79,25, 44,88, 43,83,
+43,84, 75,25, 64,102, 66,105,
+77,25, 64,103, 70,110, 43,85,
+44,89, 73,25, 39,79, 43,86,
+55,97, 67,106, 76,25, 44,90,
+43,87, 56,56, 68,108, 88,137,
+67,107, 83,25, 69,109, 84,25,
+72,112, 79,125, 55,55, 166,25,
+184,25, 71,111, 72,113, 56,56,
+81,25, 76,120, 73,114, 75,119,
+77,122, 90,25, 188,25, 189,25,
+55,55, 190,25, 191,231, 55,55,
+76,121, 56,98, 84,131, 80,25,
+56,56, 55,55, 74,25, 78,25,
+83,130, 82,25, 56,56, 58,99,
+58,99, 58,99, 58,99, 58,99,
+58,99, 58,99, 58,99, 58,99,
+58,99, 84,132, 85,25, 81,127,
+78,123, 90,139, 93,25, 92,25,
+58,99, 58,99, 58,99, 58,99,
+58,99, 58,99, 74,115, 86,25,
+87,25, 74,116, 74,117, 80,126,
+89,25, 91,25, 74,118, 85,133,
+82,128, 94,25, 78,124, 82,129,
+92,141, 102,25, 103,25, 93,142,
+86,134, 101,145, 104,25, 101,146,
+105,25, 107,25, 106,25, 109,25,
+58,99, 58,99, 58,99, 58,99,
+58,99, 58,99, 112,25, 108,25,
+110,25, 86,135, 115,25, 87,136,
+102,147, 111,25, 113,160, 104,149,
+91,140, 89,138, 116,25, 94,143,
+106,151, 103,148, 117,25, 119,25,
+101,25, 120,25, 110,155, 107,152,
+108,153, 121,25, 105,150, 111,156,
+122,25, 109,154, 125,25, 115,161,
+123,25, 124,25, 127,25, 126,25,
+128,25, 112,159, 120,165, 111,157,
+129,25, 113,25, 130,25, 131,25,
+132,25, 135,25, 111,158, 137,25,
+121,166, 119,164, 141,25, 116,162,
+133,25, 138,25, 124,169, 117,163,
+134,25, 148,25, 125,170, 136,25,
+139,25, 129,174, 140,25, 145,192,
+122,167, 132,177, 123,168, 126,171,
+142,25, 127,172, 135,180, 133,178,
+128,173, 131,176, 138,184, 134,179,
+130,175, 137,183, 136,182, 143,25,
+146,193, 139,186, 135,181, 138,185,
+141,188, 147,25, 151,25, 140,187,
+142,189, 145,25, 152,25, 153,25,
+154,25, 155,25, 156,25, 158,25,
+148,195, 157,25, 159,25, 143,190,
+161,25, 162,25, 163,25, 160,205,
+165,25, 167,25, 168,212, 170,25,
+171,25, 177,25, 146,25, 156,201,
+154,199, 164,25, 169,25, 147,194,
+172,25, 151,196, 173,25, 159,204,
+174,25, 155,200, 175,25, 176,25,
+178,25, 158,203, 152,197, 153,198,
+157,202, 160,25, 161,206, 180,25,
+165,210, 179,25, 164,209, 168,25,
+167,211, 162,207, 163,208, 182,25,
+177,221, 172,216, 169,213, 170,214,
+176,220, 171,215, 181,25, 183,25,
+185,25, 178,222, 186,25, 192,25,
+173,217, 187,25, 174,218, 193,25,
+182,226, 194,25, 175,219, 195,25,
+179,223, 180,224, 196,25, 197,25,
+198,25, 181,225, 199,25, 185,228,
+200,25, 202,25, 186,229, 201,25,
+203,25, 204,25, 183,227, 205,25,
+187,230, 207,25, 194,232, 206,25,
+208,25, 209,25, 210,25, 211,25,
+212,244, 198,235, 213,25, 214,25,
+215,25, 200,236, 216,25, 201,237,
+218,25, 217,25, 197,234, 219,25,
+196,233, 221,25, 202,238, 203,239,
+206,240, 220,25, 223,25, 222,25,
+225,25, 226,25, 210,242, 213,245,
+224,25, 209,241, 227,25, 229,25,
+216,248, 228,25, 212,25, 230,25,
+231,260, 211,243, 217,249, 221,252,
+222,253, 220,251, 232,25, 233,25,
+215,247, 234,25, 235,25, 218,250,
+214,246, 236,25, 228,257, 224,254,
+229,258, 226,256, 237,25, 238,25,
+240,25, 239,25, 241,25, 242,25,
+225,255, 243,25, 232,261, 244,25,
+245,25, 230,259, 235,264, 234,263,
+246,25, 247,25, 248,25, 249,25,
+233,262, 251,25, 250,25, 252,25,
+238,267, 253,25, 236,265, 254,25,
+242,269, 255,25, 243,270, 256,25,
+257,25, 258,25, 237,266, 239,268,
+259,25, 260,281, 249,274, 261,25,
+262,25, 245,271, 248,273, 250,275,
+263,25, 264,25, 265,25, 266,25,
+246,272, 267,25, 268,25, 270,25,
+269,25, 253,276, 271,25, 258,279,
+272,25, 259,280, 273,25, 256,277,
+274,25, 275,25, 276,25, 265,283,
+266,284, 262,282, 277,25, 278,25,
+257,278, 269,287, 279,25, 280,25,
+282,25, 283,25, 284,25, 285,25,
+286,25, 272,289, 267,285, 287,25,
+288,25, 268,286, 289,25, 273,290,
+290,25, 291,25, 293,25, 270,288,
+292,25, 294,25, 295,25, 280,294,
+278,293, 297,25, 298,25, 275,292,
+274,291, 299,25, 301,25, 296,25,
+302,25, 303,25, 282,295, 300,25,
+304,25, 283,296, 307,25, 292,302,
+284,297, 305,25, 297,306, 287,299,
+306,25, 295,304, 290,301, 286,298,
+308,25, 293,303, 288,300, 296,305,
+300,308, 309,25, 310,25, 311,25,
+298,307, 312,25, 313,25, 314,25,
+316,25, 315,25, 318,25, 303,310,
+317,25, 319,320, 305,311, 301,309,
+320,321, 323,25, 321,322, 322,323,
+0,0, 306,312, 0,0, 0,0,
+308,313, 0,0, 0,0, 0,0,
+0,0, 309,314, 315,317, 317,318,
+0,0, 0,0, 0,0, 314,316,
+0,0, 311,315, 0,0, 0,0,
+0,0, 0,0, 320,25, 0,0,
+319,25, 0,0, 318,319, 321,25,
+0,0, 322,25, 0,0, 0,0,
+0,0};
+struct yysvf yysvec[] = {
+0, 0, 0,
+yycrank+0, 0, 0,
+yycrank+0, 0, 0,
+yycrank+1, 0, 0,
+yycrank+0, yysvec+3, 0,
+yycrank+-124, 0, 0,
+yycrank+-17, yysvec+5, 0,
+yycrank+1, 0, 0,
+yycrank+0, yysvec+7, 0,
+yycrank+-126, 0, 0,
+yycrank+-2, yysvec+9, 0,
+yycrank+0, 0, yyvstop+1,
+yycrank+23, 0, 0,
+yycrank+0, 0, yyvstop+3,
+yycrank+0, 0, yyvstop+5,
+yycrank+0, 0, yyvstop+7,
+yycrank+0, 0, yyvstop+9,
+yycrank+0, 0, yyvstop+11,
+yycrank+0, 0, yyvstop+13,
+yycrank+5, 0, yyvstop+15,
+yycrank+89, 0, yyvstop+17,
+yycrank+99, 0, yyvstop+19,
+yycrank+0, 0, yyvstop+21,
+yycrank+3, 0, yyvstop+23,
+yycrank+150, 0, yyvstop+25,
+yycrank+13, yysvec+24, yyvstop+27,
+yycrank+0, 0, yyvstop+29,
+yycrank+0, 0, yyvstop+31,
+yycrank+49, yysvec+24, yyvstop+33,
+yycrank+52, yysvec+24, yyvstop+35,
+yycrank+79, yysvec+24, yyvstop+37,
+yycrank+95, yysvec+24, yyvstop+39,
+yycrank+51, yysvec+24, yyvstop+41,
+yycrank+82, yysvec+24, yyvstop+43,
+yycrank+84, yysvec+24, yyvstop+45,
+yycrank+83, yysvec+24, yyvstop+47,
+yycrank+107, yysvec+24, yyvstop+49,
+yycrank+100, yysvec+24, yyvstop+51,
+yycrank+88, yysvec+24, yyvstop+53,
+yycrank+193, yysvec+24, yyvstop+55,
+yycrank+50, yysvec+24, yyvstop+57,
+yycrank+97, yysvec+24, yyvstop+59,
+yycrank+112, yysvec+24, yyvstop+61,
+yycrank+195, yysvec+24, yyvstop+63,
+yycrank+194, yysvec+24, yyvstop+65,
+yycrank+166, yysvec+24, yyvstop+67,
+yycrank+101, yysvec+24, yyvstop+69,
+yycrank+130, yysvec+24, yyvstop+71,
+yycrank+0, 0, yyvstop+73,
+yycrank+0, 0, yyvstop+75,
+yycrank+0, 0, yyvstop+77,
+yycrank+0, 0, yyvstop+79,
+yycrank+0, 0, yyvstop+82,
+yycrank+48, 0, yyvstop+84,
+yycrank+55, 0, yyvstop+86,
+yycrank+-278, 0, 0,
+yycrank+-283, 0, 0,
+yycrank+0, 0, yyvstop+88,
+yycrank+307, 0, yyvstop+90,
+yycrank+59, 0, 0,
+yycrank+0, 0, yyvstop+93,
+yycrank+0, 0, yyvstop+95,
+yycrank+0, 0, yyvstop+97,
+yycrank+205, yysvec+24, yyvstop+99,
+yycrank+197, yysvec+24, yyvstop+101,
+yycrank+164, yysvec+24, yyvstop+103,
+yycrank+206, yysvec+24, yyvstop+105,
+yycrank+203, yysvec+24, yyvstop+107,
+yycrank+210, yysvec+24, yyvstop+109,
+yycrank+211, yysvec+24, yyvstop+111,
+yycrank+209, yysvec+24, yyvstop+113,
+yycrank+215, yysvec+24, yyvstop+115,
+yycrank+216, yysvec+24, yyvstop+117,
+yycrank+229, yysvec+24, yyvstop+119,
+yycrank+270, yysvec+24, yyvstop+121,
+yycrank+221, yysvec+24, yyvstop+123,
+yycrank+234, yysvec+24, yyvstop+125,
+yycrank+224, yysvec+24, yyvstop+127,
+yycrank+271, yysvec+24, yyvstop+129,
+yycrank+217, yysvec+24, yyvstop+131,
+yycrank+267, yysvec+24, yyvstop+133,
+yycrank+252, yysvec+24, yyvstop+135,
+yycrank+273, yysvec+24, yyvstop+137,
+yycrank+241, yysvec+24, yyvstop+139,
+yycrank+243, yysvec+24, yyvstop+141,
+yycrank+286, yysvec+24, yyvstop+143,
+yycrank+299, yysvec+24, yyvstop+145,
+yycrank+300, yysvec+24, yyvstop+147,
+yycrank+202, yysvec+24, yyvstop+149,
+yycrank+304, yysvec+24, yyvstop+151,
+yycrank+257, yysvec+24, yyvstop+153,
+yycrank+305, yysvec+24, yyvstop+155,
+yycrank+291, yysvec+24, yyvstop+157,
+yycrank+290, yysvec+24, yyvstop+159,
+yycrank+309, yysvec+24, yyvstop+161,
+yycrank+0, 0, yyvstop+163,
+yycrank+0, 0, yyvstop+165,
+yycrank+0, 0, yyvstop+167,
+yycrank+0, 0, yyvstop+169,
+yycrank+0, yysvec+58, yyvstop+171,
+yycrank+71, 0, 0,
+yycrank+348, yysvec+24, yyvstop+173,
+yycrank+313, yysvec+24, yyvstop+175,
+yycrank+314, yysvec+24, yyvstop+177,
+yycrank+318, yysvec+24, yyvstop+179,
+yycrank+320, yysvec+24, yyvstop+181,
+yycrank+322, yysvec+24, yyvstop+183,
+yycrank+321, yysvec+24, yyvstop+185,
+yycrank+331, yysvec+24, yyvstop+187,
+yycrank+323, yysvec+24, yyvstop+189,
+yycrank+332, yysvec+24, yyvstop+191,
+yycrank+337, yysvec+24, yyvstop+193,
+yycrank+330, yysvec+24, yyvstop+195,
+yycrank+369, yysvec+24, yyvstop+197,
+yycrank+96, yysvec+24, yyvstop+199,
+yycrank+334, yysvec+24, yyvstop+202,
+yycrank+342, yysvec+24, yyvstop+204,
+yycrank+346, yysvec+24, yyvstop+206,
+yycrank+98, yysvec+24, yyvstop+208,
+yycrank+347, yysvec+24, yyvstop+211,
+yycrank+349, yysvec+24, yyvstop+213,
+yycrank+353, yysvec+24, yyvstop+215,
+yycrank+356, yysvec+24, yyvstop+217,
+yycrank+360, yysvec+24, yyvstop+219,
+yycrank+361, yysvec+24, yyvstop+221,
+yycrank+358, yysvec+24, yyvstop+223,
+yycrank+363, yysvec+24, yyvstop+225,
+yycrank+362, yysvec+24, yyvstop+227,
+yycrank+364, yysvec+24, yyvstop+229,
+yycrank+368, yysvec+24, yyvstop+231,
+yycrank+370, yysvec+24, yyvstop+233,
+yycrank+371, yysvec+24, yyvstop+235,
+yycrank+372, yysvec+24, yyvstop+237,
+yycrank+380, yysvec+24, yyvstop+239,
+yycrank+384, yysvec+24, yyvstop+241,
+yycrank+373, yysvec+24, yyvstop+243,
+yycrank+387, yysvec+24, yyvstop+245,
+yycrank+375, yysvec+24, yyvstop+247,
+yycrank+381, yysvec+24, yyvstop+249,
+yycrank+388, yysvec+24, yyvstop+251,
+yycrank+390, yysvec+24, yyvstop+253,
+yycrank+378, yysvec+24, yyvstop+255,
+yycrank+396, yysvec+24, yyvstop+257,
+yycrank+407, yysvec+24, yyvstop+259,
+yycrank+74, 0, 0,
+yycrank+417, yysvec+24, yyvstop+261,
+yycrank+438, yysvec+24, yyvstop+263,
+yycrank+413, yysvec+24, yyvstop+265,
+yycrank+385, yysvec+24, yyvstop+267,
+yycrank+162, yysvec+24, yyvstop+269,
+yycrank+163, yysvec+24, yyvstop+272,
+yycrank+414, yysvec+24, yyvstop+275,
+yycrank+418, yysvec+24, yyvstop+277,
+yycrank+419, yysvec+24, yyvstop+279,
+yycrank+420, yysvec+24, yyvstop+281,
+yycrank+421, yysvec+24, yyvstop+283,
+yycrank+422, yysvec+24, yyvstop+285,
+yycrank+425, yysvec+24, yyvstop+287,
+yycrank+423, yysvec+24, yyvstop+289,
+yycrank+426, yysvec+24, yyvstop+291,
+yycrank+457, yysvec+24, yyvstop+293,
+yycrank+428, yysvec+24, yyvstop+295,
+yycrank+429, yysvec+24, yyvstop+297,
+yycrank+430, yysvec+24, yyvstop+299,
+yycrank+441, yysvec+24, yyvstop+301,
+yycrank+432, yysvec+24, yyvstop+303,
+yycrank+247, yysvec+24, yyvstop+305,
+yycrank+433, yysvec+24, yyvstop+308,
+yycrank+463, yysvec+24, yyvstop+310,
+yycrank+442, yysvec+24, yyvstop+312,
+yycrank+435, yysvec+24, yyvstop+314,
+yycrank+436, yysvec+24, yyvstop+316,
+yycrank+444, yysvec+24, yyvstop+318,
+yycrank+446, yysvec+24, yyvstop+320,
+yycrank+448, yysvec+24, yyvstop+322,
+yycrank+450, yysvec+24, yyvstop+324,
+yycrank+451, yysvec+24, yyvstop+326,
+yycrank+437, yysvec+24, yyvstop+328,
+yycrank+452, yysvec+24, yyvstop+330,
+yycrank+461, yysvec+24, yyvstop+332,
+yycrank+459, yysvec+24, yyvstop+334,
+yycrank+474, yysvec+24, yyvstop+336,
+yycrank+467, yysvec+24, yyvstop+338,
+yycrank+475, yysvec+24, yyvstop+340,
+yycrank+248, yysvec+24, yyvstop+342,
+yycrank+476, yysvec+24, yyvstop+345,
+yycrank+478, yysvec+24, yyvstop+347,
+yycrank+481, yysvec+24, yyvstop+349,
+yycrank+258, yysvec+24, yyvstop+351,
+yycrank+259, yysvec+24, yyvstop+354,
+yycrank+261, yysvec+24, yyvstop+357,
+yycrank+225, 0, 0,
+yycrank+479, yysvec+24, yyvstop+360,
+yycrank+483, yysvec+24, yyvstop+363,
+yycrank+485, yysvec+24, yyvstop+366,
+yycrank+487, yysvec+24, yyvstop+368,
+yycrank+490, yysvec+24, yyvstop+371,
+yycrank+491, yysvec+24, yyvstop+373,
+yycrank+492, yysvec+24, yyvstop+375,
+yycrank+494, yysvec+24, yyvstop+377,
+yycrank+496, yysvec+24, yyvstop+380,
+yycrank+499, yysvec+24, yyvstop+382,
+yycrank+497, yysvec+24, yyvstop+384,
+yycrank+500, yysvec+24, yyvstop+386,
+yycrank+501, yysvec+24, yyvstop+388,
+yycrank+503, yysvec+24, yyvstop+391,
+yycrank+507, yysvec+24, yyvstop+394,
+yycrank+505, yysvec+24, yyvstop+396,
+yycrank+508, yysvec+24, yyvstop+399,
+yycrank+509, yysvec+24, yyvstop+402,
+yycrank+510, yysvec+24, yyvstop+404,
+yycrank+511, yysvec+24, yyvstop+406,
+yycrank+542, yysvec+24, yyvstop+408,
+yycrank+514, yysvec+24, yyvstop+410,
+yycrank+515, yysvec+24, yyvstop+412,
+yycrank+516, yysvec+24, yyvstop+414,
+yycrank+518, yysvec+24, yyvstop+416,
+yycrank+521, yysvec+24, yyvstop+418,
+yycrank+520, yysvec+24, yyvstop+420,
+yycrank+523, yysvec+24, yyvstop+422,
+yycrank+529, yysvec+24, yyvstop+425,
+yycrank+525, yysvec+24, yyvstop+427,
+yycrank+531, yysvec+24, yyvstop+429,
+yycrank+530, yysvec+24, yyvstop+431,
+yycrank+536, yysvec+24, yyvstop+434,
+yycrank+532, yysvec+24, yyvstop+436,
+yycrank+533, yysvec+24, yyvstop+438,
+yycrank+538, yysvec+24, yyvstop+440,
+yycrank+541, yysvec+24, yyvstop+443,
+yycrank+539, yysvec+24, yyvstop+445,
+yycrank+543, yysvec+24, yyvstop+447,
+yycrank+524, 0, 0,
+yycrank+550, yysvec+24, yyvstop+449,
+yycrank+551, yysvec+24, yyvstop+451,
+yycrank+553, yysvec+24, yyvstop+453,
+yycrank+554, yysvec+24, yyvstop+455,
+yycrank+557, yysvec+24, yyvstop+457,
+yycrank+562, yysvec+24, yyvstop+459,
+yycrank+563, yysvec+24, yyvstop+461,
+yycrank+565, yysvec+24, yyvstop+463,
+yycrank+564, yysvec+24, yyvstop+465,
+yycrank+566, yysvec+24, yyvstop+468,
+yycrank+567, yysvec+24, yyvstop+471,
+yycrank+569, yysvec+24, yyvstop+473,
+yycrank+571, yysvec+24, yyvstop+475,
+yycrank+572, yysvec+24, yyvstop+478,
+yycrank+576, yysvec+24, yyvstop+480,
+yycrank+577, yysvec+24, yyvstop+482,
+yycrank+578, yysvec+24, yyvstop+485,
+yycrank+579, yysvec+24, yyvstop+487,
+yycrank+582, yysvec+24, yyvstop+489,
+yycrank+581, yysvec+24, yyvstop+491,
+yycrank+583, yysvec+24, yyvstop+494,
+yycrank+585, yysvec+24, yyvstop+497,
+yycrank+587, yysvec+24, yyvstop+499,
+yycrank+589, yysvec+24, yyvstop+502,
+yycrank+591, yysvec+24, yyvstop+505,
+yycrank+592, yysvec+24, yyvstop+507,
+yycrank+593, yysvec+24, yyvstop+509,
+yycrank+596, yysvec+24, yyvstop+511,
+yycrank+576, 0, 0,
+yycrank+599, yysvec+24, yyvstop+513,
+yycrank+600, yysvec+24, yyvstop+516,
+yycrank+604, yysvec+24, yyvstop+518,
+yycrank+605, yysvec+24, yyvstop+521,
+yycrank+606, yysvec+24, yyvstop+524,
+yycrank+607, yysvec+24, yyvstop+526,
+yycrank+609, yysvec+24, yyvstop+528,
+yycrank+610, yysvec+24, yyvstop+530,
+yycrank+612, yysvec+24, yyvstop+532,
+yycrank+611, yysvec+24, yyvstop+534,
+yycrank+614, yysvec+24, yyvstop+536,
+yycrank+616, yysvec+24, yyvstop+539,
+yycrank+618, yysvec+24, yyvstop+541,
+yycrank+620, yysvec+24, yyvstop+543,
+yycrank+621, yysvec+24, yyvstop+545,
+yycrank+622, yysvec+24, yyvstop+547,
+yycrank+626, yysvec+24, yyvstop+550,
+yycrank+627, yysvec+24, yyvstop+553,
+yycrank+630, yysvec+24, yyvstop+555,
+yycrank+631, yysvec+24, yyvstop+558,
+yycrank+0, 0, yyvstop+560,
+yycrank+632, yysvec+24, yyvstop+562,
+yycrank+633, yysvec+24, yyvstop+564,
+yycrank+634, yysvec+24, yyvstop+566,
+yycrank+635, yysvec+24, yyvstop+568,
+yycrank+636, yysvec+24, yyvstop+571,
+yycrank+639, yysvec+24, yyvstop+573,
+yycrank+640, yysvec+24, yyvstop+575,
+yycrank+642, yysvec+24, yyvstop+577,
+yycrank+644, yysvec+24, yyvstop+580,
+yycrank+645, yysvec+24, yyvstop+582,
+yycrank+648, yysvec+24, yyvstop+585,
+yycrank+646, yysvec+24, yyvstop+587,
+yycrank+649, yysvec+24, yyvstop+589,
+yycrank+650, yysvec+24, yyvstop+592,
+yycrank+659, yysvec+24, yyvstop+594,
+yycrank+653, yysvec+24, yyvstop+596,
+yycrank+654, yysvec+24, yyvstop+598,
+yycrank+657, yysvec+24, yyvstop+600,
+yycrank+663, yysvec+24, yyvstop+603,
+yycrank+658, yysvec+24, yyvstop+605,
+yycrank+660, yysvec+24, yyvstop+607,
+yycrank+661, yysvec+24, yyvstop+610,
+yycrank+664, yysvec+24, yyvstop+612,
+yycrank+669, yysvec+24, yyvstop+615,
+yycrank+672, yysvec+24, yyvstop+617,
+yycrank+666, yysvec+24, yyvstop+619,
+yycrank+676, yysvec+24, yyvstop+622,
+yycrank+681, yysvec+24, yyvstop+624,
+yycrank+682, yysvec+24, yyvstop+626,
+yycrank+683, yysvec+24, yyvstop+629,
+yycrank+685, yysvec+24, yyvstop+631,
+yycrank+686, yysvec+24, yyvstop+634,
+yycrank+687, yysvec+24, yyvstop+637,
+yycrank+689, yysvec+24, yyvstop+639,
+yycrank+688, yysvec+24, yyvstop+641,
+yycrank+692, yysvec+24, yyvstop+644,
+yycrank+690, yysvec+24, yyvstop+646,
+yycrank+724, yysvec+24, yyvstop+648,
+yycrank+722, yysvec+24, yyvstop+650,
+yycrank+727, yysvec+24, yyvstop+652,
+yycrank+729, yysvec+24, yyvstop+654,
+yycrank+697, yysvec+24, yyvstop+656,
+0, 0, 0};
+struct yywork *yytop = yycrank+809;
+struct yysvf *yybgin = yysvec+1;
+char yymatch[] = {
+00 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,
+01 ,011 ,012 ,01 ,01 ,01 ,01 ,01 ,
+01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,
+01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,
+011 ,01 ,'"' ,01 ,01 ,01 ,01 ,01 ,
+01 ,01 ,01 ,01 ,01 ,01 ,01 ,01 ,
+'0' ,'0' ,'0' ,'0' ,'0' ,'0' ,'0' ,'0' ,
+'0' ,'0' ,01 ,01 ,01 ,01 ,'>' ,01 ,
+01 ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'G' ,
+'G' ,'G' ,'G' ,'G' ,'G' ,'G' ,'G' ,'G' ,
+'G' ,'G' ,'G' ,'G' ,'G' ,'G' ,'G' ,'G' ,
+'G' ,'G' ,'G' ,01 ,01 ,01 ,01 ,'G' ,
+01 ,'A' ,'A' ,'A' ,'A' ,'A' ,'A' ,'G' ,
+'G' ,'G' ,'G' ,'G' ,'G' ,'G' ,'G' ,'G' ,
+'G' ,'G' ,'G' ,'G' ,'G' ,'G' ,'G' ,'G' ,
+'G' ,'G' ,'G' ,01 ,01 ,01 ,01 ,01 ,
+0};
+char yyextra[] = {
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0};
+int yylineno =1;
+# define YYU(x) x
+# define NLSTATE yyprevious=YYNEWLINE
+char yytext[YYLMAX];
+struct yysvf *yylstate [YYLMAX], **yylsp, **yyolsp;
+char yysbuf[YYLMAX];
+char *yysptr = yysbuf;
+int *yyfnd;
+extern struct yysvf *yyestate;
+int yyprevious = YYNEWLINE;
+yylook(){
+ register struct yysvf *yystate, **lsp;
+ register struct yywork *yyt;
+ struct yysvf *yyz;
+ int yych;
+ struct yywork *yyr;
+# ifdef LEXDEBUG
+ int debug;
+# endif
+ char *yylastch;
+ /* start off machines */
+# ifdef LEXDEBUG
+ debug = 0;
+# endif
+ if (!yymorfg)
+ yylastch = yytext;
+ else {
+ yymorfg=0;
+ yylastch = yytext+yyleng;
+ }
+ for(;;){
+ lsp = yylstate;
+ yyestate = yystate = yybgin;
+ if (yyprevious==YYNEWLINE) yystate++;
+ for (;;){
+# ifdef LEXDEBUG
+ if(debug)fprintf(yyout,"state %d\n",yystate-yysvec-1);
+# endif
+ yyt = yystate->yystoff;
+ if(yyt == yycrank){ /* may not be any transitions */
+ yyz = yystate->yyother;
+ if(yyz == 0)break;
+ if(yyz->yystoff == yycrank)break;
+ }
+ *yylastch++ = yych = input();
+ tryagain:
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"char ");
+ allprint(yych);
+ putchar('\n');
+ }
+# endif
+ yyr = yyt;
+ if ( (int)yyt > (int)yycrank){
+ yyt = yyr + yych;
+ if (yyt <= yytop && yyt->verify+yysvec == yystate){
+ if(yyt->advance+yysvec == YYLERR) /* error transitions */
+ {unput(*--yylastch);break;}
+ *lsp++ = yystate = yyt->advance+yysvec;
+ goto contin;
+ }
+ }
+# ifdef YYOPTIM
+ else if((int)yyt < (int)yycrank) { /* r < yycrank */
+ yyt = yyr = yycrank+(yycrank-yyt);
+# ifdef LEXDEBUG
+ if(debug)fprintf(yyout,"compressed state\n");
+# endif
+ yyt = yyt + yych;
+ if(yyt <= yytop && yyt->verify+yysvec == yystate){
+ if(yyt->advance+yysvec == YYLERR) /* error transitions */
+ {unput(*--yylastch);break;}
+ *lsp++ = yystate = yyt->advance+yysvec;
+ goto contin;
+ }
+ yyt = yyr + YYU(yymatch[yych]);
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"try fall back character ");
+ allprint(YYU(yymatch[yych]));
+ putchar('\n');
+ }
+# endif
+ if(yyt <= yytop && yyt->verify+yysvec == yystate){
+ if(yyt->advance+yysvec == YYLERR) /* error transition */
+ {unput(*--yylastch);break;}
+ *lsp++ = yystate = yyt->advance+yysvec;
+ goto contin;
+ }
+ }
+ if ((yystate = yystate->yyother) && (yyt= yystate->yystoff) != yycrank){
+# ifdef LEXDEBUG
+ if(debug)fprintf(yyout,"fall back to state %d\n",yystate-yysvec-1);
+# endif
+ goto tryagain;
+ }
+# endif
+ else
+ {unput(*--yylastch);break;}
+ contin:
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"state %d char ",yystate-yysvec-1);
+ allprint(yych);
+ putchar('\n');
+ }
+# endif
+ ;
+ }
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"stopped at %d with ",*(lsp-1)-yysvec-1);
+ allprint(yych);
+ putchar('\n');
+ }
+# endif
+ while (lsp-- > yylstate){
+ *yylastch-- = 0;
+ if (*lsp != 0 && (yyfnd= (*lsp)->yystops) && *yyfnd > 0){
+ yyolsp = lsp;
+ if(yyextra[*yyfnd]){ /* must backup */
+ while(yyback((*lsp)->yystops,-*yyfnd) != 1 && lsp > yylstate){
+ lsp--;
+ unput(*yylastch--);
+ }
+ }
+ yyprevious = YYU(*yylastch);
+ yylsp = lsp;
+ yyleng = yylastch-yytext+1;
+ yytext[yyleng] = 0;
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"\nmatch ");
+ sprint(yytext);
+ fprintf(yyout," action %d\n",*yyfnd);
+ }
+# endif
+ return(*yyfnd++);
+ }
+ unput(*yylastch);
+ }
+ if (yytext[0] == 0 /* && feof(yyin) */)
+ {
+ yysptr=yysbuf;
+ return(0);
+ }
+ yyprevious = yytext[0] = input();
+ if (yyprevious>0)
+ output(yyprevious);
+ yylastch=yytext;
+# ifdef LEXDEBUG
+ if(debug)putchar('\n');
+# endif
+ }
+ }
+yyback( int *p, int m)
+{
+if (p==0) return(0);
+while (*p)
+ {
+ if (*p++ == m)
+ return(1);
+ }
+return(0);
+}
+ /* the following are only used in the lex library */
+yyinput(){
+ return input();
+ }
+void yyoutput(c)
+ int c; {
+ output(c);
+ }
+void yyunput(c)
+ int c; {
+ unput(c);
+ }
diff --git a/private/os2/client/thunk/thunkcom/mtclex.l b/private/os2/client/thunk/thunkcom/mtclex.l
new file mode 100644
index 000000000..1c701ea01
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/mtclex.l
@@ -0,0 +1,245 @@
+%{
+#include <stdlib.h>
+#include "types.h"
+#include "symtab.h"
+#include "mtcpars.h"
+#include "thunk.h"
+
+typedef struct _FR {
+ int LineNo;
+ FILE *pfhFile;
+ char *pszFileName;
+ struct _FR *pPreviousFile;
+} FileRecord;
+
+FileRecord *FileList = NULL;
+
+static iCommentNesting = 0;
+
+%}
+Alpha ([a-zA-Z_]+)
+Numeric ([0-9]+)
+HexValue ([0-9a-fA-F]+)
+Ident ([a-zA-Z_][a-zA-Z_0-9]*)
+QString (\"[^"\n]*\")
+AString (\<[^>\n]*\>)
+
+%Start Normal EatComment LookFilename HexNum
+
+%%
+
+<Normal>"far16" return(syFar16);
+<Normal>"near32" return(syNear32);
+<Normal>"*" return(syPtr);
+<Normal>"API16" return(syAPI16);
+<Normal>"API32" return(syAPI32);
+<Normal>"unsigned" return(syUnsigned);
+<Normal>"signed" return(sySigned);
+<Normal>"long" return(syLong);
+<Normal>"short" return(syShort);
+<Normal>"int" return(syInt);
+<Normal>"typedef" return(syTypeDef);
+<Normal>"thunk" return(syMakeThunk);
+<Normal>"sizeof" return(sySizeOf);
+<Normal>"countof" return(syCountOf);
+<Normal>"input" return(syInput);
+<Normal>"inout" return(syInOut);
+<Normal>"output" return(syOutput);
+<Normal>"struct" return(syStruct);
+<Normal>"string" return(syString);
+<Normal>"passifhinull" return(syPassIfHiNull);
+<Normal>"special" return(sySpecial);
+<Normal>"maptoretval" return(syMapToRetval);
+<Normal>"reverserc" return(syReverseRC);
+<Normal>"localheap" return(syLocalHeap);
+<Normal>"void" return(syVoid);
+<Normal>"char" return(syChar);
+<Normal>"nulltype" return(syNullType);
+<Normal>"newelem" return(syNewElem);
+<Normal>"errnomem" return(syErrNoMem);
+<Normal>"errbadparam" return(syErrBadParam);
+<Normal>"errunknown" return(syErrUnknown);
+
+<Normal>"true" return(syTrue);
+<Normal>"false" return(syFalse);
+<Normal>"stack" return(syStack);
+<Normal>"inline" return(syInline);
+<Normal>"truncation" return(syTruncation);
+<Normal>"enablemapdirect1632" return(syEnableMapDirect1632);
+<Normal>"user" return(syUser);
+<Normal>"gdi" return(syGdi);
+<Normal>"kernel" return(syKernel);
+<Normal>"syscall" return(sySysCall);
+<Normal>"conforming" return(syConforming);
+<Normal>"byte" return(syByte);
+<Normal>"word" return(syWord);
+<Normal>"dword" return(syDWord);
+<Normal>"aligned" return(syAligned);
+<Normal>"deleted" return(syDeleted);
+
+<Normal>"allow" return(syAllow);
+<Normal>"restrict" return(syRestrict);
+
+<Normal>"=>" return(syMapDirect);
+<Normal>"=" return(syEqual);
+<Normal>"(" return(syLParen);
+<Normal>")" return(syRParen);
+<Normal>";" return(sySemi);
+<Normal>"+" return(syPlus);
+<Normal>"-" return(syMinus);
+<Normal>"/" return(syDiv);
+<Normal>"," return(syComma);
+<Normal>"{" return(syLBrace);
+<Normal>"}" return(syRBrace);
+<Normal>"[" return(syLBrack);
+<Normal>"]" return(syRBrack);
+
+<Normal>"#include" {
+ BEGIN LookFilename;
+ }
+
+<Normal>{Ident} {
+ yylval.ident = typ_DupString(yytext);
+ return(syIdent);
+ }
+
+<Normal>"0x" {
+ BEGIN HexNum;
+ }
+
+
+<HexNum>{HexValue} {
+ sscanf(yytext,"%lx",&yylval.longval);
+ BEGIN Normal;
+ return(syNumber);
+ }
+
+<HexNum>. {
+ return(syError);
+ }
+
+<Normal>{Numeric} {
+ yylval.longval = atoi(yytext);
+ return(syNumber);
+ }
+
+<Normal>[ \t\n] ;
+
+<Normal>"/*" {
+ iCommentNesting++;
+
+ BEGIN EatComment;
+ }
+
+<EatComment>"/*" {
+ iCommentNesting++;
+
+
+ }
+
+<EatComment>"*/" {
+ if(--iCommentNesting == 0) BEGIN Normal;
+ }
+
+<EatComment>[ \t\n] ;
+<EatComment>. ;
+
+<LookFilename>{QString} {
+ PushInclude(yytext);
+ BEGIN Normal;
+ }
+
+
+<LookFilename>{AString} {
+
+ }
+
+%%
+
+void PushInclude( char *yyFile)
+{
+ FILE *filePtr;
+ FileRecord *pTemp;
+
+ yyFile[yyleng-1] = '\0'; /* Remove Ending quote */
+ yyFile++; /* Skip first quote */
+
+
+ if(pTemp = (FileRecord *) malloc(sizeof(FileRecord))) {
+
+ pTemp->LineNo = yylineno;
+ pTemp->pfhFile = yyin;
+/*
+
+ if((pTemp->fhFile=dup(0)) < 0)
+ fatal("PushInclude: Out of file handles");
+*/
+
+ pTemp->pszFileName = yyinname;
+
+/*
+ if(close(0)) fatal("PushInclude close 0 failed");
+*/
+
+ pTemp->pPreviousFile = FileList;
+ FileList = pTemp;
+
+ } else {
+ fatal("PushInclude malloc failure");
+ }
+
+
+
+ filePtr = fopen(yyFile, "r");
+
+ if (filePtr == NULL) {
+ fatal("fopen(%s): Could not open file ",yyFile);
+ }
+ yyin = filePtr;
+
+ yylineno = 0;
+ yyinname = typ_DupString(yyFile);
+}
+
+
+
+void LookNormal( void)
+{
+ BEGIN Normal;
+}
+
+int yywrap( void)
+{
+ FileRecord *pTemp;
+
+ if(!FileList)
+ return 1;
+
+ /* Close current file */
+ if( fclose( yyin))
+ fatal( "yywrap close yyin failed");
+
+
+/*****
+ if(dup2(FileList->fhFile,0))
+ fatal( "yywrap dup failure");
+ if(close(FileList->fhFile))
+ fatal( "yywrap close %d failure", FileList->fhFile);
+*****/
+
+ yyin = FileList->pfhFile;
+
+ yylineno = FileList->LineNo;
+
+
+
+ yyinname = FileList->pszFileName;
+
+ pTemp= FileList;
+
+ FileList = FileList->pPreviousFile;
+
+ free( pTemp);
+
+ return 0;
+}
diff --git a/private/os2/client/thunk/thunkcom/mtcpars.y b/private/os2/client/thunk/thunkcom/mtcpars.y
new file mode 100644
index 000000000..d8c43a119
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/mtcpars.y
@@ -0,0 +1,1504 @@
+%{
+/***********************************************************************/
+/* mtcpars.y : Thunk Compiler input grammar for Yacc generated parser
+ *
+ * Created: 10/15/88 Kevin Ross Microsoft Corporation
+ *
+ *
+ * History:
+ * 10.12.90 Kevin Ruddell converted to thunk Win32, 16=>32
+ *
+ *
+*/
+/***********************************************************************/
+/* This parser generates all of the data structures used by the thunk
+ * compiler. There are three types of data structures generated, and
+ * each is explained fully in the file types.h. Semantic information
+ * is given near each rule.
+ *
+ */
+/***********************************************************************/
+#include <stdio.h>
+#include "thunk.h"
+#include "types.h"
+#include "symtab.h"
+#include "globals.h"
+
+extern FILE *StdDbg;
+
+static FunctionNode *MapF1, *MapF2;
+static TypeNode *T1, *T2;
+static TypeNode *T3, *T4;
+
+static long iPushValue;
+
+%}
+
+%union
+{
+ char *ident;
+ int intval;
+ TypeNode *type;
+ FunctionNode *func;
+ AllowNode *allow;
+ long longval;
+}
+
+%token syTypeDef
+%token syMakeThunk
+%token syArray
+%token syStruct
+%token <ident> syIdent
+%token <longval> syNumber
+%token <intval> syAPI16
+%token <intval> syAPI32
+%token syFar16
+%token syNear32
+%token syPtr /* used as both Pointer and Multiply operator */
+
+%token syStack
+%token syInline
+%token sySysCall
+%token syTrue
+%token syFalse
+
+%token sySizeOf
+%token syCountOf
+%token syPassIfHiNull
+%token sySpecial
+%token syMapToRetval
+%token syReverseRC
+%token syLocalHeap
+%token syInOut
+%token syOutput
+%token syInput
+%token syConforming
+%token syByte
+%token syWord
+%token syDWord
+%token syAligned
+%token syDeleted
+%token syTruncation
+%token syEnableMapDirect1632
+%token syUser
+%token syGdi
+%token syKernel
+%token syNewElem
+%token syErrNoMem
+%token syErrBadParam
+%token syErrUnknown
+
+%token syNullType
+%token syStruct
+%token syPointer
+%token syLong
+%token syShort
+%token syInt
+%token syUnsigned
+%token sySigned
+%token syVoid
+%token syChar
+%token syString
+
+%token syColon
+%token sySemi
+%token syComma
+%token syPlus
+%token syMinus
+%token syDiv
+%token syLParen
+%token syRParen
+
+%token syMapDirect
+%token syEqual
+
+%token syCaret
+%token syTilde
+%token syLAngle
+%token syRAngle
+%token syLBrack
+%token syRBrack
+%token syRBrace
+%token syLBrace
+
+%token syAllow
+%token syRestrict
+
+%token syError /* lex error */
+
+%left syPlus,syMinus
+%left syPtr,syDiv
+
+
+
+%type <type> BaseType KnownType ParamDecl StructElem
+%type <type> ParamList Parameters ExtendedBaseType
+%type <type> KnownType TypeDecl StructList StructDef
+%type <type> SemanticOp ParamType
+%type <func> FunctionDecl
+%type <intval> CallType Aligned Boolean PointerDecl ArrayDecl
+%type <intval> Reserved CallSemantics StructSemantics RCCondition
+%type <longval> Numeric
+%type <allow> AllowList AllowValues Allow
+
+%start Statements
+%%
+
+
+/******************************************************************************/
+/******************************************************************************/
+Statements : Statements Statement
+ {
+ }
+ | /* Empty statement OK */
+ ;
+
+
+/******************************************************************************/
+/******************************************************************************/
+/* A statement in the thunk language is either a typedef, a mapping
+ * declaration, a semantic declaration, or a mapping directive.
+ */
+
+Statement : syTypeDef TypeDecl
+ | Semantics
+ | Mapping
+ | MapDirect
+ ;
+
+/******************************************************************************/
+/******************************************************************************/
+/* These semantics are global to all API that are declared AFTER these
+ * statements. They set global values that are used in a Mapping statement
+ * when creating the mapping declarations
+ */
+
+Semantics : syErrBadParam syEqual Numeric sySemi
+ {
+ gErrBadParam = $3;
+ }
+ | syErrNoMem syEqual Numeric sySemi
+ {
+ gErrNoMem = $3;
+ }
+ | syErrUnknown syEqual Numeric sySemi
+ {
+ gfErrUnknown = 1;
+ gErrUnknown = $3;
+ }
+
+ | syUser syEqual Boolean sySemi
+ {
+ fUser = $3;
+ }
+
+ | syGdi syEqual Boolean sySemi
+ {
+ fGdi = $3;
+ }
+
+ | syKernel syEqual Boolean sySemi
+ {
+ fKernel = $3;
+ }
+
+
+/* This semantic sets the stack size for all API that follow.
+ */
+ | syStack syEqual Numeric sySemi
+ {
+ iGlobalStackSize = (unsigned int)$3;
+ }
+
+/* This semantic sets the SysCall flag for all API that follow.
+ * The Syscall determines if ES is saved or not.
+ */
+
+ | sySysCall syEqual Boolean sySemi
+ {
+ fGlobalSysCall = $3;
+ }
+
+/* This semantic sets the inline code generation flag to true or false.
+ * This flag is used to determine whether the compiler favors code size
+ * or execution speed when generating code.
+ */
+ | syInline syEqual Boolean sySemi
+ {
+ fGlobalInline = $3;
+ }
+
+/* Truncation enables/disables truncation checking when converting from
+ * a long value to a short value.
+ *
+ */
+ | syTruncation syEqual Boolean sySemi
+ {
+ fGlobalTruncation = ($3) ? SEMANTIC_TRUNC : 0;
+ }
+
+/* This semantic sets the flag to automatically generate map directives.
+ * If TRUE, a 16=>32 thunk will be generated for each mapping.
+ *
+ */
+ | syEnableMapDirect1632 syEqual Boolean sySemi
+ {
+ fEnableMapDirect1632 = $3;
+ }
+ ;
+
+
+
+/******************************************************************************/
+/******************************************************************************/
+/* A mapping directive tells the compiler to generate a thunk in FROM
+ * the first ident, TO the second ident. For example, Foo => Foo32 would
+ * generate a thunk such that if an App called Foo, the thunk would
+ * convert all parameters and call Foo32 on the App's behalf.
+ *
+ * For a mapping to be valid, both names must have been declared in
+ * the same mapping declaration (Mapping)
+ */
+
+MapDirect : syIdent syMapDirect syIdent sySemi
+ {
+ { /* Map Direct Block */
+ FunctionNode *temp1=NULL, *temp2=NULL;
+
+/* Find both identifiers in the FunctionTable. If they map to each other,
+ * and they don't already exist in the MapTable,
+ * then create a mapping node in the MapTable to include them for code
+ * generation.
+ */
+ if((temp1 = sym_FindSymbolFunctionNode(FunctionTable,$1))&&
+ (temp2 = sym_FindSymbolFunctionNode(FunctionTable,$3))){
+
+ if((temp1->pMapsToFunction == temp2) &&
+ (temp2->pMapsToFunction == temp1)) {
+
+ if(sym_FindFMapping(MapTable,$1,$3)) {
+ error("A mapping %s <=> %s already defined",$1,$3);
+ } else {
+ sym_AddFMapping(&MapTable,temp1,temp2);
+ }
+ } else {
+ error("%s does not map to %s",$1,$3);
+ }
+ } else {
+ error("Function %s undefined",(temp1) ? $3:$1);
+ }
+ } /* Map Direct Block */
+ }
+ ;
+
+
+/******************************************************************************/
+/******************************************************************************/
+/* A mapping defines the relationship between two Function declarations,
+ * and also relates the semantic operations to the parameters passed
+ * in the Function Mapping.
+ */
+
+Mapping : FunctionMap SemanticOps
+ {
+
+/* Ensure that the same functions cannot be given other semantics.
+ * MapF1 and MapF2 are two global variables set when the FunctionMap is
+ * evaluated, and used by the SemanticOps rule. By the time we reach here,
+ * both are evaluated, and done with.
+ */
+ MapF1 = MapF2 = NULL;
+ }
+ ;
+
+/******************************************************************************/
+/******************************************************************************/
+FunctionMap : FunctionDecl syEqual FunctionDecl
+
+{
+/* The thunk language does not require that the API types be declared.
+ * If no specific declaration is made, then the first API is assumed to
+ * be API16, and the second API32.
+ *
+ * Check to see if either API type was undeclared. If one was missing, insure
+ * that the other was also missing. If not, generate an error.
+ *
+ * If they were both missing, then default the first to be API16 and the
+ * second to be API32.
+ */
+
+ if(($1->iCallType < 0) || ($3->iCallType < 0)) {
+ if(($1->iCallType < 0) && ($3->iCallType < 0)) {
+ $1->iCallType = TYPE_API16;
+ $3->iCallType = TYPE_API32;
+
+ } else {
+ error("Mapping missing an API type: %s = %s",
+ $1->pchFunctionName,$3->pchFunctionName);
+ }
+ }
+
+
+/* Now check to see if the functions have already been declared. If so,
+ * then error. You may only define a function mapping once in this language.
+ */
+ if(sym_FindSymbolFunctionNode(FunctionTable,$3->pchFunctionName)) {
+
+ error("%s already defined",$3->pchFunctionName);
+
+ } else {
+ if(sym_FindSymbolFunctionNode(FunctionTable,$1->pchFunctionName)) {
+ error("%s already defined",$1->pchFunctionName);
+ } else {
+
+/* If both functions were missing from FunctionTable, then enter them into
+ * the FunctionTable, and set them so they map to each other.
+ */
+ sym_InsertFunctionNode(&FunctionTable,$3);
+ sym_InsertFunctionNode(&FunctionTable,$1);
+
+ $1->pMapsToFunction = $3;
+ $3->pMapsToFunction = $1;
+
+ MapF1 = $1;
+ MapF2 = $3;
+
+/* At this point, walk the list of parameters, and fixup pointers that
+ * have not been declared as a specific type, and any other parameters
+ * that are currently undetermined. Also, insure that all
+ * types can be converted between the two API.
+*/
+ typ_FunctionsCanMap(MapF1,MapF2);
+ }
+ }
+ }
+ ;
+
+
+/******************************************************************************/
+/******************************************************************************/
+/* SemanticOps are found between curly braces at the end of a
+ * Mapping declaration. These semantic operations are LOCAL to the two
+ * functions, and have no effect on other mappings.
+ */
+
+SemanticOps : syLBrace SemanticOpList syRBrace
+ {
+
+
+/**
+ ** Check to ensure that semantics make sense
+ **/
+ /* skip it
+ if(typ_CheckSemantics(MapF1->ParamList,MapF2->ParamList))
+ error("Semantic error in %s<=>%s",
+ MapF1->pchFunctionName,MapF2->pchFunctionName);
+ */
+
+ }
+
+SemanticOpList : /* Empty Semantics */
+ | SemanticOpList SemanticOp sySemi
+ ;
+
+SemanticOp : syIdent syEqual syInOut
+ {
+
+/* This semantic is basically the same for all, except it will set a
+ * different semantic flag.
+ *
+ * First, MapF1 must be non NULL. This implies that MapF2 is also non NULL.
+ * MapF1 points to the first function, and MapF2 points to the second.
+ */
+
+ if( ! MapF1) {
+ error("No mapping statement for semantic block");
+ } else {
+
+/* Here we search the parameter lists of both functions, looking for the
+ * first symbol name that matches the identifier given. T1 and T2 will
+ * end up pointing to the matching pair of parameters.
+ *
+ * This semantic is only valid for pointer parameters.
+ */
+ if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
+ &T1,&T2,$1)) {
+ if(T1->iPointerType && T2->iPointerType) {
+ if(T1->iBaseType == TYPE_STRING) {
+
+/* Null terminated strings are input only */
+
+ error("Strings cannot be inout parameters");
+ } else {
+
+/*
+ * Setting the INOUT semantic turns on both the INPUT and OUTPUT flags.
+ */
+ T1->fSemantics =T1->fSemantics | SEMANTIC_INOUT;
+ T2->fSemantics =T2->fSemantics | SEMANTIC_INOUT;
+ }
+ } else {
+ error("Semantic invalid for non-pointer parameters");
+ }
+ } else {
+ error("%s not in parameter list of %s",
+ $1,MapF1->pchFunctionName);
+ }
+ }
+ }
+ | syErrNoMem syEqual Numeric
+ {
+ if( ! MapF1) {
+ error("No mapping statement for semantic block");
+ } else {
+ MapF1->ulErrNoMem = $3;
+ MapF2->ulErrNoMem = $3;
+ }
+ }
+
+ | syErrBadParam syEqual Numeric
+ {
+ if( ! MapF1) {
+ error("No mapping statement for semantic block");
+ } else {
+ MapF1->ulErrBadParam = $3;
+ MapF2->ulErrBadParam = $3;
+ }
+ }
+ | syErrUnknown syEqual Numeric
+ {
+ if( ! MapF1) {
+ error("No mapping statement for semantic block");
+ } else {
+
+ MapF1->fErrUnknown = 1;
+ MapF2->fErrUnknown = 1;
+ MapF1->ulErrUnknown = $3;
+ MapF2->ulErrUnknown = $3;
+ }
+
+ }
+ | syIdent syEqual syInput
+ {
+/* Basically the same as syInout, except for semantic set is INPUT */
+
+ if( ! MapF1) {
+ error("No mapping statement for semantic block");
+ } else {
+
+ if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
+ &T1,&T2,$1)) {
+ if(T1->iPointerType && T2->iPointerType) {
+ T1->fSemantics =(T1->fSemantics | SEMANTIC_INPUT)
+ & (~SEMANTIC_OUTPUT);
+ T2->fSemantics =(T2->fSemantics | SEMANTIC_INPUT)
+ & (~SEMANTIC_OUTPUT);
+ } else {
+ error("Semantic invalid for non-pointer parameters");
+ }
+ } else {
+ error("%s not in parameter list of %s",
+ $1,MapF1->pchFunctionName);
+ }
+ }
+
+ }
+ | syIdent syEqual syOutput
+ {
+/* Basically the same as syInout, except for semantic set is OUTPUT */
+ if( ! MapF1) {
+ error("No mapping statement for semantic block");
+ } else {
+
+ if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
+ &T1,&T2,$1)) {
+
+ if(T1->iPointerType && T2->iPointerType) {
+ if(T1->iBaseType == TYPE_STRING) {
+ error("Strings cannot be output parameters");
+ } else {
+ T1->fSemantics =(T1->fSemantics | SEMANTIC_OUTPUT)
+ & (~SEMANTIC_INPUT);
+ T2->fSemantics =(T2->fSemantics | SEMANTIC_OUTPUT)
+ & (~SEMANTIC_INPUT);
+ }
+ } else {
+ error("Semantic invalid for non-pointer parameters");
+ }
+
+ } else {
+ error("%s not in parameter list of %s",
+ $1,MapF1->pchFunctionName);
+ }
+ }
+
+ }
+
+ | syIdent syEqual sySizeOf syIdent
+ {
+
+/* The Sizeof semantic declares the first syIdent to be the semantic size
+ * of the second syIdent. This size is determined at runtime of the thunk.
+ *
+ * Here, we must find both syIdent's in the parameter lists.
+ */
+
+ if( ! MapF1) {
+ error("No mapping statement for semantic block");
+ } else {
+
+ if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
+ &T1,&T2,$1)) {
+
+ if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
+ &T3,&T4,$4)) {
+
+ if(T4->iBaseType == TYPE_STRING) {
+ error("Strings have no length semantics");
+
+ } else if(T1->iBaseType >= TYPE_CONV) {
+
+ error("Type of '%s' cannot represent length",$1);
+
+ } else if(T3->iPointerType == 0) {
+
+ error("Non pointer types have no length semantics");
+
+ } else {
+
+/** Here, we relate the parameter to its size, and vice versa **/
+
+ if(T3->iBaseType == TYPE_STRUCT) {
+
+ if(typ_StructHasPointers(T3->pStructElems,T4->pStructElems))
+ error("sizeof on struct with imbedded pointers");
+
+ }
+
+ T1->fSemantics = T1->fSemantics | SEMANTIC_SIZE;
+ T2->fSemantics = T2->fSemantics | SEMANTIC_SIZE;
+ T3->pSizeParam = T1;
+ T4->pSizeParam = T2;
+ T1->pParamSizeOf = T3;
+ T2->pParamSizeOf = T4;
+ }
+ } else{
+ error("%s not in parameter list of %s",
+ $4,MapF1->pchFunctionName);
+ }
+ } else {
+ error("%s not in parameter list of %s",
+ $1,MapF1->pchFunctionName);
+ }
+ }
+
+ }
+
+ | syIdent syEqual syCountOf syIdent
+ {
+/** This is basically the same as sySizeOf, except the semantic set is
+ * different
+ */
+ if( ! MapF1) {
+ error("No mapping statement for semantic block");
+ } else {
+
+ if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
+ &T1,&T2,$1)) {
+
+ if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
+ &T3,&T4,$4)) {
+ if(T1->iBaseType == TYPE_STRING) {
+ error("Strings have no count semantics");
+ } else if(T1->iBaseType >= TYPE_CONV) {
+ error("Type of '%s' cannot represent count",$1);
+ } else if(T3->iPointerType == 0) {
+ error("Non pointer types have no count semantics");
+ } else if(T3->iBaseType == TYPE_STRUCT &&
+ typ_StructHasPointers(T3->pStructElems,
+ T4->pStructElems)) {
+ error("Countof on struct with imbedded pointers");
+ } else {
+ T1->fSemantics = T1->fSemantics | SEMANTIC_COUNT;
+ T2->fSemantics = T2->fSemantics | SEMANTIC_COUNT;
+ T3->pSizeParam = T1;
+ T4->pSizeParam = T2;
+ T1->pParamSizeOf = T3;
+ T2->pParamSizeOf = T4;
+ }
+ } else{
+ error("%s not in parameter list of %s",
+ $4,MapF1->pchFunctionName);
+ }
+ } else {
+ error("%s not in parameter list of %s",
+ $1,MapF1->pchFunctionName);
+ }
+ }
+
+ }
+
+ | syIdent syEqual syPassIfHiNull
+ {
+/* Here, we mark a parameter to be passed through without conversion
+ * if its high word is null.
+ */
+ if( !MapF1) {
+ error( "No mapping statement for semantic block");
+ } else {
+ if( sym_FindSymbolTypeNodePair( MapF1->ParamList,
+ MapF2->ParamList, &T1, &T2, $1)) {
+ if( T1->iPointerType && T2->iPointerType) {
+ T1->fSemantics |= SEMANTIC_PASSIFHINULL;
+ T2->fSemantics |= SEMANTIC_PASSIFHINULL;
+ } else {
+ error( "%s must be pointer to pass if hi null",
+ $1);
+ }
+ } else {
+ error( "%s not in parameter list of %s",
+ $1, MapF1->pchFunctionName);
+ }
+ }
+ }
+
+
+ | syIdent syEqual sySpecial
+ {
+/* Here, we mark a parameter as needing special code.
+ */
+ if( !MapF1) {
+ error( "No mapping statement for semantic block");
+ } else {
+ if( sym_FindSymbolTypeNodePair( MapF1->ParamList,
+ MapF2->ParamList, &T1, &T2, $1)) {
+ T1->fSemantics |= SEMANTIC_SPECIAL;
+ T2->fSemantics |= SEMANTIC_SPECIAL;
+ } else {
+ error( "%s not in parameter list of %s",
+ $1, MapF1->pchFunctionName);
+ }
+ }
+ }
+
+
+ | syIdent syEqual syMapToRetval RCCondition
+ {
+/* Here, we mark a parameter to map to the return value of the other API.
+ */
+ if( !MapF1) {
+ error( "No mapping statement for semantic block");
+ } else {
+ if( sym_FindSymbolTypeNodePair( MapF1->ParamList,
+ MapF2->ParamList, &T1, &T2, $1)) {
+ if( (MapF1->iCallType==TYPE_API16) &&
+ (T2->iBaseType==TYPE_STRUCT) &&
+ (T2->iPointerType)) {
+ T2->fSemantics |= SEMANTIC_MAPTORETVAL | $4;
+ } else if( (MapF2->iCallType==TYPE_API16) &&
+ (T1->iBaseType==TYPE_STRUCT) &&
+ (T1->iPointerType)) {
+ T1->fSemantics |= SEMANTIC_MAPTORETVAL | $4;
+ } else {
+ error( "%s can't map to a return value", $1);
+ }
+ } else {
+ error( "%s not in parameter list of %s",
+ $1, MapF1->pchFunctionName);
+ }
+ }
+ }
+
+
+ | syIdent syEqual syLocalHeap
+ {
+/* Here, we mark a parameter as being relative to the local heap.
+ * In 32-bit it is a flat address.
+ * In 16-bit it is relative to the base of the local heap segment.
+ */
+ if( !MapF1) {
+ error( "No mapping statement for semantic block");
+ } else {
+ if( sym_FindSymbolTypeNodePair( MapF1->ParamList,
+ MapF2->ParamList, &T1, &T2, $1)) {
+ T1->fSemantics |= SEMANTIC_LOCALHEAP;
+ T2->fSemantics |= SEMANTIC_LOCALHEAP;
+ } else {
+ error( "%s not in parameter list of %s",
+ $1, MapF1->pchFunctionName);
+ }
+ }
+ }
+
+
+ | syStack syIdent syEqual Numeric
+ {
+/* Here, we can set the stack size of an individual function. This new value
+ * This new value overwrites the default value in the function node.
+ *
+ * syIdent is the name of the function that this value is to be set on,
+ * and must be one of the functions that the current semantic block is
+ * defined in.
+ */
+ if(MapF1 && !strcmp($2, MapF1->pchFunctionName)) {
+ MapF1->iMinStack = (unsigned int)$4;
+ } else if( MapF2 && !strcmp($2, MapF2->pchFunctionName)) {
+ MapF2->iMinStack = (unsigned int)$4;
+ } else {
+ error("%s is not in current mapping",$2);
+ }
+ }
+ | syInline syIdent syEqual Boolean
+ {
+
+/* Here we set the inline flag. Same explanation as syStack */
+
+ if(MapF1 && !strcmp($2, MapF1->pchFunctionName)) {
+ MapF1->fInlineCode = $4;
+ } else if( MapF2 && !strcmp($2, MapF2->pchFunctionName)) {
+ MapF2->fInlineCode = $4;
+ } else {
+ error("%s is not in current mapping",$2);
+ }
+ }
+
+ | syIdent syEqual syConforming
+ {
+/* Here we set the conforming flag. Same explanation as syStack */
+
+ if(MapF1 && !strcmp($1, MapF1->pchFunctionName)) {
+ MapF1->fConforming = TRUE;
+ } else if( MapF2 && !strcmp($1, MapF2->pchFunctionName)) {
+ MapF2->fConforming = TRUE;
+ } else {
+ error("%s is not valid in current mapping",$1);
+ }
+ }
+
+
+ | syIdent syEqual syAllow AllowValues
+ {
+
+ if( ! MapF1) {
+ error("No mapping statement for semantic block");
+ } else {
+
+
+ if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
+ &T1,&T2,$1)) {
+
+ if(T1->AllowList)
+ error("Allow/Restrict list redefined");
+
+ T1->AllowList = $4;
+ T2->AllowList = $4;
+
+ } else {
+ error("%s not in parameter list of %s",
+ $1,MapF1->pchFunctionName);
+ }
+ }
+
+ }
+
+ | syIdent syEqual syRestrict AllowValues
+ {
+
+ if( ! MapF1) {
+ error("No mapping statement for semantic block");
+ } else {
+
+
+ if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
+ &T1,&T2,$1)) {
+ if(T1->iPointerType || T2->iPointerType) {
+ error("restrict semantic invalid "
+ "for pointer parameters");
+ } else {
+ T1->fSemantics = T1->fSemantics | SEMANTIC_RESTRICT;
+ T2->fSemantics = T2->fSemantics | SEMANTIC_RESTRICT;
+
+ if(T1->AllowList)
+ error("Allow/Restrict list redefined");
+
+ T1->AllowList = $4;
+ T2->AllowList = $4;
+ }
+ } else {
+ error("%s not in parameter list of %s",
+ $1,MapF1->pchFunctionName);
+ }
+ }
+ }
+ ;
+
+/******************************************************************************/
+/******************************************************************************/
+/* A function declaration accepts a CallType, a return type, an identifier,
+ * and a list of parameters. It then makes a function node containing
+ * all of this information. If the CallType is not given, then the
+ * field is passed as undefined (-1), and will be determined later.
+ */
+
+FunctionDecl : CallType KnownType syIdent Parameters
+ {
+ $$ = typ_MakeFunctionNode($1,$2,$3,$4);
+ }
+ | KnownType syIdent Parameters
+ {
+ $$ = typ_MakeFunctionNode(-1,$1,$2,$3);
+ }
+ | CallType CallSemantics KnownType syIdent Parameters
+ {
+ $$ = typ_MakeFunctionNode($1,$3,$4,$5);
+ $$->ReturnType->fSemantics |= $2;
+ }
+ | CallSemantics KnownType syIdent Parameters
+ {
+ $$ = typ_MakeFunctionNode(-1,$2,$3,$4);
+ $$->ReturnType->fSemantics |= $1;
+ }
+ ;
+
+
+/******************************************************************************/
+CallSemantics : syLocalHeap
+ {
+ $$ = SEMANTIC_LOCALHEAP;
+ }
+ | sySpecial
+ {
+ $$ = SEMANTIC_SPECIAL;
+ }
+ ;
+
+/******************************************************************************/
+RCCondition : /* Empty */
+ {
+ $$ = 0;
+ }
+ | syReverseRC
+ {
+ $$ = SEMANTIC_REVERSERC;
+ }
+ ;
+
+
+/******************************************************************************/
+/******************************************************************************/
+/* The Allow list is a list of values that the compiler will truncate
+ * without returning an error. Such values are used when a parameter
+ * that is normally declared as a ULONG is passed around using
+ *
+ */
+
+AllowValues : syLParen AllowList syRParen
+ {
+ $$ = $2;
+ }
+ ;
+
+AllowList : /* Empty */
+ {
+ }
+ | Allow
+ {
+ $$ = $1;
+ }
+ | AllowList syComma Allow
+ {
+ if($$ = $3) {
+ $3->Next = $1;
+ }
+ }
+ ;
+
+Allow : Numeric
+ {
+ $$ = typ_MakeAllowNode($1);
+ }
+ ;
+
+
+/******************************************************************************/
+/******************************************************************************/
+/* Because of the way the yacc parser works, the list of parameters
+ * has been built in the reverse order of what the compiler needs.
+ * Therefore, we need to reverse the order of the list of types
+ * returned by ParamList
+ */
+Parameters : syLParen ParamList syRParen
+ {
+ $$ = sym_ReverseTypeList($2);
+ }
+ ;
+
+/* A parameter list is a comma separated list of ParamType
+ */
+
+ParamList : /* empty */
+ {
+ $$ = NULL;
+ }
+
+ | ParamType
+ {
+ $$ = $1;
+ }
+
+ | ParamList syComma ParamType
+ {
+
+/* Check to see if the identifier for ParamType is already in the
+ * list ParamList. If so, it's an error.
+ */
+
+ if($$ = $3) {
+ if( sym_FindSymbolTypeNode($1,typ_NonNull($3->pchIdent))) {
+ error("Duplicate Parameter : %s",$3->pchIdent);
+ } else {
+ $3->pNextNode = $1;
+ }
+ } else {
+ $$ = $1;
+ }
+ }
+ ;
+
+
+/* Param type is only used in formal parameter declarations.
+ * Here, we look for the next ParamDecl. If it is non-null, then
+ * we check it for a few conditions, and pass it back.
+ */
+
+ParamType : ParamDecl Reserved
+ {
+ if($$ = $1) {
+ $$->iDeleted = $2;
+ $$->iFillValue = iPushValue;
+/*
+ * Structures can only be passed by pointer through an API
+ */
+/*
+ * if(($1->iBaseType == TYPE_STRUCT) && (!$1->iPointerType)) {
+ * error("Structure parameters require pointer type");
+ * }
+ */
+/*
+ * Array types can only be passed by pointer through an API
+ */
+ if(($1->iArraySize > 1) && (!$1->iPointerType)) {
+ error("Array parameters require pointer type");
+ }
+/*
+ * Void types must be pointers.
+ */
+
+ if(($1->iBaseType == TYPE_VOID) && (!$1->iPointerType)) {
+ error("Void types must be pointers");
+ }
+/*
+ * We currently don't handle arrays of structures.
+ */
+ if(($1->iBaseType == TYPE_STRUCT) && ($1->iArraySize > 1)) {
+ error("Parameters cannot be arrays of structures");
+ }
+ }
+ }
+ ;
+
+Reserved : /** No reserved keyword **/
+ {
+ $$ = 0;
+ }
+ | syDeleted
+ {
+ $$ = TYPE_DELETED;
+ iPushValue = 0;
+ }
+ | syDeleted Numeric
+ {
+ $$ = TYPE_DELETED;
+ iPushValue = $2;
+ }
+ ;
+
+
+/******************************************************************************/
+/******************************************************************************/
+/* A TypeDecl handles typedef statements. A valid typedef statement must
+ * include a KnownType, and a new identifier, an optional ArrayDecl, and
+ * end with a semicolon.
+ */
+
+TypeDecl : KnownType syIdent ArrayDecl sySemi
+ {
+
+/* If the 'KnowType' was not recogized, then an error message has already
+ * been issued, and we don't need further action
+ */
+ if( !$1) {
+ $$ = NULL;
+ } else
+
+/* Now, search for the syIdent in the currently known TypeTable. If it
+ * is found, then it is a redeclaration, which is not allowed.
+ *
+ * If not found, then make a copy of the TypeNode, and insert it into
+ * TypeTable.
+ *
+ * Check to see if the new type is a special handle. Set a flag if so.
+ *
+ * Then check the array size. If the array size > 1 already, then it's
+ * an error, since would redefine the size of the array.
+ */
+ if( sym_FindSymbolTypeNode(TypeTable,$2)) {
+ error("Duplicate Declaration of %s",$2);
+ } else {
+
+ $$ = typ_CopyTypeNode($1);
+ if($$) {
+ $$->pchIdent = typ_DupString($2);
+ sym_InsertTypeNode(&TypeTable,$$);
+ typ_EvalHandleType( $$);
+ switch ($3) {
+ case -1 : break;
+ case 0 :
+ error("%s declared as array size = 0",$2);
+ break;
+ default :
+ if($$->iArraySize == 1) {
+ $$->iArraySize = $3;
+ } else if($3 < -1) {
+ error("%s declared array size < 0",$2);
+ } else {
+ error("%s redeclared array size",$2);
+ }
+ }
+ }
+
+ }
+ }
+/* Structure definitions come in two flavors, one with an alignment
+ * declaration, and one without.
+ *
+ * The workings are exactly like the other typedef, except that arrays
+ * of structures are not allowed.
+ */
+
+ | syStruct syIdent StructDef syIdent sySemi
+ {
+ if( $$ = $3) {
+ if( sym_FindSymbolTypeNode(TypeTable,$4)) {
+ error("Duplicate Declaration of %s",$4);
+ } else {
+ $$->iAlignment = -1;
+ $$->pchBaseTypeName =(char *)malloc(8+strlen($4));
+ sprintf($$->pchBaseTypeName,"struct %s",$4);
+ $$->pchIdent = (char *) typ_DupString($4);
+ sym_InsertTypeNode(&TypeTable,$$);
+ }
+ }
+ }
+
+ | Aligned syStruct syIdent StructDef syIdent sySemi
+ {
+ if( $$ = $4) {
+ if( sym_FindSymbolTypeNode(TypeTable,$5)) {
+ error("Duplicate Declaration of %s",$5);
+ } else {
+ $$->iAlignment = $1;
+ $$->pchBaseTypeName =(char *)malloc(8+strlen($5));
+ sprintf($$->pchBaseTypeName,"struct %s",$5);
+ $$->pchIdent = (char *) typ_DupString($5);
+ sym_InsertTypeNode(&TypeTable,$$);
+ }
+ }
+ }
+ ;
+
+/******************************************************************************/
+/******************************************************************************/
+/* A structure definition creates a type node, which has pStructElems that
+ * points to a list of typenodes. This list of typenodes consists of the
+ * elements of the structure.
+ */
+StructDef : syLBrace StructList syRBrace
+ {
+ if($2) {
+ $$ = typ_MakeTypeNode(TYPE_STRUCT);
+ $$->pStructElems = $2;
+ } else
+ $$ = NULL;
+ }
+ ;
+
+/*
+ * StructList makes a list of structure elements.
+ */
+
+StructList : /* empty */
+ {
+ $$ = NULL;
+ }
+ | StructElem StructList
+ {
+
+ if($$ = $1) {
+ if( sym_FindSymbolTypeNode($2,$1->pchIdent))
+ error("Duplicate Declaration of %s",$1->pchIdent);
+ $$->pNextNode = $2;
+ }
+ }
+ ;
+
+/* A structure element is declared the same way as a formal parameter
+ * is declared, minus the comma separators. Reuse that rule for a StructElem.
+ */
+
+
+StructElem : ParamDecl Reserved sySemi
+ {
+ if($$ = $1) {
+ $$->pNextNode = NULL;
+ $$->iFillValue = iPushValue;
+ $$->iDeleted = $2;
+ if( $$->iDeleted && $$->iPointerType) {
+ error("Deleted element %s cannot be pointer",
+ $$->pchIdent);
+ }
+ }
+ }
+ | ParamDecl StructSemantics sySemi
+ {
+ if($$ = $1) {
+ $$->pNextNode = NULL;
+ $$->iFillValue = 0;
+ $$->iDeleted = 0;
+ $$->fSemantics |= $2;
+ }
+
+ }
+ ;
+
+/******************************************************************************/
+StructSemantics : syPassIfHiNull
+ {
+ $$ = SEMANTIC_PASSIFHINULL;
+ }
+ ;
+
+
+/******************************************************************************/
+/******************************************************************************/
+/* An array declaration is either non-existent, or is a number enclosed in
+ * brackets. Return the number in brackets, or -1 if it doesn't exist.
+ */
+
+ArrayDecl : /** No array Declaration **/
+ {
+ $$ = -1;
+ }
+ | syLBrack Numeric syRBrack
+ {
+ $$ = (int)$2;
+ }
+ ;
+
+/******************************************************************************/
+/******************************************************************************/
+/* ParamDecl is a rule used in the declaration of parameters, and is also
+ * used when declaring a structure. It will return a typenode, which has
+ * been filled out with all the given information. There are two types of
+ * ParamDecl. The first is the full definition, such as one would use in
+ * the definition of a structure element. The other is a short definition,
+ * such as in a function prototype. Both are legal, though the full
+ * definition is required to declare an array.
+ */
+
+
+ParamDecl : KnownType syIdent ArrayDecl
+ {
+ if($$ = $1) {
+ $$->pchIdent = typ_DupString($2);
+ switch ($3) {
+ case -1 : break;
+ case 0 : error("%s declared as array size = 0",$2);
+ break;
+ default :
+ if($$->iArraySize == 1) {
+ $$->iArraySize = $3;
+ } else if($3 < -1) {
+ error("%s declared array size < 0",$2);
+ } else {
+ error("%s redeclared array size",$2);
+ }
+ }
+ }
+ }
+
+ | KnownType
+ {
+ if($$ = $1)
+ $$->pchIdent = NULL;
+ }
+
+ ;
+
+
+/******************************************************************************/
+/******************************************************************************/
+/* The aligned statement matches an optional alignment keyword followed
+ * by the word 'aligned'. Used in the declaration and use of structures.
+ */
+
+Aligned : syDWord syAligned
+ {
+ $$ = 4;
+ }
+ | syWord syAligned
+ {
+ $$ = 2;
+ }
+ | syByte syAligned
+ {
+ $$ = 1;
+ }
+ | syDWord
+ {
+ $$ = 4;
+ }
+ | syWord
+ {
+ $$ = 2;
+ }
+ | syByte
+ {
+ $$ = 1;
+ }
+ ;
+
+/******************************************************************************/
+/******************************************************************************/
+/* A knowntype returns a pointer to a copy of a known type. A known type is
+ * one that is built into the language, or one that has been declared using
+ * a typedef. Note that it will always return a COPY of the item. This allows
+ * the rest of the compiler to change the fields in the typenode, without
+ * changing other uses of the same typenode.
+ *
+ * It is possible for a known type to be required to be a pointer.
+ * If an item must be a pointer type, such as a string, checking is done
+ * here, by using the ExtendedBaseType rule. Anything using the Extended
+ * BaseType is supposed to have a pointer operator with it, such as the
+ * case where the type is a string.
+ *
+ */
+
+KnownType : ExtendedBaseType PointerDecl
+ {
+ if( $1) {
+ $$ = typ_CopyTypeNode($1);
+ if($2)
+ $$->iPointerType = $2;
+ else
+ error("Type must be pointer");
+ }
+ }
+
+ | BaseType PointerDecl
+ {
+ if( $1) {
+ $$ = typ_CopyTypeNode($1);
+ if($2)
+ $$->iPointerType = $2;
+ }
+ }
+ | Aligned BaseType PointerDecl
+ {
+ if( $$ = $2) {
+ if( $2->iBaseType == TYPE_STRUCT) {
+ $$ = typ_CopyTypeNode($2);
+ $$->iAlignment = $1;
+ if( $3)
+ $$->iPointerType = $3;
+ } else {
+ error("Alignment only applies to structures");
+ }
+ }
+ }
+/* | Aligned BaseType PointerDecl
+ {
+ if( $$ = $2) {
+ $$ = typ_CopyTypeNode( $2);
+ if( $3)
+ $$->iPointerType = $3;
+ $$->iAlignment = $1;
+ if( ($2->iBaseType != TYPE_STRUCT) && ($1 != -1)) {
+ error( "Alignment only applies to structures");
+ }
+ }
+ }
+ */
+ ;
+
+/******************************************************************************/
+/******************************************************************************/
+/** Extended base types determine types which are pointers */
+/** An Extended base type is different in that it requires a pointer **/
+
+ExtendedBaseType : syString
+ {
+ $$ = BaseTable[SYMTAB_STRING];
+ }
+ ;
+
+/* BaseType is a rule that is the bottom of the type search tree. Here,
+ * the compiler either finds the type being looked for, or reports an
+ * error. If the type is a 'built-in' type, then a pointer to the item
+ * in the BaseTable is returned, without searching the list of types.
+ *
+ * Otherwise, the symbol found is a syIdent, which will be used to search
+ * the TypeTable. If the TypeTable contains the syIdent, then it is a
+ * known type, and a pointer to it will be returned. Otherwise, it is an
+ * undefined type, and an error is reported.
+ */
+
+BaseType : syLong
+ {
+ $$ = BaseTable[SYMTAB_LONG];
+ }
+ | syShort
+ {
+ $$ = BaseTable[SYMTAB_SHORT];
+ }
+ | syInt
+ {
+ $$ = BaseTable[SYMTAB_INT];
+ }
+ | syUnsigned syLong
+ {
+ $$ = BaseTable[SYMTAB_ULONG];
+ }
+ | syUnsigned syShort
+ {
+ $$ = BaseTable[SYMTAB_USHORT];
+ }
+ | syUnsigned syInt
+ {
+ $$ = BaseTable[SYMTAB_UINT];
+ }
+ | syVoid
+ {
+ $$ = BaseTable[SYMTAB_VOID];
+ }
+ | syUnsigned syChar
+ {
+ $$ = BaseTable[SYMTAB_UCHAR];
+ }
+ | syChar
+ {
+ $$ = BaseTable[SYMTAB_CHAR];
+ }
+ | syIdent
+ {
+ $$ = sym_FindSymbolTypeNode(TypeTable,$1);
+ if( $$ == NULL)
+ error("type '%s' unknown",$1);
+ }
+ | syNullType
+ {
+ $$ = BaseTable[SYMTAB_NULLTYPE];
+ }
+ ;
+
+/******************************************************************************/
+/******************************************************************************/
+/* There are Four types of pointer declarations. None, in which case a
+ * zero is returned. A syPtr, or '*', which defines an unspecified pointer
+ * type. A syNear32 and syFar16 define specific pointer types, which are
+ * special.
+ */
+
+
+PointerDecl : /** No pointer decl **/
+ {
+ $$ = 0;
+ }
+ | syPtr
+ {
+ $$ = TYPE_PTR;
+ }
+ | syFar16
+ {
+ $$ = TYPE_FAR16;
+ }
+ | syNear32
+ {
+ $$ = TYPE_NEAR32;
+ }
+ ;
+
+
+/******************************************************************************/
+/******************************************************************************/
+CallType : syAPI16
+ {
+ $$ = TYPE_API16 ;
+ }
+ | syAPI32
+ {
+ $$ = TYPE_API32;
+ }
+ ;
+
+/******************************************************************************/
+/******************************************************************************/
+Boolean : syTrue
+ {
+ $$ = TRUE;
+ }
+ | syFalse
+ {
+ $$ = FALSE;
+ }
+ ;
+
+/******************************************************************************/
+/******************************************************************************/
+Numeric : syNumber
+ {
+ $$ = $1;
+ }
+ | Numeric syPlus Numeric
+ {
+ $$ = $1 + $3;
+ }
+ | Numeric syMinus Numeric
+ {
+ $$ = $1 - $3;
+ }
+ | Numeric syPtr Numeric /** syPtr = '*' **/
+ {
+ $$ = $1 * $3;
+ }
+ | Numeric syDiv Numeric
+ {
+ if($3)
+ $$ = $1 / $3;
+ else
+ error("Divide by zero");
+ }
+ ;
+
+/******************************************************************************/
+/******************************************************************************/
+%%
+
+
+extern int yydebug;
+
+void yyerror(s)
+char *s;
+{
+ error(s);
+}
diff --git a/private/os2/client/thunk/thunkcom/ncform b/private/os2/client/thunk/thunkcom/ncform
new file mode 100644
index 000000000..52d2af77d
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/ncform
@@ -0,0 +1,178 @@
+int yylineno =1;
+# define YYU(x) x
+# define NLSTATE yyprevious=YYNEWLINE
+char yytext[YYLMAX];
+struct yysvf *yylstate [YYLMAX], **yylsp, **yyolsp;
+char yysbuf[YYLMAX];
+char *yysptr = yysbuf;
+int *yyfnd;
+extern struct yysvf *yyestate;
+int yyprevious = YYNEWLINE;
+yylook(){
+ register struct yysvf *yystate, **lsp;
+ register struct yywork *yyt;
+ struct yysvf *yyz;
+ int yych;
+ struct yywork *yyr;
+# ifdef LEXDEBUG
+ int debug;
+# endif
+ char *yylastch;
+ /* start off machines */
+# ifdef LEXDEBUG
+ debug = 0;
+# endif
+ if (!yymorfg)
+ yylastch = yytext;
+ else {
+ yymorfg=0;
+ yylastch = yytext+yyleng;
+ }
+ for(;;){
+ lsp = yylstate;
+ yyestate = yystate = yybgin;
+ if (yyprevious==YYNEWLINE) yystate++;
+ for (;;){
+# ifdef LEXDEBUG
+ if(debug)fprintf(yyout,"state %d\n",yystate-yysvec-1);
+# endif
+ yyt = yystate->yystoff;
+ if(yyt == yycrank){ /* may not be any transitions */
+ yyz = yystate->yyother;
+ if(yyz == 0)break;
+ if(yyz->yystoff == yycrank)break;
+ }
+ *yylastch++ = yych = input();
+ tryagain:
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"char ");
+ allprint(yych);
+ putchar('\n');
+ }
+# endif
+ yyr = yyt;
+ if ( (int)yyt > (int)yycrank){
+ yyt = yyr + yych;
+ if (yyt <= yytop && yyt->verify+yysvec == yystate){
+ if(yyt->advance+yysvec == YYLERR) /* error transitions */
+ {unput(*--yylastch);break;}
+ *lsp++ = yystate = yyt->advance+yysvec;
+ goto contin;
+ }
+ }
+# ifdef YYOPTIM
+ else if((int)yyt < (int)yycrank) { /* r < yycrank */
+ yyt = yyr = yycrank+(yycrank-yyt);
+# ifdef LEXDEBUG
+ if(debug)fprintf(yyout,"compressed state\n");
+# endif
+ yyt = yyt + yych;
+ if(yyt <= yytop && yyt->verify+yysvec == yystate){
+ if(yyt->advance+yysvec == YYLERR) /* error transitions */
+ {unput(*--yylastch);break;}
+ *lsp++ = yystate = yyt->advance+yysvec;
+ goto contin;
+ }
+ yyt = yyr + YYU(yymatch[yych]);
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"try fall back character ");
+ allprint(YYU(yymatch[yych]));
+ putchar('\n');
+ }
+# endif
+ if(yyt <= yytop && yyt->verify+yysvec == yystate){
+ if(yyt->advance+yysvec == YYLERR) /* error transition */
+ {unput(*--yylastch);break;}
+ *lsp++ = yystate = yyt->advance+yysvec;
+ goto contin;
+ }
+ }
+ if ((yystate = yystate->yyother) && (yyt= yystate->yystoff) != yycrank){
+# ifdef LEXDEBUG
+ if(debug)fprintf(yyout,"fall back to state %d\n",yystate-yysvec-1);
+# endif
+ goto tryagain;
+ }
+# endif
+ else
+ {unput(*--yylastch);break;}
+ contin:
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"state %d char ",yystate-yysvec-1);
+ allprint(yych);
+ putchar('\n');
+ }
+# endif
+ ;
+ }
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"stopped at %d with ",*(lsp-1)-yysvec-1);
+ allprint(yych);
+ putchar('\n');
+ }
+# endif
+ while (lsp-- > yylstate){
+ *yylastch-- = 0;
+ if (*lsp != 0 && (yyfnd= (*lsp)->yystops) && *yyfnd > 0){
+ yyolsp = lsp;
+ if(yyextra[*yyfnd]){ /* must backup */
+ while(yyback((*lsp)->yystops,-*yyfnd) != 1 && lsp > yylstate){
+ lsp--;
+ unput(*yylastch--);
+ }
+ }
+ yyprevious = YYU(*yylastch);
+ yylsp = lsp;
+ yyleng = yylastch-yytext+1;
+ yytext[yyleng] = 0;
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"\nmatch ");
+ sprint(yytext);
+ fprintf(yyout," action %d\n",*yyfnd);
+ }
+# endif
+ return(*yyfnd++);
+ }
+ unput(*yylastch);
+ }
+ if (yytext[0] == 0 /* && feof(yyin) */)
+ {
+ yysptr=yysbuf;
+ return(0);
+ }
+ yyprevious = yytext[0] = input();
+ if (yyprevious>0)
+ output(yyprevious);
+ yylastch=yytext;
+# ifdef LEXDEBUG
+ if(debug)putchar('\n');
+# endif
+ }
+ }
+yyback( int *p, int m)
+{
+if (p==0) return(0);
+while (*p)
+ {
+ if (*p++ == m)
+ return(1);
+ }
+return(0);
+}
+ /* the following are only used in the lex library */
+yyinput(){
+ return input();
+ }
+void yyoutput(c)
+ int c; {
+ output(c);
+ }
+void yyunput(c)
+ int c; {
+ unput(c);
+ }
diff --git a/private/os2/client/thunk/thunkcom/rcpp.err b/private/os2/client/thunk/thunkcom/rcpp.err
new file mode 100644
index 000000000..d26c8494d
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/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/os2/client/thunk/thunkcom/sample.thk b/private/os2/client/thunk/thunkcom/sample.thk
new file mode 100644
index 000000000..629a3be60
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/sample.thk
@@ -0,0 +1,175 @@
+errbadparam = 0;
+enablemapdirect1632 = true;
+
+typedef unsigned short USHORT;
+typedef unsigned long ULONG;
+typedef unsigned int UINT;
+typedef unsigned char UCHAR;
+
+typedef UCHAR BYTE;
+typedef USHORT WORD;
+typedef ULONG DWORD;
+typedef UINT HANDLE;
+typedef WORD HANDLE16;
+typedef DWORD HANDLE32;
+typedef int BOOL;
+typedef int INT;
+typedef char *LPSTR;
+typedef USHORT SEL;
+
+typedef HANDLE HWND;
+typedef HANDLE HDC;
+typedef HANDLE HBRUSH;
+typedef HANDLE HBITMAP;
+typedef HANDLE HRGN;
+typedef HANDLE HFONT;
+typedef HANDLE HCURSOR;
+typedef HANDLE HMENU;
+typedef HANDLE HICON;
+
+typedef WORD ATOM;
+typedef DWORD FARPROC; /* don't mess with it */
+
+
+typedef struct tagWNDCLASS {
+ WORD style;
+ WORD style2;
+ WORD style3;
+ FARPROC lpfnWndProc;
+ int cbClsExtra;
+ int cbWndExtra;
+ HANDLE hInstance;
+ HICON hIcon;
+ HCURSOR hCursor;
+ HBRUSH hbrBackground;
+ LPSTR lpszMenuName passifhinull;
+ LPSTR lpszClassName;
+} WNDCLASS;
+
+typedef struct tagRECT {
+ INT left;
+ INT top;
+ INT right;
+ INT bottom;
+} RECT;
+
+typedef struct tagPOINT {
+ INT x;
+ INT y;
+} POINT;
+
+typedef struct tagPAINTSTRUCT {
+ HDC hdc;
+ BOOL fErase;
+ RECT rcPaint;
+ BOOL fRestore;
+ BOOL fIncUpdate;
+ BYTE rgbReserved[16];
+} PAINTSTRUCT;
+
+
+
+BOOL InitApp16( HANDLE) =
+BOOL InitApp( HANDLE)
+{}
+
+void PostQuitMessage16( INT) =
+void PostQuitMessage( INT)
+{}
+
+void UpdateWindow16( HWND) =
+void UpdateWindow( HWND)
+{}
+
+BOOL ShowWindow16( HWND, INT) =
+BOOL ShowWindow( HWND, INT)
+{}
+
+HCURSOR LoadCursor16( HANDLE hInstance, LPSTR lpCursorName) =
+HCURSOR LoadCursor( HANDLE hInstance, LPSTR lpCursorName)
+{
+ lpCursorName = passifhinull;
+}
+
+HICON LoadIcon16( HANDLE hInstance, LPSTR lpIconName) =
+HICON LoadIcon( HANDLE hInstance, LPSTR lpIconName)
+{
+ lpIconName = passifhinull;
+}
+
+HWND CreateWindow16( DWORD dwExStyle deleted 0x80000000,
+ LPSTR lpClassName, LPSTR lpWindowName, DWORD dwStyle,
+ UINT X, UINT Y, UINT nWidth, UINT nHeight, HWND hWndParent,
+ HMENU hMenu, HANDLE hInstance, DWORD lpParam) =
+HWND CreateWindowEx( DWORD dwExStyle,
+ LPSTR lpClassName, LPSTR lpWindowName, DWORD dwStyle,
+ UINT X, UINT Y, UINT nWidth, UINT nHeight, HWND hWndParent,
+ HMENU hMenu, HANDLE hInstance, DWORD lpParam)
+{}
+
+INT DialogBox16( HANDLE hInstance, LPSTR lpTemplateName, HWND hWndParent,
+ FARPROC lpDialogFunc) =
+INT DialogBox( HANDLE hInstance, LPSTR lpTemplateName, HWND hWndParent,
+ FARPROC lpDialogFunc)
+{
+ lpTemplateName = passifhinull;
+}
+
+void EndDialog16( HWND hDlg, INT nResult) =
+void EndDialog( HWND hDlg, INT nResult)
+{}
+
+HDC BeginPaint16( HWND hWnd, PAINTSTRUCT *lpPaint) =
+HDC BeginPaint( HWND hWnd, PAINTSTRUCT *lpPaint)
+{
+ lpPaint = output;
+}
+
+BOOL RegisterClass16( WNDCLASS *lpWndClass) =
+BOOL RegisterClass( WNDCLASS *lpWndClass)
+{}
+
+DWORD GetCurrentPosition16( HDC hDC, POINT *lpPoint deleted) =
+DWORD GetCurrentPosition( HDC hDC, POINT *lpPoint)
+{
+ lpPoint = maptoretval;
+}
+
+BOOL PtInRect16( RECT *lpRect, POINT Point) =
+BOOL PtInRect( RECT *lpRect, POINT Point)
+{}
+
+DWORD GetAspectRatioFilter16( HDC hDC, POINT *lpAspectRatio deleted) =
+DWORD GetAspectRatioFilter( HDC hDC, POINT *lpAspectRatio)
+{
+ lpAspectRatio = maptoretval reverserc;
+}
+
+void SetSysColors16( INT nChanges, INT *lpSysColor, DWORD *lpColorValues) =
+void SetSysColors( INT nChanges, INT *lpSysColor, DWORD *lpColorValues)
+{
+ nChanges = sizeof lpSysColor;
+ lpSysColor = special;
+}
+
+
+/*
+
+InitApp16 => InitApp;
+PostQuitMessage16 => PostQuitMessage;
+UpdateWindow16 => UpdateWindow;
+ShowWindow16 => ShowWindow;
+LoadCursor16 => LoadCursor;
+LoadIcon16 => LoadIcon;
+CreateWindow16 => CreateWindowEx;
+RegisterClass16 => RegisterClass;
+DialogBox16 => DialogBox;
+EndDialog16 => EndDialog;
+BeginPaint16 => BeginPaint;
+GetCurrentPosition16 => GetCurrentPosition;
+PtInRect16 => PtInRect;
+GetAspectRatioFilter16 => GetAspectRatioFilter;
+
+SetSysColors16 => SetSysColors;
+
+ */
diff --git a/private/os2/client/thunk/thunkcom/symtab.c b/private/os2/client/thunk/thunkcom/symtab.c
new file mode 100644
index 000000000..b74e19bf1
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/symtab.c
@@ -0,0 +1,443 @@
+#define SCCSID "@(#)symtab.c 13.13 90/08/28"
+
+/*
+ * Thunk Compiler - Symbol Table Routines.
+ *
+ * This is an OS/2 2.x specific file
+ * Microsoft Confidential
+ *
+ * Copyright (c) Microsoft Corporation 1987, 1988, 1989
+ *
+ * All Rights Reserved
+ *
+ * Written 10/15/88 by Kevin Ross
+ */
+
+
+#include <stdio.h>
+#include "thunk.h"
+#include "types.h"
+#include "symtab.h"
+
+
+extern FILE *StdDbg;
+
+
+/*
+ * BaseTable is used to access the base data types quickly.
+ */
+TypeNode *BaseTable[SYMTAB_LASTBASEUSED];
+
+TypeNode *SymTable= NULL;
+TypeNode *TypeTable = NULL;
+FunctionNode *FunctionTable = NULL;
+MapNode *MapTable = NULL;
+
+char *SemanticTable[5];
+
+
+/*** sym_SymTabInit() - Module initialization Routine
+ *
+ * This routine is called before any other symbol table routines
+ * are used.
+ *
+ * It will setup the table of base types, and initialize any other
+ * needed variables.
+ *
+ * Entry: none
+ *
+ * Exit: tables and variables are initialized.
+ */
+
+void sym_SymTabInit()
+
+{
+ BaseTable[SYMTAB_SHORT] = typ_MakeTypeNode(TYPE_SHORT);
+ BaseTable[SYMTAB_SHORT]->iBaseType = TYPE_SHORT;
+ BaseTable[SYMTAB_SHORT]->iBaseDataSize = 2;
+ BaseTable[SYMTAB_SHORT]->pchBaseTypeName = "short";
+
+ BaseTable[SYMTAB_LONG] = typ_MakeTypeNode(TYPE_LONG);
+ BaseTable[SYMTAB_LONG]->iBaseType = TYPE_LONG;
+ BaseTable[SYMTAB_LONG]->iBaseDataSize = 4;
+ BaseTable[SYMTAB_LONG]->pchBaseTypeName = "long";
+
+ BaseTable[SYMTAB_USHORT] = typ_MakeTypeNode(TYPE_USHORT);
+ BaseTable[SYMTAB_USHORT]->iBaseType = TYPE_USHORT;
+ BaseTable[SYMTAB_USHORT]->iBaseDataSize = 2;
+ BaseTable[SYMTAB_USHORT]->pchBaseTypeName = "unsigned short";
+
+ BaseTable[SYMTAB_ULONG] = typ_MakeTypeNode(TYPE_ULONG);
+ BaseTable[SYMTAB_ULONG]->iBaseType = TYPE_ULONG;
+ BaseTable[SYMTAB_ULONG]->iBaseDataSize = 4;
+ BaseTable[SYMTAB_ULONG]->pchBaseTypeName = "unsigned long";
+
+ BaseTable[SYMTAB_INT] = typ_MakeTypeNode(TYPE_INT);
+ BaseTable[SYMTAB_INT]->iBaseType = TYPE_INT;
+ BaseTable[SYMTAB_INT]->iBaseDataSize = -99;
+ BaseTable[SYMTAB_INT]->pchBaseTypeName = "int";
+
+ BaseTable[SYMTAB_UINT] = typ_MakeTypeNode(TYPE_UINT);
+ BaseTable[SYMTAB_UINT]->iBaseType = TYPE_UINT;
+ BaseTable[SYMTAB_UINT]->iBaseDataSize = -99;
+ BaseTable[SYMTAB_UINT]->pchBaseTypeName = "unsigned int";
+
+ BaseTable[SYMTAB_VOID] = typ_MakeTypeNode(TYPE_VOID);
+ BaseTable[SYMTAB_VOID]->iBaseType = TYPE_VOID;
+ BaseTable[SYMTAB_VOID]->iBaseDataSize = 1;
+ BaseTable[SYMTAB_VOID]->pchBaseTypeName = "void";
+
+ BaseTable[SYMTAB_UCHAR] = typ_MakeTypeNode(TYPE_UCHAR);
+ BaseTable[SYMTAB_UCHAR]->iBaseType = TYPE_UCHAR;
+ BaseTable[SYMTAB_UCHAR]->iBaseDataSize = 1;
+ BaseTable[SYMTAB_UCHAR]->pchBaseTypeName = "unsigned char";
+
+ BaseTable[SYMTAB_CHAR] = typ_MakeTypeNode(TYPE_CHAR);
+ BaseTable[SYMTAB_CHAR]->iBaseType = TYPE_CHAR;
+ BaseTable[SYMTAB_CHAR]->iBaseDataSize = 1;
+ BaseTable[SYMTAB_CHAR]->pchBaseTypeName = "char";
+
+ BaseTable[SYMTAB_STRING] = typ_MakeTypeNode(TYPE_STRING);
+ BaseTable[SYMTAB_STRING]->iBaseDataSize = 1;
+ BaseTable[SYMTAB_STRING]->pchBaseTypeName = "string";
+
+ BaseTable[SYMTAB_NULLTYPE] = typ_MakeTypeNode(TYPE_NULLTYPE);
+ BaseTable[SYMTAB_NULLTYPE]->iBaseType = TYPE_NULLTYPE;
+ BaseTable[SYMTAB_NULLTYPE]->iBaseDataSize = 4;
+ BaseTable[SYMTAB_NULLTYPE]->pchBaseTypeName = "nulltype";
+
+ SemanticTable[0] = "";
+ SemanticTable[1] = "Input";
+ SemanticTable[2] = "Output";
+ SemanticTable[3] = "InOut";
+ SemanticTable[4] = "SizeOf";
+}
+
+
+/*** sym_FindSymbolTypeNode(pTab,pchSym)
+ *
+ * This function will look down the list of symbols - pTab - and
+ * return a pointer to the TypeNode that it finds.
+ *
+ * This is implemented as a linear list to get the compiler up and
+ * running. It should be revised to a faster algorithm.
+ *
+ * Entry: pTab - pointer to list of symbols.
+ * pchSym - pointer to symbol to find.
+ *
+ * Exit: returns a pointer to the typenode.
+ */
+
+TypeNode *sym_FindSymbolTypeNode(TypeNode *pTab,
+ char *pchSym)
+
+{
+ while (pTab && pchSym) {
+ if (pTab->pchIdent) {
+ if (!strcmp(pTab->pchIdent,pchSym))
+ return pTab;
+ }
+ pTab = pTab->pNextNode;
+ }
+ return (NULL);
+}
+
+
+/*** sym_FindSymbolTypeNodePair(pTab1,pTab2,ppT1,ppT2,pchSym)
+ *
+ * This routine will look down the list of symbols - pTab1 - and
+ * return in ppT1 the pointer to the TypeNode it finds that matches
+ * the pchIdent with pchSym. It will also concurrently walk a second
+ * list of symbols, pTab2, and returns ppT2.
+ *
+ * The net result is that FindSymbolTypeNodePair returns the pair of
+ * typenodes that represent the same parameter ordinal in two lists.
+ *
+ * This is implemented as a linear list to get the compiler up and
+ * running. It should be revised to a faster algorithm.
+ */
+
+int sym_FindSymbolTypeNodePair(TypeNode *pTab1,
+ TypeNode *pTab2,
+ TypeNode **ppT1,
+ TypeNode **ppT2,
+ char *pchSym)
+
+{
+ *ppT1 = pTab1;
+ *ppT2 = pTab2;
+
+ while (*ppT1 && *ppT2 && pchSym) {
+ if ((*ppT1)->pchIdent)
+ if (!strcmp((*ppT1)->pchIdent,pchSym))
+ return 1;
+ *ppT1 = (*ppT1)->pNextNode;
+ *ppT2 = (*ppT2)->pNextNode;
+ }
+ return (0);
+}
+
+
+/*** sym_FindSymbolFunctionNode(pTab,pchSym)
+ *
+ * FindSymbolFunctionNode will look down the list of symbols - pTab -
+ * and return a pointer to the FunctionNode that it finds.
+ *
+ * This is implemented as a linear list to get the compiler up and
+ * running. It should be revised to a faster algorithm.
+ */
+
+FunctionNode *sym_FindSymbolFunctionNode(FunctionNode *pTab,
+ char *pchSym)
+
+{
+ while (pTab && pchSym) {
+ if (!strcmp(pTab->pchFunctionName,pchSym))
+ return (pTab);
+ pTab = pTab->pNextFunctionNode;
+ }
+ return (NULL);
+}
+
+
+/*** sym_InsertTypeNode(ppTab,pNode)
+ *
+ * InsertTypeNode will add pNode to the symbol table ppTab.
+ *
+ * This is implemented as a linear list to get the compiler up and
+ * running. This routine will always add the new symbol to the front
+ * of the current list. It should be revised to a algorithm better
+ * for searching.
+ */
+
+void sym_InsertTypeNode(TypeNode **ppTab,
+ TypeNode *pNode)
+
+{
+ if (*ppTab) {
+ pNode->pNextNode = *ppTab;
+ }
+ *ppTab = pNode;
+}
+
+
+/*** sym_InsertFunctionNode(ppTab,pFNode)
+ *
+ * InsertFunctionNode will add pFNode to the symbol table ppTab.
+ *
+ * This is implemented as a linear list to get the compiler up and
+ * running. This routine will always add the new symbol to the front
+ * of the current list. It should be revised to a algorithm better
+ * for searching.
+ */
+
+void sym_InsertFunctionNode(FunctionNode **ppTab,
+ FunctionNode *pFNode)
+
+{
+ if (*ppTab) {
+ pFNode->pNextFunctionNode = *ppTab;
+ }
+ *ppTab = pFNode;
+}
+
+
+/*** sym_ReverseTypeList(pOld)
+ *
+ * ReverseTypeList will reverse the order of a TypeNode linked list.
+ * This is needed in several places in the compiler.
+ */
+
+TypeNode *sym_ReverseTypeList(TypeNode *pOld)
+
+{
+ register TypeNode *pNew, *pNext;
+
+
+ if (! pOld)
+ return pOld;
+
+ pNew = pOld->pNextNode;
+ pOld->pNextNode = NULL;
+
+ while (pNew) {
+ pNext = pNew->pNextNode;
+ pNew->pNextNode = pOld;
+ pOld = pNew;
+ pNew = pNext;
+ }
+ return (pOld);
+}
+
+
+/*** sym_FindFMapping(pMapTab,pSymA,pSymB)
+ *
+ * FindFMapping will search the list pMapTab in search for either pSymA
+ * or pSymB in the pFromName field of the mapping list.
+ */
+
+MapNode *sym_FindFMapping(MapNode *pMapTab,
+ char *pSymA,
+ char *pSymB)
+
+{
+ while (pMapTab) {
+ if (!strcmp(pMapTab->pFromName,pSymA) ||
+ !strcmp(pMapTab->pFromName,pSymB)) {
+ return (pMapTab);
+ }
+ pMapTab = pMapTab->pNextMapping;
+ }
+ return (NULL);
+}
+
+
+/*** sym_AddFMapping(ppMapTab,pFuncA,pFuncB)
+ *
+ * AddFMapping accepts two FunctionNode pointers, and a table.
+ * It will create a MapNode containing link information to the two
+ * functions. The mapping id is contained in pFromName.
+ */
+
+MapNode *sym_AddFMapping(MapNode **ppMapTab,
+ FunctionNode *pFuncA,
+ FunctionNode *pFuncB)
+
+{
+ MapNode *temp,*ptr;
+
+
+ if (temp = (MapNode *) malloc(sizeof(MapNode))) {
+ temp->pFromName = pFuncA->pchFunctionName;
+ temp->pFromNode = pFuncA;
+ temp->pToNode = pFuncB;
+ temp->pNextMapping = NULL;
+ temp->pFamily = NULL;
+
+ ptr = *ppMapTab;
+ if (!ptr)
+ *ppMapTab = temp;
+ else {
+ while (ptr->pNextMapping)
+ ptr = ptr->pNextMapping;
+ ptr->pNextMapping = temp;
+ }
+ return (*ppMapTab);
+ }
+ else
+ fatal("sym_AddFMapping malloc failure");
+}
+
+
+
+/***********************************************************************/
+/* Dump Routines: Used for debugging output only. */
+/***********************************************************************/
+
+static char IndentString[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+
+static int ILevel = 18;
+
+
+void sym_DumpFNode(FunctionNode *F)
+
+{
+ fprintf(StdDbg,"\nFunction Node: %s\n",F->pchFunctionName);
+ fprintf(StdDbg,"Call Type: %s\n",
+ (F->iCallType == TYPE_API16) ? "API16":"API32");
+ fprintf(StdDbg,"System Call Convention: %s\n",F->fSysCall?"TRUE":"FALSE");
+ fprintf(StdDbg,"Ring Type: %s\n",
+ (F->fConforming) ? "Conforming":"Normal");
+ fprintf(StdDbg,"Return Type: ");
+
+ sym_DumpTNode(F->ReturnType);
+
+ fprintf(StdDbg,"ErrBadParam = %lu\n",F->ulErrBadParam);
+ fprintf(StdDbg,"ErrNoMem = %lu\n",F->ulErrNoMem);
+ fprintf(StdDbg,"MinStack = %d\tInlineCode = %s\n",F->iMinStack,
+ (F->fInlineCode) ? "TRUE" : "FALSE");
+
+ fprintf(StdDbg,"Maps to function: %s\n",F->pMapsToFunction->pchFunctionName);
+
+ fprintf(StdDbg,"Parameter Types:\n");
+
+ ILevel--;
+ sym_DumpTNodeList(F->ParamList);
+ ILevel++;
+ fprintf(StdDbg,"\n");
+}
+
+
+void sym_DumpFNodeList(FunctionNode *F)
+
+{
+ for( ; F; F = F->pNextFunctionNode)
+ sym_DumpFNode( F);
+}
+
+
+void sym_DumpTNode(TypeNode *T)
+
+{
+ fprintf(StdDbg,"%s",&IndentString[ILevel]);
+
+ fprintf(StdDbg,"%s",(T->iPointerType) ?
+ ((T->iPointerType == TYPE_FAR16) ? "FAR16 ":
+ ((T->iPointerType == TYPE_NEAR32) ? "NEAR32 ":"PTR ")):"");
+ fprintf(StdDbg,"%s",T->pchBaseTypeName);
+ if (T->pchIdent)
+ fprintf(StdDbg,"\t%s", T->pchIdent);
+ if (T->iArraySize > 1)
+ fprintf(StdDbg,"[%u]",T->iArraySize);
+ fprintf(StdDbg," #SO %u BS %u #",T->iStructOffset,T->iBaseDataSize);
+ if (T->iDeleted)
+ fprintf(StdDbg," DELETED fv=%lu ",T->iFillValue);
+ if (T->iBaseType == TYPE_STRUCT) {
+ fprintf(StdDbg," Aligned %d",T->iAlignment);
+ fprintf(StdDbg,"\n%s",&IndentString[ILevel--]);
+ fprintf(StdDbg,"{\n");
+ sym_DumpTNodeList(T->pStructElems);
+ fprintf(StdDbg,"%s",&IndentString[++ILevel]);
+ fprintf(StdDbg,"}");
+ }
+
+ sym_DumpSemantics(T);
+ fprintf(StdDbg,"\n");
+}
+
+
+void sym_DumpTNodeList(TypeNode *T)
+
+{
+ for( ; T; T = T->pNextNode)
+ sym_DumpTNode(T);
+}
+
+
+void sym_DumpSemantics(TypeNode *T)
+
+{
+ fprintf(StdDbg,";");
+ if (SemanticTable[T->fSemantics & 3]) {
+ fprintf(StdDbg,"\t%s",SemanticTable[T->fSemantics & 3]);
+ }
+
+ if (T->fSemantics & SEMANTIC_SIZE)
+ fprintf(StdDbg,"\tSizeOf %s", T->pParamSizeOf->pchIdent);
+
+ if (T->fSemantics & SEMANTIC_COUNT)
+ fprintf(StdDbg,"\tCountOf %s", T->pParamSizeOf->pchIdent);
+}
+
+
+void sym_DumpFMappingList(MapNode *M)
+
+{
+ fprintf(StdDbg,"\nFunction Map Table\n\n");
+ while (M) {
+ fprintf(StdDbg,"\nMapping Id: %s\t",M->pFromName);
+ fprintf(StdDbg,"Maps %s => %s\n",M->pFromNode->pchFunctionName,
+ M->pToNode->pchFunctionName);
+ M = M->pNextMapping;
+ }
+}
diff --git a/private/os2/client/thunk/thunkcom/symtab.h b/private/os2/client/thunk/thunkcom/symtab.h
new file mode 100644
index 000000000..27b07fcd8
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/symtab.h
@@ -0,0 +1,50 @@
+/* SCCSID = @(#)symtab.h 13.8 90/08/28 */
+
+/*
+ * Thunk Compiler Symbol Table Header File
+ *
+ * Written 10/15/88 by Kevin Ross
+ * Copyright (c) 1988 Microsoft Corp. All rights reserved.
+ */
+
+
+
+/*
+ * Definitions.
+ */
+#define SYMTAB_SHORT 0
+#define SYMTAB_LONG 1
+#define SYMTAB_USHORT 2
+#define SYMTAB_ULONG 3
+#define SYMTAB_VOID 4
+#define SYMTAB_UCHAR 5
+#define SYMTAB_CHAR 6
+#define SYMTAB_STRING 7
+#define SYMTAB_NULLTYPE 8
+#define SYMTAB_INT 9
+#define SYMTAB_UINT 10
+#define SYMTAB_LASTBASEUSED 11
+
+
+/*
+ * Extern Declarations.
+ */
+extern TypeNode *BaseTable[]; /* Table of base data types */
+extern TypeNode *SymTable;
+extern TypeNode *TypeTable; /* Table of declared types */
+extern char *SemanticTable[]; /* Table of semantic operators */
+extern FunctionNode *FunctionTable; /* Table of declared functions */
+
+extern MapNode *MapTable; /* Table of mapping directives */
+
+extern void sym_InsertTypeNode();
+extern TypeNode * sym_FindSymbolTypeNode();
+extern TypeNode * sym_ReverseTypeList();
+
+extern int sym_FindSymbolTypeNodePair();
+
+extern void sym_InsertFunctionNode();
+extern FunctionNode *sym_FindSymbolFunctionNode();
+
+extern MapNode *sym_AddFMapping();
+extern MapNode *sym_FindFMapping();
diff --git a/private/os2/client/thunk/thunkcom/thunk.c b/private/os2/client/thunk/thunkcom/thunk.c
new file mode 100644
index 000000000..dd1ca13c6
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/thunk.c
@@ -0,0 +1,490 @@
+/*
+ * Thunk Compiler - Main Program Module.
+ *
+ * This is a Windows-specific file
+ * Microsoft Confidential
+ *
+ * Copyright (c) Microsoft Corporation 1987-1991
+ *
+ * All Rights Reserved
+ *
+ * Written 10/15/88 by Kevin Ross for OS/2 2.x
+ * Converted to Windows by Kevin Ruddell 10/90
+ * 10jan91 KevinR call SelToFlat to convert ptr return code if 32=>16
+ *
+ */
+
+
+/*
+ * The 'thunk' compiler is structured as follows:
+ *
+ * thunk.c
+ * / \
+ * Parser Code Generator
+ *
+ * The Parser builds up a data structure, which is in turn passed to the
+ * Code Generator. This data structure is the only communication between
+ * the two modules.
+ *
+ * The data structure that is passed is a linked list of Mapping Nodes,
+ * which contain information two function prototypes to be mapped.
+ *
+ * Mapping Node ---------------> Mapping Node ---->
+ * / \
+ * / \
+ * / \
+ * FunctionNode ----> FunctionNode
+ * | <-----|
+ *
+ *
+ * Each FunctionNode contains all the information needed to generate a
+ * thunk from/to the function.
+ *
+ * FunctionNode
+ * pchFunctionName -> ASCIIZ Name of function
+ * pReturnType -> TypeNode Type of return value
+ * iCallType Call Type (API16 or API32)
+ * pParmList -> TypeNode List of parameter types
+ * |
+ * TypeNode
+ * ...
+ *
+ * Note: Not shown in FunctionNode are several flag variables. See the
+ * definition of FunctionNode in types.h
+ *
+ * Each passed parameter and return type in a FunctionNode is made up
+ * using the data structure TypeNode. Key fields in a TypeNode are
+ *
+ * TypeNode
+ * iBaseType Defines type (long, short, string, etc)
+ * iOffset Stack position relative to eBP
+ * pStructElems -> TypeNode If iBaseType == STRUCT, list of elements
+ * pNextNode -> TypeNode Rest of parameters
+ *
+ * See types.h for more detailed explanation of TypeNode.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+#include "thunk.h"
+
+#include "error.h"
+#include "types.h"
+#include "symtab.h"
+#include "globals.h"
+
+#ifdef XENIX
+#define TimeStamp 0L /* __TIME__ */
+#define DateStamp 0L /* __DATE__ */
+#else
+#define TimeStamp __TIME__
+#define DateStamp __DATE__
+#endif
+
+char *Version = "2.06";
+
+FILE *StdDbg = stderr;
+
+unsigned int gen_LabelCount = 0;
+
+
+char *CODE32_NAME="CODE32";
+char *CODE16_NAME="CODE16";
+char *CODE32_CLASS="CODE";
+char *CODE16_CLASS="CODE";
+char *DATA32_NAME="DATA32";
+char *DATA32_CLASS="DATA";
+char *DATA16_NAME="DATA16";
+char *DATA16_CLASS="DATA";
+
+unsigned int iGlobalStackSize = DEFAULT_STACKSIZE;
+int fGlobalSysCall = FALSE,fGlobalCombine=TRUE;
+int fGlobalInline = FALSE,fUnderScore32 = FALSE,fUpperCase16=TRUE;
+int fUpperCase32 = TRUE,fGlobalTruncation = SEMANTIC_TRUNC;
+int fForceData = FALSE;
+
+int iPackingSize = 4; /** Default DWORD alignment for 32 bit API**/
+long gErrNoMem = ERRNOMEM,gErrBadParam=ERRBADPARAM,gErrUnknown=0;
+
+unsigned int gfErrUnknown = 0;
+
+#ifdef YYDEBUG
+int yydebug = 0;
+#endif
+
+boolean_t BeQuiet = FALSE;
+boolean_t BeVerbose = FALSE;
+
+boolean_t DumpTables = FALSE;
+boolean_t DumpFile = FALSE;
+
+boolean_t SyntaxCheckOnly = FALSE;
+
+int fOverWriteFile = 0;
+
+int fBPEntry = 0,fBPFrame = 0,fBPCall = 0,fBPExit = 0;
+
+char *yyinname;
+
+//extern int yyparse(void);
+//int yyparse(void);
+
+
+/*** parseArgs(argcPtr, argvPtr)
+ *
+ * This routine will parse whatever is on the command line, looking for
+ * flag values. Each flag value will start with a '-'. On return,
+ * argc and argv will point to the first command line value that didn't
+ * start with a '-'.
+ *
+ * Entry: argcPtr and argvPtr are command line arguments.
+ *
+ * Exit: argc and argv point to command line argument.
+ */
+
+static void
+parseArgs(int *argcPtr,
+ char ***argvPtr)
+
+{
+ register int argc = *argcPtr;
+ register char **argv = *argvPtr;
+ char tempc;
+ int i;
+
+
+ while (--argc) {
+ if (((++argv)[0][0] == '-') || (argv[0][0] == '/')) {
+ i = 0;
+ while (argv[0][++i]) {
+ switch (argv[0][i])
+ {
+ case 'B':
+ fBPEntry = fBPFrame = fBPCall = fBPExit = TRUE;
+ break;
+ case 'c':
+ fBPCall = TRUE;
+ break;
+ case 'C':
+ fBPFrame = fBPCall = TRUE;
+ break;
+ case 'd':
+ DumpTables = TRUE;
+ break;
+ case 'D':
+ DumpTables = TRUE;
+ DumpFile = TRUE;
+ break;
+ case 'e':
+ fBPEntry = TRUE;
+ break;
+ case 'E':
+ fBPEntry = fBPExit = TRUE;
+ break;
+ case 'f':
+ fBPFrame = TRUE;
+ break;
+ case 'h':
+ Usage();
+ fatal("");
+ case 'F':
+ fForceData = TRUE;
+ break;
+ case 'L':
+ argv++;
+ gen_LabelCount = atoi(*argv);
+ argv[0][i+1] = '\0';
+ break;
+ case 'O':
+ fGlobalCombine = FALSE;
+ break;
+ case 'N':
+ tempc = argv[0][i+1];
+ argv++;
+ switch (tempc) {
+ case 'A':
+ CODE32_NAME=*argv;
+ break;
+ case 'B':
+ CODE32_CLASS=*argv;
+ break;
+ case 'C':
+ CODE16_NAME=*argv;
+ break;
+ case 'D':
+ CODE16_CLASS=*argv;
+ break;
+ case 'E':
+ DATA32_NAME=*argv;
+ break;
+ case 'F':
+ DATA32_CLASS=*argv;
+ break;
+ default:
+ Usage();
+ fatal("Bad name modifier\n");
+ break;
+ }
+ i = strlen(*argv) - 1;
+ break;
+ case 'p':
+ iPackingSize = 2;
+ break;
+ case 'q':
+ BeQuiet = TRUE;
+ break;
+ case 'Q':
+ BeQuiet = FALSE;
+ break;
+ case 's':
+ SyntaxCheckOnly = TRUE;
+ fprintf(stderr,"** Syntax check only. No code generated \n\n");
+ break;
+ case 'U':
+ fUpperCase16 = FALSE;
+ break;
+ case 'u':
+ fUnderScore32 = TRUE;
+ break;
+ case 'v':
+ BeVerbose = TRUE;
+ break;
+ case 'y':
+ fOverWriteFile = TRUE;
+ break;
+#ifdef YYDEBUG
+ case 'Y':
+ yydebug = 1;
+ break;
+#endif
+ case 'x':
+ fBPExit = TRUE;
+ break;
+ case 'z':
+ fUpperCase32 = FALSE;
+ break;
+ default:
+ Usage();
+ fatal("unknown flag: '%s'", argv[0]);
+ /* NOT REACHED */
+ }
+ }
+ }
+ else {
+ *argcPtr = argc;
+ *argvPtr = argv;
+ return;
+ }
+ }
+}
+
+
+/*** Usage()
+ *
+ * Prints a help message if something on the command line is not
+ * understood.
+ *
+ * Entry: none
+ *
+ * Exit: message is printed to stderr.
+ */
+
+void Usage( void)
+
+{
+ fprintf(stderr,"\nThunk compiler usage\n");
+ fprintf(stderr,"thunk [{-|/}options] [-L xxxxx]infile.ext [outfile.ext]\n");
+ fprintf(stderr,"\nwhere options include:\n");
+ fprintf(stderr,"\tB\tINT 3 on entry/frame/call/exit\n");
+ fprintf(stderr,"\tc\tINT 3 on call\n");
+ fprintf(stderr,"\tC\tINT 3 on frame/call\n");
+ fprintf(stderr,"\td\tDebugging Ouput\n");
+ fprintf(stderr,"\tD\tDebugging output to file 'thunk.dmp'\n");
+ fprintf(stderr,"\te\tINT 3 on entry\n");
+ fprintf(stderr,"\tE\tINT 3 on entry/exit\n");
+ fprintf(stderr,"\tf\tINT 3 on frame generation\n");
+ fprintf(stderr,"\tF\tForce 1 byte into DATA32 segment\n");
+ fprintf(stderr,"\tL xxxxx\tInitialize label counter to xxxxx\n");
+ fprintf(stderr,"\tO\tDisable routine compacting\n");
+ fprintf(stderr,"\tp\tSet packing for 32bit objects to 2\n");
+ fprintf(stderr,"\ts\tSyntax check only\n");
+ fprintf(stderr,"\tu\tPrefix _ to all 32bit names\n");
+ fprintf(stderr,"\tU\tDisable 16-bit name uppercasing\n");
+ fprintf(stderr,"\tx\tINT 3 on exit\n");
+ fprintf(stderr,"\ty\tAnswer 'y' to overwrite file question\n");
+ fprintf(stderr,"\tz\tDisable 32-bit name uppercasing\n");
+ fprintf(stderr,"\n\tNx <name>\tName segment or class where x is\n");
+ fprintf(stderr,"\t\tA\t32-bit code segment name\n");
+ fprintf(stderr,"\t\tB\t32-bit code class name\n");
+ fprintf(stderr,"\t\tC\t16-bit code segment name\n");
+ fprintf(stderr,"\t\tD\t16-bit code class name\n");
+ fprintf(stderr,"\t\tE\t32-bit data segment name\n");
+ fprintf(stderr,"\t\tF\t32-bit data class name\n");
+ fprintf(stderr,"\n\n");
+}
+
+
+/*** main(argc, argv)
+ *
+ * Start the ball a rollin'.
+ *
+ * Entry: argc and argv are the arguments.
+ *
+ * Exit: thunk compiler is done.
+ *
+ * PCode:
+ * Parse Command Line
+ * Open input file onto stdin
+ * Open output file onto stdout
+ * Call parser to build data structures
+ * If (Debugging output enabled) then dump tables
+ * If (no parsing errors) then Call code generator
+ */
+
+void
+main(int argc,
+ char *argv[])
+
+{
+ FILE *filePtr;
+ char *ptr;
+ char fileName[260];
+ char infileName[260];
+ char outfileName[260];
+ char CommandLine[260];
+ char c;
+ int i;
+ long lTime;
+
+
+ set_program_name(argv[0]);
+
+ fprintf(stderr,"Microsoft (R) Thunk Compiler Version %s",Version);
+ fprintf(stderr," %s %s\n",DateStamp,TimeStamp);
+ fprintf(stderr,"Copyright (c) Microsoft Corp 1988-1991. All rights reserved.\n\n");
+
+ sprintf(CommandLine,"%s ",argv[0]);
+
+ for (i=1; i < argc; i++) {
+ strcat(CommandLine,argv[i]);
+ strcat(CommandLine," ");
+ }
+
+ parseArgs(&argc, &argv);
+
+ if (argc < 1 ) {
+ Usage();
+ fatal("Missing filename\n");
+ }
+
+ (void) strcpy(infileName, *argv);
+ (void) strcpy(outfileName, *argv);
+
+ argv++;
+
+ if (*argv) {
+ /* must be an output file */
+ (void) strcpy(outfileName, *argv);
+ }
+ else {
+ /* create output file from input file */
+ ptr = (char *) strrchr(outfileName, '.');
+
+ if (ptr == NULL)
+ fatal("input filename %s requires extension (%s.def)\n",
+ infileName,infileName);
+
+ ptr[0] = '\0';
+ strcat(ptr,".asm");
+ }
+ if (!SyntaxCheckOnly) {
+ if (!fOverWriteFile) {
+ if (filePtr = fopen(outfileName,"r")) {
+ fprintf(stderr,"Enter a 'y' to overwrite existing %s :",
+ outfileName);
+ c = (char)getchar();
+ if (c!='y')
+ fatal("File not overwritten\n\n");
+ fclose( filePtr);
+ }
+ }
+ }
+ (void) fclose(stdin);
+
+ filePtr = fopen(infileName, "r");
+ if (filePtr == NULL) {
+ fatal("fopen(%s): Could not open input file ",fileName);
+ }
+ else if (filePtr != stdin) {
+ fatal("fopen(%s): not opened on stdin (fd = %d)!",
+ fileName, fileno(filePtr));
+ }
+
+ yyinname = infileName;
+ yylineno = 2;
+
+ LookNormal();
+ sym_SymTabInit();
+ //(void) yyparse();
+ yyparse();
+
+ if( !MapTable && fEnableMapDirect1632)
+ cod16_EnableMapDirect( TYPE_API16, TYPE_API32);
+
+ if (DumpTables) {
+ if (DumpFile) {
+ if (!(StdDbg=fopen("thunk.dmp","w")))
+ fprintf(stderr,"Panic closing stderr");
+ }
+ fprintf(stderr,"\nTable Dump Active\n");
+ fprintf(StdDbg,"Function Table:\n");
+ if (FunctionTable == NULL)
+ fprintf(StdDbg,"Function Table is Null");
+
+ sym_DumpFNodeList(FunctionTable);
+ fprintf(StdDbg,"\n\nType Table:\n");
+ sym_DumpTNodeList(TypeTable);
+ fprintf(StdDbg,"\n\nSymbol Table:\n");
+ sym_DumpTNodeList(SymTable);
+ sym_DumpFMappingList(MapTable);
+ }
+ if (errors > 0)
+ exit(1);
+
+ if (! SyntaxCheckOnly) {
+ (void) fclose(stdout);
+ filePtr = fopen(outfileName, "w");
+
+ if (filePtr == NULL) {
+ fatal("fopen(%s): could not open output file", outfileName);
+ }
+ else if (filePtr != stdout) {
+ fatal("fopen(%s): not opened on stdout (fd = %d)!",
+ outfileName, fileno(filePtr));
+ }
+
+ /*
+ * Output version and timestamp.
+ */
+ printf("\tpage\t,132\n\n");
+ printf(";Thunk Compiler Version %s",Version);
+ printf(" %s %s\n",DateStamp,TimeStamp);
+ time(&lTime);
+ printf(";File Compiled %s\n",ctime(&lTime));
+ printf(";Command Line: %s\n\n",CommandLine);
+ printf("\tTITLE\t$%s\n\n", outfileName);
+ printf("\t.386p\n");
+
+ if (BeVerbose)
+ fprintf(stderr, "\nWriting %s ... ", fileName);
+
+ cod_GenerateCode( MapTable);
+
+ if (BeVerbose)
+ fprintf(stderr, "done.\n");
+ }
+ exit(0);
+}
diff --git a/private/os2/client/thunk/thunkcom/thunk.def b/private/os2/client/thunk/thunkcom/thunk.def
new file mode 100644
index 000000000..65d38846b
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/thunk.def
@@ -0,0 +1,6 @@
+NAME thunk WINDOWCOMPAT
+DESCRIPTION 'Win32 thunk compiler'
+STACKSIZE 8096
+HEAPSIZE 4096
+PROTMODE
+EXETYPE OS2
diff --git a/private/os2/client/thunk/thunkcom/thunk.h b/private/os2/client/thunk/thunkcom/thunk.h
new file mode 100644
index 000000000..22365819a
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/thunk.h
@@ -0,0 +1,57 @@
+/* SCCSID = @(#)thunk.h 13.16 90/08/28 */
+
+/*
+ * Thunk Compiler Main Program Module Declarations
+ *
+ * Copyright (c) 1988 Microsoft Corp. All rights reserved.
+ */
+
+
+
+#include <malloc.h>
+#include <string.h>
+#include <stdarg.h>
+
+#ifndef _THUNK_
+#define _THUNK_
+
+#ifndef MAKFPROT
+#include "fprot.h" /* function prototypes */
+#endif
+
+extern unsigned int gen_LabelCount;
+
+extern char *CODE32_NAME;
+extern char *CODE16_NAME;
+extern char *CODE32_CLASS;
+extern char *CODE16_CLASS;
+extern char *DATA32_NAME;
+extern char *DATA16_NAME;
+extern char *DATA32_CLASS;
+extern char *DATA16_CLASS;
+
+
+extern int yylineno;
+extern char *yyinname;
+extern int BeQuiet;
+extern int BeVerbose;
+extern unsigned int iGlobalStackSize;
+extern int fGlobalCombine;
+extern int fGlobalSysCall,fGlobalTruncation;
+extern int fGlobalInline,fUnderScore32,fUpperCase16,fUpperCase32;
+extern int fBPEntry,fBPFrame,fBPCall,fBPExit;
+extern int fForceData;
+extern int iPackingSize;
+extern long gErrNoMem,gErrBadParam,gErrUnknown;
+extern unsigned int gfErrUnknown;
+
+
+#define ERRNOMEM 8
+#define ERRBADPARAM 87
+
+#define DEFAULT_STACKSIZE 1024
+#define MAXSTRLEN 0xEFFF
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#endif
diff --git a/private/os2/client/thunk/thunkcom/thunk.txt b/private/os2/client/thunk/thunkcom/thunk.txt
new file mode 100644
index 000000000..e77fed5a2
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/thunk.txt
@@ -0,0 +1,1828 @@
+
+
+ Thunk Compiler Manual 11-01-1989 13:37:42
+
+
+! 1. Special Notes
+
+! The following items have changed since the last release of this
+! document.
+
+! * It is now possible to delete individual structure elements.
+
+! See the type definition section for details.
+
+! * Allow Lists
+
+! A new feature has been added which allows the user to specify a
+! list of long values that can be truncated to short value without
+! causing an error. See semantic section for details.
+
+! * Restrict Lists
+
+! This new feature will allow you to restrict the values that may be
+! passed to an API. See semantic section for details.
+
+! * Setting error codes.
+
+! You can now set the error codes for certain conditions. See
+! compiler directive and semantic sections for details. section for
+! details.
+
+! * Value truncation
+
+! The thunks will determine when data is going to be truncated, and
+! return and error if this happens. See the programmers guide for
+! further details.
+
+! 2. Command Line Options
+
+! To invoke the thunk compiler, use the command:
+
+! thunk [{-|/}options] [-L xxxxx] <infile> [ <outfile> ]
+
+! where options include zero or more of the following flags:
+
+! B INT 3 on entry/frame/call/exit. Generates inline INT 3
+! instructions in all interesting places. Equivalent to -CE
+
+! c INT 3 on call
+
+! C INT 3 on frame/call
+
+! d Debugging Output. The -d flag tells the compiler to dump
+! the internal data tables. This is debugging output, and
+! is sent to standard error. It is not intended to be
+! useful for anything but debugging the compiler itself.
+
+! D Debugging output to file thunk.dmp. Same as d, except
+! output is written to the file thunk.dmp
+
+! e INT 3 on entry
+
+
+ Page 1
+
+! E INT 3 on entry/exit
+
+! f INT 3 on frame generation
+
+! F Force 1 byte of data into data segment
+
+! L nnnn Start label generation at nnnn. Internal labels in the
+! compiler are generated numerically, such as L101:, and
+! normally start at label L0:. Labels have the range
+! 0-65535. The label generating mechanism will wrap if
+! labels pass 65535.
+
+! O Disable the compaction of routines. The thunk compiler
+! will combine thunks that have identical semantics and
+! parameters into common code groups. This reduces the
+! amount of code by reusing common subroutines. Using the
+! -O flag will disable this compaction.
+
+! p The -p flag changes the compiler default for 32-bit
+! structure packing to WORD, instead of DWORD. The default
+! for the compiler is that all structures are packed so
+! that DWORD sized or larger data are aligned on DWORD
+! boundaries. The -p flag insures that DWORD objects are
+! aligned on WORD boundaries.
+
+! s Syntax check only. No output code is produced.
+
+! u Prefix a _ to all 32-bit names. This is useful when
+! creating a C callable thunk library without using a .def
+! file.
+
+! U Disable 16-bit name uppercasing. Default is that all
+! 16-bit names are folded to uppercase. This disables the
+! folding, and names assume the case used in the source
+! file.
+
+! x INT 3 on exit
+
+! y Answer 'y' to overwrite file question. Normally, the
+! thunk compiler will stop to ask permission to overwrite
+! .asm files. The y flag overrides this query.
+
+! z Disable 32-bit name uppercasing. Default is that all
+! 32-bit names are folded to uppercase. This disables the
+! folding, and names assume the case used in the source
+! file.
+
+! N<x> <name> The -N switch allows the user to specify names of
+! segments and classes, where <x> is one of
+
+! A 32-bit code segment name
+
+! B 32-bit code class name
+
+! C 16-bit code segment name
+
+! D 16-bit code class name
+
+! E 32-bit data segment name
+
+
+ Page 2
+
+! F 32-bit data class name
+
+! and <name> is the name to be used.
+
+! <infile> is the input description file.
+
+! <outfile> is the MASM output file. This filename is optional. If it is
+! not specified, then the input filename will be used, with the extention
+! .ASM.
+
+ 3. Introduction
+
+ The Thunk Compiler is a program that will generate an interface
+ layer between 32-bit and 16-bit modules under OS/2. It will accept
+ as input a description langauge, and will output assembler code
+ suitable for compilation under MASM 5.1.
+
+ The current implementation of the thunk compiler will only generate
+ thunks in the 32 to 16 bit direction.
+
+ * Input Language
+
+ The thunk compiler input langauge is modeled after the 'C'
+ programming langauge. The syntax is very similar. There are three
+ basic sections to a thunk description.
+
+ a. Delcarations
+
+ Declarations are used to declare complex types, using basic
+ data types, or previously declared data types. Declarations use
+ the 'typedef' syntax of the 'C' langauge.
+
+ b. Mappings
+
+ Mappings define a relationship between two APIs. Each mapping
+ defines all needed information about the relationship between
+ two APIs, including names, parameters, return types, and
+ semantic information about the parameters.
+
+ c. Map Directives
+
+ Map directives are usually the last section of the program. A
+ map directive causes a thunk to be generated for two APIs whose
+ relationship was declared using a Mapping.
+
+ The thunk input language is case sensitive. Therefore, the
+ identifiers foo, Foo, and FOO are considered unique.
+
+ * Output File
+
+ The output file generated by the thunk compiler is a text file
+ containing assembler source code. It can be compiled using MASM 5.1
+ or later.
+
+ * Restrictions
+
+ The thunk compiler does not handle the following constructs:
+
+ - Arrays of pointers or arrays of data objects that contain
+
+
+ Page 3
+
+ pointers.
+
+ - Arrays of arrays.
+
+ - Arrays of structures passed as parameters.
+
+ Thunks containing such constructs will need hand modification
+ before they will operate correctly.
+
+ 4. Declarations
+
+ Declarations are used to define new data types based on existing data
+ types. There are several predefined data types.
+
+ short A 16 bit signed integer.
+
+ long A 32 bit signed integer.
+
+ unsigned short A 16 bit unsigned integer.
+
+ unsigned long A 32 bit unsigned integer.
+
+ int Using the int type will tell the compiler to use
+ which ever type is the default for the API type.
+ Using an int in a 16 bit API will result in a 16
+ bit signed integer. Using an int in a 32 bit API
+ will result in a 32 bit signed integer.
+
+ unsigned int Using the unsigned int type will tell the compiler
+ to use which ever type is the default for the API
+ type. Using an unsigned int in a 16 bit API will
+ result in a 16 bit unsigned integer. Using an int
+ in a 32 bit API will result in a 32 bit unsigned
+ integer.
+
+ string A pointer to a null terminated string of
+ characters. Must be prefaced by a pointer type.
+
+ char A single byte of type character. Most often used
+ with a pointer to point to a data buffer.
+
+ void A pointer to a single byte with no semantic
+ information. Most often used to point to a data
+ buffer. Must be prefaced by a pointer type.
+
+ nulltype A nulltype is used as a place holder for thunks
+ that will require special hand coding. The net
+ result of using a nulltype is that whenever the
+ nulltype is referenced, the compiler will output a
+ line that will cause an error if the output file is
+ assembled (ie. .err NULLTYPE).
+
+ All basic types can be prefaced by a pointer type. There are three
+ pointer types:
+
+ far16 The far16 keyword denotes that the data item is a
+ selector:offset format pointer. These pointers are used in
+ 16-bit OS/2.
+
+
+
+ Page 4
+
+ near32 The near32 keyword denotes that the data item is a 32-bit
+ flat address. These pointers are used in the 32-bit OS/2.
+
+ '*' The 'star' pointer type denotes that the data item is a
+ pointer, and should assume the pointer type native to the API
+ in which it is used (ie a star pointer used in a API16 call
+ would assume the pointer to be far16)
+
+ Declarations come in two forms, and have the following syntax:
+
+ * 'typedef' <basic type|declared type> [<pointer decl>] <ident>
+ [ArrayDecl];
+
+ This form declares <ident> to have type < basic type | previously
+ declared type>.
+
+
+ +-------------------------------------------------------------------------+
+ | |
+ | typedef unsigned short USHORT; |
+ | |
+ | typedef USHORT MyShort; |
+ | |
+ | typedef USHORT far16 PUSHORT; |
+ | |
+ | typedef USHORT ShortArray[10]; |
+ | |
+ | typedef unsigned long near32 P32ULONG; |
+ | |
+ | typedef short *PSHORT; |
+ | |
+ | |
+ | Figure 1. Examples of typedef statements |
+ +-------------------------------------------------------------------------+
+
+! * 'typedef' [<alignment>] 'struct' <ident1> '{'
+! {< basic type | previously declared type> [<identn>]
+! [deleted [n]]; }
+! '}' <ident2> ';'
+
+! Declares <ident2> to be a structure type with a list of internal
+! fields. Each internal field declaration is must contain a known
+! type. The field identifier is optional. The internal field
+! identifier is only used by the compiler to generate comments in the
+! assembler file.
+
+! The <alignment> option declares the structure to be aligned in a
+! predefined manner. The alignment option is only valid when the
+! typedef declares a structure. The syntax of the alignment option
+! is
+
+! <alignment keyword> [ aligned ]
+
+! The 'aligned' keyword is optional. Valid alignment keywords are:
+
+! byte Structure fields are byte aligned
+
+! word Structure fields more than 1 byte in length are word
+! aligned (2 bytes)
+
+
+ Page 5
+
+! dword Structure fields are dword aligned (4 bytes). All items
+! greater than or equal to 4 bytes in length will be
+! aligned on a 4 byte boundary. All word sized data will be
+! word aligned.
+
+! If no alignment keyword is defined, then the compiler will choose
+! alignment based on the type of API it is used in. For example, if
+! the alignment is undefined, and is being used in a 16-bit API, then
+! the alignment will default to being word aligned. Likewise, use in
+! a 32-bit API defaults to dword alignment.
+
+! The deleted keyword can be used to modify a structure element. The
+! deleted keyword tells the compiler that this element is a place
+! holder, and doesn't actually exist. This is useful when a structure
+! has had elements added to it, and needs to map to the old
+! structure.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Page 6
+
+
+! +-------------------------------------------------------------------------+
+! | |
+! | typedef unsigned long ULONG; |
+! | |
+! | typedef struct _PIDINFO { |
+! | unsigned short PID; |
+! | unsigned short TID; |
+! | unsigned short PPID; |
+! | } PIDINFO; |
+! | |
+! | typedef PIDINFO *PPIDINFO; /* A pointer to a PIDINFO */ |
+! | |
+! | typedef dword aligned struct _Data1 { |
+! | unsigned short; |
+! | char FileName[13]; |
+! | unsigned long LongIdent; |
+! | dword aligned PIDINFO PidIdent; /* Imbedded structure */ |
+! | } Data1; |
+! | |
+! | typedef word struct _Data2 { |
+! | ULONG; |
+! | short; |
+! | } Data2; |
+! | |
+! | typedef struct _Data3 { |
+! | string *NameString; /* Imbedded pointer to ASCIIZ */ |
+! | Data2 *StructPointer; /* Imbedded pointer to struct */ |
+! | } Data3; |
+! | |
+! | typedef struct _Data4 { |
+! | unsigned short US1; |
+! | unsigned short US2; |
+! | unsigned long UL1 deleted; |
+! | unsigned long UL2 deleted 5; |
+! | unsigned short US3; |
+! | } Data4; |
+! | |
+! | typedef struct _Data4b { |
+! | unsigned short US1; |
+! | unsigned short US2; |
+! | unsigned long UL1; |
+! | unsigned long UL2; |
+! | unsigned short US3; |
+! | } Data4b; |
+! | |
+! | |
+! | |
+! | Figure 2. Examples of structure declarations: |
+! +-------------------------------------------------------------------------+
+
+! Note the example structures Data4 and Data4b. These two structures
+! can be mapped since they contain compatible elements. However, the
+! compiler will assume that the Data4 structure only contains
+! US1,US2, and US3. UL1 and UL2 are assumed not to exist. Using this
+! construct, we are actually mapping the following:
+
+
+
+
+
+ Page 7
+
+
+! +-------------------------------------------------------------------------+
+! | |
+! | |
+! | typedef struct _Data4 { |
+! | unsigned short US1; |
+! | unsigned short US2; |
+! | unsigned short US3; |
+! | } Data4; |
+! | |
+! | typedef struct _Data4b { |
+! | unsigned short US1; |
+! | unsigned short US2; |
+! | unsigned long UL1; |
+! | unsigned long UL2; |
+! | unsigned short US3; |
+! | } Data4b; |
+! | |
+! | |
+! | Figure 3. Effective mapping using the deleted keyword |
+! +-------------------------------------------------------------------------+
+
+! When converting from Data4b to Data4, the elements UL1 and UL2 are
+! not copied over. Thus, only the US1 US2 and US3 elements are copied
+! into the new structure.
+
+! When converting from Data4 to Data4b, we need to create new values
+! for the fields UL1 and UL2, since they didn't exist in Data4. This
+! is where the value following the deleted keyword is used. If no
+! value is specified, then the compiler will default to using zero as
+! the fill value. Otherwise, the compiler will place the value
+! specified into the field.
+
+! The fill value is only used when creating a new structure. There
+! are two cases where the value will used
+
+ - Structure created on input This would be the case where the
+ caller passes in the smaller structure, which needs conversion
+ to the larger structure. In the context of the above example,
+ the input is Data4, which is then converted to Data4b. In this
+ case, UL1 and UL2 would be filled in.
+
+ - Structure created on output This would be the case where the
+ caller passes in the larger structure, and expects the API to
+ fill it in. This case is determined when the parameter has
+ output only semantics. If the parameter is output only, then no
+ useful information is assumed to be in the structure on input.
+ Thus, the API must be filling the structure with this
+ information. In this case, the thunk will complete the
+ structure by providing the default values.
+
+
+
+ The following are examples of structures that are NOT handled by
+ the compiler.
+
+
+
+
+
+
+ Page 8
+
+
+ +-------------------------------------------------------------------------+
+ | |
+ | typedef struct _K { |
+ | string *StrAray[10]; /* Arrays of pointers not support|d */
+ | } K; |
+ | |
+ | |
+ | typedef struct _D { |
+ | string *StringPtr; /* This one is ok */ |
+ | } D; |
+ | |
+ | typedef struct _M { |
+ | D DArray[10]; /* Array of objects with pointers|*/
+ | } M; |
+ | |
+ | |
+ | Figure 4. Examples of illegal structure declarations |
+ +-------------------------------------------------------------------------+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Page 9
+
+ 5. Mappings
+
+
+ +-------------------------------------------------------------------------+
+ | |
+ | API16 unsigned short DosSleep(short,short) = |
+ | API32 unsigned long Dos32Sleep(long,long) |
+ | {} |
+ | |
+ | |
+ | Figure 5. A simple mapping statement. |
+ +-------------------------------------------------------------------------+
+
+ Mappings define the relationship between two APIs. Information from
+ this relationship is used to generate the actual thunk. Mapping
+ statements can become quite complex. The best way to explain mappings
+ is by example.
+
+ Figure -- is a simple form of a mapping. It defines DosSleep to be a
+ 16-bit API, which returns an unsigned short, and is passed two shorts
+ as parameters. It also defines API32 to be a 32-bit API, which returns
+ an unsigned long, and is passed two longs as parameters. The curly
+ braces on the end are required, and will be explained later.
+
+ The basic syntax of a mapping statement is:
+
+
+ [<api type>] <return type> <ident> ( <param list> ) =
+ [<api type>] <return type> <ident> ( <param list> )
+ '{' <semantics> '}'
+
+ <api type> Defines which type of API this identifier will be. Only
+ two values are accepted.
+
+ API16 Defines the API to be a 16-bit API
+
+ API32 Defines the API to be a 32-bit API
+
+ This declaration is optional. If the <api type> is not
+ declared, then the compiler will assume that the first
+ API in the mapping is API16, and the second is API32.
+ It is not legal to tag only one of the API's. If you
+ declare one, then you must declare the other.
+
+ <return type> Defines the type returned by the API. This can be any
+ previously declared type that maps to a basic data type.
+
+ <ident> Is a unique identifier. Identifiers must start with a
+ letter, and may be followed with any number of letters,
+ digits, or underscores.
+
+ <param list> Is a list of parameters that are passed to the API. A
+ parameter can be modified with the 'deleted' keyword to
+ indicate that the parameter has been removed. See
+ examples below for details.
+
+ <semantics> Is a block contain semantic information about the
+ parameters. Semantic blocks are described in a later in
+ this section.
+
+
+ Page 10
+
+ An example of a parameter list could be:
+
+ API16 short DosExample(short,char *buf,short len)
+
+ A few of interesting points here. First is that parameters in a
+ parameter list do not require an identifier. The identifier, such as
+ 'buf', are optional. They are useful when an API requires a semantic
+ block.
+
+ The second parameter, 'buf' is a pointer to a char. The '*' declares
+ this pointer as being a 16:16 pointer, since it is being declared in a
+ API16 mapping.The other option would be to declare it as a 0:32
+ pointer, by using the near32 keyword. A pointer keyword must be used to
+ declare items as pointers. Also, all structures passed as parameters
+ are required to be passed by reference, and therefore must have a
+ pointer type as their parameter. For example:
+
+ typedef struct Killer {
+ short P1;
+ short P2;
+ };
+
+ API16 short DosExample(short, Killer far16) =
+ API32 long Dos32Example(long, Killer near32)
+ {
+ }
+
+ or without the declaration of API type or pointer type
+
+ short DosExample(short,Killer *) =
+ long Dos32Example(long,Killer *)
+ {
+ }
+
+ In this example, the pointer to structure Killer has been properly
+ defined for both API types. They are both prefixed by the pointer type.
+
+ Each mapping statement may also contain a semantic block which defines
+ additional semantic information on the parameters being passed to an
+ API.
+
+ +-------------------------------------------------------------------------+
+ | short DosExample(short,char *buf,short len)= |
+ | long Dos32Example(short,char *buf,short len) |
+ | { |
+ | buf = output; |
+ | len = sizeof buf; |
+ | } |
+ +-------------------------------------------------------------------------+
+
+ In the above example (DosExample() = Dos32Example) the first line, buf
+ = output, defines the parameter buf to be an output parameter. This
+ informs the compiler that if buf needs to be copied elsewhere in memory
+ during the thunk, that the copy may be discarded. For all pointer
+ parameters, if no semantics are given to indicate whether the item is
+ input or output, then the compiler assumes that the item is input only,
+ and will not copy the structure out.
+
+ It also defines the parameter 'len' as the length in bytes of buf.
+
+
+ Page 11
+
+ Other semantic operations are defined below.
+
+ <ident1> = input; Defines parameter ident1 to be input
+ only.
+
+ <ident1> = output; Defines parameter ident1 to be
+ output only.
+
+ <ident1> = inout; Defines parameter ident1 to be both
+ input and output.
+
+ <ident1> = sizeof <ident2>; Defines parameter ident1 to hold the
+ length of ident2 in bytes.
+
+ <ident1> = countof <ident2>; Defines parameter ident1 to hold the
+ count of items that ident2 points
+ to. The actual size in bytes will be
+ calculated by multiplying ident1 by
+ the size of the data type to which
+ ident2 points.
+
+ stack <api ident> = <number>; This operation defines the minimum
+ amount of stack space required for
+ the api given. The minimum stack
+ space value is used to determine
+ when the stack may need to be bumped
+ (See the thunk section of the design
+ workbook). It is only useful when
+ generating a 32-->16 thunk. It is
+ normally only used for an API of
+ type API16.
+
+ inline = [ true | false ]; This sets a flag that tells the
+ compiler whether to favor execution
+ speed, or code size. Setting it to
+ true will generate only inline code,
+ which will result in faster code,
+ but larger size. Setting it to
+ false will result in subroutine
+ calls where appropriate, thus slower
+ code, and smaller size.
+
+ <api ident> = conforming; In the 16:16 --> 0:32 thunks, there
+ are times when thunk code must be
+ able to deal with ring 2 conforming
+ 0:32 code. The conforming keyword
+ tells the compiler that the thunk to
+ be generated should produce a
+! conforming compatible thunk.
+
+! <ident> = allow([value [,value]]) If ident is of type long or unsigned
+! long, and is to be truncated to a
+! signed/unsigned short value, then
+! the thunk will normally check to
+! insure that the value will not be
+! truncated. If the value is outside
+! of the range available with the
+! short value, then the thunk will
+! return an error. The allow()
+
+
+ Page 12
+
+! semantic allows the specified values
+! to pass the truncation check without
+! error. The value will be truncated
+! to 16-bits, losing the high word.
+
+! <ident> = restrict([value [,value]]) The restrict semantic will
+! restrict the allowable values for a
+! parameter to only the values in the
+! value list. This is useful for
+! restricting a parameter to be only
+! 0, or some other default value. If a
+! parameter has a value that doesn't
+! appear in the list, then the thunk
+! will return the errbadparam code.
+
+! errbadparam = <numeric> This sets the errbadparam value for
+! this mapping. The value is set for
+! the current mapping only.
+
+! errnomem = <numeric> This sets the errnomemory value for
+! this mapping. The value is set for
+! the current mapping only.
+
+! errunknown = <numeric> This sets the errunknown value for
+! this mapping. The value is set for
+! the current mapping only.
+
+ 6. API with different parameter counts
+
+
+ The thunk compiler requires that two function prototypes have the same
+ number of parameters in order to be mapped. However, if you need to add
+ or remove parameters from one of the prototypes, then you can use the
+ 'deleted' keyword for that parameter.
+
+ For example, DosChDir() has a different number of parameters between
+ its 32-bit version and its 16-bit version.
+
+
+ USHORT DosChDir(PSZ pszDirPath,ULONG ulReserved);
+
+ ULONG Dos32ChDir(PSZ pszDirPath);
+
+ The thunk compiler will allow a mapping such as:
+
+ USHORT DosChDir(PSZ pszDirPath,ULONG ulReserved) =
+
+ ULONG Dos32ChDir(PSZ pszDirPath,ULONG ulReserved deleted 0 )
+
+ {
+ }
+
+
+ There are two results of this mapping declaration. In a mapping
+ directive of DosChDir => Dos32ChDir, the ulReserved parameter will not
+ be pushed the Dos32ChDir stack frame. The effective result is only
+ pszDirPath will be passed to the API.
+
+ The other possibility is a mapping directive of Dos32ChDir => DosChDir.
+
+
+ Page 13
+
+ In this case, a parameter needs to be added to the call frame the place
+ of ulReserved. The size of the item pushed is specified in the target
+ (DosChDir), and will be a ULONG. The value of the item pushed can be
+ specified by the number following the deleted keyword. In this case,
+ the value is a ULONG = 0.
+
+ In another example, say that Dos32Beep was modified to play a song
+ which is specified by a number. The mapping needs to look like
+
+ DosBeep(USHORT usFrequency,USHORT usDuration) =
+ Dos32Beep(ULONG ulFrequency,ULONG ulSongNum,ULONG ulDuration)
+ {
+ }
+
+ In the case of DosBeep => Dos32Beep, we need to add a parameter to the
+ call. This is done, same as before, with:
+
+ DosBeep(USHORT usFrequency,USHORT usSongNum deleted 7, USHORT usDuration) =
+ Dos32Beep(ULONG ulFrequency,ULONG ulSongNum,ULONG ulDuration)
+ {
+ }
+
+ where 'deleted 7' will make the default song to be the theme from "The
+ Flintstones".
+
+
+
+ 7. Map Directives
+
+ The mapping declarations only defined a relationship between two API.
+ The third and final section to the thunk description language simply
+ defines which direction thunk should be generated. A mapping directive
+ has the form:
+
+ <api ident1> => <api ident2>;
+
+ This will result in a thunk FROM ident1 TO ident2. Mapping directives
+ only work on a previously declared mapping. It is not possible to
+ create a mapping directive for two API that are not related to each
+ other by a mapping declaration. An example of a correct mapping
+ directive is
+
+ +-------------------------------------------------------------------------+
+ | |
+ | DosRead => Dos32Read; |
+ | |
+ | A correctly formed mapping directive |
+ +-------------------------------------------------------------------------+
+
+ Assuming that DosRead is a 16:16 API, and Dos32Read is a 0:32 API, then
+ the example map directive would produce a 16:16 --> 0:32 thunk.
+
+ 8. Compiler Directives
+
+ * inline
+
+ Syntax inline = < true | false >;
+
+ The inline directive changes the current default inline value. The
+
+
+ Page 14
+
+ inline value determines whether code is generated inline, or
+ whether subroutine calls are allowed. The change will only affect
+ the mapping statements defined after this statement.
+
+ * #include
+
+ Syntax: #include "filename.ext"
+
+ The #include directive works much like the 'C' #include
+ preprocessor directive. Its sole purpose is to suspend input from
+ the current source file, and direct input from an alternate source
+ file. When the end of the alternate source file is read, it is
+ closed, and input resumes from the original source file.
+
+ The syntax of the #include statement only allows for filenames to
+ be enclosed in double quotes. The #include <filename.ext> form that
+ 'C' uses is not defined. The compiler does NOT search any of the
+ include paths. If the file to be included is not in the current
+ directory, then a full pathname will be required. The filename may
+ be any legal filename accepted by fopen().
+
+ Includes may nest many levels deep. The only restriction is the
+ number of open files per process.
+
+ * stack
+
+ Syntax: stack = <n>;
+
+ The stack directive changes the current default minimum stack size
+ to <n>, where <n> is an integer value 0 thru 32767. The change
+ will only affect the mapping statements defined after this
+ statement.
+
+ * syscall
+
+ Syntax: syscall = < true | false >;
+
+ The syscall keyword is used to control the calling convention
+ assumptions made by the caller. The syscall keyword indicates that
+ the 16-bit target API follows the BASE calling convention of saving
+ all registers and segment registers, with the exception of eAX. If
+ syscall = false, then a 32->16 thunk will save the contents of ES
+ before calling. If syscall = true, then the compiler assumes that
+ the target routine will save es. Changing the syscall value will
+ only affect the mapping statements defined after this statement.
+
+! * errbadparam
+
+! Syntax: errbadparam = <numeric>;
+
+! This sets the global default for the errbadparam return code. This
+! code is returned whenever the thunk layer determines that a
+! parameter will be truncated, or is not allowed by a restrict()
+! semantic. It is also used for parameters that are 'sizeof' or
+! 'countof' when the resulting size is greater than the API will
+! allow.
+
+! * errnomem
+
+
+
+ Page 15
+
+! Syntax: errnomem = <numeric>;
+
+! This sets the global default for the errnomem return code. This
+! code is returned whenever the thunk layer cannot allocate memory
+! from its block manager.
+
+! * errunknown
+
+! Syntax: errunknown= <numeric>;
+
+! This sets the global default for the errunknown return code. This
+! code is returned whenever the thunk layer has an error returned
+! from a subsystem, such as Dos32CreateLinearAlias, or Dos32AllocMem.
+! If no errunknown value gets set, then the thunk will return the
+! error code from the subsystem.
+
+ * Comments
+
+ Syntax: /* <comment text> */
+
+ Comments in the thunk description language are similar to the 'C'
+ programming langauge. A comment block is opened by a '/*'
+ combination, and closed by a '*/' combination. Unlike 'C', the
+ thunk language will allow nesting of comments.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Page 16
+
+ 9. Programmers Guide
+
+
+ This section will discuss issues related to the writing of thunk
+ scripts. It is advised that a programmer read this section BEFORE
+ writing complex thunk scripts.
+
+ a. Numeric Constants
+
+ The thunk compiler recognizes numeric constants, and constant
+ expressions involving operators in the set ( + - * /). All numeric
+ constants are assumed to be integer values. Constants are only used
+! in array declarations, and in setting the size of the stack.
+
+! The thunk compiler will also accept hex numbers, if they are
+! specified in the standard 'C' format (ie 0xffff).
+
+ b. Using the 'C' preprocessor with the thunk compiler.
+
+ One potentially useful trick is to use the C preprocessor on a
+ script file, before feeding it to the thunk compiler. This allows
+ the programmer to use the standard C # macros, such as #define,
+ #ifdef, #include, etc. Using the preprocesser like this is a bit
+ of a hack, but it should work.
+
+ To do this, run the thunk script through the standard Microsoft C
+ compiler, using the /EP switch. This will tell the C compiler to
+ process the input file, doing string replaces on all of the
+ #defines, and will handle all of the macros. Pipe this output to a
+ temporary file, and then feed this to the thunk compiler.
+
+ For example
+ c:>cl /EP thkfile.thk > temp.thk
+ c:>thunk temp.thk
+
+ c. Data Translations
+
+
+ The compiler is capable of translating between long and short
+ types. The following table shows which translations are supported:
+
+ short <-> long
+ unsigned short <-> unsigned long
+
+
+
+ Note that it is not possible to translate semantics interpretations
+ of the data (ie unsigned to signed). This type of translation is
+ meaningless, and the compiler will produce an error message if you
+ attempt this.
+
+
+ The int type is handled slightly differently. The compiler
+ translates the int or unsigned int data type into the type that is
+ native to the API in which it is used.
+
+
+ For 16:16 API
+
+
+
+ Page 17
+
+ int -> short
+ unsigned int -> unsigned short
+
+ For 0:32 API
+
+ int -> long
+ unsigned int -> unsigned long
+
+ This allows a value to be used in both API types, and it will be
+ converted based on which API it is used in. This is especially
+ useful when a typedef is used to declare a type that must be used
+ in both worlds, but assumes a different size. For example,
+
+
+ +-------------------------------------------------------------------------+
+ | |
+ | typedef unsigned int BOOL; |
+ | |
+ | BOOL MyExample(BOOL *,string *,short) = |
+ | BOOL MyExample(BOOL *,string *,long) |
+ | {} |
+ | |
+ | is exactly equivalent to saying |
+ | |
+ | unsigned short MyExample(unsigned short *,string *,short) = |
+ | unsigned long MyExample(unsigned long *,string *,long) |
+ | {} |
+ +-------------------------------------------------------------------------+
+
+
+ d. Passing Pointer Parameters
+
+
+ The thunk compiler will handle the conversion and passing of
+ pointer parameters. Pointer parameters can point to any of the
+ predefined data types, or to structures. The compiler does not
+ support double indirect pointers (pointers to pointers), but there
+ is a workaround for this which is describe later.
+
+ If a pointer parameter points to a base data type (short, long,
+ etc), then the compiler will handle correct
+
+
+ If a pointer is passed between API, and the data types are exactly
+ the same, then the thunk compiler treats the data as a block of
+ bytes, and will emit code that does not deal with data types. The
+ code in the 0:32 --> 16:16 direction checks the block of bytes to
+ determine if it crosses a 64k boundary. If it does, then action to
+ correct the problem is taken. For example:
+
+
+
+
+
+
+
+
+
+
+
+
+ Page 18
+
+
+ +-------------------------------------------------------------------------+
+ | |
+ | typedef struct _K { |
+ | short ShortVal; |
+ | char CharVal; |
+ | } K; |
+ | |
+ | short DosExample(K *ptrK) = |
+ | long Dos32Example(K *ptrK) |
+ | { |
+ | } |
+ | |
+ | Dos32Example => DosExample; |
+ +-------------------------------------------------------------------------+
+
+
+ In the above example, the structure K will require no changes in
+ packing, since the alignment is the same in both the 32 bit and 16
+ bit API. In this case, the pointer to K can be treated as a
+ pointer to sizeof(K) bytes of data. The thunk code for this will
+ check to insure that the data buffer does not cross a 64k boundary.
+ If it does, then a copy of the data will be made, and the new
+ pointer passed on to the target API. If it doesn't cross a 64k
+ boundary, then the original pointer will be passed.
+
+
+ If the pointer is to different types (ie SHORT to LONG), or if the
+ pointer is to a structure with differences in any of the data types
+ (packing or different pointer types), then a new copy of the data
+ is made elsewhere in memory, and a pointer to the new copy is
+ passed to the target API. For example:
+
+
+ +-------------------------------------------------------------------------+
+ | typedef struct _K { |
+ | short ShortVal; |
+ | long LongVal; |
+ | } K; |
+ | |
+ | short DosExample(K *ptrK) = |
+ | long Dos32Example(K *ptrK) |
+ | { |
+ | } |
+ | |
+ | Dos32Example => DosExample; |
+ | |
+ | |
+ | 0:32 16:16 |
+ | struct K struct K |
+ | +--------+ 0 +--------+ 0 |
+ | |ShortVal| |ShortVal| |
+ | +--------+ 2 +--------+ 2 |
+ | |Padding | |LongVal | |
+ | +--------+ 4 +--------+ 4 |
+ | |LongVal | | " " | |
+ | +--------+ 6 +--------+ 6 |
+ | | " " | |
+ | +--------+ 8 |
+
+
+ Page 19
+
+ +-------------------------------------------------------------------------+
+
+ In this second example, struct K has different packing and size
+ between the API. Here, we must convert K into the form expected by
+ DosExample. In the 32 bit version, K is 8 bytes long, with
+ ShortVal starting at offset 0, and LongVal at offset 4.
+
+
+ Memory is allocated somewhere (probably the stack on such a small
+ item), and the 32 bit version of K is copied field by field into
+ the 16 bit version This creates a 16:16 equivalent. The call is
+ then made passing a pointer to the new 16:16 copy of K. When the 16
+ bit call returns, and if the struct was declared as an output
+ parameter in the semantic section, the 16:16 structure K will be
+ copied field by field back into the original. In either case, the
+ allocated memory is deallocated, and the routine returns.
+
+
+ Another case that is similar to the different packing case is when
+ a structure contains an imbedded pointer. For example:
+
+
+
+ +-------------------------------------------------------------------------+
+ | typedef struct _K { |
+ | short ShortVal; |
+ | string *StrVal; /** Imbedded Pointer **/ |
+ | } K; |
+ | |
+ | short DosExample(K *ptrK) = |
+ | long Dos32Example(K *ptrK) |
+ | { |
+ | } |
+ | |
+ | Dos32Example => DosExample; |
+ | |
+ | 0:32 stack |
+ | +-------+ |
+ | | | |
+ | +-------+ |
+ | | | 0:32 K |
+ | +-------+ +--------+0 |
+ | | *ptrK |-------------> |ShortVal| ASCIIZ |
+ | +-------+ +--------+4 +---------------+|
+ | | EIP | |*StrVal |------------->|A|B|C|C|D|E|F|0||
+ | +-------+ +--------+ +---------------+|
+ | | EBP | |
+ | +-------+ |
+ +-------------------------------------------------------------------------+
+
+
+ In this case, the struct K has a pointer to a null terminated
+ string imbedded inside. This means that the pointer will have to be
+ changed to a new value (0:32 --> 16:16). We make a copy just like
+ the previous case, but now we need to deal with the imbedded
+ pointer.
+
+
+ The object that the imbedded pointer points to must also be checked
+
+
+ Page 20
+
+ for 64k crossings. It will be handled exactly like any other buffer
+ that potentially crosses a 64k boundary. (ie check for crossing,
+ copy if needed).
+
+
+ The call to the 16 bit routine is then made. On return from the
+ 16bit call, and if the parameters semantics specify output, then
+ the structure is copied back to the original location.
+
+
+ NOTE: The following paragraph is subject to change
+
+ ***************************************************************
+
+ There is one very important exception during the copy out. The
+ pointer parameter IS NOT copied out. This is done because of many
+ problems that could arise if the output pointer changes.
+ Structures which contain pointers that are for copy out may need
+ hand modifications. The programmer must watch out for side effects,
+ such as what happened to the original pointer? Was it aliased? Was
+ its memory freed? The current version of the thunk compiler is not
+ equipped to handle these questions. There are no problems when the
+ pointer is for copy in only.
+
+ ***************************************************************
+
+
+ e. The NULLTYPE parameter
+
+ In those cases where the thunk compiler will not produce correct
+ code, either due to very complex semantics, or due to data types
+ not handled, it may be useful to have the thunk compiler do as much
+ of the thunk as possible, to limit the amount of hand coding
+ needed. This is where the basic data type 'nulltype' comes in
+ handy.
+
+ Nulltype parameters are 'place holders'. No code is emited to
+ handle the nulltype parameter. The only code emitted is an error
+ message to MASM that will cause an error if compiled. This is to
+ insure that the programmer goes into the output file and hand
+ modifies that section of code with the NULL type.
+
+ Declaring a pointer to a nulltype will result in temporary storage
+ being allocated for the nulltype, and some skeleton code that gets
+ the pointer from the stack, and checks it for null value. The rest
+ of the conversion for this parameter is left to the programmer.
+
+ f. Using semantic operators
+
+ * Specifying input/output/inout The default semantic value for
+ all parameters is 'input'. This means that if no other semantic
+ information is given, the compiler will assume that a parameter
+ is input only, and the data item will not be copied out.
+
+ If a parameter is an output type, such as a read buffer, or a
+ returned count, then the parameter must be declared as output
+ in the semantic block. For example,
+
+
+
+
+ Page 21
+
+
+ +-------------------------------------------------------------------------+
+ | |
+ | short DosFoo(short Flags, void *Buffer, short len) = |
+ | long Dos32Foo(long Flags, void *Buffer, long len) |
+ | { |
+ | Buffer = output; |
+ | len = sizeof Buffer; |
+ | } |
+ | |
+ +-------------------------------------------------------------------------+
+
+
+ In this example, Buffer is declared to be an output only
+ buffer. It is then assumed that the input buffer has no useable
+ information, and that it doesn't need to be copied in. This is
+ significant in the case where Buffer crosses a 64k boundary,
+ and must be copied elsewhere. When the semantics specify only
+ output, a buffer will be allocated in memory, but no
+ information will be copied into the new buffer. However, on the
+ return from the call, the information from the allocated buffer
+ is copied back into the original buffer.
+
+
+ If a parameter is bi-directional, then it will be both copied
+ in and copied out. To specify bi-directional parameters, use
+ the 'inout' semantic keyword. For example,
+
+
+ +-------------------------------------------------------------------------+
+ | |
+ | short DosFoo(short Flags, void *Buffer, short *len) = |
+ | long Dos32Foo(long Flags, void *Buffer, long *len) |
+ | { |
+ | Buffer = output; |
+ | len = sizeof Buffer; |
+ | len = inout; |
+ | } |
+ | |
+ +-------------------------------------------------------------------------+
+
+ In this example, the parameter 'len' may represent the length
+ of the buffer pointed to by 'Buffer', and will receive the
+ actual number of bytes placed in 'Buffer' by DosFoo. In this
+ case, we need to insure that the contents of 'len' are not lost
+ on output.
+
+ In the special case of 'string' parameters (NULL terminated
+ strings), the only valid semantic that can be applied is input.
+ If you attempt to assign an output, or inout parameter to a
+ string, then the compiler will give you an error message.
+
+ * Specifying parameter sizes
+
+ Pointer parameters will assume that the size of the object
+ pointed to is the same as the size of the object. For example,
+ a pointer to a long will be assumed to be a pointer to a 4
+ bytes buffer. This can be overridden in cases where there is a
+ pointer to a buffer. For example,
+
+
+ Page 22
+
+
+
+ +-------------------------------------------------------------------------+
+ | |
+ | short DosFoo(char *Buffer, short len) = |
+ | long Dos32Foo(char *Buffer, long len) |
+ | { |
+ | Buffer = output; |
+ | len = sizeof Buffer; |
+ | |
+ | } |
+ | |
+ +-------------------------------------------------------------------------+
+
+
+ In this example, 'len' has been defined to hold the number of
+ bytes pointed to by 'Buffer'. Often, a size parameter holds a
+ count of items rather than the size in bytes of the buffer.
+ This is handled by the countof semantic. For example,
+
+
+ +-------------------------------------------------------------------------+
+ | |
+ | short DosFoo(long *Buffer, short len) = |
+ | long Dos32Foo(long *Buffer, long len) |
+ | { |
+ | Buffer = output; |
+ | len = countof Buffer; |
+ | |
+ | } |
+ | |
+ +-------------------------------------------------------------------------+
+
+
+ In this example, 'len' represents the number of longs that
+ 'Buffer' points to. The thunk will then calculate the number of
+ bytes in 'Buffer' by multiplying len * sizeof(long). In this
+ case, if len = 4, then the compiler would deduce that Buffer
+ was 16 bytes long.
+
+
+
+
+ g. Polymorphic Parameters
+
+
+ One area that the thunk compiler does not handle is the area of
+ polymorphic parameters. These are pointer parameters that assume
+ different characteristics based on some key value. For example,
+ DosDevIOCtl is a routine which has a polymorphic pointer parameter.
+ Based on a flag value passed along with the function, the pointer
+ can be pointing to one of at least 50 different structures. In this
+ case, it is not feasible for the thunk compiler to generate a thunk
+ to handle all cases.
+
+
+ Other forms of polymorphic parameters are more subtle. For example,
+
+
+
+
+ Page 23
+
+
+ +-------------------------------------------------------------------------+
+ | short DosFoo(short Flags, void *Buffer) = |
+ | long Dos32Foo(long Flags, void *Buffer) |
+ | {} |
+ | |
+ | The semantics of this call specify that if Flags == 3, then |
+ | Buffer is to be disregarded. |
+ +-------------------------------------------------------------------------+
+
+ In this example, if Flags is 3, then Buffer is an invalid
+ parameter, and should not be used. In this case, Buffer assumes
+ different semantics based a another value in the parameter list.
+ The thunk compiler doesn't know how to handle this case, and the
+ programmer will have to hand modify the output code to deal with
+ this.
+
+ The modifications for polymorphic parameters can range from being
+ very simple, or to being very complex. Careful planning is advised,
+ as is a very clear understanding of the API.
+
+ h. Structuring of the script files
+
+ The script language was designed to be crafted in a certain
+ structure, to make maintaining the files easy. As a guideline for
+ writing the scripts, the following format is suggested.
+
+ Scripts should be divided into three basic sections,
+
+ 1) Type definitions (typedefs)
+
+ Move all of the typedef statements into a single file, which
+ can be included into files as needed using the #include
+ directive.
+
+ 2) Mapping declarations
+
+ Mapping declarations should be grouped according to the .DLL
+ file in which they reside. Mapping declarations should be
+ divided into two files.
+
+ * Thunks which are generated automatically
+
+ * Thunks which require any type of hand modification
+
+ Following this guideline, each .DLL file will have two .def
+ files associated with it.
+
+ 3) Mapping Directives
+
+ Mapping Directives should reside in the same file as their
+ associated mapping declarations. Mapping directives should be
+ placed at the end of the file, so they can easily be modified.
+
+
+ i. Hand coding thunks
+
+ Some thunks will have to be hand coded. These are thunks which pass
+ data types that the compiler cannot handle, have polymorphic
+
+
+ Page 24
+
+ parameters, or some other feature that the compiler doesn't handle.
+ If at all possible, it is suggested that the compiler be used to
+ generate a base thunk that can be modified by hand. This should
+ save the programmer from doing most of the work, and should speed
+ development time.
+
+ j. Using the inline Flag
+
+ Setting the inline flag to true can increase the speed at which
+ thunk code is executed, but it also increases the code size. There
+ is a definite time-space tradeoff when using the inline flag. Here
+ are a few guidelines to using this flag.
+
+ * Consider the amount of work to be done
+
+ If an API is known to be slow, such as an API that accesses the
+ disk, waits for an event, or does an incredible amount of work
+ such as BitBlit, then setting the inline flag may be a moot
+ point. The time saved getting through the thunk layer in these
+ cases is very insignificant when compared to the execution of
+ the API.
+
+ * Consider the frequency of calls
+
+ If an API is only called once during the run of an application,
+ such as DosGetPid, or DosExit, speed probably isn't very
+ important. However, if an API is a very frequently called one,
+ such as WinGetMsg, you will want to make the thunk as fast as
+ possible. WinGetMsg is a case where we definitely want to favor
+ speed over size, since it is usually called in a very tight
+ loop.
+
+ For the majority of thunks, we want to favor small size over speed,
+ so you should leave the inline flag set to false.
+
+ k. Using the stack flag
+
+
+ When a thunk in the 0:32 --> 16:16 direction is generated, a check
+ is made to determine if the 32 bit APP has enough stack space
+ before the next 64k boundary to complete the call. The size
+ considered 'enough' for a call can be set using the 'stack'
+ semantic. If an API is known to use a great deal of stack space,
+ then the script can modify the amount of stack to allow for the
+ particular API. This value is only used in a 0:32 --> 16:16 thunk,
+ and is based on the amount of space needed by the 16:16 routine. If
+ the stack size is issued for a 0:32 API, it is ignored.
+
+ l. Using the conforming flag
+
+ The thunk layer needs to know when to deal with conforming code.
+ This is code that can be called from either ring 3 or ring 2. The
+ conforming keyword is used in 16:16 --> 0:32 direction thunk to
+ enable the thunk to call the 0:32 ring 2 conforming code directly.
+ If a routine must be conforming, then you must tell the thunk
+! compiler by using this statement.
+
+! m. Value truncation
+
+
+
+ Page 25
+
+! Values that are being converted from a long (32-bit) type to a
+! short (16-bit) type are checked for truncation during runtime. If a
+! value is too large to fit into a 16-bit type (ie > 0xffff unsigned
+! or outside the range -32768 thru 32767), the thunk will return with
+! an error. The error code returned is ERROR_INVALID_PARAMETER, or
+! what ever the errbadparam value has been set too. To allow certain
+! parameters to truncated, see the allow() semantic in the semantic
+! section.
+
+ n. Subroutine libraries
+
+ The thunk compiler uses several subroutines in an effort to reduce
+ the code size. These subroutines are integral with the code
+ produced by the caller, and are not useful for any other purpose.
+
+ Two of these subroutines, which handle the block allocator for the
+ thunk compiler, are located in Doscall1.dll, and are exported API's
+ from that .DLL. The calls are THK32ALLOCBLOCK and THK32FREEBLOCK.
+ They allocate and deallocate 128 byte blocks. The memory space is
+ per process, and the allocation routines are guarded by a simple
+ semaphore to insure mutual exclusion between threads.
+
+ The rest of the library routines are found in thunkrt.lib, which
+ can be found in the LIB directory of the build tree. This library
+ contains several routines that are needed by the output of the
+ thunk compiler.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Page 26
+
+ 10. Reference
+
+ a. Thunk description example
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Page 27
+
+
+ /*** Example of the thunk description language ***/
+
+ typedef unsigned short USHORT;
+ typedef unsigned long ULONG;
+ typedef unsigned int UINT;
+
+ typedef struct _PIDINFO {
+ USHORT PID;
+ USHORT TID;
+ USHORT PPID;
+ } PIDINFO;
+
+ typedef PIDINFO *PPIDINFO; /* Define PPIDINFO to be a pointer type */
+
+ typedef struct _Example {
+ USHORT P1;
+ char FileName[13]; /* An array of 13 characters imbedded */
+ PIDINFO ExampleStruct; /* A structure can be statically imbedded */
+ /* A pointer to a structure will need hand */
+ /* modifications */
+ } Example;
+
+ /** The following defines the mapping between DosBeep and Dos32Beep **/
+ /** DosBeep is first in the mapping, and therefore is assumed to be **/
+ /** the 16:16 routine. Dos32Beep is second in the **/
+ /** Also, the UINT in DosBeep is considered to be an unsigned short **/
+ /** while the UINT in Dos32Beep is an unsigned long **/
+
+ USHORT DosBeep(USHORT,UINT) =
+ ULONG Dos32Beep(ULONG,UINT)
+ {}
+
+ /** This mapping passes a structure. Note that the structure must **/
+ /** be passed by a pointer type. **/
+
+ USHORT DosGetPid(PPIDINFO) =
+ ULONG Dos32GetPid(PPIDINFO)
+ {
+ PPIDINFO = output; /* Define as an output parameter */
+ }
+
+ /** Note that by using the * to denote pointers, the pointer types are */
+ /** implicitly defined based on the API type. */
+
+ USHORT DosRead(USHORT,void *buf,USHORT len,USHORT *bytesread) =
+ ULONG Dos32Read(ULONG,void *,ULONG,ULONG *)
+ {
+ buf = output; /** DosRead's buffer needs to be copied out*/
+ len = sizeof buf; /** len is # of bytes in buf */
+ bytesread = inout; /** bytesread is passed in and out */
+ }
+
+
+
+ /** Mapping Directives **/
+
+ DosBeep => Dos32Beep; /* 16 -> 32 */
+ Dos32Read => DosRead; /* 32 -> 16 */
+
+
+ Page 28
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Page 29 \ No newline at end of file
diff --git a/private/os2/client/thunk/thunkcom/thunkcom b/private/os2/client/thunk/thunkcom/thunkcom
new file mode 100644
index 000000000..46637c5cf
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/thunkcom
@@ -0,0 +1,1458 @@
+.* SCCSID = @(#)thunkcom.doc 13.4 89/11/01
+:h3.Thunk Compiler Manual &SYSDATE &SYSTIME
+.* Revision Codes and switches
+.rc 1 !
+.*
+.*
+:p
+:ol
+.rc 1 on
+:li.Special Notes
+:p
+The following items have changed since the last release of this
+document.
+:ul
+:li.It is now possible to delete individual structure elements.
+:p
+See the type definition section for details.
+:li.Allow Lists
+:p
+A new feature has been added which allows the user to specify a list
+of long values that can be truncated to short value without causing an
+error. See semantic section for details.
+:li.Restrict Lists
+:p
+This new feature will allow you to restrict the values that may be
+passed to an API. See semantic section for details.
+:li.Setting error codes.
+:p
+You can now set the error codes for certain conditions. See compiler
+directive and semantic sections for details.
+section for details.
+:li.Value truncation
+:p
+The thunks will determine when data is going to be truncated, and return
+and error if this happens. See the programmers guide for further details.
+.rc 1 off
+:eul
+:p
+.rc 1 on
+:li.Command Line Options
+:p
+To invoke the thunk compiler, use the command:
+:p
+thunk [{-|/}options] [-L xxxxx] <infile> [ <outfile> ]
+:p
+where options include zero or more of the following flags:
+:p
+:dl tsize=14.
+:dt.B
+:dd.INT 3 on entry/frame/call/exit. Generates inline INT 3 instructions in
+all interesting places. Equivalent to -CE
+:dt.c
+:dd.INT 3 on call
+:dt.C
+:dd.INT 3 on frame/call
+:dt.d
+:dd.Debugging Output. The -d flag tells the compiler to dump the
+internal data tables. This is debugging output, and is sent to
+standard error. It is not intended to be useful for anything but
+debugging the compiler itself.
+:dt.D
+:dd.Debugging output to file thunk.dmp. Same as d, except output
+is written to the file thunk.dmp
+:dt.e
+:dd.INT 3 on entry
+:dt.E
+:dd.INT 3 on entry/exit
+:dt.f
+:dd.INT 3 on frame generation
+:dt.F
+:dd.Force 1 byte of data into data segment
+:dt.L nnnn
+:dd.Start label generation at nnnn. Internal labels in the compiler are
+generated numerically, such as L101:, and normally start at label L0:.
+Labels have the range 0-65535. The label generating mechanism will wrap
+if labels pass 65535.
+:dt.O
+:dd.Disable the compaction of routines. The thunk compiler will
+combine thunks that have identical semantics and parameters into common
+code groups. This reduces the amount of code by reusing common subroutines.
+Using the -O flag will disable this compaction.
+:dt.p
+:dd.The -p flag changes the compiler default for 32-bit structure
+packing to WORD, instead of DWORD. The default for the compiler is
+that all structures are packed so that DWORD sized or larger data are
+aligned on DWORD boundaries. The -p flag insures that DWORD objects
+are aligned on WORD boundaries.
+:dt.s
+:dd.Syntax check only. No output code is produced.
+:dt.u
+:dd.Prefix a _ to all 32-bit names. This is useful when creating a
+C callable thunk library without using a .def file.
+:dt.U
+:dd.Disable 16-bit name uppercasing. Default is that all 16-bit names are
+folded to uppercase. This disables the folding, and names assume the case
+used in the source file.
+:dt.x
+:dd.INT 3 on exit
+:dt.y
+:dd.Answer 'y' to overwrite file question. Normally, the thunk compiler
+will stop to ask permission to overwrite .asm files. The y flag overrides
+this query.
+:dt.z
+:dd.Disable 32-bit name uppercasing. Default is that all 32-bit names are
+folded to uppercase. This disables the folding, and names assume the case
+used in the source file.
+:dt.N<x> <name>
+:dd.The -N switch allows the user to specify names of segments and classes,
+where <x> is one of
+:dl tsize=5
+:dt.A
+:dd.32-bit code segment name
+:dt.B
+:dd.32-bit code class name
+:dt.C
+:dd.16-bit code segment name
+:dt.D
+:dd.16-bit code class name
+:dt.E
+:dd.32-bit data segment name
+:dt.F
+:dd.32-bit data class name
+:edl
+:p
+and <name> is the name to be used.
+
+:edl
+:p
+<infile> is the input description file.
+:p
+<outfile> is the MASM output file. This filename is optional. If it is not
+specified, then the input filename will be used, with the extention .ASM.
+.rc 1 off
+:li.Introduction
+.** Intro Section ul
+:ul
+:p
+The Thunk Compiler is a program that will generate an interface
+layer between 32-bit and 16-bit modules under OS/2. It will accept as
+input a description langauge, and will output assembler code suitable
+for compilation under MASM 5.1.
+:p
+The current implementation of the thunk compiler will only generate
+thunks in the 32 to 16 bit direction.
+:li.Input Language
+:p
+The thunk compiler input langauge is modeled after the 'C' programming
+langauge. The syntax is very similar.
+There are three basic sections to
+a thunk description.
+:ol
+:li.Delcarations
+:p
+Declarations are used to declare complex types, using basic data types, or
+previously declared data types. Declarations use the 'typedef' syntax of
+the 'C' langauge.
+
+:li.Mappings
+:p
+Mappings define a relationship between two APIs. Each mapping defines
+all needed information about the relationship between two APIs, including
+names, parameters, return types, and semantic information about the
+parameters.
+:li.Map Directives
+:p
+Map directives are usually the last section of the program. A map directive
+causes a thunk to be generated for two APIs whose relationship was
+declared using a Mapping.
+:p
+:eol
+The thunk input language is case sensitive. Therefore, the identifiers
+foo, Foo, and FOO are considered unique.
+:li.Output File
+:p
+The output file generated by the thunk compiler is a text file containing
+assembler source code. It can be compiled using MASM 5.1 or later.
+:li.Restrictions
+:p
+The thunk compiler does not handle the following constructs:
+:ul
+:li.Arrays of pointers or arrays of data objects that contain pointers.
+:li.Arrays of arrays.
+:li.Arrays of structures passed as parameters.
+:eul
+:p
+Thunks containing such constructs will need hand modification before
+they will operate correctly.
+.** End Intro Section ul
+:eul
+:li.Declarations
+:p
+Declarations are used to define new data types based on existing
+data types. There are several predefined data types.
+.*
+:dl tsize=20.
+:dt.short
+:dd.A 16 bit signed integer.
+:dt.long
+:dd.A 32 bit signed integer.
+:dt.unsigned short
+:dd.A 16 bit unsigned integer.
+:dt.unsigned long
+:dd.A 32 bit unsigned integer.
+:dt.int
+:dd.Using the int type will tell the compiler to use which ever type is
+the default for the API type. Using an int in a 16 bit API will result
+in a 16 bit signed integer. Using an int in a 32 bit API will result in
+a 32 bit signed integer.
+:dt.unsigned int
+:dd.Using the unsigned int type will tell the compiler to use which ever
+type is the default for the API type. Using an unsigned int in a 16 bit
+API will result in a 16 bit unsigned integer. Using an int in a 32 bit
+API will result in a 32 bit unsigned integer.
+:dt.string
+:dd.A pointer to a null terminated string of characters. Must be
+prefaced by a pointer type.
+:dt.char
+:dd.A single byte of type character. Most often used with a pointer to
+point to a data buffer.
+:dt.void
+:dd.A pointer to a single byte with no semantic information. Most often
+used to point to a data buffer. Must be prefaced by a pointer type.
+:dt.nulltype
+:dd.A nulltype is used as a place holder for thunks that will require
+special hand coding. The net result of using a nulltype is that whenever
+the nulltype is referenced, the compiler will output a line that will
+cause an error if the output file is assembled (ie. .err NULLTYPE).
+:edl
+:p
+All basic types can be prefaced by a pointer type. There are three pointer
+types:
+:dl tsize=10.
+:dt.far16
+:dd.The far16 keyword denotes that the data item is a selector&gml.offset
+format pointer. These pointers are used in 16-bit OS/2.
+:dt.near32
+:dd.The near32 keyword denotes that the data item is a 32-bit flat address.
+These pointers are used in the 32-bit OS/2.
+:dt.'*'
+:dd.The 'star' pointer type denotes that the data item is a pointer, and
+should assume the pointer type native to the API in which it is used (ie
+a star pointer used in a API16 call would assume the pointer to be far16)
+:edl
+:p
+Declarations come in two forms, and have the following syntax:
+:p
+:ul
+:li.'typedef' <basic type|declared type> [<pointer decl>] <ident> [ArrayDecl];
+:p
+This form declares <ident> to have type
+< basic type | previously declared type>.
+
+.fo off
+:fig place=inline frame=box id=typdef1
+
+typedef unsigned short USHORT;
+
+typedef USHORT MyShort;
+
+typedef USHORT far16 PUSHORT;
+
+typedef USHORT ShortArray[10];
+
+typedef unsigned long near32 P32ULONG;
+
+typedef short *PSHORT;
+
+:figcap Examples of typedef statements
+:efig
+.fo on
+.rc 1 on
+:li.'typedef' [<alignment>] 'struct' <ident1> '{'
+ {< basic type | previously declared type> [<identn>] [deleted [n]]; }
+ '}' <ident2> ';'
+:p
+Declares <ident2> to be a structure type with a list of internal fields.
+Each internal field declaration is must contain a known type. The
+field identifier is optional. The internal field identifier is only used
+by the compiler to generate comments in the assembler file.
+:p
+The <alignment> option declares the structure to be aligned in a predefined
+manner. The alignment option is only valid when the typedef
+declares a structure.
+The syntax of the alignment option is
+:p
+<alignment keyword> [ aligned ]
+:p
+The 'aligned' keyword is optional. Valid alignment keywords are:
+:dl tsize=10.
+:dt.byte
+:dd.Structure fields are byte aligned
+:dt.word
+:dd.Structure fields more than 1 byte in length are word aligned (2 bytes)
+:dt.dword
+:dd.Structure fields are dword aligned (4 bytes). All items greater than
+or equal to 4 bytes in length will be aligned on a 4 byte boundary. All word
+sized data will be word aligned.
+:edl
+:p
+If no alignment keyword is defined, then the compiler will choose alignment
+based on the type of API it is used in. For example, if the alignment is
+undefined, and is being used in a 16-bit API, then the alignment will
+default to being word aligned. Likewise, use in a 32-bit API defaults to
+dword alignment.
+:p
+The deleted keyword can be used to modify a structure element. The deleted
+keyword tells the compiler that this element is a place holder, and doesn't
+actually exist. This is useful when a structure has had elements added to it,
+and needs to map to the old structure.
+.fo off
+:fig place=inline frame=box id=typdef2
+
+typedef unsigned long ULONG;
+
+typedef struct _PIDINFO {
+ unsigned short PID;
+ unsigned short TID;
+ unsigned short PPID;
+ } PIDINFO;
+
+typedef PIDINFO *PPIDINFO; /* A pointer to a PIDINFO */
+
+typedef dword aligned struct _Data1 {
+ unsigned short;
+ char FileName[13];
+ unsigned long LongIdent;
+ dword aligned PIDINFO PidIdent; /* Imbedded structure */
+ } Data1;
+
+typedef word struct _Data2 {
+ ULONG;
+ short;
+ } Data2;
+
+typedef struct _Data3 {
+ string *NameString; /* Imbedded pointer to ASCIIZ */
+ Data2 *StructPointer; /* Imbedded pointer to struct */
+ } Data3;
+
+typedef struct _Data4 {
+ unsigned short US1;
+ unsigned short US2;
+ unsigned long UL1 deleted;
+ unsigned long UL2 deleted 5;
+ unsigned short US3;
+ } Data4;
+
+typedef struct _Data4b {
+ unsigned short US1;
+ unsigned short US2;
+ unsigned long UL1;
+ unsigned long UL2;
+ unsigned short US3;
+ } Data4b;
+
+
+:figcap Examples of structure declarations:
+:efig
+.fo on
+:p
+Note the example structures Data4 and Data4b. These two structures can be
+mapped since they contain compatible elements. However, the compiler will
+assume that the Data4 structure only contains US1,US2, and US3. UL1 and UL2
+are assumed not to exist. Using this construct, we are actually mapping the
+following&gml
+
+.fo off
+:fig place=inline frame=box
+
+
+typedef struct _Data4 {
+ unsigned short US1;
+ unsigned short US2;
+ unsigned short US3;
+ } Data4;
+
+typedef struct _Data4b {
+ unsigned short US1;
+ unsigned short US2;
+ unsigned long UL1;
+ unsigned long UL2;
+ unsigned short US3;
+ } Data4b;
+
+:figcap Effective mapping using the deleted keyword
+:efig
+.fo on
+:p
+When converting from Data4b to Data4, the elements UL1 and UL2 are not copied
+over. Thus, only the US1 US2 and US3 elements are copied into the new
+structure.
+:p
+When converting from Data4 to Data4b, we need to create new values for the
+fields UL1 and UL2, since they didn't exist in Data4. This is where the
+value following the deleted keyword is used. If no value is specified, then
+the compiler will default to using zero as the fill value. Otherwise, the
+compiler will place the value specified into the field.
+:p
+The fill value is only used when creating a new structure. There are two
+cases where the value will used
+.rc 1 off
+:ul
+:li.Structure created on input
+This would be the case where the caller passes in the smaller structure,
+which needs conversion to the larger structure. In the context of the
+above example, the input is Data4, which is then converted to Data4b. In
+this case, UL1 and UL2 would be filled in.
+
+:li.Structure created on output
+This would be the case where the caller passes in the larger structure, and
+expects the API to fill it in. This case is determined when the parameter
+has output only semantics. If the parameter is output only, then no useful
+information is assumed to be in the structure on input. Thus, the API
+must be filling the structure with this information. In this case, the
+thunk will complete the structure by providing the default values.
+
+:eul
+
+
+:p
+The following are examples of structures that are NOT handled
+by the compiler.
+.fo off
+:fig place=inline frame=box
+
+typedef struct _K {
+ string *StrAray[10]; /* Arrays of pointers not supported */
+ } K;
+
+
+typedef struct _D {
+ string *StringPtr; /* This one is ok */
+ } D;
+
+typedef struct _M {
+ D DArray[10]; /* Array of objects with pointers */
+ } M;
+
+:figcap Examples of illegal structure declarations
+:efig
+.fo on
+:eul
+.*
+.pa
+:li.Mappings
+:p
+.fo off
+:fig place=inline frame=box id=mapex1
+
+API16 unsigned short DosSleep(short,short) =
+API32 unsigned long Dos32Sleep(long,long)
+{}
+
+:figcap.A simple mapping statement.
+:efig
+.fo on
+:p
+Mappings define the relationship between two APIs. Information from this
+relationship is used to generate the actual thunk. Mapping statements can
+become quite complex. The best way to explain mappings is by example.
+:p
+:figref refid=mapex1 page=no.
+is a simple form of a mapping. It defines DosSleep to be a 16-bit API,
+which returns an unsigned short, and is passed two shorts as parameters.
+It also defines API32 to be a 32-bit API, which returns an unsigned long,
+and is passed two longs as parameters. The curly braces on the end are
+required, and will be explained later.
+:p
+The basic syntax of a mapping statement is:
+:p
+.fo off
+
+[<api type>] <return type> <ident> ( <param list> ) =
+[<api type>] <return type> <ident> ( <param list> )
+'{' <semantics> '}'
+
+.fo on
+:p
+:dl tsize=15.
+:dt.<api type>
+:dd.Defines which type of API this identifier will be.
+Only two values are accepted.
+:dl tsize=8.
+:dt.API16
+:dd.Defines the API to be a 16-bit API
+:dt.API32
+:dd.Defines the API to be a 32-bit API
+:edl
+This declaration
+is optional. If the <api type> is not declared, then the compiler will
+assume that the first API in the mapping is API16, and the second is API32.
+It is not legal to tag only one of the API's. If you declare one, then you
+must declare the other.
+:dt.<return type>
+:dd.Defines the type returned by the API. This can be any previously
+declared type that maps to a basic data type.
+:dt.<ident>
+:dd.Is a unique identifier. Identifiers must start with a letter, and may
+be followed with any number of letters, digits, or underscores.
+:dt.<param list>
+:dd.Is a list of parameters that are passed to the API. A parameter can be
+modified with the 'deleted' keyword to indicate that the parameter has
+been removed. See examples below for details.
+:dt.<semantics>
+:dd.Is a block contain semantic information about the parameters. Semantic
+blocks are described in a later in this section.
+:edl
+:p
+An example of a parameter list could be:
+:p
+.fo off
+API16 short DosExample(short,char *buf,short len)
+.fo on
+:p
+A few of interesting points here. First is that parameters in a parameter
+list do not require an identifier. The identifier, such as 'buf', are
+optional. They are useful when an API requires a semantic block.
+:p
+The second parameter, 'buf' is a pointer to a char. The '*' declares this
+pointer as being a 16:16 pointer, since it is being declared in a API16
+mapping.The other option would be to declare it
+as a 0:32 pointer, by using the near32 keyword. A pointer keyword must be
+used to declare items as pointers. Also, all structures passed as parameters
+are required to be passed by reference, and therefore must have a pointer
+type as their parameter. For example:
+:p
+.fo off
+typedef struct Killer {
+ short P1;
+ short P2;
+ };
+
+API16 short DosExample(short, Killer far16) =
+API32 long Dos32Example(long, Killer near32)
+{
+}
+
+ or without the declaration of API type or pointer type
+
+short DosExample(short,Killer *) =
+long Dos32Example(long,Killer *)
+{
+}
+
+.fo on
+:p
+In this example, the pointer to structure Killer has been properly defined
+for both API types. They are both prefixed by the pointer type.
+:p
+Each mapping statement may also contain a semantic block which defines
+additional semantic information on the parameters being passed to an API.
+.fo off
+:fig place=inline frame=box
+short DosExample(short,char *buf,short len)=
+long Dos32Example(short,char *buf,short len)
+{
+ buf = output;
+ len = sizeof buf;
+}
+:efig
+.fo on
+:p
+In the above example (DosExample() = Dos32Example) the first line,
+buf = output, defines the
+parameter buf to be an output parameter. This informs the compiler that if
+buf needs to be copied elsewhere in memory during the thunk, that the
+copy may be discarded. For all pointer parameters, if no semantics are
+given to indicate whether the item is input or output, then the compiler
+assumes that the item is input only, and will not copy the structure out.
+:p
+It also defines the parameter 'len' as the length in bytes of buf. Other
+semantic operations are defined below.
+:p
+:dl tsize=35.
+:dt.<ident1> = input;
+:dd.Defines parameter ident1 to be input only.
+:dt.<ident1> = output;
+:dd.Defines parameter ident1 to be output only.
+:dt.<ident1> = inout;
+:dd.Defines parameter ident1 to be both input and output.
+:dt.<ident1> = sizeof <ident2>;
+:dd.Defines parameter ident1 to hold the length of ident2 in bytes.
+:dt.<ident1> = countof <ident2>;
+:dd.Defines parameter ident1 to hold the count of items that ident2 points
+to. The actual size in bytes will be calculated by multiplying ident1 by the
+size of the data type to which ident2 points.
+:dt.stack <api ident> = <number>;
+:dd.This operation defines the minimum amount of stack space required for
+the api given. The minimum stack space value is used to determine when the
+stack may need to be bumped (See the thunk section of the design workbook).
+It is only useful when generating a 32-->16
+thunk. It is normally only used for an API of type API16.
+:dt.inline = [ true | false ];
+:dd.This sets a flag that tells the compiler whether to favor
+execution speed, or code size. Setting it to true will generate only
+inline code, which will result in faster code, but larger size.
+Setting it to false will result in subroutine calls where
+appropriate, thus slower code, and smaller size.
+:dt.<api ident> = conforming;
+:dd.In the 16:16 --> 0:32 thunks, there are times when thunk code must be
+able to deal with ring 2 conforming 0:32 code. The conforming keyword tells
+the compiler that the thunk to be generated should produce a conforming
+compatible thunk.
+.rc 1 on
+:dt.<ident> = allow([value [,value]])
+:dd.If ident is of type long or unsigned long, and is to be truncated to
+a signed/unsigned short value, then the thunk will normally check to
+insure that the value will not be truncated. If the value is outside of
+the range available with the short value, then the thunk will return an error.
+The allow() semantic allows the specified values to pass the truncation check
+without error. The value will be truncated to 16-bits, losing the high word.
+:dt.<ident> = restrict([value [,value]])
+:dd.The restrict semantic will restrict the allowable values for a parameter
+to only the values in the value list. This is useful for restricting a
+parameter to be only 0, or some other default value. If a parameter has a
+value that doesn't appear in the list, then the thunk will return the
+errbadparam code.
+:dt.errbadparam = <numeric>
+:dd.This sets the errbadparam value for this mapping. The value is set for
+the current mapping only.
+:dt.errnomemory = <numeric>
+:dd.This sets the errnomemory value for this mapping. The value is set for
+the current mapping only.
+:dt.errunknown = <numeric>
+:dd.This sets the errunknown value for this mapping. The value is set for
+the current mapping only.
+.rc 1 off
+:edl
+:li.API with different parameter counts
+:p
+
+The thunk compiler requires that two function prototypes have the same
+number of parameters in order to be mapped. However, if you need to add
+or remove parameters from one of the prototypes, then you can use the
+'deleted' keyword for that parameter.
+:p
+For example, DosChDir() has a different number of parameters between its
+32-bit version and its 16-bit version.
+:p
+.fo off
+
+USHORT DosChDir(PSZ pszDirPath,ULONG ulReserved);
+
+ULONG Dos32ChDir(PSZ pszDirPath);
+.fo on
+
+:p
+The thunk compiler will allow a mapping such as:
+:p
+.fo off
+USHORT DosChDir(PSZ pszDirPath,ULONG ulReserved) =
+
+ULONG Dos32ChDir(PSZ pszDirPath,ULONG ulReserved deleted 0 )
+
+{
+}
+.fo on
+
+:p
+
+There are two results of this mapping declaration. In a mapping
+directive of DosChDir => Dos32ChDir, the ulReserved parameter will
+not be pushed the Dos32ChDir stack frame. The effective result is
+only pszDirPath will be passed to the API.
+
+:p
+The other possibility is a mapping directive of Dos32ChDir => DosChDir.
+In this case, a parameter needs to be added to the call frame the
+place of ulReserved. The size of the item pushed is specified in
+the target (DosChDir), and will be a ULONG. The value of the item
+pushed can be specified by the number following the deleted keyword.
+In this case, the value is a ULONG = 0.
+
+:p
+In another example, say that Dos32Beep was modified to play a song
+which is specified by a number. The mapping needs to look like
+
+:p
+.fo off
+DosBeep(USHORT usFrequency,USHORT usDuration) =
+Dos32Beep(ULONG ulFrequency,ULONG ulSongNum,ULONG ulDuration)
+{
+}
+.fo on
+:p
+In the case of DosBeep => Dos32Beep, we need to add a parameter to
+the call. This is done, same as before, with:
+:p
+.fo off
+DosBeep(USHORT usFrequency,USHORT usSongNum deleted 7, USHORT usDuration) =
+Dos32Beep(ULONG ulFrequency,ULONG ulSongNum,ULONG ulDuration)
+{
+}
+.fo on
+:p
+where 'deleted 7' will make the default song to be the theme from
+"The Flintstones".
+:p
+
+
+.****************************************************************
+:li.Map Directives
+:p
+The mapping declarations only defined a relationship between two API. The
+third and final section to the thunk description language simply defines
+which direction thunk should be generated. A mapping directive has the form:
+:p
+<api ident1> => <api ident2>;
+:p
+This will result in a thunk FROM ident1 TO ident2. Mapping directives only
+work on a previously declared mapping. It is not possible to create a
+mapping directive for two API that are not related to each other by a
+mapping declaration. An example of a correct mapping directive is
+.fo off
+:fig frame=box place=inline
+
+DosRead => Dos32Read;
+
+A correctly formed mapping directive
+:efig
+.fo on
+:p
+Assuming that DosRead is a 16:16 API, and Dos32Read is a 0:32 API, then the
+example map directive would produce a 16:16 --> 0:32 thunk.
+
+.****************************
+:li.Compiler Directives
+:ul
+:li.inline
+:p
+Syntax inline = < true | false >;
+:p
+The inline directive changes the current default inline value. The
+inline value determines whether code is generated inline, or whether
+subroutine calls are allowed. The change will only affect the mapping
+statements defined after this statement.
+:li.#include
+:p
+Syntax: #include "filename.ext"
+:p
+The #include directive works much like the 'C' #include preprocessor
+directive. Its sole purpose is to suspend input from the current
+source file, and direct input from an alternate source file. When the
+end of the alternate source file is read, it is closed, and input
+resumes from the original source file.
+:p
+The syntax of the #include statement only allows for filenames to be
+enclosed in double quotes. The #include <filename.ext> form that 'C'
+uses is not defined. The compiler does NOT search any of the include
+paths. If the
+file to be included is not in the current directory, then a full
+pathname will be required.
+The filename may be any legal filename accepted
+by fopen().
+:p
+Includes may nest many levels deep. The only restriction is the number
+of open files per process.
+.**********
+:li.stack
+:p
+Syntax: stack = <n>;
+:p
+The stack directive changes the current default minimum stack size to <n>,
+where <n> is an integer value 0 thru 32767.
+The change will only affect
+the mapping statements defined after this statement.
+.**********
+:li.syscall
+:p
+Syntax: syscall = < true | false >;
+:p
+The syscall keyword is used to control the calling convention assumptions
+made by the caller. The syscall keyword indicates that the 16-bit target
+API follows the BASE calling convention of saving all registers and segment
+registers, with the exception of eAX. If syscall = false, then a 32->16
+thunk will save the contents of ES before calling. If syscall = true, then
+the compiler assumes that the target routine will save es.
+Changing the syscall value will only affect
+the mapping statements defined after this statement.
+:p
+.rc 1 on
+.**********
+:li.errbadparam
+:p
+Syntax: errbadparam = <numeric>;
+:p
+This sets the global default for the errbadparam return code. This code is
+returned whenever the thunk layer determines that a parameter will be
+truncated, or is not allowed by a restrict() semantic. It is also used for
+parameters that are 'sizeof' or 'countof' when the resulting size is greater
+than the API will allow.
+.**********
+:li.errnomemory
+:p
+Syntax: errnomemory = <numeric>;
+:p
+This sets the global default for the errnomemory return code. This code is
+returned whenever the thunk layer cannot allocate memory from its block
+manager.
+.**********
+:li.errunknown
+:p
+Syntax: errunknown= <numeric>;
+:p
+This sets the global default for the errunknown return code. This code is
+returned whenever the thunk layer has an error returned from a subsystem,
+such as Dos32CreateLinearAlias, or Dos32AllocMem. If no errunknown value
+gets set, then the thunk will return the error code from the subsystem.
+.rc 1 off
+.**********
+:li.Comments
+:p
+Syntax: /* <comment text> */
+:p
+Comments in the thunk description language are similar to the 'C'
+programming langauge. A comment block is opened by a '/*' combination,
+and closed by a '*/' combination. Unlike 'C', the thunk language
+will allow nesting of comments.
+:eul
+.pa
+:li.Programmers Guide
+:p
+
+This section will discuss issues related to the writing of thunk
+scripts. It is advised that a programmer read this section BEFORE
+writing complex thunk scripts.
+:p
+:ol
+:li.Numeric Constants
+:p
+The thunk compiler recognizes numeric constants, and constant expressions
+involving operators in the set ( + - * /). All numeric constants are assumed
+to be integer values. Constants are only used in array declarations, and in
+setting the size of the stack.
+.rc 1 on
+:p
+The thunk compiler will also accept hex numbers, if they are specified in
+the standard 'C' format (ie 0xffff).
+.rc 1 off
+:li.Using the 'C' preprocessor with the thunk compiler.
+:p
+One potentially useful trick is to use the C preprocessor on a script
+file, before feeding it to the thunk compiler. This allows the programmer
+to use the standard C # macros, such as #define, #ifdef, #include, etc.
+Using the preprocesser like this is a bit of a hack, but it should work.
+:p
+To do this, run the thunk script through the standard Microsoft C compiler,
+using the /EP switch. This will tell the C compiler to process the input
+file, doing string replaces on all of the #defines, and will handle all
+of the macros. Pipe this output to a temporary file, and then feed this to
+the thunk compiler.
+:p
+For example
+.fo off
+ c:>cl /EP thkfile.thk > temp.thk
+ c:>thunk temp.thk
+.fo on
+
+:li.Data Translations
+:p
+
+The compiler is capable of translating between long and short types. The
+following table shows which translations are supported:
+
+.fo off
+short <-> long
+unsigned short <-> unsigned long
+
+.fo on
+
+:p
+
+Note that it is not possible to translate semantics interpretations of
+the data (ie unsigned to signed). This type of translation is meaningless,
+and the compiler will produce an error message if you attempt this.
+
+:p
+
+The int type is handled slightly differently. The compiler translates the
+int or unsigned int data type into the type that is native to the API in
+which it is used.
+
+.fo off
+
+For 16:16 API
+
+ int -> short
+ unsigned int -> unsigned short
+
+For 0:32 API
+
+ int -> long
+ unsigned int -> unsigned long
+.fo on
+:p
+This allows a value to be used in both API types, and it will be
+converted based on which API it is used in. This is especially
+useful when a typedef is used to declare a type that must be used
+in both worlds, but assumes a different size. For example,
+
+.fo off
+:fig place=inline frame=box
+
+typedef unsigned int BOOL;
+
+BOOL MyExample(BOOL *,string *,short) =
+BOOL MyExample(BOOL *,string *,long)
+{}
+
+is exactly equivalent to saying
+
+unsigned short MyExample(unsigned short *,string *,short) =
+unsigned long MyExample(unsigned long *,string *,long)
+{}
+:efig
+.fo on
+
+:p
+:li.Passing Pointer Parameters
+:p
+
+The thunk compiler will handle the conversion and passing of pointer
+parameters. Pointer parameters can point to any of the predefined
+data types, or to structures. The compiler does not support double
+indirect pointers (pointers to pointers), but there is a workaround for
+this which is describe later.
+
+:p
+If a pointer parameter points to a base data type (short, long, etc),
+then the compiler will handle correct
+
+:p
+
+If a pointer is passed between API, and the data types are exactly the
+same, then the thunk compiler treats the data as a block of bytes, and
+will emit code that does not deal with data types. The code in the 0:32
+--> 16:16 direction checks the block of bytes to determine if
+it crosses a 64k boundary. If it does, then action to correct the problem
+is taken. For example:
+
+.fo off
+:fig place=inline frame=box
+
+typedef struct _K {
+ short ShortVal;
+ char CharVal;
+ } K;
+
+short DosExample(K *ptrK) =
+long Dos32Example(K *ptrK)
+{
+}
+
+Dos32Example => DosExample;
+:efig
+.fo on
+
+:p
+In the above example, the structure K will require no changes in packing,
+since the alignment is the same in both the 32 bit and 16 bit API.
+In this case, the pointer to K can be treated as a pointer to sizeof(K)
+bytes of data. The thunk code for this will check to insure that the
+data buffer does not cross a 64k boundary. If it does, then a copy of the
+data will be made, and the new pointer passed on to the target API. If
+it doesn't cross a 64k boundary, then the original pointer will be
+passed.
+
+:p
+
+If the pointer is to different types (ie SHORT to LONG), or if the
+pointer is to a structure with differences in any of the data types
+(packing or different pointer types), then a new copy of the data is made
+elsewhere in memory, and a pointer to the new copy is passed to the
+target API. For example:
+
+.fo off
+:fig place=inline frame=box
+typedef struct _K {
+ short ShortVal;
+ long LongVal;
+ } K;
+
+short DosExample(K *ptrK) =
+long Dos32Example(K *ptrK)
+{
+}
+
+Dos32Example => DosExample;
+
+
+0:32 16:16
+struct K struct K
++--------+ 0 +--------+ 0
+|ShortVal| |ShortVal|
++--------+ 2 +--------+ 2
+|Padding | |LongVal |
++--------+ 4 +--------+ 4
+|LongVal | | " " |
++--------+ 6 +--------+ 6
+| " " |
++--------+ 8
+:efig
+.fo on
+:p
+In this second example, struct K has different packing and size between
+the API. Here, we must convert K into the form expected by DosExample.
+In the 32 bit version, K is 8 bytes long, with ShortVal starting at
+offset 0, and LongVal at offset 4.
+
+:p
+
+Memory is allocated somewhere (probably the stack on such a small item),
+and the 32 bit version of K is copied field by field into the 16 bit version
+This creates a 16:16 equivalent. The call is then made passing a pointer to
+the new 16:16 copy of K. When the 16 bit call returns, and if the struct
+was declared as an output parameter in the semantic section, the
+16:16 structure K will be copied field by field back into the original.
+In either case, the allocated memory is deallocated, and the routine
+returns.
+
+:p
+
+Another case that is similar to the different packing case is when a
+structure contains an imbedded pointer. For example:
+
+
+.fo off
+:fig place=inline frame=box
+typedef struct _K {
+ short ShortVal;
+ string *StrVal; /** Imbedded Pointer **/
+ } K;
+
+short DosExample(K *ptrK) =
+long Dos32Example(K *ptrK)
+{
+}
+
+Dos32Example => DosExample;
+
+0:32 stack
++-------+
+| |
++-------+
+| | 0:32 K
++-------+ +--------+0
+| *ptrK |-------------> |ShortVal| ASCIIZ
++-------+ +--------+4 +---------------+
+| EIP | |*StrVal |------------->|A|B|C|C|D|E|F|0|
++-------+ +--------+ +---------------+
+| EBP |
++-------+
+:efig
+.fo on
+:p
+
+In this case, the struct K has a pointer to a null terminated string
+imbedded inside. This means that the pointer will have to be changed
+to a new value (0:32 --> 16:16). We make a copy just like the previous
+case, but now we need to deal with the imbedded pointer.
+
+:p
+
+The object that the imbedded pointer points to must also be checked for
+64k crossings. It will be handled exactly like any other buffer that
+potentially crosses a 64k boundary. (ie check for crossing, copy if
+needed).
+
+:p
+
+The call to the 16 bit routine is then made. On return from the 16bit
+call, and if the parameters semantics specify output, then the structure
+is copied back to the original location.
+
+:p
+
+NOTE: The following paragraph is subject to change
+:p
+***************************************************************
+
+There is one very important exception during the
+copy out. The pointer parameter IS NOT copied out. This is done because
+of many problems that could arise if the output pointer changes.
+Structures which contain pointers that are for copy out may need hand
+modifications. The programmer must watch out for side effects, such as
+what happened to the original pointer? Was it aliased? Was its memory
+freed? The current version of the thunk compiler is not equipped to
+handle these questions. There are no problems when the pointer is
+for copy in only.
+
+***************************************************************
+
+:p
+
+:li.The NULLTYPE parameter
+:p
+In those cases where the thunk compiler will not produce correct code,
+either due to very complex semantics, or due to data types not handled,
+it may be useful to have the thunk compiler do as much of the thunk
+as possible, to limit the amount of hand coding needed. This is where
+the basic data type 'nulltype' comes in handy.
+
+:p
+Nulltype parameters are 'place holders'. No code is emited to handle the
+nulltype parameter. The only code emitted is an error message to
+MASM that will cause an error if compiled. This is to insure that the
+programmer goes into the output file and hand modifies that section of
+code with the NULL type.
+
+:p
+Declaring a pointer to a nulltype will result in temporary storage
+being allocated for the nulltype, and some skeleton code that gets
+the pointer from the stack, and checks it for null value. The
+rest of the conversion for this parameter is left to the programmer.
+
+:li.Using semantic operators
+:p
+:ul
+:li.Specifying input/output/inout
+The default semantic value for all parameters is 'input'. This means that
+if no other semantic information is given, the compiler will assume that
+a parameter is input only, and the data item will not be copied out.
+:p
+If a parameter is an output type, such as a read buffer, or a returned
+count, then the parameter must be declared as output in the semantic
+block. For example,
+
+.fo off
+:fig place=inline frame=box
+
+short DosFoo(short Flags, void *Buffer, short len) =
+long Dos32Foo(long Flags, void *Buffer, long len)
+{
+ Buffer = output;
+ len = sizeof Buffer;
+}
+
+:efig
+.fo on
+
+In this example, Buffer is declared to be an output only buffer. It is
+then assumed that the input buffer has no useable information, and that
+it doesn't need to be copied in. This is significant in the case where
+Buffer crosses a 64k boundary, and must be copied elsewhere. When the
+semantics specify only output, a buffer will be allocated in memory,
+but no information will be copied into the new buffer. However, on
+the return from the call, the information from the allocated buffer
+is copied back into the original buffer.
+
+
+:p
+If a parameter is bi-directional, then it will be both copied in and
+copied out. To specify bi-directional parameters, use the 'inout'
+semantic keyword. For example,
+
+.fo off
+:fig place=inline frame=box
+
+short DosFoo(short Flags, void *Buffer, short *len) =
+long Dos32Foo(long Flags, void *Buffer, long *len)
+{
+ Buffer = output;
+ len = sizeof Buffer;
+ len = inout;
+}
+
+:efig
+.fo on
+:p
+In this example, the parameter 'len' may represent the length of the
+buffer pointed to by 'Buffer', and will receive the actual number of
+bytes placed in 'Buffer' by DosFoo. In this case, we need to insure
+that the contents of 'len' are not lost on output.
+:p
+In the special case of 'string' parameters (NULL terminated strings),
+the only valid semantic that can be applied is input. If you attempt
+to assign an output, or inout parameter to a string, then the compiler
+will give you an error message.
+
+:li.Specifying parameter sizes
+:p
+Pointer parameters will assume that the size of the object pointed to is
+the same as the size of the object. For example, a pointer to a long will
+be assumed to be a pointer to a 4 bytes buffer. This can be overridden
+in cases where there is a pointer to a buffer. For example,
+
+.fo off
+:fig place=inline frame=box
+
+short DosFoo(char *Buffer, short len) =
+long Dos32Foo(char *Buffer, long len)
+{
+ Buffer = output;
+ len = sizeof Buffer;
+
+}
+
+:efig
+.fo on
+
+In this example, 'len' has been defined to hold the number of bytes
+pointed to by 'Buffer'. Often, a size parameter holds a count of items
+rather than the size in bytes of the buffer. This is handled by the
+countof semantic. For example,
+
+.fo off
+:fig place=inline frame=box
+
+short DosFoo(long *Buffer, short len) =
+long Dos32Foo(long *Buffer, long len)
+{
+ Buffer = output;
+ len = countof Buffer;
+
+}
+
+:efig
+.fo on
+
+:p
+In this example, 'len' represents the number of longs that 'Buffer' points
+to. The thunk will then calculate the number of bytes in 'Buffer' by
+multiplying len * sizeof(long). In this case, if len = 4, then the compiler
+would deduce that Buffer was 16 bytes long.
+:p
+
+
+
+:eul
+:li.Polymorphic Parameters
+:p
+
+One area that the thunk compiler does not handle is the area of
+polymorphic parameters. These are pointer parameters that assume
+different characteristics based on some key value. For example,
+DosDevIOCtl is a routine which has a polymorphic pointer parameter.
+Based on a flag value passed along with the function, the pointer can be
+pointing to one of at least 50 different structures. In this case, it
+is not feasible for the thunk compiler to generate a thunk to handle
+all cases.
+
+:p
+
+Other forms of polymorphic parameters are more subtle. For example,
+
+.fo off
+:fig place=inline frame=box
+short DosFoo(short Flags, void *Buffer) =
+long Dos32Foo(long Flags, void *Buffer)
+{}
+
+The semantics of this call specify that if Flags == 3, then
+Buffer is to be disregarded.
+:efig
+.fo on
+:p
+In this example, if Flags is 3, then Buffer is an invalid parameter,
+and should not be used. In this case, Buffer assumes different semantics
+based a another value in the parameter list. The thunk compiler doesn't
+know how to handle this case, and the programmer will have to hand
+modify the output code to deal with this.
+:p
+The modifications for polymorphic parameters can range from being
+very simple, or to being very complex. Careful planning is advised,
+as is a very clear understanding of the API.
+
+:li.Structuring of the script files
+:p
+The script language was designed to be crafted in a certain structure,
+to make maintaining the files easy. As a guideline for writing the
+scripts, the following format is suggested.
+
+:p
+Scripts should be divided into three basic sections,
+:ol
+:li.Type definitions (typedefs)
+:p
+Move all of the typedef statements into a single file, which can be
+included into files as needed using the #include directive.
+:li.Mapping declarations
+:p
+Mapping declarations should be grouped according to the .DLL file in
+which they reside. Mapping declarations should be divided into two
+files.
+:p
+:ul
+:li.Thunks which are generated automatically
+:li.Thunks which require any type of hand modification
+:eul
+:p
+Following this guideline, each .DLL file will have two .def files
+associated with it.
+:li.Mapping Directives
+:p
+Mapping Directives should reside in the same file as their associated
+mapping declarations. Mapping directives should be placed at the
+end of the file, so they can easily be modified.
+:eol
+
+:li.Hand coding thunks
+:p
+Some thunks will have to be hand coded. These are thunks which pass
+data types that the compiler cannot handle, have polymorphic parameters,
+or some other feature that the compiler doesn't handle.
+If at all possible, it is suggested that the compiler be used to
+generate a base thunk that can be modified by hand. This should save
+the programmer from doing most of the work, and should speed
+development time.
+
+:li.Using the inline Flag
+:p
+Setting the inline flag to true can increase the speed at which thunk
+code is executed, but it also increases the code size. There is a
+definite time-space tradeoff when using the inline flag. Here are a
+few guidelines to using this flag.
+
+:ul
+:li.Consider the amount of work to be done
+:p
+If an API is known to be slow, such as an API that accesses the disk,
+waits for an event, or does an incredible amount of work such as BitBlit,
+then setting the inline flag may be a moot point. The time saved
+getting through the thunk layer in these cases is very insignificant
+when compared to the execution of the API.
+:li.Consider the frequency of calls
+:p
+If an API is only called once during the run of an application, such
+as DosGetPid, or DosExit, speed probably isn't very important. However,
+if an API is a very frequently called one, such as WinGetMsg, you
+will want to make the thunk as fast as possible. WinGetMsg is a case where
+we definitely want to favor speed over size, since it is usually called
+in a very tight loop.
+:eul
+:p
+For the majority of thunks, we want to favor small size over speed, so
+you should leave the inline flag set to false.
+
+:li.Using the stack flag
+:p
+
+When a thunk in the 0:32 --> 16:16 direction is generated, a check is
+made to determine if the 32 bit APP has enough stack space before the
+next 64k boundary to complete the call. The size considered 'enough'
+for a call can be set using the 'stack' semantic. If an API is known to
+use a great deal of stack space, then the script can modify the amount
+of stack to allow for the particular API. This value is only used in a
+0:32 --> 16:16 thunk, and is based on the amount of space needed by the
+16:16 routine. If the stack size is issued for a 0:32 API, it is
+ignored.
+
+:li.Using the conforming flag
+:p
+The thunk layer needs to know when to deal with conforming code. This
+is code that can be called from either ring 3 or ring 2. The conforming
+keyword is used in 16:16 --> 0:32 direction thunk to enable the
+thunk to call the 0:32 ring 2 conforming code directly. If a routine
+must be conforming, then you must tell the thunk compiler by using
+this statement.
+.rc 1 on
+:li.Value truncation
+:p
+Values that are being converted from a long (32-bit) type to a short
+(16-bit) type are checked for truncation during runtime. If a value is
+too large to fit into a 16-bit type (ie > 0xffff unsigned or outside
+the range -32768 thru 32767), the thunk will return with an error. The
+error code returned is ERROR_INVALID_PARAMETER, or what ever the
+errbadparam value has been set too. To allow certain parameters to
+truncated, see the allow() semantic in the semantic section.
+.rc 1 off
+:li.Subroutine libraries
+:p
+The thunk compiler uses several subroutines in an effort to reduce
+the code size. These subroutines are integral with the code produced
+by the caller, and are not useful for any other purpose.
+:p
+Two of these subroutines, which handle the block allocator for the
+thunk compiler, are located in Doscall1.dll, and are exported API's
+from that .DLL. The calls are THK32ALLOCBLOCK and THK32FREEBLOCK.
+They allocate and deallocate 128 byte blocks. The memory space is
+per process, and the allocation routines are guarded by a simple
+semaphore to insure mutual exclusion between threads.
+:p
+The rest of the library routines are found in thunkrt.lib, which can
+be found in the LIB directory of the build tree. This library contains
+several routines that are needed by the output of the thunk compiler.
+:p
+:eol
+.*************************************************************************
+.pa
+:li.Reference
+:ol
+:li.Thunk description example
+.fo off
+:fig place=inline frame=none
+/*** Example of the thunk description language ***/
+
+typedef unsigned short USHORT;
+typedef unsigned long ULONG;
+typedef unsigned int UINT;
+
+typedef struct _PIDINFO {
+ USHORT PID;
+ USHORT TID;
+ USHORT PPID;
+ } PIDINFO;
+
+typedef PIDINFO *PPIDINFO; /* Define PPIDINFO to be a pointer type */
+
+typedef struct _Example {
+ USHORT P1;
+ char FileName[13]; /* An array of 13 characters imbedded */
+ PIDINFO ExampleStruct; /* A structure can be statically imbedded */
+ /* A pointer to a structure will need hand */
+ /* modifications */
+ } Example;
+
+/** The following defines the mapping between DosBeep and Dos32Beep **/
+/** DosBeep is first in the mapping, and therefore is assumed to be **/
+/** the 16:16 routine. Dos32Beep is second in the **/
+/** Also, the UINT in DosBeep is considered to be an unsigned short **/
+/** while the UINT in Dos32Beep is an unsigned long **/
+
+USHORT DosBeep(USHORT,UINT) =
+ULONG Dos32Beep(ULONG,UINT)
+{}
+
+/** This mapping passes a structure. Note that the structure must **/
+/** be passed by a pointer type. **/
+
+USHORT DosGetPid(PPIDINFO) =
+ULONG Dos32GetPid(PPIDINFO)
+{
+ PPIDINFO = output; /* Define as an output parameter */
+}
+
+/** Note that by using the * to denote pointers, the pointer types are */
+/** implicitly defined based on the API type. */
+
+USHORT DosRead(USHORT,void *buf,USHORT len,USHORT *bytesread) =
+ULONG Dos32Read(ULONG,void *,ULONG,ULONG *)
+{
+ buf = output; /** DosRead's buffer needs to be copied out*/
+ len = sizeof buf; /** len is # of bytes in buf */
+ bytesread = inout; /** bytesread is passed in and out */
+}
+
+
+
+/** Mapping Directives **/
+
+DosBeep => Dos32Beep; /* 16 -> 32 */
+Dos32Read => DosRead; /* 32 -> 16 */
+
+:efig
+.fo on
+:eol
+:eol
+
diff --git a/private/os2/client/thunk/thunkcom/thunkcom.cmd b/private/os2/client/thunk/thunkcom/thunkcom.cmd
new file mode 100644
index 000000000..fde6959af
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/thunkcom.cmd
@@ -0,0 +1,13 @@
+@REM Save PATH & LIB
+@set ALL_PATH=%PATH%
+@set ALL_LIB=%LIB%
+@set LIB=%_NTDRIVE%\NT\PRIVATE\OS2\CLIENT\THUNK\THUNKCOM
+@path .;%PATH%
+@
+nmake thunk
+@REM Restore PATH & LIB
+@set PATH=%ALL_PATH%
+@set LIB=%ALL_LIB%
+@set ALL_PATH=
+@set ALL_LIB=
+
diff --git a/private/os2/client/thunk/thunkcom/types.c b/private/os2/client/thunk/thunkcom/types.c
new file mode 100644
index 000000000..5c3596be1
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/types.c
@@ -0,0 +1,999 @@
+#define SCCSID "@(#)types.c 13.18 90/08/28"
+
+/*
+ * Thunk Compiler - Routines for Dealing with Types.
+ *
+ * This is an OS/2 2.x specific file
+ * Microsoft Confidential
+ *
+ * Copyright (c) Microsoft Corporation 1987, 1988, 1989
+ *
+ * All Rights Reserved
+ *
+ * Written 12/03/88 by Kevin Ross
+ */
+
+
+#include <stdio.h>
+#include "types.h"
+#include "symtab.h"
+#include "thunk.h"
+
+extern FILE *StdDbg;
+
+DESCHANDLE adhStandard[] = {{ "HWND", HANDLE_HWND },
+ { "HICON", HANDLE_HICON },
+ { "HCURSOR", HANDLE_HCURSOR },
+ { "HFONT", HANDLE_HFONT },
+ { "HMENU", HANDLE_HMENU },
+ { "HUSER", HANDLE_HUSER },
+ { NULL, 0 }};
+
+
+/*** typ_MakeTypeNode(BT)
+ *
+ * This function makes a type node by malloc() and filling in
+ * a set of default values.
+ *
+ * Entry: BT holds the value to be placed in iBaseType
+ *
+ * Exit: returns a pointer to the newly created typenode
+ */
+
+TypeNode *typ_MakeTypeNode(int BT)
+
+{
+ TypeNode *temp;
+
+
+ temp = (TypeNode *) malloc(sizeof(TypeNode));
+
+ if (!temp)
+ fatal("MakeTypeNode: Malloc Failure");
+
+ temp->pchIdent = NULL;
+ temp->iBaseType = BT;
+ temp->pchBaseTypeName = NULL;
+
+ temp->iPointerType = 0;
+ temp->iDeleted= 0;
+ temp->iBaseDataSize = 0;
+ temp->iOffset = 0;
+ temp->iTempOffset = 0;
+ temp->fTempAlloc = 0;
+ temp->iAlignment = -1;
+ temp->iArraySize = 1;
+ temp->iStructOffset = 0;
+ temp->fSemantics = SEMANTIC_INPUT;
+ temp->pSizeParam = NULL; /* which param is my size */
+ temp->pParamSizeOf = NULL; /* which param am I the size of */
+ temp->pStructElems = temp->pNextNode = NULL;
+ temp->AllowList = NULL;
+ temp->usSpecial = 0L;
+ temp->flHandleType = 0L;
+
+ return (temp);
+}
+
+
+/*** typ_MakeAllowNode(Val)
+ *
+ * This function makes an allow node by malloc() and filling in
+ * a set of default values.
+ *
+ * Entry: Val holds the value to be placed in ulValue
+ *
+ * Exit: returns a pointer to the newly created allownode
+ */
+
+AllowNode *typ_MakeAllowNode(unsigned long Val)
+
+{
+ AllowNode *temp;
+
+
+ temp = (AllowNode *) malloc(sizeof(AllowNode));
+ if (temp) {
+ temp->Next = NULL;
+ temp->ulValue = Val;
+ } else {
+ fatal("typ_MakeAllowNode: Out of memory");
+ }
+ return temp;
+}
+
+
+/*** typ_CopyTypeNode(N)
+ *
+ * Returns an exact copy of typenode N, except for the following:
+ *
+ * pchIdent is NULL
+ * pNextNode is NULL
+ *
+ * Will also produce copies of any structure elements that may be
+ * involved.
+ *
+ * Entry: N points to typenode to be copied
+ *
+ * Exit: Returns a pointer to a copy of N
+ */
+
+TypeNode *typ_CopyTypeNode(TypeNode *N)
+
+{
+ TypeNode *temp = NULL;
+
+
+ if (!N) return N;
+
+ if (N->iBaseType == TYPE_STRUCT) {
+ temp = (TypeNode *) typ_CopyStructNode(N);
+ } else {
+ temp = (TypeNode *) malloc(sizeof(TypeNode));
+ if (!temp) fatal("CopyTypeNode: Malloc Failure");
+
+ *temp = *N;
+ }
+ temp->pchIdent = NULL;
+ temp->pNextNode = NULL;
+
+ return (temp);
+}
+
+
+/*** typ_CopyStructNode(N)
+ *
+ * This routine will make an additional copy of a structure node.
+ * It will copy all type nodes in the structure tree. The resulting
+ * copy will be identical to the original.
+ *
+ * Entry: N points to typenode to be copied
+ *
+ * Exit: Returns a pointer to a copy of N
+ */
+
+TypeNode *typ_CopyStructNode(TypeNode *pOldNode)
+
+{
+ TypeNode *pNewNode, **ppNewElem, *pOldElem;
+
+
+ if (!pOldNode) return NULL;
+
+ pNewNode = (TypeNode *) malloc(sizeof(TypeNode));
+ if (!pNewNode) fatal("typ_CopyStruct: Malloc Failure");
+
+ *pNewNode = *pOldNode;
+ pOldElem = pNewNode->pStructElems = pOldNode->pStructElems;
+ ppNewElem = &(pNewNode->pStructElems);
+
+ while (pOldElem) {
+ if (pOldElem->iBaseType == TYPE_STRUCT) {
+ *ppNewElem= (TypeNode *) typ_CopyStructNode(pOldElem);
+ } else {
+ *ppNewElem = (TypeNode *) malloc(sizeof(TypeNode));
+ if (!*ppNewElem) fatal("typ_CopyStruct: Malloc Failure");
+ **ppNewElem = *pOldElem;
+ }
+ ppNewElem = &((*ppNewElem)->pNextNode);
+ pOldElem = pOldElem->pNextNode;
+ }
+ return (pNewNode);
+}
+
+
+/*** typ_MakeFunctionNode(CT,RT,Name,PL)
+ *
+ * This function makes a Function node by malloc() and filling in
+ * a set of default values.
+ *
+ * Entry: CT = CallType for function node
+ * RT = Pointer to Return type (Typenode *)
+ * Name = NULL terminated name of function
+ * PL = Pointer to list of parameters
+ *
+ * Exit: Returns pointer to FunctionNode created.
+ */
+
+FunctionNode *typ_MakeFunctionNode(int CT,
+ TypeNode *RT,
+ char *Name,
+ TypeNode *PL)
+
+{
+ register FunctionNode *temp;
+
+
+ temp = (FunctionNode *) malloc(sizeof(FunctionNode));
+ if (!temp) fatal("MakeFunctionNode: Malloc Failure");
+
+ temp->pchFunctionName =typ_DupString(Name);
+ temp->pNextFunctionNode = temp->pMapsToFunction = NULL;
+ temp->ReturnType = RT;
+ temp->iCallType = CT;
+ temp->ParamList = PL;
+ temp->iMinStack = iGlobalStackSize;
+ temp->fInlineCode = fGlobalInline;
+ temp->fConforming = FALSE;
+ temp->fSysCall = fGlobalSysCall;
+ temp->fSemantics = fGlobalTruncation;
+ temp->fInvalidParam = 0;
+ temp->ulErrNoMem = gErrNoMem;
+ temp->ulErrBadParam = gErrBadParam;
+ temp->ulErrUnknown = gErrUnknown;
+ temp->fErrUnknown = gfErrUnknown;
+
+ return (temp);
+}
+
+
+/*** typ_CountParams(T)
+ *
+ * This routine will count the number of items in a TypeNode list
+ *
+ * Entry: T points to Typenode List
+ *
+ * Exit: Returns integer value representing number of TypeNodes
+ * in list.
+ */
+
+int typ_CountParams(TypeNode *T)
+
+{
+ int count = 0;
+
+ while (T) {
+ count++;
+ T = T->pNextNode;
+ }
+ return count;
+}
+
+
+/*** typ_StructsCanMap(T1,T2)
+ *
+ * This function returns true if the compiler can map between structures
+ * T1 and T2. This routine is mutually recursive with TypesCanMap().
+ *
+ * Two structures can map IFF
+ * 1) The have the exact same number of elements
+ * 2) the compiler knows how to map between corresponding elements
+ *
+ * Entry: T1 and T2 hold pointers to structures for comparision
+ *
+ * Exit: Returns 1 if structures can map
+ * Returns 0 if structures cannot map
+ */
+
+int typ_StructsCanMap(TypeNode *T1,
+ TypeNode *T2)
+
+{
+ /*
+ * This only happens when T1 == T2 == NULL.
+ */
+ if (T1 == T2) return 1;
+
+ if (typ_CountParams(T1->pStructElems) != typ_CountParams(T2->pStructElems)) {
+ error("Structures %s and %s have different number of elements",
+ typ_NonNull(T1->pchBaseTypeName),
+ typ_NonNull(T1->pchBaseTypeName));
+ return 0;
+ }
+
+ T1 = T1->pStructElems;
+ T2 = T2->pStructElems;
+
+ while (T1) {
+ if (T1->iDeleted || T2->iDeleted)
+ goto TypeIsDeleted;
+
+ if (!typ_TypesCanMap(T1,T2))
+ return 0;
+
+TypeIsDeleted:
+ T1 = T1->pNextNode;
+ T2 = T2->pNextNode;
+ }
+ return 1;
+}
+
+
+/*** typ_TypesCanMap(T1,T2)
+ *
+ * Determines whether the compiler knows how to map between the two
+ * types T1 and T2.
+ *
+ * Two types can map IFF
+ *
+ * 1) If one is a pointer then so is the other.
+ * 2) They must have the same array size
+ * 3) If structures then the structures must be mappable
+ * 4) The base types are the same or the base types can be converted
+ *
+ * Entry: T1 and T2 point to typenodes to be checked.
+ *
+ * Exit: Return 0 if not mappable
+ * Return 1 if types can map
+ */
+
+int typ_TypesCanMap(TypeNode *T1,
+ TypeNode *T2)
+
+{
+ int ReturnCode = 0;
+
+
+ if (!T1 || !T2)
+ fatal("typ_TypesCanMap(T1,T2) Null Parameter");
+
+ /*
+ * If both types are deleted, then error.
+ */
+ if (T1->iDeleted && T2->iDeleted) {
+ error("both parmeters are flagged deleted");
+ return 0;
+ }
+
+#if 0
+ /*
+ * If one param is deleted, then error if pointer type.
+ */
+ if ((T1->iDeleted || T2->iDeleted) && T1->iPointerType) {
+ error("pointer type marked deleted. Not allowed");
+ return 0;
+ }
+#endif
+
+ /*
+ * If the types are arrays, then they must contain the same number of
+ * elements.
+ */
+ if (T1->iArraySize != T2->iArraySize) {
+ error("Arrays of different sizes");
+ return 0;
+ }
+
+ /*
+ * If either are TYPE_STRUCT then both must be TYPE_STRUCT, and the
+ * structs must be mappable.
+ */
+ if ((T1->iBaseType == TYPE_STRUCT) || (T2->iBaseType == TYPE_STRUCT)) {
+ if (T1->iBaseType == T2->iBaseType) {
+ return typ_StructsCanMap(T1,T2);
+ } else {
+ return 0;
+ }
+ }
+
+ /*
+ * If one is a pointer, then both must be pointers.
+ */
+ if ((T1->iPointerType || T2->iPointerType) &&
+ !(T1->iPointerType && T2->iPointerType)) {
+ error("Must map pointer type to pointer type");
+ return 0;
+ }
+
+ /*
+ * If base types are same, then they map.
+ */
+
+ if (T1->iBaseType == T2->iBaseType) {
+ return 1;
+ }
+
+ /*
+ * The only type left must be a base type.
+ * There are only three pairs that can be converted between each other:
+ * USHORT <=> ULONG, SHORT <=> LONG and UCHAR => ULONG
+ * If the combination is different than this, then the types cannot map.
+ */
+ ReturnCode = 0;
+
+ switch(T1->iBaseType) {
+ case TYPE_UCHAR:
+ if (T2->iBaseType == TYPE_ULONG)
+ ReturnCode = 1;
+ else
+ ReturnCode = 0;
+ break;
+ case TYPE_USHORT:
+ if (T2->iBaseType == TYPE_ULONG)
+ ReturnCode = 1;
+ else
+ ReturnCode = 0;
+ break;
+ case TYPE_SHORT:
+ if (T2->iBaseType == TYPE_LONG)
+ ReturnCode = 1;
+ else
+ ReturnCode = 0;
+ break;
+ case TYPE_ULONG:
+ if (T2->iBaseType == TYPE_USHORT)
+ ReturnCode = 1;
+ else
+ ReturnCode = 0;
+ break;
+ case TYPE_LONG:
+ if (T2->iBaseType == TYPE_SHORT)
+ ReturnCode = 1;
+ else
+ ReturnCode = 0;
+ break;
+ }
+ if (! ReturnCode)
+ error("%s does not map to %s",typ_NonNull(T1->pchBaseTypeName),
+ typ_NonNull(T2->pchBaseTypeName));
+ return (ReturnCode);
+}
+
+
+/*** typ_FunctionsCanMap(F1,F2)
+ *
+ * A pair of functions can map IFF the following are true:
+ * 1) The Call types are different
+ * 2) The return types can be mapped
+ * 3) The two API have the same count of parameters
+ * 4) Each parameter has a direct mapping to the other API
+ *
+ * Entry: F1 and F2 are the pointers to the FNodes
+ *
+ * Exit: Return 0 - failure
+ * Return 1 - success
+ */
+
+int typ_FunctionsCanMap(FunctionNode *F1,
+ FunctionNode *F2)
+
+{
+ int ParamCount = 0;
+ int rc = 1;
+ TypeNode *T1,*T2;
+
+
+ if (!F1 || !F2)
+ fatal("typ_FunctionsCanMap(F1,F2) Null Parameter");
+
+ if ( F1->iCallType == F2->iCallType) {
+ error("%s is the same API type as %s",
+ F1->pchFunctionName,F2->pchFunctionName);
+ rc=0;
+ }
+
+ /*
+ * Check to see if the return types are mappable. First, make sure that
+ * any default types are converted to the correct type.
+ */
+
+ typ_CheckDefaultTypes(F1->ReturnType,F2->ReturnType,
+ F1->iCallType,F2->iCallType);
+
+ if (! typ_TypesCanMap(F1->ReturnType,F2->ReturnType)) {
+ error("Cannot map %s return type to %s return type",
+ F1->pchFunctionName,F2->pchFunctionName);
+ rc=0;
+ }
+
+ /*
+ * Check to see that both functions have the same number of parameters.
+ */
+ if (typ_CountParams(F1->ParamList) != typ_CountParams(F2->ParamList)) {
+ error(" %s has different parameter count than %s ",
+ F1->pchFunctionName,F2->pchFunctionName);
+ return 0;
+ }
+
+ T1 = F1->ParamList;
+ T2 = F2->ParamList;
+
+ /*
+ * Check all default types in the parameter lists.
+ */
+ typ_CheckDefaultTypes(T1,T2,F1->iCallType,F2->iCallType);
+
+ /*
+ * For each parameter in both lists, insure that the parameters can map
+ * to eachother.
+ */
+ while (T1) {
+ ParamCount++;
+
+ if (! typ_TypesCanMap(T1,T2)) {
+ error("Cannot map %s to %s due to parameter %d %s",
+ F1->pchFunctionName,F2->pchFunctionName,ParamCount,
+ typ_NonNull(T1->pchIdent));
+ rc=0;
+ }
+
+#if 0
+ /*
+ * Children of formal parameters must inherit the semantic
+ * attributes of the formal parameter.
+ */
+ if (T1->iBaseType == TYPE_STRUCT)
+ typ_InheritSemantics(T1->pStructElems,T2->pStructElems,
+ T1->fSemantics);
+#endif
+
+ T1 = T1->pNextNode;
+ T2 = T2->pNextNode;
+ }
+ return rc;
+}
+
+
+/*** typ_CheckDefaultTypes(T1,T2,CT1,CT2)
+ *
+ * This function will traverse the typenode lists T1 and T2, insuring
+ * that any node delcared as iPointerType == TYPE_PTR is assigned
+ * the default pointer type based on the call type (CT1 or CT2).
+ * It will also ensure that any type declared as 'int' or 'unsigned int'
+ * will be converted to the appropriate data size for the API.
+ * This routine will recursively check structures for the same
+ * conditions.
+ *
+ * Entry: T1 & T2 are the two lists of TypeNodes to be checked.
+ * CT1 & CT2 are the calltypes associated with T1 and T2
+ * respectively
+ *
+ * Exit: All nodes in T1 and T2 will have iPointer set to
+ * a value in the set ( 0 , TYPE_FAR16, TYPE_NEAR32)
+ *
+ * All nodes in T1 and T2 of type 'int' or 'unsigned int' will
+ * have been converted to a value in the set (short, unsigned
+ * short, long, unsigned long)
+ */
+
+void typ_CheckDefaultTypes(TypeNode *T1,
+ TypeNode *T2,
+ int CT1,
+ int CT2)
+
+{
+ for( ; T1 && T2; T1 = T1->pNextNode, T2 = T2->pNextNode) {
+ if (T1->iPointerType == TYPE_PTR)
+ T1->iPointerType = (CT1 == TYPE_API16) ? TYPE_FAR16 : TYPE_NEAR32;
+
+ if (T2->iPointerType == TYPE_PTR)
+ T2->iPointerType = (CT2 == TYPE_API16) ? TYPE_FAR16 : TYPE_NEAR32;
+
+ if ((T1->iBaseType == TYPE_STRUCT) && (T2->iBaseType == TYPE_STRUCT))
+ typ_CheckDefaultTypes(T1->pStructElems,T2->pStructElems,CT1,CT2);
+
+ typ_CheckIntType(T1,CT1);
+ typ_CheckIntType(T2,CT2);
+ }
+}
+
+
+/*** typ_CheckIntType(T1,CT1)
+ *
+ * This routine will check typenode T1 for type INT or UINT. If either
+ * case is found, then the size and type of T1 is changed to the
+ * appropriate value based on the table:
+ *
+ * T1 type CT1 Call Type
+ * API16 API32
+ * ----------------------------------
+ * INT SHORT LONG
+ * UINT USHORT ULONG
+ * ----------------------------------
+ *
+ * All other types are left unchanged
+ */
+
+void typ_CheckIntType(TypeNode *T1, int CT1)
+
+{
+ if (!T1)
+ fatal("typ_CheckIntType(T1,CT1) Null Parameter");
+
+ switch(T1->iBaseType) {
+ case TYPE_INT:
+ switch(CT1) {
+ case TYPE_API16:
+ T1->iBaseType = TYPE_SHORT;
+ T1->iBaseDataSize = BaseTable[SYMTAB_SHORT]->iBaseDataSize;
+ T1->pchBaseTypeName =
+ BaseTable[SYMTAB_SHORT]->pchBaseTypeName;
+ break;
+ case TYPE_API32:
+ T1->iBaseType = TYPE_LONG;
+ T1->iBaseDataSize = BaseTable[SYMTAB_LONG]->iBaseDataSize;
+ T1->pchBaseTypeName =
+ BaseTable[SYMTAB_LONG]->pchBaseTypeName;
+ break;
+ default:
+ fatal("CheckIntType: Bad CT1 value");
+ }
+ break;
+ case TYPE_UINT:
+ switch(CT1) {
+ case TYPE_API16:
+ T1->iBaseType = TYPE_USHORT;
+ T1->iBaseDataSize = BaseTable[SYMTAB_USHORT]->iBaseDataSize;
+ T1->pchBaseTypeName =
+ BaseTable[SYMTAB_USHORT]->pchBaseTypeName;
+ break;
+ case TYPE_API32:
+ T1->iBaseType = TYPE_ULONG;
+ T1->iBaseDataSize = BaseTable[SYMTAB_LONG]->iBaseDataSize;
+ T1->pchBaseTypeName =
+ BaseTable[SYMTAB_ULONG]->pchBaseTypeName;
+ break;
+ default:
+ fatal("CheckIntTypes: Bad CT1 value");
+ }
+ }
+}
+
+
+/*** typ_TypesIdentical(T1,T2)
+ *
+ * This routine will check two type lists, T1 and T2, and determine if
+ * they are functionally identical, as defined in the TypeIdentical test
+ * below. This routine is intended to be used on two structures to
+ * determine whether they are identical.
+ *
+ * Entry: T1/T2 Types to compare. Assumed that the two types have
+ * already passed the 'TypesCanMap test'
+ *
+ * Exit: Return 1 - IFF types are functionally identical
+ * Return 0 - IFF types are not functionaly indentical
+ */
+
+int typ_TypesIdentical(TypeNode *T1,
+ TypeNode *T2)
+
+{
+ while (T1 && T2) {
+ if (!typ_TypeIdentical(T1,T2))
+ return 0;
+
+ T1 = T1->pNextNode;
+ T2 = T2->pNextNode;
+ }
+
+ /*
+ * If this point is reached, then all fields have been the same.
+ * Return 1.
+ */
+ return 1;
+}
+
+
+/*** typ_TypeIdentical(T1,T2)
+ *
+ * This routine will check two type nodes, T1 and T2, and determine if
+ * they are functionally identical. Two types are functionally identical
+ * if they have the same types, and the same structure offsets. If this
+ * is the case, then T1 needs no translation to be passed as T2.
+ *
+ * Entry: T1/T2 Types to compare. Assumed that the two types have
+ * already passed the 'TypesCanMap test'
+ * Exit: Return 1 - IFF types are functionally identical
+ * Return 0 - IFF types are not functionaly indentical
+ */
+
+int typ_TypeIdentical(TypeNode *T1,
+ TypeNode *T2)
+
+{
+ if (!T1 || !T2)
+ fatal("typ_TypeIdentical(T1,T2) Null Parameter");
+
+ if (T1->iArraySize != T2->iArraySize)
+ return 0;
+
+ if (T1->iBaseType == TYPE_STRUCT) {
+ if (! typ_TypesIdentical(T1->pStructElems,T2->pStructElems))
+ return 0;
+ } else {
+ if ((T1->iBaseType != T2->iBaseType) ||
+ (T1->iStructOffset != T2->iStructOffset))
+ return 0;
+ }
+ return 1;
+}
+
+
+/*** typ_CheckSemantics(T1,T2)
+ *
+ * This function will traverse the typenode lists T1 and T2, ensuring
+ * that the semantics for these parameter lists make sense.
+ *
+ * Entry: T1 & T2 are the two lists of TypeNodes to be checked.
+ *
+ * Exit: Return 0 - semantics okay
+ * Return > 0 - error
+ */
+
+int typ_CheckSemantics(TypeNode *T1,
+ TypeNode *T2)
+
+{
+ int rcode = 0;
+
+
+ /*
+ * Children of formal parameters must inherit the semantic attributes of
+ * the formal parameter.
+ */
+ while (T1) {
+ if (T1->iBaseType == TYPE_STRUCT)
+ typ_InheritSemantics(T1->pStructElems,T2->pStructElems,
+ T1->fSemantics);
+
+ /*
+ * Check for restrictions.
+ */
+ if (typ_CheckRestrict(T1,T2)) {
+ error("Restricted parameter (%s) without allow list.",
+ typ_NonNull(T1->pchIdent));
+ rcode++;
+ }
+
+
+ T1 = T1->pNextNode;
+ T2 = T2->pNextNode;
+ }
+ return (rcode);
+}
+
+
+/*** typ_CheckRestrict(T1,T2)
+ *
+ * This function will check the restrictions for the given type nodes.
+ *
+ * Entry: T1 & T2 are the two lists of TypeNodes.
+ *
+ * Exit: Return restrictions
+ */
+
+int typ_CheckRestrict(TypeNode *T1,
+ TypeNode *T2)
+
+{
+ return ( (T1->fSemantics & SEMANTIC_RESTRICT) && (T1->AllowList == NULL) );
+}
+
+
+/*** typ_InheritSemantics(T1,T2,fSems)
+ *
+ * This function will traverse the typenode lists T1 and T2, ensuring
+ * that any node that is a child of T1 or T2 receives the
+ * semantics of T1 or T2.
+ *
+ * Entry: T1 & T2 are the two lists of TypeNodes to be checked.
+ * fSems is the set of semantics to be inherited.
+ *
+ * Exit: All nodes in T1 and T2 will have fSemantics set to
+ * the value in fSem.
+ */
+
+void typ_InheritSemantics(TypeNode *T1,
+ TypeNode *T2,
+ int fSems)
+
+{
+ for( ; T1 && T2; T1 = T1->pNextNode, T2 = T2->pNextNode) {
+ T1->fSemantics = T2->fSemantics = fSems;
+
+ if ((T1->iBaseType == TYPE_STRUCT) && (T2->iBaseType == TYPE_STRUCT))
+ typ_InheritSemantics(T1->pStructElems,T2->pStructElems,fSems);
+ }
+}
+
+
+/*** typ_QuerySemanticsUsed( pmn, fSems)
+ *
+ * This function traverses the typenodes in a mapnode and returns
+ * TRUE iff some typenode uses all of the ON semantics in fSems.
+ *
+ * BUGBUG: This routine does not check within structs !!!!!!!!!!!
+ *
+ *
+ * Entry: pmn = the mapnode to be evaluated
+ * fSems = the semantics to be matched
+ *
+ * Exit: TRUE iff some typenode uses all of the ON semantics in fSems
+ *
+ */
+
+BOOL typ_QuerySemanticsUsed( PMAPNODE pmn,
+ int fSems)
+
+{
+ PTYPENODE ptnFrom, ptnTo;
+
+ if( ((pmn->pFromNode->ReturnType->fSemantics & fSems) == fSems) ||
+ (( pmn->pToNode->ReturnType->fSemantics & fSems) == fSems))
+ return TRUE;
+
+ for( ptnFrom = pmn->pFromNode->ParamList, ptnTo = pmn->pToNode->ParamList;
+ ptnFrom && ptnTo;
+ ptnFrom = ptnFrom->pNextNode, ptnTo = ptnTo->pNextNode)
+ if( ((ptnFrom->fSemantics & fSems) == fSems) ||
+ (( ptnTo->fSemantics & fSems) == fSems))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+/*** typ_StructHasPointers(T1,T2)
+ *
+ * This function will traverse the typenode lists T1 and T2, checking
+ * to see if any of the structure parameters have pointers.
+ *
+ * Entry: T1 & T2 are the two lists of TypeNodes.
+ *
+ * Exit: Return 0 - IFF structure has NO pointers.
+ * Return 1 - IFF structure HAS pointers.
+ */
+
+typ_StructHasPointers(TypeNode *T1,
+ TypeNode *T2)
+
+{
+ while (T1) {
+ if (T1->iPointerType)
+ return 1;
+ if (T1->iBaseType == TYPE_STRUCT &&
+ typ_StructHasPointers(T1->pStructElems,T2->pStructElems))
+ return 1;
+
+ T1=T1->pNextNode;
+ T2=T2->pNextNode;
+ }
+ return (0);
+}
+
+
+/*** typ_FindFirstPointer( ptn, fSkipDeleted)
+ *
+ * This function traverses the typenode list and returns the first
+ * typenode which is of pointer type.
+ *
+ *
+ * Entry: ptn = the typenode to be evaluated
+ * fSkipDeleted = skip deleted nodes
+ *
+ *
+ * Exit: the first pointer typenode found or NULL if none
+ *
+ */
+
+PTYPENODE typ_FindFirstPointer( PTYPENODE ptn, BOOL fSkipDeleted)
+{
+ for( ; ptn; ptn = ptn->pNextNode) {
+ if( ptn->iPointerType && !(fSkipDeleted && ptn->iDeleted))
+ break;
+ }
+ return ptn;
+}
+
+
+/*** typ_FindNextPointer( ptn, fSkipDeleted)
+ *
+ * This function traverses the typenode list and returns the next
+ * typenode which is of pointer type.
+ *
+ *
+ * Entry: ptn = the typenode to be evaluated
+ * fSkipDeleted = skip deleted nodes
+ *
+ * Exit: the next pointer typenode found or NULL if none
+ *
+ */
+
+PTYPENODE typ_FindNextPointer( PTYPENODE ptn, BOOL fSkipDeleted)
+{
+ return typ_FindFirstPointer( ptn->pNextNode, fSkipDeleted);
+}
+
+
+/*** typ_EvalHandleType( ptn)
+ *
+ * This function searches the list of standard type names for the
+ * name of the type being declared. If found, the handle type flag
+ * is marked in the type node. Linear search since there are only
+ * a few special handle types.
+ *
+ *
+ * Entry: ptn = the typenode to be evaluated
+ *
+ * Exit: flag set if search successful
+ *
+ */
+
+void typ_EvalHandleType( PTYPENODE ptn)
+{
+ PDESCHANDLE pdh;
+
+ for( pdh = adhStandard; pdh->pszName; pdh++)
+ if( !strcmp( pdh->pszName, ptn->pchIdent))
+ ptn->flHandleType = pdh->flHandleType;
+}
+
+
+/*** typ_GetHandleTypeName( flHandleType)
+ *
+ * This function searches the list of standard type names for the
+ * name of the type passed in. Linear search since there are only
+ * a few special handle types.
+ *
+ *
+ * Entry: flHandleType - type sought
+ *
+ * Exit: retval - name of the type
+ *
+ */
+
+PSZ typ_GetHandleTypeName( ULONG flHandleType)
+{
+ PDESCHANDLE pdh;
+
+ for( pdh = adhStandard; pdh->pszName; pdh++)
+ if( pdh->flHandleType == flHandleType)
+ return pdh->pszName;
+ return NULL;
+}
+
+/*******************************************************************************
+ * typ_ByteToByte()
+ *
+ * This routine will check if a struct elem maps a BYTE to a BYTE
+ *
+ * Entry:
+ *
+ * Exit:
+ *
+ * PCode:
+ *
+ * History:
+ * 19mar91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+BOOL typ_ByteToByte( PTYPENODE ptnFrom, PTYPENODE ptnTo)
+{
+ if( !ptnFrom || !ptnTo)
+ return FALSE;
+
+ return( !ptnFrom->iPointerType &&
+ (ptnFrom->iArraySize <= 1) &&
+ (ptnFrom->iBaseType == ptnTo->iBaseType) &&
+ ((ptnFrom->iBaseType == TYPE_CHAR) ||
+ (ptnFrom->iBaseType == TYPE_UCHAR)));
+}
+
+/*******************************************************************************
+ * typ_WordToWord()
+ *
+ * This routine will check if a struct elem maps a WORD to a WORD
+ *
+ * Entry:
+ *
+ * Exit:
+ *
+ * PCode:
+ *
+ * History:
+ * 19mar91 KevinR wrote it
+ *
+ ******************************************************************************/
+
+BOOL typ_WordToWord( PTYPENODE ptnFrom, PTYPENODE ptnTo)
+{
+ if( !ptnFrom || !ptnTo)
+ return FALSE;
+
+ return( !ptnFrom->iPointerType &&
+ (ptnFrom->iArraySize <= 1) &&
+ (ptnFrom->iBaseType == ptnTo->iBaseType) &&
+ ((ptnFrom->iBaseType == TYPE_SHORT) ||
+ (ptnFrom->iBaseType == TYPE_USHORT)));
+}
diff --git a/private/os2/client/thunk/thunkcom/types.h b/private/os2/client/thunk/thunkcom/types.h
new file mode 100644
index 000000000..b6e3d3a89
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/types.h
@@ -0,0 +1,250 @@
+/*
+ * Thunk Compiler Type Declarations
+ *
+ * Written 12/03/88 by Kevin Ross
+ * Copyright (c) 1988-1991 Microsoft Corp. All rights reserved.
+ *
+ * 10.01.90 KevinR adapted to Win32
+ */
+
+
+
+/*
+ * Define types known to compiler.
+ */
+#define TYPE_SHORT 2
+#define TYPE_LONG 3
+#define TYPE_USHORT 5
+#define TYPE_ULONG 6
+
+#define TYPE_CONV 20 /* All types below this one are convertible */
+ /* between one another */
+#define TYPE_UCHAR 24
+#define TYPE_CHAR 25
+#define TYPE_VOID 26
+
+#define TYPE_SIMPLE 39 /* Previous types are 'simple', in which they */
+ /* are the same in both 32 and 16 bit worlds */
+
+#define TYPE_INT 40 /* Ints must be converted to a long or short */
+#define TYPE_UINT 41 /* based on which API type they are used in */
+
+#define TYPE_STRING 52
+#define TYPE_STRUCT 53
+
+#define TYPE_NULLTYPE 54 /* A NULL type will always produce an .err */
+
+#define TYPE_FAR16 100
+#define TYPE_NEAR32 101
+#define TYPE_PTR 102
+
+#define TYPE_API16 200
+#define TYPE_API32 201
+
+#define TYPE_DELETED 999 /* Marks parameter as deleted */
+
+
+#define SEMANTIC_INPUT 0x0001
+#define SEMANTIC_OUTPUT 0x0002
+#define SEMANTIC_INOUT 0x0003
+#define SEMANTIC_SIZE 0x0004
+#define SEMANTIC_COUNT 0x0008
+#define SEMANTIC_RESTRICT 0x0010
+#define SEMANTIC_PASSIFHINULL 0x0020
+#define SEMANTIC_LOCALHEAP 0x0040
+#define SEMANTIC_TRUNC 0x0100
+#define SEMANTIC_MAPTORETVAL 0x0200
+#define SEMANTIC_REVERSERC 0x0400
+#define SEMANTIC_SPECIAL 0x0800
+
+/*
+ * These flags are used internally by the code generator.
+ */
+#define ALLOC_STACK 0x0001
+#define ALLOC_BMP 0x0002
+#define ALLOC_ALIAS 0x0004
+#define ALLOC_MEMORY 0x0008
+#define ALLOC_FIXED 0x0100 /* Always allocates same size data */
+
+#define ALLOC_ALL ALLOC_STACK|ALLOC_BMP|ALLOC_ALIAS|ALLOC_MEMORY
+
+
+/*
+ * Left overs from the original compiler (a MACH stub generator).
+ */
+#ifndef TRUE
+#define TRUE ((boolean_t) 1)
+#endif
+
+#ifndef FALSE
+#define FALSE ((boolean_t) 0)
+#endif
+
+typedef unsigned int u_int;
+typedef int boolean_t;
+
+typedef unsigned short BOOL;
+typedef unsigned short USHORT;
+typedef short SHORT;
+typedef unsigned long ULONG;
+typedef long LONG;
+typedef char CHAR;
+typedef unsigned char UCHAR;
+typedef unsigned char BYTE;
+typedef unsigned int UINT;
+typedef int INT;
+typedef CHAR *PCH;
+typedef PCH PSZ;
+
+
+/*
+ * flag values for special handle types
+ */
+
+#define HANDLE_HWND 0x00000001
+#define HANDLE_HICON 0x00000002
+#define HANDLE_HCURSOR 0x00000004
+#define HANDLE_HFONT 0x00000008
+#define HANDLE_HMENU 0x00000010
+#define HANDLE_HUSER 0x00000020
+
+typedef struct _DESCHANDLE { /* dh */
+ PSZ pszName;
+ ULONG flHandleType;
+} DESCHANDLE;
+typedef DESCHANDLE *PDESCHANDLE; /* pdh */
+
+
+/*
+ * Allow nodes are used to create a list of values that may be truncated
+ * when converting from a long value to a short value.
+ */
+typedef struct _AllowNode {
+
+ unsigned long ulValue;
+ struct _AllowNode *Next;
+
+} AllowNode;
+
+
+/*
+ * Type nodes are used in two places. First is the type table, where
+ * types defined by a typedef statement are stored. Second is in the
+ * formal parameter lists.
+ *
+ * TypeNodes that are defined as TYPE_STRUCT use the pStructElems field to
+ * point to a linked list of elements, which are themselves typenodes.
+ * The resulting structure looks like
+ *
+ * +------------+
+ * |TypeNode |
+ * |------------|
+ * |TYPE_STRUCT | Element 1 Element 2
+ * |------------| +-----------+ +------------+
+ * |pStructElems|--------->|TypeNode | +---->|TypeNode |
+ * +------------+ |-----------| | +------------+
+ * |pNextNode |-------+ |pNextNode |---...
+ * +-----------+ +------------+
+ */
+typedef struct _TypeNode {
+
+ char *pchIdent; /* Identifier */
+ char *pchBaseTypeName; /* Name of base type */
+ int iBaseType;
+ int iOffset; /* Formal parameter offset */
+ int iTempOffset; /* Temporary storage offset */
+ int iStructOffset; /* Offset within structure */
+ int fSemantics; /* Specify semantics for parameter */
+ int iAlignment; /* Alignment when iBaseType == STRUCT */
+ long iFillValue; /* Value pushed when parameter deleted */
+
+ unsigned int fTempAlloc; /* Possible Allocation Methods */
+ unsigned int iBaseDataSize;
+ unsigned int iArraySize; /* Non arrays == 1 */
+ unsigned int iPointerType; /* Non pointers == 0 */
+ unsigned int iPointerNumber;
+ unsigned int iDeleted; /* Deleted parameter? */
+
+ USHORT usSpecial; /* id for special code generation */
+ ULONG flHandleType; /* special handle flag */
+
+ struct _TypeNode *pNextNode,
+ *pStructElems,
+ *pSizeParam, /* Semantic Information */
+ *pParamSizeOf;
+
+ AllowNode *AllowList;
+
+} TypeNode;
+typedef TypeNode TYPENODE; /* tn */
+typedef TYPENODE *PTYPENODE; /* ptn */
+
+
+
+/*
+ * FunctionNodes are used to form Mapping Declarations.
+ *
+ * A function node contains all the information needed to generate code
+ * for a thunk that uses this function. It includes the API calltype,
+ * lists of parameters, the return type, and other semantic information.
+ */
+typedef struct _Fnode {
+
+ char *pchFunctionName;
+ int iCallType;
+ TypeNode *ParamList;
+ TypeNode *ReturnType;
+
+ unsigned int iPointerCount; /* Number of pointers in parameter list */
+ unsigned int iMinStack; /* Minimum Stack Size */
+ unsigned int fInlineCode; /* Semantics: TRUE = inline */
+ unsigned int fConforming;
+ unsigned int fSemantics; /* Other semantic flags */
+ unsigned int fSysCall; /* Flags the calling convention */
+ unsigned int fErrUnknown;
+ unsigned int fInvalidParam; /* Invalid Parameter code is used */
+ unsigned long ulErrNoMem;
+ unsigned long ulErrBadParam;
+ unsigned long ulErrUnknown;
+
+ struct _Fnode *pNextFunctionNode,
+ *pMapsToFunction;
+
+} FunctionNode;
+typedef FunctionNode FUNCTIONNODE; /* fnn */
+typedef FUNCTIONNODE *PFUNCTIONNODE; /* pfnn */
+
+
+/*
+ * Map nodes record mapping directives, and are passed to the code
+ * generator for code generation.
+ *
+ * As an example, if a mapping directive was DosFoo => DosFoo32, then
+ * the corresponding MapNode would have:
+ *
+ * pFromName = "DosFoo"
+ * pFromNode = &<DosFoo's Function Node>
+ * pToNode = &<DosFoo32's Function Node>
+ */
+typedef struct _MapNode {
+
+ char *pFromName;
+ FunctionNode *pFromNode,*pToNode;
+ struct _MapNode *pNextMapping,*pFamily;
+
+} MapNode;
+typedef MapNode MAPNODE; /* mn */
+typedef MAPNODE *PMAPNODE; /* pmn */
+
+
+extern FunctionNode *typ_MakeFunctionNode();
+extern TypeNode *typ_MakeTypeNode();
+extern TypeNode *typ_CopyTypeNode();
+extern TypeNode *typ_CopyStructNode();
+extern int typ_CheckSemantics();
+extern AllowNode *typ_MakeAllowNode();
+
+
+#define typ_NonNull(x) (x)?x:""
+#define typ_DupString(N) (char *)strcpy((char *)malloc(strlen(N)+2), N);
+#define typ_FullSize(x) x->iBaseDataSize * x->iArraySize
diff --git a/private/os2/client/thunk/thunkcom/yacc/yypars.c b/private/os2/client/thunk/thunkcom/yacc/yypars.c
new file mode 100644
index 000000000..02c75e610
--- /dev/null
+++ b/private/os2/client/thunk/thunkcom/yacc/yypars.c
@@ -0,0 +1,258 @@
+/* SCCSWHAT( "@(#)yypars.c 3.1 88/11/16 22:00:49 " ) */
+#line 3 "yypars.c"
+# define YYFLAG -1000
+# define YYERROR goto yyerrlab
+# define YYACCEPT return(0)
+# define YYABORT return(1)
+
+#ifdef YYDEBUG /* RRR - 10/9/85 */
+#define yyprintf(a, b, c, d) printf(a, b, c, d)
+#else
+#define yyprintf(a, b, c, d)
+#endif
+
+#ifndef YYPRINT
+#define YYPRINT printf
+#endif
+
+/* parser for yacc output */
+
+#ifdef YYDEBUG
+YYSTATIC int yydebug = 0; /* 1 for debugging */
+#endif
+YYSTATIC YYSTYPE yyv[YYMAXDEPTH]; /* where the values are stored */
+YYSTATIC short yys[YYMAXDEPTH]; /* the parse stack */
+YYSTATIC int yychar = -1; /* current input token number */
+YYSTATIC int yynerrs = 0; /* number of errors */
+YYSTATIC short yyerrflag = 0; /* error recovery flag */
+
+#ifdef YYRECOVER
+/*
+** yyscpy : copy f onto t and return a ptr to the null terminator at the
+** end of t.
+*/
+YYSTATIC char *yyscpy(t,f)
+ register char *t, *f;
+ {
+ while(*t = *f++)
+ t++;
+ return(t); /* ptr to the null char */
+ }
+#endif
+
+#ifndef YYNEAR
+#define YYNEAR
+#endif
+#ifndef YYPASCAL
+#define YYPASCAL
+#endif
+#ifndef YYLOCAL
+#define YYLOCAL
+#endif
+#if ! defined YYPARSER
+#define YYPARSER yyparse
+#endif
+#if ! defined YYLEX
+#define YYLEX yylex
+#endif
+
+YYLOCAL YYNEAR YYPASCAL YYPARSER()
+{
+ register short yyn;
+ short yystate, *yyps;
+ YYSTYPE *yypv;
+ short yyj, yym;
+
+ yystate = 0;
+ yychar = -1;
+ yynerrs = 0;
+ yyerrflag = 0;
+ yyps= &yys[-1];
+ yypv= &yyv[-1];
+
+ yystack: /* put a state and value onto the stack */
+
+ yyprintf( "state %d, char %d\n", yystate, yychar, 0 );
+ if( ++yyps > &yys[YYMAXDEPTH] ) {
+ yyerror( "yacc stack overflow" );
+ return(1);
+ }
+ *yyps = yystate;
+ ++yypv;
+
+ *yypv = yyval;
+
+yynewstate:
+
+ yyn = YYPACT[yystate];
+
+ if( yyn <= YYFLAG ) { /* simple state, no lookahead */
+ goto yydefault;
+ }
+ if( yychar < 0 ) { /* need a lookahead */
+ yychar = YYLEX();
+ }
+ if( ((yyn += yychar) < 0) || (yyn >= YYLAST) ) {
+ goto yydefault;
+ }
+ if( YYCHK[ yyn = YYACT[ yyn ] ] == yychar ) { /* valid shift */
+ yychar = -1;
+ yyval = yylval;
+ yystate = yyn;
+ if( yyerrflag > 0 ) {
+ --yyerrflag;
+ }
+ goto yystack;
+ }
+
+ yydefault:
+ /* default state action */
+
+ if( (yyn = YYDEF[yystate]) == -2 ) {
+ register short *yyxi;
+
+ if( yychar < 0 ) {
+ yychar = YYLEX();
+ }
+/*
+** search exception table, we find a -1 followed by the current state.
+** if we find one, we'll look through terminal,state pairs. if we find
+** a terminal which matches the current one, we have a match.
+** the exception table is when we have a reduce on a terminal.
+*/
+
+#if YYOPTTIME
+ yyxi = yyexca + yyexcaind[yystate];
+ while(( *yyxi != yychar ) && ( *yyxi >= 0 )){
+ yyxi += 2;
+ }
+#else
+ for(yyxi = yyexca;
+ (*yyxi != (-1)) || (yyxi[1] != yystate);
+ yyxi += 2
+ ) {
+ ; /* VOID */
+ }
+
+ while( *(yyxi += 2) >= 0 ){
+ if( *yyxi == yychar ) {
+ break;
+ }
+ }
+#endif
+ if( (yyn = yyxi[1]) < 0 ) {
+ return(0); /* accept */
+ }
+ }
+
+ if( yyn == 0 ){ /* error */
+ /* error ... attempt to resume parsing */
+
+ switch( yyerrflag ){
+
+ case 0: /* brand new error */
+#ifdef YYRECOVER
+ {
+ register int i,j;
+
+ for(i = 0;
+ (yyrecover[i] != -1000) && (yystate > yyrecover[i]);
+ i += 3
+ ) {
+ ;
+ }
+ if(yystate == yyrecover[i]) {
+ yyprintf("recovered, from state %d to state %d on token %d\n",
+ yystate,yyrecover[i+2],yyrecover[i+1]
+ );
+ j = yyrecover[i + 1];
+ if(j < 0) {
+ /*
+ ** here we have one of the injection set, so we're not quite
+ ** sure that the next valid thing will be a shift. so we'll
+ ** count it as an error and continue.
+ ** actually we're not absolutely sure that the next token
+ ** we were supposed to get is the one when j > 0. for example,
+ ** for(+) {;} error recovery with yyerrflag always set, stops
+ ** after inserting one ; before the +. at the point of the +,
+ ** we're pretty sure the guy wants a 'for' loop. without
+ ** setting the flag, when we're almost absolutely sure, we'll
+ ** give him one, since the only thing we can shift on this
+ ** error is after finding an expression followed by a +
+ */
+ yyerrflag++;
+ j = -j;
+ }
+ if(yyerrflag <= 1) { /* only on first insertion */
+ yyrecerr(yychar,j); /* what was, what should be first */
+ }
+ yyval = yyeval(j);
+ yystate = yyrecover[i + 2];
+ goto yystack;
+ }
+ }
+#endif
+ yyerror("syntax error");
+
+ yyerrlab:
+ ++yynerrs;
+
+ case 1:
+ case 2: /* incompletely recovered error ... try again */
+
+ yyerrflag = 3;
+
+ /* find a state where "error" is a legal shift action */
+
+ while ( yyps >= yys ) {
+ yyn = YYPACT[*yyps] + YYERRCODE;
+ if( yyn>= 0 && yyn < YYLAST && YYCHK[YYACT[yyn]] == YYERRCODE ){
+ yystate = YYACT[yyn]; /* simulate a shift of "error" */
+ goto yystack;
+ }
+ yyn = YYPACT[*yyps];
+
+ /* the current yyps has no shift onn "error", pop stack */
+
+yyprintf( "error recovery pops state %d, uncovers %d\n", *yyps, yyps[-1], 0 );
+ --yyps;
+ --yypv;
+ }
+
+ /* there is no state on the stack with an error shift ... abort */
+
+ yyabort:
+ return(1);
+
+
+ case 3: /* no shift yet; clobber input char */
+
+ yyprintf( "error recovery discards char %d\n", yychar, 0, 0 );
+
+ if( yychar == 0 ) goto yyabort; /* don't discard EOF, quit */
+ yychar = -1;
+ goto yynewstate; /* try again in the same state */
+ }
+ }
+
+ /* reduction by production yyn */
+yyreduce:
+ {
+ register YYSTYPE *yypvt;
+ yyprintf("reduce %d\n",yyn, 0, 0);
+ yypvt = yypv;
+ yyps -= YYR2[yyn];
+ yypv -= YYR2[yyn];
+ yyval = yypv[1];
+ yym = yyn;
+ yyn = YYR1[yyn]; /* consult goto table to find next state */
+ yyj = YYPGO[yyn] + *yyps + 1;
+ if( (yyj >= YYLAST) || (YYCHK[ yystate = YYACT[yyj] ] != -yyn) ) {
+ yystate = YYACT[YYPGO[yyn]];
+ }
+ switch(yym){
+ $A
+ }
+ }
+ goto yystack; /* stack new state and value */
+ }
diff --git a/private/os2/client/thunk/viocalls.def b/private/os2/client/thunk/viocalls.def
new file mode 100644
index 000000000..57688b3c2
--- /dev/null
+++ b/private/os2/client/thunk/viocalls.def
@@ -0,0 +1,102 @@
+LIBRARY VIOCALLS
+PROTMODE
+
+EXPORTS
+ VIOENDPOPUP @1 RESIDENTNAME
+ VIOGETPHYSBUF @2 RESIDENTNAME
+ VIOGETANSI @3 RESIDENTNAME
+;#if PMNT
+; VIOFREE @4 RESIDENTNAME
+;#endif
+ VIOSETANSI @5 RESIDENTNAME
+ VIODEREGISTER @6 RESIDENTNAME
+ VIOSCROLLUP @7 RESIDENTNAME
+ VIOPRTSC @8 RESIDENTNAME
+ VIOGETCURPOS @9 RESIDENTNAME
+ VIOWRTCELLSTR @10 RESIDENTNAME
+ VIOPOPUP @11 RESIDENTNAME
+ VIOSCROLLRT @12 RESIDENTNAME
+ VIOWRTCHARSTR @13 RESIDENTNAME
+; VIOAVS_PRTSC @14 RESIDENTNAME
+ VIOSETCURPOS @15 RESIDENTNAME
+;#if PMNT
+; VIOSRFUNBLOCK @16 RESIDENTNAME
+; VIOSRFBLOCK @17 RESIDENTNAME
+;#endif
+ VIOSCRUNLOCK @18 RESIDENTNAME
+ VIOWRTTTY @19 RESIDENTNAME
+;#if PMNT
+; VIOSAVE @20 RESIDENTNAME
+;#endif
+ VIOGETMODE @21 RESIDENTNAME
+ VIOSETMODE @22 RESIDENTNAME
+ VIOSCRLOCK @23 RESIDENTNAME
+ VIOREADCELLSTR @24 RESIDENTNAME
+ VIOSAVREDRAWWAIT @25 RESIDENTNAME
+ VIOWRTNATTR @26 RESIDENTNAME
+ VIOGETCURTYPE @27 RESIDENTNAME
+ VIOSAVREDRAWUNDO @28 RESIDENTNAME
+ VIOGETFONT @29 RESIDENTNAME
+ VIOREADCHARSTR @30 RESIDENTNAME
+ VIOGETBUF @31 RESIDENTNAME
+ VIOSETCURTYPE @32 RESIDENTNAME
+ VIOSETFONT @33 RESIDENTNAME
+; VIOHETINIT @34 RESIDENTNAME
+ VIOMODEUNDO @35 RESIDENTNAME
+;#if PMNT
+; VIOSSWSWITCH @36 RESIDENTNAME
+;#endif
+ VIOMODEWAIT @37 RESIDENTNAME
+; VIOAVS_PRTSCTOGGLE @38 RESIDENTNAME
+ VIOGETCP @40 RESIDENTNAME
+;#if PMNT
+; VIORESTORE @41 RESIDENTNAME
+;#endif
+ VIOSETCP @42 RESIDENTNAME
+ VIOSHOWBUF @43 RESIDENTNAME
+ VIOSCROLLLF @44 RESIDENTNAME
+ VIOREGISTER @45 RESIDENTNAME
+ VIOGETCONFIG @46 RESIDENTNAME
+ VIOSCROLLDN @47 RESIDENTNAME
+ VIOWRTCHARSTRATT @48 RESIDENTNAME
+ VIOGETSTATE @49 RESIDENTNAME
+ VIOPRTSCTOGGLE @50 RESIDENTNAME
+ VIOSETSTATE @51 RESIDENTNAME
+ VIOWRTNCELL @52 RESIDENTNAME
+ VIOWRTNCHAR @53 RESIDENTNAME
+;#if PMNT
+; VIOSHELLINIT @54 RESIDENTNAME
+;#endif
+; VIOASSOCIATE @55 RESIDENTNAME
+; VIOCREATEPS @56 RESIDENTNAME
+; VIODELETESETID @57 RESIDENTNAME
+; VIOGETDEVICECELLSIZE @58 RESIDENTNAME
+; VIOGETORG @59 RESIDENTNAME
+; VIOCREATELOGFONT @60 RESIDENTNAME
+; VIODESTROYPS @61 RESIDENTNAME
+; VIOQUERYSETIDS @62 RESIDENTNAME
+; VIOSETORG @63 RESIDENTNAME
+; VIOQUERYFONTS @64 RESIDENTNAME
+; VIOSETDEVICECELLSIZE @65 RESIDENTNAME
+; VIOSHOWPS @66 RESIDENTNAME
+#if PMNT
+ VIOGETPSADDRESS @67 RESIDENTNAME
+#endif
+; VIOQUERYCONSOLE @68 RESIDENTNAME
+#if PMNT
+ VIOREDRAWSIZE @69 RESIDENTNAME
+#endif
+; VIOGLOBALREG @70 RESIDENTNAME
+; VIOXSETCASTATE @71 RESIDENTNAME
+; VIOXCHECKCHARTYPE @72 RESIDENTNAME
+; VIOXDESTROYCA @73 RESIDENTNAME
+; VIOXCREATECA @74 RESIDENTNAME
+#if DBCS
+;MSKK Begin KazuM -Jun.22.1992-
+ VIOCHECKCHARTYPE @75 RESIDENTNAME
+;MSKK End KazuM -Jun.22.1992-
+#else
+; VIOCHECKCHARTYPE @75 RESIDENTNAME
+#endif
+; VIOXGETCASTATE @76 RESIDENTNAME
+
diff --git a/private/os2/client/tstr.h b/private/os2/client/tstr.h
new file mode 100644
index 000000000..e00d9e2f3
--- /dev/null
+++ b/private/os2/client/tstr.h
@@ -0,0 +1,292 @@
+/*++
+
+Copyright (c) 1991-92 Microsoft Corporation
+
+Module Name:
+
+ tstr.h
+
+Abstract:
+
+ This include file contains manifests and macros to be used to integrate
+ the TCHAR and LPTSTR definitions
+
+ Note that our naming convention is that a "size" indicates a number of
+ bytes whereas a "length" indicates a number of characters.
+
+Author:
+
+ Richard Firth (rfirth) 02-Apr-1991
+
+Environment:
+
+ Portable (Win/32).
+ Requires ANSI C extensions: slash-slash comments, long external names,
+ _ultoa() routine.
+
+Revision History:
+
+ 22-May-1991 Danl
+ Added STRSIZE macro
+ 19-May-1991 JohnRo
+ Changed some parm names to make things easier to read.
+ 15-May-1991 rfirth
+ Added TCHAR_SPACE and MAKE_TCHAR() macro
+ 15-Jul-1991 RFirth
+ Added STRING_SPACE_REQD() and DOWN_LEVEL_STRSIZE
+ 05-Aug-1991 JohnRo
+ Added MEMCPY macro.
+ 19-Aug-1991 JohnRo
+ Added character type stuff: ISDIGIT(), TOUPPER(), etc.
+ 20-Aug-1991 JohnRo
+ Changed strnicmp to _strnicmp to keep PC-LINT happy. Ditto stricmp.
+ 13-Sep-1991 JohnRo
+ Need UNICODE STRSIZE() too.
+ 13-Sep-1991 JohnRo
+ Added UNICODE STRCMP() and various others.
+ 18-Oct-1991 JohnRo
+ Added NetpCopy routines and WCSSIZE().
+ 26-Nov-1991 JohnRo
+ Added NetpNCopy routines (like strncpy but do conversions as well).
+ 09-Dec-1991 rfirth
+ Added STRREV
+ 03-Jan-1992 JohnRo
+ Added NetpAlloc{type}From{type} routines and macros.
+ 09-Jan-1992 JohnRo
+ Added ATOL() macro and wtol() routine.
+ Ditto ULTOA() macro and ultow() routine.
+ 16-Jan-1992 Danl
+ Cut this info from \net\inc\tstring.h
+ 30-Jan-1992 JohnRo
+ Added STRSTR().
+ Use _wcsupr() instead of wcsupr() to keep PC-LINT happy.
+ Added STRCMPI() and STRNCMPI().
+ Fixed a few definitions which were missing MAKE_STR_FUNCTION etc.
+ 14-Mar-1992 JohnRo
+ Avoid compiler warnings using WCSSIZE(), MEMCPY(), etc.
+ Added TCHAR_TAB.
+ 09-Apr-1992 JohnRo
+ Prepare for WCHAR.H (_wcsicmp vs _wcscmpi, etc).
+
+--*/
+
+#ifndef _TSTR_H_INCLUDED
+#define _TSTR_H_INCLUDED
+
+#include <ctype.h> // isdigit(), iswdigit() eventually, etc.
+#include <stdlib.h> // atol(), _ultoa().
+#include <string.h> // memcpy(), strlen(), etc.
+#include <wchar.h>
+
+
+LPWSTR
+ultow (
+ IN DWORD Value,
+ OUT LPWSTR Area,
+ IN DWORD Radix
+ );
+
+LONG
+wtol (
+ IN LPWSTR Src
+ );
+
+
+#ifdef LM20_COMPATIBLE
+#define MAKE_STR_FUNCTION(s) s##f
+#else
+#define MAKE_STR_FUNCTION(s) s
+#endif
+
+
+#if defined(UNICODE)
+
+//
+// function macro prototypes
+//
+
+#define ATOL(Src) (LONG)MAKE_STR_FUNCTION(wtol)(Src)
+
+#define ISALNUM(tchar) iswalnum(tchar) // locale-dependent.
+#define ISALPHA(tchar) iswalpha(tchar) // locale-dependent.
+#define ISCNTRL(tchar) iswcntrl(tchar) // locale-dependent.
+#define ISDIGIT(tchar) iswdigit(tchar)
+#define ISGRAPH(tchar) iswgraph(tchar) // locale-dependent.
+#define ISLOWER(tchar) iswlower(tchar) // locale-dependent.
+#define ISPRINT(tchar) iswprint(tchar) // locale-dependent.
+#define ISPUNCT(tchar) iswpunct(tchar) // locale-dependent.
+#define ISSPACE(tchar) iswspace(tchar) // locale-dependent.
+#define ISUPPER(tchar) iswupper(tchar) // locale-dependent.
+#define ISXDIGIT(tchar) iswxdigit(tchar)
+
+#define STRCAT(dest, src) (LPTSTR)MAKE_STR_FUNCTION(wcscat)((dest), (src))
+#define STRCHR(s1, c) (LPTSTR)MAKE_STR_FUNCTION(wcschr)((s1), (c))
+#define STRCPY(dest, src) (LPTSTR)MAKE_STR_FUNCTION(wcscpy)((dest), (src))
+#define STRCSPN(s, c) (DWORD)MAKE_STR_FUNCTION(wcscspn)((s), (c))
+// STRLEN: Get character count of s.
+#define STRLEN(s) (DWORD)MAKE_STR_FUNCTION(wcslen)(s)
+#define STRNCAT(dest, src, n) \
+ (LPTSTR)MAKE_STR_FUNCTION(wcsncat)((dest), (src), (n))
+#define STRNCPY(dest, src, n) \
+ (LPTSTR)MAKE_STR_FUNCTION(wcsncpy)((dest), (src), (n))
+#define STRSPN(s1, s2) (DWORD)MAKE_STR_FUNCTION(wcsspn)((s1), (s2))
+#define STRRCHR (LPTSTR)MAKE_STR_FUNCTION(wcsrchr)
+#define STRSTR (LPTSTR)MAKE_STR_FUNCTION(wcswcs)
+#define STRUPR(s) (LPTSTR)MAKE_STR_FUNCTION(_wcsupr)(s)
+
+// these don't have formal parameters because we want to take the address of
+// the mapped function in certain cases. Modify as appropriate.
+// Note that for these functions, lengths are in characters.
+
+// compare functions: len is maximum number of characters being compared.
+#define STRCMP (LONG)MAKE_STR_FUNCTION(wcscmp)
+#define STRCMPI (LONG)MAKE_STR_FUNCTION(_wcsicmp)
+#define STRICMP (LONG)MAKE_STR_FUNCTION(_wcsicmp)
+#define STRNCMP (LONG)MAKE_STR_FUNCTION(wcsncmp)
+#define STRNCMPI (LONG)MAKE_STR_FUNCTION(_wcsnicmp)
+#define STRNICMP (LONG)MAKE_STR_FUNCTION(_wcsnicmp)
+
+#define TOLOWER(tchar) towlower(tchar) // locale-dependent.
+#define TOUPPER(tchar) towupper(tchar) // locale-dependent.
+
+#define ULTOA(Value,Result,Radix) \
+ (LPTSTR)MAKE_STR_FUNCTION(ultow)( (Value), (Result), (Radix) )
+
+//
+// manifests
+//
+
+#define _CHAR_TYPE WCHAR
+
+#else // not UNICODE
+
+//
+// function macro prototypes
+//
+
+#define ATOL(Src) (LONG)MAKE_STR_FUNCTION(atol)(Src)
+
+#define ISALNUM(tchar) isalnum(tchar) // locale-dependent.
+#define ISALPHA(tchar) isalpha(tchar) // locale-dependent.
+#define ISCNTRL(tchar) iscntrl(tchar) // locale-dependent.
+#define ISDIGIT(tchar) isdigit(tchar)
+#define ISGRAPH(tchar) isgraph(tchar) // locale-dependent.
+#define ISLOWER(tchar) islower(tchar) // locale-dependent.
+#define ISPRINT(tchar) isprint(tchar) // locale-dependent.
+#define ISPUNCT(tchar) ispunct(tchar) // locale-dependent.
+#define ISSPACE(tchar) isspace(tchar) // locale-dependent.
+#define ISUPPER(tchar) isupper(tchar) // locale-dependent.
+#define ISXDIGIT(tchar) isxdigit(tchar)
+
+#define STRCAT(dest, src) (LPTSTR)MAKE_STR_FUNCTION(strcat)((dest), (src))
+#define STRNCAT(dest, src, n) \
+ (LPTSTR)MAKE_STR_FUNCTION(strncat)((dest), (src), (n))
+// STRLEN: Get character count of s.
+#define STRLEN(s) (DWORD)MAKE_STR_FUNCTION(strlen)(s)
+#define STRSPN(s1, s2) (DWORD)MAKE_STR_FUNCTION(strspn)((s1), (s2))
+#define STRCSPN(s, c) (DWORD)MAKE_STR_FUNCTION(strcspn)((s), (c))
+#define STRCPY(dest, src) (LPTSTR)MAKE_STR_FUNCTION(strcpy)((dest), (src))
+#define STRNCPY(dest, src, n) \
+ (LPTSTR)MAKE_STR_FUNCTION(strncpy)((dest), (src), (n))
+#define STRCHR(s1, c) (LPTSTR)MAKE_STR_FUNCTION(strchr)((s1), (c))
+#define STRRCHR (LPTSTR)MAKE_STR_FUNCTION(strrchr)
+#define STRSTR (LPTSTR)MAKE_STR_FUNCTION(strstr)
+#define STRUPR(s) (LPTSTR)MAKE_STR_FUNCTION(strupr)(s)
+#define STRREV(s) (LPTSTR)MAKE_STR_FUNCTION(strrev)(s)
+
+// these don't have formal parameters because we want to take the address of
+// the mapped function in certain cases. Modify as appropriate.
+// Note that for these functions, lengths are in characters.
+
+// compare functions: len is maximum number of characters being compared.
+#define STRCMP (LONG)MAKE_STR_FUNCTION(strcmp)
+#define STRCMPI (LONG)MAKE_STR_FUNCTION(_stricmp)
+#define STRICMP (LONG)MAKE_STR_FUNCTION(_stricmp)
+#define STRNCMP (LONG)MAKE_STR_FUNCTION(strncmp)
+#define STRNCMPI (LONG)MAKE_STR_FUNCTION(_strnicmp)
+#define STRNICMP (LONG)MAKE_STR_FUNCTION(_strnicmp)
+
+#define TOLOWER(tchar) tolower(tchar) // locale-dependent.
+#define TOUPPER(tchar) toupper(tchar) // locale-dependent.
+
+#define ULTOA(Value,Result,Radix) \
+ (LPTSTR)MAKE_STR_FUNCTION(_ultoa)( (Value), (Result), (Radix) )
+
+//
+// manifests
+//
+
+#define _CHAR_TYPE TCHAR
+
+#endif // not UNICODE
+
+
+//
+// For the memory routines, the counts are always BYTE counts.
+//
+#define MEMCPY MAKE_STR_FUNCTION(memcpy)
+#define MEMMOVE MAKE_STR_FUNCTION(memmove)
+
+//
+// These are used to determine the number of bytes (including the NUL
+// terminator) in a string. This will generally be used when
+// calculating the size of a string for allocation purposes.
+//
+
+#define STRSIZE(p) ((STRLEN(p)+1) * sizeof(TCHAR))
+#define WCSSIZE(s) ((MAKE_STR_FUNCTION(wcslen)(s)+1) * sizeof(WCHAR))
+
+
+//
+// character literals (both types)
+//
+
+#define TCHAR_EOS ((_CHAR_TYPE)'\0')
+#define TCHAR_STAR ((_CHAR_TYPE)'*')
+#define TCHAR_BACKSLASH ((_CHAR_TYPE)'\\')
+#define TCHAR_FWDSLASH ((_CHAR_TYPE)'/')
+#define TCHAR_COLON ((_CHAR_TYPE)':')
+#define TCHAR_DOT ((_CHAR_TYPE)'.')
+#define TCHAR_SPACE ((_CHAR_TYPE)' ')
+#define TCHAR_TAB ((_CHAR_TYPE)'\t')
+
+
+//
+// General purpose macro for casting character types to whatever type in vogue
+// (as defined in this file)
+//
+
+#define MAKE_TCHAR(c) ((_CHAR_TYPE)(c))
+
+//
+// IS_PATH_SEPARATOR
+//
+// lifted from curdir.c and changed to use TCHAR_ character literals, checks
+// if a character is a path separator i.e. is a member of the set [\/]
+//
+
+#define IS_PATH_SEPARATOR(ch) ((ch == TCHAR_BACKSLASH) || (ch == TCHAR_FWDSLASH))
+
+//
+// The following 2 macros lifted from I_Net canonicalization files
+//
+
+#define IS_DRIVE(c) ISALPHA(c)
+#define IS_NON_ZERO_DIGIT(c) (((c) >= MAKE_TCHAR('1')) && ((c) <= MAKE_TCHAR('9')))
+
+//
+// STRING_SPACE_REQD returns a number (of bytes) corresponding to the space
+// required in which (n) characters can be accomodated
+//
+
+#define STRING_SPACE_REQD(n) ((n) * sizeof(_CHAR_TYPE))
+
+//
+// DOWN_LEVEL_STRLEN returns the number of single-byte characters necessary to
+// store a converted _CHAR_TYPE string. This will be WCHAR (or wchar_t) if
+// UNICODE is defined or CHAR (or char) otherwise
+//
+
+#define DOWN_LEVEL_STRSIZE(n) ((n) / sizeof(_CHAR_TYPE))
+
+#endif // _TSTR_H_INCLUDED
diff --git a/private/os2/client/tstring.h b/private/os2/client/tstring.h
new file mode 100644
index 000000000..19a2b5211
--- /dev/null
+++ b/private/os2/client/tstring.h
@@ -0,0 +1,243 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ tstring.h
+
+Abstract:
+
+ This include file contains manifests and macros to be used to integrate
+ the TCHAR and LPTSTR definitions
+
+ Note that our naming convention is that a "size" indicates a number of
+ bytes whereas a "length" indicates a number of characters.
+
+Author:
+
+ Richard Firth (rfirth) 02-Apr-1991
+
+Environment:
+
+ Portable (Win/32).
+ Requires ANSI C extensions: slash-slash comments, long external names,
+ _ultoa() routine.
+
+Revision History:
+
+ 22-May-1991 Danl
+ Added STRSIZE macro
+ 19-May-1991 JohnRo
+ Changed some parm names to make things easier to read.
+ 15-May-1991 rfirth
+ Added TCHAR_SPACE and MAKE_TCHAR() macro
+ 15-Jul-1991 RFirth
+ Added STRING_SPACE_REQD() and DOWN_LEVEL_STRSIZE
+ 05-Aug-1991 JohnRo
+ Added MEMCPY macro.
+ 19-Aug-1991 JohnRo
+ Added character type stuff: ISDIGIT(), TOUPPER(), etc.
+ 20-Aug-1991 JohnRo
+ Changed strnicmp to _strnicmp to keep PC-LINT happy. Ditto stricmp.
+ 13-Sep-1991 JohnRo
+ Need UNICODE STRSIZE() too.
+ 13-Sep-1991 JohnRo
+ Added UNICODE STRCMP() and various others.
+ 18-Oct-1991 JohnRo
+ Added NetpCopy routines and WCSSIZE().
+ 26-Nov-1991 JohnRo
+ Added NetpNCopy routines (like strncpy but do conversions as well).
+ 09-Dec-1991 rfirth
+ Added STRREV
+ 03-Jan-1992 JohnRo
+ Added NetpAlloc{type}From{type} routines and macros.
+ 09-Jan-1992 JohnRo
+ Added ATOL() macro and wtol() routine.
+ Ditto ULTOA() macro and ultow() routine.
+ 13-Jan-1992 JohnRo
+ Oops, I missed from NetpAlloc{type}From{type} macros
+ Also added STRNCMPI as an alias for STRNICMP.
+ 16-Jan-1992 Danl
+ Moved the macros to \private\inc\tstr.h
+ 23-Mar-1992 JohnRo
+ Added NetpCopy{Str,TStr,WStr}ToUnalignedWStr().
+ 27-Apr-1992 JohnRo
+ Changed NetpNCopy{type}From{type} to return NET_API_STATUS.
+ 03-Aug-1992 JohnRo
+ RAID 1895: Net APIs and svcs should use OEM char set.
+ 14-Apr-1993 JohnRo
+ RAID 6113 ("PortUAS: dangerous handling of Unicode").
+ Made changes suggested by PC-LINT 5.0
+
+--*/
+
+#ifndef _TSTRING_H_INCLUDED
+#define _TSTRING_H_INCLUDED
+
+
+#include <lmcons.h> // NET_API_STATUS.
+// Don't complain about "unneeded" includes of these files:
+/*lint -efile(764,tstr.h,winerror.h) */
+/*lint -efile(766,tstr.h,winerror.h) */
+#include <tstr.h> // tstring stuff, used in macros below.
+#include <winerror.h> // NO_ERROR.
+
+
+//
+// Eventually, most uses of non-UNICODE strings should refer to the default
+// codepage for the LAN. The NetpCopy functions support the default codepage.
+// The other STR macros may not.
+//
+VOID
+NetpCopyStrToWStr(
+ OUT LPWSTR Dest,
+ IN LPSTR Src // string in default LAN codepage
+ );
+
+NET_API_STATUS
+NetpNCopyStrToWStr(
+ OUT LPWSTR Dest,
+ IN LPSTR Src, // string in default LAN codepage
+ IN DWORD CharCount
+ );
+
+VOID
+NetpCopyWStrToStr(
+ OUT LPSTR Dest, // string in default LAN codepage
+ IN LPWSTR Src
+ );
+
+NET_API_STATUS
+NetpNCopyWStrToStr(
+ OUT LPSTR Dest, // string in default LAN codepage
+ IN LPWSTR Src,
+ IN DWORD CharCount
+ );
+
+#ifdef UNICODE
+
+#define NetpCopyStrToTStr(Dest,Src) NetpCopyStrToWStr((Dest),(Src))
+#define NetpCopyTStrToStr(Dest,Src) NetpCopyWStrToStr((LPSTR)(Dest),(LPWSTR)(Src))
+#define NetpCopyTStrToWStr(Dest,Src) (void) wcscpy((Dest),(Src))
+#define NetpCopyWStrToTStr(Dest,Src) (void) wcscpy((Dest),(Src))
+
+#define NetpNCopyStrToTStr(Dest,Src,Len) NetpNCopyStrToWStr((Dest),(Src),(Len))
+#define NetpNCopyTStrToStr(Dest,Src,Len) NetpNCopyWStrToStr((Dest),(Src),(Len))
+#define NetpNCopyTStrToWStr(Dest,Src,Len) \
+ (wcsncpy((Dest),(Src),(Len)), NO_ERROR)
+#define NetpNCopyWStrToTStr(Dest,Src,Len) \
+ (wcsncpy((Dest),(Src),(Len)), NO_ERROR)
+
+#else // not UNICODE
+
+// BUGBUG: Does strcpy() handle code pages OK?
+#define NetpCopyStrToTStr(Dest,Src) (void) strcpy((Dest),(Src))
+#define NetpCopyTStrToStr(Dest,Src) (void) strcpy((Dest),(Src))
+#define NetpCopyTStrToWStr(Dest,Src) NetpCopyStrToWStr((Dest),(Src))
+#define NetpCopyWStrToTStr(Dest,Src) NetpCopyWStrToStr((Dest),(Src))
+
+#define NetpNCopyStrToTStr(Dest,Src,Len) \
+ (strncpy((Dest),(Src),(Len)), NO_ERROR)
+#define NetpNCopyTStrToStr(Dest,Src,Len) \
+ (strncpy((Dest),(Src),(Len)), NO_ERROR)
+#define NetpNCopyTStrToWStr(Dest,Src,Len) NetpNCopyStrToWStr((Dest),(Src),(Len))
+#define NetpNCopyWStrToTStr(Dest,Src,Len) NetpNCopyWStrToStr((Dest),(Src),(Len))
+
+#endif // not UNICODE
+
+
+//
+// Define a set of allocate and copy functions. These all return NULL if
+// unable to allocate memory. The memory must be freed with NetApiBufferFree.
+//
+
+LPSTR
+NetpAllocStrFromStr (
+ IN LPSTR Src
+ );
+
+LPSTR
+NetpAllocStrFromWStr (
+ IN LPWSTR Src
+ );
+
+LPWSTR
+NetpAllocWStrFromStr (
+ IN LPSTR Src
+ );
+
+LPWSTR
+NetpAllocWStrFromWStr (
+ IN LPWSTR Src
+ );
+
+#ifdef UNICODE
+
+#define NetpAllocStrFromTStr(Src) NetpAllocStrFromWStr(Src)
+#define NetpAllocTStrFromStr(Src) NetpAllocWStrFromStr(Src)
+#define NetpAllocTStrFromTStr(Src) NetpAllocWStrFromWStr(Src)
+#define NetpAllocTStrFromWStr(Src) NetpAllocWStrFromWStr(Src)
+#define NetpAllocWStrFromTStr(Src) NetpAllocWStrFromWStr(Src)
+
+#else // ndef UNICODE
+
+#define NetpAllocStrFromTStr(Src) NetpAllocStrFromStr(Src)
+#define NetpAllocTStrFromStr(Src) NetpAllocStrFromStr(Src)
+#define NetpAllocTStrFromTStr(Src) NetpAllocStrFromStr(Src)
+#define NetpAllocTStrFromWStr(Src) NetpAllocStrFromWStr(Src)
+#define NetpAllocWStrFromTStr(Src) NetpAllocWStrFromStr(Src)
+
+#endif // ndef UNICODE
+
+
+VOID
+NetpCopyStrToUnalignedWStr(
+ OUT LPBYTE Dest,
+ IN LPSTR Src
+ );
+
+VOID
+NetpCopyWStrToUnalignedWStr(
+ OUT LPBYTE Dest,
+ IN LPWSTR Src
+ );
+
+#ifdef UNICODE
+
+#define NetpCopyTStrToUnalignedWStr(Dest,Src) \
+ NetpCopyWStrToUnalignedWStr(Dest,Src)
+
+#else // ndef UNICODE
+
+#define NetpCopyTStrToUnalignedWStr(Dest,Src) \
+ NetpCopyStrToUnalignedWStr(Dest,Src)
+
+#endif // ndef UNICODE
+
+
+//
+// As of 03-Aug-1992, people are still arguing over whether there should
+// be an RtlInitOemString. So I'm inventing NetpInitOemString in the
+// meantime. --JR
+//
+
+#ifdef _NTDEF_ // POEM_STRING typedef visible?
+
+VOID
+NetpInitOemString(
+ OUT POEM_STRING DestinationString,
+ IN PCSZ SourceString
+ );
+
+#endif // _NTDEF_
+
+
+VOID
+NetpSubsetStr(
+ IN OUT LPSTR StringToSubset, // OEM chars, conv to subset in place.
+ IN DWORD MaxStringSize // size in bytes (incl null char)
+ );
+
+
+#endif // _TSTRING_H_INCLUDED
diff --git a/private/os2/client/vdmredir.c b/private/os2/client/vdmredir.c
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/private/os2/client/vdmredir.c
@@ -0,0 +1 @@
+
diff --git a/private/os2/client/vdmredir.h b/private/os2/client/vdmredir.h
new file mode 100644
index 000000000..66088ea28
--- /dev/null
+++ b/private/os2/client/vdmredir.h
@@ -0,0 +1,443 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ vdmredir.h
+
+Abstract:
+
+ Contains common defines, structures, macros, etc. for VdmRedir. This file
+ contains macros to read and write the 3 basic data structures from/to VDM
+ memory. We *must* use these macros because the MIPS processor does not like
+ unaligned data: a DWORD must be read/written on a DWORD boundary (low two
+ bits in address = 00), a WORD must be read/written on a WORD boundary (low
+ two bits in address = X0) and a BYTE can be read/written to any address (low
+ two bits in address = XX). It is illegal to access a WORD at an address
+ whose LSB is not 0, and a DWORD at an address whose 2 least significant bits
+ are not both 0. Dos programs don't care much about alignment (smart ones do
+ because there is a performance penalty for unaligned data on x86, but it
+ still works). So we have to assume the worst case for MIPS and break down
+ the read/writes of WORDs and DWORDs in VDM memory into BYTE read/writes
+
+ In order to improve efficiency of load/store to potentially unaligned
+ addresses, the following data pointer types are made available from this
+ include file:
+
+ ULPBYTE - unaligned byte pointer (same as LPBYTE)
+ ULPWORD - unaligned word pointer
+ ULPDWORD - unaligned dword pointer
+
+ NB. Dependent upon mvdm.h
+
+Author:
+
+ Richard L Firth (rfirth) 16-Sep-1991
+
+Revision History:
+
+ 16-Sep-1991 rfirth
+ Created
+
+--*/
+
+#ifndef _VDMREDIR_
+#define _VDMREDIR_
+
+#include <os2tile.h> // nirm
+
+//#include <softpc.h>
+
+//
+// PRIVATE - make a routine/data type inaccessible outside current module, but
+// only if not DEBUG version
+//
+
+#if DBG
+#define PRIVATE
+#else
+#define PRIVATE static
+#endif
+
+//
+// unaligned data pointer types. These produce exactly the same code as memory
+// accesses through 'aligned' pointers on x86, but generate code specific to
+// unaligned read/writes on MIPS (& other RISCs)
+//
+
+#ifdef UNALIGNED_VDM_POINTERS
+typedef BYTE UNALIGNED * ULPBYTE;
+typedef WORD UNALIGNED * ULPWORD;
+typedef DWORD UNALIGNED * ULPDWORD;
+#else
+typedef LPBYTE ULPBYTE;
+typedef LPWORD ULPWORD;
+typedef LPDWORD ULPDWORD;
+#endif
+
+//
+// misc. defines
+//
+
+#define BITS_IN_A_BYTE 8
+#define LOCAL_DEVICE_PREFIX "\\\\."
+
+//
+// Define network interrupt to be on Irql 14.
+// If NETWORK_ICA changes to ICA_MASTER then vrnetb.c should only execute 1 eoi
+// If either change then NETWORK_INTERRUPT in int5c.inc must also change.
+//
+
+#define NETWORK_ICA ICA_SLAVE
+#define NETWORK_LINE 6
+
+//
+// helper macros
+//
+
+//
+// MAKE_DWORD - converts 2 16-bit words into a 32-bit double word
+//
+#define MAKE_DWORD(h, l) ((DWORD)(((DWORD)((WORD)(h)) << 16) | (DWORD)((WORD)(l))))
+
+//
+// DWORD_FROM_WORDS - converts two 16-bit words into a 32-bit dword
+//
+#define DWORD_FROM_WORDS(h, l) MAKE_DWORD((h), (l))
+
+//
+// HANDLE_FROM_WORDS - converts a pair of 16-bit words into a 32-bit handle
+//
+#define HANDLE_FROM_WORDS(h, l) ((HANDLE)(MAKE_DWORD((h), (l))))
+
+//
+// POINTER_FROM_WORDS - returns a flat 32-bit VOID pointer (in the VDM) OR the
+// NULL macro, given the 16-bit real-mode segment & offset. On x86 this will
+// return 0 if we pass in 0:0 because all GetVDMAddr does is seg << 4 + off.
+// The MIPS version adds this to the start of the virtual DOS memory. The
+// problem arises when we have a NULL pointer, and want to keep it NULL - we
+// convert it to non-NULL on not x86
+//
+//#define POINTER_FROM_WORDS(seg, off) ((LPVOID)GetVDMAddr((seg), (off)))
+//#define POINTER_FROM_WORDS(seg, off) (((((DWORD)(seg)) << 16) | (off)) ? ((LPVOID)GetVDMAddr((seg), (off))) : ((LPVOID)0))
+
+#define POINTER_FROM_WORDS(seg, off) _inlinePointerFromWords((WORD)(seg), (WORD)(off))
+
+//
+// LPSTR_FROM_WORDS - returns a 32-bit pointer to an ASCIZ string given the
+// 16-bit real-mode segment & offset
+//
+#define LPSTR_FROM_WORDS(seg, off) ((LPSTR)POINTER_FROM_WORDS((seg), (off)))
+
+//
+// LPBYTE_FROM_WORDS - returns a 32-bit byte pointer given the 16-bit
+// real-mode segment & offset
+//
+#define LPBYTE_FROM_WORDS(seg, off) ((LPBYTE)POINTER_FROM_WORDS((seg), (off)))
+
+//
+// READ_FAR_POINTER - read the pair of words in VDM memory, currently pointed at
+// by a 32-bit flat pointer and convert them to a 32-bit flat pointer
+//
+#define READ_FAR_POINTER(addr) ((LPVOID)(POINTER_FROM_WORDS(GET_SELECTOR(addr), GET_OFFSET(addr))))
+
+//
+// READ_BYTE - retrieve a single byte from VDM memory. Both x86 and MIPS can
+// handle reading a single byte without pain
+//
+#define READ_BYTE(addr) (*((LPBYTE)(addr)))
+
+//
+// READ_WORD - read a single 16-bit little-endian word from VDM memory. x86 can
+// handle unaligned data, MIPS (&other RISCs) must be broken down into individual
+// BYTE reads & the WORD pieced together by shifting & oring. If we are using
+// UNALIGNED pointers then the RISC processor can handle non-aligned data
+//
+#ifdef i386
+#define READ_WORD(addr) (*((LPWORD)(addr)))
+#else
+#ifdef UNALIGNED_VDM_POINTERS
+#define READ_WORD(addr) (*((ULPWORD)(addr)))
+#else
+#define READ_WORD(addr) (((WORD)READ_BYTE(addr)) | (((WORD)READ_BYTE((LPBYTE)(addr)+1)) << 8))
+#endif // UNALIGNED_VDM_POINTERS
+#endif // i386
+
+//
+// READ_DWORD - read a 4-byte little-endian double word from VDM memory. x86 can
+// handle unaligned data, MIPS (&other RISCs) must be broken down into individual
+// BYTE reads & the DWORD pieced together by shifting & oring. If we are using
+// UNALIGNED pointers then the RISC processor can handle non-aligned data
+//
+#ifdef i386
+#define READ_DWORD(addr) (*((LPDWORD)(addr)))
+#else
+#ifdef UNALIGNED_VDM_POINTERS
+#define READ_DWORD(addr) (*((ULPDWORD)(addr)))
+#else
+#define READ_DWORD(addr) (((DWORD)READ_WORD(addr)) | (((DWORD)READ_WORD((LPWORD)(addr)+1)) << 16))
+#endif // UNALIGNED_VDM_POINTERS
+#endif // i386
+
+//
+// WRITE_BYTE - write a single byte in VDM memory. Both x86 and MIPS (RISC) can
+// write a single byte to a non-aligned address
+//
+#define WRITE_BYTE(addr, value) (*(LPBYTE)(addr) = (BYTE)(value))
+
+//
+// WRITE_WORD - write a 16-bit little-endian value into VDM memory. x86 can write
+// WORD data to non-word-aligned address; MIPS (& other RISCs) cannot, so we
+// break down the write into 2 byte writes. If we are using UNALIGNED pointers
+// then the MIPS (&other RISCs) can generate code to handle this situation
+//
+#ifdef i386
+#define WRITE_WORD(addr, value) (*((LPWORD)(addr)) = (WORD)(value))
+#else
+#ifdef UNALIGNED_VDM_POINTERS
+#define WRITE_WORD(addr, value) (*((ULPWORD)(addr)) = (WORD)(value))
+#else
+#define WRITE_WORD(addr, value) \
+ {\
+ ((LPBYTE)(addr))[0] = LOBYTE(value); \
+ ((LPBYTE)(addr))[1] = HIBYTE(value); \
+ }
+#endif // UNALIGNED_VDM_POINTERS
+#endif // i386
+
+//
+// WRITE_DWORD - write a 32-bit DWORD value into VDM memory. x86 can write
+// DWORD data to non-dword-aligned address; MIPS (& other RISCs) cannot, so we
+// break down the write into 4 byte writes. If we are using UNALIGNED pointers
+// then the MIPS (&other RISCs) can generate code to handle this situation
+//
+#ifdef i386
+#define WRITE_DWORD(addr, value) (*((LPDWORD)(addr)) = (DWORD)(value))
+#else
+#ifdef UNALIGNED_VDM_POINTERS
+#define WRITE_DWORD(addr, value) (*((ULPDWORD)(addr)) = (DWORD)(value))
+#else
+#define WRITE_DWORD(addr, value) \
+ { \
+ ((LPBYTE)(addr))[0] = LOBYTE(LOWORD((DWORD)(value))); \
+ ((LPBYTE)(addr))[1] = HIBYTE(LOWORD((DWORD)(value))); \
+ ((LPBYTE)(addr))[2] = LOBYTE(HIWORD((DWORD)(value))); \
+ ((LPBYTE)(addr))[3] = HIBYTE(HIWORD((DWORD)(value))); \
+ }
+#endif // UNALIGNED_VDM_POINTERS
+#endif // i386
+
+//
+// WRITE_FAR_POINTER - write a 16:16 pointer into VDM memory. This is the same
+// as writing a DWORD
+//
+#define WRITE_FAR_POINTER(addr, ptr) WRITE_DWORD((addr), (DWORD)(ptr))
+
+//
+// GET_SELECTOR - retrieves the selector word from the intel 32-bit far pointer
+// (DWORD) pointed at by <pointer> (remember: stored as offset, segment)
+//
+#define GET_SELECTOR(pointer) READ_WORD((LPWORD)(pointer)+1)
+
+//
+// GET_SEGMENT - same as GET_SELECTOR
+//
+#define GET_SEGMENT(pointer) GET_SELECTOR(pointer)
+
+//
+// GET_OFFSET - retrieves the offset word from an intel 32-bit far pointer
+// (DWORD) pointed at by <pointer> (remember: stored as offset, segment)
+//
+#define GET_OFFSET(pointer) READ_WORD((LPWORD)(pointer))
+
+//
+// SET_SELECTOR - writes a word into the segment word of a real-mode far pointer
+// (DWORD) pointed at by <pointer> (remember: stored as offset, segment)
+//
+#define SET_SELECTOR(pointer, word) WRITE_WORD(((LPWORD)(pointer)+1), (word))
+
+//
+// SET_SEGMENT - same as SET_SELECTOR
+//
+#define SET_SEGMENT(pointer, word) SET_SELECTOR(pointer, word)
+
+//
+// SET_OFFSET - writes a word into the offset word of a real-mode far pointer
+// (DWORD) pointed at by <pointer> (remember: stored as offset, segment)
+//
+#define SET_OFFSET(pointer, word) WRITE_WORD((LPWORD)(pointer), (word))
+
+//
+// POINTER_FROM_POINTER - read a segmented pointer in the VDM from an address
+// pointed at by a flat 32-bit pointer. Convert the segmented pointer to a
+// flat pointer. SAME AS READ_FAR_POINTER
+//
+#define POINTER_FROM_POINTER(pointer) POINTER_FROM_WORDS(GET_SELECTOR(pointer), GET_OFFSET(pointer))
+
+//
+// LPSTR_FROM_POINTER - perform a POINTER_FROM_POINTER, casting the result to
+// a string pointer. SAME AS READ_FAR_POINTER
+//
+#define LPSTR_FROM_POINTER(pointer) ((LPSTR)POINTER_FROM_POINTER(pointer))
+
+//
+// LPBYTE_FROM_POINTER - perform a POINTER_FROM_POINTER, casting the result to
+// a byte pointer. SAME AS READ_FAR_POINTER
+//
+#define LPBYTE_FROM_POINTER(pointer) ((LPBYTE)POINTER_FROM_POINTER(pointer))
+
+//
+// SET_ERROR - sets the caller's AX register in the VDM context descriptor to
+// the value given and sets the caller's VDM carry flag
+//
+#define SET_ERROR(err) {setAX(err); setCF(1);}
+
+//
+// SET_SUCCESS - sets the VDM caller's AX register to NERR_Success and clears
+// the carry flag
+//
+#define SET_SUCCESS() {setAX(NERR_Success); setCF(0);}
+
+//
+// SET_OK - an explicit version of SET_SUCCESS wherein NERR_Success would be
+// an inappropriate error, although the right value
+//
+#define SET_OK(value) {setAX(value); setCF(0);}
+
+
+
+//
+// Miscellaneous macros for working out sizes of things
+//
+
+//
+// ARRAY_ELEMENTS - gives the number of elements of a particular type in an
+// array
+//
+
+#define ARRAY_ELEMENTS(a) (sizeof(a)/sizeof((a)[0]))
+
+//
+// LAST_ELEMENT - returns the index of the last element in array
+//
+
+#define LAST_ELEMENT(a) (ARRAY_ELEMENTS(a)-1)
+
+//
+// BITSIN - returns the number of bits in a data type or structure. This is
+// predicated upon the number of bits in a byte being 8 and all data types
+// being composed of a collection of bytes (safe assumption?)
+//
+#define BITSIN(thing) (sizeof(thing) * BITS_IN_A_BYTE)
+
+//
+// Miscellaneous other macros
+//
+
+//
+// IS_ASCII_PATH_SEPARATOR - returns TRUE if ch is / or \. ch is a single
+// byte (ASCII) character
+//
+#define IS_ASCII_PATH_SEPARATOR(ch) (((ch) == '/') || ((ch) == '\\'))
+
+//
+// macros for setting CF and ZF flags for return from hardware interrupt
+// callback
+//
+
+#define SET_CALLBACK_NOTHING() {setZF(0); setCF(0);}
+#define SET_CALLBACK_NAMEPIPE() {setZF(0); setCF(1);}
+#define SET_CALLBACK_DLC() {setZF(1); setCF(0);}
+#define SET_CALLBACK_NETBIOS() {setZF(1); setCF(1);}
+
+//
+// DLC-specific macros etc.
+//
+
+//extern LPVDM_REDIR_DOS_WINDOW lpVdmWindow;
+
+//
+// setPostRoutine - if dw is not 0 then we write the (DOS segmented) address of
+// the post routine into the dwPostRoutine field of the VDM_REDIR_DOS_WINDOW
+// structure passed to us at redir DLC initialization. We also set the flags
+// to indicate to the redir's hardware interrupt routine there is a DLC post
+// routine to run. If dw is 0 then we set the flags to indicate that there is
+// no post routine processing
+//
+/*
+#define setPostRoutine( dw ) if (dw) {\
+ (lpVdmWindow->dwPostRoutine = (DWORD)(dw));\
+ SET_CALLBACK_DLC();\
+ } else {\
+ SET_CALLBACK_NOTHING();\
+ }
+*/
+
+//
+// VR_ASYNC_DISPOSITION - we maintain a serialized list of these structures.
+// Used to dispose of VDM redir asynchronous completions in the order in which
+// they occurred
+//
+
+typedef struct _VR_ASYNC_DISPOSITION {
+
+ //
+ // Next - maintains a singly-linked list of dispositions
+ //
+
+ struct _VR_ASYNC_DISPOSITION* Next;
+
+ //
+ // AsyncDispositionRoutine - pointer to VOID function taking no args which
+ // will dispose of the next asynchronous completion - Netbios, named pipe
+ // or DLC
+ //
+
+ VOID (*AsyncDispositionRoutine)(VOID);
+} VR_ASYNC_DISPOSITION, *PVR_ASYNC_DISPOSITION;
+
+//
+// _inlinePointerFromWords - the POINTER_FROM_WORDS macro is inefficient if the
+// arguments are calls to eg. getES(), getBX() - the calls are made twice if
+// the pointer turns out to be non-zero. Use an inline function to achieve the
+// same results, but only call function arguments once
+//
+
+#ifdef i386
+
+__inline LPVOID _inlinePointerFromWords(WORD seg, WORD off) {
+
+ WORD _seg = seg;
+ WORD _off = off;
+
+ return ((_seg + _off) ? (LPVOID)((ULONG)(SELTOFLAT(_seg))+(ULONG)_off) : 0L); // OS2SS
+}
+
+#else
+LPVOID _inlinePointerFromWords(WORD seg, WORD off);
+#endif
+
+//
+// CONVERT_ADDRESS - convert a segmented (real or protect-mode) address to a
+// flat 32-bit address
+//
+
+//#define CONVERT_ADDRESS(seg, off, size, mode) !((WORD)(seg) | (WORD)(off)) ? 0 : Sim32GetVDMPointer((((DWORD)seg) << 16) + (DWORD)(off), (size), (mode))
+//#define CONVERT_ADDRESS(seg, off, size, mode) _inlineConvertAddress((WORD)(seg), (WORD)(off), (WORD)(size), (BOOLEAN)(mode))
+//
+//#ifdef i386
+//
+//__inline LPVOID _inlineConvertAddress(WORD Seg, WORD Off, WORD Size, BOOLEAN Pm) {
+//
+// WORD _seg = Seg;
+// WORD _off = Off;
+//
+// return (_seg | _off) ? Sim32GetVDMPointer(((DWORD)_seg << 16) + _off, Size, Pm) : 0;
+//}
+//
+//#else
+//extern LPVOID _inlineConvertAddress(WORD Seg, WORD Off, WORD Size, BOOLEAN Pm);
+//#endif
+
+#endif // _VDMREDIR_
diff --git a/private/os2/client/vrdebug.h b/private/os2/client/vrdebug.h
new file mode 100644
index 000000000..2d9053352
--- /dev/null
+++ b/private/os2/client/vrdebug.h
@@ -0,0 +1,603 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ vrdebug.h
+
+Abstract:
+
+ Contains defines for Vdm Redir Debugging info
+
+Author:
+
+ Richard L Firth (rfirth) 13-Feb-1992
+
+Notes:
+
+ Add new category for each new group of functions added for which external
+ debug control is required
+
+Revision History:
+
+--*/
+
+//
+// COMPILE-time debugging options:
+// definitions for debug flags. Each bit enables diagnostic printing/specific
+// debugging of corresponding module. Also overridden at run-time in DBG
+// version by having these flags in the VR= environment variable
+//
+
+#define DEBUG_MAILSLOT 0x00000001L // general Mailslots
+#define DEBUG_NAMEPIPE 0x00000002L // general Named Pipe
+#define DEBUG_NETAPI 0x00000004L // general NETAPI
+#define DEBUG_NETBIOS 0x00000008L // general NETBIOS
+#define DEBUG_DLC 0x00000010L // general DLC
+#define DEBUG_DOS_CCB_IN 0x00000020L // input DOS CCBs & parameter tables
+#define DEBUG_DOS_CCB_OUT 0x00000040L // output DOS CCBs & parameter tables
+#define DEBUG_NT_CCB_IN 0x00000080L // input NT CCBs & parameter tables
+#define DEBUG_NT_CCB_OUT 0x00000100L // output NT CCBs & parameter tables
+#define DEBUG_DLC_BUFFERS 0x00000200L // DLC buffer pools
+#define DEBUG_DLC_TX_DATA 0x00000400L // DLC transmit data
+#define DEBUG_DLC_RX_DATA 0x00000800L // DLC received data
+#define DEBUG_DLC_ASYNC 0x00001000L // DLC async call-backs
+#define DEBUG_TRANSACT_TX 0x00002000L // Transaction send data buffer(s)
+#define DEBUG_TRANSACT_RX 0x00004000L // Transaction receive data buffer(s)
+#define DEBUG_DLC_ALLOC 0x00008000L // dump alloc/free calls in DLC
+#define DEBUG_READ_COMPLETE 0x00010000L // dump CCB when READ completes
+#define DEBUG_ASYNC_EVENT 0x00020000L // dump asynchronous event info
+#define DEBUG_CMD_COMPLETE 0x00040000L // dump command complete event info
+#define DEBUG_TX_COMPLETE 0x00080000L // dump transmit complete event info
+#define DEBUG_RX_DATA 0x00100000L // dump data received event info
+#define DEBUG_STATUS_CHANGE 0x00200000L // dump DLC status change event info
+#define DEBUG_EVENT_QUEUE 0x00400000L // dump PutEvent, GetEvent and PeekEvent
+#define DEBUG_DOUBLE_TICKS 0x00800000L // multiply timer tick counts by 2
+#define DEBUG_DUMP_FREE_BUF 0x01000000L // dump buffer header on BUFFER.FREE
+#define DEBUG_CRITSEC 0x02000000L // dump enter/leave critical section info
+#define DEBUG_SUPERCRITICAL 0x04000000L // dump only stuff we absolutely need to know
+#define DEBUG_CRITICAL 0x08000000L // where #ifdef CRITICAL_DEBUGGING used to be
+#define DEBUG_TIME 0x10000000L // display relative time of events
+#define DEBUG_TO_FILE 0x20000000L // dump output to file VRDEBUG.LOG
+#define DEBUG_DLL 0x40000000L // general DLL stuff - init, terminate
+#define DEBUG_BREAKPOINT 0x80000000L // break everywhere there's a DEBUG_BREAK
+
+#define DEBUG_DOS_CCB (DEBUG_DOS_CCB_IN | DEBUG_DOS_CCB_OUT)
+
+#define VRDEBUG_FILE "VRDEBUG.LOG"
+
+#if DBG
+#include <stdio.h>
+//extern DWORD VrDebugFlags;
+DWORD VrDebugFlags;
+extern FILE* hVrDebugLog;
+
+extern VOID DbgOut(LPSTR, ...);
+
+#define IF_DEBUG(type) if (VrDebugFlags & DEBUG_##type)
+#define DEBUG_BREAK() IF_DEBUG(BREAKPOINT) { \
+ DbgPrint("BP %s.%d\n", __FILE__, __LINE__); \
+ DbgBreakPoint(); \
+ }
+#define DBGPRINT DbgOut
+#define DPUT(s) DBGPRINT(s)
+#define DPUT1(s, a) DBGPRINT(s, a)
+#define DPUT2(s, a, b) DBGPRINT(s, a, b)
+#define DPUT3(s, a, b, c) DBGPRINT(s, a, b, c)
+#define DPUT4(s, a, b, c, d) DBGPRINT(s, a, b, c, d)
+#define DPUT5(s, a, b, c, d, e) DBGPRINT(s, a, b, c, d, e)
+#define CRITDUMP(x) DbgPrint x
+#define DUMPCCB DumpCcb
+#else
+#define IF_DEBUG(type) if (0)
+#define DEBUG_BREAK()
+#define DBGPRINT
+#define DPUT(s)
+#define DPUT1(s, a)
+#define DPUT2(s, a, b)
+#define DPUT3(s, a, b, c)
+#define DPUT4(s, a, b, c, d)
+#define DPUT5(s, a, b, c, d, e)
+#define CRITDUMP(x)
+#define DUMPCCB
+#endif
+
+//
+// defaults
+//
+
+#define DEFAULT_STACK_DUMP 32
+
+//
+// numbers
+//
+
+#define NUMBER_OF_VR_GROUPS 5
+#define NUMBER_OF_CPU_REGISTERS 14
+#define MAX_ID_LEN 40
+#define MAX_DESC_LEN 256
+
+//
+// environment strings - shortened since they all go through to dos & dos can
+// only handle 1K of environment
+//
+
+#define ES_VRDEBUG "VRDBG" // "__VRDEBUG"
+#define ES_MAILSLOT "MS" // "MAILSLOT"
+#define ES_NAMEPIPE "NP" // "NAMEPIPE"
+#define ES_LANMAN "LM" // "LANMAN"
+#define ES_NETBIOS "NB" // "NETBIOS"
+#define ES_DLC "DLC" // "DLC"
+
+//
+// diagnostic controls - in same numerical order as TOKEN!!!
+//
+
+#define DC_BREAK "BRK" // "BREAK"
+#define DC_DISPLAYNAME "DN" // "DISPLAYNAME"
+#define DC_DLC ES_DLC
+#define DC_DUMPMEM "DM" // "DUMPMEM"
+#define DC_DUMPREGS "DR" // "DUMPREGS"
+#define DC_DUMPSTACK "DK" // "DUMPSTACK"
+#define DC_DUMPSTRUCT "DS" // "DUMPSTRUCT"
+#define DC_ERROR "E" // "ERROR"
+#define DC_ERRORBREAK "EB" // "ERRORBREAK"
+#define DC_INFO "I" // "INFO"
+#define DC_LANMAN ES_LANMAN
+#define DC_MAILSLOT ES_MAILSLOT
+#define DC_NAMEPIPE ES_NAMEPIPE
+#define DC_NETBIOS ES_NETBIOS
+#define DC_PAUSEBREAK "PB" // "PAUSEBREAK"
+#define DC_WARN "W" // "WARN"
+
+//
+// diagnostic categories (groups)
+//
+
+#define DG_ALL -1L // catch first enabled set
+#define DG_NONE 0 // no category
+#define DG_MAILSLOT 0x00000001L
+#define DG_NAMEPIPE 0x00000002L
+#define DG_LANMAN 0x00000004L
+#define DG_NETBIOS 0x00000008L
+#define DG_DLC 0x00000010L
+
+//
+// diagnostic index (in VrDiagnosticGroups array)
+//
+
+#define DI_MAILSLOT 0
+#define DI_NAMEPIPE 1
+#define DI_LANMAN 2
+#define DI_NETBIOS 3
+#define DI_DLC 4
+
+//
+// diagnostic control manifests
+//
+
+#define DM_INFORMATION 0x00010000L // display all info, warning and error messages
+#define DM_WARNING 0x00020000L // display warning and error messages
+#define DM_ERROR 0x00030000L // display error messages only
+#define DM_ERRORBREAK 0x00100000L // DbgBreakPoint() on error
+#define DM_PAUSEBREAK 0x00200000L // DbgBreakPoint() on pause (wait for developer)
+#define DM_DUMPREGS 0x00800000L // dump x86 registers when routine entered
+#define DM_DUMPREGSDBG 0x01000000L // dump x86 registers when routine entered, debug style
+#define DM_DUMPMEM 0x02000000L // dump DOS memory when routine entered
+#define DM_DUMPSTACK 0x04000000L // dump DOS stack when routine entered
+#define DM_DUMPSTRUCT 0x08000000L // dump a structure when routine entered
+#define DM_DISPLAYNAME 0x10000000L // display the function name
+#define DM_BREAK 0x80000000L // break when routine entered
+
+#define DM_DISPLAY_MASK 0x000f0000L
+
+//
+// enumerated types
+//
+
+////
+//// GPREG - General Purpose REGisters
+////
+//
+//typedef enum {
+// AX = 0,
+// BX,
+// CX,
+// DX,
+// SI,
+// DI,
+// BP,
+// SP
+//} GPREG;
+//
+////
+//// SEGREG - SEGment REGisters
+////
+//
+//typedef enum {
+// CS = 8,
+// DS,
+// ES,
+// SS
+//} SEGREG;
+//
+////
+//// SPREG - Special Purpose REGisters
+////
+//
+//typedef enum {
+// IP = 12,
+// FLAGS
+//} SPREG;
+//
+//typedef union {
+// SEGREG SegReg;
+// GPREG GpReg;
+// SPREG SpReg;
+//} REGISTER;
+
+typedef enum {
+ AX = 0,
+ BX = 1,
+ CX = 2,
+ DX = 3,
+ SI = 4,
+ DI = 5,
+ BP = 6,
+ SP = 7,
+ CS = 8,
+ DS = 9,
+ ES = 10,
+ SS = 11,
+ IP = 12,
+ FLAGS = 13
+} REGISTER;
+
+//
+// REGVAL - keeps a 16-bit value or a register specification, depending on
+// sense of IsRegister
+//
+
+typedef struct {
+ BOOL IsRegister;
+ union {
+ REGISTER Register;
+ WORD Value;
+ } RegOrVal;
+} REGVAL, *LPREGVAL;
+
+//
+// structures
+//
+
+//
+// CONTROL - keeps correspondence between control keyword and control flag
+//
+
+typedef struct {
+ char* Keyword;
+ DWORD Flag;
+} CONTROL;
+
+//
+// OPTION - keeps correspondence between diagnostic option and option type
+//
+
+typedef struct {
+ char* Keyword;
+ DWORD Flag;
+} OPTION;
+
+//
+// REGDEF - defines a register - keeps correspondence between name and type
+//
+
+typedef struct {
+ char RegisterName[3];
+ REGISTER Register;
+} REGDEF, *LPREGDEF;
+
+//
+// GROUPDEF - keeps correspondence between group name and index in
+// VrDiagnosticGroups array
+//
+
+typedef struct {
+ char* Name;
+ DWORD Index;
+} GROUPDEF;
+
+//
+// MEMORY_INFO - for each each memory dump we keep a record of its type, length
+// and starting address
+//
+
+typedef struct _MEMORY_INFO {
+ struct _MEMORY_INFO* Next;
+ REGVAL Segment;
+ REGVAL Offset;
+ REGVAL DumpCount;
+ BYTE DumpType;
+} MEMORY_INFO, *LPMEMORY_INFO;
+
+//
+// STRUCT_INFO - for each structure to be dumped we keep record of the segment
+// and offset registers and the string which describes the structure to be
+// dumped. The descriptor is similar to (but NOT THE SAME AS) the Rap
+// descriptor stuff
+//
+
+typedef struct _STRUCT_INFO {
+ struct _STRUCTINFO* Next;
+ char StructureDescriptor[MAX_DESC_LEN+1];
+ REGVAL Segment;
+ REGVAL Offset;
+} STRUCT_INFO, *LPSTRUCT_INFO;
+
+//
+// DIAGNOSTIC_INFO - information common to GROUP_DIAGNOSTIC and FUNCTION_DIAGNOSTIC
+//
+
+typedef struct {
+ DWORD OnControl;
+ DWORD OffControl;
+ MEMORY_INFO StackInfo; // special case of MemoryInfo
+ MEMORY_INFO MemoryInfo;
+ STRUCT_INFO StructInfo;
+} DIAGNOSTIC_INFO, *LPDIAGNOSTIC_INFO;
+
+//
+// GROUP_DIAGNOSTIC - because the groups are predefined, we don't keep any
+// name information, or a list - just NUMBER_OF_VR_GROUPS elements in an
+// array of GROUP_DIAGNOSTIC structures
+//
+
+typedef struct {
+ char GroupName[MAX_ID_LEN+1];
+ DIAGNOSTIC_INFO Diagnostic;
+} GROUP_DIAGNOSTIC, *LPGROUP_DIAGNOSTIC;
+
+//
+// FUNCTION_DIAGNOSTIC - if we want to diagnose a particular named function,
+// then we generate one of these. We keep a (unsorted) list of these if a
+// function description is parsed from the environment string(s)
+//
+
+typedef struct _FUNCTION_DIAGNOSTIC {
+ struct _FUNCTION_DIAGNOSTIC* Next;
+ char FunctionName[MAX_ID_LEN+1];
+ DIAGNOSTIC_INFO Diagnostic;
+} FUNCTION_DIAGNOSTIC, *LPFUNCTION_DIAGNOSTIC;
+
+//
+// structure descriptor characters (general purpose data descriptors)
+//
+
+#define SD_BYTE 'B' // 8-bits, displayed as hex (0a)
+#define SD_WORD 'W' // 16-bits, displayed as hex (0abc)
+#define SD_DWORD 'D' // 32-bits, displayed as hex (0abc1234)
+#define SD_POINTER 'P' // 32-bits, displayed as pointer (0abc:1234)
+#define SD_ASCIZ 'A' // asciz string, displayed as string "this is a string"
+#define SD_ASCII 'a' // asciz pointer, displayed as pointer, string 0abc:1234 "this is a string"
+#define SD_CHAR 'C' // ascii character, displayed as character 'c'
+#define SD_NUM 'N' // 8-bits, displayed as unsigned byte (0 to 255)
+#define SD_INT 'I' // 16-bits, displayed as unsigned word (0 to 65,535)
+#define SD_LONG 'L' // 32-bits, displayed as unsigned long (0 to 4,294,967,295)
+#define SD_SIGNED '-' // convert I,L,N to signed
+#define SD_DELIM ':' // name delimiter
+#define SD_FIELDSEP ';' // separates named fields
+#define SD_NAMESEP '/' // separates structure name from fields
+
+#define SD_CHARS {SD_BYTE, \
+ SD_WORD, \
+ SD_DWORD, \
+ SD_POINTER, \
+ SD_ASCIZ, \
+ SD_ASCII,\
+ SD_CHAR, \
+ SD_NUM, \
+ SD_INT, \
+ SD_LONG, \
+ SD_SIGNED}
+
+#define MD_CHARS {SD_BYTE, SD_WORD, SD_DWORD, SD_POINTER}
+
+//
+// token stuff
+//
+
+//
+// TOKEN - enumerated, alphabetically ordered tokens
+//
+
+typedef enum {
+ TLEFTPAREN = -6, // (
+ TRIGHTPAREN = -5, // )
+ TREGISTER = -4,
+ TNUMBER = -3,
+ TEOS = -2, // end of string
+ TUNKNOWN = -1, // unknown lexeme, assume routine name?
+
+ //
+ // tokens from here on down are also the index into DiagnosticTokens which
+ // describe them
+ //
+
+ TBREAK = 0,
+ TDISPLAYNAME,
+ TDLC,
+ TDUMPMEM,
+ TDUMPREGS,
+ TDUMPSTACK,
+ TDUMPSTRUCT,
+ TERROR,
+ TERRORBREAK,
+ TINFO,
+ TLANMAN,
+ TMAILSLOT,
+ TNAMEPIPE,
+ TNETBIOS,
+ TPAUSEBREAK,
+ TWARN
+} TOKEN;
+
+//
+// TIB (Token Info Bucket) - Contains info describing token found. Only filled
+// in when we find an identifier, number or a register
+//
+
+typedef struct {
+ LPSTR TokenStream;
+ TOKEN Token;
+ union {
+ REGVAL RegVal;
+ char Id[MAX_DESC_LEN+1];
+ } RegValOrId;
+} TIB, *LPTIB;
+
+//
+// DEBUG_TOKEN - maps from lexeme to token
+//
+
+typedef struct {
+ char* TokenString;
+ TOKEN Token;
+} DEBUG_TOKEN;
+
+//
+// what to expect when parsing strings
+//
+
+#define EXPECTING_NOTHING 0x00
+#define EXPECTING_REGVAL 0x01
+#define EXPECTING_MEMDESC 0x02
+#define EXPECTING_STRUCTDESC 0x04
+#define EXPECTING_LEFTPAREN 0x08
+#define EXPECTING_RIGHTPAREN 0x10
+#define EXPECTING_EOS 0x20
+#define EXPECTING_NO_ARGS 0x40
+
+//
+// data (defined in vrdebug.c)
+//
+
+//
+// VrDiagnosticGroups - an array of GROUP_DIAGNOSTIC structures
+//
+
+GROUP_DIAGNOSTIC VrDiagnosticGroups[NUMBER_OF_VR_GROUPS];
+
+//
+// FunctionList - linked list of FUNCTION_DIAGNOSTIC structures
+//
+
+LPFUNCTION_DIAGNOSTIC FunctionList;
+
+//
+// prototypes (in vrdebug.c)
+//
+
+VOID
+VrDebugInit(
+ VOID
+ );
+
+LPDIAGNOSTIC_INFO
+VrDiagnosticEntryPoint(
+ IN LPSTR FunctionName,
+ IN DWORD FunctionCategory,
+ OUT LPDIAGNOSTIC_INFO Info
+ );
+
+VOID
+VrPauseBreak(
+ LPDIAGNOSTIC_INFO Info
+ );
+
+VOID
+VrErrorBreak(
+ LPDIAGNOSTIC_INFO Info
+ );
+
+VOID
+VrPrint(
+ IN DWORD Level,
+ IN LPDIAGNOSTIC_INFO Context,
+ IN LPSTR Format,
+ IN ...
+ );
+
+VOID
+VrDumpRealMode16BitRegisters(
+ IN BOOL DebugStyle
+ );
+
+VOID
+VrDumpDosMemory(
+ IN BYTE Type,
+ IN DWORD Iterations,
+ IN WORD Segment,
+ IN WORD Offset
+ );
+
+VOID
+VrDumpDosMemoryStructure(
+ IN LPSTR Descriptor,
+ IN WORD Segment,
+ IN WORD Offset
+ );
+
+//
+//VOID
+//VrDumpDosStack(
+// IN DWORD Depth
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// Dumps <Depth> words from the Vdm stack, as addressed by getSS():getSP().
+// Uses VrDumpDosMemory to dump stack contents
+//
+//Arguments:
+//
+// Depth - number of 16-bit words to dump from DOS memory stack
+//
+//Return Value:
+//
+// None.
+//
+//--*/
+//
+
+#define VrDumpDosStack(Depth) VrDumpDosMemory('W', Depth, getSS(), getSP())
+
+//
+// macros used in routines to be diagnosed
+//
+
+#if DBG
+#define DIAGNOSTIC_ENTRY VrDiagnosticEntryPoint
+#define DIAGNOSTIC_EXIT VrDiagnosticExitPoint
+#define BREAK_ON_PAUSE VrPauseBreak
+#define BREAK_ON_ERROR VrErrorBreak
+//#define INFORM(s, ...) VrPrint(DM_INFORMATION, s, ...)
+//#define WARN(s, ...) VrPrint(DM_WARNING, s, ...)
+//#define ERROR(s, ...) VrPrint(DM_ERROR, s, ...)
+
+#else
+
+//
+// macros used in routines to be diagnosed - don't expand to anything in non-debug
+//
+
+#define DIAGNOSTIC_ENTRY
+#define DIAGNOSTIC_EXIT
+#define BREAK_ON_PAUSE
+#define BREAK_ON_ERROR
+//#define INFORM
+//#define WARN
+//#define ERROR
+#endif
diff --git a/private/os2/client/vrremote.c b/private/os2/client/vrremote.c
new file mode 100644
index 000000000..6294f0761
--- /dev/null
+++ b/private/os2/client/vrremote.c
@@ -0,0 +1,1831 @@
+/*++
+
+This file was modified to support 16 bit OS/2 netapi.dll for the OS/2 SS
+The documentation in this file will be updated.
+
+
+Copyright (c) 1987-1991 Microsoft Corporation
+
+Module Name:
+
+ vrremote.c
+
+Abstract:
+
+ This module contains a routine VrRemoteApi which is a 16-bit only version
+ of RxRemoteApi from the net\rpcxlate project. This routine supports remoted
+ lanman APIs from a Virtual Dos Machine.
+
+ This routine does not have to convert 32-16-32, but rather receives 16-bit
+ data and sends a 16-bit transaction packet either to a down-level server
+ or an NT-level server which must be running XactSrv to respond to this
+ request.
+
+ This routine and the support routines in vrremutl.c were lifted from the
+ lanman project
+
+ Note: since this is 32-bit code which deals with 16-bit data in a few places,
+ 32-bit data items should be used where possible and only use 16-bit items
+ where unavoidable
+
+ Contents of this file:
+
+ VrRemoteApi
+ VrTransaction
+ (VrpGetStructureSize)
+ (VrpGetArrayLength)
+ (VrpGetFieldSize)
+ (VrpConvertReceiveBuffer)
+ (VrpConvertVdmPointer)
+ (VrpPackSendBuffer)
+
+Author:
+
+ Richard L Firth (rfirth) 24-Oct-1991
+
+Environment:
+
+ Flat 32-bit, user space
+
+Revision History:
+
+ 21-Oct-1991 rfirth
+ Created
+
+--*/
+
+#define NTOS2SS 1
+
+#include <wchar.h>
+
+#include <nt.h>
+#include <ntrtl.h> // ASSERT, DbgPrint
+#include <nturtl.h>
+#include <windows.h>
+//#include <softpc.h> // x86 virtual machine definitions
+//#include <vrdlctab.h>
+#include <vdmredir.h> // common Vr stuff
+#include <lmcons.h> // LM20_PATHLEN
+#include <lmerr.h>
+#include <lmwksta.h> // NetWkstaGetInfo
+#include <lmapibuf.h> // NetApiBufferFree
+#include "apiworke.h" // REM_MAX_PARMS original is at private\net\rpcxlate\apiworke.h
+//#include <mvdm.h> // FETCHWORD
+#include <vrremote.h> // prototypes
+#include "remtypes.h"
+#include "smbgtpt.h"
+#include <rxp.h> // RxpTransactSmb
+#include <apinums.h> // API_W numbers
+#include <string.h>
+#include <vrdebug.h>
+
+#include <rxuser.h> // RxNetUser...
+#include <lmaccess.h> // USER_PASSWORD_PARMNUM
+#include <crypt.h> // Needed by NetUserPasswordSet
+
+#include "os2crt.h"
+
+#define DWORD unsigned long
+#define APIRET DWORD
+
+//
+// Global data.
+//
+
+unsigned short remapi_err_flag;
+
+
+//
+// external functions
+//
+
+NET_API_STATUS
+ GetLanmanSessionKey(
+ IN LPWSTR ServerName,
+ OUT LPBYTE pSessionKey
+ );
+
+DWORD UWstrlen(IN LPWSTR);
+
+//
+// internal functions (not necessarily private)
+//
+BOOL
+OemToUppercaseUnicode(
+ IN LPSTR AnsiStringPointer,
+ OUT LPWSTR UnicodeStringPointer,
+ IN DWORD MaxLength
+ );
+
+//
+// code
+//
+
+
+APIRET
+VrTransaction(
+ IN LPSTR ServerName,
+ IN LPBYTE SendParmBuffer,
+ IN DWORD SendParmBufLen,
+ IN LPBYTE SendDataBuffer,
+ IN DWORD SendDataBufLen,
+ OUT LPBYTE ReceiveParmBuffer,
+ IN DWORD ReceiveParmBufLen,
+ IN LPBYTE ReceiveDataBuffer,
+ IN OUT LPDWORD ReceiveDataBufLen,
+ IN BOOL NullSessionFlag
+ )
+
+/*++
+
+Routine Description:
+
+ Sends a transaction request to a server and receives a response
+
+Arguments:
+
+ ServerName - to send request to
+ SendParmBuffer - send parameters
+ SendParmBufLen - length of send parameters
+ SendDataBuffer - send data
+ SendDataBufLen - length of send data
+ ReceiveParmBuffer - receive parameter buffer
+ ReceiveParmBufLen - length of receive parameter buffer
+ ReceiveDataBuffer - where to receive data
+ ReceiveDataBufLen - length of data buffer
+ NullSessionFlag - set if we are to use a null session
+
+Return Value:
+
+ APIRET
+ Success - NERR_Success
+ Failure -
+
+--*/
+
+{
+ APIRET status;
+
+ status = RxpTransactSmb(ServerName,
+
+ //
+ // BUGBUG - transport name?
+ //
+
+ NULL,
+ SendParmBuffer,
+ SendParmBufLen,
+ SendDataBuffer,
+ SendDataBufLen,
+ ReceiveParmBuffer,
+ ReceiveParmBufLen,
+ ReceiveDataBuffer,
+ ReceiveDataBufLen,
+ NullSessionFlag
+ );
+ if (status == NERR_Success) {
+ }
+
+ return status;
+}
+
+
+APIRET
+VrRemoteApi(
+ IN DWORD ApiNumber,
+ IN LPBYTE ServerNamePointer,
+ IN LPSTR ParameterDescriptor,
+ IN LPSTR DataDescriptor,
+ IN LPSTR AuxDescriptor OPTIONAL,
+ IN BOOL NullSessionFlag
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and sends a 16-bit transaction SMB containing the
+ parameters and data required for a remoted function call. Any received
+ data is copied back into the caller's data space as 16-bit data. This
+ function is being called on behalf of a VDM process which in turn is
+ running as a virtual Intel 286 which means:
+
+ * little endian
+ * pointers are 32-bits <segment|selector>:<offset>
+ * stack is 16-bits wide and EXPANDS DOWN
+
+ This routine is called as a result of the NetIRemoteAPI function being
+ called in the VDM. This is an internal function and so the descriptor
+ parameters are trusted. However, if the original (16-bit) caller gave
+ us a bad buffer address or length then the results will be unpredictable.
+
+ The original API which called NetIRemoteAPI was a pascal calling convention
+ routine so if its parameter list was:
+
+ FAR PASCAL
+ NetRoutine(server_name, buffer_pointer, buffer_length, &bytes_read, &total);
+
+ the stack would look like this: (note: all pointers are far)
+
+ +----------------+
+ stack pointer => | ip | routine was called far
+ +----------------+
+ | cs |
+ +----------------+
+ | &total | Offset
+ +----------------+
+ | &total | Segment
+ +----------------+
+ | &bytes_read | Offset
+ +----------------+
+ | &bytes_read | Segment
+ +----------------+
+ | buffer_length |
+ +----------------+
+ | buffer_pointer | Offset
+ +----------------+
+ | buffer_pointer | Segment
+ +----------------+
+ | server_name | Offset
+ +----------------+
+ | server_name | Segment
+ +----------------+
+
+ Assumes:
+
+ BYTE is an 8-bit quantity
+ WORD is a 16-bit quantity
+ DWORD is a 32-bit quantity
+ LPSTR is a 32-bit flat pointer to an 8-bit quantity
+
+Arguments:
+
+ ApiNumber - Function number of the API required
+
+ ServerNamePointer - Flat 32-bit pointer to address of 32-bit segmented
+ far pointer to ASCIZ server name in Dos image.
+ Immediately prior to this is a pascal calling
+ convention stack of 16-bit caller parameters (see
+ above). The server name identifies the server at
+ which the API is to be executed
+
+ ParameterDescriptor - Flat 32-bit pointer to ASCIZ string which describes
+ caller parameters
+
+ DataDescriptor - Flat 32-bit pointer to ASCIZ string which describes
+ data structure in caller buffer (if any) or structure
+ of data returned from server
+
+ AuxDescriptor - Flat 32-bit pointer to ASCIZ string which describes
+ auxiliary data structures in send buffer (if any) or
+ structure of aux data returned from server
+
+ NullSessionFlag - TRUE if we are to use a NULL session
+
+Return Value:
+
+ APIRET
+ Success - 0
+ Failure - NERR_InternalError
+ Return this when we have a bad descriptor character or we
+ blow an internal limit. Basically if we return this its
+ safe to assume the DOS box handed us some garbage (typically
+ a descriptor string got trashed etc)
+
+--*/
+
+{
+
+//
+// redefine our parameter identifiers as old-code identifiers
+//
+
+#define api_num ApiNumber
+#define servername_ptr ServerNamePointer
+#define parm_str ParameterDescriptor
+#define data_str DataDescriptor
+#define aux_str AuxDescriptor
+
+//
+// define a macro to perform the buffer checking and length and pointer
+// manipulation. Either quits the routine and returns ERROR_INVALID_PARAMETER
+// or updates parm_len and parm_pos to indicate the next available positions
+// and makes this_parm_pos available as the current position to write into
+//
+
+#define CHECK_PARAMETERS(len) \
+{ \
+ parm_len += len; \
+ if (parm_len > sizeof(parm_buf)) { \
+ return ERROR_INVALID_PARAMETER; \
+ } \
+ this_parm_pos = parm_pos; \
+ parm_pos += len; \
+}
+
+ //
+ // 32-bit flat pointers and buffers
+ //
+
+ BYTE parm_buf[REM_MAX_PARMS]; // Parameter buffer
+ BYTE computerName[(CNLEN+3)*2]; // To keep the local computername
+ LPBYTE parm_pos; // Pointer into parm_buf
+ LPBYTE this_parm_pos; // next place to write in parm_buf
+ LPBYTE parm_ptr; // Ponter to stack parms
+ LPSTR l_parm; // Used to index parm_str
+ LPSTR l_data; // Used to index data_str
+ LPSTR l_aux; // Used to index aux_str
+ LPBYTE rcv_data_ptr; // Pointer to callers rcv buf
+ LPBYTE send_data_ptr; // Ptr to send buffer to use
+ LPBYTE wkstaInfo;
+ LPBYTE serverName;
+
+ //
+ // lengths - 32-bit variables (even though actual lengths are quite small)
+ //
+
+ DWORD parm_len; // Length of send parameters
+ DWORD ret_parm_len; // Length of expected parms
+ DWORD rcv_data_length; // Length of callers rcv buf
+ DWORD send_data_length; // Length of callers send buf
+ DWORD parm_num; // Callers value for parm_num
+ DWORD struct_size; // Size of fixed data struct
+ DWORD aux_size; // Size of aux data struct
+ DWORD num_struct; // Loop count for ptr fixup
+
+ //
+ // 16-bit quantities - only used when converting received 16-bit data in
+ // caller's receive buffer
+ //
+
+ WORD ReceiveBufferSelector;
+ WORD ReceiveBufferOffset;
+ WORD converter; // For pointer fixups
+
+ //
+ // various flags
+ //
+
+ BOOL rcv_dl_flag; // Expect return data flag
+ BOOL send_dl_flag; // Send data buffer flag
+ BOOL rcv_dp_flag; // rcv buf ptr present flag
+ BOOL send_dp_flag; // send buf ptr present flag
+ BOOL parm_num_flag; // API has a parm_num
+ BOOL alloc_flag;
+ BOOL UBufferAllocated = FALSE; // Unicode computername allocated
+
+ //
+ // misc. variables
+ //
+
+ DWORD aux_pos; // aux structure expected
+ DWORD no_aux_check; // check flag
+ int len; // General purpose length
+ API_RET_TYPE status; // Return status from remote
+
+ UNICODE_STRING uString;
+ ANSI_STRING aString;
+ LPWSTR uncName;
+ NTSTATUS ntstatus;
+
+
+ //
+ // Clear the internal error flag
+ //
+
+ remapi_err_flag = 0;
+
+ //
+ // Set found parameter flags to FALSE and ponters to NULL
+ //
+
+ rcv_dl_flag = FALSE;
+ send_dl_flag = FALSE;
+ rcv_dp_flag = FALSE;
+ alloc_flag = FALSE;
+ send_dp_flag = FALSE;
+ parm_num_flag = FALSE;
+ rcv_data_length = 0;
+ send_data_length= 0;
+ parm_num = 0;
+ rcv_data_ptr = NULL;
+ send_data_ptr = NULL;
+
+ //
+ // Set up parm_ptr to point to first of the callers parmeters
+ //
+
+ parm_ptr = servername_ptr;
+ parm_pos = parm_buf;
+ ret_parm_len = 2 * sizeof(WORD); /* Allow for return status & offset */
+
+
+ //
+ // parse parameter descriptor/build parameter buffer for transaction
+ // and get interesting information from 16-bit parameters
+ // When finished, the parameter buffer looks like this:
+ //
+ // <api_num><parm_desc><data_desc><parms>[<aux_desc>]
+ //
+ // Remember: DOS only deals with ASCII characters
+ // NIRM ?
+ //
+
+ *((LPWORD)parm_pos)++ = (WORD)ApiNumber;
+ parm_len = sizeof(WORD);
+
+ len = strlen(ParameterDescriptor) + 1;
+ parm_len += len;
+ if (parm_len > sizeof(parm_buf)) {
+ return NERR_InternalError;
+ }
+ l_parm = parm_pos;
+ RtlCopyMemory(parm_pos, ParameterDescriptor, len);
+ parm_pos += len;
+
+ len = strlen(DataDescriptor) + 1;
+ parm_len += len;
+ if (parm_len > sizeof(parm_buf)) {
+ return NERR_InternalError;
+ }
+ l_data = parm_pos;
+ RtlCopyMemory(parm_pos, DataDescriptor, len);
+ parm_pos += len;
+
+ //
+ // parse the parameter descriptor strings. Remember interesting things such
+ // as pointers to buffers, buffer lengths, etc.
+ //
+
+ for (; *l_parm != '\0'; l_parm++) {
+ switch(*l_parm) {
+ case REM_WORD:
+ CHECK_PARAMETERS(sizeof(WORD));
+ parm_ptr -= sizeof(WORD);
+ SmbMoveUshort((LPWORD)this_parm_pos, (LPWORD)parm_ptr);
+ break;
+
+ case REM_ASCIZ: {
+ LPSTR pstring;
+
+ //
+ // the parameter is a pointer to a string. Read the string
+ // pointer from the caller's stack then check the string proper.
+ // If the pointer is NULL, change the parameter descriptor sent
+ // in the SMB to indicate the pointer was NULL at this end
+ //
+
+ parm_ptr -= sizeof(LPSTR);
+ pstring = LPSTR_FROM_POINTER(parm_ptr);
+ if (pstring == NULL) {
+ *(l_parm) = REM_NULL_PTR;
+ break;
+ }
+ len = strlen(pstring) + 1;
+ CHECK_PARAMETERS(len);
+ RtlCopyMemory(this_parm_pos, pstring, len);
+ }
+ break;
+
+ case REM_BYTE_PTR:
+ case REM_WORD_PTR:
+ case REM_DWORD_PTR: {
+ LPBYTE pointer;
+
+ parm_ptr -= sizeof(LPBYTE);
+ pointer = LPBYTE_FROM_POINTER(parm_ptr);
+ if (pointer == NULL) {
+ *(l_parm) = REM_NULL_PTR; /* Indicate null pointer */
+ break;
+ }
+ len = VrpGetArrayLength(l_parm, &l_parm);
+ CHECK_PARAMETERS(len);
+ RtlCopyMemory(this_parm_pos, pointer, len);
+ }
+ break;
+
+
+ case REM_RCV_WORD_PTR:
+ case REM_RCV_BYTE_PTR:
+ case REM_RCV_DWORD_PTR: {
+ LPBYTE pointer;
+
+ parm_ptr -= sizeof(LPBYTE*);
+ pointer = LPBYTE_FROM_POINTER(parm_ptr);
+
+ //
+ // Added this test for a NULL pointer to allow for
+ // a reserved field (currently MBN) to be a recv
+ // pointer. - ERICPE 7/19/89
+ //
+
+ if (pointer == NULL) {
+ *(l_parm) = REM_NULL_PTR;
+ break;
+ }
+ ret_parm_len += VrpGetArrayLength(l_parm, &l_parm);
+ if (ret_parm_len > sizeof(parm_buf)) {
+ ASSERT(FALSE);
+ return NERR_InternalError;
+ }
+ }
+ break;
+
+ case REM_DWORD:
+ CHECK_PARAMETERS(sizeof(DWORD));
+ parm_ptr -= sizeof(DWORD);
+ SmbMoveUlong((LPDWORD)this_parm_pos, (LPDWORD)parm_ptr);
+ break;
+
+ case REM_RCV_BUF_LEN:
+ CHECK_PARAMETERS(sizeof(WORD));
+ parm_ptr -= sizeof(WORD);
+ SmbMoveUshort((LPWORD)this_parm_pos, (LPWORD)parm_ptr);
+ rcv_data_length = (DWORD)SmbGetUshort((LPWORD)parm_ptr);
+ rcv_dl_flag = TRUE;
+#ifdef VR_DIAGNOSE
+ DbgPrint("VrRemoteApi: rcv_data_length=%x\n", rcv_data_length);
+#endif
+ break;
+
+ case REM_RCV_BUF_PTR:
+ parm_ptr -= sizeof(LPBYTE);
+ ReceiveBufferOffset = GET_OFFSET(parm_ptr);
+ ReceiveBufferSelector = GET_SELECTOR(parm_ptr);
+ rcv_data_ptr = LPBYTE_FROM_POINTER(parm_ptr);
+ rcv_dp_flag = TRUE;
+#ifdef VR_DIAGNOSE
+ DbgPrint("VrRemoteApi: Off=%x, Sel=%x, data_ptr=%x\n",
+ ReceiveBufferOffset, ReceiveBufferSelector, rcv_data_ptr);
+#endif
+ break;
+
+ case REM_SEND_BUF_PTR:
+ parm_ptr -= sizeof(LPBYTE);
+ send_data_ptr = LPBYTE_FROM_POINTER(parm_ptr);
+ send_dp_flag = TRUE;
+ break;
+
+ case REM_SEND_BUF_LEN:
+ parm_ptr -= sizeof(WORD);
+ send_data_length = (DWORD)SmbGetUshort((LPWORD)parm_ptr);
+ send_dl_flag = TRUE;
+ break;
+
+ case REM_ENTRIES_READ:
+ ret_parm_len += sizeof(WORD);
+ if (ret_parm_len > sizeof(parm_buf)) {
+ ASSERT(FALSE);
+ return NERR_InternalError;
+ }
+ parm_ptr -= sizeof(LPBYTE);
+ break;
+
+ case REM_PARMNUM:
+ CHECK_PARAMETERS(sizeof(WORD));
+ parm_ptr -= sizeof(WORD);
+ parm_num = (DWORD)SmbGetUshort((LPWORD)parm_ptr);
+ SmbMoveUshort((LPWORD)this_parm_pos, (LPWORD)parm_ptr);
+ parm_num_flag = TRUE;
+ break;
+
+ case REM_FILL_BYTES:
+
+ //
+ // This is a rare type but is needed to ensure that the
+ // send paramteres are at least as large as the return
+ // parameters so that buffer management can be simplified
+ // on the server.
+ //
+
+ len = VrpGetArrayLength(l_parm, &l_parm);
+ CHECK_PARAMETERS(len);
+ break;
+
+ default: /* Could be a digit from NULL send array */
+ break;
+ }
+ }
+
+ //
+ // The parameter buffer now contains ;
+ // api_num - word
+ // parm_str - asciz, (NULL c,i,f,z identifiers replaced with Z.
+ // data_str - asciz
+ // parameters - as identified by parm_str.
+ //
+
+ //
+ // For the receive buffer there is no data to set up for the call
+ // but there might have been an REM_AUX_COUNT descriptor in data_str
+ // which requires the aux_str to be copied onto the end of the
+ // parameter buffer.
+ //
+
+ if (rcv_dp_flag || send_dp_flag) {
+ //
+ // Find the length of the fixed length portion of the data
+ // buffer.
+ //
+
+ struct_size = VrpGetStructureSize(l_data, &aux_pos);
+ if (aux_pos != -1) {
+ l_aux = aux_str;
+ len = strlen(l_aux) + 1; /* Length of aux descriptor */
+ CHECK_PARAMETERS(len);
+ RtlCopyMemory(this_parm_pos, aux_str, len);
+ aux_size = VrpGetStructureSize(l_aux, &no_aux_check);
+ if (no_aux_check != -1) { /* Error if N in aux_str */
+ ASSERT(FALSE);
+ return NERR_InternalError;
+ }
+ }
+ }
+
+ //
+ // For a send buffer the data pointed to in the fixed structure
+ // must be copied into the send buffer. Any pointers which already
+ // point in the send buffer are NULLed as it is illegal to use
+ // the buffer for the send data, it is our transport buffer.
+ // NOTE - if parmnum was specified the buffer contains only that
+ // element of the structure so no length checking is needed at this
+ // side. A parmnum for a pointer type means that the data is at the
+ // start of the buffer so there is no copying to be done.
+ //
+
+
+ if (send_dp_flag) {
+ //
+ // Only process buffer if no parm_num and this is not a block send
+ // (no data structure) or an asciz concatenation send
+ //
+
+ if ((parm_num == 0) && (*l_data != REM_DATA_BLOCK)) {
+ status = VrpPackSendBuffer(
+ &send_data_ptr,
+ &send_data_length,
+ &alloc_flag,
+ data_str,
+ aux_str,
+ struct_size,
+ aux_pos,
+ aux_size,
+ parm_num_flag,
+ FALSE
+ );
+ if (status != 0) {
+ return status;
+ }
+ }
+ }
+
+ //
+ // Check for an internal error prior to issuing the transaction
+ //
+
+ if (remapi_err_flag != 0) {
+ if (alloc_flag) {
+ LocalFree(send_data_ptr);
+ }
+ return NERR_InternalError;
+ }
+
+ //
+ // get the server name. If it is NULL then we are faking a local API call
+ // by making a remote call to XactSrv on this machine. Fill in our computer
+ // name
+ //
+
+ serverName = LPSTR_FROM_POINTER(servername_ptr);
+
+////////////////////////////////////////////////////////////////////////////////
+//// is this actually required any longer?
+
+ if ((serverName == NULL) || (*serverName == '\0')) {
+ status = NetWkstaGetInfo(NULL, 100L, &wkstaInfo);
+ if (status) {
+ if (alloc_flag) {
+ LocalFree(send_data_ptr);
+ }
+ return status;
+ } else {
+
+ //
+ // BUGBUG - Unicode - ASCII conversion here
+ //
+#ifndef NTOS2SS
+ computerName[0] = computerName[1] = '\\';
+ strcpy(computerName+2,
+ ((LPWKSTA_INFO_100)wkstaInfo)->wki100_computername);
+#else
+ NullSessionFlag = FALSE;
+ computerName[1] = computerName[3] = 0;
+ computerName[0] = computerName[2] = '\\';
+ wcscpy((unsigned short *)(computerName+4),
+ (unsigned short *)(((LPWKSTA_INFO_100)wkstaInfo)->wki100_computername));
+#endif
+ NetApiBufferFree(wkstaInfo);
+ serverName = computerName;
+#ifdef VR_DIAGNOSE
+ DbgPrint("VrRemoteApi: computername is %s\n", serverName);
+#endif
+ uncName = (unsigned short *)computerName;
+
+ }
+ }
+ else {
+ RtlInitAnsiString(&aString, serverName);
+ ntstatus = RtlAnsiStringToUnicodeString(&uString, &aString, (BOOLEAN)TRUE);
+ if (!NT_SUCCESS(ntstatus)) {
+
+#if DBG
+ IF_DEBUG(NETAPI) {
+ DbgPrint("VrRemoteApi: Unexpected situation: RtlAnsiStringToUnicodeString returns %x\n", ntstatus);
+ }
+#endif
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ uncName = uString.Buffer;
+ UBufferAllocated = TRUE;
+
+ }
+////////////////////////////////////////////////////////////////////////////////
+
+ //
+ // The parameter buffers and data buffers are now set up for
+ // sending to the API worker so call transact to send them.
+ //
+
+
+#if DBG
+ IF_DEBUG(NETAPI) {
+ DbgPrint("VrpTransactVdm: UncName=%ws\n", uncName);
+ }
+#endif
+
+ status = RxpTransactSmb((char *)uncName,
+
+ //
+ // BUGBUG - transport name?
+ //
+
+ NULL,
+ parm_buf, // Send parm buffer
+ parm_len, // Send parm length
+ send_data_ptr, // Send data buffer
+ send_data_length, // Send data length
+ parm_buf, // Rcv prm buffer
+ ret_parm_len, // Rcv parm length
+ rcv_data_ptr, // Rcv data buffer
+ &rcv_data_length, // Rcv data length
+ NullSessionFlag
+ );
+ if (UBufferAllocated) {
+ RtlFreeUnicodeString(&uString);
+ }
+
+ if (status) {
+#ifdef VR_DIAGNOSE
+ DbgPrint("Error: VrRemoteApi: RxpTransactSmb returns %d(%x)\n",
+ status, status);
+#endif
+ switch (status) {
+ case NERR_BufTooSmall: /* No data returned from API worker */
+ rcv_data_length = 0;
+ break;
+
+ case ERROR_MORE_DATA: /* Just a warning for the caller */
+ break;
+
+ case NERR_TooMuchData: /* Just a warning for the caller */
+ break;
+
+ default:
+ rcv_data_length = 0;
+ break;
+ }
+ }
+
+ /* The API call was successful. Now translate the return buffers
+ * into the local API format.
+ *
+ * First copy any data from the return parameter buffer into the
+ * fields pointed to by the original call parmeters.
+ * The return parameter buffer contains;
+ * status, (unsigned short)
+ * converter, (unsigned short)
+ * ... - fields described by rcv ptr types in parm_str
+ */
+
+ parm_pos = parm_buf + sizeof(WORD);
+ converter = (WORD)SmbGetUshort((LPWORD)parm_pos);
+ parm_pos += sizeof(WORD);
+
+ //
+ // Set up parm_ptr to point to first of the callers parmeters
+ //
+
+ parm_ptr = servername_ptr;
+
+ //
+ // set default value of num_struct to 1, if data, 0 if no data
+ //
+
+ num_struct = (DWORD)((*data_str == '\0') ? 0 : 1);
+
+ for (; *parm_str != '\0'; parm_str++) {
+ switch (*parm_str) {
+ case REM_RCV_WORD_PTR:
+ case REM_RCV_BYTE_PTR:
+ case REM_RCV_DWORD_PTR: {
+ LPBYTE ptr;
+
+ parm_ptr -= sizeof(LPBYTE*);
+ ptr = LPBYTE_FROM_POINTER(parm_ptr);
+
+ //
+ // if the rcv buffer given to us by the user is NULL,
+ // (one currently can be - it is an MBZ parameter for
+ // now in the log read apis...), don't attempt to
+ // copy anything. len will be garbage in this
+ // case, so don't update parm_pos either. All we
+ // use VrpGetArrayLength for is to update parm_str if
+ // the parameter was NULL.
+ //
+
+ if (ptr != NULL) {
+ len = VrpGetArrayLength(parm_str, &parm_str);
+ RtlCopyMemory(ptr, parm_pos, len);
+
+ //
+ // This gross hack is to fix the problem that a
+ // down level spooler (Lan Server 1.2)
+ // do not perform level checking
+ // on the w functions of the api(s):
+ // DosPrintQGetInfo
+ // and thus can return NERR_Success
+ // and bytesavail == 0. This combination
+ // is technically illegal, and results in
+ // us attempting to unpack a buffer full of
+ // garbage. The following code detects this
+ // condition and resets the amount of returned
+ // data to zero so we do not attempt to unpack
+ // the buffer. Since we know the reason for the
+ // mistake at the server end is that we passed
+ // them a new level, we return ERROR_INVALID_LEVEL
+ // in this case.
+ // ERICPE, 5/16/90.
+ //
+
+ if ((api_num == API_WPrintQGetInfo)
+ && (status == NERR_Success)
+ && (*parm_str == REM_RCV_WORD_PTR)
+ && (*(LPWORD)ptr == 0)) {
+ rcv_data_length = 0;
+ status = ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // END OF GROSS HACK
+ //
+
+ parm_pos += len;
+ }
+ }
+ break;
+
+ case REM_ENTRIES_READ: {
+ LPWORD wptr;
+
+ parm_ptr -= sizeof(LPWORD*);
+ wptr = (LPWORD)POINTER_FROM_POINTER(parm_ptr);
+ num_struct = (DWORD)SmbGetUshort((LPWORD)parm_pos);
+ SmbPutUshort((LPWORD)wptr, (WORD)num_struct);
+ parm_pos += sizeof(WORD);
+ }
+ break;
+
+ case REM_FILL_BYTES:
+ //
+ // Special case, this was not really an input parameter
+ // so parm_ptr does not get changed. However, the parm_str
+ // pointer must be advanced past the descriptor field so
+ // use get VrpGetArrayLength to do this but ignore the
+ // return length.
+ //
+
+ VrpGetArrayLength(parm_str, &parm_str);
+ break;
+
+ default:
+ //
+ // If the descriptor was not a rcv pointer type then step
+ // over the parmeter pointer.
+ //
+
+ parm_ptr -= VrpGetFieldSize(parm_str, &parm_str);
+ }
+ }
+
+ //
+ // Now convert all pointer fields in the receive buffer to local
+ // pointers.
+ //
+
+ if (rcv_dp_flag && (rcv_data_length != 0)) {
+ VrpConvertReceiveBuffer(
+ rcv_data_ptr, // lp
+ ReceiveBufferSelector, // word
+ ReceiveBufferOffset, // word
+ converter, // word
+ num_struct, // dword
+ data_str, // lp
+ aux_str // lp
+ );
+ }
+
+ if (alloc_flag) {
+ LocalFree(send_data_ptr);
+ }
+
+ if (remapi_err_flag != 0) {
+ return NERR_InternalError;
+ }
+
+ return status;
+}
+
+
+DWORD
+VrpGetStructureSize(
+ IN LPSTR Descriptor,
+ IN LPDWORD AuxOffset
+ )
+
+/*++
+
+Routine Description:
+
+ Calculates the length of the fixed portion of a structure, based on the
+ descriptor for that structure
+
+Arguments:
+
+ Descriptor - pointer to ASCIZ data descriptor string
+ AuxOffset - pointer to returned dword which is relative position in the
+ data descriptor where a REM_AUX_NUM descriptor was found
+ This will be set to -1 if no aux descriptor found
+
+Return Value:
+
+ Length in bytes of structure described by Descriptor
+
+--*/
+
+{
+ DWORD length;
+ char c;
+
+ *AuxOffset = (DWORD)(-1);
+ for (length = 0; (c = *Descriptor) != '\0'; Descriptor++) {
+ if (c == REM_AUX_NUM) {
+ *AuxOffset = length;
+ length += sizeof(WORD);
+ } else {
+ length += VrpGetFieldSize(Descriptor, &Descriptor);
+ }
+ }
+ return length;
+}
+
+
+DWORD
+VrpGetArrayLength(
+ IN LPSTR Descriptor,
+ IN LPSTR* pDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Calculates the length of an array described by an element of a
+ descriptor string and update the descriptor string pointer to point
+ to the last char in the element of the descriptor string.
+
+Arguments:
+
+ Descriptor - pointer to ASCIZ descriptor string
+ pDescriptor - pointer to address of Descriptor
+
+Return Value:
+
+ Length in bytes of array described by Descriptor
+
+--*/
+
+{
+ DWORD num_elements;
+ DWORD element_length;
+
+ //
+ // First set length of an element in the array
+ //
+
+ switch (*Descriptor) {
+ case REM_WORD:
+ case REM_WORD_PTR:
+ case REM_RCV_WORD_PTR:
+ element_length = sizeof(WORD);
+ break;
+
+ case REM_DWORD:
+ case REM_DWORD_PTR:
+ case REM_RCV_DWORD_PTR:
+ element_length = sizeof(DWORD);
+ break;
+
+ case REM_BYTE:
+ case REM_BYTE_PTR:
+ case REM_RCV_BYTE_PTR:
+ case REM_FILL_BYTES:
+ element_length = sizeof(BYTE);
+ break;
+
+ //
+ // Warning: following fixes a bug in which "b21" type
+ // combinations in parmeter string will be
+ // handled correctly when pointer to such "bit map"
+ // in the struct is NULL. These two dumbos could
+ // interfere so we force a success return.
+ //
+
+ case REM_ASCIZ:
+ case REM_SEND_LENBUF:
+ case REM_NULL_PTR:
+ return 0;
+
+ default:
+ remapi_err_flag = NERR_InternalError;
+ ASSERT(FALSE);
+ return 0;
+ }
+
+ //
+ // Now get numeber of elements in the array
+ //
+
+ for (num_elements = 0, Descriptor++;
+ (*Descriptor <= '9') && (*Descriptor >= '0');
+ Descriptor++, (*pDescriptor)++) {
+ num_elements = (WORD)((10 * num_elements) + ((WORD)*Descriptor - (WORD)'0'));
+ }
+
+ return (num_elements == 0) ? element_length : element_length * num_elements;
+}
+
+
+DWORD
+VrpGetFieldSize(
+ IN LPSTR Descriptor,
+ IN LPSTR* pDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Calculates the length of an field described by an element of a
+ descriptor string and update the descriptor string pointer to point
+ to the last char in the element of the descriptor string.
+
+Arguments:
+
+ Descriptor - pointer to the descriptor string
+ pDescriptor - pointer to the address of the descriptor. On exit
+ this points to the last character in the descriptor
+ just parsed
+
+Return Value:
+
+ Length in bytes of the field parsed
+
+--*/
+
+{
+ char c;
+
+ c = *Descriptor;
+ if (IS_POINTER(c) || (c == REM_NULL_PTR)) { /* All pointers same size */
+ while (*(++Descriptor) <= '9' && *Descriptor >= '0') {
+ (*pDescriptor)++; /* Move ptr to end of field size */
+ }
+ return sizeof(LPSTR);
+ }
+
+ //
+ // Here if descriptor was not a pointer type so have to find the field
+ // length specifically
+ //
+
+ switch (c) {
+ case REM_WORD:
+ case REM_BYTE:
+ case REM_DWORD:
+ return VrpGetArrayLength(Descriptor, pDescriptor);
+
+ case REM_AUX_NUM:
+ case REM_PARMNUM:
+ case REM_RCV_BUF_LEN:
+ case REM_SEND_BUF_LEN:
+ return sizeof(WORD);
+
+ case REM_DATA_BLOCK:
+ case REM_IGNORE:
+ return 0; /* No structure for this */
+
+ case REM_DATE_TIME:
+ return sizeof(DWORD);
+
+ default:
+ remapi_err_flag = NERR_InternalError;
+#ifdef VR_DIAGNOSE
+ DbgPrint("VrpGetFieldSize: offending descriptor is '%c'\n", c);
+#endif
+ ASSERT(FALSE);
+ return 0;
+ }
+}
+
+
+VOID
+VrpConvertReceiveBuffer(
+ IN LPBYTE ReceiveBuffer,
+ IN WORD BufferSelector,
+ IN WORD BufferOffset,
+ IN WORD ConverterWord,
+ IN DWORD NumberStructs,
+ IN LPSTR DataDescriptor,
+ IN LPSTR AuxDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ All pointers in the receive buffer are returned from the API worker as
+ pointers into the buffer position given to the API on the API worker's
+ station. In order to convert them into local pointers the segment
+ of each pointer must be set to the segment of the rcv buffer and the offset
+ must be set to;
+
+ offset of rcv buffer + offset of pointer - converter word.
+
+ This routine steps through the receive buffer and calls VrpConvertVdmPointer
+ to perform the above pointer conversions.
+
+Arguments:
+
+ ReceiveBuffer - 32-bit flat pointer to 16-bit DOS buffer
+ BufferSelector - 16-bit selector of Dos receive buffer
+ BufferOffset - 16-bit offset of Dos receive buffer
+ ConverterWord - From API worker
+ NumberStructs - Entries read parm (or 1 for GetInfo)
+ DataDescriptor - String for data format
+ AuxDescriptor - string for aux format
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LPSTR l_data;
+ LPSTR l_aux;
+ DWORD num_aux;
+ DWORD i, j;
+ char c;
+
+
+ for (i = 0; i < NumberStructs; i++) {
+ //
+ // convert all pointers in next primary; if we hit a aux word count
+ // remember number of secondary structures
+ //
+
+ for (l_data = DataDescriptor, num_aux = 0; c = *l_data; l_data++) {
+ if (c == REM_AUX_NUM) {
+ num_aux = (DWORD)*(ULPWORD)ReceiveBuffer;
+ }
+ if (IS_POINTER(c)) {
+ VrpConvertVdmPointer(
+ (ULPWORD)ReceiveBuffer,
+ BufferSelector,
+ BufferOffset,
+ ConverterWord
+ );
+ }
+ ReceiveBuffer += VrpGetFieldSize(l_data, &l_data);
+ }
+
+ //
+ // convert any pointers in any returned secondary (aux) structures
+ //
+
+ for (j = 0; j < num_aux; j++) {
+ for (l_aux = AuxDescriptor; c = *l_aux; l_aux++) {
+ if (IS_POINTER(c)) {
+ VrpConvertVdmPointer(
+ (ULPWORD)ReceiveBuffer,
+ BufferSelector,
+ BufferOffset,
+ ConverterWord
+ );
+ }
+ ReceiveBuffer += VrpGetFieldSize(l_aux, &l_aux);
+ }
+ }
+ }
+}
+
+
+VOID
+VrpConvertVdmPointer(
+ IN ULPWORD TargetPointer,
+ IN WORD BufferSegment,
+ IN WORD BufferOffset,
+ IN WORD ConverterWord
+ )
+
+/*++
+
+Routine Description:
+
+ All pointers in the receive buffer are returned from the API worker as
+ pointers into the buffer position given to to the API on the API worker's
+ station. In order to convert them into local pointers the segment
+ of each pointer must be set to the segment of the rcv buffer and the offset
+ must be set to;
+
+ offset of rcv buffer + offset of pointer - converter word.
+
+ The pointer is not converted if it is NULL
+
+Arguments:
+
+ TargetPointer - 32-bit flat pointer to segmented Dos pointer to convert
+ BufferSegment - 16-bit selector/segment of target buffer in DOS image
+ BufferOffset - 16-bit offset within BufferSegment where buffer starts
+ ConverterWord - 16-bit offset converter word from API worker on server
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WORD offset;
+
+ if (*((UCHAR * UNALIGNED *)TargetPointer) != NULL) {
+ SET_SELECTOR(TargetPointer, BufferSegment);
+ offset = GET_OFFSET(TargetPointer) - ConverterWord;
+ SET_OFFSET(TargetPointer, BufferOffset + offset);
+ }
+}
+
+
+APIRET
+VrpPackSendBuffer(
+ IN OUT LPBYTE* SendBufferPtr,
+ IN OUT LPDWORD SendBufLenPtr,
+ OUT LPBOOL SendBufferAllocated,
+ IN OUT LPSTR DataDescriptor,
+ IN LPSTR AuxDescriptor,
+ IN DWORD StructureSize,
+ IN DWORD AuxOffset,
+ IN DWORD AuxSize,
+ IN BOOL SetInfoFlag,
+ IN BOOL OkToModifyDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ For a send buffer the data pointed to in the fixed structure
+ must be copied into the send buffer. Any pointers which already
+ point in the send buffer are NULLed ( or errored if the call is not
+ a SetInfo type) as it is illegal to use the buffer for the send data,
+ it is our transport buffer
+
+ Note that if the caller's (VDM) buffer is large enough, the variable data
+ will be copied there. Eg. if the caller is doing a NetUseAdd which has a
+ 26 byte fixed structure (use_info_1) and they placed that structure in a
+ 1K buffer, the remote name will be copied into their own buffer at offset 26.
+
+ The data pointed to is in 16-bit little-endian format; any pointers are
+ segmented 16:16 pointers combined in the (thankfully) imitable intel way
+ to result in a 20-bit linear (virtual) address
+
+ If this function fails, the caller's buffer pointer and length will not
+ have altered. If it succeeds however, *SendBufferPtr and *SendBufLenPtr
+ may be different to the values passed, depending on whether
+ *SendBufferAllocated is TRUE
+
+Arguments:
+
+ SendBufferPtr - pointer to pointer to caller's 16-bit send buffer.
+ We may be able to satisfy the send from this buffer
+ if the data is simple (ie no structures to send). If
+ we have to send structured data then we may have to
+ allocate a new buffer in this routine because we need
+ to move all of the caller's data into one buffer and
+ (s)he may not have allocated enough space to hold
+ everything. Additionally, we cannot assume that we
+ can write the caller's data into their own buffer!
+
+ SendBufLenPtr - pointer to the length of the allocated buffer. If
+ we allocate a buffer in this routine, this length
+ will alter
+
+ SendBufferAllocated - pointer to a flag which will get set (TRUE) if we do
+ actually allocate a buffer in this routine
+
+ DataDescriptor - pointer to ASCIZ string which describes the primary
+ data structure in the buffer. This may be updated if
+ NULL pointers are found where a REM_ASCIZ descriptor
+ designates a string pointer
+
+ AuxDescriptor - pointer to ASCIZ string which describes the secondary
+ data structure in the buffer
+
+ StructureSize - the size (in bytes) of the fixed portion of the
+ primary data structure
+
+ AuxOffset - offset to the REM_AUX_NUM descriptor ('N') within the
+ data descriptor, or -1 if there isn't one
+
+ AuxSize - size in bytes of the fixed part of the secondary data
+ structure, if any
+
+ SetInfoFlag - indication of whether the API was a SetInfo call
+
+ OkToModifyDescriptor- TRUE if we can modify REM_ASCIZ descriptor chars to
+ REM_NULL_PTR in DataDescriptor, if a NULL pointer is
+ found in the structure. Used by VrNet routines which
+ are not calling VrRemoteApi
+
+Return Value:
+
+ APIRET
+ Success - NERR_Success
+ Failure - ERROR_NOT_ENOUGH_MEMORY
+ NERR_BufTooSmall
+--*/
+
+{
+
+ LPBYTE struct_ptr;
+ LPBYTE c_send_buf;
+ LPBYTE send_ptr;
+ DWORD c_send_len;
+ DWORD buf_length;
+ DWORD to_send_len;
+ DWORD num_aux;
+ LPSTR data_ptr;
+ LPSTR l_dsc;
+ LPSTR l_str;
+ BOOL alloc_flag = FALSE;
+ DWORD num_struct;
+ DWORD len;
+ UCHAR c;
+ DWORD numberOfStructureTypes;
+ DWORD i, j;
+ LPBYTE ptr;
+
+ //
+ // Make local copies of the original start and length of the caller's
+ // buffer as the originals may change if malloc is used but they
+ // will still be needed for the F_RANGE check.
+ //
+
+ struct_ptr = c_send_buf = send_ptr = *SendBufferPtr;
+ c_send_len = buf_length = *SendBufLenPtr;
+
+ if ((buf_length < StructureSize) || (AuxOffset == StructureSize)) {
+ return NERR_BufTooSmall;
+ }
+
+ //
+ // if the offset to the REM_AUX_NUM descriptor is not -1 then we have
+ // associated secondary structures with this primary. The actual number
+ // is embedded in the primary structure. Retrieve it
+ //
+
+ if (AuxOffset != -1) {
+ num_aux = (DWORD)SmbGetUshort((LPWORD)(send_ptr + AuxOffset));
+ to_send_len = StructureSize + (num_aux * AuxSize);
+ if (buf_length < to_send_len) {
+ return NERR_BufTooSmall;
+ }
+ numberOfStructureTypes = 2;
+ } else {
+ to_send_len = StructureSize;
+ num_aux = AuxSize = 0;
+ numberOfStructureTypes = 1;
+ }
+
+ //
+ // Set up the data pointer to point past fixed length structures
+ //
+
+ data_ptr = send_ptr + to_send_len;
+
+ //
+ // Any data pointed to by pointers in the data or aux structures
+ // must now be copied into the buffer. Start with the primary data
+ // structure.
+ //
+
+ l_str = DataDescriptor;
+ num_struct = 1; /* Only one primary structure allowed */
+
+ for (i = 0; i < numberOfStructureTypes;
+ l_str = AuxDescriptor, num_struct = num_aux, i++) {
+ for (j = 0 , l_dsc = l_str; j < num_struct; j++, l_dsc = l_str) {
+ for (; (c = *l_dsc) != '\0'; l_dsc++) {
+ if (IS_POINTER(c)) {
+ ptr = LPBYTE_FROM_POINTER(struct_ptr);
+ if (ptr == NULL) {
+ if ((*l_dsc == REM_ASCIZ) && OkToModifyDescriptor) {
+#ifdef VR_DIAGNOSE
+ DbgPrint("VrpPackSendBuffer: modifying descriptor to REM_NULL_PTR\n");
+#endif
+ *l_dsc = REM_NULL_PTR;
+ }
+ struct_ptr += sizeof(LPBYTE);
+ VrpGetArrayLength(l_dsc, &l_dsc);
+ } else {
+
+ //
+ // If the pointer is NULL or points inside the
+ // original send buffer ( may have been reallocated)
+ // then NULL it as it is not a field being set OR
+ // return an error for a non SetInfo type call as
+ // it is illegal to have a pointer into the
+ // transport buffer.
+ //
+
+ if (RANGE_F(ptr, c_send_buf, c_send_len)) {
+ if (SetInfoFlag) {
+ SmbPutUlong((LPDWORD)struct_ptr, 0L);
+ VrpGetArrayLength(l_dsc, &l_dsc);
+ struct_ptr += sizeof(LPSTR);
+ } else {
+ return ERROR_INVALID_PARAMETER;
+ }
+ } else {
+ switch (c) {
+ case REM_ASCIZ:
+ len = strlen(ptr) + 1;
+ break;
+
+ case REM_SEND_LENBUF:
+ len = *(LPWORD)ptr;
+ break;
+
+ default:
+ len = VrpGetArrayLength(l_dsc, &l_dsc);
+ }
+
+ //
+ // There is data to be copied into the send
+ // buffer so check that it will fit.
+ //
+
+ to_send_len += len;
+ if (to_send_len > buf_length) {
+ buf_length = to_send_len + BUF_INC;
+ if (!alloc_flag) {
+
+ //
+ // Need new buffer
+ //
+
+ send_ptr = (LPBYTE)LocalAlloc(LMEM_FIXED, buf_length);
+ if (send_ptr == NULL) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ alloc_flag = TRUE;
+
+ //
+ // Got new buffer, so copy old buffer
+ //
+
+ RtlCopyMemory(send_ptr, c_send_buf, to_send_len - len);
+ struct_ptr = send_ptr + (struct_ptr - c_send_buf);
+ data_ptr = send_ptr + (data_ptr - c_send_buf);
+ } else {
+ LPBYTE newPtr;
+
+ newPtr = (LPBYTE)LocalReAlloc(send_ptr, buf_length, LMEM_MOVEABLE);
+ if (newPtr == NULL) {
+ LocalFree(send_ptr);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ } else if (newPtr != send_ptr) {
+
+ //
+ // fix up the pointers
+ //
+
+ data_ptr = newPtr + (data_ptr - send_ptr);
+ struct_ptr = newPtr + (struct_ptr - send_ptr);
+ send_ptr = newPtr;
+ }
+ }
+ }
+
+ //
+ // There is room for new data in buffer so copy
+ // it and and update the struct and data ptrs
+ //
+
+ RtlCopyMemory(data_ptr, ptr, len);
+ data_ptr += len;
+ struct_ptr += sizeof(LPBYTE);
+ }
+ }
+ } else {
+
+ //
+ // If the descriptor was not a pointer type then step
+ // over the corresponding data field.
+ //
+
+ struct_ptr += VrpGetFieldSize(l_dsc, &l_dsc);
+ }
+ }
+ }
+ }
+
+ *SendBufferPtr = send_ptr;
+
+ //
+ // Note that this is potentially incorrect: we are actually returning the
+ // size of the structure + dynamic data to be sent, which is probably not
+ // the same as the size of the buffer we (re)allocated. This is how it is
+ // done in Lanman, so we'll do the same thing until it breaks
+ //
+
+ *SendBufLenPtr = to_send_len;
+ *SendBufferAllocated = alloc_flag;
+
+ return NERR_Success;
+}
+
+APIRET
+VrEncryptSES(
+ IN LPSTR ServerNamePointer,
+ IN LPSTR passwordPointer, // Input password (Not encripted)
+ IN LPSTR encryptedLmOwfPassword // output password (encripted)
+ )
+{
+ APIRET rc;
+
+ CHAR aPassword[ENCRYPTED_PWLEN];
+// LPBYTE parameterPointer;
+// DWORD passwordEncrypted;
+// DWORD passwordLength;
+
+ LM_OWF_PASSWORD lmOwfPassword;
+ LM_SESSION_KEY lanmanKey;
+// ENCRYPTED_LM_OWF_PASSWORD encryptedLmOwfPassword; parm #2
+ NTSTATUS ntStatus;
+ WCHAR uServerName[(LM20_CNLEN + 1)*2];
+ DWORD length;
+ LPSTR lpServerName;
+ LPBYTE BufPtr;
+// PWKSTA_USER_INFO_1 pInfo1;
+ PWKSTA_INFO_100 pInfo2;
+
+
+ RtlCopyMemory(aPassword,
+ passwordPointer,
+ ENCRYPTED_PWLEN);
+
+ //
+ // BUGBUG, this isn't necessarily the correct upper-case function
+ //
+
+ strupr(aPassword);
+
+
+ if ((ServerNamePointer == NULL) || (*ServerNamePointer == '\0')) {
+ //
+ // get server name.
+ //
+ rc = NetWkstaGetInfo(NULL, 100L, &BufPtr);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ pInfo2 = (PWKSTA_INFO_100) BufPtr;
+
+ length = UWstrlen((LPWSTR)pInfo2->wki100_computername);
+ wcscpy((unsigned short *)(uServerName+2),
+ (unsigned short *)(((LPWKSTA_INFO_100)pInfo2)->wki100_computername));
+
+ uServerName[0]=uServerName[1]='\\';
+
+ NetApiBufferFree(BufPtr);
+ } else {
+
+ //
+ // convert the ANSI server name to UNICODE for GetLanmanSessionKey
+ //
+
+ lpServerName = ServerNamePointer;
+ ntStatus = RtlOemToUnicodeN(uServerName,
+ sizeof(uServerName) - sizeof(uServerName[0]),
+ &length,
+ lpServerName,
+ strlen(lpServerName)
+ );
+ if (NT_SUCCESS(ntStatus)) {
+ uServerName[length/sizeof(uServerName[0])] = 0;
+ } else {
+ return ( ERROR_INVALID_PARAMETER );
+ }
+
+ }
+ ntStatus = RtlCalculateLmOwfPassword(aPassword, &lmOwfPassword);
+ if (NT_SUCCESS(ntStatus)) {
+ ntStatus = GetLanmanSessionKey((LPWSTR)uServerName, (LPBYTE)&lanmanKey);
+ if (NT_SUCCESS(ntStatus)) {
+ ntStatus = RtlEncryptLmOwfPwdWithLmSesKey(&lmOwfPassword,
+ &lanmanKey,
+ (PENCRYPTED_LM_OWF_PASSWORD) encryptedLmOwfPassword
+ );
+ }
+ }
+ return(ntStatus);
+}
+
+APIRET
+NetIUserPasswordSet(
+ IN LPSTR ServerNamePointer,
+ IN LPSTR UserNamePointer,
+ IN LPSTR OldPasswordPointer, // Input password (Not encripted)
+ IN LPSTR NewPasswordPointer // output password (encripted))
+ )
+{
+ APIRET rc;
+
+ WCHAR uServerName[(LM20_UNCLEN + 1)*2];
+ WCHAR uUserName[(LM20_UNLEN + 1)*2];
+ WCHAR uOldPassword[(LM20_PWLEN + 1)*2];
+ WCHAR uNewPassword[(LM20_PWLEN + 1)*2];
+ NTSTATUS ntStatus;
+ DWORD length;
+// LPSTR ansiStringPointer;
+ LPBYTE BufPtr;
+// PWKSTA_USER_INFO_1 pInfo1;
+ PWKSTA_INFO_100 pInfo2;
+
+ if ((ServerNamePointer == NULL) || (*ServerNamePointer == '\0')) {
+ //
+ // get server name.
+ //
+ rc = NetWkstaGetInfo(NULL, 100L, &BufPtr);
+
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ pInfo2 = (PWKSTA_INFO_100) BufPtr;
+
+ length = UWstrlen((LPWSTR)pInfo2->wki100_computername);
+ wcscpy((unsigned short *)(uServerName+2),
+ (unsigned short *)(((LPWKSTA_INFO_100)pInfo2)->wki100_computername));
+
+ uServerName[0]=uServerName[1]='\\';
+
+ NetApiBufferFree(BufPtr);
+ } else {
+ ntStatus = RtlOemToUnicodeN(uServerName,
+ sizeof(uServerName) - sizeof(uServerName[0]),
+ &length,
+ ServerNamePointer,
+ strlen(ServerNamePointer)
+ );
+ if (NT_SUCCESS(ntStatus)) {
+ uServerName[length/sizeof(uServerName[0])] = 0;
+ } else {
+ return (ERROR_INVALID_PARAMETER);
+ }
+ }
+ //
+ // copy, upper case and convert to UNICODE, user name
+ //
+
+ if (!OemToUppercaseUnicode(UserNamePointer,
+ uUserName,
+ ARRAY_ELEMENTS(uUserName) - 1)) {
+ return (ERROR_INVALID_PARAMETER);
+ }
+
+ //
+ // copy, upper case and convert to UNICODE, old password
+ //
+
+ if (!OemToUppercaseUnicode(OldPasswordPointer,
+ uOldPassword,
+ ARRAY_ELEMENTS(uOldPassword) - 1)) {
+ return (ERROR_INVALID_PARAMETER);
+ }
+
+ //
+ // copy, upper case and convert to UNICODE, new password
+ //
+
+ if (!OemToUppercaseUnicode(NewPasswordPointer,
+ uNewPassword,
+ ARRAY_ELEMENTS(uNewPassword) - 1)) {
+ return (ERROR_INVALID_PARAMETER);
+ }
+
+ //
+ // make the call to the down-level password set function
+ //
+
+ return RxNetUserPasswordSet((LPTSTR)uServerName,
+ (LPTSTR)uUserName,
+ (LPTSTR)uOldPassword,
+ (LPTSTR)uNewPassword
+ );
+}
+
+BOOL
+OemToUppercaseUnicode(
+ IN LPSTR AnsiStringPointer,
+ OUT LPWSTR UnicodeStringPointer,
+ IN DWORD MaxLength
+ )
+
+/*++
+
+Routine Description:
+
+ given a string in OEM character set, upper cases it then converts it to
+ UNICODE
+
+Arguments:
+
+ AnsiStringPointer - pointer to 8-bit string to convert
+ UnicodeStringPointer - pointer to resultant 16-bit (UNICODE) string
+ MaxLength - maximum output buffer length in # of characters,
+ NOT including terminating NUL
+
+Return Value:
+
+ BOOL
+ TRUE - string converted
+ FALSE - failed for some reason (string too long, Rtl function failed)
+
+--*/
+
+{
+ DWORD stringLength;
+ char scratchpad[UNLEN + 1]; // UNLEN is the largest type of string we'll get
+ NTSTATUS ntStatus;
+ DWORD length;
+
+ stringLength = strlen(AnsiStringPointer);
+ if (stringLength > MaxLength) {
+ return FALSE;
+ }
+ strcpy(scratchpad, AnsiStringPointer);
+
+ //
+ // BUGBUG - this is not necessarily the correct upper-case function
+ //
+
+ strupr(scratchpad);
+ ntStatus = RtlOemToUnicodeN(UnicodeStringPointer,
+ MaxLength * sizeof(*UnicodeStringPointer),
+ &length,
+ scratchpad,
+ stringLength
+ );
+ if (NT_SUCCESS(ntStatus)) {
+ UnicodeStringPointer[length/sizeof(*UnicodeStringPointer)] = 0;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
diff --git a/private/os2/client/vrremote.h b/private/os2/client/vrremote.h
new file mode 100644
index 000000000..224507ef3
--- /dev/null
+++ b/private/os2/client/vrremote.h
@@ -0,0 +1,101 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ vrremote.h
+
+Abstract:
+
+ Prototypes for vrremote module
+
+Author:
+
+ Richard L Firth (rfirth) 28-Oct-1991
+
+Revision History:
+
+ 29-Oct-1991 rfirth
+ Created
+
+--*/
+
+NET_API_STATUS
+VrTransaction(
+ IN LPSTR ServerName,
+ IN LPBYTE SendParmBuffer,
+ IN DWORD SendParmBufLen,
+ IN LPBYTE SendDataBuffer,
+ IN DWORD SendDataBufLen,
+ OUT LPBYTE ReceiveParmBuffer,
+ IN DWORD ReceiveParmBufLen,
+ IN LPBYTE ReceiveDataBuffer,
+ IN OUT LPDWORD ReceiveDataBufLen,
+ IN BOOL NullSessionFlag
+ );
+
+NET_API_STATUS
+VrRemoteApi(
+ IN DWORD ApiNumber,
+ IN LPBYTE ServerNamePointer,
+ IN LPSTR ParameterDescriptor,
+ IN LPSTR DataDescriptor,
+ IN LPSTR AuxDescriptor OPTIONAL,
+ IN BOOL NullSessionFlag
+ );
+
+//
+// private routine prototypes
+//
+
+DWORD
+VrpGetStructureSize(
+ IN LPSTR Descriptor,
+ IN LPDWORD AuxOffset
+ );
+
+DWORD
+VrpGetArrayLength(
+ IN LPSTR type_ptr,
+ IN LPSTR* type_ptr_addr
+ );
+
+DWORD
+VrpGetFieldSize(
+ IN LPSTR Descriptor,
+ IN LPSTR* pDescriptor
+ );
+
+VOID
+VrpConvertReceiveBuffer(
+ IN LPBYTE ReceiveBuffer,
+ IN WORD BufferSelector,
+ IN WORD BufferOffset,
+ IN WORD ConverterWord,
+ IN DWORD NumberStructs,
+ IN LPSTR DataDescriptor,
+ IN LPSTR AuxDescriptor
+ );
+
+VOID
+VrpConvertVdmPointer(
+ IN ULPWORD TargetPointer,
+ IN WORD BufferSegment,
+ IN WORD BufferOffset,
+ IN WORD ConverterWord
+ );
+
+NET_API_STATUS
+VrpPackSendBuffer(
+ IN OUT LPBYTE* SendBufferPtr,
+ IN OUT LPDWORD SendBufLenPtr,
+ OUT LPBOOL BufferAllocFlagPtr,
+ IN OUT LPSTR DataDescriptor,
+ IN LPSTR AuxDescriptor,
+ IN DWORD StructureSize,
+ IN DWORD AuxOffset,
+ IN DWORD AuxSize,
+ IN BOOL SetInfoFlag,
+ IN BOOL OkToModifyDescriptor
+ );
diff --git a/private/os2/dirs b/private/os2/dirs
new file mode 100644
index 000000000..461cace0c
--- /dev/null
+++ b/private/os2/dirs
@@ -0,0 +1,31 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=ssrtl \
+ client \
+ server \
+ ldr \
+ loader \
+ os2ss \
+ os2ses
+
+OPTIONAL_DIRS=
diff --git a/private/os2/doc/ansi.src b/private/os2/doc/ansi.src
new file mode 100644
index 000000000..b35a53837
--- /dev/null
+++ b/private/os2/doc/ansi.src
@@ -0,0 +1,440 @@
+####################################################### 120
+From martind Thu Sep 28 21:37:10 1989
+To: stevewo
+Subject: ansi.c
+Date: Thu Sep 28 21:34:28 1989
+
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/machdep.h>
+#include <signal.h>
+#include <termio.h>
+#include <ctype.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <errno.h>
+#include "../include/message.h"
+#include "../include/client.h"
+
+/*
+** - character definitions for ANSI 3.64
+*/
+#define ESC 0x1b /* escape */
+#define CBT 0x5a /* backward tabulation */ /* M001 */
+#define CPL 0x46 /* cursor to previous line */
+#define CNL 0x45 /* cursor to next line */
+#define CUB 0x44 /* cursor back */
+#define CUF 0x43 /* cursor forward */
+#define CUU 0x41 /* cursor up */
+#define CUD 0x42 /* cursor down */
+#define CUP 0x48 /* cursor position */
+#define DCH 0x50 /* delete character */
+#define DL 0x4d /* delete line */
+#define ECH 0x58 /* erase character */
+#define ED 0x4a /* erase display */
+#define EL 0x4b /* erase line */
+#define ICH 0x40 /* insert character */
+#define IL 0x4c /* insert line */
+#define SU 0x53 /* scroll up */
+#define SD 0x54 /* scroll down */
+#define SGR 0x6d /* select graphic rendition */
+
+/* states of the finite state machine */
+#define NOCMD 1 /* type of crt state - most chars will go onto screen */
+#define ESCED 2 /* we've seen an ESC, waiting for rest of CSI */
+#define PARAMS 3 /* we're building the parameter list */
+
+
+#define NROWS LYSIZE /* number of rows */
+#define NCOLS LXSIZE /* number of columns */
+
+#define NPARMS 3 /* max # of params */
+
+int pt_cy = 1, pt_cx = 1; /* current active position */
+int pt_param[NPARMS]; /* parameter list */
+int pt_pnum; /* index of parameter we're building */
+int pt_state = NOCMD; /* state of machine */
+
+/*
+** Basic concepts:
+** The screen consists of rows and columns
+** columns are numbered from the left, starting with one.
+** rows on the screen are numbered from the top, starting with one.
+** Thus, the home position in the upper left corner is row one, column one.
+**
+** Associated with each screen is the 'current active position'.
+** It corresponds roughly to the cursor; in fact, after each call to screen
+** the cursor will indicate the active position. Thus,
+** the cursor movements really change the active position, and
+** the cursor follows the change.
+**
+** This code implements a finite state machine that reads a stream of
+** characters, and emits commands that alter the screen. All of these
+** commands are issued via calls through the 'crtsw' array. Each element
+** of this array consists of an aggregate of functions which are
+** responsible for making the appropriate changes to the actual screen.
+**
+** The functions in the aggregate and their responsibities are:
+**
+** v_scroll(i)
+** scroll the text on the screen i lines.
+** This will move some lines off the screen, and some blank lines
+** onto the screen. i may be negative, indicating that the text
+** moves downward, and blank lines appear at the top.
+** v_copy(sr, sc, dr, dc, cnt)
+** sr and sc specify a source row and column.
+** dr and dc specify a destination row and column.
+** Count characters are copied from the source to the dest,
+** with the copy proceeding from left to right, and top to bottom.
+** If the source and destination overlap, the copy is done
+** correctly.
+** v_clear(r, c, cnt)
+** Characters starting at row r and column are cleared to the
+** space character.
+** v_pchar(r, c, ch)
+** The character ch is placed on the screen at row r, column c,
+** using the current graphic rendition.
+** return value is number of character positions to adjust active
+** position by - zero means the character has no graphic
+** representation.
+** v_scurs(r, c)
+** The cursor is moved to row r, column c.
+** v_init()
+** The screen and all data structures are initialized.
+** v_sgr(i)
+** The current graphic rendition (e. g. font, color) is set to
+** that specified by i. See ANSI x3.64 for encoding.
+*/
+
+/*
+** screen(cp, cnt) - pass characters to the finite state machine
+** cp points to the array of characters
+** cnt indicates how many characters are being passed.
+*/
+static unsigned short ignore_next_char = 0;
+
+screen(cs, lp, cp, cnt)
+struct handle *cs;
+int lp;
+char *cp;
+int cnt;
+{
+ register char c;
+ int work;
+ char *ep, *ip;
+ int ix, iy;
+
+ ip = cp;
+ ep = cp;
+ ix = pt_cx;
+ iy = pt_cy;
+
+ while ( cnt-- ) {
+ c = *cp++;
+ /* M001 */
+ if (ignore_next_char)
+ {
+ ignore_next_char = 0;
+ continue;
+ }
+ switch ( pt_state ) {
+ case NOCMD:
+ if ( c == ESC ) {
+ /* Flush */
+ lputs(cs, lp, ix-1, iy-1, ip, (ep-ip), SA_BONW);
+ pt_state = ESCED;
+ break;
+ } else {
+ if( c >= ' ' ){
+ ep++;
+ pt_cx++;
+ }else{
+ /* Flush */
+ if( ep > ip )
+ lputs(cs, lp, ix-1, iy-1, ip, (ep-ip), SA_BONW);
+
+ switch(c) {
+ case '\n':
+ pt_cy += 1;
+ break;
+ case '\r':
+ pt_cx = 1;
+ break;
+ case '\b':
+ if ( pt_cx > 1 )
+ pt_cx -= 1;
+ break;
+ case '\t':
+ pt_cx += (8 - ((pt_cx - 1) % 8));
+ break;
+ case '\07':
+ lbeep(cs);
+ break;
+ default:
+ break;
+ } /* end switch */
+ ip = ep = cp;
+ ix = pt_cx;
+ iy = pt_cy;
+ }
+ }
+ break;
+ case ESCED:
+ switch(c) {
+ case '[':
+ pt_state = PARAMS;
+ clrparam();
+ break;
+ default:
+ pt_state = NOCMD;
+ ip = ep = cp;
+ ix = pt_cx;
+ iy = pt_cy;
+ }
+ break;
+ case PARAMS:
+ if ( c >= '0' && c <= '9' ) {
+ pt_param[pt_pnum] *= 10;
+ pt_param[pt_pnum] += (c - '0');
+ break;
+ } else if (c == ';') {
+ if ( pt_pnum < (NPARMS - 1) )
+ pt_pnum += 1;
+ else{
+ pt_state = NOCMD;
+ ip = ep = cp;
+ ix = pt_cx;
+ iy = pt_cy;
+ }
+ break;
+ } else {
+ ansicmd(cs, lp, c);
+ pt_state = NOCMD;
+ ip = ep = cp;
+ ix = pt_cx;
+ iy = pt_cy;
+ }
+ break;
+ }
+ /* if past right hand edge, move left and down */
+ if ( pt_cx > NCOLS ) {
+ pt_cy += (pt_cx / NCOLS);
+ pt_cx = ((pt_cx - 1) % NCOLS) + 1;
+ } else if ( pt_cx < 1 ) {
+ pt_cx = 1;
+ }
+
+ /* if off screen, scroll */
+ if ( pt_cy < 1 ) {
+ lscroll(cs, lp, pt_cy - 1, SA_BONW);
+ pt_cy = 1;
+ } else if ( pt_cy > NROWS ) {
+ if( ep > ip )
+ lputs(cs, lp, ix-1, iy-1, ip, (ep-ip), SA_BONW);
+ lscroll(cs, lp, pt_cy - NROWS, SA_BONW);
+ pt_cy = NROWS;
+ ip = ep = cp;
+ ix = pt_cx;
+ iy = pt_cy;
+ }
+ }
+ /* Flush */
+ if( ep > ip )
+ lputs(cs, lp, ix-1, iy-1, ip, (ep-ip), SA_BONW);
+ lcursor(cs, lp, pt_cx-1, pt_cy-1);
+}
+
+/*
+** clrparam(lp) - clear the parameters for a screen
+** lp points to the screen's crt struct
+*/
+clrparam()
+{
+ register int i;
+
+ for ( i = 0; i < NPARMS; i += 1)
+ pt_param[i] = 0;
+ pt_pnum = 0;
+}
+
+
+/*
+** ansicmd(c, lp) - perform some ANSI 3.64 function, using the parameters
+** we've just gathered.
+** c is the character that indicates the function to be performed
+** lp indicates the screen to perform the function on.
+*/
+ansicmd(cs, lp, c)
+struct handle *cs;
+int lp;
+register char c;
+{
+ register int i, col;
+
+ switch ( c ) {
+
+ case CPL: /* cursor to previous line */
+ pt_cy -= range(pt_param[0], 1, 1, NROWS);
+ pt_cx = 1;
+ break;
+
+ case CNL: /* cursor to next line */
+ pt_cy += range(pt_param[0], 1, 1, NROWS);
+ pt_cx = 1;
+ break;
+
+ case CUB: /* cursor backward */
+ pt_cx -= range(pt_param[0], 1, 1, pt_cx - 1);
+ break;
+
+ case CUF: /* cursor forward */
+ pt_cx += range(pt_param[0], 1, 1, NCOLS - pt_cx);
+ break;
+
+ case CUU: /* cursor up */
+ pt_cy -= range(pt_param[0], 1, 1, pt_cy - 1);
+ break;
+
+ case CUD: /* cursor down */
+ pt_cy += range(pt_param[0], 1, 1, NROWS - pt_cy);
+ break;
+
+ case CUP: /* cursor position */
+ pt_cy = range(pt_param[0], 1, 1, NROWS);
+ pt_cx = range(pt_param[1], 1, 1, NCOLS);
+ break;
+
+ /* M001 */
+ case CBT: /* tab backwards */
+ col = pt_cx - 1;
+ i = range(pt_param[0], 1, 1, (col + 7) >> 3);
+ if (col & 7)
+ {
+ pt_cx = (col & ~7) + 1;
+ --i;
+ }
+ pt_cx -= (i << 3);
+ break;
+ case DCH: /* delete character */
+ pt_param[0] = range(pt_param[0], 1, 1, (NCOLS - pt_cx) + 1);
+ if ( pt_cx + pt_param[0] <= NCOLS ) {
+ lcopy(cs, lp, pt_cx+pt_param[0]-1, pt_cy-1,
+ pt_cx-1, pt_cy-1, NCOLS-(pt_cx+pt_param[0]-1));
+ }
+ lclear(cs, lp, NCOLS-pt_param[0], pt_cy-1,
+ pt_param[0], SA_BONW);
+ break;
+
+ case DL: /* delete line */
+ pt_param[0] = range(pt_param[0], 1, 1, (NROWS - pt_cy) + 1);
+ /* copy lines up */
+ if ( pt_cy + pt_param[0] <= NROWS ) {
+ lcopy(cs, lp, 0, pt_cy+pt_param[0]-1, 0, pt_cy-1,
+ NCOLS*(NROWS-(pt_cy+pt_param[0]-1)));
+ }
+ /* clear new stuff */
+ lclear(cs, lp, 0, NROWS-pt_param[0],
+ NCOLS*pt_param[0], SA_BONW);
+ break;
+
+ case ECH: /* erase character */
+ pt_param[0] = range( pt_param[0], 1, 1, (NCOLS - pt_cx) + 1);
+ lclear(cs, lp, pt_cx-1, pt_cy-1, pt_param[0], SA_BONW);
+ break;
+ case ED: /* erase display */
+ switch(pt_param[0]) {
+ case 0:
+ lclear(cs, lp, pt_cx-1, pt_cy-1,
+ ((NROWS - pt_cy) * NCOLS) +
+ ((NCOLS - pt_cx) + 1 ), SA_BONW);
+ break;
+ case 1:
+ lclear(cs, lp, 0, 0, (pt_cy-1)*NCOLS+pt_cx, SA_BONW);
+ break;
+ case 2:
+ lfill(cs, lp, SA_BONW);
+ pt_cy = 1;
+ pt_cx = 1;
+ break;
+ }
+ break;
+ case EL:
+ switch(pt_param[0]) {
+ case 0: /* ap to end */
+ lclear(cs, lp, pt_cx-1, pt_cy-1,
+ (NCOLS - pt_cx) + 1, SA_BONW);
+ break;
+ case 1: /* start to ap */
+ lclear(cs, lp, 0, pt_cy-1, pt_cx, SA_BONW);
+ break;
+ case 2: /* whole line */
+ lclear(cs, lp, 0, pt_cy-1, NCOLS, SA_BONW);
+ break;
+ }
+ break;
+
+ case ICH: /* insert character */
+ pt_param[0] = range( pt_param[0], 1, 1, (NCOLS - pt_cx) + 1);
+ if ( pt_cx + pt_param[0] <= NCOLS ) {
+ lcopy(cs, lp, pt_cx-1, pt_cy-1, pt_cx+pt_param[0]-1,
+ pt_cy-1, NCOLS-(pt_cx+pt_param[0]-1));
+ }
+ lclear(cs, lp, pt_cx-1, pt_cy-1, pt_param[0], SA_BONW);
+ break;
+ case IL: /* insert line */
+ pt_param[0] = range(pt_param[0], 1, 1, (NROWS - pt_cy) + 1);
+ /* copy lines down */
+ if ( pt_cy + pt_param[0] <= NROWS ) {
+ lcopy(cs, lp, 0, pt_cy-1, 0, pt_cy+pt_param[0]-1,
+ NCOLS * ( NROWS-(pt_cy+pt_param[0]-1)));
+ }
+ /* clear new stuff */
+ lclear(cs, lp, 0, pt_cy-1, NCOLS * pt_param[0], SA_BONW);
+ break;
+ case SU: /* scroll up */
+ pt_param[0] = range(pt_param[0], 1, 1, NROWS);
+ lscroll(cs, lp, pt_param[0], SA_BONW);
+ break;
+ case SD: /* scroll down */
+ pt_param[0] = -range(pt_param[0], 1, 1, NROWS);
+ lscroll(cs, lp, pt_param[0], SA_BONW);
+ break;
+ case SGR:
+#ifdef ENSGR
+ lsgr(pt_param[0]);
+ /* M002 */
+ for (i = 1; i < NPARMS; i++)
+ {
+ if (pt_param[i])
+ lsgr(pt_param[i]);
+ else
+ break;
+ }
+#endif
+ break;
+ }
+}
+
+/*
+** range(val, default, min, max) - restrict a value to a range, or supply a
+** default
+** val is the value to be restricted.
+** default is the value to be returned if val is zero
+** min is the minimum value
+** max is the maximum value
+*/
+range( val, def, min, max)
+register int val, def;
+int min, max;
+{
+ if ( val == 0 )
+ return def;
+ if ( val < min )
+ return min;
+ if ( val > max )
+ return max;
+ return val;
+}
+
diff --git a/private/os2/doc/apistat b/private/os2/doc/apistat
new file mode 100644
index 000000000..8bcf13803
--- /dev/null
+++ b/private/os2/doc/apistat
@@ -0,0 +1,273 @@
+
+Aug-27-1991:
+
+NOTE (Yarons):
+This is the 32 bit support as of April 1st 1990 - by stevewo
+For 32 bit APIs, we added named pipes, fixed bugs and support UNC.
+
+Bulk of work and focus is on 16bit APIs, which is scheduled in a Win
+Project file with WIN32/NT product 1 schedule
+
+--------------------------------------------------------------------
+
+; This list defines the Cruiser OS/2 API Calls that are supported by the
+; NT OS/2 Emulation Subsystem. The percent complete column has the
+; following meanings:
+;
+; XXX - Api is implemented and has passed component test
+; 100 - Api is implemented and is 100% functional (i.e. passed unit test)
+; 10 - Api is implemented and is 10% functional
+; 0 - Api is implemented but does nothing (i.e. a stub to link against)
+; blank - Api is not callable
+
+ Percent Location of Notes on
+Complete External API Name Implementation Status
+
+ 90 DosQuerySysInfo DLL
+ 80 DosBeep DLL
+ 60 DosDevConfig DLL
+
+ 100 DosSetExceptionHandler DLL
+ 100 DosUnsetExceptionHandler DLL
+ 100 DosRaiseException DLL
+ 100 DosUnwindException DLL
+
+ 100 DosError DLL
+ 100 DosErrClass DLL
+
+ 100 DosGetMessage DLL
+ 100 DosInsertMessage DLL
+ 100 DosPutMessage DLL
+ 100 DosQueryMessageCP DLL
+
+ 100 DosSetProcessCp DLL
+ 100 DosQueryCp DLL
+ 70 DosQueryCtryInfo DLL
+ 70 DosQueryDBCSEnv DLL
+ 70 DosQueryCollate DLL
+ 70 DosMapCase DLL
+
+ 100 DosScanEnv DLL
+ 100 DosSearchPath DLL
+ 100 DosQueryVerify DLL
+ 100 DosSetVerify DLL
+ 100 DosSetMaxFH DLL
+
+ 100 DosCreateThread Server
+ 100 DosWaitChild Server
+ 100 DosWaitThread Server
+ 100 DosEnterCritSec Server
+ 100 DosExitCritSec Server
+ 100 DosExecPgm DLL/Server
+ 100 DosExit Server
+ 100 DosExitList DLL
+ 100 DosGetThreadInfo DLL
+ 100 DosSetPriority Server
+ 100 DosKillProcess Server
+ 100 DosResumeThread Server
+ 100 DosSuspendThread Server
+
+ 100 DosCreatePipe DLL/Server
+
+ 100 DosCreateEventSem DLL/Server
+ 100 DosOpenEventSem DLL/Server
+ 100 DosCloseEventSem DLL/Server
+ 100 DosResetEventSem DLL
+ 100 DosPostEventSem DLL
+ 100 DosWaitEventSem DLL
+ 100 DosQueryEventSem DLL
+
+ 100 DosCreateMutexSem DLL/Server
+ 100 DosOpenMutexSem DLL/Server
+ 100 DosCloseMutexSem DLL/Server
+ 100 DosRequestMutexSem DLL
+ 100 DosReleaseMutexSem DLL
+ 100 DosQueryMutexSem DLL
+
+ 90 DosCreateMuxWaitSem DLL/Server
+ 90 DosOpenMuxWaitSem DLL/Server
+ 90 DosCloseMuxWaitSem DLL/Server
+ 90 DosWaitMuxWaitSem DLL/Server
+ 90 DosAddMuxWaitSem DLL/Server
+ 90 DosDeleteMuxWaitSem DLL/Server
+ 90 DosQueryMuxWaitSem DLL/Server
+
+ 100 DosGetDateTime DLL
+ 100 DosSetDateTime DLL
+ 100 DosSleep DLL
+ 100 DosAsyncTimer DLL
+ 100 DosStartTimer DLL
+ 100 DosStopTimer DLL
+
+ 90 DosAllocMem DLL
+ 90 DosAllocSharedMem Server
+ 90 DosGetNamedSharedMem Server
+ 90 DosGetSharedMem Server
+ 90 DosGiveSharedMem Server
+ 90 DosFreeMem DLL/Server
+ 90 DosSetMem DLL
+ 90 DosQueryMem DLL
+
+ 100 DosSubAlloc DLL
+ 100 DosSubFree DLL
+ 100 DosSubSet DLL
+
+ 100 DosLoadModule DLL/Loader Subsystem
+ 100 DosFreeModule DLL/Loader Subsystem
+ 100 DosQueryProcAddr DLL/Loader Subsystem
+ 100 DosQueryModuleHandle DLL/Loader Subsystem
+ 100 DosQueryModuleName DLL/Loader Subsystem
+ 100 DosGetResource DLL/Loader Subsystem
+ 100 DosQueryResourceSize DLL/Loader Subsystem
+ 100 DosQueryAppType DLL/Loader Subsystem
+
+ 100 DosOpen DLL
+ 100 DosSetFHState DLL
+ 100 DosQueryFHState DLL
+ 100 DosQueryHType DLL
+
+ 100 DosSetFileInfo DLL
+ 100 DosQueryFileInfo DLL
+ 100 DosResetBuffer DLL
+ 100 DosSetFilePtr DLL
+ 100 DosRead DLL
+ 100 DosWrite DLL
+ 100 DosClose DLL
+
+ DosDevIOCtl DLL (see below)
+ 100 DosDupHandle DLL
+ 100 DosSetFileLocks DLL
+ 100 DosSetFileSize DLL
+
+ 85 DosFindFirst DLL
+ 85 DosFindNext DLL
+ 85 DosFindClose DLL
+ 100 DosSetDefaultDisk DLL
+ 100 DosQueryCurrentDisk DLL
+ 100 DosSetCurrentDir DLL/Server
+ 100 DosQueryCurrentDir DLL/Server
+ 100 DosDelete DLL
+ 100 DosEditName DLL
+ 100 DosQueryPathInfo DLL
+ 100 DosSetPathInfo DLL
+ DosEnumAttribute DLL
+ 100 DosCreateDir DLL
+ 100 DosDeleteDir DLL
+ 90 DosMove DLL (move not done in NT)
+ 100 DosCopy DLL
+
+ 10 DosFSAttach DLL (see below)
+ 75 DosFSCtl DLL (see below)
+ 10 DosQueryFSAttach DLL (see below)
+ 100 DosSetFSInfo DLL
+ 100 DosQueryFSInfo DLL
+
+ 100 DosStartSession Server
+ 100 DosSetSession Server
+ 100 DosSelectSession Server
+ 100 DosStopSession Server
+
+ DosCallNPipe Server
+ DosConnectNPipe Server
+ DosDisConnectNPipe Server
+ DosCreateNPipe Server
+ DosPeekNPipe Server
+ DosQueryNPHState Server
+ DosQueryNPipeInfo Server
+ DosQueryNPipeSemState Server
+ DosRawReadNPipe Server
+ DosRawWriteNPipe Server
+ DosSetNPHState Server
+ DosSetNPipeSem Server
+ DosTransactNPipe Server
+ DosWaitNPipe Server
+
+ 100 DosCreateQueue Server
+ 100 DosOpenQueue Server
+ 100 DosCloseQueue Server
+ 100 DosPeekQueue Server
+ 100 DosPurgeQueue Server
+ 100 DosQueryQueue Server
+ 100 DosReadQueue Server
+ 100 DosWriteQueue Server
+
+Work Items:
+
+1. Implement NLS support (5 days)
+
+ This work item includes the following items:
+
+ o spec the source file format for all the NLS information. This
+ will be a superset of the contents of COUNTRY.SYS. Currently
+ OS/2 uses an incomprehensible 4000 line assembler file with lots
+ of macros and a few includes just to keep you guessing.
+
+ o spec the binary file format of the NLS information. The NLS file(s?)
+ will be mapped into readonly memory at runtime and accessed directly.
+
+ o write a utility to convert the source file format to the binary file
+ format.
+
+ o write a throw away utility to convert COUNTRY.SYS to the new source
+ format.
+
+ o modify the following NLS API calls to access the new binary file format
+ by mapping the NLS binary file(s?). Maintain a cache so we only map
+ the NLS file(s?) the first time they are needed in a process.
+
+ DosSetProcessCp DosQueryCp DosQueryCtryInfo
+ DosQueryDBCSEnv DosQueryCollate DosMapCase
+
+
+2. Implement DBCS support (5 days)
+
+ This work item includes the following items:
+
+ o implement DBCS runtime code for moving forwards and backwards through
+ a string (both ASCIZ and counted STRING types). Also fetching for
+ characters as well. How does executive access DBCS NLS information if
+ we are mapping it in user mode. Is it also mapped in executive space,
+ and if so, then that is aliasing within the same addres space.
+
+ o Modify all OS/2 API calls the parse string parameters so that they call
+ runtime routines to advance a string pointer and fetch characters.
+
+ These include:
+ DosGetMessage DosInsertMessage DosPutMessage
+ DosQueryMessageCP DosMapCase DosScanEnv
+ DosSearchPath DosExecPgm DosCreateEventSem
+ DosOpenEventSem DosCreateMutexSem DosOpenMutexSem
+ DosCreateMuxWaitSem DosOpenMuxWaitSem
+ DosAllocSharedMem DosGetNamedSharedMem DosLoadModule
+ DosQueryProcAddr DosQueryModuleHandle DosQueryAppType
+ DosOpen DosFindFirst DosFindNext DosSetCurrentDir
+ DosDelete DosEditName DosQueryPathInfo
+ DosSetPathInfo DosCreateDir DosDeleteDir DosMove
+ DosCopy DosFSAttach DosQueryFSAttach DosSetFSInfo
+ DosQueryFSInfo DosStartSession DosCallNPipe
+ DosCreateNPipe DosRawReadNPipe DosRawWriteNPipe
+ DosWaitNPipe DosCreateQueue DosOpenQueue
+
+3. Implement Cruiser Named Pipes (10 days)
+
+4. DosDevioctl
+
+ We need to decide among the following options:
+
+ o remove from cruiser 32-bit API set and redefine API in
+ OS/2 subsystem to look like NtDeviceIoControl
+
+ o choose a subset of DosDevioctl function/category combinations
+ to support in subsystem (map to corresponding
+ NtDeviceIoControl functions)
+
+ The first option makes more sense since the 16-bit interface is available
+ in cruiser and the 32-bit API provides no additional functionality.
+ Using the NT interface is cleaner/more extendible.
+
+5. DosFsAttach/DosQFsAttach/DosFsctl
+
+ These are fully designed. We need to decide whether these should exist as
+ 32-bit API in cruiser since they provide no new functionality and we might
+ want to modify the interface in NT. We also need to decide whether these
+ are worth including in NT since they have no use at this time.
diff --git a/private/os2/doc/dos32.scr b/private/os2/doc/dos32.scr
new file mode 100644
index 000000000..129d1b6a4
--- /dev/null
+++ b/private/os2/doc/dos32.scr
@@ -0,0 +1,576 @@
+DosSetMaxFH DosSetMaxFH
+DosSetVerify DosSetVerify
+DosErrClass DosErrClass
+DosError DosError
+DosSetFileInfo DosSetFileInfo
+DosSetPathInfo DosSetPathInfo
+DosSetDefaultDisk DosSetDefaultDisk
+DosSetFHState DosSetFHState
+DosSetFSInfo DosSetFSInfo
+DosQueryPathInfo DosQueryPathInfo
+DosQueryHType DosQueryHType
+DosQueryVerify DosQueryVerify
+DosDeleteDir DosDeleteDir
+DosScanEnv DosScanEnv
+DosSearchPath DosSearchPath
+DosSleep DosSleep
+DosGetDateTime DosGetDateTime
+DosDevConfig DosDevConfig
+DosEnterCritSec DosEnterCritSec
+DosExitCritSec DosExitCritSec
+DosExit DosExit
+DosKillProcess DosKillProcess
+DosSetPriority DosSetPriority
+DosResumeThread DosResumeThread
+DosSuspendThread DosSuspendThread
+DosCreatePipe DosCreatePipe
+DosResetBuffer DosResetBuffer
+DosSetCurrentDir DosSetCurrentDir
+DosSetFilePtr DosSetFilePtr
+DosClose DosClose
+DosCopy DosCopy
+DosDelete DosDelete
+DosDupHandle DosDupHandle
+DosEditName DosEditName
+DosSetFileLocks DosSetFileLocks
+DosFindClose DosFindClose
+DosFindFirst DosFindFirst
+DosFindNext DosFindNext
+DosFSAttach DosFSAttach
+DosCreateDir DosCreateDir
+DosMove DosMove
+DosSetFileSize DosSetFileSize
+DosFileIO DosFileIO
+DosEnumAttribute DosEnumAttribute
+DosOpen DosOpen
+DosQueryCurrentDir DosQueryCurrentDir
+DosQueryCurrentDisk DosQueryCurrentDisk
+DosQueryFHState DosQueryFHState
+DosQueryFSAttach DosQueryFSAttach
+DosQueryFSInfo DosQueryFSInfo
+DosQueryFileInfo DosQueryFileInfo
+DosWaitChild DosWaitChild
+DosRead DosRead
+DosWrite DosWrite
+DosExecPgm DosExecPgm
+DosDevIOCtl DosDevIOCtl
+DosFSCtl DosFSCtl
+DosBeep DosBeep
+DosPhysicalDisk DosPhysicalDisk
+DosSetCp DosSetCp
+DosSetProcessCp DosSetProcessCp
+DosStopTimer DosStopTimer
+DosQueryCp DosQueryCp
+DosSetDateTime DosSetDateTime
+DosExitList DosExitList
+DosAllocProtectedMem DosAllocProtectedMem
+DosAliasMem DosAliasMem
+DosAllocMem DosAllocMem
+DosAllocSharedMem DosAllocSharedMem
+DosGetNamedSharedMem DosGetNamedSharedMem
+DosGetSharedMem DosGetSharedMem
+DosGiveSharedMem DosGiveSharedMem
+DosFreeMem DosFreeMem
+DosSetMem DosSetMem
+DosQueryMem DosQueryMem
+DosCreateThread DosCreateThread
+DosGetThreadInfo DosGetThreadInfo
+DosGetProcessInfo DosGetProcessInfo
+DosLoadModule DosLoadModule
+DosQueryModuleHandle DosQueryModuleHandle
+DosQueryModuleName DosQueryModuleName
+DosQueryProcAddr DosQueryProcAddr
+DosQueryProcType DosQueryProcType
+DosFreeModule DosFreeModule
+DosQueryAppType DosQueryAppType
+DosCreateEventSem DosCreateEventSem
+DosOpenEventSem DosOpenEventSem
+DosCloseEventSem DosCloseEventSem
+DosResetEventSem DosResetEventSem
+DosPostEventSem DosPostEventSem
+DosWaitEventSem DosWaitEventSem
+DosQueryEventSem DosQueryEventSem
+DosCreateMutexSem DosCreateMutexSem
+DosOpenMutexSem DosOpenMutexSem
+DosCloseMutexSem DosCloseMutexSem
+DosRequestMutexSem DosRequestMutexSem
+DosReleaseMutexSem DosReleaseMutexSem
+DosQueryMutexSem DosQueryMutexSem
+DosCreateMuxWaitSem DosCreateMuxWaitSem
+DosOpenMuxWaitSem DosOpenMuxWaitSem
+DosCloseMuxWaitSem DosCloseMuxWaitSem
+DosWaitMuxWaitSem DosWaitMuxWaitSem
+DosAddMuxWaitSem DosAddMuxWaitSem
+DosDeleteMuxWaitSem DosDeleteMuxWaitSem
+DosQueryMuxWaitSem DosQueryMuxWaitSem
+DosSubSet DosSubSet
+DosSubAlloc DosSubAlloc
+DosSubFree DosSubFree
+DosSubUnset DosSubUnset
+DosQuerySysInfo DosQuerySysInfo
+DosWaitThread DosWaitThread
+DosAsyncTimer DosAsyncTimer
+DosStartTimer DosStartTimer
+DosGetResource DosGetResource
+DosQueryResourceSize DosQueryResourceSize
+DosFreeResource DosFreeResource
+DosGetCtryInfo DosGetCtryInfo
+DosQueryCtryInfo DosQueryCtryInfo
+DosQueryDBCSEnv DosQueryDBCSEnv
+DosMapCase DosMapCase
+DosQueryCollate DosQueryCollate
+DosGetMessage DosGetMessage
+DosInsertMessage DosInsertMessage
+DosPutMessage DosPutMessage
+DosQueryMessageCP DosQueryMessageCP
+DosStartSession DosStartSession
+DosSetSession DosSetSession
+DosSelectSession DosSelectSession
+DosStopSession DosStopSession
+DosCreateQueue DosCreateQueue
+DosOpenQueue DosOpenQueue
+DosCloseQueue DosCloseQueue
+DosPurgeQueue DosPurgeQueue
+DosQueryQueue DosQueryQueue
+DosPeekQueue DosPeekQueue
+DosReadQueue DosReadQueue
+DosWriteQueue DosWriteQueue
+DosEnterMustComplete DosEnterMustComplete
+DosExitMustComplete DosExitMustComplete
+DosAcknowledgeSignalException DosAcknowledgeSignalException
+DosSetSignalExceptionFocus DosSetSignalExceptionFocus
+DosSendSignalException DosSendSignalException
+DosRaiseException DosRaiseException
+DosUnwindException DosUnwindException
+Dos32SetMaxFH Dos32SetMaxFH
+Dos32SetVerify Dos32SetVerify
+Dos32ErrClass Dos32ErrClass
+Dos32Error Dos32Error
+Dos32SetFileInfo Dos32SetFileInfo
+Dos32SetPathInfo Dos32SetPathInfo
+Dos32SetDefaultDisk Dos32SetDefaultDisk
+Dos32SetFHState Dos32SetFHState
+Dos32SetFSInfo Dos32SetFSInfo
+Dos32QueryPathInfo Dos32QueryPathInfo
+Dos32QueryHType Dos32QueryHType
+Dos32QueryVerify Dos32QueryVerify
+Dos32DeleteDir Dos32DeleteDir
+Dos32ScanEnv Dos32ScanEnv
+Dos32SearchPath Dos32SearchPath
+Dos32Sleep Dos32Sleep
+Dos32GetDateTime Dos32GetDateTime
+Dos32DevConfig Dos32DevConfig
+Dos32EnterCritSec Dos32EnterCritSec
+Dos32ExitCritSec Dos32ExitCritSec
+Dos32Exit Dos32Exit
+Dos32KillProcess Dos32KillProcess
+Dos32SetPriority Dos32SetPriority
+Dos32ResumeThread Dos32ResumeThread
+Dos32SuspendThread Dos32SuspendThread
+Dos32CreatePipe Dos32CreatePipe
+Dos32ResetBuffer Dos32ResetBuffer
+Dos32SetCurrentDir Dos32SetCurrentDir
+Dos32SetFilePtr Dos32SetFilePtr
+Dos32Close Dos32Close
+Dos32Copy Dos32Copy
+Dos32Delete Dos32Delete
+Dos32DupHandle Dos32DupHandle
+Dos32EditName Dos32EditName
+Dos32SetFileLocks Dos32SetFileLocks
+Dos32FindClose Dos32FindClose
+Dos32FindFirst Dos32FindFirst
+Dos32FindNext Dos32FindNext
+Dos32FSAttach Dos32FSAttach
+Dos32CreateDir Dos32CreateDir
+Dos32Move Dos32Move
+Dos32SetFileSize Dos32SetFileSize
+Dos32FileIO Dos32FileIO
+Dos32EnumAttribute Dos32EnumAttribute
+Dos32Open Dos32Open
+Dos32QueryCurrentDir Dos32QueryCurrentDir
+Dos32QueryCurrentDisk Dos32QueryCurrentDisk
+Dos32QueryFHState Dos32QueryFHState
+Dos32QueryFSAttach Dos32QueryFSAttach
+Dos32QueryFSInfo Dos32QueryFSInfo
+Dos32QueryFileInfo Dos32QueryFileInfo
+Dos32WaitChild Dos32WaitChild
+Dos32Read Dos32Read
+Dos32Write Dos32Write
+Dos32ExecPgm Dos32ExecPgm
+Dos32DevIOCtl Dos32DevIOCtl
+Dos32FSCtl Dos32FSCtl
+Dos32Beep Dos32Beep
+Dos32PhysicalDisk Dos32PhysicalDisk
+Dos32SetCp Dos32SetCp
+Dos32SetProcessCp Dos32SetProcessCp
+Dos32StopTimer Dos32StopTimer
+Dos32QueryCp Dos32QueryCp
+Dos32SetDateTime Dos32SetDateTime
+Dos32ExitList Dos32ExitList
+Dos32AllocProtectedMem Dos32AllocProtectedMem
+Dos32AliasMem Dos32AliasMem
+Dos32AllocMem Dos32AllocMem
+Dos32AllocSharedMem Dos32AllocSharedMem
+Dos32GetNamedSharedMem Dos32GetNamedSharedMem
+Dos32GetSharedMem Dos32GetSharedMem
+Dos32GiveSharedMem Dos32GiveSharedMem
+Dos32FreeMem Dos32FreeMem
+Dos32SetMem Dos32SetMem
+Dos32QueryMem Dos32QueryMem
+Dos32CreateThread Dos32CreateThread
+Dos32GetThreadInfo Dos32GetThreadInfo
+Dos32GetProcessInfo Dos32GetProcessInfo
+Dos32LoadModule Dos32LoadModule
+Dos32QueryModuleHandle Dos32QueryModuleHandle
+Dos32QueryModuleName Dos32QueryModuleName
+Dos32QueryProcAddr Dos32QueryProcAddr
+Dos32QueryProcType Dos32QueryProcType
+Dos32FreeModule Dos32FreeModule
+Dos32QueryAppType Dos32QueryAppType
+Dos32CreateEventSem Dos32CreateEventSem
+Dos32OpenEventSem Dos32OpenEventSem
+Dos32CloseEventSem Dos32CloseEventSem
+Dos32ResetEventSem Dos32ResetEventSem
+Dos32PostEventSem Dos32PostEventSem
+Dos32WaitEventSem Dos32WaitEventSem
+Dos32QueryEventSem Dos32QueryEventSem
+Dos32CreateMutexSem Dos32CreateMutexSem
+Dos32OpenMutexSem Dos32OpenMutexSem
+Dos32CloseMutexSem Dos32CloseMutexSem
+Dos32RequestMutexSem Dos32RequestMutexSem
+Dos32ReleaseMutexSem Dos32ReleaseMutexSem
+Dos32QueryMutexSem Dos32QueryMutexSem
+Dos32CreateMuxWaitSem Dos32CreateMuxWaitSem
+Dos32OpenMuxWaitSem Dos32OpenMuxWaitSem
+Dos32CloseMuxWaitSem Dos32CloseMuxWaitSem
+Dos32WaitMuxWaitSem Dos32WaitMuxWaitSem
+Dos32AddMuxWaitSem Dos32AddMuxWaitSem
+Dos32DeleteMuxWaitSem Dos32DeleteMuxWaitSem
+Dos32QueryMuxWaitSem Dos32QueryMuxWaitSem
+Dos32SubSet Dos32SubSet
+Dos32SubAlloc Dos32SubAlloc
+Dos32SubFree Dos32SubFree
+Dos32SubUnset Dos32SubUnset
+Dos32QuerySysInfo Dos32QuerySysInfo
+Dos32WaitThread Dos32WaitThread
+Dos32AsyncTimer Dos32AsyncTimer
+Dos32StartTimer Dos32StartTimer
+Dos32GetResource Dos32GetResource
+Dos32QueryResourceSize Dos32QueryResourceSize
+Dos32FreeResource Dos32FreeResource
+Dos32GetCtryInfo Dos32GetCtryInfo
+Dos32QueryCtryInfo Dos32QueryCtryInfo
+Dos32QueryDBCSEnv Dos32QueryDBCSEnv
+Dos32MapCase Dos32MapCase
+Dos32QueryCollate Dos32QueryCollate
+Dos32GetMessage Dos32GetMessage
+Dos32InsertMessage Dos32InsertMessage
+Dos32PutMessage Dos32PutMessage
+Dos32QueryMessageCP Dos32QueryMessageCP
+Dos32StartSession Dos32StartSession
+Dos32SetSession Dos32SetSession
+Dos32SelectSession Dos32SelectSession
+Dos32StopSession Dos32StopSession
+Dos32CreateQueue Dos32CreateQueue
+Dos32OpenQueue Dos32OpenQueue
+Dos32CloseQueue Dos32CloseQueue
+Dos32PurgeQueue Dos32PurgeQueue
+Dos32QueryQueue Dos32QueryQueue
+Dos32PeekQueue Dos32PeekQueue
+Dos32ReadQueue Dos32ReadQueue
+Dos32WriteQueue Dos32WriteQueue
+Dos32EnterMustComplete Dos32EnterMustComplete
+Dos32ExitMustComplete Dos32ExitMustComplete
+Dos32AcknowledgeSignalException Dos32AcknowledgeSignalException
+Dos32SetSignalExceptionFocus Dos32SetSignalExceptionFocus
+Dos32SendSignalException Dos32SendSignalException
+Dos32RaiseException Dos32RaiseException
+Dos32UnwindException Dos32UnwindException
+DOSSETMAXFH DOSSETMAXFH
+DOSSETVERIFY DOSSETVERIFY
+DOSERRCLASS DOSERRCLASS
+DOSERROR DOSERROR
+DOSSETFILEINFO DOSSETFILEINFO
+DOSSETPATHINFO DOSSETPATHINFO
+DOSSETDEFAULTDISK DOSSETDEFAULTDISK
+DOSSETFHSTATE DOSSETFHSTATE
+DOSSETFSINFO DOSSETFSINFO
+DOSQUERYPATHINFO DOSQUERYPATHINFO
+DOSQUERYHTYPE DOSQUERYHTYPE
+DOSQUERYVERIFY DOSQUERYVERIFY
+DOSDELETEDIR DOSDELETEDIR
+DOSSCANENV DOSSCANENV
+DOSSEARCHPATH DOSSEARCHPATH
+DOSSLEEP DOSSLEEP
+DOSGETDATETIME DOSGETDATETIME
+DOSDEVCONFIG DOSDEVCONFIG
+DOSENTERCRITSEC DOSENTERCRITSEC
+DOSEXITCRITSEC DOSEXITCRITSEC
+DOSEXIT DOSEXIT
+DOSKILLPROCESS DOSKILLPROCESS
+DOSSETPRIORITY DOSSETPRIORITY
+DOSRESUMETHREAD DOSRESUMETHREAD
+DOSSUSPENDTHREAD DOSSUSPENDTHREAD
+DOSCREATEPIPE DOSCREATEPIPE
+DOSRESETBUFFER DOSRESETBUFFER
+DOSSETCURRENTDIR DOSSETCURRENTDIR
+DOSSETFILEPTR DOSSETFILEPTR
+DOSCLOSE DOSCLOSE
+DOSCOPY DOSCOPY
+DOSDELETE DOSDELETE
+DOSDUPHANDLE DOSDUPHANDLE
+DOSEDITNAME DOSEDITNAME
+DOSSETFILELOCKS DOSSETFILELOCKS
+DOSFINDCLOSE DOSFINDCLOSE
+DOSFINDFIRST DOSFINDFIRST
+DOSFINDNEXT DOSFINDNEXT
+DOSFSATTACH DOSFSATTACH
+DOSCREATEDIR DOSCREATEDIR
+DOSMOVE DOSMOVE
+DOSSETFILESIZE DOSSETFILESIZE
+DOSFILEIO DOSFILEIO
+DOSENUMATTRIBUTE DOSENUMATTRIBUTE
+DOSOPEN DOSOPEN
+DOSQUERYCURRENTDIR DOSQUERYCURRENTDIR
+DOSQUERYCURRENTDISK DOSQUERYCURRENTDISK
+DOSQUERYFHSTATE DOSQUERYFHSTATE
+DOSQUERYFSATTACH DOSQUERYFSATTACH
+DOSQUERYFSINFO DOSQUERYFSINFO
+DOSQUERYFILEINFO DOSQUERYFILEINFO
+DOSWAITCHILD DOSWAITCHILD
+DOSREAD DOSREAD
+DOSWRITE DOSWRITE
+DOSEXECPGM DOSEXECPGM
+DOSDEVIOCTL DOSDEVIOCTL
+DOSFSCTL DOSFSCTL
+DOSBEEP DOSBEEP
+DOSPHYSICALDISK DOSPHYSICALDISK
+DOSSETCP DOSSETCP
+DOSSETPROCESSCP DOSSETPROCESSCP
+DOSSTOPTIMER DOSSTOPTIMER
+DOSQUERYCP DOSQUERYCP
+DOSSETDATETIME DOSSETDATETIME
+DOSEXITLIST DOSEXITLIST
+DOSALLOCPROTECTEDMEM DOSALLOCPROTECTEDMEM
+DOSALIASMEM DOSALIASMEM
+DOSALLOCMEM DOSALLOCMEM
+DOSALLOCSHAREDMEM DOSALLOCSHAREDMEM
+DOSGETNAMEDSHAREDMEM DOSGETNAMEDSHAREDMEM
+DOSGETSHAREDMEM DOSGETSHAREDMEM
+DOSGIVESHAREDMEM DOSGIVESHAREDMEM
+DOSFREEMEM DOSFREEMEM
+DOSSETMEM DOSSETMEM
+DOSQUERYMEM DOSQUERYMEM
+DOSCREATETHREAD DOSCREATETHREAD
+DOSGETTHREADINFO DOSGETTHREADINFO
+DOSGETPROCESSINFO DOSGETPROCESSINFO
+DOSLOADMODULE DOSLOADMODULE
+DOSQUERYMODULEHANDLE DOSQUERYMODULEHANDLE
+DOSQUERYMODULENAME DOSQUERYMODULENAME
+DOSQUERYPROCADDR DOSQUERYPROCADDR
+DOSQUERYPROCTYPE DOSQUERYPROCTYPE
+DOSFREEMODULE DOSFREEMODULE
+DOSQUERYAPPTYPE DOSQUERYAPPTYPE
+DOSCREATEEVENTSEM DOSCREATEEVENTSEM
+DOSOPENEVENTSEM DOSOPENEVENTSEM
+DOSCLOSEEVENTSEM DOSCLOSEEVENTSEM
+DOSRESETEVENTSEM DOSRESETEVENTSEM
+DOSPOSTEVENTSEM DOSPOSTEVENTSEM
+DOSWAITEVENTSEM DOSWAITEVENTSEM
+DOSQUERYEVENTSEM DOSQUERYEVENTSEM
+DOSCREATEMUTEXSEM DOSCREATEMUTEXSEM
+DOSOPENMUTEXSEM DOSOPENMUTEXSEM
+DOSCLOSEMUTEXSEM DOSCLOSEMUTEXSEM
+DOSREQUESTMUTEXSEM DOSREQUESTMUTEXSEM
+DOSRELEASEMUTEXSEM DOSRELEASEMUTEXSEM
+DOSQUERYMUTEXSEM DOSQUERYMUTEXSEM
+DOSCREATEMUXWAITSEM DOSCREATEMUXWAITSEM
+DOSOPENMUXWAITSEM DOSOPENMUXWAITSEM
+DOSCLOSEMUXWAITSEM DOSCLOSEMUXWAITSEM
+DOSWAITMUXWAITSEM DOSWAITMUXWAITSEM
+DOSADDMUXWAITSEM DOSADDMUXWAITSEM
+DOSDELETEMUXWAITSEM DOSDELETEMUXWAITSEM
+DOSQUERYMUXWAITSEM DOSQUERYMUXWAITSEM
+DOSSUBSET DOSSUBSET
+DOSSUBALLOC DOSSUBALLOC
+DOSSUBFREE DOSSUBFREE
+DOSSUBUNSET DOSSUBUNSET
+DOSQUERYSYSINFO DOSQUERYSYSINFO
+DOSWAITTHREAD DOSWAITTHREAD
+DOSASYNCTIMER DOSASYNCTIMER
+DOSSTARTTIMER DOSSTARTTIMER
+DOSGETRESOURCE DOSGETRESOURCE
+DOSQUERYRESOURCESIZE DOSQUERYRESOURCESIZE
+DOSFREERESOURCE DOSFREERESOURCE
+DOSGETCTRYINFO DOSGETCTRYINFO
+DOSQUERYCTRYINFO DOSQUERYCTRYINFO
+DOSQUERYDBCSENV DOSQUERYDBCSENV
+DOSMAPCASE DOSMAPCASE
+DOSQUERYCOLLATE DOSQUERYCOLLATE
+DOSGETMESSAGE DOSGETMESSAGE
+DOSINSERTMESSAGE DOSINSERTMESSAGE
+DOSPUTMESSAGE DOSPUTMESSAGE
+DOSQUERYMESSAGECP DOSQUERYMESSAGECP
+DOSSTARTSESSION DOSSTARTSESSION
+DOSSETSESSION DOSSETSESSION
+DOSSELECTSESSION DOSSELECTSESSION
+DOSSTOPSESSION DOSSTOPSESSION
+DOSCREATEQUEUE DOSCREATEQUEUE
+DOSOPENQUEUE DOSOPENQUEUE
+DOSCLOSEQUEUE DOSCLOSEQUEUE
+DOSPURGEQUEUE DOSPURGEQUEUE
+DOSQUERYQUEUE DOSQUERYQUEUE
+DOSPEEKQUEUE DOSPEEKQUEUE
+DOSREADQUEUE DOSREADQUEUE
+DOSWRITEQUEUE DOSWRITEQUEUE
+DOSENTERMUSTCOMPLETE DOSENTERMUSTCOMPLETE
+DOSEXITMUSTCOMPLETE DOSEXITMUSTCOMPLETE
+DOSACKNOWLEDGESIGNALEXCEPTION DOSACKNOWLEDGESIGNALEXCEPTION
+DOSSETSIGNALEXCEPTIONFOCUS DOSSETSIGNALEXCEPTIONFOCUS
+DOSSENDSIGNALEXCEPTION DOSSENDSIGNALEXCEPTION
+DOSRAISEEXCEPTION DOSRAISEEXCEPTION
+DOSUNWINDEXCEPTION DOSUNWINDEXCEPTION
+DOS32SETMAXFH DOS32SETMAXFH
+DOS32SETVERIFY DOS32SETVERIFY
+DOS32ERRCLASS DOS32ERRCLASS
+DOS32ERROR DOS32ERROR
+DOS32SETFILEINFO DOS32SETFILEINFO
+DOS32SETPATHINFO DOS32SETPATHINFO
+DOS32SETDEFAULTDISK DOS32SETDEFAULTDISK
+DOS32SETFHSTATE DOS32SETFHSTATE
+DOS32SETFSINFO DOS32SETFSINFO
+DOS32QUERYPATHINFO DOS32QUERYPATHINFO
+DOS32QUERYHTYPE DOS32QUERYHTYPE
+DOS32QUERYVERIFY DOS32QUERYVERIFY
+DOS32DELETEDIR DOS32DELETEDIR
+DOS32SCANENV DOS32SCANENV
+DOS32SEARCHPATH DOS32SEARCHPATH
+DOS32SLEEP DOS32SLEEP
+DOS32GETDATETIME DOS32GETDATETIME
+DOS32DEVCONFIG DOS32DEVCONFIG
+DOS32ENTERCRITSEC DOS32ENTERCRITSEC
+DOS32EXITCRITSEC DOS32EXITCRITSEC
+DOS32EXIT DOS32EXIT
+DOS32KILLPROCESS DOS32KILLPROCESS
+DOS32SETPRIORITY DOS32SETPRIORITY
+DOS32RESUMETHREAD DOS32RESUMETHREAD
+DOS32SUSPENDTHREAD DOS32SUSPENDTHREAD
+DOS32CREATEPIPE DOS32CREATEPIPE
+DOS32RESETBUFFER DOS32RESETBUFFER
+DOS32SETCURRENTDIR DOS32SETCURRENTDIR
+DOS32SETFILEPTR DOS32SETFILEPTR
+DOS32CLOSE DOS32CLOSE
+DOS32COPY DOS32COPY
+DOS32DELETE DOS32DELETE
+DOS32DUPHANDLE DOS32DUPHANDLE
+DOS32EDITNAME DOS32EDITNAME
+DOS32SETFILELOCKS DOS32SETFILELOCKS
+DOS32FINDCLOSE DOS32FINDCLOSE
+DOS32FINDFIRST DOS32FINDFIRST
+DOS32FINDNEXT DOS32FINDNEXT
+DOS32FSATTACH DOS32FSATTACH
+DOS32CREATEDIR DOS32CREATEDIR
+DOS32MOVE DOS32MOVE
+DOS32SETFILESIZE DOS32SETFILESIZE
+DOS32FILEIO DOS32FILEIO
+DOS32ENUMATTRIBUTE DOS32ENUMATTRIBUTE
+DOS32OPEN DOS32OPEN
+DOS32QUERYCURRENTDIR DOS32QUERYCURRENTDIR
+DOS32QUERYCURRENTDISK DOS32QUERYCURRENTDISK
+DOS32QUERYFHSTATE DOS32QUERYFHSTATE
+DOS32QUERYFSATTACH DOS32QUERYFSATTACH
+DOS32QUERYFSINFO DOS32QUERYFSINFO
+DOS32QUERYFILEINFO DOS32QUERYFILEINFO
+DOS32WAITCHILD DOS32WAITCHILD
+DOS32READ DOS32READ
+DOS32WRITE DOS32WRITE
+DOS32EXECPGM DOS32EXECPGM
+DOS32DEVIOCTL DOS32DEVIOCTL
+DOS32FSCTL DOS32FSCTL
+DOS32BEEP DOS32BEEP
+DOS32PHYSICALDISK DOS32PHYSICALDISK
+DOS32SETCP DOS32SETCP
+DOS32SETPROCESSCP DOS32SETPROCESSCP
+DOS32STOPTIMER DOS32STOPTIMER
+DOS32QUERYCP DOS32QUERYCP
+DOS32SETDATETIME DOS32SETDATETIME
+DOS32EXITLIST DOS32EXITLIST
+DOS32ALLOCPROTECTEDMEM DOS32ALLOCPROTECTEDMEM
+DOS32ALIASMEM DOS32ALIASMEM
+DOS32ALLOCMEM DOS32ALLOCMEM
+DOS32ALLOCSHAREDMEM DOS32ALLOCSHAREDMEM
+DOS32GETNAMEDSHAREDMEM DOS32GETNAMEDSHAREDMEM
+DOS32GETSHAREDMEM DOS32GETSHAREDMEM
+DOS32GIVESHAREDMEM DOS32GIVESHAREDMEM
+DOS32FREEMEM DOS32FREEMEM
+DOS32SETMEM DOS32SETMEM
+DOS32QUERYMEM DOS32QUERYMEM
+DOS32CREATETHREAD DOS32CREATETHREAD
+DOS32GETTHREADINFO DOS32GETTHREADINFO
+DOS32GETPROCESSINFO DOS32GETPROCESSINFO
+DOS32LOADMODULE DOS32LOADMODULE
+DOS32QUERYMODULEHANDLE DOS32QUERYMODULEHANDLE
+DOS32QUERYMODULENAME DOS32QUERYMODULENAME
+DOS32QUERYPROCADDR DOS32QUERYPROCADDR
+DOS32QUERYPROCTYPE DOS32QUERYPROCTYPE
+DOS32FREEMODULE DOS32FREEMODULE
+DOS32QUERYAPPTYPE DOS32QUERYAPPTYPE
+DOS32CREATEEVENTSEM DOS32CREATEEVENTSEM
+DOS32OPENEVENTSEM DOS32OPENEVENTSEM
+DOS32CLOSEEVENTSEM DOS32CLOSEEVENTSEM
+DOS32RESETEVENTSEM DOS32RESETEVENTSEM
+DOS32POSTEVENTSEM DOS32POSTEVENTSEM
+DOS32WAITEVENTSEM DOS32WAITEVENTSEM
+DOS32QUERYEVENTSEM DOS32QUERYEVENTSEM
+DOS32CREATEMUTEXSEM DOS32CREATEMUTEXSEM
+DOS32OPENMUTEXSEM DOS32OPENMUTEXSEM
+DOS32CLOSEMUTEXSEM DOS32CLOSEMUTEXSEM
+DOS32REQUESTMUTEXSEM DOS32REQUESTMUTEXSEM
+DOS32RELEASEMUTEXSEM DOS32RELEASEMUTEXSEM
+DOS32QUERYMUTEXSEM DOS32QUERYMUTEXSEM
+DOS32CREATEMUXWAITSEM DOS32CREATEMUXWAITSEM
+DOS32OPENMUXWAITSEM DOS32OPENMUXWAITSEM
+DOS32CLOSEMUXWAITSEM DOS32CLOSEMUXWAITSEM
+DOS32WAITMUXWAITSEM DOS32WAITMUXWAITSEM
+DOS32ADDMUXWAITSEM DOS32ADDMUXWAITSEM
+DOS32DELETEMUXWAITSEM DOS32DELETEMUXWAITSEM
+DOS32QUERYMUXWAITSEM DOS32QUERYMUXWAITSEM
+DOS32SUBSET DOS32SUBSET
+DOS32SUBALLOC DOS32SUBALLOC
+DOS32SUBFREE DOS32SUBFREE
+DOS32SUBUNSET DOS32SUBUNSET
+DOS32QUERYSYSINFO DOS32QUERYSYSINFO
+DOS32WAITTHREAD DOS32WAITTHREAD
+DOS32ASYNCTIMER DOS32ASYNCTIMER
+DOS32STARTTIMER DOS32STARTTIMER
+DOS32GETRESOURCE DOS32GETRESOURCE
+DOS32QUERYRESOURCESIZE DOS32QUERYRESOURCESIZE
+DOS32FREERESOURCE DOS32FREERESOURCE
+DOS32GETCTRYINFO DOS32GETCTRYINFO
+DOS32QUERYCTRYINFO DOS32QUERYCTRYINFO
+DOS32QUERYDBCSENV DOS32QUERYDBCSENV
+DOS32MAPCASE DOS32MAPCASE
+DOS32QUERYCOLLATE DOS32QUERYCOLLATE
+DOS32GETMESSAGE DOS32GETMESSAGE
+DOS32INSERTMESSAGE DOS32INSERTMESSAGE
+DOS32PUTMESSAGE DOS32PUTMESSAGE
+DOS32QUERYMESSAGECP DOS32QUERYMESSAGECP
+DOS32STARTSESSION DOS32STARTSESSION
+DOS32SETSESSION DOS32SETSESSION
+DOS32SELECTSESSION DOS32SELECTSESSION
+DOS32STOPSESSION DOS32STOPSESSION
+DOS32CREATEQUEUE DOS32CREATEQUEUE
+DOS32OPENQUEUE DOS32OPENQUEUE
+DOS32CLOSEQUEUE DOS32CLOSEQUEUE
+DOS32PURGEQUEUE DOS32PURGEQUEUE
+DOS32QUERYQUEUE DOS32QUERYQUEUE
+DOS32PEEKQUEUE DOS32PEEKQUEUE
+DOS32READQUEUE DOS32READQUEUE
+DOS32WRITEQUEUE DOS32WRITEQUEUE
+DOS32ENTERMUSTCOMPLETE DOS32ENTERMUSTCOMPLETE
+DOS32EXITMUSTCOMPLETE DOS32EXITMUSTCOMPLETE
+DOS32ACKNOWLEDGESIGNALEXCEPTION DOS32ACKNOWLEDGESIGNALEXCEPTION
+DOS32SETSIGNALEXCEPTIONFOCUS DOS32SETSIGNALEXCEPTIONFOCUS
+DOS32SENDSIGNALEXCEPTION DOS32SENDSIGNALEXCEPTION
+DOS32RAISEEXCEPTION DOS32RAISEEXCEPTION
+DOS32UNWINDEXCEPTION DOS32UNWINDEXCEPTION
diff --git a/private/os2/doc/fy92.ppt b/private/os2/doc/fy92.ppt
new file mode 100644
index 000000000..9558ee7c9
--- /dev/null
+++ b/private/os2/doc/fy92.ppt
Binary files differ
diff --git a/private/os2/doc/incompat.os2 b/private/os2/doc/incompat.os2
new file mode 100644
index 000000000..45220accf
--- /dev/null
+++ b/private/os2/doc/incompat.os2
@@ -0,0 +1,55 @@
+Note:
+This file contains a list of known incompatibilities between NT OS/2 and
+OS/2 v2.0, as of April 1st 1991. The focus of os2ss is now 16bit binary
+support for os2 apps, but this file is here for reference.
+Yarons 27-Aug-1991.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+DosFindFirst/Next
+
+Information levels 2 and 3 fail under certain circumstances in NT OS/2 when
+they succeed in OS/2 v2.0. Levels 2 and 3 query EA information. In NT OS/2,
+retrieving this information requires opening the file. If another process has
+the file open in a sharing mode which does not permit the file to be opened,
+the call to DosFindFirst/Next will fail. In OS/2, the file does not have to
+be opened to retrieve the information.
+
+NT OS/2 requires that a directory being searched with DosFindFirst/Next be
+open until DosFindClose is called and the search is terminated. Thus the
+directory cannot be removed. Under OS/2, a DosDeleteDir would be successful.
+This is not a big problem because unless the directory is empty, the rmdir
+would fail anyway.
+
+DosErrorClass
+
+Some error codes are meaningless in NT OS/2 and will not be supported by
+DosErrorClass.
+
+#define ERR_TSTOVFL 91
+#define ERR_TSTDUP 92
+#define ERROR_VIOKBD_REQUEST 116
+#define ERROR_AUTODATASEG_EXCEEDS_64k 199
+#define ERROR_MOUSE_NO_DATA 393
+#define ERROR_MOUSE_PTR_DRAWN 394
+
+
+DosSetPath/FileInfo (level 1)
+
+OS/2 v2.0 allows invalid dates and times to be set on a file (i.e. Feb 30).
+NT OS/2 does not. The OS/2 subsystem will return an error code.
+
+DosQueryMem
+
+NT OS/2 is 100% accurate in reporting whether a page is executable. OS/2
+v2.0 is not always correct.
+
+
+NEWFILES
+
+This exe header bit is ignored. It is effectively always on: all apps
+see long names, EAs, and case-preservation.
+
+
+DosDebug
+
+This API is not supported in NT OS/2
diff --git a/private/os2/doc/ioctls.txt b/private/os2/doc/ioctls.txt
new file mode 100644
index 000000000..18b82450e
--- /dev/null
+++ b/private/os2/doc/ioctls.txt
@@ -0,0 +1,3703 @@
+This file contains documentation about all of the 16 bit IOCTL functions
+that are supported by the 32-bit DosDevIOCTL function in Cruisers. For
+each category and function, there is a comment saying whether or not the
+category or function is supported or not. Those marked with question marks
+mean that I am not sure yet how it will be supported or not.
+
+
+Topic: ASYNC_IOCTL_CATEGORY 0x0001 // Supported
+
+Topic: ASYNC_GETBAUDRATE 0x0061 // Supported
+
+APIRET DosDevIOCtl( pusBaudRate, 0L, 0x0061, ASYNC_IOCTL_CATEGORY, hDevice )
+PUSHORT pusBaudRate; /* pointer to variable for baud rate */
+HFILE hDevice; /* device handle */
+
+The ASYNC_GETBAUDRATE function retrieves the baud rate for the specified
+serial device. The baud rate specifies the number of bits per second that
+the serial device transmits or receives.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pusBaudRate Points to the variable that receives the baud rate.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: ASYNC_GETCOMMERROR 0x006D // Supported
+
+APIRET DosDevIOCtl( pfCommErr, 0L, 0x006D, ASYNC_IOCTL_CATEGORY, hDevice )
+PUSHORT pfCommErr; /* pointer to variable for error */
+HFILE hDevice; /* device handle */
+
+The ASYNC_GETCOMMERROR function retrieves the communication error word.
+After copying the error-word value to the specified variable, the function
+clears the error word.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfCommErr Points to the variable that receives the communication status of
+ the device. This variable can be a combination of the following
+ values:
+
+ Value Meaning
+ -----------------------------------------------------------------
+ RX_QUE_OVERRUN Receive-queue overrun. There is no room in
+ the device-driver receive queue to put a
+ character read in from the receive
+ hardware.
+
+ RX_HARDWARE_OVERRUN Receive-hardware overrun. A character
+ arrived before the previous character was
+ completely read. The previous character is
+ lost.
+
+ PARITY_ERROR The hardware detected a parity error.
+
+ FRAMING_ERROR The hardware detected a framing error.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful. When an error
+occurs, the function returns an error value, and any value copied to the
+variable pointed to by the pfCommErr parameter is not valid, and the
+function does not clear the error word.
+
+Comments
+
+Other than using this function, the only way to clear the communications
+error word for a device is to open the device when there are no outstanding
+open handles for it. For more information, see the ASYNC_SETDCBINFO function
+(0x0001, 0x0053).
+
+ o
+
+Topic: ASYNC_GETCOMMEVENT 0x0072 // Supported
+
+APIRET DosDevIOCtl( pfEvent, 0L, 0x0072, ASYNC_IOCTL_CATEGORY, hDevice )
+PUSHORT pfEvent; /* pointer to variable for events */
+HFILE hDevice; /* device handle */
+
+The ASYNC_GETCOMMEVENT function retrieves the communications event flags
+from the internally maintained event word. After the function copies the
+event flags to the specified variable, it clears the event word.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfEvent Points to the variable that receives the event flags. This
+ variable can be a combination of the following values:
+
+ Value Meaning
+ -----------------------------------------------------------------
+ CHAR_RECEIVED A character has been read from the serial-device
+ receive hardware and placed in the receive
+ queue.
+
+ LAST_CHAR_SENT The last character in the device-driver transmit
+ queue has been sent to the serial-device transmit
+ hardware. This does not mean there is no data to
+ send in any outstanding write requests.
+
+ CTS_CHANGED The clear-to-send (CTS) signal has changed
+ state.
+
+ DSR_CHANGED The data-set-ready (DSR) signal has changed
+ state.
+
+ DCD_CHANGED The data-carrier-detect (DCD) signal has changed
+ state.
+
+ BREAK_DETECTED A break has been detected.
+
+ ERROR_OCCURRED A parity, framing, or overrun error has occurred.
+ An overrun can be a receive hardware overrun or a
+ receive queue overrun.
+
+ RI_DETECTED The trailing edge of the ring indicator (RI) has
+ been detected.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+This function clears the event word only when it is successful. The event
+word remains unchanged until the device is fully closed (there are no
+outstanding open handles) and then reopened.
+
+ o
+
+Topic: ASYNC_GETCOMMSTATUS 0x0064 // Supported
+
+APIRET DosDevIOCtl( pbStatus, 0L, 0x0064, ASYNC_IOCTL_CATEGORY, hDevice )
+PBYTE pbStatus; /* pointer to variable for status */
+HFILE hDevice; /* device handle */
+
+The ASYNC_GETCOMMSTATUS function retrieves the communication status of the
+specified device.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbStatus Points to the variable that receives the communication status.
+ This variable can be a combination of the following values:
+
+ Value Meaning
+ -----------------------------------------------------------------
+ TX_WAITING_FOR_CTS Transmission is waiting for the
+ clear-to-send (CTS) signal to be
+ turned on. For a full description, see
+ the ASYNC_SETDCBINFO function (0x0001,
+ 0x0053).
+
+ TX_WAITING_FOR_DSR Transmission is waiting for the
+ data-set-ready (DSR) signal to be
+ turned on. For a full description, see
+ the ASYNC_SETDCBINFO function (0x0001,
+ 0x0053).
+
+ TX_WAITING_FOR_DCD Transmission is waiting for the
+ data-carrier-detected (DCD) signal to
+ be turned on. For a full description,
+ see the ASYNC_SETDCBINFO function
+ (0x0001, 0x0053).
+
+ TX_WAITING_FOR_XON Transmission is waiting because the
+ XOFF character is received. For a full
+ description, see the following
+ "Comments" section.
+
+ TX_WAITING_TO_SEND_XON Transmission is waiting because the
+ XOFF character is transmitted. For a
+ full description, see the following
+ "Comments" section.
+
+ TX_WAITING_WHILE_BREAK_ON Transmission is waiting because a
+ break is being transmitted. For a full
+ description, see the ASYNC_SETBREAKON
+ function (0x0001, 0x004B).
+
+ TX_WAITING_TO_SEND_IMM Character is waiting to transmit
+ immediately. For a full description,
+ see the ASYNC_TRANSMITIMM function
+ (0x0001, 0x0044).
+
+ RX_WAITING_FOR_DSR Receive state is waiting for the
+ data-set-ready (DSR) signal to be
+ turned on. For a full description, see
+ the ASYNC_SETDCBINFO function (0x0001,
+ 0x0053).
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+Transmit status indicates why transmission is not occurring, regardless of
+whether or not there is data to transmit. However, the device driver must be
+enabled for the given condition (for example, enabled for output handshaking
+for the modem-control signal) for the status to reflect that the device
+driver is waiting for the given condition to transmit.
+
+For example, TX_WAITING_FOR_CTS means that the device driver puts receive
+characters in the device-driver receive queue, the device driver is not
+waiting to transmit a character immediately, and characters from the
+device-driver transmit queue are not transmitted because the clear-to-send
+(CTS) signal for output handshaking is used and CTS does not have the proper
+value.
+
+The communication status can include TX_WAITING_TO_SEND_XON if the device
+driver is enabled for automatic transmit flow control (XON/XOFF) or if the
+ASYNC_STOPTRANSMIT function (0x0001, 0x0047) has been used to tell the
+device driver to function as if an XOFF character is received. The
+ASYNC_TRANSMITIMM function (0x0001, 0x0044) can still be used to transmit
+characters immediately. The device driver can still automatically transmit
+XON and XOFF characters due to automatic receive flow control (XON/XOFF)
+when the device driver is in this state.
+
+The communication status can include TX_WAITING_FOR_XON if the device driver
+is enabled for automatic receive flow control. When in this state, the
+ASYNC_TRANSMITIMM function (0x0001, 0x0044) can still be used to transmit
+characters immediately, and the device driver can still automatically
+transmit XON characters.
+
+ o
+
+Topic: ASYNC_GETDCBINFO 0x0073 // Supported
+
+APIRET DosDevIOCtl( pusDCB, 0L, 0x0073, ASYNC_IOCTL_CATEGORY, hDevice )
+PUSHORT pusDCB; /* pointer to structure for device-control information */
+HFILE hDevice; /* device handle */
+
+The ASYNC_GETDCBINFO function retrieves device-control block information.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pusDCB Points to the DCBINFO structure that receives the device-control
+ block information.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful. When an error
+occurs, the function returns an error value, and any data copied to the
+DCBINFO structure pointed to by the pusDCB parameter is not valid.
+
+Comments
+
+To ensure that only valid values are set in the device-control block, the
+program should call the ASYNC_GETDCBINFO function to fill the block, and
+then modify the settings and call the ASYNC_SETDCBINFO function with the
+modified block.
+
+ o
+
+Topic: ASYNC_GETINQUECOUNT 0x0068 // Supported
+
+APIRET DosDevIOCtl( pcReceiveQue, 0L, 0x0068, ASYNC_IOCTL_CATEGORY, hDevice )
+PUSHORT pcReceiveQue; /* pointer to structure for character count */
+HFILE hDevice; /* device handle */
+
+The ASYNC_GETINQUECOUNT function retrieves the number of characters in the
+receive queue.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pcReceiveQue Points to the RXQUEUE structure that receives the count of
+ characters in the receive queue.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by
+ using the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The device-driver receive queue is a memory buffer between the memory
+pointed to by the read-request packet and the receive hardware for this
+serial device. The application may not assume that there are no unsatisfied
+read requests if there are characters in the device-driver receive queue.
+The behavior of data movement between the read request and the receive queue
+may change from release to release of the device driver. Programs should not
+be written to have a dependency on this information.
+
+Programs should be written to be independent of the receive queue being a
+fixed size. The information in this field allows the application to get the
+size of the receive queue. The current size of the receive queue is
+approximately 1K but is subject to change.
+
+The application should be written to avoid device-driver receive queue
+overruns by using an application-to-application block protocol with the
+system the application is communicating with.
+
+ o
+
+Topic: ASYNC_GETLINECTRL 0x0062 // Supported
+
+APIRET DosDevIOCtl( pbLineCtrl, 0L, 0x0062, ASYNC_IOCTL_CATEGORY, hDevice )
+PBYTE pbLineCtrl; /* pointer to structure for control settings */
+HFILE hDevice; /* device handle */
+
+The ASYNC_GETLINECTRL function retrieves the line characteristics (stop
+bits, parity, data bits, break) for the specified device.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbLineCtrl Points to a LINECONTROL structure that receives the settings for
+ the number of data bits, parity, and number of stop bits.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: ASYNC_GETLINESTATUS 0x0065 // Supported
+
+APIRET DosDevIOCtl( pbTransStatus, 0L, 0x0065, ASYNC_IOCTL_CATEGORY, hDevice )
+PBYTE pbTransStatus; /* pointer to variable for status */
+HFILE hDevice; /* device handle */
+
+The ASYNC_GETLINESTATUS function retrieves the data-transmission status for
+the specified serial device.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbTransStatus Points to the variable that receives the data-transmission
+ status. This variable can be a combination of the following
+ values:
+
+ Value Meaning
+ -------------------------------------------------------------
+ WRITE_REQUEST_QUEUED Write-request packets in progress or
+ queued.
+
+ DATA_IN_TX_QUE Data in the device-driver transmit
+ queue.
+
+ HARDWARE_TRANSMITTING Transmit hardware currently
+ transmitting data.
+
+ CHAR_READY_TO_SEND_IMM Character waiting to be transmitted
+ immediately.
+
+ WAITING_TO_SEND_XON Waiting to automatically transmit
+ XON.
+
+ WAITING_TO_SEND_XOFF Waiting to automatically transmit
+ XOFF.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by
+ using the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: ASYNC_GETMODEMINPUT 0x0067 // Supported
+
+APIRET DosDevIOCtl( pbCtrlSignals, 0L, 0x0067, ASYNC_IOCTL_CATEGORY, hDevice )
+PBYTE pbCtrlSignals; /* pointer to variable for control signals */
+HFILE hDevice; /* device handle */
+
+The ASYNC_GETMODEMINPUT function retrieves the modem-control input signals
+for the specified device.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCtrlSignals Points to the variable that receives the modem-control
+ signals. This variable can be a combination of the following
+ values:
+
+ Value Meaning
+ -------------------------------------------------------------
+ CTS_ON Clear-to-send (CTS) signal is on. If not given, the
+ signal is off.
+
+ DSR_ON Data-set-ready (DSR) signal is on. If not given, the
+ signal is off.
+
+ RI_ON Ring-indicator (RI) signal is on. If not given, the
+ signal is off.
+
+ DCD_ON Data-carrier-detect (DCD) signal is on. If not given,
+ the signal is off.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by
+ using the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: ASYNC_GETMODEMOUTPUT 0x0066 // Supported
+
+APIRET DosDevIOCtl( pbCtrlSignals, 0L, 0x0066, ASYNC_IOCTL_CATEGORY, hDevice )
+PBYTE pbCtrlSignals; /* pointer to variable for control signals */
+HFILE hDevice; /* device handle */
+
+The ASYNC_GETMODEMOUTPUT function retrieves the modem-control output signals
+for the specified device.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCtrlSignals Points to the variable that receives the modem-control
+ signals. This variable can be one or both of the following
+ values:
+
+ Value Meaning
+ -------------------------------------------------------------
+ DTR_ON Data-terminal-ready (DTR) signal is on. If not given,
+ the signal is off.
+
+ RTS_ON Request-to-send (RTS) signal is on. If not given, the
+ signal is off.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by
+ using the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: ASYNC_GETOUTQUECOUNT 0x0069 // Supported
+
+APIRET DosDevIOCtl( pcTransmitQue, 0L, 0x0069, ASYNC_IOCTL_CATEGORY, hDevice )
+PUSHORT pcTransmitQue; /* pointer to structure for character count */
+HFILE hDevice; /* device handle */
+
+The ASYNC_GETOUTQUECOUNT function retrieves a count of characters in the
+transmit queue.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pcTransmitQue Points to the RXQUEUE structure that receives the count of
+ characters in the transmit queue.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by
+ using the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The device-driver transmit queue is a memory buffer between the memory
+pointed to by the write-request packet and the transmit hardware for this
+serial device. If the transmit queue is empty, the program may not assume
+that all write requests are completed or that no write requests are
+outstanding. The behavior of data movement between the write request and the
+transmit queue may change from release to release of the device driver.
+Programs should not be written to have a dependency on this information.
+
+Programs should be written to be independent of the transmit queue being a
+fixed size. The information in this field allows the application to get the
+size of the transmit queue. The current size of the transmit queue is
+approximately 128 bytes but is subject to change.
+
+ o
+
+Topic: ASYNC_SETBAUDRATE 0x0041 // Supported
+
+APIRET DosDevIOCtl( 0L, pusBitRate, 0x0041, ASYNC_IOCTL_CATEGORY, hDevice )
+PUSHORT pusBitRate; /* pointer to variable with baud rate */
+HFILE hDevice; /* device handle */
+
+The ASYNC_SETBAUDRATE function sets the baud rate for the specified serial
+device. The baud rate specifies the number of bits per second that the
+serial device transmits or receives.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pusBitRate Points to the variable that contains the baud rate. This
+ parameter can be any one of the following values: 110, 150, 300,
+ 600, 1200, 2400, 4800, 9600, or 19200.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+the specified baud rate is out of range or an error occurs.
+
+Comments
+
+The initial rate for a serial device is 1200 baud. Once the rate is set, it
+remains unchanged until set again, even if the device is closed and then
+reopened.
+
+ o
+
+Topic: ASYNC_SETBREAKOFF 0x0045 // Supported
+
+APIRET DosDevIOCtl( pfCommErr, 0L, 0x0045, ASYNC_IOCTL_CATEGORY, hDevice )
+PUSHORT pfCommErr; /* pointer to variable for error value */
+HFILE hDevice; /* device handle */
+
+The ASYNC_SETBREAKOFF function turns off the break character. The device
+driver stops generating a break signal. It is not considered an error if the
+device driver is not generating a break signal. The device driver then
+resumes transmitting characters, taking into account all the other reasons
+why it may or may not transmit characters.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfCommErr Points to the variable that receives the communication status of
+ the device. This variable can be a combination of the following
+ values:
+
+ Value Meaning
+ -----------------------------------------------------------------
+ RX_QUE_OVERRUN Receive queue overrun. There is no room in
+ the device-driver receive queue to put a
+ character read in from the receive
+ hardware.
+
+ RX_HARDWARE_OVERRUN Receive hardware overrun. A character
+ arrived before the previous character was
+ completely read. The previous character is
+ lost.
+
+ PARITY_ERROR The hardware detected a parity error.
+
+ FRAMING_ERROR The hardware detected a framing error.
+
+ The function sets the variable to zero if it encounters an
+ error.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: ASYNC_SETBREAKON 0x004B // Supported
+
+APIRET DosDevIOCtl( pfCommErr, 0L, 0x004B, ASYNC_IOCTL_CATEGORY, hDevice )
+PUSHORT pfCommErr; /* pointer to variable for error value */
+HFILE hDevice; /* device handle */
+
+The ASYNC_SETBREAKON function turns on the break character. The device
+driver generates the break signal immediately. It is not considered an error
+if the device driver is already generating a break signal. The device driver
+does not wait for the transmit hardware to become empty. However, more data
+will not be given to the transmit hardware until the break is turned off.
+The break signal will always be transmitted, regardless of whether the
+device driver is or is not transmitting characters due to other reasons.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfCommErr Points to the variable that receives the communication status of
+ the device. This variable can be a combination of the following
+ values:
+
+ Value Meaning
+ -----------------------------------------------------------------
+ RX_QUE_OVERRUN Receive queue overrun. There is no room in
+ the device-driver receive queue to put a
+ character read in from the receive
+ hardware.
+
+ RX_HARDWARE_OVERRUN Receive hardware overrun. A character
+ arrived before the previous character was
+ completely read. The previous character is
+ lost.
+
+ PARITY_ERROR The hardware detected a parity error.
+
+ FRAMING_ERROR The hardware detected a framing error.
+
+ The function sets the variable to zero if it encounters an
+ error.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+Closing the device turns off the break character if there are no outstanding
+open device handles.
+
+ o
+
+Topic: ASYNC_SETDCBINFO 0x0053 // Supported
+
+APIRET DosDevIOCtl( 0L, pusDCB, 0x0053, ASYNC_IOCTL_CATEGORY, hDevice )
+PUSHORT pusDCB; /* pointer to structure with device-control information */
+HFILE hDevice; /* device handle */
+
+The ASYNC_SETDCBINFO function sets device-control block information.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pusDCB Points to the DCBINFO structure that receives the device-control
+ block information.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful. When an error
+occurs, the function returns an error value, and the device-control block
+characteristics of the device driver for this serial device remain
+unchanged.
+
+Comments
+
+A program can prevent making unwanted changes to device modes by calling the
+ASYNC_GETDCBINFO function (0x0001,0x0073) to retrieve a copy of the current
+DCB. The program can then modify only those fields it needs to and use the
+modified DCB with the ASYNC_SETDCBINFO function.
+
+ o
+
+Topic: ASYNC_SETLINECTRL 0x0042 // Supported
+
+APIRET DosDevIOCtl( 0L, pbLineCtrl, 0x0042, ASYNC_IOCTL_CATEGORY, hDevice )
+PBYTE pbLineCtrl; /* pointer to structure with line settings */
+HFILE hDevice; /* device handle */
+
+The ASYNC_SETLINECTRL function sets the line characteristics (stop bits,
+parity, and data bits) for the specified serial device.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbLineCtrl Points to the LINECONTROL structure that contains the settings
+ for the number of data bits, parity, and number of stop bits.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+any of the specified line characteristics is out of range. When an error
+occurs, line characteristics remain unchanged.
+
+Comments
+
+When a device is first opened, the initial line characteristics are 7 data
+bits, even parity, and 1 stop bit. After line characteristics are changed,
+they remain changed until the function is used again, even if the device is
+closed and reopened.
+
+If the number of data bits is less than 8, the device driver fills with
+zeros the unused high-order bits of each character it receives from the
+device; the device driver ignores the unused high-order bits of characters
+it receives from the program. Therefore, if the number of data bits is 7 but
+the XOFF character is 0x80, the device driver does not recognize the XOFF
+character even when automatic-transmission control is enabled. If the error
+substitution character is 0x80, the device driver still places 0x80 in the
+receive queue. Programs must see that these characters match the specified
+data size. Any characters that were in the receive queue before the function
+is called remain unchanged.
+
+ o
+
+Topic: ASYNC_SETMODEMCTRL 0x0046 // Supported
+
+APIRET DosDevIOCtl( pfCommErr, pbCtrlSignals, 0x0046, ASYNC_IOCTL_CATEGORY, hDevice )
+PUSHORT pfCommErr; /* pointer to variable for error value */
+PBYTE pbCtrlSignals; /* pointer to structure with control signals */
+HFILE hDevice; /* device handle */
+
+The ASYNC_SETMODEMCTRL function sets the modem-control signals. This
+function turns on or off the data-terminal-ready (DTR) and ready-to-transmit
+(RTS) signals (initially, the DTR and RTS signals are turned off).
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfCommErr Points to the variable that receives the communication status
+ of the device. This variable can be a combination of the
+ following values:
+
+ Value Meaning
+ -------------------------------------------------------------
+ RX_QUE_OVERRUN Receive queue overrun. There is no room
+ in the device driver receive queue to
+ put a character read in from the receive
+ hardware.
+
+ RX_HARDWARE_OVERRUN Receive hardware overrun. A character
+ arrived before the previous character
+ was completely read. The previous
+ character is lost.
+
+ PARITY_ERROR The hardware detected a parity error.
+
+ FRAMING_ERROR The hardware detected a framing error.
+
+ The function sets the variable to zero if it encounters an
+ error.
+
+pbCtrlSignals Points to the MODEMSTATUS structure that contains the
+ settings for the modem-control signals.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by
+ using the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+the specified signal settings are invalid. When an error occurs, the signal
+settings remain unchanged.
+
+Comments
+
+This function must not be used to enable or disable the DTR or RTS signal if
+the signal is being used for input handshaking or toggling on transmit. Any
+attempt to do so will cause a "general failure" error.
+
+Although the function copies the communication error status to the variable
+pointed to by the pfCommErr parameter, it does not clear the error.
+
+If the serial device is opened after having been closed, the DTR and RTS
+signals are set to the values specified by the DTR control mode and the RTS
+control mode, respectively. For a full description, see the
+ASYNC_SETDCBINFO function (0x0001,0x0053).
+
+After a serial device has been closed, the device driver turns off the DTR
+and RTS signals, but only after the device has transmitted all data and has
+waited for at least as long as it would take to transmit 10 additional
+characters.
+
+ o
+
+Topic: ASYNC_STARTTRANSMIT 0x0048 // Supported
+
+APIRET DosDevIOCtl( 0L, 0L, 0x0048, ASYNC_IOCTL_CATEGORY, hDevice )
+HFILE hDevice; /* device handle */
+
+The ASYNC_STARTTRANSMIT function starts transmission. This function allows
+data transmission to be resumed by the device driver if data transmission is
+halted due to the ASYNC_STOPTRANSMIT function (0x0001,0x0047) or due to an
+XOFF character being received while the device driver is in automatic
+transmit flow control mode. This function is similar to the device receiving
+the XON character.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+There may be other reasons why transmission is disabled; transmission may
+not be resumed. For more information, see the ASYNC_GETCOMMSTATUS function
+(0x0001,0x0064).
+
+ o
+
+Topic: ASYNC_STOPTRANSMIT 0x0047 // Supported
+
+APIRET DosDevIOCtl( 0L, 0L, 0x0047, ASYNC_IOCTL_CATEGORY, hDevice )
+HFILE hDevice; /* device handle */
+
+The ASYNC_STOPTRANSMIT function stops the device from transmitting. This
+function stops data transmission by preventing the device driver from
+sending additional data to the transmit hardware. This function is similar
+to the device receiving the XOFF character.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+If automatic-transmission control is enabled, this request causes the device
+driver to behave exactly as if it received the XOFF character. Transmission
+can be resumed if an XON character is received by the device driver, if an
+ASYNC_STARTTRANSMIT (0x0001,0x0048) function is received, or if the device
+driver is told to disable automatic-transmission control and in the previous
+state automatic-transmission control was enabled.
+
+If automatic-transmission control is disabled, the ASYNC_STARTTRANSMIT
+function (0x0001,0x0048) must be called for transmission to resume. If,
+after this request is received, the device driver is told to enable
+automatic-transmission control, transmission is still disabled. It can be
+re-enabled by any of the scenarios discussed above.
+
+There still may be other reasons why transmission may be disabled. For more
+information, see the ASYNC_GETCOMMSTATUS function (0x0001,0x0064).
+
+ o
+
+Topic: ASYNC_TRANSMITIMM 0x0044 // Supported
+
+APIRET DosDevIOCtl( 0L, pbChar, 0x0044, ASYNC_IOCTL_CATEGORY, hDevice )
+PBYTE pbChar; /* pointer to character */
+FILE hDevice; /* device handle */
+
+The ASYNC_TRANSMITIMM function transmits the specified byte immediately.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbChar Points to the character to be transmitted.
+
+hDevice Identifies the serial device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The device driver queues the character as the next character to be
+transmitted even if there are already characters in the transmit queue.
+
+If automatic-receiving control is enabled, an XON or XOFF character may be
+transmitted before the requested character.
+
+The function always returns before the character is actually transmitted.
+
+If a character is already waiting to be transmitted immediately, the
+function returns an error. The ASYNC_GETCOMMSTATUS function (0x0001,0x0064)
+can be used to determine whether a character is currently waiting to be
+transmitted immediately.
+
+The device driver will not immediately transmit the character that is
+waiting to be transmitted immediately if the device driver is not
+transmitting characters due to modem-control signal-output handshaking or if
+the device driver is currently transmitting a break.
+
+If the device driver is not transmitting characters due to automatic
+transmission or receiving control (XON/XOFF) being enabled or due to
+operating as if an XOFF character had been received, the device driver still
+transmits a character that is waiting to be transmitted immediately due to
+this request. An application that requests that the device driver transmit a
+character immediately if automatic transmission or receiving control is
+enabled may cause unexpected results to happen to the communications line
+flow control protocol.
+
+This function is generally used to manually send XON and XOFF characters.
+
+The character waiting to be transmitted immediately is not considered part
+of the device driver transmit queue and is not flushed due to a flush
+request. XON/XOFF characters that are automatically transmitted due to
+automatic-receiving control may or may not be placed ahead of the character
+waiting to be transmitted immediately. Applications should not be dependent
+on this ordering.
+
+ o
+
+Topic: DEV_IOCTL_CATEGORY 0x000B // Supported
+
+Topic: DEV_FLUSHINPUT 0x0001 // Supported
+
+APIRET DosDevIOCtl( 0L, pbCommand, 0x0001, DEV_IOCTL_CATEGORY, hDevice )
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The DEV_FLUSHINPUT function flushes the input buffer.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCommand Points to the variable that contains a reserved value. This value
+ must be zero.
+
+hDevice Identifies the device that receives the device-control function.
+ The handle must have been created previously by using the
+ DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: DEV_FLUSHOUTPUT 0x0002 // Supported
+
+APIRET DosDevIOCtl( 0L, pbCommand, 0x0002, DEV_IOCTL_CATEGORY, hDevice )
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The DEV_FLUSHOUTPUT function flushes the output buffer.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCommand Points to the variable that contains a reserved value. This value
+ must be zero.
+
+hDevice Identifies the device that receives the device-control function.
+ The handle must have been created previously by using the
+ DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: DEV_QUERYMONSUPPORT 0x0060 // Supported, returns error
+
+APIRET DosDevIOCtl( 0L, pbCommand, 0x0060, DEV_IOCTL_CATEGORY, hDevice )
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The DEV_QUERYMONSUPPORT function queries a device driver for monitor
+support.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCommand Points to the variable that contains a reserved value. This value
+ must be zero.
+
+hDevice Identifies the device that receives the device-control function.
+ The handle must have been created previously by using the
+ DosOpen function.
+
+Return Value
+
+The return value is zero if the device supports character monitors or an
+error value if an error occurs.
+
+ o
+
+Topic: DSK_IOCTL_CATEGORY 0x0008 // Supported, mostly
+
+
+Topic: DSK_BLOCKREMOVABLE 0x0020 // Supported
+
+APIRET DosDevIOCtl( pfNonRemovable, pbCommand, 0x0020, DSK_IOCTL_CATEGORY, hDevice )
+PBYTE pfNonRemovable; /* pointer to removable/nonremovable flag */
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The DSK_BLOCKREMOVABLE function indicates whether the block device is
+removable.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfNonRemovable Points to the variable that receives the medium type. This
+ variable is 0x0000 if the medium is removable or 0x0001 if
+ it is nonremovable.
+
+pbCommand Points to the variable that contains a reserved value. This
+ value must be zero.
+
+hDevice Identifies the disk-drive that receives the device-control
+ function. The handle must have been created previously by
+ using the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: DSK_FORMATVERIFY 0x0045 // Supported
+
+APIRET DosDevIOCtl( 0L, pbCommand, 0x0045, DSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbCommand; /* pointer to structure with command */
+HFILE hDevice; /* device handle */
+
+The DSK_FORMATVERIFY function formats and verifies a track on a disk drive
+according to the information passed in the format table. The format table is
+passed to the controller and the controller performs whatever operations are
+necessary for formatting.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCommand Points to the TRACKFORMAT structure that contains information
+ about the format operation.
+
+hDevice Identifies the disk-drive that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+Some controllers do not support formatting tracks with varying sector sizes.
+The program must make sure that the sector sizes specified in the format
+table are all the same.
+
+ o
+
+Topic: DSK_GETDEVICEPARAMS 0x0063 // Not Supported (?????)
+
+APIRET DosDevIOCtl( pbBPB, pbCommand, 0x0063, DSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbBPB; /* pointer to structure for BIOS parameter blocks */
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The DSK_GETDEVICEPARAMS function retrieves the device parameters for an MS
+OS/2 block device. The device driver maintains two BIOS parameter blocks
+(BPB) for each disk drive. One block corresponds to the medium currently in
+the disk drive. The other is a recommended BPB, based on the type of medium
+that corresponds to the physical device. For example, a high-density disk
+drive has a BPB for a 96 tracks-per-inch (tpi) floppy disk; a low-density
+disk drive has a BPB for a 48-tpi floppy disk.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbBPB Points to the BIOSPARAMETERBLOCK structure that receives the
+ BPB.
+
+pbCommand Points to the variable that specifies which BPB to retrieve. If
+ the variable is 0x0000, the function retrieves the recommended
+ BPB for the drive (the BPB for the physical device). If the
+ variable is 0x0001, the function retrieves the BPB for the medium
+ currently in the drive.
+
+hDevice Identifies the disk drive that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: DSK_GETLOGICALMAP 0x0021 // Supported (?????)
+
+APIRET DosDevIOCtl( pbDrive, pbCommand, 0x0021, DSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbDrive; /* pointer to variable for drive number */
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The DSK_GETLOGICALMAP function retrieves the mapping of a logical drive.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbDrive Points to the variable that receives the logical-drive number.
+ This can be 1 for drive A, 2 for drive B, and so on. The function
+ sets the variable to zero if only one logical drive is mapped to
+ the physical drive.
+
+pbCommand Points to a variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the physical device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: DSK_LOCKDRIVE 0x0000 // Supported
+
+APIRET DosDevIOCtl( 0L, pbCommand, 0x0000, DSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The DSK_LOCKDRIVE function locks a disk drive, preventing file I/O by
+another process on the volume in the disk drive. This function succeeds if
+there is only one file handle open on the volume in the disk drive because
+the desired result is to exclude all other I/O to the volume.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCommand Points to the variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the disk drive that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: DSK_READTRACK 0x0064 // Supported
+
+APIRET DosDevIOCtl( pbBuffer, pbCommand, 0x0064, DSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbBuffer; /* pointer to buffer for data */
+PBYTE pbCommand; /* pointer to structure with command */
+HFILE hDevice; /* device handle */
+
+The DSK_READTRACK function reads from a track on a specified disk drive. The
+track table passed in the call determines the sector number, which is passed
+to the disk controller for the operation. When the sectors are odd-numbered
+or nonconsecutive, the request is broken into an appropriate number of
+single-sector operations, and one sector at a time is read.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbBuffer Points to the buffer that receives data read from the track.
+
+pbCommand Points to the TRACKLAYOUT structure that contains the information
+ about the read operation.
+
+hDevice Identifies the disk drive that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The device driver will not correctly read sectors of sizes other than 512
+bytes if reading would generate a direct-memory-access (DMA) violation
+error. Programs must ensure that this error does not occur.
+
+ o
+
+Topic: DSK_REDETERMINEMEDIA 0x0002 // Supported
+
+APIRET DosDevIOCtl( 0L, pbCommand, 0x0002, DSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The DSK_REDETERMINEMEDIA function redetermines the media on a block device
+and updates the volume in the drive. This function is normally issued after
+the volume identification information has been changed (for example, by
+formatting the disk). This function should be called only if the volume is
+locked.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCommand Points to the variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the disk drive that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: DSK_SETDEVICEPARAMS 0x0043 // Not Supported (?????)
+
+APIRET DosDevIOCtl( pbBPB, pbCommand, 0x0043, DSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbBPB; /* pointer to structure with BIOS parameter blocks */
+PBYTE pbCommand; /* pointer to buffer with command */
+HFILE hDevice; /* device handle */
+
+The DSK_SETDEVICEPARAMS function sets the device parameters for an MS OS/2
+block device. The device driver maintains two BIOS parameter blocks (BPB)
+for each disk drive. One block is the BPB that corresponds to the medium
+currently in the disk drive. The other block is a recommended BPB, based on
+the type of medium that corresponds to the physical device. For example, a
+high-density disk drive has a BPB for a 96 tracks per inch (tpi) floppy
+disk; a low-density disk drive has a BPB for a 48-tpi floppy disk.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbBPB Points to the BIOSPARAMETERBLOCK structure that contains the
+ device parameters to be set for the drive.
+
+pbCommand Point to the variable that contains the command description. This
+ variable can be one of the following values:
+
+ Value Meaning
+ -----------------------------------------------------------------
+ BUILD_BPB_FROM_MEDIUM Build the BIOS parameter block (BPB) from
+ the medium for all subsequent build BPB
+ requests.
+
+ REPLACE_BPB_FOR_DEVICE Change the default BPB for the physical
+ device.
+
+ REPLACE_BPB_FOR_MEDIUM Change the BPB for the medium to the
+ specified BPB. Return the new BPB as the
+ BPB for the medium for all subsequent
+ build BPB requests.
+
+hDevice Identifies the disk drive that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: DSK_SETLOGICALMAP 0x0003 // Supported (?????)
+
+APIRET DosDevIOCtl( pbDrive, pbCommand, 0x0003, DSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbDrive; /* pointer to variable with drive number */
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The DSK_SETLOGICALMAP function sets the logical-drive mapping for a block
+device.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbDrive Points to the variable that contains the logical-drive number.
+ This can be 1 for drive A, 2 for drive B, and so on. When the
+ function returns, it copies the specified drive's current
+ logical-drive number to the variable. If only one logical device
+ is mapped to the physical drive, the function sets the variable
+ to zero.
+
+pbCommand Points to the variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the disk drive that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: DSK_SYNC 0x005D // Not Supported (?????)
+
+APIRET DosDevIOCtl( pbBuffer, pbCommand, 0x005D, DSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbBuffer; /* pointer to buffer with data */
+PBYTE pbCommand; /* pointer to structure with command */
+HFILE hDevice; /* device handle */
+
+The DSK_SYNC function synchronizes disk I/O operations.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbBuffer Not used; must be zero.
+
+pbCommand Points to the synchronization operation.
+
+hDevice Identifies the disk drive that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+Some I/O operations cannot be overlapped with disk operations. This IOCtl
+function allows the disk device driver to be instructed to complete
+in-process operations, and then queue all further requests for disk I/O. A
+second call must be made, with pbCommand set to 0x0000, to instruct the disk
+device driver to release queued disk I/O and resume normal processing.
+
+ o
+
+Topic: DSK_UNLOCKDRIVE 0x0001 // Supported
+
+APIRET DosDevIOCtl( 0L, pbCommand, 0x0001, DSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The DSK_UNLOCKDRIVE function unlocks a drive. The drive requires the locked
+volume represented by the handle.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCommand Points to the variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the disk drive that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: DSK_VERIFYTRACK 0x0065 // Supported
+
+APIRET DosDevIOCtl( 0L, pbCommand, 0x0065, DSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbCommand; /* pointer to structure with command */
+HFILE hDevice; /* device handle */
+
+The DSK_VERIFYTRACK function verifies an operation on a specified disk
+drive.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCommand Points to the TRACKLAYOUT structure that contains information
+ about the verification operation.
+
+hDevice Identifies the disk drive that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The track-layout table passed in the function determines the sector number,
+which is passed to the disk controller. When the sectors are odd-numbered or
+nonconsecutive, the request is broken into an appropriate number of
+single-sector operations, and one sector at a time is verified.
+
+ o
+
+Topic: DSK_WRITETRACK 0x0044 // Supported
+
+APIRET DosDevIOCtl( pbBuffer, pbCommand, 0x0044, DSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbBuffer; /* pointer to buffer with data */
+PBYTE pbCommand; /* pointer to structure with command */
+HFILE hDevice; /* device handle */
+
+The DSK_WRITETRACK function writes to a track on a specified disk drive.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbBuffer Points to the buffer that contains the data to be written.
+
+pbCommand Points to the TRACKLAYOUT structure that contains information
+ about the write operation.
+
+hDevice Identifies the disk drive that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The track-layout table passed in the function determines the sector number,
+which is passed to the disk controller. When the sectors are odd-numbered or
+nonconsecutive, the request is broken into an appropriate number of
+single-sector operations, and one sector at a time is written.
+
+ o
+
+Topic: KBD_IOCTL_CATEGORY 0x0004 // Not Supported, mostly
+
+Topic: KBD_CREATE 0x005D // Not Supported
+
+APIRET DosDevIOCtl( 0L, pbCommand, 0x005D, KBD_IOCTL_CATEGORY, hDevice )
+PBYTE pbCommand; /* pointer to buffer with handle and pid */
+HFILE hDevice; /* device handle */
+
+The KBD_CREATE function allocates memory for a logical keyboard (KCB). This
+function obtains physical memory for a new logical keyboard. The process ID
+and a logical-keyboard handle passed by the caller stored in allocated
+memory for use later by the KBD_SETKCB function. A logical keyboard is not
+created if the handle is zero.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+
+pbCommand Points to the buffer that contains the value to use as the
+ logical-keyboard handle and the code-page identifier to use with
+ the logical keyboard.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+the logical keyboard cannot be created.
+
+ o
+
+Topic: KBD_DESTROY 0x005E // Not Supported
+
+APIRET DosDevIOCtl( 0L, pbCommand, 0x005E, KBD_IOCTL_CATEGORY, hDevice )
+PBYTE pbCommand; /* pointer to buffer with handle and pid */
+HFILE hDevice; /* device handle */
+
+The KBD_DESTROY function frees memory for a logical keyboard (KCB). This
+function searches for the existing logical keyboard that has the specified
+logical-keyboard handle and process ID combination and frees the physical
+memory associated with the logical keyboard. No action is taken if the
+specified handle is zero.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCommand Points to the buffer that contains the logical-keyboard handle.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+the logical keyboard identified by the given handle cannot be found.
+
+ o
+
+Topic: KBD_GETCODEPAGEID 0x0078 // Not Supported
+
+APIRET DosDevIOCtl( pbCPID, 0L, 0x0078, KBD_IOCTL_CATEGORY, hDevice )
+PBYTE pbCPID; /* pointer to buffer for code page id */
+HFILE hDevice; /* device handle */
+
+The KBD_GETCODEPAGEID function retrieves the identifier of the code page
+being used by the current logical keyboard.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCPID Points to the CPID structure that receives the code-page
+ identifier.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+This function sets the identifier to zero to indicate that PC US 437 is
+being used.
+
+ o
+
+Topic: KBD_GETINPUTMODE 0x0071 // Supported
+
+APIRET DosDevIOCtl( pbInputMode, 0L, 0x0071, KBD_IOCTL_CATEGORY, hDevice )
+PBYTE pbInputMode; /* pointer to variable for input mode */
+HFILE hDevice; /* device handle */
+
+The KBD_GETINPUTMODE function retrieves the input mode of the screen group
+of the active process. The input mode defines whether the following keys are
+processed as commands or as keystrokes: CTRL+C, CTRL+BREAK, CTRL+S, CTRL+P,
+SCROLL LOCK, PRTSC.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbInputMode Points to the variable that receives the input mode. If the
+ variable is ASCII_MODE, the keyboard has ASCII input mode. If
+ the variable is BINARY_MODE, the keyboard has binary input
+ mode.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: KBD_GETINTERIMFLAG 0x0072 // Not Supported
+
+APIRET DosDevIOCtl( pfFlags, 0L, 0x0072, KBD_IOCTL_CATEGORY, hDevice )
+PBYTE pfFlags; /* pointer to variable for flags */
+HFILE hDevice; /* device handle */
+
+The KBD_GETINTERIMFLAG function retrieves interim character flags.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfFlags Points to the variable that receives interim flags. If the
+ variable is CONVERSION_REQUEST, the program requested conversion.
+ If it is INTERIM_CHAR, the interim console flag is set.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: KBD_GETKEYBDTYPE 0x0077 // Supported
+
+APIRET DosDevIOCtl( pbType, 0L, 0x0077, KBD_IOCTL_CATEGORY, hDevice )
+PBYTE pbType; /* pointer to structure for keyboard type */
+HFILE hDevice; /* device handle */
+
+The KBD_GETKEYBDTYPE function retrieves information about the type of
+keyboard being used.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbType Points to the KBDTYPE structure that receives the keyboard type.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: KBD_GETSESMGRHOTKEY 0x0076 // Not Supported
+
+APIRET DosDevIOCtl( pbHotKeyBuf, pcHotKeys, 0x0076, KBD_IOCTL_CATEGORY, hDevice )
+PBYTE pbHotKeyBuf; /* pointer to structure for hot-key information */
+PUSHORT pcHotKeys; /* pointer to variable for hot-key count */
+HFILE hDevice; /* device handle */
+
+The KBD_GETSESMGRHOTKEY function retrieves the hot-key information
+structures for the currently defined hot keys.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbHotKeyBuf Points to the HOTKEY structure that receives hot-key
+ information structures. The buffer must be at least as large as
+ the number of structures requested.
+
+pcHotKeys Points to the variable that specifies the number of hot-key
+ information structures to retrieve. If this variable is
+ HOTKEY_MAX_COUNT, the function copies a value to the variable
+ that specifies the maximum number of hot keys the keyboard
+ device driver can support. If this variable is
+ HOTKEY_CURRENT_COUNT, the function copies a value to this
+ variable that specifies the actual number of hot keys currently
+ supported. The function also copies the hot-key information to
+ the buffer pointed to by the pbHotKeyBuf parameter.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+If the variable pointed to by pcHotKeys is HOTKEY_MAX_COUNT, the function
+returns the number of currently defined hot keys. The program uses this
+number to allocate sufficient space to retrieve the actual hot-key
+information (retrieved by setting the variable to HOTKEY_CURRENT_COUNT).
+
+Programs should retrieve the number of hot keys first, allocate sufficient
+space for the buffer pointed to by the pbHotKeyBuf parameter, then retrieve
+the hot keys.
+
+ o
+
+Topic: KBD_GETSHIFTSTATE 0x0073 // Supported
+
+APIRET DosDevIOCtl( pbShiftState, 0L, 0x0073, KBD_IOCTL_CATEGORY, hDevice )
+PBYTE pbShiftState; /* pointer to structure for shift state */
+HFILE hDevice; /* device handle */
+
+The KBD_GETSHIFTSTATE function retrieves the shift state of the default
+keyboard of the current screen group. The shift state identifies whether the
+SHIFT, CTRL, ALT, INS, and SYSREQ keys are up or down and whether the SCROLL
+LOCK, NUMLOCK, CAPSLOCK, and INSERT modes are on.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbShiftState Points to the SHIFTSTATE structure that receives the shift
+ state.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by
+ using the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The shift state is set by incoming keystrokes. It can also be set by using
+the KBD_SETSHIFTSTATE function (0x0004, 0x0053).
+
+ o
+
+Topic: KBD_PEEKCHAR 0x0075 // Not Supported
+
+APIRET DosDevIOCtl( pkkiBuffer, pusStatus, 0x0075, KBD_IOCTL_CATEGORY, hDevice )
+PKBDKEYINFO pkkiBuffer; /* pointer to structure for keystroke */
+PUSHORT pusStatus; /* pointer to variable for status */
+HFILE hDevice; /* device handle */
+
+The KBD_PEEKCHAR function retrieves one character data record from the head
+of the keyboard-input buffer of the screen group of the active process. The
+character data record is not removed from the keyboard-input buffer.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pkkiBuffer Points to the KBDKEYINFO structure that contains keyboard
+ input.
+
+pusStatus Points to the variable that receives the keyboard status. It can
+ be one or both of the following values:
+
+ Value Meaning
+ ----------------------------------------------------------------
+ KBD_DATA_RECEIVED Character data record is retrieved. If not
+ set, no character data was retrieved.
+
+ KBD_DATA_BINARY Input mode is binary. If not set, input mode
+ is ASCII.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+If the shift-reporting input mode is enabled, the keystroke information
+retrieved may specify only a shift-state change and no character input.
+
+ o
+
+Topic: KBD_READCHAR 0x0074 // Not Supported
+
+APIRET DosDevIOCtl( pkkiBuffer, pcRecords, 0x0074, KBD_IOCTL_CATEGORY, hDevice )
+PKBDKEYINFO pkkiBuffer; /* pointer to structure for keystrokes */
+PUSHORT pcRecords; /* pointer to variable for record count */
+HFILE hDevice; /* device handle */
+
+The KBD_READCHAR function retrieves one or more character data records from
+the keyboard-input buffer for the screen group of the active process.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pkkiBuffer Points to the structure that receives the character data
+ records. The structure must be at least as large as the size of
+ an individual record multiplied by the requested number of
+ records to be read.
+
+pcRecords Points to the variable that contains the number of records to be
+ read. When the function returns, it copies the actual number of
+ records retrieved to the variable.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+This function copies the records to the buffer pointed to by the pkkiBuffer
+parameter. The variable pointed to by the pcRecords parameter specifies the
+number of records to copy. The function can copy up to 16 characters.
+
+If the variable pointed to by pcRecords is KBD_READ_WAIT, the function waits
+for the requested number of keystrokes; it blocks the calling process until
+all records have been read. If the variable is KBD_READ_NOWAIT, the function
+retrieves any available records (up to the specified number) and returns
+immediately. When the function returns, it copies the actual number of
+records retrieved to the variable. It sets the sign bit to 0 if the input
+mode is ASCII; it sets the sign bit to 1 (0x8000) if the input mode is
+binary.
+
+ o
+
+Topic: KBD_SETFGNDSCREENGRP 0x0055 // Not Supported
+
+APIRET DosDevIOCtl( 0L, pusScreenGrp, 0x0055, KBD_IOCTL_CATEGORY, hDevice )
+PUSHORT pusScreenGrp; /* pointer to structure with screen group */
+HFILE hDevice; /* device handle */
+
+The KBD_SETFGNDSCREENGRP function sets the new foreground screen group. When
+the keyboard switches to the new screen group, it switches to the shift
+state, input buffer, and monitor chain defined for that screen group.
+
+This function is reserved for the session manager.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pusScreenGrp Points to the SCREENGROUP structure that contains the
+ screen-group identifier of the new foreground screen group.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by
+ using the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: KBD_SETFOCUS 0x0057 // Not Supported
+
+APIRET DosDevIOCtl( 0L, phkbd, 0x0057, KBD_IOCTL_CATEGORY, hDevice )
+PHKBD phkbd; /* pointer to logical keyboard handle */
+HFILE hDevice; /* device handle */
+
+The KBD_SETFOCUS function sets the keyboard focus to the specified logical
+keyboard.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+phkbd Points to the logical keyboard handle. The handle must have been
+ created previously by using the KbdOpen function.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: KBD_SETINPUTMODE 0x0051 // Supported, mostly
+
+APIRET DosDevIOCtl( 0L, pbInputMode, 0x0051, KBD_IOCTL_CATEGORY, hDevice )
+PBYTE pbInputMode; /* pointer to variable with input mode */
+HFILE hDevice; /* device handle */
+
+The KBD_SETINPUTMODE function sets the input and shift-report modes for the
+keyboard device driver. The input mode defines whether the following input
+keys are processed as keystrokes or as commands: CTRL+C, CTRL+BREAK, CTRL+S,
+CTRL+P, SCROLL LOCK, PRTSC.
+
+The shift-report mode defines whether the shift keys are processed as shift
+keys or as keystrokes.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbInputMode Points to the variable that contains the input mode for the
+ keyboard. If the variable is ASCII_MODE, the input mode is
+ ASCII. If the variable is BINARY_MODE, the input mode is
+ binary. If these values are combined with SHIFT_REPORT_MODE,
+ the function enables the shift-report mode; otherwise, the
+ shift-report mode is disabled.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The default input mode is ASCII. The keyboard device driver maintains an
+input mode for each screen group.
+
+ o
+
+Topic: KBD_SETINTERIMFLAG 0x0052 // Not Supported
+
+APIRET DosDevIOCtl( 0L, pfFlags, 0x0052, KBD_IOCTL_CATEGORY, hDevice )
+PBYTE pfFlags; /* pointer to variable with flags */
+HFILE hDevice; /* device handle */
+
+The KBD_SETINTERIMFLAG function sets the interim character flags.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfFlags Points to the variable that contains the interim flags. If the
+ variable is 0x0020, the program requested conversion. If the
+ variable is 0x0080, the interim character flag is set.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The keyboard device driver maintains the interim character flags for each
+screen group and passes the interim character flags (with each character
+data record) to the keyboard monitors. The interim character flags set by
+this function are not the same as the interim character flags in a character
+data record.
+
+ o
+
+Topic: KBD_SETKCB 0x0058 // Not Supported
+
+APIRET DosDevIOCtl( 0L, phKbd, 0x0058, KBD_IOCTL_CATEGORY, hDevice )
+PHKBD phKbd; /* logical-keyboard handle */
+HFILE hDevice; /* device handle */
+
+The KBD_SETKCB function binds the specified logical keyboard (KCB) to the
+physical keyboard for this session.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+phKbd Points to the handle that identifies the logical keyboard.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: KBD_SETNLS 0x005C // Not Supported
+
+APIRET DosDevIOCtl( 0L, pbCodePage, 0x005C, KBD_IOCTL_CATEGORY, hDevice )
+PBYTE pbCodePage; /* pointer to structure with code-page info */
+HFILE hDevice; /* device handle */
+
+The KBD_SETNLS function installs one of two possible code pages into the
+device driver and updates entry number one or number two of the code-page
+control block. Entry zero is the device-driver resident code page.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCodePage Points to the CODEPAGEINFO structure that specifies the
+ translation table and code page to be set.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+This function is similar to KBD_SETTRANSTABLE (0x0004,0x0050) except it
+updates different entries in the code-page control block.
+
+ o
+
+Topic: KBD_SETSESMGRHOTKEY 0x0056 // Not Supported
+
+APIRET DosDevIOCtl( 0L, pbHotKey, 0x0056, KBD_IOCTL_CATEGORY, hDevice )
+PBYTE pbHotKey; /* pointer to structure with hot key */
+HFILE hDevice; /* device handle */
+
+The KBD_SETSESMGRHOTKEY function sets the session-manager hot keys. A new
+hot key applies to all screen groups. The session manager can define up to
+16 hot keys.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbHotKey Points to the HOTKEY structure that contains the hot-key
+ information.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The KBD_SETSESMGRHOTKEY function is successful only if it is performed by
+the process that initially called the KBD_SETFGNDSCREENGRP function (0x0004,
+0x0055).
+
+A hot key can be specified as a combination of shift flags and scan codes,
+including key combinations such as ALT+ESC. The system detects the hot key
+when the specified scan code is received. If a hot key has already been
+defined for a given hot-key identifier, specifying the identifier again
+replaces the previous definition.
+
+ o
+
+Topic: KBD_SETSHIFTSTATE 0x0053 // Supported
+
+APIRET DosDevIOCtl( 0L, pbShiftState, 0x0053, KBD_IOCTL_CATEGORY, hDevice )
+PBYTE pbShiftState; /* pointer to structure with shift state */
+HFILE hDevice; /* device handle */
+
+The KBD_SETSHIFTSTATE function sets the shift state for the default keyboard
+in the current screen group. The shift state identifies whether the SHIFT,
+CONTROL, ALT, INSERT, and SYSREQ keys are up or down and whether the SCROLL
+LOCK, NUMLOCK, CAPSLOCK, and INSERT modes are on.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbShiftState Points to the SHIFTSTATE structure that contains the shift
+ state.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by
+ using the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The system puts the shift state into the character data record built for
+each incoming keystroke; the shift state then can be used to interpret the
+meaning of keystrokes. The function sets the shift state to the specified
+state regardless of the state of the actual keys. The shift remains as set
+until the user presses or releases the corresponding key.
+
+The keyboard device driver maintains a shift state for each screen group.
+
+ o
+
+Topic: KBD_SETTRANSTABLE 0x0050 // Not Supported
+
+APIRET DosDevIOCtl( 0L, pbTransTable, 0x0050, KBD_IOCTL_CATEGORY, hDevice )
+PBYTE pbTransTable; /* pointer to translation table */
+HFILE hDevice; /* device handle */
+
+The KBD_SETTRANSTABLE function passes a new translation table to the
+keyboard translation function. The new table, which overlays the current
+table, translates subsequent keystrokes.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbTransTable Points to the translation table.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by
+ using the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The default translation table is United States English.
+
+ o
+
+Topic: KBD_SETTYPAMATICRATE 0x0054 // Supported
+
+APIRET DosDevIOCtl( 0L, pusRateDelay, 0x0054, KBD_IOCTL_CATEGORY, hDevice )
+PUSHORT pusRateDelay; /* structure with typamatic rate and delay */
+HFILE hDevice; /* device handle */
+
+The KBD_SETTYPAMATICRATE function sets the keyboard typamatic rate and
+delay.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pusRateDelay Points to the RATEDELAY structure that contains the typamatic
+ rate and delay.
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by
+ using the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: KBD_XLATESCAN 0x0079 // Not Supported
+
+APIRET DosDevIOCtl( pkbxl, pidCodePage, 0x0079, KBD_IOCTL_CATEGORY, hDevice )
+PKBDXLATE pkbxl; /* pointer to structure for scan code */
+PBYTE pidCodePage; /* pointer to code page for translation */
+HFILE hDevice; /* device handle */
+
+The KBD_XLATESCAN function translates a scan code in a character data record
+to an ASCII character.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pkbxl Points to the KBDTRANS structure that contains the scan code to
+ translate. It also receives the character value when the
+ function returns.
+pidCodePage Points to a code-page identifier that specifies which code page
+ to use for the translation. The code-page identifier can be one
+ of the following values:
+
+ Number Code page
+ ---------------------------------------------------------------
+ 437 United States
+
+ 850 Multilingual
+
+ 860 Portuguese
+
+ 863 French-Canadian
+
+ 865 Nordic
+
+hDevice Identifies the keyboard that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+You may specify a code page to use for translation. Otherwise, the code page
+of the active keyboard is used. On entry, the KBDTRANS structure specifies
+the code page to use for translation.
+
+ o
+
+Topic: MON_IOCTL_CATEGORY 0x000A // Not Supported
+
+Topic: MON_REGISTERMONITOR 0x0040 // Not Supported
+
+APIRET DosDevIOCtl( pusInfo, pbCommand, 0x0040, MON_IOCTL_CATEGORY, hDevice )
+PUSHORT pusInfo; /* pointer to structure with monitor-register info */
+PBYTE pbCommand; /* pointer to command */
+HFILE hDevice; /* device handle */
+
+The MON_REGISTERMONITOR function registers a monitor.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pusInfo Points to the MONITORPOSITION structure that contains the
+ monitor-registration information.
+
+pbCommand Points to the variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the device that receives the device-control function.
+ The handle must have been created previously by using the
+ DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_IOCTL_CATEGORY 0x0007 // Not Supported
+
+Topic: MOU_ALLOWPTRDRAW 0x0050 // Not Supported
+
+APIRET DosDevIOCtl( 0L, 0L, 0x0050, MOU_IOCTL_CATEGORY, hDevice )
+HFILE hDevice; /* device handle */
+
+The MOU_ALLOWPTRDRAW function notifies the mouse device driver that the
+screen group has been switched and that the pointer can now be drawn.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_DRAWPTR 0x0057 // Not Supported
+
+APIRET DosDevIOCtl( 0L, 0L, 0x0057, MOU_IOCTL_CATEGORY, hDevice )
+HFILE hDevice; /* device handle */
+
+The MOU_DRAWPTR function removes the current exclusion rectangle, allowing
+the pointer to be drawn anywhere on the screen. If an exclusion rectangle
+has been declared for the screen group, that rectangle is released and the
+pointer position is checked. If the pointer was in the released rectangle,
+it is drawn. If the pointer was not in the released rectangle, the
+pointer-draw operation occurs.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_DISPLAYMODECHANGE 0x005D // Not Supported
+
+APIRET DosDevIOCtl( 0L, 0L, 0x005D, MOU_IOCTL_CATEGORY, hDevice )
+HFILE hDevice; /* device handle */
+
+The MOU_DISPLAYMODECHANGE function notifies the mouse device driver that a
+display-mode change is complete.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+hDevice Identifies the pointing device that receives the device-control
+ function. This handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful. Otherwise, it is an
+error value.
+
+Comments
+
+The MOU_DISPLAYMODECHANGE function notifies the mouse that a mode switch is
+complete and that drawing is allowed. The pointer is redrawn if it was
+hidden when the mode switch began.
+
+ o
+
+Topic: MOU_GETBUTTONCOUNT 0x0060 // Not Supported
+
+APIRET DosDevIOCtl( pusCount, 0L, 0x0060, MOU_IOCTL_CATEGORY, hDevice )
+PUSHORT pusCount; /* pointer to variable for button count */
+HFILE hDevice; /* device handle */
+
+The MOU_GETBUTTONCOUNT function retrieves a count of the number of mouse
+buttons.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pusCount Points to the variable that receives the count mouse buttons.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_GETEVENTMASK 0x0065 // Not Supported
+
+APIRET DosDevIOCtl( pfEvents, 0L, 0x0065, MOU_IOCTL_CATEGORY, hDevice )
+PUSHORT pfEvents; /* pointer to variable for event mask */
+HFILE hDevice; /* device handle */
+
+The MOU_GETEVENTMASK function retrieves the event mask of the current
+pointing device.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfEvents Points to the variable that receives the event mask. This
+ variable can be a combination of the following values:
+
+ Value Meaning
+ -----------------------------------------------------------------
+ MOUSE_MOTION Motion; no buttons pressed.
+
+ MOUSE_MOTION_WITH_BN1_DOWN Motion with button 1 pressed.
+
+ MOUSE_BN1_DOWN Button 1 pressed.
+
+ MOUSE_MOTION_WITH_BN2_DOWN Motion with button 2 pressed.
+
+ MOUSE_BN2_DOWN Button 2 pressed.
+
+ MOUSE_MOTION_WITH_BN3_DOWN Motion with button 3 pressed.
+
+ MOUSE_BN3_DOWN Button 3 pressed.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_GETHOTKEYBUTTON 0x0069 // Not Supported
+
+APIRET DosDevIOCtl( pfHotKey, 0L, 0x0069, MOU_IOCTL_CATEGORY, hDevice )
+PUSHORT pfHotKey; /* pointer to variable for hot key */
+HFILE hDevice; /* device handle */
+
+The MOU_GETHOTKEYBUTTON function retrieves the mouse-button equivalent for
+the system hot key.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfHotKey Points to the variable that receives the hot key. This variable
+ can be one or more of the following values:
+
+ Value Meaning
+ -----------------------------------------------------------------
+ MHK_NO_HOTKEY No system hot key used.
+
+ MHK_BUTTON1 Button 1 is system hot key.
+
+ MHK_BUTTON2 Button 2 is system hot key.
+
+ MHK_BUTTON3 Button 3 is system hot key.
+
+ If 0x0001 is specified, no system hot-key support is provided. If
+ multiple values are given (excluding 0x0001) the system hot key
+ requires that the indicated buttons be pressed simultaneously.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_GETMICKEYCOUNT 0x0061 // Not Supported
+
+APIRET DosDevIOCtl( pcMickeys, 0L, 0x0061, MOU_IOCTL_CATEGORY, hDevice )
+PUSHORT pcMickeys; /* pointer to variable for mickeys */
+HFILE hDevice; /* device handle */
+
+The MOU_GETMICKEYCOUNT function retrieves the count of mickeys per
+centimeter for a given pointing device.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pcMickeys Points to the variable that receives the number of mickeys per
+ centimeter. The number can be any value from 0 through 32,767.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_GETMOUSTATUS 0x0062 // Not Supported
+
+APIRET DosDevIOCtl( pfStatus, 0L, 0x0062, MOU_IOCTL_CATEGORY, hDevice )
+PUSHORT pfStatus; /* pointer to variable for status flags */
+HFILE hDevice; /* device handle */
+
+The MOU_GETMOUSTATUS function retrieves the current status flags of the
+mouse device driver.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfStatus Points to the variable that receives the status flags. This
+ variable can be a combination of the following values:
+
+ Value Meaning
+ -----------------------------------------------------------------
+ MOUSE_QUEUEBUSY Event queue is busy with I/O.
+
+ MOUSE_BLOCKREAD Block read is in progress.
+
+ MOUSE_FLUSH Flush is in progress.
+
+ MOUSE_UNSUPPORTED_MODE Pointer-draw routine is disabled (device
+ in unsupported mode).
+
+ MOUSE_DISABLED Interrupt-level pointer-draw routine is
+ not called.
+
+ MOUSE_MICKEYS Mouse data is returned in mickeys (not
+ pels).
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_GETPTRPOS 0x0067 // Not Supported
+
+APIRET DosDevIOCtl( pplPosition, 0L, 0x0067, MOU_IOCTL_CATEGORY, hDevice )
+PPTRLOC pplPosition; /* pointer to structure for position */
+HFILE hDevice; /* device handle */
+
+The MOU_GETPTRPOS function retrieves the position of the current screen's
+pointer.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pplPosition Points to the PTRLOC structure that receives the new pointer
+ position.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The coordinate values depend on the display mode. If the display is in text
+mode, character-position values are used. If the display is in graphics
+mode, pel values are used.
+
+ o
+
+Topic: MOU_GETPTRSHAPE 0x0068 // Not Supported
+
+APIRET DosDevIOCtl( pbBuffer, ppsShape, 0x0068, MOU_IOCTL_CATEGORY, hDevice )
+PBYTE pbBuffer; /* pointer to buffer for pointer masks */
+PPTRSHAPE ppsShape; /* pointer to structure for shape information */
+HFILE hDevice; /* device handle */
+
+The MOU_GETPTRSHAPE function retrieves the current pointer shape.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbBuffer Points to the buffer that receives the pointer shape. The image
+ format depends on the mode of the display. For currently
+ supported modes, the buffer always consists of the AND image data
+ followed by the XOR image data. The buffer always describes one
+ display plane.
+
+ppsShape Points to the PTRSHAPE structure that receives the pointer
+ information and shape.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The function exits in a normal state if the input pointer-image buffer is
+large enough to store the pointer image. The current pointer information is
+returned in the pointer-data record, and the pointer-image data is copied
+into the data-packet buffer.
+
+An "invalid buffer size" error occurs if the input pointer-image buffer is
+smaller than the amount of storage necessary for copying the data. The
+buffer length returned will be minimum value.
+
+Comments
+
+The parameter values are in the same mode as the current screen-group
+display mode. For text mode, these are character values; for graphics mode,
+these are pel values.
+
+On input, the only field in the pointer-definition record used by the mouse
+device driver is the length of the pointer-image buffer.
+
+ o
+
+Topic: MOU_GETQUESTATUS 0x0064 // Not Supported
+
+APIRET DosDevIOCtl( pmqiStatus, 0L, 0x0064, MOU_IOCTL_CATEGORY, hDevice )
+PMOUQUEINFO pmqiStatus; /* pointer to structure for queue status */
+HFILE hDevice; /* device handle */
+
+The MOU_GETQUESTATUS function retrieves the number of elements in the event
+queue and the maximum number of elements allowed in an event queue.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pmqiStatus Points to the MOUQUEINFO structure that receives the queue
+ status.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_GETSCALEFACTORS 0x0066 // Not Supported
+
+APIRET DosDevIOCtl( psfFactors, 0L, 0x0066, MOU_IOCTL_CATEGORY, hDevice )
+PSCALEFACT psfFactors; /* pointer to structure for scaling factors */
+HFILE hDevice; /* device handle */
+
+The MOU_GETSCALEFACTORS function retrieves the scaling factors of the
+current pointing device. Scaling factors are the ratio values that determine
+how much relative movement is necessary before the mouse device driver
+reports a pointing-device event. In graphics mode, this ratio is given in
+mickeys-per-pel. In text mode, this ratio is given in mickeys-per-character.
+The default values are one mickey-per-row and one mickey-per-column.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+psfFactors Points to the SCALEFACT structure that receives the scaling
+ factors.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_READEVENTQUE 0x0063 // Not Supported
+
+APIRET DosDevIOCtl( pmeiEvent, pfWait, 0x0063, MOU_IOCTL_CATEGORY, hDevice )
+PMOUEVENTINFO pmeiEvent; /* pointer to structure for event information */
+PUSHORT pfWait; /* pointer to wait/no-wait flag */
+HFILE hDevice; /* device handle */
+
+The MOU_READEVENTQUE function reads the event queue for the pointing
+device.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pmeiEvent Points to the MOUEVENTINFO structure that receives event-queue
+ information.
+
+pfWait Points to the variable that specifies how to read from the queue
+ if no event is available. If the variable is WAIT, the function
+ returns immediately without an event. If the variable is NOWAIT,
+ the function waits until an event is available.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_REMOVEPTR 0x0058 // Not Supported
+
+APIRET DosDevIOCtl( 0L, pnprBuffer, 0x0058, MOU_IOCTL_CATEGORY, hDevice )
+PNOPTRRECT pnprBuffer; /* points to structure with exclusion rectangle */
+HFILE hDevice; /* device handle */
+
+The MOU_REMOVEPTR function specifies the exclusion rectangle to be used by
+the device driver. The exclusion rectangle specifies an area on the screen
+where the pointer-draw routine cannot draw the pointer.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pnprBuffer Points to the NOPTRRECT structure that contains the dimensions
+ of the exclusion rectangle.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The pointer is not drawn in the exclusion rectangle until a different area
+is specified by another call of this function.
+
+If the exclusion rectangle is defined as the entire screen, pointer-draw
+operations are disabled for the entire screen group.
+
+ o
+
+Topic: MOU_SCREENSWITCH 0x0052 // Not Supported
+
+APIRET DosDevIOCtl( 0L, pbNotify, 0x0052, MOU_IOCTL_CATEGORY, hDevice )
+PBYTE pbNotify; /* pointer to structure with screen group */
+HFILE hDevice; /* device handle */
+
+The MOU_SCREENSWITCH function notifies the mouse device driver that the
+screen group is about to be switched, and then sets a system pointer-draw
+enable/disable flag. Any pointer drawing is locked until the flag is cleared
+by using the MOU_ALLOWPTRDRAW function (0x0007, 0x0050).
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbNotify Points to the SCREENGROUP structure that contains the
+ notification type and screen-group identifier.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_SETEVENTMASK 0x0054 // Not Supported
+
+APIRET DosDevIOCtl( 0L, pfEvent, 0x0054, MOU_IOCTL_CATEGORY, hDevice )
+PUSHORT pfEvent; /* pointer to variable for event mask */
+HFILE hDevice; /* device handle */
+
+The MOU_SETEVENTMASK function sets the event mask of the pointing device.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfEvent Points to the variable that contains the event mask. This
+ variable can be a combination of the following values:
+
+ Value Meaning
+ -----------------------------------------------------------------
+ MOUSE_MOTION Motion; no buttons pressed.
+
+ MOUSE_MOTION_WITH_BN1_DOWN Motion with button 1 pressed.
+
+ MOUSE_BN1_DOWN Button 1 pressed.
+
+ MOUSE_MOTION_WITH_BN2_DOWN Motion with button 2 pressed.
+
+ MOUSE_BN2_DOWN Button 2 pressed.
+
+ MOUSE_MOTION_WITH_BN3_DOWN Motion with button 3 pressed.
+
+ MOUSE_BN3_DOWN Button 3 pressed.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_SETHOTKEYBUTTON 0x0055 // Not Supported
+
+APIRET DosDevIOCtl( 0L, pfHotKey, 0x0055, MOU_IOCTL_CATEGORY, hDevice )
+PUSHORT pfHotKey; /* pointer to variable with hot key */
+HFILE hDevice; /* device handle */
+
+The MOU_SETHOTKEYBUTTON function sets the mouse-button equivalent for the
+system hot key.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfHotKey Points to the variable that specifies the hot key. This variable
+ can be a combination of the following values:
+
+ Value Meaning
+ -----------------------------------------------------------------
+ MHK_NO_HOTKEY No system hot key used.
+
+ MHK_BUTTON1 Button 1 is system hot key.
+
+ MHK_BUTTON2 Button 2 is system hot key.
+
+ MHK_BUTTON3 Button 3 is system hot key.
+
+ If 0x0001 is specified, no system hot-key support is provided. If
+ multiple values are given (excluding 0x0001), the system hot key
+ requires that the indicated buttons be pressed simultaneously.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+This function can be called only by the process that initially issues it and
+should be used only by the command shell.
+
+ o
+
+Topic: MOU_SETMOUSTATUS 0x005C // Not Supported
+
+APIRET DosDevIOCtl( 0L, pfStatus, 0x005C, MOU_IOCTL_CATEGORY, hDevice )
+PUSHORT pfStatus; /* pointer to variable with status */
+HFILE hDevice; /* device handle */
+
+The MOU_SETMOUSTATUS function sets a subset of the current mouse
+device-driver status flags.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfStatus Points to the variable that contains the status flags for the
+ pointing device. If the variable contains MOUSE_DISABLED, the
+ interrupt-level pointer-draw routine is not called. If the
+ variable contains MOUSE_MICKEYS, mouse data is returned in
+ mickeys (not pels).
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_SETPROTDRAWADDRESS 0x005A // Not Supported
+
+APIRET DosDevIOCtl( pbDrawData, pbFunction, 0x005A, MOU_IOCTL_CATEGORY, hDevice )
+PBYTE pbDrawData; /* pointer to drawing data */
+PBYTE pbFunction; /* pointer to structure with drawing function */
+HFILE hDevice; /* device handle */
+
+The MOU_SETPROTDRAWADDRESS function notifies the mouse device driver of the
+address of a protected-mode pointer-draw function. This function is valid
+for protected mode only.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbDrawData Points to the PTRDRAWDATA structure.
+
+pbFunction Points to the PTRDRAWFUNCTION structure that contains the
+ address of the pointer-draw function.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The pointer-draw routine is an installed, pseudo-character device driver.
+The mouse handler must do the following:
+
+o Open the pointer-draw device driver.
+
+o Query the pointer-draw device driver for the address of its entry point.
+
+o Pass the resulting address of the pointer-draw entry point to the mouse
+ device driver that uses this function.
+
+ o
+
+Topic: MOU_SETPTRPOS 0x0059 // Not Supported
+
+APIRET DosDevIOCtl( 0L, pplPosition, 0x0059, MOU_IOCTL_CATEGORY, hDevice )
+PPTRLOC pplPosition; /* pointer to structure with pointer position */
+HFILE hDevice; /* device handle */
+
+The MOU_SETPTRPOS function sets a new screen position for the pointer
+image.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pplPosition Points to the PTRLOC structure that contains the new position
+ for the pointer.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The coordinate values depend on the display mode. If the display is in text
+mode, character-position values are used. If the display is in graphics
+mode, pel values are used.
+
+This function has no effect on the current exclusion-rectangle definitions.
+If a pointer image is already defined for the screen group, it is replaced
+by the new pointer image.
+
+If the pointer image is directed into an existing exclusion rectangle, it
+remains hidden (invisible) until sufficient movement places the pointer
+outside the exclusion rectangle or until the exclusion rectangle is
+released.
+
+ o
+
+Topic: MOU_SETPTRSHAPE 0x0056 // Not Supported
+
+APIRET DosDevIOCtl( pbBuffer, ppsShape, 0x0056, MOU_IOCTL_CATEGORY, hDevice )
+PBYTE pbBuffer; /* pointer to structure with shape masks */
+PPTRSHAPE ppsShape; /* pointer to structure with shape information */
+HFILE hDevice; /* device handle */
+
+The MOU_SETPTRSHAPE function sets the pointer shape.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbBuffer Points to the buffer that contains the pointer image. The image
+ format depends on the mode of the display. For currently
+ supported modes, the buffer always consists of the AND image
+ data, followed by the XOR image data. The buffer always describes
+ one display plane.
+
+ppsShape Points to the PTRSHAPE structure that receives the pointer
+ information and shape.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The parameter values must be in the same mode as the current screen-group
+display mode. For text mode, these must be character values; for graphics
+mode, these must be pel values.
+
+ o
+
+Topic: MOU_SETREALDRAWADDRESS 0x005B // Not Supported
+
+APIRET DosDevIOCtl( pvConfig, pbFunction, 0x005B, MOU_IOCTL_CATEGORY, hDevice )
+PVOID pvConfig; /* pointer to configuration structure */
+PBYTE pbFunction; /* pointer to structure with function */
+HFILE hDevice; /* device handle */
+
+The MOU_SETREALDRAWADDRESS function notifies the real-mode mouse device
+driver of the entry point of a real-mode pointer-draw routine. This function
+is intended for use by Session Manager at the end of system initialization
+and is valid for real mode only.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pvConfig Points to the VIOCONFIGINFO structure that contains information
+ about configuration of the default display.
+
+pbFunction Points to the PTRDRAWFUNCTION structure that contains the
+ address of the pointer-draw function.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_SETSCALEFACTORS 0x0053 // Not Supported
+
+APIRET DosDevIOCtl( 0L, psfFactors, 0x0053, MOU_IOCTL_CATEGORY, hDevice )
+PSCALEFACT psfFactors; /* pointer to structure with factors */
+HFILE hDevice; /* device handle */
+
+The MOU_SETSCALEFACTORS function reassigns the scaling factors of the
+current pointing device. Scaling factors are ratio values that determine how
+much relative movement is necessary before the mouse device driver reports a
+pointing-device event. In graphics mode, the ratio is given in
+mickeys-per-pel. In text mode, the ratio is given in mickeys-per-character.
+The default ratio values are one mickey-per-row and one mickey-per-column.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+psfFactors Points to the SCALEFACT structure that contains the scale
+ factors.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: MOU_UPDATEDISPLAYMODE 0x0051 // Not Supported
+
+APIRET DosDevIOCtl( pvConfigInfo, pviomi, 0x0051, MOU_IOCTL_CATEGORY, hDevice )
+PVOID pvConfigInfo; /* pointer to structure with configuration info */
+PVIOMODEINFO pviomi; /* pointer to structure with screen mode */
+HFILE hDevice; /* device handle */
+
+The MOU_UPDATEDISPLAYMODE function notifies the mouse device driver that the
+display mode has been modified.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pvConfigInfo Points to the VIOCONFIGINFO structure that contains the
+ current display-configuration information.
+
+pviomi Points to the VIOMODEINFO structure that contains the
+ display-mode information.
+
+hDevice Identifies the pointing device that receives the
+ device-control function. This handle must have been created
+ previously by using the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+When the video I/O subsystem or registered video I/O subsystem sets the
+display mode, it must notify the mouse device driver prior to switching
+display modes, in order to synchronize the mouse device driver's functions
+that update the pointer.
+
+ o
+
+Topic: MOU_VER 0x006A // Supported (?????)
+
+APIRET DosDevIOCtl( pusVersion, 0L, 0x006A, MOU_IOCTL_CATEGORY, hDevice )
+PUSHORT pusVersion; /* pointer to version number */
+HFILE hDevice; /* device handle */
+
+The MOU_VER function returns the version number of the mouse driver.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pusVersion Points to a data area in which the version number of the mouse
+ driver is returned.
+
+hDevice Identifies the pointing device that receives the device-control
+ function. This handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful. Otherwise, it is an
+error value.
+
+Comments
+
+The MOU_VER function returns 0x0001 as the version number of the mouse
+driver to indicate that the following features are supported. These features
+are new for MS OS/2, version 1.2.
+
+Function Change
+----------------------------------------------------------------------------
+MOU_DISPLAYMODECHANGE New IOCtl function.
+
+MOU_SETPROTDRAWADDRESS New pbDrawData parameter.
+
+MOU_SETREALDRAWADDRESS New pvConfig parameter.
+
+MOU_UPDATEDISPLAYMODE New pvConfigInfo parameter.
+
+MOU_UPDATEDISPLAYMODE Size of VIOMODEINFO structure increased from 12 to
+ 34 bytes.
+
+MOU_VER New IOCtl function.
+
+The MOU_VER function should be used to determine the version number of the
+mouse device driver before any of these features are used, in order to
+maintain compatibility with earlier versions of MS OS/2.
+
+ o
+
+Topic: PDSK_IOCTL_CATEGORY 0x0009 // Supported
+
+Topic: PDSK_GETPHYSDEVICEPARAMS 0x0063 // Supported (?????)
+
+APIRET DosDevIOCtl( pbBlock, pbCommand, 0x0063, PDSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbBlock; /* pointer to structure for device parameters */
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The PDSK_GETPHYSDEVICEPARAMS function retrieves the device parameters for a
+physical device. The retrieved parameters apply to the entire physical
+disk.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbBlock Points to the DEVICEPARAMETERBLOCK structure that receives the
+ device parameters.
+
+pbCommand Points to the variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the physical device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosPhysicalDisk function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: PDSK_LOCKPHYSDRIVE 0x0000 // Supported (?????)
+
+APIRET DosDevIOCtl( 0L, pbCommand, 0x0000, PDSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The PDSK_LOCKPHYSDRIVE function locks the physical drive and any of its
+associated logical units.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCommand Points to the variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the disk-drive device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosPhysicalDisk function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: PDSK_READPHYSTRACK 0x0064 // Supported
+
+APIRET DosDevIOCtl( pbBuffer, pbCommand, 0x0064, PDSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbBuffer; /* pointer to structure for data */
+PBYTE pbCommand; /* pointer to structure with command */
+HFILE hDevice; /* device handle */
+
+The PDSK_READPHYSTRACK function reads from a physical track on the device
+specified in the request.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbBuffer Points to the buffer that receives the data to be read.
+
+pbCommand Points to the TRACKLAYOUT structure that contains information
+ about the read operation.
+
+hDevice Identifies the disk drive that receives the device-control
+ function. The handle must have been created previously by using
+ the DosPhysicalDisk function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+This function is similar to the DSK_READTRACK function (0x0008, 0x0064)
+except that I/O is offset from the beginning of the physical drive instead
+of from the unit number.
+
+The track table passed in the function determines the sector number, which
+is passed to the disk controller. When the sectors are odd-numbered or
+nonconsecutive, the request is broken into an appropriate number of
+single-sector operations, and one sector at a time is read.
+
+The device driver will not correctly read sectors of sizes other than 512
+bytes if doing so would generate a direct-memory-access (DMA) violation
+error.
+
+ o
+
+Topic: PDSK_UNLOCKPHYSDRIVE 0x0001 // Supported (?????)
+
+APIRET DosDevIOCtl( 0L, pbCommand, 0x0001, PDSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The PDSK_UNLOCKPHYSDRIVE function unlocks the physical disk drive and any of
+its associated logical units and also affects the logical units on the
+physical disk drive.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCommand Points to the variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the disk drive that receives the device-control
+ function. The handle must have been created previously by using
+ the DosPhysicalDisk function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: PDSK_VERIFYPHYSTRACK 0x0065 // Supported
+
+APIRET DosDevIOCtl( 0L, pbCommand, 0x0065, PDSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbCommand; /* pointer to structure with verification data */
+HFILE hDevice; /* device handle */
+
+The PDSK_VERIFYPHYSTRACK function verifies I/O on a physical track on the
+device specified in the request.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCommand Points to the TRACKLAYOUT structure that contains information
+ about the verify operation.
+
+hDevice Identifies the physical device that receives the device-control
+ function. The handle must have been created previously by using
+ the DosPhysicalDisk function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+This function is similar to the DSK_VERIFYTRACK function (0x0008, 0x0065)
+except that I/O is offset from the beginning of the physical drive instead
+of from the unit number.
+
+The track-layout table passed in the function determines the sector number,
+which is passed to the disk controller. When the sectors are odd-numbered or
+nonconsecutive, the request is broken into an appropriate number of
+single-sector operations, and one sector at a time is verified.
+
+ o
+
+Topic: PDSK_WRITEPHYSTRACK 0x0044 // Supported
+
+APIRET DosDevIOCtl( pbBuffer, pbCommand, 0x0044, PDSK_IOCTL_CATEGORY, hDevice )
+PBYTE pbBuffer; /* pointer to buffer with data */
+PBYTE pbCommand; /* pointer to structure with command */
+HFILE hDevice; /* device handle */
+
+The PDSK_WRITEPHYSTRACK function writes to a physical track on the device
+specified in the request.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbBuffer Points to the buffer that contains the data to be written.
+
+pbCommand Points to the TRACKLAYOUT structure that contains information
+ about the write operation.
+
+hDevice Identifies the disk drive that receives the device-control
+ function. The handle must have been created previously by using
+ the DosPhysicalDisk function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+This function is similar to the DSK_WRITETRACK function (0x0008, 0x0044)
+except that I/O is offset from the beginning of the physical drive instead
+of from the unit number.
+
+The track-layout table passed in this function determines the sector number,
+which is passed to the disk controller. When the sectors are odd-numbered or
+nonconsecutive, the request is broken into an appropriate number of
+single-sector operations, and one sector at a time is written.
+
+ o
+
+Topic: PRT_IOCTL_CATEGORY 0x0005 // Not Supported
+
+Topic: PRT_ACTIVATEFONT 0x0048 // Not Supported
+
+APIRET DosDevIOCtl( pbFontInfo, pbCommand, 0x0048, PRT_IOCTL_CATEGORY, hDevice )
+PBYTE pbFontInfo; /* pointer to structure for font info */
+PBYTE pbCommand; /* pointer to byte with command info */
+HFILE hDevice; /* device handle */
+
+The PRT_ACTIVATEFONT function activates a font for printing.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbFontInfo Points to a FONTINFO structure that specifies the font to
+ activate.
+
+pbCommand Points to a reserved 8-bit value. The value must be zero.
+
+hDevice Identifies the printer that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: PRT_GETFRAMECTL 0x0062 // Not Supported
+
+APIRET DosDevIOCtl( pbFrameCtl, pbCommand, 0x0062, PRT_IOCTL_CATEGORY, hDevice )
+PBYTE pbFrameCtl; /* pointer to structure for frame settings */
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The PRT_GETFRAMECTL function retrieves frame-control information for a
+printer.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbFrameCtl Points to the FRAME structure that receives the frame-control
+ information.
+
+pbCommand Points to the variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the printer that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: PRT_GETINFINITERETRY 0x0064 // Not Supported
+
+APIRET DosDevIOCtl( pfRetry, pbCommand, 0x0064, PRT_IOCTL_CATEGORY, hDevice )
+PBYTE pfRetry; /* pointer to variable for retry flag */
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The PRT_GETINFINITERETRY function retrieves an infinite retry setting for a
+printer.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfRetry Points to the variable that receives the infinite retry setting.
+ The variable is FALSE if infinite retry is disabled or TRUE if
+ retry is enabled.
+
+pbCommand Points to the variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the printer that receives the device-control function.
+ The handle must have been created previously by using the
+ DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: PRT_GETPRINTERSTATUS 0x0066 // Not Supported
+
+APIRET DosDevIOCtl( pfStatus, pbCommand, 0x0066, PRT_IOCTL_CATEGORY, hDevice )
+PBYTE pfStatus; /* pointer to printer status flag */
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The PRT_GETPRINTERSTATUS function retrieves the status of a printer.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfStatus Points to the variable that receives the printer status. This
+ variable can be a combination of the following values:
+
+ Value Meaning
+ -----------------------------------------------------------------
+ PRINTER_TIMEOUT Time-out occurred.
+
+ PRINTER_IO_ERROR I/O error occurred.
+
+ PRINTER_SELECTED Printer selected.
+
+ PRINTER_OUT_OF_PAPER Printer out of paper.
+
+ PRINTER_ACKNOWLEDGED Printer acknowledged.
+
+ PRINTER_NOT_BUSY Printer not busy.
+
+pbCommand Points to the variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the printer that receives the device-control function.
+ The handle must have been created previously by using the
+ DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: PRT_INITPRINTER 0x0046 // Not Supported
+
+APIRET DosDevIOCtl( 0L, pbCommand, 0x0046, PRT_IOCTL_CATEGORY, hDevice )
+PBYTE pbCommand; /* command value */
+HFILE hDevice; /* device handle */
+
+The PRT_INITPRINTER function initializes a printer.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbCommand Points to the variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the printer that receives the device-control function.
+ The handle must have been created previously by using the
+ DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: PRT_QUERYACTIVEFONT 0x0069 // Not Supported
+
+APIRET DosDevIOCtl( pbFontInfo, pbCommand, 0x0069, PRT_IOCTL_CATEGORY, hDevice )
+PBYTE pbFontInfo; /* pointer to structure for font information */
+PBYTE pbCommand; /* pointer to byte with command information */
+HFILE hDevice; /* device handle */
+
+The PRT_QUERYACTIVEFONT function determines which code page and font are
+currently active.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbFontInfo Points to a FONTINFO structure that specifies the active font.
+
+pbCommand Points to a reserved 8-bit value. The value must be zero.
+
+hDevice Identifies the printer that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: PRT_SETFRAMECTL 0x0042 // Not Supported
+
+APIRET DosDevIOCtl( pbFrameCtl, pbCommand, 0x0042, PRT_IOCTL_CATEGORY, hDevice )
+PBYTE pbFrameCtl; /* pointer to structure with frame settings */
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The PRT_SETFRAMECTL function sets the frame-control information for a
+printer.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbFrameCtl Points to the FRAME structure that contains the frame-control
+ information.
+
+pbCommand Points to the variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the printer that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: PRT_SETINFINITERETRY 0x0044 // Not Supported
+
+APIRET DosDevIOCtl( pfRetry, pbCommand, 0x0044, PRT_IOCTL_CATEGORY, hDevice )
+PBYTE pfRetry; /* pointer to retry flag */
+PBYTE pbCommand; /* pointer to variable with command */
+HFILE hDevice; /* device handle */
+
+The PRT_SETINFINITERETRY function sets infinite retry for a printer.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pfRetry Points to the variable that specifies whether to enable infinite
+ retry. If the variable is FALSE, the function disables infinite
+ retry. If the variable is TRUE, the function enables infinite
+ retry.
+
+pbCommand Points to the variable that contains a reserved value. The value
+ must be zero.
+
+hDevice Identifies the printer that receives the device-control function.
+ The handle must have been created previously by using the
+ DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: PRT_VERIFYFONT 0x006A // Not Supported
+
+APIRET DosDevIOCtl( pbFontInfo, pbCommand, 0x006A, PRT_IOCTL_CATEGORY, hDevice )
+PBYTE pbFontInfo; /* points to structure for font info */
+PBYTE pbCommand; /* points to byte with command info */
+HFILE hDevice; /* device handle */
+
+The PRT_VERIFYFONT function verifies that a particular code page and font
+are available for the specified printer.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbFontInfo Points to the FONTINFO structure that receives information for
+ the available font.
+
+pbCommand Points to a reserved 8-bit value. The value must be zero.
+
+hDevice Identifies the printer that receives the device-control
+ function. The handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+ o
+
+Topic: PTR_IOCTL_CATEGORY 0x0003 // Not Supported
+
+Topic: PTR_GETPTRDRAWADDRESS 0x0072 // Not Supported
+
+APIRET DosDevIOCtl( pbFunctionInfo, 0L, 0x0072, PTR_IOCTL_CATEGORY, hDevice )
+PBYTE pbFunctionInfo; /* pointer to structure for function */
+HFILE hDevice; /* device handle */
+
+The PTR_GETPTRDRAWADDRESS function retrieves the entry-point address and
+other information for the pointer-draw function (the function that draws the
+mouse pointer on the screen).
+
+Parameter Description
+----------------------------------------------------------------------------
+
+pbFunctionInfo Points to PTRDRAWADDRESS structure that receives the
+ function information.
+
+hDevice Identifies the pointing device that receives the
+ device-control function. The handle must have been created
+ previously by using the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or an error value if
+an error occurs.
+
+Comments
+
+The mouse device driver uses the pointer-draw function to update the pointer
+image on the screen, and retrieves the address and saves it to use whenever
+the pointer moves.
+
+ o
+
+Topic: SCR_IOCTL_CATEGORY 0x0003 // Not Supported
+
+Topic: SCR_ALLOCLDT 0x0070 // Not Supported
+
+APIRET DosDevIOCtl( psel, pvAddrInfo, 0x0070, SCR_IOCTL_CATEGORY, hDevice )
+PSEL psel; /* pointer to LDT selector */
+PVOID pvAddrInfo; /* pointer to structure with address info */
+HFILE hDevice; /* device handle */
+
+The SCR_ALLOCLDT function allocates a logical descriptor table (LDT)
+selector for an area of memory.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+psel Points to the logical descriptor table selector for the memory
+ area specified by the LDTADDRINFO structure.
+
+pvAddrInfo Points to the LDTADDRINFO structure that contains the address
+ and size of memory for which a selector is requested.
+
+hDevice Identifies the screen device that receives the device-control
+ function. This handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or the error value
+ERROR_I24_INVALID_PARAMETER if an error occurs.
+
+Comments
+
+Read/Write access is granted to data areas completely contained in the
+address range 0xA0000 through 0xBFFFF. Read-only access is granted to data
+areas outside this range, but inside the range 0x00000 through 0xFFFFF.
+Attempts to access any address outside this range results in an error.
+
+ o
+
+Topic: SCR_ALLOCLDTOFF 0x0075 // Not Supported
+
+APIRET DosDevIOCtl( ppv, pvAddrInfo, 0x0075, SCR_IOCTL_CATEGORY, hDevice )
+PVOID FAR * ppv; /* pointer to variable to receive selector:offset */
+PVOID pvAddrInfo; /* pointer to structure with address info */
+HFILE hDevice; /* device handle */
+
+The SCR_ALLOCLDTOFF function allocates a logical descriptor table (LDT)
+selector and offset for an area of memory.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+ppv Points to the variable that receives the allocated selector and
+ offset.
+
+pvAddrInfo Points to the LDTADDRINFO structure that contains the address
+ and size of memory for which a selector is requested.
+
+hDevice Identifies the screen device that receives the device-control
+ function. This handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or the error
+ERROR_I24_INVALID_PARAMETER if an error occurs.
+
+Comments
+
+Read/Write access is granted to data areas completely contained in the
+address range 0xA0000 through 0xBFFFF. Read-only access is granted to data
+areas outside this range, but inside the range 0x00000 through 0xFFFFF.
+Attempts to access any address outside this range results in an error.
+
+ o
+
+Topic: SCR_DEALLOCLDT 0x0071 // Not Supported
+
+APIRET DosDevIOCtl( 0L, psel, 0x0071, SCR_IOCTL_CATEGORY, hDevice )
+PSEL psel; /* pointer to LDT selector */
+HFILE hDevice; /* device handle */
+
+The SCR_DEALLOCLDT function deallocates a logical descriptor table (LDT)
+selector previously allocated by the SCR_ALLOCLDT or SCR_ALLOCLDTOFF
+function.
+
+Parameter Description
+----------------------------------------------------------------------------
+
+psel Points to the logical descriptor table selector to be
+ deallocated.
+
+hDevice Identifies the screen device that receives the device-control
+ function. This handle must have been created previously by using
+ the DosOpen function.
+
+Return Value
+
+The return value is zero if the function is successful or the error value
+ERROR_I24_INVALID_PARAMETER if an error occurs.
+
+ o
diff --git a/private/os2/doc/os2api.txt b/private/os2/doc/os2api.txt
new file mode 100644
index 000000000..518fce523
--- /dev/null
+++ b/private/os2/doc/os2api.txt
@@ -0,0 +1,694 @@
+This file lists the OS/2 APIs that are supported, not supported,
+and partially supported in Windows NT 3.5. It gives an explanation
+of the restrictions on those APIs that are partially supported.
+
+
+OS/2 APIs supported in Windows NT, version 3.5
+----------------------------------------------
+
+DosAllocHuge
+DosAllocSeg
+DosAllocShrSeg
+DosBeep
+DosBufReset
+DosCallback
+DosCallNmPipe
+DosCaseMap
+DosChDir
+DosChgFilePtr
+DosCLIAccess
+DosClose
+DosCloseQueue
+DosCloseSem
+DosConnectNmPipe
+DosCopy
+DosCreateCSAlias
+DosCreateQueue
+DosCreateSem
+DosCreateThread
+DosCwait
+DosDelete
+DosDevConfig
+DosDisConnectNmPipe
+DosDupHandle
+DosEditName
+DosEnterCritSec
+DosEnumAttribute
+DosErrClass
+DosError
+DosExecPgm
+DosExit
+DosExitCritSec
+DosExitList
+DosFileIO
+DosFileLocks
+DosFindClose
+DosFindFirst
+DosFindFirst2
+DosFindNext
+DosFlagProcess
+DosFreeModule
+DosFreeResource
+DosFreeSeg
+DosFSCtl
+DosFSRamSemClear
+DosFSRamSemRequest
+DosGetCollate
+DosGetCp
+DosGetCtryInfo
+DosGetDateTime
+DosGetDBCSEv
+DosGetEnv
+DosGetHugeShift
+DosGetInfoSeg
+DosGetMachineMode
+DosGetMessage
+DosGetModHandle
+DosGetModName
+DosGetPID
+DosGetPPID
+DosGetProcAddr
+DosGetPrty
+DosGetResource
+DosGetResource2
+DosGetSeg
+DosGetShrSeg
+DosGetVersion
+DosGiveSeg
+DosHoldSignal
+DosHugeIncr
+DosHugeShift
+DosInsMessage
+DosKillProcess
+DosLoadModule
+DosLockSeg
+DosMakeNmPipe
+DosMakePipe
+DosMemAvail
+DosMkDir
+DosMkDir2
+DosMonClose
+DosMonOpen
+DosMonRead
+DosMonReg
+DosMonWrite
+DosMove
+DosMuxSemWait
+DosNewSize
+DosOpen
+DosOpen2
+DosOpenQueue
+DosOpenSem
+DosPeekNmPipe
+DosPeekQueue
+DosPhysicalDisk
+DosPTrace
+DosPurgeQueue
+DosPutMessage
+DosQAppType
+DosQCurDir
+DosQCurDisk
+DosQFHandState
+DosQFileInfo
+DosQFileMode
+DosQFSAttach
+DosQFSInfo
+DosQHandType
+DosQNmPHandState
+DosQNmPipeInfo
+DosQNmPipeSemState
+DosQPathInfo
+DosQSysInfo
+DosQueryQueue
+DosQVerify
+DosR2StackRealloc
+DosRead
+DosReadAsync
+DosReadQueue
+DosReallocHuge
+DosReallocSeg
+DosResumeThread
+DosRmDir
+DosScanEnv
+DosSearchPath
+DosSelectDisk
+DosSelectSession
+DosSemClear
+DosSemRequest
+DosSemSet
+DosSemSetWait
+DosSemWait
+DosSendSignal
+DosSetCp
+DosSetDateTime
+DosSetFHandState
+DosSetFileInfo
+DosSetFileMode
+DosSetFilePtr
+DosSetFSInfo
+DosSetMaxFH
+DosSetNmPHandState
+DosSetNmPipeSem
+DosSetPathInfo
+DosSetProcCp
+DosSetPrty
+DosSetSession
+DosSetSigHandler
+DosSetVec
+DosSetVerify
+DosSizeSeg
+DosSleep
+DosStartSession
+DosStopSession
+DosSubAlloc
+DosSubFree
+DosSubSet
+DosSuspendThread
+DosTimerAsync
+DosTimerStart
+DosTimerStop
+DosTransactNmPipe
+DosUnlockSeg
+DosWaitNmPipe
+DosWrite
+DosWriteAsync
+DosWriteQueue
+
+KbdCharIn
+KbdClose
+KbdFlushBuffer
+KbdFreeFocus
+KbdGetCp
+KbdGetFocus
+KbdGetHWID
+KbdGetStatus
+KbdOpen
+KbdPeek
+KbdSetCp
+KbdSetFgnd
+KbdSetStatus
+KbdStringIn
+KbdXlate
+
+MouClose
+MouFlushQue
+MouGetDevStatus
+MouGetEventMask
+MouGetNumButtons
+MouGetNumQueEl
+MouGetPtrPos
+MouOpen
+MouReadEventQue
+MouSetDevStatus
+MouSetEventMask
+
+
+NetAPI calls supported in Windows NT, version 3.5
+-------------------------------------------------
+
+The table below details the OS/2 NetAPIs and the level of support for them
+under Windows NT 3.5. The different levels of support are:
+- Full: no significant restrictions apply
+- Down-level server + self: the API works only when the target LanMan server
+ (i.e. the server for which information is to be retrieved/modified etc.)
+ is a 'down-level' server (i.e. not Windows NT, for example: DOS, OS/2,
+ Windows for Workgroups).
+ In addition, the API works in the special case where the API is applied
+ to the local machine.
+- Down-level server only: same as above, but doesn't work when applied to the
+ local machine.
+- Unsupported: the API is not supported under Windows NT.
+
+The APIs are listed by functional groups.
+
+
+ SUPPORT LEVEL
+
+ | Full | Down-level | Down-level | Unsupported |
+ | | server + self | server only | |
+ |------|---------------|-------------|-------------|
+Access Permission APIs: | | | | |
+---------------------- | | | | |
+ NetAccessAdd | | | x | |
+ NetAccessCheck | | | | x |
+ NetAccessDel | | | x | |
+ NetAccessEnum | | | x | |
+ NetAccessGetInfo | | | x | |
+ NetAccessGetUserPerms | | | x | |
+ NetAccessSetInfo | | | x | |
+Alert APIs: | | | | |
+----------- | | | | |
+ NetAlertRaise | | | | x |
+ NetAlertStart | | | | x |
+ NetAlertStop | | | | x |
+Auditing APIs: | | | | |
+-------------- | | | | |
+ NetAuditClear | | | x | |
+ NetAuditOpen | | | | x |
+ NetAuditRead | | | x | |
+ NetAuditWrite | | | | x |
+Character Device APIs: | | | | |
+---------------------- | | | | |
+ NetCharDevControl | | | x | |
+ NetCharDevEnum | | | x | |
+ NetCharDevGetInfo | | | x | |
+ NetCharDevQEnum | | | x | |
+ NetCharDevQGetInfo | | | x | |
+ NetCharDevQPurge | | | x | |
+ NetCharDevQPurgeSelf | | | x | |
+ NetCharDevQSetInfo | | | x | |
+Config APIs: | | | | |
+------------ | | | | |
+ NetConfigGet | x | | | |
+ NetConfigGet2 | | | | x |
+ NetConfigGetAll2 | | | | x |
+ NetConfigSet | | | | x |
+Connection APIs: | | | | |
+---------------- | | | | |
+ NetConnectionEnum | x | | | |
+Domain APIs: | | | | |
+------------ | | | | |
+ NetGetDcName | x | | | |
+ NetLogonEnum | | | x | |
+ErrorLogging APIs: | | | | |
+------------------ | | | | |
+ NetErrorLogClear | | | x | |
+ NetErrorLogRead | | | x | |
+ NetErrorLogWrite | | | | x |
+File APIs: | | | | |
+---------- | | | | |
+ NetFileClose | | | x | |
+ NetFileClose2 | | | x | |
+ NetFileEnum | | | x | |
+ NetFileEnum2 | | | x | |
+ NetFileGetInfo | | | x | |
+ NetFileGetInfo2 | | | x | |
+Group APIs: | | | | |
+----------- | | | | |
+ NetGroupAdd | x | | | |
+ NetGroupAddUser | x | | | |
+ NetGroupDel | x | | | |
+ NetGroupDelUser | x | | | |
+ NetGroupEnum | x | | | |
+ NetGroupGetInfo | x | | | |
+ NetGroupGetUsers | x | | | |
+ NetGroupSetInfo | x | | | |
+ NetGroupSetUsers | x | | | |
+Handle APIs: | | | | |
+------------ | | | | |
+ NetHandleGetInfo | | | x | |
+ NetHandleSetInfo | | | x | |
+Mailslot APIs: | | | | |
+-------------- | | | | |
+ DosDeleteMailslot | x | | | |
+ DosMailslotInfo | x | | | |
+ DosMakeMailslot | x | | | |
+ DosPeekMailslot | x | | | |
+ DosReadMailslot | x | | | |
+ DosWriteMailslot | x | | | |
+Message APIs: | | | | |
+------------- | | | | |
+ NetMessageBufferSend | x | | | |
+ NetMessageFileSend | | | x | |
+ NetMessageLogFileGet | | | x | |
+ NetMessageLogFileSet | | | x | |
+ NetMessageNameAdd | x | | | |
+ NetMessageNameDel | x | | | |
+ NetMessageNameEnum | x | | | |
+ NetMessageNameFwd | | | x | |
+ NetMessageNameGetInfo | x | | | |
+ NetMessageNameUnFwd | | | x | |
+Print Destination APIs: | | | | |
+----------------------- | | | | |
+ DosPrintDestAdd | | | | x |
+ DosPrintDestControl | | | | x |
+ DosPrintDestDel | | | | x |
+ DosPrintDestEnum | | | | x |
+ DosPrintDestGetInfo | | | | x |
+ DosPrintDestSetInfo | | | | x |
+Print Job APIs: | | | | |
+--------------- | | | | |
+ DosPrintJobContinue | | | | x |
+ DosPrintJobDel | | | | x |
+ DosPrintJobEnum | | | | x |
+ DosPrintJobGetId | | | | x |
+ DosPrintJobGetInfo | | | | x |
+ DosPrintJobPause | | | | x |
+ DosPrintJobSetInfo | | | | x |
+Print Queue APIs: | | | | |
+----------------- | | | | |
+ DosPrintQAdd | | | | x |
+ DosPrintQContinue | | | | x |
+ DosPrintQDel | | | | x |
+ DosPrintQEnum | | | | x |
+ DosPrintQGetInfo | | | | x |
+ DosPrintQPause | | | | x |
+ DosPrintQPurge | | | | x |
+ DosPrintQSetInfo | | | | x |
+Profile APIs: | | | | |
+------------- | | | | |
+ NetProfileSave | | | x | |
+ NetProfileLoad | | | x | |
+Remote Utility APIs: | | | | |
+-------------------- | | | | |
+ NetRemoteCopy | | | x | |
+ NetRemoteExec | | | x | |
+ NetRemoteMove | | | x | |
+ NetRemoteTOD | x | | | |
+Server APIs: | | | | |
+------------ | | | | |
+ NetServerAdminCommand | | | x | |
+ NetServerDiskEnum | x | | | |
+ NetServerEnum | | | x | |
+ NetServerEnum2 | | | x | |
+ NetServerGetInfo | x | | | |
+ NetServerSetInfo | x | | | |
+Service APIs: | | | | |
+------------- | | | | |
+ NetServiceControl | x | | | |
+ NetServiceEnum | x | | | |
+ NetServiceGetInfo | x | | | |
+ NetServiceInstall | x | | | |
+ NetServiceStatus | | | | x |
+Session APIs: | | | | |
+------------- | | | | |
+ NetSessionDel | x | | | |
+ NetSessionEnum | x | | | |
+ NetSessionGetInfo | x | | | |
+Share APIs: | | | | |
+----------- | | | | |
+ NetShareAdd | x | | | |
+ NetShareCheck | x | | | |
+ NetShareDel | x | | | |
+ NetShareEnum | x | | | |
+ NetShareGetInfo | x | | | |
+ NetShareSetInfo | x | | | |
+Statistics APIs: | | | | |
+---------------- | | | | |
+ NetStatisticsClear | | | x | |
+ NetStatisticsGet | | | x | |
+ NetStatisticsGet2 | x | | | |
+Use APIs: | | | | |
+--------- | | | | |
+ NetUseAdd | | x | | |
+ NetUseDel | | x | | |
+ NetUseEnum | | x | | |
+ NetUseGetInfo | | x | | |
+User APIs: | | | | |
+---------- | | | | |
+ NetUserAdd | x | | | |
+ NetUserDel | x | | | |
+ NetUserEnum | x | | | |
+ NetUserGetGroups | x | | | |
+ NetUserGetInfo | x | | | |
+ NetUserModalsGet | x | | | |
+ NetUserModalsSet | x | | | |
+ NetUserPasswordSet | x | | | |
+ NetUserSetGroups | x | | | |
+ NetUserSetInfo | x | | | |
+ NetUSerValidate2 | | | | x |
+Workstation APIs: | | | | |
+----------------- | | | | |
+ NetWkstaGetInfo | x | | | |
+ NetWkstaSetInfo | x | | | |
+ NetWkstaSetUID | | | | x |
+ NetWkstaSetUID2 | | | | x |
+
+
+NetBios (V3.0)
+--------------
+
+NetBiosClose (V2.X)
+NetBiosEnum (V2.X)
+NetBiosGetInfo (V2.X)
+NetBiosOpen (V2.X)
+NetBiosSubmit (V2.X)
+
+VIO APIs
+--------
+
+VioCheckCharType
+VioEndPopUp
+VioGetAnsi
+VioGetBuf
+VioGetCp
+VioGetCurPos
+VioGetCurType
+VioPopUp
+VioReadCellStr
+VioReadCharStr
+VioScrLock
+VioScrollDn
+VioScrollLf
+VioScrollRt
+VioScrollUp
+VioScrUnLock
+VioSetAnsi
+VioSetCp
+VioSetCurPos
+VioSetCurType
+VioShowBuf
+VioWrtCellStr
+VioWrtCharStr
+VioWrtCharStrAtt
+VioWrtNAttr
+VioWrtNCell
+VioWrtNChar
+VioWrtTTY
+
+
+VIO calls supported only when called by PM applications (non-null HPS parameter)
+--------------------------------------------------------------------------------
+
+VioAssociate
+VioCreateLogFont
+VioCreatePS
+VioDeleteSetId
+VioDeRegister
+VioDestroyPS
+VioGetDeviceCellSize
+VioGetFont
+VioGetOrg
+VioGetPhysBuf
+VioModeUndo
+VioModeWait
+VioPrtSc
+VioPrtScToggle
+VioQueryFonts
+VioQuerySetIds
+VioRedrawSize
+VioRegister
+VioSavRedrawUndo
+VioSavRedrawWait
+VioSetDeviceCellSize
+VioSetFont
+VioSetOrg
+VioShowPS
+
+Win/Gpi/Dev API: all supported by the PM Subsystem
+----------------
+
+
+OS/2 APIs Not Supported in Windows NT, version 3.5
+--------------------------------------------------
+
+DosDynamicTrace
+DosFindNotifyClose
+DosFindNotifyFirst
+DosFindNotifyNext
+DosOplockRelease
+DosOplockWait
+DosPortAccess
+DosShutdown
+DosSystemService
+DosSysTrace
+
+KbdDeRegister
+KbdRegister
+KbdSetCustXt
+KbdSynch
+
+MouDeRegister
+MouDrawPtr
+MouGetNumMickeys
+MouGetPtrShape
+MouGetScaleFact
+MouInitReal
+MouRegister
+MouRemovePtr
+MouSetPtrPos
+MouSetPtrShape
+MouSetScaleFact
+MouSynch
+
+PicIchg
+PicPrint
+
+
+OS/2 APIs Partially Supported in Windows NT, version 3.5
+--------------------------------------------------------
+
+DosDevIOCtl, DosDevIOCtl2
+
+The IOCTLs from the Screen and Pointer Draw category are not supported.
+All of the IOCTLs from the General category are supported.
+All of the IOCTLs from the Asynchronous Communications category
+are supported:
+
+ASYNC_GETBAUDRATE
+ASYNC_GETCOMMERROR
+ASYNC_GETCOMMEVENT
+ASYNC_GETCOMMSTATUS
+ASYNC_GETDCBINFO
+ASYNC_GETINQUECOUNT
+ASYNC_GETLINECTRL
+ASYNC_GETLINESTATUS
+ASYNC_GETMODEMINPUT
+ASYNC_GETMODEMOUTPUT
+ASYNC_GETOUTQUECOUNT
+ASYNC_SETBAUDRATE
+ASYNC_SETBREAKOFF
+ASYNC_SETBREAKON
+ASYNC_SETDCBINFO
+ASYNC_SETLINECTRL
+ASYNC_SETMODEMCTRL
+ASYNC_STARTTRANSMIT
+ASYNC_STOPTRANSMIT
+ASYNC_TRANSMITIMM
+
+The following IOCTLs from the Keyboard category are supported:
+
+KBD_CREATE
+KBD_DESTROY
+KBD_GETCODEPAGE
+KBD_GETINPUTMODE
+KBD_GETINTERIMFLAG
+KBD_GETSHIFTSTATE
+KBD_PEEKCHAR
+KBD_READCHAR
+KBD_SETFOCUS
+KBD_SETINPUTMODE
+KBD_SETINTERIMFLAG
+KBD_SETKCB
+KBD_SETSHIFTSTATE
+
+All of the IOCTLs from the Printer category are supported:
+
+PRT_ACTIVATEFONT
+PRT_GETFRAMECTL
+PRT_GETINFINITERETRY
+PRT_GETPRINTERSTATUS
+PRT_INITPRINTER
+PRT_QUERYACTIVEFONT
+PRT_SETFRAMECTL
+PRT_SETINFINITERETRY
+PRT_VERIFYFONT
+PTR_GETPTRDRAWADDRESS
+
+The following IOCTLs from the Pointing Device (Mouse) category
+are supported:
+
+MOU_GETBUTTONCOUNT
+MOU_GETEVENTMASK
+MOU_GETMICKEYCOUUT
+MOU_GETMOUSTATUS
+MOU_GETQUESTATUS
+MOU_READQUESTATUS
+MOU_SETEVENTMASK
+MOU_SETMOUSTATUS
+
+The following IOCTLs from the Disk Control category are supported:
+
+DSK_BLOCKREMOVABLE
+DSK_GETDEVICEPARAMS
+DSK_GETLOGICALMAP
+DSK_LOCKDRIVE
+DSK_READTRACK
+DSK_REDETERMINEMEDIA
+DSK_SETLOGICALMAP
+DSK_SYNC
+DSK_UNLOCKDRIVE
+DSK_VERIFYTRACK
+
+The following IOCTL from the Physical Disk Control category is supported:
+
+PDSK_GETPHYSDEVICEPARAMS
+
+
+The following IOCTL from the Monitors category is supported:
+
+MON_REGISTERMONITOR
+
+
+DosFSAttach
+
+This function partially implements the DosFSAttach() API. The only valid
+FsName is "LAN". The format expected for the arguments is as follows:
+
+DeviceName = device name, e.g. "J:", "LPT1:"
+FsName = "LAN"
+FsData = "\01\0SHARENAME" for a regular connection or
+ "\02\0SHARENAME\0PASSWORD" for a password connection or
+ "\03\0SHARENAME\0PASSWORD\0USERNAME" for a
+ username/password connection.
+FsDataLength = length of FsData
+AttachFlags = FS_ATTACH or FS_DETACH
+
+The function connects to the network using WNetAdd/DelConnection().
+Therefore it will use the multiple provider router to connect to any
+type of network for which Windows NT has a redirector. The SHARENAME
+format depends on the network you're trying to reach. For LanMan/MsNet
+networks it is "\\\\sharename\\servername".
+
+If DeviceName is a drive letter, the drive is automatically reset to the
+root directory after a connection and before a disconnection. This is
+for compatibility with OS/2.
+
+
+VioGetConfig
+
+The following return values will always be returned in the _VIOCONFIGINFO
+structure. All other fields will always return 0 (zero).
+
+adapter = DISPLAY_VGA
+display = MONITOR_851X_COLOR
+cbMemory = 0x40000 (262,144)
+
+
+VioGetMode
+
+The following return values will always be returned in the _VIOMODEINFO
+structure. Values for col, row, hres, and vres will contain the correct
+values.
+
+fbType = VGMT_OTHER
+color = COLOR_16
+fmt_ID = 0
+attrib = 0
+buf_addr = 0xFFFFFFFF
+buf_length = 0L
+full_length = 0L
+partial_length = 0L
+ex_data_addr = 0xFFFFFFFF
+
+
+VioSetMode
+
+The col and row fields in the _VIOMODEINFO structure will be used.
+All other fields will be ignored. No error code or value checking
+will be performed.
+
+
+VioGetState, VioSetState
+
+All fields in the structure will contain initial values, as indicated
+in the following list. Any setting of new values will be saved and
+returned on the next VioGetState call.
+
+VIOINTENSITY.fs = 0x0001
+VIOOVERSCAN.color = 0
+VIOPALSTATE.acolor = all 0
+VIOCOLORREG.colorregaddr = all 0
+VIOSETUNLINELOC.scanline = 31
+VIOSETTARGET = (only primary display)
+
diff --git a/private/os2/doc/os2dbg.doc b/private/os2/doc/os2dbg.doc
new file mode 100644
index 000000000..ced770882
--- /dev/null
+++ b/private/os2/doc/os2dbg.doc
Binary files differ
diff --git a/private/os2/doc/os2nt.txt b/private/os2/doc/os2nt.txt
new file mode 100644
index 000000000..c40852a60
--- /dev/null
+++ b/private/os2/doc/os2nt.txt
@@ -0,0 +1,674 @@
+
+ OS/2 on NT Plan white paper
+ ---------------------------
+Author: Yaron Shamir.
+
+The first 6 chapters define goals, assumptions,
+constraints, design alternatives and tasks.
+The rest break the tasks down and estimate the effort and
+experty needed to accomplish the tasks.
+
+Other helpful writeups are:
+ * .\pownt.ppt (a slide show that summerizes the project)
+ * .\ioctls.txt (Cruiser IOCTLs support)
+ * .\apistat (start point of cruiser 32 API implementation)
+ * \nt\public\spec\os2.txt (original design point of SS)
+
+Note: this paper is still in a working mode i.e. draft. It is
+checked in for convenience of reader.
+
+0. Basics:
+----------
+The overall mission is to construct a SW layer, on top of NT OS,
+that will have similar functionality to OS/2 2.0 (base, PM and basic
+utilities).
+
+1. Goals:
+---------
+This are the goals defined for the 'OS2 on NT' effort. an (*) sign means
+'reservations, assumptions etc. follow'.
+
+ 1 'clean' X86 32 bit apps of OS2 2.0 should run unmodified (*)
+ 2 the OS/2 layer should be portable accros HW platforms.
+ 3 'well-behaving' PM 16-bit apps (OS/2 1.1, 1.2, 1.3) will run binary
+ compatible.
+ 6 A complete set of system services will be provided.
+ - base APIs (*)
+ - PM APIs (32 and 16) (*)
+ - CMD, shell, spooler, task manager, control panel,
+ file manager will be integrated with WIN32, as much as schedule
+ allows.
+ - NLS support (OS2 NLS and DBCS).
+
+2. Assumptions:
+---------------
+2.1 Image Format:
+-----------------
+OS/2 2.0 will adopt PE EXE format, such that the NT loader will load
+32 bit Cruiser apps. We will provide a 16-bit EXE (NE) loader.
+
+2.2 Alignment:
+--------------
+OS/2 2.0 will support natural alignment as defined by DCRs.
+
+2.3 Exception Handling:
+----------------------
+OS2 on NT will support the NT type exception handling.
+A DCR was filed for OS2 2.0 to support it as well.
+
+2.4 OS2 2.0 API:
+---------------
+Is frozen.
+
+3 Constraints and Caveats:
+--------------------------
+
+3.1 General Restrictions on apps:
+---------------------------------
+ - No mixed 16/32 code.
+ - No direct HW manipulation:
+ * No private Decive Drivers
+ * Only a limited set of IOCTLS will be supported
+ (see list in \\popcorn\razzle!src\os2\ioctls.txt)
+ * No ring-2 code (IOPL code)
+ * No direct manipulation of physical video buffer i.e. VIO apps
+ will run inside a character window only.
+ - No use of unpublished entry points.
+
+3.2 NT features not in the plan for PM:
+--------------------------------------
+ - C2 security.
+ - prevasive exception handling thru-out the PM code. We intend to
+ put enough exception handling to make it safe for the rest of
+ the system.
+
+4 Building OS2 on NT in phases:
+------------------------------
+
+ Phase Approx MY
+ ----- ---------
+0 Build the team 2 (2 month per Engeineer, 10 Eng)
+1 32b Base APIs 2 (+1 if LE needed and SEH not accepted)
+2 16 bit VIO 5
+3 PM, split screens 10
+4 'share the glass' 10
+
+4.1 Summary of the phases:
+--------------------------
+This section summerizes the phases by current applications support,
+specific restrictions for the phase, portablility, status,
+work items and WIN/NT support. See also ???\pownt.ppt.
+Further details are in chapter ???, 'task break down'.
+
+4.1.1 Phase 1 Summary:
+----------------------
+Features:
+* Support Cruiser DOS32 APIs only. They run within the WIN32/NT
+ environment (CMD, TM, FM).
+* Not supported (in addition to general restrictions): PM,
+ VIO/KBD/MOU/MON, IBM 2.0 exception handling.
+* Applications that can run: CRT, 32 bit flat. Examples: SQL, C,
+ UNIX-ported apps.
+* Portablility: Easy. MIPS and X86 can be supported at the same
+ time.
+Status:
+* Largely complete, compatible with MS Cruiser
+ as of 7/90.
+Work:
+* Loader for LE - Flatten and Widen Cruiser loader.
+* Named pipes layer.
+* NLS ("Country.sys" etc), map on Unicode.
+* Device + FS IOCTLs (limited).
+* Misc (complete semaphores, session APIs)
+* Integration of OS2 base server with WIN/NT server.
+Support from Win/NT:
+* Assist loading non-PE executables (if need to
+ load LE).
+* NLS support.
+* HPFS support (FM).
+
+4.1.2 Phase 2 Summary:
+----------------------
+Features:
+* Support 16bit OS2 1.X , non-PM (VIO) apps, inside a character
+ window.
+* Not supported (in addition to general restrictions): None.
+* Applications that can run: WORD5.5, Paradox, Rbase, PWB.
+* Portability: hard. Require emulation for non-x86, alike the work for
+ WIn16 .
+Status:
+* No work done so far.
+Work:
+* Loader for 16b OS2 binaries (NE ).
+* Provide a 16-32 thunk layer.
+* Implement the following 16B OS2 APIs:
+ - VIO, MOU, MON, KBD support.
+ - 16B style semaphores (FSRAM etc.).
+ - 16B memory management.
+ - Signal handling.
+Support from Win/NT:
+* LDT management.
+* 16B context switch.
+* console support for VIO.
+
+4.1.3 Phase 3 Summary:
+----------------------
+* 'Frame for PM applications' - not a system of it's own - no
+ separate PM file manager, print manager, control panel etc. Support
+ 16bit and 32bit clean PM binaries.
+* Not supported (in addition to general restrictions): Clipboard, DDE
+ between PM apps and Windows apps.
+* Application that can run: PM-WORD, PM-EXCEL, 123G ...
+* Portability: 32 bit easy, 16 bit requires emulation.
+Status:
+* Win32 engine can support PMGRE, need hooks.
+* Most PMWIN is flattened and widened to 32.
+Work:
+* Write a PMGRE mapping layer to sit on GDI.
+* Flatten and widen PM GPI (sits on PMGRE).
+* Complete port PMWIN.Hook into WIN32 input.
+* 16->32 thunking.
+* Integrate with WIN32 - remoting, input etc.
+* Unicode to NLS/DBCS.
+* Configuration APIs (os2sys.ini, os2.ini).
+Support from Win/NT:
+* USER/Input: Recongize the 'PM session', SPB.
+* GDI: PMWIN callbacks. PM-flavor DC, item variants.
+
+4.1.4 Phase 4 Summary:
+----------------------
+Features:
+* OS2 and Windows app sharing the glass and communicating with
+ each other.
+* Clean PM apps (defined by ???) run unmodified (binary).
+* No restrictions except general restrictions in ???.
+Status:
+ Not started.
+Work:
+* Design necessary hooks in USER and input.
+* Implement handshake between PMWIN and USER.
+* Implement PM frame windows as USER windows ('a bit of Holeport')
+* Implement translation layers to support DDE, clipboard, metafile.
+* More environment itegration (e.g. task manager).
+Support from Win/NT:
+* Recognize PM-flavour windows (the PM 'frame' windows). Pass input
+ directed to those, to the PM queue.
+
+
+5 Design notes:
+--------------
+5.1 Phase 3: Portable, split screen groups:
+-------------------------------------------
+This is the approach that is recommended by the experts. It calls
+for remoting the PM apis selectively from the client DLL into
+a PM server that reside with the WIN32 server and uses it.
+
+The Approach - a virtual desktop:
++++++++++++++++++++++++++++++++++
+Generaly, the way we see the PM/OS2 subsystem, is that of a desktop, one
+of many. It is NOT viewed as a counter part to the NT+WIN32 system, but
+rather as a subsystem on top of it. What we mean by this is that for the
+user there is one physical desktop, managed in one place. The PM 'virtual
+desktop' is just a frame for running PM apps. The implication of this
+view are pervasive, e.g. it does not make sense to provide a PM
+print manager user interface.
++++++++++++++++++++++++++++++++++
+
+5.1.1 Split Screen block diagram:
+--------------------------------
+
+ PM app process WIN32 + PM server process
+ --------------
+ PM client DLL PMWIN module WIN USER module
+ -----+-------- ------------ ----------------
+ | GPI GRE =======> GDI module
+ | ------------ ----------------
+ | DDI (display driver)
+ ------------ ------------ ----------------
+ BASE client DLL OS2 base server WIN32 kernel module
+ --------------- ---------------------------------------
+ | |
+ NT apis + lpc (warp?) lpc + NT APIs
+ | |
+ | |
+ ------v------------------------------------|-----------------
+ +------------------------------------+
+ NT Executive
+ -----------------------------------------------------------
+
+The picture is too rough to cover all aspects. The intention is to
+build PMWIN as a separate unit that (as a rule) don't use the windows USER
+module. The reason for that is mainly the list of hard-to-solve differences
+between the two. For example, different order of messages
+(which implies a different state machine for windows, hence a different
+design) between PMWIN and USER.
+This was experienced by porthole project as a major problem in merging the
+two window managers. Hence the constraints of different screen groups,
+no DDE and no Clipboard between the two.
+
+On the other hand, it is perceived feasible, though non-trivial,
+to write a PMGRE layer that maps onto WIN32 GDI graphic engine.
+
+As for display and input drivers, the intention is to share the WIN32
+drivers all the way i.e. no PM display device drivers or input device
+drivers are needed.
+
+The OS/2 kernel (base) layer is completely independant of the PM/WIndows
+issues and sits directly on top of NT, with a client DLL and a server
+process DLL, to be merged into the WINDOWS server (csr).
+
+Some extra support (detailed thru the sections below), will be required
+from the WIN32 server modules: USER to support the input model and
+background/foreground switching, GDI and/or DDI to support PM-style
+graphics.
+
+5.1.2 Implementation Notes
+--------------------------
+5.1.2.1 Base:
+------------
+We will take the current base OS/2 layer and complete it to cover all
+APIs (see constraints for the match to Cruiser). The main items missings
+today are:
+ - named pipes APIs
+ - session APIs
+ - NLS DBCS implementation (crosses many APIs).
+ - portions of MuxWait APIs.
+ - portions of Memory management APIs.
+ - portions of EAs APIs (FindFirst/Next/Close)
+ - 16 bit support.
+
+Character based utilities: CMD32.EXE and it's built-in utilities are done
+(80%). The other utilities are written to use WIN32 base calls.
+We can offer those to the OS/2 user, since CMD32.EXE will be able to
+invoke apps written for other layers, via the NT SM. However - the prefered
+approach is to eliminate cmd32.exe all together, and have CMD.EXE be the
+only CLI in the system, invoking both flavours of apps. The cmd line
+semantics is almost identical between WIN, DOS and OS2 CMDs.
+
+5.1.2.3 PM 'Presentation' Device Drivers:
+-----------------------------------------
+The term 'presentation DD' refers to the graphic I/O devices that
+are driven by the PM graphic engine. Those are NOT based on standard
+NT I/O Device Drivers, but are rather a set of user mode programs that
+control devices directly. Such are screen, printers, scanners. The
+interface they present is called NTDDI and is used EXCLUSIVELY by the
+PM engine. This model is NOT used for the user input devices (see section
+on PMWIN and input system.
+
+For the presentation (or display) device drivers (and in short DDI), the
+PM implementation simply do not exist. Since we use the WIN32 engine,
+this part of the system us unified for WIN32 and PM (thanks to the engine
+design).
+
+5.1.2.4 PM GPI/GRE:
+-------------------
+Here is the architecure picture, now zoomed on the graphic engine area:
+ +----------------+
+ | PM Application ---------+
+ +-------|--------+ | Client
+ . .
+ --------------------------------------------------------------
+ . .
+ v | Server
+ +-------+ |
+ | PMWIN + |
+ +---+---+ v
+ | +-----------+
+ | | PM GPI |
+ | +-----V-----+
+ +PMGRE API->| PM GRE |
+ | +-----|-----+
+ | v
+ | +----------------------------+
+ M-Desktop xface+---->| WIN32 GDI Graphic Engine |
+ +----------------------------+
+ NT DDI Interface -----------------------------------
+ +----------------------------+
+ | Display DD | Printer DD |..|
+ +----------------------------+
+
+
+We will implement a PMGRE layer to sit on top of the GDI engine. We will
+take the IBM PMGPI layer and complete it (this means porting to 32 bit flat
+portable code), using the Cruiser GPI code. This approach will keep the rest
+of the system (PMWIN, PM apps ...) untouched.
+
+Engine integration Notes:
+-------------------------
+ - Need to get some extra support into the Win32 engine,
+ such that it can handle both GDI and PMGRE requests:
+ 1. callbacks for SetupDC (this is a handshake that takes place when
+ some of the graphic objects are to be repainted after a window change).
+ This callback needs to (a) know the windows is a PM-style and (b) know
+ how to call it.
+ 2. GDI interface for unicode. This is not speced yet, but bobmu
+ says it is in the plan for 1st release.
+ 3. Well define how a DC is setup to be a PM-style DC. This will
+ need to propagate correctly in order for the final pixels to be drawn
+ correclty. This is needed, to overcome a few differnces between PM
+ graphics and WIN grahpics:
+ - line drawing: end-point exclusive vs start-point exclusive.
+ - coordinate system: upper left vs lower left corner origin.
+ - rectangle fill algorithm (Hard, too technical for this memo).
+ - line drawing rounding (ditto).
+ 4. Callbacks for VisRgnCallback need to call PMWIN as well
+ as USER.
+ 5. Need to make sure that NTDDI supports PM-style drawing, and if
+ modifications needed, do it soon so external developers of drivers
+ are awarer. Make sure that MS display drivers implement and test the
+ support.
+
+
+5.1.2.5 PMWIN:
+-------------
+We will look hard into using PPM PMWIN code.
+
+The order of work will be:
+ o make it work with WIN32 components, as a server only (i.e. clients
+ will link in as a DLL). This will acheive the integration needed
+ with the input, GDI, display of WIN32/NT.
+ o After making it completely work, we will start pulling off
+ server-side APIs to the client DLL as possible. Given the approach
+ to GPI/GRE above, it could be straight forward. We will need to
+ work closely with the WIN32/NT USER and GDI group on the remoting
+ issue.
+ o We will also look at the WIN32 performance analysis on going
+ what optimizations to do to PM32 (e.g. batch GPI calls). We will
+ adjust or do differently, as fit and as time allows.
+
+Input synergy: PPM desktop sits on top of the main windowing system.
+So while WIN32 is active, you see a little icon of PM that you can
+switch to. A specific key-stroke or a mouse click on the icon will
+open and maximize the PM desktop. The support underneath is provided
+by WIN32 USER: a router sits below all desktops and an API is avail
+for switching desktops. For the WIN32 USER, PM is another (though somewhat
+special) client window. The input module of PM will be modified to
+unwrap the windowing messages back into raw input messages, so the
+rest of PMWIN is unaware. It is yet unclear to us whether additional
+support is required from USER, to get all the low-level info up to
+the PM desktop input thread.
+
+PMWIN and input system Integration notes:
+----------------------------------------
+ - we will need the input support described above.
+ - SPB calls need to be exported, such that PM 'desktop' gets the
+ information on PM apps' video output while in background.
+
+5.1.2.6 PM environment services:
+-------------------------------
+Here included all the PM apps that come with the retail OS/2 2.0. Those
+will have to be ported and to be integrated with the equivalent WIN32s.
+
+ - PM SHELL *
+ - PM Control Pannel *
+ - PM spooler (print manager) **
+ - PM File Manager **
+ - PM task manager ***
+ - PMVIO (console handler) **
+
+* must be integrated to some extent, and scrap redundant functionality.
+ Examples: the shell serves as a process frame for some system thread.
+ We might want to use the WIN32 server process for this same purpose.
+ OR - the control pannel. We would like to see there stuff related to
+ the virtual desktop of PM (e.g. background color), but not stuff related
+ to the physical desktop (e.g. printer driver setup).
+
+**want to scrap, and leave the user with one utility for the whole system
+ e.g. one file manager, one print manager - that of WIN32. For the file
+ manager, there are some questions to be answered, like 'will the WIN32
+ file manager be able to run PM apps, OS2 apps? how about managing EAs?
+
+***should see only PM tasks. Might be neat to have a quick, double-click way,
+ to get at the system print manager (this is equivalent to the sequence
+ 'get out of PM desktop; double-click on print manager under WIN32'.
+
+5.1.3 pros and cons for the split screen approach:
+---------------------------------------------------
+ + avoids the clash between PMWIN design and windows USER design.
+ + can be made robust and portable (see papers on WIN32 client-server
+ discussion).
+ + best attempt to use existing portable code.
+ + Allow IBM and MS to proceed with shell work without a hopeless
+ integration effort between IAYF and CUA.
+
+ - split screen groups is ugly and can confuse the user.
+ - duplicate functionality (control pannel, shell etc.) need
+ to be avoided, otherwise more confusion and bugs.
+ - no way to communicate between PM apps and WIN apps (a-la DDE).
+
+5.2 Non-portable, split screen groups:
+--------------------------------------
+Same as 4.1, except we can look at using larger chunks of Cruiser code.
+To get to the extreme, we could do a port of Cruiser PM code to work on
+NT/X86...
+This will not achieve any long term goals (stable, portable code base).
+but might achieve a better 16B compatibility. Does not look like a good
+match for 'OS2 on NT' goals.
+
+5.3 Portable, joint screen groups:
+---------------------------------
+HolePort. This is the user's dream. The Porthole experience says you
+can do 80% of it, but the rest is a night mare. Now, the case is similar
+but some differences are note worthy:
+
+ - the base is a portable, WIN32 environment, not the PM environment that
+ is the base for PortHole.
+ - there are very few PM32 apps, so less pecularities you need to deal
+ with.
+ - if the PM 32 APIs are written strict enough, we might be able to force
+ PM32 apps to behhave nicely.
+
+5.3.1 Pros and Cons for HolePort:
+--------------------------------
+ + same screen group, DDE, Clipboard - all those are in the reach.
+ + no need for multiple file managers, spoolers, shells... the PM
+ work boils down to PMWIN->USER layer, on client and server, plus
+ GPI->GDI.
+
+ - risky, given the porthole experience.
+ - Performance might be slow.
+
+We will not go Holeport, but rather work on both USER and PMWIN to make
+them work together. The approach will be that every PM windows will have
+it's frame be a WIN32/USER windows, while inner (clipped to it) windows
+will not be known to USER, and managed solely by PMWIN. (see separate
+note on this).
+
+
+6 Synergy with WIN32/NT:
+-----------------------
+Our intent is to find a way to work with the WIN32/NT team, such that
+we can work mostly indpendantly, without using a lot of the WIN32/NT
+time, and also to use as much as possible the development environment
+and the code itself.
+
+6.1 Development Environment:
+----------------------------
+We will pick up the OS/2 base work (os2ss), the PMWIN work and PM engine
+work, from where they were back in August 90.
+We will enlist in both in the main NT shares (popcorn\razzle and ntos2\ntrel), and get the PMWIN stuff
+from \\popcorn\oldraz, the PMGPI stuff from \\oatbran\pm, and the PMGRE stuff
+from \\rastaman\pm share incrorporated into a PM subtree of \nt\private SLM
+tree. Need to talk with kengr on doing this.
+
+In the first phase we will build the PM server together with the WIN server,
+but not in the same place, possibly using the WIN server code as a DLL
+(our server will also be a DLL). The idea here is not to put the burden of
+building PM every time you build WIN.
+
+6.2 Testing environment:
+------------------------
+We need to pick up the Cruiser test suites, those already ported to NT
+and those that were not ported yet. Need to sync with moshed.
+
+6.3 Technical writing:
+---------------------
+TBD (both requirements and plan of attack).
+
+
+7. Task Break Down:
+------------------
+
+7.1 Phase 1 - 32 base:
+----------------------
+Design and integration - this phase is farely indepenent and can
+proceed any time. The main design point to be figured out with
+the WIN/NT team is the CSR integration:
+We need to design how an OS2 application can be
+loaded from CMD.exe and WIN task manager. Ideally we will be
+able to eliminate CMD32.exe all together at this phase. A WIN32
+app should be able to load an OS2 executable and vice versa.
+
+If we need to load LE binaries, then we will implement a loader,
+using Cruiser loader source code. This loader will be a PE application
+itself, and will be loaded as a shadow when an LE application
+is to be loaded. This is an optional design point to figure out
+with the NT loader/process people.
+
+For testing we will use the Cruiser test suite.
+
+
+Task #eng #week Comments
+---------------------------------------------------
+CSR integration 1 2 (do we need UMTYPE OS2?)
+Fix Cruiser CRT 1 2 (find out who own CRT)
+Mov IO to console 1 1
+Loader for LE 1 16 May not be needed.
+Cruiser Named Pipes 1 3
+NLS 1 2 (see apistat)
+DBCS 1 2 (see apistat)
+IOCTLS 1 3 (see ioctls.txt)
+IFS apis 1 3 (?) (need to look at steve's design)
+Finish MuxWaitSem 1 2 (?) (need to look at)
+Finish Mem Apis 1 2 (?) (need to look at)
+Session APIs 1 3 (?)
+Integration+Test 1 40
+
+Total 2-3 80 (app 2 MY)
+
+Serialization notes:
+the CSR integration should be done before the session APIs and the loader.
+The APIs items can be done in parallel. NLS/DBCS is a block,
+and IFS/IOCTLs too. Component testing can be done any time.
+
+7.2 Phase 2 - 16 VIO+base:
+-------------------------
+
+Design, dependancies, integration:
+
+This phase needs phase 1 to be largely complete, and at least the non-APIs
+items must be complete. It also depends on NT kernel to provide LDT mgmt
+APIs and 16 bit context switch. If an LE loader is not provided by the
+previous phase, then the NE loader becomes a major job.
+
+Task #eng #week Comments
+---------------------------------------------------
+16->32 thunks 1 5
+NE Loader 1 8 (given we did the LE loader in phase 1)
+16B context switch 1 1 Mostly integration with NT.
+LDT management 1 3
+16B mem mgmt 1 10
+VIO APIs 1 30 (?)
+MOU 1 10 (?)
+KBD 1 10 (?)
+MON 1 5 (?)
+16B semaphores 1 4
+Signal APIs 1 4
+
+Test+Integration 2 90
+
+Total 3-4 180 (~5MY)
+
+Serialization notes:
+
+The first four items must be completed before any 16 bit program
+can be loaded.Thunks should be farely easy and can start way ahead
+the rest of the phase. We will take the WIN/DOS thunk compiler.
+The API items are mostly independent of each other, although MM and
+SEM should be done first, to get simple CRT apps running.
+
+Grouping:
+
+Loader work is an independant task. It makes sense to have the same
+group (size 1) do the LDT mgmt and 16 bit context switch.
+The VIO/KBD/MOU/MON work should be done by a group that will expertize
+in it (upto 2 developers).
+Signals, Sem and MM could be done be another group (size 1).
+
+
+7.3 Phase 3 - PM, split screen groups:
+-------------------------------------
+
+Design, dependencies, integration:
+
+PMGRE:
+------
+Implement, from scratch, a layer that provides OS2 2.0 PMGRE interface
+(defined by pmsrc\pmgre\devtable.cxx), that sits on top of WIN32 GDI.
+
+PMGPI:
+------
+transform the PMGPI IBM code of Cruiser into the NT environment, flatten
+it and make it portable.
+
+PMWIN:
+------
+write a low-level input processing thread that will process WIN32 WM
+messages coming into the PM virtual desktop, and feed them into a PM
+system queue, to mimiq the native PM environment.
+Impose exception handling to make PMWIN robust enough to sit in the
+WIN32 server process.
+
+Then take a breath, and integrate the whole chunk of PPM PMWIN code
+to run with the new GRE, GPI, input, GDI, DDI - all under one address
+space (i.e. client test app linked in).
+
+PM Utilities:
+-------------
+ - PMPRINT - don't do.
+ - PMCPL - remove stuff that conflicts with the real desktop, port
+ and test the stuff relevant to a virtual desktop.
+ - PMSHELL - port. cleanup redundant stuff.
+ - OS2SM - port and cleanup (need to look at what was done for PPM).
+ - PMFILE - don't do.
+ - PMEXEC - port.
+
+
+Task #eng #week Comments
+---------------------------------------------------
+Write PMGRE/GDI
+port GPI
+Complete PMWIN
+Hook input USER Recongize the 'PM session', SPB.
+GDI2PM callback PM-flavor DC, VisRgn.
+16->32 thunks
+Client caching
+NLS/DBCS
+Configuration (os2sys.ini, os2.ini).
+PMSHELL
+PMCPL
+PMEXEC
+Test+Integration
+
+Total
+
+Serialization notes:
+
+Grouping:
+
+
+7.4 Phase 4 - PM, joint screen groups:
+-------------------------------------
+
+TBS
+
+8 Open Issues:
+--------------
+* need to construct a table of all 'platforms' and the relative
+compatibility to be achieved on them.
+* spooler APIs: do we need to support?
+* the PPM layer is implemented on top of NT (not on top of OS/2 base
+ APIs). Will there be a mismatch when apps are going to use both PM
+ and OS2 base APIs?
+* Can we setup the WIN32 file manager to handle both environments?
+ (Run, EAs).
diff --git a/private/os2/doc/pmnt.doc b/private/os2/doc/pmnt.doc
new file mode 100644
index 000000000..cac7fdb34
--- /dev/null
+++ b/private/os2/doc/pmnt.doc
Binary files differ
diff --git a/private/os2/doc/pmntover.doc b/private/os2/doc/pmntover.doc
new file mode 100644
index 000000000..d0c1d0880
--- /dev/null
+++ b/private/os2/doc/pmntover.doc
Binary files differ
diff --git a/private/os2/doc/pownt.old b/private/os2/doc/pownt.old
new file mode 100644
index 000000000..ac323e265
--- /dev/null
+++ b/private/os2/doc/pownt.old
Binary files differ
diff --git a/private/os2/doc/pownt.ppt b/private/os2/doc/pownt.ppt
new file mode 100644
index 000000000..bdd13d6be
--- /dev/null
+++ b/private/os2/doc/pownt.ppt
Binary files differ
diff --git a/private/os2/doc/relnotes.doc b/private/os2/doc/relnotes.doc
new file mode 100644
index 000000000..1efdabdf4
--- /dev/null
+++ b/private/os2/doc/relnotes.doc
Binary files differ
diff --git a/private/os2/doc/w32thk.doc b/private/os2/doc/w32thk.doc
new file mode 100644
index 000000000..89bb9a921
--- /dev/null
+++ b/private/os2/doc/w32thk.doc
Binary files differ
diff --git a/private/os2/inc/conapi.h b/private/os2/inc/conapi.h
new file mode 100644
index 000000000..909e6fb6c
--- /dev/null
+++ b/private/os2/inc/conapi.h
@@ -0,0 +1,404 @@
+#ifndef NOGDI
+
+typedef struct _CONSOLE_GRAPHICS_BUFFER_INFO {
+ DWORD dwBitMapInfoLength;
+ LPBITMAPINFO lpBitMapInfo;
+ DWORD dwUsage;
+ HANDLE hMutex;
+ PVOID lpBitMap;
+} CONSOLE_GRAPHICS_BUFFER_INFO, *PCONSOLE_GRAPHICS_BUFFER_INFO;
+
+#endif // NOGDI
+
+#define CONSOLE_GRAPHICS_BUFFER 2
+
+BOOL
+WINAPI
+InvalidateConsoleDIBits(
+ HANDLE hConsoleOutput,
+ PSMALL_RECT lpRect
+ );
+
+#define SYSTEM_ROOT_CONSOLE_EVENT 3
+
+VOID
+WINAPI
+SetLastConsoleEventActive( VOID );
+
+#define VDM_HIDE_WINDOW 1
+#define VDM_IS_ICONIC 2
+#define VDM_CLIENT_RECT 3
+#define VDM_CLIENT_TO_SCREEN 4
+#define VDM_SCREEN_TO_CLIENT 5
+
+BOOL
+WINAPI
+VDMConsoleOperation(
+ DWORD iFunction,
+ LPVOID lpData
+ );
+
+typedef struct _CONSOLE_FONT_INFO {
+ DWORD nFont;
+ COORD dwFontSize;
+} CONSOLE_FONT_INFO, *PCONSOLE_FONT_INFO;
+
+
+BOOL
+WINAPI
+SetConsoleFont(
+ HANDLE hConsoleOutput,
+ DWORD nFont
+ );
+
+BOOL
+WINAPI
+GetCurrentConsoleFont(
+ HANDLE hConsoleOutput,
+ BOOL bMaximumWindow,
+ PCONSOLE_FONT_INFO lpConsoleCurrentFont
+ );
+
+COORD
+WINAPI
+GetConsoleFontSize(
+ HANDLE hConsoleOutput,
+ DWORD nFont
+ );
+
+DWORD
+WINAPI
+GetConsoleFontInfo(
+ HANDLE hConsoleOutput,
+ BOOL bMaximumWindow,
+ DWORD nLength,
+ PCONSOLE_FONT_INFO lpConsoleFontInfo
+ );
+
+DWORD
+WINAPI
+GetNumberOfConsoleFonts(
+ VOID
+ );
+
+BOOL
+WINAPI
+SetConsoleCursor(
+ HANDLE hConsoleOutput,
+ HCURSOR hCursor
+ );
+
+int
+WINAPI
+ShowConsoleCursor(
+ HANDLE hConsoleOutput,
+ BOOL bShow
+ );
+
+HMENU
+ConsoleMenuControl(
+ HANDLE hConsoleOutput,
+ UINT dwCommandIdLow,
+ UINT dwCommandIdHigh
+ );
+
+BOOL
+SetConsolePalette(
+ HANDLE hConsoleOutput,
+ HPALETTE hPalette,
+ UINT dwUsage
+ );
+
+#define CONSOLE_FULLSCREEN_MODE 1
+#define CONSOLE_WINDOWED_MODE 2
+
+BOOL
+SetConsoleDisplayMode(
+ HANDLE hConsoleOutput,
+ DWORD dwFlags,
+ PCOORD lpNewScreenBufferDimensions
+ );
+
+BOOL
+RegisterConsoleVDM(
+ IN BOOL bRegister,
+ IN HANDLE hStartHardwareEvent,
+ IN HANDLE hEndHardwareEvent,
+ IN LPWSTR lpStateSectionName,
+ IN DWORD dwStateSectionNameLength,
+ OUT LPDWORD lpStateLength,
+ OUT PVOID *lpState,
+ IN LPWSTR lpVDMBufferSectionName,
+ IN DWORD dwVDMBufferSectionNameLength,
+ COORD VDMBufferSize OPTIONAL,
+ OUT PVOID *lpVDMBuffer
+ );
+
+BOOL
+GetConsoleHardwareState(
+ HANDLE hConsoleOutput,
+ PCOORD lpResolution,
+ PCOORD lpFontSize
+ );
+
+BOOL
+SetConsoleHardwareState(
+ HANDLE hConsoleOutput,
+ COORD dwResolution,
+ COORD dwFontSize
+ );
+
+#define CONSOLE_FULLSCREEN 1 // fullscreen console
+#define CONSOLE_FULLSCREEN_HARDWARE 2 // console owns the hardware
+
+BOOL
+GetConsoleDisplayMode(
+ LPDWORD lpModeFlags
+ );
+
+
+
+//
+// aliasing apis
+//
+
+BOOL
+AddConsoleAliasA(
+ IN LPSTR Source,
+ IN LPSTR Target,
+ IN LPSTR ExeName
+ );
+BOOL
+AddConsoleAliasW(
+ IN LPWSTR Source,
+ IN LPWSTR Target,
+ IN LPWSTR ExeName
+ );
+#ifdef UNICODE
+#define AddConsoleAlias AddConsoleAliasW
+#else
+#define AddConsoleAlias AddConsoleAliasA
+#endif // !UNICODE
+
+DWORD
+GetConsoleAliasA(
+ IN LPSTR Source,
+ OUT LPSTR TargetBuffer,
+ IN DWORD TargetBufferLength,
+ IN LPSTR ExeName
+ );
+DWORD
+GetConsoleAliasW(
+ IN LPWSTR Source,
+ OUT LPWSTR TargetBuffer,
+ IN DWORD TargetBufferLength,
+ IN LPWSTR ExeName
+ );
+#ifdef UNICODE
+#define GetConsoleAlias GetConsoleAliasW
+#else
+#define GetConsoleAlias GetConsoleAliasA
+#endif // !UNICODE
+
+DWORD
+GetConsoleAliasesLengthA(
+ IN LPSTR ExeName
+ );
+DWORD
+GetConsoleAliasesLengthW(
+ IN LPWSTR ExeName
+ );
+#ifdef UNICODE
+#define GetConsoleAliasesLength GetConsoleAliasesLengthW
+#else
+#define GetConsoleAliasesLength GetConsoleAliasesLengthA
+#endif // !UNICODE
+
+DWORD
+GetConsoleAliasExesLengthA( VOID );
+DWORD
+GetConsoleAliasExesLengthW( VOID );
+#ifdef UNICODE
+#define GetConsoleAliasExesLength GetConsoleAliasExesLengthW
+#else
+#define GetConsoleAliasExesLength GetConsoleAliasExesLengthA
+#endif // !UNICODE
+
+DWORD
+GetConsoleAliasesA(
+ OUT LPSTR AliasBuffer,
+ IN DWORD AliasBufferLength,
+ IN LPSTR ExeName
+ );
+DWORD
+GetConsoleAliasesW(
+ OUT LPWSTR AliasBuffer,
+ IN DWORD AliasBufferLength,
+ IN LPWSTR ExeName
+ );
+#ifdef UNICODE
+#define GetConsoleAliases GetConsoleAliasesW
+#else
+#define GetConsoleAliases GetConsoleAliasesA
+#endif // !UNICODE
+
+DWORD
+GetConsoleAliasExesA(
+ OUT LPSTR ExeNameBuffer,
+ IN DWORD ExeNameBufferLength
+ );
+DWORD
+GetConsoleAliasExesW(
+ OUT LPWSTR ExeNameBuffer,
+ IN DWORD ExeNameBufferLength
+ );
+#ifdef UNICODE
+#define GetConsoleAliasExes GetConsoleAliasExesW
+#else
+#define GetConsoleAliasExes GetConsoleAliasExesA
+#endif // !UNICODE
+
+VOID
+ExpungeConsoleCommandHistoryA(
+ IN LPSTR ExeName
+ );
+VOID
+ExpungeConsoleCommandHistoryW(
+ IN LPWSTR ExeName
+ );
+#ifdef UNICODE
+#define ExpungeConsoleCommandHistory ExpungeConsoleCommandHistoryW
+#else
+#define ExpungeConsoleCommandHistory ExpungeConsoleCommandHistoryA
+#endif // !UNICODE
+
+BOOL
+SetConsoleNumberOfCommandsA(
+ IN DWORD Number,
+ IN LPSTR ExeName
+ );
+BOOL
+SetConsoleNumberOfCommandsW(
+ IN DWORD Number,
+ IN LPWSTR ExeName
+ );
+#ifdef UNICODE
+#define SetConsoleNumberOfCommands SetConsoleNumberOfCommandsW
+#else
+#define SetConsoleNumberOfCommands SetConsoleNumberOfCommandsA
+#endif // !UNICODE
+
+DWORD
+GetConsoleCommandHistoryLengthA(
+ IN LPSTR ExeName
+ );
+DWORD
+GetConsoleCommandHistoryLengthW(
+ IN LPWSTR ExeName
+ );
+#ifdef UNICODE
+#define GetConsoleCommandHistoryLength GetConsoleCommandHistoryLengthW
+#else
+#define GetConsoleCommandHistoryLength GetConsoleCommandHistoryLengthA
+#endif // !UNICODE
+
+DWORD
+GetConsoleCommandHistoryA(
+ OUT LPSTR Commands,
+ IN DWORD CommandBufferLength,
+ IN LPSTR ExeName
+ );
+DWORD
+GetConsoleCommandHistoryW(
+ OUT LPWSTR Commands,
+ IN DWORD CommandBufferLength,
+ IN LPWSTR ExeName
+ );
+#ifdef UNICODE
+#define GetConsoleCommandHistory GetConsoleCommandHistoryW
+#else
+#define GetConsoleCommandHistory GetConsoleCommandHistoryA
+#endif // !UNICODE
+
+#define CONSOLE_OVERSTRIKE 1
+
+BOOL
+SetConsoleCommandHistoryMode(
+ IN DWORD Flags
+ );
+
+#define CONSOLE_NOSHORTCUTKEY 0 /* no shortcut key */
+#define CONSOLE_ALTTAB 1 /* Alt + Tab */
+#define CONSOLE_ALTESC (1 << 1) /* Alt + Escape */
+#define CONSOLE_ALTSPACE (1 << 2) /* Alt + Space */
+#define CONSOLE_ALTENTER (1 << 3) /* Alt + Enter */
+#define CONSOLE_ALTPRTSC (1 << 4) /* Alt Print screen */
+#define CONSOLE_PRTSC (1 << 5) /* Print screen */
+#define CONSOLE_CTRLESC (1 << 6) /* Ctrl + Escape */
+
+typedef struct _APPKEY {
+ WORD Modifier;
+ WORD ScanCode;
+} APPKEY, *LPAPPKEY;
+
+#define CONSOLE_MODIFIER_RSHIFT 0x0001 // Right shift key
+#define CONSOLE_MODIFIER_LSHIFT 0x0002 // Left shift key
+#define CONSOLE_MODIFIER_CONTROL 0x0004 // Either Control shift key
+#define CONSOLE_MODIFIER_ALT 0x0008 // Either Alt shift key
+#define CONSOLE_MODIFIER_SCRLOCK 0x0010 // Scroll lock active
+#define CONSOLE_MODIFIER_NUMLOCK 0x0020 // Num lock active
+#define CONSOLE_MODIFIER_CAPSLOCK 0x0040 // Caps lock active
+#define CONSOLE_MODIFIER_INSERT 0x0080 // Insert active
+#define CONSOLE_MODIFIER_EXTENDED 0x0100 // Extended K/B shift
+#define CONSOLE_MODIFIER_HOLD 0x0200 // Ctrl-Num-Lock/Pause active
+#define CONSOLE_MODIFIER_LALT 0x0400 // Left Alt key is down
+#define CONSOLE_MODIFIER_RALT 0x0800 // Right Alt key is down
+#define CONSOLE_MODIFIER_LCTRL 0x1000 // Left Ctrl key is down
+#define CONSOLE_MODIFIER_RCTRL 0x2000 // Right Ctrl key is down
+
+BOOL
+SetConsoleKeyShortcuts(
+ BOOL bSet,
+ BYTE bReserveKeys,
+ LPAPPKEY lpAppKeys,
+ DWORD dwNumAppKeys
+ );
+
+BOOL
+SetConsoleMenuClose(
+ BOOL bEnable
+ );
+
+#define CONSOLE_ADD_SUBST 1
+#define CONSOLE_REMOVE_SUBST 2
+#define CONSOLE_QUERY_SUBST 3
+
+BOOL
+ConsoleSubst(
+ IN DWORD dwDriveNumber,
+ IN DWORD dwFlag,
+ IN OUT LPWSTR lpPhysicalDriveBuffer,
+ IN DWORD dwPhysicalDriveBufferLength
+ );
+
+BOOL
+WINAPI
+WriteConsoleInputVDMA(
+ HANDLE hConsoleInput,
+ PINPUT_RECORD lpBuffer,
+ DWORD nLength,
+ LPDWORD lpNumberOfEventsWritten
+ );
+BOOL
+WINAPI
+WriteConsoleInputVDMW(
+ HANDLE hConsoleInput,
+ PINPUT_RECORD lpBuffer,
+ DWORD nLength,
+ LPDWORD lpNumberOfEventsWritten
+ );
+#ifdef UNICODE
+#define WriteConsoleInputVDM WriteConsoleInputVDMW
+#else
+#define WriteConsoleInputVDM WriteConsoleInputVDMA
+#endif // !UNICODE
diff --git a/private/os2/inc/conrqust.h b/private/os2/inc/conrqust.h
new file mode 100644
index 000000000..4f3044834
--- /dev/null
+++ b/private/os2/inc/conrqust.h
@@ -0,0 +1,162 @@
+
+#define NTOS2_ONLY
+#include "sesport.h"
+#include "os2err.h"
+
+/*
+ * Routines defined in conrqust.c to send requests to OS2.EXE
+ */
+
+APIRET
+SendCtrlConsoleRequest(
+ IN OUT PSCREQUESTMSG Request,
+ IN PCH OutBuffer,
+ OUT PCH InBuffer,
+ IN HANDLE hSem
+ );
+
+APIRET
+Od2CallRootProcessThruLPC(
+ IN OUT PSCREQUESTMSG Request,
+ IN PCH OutBuffer,
+ OUT PCH InBuffer,
+ IN HANDLE hSem,
+ IN ULONG ArgLength
+ );
+
+APIRET
+Od2LockCtrlRequestDataBuffer();
+
+VOID
+Od2UnlockCtrlRequestDataBuffer();
+
+APIRET
+Od2RemoveConsoleThread();
+
+APIRET
+Od2RestartConsoleThread();
+
+APIRET
+Od2AddWin32ChildProcess();
+
+APIRET
+Od2RemoveWin32ChildProcess();
+
+/*
+ * Routines in "VIO" (vio/kbd/mou) that are called from dllremot.c or
+ * dllmisc.c(DosDevIOCtl)
+ */
+
+APIRET KbdOpenLogHandle(PHANDLE);
+APIRET RemoteCloseHandle(HANDLE Handle);
+NTSTATUS CtrlCloseHandle(IN HANDLE hFile);
+APIRET KbdRead(IN PFILE_HANDLE hFileRecord, OUT PCH Buffer, IN ULONG Length,
+ OUT PULONG BytesRead, IN KBDREQUESTNUMBER RequestType);
+APIRET VioWrite(IN PFILE_HANDLE hFileRecord, IN PCH Buffer, IN ULONG Length,
+ OUT PULONG BytesWritten, IN VIOREQUESTNUMBER RequestType);
+APIRET DevMouOpen(OUT PHANDLE FileHandle);
+APIRET DevMouClose();
+APIRET KbdDupLogHandle( IN HANDLE hKbd);
+APIRET OpenLVBsection(VOID);
+APIRET Od2WaitForSingleObject(IN HANDLE Handle, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL);
+
+APIRET DosMonReg( IN ULONG hMon, IN PBYTE pInBuffer, IN PBYTE pOutBuffer,
+ IN ULONG fPosition, IN ULONG usIndex);
+APIRET KbdCharIn(OUT PKBDKEYINFO Info, IN ULONG Wait, IN ULONG hKbd);
+APIRET KbdPeek(OUT PKBDKEYINFO Info, IN ULONG hKbd);
+APIRET KbdGetFocus( IN ULONG Wait, IN ULONG hKbd);
+APIRET MouDrawPtr(IN ULONG hMou);
+APIRET MouGetDevStatus(OUT PUSHORT DevStatus, IN ULONG hMou);
+APIRET MouGetEventMask(OUT PUSHORT EventMask, IN ULONG hMou);
+APIRET MouGetNumButtons(OUT PUSHORT NumButtons, IN ULONG hMou);
+APIRET MouGetNumMickeys(OUT PUSHORT NumMickeys, IN ULONG hMou);
+APIRET MouGetNumQueEl(OUT PMOUQUEINFO NumQueEl, IN ULONG hMou);
+APIRET MouGetPtrPos(OUT PPTRLOC PtrPos, IN ULONG hMou);
+APIRET MouGetPtrShape(OUT PBYTE PtrMask, OUT PPTRSHAPE PtrShape, IN ULONG hMou);
+APIRET MouGetScaleFact(OUT PSCALEFACT ScaleFact, IN ULONG hMou);
+APIRET MouReadEventQue(OUT PMOUEVENTINFO MouEvent, IN PUSHORT Wait, IN ULONG hMou);
+APIRET MouRemovePtr(IN PNOPTRRECT Rect, IN ULONG hMou);
+APIRET MouSetDevStatus(IN PUSHORT DevStatus, IN ULONG hMou);
+APIRET MouSetEventMask(IN PUSHORT EventMask, IN ULONG hMou);
+APIRET MouSetPtrPos(IN PPTRLOC PtrPos, IN ULONG hMou);
+APIRET MouSetPtrShape(IN PBYTE PtrMask, IN PPTRSHAPE PtrShape, IN ULONG hMou);
+APIRET MouSetScaleFact(IN PSCALEFACT ScaleFact, IN ULONG hMou);
+
+APIRET KbdGetCpId(OUT PUSHORT pIdCodePage, IN ULONG hKbd);
+APIRET KbdGetInputMode(OUT PBYTE pInputMode, IN ULONG hKbd);
+APIRET KbdGetInterimFlag(OUT PBYTE pInterimFlag, IN ULONG hKbd);
+APIRET KbdGetKbdType(OUT PUSHORT pKbdType, IN ULONG hKbd);
+APIRET KbdGetHotKey(IN PUSHORT pParm, OUT PBYTE pHotKey, IN ULONG hKbd);
+APIRET KbdGetShiftState(OUT PBYTE pvData, IN ULONG hDev);
+APIRET KbdSetInputMode(IN BYTE InputMode, IN ULONG hDev);
+APIRET KbdSetInterimFlag(IN BYTE InterimFlag, IN ULONG hDev);
+APIRET KbdSetShiftState(OUT PBYTE pvData, IN ULONG hDev);
+APIRET KbdSetTypamaticRate(IN PBYTE pRateDelay, IN ULONG hDev);
+APIRET MouAllowPtrDraw(IN ULONG hMou);
+APIRET MouScreenSwitch(IN PBYTE pScreenGroup, IN ULONG hMou);
+
+/*
+ * pointer to section of all-session-group parm
+ */
+
+POS2_SES_GROUP_PARMS SesGrp;
+ULONG SesGrpId;
+
+/*
+ * parameters from os2.exe ports for Vio/Kbd/Mou/Mon/Net APIs
+ */
+
+HANDLE CtrlPortHandle;
+
+PVOID VioBuff; // LVB buffer for VIO (after got selector)
+
+extern HANDLE FocusSemaphore;
+extern HANDLE CtrlDataSemaphore;
+extern HANDLE KbdDataSemaphore;
+extern HANDLE MouDataSemaphore;
+extern HANDLE PopUpSemaphore;
+extern HANDLE ScreenLockSemaphore;
+extern HANDLE PauseEvent;
+extern HANDLE Od2VioWriteSemHandle;
+
+USHORT MoniorOpenedForThisProcess;
+
+#if DBG
+
+//
+// conrqust.c
+//
+
+VOID
+AcquireStdHandleLock(
+ IN PSZ CallingRoutine
+ );
+
+VOID
+ReleaseStdHandleLock(
+ IN PSZ CallingRoutine
+ );
+
+#else
+VOID
+AcquireStdHandleLock(
+ );
+
+VOID
+ReleaseStdHandleLock(
+ );
+#endif
+
+
+#if DBG
+#define UNSUPPORTED_API() \
+ DbgPrint("%s Not Implemented Yet\n", FuncName); \
+ /* DbgUserBreakPoint(); */ \
+ return NO_ERROR;
+#else
+#define UNSUPPORTED_API() \
+ /* DbgUserBreakPoint(); */ \
+ return NO_ERROR;
+#endif
+
+
diff --git a/private/os2/inc/dllcopy.h b/private/os2/inc/dllcopy.h
new file mode 100644
index 000000000..0db2e1431
--- /dev/null
+++ b/private/os2/inc/dllcopy.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * DOSCOPY.H - Header file for the OS/2 DOSCOPY API function
+ *
+ * This file contains declarations and definitons for use by
+ * the DOSCOPY function, its helper functions, and the test
+ * functions.
+ *
+ * NOTES:
+ *
+ * 1) The contents of this file are intended for internal use only,
+ * although it may be appropriate to export parts of it to other
+ * header files.
+ *
+ * Created Oct 88, Danny Glasser (microsoft!dannygl)
+ */
+
+/* Object types */
+#define COT_FILE 1 /* Object is a file */
+#define COT_DIRECTORY 2 /* Object is a directory */
+#define COT_PARENT 3 /* Object does not exist but its parent does
+ (and is a directory) */
+#define COT_DEVICE 4 /* Object is a character device */
+#define COT_OTHER 5 /* Object is none of the above */
+
+/* Info flags for copy_file() - FOR INTERNAL USE ONLY */
+#define CFF_SOURCE_IS_FILE 0x0001 /* Source is a file */
+#define CFF_TARGET_IS_FILE 0x0002 /* Target is a file */
+#define CFF_TARGET_FILE_EXISTS 0x0004 /* Target file already exists */
+
+/* Various constants */
+#define CURRENT_DIRECTORY "." /* Shorthand for current
+ directory */
+#define PARENT_DIRECTORY ".." /* Shorthand for parent
+ directory */
diff --git a/private/os2/inc/dlldbcs.h b/private/os2/inc/dlldbcs.h
new file mode 100644
index 000000000..b0eac98f5
--- /dev/null
+++ b/private/os2/inc/dlldbcs.h
@@ -0,0 +1,48 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ dlldbcs.h
+
+Abstract:
+
+ Prototypes for OS/2 subsystem internal multibyte string functions
+
+Author:
+
+ Akihiko Sasaki (V-AkihiS) 23-June-1993
+
+Revision History:
+
+--*/
+
+#ifdef DBCS
+
+#include <string.h>
+
+unsigned char * _CRTAPI1
+Od2MultiByteStrchr(
+ const unsigned char *,
+ unsigned short
+ );
+
+unsigned char * _CRTAPI1
+Od2MultiByteStrrchr(
+ const unsigned char *,
+ unsigned short
+ );
+
+unsigned char * _CRTAPI1
+Od2MultiByteStrstr(
+ const unsigned char *,
+ const unsigned char *
+ );
+
+unsigned char * _CRTAPI1
+Od2MultiByteStrpbrk(
+ const unsigned char *,
+ const unsigned char *
+ );
+#endif
diff --git a/private/os2/inc/dllfile.h b/private/os2/inc/dllfile.h
new file mode 100644
index 000000000..0a9efe668
--- /dev/null
+++ b/private/os2/inc/dllfile.h
@@ -0,0 +1,69 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dllfile.h
+
+Abstract:
+
+ This module defines the OS/2 subsystem I/O data structures for the
+ DLL.
+
+Author:
+
+ Therese Stowell (thereses) 17-Dec-1989
+
+Revision History:
+
+--*/
+
+#include "os2file.h"
+//
+// File System variables
+//
+// per-process current directory information for current drive
+//
+CURRENT_DIRECTORY_INFORMATION Od2CurrentDirectory;
+
+// per-process default drive
+
+// BUGBUG in InitDLL, set CurrentDisk to boot disk
+
+ULONG Od2CurrentDisk;
+
+// file handle table variables. initially, HandleTable points to
+// SmallHandleTable. most processes won't use more than 20 handles.
+// if the handle table is full, space in the heap is allocated and the
+// SmallHandleTable is copied over.
+
+PFILE_HANDLE HandleTable; // pointer to handle table
+
+ULONG HandleTableLength; // number of entries in handle table
+
+FILE_HANDLE SmallHandleTable[INITIALFILEHANDLES]; // initial handle table
+
+BOOLEAN VerifyFlag; // variable used by DosSet/QueryVerify
+
+
+// search handle table variables. this size of this table is managed the
+// same way as the file handle table, except the table is grown when a search
+// handle allocation fails, not when the user specifies it.
+
+PSEARCH_RECORD *SearchHandleTable; // pointer to search handle table
+
+ULONG SearchHandleTableLength; // number of entries in search handle table
+
+PSEARCH_RECORD SmallSearchHandleTable[INITIAL_SEARCH_HANDLES]; // initial search handle table
+
+//
+// the client keeps two tables which include information about the current
+// directories on the different drives.
+// Od2DirHandles holds for each drive a handle to the current directory.
+// Od2DirHandlesIsValid holds for each drive a flag indicating whether the
+// current directory on it was initialized or not.
+//
+
+HANDLE Od2DirHandles[MAX_DRIVES];
+BOOLEAN Od2DirHandlesIsValid[MAX_DRIVES];
diff --git a/private/os2/inc/iovector.h b/private/os2/inc/iovector.h
new file mode 100644
index 000000000..6af7da38b
--- /dev/null
+++ b/private/os2/inc/iovector.h
@@ -0,0 +1,528 @@
+
+/* Type - OPEN - SET - QUERY - CLOSE - DUP_ - READ - WRITE
+ STATE TYPE HANDLE
+ -----------------------------------------------------------------
+ Nul - X - 1 - DEV - DEV - DEV - X - X
+ Con - X - 1 - DEV - DEV - DEV - X - SCR
+ Com - X - 1 - DEV - DEV - DEV - 2 - 2
+ Lpt - X - 1 - DEV - DEV - DEV - 2 - 2
+ Kbd - X - 1 - DEV - X - X - X - NUL
+ Mouse - X - 1 - DEV - X - X - 2 - 2
+ Clock - X - 1 - DEV - DEV - DEV - 2 - 2
+ Screen - X - 1 - DEV - DEV - DEV - NUL - X
+ Pointer - X - 1 - DEV - DEV - DEV - 2 - 2
+ File - X - X - X - X - X - X - X
+ Pipe - FIL - FIL - FIL - FIL - FIL - FIL - X
+ Device - FIL - 1 - X - FIL - FIL - FIL - FIL
+ Remote - - X - X - X - X - X - X
+ Monitor - - 3 - 3 - 3 - 3 - 2 - 2
+
+ other: 1 - NonFile, 2 - Tmp, 3 - NoSupp
+*/
+
+
+APIRET
+NulOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ );
+
+APIRET
+ConOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ );
+
+APIRET
+ComOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ );
+
+APIRET
+LptOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ );
+
+APIRET
+KbdOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ );
+
+APIRET
+MouseOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ );
+
+APIRET
+ClockOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ );
+
+APIRET
+ScreenOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ );
+
+APIRET
+PointerOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ );
+
+APIRET
+FileOpenRoutine(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ );
+
+APIRET
+NonFileSetHandleStateRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ IN ULONG OpenMode
+ );
+
+APIRET
+FileSetHandleStateRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ IN ULONG OpenMode
+ );
+
+APIRET
+RemoteSetHandleStateRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ IN ULONG OpenMode
+ );
+
+APIRET
+NoSuppSetHandleStateRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ IN ULONG OpenMode
+ );
+
+APIRET
+FileQueryHTypeRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PULONG HandleType,
+ OUT PULONG DeviceFlags
+ );
+
+APIRET
+DeviceQueryHTypeRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PULONG HandleType,
+ OUT PULONG DeviceFlags
+ );
+
+APIRET
+RemoteQueryHTypeRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PULONG HandleType,
+ OUT PULONG DeviceFlags
+ );
+
+APIRET
+NoSuppQueryHTypeRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PULONG HandleType,
+ OUT PULONG DeviceFlags
+ );
+
+APIRET
+KbdCloseRoutine(
+ IN PFILE_HANDLE hFileRecord
+ );
+
+APIRET
+MouseCloseRoutine(
+ IN PFILE_HANDLE hFileRecord
+ );
+
+APIRET
+FileCloseRoutine(
+ IN PFILE_HANDLE hFileRecord
+ );
+
+APIRET
+DeviceCloseRoutine(
+ IN PFILE_HANDLE hFileRecord
+ );
+
+APIRET
+RemoteCloseRoutine(
+ IN PFILE_HANDLE hFileRecord
+ );
+
+APIRET
+NoSuppCloseRoutine(
+ IN PFILE_HANDLE hFileRecord
+ );
+
+APIRET
+ComCloseRoutine(
+ IN PFILE_HANDLE hFileRecord
+ );
+
+APIRET
+ComDupHandleRoutine(
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ );
+
+APIRET
+KbdDupHandleRoutine(
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ );
+
+APIRET
+MouseDupHandleRoutine(
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ );
+
+APIRET
+FileDupHandleRoutine(
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ );
+
+APIRET
+DeviceDupHandleRoutine(
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ );
+
+APIRET
+RemoteDupHandleRoutine(
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ );
+
+APIRET
+NoSuppDupHandleRoutine(
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ );
+
+APIRET
+NulReadRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ );
+
+APIRET
+ConReadRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ );
+
+APIRET
+KbdReadRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ );
+
+APIRET
+FileReadRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ );
+
+APIRET
+RemoteReadRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ );
+
+APIRET
+TmpReadRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ );
+
+APIRET
+ComReadRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ );
+
+APIRET
+NulWriteRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ );
+
+APIRET
+ScreenWriteRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ );
+
+APIRET
+FileWriteRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ );
+
+APIRET
+RemoteWriteRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ );
+
+APIRET
+TmpWriteRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ );
+
+APIRET
+ComWriteRoutine(
+ IN PFILE_HANDLE hFileRecord,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ );
+
+//
+// This function is called to open an object.
+//
+
+typedef
+APIRET
+(*POS2OPEN_ROUTINE) (
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ OUT PULONG ActionTaken,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ );
+
+//
+// This function is called to set the state of a handle (inherited,
+// writethrough, etc)
+//
+
+typedef
+APIRET
+(*POS2SET_HANDLE_STATE_ROUTINE) (
+ IN PFILE_HANDLE hFileRecord,
+ IN ULONG OpenMode
+ );
+
+//
+// This function is called to query the type of a handle (device, file, etc)
+//
+
+typedef
+APIRET
+(*POS2QUERY_HANDLE_TYPE_ROUTINE) (
+ IN PFILE_HANDLE hFileRecord,
+ OUT PULONG HandleType,
+ OUT PULONG DeviceFlags
+ );
+
+//
+// This function is called to close a handle. it doesn't free the handle.
+//
+
+typedef
+APIRET
+(*POS2CLOSE_ROUTINE) (
+ IN PFILE_HANDLE hFileRecord
+ );
+
+//
+// This function is called to do a handle duplicate operation
+//
+
+typedef
+APIRET
+(*POS2DUP_HANDLE_ROUTINE) (
+ IN PFILE_HANDLE hOldFileRecord,
+ IN PFILE_HANDLE hNewFileRecord
+ );
+
+//
+// This function is called to do a read operation
+//
+
+typedef
+APIRET
+(*POS2READ_ROUTINE) (
+ IN PFILE_HANDLE hFileRecord,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ );
+
+//
+// This function is called to do a write operation
+//
+
+typedef
+APIRET
+(*POS2WRITE_ROUTINE) (
+ IN PFILE_HANDLE hFileRecord,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ );
+
+typedef struct _OS2IO_VECTORS {
+ POS2OPEN_ROUTINE OpenRoutine;
+ POS2SET_HANDLE_STATE_ROUTINE SetHandleStateRoutine;
+ POS2QUERY_HANDLE_TYPE_ROUTINE QueryHandleTypeRoutine;
+ POS2CLOSE_ROUTINE CloseRoutine;
+ POS2DUP_HANDLE_ROUTINE DupHandleRoutine;
+ POS2READ_ROUTINE ReadRoutine;
+ POS2WRITE_ROUTINE WriteRoutine;
+} OS2IO_VECTORS, *POS2IO_VECTORS;
diff --git a/private/os2/inc/ldrdbg.h b/private/os2/inc/ldrdbg.h
new file mode 100644
index 000000000..58f3765b6
--- /dev/null
+++ b/private/os2/inc/ldrdbg.h
@@ -0,0 +1,40 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ldrdbg.h
+
+Abstract:
+
+ Debug constants
+
+Author:
+
+ Beni Lavi (BeniL) 5-Nov-92
+
+Revision History:
+
+--*/
+
+#if DBG
+
+#define OL2_DEBUG_TRACE 0x00000001
+#define OL2_DEBUG_MEMORY 0x00000002
+#define OL2_DEBUG_MTE 0x00000004
+#define OL2_DEBUG_FIXUP 0x00000008
+
+ULONG Ol2Debug;
+#define IF_OL2_DEBUG( ComponentFlag ) \
+ if (Ol2Debug & (OL2_DEBUG_ ## ComponentFlag))
+
+#else
+
+#define IF_OL2_DEBUG( ComponentFlag ) if (FALSE)
+
+#endif
+
+
+
+
diff --git a/private/os2/inc/ldrtabs.h b/private/os2/inc/ldrtabs.h
new file mode 100644
index 000000000..2d5a972f0
--- /dev/null
+++ b/private/os2/inc/ldrtabs.h
@@ -0,0 +1,444 @@
+UCHAR acsenttab[]=
+{
+0x1,0x1,0x3,0xb8,0x4,0x0,0x0
+};
+UCHAR acsrestab[]=
+{
+0x7,0x41,0x43,0x53,0x4e,0x45,0x54,0x42,0x0,0x0,0x7,0x4e,0x45,0x54,0x42,0x49,
+0x4f,0x53,0x1,0x0,0x0
+};
+UCHAR acsnrestab[]=
+{
+0xb,0x61,0x63,0x73,0x6e,0x65,0x74,0x62,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+};
+UCHAR kbdenttab[]=
+{
+0x1,0x1,0x3,0xd0,0x3,0x1,0x0,0x3,0x1,0x3,0xc8,0x3,0x3,0xa8,0x3,0x3,0xcc,0x3,
+0x1,0x0,0x8,0x1,0x3,0xe0,0x3,0x3,0xc4,0x3,0x3,0xac,0x3,0x3,0x9c,0x3,0x3,
+0xa0,0x3,0x3,0xb0,0x3,0x3,0x98,0x3,0x3,0xd4,0x3,0x1,0x0,0x3,0x1,0x3,0xe4,
+0x3,0x3,0xb8,0x3,0x3,0xb4,0x3,0x1,0x0,0x5,0x1,0x3,0xc0,0x3,0x3,0xdc,0x3,
+0x3,0xa4,0x3,0x3,0xbc,0x3,0x3,0xd8,0x3,0x0,0x0
+};
+UCHAR kbdrestab[]=
+{
+0x8,0x4b,0x42,0x44,0x43,0x41,0x4c,0x4c,0x53,0x0,0x0,0xc,0x4b,0x42,0x44,0x53,
+0x45,0x54,0x43,0x55,0x53,0x54,0x58,0x54,0x1,0x0,0x8,0x4b,0x42,0x44,0x47,
+0x45,0x54,0x43,0x50,0x3,0x0,0x9,0x4b,0x42,0x44,0x43,0x48,0x41,0x52,0x49,
+0x4e,0x4,0x0,0x8,0x4b,0x42,0x44,0x53,0x45,0x54,0x43,0x50,0x5,0x0,0x8,
+0x4b,0x42,0x44,0x53,0x59,0x4e,0x43,0x48,0x7,0x0,0xb,0x4b,0x42,0x44,0x52,
+0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x8,0x0,0xc,0x4b,0x42,0x44,0x47,0x45,
+0x54,0x53,0x54,0x41,0x54,0x55,0x53,0xa,0x0,0xb,0x4b,0x42,0x44,0x53,0x54,
+0x52,0x49,0x4e,0x47,0x49,0x4e,0x9,0x0,0xc,0x4b,0x42,0x44,0x53,0x45,0x54,
+0x53,0x54,0x41,0x54,0x55,0x53,0xb,0x0,0xb,0x4b,0x42,0x44,0x47,0x45,0x54,
+0x46,0x4f,0x43,0x55,0x53,0xc,0x0,0xe,0x4b,0x42,0x44,0x46,0x4c,0x55,0x53,
+0x48,0x42,0x55,0x46,0x46,0x45,0x52,0xd,0x0,0x8,0x4b,0x42,0x44,0x58,0x4c,
+0x41,0x54,0x45,0xe,0x0,0xc,0x4b,0x42,0x44,0x53,0x48,0x45,0x4c,0x4c,0x49,
+0x4e,0x49,0x54,0x10,0x0,0x8,0x4b,0x42,0x44,0x43,0x4c,0x4f,0x53,0x45,0x11,
+0x0,0xc,0x4b,0x42,0x44,0x46,0x52,0x45,0x45,0x46,0x4f,0x43,0x55,0x53,0x12,
+0x0,0xd,0x4b,0x42,0x44,0x44,0x45,0x52,0x45,0x47,0x49,0x53,0x54,0x45,0x52,
+0x14,0x0,0xa,0x4b,0x42,0x44,0x53,0x45,0x54,0x46,0x47,0x4e,0x44,0x15,0x0,
+0xa,0x4b,0x42,0x44,0x47,0x45,0x54,0x48,0x57,0x49,0x44,0x18,0x0,0x7,0x4b,
+0x42,0x44,0x50,0x45,0x45,0x4b,0x16,0x0,0x7,0x4b,0x42,0x44,0x4f,0x50,0x45,
+0x4e,0x17,0x0,0x0
+};
+UCHAR kbdnrestab[]=
+{
+0xc,0x6b,0x62,0x64,0x63,0x61,0x6c,0x6c,0x73,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+
+};
+UCHAR maienttab[]=
+{
+0x6,0x1,0x3,0xd0,0x4,0x3,0xd4,0x4,0x3,0xd8,0x4,0x3,0xe0,0x4,0x3,0xdc,0x4,0x3,
+0xe4,0x4,0x0,0x0
+};
+UCHAR mairestab[]=
+{
+0x8,0x4d,0x41,0x49,0x4c,0x53,0x4c,0x4f,0x54,0x0,0x0,0xf,0x44,0x4f,0x53,0x4d,
+0x41,0x4b,0x45,0x4d,0x41,0x49,0x4c,0x53,0x4c,0x4f,0x54,0x1,0x0,0xf,0x44,
+0x4f,0x53,0x50,0x45,0x45,0x4b,0x4d,0x41,0x49,0x4c,0x53,0x4c,0x4f,0x54,0x5,
+0x0,0xf,0x44,0x4f,0x53,0x4d,0x41,0x49,0x4c,0x53,0x4c,0x4f,0x54,0x49,0x4e,
+0x46,0x4f,0x3,0x0,0x10,0x44,0x4f,0x53,0x57,0x52,0x49,0x54,0x45,0x4d,0x41,
+0x49,0x4c,0x53,0x4c,0x4f,0x54,0x6,0x0,0xf,0x44,0x4f,0x53,0x52,0x45,0x41,
+0x44,0x4d,0x41,0x49,0x4c,0x53,0x4c,0x4f,0x54,0x4,0x0,0x11,0x44,0x4f,0x53,
+0x44,0x45,0x4c,0x45,0x54,0x45,0x4d,0x41,0x49,0x4c,0x53,0x4c,0x4f,0x54,0x2,
+0x0,0x0
+};
+UCHAR mainrestab[]=
+{
+0xc,0x6d,0x61,0x69,0x6c,0x73,0x6c,0x6f,0x74,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+
+};
+UCHAR monenttab[]=
+{
+0x5,0x1,0x3,0x50,0x4,0x3,0x48,0x4,0x3,0x44,0x4,0x3,0x40,0x4,0x3,0x4c,0x4,0x0,
+0x0
+};
+UCHAR monrestab[]=
+{
+0x8,0x4d,0x4f,0x4e,0x43,0x41,0x4c,0x4c,0x53,0x0,0x0,0xb,0x44,0x4f,0x53,0x4d,
+0x4f,0x4e,0x57,0x52,0x49,0x54,0x45,0x1,0x0,0xa,0x44,0x4f,0x53,0x4d,0x4f,
+0x4e,0x52,0x45,0x41,0x44,0x2,0x0,0xb,0x44,0x4f,0x53,0x4d,0x4f,0x4e,0x43,
+0x4c,0x4f,0x53,0x45,0x3,0x0,0xa,0x44,0x4f,0x53,0x4d,0x4f,0x4e,0x4f,0x50,
+0x45,0x4e,0x4,0x0,0x9,0x44,0x4f,0x53,0x4d,0x4f,0x4e,0x52,0x45,0x47,0x5,
+0x0,0x0
+};
+UCHAR monnrestab[]=
+{
+0xc,0x6d,0x6f,0x6e,0x63,0x61,0x6c,0x6c,0x73,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+
+};
+UCHAR mouenttab[]=
+{
+0x3,0x1,0x3,0x10,0x4,0x3,0x34,0x4,0x3,0x4,0x4,0x2,0x0,0x4,0x1,0x3,0x14,0x4,
+0x3,0xf4,0x3,0x3,0x0,0x4,0x3,0xe8,0x3,0x1,0x0,0x1,0x1,0x3,0x38,0x4,0x1,
+0x0,0xe,0x1,0x3,0x8,0x4,0x3,0xec,0x3,0x3,0xfc,0x3,0x3,0x2c,0x4,0x3,0x18,
+0x4,0x3,0x24,0x4,0x3,0xc,0x4,0x3,0x1c,0x4,0x3,0x30,0x4,0x3,0xf8,0x3,0x3,
+0x3c,0x4,0x3,0x20,0x4,0x3,0x28,0x4,0x3,0xf0,0x3,0x0,0x0
+};
+UCHAR mourestab[]=
+{
+0x8,0x4d,0x4f,0x55,0x43,0x41,0x4c,0x4c,0x53,0x0,0x0,0xe,0x4d,0x4f,0x55,0x47,
+0x45,0x54,0x50,0x54,0x52,0x53,0x48,0x41,0x50,0x45,0x1,0x0,0x10,0x4d,0x4f,
+0x55,0x47,0x45,0x54,0x4e,0x55,0x4d,0x4d,0x49,0x43,0x4b,0x45,0x59,0x53,0x3,
+0x0,0xe,0x4d,0x4f,0x55,0x53,0x45,0x54,0x50,0x54,0x52,0x53,0x48,0x41,0x50,
+0x45,0x2,0x0,0xf,0x4d,0x4f,0x55,0x47,0x45,0x54,0x53,0x43,0x41,0x4c,0x45,
+0x46,0x41,0x43,0x54,0x6,0x0,0x10,0x4d,0x4f,0x55,0x47,0x45,0x54,0x4e,0x55,
+0x4d,0x42,0x55,0x54,0x54,0x4f,0x4e,0x53,0x8,0x0,0xb,0x4d,0x4f,0x55,0x46,
+0x4c,0x55,0x53,0x48,0x51,0x55,0x45,0x7,0x0,0x8,0x4d,0x4f,0x55,0x43,0x4c,
+0x4f,0x53,0x45,0x9,0x0,0xf,0x4d,0x4f,0x55,0x53,0x45,0x54,0x53,0x43,0x41,
+0x4c,0x45,0x46,0x41,0x43,0x54,0xb,0x0,0xd,0x4d,0x4f,0x55,0x44,0x45,0x52,
+0x45,0x47,0x49,0x53,0x54,0x45,0x52,0xe,0x0,0xe,0x4d,0x4f,0x55,0x47,0x45,
+0x54,0x4e,0x55,0x4d,0x51,0x55,0x45,0x45,0x4c,0xd,0x0,0xf,0x4d,0x4f,0x55,
+0x47,0x45,0x54,0x45,0x56,0x45,0x4e,0x54,0x4d,0x41,0x53,0x4b,0xf,0x0,0xf,
+0x4d,0x4f,0x55,0x53,0x45,0x54,0x45,0x56,0x45,0x4e,0x54,0x4d,0x41,0x53,0x4b,
+0x10,0x0,0x7,0x4d,0x4f,0x55,0x4f,0x50,0x45,0x4e,0x11,0x0,0xc,0x4d,0x4f,
+0x55,0x52,0x45,0x4d,0x4f,0x56,0x45,0x50,0x54,0x52,0x12,0x0,0xc,0x4d,0x4f,
+0x55,0x47,0x45,0x54,0x50,0x54,0x52,0x50,0x4f,0x53,0x13,0x0,0xf,0x4d,0x4f,
+0x55,0x52,0x45,0x41,0x44,0x45,0x56,0x45,0x4e,0x54,0x51,0x55,0x45,0x14,0x0,
+0xc,0x4d,0x4f,0x55,0x53,0x45,0x54,0x50,0x54,0x52,0x50,0x4f,0x53,0x15,0x0,
+0xf,0x4d,0x4f,0x55,0x47,0x45,0x54,0x44,0x45,0x56,0x53,0x54,0x41,0x54,0x55,
+0x53,0x16,0x0,0x8,0x4d,0x4f,0x55,0x53,0x59,0x4e,0x43,0x48,0x17,0x0,0xb,
+0x4d,0x4f,0x55,0x52,0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x18,0x0,0xa,0x4d,
+0x4f,0x55,0x44,0x52,0x41,0x57,0x50,0x54,0x52,0x1a,0x0,0xf,0x4d,0x4f,0x55,
+0x53,0x45,0x54,0x44,0x45,0x56,0x53,0x54,0x41,0x54,0x55,0x53,0x19,0x0,0x0
+
+};
+UCHAR mounrestab[]=
+{
+0xc,0x6d,0x6f,0x75,0x63,0x61,0x6c,0x6c,0x73,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+
+};
+UCHAR msgenttab[]=
+{
+0x3,0x1,0x3,0x5c,0x2,0x3,0x4c,0x2,0x3,0x58,0x2,0x0,0x0
+};
+UCHAR msgrestab[]=
+{
+0x3,0x4d,0x53,0x47,0x0,0x0,0xd,0x44,0x4f,0x53,0x50,0x55,0x54,0x4d,0x45,0x53,
+0x53,0x41,0x47,0x45,0x1,0x0,0x11,0x44,0x4f,0x53,0x54,0x52,0x55,0x45,0x47,
+0x45,0x54,0x4d,0x45,0x53,0x53,0x41,0x47,0x45,0x2,0x0,0xd,0x44,0x4f,0x53,
+0x49,0x4e,0x53,0x4d,0x45,0x53,0x53,0x41,0x47,0x45,0x3,0x0,0x0
+};
+UCHAR msgnrestab[]=
+{
+0x7,0x6d,0x73,0x67,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+};
+UCHAR namenttab[]=
+{
+0xa,0x1,0x3,0x98,0x0,0x3,0xa4,0x0,0x3,0x90,0x0,0x3,0x94,0x0,0x3,0xa0,0x0,0x3,
+0xac,0x0,0x3,0x9c,0x0,0x3,0xb8,0x0,0x3,0xb4,0x0,0x3,0x8c,0x0,0x2,0x0,0x2,
+0x1,0x3,0xb0,0x0,0x3,0xa8,0x0,0x0,0x0
+};
+UCHAR namrestab[]=
+{
+0x8,0x4e,0x41,0x4d,0x50,0x49,0x50,0x45,0x53,0x0,0x0,0x13,0x44,0x4f,0x53,0x44,
+0x49,0x53,0x43,0x4f,0x4e,0x4e,0x45,0x43,0x54,0x4e,0x4d,0x50,0x49,0x50,0x45,
+0x4,0x0,0x12,0x44,0x4f,0x53,0x53,0x45,0x54,0x4e,0x4d,0x50,0x48,0x41,0x4e,
+0x44,0x53,0x54,0x41,0x54,0x45,0x6,0x0,0xd,0x44,0x4f,0x53,0x57,0x41,0x49,
+0x54,0x4e,0x4d,0x50,0x49,0x50,0x45,0x8,0x0,0xf,0x44,0x4f,0x53,0x53,0x45,
+0x54,0x4e,0x4d,0x50,0x49,0x50,0x45,0x53,0x45,0x4d,0xd,0x0,0x11,0x44,0x4f,
+0x53,0x54,0x52,0x41,0x4e,0x53,0x41,0x43,0x54,0x4e,0x4d,0x50,0x49,0x50,0x45,
+0x9,0x0,0x10,0x44,0x4f,0x53,0x51,0x4e,0x4d,0x50,0x48,0x41,0x4e,0x44,0x53,
+0x54,0x41,0x54,0x45,0x5,0x0,0x12,0x44,0x4f,0x53,0x51,0x4e,0x4d,0x50,0x49,
+0x50,0x45,0x53,0x45,0x4d,0x53,0x54,0x41,0x54,0x45,0xe,0x0,0xd,0x44,0x4f,
+0x53,0x4d,0x41,0x4b,0x45,0x4e,0x4d,0x50,0x49,0x50,0x45,0x1,0x0,0xe,0x44,
+0x4f,0x53,0x51,0x4e,0x4d,0x50,0x49,0x50,0x45,0x49,0x4e,0x46,0x4f,0x2,0x0,
+0x10,0x44,0x4f,0x53,0x43,0x4f,0x4e,0x4e,0x45,0x43,0x54,0x4e,0x4d,0x50,0x49,
+0x50,0x45,0x3,0x0,0xd,0x44,0x4f,0x53,0x50,0x45,0x45,0x4b,0x4e,0x4d,0x50,
+0x49,0x50,0x45,0x7,0x0,0xd,0x44,0x4f,0x53,0x43,0x41,0x4c,0x4c,0x4e,0x4d,
+0x50,0x49,0x50,0x45,0xa,0x0,0x0
+};
+UCHAR namnrestab[]=
+{
+0xc,0x6e,0x61,0x6d,0x70,0x69,0x70,0x65,0x73,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+
+};
+UCHAR apienttab[]=
+{
+0x2,0x1,0x3,0x98,0x4,0x3,0xa4,0x4,0x1,0x0,0x2,0x1,0x3,0xa0,0x4,0x3,0x9c,0x4,
+0x7,0x0,0x5,0x1,0x3,0xbc,0x4,0x3,0xc0,0x4,0x3,0xc4,0x4,0x3,0xc8,0x4,0x3,
+0xcc,0x4,0x24,0x0,0x2,0x1,0x3,0x5c,0x4,0x3,0x64,0x4,0x1,0x0,0x3,0x1,0x3,
+0x68,0x4,0x3,0x6c,0x4,0x3,0x74,0x4,0x4,0x0,0x1,0x1,0x3,0xa8,0x4,0x1,0x0,
+0x3,0x1,0x3,0xac,0x4,0x3,0x78,0x4,0x3,0x7c,0x4,0x4,0x0,0x4,0x1,0x3,0x80,
+0x4,0x3,0x84,0x4,0x3,0x88,0x4,0x3,0x8c,0x4,0x2,0x0,0x1,0x1,0x3,0x90,0x4,
+0x1,0x0,0x1,0x1,0x3,0xb0,0x4,0x2,0x0,0x1,0x1,0x3,0x94,0x4,0x1f,0x0,0x1,
+0x1,0x3,0x70,0x4,0x39,0x0,0x1,0x1,0x3,0x58,0x4,0xe,0x0,0x1,0x1,0x3,0x54,
+0x4,0xff,0x0,0x38,0x0,0x4,0x1,0x3,0xd4,0x4,0x3,0xd8,0x4,0x3,0xd0,0x4,0x3,
+0xdc,0x4,0x12,0x0,0x3,0x1,0x3,0xe0,0x4,0x3,0xe4,0x4,0x3,0xb4,0x4,0x2,0x0,
+0x1,0x1,0x3,0x60,0x4,0x1,0x0,0xa,0x1,0x3,0x98,0x0,0x3,0x90,0x0,0x3,0x94,
+0x0,0x3,0xac,0x0,0x3,0xb8,0x0,0x3,0xb4,0x0,0x3,0xa0,0x0,0x3,0xa4,0x0,0x3,
+0x9c,0x0,0x3,0x8c,0x0,0x60,0x0,0x1,0x1,0x3,0xec,0x4,0x0,0x0
+};
+UCHAR apirestab[]=
+{
+0x7,0x49,0x4e,0x45,0x54,0x41,0x50,0x49,0x0,0x0,0xf,0x44,0x4f,0x53,0x4d,0x41,
+0x4b,0x45,0x4d,0x41,0x49,0x4c,0x53,0x4c,0x4f,0x54,0xf7,0x1,0x13,0x44,0x4f,
+0x53,0x44,0x49,0x53,0x43,0x4f,0x4e,0x4e,0x45,0x43,0x54,0x4e,0x4d,0x50,0x49,
+0x50,0x45,0x14,0x2,0xb,0x4e,0x45,0x54,0x55,0x53,0x45,0x52,0x45,0x4e,0x55,
+0x4d,0x4f,0x0,0x12,0x44,0x4f,0x53,0x53,0x45,0x54,0x4e,0x4d,0x50,0x48,0x41,
+0x4e,0x44,0x53,0x54,0x41,0x54,0x45,0x15,0x2,0xb,0x4e,0x45,0x54,0x42,0x49,
+0x4f,0x53,0x45,0x4e,0x55,0x4d,0xe,0x0,0xf,0x44,0x4f,0x53,0x50,0x45,0x45,
+0x4b,0x4d,0x41,0x49,0x4c,0x53,0x4c,0x4f,0x54,0xf8,0x1,0xd,0x44,0x4f,0x53,
+0x57,0x41,0x49,0x54,0x4e,0x4d,0x50,0x49,0x50,0x45,0x16,0x2,0xf,0x4e,0x45,
+0x54,0x53,0x48,0x41,0x52,0x45,0x47,0x45,0x54,0x49,0x4e,0x46,0x4f,0x44,0x0,
+0xe,0x4e,0x45,0x54,0x53,0x45,0x52,0x56,0x45,0x52,0x45,0x4e,0x55,0x4d,0x32,
+0x10,0x2,0x9,0x4e,0x45,0x54,0x55,0x53,0x45,0x41,0x44,0x44,0x49,0x0,0xa,
+0x4e,0x45,0x54,0x55,0x53,0x45,0x45,0x4e,0x55,0x4d,0x4b,0x0,0xd,0x4e,0x45,
+0x54,0x42,0x49,0x4f,0x53,0x53,0x55,0x42,0x4d,0x49,0x54,0x11,0x0,0xb,0x4e,
+0x45,0x54,0x53,0x48,0x41,0x52,0x45,0x41,0x44,0x44,0x40,0x0,0x11,0x4e,0x45,
+0x54,0x53,0x45,0x52,0x56,0x49,0x43,0x45,0x49,0x4e,0x53,0x54,0x41,0x4c,0x4c,
+0x3b,0x0,0x14,0x4e,0x45,0x54,0x4d,0x45,0x53,0x53,0x41,0x47,0x45,0x42,0x55,
+0x46,0x46,0x45,0x52,0x53,0x45,0x4e,0x44,0xd,0x2,0xc,0x4e,0x45,0x54,0x41,
+0x43,0x43,0x45,0x53,0x53,0x41,0x44,0x44,0x1,0x0,0xf,0x44,0x4f,0x53,0x4d,
+0x41,0x49,0x4c,0x53,0x4c,0x4f,0x54,0x49,0x4e,0x46,0x4f,0xf6,0x1,0x11,0x44,
+0x4f,0x53,0x54,0x52,0x41,0x4e,0x53,0x41,0x43,0x54,0x4e,0x4d,0x50,0x49,0x50,
+0x45,0x17,0x2,0x9,0x4e,0x45,0x54,0x55,0x53,0x45,0x44,0x45,0x4c,0x4a,0x0,
+0xc,0x4e,0x45,0x54,0x53,0x48,0x41,0x52,0x45,0x45,0x4e,0x55,0x4d,0x43,0x0,
+0xc,0x4e,0x45,0x54,0x41,0x43,0x43,0x45,0x53,0x53,0x44,0x45,0x4c,0x2,0x0,
+0x11,0x4e,0x45,0x54,0x53,0x45,0x52,0x56,0x49,0x43,0x45,0x47,0x45,0x54,0x49,
+0x4e,0x46,0x4f,0x74,0x0,0x10,0x4e,0x45,0x54,0x53,0x45,0x52,0x56,0x45,0x52,
+0x47,0x45,0x54,0x49,0x4e,0x46,0x4f,0x37,0x0,0xf,0x4e,0x45,0x54,0x57,0x4b,
+0x53,0x54,0x41,0x47,0x45,0x54,0x49,0x4e,0x46,0x4f,0x54,0x0,0x10,0x44,0x4f,
+0x53,0x51,0x4e,0x4d,0x50,0x48,0x41,0x4e,0x44,0x53,0x54,0x41,0x54,0x45,0x18,
+0x2,0xb,0x4e,0x45,0x54,0x53,0x48,0x41,0x52,0x45,0x44,0x45,0x4c,0x42,0x0,
+0x11,0x4e,0x45,0x54,0x53,0x45,0x52,0x56,0x45,0x52,0x44,0x49,0x53,0x4b,0x45,
+0x4e,0x55,0x4d,0x36,0x0,0xc,0x4e,0x45,0x54,0x42,0x49,0x4f,0x53,0x43,0x4c,
+0x4f,0x53,0x45,0xd,0x0,0x11,0x4e,0x45,0x54,0x53,0x45,0x52,0x56,0x49,0x43,
+0x45,0x43,0x4f,0x4e,0x54,0x52,0x4f,0x4c,0x39,0x0,0x14,0x4e,0x45,0x54,0x49,
+0x57,0x4b,0x53,0x54,0x41,0x47,0x45,0x54,0x55,0x53,0x45,0x52,0x49,0x4e,0x46,
+0x4f,0x7c,0x2,0x10,0x4e,0x45,0x54,0x41,0x43,0x43,0x45,0x53,0x53,0x47,0x45,
+0x54,0x49,0x4e,0x46,0x4f,0x4,0x0,0xd,0x44,0x4f,0x53,0x4d,0x41,0x4b,0x45,
+0x4e,0x4d,0x50,0x49,0x50,0x45,0x12,0x2,0x10,0x4e,0x45,0x54,0x48,0x41,0x4e,
+0x44,0x4c,0x45,0x47,0x45,0x54,0x49,0x4e,0x46,0x4f,0xae,0x0,0x10,0x44,0x4f,
+0x53,0x57,0x52,0x49,0x54,0x45,0x4d,0x41,0x49,0x4c,0x53,0x4c,0x4f,0x54,0xc,
+0x2,0xe,0x44,0x4f,0x53,0x51,0x4e,0x4d,0x50,0x49,0x50,0x45,0x49,0x4e,0x46,
+0x4f,0x19,0x2,0xe,0x4e,0x45,0x54,0x53,0x45,0x52,0x56,0x49,0x43,0x45,0x45,
+0x4e,0x55,0x4d,0x3a,0x0,0xc,0x4e,0x45,0x54,0x47,0x45,0x54,0x44,0x43,0x4e,
+0x41,0x4d,0x45,0xbd,0x0,0x10,0x44,0x4f,0x53,0x43,0x4f,0x4e,0x4e,0x45,0x43,
+0x54,0x4e,0x4d,0x50,0x49,0x50,0x45,0x13,0x2,0xd,0x44,0x4f,0x53,0x50,0x45,
+0x45,0x4b,0x4e,0x4d,0x50,0x49,0x50,0x45,0x1a,0x2,0xe,0x4e,0x45,0x54,0x55,
+0x53,0x45,0x52,0x47,0x45,0x54,0x49,0x4e,0x46,0x4f,0x51,0x0,0xf,0x44,0x4f,
+0x53,0x52,0x45,0x41,0x44,0x4d,0x41,0x49,0x4c,0x53,0x4c,0x4f,0x54,0xb,0x2,
+0xe,0x4e,0x45,0x54,0x42,0x49,0x4f,0x53,0x47,0x45,0x54,0x49,0x4e,0x46,0x4f,
+0xf,0x0,0x10,0x4e,0x45,0x54,0x41,0x43,0x43,0x45,0x53,0x53,0x53,0x45,0x54,
+0x49,0x4e,0x46,0x4f,0x5,0x0,0xd,0x44,0x4f,0x53,0x43,0x41,0x4c,0x4c,0x4e,
+0x4d,0x50,0x49,0x50,0x45,0x1b,0x2,0xd,0x4e,0x45,0x54,0x55,0x53,0x45,0x47,
+0x45,0x54,0x49,0x4e,0x46,0x4f,0x4c,0x0,0x11,0x44,0x4f,0x53,0x44,0x45,0x4c,
+0x45,0x54,0x45,0x4d,0x41,0x49,0x4c,0x53,0x4c,0x4f,0x54,0xf5,0x1,0xb,0x4e,
+0x45,0x54,0x42,0x49,0x4f,0x53,0x4f,0x50,0x45,0x4e,0x10,0x0,0x0
+};
+UCHAR apinrestab[]=
+{
+0xb,0x69,0x6e,0x65,0x74,0x61,0x70,0x69,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+};
+UCHAR oementtab[]=
+{
+0x4,0x0,0x1,0x1,0x3,0xb4,0x4,0x5,0x0,0x1,0x1,0x3,0x60,0x4,0x0,0x0
+};
+UCHAR oemrestab[]=
+{
+0x6,0x4e,0x45,0x54,0x4f,0x45,0x4d,0x0,0x0,0xe,0x4e,0x45,0x54,0x53,0x45,0x52,
+0x56,0x45,0x52,0x45,0x4e,0x55,0x4d,0x32,0xb,0x0,0x14,0x4e,0x45,0x54,0x4d,
+0x45,0x53,0x53,0x41,0x47,0x45,0x42,0x55,0x46,0x46,0x45,0x52,0x53,0x45,0x4e,
+0x44,0x5,0x0,0x0
+};
+UCHAR oemnrestab[]=
+{
+0xa,0x6e,0x65,0x74,0x6f,0x65,0x6d,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+};
+UCHAR nlsenttab[]=
+{
+0x4,0x1,0x3,0x34,0x0,0x3,0x38,0x0,0x3,0x2c,0x0,0x3,0x30,0x0,0x0,0x0
+};
+UCHAR nlsrestab[]=
+{
+0x3,0x4e,0x4c,0x53,0x0,0x0,0xa,0x44,0x4f,0x53,0x43,0x41,0x53,0x45,0x4d,0x41,
+0x50,0x1,0x0,0xd,0x44,0x4f,0x53,0x47,0x45,0x54,0x43,0x4f,0x4c,0x4c,0x41,
+0x54,0x45,0x2,0x0,0xe,0x44,0x4f,0x53,0x47,0x45,0x54,0x43,0x54,0x52,0x59,
+0x49,0x4e,0x46,0x4f,0x3,0x0,0xc,0x44,0x4f,0x53,0x47,0x45,0x54,0x44,0x42,
+0x43,0x53,0x45,0x56,0x4,0x0,0x0
+};
+UCHAR nlsnrestab[]=
+{
+0x7,0x6e,0x6c,0x73,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+};
+UCHAR pmsenttab[]=
+{
+0x1,0x0,0x6,0x1,0x3,0xcc,0x2,0x3,0xc0,0x2,0x3,0xd4,0x2,0x3,0xc4,0x2,0x3,0xc8,
+0x2,0x3,0xd0,0x2,0x0,0x0
+};
+UCHAR pmsrestab[]=
+{
+0x7,0x50,0x4d,0x53,0x48,0x41,0x50,0x49,0x0,0x0,0x13,0x57,0x49,0x4e,0x51,0x55,
+0x45,0x52,0x59,0x50,0x52,0x4f,0x46,0x49,0x4c,0x45,0x44,0x41,0x54,0x41,0x6,
+0x0,0x13,0x57,0x49,0x4e,0x57,0x52,0x49,0x54,0x45,0x50,0x52,0x4f,0x46,0x49,
+0x4c,0x45,0x44,0x41,0x54,0x41,0x7,0x0,0x12,0x57,0x49,0x4e,0x51,0x55,0x45,
+0x52,0x59,0x50,0x52,0x4f,0x46,0x49,0x4c,0x45,0x49,0x4e,0x54,0x2,0x0,0x13,
+0x57,0x49,0x4e,0x51,0x55,0x45,0x52,0x59,0x50,0x52,0x4f,0x46,0x49,0x4c,0x45,
+0x53,0x49,0x5a,0x45,0x5,0x0,0x15,0x57,0x49,0x4e,0x51,0x55,0x45,0x52,0x59,
+0x50,0x52,0x4f,0x46,0x49,0x4c,0x45,0x53,0x54,0x52,0x49,0x4e,0x47,0x3,0x0,
+0x15,0x57,0x49,0x4e,0x57,0x52,0x49,0x54,0x45,0x50,0x52,0x4f,0x46,0x49,0x4c,
+0x45,0x53,0x54,0x52,0x49,0x4e,0x47,0x4,0x0,0x0
+};
+UCHAR pmsnrestab[]=
+{
+0xb,0x70,0x6d,0x73,0x68,0x61,0x70,0x69,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+};
+UCHAR pmwenttab[]=
+{
+0xe0,0x0,0x2,0x1,0x3,0xd8,0x2,0x3,0xdc,0x2,0x1,0x0,0x1,0x1,0x3,0xe0,0x2,0x1,
+0x0,0x1,0x1,0x3,0xe4,0x2,0xc,0x0,0x1,0x1,0x3,0xe8,0x2,0x0,0x0
+};
+UCHAR pmwrestab[]=
+{
+0x5,0x50,0x4d,0x57,0x49,0x4e,0x0,0x0,0xe,0x57,0x49,0x4e,0x44,0x45,0x53,0x54,
+0x52,0x4f,0x59,0x48,0x45,0x41,0x50,0xe2,0x0,0xd,0x57,0x49,0x4e,0x43,0x52,
+0x45,0x41,0x54,0x45,0x48,0x45,0x41,0x50,0xe1,0x0,0xf,0x57,0x49,0x4e,0x47,
+0x45,0x54,0x4c,0x41,0x53,0x54,0x45,0x52,0x52,0x4f,0x52,0xf3,0x0,0xb,0x57,
+0x49,0x4e,0x41,0x4c,0x4c,0x4f,0x43,0x4d,0x45,0x4d,0xe4,0x0,0xa,0x57,0x49,
+0x4e,0x46,0x52,0x45,0x45,0x4d,0x45,0x4d,0xe6,0x0,0x0
+};
+UCHAR pmwnrestab[]=
+{
+0x9,0x70,0x6d,0x77,0x69,0x6e,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+};
+UCHAR os2enttab[]=
+{
+0x2e,0x0,0x1,0x1,0x3,0x84,0x2,0x0,0x0
+};
+UCHAR os2restab[]=
+{
+0x5,0x4f,0x53,0x32,0x53,0x4d,0x0,0x0,0x12,0x57,0x49,0x4e,0x53,0x45,0x54,0x54,
+0x49,0x54,0x4c,0x45,0x41,0x4e,0x44,0x49,0x43,0x4f,0x4e,0x2f,0x0,0x0
+};
+UCHAR os2nrestab[]=
+{
+0x9,0x6f,0x73,0x32,0x73,0x6d,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+};
+UCHAR sesenttab[]=
+{
+0x4,0x0,0x1,0x1,0x3,0x7c,0x2,0x2,0x0,0x2,0x1,0x3,0x70,0x2,0x3,0x78,0x2,0x4,
+0x0,0x1,0x1,0x3,0x74,0x2,0x2,0x0,0x1,0x1,0x3,0x6c,0x2,0xa,0x0,0x1,0x1,
+0x3,0x80,0x2,0x0,0x0
+};
+UCHAR sesrestab[]=
+{
+0x6,0x53,0x45,0x53,0x4d,0x47,0x52,0x0,0x0,0xe,0x44,0x4f,0x53,0x53,0x4d,0x50,
+0x4d,0x50,0x52,0x45,0x53,0x45,0x4e,0x54,0x1c,0x0,0xd,0x44,0x4f,0x53,0x53,
+0x4d,0x53,0x45,0x54,0x54,0x49,0x54,0x4c,0x45,0x5,0x0,0xe,0x44,0x4f,0x53,
+0x53,0x54,0x4f,0x50,0x53,0x45,0x53,0x53,0x49,0x4f,0x4e,0x8,0x0,0x10,0x44,
+0x4f,0x53,0x53,0x45,0x4c,0x45,0x43,0x54,0x53,0x45,0x53,0x53,0x49,0x4f,0x4e,
+0x9,0x0,0xd,0x44,0x4f,0x53,0x53,0x45,0x54,0x53,0x45,0x53,0x53,0x49,0x4f,
+0x4e,0xe,0x0,0xf,0x44,0x4f,0x53,0x53,0x54,0x41,0x52,0x54,0x53,0x45,0x53,
+0x53,0x49,0x4f,0x4e,0x11,0x0,0x0
+};
+UCHAR sesnrestab[]=
+{
+0xa,0x73,0x65,0x73,0x6d,0x67,0x72,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+};
+UCHAR queenttab[]=
+{
+0x8,0x1,0x3,0x7c,0x0,0x3,0x80,0x0,0x3,0x74,0x0,0x3,0x84,0x0,0x3,0x78,0x0,0x3,
+0x88,0x0,0x3,0x70,0x0,0x3,0x6c,0x0,0x0,0x0
+};
+UCHAR querestab[]=
+{
+0x8,0x51,0x55,0x45,0x43,0x41,0x4c,0x4c,0x53,0x0,0x0,0xc,0x44,0x4f,0x53,0x52,
+0x45,0x41,0x44,0x51,0x55,0x45,0x55,0x45,0x1,0x0,0xd,0x44,0x4f,0x53,0x50,
+0x55,0x52,0x47,0x45,0x51,0x55,0x45,0x55,0x45,0x2,0x0,0xd,0x44,0x4f,0x53,
+0x43,0x4c,0x4f,0x53,0x45,0x51,0x55,0x45,0x55,0x45,0x3,0x0,0xd,0x44,0x4f,
+0x53,0x51,0x55,0x45,0x52,0x59,0x51,0x55,0x45,0x55,0x45,0x4,0x0,0xd,0x44,
+0x4f,0x53,0x57,0x52,0x49,0x54,0x45,0x51,0x55,0x45,0x55,0x45,0x6,0x0,0xc,
+0x44,0x4f,0x53,0x50,0x45,0x45,0x4b,0x51,0x55,0x45,0x55,0x45,0x5,0x0,0xc,
+0x44,0x4f,0x53,0x4f,0x50,0x45,0x4e,0x51,0x55,0x45,0x55,0x45,0x7,0x0,0xe,
+0x44,0x4f,0x53,0x43,0x52,0x45,0x41,0x54,0x45,0x51,0x55,0x45,0x55,0x45,0x8,
+0x0,0x0
+};
+UCHAR quenrestab[]=
+{
+0xc,0x71,0x75,0x65,0x63,0x61,0x6c,0x6c,0x73,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+
+};
+UCHAR vioenttab[]=
+{
+0x3,0x1,0x3,0x58,0x3,0x3,0x74,0x3,0x3,0x2c,0x3,0x1,0x0,0x9,0x1,0x3,0x30,0x3,
+0x3,0x4c,0x3,0x3,0xec,0x2,0x3,0x90,0x3,0x3,0xf0,0x2,0x3,0x10,0x3,0x3,0x54,
+0x3,0x3,0x28,0x3,0x3,0x14,0x3,0x1,0x0,0x1,0x1,0x3,0xf4,0x2,0x2,0x0,0x2,
+0x1,0x3,0x8c,0x3,0x3,0xf8,0x2,0x1,0x0,0xd,0x1,0x3,0xfc,0x2,0x3,0x48,0x3,
+0x3,0x88,0x3,0x3,0x0,0x3,0x3,0x80,0x3,0x3,0x1c,0x3,0x3,0x40,0x3,0x3,0x84,
+0x3,0x3,0x64,0x3,0x3,0x8,0x3,0x3,0x5c,0x3,0x3,0x44,0x3,0x3,0x68,0x3,0x1,
+0x0,0x1,0x1,0x3,0x78,0x3,0x1,0x0,0x1,0x1,0x3,0x7c,0x3,0x2,0x0,0x1,0x1,
+0x3,0x38,0x3,0x1,0x0,0xc,0x1,0x3,0x3c,0x3,0x3,0x60,0x3,0x3,0x4,0x3,0x3,
+0x50,0x3,0x3,0x34,0x3,0x3,0x24,0x3,0x3,0xc,0x3,0x3,0x6c,0x3,0x3,0x94,0x3,
+0x3,0x70,0x3,0x3,0x18,0x3,0x3,0x20,0x3,0x0,0x0
+};
+UCHAR viorestab[]=
+{
+0x8,0x56,0x49,0x4f,0x43,0x41,0x4c,0x4c,0x53,0x0,0x0,0xb,0x56,0x49,0x4f,0x45,
+0x4e,0x44,0x50,0x4f,0x50,0x55,0x50,0x1,0x0,0xd,0x56,0x49,0x4f,0x47,0x45,
+0x54,0x50,0x48,0x59,0x53,0x42,0x55,0x46,0x2,0x0,0xa,0x56,0x49,0x4f,0x47,
+0x45,0x54,0x41,0x4e,0x53,0x49,0x3,0x0,0xa,0x56,0x49,0x4f,0x53,0x45,0x54,
+0x41,0x4e,0x53,0x49,0x5,0x0,0xd,0x56,0x49,0x4f,0x44,0x45,0x52,0x45,0x47,
+0x49,0x53,0x54,0x45,0x52,0x6,0x0,0xb,0x56,0x49,0x4f,0x53,0x43,0x52,0x4f,
+0x4c,0x4c,0x55,0x50,0x7,0x0,0x8,0x56,0x49,0x4f,0x50,0x52,0x54,0x53,0x43,
+0x8,0x0,0xc,0x56,0x49,0x4f,0x47,0x45,0x54,0x43,0x55,0x52,0x50,0x4f,0x53,
+0x9,0x0,0xd,0x56,0x49,0x4f,0x57,0x52,0x54,0x43,0x45,0x4c,0x4c,0x53,0x54,
+0x52,0xa,0x0,0x8,0x56,0x49,0x4f,0x50,0x4f,0x50,0x55,0x50,0xb,0x0,0xb,
+0x56,0x49,0x4f,0x53,0x43,0x52,0x4f,0x4c,0x4c,0x52,0x54,0xc,0x0,0xd,0x56,
+0x49,0x4f,0x57,0x52,0x54,0x43,0x48,0x41,0x52,0x53,0x54,0x52,0xd,0x0,0xc,
+0x56,0x49,0x4f,0x53,0x45,0x54,0x43,0x55,0x52,0x50,0x4f,0x53,0xf,0x0,0x9,
+0x56,0x49,0x4f,0x57,0x52,0x54,0x54,0x54,0x59,0x13,0x0,0xc,0x56,0x49,0x4f,
+0x53,0x43,0x52,0x55,0x4e,0x4c,0x4f,0x43,0x4b,0x12,0x0,0xa,0x56,0x49,0x4f,
+0x47,0x45,0x54,0x4d,0x4f,0x44,0x45,0x15,0x0,0xa,0x56,0x49,0x4f,0x53,0x45,
+0x54,0x4d,0x4f,0x44,0x45,0x16,0x0,0xa,0x56,0x49,0x4f,0x53,0x43,0x52,0x4c,
+0x4f,0x43,0x4b,0x17,0x0,0xe,0x56,0x49,0x4f,0x52,0x45,0x41,0x44,0x43,0x45,
+0x4c,0x4c,0x53,0x54,0x52,0x18,0x0,0xb,0x56,0x49,0x4f,0x57,0x52,0x54,0x4e,
+0x41,0x54,0x54,0x52,0x1a,0x0,0x10,0x56,0x49,0x4f,0x53,0x41,0x56,0x52,0x45,
+0x44,0x52,0x41,0x57,0x57,0x41,0x49,0x54,0x19,0x0,0xd,0x56,0x49,0x4f,0x47,
+0x45,0x54,0x43,0x55,0x52,0x54,0x59,0x50,0x45,0x1b,0x0,0x10,0x56,0x49,0x4f,
+0x53,0x41,0x56,0x52,0x45,0x44,0x52,0x41,0x57,0x55,0x4e,0x44,0x4f,0x1c,0x0,
+0xa,0x56,0x49,0x4f,0x47,0x45,0x54,0x46,0x4f,0x4e,0x54,0x1d,0x0,0xe,0x56,
+0x49,0x4f,0x52,0x45,0x41,0x44,0x43,0x48,0x41,0x52,0x53,0x54,0x52,0x1e,0x0,
+0x9,0x56,0x49,0x4f,0x47,0x45,0x54,0x42,0x55,0x46,0x1f,0x0,0xd,0x56,0x49,
+0x4f,0x53,0x45,0x54,0x43,0x55,0x52,0x54,0x59,0x50,0x45,0x20,0x0,0xa,0x56,
+0x49,0x4f,0x53,0x45,0x54,0x46,0x4f,0x4e,0x54,0x21,0x0,0xb,0x56,0x49,0x4f,
+0x4d,0x4f,0x44,0x45,0x55,0x4e,0x44,0x4f,0x23,0x0,0xb,0x56,0x49,0x4f,0x4d,
+0x4f,0x44,0x45,0x57,0x41,0x49,0x54,0x25,0x0,0x8,0x56,0x49,0x4f,0x47,0x45,
+0x54,0x43,0x50,0x28,0x0,0x8,0x56,0x49,0x4f,0x53,0x45,0x54,0x43,0x50,0x2a,
+0x0,0xa,0x56,0x49,0x4f,0x53,0x48,0x4f,0x57,0x42,0x55,0x46,0x2b,0x0,0xb,
+0x56,0x49,0x4f,0x53,0x43,0x52,0x4f,0x4c,0x4c,0x4c,0x46,0x2c,0x0,0xb,0x56,
+0x49,0x4f,0x52,0x45,0x47,0x49,0x53,0x54,0x45,0x52,0x2d,0x0,0xc,0x56,0x49,
+0x4f,0x47,0x45,0x54,0x43,0x4f,0x4e,0x46,0x49,0x47,0x2e,0x0,0xb,0x56,0x49,
+0x4f,0x53,0x43,0x52,0x4f,0x4c,0x4c,0x44,0x4e,0x2f,0x0,0x10,0x56,0x49,0x4f,
+0x57,0x52,0x54,0x43,0x48,0x41,0x52,0x53,0x54,0x52,0x41,0x54,0x54,0x30,0x0,
+0xb,0x56,0x49,0x4f,0x47,0x45,0x54,0x53,0x54,0x41,0x54,0x45,0x31,0x0,0xe,
+0x56,0x49,0x4f,0x50,0x52,0x54,0x53,0x43,0x54,0x4f,0x47,0x47,0x4c,0x45,0x32,
+0x0,0xb,0x56,0x49,0x4f,0x53,0x45,0x54,0x53,0x54,0x41,0x54,0x45,0x33,0x0,
+0xb,0x56,0x49,0x4f,0x57,0x52,0x54,0x4e,0x43,0x45,0x4c,0x4c,0x34,0x0,0xb,
+0x56,0x49,0x4f,0x57,0x52,0x54,0x4e,0x43,0x48,0x41,0x52,0x35,0x0,0x0
+};
+UCHAR vionrestab[]=
+{
+0xc,0x76,0x69,0x6f,0x63,0x61,0x6c,0x6c,0x73,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0
+
+};
diff --git a/private/os2/inc/ldrxport.h b/private/os2/inc/ldrxport.h
new file mode 100644
index 000000000..4c19cf070
--- /dev/null
+++ b/private/os2/inc/ldrxport.h
@@ -0,0 +1,75 @@
+/***ET+ ldrrei_t - Structure of exec info for return from LDRNewExe */
+
+struct ldrrei_s {
+ ptr_t ei_startaddr; /* instruction pointer */
+ ptr_t ei_stackaddr; /* stack pointer */
+ ushort_t ei_ds; /* starting ds only for 16-bit */
+ ushort_t ei_dgroupsize; /* size of dgroup */
+ ushort_t ei_heapsize; /* size of heap */
+ ushort_t ei_loadtype; /* Load type 16-bit or 32-bit */
+ SEL ei_envsel; /* Selector to environment */
+ ushort_t ei_comoff; /* Offset to command line in env */
+ ushort_t ei_stacksize; /* size of stack */
+ ushort_t ei_hmod; /* module handle */
+};
+
+typedef struct ldrrei_s ldrrei_t; /* Loader return exec info */
+
+extern PVOID LDRExecInfo;
+
+struct ldrlibi_s {
+ struct ldrlibi_s *link;
+ ptr_t startaddr;
+ ptr_t stackaddr;
+ ushort_t ds;
+ ushort_t heapsize;
+ ushort_t handle;
+};
+
+typedef struct ldrlibi_s ldrlibi_t;
+
+#define MAX_INIT_RECORDS 64
+
+extern ldrlibi_t *pldrLibiRecord;
+
+extern int _cdecl ldrLibiInit(ldrlibi_t *pldrLibiRecord, ldrrei_t *pexec_info);
+
+/***LP ldrStop - stop in kernel debugger
+ *
+ * If the global ldrErr is TRUE and the mte pointer is not doscalls
+ * or is null, this routine transfers control to the kernel debugger.
+ *
+ * ldrStop (id, pmte)
+ *
+ * ENTRY id - identifier of caller (ignored)
+ * pmte - mte pointer or NULL
+ * RETURN NONE
+ *
+ * CALLS Debug_BreakDM
+ *
+ * EFFECTS NONE
+ */
+
+extern void LDRStop(int id, void *pmte);
+#if DBG
+#define ldrStop(id, pmte) LDRStop(id, pmte)
+#else
+#define ldrStop(id, pmte)
+#endif
+
+extern void ldrSetDescInfo(SEL selector, ULONG addr, USHORT flags,
+ USHORT limit);
+
+extern void ldrstart(ldrrei_t *pexec_info);
+
+extern PVOID LDRNEHeap;
+
+extern char *pheaderbuf; /* temp buf to read header */
+
+#if PMNT
+extern void ldrDumpSegmentTable();
+#endif
+#if DBG
+extern void ldrDisplaySegmentTable();
+#endif
+
diff --git a/private/os2/inc/mi.h b/private/os2/inc/mi.h
new file mode 100644
index 000000000..575e440e4
--- /dev/null
+++ b/private/os2/inc/mi.h
@@ -0,0 +1,504 @@
+/*static char *SCCSID = "@(#)mi.h 6.1 90/11/15";*/
+/*
+ * Machine instruction, flag definitions and character types
+ *
+ * SCCSID = @(#)mi.h 13.17 90/09/13
+ */
+
+// 386 eflags definitions
+
+#define F_AC 0x00040000 // (A)lignment (C)heck
+#define F_VM 0x00020000 // (V)irtual 8086 (M)ode
+#define F_RF 0x00010000 // (R)esume (F)lag
+#define F_NT 0x00004000 // (N)ested (T)ask
+#define F_NTCLEAR (~F_NT)
+#define F_IOPL0 0
+#define F_IOPL1 0x00001000
+#define F_IOPL2 0x00002000
+#define F_IOPL3 0x00003000
+#define F_IOPLMASK 0x00003000 // (I)/(O) (P)rivilege (L)evel
+#define F_IOPLSYS F_IOPL3 // wide open
+#define F_IOPLclear (~F_IOPLMASK)
+#define F_OVERFLOW 0x00000800
+#define F_DIRECTION 0x00000400
+#define F_INTERRUPT 0x00000200
+#define F_TRACE 0x00000100
+#define F_SIGN 0x00000080
+#define F_ZERO 0x00000040
+#define F_AUX 0x00000010
+#define F_PARITY 0x00000004
+#define F_CARRY 0x00000001
+#define F_UNDEFINED 0x0000802A
+
+// CR0 (Machine Status Register) bits
+
+#define CR0_PE 0x00000001 // (P)rotect (E)nable
+#define CR0_MP 0x00000002 // (M)onitor (P)rocessor extension
+#define CR0_EM 0x00000004 // (EM)ulate processor extension
+#define CR0_TS 0x00000008 // (T)ask (thread) (S)witched
+#define CR0_ET 0x00000010 // (E)xtension (T)ype, 0/1=287/387
+#define CR0_NE 0x00000020 // (N)umeric (E)xception 0/1=use 2/10h
+#define CR0_WP 0x00010000 // (W)rite (P)rotect in rings 0-2
+#define CR0_AM 0x00040000 // (A)lignment (M)ask, enable EFlags.AC
+#define CR0_NW 0x20000000 // (N)o (W)rite-through cache
+#define CR0_CD 0x40000000 // (C)ache (D)isable
+#define CR0_PG 0x80000000 // (P)a(G)ing enable
+#define CR0_RESERVED 0x1ffaffc0 // reserved bits
+
+/*
+ * Cache Operating Modes:
+ *
+ * CR0_CD CR0_NW Cache Fills Write-Throughs and Invalidates
+ * ------ ------ ----------- ------------------------------
+ * 1 1 disabled disabled
+ * 1 0 disabled enabled
+ * 0 1 INVALID combination - CR0 load causes GP fault
+ * 0 0 enabled enabled (Normal mode)
+ */
+
+// Machine Status Word bits (obsolete)
+
+#define MSW_PE CR0_PE
+#define MSW_MP CR0_MP
+#define MSW_EM CR0_EM
+#define MSW_TS CR0_TS
+#define MSW_ET CR0_ET
+
+// CR3 (Page Directory Base Register) bits
+
+#define CR3_WRITETHROUGH 0x00000008 // write-through cache (486 ignores)
+#define CR3_CACHEDISABLE 0x00000010 // cache disable
+#define CR3_FRAME 0xfffff000 // page directory physical frame number
+#define CR3_RESERVED 0x00000fe7 // reserved bits
+
+// Debug Registers
+
+#define DR_COUNT 0x4 // number of debug registers
+
+// DR6 (Debug Registers Status Register) bits
+
+#define DR6_B0 0x00000001 // breakpoint register 0 triggered
+#define DR6_B1 0x00000002 // breakpoint register 1 triggered
+#define DR6_B2 0x00000004 // breakpoint register 2 triggered
+#define DR6_B3 0x00000008 // breakpoint register 3 triggered
+#define DR6_BD 0x00002000 // ICE hardware active
+#define DR6_BS_BIT_INDEX 0xe // Single step trap
+#define DR6_BS (1 << DR6_BS_BIT_INDEX)
+#define DR6_BT 0x00008000 // TSS trap
+
+#define DR6_VALID (DR6_B0|DR6_B1|DR6_B2|DR6_B3|DR6_BD|DR6_BS|DR6_BT)
+#define DR6_RESERVED ~(DR6_VALID)
+
+// DR7 (Debug Register Control Register) bits
+
+#define DR7_L0 0x00000001 /* DR0 Local Enable */
+#define DR7_G0 0x00000002 /* DR0 Global Enable */
+#define DR7_L1 0x00000004 /* DR1 Local Enable */
+#define DR7_G1 0x00000008 /* DR1 Global Enable */
+#define DR7_L2 0x00000010 /* DR2 Local Enable */
+#define DR7_G2 0x00000020 /* DR2 Global Enable */
+#define DR7_L3 0x00000040 /* DR3 Local Enable */
+#define DR7_G3 0x00000080 /* DR3 Global Enable */
+
+#define DR7_LE 0x00000100 /* Local - Exact Match */
+#define DR7_GE 0x00000200 /* Global - Exact Match */
+
+#define DR7_RW0 0x00030000 /* DR0 RW bits */
+#define DR7_LEN0 0x000c0000 /* DR0 Len bits */
+#define DR7_RW1 0x00300000 /* DR1 RW bits */
+#define DR7_LEN1 0x00c00000 /* DR1 Len bits */
+#define DR7_RW2 0x03000000 /* DR2 RW bits */
+#define DR7_LEN2 0x0c000000 /* DR2 Len bits */
+#define DR7_RW3 0x30000000 /* DR3 RW bits */
+#define DR7_LEN3 0xc0000000 /* DR3 Len bits */
+
+#define DR7_RESERVED 0x0000fc00 /* DR7 Intel Reserved */
+
+#define DR7_EXECUTE 0x0 /* Execute */
+#define DR7_WRITE 0x1 /* Data Write */
+#define DR7_READWRITE 0x3 /* Data Read or Write */
+
+#define DR7_LEN_1 0x0 /* Length 1 bits */
+#define DR7_LEN_2 0x1 /* Length 2 */
+#define DR7_LEN_4 0x3 /* Length 4 */
+
+// Machine instruction, flag definitions and character types
+
+#define MI_ARPL 0x63 // ARPL instruction
+#define MI_HLT 0xf4 // HLT instruction
+#define MI_OPERANDSIZE 0x66 // Operand size override prefix
+#define MI_ADDRESSSIZE 0x67 // Address size override prefix
+#define MI_TWOBYTEOP 0x0f // Two byte opcode prefix
+
+#define MI_POP_DS 0x1f
+#define MI_POP_ES 0x07
+#define MI_POP_FS 0xA1 // second byte to 0Fh opcode
+#define MI_POP_GS 0xA9 // second byte to 0Fh opcode
+
+#define MI_INT3 0xCC
+#define MI_INT 0xCD
+#define MI_IRET 0xCF
+#define MI_LONG_JMP 0xEA
+#define MI_LONG_CALL 0x9A
+#define MI_LONG_RET 0xCB
+#define MI_LONG_RETn 0xCA
+#define MI_NEAR_RET 0xC3
+
+#define MI_IN_PORT_AL 0xE4 // Opcode of IN port,AL
+#define MI_IN_PORT_AX 0xE5 // Opcode of IN port,AX
+#define MI_OUT_PORT_AL 0xE6 // Opcode of OUT port,AL
+#define MI_OUT_PORT_AX 0xE7 // Opcode of OUT port,AX
+#define MI_IN_DX_AL 0xEC // Opcode of IN DX,AL
+#define MI_IN_DX_AX 0xED // Opcode of IN DX,AX
+#define MI_OUT_DX_AL 0xEE // Opcode of OUT DX,AL
+#define MI_OUT_DX_AX 0xEF // Opcode of OUT DX,AX
+
+#define MI_GROUP5 0xFF // 5th group of 11-bit opcode inst.s
+#define MI_SEGES 0x26 // ES override prefix
+#define MI_SEGCS 0x2E // CS override prefix
+#define MI_SEGSS 0x36 // SS override prefix
+#define MI_SEGDS 0x3E // DS override prefix
+#define MI_SEGFS 0x64 // FS override prefix
+#define MI_SEGGS 0x65 // GS override prefix
+
+// ESC opcode prefix and mask
+
+#define MI_ESCMASK 0xF8
+#define MI_ESC 0xD8
+
+// MOD field equates
+
+#define MI_MODMASK 0xC0 // MOD field mask
+#define MI_MODSHIFT 6 // MOD field shift
+#define MI_MODNONE 0x00 // MOD = 0 (no displacement)
+#define MI_MODBYTE 0x40 // MOD = 1 (byte displacement)
+#define MI_MODWORD 0x80 // MOD = 2 (word displacement)
+#define MI_MODREG 0xC0 // MOD = 3 (R/M field selects register)
+
+// REG field equates
+
+#define MI_REGMASK 0x38 // REG field mask
+#define MI_REGSHIFT 3 // REG field shift
+#define MI_REGAX 0x00 // REG = 0 (AX/AL)
+#define MI_REGCX 0x08 // REG = 1 (CX/CL)
+#define MI_REGDX 0x10 // REG = 2 (DX/DL)
+#define MI_REGBX 0x18 // REG = 3 (BX/BL)
+#define MI_REG3 0x18 // REG = 3 (part of 11-bit opcode)
+#define MI_REGSP 0x20 // REG = 4 (SP/AH)
+#define MI_REGBP 0x28 // REG = 5 (BP/CH)
+#define MI_REGSI 0x30 // REG = 6 (SI/DH)
+#define MI_REGDI 0x38 // REG = 7 (DI/BH)
+
+#define MI_REGES 0x00 // REG = 0 MOV seg,r/m or MOV r/m,seg
+#define MI_REGCS 0x08 // REG = 1
+#define MI_REGSS 0x10 // REG = 2
+#define MI_REGDS 0x18 // REG = 3
+#define MI_REGFS 0x20 // REG = 4
+#define MI_REGGS 0x28 // REG = 5
+
+// R/M field equates for memory operands (for 16-bit instructions)
+
+#define MI_RMMASK 0x07 // R/M field mask
+#define MI_RMSHIFT 0 // R/M field shift
+#define MI_RMBXSI 0x00 // R/M = 0 ([BX+SI])
+#define MI_RMBXDI 0x01 // R/M = 1 ([BX+DI])
+#define MI_RMBPSI 0x02 // R/M = 2 ([BP+SI])
+#define MI_RMBPDI 0x03 // R/M = 3 ([BP+DI])
+#define MI_RMSI 0x04 // R/M = 4 ([SI])
+#define MI_RMDI 0x05 // R/M = 5 ([DI])
+#define MI_RMBP 0x06 // R/M = 6 ([BP])
+#define MI_RMBX 0x07 // R/M = 7 ([BX])
+
+// 32 bit instruction equates
+
+#define MI_SIB_SSMASK 0xc0
+#define MI_SIB_SSSHIFT 0x06
+
+#define MI_SIB_INDEXMASK 0x38
+#define MI_SIB_INDEXSHIFT 0x03
+#define MI_SIB_INDEXNONE 0x20
+
+#define MI_SIB_BASEMASK 0x07
+#define MI_SIB_BASESHIFT 0x00
+#define MI_SIB_BASEESP 0x04
+#define MI_SIB_BASENONE 0x05
+
+#define MI_RMEDX 0x02
+#define MI_RMSIB 0x04
+#define MI_RMDISP 0x05
+#define MI_RMEBP 0x05
+
+#define MI_REG6 0x30
+#define MI_REGCR0 0x00
+
+// following machine instructions are used in Enable_386_Specific_code
+// in virtmgr.asm
+
+#define MI_PUSH_AX 0x50 // "push ax" instruction
+#define MI_PUSH_IMM 0x68 // "push immediate 16/32" instruction
+#define MI_MOV_REG_IMM 0xB8 // opcode for "mov reg,immediate" instr
+#define MI_MOV_REG_IMMEDIATE 0xB8 // opcode for "mov reg,immediate" instr
+#define MI_MOV_REG_REGMEM 0x8B // opcode for "mov reg,r/m 16/32" instr
+
+// Miscellaneous Opcodes
+
+#define MI_ADD_AX_IMM 0x05 // Opcode for Add (E)AX,imm(32)16
+#define MI_CALL_NEAR_REL 0xE8 // Opcode for Call NEAR (relative)
+#define SIZE_CALL_NEAR_REL 5 // Length of Call NEAR (relative) instr
+
+#define MI_LMSW_OPCODE 0x01 // LMSW
+
+#define MI_GET_CRx_OPCODE 0x20 // MOV r32,CRx
+#define MI_GET_DRx_OPCODE 0x21 // MOV r32,DRx
+#define MI_SET_CRx_OPCODE 0x22 // MOV CRx,r32
+#define MI_SET_DRx_OPCODE 0x23 // MOV DRx,r32
+#define MI_GET_TRx_OPCODE 0x24 // MOV r32,TRx
+#define MI_SET_TRx_OPCODE 0x26 // MOV TRx,r32
+
+#define MI_MOV_REG8_MEM8 0x8A // MOV reg8,mem8
+#define MI_MOV_SEG_MEM_OPCODE 0x8e // MOV seg,r/m16
+
+typedef unsigned long ulong_t;
+typedef unsigned short ushort_t;
+typedef unsigned char uchar_t;
+typedef unsigned long vaddr_t;
+
+// WORD structure
+
+struct w_s {
+ uchar_t lobyte;
+ uchar_t hibyte;
+};
+#define LowByte lobyte
+#define HighByte hibyte
+
+// DWORD structure
+
+struct dw_s {
+ ushort_t loword;
+ ushort_t hiword;
+};
+#define LowWord loword
+#define HighWord hiword
+
+// Far pointer structure
+
+struct FarPtr {
+ ushort_t Offst;
+ ushort_t Segmt;
+};
+
+// Far 32 bit pointer structure
+
+struct FarPtr32 {
+ ulong_t Offst32; // 32 bit offset
+ ushort_t Segmt32; // segment
+ ushort_t Pad32; // segment pad
+};
+
+/*** RETF16 - 16 bit RETF frame definition
+ *
+ * 16 bit RETF frame structure
+ */
+
+typedef struct retf16_s {
+ ushort_t retf16_ip;
+ ushort_t retf16_cs;
+} RETF16;
+
+typedef RETF16 *PRETF16;
+
+/*** RETF32 - 32 bit RETF frame definition
+ *
+ * 32 bit RETF frame structure
+ */
+
+typedef struct retf32_s {
+ ulong_t retf32_eip;
+ ushort_t retf32_cs;
+ ushort_t retf32_padcs;
+} RETF32;
+
+typedef RETF32 *PRETF32;
+
+/*** IRET16 - 16 bit IRET frame definition
+ *
+ * 16 bit IRET frame structure
+ */
+
+typedef struct iret16_s {
+ ushort_t iret16_ip;
+ ushort_t iret16_cs;
+ ushort_t iret16_flag;
+} IRET16;
+
+typedef IRET16 *PIRET16;
+
+// 16 bit Iret stack frame without privilege level transition
+
+struct Iret_s {
+ struct FarPtr I_CSIP;
+ ushort_t I_FLAGS;
+};
+
+struct IretFrame {
+ ushort_t IretIP ;
+ ushort_t IretCS ;
+ ushort_t IretFLAGS;
+};
+
+/* ASM IretCSIP EQU <DWORD PTR IretIP> */
+
+/*** IRET32 - 32 bit IRET frame definition
+ *
+ * 32 bit IRET frame structure
+ */
+
+typedef struct iret32_s {
+ ulong_t iret32_eip;
+ ushort_t iret32_cs;
+ ushort_t iret32_padcs;
+ ulong_t iret32_eflag;
+} IRET32;
+
+typedef IRET32 *PIRET32;
+
+// 32 bit Iret stack frame without privilege level transition
+
+struct Iret32_s {
+ struct FarPtr32 I32_CSEIP;
+ ulong_t I32_EFLAGS;
+};
+/* ASM
+I32_CS EQU <I32_CSEIP.Segmt32>
+I32_EIP EQU <I32_CSEIP.Offst32>
+I32_IP EQU <I32_CSEIP.Offst32.loword>
+I32_FLAGS EQU <I32_EFLAGS.loword>
+*/
+
+/*** PLTIRET16 - 16 bit IRET frame definition
+ *
+ * 16 bit IRET frame structure with privilege level transtion
+ */
+
+typedef struct pltiret16_s {
+ ushort_t pltiret16_ip;
+ ushort_t pltiret16_cs;
+ ushort_t pltiret16_flag;
+ ushort_t pltiret16_sp;
+ ushort_t pltiret16_ss;
+} PLTIRET16;
+
+typedef PLTIRET16 *PPLTIRET16;
+
+// 16 bit Protected mode iret stack frame with privilege level transition
+
+struct PLTIret_s {
+ struct FarPtr PI_CSIP;
+ ushort_t PI_FLAGS;
+ struct FarPtr PI_SSSP;
+};
+
+struct PLTIretFrame {
+ ushort_t PLTIretIP;
+ ushort_t PLTIretCS;
+ ushort_t PLTIretFLAGS;
+ ushort_t PLTIretSP;
+ ushort_t PLTIretSS;
+};
+
+/* ASM
+PLTIretCSIP EQU DWORD PTR PLTIretIP
+PLTIretSSSP EQU DWORD PTR PLTIretSP
+*/
+
+/*** PLTIRET32 - 32 bit IRET frame definition
+ *
+ * 32 bit IRET frame structure with privilege level transtion
+ */
+
+typedef struct pltiret32_s {
+ ulong_t pltiret32_eip;
+ ushort_t pltiret32_cs;
+ ushort_t pltiret32_padcs;
+ ulong_t pltiret32_eflag;
+ ulong_t pltiret32_esp;
+ ushort_t pltiret32_ss;
+ ushort_t pltiret32_padss;
+} PLTIRET32;
+
+typedef PLTIRET32 *PPLTIRET32;
+
+// 32 bit Protected mode iret stack frame with privilege level transition
+
+struct PLTIret32_s {
+ struct FarPtr32 PI32_CSEIP;
+ ulong_t PI32_EFLAGS;
+ struct FarPtr32 PI32_SSESP;
+};
+/* ASM
+PI32_CS EQU <PI32_CSEIP.Segmt32>
+PI32_EIP EQU <PI32_CSEIP.Offst32>
+PI32_SS EQU <PI32_SSESP.Segmt32>
+PI32_ESP EQU <PI32_SSESP.Offst32>
+PI32_FLAGS EQU <WORD PTR PI32_EFLAGS>
+*/
+
+// Generic 32-bit pointer structure
+
+/* XLATOFF */
+union ptr_u {
+ struct FarPtr ptr_far16; /* 16-bit far pointer */
+ ulong_t ptr_flat; /* 32-bit flat pointer */
+};
+typedef union ptr_u ptr_t; /* Generic pointer type */
+
+#define ptr_sel ptr_far16.Segmt
+#define ptr_off ptr_far16.Offst
+/* XLATON */
+
+/* ASM
+ptr_t STRUC
+ ptr_flat DD ?
+ptr_t ENDS
+ptr_off equ <ptr_flat.Offst>
+ptr_sel equ <ptr_flat.Segmt>
+*/
+
+
+// PUSHA stack frame
+
+struct pusha_s {
+ ushort_t pas_di;
+ ushort_t pas_si;
+ ushort_t pas_bp;
+ ushort_t pas_sp;
+ ushort_t pas_bx;
+ ushort_t pas_dx;
+ ushort_t pas_cx;
+ ushort_t pas_ax;
+};
+
+// PUSHAD stack frame
+
+struct pushad_s {
+ ulong_t pads_edi;
+ ulong_t pads_esi;
+ ulong_t pads_ebp;
+ ulong_t pads_esp;
+ ulong_t pads_ebx;
+ ulong_t pads_edx;
+ ulong_t pads_ecx;
+ ulong_t pads_eax;
+};
+
+/* ASM
+pads_di EQU <WORD PTR pads_edi>
+pads_si EQU <WORD PTR pads_esi>
+pads_bp EQU <WORD PTR pads_ebp>
+pads_sp EQU <WORD PTR pads_esp>
+pads_bx EQU <WORD PTR pads_ebx>
+pads_dx EQU <WORD PTR pads_edx>
+pads_cx EQU <WORD PTR pads_ecx>
+pads_ax EQU <WORD PTR pads_eax>
+*/
diff --git a/private/os2/inc/monitor.h b/private/os2/inc/monitor.h
new file mode 100644
index 000000000..a188d508f
--- /dev/null
+++ b/private/os2/inc/monitor.h
@@ -0,0 +1,68 @@
+
+#ifndef _MONITOR_
+
+#define _MONITOR_
+
+#define MONITOR_DEFAULT 0x0000
+#define MONITOR_BEGIN 0x0001
+#define MONITOR_END 0x0002
+#define MONITOR_SPECIEL_DEFAULT 0x0003
+#define MONITOR_SPECIEL_BEGIN 0x0004
+#define MONITOR_SPECIEL_END 0x0005
+
+#define MIN_KBD_MON_BUFFER 64
+
+#pragma pack(1)
+
+typedef struct _MONIN /* mnin */
+{
+ USHORT cb;
+ BYTE abReserved[18];
+ BYTE abBuffer[108];
+} MONIN, *PMONIN;
+
+typedef struct _MONOUT /* mnout */
+{
+ USHORT cb;
+ UCHAR buffer[18];
+ BYTE abBuf[108];
+} MONOUT, *PMONOUT;
+
+typedef struct _KBD_MON_PACKAGE
+{
+ UCHAR MonitorFlag;
+ UCHAR DeviceFlag;
+ KBDKEYINFO KeyInfo;
+ USHORT KeyboardFlag;
+} KBD_MON_PACKAGE, *PKBD_MON_PACKAGE;
+
+typedef struct _MOU_MON_PACKAGE
+{
+ UCHAR MonitorFlag;
+ UCHAR DeviceFlag;
+ MOUEVENTINFO MouInfo;
+} MOU_MON_PACKAGE, *PMOU_MON_PACKAGE;
+
+#pragma pack()
+
+#define MON_REGISTERMONITOR 0x0040
+
+/*
+ * Monitor Flag
+ */
+
+#define MONITOR_OPEN_PACKAGE 1
+#define MONITOR_CLOSE_PACKAGE 2
+#define MONITOR_FLUSH_PACKAGE 4
+
+/*
+ * KeyboardFlag
+ */
+
+#define KBD_ACCENT_INDICATOR 0x0200 // 0000 0010 0000 0000
+#define KBD_MULTIMAKE 0x0100 // 0000 0001 0000 0000
+#define KBD_SCAN_CODE 0x0080 // 0000 0000 1000 0000
+#define KBD_KEY_BREAK 0x0040 // 0000 0000 0100 0000
+#define KBD_ZERO_USER 0xFC3F // 1111 1100 0011 1111
+
+#endif // _MONITOR_
diff --git a/private/os2/inc/nb30p.h b/private/os2/inc/nb30p.h
new file mode 100644
index 000000000..bccce431d
--- /dev/null
+++ b/private/os2/inc/nb30p.h
@@ -0,0 +1,83 @@
+
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ nb30p.h
+
+Abstract:
+
+ Private include file for the NB (NetBIOS) component of the NTOS project.
+
+Author:
+
+ Colin Watson (ColinW) 09-Dec-1991
+
+Revision History:
+
+--*/
+
+
+#ifndef _NB30P_
+#define _NB30P_
+
+#define NB_DEVICE_NAME L"\\Device\\Netbios" // name of our driver.
+
+//
+// private IOCTLs used by the Netbios routine in the dll to communicate with
+// \Device\Netbios
+//
+
+#define IOCTL_NB_BASE FILE_DEVICE_TRANSPORT
+
+#define _NB_CONTROL_CODE(request,method) \
+ CTL_CODE(IOCTL_NB_BASE, request, method, FILE_ANY_ACCESS)
+
+#define IOCTL_NB_NCB _NB_CONTROL_CODE(20,METHOD_NEITHER)
+
+//
+// MessageId: STATUS_HANGUP_REQUIRED
+//
+// MessageText:
+//
+// Warning error for the Netbios driver to the Netbios dll. When receiving this
+// status on an NCB completion, the dll will hangup the connection causing the
+// connection block to be deleted. This status will never be returned to a user
+// application.
+//
+#define STATUS_HANGUP_REQUIRED ((NTSTATUS)0x80010001L)
+
+//
+// Private extension for XNS to support vtp.exe
+//
+
+#define NCALLNIU 0x74 /* UB special */
+
+//
+// Private extension to support AsyBEUI
+//
+
+#define NCBQUICKADDNAME 0x75
+#define NCBQUICKADDGRNAME 0x76
+
+// Values for transport_id in ACTION_HEADER
+
+#define MS_ABF "MABF"
+#define MS_XNS "MXNS"
+
+// private OS/2SS stuff
+
+#define DEFAULT_NET 1 // default NET number for NetBiosSubmit
+
+#define NB2_INIT 0
+#define NB2_INIT_LANA 1
+#define NB2_LANA 2
+
+#define NB2ERR_SUCCESS 0
+#define NB2ERR_INVALID_LANA 1
+#define NB2ERR_INVALID_REQUEST 2
+
+#endif // _NB30P_
+
diff --git a/private/os2/inc/netb.h b/private/os2/inc/netb.h
new file mode 100644
index 000000000..b0866f62e
--- /dev/null
+++ b/private/os2/inc/netb.h
@@ -0,0 +1,133 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ netbios.h
+
+Abstract:
+
+ This is the main include file for the component of netbios that runs
+ in the user process.
+
+Author:
+
+ Colin Watson (ColinW) 24-Jun-91
+
+Revision History:
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windows.h>
+#include <nb30.h>
+#include "nb30p.h"
+
+//
+// Internal version of the ncb layout that uses the reserved area to hold
+// the list entry when passing ncb's to the worker thread and the IO status
+// block used when the ncb is passed to the netbios device driver.
+//
+
+#pragma pack(1)
+
+//
+// Use packing to ensure that the cu union is not forced to word alignment.
+// All elements of this structure are naturally aligned.
+//
+
+typedef struct _NCBI {
+ UCHAR ncb_command; /* command code */
+ volatile UCHAR ncb_retcode; /* return code */
+ UCHAR ncb_lsn; /* local session number */
+ UCHAR ncb_num; /* number of our network name */
+ PUCHAR ncb_buffer; /* address of message buffer */
+ WORD ncb_length; /* size of message buffer */
+ union {
+ UCHAR ncb_callname[NCBNAMSZ];/* blank-padded name of remote */
+ struct _CHAIN_SEND {
+ WORD ncb_length2;
+ PUCHAR ncb_buffer2;
+ } ncb_chain;
+ } cu;
+ UCHAR ncb_name[NCBNAMSZ]; /* our blank-padded netname */
+ UCHAR ncb_rto; /* rcv timeout/retry count */
+ UCHAR ncb_sto; /* send timeout/sys timeout */
+ void (CALLBACK *ncb_post)( struct _NCB * );
+ /* POST routine address */
+ UCHAR ncb_lana_num; /* lana (adapter) number */
+ volatile UCHAR ncb_cmd_cplt; /* 0xff => commmand pending */
+
+ // Make driver specific use of the reserved area of the NCB.
+ WORD ncb_reserved; /* return to natural alignment */
+ union {
+ LIST_ENTRY ncb_next; /* queued to worker thread */
+ IO_STATUS_BLOCK ncb_iosb; /* used for Nt I/O interface */
+ } u;
+
+ HANDLE ncb_event; /* HANDLE to Win32 event */
+ } NCBI, *PNCBI;
+
+#pragma pack()
+
+VOID
+QueueToWorker(
+ IN PNCBI pncb
+ );
+
+DWORD
+Worker(
+ IN LPVOID Parameter
+ );
+
+VOID
+SendNcbToDriver(
+ IN PNCBI pncb
+ );
+
+VOID
+PostRoutineCaller(
+ PVOID Context,
+ PIO_STATUS_BLOCK Status,
+ ULONG Reserved
+ );
+
+VOID
+ChainSendPostRoutine(
+ PVOID Context,
+ PIO_STATUS_BLOCK Status,
+ ULONG Reserved
+ );
+
+VOID
+HangupConnection(
+ PNCBI pUserNcb
+ );
+
+#if DBG
+
+VOID
+DisplayNcb(
+ IN PNCBI pncbi
+ );
+
+#define NbPrintf(String) NbPrint String;
+
+VOID
+NbPrint(
+ char *Format,
+ ...
+ );
+
+#else
+
+// Dispose of debug statements in non-debug builds.
+#define DisplayNcb( pncb ) {};
+
+#define NbPrintf( String ) {};
+
+#endif
+// End of Debug related definitions
diff --git a/private/os2/inc/netrqust.h b/private/os2/inc/netrqust.h
new file mode 100644
index 000000000..7bc045eb2
--- /dev/null
+++ b/private/os2/inc/netrqust.h
@@ -0,0 +1,338 @@
+#ifndef __NETRQUST_H
+#define __NETRQUST_H
+
+#define far
+#define near
+
+#define NEAR near
+#ifndef WINAPI
+#define WINAPI
+#endif
+#ifndef CALLBACK
+#define CALLBACK
+#endif
+#ifndef APIENTRY
+#define APIENTRY WINAPI
+#endif
+
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+typedef float FLOAT;
+typedef FLOAT *PFLOAT;
+typedef char near *PSTR;
+typedef char near *NPSTR;
+typedef char *LPSTR;
+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 far *LPLONG;
+typedef DWORD near *PDWORD;
+typedef DWORD far *LPDWORD;
+typedef void *PVOID;
+typedef void far *LPVOID;
+// typedef PVOID HANDLE;
+
+typedef int INT;
+typedef unsigned int UINT;
+typedef unsigned int *PUINT;
+
+//
+// UNICODE (Wide Character) types
+//
+
+typedef unsigned short WCHAR; // wc, 16-bit UNICODE character
+typedef WCHAR *LPWCH, *PWCH; // pwc
+typedef WCHAR *LPWSTR, *PWSTR; // pwsz, 0x0000 terminated UNICODE strings only
+
+//
+// Neutral ANSI/UNICODE types and macros
+//
+
+#include <lmcons.h> // LAN Manager common definitions
+// #include <lmerr.h> // LAN Manager network error definitions
+
+#include <lmchdev.h> // Character Device and Handle classes
+#include <lmaccess.h> // Access, Domain, Group and User classes
+#include <lmshare.h> // Connection, File, Session and Share classes
+#include <lmmsg.h> // Message class
+#include <lmremutl.h> // Remote Utility class
+#include <lmserver.h> // Server class
+#include <lmsvc.h> // Service class
+#include <lmuse.h> // Use class
+#include <lmwksta.h> // Workstation class
+#include <lmapibuf.h> // NetApiBuffer class
+#include <lmerrlog.h> // NetErrorLog class
+#include <lmconfig.h> // NetConfig class
+#include <lmstats.h> // NetStats class
+#include <lmaudit.h> // NetAudit class
+#include <nb30.h>
+
+/*
+ The following structures were used to pass messages between client and os2ses regarding Net Apis.
+ Since 11/30/92, all Net Apis are completely implemented in the client, so this communication is
+ no longer necessary. These structures are now obsolete.
+
+typedef struct _NETUSEADD_MSG {
+ ULONG Level;
+ ULONG Status;
+ ULONG AsgType;
+ ULONG RefCount;
+ ULONG UseCount;
+ BOOLEAN PasswordIsNull;
+} NETUSEADD_MSG, *PNETUSEADD_MSG;
+
+typedef struct _NETUSEADD_DATA {
+ TCHAR Server[UNCLEN];
+ TCHAR Local[DEVLEN];
+ TCHAR Remote[RMLEN];
+ TCHAR Password[PWLEN];
+} NETUSEADD_DATA, *PNETUSEADD_DATA;
+
+typedef struct _NETUSEDEL_MSG {
+ ULONG Force;
+} NETUSEDEL_MSG, *PNETUSEDEL_MSG;
+
+typedef struct _NETUSEDEL_DATA {
+ TCHAR Server[UNCLEN];
+ TCHAR UseName[RMLEN];
+} NETUSEDEL_DATA, *PNETUSEDEL_DATA;
+
+typedef struct _NETUSEENUM_MSG {
+ ULONG Level;
+ ULONG ResumeHandle;
+ ULONG EntriesRead;
+ ULONG TotalAvail;
+} NETUSEENUM_MSG, *PNETUSEENUM_MSG;
+
+typedef struct _NETUSEENUM_DATA {
+ TCHAR Server[UNCLEN];
+} NETUSEENUM_DATA, *PNETUSEENUM_DATA;
+
+typedef struct _NETUSEGETINFO_MSG {
+ ULONG Level;
+} NETUSEGETINFO_MSG, *PNETUSEGETINFO_MSG;
+
+typedef struct _NETUSEGETINFO_DATA {
+ TCHAR Server[UNCLEN];
+ TCHAR UseName[RMLEN];
+} NETUSEGETINFO_DATA, *PNETUSEGETINFO_DATA;
+
+typedef struct _NETUSERENUM_MSG {
+ ULONG Level;
+ ULONG ResumeHandle;
+ ULONG EntriesRead;
+ ULONG TotalAvail;
+} NETUSERENUM_MSG, *PNETUSERENUM_MSG;
+
+typedef struct _NETUSERENUM_DATA {
+ WCHAR Server[UNCLEN];
+} NETUSERENUM_DATA, *PNETUSERENUM_DATA;
+
+typedef struct _NETUSERGETINFO_MSG {
+ ULONG Level;
+} NETUSERGETINFO_MSG, *PNETUSERGETINFO_MSG;
+
+typedef struct _NETUSERGETINFO_DATA {
+ WCHAR Server[UNCLEN];
+ WCHAR UserName[UNLEN];
+} NETUSERGETINFO_DATA, *PNETUSERGETINFO_DATA;
+
+typedef struct _NETWKSTAGETINFO_MSG {
+ ULONG Level;
+} NETWKSTAGETINFO_MSG, *PNETWKSTAGETINFO_MSG;
+
+typedef struct _NETWKSTAGETINFO_DATA {
+ TCHAR Server[UNCLEN];
+} NETWKSTAGETINFO_DATA, *PNETWKSTAGETINFO_DATA;
+
+typedef struct _NETSHAREENUM_MSG {
+ ULONG Level;
+ ULONG ResumeHandle;
+ ULONG EntriesRead;
+ ULONG TotalAvail;
+} NETSHAREENUM_MSG, *PNETSHAREENUM_MSG;
+
+typedef struct _NETSHAREENUM_DATA {
+ TCHAR Server[UNCLEN];
+} NETSHAREENUM_DATA, *PNETSHAREENUM_DATA;
+
+typedef struct _NETSHAREGETINFO_MSG {
+ ULONG Level;
+} NETSHAREGETINFO_MSG, *PNETSHAREGETINFO_MSG;
+
+typedef struct _NETSHAREGETINFO_DATA {
+ TCHAR Server[UNCLEN];
+ TCHAR NetName[NNLEN];
+} NETSHAREGETINFO_DATA, *PNETSHAREGETINFO_DATA;
+
+typedef struct _NETSERVERDISKENUM_MSG {
+ ULONG Level;
+ ULONG ResumeHandle;
+ ULONG EntriesRead;
+ ULONG TotalAvail;
+} NETSERVERDISKENUM_MSG, *PNETSERVERDISKENUM_MSG;
+
+typedef struct _NETSERVERDISKENUM_DATA {
+ TCHAR Server[UNCLEN];
+} NETSERVERDISKENUM_DATA, *PNETSERVERDISKENUM_DATA;
+
+typedef struct _NETSERVERGETINFO_MSG {
+ ULONG Level;
+} NETSERVERGETINFO_MSG, *PNETSERVERGETINFO_MSG;
+
+typedef struct _NETSERVERGETINFO_DATA {
+ TCHAR Server[UNCLEN];
+ TCHAR Name[CNLEN];
+ TCHAR Comment[CNLEN];
+} NETSERVERGETINFO_DATA, *PNETSERVERGETINFO_DATA;
+
+typedef struct _NETSERVERENUM2_MSG {
+ ULONG Level;
+ ULONG ResumeHandle;
+ ULONG EntriesRead;
+ ULONG TotalAvail;
+ ULONG ServerType;
+} NETSERVERENUM2_MSG, *PNETSERVERENUM2_MSG;
+
+typedef struct _NETSERVERENUM2_DATA {
+ TCHAR Server[UNCLEN];
+ TCHAR Domain[CNLEN];
+} NETSERVERENUM_DATA, *PNETSERVERENUM2_DATA;
+
+typedef struct _NETSERVICECONTROL_MSG {
+ ULONG OpCode;
+ ULONG Arg;
+} NETSERVICECONTROL_MSG, *PNETSERVICECONTROL_MSG;
+
+typedef struct _NETSERVICECONTROL_DATA {
+ TCHAR Server[UNCLEN];
+ TCHAR Service[SNLEN];
+} NETSERVICECONTROL_DATA, *PNETSERVICECONTROL_DATA;
+
+typedef struct _NETSERVICEENUM_MSG {
+ ULONG Level;
+ ULONG ResumeHandle;
+ ULONG EntriesRead;
+ ULONG TotalAvail;
+} NETSERVICEENUM_MSG, *PNETSERVICEENUM_MSG;
+
+typedef struct _NETSERVICEENUM_DATA {
+ TCHAR Server[UNCLEN];
+} NETSERVICEENUM_DATA, *PNETSERVICEENUM_DATA;
+
+typedef struct _NETSERVICEGETINFO_MSG {
+ ULONG Level;
+} NETSERVICEGETINFO_MSG, *PNETSERVICEGETINFO_MSG;
+
+typedef struct _NETSERVICEGETINFO_DATA {
+ TCHAR Server[UNCLEN];
+ TCHAR Service[SNLEN];
+} NETSERVICEGETINFO_DATA, *PNETSERVICEGETINFO_DATA;
+
+typedef struct _NETSERVICEINSTALL_MSG {
+ ULONG Argc;
+} NETSERVICEINSTALL_MSG, *PNETSERVICEINSTALL_MSG;
+
+typedef struct _NETSERVICEINSTALL_DATA {
+ TCHAR Server[UNCLEN];
+ TCHAR Service[SNLEN];
+ TCHAR *CmdArgs;
+} NETSERVICEINSTALL_DATA, *PNETSERVICEINSTALL_DATA;
+
+typedef struct _NETGETDCNAME_MSG {
+ ULONG Dummy;
+} NETGETDCNAME_MSG, *PNETGETDCNAME_MSG;
+
+typedef struct _NETGETDCNAME_DATA {
+ WCHAR Server[UNCLEN];
+ WCHAR Domain[DNLEN];
+} NETGETDCNAME_DATA, *PNETGETDCNAME_DATA;
+
+typedef struct _NETACCESSADD_MSG {
+ ULONG Level;
+} NETACCESSADD_MSG, *PNETACCESSADD_MSG;
+
+typedef struct _NETACCESSADD_DATA {
+ TCHAR Server[UNCLEN];
+ ACCESS_INFO_1 AccessInfo;
+} NETACCESSADD_DATA, *PNETACCESSADD_DATA;
+
+typedef struct _NETACCESSSETINFO_MSG {
+ ULONG Level;
+ ACCESS_INFO_1002 AccessInfo1002;
+} NETACCESSSETINFO_MSG, *PNETACCESSSETINFO_MSG;
+
+typedef struct _NETACCESSSETINFO_DATA {
+ TCHAR Server[UNCLEN];
+ TCHAR Resource[NNLEN];
+ ACCESS_INFO_1 AccessInfo;
+} NETACCESSSETINFO_DATA, *PNETACCESSSETINFO_DATA;
+
+typedef struct _NETACCESSDEL_MSG {
+ ULONG Dummy;
+} NETACCESSDEL_MSG, *PNETACCESSDEL_MSG;
+
+typedef struct _NETACCESSDEL_DATA {
+ TCHAR Server[UNCLEN];
+ TCHAR Resource[NNLEN];
+} NETACCESSDEL_DATA, *PNETACCESSDEL_DATA;
+
+typedef struct _NETSHAREADD_MSG {
+ ULONG Level;
+} NETSHAREADD_MSG, *PNETSHAREADD_MSG;
+
+typedef struct _NETSHAREADD_DATA {
+ TCHAR Server[UNCLEN];
+ SHARE_INFO_2 ShareInfo;
+} NETSHAREADD_DATA, *PNETSHAREADD_DATA;
+
+typedef struct _NETSHAREDEL_MSG {
+ ULONG Dummy;
+} NETSHAREDEL_MSG, *PNETSHAREDEL_MSG;
+
+typedef struct _NETSHAREDEL_DATA {
+ TCHAR Server[UNCLEN];
+ TCHAR NetName[NNLEN];
+} NETSHAREDEL_DATA, *PNETSHAREDEL_DATA;
+
+typedef struct _NETBIOS_MSG {
+ ULONG NCB_Address;
+} NETBIOS_MSG, *PNETBIOS_MSG;
+
+typedef struct _NETBIOS_DATA {
+ NCB Ncb;
+} NETBIOS_DATA, *PNETBIOS_DATA;
+
+typedef union _NETMSG {
+ NETUSEADD_MSG NetUseAdd_Msg;
+ NETUSEDEL_MSG NetUseDel_Msg;
+ NETUSEENUM_MSG NetUseEnum_Msg;
+ NETUSEGETINFO_MSG NetUseGetInfo_Msg;
+ NETUSERENUM_MSG NetUserEnum_Msg;
+ NETUSERGETINFO_MSG NetUserGetInfo_Msg;
+ NETWKSTAGETINFO_MSG NetWkstaGetInfo_Msg;
+ NETSHAREENUM_MSG NetShareEnum_Msg;
+ NETSHAREGETINFO_MSG NetShareGetInfo_Msg;
+ NETSERVERDISKENUM_MSG NetServerDiskEnum_Msg;
+ NETSERVERGETINFO_MSG NetServerGetInfo_Msg;
+ NETSERVERENUM2_MSG NetServerEnum2_Msg;
+ NETSERVICECONTROL_MSG NetServiceControl_Msg;
+ NETSERVICEENUM_MSG NetServiceEnum_Msg;
+ NETSERVICEGETINFO_MSG NetServiceGetInfo_Msg;
+ NETSERVICEINSTALL_MSG NetServiceInstall_Msg;
+ NETGETDCNAME_MSG NetGetDCName_Msg;
+ NETACCESSADD_MSG NetAccessAdd_Msg;
+ NETACCESSSETINFO_MSG NetAccessSetInfo_Msg;
+ NETACCESSDEL_MSG NetAccessDel_Msg;
+ NETSHAREADD_MSG NetShareAdd_Msg;
+ NETSHAREDEL_MSG NetShareDel_Msg;
+ NETBIOS_MSG NetBios_Msg;
+} NETMSG, *PNETMSG;
+
+*/
+
+#endif
diff --git a/private/os2/inc/os2.h b/private/os2/inc/os2.h
new file mode 100644
index 000000000..e92adf5d5
--- /dev/null
+++ b/private/os2/inc/os2.h
@@ -0,0 +1,98 @@
+/*static char *SCCSID = "@(#)os2.h 13.5 89/06/12";*/
+/****************************** Module Header ******************************\
+*
+* Module Name: OS2.H
+*
+* This is the top level include file that includes all the files necessary
+* for writing an OS/2 application.
+*
+* Copyright (c) 1987 Microsoft Corporation
+* Copyright (c) 1987 IBM Corporation
+*
+\***************************************************************************/
+
+#define OS2_INCLUDED
+#define OS2_API32
+
+#ifdef NO_EXT_KEYS
+#define _syscall
+#define based
+#define near
+#define far
+#define cdecl
+#endif // NO_EXT_KEYS
+
+/* Common definitions */
+
+#include <ntdef.h>
+
+/* OS/2 Base Include File */
+
+#include <os2v20.h>
+
+/* OS/2 Presentation Manager Include File */
+
+// NOT INCLUDED FOR NOW - #include <pm.h>
+
+
+//
+// If debugging support enabled, define an ASSERT macro that works. Otherwise
+// define the ASSERT macro to expand to an empty expression.
+//
+
+#if DBG
+VOID
+RtlAssert(
+ IN PVOID FailedAssertion,
+ IN PVOID FileName,
+ IN ULONG LineNumber
+ );
+
+#define ASSERT( exp ) \
+ if (!(exp)) \
+ RtlAssert( #exp, __FILE__, __LINE__ )
+
+#else
+#define ASSERT( exp )
+#endif // DBG
+
+
+//
+// Fast primitives to zero and move memory
+//
+
+VOID
+RtlZeroMemory (
+ IN PVOID Destination,
+ IN ULONG Length
+ );
+
+VOID
+RtlMoveMemory (
+ IN PVOID Destination,
+ IN PVOID Source,
+ IN ULONG Length
+ );
+
+
+//
+// Debugging support functions.
+//
+
+VOID
+RtlCommandLineInterpreter(
+ PCH Prompt,
+ PCH DefaultVariableVector[] OPTIONAL,
+ PCH InitialCommandLine OPTIONAL
+ );
+
+VOID
+DbgBreakPoint(
+ VOID
+ );
+
+VOID
+DbgCommand(
+ PCH Command,
+ ULONG Parameter
+ );
diff --git a/private/os2/inc/os2crt.h b/private/os2/inc/os2crt.h
new file mode 100644
index 000000000..26eb5882b
--- /dev/null
+++ b/private/os2/inc/os2crt.h
@@ -0,0 +1,23 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2ssrtl.h
+
+Abstract:
+
+ Redefine names of CRT functions
+
+--*/
+
+#ifndef _OS2_RENAME_RUNTIME
+#define _OS2_RENAME_RUNTIME
+#define stricmp _stricmp
+#define strnicmp _strnicmp
+#define strupr _strupr
+#define itoa _itoa
+#define ltoa _ltoa
+#endif // _OS2_RENAME_RUNTIME
+
diff --git a/private/os2/inc/os2dbg.h b/private/os2/inc/os2dbg.h
new file mode 100644
index 000000000..12e4e18ca
--- /dev/null
+++ b/private/os2/inc/os2dbg.h
@@ -0,0 +1,129 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2dbg.h
+
+Abstract:
+
+ Debug constants
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Revision History:
+
+ Yaron Shamir 4-Apr-91 Add profile for ComputeValidDrives.
+ Beni Lavi 4-Oct-91 Moved debug constants from os2srv.h and os2dll.h
+ to this file.
+ Michael Jaruys 3-Jan-93 Move all Debug macro to this file and
+ make sure be don't have DbgPrint in retail code.
+--*/
+
+
+//
+// Define debugging flag as false if not defined already.
+//
+
+#ifndef DBG
+#define DBG 0
+#endif
+
+#if DBG
+
+#define OS2_DEBUG_TASKING 0x00000001
+#define OS2_DEBUG_FILESYS 0x00000002
+#define OS2_DEBUG_FSD 0x00000004
+#define OS2_DEBUG_MEMORY 0x00000008
+#define OS2_DEBUG_SEMAPHORES 0x00000010
+#define OS2_DEBUG_TIMERS 0x00000020
+#define OS2_DEBUG_LOADER 0x00000040
+#define OS2_DEBUG_NLS 0x00000080
+#define OS2_DEBUG_EXCEPTIONS 0x00000100
+#define OS2_DEBUG_ERRORMSG 0x00000200
+#define OS2_DEBUG_SESSIONMGR 0x00000400
+#define OS2_DEBUG_DEVICE_SUPPORT 0x00000800
+#define OS2_DEBUG_PIPES 0x00001000
+#define OS2_DEBUG_QUEUES 0x00002000
+#define OS2_DEBUG_INIT 0x00004000
+#define OS2_DEBUG_LPC 0x00008000
+#define OS2_DEBUG_CLEANUP 0x00010000
+#define OS2_DEBUG_FILESYSLOCK 0x00020000
+#define OS2_DEBUG_APIS 0x00040000
+#define OS2_DEBUG_BRK 0x00080000
+#define OS2_DEBUG_SIG 0x00100000
+#define OS2_DEBUG_VIO 0x00200000
+#define OS2_DEBUG_KBD 0x00400000
+#define OS2_DEBUG_MOU 0x00800000
+#define OS2_DEBUG_MON 0x01000000
+#define OS2_DEBUG_ALL_VIO 0x02000000
+/* For temporary messages, i.e used for a few debug
+ sessions. Such printings may be removed by anyone
+ who sees them. */
+#define OS2_DEBUG_TEMP 0x04000000
+#define OS2_DEBUG_OS2_EXE 0x08000000
+#define OS2_DEBUG_NET 0x10000000
+#define OS2_DEBUG_WIN 0x20000000
+#define OS2_DEBUG_MISC 0x80000000
+#define OS2_DEBUG_ANY 0xFFFFFFFF
+
+//#define OS2_DEBUG_ALL_VIO ( OS2_DEBUG_VIO | OS2_DEBUG_KBD | OS2_DEBUG_MOU | OS2_DEBUG_MON )
+#define OS2_DEBUG_VIO_FILE ( OS2_DEBUG_VIO | OS2_DEBUG_FILESYS )
+#define OS2_DEBUG_VIO_KBD_FILE ( OS2_DEBUG_VIO | OS2_DEBUG_KBD | OS2_DEBUG_FILESYS )
+#define OS2_DEBUG_KBD_FILE ( OS2_DEBUG_KBD | OS2_DEBUG_FILESYS )
+#define OS2_DEBUG_MOU_FILE ( OS2_DEBUG_MOU | OS2_DEBUG_FILESYS )
+
+//
+// Define IF_DEBUG macro that can be used to enable debugging code that is
+// optimized out if the debugging flag is false.
+//
+
+#define IF_OD2_DEBUG( ComponentFlag ) \
+ if (Os2Debug & (OS2_DEBUG_ ## ComponentFlag))
+
+#define IF_OD2_DEBUG2( Component1Flag, Component2Flag ) \
+ if (Os2Debug & ((OS2_DEBUG_ ## Component1Flag) | (OS2_DEBUG_ ## Component2Flag)))
+
+#define IF_OD2_DEBUG3( Component1Flag, Component2Flag, Component3Flag ) \
+ if (Os2Debug & ((OS2_DEBUG_ ## Component1Flag) | (OS2_DEBUG_ ## Component2Flag) | \
+ (OS2_DEBUG_ ## Component3Flag)))
+
+#define IF_OS2_DEBUG( ComponentFlag ) \
+ if (Os2Debug & (OS2_DEBUG_ ## ComponentFlag))
+
+#define IF_OS2_DEBUG2( Component1Flag, Component2Flag ) \
+ if (Os2Debug & ((OS2_DEBUG_ ## Component1Flag) | (OS2_DEBUG_ ## Component2Flag)))
+
+#define IF_OS2_DEBUG3( Component1Flag, Component2Flag, Component3Flag ) \
+ if (Os2Debug & ((OS2_DEBUG_ ## Component1Flag) | (OS2_DEBUG_ ## Component2Flag) | \
+ (OS2_DEBUG_ ## Component3Flag)))
+
+#else
+
+
+ /*
+ * Make sure be don't have DbgPrint in retail code
+ */
+
+#ifndef PMNT
+#ifdef DbgPrint
+#undef DbgPrint
+#endif // ifdef DbgPrint
+
+#define DbgPrint(_x_) \
+ Or2DbgPrintFunctionNeverExisted(_x_)
+#endif // PMNT
+
+//Dbg_Print_must_be_within_if_DBG_and_cannot_included_in_retail_code
+
+#define IF_OD2_DEBUG( ComponentFlag ) if (FALSE)
+#define IF_OD2_DEBUG2( Component1Flag, Component2Flag ) if (FALSE)
+#define IF_OD2_DEBUG3( Component1Flag, Component2Flag, Component3Flag ) if (FALSE)
+#define IF_OS2_DEBUG( ComponentFlag ) if (FALSE)
+#define IF_OS2_DEBUG2( Component1Flag, Component2Flag ) if (FALSE)
+#define IF_OS2_DEBUG3( Component1Flag, Component2Flag, Component3Flag ) if (FALSE)
+
+#endif // DBG
diff --git a/private/os2/inc/os2dev.h b/private/os2/inc/os2dev.h
new file mode 100644
index 000000000..bdff65026
--- /dev/null
+++ b/private/os2/inc/os2dev.h
@@ -0,0 +1,522 @@
+/**************************************************************************\
+*
+* Module Name: BSEDEV.H
+*
+* OS/2 Structures and constants for use with DosDevIOCtl
+*
+* Copyright (c) 1989-1990, Microsoft Corporation. All rights reserved.
+*
+\**************************************************************************/
+
+#define BSEDEV_INCLUDED
+
+/* Input and Output Control Categories */
+
+#define IOCTL_ASYNC 0x0001
+#define IOCTL_SCR_AND_PTRDRAW 0x0003
+#define IOCTL_KEYBOARD 0x0004
+#define IOCTL_PRINTER 0x0005
+#define IOCTL_LIGHTPEN 0x0006
+#define IOCTL_POINTINGDEVICE 0x0007
+#define IOCTL_DISK 0x0008
+#define IOCTL_PHYSICALDISK 0x0009
+#define IOCTL_MONITOR 0x000A
+#define IOCTL_GENERAL 0x000B
+
+/* Serial-Device Control */
+
+#define ASYNC_SETBAUDRATE 0x0041
+#define ASYNC_SETLINECTRL 0x0042
+#define ASYNC_TRANSMITIMM 0x0044
+#define ASYNC_SETBREAKOFF 0x0045
+#define ASYNC_SETMODEMCTRL 0x0046
+#define ASYNC_SETBREAKON 0x004B
+#define ASYNC_STOPTRANSMIT 0x0047
+#define ASYNC_STARTTRANSMIT 0x0048
+#define ASYNC_SETDCBINFO 0x0053
+#define ASYNC_GETBAUDRATE 0x0061
+#define ASYNC_GETLINECTRL 0x0062
+#define ASYNC_GETCOMMSTATUS 0x0064
+#define ASYNC_GETLINESTATUS 0x0065
+#define ASYNC_GETMODEMOUTPUT 0x0066
+#define ASYNC_GETMODEMINPUT 0x0067
+#define ASYNC_GETINQUECOUNT 0x0068
+#define ASYNC_GETOUTQUECOUNT 0x0069
+#define ASYNC_GETCOMMERROR 0x006D
+#define ASYNC_GETCOMMEVENT 0x0072
+#define ASYNC_GETDCBINFO 0x0073
+
+/* Screen/Pointer-Draw Control */
+
+#define SCR_ALLOCLDT 0x0070
+#define SCR_DEALLOCLDT 0x0071
+#define PTR_GETPTRDRAWADDRESS 0x0072
+#define SCR_ALLOCLDTOFF 0x0075
+
+/* Keyboard Control */
+
+#define KBD_SETTRANSTABLE 0x0050
+#define KBD_SETINPUTMODE 0x0051
+#define KBD_SETINTERIMFLAG 0x0052
+#define KBD_SETSHIFTSTATE 0x0053
+#define KBD_SETTYPAMATICRATE 0x0054
+#define KBD_SETFGNDSCREENGRP 0x0055
+#define KBD_SETSESMGRHOTKEY 0x0056
+#define KBD_SETFOCUS 0x0057
+#define KBD_SETKCB 0x0058
+#define KBD_SETNLS 0x005C
+#define KBD_CREATE 0x005D
+#define KBD_DESTROY 0x005E
+#define KBD_GETINPUTMODE 0x0071
+#define KBD_GETINTERIMFLAG 0x0072
+#define KBD_GETSHIFTSTATE 0x0073
+#define KBD_READCHAR 0x0074
+#define KBD_PEEKCHAR 0x0075
+#define KBD_GETSESMGRHOTKEY 0x0076
+#define KBD_GETKEYBDTYPE 0x0077
+#define KBD_GETCODEPAGEID 0x0078
+#define KBD_XLATESCAN 0x0079
+#if PMNT
+#define KBD_GETHARDWAREID 0x007A // Called by InitKeyboard(), PMWIN
+#define KBD_GETCPANDCOUNTRY 0x007B // Called by InitKeyboard(), PMWIN
+ // (the name is my invention - PatrickQ)
+#endif
+
+/* Printer Control */
+
+#define PRT_SETFRAMECTL 0x0042
+#define PRT_SETINFINITERETRY 0x0044
+#define PRT_INITPRINTER 0x0046
+#define PRT_ACTIVATEFONT 0x0048
+#define PRT_GETFRAMECTL 0x0062
+#define PRT_GETINFINITERETRY 0x0064
+#define PRT_GETPRINTERSTATUS 0x0066
+#define PRT_QUERYACTIVEFONT 0x0069
+#define PRT_VERIFYFONT 0x006A
+
+/* Pointing-Device (Mouse) Control */
+
+#define MOU_ALLOWPTRDRAW 0x0050
+#define MOU_UPDATEDISPLAYMODE 0x0051
+#define MOU_SCREENSWITCH 0x0052
+#define MOU_SETSCALEFACTORS 0x0053
+#define MOU_SETEVENTMASK 0x0054
+#define MOU_SETHOTKEYBUTTON 0x0055
+#define MOU_SETPTRSHAPE 0x0056
+#define MOU_DRAWPTR 0x0057
+#define MOU_REMOVEPTR 0x0058
+#define MOU_SETPTRPOS 0x0059
+#define MOU_SETPROTDRAWADDRESS 0x005A
+#define MOU_SETREALDRAWADDRESS 0x005B
+#define MOU_SETMOUSTATUS 0x005C
+#define MOU_DISPLAYMODECHANGE 0x005D
+#define MOU_GETBUTTONCOUNT 0x0060
+#define MOU_GETMICKEYCOUNT 0x0061
+#define MOU_GETMOUSTATUS 0x0062
+#define MOU_READEVENTQUE 0x0063
+#define MOU_GETQUESTATUS 0x0064
+#define MOU_GETEVENTMASK 0x0065
+#define MOU_GETSCALEFACTORS 0x0066
+#define MOU_GETPTRPOS 0x0067
+#define MOU_GETPTRSHAPE 0x0068
+#define MOU_GETHOTKEYBUTTON 0x0069
+#define MOU_VER 0x006A
+
+/* Disk/Diskette Control */
+
+#define DSK_LOCKDRIVE 0x0000
+#define DSK_UNLOCKDRIVE 0x0001
+#define DSK_REDETERMINEMEDIA 0x0002
+#define DSK_SETLOGICALMAP 0x0003
+#define DSK_BLOCKREMOVABLE 0x0020
+#define DSK_GETLOGICALMAP 0x0021
+#define DSK_SETDEVICEPARAMS 0x0043
+#define DSK_WRITETRACK 0x0044
+#define DSK_FORMATVERIFY 0x0045
+#define DSK_GETDEVICEPARAMS 0x0063
+#define DSK_READTRACK 0x0064
+#define DSK_VERIFYTRACK 0x0065
+
+/* Physical-Disk Control */
+
+#define PDSK_LOCKPHYSDRIVE 0x0000
+#define PDSK_UNLOCKPHYSDRIVE 0x0001
+#define PDSK_WRITEPHYSTRACK 0x0044
+#define PDSK_GETPHYSDEVICEPARAMS 0x0063
+#define PDSK_READPHYSTRACK 0x0064
+#define PDSK_VERIFYPHYSTRACK 0x0065
+
+/* Character-Monitor Control */
+
+#define MON_REGISTERMONITOR 0x0040
+
+/* General Device Control */
+
+#define DEV_FLUSHINPUT 0x0001
+#define DEV_FLUSHOUTPUT 0x0002
+#define DEV_QUERYMONSUPPORT 0x0060
+
+
+/* ASYNC_GETCOMMERROR, ASYNC_SETBREAKOFF, ASYNC_SETBREAKON,
+ * ASYNC_SETMODEMCTRL
+ */
+
+#define RX_QUE_OVERRUN 0x0001
+#define RX_HARDWARE_OVERRUN 0x0002
+#define PARITY_ERROR 0x0004
+#define FRAMING_ERROR 0x0008
+
+/* ASYNC_GETCOMMEVENT */
+
+#define CHAR_RECEIVED 0x0001
+#define LAST_CHAR_SENT 0x0004
+#define CTS_CHANGED 0x0008
+#define DSR_CHANGED 0x0010
+#define DCD_CHANGED 0x0020
+#define BREAK_DETECTED 0x0040
+#define ERROR_OCCURRED 0x0080
+#define RI_DETECTED 0x0100
+
+/* ASYNC_GETCOMMSTATUS */
+
+#define TX_WAITING_FOR_CTS 0x0001
+#define TX_WAITING_FOR_DSR 0x0002
+#define TX_WAITING_FOR_DCD 0x0004
+#define TX_WAITING_FOR_XON 0x0008
+#define TX_WAITING_TO_SEND_XON 0x0010
+#define TX_WAITING_WHILE_BREAK_ON 0x0020
+#define TX_WAITING_TO_SEND_IMM 0x0040
+#define RX_WAITING_FOR_DSR 0x0080
+
+/* ASYNC_GETLINESTATUS */
+
+#define WRITE_REQUEST_QUEUED 0x0001
+#define DATA_IN_TX_QUE 0x0002
+#define HARDWARE_TRANSMITTING 0x0004
+#define CHAR_READY_TO_SEND_IMM 0x0008
+#define WAITING_TO_SEND_XON 0x0010
+#define WAITING_TO_SEND_XOFF 0x0020
+
+/* ASYNC_GETMODEMINPUT */
+
+#define CTS_ON 0x10
+#define DSR_ON 0x20
+#define RI_ON 0x40
+#define DCD_ON 0x80
+
+/* DSK_SETDEVICEPARAMS */
+
+#define BUILD_BPB_FROM_MEDIUM 0x00
+#define REPLACE_BPB_FOR_DEVICE 0x01
+#define REPLACE_BPB_FOR_MEDIUM 0x02
+
+/* KBD_GETINPUTMODE, KBD_PEEKCHAR, KBD_SETINPUTMODE*/
+
+#define ASCII_MODE 0x00
+#define BINARY_MODE 0x80
+
+/* KBD_GETINTERIMFLAG */
+
+#define CONVERSION_REQUEST 0x20
+#define INTERIM_CHAR 0x80
+
+/* KBD_GETSESMGRHOTKEY */
+
+#define HOTKEY_MAX_COUNT 0x0000
+#define HOTKEY_CURRENT_COUNT 0x0001
+
+/* KBD_PEEKCHAR */
+
+#define KBD_DATA_RECEIVED 0x0001
+#define KBD_DATA_BINARY 0x8000
+
+/* KBD_READCHAR */
+
+#define KBD_READ_WAIT 0x0000
+#define KBD_READ_NOWAIT 0x8000
+
+/* KBD_SETINPUTMODE */
+
+#define SHIFT_REPORT_MODE 0x01
+
+#ifndef INCL_MOU
+
+#define MOUSE_MOTION 0x0001
+#define MOUSE_MOTION_WITH_BN1_DOWN 0x0002
+#define MOUSE_BN1_DOWN 0x0004
+#define MOUSE_MOTION_WITH_BN2_DOWN 0x0008
+#define MOUSE_BN2_DOWN 0x0010
+#define MOUSE_MOTION_WITH_BN3_DOWN 0x0020
+#define MOUSE_BN3_DOWN 0x0040
+
+#define MHK_BUTTON1 0x0001
+#define MHK_BUTTON2 0x0002
+#define MHK_BUTTON3 0x0004
+
+#ifndef MOU_NOWAIT
+#define MOU_NOWAIT 0x0000
+#endif
+#ifndef MOU_WAIT
+#define MOU_WAIT 0x0001
+#endif
+
+#endif /* #ifndef INCL_MOU */
+
+/* MOU_GETHOTKEYBUTTON, MOU_SETHOTKEYBUTTON */
+
+#define MHK_NO_HOTKEY 0x0000
+
+/* MOU_GETMOUSTATUS */
+
+#define MOUSE_QUEUEBUSY 0x0001
+#define MOUSE_BLOCKREAD 0x0002
+#define MOUSE_FLUSH 0x0004
+#define MOUSE_UNSUPPORTED_MODE 0x0008
+#define MOUSE_DISABLED 0x0100
+#define MOUSE_MICKEYS 0x0200
+
+/* PRT_GETPRINTERSTATUS */
+
+#define PRINTER_TIMEOUT 0x0001
+#define PRINTER_IO_ERROR 0x0008
+#define PRINTER_SELECTED 0x0010
+#define PRINTER_OUT_OF_PAPER 0x0020
+#define PRINTER_ACKNOWLEDGED 0x0040
+#define PRINTER_NOT_BUSY 0x0080
+
+/* fbCtlHndShake */
+
+#define MODE_DTR_CONTROL 0x01
+#define MODE_DTR_HANDSHAKE 0x02
+#define MODE_CTS_HANDSHAKE 0x08
+#define MODE_DSR_HANDSHAKE 0x10
+#define MODE_DCD_HANDSHAKE 0x20
+#define MODE_DSR_SENSITIVITY 0x40
+
+/* fbFlowReplace */
+
+#define MODE_AUTO_TRANSMIT 0x01
+#define MODE_AUTO_RECEIVE 0x02
+#define MODE_ERROR_CHAR 0x04
+#define MODE_NULL_STRIPPING 0x08
+#define MODE_BREAK_CHAR 0x10
+#define MODE_RTS_CONTROL 0x40
+#define MODE_RTS_HANDSHAKE 0x80
+#define MODE_TRANSMIT_TOGGLE 0xC0
+
+/* fbTimeout */
+
+#define MODE_NO_WRITE_TIMEOUT 0x01
+#define MODE_READ_TIMEOUT 0x02
+#define MODE_WAIT_READ_TIMEOUT 0x04
+#define MODE_NOWAIT_READ_TIMEOUT 0x06
+
+#pragma pack(1)
+
+typedef struct _DCBINFO { /* dcbinf */
+ USHORT usWriteTimeout;
+ USHORT usReadTimeout;
+ BYTE fbCtlHndShake;
+ BYTE fbFlowReplace;
+ BYTE fbTimeout;
+ BYTE bErrorReplacementChar;
+ BYTE bBreakReplacementChar;
+ BYTE bXONChar;
+ BYTE bXOFFChar;
+} DCBINFO, *PDCBINFO;
+
+typedef struct _TRACKLAYOUT { /* trckl */
+ BYTE bCommand;
+ USHORT usHead;
+ USHORT usCylinder;
+ USHORT usFirstSector;
+ USHORT cSectors;
+ struct {
+ USHORT usSectorNumber;
+ USHORT usSectorSize;
+ } TrackTable[1];
+} TRACKLAYOUT, *PTRACKLAYOUT;
+
+#define DEVTYPE_48TPI 0x0000
+#define DEVTYPE_96TPI 0x0001
+#define DEVTYPE_35 0x0002
+#define DEVTYPE_8SD 0x0003
+#define DEVTYPE_8DD 0x0004
+#define DEVTYPE_FIXED 0x0005
+#define DEVTYPE_TAPE 0x0006
+#define DEVTYPE_UNKNOWN 0x0007
+
+typedef struct _BIOSPARAMETERBLOCK { /* bspblk */
+ USHORT usBytesPerSector;
+ BYTE bSectorsPerCluster;
+ USHORT usReservedSectors;
+ BYTE cFATs;
+ USHORT cRootEntries;
+ USHORT cSectors;
+ BYTE bMedia;
+ USHORT usSectorsPerFAT;
+ USHORT usSectorsPerTrack;
+ USHORT cHeads;
+ ULONG cHiddenSectors;
+ ULONG cLargeSectors;
+ BYTE abReserved[6];
+ USHORT cCylinders;
+ BYTE bDeviceType;
+ USHORT fsDeviceAttr;
+} BIOSPARAMETERBLOCK, *PBIOSPARAMETERBLOCK;
+
+typedef struct _SCREENGROUP { /* scrgrp */
+ USHORT idScreenGrp;
+ USHORT fTerminate;
+} SCREENGROUP, *PSCREENGROUP;
+
+typedef struct _FRAME { /* frm */
+ BYTE bCharsPerLine;
+ BYTE bLinesPerInch;
+} FRAME, *PFRAME;
+
+typedef struct _KBDTYPE { /* kbdtyp */
+ USHORT usType;
+ USHORT reserved1;
+ USHORT reserved2;
+} KBDTYPE, *PKBDTYPE;
+
+typedef struct _LINECONTROL { /* lnctl */
+ BYTE bDataBits;
+ BYTE bParity;
+ BYTE bStopBits;
+ BYTE fTransBreak;
+} LINECONTROL, *PLINECONTROL;
+
+/* MODEMSTATUS.fbModemOn, ASYNC_GETMODEMOUTPUT */
+
+#define DTR_ON 0x01
+#define RTS_ON 0x02
+
+/* MODEMSTATUS.fbModemOff */
+
+#define DTR_OFF 0xFE
+#define RTS_OFF 0xFD
+
+typedef struct _MODEMSTATUS { /* mdmst */
+ BYTE fbModemOn;
+ BYTE fbModemOff;
+} MODEMSTATUS, *PMODEMSTATUS;
+
+typedef struct _TRACKFORMAT { /* trckfmt */
+ BYTE bCommand;
+ USHORT usHead;
+ USHORT usCylinder;
+ USHORT usReserved;
+ USHORT cSectors;
+ struct {
+ BYTE bCylinder;
+ BYTE bHead;
+ BYTE idSector;
+ BYTE bBytesSector;
+ } FormatTable[1];
+} TRACKFORMAT, *PTRACKFORMAT;
+
+typedef struct _RXQUEUE { /* rxq */
+ USHORT cch;
+ USHORT cb;
+} RXQUEUE, *PRXQUEUE;
+
+typedef struct _DEVICEPARAMETERBLOCK { /* dvpblck */
+ USHORT reserved1;
+ USHORT cCylinders;
+ USHORT cHeads;
+ USHORT cSectorsPerTrack;
+ USHORT reserved2;
+ USHORT reserved3;
+ USHORT reserved4;
+ USHORT reserved5;
+} DEVICEPARAMETERBLOCK, *PDEVICEPARAMETERBLOCK;
+
+#ifndef PFN
+typedef int (*PFN)();
+#endif
+
+typedef struct _PTRDRAWFUNCTION { /* ptrdfnc */
+ USHORT usReturnCode;
+ PFN pfnDraw;
+ CHAR* pchDataSeg;
+} PTRDRAWFUNCTION, *PPTRDRAWFUNCTION;
+
+typedef struct _PTRDRAWADDRESS { /* ptrdaddr */
+ USHORT reserved;
+ PTRDRAWFUNCTION ptrdfnc;
+} PTRDRAWADDRESS, *PPTRDRAWADDRESS;
+
+typedef struct _SHIFTSTATE { /* shftst */
+ USHORT fsState;
+ BYTE fNLS;
+} SHIFTSTATE, *PSHIFTSTATE;
+
+/* HOTKEY.fsHotKey/SHIFTSTATE.fsState */
+
+//#define RIGHTSHIFT 0x0001
+//#define LEFTSHIFT 0x0002
+//#define CONTROL 0x0004
+//#define ALT 0x0008
+//#define SCROLLLOCK_ON 0x0010
+//#define NUMLOCK_ON 0x0020
+//#define CAPSLOCK_ON 0x0040
+//#define INSERT_ON 0x0080
+//#define LEFTCONTROL 0x0100
+//#define LEFTALT 0x0200
+//#define RIGHTCONTROL 0x0400
+//#define RIGHTALT 0x0800
+//#define SCROLLLOCK 0x1000
+//#define NUMLOCK 0x2000
+//#define CAPSLOCK 0x4000
+//#define SYSREQ 0x8000
+
+typedef struct _HOTKEY { /* htky */
+ USHORT fsHotKey;
+ UCHAR uchScancodeMake;
+ UCHAR uchScancodeBreak;
+ USHORT idHotKey;
+} HOTKEY, *PHOTKEY;
+
+typedef struct _MONITORPOSITION { /* mnpos */
+ USHORT fPosition;
+ USHORT index;
+ ULONG pbInBuf;
+ USHORT offOutBuf;
+} MONITORPOSITION, *PMONITORPOSITION;
+
+typedef struct _RATEDELAY { /* rtdly */
+ USHORT usDelay;
+ USHORT usRate;
+} RATEDELAY, *PRATEDELAY;
+
+typedef struct _CODEPAGEINFO { /* cpi */
+ PBYTE pbTransTable;
+ USHORT idCodePage;
+ USHORT idTable;
+} CODEPAGEINFO, *PCODEPAGEINFO;
+
+typedef struct _CPID { /* cpid */
+ USHORT idCodePage;
+ USHORT Reserved;
+} CPID, *PCPID;
+
+typedef struct _LDTADDRINFO { /* ldtaddr */
+ PULONG pulPhysAddr;
+ USHORT cb;
+} LDTADDRINFO, *PLDTADDRINFO;
+
+typedef struct _PTRDRAWDATA { /* ptrdd */
+ USHORT cb;
+ USHORT usConfig;
+ USHORT usFlag;
+} PTRDRAWDATA, *PPTRDRAWDATA;
+
+typedef struct _FONTINFO {
+ USHORT idCodePage;
+ USHORT idFont;
+} FONTINFO, *PFONTINFO;
+
+#pragma pack()
+
diff --git a/private/os2/inc/os2dll.h b/private/os2/inc/os2dll.h
new file mode 100644
index 000000000..b290f13fa
--- /dev/null
+++ b/private/os2/inc/os2dll.h
@@ -0,0 +1,1202 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2dll.h
+
+Abstract:
+
+ Main include file for OS/2 Subsystem Client DLL
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Revision History:
+
+--*/
+
+//
+// Include OS/2 SubSystem Runtime Definitions. Includes NT Definitions
+// OS/2 V2.0 Definitions and Debug definitions.
+//
+
+#include "os2ssrtl.h"
+
+#if DBG
+extern ULONG Os2Debug;
+#endif
+
+//
+// Include definitions of API Calls exported by the OS/2 Subsystem Server
+// (i.e. the stub procedure definitions).
+//
+#include "dllfile.h"
+#include "os2ssmsg.h"
+
+
+//
+// Common Types and Definitions
+//
+
+//
+// OD2_HEAP_MEMORY_SIZE defines how much address space should be
+// reserved for the OS/2 Client heap. This heap is used to store all
+// data structures maintained by the OS/2 Client DLL.
+//
+
+#define OD2_HEAP_MEMORY_SIZE (64*1024)
+
+
+//
+// OD2_PORT_MEMORY_SIZE defines how much address space should be
+// reserved for passing data to the OS/2 Server. The memory is visible
+// to both the client and server processes.
+//
+
+#define OD2_PORT_MEMORY_SIZE 0x10000
+
+
+//
+// OD2_SEMAPHORE and its related types are the client represenation of OS/2
+// shared semaphores and the entire representation of private OS/2 semaphores.
+//
+
+typedef enum _OD2_SEMAPHORE_TYPE {
+ Od2EventSem = 1,
+ Od2MutexSem,
+ Od2MuxWaitSem
+} OD2_SEMAPHORE_TYPE;
+
+typedef struct _OD2_MUTEX_SEMAPHORE {
+ HANDLE MutantHandle;
+ ULONG OwnerRequestLevel;
+ TID OwnerTid;
+} OD2_MUTEX_SEMAPHORE, *POD2_MUTEX_SEMAPHORE;
+
+typedef struct _OD2_MUXWAIT_RECORD {
+ HSEM SemHandle;
+ ULONG UserKey;
+ struct _OD2_SEMAPHORE *Semaphore;
+} OD2_MUXWAIT_RECORD, *POD2_MUXWAIT_RECORD;
+
+typedef struct _OD2_MUXWAIT_SEMAPHORE {
+ USHORT CountMuxWaitRecords;
+ USHORT Type : 2;
+ USHORT WaitAll : 1;
+ USHORT Reserved : 13;
+ OD2_MUXWAIT_RECORD MuxWaitRecords[ DCMW_MAX_SEMRECORDS ];
+} OD2_MUXWAIT_SEMAPHORE, *POD2_MUXWAIT_SEMAPHORE;
+
+typedef struct _OD2_SEMAPHORE {
+ USHORT PointerCount : 13;
+ USHORT Type : 2;
+ USHORT Shared : 1;
+ USHORT OpenCount;
+ union {
+ PVOID Value;
+ HANDLE EventHandle;
+ POD2_MUTEX_SEMAPHORE Mutex;
+ POD2_MUXWAIT_SEMAPHORE MuxWait;
+ } u;
+} OD2_SEMAPHORE, *POD2_SEMAPHORE;
+
+typedef struct _OD2_QUEUE {
+ ULONG OpenCount;
+ PID OwnerProcessId;
+} OD2_QUEUE, *POD2_QUEUE;
+
+//
+// The OD2_PROCESS and OD2_THREAD data structures describe the OS/2 Client
+// process. Both data structures are allocated from the Od2Heap.
+//
+
+typedef struct _OD2_PROCESS {
+ HANDLE TaskLock;
+ RTL_RESOURCE FileLock;
+ LIST_ENTRY ThreadList;
+ LIST_ENTRY ExitList;
+ RESULTCODES ResultCodes; // Valid if PS_EXITLIST is set in Pib.Status
+ ULONG ErrorAction;
+ ULONG VerifyFlag;
+ ULONG MaximumFileHandles;
+ ULONG DefaultDisk;
+ BOOLEAN BoundApp;
+ POR2_HANDLE_TABLE PrivateSemaphoreTable;
+ POR2_HANDLE_TABLE SharedSemaphoreTable;
+ POR2_QHANDLE_TABLE QueueTable;
+ LIST_ENTRY MsgFileList;
+ UCHAR ApplName[OS2_PROCESS_MAX_APPL_NAME];
+ PIB Pib; // Make this the last field in the
+ // the structure so client cant inadvertantly
+ // muck with the other fields in OD2_PROCESS
+} OD2_PROCESS, *POD2_PROCESS;
+
+
+
+
+#define OD2_ENABLE_HARD_ERROR_POPUP 0x1
+#define OD2_ENABLE_ACCESS_VIO_POPUP 0x2
+
+typedef struct _OD2_THREAD {
+ LIST_ENTRY Link;
+ PFNTHREAD StartAddress; // Used to pass startup information
+ ULONG Parameter; // ... to Od2UserThreadStartup
+ POD2_SEMAPHORE WaitingForSemaphore;
+ ULONG Saved32Esp;
+ ULONG ApiIndex;
+ HANDLE ThreadHandle;
+ HANDLE Event; // DosCreateThread use this event to get
+ // notification from the thread that it has
+ // be created and initialized
+ // DosSuspendThread use it to suspend thread in
+ // 32 bit
+ ULONG Flags; // Parameter of DosCreateThread
+ APIRET rc; // Return code of the thread during startup
+ // to DosCreateThread
+ OS2_TIB Os2Tib; // OS2 specific part of the TIB
+ // (subsystem portable part is in TEB)
+ // Make this the last field in the
+ // the structure so client can't inadvertantly
+ // muck with the other fields in OD2_THREAD
+} OD2_THREAD, *POD2_THREAD;
+
+
+typedef struct _OS2_EXITLISTENTRY {
+ LIST_ENTRY Link;
+ ULONG Order;
+ PFNEXITLIST ExitRoutine;
+ ULONG flag;
+} OD2_EXITLISTENTRY, *POS2_EXITLISTENTRY;
+
+typedef struct _OD2_CONTEXT_SAVE_AREA {
+ LOCALINFOSEG TebBlock;
+ ULONG Saved16Stack;
+ BOOLEAN SignalHandlingInProgress;
+ USHORT SegEs;
+ USHORT SegDs;
+} OD2_CONTEXT_SAVE_AREA, *POD2_CONTEXT_SAVE_AREA;
+
+#define Od2CurrentThreadId() \
+ ( \
+ ((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer)) ? \
+ (((POD2_THREAD)(NtCurrentTeb()->EnvironmentPointer))->Os2Tib.ThreadId) : \
+ 0 \
+ )
+
+
+//
+// The Lock field in an OS/2 Process object protects the fields of the process
+// data structure. This includes the list of thread objects attached
+// to the process object and the list of exit procedures.
+//
+//
+// If the process is dieing, and there is only thread 1, there is no
+// need for the lock, and we should not try it incase we terminated
+// a thread inside (Acquire .. Release) block.
+//
+/*
+#define AcquireTaskLock() \
+ if ((!Od2SigHandlingInProgress) || ((Od2CurrentThreadId()) != 1)) \
+ RtlEnterCriticalSection( &Od2Process->TaskLock )
+#define ReleaseTaskLock() \
+ if ((!Od2SigHandlingInProgress) || ((Od2CurrentThreadId()) != 1)) \
+ RtlLeaveCriticalSection( &Od2Process->TaskLock )
+*/
+
+NTSTATUS AcquireTaskLock(VOID);
+NTSTATUS ReleaseTaskLock(VOID);
+
+#if DBG
+//
+// dllutil.c
+//
+
+VOID
+AcquireFileLockShared(
+ IN PSZ CallingRoutine
+ );
+
+VOID
+ReleaseFileLockShared(
+ IN PSZ CallingRoutine
+ );
+
+VOID
+PromoteFileLocktoExclusive(
+ IN PSZ CallingRoutine
+ );
+
+VOID
+AcquireFileLockExclusive(
+ IN PSZ CallingRoutine
+ );
+
+VOID
+ReleaseFileLockExclusive(
+ IN PSZ CallingRoutine
+ );
+
+#else
+#define PromoteFileLocktoExclusive(x) RtlConvertSharedToExclusive( &Od2Process->FileLock )
+
+VOID
+AcquireFileLockShared( VOID );
+
+VOID
+ReleaseFileLockShared( VOID );
+
+VOID
+AcquireFileLockExclusive( VOID );
+
+VOID
+ReleaseFileLockExclusive( VOID );
+
+#endif
+
+//
+// Global data accessed by Client DLL
+//
+
+//
+// dllnls.c
+//
+
+#define Od2ProcessCodePage Or2ProcessCodePage
+#define Od2CurrentCodePageIsOem Or2CurrentCodePageIsOem
+
+#define Od2InitMBString Or2InitMBString
+#define Od2MBStringToUnicodeString Or2MBStringToUnicodeString
+#define Od2CreateUnicodeStringFromMBz Or2CreateUnicodeStringFromMBz
+#define Od2UnicodeStringToMBString Or2UnicodeStringToMBString
+#define Od2FreeMBString Or2FreeMBString
+
+//
+// The Od2NtSysInfo global variable contains NT specific constants of
+// interest, such as page size, allocation granularity, etc. It is filled
+// in once during process initialization.
+//
+
+extern SYSTEM_BASIC_INFORMATION Od2NtSysInfo;
+
+#define ROUND_UP_TO_PAGES(SIZE) (((ULONG)(SIZE) + Od2NtSysInfo.PageSize - 1) & ~(Od2NtSysInfo.PageSize - 1))
+#define ROUND_DOWN_TO_PAGES(SIZE) (((ULONG)(SIZE)) & ~(Od2NtSysInfo.PageSize - 1))
+
+//
+// The Od2DebugFlag is non-zero if the OS/2 Client Application was invoked
+// with the Debug option.
+//
+
+extern ULONG Od2DebugFlag;
+
+
+//
+// The Od2Heap global variable describes a single heap used by the Client DLL
+// for process wide storage management. The process data structure, thread
+// data structures, file handle table, current directory structures, etc. are
+// all allocated out of this heap.
+//
+
+extern PVOID Od2Heap;
+
+
+//
+// The Od2Environment variable points to a block of memory that contains the
+// OS/2 Environment block. Od2EnvSize describes how much virtual address space
+// is reserved at this location.
+//
+
+extern PVOID Od2Environment;
+extern ULONG Od2EnvSize;
+
+
+//
+// The Od2BootDrive and Od2SystemDrive define the meaning of \BootDevice and
+// \SystemDisk respectively.
+//
+
+extern ULONG Od2BootDrive;
+extern ULONG Od2SystemDrive;
+
+
+//
+// The connection to the OS/2 Emulation Subsystem is described by the
+// Od2PortHandle global variable. The connection is established during
+// process initialization by Od2ProcessStartup.
+//
+
+extern HANDLE Od2PortHandle;
+
+
+//
+// In order to pass large arguments to the OS/2 Emulation Subsystem (e.g.
+// path name arguments) the Od2PortHeap global variable describes a
+// heap that is visible to both the OS/2 Client process and the OS/2
+// Emulation Subsystem.
+//
+
+extern PVOID Od2PortHeap;
+extern ULONG Od2PortMemoryRemoteDelta;
+
+//
+// The Od2Process global variable points to the OD2_PROCESS structure for
+// the client process. It is allocated out of Od2Heap.
+//
+
+extern POD2_PROCESS Od2Process;
+
+
+//
+// The Od2Thread1 global variable points to the first thread structure for
+// the client process. It is allocated out of Od2Heap.
+//
+
+extern POD2_THREAD Od2Thread1;
+
+
+//
+// The Od2DllHandle global variable contains the DLL handle for the OS2DLL
+// client stubs executable.
+//
+
+extern HMODULE Od2DllHandle;
+
+
+//
+// The Od2DeviceDirecotory global variable contains the handle to the
+// \OS2SS\DEVICES directory in the object name space.
+//
+
+extern HANDLE Od2DeviceDirectory;
+
+//
+// Od2NtLibPath replaces what in Os2 1.X is kept in the kernel
+// The DLl get's it from the subsystem
+//
+extern PSZ Od2NtLibPath;
+extern USHORT Od2NtLibPathLength;
+
+//
+// Od2LibPath holds the search path for the loader to load
+// the OS/2 specific DLLs. This search path may be different than the
+// NT LibPath since some OS/2 thunk DLLs conflict in name with NT DLLs
+// (like netapi.dll)
+//
+extern PSZ Od2LibPath;
+extern USHORT Od2LibPathLength;
+
+//
+//
+// Od2DllInitialize does the OS/2 Client DLL initialization of all of
+// the above global variables. It is a DLL Initialization routine.
+//
+
+BOOLEAN
+Od2DllInitialize(
+ IN PVOID DllHandle,
+ IN ULONG Reason,
+ IN PCONTEXT Context OPTIONAL
+ );
+
+
+//
+//
+// Od2ProcessStartup is the modified start address for OS/2 applications.
+// The DLL Initialization procedure makes this the new start address if
+// it successfully initializes the client process. This function in turns
+// calls the application entry point with the OS/2 defined process startup
+// parameters.
+//
+
+VOID
+Od2ProcessStartup(
+ IN PPEB Peb
+ );
+
+
+//
+// The Od2InitializeTask procedure is called by the Od2ProcessStartup code
+// to initialize the tasking component of the OS/2 Client DLL.
+//
+
+NTSTATUS
+Od2InitializeTask( VOID );
+
+
+NTSTATUS
+Od2InitializeThread(
+ IN POD2_THREAD Thread
+ );
+
+
+VOID
+Od2UserThreadStartup(
+ IN POD2_THREAD Thread
+ );
+
+//
+// Common Exec Message formatter used by DosExecPgm and DosStartSession
+//
+
+APIRET
+Od2FormatExecPgmMessage(
+ OUT POS2_DOSEXECPGM_MSG a,
+ OUT POS2_CAPTURE_HEADER *CaptureBuffer,
+ OUT PNTSTATUS Od2IsConsoleTypeReturnStatus,
+#if PMNT
+ OUT PULONG IsPMApp,
+#endif // PMNT
+ IN PSZ ErrorText,
+ IN LONG MaximumErrorTextLength,
+ IN ULONG Flags,
+ IN OUT PSZ *VariablesBuffer,
+ IN OUT PSZ *ArgumentBuffer,
+ IN PSZ *ImageFileName
+ );
+
+NTSTATUS
+Od2IsFileConsoleType(
+ PSTRING NtImagePathName
+#if PMNT
+ ,
+ PULONG IsPMApp
+#endif // PMNT
+ );
+
+//
+// routines defined in dllinit.c
+//
+
+extern PUCHAR Od2SystemRoot;
+
+ULONG
+Od2ProcessException(
+ IN PEXCEPTION_POINTERS ExceptionInfo,
+ OUT PEXCEPTION_RECORD ExceptionRecord
+ );
+
+VOID
+Od2ExceptionHandler(
+ IN PEXCEPTION_RECORD ExceptionRecord
+ );
+
+//
+// Routines defined in dllsem.c
+//
+
+//
+// The following bit masks define the fields within a 32 bit semaphore
+// handle.
+//
+
+#define SEM_SHARED 0x80000000
+#define SEM_HANDLESIG 0x00010000 // 32-bit handle signature
+#define SEM_SIGBITS 0x7FFF0000 // Isolates 32-bit signature bits
+#define SEM_INDEX 0x0000FFFF
+
+APIRET
+Od2CaptureSemaphoreName(
+ IN PSZ ObjectName,
+ IN ULONG ExtraCaptureBufferLength OPTIONAL,
+ OUT POS2_CAPTURE_HEADER *CaptureBuffer,
+ OUT PSTRING CapturedObjectName
+ );
+
+
+POR2_HANDLE_TABLE
+Od2GetSemaphoreTable(
+ BOOLEAN SharedSem,
+ BOOLEAN CreateOkay
+ );
+
+
+HSEM
+Od2ConstructSemaphoreHandle(
+ IN BOOLEAN SharedSem,
+ IN ULONG Index
+ );
+
+
+APIRET
+Od2ValidateSemaphoreHandle(
+ IN HSEM SemaphoreHandle,
+ OUT PBOOLEAN SharedSem,
+ OUT PULONG Index
+ );
+
+POD2_SEMAPHORE
+Od2ReferenceSemaphore(
+ IN POD2_SEMAPHORE Semaphore
+ );
+
+VOID
+Od2DereferenceSemaphore(
+ IN POD2_SEMAPHORE Semaphore
+ );
+
+VOID
+Od2ThreadWaitingOnSemaphore(
+ IN POR2_HANDLE_TABLE SemaphoreTable,
+ IN POD2_SEMAPHORE Semaphore,
+ IN BOOLEAN AboutToWait
+ );
+
+POD2_THREAD
+Od2SearchForWaitingThread(
+ IN POD2_SEMAPHORE Semaphore
+ );
+
+VOID
+Od2SemaphoreDestroyProcedure(
+ IN POD2_SEMAPHORE Semaphore,
+ IN ULONG HandleIndex
+ );
+
+VOID
+Od2CloseAllSemaphores( VOID );
+
+
+#if DBG
+
+VOID
+Od2SemaphoreDumpProcedure(
+ IN POD2_SEMAPHORE Semaphore,
+ IN ULONG HandleIndex,
+ IN PVOID DumpParameter
+ );
+
+VOID
+Od2DumpAllSemaphores(
+ IN PCHAR Title
+ );
+
+#endif // DBG
+
+
+//
+// Routines defined in dllmuxwt.c
+//
+
+APIRET
+Od2AddMuxWait(
+ IN POD2_MUXWAIT_SEMAPHORE MuxWait,
+ IN PSEMRECORD MuxWaitEntry
+ );
+
+
+APIRET
+Od2DeleteMuxWait(
+ IN POD2_MUXWAIT_SEMAPHORE MuxWait,
+ IN ULONG MuxWaitEntryIndex,
+ IN HSEM MuxWaitEntrySem OPTIONAL
+ );
+
+
+//
+// Routines defined in dlltimer.c
+//
+
+NTSTATUS
+Od2InitializeTimers(VOID);
+
+VOID
+Od2CloseAllTimers(VOID);
+
+
+//
+// Definitions for dllflopy.c
+//
+
+VOID
+Od2DiskIOInitialize(
+ VOID
+ );
+
+VOID
+Od2DiskIOTerminate(
+ VOID
+ );
+
+
+//
+// Routines defined in dllname.c
+//
+
+APIRET
+Od2Canonicalize(
+ IN PSZ Path,
+ IN ULONG ExpectedType,
+ OUT PSTRING OutputString,
+ OUT PHANDLE OutputDirectory OPTIONAL,
+ OUT PULONG ParseFlags OPTIONAL,
+ OUT PULONG FileType OPTIONAL
+ );
+
+//
+// Valid values for ExpectedType parameter
+//
+
+#define CANONICALIZE_FILE_DEV_OR_PIPE 0x00000000
+#define CANONICALIZE_FILE_OR_DEV 0x00000001
+#define CANONICALIZE_SHARED_MEMORY 0x00000002
+#define CANONICALIZE_SEMAPHORE 0x00000003
+#define CANONICALIZE_QUEUE 0x00000004
+#define CANONICALIZE_MAILSLOT 0x00000005
+
+//
+// Flag definitions returned via the ParseFlags parameter
+//
+
+#define CANONICALIZE_META_CHARS_FOUND 0x00000001
+#define CANONICALIZE_IS_ROOT_DIRECTORY 0x00000002
+
+//
+// Maximum length of NT specific prefix that is placed at the beginning
+// of the canonical output string.
+//
+
+#define CANONICALIZE_MAX_PREFIX_LENGTH 32
+#define IS_OBJ_NAME_PATH_SEPARATOR(ch) ((ch == '\\') || (ch == '\0'))
+
+BOOLEAN
+Od2IsAbsolutePath(
+ IN PSZ Path
+ );
+
+
+//
+// Routines defined in dllque.c
+//
+
+POR2_QHANDLE_TABLE
+Od2GetQueueTable(
+ BOOLEAN CreateOkay
+ );
+
+APIRET
+Od2ValidateQueueSemaphore(
+ IN HSEM EventHandle,
+ IN PULONG HandleIndex
+ );
+
+VOID
+Od2CloseAllQueues( VOID );
+
+VOID
+Od2QueueDestroyProcedure(
+ IN POD2_QUEUE Semaphore,
+ IN ULONG HandleIndex
+ );
+
+//
+// Routines defined in dllutil.c
+//
+
+APIRET
+Od2CallSubsystem(
+ IN OUT POS2_API_MSG m,
+ IN OUT POS2_CAPTURE_HEADER CaptureBuffer OPTIONAL,
+ IN OS2_API_NUMBER ApiNumber,
+ IN ULONG ArgLength
+ );
+
+POS2_CAPTURE_HEADER
+Od2AllocateCaptureBuffer(
+ IN ULONG CountMessagePointers,
+ IN ULONG CountCapturePointers,
+ IN ULONG Size
+ );
+
+VOID
+Od2FreeCaptureBuffer(
+ IN POS2_CAPTURE_HEADER CaptureBuffer
+ );
+
+ULONG
+Od2AllocateMessagePointer(
+ IN OUT POS2_CAPTURE_HEADER CaptureBuffer,
+ IN ULONG Length,
+ OUT PVOID *Pointer
+ );
+
+ULONG
+Od2AllocateCapturePointer(
+ IN OUT POS2_CAPTURE_HEADER CaptureBuffer,
+ IN ULONG Length,
+ OUT PVOID *Pointer
+ );
+
+VOID
+Od2CaptureMessageString(
+ IN OUT POS2_CAPTURE_HEADER CaptureBuffer,
+ IN PCHAR String,
+ IN ULONG Length,
+ IN ULONG MaximumLength,
+ OUT PSTRING CapturedString
+ );
+
+void
+Od2StartTimeout(
+ PLARGE_INTEGER StartTimeStamp
+ );
+
+NTSTATUS
+Od2ContinueTimeout(
+ PLARGE_INTEGER StartTimeStamp,
+ PLARGE_INTEGER Timeout
+ );
+
+PLARGE_INTEGER
+Od2CaptureTimeout(
+ IN ULONG Milliseconds,
+ OUT PLARGE_INTEGER Timeout
+ );
+
+VOID
+Od2ProbeForWrite(
+ IN PVOID Address,
+ IN ULONG Length,
+ IN ULONG Alignment
+ );
+
+VOID
+Od2ProbeForRead(
+ IN PVOID Address,
+ IN ULONG Length,
+ IN ULONG Alignment
+ );
+
+APIRET
+Od2CaptureObjectName(
+ IN PSZ ObjectName,
+ IN ULONG ObjectType,
+ IN ULONG ExtraCaptureBufferLength OPTIONAL,
+ OUT POS2_CAPTURE_HEADER *CaptureBuffer,
+ OUT PSTRING CapturedObjectName
+ );
+
+PWSTR
+Od2CopyStrToWstr(
+ IN OUT PWSTR wstr OPTIONAL,
+ IN PSZ str
+ );
+
+int
+Od2WstrSize(
+ IN PWSTR pwstr
+ );
+
+PSZ
+Od2CopyWstrToStr(
+ IN OUT PSZ str OPTIONAL,
+ IN PWSTR wstr
+ );
+
+PSZ Od2nCopyWstrToStr(
+ IN OUT PSZ str OPTIONAL,
+ IN PWSTR wstr,
+ IN int n
+ );
+
+APIRET Od2FixFEA2List(
+ IN FEA2LIST *fpFEA2List);
+
+VOID
+Od2ExitGP();
+
+BOOLEAN
+RetryIO(
+ IN NTSTATUS Status,
+ IN HANDLE Handle
+ );
+
+BOOLEAN
+RetryCreateOpen(
+ IN NTSTATUS Status,
+ IN POBJECT_ATTRIBUTES pObja
+ );
+
+//
+// Routines defined in dlltask.c
+//
+
+VOID
+Od2ProcessCleanup( VOID );
+
+
+VOID
+Od2DosExit(
+ ULONG ExitAction,
+ ULONG ExitResult,
+ ULONG ExitReason);
+
+//
+// Routines defined in dllxcpt.c
+//
+
+APIRET
+Od2AcknowledgeSignalException(
+ IN ULONG SignalNumber
+ );
+
+VOID
+_Od2VectorHander( VOID );
+
+//
+// Routines defined in dllthunk.s
+//
+
+VOID
+_Od2ExitListDispatcher( VOID );
+
+VOID
+Od2JumpToExitRoutine(
+ IN PFNEXITLIST ExitRoutine,
+ IN ULONG ExitReason
+ );
+
+VOID
+_Od2SignalDeliverer(
+ IN PCONTEXT pContext,
+ IN int Signal
+ );
+
+VOID
+_Od2ProcessSignal16(
+ IN POS2_REGISTER16_SIGNAL pa
+ );
+
+VOID
+_Od2FreezeThread(
+ IN PCONTEXT pContext
+ );
+
+VOID
+_Od2UnfreezeThread(
+ IN PCONTEXT pContext
+ );
+
+//
+// Routines defined in dllhandl.c
+//
+
+APIRET
+OpenCreatePath(
+ OUT PHANDLE FileHandle,
+ IN ULONG DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN PIO_STATUS_BLOCK IoStatus,
+ IN ULONG CreateSize,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttributes,
+ IN BOOLEAN OpenDirectory
+ );
+
+APIRET
+MapFileType(
+ IN HANDLE FileHandle,
+ OUT PBOOLEAN Directory OPTIONAL,
+ OUT PUSHORT FileType,
+ OUT PUSHORT DeviceAttribute
+ );
+
+BOOLEAN
+CheckFileType(
+ IN HANDLE FileHandle,
+ IN USHORT FileTypes
+ );
+
+APIRET
+AllocateHandle(
+ OUT PHFILE FileHandle
+ );
+
+APIRET
+FreeHandle(
+ IN HFILE FileHandle
+ );
+
+APIRET
+DereferenceFileHandle(
+ IN HFILE FileHandle,
+ OUT PFILE_HANDLE *hFileRecord
+ );
+
+PFILE_HANDLE
+DereferenceFileHandleNoCheck(
+ IN HFILE FileHandle
+ );
+
+VOID
+InvalidateHandle(
+ IN PFILE_HANDLE hFileRecord
+ );
+
+VOID
+ValidateHandle(
+ IN PFILE_HANDLE hFileRecord
+ );
+
+
+//
+// Routines defined in fileinit.c
+//
+
+APIRET
+Od2InitializeFileSystemForExec(
+ IN ULONG ParentTableLength, // number of entries in handle table
+ IN ULONG CurrentDrive // current drive in parent process
+ );
+
+APIRET
+Od2InitializeFileSystemForSM(
+ IN ULONG DefaultDrive, // default drive for this session
+ IN HANDLE StandardInput,
+ IN HANDLE StandardOutput,
+ IN HANDLE StandardError
+ );
+
+APIRET
+Od2InitializeFileSystemForChildSM(
+ IN ULONG ParentTableLength, // number of entries in handle table
+ IN ULONG CurrentDrive // current drive in parent process
+ );
+
+APIRET
+Od2InitCurrentDir(
+ IN ULONG CurrentDisk
+ );
+
+//
+// Routines defined in name.c
+//
+
+APIRET
+Canonicalize(
+ IN PSZ Name,
+ IN ULONG Flags,
+ OUT PHANDLE Handle,
+ OUT PSTRING CanonicalString,
+ OUT PUSHORT FileType,
+ OUT PBOOLEAN MetaCharacters,
+ OUT PBOOLEAN RootDirectory
+ );
+
+PSZ
+FindLastComponent(
+ IN PSZ String
+ );
+
+//
+// Routines defined in dllea.c
+//
+
+BOOLEAN
+NtTimeToFatTimeAndDate (
+ OUT PFTIME FatTime,
+ OUT PFDATE FatDate,
+ IN LARGE_INTEGER NtTime
+ );
+
+APIRET
+GetEaListLength(
+ IN HANDLE NtHandle,
+ OUT PULONG EaListSize
+);
+
+APIRET
+GetGEAList(
+ IN HANDLE NtHandle,
+ OUT PBYTE UserBuffer,
+ IN ULONG Length
+);
+
+//
+// Routines defined in dllea.c
+//
+
+VOID
+MapAttributesToOs2(
+ IN ULONG NtAttributes,
+ OUT PUSHORT Os2Attributes
+ );
+
+APIRET
+MapEaListToNt(
+ IN OUT PBYTE UserBuffer,
+ IN ULONG Length,
+ OUT PVOID *Buffer,
+ OUT PULONG ListLength,
+ OUT PULONG BufferLength
+);
+
+
+//
+// Routines defined in dlldir.c
+//
+
+APIRET
+Od2GetCurrentDirectory(
+ IN ULONG DiskNumber,
+ OUT PSTRING *CurrentDirectoryString,
+ OUT PHANDLE CurrentDirectoryHandle,
+ IN OUT PULONG DirectoryNameLength,
+ IN BOOLEAN Verify
+ );
+
+//
+// Routines defined in coninit.c
+//
+
+NTSTATUS Od2InitializeSessionPort(OUT PBOOLEAN RootProcessInSession);
+
+//
+// Routines defined in dllmsg.c
+//
+
+
+#define COMP_ID_LEN 3 // length of component ID
+
+
+//
+// header for a 16 bit (OS/2 1.X) message segment
+//
+
+typedef struct _MSGSEGMENT_HEADER16 {
+ BYTE Signature[10]; // "\xffMKMSGSEG"
+ USHORT Version; // should be 1
+ USHORT Reserved;
+ USHORT FileTableOffset;
+} MSGSEGMENT_HEADER16, *PMSGSEGMENT_HEADER16;
+
+
+typedef struct _OD2_MSGFILE {
+ LIST_ENTRY Link;
+ HANDLE SectionHandle;
+ PVOID BaseAddress;
+ ULONG Size;
+ ULONG Type;
+ STRING FileName;
+} OD2_MSGFILE, *POD2_MSGFILE;
+
+#define MSG_FILE_TYPE_OS2_20 0
+#define MSG_FILE_TYPE_OS2_1x 1
+
+typedef struct _OD2_MSGFILE_HEADER {
+ ULONG HeaderLength;
+ CHAR Signature[ 8 ];
+ CHAR Component[ COMP_ID_LEN ];
+ CHAR Reserved[ 5 ];
+ ULONG CountOfMessages;
+ ULONG BaseMessageId;
+ ULONG MessageOffsets[ 1 ];
+} OD2_MSGFILE_HEADER, *POD2_MSGFILE_HEADER;
+
+APIRET
+Od2FindMessageFile(
+ IN PSZ MessageFileName,
+ OUT POD2_MSGFILE *ReturnedMsgFile
+ );
+
+//
+// OD2_MESSAGE_RESOURCE_FILENAME defines the file
+// string, that if specified as the MessageFileName parameter to DosGetMessage
+// or DosQueryMessageCP, will cause the function to access the data in
+// the OS/2 system message file.
+//
+
+#define OD2_MESSAGE_RESOURCE_FILENAME "OSO001.MSG"
+
+
+//
+// Od2MsgFile variable points to an OD2_MSGFILE structure that represents the
+// OSO001.MSG resource contained in the OS/2 DLL image file.
+//
+
+extern POD2_MSGFILE Od2MsgFile;
+
+//
+// This function will initialize the Od2MsgFile variable.
+//
+
+NTSTATUS
+Od2InitializeMessageFile( VOID );
+
+// Signal numbers
+// these are also defined in os2srv.h, so if the values change be sure
+// to change them there
+
+#define SIGNAL_TO_FLAG(Signal) (1 << (Signal - 1))
+
+#define SIGAPTERM 8 // Asynchronous PTERM
+#define SIGPTERM 9 // Synchronous PTERM
+
+// Signal flags
+
+#define SIGINTRF (1 << (XCPT_SIG_INTR - 1)) // Ctrl-C
+#define SIGTERMF (1 << (XCPT_SIG_KILLPROC - 1)) // program termination
+#define SIGBREAKF (1 << (XCPT_SIG_BREAK - 1)) // Ctrl-Break
+#define SIGAPTERMF (1 << (SIGAPTERM - 1)) // Asyncronous PTERM
+
+/* Vector exception handlers */
+
+#define VECTOR_DIVIDE_BY_ZERO 0x0000
+#define VECTOR_OVERFLOW 0x0004
+#define VECTOR_OUTOFBOUNDS 0x0005
+#define VECTOR_INVALIDOPCODE 0x0006
+#define VECTOR_NO_EXTENSION 0x0007
+#define VECTOR_EXTENSION_ERROR 0x0010
+
+typedef struct _OD2_VEC_HANDLER_REC {
+ ULONG VecHandler[6];
+ ULONG doscallssel;
+} OD2_VEC_HANDLER_REC, *POD2_VEC_HANDLER_REC;
+
+#define FIELD_SIZE(type, field) (sizeof( ((type *)0)->field ))
+
+//
+// Support for mapping c:\config.sys
+// to the OS/2 SS directory
+//
+
+BOOLEAN
+Od2FileIsConfigSys(
+ IN OUT PANSI_STRING FileName_A,
+ IN ULONG AccessMode,
+ OUT PNTSTATUS ResultStatus
+ );
+
+//
+// routines in dllnb.c
+//
+
+
+VOID
+Od2NetbiosInitialize(
+ VOID
+ );
+
+VOID
+Od2NetbiosDelete(
+ VOID
+ );
+
+
+/* Fix for a C8 compilation warning */
+#undef TRUE
+#define TRUE (BOOLEAN)1
+
+#undef FALSE
+#define FALSE (BOOLEAN)0
+
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))? (a):(b))
+#endif
+
diff --git a/private/os2/inc/os2dll16.h b/private/os2/inc/os2dll16.h
new file mode 100644
index 000000000..b24b96723
--- /dev/null
+++ b/private/os2/inc/os2dll16.h
@@ -0,0 +1,322 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ os2dll16.h
+
+Abstract:
+
+ Main include file for OS/2 Subsystem Client 16 bit API support
+
+Author:
+
+ Yaron Shamir (YaronS) 15-Apr-1991
+
+Revision History:
+
+ add SEG_SIZABLE (NirM) 7-jan-1993
+
+--*/
+
+
+/* Segment attribute flags (used with DosAllocSeg) */
+
+#define SEG_NONSHARED 0x0000
+#define SEG_GIVEABLE 0x0001
+#define SEG_GETTABLE 0x0002
+#define SEG_DISCARDABLE 0x0004
+#define SEG_SIZEABLE 0x0008
+
+//
+// Support for Huge Segments: we keep, per client, a linked
+// list of HugeSegRecord records, each containing the info on
+// base selector, maximum selectors for reallocation and link
+// forward. This is used by DosFreeSeg to free up all the memory
+// and selectors involved, and by DosReallocHuge to adhere to
+// 1.X sematics for Huge Segments
+//
+
+typedef struct _HUGE_SEG_RECORD {
+ struct HUGE_SEG_RECORD *Next;
+ ULONG MaxNumSeg;
+ ULONG cNumSeg;
+ ULONG BaseSelector;
+ ULONG PartialSeg;
+ BOOLEAN fShared;
+ BOOLEAN fSizeable;
+} HUGE_SEG_RECORD, *PHUGE_SEG_RECORD;
+
+PHUGE_SEG_RECORD pHugeSegHead;
+
+#define SEL_RPL3 0x3 // Rpl Ring 3
+#define SEL_RPLCLR 0xfffc // Non RPL bits mask
+
+/* LDT Descriptor (as defined by the NT support routines) */
+
+typedef enum _I386DESCRIPTOR_TYPE {
+ INVALID, EXECUTE_CODE, EXECUTE_READ_CODE, READ_DATA, READ_WRITE_DATA
+} I386DESCRIPTOR_TYPE;
+typedef struct _I386DESCRIPTOR {
+ ULONG BaseAddress;
+ ULONG Limit;
+ I386DESCRIPTOR_TYPE Type;
+} I386DESCRIPTOR;
+
+//
+// A high-level routine profile for LDT support. NT supports HW-like API
+//
+NTSTATUS
+Nt386SetDescriptorLDT
+ (
+ HANDLE LDT,
+ ULONG Sel,
+ I386DESCRIPTOR Desc
+ );
+
+#include "os2tile.h"
+
+
+typedef unsigned short SEL;
+
+typedef SEL *PSEL;
+
+typedef unsigned short SHANDLE;
+typedef void *LHANDLE;
+
+//typedef LHANDLE HSYSSEM;
+
+//typedef HSYSSEM *PHSYSSEM;
+
+typedef USHORT PID16;
+
+typedef PID16 *PPID16;
+
+typedef USHORT TID16;
+
+typedef TID16 *PTID16;
+
+#pragma pack(1)
+typedef struct _PIDINFO16 {
+ PID16 pid;
+ TID16 tid;
+ PID16 pidParent;
+} PIDINFO16, *PPIDINFO16;
+#pragma pack()
+
+#define INCL_16
+#define INCL_DOS
+#define FAR
+#define PASCAL
+#define BOOL BOOLEAN
+#define INCL_NOXLATE_DOS16
+// #include "bsedos16.h"
+#include "os2v12.h"
+
+
+typedef struct _FILEFINDBUF1 { /* findbuf for DosFindFirst */
+ FDATE fdateCreation;
+ FTIME ftimeCreation;
+ FDATE fdateLastAccess;
+ FTIME ftimeLastAccess;
+ FDATE fdateLastWrite;
+ FTIME ftimeLastWrite;
+ ULONG cbFile;
+ ULONG cbFileAlloc;
+ USHORT attrFile;
+ UCHAR cchName;
+ CHAR achName[13];
+} FILEFINDBUF1;
+typedef FILEFINDBUF1 FAR *PFILEFINDBUF1;
+
+//
+// OS2 1.X Sempahore types
+//
+// We simulate the multi-semantic OS2 1.x Semaphore by two
+// object, an event and a mutex.
+// Clear - clear them both (Release, Post)
+//
+
+
+typedef struct _OS21X_SEM {
+ PVOID pMyself; // Myself makes RAM and SYS semaphore
+ // Handles to look the same (both becomes
+ // a pointer to an OS21X_SEM sempahore
+ //
+ HSEM Mutex;
+ TID OwnerThread;
+ USHORT RequestCount;
+ UCHAR FlagsByte;
+ UCHAR SysSemCount;
+ HSEM Event;
+ union {
+ ULONG SharedRamSignature; // in use for Ram Sem.
+ PCHAR SysSemName; // in use for System Sem. (its name)
+ } u;
+ struct OS21X_SEM *Next; // Per process list for cleanup
+} OS21X_SEM, *POS21X_SEM;
+
+#define SYSSEM_QUEUE 4
+#define SYSSEM_PRIVATE 2
+#define SYSSEM_PUBLIC 1
+
+
+ //
+ // per process Semaphore list head
+ //
+
+struct OS21X_SEM *Od2Sem16ListHead;
+
+ //
+ // FSRAM Semaphores (Fast Safe RAM)
+ //
+#pragma pack(1)
+typedef struct _DOSFSRSEM16 {
+ USHORT cb;
+ PID16 pid;
+ TID16 tid;
+ USHORT cUsage;
+ USHORT client;
+ ULONG sem;
+} DOSFRSEM16, *PDOSFSRSEM16;
+#pragma pack()
+
+BOOLEAN Od2ExitListInProgress;
+
+typedef struct _OS21X_CS {
+ SEL selCS;
+ struct OS21X_CS *Next;
+} OS21X_CS, *POS21X_CS;
+
+typedef struct _OS21X_CSALIAS {
+ SEL selDS;
+ POS21X_CS pCSList;
+ HANDLE SectionHandle;
+ struct OS21X_CSALIAS *Next;
+} OS21X_CSALIAS, *POS21X_CSALIAS;
+
+struct OS21X_CSALIAS *Od2CSAliasListHead;
+
+#pragma pack(1)
+typedef struct _OD2_MSGFILE_HEADER16 {
+ UCHAR HeaderMsgFF;
+ CHAR Signature[ 7 ];
+ CHAR Component[ 3 ];
+ USHORT CountOfMessages;
+ USHORT BaseMessageId;
+ CHAR Reserved[ 16 ];
+ USHORT MessageOffsets[ 1 ];
+} OD2_MSGFILE_HEADER16, *POD2_MSGFILE_HEADER16;
+
+typedef struct _OD2_MSGFILE_HEADER_SYS16 {
+ UCHAR HeaderMsgFF;
+ CHAR Signature[ 7 ];
+ CHAR Component[ 3 ];
+ USHORT CountOfMessages;
+ USHORT BaseMessageId;
+ CHAR Reserved[ 16 ];
+ ULONG MessageOffsets[ 1 ];
+} OD2_MSGFILE_HEADER_SYS16, *POD2_MSGFILE_HEADER_SYS16;
+
+typedef struct _COUNTRYCODE16 {
+ USHORT country;
+ USHORT codepage;
+} COUNTRYCODE16, *PCOUNTRYCODE16;
+
+typedef struct _COUNTRYINFO16 {
+ USHORT country;
+ USHORT codepage;
+ USHORT fsDateFmt;
+ CHAR szCurrency[5];
+ CHAR szThousandsSeparator[2];
+ CHAR szDecimal[2];
+ CHAR szDateSeparator[2];
+ CHAR szTimeSeparator[2];
+ UCHAR fsCurrencyFmt;
+ UCHAR cDecimalPlace;
+ UCHAR fsTimeFmt;
+ USHORT abReserved1[2];
+ CHAR szDataSeparator[2];
+ USHORT abReserved2[5];
+} COUNTRYINFO16, *PCOUNTRYINFO16;
+#pragma pack()
+
+
+//
+// 16B Prototypes (for use by other OS2 16B APIs
+//
+
+APIRET
+DosSemClear(
+ HSEM Sem);
+
+APIRET
+DosCloseSem(
+ IN HSEM hsem
+ );
+
+APIRET
+DosFreeSeg(
+ SEL Sel);
+APIRET
+DosAllocSeg(
+ IN USHORT cbSize,
+ OUT PSEL pSel,
+ IN USHORT fsAlloc);
+APIRET
+DosSizeSeg(
+ IN SEL sel,
+ PULONG pcbSize
+ );
+APIRET
+LDRGetProcAddr(
+ USHORT hmte,
+ PSZ pchname,
+ PULONG paddress);
+
+APIRET
+LDRGetModName(
+ ULONG hMod,
+ ULONG cbBuf,
+ PCHAR pchBuf);
+
+APIRET
+LDRGetModHandle(
+ PSZ pszModName,
+ ULONG len,
+ PULONG phMode);
+
+APIRET
+LDRQAppType(
+ IN PSZ pszAppName,
+ OUT PUSHORT pusType
+ );
+
+APIRET
+Od2GetSemNtEvent(
+ HSEM hsem,
+ PHANDLE pNtHandle
+ );
+VOID
+Od2JumpTo16ExitRoutine(
+ PFNEXITLIST ExitRoutine,
+ ULONG ExitReason);
+
+#define SEM_FROM_SET 0
+#define SEM_FROM_REQUESTWAIT 1
+#define SEM_FROM_CLEAR 2
+
+POS21X_SEM
+Od2LookupOrCreateSem (
+ HSEM hsem,
+ PBOOLEAN firsttime,
+ ULONG source
+ );
+
+#pragma pack(1)
+typedef struct _R2StackEntry {
+ USHORT R2StackSize;
+ USHORT R2StackSel;
+} R2StackEntry, *PR2StackEntry;
+#pragma pack()
diff --git a/private/os2/inc/os2err.h b/private/os2/inc/os2err.h
new file mode 100644
index 000000000..0ddee9e64
--- /dev/null
+++ b/private/os2/inc/os2err.h
@@ -0,0 +1,631 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2err.h
+
+Abstract:
+
+ This file contains the OS/2 return codes (ERROR_ ... )
+
+Author:
+
+ Michael Jarus (mjarus) 20-Nov-1991
+
+Parameters:
+
+
+Revision History:
+
+--*/
+
+#ifndef _OS2V20_ERRORS_
+
+#define _OS2V20_ERRORS_
+
+#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
+
+#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_CODE_PAGE_MISMATCHED 37
+#define ERROR_HANDLE_EOF 38
+#define ERROR_HANDLE_DISK_FULL 39
+#define ERROR_NOT_SUPPORTED 50
+#define ERROR_REM_NOT_LIST 51
+#define ERROR_DUP_NAME 52
+#define ERROR_BAD_NETPATH 53
+#define ERROR_NETWORK_BUSY 54
+#define ERROR_DEV_NOT_EXIST 55
+#define ERROR_TOO_MANY_CMDS 56
+#define ERROR_ADAP_HDW_ERR 57
+#define ERROR_BAD_NET_RESP 58
+#define ERROR_UNEXP_NET_ERR 59
+#define ERROR_BAD_REM_ADAP 60
+#define ERROR_PRINTQ_FULL 61
+#define ERROR_NO_SPOOL_SPACE 62
+#define ERROR_PRINT_CANCELLED 63
+#define ERROR_NETNAME_DELETED 64
+#define ERROR_NETWORK_ACCESS_DENIED 65
+#define ERROR_BAD_DEV_TYPE 66
+#define ERROR_BAD_NET_NAME 67
+#define ERROR_TOO_MANY_NAMES 68
+#define ERROR_TOO_MANY_SESS 69
+#define ERROR_SHARING_PAUSED 70
+#define ERROR_REQ_NOT_ACCEP 71
+#define ERROR_REDIR_PAUSED 72
+
+#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
+#define ERROR_NOT_FROZEN 90
+#define ERROR_SYS_COMP_NOT_LOADED ERROR_NOT_FROZEN
+#define ERROR_TSTOVFL 91
+#define ERROR_TSTDUP 92
+#define ERROR_NO_ITEMS 93
+#define ERROR_INTERRUPT 95
+#define ERROR_DEVICE_IN_USE 99
+#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
+#define ERROR_SEM_USER_LIMIT 106
+#define ERROR_DISK_CHANGE 107
+#define ERROR_DRIVE_LOCKED 108
+#define ERROR_BROKEN_PIPE 109
+#define ERROR_OPEN_FAILED 110
+#define ERROR_BUFFER_OVERFLOW 111
+#define ERROR_DISK_FULL 112
+#define ERROR_NO_MORE_SEARCH_HANDLES 113
+#define ERROR_INVALID_TARGET_HANDLE 114
+#define ERROR_PROTECTION_VIOLATION 115
+#define ERROR_VIOKBD_REQUEST 116
+#define ERROR_INVALID_CATEGORY 117
+#define ERROR_INVALID_VERIFY_SWITCH 118
+#define ERROR_BAD_DRIVER_LEVEL 119
+#define ERROR_CALL_NOT_IMPLEMENTED 120
+#define ERROR_SEM_TIMEOUT 121
+#define ERROR_INSUFFICIENT_BUFFER 122
+#define ERROR_INVALID_NAME 123
+#define ERROR_INVALID_LEVEL 124
+#define ERROR_NO_VOLUME_LABEL 125
+#define ERROR_MOD_NOT_FOUND 126
+#define ERROR_PROC_NOT_FOUND 127
+#define ERROR_WAIT_NO_CHILDREN 128
+#define ERROR_CHILD_NOT_COMPLETE 129
+#define ERROR_DIRECT_ACCESS_HANDLE 130
+#define ERROR_NEGATIVE_SEEK 131
+#define ERROR_SEEK_ON_DEVICE 132
+#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
+#define ERROR_INVALID_EVENT_COUNT 151
+#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
+#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
+#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
+#define ERROR_RING2_STACK_IN_USE 207
+#define ERROR_META_EXPANSION_TOO_LONG 208
+#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
+#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_FORCENOSWAP_FAILED 223
+#define ERROR_NO_CHILDREN 228
+#define ERROR_INVALID_SCREEN_GROUP 229
+
+#define ERROR_BAD_PIPE 230
+#define ERROR_PIPE_BUSY 231
+#define ERROR_NO_DATA 232
+#define ERROR_PIPE_NOT_CONNECTED 233
+#define ERROR_MORE_DATA 234
+
+#define ERROR_VC_DISCONNECTED 240
+
+#define ERROR_CIRCULARITY_REQUESTED 250
+#define ERROR_DIRECTORY_IN_CDS 251
+#define ERROR_INVALID_FSD_NAME 252
+#define ERROR_INVALID_PATH 253
+#define ERROR_INVALID_EA_NAME 254
+#define ERROR_EA_LIST_INCONSISTENT 255
+#define ERROR_EA_LIST_TOO_LONG 256
+#define ERROR_NO_META_MATCH 257
+#define ERROR_FINDNOTIFY_TIMEOUT 258
+#define ERROR_NO_MORE_ITEMS 259
+#define ERROR_SEARCH_STRUC_REUSED 260
+#define ERROR_CHAR_NOT_FOUND 261
+#define ERROR_TOO_MUCH_STACK 262
+#define ERROR_INVALID_ATTR 263
+#define ERROR_INVALID_STARTING_RING 264
+#define ERROR_INVALID_DLL_INIT_RING 265
+#define ERROR_CANNOT_COPY 266
+#define ERROR_DIRECTORY 267
+#define ERROR_OPLOCKED_FILE 268
+#define ERROR_OPLOCK_THREAD_EXISTS 269
+#define ERROR_VOLUME_CHANGED 270
+#define ERROR_FINDNOTIFY_HANDLE_IN_USE 271
+#define ERROR_FINDNOTIFY_HANDLE_CLOSED 272
+#define ERROR_NOTIFY_OBJECT_REMOVED 273
+#define ERROR_ALREADY_SHUTDOWN 274
+#define ERROR_EAS_DIDNT_FIT 275
+#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_EAS_NOT_SUPPORTED 282
+#define ERROR_NEED_EAS_FOUND 283
+#define ERROR_DUPLICATE_HANDLE 284
+#define ERROR_DUPLICATE_NAME 285
+#define ERROR_EMPTY_MUXWAIT 286
+#define ERROR_MUTEX_OWNED 287
+#define ERROR_NOT_OWNER 288
+#define ERROR_PARAM_TOO_SMALL 289
+#define ERROR_TOO_MANY_HANDLES 290
+#define ERROR_TOO_MANY_OPENS 291
+#define ERROR_WRONG_TYPE 292
+#define ERROR_INVALID_TID 293
+#define ERROR_THREAD_NOT_TERMINATED 294
+#define ERROR_INIT_ROUTINE_FAILED 295
+#define ERROR_MODULE_IN_USE 296
+#define ERROR_NOT_ENOUGH_WATCHPOINTS 297
+#define ERROR_TOO_MANY_POSTS 298
+#define ERROR_ALREADY_POSTED 299
+#define ERROR_ALREADY_RESET 300
+#define ERROR_SEM_BUSY 301
+
+#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 ERROR_MOUSE_NO_DATA 393
+#define 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
+
+/* New Equates For OS/2 1.2 */
+#define ERROR_TRC_PID_NON_EXISTENT 507
+#define ERROR_TRC_COUNT_ACTIVE 508
+#define ERROR_TRC_SUSPENDED_BY_COUNT 509
+#define ERROR_TRC_COUNT_INACTIVE 510
+#define ERROR_TRC_COUNT_REACHED 511
+#define ERROR_NO_MC_TRACE 512
+#define ERROR_MC_TRACE 513
+#define ERROR_TRC_COUNT_ZERO 514
+#define ERROR_SMG_TOO_MANY_DDS 515
+#define ERROR_SMG_INVALID_NOTIFICATION 516
+#define ERROR_LF_INVALID_FUNCTION 517
+#define ERROR_LF_NOT_AVAIL 518
+#define ERROR_LF_SUSPENDED 519
+#define ERROR_LF_BUF_TOO_SMALL 520
+#define ERROR_LF_BUFFER_CORRUPTED 521
+#define ERROR_LF_INVALID_DAEMON 522
+#define ERROR_LF_INVALID_TEMPL 523
+#define ERROR_LF_GENERAL_FAILURE 524
+#define ERROR_LF_INVALID_ID 525
+#define ERROR_LF_INVALID_HANDLE 526
+#define ERROR_LF_NO_ID_AVAIL 527
+#define ERROR_LF_TEMPLATE_AREA_FULL 528
+#define ERROR_LF_ID_IN_USE 529
+#define ERROR_MOU_NOT_INITIALIZED 530
+#define ERROR_MOUINITREAL_DONE 531
+
+/* now more 2.0 stuff */
+#define ERROR_DOSSUB_CORRUPTED 532
+#define ERROR_MOUSE_CALLER_NOT_SUBSYS 533
+#define ERROR_ARITHMETIC_OVERFLOW 534
+
+/* TMR device */
+
+#define ERROR_TMR_NO_DEVICE 535
+#define ERROR_TMR_INVALID_TIME 536
+
+/* Perfview */
+
+#define ERROR_PVW_INVALID_ENTITY 537
+#define ERROR_PVW_INVALID_ENTITY_TYPE 538
+#define ERROR_PVW_INVALID_SPEC 539
+#define ERROR_PVW_INVALID_RANGE_TYPE 540
+#define ERROR_PVW_INVALID_COUNTER_BLK 541
+#define ERROR_PVW_INVALID_TEXT_BLK 542
+
+/* PROFILER */
+
+#define ERROR_PRF_NOT_INITIALIZED 543
+#define ERROR_PRF_ALREADY_INITIALIZED 544
+#define ERROR_PRF_NOT_STARTED 545
+#define ERROR_PRF_ALREADY_STARTED 546
+#define ERROR_PRF_TIMER_OUT_OF_RANGE 547
+#define ERROR_PRF_TIMER_RESET 548
+
+#define ERROR_TIMEOUT 640
+#define ERROR_VDM_DOWN 641
+#define ERROR_VDM_LIMIT 642
+#define ERROR_VDD_NOT_FOUND 643
+#define ERROR_INVALID_CALLER 644
+#define ERROR_PID_MISMATCH 645
+#define ERROR_INVALID_VDD_HANDLE 646
+#define ERROR_VLPT_NO_SPOOLER 647
+#define ERROR_VCOM_DEVICE_BUSY 648
+#define ERROR_VLPT_DEVICE_BUSY 649
+#define ERROR_NESTING_TOO_DEEP 650
+
+#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_BLOCKED 32791
+#define ERROR_NOBLOCK 32792
+#define ERROR_INSTANCE_SHARED 32793
+#define ERROR_NO_OBJECT 32794
+#define ERROR_PARTIAL_ATTACH 32795
+#define ERROR_INCACHE 32796
+#define ERROR_SWAP_IO_PROBLEMS 32797
+#define ERROR_CROSSES_OBJECT_BOUNDARY 32798
+#define ERROR_LONGLOCK 32799
+#define ERROR_SHORTLOCK 32800
+#define ERROR_UVIRTLOCK 32801
+#define ERROR_ALIASLOCK 32802
+#define ERROR_ALIAS 32803
+#define ERROR_NO_MORE_HANDLES 32804
+#define ERROR_SCAN_TERMINATED 32805
+#define ERROR_TERMINATOR_NOT_FOUND 32806
+#define ERROR_NOT_DIRECT_CHILD 32807
+#define ERROR_DELAY_FREE 32808
+#define ERROR_GUARDPAGE 32809
+#define ERROR_SWAPERROR 32900
+#define ERROR_LDRERROR 32901
+#define ERROR_NOMEMORY 32902
+#define ERROR_NOACCESS 32903
+#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
+#define ERROR_ENTRY_IS_CALLGATE 65079
+
+#define ERROR_USER_DEFINED_BASE 0xFF00
+
+#endif // _OS2V20_ERRORS_
+
diff --git a/private/os2/inc/os2file.h b/private/os2/inc/os2file.h
new file mode 100644
index 000000000..ec1a46c66
--- /dev/null
+++ b/private/os2/inc/os2file.h
@@ -0,0 +1,442 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ os2file.h
+
+Abstract:
+
+ This module defines the OS/2 subsystem I/O data types for both the
+ DLL and server.
+
+Author:
+
+ Therese Stowell (thereses) 17-Dec-1989
+
+Revision History:
+
+--*/
+
+
+//
+// there is one of these records per drive letter, per process. the CurDir
+// contains the current directory string, beginning with the drive letter
+// in the first subdirectory. for example, if the current directory for
+// drive a: is "a:\bin\test", "a:\bin\test" is the CurDir string. However,
+// if the current directory is the root, the pCurDir is NULL.
+//
+
+typedef struct _CURRENT_DIRECTORY_STRING {
+ USHORT RefCount; /* number of processes which has this string as a curdir */
+ STRING CurDirString; /* current directory string */
+} CURRENT_DIRECTORY_STRING, *PCURRENT_DIRECTORY_STRING;
+
+// each element in the array is in the form:
+
+typedef struct _CURRENT_DIRECTORY_INFORMATION {
+ HANDLE NtHandle; /* handle to open current directory */
+ PCURRENT_DIRECTORY_STRING pCurDir; /* pointer to current directory string and ref count. */
+ BOOLEAN CurrentDirectoryIsValid; /* Indicates whether the current directory was explicity set */
+} CURRENT_DIRECTORY_INFORMATION, *PCURRENT_DIRECTORY_INFORMATION;
+
+//BUGBUG this typedef belongs in iovector.h
+
+
+typedef enum _IO_VECTOR_TYPE {
+ NulVectorType,
+ ConVectorType,
+// AuxVectorType, as ComVectorType
+ ComVectorType,
+// PrnVectorType, as LptVectorType
+ LptVectorType,
+ KbdVectorType,
+ MouseVectorType,
+ ClockVectorType,
+ ScreenVectorType,
+ PointerVectorType,
+ FileVectorType,
+ PipeVectorType,
+ DeviceVectorType,
+ RemoteVectorType,
+ MonitorVectorType
+} IO_VECTOR_TYPE;
+
+typedef struct _FILE_HANDLE {
+ HANDLE NtHandle; // NT or pipe or OS2.EXE (for Screen, Kbd, Mouse, Con & Monitor) handle
+ HANDLE NtAsyncReadEvent; // These handles are used for Asynchronous IO
+ HANDLE NtAsyncWriteEvent; // Operations. At present, they are used only
+ HANDLE NtAsyncIOCtlEvent; // for the COM devices
+ USHORT FileType; // file, pipe, device, unc
+ USHORT DeviceAttribute; // device flags, if char device
+ ULONG Flags; // free or allocated, plus DosQueryFHState flags
+ // inherit, write-through, fail-error, cache
+ // access and sharing mode
+ IO_VECTOR_TYPE IoVectorType; // which IO routines to call
+} FILE_HANDLE, *PFILE_HANDLE;
+
+#include "iovector.h"
+
+typedef ULONG FILE_HANDLE_NUMBER, *PFILE_HANDLE_NUMBER; // handle returned to user (index into array)
+
+// the following three values are chosen to not conflict with the bits accessible
+// through DosQueryFHState. An allocated file handle is reserved, but
+// uninitialized. A valid file handle is allocated and initialized.
+
+#define FILE_HANDLE_FREE 0x00000100 /* ---- -001 ---- ---- */
+#define FILE_HANDLE_ALLOCATED 0x00000200 /* ---- -010 ---- ---- */
+#define FILE_HANDLE_VALID 0x00000400 /* ---- -100 ---- ---- */
+
+/*
+
+ device attributes
+
+ 15 14 13 12 11 9 8 7 6 5 4 3 2 1 0
+
+ C C I O G C N S K
+ H O B P LEVEL I L U C B
+ R N M N O K L R D
+
+ since OS/2 doesn't return the device header for block devices via
+ DosQueryHType, we don't need to worry about the bits that describe
+ block devices: DEVICE_ATTRIBUTE_NONIBM and DEVICE_ATTRIBUTE_OPEN for
+ block devices.
+
+ FYI:
+
+ DEVICE_ATTRIBUTE_NONIBM describes how the system builds the BPB from the
+ medium. if this bit is set, there is no boot sector on the disk. in NT,
+ this bit is meaningless and is always set.
+
+ BuildBPB:
+ get free buffer
+ If (ibm block format)
+ Read first sector of first fat into buffer
+ call device driver build bpb passing in buffer
+
+*/
+
+#define DEVICE_ATTRIBUTE_STDIN 0x0001 /* ---- ---- ---- 0001 */
+#define DEVICE_ATTRIBUTE_STDOUT 0x0002 /* ---- ---- ---- 0010 */
+#define DEVICE_ATTRIBUTE_NUL 0x0004 /* ---- ---- ---- 0100 */
+#define DEVICE_ATTRIBUTE_CLOCK 0x0008 /* ---- ---- ---- 1000 */
+#define DEVICE_ATTRIBUTE_GENIOCTL 0x0040 /* ---- ---- 0100 ---- */
+#define DEVICE_ATTRIBUTE_NTLEVEL 0x0380 /* ---- --11 1000 ---- */
+#define DEVICE_ATTRIBUTE_OPEN 0x0800 /* ---- 1000 ---- ---- */
+#define DEVICE_ATTRIBUTE_REM_MEDIA 0x0800 /* ---- 1000 ---- ---- */
+#define DEVICE_ATTRIBUTE_NONIBM 0x2000 /* 0010 ---- ---- ---- */
+#define DEVICE_ATTRIBUTE_CONSOLE 0x4000 /* 0100 ---- ---- ---- */
+#define DEVICE_ATTRIBUTE_CHAR 0x8000 /* 1000 ---- ---- ---- */
+#define DEVICE_ATTRIBUTE_BLOCK 0x8000 /* 1000 ---- ---- ---- */
+
+#define DEVICE_ATTRIBUTE_DEFAULT (DEVICE_ATTRIBUTE_NTLEVEL | DEVICE_ATTRIBUTE_OPEN)
+#define DEVICE_ATTRIBUTE_DEFAULT_CHAR (DEVICE_ATTRIBUTE_DEFAULT | DEVICE_ATTRIBUTE_CHAR | DEVICE_ATTRIBUTE_GENIOCTL)
+
+#define MapDeviceAction(CreateDisposition) (CreateDisposition == FILE_CREATE ? FILE_CREATED : FILE_EXISTED)
+
+typedef enum _SHARE_OPERATION {
+ AddShare,
+ DupShare,
+ RemoveShare
+} SHARE_OPERATION;
+
+#define NUMBER_OF_DEVICES (PointerVectorType+1)
+#define MAXIMUM_DEVICE_VECTOR_TYPE PointerVectorType
+
+typedef struct _SHARE_ACCESS {
+ ULONG OpenCount;
+ ULONG Readers;
+ ULONG Writers;
+ ULONG Deleters;
+ ULONG SharedRead;
+ ULONG SharedWrite;
+ ULONG SharedDelete;
+} SHARE_ACCESS, *PSHARE_ACCESS;
+
+//
+// FindFirst/Next search record. if FindBuffer == NULL, the search doesn't
+// need to be rewound and RewindEntry is meaningless.
+//
+
+typedef struct _SEARCH_RECORD {
+ HANDLE NtHandle; // NT directory handle
+ ULONG Attributes; // attributes associated with search
+ ULONG InformationLevel; // what type of info to return
+ PVOID FindBuffer; // buffer filled by NtQueryDirectoryFile
+ ULONG BufferLength; // length of FindBuffer
+ PFILE_DIRECTORY_INFORMATION RewindEntry; // pointer to entry in buffer to begin search from
+} SEARCH_RECORD, *PSEARCH_RECORD;
+
+// the following value is specially defined. the search handle table does
+// not have an allocated field, it is an array of heap addresses that point
+// to search records. since zero is never an invalid heap address (per
+// SteveWo, 1/4/90), we use it to indicate a free handle.
+
+#define SEARCH_HANDLE_FREE 0x0000
+#define INITIAL_SEARCH_HANDLES 5 // initial number of search handles
+#define SEARCH_TABLE_HANDLE_INCREMENT 10 // number of handles table grows by
+
+/* takes zero-based drive number and returns ascii drive char */
+
+#define CONVERTTOASCII(drivenumber) ((char)(drivenumber+(int)'A'))
+
+#define ISSLASH(ch) ((ch == '\\') || (ch == '/'))
+#define ISPATHSEP(ch) ((ch == '\\') || (ch == '/') || (ch == '\0'))
+
+/* !!! when changing update os2ses\os2.c */
+
+#define FILE_TYPE_FILE 0x0000
+#define FILE_TYPE_DEV 0x0001
+#define FILE_TYPE_PIPE 0x0002
+#define FILE_TYPE_NMPIPE 0x0004
+#define FILE_TYPE_UNC 0x0008
+#define FILE_TYPE_PSDEV 0x0010
+#define FILE_TYPE_MAILSLOT 0x0020
+#define FILE_TYPE_COM 0x0040
+
+#define MAX_DRIVES 26
+#define DRIVE_EXISTS 1
+
+#define FILE_PREFIX_LENGTH 14 // "\OS2SS\DRIVES\"
+#define DEV_PREFIX_LENGTH 12 // "\DosDevices\"
+#define NMPIPE_PREFIX_LENGTH 12 // "\OS2SS\PIPE\"
+#define UNC_PREFIX_LENGTH 11 // "\OS2SS\UNC\"
+#define PSDEV_PREFIX_LENGTH 2 // "@n"
+#define MAILSLOT_PREFIX_LENGTH 16 // "\OS2SS\MAILSLOT\"
+#define COM_PREFIX_LENGTH 12 // "\DosDevices\"
+
+#define ROOTDIRLENGTH 3
+#define DRIVE_LETTER 0
+#define COLON 1
+#define FIRST_SLASH 2
+#define DRIVE_LETTER_SIZE ROOTDIRLENGTH // size of "d:\"
+
+#define INITIALFILEHANDLES 20
+
+#define MINFEALISTSIZE 4 // minimum FEA list size
+#define MINFEAVALUESIZE 1 // minimum length of ea value
+#define MINFEANAMESIZE 2 // minimum length of ea name (including NUL)
+
+typedef struct _OLDFEA {
+ BYTE fEA; /* flags */
+ BYTE cbName; /* name length not including NULL */
+ USHORT cbValue; /* value length */
+ CHAR szName[1]; /* attribute name */
+} OLDFEA, *POLDFEA;
+
+//
+// maximum EA buffer to allocate. this figures out the maximum number of
+// packed EAs that will fit in 64K-1, then calculates the amount of memory
+// necessary to hold them in NT form. then we're guaranteed that all the EAs
+// for a file will fit in a buffer this size.
+//
+
+//
+// this equated defines the maximum size of an unaligned EA. it is the
+// maximum size of an unaligned EA list minus the size of the cblist.
+//
+
+#define MAX_UNALIGNED_EA_LIST_SIZE 0xFFFF
+#define MAX_UNALIGNED_EA_SIZE (MAX_UNALIGNED_EA_LIST_SIZE - MINFEALISTSIZE)
+
+//
+// this equated defines the maximum size of an aligned EA. it is the
+// maximum size of an unaligned EA plus the size of the NextEntryOffset field.
+//
+
+#define MAX_EA_SIZE (MAX_UNALIGNED_EA_SIZE + sizeof(ULONG))
+
+//
+// maximum EA buffer to allocate. this figures out the maximum number of
+// packed EAs that will fit in 64K-1, then calculates the amount of memory
+// necessary to hold them in NT form. then we're guaranteed that all the EAs
+// for a file will fit in a buffer this size.
+//
+
+#define SMALLEST_UNALIGNED_EA (sizeof(OLDFEA) + MINFEAVALUESIZE + MINFEANAMESIZE)
+#define MAXIMUM_NUMBER_OF_EAS ((MAX_UNALIGNED_EA_LIST_SIZE-MINFEALISTSIZE) / SMALLEST_UNALIGNED_EA)
+#define SMALLEST_NT_EA (RoundUpToUlong(FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName ) + MINFEAVALUESIZE + MINFEANAMESIZE))
+#define MAX_ALIGNED_EA_LIST_SIZE (MAXIMUM_NUMBER_OF_EAS * SMALLEST_NT_EA)
+
+#define DENA1_sizeof(fea) (FIELD_OFFSET (DENA1,szName) + (fea)->cbName+1)
+#define DENA1_oNextEntryOffset(fea) (RoundUpToUlong(DENA1_sizeof(fea)))
+
+#define BLOCK_SIZE 512L
+#define BLOCK_SHIFT 9L
+
+//++
+//
+// ULONG
+// BYTES_TO_BLOCKS (
+// IN ULONG SIZE
+// )
+//
+// Routine Description:
+//
+//
+// The BYTES_TO_BLOCKS macro takes the size in bytes and calculates the number
+// of 512-byte blocks required to contain the bytes.
+//
+//
+// Arguments:
+//
+// SIZE - Size in bytes.
+//
+// Return Value:
+//
+// Returns the number of blocks required to contain the specified size.
+//
+// adapted from BYTES_TO_PAGES
+//
+//--
+
+#define BYTES_TO_BLOCKS(SIZE) (((ULONG)SIZE + BLOCK_SIZE - 1) >> BLOCK_SHIFT)
+
+//++
+//
+// ULONG
+// BYTES_TO_OFFSET (
+// IN ULONG SIZE
+// )
+//
+// Routine Description:
+//
+//
+// The BYTES_TO_OFFSET macro takes the size in bytes and calculates BYTES MOD
+// BLOCKSIZE in order to determine the number of bytes in the last block.
+//
+//
+// Arguments:
+//
+// SIZE - Size in bytes.
+//
+// Return Value:
+//
+// Returns the number of blocks required to contain the specified size.
+//
+//--
+
+#define BYTES_TO_OFFSET(SIZE) ((ULONG)SIZE & (BLOCK_SIZE - 1))
+
+//++
+//
+// ULONG
+// BLOCKS_TO_BYTES (
+// IN ULONG BLOCKS
+// IN ULONG OFFSET
+// )
+//
+// Routine Description:
+//
+//
+// The BLOCKS_TO_BYTES macro takes the size in blocks and offset and calculates
+// BLOCKS * BLOCK_SIZE + OFFSET in order to determine the number of bytes in
+// the file.
+//
+// Arguments:
+//
+// SIZE - Size in bytes.
+//
+// Return Value:
+//
+// Returns the number of blocks required to contain the specified size.
+//
+//--
+
+#define BLOCKS_TO_BYTES(BLOCKS,OFFSET) ((BLOCKS << BLOCK_SHIFT) + OFFSET)
+
+
+// used in exec call to initialize file system
+
+typedef struct _OS2_FILE_SYSTEM_PARAMETERS {
+ PFILE_HANDLE ParentHandleTable; // address of parent handle table
+ ULONG ParentTableLength; // number of entries in parent table
+ ULONG CurrentDrive; // process's current drive
+} OS2_FILE_SYSTEM_PARAMETERS, *POS2_FILE_SYSTEM_PARAMETERS;
+
+// passed to Os2SetProcessContext which passes it to Od2ProcessStartup
+// because the file system needs to know whether to set up stdin, etc.
+// and initialize the file handle table or to copy the file handle table from
+// the parent.
+
+#define CALLED_BY_EXEC 1
+#define CALLED_BY_SESMGR 2
+
+typedef struct _PIPE_HEADER {
+ ULONG PipeSize; // pipe size, not including header
+ ULONG RefCount; // number of references to pipe
+ ULONG ReadCount; // count of readers
+ ULONG WriteCount; // count of writers
+ ULONG First; // ptr to base of circular buffer
+ ULONG In; // ptr to next free byte
+ ULONG Out; // ptr to next byte of data
+ ULONG Last; // ptr to end+1 of buffer
+ HANDLE ReadNeedMoreData; // wait on this if out of data to read
+ HANDLE WriteBufferFull; // wait on this if out of space to write
+ RTL_CRITICAL_SECTION LockForRead; // serialize reads using this
+ RTL_CRITICAL_SECTION LockForWrite; // serialize writes using this
+} PIPE_HEADER, *PPIPE_HEADER;
+
+#define PIPE_READ_HANDLE OPEN_ACCESS_READONLY
+#define PIPE_WRITE_HANDLE OPEN_ACCESS_WRITEONLY
+#define DEFAULT_PIPE_SIZE 512
+
+
+// the size of the information for one directory entry for the various
+// FindFirst/Next infolevels, assuming a 1 byte name.
+
+#define FIND_LEVEL_ONE_INFO_SIZE (sizeof(FILEFINDBUF3) - CCHMAXPATHCOMP + 2)
+#define FIND_LEVEL_TWO_INFO_SIZE (sizeof(FILEFINDBUF4) - CCHMAXPATHCOMP + 2)
+
+#define ATTR_IGNORE (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_ARCHIVE)
+
+// BUGBUG does this work correctly (aligned)?
+
+#define ATTR_SIZE3 (FIELD_OFFSET(FILEFINDBUF3,cchName))
+#define ATTR_SIZE4 (FIELD_OFFSET(FILEFINDBUF4,cchName))
+
+//
+// The following are the flags passed to Canonicalize
+//
+
+#define FULL_PATH_REQUIRED 0x0001 // full canonical path needed
+
+#define PIPE_DIR_OK 0x0002 // "d:\pipe" is ok as file
+
+#define PIPE_DIR_SIZE 6 // length of "\PIPE\"
+
+//
+// The DBCS macro determines whether a character is DBCS
+//
+// BUGBUG make DBCS macro do something
+
+#ifdef DBCS
+// MSKK Sep.27.1993 V-AkihiS
+#define IsDbcs(pChar) Ow2NlsIsDBCSLeadByte(*pChar, SesGrp->DosCP)
+#else
+//#define DBCS(pChar) FALSE
+#define IsDbcs(pChar) FALSE // MSKK fix for NON-DBCS build break
+#endif
+
+#define UCase(Char) (((Char >= 'a') && (Char <= 'z')) ? (Char - ('a' - 'A')) : (Char))
+
+
+//
+// The CharsEqual macro determines whether two characters are equal and is
+// DBCS-correct
+// BUGBUG what if DBCS chars aren't aligned?
+//
+
+// MSKK fix for NON-DBCS build break
+/*
+#define CharsEqual(pChar1,pChar2) ((DBCS(pChar1)) ? ((*(PUSHORT)(pChar1)) == (*(PUSHORT)(pChar1))) : \
+ (UCase(*pChar1) == UCase(*pChar2)))
+*/
+#define CharsEqual(pChar1,pChar2) ((IsDbcs(pChar1)) ? ((*(PUSHORT)(pChar1)) == (*(PUSHORT)(pChar2))) : \
+ (UCase(*pChar1) == UCase(*pChar2)))
+//
+// sectors in NT are always 512 bytes
+//
+
+#define BYTES_PER_SECTOR 512
diff --git a/private/os2/inc/os2flopy.h b/private/os2/inc/os2flopy.h
new file mode 100644
index 000000000..c727069b0
--- /dev/null
+++ b/private/os2/inc/os2flopy.h
@@ -0,0 +1,83 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ os2flopy.h
+
+Abstract:
+
+ Definitions file for the floppy disk module (dllflopy.c).
+
+Author:
+
+ Ofer Porat (oferp) 6-23-93
+
+Revision History:
+
+--*/
+
+#ifndef __OS2FLOPY_H
+#define __OS2FLOPY_H
+
+//
+// os2dev.h must be included for this file to be valid
+//
+
+#define READ_TRACK_CMD 0
+#define WRITE_TRACK_CMD 1
+#define VERIFY_TRACK_CMD 2
+#define TRACK_CMD_LIMIT 3
+
+
+APIRET
+Od2IdentifyDiskDrive(
+ IN HANDLE NtHandle,
+ IN PULONG pDriveNumberPermanentStorageLocation,
+ OUT PULONG pDriveNumber
+ );
+
+APIRET
+Od2AcquireDeviceBPB(
+ IN ULONG DriveNumber,
+ IN HANDLE NtHandle,
+ IN BOOLEAN Validate,
+ IN BOOLEAN UseDefault,
+ IN OUT PBIOSPARAMETERBLOCK pBpb OPTIONAL
+ );
+
+APIRET
+Od2AcquireMediaBPB(
+ IN ULONG DriveNumber,
+ IN HANDLE NtHandle,
+ IN BOOLEAN Validate,
+ IN BOOLEAN UseDefault,
+ IN BOOLEAN EnforceFakeGeometry,
+ IN OUT PBIOSPARAMETERBLOCK pBpb OPTIONAL,
+ OUT PMEDIA_TYPE pMediaType OPTIONAL,
+ OUT PDISK_GEOMETRY pTrueMediaGeometry OPTIONAL
+ );
+
+APIRET
+Od2ReadWriteVerifyTrack(
+ IN HANDLE NtHandle,
+ IN ULONG Command,
+ IN PTRACKLAYOUT TrackLayout,
+ IN PBYTE pData OPTIONAL,
+ IN ULONG CountSectors,
+ IN PBIOSPARAMETERBLOCK pBpb,
+ IN PDISK_GEOMETRY pTrueGeometry
+ );
+
+APIRET
+Od2FormatTrack(
+ IN HANDLE NtHandle,
+ IN PTRACKFORMAT TrackFormat,
+ IN ULONG CountSectors,
+ IN BYTE FormatSectorSizeType,
+ IN PBIOSPARAMETERBLOCK pBpb,
+ IN MEDIA_TYPE MediaType
+ );
+
+#endif
diff --git a/private/os2/inc/os2ldr.h b/private/os2/inc/os2ldr.h
new file mode 100644
index 000000000..13c5cace4
--- /dev/null
+++ b/private/os2/inc/os2ldr.h
@@ -0,0 +1,67 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2ldr.h
+
+Abstract:
+
+ Main include file for OS/2 Subsystem Loader
+
+Author:
+
+ Beni Lavi (BeniL) 5-Nov-1992
+
+Revision History:
+
+--*/
+
+#include <ldrdbg.h>
+
+BOOLEAN
+ldrInit(
+ VOID
+);
+
+APIRET
+Allocate16BHandle(
+ OUT PUSHORT pusHandle,
+ IN ULONG h32bHandle
+);
+
+BOOLEAN
+ldrCreateSelBitmap();
+
+VOID
+ldrMarkAllocatedSel(
+ IN ULONG NumberOfSel,
+ IN BOOLEAN MarkFronTop
+);
+
+ULONG
+ldrAllocateSel(
+ IN ULONG NumberOfSel,
+ IN BOOLEAN TopDownAllocation
+);
+
+VOID
+ldrFreeSel(
+ IN ULONG StartSel,
+ IN ULONG NumberOfSel
+);
+
+BOOLEAN
+ldrCreateCallGateBitmap();
+
+VOID
+ldrMarkAllocatedCallGates(ULONG NumberOfCallGates);
+
+ULONG
+ldrAllocateCallGate();
+
+VOID
+ldrDeallocateCallGate(
+ ULONG CallGate
+);
diff --git a/private/os2/inc/os2net16.h b/private/os2/inc/os2net16.h
new file mode 100644
index 000000000..fd0468966
--- /dev/null
+++ b/private/os2/inc/os2net16.h
@@ -0,0 +1,974 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ os2net16.h
+
+Abstract:
+
+ This module implements 32 equivalents of OS/2 V1.21
+ LANMAN API Calls.
+ The APIs are called from 16->32 thunks (i386\doscalls.asm).
+
+Author:
+
+ Beni Lavi (BeniL) 15-Jan-1992
+
+Revision History:
+
+--*/
+
+#define DEVLEN_LM20 8
+#define CNLEN_LM20 15 /* Computer name length */
+#define UNLEN_LM20 20 /* Maximum user name length */
+#define ENCRYPTED_PWLEN_LM20 16
+#define NNLEN_LM20 12 /* 8.3 Net name length */
+#define SHPWLEN_LM20 8 /* Share password length */
+#define SNLEN_LM20 15 /* Service name length */
+#define STXTLEN_LM20 63 /* Service text length */
+
+#pragma pack(1)
+
+struct use_info_0 {
+ char ui0_local[DEVLEN_LM20+1];
+ char ui0_pad_1;
+ char *ui0_remote;
+}; /* use_info_0 */
+
+struct use_info_1 {
+ char ui1_local[DEVLEN_LM20+1];
+ char ui1_pad_1;
+ char * ui1_remote;
+ char * ui1_password;
+ unsigned short ui1_status;
+ short ui1_asg_type;
+ unsigned short ui1_refcount;
+ unsigned short ui1_usecount;
+}; /* use_info_1 */
+
+struct wksta_info_0 {
+ unsigned short wki0_reserved_1;
+ unsigned long wki0_reserved_2;
+ char far * wki0_root;
+ char far * wki0_computername;
+ char far * wki0_username;
+ char far * wki0_langroup;
+ unsigned char wki0_ver_major;
+ unsigned char wki0_ver_minor;
+ unsigned long wki0_reserved_3;
+ unsigned short wki0_charwait;
+ unsigned long wki0_chartime;
+ unsigned short wki0_charcount;
+ unsigned short wki0_reserved_4;
+ unsigned short wki0_reserved_5;
+ unsigned short wki0_keepconn;
+ unsigned short wki0_keepsearch;
+ unsigned short wki0_maxthreads;
+ unsigned short wki0_maxcmds;
+ unsigned short wki0_reserved_6;
+ unsigned short wki0_numworkbuf;
+ unsigned short wki0_sizworkbuf;
+ unsigned short wki0_maxwrkcache;
+ unsigned short wki0_sesstimeout;
+ unsigned short wki0_sizerror;
+ unsigned short wki0_numalerts;
+ unsigned short wki0_numservices;
+ unsigned short wki0_errlogsz;
+ unsigned short wki0_printbuftime;
+ unsigned short wki0_numcharbuf;
+ unsigned short wki0_sizcharbuf;
+ char far * wki0_logon_server;
+ char far * wki0_wrkheuristics;
+ unsigned short wki0_mailslots;
+}; /* wksta_info_0 */
+
+struct wksta_info_1 {
+ unsigned short wki1_reserved_1;
+ unsigned long wki1_reserved_2;
+ char far * wki1_root;
+ char far * wki1_computername;
+ char far * wki1_username;
+ char far * wki1_langroup;
+ unsigned char wki1_ver_major;
+ unsigned char wki1_ver_minor;
+ unsigned long wki1_reserved_3;
+ unsigned short wki1_charwait;
+ unsigned long wki1_chartime;
+ unsigned short wki1_charcount;
+ unsigned short wki1_reserved_4;
+ unsigned short wki1_reserved_5;
+ unsigned short wki1_keepconn;
+ unsigned short wki1_keepsearch;
+ unsigned short wki1_maxthreads;
+ unsigned short wki1_maxcmds;
+ unsigned short wki1_reserved_6;
+ unsigned short wki1_numworkbuf;
+ unsigned short wki1_sizworkbuf;
+ unsigned short wki1_maxwrkcache;
+ unsigned short wki1_sesstimeout;
+ unsigned short wki1_sizerror;
+ unsigned short wki1_numalerts;
+ unsigned short wki1_numservices;
+ unsigned short wki1_errlogsz;
+ unsigned short wki1_printbuftime;
+ unsigned short wki1_numcharbuf;
+ unsigned short wki1_sizcharbuf;
+ char far * wki1_logon_server;
+ char far * wki1_wrkheuristics;
+ unsigned short wki1_mailslots;
+ char far * wki1_logon_domain;
+ char far * wki1_oth_domains;
+ unsigned short wki1_numdgrambuf;
+}; /* wksta_info_1 */
+
+struct wksta_info_10 {
+ char far * wki10_computername;
+ char far * wki10_username;
+ char far * wki10_langroup;
+ unsigned char wki10_ver_major;
+ unsigned char wki10_ver_minor;
+ char far * wki10_logon_domain;
+ char far * wki10_oth_domains;
+}; /* wksta_info_10 */
+
+struct server_info_0 {
+ char sv0_name[CNLEN_LM20 + 1]; /* Server name */
+}; /* server_info_0 */
+
+
+struct server_info_1 {
+ char sv1_name[CNLEN_LM20 + 1];
+ unsigned char sv1_version_major; /* Major version # of net */
+ unsigned char sv1_version_minor; /* Minor version # of net */
+ unsigned long sv1_type; /* Server type */
+ char far * sv1_comment; /* Exported server comment */
+}; /* server_info_1 */
+
+
+struct server_info_2 {
+ char sv2_name[CNLEN_LM20 + 1];
+ unsigned char sv2_version_major;
+ unsigned char sv2_version_minor;
+ unsigned long sv2_type;
+ char far * sv2_comment;
+ unsigned long sv2_ulist_mtime; /* User list, last modification time */
+ unsigned long sv2_glist_mtime; /* Group list, last modification time */
+ unsigned long sv2_alist_mtime; /* Access list, last modification time */
+ unsigned short sv2_users; /* max number of users allowed */
+ unsigned short sv2_disc; /* auto-disconnect timeout(in minutes) */
+ char far * sv2_alerts; /* alert names (semicolon separated) */
+ unsigned short sv2_security; /* SV_USERSECURITY or SV_SHARESECURITY */
+ unsigned short sv2_auditing; /* 0 = no auditing; nonzero = auditing */
+
+ unsigned short sv2_numadmin; /* max number of administrators allowed */
+ unsigned short sv2_lanmask; /* bit mask representing the srv'd nets */
+ unsigned short sv2_hidden; /* 0 = visible; nonzero = hidden */
+ unsigned short sv2_announce; /* visible server announce rate (sec) */
+ unsigned short sv2_anndelta; /* announce randomize interval (sec) */
+ /* name of guest account */
+ char sv2_guestacct[UNLEN_LM20 + 1];
+ unsigned char sv2_pad1; /* Word alignment pad byte */
+ char far * sv2_userpath; /* ASCIIZ path to user directories */
+ unsigned short sv2_chdevs; /* max # shared character devices */
+ unsigned short sv2_chdevq; /* max # character device queues */
+ unsigned short sv2_chdevjobs; /* max # character device jobs */
+ unsigned short sv2_connections; /* max # of connections */
+ unsigned short sv2_shares; /* max # of shares */
+ unsigned short sv2_openfiles; /* max # of open files */
+ unsigned short sv2_sessopens; /* max # of open files per session */
+ unsigned short sv2_sessvcs; /* max # of virtual circuits per client */
+ unsigned short sv2_sessreqs; /* max # of simul. reqs. from a client */
+ unsigned short sv2_opensearch; /* max # of open searches */
+ unsigned short sv2_activelocks; /* max # of active file locks */
+ unsigned short sv2_numreqbuf; /* number of server (standard) buffers */
+ unsigned short sv2_sizreqbuf; /* size of svr (standard) bufs (bytes) */
+ unsigned short sv2_numbigbuf; /* number of big (64K) buffers */
+ unsigned short sv2_numfiletasks;/* number of file worker processes */
+ unsigned short sv2_alertsched; /* alert counting interval (minutes) */
+ unsigned short sv2_erroralert; /* error log alerting threshold */
+ unsigned short sv2_logonalert; /* logon violation alerting threshold */
+ unsigned short sv2_accessalert; /* access violation alerting threshold */
+ unsigned short sv2_diskalert; /* low disk space alert threshold (KB) */
+ unsigned short sv2_netioalert; /* net I/O error ratio alert threshold */
+ /* (tenths of a percent) */
+ unsigned short sv2_maxauditsz; /* Maximum audit file size (KB) */
+ char far * sv2_srvheuristics;/* performance related server switches */
+}; /* server_info_2 */
+
+
+struct server_info_3 {
+ char sv3_name[CNLEN_LM20 + 1];
+ unsigned char sv3_version_major;
+ unsigned char sv3_version_minor;
+ unsigned long sv3_type;
+ char far * sv3_comment;
+ unsigned long sv3_ulist_mtime; /* User list, last modification time */
+ unsigned long sv3_glist_mtime; /* Group list, last modification time */
+ unsigned long sv3_alist_mtime; /* Access list, last modification time */
+ unsigned short sv3_users; /* max number of users allowed */
+ unsigned short sv3_disc; /* auto-disconnect timeout(in minutes) */
+ char far * sv3_alerts; /* alert names (semicolon separated) */
+ unsigned short sv3_security; /* SV_USERSECURITY or SV_SHARESECURITY */
+ unsigned short sv3_auditing; /* 0 = no auditing; nonzero = auditing */
+
+ unsigned short sv3_numadmin; /* max number of administrators allowed */
+ unsigned short sv3_lanmask; /* bit mask representing the srv'd nets */
+ unsigned short sv3_hidden; /* 0 = visible; nonzero = hidden */
+ unsigned short sv3_announce; /* visible server announce rate (sec) */
+ unsigned short sv3_anndelta; /* announce randomize interval (sec) */
+ /* name of guest account */
+ char sv3_guestacct[UNLEN_LM20 + 1];
+ unsigned char sv3_pad1; /* Word alignment pad byte */
+ char far * sv3_userpath; /* ASCIIZ path to user directories */
+ unsigned short sv3_chdevs; /* max # shared character devices */
+ unsigned short sv3_chdevq; /* max # character device queues */
+ unsigned short sv3_chdevjobs; /* max # character device jobs */
+ unsigned short sv3_connections; /* max # of connections */
+ unsigned short sv3_shares; /* max # of shares */
+ unsigned short sv3_openfiles; /* max # of open files */
+ unsigned short sv3_sessopens; /* max # of open files per session */
+ unsigned short sv3_sessvcs; /* max # of virtual circuits per client */
+ unsigned short sv3_sessreqs; /* max # of simul. reqs. from a client */
+ unsigned short sv3_opensearch; /* max # of open searches */
+ unsigned short sv3_activelocks; /* max # of active file locks */
+ unsigned short sv3_numreqbuf; /* number of server (standard) buffers */
+ unsigned short sv3_sizreqbuf; /* size of svr (standard) bufs (bytes) */
+ unsigned short sv3_numbigbuf; /* number of big (64K) buffers */
+ unsigned short sv3_numfiletasks;/* number of file worker processes */
+ unsigned short sv3_alertsched; /* alert counting interval (minutes) */
+ unsigned short sv3_erroralert; /* error log alerting threshold */
+ unsigned short sv3_logonalert; /* logon violation alerting threshold */
+ unsigned short sv3_accessalert; /* access violation alerting threshold */
+ unsigned short sv3_diskalert; /* low disk space alert threshold (KB) */
+ unsigned short sv3_netioalert; /* net I/O error ratio alert threshold */
+ /* (tenths of a percent) */
+ unsigned short sv3_maxauditsz; /* Maximum audit file size (KB) */
+ char far * sv3_srvheuristics; /* performance related server switches*/
+ unsigned long sv3_auditedevents; /* Audit event control mask */
+ unsigned short sv3_autoprofile; /* (0,1,2,3) = (NONE,LOAD,SAVE,or BOTH) */
+ char far * sv3_autopath; /* file pathname (where to load & save) */
+}; /* server_info_3 */
+
+/****************************************************************
+ * *
+ * Data structure templates - USER *
+ * *
+ ****************************************************************/
+
+struct user_info_0 {
+ char usri0_name[UNLEN_LM20+1];
+}; /* user_info_0 */
+
+struct user_info_1 {
+ char usri1_name[UNLEN_LM20+1];
+ char usri1_pad_1;
+ char usri1_password[ENCRYPTED_PWLEN_LM20];/* See note below */
+ long usri1_password_age;
+ unsigned short usri1_priv; /* See values below */
+ char far * usri1_home_dir;
+ char far * usri1_comment;
+ unsigned short usri1_flags; /* See values below */
+ char far * usri1_script_path;
+}; /* user_info_1 */
+
+/*
+ * NOTE: The maximum length of a user password is PWLEN. The
+ * field usri1_password contains extra room for transporting
+ * the encrypted form of the password over the network. When
+ * setting the user's password, check length vs. PWLEN, not
+ * the size of this field. PWLEN is defined in NETCONS.H.
+ */
+
+
+
+struct user_info_2 {
+ char usri2_name[UNLEN_LM20+1];
+ char usri2_pad_1;
+ char usri2_password[ENCRYPTED_PWLEN_LM20];
+ long usri2_password_age;
+ unsigned short usri2_priv;
+ char far * usri2_home_dir;
+ char far * usri2_comment;
+ unsigned short usri2_flags;
+ char far * usri2_script_path;
+ unsigned long usri2_auth_flags;
+ char far * usri2_full_name;
+ char far * usri2_usr_comment;
+ char far * usri2_parms;
+ char far * usri2_workstations;
+ long usri2_last_logon;
+ long usri2_last_logoff;
+ long usri2_acct_expires;
+ unsigned long usri2_max_storage;
+ unsigned short usri2_units_per_week;
+ unsigned char far*usri2_logon_hours;
+ unsigned short usri2_bad_pw_count;
+ unsigned short usri2_num_logons;
+ char far * usri2_logon_server;
+ unsigned short usri2_country_code;
+ unsigned short usri2_code_page;
+}; /* user_info_2 */
+
+
+struct user_info_10 {
+ char usri10_name[UNLEN_LM20+1];
+ char usri10_pad_1;
+ char far * usri10_comment;
+ char far * usri10_usr_comment;
+ char far * usri10_full_name;
+}; /* user_info_10 */
+
+struct user_info_11 {
+ char usri11_name[UNLEN_LM20+1];
+ char usri11_pad_1;
+ char far * usri11_comment;
+ char far * usri11_usr_comment;
+ char far * usri11_full_name;
+ unsigned short usri11_priv;
+ unsigned long usri11_auth_flags;
+ long usri11_password_age;
+ char far * usri11_home_dir;
+ char far * usri11_parms;
+ long usri11_last_logon;
+ long usri11_last_logoff;
+ unsigned short usri11_bad_pw_count;
+ unsigned short usri11_num_logons;
+ char far * usri11_logon_server;
+ unsigned short usri11_country_code;
+ char far * usri11_workstations;
+ unsigned long usri11_max_storage;
+ unsigned short usri11_units_per_week;
+ unsigned char far*usri11_logon_hours;
+ unsigned short usri11_code_page;
+}; /* user_info_11 */
+
+/****************************************************************
+ * *
+ * Data structure templates - HANDLE *
+ * *
+ ****************************************************************/
+
+struct handle_info_1 {
+ unsigned long hdli1_chartime; /* time in msec to wait before send */
+ unsigned short hdli1_charcount; /* max size of send buffer */
+}; /* handle_info_1 */
+
+struct handle_info_2 {
+ char far * hdli2_username; /* owner of name-pipe handle */
+}; /* handle_info_2 */
+
+/****************************************************************
+ * *
+ * Data structure templates - SHARE *
+ * *
+ ****************************************************************/
+
+struct share_info_0 {
+ char shi0_netname[NNLEN_LM20+1];
+}; /* share_info_0 */
+
+struct share_info_1 {
+ char shi1_netname[NNLEN_LM20+1];
+ char shi1_pad1;
+ unsigned short shi1_type;
+ char far * shi1_remark;
+}; /* share_info_1 */
+
+struct share_info_2 {
+ char shi2_netname[NNLEN_LM20+1];
+ char shi2_pad1;
+ unsigned short shi2_type;
+ char far * shi2_remark;
+ unsigned short shi2_permissions;
+ unsigned short shi2_max_uses;
+ unsigned short shi2_current_uses;
+ char far * shi2_path;
+ char shi2_passwd[SHPWLEN_LM20+1];
+ char shi2_pad2;
+}; /* share_info_2 */
+
+/****************************************************************
+ * *
+ * Data structure templates *
+ * *
+ ****************************************************************/
+
+
+struct service_info_0 {
+ char svci0_name[SNLEN_LM20+1];
+}; /* service_info_0 */
+
+struct service_info_1 {
+ char svci1_name[SNLEN_LM20+1]; /* service name */
+ unsigned short svci1_status; /* See status values below */
+ unsigned long svci1_code; /* install code of service */
+ unsigned short svci1_pid; /* pid of service program */
+}; /* service_info_1 */
+
+struct service_info_2 {
+ char svci2_name[SNLEN_LM20+1]; /* service name */
+ unsigned short svci2_status; /* See status values below */
+ unsigned long svci2_code; /* install code of service */
+ unsigned short svci2_pid; /* pid of service program */
+ char svci2_text[STXTLEN_LM20+1];/* text area for use by services */
+}; /* service_info_2 */
+
+struct service_status {
+ unsigned short svcs_status; /* See status values below */
+ unsigned long svcs_code; /* install code of service */
+ unsigned short svcs_pid; /* pid of service program */
+ char svcs_text[STXTLEN_LM20+1]; /* text area for use by services */
+}; /* service_status */
+
+/****************************************************************
+ * *
+ * Data structure templates - ACCESS *
+ * *
+ ****************************************************************/
+
+struct access_list {
+ char acl_ugname[UNLEN_LM20+1];
+ char acl_ugname_pad_1;
+ short acl_access;
+}; /* access_list */
+
+struct access_info_0 {
+ char far * acc0_resource_name;
+}; /* access_info_0 */
+
+struct access_info_1 {
+ char far * acc1_resource_name;
+ short acc1_attr; /* See values below */
+ short acc1_count;
+}; /* access_info_1 */
+
+/****************************************************************
+ * *
+ * Special values and constants - ACCESS *
+ * *
+ ****************************************************************/
+
+/*
+ * Maximum number of permission entries for each resource.
+ */
+
+#define MAXPERMENTRIES 64
+
+
+/****************************************************************
+ * *
+ * Data structure templates - NETBIOS *
+ * *
+ ****************************************************************/
+
+
+struct netbios_info_0 {
+ char nb0_net_name[NETBIOS_NAME_LEN+1];
+}; /* netbios_info_0 */
+
+struct netbios_info_1 {
+ char nb1_net_name[NETBIOS_NAME_LEN+1];
+ char nb1_driver_name[DEVLEN_LM20+1];/* OS/2 device driver name */
+ unsigned char nb1_lana_num; /* LAN adapter number of this net */
+ char nb1_pad_1;
+ unsigned short nb1_driver_type;
+ unsigned short nb1_net_status;
+ unsigned long nb1_net_bandwidth; /* Network bandwidth, bits/second */
+ unsigned short nb1_max_sess; /* Max number of sessions */
+ unsigned short nb1_max_ncbs; /* Max number of outstanding NCBs */
+ unsigned short nb1_max_names; /* Max number of names */
+}; /* netbios_info_1 */
+
+
+/****************************************************************
+ * *
+ * Special values and constants - NETBIOS *
+ * *
+ ****************************************************************/
+
+
+/*
+ * Driver types (nb1_driver_type).
+ */
+
+#define NB_TYPE_NCB 1
+#define NB_TYPE_MCB 2
+
+/*
+ * Bits defined in nb1_net_status.
+ */
+
+#define NB_LAN_FLAGS_MASK 0x3FFF /* Mask for LAN Flags */
+#define NB_LAN_MANAGED 0x0001 /* LAN is managed by redirector */
+#define NB_LAN_LOOPBACK 0x0002 /* LAN is a loopback driver */
+#define NB_LAN_SENDNOACK 0x0004 /* LAN allows SendNoAck NCBs */
+#define NB_LAN_LMEXT 0x0008 /* LAN supports LAN Manager extended NCBs */
+#define NB_LAN_INTNCB 0x0010 /* LAN allows NCB submission at */
+ /* interrupt time (from NCBDone) */
+#define NB_LAN_16M 0x0020 /* LAN can support phys addr > 16M */
+
+#define NB_LAN_LM10PLUS 0x0080 /* Transport supports extensions to */
+ /* LM10 to work with Netbios$ drvr */
+#define NB_LAN_NONETBIND 0x0100 /* Driver can not netbind on bootup */
+
+
+#define NB_OPEN_MODE_MASK 0xC000 /* Mask for NetBios Open Modes */
+#define NB_OPEN_REGULAR 0x4000 /* NetBios opened in Regular mode */
+#define NB_OPEN_PRIVILEGED 0x8000 /* NetBios opened in Privileged mode */
+#define NB_OPEN_EXCLUSIVE 0xC000 /* NetBios opened in Exclusive mode */
+
+/*
+ * Open modes for NetBiosOpen.
+ */
+
+#define NB_REGULAR 1
+#define NB_PRIVILEGED 2
+#define NB_EXCLUSIVE 3
+
+#pragma pack()
+
+#define NERR_Success 0
+
+/*** NERR_BASE is the base of error codes from network utilities,
+ * chosen to avoid conflict with OS/2 and redirector error codes.
+ * 2100 is a value that has been assigned to us by OS/2.
+ */
+#define NERR_BASE 2100
+
+
+
+/* UNUSED BASE+0 */
+/* UNUSED BASE+1 */
+#define NERR_NetNotStarted (NERR_BASE+2) /* The workstation driver (NETWKSTA.SYS on OS/2 workstations, NETWKSTA.EXE on DOS workstations) isn't installed. */
+#define NERR_UnknownServer (NERR_BASE+3) /* The server cannot be located. */
+#define NERR_ShareMem (NERR_BASE+4) /* An internal error occurred. The network cannot access a shared memory segment. */
+#define NERR_NoNetworkResource (NERR_BASE+5) /* A network resource shortage occurred . */
+#define NERR_RemoteOnly (NERR_BASE+6) /* This operation is not supported on workstations. */
+#define NERR_DevNotRedirected (NERR_BASE+7) /* The device is not connected. */
+/* UNUSED BASE+8 */
+/* UNUSED BASE+9 */
+/* UNUSED BASE+10 */
+/* UNUSED BASE+11 */
+/* UNUSED BASE+12 */
+/* UNUSED BASE+13 */
+#define NERR_ServerNotStarted (NERR_BASE+14) /* The Server service isn't started. */
+#define NERR_ItemNotFound (NERR_BASE+15) /* The queue is empty. */
+#define NERR_UnknownDevDir (NERR_BASE+16) /* The device or directory does not exist. */
+#define NERR_RedirectedPath (NERR_BASE+17) /* The operation is invalid on a redirected resource. */
+#define NERR_DuplicateShare (NERR_BASE+18) /* The name has already been shared. */
+#define NERR_NoRoom (NERR_BASE+19) /* The server is currently out of the requested resource. */
+/* UNUSED BASE+20 */
+#define NERR_TooManyItems (NERR_BASE+21) /* Requested add of item exceeds maximum allowed. */
+#define NERR_InvalidMaxUsers (NERR_BASE+22) /* The Peer service supports only two simultaneous users. */
+#define NERR_BufTooSmall (NERR_BASE+23) /* The API return buffer is too small. */
+/* UNUSED BASE+24 */
+/* UNUSED BASE+25 */
+/* UNUSED BASE+26 */
+#define NERR_RemoteErr (NERR_BASE+27) /* A remote API error occurred. */
+/* UNUSED BASE+28 */
+/* UNUSED BASE+29 */
+/* UNUSED BASE+30 */
+#define NERR_LanmanIniError (NERR_BASE+31) /* An error occurred when opening or reading LANMAN.INI. */
+/* UNUSED BASE+32 */
+/* UNUSED BASE+33 */
+#define NERR_OS2IoctlError (NERR_BASE+34) /* An internal error occurred when calling the workstation driver. */
+/* UNUSED BASE+35 */
+#define NERR_NetworkError (NERR_BASE+36) /* A general network error occurred. */
+/* UNUSED BASE+37 */
+#define NERR_WkstaNotStarted (NERR_BASE+38) /* The Workstation service has not been started. */
+#define NERR_BrowserNotStarted (NERR_BASE+39) /* The requested information is not available. */
+#define NERR_InternalError (NERR_BASE+40) /* An internal LAN Manager error occurred.*/
+#define NERR_BadTransactConfig (NERR_BASE+41) /* The server is not configured for transactions. */
+#define NERR_InvalidAPI (NERR_BASE+42) /* The requested API isn't supported on the remote server. */
+#define NERR_BadEventName (NERR_BASE+43) /* The event name is invalid. */
+/* UNUSED BASE+44 */
+
+/*
+ * Config API related
+ * Error codes from BASE+45 to BASE+49
+ */
+
+/* UNUSED BASE+45 */
+#define NERR_CfgCompNotFound (NERR_BASE+46) /* Could not find the specified component in LANMAN.INI. */
+#define NERR_CfgParamNotFound (NERR_BASE+47) /* Could not find the specified parameter in LANMAN.INI. */
+#define NERR_LineTooLong (NERR_BASE+49) /* A line in LANMAN.INI is too long. */
+
+/*
+ * Spooler API related
+ * Error codes from BASE+50 to BASE+79
+ */
+
+#define NERR_QNotFound (NERR_BASE+50) /* The printer queue does not exist. */
+#define NERR_JobNotFound (NERR_BASE+51) /* The print job does not exist. */
+#define NERR_DestNotFound (NERR_BASE+52) /* The printer destination cannot be found. */
+#define NERR_DestExists (NERR_BASE+53) /* The printer destination already exists. */
+#define NERR_QExists (NERR_BASE+54) /* The printer queue already exists. */
+#define NERR_QNoRoom (NERR_BASE+55) /* No more printer queues can be added. */
+#define NERR_JobNoRoom (NERR_BASE+56) /* No more print jobs can be added. */
+#define NERR_DestNoRoom (NERR_BASE+57) /* No more printer destinations can be added. */
+#define NERR_DestIdle (NERR_BASE+58) /* This printer destination is idle and cannot accept control operations. */
+#define NERR_DestInvalidOp (NERR_BASE+59) /* This printer destination request contains an invalid control function. */
+#define NERR_ProcNoRespond (NERR_BASE+60) /* The printer processor is not responding. */
+#define NERR_SpoolerNotLoaded (NERR_BASE+61) /* The spooler is not running. */
+#define NERR_DestInvalidState (NERR_BASE+62) /* This operation cannot be performed on the print destination in its current state. */
+#define NERR_QInvalidState (NERR_BASE+63) /* This operation cannot be performed on the printer queue in its current state. */
+#define NERR_JobInvalidState (NERR_BASE+64) /* This operation cannot be performed on the print job in its current state. */
+#define NERR_SpoolNoMemory (NERR_BASE+65) /* A spooler memory allocation failure occurred. */
+#define NERR_DriverNotFound (NERR_BASE+66) /* The device driver does not exist. */
+#define NERR_DataTypeInvalid (NERR_BASE+67) /* The datatype is not supported by the processor. */
+#define NERR_ProcNotFound (NERR_BASE+68) /* The print processor is not installed. */
+
+/*
+ * Service API related
+ * Error codes from BASE+80 to BASE+99
+ */
+
+#define NERR_ServiceTableLocked (NERR_BASE+80) /* The service does not respond to control actions. */
+#define NERR_ServiceTableFull (NERR_BASE+81) /* The service table is full. */
+#define NERR_ServiceInstalled (NERR_BASE+82) /* The requested service has already been started. */
+#define NERR_ServiceEntryLocked (NERR_BASE+83) /* The service does not respond to control actions. */
+#define NERR_ServiceNotInstalled (NERR_BASE+84) /* The service has not been started. */
+#define NERR_BadServiceName (NERR_BASE+85) /* The service name is invalid. */
+#define NERR_ServiceCtlTimeout (NERR_BASE+86) /* The service is not responding to the control function. */
+#define NERR_ServiceCtlBusy (NERR_BASE+87) /* The service control is busy. */
+#define NERR_BadServiceProgName (NERR_BASE+88) /* LANMAN.INI contains an invalid service program name. */
+#define NERR_ServiceNotCtrl (NERR_BASE+89) /* The service cannot be controlled in its present state. */
+#define NERR_ServiceKillProc (NERR_BASE+90) /* The service ended abnormally. */
+#define NERR_ServiceCtlNotValid (NERR_BASE+91) /* The requested pause or stop is not valid for this service. */
+
+/*
+ * Wksta and Logon API related
+ * Error codes from BASE+100 to BASE+118
+ */
+
+#define NERR_AlreadyLoggedOn (NERR_BASE+100) /* This workstation is already logged on to the local-area network. */
+#define NERR_NotLoggedOn (NERR_BASE+101) /* The workstation isn't logged on to the local-area network. */
+#define NERR_BadUsername (NERR_BASE+102) /* The username or groupname parameter is invalid. */
+#define NERR_BadPassword (NERR_BASE+103) /* The password parameter is invalid. */
+#define NERR_UnableToAddName_W (NERR_BASE+104) /* @W The logon processor did not add the message alias. */
+#define NERR_UnableToAddName_F (NERR_BASE+105) /* The logon processor did not add the message alias. */
+#define NERR_UnableToDelName_W (NERR_BASE+106) /* @W The logoff processor did not delete the message alias. */
+#define NERR_UnableToDelName_F (NERR_BASE+107) /* The logoff processor did not delete the message alias. */
+/* UNUSED BASE+108 */
+#define NERR_LogonsPaused (NERR_BASE+109) /* Network logons are paused. */
+#define NERR_LogonServerConflict (NERR_BASE+110)/* A centralized logon-server conflict occurred. */
+#define NERR_LogonNoUserPath (NERR_BASE+111) /* The server is configured without a valid user path. */
+#define NERR_LogonScriptError (NERR_BASE+112) /* An error occurred while loading or running the logon script. */
+/* UNUSED BASE+113 */
+#define NERR_StandaloneLogon (NERR_BASE+114) /* The logon server was not specified. Your computer will be logged on as STANDALONE. */
+#define NERR_LogonServerNotFound (NERR_BASE+115) /* The logon server cannot be found. */
+#define NERR_LogonDomainExists (NERR_BASE+116) /* There is already a logon domain for this computer. */
+#define NERR_NonValidatedLogon (NERR_BASE+117) /* The logon server could not validate the logon. */
+
+/*
+ * ACF API related (access, user, group)
+ * Error codes from BASE+119 to BASE+149
+ */
+
+#define NERR_ACFNotFound (NERR_BASE+119) /* The accounts file NET.ACC cannot be found. */
+#define NERR_GroupNotFound (NERR_BASE+120) /* The groupname cannot be found. */
+#define NERR_UserNotFound (NERR_BASE+121) /* The username cannot be found. */
+#define NERR_ResourceNotFound (NERR_BASE+122) /* The resource name cannot be found. */
+#define NERR_GroupExists (NERR_BASE+123) /* The group already exists. */
+#define NERR_UserExists (NERR_BASE+124) /* The user account already exists. */
+#define NERR_ResourceExists (NERR_BASE+125) /* The resource permission list already exists. */
+#define NERR_NotPrimary (NERR_BASE+126) /* The UAS database is replicant and will not allow updates. */
+#define NERR_ACFNotLoaded (NERR_BASE+127) /* The user account system has not been started. */
+#define NERR_ACFNoRoom (NERR_BASE+128) /* There are too many names in the user account system. */
+#define NERR_ACFFileIOFail (NERR_BASE+129) /* A disk I/O failure occurred.*/
+#define NERR_ACFTooManyLists (NERR_BASE+130) /* The limit of 64 entries per resource was exceeded. */
+#define NERR_UserLogon (NERR_BASE+131) /* Deleting a user with a session is not allowed. */
+#define NERR_ACFNoParent (NERR_BASE+132) /* The parent directory cannot be located. */
+#define NERR_CanNotGrowSegment (NERR_BASE+133) /* Unable to grow UAS session cache segment. */
+#define NERR_SpeGroupOp (NERR_BASE+134) /* This operation is not allowed on this special group. */
+#define NERR_NotInCache (NERR_BASE+135) /* This user is not cached in UAS session cache. */
+#define NERR_UserInGroup (NERR_BASE+136) /* The user already belongs to this group. */
+#define NERR_UserNotInGroup (NERR_BASE+137) /* The user does not belong to this group. */
+#define NERR_AccountUndefined (NERR_BASE+138) /* This user account is undefined. */
+#define NERR_AccountExpired (NERR_BASE+139) /* This user account has expired. */
+#define NERR_InvalidWorkstation (NERR_BASE+140) /* The user is not allowed to log on from this workstation. */
+#define NERR_InvalidLogonHours (NERR_BASE+141) /* The user is not allowed to log on at this time. */
+#define NERR_PasswordExpired (NERR_BASE+142) /* The password of this user has expired. */
+#define NERR_PasswordCantChange (NERR_BASE+143) /* The password of this user cannot change. */
+#define NERR_PasswordHistConflict (NERR_BASE+144) /* This password cannot be used now. */
+#define NERR_PasswordTooShort (NERR_BASE+145) /* The password is shorter than required. */
+#define NERR_PasswordTooRecent (NERR_BASE+146) /* The password of this user is too recent to change. */
+#define NERR_InvalidDatabase (NERR_BASE+147) /* The UAS database file is corrupted. */
+#define NERR_DatabaseUpToDate (NERR_BASE+148) /* No updates are necessary to this replicant UAS database. */
+#define NERR_SyncRequired (NERR_BASE+149) /* This replicant database is outdated; synchronization is required. */
+
+/*
+ * Use API related
+ * Error codes from BASE+150 to BASE+169
+ */
+
+#define NERR_UseNotFound (NERR_BASE+150) /* The connection cannot be found. */
+#define NERR_BadAsgType (NERR_BASE+151) /* This asg_type is invalid. */
+#define NERR_DeviceIsShared (NERR_BASE+152) /* This device is currently being shared. */
+
+/*
+ * Message Server related
+ * Error codes BASE+170 to BASE+209
+ */
+
+#define NERR_NoComputerName (NERR_BASE+170) /* A computername has not been configured. */
+#define NERR_MsgAlreadyStarted (NERR_BASE+171) /* The Messenger service is already started. */
+#define NERR_MsgInitFailed (NERR_BASE+172) /* The Messenger service failed to start. */
+#define NERR_NameNotFound (NERR_BASE+173) /* The message alias cannot be found on the local-area network. */
+#define NERR_AlreadyForwarded (NERR_BASE+174) /* This message alias has already been forwarded. */
+#define NERR_AddForwarded (NERR_BASE+175) /* This message alias has been added but is still forwarded. */
+#define NERR_AlreadyExists (NERR_BASE+176) /* This message alias already exists locally. */
+#define NERR_TooManyNames (NERR_BASE+177) /* The maximum number of added message aliases has been exceeded. */
+#define NERR_DelComputerName (NERR_BASE+178) /* The computername cannot be deleted.*/
+#define NERR_LocalForward (NERR_BASE+179) /* Messages cannot be forwarded back to the same workstation. */
+#define NERR_GrpMsgProcessor (NERR_BASE+180) /* Error in domain message processor */
+#define NERR_PausedRemote (NERR_BASE+181) /* The message was sent, but the recipient has paused the Messenger service. */
+#define NERR_BadReceive (NERR_BASE+182) /* The message was sent but not received. */
+#define NERR_NameInUse (NERR_BASE+183) /* The message alias is currently in use. Try again later. */
+#define NERR_MsgNotStarted (NERR_BASE+184) /* The Messenger service has not been started. */
+#define NERR_NotLocalName (NERR_BASE+185) /* The name is not on the local computer. */
+#define NERR_NoForwardName (NERR_BASE+186) /* The forwarded message alias cannot be found on the network. */
+#define NERR_RemoteFull (NERR_BASE+187) /* The message alias table on the remote station is full. */
+#define NERR_NameNotForwarded (NERR_BASE+188) /* Messages for this alias are not currently being forwarded. */
+#define NERR_TruncatedBroadcast (NERR_BASE+189) /* The broadcast message was truncated. */
+#define NERR_InvalidDevice (NERR_BASE+194) /* This is an invalid devicename. */
+#define NERR_WriteFault (NERR_BASE+195) /* A write fault occurred. */
+/* UNUSED BASE+196 */
+#define NERR_DuplicateName (NERR_BASE+197) /* A duplicate message alias exists on the local-area network. */
+#define NERR_DeleteLater (NERR_BASE+198) /* @W This message alias will be deleted later. */
+#define NERR_IncompleteDel (NERR_BASE+199) /* The message alias was not successfully deleted from all networks. */
+#define NERR_MultipleNets (NERR_BASE+200) /* This operation is not supported on machines with multiple networks. */
+
+/*
+ * Server API related
+ * Error codes BASE+210 to BASE+229
+ */
+
+#define NERR_NetNameNotFound (NERR_BASE+210) /* This shared resource does not exist.*/
+#define NERR_DeviceNotShared (NERR_BASE+211) /* This device is not shared. */
+#define NERR_ClientNameNotFound (NERR_BASE+212) /* A session does not exist with that computername. */
+#define NERR_FileIdNotFound (NERR_BASE+214) /* There isn't an open file with that ID number. */
+#define NERR_ExecFailure (NERR_BASE+215) /* A failure occurred when executing a remote administration command. */
+#define NERR_TmpFile (NERR_BASE+216) /* A failure occurred when opening a remote temporary file. */
+#define NERR_TooMuchData (NERR_BASE+217) /* The data returned from a remote administration command has been truncated to 64K. */
+#define NERR_DeviceShareConflict (NERR_BASE+218) /* This device cannot be shared as both a spooled and a non-spooled resource. */
+#define NERR_BrowserTableIncomplete (NERR_BASE+219) /* The information in the list of servers may be incorrect. */
+#define NERR_NotLocalDomain (NERR_BASE+220) /* The computer isn't active on this domain. */
+
+/*
+ * CharDev API related
+ * Error codes BASE+230 to BASE+249
+ */
+
+/* UNUSED BASE+230 */
+#define NERR_DevInvalidOpCode (NERR_BASE+231) /* The operation is invalid for this device. */
+#define NERR_DevNotFound (NERR_BASE+232) /* This device cannot be shared. */
+#define NERR_DevNotOpen (NERR_BASE+233) /* This device was not open. */
+#define NERR_BadQueueDevString (NERR_BASE+234) /* This devicename list is invalid. */
+#define NERR_BadQueuePriority (NERR_BASE+235) /* The queue priority is invalid. */
+#define NERR_NoCommDevs (NERR_BASE+237) /* There are no shared communication devices. */
+#define NERR_QueueNotFound (NERR_BASE+238) /* The queue you specified doesn't exist. */
+#define NERR_BadDevString (NERR_BASE+240) /* This list of devices is invalid. */
+#define NERR_BadDev (NERR_BASE+241) /* The requested device is invalid. */
+#define NERR_InUseBySpooler (NERR_BASE+242) /* This device is already in use by the spooler. */
+#define NERR_CommDevInUse (NERR_BASE+243) /* This device is already in use as a communication device. */
+
+/*
+ * NetICanonicalize and NetIType and NetIMakeLMFileName
+ * NetIListCanon and NetINameCheck
+ * Error codes BASE+250 to BASE+269
+ */
+
+#define NERR_InvalidComputer (NERR_BASE+251) /* This computername is invalid. */
+/* UNUSED BASE+252 */
+/* UNUSED BASE+253 */
+#define NERR_MaxLenExceeded (NERR_BASE+254) /* The string and prefix specified are too long. */
+/* UNUSED BASE+255 */
+#define NERR_BadComponent (NERR_BASE+256) /* This path component is invalid. */
+#define NERR_CantType (NERR_BASE+257) /* Cannot determine type of input. */
+/* UNUSED BASE+258 */
+/* UNUSED BASE+259 */
+#define NERR_TooManyEntries (NERR_BASE+262) /* The buffer for types is not big enough. */
+
+/*
+ * NetProfile
+ * Error codes BASE+270 to BASE+276
+ */
+
+#define NERR_ProfileFileTooBig (NERR_BASE+270) /* Profile files cannot exceed 64K. */
+#define NERR_ProfileOffset (NERR_BASE+271) /* The start offset is out of range. */
+#define NERR_ProfileCleanup (NERR_BASE+272) /* The system cannot delete current connections to network resources. */
+#define NERR_ProfileUnknownCmd (NERR_BASE+273) /* The system was unable to parse the command line in this file.*/
+#define NERR_ProfileLoadErr (NERR_BASE+274) /* An error occurred while loading the profile file. */
+#define NERR_ProfileSaveErr (NERR_BASE+275) /* @W Errors occurred while saving the profile file. The profile was partially saved. */
+
+
+/*
+ * NetAudit and NetErrorLog
+ * Error codes BASE+277 to BASE+279
+ */
+
+#define NERR_LogOverflow (NERR_BASE+277) /* This log file exceeds the maximum defined size. */
+#define NERR_LogFileChanged (NERR_BASE+278) /* This log file has changed between reads. */
+#define NERR_LogFileCorrupt (NERR_BASE+279) /* This log file is corrupt. */
+
+/*
+ * NetRemote
+ * Error codes BASE+280 to BASE+299
+ */
+#define NERR_SourceIsDir (NERR_BASE+280) /* The source path cannot be a directory. */
+#define NERR_BadSource (NERR_BASE+281) /* The source path is illegal. */
+#define NERR_BadDest (NERR_BASE+282) /* The destination path is illegal. */
+#define NERR_DifferentServers (NERR_BASE+283) /* The source and destination paths are on different servers. */
+/* UNUSED BASE+284 */
+#define NERR_RunSrvPaused (NERR_BASE+285) /* The Run server you requested is paused. */
+/* UNUSED BASE+286 */
+/* UNUSED BASE+287 */
+/* UNUSED BASE+288 */
+#define NERR_ErrCommRunSrv (NERR_BASE+289) /* An error occurred when communicating with a Run server. */
+/* UNUSED BASE+290 */
+#define NERR_ErrorExecingGhost (NERR_BASE+291) /* An error occurred when starting a background process. */
+#define NERR_ShareNotFound (NERR_BASE+292) /* The shared resource you are connected to could not be found.*/
+/* UNUSED BASE+293 */
+/* UNUSED BASE+294 */
+
+
+/*
+ * NetWksta.sys (redir) returned error codes.
+ *
+ * NERR_BASE + (300-329)
+ */
+
+#define NERR_InvalidLana (NERR_BASE+300) /* The LAN adapter number is invalid. */
+#define NERR_OpenFiles (NERR_BASE+301) /* There are open files on the connection. */
+#define NERR_ActiveConns (NERR_BASE+302) /* Active connections still exist. */
+#define NERR_BadPasswordCore (NERR_BASE+303) /* This netname or password is invalid. */
+#define NERR_DevInUse (NERR_BASE+304) /* The device is being accessed by an active process. */
+#define NERR_LocalDrive (NERR_BASE+305) /* The drive letter is in use locally. */
+
+/*
+ * Alert error codes.
+ *
+ * NERR_BASE + (330-339)
+ */
+#define NERR_AlertExists (NERR_BASE+330) /* The specified client is already registered for the specified event. */
+#define NERR_TooManyAlerts (NERR_BASE+331) /* The alert table is full. */
+#define NERR_NoSuchAlert (NERR_BASE+332) /* An invalid or nonexistent alertname was raised. */
+#define NERR_BadRecipient (NERR_BASE+333) /* The alert recipient is invalid.*/
+#define NERR_AcctLimitExceeded (NERR_BASE+334) /* A user's session with this server has been deleted
+ * because his logon hours are no longer valid */
+
+/*
+ * Additional Error and Audit log codes.
+ *
+ * NERR_BASE +(340-343)
+ */
+#define NERR_InvalidLogSeek (NERR_BASE+340) /* The log file does not contain the requested record number. */
+/* UNUSED BASE+341 */
+/* UNUSED BASE+342 */
+/* UNUSED BASE+343 */
+
+/*
+ * Additional UAS and NETLOGON codes
+ *
+ * NERR_BASE +(350-359)
+ */
+#define NERR_BadUasConfig (NERR_BASE+350) /* The user account system database is not configured correctly. */
+#define NERR_InvalidUASOp (NERR_BASE+351) /* This operation is not permitted when the Netlogon service is running. */
+#define NERR_LastAdmin (NERR_BASE+352) /* This operation is not allowed on the last admin account. */
+#define NERR_DCNotFound (NERR_BASE+353) /* Unable to find domain controller for this domain. */
+#define NERR_LogonTrackingError (NERR_BASE+354) /* Unable to set logon information for this user. */
+#define NERR_NetlogonNotStarted (NERR_BASE+355) /* The Netlogon service has not been started. */
+#define NERR_CanNotGrowUASFile (NERR_BASE+356) /* Unable to grow the user account system database. */
+/* UNUSED BASE+357 */
+/* UNUSED BASE+358 */
+/* UNUSED BASE+359 */
+
+/*
+ * Server Integration error codes.
+ *
+ * NERR_BASE +(360-369)
+ */
+#define NERR_NoSuchServer (NERR_BASE+360) /* The server ID does not specify a valid server. */
+#define NERR_NoSuchSession (NERR_BASE+361) /* The session ID does not specify a valid session. */
+#define NERR_NoSuchConnection (NERR_BASE+362) /* The connection ID does not specify a valid connection. */
+#define NERR_TooManyServers (NERR_BASE+363) /* There is no space for another entry in the table of available servers. */
+#define NERR_TooManySessions (NERR_BASE+364) /* The server has reached the maximum number of sessions it supports. */
+#define NERR_TooManyConnections (NERR_BASE+365) /* The server has reached the maximum number of connections it supports. */
+#define NERR_TooManyFiles (NERR_BASE+366) /* The server cannot open more files because it has reached its maximum number. */
+#define NERR_NoAlternateServers (NERR_BASE+367) /* There are no alternate servers registered on this server. */
+/* UNUSED BASE+368 */
+/* UNUSED BASE+369 */
+
+/*
+ * UPS error codes.
+ *
+ * NERR_BASE + (380-384)
+ */
+#define NERR_UPSDriverNotStarted (NERR_BASE+380) /* The UPS driver could not be accessed by the UPS service. */
+/* UNUSED BASE+381 */
+/* UNUSED BASE+382 */
+/* UNUSED BASE+383 */
+/* UNUSED BASE+384 */
+
+/*
+ * Remoteboot error codes.
+ *
+ * NERR_BASE + (400-419)
+ * Error codes 400 - 405 are used by RPLBOOT.SYS.
+ * Error codes 403, 407 - 416 are used by RPLLOADR.COM,
+ * Error code 417 is the alerter message of REMOTEBOOT (RPLSERVR.EXE).
+ * Error code 418 is for when REMOTEBOOT can't start
+ * Error code 419 is for a disallowed 2nd rpl connection
+ */
+#define NERR_BadDosRetCode (NERR_BASE+400) /* The program below returned an MS-DOS error code:*/
+#define NERR_ProgNeedsExtraMem (NERR_BASE+401) /* The program below needs more memory:*/
+#define NERR_BadDosFunction (NERR_BASE+402) /* The program below called an unsupported MS-DOS function:*/
+#define NERR_RemoteBootFailed (NERR_BASE+403) /* The workstation failed to boot.*/
+#define NERR_BadFileCheckSum (NERR_BASE+404) /* The file below is corrupt.*/
+#define NERR_NoRplBootSystem (NERR_BASE+405) /* No loader is specified in the boot-block definition file.*/
+#define NERR_RplLoadrNetBiosErr (NERR_BASE+406) /* NetBIOS returned an error: The NCB and SMB are dumped above.*/
+#define NERR_RplLoadrDiskErr (NERR_BASE+407) /* A disk I/O error occurred.*/
+#define NERR_ImageParamErr (NERR_BASE+408) /* Image parameter substitution failed.*/
+#define NERR_TooManyImageParams (NERR_BASE+409) /* Too many image parameters cross disk sector boundaries.*/
+#define NERR_NonDosFloppyUsed (NERR_BASE+410) /* The image was not generated from an MS-DOS diskette formatted with /S.*/
+#define NERR_RplBootRestart (NERR_BASE+411) /* Remote boot will be restarted later.*/
+#define NERR_RplSrvrCallFailed (NERR_BASE+412) /* The call to the Remoteboot server failed.*/
+#define NERR_CantConnectRplSrvr (NERR_BASE+413) /* Cannot connect to the Remoteboot server.*/
+#define NERR_CantOpenImageFile (NERR_BASE+414) /* Cannot open image file on the Remoteboot server.*/
+#define NERR_CallingRplSrvr (NERR_BASE+415) /* Connecting to the Remoteboot server...*/
+#define NERR_StartingRplBoot (NERR_BASE+416) /* Connecting to the Remoteboot server...*/
+#define NERR_RplBootServiceTerm (NERR_BASE+417) /* Remote boot service was stopped; check the error log for the cause of the problem.*/
+#define NERR_RplBootStartFailed (NERR_BASE+418) /* Remote boot startup failed; check the error log for the cause of the problem.*/
+#define NERR_RPL_CONNECTED (NERR_BASE+419) /* A second connection to a Remoteboot resource is not allowed.*/
+
+/*
+ * FTADMIN API error codes
+ *
+ * NERR_BASE + (425-434)
+ *
+ */
+#define NERR_FTNotInstalled (NERR_BASE+425) /* DISKFT.SYS is not installed. */
+#define NERR_FTMONITNotRunning (NERR_BASE+426) /* FTMONIT is not running */
+#define NERR_FTDiskNotLocked (NERR_BASE+427) /* FTADMIN has not locked the disk. */
+#define NERR_FTDiskNotAvailable (NERR_BASE+428) /* Some other process has locked the disk. */
+#define NERR_FTUnableToStart (NERR_BASE+429) /* The verifier/correcter cannot be started. */
+#define NERR_FTNotInProgress (NERR_BASE+430) /* The verifier/correcter can't be aborted because it isn't started. */
+#define NERR_FTUnableToAbort (NERR_BASE+431) /* The verifier/correcter can't be aborted. */
+#define NERR_FTUnabletoChange (NERR_BASE+432) /* The disk could not be locked/unlocked. */
+#define NERR_FTInvalidErrHandle (NERR_BASE+433) /* The error handle was not recognized. */
+#define NERR_FTDriveNotMirrored (NERR_BASE+434) /* The drive is not mirrored. */
+
+
+#define MAX_NERR (NERR_BASE+899) /* This is the last error in NERR range. */
+
+/*
+ * end of list
+ *
+ * WARNING: Do not exceed MAX_NERR; values above this are used by
+ * other error code ranges (errlog.h, service.h, apperr.h).
+ */
+
+
diff --git a/private/os2/inc/os2nls.h b/private/os2/inc/os2nls.h
new file mode 100644
index 000000000..27a9b0686
--- /dev/null
+++ b/private/os2/inc/os2nls.h
@@ -0,0 +1,388 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2nls.h
+
+Abstract:
+
+ This file contains the NLS OS/2 V2.0/1.X API definitions for the OS/2 Subsystem
+
+Author:
+
+ Michael Jarus (mjarus) 15-Apr-1992
+
+Revision History:
+
+--*/
+
+#ifndef _OS2NLS_
+
+#define _OS2NLS_
+
+//#define OS2SS_INCLUDE_HEBREW
+//#define OS2SS_INCLUDE_ARABIC
+//#define OS2SS_INCLUDE_PRCHINA
+
+#define CCHMAXSYSTEMPATH 260
+
+/*
+ * NLS Support API Structures
+ */
+
+typedef struct _COUNTRYCODE {
+ ULONG country;
+ ULONG codepage;
+} COUNTRYCODE, *PCOUNTRYCODE;
+
+typedef struct _COUNTRYINFO {
+ ULONG country;
+ ULONG codepage;
+ ULONG fsDateFmt;
+ CHAR szCurrency[5];
+ CHAR szThousandsSeparator[2];
+ CHAR szDecimal[2];
+ CHAR szDateSeparator[2];
+ CHAR szTimeSeparator[2];
+ UCHAR fsCurrencyFmt;
+ UCHAR cDecimalPlace;
+ UCHAR fsTimeFmt;
+ USHORT abReserved1[2];
+ CHAR szDataSeparator[2];
+ USHORT abReserved2[5];
+} COUNTRYINFO, *PCOUNTRYINFO;
+
+/*
+ * NLS internal Structures (for NLS tables in client\nlstable.c)
+ */
+
+typedef struct _OD2_COUNTRY_ENTRY
+{
+ ULONG Country;
+ USHORT WinLanuage;
+ USHORT WinSubLanuage;
+ PCOUNTRYINFO pCtryInfo;
+ ULONG CodePageIndex1;
+ ULONG CodePageIndex2;
+ ULONG CaseMapFixTableIndex;
+} OD2_COUNTRY_ENTRY, *POD2_COUNTRY_ENTRY;
+
+typedef struct _OD2_CODEPAGE_ENTRY
+{
+ ULONG CodePage;
+ ULONG CollateIndex;
+ ULONG CaseMapIndex;
+ ULONG DBCSVecIndex;
+} OD2_CODEPAGE_ENTRY, *POD2_CODEPAGE_ENTRY;
+
+typedef struct _OD2_DBCS_VECTOR_ENTRY
+{
+ ULONG VectorSize;
+ UCHAR Vector[12];
+} OD2_DBCS_VECTOR_ENTRY, *POD2_DBCS_VECTOR_ENTRY;
+
+typedef struct _OD2_COLLATE_CTRY_ENTRY
+{
+ ULONG Country;
+ ULONG CodePage;
+ PUCHAR FixTable;
+} OD2_COLLATE_CTRY_ENTRY, *POD2_COLLATE_CTRY_ENTRY;
+
+
+/*** NLS Support API Calls */
+#ifndef APIRET // this happens for os2.exe, a windows app
+#define APIRET ULONG
+#endif
+#ifndef DWORD // this happens for client\dll*.c , a "nt" code
+#define DWORD ULONG
+#endif
+#ifndef LCID // this happens for client\dll*.c , a "nt" code
+typedef DWORD LCID;
+#endif
+#ifndef UINT // this happens for client\dll*.c , a "nt" code
+typedef unsigned int UINT;
+#endif
+
+/*
+ * NLS ssrtl routines
+ */
+
+extern USHORT Or2NlsLangIdTable[];
+
+DWORD
+Or2NlsGetCtryInfo(
+ IN LCID LocaleID,
+ IN UINT CodePage,
+ OUT PCOUNTRYINFO pCountryInfo
+ );
+
+DWORD
+Or2NlsGetMapTable(
+ IN LCID LocaleID,
+ IN UINT CodePage,
+ IN DWORD dwFlag,
+ OUT PUCHAR pTable
+ );
+
+DWORD
+Or2NlsGetCountryFromLocale(
+ IN LCID LocaleID,
+ OUT PULONG pCountry
+ );
+
+DWORD
+Or2NlsGetCPInfo(
+ IN UINT CP,
+ OUT POD2_DBCS_VECTOR_ENTRY DBCSVec
+ );
+
+/*
+ * NLS APIs
+ */
+
+APIRET
+DosQueryCtryInfo(
+ IN ULONG MaxCountryInfoLength,
+ IN PCOUNTRYCODE CountryCode,
+ OUT PCOUNTRYINFO CountryInfo,
+ OUT PULONG ActualCountryInfoLength
+ );
+
+APIRET
+DosQueryDBCSEnv(
+ IN ULONG MaxDBCSEvLength,
+ IN PCOUNTRYCODE CountryCode,
+ OUT PCHAR DBCSEv
+ );
+
+APIRET
+DosMapCase(
+ IN ULONG StringLength,
+ IN PCOUNTRYCODE CountryCode,
+ IN OUT PUCHAR String
+ );
+
+APIRET
+DosQueryCollate(
+ IN ULONG MaxCollateInfoLength,
+ IN PCOUNTRYCODE CountryCode,
+ OUT PUCHAR CollateInfo,
+ OUT PULONG ActualCollateInfoLength
+ );
+
+APIRET
+DosQueryCp(
+ IN ULONG MaxLengthCodePageList,
+ OUT ULONG CodePages[],
+ OUT PULONG CountCodePages
+ );
+
+APIRET
+DosSetProcessCp(
+ IN ULONG ulCodePage,
+ IN ULONG ulReserved
+ );
+
+/*
+ * NLS Support Internal Functions
+ */
+
+APIRET
+Od2InitNls( IN ULONG CodePage,
+ IN BOOLEAN StartBySM);
+
+APIRET
+Od2GetCtryInfo(
+ IN ULONG Country,
+ IN ULONG CodePage,
+ OUT PCOUNTRYINFO CountryInfo
+ );
+
+APIRET
+Od2GetDBCSEv(
+ IN ULONG Country,
+ IN ULONG CodePage,
+ IN OUT PUCHAR DBCSEv,
+ OUT PULONG StringLength
+ );
+
+APIRET
+Od2GetCaseMapTable(
+ IN ULONG Country,
+ IN ULONG CodePage,
+ OUT PUCHAR CaseMapTable);
+
+APIRET
+Od2GetCollateTable(
+ IN ULONG Country,
+ IN ULONG CodePage,
+ OUT PUCHAR CollateTable);
+
+APIRET
+Od2GetCtryCp(
+ IN OUT PULONG Country,
+ IN OUT PULONG CodePage,
+ OUT PULONG CountryIndex,
+ OUT PULONG CodePageIndex
+ );
+
+APIRET
+VioSetCp(
+ IN ULONG usReserved,
+ IN ULONG idCodePage,
+ IN ULONG hVio
+ );
+
+APIRET
+KbdSetCp(
+ IN ULONG usReserved,
+ IN ULONG idCodePage,
+ IN ULONG hKbd
+ );
+
+APIRET
+KbdFlushBuffer(
+ IN ULONG hKbd
+ );
+
+
+/*
+ * NLS Support API definitions
+ */
+
+#define OS2SS_NLS_MB_DEFAULT 0
+#define OS2SS_NLS_WC_DEFAULT 0
+
+#define COUNTRY_LATIN_AMERICA 3
+#define COUNTRY_SPAIN 34
+#define COUNTRY_JAPAN 81
+#define COUNTRY_SOUTH_KOREA 82
+#define COUNTRY_PRCHINA 86
+#define COUNTRY_TAIWAN 88
+#define COUNTRY_ARABIC 785
+#define COUNTRY_HEBREW 972
+
+//#define MESSAGE_LANGUAGE_ENGLISH LANG_ENGLISH
+//#define MESSAGE_LANGUAGE_FRENCH LANG_FRENCH
+//#define MESSAGE_LANGUAGE_GERMAN LANG_GERMAN
+//#define MESSAGE_LANGUAGE_ITALIAN LANG_ITALIAN
+//#define MESSAGE_LANGUAGE_SPANISH LANG_SPANISH
+//#define MESSAGE_LANGUAGE_DANISH LANG_DANISH
+//#define MESSAGE_LANGUAGE_DUTCH LANG_DUTCH
+//#define MESSAGE_LANGUAGE_FINNISH LANG_FINNISH
+//#define MESSAGE_LANGUAGE_NORWEGIAN LANG_NORWEGIAN
+//#define MESSAGE_LANGUAGE_PORTUGUESE LANG_PORTUGUESE
+//#define MESSAGE_LANGUAGE_SWEDISH LANG_SWEDISH
+//#define MESSAGE_LANGUAGE_JAPAN LANG_JAPANESE
+//#define MESSAGE_LANGUAGE_KOREAN LANG_KOREAN
+//#define MESSAGE_LANGUAGE_CHINESE LANG_CHINESE
+//#define MESSAGE_LANGUAGE_THAI LANG_THAI
+
+#define DATEFMT_MM_DD_YY 0
+#define DATEFMT_DD_MM_YY 1
+#define DATEFMT_YY_MM_DD 2
+
+#define CURRENCY_FOLLOW (UCHAR)0x01
+#define CURRENCY_SPACE (UCHAR)0x02
+#define CURRENCY_DECIMAL (UCHAR)0x04
+
+#define TIMEFMT_12_HOUR 0
+#define TIMEFMT_24_HOUR 1
+
+#define CODEPAGE_US 437
+#define CODEPAGE_MULTI 850
+#define CODEPAGE_PORTUGESE 860
+#define CODEPAGE_CANADIAN 863
+#define CODEPAGE_NORDIC 865
+#define CODEPAGE_JAPAN 932
+#define CODEPAGE_KOREA 934
+#define CODEPAGE_TAIWAN 938
+#define CODEPAGE_HEBREW 862
+#define CODEPAGE_ARABIC 864
+#define CODEPAGE_PRC 936
+
+#define INDEX_CODEPAGE_US 0
+#define INDEX_CODEPAGE_MULTI 1
+#define INDEX_CODEPAGE_PORTUGESE 2
+#define INDEX_CODEPAGE_CANADIAN 3
+#define INDEX_CODEPAGE_NORDIC 4
+#define INDEX_CODEPAGE_JAPAN 5
+#define INDEX_CODEPAGE_KOREA 6
+#define INDEX_CODEPAGE_TAIWAN 7
+#define INDEX_CODEPAGE_HEBREW 8
+#define INDEX_CODEPAGE_ARABIC 9
+#define INDEX_CODEPAGE_PRC 10
+
+#define INDEX_DBCS_437 0
+#define INDEX_DBCS_850 0
+#define INDEX_DBCS_860 0
+#define INDEX_DBCS_863 0
+#define INDEX_DBCS_865 0
+#define INDEX_DBCS_932 1
+#define INDEX_DBCS_934 2
+#define INDEX_DBCS_938 3
+#define INDEX_DBCS_862 0
+#define INDEX_DBCS_864 0
+#define INDEX_DBCS_936 4
+
+#define INDEX_COLLATE_437 0
+#define INDEX_COLLATE_850 1
+#define INDEX_COLLATE_860 2
+#define INDEX_COLLATE_863 3
+#define INDEX_COLLATE_865 4
+#define INDEX_COLLATE_932 5
+#define INDEX_COLLATE_934 6
+#define INDEX_COLLATE_938 7
+#define INDEX_COLLATE_862 8
+#define INDEX_COLLATE_864 9
+#define INDEX_COLLATE_936 10
+
+#define INDEX_CASEMAP_437 0
+#define INDEX_CASEMAP_850 1
+#define INDEX_CASEMAP_860 2
+#define INDEX_CASEMAP_863 3
+#define INDEX_CASEMAP_865 4
+#define INDEX_CASEMAP_932 5
+#define INDEX_CASEMAP_934 6
+#define INDEX_CASEMAP_938 7
+#define INDEX_CASEMAP_862 8
+#define INDEX_CASEMAP_864 9
+#define INDEX_CASEMAP_936 10
+
+// index for CP fix table for 437 code page
+// pCaseMapFixTable field in OD2_COUNTRY_ENTRY/TABLE for OD2_FIX_CASEMAP_TABLE
+
+#define INDEX_FIX_CASE_UNITED_STATES 0
+#define INDEX_FIX_CASE_CANADA 0
+#define INDEX_FIX_CASE_LATIN_AMERICA 0
+#define INDEX_FIX_CASE_NETHERLANDS 2
+#define INDEX_FIX_CASE_BELGIUM 1
+#define INDEX_FIX_CASE_FRANCE 0
+#define INDEX_FIX_CASE_SPAIN 0
+#define INDEX_FIX_CASE_ITALY 0
+#define INDEX_FIX_CASE_SWITZERLAND 1
+#define INDEX_FIX_CASE_AUSTRIA 0
+#define INDEX_FIX_CASE_UNITED_KINGDOM 0
+#define INDEX_FIX_CASE_DENMARK 0
+#define INDEX_FIX_CASE_SWEDEN 1
+#define INDEX_FIX_CASE_NORWAY 0
+#define INDEX_FIX_CASE_GERMANY 0
+#define INDEX_FIX_CASE_MEXICO 0
+#define INDEX_FIX_CASE_BRAZIL 0
+#define INDEX_FIX_CASE_AUSTRALIA 0
+#define INDEX_FIX_CASE_NEW_ZEALAND 0
+#define INDEX_FIX_CASE_PORTUGAL 0
+#define INDEX_FIX_CASE_IRELAND 0
+#define INDEX_FIX_CASE_ICELAND 0
+#define INDEX_FIX_CASE_FINLAND 1
+#define INDEX_FIX_CASE_JAPAN 0
+#define INDEX_FIX_CASE_SOUTH_KOREA 0
+#define INDEX_FIX_CASE_TAIWAN 0
+#define INDEX_FIX_CASE_HEBREW 0
+#define INDEX_FIX_CASE_ARABIC 0
+#define INDEX_FIX_CASE_PRCHINA 0
+
+#endif // _OS2NLS_
+
diff --git a/private/os2/inc/os2nt.h b/private/os2/inc/os2nt.h
new file mode 100644
index 000000000..b47b3286f
--- /dev/null
+++ b/private/os2/inc/os2nt.h
@@ -0,0 +1,986 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2nt.h
+
+Abstract:
+
+ Prototypes for NT functions that are called from Win32 only os2ss files.
+
+Author:
+
+ Michael Jarus (mjarus) 21-Dec-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+/****************************************
+ * Definitions from nt.h and ntrtl.h
+ ***************************************/
+
+#ifndef NT_INCLUDED // or _NTRTL_
+
+VOID
+RtlFillMemoryUlong (
+ IN PVOID Destination,
+ IN ULONG Length,
+ IN ULONG Pattern
+ );
+
+#if DBG
+
+#define KdPrint(_x_) DbgPrint _x_
+
+ULONG
+DbgPrint(
+ PCH Format,
+ ...
+ );
+
+VOID
+RtlAssert(
+ PVOID FailedAssertion,
+ PVOID FileName,
+ ULONG LineNumber,
+ PCHAR Message OPTIONAL
+ );
+
+#define ASSERT( exp ) \
+ if (!(exp)) \
+ RtlAssert( #exp, __FILE__, __LINE__, NULL )
+
+#define ASSERTMSG( msg, exp ) \
+ if (!(exp)) \
+ RtlAssert( #exp, __FILE__, __LINE__, msg )
+
+#else
+
+#define KdPrint(_x_)
+
+#define ASSERT( exp )
+#define ASSERTMSG( msg, exp )
+#endif // DBG
+
+#endif // NT_INCLUDED
+
+/************************************
+ * Internal definitions from Win32
+ ***********************************/
+
+BOOL
+VerifyConsoleIoHandle(
+ HANDLE hIoHandle
+ );
+
+#ifdef DBCS
+// MSKK Feb.10.1993 V-AkihiS
+/*******************************************
+ * Intrenal definitions from Win32 for DBCS
+ *******************************************/
+BOOL
+GetConsoleNlsMode(
+ IN HANDLE hConsole,
+ OUT PDWORD lpdwNlsMode
+ );
+
+BOOL
+SetConsoleNlsMode(
+ IN HANDLE hConsole,
+ IN DWORD fdwNlsMode
+ );
+
+// MSKK Jul.02.1992 KazuM
+BOOL
+GetConsoleCharType(
+ IN HANDLE hConsole,
+ IN COORD coordCheck,
+ OUT PDWORD pdwType
+ );
+
+#define CHAR_TYPE_SBCS 0 // Displayed SBCS character
+#define CHAR_TYPE_LEADING 2 // Displayed leading byte of DBCS
+#define CHAR_TYPE_TRAILING 3 // Displayed trailing byte of DBCS
+#endif
+#ifdef JAPAN
+// MSKK May.11.1993 V-AkihiS
+
+// kbdjpn.h
+
+
+//
+// Returned this value as keyboard type of GetKeyboardType()
+//
+#define KBD_TYPE_JAPAN 7
+
+// There are Microsoft keyboard types
+#define SUB_KBD_TYPE_MICROSOFT 0x00
+#define MICROSOFT_KBD_101_TYPE 0
+#define MICROSOFT_KBD_AX_TYPE 1
+#define MICROSOFT_KBD_106_TYPE 2
+#define MICROSOFT_KBD_002_TYPE 3
+#define MICROSOFT_KBD_001_TYPE 4
+#define MICROSOFT_KBD_FUNC 12
+
+// There are AX keyboard types
+#define SUB_KBD_TYPE_AX 0x01
+#define AX_KBD_DESKTOP_TYPE 1
+#define AX_KBD_DESKTOP_FUNC 12
+
+// There are EPSON keyboard types
+#define SUB_KBD_TYPE_EPSON 0x04
+
+// There are FUJITSU keyboard types
+#define SUB_KBD_TYPE_FUJITSU 0x05
+#define FUJITSU_KBD_JIS_TYPE 0
+#define FUJITSU_KBD_OASYS_TYPE 1
+
+// There are IBM keyboard types
+#define SUB_KBD_TYPE_IBM 0x07
+#define IBM_KBD_001_TYPE 1
+#define IBM_KBD_002_TYPE 2
+#define IBM_KBD_003_TYPE 3
+#define IBM_KBD_A01_TYPE 4
+#define IBM_KBD_S_TYPE 5
+
+#define IBM_KBD_002_FUNC 12
+#define IBM_KBD_A01_FUNC 12
+
+// There are MATSUSITA keyboard types
+#define SUB_KBD_TYPE_MATSUSITA 0x0a
+
+// There are NEC keyboard types
+#define SUB_KBD_TYPE_NEC 0x0d
+#define NEC_KBD_NORMAL_TYPE 1
+#define NEC_KBD_N_MODE_TYPE 2
+#define NEC_KBD_H_MODE_TYPE 3
+#define NEC_KBD_LAPTOP_TYPE 4
+
+#define NEC_KBD_NORMAL_FUNC 15
+#define NEC_KBD_N_MODE_FUNC 10
+#define NEC_KBD_H_MODE_FUNC 15
+#define NEC_KBD_LAPTOP_FUNC 15
+
+// There are TOSHIBA keyboard types
+#define SUB_KBD_TYPE_TOSHIBA 0x12
+#define TOSHIBA_KBD_LAPTOP_TYPE 1
+#define TOSHIBA_KBD_LAPTOP_TENKEY_TYPE 2
+#define TOSHIBA_KBD_DESKTOP_TYPE 3
+#define TOSHIBA_KBD_J3100GX_TYPE 4
+
+#define TOSHIBA_KBD_LAPTOP_FUNC 10
+#define TOSHIBA_KBD_LAPTOP_TENKEY_FUNC 10
+#define TOSHIBA_KBD_DESKTOP_FUNC 12
+#define TOSHIBA_KBD_J3100GX_FUNC 10
+#endif
+
+/********************************************************
+ * Definitions of debug Win32 API (ssrtl\sswinapi.c)
+ *******************************************************/
+
+#if DBG
+BOOL
+Or2WinPeekConsoleInputA(
+ PSZ FuncName,
+ HANDLE hConsoleInput,
+ PINPUT_RECORD lpBuffer,
+ DWORD nLength,
+ LPDWORD lpNumberOfEventsRead
+ );
+
+BOOL
+Or2WinReadConsoleInputA(
+ PSZ FuncName,
+ HANDLE hConsoleInput,
+ PINPUT_RECORD lpBuffer,
+ DWORD nLength,
+ LPDWORD lpNumberOfEventsRead
+ );
+
+BOOL
+Or2WinWriteConsoleInputA(
+ PSZ FuncName,
+ HANDLE hConsoleInput,
+ PINPUT_RECORD lpBuffer,
+ DWORD nLength,
+ LPDWORD lpNumberOfEventsWritten
+ );
+
+BOOL
+Or2WinReadConsoleOutputCharacterA(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ LPSTR lpCharacter,
+ DWORD nLength,
+ COORD dwReadCoord,
+ LPDWORD lpNumberOfCharsRead
+ );
+
+BOOL
+Or2WinReadConsoleOutputCharacterW(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ LPWSTR lpCharacter,
+ DWORD nLength,
+ COORD dwReadCoord,
+ LPDWORD lpNumberOfCharsRead
+ );
+
+BOOL
+Or2WinReadConsoleOutputAttribute(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ LPWORD lpAttribute,
+ DWORD nLength,
+ COORD dwReadCoord,
+ LPDWORD lpNumberOfAttrsRead
+ );
+
+BOOL
+Or2WinWriteConsoleOutputCharacterA(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ LPSTR lpCharacter,
+ DWORD nLength,
+ COORD dwWriteCoord,
+ LPDWORD lpNumberOfCharsWritten
+ );
+
+BOOL
+Or2WinWriteConsoleOutputCharacterW(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ LPWSTR lpCharacter,
+ DWORD nLength,
+ COORD dwWriteCoord,
+ LPDWORD lpNumberOfCharsWritten
+ );
+
+BOOL
+Or2WinWriteConsoleOutputAttribute(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ LPWORD lpAttribute,
+ DWORD nLength,
+ COORD dwWriteCoord,
+ LPDWORD lpNumberOfAttrsWritten
+ );
+
+BOOL
+Or2WinFillConsoleOutputCharacterA(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ CHAR cCharacter,
+ DWORD nLength,
+ COORD dwWriteCoord,
+ LPDWORD lpNumberOfCharsWritten
+ );
+
+BOOL
+Or2WinFillConsoleOutputAttribute(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ WORD wAttribute,
+ DWORD nLength,
+ COORD dwWriteCoord,
+ LPDWORD lpNumberOfAttrsWritten
+ );
+
+BOOL
+Or2WinGetConsoleMode(
+ PSZ FuncName,
+ HANDLE hConsoleHandle,
+ LPDWORD lpMode
+ );
+
+BOOL
+Or2WinGetNumberOfConsoleInputEvents(
+ PSZ FuncName,
+ HANDLE hConsoleInput,
+ LPDWORD lpNumberOfEvents
+ );
+
+BOOL
+Or2WinGetConsoleScreenBufferInfo(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo
+ );
+
+COORD
+Or2WinGetLargestConsoleWindowSize(
+ PSZ FuncName,
+ HANDLE hConsoleOutput
+ );
+
+BOOL
+Or2WinGetConsoleCursorInfo(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
+ );
+
+BOOL
+Or2WinGetNumberOfConsoleMouseButtons(
+ PSZ FuncName,
+ LPDWORD lpNumberOfMouseButtons
+ );
+
+BOOL
+Or2WinSetConsoleMode(
+ PSZ FuncName,
+ HANDLE hConsoleHandle,
+ DWORD dwMode
+ );
+
+BOOL
+Or2WinSetConsoleActiveScreenBuffer(
+ PSZ FuncName,
+ HANDLE hConsoleOutput
+ );
+
+BOOL
+Or2WinSetConsoleScreenBufferSize(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ COORD dwSize
+ );
+
+BOOL
+Or2WinSetConsoleCursorPosition(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ COORD dwCursorPosition
+ );
+
+BOOL
+Or2WinSetConsoleCursorInfo(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
+ );
+
+BOOL
+Or2WinScrollConsoleScreenBufferA(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ PSMALL_RECT lpScrollRectangle,
+ PSMALL_RECT lpClipRectangle,
+ COORD dwDestinationOrigin,
+ PCHAR_INFO lpFill
+ );
+
+BOOL
+Or2WinScrollConsoleScreenBufferW(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ PSMALL_RECT lpScrollRectangle,
+ PSMALL_RECT lpClipRectangle,
+ COORD dwDestinationOrigin,
+ PCHAR_INFO lpFill
+ );
+
+BOOL
+Or2WinSetConsoleWindowInfo(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ BOOL bAbsolute,
+ PSMALL_RECT lpConsoleWindow
+ );
+
+BOOL
+Or2WinSetConsoleTextAttribute(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ WORD wAttributes
+ );
+
+BOOL
+Or2WinSetConsoleCtrlHandler(
+ PSZ FuncName,
+ PHANDLER_ROUTINE HandlerRoutine,
+ BOOL Add
+ );
+
+DWORD
+Or2WinGetConsoleTitleW(
+ PSZ FuncName,
+ LPWSTR lpConsoleTitle,
+ DWORD nSize
+ );
+
+BOOL
+Or2WinSetConsoleTitleA(
+ PSZ FuncName,
+ LPSTR lpConsoleTitle
+ );
+
+BOOL
+Or2WinSetConsoleTitleW(
+ PSZ FuncName,
+ LPWSTR lpConsoleTitle
+ );
+
+BOOL
+Or2WinWriteConsoleA(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ CONST VOID *lpBuffer,
+ DWORD nNumberOfCharsToWrite,
+ LPDWORD lpNumberOfCharsWritten,
+ LPVOID lpReserved
+ );
+
+HANDLE
+Or2WinCreateConsoleScreenBuffer(
+ PSZ FuncName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwFlags,
+ PVOID lpScreenBufferData
+ );
+
+UINT
+Or2WinGetConsoleCP(
+ PSZ FuncName
+ );
+
+BOOL
+Or2WinSetConsoleCP(
+ PSZ FuncName,
+ UINT wCodePageID
+ );
+
+UINT
+Or2WinGetConsoleOutputCP(
+ PSZ FuncName
+ );
+
+BOOL
+Or2WinSetConsoleOutputCP(
+ PSZ FuncName,
+ UINT wCodePageID
+ );
+
+BOOL
+Or2WinBeep(
+ PSZ FuncName,
+ DWORD dwFreq,
+ DWORD dwDuration
+ );
+
+BOOL
+Or2WinCloseHandle(
+ PSZ FuncName,
+ HANDLE hObject
+ );
+
+HANDLE
+Or2WinCreateEventW(
+ PSZ FuncName,
+ LPSECURITY_ATTRIBUTES lpEventAttributes,
+ BOOL bManualReset,
+ BOOL bInitialState,
+ LPWSTR lpName
+ );
+
+HANDLE
+Or2WinCreateFileA(
+ PSZ FuncName,
+ LPCSTR lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile
+ );
+
+HANDLE
+Or2WinCreateFileW(
+ PSZ FuncName,
+ LPCWSTR lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile
+ );
+
+BOOL
+Or2WinCreateProcessA(
+ PSZ FuncName,
+ LPCSTR lpApplicationName,
+ LPCSTR lpCommandLine,
+ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ BOOL bInheritHandles,
+ DWORD dwCreationFlags,
+ LPVOID lpEnvironment,
+ LPSTR lpCurrentDirectory,
+ LPSTARTUPINFOA lpStartupInfo,
+ LPPROCESS_INFORMATION lpProcessInformation
+ );
+
+HANDLE
+Or2WinCreateThread(
+ PSZ FuncName,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ DWORD dwStackSize,
+ LPTHREAD_START_ROUTINE lpStartAddress,
+ LPVOID lpParameter,
+ DWORD dwCreationFlags,
+ LPDWORD lpThreadId
+ );
+
+BOOL
+Or2WinDuplicateHandle(
+ PSZ FuncName,
+ HANDLE hSourceProcessHandle,
+ HANDLE hSourceHandle,
+ HANDLE hTargetProcessHandle,
+ LPHANDLE lpTargetHandle,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ DWORD dwOptions
+ );
+
+VOID
+Or2WinEnterCriticalSection(
+ PSZ FuncName,
+ LPCRITICAL_SECTION lpCriticalSection
+ );
+
+LPSTR
+Or2WinGetCommandLineA(
+ PSZ FuncName
+ );
+
+COORD
+Or2WinGetConsoleFontSize(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ DWORD nFont
+ );
+
+DWORD
+Or2WinGetFileType(
+ PSZ FuncName,
+ HANDLE hFile
+ );
+
+DWORD
+Or2WinGetFullPathNameA(
+ PSZ FuncName,
+ LPCSTR lpFileName,
+ DWORD nBufferLength,
+ LPSTR lpBuffer,
+ LPSTR *lpFilePart
+ );
+
+HANDLE
+Or2WinGetModuleHandleA(
+ PSZ FuncName,
+ LPCSTR lpModuleName
+ );
+
+HANDLE
+Or2WinGetStdHandle(
+ PSZ FuncName,
+ DWORD nStdHandle
+ );
+
+UINT
+Or2WinGetSystemDirectoryA(
+ PSZ FuncName,
+ LPSTR lpBuffer,
+ UINT uSize
+ );
+
+VOID
+Or2WinInitializeCriticalSection(
+ PSZ FuncName,
+ LPCRITICAL_SECTION lpCriticalSection
+ );
+
+VOID
+Or2WinLeaveCriticalSection(
+ PSZ FuncName,
+ LPCRITICAL_SECTION lpCriticalSection
+ );
+
+int
+Or2WinLoadStringA(
+ PSZ FuncName,
+ HINSTANCE hInstance,
+ UINT uID,
+ LPSTR lpBuffer,
+ int nBufferMax
+ );
+
+int
+Or2WinMessageBoxA(
+ PSZ FuncName,
+ HWND hWnd ,
+ LPCSTR lpText,
+ LPCSTR lpCaption ,
+ UINT uType
+ );
+
+HANDLE
+Or2WinOpenProcess(
+ PSZ FuncName,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ DWORD dwProcessId
+ );
+
+DWORD
+Or2WinResumeThread(
+ PSZ FuncName,
+ HANDLE hThread
+ );
+
+UINT
+Or2WinSetErrorMode(
+ PSZ FuncName,
+ UINT uMode
+ );
+
+BOOL
+Or2WinSetEvent(
+ PSZ FuncName,
+ HANDLE hEvent
+ );
+
+BOOL
+Or2WinSetStdHandle(
+ PSZ FuncName,
+ DWORD nStdHandle,
+ HANDLE hHandle
+ );
+
+LCID
+Or2WinGetThreadLocale(
+ PSZ FuncName
+ );
+
+BOOL
+Or2WinSetThreadLocale(
+ PSZ FuncName,
+ LCID Locale
+ );
+
+BOOL
+Or2WinSetThreadPriority(
+ PSZ FuncName,
+ HANDLE hThread,
+ int nPriority
+ );
+
+BOOL
+Or2WinSystemParametersInfoA(
+ PSZ FuncName,
+ UINT uiAction,
+ UINT uiParam,
+ PVOID pvParam,
+ UINT fWinIni
+ );
+
+BOOL
+Or2WinTerminateThread(
+ PSZ FuncName,
+ HANDLE hThread,
+ DWORD dwExitCode
+ );
+
+BOOL
+Or2WinVerifyConsoleIoHandle(
+ PSZ FuncName,
+ HANDLE hIoHandle
+ );
+
+DWORD
+Or2WinWaitForSingleObject(
+ PSZ FuncName,
+ HANDLE hHandle,
+ DWORD dwMilliseconds
+ );
+
+BOOL
+Or2WinWriteFile(
+ PSZ FuncName,
+ HANDLE hFile,
+ CONST VOID *lpBuffer,
+ DWORD nNumberOfBytesToWrite,
+ LPDWORD lpNumberOfBytesWritten,
+ LPOVERLAPPED lpOverlapped
+ );
+
+int
+Or2Win_read(
+ PSZ FuncName,
+ int hFile,
+ void *Buffer,
+ unsigned int Length
+ );
+
+BOOL
+Or2WinReadFile(
+ PSZ FuncName,
+ HANDLE hFile,
+ LPVOID lpBuffer,
+ DWORD nNumberOfBytesToRead,
+ LPDWORD lpNumberOfBytesRead,
+ LPOVERLAPPED lpOverlapped
+ );
+
+BOOL
+Or2WinIsValidCodePage(
+ PSZ FuncName,
+ UINT CodePage
+ );
+
+UINT
+Or2WinGetACP(
+ PSZ FuncName
+ );
+
+UINT
+Or2WinGetOEMCP(
+ PSZ FuncName
+ );
+
+BOOL
+Or2WinGetCPInfo(
+ PSZ FuncName,
+ UINT CodePage,
+ LPCPINFO lpCPInfo
+ );
+
+BOOL
+Or2WinIsDBCSLeadByte(
+ PSZ FuncName,
+ BYTE TestChar
+ );
+
+int
+Or2WinMultiByteToWideChar(
+ PSZ FuncName,
+ UINT CodePage,
+ DWORD dwFlags,
+ LPCSTR lpMultiByteStr,
+ int cchMultiByte,
+ LPWSTR lpWideCharStr,
+ int cchWideChar
+ );
+
+int
+Or2WinWideCharToMultiByte(
+ PSZ FuncName,
+ UINT CodePage,
+ DWORD dwFlags,
+ LPCWSTR lpWideCharStr,
+ int cchWideChar,
+ LPSTR lpMultiByteStr,
+ int cchMultiByte,
+ LPSTR lpDefaultChar,
+ LPBOOL lpUsedDefaultChar
+ );
+
+int
+Or2WinCompareStringW(
+ PSZ FuncName,
+ LCID Locale,
+ DWORD dwCmpFlags,
+ LPCWSTR lpString1,
+ int cchCount1,
+ LPCWSTR lpString2,
+ int cchCount2
+ );
+
+int
+Or2WinLCMapStringW(
+ PSZ FuncName,
+ LCID Locale,
+ DWORD dwMapFlags,
+ LPCWSTR lpSrcStr,
+ int cchSrc,
+ LPWSTR lpDestStr,
+ int cchDest
+ );
+
+int
+Or2WinGetLocaleInfoW(
+ PSZ FuncName,
+ LCID Locale,
+ LCTYPE LCType,
+ LPWSTR lpLCData,
+ int cchData
+ );
+
+LANGID
+Or2WinGetSystemDefaultLangID(
+ PSZ FuncName
+ );
+
+LANGID
+Or2WinGetUserDefaultLangID(
+ PSZ FuncName
+ );
+
+LCID
+Or2WinGetSystemDefaultLCID(
+ PSZ FuncName
+ );
+
+LCID
+Or2WinGetUserDefaultLCID(
+ PSZ FuncName
+ );
+
+BOOL
+Or2WinGetStringTypeW(
+ PSZ FuncName,
+ DWORD dwInfoType,
+ LPCWSTR lpSrcStr,
+ int cchSrc,
+ LPWORD lpCharType
+ );
+
+int
+Or2WinFoldStringW(
+ PSZ FuncName,
+ DWORD dwMapFlags,
+ LPCWSTR lpSrcStr,
+ int cchSrc,
+ LPWSTR lpDestStr,
+ int cchDest
+ );
+
+HANDLE
+Or2WinHeapCreate(
+ PSZ FuncName,
+ DWORD flOptions,
+ DWORD dwInitialSize,
+ DWORD dwMaximumSize
+ );
+
+LPSTR
+Or2WinHeapAlloc(
+ PSZ FuncName,
+ HANDLE hHeap,
+ DWORD dwFlags,
+ DWORD dwBytes
+ );
+
+BOOL
+Or2WinHeapFree(
+ PSZ FuncName,
+ HANDLE hHeap,
+ DWORD dwFlags,
+ LPSTR lpMem
+ );
+
+#else
+#define Or2WinPeekConsoleInputA PeekConsoleInputA
+#define Or2WinReadConsoleInputA ReadConsoleInputA
+#define Or2WinWriteConsoleInputA WriteConsoleInputA
+#define Or2WinReadConsoleOutputCharacterA ReadConsoleOutputCharacterA
+#define Or2WinReadConsoleOutputCharacterW ReadConsoleOutputCharacterW
+#define Or2WinReadConsoleOutputAttribute ReadConsoleOutputAttribute
+#define Or2WinWriteConsoleOutputCharacterA WriteConsoleOutputCharacterA
+#define Or2WinWriteConsoleOutputCharacterW WriteConsoleOutputCharacterW
+#define Or2WinWriteConsoleOutputAttribute WriteConsoleOutputAttribute
+#define Or2WinFillConsoleOutputCharacterA FillConsoleOutputCharacterA
+#define Or2WinFillConsoleOutputAttribute FillConsoleOutputAttribute
+#define Or2WinGetConsoleMode GetConsoleMode
+#define Or2WinGetNumberOfConsoleInputEvents GetNumberOfConsoleInputEvents
+#define Or2WinGetConsoleScreenBufferInfo GetConsoleScreenBufferInfo
+#define Or2WinGetLargestConsoleWindowSize GetLargestConsoleWindowSize
+#define Or2WinGetConsoleCursorInfo GetConsoleCursorInfo
+#define Or2WinGetNumberOfConsoleMouseButtons GetNumberOfConsoleMouseButtons
+#define Or2WinSetConsoleMode SetConsoleMode
+#define Or2WinSetConsoleActiveScreenBuffer SetConsoleActiveScreenBuffer
+#define Or2WinSetConsoleScreenBufferSize SetConsoleScreenBufferSize
+#define Or2WinSetConsoleCursorPosition SetConsoleCursorPosition
+#define Or2WinSetConsoleCursorInfo SetConsoleCursorInfo
+#define Or2WinScrollConsoleScreenBufferA ScrollConsoleScreenBufferA
+#define Or2WinScrollConsoleScreenBufferW ScrollConsoleScreenBufferW
+#define Or2WinSetConsoleWindowInfo SetConsoleWindowInfo
+#define Or2WinSetConsoleTextAttribute SetConsoleTextAttribute
+#define Or2WinSetConsoleCtrlHandler SetConsoleCtrlHandler
+#define Or2WinGetConsoleTitleW GetConsoleTitleW
+#define Or2WinSetConsoleTitleA SetConsoleTitleA
+#define Or2WinSetConsoleTitleW SetConsoleTitleW
+#define Or2WinWriteConsoleA WriteConsoleA
+#define Or2WinCreateConsoleScreenBuffer CreateConsoleScreenBuffer
+#define Or2WinGetConsoleCP GetConsoleCP
+#define Or2WinSetConsoleCP SetConsoleCP
+#define Or2WinGetConsoleOutputCP GetConsoleOutputCP
+#define Or2WinSetConsoleOutputCP SetConsoleOutputCP
+#define Or2WinBeep Beep
+#define Or2WinCloseHandle CloseHandle
+#define Or2WinCreateEventW CreateEventW
+#define Or2WinCreateFileA CreateFileA
+#define Or2WinCreateFileW CreateFileW
+#define Or2WinCreateProcessA CreateProcessA
+#define Or2WinCreateThread CreateThread
+#define Or2WinDuplicateHandle DuplicateHandle
+#define Or2WinEnterCriticalSection EnterCriticalSection
+#define Or2WinGetCommandLineA GetCommandLineA
+#define Or2WinGetConsoleFontSize GetConsoleFontSize
+#define Or2WinGetCurrentConsoleFont GetCurrentConsoleFont
+#define Or2WinGetFileType GetFileType
+#define Or2WinGetFullPathNameA GetFullPathNameA
+#define Or2WinGetModuleHandleA GetModuleHandleA
+#define Or2WinGetStdHandle GetStdHandle
+#define Or2WinGetSystemDirectoryA GetSystemDirectoryA
+#define Or2WinInitializeCriticalSection InitializeCriticalSection
+#define Or2WinLeaveCriticalSection LeaveCriticalSection
+#define Or2WinLoadStringA LoadStringA
+#define Or2WinMessageBoxA MessageBoxA
+#define Or2WinOpenProcess OpenProcess
+#define Or2WinResumeThread ResumeThread
+#define Or2WinSetErrorMode SetErrorMode
+#define Or2WinSetEvent SetEvent
+#define Or2WinSetStdHandle SetStdHandle
+#define Or2WinGetThreadLocale GetThreadLocale
+#define Or2WinSetThreadLocale SetThreadLocale
+#define Or2WinSetThreadPriority SetThreadPriority
+#define Or2WinSystemParametersInfoA SystemParametersInfoA
+#define Or2WinTerminateThread TerminateThread
+#define Or2WinVerifyConsoleIoHandle VerifyConsoleIoHandle
+#define Or2WinWaitForSingleObject WaitForSingleObject
+#define Or2WinWriteFile WriteFile
+#define Or2Win_read _read
+#define Or2WinReadFile ReadFile
+#define Or2WinIsValidCodePage IsValidCodePage
+#define Or2WinGetACP GetACP
+#define Or2WinGetOEMCP GetOEMCP
+#define Or2WinGetCPInfo GetCPInfo
+#define Or2WinIsDBCSLeadByte IsDBCSLeadByte
+#define Or2WinMultiByteToWideChar MultiByteToWideChar
+#define Or2WinWideCharToMultiByte WideCharToMultiByte
+#define Or2WinCompareStringW CompareStringW
+#define Or2WinLCMapStringW LCMapStringW
+#define Or2WinGetLocaleInfoW GetLocaleInfoW
+#define Or2WinGetSystemDefaultLangID GetSystemDefaultLangID
+#define Or2WinGetUserDefaultLangID GetUserDefaultLangID
+#define Or2WinGetSystemDefaultLCID GetSystemDefaultLCID
+#define Or2WinGetUserDefaultLCID GetUserDefaultLCID
+#define Or2WinGetStringTypeW GetStringTypeW
+#define Or2WinFoldStringW FoldStringW
+#define Or2WinHeapCreate HeapCreate
+#define Or2WinHeapAlloc HeapAlloc
+#define Or2WinHeapFree HeapFree
+#endif
diff --git a/private/os2/inc/os2res.h b/private/os2/inc/os2res.h
new file mode 100644
index 000000000..234a52541
--- /dev/null
+++ b/private/os2/inc/os2res.h
@@ -0,0 +1,80 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2res.h
+
+Abstract:
+
+ Prototypes for resources
+
+Author:
+
+ Michael Jarus (mjarus) 19-Jul-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+
+#define ERROR_BUFFER_SIZE 256
+
+/*
+ * OS2.EXE
+ */
+
+#define IDS_OS2_WHATFLAG 100
+#define IDS_OS2_USAGE 101
+#define IDS_OS2_NOCMD 102
+#define IDS_OS2_NOCONNECT 103
+#define IDS_OS2_STARTPROCESS 104
+#define IDS_OS2_CREATECONOUT 105
+#define IDS_OS2_CREATETHREAD 106
+
+#define IDS_OS2_INITFAIL 200
+#define IDS_OS2_SEGNUMBER 201
+#define IDS_OS2_EXEINVALID 202
+#define IDS_OS2_STACKSEG 203
+#define IDS_OS2_NOFILE 204
+#define IDS_OS2_NOPROC 205
+#define IDS_OS2_NOORDINAL 206
+#define IDS_OS2_CODESEG 207
+#define IDS_OS2_MODULETYPE 208
+#define IDS_OS2_EXEFORMAT 209
+#define IDS_OS2_NOMEMORY 210
+#define IDS_OS2_RELOCCHAIN 211
+#define IDS_OS2_OS2CODE 212
+#define IDS_OS2_BADFORMAT 213
+
+#define IDS_OS2_CONFIGSYS_ACCESS_CAP 300
+#define IDS_OS2_CONFIGSYS_ACCESS_TXT 301
+#define IDS_OS2_WRITE_PROTECT_CAP 302
+#define IDS_OS2_WRITE_PROTECT_TXT 303
+#define IDS_OS2_DEVIVE_NOT_READY_CAP 304
+#define IDS_OS2_DEVIVE_NOT_READY_TXT 305
+#define IDS_OS2_INTERNAL_ERROR 306
+#define IDS_OS2_BOUND_APP_LOAD_CAP 307
+#define IDS_OS2_BOUND_APP_LOAD_TXT 308
+#ifdef PMNT
+#define IDS_OS2_PMSHELL_NOT_UP_CAP 309
+#define IDS_OS2_PMSHELL_NOT_UP_TXT 310
+#define IDS_OS2_2ND_PMSHELL_CAP 311
+#define IDS_OS2_2ND_PMSHELL_TXT 312
+#define IDS_OS2_PMSHELL_FULLSCREEN_CAP 313
+#define IDS_OS2_PMSHELL_FULLSCREEN_TXT 314
+#endif
+
+/*
+ * OS2SRV.EXE
+ */
+
+#define IDS_OS2SRV_ACCESS_API_GP_CAP 100
+#define IDS_OS2SRV_ACCESS_GP_TXT 101
+#define IDS_OS2SRV_API_GP_TXT 102
+
diff --git a/private/os2/inc/os2srv.h b/private/os2/inc/os2srv.h
new file mode 100644
index 000000000..8b80171b2
--- /dev/null
+++ b/private/os2/inc/os2srv.h
@@ -0,0 +1,1650 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2srv.h
+
+Abstract:
+
+ Main include file for OS/2 Subsystem Server
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Revision History:
+
+ Yaron Shamor 4-Apr-91 Add profile for ComputeValidDrives.
+--*/
+
+//
+// Include OS/2 SubSystem Runtime Definitions. Includes NT Definitions,
+// OS/2 V2.0 Definitions and Debug definitions.
+//
+
+#include "os2ssrtl.h"
+
+#if DBG
+ULONG Os2Debug;
+#endif
+
+// Flag to let OS2SRV know whether or not to ignore LOGOFF (when started as a service)
+extern BOOLEAN fService;
+
+//
+// Include NT Session Manager and Debug SubSystem Interfaces
+
+#include <ntsm.h>
+#include <ntdbg.h>
+typedef BOOLEAN (*PSB_API_ROUTINE)( IN PSBAPIMSG SbApiMsg );
+
+
+#include "os2file.h"
+#include "os2ssmsg.h"
+
+//
+// OS/2 Subsystem Semaphore structures.
+//
+
+typedef enum _OS2_SEMAPHORE_TYPE {
+ Os2EventSem = 1,
+ Os2MutexSem,
+ Os2MuxWaitSem
+} OS2_SEMAPHORE_TYPE;
+
+typedef struct _OS2_MUXWAIT_RECORD {
+ ULONG SemHandleIndex;
+ ULONG UserKey;
+ struct _OS2_SEMAPHORE *Semaphore;
+} OS2_MUXWAIT_RECORD, *POS2_MUXWAIT_RECORD;
+
+typedef struct _OS2_MUXWAIT_SEMAPHORE {
+ USHORT CountMuxWaitRecords;
+ USHORT Type : 2;
+ USHORT WaitAll : 1;
+ USHORT Reserved : 13;
+ OS2_MUXWAIT_RECORD MuxWaitRecords[ DCMW_MAX_SEMRECORDS ];
+} OS2_MUXWAIT_SEMAPHORE, *POS2_MUXWAIT_SEMAPHORE;
+
+typedef struct _OS2_SEMAPHORE {
+ USHORT PointerCount : 14;
+ USHORT Type : 2;
+ USHORT OpenCount;
+ STRING Name;
+ union {
+ PVOID Value;
+ HANDLE EventHandle;
+ HANDLE MutantHandle;
+ POS2_MUXWAIT_SEMAPHORE MuxWait;
+ } u;
+} OS2_SEMAPHORE, *POS2_SEMAPHORE;
+
+
+typedef struct _OS2_SESSION {
+ LIST_ENTRY SessionLink;
+ ULONG SessionId;
+ ULONG ReferenceCount;
+ ULONG TerminationQueueHandle;
+ struct _OS2_QUEUE *TerminationQueue;
+ struct _OS2_SESSION *RelatedSession;
+ struct _OS2_SESSION *BindSession;
+ HANDLE ConsolePort;
+ ULONG SessionUniqueId;
+ ULONG ProcessId;
+ BOOLEAN Selectable;
+ USHORT FgBg; // TRUE for background
+ USHORT InheritOpt;
+ BOOLEAN ChildSession;
+ BOOLEAN WinSession;
+ PVOID Thread;
+ PVOID Process;
+ HANDLE hWaitThread;
+ HANDLE hProcess;
+ ULONG dwProcessId;
+ ULONG dwParentProcessId;
+ HANDLE SesGrpHandle;
+ PVOID SesGrpAddress;
+ BOOLEAN InTermination;
+ HANDLE Win32ForegroundWindow;
+ struct _OS2_REGISTER_HANDLER_REC *RegisterCtrlHandler;
+} OS2_SESSION, *POS2_SESSION;
+
+typedef struct _OS2_NT_SESSION {
+ LIST_ENTRY SessionLink;
+ ULONG SessionId;
+ ULONG ReferenceCount;
+ STRING RootDirectory;
+} OS2_NT_SESSION, *POS2_NT_SESSION;
+
+typedef struct _OS2_THREAD {
+ LIST_ENTRY Link;
+ struct _OS2_PROCESS *Process;
+ struct _OS2_WAIT_BLOCK *WaitBlock;
+ POS2_SEMAPHORE WaitingForSemaphore;
+ CLIENT_ID ClientId;
+ TID ThreadId;
+ HANDLE ThreadHandle;
+ POS2_TIB ClientOs2Tib;
+ ULONG Flags;
+ KPRIORITY Priority;
+ USHORT PendingSignals;
+ USHORT CurrentSignals;
+ USHORT MustComplete;
+ USHORT DebugState; // A flag for DosPtrace().
+ BOOLEAN Dying;
+ CHAR Os2Level;
+ UCHAR Os2Class;
+ ULONG InitialStack;
+} OS2_THREAD, *POS2_THREAD;
+
+//
+// Flag definitions for OS2_THREAD.Flags
+//
+
+#define OS2_THREAD_THREAD1 0x00000001
+#define OS2_THREAD_ATTACHED 0x00000002
+
+#ifdef PMNT
+#define PMNTFIRSTHIDDENTHREAD 40 // There is a check for Maximum thread in
+ // pmwin\wintodos.inc MAXTHRDID = 52
+ // Maximum #threads per process handled by
+ // AAB.ASM. Assumes thread IDs range from
+ // 0 to MAXTHRDID-1
+#define PMNTMAXHIDDENTHREADS 10 // We allocated 10 PMNT hidden threads with
+ // Tid 40-50. See process.c os2allocatetid
+#endif
+
+#define OS2_EXIT_IN_PROGRESS 0x00000001
+#define OS2_EXIT_WAIT_FOR_SYNC 0x00000002
+
+typedef struct _OS2_PROCESS {
+ LIST_ENTRY ListLink;
+ struct _OS2_PROCESS *Parent;
+ LIST_ENTRY ChildrenList;
+ LIST_ENTRY SiblingLink;
+ LIST_ENTRY ThreadList;
+ LIST_ENTRY SharedMemoryList;
+ POS2_NT_SESSION NtSession;
+ POS2_SESSION Session;
+ PVOID ExitListDispatcher;
+ PVOID InfiniteSleep;
+ PVOID SignalDeliverer;
+ PVOID FreezeThread;
+ PVOID UnfreezeThread;
+ PVOID VectorHandler;
+ PVOID CritSectionAddr;
+ PVOID TidBitMapHeader;
+ PEB_OS2_DATA InitialPebOs2Data;
+ RESULTCODES ResultCodes;
+ ULONG ExpectedVersion;
+ HANDLE ClientPort;
+ PCH ClientViewBase;
+ PCH ClientViewBounds;
+ CLIENT_ID ClientId;
+ PID ProcessId;
+ PID CommandSubTreeId;
+ HANDLE ProcessHandle;
+ PPIB ClientPib;
+// ULONG LastThreadId; removed after TidBitMapHeader was added
+#ifdef PMNT
+ ULONG LastHiddenThreadId;
+#endif
+ ULONG Flags;
+ USHORT ExceptionFocus;
+ PFILE_HANDLE HandleTable; // temporary copy of the file handle table during exec
+ ULONG HandleTableLength; // length of handle table
+ ULONG ErrorAction;
+ BOOLEAN CtrlHandlerFlag;
+ ULONG ExitStatus; // 2 bits:
+ // Exit in progress
+ // Wait for sync during exit processing
+ UCHAR ApplName[OS2_PROCESS_MAX_APPL_NAME];
+ ULONG ApplNameLength;
+ TID DebugThreadId;
+ PVOID ProcessMTE; // Pointer to process MTE structure
+ BOOLEAN FirstPtrace; // A flag for first DosPtrace(0xA)
+ PVOID FirstMTE; // Pointer to the mte that has the INT 3 we inserted for DosPtrace()
+ PVOID LinkMte; // Link list of mte's to transfer to a debugger process
+ BOOLEAN ConfigSysUsageFlag; // TRUE if process used config.sys during its life
+} OS2_PROCESS, *POS2_PROCESS;
+
+typedef struct _OS2_REGISTER_HANDLER_REC {
+ ULONG Signal;
+ ULONG fAction;
+ POS2_PROCESS Process;
+ struct _OS2_REGISTER_HANDLER_REC *Link;
+} OS2_REGISTER_HANDLER_REC, *POS2_REGISTER_HANDLER_REC;
+
+//
+// Flags field bit definitions
+//
+
+// When process terminates if no process is waiting for result, put the
+// process in the zombie list so that DosWaitChild can find it and return
+// the result.
+//
+#define OS2_PROCESS_SAVERESULT 0x00000001
+
+// The process was invoked synchronously and the client is waiting for a
+// response to their DosExecPgm request when this process terminates.
+//
+#define OS2_PROCESS_SYNCHRONOUS 0x00000002
+
+// The process was invoked detached from the console and does not get any
+// handles to the console device (keyboard, mouse and/or screen).
+//
+#define OS2_PROCESS_BACKGROUND 0x00000004
+
+// The process was invoked in z suspended state. It may be resumed with the
+// DosSystemService API call.
+//
+#define OS2_PROCESS_FROZEN 0x00000008
+
+// The process may be modified via the Debug Subsystem. FIX, FIX - what does
+// this really mean.
+//
+#define OS2_PROCESS_TRACE 0x00000010
+
+// Any child process created by this process inherits the OS2_PROCESS_TRACE????
+// flags.
+//
+#define OS2_PROCESS_TRACETREE 0x00000020
+
+// The process is terminating after DosPtrace() with a TERMINATE command.
+//
+#define OS2_PROCESS_TERMINATE 0x00000040
+
+// Process is doing ExitList processing
+//
+#define OS2_PROCESS_EXIT 0x00010000
+
+// // Obsolete code below: OS/2 ss was keeping processes around as zombie so
+// // that DosCWait doesn't fail when father calls it after child termination.
+// // However, it turns out that OS/2 doesn't do this.
+//
+// // Process is linked into the zombie list.
+// //
+// #define OS2_PROCESS_ZOMBIE 0x00020000
+
+// Process cannot run in the PM screen
+//
+#define OS2_PROCESS_NOTWINDOWCOMPAT 0x00040000
+
+// Process can run in a PM screen
+//
+#define OS2_PROCESS_WINDOWCOMPAT 0x00080000
+
+// Process is using PM APIs
+//
+#define OS2_PROCESS_WINDOWAPI 0x00100000
+
+// Process is PMSHELL - special handling for GPs
+//
+#define OS2_PROCESS_IS_PMSHELL 0x00200000
+
+#if PMNT
+// Process is Forced PM process (PM but not marked as WINDOWAPI)
+//
+#define OS2_PROCESS_FORCEDPM 0x00400000
+
+// Process calls WinCreateMsgQueue()
+//
+#define OS2_PROCESS_PMMSGQUE 0x00800000
+
+#define Os2srvProcessIsPMProcess(Process) (Process->Flags & (OS2_PROCESS_WINDOWAPI \
+ | OS2_PROCESS_PMMSGQUE | OS2_PROCESS_FORCEDPM))
+#endif
+//
+// ProcessId limits
+//
+
+#define PID_MIN 0x00000001 // Lowest process id
+#define PID_MAX 0x0000FFFF // Highest process id
+
+//
+// ProcessStatus field flag bits. All but the first are private to OS/2
+//
+
+#define PS_XITLST PS_EXITLIST // Doing ExitList Processing
+#define PS_XITTH1 0x00000002 // Exiting thread 1
+#define PS_XITALL 0x00000004 // The whole process is exiting
+#define PS_SYNCPARENT 0x00000010 // Parent cares about termination
+#define PS_WAITPARENT 0x00000020 // Parent did an exec-and-wait
+#define PS_DYING 0x00000040 // Process is dying
+#define PS_EMBRYO 0x00000080 // Process in embryonic state
+
+#define AcquireLocalObjectLock(AssociatedHandleTable) RtlEnterCriticalSection( &(AssociatedHandleTable)->Lock );
+#define ReleaseLocalObjectLock(AssociatedHandleTable) RtlLeaveCriticalSection( &(AssociatedHandleTable)->Lock );
+//
+// All exported API calls define the same interface to the OS/2 Server Request
+// loop. The return value indicates to the request loop whether or not to
+// generate a reply to the client.
+//
+
+typedef BOOLEAN (*POS2_API_ROUTINE)( IN POS2_THREAD t, IN POS2_API_MSG m );
+
+BOOLEAN Os2InternalNullApiCall( IN POS2_THREAD t, IN POS2_API_MSG m );
+
+
+//
+// Global data accessed by OS/2 Subsystem Server
+//
+
+#if DBG
+ULONG Os2DebugFlag;
+#endif // DBG
+
+PVOID Os2Heap;
+
+ULONG Os2BootDrive;
+ULONG Os2DefaultDrive;
+ULONG Os2ValidDrives;
+PSZ *environ;
+PSZ SystemRootValuePtr;
+
+HANDLE Os2RootDirectory;
+HANDLE Os2DrivesDirectory;
+HANDLE Os2DevicesDirectory;
+
+STRING Os2DebugPortName;
+UNICODE_STRING Os2DebugPortName_U;
+HANDLE Os2DebugPort;
+
+STRING Os2ExceptionPortName;
+UNICODE_STRING Os2ExceptionPortName_U;
+HANDLE Os2ExceptionPort;
+
+UNICODE_STRING Os2SbApiPortName_U;
+HANDLE Os2SbApiPort;
+HANDLE Os2SmApiPort;
+
+/*
+ * Port and threads for Console Session globals.
+ */
+HANDLE Os2SessionPort;
+
+HANDLE Os2SessionRequestThreadHandle;
+
+
+#define OS2_SS_SBAPI_PORT_NAME L"\\OS2SS\\SbApiPort"
+
+#define OS2_SS_API_LISTEN_THREAD 0
+#define OS2_SS_SBAPI_REQUEST_THREAD 1
+#define OS2_SS_FIRST_API_REQUEST_THREAD 2
+
+#define OS2_SS_MAX_THREADS 64
+
+HANDLE Os2ServerThreadHandles[ OS2_SS_MAX_THREADS ];
+HANDLE Os2DebugThreadHandle;
+CLIENT_ID Os2ServerThreadClientIds[ OS2_SS_MAX_THREADS ];
+CLIENT_ID Os2DebugThreadClientId;
+
+POR2_HANDLE_TABLE Os2SharedSemaphoreTable;
+
+CLIENT_ID Os2DebugUserClientId;
+
+
+//
+// Routines defined in srvinit.c
+//
+
+NTSTATUS
+Os2Initialize( VOID );
+
+BOOLEAN
+Os2SrvHandleCtrlEvent(
+ IN int CtrlType
+ );
+
+ULONG
+NtGetIntegerFromUnicodeString(
+ IN WCHAR *WString
+ );
+
+//
+// Routines defined in srvnls.c
+//
+// Note: srvnls.c doesn't include this file. It includes <windows.h> instead
+// of <nt.h>.
+// All callers to Win32 APIs (like SetConsoleCtrlHandler) should be put there.
+//
+
+ULONG Os2ssCountryCode;
+ULONG Os2ssCodePage[2];
+UCHAR Os2ssKeyboardLayout[2];
+#if PMNT
+UCHAR Os2ssKeyboardName[4]; // Allow space for keyboard sub-code (103,
+ // 189, 150G etc.)
+#endif
+ULONG Os2ssKeysOnFlag;
+ULONG Os2SrvExitNow;
+
+VOID
+Os2SrvExitProcess(IN ULONG uExitCode);
+
+APIRET
+Os2InitializeNLS( VOID );
+
+VOID
+SetEventHandlersAndErrorMode(
+ IN BOOLEAN fSet
+ );
+
+//
+// Routines defined in srvobjmn.c
+//
+
+typedef enum _OS2_LOCAL_OBJECT_TYPE {
+ LocalObjectAnyType,
+ LocalObjectQueue,
+ MaxLocalObject
+} OS2_LOCAL_OBJECT_TYPE;
+
+typedef struct _OS2_LOCAL_OBJECT_DIRENT {
+ STRING ObjectName;
+ OS2_LOCAL_OBJECT_TYPE ObjectType;
+ ULONG ObjectHandle;
+} OS2_LOCAL_OBJECT_DIRENT, *POS2_LOCAL_OBJECT_DIRENT;
+
+NTSTATUS
+Os2InitializeLocalObjectManager( VOID );
+
+RTL_GENERIC_TABLE Os2LocalObjectNames;
+
+RTL_GENERIC_COMPARE_RESULTS
+Os2LocalObjectCompare(
+ IN struct _RTL_GENERIC_TABLE *Table,
+ IN PVOID FirstStruct,
+ IN PVOID SecondStruct
+ );
+
+PVOID
+Os2LocalObjectDirentAllocate(
+ IN struct _RTL_GENERIC_TABLE *Table,
+ IN CLONG ByteSize
+ );
+
+VOID
+Os2LocalObjectDirentDeallocate(
+ IN struct _RTL_GENERIC_TABLE *Table,
+ IN PVOID Buffer
+ );
+
+POS2_LOCAL_OBJECT_DIRENT
+Os2LookupLocalObjectByName(
+ IN PSTRING ObjectName,
+ IN OS2_LOCAL_OBJECT_TYPE ObjectType
+ );
+
+POS2_LOCAL_OBJECT_DIRENT
+Os2InsertLocalObjectName(
+ IN PSTRING ObjectName,
+ IN OS2_LOCAL_OBJECT_TYPE ObjectType,
+ IN ULONG ObjectHandle
+ );
+
+VOID
+Os2DeleteLocalObject(
+ IN POS2_LOCAL_OBJECT_DIRENT Dirent
+ );
+
+//
+// Routines defined in srvname.c
+//
+
+NTSTATUS
+Os2InitializeNameSpace( VOID );
+
+NTSTATUS
+Os2InitializeDriveLetters( VOID );
+
+NTSTATUS
+Os2InitLocalObjectDirectory( VOID );
+
+ULONG
+Os2ComputeValidDrives( VOID );
+
+NTSTATUS
+Os2GetClientId(void);
+
+NTSTATUS
+Os2DebugProcess(
+ IN PCLIENT_ID DebugUserInterface,
+ IN POS2_THREAD Thread,
+ IN HANDLE ReplyEvent
+ );
+
+NTSTATUS
+Os2DebugThread(
+ IN HANDLE hThread,
+ IN HANDLE ReplyEvent
+ );
+
+//
+// Routines defined in srvcnfg.c
+//
+
+NTSTATUS
+Os2InitializeRegistry(
+ VOID
+ );
+
+BOOLEAN
+Os2ConfigSysCreator(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ );
+
+VOID
+Os2UpdateRegistryFromConfigSys(
+ VOID
+ );
+
+//
+// Routines defined in srvnet.c
+//
+
+BOOLEAN
+Os2Netbios2Request(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ );
+
+//
+// Routines defined in sbinit.c
+//
+
+NTSTATUS
+Os2SbApiPortInitialize( VOID );
+
+
+VOID
+Os2SbApiPortTerminate(
+ NTSTATUS Status
+ );
+
+//
+// Routines defined in sbreqst.c
+//
+
+NTSTATUS
+Os2SbApiRequestThread(
+ IN PVOID Parameter
+ );
+
+//
+// Routines defined in sbapi.c
+//
+
+BOOLEAN
+Os2SbCreateSession(
+ IN PSBAPIMSG Msg
+ );
+
+BOOLEAN
+Os2SbTerminateSession(
+ IN PSBAPIMSG Msg
+ );
+
+BOOLEAN
+Os2SbForeignSessionComplete(
+ IN PSBAPIMSG Msg
+ );
+
+//
+// Routines defined in apiinit.c
+//
+
+NTSTATUS
+Os2DebugPortInitialize(void);
+
+
+//
+// Routines defined in apireqst.c
+//
+
+NTSTATUS
+Os2ApiRequestThread(
+ IN PVOID Parameter
+ );
+
+
+BOOLEAN
+Os2CaptureArguments(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ );
+
+VOID
+Os2ReleaseCapturedArguments(
+ IN POS2_API_MSG m
+ );
+
+NTSTATUS
+Os2DebugRequestThread(
+ IN PVOID Parameter
+ );
+
+NTSTATUS
+Os2ExceptionRequestThread(
+ IN PVOID Parameter
+ );
+
+//
+// Routines defined in coninit.c
+//
+
+NTSTATUS
+Os2InitializeConsolePort( VOID );
+
+
+//
+// Routines defined in conthrds.c
+//
+
+VOID
+Os2SessionHandleConnectionRequest(
+ struct _OS2SESREQUESTMSG *Message
+ );
+
+VOID
+HandleOs2ConRequest(IN PVOID pApiReceiveMsg,
+ OUT PVOID *PReplyMsg
+ );
+
+//
+// Routines defined in concreat.c
+//
+
+NTSTATUS
+Os2CreateConSession(
+ IN OUT PVOID RequestMsg
+ );
+
+//
+// Routines defined in consignl.c
+//
+
+NTSTATUS
+Os2CtrlSignalHandler(
+ IN OUT PVOID RequestMsg,
+ IN POS2_PROCESS RecievingProcess
+ );
+
+NTSTATUS
+Os2TerminateConSession(
+ IN POS2_SESSION Session,
+ IN POS2_TERMINATEPROCESS_MSG a
+ );
+
+//
+// Routines and data defined in process.c
+//
+
+//
+// The Os2StructureLock critical section protects against races with various
+// threads accessing internal structures.
+//
+
+RTL_CRITICAL_SECTION Os2StructureLock;
+#define Os2AcquireStructureLock() RtlEnterCriticalSection( &Os2StructureLock )
+#define Os2ReleaseStructureLock() RtlLeaveCriticalSection( &Os2StructureLock )
+
+//
+// The following is a dummy process that acts as the root of the OS/2 Process
+// Structure. It has a ClientId of -1.-1 so it does not conflict with actual
+// OS/2 Processes. All processes created via the session manager are children
+// of this process, as are all orphaned processes. The ListLink field of this
+// process is the head of a list of all OS/2 Processes.
+//
+POS2_PROCESS Os2RootProcess;
+
+// // Obsolete code below: OS/2 ss was keeping processes around as zombie so
+// // that DosCWait doesn't fail when father calls it after child termination.
+// // However, it turns out that OS/2 doesn't do this.
+//
+// The Os2ZombieList is a list of all zombie processes that contain result
+// codes that have not been retrieved yet. Processes in the Zombie List
+// are NOT in the process tree rooted at Os2RootProcess. The ListLink
+// field of each zombie process is used for the zombie list pointers, since
+// they are not used to link them into the process structure.
+//
+//
+// LIST_ENTRY Os2ZombieList;
+
+//
+// OS/2 Process Id values are assigned from this variable. They are handed
+// out sequentially.
+//
+
+PID Os2LastProcessId;
+PID Os2NextHigherProcessId;
+
+#define MINIMUM_PROCESS_ID (PID)0x00000001
+#define MAXIMUM_PROCESS_ID (PID)0x0000FFFF
+
+
+NTSTATUS
+Os2InitializeProcessStructure( VOID );
+
+POS2_PROCESS
+Os2AllocateProcess( VOID );
+
+VOID
+Os2DeallocateProcess(
+ IN POS2_PROCESS Process
+ );
+
+VOID
+Os2InsertProcess(
+ IN POS2_PROCESS ParentProcess,
+ IN POS2_PROCESS Process
+ );
+
+VOID
+Os2RemoveProcess(
+ IN POS2_PROCESS Process
+ );
+
+VOID
+Os2SuspendProcess(
+ IN POS2_PROCESS Process
+ );
+
+NTSTATUS
+Os2SetProcessContext(
+ IN POS2_PROCESS Process,
+ IN POS2_THREAD Thread,
+ IN BOOLEAN StartedBySm,
+ IN ULONG HandleTableLength,
+ IN ULONG CurrentDrive,
+ IN ULONG CodePage
+ );
+
+POS2_THREAD
+Os2AllocateThread(
+#ifdef PMNT
+ IN ULONG Flags,
+#endif
+ IN POS2_PROCESS Process
+ );
+
+VOID
+Os2DeallocateThread(
+ IN POS2_THREAD Thread
+ );
+
+VOID
+Os2InsertThread(
+ IN POS2_PROCESS Process,
+ IN POS2_THREAD Thread
+ );
+
+VOID
+Os2RemoveThread(
+ IN POS2_PROCESS Process,
+ IN POS2_THREAD Thread
+ );
+
+VOID
+Os2SetThreadPriority(
+ IN POS2_THREAD Thread,
+ IN ULONG NewClass,
+ IN ULONG Delta
+ );
+
+VOID
+Os2SetProcessPriority(
+ IN POS2_PROCESS Process,
+ IN ULONG NewClass,
+ IN ULONG Delta
+ );
+
+VOID
+Os2SetProcessTreePriority(
+ IN POS2_PROCESS RootProcess,
+ IN ULONG NewClass,
+ IN ULONG Delta
+ );
+
+POS2_PROCESS
+Os2LocateProcessByProcessId(
+ IN POS2_API_MSG m OPTIONAL,
+ IN POS2_PROCESS CurrentProcess,
+ IN PID ProcessId,
+ IN BOOLEAN MustBeChild
+ );
+
+POS2_PROCESS
+Os2LocateProcessByClientId(
+ IN PCLIENT_ID ClientId
+ );
+
+POS2_THREAD
+Os2LocateThreadByThreadId(
+ IN POS2_API_MSG m OPTIONAL,
+ IN POS2_THREAD CurrentThread,
+ IN TID ThreadId
+ );
+
+POS2_THREAD
+Os2LocateThreadByClientId(
+ IN POS2_PROCESS Process,
+ IN PCLIENT_ID ClientId
+ );
+
+//
+// Routines and data defined in wait.c
+//
+
+typedef enum _OS2_WAIT_REASON {
+ WaitProcess,
+ WaitThread,
+ WaitQueue,
+ WaitInterrupt,
+ WaitSession,
+ WaitWinProcess,
+ MaxWaitReason
+} OS2_WAIT_REASON;
+
+typedef
+BOOLEAN
+(*OS2_WAIT_ROUTINE)(
+ IN OS2_WAIT_REASON WaitReason,
+ IN POS2_THREAD WaitingThread,
+ IN POS2_API_MSG WaitReplyMessage,
+ IN PVOID WaitParameter,
+ IN PVOID SatisfyParameter1,
+ IN PVOID SatisfyParameter2
+ );
+
+typedef struct _OS2_WAIT_BLOCK {
+ ULONG Length;
+ LIST_ENTRY Link;
+ LIST_ENTRY UserLink;
+ PVOID WaitParameter;
+ POS2_THREAD WaitingThread;
+ OS2_WAIT_ROUTINE WaitRoutine;
+ OS2_API_MSG WaitReplyMessage;
+} OS2_WAIT_BLOCK, *POS2_WAIT_BLOCK;
+
+LIST_ENTRY Os2WaitLists[ MaxWaitReason ];
+
+BOOLEAN
+Os2InitializeWait(
+ IN OS2_WAIT_ROUTINE WaitRoutine,
+ IN POS2_THREAD WaitingThread,
+ IN OUT POS2_API_MSG WaitReplyMessage,
+ IN PVOID WaitParameter,
+ OUT POS2_WAIT_BLOCK *WaitBlockPtr
+ );
+
+BOOLEAN
+Os2CreateWait(
+ IN OS2_WAIT_REASON WaitReason,
+ IN OS2_WAIT_ROUTINE WaitRoutine,
+ IN POS2_THREAD WaitingThread,
+ IN OUT POS2_API_MSG WaitReplyMessage,
+ IN PVOID WaitParameter,
+ IN PLIST_ENTRY UserLinkListHead OPTIONAL
+ );
+
+
+BOOLEAN
+Os2NotifyWaitBlock(
+ IN POS2_WAIT_BLOCK WaitBlock,
+ IN OS2_WAIT_REASON WaitReason,
+ IN PVOID SatisfyParameter1,
+ IN PVOID SatisfyParameter2
+ );
+
+BOOLEAN
+Os2NotifyWait(
+ IN OS2_WAIT_REASON WaitReason,
+ IN PVOID SatisfyParameter1,
+ IN PVOID SatisfyParameter2
+ );
+
+VOID
+Os2DestroyWait(
+ IN POS2_WAIT_BLOCK WaitBlock
+ );
+
+//
+// srvque.c
+//
+
+NTSTATUS
+Os2InitializeQueues( VOID );
+
+typedef struct _OS2_QUEUE_ENTRY {
+ LIST_ENTRY Links;
+ REQUESTDATA RequestData;
+ ULONG EntryId;
+ PVOID ElementAddress;
+ ULONG ElementLength;
+ ULONG Priority;
+} OS2_QUEUE_ENTRY, *POS2_QUEUE_ENTRY;
+
+typedef struct _OS2_QUEUE_SEM_BLOCK {
+ LIST_ENTRY Links;
+ HANDLE NtEvent;
+} OS2_QUEUE_SEM_BLOCK, *POS2_QUEUE_SEM_BLOCK;
+
+typedef struct _OS2_QUEUE {
+ PID CreatorPid;
+ POS2_LOCAL_OBJECT_DIRENT Dirent;
+ LONG OpenCount;
+ ULONG QueueType;
+ ULONG EntryIdCounter;
+ LIST_ENTRY Entries;
+ LIST_ENTRY Waiters;
+ LIST_ENTRY SemBlocks;
+} OS2_QUEUE, *POS2_QUEUE;
+
+POR2_QHANDLE_TABLE Os2QueueTable;
+
+VOID
+Os2PurgeQueueEntries(
+ IN POS2_QUEUE Queue
+ );
+
+POS2_QUEUE_ENTRY
+Os2LocateQueueEntry(
+ IN POS2_QUEUE Queue,
+ IN ULONG ReadPosition
+ );
+
+BOOLEAN
+Os2WaitQueueEntries(
+ IN OS2_WAIT_REASON WaitReason,
+ IN POS2_THREAD WaitingThread,
+ IN POS2_API_MSG WaitReplyMessage,
+ IN PVOID WaitParameter,
+ IN PVOID SatisfyParameter1,
+ IN PVOID SatisfyParameter2
+ );
+
+POS2_QUEUE
+Os2OpenQueueByHandle(
+ IN HQUEUE QueueHandle
+ );
+
+APIRET
+Os2CloseQueueByHandle(
+ IN HQUEUE QueueHandle,
+ IN ULONG CloseCount,
+ IN PID OwnerPid,
+ IN POS2_PROCESS Process
+ );
+
+APIRET
+Os2WriteQueueByHandle(
+ POS2_DOSWRITEQUEUE_MSG a,
+ PID ProcessId
+ );
+
+VOID
+Os2ReadQueueEntry(
+ IN POS2_QUEUE_ENTRY QueueEntry,
+ OUT POS2_DOSREADQUEUE_MSG ReadMsg
+ );
+
+VOID
+Os2PeekQueueEntry(
+ IN POS2_QUEUE Queue,
+ IN POS2_QUEUE_ENTRY QueueEntry,
+ OUT POS2_DOSPEEKQUEUE_MSG PeekMsg
+ );
+
+VOID
+DumpQueueEntry(
+ IN PSZ Str,
+ IN POS2_QUEUE_ENTRY QueueEntry
+ );
+VOID
+Os2QueueWaitCheck(
+ POS2_QUEUE Queue
+ );
+
+VOID
+Os2ProcessSemBlocks(
+ IN POS2_QUEUE Queue
+ );
+
+
+BOOLEAN Os2DosCreateQueue( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosOpenQueue( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosCloseQueue( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosPurgeQueue( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosQueryQueue( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosPeekQueue( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosReadQueue( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosWriteQueue( IN POS2_THREAD t, IN POS2_API_MSG m );
+
+//
+// srvsm.c
+//
+
+LIST_ENTRY Os2SessionList;
+
+#define OS2_MAX_SESSION 30
+
+typedef struct
+{
+ LIST_ENTRY Waiters;
+ POS2_SESSION Session;
+} SessionTableEntry;
+
+SessionTableEntry SessionTable[OS2_MAX_SESSION];
+
+POS2_SESSION
+Os2AllocateSession(
+ POS2_DOSSTARTSESSION_INFO SessionInfo OPTIONAL,
+ ULONG UniqueId,
+ PAPIRET ApiRet
+ );
+
+VOID
+Os2ReferenceSession(
+ POS2_SESSION Session
+ );
+
+POS2_SESSION
+Os2DereferenceSession(
+ POS2_SESSION Session,
+ POS2_TERMINATEPROCESS_MSG msg,
+ BOOLEAN Bailout
+ );
+
+VOID
+Os2DereferenceSessionByUniqueId(
+ ULONG UniqueId,
+ POS2_TERMINATEPROCESS_MSG msg,
+ BOOLEAN Bailout
+ );
+
+POS2_SESSION
+Os2GetSessionByUniqueId(
+ ULONG UniqueId
+ );
+
+VOID
+Os2CreateConSessionFail( IN ULONG SessionUniqueId);
+
+VOID
+Os2CreateConSessionAccept(IN POS2_SESSION Session);
+
+NTSTATUS
+Os2SessionFocusSet(IN OUT PVOID RequestMsg);
+
+BOOLEAN Os2DosStartSession( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosSelectSession( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosSetSession( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosStopSession( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosSmSetTitle( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosGetCtrlPortForSessionID( IN POS2_THREAD t, IN POS2_API_MSG m);
+
+//
+// srvtask.c
+//
+
+VOID
+Os2HandleException(
+ IN POS2_PROCESS Process,
+ IN PDBGKM_APIMSG ReceiveMsg
+ );
+
+VOID
+Os2HandleDebugEvent(
+ IN POS2_PROCESS Process,
+ IN PDBGKM_APIMSG ReceiveMsg
+ );
+
+BOOLEAN Os2DosCreateThread( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosSuspendThread( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosResumeThread( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosExit( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosExitGP(IN POS2_THREAD t, IN POS2_API_MSG m);
+BOOLEAN Os2DosWaitChild( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosWaitThread( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosEnterCritSec( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosExitCritSec( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosExecPgm( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosKillProcess( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosSetPriority( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosGetPriority( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosGetPPID( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosError( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2InternalTerminateProcess( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2InternalTerminateThread( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosPTrace( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosCloseHandle(IN POS2_THREAD t, IN POS2_API_MSG m);
+#if PMNT
+BOOLEAN PMSetPMshellFlag(IN POS2_THREAD t, IN POS2_API_MSG m);
+#endif
+
+BOOLEAN
+Os2WaitDeadThreadSatisfy(
+ IN OS2_WAIT_REASON WaitReason,
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m,
+ IN PVOID WaitParameter,
+ IN PVOID SatisfyParameter1,
+ IN PVOID SatisfyParameter2
+ );
+
+BOOLEAN
+Os2WaitChildSatisfy(
+ IN OS2_WAIT_REASON WaitReason,
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m,
+ IN PVOID WaitParameter,
+ IN POS2_PROCESS TerminatingProcess,
+ IN PVOID SatisfyParameter2
+ );
+
+BOOLEAN
+Os2WaitThreadSatisfy(
+ IN OS2_WAIT_REASON WaitReason,
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m,
+ IN PVOID WaitParameter,
+ IN POS2_THREAD TerminatingThread,
+ IN PVOID SatisfyParameter2
+ );
+
+BOOLEAN
+Os2WaitWinExec(
+ IN OS2_WAIT_REASON WaitReason,
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m,
+ IN PVOID WaitParameter,
+ IN PID TerminatingProcess,
+ IN PVOID SatisfyParameter2
+ );
+
+APIRET
+Os2CreateProcess(
+ IN PVOID RequestMsg OPTIONAL,
+ IN POS2_THREAD t,
+ POS2_DOSEXECPGM_MSG a,
+ POS2_SESSION Session OPTIONAL,
+ POS2_THREAD *NewThread
+ );
+
+//
+// srvxcpt.c
+//
+
+BOOLEAN Os2DosSetSignalExceptionFocus( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosEnterMustComplete( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosExitMustComplete( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosSendSignalException( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosAcknowledgeSignalException( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosDispatch16Signal( IN POS2_THREAD t, IN POS2_API_MSG m);
+
+BOOLEAN
+Os2DispatchVector(
+ IN PDBGKM_APIMSG ReceiveMsg,
+ POS2_THREAD Thread,
+ CONTEXT Context
+ );
+
+VOID
+SendSyncPterm(
+ IN POS2_THREAD Thread
+ );
+
+VOID
+SendAsyncPterm(
+ IN POS2_THREAD Thread
+ );
+
+APIRET
+Os2IssueSignal(
+ IN POS2_PROCESS Process,
+ IN int Signal
+ );
+
+VOID
+Os2IssueSignalTree(
+ IN POS2_PROCESS RootProcess,
+ IN int Signal
+ );
+
+BOOLEAN Os2DosRegisterCtrlHandler( IN POS2_THREAD t, IN POS2_API_MSG m );
+
+VOID Os2DeRegisterCtrlHandler(IN POS2_PROCESS Process);
+
+//
+// srvvm.c
+//
+
+typedef struct _OS2_SHARED_MEMORY_OBJECT {
+ LIST_ENTRY Link;
+ ULONG RefCount;
+ PVOID BaseAddress;
+ ULONG Index;
+ ULONG RegionSize;
+ HANDLE SectionHandle;
+ ULONG AllocationFlags;
+ STRING SectionName;
+ BOOLEAN IsHuge;
+ ULONG MaxSegments;
+ ULONG NumOfSegments;
+ ULONG SizeOfPartialSeg;
+ BOOLEAN Sizeable;
+} OS2_SHARED_MEMORY_OBJECT, *POS2_SHARED_MEMORY_OBJECT;
+
+LIST_ENTRY Os2SharedMemoryList;
+
+//
+// A linked list of all the shared memory objects that a process currently
+// has open.
+//
+
+typedef struct _OS2_SHARED_MEMORY_PROCESS_REF {
+ LIST_ENTRY Link;
+ ULONG RefCount;
+ ULONG AllocationFlags;
+ POS2_SHARED_MEMORY_OBJECT SharedMemoryObject;
+} OS2_SHARED_MEMORY_PROCESS_REF, *POS2_SHARED_MEMORY_PROCESS_REF;
+
+
+NTSTATUS
+Os2InitializeMemory( VOID );
+
+
+POS2_SHARED_MEMORY_OBJECT
+Os2CreateSharedMemoryObject(
+ IN POS2_API_MSG m,
+ IN PVOID BaseAddress,
+ IN ULONG Index,
+ IN ULONG RegionSize,
+ IN HANDLE SectionHandle OPTIONAL,
+ IN ULONG AllocationFlags,
+ IN PSTRING SectionName
+ );
+
+
+VOID
+Os2FreeSharedMemoryObject(
+ POS2_SHARED_MEMORY_OBJECT MemoryObject
+ );
+
+
+POS2_SHARED_MEMORY_PROCESS_REF
+Os2CreateProcessRefToSharedMemory(
+ IN POS2_PROCESS Process,
+ IN POS2_SHARED_MEMORY_OBJECT MemoryObject
+ );
+
+
+BOOLEAN
+Os2FreeProcessRefToSharedMemory(
+ IN POS2_PROCESS Process,
+ IN POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef
+ );
+
+
+VOID
+Os2FreeAllSharedMemoryForProcess(
+ IN POS2_PROCESS Process
+ );
+
+
+POS2_SHARED_MEMORY_OBJECT
+Os2FindSharedMemoryObject(
+ IN PVOID BaseAddress,
+ IN POS2_PROCESS Process
+ );
+
+
+APIRET
+Os2MapViewOfSharedMemoryObject(
+ POS2_SHARED_MEMORY_OBJECT MemoryObject,
+ POS2_PROCESS Process,
+ BOOLEAN ProcessIsSelf,
+ ULONG RequiredAccess,
+ ULONG PageProtection
+ );
+
+BOOLEAN Os2DosFreeMem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosSetMem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosGiveSharedMem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosGetSharedMem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosGetNamedSharedMem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosAllocSharedMem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2InternalQueryVirtualMemory( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2InternalMarkSharedMemAsHuge( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosReallocSharedMem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2InternalReallocSharedHuge( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosGetSeg( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosGiveSeg( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosGetShrSeg( IN POS2_THREAD t, IN POS2_API_MSG m );
+
+//
+// srvfile.c
+//
+
+BOOLEAN Os2InternalCopyHandleTable( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2InternalDeviceShare( IN POS2_THREAD t, IN POS2_API_MSG m );
+
+APIRET
+InitializeFileSystemForExec(
+ IN POS2_FILE_SYSTEM_PARAMETERS FileSystemParameters,
+ IN HANDLE ParentProcessHandle, // NT process handle
+ IN HANDLE ChildProcessHandle, // NT process handle
+ POS2_PROCESS ParentProcess, // OS/2 parent process
+ POS2_PROCESS ChildProcess, // OS/2 child process
+ IN POS2_DOSEXECPGM_MSG pExecPgmMsg
+ );
+
+VOID
+InitializeFileSystemForSesMgr(
+ IN POS2_PROCESS Process // OS/2 process
+ );
+
+APIRET
+InitializeFileSystemForChildSesMgr(
+ IN POS2_FILE_SYSTEM_PARAMETERS FileSystemParameters,
+ IN HANDLE ParentProcessHandle, // NT process handle
+ IN HANDLE ChildProcessHandle, // NT process handle
+ POS2_PROCESS ParentProcess, // OS/2 parent process
+ POS2_PROCESS ChildProcess, // OS/2 child process
+ IN POS2_DOSEXECPGM_MSG pExecPgmMsg
+ );
+
+//
+// srvwin.c
+//
+
+ULONG
+Os2AccessGPPopup(
+ IN ULONG CS,
+ IN ULONG IP,
+ IN ULONG AX,
+ IN ULONG BX,
+ IN ULONG CX,
+ IN ULONG DX,
+ IN ULONG SI,
+ IN ULONG DI,
+ IN ULONG BP,
+ IN ULONG SP,
+ IN ULONG SS,
+ IN ULONG DS,
+ IN ULONG ES,
+ IN PUCHAR AppName
+ );
+
+ULONG
+Os2ApiGPPopup(
+ IN PUCHAR AppName,
+ IN PUCHAR Text
+ );
+
+extern HANDLE Os2hOs2SrvInstance; // for resouces
+
+//
+// srvsem.c
+//
+
+NTSTATUS
+Os2InitializeSemaphores( VOID );
+
+BOOLEAN
+Os2SemaphoreCreateProcedure(
+ IN POS2_SEMAPHORE Semaphore,
+ IN POS2_SEMAPHORE CreateSemaphore
+ );
+
+BOOLEAN
+Os2SemaphoreOpenProcedure(
+ IN POS2_SEMAPHORE Semaphore,
+ IN POS2_SEMAPHORE OpenSemaphore
+ );
+
+APIRET
+Os2ProcessSemaphoreName(
+ IN PSTRING ObjectName,
+ IN POS2_SEMAPHORE Semaphore OPTIONAL,
+ OUT PULONG ExistingHandleIndex OPTIONAL
+ );
+
+PVOID
+Os2DestroySemaphore(
+ IN POS2_SEMAPHORE Semaphore,
+ IN ULONG HandleIndex
+ );
+
+POS2_SEMAPHORE
+Os2ReferenceSemaphore(
+ IN POS2_SEMAPHORE Semaphore
+ );
+
+VOID
+Os2DereferenceSemaphore(
+ IN POS2_SEMAPHORE Semaphore
+ );
+
+VOID
+Os2ThreadWaitingOnSemaphore(
+ IN POS2_THREAD t,
+ IN POS2_SEMAPHORE Semaphore,
+ IN BOOLEAN AboutToWait
+ );
+
+
+#if DBG
+
+VOID
+Os2SemaphoreDumpProcedure(
+ IN POS2_SEMAPHORE Semaphore,
+ IN ULONG HandleIndex,
+ IN PVOID DumpParameter
+ );
+
+VOID
+Os2DumpSemaphoreTable(
+ IN PCHAR Title
+ );
+
+#endif // DBG
+
+
+//
+// srvevent.c
+//
+
+BOOLEAN Os2DosCreateEventSem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosOpenEventSem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosCloseEventSem( IN POS2_THREAD t, IN POS2_API_MSG m );
+
+
+//
+// srvmutex.c
+//
+
+BOOLEAN Os2DosCreateMutexSem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosOpenMutexSem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosCloseMutexSem( IN POS2_THREAD t, IN POS2_API_MSG m );
+
+
+//
+// srvmuxwt.c
+//
+
+APIRET
+Os2AddMuxWait(
+ IN POS2_MUXWAIT_SEMAPHORE MuxWait,
+ IN PSEMRECORD MuxWaitEntry
+ );
+
+APIRET
+Os2DeleteMuxWait(
+ IN POS2_MUXWAIT_SEMAPHORE MuxWait,
+ IN ULONG MuxWaitEntryIndex,
+ IN ULONG SemHandleIndex OPTIONAL
+ );
+
+BOOLEAN Os2DosCreateMuxWaitSem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosOpenMuxWaitSem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosCloseMuxWaitSem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosWaitMuxWaitSem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosAddMuxWaitSem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosDeleteMuxWaitSem( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2InternalAlertMuxWaiter( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN Os2DosQueryMuxWaitSem( IN POS2_THREAD t, IN POS2_API_MSG m );
+
+//
+// loader routines
+//
+
+BOOLEAN LDRNewExe( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN LDRUnloadExe( IN POS2_PROCESS Process );
+BOOLEAN LDRDosLoadModule( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN LDRDosFreeModule( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN LDRDosGetModName( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN LDRDosGetModHandle( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN LDRDosGetProcAddr( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN LDRDosQAppType( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN LDRDosGetResource( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN LDRDosGetResource2( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN LDRDosFreeResource( IN POS2_THREAD t, IN POS2_API_MSG m );
+#if PMNT
+BOOLEAN LDRIdentifyCodeSelector( IN POS2_THREAD t, IN POS2_API_MSG m );
+BOOLEAN LDRDumpSegments( IN POS2_THREAD t, IN POS2_API_MSG m );
+#endif
+
+BOOLEAN LDRModifySizeOfSharedSegment( IN POS2_THREAD t, IN ULONG Sel, IN ULONG NewLimit );
+
+//
+// LinkMTE is used for saving all the mte's of a process
+// in a linked list.
+//
+
+typedef struct _LinkMTE {
+ USHORT MTE;
+ struct _LinkMTE *NextMTE;
+ USHORT NeedToTransfer; // used as counter for mtes
+ // and for flag for DosPtrace
+} LinkMTE;
+
+
+//
+// xtlexec.c
+//
+
+NTSTATUS
+XtlCreateUserProcess(
+ IN PSTRING NtImagePathName,
+ IN PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
+ IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL,
+ IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL,
+ IN HANDLE ParentProcess OPTIONAL,
+ IN BOOLEAN InheritHandles,
+ IN HANDLE DebugPort OPTIONAL,
+ IN HANDLE ExceptionPort OPTIONAL,
+ OUT PRTL_USER_PROCESS_INFORMATION ProcessInformation
+ );
+
+NTSTATUS
+Os2WinCreateProcess (POS2_DOSEXECPGM_MSG a,
+ POS2_PROCESS ParentProcess,
+ POS2_SESSION Session,
+ PHANDLE pHandle
+ );
+
+NTSTATUS
+Os2WinRunProcess (IN HANDLE tHandle,
+ IN POS2_SESSION Session
+ );
+
+//
+// srvdebug.c
+//
+
+NTSTATUS
+Os2UiLookup(PCLIENT_ID AppClientId,
+ PCLIENT_ID DebugUiClientId);
+
+NTSTATUS
+Os2CheckStopDebugThread(
+ IN PVOID Parameter
+ );
+
+//
+// exception handling structures and equates
+//
+
+#define MAXIMUM_MUST_COMPLETE 0xFFFF // maximum must complete nesting
+
+#define SIG_MAXSF 0xFFFF // maximum signal focus nesting
+
+
+// Signal numbers
+// these are also defined in os2dll.h, so if the values change be sure
+// to change them there
+
+#define SIGNAL_TO_FLAG(Signal) (1 << (Signal - 1))
+
+#define SIGAPTERM 8 // Asynchronous PTERM
+#define SIGPTERM 9 // Synchronous PTERM
+
+// Signal flags
+
+#define SIGINTRF (1 << (XCPT_SIG_INTR - 1)) // Ctrl-C
+#define SIGTERMF (1 << (XCPT_SIG_KILLPROC - 1)) // program termination
+#define SIGBREAKF (1 << (XCPT_SIG_BREAK - 1)) // Ctrl-Break
+#define SIGAPTERMF (1 << (SIGAPTERM - 1)) // Asyncronous PTERM
+
+// Error flags
+// Similar flags are defined in os2dll.h as OD2_ENABLE_ ...
+
+#define OS2_ENABLE_HARD_ERROR_POPUP 0x1
+#define OS2_ENABLE_ACCESS_VIO_POPUP 0x2
+
+/* Fix for a C8 compilation warning */
+#undef TRUE
+#define TRUE (BOOLEAN)1
+
+#undef FALSE
+#define FALSE (BOOLEAN)0
+
+/* Global Information Segment */
+
+typedef struct _GINFOSEG { /* gis */
+ ULONG time;
+ ULONG msecs;
+ UCHAR hour;
+ UCHAR minutes;
+ UCHAR seconds;
+ UCHAR hundredths;
+ USHORT timezone;
+ USHORT cusecTimerInterval;
+ UCHAR day;
+ UCHAR month;
+ USHORT year;
+ UCHAR weekday;
+ UCHAR uchMajorVersion;
+ UCHAR uchMinorVersion;
+ UCHAR chRevisionLetter;
+ UCHAR sgCurrent;
+ UCHAR sgMax;
+ UCHAR cHugeShift;
+ UCHAR fProtectModeOnly;
+ USHORT pidForeground;
+ UCHAR fDynamicSched;
+ UCHAR csecMaxWait;
+ USHORT cmsecMinSlice;
+ USHORT cmsecMaxSlice;
+ USHORT bootdrive;
+ UCHAR amecRAS[32];
+ UCHAR csgWindowableVioMax;
+ UCHAR csgPMMax;
+} GINFOSEG;
+
+
diff --git a/private/os2/inc/os2ssmsg.h b/private/os2/inc/os2ssmsg.h
new file mode 100644
index 000000000..a4ff4bb69
--- /dev/null
+++ b/private/os2/inc/os2ssmsg.h
@@ -0,0 +1,886 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2ssmsg.h
+
+Abstract:
+
+ Include file that defines the message formats needed to communicate with
+ the OS/2 Subsystem Server process
+
+Author:
+
+ Steve Wood (stevewo) 18-Sep-1989
+
+Revision History:
+
+--*/
+
+#define OS2_SS_API_PORT_NAME L"\\OS2SS\\ApiPort"
+#define OS2_SS_DEBUG_PORT_NAME L"\\OS2SS\\DebugPort"
+#define OS2_SS_EXCEPTION_PORT_NAME L"\\OS2SS\\ExceptionPost"
+#define OS2_SS_SYNCHRONIZATION_SEM L"\\OS2SS\\SyncSemaphore"
+#if PMNT
+#define OS2_SS_PMSHELL_EVENT L"\\OS2SS\\PMShellEvent"
+#endif // PMNT
+
+//
+// Important!!! -- MAX_LANA must be kept in sync with <nb30.h> !
+//
+#define MAX_LANA_OS2SSMSG 254
+
+typedef struct _ExecInfo {
+ ULONG startaddr; /* instruction pointer */
+ ULONG stackaddr; /* stack pointer */
+ USHORT ds; /* starting ds only for 16-bit */
+ USHORT dgroupsize; /* size of dgroup */
+ USHORT heapsize; /* size of heap */
+ USHORT loadtype; /* Load type 16-bit or 32-bit */
+ USHORT envsel; /* Selector to environment */
+ USHORT comoff; /* Offset to command line in env */
+ USHORT stacksize; /* size of stack */
+ USHORT hmod; /* module handle */
+} EXECINFO;
+
+typedef struct _PTRACEBUF {
+ USHORT pid;
+ USHORT tid;
+ USHORT cmd;
+ USHORT value;
+ USHORT offv;
+ USHORT segv;
+ USHORT mte;
+ USHORT rAX;
+ USHORT rBX;
+ USHORT rCX;
+ USHORT rDX;
+ USHORT rSI;
+ USHORT rDI;
+ USHORT rBP;
+ USHORT rDS;
+ USHORT rES;
+ USHORT rIP;
+ USHORT rCS;
+ USHORT rF;
+ USHORT rSP;
+ USHORT rSS;
+} PTRACEBUF, *pPTRACEBUF;
+
+
+typedef enum _OS2_API_NUMBER {
+ Oi2NullApiCall,
+ Oi2AlertMuxWaiter,
+ Oi2CopyHandleTable,
+ Oi2DeviceShare,
+ Oi2TerminateThread,
+ Oi2TerminateProcess,
+ Oi2QueryVirtualMemory,
+ Oi2MarkSharedMemAsHuge,
+ Oi2ReallocSharedHuge,
+ Os2CreateThread,
+ Os2Exit,
+ Os2WaitChild,
+ Os2WaitThread,
+ Os2ExecPgm,
+ Os2KillProcess,
+ Os2SetPriority,
+ Os2FreeMem,
+ Os2GiveSharedMem,
+ Os2GetSharedMem,
+ Os2GetNamedSharedMem,
+ Os2AllocSharedMem,
+ Os2CreateEventSem,
+ Os2OpenEventSem,
+ Os2CloseEventSem,
+ Os2CreateMutexSem,
+ Os2OpenMutexSem,
+ Os2CloseMutexSem,
+ Os2CreateMuxWaitSem,
+ Os2OpenMuxWaitSem,
+ Os2CloseMuxWaitSem,
+ Os2WaitMuxWaitSem,
+ Os2AddMuxWaitSem,
+ Os2DeleteMuxWaitSem,
+ Os2QueryMuxWaitSem,
+ Os2StartSession,
+ Os2SelectSession,
+ Os2SetSession,
+ Os2StopSession,
+ Os2SmSetTitle,
+ Os2CreateQueue,
+ Os2OpenQueue,
+ Os2CloseQueue,
+ Os2PurgeQueue,
+ Os2QueryQueue,
+ Os2PeekQueue,
+ Os2ReadQueue,
+ Os2WriteQueue,
+ Os2EnterMustComplete,
+ Os2ExitMustComplete,
+ Os2SetSignalExceptionFocus,
+ Os2SendSignalException,
+ Os2AcknowledgeSignalException,
+ Os2Dispatch16Signal,
+ Os2GetPriority,
+ Os2GetPPID,
+ Os2Error,
+ Os2RegisterCtrlHandler,
+ Os2GetCtrlPortForSessionID,
+ Os2ExitGP,
+ Os2CloseHandle,
+ Os2CreateConfigSys,
+ Os2Netbios2Reqst,
+ Os2ReallocSharedMem,
+ Os2GetSeg,
+ Os2GiveSeg,
+ Os2GetShrSeg,
+ Os2Ptrace,
+ Ol2LdrNewExe,
+ Ol2LdrLoadModule,
+ Ol2LdrFreeModule,
+ Ol2LdrGetModuleName,
+ Ol2LdrGetModuleHandle,
+ Ol2LdrGetProcAddr,
+ Ol2LdrQAppType,
+ Ol2LdrGetResource,
+ Ol2LdrFreeResource,
+#if PMNT
+ Op2IdentifyCodeSelector,
+ Op2SetPMshellFlag,
+#endif
+#if PMNT
+ Ol2LdrDumpSegments,
+#endif
+ Os2MaxApiNumber
+} OS2_API_NUMBER;
+
+
+//
+// Internal server API messages
+//
+
+typedef struct _OS2_NULLAPICALL_MSG {
+ LONG CountArguments;
+ ULONG FastArguments[ 12 ];
+ PCHAR *Arguments;
+} OS2_NULLAPICALL_MSG, *POS2_NULLAPICALL_MSG;
+
+typedef struct _OS2_ALERTMUXWAITER_MSG {
+ TID ThreadId;
+} OS2_ALERTMUXWAITER_MSG, *POS2_ALERTMUXWAITER_MSG;
+
+typedef struct _OS2_COPYHANDLETABLE_MSG {
+ PFILE_HANDLE ChildHandleTable; // address of child handle table
+ ULONG ChildTableLength; // number of entries in child table
+} OS2_COPYHANDLETABLE_MSG, *POS2_COPYHANDLETABLE_MSG;
+
+typedef struct _OS2_SHARE_MSG {
+ SHARE_OPERATION Operation;
+ IO_VECTOR_TYPE VectorType;
+ ULONG DesiredAccess;
+ ULONG ShareAccess;
+} OS2_SHARE_MSG, *POS2_SHARE_MSG;
+
+typedef struct _OS2_TERMINATETHREAD_MSG {
+ ULONG ExitResult;
+} OS2_TERMINATETHREAD_MSG, *POS2_TERMINATETHREAD_MSG;
+
+typedef struct _OS2_TERMINATEPROCESS_MSG {
+ ULONG ExitResult;
+ ULONG ExitReason;
+ CHAR ErrorText[50];
+} OS2_TERMINATEPROCESS_MSG, *POS2_TERMINATEPROCESS_MSG;
+
+typedef struct _OS2_QUERYVIRTUALMEMORY_MSG {
+ PVOID BaseAddress;
+ BOOLEAN SharedMemory;
+ ULONG AllocationFlags;
+ BOOLEAN IsHuge;
+ ULONG MaxSegments;
+ ULONG NumOfSegments;
+ ULONG SizeOfPartialSeg;
+ BOOLEAN Sizeable;
+} OS2_QUERYVIRTUALMEMORY_MSG, *POS2_QUERYVIRTUALMEMORY_MSG;
+
+typedef struct _OS2_MARKHAREDMEMASHUGE_MSG {
+ PVOID BaseAddress;
+ ULONG MaxSegments;
+ ULONG NumOfSegments;
+ ULONG SizeOfPartialSeg;
+ BOOLEAN Sizeable;
+} OS2_MARKSHAREDMEMASHUGE_MSG, *POS2_MARKSHAREDMEMASHUGE_MSG;
+
+typedef struct _OS2_REALLOCSHAREDHUGE_MSG {
+ PVOID BaseAddress;
+ ULONG NumOfSegments;
+ ULONG SizeOfPartialSeg;
+} OS2_REALLOCSHAREDHUGE_MSG, *POS2_REALLOCSHAREDHUGE_MSG;
+
+
+//
+// Public server API messages
+//
+
+typedef struct _OS2_DOSCREATETHREAD_MSG {
+ HANDLE ThreadHandle;
+ CLIENT_ID ClientId;
+ ULONG Flags;
+ POS2_TIB ClientOs2Tib;
+ TID ThreadId;
+} OS2_DOSCREATETHREAD_MSG, *POS2_DOSCREATETHREAD_MSG;
+
+
+typedef struct _OS2_DOSEXIT_MSG {
+ ULONG ExitAction;
+ ULONG ExitResult;
+} OS2_DOSEXIT_MSG, *POS2_DOSEXIT_MSG;
+
+
+typedef struct _OS2_DOSWAITCHILD_MSG {
+ ULONG WaitTarget;
+ ULONG WaitOption;
+ PID ProcessId;
+ RESULTCODES ResultCodes;
+ PID ResultProcessId;
+} OS2_DOSWAITCHILD_MSG, *POS2_DOSWAITCHILD_MSG;
+
+
+typedef struct _OS2_DOSWAITTHREAD_MSG {
+ TID ThreadId;
+ ULONG WaitOption;
+} OS2_DOSWAITTHREAD_MSG, *POS2_DOSWAITTHREAD_MSG;
+
+
+typedef struct _OS2_DOSEXECPGM_MSG {
+ ULONG Flags;
+ STRING ErrorText;
+ RESULTCODES ResultCodes;
+ PID ResultProcessId;
+ OS2_FILE_SYSTEM_PARAMETERS FileSystemParameters;
+ ULONG CodePage;
+ ULONG CurrentDrive;
+ ULONG CmdLineFlag;
+ HANDLE hRedirectedFile;
+ USHORT RedirectedFileType;
+ HANDLE hProcess;
+ HANDLE hThread;
+ CLIENT_ID ClientId;
+ UCHAR ApplName[33];
+ ULONG ApplNameLength;
+} OS2_DOSEXECPGM_MSG, *POS2_DOSEXECPGM_MSG;
+
+
+typedef struct _OS2_DOSPTRACE_MSG {
+ PTRACEBUF PtraceBuf;
+} OS2_DOSPTRACE_MSG, *POS2_DOSPTRACE_MSG;
+
+typedef struct _OS2_DOSKILLPROCESS_MSG {
+ ULONG KillTarget;
+ PID ProcessId;
+} OS2_DOSKILLPROCESS_MSG, *POS2_DOSKILLPROCESS_MSG;
+
+
+typedef struct _OS2_DOSSETPRIORITY_MSG {
+ ULONG Scope;
+ ULONG Class;
+ LONG Delta;
+ ULONG TargetId;
+} OS2_DOSSETPRIORITY_MSG, *POS2_DOSSETPRIORITY_MSG;
+
+
+typedef struct _OS2_DOSGETPRIORITY_MSG {
+ ULONG Scope;
+ ULONG TargetId;
+ ULONG Priority;
+} OS2_DOSGETPRIORITY_MSG, *POS2_DOSGETPRIORITY_MSG;
+
+
+typedef struct _OS2_DOSGETPPID_MSG {
+ PID ChildPid;
+ PID ParentPid;
+} OS2_DOSGETPPID_MSG, *POS2_DOSGETPPID_MSG;
+
+
+typedef struct _OS2_DOSERROR_MSG {
+ ULONG ErrorAction;
+} OS2_DOSERROR_MSG, *POS2_DOSERROR_MSG;
+
+
+typedef struct _OS2_DOSFREEMEM_MSG {
+ PVOID BaseAddress;
+ BOOLEAN RemoveLDTEntry;
+} OS2_DOSFREEMEM_MSG, *POS2_DOSFREEMEM_MSG;
+
+
+typedef struct _OS2_DOSGIVESHAREDMEM_MSG {
+ PVOID BaseAddress;
+ PID ProcessId;
+ ULONG Flags;
+ ULONG PageProtection;
+} OS2_DOSGIVESHAREDMEM_MSG, *POS2_DOSGIVESHAREDMEM_MSG;
+
+
+typedef struct _OS2_DOSGETSHAREDMEM_MSG {
+ PVOID BaseAddress;
+ ULONG Flags;
+ ULONG PageProtection;
+} OS2_DOSGETSHAREDMEM_MSG, *POS2_DOSGETSHAREDMEM_MSG;
+
+
+typedef struct _OS2_DOSGETNAMEDSHAREDMEM_MSG {
+ PVOID BaseAddress;
+ ULONG Flags;
+ ULONG PageProtection;
+ STRING ObjectName;
+} OS2_DOSGETNAMEDSHAREDMEM_MSG, *POS2_DOSGETNAMEDSHAREDMEM_MSG;
+
+
+typedef struct _OS2_DOSALLOCSHAREDMEM_MSG {
+ PVOID BaseAddress;
+ ULONG RegionSize;
+ ULONG Flags;
+ ULONG PageProtection;
+ STRING ObjectName;
+ BOOLEAN CreateLDTEntry;
+} OS2_DOSALLOCSHAREDMEM_MSG, *POS2_DOSALLOCSHAREDMEM_MSG;
+
+
+typedef struct _OS2_DOSCREATEEVENTSEM_MSG {
+ ULONG HandleIndex;
+ HANDLE NtEventHandle;
+ STRING ObjectName;
+ ULONG CreateAttributes;
+ BOOLEAN InitialState;
+} OS2_DOSCREATEEVENTSEM_MSG, *POS2_DOSCREATEEVENTSEM_MSG;
+
+
+typedef struct _OS2_DOSOPENEVENTSEM_MSG {
+ ULONG HandleIndex;
+ HANDLE NtEventHandle;
+ STRING ObjectName;
+} OS2_DOSOPENEVENTSEM_MSG, *POS2_DOSOPENEVENTSEM_MSG;
+
+
+typedef struct _OS2_DOSCLOSEEVENTSEM_MSG {
+ ULONG HandleIndex;
+} OS2_DOSCLOSEEVENTSEM_MSG, *POS2_DOSCLOSEEVENTSEM_MSG;
+
+
+typedef struct _OS2_DOSCREATEMUTEXSEM_MSG {
+ ULONG HandleIndex;
+ HANDLE NtMutantHandle;
+ STRING ObjectName;
+ ULONG CreateAttributes;
+ BOOLEAN InitialState;
+} OS2_DOSCREATEMUTEXSEM_MSG, *POS2_DOSCREATEMUTEXSEM_MSG;
+
+
+typedef struct _OS2_DOSOPENMUTEXSEM_MSG {
+ ULONG HandleIndex;
+ HANDLE NtMutantHandle;
+ STRING ObjectName;
+} OS2_DOSOPENMUTEXSEM_MSG, *POS2_DOSOPENMUTEXSEM_MSG;
+
+
+typedef struct _OS2_DOSCLOSEMUTEXSEM_MSG {
+ ULONG HandleIndex;
+} OS2_DOSCLOSEMUTEXSEM_MSG, *POS2_DOSCLOSEMUTEXSEM_MSG;
+
+
+typedef struct _OS2_DOSCREATEMUXWAITSEM_MSG {
+ ULONG HandleIndex;
+ STRING ObjectName;
+ ULONG CreateAttributes;
+ ULONG CountMuxWaitEntries;
+ PSEMRECORD MuxWaitEntries;
+} OS2_DOSCREATEMUXWAITSEM_MSG, *POS2_DOSCREATEMUXWAITSEM_MSG;
+
+
+typedef struct _OS2_DOSOPENMUXWAITSEM_MSG {
+ ULONG HandleIndex;
+ STRING ObjectName;
+} OS2_DOSOPENMUXWAITSEM_MSG, *POS2_DOSOPENMUXWAITSEM_MSG;
+
+
+typedef struct _OS2_DOSCLOSEMUXWAITSEM_MSG {
+ ULONG HandleIndex;
+} OS2_DOSCLOSEMUXWAITSEM_MSG, *POS2_DOSCLOSEMUXWAITSEM_MSG;
+
+
+typedef struct _OS2_DOSWAITMUXWAITSEM_MSG {
+ ULONG HandleIndex;
+ LARGE_INTEGER Timeout;
+ ULONG UserValue;
+} OS2_DOSWAITMUXWAITSEM_MSG, *POS2_DOSWAITMUXWAITSEM_MSG;
+
+
+typedef struct _OS2_DOSADDMUXWAITSEM_MSG {
+ ULONG HandleIndex;
+ SEMRECORD MuxWaitEntry;
+} OS2_DOSADDMUXWAITSEM_MSG, *POS2_DOSADDMUXWAITSEM_MSG;
+
+
+typedef struct _OS2_DOSDELETEMUXWAITSEM_MSG {
+ ULONG HandleIndex;
+ ULONG EntryHandleIndex;
+} OS2_DOSDELETEMUXWAITSEM_MSG, *POS2_DOSDELETEMUXWAITSEM_MSG;
+
+
+typedef struct _OS2_DOSQUERYMUXWAITSEM_MSG {
+ ULONG HandleIndex;
+ ULONG CreateAttributes;
+ ULONG CountMuxWaitEntries;
+ PSEMRECORD MuxWaitEntries;
+} OS2_DOSQUERYMUXWAITSEM_MSG, *POS2_DOSQUERYMUXWAITSEM_MSG;
+
+typedef struct _OS2_DOSSTARTSESSION_INFO {
+ ULONG ResultSessionId;
+ USHORT Related;
+ ULONG QueueHandleIndex;
+ ULONG dwProcessId;
+ USHORT SessionType;
+ BOOLEAN WinSession;
+ BOOLEAN FgBg;
+} OS2_DOSSTARTSESSION_INFO, *POS2_DOSSTARTSESSION_INFO;
+
+typedef struct _OS2_DOSSELECTSESSION_MSG {
+ ULONG SessionId;
+} OS2_DOSSELECTSESSION_MSG, *POS2_DOSSELECTSESSION_MSG;
+
+typedef struct _OS2_DOSSETSESSION_MSG {
+ ULONG SessionId;
+ STATUSDATA StatusData;
+} OS2_DOSSETSESSION_MSG, *POS2_DOSSETSESSION_MSG;
+
+typedef struct _OS2_DOSSTOPSESSION_MSG {
+ ULONG SessionId;
+ ULONG fScope;
+} OS2_DOSSTOPSESSION_MSG, *POS2_DOSSTOPSESSION_MSG;
+
+typedef struct _OS2_DOSSMSETTITLE_MSG {
+ STRING Title;
+} OS2_DOSSMSETTITLE_MSG, *POS2_DOSSMSETTITLE_MSG;
+
+typedef struct _OS2_DOSSTARTSESSION_MSG {
+ OS2_DOSEXECPGM_MSG ExecPgmInformation;
+ OS2_DOSSTARTSESSION_INFO StartSessionInformation;
+} OS2_DOSSTARTSESSION_MSG, *POS2_DOSSTARTSESSION_MSG;
+
+typedef struct _OS2_DOSGETCTRLPORTFORSESSION_MSG {
+ ULONG SessionUniqueId;
+ HANDLE hControlPort;
+} OS2_DOSGETCTRLPORTFORSESSION_MSG, *POS2_DOSGETCTRLPORTFORSESSION_MSG;
+
+typedef struct _OS2_DOSCREATEQUEUE_MSG {
+ HQUEUE QueueHandle;
+ ULONG QueueType;
+ STRING QueueName;
+} OS2_DOSCREATEQUEUE_MSG, *POS2_DOSCREATEQUEUE_MSG;
+
+typedef struct _OS2_DOSOPENQUEUE_MSG {
+ PID OwnerProcessId;
+ HQUEUE QueueHandle;
+ STRING QueueName;
+} OS2_DOSOPENQUEUE_MSG, *POS2_DOSOPENQUEUE_MSG;
+
+typedef struct _OS2_DOSCLOSEQUEUE_MSG {
+ HQUEUE QueueHandle;
+ ULONG CloseCount;
+ PID OwnerProcessId;
+} OS2_DOSCLOSEQUEUE_MSG, *POS2_DOSCLOSEQUEUE_MSG;
+
+typedef struct _OS2_DOSPURGEQUEUE_MSG {
+ HQUEUE QueueHandle;
+} OS2_DOSPURGEQUEUE_MSG, *POS2_DOSPURGEQUEUE_MSG;
+
+typedef struct _OS2_DOSQUERYQUEUE_MSG {
+ HQUEUE QueueHandle;
+ ULONG CountQueueElements;
+ PID OwnerProcessId;
+} OS2_DOSQUERYQUEUE_MSG, *POS2_DOSQUERYQUEUE_MSG;
+
+typedef struct _OS2_DOSPEEKQUEUE_MSG {
+ HQUEUE QueueHandle;
+ REQUESTDATA RequestInfo;
+ ULONG DataLength;
+ PVOID Data;
+ ULONG ReadPosition;
+ BOOL32 NoWait;
+ ULONG SemIndex;
+ BYTE ElementPriority;
+} OS2_DOSPEEKQUEUE_MSG, *POS2_DOSPEEKQUEUE_MSG;
+
+typedef struct _OS2_DOSREADQUEUE_MSG {
+ HQUEUE QueueHandle;
+ REQUESTDATA RequestInfo;
+ ULONG DataLength;
+ PVOID Data;
+ ULONG ReadPosition;
+ BOOL32 NoWait;
+ ULONG SemIndex;
+ BYTE ElementPriority;
+} OS2_DOSREADQUEUE_MSG, *POS2_DOSREADQUEUE_MSG;
+
+typedef struct _OS2_DOSWRITEQUEUE_MSG {
+ HQUEUE QueueHandle;
+ PID OwnerProcessId;
+ ULONG SenderData;
+ ULONG DataLength;
+ PVOID Data;
+ BYTE ElementPriority;
+} OS2_DOSWRITEQUEUE_MSG, *POS2_DOSWRITEQUEUE_MSG;
+
+typedef struct _OS2_DOSENTERMUSTCOMPLETE_MSG {
+ ULONG NestingLevel;
+} OS2_DOSENTERMUSTCOMPLETE_MSG, *POS2_DOSENTERMUSTCOMPLETE_MSG;
+
+typedef struct _OS2_DOSEXITMUSTCOMPLETE_MSG {
+ ULONG NestingLevel;
+} OS2_DOSEXITMUSTCOMPLETE_MSG, *POS2_DOSEXITMUSTCOMPLETE_MSG;
+
+typedef struct _OS2_DOSSETSIGNALEXCEPTIONFOCUS_MSG {
+ ULONG NestingLevel;
+ BOOL32 Flag;
+} OS2_DOSSETSIGNALEXCEPTIONFOCUS_MSG, *POS2_DOSSETSIGNALEXCEPTIONFOCUS_MSG;
+
+typedef struct _OS2_DOSSENDSIGNALEXCEPTION_MSG {
+ PID ProcessId;
+ ULONG Exception;
+} OS2_DOSSENDSIGNALEXCEPTION_MSG, *POS2_DOSSENDSIGNALEXCEPTION_MSG;
+
+typedef struct _OS2_DOSACKNOWLEDGESIGNALEXCEPTION_MSG {
+ ULONG SignalNumber;
+} OS2_DOSACKNOWLEDGESIGNALEXCEPTION_MSG, *POS2_DOSACKNOWLEDGESIGNALEXCEPTION_MSG;
+
+typedef struct _OS2_DISPATCH16_SIGNAL {
+ USHORT usFlagNum;
+ USHORT usFlagArg;
+ ULONG fscope;
+ ULONG pidProcess;
+ ULONG routine;
+ ULONG sighandleraddr;
+} OS2_DISPATCH16_SIGNAL, *POS2_DISPATCH16_SIGNAL;
+
+#define MAX_API_NAME_FOR_GP 40
+
+typedef struct _OS2_DOSGP_MSG {
+ UCHAR ApiName[MAX_API_NAME_FOR_GP];
+} OS2_DOSGP_MSG, *POS2_DOSGP_MSG;
+
+typedef struct _OS2_DOSCLOSE_HANDLE_MSG {
+ ULONG HandleNumber;
+ HANDLE HandleTable[7];
+} OS2_DOSCLOSE_HANDLE_MSG, *POS2_DOSCLOSE_HANDLE_MSG;
+
+typedef struct _OS2_CONFIGSYS_MSG {
+ ULONG RequiredAccess; // IN: either OPEN_ACCESS_READONLY or OPEN_ACCESS_READWRITE
+ ULONG AllowedAccess; // OUT: either OPEN_ACCESS_READONLY or OPEN_ACCESS_READWRITE
+ NTSTATUS ReturnStatus; // OUT: an error status report
+
+//
+// Notes:
+// -- The os2conf.nt file has been created only if ReturnStatus is success
+// -- AllowedAccess is valid on return only if ReturnStatus is success or STATUS_ACCESS_DENIED
+// -- if RequiredAccess is READWRITE and only READONLY is available, the
+// os2conf.nt won't be created, ReturnStatus will be STATUS_ACCESS_DENIED,
+// and AllowedAccess will be READONLY.
+//
+
+} OS2_CONFIGSYS_MSG, *POS2_CONFIGSYS_MSG;
+
+typedef struct _OS2_NETBIOS_MSG {
+ UCHAR RequestType; // IN
+ UCHAR NetNumber; // IN
+ UCHAR RetCode; // OUT
+ UCHAR LanaEnumLength; // OUT
+ NTSTATUS ReturnStatus; // OUT
+ HANDLE hDev; // OUT
+ UCHAR LanaEnum[MAX_LANA_OS2SSMSG]; // OUT
+} OS2_NETBIOS_MSG, *POS2_NETBIOS_MSG;
+
+typedef struct _OS2_CAPTURE_HEADER {
+ ULONG Length;
+ struct _OS2_CAPTURE_HEADER *RelatedCaptureBuffer;
+ ULONG CountMessagePointers;
+ ULONG CountCapturePointers;
+ PULONG MessagePointerOffsets; // Offsets within OS2_API_MSG of pointers
+ PULONG CapturePointerOffsets; // Offsets within CaptureBuffer of pointers
+ PCHAR FreeSpace;
+} OS2_CAPTURE_HEADER, *POS2_CAPTURE_HEADER;
+
+typedef struct _OS2_REGISTER_HANDLER {
+ ULONG usFlagNum;
+ ULONG fAction;
+} OS2_REGISTER_HANDLER, *POS2_REGISTER_HANDLER;
+
+typedef struct _OS2_REALLOCSHAREDMEM_MSG{
+ PVOID BaseAddress; // base address of shared memory
+ PVOID AllocFreeBaseAddress; // start address of new allocation / free
+ USHORT NewLdtLimit; // New segment size in bytes
+ ULONG NewRegionSize; // New segment size rounded to pages
+ ULONG CurrentSize; // ldt limit rounded to pages
+ ULONG Flags; // Flags of new allocated memory
+ BOOLEAN SharedMemory; // flag set to true if shared segment found
+}OS2_REALLOCSHAREDMEM_MSG, *POS2_REALLOCSHAREDMEM_MSG;
+
+typedef struct _OS2_GIVESEG_MSG{
+ ULONG Selector;
+ PID TargetPid;
+}OS2_GIVESEG_MSG, *POS2_GIVESEG_MSG;
+
+typedef struct _OS2_GETSEG_MSG{
+ ULONG Selector;
+}OS2_GETSEG_MSG, *POS2_GETSEG_MSG;
+
+typedef struct _OS2_DOSGETSHRSEG_MSG {
+ ULONG Selector;
+ STRING ObjectName;
+} OS2_DOSGETSHRSEG_MSG, *POS2_DOSGETSHRSEG_MSG;
+
+typedef struct _LDRNEWEXE_MSG {
+ STRING ProcessName;
+ STRING FailName;
+ STRING LibPathName;
+ STRING InitRecords;
+ ULONG CurrentDrive;
+ ULONG DoscallsSel;
+ ULONG EntryFlatAddr;
+ ULONG NumOfInitRecords;
+#if PMNT
+ BOOLEAN PMProcess;
+#endif
+ BOOLEAN BoundApp;
+ EXECINFO ExecInfo;
+} LDRNEWEXE_MSG, *P_LDRNEWEXE_MSG;
+
+typedef struct _LDRLOADMODULE_MSG {
+ STRING ModuleName;
+ STRING FailName;
+ STRING LibPathName;
+ STRING InitRecords;
+ ULONG ModuleHandle;
+ ULONG NumOfInitRecords;
+ EXECINFO ExecInfo;
+} LDRLOADMODULE_MSG, *P_LDRLOADMODULE_MSG;
+
+typedef struct _LDRFREEMODULE_MSG {
+ ULONG ModuleHandle;
+} LDRFREEMODULE_MSG, *P_LDRFREEMODULE_MSG;
+
+typedef struct _LDRGETMODULENAME_MSG {
+ STRING ModuleName;
+ ULONG ModuleHandle;
+} LDRGETMODULENAME_MSG, *P_LDRGETMODULENAME_MSG;
+
+typedef struct _LDRGETMODULEHANDLE_MSG {
+ STRING ModuleName;
+ STRING LibPathName;
+ ULONG ModuleHandle;
+} LDRGETMODULEHANDLE_MSG, *P_LDRGETMODULEHANDLE_MSG;
+
+typedef struct _LDRGETPROCADDR_MSG {
+ STRING ProcName;
+ ULONG ModuleHandle;
+ BOOLEAN ProcNameIsOrdinal; // Selects OrdinalNumber or ProcName fields
+ ULONG OrdinalNumber;
+ ULONG ProcAddr;
+} LDRGETPROCADDR_MSG, *P_LDRGETPROCADDR_MSG;
+
+typedef struct _LDRQAPPTYPE_MSG {
+ STRING AppName;
+ STRING PathName;
+ ULONG AppType;
+} LDRQAPPTYPE_MSG, *P_LDRQAPPTYPE_MSG;
+
+typedef struct _LDRGETRESOURCE_MSG {
+ ULONG ModuleHandle ;
+ ULONG ResourceType ;
+ ULONG ResourceName;
+ ULONG ResourceSel;
+ ULONG ResourceAddr;
+ ULONG NumberOfSegments;
+} LDRGETRESOURCE_MSG, *P_LDRGETRESOURCE_MSG;
+
+typedef struct _LDRFREERESOURCE_MSG {
+ ULONG ResourceAddr;
+} LDRFREERESOURCE_MSG, *P_LDRFREERESOURCE_MSG;
+
+#if PMNT
+typedef struct _LDRIDENTIFYCODESELECTOR_MSG {
+ USHORT sel;
+ USHORT segNum;
+ USHORT mte;
+ STRING ModName;
+} LDRIDENTIFYCODESELECTOR_MSG, *P_LDRIDENTIFYCODESELECTOR_MSG;
+
+typedef struct _PMNTSETPMSHELLFLAG_MSG {
+ ULONG Dummy;
+} PMNTSETPMSHELLFLAG_MSG, *P_PMNTSETPMSHELLFLAG_MSG;
+#endif
+
+#if PMNT && DBG
+typedef struct _LDRDUMPSEGMENTS_MSG {
+ ULONG Dummy ;
+} LDRDUMPSEGMENTS_MSG, *P_LDRDUMPSEGMENTS_MSG;
+#endif
+
+typedef struct _OS2_API_MSG {
+ PORT_MESSAGE h;
+ ULONG PortType; // 0 - this port; 1 - Console port server.
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ OS2_API_NUMBER ApiNumber;
+ ULONG ReturnedErrorValue;
+ union {
+ OS2_NULLAPICALL_MSG NullApiCall;
+ OS2_COPYHANDLETABLE_MSG CopyHandleTable;
+ OS2_SHARE_MSG DeviceShare;
+ OS2_ALERTMUXWAITER_MSG AlertMuxWaiter;
+ OS2_TERMINATETHREAD_MSG TerminateThread;
+ OS2_TERMINATEPROCESS_MSG TerminateProcess;
+ OS2_QUERYVIRTUALMEMORY_MSG QueryVirtualMemory;
+ OS2_MARKSHAREDMEMASHUGE_MSG MarkSharedMemAsHuge;
+ OS2_REALLOCSHAREDHUGE_MSG ReallocSharedHuge;
+
+ OS2_DOSCREATETHREAD_MSG DosCreateThread;
+ OS2_DOSWAITCHILD_MSG DosWaitChild;
+ OS2_DOSWAITTHREAD_MSG DosWaitThread;
+ OS2_DOSEXIT_MSG DosExit;
+ OS2_DOSEXECPGM_MSG DosExecPgm;
+ OS2_DOSKILLPROCESS_MSG DosKillProcess;
+ OS2_DOSSETPRIORITY_MSG DosSetPriority;
+ OS2_DOSGETPRIORITY_MSG DosGetPriority;
+ OS2_DOSGETPPID_MSG DosGetPPID;
+ OS2_DOSERROR_MSG DosError;
+ OS2_DOSFREEMEM_MSG DosFreeMem;
+ OS2_DOSGIVESHAREDMEM_MSG DosGiveSharedMem;
+ OS2_DOSGETSHAREDMEM_MSG DosGetSharedMem;
+ OS2_DOSGETNAMEDSHAREDMEM_MSG DosGetNamedSharedMem;
+ OS2_DOSALLOCSHAREDMEM_MSG DosAllocSharedMem;
+ OS2_DOSCREATEEVENTSEM_MSG DosCreateEventSem;
+ OS2_DOSOPENEVENTSEM_MSG DosOpenEventSem;
+ OS2_DOSCLOSEEVENTSEM_MSG DosCloseEventSem;
+ OS2_DOSCREATEMUTEXSEM_MSG DosCreateMutexSem;
+ OS2_DOSOPENMUTEXSEM_MSG DosOpenMutexSem;
+ OS2_DOSCLOSEMUTEXSEM_MSG DosCloseMutexSem;
+ OS2_DOSCREATEMUXWAITSEM_MSG DosCreateMuxWaitSem;
+ OS2_DOSOPENMUXWAITSEM_MSG DosOpenMuxWaitSem;
+ OS2_DOSCLOSEMUXWAITSEM_MSG DosCloseMuxWaitSem;
+ OS2_DOSWAITMUXWAITSEM_MSG DosWaitMuxWaitSem;
+ OS2_DOSADDMUXWAITSEM_MSG DosAddMuxWaitSem;
+ OS2_DOSDELETEMUXWAITSEM_MSG DosDeleteMuxWaitSem;
+ OS2_DOSQUERYMUXWAITSEM_MSG DosQueryMuxWaitSem;
+ OS2_DOSSTARTSESSION_MSG DosStartSession;
+ OS2_DOSGETCTRLPORTFORSESSION_MSG DosGetCtrlPortForSession;
+ OS2_DOSSELECTSESSION_MSG DosSelectSession;
+ OS2_DOSSETSESSION_MSG DosSetSession;
+ OS2_DOSSTOPSESSION_MSG DosStopSession;
+ OS2_DOSSMSETTITLE_MSG DosSmSetTitle;
+ OS2_DOSCREATEQUEUE_MSG DosCreateQueue;
+ OS2_DOSOPENQUEUE_MSG DosOpenQueue;
+ OS2_DOSCLOSEQUEUE_MSG DosCloseQueue;
+ OS2_DOSPURGEQUEUE_MSG DosPurgeQueue;
+ OS2_DOSQUERYQUEUE_MSG DosQueryQueue;
+ OS2_DOSPEEKQUEUE_MSG DosPeekQueue;
+ OS2_DOSREADQUEUE_MSG DosReadQueue;
+ OS2_DOSWRITEQUEUE_MSG DosWriteQueue;
+ OS2_DOSENTERMUSTCOMPLETE_MSG DosEnterMustComplete;
+ OS2_DOSEXITMUSTCOMPLETE_MSG DosExitMustComplete;
+ OS2_DOSSETSIGNALEXCEPTIONFOCUS_MSG DosSetSignalExceptionFocus;
+ OS2_DOSSENDSIGNALEXCEPTION_MSG DosSendSignalException;
+ OS2_DOSACKNOWLEDGESIGNALEXCEPTION_MSG DosAcknowledgeSignalException;
+ OS2_DISPATCH16_SIGNAL Dispatch16Signal;
+ OS2_REGISTER_HANDLER DosRegisterCtrlHandler;
+ OS2_DOSGP_MSG DosExitGP;
+ OS2_DOSCLOSE_HANDLE_MSG DosCloseHandle;
+ OS2_CONFIGSYS_MSG CreateConfigSysRequest;
+ OS2_NETBIOS_MSG Netbios2Request;
+ OS2_REALLOCSHAREDMEM_MSG ReallocSharedMem;
+ OS2_GETSEG_MSG DosGetSeg;
+ OS2_GIVESEG_MSG DosGiveSeg;
+ OS2_DOSGETSHRSEG_MSG DosGetShrSeg;
+ OS2_DOSPTRACE_MSG DosPTrace;
+ LDRNEWEXE_MSG LdrNewExe;
+ LDRLOADMODULE_MSG LdrLoadModule;
+ LDRFREEMODULE_MSG LdrFreeModule;
+ LDRGETMODULENAME_MSG LdrGetModuleName;
+ LDRGETMODULEHANDLE_MSG LdrGetModuleHandle;
+ LDRGETPROCADDR_MSG LdrGetProcAddr;
+ LDRQAPPTYPE_MSG LdrQAppType;
+ LDRGETRESOURCE_MSG LdrGetResource;
+ LDRFREERESOURCE_MSG LdrFreeResource;
+#if PMNT
+ LDRIDENTIFYCODESELECTOR_MSG LdrIdentifyCodeSelector;
+ PMNTSETPMSHELLFLAG_MSG PMNTSetPMshellFlag;
+#endif
+#if PMNT && DBG
+ LDRDUMPSEGMENTS_MSG LdrDumpSegments;
+#endif
+ } u;
+} OS2_API_MSG, *POS2_API_MSG;
+
+typedef struct _OD2_SIG_HANDLER_REC {
+ ULONG signature;
+ ULONG fholdenable;
+ ULONG sighandler[7];
+ OS2_DISPATCH16_SIGNAL outstandingsig[7];
+ ULONG doscallssel;
+ USHORT action[7];
+} OD2_SIG_HANDLER_REC, *POD2_SIG_HANDLER_REC;
+
+#define ThunkOffsetDosExitStub 0
+#define ThunkOffsetLDRLibiReturn 4
+#define ThunkOffsetExitProcessStub 8
+#define ThunkOffsetDosReturn 12
+
+/* Signal Numbers for DosSetSigHandler */
+
+#define SIG_CTRLC 1 /* Control C */
+#define SIG_BROKENPIPE 2 /* Broken Pipe */
+#define SIG_KILLPROCESS 3 /* Program Termination */
+#define SIG_CTRLBREAK 4 /* Control Break */
+#define SIG_PFLG_A 5 /* Process Flag A */
+#define SIG_PFLG_B 6 /* Process Flag B */
+#define SIG_PFLG_C 7 /* Process Flag C */
+#define SIG_CSIGNALS 8 /* number of signals plus one */
+
+/* Flag Numbers for DosFlagProcess */
+
+#define PFLG_A 0 /* Process Flag A */
+#define PFLG_B 1 /* Process Flag B */
+#define PFLG_C 2 /* Process Flag C */
+
+/* Signal actions */
+
+#define SIGA_KILL 0
+#define SIGA_IGNORE 1
+#define SIGA_ACCEPT 2
+#define SIGA_ERROR 3
+#define SIGA_ACKNOWLEDGE 4
+#define SIGA_ENABLE_HANDLING 5
+
+#define SIGA_ACKNOWLEDGE_AND_ACCEPT 0xbeef
+
+/* DosHoldSignal defines */
+#define HLDSIG_ENABLE 0
+#define HLDSIG_DISABLE 1
+
+#define HOLD_SIGNAL_CLEARED 0xffff
+
+typedef struct _OS2_REGISTER16_SIGNAL {
+ USHORT regSP; /* offset 0 */
+ USHORT regSS; /* offset 2 */
+ USHORT regBP; /* offset 4 */
+ USHORT regDX; /* offset 6 */
+ USHORT regBX; /* offset 8 */
+ USHORT regCX; /* offset 10 */
+ USHORT regSI; /* offset 12 */
+ USHORT regDI; /* offset 14 */
+ USHORT regES; /* offset 16 */
+ USHORT regDS; /* offset 18 */
+ USHORT usFlagNum;
+ USHORT usFlagArg;
+} OS2_REGISTER16_SIGNAL, *POS2_REGISTER16_SIGNAL;
+
diff --git a/private/os2/inc/os2ssrtl.h b/private/os2/inc/os2ssrtl.h
new file mode 100644
index 000000000..86dff4920
--- /dev/null
+++ b/private/os2/inc/os2ssrtl.h
@@ -0,0 +1,476 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2ssrtl.h
+
+Abstract:
+
+ Main include file for OS/2 Subsystem Runtime Library shared by the Client
+ and Server image files.
+
+Author:
+
+ Steve Wood (stevewo) 7-Nov-1989
+
+Revision History:
+
+
+ 4/14/93 - MJarus - Add OS2SS_SKIP_INCL_OS2V20, for not including os2v20.h
+ and so enable including <nt.h> and <windows.h> together.
+
+--*/
+
+//
+// Include NT Definitions
+//
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+
+//
+// Include OS/2SS Debug Definitions
+//
+
+extern ULONG Os2Debug;
+#include "os2dbg.h"
+
+
+
+//
+// Include OS/2 V2.0 Definitions
+//
+
+#ifndef OS2SS_SKIP_INCL_OS2V20 // don'y include os2v20: include nt & windows
+#include "os2v20.h"
+#else
+#ifndef APIRET
+#define APIRET ULONG
+#endif // APIRET
+#endif // OS2SS_SKIP_INCL_OS2V20
+
+
+//
+// Include C Runtime Definitions
+//
+
+#include <string.h>
+
+
+//
+// CMD shortcut communication between dlltask.c and server
+//
+
+#define NO_REDIR 0
+#define REDIR_NUL 1
+#define REDIR_FILE 2
+#define CMD_SHORTCUT 4
+
+//
+// Common types and constant definitions
+//
+
+#define OS2_SS_ROOT_OBJECT_DIRECTORY L"\\OS2SS"
+
+ //
+ // The following constant should get into ntrtl.h
+ //
+#define RTL_USER_PROC_OS2_16BIT_PROG 0x80000000
+
+//
+// SubSystemData field in PEB points to the following data structure for
+// OS/2 applications. Initial contents is passed back via the connection
+// information structure when the client process connects to the OS/2
+// Emulation Subsystem server
+//
+
+// This is equal to OS2_MAX_APPL_NAME in sesport.h
+// If you change either one, update also the other.
+
+#define OS2_PROCESS_MAX_APPL_NAME 33
+
+typedef struct _PEB_OS2_DATA {
+ ULONG Length;
+ PVOID ClientStartAddress;
+ BOOLEAN StartedBySm;
+ ULONG SizeOfInheritedHandleTable;
+ ULONG InitialDefaultDrive;
+ HANDLE StdIn;
+ HANDLE StdOut;
+ HANDLE StdErr;
+ HANDLE SessionPortHandle;
+ PVOID SessionDataBaseAddress;
+ ULONG CodePage;
+} PEB_OS2_DATA, *PPEB_OS2_DATA;
+
+
+//
+// shandle.c
+//
+
+typedef struct _OR2_HANDLE_TABLE {
+ ULONG Length;
+ RTL_CRITICAL_SECTION Lock;
+ PVOID Heap;
+ ULONG LogEntrySize;
+ ULONG CountEntries;
+ ULONG CountFixedEntries;
+ ULONG CountFreeEntries;
+ PVOID FixedEntries;
+ PVOID Entries;
+ PVOID Reserved;
+} OR2_HANDLE_TABLE, *POR2_HANDLE_TABLE;
+
+//
+// If the process is dieing, and there is only thread 1, there is no
+// need for the lock, and we should not try it incase we terminated
+// a thread inside (Acquire .. Release) block.
+//
+ULONG Od2ThreadId();
+#ifdef Od2SigHandlingInProgress
+ extern BOOLEAN Od2SigHandlingInProgress;
+#else
+ BOOLEAN Od2SigHandlingInProgress;
+#endif
+#define AcquireHandleTableLock( p ) \
+ if ((!Od2SigHandlingInProgress) || (Od2ThreadId() != 1)) \
+ RtlEnterCriticalSection( &(p)->Lock )
+#define ReleaseHandleTableLock( p ) \
+ if ((!Od2SigHandlingInProgress) || (Od2ThreadId() != 1)) \
+ RtlLeaveCriticalSection( &(p)->Lock )
+
+POR2_HANDLE_TABLE
+Or2CreateHandleTable(
+ IN PVOID Heap,
+ IN ULONG SizeOfEntry,
+ IN ULONG CountFixedEntries
+ );
+
+
+typedef VOID (*OR2_DESTROY_HANDLE_ROUTINE)(
+ IN PVOID HandleTableEntry,
+ IN ULONG HandleIndex
+ );
+
+BOOLEAN
+Or2DestroyHandleTable(
+ IN POR2_HANDLE_TABLE HandleTable,
+ IN OR2_DESTROY_HANDLE_ROUTINE DestroyHandleProcedure
+ );
+
+
+BOOLEAN
+Or2CreateHandle(
+ IN POR2_HANDLE_TABLE HandleTable,
+ IN OUT PULONG Handle,
+ IN PVOID Value
+ );
+
+
+BOOLEAN
+Or2DestroyHandle(
+ IN POR2_HANDLE_TABLE HandleTable,
+ IN ULONG Handle
+ );
+
+
+PVOID
+Or2MapHandle(
+ IN POR2_HANDLE_TABLE HandleTable,
+ IN ULONG Handle,
+ IN BOOLEAN TableLocked
+ );
+
+typedef BOOLEAN (*OR2_ENUMERATE_HANDLE_ROUTINE)(
+ IN PVOID HandleTableEntry,
+ IN PVOID EnumParameter
+ );
+
+BOOLEAN
+Or2EnumHandleTable(
+ IN POR2_HANDLE_TABLE HandleTable,
+ IN OR2_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
+ IN PVOID EnumParameter,
+ OUT PULONG Handle OPTIONAL
+ );
+
+#if DBG
+typedef VOID (*OR2_DUMP_HANDLE_ROUTINE)(
+ IN PVOID HandleTableEntry,
+ IN ULONG HandleIndex,
+ IN PVOID DumpParameter
+ );
+
+ULONG
+Or2DumpHandleTable(
+ IN POR2_HANDLE_TABLE HandleTable,
+ IN OR2_DUMP_HANDLE_ROUTINE DumpHandleProcedure,
+ IN PVOID DumpParameter
+ );
+#endif
+
+//
+// qhandle.c
+//
+
+typedef struct _OR2_QHANDLE_ENTRY {
+ PVOID Entry;
+ BOOLEAN EntryIsAllocated;
+ BOOLEAN EntryIsChunkPointer;
+} OR2_QHANDLE_ENTRY, *POR2_QHANDLE_ENTRY;
+
+typedef struct _OR2_QHANDLE_TABLE {
+ RTL_CRITICAL_SECTION Lock;
+ PVOID Heap;
+ ULONG EntrySize;
+ ULONG CountEntries;
+ ULONG CountFreeEntries;
+ ULONG NextToAllocate;
+ POR2_QHANDLE_ENTRY QHandles;
+} OR2_QHANDLE_TABLE, *POR2_QHANDLE_TABLE;
+
+POR2_QHANDLE_TABLE
+Or2CreateQHandleTable(
+ IN PVOID Heap,
+ IN ULONG SizeOfEntry,
+ IN ULONG CountFixedEntries
+ );
+
+typedef VOID (*OR2_DESTROY_QHANDLE_ROUTINE)(
+ IN PVOID HandleTableEntry,
+ IN ULONG HandleIndex
+ );
+
+BOOLEAN
+Or2DestroyQHandleTable(
+ IN POR2_QHANDLE_TABLE HandleTable,
+ IN OR2_DESTROY_QHANDLE_ROUTINE DestroyHandleProcedure
+ );
+
+
+BOOLEAN
+Or2CreateQHandle(
+ IN POR2_QHANDLE_TABLE HandleTable,
+ IN OUT PULONG Handle,
+ IN PVOID Value
+ );
+
+
+BOOLEAN
+Or2DestroyQHandle(
+ IN POR2_QHANDLE_TABLE HandleTable,
+ IN ULONG Handle
+ );
+
+
+PVOID
+Or2MapQHandle(
+ IN POR2_QHANDLE_TABLE HandleTable,
+ IN ULONG Handle,
+ IN BOOLEAN TableLocked
+ );
+
+//
+// ntmap.c
+//
+
+APIRET
+Or2MapStatus(
+ IN NTSTATUS Status
+ );
+
+APIRET
+Or2MapFlagsToProtection(
+ ULONG Flags,
+ PULONG Protection
+ );
+
+APIRET
+Or2MapProtectionToFlags(
+ ULONG Protection,
+ PULONG Flags
+ );
+
+APIRET
+Or2MapNtStatusToOs2Error(
+ IN NTSTATUS Status,
+ IN APIRET DefaultRetCode
+ );
+
+//
+// consys.c
+//
+
+#define FWD +1L // these are used with
+#define BWD -1L // Or2SkipWWS
+
+#define NULL_DELIM 0 // these are used with
+#define CRLF_DELIM 1 // Or2IterateEnvironment
+
+//
+// if OS2CONF_NAME_OPT == 1 then os2conf.nt will reside in %SystemRoot%\system32\os2 .
+// if OS2CONF_NAME_OPT == 0 then os2conf.nt will reside in c:\ .
+//
+// CLIENT_POPUP_ON_READ designates whether the client should generate a popup if the
+// program tries to open config.sys for reading (it always generates a popup when
+// opening for writing).
+//
+
+#define OS2CONF_NAME_OPT 0
+#define CLIENT_POPUP_ON_READ 1
+
+#if OS2CONF_NAME_OPT
+#define OS2CONF_NAMEA "\\OS2\\OS2CONF.NT"
+#define OS2CONF_NAMEW L"\\OS2\\OS2CONF.NT"
+#else
+#define OS2CONF_NAMEA "\\OS2CONF.NT"
+#define OS2CONF_NAMEW L"\\OS2CONF.NT"
+#endif
+
+typedef VOID (*PFN_ENVIRONMENT_PROCESSOR)(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ );
+
+typedef struct _ENVIRONMENT_DISPATCH_TABLE_ENTRY {
+ PWSTR VarName;
+ PWSTR Delimiters;
+ PFN_ENVIRONMENT_PROCESSOR DispatchFunction;
+ PVOID UserParameter;
+} ENVIRONMENT_DISPATCH_TABLE_ENTRY, *PENVIRONMENT_DISPATCH_TABLE_ENTRY;
+
+typedef PENVIRONMENT_DISPATCH_TABLE_ENTRY ENVIRONMENT_DISPATCH_TABLE;
+
+typedef struct _ENVIRONMENT_SEARCH_RECORD {
+ ULONG DispatchTableIndex;
+ PWSTR Name;
+ ULONG NameLen;
+ PWSTR Value;
+ ULONG ValueLen;
+} ENVIRONMENT_SEARCH_RECORD, *PENVIRONMENT_SEARCH_RECORD;
+
+VOID
+Or2SkipWWS(
+ IN OUT PWSTR *Str,
+ IN LONG Direction
+ );
+
+VOID
+Or2UnicodeStrupr(
+ IN OUT PWSTR Str
+ );
+
+BOOLEAN
+Or2UnicodeEqualCI(
+ IN PWSTR Str1,
+ IN PWSTR Str2,
+ IN ULONG Count
+ );
+
+BOOLEAN
+Or2AppendPathToPath(
+ IN PVOID HeapHandle,
+ IN PWSTR SrcPath,
+ IN OUT PUNICODE_STRING DestPath,
+ IN BOOLEAN ExpandIt
+ );
+
+BOOLEAN
+Or2ReplacePathByPath(
+ IN PVOID HeapHandle,
+ IN PWSTR SrcPath,
+ IN OUT PUNICODE_STRING DestPath
+ );
+
+VOID
+Or2CheckSemicolon(
+ IN OUT PUNICODE_STRING Str
+ );
+
+BOOLEAN
+Or2GetEnvPath(
+ OUT PUNICODE_STRING Data,
+ IN PVOID HeapHandle,
+ IN USHORT MaxSiz,
+ IN HANDLE EnvKey,
+ IN PWSTR ValueName,
+ IN BOOLEAN ExpandIt
+ );
+
+VOID
+Or2IterateEnvironment(
+ IN PWSTR Environment,
+ IN ENVIRONMENT_DISPATCH_TABLE DispatchTable,
+ IN ULONG NumberOfDispatchItems,
+ IN ULONG DelimOption
+ );
+
+VOID
+Or2FillInSearchRecordDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ );
+
+//
+// datetime.c
+//
+
+APIRET
+Or2GetDateTimeInfo(
+ PLARGE_INTEGER pSystemTime,
+ PLARGE_INTEGER pLocalTime,
+ PTIME_FIELDS pNtDateTime,
+ PVOID pSystemInformation,
+ PSHORT pTimeZone
+ );
+
+//
+// nls.c
+//
+
+extern ULONG Or2ProcessCodePage;
+extern ULONG Or2CurrentCodePageIsOem;
+
+#define Or2InitMBString RtlInitAnsiString
+
+//VOID
+//Or2InitMBString(
+// PANSI_STRING DestinationString,
+// PCSZ SourceString);
+
+APIRET
+Or2MBStringToUnicodeString(
+ PUNICODE_STRING DestinationString,
+ PANSI_STRING SourceString,
+ BOOLEAN AllocateDestinationString);
+
+BOOLEAN
+Or2CreateUnicodeStringFromMBz(
+ OUT PUNICODE_STRING DestinationString,
+ IN PCSZ SourceString);
+
+APIRET
+Or2UnicodeStringToMBString(
+ PANSI_STRING DestinationString,
+ PUNICODE_STRING SourceString,
+ BOOLEAN AllocateDestinationString);
+
+#define Or2FreeMBString RtlFreeOemString
+
+//VOID
+//Or2FreeMBString(
+// PANSI_STRING AnsiString);
+
+#include "os2crt.h"
diff --git a/private/os2/inc/os2sub.h b/private/os2/inc/os2sub.h
new file mode 100644
index 000000000..1bd64662f
--- /dev/null
+++ b/private/os2/inc/os2sub.h
@@ -0,0 +1,416 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ os2sub.h
+
+Abstract:
+
+ Main include file for OS/2 Client 16 bit VIO API support (Vio, Kbd & Mou )
+
+Author:
+
+ Yaron Shamir (YaronS) 19-Jul-1991
+
+Revision History:
+
+--*/
+
+#ifndef _OS2VIO_
+#define _OS2VIO_
+
+#define KR_KBDCHARIN 0x00000001L
+#define KR_KBDPEEK 0x00000002L
+#define KR_KBDFLUSHBUFFER 0x00000004L
+#define KR_KBDGETSTATUS 0x00000008L
+#define KR_KBDSETSTATUS 0x00000010L
+#define KR_KBDSTRINGIN 0x00000020L
+#define KR_KBDOPEN 0x00000040L
+#define KR_KBDCLOSE 0x00000080L
+#define KR_KBDGETFOCUS 0x00000100L
+#define KR_KBDFREEFOCUS 0x00000200L
+#define KR_KBDGETCP 0x00000400L
+#define KR_KBDSETCP 0x00000800L
+#define KR_KBDXLATE 0x00001000L
+#define KR_KBDSETCUSTXT 0x00002000L
+
+#define IO_WAIT 0
+#define IO_NOWAIT 1
+
+#define KEYBOARD_ECHO_ON 0x0001
+#define KEYBOARD_ECHO_OFF 0x0002
+#define KEYBOARD_BINARY_MODE 0x0004
+#define KEYBOARD_ASCII_MODE 0x0008
+#define KEYBOARD_MODIFY_STATE 0x0010
+#define KEYBOARD_MODIFY_INTERIM 0x0020
+#define KEYBOARD_MODIFY_TURNAROUND 0x0040
+#define KEYBOARD_2B_TURNAROUND 0x0080
+#define KEYBOARD_SHIFT_REPORT 0x0100
+
+#define KBDTRF_SHIFT_KEY_IN 0x01
+#define KBDTRF_CONVERSION_REQUEST 0x20
+#define KBDTRF_FINAL_CHAR_IN 0x40
+#define KBDTRF_INTERIM_CHAR_IN 0x80
+
+#define KEYBOARD_AT_COMPATABLE 0x0001
+#define KEYBOARD_ENHANCED_101 0xAB41
+#define KEYBOARD_ENHANCED_102 0xAB41
+#define KEYBOARD_ENHANCED_122 0xAB85
+#define KEYBOARD_SPACESAVER 0xAB54
+
+/* KBDKEYINFO structure, for KbdCharIn and KbdPeek */
+
+#pragma pack(1)
+typedef struct _KBDKEYINFO { /* kbci */
+ UCHAR chChar;
+ UCHAR chScan;
+ UCHAR fbStatus;
+ UCHAR bNlsShift;
+ USHORT fsState;
+ ULONG time;
+} KBDKEYINFO, *PKBDKEYINFO;
+
+/* structure for KbdStringIn() */
+
+typedef struct _STRINGINBUF { /* kbsi */
+ USHORT cb;
+ USHORT cchIn;
+} STRINGINBUF, *PSTRINGINBUF;
+
+/* KBDINFO structure, for KbdSet/GetStatus */
+
+typedef struct _KBDINFO { /* kbst */
+ USHORT cb;
+ USHORT fsMask;
+ USHORT chTurnAround;
+ USHORT fsInterim;
+ USHORT fsState;
+} KBDINFO, *PKBDINFO;
+
+/* structure for KbdGetHWID() */
+
+typedef struct _KBDHWID { /* kbhw */
+ USHORT cb;
+ USHORT idKbd;
+ USHORT usReserved1;
+ USHORT usReserved2;
+} KBDHWID, *PKBDHWID;
+
+/* structure for KbdXlate() */
+
+typedef struct _KBDTRANS { /* kbxl */
+ UCHAR chChar;
+ UCHAR chScan;
+ UCHAR fbStatus;
+ UCHAR bNlsShift;
+ USHORT fsState;
+ ULONG time;
+ USHORT fsDD;
+ USHORT fsXlate;
+ USHORT fsShift;
+ USHORT sZero;
+} KBDTRANS, *PKBDTRANS;
+
+/* first parameter registration constants */
+
+#define VR_VIOGETCURPOS 0x00000001L
+#define VR_VIOGETCURTYPE 0x00000002L
+#define VR_VIOGETMODE 0x00000004L
+#define VR_VIOGETBUF 0x00000008L
+#define VR_VIOGETPHYSBUF 0x00000010L
+#define VR_VIOSETCURPOS 0x00000020L
+#define VR_VIOSETCURTYPE 0x00000040L
+#define VR_VIOSETMODE 0x00000080L
+#define VR_VIOSHOWBUF 0x00000100L
+#define VR_VIOREADCHARSTR 0x00000200L
+#define VR_VIOREADCELLSTR 0x00000400L
+#define VR_VIOWRTNCHAR 0x00000800L
+#define VR_VIOWRTNATTR 0x00001000L
+#define VR_VIOWRTNCELL 0x00002000L
+#define VR_VIOWRTTTY 0x00004000L
+#define VR_VIOWRTCHARSTR 0x00008000L
+
+#define VR_VIOWRTCHARSTRATT 0x00010000L
+#define VR_VIOWRTCELLSTR 0x00020000L
+#define VR_VIOSCROLLUP 0x00040000L
+#define VR_VIOSCROLLDN 0x00080000L
+#define VR_VIOSCROLLLF 0x00100000L
+#define VR_VIOSCROLLRT 0x00200000L
+#define VR_VIOSETANSI 0x00400000L
+#define VR_VIOGETANSI 0x00800000L
+#define VR_VIOPRTSC 0x01000000L
+#define VR_VIOSCRLOCK 0x02000000L
+#define VR_VIOSCRUNLOCK 0x04000000L
+#define VR_VIOSAVREDRAWWAIT 0x08000000L
+#define VR_VIOSAVREDRAWUNDO 0x10000000L
+#define VR_VIOPOPUP 0x20000000L
+#define VR_VIOENDPOPUP 0x40000000L
+#define VR_VIOPRTSCTOGGLE 0x80000000L
+
+/* second parameter registration constants */
+
+#define VR_VIOMODEWAIT 0x00000001L
+#define VR_VIOMODEUNDO 0x00000002L
+#define VR_VIOGETFONT 0x00000004L
+#define VR_VIOGETCONFIG 0x00000008L
+#define VR_VIOSETCP 0x00000010L
+#define VR_VIOGETCP 0x00000020L
+#define VR_VIOSETFONT 0x00000040L
+#define VR_VIOGETSTATE 0x00000080L
+#define VR_VIOSETSTATE 0x00000100L
+
+/* structure for VioSet/GetCurType() */
+
+typedef struct _VIOCURSORINFO { /* vioci */
+ USHORT yStart;
+ USHORT cEnd;
+ USHORT cx;
+ USHORT attr;
+} VIOCURSORINFO, *PVIOCURSORINFO;
+
+/* VIOMODEINFO.color constants */
+
+#define COLORS_2 0x0001
+#define COLORS_4 0x0002
+#define COLORS_16 0x0004
+
+/* structure for VioSet/GetMode() */
+
+typedef struct _VIOMODEINFO { /* viomi */
+ USHORT cb;
+ UCHAR fbType;
+ UCHAR color;
+ USHORT col;
+ USHORT row;
+ USHORT hres;
+ USHORT vres;
+ UCHAR fmt_ID;
+ UCHAR attrib;
+ ULONG buf_addr;
+ ULONG buf_length;
+ ULONG full_length;
+ ULONG partial_length;
+ CHAR *ext_data_addr; /* => PCH */
+} VIOMODEINFO, *PVIOMODEINFO;
+
+#define VGMT_OTHER 0x01
+#define VGMT_GRAPHICS 0x02
+#define VGMT_DISABLEBURST 0x04
+
+#define ANSI_ON 1
+#define ANSI_OFF 0
+
+#define VSRWI_SAVEANDREDRAW 0
+#define VSRWI_REDRAW 1
+
+#define VSRWN_SAVE 0
+#define VSRWN_REDRAW 1
+
+#define UNDOI_GETOWNER 0
+#define UNDOI_RELEASEOWNER 1
+
+#define UNDOK_ERRORCODE 0
+#define UNDOK_TERMINATE 1
+
+#define VMWR_POPUP 0
+#define VMWN_POPUP 0
+
+#define LOCKIO_NOWAIT 0
+#define LOCKIO_WAIT 1
+
+#define LOCK_SUCCESS 0
+#define LOCK_FAIL 1
+
+#define VP_NOWAIT 0x0000
+#define VP_WAIT 0x0001
+#define VP_OPAQUE 0x0000
+#define VP_TRANSPARENT 0x0002
+
+/* VIOCONFIGINFO.adapter constants */
+
+#define DISPLAY_MONOCHROME 0x0000
+#define DISPLAY_CGA 0x0001
+#define DISPLAY_EGA 0x0002
+#define DISPLAY_VGA 0x0003
+#define DISPLAY_8514A 0x0007
+
+/* VIOCONFIGINFO.display constants */
+
+#define MONITOR_MONOCHROME 0x0000
+#define MONITOR_COLOR 0x0001
+#define MONITOR_ENHANCED 0x0002
+#define MONITOR_8503 0x0003
+#define MONITOR_851X_COLOR 0x0004
+#define MONITOR_8514 0x0009
+
+/* structure for VioGetConfig() */
+
+typedef struct _VIOCONFIGINFO { /* vioin */
+ USHORT cb;
+ USHORT adapter;
+ USHORT display;
+ ULONG cbMemory;
+ USHORT Configuration;
+ USHORT VDHVersion;
+ USHORT Flags;
+ ULONG HWBufferSize;
+ ULONG FullSaveSize;
+ ULONG PartSaveSize;
+ USHORT EMAdaptersOFF;
+ USHORT EMDisplaysOFF;
+} VIOCONFIGINFO, *PVIOCONFIGINFO;
+
+#define VIO_CONFIG_CURRENT 0
+#define VIO_CONFIG_PRIMARY 1
+#define VIO_CONFIG_SECONDARY 2
+
+/* structure for VioGet/SetFont() */
+
+typedef struct _VIOFONTINFO { /* viofi */
+ USHORT cb;
+ USHORT type;
+ USHORT cxCell;
+ USHORT cyCell;
+ PVOID pbData;
+ USHORT cbData;
+} VIOFONTINFO, *PVIOFONTINFO;
+
+#define VGFI_GETCURFONT 0
+#define VGFI_GETROMFONT 1
+
+typedef struct _VIOPALSTATE { /* viopal */
+ USHORT cb;
+ USHORT type;
+ USHORT iFirst;
+ USHORT acolor[1];
+} VIOPALSTATE, *PVIOPALSTATE;
+
+typedef struct _VIOOVERSCAN { /* vioos */
+ USHORT cb;
+ USHORT type;
+ USHORT color;
+} VIOOVERSCAN, *PVIOOVERSCAN;
+
+typedef struct _VIOINTENSITY { /* vioint */
+ USHORT cb;
+ USHORT type;
+ USHORT fs;
+} VIOINTENSITY, *PVIOINTENSITY;
+
+typedef struct _VIOCOLORREG { /* viocreg */
+ USHORT cb;
+ USHORT type;
+ USHORT firstcolorreg;
+ USHORT numcolorregs;
+ CHAR *colorregaddr; /* => PCH */
+} VIOCOLORREG, *PVIOCOLORREG;
+
+typedef struct _VIOSETULINELOC { /* viouline */
+ USHORT cb;
+ USHORT type;
+ USHORT scanline;
+} VIOSETULINELOC, *PVIOSETULINELOC;
+
+typedef struct _VIOSETTARGET { /* viosett */
+ USHORT cb;
+ USHORT type;
+ USHORT defaultalgorithm;
+} VIOSETTARGET, *PVIOSETTARGET;
+
+#define MR_MOUGETNUMBUTTONS 0x00000001L
+#define MR_MOUGETNUMMICKEYS 0x00000002L
+#define MR_MOUGETDEVSTATUS 0x00000004L
+#define MR_MOUGETNUMQUEEL 0x00000008L
+#define MR_MOUREADEVENTQUE 0x00000010L
+#define MR_MOUGETSCALEFACT 0x00000020L
+#define MR_MOUGETEVENTMASK 0x00000040L
+#define MR_MOUSETSCALEFACT 0x00000080L
+#define MR_MOUSETEVENTMASK 0x00000100L
+#define MR_MOUOPEN 0x00000800L
+#define MR_MOUCLOSE 0x00001000L
+#define MR_MOUGETPTRSHAPE 0x00002000L
+#define MR_MOUSETPTRSHAPE 0x00004000L
+#define MR_MOUDRAWPTR 0x00008000L
+#define MR_MOUREMOVEPTR 0x00010000L
+#define MR_MOUGETPTRPOS 0x00020000L
+#define MR_MOUSETPTRPOS 0x00040000L
+#define MR_MOUINITREAL 0x00080000L
+#define MR_MOUSETDEVSTATUS 0x00100000L
+
+#define MHK_BUTTON1 0x0001
+#define MHK_BUTTON2 0x0002
+#define MHK_BUTTON3 0x0004
+
+/* structure for MouGet/SetPtrPos() */
+
+typedef struct _PTRLOC { /* moupl */
+ USHORT row;
+ USHORT col;
+} PTRLOC, *PPTRLOC;
+
+/* structure for MouGet/SetPtrShape() */
+
+typedef struct _PTRSHAPE { /* moups */
+ USHORT cb;
+ USHORT col;
+ USHORT row;
+ USHORT colHot;
+ USHORT rowHot;
+} PTRSHAPE, *PPTRSHAPE;
+
+/* structure for MouReadEventQue() */
+
+typedef struct _MOUEVENTINFO { /* mouev */
+ USHORT fs;
+ ULONG time;
+ USHORT row;
+ USHORT col;
+} MOUEVENTINFO, *PMOUEVENTINFO;
+
+/* structure for MouGetNumQueEl() */
+
+typedef struct _MOUQUEINFO { /* mouqi */
+ USHORT cEvents;
+ USHORT cmaxEvents;
+} MOUQUEINFO, *PMOUQUEINFO;
+
+/* structure for MouGet/SetScaleFact() */
+
+typedef struct _SCALEFACT { /* mousc */
+ USHORT rowScale;
+ USHORT colScale;
+} SCALEFACT, *PSCALEFACT;
+
+/* structure for MouRemovePtr() */
+
+typedef struct _NOPTRRECT { /* mourt */
+ USHORT row;
+ USHORT col;
+ USHORT cRow;
+ USHORT cCol;
+} NOPTRRECT, *PNOPTRRECT;
+#pragma pack()
+
+/* MouGetDevStatus/MouSetDevStatus device status constants */
+
+#define MOUSE_QUEUEBUSY 0x0001
+#define MOUSE_BLOCKREAD 0x0002
+#define MOUSE_FLUSH 0x0004
+#define MOUSE_UNSUPPORTED_MODE 0x0008
+#define MOUSE_DISABLED 0x0100
+#define MOUSE_MICKEYS 0x0200
+
+/* MouReadEventQue */
+
+#define MOU_NOWAIT 0x0000
+#define MOU_WAIT 0x0001
+
+#define MOU_NODRAW 0x0001
+#define MOU_DRAW 0x0000
+#define MOU_MICKEYS 0x0002
+#define MOU_PELS 0x0000
+
+#endif /* _OS2VIO_ */
+
diff --git a/private/os2/inc/os2tile.h b/private/os2/inc/os2tile.h
new file mode 100644
index 000000000..9007cf290
--- /dev/null
+++ b/private/os2/inc/os2tile.h
@@ -0,0 +1,85 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ os2tile.h
+
+Abstract:
+
+ Defines the Tiling scheme number for os2ss. Included by thunkcom, client
+ loader & server.
+
+Author:
+
+ Yaron Shamir (YaronS) 22-Oct-1992
+
+Revision History:
+
+ Patrick Questembert (PatrickQ) 04-Nov-92
+ Fixed FLATTOSEL macro (needed ULONG cast) + changed ULONG cast position so
+ that FLAT may be a pointer to types of any length.
+
+--*/
+
+
+#define BASE_TILE 0x38000000
+#define BASE_TILE_ZERO_BITS 1
+
+//
+// Preallocated areas at the top of the tiled region
+//
+
+#define _64K (64L*1024)
+#define _512M ((512L*1024)*1024)
+
+#define OD2TILEDHEAP_SIZE 20*_64K
+
+#define VIOSECTION_BASE (BASE_TILE + _512M - _64K) // This must be the last one
+#define OD2TILEDHEAP_BASE (VIOSECTION_BASE - OD2TILEDHEAP_SIZE)
+#define OD2ENVIRONMENT_BASE (OD2TILEDHEAP_BASE - _64K)
+#define GINFOSEG_BASE (OD2ENVIRONMENT_BASE - _64K)
+#define R2STACKS_BASE (GINFOSEG_BASE - _64K)
+#define R2XFER_BASE (R2STACKS_BASE - _64K)
+#define DOSCALLS_BASE (R2XFER_BASE - _64K)
+#if PMNT
+// The 3 selectors below are used to reserve the same 2 LDT selectors in each
+// OS/2 process so that they can map the video memory for PM apps.
+// PMDISPLAY_DUMMY is required to allow mapping of frame buffer sections where
+// the 2nd selector is not aligned to 64K + the length crosses the 64K
+// boundary: in such a case, we need to have the next selector free.
+#define PMDISPLAY_DUMMY (DOSCALLS_BASE - _64K)
+#define PMDISPLAY_BASE2 (PMDISPLAY_DUMMY - _64K)
+#define PMDISPLAY_BASE1 (PMDISPLAY_BASE2 - _64K)
+#endif
+//
+// OD2MAXSEG_MEM must be set to the lowest virtual address which
+// is pre-allocated.
+//
+#if PMNT
+#define OD2MAXSEG_MEM (PMDISPLAY_BASE1)
+#else
+#define OD2MAXSEG_MEM (DOSCALLS_BASE)
+#endif
+#define OD2MAXSEG_BASE (OD2MAXSEG_MEM - _64K)
+
+#define SELTOFLAT(SEL) (PVOID) (BASE_TILE + (((SEL) >> 3) << 16))
+#define FLATTOSEL(FLAT) (USHORT) (((((ULONG)(FLAT) - BASE_TILE) & 0x1fff0000) >> 13) | 7)
+#define FARPTRTOFLAT(FARPTR) (PVOID) (BASE_TILE + (((((ULONG)(FARPTR)) >> 19) << 16) | (((ULONG)(FARPTR)) & 0xffff)))
+#define FLATTOFARPTR(FLAT) ( (((((ULONG)(FLAT) - BASE_TILE) & 0x1fff0000) << 3) | 0x00070000) | (((ULONG)(FLAT)) & 0x0000ffff) )
+
+//
+// The LDT_DISJOINT_ENTRIES parameter defines the number of LDT entries
+// which are reserved for PROGRAM/DLL loading and shared memory segments.
+// The entries are reserved at the top of the LDT table.
+// PROGRAM/DLL segments are allocated from the bottom of the disjoint area
+// while shared memory segments are allocated from the top of the disjoint
+// area.
+//
+// This number MUST be a multiple of 32!
+//
+#define LDT_DISJOINT_ENTRIES 0x1800
+
+#define FIRST_SHARED_SELECTOR ((0x2000-LDT_DISJOINT_ENTRIES)*8)
+
diff --git a/private/os2/inc/os2v12.h b/private/os2/inc/os2v12.h
new file mode 100644
index 000000000..aad8956fd
--- /dev/null
+++ b/private/os2/inc/os2v12.h
@@ -0,0 +1,1106 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ os2v12.h
+
+Abstract:
+
+ Include file for OS/2 Subsystem Client 16 bit API support.
+
+Author:
+
+ Patrick Questembert 16-Feb-92
+
+Revision History:
+
+--*/
+
+#pragma pack(2) /* To cancel alignement done by 32-bit compiler since we
+ have in this include file only OS/2 1.x typedefs */
+
+#define INCL_DOSINCLUDED
+
+#ifndef INCL_BASEINCLUDED
+#if !(defined(INCL_32) || defined(INCL_16))
+#ifdef M_I386
+ #define INCL_32
+#else /* not M_I386 */
+ #define INCL_16
+#endif /* M_I386 */
+#endif /* INCL_32 || INCL_16 */
+
+#if !defined(INCL_16)
+#pragma message ("16-bit Base API included when using 32-bit compiler")
+#endif /* INCL_32 */
+#endif /* INCL_BASEINCLUDED */
+
+#ifdef INCL_DOS
+
+#define INCL_DOSPROCESS
+#define INCL_DOSINFOSEG
+#define INCL_DOSFILEMGR
+#define INCL_DOSMEMMGR
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSDATETIME
+#define INCL_DOSMODULEMGR
+#define INCL_DOSRESOURCES
+#define INCL_DOSNLS
+#define INCL_DOSSIGNALS
+#define INCL_DOSMISC
+#define INCL_DOSMONITORS
+#define INCL_DOSQUEUES
+#define INCL_DOSSESMGR
+#define INCL_DOSDEVICES
+#define INCL_DOSNMPIPES
+#define INCL_DOSPROFILE
+#define INCL_DOSMVDM
+
+#endif /* INCL_DOS */
+
+#ifdef INCL_ERRORS
+#define INCL_DOSERRORS
+#endif /* INCL_ERRORS */
+
+#if (defined(INCL_DOSPROCESS) || !defined(INCL_NOCOMMON))
+
+
+/* DosExit codes */
+#define EXIT_THREAD 0
+#define EXIT_PROCESS 1
+
+#endif /* common INCL_DOSPROCESS definitions */
+
+#ifdef INCL_DOSPROCESS
+
+typedef struct _PIDINFO { /* pidi */
+ USHORT pid;
+ USHORT tid;
+ USHORT pidParent;
+} PIDINFO;
+typedef PIDINFO FAR *PPIDINFO;
+
+
+/* Action code values */
+#define DCWA_PROCESS 0
+#define DCWA_PROCESSTREE 1
+
+/* Wait option values */
+#define DCWW_WAIT 0
+#define DCWW_NOWAIT 1
+
+/* codeTerminate values (also passed to ExitList routines) */
+#define TC_EXIT 0
+#define TC_HARDERROR 1
+#define TC_TRAP 2
+#define TC_KILLPROCESS 3
+
+
+/* DosExitList functions */
+#define EXLST_ADD 1
+#define EXLST_REMOVE 2
+#define EXLST_EXIT 3
+
+
+/* DosExecPgm functions */
+#define EXEC_SYNC 0
+#define EXEC_ASYNC 1
+#define EXEC_ASYNCRESULT 2
+#define EXEC_TRACE 3
+#define EXEC_BACKGROUND 4
+#define EXEC_LOAD 5
+
+
+
+/* Priority scopes */
+#define PRTYS_PROCESS 0
+#define PRTYS_PROCESSTREE 1
+#define PRTYS_THREAD 2
+
+/* Priority classes */
+#define PRTYC_NOCHANGE 0
+#define PRTYC_IDLETIME 1
+#define PRTYC_REGULAR 2
+#define PRTYC_TIMECRITICAL 3
+#define PRTYC_FOREGROUNDSERVER 4
+
+/* Priority deltas */
+#define PRTYD_MINIMUM -31
+#define PRTYD_MAXIMUM 31
+
+
+#define DKP_PROCESSTREE 0
+#define DKP_PROCESS 1
+
+#endif /* INCL_DOSPROCESS */
+
+
+/*** InfoSeg support */
+
+#ifdef INCL_DOSINFOSEG
+
+/* Global Information Segment */
+
+typedef struct _GINFOSEG { /* gis */
+ ULONG time;
+ ULONG msecs;
+ UCHAR hour;
+ UCHAR minutes;
+ UCHAR seconds;
+ UCHAR hundredths;
+ USHORT timezone;
+ USHORT cusecTimerInterval;
+ UCHAR day;
+ UCHAR month;
+ USHORT year;
+ UCHAR weekday;
+ UCHAR uchMajorVersion;
+ UCHAR uchMinorVersion;
+ UCHAR chRevisionLetter;
+ UCHAR sgCurrent;
+ UCHAR sgMax;
+ UCHAR cHugeShift;
+ UCHAR fProtectModeOnly;
+ USHORT pidForeground;
+ UCHAR fDynamicSched;
+ UCHAR csecMaxWait;
+ USHORT cmsecMinSlice;
+ USHORT cmsecMaxSlice;
+ USHORT bootdrive;
+ UCHAR amecRAS[32];
+ UCHAR csgWindowableVioMax;
+ UCHAR csgPMMax;
+} GINFOSEG;
+typedef GINFOSEG FAR *PGINFOSEG;
+
+/* Local Information Segment */
+
+typedef struct _LINFOSEG { /* lis */
+ USHORT pidCurrent;
+ USHORT pidParent;
+ USHORT prtyCurrent;
+ USHORT tidCurrent;
+ USHORT sgCurrent;
+ UCHAR rfProcStatus;
+ UCHAR dummy1;
+ USHORT fForeground;
+ UCHAR typeProcess;
+ UCHAR dummy2;
+ SEL selEnvironment;
+ USHORT offCmdLine;
+ USHORT cbDataSegment;
+ USHORT cbStack;
+ USHORT cbHeap;
+ USHORT hmod;
+ SEL selDS;
+} LINFOSEG;
+typedef LINFOSEG FAR *PLINFOSEG;
+
+/* Process Type codes (local information segment typeProcess field) */
+
+#define PT_FULLSCREEN 0 /* Full screen application */
+#define PT_REALMODE 1 /* Real mode process */
+#define PT_WINDOWABLEVIO 2 /* VIO windowable application */
+#define PT_PM 3 /* Presentation Manager application */
+#define PT_DETACHED 4 /* Detached application */
+
+/* Process Status Flag definitions (local info seg rfProcStatus field) */
+
+#define PS_EXITLIST 1 /* Thread is in exitlist routine */
+
+
+/* Helper macros used to convert selector to PINFOSEG or LINFOSEG */
+
+#define MAKEPGINFOSEG(sel) ((PGINFOSEG)MAKEP(sel, 0))
+#define MAKEPLINFOSEG(sel) ((PLINFOSEG)MAKEP(sel, 0))
+
+#endif /* INCL_DOSINFOSEG */
+
+/*
+ * CCHMAXPATH is the maximum fully qualified path name length including
+ * the drive letter, colon, backslashes and terminating NULL.
+ */
+#define CCHMAXPATH 260
+
+/*
+ * CCHMAXPATHCOMP is the maximum individual path component name length
+ * including a terminating NULL.
+ */
+#define CCHMAXPATHCOMP 256
+
+#if (defined(INCL_DOSFILEMGR) || !defined(INCL_NOCOMMON))
+
+/*** File manager */
+
+/* DosSetFilePtr() file position codes */
+
+#define FILE_BEGIN 0x0000 /* relative to beginning of file */
+#define FILE_CURRENT 0x0001 /* relative to current fptr position*/
+#define FILE_END 0x0002 /* relative to end of file */
+
+/* DosFindFirst/Next Directory handle types */
+
+#define HDIR_SYSTEM 1 /* Use system handle (1) */
+
+/* DosCopy control bits - may be or'ed together */
+#define DCPY_EXISTING 0x00001 /* Copy even if target exists */
+#define DCPY_APPEND 0x00002 /* Append to existing file, don't replace*/
+#define DCPY_FAILEAS 0x00004 /* Fail if EAs not supported on target*/
+
+/* Dosopen/DosQFHandState/DosQueryFileInfo et al file attributes; also */
+/* known as Dos File Mode bits... */
+#define FILE_NORMAL 0x0000
+#define FILE_READONLY 0x0001
+#define FILE_HIDDEN 0x0002
+#define FILE_SYSTEM 0x0004
+#define FILE_DIRECTORY 0x0010
+#define FILE_ARCHIVED 0x0020
+
+/* DosOpen() actions */
+#define FILE_EXISTED 0x0001
+#define FILE_CREATED 0x0002
+#define FILE_TRUNCATED 0x0003
+
+/* DosOpen() open flags */
+//#define FILE_OPEN 0x0001
+#define FILE_TRUNCATE 0x0002
+//#define FILE_CREATE 0x0010
+
+/* applies if file already exists */
+
+#define OPEN_ACTION_FAIL_IF_EXISTS 0x0000 /* ---- ---- ---- 0000 */
+#define OPEN_ACTION_OPEN_IF_EXISTS 0x0001 /* ---- ---- ---- 0001 */
+#define OPEN_ACTION_REPLACE_IF_EXISTS 0x0002 /* ---- ---- ---- 0010 */
+
+/* applies if file does not exist */
+
+#define OPEN_ACTION_FAIL_IF_NEW 0x0000 /* ---- ---- 0000 ---- */
+#define OPEN_ACTION_CREATE_IF_NEW 0x0010 /* ---- ---- 0001 ---- */
+
+/* DosOpen/DosSetFHandState flags */
+
+//#define OPEN_ACCESS_READONLY 0x0000 /* ---- ---- ---- -000 */
+//#define OPEN_ACCESS_WRITEONLY 0x0001 /* ---- ---- ---- -001 */
+//#define OPEN_ACCESS_READWRITE 0x0002 /* ---- ---- ---- -010 */
+//#define OPEN_SHARE_DENYREADWRITE 0x0010 /* ---- ---- -001 ---- */
+//#define OPEN_SHARE_DENYWRITE 0x0020 /* ---- ---- -010 ---- */
+//#define OPEN_SHARE_DENYREAD 0x0030 /* ---- ---- -011 ---- */
+//#define OPEN_SHARE_DENYNONE 0x0040 /* ---- ---- -100 ---- */
+//#define OPEN_FLAGS_NOINHERIT 0x0080 /* ---- ---- 1--- ---- */
+//#define OPEN_FLAGS_NO_LOCALITY 0x0000 /* ---- -000 ---- ---- */
+//#define OPEN_FLAGS_SEQUENTIAL 0x0100 /* ---- -001 ---- ---- */
+//#define OPEN_FLAGS_RANDOM 0x0200 /* ---- -010 ---- ---- */
+//#define OPEN_FLAGS_RANDOMSEQUENTIAL 0x0300 /* ---- -011 ---- ---- */
+//#define OPEN_FLAGS_NO_CACHE 0x1000 /* ---1 ---- ---- ---- */
+//#define OPEN_FLAGS_FAIL_ON_ERROR 0x2000 /* --1- ---- ---- ---- */
+//#define OPEN_FLAGS_WRITE_THROUGH 0x4000 /* -1-- ---- ---- ---- */
+//#define OPEN_FLAGS_DASD 0x8000 /* 1--- ---- ---- ---- */
+#define OPEN_FLAGS_NONSPOOLED 0x00040000
+
+#define MUST_HAVE_READONLY ( (FILE_READONLY << 8) | FILE_READONLY )
+#define MUST_HAVE_HIDDEN ( (FILE_HIDDEN << 8) | FILE_HIDDEN )
+#define MUST_HAVE_SYSTEM ( (FILE_SYSTEM << 8) | FILE_SYSTEM )
+#define MUST_HAVE_DIRECTORY ( (FILE_DIRECTORY << 8) | FILE_DIRECTORY )
+#define MUST_HAVE_ARCHIVED ( (FILE_ARCHIVED << 8) | FILE_ARCHIVED )
+
+/* DosSearchPath() constants */
+
+#define SEARCH_PATH 0x0000
+#define SEARCH_CUR_DIRECTORY 0x0001
+#define SEARCH_ENVIRONMENT 0x0002
+#define SEARCH_IGNORENETERRS 0x0004
+
+/*
+ * DosFileIO
+ */
+/* File IO command words */
+#define FIO_LOCK 0 /* Lock Files */
+#define FIO_UNLOCK 1 /* Unlock Files */
+#define FIO_SEEK 2 /* Seek (set file ptr) */
+#define FIO_READ 3 /* File Read */
+#define FIO_WRITE 4 /* File Write */
+
+/* Lock Sharing Modes */
+#define FIO_NOSHARE 0 /* None */
+#define FIO_SHAREREAD 1 /* Read-Only */
+
+typedef struct _FIOLOCKCMD16 { /* FLC FileLockCmd prefix */
+ USHORT usCmd; /* Cmd = FIO_LOCK */
+ USHORT cLockCnt; /* Lock records that follow */
+ ULONG cTimeOut; /* in Msec */
+} FIOLOCKCMD16;
+typedef FIOLOCKCMD16 FAR *PFIOLOCKCMD16;
+
+
+typedef struct _FIOLOCKREC16 { /* FLR FileLockRecord */
+ USHORT fShare; /* FIO_NOSHARE or FIO_SHAREREAD */
+ ULONG cbStart; /* Starting offset for lock region */
+ ULONG cbLength; /* Length of lock region */
+} FIOLOCKREC16;
+typedef FIOLOCKREC16 FAR *PFIOLOCKREC16;
+
+
+typedef struct _FIOUNLOCKCMD16 { /* FUC FileUnlockCmd prefix */
+ USHORT usCmd; /* Cmd = FIO_UNLOCK */
+ USHORT cUnlockCnt; /* Unlock records that follow */
+} FIOUNLOCKCMD16;
+typedef FIOUNLOCKCMD16 FAR *PFIOUNLOCKCMD16;
+
+
+typedef struct _FIOUNLOCKREC16 { /* FUR FileUnlockRecord */
+ ULONG cbStart; /* Starting offset for unlock region */
+ ULONG cbLength; /* Length of unlock region */
+} FIOUNLOCKREC16;
+typedef FIOUNLOCKREC16 FAR *PFIOUNLOCKREC16;
+
+
+typedef struct _FIOSEEKCMD16 { /* FSC Seek command structure */
+ USHORT usCmd; /* Cmd = FIO_SEEK */
+ USHORT fsMethod; /* One of&gml FPM_BEGINNING, FPM_CURRENT, */
+ ///* or FPM_END */
+ ULONG cbDistance; /* Byte offset for seek */
+ ULONG cbNewPosition; /* Bytes from start of file after seek */
+} FIOSEEKCMD16;
+typedef FIOSEEKCMD16 FAR *PFIOSEEKCMD16;
+
+
+typedef struct _FIOREADWRITE16 { /* RWC Read&Write command structure */
+ USHORT usCmd; /* Cmd = FIO_READ or FIO_WRITE */
+ PVOID pbBuffer; /* Pointer to data buffer */
+ USHORT cbBufferLen; /* Bytes in buffer or max size */
+ USHORT cbActualLen; /* Bytes actually read/written */
+} FIOREADWRITE16;
+typedef FIOREADWRITE16 FAR *PFIOREADWRITE16;
+
+/***
+ * EA Info Levels & Find First/Next
+ * API's: DosFindFirst, DosQueryFileInfo, DosQueryPathInfo, DosSetFileInfo,
+ * DosSetPathInfo
+ */
+
+/* File info levels : All listed API's */
+#define FIL_STANDARD 1 /* Info level 1, standard file info */
+#define FIL_QUERYEASIZE 2 /* Level 2, return Full EA size */
+#define FIL_QUERYEASFROMLIST 3 /* Level 3, return requested EA's */
+#define FIL_QUERYALLEAS 4 /* Level 4, return all EA's */
+
+/* File info levels: Dos...PathInfo only */
+#define FIL_QUERYFULLNAME 5 /* Level 5, return fully qualified */
+ /* name of file */
+#define FIL_NAMEISVALID 6 /* Level 6, check validity of */
+ /* file/path name for this FSD */
+
+/* DosFindNotifyFirst() */
+#define FNOTIL_STANDARD 1 /* Find-Notify Info level 1&gml Return */
+ /* standard directory change info */
+
+/* DosFsAttach() */
+/* Attact or detach */
+#define FSATTACH 0 /* Attach file server */
+#define FSDETACH 1 /* Detach file server */
+#define FS_SPOOLATTACH 2 /* Register a spooler device */
+#define FS_SPOOLDETACH 3 /* De-register a spooler device */
+
+/* DosFsCtl() */
+/* Routing type */
+#define FSCTL_HANDLE 1 /* File Handle directs req routing */
+#define FSCTL_PATHNAME 2 /* Path Name directs req routing */
+#define FSCTL_FSDNAME 3 /* FSD Name directs req routing */
+
+/* DosQueryFSAttach() */
+/* Information level types (defines method of query) */
+#define FSAIL_QUERYNAME 1 /* Return data for a Drive or Device */
+#define FSAIL_DEVNUMBER 2 /* Return data for Ordinal Device # */
+#define FSAIL_DRVNUMBER 3 /* Return data for Ordinal Drive # */
+
+/* Item types (from data structure item "iType") */
+#define FSAT_CHARDEV 1 /* Resident character device */
+#define FSAT_PSEUDODEV 2 /* Pusedu-character device */
+#define FSAT_LOCALDRV 3 /* Local drive */
+#define FSAT_REMOTEDRV 4 /* Remote drive attached to FSD */
+
+typedef struct _SPOOLATTACH { /* Data structure for spooler operations */
+ USHORT hNmPipe; /* Named pipe handle */
+ ULONG ulKey; /* Attached Key */
+} SPOOLATTACH;
+typedef SPOOLATTACH FAR *PSPOOLATTACH;
+
+
+/*
+ * File System Drive Information&gml DosQueryFSInfo DosSetFSInfo
+ */
+
+/* FS Drive Info Levels */
+#define FSIL_ALLOC 1 /* Drive allocation info (Query only) */
+#define FSIL_VOLSER 2 /* Drive Volume/Serial information */
+
+/* DosQueryFHType() */
+/* Handle classes (low 8 bits of Handle Type) */
+#define FHT_DISKFILE 0x0000 /* Disk file handle */
+#define FHT_CHRDEV 0x0001 /* Character device handle */
+#define FHT_PIPE 0x0002 /* Pipe handle */
+
+/* Handle bits (high 8 bits of Handle Type) */
+#define FHB_DSKREMOTE 0x8000 /* Remote disk */
+#define FHB_CHRDEVREMOTE 0x8000 /* Remote character device */
+#define FHB_PIPEREMOTE 0x8000 /* Remote pipe */
+
+
+//typedef SHANDLE HFILE; /* hf */
+//typedef HFILE FAR *PHFILE;
+
+
+/* File time and date types */
+
+//typedef struct _FTIME { /* ftime */
+// USHORT twosecs : 5;
+// USHORT minutes : 6;
+// USHORT hours : 5;
+//} FTIME;
+//typedef FTIME FAR *PFTIME;
+
+//typedef struct _FDATE { /* fdate */
+// USHORT day : 5;
+// USHORT month : 4;
+// USHORT year : 7;
+//} FDATE;
+//typedef FDATE FAR *PFDATE;
+
+typedef struct _FILEFINDBUF { /* findbuf */
+ FDATE fdateCreation;
+ FTIME ftimeCreation;
+ FDATE fdateLastAccess;
+ FTIME ftimeLastAccess;
+ FDATE fdateLastWrite;
+ FTIME ftimeLastWrite;
+ ULONG cbFile;
+ ULONG cbFileAlloc;
+ USHORT attrFile;
+ UCHAR cchName;
+ CHAR achName[CCHMAXPATHCOMP];
+} FILEFINDBUF;
+typedef FILEFINDBUF FAR *PFILEFINDBUF;
+
+typedef struct _FILEFINDBUF2 { /* findbuf2 */
+ FDATE fdateCreation;
+ FTIME ftimeCreation;
+ FDATE fdateLastAccess;
+ FTIME ftimeLastAccess;
+ FDATE fdateLastWrite;
+ FTIME ftimeLastWrite;
+ ULONG cbFile;
+ ULONG cbFileAlloc;
+ USHORT attrFile;
+ ULONG cbList;
+ UCHAR cchName;
+ CHAR achName[CCHMAXPATHCOMP];
+} FILEFINDBUF2;
+typedef FILEFINDBUF2 FAR *PFILEFINDBUF2;
+
+/* extended attribute structures */
+typedef struct _GEA { /* gea */
+ BYTE cbName; /* name length not including NULL */
+ CHAR szName[1]; /* attribute name */
+} GEA;
+typedef GEA FAR *PGEA;
+
+typedef struct _GEALIST { /* geal */
+ ULONG cbList; /* total bytes of structure inc full list */
+ GEA list[1]; /* variable length GEA structures */
+} GEALIST;
+typedef GEALIST FAR * PGEALIST;
+
+typedef struct _FEA { /* fea */
+ BYTE fEA; /* flags */
+ BYTE cbName; /* name length not including NULL */
+ USHORT cbValue; /* value length */
+} FEA;
+typedef FEA FAR *PFEA;
+
+/* flags for _FEA.fEA */
+
+#define FEA_NEEDEA 0x80 /* need EA bit */
+
+typedef struct _FEALIST { /* feal */
+ ULONG cbList; /* total bytes of structure inc full list */
+ FEA list[1]; /* variable length FEA structures */
+} FEALIST;
+typedef FEALIST FAR * PFEALIST;
+
+typedef struct _EAOP { /* eaop */
+ PGEALIST fpGEAList; /* general EA list */
+ PFEALIST fpFEAList; /* full EA list */
+ ULONG oError;
+} EAOP;
+typedef EAOP FAR * PEAOP;
+
+
+/*
+ * Equates for EA types
+ *
+ * Values 0xFFFE thru 0x8000 are reserved.
+ * Values 0x0000 thru 0x7fff are user definable.
+ * Value 0xFFFC is not used
+ */
+
+#define EAT_BINARY 0xFFFE /* length preceeded binary */
+#define EAT_ASCII 0xFFFD /* length preceeded ASCII */
+#define EAT_BITMAP 0xFFFB /* length preceeded bitmap */
+#define EAT_METAFILE 0xFFFA /* length preceeded metafile */
+#define EAT_ICON 0xFFF9 /* length preceeded icon */
+#define EAT_EA 0xFFEE /* length preceeded ASCII extended attribute */
+ /* name of associated data (#include)*/
+#define EAT_MVMT 0xFFDF /* multi-valued, multi-typed field */
+#define EAT_MVST 0xFFDE /* multi-valued, single-typed field */
+#define EAT_ASN1 0xFFDD /* ASN.1 field */
+
+
+typedef struct _FILESTATUS16 { /* fsts */
+ FDATE fdateCreation;
+ FTIME ftimeCreation;
+ FDATE fdateLastAccess;
+ FTIME ftimeLastAccess;
+ FDATE fdateLastWrite;
+ FTIME ftimeLastWrite;
+ ULONG cbFile;
+ ULONG cbFileAlloc;
+ USHORT attrFile;
+} FILESTATUS16;
+typedef FILESTATUS16 FAR *PFILESTATUS16;
+
+typedef struct _FILESTATUS2_16 { /* fsts2 */
+ FDATE fdateCreation;
+ FTIME ftimeCreation;
+ FDATE fdateLastAccess;
+ FTIME ftimeLastAccess;
+ FDATE fdateLastWrite;
+ FTIME ftimeLastWrite;
+ ULONG cbFile;
+ ULONG cbFileAlloc;
+ USHORT attrFile;
+ ULONG cbList;
+} FILESTATUS2_16;
+typedef FILESTATUS2_16 FAR *PFILESTATUS2_16;
+
+//typedef struct _FSALLOCATE { /* fsalloc */
+// ULONG idFileSystem;
+// ULONG cSectorUnit;
+// ULONG cUnit;
+// ULONG cUnitAvail;
+// USHORT cbSector;
+//} FSALLOCATE;
+//typedef FSALLOCATE FAR *PFSALLOCATE;
+
+//typedef struct _VOLUMELABEL { /* vol */
+// BYTE cch;
+// CHAR szVolLabel[12];
+//} VOLUMELABEL;
+//typedef VOLUMELABEL FAR *PVOLUMELABEL;
+
+//typedef struct _FSINFO { /* fsinf */
+// FDATE fdateCreation;
+// FTIME ftimeCreation;
+// VOLUMELABEL vol;
+//} FSINFO;
+//typedef FSINFO FAR *PFSINFO;
+
+/* HANDTYPE values */
+
+#define HANDTYPE_FILE 0x0000
+#define HANDTYPE_DEVICE 0x0001
+#define HANDTYPE_PIPE 0x0002
+#define HANDTYPE_NETWORK 0x8000
+
+//typedef struct _FILELOCK { /* flock */
+// LONG lOffset;
+// LONG lRange;
+//} FILELOCK;
+//typedef FILELOCK FAR *PFILELOCK;
+
+//typedef SHANDLE HDIR; /* hdir */
+//typedef HDIR FAR *PHDIR;
+
+/* defines for dossetpathinfo -pathinfo flag */
+#define DSPI_WRTTHRU 0x10 /* write through */
+
+typedef struct _DENA1_16
+{ /* _dena1 level 1 info returned from DosEnumAttribute */
+ UCHAR reserved; /* 0 */
+ UCHAR cbName; /* length of name exculding NULL */
+ USHORT cbValue; /* length of value */
+ UCHAR szName[1]; /* variable length asciiz name */
+} DENA1_16;
+typedef DENA1_16 FAR *PDENA1_16;
+
+/* Infolevels for DosEnumAttribute */
+//#define ENUMEA_LEVEL_NO_VALUE 1L /* FEA without value */
+/* Reference types for DosEnumAttribute */
+#define ENUMEA_REFTYPE_FHANDLE 0 /* file handle */
+#define ENUMEA_REFTYPE_PATH 1 /* path name */
+#define ENUMEA_REFTYPE_MAX ENUMEA_REFTYPE_PATH
+
+#endif /* common INCL_DOSFILEMGR */
+
+#if (defined(INCL_DOSMEMMGR) || !defined(INCL_NOCOMMON))
+/*** Memory management */
+
+/* Segment attribute flags (used with DosAllocSeg) */
+
+#define SEG_NONSHARED 0x0000
+#define SEG_GIVEABLE 0x0001
+#define SEG_GETTABLE 0x0002
+#define SEG_DISCARDABLE 0x0004
+#define SEG_SIZEABLE 0x0008
+
+#endif /* common INCL_DOSMEMMGR */
+
+#if (defined(INCL_DOSSEMAPHORES) || !defined(INCL_NOCOMMON))
+
+/*** Semaphore support */
+
+#define SEM_INDEFINITE_WAIT -1L
+#define SEM_IMMEDIATE_RETURN 0L
+
+#endif /* common INCL_DOSSEMAPHORES */
+
+#ifdef INCL_DOSSEMAPHORES
+
+typedef LHANDLE HSYSSEM; /* hssm */
+typedef HSYSSEM FAR *PHSYSSEM;
+
+#define CSEM_PRIVATE 0
+#define CSEM_PUBLIC 1
+
+typedef struct _MUXSEM { /* mxs */
+ USHORT zero;
+ HSEM hsem;
+} MUXSEM;
+typedef MUXSEM FAR *PMUXSEM;
+
+typedef struct _MUXSEMLIST { /* mxsl */
+ USHORT cmxs;
+ MUXSEM amxs[16];
+} MUXSEMLIST;
+typedef MUXSEMLIST FAR *PMUXSEMLIST;
+
+/*
+ * Since a MUXSEMLIST structure is actually a variable length
+ * structure, the following macro may be used to define a MUXSEMLIST
+ * structure having size elements, named "name".
+ */
+#define DEFINEMUXSEMLIST(name, size) \
+ struct { \
+ USHORT cmxs; \
+ MUXSEM amxs[size]; \
+ } name;
+
+
+/*** Fast safe ram semaphores */
+
+typedef struct _DOSFSRSEM { /* dosfsrs */
+ USHORT cb;
+ USHORT pid;
+ USHORT tid;
+ USHORT cUsage;
+ USHORT client;
+ ULONG sem;
+} DOSFSRSEM;
+typedef DOSFSRSEM FAR *PDOSFSRSEM;
+
+
+#endif /* INCL_DOSSEMAPHORES */
+
+
+/*** Module manager */
+
+#ifdef INCL_DOSMODULEMGR
+
+#define PT_16BIT 0L
+#define PT_32BIT 1L
+
+#endif /* INCL_DOSMODULEMGR */
+
+#if (defined(INCL_DOSRESOURCES) || !defined(INCL_NOCOMMON))
+
+/*** Resource support */
+
+/* Predefined resource types */
+
+#define RT_POINTER 1 /* mouse pointer shape */
+#define RT_BITMAP 2 /* bitmap */
+#define RT_MENU 3 /* menu template */
+#define RT_DIALOG 4 /* dialog template */
+#define RT_STRING 5 /* string tables */
+#define RT_FONTDIR 6 /* font directory */
+#define RT_FONT 7 /* font */
+#define RT_ACCELTABLE 8 /* accelerator tables */
+#define RT_RCDATA 9 /* binary data */
+#define RT_MESSAGE 10 /* error mesage tables */
+#define RT_DLGINCLUDE 11 /* dialog include file name */
+#define RT_VKEYTBL 12 /* key to vkey tables */
+#define RT_KEYTBL 13 /* key to UGL tables */
+#define RT_CHARTBL 14
+#define RT_DISPLAYINFO 15 /* screen display information */
+
+#define RT_FKASHORT 16 /* function key area short form */
+#define RT_FKALONG 17 /* function key area long form */
+
+#define RT_HELPTABLE 18 /* Help table for Cary Help manager */
+#define RT_HELPSUBTABLE 19 /* Help subtable for Cary Help manager */
+
+#define RT_FDDIR 20 /* DBCS uniq/font driver directory */
+#define RT_FD 21 /* DBCS uniq/font driver */
+
+#define RT_MAX 22 /* 1st unused Resource Type */
+
+
+#endif /* common INCL_DOSRESOURCES */
+
+
+/*** Signal support */
+
+#ifdef INCL_DOSSIGNALS
+
+/* Signal Numbers for DosSetSigHandler */
+
+#define SIG_CTRLC 1 /* Control C */
+#define SIG_BROKENPIPE 2 /* Broken Pipe */
+#define SIG_KILLPROCESS 3 /* Program Termination */
+#define SIG_CTRLBREAK 4 /* Control Break */
+#define SIG_PFLG_A 5 /* Process Flag A */
+#define SIG_PFLG_B 6 /* Process Flag B */
+#define SIG_PFLG_C 7 /* Process Flag C */
+#define SIG_CSIGNALS 8 /* number of signals plus one */
+
+/* Flag Numbers for DosFlagProcess */
+
+#define PFLG_A 0 /* Process Flag A */
+#define PFLG_B 1 /* Process Flag B */
+#define PFLG_C 2 /* Process Flag C */
+
+/* Signal actions */
+
+#define SIGA_KILL 0
+#define SIGA_IGNORE 1
+#define SIGA_ACCEPT 2
+#define SIGA_ERROR 3
+#define SIGA_ACKNOWLEDGE 4
+
+/* DosHoldSignal constants */
+
+#define HLDSIG_ENABLE 0
+#define HLDSIG_DISABLE 1
+
+/* DosFlagProcess codes */
+
+#define FLGP_SUBTREE 0
+#define FLGP_PID 1
+
+typedef VOID (PASCAL FAR *PFNSIGHANDLER)(USHORT, USHORT);
+
+#endif /* INCL_DOSSIGNALS */
+
+
+/*** Monitor support */
+
+#ifdef INCL_DOSMONITORS
+
+typedef SHANDLE HMONITOR; /* hmon */
+typedef HMONITOR FAR *PHMONITOR;
+
+#endif /* INCL_DOSMONITORS */
+
+
+/*** Pipe and queue support */
+
+#ifdef INCL_DOSQUEUES
+#if (defined(INCL_DOSFILEMGR) || !defined(INCL_NOCOMMON))
+
+#else /* INCL_DOSFILEMGR || !INCL_NOCOMMON */
+#error PHFILE not defined - define INCL_DOSFILEMGR or undefine INCL_NOCOMMON
+#endif /* INCL_DOSFILEMGR || !INCL_NOCOMMON */
+#endif /* INCL_DOSQUEUES */
+
+#ifdef INCL_DOSMISC
+
+/* definitions for DOSSEARCHPATH control word */
+#define DSP_IMPLIEDCUR 1 /* current dir will be searched first */
+#define DSP_PATHREF 2 /* from envirnoment variable */
+#define DSP_IGNORENETERR 4 /* ignore net errs & continue search */
+
+/* definition for DOSQSYSINFO */
+#define Q_MAX_PATH_LENGTH (0) /* index for query max path length */
+
+/* definitions for DosError - combine with | */
+#define FERR_DISABLEHARDERR 0x00000000L /* disable hard error popups */
+#define FERR_ENABLEHARDERR 0x00000001L /* enable hard error popups */
+#define FERR_ENABLEEXCEPTION 0x00000000L /* enable exception popups */
+#define FERR_DISABLEEXCEPTION 0x00000002L /* disable exception popups */
+
+#endif /* INCL_DOSMISC */
+
+
+/*** Session manager support */
+
+#ifdef INCL_DOSSESMGR
+
+#define SSF_RELATED_INDEPENDENT 0
+#define SSF_RELATED_CHILD 1
+
+#define SSF_FGBG_FORE 0
+#define SSF_FGBG_BACK 1
+
+#define SSF_TRACEOPT_NONE 0
+#define SSF_TRACEOPT_TRACE 1
+#define SSF_TRACEOPT_TRACEALL 2
+
+#define SSF_INHERTOPT_SHELL 0
+#define SSF_INHERTOPT_PARENT 1
+
+/* note that these types are identical to those in pmshl.h for PROG_* */
+#define SSF_TYPE_DEFAULT 0
+#define SSF_TYPE_FULLSCREEN 1
+#define SSF_TYPE_WINDOWABLEVIO 2
+#define SSF_TYPE_PM 3
+#define SSF_TYPE_VDM 4
+#define SSF_TYPE_GROUP 5
+#define SSF_TYPE_DLL 6
+#define SSF_TYPE_WINDOWEDVDM 7
+#define SSF_TYPE_PDD 8
+#define SSF_TYPE_VDD 9
+
+/* note that these flags are identical to those in pmshl.h for SHE_* */
+#define SSF_CONTROL_VISIBLE 0x0000
+#define SSF_CONTROL_INVISIBLE 0x0001
+#define SSF_CONTROL_MAXIMIZE 0x0002
+#define SSF_CONTROL_MINIMIZE 0x0004
+#define SSF_CONTROL_NOAUTOCLOSE 0x0008
+#define SSF_CONTROL_SETPOS 0x8000
+
+typedef struct _REGISTERDATA { /* regdata */
+ USHORT Length;
+ USHORT NotifType;
+ PSZ DDName;
+} REGISTERDATA;
+typedef REGISTERDATA FAR *PREGISTERDATA;
+
+#endif /* INCL_DOSSESMGR */
+
+#if (defined(INCL_DOSSESMGR) || defined(INCL_DOSFILEMGR))
+
+/* AppType returned in by DosQueryAppType in pFlags as follows */
+#define FAPPTYP_NOTSPEC 0x0000
+#define FAPPTYP_NOTWINDOWCOMPAT 0x0001
+#define FAPPTYP_WINDOWCOMPAT 0x0002
+#define FAPPTYP_WINDOWAPI 0x0003
+#define FAPPTYP_BOUND 0x0008
+#define FAPPTYP_DLL 0x0010
+#define FAPPTYP_DOS 0x0020
+#define FAPPTYP_PHYSDRV 0x0040 /* physical device driver */
+#define FAPPTYP_VIRTDRV 0x0080 /* virtual device driver */
+#define FAPPTYP_PROTDLL 0x0100 /* 'protected memory' dll */
+#define FAPPTYP_32BIT 0x4000
+#define FAPPTYP_EXETYPE FAPPTYP_WINDOWAPI
+
+#define FAPPTYP_RESERVED ~(FAPPTYP_WINDOWAPI | FAPPTYP_BOUND | FAPPTYP_DLL | FAPPTYP_DOS | FAPPTYP_PHYSDRV | FAPPTYP_VIRTDRV | FAPPTYP_PROTDLL | FAPPTYP_32BIT)
+
+#ifdef INCL_DOSFILEMGR
+
+#define EAT_APPTYP_PMAPI 0x00 /* Uses PM API */
+#define EAT_APPTYP_DOS 0x01 /* DOS APP */
+#define EAT_APPTYP_PMW 0x02 /* Window compatible */
+#define EAT_APPTYP_NOPMW 0x03 /* Not Window compatible */
+#define EAT_APPTYP_EXETYPE 0x03 /* EXE type mask */
+#define EAT_APPTYP_RESERVED ~(EAT_APPTYP_EXETYPE)
+
+#endif /* INCL_DOSFILEMGR */
+
+#endif /* INCL_DOSSESMGR || INCL_DOSFILEMGR */
+
+/*** Device support */
+
+#ifdef INCL_DOSDEVICES
+
+#define DEVINFO_PRINTER 0 /* Number of printers attached */
+#define DEVINFO_RS232 1 /* Number of RS232 ports */
+#define DEVINFO_FLOPPY 2 /* Number of diskette drives */
+#define DEVINFO_COPROCESSOR 3 /* Presence of math coprocessor */
+#define DEVINFO_SUBMODEL 4 /* PC Submodel Type */
+#define DEVINFO_MODEL 5 /* PC Model Type */
+#define DEVINFO_ADAPTER 6 /* Primary display adapter type */
+#define DEVINFO_COPROCESSORTYPE 7 /* Type of coprocessor functionality */
+
+#define INFO_COUNT_PARTITIONABLE_DISKS 1 /* # of partitionable disks */
+#define INFO_GETIOCTLHANDLE 2 /* Obtain handle */
+#define INFO_FREEIOCTLHANDLE 3 /* Release handle */
+
+
+#endif /* INCL_DOSDEVICES */
+
+
+/*** DosNamedPipes API Support */
+
+#ifdef INCL_DOSNMPIPES
+
+typedef struct _AVAILDATA { /* AVAILDATA */
+ USHORT cbpipe; /* bytes left in the pipe */
+ USHORT cbmessage; /* bytes left in current message */
+} AVAILDATA;
+typedef AVAILDATA FAR *PAVAILDATA;
+
+typedef struct _PIPEINFO { /* nmpinf */
+ USHORT cbOut; /* length of outgoing I/O buffer */
+ USHORT cbIn; /* length of incoming I/O buffer */
+ BYTE cbMaxInst; /* maximum number of instances */
+ BYTE cbCurInst; /* current number of instances */
+ BYTE cbName; /* length of pipe name */
+ CHAR szName[1]; /* start of name */
+} PIPEINFO;
+typedef PIPEINFO FAR *PPIPEINFO;
+
+typedef struct _PIPESEMSTATE { /* nmpsmst */
+ BYTE fStatus; /* type of record, 0 = EOI, 1 = read ok, */
+ /* 2 = write ok, 3 = pipe closed */
+ BYTE fFlag; /* additional info, 01 = waiting thread */
+ USHORT usKey; /* user's key value */
+ USHORT usAvail; /* available data/space if status = 1/2 */
+} PIPESEMSTATE;
+typedef PIPESEMSTATE FAR *PPIPESEMSTATE;
+
+#define NP_INDEFINITE_WAIT -1
+#define NP_DEFAULT_WAIT 0L
+
+/* DosPeekNmPipe() pipe states */
+
+#define NP_STATE_DISCONNECTED 0x0001
+#define NP_STATE_LISTENING 0x0002
+#define NP_STATE_CONNECTED 0x0003
+#define NP_STATE_CLOSING 0x0004
+
+/* DosCreateNPipe open modes */
+
+#define NP_ACCESS_INBOUND 0x0000
+#define NP_ACCESS_OUTBOUND 0x0001
+#define NP_ACCESS_DUPLEX 0x0002
+#define NP_INHERIT 0x0000
+#define NP_NOINHERIT 0x0080
+#define NP_WRITEBEHIND 0x0000
+#define NP_NOWRITEBEHIND 0x4000
+
+/* DosCreateNPipe and DosQueryNPHState state */
+
+#define NP_READMODE_BYTE 0x0000
+#define NP_READMODE_MESSAGE 0x0100
+#define NP_TYPE_BYTE 0x0000
+#define NP_TYPE_MESSAGE 0x0400
+#define NP_END_CLIENT 0x0000
+#define NP_END_SERVER 0x4000
+#define NP_WAIT 0x0000
+#define NP_NOWAIT 0x8000
+#define NP_UNLIMITED_INSTANCES 0x00FF
+
+
+/* values in npss_status */
+#define NPSS_EOI 0 /* End Of Information */
+#define NPSS_RDATA 1 /* read data available */
+#define NPSS_WSPACE 2 /* write space available */
+#define NPSS_CLOSE 3 /* pipe in CLOSING state */
+
+/* values in npss_flag */
+#define NPSS_WAIT 0x01 /* waiting thread on end of pipe */
+
+/* defined bits in pipe mode */
+#define NP_NBLK 0x8000 /* non-blocking read/write */
+#define NP_SERVER 0x4000 /* set if server end */
+#define NP_WMESG 0x0400 /* write messages */
+#define NP_RMESG 0x0100 /* read as messages */
+#define NP_ICOUNT 0x00FF /* instance count field */
+
+
+/* Named pipes may be in one of several states depending on the actions
+ * that have been taken on it by the server end and client end. The
+ * following state/action table summarizes the valid state transitions:
+ *
+ * Current state Action Next state
+ *
+ * <none> server DosMakeNmPipe DISCONNECTED
+ * DISCONNECTED server connect LISTENING
+ * LISTENING client open CONNECTED
+ * CONNECTED server disconn DISCONNECTED
+ * CONNECTED client close CLOSING
+ * CLOSING server disconn DISCONNECTED
+ * CONNECTED server close CLOSING
+ * <any other> server close <pipe deallocated>
+ *
+ * If a server disconnects his end of the pipe, the client end will enter a
+ * special state in which any future operations (except close) on the file
+ * descriptor associated with the pipe will return an error.
+ */
+
+/*
+ * Values for named pipe state
+ */
+
+#define NP_DISCONNECTED 1 /* after pipe creation or Disconnect */
+#define NP_LISTENING 2 /* after DosNmPipeConnect */
+#define NP_CONNECTED 3 /* after Client open */
+#define NP_CLOSING 4 /* after Client or Server close */
+
+
+#endif /* INCL_DOSNMPIPES */
+
+
+/*** DosProfile API support */
+
+#ifdef INCL_DOSPROFILE
+
+/* DosProfile ordinal number */
+
+#define PROF_ORDINAL 133
+
+/* DosProfile usType */
+
+#define PROF_SYSTEM 0
+#define PROF_USER 1
+#define PROF_USEDD 2
+#define PROF_KERNEL 4
+#define PROF_VERBOSE 8
+#define PROF_ENABLE 16
+
+/* DosProfile usFunc */
+
+#define PROF_ALLOC 0
+#define PROF_CLEAR 1
+#define PROF_ON 2
+#define PROF_OFF 3
+#define PROF_DUMP 4
+#define PROF_FREE 5
+
+/* DosProfile tic count granularity (DWORD) */
+
+#define PROF_SHIFT 2
+
+/* DosProfile module name string length */
+
+#define PROF_MOD_NAME_SIZE 10
+
+/* DosProfile error code for end of data */
+
+#define PROF_END_OF_DATA 13
+
+#endif /* INCL_DOSPROFILE */
+
+
+/*** Virtual DOS Machine API support */
+
+#ifdef INCL_DOSMVDM
+
+typedef LHANDLE HVDD; /* hvdd */
+typedef HVDD FAR *PHVDD; /* phvdd */
+
+#endif /* INCL_DOSMVDM */
+
+#pragma pack()
+
diff --git a/private/os2/inc/os2v20.h b/private/os2/inc/os2v20.h
new file mode 100644
index 000000000..d7502db71
--- /dev/null
+++ b/private/os2/inc/os2v20.h
@@ -0,0 +1,2582 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2v20.h
+
+Abstract:
+
+ This file contains the OS/2 V2.0 API calls exported by the OS/2 Subsystem
+
+Author:
+
+ Steve Wood (stevewo) 19-Sep-1989
+
+Parameters:
+
+ This header file uses the following symbols names to control how much
+ of the header file is include. They are:
+
+ INCL_OS2V20_TASKING
+ INCL_OS2V20_FILESYS
+ INCL_OS2V20_FSD
+ INCL_OS2V20_MEMORY
+ INCL_OS2V20_SEMAPHORES
+ INCL_OS2V20_TIMERS
+ INCL_OS2V20_LOADER
+ INCL_OS2V20_NLS
+ INCL_OS2V20_EXCEPTIONS
+ INCL_OS2V20_ERRORMSG
+ INCL_OS2V20_SESSIONMGR
+ INCL_OS2V20_DEVICE_SUPPORT
+ INCL_OS2V20_PIPES
+ INCL_OS2V20_QUEUES
+ INCL_OS2V20_ERRORS
+
+Revision History:
+
+--*/
+
+#ifndef _NTDEF__
+#include <nt.h>
+#endif // _NTDEF_
+
+#ifdef FILE_CREATED
+#undef FILE_CREATED // Fortunately NT and OS/2 2.0 both use 0x2 for this
+#endif // FILE_CREATED
+
+#ifdef INCL_OS2V20_ALL
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_FSD
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_TIMERS
+#define INCL_OS2V20_LOADER
+#define INCL_OS2V20_NLS
+#define INCL_OS2V20_EXCEPTIONS
+#define INCL_OS2V20_ERRORMSG
+#define INCL_OS2V20_SESSIONMGR
+#define INCL_OS2V20_DEVICE_SUPPORT
+#define INCL_OS2V20_PIPES
+#define INCL_OS2V20_QUEUES
+#define INCL_OS2V20_ERRORS
+#endif // INCL_OS2V20_ALL
+
+#define APIRET ULONG
+typedef APIRET *PAPIRET;
+
+typedef HANDLE HMODULE, *PHMODULE;
+typedef HANDLE PID, *PPID;
+typedef HANDLE TID, *PTID;
+typedef HANDLE HFILE, *PHFILE;
+typedef HANDLE HDIR, *PHDIR;
+typedef HANDLE HTIMER, *PHTIMER;
+typedef HANDLE HQUEUE, *PHQUEUE;
+typedef HANDLE HPIPE, *PHPIPE;
+typedef HANDLE HSEM, *PHSEM;
+typedef HANDLE HMTX, *PHMTX;
+typedef HANDLE HEV, *PHEV;
+typedef HANDLE HMUX, *PHMUX;
+
+typedef UCHAR BYTE, *PBYTE;
+
+typedef ULONG BOOL32, *PBOOL32;
+
+typedef int (*PFN)();
+
+/* Tasking API Calls */
+
+/* Process Information Block */
+
+
+typedef struct _PIB {
+ /* Warning: when adding fields here (which are updated by the server),
+ add them to sesport.h in SCREQ_CREATE */
+ PID ProcessId; /* Process I.D. */
+ PID ParentProcessId; /* Parent process I.D. */
+ HMODULE ImageFileHandle; /* Program (.EXE) module handle */
+ PCHAR CommandLine; /* Command line pointer */
+ PCHAR Environment; /* Environment pointer */
+ ULONG Status; /* Process Status */
+ ULONG Type; /* Process Type */
+ ULONG Killed; /* True if Process was killed */
+ ULONG SyncOwner; /* Thread Id of the thread owner SyncSem */
+ ULONG Saved32Esp; /* Last top of stack in 32bit */
+ BOOLEAN SigHandInProgress; /* Signal handler in progress */
+ BOOLEAN SignalWasntDelivered; /* The signal wasn't delivered, yet */
+} PIB, *PPIB;
+
+/* Process Type codes (Type field) */
+
+#define PT_FULLSCREEN 0 /* Full screen app. */
+#define PT_REALMODE 1 /* Real mode process */
+#define PT_WINDOWABLEVIO 2 /* VIO windowable app. */
+#define PT_PM 3 /* Presentation Manager app. */
+#define PT_DETACHED 4 /* Detached app. */
+
+/* Process Status Flag definitions (Status field) */
+
+#define PS_EXITLIST 1 /* Thread is in exitlist routine */
+
+typedef APIRET (*PFNPROCESS)( PPEB Peb );
+
+#pragma pack(1)
+typedef struct _LOCALINFOSEG { /* lis */
+ USHORT pidCurrent;
+ USHORT pidParent;
+ USHORT prtyCurrent;
+ USHORT tidCurrent;
+ USHORT sgCurrent;
+ UCHAR rfProcStatus;
+ UCHAR dummy1;
+ USHORT fForeground;
+ UCHAR typeProcess;
+ UCHAR dummy2;
+ USHORT selEnvironment;
+ USHORT offCmdLine;
+ USHORT cbDataSegment;
+ USHORT cbStack;
+ USHORT cbHeap;
+ USHORT hmod;
+ USHORT selDS;
+// UCHAR dummy3;
+ USHORT dummy5;
+ ULONG tebptr;
+ ULONG IsRealTEB; // in 16 bit this will always be zero. in 32bit will always be non-zero (ClientId)
+} LOCALINFOSEG;
+
+#pragma pack()
+
+typedef struct _OS2_TIB {
+ /* Warning: when adding fields here (which are updated by the server),
+ add them to sesport.h in SCREQ_CREATE */
+ ULONG ThreadId; /* OS/2 ID for the thread */
+ ULONG Priority; /* Thread priority */
+ ULONG Version; /* Version number for this structure */
+ USHORT MustCompleteCount;
+ USHORT MustCompleteForceFlag; /* Used by DosSuspend(Resume)Thread and
+ * DosEnter(Exit)CritSec APIs. See possible values below
+ */
+ LOCALINFOSEG LInfoSeg;
+ /* WARNING: The following filed must follow immediately the previous one */
+ /* Refer to client\i386\dllthunk\MoveInfoSegintoTeb and RestoreTeb */
+ LOCALINFOSEG TebBackupIn16Bit; /* This field holds the TEB info when app runs in */
+ /* 16 bits (LOCALINFOSEG type is for the size only) */
+} OS2_TIB, *POS2_TIB;
+//
+// The bits of MustCompleteForceFlag in TIB:
+//
+#define MCF_SUSPENDED 1 // Was suspended by DosSuspendThread
+#define MCF_IN32BIT 2 // The thread is in 32 bit context (between 16->32 and
+ // 32->16 thunks)
+#define MCF_FROZEN 4
+#define MCF_SUSPENDED_AND_FROZEN 8
+
+typedef APIRET (*PFNTHREAD)( ULONG Parameter );
+
+typedef VOID (*PFNEXITLIST)( ULONG ExitReason );
+
+typedef struct _RESULTCODES {
+ ULONG ExitReason;
+ ULONG ExitResult;
+} RESULTCODES, *PRESULTCODES;
+
+typedef struct _FTIME {
+ USHORT twosecs : 5;
+ USHORT minutes : 6;
+ USHORT hours : 5;
+} FTIME, *PFTIME;
+
+typedef struct _FDATE {
+ USHORT day : 5;
+ USHORT month : 4;
+ USHORT year : 7;
+} FDATE, *PFDATE;
+
+typedef struct _FDATETIME {
+ FDATE date;
+ FTIME time;
+} FDATETIME, *PFDATETIME;
+
+typedef struct _FILESTATUS {
+ FDATE fdateCreation;
+ FTIME ftimeCreation;
+ FDATE fdateLastAccess;
+ FTIME ftimeLastAccess;
+ FDATE fdateLastWrite;
+ FTIME ftimeLastWrite;
+ ULONG cbFile;
+ ULONG cbFileAlloc;
+ ULONG attrFile;
+} FILESTATUS, *PFILESTATUS;
+
+typedef struct _FILESTATUS2 {
+ FDATE fdateCreation;
+ FTIME ftimeCreation;
+ FDATE fdateLastAccess;
+ FTIME ftimeLastAccess;
+ FDATE fdateLastWrite;
+ FTIME ftimeLastWrite;
+ ULONG cbFile;
+ ULONG cbFileAlloc;
+ ULONG attrFile;
+ ULONG cbList;
+} FILESTATUS2, *PFILESTATUS2;
+
+/*
+ * CCHMAXPATH is the maximum fully qualified path name length including
+ * the drive letter, colon, backslashes and terminating NULL.
+ */
+#define CCHMAXPATH 260
+
+/*
+ * CCHMAXPATH is the maximum fully qualified path name length including
+ * the drive letter, colon, backslashes and terminating NULL.
+ */
+#define CCHMAXCOMP 255
+
+/*
+ * CCHMAXPATHCOMP is the maximum individual path component name length
+ * including a terminating NULL.
+ */
+#define CCHMAXPATHCOMP 256
+
+typedef struct _FILEFINDBUF3 {
+ ULONG oNextEntryOffset;
+ FDATE fdateCreation;
+ FTIME ftimeCreation;
+ FDATE fdateLastAccess;
+ FTIME ftimeLastAccess;
+ FDATE fdateLastWrite;
+ FTIME ftimeLastWrite;
+ ULONG cbFile;
+ ULONG cbFileAlloc;
+ ULONG attrFile;
+ UCHAR cchName;
+ CHAR achName[CCHMAXPATHCOMP];
+} FILEFINDBUF3, *PFILEFINDBUF3;
+
+typedef struct _FILEFINDBUF4 {
+ ULONG oNextEntryOffset;
+ FDATE fdateCreation;
+ FTIME ftimeCreation;
+ FDATE fdateLastAccess;
+ FTIME ftimeLastAccess;
+ FDATE fdateLastWrite;
+ FTIME ftimeLastWrite;
+ ULONG cbFile;
+ ULONG cbFileAlloc;
+ ULONG attrFile;
+ ULONG cbList;
+ UCHAR cchName;
+ CHAR achName[CCHMAXPATHCOMP];
+} FILEFINDBUF4, *PFILEFINDBUF4;
+
+/* extended attribute structures */
+
+typedef struct _GEA2 {
+ ULONG oNextEntryOffset; /* offset to next GEA */
+ BYTE cbName; /* name length not including NULL */
+ CHAR szName[1]; /* attribute name */
+} GEA2, *PGEA2;
+
+typedef struct _GEA2LIST {
+ ULONG cbList; /* total bytes of structure including full list */
+ GEA2 list[1]; /* variable length GEA structures */
+} GEA2LIST, *PGEA2LIST;
+
+typedef struct _FEA2 {
+ ULONG oNextEntryOffset; /* offset to next FEA */
+ BYTE fEA; /* flags */
+ BYTE cbName; /* name length not including NULL */
+ USHORT cbValue; /* value length */
+ CHAR szName[1]; /* attribute name */
+} FEA2, *PFEA2;
+
+/* flags for _FEA.fEA */
+
+#define FEA_NEEDEA 0x80 /* need EA bit */
+
+typedef struct _FEA2LIST {
+ ULONG cbList; /* total bytes of structure including full list */
+ FEA2 list[1]; /* variable length FEA structures */
+} FEA2LIST, *PFEA2LIST;
+
+typedef struct _EAOP2 {
+ PGEA2LIST fpGEA2List; /* general EA list */
+ PFEA2LIST fpFEA2List; /* full EA list */
+ ULONG oError;
+} EAOP2, *PEAOP2;
+
+#define ULONG_MASK ~3
+#define RoundUpToUlong(number) ((number+(sizeof(ULONG)-1)) & ULONG_MASK)
+
+/*
+ * The following macros can be used to calculate the size of the current FEA
+ * and the offset of the next FEA
+ *
+ */
+
+#define FEA_sizeof(fea) (sizeof(FEA2)+(fea).cbName+1+(fea).cbValue)
+#define FEA_oNextEntryOffset(fea) (RoundUpToUlong(FEA_sizeof(fea))
+
+/*
+ * The following macros can be used to access the fea_szName and
+ * fea_aValue fields in a given FEA.
+ *
+ */
+
+#define FEA_szNameFromFEA(fea) (((PCHAR)&(fea))+sizeof(FEA2))
+#define FEA_AValueFromFEA(fea) (((PCHAR)&(fea))+sizeof(FEA2)+(fea).cbName+1)
+
+typedef struct _FILELOCK {
+ LONG lOffset;
+ LONG lRange;
+} FILELOCK, *PFILELOCK;
+
+typedef struct _FSQBUFFER {
+ USHORT iType; /* Item type */
+ USHORT cbName; /* Length of item name, sans NULL */
+ UCHAR szName[1]; /* ASCIIZ item name */
+ USHORT cbFSDName; /* Length of FSD name, sans NULL */
+ UCHAR szFSDName[1]; /* ASCIIZ FSD name */
+ USHORT cbFSAData; /* Length of FSD Attach data returned */
+ UCHAR rgFSAData[1]; /* FSD Attach data from FSD */
+} FSQBUFFER, *PFSQBUFFER;
+
+typedef struct _PSEMRECORD {
+ HSEM hsemCur;
+ ULONG ulUser;
+} SEMRECORD, *PSEMRECORD;
+
+#define DC_SEM_NAMEPREFIX "\\SEM32\\"
+
+#define DCMW_MAX_SEMRECORDS 64 /* DosCreateMuxWait limit on the */
+ /* CountMuxWaitEntries parameter */
+
+
+typedef struct _DATETIME {
+ UCHAR hours;
+ UCHAR minutes;
+ UCHAR seconds;
+ UCHAR hundredths;
+ UCHAR day;
+ UCHAR month;
+ USHORT year;
+ SHORT timezone;
+ UCHAR weekday;
+} DATETIME, *PDATETIME;
+
+typedef struct _STARTDATA {
+ USHORT Length;
+ USHORT Related;
+ USHORT FgBg;
+ USHORT TraceOpt;
+ PSZ PgmTitle;
+ PSZ PgmName;
+ PBYTE PgmInputs;
+ PBYTE TermQ;
+ PBYTE Environment;
+ USHORT InheritOpt;
+ USHORT SessionType;
+ PSZ IconFile;
+ ULONG PgmHandle;
+ USHORT PgmControl;
+ USHORT InitXPos;
+ USHORT InitYPos;
+ USHORT InitXSize;
+ USHORT InitYSize;
+ USHORT Reserved;
+ PSZ ObjectBuffer;
+ ULONG ObjectBuffLen;
+} STARTDATA, *PSTARTDATA;
+
+#define SSF_RELATED_INDEPENDENT 0
+#define SSF_RELATED_CHILD 1
+
+#define SSF_FGBG_FORE 0
+#define SSF_FGBG_BACK 1
+
+#define SSF_TRACEOPT_NONE 0
+#define SSF_TRACEOPT_TRACE 1
+#define SSF_TRACEOPT_TRACEALL 2
+
+#define SSF_INHERTOPT_SHELL 0
+#define SSF_INHERTOPT_PARENT 1
+
+/* note that these types are identical to those in pmshl.h for PROG_* */
+#define SSF_TYPE_DEFAULT 0
+#define SSF_TYPE_FULLSCREEN 1
+#define SSF_TYPE_WINDOWABLEVIO 2
+#define SSF_TYPE_PM 3
+#define SSF_TYPE_VDM 4
+#define SSF_TYPE_GROUP 5
+#define SSF_TYPE_DLL 6
+#define SSF_TYPE_WINDOWEDVDM 7
+#define SSF_TYPE_PDD 8
+#define SSF_TYPE_VDD 9
+
+/* note that these flags are identical to those in pmshl.h for SHE_* */
+#define SSF_CONTROL_VISIBLE 0x0000
+#define SSF_CONTROL_INVISIBLE 0x0001
+#define SSF_CONTROL_MAXIMIZE 0x0002
+#define SSF_CONTROL_MINIMIZE 0x0004
+#define SSF_CONTROL_NOAUTOCLOSE 0x0008
+#define SSF_CONTROL_SETPOS 0x8000
+
+#pragma pack(1)
+typedef struct _STATUSDATA {
+ USHORT Length;
+ USHORT SelectInd;
+ USHORT BondInd;
+} STATUSDATA, *PSTATUSDATA;
+#pragma pack()
+
+/* STATUSDATA.SelectInd constants */
+
+#define TARGET_UNCHANGED 0x0000
+#define TARGET_SELECTABLE 0x0001
+#define TARGET_NOT_SELECTABLE 0x0002
+
+/* STATUSDATA.BondInd constants */
+
+#define BOND_UNCHANGED 0x0000
+#define BOND_CHILD 0x0001
+#define BOND_NONE 0x0002
+
+typedef struct _REQUESTDATA {
+ PID SenderProcessId;
+ ULONG SenderData;
+} REQUESTDATA, *PREQUESTDATA;
+
+#ifdef INCL_OS2V20_TASKING
+
+APIRET
+DosCreateThread(
+ OUT PTID ThreadId,
+ IN PFNTHREAD StartAddress,
+ IN ULONG Parameter,
+ IN ULONG Flags,
+ IN ULONG StackSize
+ );
+
+/* Flags parameter values */
+
+#define DCT_RUNABLE 0 // Create thread in a runable state
+ // allocate low thread ID (1,2,..n)
+#define DCT_SUSPENDED 1 // Create thread in a suspened state
+#ifdef PMNT
+#define DCT_RUNABLE_HIDDEN 2 // Create thread in a runable state and
+#endif // allocate high thread ID (53, 52..)
+
+#define DCT_ATTACHED 4 // Created from Win32 thread
+
+APIRET
+DosResumeThread(
+ IN TID ThreadId
+ );
+
+APIRET
+DosSuspendThread(
+ IN TID ThreadId
+ );
+
+APIRET
+DosGetThreadInfo(
+ OUT PNT_TIB *ThreadInfo,
+ OUT PPIB *ProcessInfo
+ );
+
+APIRET
+DosGetProcessInfo(
+ OUT PPIB *ProcessInfo
+ );
+
+VOID
+DosExit(
+ IN ULONG ExitAction,
+ IN ULONG ExitResult
+ );
+
+#define EXIT_THREAD 0
+#define EXIT_PROCESS 1
+
+/* ExitReason values (also passed to ExitList routines) */
+
+#define TC_EXIT 0
+#define TC_HARDERROR 1
+#define TC_TRAP 2
+#define TC_KILLPROCESS 3
+
+/* Wait target values */
+
+#define DCWA_PROCESS 0
+#define DCWA_PROCESSTREE 1
+
+/* Wait option values */
+
+#define DCWW_WAIT 0
+#define DCWW_NOWAIT 1
+
+APIRET
+DosWaitChild(
+ IN ULONG WaitTarget,
+ IN ULONG WaitOption,
+ OUT PRESULTCODES ResultCodes,
+ OUT PPID ResultProcessId,
+ IN PID ProcessId
+ );
+
+APIRET
+DosWaitThread(
+ IN OUT PTID ThreadId,
+ IN ULONG WaitOption
+ );
+
+APIRET
+DosEnterCritSec( VOID );
+
+APIRET
+DosExitCritSec( VOID );
+
+APIRET
+DosSleep(
+ IN ULONG MilliSeconds
+ );
+
+APIRET
+DosExecPgm(
+ OUT PSZ ErrorText,
+ IN LONG ErrorTextMaximumLength,
+ IN ULONG Flags,
+ IN PSZ Arguments OPTIONAL,
+ IN PSZ Variables OPTIONAL,
+ OUT PRESULTCODES ResultCodes,
+ IN PSZ ImageFileName
+ );
+
+/* DosExecPgm Flags parameter values */
+
+#define EXEC_SYNC 0
+#define EXEC_ASYNC 1
+#define EXEC_ASYNCRESULT 2
+#define EXEC_TRACE 3
+#define EXEC_BACKGROUND 4
+#define EXEC_FROZEN 5
+#define EXEC_TRACETREE 6
+
+APIRET
+Od2ExitList(
+ ULONG OrderCode,
+ PFNEXITLIST ExitRoutine,
+ BOOLEAN flag
+ );
+
+APIRET
+DosExitList(
+ ULONG OrderCode,
+ PFNEXITLIST ExitRoutine
+ );
+
+APIRET
+Dos16ExitList(
+ ULONG OrderCode,
+ PFNEXITLIST ExitRoutine
+ );
+
+/* DosExitList functions */
+
+#define EXLST_ADD 1
+#define EXLST_REMOVE 2
+#define EXLST_EXIT 3
+
+APIRET
+DosKillProcess(
+ IN ULONG KillTarget,
+ IN PID ProcessId
+ );
+
+#define DKP_PROCESSTREE 0
+#define DKP_PROCESS 1
+
+APIRET
+DosSetPriority(
+ IN ULONG Scope,
+ IN ULONG Class,
+ IN LONG Delta,
+ IN ULONG TargetId
+ );
+
+/* Priority scopes */
+
+#define PRTYS_PROCESS 0
+#define PRTYS_PROCESSTREE 1
+#define PRTYS_THREAD 2
+
+/* Priority classes */
+
+#define PRTYC_NOCHANGE 0
+#define PRTYC_IDLETIME 1
+#define PRTYC_REGULAR 2
+#define PRTYC_TIMECRITICAL 3
+#define PRTYC_FOREGROUNDSERVER 4
+
+/* Priority deltas */
+
+#define PRTYD_MINIMUM -31
+#define PRTYD_MAXIMUM 31
+
+
+APIRET
+DosSetDefaultDisk(
+ IN ULONG DiskNumber
+ );
+
+APIRET
+DosQueryCurrentDisk(
+ OUT PULONG DiskNumber,
+ OUT PULONG LogicalDrives
+ );
+
+APIRET
+DosSetCurrentDir(
+ IN PSZ DirectoryName
+ );
+
+APIRET
+DosQueryCurrentDir(
+ IN ULONG DiskNumber,
+ OUT PSZ DirectoryName,
+ IN OUT PULONG DirectoryNameLength
+ );
+
+APIRET
+DosQueryVerify(
+ OUT PBOOL32 Verify
+ );
+
+APIRET
+DosSetVerify(
+ IN BOOL32 Verify
+ );
+
+APIRET
+DosSetMaxFH(
+ IN ULONG MaxFileHandles
+ );
+
+APIRET
+DosScanEnv(
+ IN PSZ VariableName,
+ OUT PSZ *VariableValue
+ );
+
+APIRET
+DosSearchPath(
+ IN ULONG SearchFlags,
+ IN PSZ PathOrVariableName,
+ IN PSZ FileName,
+ OUT PBYTE Buffer,
+ IN ULONG Length
+ );
+
+/* DosSearchPath() constants */
+
+#define SEARCH_PATH 0x0000
+#define SEARCH_CUR_DIRECTORY 0x0001
+#define SEARCH_ENVIRONMENT 0x0002
+#define SEARCH_IGNORENETERRS 0x0004
+
+/* definitions for DosSearchPath control word */
+#define DSP_IMPLIEDCUR 1 /* current dir will be searched first */
+#define DSP_PATHREF 2 /* from env.variable */
+#define DSP_IGNORENETERR 4 /* ignore net errs & continue search */
+
+#endif // INCL_OS2V20_TASKING
+
+
+#ifdef INCL_OS2V20_FILESYS
+
+/* File System API Calls */
+
+/*** File System */
+
+/* File info levels: All listed API's */
+#define FIL_STANDARD 1 /* Info level 1, standard file info */
+#define FIL_QUERYEASIZE 2 /* Level 2, return Full EA size */
+#define FIL_QUERYEASFROMLIST 3 /* Level 3, return requested EA's */
+#define FIL_QUERYALLEAS 4 /* Level 4, return all EAs NOT SUPPORTED */
+/* File info levels: Dos32...PathInfo only */
+#define FIL_QUERYFULLNAME 5 /* Level 5, return fully qualified
+ name of file */
+#define FIL_NAMEISVALID 6 /* Level 6, check validity of file/path
+ name for this FSD */
+
+#define FIL_SETEAS 2 /* Level 2, set EAs */
+
+#define MAXQFILEINFOLEVEL FIL_QUERYEASFROMLIST // level 4 is invalid
+#define MAXSETFILEINFOLEVEL FIL_SETEAS
+#define MAXQPATHINFOLEVEL FIL_NAMEISVALID // level 4 is invalid
+#define MAXSETPATHINFOLEVEL FIL_SETEAS
+#define MAXFINDINFOLEVEL FIL_QUERYEASFROMLIST
+
+/* File time and date types */
+
+/*
+ * Equates for the types of EAs that follow the convention that we have
+ * established.
+ *
+ * Values 0xFFFE thru 0x8000 are reserved.
+ * Values 0x0000 thru 0x7fff are user definable.
+ * Value 0xFFFC is not used
+ */
+
+#define EAT_BINARY 0xFFFE /* length preceeded binary */
+#define EAT_ASCII 0xFFFD /* length preceeded ASCII */
+#define EAT_BITMAP 0xFFFB /* length preceeded bitmap */
+#define EAT_METAFILE 0xFFFA /* length preceeded metafile */
+#define EAT_ICON 0xFFF9 /* length preceeded icon */
+#define EAT_EA 0xFFEE /* length preceeded ASCII */
+ /* name of associated data (#include) */
+#define EAT_MVMT 0xFFDF /* multi-valued, multi-typed field */
+#define EAT_MVST 0xFFDE /* multi-valued, single-typed field */
+#define EAT_ASN1 0xFFDD /* ASN.1 field */
+
+
+APIRET
+DosOpen(
+ IN PSZ FileName,
+ OUT PHFILE FileHandle,
+ OUT PULONG ActionTaken,
+ IN ULONG CreateSize,
+ IN ULONG FileAttribute,
+ IN ULONG OpenFlags,
+ IN ULONG OpenMode,
+ IN OUT PEAOP2 ExtendedFileAttr OPTIONAL
+ );
+
+/* DosOpen/DosQueryFHState/DosQueryFileInfo et al file attributes; also */
+/* known as Dos File Mode bits... */
+#define FILE_READONLY 0x0001
+#define FILE_HIDDEN 0x0002
+#define FILE_SYSTEM 0x0004
+#define FILE_DIRECTORY 0x0010
+#define FILE_ARCHIVED 0x0020
+
+#define ATTR_CHANGEABLE (FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_ARCHIVED)
+#define ATTR_ALL (FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY | FILE_ARCHIVED)
+#define ATTR_NOT_NORM 0x8000 // do not find normal files
+
+/* DosOpen() actions */
+
+#define FILE_EXISTED 0x0001
+#define FILE_CREATED 0x0002
+#define FILE_TRUNCATED 0x0003
+
+/* DosOpen() open flags */
+#define FILE_OPEN_EXISTING_FILE 0x0001
+#define FILE_TRUNCATE_EXISTING_FILE 0x0002
+#define FILE_CREATE_NEW_FILE 0x0010
+
+/* this nibble applies if file already exists xxxx */
+
+#define OPEN_ACTION_FAIL_IF_EXISTS 0x0000 /* ---- ---- ---- 0000 */
+#define OPEN_ACTION_OPEN_IF_EXISTS 0x0001 /* ---- ---- ---- 0001 */
+#define OPEN_ACTION_REPLACE_IF_EXISTS 0x0002 /* ---- ---- ---- 0010 */
+
+/* this nibble applies if file does not exist xxxx */
+
+#define OPEN_ACTION_FAIL_IF_NEW 0x0000 /* ---- ---- 0000 ---- */
+#define OPEN_ACTION_CREATE_IF_NEW 0x0010 /* ---- ---- 0001 ---- */
+
+#define OPEN_ACTION_RESERVED 0xFFEC
+
+/* DosOpen/DosSetFHState flags */
+
+#define OPEN_ACCESS_READONLY 0x00000000 /* ---- ---- ---- -000 */
+#define OPEN_ACCESS_WRITEONLY 0x00000001 /* ---- ---- ---- -001 */
+#define OPEN_ACCESS_READWRITE 0x00000002 /* ---- ---- ---- -010 */
+#define OPEN_SHARE_DENYREADWRITE 0x00000010 /* ---- ---- -001 ---- */
+#define OPEN_SHARE_DENYWRITE 0x00000020 /* ---- ---- -010 ---- */
+#define OPEN_SHARE_DENYREAD 0x00000030 /* ---- ---- -011 ---- */
+#define OPEN_SHARE_DENYNONE 0x00000040 /* ---- ---- -100 ---- */
+#define OPEN_FLAGS_NOINHERIT 0x00000080 /* ---- ---- 1--- ---- */
+#define OPEN_FLAGS_NO_LOCALITY 0x00000000 /* ---- -000 ---- ---- */
+#define OPEN_FLAGS_SEQUENTIAL 0x00000100 /* ---- -001 ---- ---- */
+#define OPEN_FLAGS_RANDOM 0x00000200 /* ---- -010 ---- ---- */
+#define OPEN_FLAGS_RANDOMSEQUENTIAL 0x00000300 /* ---- -011 ---- ---- */
+#define OPEN_FLAGS_NO_CACHE 0x00001000 /* ---1 ---- ---- ---- */
+#define OPEN_FLAGS_FAIL_ON_ERROR 0x00002000 /* --1- ---- ---- ---- */
+#define OPEN_FLAGS_WRITE_THROUGH 0x00004000 /* -1-- ---- ---- ---- */
+#define OPEN_FLAGS_DASD 0x00008000 /* 1--- ---- ---- ---- */
+
+#define ACCESS_FLAGS (OPEN_ACCESS_READONLY | OPEN_ACCESS_WRITEONLY | \
+ OPEN_ACCESS_READWRITE)
+#define SHARE_FLAGS (OPEN_SHARE_DENYREADWRITE | OPEN_SHARE_DENYWRITE | \
+ OPEN_SHARE_DENYREAD | OPEN_SHARE_DENYNONE)
+#define QFHSTATE_FLAGS (OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_WRITE_THROUGH | \
+ OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE | \
+ ACCESS_FLAGS | SHARE_FLAGS)
+#define SETFHSTATE_FLAGS (OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_WRITE_THROUGH | \
+ OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE)
+#define OPEN_RESERVED ~(OPEN_ACCESS_READONLY | OPEN_ACCESS_WRITEONLY | \
+ OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE | \
+ OPEN_SHARE_DENYWRITE | OPEN_SHARE_DENYREAD | \
+ OPEN_SHARE_DENYNONE | OPEN_FLAGS_NOINHERIT | \
+ OPEN_FLAGS_NO_LOCALITY | OPEN_FLAGS_SEQUENTIAL | \
+ OPEN_FLAGS_RANDOM | OPEN_FLAGS_RANDOMSEQUENTIAL | \
+ OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_FAIL_ON_ERROR | \
+ OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_DASD)
+
+
+#define LOCALITY_FLAGS (OPEN_FLAGS_NO_LOCALITY | OPEN_FLAGS_SEQUENTIAL | \
+ OPEN_FLAGS_RANDOM | OPEN_FLAGS_RANDOMSEQUENTIAL)
+
+APIRET
+DosClose(
+ IN HFILE FileHandle
+ );
+
+APIRET
+DosRead(
+ IN HFILE FileHandle,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesRead
+ );
+
+APIRET
+DosWrite(
+ IN HFILE FileHandle,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG BytesWritten
+ );
+
+APIRET
+DosDelete(
+ IN PSZ FileName
+ );
+
+
+APIRET
+DosDupHandle(
+ IN HFILE OldFileHandle,
+ IN OUT PHFILE NewFileHandle
+ );
+
+#define DDH_NEW_HANDLE -1
+
+APIRET
+DosQueryFHState(
+ IN HFILE FileHandle,
+ OUT PULONG OpenMode
+ );
+
+APIRET
+DosSetFHState(
+ IN HFILE FileHandle,
+ IN ULONG OpenMode
+ );
+
+APIRET
+DosQueryHType(
+ IN HFILE FileHandle,
+ OUT PULONG HandleType,
+ OUT PULONG DeviceFlags
+ );
+
+/* DosQueryHType() */
+/* Handle classes (low 8 bits of Handle Type) */
+#define FHT_DISKFILE 0x0000 /* Disk file handle */
+#define FHT_CHRDEV 0x0001 /* Character device handle */
+#define FHT_PIPE 0x0002 /* Pipe handle */
+
+/* Handle bits (high 8 bits of Handle Type) */
+#define FHB_DSKREMOTE 0x8000 /* Remote disk */
+#define FHB_CHRDEVREMOTE 0x8000 /* Remote character device */
+#define FHB_PIPEREMOTE 0x8000 /* Remote pipe */
+
+#define HANDTYPE_FILE 0x0000
+#define HANDTYPE_DEVICE 0x0001
+#define HANDTYPE_PIPE 0x0002
+#define HANDTYPE_NETWORK 0x8000
+
+APIRET
+DosFindFirst(
+ IN PSZ FileName,
+ IN OUT PHDIR DirectoryHandle,
+ IN ULONG FileAttributes,
+ IN PFILEFINDBUF3 Buffer,
+ IN ULONG Length,
+ IN OUT PULONG CountEntriesFound,
+ IN ULONG FileInformationLevel
+ );
+
+APIRET
+DosFindNext(
+ IN HDIR DirectoryHandle,
+ IN PFILEFINDBUF3 Buffer,
+ IN ULONG Length,
+ IN OUT PULONG CountEntriesFound
+ );
+
+/* DosFindFirst/Next Directory handle types */
+
+#define HDIR_SYSTEM 1 /* Use system handle (1) */
+#define HDIR_CREATE -1 /* Allocate a new, unused handle */
+
+APIRET
+DosFindClose(
+ IN HDIR DirectoryHandle
+ );
+
+APIRET
+DosSetFileSize(
+ IN HFILE FileHandle,
+ IN ULONG NewFileSize
+ );
+
+APIRET
+DosResetBuffer(
+ IN HFILE FileHandle
+ );
+
+#define FLUSH_ALL -1 // Flush buffers for all of process's handles
+
+APIRET
+DosSetFilePtr(
+ IN HFILE FileHandle,
+ IN LONG StartingFilePosition,
+ IN ULONG NewFilePosition,
+ IN OUT PULONG CurrentFilePosition
+ );
+
+/* DosSetFilePtr() file position codes */
+
+#define FILE_BEGIN 0x0000 /* Move relative to beginning of file */
+#define FILE_CURRENT 0x0001 /* Move relative to current fptr position */
+#define FILE_END 0x0002 /* Move relative to end of file */
+
+APIRET
+DosSetFileLocks(
+ IN HFILE FileHandle,
+ IN PFILELOCK UnlockRequest,
+ IN PFILELOCK LockRequest
+ );
+
+APIRET
+DosMove(
+ IN PSZ OldFileName,
+ IN PSZ NewFileName
+ );
+
+APIRET
+DosCopy(
+ IN PSZ OldFileName,
+ IN PSZ NewFileName,
+ IN ULONG CopyOption
+ );
+
+/* DosCopy option bits; may be or'ed together */
+
+#define DCPY_EXISTING 0x00001 /* Copy even if target exists */
+#define DCPY_APPEND 0x00002 /* Append to existing file, do not replace */
+#define DCPY_EA_FAIL_COPY 0x0004 /* fail copy if EAs not supported */
+ /* by destination file system */
+#define DCPY_ALL (DCPY_EXISTING | DCPY_APPEND | DCPY_EA_FAIL_COPY)
+
+
+APIRET
+DosEditName(
+ IN ULONG EditLevel,
+ IN PSZ SourceString,
+ IN PSZ EditString,
+ OUT PBYTE Buffer,
+ IN ULONG Length
+ );
+
+#define EDIT_LEVEL_ONE 0x0001 // use OS2 v1.2 editing semantics
+#define MAX_EDIT_LEVEL EDIT_LEVEL_ONE
+
+APIRET
+DosFileIO(
+ IN HFILE FileHandle,
+ IN PBYTE CommandBuffer,
+ IN ULONG Length,
+ OUT PUSHORT ErrorOffset
+ );
+
+/* DosFileIO command words */
+
+#define FIO_LOCK 0 /* Lock Files */
+#define FIO_UNLOCK 1 /* Unlock Files */
+#define FIO_SEEK 2 /* Seek (set file ptr) */
+#define FIO_READ 3 /* File Read */
+#define FIO_WRITE 4 /* File Write */
+
+/* Lock Sharing Modes */
+#define FIO_NOSHARE 0 /* None */
+#define FIO_SHAREREAD 1 /* Read-Only */
+
+typedef struct _FIOLOCKCMD {
+ USHORT usCmd; /* Cmd = FIO_LOCK */
+ USHORT cLockCnt; /* Lock records that follow */
+ ULONG cTimeOut; /* in Msec */
+} FIOLOCKCMD, *PFIOLOCKCMD;
+
+
+typedef struct _FIOLOCKREC {
+ USHORT fShare; /* FIO_NOSHARE or FIO_SHAREREAD */
+ ULONG cbStart; /* Starting offset for lock region */
+ ULONG cbLength; /* Length of lock region */
+} FIOLOCKREC, *PIOLOCKREC;
+
+
+typedef struct _FIOUNLOCKCMD {
+ USHORT usCmd; /* Cmd = FIO_UNLOCK */
+ USHORT cUnlockCnt; /* Unlock records that follow */
+} FIOUNLOCKCMD, *PFIOUNLOCKCMD;
+
+
+typedef struct _FIOUNLOCKREC {
+ ULONG cbStart; /* Starting offset for unlock region */
+ ULONG cbLength; /* Length of unlock region */
+} FIOUNLOCKREC, *PFIOUNLOCKREC;
+
+
+typedef struct _FIOSEEKCMD {
+ USHORT usCmd; /* Cmd = FIO_SEEK */
+ USHORT fsMethod; /* One of: FPM_BEGINNING, FPM_CURRENT,
+ or FPM_END */
+ ULONG cbDistance; /* Byte offset for seek */
+ ULONG cbNewPosition; /* Bytes from start of file after
+ seek */
+} FIOSEEKCMD, *PFIOSEEKCMD;
+
+
+typedef struct _FIOREADWRITE {
+ USHORT usCmd; /* Cmd = FIO_READ or FIO_WRITE */
+ PVOID pbBuffer; /* Pointer to data buffer */
+ ULONG cbBufferLen; /* Bytes in buffer or max size */
+ ULONG cbActualLen; /* Bytes actually read/written */
+} FIOREADWRITE, *PFIOREADWRITE;
+
+
+
+APIRET
+DosCreateDir(
+ IN PSZ DirectoryName,
+ IN PEAOP2 DirectoryAttributes OPTIONAL
+ );
+
+APIRET
+DosDeleteDir(
+ IN PSZ DirectoryName
+ );
+
+APIRET
+DosQueryFileInfo(
+ IN HFILE FileHandle,
+ IN ULONG FileInformationLevel,
+ OUT PBYTE Buffer,
+ IN ULONG Length
+ );
+
+APIRET
+DosSetFileInfo(
+ IN HFILE FileHandle,
+ IN ULONG FileInformationLevel,
+ IN OUT PBYTE Buffer,
+ IN ULONG Length
+ );
+
+APIRET
+DosQueryPathInfo(
+ IN PSZ pszPath,
+ IN ULONG FileInformationLevel,
+ OUT PBYTE Buffer,
+ IN ULONG Length
+ );
+
+APIRET
+DosSetPathInfo(
+ IN PSZ pszPath,
+ IN ULONG FileInformationLevel,
+ IN OUT PBYTE Buffer,
+ IN ULONG Length,
+ IN ULONG Flags
+ );
+
+/* defines for DosSetPathInfo Flags parameter values */
+#define DSPI_WRTTHRU 0x10 /* write through */
+
+APIRET
+DosEnumAttribute(
+ IN ULONG RefType,
+ IN PVOID FileRef,
+ IN ULONG EntryNum,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ IN OUT PULONG ActualLength,
+ IN ULONG FileInformationLevel
+ );
+
+#define ENUM_EANAME 1 // DosEnumAttribute infolevel 1
+
+/* Infolevels for DosEnumAttribute */
+#define ENUMEA_LEVEL_NO_VALUE 1 /* FEA without value */
+
+/* Reference types for DosEnumAttribute */
+#define ENUMEA_REFTYPE_FHANDLE 0 /* file handle */
+#define ENUMEA_REFTYPE_PATH 1 /* path name */
+#define ENUMEA_REFTYPE_MAX ENUMEA_REFTYPE_PATH
+
+/* level 1 info returned from DosEnumAttribute */
+
+typedef struct _DENA1 {
+ ULONG oNextEntryOffset; /* offset to next EA */
+ UCHAR fEA; /* flags */
+ UCHAR cbName; /* length of name excluding NULL */
+ USHORT cbValue; /* length of value */
+ UCHAR szName[1]; /* variable length asciiz name */
+} DENA1, *PDENA1;
+
+#endif // INCL_OS2V20_FILESYS
+
+#ifdef INCL_OS2V20_FSD
+
+/* FSD API Calls */
+
+APIRET
+DosShutdown(
+ IN ULONG Reserved
+ );
+
+APIRET
+DosFSAttach(
+ IN PSZ DeviceName,
+ IN PSZ FsName,
+ IN PBYTE FsData,
+ IN ULONG FsDataLength,
+ IN ULONG AttachFlags
+ );
+
+/* Dos32FsAttach() */
+/* Attact or detach */
+#define FS_ATTACH 0 /* Attach file server */
+#define FS_DETACH 1 /* Detach file server */
+
+
+APIRET
+DosQueryFSAttach(
+ IN PSZ DeviceName,
+ IN ULONG Ordinal,
+ IN ULONG FsInformationLevel,
+ OUT PBYTE FsAttributes,
+ IN OUT PULONG FsAttributesLength
+ );
+
+/* DosQueryFSAttach() */
+/* Information level types (defines method of query) */
+#define FSAIL_QUERYNAME 1 /* Return data for a Drive or Device */
+#define FSAIL_DEVNUMBER 2 /* Return data for Ordinal Device # */
+#define FSAIL_DRVNUMBER 3 /* Return data for Ordinal Drive # */
+
+/* Item types (from data structure item "iType") */
+#define FSAT_CHARDEV 1 /* Resident character device */
+#define FSAT_PSEUDODEV 2 /* Pusedu-character device */
+#define FSAT_LOCALDRV 3 /* Local drive */
+#define FSAT_REMOTEDRV 4 /* Remote drive attached to FSD */
+
+typedef struct _FSQBUFFER2 { /* Data structure for QFSAttach */
+ USHORT iType; /* Item type */
+ USHORT cbName; /* Length of item name, sans NULL */
+ USHORT cbFSDName; /* Length of FSD name, sans NULL */
+ USHORT cbFSAData; /* Length of FSD Attach data returned */
+ UCHAR szName[1]; /* ASCIIZ item name */
+ UCHAR szFSDName[1]; /* ASCIIZ FSD name */
+ UCHAR rgFSAData[1]; /* FSD Attach data from FSD */
+} FSQBUFFER2, *PFSQBUFFER2;
+
+APIRET
+DosFSCtl(
+ IN PBYTE Data,
+ IN ULONG DataLength,
+ OUT PULONG ActualDataLength,
+ IN PBYTE Parameters,
+ IN ULONG ParametersLength,
+ OUT PULONG ActualParametersLength,
+ IN ULONG Function,
+ IN PSZ RouteName,
+ IN HFILE FileHandle,
+ IN ULONG RoutingMethod
+ );
+
+/* Dos32FsCtl() */
+/* Routing type */
+#define FSCTL_HANDLE 1 /* File Handle directs req routing */
+#define FSCTL_PATHNAME 2 /* Path Name directs req routing */
+#define FSCTL_FSDNAME 3 /* FSD Name directs req routing */
+
+
+APIRET
+DosQueryFSInfo(
+ IN ULONG DiskNumber,
+ IN ULONG FsInformationLevel,
+ IN PBYTE Buffer,
+ IN ULONG Length
+ );
+
+APIRET
+DosSetFSInfo(
+ ULONG DiskNumber,
+ ULONG FsInformationLevel,
+ PBYTE Buffer,
+ ULONG Length
+ );
+
+/* FS Drive Info Levels */
+#define FSIL_ALLOC 1 /* Drive allocation info (Query only) */
+#define FSIL_VOLSER 2 /* Drive Volum/Serial info */
+
+#pragma pack(1)
+typedef struct _FSALLOCATE {
+ ULONG ulReserved;
+ ULONG cSectorUnit;
+ ULONG cUnit;
+ ULONG cUnitAvail;
+ USHORT cbSector;
+} FSALLOCATE, *PFSALLOCATE;
+#pragma pack()
+
+#define MAX_LABEL_LENGTH 11 // maximum length of volume label
+
+typedef struct _VOLUMELABEL {
+ BYTE cch;
+ CHAR szVolLabel[MAX_LABEL_LENGTH+1];
+} VOLUMELABEL, *PVOLUMELABEL;
+
+typedef struct _FSINFO {
+ ULONG ulVSN;
+ VOLUMELABEL vol;
+} FSINFO, *PFSINFO;
+
+#endif // INCL_OS2V20_FSD
+
+#ifdef INCL_OS2V20_MEMORY
+
+/*** Memory management API Calls */
+
+APIRET
+DosAllocMem(
+ OUT PVOID *BaseAddress,
+ IN ULONG RegionSize,
+ IN ULONG Flags
+ );
+
+APIRET
+DosFreeMem(
+ PVOID BaseAddress,
+ PBOOLEAN pRemoveLDTEntry
+ );
+
+APIRET
+DosSetMem(
+ IN PVOID BaseAddress,
+ IN ULONG RegionSize,
+ IN ULONG Flags
+ );
+
+APIRET
+DosGiveSharedMem(
+ IN PVOID BaseAddress,
+ IN PID ProcessId,
+ IN ULONG Flags
+ );
+
+APIRET
+DosGetSharedMem(
+ IN PVOID BaseAddress,
+ IN ULONG Flags
+ );
+
+APIRET
+DosGetNamedSharedMem(
+ OUT PVOID *BaseAddress,
+ IN PSZ ObjectName,
+ IN ULONG Flags
+ );
+
+APIRET
+DosAllocSharedMem(
+ OUT PVOID *BaseAddress,
+ IN PSZ ObjectName,
+ IN ULONG RegionSize,
+ IN ULONG Flags,
+ IN BOOLEAN CreateLDTEntry
+ );
+
+APIRET
+DosQueryMem(
+ IN PVOID BaseAddress,
+ IN OUT PULONG RegionSize,
+ OUT PULONG Flags
+ );
+
+#define DA_SHAREMEM_NAMEPREFIX "\\SHAREMEM\\"
+
+/* Access protection */
+#define PAG_READ 0x00000001 /* read access */
+#define PAG_WRITE 0x00000002 /* write access */
+#define PAG_EXECUTE 0x00000004 /* execute access */
+#define PAG_GUARD 0x00000008 /* guard protection */
+#define PAG_DEFAULT 0x00000400 /* default (initial) access */
+
+/* Commit */
+#define PAG_COMMIT 0x00000010 /* commit storage */
+#define PAG_DECOMMIT 0x00000020 /* decommit storage */
+
+/* Allocation attributes */
+#define OBJ_TILE 0x00000040 /* tile object */
+#define OBJ_GETTABLE 0x00000100 /* gettable by other processes */
+#define OBJ_GIVEABLE 0x00000200 /* giveable to other processes */
+
+/* Allocation type (returned from DosQueryMem) */
+#define PAG_SHARED 0x00002000 /* shared object */
+#define PAG_FREE 0x00004000 /* pages are free */
+#define PAG_BASE 0x00010000 /* first page in object */
+
+#define fPERM (PAG_EXECUTE + PAG_READ + PAG_WRITE + PAG_GUARD)
+#define fSHARE (OBJ_GETTABLE + OBJ_GIVEABLE)
+
+/* DosAllocMem flags */
+#define fALLOC (OBJ_TILE + PAG_COMMIT + fPERM)
+
+/* DosAllocSharedMem flags */
+#define fALLOCSHR (OBJ_TILE + PAG_COMMIT + fSHARE + fPERM)
+
+/* DosGetNamedSharedMem flags */
+#define fGETNMSHR (fPERM)
+
+/* DosGetSharedMem flags */
+#define fGETSHR (fPERM)
+
+/* DosGiveSharedMem flags */
+#define fGIVESHR (fPERM)
+
+/* DosSetMem flags */
+#define fSET (OBJ_TILE + PAG_COMMIT + PAG_DECOMMIT + PAG_DEFAULT + fPERM)
+
+#ifdef NOT_IMPLEMENTED
+
+#define OBJ_PROTECTED 0x00000080 /* protect object
+ NOTE: This flag is NOT available at
+ the api level */
+#define PAG_PRIVATE 0x00001000 /* private object */
+
+APIRET
+DosAliasMem(
+ PVOID pb,
+ ULONG cb,
+ PVOID *ppbAlias
+ );
+
+APIRET
+DosQueryMemState(
+ IN PVOID BaseAddress,
+ IN OUT PULONG RegionSize,
+ OUT PULONG Flags
+ );
+
+/* Page state (returned from DosQueryMemState) */
+#define PAG_NPOUT 0x00000000 /* page is not present, not in core */
+#define PAG_PRESENT 0x00000001 /* page is present */
+#define PAG_NPIN 0x00000002 /* page is not present, in core */
+#define PAG_PRESMASK 0x00000003 /* present state mask */
+#define PAG_INVALID 0x00000000 /* page is invalid */
+#define PAG_RESIDENT 0x00000010 /* page is resident */
+#define PAG_SWAPPABLE 0x00000020 /* page is swappable */
+#define PAG_DISCARDABLE 0x00000030 /* page is discardable */
+#define PAG_TYPEMASK 0x00000030 /* type mask */
+
+
+APIRET
+DosQueryMemState(
+ PVOID pb,
+ PULONG cb,
+ PULONG pFlag
+ );
+
+#endif // NOT_IMPLEMENTED
+
+
+APIRET
+DosSubSet(
+ IN PVOID HeapAddress,
+ IN ULONG Flags,
+ IN ULONG NewSize
+ );
+
+/* DosSubSet flags */
+#define DOSSUB_INIT 0x01 /* initialize memory object for */
+ /* suballocation */
+#define DOSSUB_GROW 0x02 /* increase size of memory pool */
+ /* for suballocation */
+#define DOSSUB_SPARSE_OBJ 0x04 /* indicator for DosSub to */
+ /* manage the commitment of */
+ /* pages spanned by the memory */
+ /* pool */
+#define DOSSUB_SERIALIZE 0x08 /* indicates that access to the */
+ /* memory pool is to be */
+ /* serialized by DosSub */
+
+
+APIRET
+DosSubUnset(
+ IN PVOID HeapAddress
+ );
+
+
+APIRET
+DosSubAlloc(
+ IN PVOID HeapAddress,
+ OUT PVOID *BaseAddress,
+ IN ULONG Size
+ );
+
+APIRET
+DosSubFree(
+ IN PVOID HeapAddress,
+ IN PVOID BaseAddress,
+ IN ULONG Size
+ );
+
+#endif // INCL_OS2V20_MEMORY
+
+#ifdef INCL_OS2V20_SEMAPHORES
+
+/* Semaphore API Calls */
+
+
+/* Semaphore CreateAttributes */
+
+#define DC_SEM_MAXNAMEL 256
+
+#define DC_SEM_SHARED 0x01 /* DosCreateMutex, DosCreateEvent, and */
+ /* DosCreateMuxWait use it to indicate */
+ /* whether the semaphore is shared or */
+ /* private when the PSZ is null */
+#define DCMW_WAIT_ANY 0x02 /* DosCreateMuxWait option for wait on any */
+ /* event/mutex to occur */
+#define DCMW_WAIT_ALL 0x04 /* DosCreateMuxWait option for wait on all */
+ /* events/mutexs to occur */
+
+#define SEM_INDEFINITE_WAIT -1L
+#define SEM_IMMEDIATE_RETURN 0L
+
+APIRET
+DosCreateEventSem(
+ IN PSZ ObjectName,
+ OUT PHEV EventHandle,
+ IN ULONG CreateAttributes,
+ IN BOOL32 InitialState
+ );
+
+APIRET
+DosOpenEventSem(
+ IN PSZ ObjectName,
+ IN OUT PHEV EventHandle
+ );
+
+APIRET
+DosCloseEventSem(
+ IN HEV EventHandle
+ );
+
+APIRET
+DosResetEventSem(
+ IN HEV EventHandle,
+ OUT PULONG PostCount
+ );
+
+APIRET
+DosPostEventSem(
+ IN HEV EventHandle
+ );
+
+APIRET
+DosWaitEventSem(
+ IN HEV EventHandle,
+ IN ULONG Timeout
+ );
+
+APIRET
+DosQueryEventSem(
+ IN HEV EventHandle,
+ OUT PULONG PostCount
+ );
+
+APIRET
+DosCreateMutexSem(
+ IN PSZ ObjectName,
+ OUT PHMTX MutexHandle,
+ IN ULONG CreateAttributes,
+ IN BOOL32 InitialState
+ );
+
+APIRET
+DosOpenMutexSem(
+ IN PSZ ObjectName,
+ IN OUT PHMTX MutexHandle
+ );
+
+APIRET
+DosCloseMutexSem(
+ IN HMTX MutexHandle
+ );
+
+APIRET
+DosRequestMutexSem(
+ IN HMTX MutexHandle,
+ IN ULONG Timeout
+ );
+
+APIRET
+DosReleaseMutexSem(
+ IN HMTX MutexHandle
+ );
+
+APIRET
+DosQueryMutexSem(
+ IN HMTX MutexHandle,
+ OUT PPID OwnerPid,
+ OUT PTID OwnerTid,
+ OUT PULONG OwnerRequestLevel
+ );
+
+APIRET
+DosCreateMuxWaitSem(
+ IN PSZ ObjectName,
+ OUT PHMUX MuxWaitHandle,
+ IN ULONG CountMuxWaitEntries,
+ IN SEMRECORD MuxWaitEntries[],
+ IN ULONG CreateAttributes
+ );
+
+APIRET
+DosOpenMuxWaitSem(
+ IN PSZ ObjectName,
+ IN OUT PHMUX MuxWaitHandle
+ );
+
+APIRET
+DosCloseMuxWaitSem(
+ IN HMUX MuxWaitHandle
+ );
+
+APIRET
+DosWaitMuxWaitSem(
+ IN HMUX MuxWaitHandle,
+ IN ULONG Timeout,
+ OUT PULONG UserValue
+ );
+
+APIRET
+DosAddMuxWaitSem(
+ IN HMUX MuxWaitHandle,
+ IN PSEMRECORD MuxWaitEntry
+ );
+
+APIRET
+DosDeleteMuxWaitSem(
+ IN HMUX MuxWaitHandle,
+ IN HSEM MuxWaitEntrySem
+ );
+
+APIRET
+DosQueryMuxWaitSem(
+ IN HMUX MuxWaitHandle,
+ IN OUT PULONG CountMuxWaitEntries,
+ OUT SEMRECORD MuxWaitEntries[],
+ OUT PULONG CreateAttributes
+ );
+
+#endif // INCL_OS2V20_SEMAPHORES
+
+#ifdef INCL_OS2V20_TIMERS
+
+/*** Timer Services API Calls */
+
+APIRET
+DosGetDateTime(
+ OUT PDATETIME DateTime
+ );
+
+APIRET
+DosSetDateTime(
+ IN PDATETIME DateTime
+ );
+
+
+APIRET
+DosAsyncTimer(
+ IN ULONG MilliSeconds,
+ IN HEV EventSem,
+ OUT PHTIMER TimerHandle
+ );
+
+APIRET
+DosStartTimer(
+ IN ULONG MilliSeconds,
+ IN HEV EventSem,
+ OUT PHTIMER TimerHandle
+ );
+
+APIRET
+DosStopTimer(
+ IN HTIMER TimerHandle
+ );
+
+#endif // INCL_OS2V20_TIMERS
+
+
+#ifdef INCL_OS2V20_LOADER
+
+/*** Loader API Calls */
+
+APIRET
+DosLoadModule(
+ OUT PSZ ErrorText,
+ IN ULONG ErrorTextLength,
+ IN PSZ ModuleName,
+ OUT PHMODULE ModuleHandle
+ );
+
+APIRET
+DosFreeModule(
+ IN HMODULE ModuleHandle
+ );
+
+APIRET
+DosQueryProcAddr(
+ IN HMODULE ModuleHandle,
+ IN ULONG ProcOrdinal,
+ IN PSZ ProcName OPTIONAL,
+ OUT PFN *ProcAddress
+ );
+
+APIRET
+DosQueryProcType(
+ IN HMODULE ModuleHandle,
+ IN ULONG ProcOrdinal,
+ IN PSZ ProcName OPTIONAL,
+ OUT PULONG *ProcType
+ );
+
+/****
+ defined in os2v12.h
+#define PT_32BIT 0
+#define PT_16BIT 1
+*****/
+
+APIRET
+DosReplaceModule(
+ IN PSZ pszOldModule,
+ IN PSZ pszNewModule,
+ IN PSZ pszBackupModule
+ );
+
+APIRET
+DosQueryModuleHandle(
+ IN PSZ ModuleName,
+ OUT PHMODULE ModuleHandle
+ );
+
+APIRET
+DosQueryModuleName(
+ IN HMODULE ModuleHandle,
+ IN ULONG ModuleNameLength,
+ OUT PSZ ModuleName
+ );
+
+APIRET
+DosGetResource(
+ IN HMODULE ModuleHandle,
+ IN ULONG ResourceTypeId,
+ IN ULONG ResourceNameId,
+ OUT PVOID *ResourceBaseAddress
+ );
+
+APIRET
+DosQueryResourceSize(
+ IN HMODULE ModuleHandle,
+ IN ULONG ResourceTypeId,
+ IN ULONG ResourceNameId,
+ OUT PULONG ResourceSize
+ );
+
+
+/* Predefined resource types */
+
+#define RT_POINTER 1 /* mouse pointer shape */
+#define RT_BITMAP 2 /* bitmap */
+#define RT_MENU 3 /* menu template */
+#define RT_DIALOG 4 /* dialog template */
+#define RT_STRING 5 /* string tables */
+#define RT_FONTDIR 6 /* font directory */
+#define RT_FONT 7 /* font */
+#define RT_ACCELTABLE 8 /* accelerator tables */
+#define RT_RCDATA 9 /* binary data */
+#define RT_MESSAGE 10 /* error msg tables */
+#define RT_DLGINCLUDE 11 /* dialog include file name */
+#define RT_VKEYTBL 12 /* key to vkey tables */
+#define RT_KEYTBL 13 /* key to UGL tables */
+#define RT_CHARTBL 14 /* glyph to character tables */
+#define RT_DISPLAYINFO 15 /* screen display information */
+
+#define RT_FKASHORT 16 /* function key area short form */
+#define RT_FKALONG 17 /* function key area long form */
+
+#define RT_HELPTABLE 18 /* Help table for Cary Help manager */
+#define RT_HELPSUBTABLE 19 /* Help subtable for Cary Help manager */
+
+#define RT_FDDIR 20 /* DBCS uniq/font driver directory */
+#define RT_FD 21 /* DBCS uniq/font driver */
+
+#define RT_MAX 22 /* 1st unused Resource Type */
+
+
+#define RF_ORDINALID 0x80000000L /* ordinal id flag in resource table */
+
+
+APIRET
+DosQueryAppType(
+ IN PSZ ImageFileName,
+ OUT PULONG AppTypeFlags
+ );
+
+/* AppType returned in AppTypeFlags is defined as follows */
+
+#define FAPPTYP_NOTSPEC 0x0000
+#define FAPPTYP_NOTWINDOWCOMPAT 0x0001
+#define FAPPTYP_WINDOWCOMPAT 0x0002
+#define FAPPTYP_WINDOWAPI 0x0003
+#define FAPPTYP_BOUND 0x0008
+#define FAPPTYP_DLL 0x0010
+#define FAPPTYP_DOS 0x0020
+#define FAPPTYP_PHYSDRV 0x0040 /* physical device driver */
+#define FAPPTYP_VIRTDRV 0x0080 /* virtual device driver */
+#define FAPPTYP_PROTDLL 0x0100 /* 'protected memory' dll */
+
+#endif // INCL_OS2V20_LOADER
+
+
+#ifdef INCL_OS2V20_NLS
+
+// #include "os2nls.h"
+
+#endif // INCL_OS2V20_NLS
+
+
+#ifdef INCL_OS2V20_EXCEPTIONS
+
+/*** Exception API Calls */
+
+/*
+ * User Exception Handler Return Codes:
+ */
+
+#define XCPT_CONTINUE_SEARCH 0x00000000 /* exception not handled */
+#define XCPT_CONTINUE_EXECUTION 0xFFFFFFFF /* exception handled /*
+
+/*
+ * fHandlerFlags values (see ExceptionStructure):
+ *
+ * The user may only set (but not clear) the EH_NONCONTINUABLE flag.
+ * All other flags are set by the system.
+ *
+ */
+
+#define EH_NONCONTINUABLE 0x1 /* Noncontinuable exception */
+#define EH_UNWINDING 0x2 /* Unwind is in progress */
+#define EH_EXIT_UNWIND 0x4 /* Exit unwind is in progress */
+#define EH_STACK_INVALID 0x8 /* Stack out of limits or unaligned */
+#define EH_NESTED_CALL 0x10 /* Nested exception handler call */
+
+
+/*
+ * Unwind all exception handlers (see DosUnwindException API)
+ */
+
+#define UNWIND_ALL 0
+
+/*
+ * Exception values are 32 bit values layed out as follows:
+ *
+ * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---+-+-------------------------+-------------------------------+
+ * |Sev|C| Facility | Code |
+ * +---+-+-------------------------+-------------------------------+
+ *
+ * where
+ *
+ * Sev - is the severity code
+ * 00 - Success
+ * 01 - Informational
+ * 10 - Warning
+ * 11 - Error
+ *
+ * C - is the Customer code flag
+ *
+ * Facility - is the facility code
+ *
+ * Code - is the facility's status code
+ *
+ * Exceptions specific to Cruiser (e.g. XCPT_SIGNAL) will be marked
+ * with a facility code of 1.
+ *
+ * System defined exceptions have a facility code of zero.
+ *
+ * Each exception may also have several pieces of additional information.
+ * These are stored in the ExceptionInformation fields of the
+ * ExceptionReportRecord. They are documented here with the exceptions
+ * only for ease of reference.
+ */
+
+#define XCPT_FATAL_EXCEPTION 0xC0000000
+#define XCPT_SEVERITY_CODE 0xC0000000
+#define XCPT_CUSTOMER_CODE 0x20000000
+#define XCPT_FACILITY_CODE 0x1FFF0000
+#define XCPT_EXCEPTION_CODE 0x0000FFFF
+
+/*
+ * Access flags in ExceptionInformation
+ */
+#define XCPT_READ_ACCESS 0
+#define XCPT_WRITE_ACCESS 1
+#define XCPT_EXECUTE_ACCESS 2
+#define XCPT_ACCESS_UNKNOWN 3
+
+/*
+ * Signal subtypes for XCPT_SIGNAL
+ */
+#define XCPT_SIGNAL_INTR 1
+#define XCPT_SIGNAL_KILLPROC 3
+#define XCPT_SIGNAL_BREAK 4
+
+/*
+ * Portable non-fatal software generated exceptions
+ */
+
+#define XCPT_GUARD_PAGE_VIOLATION 0x80000001
+ /* ExceptionInformation[ 0 ] - R/W flag */
+ /* ExceptionInformation[ 1 ] - FaultAddr */
+
+#define XCPT_UNABLE_TO_GROW_STACK 0x80010001
+
+/*
+ * Portable fatal hardware generated exceptions
+ */
+
+#define XCPT_DATATYPE_MISALIGNMENT 0x80000002
+ /* ExceptionInformation[ 0 ] - R/W flag */
+ /* ExceptionInformation[ 1 ] - Alignment */
+ /* ExceptionInformation[ 2 ] - FaultAddr */
+
+#define XCPT_BREAKPOINT 0xC0000003
+ /* ExceptionInformation[ 0 ] - R/W/E/I flags */
+
+#define XCPT_SINGLE_STEP 0xC0000004
+
+#define XCPT_ACCESS_VIOLATION 0xC0000005
+ /* ExceptionInformation[ 0 ] - R/W flag */
+ /* ExceptionInformation[ 1 ] - FaultAddr */
+
+#define XCPT_ILLEGAL_INSTRUCTION 0xC000001C
+#define XCPT_FLOAT_DENORMAL_OPERAND 0xC0000094
+#define XCPT_FLOAT_DIVIDE_BY_ZERO 0xC0000095
+#define XCPT_FLOAT_INEXACT_RESULT 0xC0000096
+#define XCPT_FLOAT_INVALID_OPERATION 0xC0000097
+#define XCPT_FLOAT_OVERFLOW 0xC0000098
+#define XCPT_FLOAT_STACK_CHECK 0xC0000099
+#define XCPT_FLOAT_UNDERFLOW 0xC000009A
+
+#define XCPT_INTEGER_DIVIDE_BY_ZERO 0xC000009B
+#define XCPT_INTEGER_OVERFLOW 0xC000009C
+#define XCPT_PRIVILEGED_INSTRUCTION 0xC000009D
+
+/*
+ * Portable fatal software generated exceptions
+ */
+
+#define XCPT_IN_PAGE_ERROR 0xC0000006
+ /* ExceptionInformation[ 0 ] - FaultAddr */
+
+#define XCPT_PROCESS_TERMINATE 0xC0010001
+#define XCPT_ASYNC_PROCESS_TERMINATE 0xC0010002
+ /* ExceptionInfo[0] - TID of 'terminator' thread */
+
+#define XCPT_NONCONTINUABLE_EXCEPTION 0xC0000024
+#define XCPT_INVALID_DISPOSITION 0xC0000025
+
+/*
+ * Non-portable fatal exceptions
+ */
+
+#define XCPT_INVALID_LOCK_SEQUENCE 0xC000001D
+#define XCPT_ARRAY_BOUNDS_EXCEEDED 0xC0000093
+
+/*
+ * Misc exceptions
+ */
+
+#define XCPT_UNWIND 0xC0000026
+#define XCPT_BAD_STACK 0xC0000027
+#define XCPT_INVALID_UNWIND_TARGET 0xC0000028
+
+/*
+ * Signal Exceptions
+ */
+
+#define XCPT_SIGNAL 0xC0010003
+ /* ExceptionInfo[0] - signal number */
+
+/*
+ * Exception Context.
+ *
+ * This is the machine specific register contents for the thread
+ * at the time of the exception. Note that only the register sets
+ * specified by ContextFlags contain valid data. Conversely, only
+ * registers specified in ContextFlags will be restored if an exception
+ * is handled.
+ */
+
+/* XLATOFF */
+#pragma pack(1)
+/* XLATON */
+
+struct _fpreg { /* coprocessor stack register element */
+ ULONG losig;
+ ULONG hisig;
+ USHORT signexp;
+};
+typedef struct _fpreg FPREG;
+
+/* XLATOFF */
+#pragma pack()
+/* XLATON */
+
+
+/*
+ * ExceptionReportRecord
+ *
+ * This structure contains machine independant information about an
+ * exception/unwind. No system exception will ever have more than
+ * EXCEPTION_MAXIMUM_PARAMETERS parameters. User exceptions are not
+ * bound to this limit.
+ */
+
+#undef EXCEPTION_MAXIMUM_PARAMETERS
+
+#define EXCEPTION_MAXIMUM_PARAMETERS 4 /* Enough for all system exceptions. */
+
+struct _EXCEPTIONREPORTRECORD {
+ ULONG ExceptionNum; /* exception number */
+ ULONG fHandlerFlags;
+ struct _EXCEPTIONREPORTRECORD *NestedExceptionReportRecord;
+ PVOID ExceptionAddress;
+ ULONG cParameters; /* Size of Exception Specific Info */
+ ULONG ExceptionInfo[EXCEPTION_MAXIMUM_PARAMETERS];
+ /* Exception Specfic Info */
+};
+typedef struct _EXCEPTIONREPORTRECORD EXCEPTIONREPORTRECORD;
+typedef struct _EXCEPTIONREPORTRECORD *PEXCEPTIONREPORTRECORD;
+
+/*
+ * ExceptionRegistrationRecord
+ *
+ * These are linked together to form a chain of exception handlers that
+ * will be dispatched to upon receipt of an exception.
+ *
+ * NOTE: Exception handlers should *NOT* be Registered directly from a
+ * high level language, such as 'C'. This is the responsibility of
+ * the language runtime.
+ */
+
+struct _EXCEPTIONREGISTRATIONRECORD {
+ struct _EXCEPTIONREGISTRATIONRECORD *prev_structure;
+ ULONG (*ExceptionHandler)();
+};
+typedef struct _EXCEPTIONREGISTRATIONRECORD EXCEPTIONREGISTRATIONRECORD;
+typedef struct _EXCEPTIONREGISTRATIONRECORD *PEXCEPTIONREGISTRATIONRECORD;
+
+//
+// DosSetSigExceptionFocus codes
+//
+
+#define SIG_UNSETFOCUS 0
+#define SIG_SETFOCUS 1
+
+APIRET
+DosRaiseException(
+ IN PEXCEPTIONREPORTRECORD ExceptionReportRecord
+ );
+
+APIRET
+DosUnwindException(
+ IN PEXCEPTIONREGISTRATIONRECORD ExceptionHandler,
+ IN PVOID TargetIP,
+ IN PEXCEPTIONREPORTRECORD ExceptionReportRecord
+ );
+
+APIRET
+DosEnterMustComplete(
+ OUT PULONG NestingLevel
+ );
+
+APIRET
+DosExitMustComplete(
+ OUT PULONG NestingLevel
+ );
+
+APIRET
+DosAcknowledgeSignalException(
+ IN ULONG SignalNumber
+ );
+
+APIRET
+DosSendSignalException(
+ IN PID ProcessId,
+ IN ULONG Exception
+ );
+
+APIRET
+DosSetSignalExceptionFocus(
+ IN BOOL32 Flag,
+ OUT PULONG NestingLevel
+ );
+
+#endif // INCL_OS2V20_EXCEPTIONS
+
+#ifdef INCL_OS2V20_ERRORMSG
+
+/* Error API Calls */
+
+APIRET
+DosError(
+ IN ULONG ErrorFlags
+ );
+
+/* definitions for DosError - combine with | */
+
+#define DE_DISABLE_HARD_ERRORS 0x00000000
+#define DE_ENABLE_HARD_ERRORS 0x00000001
+#define DE_ENABLE_EXCEPTIONS 0x00000000
+#define DE_DISABLE_EXCEPTIONS 0x00000002
+
+#define FERR_DISABLEHARDERR 0x00000000L /* disable hard error popups */
+#define FERR_ENABLEHARDERR 0x00000001L /* enable hard error popups */
+#define FERR_ENABLEEXCEPTION 0x00000000L /* enable exception popups */
+#define FERR_DISABLEEXCEPTION 0x00000002L /* disable exception popups */
+
+
+APIRET
+DosErrClass(
+ IN ULONG ErrorCode,
+ OUT PULONG ErrorClass,
+ OUT PULONG ErrorAction,
+ OUT PULONG ErrorLocus
+ );
+
+/* Values for error CLASS */
+
+#define ERRCLASS_OUTRES 1
+#define ERRCLASS_TEMPSIT 2
+#define ERRCLASS_AUTH 3
+#define ERRCLASS_INTRN 4
+#define ERRCLASS_HRDFAIL 5
+#define ERRCLASS_SYSFAIL 6
+#define ERRCLASS_APPERR 7
+#define ERRCLASS_NOTFND 8
+#define ERRCLASS_BADFMT 9
+#define ERRCLASS_LOCKED 10
+#define ERRCLASS_MEDIA 11
+#define ERRCLASS_ALREADY 12
+#define ERRCLASS_UNK 13
+#define ERRCLASS_CANT 14
+#define ERRCLASS_TIME 15
+
+/* Values for error ACTION */
+
+#define ERRACT_RETRY 1
+#define ERRACT_DLYRET 2
+#define ERRACT_USER 3
+#define ERRACT_ABORT 4
+#define ERRACT_PANIC 5
+#define ERRACT_IGNORE 6
+#define ERRACT_INTRET 7
+
+/* Values for error LOCUS */
+
+#define ERRLOC_UNK 1
+#define ERRLOC_DISK 2
+#define ERRLOC_NET 3
+#define ERRLOC_SERDEV 4
+#define ERRLOC_MEM 5
+
+
+APIRET
+DosGetMessage(
+ IN PSZ Variables[],
+ IN ULONG CountVariables,
+ OUT PCHAR Buffer,
+ IN ULONG Length,
+ IN ULONG MessageNumber,
+ IN PSZ MessageFileName,
+ OUT PULONG MessageLength,
+ IN PBYTE pMsgSeg
+ );
+
+APIRET
+DosInsertMessage(
+ IN PSZ Variables[],
+ IN ULONG CountVariables,
+ IN PCHAR Message,
+ IN ULONG MessageLength,
+ OUT PCHAR Buffer,
+ IN ULONG Length,
+ OUT PULONG ActualMessageLength
+ );
+
+APIRET
+DosPutMessage(
+ IN HFILE FileHandle,
+ IN ULONG MessageLength,
+ IN PCHAR Message
+ );
+
+APIRET
+DosQueryMessageCP(
+ PCHAR Buffer,
+ ULONG Length,
+ IN PSZ MessageFileName,
+ OUT PULONG ActualLength
+ );
+
+
+#endif // INCL_OS2V20_ERRORMSG
+
+#ifdef INCL_OS2V20_SESSIONMGR
+
+/*** Session manager API Calls */
+
+APIRET
+DosShutdown(
+ ULONG ulReserved
+ );
+
+APIRET
+DosStartSession(
+ IN PSTARTDATA StartData,
+ OUT PULONG SessionId,
+ OUT PPID ProcessId
+ );
+
+APIRET
+DosSetSession(
+ IN ULONG SessionId,
+ IN PSTATUSDATA SessionStatusData
+ );
+
+APIRET
+DosSelectSession(
+ IN ULONG SessionId,
+ IN ULONG ulReserved
+ );
+
+APIRET
+DosStopSession(
+ IN ULONG StopTarget,
+ IN ULONG SessionId,
+ IN ULONG ulReserved
+ );
+
+#define DSS_SESSION 0x0
+#define DSS_ALL_SESSIONS 0x1
+
+#endif // INCL_OS2V20_SESSIONMSG
+
+#ifdef INCL_OS2V20_DEVICE_SUPPORT
+
+/*** Device support API Calls */
+
+APIRET
+DosBeep(
+ IN ULONG Frequency,
+ IN ULONG Duration
+ );
+
+
+APIRET
+DosDevConfig(
+ OUT PVOID DeviceInformation,
+ IN ULONG DeviceInformationIndex
+ );
+
+#define DDC_NUMBER_PRINTERS 0 // USHORT
+#define DDC_NUMBER_RS232_PORTS 1 // USHORT
+#define DDC_NUMBER_DISKETTE_DRIVES 2 // USHORT
+#define DDC_MATH_COPROCESSOR 3 // BYTE
+#define DDC_PC_SUBMODEL_TYPE 4 // BYTE
+#define DDC_PC_MODEL_TYPE 5 // BYTE
+#define DDC_PRIMARY_DISPLAY_TYPE 6 // BYTE
+#define DDC_COPROCESSORTYPE 7 // BYTE
+
+APIRET
+DosQuerySysInfo(
+ IN ULONG SysInfoIndexStart,
+ IN ULONG SysInfoIndexEnd,
+ OUT PBYTE Buffer,
+ IN ULONG Length
+ );
+
+/* Values for SysInfoIndex of DosQuerySysInfo */
+
+#define QSV_MAX_PATH_LENGTH 1
+/*
+defined in os2v12.h #define Q_MAX_PATH_LENGTH QSV_MAX_PATH_LENGTH
+*/
+#define QSV_MAX_TEXT_SESSIONS 2
+#define QSV_MAX_PM_SESSIONS 3
+#define QSV_MAX_VDM_SESSIONS 4
+#define QSV_BOOT_DRIVE 5 /* 1=A, 2=B, etc. */
+#define QSV_DYN_PRI_VARIATION 6 /* 0=Absolute, 1=Dynamic */
+#define QSV_MAX_WAIT 7 /* seconds */
+#define QSV_MIN_SLICE 8 /* milli seconds */
+#define QSV_MAX_SLICE 9 /* milli seconds */
+#define QSV_PAGE_SIZE 10
+#define QSV_VERSION_MAJOR 11
+#define QSV_VERSION_MINOR 12
+#define QSV_VERSION_REVISION 13 /* Revision letter */
+#define QSV_MS_COUNT 14 /* Free running millisecond counter */
+#define QSV_TIME_LOW 15 /* Low dword of time in seconds */
+#define QSV_TIME_HIGH 16 /* High dword of time in seconds */
+#define QSV_TOTPHYSMEM 17 /* Physical memory on system */
+#define QSV_TOTRESMEM 18 /* Resident memory on system */
+#define QSV_TOTAVAILMEM 19 /* Available memory for all processes */
+#define QSV_MAXPRMEM 20 /* Avail private mem for calling proc */
+#define QSV_MAXSHMEM 21 /* Avail shared mem for calling proc */
+#define QSV_TIMER_INTERVAL 22 /* Timer interval in tenths of ms */
+#define QSV_MAX_COMP_LENGTH 23 /* max len of one component in a name */
+#define QSV_MAXIMUM_INDEX 23
+
+#ifdef NOT_IMPLEMENTED
+
+APIRET
+DosDevIOCtl(
+ PVOID pData,
+ ULONG cbData,
+ PVOID pParams,
+ ULONG cbParams,
+ ULONG function,
+ ULONG category,
+ PHFILE phDevice
+ );
+
+APIRET
+DosPhysicalDisk(
+ ULONG function,
+ PBYTE pBuf,
+ ULONG cbBuf,
+ PBYTE pParams,
+ ULONG cbParams
+ );
+#endif // NOT_IMPLEMENTED
+
+#endif // INCL_OS2V20_DEVICE_SUPPORT
+
+#ifdef INCL_OS2V20_PIPES
+
+/*** Pipe and Named Pipe API Calls */
+
+APIRET
+DosCreatePipe(
+ OUT PHFILE phfRead,
+ OUT PHFILE phfWrite,
+ IN ULONG PipeSize
+ );
+
+APIRET
+DosCallNPipe(
+ PSZ pszName,
+ PBYTE pInbuf,
+ ULONG cbIn,
+ PBYTE pOutbuf,
+ ULONG cbOut,
+ PULONG pcbActual,
+ ULONG msec
+ );
+
+APIRET
+DosConnectNPipe(
+ HPIPE hpipe
+ );
+
+APIRET
+DosDisConnectNPipe(
+ HPIPE hpipe
+ );
+
+APIRET
+DosCreateNPipe(
+ PSZ pszName,
+ PHPIPE pHpipe,
+ ULONG openmode,
+ ULONG pipemode,
+ ULONG cbOutbuf,
+ ULONG cbInbuf,
+ ULONG msec
+ );
+
+APIRET
+DosPeekNPipe(
+ HPIPE hpipe,
+ PBYTE pBuf,
+ ULONG cbBuf,
+ PULONG pcbActual,
+ PULONG pcbMore,
+ PULONG pState
+ );
+
+APIRET
+DosQueryNPHState(
+ HPIPE hpipe,
+ PULONG pState
+ );
+
+APIRET
+DosQueryNPipeInfo(
+ HPIPE hpipe,
+ ULONG infolevel,
+ PBYTE pBuf,
+ ULONG cbBuf
+ );
+
+APIRET
+DosQueryNPipeSemState(
+ HSEM hsem,
+ PBYTE pBuf,
+ ULONG cbBuf
+ );
+
+APIRET
+DosRawReadNPipe(
+ PSZ pszName,
+ ULONG cb
+ );
+
+APIRET
+DosRawWriteNPipe(
+ PSZ pszName,
+ ULONG cb
+ );
+
+APIRET
+DosSetNPHState(
+ HPIPE hpipe,
+ ULONG state
+ );
+
+APIRET
+DosSetNPipeSem(
+ HPIPE hpipe,
+ HSEM hsem,
+ ULONG key
+ );
+
+APIRET
+DosTransactNPipe(
+ HPIPE hpipe,
+ PBYTE pOutbuf,
+ ULONG cbOut,
+ PBYTE pInbuf,
+ ULONG cbIn,
+ PULONG pcbRead
+ );
+
+APIRET
+DosWaitNPipe(
+ PSZ pszName,
+ ULONG msec
+ );
+
+/*** Data structures and equates used with named pipes ***/
+
+struct npi_data1 { /* PipeInfo data block (returned, level 1) */
+ unsigned short npi_obuflen; /* length of outgoing I/O buffer */
+ unsigned short npi_ibuflen; /* length of incoming I/O buffer */
+ unsigned char npi_maxicnt; /* maximum number of instances */
+ unsigned char npi_curicnt; /* current number of instances */
+ unsigned char npi_namlen; /* length of pipe name */
+ char npi_name[1]; /* start of name */
+}; /* npi_data1 */
+
+struct npss { /* QNmPipeSemState information record */
+ unsigned char npss_status; /* type of record, 0 = EOI, 1 = read ok, */
+ /* 2 = write ok, 3 = pipe closed */
+ unsigned char npss_flag; /* additional info, 01 = waiting thread */
+ unsigned short npss_key; /* user's key value */
+ unsigned short npss_avail; /* available data/space if status = 1/2 */
+}; /* npss */
+
+/* values in npss_status */
+#define NPSS_EOI 0 /* End Of Information */
+#define NPSS_RDATA 1 /* read data available */
+#define NPSS_WSPACE 2 /* write space available */
+#define NPSS_CLOSE 3 /* pipe in CLOSING state */
+
+/* values in npss_flag */
+#define NPSS_WAIT 0x01 /* waiting thread on end of pipe */
+
+/* defined bits in pipe mode */
+#define NP_NBLK 0x8000 /* non-blocking read/write */
+#define NP_SERVER 0x4000 /* set if server end */
+#define NP_WMESG 0x0400 /* write messages */
+#define NP_RMESG 0x0100 /* read as messages */
+#define NP_ICOUNT 0x00FF /* instance count field */
+
+
+/* Named pipes may be in one of several states depending on the actions
+ * that have been taken on it by the server end and client end. The
+ * following state/action table summarizes the valid state transitions:
+ *
+ * Current state Action Next state
+ *
+ * <none> server DosMakeNmPipe DISCONNECTED
+ * DISCONNECTED server connect LISTENING
+ * LISTENING client open CONNECTED
+ * CONNECTED server disconn DISCONNECTED
+ * CONNECTED client close CLOSING
+ * CLOSING server disconn DISCONNECTED
+ * CONNECTED server close CLOSING
+ * <any other> server close <pipe deallocated>
+ *
+ * If a server disconnects his end of the pipe, the client end will enter a
+ * special state in which any future operations (except close) on the file
+ * descriptor associated with the pipe will return an error.
+ */
+
+/*
+ * Values for named pipe state
+ */
+
+#define NP_DISCONNECTED 1 /* after pipe creation or Disconnect */
+#define NP_LISTENING 2 /* after DosNmPipeConnect */
+#define NP_CONNECTED 3 /* after Client open */
+#define NP_CLOSING 4 /* after Client or Server close */
+
+
+#endif // INCL_OS2V20_PIPES
+
+
+#ifdef INCL_OS2V20_QUEUES
+
+#define DC_QUEUES_NAMEPREFIX "\\QUEUES\\"
+
+/*** Queue API Calls */
+
+APIRET
+DosCreateQueue(
+ OUT PHQUEUE QueueHandle,
+ IN ULONG QueueType,
+ IN PSZ ObjectName
+ );
+
+#define QUE_FIFO 0x0
+#define QUE_LIFO 0x1
+#define QUE_PRIORITY 0x2
+
+APIRET
+DosOpenQueue(
+ OUT PPID OwnerProcessId,
+ OUT PHQUEUE QueueHandle,
+ IN PSZ ObjectName
+ );
+
+APIRET
+DosCloseQueue(
+ IN HQUEUE QueueHandle
+ );
+
+APIRET
+DosPurgeQueue(
+ IN HQUEUE QueueHandle
+ );
+
+APIRET
+DosQueryQueue(
+ IN HQUEUE QueueHandle,
+ OUT PULONG CountQueuedElements
+ );
+
+
+APIRET
+DosPeekQueue(
+ IN HQUEUE QueueHandle,
+ OUT PREQUESTDATA RequestInfo,
+ OUT PULONG DataLength,
+ OUT PULONG Data,
+ IN OUT PULONG ReadPosition,
+ IN BOOL32 NoWait,
+ OUT PBYTE ElementPriority,
+ IN HSEM SemHandle
+ );
+
+APIRET
+DosReadQueue(
+ IN HQUEUE QueueHandle,
+ OUT PREQUESTDATA RequestInfo,
+ OUT PULONG DataLength,
+ OUT PULONG Data,
+ IN ULONG ReadPosition,
+ IN BOOL32 NoWait,
+ OUT PBYTE ElementPriority,
+ IN HSEM SemHandle
+ );
+
+APIRET
+DosWriteQueue(
+ IN HQUEUE QueueHandle,
+ IN ULONG SenderData,
+ IN ULONG DataLength,
+ IN PBYTE Data,
+ IN ULONG ElementPriority
+ );
+
+#endif // INCL_OS2V20_QUEUES
+
+#ifdef INCL_OS2V20_ERRORS
+
+#include "os2err.h"
+
+#endif // INCL_OS2V20_ERRORS
+
+//
+// The following error codes are defined by the OS/2 Emulation Subsystem
+// server as a means of communicating with the stub procedures in the OS/2
+// Client DLL.
+//
+
+#define ERROR_SS_RETRY 0xF000
+#define ERROR_SS_UNKNOWN_STATUS 0xF800
+
+APIRET
+DosNullApiCall(
+ IN LONG CountArguments,
+ IN PCHAR *Arguments OPTIONAL
+ );
diff --git a/private/os2/inc/os2win.h b/private/os2/inc/os2win.h
new file mode 100644
index 000000000..4289356c7
--- /dev/null
+++ b/private/os2/inc/os2win.h
@@ -0,0 +1,767 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2win.h
+
+Abstract:
+
+ Prototypes for win32 functions that are called from NT only os2ss files.
+
+Author:
+
+ Yaron Shamir (yarons) 2-Nov-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#ifndef _WINDOWS_
+
+#ifndef DWORD
+typedef long int DWORD;
+#endif
+typedef unsigned short WORD;
+typedef unsigned int UINT;
+#define APIENTRY
+#ifndef BOOL
+typedef long int BOOL;
+#endif
+#ifndef LPBOOL
+typedef BOOL *LPBOOL;
+#endif
+
+
+ //
+ // Termination commands - communication to Os2TerminationThread (srvwin.c)
+ //
+typedef enum _OS2_TERMCMD_TYPE {
+ Os2TerminateProcess = 1,
+ Os2TerminateThread,
+ Os2MaxTermCmd
+} OS2_TERMCMD_TYPE;
+
+typedef struct _OS2_TERMCMD {
+ OS2_TERMCMD_TYPE op;
+ HANDLE Handle;
+ PVOID Param1;
+ PVOID Param2;
+} OS2_TERMCMD, *POS2_TERMCMD;
+
+// winbase.h
+
+#ifndef WAIT_FAILED
+#define WAIT_FAILED (DWORD)0xFFFFFFFF
+#endif
+
+#if PMNT
+ULONG
+SetThreadAffinityMask(
+ HANDLE hThread,
+ DWORD dwThreadAffinityMask
+ );
+#endif // PMNT
+
+ULONG
+GetCurrentProcessId(
+ VOID
+ );
+
+HANDLE
+GetCurrentProcess(
+ VOID
+ );
+
+HANDLE
+GetCurrentThread(
+ VOID
+ );
+
+HANDLE
+OpenProcess(
+ ULONG dwDesiredAccess,
+ BOOLEAN bInheritHandle,
+ ULONG dwProcessId
+ );
+
+#define CREATE_SUSPENDED 0x00000004
+#define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 )
+#define MAX_PATH 260
+#define STD_INPUT_HANDLE (ULONG)-10
+#define STD_OUTPUT_HANDLE (ULONG)-11
+#define STD_ERROR_HANDLE (ULONG)-12
+#define INVALID_HANDLE_VALUE (HANDLE)-1
+#define MB_OK 0x00000000L
+#define MB_OKCANCEL 0x00000001L
+#define MB_ABORTRETRYIGNORE 0x00000002L
+#define MB_YESNOCANCEL 0x00000003L
+#define MB_YESNO 0x00000004L
+#define MB_RETRYCANCEL 0x00000005L
+#define MB_ICONHAND 0x00000010L
+#define MB_ICONQUESTION 0x00000020L
+#define MB_ICONEXCLAMATION 0x00000030L
+#define MB_ICONASTERISK 0x00000040L
+#define MB_ICONINFORMATION MB_ICONASTERISK
+#define MB_ICONSTOP MB_ICONHAND
+#define MB_APPLMODAL 0x00000000L
+#define MB_SETFOREGROUND 0x00010000L
+#define IDOK 1
+#define IDCANCEL 2
+#define IDABORT 3
+#define IDRETRY 4
+#define IDIGNORE 5
+#define IDYES 6
+#define IDNO 7
+#define RESOURCETYPE_ANY 0x00000000
+
+
+typedef struct _NETRESOURCEA {
+ ULONG dwScope;
+ ULONG dwType;
+ ULONG dwDisplayType;
+ ULONG dwUsage;
+ PSZ lpLocalName;
+ PSZ lpRemoteName;
+ PSZ lpComment ;
+ PSZ lpProvider;
+}NETRESOURCEA, *PNETRESOURCEA;
+
+#ifndef PFNTHREAD
+typedef ULONG (*PFNTHREAD)(
+ ULONG lpThreadParameter
+ );
+
+#endif // PFNTHREAD
+
+HANDLE
+CreateThread(
+ PVOID lpThreadAttributes, // LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ ULONG dwStackSize,
+ PFNTHREAD lpStartAddress,
+ PVOID lpParameter,
+ ULONG dwCreationFlags,
+ PULONG lpThreadId
+ );
+
+VOID
+ExitThread(
+ ULONG dwExitCode
+ );
+
+ULONG
+ResumeThread(
+ HANDLE hThread
+ );
+
+BOOLEAN
+TerminateThread(
+ HANDLE hThread,
+ ULONG dwExitCode
+ );
+
+BOOLEAN
+TerminateProcess(
+ HANDLE hProcess,
+ ULONG dwExitCode
+ );
+
+VOID
+Sleep(
+ ULONG dwMilliseconds
+ );
+
+ULONG
+GetTickCount(
+ VOID
+ );
+
+#ifndef ERROR_NO_MEDIA_IN_DRIVE
+#define ERROR_NO_MEDIA_IN_DRIVE 1112L
+#endif
+
+ULONG
+GetLastError(
+ VOID
+ );
+
+BOOLEAN
+GetExitCodeProcess(
+ HANDLE hProcess,
+ PULONG lpExitCode
+ );
+#ifndef INFINITE
+#define INFINITE 0xFFFFFFFF // Infinite timeout
+#endif
+
+ULONG
+WaitForSingleObject(
+ HANDLE hObject,
+ ULONG dwTimeout
+ );
+
+BOOLEAN
+WriteFile(
+ HANDLE hFile,
+ VOID *lpBuffer,
+ ULONG nNumberOfBytesToWrite,
+ PULONG lpNumberOfBytesWritten,
+ PVOID lpOverlapped
+ );
+
+BOOLEAN
+DuplicateHandle(
+ HANDLE hSourceProcessHandle,
+ HANDLE hSourceHandle,
+ HANDLE hTargetProcessHandle,
+ PHANDLE lpTargetHandle,
+ ULONG dwDesiredAccess,
+ BOOLEAN bInheritHandle,
+ ULONG dwOptions
+ );
+
+HANDLE
+GetStdHandle(
+ ULONG nStdHandle
+ );
+
+BOOLEAN
+SetStdHandle(
+ ULONG nStdHandle,
+ HANDLE hHandle
+ );
+
+BOOLEAN
+CloseHandle(
+ HANDLE hObject
+ );
+
+PVOID
+GetEnvironmentStrings(
+ VOID
+ );
+
+BOOLEAN
+SetEnvironmentVariableA(
+ PSZ lpName,
+ PSZ lpValue
+ );
+
+ULONG
+WNetGetConnectionA(
+ PSZ lpName,
+ PSZ lpData,
+ PULONG pCb
+ );
+
+ULONG
+GetEnvironmentVariableA(
+ PSZ lpName,
+ PSZ lpBuffer,
+ ULONG nSize
+ );
+
+BOOLEAN
+SetCurrentDirectoryA(
+ PSZ DirectoryName);
+
+DWORD
+GetCurrentDirectoryA(
+ DWORD nSize,
+ PSZ DirectoryName);
+
+HANDLE
+OpenProcess(
+ ULONG dwDesiredAccess,
+ BOOLEAN bInheritHandle,
+ ULONG dwProcessId
+ );
+
+VOID
+ExitProcess(
+ int ExitCode
+ );
+
+PUCHAR
+GetCommandLineA(
+ VOID
+ );
+
+int
+MessageBoxExW(
+ HANDLE hWnd,
+ PWSTR lpText,
+ PWSTR lpCaption,
+ UINT uType,
+ WORD wLanguageId);
+
+ULONG
+SetErrorMode(
+ ULONG uMode
+ );
+
+ULONG
+GetLogicalDrives(
+ VOID
+ );
+
+UINT
+GetSystemDirectoryA(
+ LPSTR lpBuffer,
+ UINT uSize
+ );
+
+UINT
+GetSystemDirectoryW(
+ LPWSTR lpBuffer,
+ UINT uSize
+ );
+
+ULONG
+WNetAddConnection2A(
+ PNETRESOURCEA lpNetResource,
+ PSZ lpPassword,
+ PSZ lpUserName,
+ ULONG dwFlags
+ );
+
+ULONG
+WNetCancelConnection2A(
+ PSZ lpName,
+ ULONG dwFlags,
+ ULONG fForce
+ );
+
+// wincon.h
+
+BOOLEAN
+SetConsoleTitleA(
+ PSZ lpConsoleTitle
+ );
+
+#if PMNT
+ULONG
+GetConsoleTitleA(
+ PSZ lpConsoleTitle,
+ ULONG lConsoleTitleLength
+ );
+
+#ifdef JAPAN //MSKK [ShigeO] Aug 6, 1993
+
+// wingdi.h
+
+HANDLE
+CreateFontIndirectA(
+ PVOID lpLogFont
+ );
+
+HANDLE
+CreateDCA(
+ LPCSTR lpszDriver,
+ LPCSTR lpszDevice,
+ LPCSTR lpszOutput,
+ PVOID lpInitdata
+ );
+
+BOOLEAN
+GetTextMetricsA(
+ HANDLE hdc,
+ PVOID lptm
+ );
+
+HANDLE
+SelectObject(
+ HANDLE hdc,
+ HANDLE hgdiobj
+ );
+
+UINT
+GetStringBitmapA(
+ HANDLE hdc,
+ LPCSTR lpszStr,
+ UINT cbStr,
+ UINT cbData,
+ PVOID lpSB
+ );
+
+#endif //JAPAN
+#endif // PMNT
+
+#define CTRL_C_EVENT 0
+#define CTRL_BREAK_EVENT 1
+#define CTRL_CLOSE_EVENT 2
+// 3 is reserved!
+// 4 is reserved!
+#define CTRL_LOGOFF_EVENT 5
+#define CTRL_SHUTDOWN_EVENT 6
+
+BOOLEAN
+GenerateConsoleCtrlEvent(
+ ULONG dwCtrlEvent,
+ ULONG dwProcessGroupId
+ );
+
+// winnls.h
+
+int
+MultiByteToWideChar(
+ UINT CodePage,
+ ULONG dwFlags,
+ LPCSTR lpMultiByteStr,
+ int cchMultiByte,
+ LPWSTR lpWideCharStr,
+ int cchWideChar
+ );
+
+int
+WideCharToMultiByte(
+ UINT CodePage,
+ ULONG dwFlags,
+ LPCWSTR lpWideCharStr,
+ int cchWideChar,
+ LPSTR lpMultiByteStr,
+ int cchMultiByte,
+ LPSTR lpDefaultChar,
+ LPBOOL lpUsedDefaultChar
+ );
+
+BOOLEAN
+OpenIcon(
+ HANDLE hwnd
+ );
+
+BOOLEAN
+SetForegroundWindow(
+ HANDLE hwnd
+ );
+
+ULONG
+GetLogicalDrives( VOID );
+
+#endif // _WINDOWS_
+
+ //
+ // Internal Routines (Ow2Xxx) to interface between client side code
+ // and os2ses modules which inturn call win32
+ //
+
+// This bit is set in Flags for a window program. The process is created with
+// CREATE_NEW_PROCESS_GROUP (which enable us to send CTRL_EVENT to all the group)
+
+#define EXEC_WINDOW_PROGRAM 0x80000000
+
+ //
+ // Used to pass standard handle redir info in ExecPgm/StartSession
+ //
+
+#define STDFLAG_IN 0x1L // enables stdin redir
+#define STDFLAG_OUT 0x2L // enables stdout redir
+#define STDFLAG_ERR 0x4L // enables stderr redir
+#define STDFLAG_ALL 0x7L // mask for previous 3
+#define STDFLAG_CLOSEIN 0x10L // indicates that stdin should be closed after use
+#define STDFLAG_CLOSEOUT 0x20L // indicates that stdout should be closed after use
+#define STDFLAG_CLOSEERR 0x40L // indicates that stderr should be closed after use
+#define STDFLAG_CLOSEALL 0x70L // mask for previous 3
+
+typedef struct _OS2_STDHANDLES {
+ ULONG Flags;
+ HANDLE StdIn;
+ HANDLE StdOut;
+ HANDLE StdErr;
+} OS2_STDHANDLES, *POS2_STDHANDLES;
+
+HANDLE
+Ow2GetNulDeviceHandle(
+ VOID
+ );
+
+ULONG
+Ow2ExecPgm(
+ IN ULONG Flags,
+ IN PSZ Arguments OPTIONAL,
+ IN PSZ Variables OPTIONAL,
+ IN PSZ ImageFileName,
+#if PMNT
+ IN ULONG IsPMApp,
+#endif // PMNT
+ IN PVOID SessionStartData OPTIONAL,
+ IN POS2_STDHANDLES StdStruc,
+ OUT HANDLE *pHandle,
+ OUT HANDLE *tHandle,
+ OUT ULONG *dwProcessId
+ );
+
+VOID
+Ow2WinExitCode2ResultCode(
+ IN ULONG Status,
+ OUT PULONG pReturnCode,
+ OUT PULONG pExitReason
+ );
+
+ULONG
+Ow2HardErrorPopup(
+ IN int Drive,
+ IN BOOLEAN WriteProtectError,
+ OUT int * ReturnedAction,
+ IN PUCHAR AppName
+ );
+
+ULONG
+Ow2ConReadFile(
+ IN HANDLE hFile,
+ IN ULONG Length,
+ OUT PVOID Buffer,
+ OUT PULONG BytesRead
+ );
+
+ULONG
+Ow2ConWriteFile(
+ IN HANDLE hFile,
+ IN ULONG Length,
+ IN PVOID Buffer,
+ OUT PULONG BytesWritten
+ );
+
+ULONG
+Ow2ConCloseHandle(
+ IN HANDLE hFile
+ );
+
+ULONG
+Ow2ConBeep(
+ IN ULONG dwFreq,
+ IN ULONG dwDuration
+ );
+
+/*
+ * internal vio routine to perform:
+ *
+ * VioWriteTTYStr - in viotty.c
+ * VioWriteCellStr - used also by violvb.c
+ * VioReadCellStr - used also by violvb.c
+ * VioGetLVBBuf - in violvb.c
+ * VioShowLVBBuf - in violvb.c
+*/
+
+ULONG
+Ow2VioWriteTTYStr(
+ IN PUCHAR string,
+ IN ULONG Length,
+ IN ULONG RequestType
+ );
+
+ULONG
+Ow2VioWriteCellStr(
+ IN ULONG Length,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID SourBuffer
+ );
+
+ULONG
+Ow2VioWriteCharStr(
+ IN ULONG Length,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID SourBuffer
+ );
+
+ULONG
+Ow2VioWriteCharStrAtt(
+ IN ULONG Length,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID SourBuffer,
+ IN PUCHAR AttrBuffer
+ );
+
+ULONG
+Ow2VioReadCellStr(
+ IN OUT PULONG Length,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID DestBuffer
+ );
+
+ULONG
+Ow2VioReadCharStr(
+ IN OUT PULONG pLength,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID DestBuffer
+ );
+
+ULONG
+Ow2VioFillNChar(
+ IN ULONG Number,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID SourBuffer
+ );
+
+ULONG
+Ow2VioFillNAttr(
+ IN ULONG Number,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID SourBuffer
+ );
+
+ULONG
+Ow2VioFillNCell(
+ IN ULONG Number,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID SourBuffer
+ );
+
+ULONG
+Ow2VioScroll(
+ IN PVOID VioScroll,
+ IN ULONG ScrollDirection
+ );
+
+ULONG
+Ow2VioGetConfig(
+ IN OUT PVOID VioConfig
+ );
+
+ULONG
+Ow2VioSetMode(
+ IN PVOID VioMode
+ );
+
+ULONG
+Ow2VioGetMode(
+ IN OUT PVOID VioMode
+ );
+
+ULONG
+Ow2VioSetCurPos(
+ IN ULONG Row,
+ IN ULONG Column
+ );
+
+ULONG
+Ow2VioGetCurPos(
+ IN PUSHORT pRow,
+ IN PUSHORT pColumn
+ );
+
+ULONG
+Ow2VioSetCurType(
+ IN PVOID VioCurType
+ );
+
+ULONG
+Ow2VioGetCurType(
+ IN OUT PVOID VioCurType
+ );
+
+ULONG
+Ow2VioSetNewCp(
+ IN ULONG CodePage
+ );
+
+ULONG
+Ow2VioPopUp(
+ ULONG PopUpMode,
+ PUCHAR AppName
+ );
+
+ULONG
+Ow2VioEndPopUp();
+
+ULONG
+Ow2VioGetLVBBuf(
+ IN PULONG Length
+ );
+
+ULONG
+Ow2VioShowLVBBuf(
+ IN ULONG Length,
+ IN ULONG Offset
+ );
+
+#ifdef DBCS
+// MSKK Apr.20.1993 V-AkihiS
+ULONG
+Ow2VioCheckCharType(
+ OUT PVOID pchType,
+ IN ULONG Row,
+ IN ULONG Column
+ );
+#endif
+
+ULONG
+Ow2PrintOpen(
+ IN ULONG Attribute,
+ IN ULONG OpenFlags,
+ IN ULONG OpenMode,
+ IN PUCHAR PrinterName,
+ IN OUT PHANDLE phPrinter,
+ IN OUT PULONG Action
+ );
+
+ULONG
+Ow2PrintClose(
+ IN HANDLE hPrinter
+ );
+
+ULONG
+Ow2PrintWrite(
+ IN HANDLE hPrinter,
+ IN PVOID Buffer,
+ IN OUT PULONG Length
+ );
+
+ULONG
+Ow2NlsGetCtryInfo(
+ IN ULONG NlsCodePage,
+ IN ULONG NlsCountryCode,
+ OUT PVOID NlsCountryInfo
+ );
+
+ULONG
+Ow2NlsGetDBCSEn(
+ IN ULONG NlsCodePage,
+ OUT PVOID NlsDBCSVec
+ );
+
+ULONG
+Ow2NlsGetCollateTable(
+ IN ULONG NlsCodePage,
+ IN ULONG NlsCountryCode,
+ OUT PVOID NlsColateTable
+ );
+
+ULONG
+Ow2NlsGetCaseMapTable(
+ IN ULONG NlsCodePage,
+ IN ULONG NlsCountryCode,
+ OUT PVOID NlsColateTable
+ );
+
+ //
+ // Routines for displaying and filtering Exception information - os2ses\os2.c
+ //
+
+ULONG
+Ow2FaultFilter(
+ IN ULONG uFaultFilter,
+ IN PEXCEPTION_POINTERS lpExP);
+
+VOID Ow2DisplayExceptionInfo( VOID );
+
+#ifdef DBCS
+// MSKK Sep.27.1993 V-AkihiS
+#define Ow2NlsIsDBCSLeadByte(NlsTestChar, NlsCodePage) \
+ ((NlsCodePage == SesGrp->PrimaryCP) || (NlsCodePage == 0)) \
+ ? IsDBCSLeadByte(NlsTestChar) : FALSE
+#endif
+
diff --git a/private/os2/inc/pmnt.h b/private/os2/inc/pmnt.h
new file mode 100644
index 000000000..e7fbad4a3
--- /dev/null
+++ b/private/os2/inc/pmnt.h
@@ -0,0 +1,306 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ pmnt.h
+
+Abstract:
+
+ This is the include file that defines all constants and types for
+ the PMNTDD device & the PMNT.DLL services.
+ Define INCL_32BIT before #include statement if and only if this file is
+ included by a 32-bit C module (ie OS/2 ss or PMNTDD.SYS).
+
+Author:
+
+ Patrick Questembert (PatrickQ) 03-Aug-1992.
+
+Revision History:
+
+--*/
+
+#ifndef _PMNTINCLUDE_
+#define _PMNTINCLUDE_
+
+#ifndef INCL_32BIT
+#define INCL_16BIT
+#endif // INCL_32BIT
+
+#define PMNT_DAYTONA 1 // Define this ONLY for post 570 builds (i.e. DAYTONA)
+
+/***************************************************************************/
+/* Below is the structure returned by the 32-bit code down to PM from the */
+/* ReadConsoleInputA API. This */
+/* duplicates the WIN32 Console structure (29 Nov 92) - it is defined here */
+/* so that the 16-bit PM code is unaffected by possible changes to the */
+/* WIN32 structure. */
+/***************************************************************************/
+
+#ifdef INCL_16BIT
+#pragma pack(1)
+#endif
+
+typedef struct _PM_KEY_INPUT_RECORD {
+ UCHAR monflags;
+ UCHAR scancode;
+ UCHAR xlatedchar;
+ UCHAR xlatedscan;
+ USHORT shiftDBCS;
+ USHORT shiftstate;
+ ULONG time;
+ USHORT ddflags;
+ } PM_KEY_INPUT_RECORD;
+
+#ifdef INCL_16BIT
+#pragma pack ()
+#endif
+
+#ifdef INCL_16BIT
+#pragma pack(4) // Because the structures below will come from NT
+#endif
+
+typedef struct _PMNT_KEY_EVENT_RECORD {
+ ULONG bKeyDown; // ULONG instead of BOOL
+ USHORT wRepeatCount; // USHORT instead of WORD
+ USHORT wVirtualKeyCode; // USHORT instead of WORD
+ USHORT wVirtualScanCode; // USHORT instead of WORD
+ union {
+ USHORT UnicodeChar; // USHORT instead of WCHAR
+ CHAR AsciiChar;
+ } uChar;
+ ULONG dwControlKeyState; // ULONG instead of DWORD
+} PMNT_KEY_EVENT_RECORD;
+
+typedef struct _PMNT_COORD {
+ SHORT X;
+ SHORT Y;
+} PMNT_COORD;
+
+typedef struct _PMNT_MOUSE_EVENT_RECORD {
+ PMNT_COORD dwMousePosition; // PMNT_COORD instead of COORD
+ ULONG dwButtonState; // ULONG instead of DWORD
+ ULONG dwControlKeyState; // ULONG instead of DWORD
+ ULONG dwEventFlags; // ULONG instead of DWORD
+} PMNT_MOUSE_EVENT_RECORD;
+
+typedef struct _PMNT_WINDOW_BUFFER_SIZE_RECORD {
+ PMNT_COORD dwSize;
+} PMNT_WINDOW_BUFFER_SIZE_RECORD;
+
+typedef struct _PMNT_MENU_EVENT_RECORD {
+ unsigned int dwCommandId;
+} PMNT_MENU_EVENT_RECORD;
+
+typedef struct _PMNT_FOCUS_EVENT_RECORD {
+ ULONG bSetFocus; // ULONG instead of BOOL
+} PMNT_FOCUS_EVENT_RECORD;
+
+typedef struct _PMNT_INPUT_RECORD {
+ USHORT EventType;
+ union {
+ PMNT_KEY_EVENT_RECORD KeyEvent;
+ PMNT_MOUSE_EVENT_RECORD MouseEvent;
+ PMNT_WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
+ PMNT_MENU_EVENT_RECORD MenuEvent;
+ PMNT_FOCUS_EVENT_RECORD FocusEvent;
+ } Event;
+} PMNT_INPUT_RECORD;
+
+#define PMNT_KEY_EVENT 0x0001 // Event contains key event record
+#define PMNT_MOUSE_EVENT 0x0002 // Event contains mouse event record
+#define PMNT_WINDOW_BUFFER_SIZE_EVENT 0x0004 // Event contains window change event record
+#define PMNT_MENU_EVENT 0x0008 // Event contains menu event record
+#define PMNT_FOCUS_EVENT 0x0010 // event contains focus change
+
+/* Flags for the WIN32 Console mouse event mask */
+#define PMNT_MOUSE_CLICK 0x0000
+#define PMNT_MOUSE_MOVED 0x0001
+#define PMNT_DOUBLE_CLICK 0x0002
+
+#ifdef INCL_16BIT
+#pragma pack(1)
+#endif
+
+typedef struct _PM_MOUSE_INPUT_RECORD {
+ USHORT EventMask;
+ ULONG Time;
+ USHORT absY;
+ USHORT absX;
+ } PM_MOUSE_INPUT_RECORD;
+
+#define PMNT_SQ_KBD 1 /* See ..\h\pmwinp.h, SQ_XXX */
+#define PMNT_SQ_MOU 2
+
+typedef struct _PM_INPUT_RECORD {
+ USHORT EventType;
+ union
+ {
+ PM_KEY_INPUT_RECORD KeyEvent;
+ PM_MOUSE_INPUT_RECORD MouseEvent;
+ } Event;
+} PM_INPUT_RECORD;
+
+#ifdef INCL_16BIT
+#pragma pack ()
+#endif
+
+
+#ifdef INCL_16BIT
+#pragma pack (4) /* Because structures are aligned to DWORD in 32-bit DLL */
+#endif
+
+#ifndef INCL_16BIT
+#if DBG
+#define KdPrint(_x_) DbgPrint _x_
+#else
+#define KdPrint(_x_)
+#endif // else of DBG
+#endif // else of INCL_16BIT
+
+/***************************************************************************/
+/* PMNTDD.SYS definitions */
+/***************************************************************************/
+
+#define IOCTL_PMNT_IO_MAP 0L
+#define IOCTL_PMNT_MEM_MAP 1L
+#define IOCTL_PMNT_REGISTER_HARDWARE 2L
+
+#ifndef INCL_16BIT
+#include "devioctl.h"
+
+#define PMNTDD_DEVICE_TYPE FILE_DEVICE_BEEP
+
+#define PMNTDD_DEVICE_NAME "\\Device\\PMNTDD"
+#define PMNTDD_DEVICE_NAME_U L"\\Device\\PMNTDD"
+
+#define IOCTL_PMNTDD_IO_MAP CTL_CODE((unsigned long)PMNTDD_DEVICE_TYPE, IOCTL_PMNT_IO_MAP, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_PMNTDD_MEM_MAP CTL_CODE((unsigned long)PMNTDD_DEVICE_TYPE, IOCTL_PMNT_MEM_MAP, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_PMNTDD_REGISTER_HARDWARE \
+ CTL_CODE((unsigned long)PMNTDD_DEVICE_TYPE, IOCTL_PMNT_REGISTER_HARDWARE, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#endif // ndef INCL_16BIT
+
+/* Data types for the PMNTRegisterDisplayHardware routine */
+
+#define PMNT_IOPM_DATA_TYPE_PORT 0L
+#define PMNT_IOPM_DATA_TYPE_MEMORY 1L
+
+typedef struct _PMNT_IOPM_DATA_ENTRY {
+ ULONG Base;
+ ULONG Length;
+} PMNT_IOPM_DATA_ENTRY, *PPMNT_IOPM_DATA_ENTRY;
+
+typedef struct _PMNT_IOPM_DATA {
+ ULONG EntryType; // PMNT_IOPM_DATA_TYPE_PORT or PMNT_IOPM_DATA_TYPE_MEMORY
+ ULONG NumEntries;
+ PMNT_IOPM_DATA_ENTRY Entry[1];
+} PMNT_IOPM_DATA, *PPMNT_IOPM_DATA;
+
+typedef struct _PMNT_IOPM_IOCTL_DATA
+{
+ ULONG ThreadHandle;
+ PMNT_IOPM_DATA DriverData;
+} PMNT_IOPM_IOCTL_DATA, *PPMNT_IOPM_IOCTL_DATA;
+
+/* Data types for the PMNTMemMap routine */
+
+//BUGBUG - needed anymore ???
+typedef struct _PMNT_MEM_DATA
+{
+ ULONG PhysicalAddress;
+ ULONG VirtualAddress;
+ ULONG Length;
+} PMNT_MEM_DATA, *PPMNT_MEM_DATA;
+
+typedef struct _PMNT_MEMMAP_RESULTS
+{
+ ULONG VirtualAddress;
+ ULONG Length;
+} PMNT_MEMMAP_RESULTS;
+
+/* Data structure for passing parameters to PMNTDD.SYS via PMNT.DLL */
+typedef struct _PMNT_IOCTL_DD_IOCTL_PARAMS
+{
+ ULONG Request;
+ ULONG InputBuffer;
+ ULONG InputBufferLength;
+ ULONG OutputBuffer;
+ ULONG OutputBufferLength;
+} PMNT_IOCTL_DD_IOCTL_PARAMS;
+
+/* IOCTL codes for the PMNT.DLL PMNTIOCTL service */
+#define PMNT_IOCTL_DD_IOCTL 2 /* PMNTDD.SYS IOCTL services */
+#define PMNT_IOCTL_DUMP_SEGMENT_TABLE 3 /* Debug service - dump segment table */
+#define PMNT_IOCTL_HIDE_WIN32_WINDOW 4 /* Hide WIN32 Console window - for CBA */
+
+#ifdef INCL_16BIT
+#pragma pack () /* Restore default */
+#endif
+
+#ifdef INCL_16BIT
+/***************************************************************************/
+/* PMNT.DLL exported services which can be called directly without using */
+/* PMNT.LIB. */
+/***************************************************************************/
+extern VOID APIENTRY PMNTSetFullScreen(USHORT Register);
+extern USHORT APIENTRY PMNTGetWin32Hwnd(ULONG far *pWin32ShellHwnd);
+extern USHORT APIENTRY PMNTSetFocus(ULONG Win32Hwnd);
+extern USHORT APIENTRY PMNTCloseWindow(VOID);
+extern USHORT APIENTRY PMNTGetNextEvent(PMNT_INPUT_RECORD far *ppm_input_rec);
+extern USHORT APIENTRY PMNTGetPgmName(char far *Buffer, short BufferLength);
+extern USHORT APIENTRY PMNTSetConsoleTitle(PSZ Buffer);
+extern USHORT APIENTRY PMNTGetFullScreen(ULONG Operation);
+extern USHORT APIENTRY PMNTIOCTL(USHORT req, PVOID pin, PVOID pout);
+extern VOID APIENTRY PMNTDbgPrint(PSZ str, ULONG l1, ULONG l2, ULONG l3, ULONG l4);
+extern USHORT APIENTRY PMNTMemMap(PUSHORT PSel);
+extern USHORT APIENTRY PMNTSetPMshellFlag(VOID);
+extern VOID APIENTRY PMNTGetSystemTime(PULONG pTime);
+extern USHORT APIENTRY PMNTRegisterDisplayAdapter(PMNT_IOPM_DATA far *MemoryRange, PMNT_IOPM_DATA far *IORange, USHORT col, USHORT row);
+extern USHORT APIENTRY PMNTIOMap(VOID);
+extern USHORT APIENTRY PMNTIsSessionRoot(VOID);
+extern USHORT APIENTRY PMNTIdentifyCodeSelector( USHORT, PVOID );
+extern USHORT APIENTRY PMNTCreateHiddenThread(PVOID pfnFun, PUSHORT pTid, PBYTE pbStack);
+extern USHORT APIENTRY PMNTProcessIsPMShell(VOID);
+extern USHORT APIENTRY PMNTQueryScreenSize(PUSHORT xRight, PUSHORT yTop);
+extern USHORT APIENTRY PMNTCreateFontIndirect(PVOID lplf);
+extern USHORT APIENTRY PMNTGetTextMetrics(ULONG ulFont, PVOID lptm);
+extern USHORT APIENTRY PMNTGetStringBitmap(ULONG ulFont, PSZ lpszStr, ULONG cbStr, ULONG cbData, PVOID lpSB);
+extern USHORT APIENTRY PMNTDeleteObject(ULONG ulFont);
+extern USHORT APIENTRY PMNTGetEUDCTimeStamp(VOID);
+extern USHORT APIENTRY PMNTDisableWin32IME(VOID);
+extern USHORT APIENTRY PMNTSetShutdownPriority(ULONG NewPriority, USHORT Disable);
+
+/***************************************************************************/
+/* Services provided by PMNT.LIB */
+/***************************************************************************/
+extern VOID _cdecl far PMNTPrint(PSZ str, ...);
+extern USHORT _cdecl far PMNTCreateThread(PFN Thread, USHORT StackSize);
+#endif // INCL_16BIT
+
+#ifdef INCL_32BIT
+/* Values returned by the server to specify type of application loaded */
+#define APPTYPE_CHARMODE 0
+#define APPTYPE_PM 1
+#define APPTYPE_PMSHELL 2
+#define APPTYPE_PMSHELL_CHILD 4
+
+extern ULONG PMFlags;
+
+#define ProcessIsPMProcess() (PMFlags & APPTYPE_PM)
+#define ProcessIsPMShell() (PMFlags & APPTYPE_PMSHELL)
+#define ProcessIsPMApp() (ProcessIsPMProcess() && !ProcessIsPMShell())
+#define ProcessIsPMShellChild() (PMFlags & APPTYPE_PMSHELL_CHILD)
+#define SetPMShellFlag() PMFlags |= APPTYPE_PMSHELL;
+#define SetPMAppFlag() PMFlags |= APPTYPE_PM;
+
+/***************************************************************************/
+/* PM\NT specific error codes and popup */
+/***************************************************************************/
+#define ERROR_PMSHELL_NOT_UP 0xff01
+#define ERROR_2ND_PMSHELL 0xff02
+#define ERROR_PMSHELL_FULLSCREEN 0xff03
+extern VOID Ow2PMShellErrorPopup(PSZ AppName,int rc);
+#endif //INCL_32BIT
+
+#endif /* _PMNTINCLUDE_ */
diff --git a/private/os2/inc/sesgrp.h b/private/os2/inc/sesgrp.h
new file mode 100644
index 000000000..4ca436494
--- /dev/null
+++ b/private/os2/inc/sesgrp.h
@@ -0,0 +1,180 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ sesgrp.h
+
+Abstract:
+
+ This module defines the OS/2 subsystem memory view of Session-Group
+
+Author:
+
+ Michael Jarus (mjarus) 20-Nov-1991
+
+Revision History:
+
+--*/
+
+
+/*
+ * This file defines the SesGrp : a section, which holds all common
+ * parameters for the entire session (SES_GROUP).
+ *
+ * It's initilized to zero by the os2srv (which also init the NLS and
+ * some other parameters).
+ *
+ * Parameters can be put into SesGrp in os2ses/client only after it
+ * gets the section from the os2srv (after ntinitss.CtrlListen is called).
+ */
+
+typedef struct _OS2_SES_GROUP_PARMS
+{
+ USHORT FirstProcess;
+ ULONG InTermination;
+
+ HANDLE LockProcess;
+ ULONG PrinterMonitor;
+ ULONG OutputModeFlags; // Console Output Mode
+ ULONG DefaultWinOutputMode; // Default Win Console Input Mode
+ ULONG WinProcessNumberInSession;
+ ULONG WinSyncProcessNumberInSession;
+
+ /*
+ * handles (and flags) for in/out/Std,
+ */
+
+ HANDLE hConsoleInput;
+ HANDLE hConsoleOutput;
+ HANDLE StdIn;
+ HANDLE StdOut;
+ HANDLE StdErr;
+ USHORT StdInFlag; // TRUE if console (not redirected)
+ USHORT StdOutFlag;
+ USHORT StdErrFlag;
+ USHORT StdInFileType; // FileType for HandleTable
+ USHORT StdOutFileType;
+ USHORT StdErrFileType;
+ USHORT StdInHandleCount; // Count of open handle
+ USHORT StdOutHandleCount;
+ USHORT StdErrHandleCount;
+
+ /*
+ * VIO Parameters
+ */
+
+ ULONG PauseScreenUpdate;
+ USHORT BytesPerCell;
+ USHORT VioLengthMask;
+ WCHAR WinSpaceChar;
+ WCHAR WinBlankChar;
+ VIOMODEINFO Os2ModeInfo;
+ SHORT MinRowNum;
+ SMALL_RECT ScreenRect; // Screen Rect for WriteConsoleOutput
+ VIOCURSORINFO CursorInfo; // Cursor Info
+ SHORT ScreenColNum; // col number
+ SHORT ScreenRowNum; // row number
+ ULONG ScreenSize; // screen size in bytes
+ SHORT CellHSize; // Horizontal Cell size
+ SHORT CellVSize; // Vertical Cell size
+ USHORT VioLength2CellShift;
+ ULONG dwWinCursorSize;
+ BOOLEAN bWinCursorVisible;
+
+ /*
+ * TTY Parameters
+ */
+
+ ULONG AnsiMode; // state of AnsiFlag
+ UCHAR AnsiCellAttr[3]; // attribute of TTY (3 bytes for MSKK)
+ UCHAR ansi_base;
+ UCHAR ansi_foreground;
+ UCHAR ansi_background;
+ UCHAR ansi_reverse;
+ UCHAR ansi_bold;
+ UCHAR ansi_cancel;
+ UCHAR ansi_faint;
+ UCHAR ansi_italic;
+ UCHAR ansi_blink;
+ UCHAR ansi_blue;
+ COORD WinCoord;
+ USHORT WinAttr;
+
+ /*
+ * LVB Parameters
+ */
+
+ ULONG MaxLVBsize;
+ ULONG LVBsize;
+ BOOLEAN LVBOn;
+
+ /*
+ * POPUP Parameters
+ */
+
+ HANDLE hConsolePopUp;
+ HANDLE PopUpProcess;
+ USHORT PopUpFlag;
+
+ /*
+ * Kbd parameters
+ */
+
+ ULONG KbdInFocus;
+ PVOID PhyKbd;
+ ULONG KeysOnFlag;
+ ULONG KeyboardCountry;
+ ULONG KeyboardType;
+ USHORT NoKbdFocus;
+ USHORT ModeFlag; // 0 - ASCII, 1 - Binary
+
+ /*
+ * NLS definitions.
+ * If you add anything or change the order, do it also in server\srvnls.c
+ */
+
+ ULONG Os2srvUseRegisterInfo; // set when NLS parms are from the registry
+ // reset when they are inherit from Win32
+ ULONG Win32CountryCode; // Win32 NLS parms: country code
+ ULONG Win32OEMCP; // OEM CP
+ ULONG Win32ACP; // ACP
+ ULONG Win32LANGID; // LANGID
+ ULONG Win32LCID; // LCID
+ ULONG CountryCode; // Os2ss NLS parms: country code
+ ULONG DosCP; // Dos CP
+ ULONG PrimaryCP; // Primary CP
+ ULONG SecondaryCP; // Secondary CP
+ ULONG VioCP; // Vio CP
+ ULONG KbdCP; // Kbd CP
+ ULONG Os2ssLCID; // LCID
+ ULONG LanguageID; // message file LanguageID
+ UCHAR KeyboardLayout[2]; // Keyboard Layout
+#if PMNT
+ UCHAR KeyboardName[4]; // Keyboard Name
+#endif // PMNT
+ OD2_DBCS_VECTOR_ENTRY PriDBCSVec;
+ OD2_DBCS_VECTOR_ENTRY SecDBCSVec;
+ UCHAR PriCollateTable[256]; // Primary Collate Table
+ UCHAR SecCollateTable[256]; // Secondary Collate Table
+ UCHAR PriCaseMapTable[256]; // Primary Case Map Table
+ UCHAR SecCaseMapTable[256]; // Secondary Case Map Table
+ COUNTRYINFO CountryInfo; // Country Info
+ ULONG DBCSCountryFlag; //
+ UCHAR SystemDirectory[CCHMAXSYSTEMPATH];
+
+ /*
+ * End of NLS definitions.
+ */
+
+} OS2_SES_GROUP_PARMS, *POS2_SES_GROUP_PARMS;
+
+ /*
+ * KeyboardType
+ */
+
+#define OS2SS_EN_KBD 0
+#define OS2SS_AT_KBD 1
+#define OS2SS_ENNEW_KBD 2
+
diff --git a/private/os2/inc/sesport.h b/private/os2/inc/sesport.h
new file mode 100644
index 000000000..408337946
--- /dev/null
+++ b/private/os2/inc/sesport.h
@@ -0,0 +1,659 @@
+
+#ifndef _SESPORT_
+
+#define _SESPORT_
+
+#ifndef _WINCON_
+
+typedef struct _COORD
+{
+ SHORT X; /* Row */
+ SHORT Y; /* Col */
+} COORD, *PCOORD;
+
+typedef struct _SMALL_RECT
+{
+ SHORT Left;
+ SHORT Top;
+ SHORT Right;
+ SHORT Bottom;
+} SMALL_RECT, *PSMALL_RECT;
+
+#endif /* _WINCON_ */
+
+#include "os2sub.h"
+#include "os2nls.h"
+#include "sesgrp.h"
+#ifndef BYTE
+typedef UCHAR BYTE;
+#endif
+#ifndef PBYTE
+typedef UCHAR *PBYTE;
+#endif
+#include "os2dev.h"
+
+//#include "wincon.h" should be called by the caller to this
+/* this files need to be included if NTOS2_ONLY macro doesn't protect
+ * tructures with PORT_MESSAGE:
+ *
+ * #include <ntdef.h>
+ * #include <ntkeapi.h>
+ * #include <ntseapi.h>
+ * #include <ntpsapi.h>
+ * #include <ntlpcapi.h>
+ */
+
+#define U_OS2_SS_INITIALIZATION_EVENT L"OS2SSINITIALIZATIONEVENT"
+
+/*
+ * os2srv port to accept all requests (CON and API) from clients
+ */
+
+#define U_OS2_SS_SESSION_PORT_NAME L"\\OS2SS\\SESPORT"
+
+/*
+ * Session sections and port
+ *
+ * Each session is identified by an unique id (which is define by the os2srv).
+ * For each session, the OS2 creates:
+ *
+ * - Section to hold all common parameters - SES_GROUP (G)
+ * - Port for all input requests (i.e. KBD, MOU and MON) to get to the
+ * first OS2.EXE in the session from all processes in that session (P).
+ * - Section to serve as the LVB (L)
+ */
+
+#define U_OS2_SES_BASE_PORT_NAME L"\\OS2SS\\OS2SES"
+#define U_OS2_SES_BASE_PORT_NAME_LENGTH 32
+#define U_OS2_SES_BASE_PORT_PREFIX L'P' // Port
+#define U_OS2_SES_BASE_DATA_PREFIX L'D' // Data
+#define U_OS2_SES_GROUP_PREFIX L'G' // Session Group Data
+#define U_OS2_SES_BASE_LVB_PREFIX L'L' // LVB
+#define U_OS2_SES_PAUSE_EVENT_PREFIX L'S' // ^S (pause)
+#define U_OS2_SES_CTRL_PORT_SEMAPHORE_PREFIX L'T' // Data Section Semaphore
+#define U_OS2_SES_KBD_PORT_SEMAPHORE_PREFIX L'K' // Kbd Port(requests) Semaphore
+#define U_OS2_SES_MOU_PORT_SEMAPHORE_PREFIX L'M' // Mou Port(requests) Semaphore
+#define U_OS2_SES_KBD_FOCUS_SEMAPHORE_PREFIX L'F' // KbdGetFocus(logical)
+#define U_OS2_SES_POPUP_SEMAPHORE_PREFIX L'O' // PopUp
+#define U_OS2_SES_SLOCK_SEMAPHORE_PREFIX L'C' // Screen Lock
+#define U_OS2_SES_STD_HANDLE_LOCK_PREFIX L'H' // STD-handle lock
+#define U_OS2_SES_VIOWRITE_SEMAPHORE_PREFIX L'W' // Vio Write mutex
+
+#define CONSTRUCT_U_OS2_SES_NAME(Name_U, t, id) \
+ { \
+int __cdecl wsprintfW(LPWSTR, LPCWSTR, ...); \
+ \
+ wsprintfW(Name_U, L"%s\\%c%d", \
+ U_OS2_SES_BASE_PORT_NAME, t, id); \
+ }
+
+/*
+ * max message size
+ */
+
+#define OS2_CON_PORT_MSG_SIZE 0x10000L
+#define OS2_KBD_PORT_MSG_SIZE 0x200
+#define OS2SES_CTRL_SECTION_SIZE (OS2_CON_PORT_MSG_SIZE + OS2_KBD_PORT_MSG_SIZE)
+#define KBD_OFFSET OS2_CON_PORT_MSG_SIZE
+
+#define OS2SES_GROUP_SECTION_SIZE sizeof(OS2_SES_GROUP_PARMS)
+
+/*
+ * section size
+ *
+ * The OS2_Ses_BASE_DATA section is combined from the following:
+ *
+ * - OS2_CON_PORT_MSG_SIZE bytes : data passed between os2.exe and client
+ * - OS2_KBD_PORT_MSG_SIZE bytes : kbd data passed from os2.exe to client
+ */
+
+#define OS2_MAX_APPL_NAME 13
+
+/*
+ * Session Console ConnectInfo struct
+ */
+
+typedef struct _SCCONNECTINFO
+{ int dummy;
+} SCCONNECTINFO, *PSCCONNECTINFO;
+
+typedef struct _VIOSCROLL
+{ SMALL_RECT ScrollRect;
+ SHORT cbLines;
+ UCHAR Cell[4];
+} VIOSCROLL, *PVIOSCROLL;
+
+typedef enum
+{
+ VIOWrtTTY,
+ VIOWrtStdOut,
+ VIOWrtStdErr,
+ VIOWrtScreen
+} VIOREQUESTNUMBER;
+
+/* -------- End of Vio Requests section -------- */
+
+/*
+ * Kbd requests
+ */
+
+typedef enum
+{ KBDOpen,
+ KBDClose,
+ KBDDupLogHandle,
+ KBDNewFocus,
+ KBDFreeFocus,
+ KBDCharIn,
+ KBDStringIn,
+ KBDPeek,
+ KBDFlushBuffer,
+ KBDReadStdIn,
+ KBDRead,
+ KBDGetStatus,
+ KBDSetStatus,
+ KBDXlate,
+ KBDGetCp,
+ KBDSetCp,
+ KBDSetCustXt,
+ KBDGetInputMode,
+ KBDGetInterimFlag,
+ KBDGetKbdType,
+ KBDGetHotKey,
+ KBDGetShiftState,
+ KBDSetInputMode,
+ KBDSetShiftState,
+ KBDSetTypamaticRate,
+ KBDSetInTerimFlag,
+ KBDNewCountry
+} KBDREQUESTNUMBER;
+
+typedef struct _KBDREQUEST
+{ KBDREQUESTNUMBER Request;
+ HANDLE hKbd;
+ ULONG fWait;
+ ULONG Length; /* Length for string R/W */
+ union
+ { KBDKEYINFO KeyInfo;
+ STRINGINBUF String;
+ KBDINFO KbdInfo;
+ KBDTRANS KbdTrans;
+ ULONG CodePage;
+ UCHAR InputMode;
+ UCHAR Interim;
+ SHIFTSTATE Shift;
+#ifdef JAPAN
+// MSKK May.07.1993 V-AkihiS
+ USHORT KbdType[3];
+#else
+ USHORT KbdType;
+#endif
+ UCHAR HotKey[8];
+ RATEDELAY RateDelay;
+ } d;
+} KBDREQUEST, *PKBDREQUEST;
+
+/* -------- End of Kbd Requests section -------- */
+
+/*
+ * Mou requests
+ */
+
+typedef enum
+{
+ MOUOpen,
+ MOUClose,
+ MOUReadEventQue,
+ MOUFlushQue,
+ MOUGetNumQueEl,
+ MOUDrawPtr,
+ MOURemovePtr,
+ MOUGetDevStatus,
+ MOUSetDevStatus,
+ MOUGetEventMask,
+ MOUSetEventMask,
+ MOUGetNumButtons,
+ MOUGetNumMickeys,
+ MOUGetPtrPos,
+ MOUSetPtrPos,
+ MOUGetPtrShape,
+ MOUSetPtrShape,
+ MOUGetScaleFact,
+ MOUSetScaleFact
+} MOUREQUESTNUMBER;
+
+typedef struct _MOUREQUEST
+{ MOUREQUESTNUMBER Request;
+ HANDLE hMOU;
+ USHORT fWait;
+ union
+ { ULONG Setup; /* according to API: DevStatus, EventMask,
+ #Buttoms, #Mickeys */
+ PTRLOC Loc;
+ PTRSHAPE Shape;
+ SCALEFACT ScalFact;
+ MOUEVENTINFO MouInfo;
+ NOPTRRECT NoPtrRect;
+ MOUQUEINFO NumEvent;
+ } d;
+} MOUREQUEST, *PMOUREQUEST;
+
+/* -------- End of Mou Requests section -------- */
+
+/*
+ * Mon requests
+ */
+
+#define MON_BUFFER_SIZE 80
+
+typedef enum
+{ KbdDevice,
+ MouseDevice,
+ Lpt1Device,
+ Lpt2Device,
+ Lpt3Device
+} MONDEVNUMBER;
+
+typedef enum
+{ MONOpen,
+ MONReg,
+ MONRead,
+ MONWrite,
+ MONClose
+} MONREQUESTNUMBER;
+
+typedef struct _MON_OC
+{
+ HANDLE hMON;
+ MONDEVNUMBER MonDevice;
+} MON_OC, *PMON_OC;
+
+typedef struct _MON_REG
+{
+ ULONG Pos;
+ ULONG Index;
+ USHORT InSize;
+ USHORT OutSize;
+ PVOID In;
+ PVOID Out;
+ ULONG ProcessId;
+ HANDLE hMON;
+} MON_REG, *PMON_REG;
+
+typedef struct _MON_RW
+{
+ ULONG ProcessId;
+ USHORT Length;
+ PVOID MonBuffer;
+ USHORT fWait;
+ UCHAR ioBuff[MON_BUFFER_SIZE];
+} MON_RW, *PMON_RW;
+
+typedef struct _MONREQUEST
+{ MONREQUESTNUMBER Request;
+ union
+ {
+ MON_OC OpenClose;
+ MON_REG Reg;
+ MON_RW rwParms;
+ } d;
+} MONREQUEST, *PMONREQUEST;
+
+/* -------- End of Mon Requests section -------- */
+
+/*
+ * Net requests
+ */
+
+typedef enum {
+ NETGetDCName,
+ NETHandleGetInfo,
+ NETServerDiskEnum,
+ NETServerEnum2,
+ NETServerGetInfo,
+ NETServiceControl,
+ NETServiceEnum,
+ NETServiceGetInfo,
+ NETServiceInstall,
+ NETShareEnum,
+ NETShareGetInfo,
+ NETUseAdd,
+ NETUseDel,
+ NETUseEnum,
+ NETUseGetInfo,
+ NETUserEnum,
+ NETUserGetInfo,
+ NETWkstaGetInfo,
+ NETAccessAdd,
+ NETAccessSetInfo,
+ NETAccessDel,
+ NETShareAdd,
+ NETShareDel,
+ NETBios
+} NETREQUESTNUMBER;
+
+#define MAXNETMSGSIZE 64
+
+typedef struct _NETREQUEST {
+ NETREQUESTNUMBER Request;
+ char d[MAXNETMSGSIZE];
+} NETREQUEST, *PNETREQUEST;
+
+/* -------- End of Net Requests section -------- */
+
+/*
+ * Console requests
+ * these are mapped 1-1 to the win32 Console services
+ */
+
+
+#define OS2SS_IDABORT 3
+#define OS2SS_IDRETRY 4
+#define OS2SS_IDIGNORE 5
+
+/*
+ * Prt requests
+ */
+
+#define OS2_MAX_PRT_NAME 10
+
+typedef enum
+{ PRTOpen,
+ PRTClose,
+ PRTWrite,
+ PRTRead // BUGBUG: do we need it ?
+} PRTREQUESTNUMBER;
+
+typedef struct _PRTWRITE
+{ ULONG Length; /* Length for string R/W */
+ PVOID Offset;
+} PRTWRITE;
+
+typedef struct _PRTOPEN
+{ ULONG Attribute;
+ ULONG OpenFlags;
+ ULONG OpenMode;
+ ULONG Action;
+ UCHAR PrinterName[OS2_MAX_PRT_NAME];
+} PRTOPEN, *PPRTOPEN;
+
+typedef struct _PRTREQUEST
+{ PRTREQUESTNUMBER Request;
+ HANDLE hPrinter;
+ union
+ { PRTOPEN Open;
+ PRTWRITE Write;
+ } d;
+} PRTREQUEST, *PPRTREQUEST;
+
+/* -------- End of Prt Requests section -------- */
+
+/*
+ * TaskManager requests
+ */
+
+typedef enum
+{ TmExit,
+ TmTitle,
+ TmReleaseLPC
+} SCTMREQUESTNUMBER;
+
+
+typedef struct
+{ SCTMREQUESTNUMBER Request;
+ ULONG ExitResults;
+ CHAR ErrorText[50];
+} SCTMREQUEST, *PSCTMREQUEST;
+
+
+/* -------- End of TaskManager Requests section -------- */
+
+typedef enum _EXECREQUESTNUMBER
+{ RemoveConsoleThread,
+ RestartConsoleThread,
+ AddWin32ChildProcess,
+ RemWin32ChildProcess
+} EXECREQUESTNUMBER;
+
+
+typedef struct _WINEXECPGM_MSG
+{
+ EXECREQUESTNUMBER Request;
+} WINEXECPGM_MSG, *PWINEXECPGM_MSG;
+
+/* -------- End of CreateProcess Requests section -------- */
+
+#ifdef DBCS
+// MSKK Dec.18.1992 V-AkihiS
+// Support IMMON API
+/*
+ * IMMon requests
+ */
+
+typedef enum
+{ IMMONStatus,
+ IMMONActive,
+ IMMONInactive
+} IMMONREQUESTNUMBER;
+
+#pragma pack(1)
+typedef struct _MONINSBLK
+{
+ USHORT cb;
+ ULONG ulReserved1;
+ ULONG ulReserved2;
+ ULONG ulReserved3;
+} MONINSBLK, *PMONINSBLK;
+
+typedef struct _MONSTATBLK
+{
+ USHORT cb;
+ USHORT usInfoLevel;
+ PUCHAR pInfoBuf;
+ USHORT cbInfoBuf;
+} MONSTATBLK, *PMONSTATBLK;
+#pragma pack()
+
+typedef struct _IMMONREQUEST
+{ IMMONREQUESTNUMBER Request;
+ union
+ { MONSTATBLK MonStatBlk;
+ } d;
+} IMMONREQUEST, *PIMMONREQUEST;
+
+/* -------- End of IMMON Requests section -------- */
+#endif
+
+/*
+ * Os2Ses requests:
+ * Request for CONSOLE services from OS2 SS and OS2 clients to the console
+ * process
+ */
+
+typedef enum _SCREQUESTNUMBER
+{ KbdRequest,
+ MouRequest,
+ MonRequest,
+ NetRequest,
+ TaskManRequest,
+ WinCreateProcess,
+ PrtRequest
+#ifdef DBCS
+// MSKK Dec.18.1992 V-AkihiS
+ ,
+ ImmonRequest
+#endif
+} SCREQUESTNUMBER;
+
+#ifdef NTOS2_ONLY
+
+typedef struct _SCREQUESTMSG
+{ PORT_MESSAGE h;
+ union {
+ SCCONNECTINFO ConnectionRequest;
+ struct {
+ SCREQUESTNUMBER Request;
+ NTSTATUS Status; // returned status for the request.
+ PVOID DataPointer; // for read/write
+ union {
+ KBDREQUEST Kbd;
+ MOUREQUEST Mou;
+ MONREQUEST Mon;
+ NETREQUEST Net;
+ SCTMREQUEST Tm;
+ WINEXECPGM_MSG WinExecPgm;
+ PRTREQUEST Prt;
+#ifdef DBCS
+// MSKK Dec.18.1992 V-AkihiS
+ IMMONREQUEST Immon;
+#endif
+ } d;
+ };
+ };
+} SCREQUESTMSG, *PSCREQUESTMSG;
+
+#endif // NTOS2_ONLY
+
+#define OS2_SS_VERSION 0x00000201
+
+/*
+ * OS2 SS Session ConnectInfo struct
+ */
+
+typedef union _OS2SESCONNECTINFO {
+ struct {
+ int SessionDbg;
+ ULONG ExpectedVersion;
+ HANDLE Win32ForegroundWindow;
+ } In;
+
+ struct {
+ ULONG Os2SrvId;
+ ULONG SessionUniqueID; // unique ID of the ssesion
+ ULONG ProcessUniqueID;
+ ULONG IsNewSession; // see definitions below
+ ULONG CurrentVersion;
+ ULONG Od2Debug;
+ } Out;
+
+} OS2SESCONNECTINFO, *POS2SESCONNECTINFO;
+
+/*
+ * IsNewSession definitions
+ *
+ * 0 - child process, 1 - new session, 2 - child session
+ */
+
+#define OS2SS_CHILD_PROCESS 0
+#define OS2SS_NEW_SESSION 1
+#define OS2SS_CHILD_SESSION 2
+
+#define OS2SS_IS_SESSION(SessionFlag) \
+ (((SessionFlag) == OS2SS_NEW_SESSION) || \
+ ((SessionFlag) == OS2SS_CHILD_SESSION))
+
+#define OS2SS_IS_PROCESS(SessionFlag) \
+ ((SessionFlag) == OS2SS_CHILD_PROCESS)
+
+#define OS2SS_IS_NEW_SESSION(SessionFlag) \
+ ((SessionFlag) == OS2SS_NEW_SESSION)
+
+/*
+ * Os2 SS Session requests
+ * Requests from the session console process (OS2SES.EXE) to the OS2 SS
+ * e.g. Create session, CtrlBreak, etc.
+ */
+
+typedef enum _OS2SESREQUESTNUMBER {
+ SesCheckPortAndConCreate,
+ SesConCreate,
+ SesConSignal,
+ SesConFocus,
+ SesNetBiosPost
+} OS2SESREQUESTNUMBER;
+
+typedef struct {
+ union
+ {
+ struct
+ {
+ HANDLE hEventThread;
+ HANDLE hSessionRequestThread;
+ HANDLE hProcess;
+ HANDLE hThread;
+ PVOID SignalDeliverer;
+ PVOID ExitListDispatcher;
+ PVOID InfiniteSleep;
+ PVOID FreezeThread;
+ PVOID UnfreezeThread;
+ PVOID VectorHandler;
+ PVOID CritSectionAddr;
+ PVOID ClientPib;
+ PVOID ClientOs2Tib;
+ ULONG InitialPebOs2Length;
+ //ULONG SessionUniqueId;
+ ULONG IsNewSession; // see definitions in OS2SESCONNECTINFO
+ UCHAR ApplName[OS2_MAX_APPL_NAME];
+ } In;
+ struct
+ {
+ HANDLE DeviceDirectory;
+ HANDLE CtrlPortHandle;
+ ULONG BootDrive;
+ ULONG SystemDrive;
+ ULONG SessionNumber;
+ PVOID GInfoAddr;
+ ULONG InitialPebOs2Data[12];
+ ULONG Os2TibThreadId; /* Os2Tib: OS/2 ID for the thread */
+ ULONG Os2TibVersion; /* Os2Tib: Version number for this structure */
+ HANDLE PibProcessId; /* Pib: Process I.D. */
+ HANDLE PibParentProcessId; /* Pib: Parent process I.D. */
+ HANDLE PibImageFileHandle; /* Pib: Program (.EXE) module handle */
+ ULONG PibStatus; /* Pib: Process Status */
+ ULONG PibType; /* Pib: Process Type */
+ } Out;
+ } d;
+} SCREQ_CREATE, *PSCREQ_CREATE;
+
+typedef struct {
+ int Type;
+} SCREQ_SIGNAL;
+
+typedef struct {
+ ULONG AppNcbAddr;
+ ULONG AppPostAddr;
+ ULONG RetCode;
+} SCREQ_NETBIOS;
+
+#ifdef NTOS2_ONLY
+
+typedef struct _OS2SESREQUESTMSG {
+ PORT_MESSAGE h;
+ union {
+ OS2SESCONNECTINFO ConnectionRequest;
+ struct {
+ ULONG PortType; // 0 - ApiPort in server; 1 - this port.
+ HANDLE Session;
+ OS2SESREQUESTNUMBER Request;
+ NTSTATUS Status;
+ union {
+ SCREQ_CREATE Create;
+ SCREQ_SIGNAL Signal;
+ ULONG FocusSet;
+ SCREQ_NETBIOS NetBios;
+ } d;
+ };
+ };
+} OS2SESREQUESTMSG, *POS2SESREQUESTMSG;
+
+#endif // NTOS2_ONLY
+
+
+/*
+ * Common macros to access PORT_MESSAGE fields
+ */
+#define PORT_MSG_TYPE(m) ((m).h.u2.s2.Type)
+#define PORT_MSG_DATA_LENGTH(m) ((m).h.u1.s1.DataLength)
+#define PORT_MSG_TOTAL_LENGTH(m) ((m).h.u1.s1.TotalLength)
+#define PORT_MSG_ZERO_INIT(m) ((m).h.u2.ZeroInit)
+
+#endif // _SESPORT_
diff --git a/private/os2/ldr/basedef.h b/private/os2/ldr/basedef.h
new file mode 100644
index 000000000..15de3ae40
--- /dev/null
+++ b/private/os2/ldr/basedef.h
@@ -0,0 +1,233 @@
+/*static char *SCCSID = "@(#)basedef.h 6.1 90/11/15";*/
+/*** BASEDEF.H
+ *
+ * SCCSID = @(#)basedef.h 13.11 90/07/10
+ *
+ * Basic constants and types
+ * Copyright (c) 1988,1989 Microsoft Corporation
+ *
+ *
+ * MODIFICATION HISTORY
+ * 10/10/88 JTP Created.
+ * 10/11/88 JTP Added more base types.
+ *
+ * To control what is included use the following:
+ *
+ * INCL_TYPES basic typedefs
+ */
+
+
+/*** Basic constants
+ */
+
+//c-begin
+#include <os2std.h>
+//c-end
+
+//masm-begin
+//NULL equ 0
+//TRUE equ -1
+//FALSE equ 0
+//masm-end
+
+#define CTRUE 1
+
+#define KSIZE 1024
+
+#ifdef INCL_PAGE
+#define PAGESIZE 4096
+#endif
+
+
+/*** Basic data types
+ */
+
+//c-begin
+#define CDECL _cdecl
+#define PASCAL _pascal
+#define VOID void
+#define CONST const
+#define VOLATILE volatile
+
+#ifdef M_I386
+#define FAR _near // p (32-bit pointer)
+#define NEAR _near // np (near pointer)
+#define FAR32 _far // fp (48-bit pointer, restricted)
+#else
+#define FAR _far
+#define NEAR _near
+#endif
+//c-end
+
+//masm-begin
+//DefType VOID
+//masm-end
+
+#define CENTRY CDECL FAR // to declare misc. C-based interfaces
+#define PRIVENTRY PASCAL FAR // to declare private routines
+#define EXPENTRY PASCAL FAR // to declare exported routines
+#define API32ENTRY PASCAL FAR // to declare exported API routines
+#define DYNENTRY PASCAL FAR _export // to declare exported dynlink routines
+
+#ifdef INCL_TYPES
+
+typedef int INT; // i
+typedef unsigned int UINT; // u
+typedef INT BOOL; // f
+
+typedef unsigned char BYTE; // b
+typedef unsigned short WORD; // w
+typedef unsigned long DWORD; // dw
+
+typedef char CHAR; // ch
+typedef unsigned char UCHAR; // uch
+typedef short SHORT; // s
+typedef unsigned short USHORT; // us
+typedef long LONG; // l
+typedef unsigned long ULONG; // ul
+
+typedef UCHAR BBOOL; // bf
+typedef USHORT SBOOL; // sf
+typedef ULONG LBOOL; // lf
+
+typedef ULONG FLAGS; // fl
+typedef ULONG PORT; // port
+
+
+/*** Basic pointer types
+ */
+typedef VOID FAR *PVOID; // p
+typedef VOID NEAR *NPVOID; // np
+
+
+/*** Basic pointer-to-basic-data types
+ */
+typedef INT FAR *PINT; // pi
+typedef INT NEAR *NPINT; // npi
+
+typedef UINT FAR *PUINT; // pu
+typedef UINT NEAR *NPUINT; // npu
+
+typedef BYTE FAR *PBYTE; // pb
+typedef BYTE NEAR *NPBYTE; // npb
+
+typedef WORD FAR *PWORD; // pw
+typedef WORD NEAR *NPWORD; // npw
+
+typedef DWORD FAR *PDWORD; // pdw
+typedef DWORD NEAR *NPDWORD; // npdw
+
+typedef CHAR FAR *PCHAR; // pch
+typedef CHAR NEAR *NPCHAR; // npch
+
+typedef SHORT FAR *PSHORT; // ps
+typedef SHORT NEAR *NPSHORT; // nps
+
+typedef LONG FAR *PLONG; // pl
+typedef LONG NEAR *NPLONG; // npl
+
+typedef UCHAR FAR *PUCHAR; // puch
+typedef UCHAR NEAR *NPUCHAR; // npuch
+
+typedef USHORT FAR *PUSHORT; // pus
+typedef USHORT NEAR *NPUSHORT; // npus
+
+typedef ULONG FAR *PULONG; // pul
+typedef ULONG NEAR *NPULONG; // npul
+
+typedef BOOL FAR *PBOOL; // pf
+typedef BOOL NEAR *NPBOOL; // npf
+
+typedef BBOOL FAR *PBBOOL; // pbf
+typedef BBOOL NEAR *NPBBOOL; // npbf
+
+typedef SBOOL FAR *PSBOOL; // psf
+typedef SBOOL NEAR *NPSBOOL; // npsf
+
+typedef LBOOL FAR *PLBOOL; // plf
+typedef LBOOL NEAR *NPLBOOL; // nplf
+
+typedef FLAGS FAR *PFLAGS; // pfl
+typedef FLAGS NEAR *NPFLAGS; // npfl
+
+typedef PVOID FAR *PPVOID; // pp
+typedef PVOID NEAR *NPPVOID; // npp
+
+
+/*** Other common types (and their pointers)
+ */
+typedef BYTE BUF[]; // buf
+typedef BUF FAR *PBUF; // pbuf
+
+typedef CHAR NAM[8]; // nam
+typedef CHAR SZ[]; // sz
+typedef CHAR FAR *PSZ; // psz
+typedef CHAR NEAR *NPSZ; // npsz
+typedef CHAR SZZ[]; // szz
+typedef CHAR FAR *PSZZ; // pszz
+typedef CHAR NEAR *NPSZZ; // npszz
+
+typedef USHORT SEL; // sel
+typedef SEL FAR *PSEL; // psel
+typedef SEL NEAR *NPSEL; // npsel
+
+typedef USHORT SOFFSET; // soff
+typedef ULONG OFFSET; // off
+
+typedef ULONG PPHYS; // pphys
+
+typedef (PASCAL FAR *PFN)(); // pfn
+typedef (PASCAL NEAR *NPFN)(); // npfn
+typedef (PASCAL FAR32 *FPFN)(); // fpfn
+typedef (PASCAL FAR32 *FPVOID)(); // fp (the only kind of FPVOID allowed)
+
+typedef PFN FAR *PPFN; // ppfn
+typedef PFN NEAR *NPPFN; // nppfn
+typedef FPFN FAR *PFPFN; // pfpfn
+typedef FPFN NEAR *NPFPFN; // npfpfn
+
+typedef USHORT SHANDLE; // sh
+typedef PVOID HANDLE; // h
+
+typedef struct _POINTL { // ptl
+ LONG x;
+ LONG y;
+} POINTL;
+typedef POINTL FAR *PPOINTL;
+
+typedef struct _RECTL { // rcl
+ LONG xLeft;
+ LONG yBottom;
+ LONG xRight;
+ LONG yTop;
+} RECTL;
+typedef RECTL FAR *PRECTL;
+
+typedef struct _RGB { // rgb
+ BYTE bBlue;
+ BYTE bGreen;
+ BYTE bRed;
+} RGB;
+typedef RGB FAR *PRGB;
+
+
+/*** OS/2-specific types
+ */
+typedef ULONG ERRCODE; // errc
+typedef ULONG RETCODE; // rc
+typedef USHORT SRETCODE; // src
+
+typedef USHORT PID; // pid
+typedef USHORT SGID; // sgid
+typedef USHORT TID; // tid
+
+typedef struct _RESULTCODES { // rsc
+ USHORT codeTerminate;
+ USHORT codeResult;
+} RESULTCODES;
+typedef RESULTCODES FAR *PRESULTCODES;
+
+typedef SHANDLE HFILE; // shf
+typedef HFILE FAR *PHFILE; // pshf
+
+#endif // INCL_TYPES
diff --git a/private/os2/ldr/basemac.h b/private/os2/ldr/basemac.h
new file mode 100644
index 000000000..c3dbd0e57
--- /dev/null
+++ b/private/os2/ldr/basemac.h
@@ -0,0 +1,129 @@
+/*static char *SCCSID = "@(#)basemac.h 6.1 90/11/15";*/
+/*** BASEMAC.H
+ *
+ * SCCSID = @(#)basemac.h 13.20 90/09/06
+ *
+ * Macros required for other include files
+ * Copyright (c) 1988,1989 Microsoft Corporation
+ *
+ *
+ * MODIFICATION HISTORY
+ * 10/14/88 JTP Created.
+ * 12/04/88 JTP Added OS/2-specific macros.
+ */
+
+
+/*** Generic macros
+ */
+
+#define NElements(array) ((sizeof array)/(sizeof array[0]))
+
+#define SWAP(a,b,tmp) (tmp=b, b=a, a=tmp)
+
+
+// Assorted macros from STDLIB.H...
+#define min(a, b) (((a) < (b))? (a) : (b))
+#define max(a, b) (((a) > (b))? (a) : (b))
+
+
+// To extract offset or selector from a FAR32 (16:32) pointer
+#define OFFSETOF32(p) (((PDWORD)&(p))[0])
+#define SEGMENTOF32(p) (((PWORD)&(p))[2])
+
+// To extract offset or selector from any FAR (16:16) pointer
+#define OFFSETOF16(p) (((PWORD)&(p))[0])
+#define SEGMENTOF16(p) (((PWORD)&(p))[1])
+
+// For now, the default operators assume they're working on 16:16 pointers
+#define OFFSETOF OFFSETOF16
+#define SEGMENTOF SEGMENTOF16
+
+// To convert a tiled 16:16 address to a 0:32 address
+#define MAKEFLATP(fp) ((PVOID)((SEGMENTOF(fp)&~7)<<13 | OFFSETOF(fp)))
+
+// To extract any byte, word, dword, pfn, etc. from the given item
+#define BYTEOF(p,i) (((PBYTE)&(p))[i])
+#define WORDOF(p,i) (((PWORD)&(p))[i])
+#define DWORDOF(p,i) (((PDWORD)&(p))[i])
+#define PFNOF(p,i) (((PPFN)&(p))[i])
+
+// To test/set bits
+#define TESTBIT(i,b) (((i)&(b)) != 0)
+#define SETBIT(i,b,f) (i = ((i)&~(b)) | (b)*(!!(f)))
+#define SETBITB(i,b,f) (i = (BYTE)(((i)&~(b)) | (b)*(!!(f))))
+
+// ZEROBITS returns the number of low zero bits in a 32-bit constant
+#define _Z2(l) ((l)&1?0:(l)&2?1:2)
+#define _Z4(l) ((l)&3?_Z2(l):_Z2((l)>>2)+2)
+#define _Z8(l) ((l)&15?_Z4(l):_Z4((l)>>4)+4)
+#define _Z16(l) ((l)&255?_Z8(l):_Z8((l)>>8)+8)
+#define _Z32(l) ((l)&65535?_Z16(l):_Z16((l)>>16)+16)
+#define ZEROBITS(l) _Z32(l)
+
+// LOG2 returns the nearest base-2 log of a 32-bit constant, rounded up
+#define _L2(l) ((l)&~1?2:(l)&1)
+#define _L4(l) ((l)&~3?_L2((l)>>2)+2:_L2(l))
+#define _L8(l) ((l)&~15?_L4((l)>>4)+4:_L4(l))
+#define _L16(l) ((l)&~255?_L8((l)>>8)+8:_L8(l))
+#define _L32(l) ((l)&~65535?_L16((l)>>16)+16:_L16(l))
+#define LOG2(l) _L32((l)-1)
+
+// EXP2 returns 2 raised to the given power
+#define EXP2(l) (1 << (l))
+
+// Unit conversion macros
+#define KBFROMBYTES(nb) (((nb)+KSIZE-1)/KSIZE)
+#define BYTESFROMKB(nkb) ((nkb)*KSIZE)
+#define PAGESFROMBYTES(nb) (((nb)+PAGESIZE-1)/PAGESIZE)
+
+// To obtain a pointer to the page containing the given linear address
+#define PPAGEFROMP(p) ((PVOID)((ULONG)(p) & ~(PAGESIZE-1)))
+#define PPAGEFROMPGNO(p) ((PVOID)((ULONG)(p) * PAGESIZE))
+#define PGNOFROMP(p) ((ULONG)(p) / PAGESIZE)
+
+
+// To create a usable FAR pointer from an unusable FAR16 pointer
+#define FPFROMF16P(fp,f16p) OFFSETOF32(fp) = OFFSETOF16(f16p),\
+ SEGMENTOF32(fp) = SEGMENTOF16(f16p)
+
+// To create pointers from V86-mode segments+offsets
+// Note the validity of these pointers depends on the context they're used in
+#define PFROMVP(vp) ((PVOID)((WORDOF(vp,1)<<4)+WORDOF(vp,0)))
+#define PFROMVADDR(seg,off) ((PVOID)(((WORD)(seg)<<4)+(WORD)(off)))
+#define VPFROMVADDR(seg,off) ((VPVOID)(((WORD)(seg)<<16)|(WORD)(off)))
+
+// To create V86 pointers from normal (flat) pointers
+#define HISEG(p) ((USHORT)((ULONG)(p)>>4))
+#define LOOFF(p) ((USHORT)((ULONG)(p)&0xf))
+#define VPFROMP(p) ((VPVOID)((((ULONG)(p)&~0xf)<<12)|((ULONG)(p)&0xf)))
+
+#define LOSEG(p) (((ULONG)(p)-HIOFF(p))>>4)
+#define HIOFF(p) (min(0xfff0,(ULONG)(p)&0xffff0)|((ULONG)(p)&0xf))
+#define LOSEGVPFROMP(p) ((VPVOID)((LOSEG(p)<<16)|HIOFF(p)))
+
+
+// To calculate the byte offset of a field in a structure of type "type"
+#define FIELDOFFSET(type,field) ((ULONG)&(((type *)0)->field))
+
+
+/*** Older stuff (discouraged -JTP)
+ */
+
+// To extract high and low order parts of a 32-bit quantity
+#define LOUSHORT(l) (((PUSHORT)&(l))[0])
+#define HIUSHORT(l) (((PUSHORT)&(l))[1])
+
+// To create pointer from V86-mode segment+offset
+#define SEGOFF2P(seg,off) ((PVOID)((seg<<4)+(USHORT)off))
+
+
+/*** OS/2-specific macros
+ */
+
+#ifdef INCL_SSTODS
+
+#define SSToDS(p) ((void *) (TKSSBase + (unsigned) (p)))
+
+extern char *TKSSBase;
+
+#endif
diff --git a/private/os2/ldr/bseerr.h b/private/os2/ldr/bseerr.h
new file mode 100644
index 000000000..aacab0988
--- /dev/null
+++ b/private/os2/ldr/bseerr.h
@@ -0,0 +1,856 @@
+/*static char *SCCSID = "@(#)bseerr.h 6.9 91/03/29";*/
+/****************************** Module Header ******************************\
+*
+* Module Name: BSEERR.H
+*
+* This file includes the error codes for Base OS/2 applications.
+*
+* Copyright (c) 1987 Microsoft Corporation
+*
+* ===========================================================================
+*
+* The following symbols are used in this file for conditional sections.
+*
+* INCL_DOSERRORS - OS/2 Errors - only included if symbol defined
+* INCL_ERROR_H - Set from error.h - to be deleted when error.h deleted
+* INCL_ERROR2_H - Set from error2.h - to be deleted when error.h deleted
+*
+* Note that the message id's for the first 1000 error codes (in basemid.h)
+* are constructed from the comment on the #define for those error codes.
+* See h.mak and basemid.skl for further information. Note that some message
+* id's conflict with error codes, so some error codes are unusable. In
+* other words, if there is a message id defined in a certain location,
+* that position may not, in general, be used for an error id.
+*
+* There are three formats of these special comments:
+* #define ERROR_NO <nnn> <opencomment> <MSG>%<none> <closecomment>
+* #define ERROR_NO <nnn> <opencomment> <MSG>%<message_name> <closecomment>
+* <opencomment> <nnn>%<msg>%<message_name> <closecomment>
+* The first version is used when there is an error id, but no message id
+* associated with it. This is the case when the error is an internal error
+* and is never seen by the user, or it is incorrect and there really should
+* be a message.
+*
+* The second format is used when there is both an error id and message id.
+*
+* The third case is used when there is a message id in that position, but no
+* error id. It may also be used when there is more than one message id for
+* a particular error id.
+*
+* Whenever a new error id is defined, the person defining that error MUST
+* decide if it is to be a user-seeable error or not. If it is, a message
+* id MUST be declared, and the appropriate message added to oso001.txt.
+* This should be coordinated with the IBM Instructional Design people.
+* The current contact is Kathleen Hamill.
+*
+\***************************************************************************/
+
+#ifdef INCL_ERRORS
+
+#define INCL_DOSERRORS
+#define INCL_ERROR_H
+#define INCL_ERROR2_H
+
+#endif /* INCL_ERRORS */
+
+#if defined(INCL_DOSERRORS) || defined(INCL_ERROR_H)
+
+#define NO_ERROR 0 /* MSG%RESPONSE_DATA */
+#define ERROR_INVALID_FUNCTION 1 /* MSG%INVALID_FUNCTION */
+#define ERROR_FILE_NOT_FOUND 2 /* MSG%FILE_NOT_FOUND */
+#define ERROR_PATH_NOT_FOUND 3 /* MSG%PATH_NOT_FOUND */
+#define ERROR_TOO_MANY_OPEN_FILES 4 /* MSG%OUT_OF_HANDLES */
+#define ERROR_ACCESS_DENIED 5 /* MSG%ACCESS_DENIED */
+#define ERROR_INVALID_HANDLE 6 /* MSG%INVALID_HANDLE */
+#define ERROR_ARENA_TRASHED 7 /* MSG%MEMORY_BLOCKS_BAD */
+#define ERROR_NOT_ENOUGH_MEMORY 8 /* MSG%NO_MEMORY */
+#define ERROR_INVALID_BLOCK 9 /* MSG%INVALID_MEM_ADDR */
+#define ERROR_BAD_ENVIRONMENT 10 /* MSG%INVALID_ENVIRON */
+#define ERROR_BAD_FORMAT 11 /* MSG%INVALID_FORMAT */
+#define ERROR_INVALID_ACCESS 12 /* MSG%INVALID_ACC_CODE */
+#define ERROR_INVALID_DATA 13 /* MSG%INVALID_DATA */
+#define ERROR_INVALID_DRIVE 15 /* MSG%INVALID_DRIVE */
+#define ERROR_CURRENT_DIRECTORY 16 /* MSG%ATT_RD_CURDIR */
+#define ERROR_NOT_SAME_DEVICE 17 /* MSG%NOT_SAME_DEVICE */
+#define ERROR_NO_MORE_FILES 18 /* MSG%NO_MORE_FILES */
+#define ERROR_WRITE_PROTECT 19 /* MSG%ATT_WRITE_PROT */
+#define ERROR_BAD_UNIT 20 /* MSG%UNKNOWN_UNIT */
+#define ERROR_NOT_READY 21 /* MSG%DRIVE_NOT_READY */
+#define ERROR_BAD_COMMAND 22 /* MSG%UNKNOWN_COMMAND */
+#define ERROR_CRC 23 /* MSG%DATA_ERROR */
+#define ERROR_BAD_LENGTH 24 /* MSG%BAD_REQ_STRUCTURE */
+#define ERROR_SEEK 25 /* MSG%SEEK_ERROR */
+#define ERROR_NOT_DOS_DISK 26 /* MSG%UNKNOWN_MEDIA */
+#define ERROR_SECTOR_NOT_FOUND 27 /* MSG%SECTOR_NOT_FOUND */
+#define ERROR_OUT_OF_PAPER 28 /* MSG%OUT_OF_PAPER */
+#define ERROR_WRITE_FAULT 29 /* MSG%WRITE_FAULT */
+#define ERROR_READ_FAULT 30 /* MSG%READ_FAULT */
+#define ERROR_GEN_FAILURE 31 /* MSG%GENERAL_FAILURE */
+#define ERROR_SHARING_VIOLATION 32 /* MSG%SHARING_VIOLATION */
+/* 32%msg%SHAR_VIOLAT_FIND */
+#define ERROR_LOCK_VIOLATION 33 /* MSG%LOCK_VIOLATION */
+#define ERROR_WRONG_DISK 34 /* MSG%INVALID_DISK_CHANGE */
+#define ERROR_FCB_UNAVAILABLE 35 /* MSG%35 */
+#define ERROR_SHARING_BUFFER_EXCEEDED 36 /* MSG%SHARING_BUFF_OFLOW */
+#define ERROR_CODE_PAGE_MISMATCHED 37 /* MSG%ERROR_WRITE_PROTECT */
+#define ERROR_HANDLE_EOF 38 /* MSG%ERROR_BAD_UNIT */
+#define ERROR_HANDLE_DISK_FULL 39 /* MSG%ERROR_NOT_READY */
+/* 40%msg%ERROR_BAD_COMMAND */
+/* 41%msg%ERROR_CRC */
+/* 42%msg%ERROR_BAD_LENGTH */
+/* 43%msg%ERROR_SEEK */
+/* 44%msg%ERROR_NOT_DOS_DISK */
+/* 45%msg%ERROR_SECTOR_NOT_FOUND */
+/* 46%msg%ERROR_OUT_OF_PAPER */
+/* 47%msg%ERROR_WRITE_FAULT */
+/* 48%msg%ERROR_READ_FAULT */
+/* 49%msg%ERROR_GEN_FAILURE */
+#define ERROR_NOT_SUPPORTED 50 /* MSG%NET_REQ_NOT_SUPPORT */
+#define ERROR_REM_NOT_LIST 51 /* MSG%NET_REMOTE_NOT_ONLINE */
+#define ERROR_DUP_NAME 52 /* MSG%NET_DUP_FILENAME */
+#define ERROR_BAD_NETPATH 53 /* MSG%NET_PATH_NOT_FOUND */
+#define ERROR_NETWORK_BUSY 54 /* MSG%NET_BUSY */
+#define ERROR_DEV_NOT_EXIST 55 /* MSG%NET_DEV_NOT_INSTALLED */
+#define ERROR_TOO_MANY_CMDS 56 /* MSG%NET_BIOS_LIMIT_REACHED */
+#define ERROR_ADAP_HDW_ERR 57 /* MSG%NET_ADAPT_HRDW_ERROR */
+#define ERROR_BAD_NET_RESP 58 /* MSG%NET_INCORRECT_RESPONSE */
+#define ERROR_UNEXP_NET_ERR 59 /* MSG%NET_UNEXPECT_ERROR */
+#define ERROR_BAD_REM_ADAP 60 /* MSG%NET_REMOT_ADPT_INCOMP */
+#define ERROR_PRINTQ_FULL 61 /* MSG%NET_PRINT_Q_FULL */
+#define ERROR_NO_SPOOL_SPACE 62 /* MSG%NET_NO_SPACE_TO_PRINT_FL */
+#define ERROR_PRINT_CANCELLED 63 /* MSG%NET_PRINT_FILE_DELETED */
+#define ERROR_NETNAME_DELETED 64 /* MSG%NET_NAME_DELETED */
+#define ERROR_NETWORK_ACCESS_DENIED 65 /* MSG%NET_ACCESS_DENIED */
+#define ERROR_BAD_DEV_TYPE 66 /* MSG%NET_DEV_TYPE_INVALID */
+#define ERROR_BAD_NET_NAME 67 /* MSG%NET_NAME_NOT_FOUND */
+#define ERROR_TOO_MANY_NAMES 68 /* MSG%NET_NAME_LIMIT_EXCEED */
+#define ERROR_TOO_MANY_SESS 69 /* MSG%NET_BIOS_LIMIT_EXCEED */
+#define ERROR_SHARING_PAUSED 70 /* MSG%NET_TEMP_PAUSED */
+#define ERROR_REQ_NOT_ACCEP 71 /* MSG%NET_REQUEST_DENIED */
+#define ERROR_REDIR_PAUSED 72 /* MSG%NET_PRT_DSK_REDIR_PAUSE */
+#define ERROR_SBCS_ATT_WRITE_PROT 73 /* Attempted write on protected disk */
+#define ERROR_SBCS_GENERAL_FAILURE 74 /* General failure */
+#define ERROR_XGA_OUT_MEMORY 75 /* MSG%XGA_OUT_MEMORY */
+#define ERROR_FILE_EXISTS 80 /* MSG%FILE_EXISTS */
+#define ERROR_DUP_FCB 81 /* MSG%none */
+#define ERROR_CANNOT_MAKE 82 /* MSG%CANNOT_MAKE */
+#define ERROR_FAIL_I24 83 /* MSG%NET_FAIL_INT_TWO_FOUR */
+#define ERROR_OUT_OF_STRUCTURES 84 /* MSG%NET_TOO_MANY_REDIRECT */
+#define ERROR_ALREADY_ASSIGNED 85 /* MSG%NET_DUP_REDIRECTION */
+#define ERROR_INVALID_PASSWORD 86 /* MSG%NET_INVALID_PASSWORD */
+#define ERROR_INVALID_PARAMETER 87 /* MSG%NET_INCORR_PARAMETER */
+#define ERROR_NET_WRITE_FAULT 88 /* MSG%NET_DATA_FAULT */
+#define ERROR_NO_PROC_SLOTS 89 /* MSG%NO_PROC_SLOTS */
+#define ERROR_NOT_FROZEN 90 /* MSG%none */
+#define ERROR_SYS_COMP_NOT_LOADED ERROR_NOT_FROZEN
+#define ERR_TSTOVFL 91 /* MSG%none */
+#define ERR_TSTDUP 92 /* MSG%none */
+#define ERROR_NO_ITEMS 93 /* MSG%none */
+#define ERROR_INTERRUPT 95 /* MSG%none */
+#define ERROR_DEVICE_IN_USE 99 /* MSG%DEVICE_IN_USE */
+#define ERROR_TOO_MANY_SEMAPHORES 100 /* MSG%TOO_MANY_SEMAPHORES */
+#define ERROR_EXCL_SEM_ALREADY_OWNED 101 /* MSG%EXCL_SEM_ALREADY_OWNED */
+#define ERROR_SEM_IS_SET 102 /* MSG%SEM_IS_SET */
+#define ERROR_TOO_MANY_SEM_REQUESTS 103 /* MSG%TOO_MANY_SEM_REQUESTS */
+#define ERROR_INVALID_AT_INTERRUPT_TIME 104 /* MSG%INVALID_AT_INTERRUPT_TIME */
+#define ERROR_SEM_OWNER_DIED 105 /* MSG%SEM_OWNER_DIED */
+#define ERROR_SEM_USER_LIMIT 106 /* MSG%ERROR_DISK_CHANGE */
+#define ERROR_DISK_CHANGE 107 /* MSG%DISK_CHANGE */
+#define ERROR_DRIVE_LOCKED 108 /* MSG%DRIVE_LOCKED */
+#define ERROR_BROKEN_PIPE 109 /* MSG%BROKEN_PIPE */
+#define ERROR_OPEN_FAILED 110 /* MSG%ERROR_OPEN_FAILED */
+#define ERROR_BUFFER_OVERFLOW 111 /* MSG%ERROR_FILENAME_LONG */
+#define ERROR_DISK_FULL 112 /* MSG%DISK_FULL */
+#define ERROR_NO_MORE_SEARCH_HANDLES 113 /* MSG%NO_SEARCH_HANDLES */
+#define ERROR_INVALID_TARGET_HANDLE 114 /* MSG%ERR_INV_TAR_HANDLE */
+#define ERROR_PROTECTION_VIOLATION 115 /* MSG%none */
+#define ERROR_VIOKBD_REQUEST 116 /* MSG%none */
+#define ERROR_INVALID_CATEGORY 117 /* MSG%INVALID_CATEGORY */
+#define ERROR_INVALID_VERIFY_SWITCH 118 /* MSG%INVALID_VERIFY_SWITCH */
+#define ERROR_BAD_DRIVER_LEVEL 119 /* MSG%BAD_DRIVER_LEVEL */
+#define ERROR_CALL_NOT_IMPLEMENTED 120 /* MSG%BAD_DYNALINK */
+#define ERROR_SEM_TIMEOUT 121 /* MSG%SEM_TIMEOUT */
+#define ERROR_INSUFFICIENT_BUFFER 122 /* MSG%INSUFFICIENT_BUFFER */
+#define ERROR_INVALID_NAME 123 /* MSG%INVALID_NAME */
+/* 123%msg%HPFS_INVALID_VOLUME_CHAR */
+#define ERROR_INVALID_LEVEL 124 /* MSG%INVALID_LEVEL */
+#define ERROR_NO_VOLUME_LABEL 125 /* MSG%NO_VOLUME_LABEL */
+#define ERROR_MOD_NOT_FOUND 126 /* MSG%MOD_NOT_FOUND */
+#define ERROR_PROC_NOT_FOUND 127 /* MSG%PROC_NOT_FOUND */
+#define ERROR_WAIT_NO_CHILDREN 128 /* MSG%none */
+#define ERROR_CHILD_NOT_COMPLETE 129 /* MSG%PROT_MODE_ONLY */
+#define ERROR_DIRECT_ACCESS_HANDLE 130 /* MSG%APPL_SINGLEFRAMECHAR */
+#define ERROR_NEGATIVE_SEEK 131 /* MSG%APPL_DOUBLEFRAMECHAR */
+#define ERROR_SEEK_ON_DEVICE 132 /* MSG%APPL_ARROWCHAR */
+#define ERROR_IS_JOIN_TARGET 133 /* MSG%JOIN_ON_DRIV_IS_TAR */
+#define ERROR_IS_JOINED 134 /* MSG%JOIN_DRIVE_IS */
+#define ERROR_IS_SUBSTED 135 /* MSG%SUB_DRIVE_IS */
+#define ERROR_NOT_JOINED 136 /* MSG%DRIVE_IS_NOT_JOINED */
+#define ERROR_NOT_SUBSTED 137 /* MSG%DRIVE_NOT_SUBSTED */
+#define ERROR_JOIN_TO_JOIN 138 /* MSG%JOIN_CANNOT_JOIN_DRIVE */
+#define ERROR_SUBST_TO_SUBST 139 /* MSG%SUB_CANNOT_SUBST_DRIVE */
+#define ERROR_JOIN_TO_SUBST 140 /* MSG%JOIN_CANNOT_SUB_DRIVE */
+#define ERROR_SUBST_TO_JOIN 141 /* MSG%SUB_CANNOT_JOIN_DRIVE */
+#define ERROR_BUSY_DRIVE 142 /* MSG%DRIVE_IS_BUSY */
+#define ERROR_SAME_DRIVE 143 /* MSG%JOIN_SUB_SAME_DRIVE */
+#define ERROR_DIR_NOT_ROOT 144 /* MSG%DIRECT_IS_NOT_SUBDIR */
+#define ERROR_DIR_NOT_EMPTY 145 /* MSG%DIRECT_IS_NOT_EMPTY */
+#define ERROR_IS_SUBST_PATH 146 /* MSG%PATH_USED_SUBST_JOIN */
+#define ERROR_IS_JOIN_PATH 147 /* MSG%NO_NEEDED_RESOURCES */
+#define ERROR_PATH_BUSY 148 /* MSG%PATH_BUSY */
+#define ERROR_IS_SUBST_TARGET 149 /* MSG%SUB_ON_DRIVE_IS_JOIN */
+#define ERROR_SYSTEM_TRACE 150 /* MSG%SYSTEM_TRACE */
+#define ERROR_INVALID_EVENT_COUNT 151 /* MSG%INVALID_EVENT_COUNT */
+#define ERROR_TOO_MANY_MUXWAITERS 152 /* MSG%TOO_MANY_MUXWAITERS */
+#define ERROR_INVALID_LIST_FORMAT 153 /* MSG%INVALID_LIST_FORMAT */
+#define ERROR_LABEL_TOO_LONG 154 /* MSG%VOLUME_TOO_LONG */
+/* 154%msg%HPFS_VOL_LABEL_LONG */
+#define ERROR_TOO_MANY_TCBS 155 /* MSG%TOO_MANY_TCBS */
+#define ERROR_SIGNAL_REFUSED 156 /* MSG%SIGNAL_REFUSED */
+#define ERROR_DISCARDED 157 /* MSG%DISCARDED */
+#define ERROR_NOT_LOCKED 158 /* MSG%NOT_LOCKED */
+#define ERROR_BAD_THREADID_ADDR 159 /* MSG%BAD_THREADID_ADDR */
+#define ERROR_BAD_ARGUMENTS 160 /* MSG%BAD_ARGUMENTS */
+#define ERROR_BAD_PATHNAME 161 /* MSG%none */
+#define ERROR_SIGNAL_PENDING 162 /* MSG%SIGNAL_PENDING */
+#define ERROR_UNCERTAIN_MEDIA 163 /* MSG%none */
+#define ERROR_MAX_THRDS_REACHED 164 /* MSG%MAX_THRDS_REACHED */
+#define ERROR_MONITORS_NOT_SUPPORTED 165 /* MSG%none */
+#define ERROR_UNC_DRIVER_NOT_INSTALLED 166 /* MSG%UNC_DRIVER_NOT_INSTALLED */
+#define ERROR_LOCK_FAILED 167 /* MSG%LOCK_FAILED */
+#define ERROR_SWAPIO_FAILED 168 /* MSG%SWAPIO_FAILED */
+#define ERROR_SWAPIN_FAILED 169 /* MSG%SWAPIN_ATTEMPT_FAILED */
+#define ERROR_BUSY 170 /* MSG%SEGMENT_BUSY */
+/* 171%msg%INT_TOO_LONG */
+#define ERROR_CANCEL_VIOLATION 173 /* MSG%UNLOCK_VIOLATION */
+#define ERROR_ATOMIC_LOCK_NOT_SUPPORTED 174 /* MSG%none */
+#define ERROR_READ_LOCKS_NOT_SUPPORTED 175 /* MSG%none */
+#define ERROR_INVALID_SEGMENT_NUMBER 180 /* MSG%INVALID_SEGMENT_NUM */
+#define ERROR_INVALID_CALLGATE 181 /* MSG%none */
+#define ERROR_INVALID_ORDINAL 182 /* MSG%INVALID_ORDINAL */
+#define ERROR_ALREADY_EXISTS 183 /* MSG%none */
+#define ERROR_NO_CHILD_PROCESS 184 /* MSG%none */
+#define ERROR_CHILD_ALIVE_NOWAIT 185 /* MSG%none */
+#define ERROR_INVALID_FLAG_NUMBER 186 /* MSG%INVALID_FLAG_NUMBER */
+#define ERROR_SEM_NOT_FOUND 187 /* MSG%SEM_NOT_FOUND */
+#define ERROR_INVALID_STARTING_CODESEG 188 /* MSG%INVALID_STARTING_CODESEG */
+#define ERROR_INVALID_STACKSEG 189 /* MSG%INVALID_STACKSEG */
+#define ERROR_INVALID_MODULETYPE 190 /* MSG%INVALID_MODULETYPE */
+#define ERROR_INVALID_EXE_SIGNATURE 191 /* MSG%INVALID_EXE_SIGNATURE */
+#define ERROR_EXE_MARKED_INVALID 192 /* MSG%EXE_MARKED_INVALID */
+#define ERROR_BAD_EXE_FORMAT 193 /* MSG%BAD_EXE_FORMAT */
+#define ERROR_ITERATED_DATA_EXCEEDS_64k 194 /* MSG%ITERATED_DATA_EXCEEDS_64K */
+#define ERROR_INVALID_MINALLOCSIZE 195 /* MSG%INVALID_MINALLOCSIZE */
+#define ERROR_DYNLINK_FROM_INVALID_RING 196 /* MSG%DYNLINK_FROM_INVALID_RING */
+#define ERROR_IOPL_NOT_ENABLED 197 /* MSG%IOPL_NOT_ENABLED */
+#define ERROR_INVALID_SEGDPL 198 /* MSG%INVALID_SEGDPL */
+#define ERROR_AUTODATASEG_EXCEEDS_64k 199 /* MSG%AUTODATASEG_EXCEEDS_64K */
+#define ERROR_RING2SEG_MUST_BE_MOVABLE 200 /* MSG%CODESEG_CANNOT_BE_64K */
+#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201 /* MSG%RELOC_CHAIN_XEEDS_SEGMENT */
+#define ERROR_INFLOOP_IN_RELOC_CHAIN 202 /* MSG%INFLOOP_IN_RELOC_CHAIN */
+#define ERROR_ENVVAR_NOT_FOUND 203 /* MSG%ENVVAR_NOT_FOUND */
+#define ERROR_NOT_CURRENT_CTRY 204 /* MSG%none */
+#define ERROR_NO_SIGNAL_SENT 205 /* MSG%SIGNAL_NOT_SENT */
+#define ERROR_FILENAME_EXCED_RANGE 206 /* MSG%NAME_TOO_LONG */
+#define ERROR_RING2_STACK_IN_USE 207 /* MSG%RING2_STACK_IN_USE */
+#define ERROR_META_EXPANSION_TOO_LONG 208 /* MSG%WILD_CARD_NAME */
+#define ERROR_INVALID_SIGNAL_NUMBER 209 /* MSG%INVALID_SIGNAL_NUMBER */
+#define ERROR_THREAD_1_INACTIVE 210 /* MSG%THREAD_1_INACTIVE */
+#define ERROR_INFO_NOT_AVAIL 211 /* MSG%none */
+#define ERROR_LOCKED 212 /* MSG%LOCKED */
+#define ERROR_BAD_DYNALINK 213 /* MSG%none */
+#define ERROR_TOO_MANY_MODULES 214 /* MSG%TOO_MANY_MODULES */
+#define ERROR_NESTING_NOT_ALLOWED 215 /* MSG%none */
+#define ERROR_CANNOT_SHRINK 216 /* MSG%CANNOT_SHRINK */
+#define ERROR_ZOMBIE_PROCESS 217 /* MSG%none */
+#define ERROR_STACK_IN_HIGH_MEMORY 218 /* MSG%none */
+#define ERROR_INVALID_EXITROUTINE_RING 219 /* MSG%INVALID_EXITROUTINE_RING */
+#define ERROR_GETBUF_FAILED 220 /* MSG%none */
+#define ERROR_FLUSHBUF_FAILED 221 /* MSG%none */
+#define ERROR_TRANSFER_TOO_LONG 222 /* MSG%none */
+#define ERROR_FORCENOSWAP_FAILED 223 /* MSG%none */
+#define ERROR_SMG_NO_TARGET_WINDOW 224 /* PM ID can't be selected */
+#define ERROR_NO_CHILDREN 228 /* MSG%NO_CHILDREN */
+#define ERROR_INVALID_SCREEN_GROUP 229 /* MSG%none */
+#define ERROR_BAD_PIPE 230 /* MSG%ERROR_BAD_PIPE */
+#define ERROR_PIPE_BUSY 231 /* MSG%ERROR_PIPE_BUSY */
+#define ERROR_NO_DATA 232 /* MSG%ERROR_NO_DATA */
+#define ERROR_PIPE_NOT_CONNECTED 233 /* MSG%ERROR_PIPE_NOT_CONNECTED */
+#define ERROR_MORE_DATA 234 /* MSG%ERROR_MORE_DATA */
+#define ERROR_VC_DISCONNECTED 240 /* MSG%ERROR_VC_DISCONNECTED */
+#define ERROR_CIRCULARITY_REQUESTED 250 /* MSG%CIRCULARITY_REQUESTED */
+#define ERROR_DIRECTORY_IN_CDS 251 /* MSG%DIRECTORY_IN_CDS */
+#define ERROR_INVALID_FSD_NAME 252 /* MSG%INVALID_FSD_NAME */
+#define ERROR_INVALID_PATH 253 /* MSG%INVALID_PATH */
+#define ERROR_INVALID_EA_NAME 254 /* MSG%INVALID_EA_NAME */
+#define ERROR_EA_LIST_INCONSISTENT 255 /* MSG%EA_LIST_INCONSISTENT */
+#define ERROR_EA_LIST_TOO_LONG 256 /* MSG%EA_LIST_TOO_LONG */
+#define ERROR_NO_META_MATCH 257 /* MSG%NO_META_MATCH */
+#define ERROR_FINDNOTIFY_TIMEOUT 258 /* MSG%FINDNOTIFY_TIMEOUT */
+#define ERROR_NO_MORE_ITEMS 259 /* MSG%NO_MORE_ITEMS */
+#define ERROR_SEARCH_STRUC_REUSED 260 /* MSG%SEARCH_STRUC_REUSED */
+#define ERROR_CHAR_NOT_FOUND 261 /* MSG%CHAR_NOT_FOUND */
+#define ERROR_TOO_MUCH_STACK 262 /* MSG%TOO_MUCH_STACK */
+#define ERROR_INVALID_ATTR 263 /* MSG%INVALID_ATTR */
+#define ERROR_INVALID_STARTING_RING 264 /* MSG%INVALID_STARTING_RING */
+#define ERROR_INVALID_DLL_INIT_RING 265 /* MSG%INVALID_DLL_INIT_RING */
+#define ERROR_CANNOT_COPY 266 /* MSG%CANNOT_COPY */
+#define ERROR_DIRECTORY 267 /* MSG%DIRECTORY */
+#define ERROR_OPLOCKED_FILE 268 /* MSG%OPLOCKED_FILE */
+#define ERROR_OPLOCK_THREAD_EXISTS 269 /* MSG%OPLOCK_THREAD_EXISTS */
+#define ERROR_VOLUME_CHANGED 270 /* MSG%none */
+#define ERROR_FINDNOTIFY_HANDLE_IN_USE 271 /* MSG%none */
+#define ERROR_FINDNOTIFY_HANDLE_CLOSED 272 /* MSG%none */
+#define ERROR_NOTIFY_OBJECT_REMOVED 273 /* MSG%none */
+#define ERROR_ALREADY_SHUTDOWN 274 /* MSG%none */
+#define ERROR_EAS_DIDNT_FIT 275 /* MSG%none */
+#define ERROR_EA_FILE_CORRUPT 276 /* MSG%ERROR_EAS_CORRUPT */
+#define ERROR_EA_TABLE_FULL 277 /* MSG%EA_TABLE_FULL */
+#define ERROR_INVALID_EA_HANDLE 278 /* MSG%INVALID_EA_HANDLE */
+#define ERROR_NO_CLUSTER 279 /* MSG%NO_CLUSTER */
+#define ERROR_CREATE_EA_FILE 280 /* MSG%ERROR_CREATE_EA_FILE */
+#define ERROR_CANNOT_OPEN_EA_FILE 281 /* MSG%CANNOT_OPEN_FILE */
+#define ERROR_EAS_NOT_SUPPORTED 282 /* MSG%EAS_NOT_SUPPORTED */
+#define ERROR_NEED_EAS_FOUND 283 /* MSG%NEED_EAS_FOUND */
+#define ERROR_DUPLICATE_HANDLE 284 /* MSG%EAS_DISCARDED */
+#define ERROR_DUPLICATE_NAME 285 /* MSG%DUPLICATE_SEM_NAME */
+#define ERROR_EMPTY_MUXWAIT 286 /* MSG%EMPTY_MUXWAIT_SEM */
+#define ERROR_MUTEX_OWNED 287 /* MSG%MUTEX_SEM_OWNED */
+#define ERROR_NOT_OWNER 288 /* MSG%NOT_MUTEX_SEM_OWNER */
+#define ERROR_PARAM_TOO_SMALL 289 /* MSG%QUERY_MUX_PARAM_TOO_SMALL */
+#define ERROR_TOO_MANY_HANDLES 290 /* MSG%TOO_MANY_SEM_HANDLES */
+#define ERROR_TOO_MANY_OPENS 291 /* MSG%TOO_MANY_SEM_OPENS */
+#define ERROR_WRONG_TYPE 292 /* MSG%SEM_WRONG_TYPE */
+#define ERROR_UNUSED_CODE 293 /* MSG%none */
+#define ERROR_THREAD_NOT_TERMINATED 294 /* MSG%none */
+#define ERROR_INIT_ROUTINE_FAILED 295 /* MSG%none */
+#define ERROR_MODULE_IN_USE 296 /* MSG%none */
+#define ERROR_NOT_ENOUGH_WATCHPOINTS 297 /* MSG%none */
+#define ERROR_TOO_MANY_POSTS 298 /* MSG%TOO_MANY_EVENT_SEM_POSTS */
+#define ERROR_ALREADY_POSTED 299 /* MSG%EVENT_SEM_ALREADY_POSTED */
+#define ERROR_ALREADY_RESET 300 /* MSG%EVENT_SEM_ALREADY_RESET */
+#define ERROR_SEM_BUSY 301 /* MSG%SEM_BUSY */
+
+/* end of set 0 - 302 */
+
+#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 ALLOWED_DETACHED ALLOWED_DISPATCH
+#define ALLOWED_RESERVED ~(ALLOWED_FAIL|ALLOWED_ABORT|ALLOWED_RETRY|ALLOWED_IGNORE|ALLOWED_ACKNOWLEDGE)
+
+#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 TC_XCPT 4
+
+#endif /* INCL_ERROR_H || INCL_DOSERRORS */
+
+#if defined(INCL_DOSERRORS) || defined(INCL_ERROR2_H)
+
+#define ERROR_INVALID_PROCID 303 /* MSG%none */
+#define ERROR_INVALID_PDELTA 304 /* MSG%none */
+#define ERROR_NOT_DESCENDANT 305 /* MSG%none */
+#define ERROR_NOT_SESSION_MANAGER 306 /* MSG%none */
+#define ERROR_INVALID_PCLASS 307 /* MSG%none */
+#define ERROR_INVALID_SCOPE 308 /* MSG%none */
+#define ERROR_INVALID_THREADID 309 /* MSG%none */
+#define ERROR_DOSSUB_SHRINK 310 /* MSG%none */
+#define ERROR_DOSSUB_NOMEM 311 /* MSG%none */
+#define ERROR_DOSSUB_OVERLAP 312 /* MSG%none */
+#define ERROR_DOSSUB_BADSIZE 313 /* MSG%none */
+#define ERROR_DOSSUB_BADFLAG 314 /* MSG%none */
+#define ERROR_DOSSUB_BADSELECTOR 315 /* MSG%none */
+#define ERROR_MR_MSG_TOO_LONG 316 /* MSG%MR_MSG_TOO_LONG */
+#define MGS_MR_MSG_TOO_LONG 316
+#define ERROR_MR_MID_NOT_FOUND 317 /* MSG%MR_CANT_FORMAT */
+#define ERROR_MR_UN_ACC_MSGF 318 /* MSG%MR_NOT_FOUND */
+#define ERROR_MR_INV_MSGF_FORMAT 319 /* MSG%MR_READ_ERROR */
+#define ERROR_MR_INV_IVCOUNT 320 /* MSG%MR_IVCOUNT_ERROR */
+#define ERROR_MR_UN_PERFORM 321 /* MSG%MR_UN_PERFORM */
+#define ERROR_TS_WAKEUP 322 /* MSG%none */
+#define ERROR_TS_SEMHANDLE 323 /* MSG%none */
+#define ERROR_TS_NOTIMER 324 /* MSG%none */
+#define ERROR_TS_HANDLE 326 /* MSG%none */
+#define ERROR_TS_DATETIME 327 /* MSG%none */
+#define ERROR_SYS_INTERNAL 328 /* MSG%none */
+#define ERROR_QUE_CURRENT_NAME 329 /* MSG%none */
+#define ERROR_QUE_PROC_NOT_OWNED 330 /* MSG%QUE_PROC_NOT_OWNED */
+#define ERROR_QUE_PROC_OWNED 331 /* MSG%none */
+#define ERROR_QUE_DUPLICATE 332 /* MSG%QUE_DUPLICATE */
+#define ERROR_QUE_ELEMENT_NOT_EXIST 333 /* MSG%QUE_ELEMENT_NOT_EXIST */
+#define ERROR_QUE_NO_MEMORY 334 /* MSG%QUE_NO_MEMORY */
+#define ERROR_QUE_INVALID_NAME 335 /* MSG%none */
+#define ERROR_QUE_INVALID_PRIORITY 336 /* MSG%none */
+#define ERROR_QUE_INVALID_HANDLE 337 /* MSG%none */
+#define ERROR_QUE_LINK_NOT_FOUND 338 /* MSG%none */
+#define ERROR_QUE_MEMORY_ERROR 339 /* MSG%none */
+#define ERROR_QUE_PREV_AT_END 340 /* MSG%none */
+#define ERROR_QUE_PROC_NO_ACCESS 341 /* MSG%none */
+#define ERROR_QUE_EMPTY 342 /* MSG%none */
+#define ERROR_QUE_NAME_NOT_EXIST 343 /* MSG%none */
+#define ERROR_QUE_NOT_INITIALIZED 344 /* MSG%none */
+#define ERROR_QUE_UNABLE_TO_ACCESS 345 /* MSG%none */
+#define ERROR_QUE_UNABLE_TO_ADD 346 /* MSG%none */
+#define ERROR_QUE_UNABLE_TO_INIT 347 /* MSG%none */
+#define ERROR_VIO_INVALID_MASK 349 /* MSG%VIO_INVALID_MASK */
+#define ERROR_VIO_PTR 350 /* MSG%VIO_PTR */
+#define ERROR_VIO_APTR 351 /* MSG%none */
+#define ERROR_VIO_RPTR 352 /* MSG%none */
+#define ERROR_VIO_CPTR 353 /* MSG%none */
+#define ERROR_VIO_LPTR 354 /* MSG%none */
+#define ERROR_VIO_MODE 355 /* MSG%DIS_ERROR */
+#define ERROR_VIO_WIDTH 356 /* MSG%VIO_WIDTH */
+#define ERROR_VIO_ATTR 357 /* MSG%none */
+#define ERROR_VIO_ROW 358 /* MSG%VIO_ROW */
+#define ERROR_VIO_COL 359 /* MSG%VIO_COL */
+#define ERROR_VIO_TOPROW 360 /* MSG%none */
+#define ERROR_VIO_BOTROW 361 /* MSG%none */
+#define ERROR_VIO_RIGHTCOL 362 /* MSG%none */
+#define ERROR_VIO_LEFTCOL 363 /* MSG%none */
+#define ERROR_SCS_CALL 364 /* MSG%none */
+#define ERROR_SCS_VALUE 365 /* MSG%none */
+#define ERROR_VIO_WAIT_FLAG 366 /* MSG%VIO_WAIT_FLAG */
+#define ERROR_VIO_UNLOCK 367 /* MSG%VIO_UNLOCK */
+#define ERROR_SGS_NOT_SESSION_MGR 368 /* MSG%none */
+#define ERROR_SMG_INVALID_SGID 369 /* MSG%SMG_INVALID_SESSION_ID */
+#define ERROR_SMG_INVALID_SESSION_ID ERROR_SMG_INVALID_SGID
+#define ERROR_SMG_NOSG 370 /* MSG%none */
+#define ERROR_SMG_NO_SESSIONS 370 /* MSG%none */
+#define ERROR_SMG_GRP_NOT_FOUND 371 /* MSG%SMG_GRP_NOT_FOUND */
+#define ERROR_SMG_SESSION_NOT_FOUND ERROR_SMG_GRP_NOT_FOUND
+/* 371%msg%SMG_SESSION_NOT_FOUND */
+#define ERROR_SMG_SET_TITLE 372 /* MSG%SMG_SET_TITLE */
+#define ERROR_KBD_PARAMETER 373 /* MSG%KBD_PARAMETER */
+#define ERROR_KBD_NO_DEVICE 374 /* MSG%none */
+#define ERROR_KBD_INVALID_IOWAIT 375 /* MSG%KBD_INVALID_IOWAIT */
+#define ERROR_KBD_INVALID_LENGTH 376 /* MSG%KBD_INVALID_LENGTH */
+#define ERROR_KBD_INVALID_ECHO_MASK 377 /* MSG%KBD_INVALID_ECHO_MASK */
+/* 377%msg%KBD_INVALID_INPUT_MASK */
+#define ERROR_KBD_INVALID_INPUT_MASK 378 /* MSG%none */
+#define ERROR_MON_INVALID_PARMS 379 /* MSG%MON_INVALID_PARMS */
+#define ERROR_MON_INVALID_DEVNAME 380 /* MSG%MON_INVALID_DEVNAME */
+#define ERROR_MON_INVALID_HANDLE 381 /* MSG%MON_INVALID_HANDLE */
+#define ERROR_MON_BUFFER_TOO_SMALL 382 /* MSG%MON_BUFFER_TOO_SMALL */
+#define ERROR_MON_BUFFER_EMPTY 383 /* MSG%MON_BUFFER_EMPTY */
+#define ERROR_MON_DATA_TOO_LARGE 384 /* MSG%MON_DATA_TOO_LARGE */
+#define ERROR_MOUSE_NO_DEVICE 385 /* MSG%MOUSE_NO_DEVICE */
+#define ERROR_MOUSE_INV_HANDLE 386 /* MSG%MOUSE_INV_HANDLE */
+#define ERROR_MOUSE_INV_PARMS 387 /* MSG%MOUSE_CALLER_NOT_SYBSYS */
+#define ERROR_MOUSE_CANT_RESET 388 /* MSG%none */
+#define ERROR_MOUSE_DISPLAY_PARMS 389 /* MSG%none */
+#define ERROR_MOUSE_INV_MODULE 390 /* MSG%none */
+#define ERROR_MOUSE_INV_ENTRY_PT 391 /* MSG%none */
+#define ERROR_MOUSE_INV_MASK 392 /* MSG%none */
+#define NO_ERROR_MOUSE_NO_DATA 393 /* MSG%none */
+#define NO_ERROR_MOUSE_PTR_DRAWN 394 /* MSG%none */
+#define ERROR_INVALID_FREQUENCY 395 /* MSG%none */
+#define ERROR_NLS_NO_COUNTRY_FILE 396 /* MSG%NLS_NO_COUNTRY_FILE */
+/* 396%msg%NO_COUNTRY_SYS */
+#define ERROR_NLS_OPEN_FAILED 397 /* MSG%NLS_OPEN_FAILED */
+/* 397%msg%OPEN_COUNTRY_SYS */
+#define ERROR_NLS_NO_CTRY_CODE 398 /* MSG%NLS_NO_CTRY_CODE */
+#define ERROR_NO_COUNTRY_OR_CODEPAGE 398 /* MSG%NO_COUNTRY_OR_CODEPAGE */
+#define ERROR_NLS_TABLE_TRUNCATED 399 /* MSG%NLS_TABLE_TRUNCATED */
+#define ERROR_NLS_BAD_TYPE 400 /* MSG%NLS_BAD_TYPE */
+#define ERROR_NLS_TYPE_NOT_FOUND 401 /* MSG%NLS_TYPE_NOT_FOUND */
+/* 401%msg%COUNTRY_NO_TYPE */
+#define ERROR_VIO_SMG_ONLY 402 /* MSG%SWAPIN_FAILED */
+#define ERROR_VIO_INVALID_ASCIIZ 403 /* MSG%SEGVALIDATE_FAILURE */
+#define ERROR_VIO_DEREGISTER 404 /* MSG%VIO_DEREGISTER */
+#define ERROR_VIO_NO_POPUP 405 /* MSG%VIO_NO_POPUP */
+#define ERROR_VIO_EXISTING_POPUP 406 /* MSG%VIO_EXISTING_POPUP */
+#define ERROR_KBD_SMG_ONLY 407 /* MSG%KBD_SMG_ONLY */
+#define ERROR_KBD_INVALID_ASCIIZ 408 /* MSG%KBD_INVALID_ASCIIZ */
+#define ERROR_KBD_INVALID_MASK 409 /* MSG%KBD_INVALID_MASK */
+#define ERROR_KBD_REGISTER 410 /* MSG%KBD_REGISTER */
+#define ERROR_KBD_DEREGISTER 411 /* MSG%KBD_DEREGISTER */
+#define ERROR_MOUSE_SMG_ONLY 412 /* MSG%MOUSE_SMG_ONLY */
+#define ERROR_MOUSE_INVALID_ASCIIZ 413 /* MSG%MOUSE_INVALID_ASCIIZ */
+#define ERROR_MOUSE_INVALID_MASK 414 /* MSG%MOUSE_INVALID_MASK */
+#define ERROR_MOUSE_REGISTER 415 /* MSG%MOUSE_REGISTER */
+#define ERROR_MOUSE_DEREGISTER 416 /* MSG%MOUSE_DEREGISTER */
+#define ERROR_SMG_BAD_ACTION 417 /* MSG%SMG_BAD_ACTION */
+#define ERROR_SMG_INVALID_CALL 418 /* MSG%SMG_INVALID_CALL */
+#define ERROR_SCS_SG_NOTFOUND 419 /* MSG%none */
+#define ERROR_SCS_NOT_SHELL 420 /* MSG%none */
+#define ERROR_VIO_INVALID_PARMS 421 /* MSG%VIO_INVALID_PARMS */
+#define ERROR_VIO_FUNCTION_OWNED 422 /* MSG%VIO_FUNCTION_OWNED */
+#define ERROR_VIO_RETURN 423 /* MSG%none */
+#define ERROR_SCS_INVALID_FUNCTION 424 /* MSG%none */
+#define ERROR_SCS_NOT_SESSION_MGR 425 /* MSG%none */
+#define ERROR_VIO_REGISTER 426 /* MSG%VIO_REGISTER */
+#define ERROR_VIO_NO_MODE_THREAD 427 /* MSG%none */
+#define ERROR_VIO_NO_SAVE_RESTORE_THD 428 /* MSG%VIO_NO_SAVE_RESTORE_THD */
+#define ERROR_VIO_IN_BG 429 /* MSG%VIO_IN_BG */
+#define ERROR_VIO_ILLEGAL_DURING_POPUP 430 /* MSG%VIO_ILLEGAL_DURING_POPUP */
+#define ERROR_SMG_NOT_BASESHELL 431 /* MSG%SMG_NOT_BASESHELL */
+#define ERROR_SMG_BAD_STATUSREQ 432 /* MSG%SMG_BAD_STATUSREQ */
+#define ERROR_QUE_INVALID_WAIT 433 /* MSG%none */
+#define ERROR_VIO_LOCK 434 /* MSG%VIO_LOCK */
+#define ERROR_MOUSE_INVALID_IOWAIT 435 /* MSG%MOUSE_INVALID_IOWAIT */
+#define ERROR_VIO_INVALID_HANDLE 436 /* MSG%VIO_INVALID_HANDLE */
+#define ERROR_VIO_ILLEGAL_DURING_LOCK 437 /* MSG%none */
+#define ERROR_VIO_INVALID_LENGTH 438 /* MSG%VIO_INVALID_LENGTH */
+#define ERROR_KBD_INVALID_HANDLE 439 /* MSG%KBD_INVALID_HANDLE */
+#define ERROR_KBD_NO_MORE_HANDLE 440 /* MSG%KBD_NO_MORE_HANDLE */
+#define ERROR_KBD_CANNOT_CREATE_KCB 441 /* MSG%KBD_CANNOT_CREATE_KCB */
+#define ERROR_KBD_CODEPAGE_LOAD_INCOMPL 442 /* MSG%KBD_CODEPAGE_LOAD_INCOMPL */
+#define ERROR_KBD_INVALID_CODEPAGE_ID 443 /* MSG%KBD_INVALID_CODEPAGE_ID */
+#define ERROR_KBD_NO_CODEPAGE_SUPPORT 444 /* MSG%KBD_NO_CODEPAGE_SUPPORT */
+#define ERROR_KBD_FOCUS_REQUIRED 445 /* MSG%KBD_FOCUS_REQUIRED */
+#define ERROR_KBD_FOCUS_ALREADY_ACTIVE 446 /* MSG%KBD_FOCUS_ALREADY_ACTIVE */
+#define ERROR_KBD_KEYBOARD_BUSY 447 /* MSG%KBD_KEYBOARD_BUSY */
+#define ERROR_KBD_INVALID_CODEPAGE 448 /* MSG%KBD_INVALID_CODEPAGE */
+#define ERROR_KBD_UNABLE_TO_FOCUS 449 /* MSG%KBD_UNABLE_TO_FOCUS */
+#define ERROR_SMG_SESSION_NON_SELECT 450 /* MSG%SMG_SESSION_NON_SELECT */
+#define ERROR_SMG_SESSION_NOT_FOREGRND 451 /* MSG%SMG_SESSION_NOT_FOREGRND */
+#define ERROR_SMG_SESSION_NOT_PARENT 452 /* MSG%SMG_SESSION_NOT_PARENT */
+#define ERROR_SMG_INVALID_START_MODE 453 /* MSG%SMG_INVALID_START_MODE */
+#define ERROR_SMG_INVALID_RELATED_OPT 454 /* MSG%SMG_INVALID_RELATED_OPT */
+#define ERROR_SMG_INVALID_BOND_OPTION 455 /* MSG%SMG_INVALID_BOND_OPTION */
+#define ERROR_SMG_INVALID_SELECT_OPT 456 /* MSG%SMG_INVALID_SELECT_OPT */
+#define ERROR_SMG_START_IN_BACKGROUND 457 /* MSG%SMG_START_IN_BACKGROUND */
+#define ERROR_SMG_INVALID_STOP_OPTION 458 /* MSG%SMG_INVALID_STOP_OPTION */
+#define ERROR_SMG_BAD_RESERVE 459 /* MSG%SMG_BAD_RESERVE */
+#define ERROR_SMG_PROCESS_NOT_PARENT 460 /* MSG%SMG_PROCESS_NOT_PARENT */
+#define ERROR_SMG_INVALID_DATA_LENGTH 461 /* MSG%SMG_INVALID_DATA_LENGTH */
+#define ERROR_SMG_NOT_BOUND 462 /* MSG%SMG_NOT_BOUND */
+#define ERROR_SMG_RETRY_SUB_ALLOC 463 /* MSG%SMG_RETRY_SUB_ALLOC */
+#define ERROR_KBD_DETACHED 464 /* MSG%KBD_DETACHED */
+#define ERROR_VIO_DETACHED 465 /* MSG%VIO_DETACHED */
+#define ERROR_MOU_DETACHED 466 /* MSG%MOU_DETACHED */
+#define ERROR_VIO_FONT 467 /* MSG%VIO_FONT */
+#define ERROR_VIO_USER_FONT 468 /* MSG%VIO_USER_FONT */
+#define ERROR_VIO_BAD_CP 469 /* MSG%VIO_BAD_CP */
+#define ERROR_VIO_NO_CP 470 /* MSG%none */
+#define ERROR_VIO_NA_CP 471 /* MSG%VIO_NA_CP */
+#define ERROR_INVALID_CODE_PAGE 472 /* MSG%none */
+#define ERROR_CPLIST_TOO_SMALL 473 /* MSG%none */
+#define ERROR_CP_NOT_MOVED 474 /* MSG%none */
+#define ERROR_MODE_SWITCH_INIT 475 /* MSG%none */
+#define ERROR_CODE_PAGE_NOT_FOUND 476 /* MSG%none */
+#define ERROR_UNEXPECTED_SLOT_RETURNED 477 /* MSG%none */
+#define ERROR_SMG_INVALID_TRACE_OPTION 478 /* MSG%SMG_INVALID_TRACE_OPTION */
+#define ERROR_VIO_INTERNAL_RESOURCE 479 /* MSG%none */
+#define ERROR_VIO_SHELL_INIT 480 /* MSG%VIO_SHELL_INIT */
+#define ERROR_SMG_NO_HARD_ERRORS 481 /* MSG%SMG_NO_HARD_ERRORS */
+#define ERROR_CP_SWITCH_INCOMPLETE 482 /* MSG%none */
+#define ERROR_VIO_TRANSPARENT_POPUP 483 /* MSG%VIO_TRANSPARENT_POPUP */
+#define ERROR_CRITSEC_OVERFLOW 484 /* MSG%none */
+#define ERROR_CRITSEC_UNDERFLOW 485 /* MSG%none */
+#define ERROR_VIO_BAD_RESERVE 486 /* MSG%VIO_BAD_RESERVE */
+#define ERROR_INVALID_ADDRESS 487 /* MSG%INVALID_ADDRESS */
+#define ERROR_ZERO_SELECTORS_REQUESTED 488 /* MSG%ZERO_SELECTORS_REQUESTED */
+#define ERROR_NOT_ENOUGH_SELECTORS_AVA 489 /* MSG%NOT_ENOUGH_SELECTORS_AVA */
+#define ERROR_INVALID_SELECTOR 490 /* MSG%INVALID_SELECTOR */
+#define ERROR_SMG_INVALID_PROGRAM_TYPE 491 /* MSG%SMG_INVALID_PROGRAM_TYPE */
+#define ERROR_SMG_INVALID_PGM_CONTROL 492 /* MSG%SMG_INVALID_PGM_CONTROL */
+#define ERROR_SMG_INVALID_INHERIT_OPT 493 /* MSG%SMG_INVALID_INHERIT_OPT */
+#define ERROR_VIO_EXTENDED_SG 494 /* MSG%VIO_EXTENDED_SG */
+#define ERROR_VIO_NOT_PRES_MGR_SG 495 /* MSG%VIO_NOT_PRES_MGR_SG */
+#define ERROR_VIO_SHIELD_OWNED 496 /* MSG%VIO_SHIELD_OWNED */
+#define ERROR_VIO_NO_MORE_HANDLES 497 /* MSG%VIO_NO_MORE_HANDLES */
+#define ERROR_VIO_SEE_ERROR_LOG 498 /* MSG%none */
+#define ERROR_VIO_ASSOCIATED_DC 499 /* MSG%none */
+#define ERROR_KBD_NO_CONSOLE 500 /* MSG%KBD_NO_CONSOLE */
+#define ERROR_MOUSE_NO_CONSOLE 501 /* MSG%DOS_STOPPED */
+#define ERROR_MOUSE_INVALID_HANDLE 502 /* MSG%MOUSE_INVALID_HANDLE */
+#define ERROR_SMG_INVALID_DEBUG_PARMS 503 /* MSG%SMG_INVALID_DEBUG_PARMS */
+#define ERROR_KBD_EXTENDED_SG 504 /* MSG%KBD_EXTENDED_SG */
+#define ERROR_MOU_EXTENDED_SG 505 /* MSG%MOU_EXTENDED_SG */
+#define ERROR_SMG_INVALID_ICON_FILE 506 /* MSG%none */
+#define ERROR_TRC_PID_NON_EXISTENT 507 /* MSG%TRC_PID_NON_EXISTENT */
+#define ERROR_TRC_COUNT_ACTIVE 508 /* MSG%TRC_COUNT_ACTIVE */
+#define ERROR_TRC_SUSPENDED_BY_COUNT 509 /* MSG%TRC_SUSPENDED_BY_COUNT */
+#define ERROR_TRC_COUNT_INACTIVE 510 /* MSG%TRC_COUNT_INACTIVE */
+#define ERROR_TRC_COUNT_REACHED 511 /* MSG%TRC_COUNT_REACHED */
+#define ERROR_NO_MC_TRACE 512 /* MSG%NO_MC_TRACE */
+#define ERROR_MC_TRACE 513 /* MSG%MC_TRACE */
+#define ERROR_TRC_COUNT_ZERO 514 /* MSG%TRC_COUNT_ZERO */
+#define ERROR_SMG_TOO_MANY_DDS 515 /* MSG%SMG_TOO_MANY_DDS */
+#define ERROR_SMG_INVALID_NOTIFICATION 516 /* MSG%SMG_INVALID_NOTIFICATION */
+#define ERROR_LF_INVALID_FUNCTION 517 /* MSG%LF_INVALID_FUNCTION */
+#define ERROR_LF_NOT_AVAIL 518 /* MSG%LF_NOT_AVAIL */
+#define ERROR_LF_SUSPENDED 519 /* MSG%LF_SUSPENDED */
+#define ERROR_LF_BUF_TOO_SMALL 520 /* MSG%LF_BUF_TOO_SMALL */
+#define ERROR_LF_BUFFER_CORRUPTED 521 /* MSG%none */
+#define ERROR_LF_BUFFER_FULL 521 /* MSG%LF_BUF_FULL */
+#define ERROR_LF_INVALID_DAEMON 522 /* MSG%none */
+#define ERROR_LF_INVALID_RECORD 522 /* MSG%LF_INVAL_RECORD */
+#define ERROR_LF_INVALID_TEMPL 523 /* MSG%none */
+#define ERROR_LF_INVALID_SERVICE 523 /* MSG%LF_INVAL_SERVICE */
+#define ERROR_LF_GENERAL_FAILURE 524 /* MSG%LF_GENERAL_FAILURE */
+#define ERROR_LF_INVALID_ID 525 /* MSG%HPFS_DISK_ALREADY_INUSE */
+#define ERROR_LF_INVALID_HANDLE 526 /* MSG%HPFS_CANNOT_FORMAT_DISK */
+#define ERROR_LF_NO_ID_AVAIL 527 /* MSG%HPFS_CANNOT_COPY_SYS_DATA */
+#define ERROR_LF_TEMPLATE_AREA_FULL 528 /* MSG%HPFS_FORMAT_NOT_DONE */
+#define ERROR_LF_ID_IN_USE 529 /* MSG%HPFS_FMT_NOT_ENOUGH_MEM */
+#define ERROR_MOU_NOT_INITIALIZED 530 /* MSG%HPFS_SPECIFY_FIXDSK */
+#define ERROR_MOUINITREAL_DONE 531 /* MSG%HPFS_SPECIFY_ONE_DRIVE */
+#define ERROR_DOSSUB_CORRUPTED 532 /* MSG%HPFS_UNKNOWN_ERR_NO_FORMAT */
+#define ERROR_MOUSE_CALLER_NOT_SUBSYS 533 /* MSG%HPFS_SYNTAX_HELP */
+#define ERROR_ARITHMETIC_OVERFLOW 534 /* MSG%HPFS_DISK_FORMATING */
+#define ERROR_TMR_NO_DEVICE 535 /* MSG%HPFS_AVAIL_DISK_SPACE */
+#define ERROR_TMR_INVALID_TIME 536 /* MSG%HPFS_BAD_BLOCKS */
+#define ERROR_PVW_INVALID_ENTITY 537 /* MSG%HPFS_DISK_SPACE_AVAIL */
+#define ERROR_PVW_INVALID_ENTITY_TYPE 538 /* MSG%HPFS_SPACE_FORMATTED */
+#define ERROR_PVW_INVALID_SPEC 539 /* MSG%HPFS_TYPE_CUR_VOLUME_LABEL */
+#define ERROR_PVW_INVALID_RANGE_TYPE 540 /* MSG%HPFS_DRIVER_NOT_LOADED */
+#define ERROR_PVW_INVALID_COUNTER_BLK 541 /* MSG%HPFS_DRIVER_LOADER */
+#define ERROR_PVW_INVALID_TEXT_BLK 542 /* MSG%HPFS_CACHE_BUF_SPECIFIED */
+#define ERROR_PRF_NOT_INITIALIZED 543 /* MSG%HPFS_CHKDSK_PARM_ERROR */
+#define ERROR_PRF_ALREADY_INITIALIZED 544 /* MSG%HPFS_CHKDSK_NOACCESS_DRIVE */
+#define ERROR_PRF_NOT_STARTED 545 /* MSG%HPFS_UNKNOWN_ERR_NO_CHKDSK */
+#define ERROR_PRF_ALREADY_STARTED 546 /* MSG%HPFS_CHKDSK_NOT_ENOUGH_MEM */
+#define ERROR_PRF_TIMER_OUT_OF_RANGE 547 /* MSG%HPFS_CHKDSK_NOWRITEODATA */
+#define ERROR_PRF_TIMER_RESET 548 /* MSG%HPFS_CHKDSK_NORECOVER_DATA */
+/* 549%msg%HPFS_CHKDSK_NO_PARM_SPACE */
+/* 550%msg%HPFS_CHKDSK_NORECOGNIZE */
+/* 551%msg%HPFS_CHKDSK_NOROOT_FIND */
+/* 552%msg%HPFS_CHKDSK_NOFIX_FS_ERROR */
+/* 553%msg%HPFS_CHKDSK_CORRECT_FS_ERR */
+/* 554%msg%HPFS_CHKDSK_ORGAN_FIX */
+/* 555%msg%HPFS_CHKDSK_RELOC_BBPDATA */
+/* 556%msg%HPFS_CHKDSK_REM_CORRU_BLOC */
+/* 557%msg%HPFS_CHKDSK_REM_CORRUP_FIL */
+/* 558%msg%HPFS_CHKDSK_FIX_SPACE_ALLO */
+/* 559%msg%HPFS_NOT_FORMATTED_DISK */
+/* 560%msg%HPFS_CHKDSK_COR_ALLOC */
+/* 561%msg%HPFS_CHKDSK_SEARC_UNALLOC */
+/* 562%msg%HPFS_CHKDSK_DET_LOST_DATA */
+/* 563%msg%HPFS_CHKDSK_PERCENT_SEARC */
+/* 564%msg%HPFS_CHKDSK_LOST_DATASEARC */
+/* 565%msg%HPFS_CHKDSK_CRIT_NOREAD */
+/* 566%msg%HPFS_CHKDSK_DISK_INUSE */
+/* 567%msg%HPFS_CHKDSK_RECOVTEMP_RELOC */
+/* 568%msg%HPFS_TOTAL_DISK_SPACE */
+/* 569%msg%HPFS_DIR_KBYTES */
+/* 570%msg%HPFS_FILE_KBYTES */
+/* 571%msg%HPFS_KBYTES_AVAILABLE */
+/* 572%msg%HPFS_CHKDSK_PLACE_REC_FILE */
+/* 573%msg%HPFS_CHKDSK_RECO_DIR_AS */
+/* 574%msg%HPFS_CHKDSK_PLACEED_DATA */
+/* 575%msg%HPFS_CHKDSK_RECOV_EA */
+/* 576%msg%HPFS_CHKDSK_FIND_EA_INTEM */
+/* 577%msg%HPFS_CHKDSK_RELOC_TEMP_EA */
+/* 578%msg%HPFS_CHKDSK_RELOC_AC_LIST */
+/* 579%msg%HPFS_CHKDSK_LIST_NORELOC */
+/* 580%msg%HPFS_CHKDSK_TRUN_EA_LIST */
+/* 581%msg%HPFS_CHKDSK_TRUN_EA_NAME */
+/* 582%msg%HPFS_CHKDSK_TRUN_EA_BBLOCK */
+/* 583%msg%HPFS_CHKDSK_REM_INVALID_EA */
+/* 584%msg%HPFS_CHKDSK_FIX_EA_ALLOC */
+/* 585%msg%HPFS_CHKDSK_FIX_ALACCCTRL */
+/* 586%msg%HPFS_CHKDSK_ACCTR_LIST_BBL */
+/* 587%msg%HPFS_CHKDSK_REM_ACLIST */
+/* 588%msg%HPFS_CHKDSK_FOUND_DATANORL */
+/* 589%msg%HPFS_WRONG_VERSION */
+/* 590%msg%HPFS_CHKDSK_FOUND_DATATEMP */
+/* 591%msg%HPFS_CHKDSK_FIX_TEMPSTATUS */
+/* 592%msg%HPFS_CHKDSK_FIX_NEEDEADATA */
+/* 593%msg%HPFS_RECOVER_PARM_ERROR */
+/* 594%msg%HPFS_RECOV_FILE_NOT_FOUND */
+/* 595%msg%HPFS_RECOV_UNKNOWN_ERROR */
+/* 596%msg%HPFS_RECOV_NOT_ENOUGH_MEM */
+/* 597%msg%HPFS_RECOV_NOWRITE_DATA */
+/* 598%msg%HPFS_RECOV_NOTEMP_CREATE */
+/* 599%msg%HPFS_RECOV_EA_NOREAD */
+/* 600%msg%HPFS_RECOV_FILE_BYTES */
+/* 601%msg%HPFS_RECOV_BAD_BYTES_RECOV */
+/* 602%msg%HPFS_RECOV_FILEBYTES_NOREC */
+/* 603%msg%HPFS_RECOV_DISK_INUSE */
+/* 604%msg%HPFS_RECOV_FILE_NODELETE */
+/* 605%msg%HPFS_RECOV_NOCREATE_NEWFILE */
+/* 606%msg%HPFS_RECOV_SYSTEM_ERROR */
+/* 607%msg%HPFS_SYS_PARM_ERROR */
+/* 608%msg%HPFS_SYS_CANNOT_INSTALL */
+/* 609%msg%HPFS_SYS_DRIVE_NOTFORMATED */
+/* 610%msg%HPFS_SYS_FILE_NOCREATE */
+/* 611%msg%HPFS_SIZE_EXCEED */
+/* 612%msg%HPFS_SYNTAX_ERR */
+/* 613%msg%HPFS_NOTENOUGH_MEM */
+/* 614%msg%HPFS_WANT_MEM */
+/* 615%msg%HPFS_GET_RETURNED */
+/* 616%msg%HPFS_SET_RETURNED */
+/* 617%msg%HPFS_BOTH_RETURNED */
+/* 618%msg%HPFS_STOP_RETURNED */
+/* 619%msg%HPFS_SETPRTYRETURNED */
+/* 620%msg%HPFS_ALCSG_RETURNED */
+/* 621%msg%HPFS_MSEC_SET */
+/* 622%msg%HPFS_OPTIONS */
+/* 623%msg%HPFS_POS_NUM_VALUE */
+/* 624%msg%HPFS_VALUE_TOO_LARGE */
+/* 625%msg%HPFS_LAZY_NOT_VALID */
+/* 626%msg%HPFS_VOLUME_ERROR */
+/* 627%msg%HPFS_VOLUME_DIRTY */
+/* 628%msg%HPFS_NEW_SECTOR */
+/* 629%msg%HPFS_FORMAT_PARM_ERROR */
+/* 630%msg%HPFS_CANNOT_ACCESS_CONFIG */
+/* 631%msg%HPFS_RECOV_FILE */
+/* 632%msg%HPFS_CHKDSK_KBYTES_RESERVE */
+/* 633%msg%HPFS_CHKDSK_KBYTES_IN_EA */
+/* 634%msg%HPFS_BYTEBUF_SET */
+/* 635%msg%HPFS_FORMATTING_COMPLETE */
+/* 636%msg%HPFS_WRONG_VOLUME_LABEL */
+/* 637%msg%HPFS_FMAT_TOO_MANY_DRS */
+/* 638%msg%VDD_UNSUPPORTED_ACCESS */
+#define ERROR_VDD_LOCK_USEAGE_DENIED 639 /* KP.COM not supported in DOS */
+#define ERROR_TIMEOUT 640 /* MSG%none */
+#define ERROR_VDM_DOWN 641 /* MSG%none */
+#define ERROR_VDM_LIMIT 642 /* MSG%none */
+#define ERROR_VDD_NOT_FOUND 643 /* MSG%none */
+#define ERROR_INVALID_CALLER 644 /* MSG%none */
+#define ERROR_PID_MISMATCH 645 /* MSG%none */
+#define ERROR_INVALID_VDD_HANDLE 646 /* MSG%none */
+#define ERROR_VLPT_NO_SPOOLER 647 /* MSG%none */
+#define ERROR_VCOM_DEVICE_BUSY 648 /* MSG%none */
+#define ERROR_VLPT_DEVICE_BUSY 649 /* MSG%none */
+#define ERROR_NESTING_TOO_DEEP 650 /* MSG%none */
+#define ERROR_VDD_MISSING 651 /* MSG%VDD_MISSING */
+/* 689%msg%HPFS_LAZY_ON */
+/* 690%msg%HPFS_LAZY_OFF */
+#define ERROR_IMP_INVALID_PARM 691 /* MSG%none */
+#define ERROR_IMP_INVALID_LENGTH 692 /* MSG%none */
+#define ERROR_MON_BAD_BUFFER 730 /* MSG%BAD_MON_BUFFER */
+
+#define ERROR_MODULE_CORRUPTED 731 /* MSG%MODULE_CORRUPTED */
+
+/****/
+#define ERROR_LF_TIMEOUT 2055 /* MSG%LF_TIMEOUT */
+#define ERROR_LF_SUSPEND_SUCCESS 2057 /* MSG%LF_SUSP_SUCCESS */
+#define ERROR_LF_RESUME_SUCCESS 2058 /* MSG%LF_RESUM_SUCCESS */
+#define ERROR_LF_REDIRECT_SUCCESS 2059 /* MSG%LF_REDIR_SUCCESS */
+#define ERROR_LF_REDIRECT_FAILURE 2060 /* MSG%LF_REDIR_FAILURE */
+
+#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_BLOCKED 32791
+#define ERROR_NOBLOCK 32792
+#define ERROR_INSTANCE_SHARED 32793
+#define ERROR_NO_OBJECT 32794
+#define ERROR_PARTIAL_ATTACH 32795
+#define ERROR_INCACHE 32796
+#define ERROR_SWAP_IO_PROBLEMS 32797
+#define ERROR_CROSSES_OBJECT_BOUNDARY 32798
+#define ERROR_LONGLOCK 32799
+#define ERROR_SHORTLOCK 32800
+#define ERROR_UVIRTLOCK 32801
+#define ERROR_ALIASLOCK 32802
+#define ERROR_ALIAS 32803
+#define ERROR_NO_MORE_HANDLES 32804
+#define ERROR_SCAN_TERMINATED 32805
+#define ERROR_TERMINATOR_NOT_FOUND 32806
+#define ERROR_NOT_DIRECT_CHILD 32807
+#define ERROR_DELAY_FREE 32808
+#define ERROR_GUARDPAGE 32809
+#define ERROR_SWAPERROR 32900
+#define ERROR_LDRERROR 32901
+#define ERROR_NOMEMORY 32902
+#define ERROR_NOACCESS 32903
+#define ERROR_NO_DLL_TERM 32904
+#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
+#define ERROR_ENTRY_IS_CALLGATE 65079
+
+#endif /* INCL_ERROR2_H || INCL_DOSERRORS */
diff --git a/private/os2/ldr/exe386.h b/private/os2/ldr/exe386.h
new file mode 100644
index 000000000..631341423
--- /dev/null
+++ b/private/os2/ldr/exe386.h
@@ -0,0 +1,870 @@
+/*
+ * Title
+ *
+ * exe386.h
+ * (C) Copyright Microsoft Corp 1988-1990
+ *
+ * Description
+ *
+ * Data structure definitions for the OS/2
+ * executable file format (flat model).
+ *
+ * Modification History
+ *
+ * 90/07/30 Wieslaw Kalkus Modified linear-executable
+ * 88/08/05 Wieslaw Kalkus Initial version
+ */
+
+
+
+ /*_________________________________________________________________*
+ | |
+ | |
+ | OS/2 .EXE FILE HEADER DEFINITION - 386 version 0:32 |
+ | |
+ |_________________________________________________________________|
+ * */
+
+#define BITPERBYTE 8 /* Should never change */
+#define BITPERWORD 16 /* I'm not sure about this one */
+#define OBJPAGELEN 4096 /* Memory page size in bytes */
+#define E32RESBYTES1 1 /* First bytes reserved */
+#define E32RESBYTES2 0 /* Second bytes reserved */
+#define E32RESBYTES3 8 /* Third bytes reserved */
+#define E32RESBYTES4 28
+#define STD_EXTRA 7 /* Standard number of extra information*/
+ /* units palced in the header; this */
+ /* includes the following tables: */
+ /* - export, import, resource, */
+ /* exception, security, fixup and */
+ /* debug information */
+#define EXP 0 /* Export table position */
+#define IMP 1 /* Import table position */
+#define RES 2 /* Resource table position */
+#define EXC 3 /* Exception table position */
+#define SEC 4 /* Security table position */
+#define FIX 5 /* Fixup table position */
+#define DEB 6 /* Debug table position */
+
+struct info /* Extra information header block */
+{
+ unsigned long rva; /* Virtual relative address of info */
+ unsigned long size; /* Size of information block */
+};
+
+
+struct e32_exe /* LE 32-bit .EXE header */
+{
+ unsigned char e32_magic[4]; /* Magic number E32_MAGIC */
+ unsigned char e32_bworder; /* The byte/word ordering for the .EXE */
+ unsigned char e32_res1[E32RESBYTES1];
+ /* Reserved bytes - must be zero */
+ unsigned short e32_cpu; /* The CPU type */
+ unsigned short e32_os; /* The OS type */
+ unsigned short e32_subsys; /* The subsystem type */
+ unsigned short e32_osmajor; /* The operating system major ver. no. */
+ unsigned short e32_osminor; /* The operating system minor ver. no. */
+ unsigned short e32_linkmajor; /* The linker major version number */
+ unsigned short e32_linkminor; /* The linker minor version number */
+ unsigned short e32_usermajor; /* The user major version number */
+ unsigned short e32_userminor; /* The user minor version number */
+ unsigned long e32_mflags; /* Module flags */
+ unsigned long e32_vpages; /* Number of pages in memory image */
+ unsigned long e32_filechksum; /* Checksum for entire file */
+ unsigned long e32_entryrva; /* Relative virt. addr. of entry point */
+
+ unsigned long e32_vbase; /* Virtual base address of module */
+ unsigned long e32_vsize; /* Virtual size of the entire image */
+ unsigned long e32_hdrsize; /* Header information size */
+ unsigned long e32_filealign; /* Alignment factor used to */
+ /* align/truncate image pages */
+ unsigned long e32_pagesize; /* The size of one page for this module*/
+ unsigned long e32_timestamp; /* Time the .EXE file was created/modified*/
+ unsigned long e32_stackmax; /* Maximum stack size */
+ unsigned long e32_stackinit; /* Initial committed stack size */
+ unsigned long e32_heapmax; /* Maximum heap size */
+ unsigned long e32_heapinit; /* Initial committed heap size */
+ unsigned long e32_objcnt; /* Number of memory objects */
+ unsigned long e32_objtab; /* Object table offset */
+ unsigned long e32_dircnt; /* Number of module directives */
+ unsigned long e32_dirtab; /* Module format directives table off */
+ unsigned char e32_res3[E32RESBYTES3];
+ /* Reserved bytes - must be zero */
+ unsigned long e32_rescnt; /* Number of resources */
+ unsigned long e32_hdrextra; /* Number of extra info units in header*/
+ struct info e32_unit[STD_EXTRA];
+ /* Array of extra info units */
+ unsigned char e32_res4[E32RESBYTES4];
+};
+
+
+#define E32HDR_SIZE sizeof(struct e32_exe)
+
+#define E32_MAGIC(x) ((unsigned short)((x).e32_magic[0]<<BITPERBYTE)|(x).e32_magic[1])
+#define E32_MAGIC1(x) (x).e32_magic[0]
+#define E32_MAGIC2(x) (x).e32_magic[1]
+#define E32_BWORDER(x) (x).e32_bworder
+#define E32_CPU(x) (x).e32_cpu
+#define E32_OS(x) (x).e32_os
+#define E32_SUBSYS(x) (x).e32_subsys
+#define E32_OSMAJOR(x) (x).e32_osmajor
+#define E32_OSMINOR(x) (x).e32_osminor
+#define E32_LINKMAJOR(x) (x).e32_linkmajor
+#define E32_LINKMINOR(x) (x).e32_linkminor
+#define E32_USERMAJOR(x) (x).e32_usermajor
+#define E32_USERMINOR(x) (x).e32_userminor
+#define E32_MFLAGS(x) (x).e32_mflags
+#define E32_VPAGES(x) (x).e32_vpages
+#define E32_FILECHKSUM(x) (x).e32_filechksum
+#define E32_ENTRYRVA(x) (x).e32_entryrva
+#define E32_VBASE(x) (x).e32_vbase
+#define E32_VSIZE(x) (x).e32_vsize
+#define E32_HDRSIZE(x) (x).e32_hdrsize
+#define E32_FILEALIGN(x) (x).e32_filealign
+#define E32_PAGESIZE(x) (x).e32_pagesize
+#define E32_TIMESTAMP(x) (x).e32_timestamp
+#define E32_STACKMAX(x) (x).e32_stackmax
+#define E32_STACKINIT(x) (x).e32_stackinit
+#define E32_HEAPMAX(x) (x).e32_heapmax
+#define E32_HEAPINIT(x) (x).e32_heapinit
+#define E32_OBJCNT(x) (x).e32_objcnt
+#define E32_OBJTAB(x) (x).e32_objtab
+#define E32_DIRCNT(x) (x).e32_dircnt
+#define E32_DIRTAB(x) (x).e32_dirtab
+#define E32_RESCNT(x) (x).e32_rescnt
+#define E32_HDREXTRA(x) (x).e32_hdrextra
+#define E32_EXPTAB(x) (x).e32_unit[EXP].rva
+#define E32_EXPSIZ(x) (x).e32_unit[EXP].size
+#define E32_IMPTAB(x) (x).e32_unit[IMP].rva
+#define E32_IMPSIZ(x) (x).e32_unit[IMP].size
+#define E32_RESTAB(x) (x).e32_unit[RES].rva
+#define E32_RESSIZ(x) (x).e32_unit[RES].size
+#define E32_EXCTAB(x) (x).e32_unit[EXC].rva
+#define E32_EXCSIZ(x) (x).e32_unit[EXC].size
+#define E32_SECTAB(x) (x).e32_unit[SEC].rva
+#define E32_SECSIZ(x) (x).e32_unit[SEC].size
+#define E32_FIXTAB(x) (x).e32_unit[FIX].rva
+#define E32_FIXSIZ(x) (x).e32_unit[FIX].size
+#define E32_DEBTAB(x) (x).e32_unit[DEB].rva
+#define E32_DEBSIZ(x) (x).e32_unit[DEB].size
+
+
+
+/*
+ * Valid linear-executable signature:
+ */
+
+#define E32MAGIC1 'L' /* New magic number "LE" */
+#define E32MAGIC2 'E' /* New magic number "LE" */
+#define E32MAGIC 0x454c /* New magic number "LE" */
+
+/*
+ * Format of E32_BWORDER(x):
+ *
+ * 7 6 5 4 3 2 1 0 - bit no
+ * | |
+ * | +--- Big Endian Byte Ordering (else Little Endian)
+ * +----- Big Endian Word Ordering (else Little Endian)
+ */
+
+#define E32LEBO 0x00 /* Little Endian Byte Order */
+#define E32BEBO 0x01 /* Big Endian Byte Order */
+#define E32LEWO 0x00 /* Little Endian Word Order */
+#define E32BEWO 0x02 /* Big Endian Word Order */
+
+/*
+ * Valid CPU types:
+ */
+
+#define E32CPUUNKNOWN 0x000 /* Unknown CPU */
+#define E32CPU286 0x001 /* Intel 80286 or upwardly compatibile */
+#define E32CPU386 0x002 /* Intel 80386 or upwardly compatibile */
+#define E32CPU486 0x003 /* Intel 80486 or upwardly compatibile */
+#define E32CPU586 0x004 /* Intel 80586 or upwardly compatibile */
+#define E32CPUi860 0x020 /* Intel i860 or upwardly compatibile */
+#define E32CPUixxx 0x021 /* Intel i??? or upwardly compatibile */
+#define E32CPUMIPS_I 0x040 /* MIPS Mark I (R2000, R3000) */
+#define E32CPUMIPS_II 0x041 /* MIPS Mark II (R6000) */
+#define E32CPUMIPS_III 0x042 /* MIPS Mark II (R4000) */
+
+/*
+ * Target operating systems
+ */
+
+#define E32_UNKNOWN NE_UNKNOWN /* Unknown (any "new-format" OS) */
+#define E32_OS2 NE_OS2 /* Microsoft/IBM OS/2 (default) */
+#define E32_WINDOWS NE_WINDOWS /* Microsoft Windows */
+#define E32_DOS NE_DOS4 /* Microsoft MS-DOS */
+#define E32_NT 0x4 /* NT */
+#define E32_UNIX 0x5 /* UNIX */
+
+
+#ifndef FALSE
+
+/* DEFINED in the newexe.h !!!!! */
+
+#define NE_UNKNOWN 0x0 /* Unknown (any "new-format" OS) */
+#define NE_OS2 0x1 /* Microsoft/IBM OS/2 (default) */
+#define NE_WINDOWS 0x2 /* Microsoft Windows */
+#define NE_DOS4 0x3 /* Microsoft MS-DOS 4.x */
+#define NE_DEV386 0x4 /* Microsoft Windows 386 */
+#endif
+
+/*
+ * Target subsystems required to run module
+ */
+
+#define E32_SUB_UNKNOWN 0x0 /* Unknown subsystem */
+#define E32_SUB_OS2 0x1 /* OS/2 subsystem */
+#define E32_SUB_WINDOWS 0x2 /* Windows subsystem */
+#define E32_SUB_NATIVE 0x4 /* NT native subsystem */
+#define E32_SUB_POSIX 0x5 /* POSIX subsystem */
+
+
+/*
+ * Format of E32_MFLAGS(x):
+ *
+ * 31 25 24 16 15 8 7 0
+ * #### #### | #### #### | #### #### | #### #### - bit no
+ * |||| |||| |||| |||| |||| |||| |||| ||||
+ * |||| |||| |||| |||| |||| |||| |||| ||++-- Reserved - must be zero
+ * |||| |||| |||| |||| |||| |||| |||| |+---- Per-Process Library Initialization
+ * |||| |||| |||| |||| |||| |||| |||| +----- Reserved - must be zero
+ * |||| |||| |||| |||| |||| |||| |||+------- Resolved fixups have been removed
+ * |||| |||| |||| |||| |||| |||| +++-------- Reserved - must be zero
+ * |||| |||| |||| |||| |||| |+++-------------- Application type
+ * |||| |||| |||| |||| |||+-+----------------- Reserved - must be zero
+ * |||| |||| |||| |||| ||+-------------------- Module not Loadable
+ * |||| |||| |||| |||| |+--------------------- Reserved - must be zero
+ * |||| |||| |||| ||++---+---------------------- Module type
+ * ||++-++++---++++-++---------------------------- Reserved - must be zero
+ * |+--------------------------------------------- Per-Process Library Termination
+ * +---------------------------------------------- Reserved - must be zero
+ *
+ */
+
+
+#define E32_LIBINIT 0x0004L /* Per-Process Library Initialization */
+#define E32_NOINTFIX 0x0010L /* Resolved fixups have been removed */
+
+/*
+ * Application types:
+ *
+ * 0x000 - Illegal - reserved for future use
+ * 0x100 - Incompatible with PM windowing
+ * 0x200 - Compatible with PM windowing
+ * 0x300 - Uses PM windowing API
+ * 0x400 - Illegal - reserved for future use
+ * 0x500 - Illegal - reserved for future use
+ * 0x600 - Illegal - reserved for future use
+ * 0x700 - Illegal - reserved for future use
+ */
+
+#define E32_NOPMW 0x0100L /* Incompatible with PM Windowing */
+#define E32_PMW 0x0200L /* Compatible with PM Windowing */
+#define E32_PMAPI 0x0300L /* Uses PM Windowing API */
+#define E32_APPMASK 0x0700L /* Aplication Type Mask */
+
+#define E32_NOLOAD 0x2000L /* Module not Loadable */
+
+/*
+ * Module types:
+ *
+ * 0x00000 - Program module
+ * 0x08000 - Dynamic-Link Library module
+ * 0x10000 - Illegal - reserved for future use
+ * 0x18000 - Illegal - reserved for future use
+ * 0x20000 - Physical Device Driver module
+ * 0x28000 - Virtual Device Driver module
+ * 0x30000 - Illegal - reserved for future use
+ * 0x38000 - Illegal - reserved for future use
+ */
+
+#define E32_MODEXE 0x00000L /* Program module */
+#define E32_MODDLL 0x08000L /* Library Module - used as NENOTP */
+#define E32_MODPDEV 0x20000L /* Physical device driver */
+#define E32_MODVDEV 0x28000L /* Virtual device driver */
+#define E32_MODMASK 0x38000L /* Module type mask */
+
+#define E32_NOFIXUPS 0x20000000L /* Image has no fixups that reference the IAT or EAT */
+#define E32_LIBTERM 0x40000000L /* Per-Process library termination */
+#define E32_PURE32 0x80000000L /* Image is pure 32 bit */
+
+#define IsINSTINIT(x) ((x)&E32_LIBINIT)
+#define IsNOTRELOC(x) ((x)&E32_NOINTFIX)
+#define IsNOTGUI(x) (((x)&E32_APPMASK)==E32_NOPMW)
+#define IsGUICOMPAT(x) (((x)&E32_APPMASK)==E32_PMW)
+#define IsGUI(x) (((x)&E32_APPMASK)==E32_PMAPI)
+#define IsLOADABLE(x) (!((x)&E32_NOLOAD))
+#define IsAPLIPROG(x) (((x)&E32_MODMASK)==E32_MODEXE)
+#define IsDLL(x) (((x)&E32_MODMASK)==E32_MODDLL)
+#define IsPDEVICE(x) (((x)&E32_MODMASK)==E32_MODPDEV)
+#define IsVDEVICE(x) (((x)&E32_MODMASK)==E32_MODVDEV)
+#define NoFIXUPS(x) ((x)&E32_NOFIXUPS)
+#define IsINSTTERM(x) ((x)&E32_LIBTERM)
+#define IsPURE32(x) ((x)&E32_PURE32)
+
+#define SetINSTINIT(x) ((x)|=E32_LIBINIT)
+#define SetNOTRELOC(x) ((x)|=E32_NOINTFIX)
+#define SetNOTGUI(x) ((x)=((x)&~E32_APPMASK)|E32_NOPMW)
+#define SetGUICOMPAT(x) ((x)=((x)&~E32_APPMASK)|E32_PMW)
+#define SetGUI(x) ((x)=((x)&~E32_APPMASK)|E32_PMAPI)
+#define SetNOTLOADABLE(x) (((x)|=E32_NOLOAD))
+#define SetAPLIPROG(x) ((x)=((x)&~E32_MODMASK)|E32_MODEXE)
+#define SetDLL(x) ((x)=((x)&~E32_MODMASK)|E32_MODDLL)
+#define SetPDEVICE(x) ((x)=((x)&~E32_MODMASK)|E32_MODPDEV)
+#define SetVDEVICE(x) ((x)=((x)&~E32_MODMASK)|E32_MODVDEV)
+#define SetNOFIXUPS(x) ((x)|=E32_NOFIXUPS)
+#define SetINSTTERM(x) ((x)|=E32_LIBTERM)
+#define SetPURE32(x) ((x)|=E32_PURE32)
+
+
+/*
+ * OBJECT TABLE
+ */
+
+/***ET+ o32_obj Object Table Entry */
+
+struct o32_obj /* .EXE memory object table entry */
+{
+ unsigned long o32_rva; /* Object relative virtual address */
+ unsigned long o32_vsize; /* Virtual memory size */
+ unsigned long o32_pages; /* Image pages offset */
+ unsigned long o32_psize; /* Physical file size of init. data*/
+ unsigned long o32_flags; /* Attribute flags for the object */
+ unsigned long o32_reserved;
+};
+
+#define O32_OBJSIZE sizeof(struct o32_obj)
+
+#define O32_RVA(x) (x).o32_rva
+#define O32_VSIZE(x) (x).o32_vsize
+#define O32_PAGES(x) (x).o32_pages
+#define O32_PSIZE(x) (x).o32_psize
+#define O32_FLAGS(x) (x).o32_flags
+
+
+/*
+ * Format of O32_FLAGS(x)
+ *
+ * 31 25 24 16 15 8 7 0
+ * #### #### | #### #### | #### #### | #### #### - bit no
+ * |||| |||| |||| |||| |||| |||| |||| ||||
+ * |||| |||| |||| |||| |||| |||| |||| |||+-- Readable object
+ * |||| |||| |||| |||| |||| |||| |||| ||+--- Writable object
+ * |||| |||| |||| |||| |||| |||| |||| |+---- Executable object
+ * |||| |||| |||| |||| |||| |||| |||| +----- Resource object
+ * |||| |||| |||| |||| |||| |||| |||+------- Discardable object
+ * |||| |||| |||| |||| |||| |||| ||+-------- Shared object
+ * |||| |||| |||| |||| |||| |||| |+--------- Reserved - must be zero
+ * |||| |||| |||| |||| |||| |||| +---------- Trailing pages are invalid
+ * |||| |||| |||| |||| |||| ++++-------------- Object type
+ * |||| |||| |||| |||| |||+------------------- 16:16 Alias required
+ * |||| |||| |||| |||| ||+-------------------- Big/Default bit setting
+ * |||| |||| |||| |||| |+--------------------- Object is conformin for code
+ * |||| |||| |||| |||| +---------------------- Object has I/O privilege level
+ * |||| |||| |||| |||+-------------------------- Object must not be cached
+ * |||| |||| |||| ||+--------------------------- Debug object
+ * ++++-++++---++++-+++--------------------------- Reserved - must be zero
+ *
+ */
+
+#define OBJ_READ 0x0001L /* Readable Object */
+#define OBJ_WRITE 0x0002L /* Writeable Object */
+#define OBJ_EXEC 0x0004L /* Executable Object */
+#define OBJ_RSRC 0x0008L /* Resource Object */
+
+#define OBJ_DISCARD 0x0010L /* Object is Discardable */
+#define OBJ_SHARED 0x0020L /* Object is Shared */
+#define OBJ_INVALID 0x0080L /* Object has trailing invalid pages */
+
+/*
+ * Object types:
+ *
+ * 0x0000 - object is nonpermanent or normal EXE, DLL object
+ * 0x0100 - object is permanent (FDSs, VDDs, PDDs only)
+ * 0x0200 - object is resident (FDSs, VDDs, PDDs only)
+ * 0x0300 - object is contiguous (FDSs, VDDs, PDDs only)
+ * 0x0400 - object is dynamic (FDSs, VDDs, PDDs only)
+ * 0x0500 - illegal - reserved for future use
+ * 0x0600 - illegal - reserved for future use
+ * 0x0700 - illegal - reserved for future use
+ * 0x0800 - object reserves space for call-gates
+ * 0x0900 - illegal - reserved for future use
+ * 0x0a00 - illegal - reserved for future use
+ * 0x0b00 - illegal - reserved for future use
+ * 0x0c00 - illegal - reserved for future use
+ * 0x0d00 - illegal - reserved for future use
+ * 0x0e00 - illegal - reserved for future use
+ * 0x0f00 - illegal - reserved for future use
+ *
+ */
+
+#define OBJ_NONPERM 0x0000L /* Object is nonpermanent */
+#define OBJ_PERM 0x0100L /* Object is permanent and swappable */
+#define OBJ_RESIDENT 0x0200L /* Object is permanent and resident */
+#define OBJ_CONTIG 0x0300L /* Object is resident and contiguous */
+#define OBJ_DYNAMIC 0x0400L /* Object is dynamic */
+#define OBJ_GATE 0x0800L /* Object reserves space for call-gates */
+#define OBJ_TYPEMASK 0x0f00L /* Object type mask */
+
+
+#define OBJ_ALIAS16 0x1000L /* 16:16 alias required (80x86 specific) */
+#define OBJ_BIGDEF 0x2000L /* Big/Default bit setting (80x86 specific) */
+#define OBJ_CONFORM 0x4000L /* Object is conforming for code (80x86 specific) */
+#define OBJ_IOPL 0x8000L /* Object I/O privilege level (80x86 specific) */
+#define OBJ_CACHE 0x10000L /* Object must be cached */
+#define OBJ_DEBUG 0x20000L /* Object describes debugger information */
+
+#define IsREADABLE(x) ((x)&OBJ_READ)
+#define IsWRITEABLE(x) ((x)&OBJ_WRITE)
+#define IsEXECUTABLE(x) ((x)&OBJ_EXEC)
+#define IsRESOURCE(x) ((x)&OBJ_RSRC)
+#define IsDISCARDABLE(x) ((x)&OBJ_DISCARD)
+#define IsSHARED(x) ((x)&OBJ_SHARED)
+#define IsINVALID(x) ((x)&OBJ_INVALID)
+#define IsNONPERM(x) (((x)&OBJ_TYPEMASK)==OBJ_NONPERM)
+#define IsPERMANENT(x) (((x)&OBJ_TYPEMASK)==OBJ_PERM)
+#define IsRESIDENT(x) (((x)&OBJ_TYPEMASK)==OBJ_RESIDENT)
+#define IsCONTIG(x) (((x)&OBJ_TYPEMASK)==OBJ_CONTIG)
+#define IsDYNAMIC(x) (((x)&OBJ_TYPEMASK)==OBJ_DYNAMIC)
+#define IsGATERESERV(x) (((x)&OBJ_TYPEMASK)==OBJ_GATE)
+#define ObjTYPE(x) ((x)&OBJ_TYPEMASK)
+#define IsALIAS16(x) ((x)&OBJ_ALIAS16)
+#define IsBIGDEF(x) ((x)&OBJ_BIGDEF)
+#define IsCONFORMING(x) ((x)&OBJ_CONFORM)
+#define IsIOPL(x) ((x)&OBJ_IOPL)
+#define IsCACHED(x) ((x)&OBJ_CACHE)
+#define IsDEBUG(x) ((x)&OBJ_DEBUG)
+
+#define SetREADABLE(x) ((x)|=OBJ_READ)
+#define SetWRITABLE(x) ((x)|=OBJ_WRITE)
+#define SetEXECUTABLE(x) ((x)|=OBJ_EXEC)
+#define SetRESOURCE(x) ((x)|=OBJ_RSRC)
+#define SetDISCARABLE(x) ((x)|=OBJ_DISCARD)
+#define SetSHARED(x) ((x)|=OBJ_SHARED)
+#define SetINVALID(x) ((x)|=OBJ_INVALID)
+#define SetNONPERM(x) ((x)=((x)&~OBJ_TYPEMASK)|OBJ_NONPERM)
+#define SetPERMANENT(x) ((x)=((x)&~OBJ_TYPEMASK)|OBJ_PERM)
+#define SetRESIDENT(x) ((x)=((x)&~OBJ_TYPEMASK)|OBJ_RESIDENT)
+#define SetCONTIG(x) ((x)=((x)&~OBJ_TYPEMASK)|OBJ_CONTIG)
+#define SetDYNAMIC(x) ((x)=((x)&~OBJ_TYPEMASK)|OBJ_DYNAMIC)
+#define SetGATERESERV(x) ((x)=((x)&~OBJ_TYPEMASK)|OBJ_GATE)
+#define SetALIAS16(x) ((x)|=OBJ_ALIAS16)
+#define SetBIGDEF(x) ((x)|=OBJ_BIGDEF)
+#define SetCONFORMING(x) ((x)|=OBJ_CONFORM)
+#define SetIOPL(x) ((x)|=OBJ_IOPL)
+#define SetCACHED(x) ((x)|=OBJ_CACHE)
+#define SetDEBUG(x) ((x)|=OBJ_DEBUG)
+
+/*
+ * MODULE FORMAT DIRECTIVES TABLE
+ */
+
+struct FmtDir
+{
+ unsigned short dir; /* Directive number */
+ unsigned short reserved;
+ unsigned long offset; /* Directive data offset */
+ unsigned long length; /* Directive data length */
+};
+
+#define FMTDIR_SIZE sizeof(struct FmtDir)
+
+#define DIRECTIVE(x) (x).dir
+#define DIR_OFF(x) (x).offset
+#define DIR_LEN(x) (x).length
+
+/*
+ * Directive numbers
+ */
+
+#define OS2LDR16 0x200
+#define OS2RSRCNT 0x300
+#define OS2FIXMAP 0x400
+
+struct ComDir
+{
+ unsigned long stackobj;
+ unsigned long autods;
+};
+
+#define COMDIR_SIZE sizeof(struct ComDir)
+
+
+/*
+ * EXPORT ADDRESS TABLE - Previously called entry table
+ */
+
+struct ExpHdr /* Export directory table */
+{
+ unsigned long exp_flags; /* Export table flags */
+ unsigned long exp_ver; /* Version stamp */
+ unsigned long exp_size; /* Export table size */
+ unsigned long exp_dllname; /* Offset to the DLL name */
+ unsigned long exp_ordbase; /* First valid ordinal */
+ unsigned long exp_eatcnt; /* Number of EAT entries */
+ unsigned long exp_namecnt; /* Number of exported names */
+ unsigned long exp_eat; /* Export Address Table offset */
+ unsigned long exp_name; /* Export name pointers table off */
+ unsigned long exp_ordinal; /* Export ordinals table offset */
+};
+
+#define EXPHDR_SIZE sizeof(struct ExpHdr)
+
+#define EXP_FLAGS(x) (x).exp_flags
+#define EXP_DLLNAME(x) (x).exp_dllname
+#define EXP_VER(x) (x).exp_ver
+#define EXP_SIZE(x) (x).exp_size
+#define EXP_ORDBASE(x) (x).exp_ordbase
+#define EXP_EATCNT(x) (x).exp_eatcnt
+#define EXP_NAMECNT(x) (x).exp_namecnt
+#define EXP_EAT(x) (x).exp_eat
+#define EXP_NAME(x) (x).exp_name
+#define EXP_ORDINAL(x) (x).exp_ordinal
+
+/*
+ * EXPORT ADDRESS TABLE MASKS
+ */
+
+#define ESCAPE_BIT 0x80000000L /* Escape bit in export address */
+#define ADDR_MASK 0x7fffffffL /* Export address mask */
+#define VALUE_MASK 0x3fffffffL /* Value mask */
+
+/*
+ * ENTRY TYPES - TT field values
+ */
+
+#define AUX_DATA 0x40000000L /* Auxiliary data present */
+
+#define IsESCAPED(x) ((x)&ESCAPE_BIT)
+#define IsAUXDATA(x) ((x)&AUX_DATA)
+
+#define SetESCAPE(x) ((x)|=ESCAPE_BIT)
+#define SetAUXDATA(x) ((x)|=AUX_DATA)
+#define SetVALUE(x,v) ((x)|=((v)&VALUE_MASK))
+
+/*
+ * AUXILIARY DATA TYPES
+ */
+
+#define ABS_DATA 0x00
+#define INT_GATE 0x01
+#define EXT_GATE 0x02
+#define FORWARDER 0x03
+
+/*
+ * AUXILIARY DATA ENTRIES
+ */
+
+#pragma pack(1)
+
+struct AuxData
+{
+ unsigned char dataType;
+ unsigned char reserved;
+ union
+ {
+ struct AbsData
+ {
+ unsigned short reserved;
+ unsigned long val;
+ }
+ abs;
+ struct GateData
+ {
+ unsigned char obj;
+ unsigned char parm;
+ unsigned short off;
+ unsigned short sel;
+ }
+ gate;
+ struct FwdData
+ {
+ unsigned short idx;
+ unsigned long iat;
+ }
+ fwd;
+ }
+ data;
+};
+
+#pragma pack()
+
+#define DATA_TYP(x) (x).dataType
+#define ABS_VAL(x) (x).data.abs.val
+#define GATE_OBJ(x) (x).data.gate.obj
+#define GATE_PARM(x) (x).data.gate.parm
+#define GATE_OFF(x) (x).data.gate.off
+#define GATE_SEL(x) (x).data.gate.sel
+#define FWD_IDX(x) (x).data.fwd.idx
+#define FWD_IAT(x) (x).data.fwd.iat
+
+
+/*
+ * IMPORT MODULE DESCRIPTOR TABLE
+ */
+
+struct ImpHdr /* Import directory table */
+{
+ unsigned long imp_flags; /* Import table flags */
+ unsigned long imp_ver; /* Version stamp */
+ unsigned long imp_reserved;
+ unsigned long imp_dllname; /* Offset to the DLL name */
+ unsigned long imp_address; /* Import address table offset */
+};
+
+#define IMPHDR_SIZE sizeof(struct ImpHdr)
+
+#define IMP_FLAGS(x) (x).imp_flags
+#define IMP_VER(x) (x).imp_ver
+#define IMP_DLLNAME(x) (x).imp_dllname
+#define IMP_ADDRESS(x) (x).imp_address
+
+/*
+ * Format of IMP_FLAGS(x)
+ *
+ * 31 25 24 16 15 8 7 0
+ * #### #### | #### #### | #### #### | #### #### - bit no
+ * |||| |||| |||| |||| |||| |||| |||| ||||
+ * |||| |||| |||| |||| |||| |||| |||| |||+-- Copy of the IAT in header
+ * ++++-++++---++++-++++---++++-++++---++++-+++--- Reserved - must be zero
+ *
+ */
+
+#define HDRIAT 0x01
+
+#define IsHDRIAT(x) ((x)&HDRIAT)
+
+#define SetHDRIAT(x) ((x)|=HDRIAT)
+
+
+struct ImpMod
+{
+ unsigned long im_offset; /* Imported module name table offset */
+ unsigned long im_vaddr; /* Import Address table virtual address */
+};
+
+#define IMPMOD_SIZE sizeof(struct ImpMod)
+
+#define IM_OFFSET(x) (x).im_offset
+#define IM_VADDR(x) (x).im_vaddr
+
+/*
+ * IMPORT PROCEDURE NAME TABLE
+ */
+
+struct ImpProc
+{
+ unsigned short ip_hint; /* Hint value */
+ char ip_name[1]; /* Zero terminated imported procedure name */
+};
+
+#define IP_HINT(x) (x).ip_hint;
+
+/*
+ * IMPORT ADDRESS TABLE
+ */
+
+/*
+ * Valid import address types:
+ *
+ * 0x00000000 - 0:32 Offset - Flat offset
+ * 0x20000000 - 16:16 non-FLAT, non-gate pointer
+ * 0x40000000 - 16:16 gate pointer - Callgate needed if used
+ * 0x60000000 - Illegal - reserved for future use
+ *
+ */
+
+#define IMPORD_MASK 0x1fffffffL /* Ordinal number mask */
+#define IMPOFF_MASK 0x1fffffffL /* Import data offset mask */
+#define IMPTYPE_MASK 0x60000000L /* Import address type mask */
+#define ORD_BIT 0x80000000L /* Import by ordinal bit */
+
+#define IMP_FLATOFF 0x00000000L /* FLAT offset */
+#define IMP_ALIAS 0x20000000L /* 16:16 non-FLAT, non-gate pointer */
+#define IMP_GATE 0x40000000L /* 16:16 gate pointer */
+
+#define IsIMPBYORD(x) ((x)&ORD_BIT)
+#define IsFLATIMP(x) (!((x)&IMPTYPE_MASK))
+#define IsALIASIMP(x) (((x)&IMPTYPE_MASK)==IMP_ALIAS)
+#define IsGATEIMP(x) (((x)&IMPTYPE_MASK)==IMP_GATE)
+
+/*
+ * RESOURCE TABLE
+ */
+
+/***ET+ rsrc32 - Resource Table Entry */
+
+struct ResDir
+{
+ unsigned long dir_flags;
+ unsigned long dir_ver;
+ unsigned long dir_size;
+ unsigned short dir_namecnt;
+ unsigned short dir_idcnt;
+};
+
+
+struct ResDirEntry
+{
+ unsigned long dir_name;
+ unsigned long dir_data;
+};
+
+struct ResDirStrEntry
+{
+ unsigned short str_len;
+ char ast_ascii[1];
+};
+
+struct ResData
+{
+ unsigned long res_data;
+ unsigned long res_size;
+ unsigned long res_codepage;
+ unsigned long res_reserved;
+};
+
+/*end*/
+
+
+/*
+ * RELOCATION DEFINITIONS - RUN-TIME FIXUPS
+ */
+
+
+/***ET+ r32_rlc - Relocation item */
+
+struct r32_rlc
+{
+ unsigned short flags;
+ unsigned char cnt;
+ unsigned char obj;
+};
+
+
+#define R32_FLAGS(x) (x).flags
+#define R32_CNT(x) (x).cnt
+#define R32_OBJ(x) (x).obj
+
+
+/*
+ * Format of R32_FLAGS - relocation flags
+ *
+ * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - bit no
+ * | | | | | | | | | | | | | | | |
+ * | | | | | | | | | | | | +-+-+-+--- Source type
+ * | | | | | | | | | | | +----------- Fixup to 16:16 alias
+ * | | | | | | | | | | +------------- Reserved - must be zero
+ * | | | | | | | | | +--------------- Fixup data present
+ * | | | | | | | | +----------------- Reserved - must be zero
+ * | | | | | | +-+------------------- Reference type
+ * | | | | | +----------------------- Target has IOPL - valid only for non-aliased selector fixups
+ * | | | | +-------------------------- Target is CODE (else DATA) - valid only for non-aliased selector fixups
+ * | +--+--+----------------------------- Reserved - must be zero
+ * +-------------------------------------- Escaped fixup
+ */
+
+/*
+ * Valid source types:
+ *
+ * 0x00 - Byte fixup (8-bits)
+ * 0x01 - Align fixup - nop used to skip 2 bytes
+ * 0x02 - 16-bit Selector fixup (16-bits)
+ * 0x03 - 16:16 Pointer fixup (32-bits)
+ * 0x04 - Illegal - reserved for future use
+ * 0x05 - 16-bit Offset fixup (16-bits)
+ * 0x06 - 16:32 Pointer fixup (48-bits)
+ * 0x07 - 32-bit Offset fixup (32-bits)
+ * 0x08 - 32-bit Self-relative offset fixup (32-bits)
+ * 0x09 - Illegal - reserved for future use
+ * 0x0a - Illegal - reserved for future use
+ * 0x0b - Illegal - reserved for future use
+ * 0x0c - Illegal - reserved for future use
+ * 0x0d - Illegal - reserved for future use
+ * 0x0e - Illegal - reserved for future use
+ * 0x0f - Illegal - reserved for future use
+ */
+
+
+#define R32_BYTE 0x0000
+#define R32_ALIGN 0x0001
+#define R32_SEL 0x0002
+#define R32_PTR32 0x0003
+#define R32_OFF16 0x0005
+#define R32_PTR48 0x0006
+#define R32_OFF32 0x0007
+#define R32_SOFF32 0x0008
+#define R32_SRCMASK 0x000f
+
+#define IsBYTE(x) (((x)&R32_SRCMASK)==R32_BYTE)
+#define IsALIGN(x) (((x)&R32_SRCMASK)==R32_ALIGN)
+#define IsSEL(x) (((x)&R32_SRCMASK)==R32_SEL)
+#define IsPTR32(x) (((x)&R32_SRCMASK)==R32_PTR32)
+#define IsOFF16(x) (((x)&R32_SRCMASK)==R32_OFF16)
+#define IsPTR48(x) (((x)&R32_SRCMASK)==R32_PTR48)
+#define IsOFF32(x) (((x)&R32_SRCMASK)==R32_OFF32)
+#define IsSOFF32(x) (((x)&R32_SRCMASK)==R32_SOFF32)
+
+#define R32_ALIAS 0x0010 /* Fixup to alias */
+#define R32_FIXDATA 0x0040 /* Fixup data present */
+#define R32_IOPL 0x0080 /* Fixup Source has IOPL and is not conforming */
+
+
+#define IsALIAS(x) ((x)&R32_ALIAS)
+#define IsFIXDATA(x) ((x)&R32_FIXDATA)
+#define IsSRCIOPL(x) ((x)&R32_IOPL)
+
+/*
+ * Reference types:
+ *
+ * 0x0000 - internal reference
+ * 0x0100 - Imported reference by ordinal or name
+ * 0x0200 - Illegal - reserved for future use
+ * 0x0300 - Internal reference via export address table
+ *
+ */
+
+#define R32_INTER 0x0000 /* Internal reference */
+#define R32_IMPORT 0x0100 /* Imported reference */
+#define R32_ENTRY 0x0300 /* Internal entry table fixup */
+#define R32_REFMASK 0x0300 /* Reference type mask */
+
+#define IsINTERNAL(x) (((x)&R32_REFMASK)==R32_INTER)
+#define IsIMPORT(x) (((x)&R32_REFMASK)==R32_IMPORT)
+#define IsENTRY(x) (((x)&R32_REFMASK)==R32_ENTRY)
+
+#define TGT_IOPL 0x0400 /* Target has IOPL */
+#define TGT_CODE 0x0800 /* Target is CODE */
+
+#define IsTGTIOPL(x) ((x)&TGT_IOPL)
+#define IsTGTCODE(x) ((x)&TGT_CODE)
+
+#define R32_ESCAPE 0x8000
+#define IsESCAPEFIX(x) ((x)&R32_ESCAPE)
+
+/*end*/
+
+
+/*
+ * DEBUG INFORMATION
+ */
+
+struct DbgDir
+{
+ unsigned long dbg_flags;
+ unsigned long dbg_ver;
+ unsigned long dbg_size;
+ unsigned long dbg_type;
+ unsigned long dbg_lva;
+ unsigned long dbg_seek;
+};
+
+#define DBG_FLAGS(x) (x).dbg_flags
+#define DBG_TYPE(x) (x).dbg_type
+#define DBG_VER(x) (x).dbg_ver
+#define DBG_LVA(x) (x).dbg_lva
+#define DBG_SIZE(x) (x).dbg_size
+#define DBG_SEEK(x) (x).dbg_seek
+#define DBGDIR_SIZE sizeof(struct DbgDir)
diff --git a/private/os2/ldr/ldrdbcs.c b/private/os2/ldr/ldrdbcs.c
new file mode 100644
index 000000000..758a4770b
--- /dev/null
+++ b/private/os2/ldr/ldrdbcs.c
@@ -0,0 +1,159 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ ldrdbcs.c
+
+Abstract:
+
+ This module contains the multibyte string functions.
+
+Author:
+
+ Akihiko Sasaki (V-AkihiS) 23-June-1993
+
+Revision History:
+
+--*/
+
+#ifdef DBCS
+
+#include "ldrdbcs.h"
+
+unsigned char * _CRTAPI1
+ldrMultiByteStrchr(
+ const unsigned char *string,
+ unsigned short c
+ )
+{
+ const unsigned char ch = c;
+
+ while (*string != ch) {
+ if (IsDBCSLeadByte(*string)) {
+ string++;
+ }
+ if (*string == '\0')
+ return NULL;
+ string++;
+ }
+ return (unsigned char *)string;
+}
+
+unsigned char * _CRTAPI1
+ldrMultiByteStrrchr(
+ const unsigned char *string,
+ unsigned short c
+ )
+{
+ const unsigned char ch = c;
+ const unsigned char *lastoccurence = NULL;
+
+ while (1) {
+ if (IsDBCSLeadByte(*string)) {
+ string++;
+ } else {
+ if (*string == ch)
+ lastoccurence = string;
+ }
+ if (*string == '\0')
+ return (unsigned char *)lastoccurence;
+ string++;
+ }
+}
+
+unsigned char * _CRTAPI1
+ldrMultiByteStrstr(
+ const unsigned char *string1,
+ const unsigned char *string2
+ )
+{
+ if (*string2 == '\0')
+ return (unsigned char *)string1;
+ while((string1 = ldrMultiByteStrchr(string1, *string2)) != NULL) {
+ const unsigned char *substring1 = string1;
+ const unsigned char *substring2 = string2;
+
+ while (1) {
+ if (IsDBCSLeadByte(*substring1)) {
+ if (IsDBCSLeadByte(*substring2)) {
+ if (*substring1++ == *substring2++) {
+ if (*substring2 == '\0')
+ if (*substring1 == '\0')
+ return (unsigned char *)string1;
+ else
+ return NULL;
+ else if (*substring1++ != *substring2++)
+ break;
+ } else {
+ if (*substring1 == '\0' || *substring2 == '\0')
+ return NULL;
+ substring1 +=2;
+ substring2 +=2;
+ }
+ } else {
+ if (*substring2 == '\0') {
+ return (unsigned char *)string1;
+ } else {
+ substring1++;
+ if (*substring1 == '\0')
+ return NULL;
+ substring1++;
+ substring2++;
+ }
+ }
+ } else {
+ if (IsDBCSLeadByte(*substring2)) {
+ if (*substring1 == '\0') {
+ return NULL;
+ } else {
+ substring2++;
+ if (*substring2 == '\0')
+ return NULL;
+ substring1++;
+ substring2++;
+ }
+
+ } else {
+ if (*substring2 == '\0')
+ return (unsigned char *)string1;
+ else if (*substring1 == '\0')
+ return NULL;
+ else if (*substring1++ != *substring2++)
+ break;
+ }
+ }
+ }
+ string1++;
+ }
+ return NULL;
+}
+
+unsigned char * _CRTAPI1
+ldrMultiByteStrpbrk(
+ const unsigned char *string1,
+ const unsigned char *string2
+ )
+{
+ const unsigned char *substring1, *substring2;
+
+ substring1 = string1;
+ while (*substring1 != '\0') {
+ substring2 = string2;
+ if (IsDBCSLeadByte(*substring1)) {
+ substring1++;
+ if (*substring1 == '\0')
+ return NULL;
+ } else {
+ while (*substring2 != '\0') {
+ if (*substring1 == *substring2)
+ return (unsigned char *)substring1;
+ substring2++;
+ }
+ }
+ substring1++;
+ }
+ return NULL;
+}
+#endif
diff --git a/private/os2/ldr/ldrdbcs.h b/private/os2/ldr/ldrdbcs.h
new file mode 100644
index 000000000..f8ae6abe7
--- /dev/null
+++ b/private/os2/ldr/ldrdbcs.h
@@ -0,0 +1,48 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ ldrdbcs.h
+
+Abstract:
+
+ Prototypes for OS/2 subsystem internal multibyte string functions
+
+Author:
+
+ Akihiko Sasaki (V-AkihiS) 23-June-1993
+
+Revision History:
+
+--*/
+
+#ifdef DBCS
+
+#include <string.h>
+
+unsigned char * _CRTAPI1
+ldrMultiByteStrchr(
+ const unsigned char *,
+ unsigned short
+ );
+
+unsigned char * _CRTAPI1
+ldrMultiByteStrrchr(
+ const unsigned char *,
+ unsigned short
+ );
+
+unsigned char * _CRTAPI1
+ldrMultiByteStrstr(
+ const unsigned char *,
+ const unsigned char *
+ );
+
+unsigned char * _CRTAPI1
+ldrMultiByteStrpbrk(
+ const unsigned char *,
+ const unsigned char *
+ );
+#endif
diff --git a/private/os2/ldr/ldrdll.def b/private/os2/ldr/ldrdll.def
new file mode 100644
index 000000000..7b2c4c119
--- /dev/null
+++ b/private/os2/ldr/ldrdll.def
@@ -0,0 +1,28 @@
+LIBRARY LDRDLL
+
+DESCRIPTION 'OS/2 Emulation Subsystem - 16-bit loader DLL'
+
+SECTIONS .text READ WRITE EXECUTE
+
+EXPORTS
+ LDRNewExe
+ ldrSetDescInfo
+ LDRStop
+ ldrstart
+ ldrLibiInit
+ ldrInit
+ LDRDosLoadModule
+ LDRGetProcAddr
+ LDRGetModName
+ LDRGetModHandle
+ LDRLibiReturn
+ LDRDosFreeModule
+ LDRGetResource
+ LDRGetResource2
+ LDRFreeResource
+ LDRQAppType
+ Od2JumpTo16SignalDispatch
+ LDRIsLDTValid
+ LDRExecInfo constant
+ LDRDoscallsSel constant
+ pldrLibiRecord constant
diff --git a/private/os2/ldr/ldrextrn.h b/private/os2/ldr/ldrextrn.h
new file mode 100644
index 000000000..c336d899a
--- /dev/null
+++ b/private/os2/ldr/ldrextrn.h
@@ -0,0 +1,127 @@
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_FILESYS
+#define INCL_ERROR_H
+#define INCL_TYPES
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <bseerr.h>
+#include "os2tile.h"
+#include "os2srv.h"
+#include "os2defp.h"
+#include "mi.h"
+#include "seldesc.h"
+#define FOR_EXEHDR 1
+#include "newexe.h"
+#include "exe386.h"
+#include "ldrvars.h"
+#include "ldrxport.h"
+#include "os2ldr.h"
+#ifdef DBCS
+// MSKK Apr.19.1993 V-AkihiS
+//
+// OS/2 internal multibyte string function.
+//
+#include "ldrdbcs.h"
+#define strpbrk ldrMultiByteStrpbrk
+#define strchr ldrMultiByteStrchr
+#define strrchr ldrMultiByteStrrchr
+#endif
+
+int ldrFindModule(PUCHAR pachModname, USHORT cb, USHORT class,
+ ldrmte_t **ppmte);
+int ldrOpenNewExe(PUCHAR pachModname, USHORT cb, ldrlv_t *plv,
+ PUSHORT pfl, PBOOLEAN pBound, PULONG pNEFlags);
+APIRET ldrGetMte(PUCHAR pachModname, USHORT cb, UCHAR chLdrtype,
+ USHORT class, ldrmte_t **ppmte, PBOOLEAN pBound, PULONG pNEFlags);
+int ldrGetModParams(ldrmte_t *pmte, ldrrei_t *pei);
+int ldrIsAttached(ldrmte_t *pmte);
+void ldrChkLoadType(ULONG lflags, ldrlv_t *plv);
+void ldrPromoteMTE(ldrmte_t *pmte);
+int ldrCheckGlobal(PUCHAR pachname, USHORT cb, ldrmte_t **ppmte);
+int ldrCheckSpecific(ldrmte_t **ppmte, ldrlv_t *plv);
+int ldrCheckInternalName(ldrmte_t *pmte);
+int ldrMungeFlags(struct e32_exe *pe32);
+APIRET ldrCreateMte(struct e32_exe *pe32, ldrlv_t *plv);
+int ldrMTEValidatePtrs(ldrmte_t *pmte, ULONG limit, ULONG constant);
+void ldrExpandSegment(ldrmte_t *pmte, UCHAR type);
+int ldrOpenPath(PUCHAR pachModname, USHORT cb, ldrlv_t *plv,
+ ULONG *pflmte);
+void ldrstart(ldrrei_t *pexec_info);
+ldrmte_t *ldrFindMTEForHandle(USHORT hmte);
+APIRET Allocate16BHandle(PUSHORT pusHandle, ULONG h32bHandle);
+APIRET Free16BHandle(USHORT usHandle);
+APIRET ldrAllocSegment(ldrmte_t *pmte, ldrste_t *pste, ulong_t iseg);
+APIRET ldrDoFixups(ri_t *pri, ulong_t laddr, struct taddr_s *ptaddr,
+ ushort_t segsize);
+APIRET ldrLoadIteratedData(ldrmte_t *pmte,
+ ldrste_t *pste,
+ PIO_STATUS_BLOCK pIoStatusBlock,
+ ULONG laddr);
+ldrote_t *ldrNumToOte(ldrmte_t *pmte, ulong_t objnum);
+APIRET ldrAllocSegments(ldrlv_t *plv);
+APIRET ldrLoadModule(ldrlv_t *plv);
+APIRET ldrLoadSegment(ldrmte_t *pmte, ldrste_t *pste);
+APIRET ldrGetTgtMte(ushort_t modord, ldrmte_t *pmte, ldrmte_t **ptgtmte);
+ulong_t ldrAscToOrd(char *pachstring, int cchstring);
+APIRET ldrGetOrdNum(ldrmte_t *pmte, uchar_t *pprocnam, ushort_t *pentord, int fstring);
+APIRET ldrGetOrdNumSub(uchar_t *pnt, uchar_t *pprocnam, ushort_t *pentord);
+APIRET ldrGetEntAddr(ushort_t entord, ldrmte_t *pmte,
+ struct taddr_s *ptaddr, ldrste_t *psrcste, ldrmte_t *psrcmte);
+APIRET ldrGetModule(PUCHAR pachModname, USHORT cb, char chLdrtype,
+ USHORT class, ldrmte_t **ppmte, PBOOLEAN pBound, PULONG pNEFlags);
+int ldrEachObjEntry(ulong_t objnum,
+ ldrmte_t *pmte,
+ int (*pwork)(ldret_t *pet, ulong_t *pentry,
+ ldrmte_t *pmte, ldrlv_t *plv),
+ ldrlv_t *plv);
+int ldrInitEntry(ldret_t *pet, ulong_t *pentry,
+ ldrmte_t *pmte, ldrlv_t *plv);
+int ldrEditProlog(ldret_t *pet, ulong_t *pentry,
+ ldrmte_t *pmte, ldrlv_t *plv);
+int ldrGetCallGate(ldret_t *pet, ulong_t *pentry,
+ ldrmte_t *pmte, ldrlv_t *plv);
+int ldrFreeCallGate(ldret_t *pet, ulong_t *pentry,
+ ldrmte_t *pmte, ldrlv_t *plv);
+ulong_t ldrSkipEnts(ldrmte_t *pmte, uchar_t type, uchar_t count);
+VOID ldrUnlinkMTE(ldrmte_t *pmte);
+VOID ldrTagModuleTree(ldrmte_t *pmte);
+VOID ldrTagModuleTree_USED(ldrmte_t *pmte);
+BOOLEAN ldrUnloadTagedModules(POS2_PROCESS Process);
+VOID ldrClearAllMteFlag(ULONG Flags);
+VOID ldrWriteErrTxt(int errcode);
+VOID ldrUCaseString(PCHAR pstring, ULONG cb);
+VOID ldrNewExeInit(POS2_THREAD t,P_LDRNEWEXE_MSG a,PUSHORT cb);
+#if PMNT
+BOOLEAN ldrSaveErrInfo(int errcode);
+VOID ldrRestoreErrInfo(int *errcode);
+BOOLEAN ldrFreeErrInfo(VOID);
+#endif
+
+#define SEL_RPL3 0x3 // Rpl Ring 3
+#define SEL_RPLCLR 0xfffc // Non RPL bits mask
+
+ULONG Ol2EntryFlat;
+ldrlibi_t *pldrLibiRecord;
+ULONG *pldrLibiCounter;
+
+PSTRING Od2ExecPgmErrorText;
+
+jmp_buf ljmpError;
+
+POS2_THREAD CurrentThread;
+
+ULONG ProgramIndex;
+
+ULONG LoadFactor;
+
+PSTRING pErrText;
+
+BOOLEAN fForceUnmap;
+
+BOOLEAN DoscallsLoaded;
+
+HANDLE R2XferSegHandle;
+
diff --git a/private/os2/ldr/ldrfixup.c b/private/os2/ldr/ldrfixup.c
new file mode 100644
index 000000000..1e5941eba
--- /dev/null
+++ b/private/os2/ldr/ldrfixup.c
@@ -0,0 +1,483 @@
+
+#include "ldrextrn.h"
+#ifdef PMNT
+#define INCL_32BIT
+#include "pmnt.h"
+extern PID PMNTPMShellPid;
+#endif
+
+/***LP ldrGetTgtMte - get target mte linear address
+ *
+ * Get MTE of module referenced by ordinal number passed. Use the
+ * ordinal number to index into the import module pointers table.
+ *
+ * ENTRY modord - ordinal number of module referenced
+ * pmte - pointer to mte
+ * pptgtmte - pointer to target mte
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ * ptgtmte - mte linear address
+ * if mte == 0 reference to DOSCALLS
+ *
+ * This procedure performs the following steps:
+ *
+ * - Check that module ordinal number is within module pointer table
+ * - Index into module pointer table and return linear address to mte
+ */
+
+APIRET ldrGetTgtMte(modord, pmte, pptgtmte)
+ushort_t modord;
+ldrmte_t *pmte;
+ldrmte_t **pptgtmte;
+{
+ modord--; /* normalize ordinal */
+
+ if (modord < (ushort_t) pmte->mte_impmodcnt) {
+ *pptgtmte = ((ldrmte_t *) ((ulong_t *) pmte->mte_modptrs)[modord]);
+ return(NO_ERROR);
+ }
+
+ /*
+ * set error = ERROR_BAD_EXE_FORMAT
+ */
+ return(ERROR_BAD_EXE_FORMAT);
+}
+
+/***LP ldrGetEntAddr - get entry point address
+ *
+ * For a given ordinal number, this routine locates the
+ * appropriate entry contained in the module's entry table.
+ * It returns a 48-bit pointer for the specified entry point.
+ *
+ * ENTRY entord - ordinal number
+ * pmte - pointer to target mte
+ * ptaddr - pointer to return target address (off,sel,flags)
+ * psrcste - pointer to source ste
+ * psrcmte - pointer to source mte
+ *
+ * EXIT entry point address
+ * global variable obj_ptr pointing to target segment
+ * global variable entry_ptr pointing to entry table entry
+ *
+ * This procedure performs the following steps:
+ *
+ * - Check for zero ordinal number
+ * - Normalize ordinal number
+ * - Checks and handles installable file system mte entry points
+ * - Checks and handles DOSCALLS mte entry points
+ * - Locates the correct bundle for the given ordinal
+ * - Creates the desired entry point address based on source and target
+ */
+
+APIRET ldrGetEntAddr(entord, pmte, ptaddr, psrcste, psrcmte)
+ushort_t entord;
+register ldrmte_t *pmte;
+register struct taddr_s *ptaddr;
+ldrste_t *psrcste;
+ldrmte_t *psrcmte;
+{
+ int fcallgate;
+ ulong_t objnum;
+ ldrsmte_t *psmte;
+
+ UNREFERENCED_PARAMETER(psrcmte);
+
+ psmte = pmte->mte_swapmte;
+
+ (ulong_t) ldrProcNameBuf = (ulong_t) entord;
+
+ if (entord == 0) {
+ return(ERROR_INVALID_ORDINAL);
+ }
+#if PMNT
+ /*
+ * This process loads PMWIN.WinCreateMsgQueue()
+ */
+ if (entord == 58 &&
+ 5 == (USHORT) *((PCHAR )pmte->mte_modname) &&
+ ! strncmp((PCHAR)(pmte->mte_modname+1),"PMWIN",5)) {
+ CurrentThread->Process->Flags |= OS2_PROCESS_PMMSGQUE;
+ }
+ /*
+ * This process loads PMNT.PMNTSetPMshellFlag(), thus it is PM Shell.
+ */
+ else if (entord == 12 &&
+ 4 == (USHORT) *((PCHAR )pmte->mte_modname) &&
+ ! strncmp((PCHAR)(pmte->mte_modname+1),"PMNT",4)) {
+ if (!PMNTPMShellPid) {
+ PMNTPMShellPid = CurrentThread->Process->ProcessId;
+ CurrentThread->Process->Flags |= OS2_PROCESS_IS_PMSHELL;
+ }
+ else {
+ // Do not allow another PMshell
+ return(ERROR_2ND_PMSHELL);
+ }
+ }
+
+#endif
+
+ --entord; /* Normalize object number */
+
+ ptaddr->fflags = 0; /* Clear forwarder flags */
+ fcallgate = FALSE; /* assume not a callgate entry */
+
+ if (ldrIsNE(pmte)) { /* check for 16-bit module */
+
+ register ldrste_t *pste;
+ register ldret_t *pbndl;
+ ldrcte_t *pcte;
+ ldrent_t *pent;
+
+ /*
+ * Find entry point, loop to determine which bundle the
+ * ordinal number belongs too.
+ */
+ pbndl = (ldret_t *) psmte->smte_enttab;
+
+ while (TRUE) { /* find bundle ord is in */
+ if (pbndl->et_cnt == 0) { /* check for end of table */
+ return(ERROR_INVALID_ORDINAL);
+ }
+
+ if (entord < pbndl->et_cnt) /* is ord in this bundle? */
+ break;
+
+ entord -= pbndl->et_cnt;
+ pbndl = (ldret_t *)((char *) pbndl +
+ ldrSkipEnts(pmte, pbndl->et_type, pbndl->et_cnt));
+ }
+
+ if (pbndl->et_type == EMPTY) {/* check for empty bundle */
+ return(ERROR_INVALID_ORDINAL);
+ }
+
+ pent = (ldrent_t *)((char *) pbndl +
+ ldrSkipEnts(pmte, pbndl->et_type, (uchar_t) entord));
+ pcte = (ldrcte_t *) pent;
+
+ ptaddr->fflags |= FWD_ALIAS16; /* indicate tiled object */
+ if (pbndl->et_type == B16MOVABLE) { /* check for movable entry */
+ objnum = pcte->cte_obj;
+ /* get target object */
+ if (objnum == B16ABSOLUTE) { /* if absolute entry */
+ ptaddr->toff = (ulong_t) pcte->cte_off;
+ ptaddr->tsel = 0;
+ ptaddr->tflags = pcte->cte_flags;
+ return(NO_ERROR);
+ }
+ if (objnum > psmte->smte_objcnt) {
+ return(ERROR_INVALID_SEGMENT_NUMBER);
+ }
+ pste = (ldrste_t *) psmte->smte_objtab + objnum - 1;
+ ptaddr->toff = (ulong_t) pcte->cte_off;
+ //
+ // If the target object is a code segment which has IOPL (ring 2)
+ // create call gate emulation
+ //
+ if ((pcte->cte_sel != 0) &&
+ (pcte->cte_sel != 0x3fcd) &&
+ ((psrcste == NULL) || // ldrDosGetProcAddress() calls with NULL
+ (((psrcste->ste_flags & STE_SEGDPL) == STE_RING_3) &&
+ ((psrcste->ste_flags & STE_DATA) == 0))) // source is a code segment
+ ) {
+ ptaddr->fflags |= FWD_IOPL;
+ ptaddr->toff = (ulong_t)pcte->cte_sel;
+ ptaddr->tsel = FLATTOSEL(R2XFER_BASE);
+ return(NO_ERROR);
+ }
+ }
+
+ /*
+ * check for absolute entry
+ */
+ else if (pbndl->et_type == B16ABSOLUTE) {
+ ptaddr->toff = (ulong_t) pent->ent_off;
+ ptaddr->tsel = 0;
+ ptaddr->tflags = pent->ent_flags;
+ return(NO_ERROR);
+ }
+ else { /* entry is fixed */
+ if((ulong_t) pbndl->et_type > psmte->smte_objcnt) {
+ return(ERROR_INVALID_SEGMENT_NUMBER);
+ }
+
+ /*
+ * get target object
+ */
+ pste = (ldrste_t *) psmte->smte_objtab + pbndl->et_type - 1;
+ ptaddr->toff = (ulong_t) pent->ent_off;
+ }
+
+ ptaddr->tsel = pste->ste_selector | 7;
+ ptaddr->tflags = pent->ent_flags;
+ return(NO_ERROR);
+ }
+
+ return(NO_ERROR);
+}
+
+
+/***LP ldrGetOrdNum - get the ordinal number for procedure name
+ *
+ * Given a procedure name and a module table, checks to see if
+ * the procedure is in the resident or nonresident table. If the
+ * procedure is found in either of the tables, ldrGetOrdNum
+ * returns the corresponding ordinal number. A 0 ordinal is
+ * returned if the procedure is not found in either of the tables.
+ *
+ * ENTRY pmte - pointer to module table entry
+ * pprocnam - pointer to procedure name
+ * pentord - address to return ordinal number
+ * fstring - flag to tell if null terminated
+ * STRINGNULLTERM
+ * STRINGPREPENDED
+ *
+ * EXIT if found
+ * NO_ERROR
+ * else
+ * ERROR_NOT_ENOUGH_MEMORY
+ * ERROR_PROC_NOT_FOUND
+ */
+
+APIRET ldrGetOrdNum(pmte, pprocnam, pentord, fstring)
+ldrmte_t *pmte;
+uchar_t *pprocnam;
+ushort_t *pentord;
+int fstring;
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ PIO_STATUS_BLOCK pIoStatusBlock = &IoStatusBlock;
+ LARGE_INTEGER ByteOffset;
+ PVOID MemoryAddress;
+ ULONG RegionSize;
+ ulong_t cbread;
+ register ldrsmte_t *psmte;
+ ushort_t proclen;
+ char tname[MAX_PROC_LEN+1];
+ char *ptname;
+ int rc = NO_ERROR;
+
+ ptname = (char *) &tname;
+ psmte = pmte->mte_swapmte;
+
+ ldrProcNameBuf = (PUCHAR) (pprocnam + 1);
+ ldrProcNameBufL = proclen = (USHORT) (pprocnam[0]);
+
+ /*
+ * Check for 32-bit module
+ */
+ if (ldrIsLE(pmte)) {
+ struct ExpHdr *pexpdir;
+ ulong_t *pexpnameptrs;
+ ushort_t *pexpordinals;
+
+ if (fstring == STRINGNONNULL) {
+
+ /*
+ * Since the procedure name strings in a 32-bit module are in
+ * the format of a null terminated string we need to convert
+ * the 16-bit formated string of a length followed by string
+ * to a null terminated string.
+ */
+ proclen = pprocnam[0];
+ memcpy(pprocnam, pprocnam + 1, proclen);
+ pprocnam[proclen] = '\0';
+ }
+ pexpdir = (struct ExpHdr *) psmte->smte_expdir;
+ pexpnameptrs = (ulong_t *) pexpdir->exp_name;
+ pexpordinals = (ushort_t *) pexpdir->exp_ordinal;
+// rc = ldrBinarySearchOrd(psmte,
+// pprocnam,
+// pexpnameptrs,
+// pexpordinals,
+// pexpdir->exp_namecnt,
+// pentord);
+ /*
+ * Restore procedure name back to length followed by string.
+ */
+// if (fstring == STRINGNONNULL) {
+// ldrStrCpyB(pprocnam + 1, pprocnam, proclen);
+// pprocnam[0] = (uchar_t) proclen;
+// }
+
+ return(rc);
+ }
+
+ /*
+ * Check for null terminated string passed. If it is we were called
+ * by ldrGetProcAddr and we may do this in place copy and not restore
+ * it because it is from the stack of ldrGetProcAddr
+ */
+ if (fstring == STRINGNULLTERM) {
+ proclen = (ushort_t) strlen(pprocnam);
+ strncpy(&ptname[1], pprocnam, proclen);
+ ptname[0] = (uchar_t) proclen;
+ }
+
+ else {
+ strncpy(ptname, pprocnam, proclen + 1);
+ }
+
+ /*
+ * 16-bit module, first search the resident name table.
+ */
+ if ((rc = ldrGetOrdNumSub((uchar_t *) psmte->smte_restab,
+ ptname,
+ pentord)) != ERROR_PROC_NOT_FOUND) {
+ return(rc);
+ }
+#if DBG
+ IF_OL2_DEBUG ( FIXUP ) {
+ if (fstring == STRINGNONNULL) {
+ strncpy(&tname[0], &pprocnam[1], proclen);
+ tname[proclen] = '\0';
+ DbgPrint(
+ "Could not find Procedure %s in module %s in Resident name table\n",
+ &tname, (char *) (pmte->mte_modname+1));
+ }
+ else {
+ DbgPrint(
+ "Could not find Procedure %s in module %s in Resident name table\n",
+ pprocnam, (char *) (pmte->mte_modname+1));
+ }
+
+ if (fstring == STRINGNONNULL) {
+ strncpy(ptname, pprocnam, proclen + 1);
+ }
+ }
+#endif
+
+ /*
+ * The procedure name was not found in the resident name table,
+ * need to search the non-resident name table.
+ * Do not do this for system dll's other than doscall
+ */
+
+ if (pmte->mte_mflags & DOSMOD) {
+ return(ERROR_PROC_NOT_FOUND);
+ }
+
+ RegionSize = psmte->smte_cbnrestab;
+ MemoryAddress = 0;
+ if ((rc = NtAllocateVirtualMemory(NtCurrentProcess(),
+ &MemoryAddress,
+ 0,
+ &RegionSize,
+ MEM_COMMIT,
+ PAGE_READWRITE)) != NO_ERROR) {
+ return(ERROR_PROC_NOT_FOUND);
+ }
+
+ /*
+ * read the non-resident nametable from the file into non-
+ * resident name table object.
+ */
+ ByteOffset.LowPart = psmte->smte_nrestab;
+ ByteOffset.HighPart = 0;
+ cbread = psmte->smte_cbnrestab;
+ if ((rc = NtReadFile(pmte->mte_sfn,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ (void *) MemoryAddress,
+ cbread,
+ &ByteOffset,
+ 0)) != 0) {
+ return(ERROR_BAD_EXE_FORMAT);
+ }
+
+ if (IoStatusBlock.Information != cbread) {
+ rc = ERROR_BAD_EXE_FORMAT;
+ goto returnstatus;
+ }
+
+ /*
+ * Now check if the procname is in the nonresident name table.
+ */
+ rc = ldrGetOrdNumSub((uchar_t *) MemoryAddress,
+ ptname,
+ pentord);
+returnstatus:
+ NtFreeVirtualMemory(NtCurrentProcess(),
+ &MemoryAddress,
+ &cbread,
+ MEM_RELEASE);
+ if (rc == NO_ERROR)
+ return(rc);
+
+ if (fstring == STRINGNONNULL) {
+ strncpy(&ptname[0], &pprocnam[1], proclen);
+ ptname[proclen] = '\0';
+ }
+#if DBG
+ IF_OL2_DEBUG ( FIXUP ) {
+ DbgPrint(
+ "Could not find Procedure %s in module %s in Non-resident table\n",
+ ptname, (char *) (pmte->mte_modname+1));
+ }
+#endif
+ return(ERROR_PROC_NOT_FOUND);
+}
+
+
+/***LP ldrGetOrdNumSub - get the ordinal number for procedure name
+ *
+ * Given a procedure name and a resident or nonresident name table
+ * containing the procedures exported by a module, checks to see
+ * if the procedure is in the table. If the procedure is found
+ * in the table, ldrGetOrdNumSub gets the corresponding ordinal
+ * number. A 0 ordinal value is returned if the procedure is not
+ * found in the table. The ordinal number for the module name string
+ * is set to zero, therefore matching strings with a 0 ordinal number
+ * are skipped.
+ *
+ * ENTRY pnt - pointer to resident or nonresident name table
+ * pprocnam - pointer to procedure name
+ * pentord - place to return ordinal
+ *
+ * EXIT if found
+ * NO_ERROR
+ * else
+ * ERROR_PROC_NOT_FOUND
+ * ERROR_BAD_EXE_FORMAT
+ *
+ * This procedure performs the following steps:
+ *
+ * - compare procedure name to each entry in table
+ * - if ordinal number is 0 skip to next string
+ * - return ordinal number if found
+ */
+
+APIRET ldrGetOrdNumSub(pnt, pprocnam, pentord)
+register uchar_t *pnt;
+register uchar_t *pprocnam;
+ushort_t *pentord;
+{
+ register int len;
+
+
+ /*
+ * remove typeinfo from length
+ */
+ while ((len = (int) (*pnt /*& ~NT_TYPEINFO*/)) != 0) { // YOSEFD: The using of the flag
+ // harm the names that are longer
+ // then 0x7F. The description string
+ // can be longer.
+ /*
+ * include string size field
+ */
+ if (memcmp(pnt, pprocnam, ++len) == 0)
+
+ if ((*(ushort_t *) (pnt + len)) != 0) {
+ /*
+ * return ordinal number
+ */
+ *pentord = *(ushort_t *)(pnt + len);
+ return(NO_ERROR);
+ }
+ pnt += len + sizeof(ushort_t); /* skip to next string */
+ }
+
+ return(ERROR_PROC_NOT_FOUND); /* end of table, return not found */
+}
diff --git a/private/os2/ldr/ldrinit.c b/private/os2/ldr/ldrinit.c
new file mode 100644
index 000000000..684fa6e07
--- /dev/null
+++ b/private/os2/ldr/ldrinit.c
@@ -0,0 +1,1415 @@
+#include <string.h>
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_FILESYS
+#define INCL_DOSERRORS
+#include "bseerr.h"
+#include <os2ssrtl.h>
+#include "os2defp.h"
+#include "mi.h"
+#define FOR_EXEHDR 1
+#include "newexe.h"
+#include "exe386.h"
+#include "ldrvars.h"
+#include <ldrxport.h>
+#include <os2tile.h>
+#include <os2file.h>
+#include <os2ldr.h>
+
+USHORT LDRDoscallsSel;
+
+PVOID LDRNEHeap;
+
+CHAR ldrLibPathBuf[1024];
+
+PCHAR ldrpLibPath = ldrLibPathBuf;
+
+ULONG SizeOfldrLibPathBuf = sizeof(ldrLibPathBuf);
+
+char LdrBuf[MAXPATHLEN+14]; // 14 is for the '\OS2SS\DRIVES\'
+
+char *pheaderbuf;
+
+ldrmte_t *mte_h = NULL; /* head of linked mte list */
+
+ldrmte_t *program_h = NULL; /* head of list of program modules */
+
+ldrmte_t *program_l = NULL; /* tail of list of program modules */
+
+ldrmte_t *global_h = NULL; /* head of list of global modules */
+
+ldrmte_t *global_l = NULL; /* tail of list of global modules */
+
+ldrmte_t *specific_h = NULL; /* head of list of specific modules */
+
+ldrmte_t *specific_l = NULL; /* tail of list of specific modules */
+
+ushort_t ldrInitCallGate; /* first selector of call gate obj */
+
+ulong_t ldrMINSEGPACKCNT = 5;
+ulong_t ldrMINPGPACKSIZE = 0xf00; /* 4k-256 */
+ulong_t ldrMAXSEGPACKSIZE = 32768; /* 32K */
+
+ldrlibi_t *pldrLibiRecord = NULL;
+ULONG *pldrLibiCounter = NULL;
+
+PUCHAR ldrSrcModNameBuf = NULL;
+ushort_t ldrSrcModNameBufL = 0;
+PUCHAR ldrTgtModNameBuf = NULL;
+ushort_t ldrTgtModNameBufL = 0;
+PUCHAR ldrProcNameBuf = NULL;
+ushort_t ldrProcNameBufL = 0;
+#if PMNT
+PUCHAR ldrSaveSrcModNameBuf = NULL;
+ushort_t ldrSaveSrcModNameBufL = 0;
+PUCHAR ldrSaveTgtModNameBuf = NULL;
+ushort_t ldrSaveTgtModNameBufL = 0;
+PUCHAR ldrSaveProcNameBuf = NULL;
+ushort_t ldrSaveProcNameBufL = 0;
+int ldrSaveRc = 0;
+#endif
+
+HANDLE R2XferSegHandle;
+
+PSTRING pErrText;
+
+ldrmte_t acscallmte;
+ldrsmte_t acscallsmte;
+
+ldrmte_t kbdcallmte;
+ldrsmte_t kbdcallsmte;
+
+ldrmte_t maicallmte;
+ldrsmte_t maicallsmte;
+
+ldrmte_t moncallmte;
+ldrsmte_t moncallsmte;
+
+ldrmte_t moucallmte;
+ldrsmte_t moucallsmte;
+
+ldrmte_t msgcallmte;
+ldrsmte_t msgcallsmte;
+
+ldrmte_t namcallmte;
+ldrsmte_t namcallsmte;
+
+ldrmte_t apicallmte;
+ldrsmte_t apicallsmte;
+
+ldrmte_t oemcallmte;
+ldrsmte_t oemcallsmte;
+
+ldrmte_t nlscallmte;
+ldrsmte_t nlscallsmte;
+
+#ifndef PMNT
+ldrmte_t pmscallmte;
+ldrsmte_t pmscallsmte;
+
+ldrmte_t pmwcallmte;
+ldrsmte_t pmwcallsmte;
+
+ldrmte_t os2smcallmte;
+ldrsmte_t os2smcallsmte;
+#endif
+
+ldrmte_t quecallmte;
+ldrsmte_t quecallsmte;
+
+ldrmte_t sescallmte;
+ldrsmte_t sescallsmte;
+
+#ifdef PMNT
+ldrmte_t pmntcallmte;
+ldrsmte_t pmntcallsmte;
+#endif
+
+ldrmte_t viocallmte;
+ldrsmte_t viocallsmte;
+
+#ifdef DBCS
+// MSKK Dec.15.1992 V-AkihiS
+// Support IMMON API
+ldrmte_t imdaemonmte;
+ldrsmte_t imdaemonsmte;
+#endif
+
+//BUGBUG - used to assign selector's till LDT defined
+ushort_t UserGDTSelector=0x93;
+
+ulong_t LdrSaveStack;
+
+/*
+ * this table is used to validate and update pointer in the MTE in
+ * mtevalidateptrs
+ * ******* NOTE: ********
+ * If the entry in the array for the resource table changes you need to
+ * also change the define rsrcvalidatetbl
+ */
+ ushort_t validatetbl[] = {
+ FIELDOFFSET(ldrsmte_t, smte_expdir), /* export directory */
+ FIELDOFFSET(ldrsmte_t, smte_impdir), /* import directory */
+ FIELDOFFSET(ldrsmte_t, smte_fixtab), /* fixup table */
+ FIELDOFFSET(ldrsmte_t, smte_rsrctab), /* resource table */
+ FIELDOFFSET(ldrsmte_t, smte_iat), /* 16-bit imp proc table */
+ ENDMTETBL, /* MUST BE AT END OF TABLE */
+ };
+
+/*
+ * This table is used to copy the linker EXE formated header to the loader
+ * Resident MTE format in place.
+ */
+struct etmt_s ExeToResMTETbl[] = {
+ {
+ FIELDOFFSET(struct e32_exe, e32_magic), /* Magic number and usecnt */
+ },
+ {
+ FIELDOFFSET(struct e32_exe, e32_mflags), /* Module flags */
+ },
+ {
+ (USHORT) SKIPCOPY, /* # entries in Imp Mod Tbl */
+ },
+ {
+ (USHORT) SKIPCOPY, /* mte_modptrs */
+ },
+ {
+ (USHORT) SKIPCOPY, /* mte_modname */
+ },
+ {
+ (USHORT) SKIPCOPY, /* mte_handle and mte_sfn */
+ },
+ {
+ (USHORT) SKIPCOPY, /* mte_link */
+ },
+ {
+ (USHORT) SKIPCOPY, /* mte_swapmte */
+ },
+ {
+ ENDMTETBL, /* MUST BE AT END OF TABLE */
+ }
+ };
+
+/*
+ * This table is used to copy the linker EXE formated header to the
+ * (LE) loader Swappable MTE format.
+ */
+struct etmt_s ExeTo32SwapMTETbl[] = {
+ {
+ FIELDOFFSET(struct e32_exe, e32_entryrva), /* Extended IP */
+ },
+ {
+ (USHORT) SKIPCOPY, /* stack object */
+ },
+ {
+ FIELDOFFSET(struct e32_exe, e32_stackmax), /* committed stack */
+ },
+ {
+ FIELDOFFSET(struct e32_exe, e32_objtab), /* Object table offset */
+ },
+ {
+ FIELDOFFSET(struct e32_exe, e32_objcnt), /* Object table count */
+ },
+ {
+ (USHORT) SKIPCOPY, /* Offset of fixup page map */
+ },
+ {
+ FIELDOFFSET(struct e32_exe, e32_unit[EXP].rva),/* Offset of Export Tb */
+ },
+ {
+ FIELDOFFSET(struct e32_exe, e32_unit[IMP].rva),/* Offset of Import Tb */
+ },
+ {
+ FIELDOFFSET(struct e32_exe, e32_unit[FIX].rva),/* Offset of Fixup Tb */
+ },
+ {
+ FIELDOFFSET(struct e32_exe, e32_unit[RES].rva),/* Offset of resource Tb */
+ },
+ {
+ (USHORT) SKIPCOPY, /* Count of resources */
+ },
+ {
+ FIELDOFFSET(struct e32_exe, e32_filealign), /* Alignment factor */
+ },
+ {
+ FIELDOFFSET(struct e32_exe, e32_vbase), /* load address of module */
+ },
+ {
+ FIELDOFFSET(struct e32_exe, e32_heapmax), /* Maximum heap size */
+ },
+ {
+ (USHORT) SKIPCOPY, /* skip autods */
+ },
+ {
+ (USHORT) SKIPCOPY, /* skip iat pointer */
+ },
+ {
+ FIELDOFFSET(struct e32_exe, e32_unit[DEB].rva),/* Offset of Debug info */
+ },
+ {
+ FIELDOFFSET(struct e32_exe, e32_unit[DEB].size),/* Size of debug info */
+ },
+ {
+ (USHORT) SKIPCOPY, /* skip delta size */
+ },
+ {
+ (USHORT) SKIPCOPY, /* skip cache pointer */
+ },
+ {
+ (USHORT) SKIPCOPY, /* skip pathname pointer */
+ },
+ {
+ (USHORT) SKIPCOPY, /* skip pathname length */
+ }, /* and skip dyn trace count */
+ {
+ (USHORT) SKIPCOPY, /* skip semaphore count */
+ }, /* and skip semaphore owner */
+ {
+ (USHORT) SKIPCOPY, /* 16-bit non-res tb offset */
+ },
+ {
+ (USHORT) SKIPCOPY, /* 16-bit size of non-res table */
+ },
+ {
+ (USHORT) SKIPCOPY, /* 16-bit count of segs to pack */
+ },
+ {
+ (USHORT) SKIPCOPY, /* 16-bit size of obj for seg pack */
+ },
+ {
+ (USHORT) SKIPCOPY, /* 16-bit VA of seg packed obj */
+ },
+ {
+ (USHORT) SKIPCOPY, /* zero and skip copy of NEflags */
+ }, /* and smte_NEexpver */
+ {
+ (USHORT) SKIPCOPY, /* zero and skip copy of NEexetype */
+ }, /* and smte_NEflagsothers */
+ {
+ ENDMTETBL, /* MUST BE AT END OF TABLE */
+ }
+ };
+
+/*
+ * This table is used to copy the linker EXE formated header to the
+ * (NE) loader Swappable MTE format.
+ */
+struct etmt_s ExeTo16SwapMTETbl[] = {
+ {
+ FIELDOFFSET(struct new_exe, ne_csip), /* Extended IP */
+ }, /* get offset only of starting address */
+ {
+ FIELDOFFSET(struct e32_exe, e32_res4)+2, /* Object # for stack ptr */
+ },
+ {
+ FIELDOFFSET(struct e32_exe, e32_res4), /* extended stack pointer */
+ },
+ {
+ FIELDOFFSET(struct new_exe, ne_segtab), /* Object table offset */
+ },
+ {
+ FIELDOFFSET(struct new_exe, ne_cseg), /* Object table count */
+ },
+ {
+ (USHORT) SKIPCOPY, /* Offset of fixup page map */
+ },
+ {
+ FIELDOFFSET(struct new_exe, ne_enttab), /* Offset of entry table */
+ },
+ {
+ FIELDOFFSET(struct new_exe, ne_imptab), /* Offset of Import Tb */
+ },
+ {
+ FIELDOFFSET(struct new_exe, ne_restab), /* Offset of resident name */
+ },
+ {
+ FIELDOFFSET(struct new_exe, ne_rsrctab), /* Offset of resource Tb */
+ },
+ {
+ FIELDOFFSET(struct new_exe, ne_cres), /* count of resources */
+ },
+ {
+ FIELDOFFSET(struct new_exe, ne_align), /* Alignment factor */
+ },
+ {
+ (USHORT) SKIPCOPY, /* vbase */
+ },
+ {
+ FIELDOFFSET(struct new_exe, ne_heap), /* Maximum heap size */
+ },
+ {
+ FIELDOFFSET(struct new_exe, ne_autodata), /* autods segment # */
+ },
+ {
+ FIELDOFFSET(struct new_exe, ne_modtab), /* Offset of module ref tb */
+ },
+ {
+ (USHORT) SKIPCOPY, /* debug info */
+ },
+ {
+ FIELDOFFSET(struct new_exe, ne_stack), /* Stack size */
+ },
+ {
+ FIELDOFFSET(struct new_exe, ne_csip)+2, /* Start object number */
+ },
+ {
+ (USHORT) SKIPCOPY, /* skip cache pointer */
+ },
+ {
+ (USHORT) SKIPCOPY, /* skip pathname pointer */
+ },
+ {
+ (USHORT) SKIPCOPY, /* skip pathname length */
+ }, /* and skip dyn trace count */
+ {
+ (USHORT) SKIPCOPY, /* skip semaphore count */
+ }, /* and skip semaphore owner */
+ {
+ FIELDOFFSET(struct new_exe, ne_nrestab),/* 16-bit non-resident tb off */
+ },
+ {
+ (USHORT) SKIPCOPY, /* 16-bit size of non-res */
+ }, /* This is a DWORD value copy later */
+ {
+ (USHORT) SKIPCOPY, /* 16-bit count of packed segments */
+ },
+ {
+ (USHORT) SKIPCOPY, /* 16-bit size of packed object */
+ },
+ {
+ (USHORT) SKIPCOPY, /* 16-bit pointer to packed object */
+ },
+ {
+ FIELDOFFSET(struct new_exe, ne_flags),/* copy of ne_flags */
+ }, /* and zero ne_expver */
+ {
+ FIELDOFFSET(struct new_exe, ne_exetyp),/* copy of ne_exetype */
+ }, /* and zero ne_flagsothers */
+ {
+ ENDMTETBL, /* MUST BE AT END OF TABLE */
+ }
+ };
+
+/*
+ * This table is used to copy header info for the API DosQueryHeaderInfo
+ * function HEADER_EXEINFO, see VR32QueryHeaderInfo.
+ */
+struct hit_s HeaderInfoTbl[] = {
+ {
+ FIELDOFFSET(ldrsmte_t, smte_NEflags),/* Original flags from NE header */
+ sizeof(((ldrsmte_t *) 0)->smte_NEflags),/* number of bytes to copy */
+ },
+ {
+ FIELDOFFSET(ldrsmte_t, smte_NEflagsothers),/* fixup page table */
+ sizeof(((ldrsmte_t *) 0)->smte_NEflagsothers),/* number of bytes to copy */
+ },
+ {
+ FIELDOFFSET(ldrsmte_t, smte_NEexetype),/* exetyp from NE header */
+ sizeof(((ldrsmte_t *) 0)->smte_NEexetype),/* number of bytes to copy */
+ },
+ {
+ FIELDOFFSET(ldrsmte_t, smte_NEexpver),/* expver from NE header */
+ sizeof(((ldrsmte_t *) 0)->smte_NEexpver),/* number of bytes to copy */
+ },
+ {
+ 0, /* special case for size of rsrc table */
+ 2, /* copy 2 bytes */
+ },
+ {
+ ENDMTETBL, /* MUST BE AT END OF TABLE */
+ 0, /* copy 0 bytes */
+ }
+ };
+
+
+/*
+ * This table is used to copy header info for the API DosQueryHeaderInfo
+ * function HEADER_STE, see VR32QueryHeaderInfo.
+ */
+struct his_s HeaderInfoSTE[] = {
+ {
+ FIELDOFFSET(ldrste_t, ste_offset), /* file offset to segment data */
+ 2, /* copy 2 bytes */
+ },
+ {
+ FIELDOFFSET(ldrste_t, ste_size), /* file data size */
+ 2, /* copy 2 byte */
+ },
+ {
+ FIELDOFFSET(ldrste_t, ste_flags), /* type and attribute flags */
+ 2, /* copy 2 byte */
+ },
+ {
+ FIELDOFFSET(ldrste_t, ste_minsiz), /* minimum allocation size */
+ 2, /* copy 2 bytes */
+ },
+ {
+ ENDMTETBL, /* MUST BE AT END OF TABLE */
+ 0, /* copy 0 bytes */
+ }
+ };
+
+/*
+ * This structure is used to convert from Object type flags to the
+ * required VM flags needed for allocation of memory. See setVMflags()
+ * for use.
+ */
+
+struct objflags_s objflags[] =
+ {
+ {
+ OBJ_READ, /* Readable Object */
+ PAG_READ, /* Allocate as Readable */
+ },
+ {
+ OBJ_WRITE, /* Writeable Object */
+ PAG_WRITE, /* Allocate as Writeable */
+ },
+ {
+ OBJ_EXEC, /* Executable Object */
+ PAG_EXECUTE, /* Alloc as eXecutable and shared */
+ },
+ {
+ 0, /* must have end of table entry */
+ 0,
+ }
+ };
+
+/*
+ * This sturcture is used to convert from Object type flags to the
+ * required SEL flags needed for allocation of memory. See setVMflags()
+ * for use.
+ */
+
+struct selflags_s selflags[] =
+ {
+ {
+ OBJ_READ, /* Readable Object */
+ 0, /* Allocate as Readable */
+ },
+ {
+ OBJ_WRITE, /* Writeable Object */
+ 0, /* Allocate as Writeable */
+ },
+ {
+ OBJ_EXEC, /* Executable Object */
+ 0, /* Alloc as eXecutable and readable */
+ },
+ {
+ OBJ_CONFORM, /* Objects is conforming */
+ 0,
+ },
+ {
+ 0, /* must have end of table entry */
+ 0,
+ }
+ };
+
+#include <ldrtabs.h>
+
+//
+// The segtab structure below is overwritten by the segment values
+// of the DOSCALLS.DLL module when it is first loaded.
+//
+ldrste_t segtab;
+/* =
+{
+ 0,
+ 0,
+ 0x0c00,
+ 0,
+ 0,
+ FLATTOSEL(DOSCALLS_BASE),
+ 0
+};
+*/
+
+//
+// Structures private to 16B handles allocation
+//
+
+// NUM_OF_COOKIES MUST be a power of 2
+#define NUM_OF_COOKIES 4096
+
+ULONG NextCookie = 1;
+
+typedef struct _A16B_COOKIE {
+ ULONG value32;
+ ULONG cookie;
+} A16B_COOKIE, *P16B_COOKIE;
+
+A16B_COOKIE Cookies[NUM_OF_COOKIES];
+
+NTSTATUS ldrCreateR2XferSeg();
+
+extern PSZ Os2ServerSystemDirectory;
+
+BOOLEAN ldrInit()
+{
+ ULONG size;
+ CHAR SystemDir[260 + FILE_PREFIX_LENGTH];
+#if DBG
+ ldrmte_t *pmte;
+#endif
+ ULONG SizeOfSystemDir;
+ ULONG ModSize;
+ PCHAR DotDll = ".DLL";
+
+ strcpy(SystemDir, "\\OS2SS\\DRIVES\\");
+ SizeOfSystemDir = FILE_PREFIX_LENGTH;
+ size = strlen(Os2ServerSystemDirectory);
+ if( size > (sizeof(SystemDir) - FILE_PREFIX_LENGTH - 10))
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - system directory too long %ld\n", size);
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ strncpy(&SystemDir[SizeOfSystemDir],
+ Os2ServerSystemDirectory,
+ size);
+ _strupr(&SystemDir[SizeOfSystemDir]);
+ SizeOfSystemDir += size;
+ strcpy(&SystemDir[SizeOfSystemDir], "\\OS2\\DLL\\");
+ SizeOfSystemDir += 9;
+
+/*
+ Ol2Heap = RtlCreateHeap( HEAP_GROWABLE,
+ NULL,
+ 64 * 1024, // Initial size of heap is 64K
+ 64 * 1024, // Commit for 64K
+ NULL,
+ 0
+ );
+ if( Ol2Heap == NULL )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - cannot create Ol2Heap\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+*/
+ LDRNEHeap = RtlCreateHeap( HEAP_GROWABLE,
+ NULL,
+ 64 * 1024, // Initial size of heap is 64K
+ 64 * 1024, // Commit for 64K
+ NULL,
+ 0
+ );
+ if ( LDRNEHeap == NULL )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - cannot create LDRNEHeap\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+
+ /*
+ * Allocate a heap object of the size of one sector to hold the
+ * header of file into
+ */
+ pheaderbuf = (char *) RtlAllocateHeap( LDRNEHeap, 0, 512 );
+
+ if ( pheaderbuf == NULL )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - cannot create pheaderbuf\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+
+ if (!ldrCreateSelBitmap()) {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - cannot allocate the segment bitmap\n");
+#endif
+ return(FALSE);
+ }
+
+ // Mark the preallocated segments at the top of the tiled area
+ // as used so that they are not allocated by the loader.
+
+ ldrMarkAllocatedSel((_512M - (OD2MAXSEG_MEM - BASE_TILE)) / _64K, TRUE);
+
+ //
+ // Create an address space for the R2XFER segment (which is the second
+ // code segment of DOSCALLS.DLL).
+ // This segment needs to be pre-allocated because modules that contain
+ // ring 2 entry points may be allocated before DOSCALLS.DLL is allocated.
+ //
+ if (!NT_SUCCESS(ldrCreateR2XferSeg())) {
+ return(FALSE);
+ }
+
+ if (!ldrCreateCallGateBitmap()) {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - cannot allocate the call gate bitmap\n");
+#endif
+ return(FALSE);
+ }
+
+ // Mark pre-allocated call gates (which is the area reserved by the
+ // ring transfer code in client\thunk\r2xfer.asm) as used so that they
+ // are not allocated as call gates.
+
+ ldrMarkAllocatedCallGates(0x200/8);
+
+ acscallmte.mte_magic[0] = 'N';
+ acscallmte.mte_magic[1] = 'E';
+ acscallmte.mte_usecnt = 1;
+ acscallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ acscallmte.mte_swapmte = &acscallsmte;
+ acscallmte.mte_modname = (ULONG) &acsrestab;
+ acscallmte.mte_link = NULL;
+ Allocate16BHandle(&acscallmte.mte_handle, (ULONG) &acscallsmte);
+ acscallsmte.smte_restab = (ULONG) &acsrestab;
+ acscallsmte.smte_nrestab = (ULONG) &acsnrestab;
+ acscallsmte.smte_cbnrestab = 10;
+ acscallsmte.smte_enttab = (ULONG) &acsenttab;
+ acscallsmte.smte_objtab = (ULONG) &segtab;
+ acscallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)acscallmte.mte_modname;
+ acscallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(acscallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)acscallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)acscallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)acscallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)acscallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ acscallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+ kbdcallmte.mte_magic[0] = 'N';
+ kbdcallmte.mte_magic[1] = 'E';
+ kbdcallmte.mte_usecnt = 1;
+ kbdcallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ kbdcallmte.mte_swapmte = &kbdcallsmte;
+ kbdcallmte.mte_modname = (ULONG) &kbdrestab;
+ kbdcallmte.mte_link = &acscallmte;
+ Allocate16BHandle(&kbdcallmte.mte_handle, (ULONG) &kbdcallsmte);
+ kbdcallsmte.smte_restab = (ULONG) &kbdrestab;
+ kbdcallsmte.smte_nrestab = (ULONG) &kbdnrestab;
+ kbdcallsmte.smte_cbnrestab = 10;
+ kbdcallsmte.smte_enttab = (ULONG) &kbdenttab;
+ kbdcallsmte.smte_objtab = (ULONG) &segtab;
+ kbdcallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)kbdcallmte.mte_modname;
+ kbdcallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(kbdcallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)kbdcallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)kbdcallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)kbdcallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)kbdcallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ kbdcallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+ maicallmte.mte_magic[0] = 'N';
+ maicallmte.mte_magic[1] = 'E';
+ maicallmte.mte_usecnt = 1;
+ maicallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ maicallmte.mte_swapmte = &maicallsmte;
+ maicallmte.mte_modname = (ULONG) &mairestab;
+ maicallmte.mte_link = &kbdcallmte;
+ Allocate16BHandle(&maicallmte.mte_handle, (ULONG) &maicallsmte);
+ maicallsmte.smte_restab = (ULONG) &mairestab;
+ maicallsmte.smte_nrestab = (ULONG) &mainrestab;
+ maicallsmte.smte_cbnrestab = 10;
+ maicallsmte.smte_enttab = (ULONG) &maienttab;
+ maicallsmte.smte_objtab = (ULONG) &segtab;
+ maicallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)maicallmte.mte_modname;
+ maicallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(maicallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)maicallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)maicallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)maicallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)maicallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ maicallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+ moncallmte.mte_magic[0] = 'N';
+ moncallmte.mte_magic[1] = 'E';
+ moncallmte.mte_usecnt = 1;
+ moncallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ moncallmte.mte_swapmte = &moncallsmte;
+ moncallmte.mte_modname = (ULONG) &monrestab;
+ moncallmte.mte_link = &maicallmte;
+ Allocate16BHandle(&moncallmte.mte_handle, (ULONG) &moncallsmte);
+ moncallsmte.smte_restab = (ULONG) &monrestab;
+ moncallsmte.smte_nrestab = (ULONG) &monnrestab;
+ moncallsmte.smte_cbnrestab = 10;
+ moncallsmte.smte_enttab = (ULONG) &monenttab;
+ moncallsmte.smte_objtab = (ULONG) &segtab;
+ moncallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)moncallmte.mte_modname;
+ moncallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(moncallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)moncallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)moncallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)moncallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)moncallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ moncallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+ moucallmte.mte_magic[0] = 'N';
+ moucallmte.mte_magic[1] = 'E';
+ moucallmte.mte_usecnt = 1;
+ moucallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ moucallmte.mte_swapmte = &moucallsmte;
+ moucallmte.mte_modname = (ULONG) &mourestab;
+ moucallmte.mte_link = &moncallmte;
+ Allocate16BHandle(&moucallmte.mte_handle, (ULONG) &moucallsmte);
+ moucallsmte.smte_restab = (ULONG) &mourestab;
+ moucallsmte.smte_nrestab = (ULONG) &mounrestab;
+ moucallsmte.smte_cbnrestab = 10;
+ moucallsmte.smte_enttab = (ULONG) &mouenttab;
+ moucallsmte.smte_objtab = (ULONG) &segtab;
+ moucallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)moucallmte.mte_modname;
+ moucallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(moucallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)moucallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)moucallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)moucallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)moucallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ moucallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+ msgcallmte.mte_magic[0] = 'N';
+ msgcallmte.mte_magic[1] = 'E';
+ msgcallmte.mte_usecnt = 1;
+ msgcallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ msgcallmte.mte_swapmte = &msgcallsmte;
+ msgcallmte.mte_modname = (ULONG) &msgrestab;
+ msgcallmte.mte_link = &moucallmte;
+ Allocate16BHandle(&msgcallmte.mte_handle, (ULONG) &msgcallsmte);
+ msgcallsmte.smte_restab = (ULONG) &msgrestab;
+ msgcallsmte.smte_nrestab = (ULONG) &msgnrestab;
+ msgcallsmte.smte_cbnrestab = 10;
+ msgcallsmte.smte_enttab = (ULONG) &msgenttab;
+ msgcallsmte.smte_objtab = (ULONG) &segtab;
+ msgcallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)msgcallmte.mte_modname;
+ msgcallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(msgcallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)msgcallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)msgcallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)msgcallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)msgcallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ msgcallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+ namcallmte.mte_magic[0] = 'N';
+ namcallmte.mte_magic[1] = 'E';
+ namcallmte.mte_usecnt = 1;
+ namcallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ namcallmte.mte_swapmte = &namcallsmte;
+ namcallmte.mte_modname = (ULONG) &namrestab;
+ namcallmte.mte_link = &msgcallmte;
+ Allocate16BHandle(&namcallmte.mte_handle, (ULONG) &namcallsmte);
+ namcallsmte.smte_restab = (ULONG) &namrestab;
+ namcallsmte.smte_nrestab = (ULONG) &namnrestab;
+ namcallsmte.smte_cbnrestab = 10;
+ namcallsmte.smte_enttab = (ULONG) &namenttab;
+ namcallsmte.smte_objtab = (ULONG) &segtab;
+ namcallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)namcallmte.mte_modname;
+ namcallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(namcallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)namcallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)namcallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)namcallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)namcallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ namcallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+ apicallmte.mte_magic[0] = 'N';
+ apicallmte.mte_magic[1] = 'E';
+ apicallmte.mte_usecnt = 1;
+ apicallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ apicallmte.mte_swapmte = &apicallsmte;
+ apicallmte.mte_modname = (ULONG) &apirestab;
+ apicallmte.mte_link = &namcallmte;
+ Allocate16BHandle(&apicallmte.mte_handle, (ULONG) &apicallsmte);
+ apicallsmte.smte_restab = (ULONG) &apirestab;
+ apicallsmte.smte_nrestab = (ULONG) &apinrestab;
+ apicallsmte.smte_cbnrestab = 10;
+ apicallsmte.smte_enttab = (ULONG) &apienttab;
+ apicallsmte.smte_objtab = (ULONG) &segtab;
+ apicallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)apicallmte.mte_modname;
+ apicallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(apicallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)apicallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)apicallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)apicallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)apicallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ apicallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+ oemcallmte.mte_magic[0] = 'N';
+ oemcallmte.mte_magic[1] = 'E';
+ oemcallmte.mte_usecnt = 1;
+ oemcallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ oemcallmte.mte_swapmte = &oemcallsmte;
+ oemcallmte.mte_modname = (ULONG) &oemrestab;
+ oemcallmte.mte_link = &apicallmte;
+ Allocate16BHandle(&oemcallmte.mte_handle, (ULONG) &oemcallsmte);
+ oemcallsmte.smte_restab = (ULONG) &oemrestab;
+ oemcallsmte.smte_nrestab = (ULONG) &oemnrestab;
+ oemcallsmte.smte_cbnrestab = 10;
+ oemcallsmte.smte_enttab = (ULONG) &oementtab;
+ oemcallsmte.smte_objtab = (ULONG) &segtab;
+ oemcallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)oemcallmte.mte_modname;
+ oemcallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(oemcallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)oemcallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)oemcallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)oemcallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)oemcallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ oemcallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+ nlscallmte.mte_magic[0] = 'N';
+ nlscallmte.mte_magic[1] = 'E';
+ nlscallmte.mte_usecnt = 1;
+ nlscallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ nlscallmte.mte_swapmte = &nlscallsmte;
+ nlscallmte.mte_modname = (ULONG) &nlsrestab;
+ nlscallmte.mte_link = &oemcallmte;
+ Allocate16BHandle(&nlscallmte.mte_handle, (ULONG) &nlscallsmte);
+ nlscallsmte.smte_restab = (ULONG) &nlsrestab;
+ nlscallsmte.smte_nrestab = (ULONG) &nlsnrestab;
+ nlscallsmte.smte_cbnrestab = 10;
+ nlscallsmte.smte_enttab = (ULONG) &nlsenttab;
+ nlscallsmte.smte_objtab = (ULONG) &segtab;
+ nlscallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)nlscallmte.mte_modname;
+ nlscallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(nlscallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)nlscallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)nlscallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)nlscallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)nlscallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ nlscallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+#ifndef PMNT
+ pmscallmte.mte_magic[0] = 'N';
+ pmscallmte.mte_magic[1] = 'E';
+ pmscallmte.mte_usecnt = 1;
+ pmscallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ pmscallmte.mte_swapmte = &pmscallsmte;
+ pmscallmte.mte_modname = (ULONG) &pmsrestab;
+ pmscallmte.mte_link = &nlscallmte;
+ Allocate16BHandle(&pmscallmte.mte_handle, (ULONG) &pmscallsmte);
+ pmscallsmte.smte_restab = (ULONG) &pmsrestab;
+ pmscallsmte.smte_nrestab = (ULONG) &pmsnrestab;
+ pmscallsmte.smte_cbnrestab = 10;
+ pmscallsmte.smte_enttab = (ULONG) &pmsenttab;
+ pmscallsmte.smte_objtab = (ULONG) &segtab;
+ pmscallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)pmscallmte.mte_modname;
+ pmscallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(pmscallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)pmscallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)pmscallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)pmscallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)pmscallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ pmscallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+ pmwcallmte.mte_magic[0] = 'N';
+ pmwcallmte.mte_magic[1] = 'E';
+ pmwcallmte.mte_usecnt = 1;
+ pmwcallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ pmwcallmte.mte_swapmte = &pmwcallsmte;
+ pmwcallmte.mte_modname = (ULONG) &pmwrestab;
+ pmwcallmte.mte_link = &pmscallmte;
+ Allocate16BHandle(&pmwcallmte.mte_handle, (ULONG) &pmwcallsmte);
+ pmwcallsmte.smte_restab = (ULONG) &pmwrestab;
+ pmwcallsmte.smte_nrestab = (ULONG) &pmwnrestab;
+ pmwcallsmte.smte_cbnrestab = 10;
+ pmwcallsmte.smte_enttab = (ULONG) &pmwenttab;
+ pmwcallsmte.smte_objtab = (ULONG) &segtab;
+ pmwcallsmte.smte_objcnt = 1;
+ ModSize = *(PCHAR)pmwcallmte.mte_modname;
+ pmwcallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(pmwcallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)pmwcallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)pmwcallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)pmwcallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)pmwcallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ pmwcallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+ os2smcallmte.mte_magic[0] = 'N';
+ os2smcallmte.mte_magic[1] = 'E';
+ os2smcallmte.mte_usecnt = 1;
+ os2smcallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ os2smcallmte.mte_swapmte = &os2smcallsmte;
+ os2smcallmte.mte_modname = (ULONG) &os2restab;
+ os2smcallmte.mte_link = &pmwcallmte;
+ Allocate16BHandle(&os2smcallmte.mte_handle, (ULONG) &os2smcallsmte);
+ os2smcallsmte.smte_restab = (ULONG) &os2restab;
+ os2smcallsmte.smte_nrestab = (ULONG) &os2nrestab;
+ os2smcallsmte.smte_cbnrestab = 10;
+ os2smcallsmte.smte_enttab = (ULONG) &os2enttab;
+ os2smcallsmte.smte_objtab = (ULONG) &segtab;
+ os2smcallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)os2smcallmte.mte_modname;
+ os2smcallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(os2smcallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)os2smcallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)os2smcallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)os2smcallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)os2smcallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ os2smcallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+#endif /* ifndef PMNT */
+
+ quecallmte.mte_magic[0] = 'N';
+ quecallmte.mte_magic[1] = 'E';
+ quecallmte.mte_usecnt = 1;
+ quecallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ quecallmte.mte_swapmte = &quecallsmte;
+ quecallmte.mte_modname = (ULONG) &querestab;
+#ifndef PMNT
+ quecallmte.mte_link = &os2smcallmte;
+#else
+ quecallmte.mte_link = &nlscallmte;
+#endif
+ Allocate16BHandle(&quecallmte.mte_handle, (ULONG) &quecallsmte);
+ quecallsmte.smte_restab = (ULONG) &querestab;
+ quecallsmte.smte_nrestab = (ULONG) &quenrestab;
+ quecallsmte.smte_cbnrestab = 10;
+ quecallsmte.smte_enttab = (ULONG) &queenttab;
+ quecallsmte.smte_objtab = (ULONG) &segtab;
+ quecallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)quecallmte.mte_modname;
+ quecallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(quecallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)quecallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)quecallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)quecallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)quecallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ quecallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+ sescallmte.mte_magic[0] = 'N';
+ sescallmte.mte_magic[1] = 'E';
+ sescallmte.mte_usecnt = 1;
+ sescallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ sescallmte.mte_swapmte = &sescallsmte;
+ sescallmte.mte_modname = (ULONG) &sesrestab;
+ sescallmte.mte_link = &quecallmte;
+ Allocate16BHandle(&sescallmte.mte_handle, (ULONG) &sescallsmte);
+ sescallsmte.smte_restab = (ULONG) &sesrestab;
+ sescallsmte.smte_nrestab = (ULONG) &sesnrestab;
+ sescallsmte.smte_cbnrestab = 10;
+ sescallsmte.smte_enttab = (ULONG) &sesenttab;
+ sescallsmte.smte_objtab = (ULONG) &segtab;
+ sescallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)sescallmte.mte_modname;
+ sescallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(sescallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)sescallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)sescallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)sescallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)sescallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ sescallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+#ifdef PMNT
+ pmntcallmte.mte_magic[0] = 'N';
+ pmntcallmte.mte_magic[1] = 'E';
+ pmntcallmte.mte_usecnt = 1;
+ pmntcallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ pmntcallmte.mte_swapmte = &pmntcallsmte;
+ pmntcallmte.mte_modname = (ULONG) &pmnrestab;
+ pmntcallmte.mte_link = &sescallmte;
+ Allocate16BHandle(&pmntcallmte.mte_handle, (ULONG) &pmntcallsmte);
+ pmntcallsmte.smte_restab = (ULONG) &pmnrestab;
+ pmntcallsmte.smte_nrestab = (ULONG) &pmnnrestab;
+ pmntcallsmte.smte_cbnrestab = 10;
+ pmntcallsmte.smte_enttab = (ULONG) &pmnenttab;
+ pmntcallsmte.smte_objtab = (ULONG) &segtab;
+ pmntcallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)pmntcallmte.mte_modname;
+ pmntcallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(pmntcallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)pmntcallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)pmntcallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)pmntcallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)pmntcallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ pmntcallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+#endif
+
+ viocallmte.mte_magic[0] = 'N';
+ viocallmte.mte_magic[1] = 'E';
+ viocallmte.mte_usecnt = 1;
+ viocallmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ viocallmte.mte_swapmte = &viocallsmte;
+ viocallmte.mte_modname = (ULONG) &viorestab;
+#ifdef PMNT
+ viocallmte.mte_link = &pmntcallmte;
+#else
+ viocallmte.mte_link = &sescallmte;
+#endif
+ viocallsmte.smte_path = (ULONG) &viorestab;
+ viocallsmte.smte_pathlen = (USHORT) 9;
+ Allocate16BHandle(&viocallmte.mte_handle, (ULONG) &viocallsmte);
+ viocallsmte.smte_restab = (ULONG) &viorestab;
+ viocallsmte.smte_nrestab = (ULONG) &vionrestab;
+ viocallsmte.smte_cbnrestab = 15;
+ viocallsmte.smte_enttab = (ULONG) &vioenttab;
+ viocallsmte.smte_objtab = (ULONG) &segtab;
+ viocallsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)viocallmte.mte_modname;
+ viocallsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(viocallsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)viocallsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)viocallsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)viocallmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)viocallsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ viocallsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+#ifdef DBCS
+// MSKK Dec.15.1992 V-AkihiS
+ imdaemonmte.mte_magic[0] = 'N';
+ imdaemonmte.mte_magic[1] = 'E';
+ imdaemonmte.mte_usecnt = 1;
+ imdaemonmte.mte_mflags = CLASS_GLOBAL | LIBRARYMOD | GINIDONE | DOSMOD | MTEPROCESSED;
+ imdaemonmte.mte_swapmte = &imdaemonsmte;
+ imdaemonmte.mte_modname = (ULONG) &imdrestab;
+ imdaemonmte.mte_link = &viocallmte;
+ Allocate16BHandle(&imdaemonmte.mte_handle, (ULONG) &imdaemonsmte);
+ imdaemonsmte.smte_restab = (ULONG) &imdrestab;
+ imdaemonsmte.smte_nrestab = (ULONG) &imdnrestab;
+ imdaemonsmte.smte_cbnrestab = 10;
+ imdaemonsmte.smte_enttab = (ULONG) &imdenttab;
+ imdaemonsmte.smte_objtab = (ULONG) &segtab;
+ imdaemonsmte.smte_objcnt = 1;
+
+ ModSize = *(PCHAR)imdaemonmte.mte_modname;
+ imdaemonsmte.smte_path =
+ (ULONG)RtlAllocateHeap(LDRNEHeap, 0, SizeOfSystemDir + ModSize + 5);
+ if ( !(imdaemonsmte.smte_path) )
+ {
+#if DBG
+ DbgPrint("OS2LDR: ldrinit - out of heap memory\n");
+ ASSERT( FALSE );
+#endif
+ return(FALSE);
+ }
+ memcpy((PVOID)imdaemonsmte.smte_path, SystemDir, SizeOfSystemDir);
+ memcpy((PCHAR)imdaemonsmte.smte_path + SizeOfSystemDir,
+ (PCHAR)imdaemonmte.mte_modname + 1, ModSize);
+ strcpy((PCHAR)imdaemonsmte.smte_path + SizeOfSystemDir + ModSize, DotDll);
+ imdaemonsmte.smte_pathlen = (USHORT)(SizeOfSystemDir + ModSize + 4);
+
+ mte_h = global_h = (ldrmte_t *)&imdaemonmte;
+#else
+ mte_h = global_h = (ldrmte_t *)&viocallmte;
+#endif
+ global_l = (ldrmte_t *)&acscallmte;
+
+#if 0
+ //
+ // Preload the DOSCALLS dll (not implemented yet)
+ //
+
+ //
+ // Init the Library Intialization routines data structure to NULL
+ // in order to detect bugs
+ //
+ pldrLibiRecord = NULL;
+ pldrLibiCounter = NULL;
+
+ /*
+ * Point to ldrLibPathBuf to contain the environment string
+ */
+ strcpy(ldrLibPathBuf, SystemDir);
+
+ rc = ldrGetModule("DOSCALLS",
+ 8,
+ (char)EXT_LIBRARY,
+ CLASS_GLOBAL,
+ &pmte,
+ 0);
+ if (rc != NO_ERROR) {
+ return(FALSE);
+ }
+ pmte->mte_usecnt = 1;
+#endif
+
+#if DBG
+ IF_OL2_DEBUG ( MTE ) {
+ DbgPrint("OS2LDR: List of LDR dlls:\n");
+ for (pmte = mte_h; pmte != NULL; pmte = pmte->mte_link) {
+ DbgPrint("%s, NameLen=%d, %s\n",
+ pmte->mte_swapmte->smte_path,
+ pmte->mte_swapmte->smte_pathlen,
+ (PCHAR)pmte->mte_modname + 1);
+ }
+ }
+#endif
+ return(TRUE);
+}
+
+
+//
+// Service routines to create and translate mapping between
+// 32b Cruiser Handles and random 16b handles (not to confuse
+// with OS2 1.X File Handles and Thread Handles which are
+// not random)
+//
+
+APIRET
+Allocate16BHandle(
+ OUT PUSHORT pusHandle,
+ IN ULONG h32bHandle
+ )
+{
+ ULONG Entry;
+ ULONG LoopCounter = 0;
+
+ //
+ // Find a free entry in the cookie table
+ //
+ Entry = NextCookie & (NUM_OF_COOKIES - 1);
+ while (Cookies[Entry].cookie != 0) {
+ //
+ // Verify that we are not looping forever
+ //
+ LoopCounter++;
+ if (LoopCounter == NUM_OF_COOKIES) {
+ return(ERROR_NO_OBJECT);
+ }
+ NextCookie++;
+ if (NextCookie == _64K) {
+ NextCookie = 1;
+ }
+ Entry = NextCookie & (NUM_OF_COOKIES - 1);
+ }
+
+ Cookies[Entry].value32 = h32bHandle;
+ Cookies[Entry].cookie = NextCookie;
+ *pusHandle = (USHORT)NextCookie;
+ NextCookie++;
+ if (NextCookie == _64K) {
+ NextCookie = 1;
+ }
+ return(NO_ERROR);
+}
+
+APIRET
+Free16BHandle(
+ IN USHORT usHandle
+ )
+{
+ ULONG Entry;
+
+ //
+ // Find a free entry in the cookie table
+ //
+ Entry = usHandle & (NUM_OF_COOKIES - 1);
+ if (Cookies[Entry].cookie != (ULONG)usHandle) {
+ return(ERROR_INVALID_HANDLE);
+ }
+ Cookies[Entry].cookie = 0;
+ return(NO_ERROR);
+}
+
+NTSTATUS
+ldrCreateR2XferSeg()
+{
+ NTSTATUS Status;
+ LARGE_INTEGER SectionSize;
+ ULONG RegionSize = _64K;
+ PVOID BaseAddress;
+
+ SectionSize.LowPart = _64K;
+ SectionSize.HighPart = 0;
+ Status = NtCreateSection( &R2XferSegHandle,
+ SECTION_ALL_ACCESS,
+ NULL,
+ &SectionSize,
+ PAGE_EXECUTE_READWRITE,
+ SEC_COMMIT,
+ NULL
+ );
+
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2LDR: unable to create the R2XFER section, Status=%x\n", Status));
+#endif
+ return( Status );
+ }
+
+ BaseAddress = (PVOID)R2XFER_BASE;
+ Status = NtMapViewOfSection( R2XferSegHandle,
+ NtCurrentProcess(),
+ &BaseAddress,
+ 0,
+ 0,
+ NULL,
+ &RegionSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE
+ );
+
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2LDR: unable to Map View the R@XFER section, Status=%x\n", Status));
+#endif
+ return( Status );
+ }
+
+ return( Status );
+}
+
+
+
diff --git a/private/os2/ldr/ldrmte.c b/private/os2/ldr/ldrmte.c
new file mode 100644
index 000000000..e78cbeba1
--- /dev/null
+++ b/private/os2/ldr/ldrmte.c
@@ -0,0 +1,4290 @@
+
+#include "ldrextrn.h"
+#include "ldrdbg.h"
+#ifdef PMNT
+#define INCL_32BIT
+#include "pmnt.h"
+PID PMNTPMShellPid = 0;
+#endif
+
+/***EP LDRNewExe - load a new .EXE file format program.
+ *
+ * This routine is called by the w_execpgm function to
+ * load a program module and it's referenced library
+ * modules.
+ *
+ * This procedure performs the following steps:
+ *
+ * - Compute module name string length and validate it.
+ * - Load the program module and referenced library modules.
+ * - Copy startup information into the exec_info structure.
+ *
+ * ENTRY pachModname - pointer to ASCII module name
+ * pexec_info - pointer to return buffer
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ * pexec_info structure set
+ */
+
+BOOLEAN
+LDRNewExe(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ P_LDRNEWEXE_MSG a = &m->u.LdrNewExe;
+ ldrmte_t *pmte; /* Pointer to loaded mte */
+ ldrmte_t *pmteToChange;
+ ldrste_t *psteToChange;
+ USHORT Offset;
+ PVOID FlatEntryPoint;
+ UCHAR c = (UCHAR)0xCC;
+ USHORT cb;
+ int rc;
+ NTSTATUS Status;
+ ULONG NEFlags;
+#if PMNT
+ BOOLEAN SavedErrInfo=FALSE;
+#endif
+
+ ldrNewExeInit(t,a,&cb);
+ /*
+ * Load the program module and referenced library modules.
+ */
+ rc = ldrGetModule(a->ProcessName.Buffer,
+ cb,
+ (char)EXT_PROGRAM,
+ (ushort_t) CLASS_PROGRAM,
+ &pmte,
+ &a->BoundApp,
+ &NEFlags);
+#if PMNT
+ if ((rc == ERROR_INVALID_ORDINAL || rc == ERROR_PROC_NOT_FOUND) &&
+ !(CurrentThread->Process->Flags & OS2_PROCESS_WINDOWAPI) &&
+ ldrTgtModNameBufL == 8 && ! strncmp(ldrTgtModNameBuf,"VIOCALLS",8)
+ ) {
+ SavedErrInfo = ldrSaveErrInfo(rc);
+ CurrentThread->Process->Flags |= OS2_PROCESS_FORCEDPM;
+ //
+ // Maybe a PM application with WINDOWAPI flags off; try forced PM
+ //
+ ldrUnloadTagedModules(t->Process);
+
+ ldrNewExeInit(t,a,&cb);
+
+ /*
+ * Load the program module and referenced library modules.
+ */
+ rc = ldrGetModule(a->ProcessName.Buffer,
+ cb,
+ (char)EXT_PROGRAM,
+ (ushort_t) CLASS_PROGRAM,
+ &pmte,
+ &a->BoundApp,
+ &NEFlags);
+ if ((rc != NO_ERROR || ! (CurrentThread->Process->Flags & OS2_PROCESS_PMMSGQUE))
+ && SavedErrInfo) {
+ ldrRestoreErrInfo(&rc);
+ }
+
+ }
+ else if (rc == ERROR_2ND_PMSHELL) {
+ ldrUnloadTagedModules(t->Process);
+ m->ReturnedErrorValue = ERROR_2ND_PMSHELL;
+ return(TRUE);
+ }
+#endif // if PMNT
+
+ if (rc != NO_ERROR) {
+ ldrWriteErrTxt(rc);
+#if PMNT
+ if (SavedErrInfo) {
+ ldrFreeErrInfo();
+ }
+#endif
+ ldrUnloadTagedModules(t->Process);
+ m->ReturnedErrorValue = rc;
+ return(TRUE);
+ }
+
+#if PMNT
+ if (SavedErrInfo) {
+ ldrFreeErrInfo();
+ }
+#endif
+ if (CurrentThread->Process->Flags & OS2_PROCESS_TRACE) {
+ /*
+ * Replace the initial instruction of the first init
+ * routine with int 3. This will be replaced back by
+ * Os2DebugEventHandle at init time.
+ */
+
+ if (*pldrLibiCounter > 0) {
+ /*
+ * There is an init routine
+ */
+
+ pmteToChange = ldrFindMTEForHandle(pldrLibiRecord[0].handle);
+ }
+ else {
+ pmteToChange = ldrFindMTEForHandle(((LinkMTE *)CurrentThread->Process->LinkMte)->NextMTE->MTE);
+ }
+
+ CurrentThread->Process->FirstMTE = pmteToChange;
+ psteToChange = ldrNumToSte(pmteToChange, pmteToChange->mte_swapmte->smte_startobj);
+ Offset = (USHORT)pmteToChange->mte_swapmte->smte_eip;
+ FlatEntryPoint = (PVOID)((ULONG)(SELTOFLAT(psteToChange->ste_selector |7)) | (ULONG)(Offset));
+ Status = NtWriteVirtualMemory( CurrentThread->Process->ProcessHandle,
+ (PVOID) FlatEntryPoint,
+ (PVOID) &(c),
+ 1,
+ NULL
+ );
+#if DBG
+ if (!(NT_SUCCESS(Status))) {
+ KdPrint(( "LDRNewExe: PTrace support failed to write entry. Status %lx\n", Status));
+ }
+#endif
+ }
+
+ //
+ // Update app type in process structure
+ //
+ pmte->mte_mflags2 = NEFlags;
+
+ //
+ // set/force bound-app flag
+ //
+ if (a->BoundApp) {
+ pmte->mte_mflags2 |= NEBOUND;
+ }
+
+#if PMNT
+ a->PMProcess = 0;
+
+ if (CurrentThread->Process->Flags & OS2_PROCESS_IS_PMSHELL)
+ {
+ pmte->mte_mflags2 |= NEPMSHELL;
+ a->PMProcess |= APPTYPE_PMSHELL;
+ }
+
+ if (CurrentThread->Process->Flags & OS2_PROCESS_PMMSGQUE)
+ {
+ pmte->mte_mflags2 |= NEPMMSGQUE;
+ }
+
+ if (Os2srvProcessIsPMProcess(CurrentThread->Process))
+ {
+ a->PMProcess |= APPTYPE_PM;
+ }
+
+ if ((CurrentThread->Process->Parent != NULL) &&
+ (CurrentThread->Process->Parent->ProcessId != 0) &&
+ (CurrentThread->Process->Parent->ProcessId == PMNTPMShellPid))
+ {
+ a->PMProcess |= APPTYPE_PMSHELL_CHILD;
+ }
+
+ if (a->PMProcess && !PMNTPMShellPid) {
+ ldrUnloadTagedModules(t->Process);
+ m->ReturnedErrorValue = ERROR_PMSHELL_NOT_UP;
+ return(TRUE);
+ }
+#endif // PMNT
+
+ /*
+ * get program module startup parameters
+ */
+ rc = ldrGetModParams(pmte, (ldrrei_t *)&a->ExecInfo);
+ if (rc != NO_ERROR) {
+ ldrWriteErrTxt(rc);
+ ldrUnloadTagedModules(t->Process);
+ m->ReturnedErrorValue = rc;
+ return(TRUE);
+ }
+
+ //
+ // Save the handle of the CLASS_PROGRAM mte in the process
+ // data structure
+ //
+ t->Process->ProcessMTE = (PVOID)pmte;
+
+ a->DoscallsSel = LDRDoscallsSel;
+ m->ReturnedErrorValue = NO_ERROR;
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: LDRNewExe is returning to the client, rc = %d\n", rc);
+ }
+#endif
+ //
+ // Increment the usecnt of the referenced modules
+ //
+ pmte = mte_h;
+ while (pmte != NULL) {
+ if ((pmte->mte_mflags & INGRAPH) != 0) {
+ pmte->mte_usecnt++;
+ }
+ pmte = pmte->mte_link;
+ }
+
+#if DBG
+ IF_OL2_DEBUG ( MTE ) {
+ DbgPrint("\nDumping segments after LDRNewExe() processing\n");
+ ldrDisplaySegmentTable();
+ }
+#endif
+
+#if PMNT && DBG
+ LDRDumpSegments((POS2_THREAD)NULL,
+ (POS2_API_MSG)NULL);
+#endif
+
+ m->ReturnedErrorValue = NO_ERROR;
+ return(TRUE);
+}
+
+
+VOID
+ldrNewExeInit(
+ IN POS2_THREAD t,
+ IN P_LDRNEWEXE_MSG a,
+ OUT PUSHORT cb
+ )
+{
+ //
+ // Set the global variable CurrentThread to the value of
+ // the current running Thread. This is used by other routines
+ // in the loader to find relevant information regarding the
+ // OS/2 process that issued the call.
+ //
+ CurrentThread = t;
+
+ //
+ // Set the fForceUnmap flag to TRUE so that ldrUnloadTagedModules()
+ // does unmap the app's freed segments from the app's address space.
+ //
+ fForceUnmap = TRUE;
+
+ //
+ // Invalidate the error message buffers
+ //
+ ldrInvSrcErrTxt();
+ ldrInvTgtErrTxt();
+
+ //
+ // Update once the Ol2EntryFlat variable which points to
+ // the client's entry flat address
+ //
+ Ol2EntryFlat = a->EntryFlatAddr;
+
+ //
+ // Init the Library Intialization routines data structure
+ //
+ pldrLibiRecord = (ldrlibi_t *)a->InitRecords.Buffer;
+ pldrLibiCounter = &a->NumOfInitRecords;
+ *pldrLibiCounter = 0;
+
+ //
+ // init the pointer to the error string
+ //
+ pErrText = &a->FailName;
+
+ ldrClearAllMteFlag(INGRAPH | USED);
+
+ /*
+ * Point to ldrLibPathBuf to contain the environment string
+ */
+ strncpy(ldrLibPathBuf, a->LibPathName.Buffer, SizeOfldrLibPathBuf);
+ ldrLibPathBuf[SizeOfldrLibPathBuf - 1] = '\0';
+
+ _strupr(ldrpLibPath);
+
+ *cb = (USHORT)a->ProcessName.Length;
+
+}
+
+UCHAR
+ldrGetEntryPoint(
+ IN POS2_PROCESS Process
+ )
+{
+ ldrsmte_t *psmte;
+ ldrste_t *pste;
+ USHORT offset;
+ PVOID FlatEntryPoint;
+ NTSTATUS Status;
+ UCHAR c;
+ ldrmte_t *pMte;
+
+ if (((LinkMTE *)Process->LinkMte)->NextMTE == NULL) {
+ return(0);
+ }
+
+ pMte = Process->FirstMTE;
+ psmte = pMte->mte_swapmte;
+ pste = ldrNumToSte(pMte, psmte->smte_startobj);
+ offset = (USHORT) psmte->smte_eip;
+ FlatEntryPoint = (PVOID)((ULONG)(SELTOFLAT(pste->ste_selector | 7)) | (ULONG)(offset));
+ Status = NtReadVirtualMemory(Process->ProcessHandle,
+ FlatEntryPoint,
+ (PVOID) &(c),
+ 1,
+ NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ KdPrint(( "ldrGetEntryPoint failed to read entry. Status %lx\n", Status));
+#endif
+
+ return(0);
+ }
+
+ return(c);
+}
+
+VOID
+ldrRestoreEntryPoint(
+ IN POS2_PROCESS Process
+ )
+{
+ //
+ // A process being traced just started, replace the int 3 with the real
+ // code
+ //
+ PVOID FlatEntryPoint;
+ UCHAR c;
+ NTSTATUS Status;
+ ldrste_t *pste;
+ USHORT offset;
+ ldrsmte_t *psmte;
+ ldrmte_t *pMte;
+
+ if (((LinkMTE *)Process->LinkMte)->NextMTE == NULL) {
+ return;
+ }
+
+ pMte = Process->FirstMTE;
+ psmte = pMte->mte_swapmte;
+ pste = ldrNumToSte(pMte, psmte->smte_startobj);
+ offset = (USHORT) psmte->smte_eip;
+ FlatEntryPoint = (PVOID)((ULONG)(SELTOFLAT(pste->ste_selector | 7)) | (ULONG)(offset));
+ //
+ // get the original value from os2srv address space, and stick it into
+ // the debuggee process
+ //
+ c = *(PUCHAR)(FlatEntryPoint);
+ Status = NtWriteVirtualMemory(Process->ProcessHandle,
+ FlatEntryPoint,
+ (PVOID) &(c),
+ 1,
+ NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ KdPrint(( "ldrRestoreEntryPoint failed to write entry. Status %lx\n", Status));
+#endif
+
+ }
+
+}
+
+
+
+/***LP ldrGetModule - Get module handle, load if required
+ *
+ * Get the module table entry handle for this module. If the
+ * module is not already loaded, call ldrLoadModule to load it.
+ *
+ * This procedure performs the following steps:
+ *
+ * - Allocate loader variables on the stack and initialize.
+ * - Get the desired module table entry handle.
+ * - Scan the mte list loading objects for modules that
+ * are not loaded.
+ * - Load the module
+ * - Release loader variables on the stack.
+ *
+ * ENTRY pachModname - pointer to module name
+ * cb - length of module name
+ * chLdrtype - load type being requested
+ * (program,library)
+ * class - module class
+ * (PROGRAM, GLOBAL or SPECIFIC)
+ * ppmte - a pointer to a mte pointer which
+ * was loaded
+ * pBound - optional pointer to a flag set if BOUND exe
+ *
+ * pNEFlags - Flags word of the NE header
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ *
+ * COMMENT:
+ * ldrGetModule is called from LDRNewExe, LDRLoadVdd and w_loadmodule.
+ */
+
+APIRET ldrGetModule(pachModname, cb, chLdrtype, class, ppmte, pBound, pNEFlags)
+PUCHAR pachModname; /* pointer to ASCII module name */
+USHORT cb; /* length of mod name */
+char chLdrtype; /* type of module to load */
+USHORT class; /* module class */
+ldrmte_t **ppmte; /* place to return pointer to mte */
+PBOOLEAN pBound; /* optional pointer to a flag set if BOUND exe */
+PULONG pNEFlags; /* optional pointer to Flags word of the NE header */
+{
+ register ldrmte_t *pmte; /* pointer to mte */
+ ldrlv_t lv; /* define local variables */
+ ldrlv_t *plv = &lv;
+ int rc;
+ LinkMTE *mteInLinkList;
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: ldrGetModule() was called with modname=%.*s, ", cb, pachModname);
+ if (chLdrtype == EXT_PROGRAM) {
+ DbgPrint("Type=PROGRAM\n");
+ }
+ else {
+ DbgPrint("Type=LIBRARY\n");
+ }
+ }
+#endif
+
+ if (pBound != 0) {
+ *pBound = FALSE;
+ }
+
+ try {
+ /*
+ * Init local variables
+ */
+ memset((PCHAR) plv, 0, sizeof(ldrlv_t));
+
+ lv.lv_type = chLdrtype;
+ lv.lv_sfn = 0;
+ lv.lv_class = class;
+
+ /*
+ * initialize mte
+ */
+ rc = ldrGetMte(pachModname, cb, chLdrtype, class, &plv->lv_pmte, pBound, pNEFlags);
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+
+ /*
+ * return handle and pointer of loaded mte
+ */
+ pmte = *ppmte = lv.lv_pmte;
+
+ //
+ // Scan linked list of mtes and load or attach to objects.
+ //
+
+ for (pmte = mte_h; pmte != NULL; pmte = pmte->mte_link) {
+ //
+ // If module is not referenced, continue to next module
+ //
+ if ((pmte->mte_mflags & INGRAPH) == 0) {
+ continue;
+ }
+
+ //
+ // Module was referenced. Load it into memory
+ //
+ lv.lv_pmte = pmte; /* save pointer to mte */
+ lv.lv_hobmte = pmte->mte_handle;/* save handle to mte */
+ lv.lv_sfn = pmte->mte_sfn; /* save SFN of this mte */
+ rc = ldrLoadModule(plv); /* load required objects */
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+ if (CurrentThread->Process->Flags & OS2_PROCESS_TRACE) {
+ if ((*(PCHAR)pmte->mte_modname != 8) ||
+ (strncmp((PCHAR)(pmte->mte_modname)+1, "DOSCALLS", 8))) {
+ /*
+ * Add the mte to the process link list of mte.
+ */
+ mteInLinkList = (LinkMTE *) (CurrentThread->Process->LinkMte);
+ mteInLinkList->NeedToTransfer++;
+ while (mteInLinkList->NextMTE != NULL) {
+ mteInLinkList = mteInLinkList->NextMTE;
+ }
+
+ mteInLinkList->NextMTE = RtlAllocateHeap(Os2Heap, 0, sizeof(LinkMTE));
+ if (mteInLinkList->NextMTE) {
+ mteInLinkList->NextMTE->MTE = pmte->mte_handle;
+ mteInLinkList->NextMTE->NextMTE = NULL;
+ mteInLinkList->NextMTE->NeedToTransfer = TRUE;
+ }
+ else {
+#if DBG
+ KdPrint(( "ldrGetModule: Unable to allocate memory for new mte in link list\n"));
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ }
+ }
+ }
+
+ return(NO_ERROR);
+ }
+ except(EXCEPTION_EXECUTE_HANDLER) {
+ return(0xdeadbeef);
+ }
+}
+
+
+/***LP ldrUCaseString - Upper case string
+*/
+void ldrUCaseString(PCHAR pstring, ULONG cb)
+{
+ PUCHAR plocal;
+ ULONG i;
+
+ plocal = (PUCHAR)pstring;
+ for (i = 0; i < cb; i++) {
+#ifdef DBCS
+// MSKK Apr.09.1993 V-AkihiS
+ if (IsDBCSLeadByte(*plocal)) {
+ plocal++;
+ if (i < cb) {
+ i++;
+ plocal++;
+ }
+ } else {
+ *plocal = (CHAR) toupper(*plocal);
+ plocal++;
+ }
+#else
+ *plocal = (CHAR) toupper(*plocal);
+ plocal++;
+#endif
+ }
+
+}
+
+
+/***LP ldrGetMte - Get module handle
+ *
+ * Get the module table entry (mte) handle for this module. If
+ * the module's mte is not in the linked list of mte's, open and
+ * read the file EXE header, verify the header is for a segmented
+ * or linear EXE file format, create an mte for the module and initialize
+ * it. If this is a program module, save the mte handle in the user's
+ * PTDA. If the module's mte is found in the linked list of mte's,
+ * attach to the module if not already attached and allocate non_shared
+ * objects.
+ *
+ * ENTRY pachModname - pointer to module name
+ * cb - length of module name
+ * chLdrtype - load type being requested
+ * (program,library,device)
+ * class - program,global or specific
+ * ppmte - pointer to a pmte if exist else 0
+ * pBound - optional pointer to a flag set if BOUND exe
+ * pNEFlags - Flags word of the NE header
+ *
+ * EXIT none - return successful or call load_error
+ *
+ * EFFECTS - pointer of reqested mte placed in
+ * ppmte
+ *
+ * COMMENT - ldrGetMte is called from ldrGetModule
+ * and ldrLoadModule
+ */
+
+APIRET ldrGetMte(pachModname, cb, chLdrtype, class, ppmte, pBound, pNEFlags)
+PUCHAR pachModname; /* pointer to ASCII module name */
+USHORT cb; /* length of module name */
+UCHAR chLdrtype; /* type of module to load */
+USHORT class; /* class to which module belongs */
+ldrmte_t **ppmte; /* pointer to a mte pointer */
+PBOOLEAN pBound; /* optional pointer to a flag set if BOUND exe */
+PULONG pNEFlags; /* optional pointer to Flags word of the NE header */
+{
+ ldrlv_t lv; /* loader variable */
+ register ldrlv_t *plv = &lv;
+ register ldrmte_t *pmte; /* pointer to mte */
+ struct e32_exe *pe32; /* pointer to link exe format image */
+ ldrmte_t *ptemp;
+ ldrsmte_t *psmte;
+ int rc;
+ int rc1;
+ int ModuleNameSize;
+ PCHAR ModuleNameString;
+ ULONG i;
+ ULONG lindex;
+ PCHAR RefModname;
+ USHORT Refcb;
+ BOOLEAN BoundApp;
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: ldrGetMte() was called with modname=%.*s, ", cb, pachModname);
+ if (chLdrtype == EXT_PROGRAM) {
+ DbgPrint("Type=PROGRAM\n");
+ }
+ else {
+ DbgPrint("Type=LIBRARY\n");
+ }
+ }
+#endif
+
+ if (pBound != 0) {
+ *pBound = FALSE;
+ }
+
+ /*
+ * Init local variables
+ */
+ memset((PCHAR) plv, 0, sizeof(ldrlv_t));
+
+ /*
+ * setup source global error message txt
+ */
+
+ if ((cb > 14) && !strncmp(pachModname, "\\OS2SS\\DRIVES\\", 14)) {
+ ldrSetupSrcErrTxt(pachModname+14, cb-14);
+ }
+ else {
+ ldrSetupSrcErrTxt(pachModname, cb);
+ }
+
+ lv.lv_type = chLdrtype;
+ lv.lv_sfn = 0;
+ lv.lv_class = class;
+
+ if ((*ppmte == NULL) && (lv.lv_type != EXT_DEVICE)) {
+ /*
+ * Upper case module name
+ */
+ ldrUCaseString(pachModname, (ulong_t) cb);
+
+ /*
+ * Do not search for device drivers.
+ * Search to see if the module is already loaded so that
+ * it may be shared. ppmte is set to zero if the module
+ * is not found
+ */
+ ldrFindModule(pachModname, cb, class, ppmte);
+
+ /*
+ * We can not load VDDs twice, so if FindModule found it
+ * return an error.
+ * BUGBUG - This error should be changed to:
+ * ERROR_VDD_ALREADY_LOADED
+ */
+ if (chLdrtype == EXT_VDD && *ppmte != NULL) {
+
+ if (pBound != 0 &&
+ ((*ppmte)->mte_mflags2 & NEBOUND)) {
+
+ *pBound = TRUE;
+ }
+
+ return(ERROR_NOT_SAME_DEVICE);
+ }
+ }
+
+ again:
+ pmte = lv.lv_pmte = *ppmte;
+
+ if (pmte != NULL) {
+
+ if (pBound != 0 &&
+ (pmte->mte_mflags2 & NEBOUND)) {
+
+ *pBound = TRUE;
+ }
+
+ if (class == CLASS_PROGRAM) {
+ //
+ // process with same name is running
+ // initialize the new process Flags (normally done during loading
+ //
+
+ *pNEFlags = pmte->mte_mflags2;
+
+ if ((pmte->mte_mflags2 & NEAPPTYP) == NENOTWINCOMPAT) {
+ CurrentThread->Process->Flags |= OS2_PROCESS_NOTWINDOWCOMPAT;
+ }
+ else if ((pmte->mte_mflags2 & NEAPPTYP) == NEWINCOMPAT) {
+ CurrentThread->Process->Flags |= OS2_PROCESS_WINDOWCOMPAT;
+ }
+ else if ((pmte->mte_mflags2 & NEAPPTYP) == NEWINAPI) {
+ CurrentThread->Process->Flags |= OS2_PROCESS_WINDOWAPI;
+ }
+#if PMNT
+ if (pmte->mte_mflags2 & NEPMSHELL) {
+ return(ERROR_2ND_PMSHELL);
+ }
+ if (pmte->mte_mflags2 & NEPMMSGQUE) {
+ CurrentThread->Process->Flags |= OS2_PROCESS_PMMSGQUE;
+ }
+#endif //if PMNT
+ }
+
+ if ((pmte->mte_mflags & INGRAPH) != 0) {
+ return(NO_ERROR);
+ }
+ ldrChkLoadType(pmte->mte_mflags, plv);
+
+// ldrInvTgtErrTxt();
+#if 0
+ /*
+ * Don't load modules that are attached already.
+ */
+ if (ldrIsAttached(pmte)) {
+ return;
+ }
+ else {
+ /*
+ * setup existing SFN to load non-shared objects
+ */
+ lv.lv_sfn = pmte->mte_sfn;
+ /*
+ * Indicate that shared objects should not have the page tables
+ * scanned. We will use the USED bit to indicate this
+ */
+ pmte->mte_mflags |= USED;
+ }
+#endif
+ }
+ else {
+ /*
+ * We come here after ldrFindModule has failed to find this module
+ * in the class specified. We can have the following situation:
+ *
+ * a, We are trying to load a CLASS_SPECIFIC module. In this case
+ * we need to check if this module is loaded as a CLASS_GLOBAL
+ * module. If it is we use that MTE. The MTE is maintained as
+ * CLASS_GLOBAL.
+ *
+ * b, We are trying to load a CLASS_GLOBAL module. In this case
+ * we need to check if this mod is loaded as a CLASS_SPECIFIC
+ * module. If it is we use that MTE. The MTE is then promoted
+ * to CLASS_GLOBAL.
+ */
+ if ((class == CLASS_SPECIFIC) &&
+ ldrCheckGlobal(pachModname, cb, ppmte))
+ goto again;
+
+ if ((rc=ldrOpenNewExe(pachModname, cb, plv, 0, &BoundApp, pNEFlags)) != NO_ERROR) {
+
+ if (rc == ERROR_OPEN_FAILED)
+ rc = ERROR_FILE_NOT_FOUND;
+
+ if (pBound != 0) {
+ *pBound = BoundApp;
+ }
+
+ return(rc) ;
+ }
+
+ if (pBound != 0) {
+ *pBound = BoundApp;
+ }
+
+ if ((class == CLASS_GLOBAL) && ldrCheckSpecific(ppmte, plv)) {
+ NtClose(lv.lv_sfn);
+ lv.lv_sfn = (*ppmte)->mte_sfn;
+ goto again;
+ }
+ pe32 = (struct e32_exe *) pheaderbuf;
+ ldrChkLoadType(pe32->e32_mflags, plv);
+ rc = ldrCreateMte(pe32, plv);
+ if (rc != NO_ERROR) {
+ NtClose(lv.lv_sfn);
+ return(rc);
+ }
+ pmte = lv.lv_pmte;
+
+ ModuleNameSize = *(PCHAR)pmte->mte_modname;
+ ModuleNameString = ((PCHAR)pmte->mte_modname)+1;
+ if ((ModuleNameSize == 8) &&
+ (strncmp("DOSCALLS", ModuleNameString, 8) == 0)) {
+ pmte->mte_mflags |= DOSLIB;
+ pmte->mte_usecnt = 1;
+ }
+
+// ldrInvTgtErrTxt();
+ /*
+ * If VMProtectedMem is TRUE, set MTEMODPROT if module is a 16-bit
+ * DLL and is in PROTECT16 list.
+ * Else clear MTEMODPROT (for both 16 and 32-bit modules).
+ */
+// if (VMProtectedMem) {
+// if (ldrIsNE(pmte) && (pmte->mte_mflags & LIBRARYMOD) &&
+// ldrIsModuleProtected())
+// pmte->mte_mflags |= MTEMODPROT;
+// }
+// else pmte->mte_mflags &= ~MTEMODPROT;
+
+ }
+
+ //
+ // Set the INGRAPH flag in order to prevent cycles
+ //
+ pmte->mte_mflags |= INGRAPH;
+
+ /*
+ * allocate object for this module by calling ldrAllocSegments for
+ * 16-bit modules or ldrAllocObjects for 32-bit modules
+ */
+ if (ldrIsNE(pmte)) {
+ //
+ // For system dll's other than Doscalls don't allocate
+ // segments.
+ //
+ if ((pmte->mte_mflags & DOSMOD) == 0) {
+ //
+ // Don't allocate segments for modules that are already
+ // allocated for this program
+ //
+ if ((pmte->mte_mflags & USED) == 0) {
+ rc = ldrAllocSegments(plv);
+ if (rc != NO_ERROR) {
+ if (pmte->mte_usecnt == 0) {
+ NtClose(lv.lv_sfn);
+ rc1 = Free16BHandle(pmte->mte_handle);
+ ASSERT(rc1 == NO_ERROR);
+ ldrUnlinkMTE(pmte);
+ RtlFreeHeap(LDRNEHeap, 0, pmte->mte_swapmte);
+ RtlFreeHeap(LDRNEHeap, 0, pmte);
+ }
+ return(rc);
+ }
+ }
+ }
+ }
+
+ *ppmte = pmte; /* return pmte */
+
+ //
+ // Now try to recursively allocate the referenced modules
+ //
+
+ /*
+ * For Each module in import module name table attach to or load
+ */
+ ppmte = (ldrmte_t **) pmte->mte_modptrs;
+
+ for (i = 1; i <= pmte->mte_impmodcnt; i++) {
+ /*
+ * Since it is required for 16-bit modules to load the
+ * referneced module in reverse order and not for 32-bit,
+ * lindex will be the index for the array of mte pointers
+ * for both 16-bit and 32-bit modules
+ */
+ lindex = pmte->mte_impmodcnt-i;
+
+ /*
+ * check if module loaded already, if so try to attach to it
+ */
+ ptemp = ppmte[lindex];
+
+ if ((ptemp != NULL) && ((ptemp->mte_mflags & INGRAPH) != 0)) {
+ continue;
+ }
+
+ /*
+ * point to mod name in table for 16-bit modules,
+ * load in reverse order
+ */
+ psmte = pmte->mte_swapmte;
+ RefModname = (uchar_t *) (psmte->smte_impproc +
+ ((ushort_t *) (psmte->smte_impmod))[lindex]);
+ Refcb = (USHORT) (*((uchar_t *) RefModname++));
+
+ rc = ldrGetMte(RefModname, Refcb, EXT_LIBRARY, CLASS_GLOBAL, &ptemp, NULL, NULL);
+ if (rc != NO_ERROR) {
+ return(rc);
+ }
+ ppmte[lindex] = ptemp;
+
+ /*
+ * validate as mte
+ */
+ ASSERT(fMTEValid(ptemp));
+
+ }
+ return(NO_ERROR);
+}
+
+
+/***LP ldrGetModParams - get program module startup parameters
+ *
+ * The program module startup parameters are obtained
+ * from the module's MTE header and are returned to the
+ * Exec function through the exec_info structure. This
+ * routine gets these parameters from the MTE and validates
+ * them and places them into the exec_info structure passed
+ * on the stack.
+ *
+ * This procedure performs the following steps:
+ *
+ * - Validates the starting code segment number.
+ * - Stores the starting CS:IP in the exec_info structure.
+ * - Validates the initial stack segment number and
+ * checks that it is not a shared segment.
+ * - Stores the initial SS in the exec_info structure.
+ * - Stores the auto data selector in the exec_info structure.
+ * - Calculates the initial SP and stores it in the exec_info
+ * structure.
+ * - Stores the additional heap size and stack size values in
+ * the exec_info structure.
+ *
+ * ENTRY pmte - pointer to module table entry
+ * pei - pointer to exec_info structure
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ */
+
+int ldrGetModParams(pmte, pei)
+ldrmte_t *pmte; /* pointer to mte */
+register ldrrei_t *pei; /* pointer to return buffer */
+{
+ ldrsmte_t *psmte; /* pointer to swappable mte */
+ ulong_t lobjnum;
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: ldrGetModParams(pmte=%X) was called\n", pmte);
+ }
+#endif
+
+ psmte = pmte->mte_swapmte;
+
+ /*
+ * see what type of module it is
+ */
+ if (ldrIsNE(pmte)) {
+ register ldrste_t *pste;
+
+ pei->ei_loadtype = LDR_16bit;
+ pei->ei_stacksize = (USHORT) psmte->smte_stacksize;
+ pei->ei_hmod = pmte->mte_handle;
+ pei->ei_heapsize = (USHORT) psmte->smte_heapsize;
+
+ /*
+ * The start object was checked in ldrCreateMTE
+ */
+ pste = ldrNumToSte(pmte, psmte->smte_startobj);
+ pei->ei_startaddr.ptr_off = (USHORT) psmte->smte_eip;
+ pei->ei_startaddr.ptr_sel = pste->ste_selector | 7;
+
+ /*
+ * compute stack, force word alignment. Stack object checked in
+ * ldrCreateMTE.
+ */
+ if (psmte->smte_stackobj != 0) {
+ pste = ldrNumToSte(pmte, psmte->smte_stackobj);
+ pei->ei_stackaddr.ptr_sel = pste->ste_selector | 7;
+ pei->ei_stackaddr.ptr_off = (USHORT) (psmte->smte_esp & 0x0fffe);
+ }
+ else {
+ pei->ei_stackaddr.ptr_sel = pste->ste_selector | 7;
+ pei->ei_stackaddr.ptr_off = (USHORT) (psmte->smte_esp & 0x0fffe);
+ }
+
+ /*
+ * setup autods
+ */
+ if (psmte->smte_autods != 0) {
+ pste = ldrNumToSte(pmte, psmte->smte_autods);
+ pei->ei_ds = pste->ste_selector | 7;
+ pei->ei_dgroupsize = pste->ste_minsiz;
+ }
+ else {
+ pei->ei_ds = 0; /* insure that value is ZERO */
+ }
+ }
+ else { /* 32-bit module */
+ register ldrote_t *pote;
+ ulong_t eip;
+
+ eip = psmte->smte_eip + psmte->smte_vbase;
+ pote = (ldrote_t *) psmte->smte_objtab;
+ for (lobjnum = 0; lobjnum < psmte->smte_objcnt; lobjnum++,
+ pote++) {
+ if ((eip >= pote->ote_base) &&
+ (eip < (pote->ote_base + pote->ote_psize)))
+ break;
+ }
+ if (lobjnum == psmte->smte_objcnt) {
+ return(ERROR_INVALID_STARTING_CODESEG);
+ }
+
+ /*
+ * check to see what type of entry point we have in this
+ * 32-bit module.
+ */
+ if (pote->ote_flags & OBJ_BIGDEF) { /* 32-bit object */
+ pei->ei_loadtype = LDR_32bit;
+ pei->ei_startaddr.ptr_flat = eip;
+ pei->ei_ds = 0;
+
+ /*
+ * The stack object was checked in ldrCreateMTE
+ */
+ pote = ldrNumToOte(pmte, psmte->smte_stackobj);
+ pei->ei_stackaddr.ptr_flat = pote->ote_base +
+ ((pote->ote_flags & OBJ_INVALID) ? pote->ote_psize :
+ pote->ote_vsize);
+ pei->ei_heapsize = 0;
+ }
+ else { /* 16-bit object */
+ pei->ei_loadtype = LDR_16bit;
+ pei->ei_heapsize = (USHORT) psmte->smte_heapsize;
+ pei->ei_startaddr.ptr_off = (USHORT) eip;
+// pei->ei_startaddr.ptr_sel = LaToSelTiled(pote->ote_base) |
+// (USHORT) SEL_RPL3;
+ pei->ei_startaddr.ptr_sel = FLATTOSEL(pote->ote_base);
+
+ if ((psmte->smte_autods == 0) ||
+ (pote = ldrNumToOte(pmte, psmte->smte_autods)) == NULL)
+ pei->ei_ds = 0;
+ else
+ pei->ei_ds = FLATTOSEL(pote->ote_base);
+// pei->ei_ds = LaToSelTiled(pote->ote_base) |
+// (USHORT) SEL_RPL3;
+ /*
+ * The stack object was checked in ldrCreateMTE
+ */
+ pote = ldrNumToOte(pmte, psmte->smte_stackobj);
+ pei->ei_stackaddr.ptr_sel = FLATTOSEL(pote->ote_base +
+ psmte->smte_esp);
+
+// pei->ei_stackaddr.ptr_sel = LaToSelTiled(pote->ote_base +
+// psmte->smte_esp) | (USHORT) SEL_RPL3;
+ pei->ei_stackaddr.ptr_off = (ushort_t) psmte->smte_esp;
+ }
+ } /* end 32-bit module */
+ return(NO_ERROR);
+}
+
+#if PMNT
+BOOLEAN
+LDRDumpSegments(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ UNICODE_STRING name_U;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE File;
+ IO_STATUS_BLOCK IoStatusBlock;
+ char Buffer[256]; // = "Hello, world\n";
+ ldrmte_t *pmte = mte_h; /* pointer to module table entry */
+ ldrsmte_t *psmte; /* pointer to swappable mte */
+ ldrste_t *pste;
+ ulong_t csegs;
+
+ RtlInitUnicodeString(&name_U, L"\\OS2SS\\DRIVES\\p:\\tmp\\pmnt.log");
+ InitializeObjectAttributes( &ObjectAttributes,
+ &name_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+
+ Status = NtCreateFile(
+ &File,
+ FILE_GENERIC_WRITE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL, // Allocation size
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ,
+ FILE_SUPERSEDE,
+ FILE_NON_DIRECTORY_FILE |
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL, // EA buffer
+ 0 // EA size
+ );
+
+ if (!NT_SUCCESS(Status))
+ {
+ KdPrint(("ldrDumpSegmentTable: NtOpenFile failed, Status=%x\n", Status));
+ return(TRUE);
+ }
+
+ while (pmte != NULL)
+ {
+ Status = NtWriteFile(
+ File,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ Buffer,
+ sprintf(Buffer, "\n%.*s\n",
+ *(char *)pmte->mte_modname,
+ pmte->mte_modname + 1),
+ NULL,
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ {
+ KdPrint(("ldrDumpSegmentTable: NtWriteFile failed, Status=%x\n", Status));
+ return(TRUE);
+ }
+
+ psmte = (ldrsmte_t *) pmte->mte_swapmte;
+ pste = (ldrste_t *) psmte->smte_objtab;
+ for (csegs = 1; csegs <= psmte->smte_objcnt; csegs++,
+ pste++)
+ {
+ Status = NtWriteFile(
+ File,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ Buffer,
+ sprintf(Buffer, " %2x: %4x %4x %4x %4x %4x %4x %8x\n",
+ csegs,
+ pste->ste_offset, /* file offset to segment data */
+ pste->ste_size, /* file data size */
+ pste->ste_flags, /* type and attribute flags */
+ pste->ste_minsiz, /* minimum allocation size */
+ pste->ste_seghdl, /* segment handle */
+ pste->ste_selector,/* segment selector */
+ pste->ste_fixups /* fixup record storage */
+ ),
+ NULL,
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ {
+ KdPrint(("ldrDumpSegmentTable: NtWriteFile failed, Status=%x\n", Status));
+ return(TRUE);
+ }
+ }
+
+ pmte = pmte->mte_link;
+ }
+
+ NtClose(File);
+
+ return(TRUE);
+}
+#endif // PMNT
+
+#if DBG
+void ldrDisplaySegmentTable()
+{
+ ldrmte_t *pmte = mte_h; /* pointer to module table entry */
+ ldrsmte_t *psmte; /* pointer to swappable mte */
+ ldrste_t *pste;
+ ulong_t csegs;
+
+ while (pmte != NULL)
+ {
+ DbgPrint("\n%.*s\npmte=%x, usecnt=%d, handle=%d\n",
+ *(char *)pmte->mte_modname,
+ pmte->mte_modname + 1,
+ pmte,
+ pmte->mte_usecnt,
+ pmte->mte_handle
+ );
+
+ psmte = (ldrsmte_t *) pmte->mte_swapmte;
+ pste = (ldrste_t *) psmte->smte_objtab;
+ for (csegs = 1; csegs <= psmte->smte_objcnt; csegs++,
+ pste++)
+ {
+ DbgPrint(" %2x: %4x %4x %4x %4x %4x %4x %8x %4x\n",
+ csegs,
+ pste->ste_offset, /* file offset to segment data */
+ pste->ste_size, /* file data size */
+ pste->ste_flags, /* type and attribute flags */
+ pste->ste_minsiz, /* minimum allocation size */
+ pste->ste_seghdl, /* segment handle */
+ pste->ste_selector,/* segment selector */
+ pste->ste_fixups /* fixup record storage */
+ );
+ }
+
+ pmte = pmte->mte_link;
+ }
+}
+#endif
+
+#if PMNT
+/*
+ * We want PMNT apps to load the original viocalls.dll
+ * and OS2 char. apps to load it from doscalls.dll
+ * This routine returns FALSE if an app. finds the wrong DLL
+ */
+BOOLEAN
+ldrChkPmntApp(pachModname, cb, pmte)
+PUCHAR pachModname; /* pointer to ASCII module name */
+USHORT cb; /* length of module name */
+ldrmte_t *pmte; /* pointer to mte */
+{
+ ULONG pmapp,dosmod;
+
+ if ((cb != 8) || (strncmp (pachModname,"VIOCALLS",cb))) {
+ return(TRUE);
+ }
+
+// pmapp = CurrentThread->Process->Flags &
+// (OS2_PROCESS_WINDOWAPI | OS2_PROCESS_FORCEDPM | OS2_PROCESS_PMMSGQUE);
+ pmapp = Os2srvProcessIsPMProcess(CurrentThread->Process);
+ dosmod = pmte->mte_mflags & DOSMOD;
+
+ return((pmapp && !dosmod) || (!pmapp && dosmod));
+}
+#endif //if PMNT
+
+
+/***LP ldrFindModule - Check if module is already loaded.
+ *
+ * Scans the class-list (CLASS_PROGRAM, CLASS_GLOBAL or CLASS_SPECIFIC)
+ * searching for a matching pathname. If the request is for a global
+ * dynlink library module, the module name, which is the first entry in
+ * the resident name table, is used for comparison. Otherwise the pathname
+ * is fully expanded and compared with expanded pathname in the mte.
+ *
+ * The MTE list is organised like this:
+ *
+ * program_h global_h specific_h
+ * | | |
+ * mte_h +------+ +-----+ +-----+ +-----+ +-----+ +-----+
+ * ----> | | | |--->| | | |--->| | | |---+
+ * +------+ .. +-----+ +-----+ .. +-----+ +-----+ .. +-----+ |
+ * | | | ___
+ * program_l global_l specific_l -
+ *
+ * mte_h is the head of the linked list. Both program_h and specific_h
+ * could be NULL. If program_h is NULL, then mte_h and global_h point to
+ * the same MTE. global_l can never be NULL. program_l and specific_l
+ * can be.
+ *
+ * ENTRY pachModname - pointer to module name
+ * class - CLASS_GLOBAL, CLASS_SPECIFIC or
+ * CLASS_PROGRAM
+ * ppmte - pointer to a pmte to return
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ * - pointer to reqested mte returned in
+ * ppmte
+ *
+ */
+
+int ldrFindModule(pachModname, cb, class, ppmte)
+PUCHAR pachModname; /* pointer to ASCII module name */
+USHORT cb; /* length of module name */
+USHORT class; /* class of module */
+ldrmte_t **ppmte; /* place to return pointer */
+{
+ register ldrmte_t *pmte; /* pointer to module table entry */
+ ldrsmte_t *psmte; /* pointer to swappable MTE */
+ USHORT cchlen; /* length of module name in restab */
+ USHORT fpath; /* If TRUE then search by path */
+
+ fpath = (USHORT) (class & SEARCH_BY_PATH);
+ class &= ~SEARCH_BY_PATH;
+
+ switch (class) {
+ case CLASS_ALL:
+ pmte = mte_h;
+ break;
+ case CLASS_GLOBAL:
+ pmte = global_h;
+ break;
+ case CLASS_SPECIFIC:
+ pmte = specific_h;
+ break;
+ case CLASS_PROGRAM:
+ pmte = program_h;
+ break;
+ default:
+#if DBG
+ DbgPrint("ldrFindModule: Invalid class");
+#endif
+ pmte = mte_h;
+ break;
+ }
+
+ /*
+ * Search the mte list for module name in TempBuf
+ */
+ while (pmte != NULL) {
+
+ /*
+ * If not searching CLASS_ALL, terminate the scan when the
+ * class value in the MTE is not what we want.
+ */
+ if ((class != CLASS_ALL) &&
+ ((USHORT)(pmte->mte_mflags & CLASS_MASK) != class)) {
+ pmte = NULL;
+ break;
+ }
+ if ((class == CLASS_GLOBAL) && (fpath != SEARCH_BY_PATH)) {
+ /*
+ * If we're looking for global library module, first check
+ * length of name for match then check name.
+ */
+ cchlen = (USHORT) *((PCHAR )pmte->mte_modname);
+ if ((cb == cchlen) &&
+ (strncmp((PCHAR)(pmte->mte_modname+1),
+ pachModname,
+ cchlen) == 0)) {
+#if PMNT
+ /*
+ * check for viocalls
+ *
+ */
+ if (ldrChkPmntApp(pachModname, cb, pmte))
+#endif //if PMNT
+ break;
+ }
+ }
+
+ /*
+ * If either program or specific module, just compare name.
+ * First compare length of strings to fix the problem of
+ * the string matching the first n characters of the pathname
+ * but what if the pathname has n+1 characters in name.
+ */
+ else {
+ psmte = pmte->mte_swapmte;
+ if (psmte->smte_pathlen == cb) {
+ if (strncmp((PCHAR) psmte->smte_path,
+ pachModname,
+ cb) == 0) {
+ break;
+ }
+ }
+ }
+
+ pmte = pmte->mte_link;
+ }
+ *ppmte = pmte; /* Could be NULL, in which case we */
+ return(NO_ERROR); /* did not find the module */
+}
+
+
+/***LP ldrLinkMTE - Link MTE in the list at the appropriate place
+ *
+ * MTEs are linked according to the class they belong to. The possible
+ * classes are CLASS_PROGRAM, CLASS_GLOBAL and CLASS_SPECIFIC. The corres.
+ * list heads are program_h, global_h and specific_h. We also have the
+ * tail of CLASS_PROGRAM, CLASS_GLOBAL and CLASS_SPECIFIC lists which are
+ * program_l, global_l and specific_l. These aid us in linking and
+ * unlinking the list and not having to go through the chain every time.
+ *
+ * To begin with mte_h and global_h point to the same MTE, program_h,
+ * program_l, specific_h and specific_l are NULL. global_l is also
+ * initialised.
+ * See ldrFindModule for organisation of the MTE List.
+ *
+ * The possible cases are:
+ * 1. Link a CLASS_PROGRAM MTE.
+ * if (program_h == NULL) {
+ * pmte->mte_link = global_h;
+ * program_l = pmte;
+ * }
+ * else pmte->mte_link = program_h;
+ * mte_h = program_h = pmte;
+ *
+ * 2. Link a CLASS_GLOBAL MTE.
+ * pmte->mte_link = global_h; // global_h can never be NULL
+ * global_h = pmte;
+ * if (program_l == NULL) // and hence program_h is NULL
+ * mte_h = global_h;
+ * else program_l->mte_link = global_h;
+ *
+ * 3. Link a CLASS_SPECIFIC MTE.
+ * if (specific_l == NULL)
+ * specific_l = pmte;
+ * pmte->mte_link = specific_h;
+ * global_l->mte_link = pmte;
+ *
+ * ENTRY
+ * pmte MTE to link in the list
+ *
+ * EXIT NONE
+ * MTE is linked at the right place
+ */
+void ldrLinkMTE(pmte)
+register ldrmte_t *pmte;
+{
+
+ switch (pmte->mte_mflags & CLASS_MASK) {
+ case CLASS_PROGRAM:
+ if (program_h == NULL) {
+ pmte->mte_link = global_h;
+ program_l = pmte;
+ }
+ else
+ pmte->mte_link = program_h;
+ mte_h = program_h = pmte;
+ break;
+
+ case CLASS_GLOBAL:
+ pmte->mte_link = global_h; /* global_h can never be NULL */
+ global_h = pmte;
+ if (program_l == NULL) /* and hence program_h is NULL */
+ mte_h = pmte;
+ else
+ program_l->mte_link = pmte;
+ break;
+
+ case CLASS_SPECIFIC:
+ if (specific_l == NULL)
+ specific_l = pmte;
+ pmte->mte_link = specific_h;
+ specific_h = pmte;
+ global_l->mte_link = pmte; /* global_l can never be NULL */
+ break;
+
+ default:
+#if DBG
+ DbgPrint("ldrLinkMTE: Invalid class");
+#endif
+ // same as CLASS_GLOBAL
+ pmte->mte_link = global_h; /* global_h can never be NULL */
+ global_h = pmte;
+ if (program_l == NULL) /* and hence program_h is NULL */
+ mte_h = pmte;
+ else
+ program_l->mte_link = pmte;
+ break;
+ }
+}
+
+
+/***LP ldrUnlinkMTE - Unlink MTE from the list
+ *
+ * Unlink the given MTE from the list. See ldrFindModule and ldrLinkMTE
+ * for details of how the list is organised.
+ *
+ * ENTRY
+ * pmte MTE to unlink from the list
+ *
+ * EXIT NONE
+ * MTE is unlinked
+ */
+void ldrUnlinkMTE(pmte)
+register ldrmte_t *pmte;
+{
+ register ldrmte_t *pmtecur; /* Current mte */
+ register ldrmte_t **ppmtepred; /* Predecessor mte */
+ ldrmte_t **ppmtehead; /* Pointer to class head */
+ ldrmte_t **ppmtetail; /* Pointer to class tail */
+ USHORT class;
+
+ switch (class = (USHORT)(pmte->mte_mflags & CLASS_MASK)) {
+ case CLASS_PROGRAM:
+ pmtecur = program_h;
+ ppmtepred = &mte_h;
+ ppmtehead = &program_h;
+ ppmtetail = &program_l;
+ break;
+
+ case CLASS_GLOBAL:
+ pmtecur = global_h;
+ ppmtepred = &program_l->mte_link;
+ if (program_l == NULL)
+ ppmtepred = &mte_h;
+ ppmtehead = &global_h;
+ ppmtetail = &global_l;
+ break;
+
+ case CLASS_SPECIFIC:
+ pmtecur = specific_h;
+ ppmtepred = &global_l->mte_link;
+ ppmtehead = &specific_h;
+ ppmtetail = &specific_l;
+ break;
+
+ default:
+#if DBG
+ DbgPrint("ldrUnlinkMTE: Invalid list");
+#endif
+ // same as class global
+ pmtecur = global_h;
+ ppmtepred = &program_l->mte_link;
+ if (program_l == NULL)
+ ppmtepred = &mte_h;
+ ppmtehead = &global_h;
+ ppmtetail = &global_l;
+ break;
+ }
+ while (TRUE) {
+
+ ldrAssert((pmtecur != NULL &&
+ (pmtecur->mte_mflags & CLASS_MASK) == class));
+
+ if (pmtecur == pmte)
+ break;
+ ppmtepred = &pmtecur->mte_link;
+ pmtecur = pmtecur->mte_link;
+ }
+
+ *ppmtepred = pmte->mte_link; /* Unlink MTE */
+
+ if (pmte == *ppmtehead) { /* If unlinkee is at the head */
+ *ppmtehead = pmte->mte_link;
+ /* If class disappears, then both head and tail disappear */
+ if ((*ppmtehead == NULL) ||
+ ((USHORT)((*ppmtehead)->mte_mflags & CLASS_MASK) != class)) {
+ *ppmtehead = NULL;
+ *ppmtetail = NULL;
+ }
+ }
+ /*
+ * Since we have a pointer to the mte_link field of the predecessor
+ * we need to get back to the mte pointer by subtracting the offset
+ * of the link field of MTE from the pointer to predecessor.
+ */
+ if (pmte == *ppmtetail) { /* If unlinkee is at the tail */
+ *ppmtetail = (ldrmte_t *)((ULONG)ppmtepred -
+ FIELDOFFSET(ldrmte_t, mte_link));
+ ldrAssert(fMTEValid(*ppmtetail));
+ }
+}
+
+
+/***LP ldrCheckGlobal - Check if specified module is loaded as global
+ *
+ * Called by ldrGetMte. If a module is being loaded as a specific module
+ * and ldrFindModule has not found this in the specific list, we see if
+ * this is loaded as a global module. For this to happen, the following
+ * has to be satisfied.
+ * a, The file has to have a ".DLL" as the last part of its name.
+ * b, It should be somewhere in the libpath
+ *
+ * ENTRY
+ * pachModname file name string
+ * cb length of module name
+ * ppmte pointer to where the MTE pointer, if found,
+ * is to be returned
+ *
+ * EXIT
+ * TRUE if module found as loaded global
+ * FALSE module not global.
+ */
+int ldrCheckGlobal(pachModname, cb, ppmte)
+PUCHAR pachModname;
+USHORT cb;
+register ldrmte_t **ppmte;
+{
+ int rc;
+
+ if ((cb <= 4) || _strnicmp(&pachModname[cb-4], ".DLL", 4)) {
+ return(FALSE);
+ }
+
+ if ((rc = ldrFindModule(pachModname, cb,
+ CLASS_GLOBAL|SEARCH_BY_PATH, ppmte)) != NO_ERROR) {
+ load_error(rc, NULL);
+ }
+ return (*ppmte != NULL);
+}
+
+
+/***LP ldrCheckSpecific - Check if specified module is loaded as specfic
+ *
+ * Called by ldrGetMte. If a module is being loaded as a global module
+ * and ldrFindModule has not found this in the global list, we see if
+ * this is loaded as a specific module. If we find this in the specific
+ * list, then we promte it to the global list.
+ *
+ * ENTRY ppmte pointer to where the MTE pointer, if found,
+ * is to be returned.
+ * plv pointer to loader variables structure
+ *
+ * EXIT
+ * TRUE If module found as loaded global
+ * FALSE Otherwise.
+ */
+int ldrCheckSpecific(ppmte, plv)
+ldrmte_t **ppmte;
+ldrlv_t *plv ;
+{
+ USHORT cchModname;
+ register PCHAR pldrbuf = LdrBuf;
+ int rc;
+
+ cchModname = (USHORT) (strlen(pldrbuf));
+
+ ldrUCaseString(pldrbuf, cchModname);
+
+ if ((rc = ldrFindModule(pldrbuf, cchModname, CLASS_SPECIFIC, ppmte)) != NO_ERROR) {
+ NtClose(plv->lv_sfn);
+ load_error(rc, NULL);
+ }
+ if (*ppmte == NULL)
+ return (FALSE);
+ ldrPromoteMTE(*ppmte);
+ return (TRUE);
+}
+
+
+/***LP ldrPromoteMTE - Promote MTE from specific class list to global
+ *
+ * Unlink an MTE from the specific class list and link into global
+ * class list.
+ *
+ * ENTRY pmte MTE to promote
+ *
+ * EXIT NONE
+ */
+void ldrPromoteMTE(pmte)
+ldrmte_t *pmte;
+{
+#ifdef MISCSTRICT
+ if ((pmte->mte_mflags & CLASS_MASK) != CLASS_SPECIFIC)
+ panic("ldrPromoteMTE: Invalid class");
+#endif
+ ldrUnlinkMTE(pmte);
+ pmte->mte_mflags &= ~CLASS_SPECIFIC;
+ pmte->mte_mflags |= CLASS_GLOBAL;
+ ldrLinkMTE(pmte);
+}
+
+
+/***LP ldrOpenNewExe - Open module pathname and verify it's a new EXE format
+ *
+ * The specified file is opened and the old header and
+ * New EXE headers are read and verified. If New EXE header is
+ * a 16-bit module ("NE"), expand the 16-bit header to a 32-bit
+ * header. pheaderbuf is implicitly used.
+ *
+ * ENTRY pachModname - pointer to module name
+ * cb - length of module name
+ * plv - pointer to local variables on stack
+ * pfl - optional pointer to a flag set if OLD exe
+ * pBound - optional pointer to a flag set if BOUND exe
+ * pNEFlags - Flags word of the NE header
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ */
+
+int ldrOpenNewExe(pachModname, cb, plv, pfl, pBound, pNEFlags)
+PUCHAR pachModname; /* pointer to ASCII module name */
+USHORT cb; /* length of module name */
+ldrlv_t *plv; /* pointer to local variables */
+PUSHORT pfl; /* optional pointer to a flag set if OLD exe */
+PBOOLEAN pBound; /* optional pointer to a flag set if BOUND exe */
+PULONG pNEFlags; /* optional pointer to Flags word of the NE header */
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ LARGE_INTEGER ByteOffset;
+ ULONG ulNewHdrOff; /* Offset hdr offset */
+ ULONG ulCopied; /* Number of bytes copied */
+ ULONG ulNeeded; /* Number of bytes needed */
+ ULONG usoff; /* Offset to new exe header */
+ ULONG *pl; /* pointer to a long */
+ USHORT *ps; /* pointer to a short */
+ struct e32_exe *pe32;
+ struct e32_exe *pe32temp;
+ ULONG flmte; /* flags */
+ int rc;
+ ULONG BoundAppFlag = 0L;
+ struct new_exe *ne;
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: ldrOpenNewExe() was called\n");
+ }
+#endif
+
+ flmte = 0;
+
+ if (pfl != 0)
+ *pfl = FALSE;
+
+ if (pBound != 0)
+ *pBound = FALSE;
+
+ if ((rc = ldrOpenPath(pachModname,
+ cb,
+ plv,
+ &flmte)) != NO_ERROR) {
+ plv->lv_sfn = NULL;
+ return(rc);
+ }
+
+ pe32 = (struct e32_exe *) pheaderbuf;
+ ne = (struct new_exe *) pe32;
+
+ /*
+ * Start read at beginning of file
+ */
+ ByteOffset.LowPart = 0;
+ ByteOffset.HighPart = 0;
+
+ if ((rc = NtReadFile( plv->lv_sfn,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ pe32,
+ 512,
+ &ByteOffset,
+ 0 )) != 0) {
+ NtClose(plv->lv_sfn);
+ rc = Or2MapNtStatusToOs2Error(rc, ERROR_BAD_FORMAT);
+ return(rc);
+ }
+
+ /*
+ * validate old (MZ) signature in header
+ */
+ if (((struct exe_hdr *) pe32)->e_magic != EMAGIC) {
+ NtClose(plv->lv_sfn);
+ return(ERROR_INVALID_EXE_SIGNATURE) ;
+ }
+
+ usoff = ((struct exe_hdr *) pe32)->e_lfarlc;
+
+ /*
+ * Set flag to say that it's at least a DOS app
+ */
+ if (pfl != 0) {
+ *pfl = TRUE;
+ }
+
+ /*
+ * get pointer to (NE) or (LE) exe header
+ */
+ ulNewHdrOff =
+ plv->lv_new_exe_off = ((struct exe_hdr *) pe32)->e_lfanew;
+
+ //
+ // Check if the file has the potential of being a bound
+ // app, and if so set BoundAppFlag
+ //
+
+ if (pBound != 0 &&
+ plv->lv_new_exe_off != 0x40L &&
+ ((struct exe_hdr *) pe32)->e_minalloc != 0xffff &&
+ IoStatusBlock.Information >= 0x52 &&
+ strncmp(((char *) pe32) + 0x4e, "This", 4) != 0
+ ) {
+
+ BoundAppFlag |= 0x1L;
+ }
+
+ /*
+ * check if we read at least up to the (NE) or (LE) header
+ */
+ if (ulNewHdrOff < IoStatusBlock.Information) {
+
+ /*
+ * assume we are reading a 32-bit module
+ */
+ ulNeeded = sizeof(struct e32_exe);
+ pe32temp = (struct e32_exe *) ((ULONG) pe32 + ulNewHdrOff);
+
+ if ((ulNewHdrOff < (IoStatusBlock.Information -
+ sizeof(pe32->e32_magic))) &&
+ (*(short *) (pe32temp->e32_magic) == NEMAGIC))
+ ulNeeded = sizeof(struct new_exe);
+
+ ulCopied = min(IoStatusBlock.Information - ulNewHdrOff, ulNeeded);
+
+ memcpy(pe32, (PVOID) ((ULONG) pe32 + ulNewHdrOff), ulCopied);
+
+ if (ulNeeded -= ulCopied) {
+ if ((rc = NtReadFile( plv->lv_sfn,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ (PCHAR) pe32 + ulCopied,
+ ulNeeded,
+ &ByteOffset,
+ 0 )) != 0) {
+ NtClose(plv->lv_sfn);
+ rc = Or2MapNtStatusToOs2Error(rc, ERROR_BAD_FORMAT);
+ return(rc);
+ }
+ }
+ }
+ else {
+
+ /*
+ * read in new header to size of 32-bit mte plus a ote entry
+ */
+ ByteOffset.LowPart = (ULONG)((struct exe_hdr *)pe32)->e_lfanew;
+ ByteOffset.HighPart = 0;
+
+ if ((rc = NtReadFile( plv->lv_sfn,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ (PCHAR) pe32,
+ sizeof(struct e32_exe)+sizeof(ldrote_t),
+ &ByteOffset,
+ 0 )) != 0) {
+ NtClose(plv->lv_sfn);
+ rc = Or2MapNtStatusToOs2Error(rc, ERROR_BAD_FORMAT);
+ return(rc);
+ }
+ }
+
+ /* Verify that this is a protect-mode exe. (Check this before
+ * checking MTE signature for 1.2 error code compatability.)
+ */
+ if (usoff != 0x40) {
+ NtClose(plv->lv_sfn);
+ return(ERROR_BAD_EXE_FORMAT) ;
+ }
+
+ /*
+ * validate as 16-bit signature or 32-bit signature
+ */
+ if (!(*(short *) (pe32->e32_magic) == LEMAGIC ||
+ *(short *) (pe32->e32_magic) == NEMAGIC)) {
+ NtClose(plv->lv_sfn);
+ return(ERROR_INVALID_EXE_SIGNATURE);
+ }
+
+ /*
+ * verify some header fields for LE modules only.
+ */
+ if ((*(short *) (pe32->e32_magic) == LEMAGIC) &&
+ (!((pe32->e32_bworder == E32LEWO) &&
+ (pe32->e32_os == NE_OS2)))) {
+ NtClose(plv->lv_sfn);
+ return(ERROR_INVALID_EXE_SIGNATURE);
+ }
+
+ /*
+ * This is known to be a Protect-mode app at this point.
+ */
+ if (pfl != NULL)
+ *pfl = FALSE;
+
+ /*
+ * if header in 16-bit format save ne_sssp and move ne_mflags into
+ * e32_mflags
+ */
+ if (*(short *) (pe32->e32_magic) == NEMAGIC) {
+ pl = (ULONG *) ((PCHAR) pe32 +
+ FIELDOFFSET(struct e32_exe, e32_res4));
+ *pl = ((struct new_exe *) pe32)->ne_sssp;
+ ps = (USHORT *) ((PCHAR) pe32 +
+ FIELDOFFSET(struct e32_exe, e32_mflags));
+ *ps = ((struct new_exe *)pe32)->ne_flags;
+ /*
+ * mask out those flags that are not used in the 32-bit header
+ */
+ pe32->e32_mflags &= (AUTODS_MASK | INSTLIBINIT | LDRINVALID |
+ LIBRARYMOD | E32_APPMASK | NEBOUND);
+ if (((struct new_exe *)pe32)->ne_flagsothers & NELONGNAMES)
+ pe32->e32_mflags |= MTELONGNAMES;
+ }
+ else {
+ pe32->e32_mflags |= MTELONGNAMES;
+ }
+
+ /*
+ * check if executable is a valid image
+ */
+ if (pe32->e32_mflags & LDRINVALID) {
+ NtClose(plv->lv_sfn);
+ return(ERROR_EXE_MARKED_INVALID);
+ }
+
+ /* Clear for internal use */
+ pe32->e32_mflags &= ~(MTE_MEDIAFIXED|MTE_MEDIACONTIG|MTE_MEDIA16M);
+ pe32->e32_mflags |= flmte; /* Set flags set by ldrOpenPath */
+
+ rc = ldrMungeFlags(pe32);
+ if (rc != NO_ERROR) {
+ NtClose(plv->lv_sfn);
+ return(rc);
+ }
+
+ //
+ // Figure out if this is a bound app
+ //
+
+ if (pBound != 0 &&
+ *(short *) (pe32->e32_magic) == NEMAGIC) {
+
+ if ((ne->ne_flags & NENOTP) == 0) {
+
+ if ((ne->ne_flags & NEBOUND) != 0) {
+
+ BoundAppFlag |= 0x2;
+
+ } else if ((BoundAppFlag & 0x1) != 0 &&
+ ne->ne_enttab - ne->ne_imptab != 0 &&
+ ne->ne_restab - ne->ne_rsrctab == 0) {
+
+ BoundAppFlag |= 0x2;
+ }
+ }
+
+ if ((BoundAppFlag & 0x2) != 0)
+ *pBound = TRUE;
+ }
+
+ //
+ // Get the NE file Flags word
+ //
+ if ((pNEFlags != NULL) &&
+ *(short *) (pe32->e32_magic) == NEMAGIC) {
+
+ *pNEFlags = (ULONG)ne->ne_flags;
+ if (plv->lv_class == CLASS_PROGRAM) {
+ if ((*pNEFlags & NEAPPTYP) == NENOTWINCOMPAT) {
+ CurrentThread->Process->Flags |= OS2_PROCESS_NOTWINDOWCOMPAT;
+ }
+ else if ((*pNEFlags & NEAPPTYP) == NEWINCOMPAT) {
+ CurrentThread->Process->Flags |= OS2_PROCESS_WINDOWCOMPAT;
+ }
+ else if ((*pNEFlags & NEAPPTYP) == NEWINAPI) {
+ CurrentThread->Process->Flags |= OS2_PROCESS_WINDOWAPI;
+ }
+ }
+ }
+
+ //
+ // Verify number of segments in the NE header
+ //
+ if (*(short *) (pe32->e32_magic) == NEMAGIC) {
+ if ((USHORT)(ne->ne_cseg * (USHORT)sizeof(struct new_seg)) >
+ ((USHORT)ne->ne_rsrctab - (USHORT)ne->ne_segtab)) {
+#if DBG
+ DbgPrint("ne_cseg 0x%x\n", (USHORT)ne->ne_cseg);
+ DbgPrint("ne_cmod 0x%x\n", (USHORT)ne->ne_cmod);
+ DbgPrint("ne_cbnrestab 0x%x\n", (USHORT)ne->ne_cbnrestab);
+ DbgPrint("ne_segtab 0x%x\n", (USHORT)ne->ne_segtab);
+ DbgPrint("ne_rsrctab 0x%x\n", (USHORT)ne->ne_rsrctab);
+ DbgPrint("ne_restab 0x%x\n", (USHORT)ne->ne_restab);
+ DbgPrint("ne_modtab 0x%x\n", (USHORT)ne->ne_modtab);
+#endif
+ NtClose(plv->lv_sfn);
+ return(ERROR_BAD_EXE_FORMAT);
+ }
+ }
+ return(NO_ERROR);
+}
+
+/***LP ldrOpenPath - Open module file, possibly searching LIBPATH
+ *
+ * ldrOpenPath opens the file for the module, given the module name.
+ *
+ * The names passed for CLASS_GLOBAL must not contain a drive,
+ * path, or extension. For program modules, the name must contain
+ * the desired null terminated relative path. If IsIFS, the LIBPATH
+ * name is ignored.
+ *
+ * ldrOpenPath(pchModname, cchModname, plv, pflmte)
+ *
+ * ENTRY pachModname - pointer to module name
+ * cb - module name length
+ * plv - pointer to local variables
+ * pflmte - pointer to mte flags to return
+ * piostatus - pointer to IO stat buffer
+ *
+ * EXIT none - return successful or call load_error
+ *
+ */
+
+int ldrOpenPath(pachModname, cb, plv, pflmte)
+PUCHAR pachModname; /* pointer to ASCII module name */
+USHORT cb; /* length of module name */
+ldrlv_t *plv; /* pointer to local variables */
+PULONG pflmte; /* pointer to return mte flags in */
+
+{
+
+ HANDLE File;
+ STRING name;
+ UNICODE_STRING name_U;
+ NTSTATUS Status;
+ PSTRING pname = &name;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PUCHAR pstring;
+ PUCHAR ptmp;
+ ULONG cbstring;
+ PUCHAR plibpath;
+ int rc; /* return code */
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: ldrOpenPath() was called with modname=%.*s\n", cb, pachModname);
+ }
+#endif
+
+ if (plv->lv_class == CLASS_GLOBAL) {
+ plibpath = ldrpLibPath;
+ }
+ else {
+ LdrBuf[0] = '\0'; // This causes the try_another loop to exit
+ plibpath = LdrBuf; // after the first try
+ }
+
+ do {
+ if (plv->lv_class == CLASS_GLOBAL) {
+ ptmp = (PUCHAR)strchr(plibpath, ';');
+ if (ptmp == NULL)
+ cbstring = strlen(plibpath);
+ else
+ cbstring = ptmp - plibpath;
+ memcpy(LdrBuf, plibpath, cbstring);
+ plibpath += cbstring;
+ pstring = &LdrBuf[cbstring];
+ if (*(pstring - 1) != '\\') { // prevent double backslash in \OS2SS\DRIVES\C:\ cases
+ *pstring++ = '\\';
+ }
+ memcpy(pstring, pachModname, cb);
+ pstring += cb;
+ if (pflmte != NULL) {
+ memcpy(pstring, ".DLL\0", 5);
+ }
+ else {
+ *pstring = '\0';
+ }
+ pstring = LdrBuf;
+ }
+ else {
+ pstring = pachModname;
+ }
+
+ RtlInitAnsiString(pname, pstring);
+
+ //
+ // UNICODE conversion -
+ //
+ Status = RtlOemStringToUnicodeString(
+ &name_U,
+ pname,
+ TRUE);
+ ASSERT (NT_SUCCESS(Status));
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &name_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+
+ Status = NtOpenFile(&File,
+ GENERIC_READ | FILE_READ_DATA | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ,
+ FILE_NON_DIRECTORY_FILE |
+ FILE_SYNCHRONOUS_IO_NONALERT);
+
+ RtlFreeUnicodeString (&name_U);
+ if (NT_SUCCESS(Status) && (plv->lv_class != CLASS_GLOBAL)) {
+ strncpy(&LdrBuf[0], name.Buffer, name.Length);
+ LdrBuf[name.Length] = '\0';
+ }
+
+ if (NT_SUCCESS(Status)) { // Avoid switch in the NO_ERROR case.
+ plv->lv_sfn = File;
+ return(NO_ERROR);
+ }
+
+ rc = ERROR_FILE_NOT_FOUND; // Assume end of LibPath
+ } while (*plibpath++ != '\0');
+
+ //
+ // Test if the error code should be
+ // ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND or ERROR_INVALID_DRIVE
+ // by trying to open the directory path for SPECIFIC modules
+ //
+ if (plv->lv_class == CLASS_SPECIFIC) {
+ memcpy(LdrBuf, pachModname, cb);
+ LdrBuf[cb] = '\0';
+ ptmp = strrchr(LdrBuf, '\\');
+ if (ptmp == NULL) {
+ return(rc);
+ }
+ *ptmp = '\0';
+
+ RtlInitAnsiString(pname, LdrBuf);
+
+ //
+ // UNICODE conversion -
+ //
+ Status = RtlOemStringToUnicodeString(
+ &name_U,
+ pname,
+ TRUE);
+ if (!NT_SUCCESS(Status)) {
+ return(rc);
+ }
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &name_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+
+ Status = NtOpenFile(&File,
+ GENERIC_READ | FILE_READ_DATA | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ,
+ FILE_DIRECTORY_FILE |
+ FILE_SYNCHRONOUS_IO_NONALERT);
+
+ RtlFreeUnicodeString (&name_U);
+ if (NT_SUCCESS(Status)) {
+ NtClose(File);
+ return(rc);
+ }
+ else {
+ rc = ERROR_PATH_NOT_FOUND;
+ }
+ //
+ // Now differentiate between
+ // ERROR_PATH_NOT_FOUND and ERROR_INVALID_DRIVE
+ //
+ ptmp = strchr(LdrBuf, ':');
+ if (ptmp == NULL) {
+ return(rc);
+ }
+ ptmp++; // point to the \ after the drive name
+ if (*ptmp != '\\') {
+ return(rc);
+ }
+ ptmp++;
+ *ptmp = '\0';
+
+ RtlInitAnsiString(pname, LdrBuf);
+
+ //
+ // UNICODE conversion -
+ //
+ Status = RtlOemStringToUnicodeString(
+ &name_U,
+ pname,
+ TRUE);
+ if (!NT_SUCCESS(Status)) {
+ return(rc);
+ }
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &name_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL );
+
+ Status = NtOpenFile(&File,
+ GENERIC_READ | FILE_READ_DATA | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ,
+ FILE_DIRECTORY_FILE |
+ FILE_SYNCHRONOUS_IO_NONALERT);
+
+ RtlFreeUnicodeString (&name_U);
+ if (NT_SUCCESS(Status)) {
+ NtClose(File);
+ return(rc);
+ }
+ else {
+ rc = ERROR_INVALID_DRIVE;
+ }
+ }
+ return(rc);
+}
+
+#pragma optimize("", off)
+/***LP ldrMungeFlags - Translate Module flags to internal flags
+ *
+ * Translate the module info in the EXE header to the internal
+ * format.
+ *
+ * ENTRY pe32 Pointer to the linker EXE image
+ *
+ * EXIT NO_ERROR
+ * ERROR_BAD_EXE_FORMAT, if the module type is garbage
+ */
+int ldrMungeFlags(pe32)
+register struct e32_exe *pe32;
+{
+ register int modtype;
+
+ modtype = pe32->e32_mflags & E32_MODMASK;
+ pe32->e32_mflags &= ~E32_MODMASK;
+
+ switch (modtype) {
+
+ case E32_MODEXE:
+ break;
+
+ case E32_MODDLL:
+ pe32->e32_mflags |= LIBRARYMOD;
+ break;
+
+ case E32_MODPDEV:
+ pe32->e32_mflags |= DEVDRVMOD | LIBRARYMOD;
+ break;
+
+ /* BUGBUG: JH - The following case is to overcome a LINK386 bug
+ which turns on the PROTMOD bit if loaddses is used */
+ case E32_MODVDEV:
+ pe32->e32_mflags |= VDDMOD | LIBRARYMOD;
+ break;
+
+ default:
+ return (ERROR_BAD_EXE_FORMAT);
+ }
+ return (NO_ERROR);
+}
+#pragma optimize("", on)
+
+
+/***LP ldrCreateMte - allocate and load module table entry
+ *
+ * This routine loads and initializes a module table entry. Memory
+ * is allocated for the file module data with additional
+ * space for module handles and the module
+ * pathname. Segment handle and selector fields are added to the
+ * end of each segment table entry for 16-bit modules. The module
+ * reference strings are checked to make sure there are no wild pointers
+ * that would cause a gp fault. The resident name table is checked to
+ * make sure that it can be scanned without causing a gp fault.
+ *
+ * If the module that is being loaded is a 16-bit module the 16-bit
+ * exe header was expanded into a 32-bit exe header when file
+ * was opened.
+ *
+ * ENTRY pe32 - pointer to link exe image
+ * plv - pointer to local variables
+ * - ptda and search buff are setup
+ *
+ * EXIT none - return successful or call load_error
+ */
+
+APIRET ldrCreateMte(pe32, plv)
+struct e32_exe *pe32; /* pointer to linker exe image */
+register ldrlv_t *plv; /* pointer to local variables */
+
+{
+ldrmte_t *pmte = NULL; /* pointer to loader MTE */
+ldrsmte_t *psmte = NULL; /* pointer to swappable loader MTE */
+struct ImpHdr *piat = NULL; /* pointer to iat memory */
+int rc;
+ULONG csmte; /* size of swappable MTE */
+ULONG mte_16_32_constant; /* adjustment constant for ptrs */
+ULONG cbpathlen; /* length of pathname in TempBuf */
+USHORT hobmte = 0; /* MTE pseudo handle */
+ULONG lobjnum; /* object number count */
+ldrste_t *pste; /* pointer to segment table entry */
+ldrote_t *pote; /* pointer to object table entry */
+ldrote_t *poteiat = NULL; /* pointer to ote for IAT */
+ldrote_t *potersrc = NULL; /* pointer to ote for resource dir */
+ldrrsrcinfo_t *prsrcinfo;
+ULONG cbfile; /* Amount of data for seg in file */
+ULONG cbseg; /* Size of segment */
+ULONG *pdst; /* used to copy MTE */
+//VMAC ac; /* buffer for VMReserve */
+ULONG cimpmod; /* count of import modules */
+ULONG cpad;
+PCHAR pac;
+UCHAR length;
+struct ExpHdr *pexp; /* pointer to export dircetory */
+struct ImpHdr *pimpdir; /* pointer to import directory */
+struct ImpHdr *pprevimpdir; /* pointer to import directory */
+ULONG vsize = 0; /* virtaul size of module */
+ULONG lsize;
+ULONG lfixtab;
+ULONG cpages = 1; /* count of pages in module */
+ULONG lconstant;
+ULONG lcount;
+ULONG cbiat = 0; /* size of IAT */
+ULONG cbrsrc = 0;
+ULONG iataddr;
+USHORT i;
+IO_STATUS_BLOCK IoStatusBlock;
+LARGE_INTEGER ByteOffset;
+
+#define MAXRESMOD 33
+
+/***ET+ mte_alloc - memory allocation for resident MTE section
+ *
+ * pe32 - Pointer to memory for resident MTE.
+ *
+ * The MTE consists of two parts the MTE pointers section and the table
+ * section. The pointer section is allocated in two parts the resident
+ * section and the swappable section. The table section of the mte is
+ * also allocated from the swappable heap.
+ *
+ * The first section of the pointer section allocated from the resident
+ * heap will also contain the module name and the pointers to the import
+ * modules.
+ * The second section of the pointer section is allocated from the swappable
+ * heap, also attached to this heap object will be the loader's table
+ * sections. The loader's table section will contain space for the pathname,
+ * object table, loader info and the fixup table.
+ *
+ *
+ * Memory resident object Resident heap object
+ * pe32->+----------------+ -+ Copy ->+----------------+<-pmte
+ * | Linker EXE info| |------------| | MTE pointers |
+ * +----------------+ -+ | ->|----------------|
+ * | | Module name |
+ * | +----------------+
+ * | |Space for Modptr|
+ * | +----------------+
+ * |
+ * | Swappable heap object
+ * | +----------------+<-psmte
+ * +-------->| MTE pointers |
+ * +----------------+
+ * |Space for pathnm|
+ * +----------------+
+ * | Object table |
+ * |or segment table|
+ * +----------------+
+ * | Export Section |
+ * +----------------+
+ * | Import Section |
+ * +----------------+
+ * | Fixup Records |
+ * +----------------+
+ */
+/*end*/
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: ldrCreateMte() was called\n");
+ }
+#endif
+
+ /*
+ * allocate memory for MTE from resident heap
+ */
+
+ /*
+ * Compute size of resident heap object to hold resident loader MTE.
+ * The size is madeup of:
+ * size of resident MTE struct
+ * 4 bytes * number of import module - to hold pointers to MTEs
+ * 9 bytes to hold max module name plus a null this will avoid
+ * the realloc needed because we do not know the length of the
+ * string till we read the rest of the header
+ */
+
+ /*
+ * Set import module count
+ */
+ cimpmod = (*(short *) (pe32->e32_magic) == LEMAGIC ?
+ ((pe32->e32_unit[IMP].size > 0) ?
+ (pe32->e32_unit[IMP].size / IMPHDR_SIZE) - 1 : 0) :
+ (ulong_t) ((struct new_exe *) pe32)->ne_cmod);
+ if ((pmte = (ldrmte_t *) RtlAllocateHeap(LDRNEHeap, HEAP_ZERO_MEMORY, sizeof(ldrmte_t)
+ + (4 * cimpmod) + MAXRESMOD)) == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto createerror;
+ }
+
+ /*
+ * Copy fields from the Linker EXE image to the loader MTE allocated
+ * from the resident heap.
+ */
+ pdst = (ulong_t *) pmte;
+
+ for(i = 0; ExeToResMTETbl[i].offset != ENDMTETBL; i++) {
+
+ if (ExeToResMTETbl[i].offset == (USHORT) SKIPCOPY)
+ *pdst++ = 0;
+ else {
+ /*
+ * fetch word value from 16-bit linker EXE image and place in
+ * loader mte
+ */
+ *pdst++ = *(ulong_t *) ((ulong_t) pe32 +
+ (ulong_t) ExeToResMTETbl[i].offset);
+ }
+ }
+
+ /*
+ * Setup fields in resident MTE
+ */
+
+ pmte->mte_usecnt = 0; /* clear out e32_bworder */
+ pmte->mte_dldchain = NULL;
+
+ /*
+ * Initialize MTE Flags
+ */
+ pmte->mte_mflags |= plv->lv_class;
+ if (plv->lv_type == EXT_DEVICE) /* is this a device driver module? */
+ pmte->mte_mflags |= DEVDRVMOD;
+ else if (plv->lv_type == EXT_FSD) { /* or is it an FSD module */
+ pmte->mte_mflags |= FSDMOD;
+
+ /*
+ * force all segments to swappable
+ */
+ pmte->mte_mflags &= ~MTE_MEDIAFIXED;
+ }
+
+ pmte->mte_mflags &= ~MTE_INTNL_MASK; /* Clear internal flags */
+
+ /*
+ * allocate memory for swappable heap object for loader tables
+ */
+
+ /*
+ * Round pathname up to a Dword
+ */
+ cbpathlen = ((strlen(LdrBuf) + 4) & ~3);
+
+ /*
+ * compute size of swappable heap object which is madeup of the
+ * swappable MTE pointers, the pathname, import, export and fixup
+ * sections.
+ */
+ if (ldrIsLE(pmte)) {
+ cpad = 0;
+ csmte = pe32->e32_hdrsize - (plv->lv_new_exe_off +
+ sizeof(struct e32_exe));
+ if (pe32->e32_unit[RES].rva != 0) {
+ cbrsrc = pe32->e32_unit[RES].size +
+ (pe32->e32_rescnt * sizeof(ldrrsrc32_t));
+ csmte += cbrsrc;
+ }
+ }
+ else {
+ /*
+ * Compute size of 16-bit loader tables also add space for
+ * expanded segment table for 16-bit modules
+ */
+ cpad = ((struct new_exe *)pe32)->ne_cseg * (sizeof(ldrste_t) -
+ sizeof(struct new_seg));
+ csmte = (ulong_t) (((struct new_exe *) pe32)->ne_cbenttab +
+ (((struct new_exe *) pe32)->ne_enttab -
+ sizeof(struct new_exe))) + cpad;
+
+ }
+ csmte += sizeof(ldrsmte_t) + cbpathlen;
+
+ /*
+ * allocate memory for swappable MTE from swappable heap
+ */
+ if ((psmte = (ldrsmte_t *) RtlAllocateHeap(LDRNEHeap, HEAP_ZERO_MEMORY, csmte)) == 0) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ goto createerror;
+ }
+
+ /*
+ * Copy fields from the Linker EXE image to the loader swappable MTE
+ * pointers.
+ */
+ pdst = (ulong_t *) psmte;
+
+ if (ldrIsLE(pmte)) {
+
+ for (i = 0; ExeTo32SwapMTETbl[i].offset != ENDMTETBL; i++) {
+
+ if (ExeTo32SwapMTETbl[i].offset == (USHORT) SKIPCOPY)
+ *pdst++ = 0;
+ else {
+ /*
+ * fetch value from linker EXE image and place in loader
+ * mte
+ */
+ *pdst++ = *(ulong_t *) ((ulong_t) pe32 +
+ (ulong_t) ExeTo32SwapMTETbl[i].offset);
+ }
+ }
+ }
+ else {
+ for (i = 0; ExeTo16SwapMTETbl[i].offset != ENDMTETBL; i++) {
+
+ if (ExeTo16SwapMTETbl[i].offset == (USHORT) SKIPCOPY)
+ *pdst++ = 0;
+ else {
+ /*
+ * fetch value from linker EXE image and place in loader
+ * mte
+ */
+ *pdst++ = (*(ulong_t *) ((ulong_t) pe32 +
+ (ulong_t) ExeTo16SwapMTETbl[i].offset)) &
+ WORDMASK;
+ }
+ }
+ psmte->smte_cbnrestab = ((struct new_exe *)pe32)->ne_cbnrestab;
+ psmte->smte_NEflagsothers =
+ ((struct new_exe *)pe32)->ne_flagsothers;
+ psmte->smte_NEexpver =
+ (USHORT) (((struct new_exe *)pe32)->ne_res[6]);
+ }
+ pmte->mte_swapmte = psmte;
+
+/*
+ * Read the data into the swappable part of the MTE which contains the
+ * object table, Export section and Import section.
+ *
+ *
+ * Swappable heap object
+ * +----------------+<-psmte
+ * | MTE pointers |
+ * |----------------|
+ * |Space for pathnm|
+ * --->|----------------|
+ * cpad-->| | 16-bit pad for |
+ * | | expand for seg |
+ * | | table |
+ * --->|----------------|<-start read here
+ * | Object table |
+ * | or segment tbl|
+ * |----------------|
+ * | Export Section |
+ * |----------------|
+ * | Import Section |
+ * |----------------|
+ * | Fixup records |
+ * +----------------+
+ */
+
+ lconstant = (ulong_t) psmte + sizeof(ldrsmte_t) + cpad + cbpathlen;
+ ByteOffset.LowPart = ldrIsNE(pmte) ? psmte->smte_objtab +
+ plv->lv_new_exe_off :
+ psmte->smte_objtab;
+ ByteOffset.HighPart = 0;
+
+ if ((rc = NtReadFile( plv->lv_sfn,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ (PCHAR) lconstant,
+ csmte - (sizeof(ldrsmte_t)+cbpathlen) - cpad -
+ cbrsrc,
+ &ByteOffset,
+ 0 )) != 0) {
+ rc = Or2MapNtStatusToOs2Error(rc, ERROR_ACCESS_DENIED);
+ goto createerror;
+ }
+
+ /*
+ * An adjustment constant has to be added to pointers in MTE. The
+ * pointers in MTE are relative to the beginning of the MTE header.
+ * Since space has been added between the header and the tables,
+ * the pointers need to be updated by a constant.
+ */
+ mte_16_32_constant = lconstant - psmte->smte_objtab;
+
+ psmte->smte_objtab = lconstant - cpad;
+
+ /*
+ * check that ptrs in MTE are valid
+ */
+ if ((rc = ldrMTEValidatePtrs(pmte, csmte + (ulong_t) psmte,
+ mte_16_32_constant)) != NO_ERROR) {
+ goto createerror;
+ }
+
+ if (cbrsrc != 0) {
+ /*
+ * Set first dword of space used to convert resource table
+ * to ENDMTETBL to indicate that the table has not been
+ * converted. The table will be convert for each module
+ * when the first resource is gotten.
+ */
+ psmte->smte_rsrccnt = pe32->e32_rescnt;
+ psmte->smte_rsrctab = (ulong_t) psmte + (csmte - cbrsrc);
+ prsrcinfo = (ldrrsrcinfo_t *) psmte->smte_rsrctab;
+ prsrcinfo->ldrrsrcinfo_flag = ENDMTETBL;
+
+ /*
+ * Also save the resource directory size and pote and the
+ * size of the iat and object page map.
+ */
+ prsrcinfo->ldrrsrcinfo_size = pe32->e32_unit[RES].size;
+ prsrcinfo->ldrrsrcinfo_iatsize = csmte - cbrsrc;
+ pote = (ldrote_t *) psmte->smte_objtab;
+ for (lobjnum = 0; lobjnum < psmte->smte_objcnt;lobjnum++,pote++) {
+ if (pe32->e32_unit[RES].rva >= pote->ote_base &&
+ pe32->e32_unit[RES].rva < pote->ote_base + pote->ote_psize)
+ break;
+ }
+ if (lobjnum == psmte->smte_objcnt) {
+ rc = ERROR_BAD_EXE_FORMAT;
+ }
+
+ prsrcinfo->ldrrsrcinfo_pote = (ulong_t) pote;
+
+ }
+
+ /*
+ * Reallocate resident heap space for MTE to include module name.
+ * We will copy the module entry in the export name table since this
+ * table is in the swappable heap. The module name for 32-bit modules
+ * is found by a pointer in the export directory table. For 16-bit
+ * modules it is the first entry in the resident name table
+ */
+ if (ldrIsLE(pmte)) {
+ pexp = (struct ExpHdr *) psmte->smte_expdir;
+ pac = (PCHAR) (psmte->smte_expdir + pexp->exp_dllname);
+ length = (UCHAR) (strlen(pac) + 1);
+ }
+ else {
+ pac = (PCHAR) psmte->smte_restab;
+ length = *((PCHAR) psmte->smte_restab) + (UCHAR) 1;
+ }
+ if (length > MAXRESMOD) {
+ rc = ERROR_BAD_FORMAT;
+ goto createerror;
+ }
+ plv->lv_pmte = pmte;
+
+ /*
+ * Setup import module pointer table
+ */
+ pmte->mte_modptrs = (ulong_t) ((PCHAR) pmte + sizeof(ldrmte_t));
+ pmte->mte_impmodcnt = cimpmod;
+ if (pmte->mte_impmodcnt > 0) {
+ memset((void *) pmte->mte_modptrs, '\0',
+ pmte->mte_impmodcnt << 2);
+ }
+
+ /*
+ * create a handle to use
+ */
+ if ((rc = Allocate16BHandle((PUSHORT) &hobmte,
+ (ULONG) pmte)) != NO_ERROR) {
+ goto createerror;
+ }
+
+ plv->lv_hobmte = pmte->mte_handle = hobmte;
+
+ pmte->mte_modname = (ULONG) pmte + sizeof(ldrmte_t) + (4 * cimpmod);
+
+ /*
+ * copy module name into resident MTE resident heap object for 32-bit
+ * modules place length byte before string.
+ */
+ memcpy((ldrIsLE(pmte) ? (PCHAR) pmte->mte_modname + 1 :
+ (PCHAR) pmte->mte_modname),
+ pac,
+ (ldrIsLE(pmte) ? length - 1 : length));
+
+ if (ldrIsLE(pmte))
+ *((PCHAR) pmte->mte_modname) = length - (uchar_t) 1;
+
+ /*
+ * upper case module name
+ */
+ ldrUCaseString((PCHAR) pmte->mte_modname + 1,
+ *((PCHAR) pmte->mte_modname));
+
+ /*
+ * Set size of pathname (not including terminating NUL).
+ */
+ cbpathlen =
+ psmte->smte_pathlen = (USHORT) strlen(LdrBuf);
+ cbpathlen++;
+
+ /*
+ * copy pathname from TempBuf into MTE
+ */
+ psmte->smte_path = (ulong_t) psmte + sizeof(ldrsmte_t);
+ memcpy((void *) psmte->smte_path, &LdrBuf, cbpathlen);
+
+ /*
+ * Upper case pathname
+ */
+ ldrUCaseString((PCHAR) psmte->smte_path, cbpathlen - 1);
+
+ if (ldrIsNE(pmte) ||
+ (plv->lv_type != EXT_PROGRAM && !(ldrIsLE(pmte)))) {
+ /*
+ * zero init call gate selector value in entry table for all
+ * objects.
+ */
+ if ((rc = ldrEachObjEntry(0, pmte, ldrInitEntry, 0)) != NO_ERROR){
+ goto createerror;
+ }
+ }
+
+ if (ldrIsNE(pmte)) {
+
+ /*
+ * Save size of swappable mte in mte_fpagetab so
+ * the debugger command .lm <addr> works for 16-bit modules
+ */
+ psmte->smte_fpagetab = csmte;
+
+ /*
+ * expand segments by adding a handle and selector field
+ * after each segment table entry
+ */
+ ldrExpandSegment(pmte, plv->lv_type);
+
+ /*
+ * Check for porthole modules
+ */
+ if ((psmte->smte_NEexetype == 2) || (psmte->smte_NEexetype == 0 &&
+ ((psmte->smte_NEexpver & 0xff00) == 0x200 ||
+ (psmte->smte_NEexpver & 0xff00) == 0x300)))
+ pmte->mte_mflags |= MTEPORTHOLE;
+ else
+ pmte->mte_mflags &= ~MTEPORTHOLE;
+
+ /*
+ * check for program modules
+ */
+ if (plv->lv_type == EXT_PROGRAM) {
+
+ /*
+ * Validate start segment
+ */
+ if (psmte->smte_startobj == 0 ||
+ ldrNumToSte(pmte, psmte->smte_startobj) == 0) {
+ rc = ERROR_INVALID_STARTING_CODESEG;
+ goto createerror;
+ }
+
+ /*
+ * Validate stack segment
+ */
+ if (psmte->smte_stackobj == 0 ||
+ (pste = ldrNumToSte(pmte, psmte->smte_stackobj)) == 0 ||
+ pste->ste_flags & STE_SHARED) {
+ rc = ERROR_INVALID_STACKSEG;
+ goto createerror;
+ }
+
+ /*
+ * Validate auto data segment
+ */
+ if (psmte->smte_autods != 0 &&
+ ldrNumToSte(pmte, psmte->smte_autods) == 0) {
+ rc = ERROR_INVALID_STARTING_CODESEG;
+ goto createerror;
+ }
+
+ /*
+ * if SS = DS and SP = 0
+ */
+ if (psmte->smte_stackobj == psmte->smte_autods &&
+ psmte->smte_esp == 0) {
+
+ /*
+ * Set SP to top of auto data segment just below
+ * the additional heap
+ */
+ psmte->smte_esp = RESIZE64K(pste->ste_minsiz) +
+ psmte->smte_stacksize;
+ }
+
+ } /* end if for EXT_PROGRAM */
+ else if (psmte->smte_startobj == 0) {
+ /*
+ * DLL has no init routine: mark it as global
+ * complete. This way libinit will not bother about
+ * it. Also clear instance libinit bit as linker can
+ * turn this on even without an init routine; this
+ * should be an error, but is not for compatibility
+ * reasons.
+ */
+ pmte->mte_mflags |= GINISETUP | GINIDONE;
+ pmte->mte_mflags &= ~INSTLIBINIT;
+ }
+ else {
+ /*
+ * if SS = DS and SP = 0 (this is a dll, so ignore the case
+ * where SS = DS = 0).
+ */
+ if (psmte->smte_stackobj == psmte->smte_autods &&
+ psmte->smte_stackobj != 0 &&
+ psmte->smte_esp == 0) {
+
+ /*
+ * Validate stack segment
+ */
+ if ((pste = ldrNumToSte(pmte, psmte->smte_stackobj)) == 0 ||
+ pste->ste_flags & STE_SHARED) {
+ rc = ERROR_INVALID_STACKSEG;
+ goto createerror;
+ }
+
+ /*
+ * Set SP to top of auto data segment just below
+ * the additional heap
+ */
+ psmte->smte_esp = RESIZE64K(pste->ste_minsiz) +
+ psmte->smte_stacksize;
+ }
+ }
+ } /* end if for NE module */
+ else { /* 32-bit module */
+
+ struct FmtDir *pfmtdir;
+ struct ComDir *pcomdir;
+
+ /*
+ * Make sure that pointers are zero if size in header is zero
+ */
+ if ((pe32->e32_unit[EXP].size == 0 &&
+ psmte->smte_expdir != 0) ||
+ (pe32->e32_unit[IMP].size == 0 && psmte->smte_impdir != 0) ||
+ (pe32->e32_unit[RES].size == 0 && psmte->smte_rsrctab != 0) ||
+ (pe32->e32_unit[FIX].size == 0 && psmte->smte_fixtab != 0) ||
+ (pe32->e32_unit[DEB].size == 0 &&
+ psmte->smte_debuginfo != 0)) {
+ rc = ERROR_BAD_EXE_FORMAT;
+ goto createerror;
+ }
+
+ psmte->smte_fixupsize = pe32->e32_unit[FIX].size;
+
+ /*
+ * Check for wild pointers in names ptr table
+ */
+ for (lcount = 0; lcount < pexp->exp_namecnt; lcount++) {
+ pac = (uchar_t *) (*(ulong_t *)
+ (pexp->exp_name + (lcount * sizeof(ulong_t)) +
+ (ulong_t) pexp) + (ulong_t) pexp);
+ lconstant = strlen(pac) + 1;
+ if (psmte + lconstant > psmte + csmte) {
+ rc = ERROR_BAD_EXE_FORMAT;
+ goto createerror;
+ }
+ }
+
+ pimpdir = (struct ImpHdr *) psmte->smte_impdir;
+
+ /*
+ * Remove info from module directives table:
+ * For module with 16-bit code get stack object & auto ds.
+ * Get count of resources for this module.
+ */
+ if (pe32->e32_dircnt != 0) {
+ pfmtdir = (struct FmtDir *) (pe32->e32_dirtab +
+ mte_16_32_constant);
+ for (lcount = 0; lcount < pe32->e32_dircnt; lcount++,
+ pfmtdir++) {
+
+ if ((ulong_t) pfmtdir >
+ psmte->smte_objtab + csmte) {
+ rc = ERROR_BAD_EXE_FORMAT;
+ }
+
+ switch (pfmtdir->dir) {
+
+ case OS2LDR16:
+ if (pfmtdir->length != sizeof(struct ComDir)) {
+ rc = ERROR_BAD_EXE_FORMAT;
+ goto createerror;
+ }
+ pcomdir = (struct ComDir *) (pe32->e32_dirtab +
+ mte_16_32_constant +
+ pfmtdir->offset);
+ if ((ulong_t) pcomdir >
+ psmte->smte_objtab + csmte) {
+ rc = ERROR_BAD_EXE_FORMAT;
+ goto createerror;
+ }
+ psmte->smte_autods = pcomdir->autods;
+ psmte->smte_stackobj = pcomdir->stackobj;
+ break;
+
+// LTS - 1/16/91
+// Moved count back to header
+
+ case OS2RSRCNT:
+// prsrccnt = (ulong_t *) (pe32->e32_dirtab +
+// mte_16_32_constant +
+// pfmtdir->offset);
+// if ((ulong_t) prsrccnt >
+// psmte->smte_objtab + csmte) {
+// rc = ERROR_BAD_EXE_FORMAT;
+// goto createerror;
+// }
+ break;
+
+ case OS2FIXMAP:
+ psmte->smte_fpagetab = pfmtdir->offset +
+ pe32->e32_dirtab +
+ mte_16_32_constant;
+ psmte->smte_mpages = pfmtdir->length /
+ sizeof(ulong_t);
+ for (lfixtab = 0; lfixtab < psmte->smte_mpages;
+ lfixtab++) {
+ lsize =
+ ((ulong_t *) psmte->smte_fpagetab)[lfixtab];
+ /*
+ * check if any fixups exist
+ */
+ if (lsize == 0xffffffff)
+ continue;
+ lsize += psmte->smte_fixtab;
+ if (lsize > psmte->smte_fixtab +
+ pe32->e32_unit[FIX].size) {
+ rc = ERROR_BAD_EXE_FORMAT;
+ goto createerror;
+ }
+ else {
+ ((ulong_t *) psmte->smte_fpagetab)[lfixtab] =
+ lsize;
+ }
+ }
+ break;
+
+ default:
+ rc = ERROR_BAD_EXE_FORMAT;
+ goto createerror;
+ }
+ }
+ }
+
+ if (plv->lv_type == EXT_PROGRAM) {
+
+ /*
+ * Init call gate value for Exec's
+ */
+ ldrInitCallGate = 0;
+ /*
+ * Validate stack
+ */
+ if (psmte->smte_stackobj <= psmte->smte_objcnt) {
+ pote =
+ &((ldrote_t *)psmte->smte_objtab)[psmte->smte_stackobj-1];
+ pote->ote_vsize += psmte->smte_stackinit;
+ }
+ else {
+ rc = ERROR_INVALID_STACKSEG;
+ goto createerror;
+ }
+
+ /*
+ * Validate starting code object
+ */
+ if (psmte->smte_eip == 0) {
+ rc = ERROR_INVALID_STARTING_CODESEG;
+ goto createerror;
+ }
+ }
+ else { /* Else some flavor of DLL */
+ /*
+ * For 32-bit DLLs, fail the load if
+ *
+ * A. The specified starting address is bad, or
+ * B. no starting object is specified, but either
+ * instance DLL initialization or instance DLL
+ * termination is requested, or
+ * C. instance DLL termination is requested, but the
+ * the starting object is 16-bit.
+ */
+ pote = (ldrote_t *) psmte->smte_objtab;
+ for (lobjnum = 0; lobjnum < psmte->smte_objcnt; lobjnum++,
+ pote++) {
+
+ if ((psmte->smte_eip > pote->ote_base) &&
+ (psmte->smte_eip < (pote->ote_base + pote->ote_psize)))
+ break;
+ if (lobjnum == psmte->smte_objcnt) {
+ rc = ERROR_INVALID_STARTING_CODESEG;
+ goto createerror;
+ }
+ }
+
+ if ((psmte->smte_eip == 0 &&
+ (pmte->mte_mflags & (MTEDLLTERM | INSTLIBINIT))) ||
+ ((pmte->mte_mflags & MTEDLLTERM) &&
+ !(pote->ote_flags & OBJ_BIGDEF))) {
+ rc = ERROR_INVALID_STARTING_CODESEG;
+ goto createerror;
+ }
+ if (psmte->smte_eip == 0)
+ pmte->mte_mflags |= GINISETUP | GINIDONE;
+ /* Fake global initialization done */
+ }
+ }
+
+ /*
+ * Check each segment or object in module
+ */
+ for (lobjnum = 0; lobjnum < psmte->smte_objcnt; lobjnum++) {
+
+ if (ldrIsNE(pmte)) {
+ pste = &((ldrste_t *) psmte->smte_objtab)[lobjnum];
+
+ /*
+ * Check that the amount of data in the file does
+ * not exceed the size of the segment.
+ */
+ if ((cbseg = pste->ste_minsiz) == 0)
+ cbseg = _64K; /* Get size of segment */
+ if ((cbfile = pste->ste_size) == 0 && pste->ste_offset != 0)
+ cbfile = _64K; /* Get amount of data in file */
+ if (cbfile > cbseg) {
+ /* Error if file size > segment size */
+ rc = ERROR_INVALID_MINALLOCSIZE;
+ goto createerror;
+ }
+
+ /*
+ * Check for auto data segment. If found, add in stack
+ * and heap sizes and store in ste entry and check for
+ * overflow
+ */
+ if (lobjnum + 1 == psmte->smte_autods) {
+ if ((cbseg += psmte->smte_heapsize +
+ psmte->smte_stacksize) > _64K) {
+ rc = ERROR_AUTODATASEG_EXCEEDS_64k;
+ goto createerror;
+ }
+ }
+ pste->ste_minsiz = (USHORT) cbseg;
+ }
+ /* 32-bit module */
+ else {
+ pote = &((ldrote_t *) psmte->smte_objtab)[lobjnum];
+
+ /*
+ * Check if IAT in this object
+ */
+ if (pimpdir != NULL &&
+ pimpdir->imp_address >= pote->ote_base &&
+ pimpdir->imp_address < pote->ote_base + pote->ote_psize) {
+
+ /*
+ * Save object table pointer to iat
+ */
+ poteiat = pote;
+ }
+
+ /*
+ * Check for auto data object. If found, add heap size
+ * to virtual size of object. If virtual size > 64k
+ * and this is USE16 object goto error.
+ */
+ if (lobjnum + 1 == psmte->smte_autods &&
+ (pote->ote_vsize += psmte->smte_heapsize) > _64K &&
+ !(pote->ote_flags & OBJ_BIGDEF)) {
+ rc = ERROR_AUTODATASEG_EXCEEDS_64k;
+ goto createerror;
+ }
+
+ /*
+ * 1/24/91 - LTS
+ * If we are to preload resources set the object flag
+ * preload. This only has meaning for resources not
+ * for any other objects.
+ */
+ if (pote->ote_flags & OBJ_RSRC) {
+ if (!(pmte->mte_mflags & MTE_MEDIAFIXED))
+ pote->ote_flags |= OBJ_PRELOAD;
+ }
+
+ if (!(pote->ote_flags & OBJ_DEBUG)) {
+ vsize += ((pote->ote_vsize + (_64K - 1)) / _64K) * _64K;
+ cpages += (pote->ote_vsize + PAGEMASK) / PAGESIZE;
+ }
+
+ if (pote->ote_flags & OBJ_DEBUG) {
+ pote->ote_base =
+ pote->ote_selector =
+ pote->ote_handle = 0;
+ }
+
+ /*
+ * Clear bit in flags to use as allocation flag
+ */
+ pote->ote_flags &= ~OBJALLOC;
+
+ /*
+ * check that executable objects don't have write access also
+ */
+ if (pote->ote_flags & OBJ_EXEC &&
+ pote->ote_flags & OBJ_WRITE) {
+ rc = ERROR_BAD_EXE_FORMAT;
+ goto createerror;
+ }
+
+ /*
+ * if object readonly force it to be shared
+ */
+ if (!(pote->ote_flags & OBJ_WRITE))
+ pote->ote_flags |= OBJ_SHARED;
+ }
+ } /* end of for loop for each object */
+
+ if (ldrIsLE(pmte)) {
+
+ /*
+ * Compute size of IAT
+ */
+ if (poteiat != NULL) {
+
+ /*
+ * See if IAT exists already
+ */
+ if (!(pimpdir->imp_flags & HDRIAT)) {
+ if (poteiat->ote_vsize < poteiat->ote_psize)
+ cbiat = poteiat->ote_vsize;
+ else
+ cbiat = poteiat->ote_psize;
+ cbiat -= pimpdir->imp_address - poteiat->ote_base;
+
+// if ((rc = VMAllocKHB(VM_HKH_PUB_SWAPRW,
+// cbiat,
+// (VMHOB) LDRMTEOWNER,
+// NA,
+// SSToDS(&piat))) != NO_ERROR) {
+// goto createerror;
+// }
+ psmte->smte_iat = (ulong_t) piat;
+
+ /*
+ * Read IAT if it exits
+ */
+// if ((rc=ldrRead(plv->lv_sfn,
+// poteiat->ote_pages +
+// (pimpdir->imp_address -
+// poteiat->ote_base),
+// (PCHAR) psmte->smte_iat,
+// NULL,
+// cbiat,
+// pmte)) != NO_ERROR) {
+// goto createerror;
+// }
+ }
+
+ if (pimpdir->imp_flags & HDRIAT) {
+ piat = (struct ImpHdr *) ((pimpdir->imp_reserved -
+ pe32->e32_objtab) +
+ psmte->smte_objtab);
+ psmte->smte_iat = (ulong_t) piat;
+ cbiat = pe32->e32_unit[FIX].rva - pimpdir->imp_reserved;
+ }
+
+ /*
+ * Update Import directory entries to point to the
+ * swappable heap copy of the IAT.
+ */
+ iataddr = pimpdir->imp_address;
+ for (lcount = 0; lcount < pmte->mte_impmodcnt; lcount++,
+ pimpdir++) {
+ /*
+ * Save imp_address in imp_ver for check if page
+ * that is being faulted contains iat
+ */
+ pimpdir->imp_ver = pimpdir->imp_address;
+ pimpdir->imp_address = (pimpdir->imp_address -
+ iataddr) + (ulong_t) piat;
+
+ /*
+ * Store in imp_flags field size of iat
+ */
+ if (lcount != 0) {
+ pprevimpdir->imp_flags = pimpdir->imp_address;
+ }
+ pprevimpdir = pimpdir;
+ }
+
+ /*
+ * Update size of last iat (imp_flags)
+ */
+ pimpdir--;
+ pdst = (ulong_t *) pimpdir->imp_address;
+ while ((*pdst != 0) &&
+ ((ulong_t) pdst < (ulong_t) piat + cbiat)) {
+ pdst++;
+ }
+ if ((ulong_t) pdst >= (ulong_t) piat + cbiat) {
+ rc = ERROR_BAD_EXE_FORMAT;
+ goto createerror;
+ }
+ /*
+ * Add one to size for terminator of directory
+ */
+ pdst++;
+ pimpdir->imp_flags = (ulong_t) pdst;
+ cbiat = (ulong_t) pdst - (ulong_t) piat;
+ psmte->smte_iatsize = cbiat;
+ }
+
+
+ /*
+ * reserve address space for dlls
+ */
+// if (pmte->mte_mflags & LIBRARYMOD && vsize > 0 &&
+// !(pmte->mte_mflags & (FSDMOD | DEVDRVMOD | VDDMOD))) {
+// pote = (ldrote_t *) psmte->smte_objtab;
+// ac.ac_va = pote->ote_base + psmte->smte_vbase;
+// if (ac.ac_va > SEL_512MEG - _64MEG) {
+// /*
+// * The address we are to reserve at is greater than
+// * the reserved space for DLLs. Set the address to zero
+// * so we will fail the first reserve and than we can
+// * reserve at any address.
+// */
+// ac.ac_va = 0;
+// }
+
+// /*
+// * Try to reserve address space for module at which it was
+// * linked at. If that fails allocate at any address.
+// */
+// fl = VMAC_ARENASHR | VMAC_ALIGNSEL | VMAC_PRERES |
+// VMAC_LOCSPECIFIC;
+// for (i = 0; i < 2; i++) {
+// if ((rc = VMReserveMem(vsize,
+// fl,
+// pPTDACur->ptda_handle,
+// NULL,
+// SSToDS(&ac))) == NO_ERROR)
+// break;
+
+// /*
+// * At this point we have failed to allocate at the address
+// * the linker assigned. Check to see if fixups have been
+// * removed. If they have fail to load this module.
+// */
+// if (pmte->mte_mflags & E32_NOINTFIX) {
+// rc = ERROR_BAD_EXE_FORMAT;
+// goto createerror;
+// }
+// fl &= ~VMAC_LOCSPECIFIC;
+// fl |= VMAC_LOCANY;
+// }
+// if (rc != NO_ERROR) {
+// goto createerror;
+// }
+// if ((vsize = ac.ac_va-pote->ote_base) != psmte->smte_vbase) {
+// psmte->smte_delta = ac.ac_va - (psmte->smte_vbase +
+// pote->ote_base);
+// psmte->smte_vbase = vsize;
+// }
+
+// }
+ }
+
+ /*
+ * Check if internal name for a LIBRARY matches the module name
+ * but not for porthole apps.
+ */
+ if ((plv->lv_type == EXT_LIBRARY) &&
+ !(pmte->mte_mflags & MTEPORTHOLE) &&
+ (rc = ldrCheckInternalName(pmte)) != NO_ERROR) {
+ goto createerror;
+ }
+
+ pmte->mte_sfn = plv->lv_sfn; /* save system file number in mte */
+
+// if (IOPLEnabled || (ldrChkIOPLTable(psmte) == NO_ERROR))
+// pmte->mte_mflags |= MTEIOPLALLOWED;
+
+ /*
+ * link mte in list of mtes
+ */
+ ldrLinkMTE(pmte);
+
+ pmte->mte_mflags |= MTEVALID;
+
+createerror:
+ if (rc != NO_ERROR) {
+ /*
+ * Check if Pseudo Handle allocated
+ */
+ if (hobmte != 0) {
+ Free16BHandle(hobmte);
+ }
+
+ /*
+ * check if swappable MTE allocated
+ */
+ if (psmte != NULL) {
+ /*
+ * check if page table, IAT and resource table allocated
+ */
+ if (ldrIsLE(pmte) && psmte->smte_fpagetab != 0)
+ RtlFreeHeap(LDRNEHeap, 0, (void *) psmte->smte_fpagetab);
+
+ RtlFreeHeap(LDRNEHeap, 0, (void *) psmte);
+ }
+
+ /*
+ * check if resident MTE allocated
+ */
+ if (pmte != NULL)
+ RtlFreeHeap(LDRNEHeap, 0, (void *) pmte);
+
+ }
+ return(rc);
+}
+
+
+/***LP ldrMTEValidatePtrs - Validate pointers in MTE table and update to new
+ * values
+ *
+ * Check for any wild pointers in MTE before converting to new
+ * value.
+ *
+ * ENTRY pmte - pointer to loader MTE
+ * limit - max value any ptrs may be
+ * constant - value to update pointers by
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ */
+
+int ldrMTEValidatePtrs(pmte, limit, constant)
+ldrmte_t *pmte; /* pointer to loader MTE */
+ULONG limit;
+ULONG constant;
+{
+ ldrsmte_t *psmte;
+ register PULONG p;
+ register unsigned int i;
+
+ psmte = pmte->mte_swapmte;
+
+ /*
+ * do for each entry in MTE found in validatetbl
+ */
+
+ for (i = 0; validatetbl[i] != ENDMTETBL; i++) {
+
+ /*
+ * Since the resource table is no longer part of the
+ * header for a 32-bit module do not validate it.
+ */
+ if (ldrIsLE(pmte) && i == rsrcvalidatetbl)
+ continue;
+ /*
+ * point to entry in exe image
+ */
+ (PCHAR ) p = ((PCHAR ) psmte + validatetbl[i]);
+
+ /*
+ * check if pointer valid, non-zero
+ */
+ if (*p != 0)
+ /*
+ * range check and add constant to value at pointer
+ */
+ if ((*p += constant) > limit)
+ return(ERROR_BAD_EXE_FORMAT);
+ }
+ return(NO_ERROR);
+}
+
+
+/***LP ldrExpandSegment - expand segments in place
+ *
+ * copy each segment table entry from pointer at psrc to
+ * pmte->mte_objtab, the region starting immediately after the space for
+ * pathname, and expand each entry by adding two bytes for the segment
+ * handle and 4 bytes for the linear address of the segment
+ *
+ * ENTRY pmte - pointer to mte
+ * type - module type
+ *
+ * EXIT none - segments expanded
+ */
+
+void ldrExpandSegment(pmte, type)
+ldrmte_t *pmte; /* pointer to module table entry */
+UCHAR type; /* module type */
+{
+ register ldrste_t *psrc; /* pointer to source */
+ register ldrste_t *pdst; /* pointer to destination */
+ register int i; /* count of segments */
+ ldrsmte_t *psmte; /* pointer to swappable mte */
+ ulong_t ldrccodeseg = 0;/* count of seg that can be packed */
+ ulong_t ldrcsegpack = 0;/* running size of packed segs */
+
+ psmte = pmte->mte_swapmte;
+ pdst = (ldrste_t *) psmte->smte_objtab;
+
+ psrc = (ldrste_t *) (psmte->smte_objtab + (psmte->smte_objcnt *
+ (sizeof(ldrste_t) - sizeof(struct new_seg))));
+
+ /* loop for all STEs */
+ for (i = 0; pdst != psrc; i++, ((struct new_seg *) psrc)++, pdst++) {
+
+ /*
+ * Make sure the following flags are cleared:
+ */
+ psrc->ste_flags &= ~(STE_PACKED | STE_SEMAPHORE | STE_SELALLOC |
+ STE_HUGE | STE_WAITING);
+
+ if ((type == EXT_DEVICE)) {
+ /*
+ * For a device driver module.
+ * If it is a first or the second segment, set the GDTSEG flag.
+ * If the segment is ring 2 segment (IOPL), set the GDTSEG flag.
+ */
+ if (i >= 2) {
+ if ((psrc->ste_flags & STE_SEGDPL) == STE_RING_2)
+ psrc->ste_flags |= STE_GDTSEG;
+ }
+ else
+ psrc->ste_flags |= STE_GDTSEG;
+ }
+
+ if ((type == EXT_DEVICE) || (type == EXT_FSD)) {
+ /*
+ * This is an FSD/DD module. We need to force the seg's to be
+ * movable, preloaded and have DPL = 3(because the init routine
+ * will run in ring 3). These segments cannot be shared, cannot
+ * be conforming and cannot be discarded.
+ */
+ psrc->ste_flags |= (STE_PRELOAD | STE_RING_3);
+ psrc->ste_flags &= ~(STE_SHARED | STE_CONFORM);
+ }
+
+ /*
+ * if swapping is not on or loading from removable media
+ * force preloading of segment
+ */
+ if (!(pmte->mte_mflags & MTE_MEDIAFIXED))
+ psrc->ste_flags |= STE_PRELOAD;
+
+ /*
+ * if readonly, force segment to be shared
+ */
+ if (psrc->ste_flags & STE_ERONLY)
+ psrc->ste_flags |= STE_SHARED;
+
+ /*
+ * if this is a code segment, force it to be shared
+ */
+ else if ((psrc->ste_flags & STE_TYPE_MASK) == STE_CODE) {
+ psrc->ste_flags |= STE_SHARED;
+ ldrccodeseg++;
+ }
+
+ /*
+ * Set Pageable bit:
+ * If read-only data and fixed media, then it is pageable
+ */
+ if (((psrc->ste_flags & STE_DATA) &&
+ !(psrc->ste_flags & STE_ERONLY)) ||
+ !(pmte->mte_mflags & MTE_MEDIAFIXED))
+ psrc->ste_flags &= ~STE_PAGEABLE;
+ else
+ psrc->ste_flags |= STE_PAGEABLE;
+
+ /*
+ * copy ste to final destination
+ */
+
+ *(struct new_seg *) pdst = *(struct new_seg *) psrc;
+
+ /*
+ * initialize segment handle and selector to zero
+ */
+ pdst->ste_selector = 0;
+ pdst->ste_seghdl = 0;
+
+ /*
+ * initialize segment fixup table to null
+ */
+ pdst->ste_fixups = 0;
+ }
+
+ /*
+ * Check if we can pack the segments
+ */
+ if (type == EXT_PROGRAM && ldrccodeseg > MINSEGPACKCNT) {
+ pdst = (ldrste_t *) psmte->smte_objtab;
+ ldrccodeseg = 0;
+ for (i = 0; i < (int) psmte->smte_objcnt; i++, pdst++) {
+
+ ulong_t minsiz_l = RESIZE64K(pdst->ste_minsiz);
+
+ if ((pdst->ste_flags & STE_TYPE_MASK) == STE_CODE &&
+ ((USHORT)(pdst->ste_minsiz % (USHORT) PAGEMASK) <
+ (USHORT) MINPGPACKSIZE) &&
+ minsiz_l < MAXSEGPACKSIZE) {
+ ldrccodeseg++;
+ pdst->ste_flags |= STE_PACKED;
+ pdst->ste_flags &= ~STE_PRESENT;
+ pdst->ste_minsiz = (pdst->ste_minsiz + (USHORT) 3) &
+ (USHORT) ~3;
+ ldrcsegpack += minsiz_l;
+ }
+ }
+ psmte->smte_csegpack = ldrccodeseg;
+ psmte->smte_ssegpack = ldrcsegpack;
+ }
+
+}
+
+
+/***LP ldrCheckInternalName - Check if internal name of a library matches
+ * its module name
+ *
+ * ENTRY pmte pointer to its MTE
+ * File name assumed to be in pPTDACur->ptda_pLdrBuf
+ *
+ * EFFECTS The internal name is changed to Upper Case and NULL terminated
+ *
+ * EXIT NO_ERROR name matches
+ * ERROR_INVALID_NAME mismatch
+ */
+int ldrCheckInternalName(pmte)
+register ldrmte_t *pmte;
+{
+ PUCHAR pchintname; /* pointer to internal name */
+ USHORT cchintname; /* length of internal name */
+ PCHAR pchmodname; /* pointer to module name */
+ USHORT cchmodname; /* length of module name */
+ PCHAR ptemp;
+ PCHAR ptemp2;
+ USHORT count;
+
+ pchintname = (PCHAR) pmte->mte_modname;
+ cchintname = *pchintname++; /* length of internal name */
+
+ /*
+ * For library modules, the internal name must match the name
+ * by which the module is being loaded. We extract the name from
+ * the fully qualified name in LdrBuf for comparison.
+ */
+ if (pmte->mte_mflags & LIBRARYMOD) {
+ ptemp = LdrBuf;
+ while (ptemp != NULL) {
+ pchmodname = ptemp;
+ ptemp = strpbrk(ptemp, "\\/");
+ if (ptemp != NULL) {
+ ptemp++;
+ }
+ }
+ ptemp = strchr(pchmodname, '.');
+ if (ptemp == NULL) {
+ ptemp = strchr(pchmodname, '\0');
+ }
+ cchmodname = (USHORT) (ptemp - pchmodname);
+ if (cchintname != cchmodname) {
+ return(ERROR_INVALID_NAME);
+ }
+
+ count = cchmodname;
+ ptemp = pchmodname;
+ ptemp2 = pchintname;
+#ifdef DBCS
+// MSKK Apr.20.1993 V-AkihiS
+ while (count-- > 0) {
+ if (IsDBCSLeadByte(*ptemp)) {
+ ptemp++;
+ if (count > 0) {
+ count--;
+ ptemp++;
+ }
+ } else {
+ *ptemp = (CHAR) toupper(*(PUCHAR)ptemp);
+ ptemp++;
+ }
+ }
+ count = cchmodname;
+ while (count-- > 0) {
+ if (IsDBCSLeadByte(*ptemp2)) {
+ ptemp2++;
+ if (count > 0) {
+ count--;
+ ptemp2++;
+ }
+ } else {
+ *ptemp2 = (CHAR) toupper(*(PUCHAR)ptemp2);
+ ptemp2++;
+ }
+ }
+#else
+ while (count-- > 0) {
+ *ptemp = (CHAR) toupper(*(PUCHAR)ptemp);
+ ptemp++;
+ *ptemp2 = (CHAR) toupper(*(PUCHAR)ptemp2);
+ ptemp2++;
+ }
+#endif
+
+ if (strncmp(pchintname, pchmodname, cchintname) != 0) {
+ return(ERROR_INVALID_NAME);
+ }
+
+ }
+ return (NO_ERROR);
+}
+
+
+/***LP ldrChkLoadType - Check if module matches requested load type
+ *
+ * ENTRY lflags - flags
+ * plv - pointer to local variables
+ *
+ * EXIT none - return successful or call load_error
+ */
+
+void ldrChkLoadType(lflags, plv)
+ULONG lflags; /* module table entry flags */
+register ldrlv_t *plv; /* pointer to local variables */
+{
+ if (!((plv->lv_type != EXT_PROGRAM) ^ (!(lflags & LIBRARYMOD)))) {
+ if (plv->lv_sfn != 0)
+ NtClose(plv->lv_sfn);
+ load_error(ERROR_INVALID_MODULETYPE, NULL);
+ }
+}
+
+
+/***LP ldrIsAttached - Check if process is already attached to module
+ *
+ * Check if the current (or child) process is attached to
+ * each of the objects in the given module.
+ *
+ * This procedure performs the following steps:
+ *
+ * for each segment (object) in the module,
+ * if shared,
+ * if (error from VMIsAttached)
+ * return (FALSE)
+ * else (it is private)
+ * if no handle maps the segment (object) address
+ * retun (FALSE)
+ * return (TRUE)
+ *
+ * ENTRY pmte - pointer to mte to check
+ *
+ * EXIT int
+ * FALSE - Process is not attached to module
+ * TRUE - Process is attached to module
+ *
+ */
+int ldrIsAttached(pmte)
+register ldrmte_t *pmte;
+{
+ ldrsmte_t *psmte; /* pointer to swappable mte */
+// ULONG objno;
+// VMHOB hptda;
+// VMHOB hob;
+ ULONG lnonrsrccnt;
+// register ldrote_t *pote;
+// register ldrste_t *pste;
+
+ psmte = pmte->mte_swapmte;
+ /*
+ * Do not process resource objects for 16-bit modules
+ */
+ if (ldrIsNE(pmte))
+ lnonrsrccnt = psmte->smte_objcnt - psmte->smte_rsrccnt;
+ else
+ lnonrsrccnt = psmte->smte_objcnt;
+
+ /*
+ * If there are no non-resource objects, then we must
+ * say we are not attached, since this may be a forwarder
+ * module, and we need to process its list of static
+ * links.
+ */
+ if (lnonrsrccnt == 0)
+ return(FALSE);
+
+// (ULONG) pste = (ULONG) pote = psmte->smte_objtab;
+// for (objno = 0; objno < lnonrsrccnt; objno++, pote++, pste++) {
+
+ /*
+ * skip resource objects for 32-bit modules
+ */
+// if (ldrIsLE(pmte) && pote->ote_flags & (OBJ_RSRC | OBJ_DEBUG))
+// continue;
+
+ /*
+ * get handle from object or segment table
+ */
+// if (ldrIsNE(pmte)) {
+// if (pste-> ste_flags & STE_SHARED) {
+// if (pste->ste_seghdl == HOBNULL)
+// return(FALSE);
+// if (VMIsAttached((VMHOB)pste->ste_seghdl,hptda) != NO_ERROR)
+// return(FALSE);
+// }
+// else if (VMGetHandle(SelToLaTiled(pste->ste_selector), hptda,
+// SSToDS (&hob)) != NO_ERROR)
+// return (FALSE);
+// }
+// else {
+// if (pote-> ote_flags & OBJ_SHARED) {
+// if (pote->ote_handle == HOBNULL)
+// return(FALSE);
+// if (VMIsAttached((VMHOB)pote->ote_handle,hptda) != NO_ERROR)
+// return(FALSE);
+// }
+// else if (VMGetHandle(pote->ote_base, hptda,
+// SSToDS (&hob)) != NO_ERROR)
+// return (FALSE);
+// }
+// }
+ return(TRUE);
+}
+
+
+/***LP ldrWriteErrTxt - write error message into user's message buffer
+ *
+ * This procedure preforms the following steps:
+ *
+ * - if user supplied buffer zero error message will not be setup
+ * - else copy module name into user suppiled buffer
+ * - if errcode = ERROR_PROC_NOT_FOUND copy procedure name
+ * to user buffer
+ *
+ * ENTRY errcode - loader error code
+ * pmte - pointer to module table entry
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ * - else ERROR_PROTECTION_VIOLATION
+ *
+ * EFFECTS error message copied into user's message buffer
+ */
+
+VOID
+ldrWriteErrTxt( errcode )
+int errcode; /* loader error code */
+{
+ int rc = NO_ERROR;
+ USHORT cnt;
+ USHORT BufferLen;
+ char ordbuf[20]; // Buffer to translate ordinal number
+ char *pordbuf;
+ PSZ pstring;
+
+ pstring = pErrText->Buffer;
+ BufferLen = pErrText->MaximumLength - 1;
+ if ((pstring == NULL) || (BufferLen == 0)) {
+ return;
+ }
+
+ /*
+ * Check if module name setup by ldrSetupSrcErrTxt. If so use that
+ * module else check the MTE passed.
+ */
+ cnt = ldrSrcModNameBufL;
+ if (cnt != 0) {
+ if (cnt > BufferLen)
+ cnt = BufferLen;
+ RtlMoveMemory(pstring, ldrSrcModNameBuf, (ULONG) cnt);
+ pstring += (UCHAR) cnt;
+ BufferLen -= cnt;
+ }
+
+ if (ldrTgtModNameBufL != 0) {
+ /*
+ * First, place a '->' in the buffer to delimit the source
+ * and target module names. Protect against small buffers...
+ */
+ cnt = (USHORT) 2;
+ if (cnt > BufferLen)
+ cnt = BufferLen;
+ RtlMoveMemory(pstring, "->", (ULONG) cnt);
+ pstring += (UCHAR) cnt;
+ BufferLen -= cnt;
+ cnt = ldrTgtModNameBufL;
+ if (cnt > BufferLen)
+ cnt = BufferLen;
+ RtlMoveMemory(pstring, ldrTgtModNameBuf, (ULONG) cnt);
+ pstring += (UCHAR) cnt;
+ BufferLen -= cnt;
+ }
+
+ /*
+ * If errcode == ERROR_PROC_NOT_FOUND, then ldrProcNameBuf has
+ * the procedure name. Else if errocode == ERROR_INVALID_ORDINAL
+ * then ldrProcNameBuf has the ordinal.
+ */
+ if ((errcode == ERROR_PROC_NOT_FOUND)
+ || (errcode == ERROR_INVALID_ORDINAL)) {
+ /*
+ * First, place a '.' in the buffer to delimit the module
+ * and procedure names. Protect against small buffers...
+ */
+ cnt = 1;
+ if (cnt > BufferLen)
+ cnt = BufferLen;
+ RtlMoveMemory(pstring, ".", (ULONG) cnt);
+ pstring += (UCHAR) cnt;
+ BufferLen -= cnt;
+ if (errcode == ERROR_PROC_NOT_FOUND) {
+ cnt = ldrProcNameBufL;
+ if (cnt > BufferLen)
+ cnt = BufferLen;
+ RtlMoveMemory(pstring, ldrProcNameBuf, (ULONG) cnt);
+ pstring += (UCHAR) cnt;
+ BufferLen -= cnt;
+ }
+ else { /* errcode == ERROR_INVALID_ORDINAL */
+ pordbuf = _itoa((int) ldrProcNameBuf, ordbuf, 10);
+ cnt = (USHORT) strlen(pordbuf);
+ if (cnt > BufferLen)
+ cnt = BufferLen;
+ RtlMoveMemory(pstring, pordbuf, (ULONG) cnt);
+ pstring += (UCHAR) cnt;
+ BufferLen -= cnt;
+ }
+ }
+
+ pErrText->Length = (pErrText->MaximumLength - 1) - BufferLen;
+}
+
+#if PMNT
+
+BOOLEAN
+ldrSaveErrInfo( errcode )
+int errcode; /* loader error code */
+{
+
+ if (ldrSaveSrcModNameBufL=ldrSrcModNameBufL) {
+ if (!(ldrSaveSrcModNameBuf=
+ RtlAllocateHeap(LDRNEHeap, 0, ldrSrcModNameBufL))) {
+ KdPrint(("ldrSaveErrInfo() failed\n"));
+ return(FALSE);
+ }
+ strncpy(ldrSaveSrcModNameBuf,ldrSrcModNameBuf,ldrSrcModNameBufL);
+ }
+ if (ldrSaveTgtModNameBufL=ldrTgtModNameBufL) {
+ if (!(ldrSaveTgtModNameBuf=
+ RtlAllocateHeap(LDRNEHeap, 0, ldrTgtModNameBufL))){
+ KdPrint(("ldrSaveErrInfo() failed\n"));
+ return(FALSE);
+ }
+ strncpy(ldrSaveTgtModNameBuf,ldrTgtModNameBuf,ldrTgtModNameBufL);
+ }
+ if (errcode==ERROR_PROC_NOT_FOUND) {
+ if (ldrSaveProcNameBufL=ldrProcNameBufL) {
+ if (!(ldrSaveProcNameBuf=
+ RtlAllocateHeap(LDRNEHeap, 0, ldrProcNameBufL))) {
+ KdPrint(("ldrSaveErrInfo() failed\n"));
+ return(FALSE);
+ }
+ strncpy(ldrSaveProcNameBuf,ldrProcNameBuf,ldrProcNameBufL);
+ }
+ }
+ else {
+ ldrSaveProcNameBuf = ldrProcNameBuf;
+ }
+ ldrSaveRc = errcode;
+ return(TRUE);
+}
+
+VOID
+ldrRestoreErrInfo( errcode )
+int *errcode; /* loader error code */
+{
+
+ if (ldrSrcModNameBufL = ldrSaveSrcModNameBufL) {
+ ldrSrcModNameBuf = ldrSaveSrcModNameBuf;
+ }
+ if (ldrTgtModNameBufL = ldrSaveTgtModNameBufL) {
+ ldrTgtModNameBuf = ldrSaveTgtModNameBuf;
+ }
+ if (ldrSaveRc==ERROR_PROC_NOT_FOUND) {
+ ldrProcNameBufL = ldrSaveProcNameBufL;
+ }
+ ldrProcNameBuf = ldrSaveProcNameBuf;
+ *errcode = ldrSaveRc;
+}
+
+BOOLEAN
+ldrFreeErrInfo( )
+{
+ if (ldrSaveSrcModNameBuf) {
+ if (!(RtlFreeHeap(LDRNEHeap, 0, ldrSaveSrcModNameBuf))){
+ KdPrint(("ldrFreeErrInfo() failed\n"));
+ return(FALSE);
+ }
+ ldrSaveSrcModNameBuf=NULL;
+ }
+ if (ldrSaveTgtModNameBuf) {
+ if (!(RtlFreeHeap(LDRNEHeap, 0, ldrSaveTgtModNameBuf))){
+ KdPrint(("ldrFreeErrInfo() failed\n"));
+ return(FALSE);
+ }
+ ldrSaveTgtModNameBuf=NULL;
+ }
+ if (ldrSaveRc == ERROR_PROC_NOT_FOUND && ldrSaveProcNameBuf) {
+ if (!(RtlFreeHeap(LDRNEHeap, 0, ldrSaveProcNameBuf))){
+ KdPrint(("ldrFreeErrInfo() failed\n"));
+ return(FALSE);
+ }
+ ldrSaveProcNameBuf=NULL;
+ }
+ ldrSaveSrcModNameBufL = ldrSaveTgtModNameBufL = ldrSaveProcNameBufL= 0;
+ ldrSaveRc = 0;
+ return(TRUE);
+}
+
+#endif
+
+/***LP load_error - General error handler for new EXE load errors
+ *
+ * ENTRY errcode - load error code
+ * pmte - pointer to mte if it exists
+ *
+ * EXIT none
+ *
+ */
+
+void load_error(errcode, pmte)
+int errcode; /* load error code */
+ldrmte_t *pmte; /* pointer to module table entry */
+{
+ /*
+ * ldrOpen returns ERROR_OPEN_FAILED for non-existent files. This
+ * is incorrect with the definition of the error-code. It should
+ * be ERROR_FILE_NOT_FOUND instead
+ */
+
+ if (errcode == ERROR_OPEN_FAILED)
+ errcode = ERROR_FILE_NOT_FOUND;
+
+ ldrWriteErrTxt(errcode);
+}
+
+VOID ldrInvalidateDesc(
+ SEL Selector // selector to be invalidated
+ )
+{
+ PROCESS_LDT_INFORMATION LdtInfo;
+ NTSTATUS Status;
+
+ LdtInfo.Start = Selector & 0xfff8;
+ LdtInfo.Length = sizeof(LDT_ENTRY);
+
+ RtlZeroMemory(LdtInfo.LdtEntries, sizeof(LDT_ENTRY));
+
+ Status = NtSetInformationProcess( CurrentThread->Process->ProcessHandle,
+ ProcessLdtInformation,
+ &LdtInfo,
+ sizeof(PROCESS_LDT_INFORMATION)
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("ldrSetDescInfo: Invalid request\n");
+#endif
+ }
+}
+
+VOID
+ldrTagModuleTree(
+ ldrmte_t *pmte
+ )
+{
+ ldrmte_t **ppmte;
+ ULONG lindex;
+ ULONG i;
+
+ pmte->mte_mflags |= INGRAPH;
+
+ ppmte = (ldrmte_t **) pmte->mte_modptrs;
+ for (i = 1; i <= pmte->mte_impmodcnt; i++) {
+ /*
+ * It is required for 16-bit modules to load the
+ * referneced module in reverse order.
+ */
+ lindex = pmte->mte_impmodcnt-i;
+
+ //
+ // Check if the referenced module has already been processed.
+ // Processing the modules is done in reverse order.
+ //
+ if ((ppmte[lindex]->mte_mflags & INGRAPH) == 0) {
+ ldrTagModuleTree(ppmte[lindex]);
+ }
+ }
+}
+
+VOID
+ldrTagModuleTree_USED(
+ ldrmte_t *pmte
+ )
+{
+ ldrmte_t **ppmte;
+ ULONG lindex;
+ ULONG i;
+
+ pmte->mte_mflags |= INGRAPH | USED;
+
+ ppmte = (ldrmte_t **) pmte->mte_modptrs;
+ for (i = 1; i <= pmte->mte_impmodcnt; i++) {
+ /*
+ * It is required for 16-bit modules to load the
+ * referneced module in reverse order.
+ */
+ lindex = pmte->mte_impmodcnt-i;
+
+ //
+ // Check if the referenced module has already been processed.
+ // Processing the modules is done in reverse order.
+ //
+ if ((ppmte[lindex]->mte_mflags & INGRAPH) == 0) {
+ ldrTagModuleTree_USED(ppmte[lindex]);
+ }
+ }
+}
+
+BOOLEAN
+ldrUnloadTagedModules(
+ IN POS2_PROCESS Process
+)
+{
+ ldrmte_t *pmte;
+ ldrmte_t *ptmte;
+ ldrsmte_t *psmte;
+ ldrste_t *pste;
+ ULONG i;
+ NTSTATUS Status;
+ APIRET rc;
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: LDRUnloadTagedModules() was called\n");
+ }
+#endif
+
+ //
+ // Scan loaded module chain for referenced modules
+ //
+ pmte = mte_h;
+ while (pmte != NULL) {
+ //
+ // skip non tagged modules
+ //
+ if (((pmte->mte_mflags & INGRAPH) == 0) ||
+ ((pmte->mte_mflags & (USED | DOSMOD)) != 0)
+ ) {
+ pmte = pmte->mte_link;
+ continue;
+ }
+
+ //
+ // Handle the case where the first loaded app failed
+ // and DOSCALLS was loaded. Allow to release it.
+ //
+ if (((pmte->mte_mflags & DOSLIB) != 0) &&
+ (!DoscallsLoaded)
+ ) {
+ pmte->mte_usecnt--;
+ }
+
+ //
+ // Tagged modules are processed here
+ //
+
+ //
+ // Unmap the segments of the current module from the address
+ // space of the current process.
+ //
+ psmte = pmte->mte_swapmte;
+ pste = (ldrste_t *)psmte->smte_objtab;
+
+ for (i = 1; i <= psmte->smte_objcnt; i++, pste++) {
+ //
+ // If we are terminating an app then no need to unmap the
+ // sections from the address space of the terminating process.
+ // The section will be unmapped by themself.
+ // In fact, trying to unmap will return status of
+ // STATUS_PROCESS_IS_TERMINATING
+ if (fForceUnmap) {
+ Status = NtUnmapViewOfSection(
+ CurrentThread->Process->ProcessHandle,
+ (PVOID)SELTOFLAT(pste->ste_selector)
+ );
+ //
+ // Error while unmapping resources is acceptable since
+ // resources are not mapped when the module is loaded,
+ // but we need to try to unmap them in case they were
+ // loaded by DosGetResource().
+ //
+ if ((!NT_SUCCESS(Status)) &&
+ (i <= psmte->smte_objcnt - psmte->smte_rsrccnt)
+ ) {
+#if DBG
+ DbgPrint("OS2LDR: ldrUnloadModule(): Unable to unmap a segment form the app, Status=%x\n", Status);
+#endif
+ }
+ //
+ // Invalidate the descriptor of the unmapped section
+ //
+ ldrInvalidateDesc(pste->ste_selector);
+ }
+
+ //
+ // If this was the last module referencing this mte
+ // then close the section and its mappings
+ //
+ if ((pmte->mte_usecnt == 0) &&
+ (pste->ste_seghdl != (ulong_t)R2XferSegHandle)
+ ) {
+ Status = NtUnmapViewOfSection(
+ NtCurrentProcess(),
+ (PVOID)SELTOFLAT(pste->ste_selector)
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("OS2LDR: ldrUnloadModule(): Unable to self unmap a segment, Status=%x\n", Status);
+#endif
+ return(FALSE);
+ }
+ Status = NtClose((HANDLE)pste->ste_seghdl);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("OS2LDR: ldrUnloadModule(): Unable to close segment section, Status=%x\n", Status);
+#endif
+ return(FALSE);
+ }
+ //
+ // Check if the module has ring 2 segments which have entry points.
+ // If yes, delete the call gate entries
+ //
+ if (((pste->ste_flags & STE_SEGDPL) == STE_RING_2) && // ring 2 segment
+ ((pste->ste_flags & STE_DATA) == 0) && // code segment
+ ((pste->ste_flags & STE_CONFORM) == 0) // non conforming
+ ) {
+ ldrEachObjEntry(i, pmte, ldrFreeCallGate, NULL);
+ }
+ //
+ // Don't free the bit map entries of the DOSCALLS selectors
+ // as these were not allocated explicity
+ //
+ if ((pmte->mte_mflags & DOSLIB) == 0) {
+ ldrFreeSel(pste->ste_selector, 1);
+ }
+ }
+ }
+ ptmte = pmte;
+ pmte = pmte->mte_link;
+ //
+ // If this module is no more referenced, disconnect it from
+ // the MTE chain and free its allocated memory
+ //
+ if (ptmte->mte_usecnt == 0) {
+ if (ptmte->mte_sfn != NULL) {
+ NtClose(ptmte->mte_sfn);
+ }
+ rc = Free16BHandle(ptmte->mte_handle);
+ ASSERT(rc == NO_ERROR);
+ ldrUnlinkMTE(ptmte);
+ RtlFreeHeap(LDRNEHeap, 0, ptmte->mte_swapmte);
+ RtlFreeHeap(LDRNEHeap, 0, ptmte);
+ }
+ }
+}
+
+BOOLEAN
+LDRUnloadExe(
+ IN POS2_PROCESS Process
+ )
+{
+ //
+ // Unload the .EXE file
+ //
+
+ ldrmte_t *pmte;
+ ldrmte_t *ptmte;
+ ldrdld_t *pdld;
+ ldrdld_t *prev_pdld;
+ ldrdld_t *pcurdld;
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: LDRUnloadExe() called for NT process handle %x\n",
+ Process->ProcessHandle);
+ }
+#endif
+
+ pmte = (ldrmte_t *)Process->ProcessMTE;
+ if (pmte == NULL) {
+ return(TRUE);
+ }
+
+ //
+ // Set the fForceUnmap flag to FALSE so that ldrUnloadTagedModules()
+ // does not unmap the app's segments from the app's address space
+ // since the app is in a terminating satate
+ //
+ fForceUnmap = FALSE;
+
+ //
+ // Loop over the DLD chain.
+ // For Each entry, tag all referenced DLD modules with the INGRAPH flag
+ // The tagged modules will be then unloaded
+ //
+ pdld = pmte->mte_dldchain;
+ prev_pdld = (ldrdld_t *)&pmte->mte_dldchain;
+ while (pdld != NULL) {
+ if (pdld->Cookie == (ULONG)Process) {
+ //
+ // Clear the INGRAPH flag of all modules so that we
+ // know that this module has already been processed
+ //
+ ldrClearAllMteFlag(INGRAPH | USED);
+
+ ldrTagModuleTree(pdld->dld_mteptr);
+
+ //
+ // Remove the DLD entry
+ //
+ pcurdld = pdld;
+ pdld = pdld->dld_next;
+ prev_pdld->dld_next = pdld;
+ RtlFreeHeap(LDRNEHeap, 0, pcurdld);
+
+ //
+ // Decrement the usecnt of the marked modules
+ //
+ ptmte = mte_h;
+ while (ptmte != NULL) {
+ if ((ptmte->mte_mflags & INGRAPH) != 0) {
+ ptmte->mte_usecnt--;
+ }
+ ptmte = ptmte->mte_link;
+ }
+
+ ldrUnloadTagedModules(Process);
+ }
+ else {
+ prev_pdld = pdld;
+ pdld = pdld->dld_next;
+ }
+ }
+
+ //
+ // Clear the INGRAPH flag of all modules so that we
+ // know that this module has already been processed
+ //
+ ldrClearAllMteFlag(INGRAPH | USED);
+
+ //
+ // Tag all referenced modules with the INGRAPH flag
+ // The tagged modules will be then unloaded
+ //
+ ldrTagModuleTree(pmte);
+
+ //
+ // Decrement the usecnt of the marked modules
+ //
+ ptmte = mte_h;
+ while (ptmte != NULL) {
+ if ((ptmte->mte_mflags & INGRAPH) != 0) {
+ ptmte->mte_usecnt--;
+ }
+ ptmte = ptmte->mte_link;
+ }
+
+ ldrUnloadTagedModules(Process);
+
+#if DBG
+ IF_OL2_DEBUG ( MTE ) {
+ DbgPrint("\nDumping segmenst after LDRUnloadExe()\n");
+ ldrDisplaySegmentTable();
+ }
+#endif
+ Process->ProcessMTE = NULL;
+ return(TRUE);
+}
+
diff --git a/private/os2/ldr/ldrste.c b/private/os2/ldr/ldrste.c
new file mode 100644
index 000000000..54cc251c9
--- /dev/null
+++ b/private/os2/ldr/ldrste.c
@@ -0,0 +1,1159 @@
+
+#include "ldrextrn.h"
+
+extern ldrste_t segtab;
+
+VOID ldrSetDescInfo(
+ SEL Selector, // selector to set desc info on
+ ULONG MemoryAddress, // base address of selector
+ USHORT ste_flags, // ste flags
+ USHORT SegSize) // size of segment
+{
+ PROCESS_LDT_INFORMATION LdtInfo;
+ NTSTATUS Status;
+
+ LdtInfo.Start = Selector & 0xfff8;
+ LdtInfo.Length = sizeof(LDT_ENTRY);
+
+ LdtInfo.LdtEntries[0].LimitLow = SegSize - 1;
+ LdtInfo.LdtEntries[0].BaseLow = (USHORT)(MemoryAddress);
+ LdtInfo.LdtEntries[0].HighWord.Bytes.BaseMid = (UCHAR)(MemoryAddress >> 16);
+ LdtInfo.LdtEntries[0].HighWord.Bytes.BaseHi = (UCHAR)(MemoryAddress >> 24);
+ LdtInfo.LdtEntries[0].HighWord.Bytes.Flags1 = D_SEG+D_PRES+D_DPL3;
+ LdtInfo.LdtEntries[0].HighWord.Bytes.Flags2 = 0;
+
+ if ((ste_flags & STE_DATA) == 0) {
+ LdtInfo.LdtEntries[0].HighWord.Bytes.Flags1 |= D_CODE;
+ }
+
+ if ((ste_flags & STE_ERONLY) == 0) {
+ // The STE_ERONLY is applicable for both D_RX in CODE segments
+ // and D_RW in DATA segments. D_RX and D_RW are the same bit
+ LdtInfo.LdtEntries[0].HighWord.Bytes.Flags1 |= D_RX;
+ }
+
+ Status = NtSetInformationProcess( CurrentThread->Process->ProcessHandle,
+ ProcessLdtInformation,
+ &LdtInfo,
+ sizeof(PROCESS_LDT_INFORMATION)
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("ldrSetDescInfo: Invalid request\n");
+#endif
+ }
+}
+
+/***LP ldrLoadModule - Load a new exe file for given module table entry.
+ *
+ * Each segment in the module which has not been
+ * previously initialized will be initialized and
+ * loaded as required.
+ *
+ * ENTRY plv - pointer to local variables
+ *
+ * EXIT Module marked as loaded
+ *
+ *
+ * This procedure performs the following steps:
+ *
+ * - calls TKLibiRecordMTE
+ * - calls DebugLoadSymMTE
+ * - must attach to or load each module that is referenced by our module
+ * - if 32-bit module finish loading objects
+ * - mark mte as module has been loaded
+ */
+
+APIRET ldrLoadModule(plv)
+ldrlv_t *plv; /* local variables */
+{
+ register ldrmte_t *pmte; /* pointer to mte */
+ register ldrsmte_t *psmte; /* pointer to swappable mte */
+ ldrste_t *pste;
+ ldrlibi_t *ptmp;
+ ulong_t csegs;
+ int rc;
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: ldrLoadModule(pmte=%x) was called\n", plv->lv_pmte);
+ }
+#endif
+
+ pmte = plv->lv_pmte; /* point to mte */
+ psmte = pmte->mte_swapmte; /* pointer to swappable mte */
+
+ /*
+ * Setup for Library init
+ */
+ if (((pmte->mte_mflags & LIBRARYMOD) != 0) &&
+ ((pmte->mte_mflags & USED) == 0) &&
+ ((pmte->mte_mflags & (INSTLIBINIT | GINIDONE)) != GINIDONE)) {
+ ptmp = &pldrLibiRecord[*pldrLibiCounter];
+ ptmp->handle = pmte->mte_handle;
+ pste = ldrNumToSte(pmte, psmte->smte_startobj);
+ ptmp->startaddr.ptr_off = (USHORT) psmte->smte_eip;
+ ptmp->startaddr.ptr_sel = pste->ste_selector | 7;
+ if (psmte->smte_stackobj != 0) {
+ if ((pste = ldrNumToSte(pmte, psmte->smte_stackobj))==0) {
+ rc = ERROR_INVALID_STACKSEG;
+ return(rc);
+ }
+ ptmp->stackaddr.ptr_off = (USHORT) psmte->smte_esp;
+ ptmp->stackaddr.ptr_sel = pste->ste_selector | 7;
+ }
+ else {
+ ptmp->stackaddr.ptr_off = 0;
+ ptmp->stackaddr.ptr_sel = 0;
+ }
+ if ((psmte->smte_autods == 0) ||
+ (pste = ldrNumToSte(pmte, psmte->smte_autods)) == NULL)
+ ptmp->ds = 0;
+ else
+ ptmp->ds = pste->ste_selector | 7;
+ ptmp->heapsize = (USHORT) psmte->smte_heapsize;
+ (*pldrLibiCounter)++;
+ pmte->mte_mflags |= GINIDONE;
+ }
+
+ //
+ // For system dll's other than Doscalls don't load segments
+ //
+ if ((pmte->mte_mflags & DOSMOD) != 0) {
+ ASSERT(LDRDoscallsSel != 0);
+ return(NO_ERROR);
+ }
+
+ //
+ // If this module has already been loaded, no need to load again
+ //
+ if ((pmte->mte_mflags & MTEPROCESSED) != 0) {
+ return(NO_ERROR);
+ }
+
+ /*
+ * Make sure starting point (or init routine) is ring 3
+ */
+ if (ldrIsNE(pmte) &&
+ psmte->smte_startobj != 0) {
+ if ((pste=ldrNumToSte(pmte, psmte->smte_startobj)) == NULL) {
+ rc = ERROR_INVALID_STARTING_CODESEG;
+ return(rc);
+ }
+
+ if ((pste->ste_selector & RPL_MASK) != RPL_RING3) {
+ if (pmte->mte_mflags & LIBRARYMOD) {
+ rc = ERROR_INVALID_DLL_INIT_RING;
+ }
+ else {
+ rc = ERROR_INVALID_STARTING_RING, pmte;
+ }
+ return(rc);
+ }
+ }
+
+ pste = (ldrste_t *) psmte->smte_objtab;
+ for (csegs = 0;
+ csegs < psmte->smte_objcnt;
+ csegs++, pste++
+ ) {
+ if ((rc = ldrLoadSegment(pmte, pste)) != NO_ERROR) {
+#if DBG
+ DbgPrint("OS2LDR: ldrGetModule - failed to ldrLoadSegment, rc = %d\n", rc);
+#endif
+ return(rc);
+ }
+ }
+ if ((psmte->smte_autods != 0) &&
+ (psmte->smte_autods <= psmte->smte_objcnt)
+ ) {
+ ldrEachObjEntry(0, pmte, ldrEditProlog, NULL);
+ }
+ pmte->mte_mflags |= MTEPROCESSED;
+ return(NO_ERROR);
+}
+
+
+/***LP ldrAllocSegments - allocate segments/selectors for requested mte.
+ *
+ * Each segment in the module which requests to be
+ * preloaded is allocated and all selectors for the
+ * module are allocated for the child task.
+ *
+ * ENTRY plv - pointer to set of local variables
+ *
+ * EXIT None
+ *
+ *
+ * This procedure performs the following steps:
+ *
+ * - For each segment in this module
+ * - check if load should abort
+ * - allocate memory
+ */
+
+APIRET ldrAllocSegments(plv)
+register ldrlv_t *plv; /* pointer to set of local variables */
+{
+ldrmte_t *pmte; /* pointer to mte */
+ldrsmte_t *psmte; /* pointer to swappable mte */
+register ldrste_t *pste; /* pointer to a segment table entry */
+//PVOID MemoryAddress;
+ULONG LastSuccessful;
+int rc;
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: ldrAllocSegments(pste=%x) was called\n", plv->lv_pmte);
+ }
+#endif
+
+ pmte = plv->lv_pmte;
+ psmte = pmte->mte_swapmte;
+ pste = (ldrste_t *) psmte->smte_objtab;
+
+ for (plv->lv_objnum = 1; plv->lv_objnum <= psmte->smte_objcnt;
+ plv->lv_objnum++, pste++) {
+
+ if ((rc=ldrAllocSegment(pmte, pste, plv->lv_objnum)) != NO_ERROR) {
+
+ /*
+ * We got an error allocating the segments for this
+ * module. We must cleanup any segments that were
+ * allocated before the error if the module we are loading
+ * was a library module. The reason is that the mte for this
+ * module will not have a run time attachment to this process.
+ * The case we are covering here is if a module that references
+ * another, is not loaded that module's module pointer table
+ * will not get the pointer to the mte for this one. Therefore
+ * when garbage collection is run this module will be freed
+ * and the allocated segments will not get freed.
+ */
+ LastSuccessful = plv->lv_objnum - 1;
+ pste = (ldrste_t *) psmte->smte_objtab;
+
+ for (plv->lv_objnum = 1; plv->lv_objnum <= LastSuccessful;
+ plv->lv_objnum++, pste++) {
+
+ NtUnmapViewOfSection(CurrentThread->Process->ProcessHandle,
+ SELTOFLAT(pste->ste_selector)
+ );
+
+ if ((pmte->mte_mflags & MTEPROCESSED) == 0) {
+ //
+ // If the allocated segment is a ring 2 segment, check
+ // entry records that need to be referenced by call gates.
+ // Remove the emulation thunk for the call gate.
+ //
+ if (((pste->ste_flags & STE_SEGDPL) == STE_RING_2) && // ring 2 segment
+ ((pste->ste_flags & STE_DATA) == 0) && // code segment
+ ((pste->ste_flags & STE_CONFORM) == 0) // non conforming
+ ) {
+ ldrEachObjEntry(plv->lv_objnum, pmte, ldrFreeCallGate, NULL);
+ }
+ NtUnmapViewOfSection(NtCurrentProcess(),
+ SELTOFLAT(pste->ste_selector)
+ );
+ NtClose((HANDLE)pste->ste_seghdl);
+ ldrFreeSel(pste->ste_selector, 1);
+ }
+ }
+// /*
+// * Slip packed segments, free as one object later
+// */
+// if (pste->ste_flags & STE_PACKED)
+// continue;
+// if ((pste->ste_seghdl != HOBNULL) &&
+// (pste->ste_selector & SEL_LDTBIT) &&
+// ((pste->ste_flags & STE_SHARED) == 0)) {
+// /* If cached instance data object */
+// ldrAssert(pste->ste_offset != 0);
+// if (VMHandleVerify(pste->ste_seghdl,
+// 1,SSToDS(&pbcache)) == NO_ERROR) {
+// /* Free the pseudohandle */
+// VMFreePseudoHandle(pste->ste_seghdl);
+// /* Free small caches from heap */
+// VMFreeKHB(VM_HKH_PUB_SWAPRW, pbcache);
+// }
+// else { /* Else cache has own object */
+// rc = VMGetLaddr(pste->ste_seghdl, SSToDS(&laddr));
+// ldrAssert(rc == NO_ERROR);
+// while (VMFreeMem(laddr,HOBNULL,0)==ERROR_INTERRUPT)
+// ; /* Free the object */
+// }
+// pste->ste_seghdl = HOBNULL;
+// /* Clear the handle */
+// }
+// else if (pste->ste_selector != 0)
+// VMFreeMem(SelToLaTiled(pste->ste_selector),
+// (VMHOB) ((pPTDACur->ptda_child != HOBNULL) ?
+// pPTDACur->ptda_child :
+// pPTDACur->ptda_handle),
+// VMFM_NOLDR | VMFM_GC);
+
+// /*
+// * See if any packed segments exists, free as one object.
+// */
+// if (psmte->smte_csegpack > 0)
+// VMFreeMem(psmte->smte_ssegpack, NA, NA);
+
+ return(rc);
+ }
+ }
+
+ /*
+ * Clear packed segment flag for second load of EXE
+ */
+ if (psmte->smte_csegpack > 0)
+ psmte->smte_csegpack = 0;
+
+ return(NO_ERROR);
+}
+
+
+/***LP ldrAllocSegment - verify allocation size and allocate memory
+ *
+ * If the segment's file size is larger than the minimum
+ * allocation size an error is reported.
+ * Both the allocation size and the segment handle are saved in
+ * the segment table entry. Also indicate the segment
+ * is being loaded so that it's memory will not be
+ * discarded during the load.
+ *
+ * ldrAllocSegment (pmte, pste, iseg)
+ *
+ * ENTRY pmte - pointer to mte
+ * pste - pointer to ste
+ * iseg - segment number
+ * RETURN int - error code (NO_ERROR if successful)
+ *
+ */
+
+static ULONG RegionSize64K = _64K;
+
+APIRET ldrAllocSegment(pmte,pste,iseg)
+register ldrmte_t *pmte; /* MTE pointer */
+register ldrste_t *pste; /* STE pointer */
+ulong_t iseg; /* Segment number (1-based) */
+{
+ register ldrsmte_t *psmte; /* swappable mte pointer */
+ ulong_t fl; /* Memory allocation flags */
+ int frsrc; /* Resource segment flag */
+ int frsrcused; /* True if resource really used */
+ ULONG RegionSize;
+ uchar_t sharename[23] = "\\sharemem\\";
+ uchar_t *psharename = sharename;
+ uchar_t ext[3] = {0,0,0};
+ ulong_t Index;
+ PVOID MemoryAddress;
+ NTSTATUS Status;
+ LARGE_INTEGER LargeRegionSize;
+ HANDLE SectionHandle;
+ ULONG ViewSize;
+ ULONG Protect;
+ BOOLEAN SectionCreated = FALSE;
+ APIRET rc;
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: ldrAllocSegment(pmte=%x) was called\n", pmte);
+ }
+#endif
+
+ psmte = pmte->mte_swapmte;
+
+ frsrc = iseg > psmte->smte_objcnt - psmte->smte_rsrccnt;
+ /* Set resource flag */
+ /*
+ * Note that for debugging purposes, we will actually allocate
+ * memory for resources that are not marked STE_PRELOAD if the
+ * ldrLoadRsrc flag is set. Such resources are born with a
+ * reference count of zero instead of one, however. The flag
+ * frsrcused is used to distinguish the special case.
+ */
+// if (!(pste->ste_flags & STE_PRELOAD) && frsrc)
+// return(NO_ERROR); /* Skip non-preloaded resources */
+ frsrcused = FALSE; /* Assume not meant to be used yet */
+ fl = 0; /* Initialize VM and PG flags */
+
+ if ((pste->ste_flags & STE_PRELOAD)) {
+ /* If swapping off or preload seg */
+ /*
+ * For a resource, the preload attribute does not actually
+ * mean the resource should be preloaded. It just means we
+ * should allocate the segment for the resource at load time.
+ * Unless we are loading the resource from a floppy, we should
+ * always preload it.
+ */
+ if (pste->ste_flags & STE_SHARED) {
+ /* If shared object */
+ pste->ste_flags &= ~STE_PRELOAD;
+ /* Only preload shared guys once */
+ frsrcused = TRUE; /* Resource actually referenced */
+ }
+ }
+
+ RegionSize = pste->ste_minsiz;
+ if (RegionSize == 0) {
+ RegionSize = _64K;
+ }
+
+ if ((pmte->mte_mflags & MTEPROCESSED) == 0) {
+ if ((pmte->mte_mflags & DOSLIB) != 0) {
+ Index = 0;
+ // DOSCALLS.DLL is loaded into fixed locationions
+ MemoryAddress = (PVOID)(DOSCALLS_BASE + (iseg - 1) * _64K);
+ }
+ else {
+ Index = ldrAllocateSel(1, FALSE); // _64K are exactly 1 selector
+ MemoryAddress = SELTOFLAT(Index);
+ }
+ //
+ // Special handling for the R2XFER_BASE segment which has
+ // already been allocated at ldrInit()
+ //
+ if (MemoryAddress == (PVOID)R2XFER_BASE) {
+ pste->ste_seghdl = (ulong_t)R2XferSegHandle;
+ SectionHandle = R2XferSegHandle;
+ }
+ else {
+ LargeRegionSize.LowPart = _64K;
+ LargeRegionSize.HighPart = 0;
+ Status = NtCreateSection(&SectionHandle,
+ SECTION_ALL_ACCESS,
+ NULL,
+ &LargeRegionSize,
+ PAGE_EXECUTE_READWRITE,
+ SEC_RESERVE,
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("OS2LDR: ldrAllocSegment - Can't create section, Status=%x\n", Status);
+#endif
+ if (Index != 0) {
+ ldrFreeSel(Index, 1);
+ }
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ ViewSize = 0;
+ Status = NtMapViewOfSection(SectionHandle,
+ NtCurrentProcess(),
+ &MemoryAddress,
+ 1,
+ RegionSize,
+ NULL,
+ &ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("OS2LDR: ldrAllocSegment - Can't map section to server process at addr=%x, Status=%x\n",
+ MemoryAddress, Status);
+#endif
+ NtClose(SectionHandle);
+ if (Index != 0) {
+ ldrFreeSel(Index, 1);
+ }
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ SectionCreated = TRUE;
+ pste->ste_seghdl = (ulong_t)SectionHandle;
+ }
+ }
+ else {
+ SectionHandle = (HANDLE)pste->ste_seghdl;
+ MemoryAddress = SELTOFLAT(pste->ste_selector);
+ }
+
+ //
+ // Any change in determinig the Protect value should be
+ // done in ldrsubr.c LDRDosGetResource() too.
+ //
+ if ((pste->ste_flags & STE_DATA) == 0) {
+ // This is a code segment
+ if (CurrentThread->Process->Flags & OS2_PROCESS_TRACE) {
+ Protect = PAGE_EXECUTE_WRITECOPY;
+ }
+ else {
+ if ((pste->ste_flags & STE_ERONLY) != 0) {
+ // This is an execute only segment
+ Protect = PAGE_EXECUTE;
+ }
+ else {
+ Protect = PAGE_EXECUTE_READ;
+ }
+ }
+ }
+ else {
+ // This is a data segment
+ if ((pste->ste_flags & STE_SHARED) != 0) {
+ // This is a shared data segment
+ if ((pste->ste_flags & STE_ERONLY) != 0) {
+ // This is a read only segment
+ Protect = PAGE_READONLY;
+ }
+ else {
+ // This is a read/write segment
+ Protect = PAGE_READWRITE;
+ }
+ }
+ else {
+ // This is a non shared data segment
+ if ((pste->ste_flags & STE_ERONLY) != 0) {
+ // This is a read only segment
+ if (CurrentThread->Process->Flags & OS2_PROCESS_TRACE) {
+ Protect = PAGE_EXECUTE_WRITECOPY;
+ }
+ else {
+ Protect = PAGE_READONLY;
+ }
+ }
+ else {
+ // This is a sizeable read/write segment
+ Protect = PAGE_EXECUTE_WRITECOPY;
+ }
+ }
+ }
+
+ if ((pmte->mte_mflags & MTEPROCESSED) == 0) {
+ pste->ste_selector = FLATTOSEL((ULONG)MemoryAddress);
+ pste->ste_selector = (SEL)((pste->ste_selector & SEL_RPLCLR) |
+ ((pste->ste_flags & STE_SEGDPL) >> 10));
+ pste->ste_fixups = (ulong_t)MemoryAddress;
+ }
+
+ //
+ // Non resource segments are mapped into the address space of the
+ // client process.
+ // Resources are not mapped yet into the address space of the process.
+ // DosGetResource() does the mapping job for resources.
+ //
+ if (iseg <= psmte->smte_objcnt - psmte->smte_rsrccnt) {
+ if (Protect == PAGE_EXECUTE_WRITECOPY) {
+ ViewSize = RegionSize;
+ }
+ else {
+ ViewSize = 0;
+ }
+ Status = NtMapViewOfSection(SectionHandle,
+ CurrentThread->Process->ProcessHandle,
+ &MemoryAddress,
+ 1,
+ RegionSize,
+ NULL,
+ &ViewSize,
+ ViewUnmap,
+ 0,
+ Protect
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("OS2LDR: ldrAllocSegment - Can't map section to client process %x at addr=%x, Status=%x\n",
+ CurrentThread->Process->ProcessHandle, MemoryAddress, Status);
+#endif
+ if (SectionCreated) {
+ NtUnmapViewOfSection(NtCurrentProcess(), MemoryAddress);
+ NtClose(SectionHandle);
+ if (Index != 0) {
+ ldrFreeSel(Index, 1);
+ }
+ }
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ if ((pmte->mte_mflags & MTEPROCESSED) == 0) {
+ /*
+ * If this is Doscalls module save the code selector
+ * of the first code segment
+ */
+ if (((pmte->mte_mflags & DOSLIB) != 0) &&
+ (iseg == 1)
+ ) {
+ LDRDoscallsSel = pste->ste_selector | 7;
+ segtab = *pste;
+ }
+ //
+ // If the allocated segment is a ring 2 segment, check for
+ // entry records that need to be referenced by call gates.
+ // Create an emulation thunk for the call gate.
+ //
+ if (((pste->ste_flags & STE_SEGDPL) == STE_RING_2) && // ring 2 segment
+ ((pste->ste_flags & STE_DATA) == 0) && // code segment
+ ((pste->ste_flags & STE_CONFORM) == 0) // non conforming
+ ) {
+ rc = ldrEachObjEntry(iseg, pmte, ldrGetCallGate, NULL);
+ if (rc != NO_ERROR) {
+ ldrEachObjEntry(iseg, pmte, ldrFreeCallGate, NULL);
+ NtUnmapViewOfSection(CurrentThread->Process->ProcessHandle,
+ MemoryAddress
+ );
+
+ if (SectionCreated) {
+ NtUnmapViewOfSection(NtCurrentProcess(), MemoryAddress);
+ NtClose(SectionHandle);
+ if (Index != 0) {
+ ldrFreeSel(Index, 1);
+ }
+ }
+ return(rc);
+ }
+ }
+ }
+
+ ldrSetDescInfo(pste->ste_selector, (ULONG) MemoryAddress,
+ pste->ste_flags, pste->ste_minsiz);
+ }
+
+ return(NO_ERROR);
+}
+
+
+/***LP ldrLoadSegment - segment load
+ *
+ * Setup to call ldrLoadSegment
+ *
+ * ENTRY pmte - pointer to mte
+ * pste - pointer to a segment table entry
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ *
+ */
+
+APIRET ldrLoadSegment(pmte, pste)
+ldrmte_t *pmte; /* pointer to mte */
+ldrste_t *pste; /* pointer to segment table entry */
+
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ PIO_STATUS_BLOCK pIoStatusBlock = &IoStatusBlock;
+ LARGE_INTEGER ByteOffset;
+ ldrmte_t *ptgtmte;
+ ldrsmte_t *psmte;
+ ldrste_t *ptgtste;
+ struct taddr_s taddr;
+ ULONG laddr;
+ ULONG seek;
+ uchar_t relocbuf[RELOCBUFLEN];
+ ushort_t crelrecs;
+ ushort_t i;
+ ulong_t cbread;
+ ushort_t crecs;
+ ri_t *pri;
+ uchar_t *pprocname;
+ ushort_t ord;
+ uchar_t *pchar;
+ ulong_t minsiz;
+ int rc = NO_ERROR;
+ NTSTATUS Status;
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: ldrLoadSegment(pmte=%x, pste=%x) was called\n", pmte, pste);
+ }
+#endif
+
+ ldrSetupSrcErrTxt(((char *) pmte->mte_modname)+1,
+ (USHORT) *((char *) pmte->mte_modname));
+
+ psmte = pmte->mte_swapmte;
+
+// BUGBUG - remove after LDT defined
+// laddr = SelToLaTiled(pste->ste_selector);
+ laddr = pste->ste_fixups;
+
+ if (pste->ste_offset != 0) {
+
+ if (pste->ste_flags & STE_ITERATED) {
+ if ((rc = ldrLoadIteratedData(pmte,
+ pste,
+ pIoStatusBlock,
+ laddr)) != NO_ERROR) {
+ return(rc);
+ }
+ IoStatusBlock.Status -= laddr;
+ cbread = IoStatusBlock.Information;
+ ByteOffset.LowPart = (ULONG)
+ (pste->ste_offset << psmte->smte_alignshift);
+ ByteOffset.HighPart = 0;
+ }
+
+ else {
+ seek = (ULONG) (pste->ste_offset << psmte->smte_alignshift);
+ ByteOffset.LowPart = seek;
+ ByteOffset.HighPart = 0;
+ cbread = (ulong_t) ((pste->ste_size == 0) ? _64K :
+ pste->ste_size);
+ if ((Status = NtReadFile(pmte->mte_sfn,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ (void *) laddr,
+ cbread,
+ &ByteOffset,
+ 0)) != 0) {
+ return(ERROR_BAD_EXE_FORMAT);
+ }
+ }
+ if (IoStatusBlock.Information != cbread)
+ return(ERROR_BAD_EXE_FORMAT);
+
+ if (pste->ste_size != 0) {
+ minsiz = (ulong_t) pste->ste_minsiz;
+ if (minsiz == 0) { /* size = 64k */
+ minsiz = 0x10000;
+ }
+ //
+ // Need to handle this special case because the segment
+ // is already set with the ring 2 xfer thunks
+ //
+ if (laddr != R2XFER_BASE) {
+ memset((void *) (laddr +
+ ((pste->ste_flags & STE_ITERATED) ?
+ IoStatusBlock.Status :
+ IoStatusBlock.Information)),
+ '\0',
+ (pste->ste_flags & STE_ITERATED) ?
+ minsiz - IoStatusBlock.Status :
+ minsiz - pste->ste_size);
+ }
+ }
+
+ /*
+ * HACK - This will check for Doscalls.dll and if it is
+ * the code segment it will search the code for the OPCodes
+ * "0xDD, 0x1f" which will be changed to a call to
+ * _EntryFlat
+ */
+ if (((pmte->mte_mflags & DOSLIB) != 0) &&
+ ((pste->ste_flags & STE_TYPE_MASK) == STE_CODE) &&
+ (!DoscallsLoaded)
+ ) {
+ pchar = (uchar_t *) laddr;
+ while(TRUE) {
+ while (*pchar++ != 0xdd &&
+ pchar < (uchar_t *) (laddr + cbread));
+ if (pchar == (uchar_t *) (laddr + cbread))
+ break;
+ if (*pchar == 0x1f) {
+ pchar--;
+ *((ULONG *) pchar) = Ol2EntryFlat;
+ break;
+ }
+ }
+ DoscallsLoaded = TRUE;
+ }
+ }
+
+ /*
+ * Process fixups if present
+ */
+ if (pste->ste_flags & STE_RELOCINFO) {
+
+ /*
+ * Read the number of relocation records
+ */
+ cbread = 2;
+ ByteOffset.LowPart += IoStatusBlock.Information;
+ if ((Status = NtReadFile(pmte->mte_sfn,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ &crelrecs,
+ cbread,
+ &ByteOffset,
+ 0 )) != 0) {
+ return(ERROR_BAD_EXE_FORMAT);
+ }
+ if (IoStatusBlock.Information != cbread)
+ return(ERROR_BAD_EXE_FORMAT);
+
+ crecs = RELOCSPERBUF;
+ for (i = 0; i < crelrecs; i++, crecs++) {
+
+ if ((crecs % RELOCSPERBUF) == 0) {
+ if (crelrecs - i > RELOCSPERBUF)
+ cbread = RELOCBUFLEN;
+ else
+ cbread = (crelrecs - i) * sizeof(struct ri_s);
+
+ ByteOffset.LowPart += IoStatusBlock.Information;
+ if ((Status = NtReadFile(pmte->mte_sfn,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ &relocbuf,
+ cbread,
+ &ByteOffset,
+ 0)) != 0) {
+ return(ERROR_BAD_EXE_FORMAT);
+ }
+ if (IoStatusBlock.Information != cbread)
+ return(ERROR_BAD_EXE_FORMAT);
+ crecs = 0;
+ }
+ pri = (ri_t *) &relocbuf[crecs * sizeof(struct ri_s)];
+
+ switch (pri->ri_flags & TARGET_MASK) {
+
+ case INTERNALREF: /* Internal fixup */
+
+ /*
+ * Check for fixed or movable
+ */
+ if (pri->ri_target_seg != B16MOVABLE) {
+ if ((ptgtste=ldrNumToSte(pmte,
+ pri->ri_target_seg
+ ))== NULL) {
+ return(ERROR_INVALID_SEGMENT_NUMBER);
+ }
+ taddr.tsel = ptgtste->ste_selector | 7;
+ taddr.toff = (ulong_t) pri->ri_target_off;
+ break;
+ }
+
+ /*
+ * A movable entry exists
+ */
+ else {
+ if ((rc = ldrGetEntAddr(pri->ri_target_off,
+ pmte,
+ &taddr,
+ pste,
+ pmte)) != NO_ERROR) {
+ return(ERROR_BAD_EXE_FORMAT);
+ }
+ break;
+ }
+
+ case IMPORTNAME: /* Import by name fixup */
+ case IMPORTORDINAL: /* Import by ordinal fixup */
+
+ if ((rc = ldrGetTgtMte(pri->ri_target_modnam,
+ pmte,
+ &ptgtmte)) != NO_ERROR) {
+ return(rc);
+ }
+
+ ldrSetupTgtErrTxt(((char *) ptgtmte->mte_modname)+1,
+ (USHORT) *((char *) ptgtmte->mte_modname));
+
+ if ((pri->ri_flags & TARGET_MASK) == IMPORTNAME) {
+ pprocname = (uchar_t *) (psmte->smte_impproc +
+ (ulong_t) pri->ri_target_impnam);
+ if (pprocname[1] == '#') {
+//BUGBUG - convert routine from asm
+// ldrStop(0xffff, 0);
+// ord = (ushort_t) ldrAscToOrd(&pprocname[2],
+// (ushort_t) pprocname[0] - 1);
+ }
+ else {
+
+ ldrProcNameBufL = (USHORT) (pprocname[0]);
+ ldrProcNameBuf = (PUCHAR) (pprocname + 1);
+ if ((rc = ldrGetOrdNum(ptgtmte,
+ pprocname,
+ &ord,
+ STRINGNONNULL
+ )) != NO_ERROR) {
+ return(rc);
+ }
+ }
+ }
+ else {
+ ord = pri->ri_target_ord;
+ ldrProcNameBufL = 2;
+ ldrProcNameBuf = (PUCHAR) &pri->ri_target_ord;
+ }
+
+ if ((rc = ldrGetEntAddr(ord,
+ ptgtmte,
+ &taddr,
+ pste,
+ pmte)) != NO_ERROR) {
+#if DBG
+ DbgPrint("ldrLoadSegment: failed to locate ordinal %d in %s for %s\n",
+ pri->ri_target_ord,
+ 1+(char *) (ptgtmte->mte_modname),
+ 1+(char *) (pmte->mte_modname)
+ );
+#endif
+ return(rc);
+ }
+ ldrInvTgtErrTxt();
+ break;
+
+ default:
+ continue;
+
+ }
+
+ if ((rc = ldrDoFixups(pri, laddr, &taddr,
+ pste->ste_minsiz)) != NO_ERROR) {
+ return(rc);
+ }
+ }
+ }
+ return(rc);
+
+}
+
+
+/***LP ldrLoadIteratedData - load iterated data
+ *
+ * Reads the iterated data from the file, expands it and loads it into
+ * the segment.
+ *
+ * ENTRY
+ * pmte - pointer to mte
+ * pste - pointer to segment table
+ * pIoStatusBlock - pointer to IO status buffer
+ * laddr - address of page we are loading
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ *
+ */
+
+APIRET ldrLoadIteratedData(pmte, pste, pIoStatusBlock, laddr)
+ldrmte_t *pmte;
+ldrste_t *pste;
+PIO_STATUS_BLOCK pIoStatusBlock;
+ULONG laddr;
+
+{
+ ldrsmte_t *psmte;
+ ULONG IOcount = 0;
+ ULONG seek;
+ LARGE_INTEGER ByteOffset;
+ ULONG cbread;
+ int rc;
+ ULONG filedata;
+ ULONG segsize;
+ struct iter {
+ USHORT numberiter;
+ USHORT patternsize;
+ } iterdata;
+ ULONG expandsize;
+ ULONG temp;
+ ULONG i;
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: ldrLoadIteratedData(pmte=%x) was called\n", pmte);
+ }
+#endif
+
+ psmte = pmte->mte_swapmte;
+ filedata = (ULONG) pste->ste_size; /* size of data */
+ if (filedata == 0) { /* check if file data = 64k */
+ filedata = 0x10000;
+ }
+
+ segsize = pste->ste_minsiz; /* size of segment */
+ if (segsize == 0) { /* check if size = 64k */
+ segsize = _64K;
+ }
+
+ seek = (ULONG) (pste->ste_offset << psmte->smte_alignshift);
+
+ while (TRUE) {
+
+ if (filedata < 3) {
+ return(ERROR_BAD_EXE_FORMAT);
+ }
+
+ filedata -= 4;
+
+ if (filedata == 0) /* See if done */
+ break;
+
+ ByteOffset.LowPart = seek;
+ ByteOffset.HighPart = 0;
+ cbread = 4;
+ if ((rc = NtReadFile(pmte->mte_sfn,
+ 0,
+ 0,
+ 0,
+ pIoStatusBlock,
+ &iterdata,
+ cbread,
+ &ByteOffset,
+ 0)) != 0) {
+ return(ERROR_BAD_EXE_FORMAT);
+ }
+
+ if (pIoStatusBlock->Information != cbread) {
+ return(ERROR_BAD_EXE_FORMAT);
+ }
+
+ seek += 4; /* We read 4 bytes */
+ IOcount += pIoStatusBlock->Information;
+
+ if (iterdata.numberiter == 0 || iterdata.patternsize == 0)
+ continue;
+
+ filedata -= iterdata.patternsize;
+ if (filedata > 0xffff) {
+ return(ERROR_BAD_EXE_FORMAT);
+ }
+
+ expandsize = (ULONG) (iterdata.patternsize * iterdata.numberiter);
+ if (expandsize > 0xffff) {
+ return(ERROR_ITERATED_DATA_EXCEEDS_64k);
+ }
+
+ segsize -= expandsize;
+ if (segsize > 0xffff) {
+ return(ERROR_INVALID_MINALLOCSIZE);
+ }
+
+ ByteOffset.LowPart = seek;
+ ByteOffset.HighPart = 0;
+ cbread = iterdata.patternsize;
+ if ((rc = NtReadFile(pmte->mte_sfn,
+ 0,
+ 0,
+ 0,
+ pIoStatusBlock,
+ (void *) laddr,
+ cbread,
+ &ByteOffset,
+ 0)) != 0) {
+ return(ERROR_BAD_EXE_FORMAT);
+ }
+
+ if (pIoStatusBlock->Information != cbread) {
+ return(ERROR_BAD_EXE_FORMAT);
+ }
+
+ seek += iterdata.patternsize;
+ IOcount += pIoStatusBlock->Information;
+
+ temp = laddr;
+ laddr += iterdata.patternsize;
+ for (i=1; i<iterdata.numberiter; i++) {
+ memmove((void *) laddr,
+ (void *) temp,
+ iterdata.patternsize);
+ laddr += iterdata.patternsize;
+ }
+
+ if (filedata == 0)
+ break;
+
+ }
+
+ pIoStatusBlock->Information = IOcount;
+ pIoStatusBlock->Status = laddr;
+
+ return(NO_ERROR);
+}
+
+
+/***LP ldrDoFixups - Do the fixups following the source chain
+ *
+ * Apply fixups to source
+*
+ *
+ * ENTRY pri - pointer to fixup record
+ * laddr - address of start of segment
+ * taddr - pointer to target address
+ * segsize - size of segment
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ *
+ */
+
+APIRET ldrDoFixups(pri, laddr, ptaddr, segsize)
+ri_t *pri; /* pointer to fixup record */
+ulong_t laddr; /* address of start of segment */
+struct taddr_s *ptaddr; /* target address */
+ushort_t segsize; /* size of segment */
+
+{
+ uchar_t *pcoffset;
+ ushort_t *psoffset;
+ ushort_t chain;
+ int count;
+ ulong_t segsize_l = RESIZE64K(segsize);
+
+#if DBG
+ IF_OL2_DEBUG ( FIXUP ) {
+ DbgPrint("OS2LDR: ldrDoFixups(): laddr=%x\n", laddr);
+ }
+#endif
+
+ chain = 1; /* we do at least one fixup */
+ count = (int) (segsize_l / sizeof(ushort_t));
+
+ if ((ulong_t)pri->ri_source > segsize_l)
+ return(ERROR_RELOC_CHAIN_XEEDS_SEGLIM);
+
+ pcoffset = (uchar_t *) (laddr + (ulong_t) pri->ri_source);
+
+ while (chain != 0xffff) {
+
+ if (!(pri->ri_flags & ADDITIVE))
+ chain = *((ushort_t *) pcoffset);
+ else
+ chain = 0xffff;
+
+ switch(pri->ri_stype & SOURCE_MASK) {
+
+ case BYTE_ADR:
+ if (pri->ri_flags & ADDITIVE)
+ *pcoffset += (uchar_t) (ptaddr->toff & BYTEMASK);
+ else
+ *pcoffset = (uchar_t) (ptaddr->toff & BYTEMASK);
+ break;
+ case SEG_ADR:
+ psoffset = (ushort_t *) pcoffset;
+ if (pri->ri_flags & ADDITIVE)
+ *psoffset += ptaddr->tsel;
+ else
+ *psoffset = ptaddr->tsel;
+ break;
+ case FAR_ADR:
+ psoffset = (ushort_t *) pcoffset;
+ if (pri->ri_flags & ADDITIVE) {
+ *psoffset += (ushort_t) (ptaddr->toff & WORDMASK);
+ psoffset++;
+ *psoffset += ptaddr->tsel;
+ }
+ else {
+ *psoffset = (ushort_t) (ptaddr->toff & WORDMASK);
+ psoffset++;
+ *psoffset = ptaddr->tsel;
+ }
+ break;
+ case OFF_ADR:
+ psoffset = (ushort_t *) pcoffset;
+ if (pri->ri_flags & ADDITIVE) {
+ *psoffset += (ushort_t) (ptaddr->toff & WORDMASK);
+ }
+ else {
+ *psoffset = (ushort_t) (ptaddr->toff & WORDMASK);
+ }
+ }
+ if (!(pri->ri_flags & ADDITIVE)) {
+ if (chain != 0xffff && (ulong_t)chain > segsize_l)
+ return(ERROR_RELOC_CHAIN_XEEDS_SEGLIM);
+
+ pcoffset = (uchar_t *) (laddr + (ulong_t) chain);
+ }
+
+ if (--count < 0) { // check for internal loops
+ return(ERROR_RELOC_CHAIN_XEEDS_SEGLIM);
+ }
+ }
+
+ return(NO_ERROR);
+
+}
diff --git a/private/os2/ldr/ldrsubr.c b/private/os2/ldr/ldrsubr.c
new file mode 100644
index 000000000..e8f9ff357
--- /dev/null
+++ b/private/os2/ldr/ldrsubr.c
@@ -0,0 +1,1962 @@
+#include <os2tile.h>
+
+#include "ldrextrn.h"
+
+#define TRC_C_SUC_ret 0
+#define TRC_C_LIB_ret -8
+
+VOID
+ldrClearAllMteFlag(
+ IN ULONG Flags
+ )
+{
+ ldrmte_t *pmte;
+
+ //
+ // Clear specific flags of all modules
+ //
+ pmte = mte_h;
+ while (pmte != NULL) {
+ pmte->mte_mflags &= ~Flags;
+ pmte = pmte->mte_link;
+ }
+}
+
+ //
+ // This is set to interface the assembly routine
+ // _ldrSetDescInfo in i386\ldrstart.asm
+ // Such that it is immune to kernel changes
+ //
+
+NTSTATUS
+SetLDT(
+ IN HANDLE ProcessHandle,
+ IN PROCESSINFOCLASS ProcessInformationClass,
+ IN PVOID ProcessInformation,
+ IN ULONG ProcessInformationLength
+ )
+{
+ UNREFERENCED_PARAMETER(ProcessInformationClass);
+ return NtSetInformationProcess (ProcessHandle,
+ ProcessLdtInformation,
+ ProcessInformation,
+ ProcessInformationLength);
+
+}
+
+/***LP ldrEachObjEntry - scan entry table entries for given object(s)
+ *
+ * Scan the entry table entries for the matching object and
+ * call the worker routine for processing at each entry.
+ *
+ * The worker routines are:
+ * ldrEditProlog
+ * ldrGetCallGate
+ * ldrInitEntry
+ * ldrFreeLDTGate
+ * ldrFreeCallGate
+ *
+ * ENTRY objnum - number of object to search for
+ * 0 - match all objects
+ * pmte - pointer to module table entry
+ * pworker - pointer to worker routine
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ *
+ */
+
+int ldrEachObjEntry(
+ULONG objnum, /* object number to search on */
+register ldrmte_t *pmte, /* pointer to object table entry */
+int (*pworker)(ldret_t *pet, ulong_t *pentry,
+ ldrmte_t *pmte, ldrlv_t *plv),/* pointer to worker routine */
+ldrlv_t *plv /* pointer to local vars */
+)
+{
+ register ldrsmte_t *psmte; /* pointer to swappable mte */
+ USHORT etobj; /* object number from entry table */
+ ULONG pentry; /* pointer to entry table entry */
+ struct ExpHdr *pexpdir; /* pointer to export directory */
+ ULONG i;
+ int rc;
+
+ /*
+ * validate mte pointer
+ */
+ if (!fMTEValid(pmte))
+ ASSERT("Eachobjentry: Invalid MTE");
+
+ psmte = pmte->mte_swapmte;
+
+ if (ldrIsNE(pmte)) { /* process 16-bit module */
+ register ldret_t *pet; /* pointer to entry table */
+
+ /*
+ * does module contain an entry table
+ */
+ if ((pet = (ldret_t *) (psmte->smte_enttab)) == 0)
+ return(NO_ERROR);
+
+ while (TRUE) {
+ if (pet->et_cnt == 0) /* check for end of table */
+ return(NO_ERROR);
+
+ if (pet->et_type == EMPTY) { /* check for empty bundle */
+ (ULONG) pet += (ULONG) ldrSkipEnts(pmte, pet->et_type,
+ (UCHAR) pet->et_cnt);
+ continue;
+ }
+
+ /*
+ * skip over count and type fields
+ */
+ pentry = (ULONG) pet +
+ (ULONG) ldrSkipEnts(pmte, pet->et_type, 0);
+
+ /*
+ * call routine for each entry
+ */
+ for (i = 1; i <= (ULONG) pet->et_cnt; i++) {
+ if (pet->et_type == B16MOVABLE)
+ etobj = (USHORT) (((ldrcte_t *) pentry)->cte_obj);
+ else
+ etobj = pet->et_type;
+ if ((objnum == 0) || (objnum == (ULONG) etobj)) {
+ /*
+ * call worker routine
+ */
+ if ((rc = pworker(pet, (PULONG) pentry, pmte,
+ plv)) != NO_ERROR)
+ return(rc);
+ }
+ if (pet->et_type == B16MOVABLE)
+ pentry += sizeof(ldrcte_t);
+ else
+ pentry += sizeof(ldrent_t);
+ }
+ (ULONG) pet += pentry - (ULONG) pet;
+
+ }
+ }
+ else { /* 32-bit module */
+ register PULONG peat; /* pointer to export addr tb entry */
+
+ pexpdir = (struct ExpHdr *) psmte->smte_expdir;
+ peat = (ULONG *) ((ULONG) pexpdir + pexpdir->exp_eat);
+ i = pexpdir->exp_eatcnt;
+ for (; i--; peat++) {
+
+ /*
+ * call worker routine
+ */
+ if ((rc = pworker(NULL, peat, pmte, plv)) != NO_ERROR)
+ return(rc);
+ }
+ }
+
+ return(NO_ERROR);
+
+}
+
+
+/***LP ldrSkipEnts - skip the given number of entries in the entry table
+ *
+ * For a given number, return the number of bytes to skip to the
+ * next bundle in the entry table.
+ *
+ * ENTRY pmte - pointer to mte for this module
+ * type - the type of bundle to skip
+ * count - the number of entries in this bundle
+ *
+ * EXIT count of byte to skip to get to desired entry
+ *
+ * This procedure performs the following steps:
+ *
+ * - determines the type of module
+ * - returns the number of bytes to skip based on entry type
+ */
+
+ulong_t ldrSkipEnts(pmte, type, count)
+ldrmte_t *pmte;
+uchar_t type;
+uchar_t count;
+{
+ if (ldrIsNE(pmte)) /* check for 16-bit module */
+ switch (type) {
+
+ case B16EMPTY: /* unused bundle */
+ return(sizeof(ldrempty_t));
+
+ case B16MOVABLE: /* movable object */
+ return(sizeof(ldrempty_t) + sizeof(ldrcte_t) * count);
+
+ default: /* fixed object */
+ return(sizeof(ldrempty_t) + sizeof(ldrent_t) * count);
+ }
+ else { /* 32-bit module */
+ ldrAssert(FALSE); /* should not get here */
+ }
+}
+
+
+/***LP ldrInitEntry - Zero initialize INT 3Fh in movable entries
+ *
+ * For ring 2 segments the callgate selector overlays the int 3fh
+ * instruction in a movable entry table entry. This value is
+ * intitialized to zero to indicate that the callgate has not yet
+ * been allocated. Also for 16-bit modules that are pageable, check
+ * to see if any exported procedure entries cross a page boundary.
+ * (Called from CreateMTE)
+ *
+ * ENTRY pet - pointer to entry table bundle
+ * pentry - pointer to entry table entry
+ * pmte - pointer to module table entry
+ * plv - pointer to local vars
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ *
+ * This procedure performs the following steps
+ *
+ * - check for movable entry
+ * - zero entry
+ */
+
+int ldrInitEntry(pet, pentry, pmte, plv)
+ldret_t *pet; /* pointer to entry table bundle */
+PULONG pentry; /* pointer to entry table entry */
+ldrmte_t *pmte; /* pointer to module table entry */
+ldrlv_t *plv; /* pointer to local vars */
+{
+ UCHAR flags;
+ USHORT offset;
+ USHORT obj;
+
+ UNREFERENCED_PARAMETER(plv);
+
+ if (ldrIsNE(pmte)) { /* 16-bit module */
+
+ flags = ((ldrent_t *) pentry)->ent_flags;
+
+ /*
+ * Check to see if have an exported entry point which is not a
+ * library module or a library module which has global data.
+ */
+ if (flags & EF_EXPORT && !(pmte->mte_mflags & LIBRARYMOD) ||
+ (pmte->mte_mflags & LIBRARYMOD && flags & EF_GDATA)) {
+
+ /*
+ * Remove offset and object number from entry table bundle
+ */
+ if (pet->et_type == B16MOVABLE) {
+ offset = ((ldrcte_t *) pentry)->cte_off;
+ obj = ((ldrcte_t *) pentry)->cte_obj;
+ }
+ else {
+ offset = ((ldrent_t *) pentry)->ent_off;
+ obj = pet->et_type;
+ }
+ }
+
+ /*
+ * check for movable entry
+ */
+ if (pet->et_type != B16MOVABLE)
+ return(NO_ERROR);
+ /*
+ * init callgate selector to 0
+ */
+ ((ldrcte_t *)pentry)->cte_sel = 0;
+
+ }
+
+ else { /* 32-bit module */
+ /*
+ * We do not need to do anything for 32-bit modules
+ */
+ return(ERROR_BAD_EXE_FORMAT);
+ }
+
+ return(NO_ERROR);
+}
+
+
+/***LP ldrEditProlog - Edit prolog for shared data segment
+ *
+ * ENTRY pet - pointer to entry table bundle
+ * pentry - pointer to entry table entry
+ * pmte - pointer to module table entry
+ * plv - pointer to local vars
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ *
+ * This procedure performs the following steps
+ *
+ * - check for special hard coded prologs to functions
+ * - modify the prologs
+ */
+
+int ldrEditProlog(pet, pentry, pmte, plv)
+ldret_t *pet; /* pointer to entry table bundle */
+PULONG pentry; /* pointer to entry table entry */
+ldrmte_t *pmte; /* pointer to module table entry */
+ldrlv_t *plv; /* pointer to local vars */
+{
+ UCHAR flags;
+ USHORT offset;
+ USHORT obj;
+ USHORT SharedDataSeg;
+ PUCHAR laddr;
+ ldrsmte_t *psmte;
+ ldrste_t *pste;
+ ULONG tmp_opcodes;
+
+ UNREFERENCED_PARAMETER(plv);
+
+ flags = ((ldrent_t *) pentry)->ent_flags;
+ //
+ // Check for prolog editing
+ //
+ if ((flags & EF_EXPORT) == 0) {
+ return(NO_ERROR);
+ }
+
+//#if DBG
+// DbgPrint("OS2LDR: ldrEditProlog: Processing %s\n", (PCHAR)pmte->mte_modname + 1);
+//#endif
+ /*
+ * Remove offset and object number from entry table bundle
+ */
+ if (pet->et_type == B16MOVABLE) {
+ //
+ // This is a moveable entry table entry
+ //
+ offset = ((ldrcte_t *) pentry)->cte_off;
+ obj = ((ldrcte_t *) pentry)->cte_obj;
+ }
+ else if (pet->et_type == B16ABSOLUTE) {
+ //
+ // This is an absolute entry table entry
+ //
+ return(NO_ERROR);
+ }
+ else {
+ //
+ // This is a fixed entry table entry
+ //
+ offset = ((ldrent_t *) pentry)->ent_off;
+ obj = pet->et_type;
+ }
+
+ psmte = pmte->mte_swapmte;
+ if (psmte->smte_autods == 0) {
+ return(NO_ERROR);
+ }
+ pste = ldrNumToSte(pmte, psmte->smte_autods);
+ SharedDataSeg = pste->ste_selector | 7;
+ if (SharedDataSeg == 0) {
+ ASSERT(FALSE);
+#if DBG
+ DbgPrint("OS2LDR: Strange DLL: %s, Segment %d\n",
+ (PCHAR)pmte->mte_modname + 1, obj);
+#endif
+ }
+ pste = ldrNumToSte(pmte, obj);
+ laddr = (PCHAR)SELTOFLAT(pste->ste_selector) + offset;
+ tmp_opcodes = (*(PULONG)laddr)&0x00FFFFFF;
+ if ((tmp_opcodes == 0x90D88C) || // MOV AX,DS + NOP
+ (tmp_opcodes == 0x90581e)) // PUSH DS + POP AX + NOP
+ {
+//#if DBG
+// DbgPrint("OS2LDR: Updating addr %x\n", laddr);
+//#endif
+ *laddr++ = (UCHAR)0xB8;
+ *(PUSHORT)laddr = SharedDataSeg;
+ }
+
+ return(NO_ERROR);
+}
+
+/***LP ldrGetCallGate - Create a call gate for ring 2 entries
+ *
+ * ENTRY pet - pointer to entry table bundle
+ * pentry - pointer to entry table entry
+ * pmte - pointer to module table entry
+ * plv - pointer to local vars
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ *
+ * This procedure performs the following steps
+ *
+ * - check for movable entry
+ * - zero entry
+ */
+
+int ldrGetCallGate(pet, pentry, pmte, plv)
+ldret_t *pet; /* pointer to entry table bundle */
+PULONG pentry; /* pointer to entry table entry */
+ldrmte_t *pmte; /* pointer to module table entry */
+ldrlv_t *plv; /* pointer to local vars */
+{
+ ldrste_t *pste;
+ UCHAR flags;
+ ULONG CallGateOffset;
+ PR2CallInfo pR2CallEntry;
+
+ UNREFERENCED_PARAMETER(plv);
+
+ flags = ((ldrent_t *) pentry)->ent_flags;
+ //
+ // Check for valid entry for callgate
+ //
+ if (((flags & EF_EXPORT) == 0) ||
+ (pet->et_type != B16MOVABLE)
+ ) {
+ return(NO_ERROR);
+ }
+
+//#if DBG
+// DbgPrint("OS2LDR: ldrGetCallGate: Processing %s\n", (PCHAR)pmte->mte_modname + 1);
+//#endif
+ //
+ // Allocate a call gate and place it in the entry
+ //
+ CallGateOffset = ldrAllocateCallGate();
+ if (CallGateOffset == -1) {
+#if DBG
+ KdPrint(("OS2LDR: cannot allocate call gate\n"));
+#endif
+ return(ERROR_INVALID_CALLGATE);
+ }
+
+ ((ldrcte_t *) pentry)->cte_sel = (ushort_t)CallGateOffset;
+ pR2CallEntry = (PR2CallInfo)(R2XFER_BASE + CallGateOffset);
+ pR2CallEntry->R2CallNearInst = 0xE8;
+ pR2CallEntry->R2CommonEntry = (USHORT)(0 - (CallGateOffset + 3));
+ pR2CallEntry->R2BytesToCopy = (((ldrcte_t *) pentry)->cte_flags & 0xF8) >> 2;
+ pR2CallEntry->R2EntryPointOff = ((ldrcte_t *) pentry)->cte_off;
+ pste = ldrNumToSte(pmte, ((ldrcte_t *) pentry)->cte_obj);
+ pR2CallEntry->R2EntryPointSel = pste->ste_selector | 7; // force ring 3
+
+ return(NO_ERROR);
+}
+
+
+/***LP ldrFreeCallGate - Free the call gate stubs for ring 2 entries
+ *
+ * ENTRY pet - pointer to entry table bundle
+ * pentry - pointer to entry table entry
+ * pmte - pointer to module table entry
+ * plv - pointer to local vars
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ *
+ * This procedure performs the following steps
+ *
+ * - check for movable entry
+ * - mark the call gate entry as free
+ */
+
+int ldrFreeCallGate(pet, pentry, pmte, plv)
+ldret_t *pet; /* pointer to entry table bundle */
+ulong_t *pentry; /* pointer to entry table entry */
+ldrmte_t *pmte; /* pointer to module table entry */
+ldrlv_t *plv; /* pointer to local vars */
+{
+ UCHAR flags;
+ ULONG CallGateOffset;
+ PR2CallInfo pR2CallEntry;
+
+ UNREFERENCED_PARAMETER(plv);
+
+ flags = ((ldrent_t *) pentry)->ent_flags;
+ //
+ // Check for valid entry for callgate
+ //
+ if (((flags & EF_EXPORT) == 0) ||
+ (pet->et_type != B16MOVABLE)
+ ) {
+ return(NO_ERROR);
+ }
+
+//#if DBG
+// DbgPrint("OS2LDR: ldrFreeCallGate: Processing %s\n", (PCHAR)pmte->mte_modname + 1);
+//#endif
+ //
+ // Free the call gate
+ //
+ CallGateOffset = ((ldrcte_t *) pentry)->cte_sel;
+ if ((CallGateOffset == 0) ||
+ (CallGateOffset == 0x3fcd)
+ ) {
+#if DBG
+ KdPrint(("OS2LDR: OK to ignore non-initialized call gate 0x%x when app loading fails\n",
+ CallGateOffset));
+#endif
+ return(NO_ERROR);
+ }
+ ldrDeallocateCallGate(CallGateOffset);
+ pR2CallEntry = (PR2CallInfo)(R2XFER_BASE + CallGateOffset);
+ pR2CallEntry->R2CallNearInst = 0;
+ pR2CallEntry->R2CommonEntry = 0;
+ pR2CallEntry->R2BytesToCopy = 0;
+ pR2CallEntry->R2EntryPointOff = 0;
+ pR2CallEntry->R2EntryPointSel = 0;
+ return(NO_ERROR);
+}
+
+
+/***LP ldrSetLoaded - set MTEPROCESSED bit in the module flags for all mtes.
+ *
+ *
+ * ENTRY none
+ *
+ * EXIT none
+ *
+ * This procedure performs the following steps
+ *
+ */
+
+void ldrSetLoaded()
+{
+ register ldrmte_t *pmte; /* pointer to a module table entry */
+
+ /*
+ * scan list of mtes til end of list is found
+ */
+ for (pmte = mte_h; pmte != NULL; pmte = (ldrmte_t *)pmte->mte_link) {
+ /*
+ * check if mte valid yet
+ */
+ if (pmte->mte_mflags & MTEVALID)
+ pmte->mte_mflags |= MTEPROCESSED; /* mark as loaded */
+ pmte->mte_mflags &= ~MTENEWMOD;
+ }
+}
+
+
+/***LP ldrNumToOte - validate object number and return ote address
+ *
+ * Given a object number, check if object exists in current mte,
+ * and return a pointer to the object table entry.
+ *
+ * ENTRY pmte - pointer to module table entry
+ * objnum - object number to check for
+ *
+ * EXIT pointer to object table entry for object
+ * or 0 for object not present
+ */
+
+ldrote_t *ldrNumToOte(pmte, objnum)
+register ldrmte_t *pmte; /* pointer to a module table entry */
+ulong_t objnum; /* object number to check for */
+{
+ register ldrsmte_t *psmte; /* pointer to swappable mte */
+
+ psmte = pmte->mte_swapmte;
+
+ if (objnum-- <= psmte->smte_objcnt) {
+ if (ldrIsNE(pmte)) /* is this a 16-bit module */
+ return((ldrote_t *)&(((ldrste_t *)psmte->smte_objtab)[objnum]));
+ else
+ return(&(((ldrote_t *)psmte->smte_objtab)[objnum]));
+ }
+ return(0);
+}
+
+
+/***LP LDRStop - stop in kernel debugger
+ *
+ * If the global DBG is TRUE print a debug message
+ *
+ * LDRStop (id, pmte)
+ *
+ * ENTRY id - identifier of caller (ignored)
+ * pmte - mte pointer or NULL
+ * RETURN NONE
+ *
+ * CALLS DbgUserBreakPoint
+ *
+ * EFFECTS NONE
+ */
+void LDRStop(id, pmte)
+int id;
+void *pmte;
+
+{
+ UNREFERENCED_PARAMETER(id);
+ UNREFERENCED_PARAMETER(pmte);
+
+#if DBG
+ DbgPrint("ldrStop\n");
+// DbgUserBreakPoint();
+#endif
+
+}
+
+
+/***LP ldrFindMTEForHandle - Find MTE for given handle
+ *
+ * ENTRY handle - 16-bit handle
+ *
+ * EXIT pointer to mte or 0 for not present
+ */
+ldrmte_t *ldrFindMTEForHandle(hmte)
+USHORT hmte;
+
+{
+ ldrmte_t *pmte;
+
+ pmte = mte_h;
+
+ while (pmte != 0) {
+ if (pmte->mte_handle == hmte)
+ break;
+ pmte = pmte->mte_link;
+ }
+
+ return(pmte);
+
+}
+
+/***LP ldrFindSegForHandleandNum - Given a Handle and a seg number,
+ * return the selector
+ *
+ */
+USHORT ldrFindSegForHandleandNum(inmte, handle, segnum)
+USHORT inmte;
+USHORT handle;
+USHORT segnum;
+
+{
+ ldrmte_t *pmte;
+ ldrste_t *pste;
+
+
+ if (inmte){
+ pmte = ldrFindMTEForHandle(inmte);
+ }
+ else {
+ pmte = ldrFindMTEForHandle(handle);
+ if (pmte == NULL) {
+ return(0);
+ }
+ }
+
+ pste = ldrNumToSte(pmte, segnum);
+
+ if (pste == NULL){
+ return(0);
+ }
+
+ return(pste->ste_selector);
+
+}
+
+// ldrFindDLDForHandle - Find the DLD which points to the
+// requested handle.
+//
+// ENTRY pmte_prog - MTE ptr of the process MTE
+// handle - Handle of module
+//
+// EXIT Pointer to the DLD if the module belongs to the process
+// NULL otherwise
+//
+ldrdld_t *
+ldrFindDLDForHandle(
+ ldrmte_t *pmte_prog,
+ USHORT handle
+ )
+{
+ ldrdld_t *pdld;
+
+ pdld = pmte_prog->mte_dldchain;
+ while (pdld != NULL) {
+ if ((pdld->Cookie == (ULONG)CurrentThread->Process) &&
+ (pdld->dld_mteptr->mte_handle == handle)) {
+ break;
+ }
+ pdld = pdld->dld_next;
+ }
+ return(pdld);
+}
+
+// ModuleIsAttachedToProcess - Verify that a module that was statically
+// loaded at process start belongs to the
+// current procee
+//
+// ENTRY pmte_prog - MTE ptr of the process MTE
+// pmte - MTE ptr of the module MTE
+//
+// EXIT TRUE if the module belongs to the process
+// FALSE otherwise
+//
+BOOLEAN
+ModuleIsAttachedToProcess(
+ ldrmte_t *pmte_cur,
+ ldrmte_t *pmte
+ )
+{
+ ldrmte_t **ppmte;
+ ULONG lindex;
+ ULONG i;
+
+ if (pmte_cur == pmte) {
+ return(TRUE);
+ }
+ pmte_cur->mte_mflags |= INGRAPH;
+
+ ppmte = (ldrmte_t **) pmte_cur->mte_modptrs;
+ for (i = 1; i <= pmte_cur->mte_impmodcnt; i++) {
+ /*
+ * It is required for 16-bit modules to load the
+ * referneced module in reverse order.
+ */
+ lindex = pmte_cur->mte_impmodcnt-i;
+
+ //
+ // Check if the referenced module has already been processed.
+ // Processing the modules is done in reverse order.
+ //
+ if ((ppmte[lindex]->mte_mflags & INGRAPH) == 0) {
+ if (ModuleIsAttachedToProcess(ppmte[lindex], pmte)) {
+ return(TRUE);
+ }
+ }
+ }
+ return(FALSE);
+}
+
+// ModuleLoadedForProcess - Verify that a loaded module belongs
+// to the current procee
+//
+// ENTRY pmte_prog - MTE ptr of the process MTE
+// pmte - MTE ptr of the module MTE
+//
+// EXIT TRUE if the module belongs to the process
+// FALSE otherwise
+//
+BOOLEAN
+ModuleLoadedForProcess(
+ ldrmte_t *pmte_prog,
+ ldrmte_t *pmte
+ )
+{
+ ldrdld_t *pdld;
+
+ ldrClearAllMteFlag(INGRAPH); // Clear INGRAPH flag. We might start
+ // recursive search for module.
+
+ pdld = pmte_prog->mte_dldchain;
+ while (pdld != NULL) {
+ if (pdld->Cookie == (ULONG)CurrentThread->Process) {
+ if(pdld->dld_mteptr == pmte) {
+ return(TRUE);
+ }
+ // Check if module was attached to the module
+ // that was loaded dynamically.
+ else {
+ if (ModuleIsAttachedToProcess(pdld->dld_mteptr, pmte)) {
+ return(TRUE);
+ }
+ }
+ }
+ pdld = pdld->dld_next;
+ }
+
+ return (ModuleIsAttachedToProcess(pmte_prog, pmte));
+}
+
+// ldrCreateDLDRecord - Create a DLD record for the new module
+//
+// ENTRY pmte_prog - MTE ptr of the process MTE
+// pmte - MTE ptr of the module MTE
+// DLDExists - Pointer to BOOLEAN variable which is set to
+// TRUE if the module was already loaded by this program
+// FALSE if the module is a new module for the program
+//
+// EXIT rc - return value indicating the success o fthe function
+//
+APIRET
+ldrCreateDldRecord(
+ ldrmte_t *pmte_prog, /* Pointer to process MTE */
+ ldrmte_t *pmte, /* Pointer to new loaded module's MTE */
+ BOOLEAN *DLDExisted /* Flag indicating if the DLD already existed */
+ )
+{
+ ldrdld_t *pdld;
+
+ pdld = pmte_prog->mte_dldchain;
+ while (pdld != NULL) {
+ if ((pdld->Cookie == (ULONG)CurrentThread->Process) &&
+ (pdld->dld_mteptr == pmte)) {
+ //
+ // A DLD which references the newly loaded module was found
+ //
+ pdld->dld_usecnt++;
+ *DLDExisted = TRUE;
+ return(NO_ERROR);
+ }
+ pdld = pdld->dld_next;
+ }
+ //
+ // The newly loaded module is not referenced yet in the DLD chain.
+ // Create and link a new record into the chain.
+ //
+ pdld = RtlAllocateHeap(LDRNEHeap, 0, sizeof(ldrdld_t));
+ if (pdld == NULL) {
+ *DLDExisted = FALSE;
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ pdld->dld_usecnt = 1;
+ pdld->dld_mteptr = pmte;
+ pdld->Cookie = (ULONG)CurrentThread->Process;
+ pdld->dld_next = pmte_prog->mte_dldchain;
+ pmte_prog->mte_dldchain = pdld;
+ *DLDExisted = FALSE;
+ return(NO_ERROR);
+}
+
+/***EP LDRDosLoadModule - Load dynamic link library module.
+ *
+ * This routine loads a dynamic link library module and returns
+ * a handle for the library.
+ *
+ * ENTRY pszFailName - ptr to buffer for name if failure
+ * cbFileName - length of buffer for name if failure
+ * pszModName - ptr to module name
+ * phmod - ptr to module handle
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ * pexec_info structure set
+ */
+
+BOOLEAN
+LDRDosLoadModule(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ P_LDRLOADMODULE_MSG a = &m->u.LdrLoadModule;
+ USHORT class;
+ ldrmte_t *pmte_prog; /* Pointer to process MTE */
+ ldrmte_t *pmte;
+ ldrmte_t *ptmte;
+ ldrdld_t *pdld;
+ BOOLEAN DLDExisted;
+ int rc;
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: DosLoadModule() was called\n");
+ }
+#endif
+
+ CurrentThread = t;
+
+ //
+ // Set the fForceUnmap flag to TRUE so that ldrUnloadTagedModules()
+ // does unmap the app's freed segments from the app's address space.
+ //
+ fForceUnmap = TRUE;
+
+ //
+ // Clear the INGRAPH and USE flags of all modules so that we
+ // know that this module has already been processed
+ //
+ ldrClearAllMteFlag(INGRAPH | USED);
+
+ //
+ // Tag all referenced modules with the USED flag
+ // so that they are not loaded again
+ //
+ pmte = t->Process->ProcessMTE;
+ ldrTagModuleTree_USED(pmte);
+ for (pdld = pmte->mte_dldchain; pdld != NULL; pdld = pdld->dld_next) {
+ if (pdld->Cookie == (ULONG)CurrentThread->Process) {
+ ldrTagModuleTree_USED(pdld->dld_mteptr);
+ }
+ }
+ ldrClearAllMteFlag(INGRAPH);
+
+ //
+ // Init the Library Intialization routines data structure
+ //
+ pldrLibiRecord = (ldrlibi_t *)a->InitRecords.Buffer;
+ pldrLibiCounter = &a->NumOfInitRecords;
+ *pldrLibiCounter = 0;
+
+ //
+ // init the pointer to the error string
+ //
+ pErrText = &a->FailName;
+
+ /*
+ * Point to ldrLibPathBuf to contain the environment string
+ */
+ strncpy(ldrLibPathBuf, a->LibPathName.Buffer, SizeOfldrLibPathBuf);
+ ldrLibPathBuf[SizeOfldrLibPathBuf-1] = '\0';
+
+#ifndef DBCS // MSKK Aug.20.1993 V-AkihiS
+ /*
+ * Check for any meta characters
+ */
+ if (strpbrk(a->ModuleName.Buffer, "*?") != NULL) {
+ m->ReturnedErrorValue = ERROR_INVALID_NAME;
+ return(TRUE);
+ }
+
+ if ((strchr(a->ModuleName.Buffer, '.') != NULL) &&
+ (strpbrk(a->ModuleName.Buffer, "\\/") == NULL)
+ ) {
+ m->ReturnedErrorValue = ERROR_FILE_NOT_FOUND;
+ return(TRUE);
+ }
+#endif
+
+ /*
+ * Check if module we are loading has any path characters
+ */
+ if (strpbrk(a->ModuleName.Buffer, ":\\/.") == NULL)
+ class = CLASS_GLOBAL;
+ else
+ class = CLASS_SPECIFIC;
+
+ if ((rc = ldrGetModule(a->ModuleName.Buffer,
+ a->ModuleName.Length,
+ (char)EXT_LIBRARY,
+ class,
+ &pmte,
+ NULL,
+ NULL)) == NO_ERROR) {
+ pmte_prog = (ldrmte_t *)t->Process->ProcessMTE;
+ ASSERT(pmte_prog != NULL);
+ rc = ldrCreateDldRecord(pmte_prog, pmte, &DLDExisted);
+ if (rc != NO_ERROR) {
+ ldrUnloadTagedModules(t->Process);
+ m->ReturnedErrorValue = rc;
+ return(TRUE);
+ }
+ a->ModuleHandle = pmte->mte_handle;
+ //
+ // Increment the usecnt of the referenced modules
+ //
+ if (!DLDExisted) {
+ ptmte = mte_h;
+ while (ptmte != NULL) {
+ if ((ptmte->mte_mflags & INGRAPH) != 0) {
+ ptmte->mte_usecnt++;
+ }
+ ptmte = ptmte->mte_link;
+ }
+ }
+ /*
+ * get module startup parameters
+ */
+ rc = ldrGetModParams(CurrentThread->Process->ProcessMTE,
+ (ldrrei_t *)&a->ExecInfo
+ );
+#if DBG
+ IF_OL2_DEBUG ( MTE ) {
+ DbgPrint("\nDumping segmenst after DosLoadModule() processing\n");
+ ldrDisplaySegmentTable();
+ }
+#endif
+
+ }
+ else {
+ ldrWriteErrTxt(rc);
+ ldrUnloadTagedModules(t->Process);
+ }
+
+ m->ReturnedErrorValue = rc;
+ return(TRUE);
+}
+
+
+/***EP LDRDosGetProcAddr - Get dynamic link procedure address
+ *
+ *
+ * ENTRY hmte Module handle returned by DOSLOADMODULE
+ * pchname ASCIIZ name of procedure.
+ * paddress Ptr to where the address should be returned.
+ *
+ * EXIT NO_ERROR paddress has the valid address
+ * ERROR_PROC_NOT_FOUND
+ */
+
+BOOLEAN
+LDRDosGetProcAddr(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ P_LDRGETPROCADDR_MSG a = &m->u.LdrGetProcAddr;
+ ldrmte_t *pmte_prog; /* Pointer to process MTE */
+ ldrmte_t *pmte; /* Pointer to MTE */
+ struct taddr_s taddr;
+ int cch; /* Length of name */
+ ulong_t ulord;
+ int rc; /* Return code */
+
+ CurrentThread = t;
+
+ do { /* Dummy loop */
+ //
+ // Verify that the module belongs to the current process
+ //
+ pmte_prog = (ldrmte_t *)t->Process->ProcessMTE;
+ ASSERT(pmte_prog != NULL);
+
+ pmte = ldrFindMTEForHandle((USHORT)a->ModuleHandle);
+ if (pmte == NULL) {
+ rc = ERROR_INVALID_HANDLE;
+ break;
+ }
+ if (!ModuleLoadedForProcess(pmte_prog, pmte)) {
+ rc = ERROR_INVALID_HANDLE;
+ break;
+ }
+
+ /*
+ * See if name specified
+ */
+ if (!a->ProcNameIsOrdinal) {
+ cch = a->ProcName.Length;
+ if (cch > MAX_PROC_LEN) {
+ rc = ERROR_INVALID_NAME;
+ break; /* Exit */
+ }
+
+ if (a->ProcName.Buffer[0] != '#') {
+
+ rc = ldrGetOrdNum(pmte,
+ a->ProcName.Buffer,
+ (PUSHORT) &ulord,
+ STRINGNULLTERM);
+
+ if (rc != NO_ERROR)
+ break; /* Exit if name not found */
+ }
+
+ else {
+ ulord = atol(&a->ProcName.Buffer[1]);
+ }
+
+ }
+ else {
+ ulord = a->OrdinalNumber;
+ }
+
+ memset(&taddr, 0, sizeof(taddr));
+ rc = ldrGetEntAddr((USHORT) ulord,
+ pmte,
+ &taddr,
+ NULL,
+ NULL);
+
+ if (rc != NO_ERROR)
+ break; /* Break if error */
+
+ ldrAssert(taddr.toff < _64K);
+ taddr.toff += (ulong_t) taddr.tsel << WORDSHIFT;
+ a->ProcAddr = (ULONG) taddr.toff;
+
+ } while(FALSE); /* End dummy loop */
+ m->ReturnedErrorValue = rc; /* Return error code */
+ return(TRUE);
+}
+
+
+/***EP LDRDosGetModName - Retrieves the filename of the specified module.
+ *
+ *
+ * ENTRY hMod module handle
+ * cbBuf number of bytes in buffer
+ * pchBuf pointer to buffer to receiving module name
+ *
+ * EXIT NO_ERROR
+ * ERROR_MOD_NOT_FOUND
+ */
+
+BOOLEAN
+LDRDosGetModName(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ P_LDRGETMODULENAME_MSG a = &m->u.LdrGetModuleName;
+ ldrmte_t *pmte;
+ ldrsmte_t *psmte;
+
+ CurrentThread = t;
+
+ //
+ // Verify that a module with the specified handle does exist.
+ // The module can belong to any process in the system!
+ // (found while running the PM code)
+ //
+ pmte = ldrFindMTEForHandle((USHORT)a->ModuleHandle);
+ if (pmte == NULL) {
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ return(TRUE);
+ }
+
+ psmte = pmte->mte_swapmte;
+ if ((USHORT)(psmte->smte_pathlen + 1) > a->ModuleName.MaximumLength) {
+ m->ReturnedErrorValue = ERROR_BAD_LENGTH;
+ return TRUE;
+ }
+ memcpy(a->ModuleName.Buffer, (PCHAR)psmte->smte_path+14, psmte->smte_pathlen-14);
+ a->ModuleName.Buffer[psmte->smte_pathlen-14] = '\0';
+ a->ModuleName.Length = psmte->smte_pathlen-14;
+ m->ReturnedErrorValue = NO_ERROR;
+ return(TRUE);
+}
+
+/***EP ldrGetModName - Retrieves the filename of the specified module.
+ *
+ *
+ * ENTRY hMod module handle
+ * cbBuf number of bytes in buffer
+ * pchBuf pointer to buffer to receiving module name
+ *
+ */
+
+BOOLEAN
+ldrGetModName(
+ ldrmte_t *inmte,
+ USHORT hmod,
+ PCHAR buf,
+ USHORT bc
+ )
+{
+ ldrmte_t *pmte;
+ ldrsmte_t *psmte;
+
+
+ if (inmte){
+ pmte = inmte;
+ }
+ else {
+ pmte = ldrFindMTEForHandle(hmod);
+ if (pmte == NULL) {
+ return(FALSE);
+ }
+ }
+
+ psmte = pmte->mte_swapmte;
+
+
+ if (bc <= (psmte->smte_pathlen-14)) {
+ return(FALSE);
+ }
+ memcpy(buf, (PCHAR)psmte->smte_path+14, psmte->smte_pathlen-14 );
+ buf[psmte->smte_pathlen-14] = '\0';
+ return(TRUE);
+}
+
+/***EP LDRDosGetModHandle - Retrieves the handle of a dynamic-link module.
+ *
+ *
+ * ENTRY pchname ASCIIZ name of procedure.
+ * paddress Ptr to variable receiving module handle
+ *
+ * EXIT NO_ERROR
+ * ERROR_MOD_NOT_FOUND
+ */
+
+BOOLEAN
+LDRDosGetModHandle(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ P_LDRGETMODULEHANDLE_MSG a = &m->u.LdrGetModuleHandle;
+ ldrmte_t *pmte_prog; /* Pointer to process MTE */
+ ldrmte_t *pmte;
+ USHORT class;
+ ULONG rc;
+
+ CurrentThread = t;
+
+ /*
+ * Point to ldrLibPathBuf to contain the environment string
+ */
+ strncpy(ldrLibPathBuf, a->LibPathName.Buffer, SizeOfldrLibPathBuf);
+ ldrLibPathBuf[SizeOfldrLibPathBuf-1] = '\0';
+
+ ldrUCaseString(a->ModuleName.Buffer, a->ModuleName.Length);
+
+ /*
+ * Check if module we are loading has any path characters
+ */
+ if (strpbrk(a->ModuleName.Buffer, ":\\/.") == NULL)
+ class = CLASS_GLOBAL;
+ else
+ class = CLASS_SPECIFIC;
+
+ pmte = NULL;
+ if (((rc = ldrFindModule(a->ModuleName.Buffer, a->ModuleName.Length,
+ class,
+ &pmte)) != NO_ERROR) ||
+ (pmte == NULL)
+ ) {
+ m->ReturnedErrorValue = ERROR_MOD_NOT_FOUND;
+ return(TRUE);
+ }
+
+ //
+ // Verify that the module belongs to the current process
+ //
+ pmte_prog = (ldrmte_t *)t->Process->ProcessMTE;
+ ASSERT(pmte_prog != NULL);
+
+ if (!ModuleLoadedForProcess(pmte_prog, pmte)) {
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ return(TRUE);
+ }
+
+ a->ModuleHandle = (ULONG) pmte->mte_handle;
+ m->ReturnedErrorValue = NO_ERROR;
+ return(TRUE);
+}
+
+
+/***EP LDRDosFreeModule - Free a dynamic-link module.
+ *
+ *
+ * ENTRY hMod handle of module to free
+ *
+ * EXIT NO_ERROR
+ * ERROR_INVALID_HANDLE
+ */
+
+BOOLEAN
+LDRDosFreeModule(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ P_LDRFREEMODULE_MSG a = &m->u.LdrFreeModule;
+ ldrmte_t *pmte_prog; /* Pointer to process MTE */
+ ldrmte_t *pmte;
+ ldrdld_t *pdld;
+ ldrdld_t *prev_pdld;
+
+ CurrentThread = t;
+
+ //
+ // Set the fForceUnmap flag to TRUE so that ldrUnloadTagedModules()
+ // does unmap the app's freed segments from the app's address space.
+ //
+ fForceUnmap = TRUE;
+
+ //
+ // Verify that the module belongs to the current process
+ //
+ pmte_prog = (ldrmte_t *)t->Process->ProcessMTE;
+ ASSERT(pmte_prog != NULL);
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: DosFreeModule was called\n");
+ }
+#endif
+
+ pdld = pmte_prog->mte_dldchain;
+ prev_pdld = (ldrdld_t *)&pmte_prog->mte_dldchain;
+ while (pdld != NULL) {
+ pmte = pdld->dld_mteptr;
+ if ((pdld->Cookie == (ULONG)CurrentThread->Process) &&
+ (pmte->mte_handle == (USHORT)a->ModuleHandle)) {
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: Going to free module %.*s\n",
+ *(PCHAR)pmte->mte_modname,
+ (PCHAR)pmte->mte_modname + 1
+ );
+ }
+#endif
+ break;
+ }
+ prev_pdld = pdld;
+ pdld = pdld->dld_next;
+ }
+ if (pdld == NULL) {
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ return(TRUE);
+ }
+
+ pdld->dld_usecnt--;
+ if (pdld->dld_usecnt != 0) {
+ m->ReturnedErrorValue = NO_ERROR;
+ return(TRUE);
+ }
+
+ prev_pdld->dld_next = pdld->dld_next;
+ RtlFreeHeap(LDRNEHeap, 0, pdld);
+
+ //
+ // Clear the INGRAPH flag of all modules so that we
+ // know that this module has already been processed
+ //
+ ldrClearAllMteFlag(INGRAPH | USED);
+
+ //
+ // Tag all referenced modules with the USE flag
+ // so that they are not discarded
+ //
+ ldrTagModuleTree_USED(pmte_prog);
+ for (pdld = pmte_prog->mte_dldchain; pdld != NULL; pdld = pdld->dld_next) {
+ if (pdld->Cookie == (ULONG)CurrentThread->Process) {
+ ldrTagModuleTree_USED(pdld->dld_mteptr);
+ }
+ }
+ ldrClearAllMteFlag(INGRAPH);
+
+ //
+ // Tag all referenced modules with the INGRAPH flag
+ // The tagged modules will be then unloaded
+ //
+ ldrTagModuleTree(pmte);
+
+ //
+ // Decrement the usecnt of the marked modules
+ //
+ pmte = mte_h;
+ while (pmte != NULL) {
+ if ((pmte->mte_mflags & INGRAPH) != 0) {
+ pmte->mte_usecnt--;
+ }
+ pmte = pmte->mte_link;
+ }
+
+ ldrUnloadTagedModules(t->Process);
+
+#if DBG
+ IF_OL2_DEBUG ( MTE ) {
+ DbgPrint("\nDumping segmenst after DosFreeModule() processing\n");
+ ldrDisplaySegmentTable();
+ }
+#endif
+
+ m->ReturnedErrorValue = NO_ERROR;
+ return(TRUE);
+}
+
+
+/***EP LDRGetResource - Retrieves the specified resource.
+ *
+ *
+ * ENTRY hmod module handle.
+ * idType resource type identifier.
+ * idName resource name identifier
+ * psel pointer to variable for resource selector
+ *
+ * EXIT NO_ERROR
+ * ERROR_CANT_FIND_RESOURCE
+ * ERROR_INVALID_MODULE
+ * ERROR_INVALID_SELECTOR
+ */
+
+BOOLEAN
+LDRDosGetResource(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ P_LDRGETRESOURCE_MSG a = &m->u.LdrGetResource;
+ ldrmte_t *pmte;
+ ldrsmte_t *psmte;
+ ldrste_t *pste;
+ ULONG lrsrc;
+ ULONG rc;
+ ULONG ModHandle;
+ ULONG ViewSize;
+ ULONG Protect;
+ PVOID MemoryAddress;
+ NTSTATUS Status;
+ ULONG RegionSize;
+ HANDLE SectionHandle;
+
+ CurrentThread = t;
+
+ //
+ // Get resources from first loaded program
+ //
+ if (a->ModuleHandle == 0) {
+ pmte = (ldrmte_t *)t->Process->ProcessMTE;
+ ModHandle = pmte->mte_handle;
+ }
+ else {
+ ModHandle = a->ModuleHandle;
+ if ((pmte = ldrFindMTEForHandle((USHORT)ModHandle)) == NULL) {
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ return(TRUE);
+ }
+ }
+
+ psmte = pmte->mte_swapmte;
+
+ rc = ERROR_INVALID_PARAMETER;
+
+ for (lrsrc = 0; lrsrc < psmte->smte_rsrccnt; lrsrc++) {
+
+ if ((((ldrrsrc16_t *)psmte->smte_rsrctab)[lrsrc].ldrrsrc16_type
+ == (USHORT)a->ResourceType) &&
+ (((ldrrsrc16_t *)psmte->smte_rsrctab)[lrsrc].ldrrsrc16_name
+ == (USHORT)a->ResourceName) ) {
+ rc = NO_ERROR;
+ break;
+ }
+ }
+
+ if (rc == NO_ERROR) {
+ pste = ldrNumToSte(pmte,
+ (psmte->smte_objcnt - psmte->smte_rsrccnt + lrsrc + 1));
+ MemoryAddress = SELTOFLAT(pste->ste_selector);
+ SectionHandle = (HANDLE)pste->ste_seghdl;
+ //
+ // Map the resource into the client address space
+ // Any change in determinig the Protect value should be
+ // done in ldrste.c ldrAllocSegment() too.
+ //
+ if ((pste->ste_flags & STE_DATA) == 0) {
+ // This is a code segment
+ if ((pste->ste_flags & STE_ERONLY) != 0) {
+ // This is an execute only segment
+ Protect = PAGE_EXECUTE;
+ }
+ else {
+ Protect = PAGE_EXECUTE_READ;
+ }
+ }
+ else {
+ // This is a data segment
+ if ((pste->ste_flags & STE_SHARED) != 0) {
+ // This is a shared data segment
+ if ((pste->ste_flags & STE_ERONLY) != 0) {
+ // This is a read only segment
+ Protect = PAGE_READONLY;
+ }
+ else {
+ // This is a read/write segment
+ Protect = PAGE_READWRITE;
+ }
+ }
+ else {
+ // This is a non shared data segment
+ if ((pste->ste_flags & STE_ERONLY) != 0) {
+ // This is a read only segment
+ Protect = PAGE_READONLY;
+ }
+ else {
+ // This is a sizeable read/write segment
+ Protect = PAGE_EXECUTE_WRITECOPY;
+ }
+ }
+ }
+
+ a->ResourceSel = pste->ste_selector | 7;
+ a->ResourceAddr = (ULONG)((pste->ste_selector << 16) & 0xffff0000);
+ a->NumberOfSegments = 0;
+ // This should be performed in a loop for huge resources (longer then a
+ // single segment)
+ for (;
+ ((((ldrrsrc16_t *)psmte->smte_rsrctab)[lrsrc].ldrrsrc16_type
+ == (USHORT)a->ResourceType) &&
+ (((ldrrsrc16_t *)psmte->smte_rsrctab)[lrsrc].ldrrsrc16_name
+ == (USHORT)a->ResourceName) )
+ ; lrsrc++) {
+
+ (a->NumberOfSegments)++;
+ pste = ldrNumToSte(pmte,
+ (psmte->smte_objcnt - psmte->smte_rsrccnt + lrsrc + 1));
+ MemoryAddress = SELTOFLAT(pste->ste_selector);
+ SectionHandle = (HANDLE)pste->ste_seghdl;
+
+ ViewSize = 0;
+ RegionSize = pste->ste_minsiz;
+ if (RegionSize == 0) {
+ RegionSize = _64K;
+ }
+
+ if (Protect == PAGE_EXECUTE_WRITECOPY) {
+ ViewSize = RegionSize;
+ }
+
+ Status = NtMapViewOfSection(SectionHandle,
+ CurrentThread->Process->ProcessHandle,
+ &MemoryAddress,
+ 1,
+ RegionSize,
+ NULL,
+ &ViewSize,
+ ViewUnmap,
+ 0,
+ Protect
+ );
+ //
+ // Don't check for error code as this section may be multiple
+ // mapped because DosFreeResource() does not unmap it.
+ //
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ // DbgPrint("OS2LDR: ldrAllocSegment - Can't map section to client process %x at addr=%x, Status=%x\n",
+ // CurrentThread->Process->ProcessHandle, MemoryAddress, Status);
+#endif
+ }
+
+ ldrSetDescInfo(pste->ste_selector, (ULONG)MemoryAddress,
+ pste->ste_flags, pste->ste_minsiz);
+
+ }
+
+ }
+
+ m->ReturnedErrorValue = rc;
+ return(TRUE);
+}
+
+
+/***EP LDRDosFreeResource - Free a specified resource.
+ *
+ *
+ * ENTRY psel pointer to resource
+ *
+ * EXIT NO_ERROR
+ * ERROR_INVALID_SELECTOR
+ */
+
+BOOLEAN
+LDRDosFreeResource(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ P_LDRFREERESOURCE_MSG a = &m->u.LdrFreeResource;
+
+ CurrentThread = t;
+
+ ldrClearAllMteFlag(INGRAPH | USED);
+
+ m->ReturnedErrorValue = NO_ERROR;
+ return(TRUE);
+}
+
+#if PMNT
+BOOLEAN
+LDRIdentifyCodeSelector(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ P_LDRIDENTIFYCODESELECTOR_MSG a = &m->u.LdrIdentifyCodeSelector;
+ ldrmte_t *pmte_prog; /* Pointer to process MTE */
+ ldrmte_t *pmte;
+ ldrdld_t *pdld;
+ ldrsmte_t *psmte;
+ ldrste_t *pste;
+ ULONG i;
+
+ CurrentThread = t;
+
+ //
+ // Verify that the module belongs to the current process
+ //
+ pmte_prog = (ldrmte_t *)t->Process->ProcessMTE;
+ ASSERT(pmte_prog != NULL);
+
+ //
+ // Clear the INGRAPH flag of all modules so that we
+ // know that this module has already been processed
+ //
+ ldrClearAllMteFlag(INGRAPH | USED);
+
+ //
+ // Tag all referenced modules with the INGRAPH flag
+ // The tagged modules will then be scanned for the desired selector
+ //
+ ldrTagModuleTree(pmte_prog);
+ for (pdld = pmte_prog->mte_dldchain; pdld != NULL; pdld = pdld->dld_next) {
+ ldrTagModuleTree(pdld->dld_mteptr);
+ }
+
+ //
+ // Scan the marked modules for one containing the resized selector
+ //
+ pmte = mte_h;
+ while (pmte != NULL)
+ {
+ if ((pmte->mte_mflags & INGRAPH) != 0)
+ {
+ psmte = pmte->mte_swapmte;
+ pste = (ldrste_t *)psmte->smte_objtab;
+
+ for (i = 1; i <= psmte->smte_objcnt; i++, pste++)
+ {
+ if (((ULONG)(pste->ste_selector | 7) == a->sel))
+ {
+ a->segNum = (USHORT)i;
+ a->mte = pmte->mte_handle;
+ memcpy( a->ModName.Buffer,
+ (PCHAR)psmte->smte_path+14,
+ psmte->smte_pathlen-14);
+ a->ModName.Buffer[psmte->smte_pathlen-14] = '\0';
+
+ return(TRUE);
+ }
+ }
+ }
+ pmte = pmte->mte_link;
+ }
+
+ // Selector not found. Return default values
+ a->segNum = 1;
+ a->mte = 0;
+ strcpy( a->ModName.Buffer, "UNKNOWN");
+
+ m->ReturnedErrorValue = NO_ERROR;
+ return(TRUE);
+}
+#endif // PMNT
+
+/***EP LDRDosQAppType - return file's exe type
+ *
+ * ENTRY pszModName - pointer to ASCII module name
+ * pulType - pointer to put type
+ *
+ * EXIT int - return code (NO_ERROR if successful)
+ */
+
+BOOLEAN
+LDRDosQAppType(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ P_LDRQAPPTYPE_MSG a = &m->u.LdrQAppType;
+
+ IO_STATUS_BLOCK IoStatusBlock;
+ LARGE_INTEGER ByteOffset;
+ ULONG ulNewHdrOff; /* Offset hdr offset */
+ ULONG ulCopied; /* Number of bytes copied */
+ ULONG ulNeeded; /* Number of bytes needed */
+ ULONG usoff; /* Offset to new exe header */
+ struct e32_exe *pe32;
+ struct e32_exe *pe32temp;
+ ldrlv_t lv; /* local variables */
+ PCHAR ptmp;
+ int rc;
+ NTSTATUS Status;
+
+#define NOTSPECIFIED 0x0000
+#define NOTWINDOCOMPAT 0x0001
+#define WINDOWCOMPAT 0x0002
+#define WINDOWAPI 0x0003
+#define BOUND 0x0008
+#define DYNAMICLINK 0x0010
+#define DOSFORMAT 0x0020
+
+ CurrentThread = t;
+
+ /*
+ * Point to ldrLibPathBuf to contain the environment string
+ */
+ strncpy(ldrLibPathBuf, a->PathName.Buffer, SizeOfldrLibPathBuf);
+ ldrLibPathBuf[SizeOfldrLibPathBuf-1] = '\0';
+
+ /*
+ * Check if the App we are loading has any path characters
+ */
+ if (strpbrk(a->AppName.Buffer, ":\\/") == NULL) {
+ lv.lv_class = CLASS_GLOBAL;
+ }
+ else {
+ lv.lv_class = CLASS_SPECIFIC;
+ }
+
+ if ((rc = ldrOpenPath(a->AppName.Buffer,
+ (USHORT)a->AppName.Length,
+ &lv,
+ NULL)) != NO_ERROR) {
+ //
+ // If file was not found, check if the file name has no extension.
+ // If it does not have, try again with the extension .EXE
+ //
+
+ UCHAR NewPathWithExt[MAXPATHLEN];
+
+ memcpy(NewPathWithExt, a->AppName.Buffer, a->AppName.Length);
+ NewPathWithExt[a->AppName.Length] = '\0';
+ ptmp = strrchr(NewPathWithExt, '\\');
+ if (ptmp == NULL) {
+ ptmp = strrchr(NewPathWithExt, '/');
+ if (ptmp == NULL) {
+ ptmp = strrchr(NewPathWithExt, ':');
+ if (ptmp == NULL) {
+ ptmp = NewPathWithExt;
+ }
+ }
+ }
+ ptmp = strchr(ptmp, '.');
+ if (ptmp != NULL) {
+ //
+ // The file has an extension. So, the error returned
+ // previously by ldrOpenPath() is valid
+ //
+ m->ReturnedErrorValue = rc;
+ return(TRUE);
+ }
+ strcpy(&NewPathWithExt[a->AppName.Length], ".EXE");
+ rc = ldrOpenPath(NewPathWithExt,
+ (USHORT)(a->AppName.Length + 4),
+ &lv,
+ NULL);
+ }
+ if (rc != NO_ERROR) {
+ m->ReturnedErrorValue = rc;
+ return(TRUE);
+ }
+
+ pe32 = (struct e32_exe *) pheaderbuf;
+
+ /*
+ * Start read at beginning of file
+ */
+ ByteOffset.LowPart = 0;
+ ByteOffset.HighPart = 0;
+
+ if ((Status = NtReadFile( lv.lv_sfn,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ pe32,
+ 512,
+ &ByteOffset,
+ 0 )) != STATUS_SUCCESS) {
+ NtClose(lv.lv_sfn);
+ m->ReturnedErrorValue = ERROR_FILE_NOT_FOUND;
+ return(TRUE);
+ }
+
+ /*
+ * validate old (MZ) signature in header
+ */
+ if (((struct exe_hdr *) pe32)->e_magic != EMAGIC) {
+ NtClose(lv.lv_sfn);
+ m->ReturnedErrorValue = ERROR_INVALID_EXE_SIGNATURE;
+ return(TRUE);
+ }
+
+ usoff = ((struct exe_hdr *) pe32)->e_lfarlc;
+
+ /*
+ * get pointer to (NE) or (LE) exe header
+ */
+ ulNewHdrOff =
+ lv.lv_new_exe_off = ((struct exe_hdr *) pe32)->e_lfanew;
+
+ /*
+ * check if we read at least up to the (NE) or (LE) header
+ */
+ if (ulNewHdrOff < IoStatusBlock.Information) {
+
+ /*
+ * assume we are reading a 32-bit module
+ */
+ ulNeeded = sizeof(struct e32_exe);
+ pe32temp = (struct e32_exe *) ((ULONG) pe32 + ulNewHdrOff);
+
+ if ((ulNewHdrOff < (IoStatusBlock.Information -
+ sizeof(pe32->e32_magic))) &&
+ (*(short *) (pe32temp->e32_magic) == NEMAGIC))
+ ulNeeded = sizeof(struct new_exe);
+
+ ulCopied = min(IoStatusBlock.Information - ulNewHdrOff, ulNeeded);
+
+ memcpy(pe32, (PVOID) ((ULONG) pe32 + ulNewHdrOff), ulCopied);
+
+ if (ulNeeded -= ulCopied) {
+ if ((Status = NtReadFile( lv.lv_sfn,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ (PCHAR) pe32 + ulCopied,
+ ulNeeded,
+ &ByteOffset,
+ 0 )) != STATUS_SUCCESS) {
+ NtClose(lv.lv_sfn);
+ m->ReturnedErrorValue = ERROR_FILE_NOT_FOUND;
+ return(TRUE);
+ }
+ }
+ }
+ else {
+
+ /*
+ * read in new header to size of 32-bit mte plus a ote entry
+ */
+ ByteOffset.LowPart = (ULONG)((struct exe_hdr *)pe32)->e_lfanew;
+ ByteOffset.HighPart = 0;
+
+ if ((Status = NtReadFile( lv.lv_sfn,
+ 0,
+ 0,
+ 0,
+ &IoStatusBlock,
+ (PCHAR) pe32,
+ sizeof(struct e32_exe)+sizeof(ldrote_t),
+ &ByteOffset,
+ 0 )) != STATUS_SUCCESS) {
+ NtClose(lv.lv_sfn);
+ m->ReturnedErrorValue = ERROR_FILE_NOT_FOUND;
+ return(TRUE);
+ }
+ }
+
+ Status = NtClose(lv.lv_sfn);
+
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(("OS2SRV: Failed to close the file opened for DosQApptype(), Status=%x\n", Status));
+ }
+#endif
+
+ /* Verify that this is a protect-mode exe. (Check this before
+ * checking MTE signature for 1.2 error code compatability.)
+ */
+ if (usoff != 0x40) {
+ a->AppType = DOSFORMAT;
+ m->ReturnedErrorValue = NO_ERROR;
+ return(TRUE);
+ }
+
+ /*
+ * validate as 16-bit signature or 32-bit signature
+ */
+ if (!(*(short *) (pe32->e32_magic) == NEMAGIC)) {
+ m->ReturnedErrorValue = ERROR_INVALID_EXE_SIGNATURE;
+ return(TRUE);
+ }
+
+ a->AppType = 0;
+ if (((struct new_exe *)pe32)->ne_flags & 0x800) {
+ a->AppType |= BOUND;
+ }
+ if (((struct new_exe *)pe32)->ne_flags & 0x8000) {
+ a->AppType |= DYNAMICLINK;
+ }
+ if ((((struct new_exe *)pe32)->ne_flags & 0x700) == 0x100) {
+ a->AppType |= NOTWINDOCOMPAT;
+ }
+ if ((((struct new_exe *)pe32)->ne_flags & 0x700) == 0x200) {
+ a->AppType |= WINDOWCOMPAT;
+ }
+ if ((((struct new_exe *)pe32)->ne_flags & 0x700) == 0x300) {
+ a->AppType |= WINDOWAPI;
+ }
+
+ m->ReturnedErrorValue = NO_ERROR;
+ return(TRUE);
+}
+
+BOOLEAN
+LDRModifySizeOfSharedSegment(
+ IN POS2_THREAD t,
+ IN ULONG Sel,
+ IN ULONG NewLimit
+ )
+{
+ ldrmte_t *pmte_prog; /* Pointer to process MTE */
+ ldrmte_t *pmte;
+ ldrdld_t *pdld;
+ ldrsmte_t *psmte;
+ ldrste_t *pste;
+ ULONG i;
+
+ CurrentThread = t;
+
+ //
+ // Verify that the module belongs to the current process
+ //
+ pmte_prog = (ldrmte_t *)t->Process->ProcessMTE;
+ ASSERT(pmte_prog != NULL);
+
+#if DBG
+ IF_OL2_DEBUG ( TRACE ) {
+ DbgPrint("OS2LDR: LDRModifySizeOfSharedSegment was called\n");
+ }
+#endif
+ //
+ // Clear the INGRAPH flag of all modules so that we
+ // know that this module has already been processed
+ //
+ ldrClearAllMteFlag(INGRAPH | USED);
+
+ //
+ // Tag all referenced modules with the INGRAPH flag
+ // The tagged modules will then be scanned for the desired selector
+ //
+ ldrTagModuleTree(pmte_prog);
+ for (pdld = pmte_prog->mte_dldchain; pdld != NULL; pdld = pdld->dld_next) {
+ ldrTagModuleTree(pdld->dld_mteptr);
+ }
+
+ //
+ // Scan the marked modules for one containing the resized selector
+ //
+ pmte = mte_h;
+ while (pmte != NULL) {
+ if ((pmte->mte_mflags & INGRAPH) != 0) {
+ psmte = pmte->mte_swapmte;
+ pste = (ldrste_t *)psmte->smte_objtab;
+
+ for (i = 1; i <= psmte->smte_objcnt; i++, pste++) {
+ if (((ULONG)(pste->ste_selector | 7) == Sel) &&
+ ((pste->ste_flags & STE_SHARED) != 0)
+ ) {
+ pste->ste_minsiz = (ushort_t)(NewLimit + 1);
+ return(TRUE);
+ }
+ }
+ }
+ pmte = pmte->mte_link;
+ }
+
+ return(FALSE);
+}
+
+VOID
+ldrReturnProgramAndLibMTE(
+ IN POS2_PROCESS Process,
+ OUT USHORT *ProgramMTE,
+ OUT USHORT *LibMTE,
+ OUT USHORT *Cmd
+ )
+{
+ LinkMTE *pMte;
+
+ //
+ // Get the program MTE.
+ //
+ pMte = ((LinkMTE *)Process->LinkMte)->NextMTE;
+
+ *ProgramMTE = pMte->MTE;
+ *LibMTE = 0;
+ *Cmd= TRC_C_SUC_ret;
+
+ while ((pMte != NULL) && (!(pMte->NeedToTransfer))) {
+ pMte = pMte->NextMTE;
+ }
+ if (pMte != NULL) {
+ *LibMTE = pMte->MTE;
+ *Cmd = (USHORT)TRC_C_LIB_ret;
+ pMte->NeedToTransfer = FALSE;
+ ((LinkMTE *)Process->LinkMte)->NeedToTransfer--;
+ }
+
+ return;
+}
diff --git a/private/os2/ldr/ldrutil.c b/private/os2/ldr/ldrutil.c
new file mode 100644
index 000000000..ea701b2ef
--- /dev/null
+++ b/private/os2/ldr/ldrutil.c
@@ -0,0 +1,228 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ldrutil.c
+
+Abstract:
+
+ This module contains various ldr utility routines
+
+Author:
+
+ Beni Lavi (BeniL) 5-Nov-92
+
+Revision History:
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include "os2tile.h"
+#include "ldrextrn.h"
+
+static PVOID ldrBMHeap;
+static RTL_BITMAP ldrBitMapHeader;
+
+static PVOID ldrCGHeap;
+static RTL_BITMAP ldrCallGateHeader;
+static ULONG CallGateHintIndex;
+
+ULONG
+FindTopDownClearBitsAndSet(
+ PRTL_BITMAP pBitMap,
+ ULONG Bits
+ )
+{
+ ULONG Index;
+ ULONG i;
+
+ Index = pBitMap->SizeOfBitMap;
+
+ while (Index >= Bits) {
+ for (i = 1; i <= Bits; i++) {
+ if (RtlCheckBit(pBitMap, Index-i)) {
+ Index -= i;
+ break;
+ }
+ }
+ if (i > Bits) {
+ RtlSetBits( pBitMap,
+ Index+1-i,
+ Bits
+ );
+ return(Index+1-i);
+ }
+ }
+ // failed to find a free entry
+ return(0xffffffff);
+}
+
+BOOLEAN
+ldrCreateSelBitmap(
+ )
+{
+
+ ldrBMHeap = RtlAllocateHeap(Os2Heap, 0, (LDT_DISJOINT_ENTRIES + 7) / 8);
+ if (ldrBMHeap == NULL) {
+ return(FALSE);
+ }
+/*
+ ldrBMHeap = RtlCreateHeap( HEAP_GROWABLE,
+ NULL,
+ 64 * 1024, // Initial size of heap is 64K
+ (LDT_DISJOINT_ENTRIES + 7) / 8, // 8 bits per byte
+ NULL,
+ 0
+ );
+ if (ldrBMHeap == NULL) {
+ return(FALSE);
+ }
+*/
+ RtlInitializeBitMap(&ldrBitMapHeader ,ldrBMHeap, LDT_DISJOINT_ENTRIES);
+ RtlClearAllBits(&ldrBitMapHeader);
+ return(TRUE);
+}
+
+VOID
+ldrMarkAllocatedSel(
+ ULONG NumberOfSel,
+ BOOLEAN MarkFromTop
+ )
+{
+ ULONG StartOfMark = 0;
+
+ if (MarkFromTop) {
+ StartOfMark = ldrBitMapHeader.SizeOfBitMap - NumberOfSel;
+ }
+
+ RtlSetBits( &ldrBitMapHeader,
+ StartOfMark,
+ NumberOfSel
+ );
+}
+
+ULONG
+ldrAllocateSel(
+ ULONG NumberOfSel,
+ BOOLEAN TopDownAllocation
+ )
+{
+ ULONG Index;
+
+ if (TopDownAllocation) {
+ Index = FindTopDownClearBitsAndSet( &ldrBitMapHeader,
+ NumberOfSel
+ );
+ }
+ else {
+ Index = RtlFindClearBitsAndSet( &ldrBitMapHeader,
+ NumberOfSel,
+ 0
+ );
+ }
+ if (Index == 0xffffffff) {
+ return(Index);
+ }
+
+ Index += (_64K / 8) - LDT_DISJOINT_ENTRIES;
+ return((Index << 3) | 7); // convert the index to selector
+}
+
+VOID
+ldrFreeSel(
+ ULONG Sel,
+ ULONG NumberOfSel
+ )
+{
+ if (Sel > _64K) {
+#if DBG
+ KdPrint(("OS2SRV: ldrFreeSel - invalid Sel %x\n", Sel));
+#endif
+ return;
+ }
+ RtlClearBits( &ldrBitMapHeader,
+ (Sel >> 3) - ((_64K / 8) - LDT_DISJOINT_ENTRIES),
+ NumberOfSel
+ );
+}
+
+BOOLEAN
+ldrCreateCallGateBitmap(
+ )
+{
+ ldrCGHeap = RtlAllocateHeap(Os2Heap, 0, _64K / 8);
+ if (ldrCGHeap == NULL) {
+ return(FALSE);
+ }
+/*
+ ldrCGHeap = RtlCreateHeap( HEAP_GROWABLE,
+ NULL,
+ 64 * 1024, // Initial size of heap is 64K
+ _64K / 8, // 8 bits per byte
+ NULL,
+ 0
+ );
+ if (ldrCGHeap == NULL) {
+ return(FALSE);
+ }
+*/
+ RtlInitializeBitMap(&ldrCallGateHeader ,ldrCGHeap, _64K / 8);
+ RtlClearAllBits(&ldrCallGateHeader);
+ return(TRUE);
+}
+
+VOID
+ldrMarkAllocatedCallGates(
+ ULONG NumberOfCallGates
+ )
+{
+ RtlSetBits( &ldrCallGateHeader,
+ 0,
+ NumberOfCallGates
+ );
+ CallGateHintIndex = NumberOfCallGates;
+}
+
+ULONG
+ldrAllocateCallGate()
+{
+ ULONG Index;
+
+ Index = RtlFindClearBitsAndSet( &ldrCallGateHeader,
+ 1,
+ CallGateHintIndex
+ );
+ if (Index == 0xffffffff) {
+ return(Index);
+ }
+
+ return(Index * 8); // 8 bytes for each call gate entry
+}
+
+VOID
+ldrDeallocateCallGate(
+ ULONG CallGate
+ )
+{
+ ULONG Index;
+
+ if (CallGate > _64K) {
+#if DBG
+ KdPrint(("OS2SRV: ldrDeallocateCallGate - invalid callgate %x\n", CallGate));
+#endif
+ return;
+ }
+ Index = CallGate / 8;
+ RtlClearBits( &ldrCallGateHeader,
+ Index,
+ 1
+ );
+ if (Index < CallGateHintIndex) {
+ CallGateHintIndex = Index;
+ }
+}
+
diff --git a/private/os2/ldr/ldrvars.h b/private/os2/ldr/ldrvars.h
new file mode 100644
index 000000000..a02cbf667
--- /dev/null
+++ b/private/os2/ldr/ldrvars.h
@@ -0,0 +1,928 @@
+/* SCCSID = @(#)ldrvars.h 13.100 90/10/11 */
+/*
+ * Microsoft Confidential
+ *
+ * Copyright (c) Microsoft Corporation 1987, 1989
+ *
+ * All Rights Reserved
+ */
+/* INT32 */
+/* XLATOFF */
+
+extern CHAR ldrLibPathBuf[];
+
+extern PCHAR ldrpLibPath;
+
+extern ULONG SizeOfldrLibPathBuf;
+
+typedef unsigned short VMHOB; /* not including vmexport.h */
+
+
+/***ET+ ldrmte_t - MTE */
+
+struct ldrmte_s {
+ uchar_t mte_magic[2]; /* Magic number E32_MAGIC */
+ ushort_t mte_usecnt; /* count of moudules using us */
+ ulong_t mte_mflags; /* Module flags */
+ ulong_t mte_mflags2; /* extension flags word */
+ ulong_t mte_modname; /* pointer to resident module name */
+ ulong_t mte_impmodcnt; /* Num of entries Import Modules */
+ ulong_t mte_modptrs; /* pointer to module pointers table */
+ struct ldrdld_s *mte_dldchain; /* pointer to chain of modules loaded by DosLoadModule() */
+ ushort_t mte_handle; /* the handle for this mte */
+ HANDLE mte_sfn; /* file system number for open file */
+ struct ldrmte_s *mte_link; /* link to next mte */
+ struct ldrsmte_s *mte_swapmte; /* link to swappable mte */
+};
+typedef struct ldrmte_s ldrmte_t; /* Swappable Module table entry */
+
+struct ldrsmte_s {
+ ulong_t smte_eip; /* Starting address for module */
+ ulong_t smte_stackbase; /* Stack base */
+ ulong_t smte_stackinit; /* Init commited stack */
+ ulong_t smte_objtab; /* Object table offset */
+ ulong_t smte_objcnt; /* Number of objects in module */
+ ulong_t smte_fpagetab; /* Offset fixup pg tab for 32-bit */
+ ulong_t smte_expdir; /* Export directory offset */
+ ulong_t smte_impdir; /* Import directory offset */
+ ulong_t smte_fixtab; /* Fixup record table offset */
+ ulong_t smte_rsrctab; /* Offset of Resource Table */
+ ulong_t smte_rsrccnt; /* count of resources */
+ ulong_t smte_filealign; /* Alignment factor */
+ ulong_t smte_vbase; /* Virtual base address of module */
+ ulong_t smte_heapsize; /* use for converted 16-bit modules */
+ ulong_t smte_autods; /* Object # for automatic data obj */
+ ulong_t smte_iat; /* pointer to import address table */
+ ulong_t smte_debuginfo; /* Offset of the debugging info */
+ ulong_t smte_debuglen; /* Len of the debug info in bytes */
+ ulong_t smte_delta; /* difference in load address */
+ ulong_t smte_pfilecache; /* Pointer to file cache for */
+ ulong_t smte_path; /* full pathname */
+ ushort_t smte_pathlen; /* length of full pathname */
+ ushort_t smte_dyntrchndl; /* used by dyn trace */
+ ushort_t smte_semcount; /* Count of threads waiting on MTE
+ semaphore. 0=> semaphore is free */
+ ushort_t smte_semowner; /* Slot number of the owner of MTE
+ semaphore */
+ ulong_t smte_nrestab; /* Offset of non-resident tb 16-bit */
+ ulong_t smte_cbnrestab; /* size of non-resident tb 16-bit */
+ ulong_t smte_csegpack; /* count of segments to pack */
+ ulong_t smte_ssegpack; /* size of object for seg packing */
+ ulong_t smte_spaddr; /* virtual address of packed obj */
+ ushort_t smte_NEflags; /* Orginal flags from NE header */
+ ushort_t smte_NEexpver; /* Expver from NE header */
+ ushort_t smte_NEexetype; /* Exetype from NE header */
+ ushort_t smte_NEflagsothers;/* Flagsothers from NE header */
+};
+typedef struct ldrsmte_s ldrsmte_t; /* Swappable Module table entry */
+
+/*
+ * Defines for 16-bit loading
+ * overlay using unused fields of a (NE) 16-bit MTE.
+ */
+#define smte_stackobj smte_stackbase /* Object # for stack pointer */
+#define smte_esp smte_stackinit /* Extended stack pointer */
+#define smte_smtesize smte_fpagetab /* size of swappable heap debug use */
+#define smte_enttab smte_expdir /* Offset of entry table */
+#define smte_impproc smte_impdir /* Offset of import procedure tb */
+#define smte_restab smte_fixtab /* Offset of resident name table */
+#define smte_alignshift smte_filealign /* File alignment */
+#define smte_impmod smte_iat /* Offset of import module table */
+#define smte_stacksize smte_debuglen /* Size of stack */
+#define smte_startobj smte_delta /* Object # for instruction pointer */
+
+/*
+ * Defines for 32-bit loading
+ * overlay using unused fields of a (LE) 32-bit MTE
+ */
+#define smte_iatsize smte_spaddr /* Size of IAT */
+#define smte_mpages smte_ssegpack /* number of pages in module */
+#define smte_fixupsize smte_csegpack /* fixup table size */
+#define smte_vddfixaddr smte_cbnrestab /* vdd fixup address */
+
+
+/***LK+ Definitions for mte_mflags
+ *
+ * USED and INGRAPH are used by the graph traversl routines. If
+ * the loader semaphore is clear, these bits must both be clear.
+ * See traversal routines for more.
+ *
+ * MTE_INTNL_MASK is the set of bits which are used by the kernel.
+ * These bits are cleared when a module is finished loading.
+ *
+ * LDRINVALID and MTEVALID are overloaded. Once an mte is linked
+ * into the chain, this bit is used to indicate (if set) that the
+ * mte contains valid information that demand loaders (who are not
+ * excluded by the loader semaphore) may examine.
+ *
+ */
+
+#define NOAUTODS 0x00000000 /* No Auto DS exists */
+#define SOLO 0x00000001 /* Auto DS is shared */
+#define INSTANCEDS 0x00000002 /* Auto DS is not shared */
+#define INSTLIBINIT 0x00000004 /* Per-instance Libinit */
+#define GINISETUP 0x00000008 /* Global Init has been setup */
+/* 0x00000010 reserved for NO external fixups in .EXE */
+/* 0x00000020 reserved for NO internal fixups in .EXE */
+#define CLASS_PROGRAM 0x00000040 /* Program class */
+#define CLASS_GLOBAL 0x00000080 /* Global class */
+#define CLASS_SPECIFIC 0x000000C0 /* Specific class, as against global */
+#define CLASS_ALL 0x00000000 /* nonspecific class - all modules */
+#define CLASS_MASK 0x000000C0
+#define MTEPROCESSED 0x00000100 /* MTE being loaded */
+#define USED 0x00000200 /* MTE is referenced - see ldrgc.c */
+#define DOSLIB 0x00000400 /* set if DOSCALL1 */
+#define DOSMOD 0x00000800 /* set if DOSCALLS */
+#define MTE_MEDIAFIXED 0x00001000 /* File Media permits discarding */
+#define LDRINVALID 0x00002000 /* module not loadable */
+#define PROGRAMMOD 0x00000000 /* program module */
+#define DEVDRVMOD 0x00004000 /* device driver module */
+#define LIBRARYMOD 0x00008000 /* DLL module */
+#define VDDMOD 0x00010000 /* VDD module */
+#define MVDMMOD 0x00020000 /* Set if VDD Helper MTE (MVDM.DLL) */
+#define INGRAPH 0x00040000 /* In Module Graph - see ldrgc.c */
+#define GINIDONE 0x00080000 /* Global Init has finished */
+#define MTEADDRALLOCED 0x00100000 /* Allocate specific or not */
+#define FSDMOD 0x00200000 /* FSD MTE */
+#define FSHMOD 0x00400000 /* FS helper MTE */
+#define MTELONGNAMES 0x00800000 /* Module supports long-names */
+#define MTE_MEDIACONTIG 0x01000000 /* File Media contiguous memory req */
+#define MTE_MEDIA16M 0x02000000 /* File Media requires mem below 16M */
+#define MTEIOPLALLOWED 0x04000000 /* Module has IOPL privilege */
+#define MTEPORTHOLE 0x08000000 /* porthole module */
+#define MTEMODPROT 0x10000000 /* Module has shared memory protected */
+#define MTENEWMOD 0x20000000 /* Newly added module */
+#define MTEDLLTERM 0x40000000 /* Gets instance termination */
+#define MTESYMLOADED 0x80000000 /* Set if debugger symbols loaded */
+
+/* The following bits are overloaded or aliased. */
+
+#define MTEVALID (LDRINVALID)
+#define AUTODS_MASK (NOAUTODS|SOLO|INSTANCEDS)
+
+/* The following bits are cleared after each successful module load. */
+
+#define MTE_INTNL_MASK (DOSLIB|DOSMOD|MTEVALID|MTEPROCESSED| \
+ GINISETUP|GINIDONE|USED|INGRAPH|MTENEWMOD)
+
+/*
+ * The following define which modules are "ring 0" for the purpose of
+ * indirect fixups.
+ */
+#define MTE_RING0 (DEVDRVMOD | VDDMOD | MVDMMOD | FSDMOD | FSHMOD)
+
+#define SEARCH_BY_PATH 1 /* FindModule class parameter */
+
+/*end*/
+
+/***ET+ ldrote_s - Object Table entry */
+
+struct _oteres_s {
+ ushort_t _ote_selector; /* store selector used by loader only */
+ ushort_t _ote_handle; /* store handle used by loader only */
+};
+
+/*
+ * Since H2INC will not work correctly with unions to get SIZE of ldrote_t
+ * to return the correct size remove the ulong_t from the assembler declare
+ */
+
+union _oteres_u {
+ struct _oteres_s _ote_res;
+ ulong_t _ote_linkbase; /* store link base address */
+};
+
+
+/* ASM
+_oteres_u STRUC
+ _ote_res DB SIZE _oteres_s DUP (?)
+_oteres_u ENDS
+*/
+
+struct ldrote_s { /* Flat .EXE object table entry */
+ ulong_t ote_base; /* Object virtual base address */
+ ulong_t ote_vsize; /* Virtual memory size */
+ ulong_t ote_pages; /* Image pages offset */
+ ulong_t ote_psize; /* Physical file size of init. data */
+ ulong_t ote_flags; /* Attribute flags for the object */
+ union _oteres_u _ote_resu;
+};
+typedef struct ldrote_s ldrote_t; /* Object table entry */
+
+#define ote_handle _ote_resu._ote_res._ote_handle
+#define ote_selector _ote_resu._ote_res._ote_selector
+#define OBJ_PRELOAD 0x0040L
+
+#define ote_linkbase _ote_resu._ote_linkbase
+
+/* ASM
+ote_linkbase equ <dword ptr _ote_resu>
+*/
+
+#define OBJALLOC 0x80000000L /* Object is allocated used by loader */
+
+/***ET+ ldrote_t - Object Table entry */
+
+#define LGS_FSDMOD 8L /* for ldrGetSelector */
+#define LGS_FSDMODSHF 18L /* for ldrGetSelector */
+#define LGS_VDDMOD 4L /* for ldrGetSelector */
+#define LGS_VDDMODSHF 14L /* for ldrGetSelector */
+#define LGS_DEVDRVMOD 4L /* for ldrGetSelector */
+#define LGS_DEVDRVSHF 12L /* for ldrGetSeletor */
+#define LGS_OBJEXECSHF 2L /* for ldrGetSelector */
+#define LGS_OBJIOPLSHF 14L /* for ldrGetSelector */
+#define LGS_OBJEXEC 1L /* for ldrGetSelector */
+#define LGS_OBJIOPL 2L /* for ldrGetSelector */
+
+#if ((LGS_VDDMOD << LGS_VDDMODSHF) != VDDMOD)
+ error ldrvars.h include file changed /* create compile error */
+#endif
+
+#if ((LGS_OBJEXEC << LGS_OBJEXECSHF) != OBJ_EXEC)
+ error exe386.h include file changed /* create compile error */
+#endif
+
+#if ((LGS_OBJIOPL << LGS_OBJIOPLSHF) != OBJ_IOPL)
+ error exe386.h include file changed /* create compile error */
+#endif
+
+/***ET+ ldropm_t - Object Page Map */
+
+typedef struct o32_map ldropm_t; /* Object Page Map */
+
+
+/***ET+ ldrste_t - Segment Table entry */
+
+struct ldrste_s {
+ ushort_t ste_offset; /* file offset to segment data */
+ ushort_t ste_size; /* file data size */
+ ushort_t ste_flags; /* type and attribute flags */
+ ushort_t ste_minsiz; /* minimum allocation size */
+ ulong_t ste_seghdl; /* segment handle returned by NtCreateSection() */
+ ulong_t ste_fixups; /* fixup record storage */
+ ushort_t ste_selector; /* segment selector */
+ ushort_t ste_pad; /* pad ldrste_s to 4 bytes */
+
+};
+ /* ste_flags bit definitions */
+/* XLATON */
+#define STE_TYPE_MASK 0x0001 /* segment type field */
+#define STE_CODE 0x0000 /* code segment type */
+#define STE_DATA 0x0001 /* data segment type */
+#define STE_PACKED 0x0002 /* segment is packed */
+#define STE_SEMAPHORE 0x0004 /* segment semaphore */
+#define STE_ITERATED 0x0008 /* segment data is iterated */
+#define STE_WAITING 0x0010 /* segment is waiting on semephore */
+#define STE_SHARED 0x0020 /* segment can be shared */
+#define STE_PRELOAD 0x0040 /* segment is preload */
+#define STE_ERONLY 0x0080 /* excute only if code segment */
+ /* read only if data segment */
+#define STE_RELOCINFO 0x0100 /* set if segment has reloc records */
+#define STE_CONFORM 0x0200 /* segment is conforming */
+#define STE_RING_2 0x0800 /* ring 2 selector */
+#define STE_RING_3 0x0C00 /* ring 3 selector */
+#define STE_SEGDPL 0x0C00 /* I/O privilege level */
+#define STE_HUGE 0x1000 /* huge segment */
+#define STE_PAGEABLE 0x2000 /* just a page can be faulted in */
+#define STE_PRESENT 0x2000 /* packed segment already loaded */
+#define STE_SELALLOC 0x4000 /* used to indicate sel allocated */
+#define STE_GDTSEG 0x8000 /* used to indicate GTD sel alloc */
+
+#define STE_HUGE_MASK STE_TYPE_MASK|STE_SHARED|STE_SEGDPL
+#define STE_RSRC_HUGE STE_HUGE_MASK & ((NOT STE_TYPE_MASK)|STE_PRELOAD)
+
+#define ISRSRC 1 /* flag to indice we have a rsrc seg */
+/* XLATOFF */
+typedef struct ldrste_s ldrste_t; /* Segment table entry */
+
+struct ri_s { /* relocation data item */
+ uchar_t ri_stype; /* sources type */
+ uchar_t ri_flags; /* target type */
+ ushort_t ri_source; /* source offset */
+ ushort_t ri_target_seg; /* target segment index */
+ ushort_t ri_target_off; /* target entry offset index */
+};
+
+typedef struct ri_s ri_t;
+
+#define ri_target_modnam ri_target_seg
+#define ri_target_impnam ri_target_off
+#define ri_target_ord ri_target_off
+
+#define RELOCSPERBUF 8
+#define RELOCBUFLEN (sizeof(struct ri_s) * RELOCSPERBUF)
+
+#define SOURCE_MASK 0x07
+#define BYTE_ADR 0x00 /* Byte source location */
+#define SEG_ADR 0x02 /* Base source location */
+#define FAR_ADR 0x03 /* Pointer source location */
+#define OFF_ADR 0x05 /* Offset source location */
+#define TARGET_MASK 0x03
+#define INTERNALREF 0x00
+#define IMPORTORDINAL 0x01
+#define IMPORTNAME 0x02
+#define ADDITIVE 0x04
+
+/*
+ * The sfr_s is used to store segment fixup information so we can
+ * page segments.
+ *
+ * If sfr_fchained, then sfr_soff holds the count of chain records
+ * immediately following the fixup data bytes (sfr_bytes). If records
+ * are not chained, then sfr_soff holds the page offset for the fixup
+ * data.
+ *
+ */
+#define SFR_DATALEN 4
+struct sfr_s { // Segment fixup record
+ unsigned short sfr_fchained:1; // Flag: Is it chained
+ unsigned short sfr_fixsize:3; // Number of bytes in fixup
+ unsigned short sfr_soff:12; // Page offset or count of fixups
+ unsigned char sfr_bytes[SFR_DATALEN]; // Fixup data bytes
+ } ;
+
+typedef struct sfr_s sfr_t;
+
+#define SFR_HEADSIZE (sizeof(sfr_t)-SFR_DATALEN)
+
+#define PAGESPERSEGMENT 16
+
+/*
+ * segfix iterated record
+ */
+struct sfir_s {
+ ulong_t sfir_doffset; // Offset into data file
+ ushort_t sfir_soffset; // Offset into segment
+ ushort_t sfir_cbdata; // Number of bytes in record
+ ushort_t sfir_count; // Number of iterations
+};
+
+typedef struct sfir_s sfir_t;
+
+
+
+struct ldret_s /* General entry table types */
+{
+ unsigned char et_cnt; /* Number of entries in this bundle */
+ unsigned char et_type; /* Bundle type */
+ unsigned short et_obj; /* Object number */
+}; /* Follows entry types */
+
+typedef struct ldret_s ldret_t;
+
+/***EC+ B16 - 16-bit bundle types */
+#define EMPTY 0x00 /* empty bundle */
+#define B16EMPTY EMPTY /* empty bundle */
+#define B16ABSOLUTE 0xFE /* absolute entry bundle */
+#define B16MOVABLE 0xFF /* movable entry bundle */
+/*end*/
+
+/***ET+ ldrcte_t - Loader call thunk entry for 16-bit entry table */
+
+#pragma pack(1)
+struct ldrcte_s {
+ uchar_t cte_flags; /* entry flags */
+ ushort_t cte_sel; /* space for callgate selector */
+ uchar_t cte_obj; /* object index */
+ ushort_t cte_off; /* offset of routine entry point */
+};
+
+typedef struct ldrcte_s ldrcte_t; /* Loader call thunk entry */
+/*end*/
+
+/***ET+ ldrent_t - Loader Exported entry for 16-bit entry table */
+
+struct ldrent_s {
+ uchar_t ent_flags; /* entry flags */
+ ushort_t ent_off; /* offset of routine entry point */
+};
+
+#pragma pack()
+
+typedef struct ldrent_s ldrent_t; /* Loader exported entry */
+/*end*/
+
+/***+ ldrempty_t unused entry */
+struct ldrempty_s {
+ uchar_t empty_count; /* count of empty entries */
+ uchar_t empty_type; /* type 0 for empty */
+};
+
+typedef struct ldrempty_s ldrempty_t;
+/*end*/
+
+/***ET+ ldrfwd_t forwarder entry table entry */
+struct ldrfwd_s {
+ uchar_t fwd_flags; /* entry flags */
+ ushort_t fwd_modord; /* module ordinal */
+ ulong_t fwd_value; /* offset in table, or ordinal */
+ };
+
+typedef struct ldrfwd_s ldrfwd_t;
+/*end*/
+
+/***ET+ ldrfrt_t 32-bit fixup page table */
+
+#define fr_stype nr_stype
+#define fr_flags nr_flags
+
+typedef struct r32_rlc ldrfrt_t;
+/*end*/
+
+struct ldrefrt_s { /* expanded fixup record */
+ ulong_t efr_tgt; /* 32-bit target field */
+ ulong_t efr_add; /* addtive value */
+ ushort_t efr_srcoff; /* source offset */
+ ushort_t efr_tobj; /* target object or ordinal */
+ uchar_t efr_stype; /* source type */
+ uchar_t efr_flags; /* flags */
+ uchar_t efr_cchain; /* count for chained records */
+};
+
+typedef struct ldrefrt_s ldrefrt_t;
+
+struct objmem_s {
+ ulong_t flobj; /* allocation flags needed */
+};
+
+
+/*
+ * Warning this structure must match the structure defined in the ASM
+ * part at the end of this file
+ */
+
+struct taddr_s {
+ ulong_t toff;
+ ushort_t tsel;
+ uchar_t tflags;
+ /*
+ * For use by ldrGetFwdEnt():
+ */
+ uchar_t fflags; /* forwarder flags */
+ ushort_t cgsel; /* callgate selector */
+};
+
+/* The structure of a non-resident name table is as follows: */
+
+struct nonres_s {
+ struct nonres_s *nr_link; /* link to next non-resident table */
+ ushort_t nr_mte; /* mte handle to which names belong */
+ uchar_t nr_names; /* nonresident nametable from file */
+};
+
+// #define NT_TYPEINFO 0x80 // YosefD Mar-24-1996 Not in use
+#define E32EXPORT 0x01
+
+#if 0
+struct bndl_s {
+ uchar_t bndl_cnt;
+ uchar_t bndl_type;
+};
+#endif
+
+struct hit_s {
+ ulong_t offset; /* offset of field in mte */
+ ulong_t cnt; /* count of bytes to copy */
+};
+
+struct his_s {
+ ulong_t offset; /* offset of field in ste */
+ ulong_t cnt; /* count of bytes to copy */
+};
+
+struct etmt_s {
+ ushort_t offset; /* offset of field in linker exe image */
+};
+
+struct zmt_s {
+ ushort_t offset; /* offset of field in swappable MTE */
+ uchar_t size; /* size of field */
+ uchar_t zero; /* flag to zero or not */
+};
+
+struct objflags_s {
+ ulong_t flobj; /* object's flags */
+ ulong_t flVM; /* required allocation flags */
+};
+
+struct selflags_s {
+ ulong_t flobj; /*object's flags */
+ ushort_t fsSEL; /* required allocation flags */
+};
+
+struct pgstatechg_s {
+ ulong_t flpage; /* allocation flags needed */
+};
+
+
+/***ET+ ldrlv_t - Loader local variables */
+
+struct ldrlv_s {
+ ldrmte_t *lv_pmte; /* pointer to mte */
+ ulong_t lv_lbufaddr; /* linear addr of alloc buf from PG */
+ ulong_t lv_sbufaddr; /* segment addr of alloc buf from PG */
+ ulong_t lv_new_exe_off; /* offset relative begin of new exe */
+ HANDLE lv_sfn; /* current system file number */
+ ushort_t lv_hobmte; /* handle of current mte */
+ ulong_t lv_objnum; /* object number */
+ ushort_t lv_class; /* module class */
+ uchar_t lv_type; /* module type */
+};
+
+typedef struct ldrlv_s ldrlv_t; /* Loader local variables */
+
+/*end*/
+
+/***ET+ ldrrsrc16_t 16-bit Resource structure */
+
+struct ldrrsrc16_s {
+ ushort_t ldrrsrc16_type;
+ ushort_t ldrrsrc16_name;
+};
+
+typedef struct ldrrsrc16_s ldrrsrc16_t;
+/*end*/
+
+
+/***ET+ ldrrsrc32_t 32-bit Resource structure */
+
+struct ldrrsrc32_s {
+ ushort_t rsrctype; /* Resource type */
+ ushort_t rsrcname; /* Resource name */
+ ulong_t rsrccb; /* Resource size */
+ ushort_t rsrccodepage; /* Resource codepage */
+ ushort_t rsrcobj; /* Obj num rsrc is found in */
+ ulong_t rsrcoffset; /* Offset within object */
+};
+
+typedef struct ldrrsrc32_s ldrrsrc32_t;
+/*end*/
+
+
+/***ET+ Resource segment structure, kept in BMP segment */
+
+struct ldrrsrc_s {
+ ulong_t rsrc_typeid; /* resource type id */
+ ulong_t rsrc_nameid; /* resource name id */
+ ushort_t rsrc_mte; /* owner */
+ ushort_t rsrc_refcount; /* local reference count */
+ ushort_t rsrc_localptr; /* local PTDA chain */
+ ushort_t rsrc_globalptr; /* global chain */
+};
+
+typedef struct ldrrsrc_s ldrrsrc_t;
+/*end*/
+
+
+/***ET+ ldrrrsrc_t Return Resource structure */
+
+struct ldrrrsrc_s {
+ ptr_t ldrrrsrc_ptr;
+ int ldrrrsrc_type;
+};
+
+typedef struct ldrrrsrc_s ldrrrsrc_t;
+
+/***ET+ ldrrsrcinfo_t Store resource info */
+
+struct ldrrsrcinfo_s {
+ ulong_t ldrrsrcinfo_flag;
+ ulong_t ldrrsrcinfo_size;
+ ulong_t ldrrsrcinfo_pote;
+ ulong_t ldrrsrcinfo_iatsize;
+};
+typedef struct ldrrsrcinfo_s ldrrsrcinfo_t;
+
+/***ET+ ldrwhois_t who is sructure */
+
+struct ldrwhois_s {
+ ushort_t whois_ssegnum;
+ ushort_t whois_hmte;
+ uchar_t whois_achname[256];
+};
+
+typedef struct ldrwhois_s ldrwhois_t;
+/*end*/
+
+#define STRINGNULLTERM 0
+#define STRINGNONNULL 1
+#define NO_FORCE_PRELOAD 0
+#define FORCE_PRELOAD 1
+#define MAX_DEMAND_READ 8 /* current we can only read 8 pages */
+#ifdef RANGE
+#define RANGEINVALID (INVALID | RANGE)
+#define RANGEZEROED (ZEROED | RANGE)
+#endif
+
+#define LOAD_PAGE 0 /* return value for LDRGetPGInfo */
+#define LOAD_SEGMENT 1 /* return value for LDRGetPGInfo */
+#define ALIGNMENT_SHIFT 512 /* logical sector alignment shift */
+#define ENDMTETBL 0xDEAD /* mark end of validatetbl */
+#define rsrcvalidatetbl 3 /* rsrc table is 3rd entry in tbl */
+#define SKIPCOPY -1
+
+#define MAX_NAME_LEN 8
+#define MAX_PROC_LEN 256 /* Max proc name length incl. NUL */
+#define MAXPATHLEN 260
+
+#define EXT_PROGRAM 0 /* program */
+#define EXT_LIBRARY 1 /* library */
+#define EXT_DEVICE 2 /* device driver */
+#define EXT_FSD 3 /* installable file system */
+#define EXT_VDD 4 /* VDD */
+
+#define CHECK_ALL 1 /* Use full set off invalid chars */
+#define CHECK_WILDCARDS 2 /* Use wild card char set */
+#define MIN_CHAR_VALUE 0x20 /* space */
+#define LDR_16bit 0 /* 16-bit module */
+#define LDR_32bit 1 /* 32-bit module */
+#define LDR_PORTHOLE 2 /* Porthole Init module */
+#define EF_EXPORT 1 /* entry is exported */
+#define EF_GDATA 2 /* entry uses global shared data */
+
+/*
+ * Sub-function code for DosQueryHeaderInfo
+ */
+#define HEADER_EXEINFO 1 /* return fields values from EXE hdr */
+#define HEADER_READRSRCTBL 2 /* return pointer of rsrc table */
+#define HEADER_READSECTOR 3 /* read resource table */
+#define HEADER_LIBPATHLEN 4 /* return length of LIBPATH */
+#define HEADER_LIBPATH 5 /* return LIBPATH string */
+#define HEADER_FIXENTRY 6 /* fix a value in entry table */
+#define HEADER_STE 7 /* return segment table info */
+#define HEADER_MAPSEL 8 /* map selector to segment number */
+
+
+/***LT+ ldrdld_t - Loader Demand Load Data.
+ *
+ * Each process (PTDA) has a chain of ldrdld records, managed
+ * by the loader, allocated from the kernel heap, to keep track
+ * of the runtime attachments to a process.
+ *
+ * The ldrdld records are created on the initial attachment
+ * to a module via a DOSLOADMODULE call, setting ldrdld_cRef
+ * to 1. Subsequent DOSLOADMODULE calls increment ldrdld_cRef
+ * for the appropriate record. ldrdld_cRef is decremented when
+ * the program calls DOSFREEMODULE, and the record is removed
+ * if ldrdld_cRef goes to Zero. The entire chain of ldrdld
+ * records is freed when the process dies, in LDRFreeTask.
+ */
+
+struct ldrdld_s {
+ struct ldrdld_s *dld_next; // MUST be first element in structure!
+ ldrmte_t *dld_mteptr;
+ ULONG Cookie; // This field holds a unique value for each
+ // process. We chose the address of the process's
+ // OS2_PROCESS data structure.
+ ULONG dld_usecnt;
+};
+
+typedef struct ldrdld_s ldrdld_t;
+
+
+/***LT ldrpip_t - page count packet
+ * used by ldrMakeIDCache32, getpages and ldrProcessObjects
+ */
+struct ldrpip_s {
+ ulong_t pip_pbuf; /* Pointer to load buffer */
+ int pip_spbf; /* Starting page in load buffer */
+ int pip_cpbf; /* Count of pages in load buffer */
+ int pip_maxp; /* Max. page to read */
+};
+typedef struct ldrpip_s ldrpip_t;
+
+/**LT ldrmodhdr - return structure for MTE info
+ * used to return info from the MTE.
+ */
+struct ldrmhdr_s {
+ ushort_t mhdr_flags; /* ne_flags */
+ ushort_t mhdr_flagsothers; /* ne_flagsothers */
+ ushort_t mhdr_exetyp; /* ne_exetyp */
+ ushort_t mhdr_expver; /* ne_expver */
+ ulong_t mhdr_rsrctab; /* mte_rsrctab */
+ ulong_t mhdr_restab; /* mte_restab */
+ ushort_t mhdr_sfn; /* sfn */
+};
+typedef struct ldrmhdr_s ldrmhdr_t;
+
+#ifdef KM_REG_DS
+/***LT dllterm_t - DLL termination data buffer
+ *
+ * This buffer contains the registers of the caller of
+ * DosFreeModule as well as all the handles of all the
+ * modules requiring termination notification.
+ */
+
+struct dllterm_s {
+ struct dllterm_s *dllt_pdlltnext; /* Next record in chain */
+ struct kmreg_s dllt_regs; /* User registers */
+ ushort_t dllt_chmod; /* # of module handles left to call */
+ VMHOB dllt_ahmod[1]; /* Array of handles (var length) */
+};
+typedef struct dllterm_s dllterm_t;
+#endif
+
+
+/**LT ldrnewseg - return structure for STE info
+ * used to return info from the STE
+ */
+struct newseg { /* Segment Table entry info */
+ USHORT ns_sector; /* file sector of start of segment */
+ USHORT ns_cbseg; /* number of bytes in file */
+ USHORT ns_flags; /* attribute flags */
+ USHORT ns_minalloc; /* minimum alloc in bytes */
+};
+typedef struct ldrnewseg_s ldrnewseg_t;
+
+#define ldrNumToSte(pmte, objnum) ((ldrste_t *) ldrNumToOte(pmte, objnum))
+
+#define LEMAGIC ((E32MAGIC2 << 8) | (E32MAGIC1))
+#define ldrIsLE(pmte) (*(short *) ((pmte)->mte_magic) == LEMAGIC)
+#define ldrIsNE(pmte) (*(short *) ((pmte)->mte_magic) == NEMAGIC)
+#define MAX_PRELOAD 10
+
+#define RESIZE64K(cb) (cb? (ulong_t) cb : (ulong_t) 64*1024)
+#define TCYIELD_CNT 31
+#define RSRC32TYPEID 0xffffffff
+#define LDRMAXHEAPCACHE 2048 /* Max. size of cache to put on heap */
+#define _5K 5*1024
+#define MINSEGPACKCNT ldrMINSEGPACKCNT
+#define MINPGPACKSIZE ldrMINPGPACKSIZE
+#define MAXSEGPACKSIZE ldrMAXSEGPACKSIZE
+#define HEADERBUFSIZE 512
+#define PAGESHIFT 12
+#define PAGESIZE (1 << PAGESHIFT)
+#define PAGEMASK (PAGESIZE - 1)
+#define WORDMASK 0xffff
+#define BYTEMASK 0xff
+#define WORDSHIFT 16
+
+/***LP ldrAssert - cause internal error if assertion fails
+ *
+ * Given a boolean, this procedure causes an internal error if
+ * the boolean is false. Typically, the value of this boolean is
+ * derived from some test expression.
+ *
+ * ldrAssert (e)
+ *
+ * ENTRY e - boolean value (int)
+ * RETURN NONE
+ *
+ * CALLS panicfmt
+ *
+ * WARNING This procedure is implemented as a macro.
+ *
+ * EFFECTS NONE
+ */
+#ifdef LDRSTRICT
+# define ldrAssert(e) _assert(e)
+#else
+# define ldrAssert(e)
+#endif
+
+
+/***LP ldrStop - stop in kernel debugger
+ *
+ * If the global ldrErr is TRUE and the mte pointer is not doscalls
+ * or is null, this routine transfers control to the kernel debugger.
+ *
+ * ldrStop (id, pmte)
+ *
+ * ENTRY id - identifier of caller (ignored)
+ * pmte - mte pointer or NULL
+ * RETURN NONE
+ *
+ * CALLS Debug_BreakDM
+ *
+ * EFFECTS NONE
+ */
+#if DBG
+ extern void ldrStop(int id, void *pmte);
+#else
+#define ldrStop(id, pmte)
+#endif
+
+/*
+ * Forwarder declarations
+ */
+extern int ldrGetFwdEnt(struct AuxData *, ldrmte_t *);
+extern int ldrSelToFwdFlg (ushort_t);
+extern int ldrGetImport (ldrmte_t *, ulong_t, ushort_t, int,
+ ldrmte_t **, ushort_t *);
+/*
+ * Values for forwarder flags after processing:
+ */
+#define FWD_ALIAS16 0x01 /* Target object requires 16:16 alias */
+#define FWD_SPECIAL 0x02 /* DOSMOD, FSHMOD, MVDMMOD */
+#define FWD_PROCESSED 0x04 /* Forwarder has been processed */
+#define FWD_SHIFT 3 /* Flat target selector field is 0x38 */
+#define FWD_GATE16 0x40 /* 286 call gate */
+#define FWD_IOPL 0x80 /* Target object has I/O privilege */
+
+/*
+ * Other forwarder constants.
+ */
+#define ERROR_LDR_FWD -1 /* Return code indicating forwarder */
+#define LDRFWDMAX 1024 /* Max length of forwarder chain */
+#define SMALLFWDMAX 3 /* Max length of chain to fix up in memory */
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+extern ldrmte_t *mte_h; /* head of linked mte list */
+
+extern ldrmte_t *program_h; /* head of list of
+ program modules */
+extern ldrmte_t *program_l; /* tail of list of
+ program modules */
+extern ldrmte_t *global_h; /* head of list of
+ global modules */
+extern ldrmte_t *global_l; /* tail of list of
+ global modules */
+extern ldrmte_t *specific_h; /* head of list of
+ specific modules */
+extern ldrmte_t *specific_l; /* tail of list of
+ specific modules */
+extern ushort_t validatetbl[]; /* validation table */
+extern struct etmt_s ExeToResMTETbl[];/* Reduce EXE image to MTE */
+extern struct etmt_s ExeTo32SwapMTETbl[];/* Reduce EXE to LE MTE */
+extern struct etmt_s ExeTo16SwapMTETbl[];/* Reduce EXE to NE MTE */
+extern struct objflags_s objflags[]; /* object flags table */
+extern struct selflags_s selflags[]; /* selector flags table */
+extern struct objmem_s objmem[]; /* memory type flags table */
+extern struct pgstatechg_s pgstatechg[]; /* set type table */
+extern ushort_t ldrInitCallGate;
+extern ulong_t ldrMINSEGPACKCNT;
+extern ulong_t ldrMINPGPACKSIZE;
+extern ulong_t ldrMAXSEGPACKSIZE;
+extern char LdrBuf[MAXPATHLEN+14]; // 14 is for the '\OS2SS\DRIVES\'
+
+extern void load_error(int errcode, ldrmte_t * pmte);
+
+extern USHORT LDRDoscallsSel;
+
+#define FIELDOFFSET(type,field) ((USHORT)&(((type *)0)->field))
+
+/***LP fMTEValid - Validate if MTE has a valid signature */
+#define fMTEValid(pmte) (ldrIsNE(pmte) || ldrIsLE(pmte))
+
+extern PUCHAR ldrSrcModNameBuf;
+extern ushort_t ldrSrcModNameBufL;
+extern PUCHAR ldrTgtModNameBuf;
+extern ushort_t ldrTgtModNameBufL;
+extern PUCHAR ldrProcNameBuf;
+extern ushort_t ldrProcNameBufL;
+#if PMNT
+extern PUCHAR ldrSaveSrcModNameBuf;
+extern ushort_t ldrSaveSrcModNameBufL;
+extern PUCHAR ldrSaveTgtModNameBuf;
+extern ushort_t ldrSaveTgtModNameBufL;
+extern PUCHAR ldrSaveProcNameBuf;
+extern ushort_t ldrSaveProcNameBufL;
+extern int ldrSaveRc;
+#endif
+
+/***LP ldrSetupSrcErrTxt - Sets up source module name in error text buffer
+ ***LP ldrInvSrcErrTxt - Invalidates source module in error text buffer
+ *
+ * This procedure is implemented as a macro.
+ *
+ * ENTRY pachmodname - ModuleName/FullPathName string
+ * cchmodname - length of string
+ *
+ * EXIT none - ldrSrcModNameBuf[L] is setup
+ *
+ */
+#define ldrSetupSrcErrTxt(pachmodname, cchmodname) \
+ ldrSrcModNameBuf = pachmodname; \
+ ldrSrcModNameBufL = cchmodname
+
+#define ldrInvSrcErrTxt() \
+ ldrSrcModNameBufL = 0;
+
+/***LP ldrSetupTgtErrTxt - Sets up target module name in error text buffer
+ ***LP ldrInvTgtErrTxt - Invalidates target module in error text buffer
+ *
+ * This procedure is implemented as a macro.
+ *
+ * ENTRY pachmodname - ModuleName/FullPathName string
+ * cchmodname - length of string
+ *
+ * EXIT none - ldrTgtModNameBuf[L] is setup
+ *
+ */
+#define ldrSetupTgtErrTxt(pachmodname, cchmodname) \
+ ldrTgtModNameBuf = pachmodname; \
+ ldrTgtModNameBufL = cchmodname
+
+#define ldrInvTgtErrTxt() \
+ ldrTgtModNameBufL = 0;
+
+#pragma pack(1)
+typedef struct _R2CallInfo {
+ UCHAR R2CallNearInst; // Opcode of the call near inst 0xFF
+ USHORT R2CommonEntry; // This field will contain a 400H
+ UCHAR R2BytesToCopy; // Total size of proc parameters to copy between stacks
+ USHORT R2EntryPointOff; // Offset of entry address of R2 routine
+ USHORT R2EntryPointSel; // Selector of entry address of R2 routine
+} R2CallInfo, *PR2CallInfo;
+#pragma pack()
+
diff --git a/private/os2/ldr/ldrvars.inc b/private/os2/ldr/ldrvars.inc
new file mode 100644
index 000000000..2893fb8d3
--- /dev/null
+++ b/private/os2/ldr/ldrvars.inc
@@ -0,0 +1,23 @@
+STE_TYPE_MASK EQU 0001H
+STE_CODE EQU 0000H
+STE_DATA EQU 0001H
+STE_PACKED EQU 0002H
+STE_SEMAPHORE EQU 0004H
+STE_ITERATED EQU 0008H
+STE_WAITING EQU 0010H
+STE_SHARED EQU 0020H
+STE_PRELOAD EQU 0040H
+STE_ERONLY EQU 0080H
+STE_RELOCINFO EQU 0100H
+STE_CONFORM EQU 0200H
+STE_RING_2 EQU 0800H
+STE_RING_3 EQU 0C00H
+STE_SEGDPL EQU 0C00H
+STE_HUGE EQU 1000H
+STE_PAGEABLE EQU 2000H
+STE_PRESENT EQU 2000H
+STE_SELALLOC EQU 4000H
+STE_GDTSEG EQU 8000H
+STE_HUGE_MASK EQU STE_TYPE_MASK OR STE_SHARED OR STE_SEGDPL
+STE_RSRC_HUGE EQU STE_HUGE_MASK AND ((NOT STE_TYPE_MASK) OR STE_PRELOAD)
+ISRSRC EQU 1
diff --git a/private/os2/ldr/makefile b/private/os2/ldr/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/os2/ldr/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/os2/ldr/mi.h b/private/os2/ldr/mi.h
new file mode 100644
index 000000000..65eebc912
--- /dev/null
+++ b/private/os2/ldr/mi.h
@@ -0,0 +1,497 @@
+/*static char *SCCSID = "@(#)mi.h 6.1 90/11/15";*/
+/*
+ * Machine instruction, flag definitions and character types
+ *
+ * SCCSID = @(#)mi.h 13.17 90/09/13
+ */
+
+// 386 eflags definitions
+
+#define F_AC 0x00040000 // (A)lignment (C)heck
+#define F_VM 0x00020000 // (V)irtual 8086 (M)ode
+#define F_RF 0x00010000 // (R)esume (F)lag
+#define F_NT 0x00004000 // (N)ested (T)ask
+#define F_NTCLEAR (~F_NT)
+#define F_IOPL0 0
+#define F_IOPL1 0x00001000
+#define F_IOPL2 0x00002000
+#define F_IOPL3 0x00003000
+#define F_IOPLMASK 0x00003000 // (I)/(O) (P)rivilege (L)evel
+#define F_IOPLSYS F_IOPL3 // wide open
+#define F_IOPLclear (~F_IOPLMASK)
+#define F_OVERFLOW 0x00000800
+#define F_DIRECTION 0x00000400
+#define F_INTERRUPT 0x00000200
+#define F_TRACE 0x00000100
+#define F_SIGN 0x00000080
+#define F_ZERO 0x00000040
+#define F_AUX 0x00000010
+#define F_PARITY 0x00000004
+#define F_CARRY 0x00000001
+#define F_UNDEFINED 0x0000802A
+
+// CR0 (Machine Status Register) bits
+
+#define CR0_PE 0x00000001 // (P)rotect (E)nable
+#define CR0_MP 0x00000002 // (M)onitor (P)rocessor extension
+#define CR0_EM 0x00000004 // (EM)ulate processor extension
+#define CR0_TS 0x00000008 // (T)ask (thread) (S)witched
+#define CR0_ET 0x00000010 // (E)xtension (T)ype, 0/1=287/387
+#define CR0_NE 0x00000020 // (N)umeric (E)xception 0/1=use 2/10h
+#define CR0_WP 0x00010000 // (W)rite (P)rotect in rings 0-2
+#define CR0_AM 0x00040000 // (A)lignment (M)ask, enable EFlags.AC
+#define CR0_NW 0x20000000 // (N)o (W)rite-through cache
+#define CR0_CD 0x40000000 // (C)ache (D)isable
+#define CR0_PG 0x80000000 // (P)a(G)ing enable
+#define CR0_RESERVED 0x1ffaffc0 // reserved bits
+
+/*
+ * Cache Operating Modes:
+ *
+ * CR0_CD CR0_NW Cache Fills Write-Throughs and Invalidates
+ * ------ ------ ----------- ------------------------------
+ * 1 1 disabled disabled
+ * 1 0 disabled enabled
+ * 0 1 INVALID combination - CR0 load causes GP fault
+ * 0 0 enabled enabled (Normal mode)
+ */
+
+// Machine Status Word bits (obsolete)
+
+#define MSW_PE CR0_PE
+#define MSW_MP CR0_MP
+#define MSW_EM CR0_EM
+#define MSW_TS CR0_TS
+#define MSW_ET CR0_ET
+
+// CR3 (Page Directory Base Register) bits
+
+#define CR3_WRITETHROUGH 0x00000008 // write-through cache (486 ignores)
+#define CR3_CACHEDISABLE 0x00000010 // cache disable
+#define CR3_FRAME 0xfffff000 // page directory physical frame number
+#define CR3_RESERVED 0x00000fe7 // reserved bits
+
+// Debug Registers
+
+#define DR_COUNT 0x4 // number of debug registers
+
+// DR6 (Debug Registers Status Register) bits
+
+#define DR6_B0 0x00000001 // breakpoint register 0 triggered
+#define DR6_B1 0x00000002 // breakpoint register 1 triggered
+#define DR6_B2 0x00000004 // breakpoint register 2 triggered
+#define DR6_B3 0x00000008 // breakpoint register 3 triggered
+#define DR6_BD 0x00002000 // ICE hardware active
+#define DR6_BS_BIT_INDEX 0xe // Single step trap
+#define DR6_BS (1 << DR6_BS_BIT_INDEX)
+#define DR6_BT 0x00008000 // TSS trap
+
+#define DR6_VALID (DR6_B0|DR6_B1|DR6_B2|DR6_B3|DR6_BD|DR6_BS|DR6_BT)
+#define DR6_RESERVED ~(DR6_VALID)
+
+// DR7 (Debug Register Control Register) bits
+
+#define DR7_L0 0x00000001 /* DR0 Local Enable */
+#define DR7_G0 0x00000002 /* DR0 Global Enable */
+#define DR7_L1 0x00000004 /* DR1 Local Enable */
+#define DR7_G1 0x00000008 /* DR1 Global Enable */
+#define DR7_L2 0x00000010 /* DR2 Local Enable */
+#define DR7_G2 0x00000020 /* DR2 Global Enable */
+#define DR7_L3 0x00000040 /* DR3 Local Enable */
+#define DR7_G3 0x00000080 /* DR3 Global Enable */
+
+#define DR7_LE 0x00000100 /* Local - Exact Match */
+#define DR7_GE 0x00000200 /* Global - Exact Match */
+
+#define DR7_RW0 0x00030000 /* DR0 RW bits */
+#define DR7_LEN0 0x000c0000 /* DR0 Len bits */
+#define DR7_RW1 0x00300000 /* DR1 RW bits */
+#define DR7_LEN1 0x00c00000 /* DR1 Len bits */
+#define DR7_RW2 0x03000000 /* DR2 RW bits */
+#define DR7_LEN2 0x0c000000 /* DR2 Len bits */
+#define DR7_RW3 0x30000000 /* DR3 RW bits */
+#define DR7_LEN3 0xc0000000 /* DR3 Len bits */
+
+#define DR7_RESERVED 0x0000fc00 /* DR7 Intel Reserved */
+
+#define DR7_EXECUTE 0x0 /* Execute */
+#define DR7_WRITE 0x1 /* Data Write */
+#define DR7_READWRITE 0x3 /* Data Read or Write */
+
+#define DR7_LEN_1 0x0 /* Length 1 bits */
+#define DR7_LEN_2 0x1 /* Length 2 */
+#define DR7_LEN_4 0x3 /* Length 4 */
+
+// Machine instruction, flag definitions and character types
+
+#define MI_ARPL 0x63 // ARPL instruction
+#define MI_HLT 0xf4 // HLT instruction
+#define MI_OPERANDSIZE 0x66 // Operand size override prefix
+#define MI_ADDRESSSIZE 0x67 // Address size override prefix
+#define MI_TWOBYTEOP 0x0f // Two byte opcode prefix
+
+#define MI_POP_DS 0x1f
+#define MI_POP_ES 0x07
+#define MI_POP_FS 0xA1 // second byte to 0Fh opcode
+#define MI_POP_GS 0xA9 // second byte to 0Fh opcode
+
+#define MI_INT3 0xCC
+#define MI_INT 0xCD
+#define MI_IRET 0xCF
+#define MI_LONG_JMP 0xEA
+#define MI_LONG_CALL 0x9A
+#define MI_LONG_RET 0xCB
+#define MI_LONG_RETn 0xCA
+#define MI_NEAR_RET 0xC3
+
+#define MI_IN_PORT_AL 0xE4 // Opcode of IN port,AL
+#define MI_IN_PORT_AX 0xE5 // Opcode of IN port,AX
+#define MI_OUT_PORT_AL 0xE6 // Opcode of OUT port,AL
+#define MI_OUT_PORT_AX 0xE7 // Opcode of OUT port,AX
+#define MI_IN_DX_AL 0xEC // Opcode of IN DX,AL
+#define MI_IN_DX_AX 0xED // Opcode of IN DX,AX
+#define MI_OUT_DX_AL 0xEE // Opcode of OUT DX,AL
+#define MI_OUT_DX_AX 0xEF // Opcode of OUT DX,AX
+
+#define MI_GROUP5 0xFF // 5th group of 11-bit opcode inst.s
+#define MI_SEGES 0x26 // ES override prefix
+#define MI_SEGCS 0x2E // CS override prefix
+#define MI_SEGSS 0x36 // SS override prefix
+#define MI_SEGDS 0x3E // DS override prefix
+#define MI_SEGFS 0x64 // FS override prefix
+#define MI_SEGGS 0x65 // GS override prefix
+
+// ESC opcode prefix and mask
+
+#define MI_ESCMASK 0xF8
+#define MI_ESC 0xD8
+
+// MOD field equates
+
+#define MI_MODMASK 0xC0 // MOD field mask
+#define MI_MODSHIFT 6 // MOD field shift
+#define MI_MODNONE 0x00 // MOD = 0 (no displacement)
+#define MI_MODBYTE 0x40 // MOD = 1 (byte displacement)
+#define MI_MODWORD 0x80 // MOD = 2 (word displacement)
+#define MI_MODREG 0xC0 // MOD = 3 (R/M field selects register)
+
+// REG field equates
+
+#define MI_REGMASK 0x38 // REG field mask
+#define MI_REGSHIFT 3 // REG field shift
+#define MI_REGAX 0x00 // REG = 0 (AX/AL)
+#define MI_REGCX 0x08 // REG = 1 (CX/CL)
+#define MI_REGDX 0x10 // REG = 2 (DX/DL)
+#define MI_REGBX 0x18 // REG = 3 (BX/BL)
+#define MI_REG3 0x18 // REG = 3 (part of 11-bit opcode)
+#define MI_REGSP 0x20 // REG = 4 (SP/AH)
+#define MI_REGBP 0x28 // REG = 5 (BP/CH)
+#define MI_REGSI 0x30 // REG = 6 (SI/DH)
+#define MI_REGDI 0x38 // REG = 7 (DI/BH)
+
+#define MI_REGES 0x00 // REG = 0 MOV seg,r/m or MOV r/m,seg
+#define MI_REGCS 0x08 // REG = 1
+#define MI_REGSS 0x10 // REG = 2
+#define MI_REGDS 0x18 // REG = 3
+#define MI_REGFS 0x20 // REG = 4
+#define MI_REGGS 0x28 // REG = 5
+
+// R/M field equates for memory operands (for 16-bit instructions)
+
+#define MI_RMMASK 0x07 // R/M field mask
+#define MI_RMSHIFT 0 // R/M field shift
+#define MI_RMBXSI 0x00 // R/M = 0 ([BX+SI])
+#define MI_RMBXDI 0x01 // R/M = 1 ([BX+DI])
+#define MI_RMBPSI 0x02 // R/M = 2 ([BP+SI])
+#define MI_RMBPDI 0x03 // R/M = 3 ([BP+DI])
+#define MI_RMSI 0x04 // R/M = 4 ([SI])
+#define MI_RMDI 0x05 // R/M = 5 ([DI])
+#define MI_RMBP 0x06 // R/M = 6 ([BP])
+#define MI_RMBX 0x07 // R/M = 7 ([BX])
+
+// 32 bit instruction equates
+
+#define MI_SIB_SSMASK 0xc0
+#define MI_SIB_SSSHIFT 0x06
+
+#define MI_SIB_INDEXMASK 0x38
+#define MI_SIB_INDEXSHIFT 0x03
+#define MI_SIB_INDEXNONE 0x20
+
+#define MI_SIB_BASEMASK 0x07
+#define MI_SIB_BASESHIFT 0x00
+#define MI_SIB_BASEESP 0x04
+#define MI_SIB_BASENONE 0x05
+
+#define MI_RMEDX 0x02
+#define MI_RMSIB 0x04
+#define MI_RMDISP 0x05
+#define MI_RMEBP 0x05
+
+#define MI_REG6 0x30
+#define MI_REGCR0 0x00
+
+// following machine instructions are used in Enable_386_Specific_code
+// in virtmgr.asm
+
+#define MI_PUSH_AX 0x50 // "push ax" instruction
+#define MI_PUSH_IMM 0x68 // "push immediate 16/32" instruction
+#define MI_MOV_REG_IMM 0xB8 // opcode for "mov reg,immediate" instr
+#define MI_MOV_REG_IMMEDIATE 0xB8 // opcode for "mov reg,immediate" instr
+#define MI_MOV_REG_REGMEM 0x8B // opcode for "mov reg,r/m 16/32" instr
+
+// Miscellaneous Opcodes
+
+#define MI_ADD_AX_IMM 0x05 // Opcode for Add (E)AX,imm(32)16
+#define MI_CALL_NEAR_REL 0xE8 // Opcode for Call NEAR (relative)
+#define SIZE_CALL_NEAR_REL 5 // Length of Call NEAR (relative) instr
+
+#define MI_LMSW_OPCODE 0x01 // LMSW
+
+#define MI_GET_CRx_OPCODE 0x20 // MOV r32,CRx
+#define MI_GET_DRx_OPCODE 0x21 // MOV r32,DRx
+#define MI_SET_CRx_OPCODE 0x22 // MOV CRx,r32
+#define MI_SET_DRx_OPCODE 0x23 // MOV DRx,r32
+#define MI_GET_TRx_OPCODE 0x24 // MOV r32,TRx
+#define MI_SET_TRx_OPCODE 0x26 // MOV TRx,r32
+
+#define MI_MOV_REG8_MEM8 0x8A // MOV reg8,mem8
+#define MI_MOV_SEG_MEM_OPCODE 0x8e // MOV seg,r/m16
+
+// WORD structure
+
+struct w_s {
+ uchar_t lobyte;
+ uchar_t hibyte;
+};
+#define LowByte lobyte
+#define HighByte hibyte
+
+// DWORD structure
+
+struct dw_s {
+ ushort_t loword;
+ ushort_t hiword;
+};
+
+// Far pointer structure
+
+struct FarPtr {
+ ushort_t Offst;
+ ushort_t Segmt;
+};
+
+// Far 32 bit pointer structure
+
+struct FarPtr32 {
+ ulong_t Offst32; // 32 bit offset
+ ushort_t Segmt32; // segment
+ ushort_t Pad32; // segment pad
+};
+
+/*** RETF16 - 16 bit RETF frame definition
+ *
+ * 16 bit RETF frame structure
+ */
+
+typedef struct retf16_s {
+ ushort_t retf16_ip;
+ ushort_t retf16_cs;
+} RETF16;
+
+typedef RETF16 *PRETF16;
+
+/*** RETF32 - 32 bit RETF frame definition
+ *
+ * 32 bit RETF frame structure
+ */
+
+typedef struct retf32_s {
+ ulong_t retf32_eip;
+ ushort_t retf32_cs;
+ ushort_t retf32_padcs;
+} RETF32;
+
+typedef RETF32 *PRETF32;
+
+/*** IRET16 - 16 bit IRET frame definition
+ *
+ * 16 bit IRET frame structure
+ */
+
+typedef struct iret16_s {
+ ushort_t iret16_ip;
+ ushort_t iret16_cs;
+ ushort_t iret16_flag;
+} IRET16;
+
+typedef IRET16 *PIRET16;
+
+// 16 bit Iret stack frame without privilege level transition
+
+struct Iret_s {
+ struct FarPtr I_CSIP;
+ ushort_t I_FLAGS;
+};
+
+struct IretFrame {
+ ushort_t IretIP ;
+ ushort_t IretCS ;
+ ushort_t IretFLAGS;
+};
+
+/* ASM IretCSIP EQU <DWORD PTR IretIP> */
+
+/*** IRET32 - 32 bit IRET frame definition
+ *
+ * 32 bit IRET frame structure
+ */
+
+typedef struct iret32_s {
+ ulong_t iret32_eip;
+ ushort_t iret32_cs;
+ ushort_t iret32_padcs;
+ ulong_t iret32_eflag;
+} IRET32;
+
+typedef IRET32 *PIRET32;
+
+// 32 bit Iret stack frame without privilege level transition
+
+struct Iret32_s {
+ struct FarPtr32 I32_CSEIP;
+ ulong_t I32_EFLAGS;
+};
+/* ASM
+I32_CS EQU <I32_CSEIP.Segmt32>
+I32_EIP EQU <I32_CSEIP.Offst32>
+I32_IP EQU <I32_CSEIP.Offst32.loword>
+I32_FLAGS EQU <I32_EFLAGS.loword>
+*/
+
+/*** PLTIRET16 - 16 bit IRET frame definition
+ *
+ * 16 bit IRET frame structure with privilege level transtion
+ */
+
+typedef struct pltiret16_s {
+ ushort_t pltiret16_ip;
+ ushort_t pltiret16_cs;
+ ushort_t pltiret16_flag;
+ ushort_t pltiret16_sp;
+ ushort_t pltiret16_ss;
+} PLTIRET16;
+
+typedef PLTIRET16 *PPLTIRET16;
+
+// 16 bit Protected mode iret stack frame with privilege level transition
+
+struct PLTIret_s {
+ struct FarPtr PI_CSIP;
+ ushort_t PI_FLAGS;
+ struct FarPtr PI_SSSP;
+};
+
+struct PLTIretFrame {
+ ushort_t PLTIretIP;
+ ushort_t PLTIretCS;
+ ushort_t PLTIretFLAGS;
+ ushort_t PLTIretSP;
+ ushort_t PLTIretSS;
+};
+
+/* ASM
+PLTIretCSIP EQU DWORD PTR PLTIretIP
+PLTIretSSSP EQU DWORD PTR PLTIretSP
+*/
+
+/*** PLTIRET32 - 32 bit IRET frame definition
+ *
+ * 32 bit IRET frame structure with privilege level transtion
+ */
+
+typedef struct pltiret32_s {
+ ulong_t pltiret32_eip;
+ ushort_t pltiret32_cs;
+ ushort_t pltiret32_padcs;
+ ulong_t pltiret32_eflag;
+ ulong_t pltiret32_esp;
+ ushort_t pltiret32_ss;
+ ushort_t pltiret32_padss;
+} PLTIRET32;
+
+typedef PLTIRET32 *PPLTIRET32;
+
+// 32 bit Protected mode iret stack frame with privilege level transition
+
+struct PLTIret32_s {
+ struct FarPtr32 PI32_CSEIP;
+ ulong_t PI32_EFLAGS;
+ struct FarPtr32 PI32_SSESP;
+};
+/* ASM
+PI32_CS EQU <PI32_CSEIP.Segmt32>
+PI32_EIP EQU <PI32_CSEIP.Offst32>
+PI32_SS EQU <PI32_SSESP.Segmt32>
+PI32_ESP EQU <PI32_SSESP.Offst32>
+PI32_FLAGS EQU <WORD PTR PI32_EFLAGS>
+*/
+
+// Generic 32-bit pointer structure
+
+/* XLATOFF */
+union ptr_u {
+ struct FarPtr ptr_far16; /* 16-bit far pointer */
+ ulong_t ptr_flat; /* 32-bit flat pointer */
+};
+typedef union ptr_u ptr_t; /* Generic pointer type */
+
+#define ptr_sel ptr_far16.Segmt
+#define ptr_off ptr_far16.Offst
+/* XLATON */
+
+/* ASM
+ptr_t STRUC
+ ptr_flat DD ?
+ptr_t ENDS
+ptr_off equ <ptr_flat.Offst>
+ptr_sel equ <ptr_flat.Segmt>
+*/
+
+
+// PUSHA stack frame
+
+struct pusha_s {
+ ushort_t pas_di;
+ ushort_t pas_si;
+ ushort_t pas_bp;
+ ushort_t pas_sp;
+ ushort_t pas_bx;
+ ushort_t pas_dx;
+ ushort_t pas_cx;
+ ushort_t pas_ax;
+};
+
+// PUSHAD stack frame
+
+struct pushad_s {
+ ulong_t pads_edi;
+ ulong_t pads_esi;
+ ulong_t pads_ebp;
+ ulong_t pads_esp;
+ ulong_t pads_ebx;
+ ulong_t pads_edx;
+ ulong_t pads_ecx;
+ ulong_t pads_eax;
+};
+
+/* ASM
+pads_di EQU <WORD PTR pads_edi>
+pads_si EQU <WORD PTR pads_esi>
+pads_bp EQU <WORD PTR pads_ebp>
+pads_sp EQU <WORD PTR pads_esp>
+pads_bx EQU <WORD PTR pads_ebx>
+pads_dx EQU <WORD PTR pads_edx>
+pads_cx EQU <WORD PTR pads_ecx>
+pads_ax EQU <WORD PTR pads_eax>
+*/
diff --git a/private/os2/ldr/newexe.h b/private/os2/ldr/newexe.h
new file mode 100644
index 000000000..305db12fd
--- /dev/null
+++ b/private/os2/ldr/newexe.h
@@ -0,0 +1,464 @@
+/*static char *SCCSID = "@(#)newexe.h 6.2 91/02/12";*/
+/*
+ * SCCSID = @(#)newexe.h 6.2 91/02/12
+ *
+ * Title
+ *
+ * newexe.h
+ * (C) Copyright Microsoft Corp 1984-1987
+ *
+ * Description
+ *
+ * Data structure definitions for the DOS 4.0/Windows 2.0
+ * executable file format.
+ *
+ */
+
+
+
+ /*_________________________________________________________________*
+ | |
+ | |
+ | DOS3 .EXE FILE HEADER DEFINITION |
+ | |
+ |_________________________________________________________________|
+ * */
+
+
+#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 (OLD) */
+#define ERES1WDS 0x0004 /* No. of reserved words in e_res */
+#define ERES2WDS 0x000A /* No. of reserved words in e_res2 */
+#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[ERES1WDS];/* Reserved words */
+ unsigned short e_oemid; /* OEM identifier (for e_oeminfo) */
+ unsigned short e_oeminfo; /* OEM information; e_oemid specific */
+ unsigned short e_res2[ERES2WDS];/* 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_OEMID(x) (x).e_oemid
+#define E_OEMINFO(x) (x).e_oeminfo
+#define E_RES2(x) (x).e_res2
+#define E_LFANEW(x) (x).e_lfanew
+
+
+ /*_________________________________________________________________*
+ | |
+ | |
+ | OS/2 & WINDOWS .EXE FILE HEADER DEFINITION - 286 version |
+ | |
+ |_________________________________________________________________|
+ * */
+
+#define NEMAGIC 0x454E /* New magic number */
+#define NERESBYTES 8 /* Eight bytes reserved (now) */
+#define NECRC 8 /* Offset into new header of NE_CRC */
+
+struct new_exe /* New .EXE header */
+ {
+ unsigned short ne_magic; /* Magic number NE_MAGIC */
+ unsigned char ne_ver; /* Version number */
+ unsigned char ne_rev; /* Revision number */
+ unsigned short ne_enttab; /* Offset of Entry Table */
+ unsigned short ne_cbenttab; /* Number of bytes in Entry Table */
+ long ne_crc; /* Checksum of whole file */
+ unsigned short ne_flags; /* Flag word */
+ unsigned short ne_autodata; /* Automatic data segment number */
+ unsigned short ne_heap; /* Initial heap allocation */
+ unsigned short ne_stack; /* Initial stack allocation */
+ long ne_csip; /* Initial CS:IP setting */
+ long ne_sssp; /* Initial SS:SP setting */
+ unsigned short ne_cseg; /* Count of file segments */
+ unsigned short ne_cmod; /* Entries in Module Reference Table */
+ unsigned short ne_cbnrestab; /* Size of non-resident name table */
+ unsigned short ne_segtab; /* Offset of Segment Table */
+ unsigned short ne_rsrctab; /* Offset of Resource Table */
+ unsigned short ne_restab; /* Offset of resident name table */
+ unsigned short ne_modtab; /* Offset of Module Reference Table */
+ unsigned short ne_imptab; /* Offset of Imported Names Table */
+ long ne_nrestab; /* Offset of Non-resident Names Table */
+ unsigned short ne_cmovent; /* Count of movable entries */
+ unsigned short ne_align; /* Segment alignment shift count */
+ unsigned short ne_cres; /* Count of resource entries */
+ unsigned char ne_exetyp; /* Target operating system */
+ unsigned char ne_flagsothers; /* Other .EXE flags */
+ char ne_res[NERESBYTES];
+ /* Pad structure to 64 bytes */
+ };
+
+#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_CRES(x) (x).ne_cres
+#define NE_RES(x) (x).ne_res
+#define NE_EXETYP(x) (x).ne_exetyp
+#define NE_FLAGSOTHERS(x) (x).ne_flagsothers
+
+#define NE_USAGE(x) (WORD)*((WORD *)(x)+1)
+#define NE_PNEXTEXE(x) (WORD)(x).ne_cbenttab
+#define NE_ONEWEXE(x) (WORD)(x).ne_crc
+#define NE_PFILEINFO(x) (WORD)((DWORD)(x).ne_crc >> 16)
+
+
+/*
+ * Target operating systems
+ */
+
+#define NE_UNKNOWN 0x0 /* Unknown (any "new-format" OS) */
+#define NE_OS2 0x1 /* Microsoft/IBM OS/2 (default) */
+#define NE_WINDOWS 0x2 /* Microsoft Windows */
+#define NE_DOS4 0x3 /* Microsoft MS-DOS 4.x */
+#define NE_DEV386 0x4 /* Microsoft Windows 386 */
+
+
+/*
+ * Format of NE_FLAGS(x):
+ *
+ * p Not-a-process
+ * x Unused
+ * e Errors in image
+ * x Unused
+ * b Bound Family/API
+ * ttt Application type
+ * f Floating-point instructions
+ * 3 386 instructions
+ * 2 286 instructions
+ * 0 8086 instructions
+ * P Protected mode only
+ * p Per-process library initialization
+ * i Instance data
+ * s Solo data
+ */
+#define NENOTP 0x8000 /* Not a process */
+#if PMNT
+#define NEPMSHELL 0x4000 /* PM Shell */
+#define NEPMMSGQUE 0x1000 /* calls WinCreateMsgQueue */
+#endif
+#define NEIERR 0x2000 /* Errors in image */
+#define NEBOUND 0x0800 /* Bound Family/API */
+#define NEAPPTYP 0x0700 /* Application type mask */
+#define NENOTWINCOMPAT 0x0100 /* Not compatible with P.M. Windowing */
+#define NEWINCOMPAT 0x0200 /* Compatible with P.M. Windowing */
+#define NEWINAPI 0x0300 /* Uses P.M. Windowing API */
+#define NEFLTP 0x0080 /* Floating-point instructions */
+#define NEI386 0x0040 /* 386 instructions */
+#define NEI286 0x0020 /* 286 instructions */
+#define NEI086 0x0010 /* 8086 instructions */
+#define NEPROT 0x0008 /* Runs in protected mode only */
+#define NEPPLI 0x0004 /* Per-Process Library Initialization */
+#define NEINST 0x0002 /* Instance data */
+#define NESOLO 0x0001 /* Solo data */
+
+/*
+ * Format of NE_FLAGSOTHERS(x):
+ *
+ * 7 6 5 4 3 2 1 0 - bit no
+ * |
+ * +---------------- Support for long file names
+ *
+ */
+
+#define NELONGNAMES 0x01
+
+
+
+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 */
+ };
+
+#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)
+ *
+ * Flag word has the following format:
+ *
+ * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - bit no
+ * | | | | | | | | | | | | | | |
+ * | | | | | | | | | | | | +-+-+--- Segment type DATA/CODE
+ * | | | | | | | | | | | +--------- Iterated segment
+ * | | | | | | | | | | +----------- Movable segment
+ * | | | | | | | | | +------------- Segment can be shared
+ * | | | | | | | | +--------------- Preload segment
+ * | | | | | | | +----------------- Execute/read-only for code/data segment
+ * | | | | | | +------------------- Segment has relocations
+ * | | | | | +--------------------- Code conforming/Data is expand down
+ * | | | +--+----------------------- I/O privilege level
+ * | | +----------------------------- Discardable segment
+ * | +-------------------------------- 32-bit code segment
+ * +----------------------------------- Huge segment/GDT allocation requested
+ *
+ */
+
+#define NSTYPE 0x0007 /* Segment type mask */
+
+#if (EXE386 == 0)
+#define NSCODE 0x0000 /* Code segment */
+#define NSDATA 0x0001 /* Data segment */
+#define NSITER 0x0008 /* Iterated segment flag */
+#define NSMOVE 0x0010 /* Movable segment flag */
+#define NSSHARED 0x0020 /* Shared 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 NSCONFORM 0x0200 /* Conforming segment */
+#define NSEXPDOWN 0x0200 /* Data segment is expand down */
+#define NSDPL 0x0C00 /* I/O privilege level (286 DPL bits) */
+#define SHIFTDPL 10 /* Left shift count for SEGDPL field */
+#define NSDISCARD 0x1000 /* Segment is discardable */
+#define NS32BIT 0x2000 /* 32-bit code segment */
+#define NSHUGE 0x4000 /* Huge memory segment, length of
+ * segment and minimum allocation
+ * size are in segment sector units
+ */
+#define NSGDT 0x8000 /* GDT allocation requested */
+
+#define NSPURE NSSHARED /* For compatibility */
+
+#define NSALIGN 9 /* Segment data aligned on 512 byte boundaries */
+
+#define NSLOADED 0x0004 /* ns_sector field contains memory addr */
+#endif
+
+
+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 */
+
+#pragma pack(1)
+
+
+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 */
+ struct
+ {
+ unsigned short nr_ostype; /* OSFIXUP type */
+ unsigned short nr_osres; /* reserved */
+ } nr_osfix; /* Operating system fixup */
+ } nr_union; /* Union */
+ };
+
+#pragma pack()
+
+
+#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
+#define NR_OSTYPE(x) (x).nr_union.nr_osfix.nr_ostype
+#define NR_OSRES(x) (x).nr_union.nr_osfix.nr_osres
+
+
+
+/*
+ * Format of NR_STYPE(x) and R32_STYPE(x):
+ *
+ * 7 6 5 4 3 2 1 0 - bit no
+ * | | | |
+ * +-+-+-+--- source type
+ *
+ */
+
+#define NRSTYP 0x0f /* Source type mask */
+#define NRSBYT 0x00 /* lo byte (8-bits)*/
+#define NRSSEG 0x02 /* 16-bit segment (16-bits) */
+#define NRSPTR 0x03 /* 16:16 pointer (32-bits) */
+#define NRSOFF 0x05 /* 16-bit offset (16-bits) */
+#define NRPTR48 0x06 /* 16:32 pointer (48-bits) */
+#define NROFF32 0x07 /* 32-bit offset (32-bits) */
+#define NRSOFF32 0x08 /* 32-bit self-relative offset (32-bits) */
+
+
+/*
+ * Format of NR_FLAGS(x) and R32_FLAGS(x):
+ *
+ * 7 6 5 4 3 2 1 0 - bit no
+ * | | |
+ * | +-+--- Reference type
+ * +------- Additive fixup
+ */
+
+#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 NRROSF 0x03 /* Operating system fixup */
+
+
+#if (EXE386 == 0)
+
+/* 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 0xF000 /* Discard priority level for resource */
+
+/* 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
+
+
+#endif /* NOT EXE386 */
diff --git a/private/os2/ldr/os2defp.h b/private/os2/ldr/os2defp.h
new file mode 100644
index 000000000..fc727553e
--- /dev/null
+++ b/private/os2/ldr/os2defp.h
@@ -0,0 +1,30 @@
+/*static char *SCCSID = "@(#)os2defp.h 6.1 90/11/15";*/
+/*static char *SCCSID = "@(#)os2defp.h 13.6 90/08/28";*/
+/***************************************************************************\
+*
+* Module Name: OS2DEFP.H
+*
+* OS/2 Private common definitions include file
+*
+* Copyright (c) 1987 Microsoft Corporation
+*
+\***************************************************************************/
+
+typedef unsigned long ulong_t;
+typedef unsigned short ushort_t;
+typedef unsigned char uchar_t;
+typedef unsigned long vaddr_t;
+
+/* XLATOFF */
+typedef unsigned long dword;
+typedef unsigned short word;
+typedef unsigned char byte;
+
+typedef unsigned long DWORD;
+typedef unsigned short WORD;
+
+/* XLATON */
+
+typedef unsigned short SEL;
+
+/* XLATOFF */
diff --git a/private/os2/ldr/seldesc.h b/private/os2/ldr/seldesc.h
new file mode 100644
index 000000000..c54bb4862
--- /dev/null
+++ b/private/os2/ldr/seldesc.h
@@ -0,0 +1,265 @@
+/*static char *SCCSID = "@(#)seldesc.h 6.1 90/11/16";*/
+/* SCCSID = @(#)seldesc.h 13.2 90/07/10 */
+
+
+/*
+ * Microsoft Confidential
+ *
+ * Copyright (c) Microsoft Corporation 1987, 1989
+ *
+ * All Rights Reserved
+ */
+
+
+/*
+;----------------------------------------------------
+;
+; Some useful definitions
+;
+;----------------------------------------------------
+*/
+
+/* Definitions for selector fields */
+
+#define TABLE_MASK 0x004
+#define RPL_MASK 0x003
+#define RPL_CLR 0x0fffc
+
+#define RPL_RING0 0x000
+#define RPL_RING1 0x001
+#define RPL_RING2 0x002
+#define RPL_RING3 0x003
+
+
+
+/*
+; ---------------------------------------------------
+;
+; Definitions for the access byte in a descriptor
+;
+; ---------------------------------------------------
+*/
+
+/* Following fields are common to segment and control descriptors */
+
+#define D_PRES 0x80 /* present in memory */
+#define D_NOTPRES 0 /* not present in memory*/
+
+#define D_DPL0 0 /* Ring 0 */
+#define D_DPL1 0x20 /* Ring 1 */
+#define D_DPL2 0x40 /* Ring 2 */
+#define D_DPL3 0x60 /* Ring 3 */
+#define D_PRIV D_DPL3 /* DPL mask */
+
+#define D_SEG 0x10 /* Segment descriptor */
+#define D_CTRL 0 /* Control descriptor */
+
+
+/* Following fields are specific to control descriptors */
+
+#define D_TSS_BUSY_BIT 0x2 /* TSS busy bit */
+#define D_GATE 0x4 /* gate bit */
+#define D_32 0x8 /* 32 bit gate/descriptor bit */
+#define D_TSS 0x1 /* A Free TSS */
+#define D_LDT 0x2 /* LDT */
+#define D_TSS_BUSY (D_TSS+D_TSS_BUSY_BIT) /* A Busy TSS */
+#define D_CALLGATE (D_GATE+0) /* call gate */
+#define D_TASKGATE (D_GATE+1) /* task gate */
+#define D_INTGATE (D_GATE+2) /* interrupt gate */
+#define D_TRAPGATE (D_GATE+3) /* trap gate */
+#define D_TSS32 (D_TSS+D_32) /* 32 bit TSS */
+#define D_TSSBUSY32 (D_TSS_BUSY+D_32) /* busy 32 bit TSS */
+#define D_CALLGATE32 (D_CALLGATE+D_32) /* 32 bit call gate */
+#define D_INTGATE32 (D_INTGATE+D_32) /* 32 bit interrupt gate */
+#define D_TRAPGATE32 (D_TRAPGATE+D_32) /* 32 bit trap gate */
+
+#define D_TYPEMASK 0x0f /* descriptor type mask */
+#define D_WCMASK 0x01f /* word count mask (call gates) */
+#define D_MINGATE D_CALLGATE /* lowest numerical gate type */
+#define D_MAXGATE D_TRAPGATE32 /* highest numerical gate type */
+
+#define D_TSSBUSY_CLR (~D_TSS_BUSY_BIT)
+
+/* Following fields are specific to segment descriptors */
+
+#define D_CODE 0x8 /* code */
+#define D_DATA 0 /* data */
+
+#define D_CONFORM 0x4 /* if code, conforming */
+#define D_EXPDN 0x4 /* if data, expand down */
+
+#define D_RX 0x2 /* if code, readable */
+#define D_X 0 /* if code, exec only */
+#define D_W 0x2 /* if data, writable */
+#define D_R 0 /* if data, read only */
+
+#define D_ACCESSED 0x1 /* segment accessed bit */
+
+/*
+; ---------------------------------------------------
+;
+; Definitions for the attribute byte in a descriptor
+;
+; ---------------------------------------------------
+*/
+
+#define D_GRAN4K 0x80 /* 4k granularity (limit only) */
+#define D_COPER32 0x40 /* code: use 32 bit operand size */
+#define D_DBIG D_COPER32 /* data: use 32 bit offsets */
+#define D_PAD 0x20 /* unused */
+#define D_UVIRT 0x10 /* PhysToUvirt selector */
+#define D_EXTLIMIT 0x0f /* extended limit mask */
+#define D_1MEG 0x100000 /* 1 Meg */
+#define D_GRANMASK 0x0fffff /* 1Meg - 1 */
+
+/* Useful combination access rights bytes */
+
+#define D_DATA0 (D_PRES+D_DPL0+D_SEG+D_DATA+D_W) /* Ring 0 rw data */
+#define D_CODE0 (D_PRES+D_DPL0+D_SEG+D_CODE+D_RX) /* Ring 0 rx code */
+#define D_TRAP0 (D_PRES+D_DPL0+D_CTRL+D_TRAPGATE) /* Ring 0 trap gate */
+#define D_INT0 (D_PRES+D_DPL0+D_CTRL+D_INTGATE) /* Ring 0 int gate */
+#define D_TASK0 (D_PRES+D_DPL0+D_CTRL+D_TASKGATE) /* Ring 0 task gate */
+#define D_TSS0 (D_PRES+D_DPL0+D_CTRL+D_TSS) /* Ring 0 TSS */
+#define D_LDT0 (D_PRES+D_DPL0+D_CTRL+D_LDT) /* Ring 0 LDT */
+#define D_TRAP032 (D_PRES+D_DPL0+D_CTRL+D_TRAPGATE32) /* Ring 0 32-bit TG */
+#define D_INT032 (D_PRES+D_DPL0+D_CTRL+D_INTGATE32) /* Ring 0 32-bit IG */
+#define D_TSS032 (D_PRES+D_DPL0+D_CTRL+D_TSS32) /* Ring 0 32-bit TSS*/
+
+#define D_DATA1 (D_PRES+D_DPL1+D_SEG+D_DATA+D_W) /* Ring 1 rw data */
+#define D_CODE1 (D_PRES+D_DPL1+D_SEG+D_CODE+D_RX) /* Ring 1 rx code */
+
+#define D_DATA2 (D_PRES+D_DPL2+D_SEG+D_DATA+D_W) /* Ring 2 rw data */
+#define D_CODE2 (D_PRES+D_DPL2+D_SEG+D_CODE+D_RX) /* Ring 2 rx code */
+
+#define D_DATA3 (D_PRES+D_DPL3+D_SEG+D_DATA+D_W) /* Ring 3 rw data */
+#define D_CODE3 (D_PRES+D_DPL3+D_SEG+D_CODE+D_RX) /* Ring 3 rx code */
+#define D_INT3 (D_PRES+D_DPL3+D_CTRL+D_INTGATE) /* Ring 3 int gate */
+#define D_TRAP3 (D_PRES+D_DPL3+D_CTRL+D_TRAPGATE) /* Ring 3 trap gate */
+#define D_GATE3 (D_PRES+D_DPL3+D_CTRL+D_CALLGATE) /* Ring 3 call gate */
+#define D_INT332 (D_PRES+D_DPL3+D_CTRL+D_INTGATE32) /* Ring 3 32 bit int */
+#define D_GATE332 (D_PRES+D_DPL3+D_CTRL+D_CALLGATE32) /* Ring 3 32-bit CG */
+#define D_TRAP332 (D_PRES+D_DPL3+D_CTRL+D_TRAPGATE32) /* Ring 3 32-bit TG */
+
+
+/* Descriptor definition */
+
+struct desctab {
+ ushort_t d_limit; /* Segment limit */
+ ushort_t d_loaddr; /* Low word of physical address */
+ unsigned char d_hiaddr; /* High byte of physical address */
+ unsigned char d_access; /* Access byte */
+ unsigned char d_attr; /* Attributes/extended limit */
+ unsigned char d_extaddr; /* Extended physical address byte */
+};
+
+
+struct desc32 {
+ ulong_t d32_low; /* low dword in descriptor */
+ ulong_t d32_high; /* high dword in descriptor */
+};
+
+/* GDT free list descriptor definitions */
+
+#define d_flink d_loaddr /* Forward link */
+#define d_blink d_limit /* Back link */
+
+/* XLATOFF */
+struct gate {
+ ushort_t g_lowoffset; /* low word of offset */
+ ushort_t g_sel; /* selector to gate segment */
+ uchar_t g_parms; /* Parameter word count for call gate */
+ uchar_t g_access; /* Access byte */
+ ushort_t g_extoffset; /* Extended target offset */
+};
+
+/* XLATON */
+/* Following is for the old masm code only */
+
+/* ASM
+
+gate STRUC
+g_handler DD ?
+g_parms DB ?
+g_access DB ?
+g_extoffset DW ?
+gate ENDS
+
+g_lowoffset EQU WORD PTR g_handler
+g_sel EQU WORD PTR g_handler + 2
+
+*/
+
+/* LIDT/SIDT, LGDT/SGDT structure */
+
+struct lidt_s {
+ ushort_t lidt_limit; /* limit of idt or gdt */
+ ulong_t lidt_base; /* base of idt or gdt */
+};
+
+/*
+; Task State Segment structure definition
+*/
+
+struct tss_s {
+ ushort_t tss_backlink; /* backlink to prev task (none) */
+ ushort_t tss_reservdbl;
+ ulong_t tss_esp0;
+ ushort_t tss_ss0; /* ring 0 ss */
+ ushort_t tss_reservdss0;
+ ulong_t tss_esp1; /* ring 1 esp */
+ ushort_t tss_ss1; /* ring 1 ss */
+ ushort_t tss_reservdss1;
+ ulong_t tss_esp2; /* ring 2 esp */
+ ushort_t tss_ss2; /* ring 2 ss */
+ ushort_t tss_reservdss2;
+ ulong_t tss_cr3;
+ ulong_t tss_eip; /* entry point */
+ ulong_t tss_eflags; /* eflags */
+ ulong_t tss_eax;
+ ulong_t tss_ecx;
+ ulong_t tss_edx;
+ ulong_t tss_ebx;
+ ulong_t tss_esp;
+ ulong_t tss_ebp;
+ ulong_t tss_esi;
+ ulong_t tss_edi;
+ ushort_t tss_es;
+ ushort_t tss_reservdes;
+ ushort_t tss_cs;
+ ushort_t tss_reservdcs;
+ ushort_t tss_ss;
+ ushort_t tss_reservdss;
+ ushort_t tss_ds;
+ ushort_t tss_reservdds;
+ ushort_t tss_fs;
+ ushort_t tss_reservdfs;
+ ushort_t tss_gs;
+ ushort_t tss_reservdgs;
+ ushort_t tss_ldt;
+ ushort_t tss_reservdldt;
+ ushort_t tss_tflags;
+ ushort_t tss_iomap; /* I/O map TSS relative offset */
+} ;
+
+/* XLATOFF */
+typedef struct tss_s TSS;
+typedef TSS *PTSS;
+/* XLATON */
+
+
+/* tss_tflags bit definitions: */
+
+#define TSS_DEBUGTRAP 0x001 /* raise debug exception on task switch */
+
+/* 286/386 compatibility definitions: Needs to be included in seldesc.inc
+ file. */
+/* ASM
+tss_sp1 equ word ptr tss_esp1
+tss_sp2 equ word ptr tss_esp2
+tss_sp0 equ word ptr tss_esp0
+tss_ip equ word ptr tss_eip
+tss_bx equ word ptr tss_ebx
+tss_sp equ word ptr tss_esp
+tss_flags equ word ptr tss_eflags
+tss_cs0 equ word ptr tss_cs
+*/
diff --git a/private/os2/ldr/seldesc.inc b/private/os2/ldr/seldesc.inc
new file mode 100644
index 000000000..27d3996a2
--- /dev/null
+++ b/private/os2/ldr/seldesc.inc
@@ -0,0 +1,163 @@
+TABLE_MASK EQU 004H
+RPL_MASK EQU 003H
+RPL_CLR EQU 0fffcH
+RPL_RING0 EQU 000H
+RPL_RING1 EQU 001H
+RPL_RING2 EQU 002H
+RPL_RING3 EQU 003H
+D_PRES EQU 80H
+D_NOTPRES EQU 0
+D_DPL0 EQU 0
+D_DPL1 EQU 20H
+D_DPL2 EQU 40H
+D_DPL3 EQU 60H
+D_PRIV EQU D_DPL3
+D_SEG EQU 10H
+D_CTRL EQU 0
+D_TSS_BUSY_BIT EQU 2H
+D_GATE EQU 4H
+D_32 EQU 8H
+D_TSS EQU 1H
+D_LDT EQU 2H
+D_TSS_BUSY EQU (D_TSS+D_TSS_BUSY_BIT)
+D_CALLGATE EQU (D_GATE+0 )
+D_TASKGATE EQU (D_GATE+1 )
+D_INTGATE EQU (D_GATE+2 )
+D_TRAPGATE EQU (D_GATE+3 )
+D_TSS32 EQU (D_TSS+D_32)
+D_TSSBUSY32 EQU (D_TSS_BUSY+D_32)
+D_CALLGATE32 EQU (D_CALLGATE+D_32)
+D_INTGATE32 EQU (D_INTGATE+D_32)
+D_TRAPGATE32 EQU (D_TRAPGATE+D_32)
+D_TYPEMASK EQU 0fH
+D_WCMASK EQU 01fH
+D_MINGATE EQU D_CALLGATE
+D_MAXGATE EQU D_TRAPGATE32
+D_TSSBUSY_CLR EQU ( NOT D_TSS_BUSY_BIT)
+D_CODE EQU 8H
+D_DATA EQU 0
+D_CONFORM EQU 4H
+D_EXPDN EQU 4H
+D_RX EQU 2H
+D_X EQU 0
+D_W EQU 2H
+D_R EQU 0
+D_ACCESSED EQU 1H
+D_GRAN4K EQU 80H
+D_COPER32 EQU 40H
+D_DBIG EQU D_COPER32
+D_PAD EQU 20H
+D_UVIRT EQU 10H
+D_EXTLIMIT EQU 0fH
+D_1MEG EQU 100000H
+D_GRANMASK EQU 0fffffH
+D_DATA0 EQU (D_PRES+D_DPL0+D_SEG+D_DATA+D_W)
+D_CODE0 EQU (D_PRES+D_DPL0+D_SEG+D_CODE+D_RX)
+D_TRAP0 EQU (D_PRES+D_DPL0+D_CTRL+D_TRAPGATE)
+D_INT0 EQU (D_PRES+D_DPL0+D_CTRL+D_INTGATE)
+D_TASK0 EQU (D_PRES+D_DPL0+D_CTRL+D_TASKGATE)
+D_TSS0 EQU (D_PRES+D_DPL0+D_CTRL+D_TSS)
+D_LDT0 EQU (D_PRES+D_DPL0+D_CTRL+D_LDT)
+D_TRAP032 EQU (D_PRES+D_DPL0+D_CTRL+D_TRAPGATE32)
+D_INT032 EQU (D_PRES+D_DPL0+D_CTRL+D_INTGATE32)
+D_TSS032 EQU (D_PRES+D_DPL0+D_CTRL+D_TSS32)
+D_DATA1 EQU (D_PRES+D_DPL1+D_SEG+D_DATA+D_W)
+D_CODE1 EQU (D_PRES+D_DPL1+D_SEG+D_CODE+D_RX)
+D_DATA2 EQU (D_PRES+D_DPL2+D_SEG+D_DATA+D_W)
+D_CODE2 EQU (D_PRES+D_DPL2+D_SEG+D_CODE+D_RX)
+D_DATA3 EQU (D_PRES+D_DPL3+D_SEG+D_DATA+D_W)
+D_CODE3 EQU (D_PRES+D_DPL3+D_SEG+D_CODE+D_RX)
+D_INT3 EQU (D_PRES+D_DPL3+D_CTRL+D_INTGATE)
+D_TRAP3 EQU (D_PRES+D_DPL3+D_CTRL+D_TRAPGATE)
+D_GATE3 EQU (D_PRES+D_DPL3+D_CTRL+D_CALLGATE)
+D_INT332 EQU (D_PRES+D_DPL3+D_CTRL+D_INTGATE32)
+D_GATE332 EQU (D_PRES+D_DPL3+D_CTRL+D_CALLGATE32)
+D_TRAP332 EQU (D_PRES+D_DPL3+D_CTRL+D_TRAPGATE32)
+
+desctab STRUC
+d_limit DW ?
+d_loaddr DW ?
+d_hiaddr DB ?
+d_access DB ?
+d_attr DB ?
+d_extaddr DB ?
+desctab ENDS
+
+
+desc32 STRUC
+d32_low DD ?
+d32_high DD ?
+desc32 ENDS
+
+d_flink EQU d_loaddr
+d_blink EQU d_limit
+
+gate STRUC
+g_handler DD ?
+g_parms DB ?
+g_access DB ?
+g_extoffset DW ?
+gate ENDS
+
+g_lowoffset EQU WORD PTR g_handler
+g_sel EQU WORD PTR g_handler + 2
+
+
+
+lidt_s STRUC
+lidt_limit DW ?
+lidt_base DD ?
+lidt_s ENDS
+
+
+tss_s STRUC
+tss_backlink DW ?
+tss_reservdbl DW ?
+tss_esp0 DD ?
+tss_ss0 DW ?
+tss_reservdss0 DW ?
+tss_esp1 DD ?
+tss_ss1 DW ?
+tss_reservdss1 DW ?
+tss_esp2 DD ?
+tss_ss2 DW ?
+tss_reservdss2 DW ?
+tss_cr3 DD ?
+tss_eip DD ?
+tss_eflags DD ?
+tss_eax DD ?
+tss_ecx DD ?
+tss_edx DD ?
+tss_ebx DD ?
+tss_esp DD ?
+tss_ebp DD ?
+tss_esi DD ?
+tss_edi DD ?
+tss_es DW ?
+tss_reservdes DW ?
+tss_cs DW ?
+tss_reservdcs DW ?
+tss_ss DW ?
+tss_reservdss DW ?
+tss_ds DW ?
+tss_reservdds DW ?
+tss_fs DW ?
+tss_reservdfs DW ?
+tss_gs DW ?
+tss_reservdgs DW ?
+tss_ldt DW ?
+tss_reservdldt DW ?
+tss_tflags DW ?
+tss_iomap DW ?
+tss_s ENDS
+
+TSS_DEBUGTRAP EQU 001H
+tss_sp1 equ word ptr tss_esp1
+tss_sp2 equ word ptr tss_esp2
+tss_sp0 equ word ptr tss_esp0
+tss_ip equ word ptr tss_eip
+tss_bx equ word ptr tss_ebx
+tss_sp equ word ptr tss_esp
+tss_flags equ word ptr tss_eflags
+tss_cs0 equ word ptr tss_cs
+
diff --git a/private/os2/ldr/sources b/private/os2/ldr/sources
new file mode 100644
index 000000000..7fc8de06d
--- /dev/null
+++ b/private/os2/ldr/sources
@@ -0,0 +1,75 @@
+!IF 0
+*****************************************************************************
+Copyright (c) 1989, 1990 Microsoft Corporation
+
+Module Name: SOURCES for OS/2 subsystem loader
+
+Author: larrys
+
+Revision History:
+ 04-19-91 larrys original version
+*****************************************************************************
+!ENDIF
+
+#------------------------------------------------
+# INFO FOR CREATING LIBRARY
+#------------------------------------------------
+MAJORCOMP=os2
+MINORCOMP=ldr
+
+TARGETNAME=os2ldr
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+#TARGETLIBS=..\obj\*\os2ssrtl.lib ..\client\obj\*\os2dll.lib \
+# $(BASEDIR)\public\sdk\lib\*\ntcrt.lib
+
+#------------------------------------------------
+# INCLUDE PATH
+#------------------------------------------------
+
+INCLUDES=..\inc
+
+#------------------------------------------------
+# SOURCE FILES (used to make library)
+#------------------------------------------------
+SYNCHRONIZE_DRAIN=1
+WIMPYMASM=1
+
+NO_READONLY_STRINGS=1
+
+SOURCES=ldrmte.c \
+ ldrste.c \
+ ldrsubr.c \
+ ldrinit.c \
+ ldrutil.c \
+ ldrfixup.c \
+ ldrdbcs.c
+
+i386_SOURCES=
+
+#------------------------------------------------
+# FLAGS
+#------------------------------------------------
+
+!IFDEF PMNT
+
+C_DEFINES=-DOS2_CLIENT -DPMNT
+
+!ELSE
+
+C_DEFINES=-DOS2_CLIENT
+
+!ENDIF
+
+#------------------------------------------------
+# EXECUTABLES
+#------------------------------------------------
+
+#UMTYPE=os2
+
+#------------------------------------------------
+# LIBRARIES created by the SOURCES= line (above)
+# (currently commented out - not used)
+#------------------------------------------------
+
+#UMLIBS= ..\obj\*\os2ldr.lib
diff --git a/private/os2/loader/loader.c b/private/os2/loader/loader.c
new file mode 100644
index 000000000..0e0249167
--- /dev/null
+++ b/private/os2/loader/loader.c
@@ -0,0 +1,571 @@
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_FILESYS
+#define INCL_ERROR_H
+#define INCL_TYPES
+#include <stdio.h>
+#include <ctype.h>
+#include <bseerr.h>
+#include <os2dll.h>
+#include <os2dll16.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <os2defp.h>
+#include <mi.h>
+#include <ldrxport.h>
+#if PMNT
+#define INCL_32BIT
+#include <pmnt.h>
+extern APIRET PMNTMemMap(PSEL);
+extern APIRET PMNTIOMap(void);
+#endif
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 260
+#endif
+
+ULONG GetTickCount(VOID);
+PVOID LDRExecInfo;
+extern ULONG Od2Start16Stack;
+extern ULONG Od2Start16DS;
+extern POD2_SIG_HANDLER_REC pSigHandlerRec;
+extern POD2_VEC_HANDLER_REC pVecHandlerRec;
+USHORT LDRDoscallsSel;
+extern VOID Od2EnableCtrlHandling(VOID);
+extern VOID Od2UpdateLocalInfoAtStart(VOID);
+extern char Od2PgmFullPathBuf[];
+extern PSZ Od2PgmFilePath;
+extern ULONG timing;
+extern BOOLEAN Od2SignalEnabled;
+extern BOOL Od2ExpandOd2LibPathElements(PCHAR ExpandedString, ULONG MaxSize);
+extern PVOID EntryFlat(VOID);
+extern ULONG Od2ExecPgmErrorText;
+extern ULONG Od2ExecPgmErrorTextLength;
+extern ULONG Od2EnvCommandOffset;
+extern POD2_PROCESS Od2Process;
+
+
+#if PMNT
+// From winbase.h
+
+ULONG
+SetThreadAffinityMask(
+ HANDLE hThread,
+ DWORD dwThreadAffinityMask
+ );
+
+HANDLE
+GetCurrentThread(
+ VOID
+ );
+
+#endif // PMNT
+
+VOID
+Ow2BoundAppLoadPopup(
+ IN PSZ AppName
+ );
+
+ldrlibi_t InitRecords[MAX_INIT_RECORDS];
+
+#if DBG
+void LoadStop(
+ int id
+ )
+{
+ UNREFERENCED_PARAMETER(id);
+
+ DbgPrint("LoadStop\n");
+// DbgUserBreakPoint();
+}
+#else
+#define LoadStop(x)
+#endif
+
+int
+Loader_main()
+{
+ PUCHAR pname;
+ ldrrei_t exec_info;
+ ldrrei_t *pexec_info = &exec_info;
+ PNT_TIB ptib;
+ PIB *pib;
+ PVOID MemoryAddress;
+ ULONG RegionSize;
+ PCHAR pchar;
+ ULONG i;
+ OD2_SIG_HANDLER_REC *pSig;
+ OD2_VEC_HANDLER_REC *pVec;
+ ULONG address;
+ int rc;
+ NTSTATUS Status;
+ I386DESCRIPTOR Desc;
+ OS2_API_MSG m;
+ P_LDRNEWEXE_MSG a = &m.u.LdrNewExe;
+ POS2_CAPTURE_HEADER CaptureBuffer;
+ ULONG FileFlags;
+ ULONG FileType;
+ STRING ProcessNameString;
+ STRING LibPathNameString;
+ STRING FailNameString;
+ // Remember that \OS2SS\DRIVES\ is added for each path element !
+ // Let's assume the smallest component is 5 chars long (like C:\X;)
+ // (although it could be less, like "." or "\")
+ // => we need to add 14 * (MAXPATHLEN/5) = MAXPATHLEN*3
+ CHAR ExpandedLibPath[MAXPATHLEN*4];
+ ULONG NumOfInitRecords;
+
+ DosGetThreadInfo(&ptib, &pib);
+
+ pname = Od2PgmFullPathBuf;
+
+ rc = Od2Canonicalize(pname,
+ CANONICALIZE_FILE_OR_DEV,
+ &ProcessNameString,
+ NULL,
+ &FileFlags,
+ &FileType
+ );
+ /*
+ * Reserve 64k at BASE_TILE, which corresponds with selector 0
+ */
+ MemoryAddress = (PVOID) BASE_TILE;
+ RegionSize = _64K;
+ if ((rc = NtAllocateVirtualMemory(NtCurrentProcess(),
+ &MemoryAddress,
+ 0,
+ &RegionSize,
+ MEM_RESERVE,
+ PAGE_NOACCESS)) != NO_ERROR) {
+ LoadStop(0);
+ goto returnlabel;
+ }
+
+ Od2ExpandOd2LibPathElements(ExpandedLibPath, sizeof(ExpandedLibPath));
+ RtlInitString(&LibPathNameString, ExpandedLibPath);
+
+ FailNameString.Buffer = NULL;
+ FailNameString.Length = 0;
+ FailNameString.MaximumLength = 50; // same size as ErrorBuffer in client\dllinit.c
+
+ CaptureBuffer = Od2AllocateCaptureBuffer(
+ 4,
+ 0,
+ ProcessNameString.MaximumLength +
+ LibPathNameString.MaximumLength +
+ FailNameString.MaximumLength +
+ MAX_INIT_RECORDS * sizeof(ldrlibi_t)
+ );
+ if (CaptureBuffer == NULL) {
+ LoadStop(6);
+ goto returnlabel;
+ }
+
+ Od2CaptureMessageString( CaptureBuffer,
+ ProcessNameString.Buffer,
+ ProcessNameString.Length,
+ ProcessNameString.MaximumLength,
+ &a->ProcessName
+ );
+ RtlFreeHeap(Od2Heap, 0, ProcessNameString.Buffer);
+
+ Od2CaptureMessageString( CaptureBuffer,
+ FailNameString.Buffer,
+ FailNameString.Length,
+ FailNameString.MaximumLength,
+ &a->FailName
+ );
+
+ Od2CaptureMessageString( CaptureBuffer,
+ LibPathNameString.Buffer,
+ LibPathNameString.Length,
+ LibPathNameString.MaximumLength,
+ &a->LibPathName
+ );
+
+ Od2CaptureMessageString( CaptureBuffer,
+ NULL,
+ 0,
+ MAX_INIT_RECORDS * sizeof(ldrlibi_t),
+ &a->InitRecords
+ );
+
+ a->EntryFlatAddr = (ULONG)EntryFlat;
+
+ Od2CallSubsystem( &m, CaptureBuffer, Ol2LdrNewExe, sizeof( *a ) );
+
+#if DBG
+ IF_OD2_DEBUG( LOADER ) {
+ if (a->BoundApp) {
+ KdPrint(("Loader_main: Bound App Detected\n"));
+ }
+ }
+#endif
+
+ Od2Process->BoundApp = a->BoundApp; // store away the BoundApp flag
+
+#if PMNT
+ PMFlags = a->PMProcess;
+#endif // PMNT
+
+ rc = m.ReturnedErrorValue;
+ if (rc != NO_ERROR) {
+#if PMNT
+ if (rc == ERROR_PMSHELL_NOT_UP || rc == ERROR_2ND_PMSHELL) {
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ Ow2PMShellErrorPopup(Od2PgmFilePath,rc);
+ DosExit(EXIT_PROCESS, rc);
+ return(rc);
+ }
+#endif
+ RtlCopyMemory((PVOID)Od2ExecPgmErrorText, a->FailName.Buffer, a->FailName.Length);
+ Od2ExecPgmErrorTextLength = a->FailName.Length;
+ *((PCHAR)Od2ExecPgmErrorText + Od2ExecPgmErrorTextLength) = '\0';
+ Od2FreeCaptureBuffer( CaptureBuffer );
+ LoadStop(5);
+
+ if (a->BoundApp) {
+ Ow2BoundAppLoadPopup(Od2PgmFilePath);
+ }
+
+ goto returnlabel;
+ }
+
+#if PMNT
+ if (ProcessIsPMProcess() && !ProcessIsPMShell())
+ {
+ UNICODE_STRING EventString_U;
+ OBJECT_ATTRIBUTES Obja;
+ NTSTATUS Status;
+ HANDLE Od2PMShellEvent;
+
+ // Whether PMShell or just a PM app, we need to open the PMShell
+ // synchronization semaphore
+
+ RtlInitUnicodeString( &EventString_U, OS2_SS_PMSHELL_EVENT);
+ InitializeObjectAttributes(
+ &Obja,
+ &EventString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ //
+ // Open the global subsystem synchronization Nt semaphore
+ //
+ Status = NtOpenEvent(&Od2PMShellEvent,
+ EVENT_ALL_ACCESS,
+ &Obja);
+
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ DbgPrint("Os2: Loader_main(), failed to open PMShellEvent, Status %x\n", Status);
+#endif // DBG
+ }
+ else
+ {
+ // Regular PM app - wait on the PMShell semaphore !
+ Status = NtWaitForSingleObject(
+ Od2PMShellEvent,
+ TRUE, // Alertable
+ NULL
+ );
+#if DBG
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("Os2: Loader_main(), failed to NtWaitForSingleObject PMShellEvent, Status %x\n", Status);
+ }
+#endif
+ }
+ } // PM apps (non-PMShell) handling
+
+ // Force all PM threads to run on processor#1. Otherwise, PM Desktop
+ // locks-up
+ if (ProcessIsPMProcess())
+ {
+ DWORD Ret;
+
+ Ret = SetThreadAffinityMask(
+ GetCurrentThread(),
+ 0x1);
+#if DBG
+ if (Ret == 0)
+ {
+ DbgPrint("OS2: main() - failed to SetThreadAffinityMask\n");
+ }
+ else if (Ret != 1)
+ {
+ DbgPrint("OS2: Loader_main() - SetThreadAffinityMask returned %x (now set to 1)\n",
+ Ret);
+ }
+#endif // DBG
+ }
+#endif // PMNT
+
+ NumOfInitRecords = a->NumOfInitRecords;
+ RtlCopyMemory(InitRecords, a->InitRecords.Buffer,
+ NumOfInitRecords * sizeof(ldrlibi_t));
+ RtlCopyMemory(pexec_info, &a->ExecInfo, sizeof(exec_info));
+ LDRDoscallsSel = (USHORT)a->DoscallsSel;
+ Od2FreeCaptureBuffer( CaptureBuffer );
+
+ Desc.Limit = _64K - 1;
+ Desc.Type = READ_WRITE_DATA;
+
+ //
+ // Set selectors for the tiled heap area
+ //
+ for (Desc.BaseAddress = OD2TILEDHEAP_BASE;
+ Desc.BaseAddress < (OD2TILEDHEAP_BASE + OD2TILEDHEAP_SIZE);
+ (ULONG)(Desc.BaseAddress) += _64K ) {
+
+ Status = Nt386SetDescriptorLDT (
+ NULL,
+ FLATTOSEL(Desc.BaseAddress),
+ Desc);
+ ASSERT (NT_SUCCESS( Status ));
+ }
+
+ Desc.BaseAddress = OD2ENVIRONMENT_BASE;
+ Status = Nt386SetDescriptorLDT (
+ NULL,
+ FLATTOSEL(OD2ENVIRONMENT_BASE),
+ Desc);
+ ASSERT (NT_SUCCESS( Status ));
+
+ pexec_info->ei_envsel = FLATTOSEL(Od2Environment);
+ pchar = (PCHAR)Od2Environment;
+
+ /*
+ * Start at beginning of environment and find the command line
+ * (Env, 0, fullpathname, cmdline)
+ */
+
+ pchar = (PCHAR)Od2Environment;
+ while(*pchar++ != '\0') {
+ if (*pchar == '\0') {
+ pchar++;
+ if (*pchar == '\0')
+ break;
+ }
+ }
+ pchar++;
+ pchar += strlen(pname);
+ pchar++;
+
+ pexec_info->ei_comoff = (USHORT)((ULONG) pchar & 0xffff);
+ Od2EnvCommandOffset = pexec_info->ei_comoff;
+
+ /*
+ * Set LDRExecInfo pointer for use in OS2DLL in DosGetInfoSeg
+ */
+ (PVOID) LDRExecInfo = pexec_info;
+
+ Od2UpdateLocalInfoAtStart();
+
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("Values in exec_info for program:\n");
+ DbgPrint("ei_startaddr=%x\n", pexec_info->ei_startaddr); /* instruction pointer */
+ DbgPrint("ei_stackaddr=%x\n", pexec_info->ei_stackaddr); /* instruction pointer */
+ DbgPrint("ei_ds=%x\n", pexec_info->ei_ds); /* instruction pointer */
+ DbgPrint("ei_dgroupsize=%x\n", pexec_info->ei_dgroupsize); /* instruction pointer */
+ DbgPrint("ei_heapsize=%x\n", pexec_info->ei_heapsize); /* instruction pointer */
+ DbgPrint("ei_loadtype=%x\n", pexec_info->ei_loadtype); /* instruction pointer */
+ DbgPrint("ei_envsel=%x\n", pexec_info->ei_envsel); /* instruction pointer */
+ DbgPrint("ei_comoff=%x\n", pexec_info->ei_comoff); /* instruction pointer */
+ DbgPrint("ei_stacksize=%x\n", pexec_info->ei_stacksize); /* instruction pointer */
+ DbgPrint("ei_hmod=%x\n", pexec_info->ei_hmod); /* instruction pointer */
+ }
+#endif
+
+#ifdef PMNT
+ if (ProcessIsPMApp())
+ {
+ SEL DummySel;
+
+ PMNTMemMap(&DummySel);
+ PMNTIOMap();
+ }
+#endif // PMNT
+
+ /*
+ * Setup Signal handling default values.
+ */
+ pSig = (POD2_SIG_HANDLER_REC) pSigHandlerRec;
+ address = FLATTOFARPTR((ULONG)(SELTOFLAT(LDRDoscallsSel)));
+ pSig->fholdenable = HLDSIG_ENABLE;
+ pSig->outstandingsig[0].sighandleraddr =
+ pSig->outstandingsig[1].sighandleraddr =
+ pSig->outstandingsig[2].sighandleraddr =
+ pSig->outstandingsig[3].sighandleraddr =
+ pSig->outstandingsig[4].sighandleraddr =
+ pSig->outstandingsig[5].sighandleraddr =
+ pSig->outstandingsig[6].sighandleraddr = 0;
+ pSig->doscallssel = address;
+ pSig->sighandler[SIG_BROKENPIPE - 1] = (ULONG)
+ (address | ThunkOffsetDosReturn);
+ pSig->action[SIG_BROKENPIPE - 1] = SIGA_IGNORE;
+
+ pSig->sighandler[SIG_CTRLBREAK - 1] = (ULONG)
+ (address | ThunkOffsetExitProcessStub);
+ pSig->action[SIG_CTRLBREAK - 1] = SIGA_ACCEPT;
+
+ pSig->sighandler[SIG_CTRLC - 1] = (ULONG)
+ (address | ThunkOffsetExitProcessStub);
+ pSig->action[SIG_CTRLC - 1] = SIGA_ACCEPT;
+
+ pSig->sighandler[SIG_KILLPROCESS - 1] = (ULONG)
+ (address | ThunkOffsetExitProcessStub);
+ pSig->action[SIG_KILLPROCESS - 1] = SIGA_ACCEPT;
+
+ pSig->sighandler[SIG_PFLG_A - 1] = (ULONG)
+ (address | ThunkOffsetDosReturn);
+ pSig->action[SIG_PFLG_A - 1] = SIGA_ACCEPT;
+
+ pSig->sighandler[SIG_PFLG_B - 1] = (ULONG)
+ (address | ThunkOffsetDosReturn);
+ pSig->action[SIG_PFLG_B - 1] = SIGA_ACCEPT;
+
+ pSig->sighandler[SIG_PFLG_C - 1] = (ULONG)
+ (address | ThunkOffsetDosReturn);
+ pSig->action[SIG_PFLG_C - 1] = SIGA_ACCEPT;
+
+ /*
+ * Setup Vector handling default values.
+ */
+ pVec = (POD2_VEC_HANDLER_REC) pVecHandlerRec;
+ pVec->doscallssel = address;
+ pVec->VecHandler[0] = (ULONG) (address | ThunkOffsetDosReturn);
+ pVec->VecHandler[1] = (ULONG) (address | ThunkOffsetDosReturn);
+ pVec->VecHandler[2] = (ULONG) (address | ThunkOffsetDosReturn);
+ pVec->VecHandler[3] = (ULONG) (address | ThunkOffsetDosReturn);
+ pVec->VecHandler[4] = (ULONG) (address | ThunkOffsetDosReturn);
+ pVec->VecHandler[5] = (ULONG) (address | ThunkOffsetDosReturn);
+
+ //
+ // Go over all DLLs init routines
+ //
+ for (i = 0; i < NumOfInitRecords; i++) {
+ if (InitRecords[i].stackaddr.ptr_sel == 0) {
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("Replacing SS:SP of module\n");
+ }
+#endif
+ InitRecords[i].stackaddr.ptr_sel = pexec_info->ei_stackaddr.ptr_sel;
+ InitRecords[i].stackaddr.ptr_off = pexec_info->ei_stackaddr.ptr_off;
+ }
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("=== Calling Init routine %d for app.\n", i);
+ DbgPrint("Values of libi:\n");
+ DbgPrint("startaddr=%x\n", InitRecords[i].startaddr); /* instruction pointer */
+ DbgPrint("stackaddr=%x\n", InitRecords[i].stackaddr); /* instruction pointer */
+ DbgPrint("ds=%x\n", InitRecords[i].ds); /* instruction pointer */
+ DbgPrint("heapsize=%x\n", InitRecords[i].heapsize); /* instruction pointer */
+ DbgPrint("handle=%x\n", InitRecords[i].handle); /* instruction pointer */
+ }
+#endif
+ rc = ldrLibiInit(&InitRecords[i], pexec_info);
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("=== Init routine returned %d\n", rc);
+ }
+#endif
+ if (rc == 0) {
+ DosExit(EXIT_PROCESS, 255); // same as OS/2 1.x does
+ return(rc);
+ }
+ }
+
+#if PMNT
+ // If this is PMShell, release waiting PM apps now
+ if (ProcessIsPMShell())
+ {
+ UNICODE_STRING EventString_U;
+ OBJECT_ATTRIBUTES Obja;
+ NTSTATUS Status;
+ HANDLE Od2PMShellEvent;
+
+ RtlInitUnicodeString( &EventString_U, OS2_SS_PMSHELL_EVENT);
+ InitializeObjectAttributes(
+ &Obja,
+ &EventString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ //
+ // Open the global subsystem synchronization Nt semaphore
+ //
+ Status = NtOpenEvent(&Od2PMShellEvent,
+ EVENT_ALL_ACCESS,
+ &Obja);
+
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ DbgPrint("Os2: Loader_main(), after LdrLibiInit, failed to open PMShellEvent, Status %x\n", Status);
+#endif // DBG
+ }
+ else
+ {
+ // For PMShell, release the PMShell synchronization event
+ Status = NtSetEvent (
+ Od2PMShellEvent,
+ NULL);
+#if DBG
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("Os2: Loader_main(), after LdrLibiInit, failed to NtSetEvent PMShellEvent, Status %x\n", Status);
+ }
+#endif // DBG
+ }
+ }
+#endif // PMNT
+
+ /*
+ * Save starting stack address & DS for exit list processing
+ */
+ (PULONG) Od2Start16Stack =
+ (PULONG)(pexec_info->ei_stackaddr.ptr_flat);
+ (PULONG) Od2Start16DS = (PULONG) (pexec_info->ei_ds);
+
+ pSig->signature = 0xdead;
+ Od2EnableCtrlHandling();
+ if (timing)
+ {
+ printf("Os2 time before ldrstart is %d\n", (GetTickCount()) - timing);
+ }
+ Od2SignalEnabled = TRUE;
+
+#if DBG
+ IF_OD2_DEBUG ( LOADER ) {
+ DbgPrint("Values in exec_info:\n");
+ DbgPrint("ei_startaddr=%x\n", pexec_info->ei_startaddr); /* instruction pointer */
+ DbgPrint("ei_stackaddr=%x\n", pexec_info->ei_stackaddr); /* instruction pointer */
+ DbgPrint("ei_ds=%x\n", pexec_info->ei_ds); /* instruction pointer */
+ DbgPrint("ei_dgroupsize=%x\n", pexec_info->ei_dgroupsize); /* instruction pointer */
+ DbgPrint("ei_heapsize=%x\n", pexec_info->ei_heapsize); /* instruction pointer */
+ DbgPrint("ei_loadtype=%x\n", pexec_info->ei_loadtype); /* instruction pointer */
+ DbgPrint("ei_envsel=%x\n", pexec_info->ei_envsel); /* instruction pointer */
+ DbgPrint("ei_comoff=%x\n", pexec_info->ei_comoff); /* instruction pointer */
+ DbgPrint("ei_stacksize=%x\n", pexec_info->ei_stacksize); /* instruction pointer */
+ DbgPrint("ei_hmod=%x\n", pexec_info->ei_hmod); /* instruction pointer */
+ }
+#endif
+
+ ldrstart(pexec_info);
+
+returnlabel:
+
+ //
+ // Set to indicate loader error to os2srv
+ //
+
+ DosExit(EXIT_PROCESS, 0x80000000 | rc);
+ return(rc);
+}
+
diff --git a/private/os2/loader/makefile b/private/os2/loader/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/os2/loader/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/os2/loader/sources b/private/os2/loader/sources
new file mode 100644
index 000000000..644104e91
--- /dev/null
+++ b/private/os2/loader/sources
@@ -0,0 +1,69 @@
+!IF 0
+*****************************************************************************
+Copyright (c) 1989, 1990 Microsoft Corporation
+
+Module Name: SOURCES for OS/2 subsystem loader
+
+Author: larrys
+
+Revision History:
+ 04-19-91 larrys original version
+*****************************************************************************
+!ENDIF
+
+#------------------------------------------------
+# INFO FOR CREATING LIBRARY
+#------------------------------------------------
+MAJORCOMP=os2
+MINORCOMP=loader
+
+TARGETNAME=loader
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+#TARGETLIBS= $(BASEDIR)\public\sdk\lib\*\ldrdll.lib \
+# $(BASEDIR)\public\sdk\lib\*\nt.lib \
+# ..\client\obj\*\os2dll.lib \
+# $(BASEDIR)\public\sdk\lib\*\ntcrt.lib \
+# $(BASEDIR)\public\sdk\lib\*\user32.lib
+
+NO_READONLY_STRINGS=1
+
+#------------------------------------------------
+# INCLUDE PATH
+#------------------------------------------------
+
+INCLUDES=..\inc;..\ldr
+
+#------------------------------------------------
+# SOURCE FILES (used to make library)
+#------------------------------------------------
+
+SOURCES=loader.c
+
+#------------------------------------------------
+# FLAGS
+#------------------------------------------------
+
+!IFDEF PMNT
+C_DEFINES=-DOS2_CLIENT -DWIN32=1 -DPMNT
+!ELSE
+C_DEFINES=-DOS2_CLIENT -DWIN32=1
+!ENDIF
+
+USE_CRTDLL=1
+#------------------------------------------------
+# EXECUTABLES
+#------------------------------------------------
+
+#UMTYPE=console
+# UMTEST=loader
+
+#------------------------------------------------
+# LIBRARIES created by the SOURCES= line (above)
+# (currently commented out - not used)
+#------------------------------------------------
+
+# UMAPPL=loader
+#UMLIBS= $(BASEDIR)\public\sdk\lib\*\ldrdll.lib \
+# $(BASEDIR)\public\sdk\lib\*\nt.lib
+#COFFBASE=loader
diff --git a/private/os2/msg/oso001.007 b/private/os2/msg/oso001.007
new file mode 100644
index 000000000..86ea54c98
--- /dev/null
+++ b/private/os2/msg/oso001.007
Binary files differ
diff --git a/private/os2/msg/oso001.009 b/private/os2/msg/oso001.009
new file mode 100644
index 000000000..d15927ba1
--- /dev/null
+++ b/private/os2/msg/oso001.009
Binary files differ
diff --git a/private/os2/msg/oso001.010 b/private/os2/msg/oso001.010
new file mode 100644
index 000000000..82eb8700e
--- /dev/null
+++ b/private/os2/msg/oso001.010
Binary files differ
diff --git a/private/os2/msg/oso001.012 b/private/os2/msg/oso001.012
new file mode 100644
index 000000000..5d7fcfa16
--- /dev/null
+++ b/private/os2/msg/oso001.012
Binary files differ
diff --git a/private/os2/msg/oso001.016 b/private/os2/msg/oso001.016
new file mode 100644
index 000000000..fdca31488
--- /dev/null
+++ b/private/os2/msg/oso001.016
Binary files differ
diff --git a/private/os2/msg/oso001.029 b/private/os2/msg/oso001.029
new file mode 100644
index 000000000..9a3ad6a87
--- /dev/null
+++ b/private/os2/msg/oso001.029
Binary files differ
diff --git a/private/os2/os2ses/conrqust.c b/private/os2/os2ses/conrqust.c
new file mode 100644
index 000000000..3e2254bb7
--- /dev/null
+++ b/private/os2/os2ses/conrqust.c
@@ -0,0 +1,199 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ conrqust.c
+
+Abstract:
+
+ This module contains the handler for console requests.
+
+Author:
+
+ Avi Nathan (avin) 17-Jul-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "event.h"
+#include "trans.h"
+#include "os2win.h"
+#include <io.h>
+#include <stdio.h>
+
+
+#if DBG
+BYTE Ow2ConReadFileStr[] = "Ow2ConReadFile";
+BYTE Ow2ConWriteFileStr[] = "Ow2ConWriteFile";
+BYTE Ow2ConCloseHandleStr[] = "Ow2ConCloseHandle";
+BYTE Ow2ConBeepStr[] = "Ow2ConBeep";
+#endif
+
+DWORD
+Ow2ConReadFile(
+ IN HANDLE hFile,
+ IN ULONG Length,
+ OUT PVOID Buffer,
+ OUT PULONG BytesRead
+ )
+{
+ DWORD Rc;
+
+ if (Or2WinReadFile(
+ #if DBG
+ Ow2ConReadFileStr,
+ #endif
+ hFile,
+ Buffer,
+ Length,
+ BytesRead,
+ NULL
+ )) {
+#if DBG
+ if (Length != *BytesRead)
+ {
+ IF_OD2_DEBUG( OS2_EXE )
+ KdPrint(("OS2SES(ConRqust-Ow2ConReadFile): partial data: %lu from %lu\n",
+ *BytesRead, Length));
+ }
+#endif
+ return(NO_ERROR);
+
+ } else {
+
+ Rc = GetLastError();
+
+ if (Rc == ERROR_BROKEN_PIPE) {
+
+ //
+ // This is a special case. It's returned if we're reading
+ // from a pipe, and the other side closed the pipe. In this
+ // case, we simulate a closed file
+ //
+
+ *BytesRead = 0;
+ return(NO_ERROR);
+ }
+
+#if DBG
+ KdPrint(( "OS2SES(ConRqust-Ow2ConReadFile): ReadFile: Rc %lu\n", Rc));
+#endif
+ *BytesRead = 0;
+ return(Rc);
+ }
+}
+
+
+DWORD
+Ow2ConWriteFile(
+ IN HANDLE hFile,
+ IN ULONG Length,
+ IN PVOID Buffer,
+ OUT PULONG BytesWritten
+ )
+{
+ DWORD Rc;
+
+ if (Or2WinWriteFile(
+ #if DBG
+ Ow2ConWriteFileStr,
+ #endif
+ hFile,
+ Buffer,
+ Length,
+ BytesWritten,
+ NULL))
+ {
+#if DBG
+ if (Length != *BytesWritten)
+ {
+ IF_OD2_DEBUG( OS2_EXE )
+ KdPrint(("OS2SES(ConRqust-Ow2ConWriteFile): partial data: %lu from %lu\n",
+ *BytesWritten, Length));
+ }
+#endif
+
+ return(NO_ERROR);
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(( "OS2SES(ConRqust-Ow2ConWriteFile): WriteFile: Rc %lu\n", Rc));
+#endif
+ *BytesWritten = 0;
+ return(Rc);
+ }
+}
+
+
+DWORD
+Ow2ConCloseHandle(
+ IN HANDLE hFile
+ )
+{
+ DWORD Rc;
+
+ if ((hFile == hConsoleOutput) ||
+ (hFile == hConsoleInput))
+ {
+#if DBG
+ KdPrint(("OS2SES(ConRqust-ScCloseHandle): Std-handle\n"));
+#endif
+ return(NO_ERROR);
+ }else
+ {
+ if (Or2WinCloseHandle(
+ #if DBG
+ Ow2ConCloseHandleStr,
+ #endif
+ hFile))
+ {
+ return(NO_ERROR);
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(( "OS2SES(ConRqust-Ow2ConCloseHandle): CloseHandle: Rc %lu\n", Rc));
+#endif
+ return(Rc);
+ }
+ }
+}
+
+
+DWORD
+Ow2ConBeep(
+ IN ULONG dwFreq,
+ IN ULONG dwDuration
+ )
+{
+ DWORD Rc;
+
+ if(Or2WinBeep(
+ #if DBG
+ Ow2ConBeepStr,
+ #endif
+ dwFreq,
+ dwDuration
+ ))
+ {
+ return(NO_ERROR);
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(( "OS2SES(ConRqust-Ow2ConBeep): Beep: Rc %lu\n", Rc));
+#endif
+ return(Rc);
+ }
+}
+
diff --git a/private/os2/os2ses/event.c b/private/os2/os2ses/event.c
new file mode 100644
index 000000000..0095988c8
--- /dev/null
+++ b/private/os2/os2ses/event.c
@@ -0,0 +1,4205 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ Event.c
+
+Abstract:
+
+ This module contains the code of the input event handler. It
+ read input from the input buffer queue and divide the event to 2
+ different queues: Kbd & Mou.
+ It also contains the code of the Kbd & Mou routines of reading
+ events from their queues.
+
+Author:
+
+ Michael Jarus (mjarus) 3-Nov-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#if PMNT
+#include <windows.h>
+#include <wincon.h>
+#include <ntddvdeo.h>
+#include "conapi.h"
+#define PMNT_CONSOLE_INCLUDED // to fix a redefinition in "os2nt.h"
+#endif // PMNT
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "event.h"
+#include "trans.h"
+#if PMNT
+#ifndef FIELD_OFFSET
+#define FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field))
+#endif
+#define INCL_32BIT
+#include "pmnt.h"
+#endif
+
+#define AccentedKey 0x0200 // Key was translated using previous accent.
+#define KeyTypeMask 0x003F // Isolates the Key Type field of DDFlags.
+#define AccentKey 0x0010 // @@ This packet is an accent key
+
+#if PMNT
+/* Hand-shaking events */
+HANDLE hStartHardwareEvent;
+HANDLE hEndHardwareEvent;
+LONG ScreenX = 640L;
+LONG ScreenY = 480L;
+extern PSZ Od2PgmFilePath;
+#endif // PMNT
+
+VOID
+ExitThread(
+ ULONG dwExitCode
+ );
+
+#if PMNT
+DWORD
+NtClose(
+ IN HANDLE Handle
+ );
+#endif // PMNT
+
+VOID Od2ExitGP();
+DWORD MonQueueClose(IN HANDLE hMon);
+
+DWORD
+ReadInputEvent(IN ULONG PeekFlag);
+
+BOOLEAN
+Ow2WriteBackDummyEvent(VOID);
+
+BOOLEAN
+Ow2ClearupDummyEvent(VOID);
+
+DWORD
+Ow2FaultFilter(
+ IN DWORD uFaultFilter,
+ IN PEXCEPTION_POINTERS lpExP);
+
+VOID Ow2DisplayExceptionInfo( VOID );
+
+DWORD
+Ow2GetInputConsoleMode(
+#if DBG
+ PSZ FuncName,
+#endif
+ LPDWORD lpMode
+ );
+
+DWORD
+Ow2SetInputConsoleMode(
+#if DBG
+ PSZ FuncName,
+#endif
+ DWORD dwMode
+ );
+
+CRITICAL_SECTION QueueInputCriticalSection;
+ULONG EventServerThreadSuspend = TRUE;
+ULONG NextEventServerThreadSuspend;
+HANDLE SuspendEvent;
+HANDLE HandsOffEvent;
+HANDLE HandsOnEvent;
+BOOL IgnoreNextMouseEventDueToFocus = FALSE;
+BOOL EventThreadHandsOff = FALSE;
+DWORD Ow2dwInputMode; /* Console Current Input Mode */
+DWORD Ow2dwWinInputMode; /* The desired mode (DefaultWinInputMode | ENABLE_MOUSE_INPUT) */
+
+#if DBG
+BYTE GetOs2MouEventIntoQueueStr[] = "GetOs2MouEventIntoQueue";
+BYTE Ow2GetOs2KbdEventIntoQueueStr[] = "Ow2GetOs2KbdEventIntoQueue";
+BYTE StartEventHandlerForSessionStr[] = "StartEventHandlerForSession";
+BYTE AddConAfterWinProcessStr[] = "AddConAfterWinProcess";
+BYTE RemoveConForWinProcessStr[] = "RemoveConForWinProcess";
+BYTE ReadInputEventStr[] = "ReadInputEvent";
+BYTE StartEventHandlerStr[] = "StartEventHandler";
+BYTE InitQueueStr[] = "InitQueue";
+BYTE InitMouQueueStr[] = "InitMouQueue";
+BYTE EventServerThreadStr[] = "EventServerThread";
+BYTE Ow2MouOnStr[] = "Ow2MouOn";
+BYTE Ow2MouOffStr[] = "Ow2MouOff";
+#endif
+
+#if DBG
+ULONG InternalDebug = 0;
+#define InputModeDebug 0001
+#define InputEventDebug 0002
+#endif
+
+
+PVOID
+StartEventHandlerForSession(VOID)
+{
+ DWORD NewInput = (OS2_DEFAULT_INPUT_MODE /*| ENABLE_MOUSE_INPUT*/);
+
+ EventLoop = TRUE;
+ InitializeCriticalSection(&QueueInputCriticalSection);
+ if (hStdInConsoleType)
+ {
+ hConsoleInput = hConsoleStdIn;
+ } else
+ {
+ hConsoleInput = Or2WinCreateFileW(
+ #if DBG
+ StartEventHandlerForSessionStr,
+ #endif
+ L"CONIN$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL, /* &SecurityAttributes */
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+
+ if (hConsoleInput == INVALID_HANDLE_VALUE)
+ {
+#if DBG
+ ASSERT1( "StartEvent: unable to create CONIN$", FALSE );
+#endif
+ // return(NULL);
+ }
+ }
+
+ if (!Or2WinGetConsoleMode(
+ #if DBG
+ StartEventHandlerForSessionStr,
+ #endif
+ hConsoleInput,
+ &DefaultWinInputMode
+ ))
+ {
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ ASSERT1( "StartEvent: Can not get CONIN Mode", FALSE );
+ }
+#endif
+ DefaultWinInputMode = WINDOW_DEFAULT_INPUT_MODE;
+ }
+
+ Ow2dwWinInputMode = DefaultWinInputMode /*| ENABLE_MOUSE_INPUT*/;
+ Ow2dwInputMode = DefaultWinInputMode;
+ InputModeFlags = WINDOW_DEFAULT_INPUT_MODE;
+
+ if (Ow2SetInputConsoleMode(
+ #if DBG
+ StartEventHandlerForSessionStr,
+ #endif
+ Ow2dwWinInputMode
+ ))
+ {
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ ASSERT1( "StartEvent: Can not set CONIN Mode", FALSE );
+ } else
+ KdPrint(("OS2SES(StartEvent): Can not set CONIN Mode\n"));
+#endif
+ } else
+ {
+ Ow2dwInputMode = Ow2dwWinInputMode;
+ }
+ InputModeFlags = NewInput;
+
+ HandleHeap = Or2WinHeapCreate(
+ #if DBG
+ StartEventHandlerForSessionStr,
+ #endif
+ 0, // Serialize the heap
+ HANDLE_HEAP_SIZE, // Init size = 64K
+ 0 // Max size is unlimited
+ );
+ if (HandleHeap == NULL)
+ {
+#if DBG
+ ASSERT1( "StartEvent: unable to create heap for event-queue", FALSE );
+#endif
+
+ return(NULL);
+ }
+
+ KbdEventQueueSize = PortMessageHeaderSize + KEYBOARD_QUEUE_SIZE;
+ MouEventQueueSize = PortMessageHeaderSize + MOUSE_QUEUE_SIZE;
+
+ //
+ // Complete window initialization and set SesGrp parameters
+ //
+
+ if( SesGrpInit() || KbdInit() || MouInit() || InitMonitor() || VioInitForSession() ||
+ AnsiInitForSession())
+ {
+ return(NULL);
+ }
+
+ SuspendEvent = Or2WinCreateEventW(
+ #if DBG
+ StartEventHandlerForSessionStr,
+ #endif
+ NULL,
+ FALSE, /* auto reset */
+ FALSE, // not set at creation
+ NULL
+ );
+
+ if (SuspendEvent == NULL)
+ {
+#if DBG
+ ASSERT1( "StartEvent: unable to create event", FALSE );
+#endif
+ return (NULL);
+ }
+
+ HandsOffEvent = Or2WinCreateEventW(
+ #if DBG
+ StartEventHandlerForSessionStr,
+ #endif
+ NULL,
+ FALSE, // auto reset
+ FALSE, // Clear at creation
+ NULL
+ );
+
+ if (HandsOffEvent == NULL)
+ {
+#if DBG
+ ASSERT1( "StartEvent: unable to create HandsOff event", FALSE );
+#endif
+ return (NULL);
+ }
+
+ HandsOnEvent = Or2WinCreateEventW(
+ #if DBG
+ StartEventHandlerForSessionStr,
+ #endif
+ NULL,
+ FALSE, // auto reset
+ TRUE, // Set at creation
+ NULL
+ );
+
+ if (HandsOnEvent == NULL)
+ {
+#if DBG
+ ASSERT1( "StartEvent: unable to create HandsOn event", FALSE );
+#endif
+ return (NULL);
+ }
+ Os2WindowFocus = (ULONG)-1;
+ return ((PVOID)KbdQueue);
+}
+
+
+PVOID
+StartEventHandler(VOID)
+{
+ HandleHeap = Or2WinHeapCreate(
+ #if DBG
+ StartEventHandlerStr,
+ #endif
+ 0, // Serialize the heap
+ HANDLE_HEAP_SIZE, // Init size = 64K
+ 0 // Max size is unlimited
+ );
+
+ if (HandleHeap == NULL)
+ {
+#if DBG
+ ASSERT1( "StartEvent(non root): unable to create heap for event-queue", FALSE );
+#endif
+
+ return(NULL);
+ }
+
+ if (VioInit() || AnsiInit())
+ {
+ return(NULL);
+ }
+
+ return ((PVOID)-1L);
+}
+
+
+DWORD
+InitQueue(IN PKEY_EVENT_QUEUE *ppKbdQueue)
+{
+ PKEY_EVENT_QUEUE pKbdQueue;
+ PBYTE Ptr;
+
+ *ppKbdQueue == NULL;
+
+ Ptr = Or2WinHeapAlloc(
+ #if DBG
+ InitQueueStr,
+ #endif
+ HandleHeap,
+ 0,
+ KbdEventQueueSize
+ );
+
+ if ( Ptr == NULL )
+ {
+#if DBG
+ KdPrint(("OS2SES(Event-InitKbdQueue): unable to allocate handle\n"));
+#endif
+ return ERROR_KBD_NO_MORE_HANDLE;
+ }
+
+ pKbdQueue = (PKEY_EVENT_QUEUE) ( Ptr + PortMessageHeaderSize );
+ RtlZeroMemory(pKbdQueue, sizeof(MON_HEADER));
+ pKbdQueue->MonHdr.MemoryStartAddress = Ptr;
+
+ pKbdQueue->In = pKbdQueue->Out = pKbdQueue->Event;
+ pKbdQueue->End = pKbdQueue->Event + (KEYBOARD_QUEUE_LENGTH-1);
+
+ if (KbdQueue != NULL)
+ {
+ pKbdQueue->Setup = KbdQueue->Setup;
+ pKbdQueue->Cp = KbdQueue->Cp;
+ pKbdQueue->bNlsShift = KbdQueue->bNlsShift;
+ }
+
+ pKbdQueue->Count = 1;
+
+ // add initialization for MON_HDR ( & to sign queue-end)
+
+ InitializeCriticalSection(&pKbdQueue->MonHdr.SyncCriticalSection);
+ pKbdQueue->MonHdr.MonReg.Pos = 3;
+ pKbdQueue->MonHdr.DevType = KbdDevice;
+
+ *ppKbdQueue = pKbdQueue;
+
+ return(FALSE);
+}
+
+
+DWORD
+InitMouQueue(IN PMOU_EVENT_QUEUE *ppMouQueue)
+{
+ PMOU_EVENT_QUEUE pMouQueue;
+ PBYTE Ptr;
+
+ *ppMouQueue = NULL;
+
+ Ptr = Or2WinHeapAlloc(
+ #if DBG
+ InitMouQueueStr,
+ #endif
+ HandleHeap,
+ 0,
+ MouEventQueueSize
+ );
+
+ if ( Ptr == NULL )
+ {
+#if DBG
+ KdPrint(("OS2SES(Event-InitMouQueue): unable to allocate handle\n"));
+#endif
+ return TRUE;
+ }
+
+ pMouQueue = (PMOU_EVENT_QUEUE) ( Ptr + PortMessageHeaderSize );
+ RtlZeroMemory(pMouQueue, sizeof(MON_HEADER));
+ pMouQueue->MonHdr.MemoryStartAddress = Ptr;
+
+ pMouQueue->In = pMouQueue->Out = pMouQueue->Event;
+ pMouQueue->End = pMouQueue->Event + (MOUSE_QUEUE_LENGTH-1);
+
+ // add initialization for MON_HDR ( & to sign queue-end)
+
+ InitializeCriticalSection(&pMouQueue->MonHdr.SyncCriticalSection);
+ pMouQueue->MonHdr.MonReg.Pos = 3;
+ pMouQueue->MonHdr.DevType = MouseDevice;
+
+ *ppMouQueue = pMouQueue;
+
+ return(FALSE);
+}
+
+
+DWORD
+AddConAfterWinProcess()
+{
+ DWORD Rc;
+
+
+ Or2WinEnterCriticalSection(
+ #if DBG
+ AddConAfterWinProcessStr,
+ #endif
+ &QueueInputCriticalSection
+ );
+ EventServerThreadSuspend = NextEventServerThreadSuspend;
+ if(EventServerThreadSuspend)
+ {
+ if(KbdMonQueue->MonHdr.WaitForEvent || MouMonQueue->MonHdr.WaitForEvent)
+ {
+ Or2WinSetEvent(
+ #if DBG
+ AddConAfterWinProcessStr,
+ #endif
+ SuspendEvent
+ );
+ EventServerThreadSuspend = FALSE;
+ }
+ }
+
+ Or2WinLeaveCriticalSection(
+ #if DBG
+ AddConAfterWinProcessStr,
+ #endif
+ &QueueInputCriticalSection
+ );
+
+ if (!Or2WinSetConsoleMode(
+ #if DBG
+ AddConAfterWinProcessStr,
+ #endif
+ hConsoleOutput,
+ SesGrp->OutputModeFlags
+ ))
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("ServeWinWaitThread: SetConsoleMode failed\n",
+ Rc));
+#endif
+ }
+
+ if (Ow2SetInputConsoleMode(
+ #if DBG
+ AddConAfterWinProcessStr,
+ #endif
+ Ow2dwWinInputMode
+ ))
+ {
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ ASSERT1( "AddConAfterWinProcess: Can not set CONIN Mode", FALSE );
+ } else
+ KdPrint(("OS2SES(AddConAfterWinProcess): Can not set CONIN Mode\n"));
+#endif
+ } else
+ {
+ Ow2dwInputMode = Ow2dwWinInputMode;
+ }
+ //
+ // Put EventServerThread back to work
+ //
+ Or2WinSetEvent(
+ #if DBG
+ AddConAfterWinProcessStr,
+ #endif
+ HandsOnEvent
+ );
+
+ return (NO_ERROR);
+}
+
+
+DWORD
+RemoveConForWinProcess()
+{
+ DWORD Rc;
+
+ EventThreadHandsOff = TRUE;
+ Or2WinEnterCriticalSection(
+ #if DBG
+ RemoveConForWinProcessStr,
+ #endif
+ &QueueInputCriticalSection
+ );
+
+ NextEventServerThreadSuspend = TRUE;
+
+ if(KbdMonQueue->MonHdr.WaitForEvent || MouMonQueue->MonHdr.WaitForEvent)
+ {
+ NextEventServerThreadSuspend = FALSE;
+ }
+ EventServerThreadSuspend = FALSE;
+
+ //
+ // Set the suspend event, to release EventServerThread, to
+ // will take hands off the console
+ //
+#if DBG
+ if (InternalDebug & InputEventDebug)
+ {
+ KdPrint(("RemoveConForWinProcess: SetEvent\n"));
+ }
+#endif
+ Or2WinSetEvent(
+ #if DBG
+ RemoveConForWinProcessStr,
+ #endif
+ SuspendEvent
+ );
+
+ //
+ // Write Back to console in case EventThread is in ReadInput()
+ //
+ Ow2WriteBackDummyEvent();
+
+ Or2WinLeaveCriticalSection(
+ #if DBG
+ RemoveConForWinProcessStr,
+ #endif
+ &QueueInputCriticalSection
+ );
+
+ //
+ // Wait to synchronize with EventServerThread
+ //
+ WaitForSingleObject(HandsOffEvent, INFINITE);
+
+ //
+ // Set default console mode here. We can be sure that EventServerThread will
+ // not change these settings, because it has set HandsOffEvent and going to
+ // wait on HandsOnEvent.
+ //
+
+ if (Rc = Ow2SetInputConsoleMode(
+ #if DBG
+ RemoveConForWinProcessStr,
+ #endif
+ DefaultWinInputMode
+ ))
+ {
+#if DBG
+ KdPrint(("OS2SES(RemoveConForWinProcess): SetConsoleMode(Input) failed \n"));
+#endif
+ }
+
+ if (!Or2WinSetConsoleMode(
+ #if DBG
+ RemoveConForWinProcessStr,
+ #endif
+ hConsoleOutput,
+ SesGrp->DefaultWinOutputMode
+ ))
+ {
+#if DBG
+ KdPrint(("OS2SES(event-RemoveConForWinProcess): SetConsoleMode(Output) failed \n"));
+#endif
+ }
+
+ return (0L);
+}
+
+
+DWORD
+EventServerThread(IN PVOID Parameter)
+{
+ UNREFERENCED_PARAMETER(Parameter);
+
+ try {
+
+restart:
+
+ WaitForSingleObject( HandsOnEvent, INFINITE );
+
+ if (SesGrp->Os2ssLCID != SesGrp->Win32LCID)
+ {
+ if(!Or2WinSetThreadLocale(
+ #if DBG
+ EventServerThreadStr,
+ #endif
+ SesGrp->Os2ssLCID
+ ))
+ {
+ ASSERT1("OS2SS(event): cannot set Thread Locale", FALSE);
+ }
+ }
+
+ EventServerThreadSuspend = TRUE;
+ for ( ; ; )
+ {
+ //SuspendEvent
+#if DBG
+ if (InternalDebug & InputEventDebug)
+ {
+ KdPrint(("EventServerThread: WaitEvent\n"));
+ }
+#endif
+ //
+ // Wait for an application to ask for Keyboard/Monitor/Mouse
+ //
+ while (WaitForSingleObject( SuspendEvent, INFINITE ));
+
+#if PMNT
+ /*
+ * Terminate EventServerThread for PMNT processes.
+ */
+ if (ProcessIsPMProcess()) {
+ NtClose(EventServerThreadHandle);
+ ExitThread(0L);
+ }
+#endif
+
+ if (EventThreadHandsOff) {
+ EventThreadHandsOff = FALSE;
+ //
+ // RemoveConForWinProcess puts a dummy event to wake this
+ // thread from ReadInputEvent, clear it is there
+ //
+ Ow2ClearupDummyEvent();
+ SetEvent( HandsOffEvent );
+ goto restart;
+ }
+
+ EventServerThreadSuspend = FALSE;
+
+ ReadInputEvent(0L); // read next event
+ if (EventThreadHandsOff) {
+ EventThreadHandsOff = FALSE;
+ //
+ // RemoveConForWinProcess puts a dummy event to wake this
+ // thread from ReadInputEvent, clear it is there
+ //
+ Ow2ClearupDummyEvent();
+ SetEvent( HandsOffEvent );
+ goto restart;
+ }
+
+ EnterCriticalSection(&QueueInputCriticalSection);
+ if (EventThreadHandsOff) {
+ EventThreadHandsOff = FALSE;
+ //
+ // RemoveConForWinProcess puts a dummy event to wake this
+ // thread from ReadInputEvent, clear it is there
+ //
+ Ow2ClearupDummyEvent();
+ SetEvent( HandsOffEvent );
+ LeaveCriticalSection(&QueueInputCriticalSection);
+ goto restart;
+ }
+
+ if(KbdMonQueue->MonHdr.WaitForEvent || MouMonQueue->MonHdr.WaitForEvent ||
+ SesGrp->PauseScreenUpdate )
+ {
+#if DBG
+ if (InternalDebug & InputEventDebug)
+ {
+ KdPrint(("EventServerThread: SetEvent\n"));
+ }
+#endif
+ SetEvent( SuspendEvent );
+ } else
+ {
+ EventServerThreadSuspend = TRUE;
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+ }
+
+ }
+ //
+ // if Os2Debug is on, and ntsd is attached, it will get the second chance
+ //
+#if DBG
+ except( (Os2Debug ? Ow2FaultFilter(EXCEPTION_CONTINUE_SEARCH, GetExceptionInformation()):
+
+ Ow2FaultFilter(EXCEPTION_EXECUTE_HANDLER, GetExceptionInformation())) ) {
+#else
+ except( Ow2FaultFilter(EXCEPTION_EXECUTE_HANDLER, GetExceptionInformation()) ) {
+#endif
+
+#if DBG
+ KdPrint(("OS2SES: Internal error - Exception occured in EventServerThread\n"));
+#endif
+ Ow2DisplayExceptionInfo();
+ ExitThread(1);
+ }
+ ExitThread(0L);
+ return(0L);
+}
+
+
+DWORD
+ReadInputEvent(IN ULONG PeekFlag)
+/*++
+
+Routine Description:
+
+ This routine get next Input Event from queue and handle it
+ according to the EventType.
+
+Arguments:
+
+ PeekFlag - indicate if should try to peek before read (1)
+ or to wait till next event(0).
+
+Return Value:
+
+ 0 - no event
+
+ -1 - try again (event was ignore or was illegal)
+
+ other (KEY_EVENT, MOUSE_EVENT) - type of the event read and handled
+
+ (WINDOW_BUFFER_SIZE_EVENT, MENU_EVENT, FOCUS_EVENT)
+
+Note:
+
+--*/
+{
+ INPUT_RECORD In;
+ KEYEVENTINFO KbdEvent[3];
+ MOU_MON_PACKAGE MouEvent;
+ DWORD cEvents, Rc, RetCode = 0, i, j, NumKbd;
+ DWORD InConMode;
+ BOOL ReadInputFail = FALSE;
+
+ /*
+ * 1. Set ConsoleInputMode
+ *
+ * This is done if there is other proess performing ReadConsoleInput
+ * from the same win-session (who might change the input mode).
+ * Another reason: when KbdRead(or KbdCharIn) is stopped for a long
+ * period for another processing, the OS2SS won't detect ^C (like
+ * ISQL, bug# 1341, 3/31/93 MJarus).
+ */
+
+ InConMode = WINDOW_DEFAULT_INPUT_MODE;
+ if (Ow2GetInputConsoleMode(
+ #if DBG
+ ReadInputEventStr,
+ #endif
+ &InConMode
+ ))
+ {
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ ASSERT1( "ReadInputEvent: Can not get CONIN Mode", FALSE );
+ }
+#endif
+ }
+
+ Ow2SetInputConsoleMode(
+ #if DBG
+ ReadInputEventStr,
+ #endif
+ InputModeFlags
+ );
+
+ /*
+ * 2. Peek ConsoleInput
+ *
+ * In case ReadInputEvent is called from KbdXxxx, MouXxxx or DosMonXxx
+ * API and there is no data in buffer.
+ * PeekConsoleInput is called before ReadConsoleInput to check if there
+ * is data in the input queue. If no data (and wait is ON) -
+ * EventServerThread will resume to wait for the data and will send reply
+ * to client.
+ */
+
+ if (PeekFlag)
+ {
+ if (!PeekConsoleInputW(
+ hConsoleInput,
+ &In,
+ 1L,
+ &cEvents
+ ))
+ { /* check why, should not happend */
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ ASSERT1("EventServer: unable to peek from CONIN$", FALSE);
+ } else
+ {
+ KdPrint(("OS2SES(EventSever): unable to peek from CONIN$\n"));
+ }
+#endif
+ ReadInputFail = TRUE;
+ RetCode = (DWORD)-1;
+ } else if (cEvents != 1L)
+ {
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ //KdPrint(("OS2SES(EventSever): no data peeked from CONIN$\n"));
+ }
+#endif
+ ReadInputFail = TRUE;
+ //RetCode = 0;
+ }
+
+ if ( ReadInputFail )
+ {
+ Ow2SetInputConsoleMode(
+ #if DBG
+ ReadInputEventStr,
+ #endif
+ InConMode
+ );
+
+ return(RetCode);
+ }
+ }
+
+ /*
+ * 3. Read ConsoleInput
+ *
+ * Wait for InputEvent
+ */
+
+ if (!ReadConsoleInputW(
+ hConsoleInput,
+ &In,
+ 1L,
+ &cEvents
+ ))
+ { /* check why, should not happend */
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ ASSERT1("EventServer: unable to read from CONIN$", FALSE);
+ } else
+ KdPrint(("OS2SES(EventSever): unable to read from CONIN$\n"));
+#endif
+ ReadInputFail = TRUE;
+ RetCode = (DWORD)-1L;
+ } else if (cEvents != 1L)
+ { /* check why, should not happend */
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ ASSERT1( "EventServer: no data read from CONIN$", FALSE );
+ } else
+ KdPrint(("OS2SES(EventSever): no data read from CONIN$\n"));
+#endif
+ ReadInputFail = TRUE;
+ RetCode = (DWORD)-1L;
+ }
+
+ Ow2SetInputConsoleMode(
+ #if DBG
+ ReadInputEventStr,
+ #endif
+ InConMode
+ );
+
+ if ( ReadInputFail )
+ {
+ return(RetCode);
+ }
+
+ /*
+ * 4. Get Time Stamp (needed for KBD and MOUSE events)
+ *
+ * Set RetCode to be the EventType (in case the event
+ * will be handled)
+ *
+ * Handle the Event according its type
+ */
+
+ RetCode = (DWORD)In.EventType;
+
+ if (In.EventType != MOUSE_EVENT)
+ {
+ IgnoreNextMouseEventDueToFocus = FALSE;
+ }
+
+ switch (In.EventType)
+ {
+ case KEY_EVENT :
+ RetCode = (DWORD)-1L;
+ for ( i = In.Event.KeyEvent.wRepeatCount,
+ In.Event.KeyEvent.wRepeatCount = 1 ; i ; i-- )
+ {
+
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("EventServer(KBD): queue %lx, char %x\n",
+ KbdMonQueue, In.Event.KeyEvent.uChar.AsciiChar));
+ }
+#endif
+
+ /*
+ * update KbdInfo: Kbd-data & time
+ */
+
+ if (!(NumKbd = MapWin2Os2KbdInfo(&(In.Event.KeyEvent),
+ &KbdEvent[0])))
+ {
+ continue;
+ }
+
+ KbdEvent[0].KeyInfo[0].KeyInfo.time = GetTickCount();
+
+ /*
+ * ^Break
+ * ^C for ASCII mode only
+ *
+ */
+
+ if (Rc = CheckForBreakEvent(&KbdEvent[0]))
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ {
+ KdPrint(("Event: CheckForBreakEvent %u, ignore char\n", Rc));
+ }
+#endif
+ if (Rc == 1) // not PopUp
+ {
+ //BUGBUG release Waiting threads
+ }
+
+ continue;
+ }
+
+ /*
+ * write event
+ */
+
+ for ( j = 0 ; j < NumKbd ; j++ )
+ {
+ Rc = (USHORT)PutMonInput(
+ sizeof(KBD_MON_PACKAGE),
+ KbdMonQueue,
+ KbdEvent[0].wRepeatCount,
+ &KbdEvent[j].KeyInfo[0],
+ NULL,
+ NULL);
+
+ if (Rc)
+ {
+ /* BUGBUG=> ? beep */
+ i = 1;
+ break;
+ }
+ RetCode = KEY_EVENT;
+ //RetCode = 0;
+ }
+ }
+ break;
+
+ case MOUSE_EVENT :
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("EventServer(MOU): State %x, Flag %x, Pos %u-%u, queue %lx\n",
+ In.Event.MouseEvent.dwButtonState,
+ In.Event.MouseEvent.dwEventFlags,
+ In.Event.MouseEvent.dwMousePosition.Y,
+ In.Event.MouseEvent.dwMousePosition.X,
+ MouMonQueue));
+ } else IF_OD2_DEBUG( MOU )
+ {
+ KdPrint(("EventServer: State %x, Flag %x, Pos %u-%u\n",
+ In.Event.MouseEvent.dwButtonState,
+ In.Event.MouseEvent.dwEventFlags,
+ In.Event.MouseEvent.dwMousePosition.Y,
+ In.Event.MouseEvent.dwMousePosition.X));
+ }
+#endif
+ //
+ // YS - 6.8.93 overcome the case where the console position is negative
+ //
+ if ( (LONG)(In.Event.MouseEvent.dwMousePosition.X) < 0)
+ {
+ In.Event.MouseEvent.dwMousePosition.X = 0;
+ }
+
+ if ( (LONG)(In.Event.MouseEvent.dwMousePosition.Y) < 0)
+ {
+ In.Event.MouseEvent.dwMousePosition.Y = 0;
+ }
+
+ MouPtrLoc.row = In.Event.MouseEvent.dwMousePosition.Y;
+ MouPtrLoc.col = In.Event.MouseEvent.dwMousePosition.X;
+
+ if(IgnoreNextMouseEventDueToFocus &&
+ In.Event.MouseEvent.dwButtonState &&
+ (In.Event.MouseEvent.dwEventFlags == MOUSE_MOVED))
+ {
+ In.Event.MouseEvent.dwButtonState = 0;
+ }
+
+ IgnoreNextMouseEventDueToFocus = FALSE;
+
+ /*
+ * update MouInfo: Mou-data & time
+ */
+
+ if (!MouNumber ||
+ (MouDevStatus & MOUSE_DISABLED) ||
+ !MapWin2Os2MouEvent(&MouEvent.MouInfo,
+ &In.Event.MouseEvent))
+ {
+ RetCode = (DWORD)-1L;
+ break;
+ }
+
+ MouEvent.MouInfo.time = GetTickCount();
+ /*
+ * write mouse event to queue
+ */
+
+ Rc = (USHORT)PutMonInput(
+ sizeof(MOU_MON_PACKAGE),
+ (PKEY_EVENT_QUEUE)MouMonQueue,
+ 1,
+ (PKBD_MON_PACKAGE)&MouEvent,
+ NULL,
+ NULL);
+
+ if (!Rc && !MouEvent.MouInfo.fs)
+ {
+ /*
+ * Release of last button - add OS2_MOUSE_MOTION
+ */
+
+ MouEvent.MouInfo.fs = OS2_MOUSE_MOTION;
+
+ Rc = (USHORT)PutMonInput(
+ sizeof(MOU_MON_PACKAGE),
+ (PKEY_EVENT_QUEUE)MouMonQueue,
+ 1,
+ (PKBD_MON_PACKAGE)&MouEvent,
+ NULL,
+ NULL);
+ }
+
+ if (Rc)
+ /* BUGBUG=> ? over-write last event */ ;
+
+ break;
+
+ case WINDOW_BUFFER_SIZE_EVENT :
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ KdPrint(("EventServer: window event size %x:%x\n",
+ In.Event.WindowBufferSizeEvent.dwSize.Y,
+ In.Event.WindowBufferSizeEvent.dwSize.X));
+ }
+#endif
+ break;
+
+ case MENU_EVENT :
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ KdPrint(("EventServer: menu event command %x\n",
+ In.Event.MenuEvent.dwCommandId));
+ }
+#endif
+ break;
+
+ case FOCUS_EVENT :
+ if(Os2WindowFocus != (ULONG)In.Event.FocusEvent.bSetFocus)
+ {
+ //if(Os2WindowFocus != (ULONG)-1)
+ {
+ SendNewFocusSet((ULONG)In.Event.FocusEvent.bSetFocus);
+ }
+
+ Os2WindowFocus = (ULONG)In.Event.FocusEvent.bSetFocus;
+ IgnoreNextMouseEventDueToFocus = Os2WindowFocus;
+ }
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ KdPrint(("EventServer: focus event(%u-%s)\n",
+ In.Event.FocusEvent.bSetFocus,
+ (In.Event.FocusEvent.bSetFocus) ? "Set" : "Reset"));
+ }
+#endif
+ break;
+
+ default :
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ KdPrint(("OS2SES(Event): unknown event %x\n",
+ In.EventType));
+ }
+#endif
+ RetCode = (DWORD)-1L;
+ break;
+ }
+ return(RetCode);
+}
+
+
+DWORD
+CheckForBreakEvent(IN PKEYEVENTINFO KbdEvent)
+{
+ DWORD Rc = 0;
+ UCHAR Os2ScanCode = KbdEvent->KeyInfo[0].KeyInfo.chScan;
+ BOOL Os2ControlOn = ( KbdEvent->KeyInfo[0].KeyInfo.fsState & OS2_CONTROL );
+
+ /*
+ * 1. ^Break
+ * ^C for ASCII mode only
+ * 2. Pause
+ * ^S - (not paused)
+ * 3. End-Pause
+ *
+ * return: 0 - character
+ * 1 - ^Break/^C
+ * 2 - ignore (^Break/^C in PopUp, ^S[pause], end_pause)
+ */
+
+ if (( KbdEvent->KeyInfo[0].KeyboardFlag & KBD_KEY_BREAK ) ||
+ ( KbdEvent->KeyInfo[0].KeyInfo.fbStatus & 1 ))
+ {
+ // ignore:
+ // break
+ // shift
+
+ return (0);
+ }
+
+ if ( SesGrp->PauseScreenUpdate )
+ {
+ // Screen is Paused: release (if no ^C or ^BRK) and ignore key (always)
+
+ if ( Os2ScanCode != 0xFF ) // not pause
+ {
+ EnableScreenUpdate();
+ }
+
+ Rc = 2;
+ } else if (( Os2ControlOn && ( Os2ScanCode == 0x1F ) && KbdAsciiMode ) ||
+ ( !Os2ControlOn && ( Os2ScanCode == 0xFF )))
+ {
+ // ^S in ASCII or PAUSE (but not ^)
+
+ DisableScreenUpdate();
+ return (2);
+ }
+
+ if ( !Os2ControlOn )
+ {
+ return (Rc);
+ }
+
+ if (( Os2ScanCode == 0xFF ) || // ^Brk
+ (( Os2ScanCode == 0x2E ) && KbdAsciiMode )) // ^C in ACSII mode
+ {
+
+ if (hPopUpOutput != (HANDLE) NULL ) // PopUp - ignore
+ {
+ return (2);
+ }
+
+#if DBG
+ IF_OD2_DEBUG( CLEANUP )
+ {
+ if ( Os2ScanCode == 0x2E )
+ KdPrint(("Os2: send ^C event to server\n"));
+ else
+ KdPrint(("Os2: send ^Break event to server\n"));
+ }
+#endif
+
+ //EventLoop = FALSE;
+
+ SendSignalToOs2Srv(
+ ( Os2ScanCode == 0x2E) ?
+ XCPT_SIGNAL_INTR : XCPT_SIGNAL_BREAK);
+
+#if DBG
+ IF_OD2_DEBUG( CLEANUP )
+ {
+ KdPrint(("Os2: event was send\n"));
+ }
+#endif
+
+ return (1);
+ }
+
+ if ( Os2ControlOn && KbdAsciiMode && ( Os2ScanCode == 0x19 ) && // ^P in ASCII
+ !( KbdEvent->KeyInfo[0].KeyInfo.fsState & OS2_ALT ))
+ {
+ return (2);
+ }
+
+ return (Rc);
+}
+
+
+DWORD
+GetKeyboardInput( IN ULONG Flag,
+ OUT PKEYEVENTINFO Event,
+ IN PVOID pMsg,
+ OUT PULONG pReply)
+{
+ WORD KeyCount = Event->wRepeatCount;
+ DWORD Rc;
+ BOOL IgnoreKey;
+
+ for ( ; EventLoop ; )
+ {
+ if ( KbdQueue->In == KbdQueue->Out )
+ {
+ SaveKbdPortMessegeInfo(KbdQueue->MonHdr.MemoryStartAddress,
+ (PVOID)&KbdRequestSaveArea,
+ pMsg);
+
+ /*
+ * Enter critical Section
+ */
+
+ EnterCriticalSection(&QueueInputCriticalSection);
+
+ if (KbdQueue->In == KbdQueue->Out)
+ {
+ if (!EventServerThreadSuspend)
+ {
+ goto NoKbdReturn;
+ }
+
+ if (KbdQueue != KbdMonQueue)
+ {
+ goto NoKbdReturn;
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+
+ while ((Rc = ReadInputEvent(1L)) && (Rc != (DWORD)KEY_EVENT))
+ {
+ ;
+ }
+
+ EnterCriticalSection(&QueueInputCriticalSection);
+
+ if (KbdQueue->In == KbdQueue->Out)
+ {
+ if (EventServerThreadSuspend &&
+ ((( Flag & WAIT_MASK) != IO_NOWAIT ) ||
+ SesGrp->PauseScreenUpdate ))
+ {
+#if DBG
+ if (InternalDebug & InputEventDebug)
+ {
+ KdPrint(("GetKeyboardInput: SetEvent\n"));
+ }
+#endif
+ SetEvent( SuspendEvent );
+ }
+NoKbdReturn:
+ if ((Flag & WAIT_MASK) != IO_NOWAIT)
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ {
+ KdPrint(("GetKeyboardInput: no kbd so wait\n"));
+ }
+#endif
+ KbdQueue->MonHdr.WaitForEvent = TRUE;
+ *pReply = 0;
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+ return (NO_ERROR);
+ } else if ( SesGrp->PauseScreenUpdate && EventServerThreadSuspend )
+ {
+#if DBG
+ if (InternalDebug & InputEventDebug)
+ {
+ KdPrint(("GetKeyboardInput 2: SetEvent\n"));
+ }
+#endif
+ SetEvent( SuspendEvent );
+ }
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+
+ } else
+ {
+ *Event = *(KbdQueue->Out);
+
+ IgnoreKey = (BOOL)KbdCheckPackage(&Event->KeyInfo[0]);
+
+ if ( IgnoreKey || ( KbdQueue->Out->wRepeatCount <= KeyCount ))
+ {
+ if (KbdQueue->Out == KbdQueue->End)
+ KbdQueue->Out = KbdQueue->Event;
+ else
+ KbdQueue->Out++;
+ } else
+ {
+ KbdQueue->Out->wRepeatCount -= KeyCount;
+ Event->wRepeatCount = KeyCount;
+ }
+
+ if ( !IgnoreKey )
+ {
+ return (1L);
+ }
+ }
+ }
+
+ return (0L);
+}
+
+
+DWORD
+GetOs2MouEvent( IN USHORT WaitFlag,
+ OUT PMOUEVENTINFO Event,
+ IN PVOID pMsg,
+ OUT PULONG pReply)
+{
+ DWORD Rc;
+
+ for ( ; EventLoop ; )
+ {
+ if (MouQueue->In == MouQueue->Out)
+ {
+ SavePortMessegeInfo(MouQueue->MonHdr.MemoryStartAddress, pMsg);
+
+ /*
+ * Enter critical Section
+ */
+
+ EnterCriticalSection(&QueueInputCriticalSection);
+
+ if (MouQueue->In == MouQueue->Out)
+ {
+ if (!EventServerThreadSuspend)
+ {
+ goto NoMouReturn;
+ }
+
+ if (MouQueue != MouMonQueue)
+ {
+ goto NoMouReturn;
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+
+ while ((Rc = ReadInputEvent(1L)) && (Rc != (DWORD)MOUSE_EVENT))
+ {
+ ;
+ }
+
+ EnterCriticalSection(&QueueInputCriticalSection);
+
+ if (MouQueue->In == MouQueue->Out)
+ {
+ if (EventServerThreadSuspend &&
+ (( WaitFlag != MOU_NOWAIT ) ||
+ SesGrp->PauseScreenUpdate ))
+ {
+#if DBG
+ if (InternalDebug & InputEventDebug)
+ {
+ KdPrint(("GetOs2MouEvent: SetEvent\n"));
+ }
+#endif
+ SetEvent( SuspendEvent );
+ }
+NoMouReturn:
+ if ( WaitFlag != MOU_NOWAIT)
+ {
+ MouQueue->MonHdr.WaitForEvent = TRUE;
+ *pReply = 0;
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+ return (NO_ERROR);
+ } else if ( SesGrp->PauseScreenUpdate && EventServerThreadSuspend )
+ {
+#if DBG
+ if (InternalDebug & InputEventDebug)
+ {
+ KdPrint(("GetOs2MouEvent 2: SetEvent\n"));
+ }
+#endif
+ SetEvent( SuspendEvent );
+ }
+
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+
+ } else
+ {
+ *Event = MouQueue->Out->MouInfo;
+
+ if (MouQueue->Out == MouQueue->End)
+ MouQueue->Out = MouQueue->Event;
+ else
+ MouQueue->Out++;
+#if DBG
+ IF_OD2_DEBUG( MOU )
+ {
+ KdPrint(("GetOs2MouEvent: fs %x, Pos %u-%u, Time %u\n",
+ Event->fs, Event->row, Event->col, Event->time ));
+ }
+#endif
+ return (0L);
+ }
+ }
+
+ return (0L);
+}
+
+
+DWORD
+Ow2GetOs2KbdEventIntoQueue()
+{
+ DWORD Rc, NumEvent, ReadDone = FALSE;
+
+ if (!EventServerThreadSuspend)
+ {
+ return (0L);
+ }
+ Or2WinGetNumberOfConsoleInputEvents(
+ #if DBG
+ Ow2GetOs2KbdEventIntoQueueStr,
+ #endif
+ hConsoleInput,
+ &NumEvent
+ );
+ for ( ; NumEvent ; )
+ {
+ while ((Rc = ReadInputEvent(1L)) && (Rc != (DWORD)KEY_EVENT));
+ if (!Rc)
+ {
+ // No more events
+
+ break;
+ }
+ ReadDone = TRUE;
+ Or2WinGetNumberOfConsoleInputEvents(
+ #if DBG
+ Ow2GetOs2KbdEventIntoQueueStr,
+ #endif
+ hConsoleInput,
+ &NumEvent
+ );
+ }
+
+ if ( ReadDone && EventServerThreadSuspend && SesGrp->PauseScreenUpdate )
+ {
+ EnterCriticalSection(&QueueInputCriticalSection);
+ if ( EventServerThreadSuspend && SesGrp->PauseScreenUpdate )
+ {
+#if DBG
+ if (InternalDebug & InputEventDebug)
+ {
+ KdPrint(("Ow2GetOs2KbdEventIntoQueue: SetEvent\n"));
+ }
+#endif
+ SetEvent( SuspendEvent );
+ }
+ LeaveCriticalSection(&QueueInputCriticalSection);
+ }
+
+ return (0L);
+}
+
+
+DWORD
+GetOs2MouEventIntoQueue()
+{
+ DWORD Rc, NumEvent, ReadDone = FALSE;
+ PMOU_MON_PACKAGE NextMouIn;
+
+ if (!EventServerThreadSuspend)
+ {
+ return (0L);
+ }
+ Or2WinGetNumberOfConsoleInputEvents(
+ #if DBG
+ GetOs2MouEventIntoQueueStr,
+ #endif
+ hConsoleInput,
+ &NumEvent
+ );
+ for ( ; NumEvent ; )
+ {
+ NextMouIn = (MouMonQueue->In == MouMonQueue->End) ?
+ MouMonQueue->Event :
+ (MouMonQueue->In+1);
+
+ if (NextMouIn == MouQueue->Out)
+ {
+ // QUEUE is full
+
+ break;
+ } else
+ {
+ while ((Rc = ReadInputEvent(1L)) && (Rc != (DWORD)MOUSE_EVENT));
+ if (!Rc)
+ {
+ // No more events
+
+ break;
+ }
+ ReadDone = TRUE;
+ }
+ Or2WinGetNumberOfConsoleInputEvents(
+ #if DBG
+ GetOs2MouEventIntoQueueStr,
+ #endif
+ hConsoleInput,
+ &NumEvent
+ );
+ }
+
+ if ( ReadDone && EventServerThreadSuspend && SesGrp->PauseScreenUpdate )
+ {
+ EnterCriticalSection(&QueueInputCriticalSection);
+ if ( EventServerThreadSuspend && SesGrp->PauseScreenUpdate )
+ {
+#if DBG
+ if (InternalDebug & InputEventDebug)
+ {
+ KdPrint(("GetOs2MouEventIntoQueue: SetEvent\n"));
+ }
+#endif
+ SetEvent( SuspendEvent );
+ }
+ LeaveCriticalSection(&QueueInputCriticalSection);
+ }
+
+ return (0L);
+}
+
+
+DWORD
+GetMonInput(IN USHORT MaxLength, // BUGBUG - not implemented
+ IN PKEY_EVENT_QUEUE KbdMon,
+ IN OUT PMON_RW rwParms,
+ IN PVOID pMsg,
+ OUT PULONG pReply)
+{
+ PMOU_EVENT_QUEUE MouMon;
+ PMOU_MON_PACKAGE MouPackage;
+ PKBD_MON_PACKAGE MonPackage;
+ DWORD Rc;
+
+ UNREFERENCED_PARAMETER(MaxLength);
+
+ if (KbdMon->MonHdr.DevType == KbdDevice)
+ {
+ MonPackage = (PKBD_MON_PACKAGE) &(rwParms->ioBuff[0]);
+
+ for ( ; EventLoop ; )
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("OS2SES(GetMonInput): enter, queue %lx\n", KbdMon));
+ }
+#endif
+
+ if (KbdMon->LastKeyFlag)
+ {
+ *MonPackage = KbdMon->LastKey.KeyInfo[0];
+ KbdMon->LastKey.wRepeatCount-- ;
+
+ if (KbdMon->LastKey.wRepeatCount == 0)
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("OS2SES(GetMonInput): no more last\n"));
+ }
+#endif
+
+ KbdMon->LastKeyFlag = FALSE;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("OS2SES(GetMonInput): return last\n"));
+ }
+#endif
+
+ return(NO_ERROR);
+ }
+
+ if (KbdMon->In == KbdMon->Out)
+ {
+ SavePortMessegeInfo(KbdMon->MonHdr.MemoryStartAddress, pMsg);
+
+ /*
+ * Enter critical Section
+ */
+
+ EnterCriticalSection(&QueueInputCriticalSection);
+
+ if (KbdMon->In == KbdMon->Out)
+ {
+ if (!EventServerThreadSuspend)
+ {
+ goto NoMonReturn;
+ }
+
+ if (KbdMon != KbdMonQueue)
+ {
+ goto NoMonReturn;
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+
+ while ((Rc = ReadInputEvent(1L)) && (Rc != (DWORD)KEY_EVENT))
+ {
+ ;
+ }
+
+ EnterCriticalSection(&QueueInputCriticalSection);
+
+ if (KbdMon->In == KbdMon->Out)
+ {
+ if (EventServerThreadSuspend &&
+ ( !rwParms->fWait || SesGrp->PauseScreenUpdate ))
+ {
+#if DBG
+ if (InternalDebug & InputEventDebug)
+ {
+ KdPrint(("GetMonInput: SetEvent\n"));
+ }
+#endif
+ SetEvent( SuspendEvent );
+ }
+NoMonReturn:
+ if ( !rwParms->fWait )
+ {
+ Rc = NO_ERROR;
+ *pReply = 0;
+ KbdMon->MonHdr.WaitForEvent = TRUE;
+ } else
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("OS2SES(GetMonInput-Kbd): no wait\n"));
+ }
+#endif
+ //Rc = NO_ERROR;
+ Rc = ERROR_MON_BUFFER_EMPTY;
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+ return (Rc);
+ } else if ( SesGrp->PauseScreenUpdate && EventServerThreadSuspend )
+ {
+#if DBG
+ if (InternalDebug & InputEventDebug)
+ {
+ KdPrint(("GetMonInput 2: SetEvent\n"));
+ }
+#endif
+ SetEvent( SuspendEvent );
+ }
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+
+ } else
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("OS2SES(GetMonInput): found package\n"));
+ }
+#endif
+
+ *MonPackage = KbdMon->Out->KeyInfo[0];
+
+ if (KbdMon->Out->wRepeatCount != 1)
+ {
+ /*
+ * decrement count and keep package
+ */
+
+ KbdMon->LastKey = *KbdMon->Out;
+ KbdMon->LastKey.wRepeatCount-- ;
+ KbdMon->LastKey.KeyInfo[0].KeyboardFlag |= KBD_MULTIMAKE;
+ KbdMon->LastKeyFlag = TRUE;
+
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("OS2SES(GetMonInput): package saved as last\n"));
+ }
+#endif
+ }
+
+ /*
+ * update OUT pointer
+ */
+
+ if (KbdMon->Out == KbdMon->End)
+ KbdMon->Out = KbdMon->Event;
+ else
+ KbdMon->Out++;
+
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("OS2SES(GetMonInput): last repeat of package\n"));
+ }
+#endif
+
+ return (NO_ERROR);
+ }
+ }
+
+ } else
+ {
+ MouMon = (PMOU_EVENT_QUEUE) KbdMon;
+ MouPackage = (PMOU_MON_PACKAGE) &(rwParms->ioBuff[0]);
+
+ for ( ; EventLoop ; )
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("OS2SES(GetMonInput): enter, queue %lx\n", MouMon));
+ }
+#endif
+
+ if (MouMon->LastMouFlag)
+ {
+ *MouPackage = MouMon->LastEvent;
+ MouMon->LastMouFlag = FALSE;
+
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("OS2SES(GetMonInput): return last\n"));
+ }
+#endif
+
+ return (NO_ERROR);
+ }
+
+ if (MouMon->In == MouMon->Out)
+ {
+ SavePortMessegeInfo(MouMon->MonHdr.MemoryStartAddress, pMsg);
+
+ /*
+ * Enter critical Section
+ */
+
+ EnterCriticalSection(&QueueInputCriticalSection);
+
+ if (MouMon->In == MouMon->Out)
+ {
+ if (!EventServerThreadSuspend)
+ {
+ goto NoMouseMonReturn;
+ }
+
+ if (MouMon != MouMonQueue)
+ {
+ goto NoMouseMonReturn;
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+
+ while ((Rc = ReadInputEvent(1L)) && (Rc != (DWORD)MOUSE_EVENT))
+ {
+ ;
+ }
+
+ EnterCriticalSection(&QueueInputCriticalSection);
+
+ if (MouMon->In == MouMon->Out)
+ {
+ if (EventServerThreadSuspend &&
+ ( !rwParms->fWait || SesGrp->PauseScreenUpdate ))
+ {
+#if DBG
+ if (InternalDebug & InputEventDebug)
+ {
+ KdPrint(("GetMonInput-Mou: SetEvent\n"));
+ }
+#endif
+ SetEvent( SuspendEvent );
+ }
+NoMouseMonReturn:
+ if ( !rwParms->fWait )
+ {
+ Rc = NO_ERROR;
+ *pReply = 0;
+ MouMon->MonHdr.WaitForEvent = TRUE;
+ } else
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("OS2SES(GetMonInput-Mouse): no wait\n"));
+ }
+#endif
+ //Rc = NO_ERROR;
+ Rc = ERROR_MON_BUFFER_EMPTY;
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+ return (Rc);
+ } else if ( SesGrp->PauseScreenUpdate && EventServerThreadSuspend )
+ {
+#if DBG
+ if (InternalDebug & InputEventDebug)
+ {
+ KdPrint(("GetMonInput-Mou 2: SetEvent\n"));
+ }
+#endif
+ SetEvent( SuspendEvent );
+ }
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+
+ } else
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("OS2SES(GetMonInput): found package\n"));
+ }
+#endif
+
+ *MouPackage = *MouMon->Out;
+
+ /*
+ * update OUT pointer
+ */
+
+ if (MouMon->Out == MouMon->End)
+ MouMon->Out = MouMon->Event;
+ else
+ MouMon->Out++;
+
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("OS2SES(GetMonInput): last repeat of package\n"));
+ }
+#endif
+
+ return (NO_ERROR);
+ }
+ }
+
+ }
+ return(0L);
+}
+
+
+DWORD
+PutMonInput(
+ IN USHORT MaxLength, // BUGBUG - not implemented
+ IN PKEY_EVENT_QUEUE NextKbdMon,
+ IN WORD RepeatCount,
+ IN PKBD_MON_PACKAGE MonPackage,
+ //IN OUT PMON_RW rwParms,
+ IN PVOID pMsg,
+ OUT PULONG pReply)
+{
+ /* return non-zero if no place */
+
+ PKEYEVENTINFO NextKbdIn;
+ BOOL FirstEvent;
+ PMOU_MON_PACKAGE MouPackage;
+ //PKBD_MON_PACKAGE MonPackage;
+ PMOU_MON_PACKAGE NextMouIn;
+ PMOU_EVENT_QUEUE NextMouMon;
+
+ UNREFERENCED_PARAMETER(MaxLength);
+ UNREFERENCED_PARAMETER(pMsg);
+ UNREFERENCED_PARAMETER(pReply);
+
+ if (NextKbdMon->MonHdr.DevType == KbdDevice)
+ {
+ //MonPackage = (PKBD_MON_PACKAGE) &(rwParms->ioBuff[0]);
+
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("OS2SES(PutMonInput): enter, to queue %lx, char %x\n",
+ NextKbdMon, MonPackage->KeyInfo.chChar ));
+ }
+#endif
+
+ if (( NextKbdMon == KbdQueue ) && /* last monitor in queue */
+ (( MonPackage->KeyboardFlag & KeyTypeMask ) == AccentKey ) &&
+ !( MonPackage->KeyboardFlag & AccentedKey ))
+ {
+#if DBG
+ IF_OD2_DEBUG2( MON, KBD )
+ {
+ KdPrint(("OS2SES(PutMonInput): ignore package for DeviceFlag=0x%x\n",
+ MonPackage->DeviceFlag ));
+ }
+#endif
+ return (0L);
+ }
+
+ NextKbdMon->In->KeyInfo[0] = *MonPackage;
+ NextKbdMon->In->wRepeatCount = RepeatCount;
+
+ NextKbdIn = (NextKbdMon->In == NextKbdMon->End) ?
+ NextKbdMon->Event :
+ (NextKbdMon->In+1);
+
+ FirstEvent = (NextKbdMon->In == NextKbdMon->Out);
+
+ if ( NextKbdMon->In == NextKbdMon->Out )
+ {
+ EnterCriticalSection(&QueueInputCriticalSection);
+
+ if ( NextKbdMon->In == NextKbdMon->Out )
+ {
+ if ( NextKbdMon->MonHdr.WaitForEvent )
+ {
+ if ( NextKbdMon == KbdQueue ) /* last monitor in queue */
+ {
+ KbdHandlePackage(NextKbdMon,
+ MonPackage);
+ } else
+ {
+ NextKbdMon->MonHdr.WaitForEvent = FALSE;
+ NextKbdMon->MonHdr.MonStat = MON_STAT_REG;
+
+ SendMonReply(NextKbdMon->MonHdr.MemoryStartAddress,
+ MonPackage,
+ sizeof(KBD_MON_PACKAGE));
+ }
+
+ } else
+ NextKbdMon->In = NextKbdIn;
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+ return (0L);
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+ }
+
+ if (NextKbdIn != NextKbdMon->Out)
+ NextKbdMon->In = NextKbdIn;
+ else
+ return(1L);
+ } else
+ {
+ NextMouMon = (PMOU_EVENT_QUEUE) NextKbdMon;
+ MouPackage = (PMOU_MON_PACKAGE) MonPackage;
+ //MouPackage = (PMOU_MON_PACKAGE) &(rwParms->ioBuff[0]);
+
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ KdPrint(("OS2SES(PutMonInput): enter, to queue %lx, event %x (%x:%x)\n",
+ NextMouMon, MouPackage->MouInfo.fs,
+ MouPackage->MouInfo.row, MouPackage->MouInfo.col ));
+ }
+#endif
+
+ *NextMouMon->In = *MouPackage;
+
+ NextMouIn = (NextMouMon->In == NextMouMon->End) ?
+ NextMouMon->Event :
+ (NextMouMon->In+1);
+
+ if ( NextMouMon->In == NextMouMon->Out )
+ {
+ EnterCriticalSection(&QueueInputCriticalSection);
+
+ if ( NextMouMon->In == NextMouMon->Out )
+ {
+ if ( NextMouMon->MonHdr.WaitForEvent )
+ {
+ NextMouMon->MonHdr.WaitForEvent = FALSE;
+
+ if ( NextMouMon == MouQueue ) /* last monitor in queue */
+ SendMouReply(NextMouMon->MonHdr.MemoryStartAddress,
+ &MouPackage->MouInfo);
+ else
+ {
+ NextMouMon->MonHdr.MonStat = MON_STAT_REG;
+ SendMonReply(NextMouMon->MonHdr.MemoryStartAddress,
+ MouPackage,
+ sizeof(MOU_MON_PACKAGE));
+ }
+
+ } else
+ NextMouMon->In = NextMouIn;
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+ return (0L);
+ }
+
+ LeaveCriticalSection(&QueueInputCriticalSection);
+ }
+
+ if (NextMouIn != NextMouMon->Out)
+ NextMouMon->In = NextMouIn;
+ else
+ {
+ if ( NextMouMon == MouQueue ) /* last monitor in queue */
+ {
+ /* no place - throw the oldest info */
+
+ NextMouMon->Out = (NextMouMon->Out == NextMouMon->End) ?
+ NextMouMon->Event :
+ (NextMouMon->Out+1);
+
+ NextMouMon->In = NextMouIn;
+ }
+
+ return(1L);
+ }
+ }
+
+ return(0L);
+
+}
+
+
+VOID
+EventReleaseLPC(
+ IN ULONG ProcessId
+ )
+{
+ PKEY_EVENT_QUEUE CurrentKbdQueue, LastKbdQueue;
+ PMOU_EVENT_QUEUE CurrentMouQueue, LastMouQueue;
+
+ for ( CurrentKbdQueue = KbdMonQueue, LastKbdQueue = NULL ;
+ LastKbdQueue != KbdQueue ;
+ LastKbdQueue = CurrentKbdQueue,
+ CurrentKbdQueue = (PKEY_EVENT_QUEUE)CurrentKbdQueue->MonHdr.NextQueue)
+ {
+ if((CurrentKbdQueue->MonHdr.WaitForEvent) &&
+ (Ow2GetProcessIdFromLPCMessage(
+ CurrentKbdQueue->MonHdr.MemoryStartAddress) == ProcessId))
+ {
+ if(CurrentKbdQueue != KbdQueue)
+ {
+ SendMonReply(CurrentKbdQueue->MonHdr.MemoryStartAddress,
+ NULL,
+ sizeof(KBD_MON_PACKAGE));
+
+ MonQueueClose((HANDLE)CurrentKbdQueue);
+ } else
+ {
+ RtlZeroMemory(
+ &KbdRequestSaveArea.d.KeyInfo,
+ sizeof(KBDKEYINFO));
+
+ SendKbdReply(CurrentKbdQueue->MonHdr.MemoryStartAddress,
+ (PVOID)&KbdRequestSaveArea,
+ NULL,
+ 0);
+ }
+ }
+ }
+
+ for ( CurrentMouQueue = MouMonQueue, LastMouQueue = NULL ;
+ LastMouQueue != MouQueue ;
+ LastMouQueue = CurrentMouQueue,
+ CurrentMouQueue = (PMOU_EVENT_QUEUE)CurrentMouQueue->MonHdr.NextQueue)
+ {
+ if((CurrentMouQueue->MonHdr.WaitForEvent) &&
+ (Ow2GetProcessIdFromLPCMessage(
+ CurrentMouQueue->MonHdr.MemoryStartAddress) == ProcessId))
+ {
+ if(CurrentMouQueue != MouQueue)
+ {
+ SendMonReply(CurrentMouQueue->MonHdr.MemoryStartAddress,
+ NULL,
+ sizeof(MOU_MON_PACKAGE));
+
+ MonQueueClose((HANDLE)CurrentMouQueue);
+ } else
+ {
+ SendMouReply(CurrentMouQueue->MonHdr.MemoryStartAddress,
+ NULL);
+ }
+ }
+ }
+
+ //if ((MouQueue->MonHdr.WaitForEvent) &&
+ // (MouMonQueue == MouQueue ) && /* last monitor in queue */
+ // (Ow2GetProcessIdFromLPCMessage(
+ // MouQueue->MonHdr.MemoryStartAddress) == ProcessId))
+ //{
+ // RtlZeroMemory(
+ // &MouPackage,
+ // sizeof(MOU_MON_PACKAGE));
+ //
+ // SendMouReply(MouQueue->MonHdr.MemoryStartAddress,
+ // &MouPackage);
+ //}
+}
+
+
+VOID
+Ow2MouOn()
+{
+ Ow2dwWinInputMode |= ENABLE_MOUSE_INPUT;
+ InputModeFlags |= ENABLE_MOUSE_INPUT;
+
+ if (!SesGrp->WinProcessNumberInSession)
+ {
+ Ow2SetInputConsoleMode(
+ #if DBG
+ Ow2MouOnStr,
+ #endif
+ Ow2dwInputMode | ENABLE_MOUSE_INPUT
+ );
+ }
+}
+
+
+VOID
+Ow2MouOff()
+{
+ Ow2dwWinInputMode &= ~ENABLE_MOUSE_INPUT;
+ InputModeFlags &= ~ENABLE_MOUSE_INPUT;
+
+ if (!SesGrp->WinProcessNumberInSession)
+ {
+ Ow2SetInputConsoleMode(
+ #if DBG
+ Ow2MouOffStr,
+ #endif
+ Ow2dwInputMode & ~ENABLE_MOUSE_INPUT
+ );
+ }
+}
+
+
+DWORD
+Ow2GetInputConsoleMode(
+#if DBG
+ PSZ FuncName,
+#endif
+ LPDWORD lpMode
+ )
+{
+ BOOL Rc;
+
+ if (SesGrp->WinProcessNumberInSession)
+ {
+ Rc = Or2WinGetConsoleMode(
+#if DBG
+ FuncName,
+#endif
+ hConsoleInput,
+ lpMode
+ );
+#if DBG
+ ASSERT1( "Ow2GetInputConsoleMode: GetConsoleMode fail", Rc );
+#endif
+ if (Rc)
+ {
+ Ow2dwInputMode = *lpMode;
+ } else
+ {
+ return(GetLastError());
+ }
+ } else
+ {
+ *lpMode = Ow2dwInputMode;
+ }
+
+#if DBG
+ if (InternalDebug & InputModeDebug)
+ {
+ KdPrint(("Ow2GetInputConsoleMode, Ow2dwInputMode = %x\n",
+ Ow2dwInputMode));
+ }
+#endif
+ return (NO_ERROR);
+}
+
+
+DWORD
+Ow2SetInputConsoleMode(
+#if DBG
+ PSZ FuncName,
+#endif
+ DWORD dwMode
+ )
+{
+ BOOL Rc;
+
+#if DBG
+ if (InternalDebug & InputModeDebug)
+ {
+ KdPrint(("Ow2SetInputConsoleMode, Ow2dwInputMode = %x, input argument dwMode = %x\n",
+ Ow2dwInputMode, dwMode));
+ }
+#endif
+ if (SesGrp->WinProcessNumberInSession ||
+ (dwMode != Ow2dwInputMode))
+ {
+ Rc = Or2WinSetConsoleMode(
+#if DBG
+ FuncName,
+#endif
+ hConsoleInput,
+ dwMode
+ );
+#if DBG
+ ASSERT1( "Ow2SetInputConsoleMode: SetConsoleMode fail", Rc );
+#endif
+ if (Rc)
+ {
+ Ow2dwInputMode = dwMode;
+ }
+ }
+
+ return (NO_ERROR);
+}
+
+BOOLEAN
+Ow2WriteBackDummyEvent()
+{
+ INPUT_RECORD InputRecord;
+ INPUT_RECORD In;
+ BOOLEAN WriteSucceeded;
+ DWORD RecordsWritten;
+ DWORD cEvents;
+ DWORD PeekSuccess;
+
+ if ((PeekSuccess = PeekConsoleInputW(
+ hConsoleInput,
+ &In,
+ 1L,
+ &cEvents
+ )) && cEvents == 0)
+ {
+ InputRecord.EventType = MENU_EVENT;
+ InputRecord.Event.MenuEvent.dwCommandId = WM_USER+1;
+ WriteSucceeded = WriteConsoleInput(hConsoleInput,
+ &InputRecord, 1, &RecordsWritten);
+ if (!WriteSucceeded || (RecordsWritten != 1)) {
+#if DBG
+ DbgPrint("OS2: Ow2WriteBackDummyEvent - failed to write into input queue\n");
+#endif // DBG
+ return(FALSE);
+ }
+ }
+ else if (!PeekSuccess){
+#if DBG
+ DbgPrint("OS2: Ow2WriteBackDummyEvent - failed to peek input queue\n");
+#endif // DBG
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+BOOLEAN
+Ow2ClearupDummyEvent()
+{
+ INPUT_RECORD In;
+ DWORD cEvents;
+ DWORD PeekSuccess;
+
+ if ((PeekSuccess = PeekConsoleInputW(
+ hConsoleInput,
+ &In,
+ 1L,
+ &cEvents
+ )) && cEvents == 1)
+ {
+ //
+ // Check if the event in the queue is the special dummy event
+ //
+ if (In.EventType == MENU_EVENT && In.Event.MenuEvent.dwCommandId == (WM_USER+1))
+ {
+ if (!ReadConsoleInputW(
+ hConsoleInput,
+ &In,
+ 1L,
+ &cEvents
+ ))
+ { // check why, should not happen
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ ASSERT1("Ow2ClearupDummyEvent: unable to read from CONIN$", FALSE);
+ } else
+ KdPrint(("OS2SES(Ow2ClearupDummyEvent): unable to read from CONIN$\n"));
+#endif
+ return(FALSE);
+ } else if (cEvents != 1L)
+ { // check why, should not happen
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ ASSERT1( "Ow2ClearupDummyEvent: no data read from CONIN$", FALSE );
+ } else
+ KdPrint(("OS2SES(Ow2ClearupDummyEvent): no data read from CONIN$\n"));
+#endif
+ return(FALSE);
+ }
+ }
+ }
+ else if (!PeekSuccess) {
+ // Peek Failed, check why, should not happen
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ ASSERT1("ClearupDummyEvent: unable to peek from CONIN$", FALSE);
+ } else
+ {
+ KdPrint(("OS2SES(ClearupDummyEvent): unable to peek from CONIN$\n"));
+ }
+#endif
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+#if PMNT
+
+APIRET
+MouSetPtrPosPM(
+ PPTRLOC pPtrLoc)
+{
+ if (SetCursorPos(pPtrLoc->col, pPtrLoc->row))
+ return NO_ERROR;
+ else
+ return ERROR_MOUSE_INV_PARMS;
+}
+
+APIRET
+MouGetPtrPosPM(
+ PPTRLOC pPtrLoc)
+{
+ POINT pt;
+
+ if (GetCursorPos(&pt))
+ {
+ pPtrLoc->col = (USHORT)pt.x;
+ pPtrLoc->row = (USHORT)pt.y;
+
+ return NO_ERROR;
+ }
+ else
+ return ERROR_MOUSE_INV_PARMS;
+}
+
+COORD LastMousePosition = {-1, -1};
+BOOLEAN PMNTInFocus = TRUE;
+
+APIRET
+PMNTGetNextEvent(
+ PMNT_INPUT_RECORD *ppm_input_rec)
+{
+ int count;
+ INPUT_RECORD input_rec;
+ static int IgnoreNextMouseEvent = 0;
+ static BOOLEAN firsttime = TRUE;
+
+ if (firsttime)
+ {
+ firsttime = FALSE;
+ // For PM apps, this will cause EventServerThread to actually terminate
+ SetEvent(SuspendEvent);
+ }
+
+ while (1)
+ {
+ int SetNewMousePosition = 0;
+
+ if (!Or2WinReadConsoleInputA(
+ #if DBG
+ ReadInputEventStr,
+ #endif
+ hConsoleInput,
+ &input_rec,
+ 1,
+ &count
+ ))
+ {
+#if 0
+ KdPrint(("PMNTGetNextEvent : Read Console input error = %lx \n",
+ GetLastError()));
+#endif
+ return ERROR_INVALID_PARAMETER;
+ }
+ else
+ {
+ try
+ {
+ switch (input_rec.EventType)
+ {
+ case KEY_EVENT:
+ ppm_input_rec->EventType = PMNT_KEY_EVENT;
+ ppm_input_rec->Event.KeyEvent.bKeyDown =
+ input_rec.Event.KeyEvent.bKeyDown;
+ ppm_input_rec->Event.KeyEvent.wRepeatCount =
+ input_rec.Event.KeyEvent.wRepeatCount;
+ ppm_input_rec->Event.KeyEvent.wVirtualKeyCode =
+ input_rec.Event.KeyEvent.wVirtualKeyCode;
+ ppm_input_rec->Event.KeyEvent.wVirtualScanCode =
+ input_rec.Event.KeyEvent.wVirtualScanCode;
+ //BUGBUG - when/how should we look at unicode ?
+ ppm_input_rec->Event.KeyEvent.uChar.AsciiChar =
+ input_rec.Event.KeyEvent.uChar.AsciiChar;
+ ppm_input_rec->Event.KeyEvent.dwControlKeyState =
+ input_rec.Event.KeyEvent.dwControlKeyState;
+//#if DBG
+// DbgPrint(">>> Key event (%s): Char=%x, Scan=%x, VK=%x\n",
+// (input_rec.Event.KeyEvent.bKeyDown ? "DOWN":" UP "),
+// input_rec.Event.KeyEvent.uChar.AsciiChar,
+// input_rec.Event.KeyEvent.wVirtualScanCode,
+// input_rec.Event.KeyEvent.wVirtualKeyCode);
+//#endif
+ return NO_ERROR;
+
+ case MOUSE_EVENT:
+
+ if (IgnoreNextMouseEvent)
+ {
+ IgnoreNextMouseEvent = 0;
+ break;
+ }
+
+ if (input_rec.Event.MouseEvent.dwMousePosition.X < 0)
+ {
+ input_rec.Event.MouseEvent.dwMousePosition.X = 0;
+ SetNewMousePosition = 1;
+ }
+ else if (input_rec.Event.MouseEvent.dwMousePosition.X
+ >= (ScreenX-1))
+ {
+ input_rec.Event.MouseEvent.dwMousePosition.X =
+ ScreenX - 1;
+ if (input_rec.Event.MouseEvent.dwMousePosition.Y
+ >= (ScreenY-1))
+ input_rec.Event.MouseEvent.dwMousePosition.Y =
+ ScreenY - 1;
+ SetCursorPos(input_rec.Event.MouseEvent.dwMousePosition.X,
+ input_rec.Event.MouseEvent.dwMousePosition.Y);
+ IgnoreNextMouseEvent = 1;
+ }
+
+ if (input_rec.Event.MouseEvent.dwMousePosition.Y < 0)
+ {
+ input_rec.Event.MouseEvent.dwMousePosition.Y = 0;
+ SetNewMousePosition = 1;
+ }
+ else if (input_rec.Event.MouseEvent.dwMousePosition.Y
+ >= (ScreenY-1))
+ {
+ input_rec.Event.MouseEvent.dwMousePosition.Y =
+ ScreenY - 1;
+ if (input_rec.Event.MouseEvent.dwMousePosition.X
+ >= (ScreenX-1))
+ input_rec.Event.MouseEvent.dwMousePosition.X =
+ ScreenX - 1;
+ SetCursorPos(input_rec.Event.MouseEvent.dwMousePosition.X,
+ input_rec.Event.MouseEvent.dwMousePosition.Y);
+ IgnoreNextMouseEvent = 1;
+ }
+
+ if (SetNewMousePosition)
+ {
+ SetNewMousePosition = 0;
+ // Reset the mouse position to be within the screen
+ // boundaries
+ SetCursorPos(input_rec.Event.MouseEvent.dwMousePosition.X,
+ input_rec.Event.MouseEvent.dwMousePosition.Y);
+ break; // No need to generate a mouse event
+ }
+ else
+ {
+ ppm_input_rec->EventType = PMNT_MOUSE_EVENT;
+ ppm_input_rec->Event.MouseEvent.dwMousePosition.X =
+ input_rec.Event.MouseEvent.dwMousePosition.X;
+ ppm_input_rec->Event.MouseEvent.dwMousePosition.Y =
+ input_rec.Event.MouseEvent.dwMousePosition.Y;
+ ppm_input_rec->Event.MouseEvent.dwButtonState =
+ input_rec.Event.MouseEvent.dwButtonState;
+ ppm_input_rec->Event.MouseEvent.dwControlKeyState =
+ input_rec.Event.MouseEvent.dwControlKeyState;
+ ppm_input_rec->Event.MouseEvent.dwEventFlags =
+ input_rec.Event.MouseEvent.dwEventFlags;
+
+ if (PMNTInFocus)
+ {
+ LastMousePosition.X =
+ input_rec.Event.MouseEvent.dwMousePosition.X;
+ LastMousePosition.Y =
+ input_rec.Event.MouseEvent.dwMousePosition.Y;
+ }
+
+ return NO_ERROR;
+ }
+
+ case FOCUS_EVENT:
+ ppm_input_rec->EventType = PMNT_FOCUS_EVENT;
+ ppm_input_rec->Event.FocusEvent.bSetFocus =
+ input_rec.Event.FocusEvent.bSetFocus;
+ return NO_ERROR;
+
+ case WINDOW_BUFFER_SIZE_EVENT:
+#if DBG
+ KdPrint(("PMNTGetNextEvent: WINDOW_BUFFER_SIZE_EVENT\n"));
+#endif
+ break;
+
+ case MENU_EVENT:
+#if DBG
+ KdPrint(("PMNTGetNextEvent: MENU_EVENT\n"));
+ KdPrint((" (command ID=0x%x)\n",
+ input_rec.Event.MenuEvent.dwCommandId));
+#endif
+ if (input_rec.Event.MenuEvent.dwCommandId == WM_USER)
+ {
+ ppm_input_rec->EventType = PMNT_MENU_EVENT;
+ ppm_input_rec->Event.MenuEvent.dwCommandId = 0xdead;
+ return(NO_ERROR);
+ }
+ else if (input_rec.Event.MenuEvent.dwCommandId == (WM_USER+1))
+ {
+ ppm_input_rec->EventType = PMNT_MENU_EVENT;
+ ppm_input_rec->Event.MenuEvent.dwCommandId = 0x1;
+ return(NO_ERROR);
+ }
+ else if (input_rec.Event.MenuEvent.dwCommandId == (WM_USER+2))
+ {
+ ppm_input_rec->EventType = PMNT_MENU_EVENT;
+ ppm_input_rec->Event.MenuEvent.dwCommandId = 0x2;
+ return(NO_ERROR);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+ }
+ } // while(1)
+}
+
+#ifndef CONSOLE_FULLSCREEN_MODE
+#define CONSOLE_FULLSCREEN_MODE 1
+#define CONSOLE_WINDOWED_MODE 2
+
+//BUGBUG !!! Most definitions below are taken from the private API include
+// file of the console ('conapi.h') -> needs to be updated from
+// time to time.
+
+typedef struct _CONSOLE_GRAPHICS_BUFFER_INFO {
+ DWORD dwBitMapInfoLength;
+ LPBITMAPINFO lpBitMapInfo;
+ DWORD dwUsage;
+ HANDLE hMutex;
+ PVOID lpBitMap;
+} CONSOLE_GRAPHICS_BUFFER_INFO, *PCONSOLE_GRAPHICS_BUFFER_INFO;
+
+#define CONSOLE_GRAPHICS_BUFFER 2
+
+BOOL
+SetConsoleDisplayMode(
+ HANDLE hConsoleOutput,
+ DWORD dwFlags,
+ PCOORD lpNewScreenBufferDimensions
+ );
+#endif
+
+typedef struct _BITMAPINFOPAT
+{
+ BITMAPINFOHEADER bmiHeader;
+ RGBQUAD bmiColors[1];
+} BITMAPINFOPAT;
+
+BITMAPINFOPAT bmiPat =
+{
+ {
+ sizeof(BITMAPINFOHEADER),
+ 640,
+ -480, // For some weird reason, the Console wants a negative value,
+ // otherwise it prints a: "****** Negating biHeight" message.
+ 1,
+ 1,
+ BI_RGB,
+ (640 * 480 / 8),
+ 0,
+ 0,
+ 0,
+ 0
+ },
+
+ { // B G R
+ { 0, 0, 0x0, 0 }
+ }
+};
+
+/******************************************************************************
+ * PMNTGetWin32Hwnd:
+ * Returns the WIN32 HWND of our window.
+ ******************************************************************************/
+ULONG PMNTGetWin32Hwnd(ULONG *pHwnd)
+{
+ try
+ {
+ *pHwnd = (ULONG)Ow2ForegroundWindow;
+ }
+ except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ return NO_ERROR;
+}
+
+static BOOL HWDumpVersion=FALSE;
+
+PVIDEO_HARDWARE_STATE_HEADER videoState;
+
+UCHAR InitStatePortValue[0x30] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+0x20, 0, 0xe3, 0, 2, 0, 0xff, 0, 0x10, 0, 0, 0, 0, 0, 4, 0,
+ 0, 0, 0, 0, 0x3f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+UCHAR InitStateBasicSequencer[] = {3,1,0xf,0,6};
+UCHAR InitStateBasicCrtCont[] = {
+0x5f,0x4f,0x50,0x82,0x54,0x80,0xb,0x3e,0,0x40,0,0,0,0,0,0,
+0xea,0xac,0xdf,0x28,0,0xe7,4,0xc3,0xff};
+UCHAR InitStateBasicGraphCont[] = {0,0,0,0,3,0,5,0xf,0xff};
+UCHAR InitStateBasicAttribCont[] = {
+0,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,
+1,0,0xf,0,0};
+
+UCHAR InitStateBasicDac[] = {
+0, 0, 0, 0, 0,0x2a, 0,0x2a, 0, 0,0x2a,0x2a,0x2a,0, 0,0x2a,
+0,0x2a,0x2a,0x2a, 0,0x28,0x28,0x28,0x36,0x36,0x36, 0, 0,0x3f, 0,0x3f,
+0, 0,0x3f,0x3f,0x3f, 0, 0,0x3f, 0,0x3f,0x3f,0x3f, 0, 0x3f, 0x3f, 0x3f,
+0, 0x15, 0, 0, 0x15, 0x2a, 0, 0x3f, 0, 0, 0x3f, 0x2a, 0x2a, 0x15, 0, 0x2a,
+0x15, 0x2a, 0x2a, 0x3f, 0, 0x2a, 0x3f, 0x2a, 0, 0x15, 0x15, 0, 0x15, 0x3f, 0, 0x3f,
+0x15, 0, 0x3f, 0x3f, 0x2a, 0x15, 0x15, 0x2a, 0x15, 0x3f, 0x2a, 0x3f, 0x15, 0x2a, 0x3f, 0x3f,
+0x15, 0, 0, 0x15, 0,0x2a, 0x15, 0x2a, 0, 0x15, 0x2a, 0x2a, 0x3f, 0, 0, 0x3f,
+ 0,0x2a, 0x3f, 0x2a, 0,0x3f, 0x2a, 0x2a, 0x15, 0,0x15,0x15,0,0x3f,0x15,0x2a,
+0x15, 0x15, 0x2a, 0x3f, 0x3f, 0,0x15, 0x3f, 0,0x3f,0x3f,0x2a,0x15,0x3f,0x2a,0x3f,
+0x15, 0x15, 0,0x15, 0x15, 0x2a, 0x15, 0x3f, 0,0x15,0x3f,0x2a,0x3f,0x15,0,0x3f,
+0x15, 0x2a, 0x3f, 0x3f, 0,0x3f, 0x3f, 0x2a, 0x15,0x15,0x15,0x15,0x15,0x3f,0x15,0x3f,
+0x15, 0x15, 0x3f, 0x3f, 0x3f, 0x15, 0x15, 0x3f,0x15,0x3f,0x3f,0x3f,0x15,0x3f,0x3f,0x3f,
+ 0, 0, 0, 0, 0,0x2a, 0,0x2a, 0, 0,0x2a, 0x2a, 0x2a, 0, 0,0x2a,
+ 0,0x2a, 0x2a, 0x2a, 0,0x2a, 0x2a, 0x2a, 0, 0,0x15, 0, 0,0x3f, 0,0x2a,
+0x15, 0,0x2a, 0x3f, 0x2a, 0,0x15, 0x2a, 0,0x3f, 0x2a, 0x2a, 0x15, 0x2a, 0x2a, 0x3f,
+ 0,0x15, 0, 0,0x15, 0x2a, 0,0x3f, 0, 0,0x3f, 0x2a, 0x2a, 0x15, 0,0x2a,
+0x15, 0x2a, 0x2a, 0x3f, 0,0x2a, 0x3f, 0x2a, 0,0x15, 0x15, 0,0x15, 0x3f, 0,0x3f,
+0x15, 0,0x3f, 0x3f, 0x2a, 0x15, 0x15, 0x2a, 0x15, 0x3f, 0x2a, 0x3f, 0x15, 0x2a, 0x3f, 0x3f,
+0x15, 0, 0,0x15, 0,0x2a, 0x15, 0x2a, 0,0x15, 0x2a, 0x2a, 0x3f, 0, 0,0x3f,
+ 0,0x2a, 0x3f, 0x2a, 0,0x3f, 0x2a, 0x2a, 0x15, 0,0x15, 0x15, 0,0x3f, 0x15, 0x2a,
+0x15, 0x15, 0x2a, 0x3f, 0x3f, 0,0x15, 0x3f, 0,0x3f, 0x3f, 0x2a, 0x15, 0x3f, 0x2a, 0x3f,
+0x15, 0x15, 0,0x15, 0x15, 0x2a, 0x15, 0x3f, 0,0x15, 0x3f, 0x2a, 0x3f, 0x15, 0,0x3f,
+0x15, 0x2a, 0x3f, 0x3f, 0,0x3f, 0x3f, 0x2a, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3f, 0x15, 0x3f,
+0x15, 0x15, 0x3f, 0x3f, 0x3f, 0x15, 0x15, 0x3f, 0x15, 0x3f, 0x3f, 0x3f, 0x15, 0x3f, 0x3f, 0x3f,
+ 0, 0, 0, 0, 0,0x2a, 0,0x2a, 0, 0,0x2a, 0x2a, 0x2a, 0, 0,0x2a,
+ 0,0x2a, 0x2a, 0x2a, 0,0x2a, 0x2a, 0x2a, 0, 0,0x15, 0, 0,0x3f, 0,0x2a,
+0x15, 0,0x2a, 0x3f, 0x2a, 0,0x15, 0x2a, 0,0x3f, 0x2a, 0x2a, 0x15, 0x2a, 0x2a, 0x3f,
+ 0,0x15, 0, 0,0x15, 0x2a, 0,0x3f, 0, 0,0x3f, 0x2a, 0x2a, 0x15, 0,0x2a,
+0x15, 0x2a, 0x2a, 0x3f, 0,0x2a, 0x3f, 0x2a, 0,0x15, 0x15, 0,0x15, 0x3f, 0,0x3f,
+0x15, 0,0x3f, 0x3f, 0x2a, 0x15, 0x15, 0x2a, 0x15, 0x3f, 0x2a, 0x3f, 0x15, 0x2a, 0x3f, 0x3f,
+0x15, 0, 0,0x15, 0,0x2a, 0x15, 0x2a, 0,0x15, 0x2a, 0x2a, 0x3f, 0, 0,0x3f,
+ 0,0x2a, 0x3f, 0x2a, 0,0x3f, 0x2a, 0x2a, 0x15, 0,0x15, 0x15, 0,0x3f, 0x15, 0x2a,
+0x15, 0x15, 0x2a, 0x3f, 0x3f, 0,0x15, 0x3f, 0,0x3f, 0x3f, 0x2a, 0x15, 0x3f, 0x2a, 0x3f,
+0x15, 0x15, 0,0x15, 0x15, 0x2a, 0x15, 0x3f, 0,0x15, 0x3f, 0x2a, 0x3f, 0x15, 0,0x3f,
+0x15, 0x2a, 0x3f, 0x3f, 0,0x3f, 0x3f, 0x2a, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3f, 0x15, 0x3f,
+0x15, 0x15, 0x3f, 0x3f, 0x3f, 0x15, 0x15, 0x3f, 0x15, 0x3f, 0x3f, 0x3f, 0x15, 0x3f, 0x3f, 0x3f,
+ 0, 0, 0, 0, 0,0x2a, 0,0x2a, 0, 0,0x2a, 0x2a, 0x2a, 0, 0,0x2a,
+ 0,0x2a, 0x2a, 0x2a, 0,0x2a, 0x2a, 0x2a, 0, 0,0x15, 0, 0,0x3f, 0,0x2a,
+0x15, 0,0x2a, 0x3f, 0x2a, 0,0x15, 0x2a, 0,0x3f, 0x2a, 0x2a, 0x15, 0x2a, 0x2a, 0x3f,
+ 0,0x15, 0, 0,0x15, 0x2a, 0,0x3f, 0, 0,0x3f, 0x2a, 0x2a, 0x15, 0,0x2a,
+0x15, 0x2a, 0x2a, 0x3f, 0,0x2a, 0x3f, 0x2a, 0,0x15, 0x15, 0,0x15, 0x3f, 0,0x3f,
+0x15, 0,0x3f, 0x3f, 0x2a, 0x15, 0x15, 0x2a, 0x15, 0x3f, 0x2a, 0x3f, 0x15, 0x2a, 0x3f, 0x3f,
+0x15, 0, 0,0x15, 0,0x2a, 0x15, 0x2a, 0,0x15, 0x2a, 0x2a, 0x3f, 0, 0,0x3f,
+ 0,0x2a, 0x3f, 0x2a, 0,0x3f, 0x2a, 0x2a, 0x15, 0,0x15, 0x15, 0,0x3f, 0x15, 0x2a,
+0x15, 0x15, 0x2a, 0x3f, 0x3f, 0,0x15, 0x3f, 0,0x3f, 0x3f, 0x2a, 0x15, 0x3f, 0x2a, 0x3f,
+0x15, 0x15, 0,0x15, 0x15, 0x2a, 0x15, 0x3f, 0,0x15, 0x3f, 0x2a, 0x3f, 0x15, 0,0x3f,
+0x15, 0x2a, 0x3f, 0x3f, 0,0x3f, 0x3f, 0x2a, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3f, 0x15, 0x3f,
+0x15, 0x15, 0x3f, 0x3f, 0x3f, 0x15, 0x15, 0x3f, 0x15, 0x3f, 0x3f, 0x3f, 0x15, 0x3f, 0x3f, 0x3f};
+UCHAR InitStateBasicLatches[] = {0, 0, 0,0xff};
+#if 0
+UCHAR InitStateExtendedCrtCont[] = {
+0x48,0x93, 0,0x20, 0, 0, 0, 0, 0, 0,0xff, 0xff, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0xff, 0xff, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xf, 0xef, 0, 0, 0, 0,0x2f, 0,0xff,
+ 0xff, 0xff, 0xff, 0,0xff, 0, 0, 0, 0,0xff, 0xff, 0xff, 0xff, 0,0xff, 0,
+ 2, 2, 0,0xff, 0xff, 0, 0, 0, 0,0xff, 0xf, 0xff, 0xf};
+UCHAR InitStateExtendedGraphCont[] = {
+0x10, 0x31, 0xa5, 0x28, 0, 0, 0,0xfb, 0xdf, 0, 0, 0, 0,0x50, 0,0xd6,
+0xa1, 0, 0, 0, 0, 0, 0x1f, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xf, 0xf, 0xf, 0xf, 0xf};
+#endif //0
+
+
+extern BOOLEAN Os2InitializeVDMEvents(VOID);
+extern BOOLEAN Os2WaitForVDMThread(HANDLE hEvent);
+extern VOID Os2VDMThread(PVOID Parameter);
+#ifndef PMNT_DAYTONA
+extern BOOLEAN Os2WaitForVDMThreadReady(VOID);
+extern VOID Os2VDMGetStartThread(PVOID Parameter);
+#endif // not PMNT_DAYTONA
+
+extern VOID DosExit(ULONG ExitAction,ULONG ExitResult);
+
+ULONG
+PMNTSetShutdownPriority(ULONG NewPriority, ULONG DisablePopup)
+{
+ ULONG rc = NO_ERROR;
+
+ if (DisablePopup == 1) // i.e. disable
+ {
+ if (!SetProcessShutdownParameters(
+ NewPriority,
+ 1 // Don't give pop-up when 20 sec are exceeded
+ ))
+ {
+#if DBG
+ DbgPrint("Os2: PMNTSetShutdownPriority(0x%X, %d) failed\n",
+ NewPriority, DisablePopup);
+#endif
+ rc = ERROR_INVALID_PARAMETER;
+ }
+ }
+ else if (DisablePopup == 0) // i.e. enable
+ {
+ if (!SetProcessShutdownParameters(
+ NewPriority,
+ 0 // Give pop-up when 20 sec are exceeded
+ ))
+ {
+#if DBG
+ DbgPrint("Os2: PMNTSetShutdownPriority(0x%X, %d) failed\n",
+ NewPriority, DisablePopup);
+#endif
+ rc = ERROR_INVALID_PARAMETER;
+ }
+ }
+ else // leave unchanged
+ {
+ ULONG tmpPriority, tmpDisable;
+
+ if (!GetProcessShutdownParameters(
+ &tmpPriority,
+ &tmpDisable
+ ))
+ {
+#if DBG
+ DbgPrint("Os2: PMNTSetShutdownPriority(0x%X, %d) failed because of query\n",
+ NewPriority, DisablePopup);
+#endif
+ rc = ERROR_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (!SetProcessShutdownParameters(
+ NewPriority,
+ tmpDisable
+ ))
+ {
+#if DBG
+ DbgPrint("Os2: PMNTSetShutdownPriority(0x%X, %d) failed\n",
+ NewPriority, DisablePopup);
+#endif
+ rc = ERROR_INVALID_PARAMETER;
+ }
+ }
+ }
+ return rc;
+}
+
+//
+//This is a workaround for Unknown Video Adapters
+//It is basically the same as PMNTSetFullScreen of event.c@v52
+//
+void PMNTSetFullScreenDump(void)
+{
+ CONSOLE_GRAPHICS_BUFFER_INFO GraphicsInfo;
+ HANDLE Handle;
+ COORD NewCoord;
+ /* Size of video save block. */
+ DWORD stateLength;
+ CHAR_INFO *textBuffer;
+ COORD textBufferSize; // Dimensions of the shared buffer
+ DWORD ModeFlags;
+ DWORD OldPriorityClass;
+ DWORD OldPriorityThread;
+
+#if DBG
+ DbgPrint("PMNTSetFullScreenDump was called\n");
+#endif
+
+ //
+ // open a new console
+ //
+
+ GraphicsInfo.dwBitMapInfoLength = sizeof(bmiPat);
+ GraphicsInfo.lpBitMapInfo = (LPBITMAPINFO)&bmiPat;
+ GraphicsInfo.dwUsage = DIB_RGB_COLORS;
+
+ // Set some fields according to the display resolution
+ GraphicsInfo.lpBitMapInfo->bmiHeader.biWidth = ScreenX;
+ // For some weird reason, the Console wants a negative value,
+ // otherwise it prints a: "****** Negating biHeight" message.
+ GraphicsInfo.lpBitMapInfo->bmiHeader.biHeight = -ScreenY;
+ GraphicsInfo.lpBitMapInfo->bmiHeader.biSizeImage = ScreenX*ScreenY/8;
+
+ Handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CONSOLE_GRAPHICS_BUFFER,
+ &GraphicsInfo
+ );
+ if (Handle == (HANDLE)-1)
+ {
+#if DBG
+ DbgPrint("CreateConsoleScreenBuffer failed\n");
+#endif
+ return;
+ }
+
+ //
+ // make it current
+ //
+
+ if (!SetConsoleActiveScreenBuffer(Handle))
+ {
+#if DBG
+ DbgPrint("SetConsoleActiveScreenBuffer() failed\n");
+#endif
+ }
+
+ if (!GetConsoleDisplayMode(&ModeFlags))
+ {
+#if DBG
+ DbgPrint("GetConsoleDisplayMode() failed, error=%d\n",
+ GetLastError());
+#endif
+ }
+
+ OldPriorityClass = GetPriorityClass(GetCurrentProcess());
+ OldPriorityThread = GetThreadPriority(GetCurrentThread());
+
+#if DBG
+ if (!OldPriorityClass)
+ {
+ DbgPrint("PMNTSetFullScreen: GetPriorityClass failed, error=%d\n",
+ GetLastError());
+ }
+
+ if (OldPriorityThread == THREAD_PRIORITY_ERROR_RETURN)
+ {
+ DbgPrint("PMNTSetFullScreen: GetThreadPriority failed, error=%d\n",
+ GetLastError());
+ }
+#endif
+
+ if (!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS))
+ {
+#if DBG
+ DbgPrint("PMNTSetFullScreen: SetPriorityClass failed, error=%d\n",
+ GetLastError());
+#endif
+ }
+
+ if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL))
+ {
+#if DBG
+ DbgPrint("PMNTSetFullScreen: SetThreadPriority failed, error=%d\n",
+ GetLastError());
+#endif
+ }
+
+ // Is the Console already full-screen ?
+ if ((ModeFlags & CONSOLE_FULLSCREEN) == 0)
+ {
+ INPUT_RECORD input_rec;
+ int count;
+
+ if (!SetConsoleDisplayMode(
+ Handle,
+ CONSOLE_FULLSCREEN_MODE,
+ &NewCoord
+ ))
+ {
+#if DBG
+ DbgPrint("SetConsoleDisplayMode() 0x%x %d failed\n", GetLastError(),
+ GetLastError());
+#endif
+ }
+
+ // The 2 loops below are here because of a Console bug: when one windows
+ // goes full-screen, GDI relinquishes the display and sends a lost focus
+ // message to all windows on the desktop, incl. to the window going
+ // full-screen. The Console is not smart enough to filter out this
+ // spurious event and it passes it on to the Console client in the form
+ // of a negative Console focus event. Then, the window gets a positive
+ // focus event.
+ // There is more: when the full-screen window happens to register itself
+ // as a VDM, the Console actually goes through the usual handshake
+ // involved when loosing/gaining focus, with the 2 hardware events !!!
+ // The PM/NT loop handling these events was created only later. All
+ // Console APIs (such as SetInputConsoleMode) issued from PMSHELL before
+ // the creation of the thread handling the dialog with the Console but
+ // after the spurious focus event resulted in a dead-lock: PMSHELL was
+ // waiting for some answer from the Console, which was waiting for the VDM
+ // (i.e. PMSHELL) to perform the handshake !
+ // Note that the problem didn't appear consistently because it was
+ // dependent on the timing on the WM_FOCUS message(s).
+ //
+ // The 2 loops below wait for these events and discard them.
+ //
+
+ while (1)
+ {
+ if (!Or2WinReadConsoleInputA(
+ #if DBG
+ ReadInputEventStr,
+ #endif
+ hConsoleInput,
+ &input_rec,
+ 1,
+ &count
+ ))
+ {
+ KdPrint(("PMNTSetFullScreent : Read Console input error = %lx \n",
+ GetLastError()));
+ return;
+ }
+
+ if (input_rec.EventType == FOCUS_EVENT)
+ {
+ if (input_rec.Event.FocusEvent.bSetFocus)
+ {
+ // Expected negative focus at that point but go on
+ KdPrint(("PMNTSetFullScreen: positive Focus event ?!?\n"));
+ goto SkipConsoleWait;
+ }
+ else
+ {
+ // Got the first spurious event (negative focus) - go on
+ break;
+ }
+ }
+ else
+ {
+ KdPrint(("PMNTSetFullScreen: ignoring non-focus event (%d)\n",
+ input_rec.EventType));
+ }
+ }
+
+ while (1)
+ {
+ if (!Or2WinReadConsoleInputA(
+ #if DBG
+ ReadInputEventStr,
+ #endif
+ hConsoleInput,
+ &input_rec,
+ 1,
+ &count
+ ))
+ {
+ KdPrint(("PMNTSetFullScreen : Read Console input error = %lx \n"));
+ return;
+ }
+
+ if (input_rec.EventType == FOCUS_EVENT)
+ {
+ if (!input_rec.Event.FocusEvent.bSetFocus)
+ {
+ // Expects positive focus at that point.
+ KdPrint(("PMNTSetFullScreen: negative Focus event ?!?\n"));
+ }
+ else
+ {
+ // Got the 2nd spurious event (positive focus) - go on
+ break;
+ }
+ }
+ }
+ }
+
+SkipConsoleWait:
+
+ // Get rid of any events at that point
+ FlushConsoleInputBuffer(hConsoleInput);
+
+ /*
+ * Register start and end events with the console. These events are used
+ * when gaining or losing control of the hardware.
+ */
+ hStartHardwareEvent = CreateEventW((LPSECURITY_ATTRIBUTES) NULL,
+ FALSE,
+ FALSE,
+ NULL);
+ hEndHardwareEvent = CreateEventW((LPSECURITY_ATTRIBUTES) NULL,
+ FALSE,
+ FALSE,
+ NULL);
+ if ((hStartHardwareEvent == NULL) || (hEndHardwareEvent == NULL))
+ {
+#if DBG
+ DbgPrint("PMNTSetFullScreen: ERROR, Cannot create start or end events\n");
+#endif
+ }
+ /* Poll the event to try and get rid of any console queued sets
+ * This shouldn't be needed (or shouldn't work) but something along
+ * those lines seems to be happening at the moment.
+ */
+ WaitForSingleObject(hStartHardwareEvent, 0);
+
+ if (!SetConsoleKeyShortcuts(
+ TRUE,
+ CONSOLE_ALTENTER,
+ NULL,
+ 0
+ )
+ )
+ {
+#if DBG
+ DbgPrint("PMNTSetFullScreen: ERROR, SetConsoleKetShortcuts() failed\n");
+#endif
+ }
+
+ textBufferSize.X = 80;
+ textBufferSize.Y = 50;
+ stateLength = sizeof(CHAR_INFO)*80*50;
+
+ if (!RegisterConsoleVDM( TRUE,
+ hStartHardwareEvent,
+ hEndHardwareEvent,
+ (LPWSTR) NULL,
+ (DWORD) 0,
+ &stateLength,
+ (PVOID *) &videoState,
+ (LPWSTR) NULL,
+ (DWORD) 0,
+ textBufferSize,
+ (PVOID *) &textBuffer
+ )
+ )
+ {
+#if DBG
+ DbgPrint("PMNTSetFullScreen: ERROR, RegisterConsoleVDM() failed\n");
+#endif
+ }
+
+ // Restore process/thread priority class & priority
+ if (!SetPriorityClass(GetCurrentProcess(), OldPriorityClass))
+ {
+#if DBG
+ DbgPrint("PMNTSetFullScreen: SetPriorityClass(%d) failed, error=%d\n",
+ OldPriorityClass,
+ GetLastError());
+#endif
+ }
+
+ if (!SetThreadPriority(GetCurrentThread(), OldPriorityThread))
+ {
+#if DBG
+ DbgPrint("PMNTSetFullScreen: SetThreadPriority(%d) failed, error=%d\n",
+ OldPriorityThread,
+ GetLastError());
+#endif
+ }
+}
+
+extern ULONG
+Dos16Open(PSZ pszFileName,PUSHORT phf,PUSHORT pusAction,ULONG cbFile,
+ ULONG ulAttribute,ULONG fsOpenFlags,ULONG fsOpenMode,ULONG ulReserved);
+extern ULONG DosClose(IN HFILE FileHandle);
+extern ULONG Dos16Write(HFILE FileHandle,PVOID Buffer,ULONG Length,PUSHORT BytesWritten);
+extern ULONG Dos16Read(ULONG hFile, PVOID pBuffer, ULONG cbRead, PUSHORT pcbActual);
+
+static BOOL VideoDumped = FALSE;
+#define PMNTREGQUERYVALMAX 256
+char PMNTDisplayAdapterName[PMNTREGQUERYVALMAX] = {'\0'};
+LONG PMNTDisplayAdapterLen = 0;
+
+//
+// This routine dumps the videostate buffer into c:\os2\videohw.dmp exists
+//
+
+void PMNTVideoDump(void)
+{
+ ULONG rc;
+ ULONG len;
+ USHORT hfile,Action,cbWritten;
+
+ if (PMNTDisplayAdapterLen == 0)
+ {
+ KdPrint(("PMNTVideoDump: couldn't get current display name - returning"));
+ return;
+ }
+
+ len = sizeof(VIDEO_HARDWARE_STATE_HEADER);
+
+ if (len < videoState->BasicSequencerOffset) len = videoState->BasicSequencerOffset;
+ if (len < videoState->BasicCrtContOffset) len = videoState->BasicCrtContOffset;
+ if (len < videoState->BasicGraphContOffset) len = videoState->BasicGraphContOffset;
+ if (len < videoState->BasicAttribContOffset) len = videoState->BasicAttribContOffset;
+ if (len < videoState->BasicDacOffset) len = videoState->BasicDacOffset;
+ if (len < videoState->BasicLatchesOffset) len = videoState->BasicLatchesOffset;
+ if (len < videoState->ExtendedSequencerOffset) len = videoState->ExtendedSequencerOffset;
+ if (len < videoState->ExtendedCrtContOffset) len = videoState->ExtendedCrtContOffset;
+ if (len < videoState->ExtendedGraphContOffset) len = videoState->ExtendedGraphContOffset;
+ if (len < videoState->ExtendedAttribContOffset) len = videoState->ExtendedAttribContOffset;
+ if (len < videoState->ExtendedDacOffset) len = videoState->ExtendedDacOffset;
+ if (len < videoState->ExtendedValidatorStateOffset) len = videoState->ExtendedValidatorStateOffset;
+ if (len < videoState->ExtendedMiscDataOffset) len = videoState->ExtendedMiscDataOffset;
+ if (len < videoState->Plane1Offset) len = videoState->Plane1Offset;
+
+ if (rc=Dos16Open("C:\\OS2\\VIDEOHW.DMP",
+ &hfile,
+ &Action,
+ 0L,
+ 0L,
+ 0x00000012, /* FILE_TRUNCATE | FILE_CREATE */
+ 0x00000012, /* OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE */
+ 0L))
+ {
+ KdPrint(("PMNTVideoDump: cannot open VIDEOHW.DMP, rc= %d\n",rc));
+ return;
+ }
+
+ if (rc=Dos16Write((ULONG)hfile,
+ PMNTDisplayAdapterName,
+ PMNTDisplayAdapterLen,
+ &cbWritten))
+ {
+ KdPrint(("PMNTVideoDump: cannot write display name to VIDEOHW.DMP, rc= %d\n",rc));
+ DosClose((ULONG)hfile);
+ return;
+ }
+
+ if (rc=Dos16Write((ULONG)hfile,videoState,len,&cbWritten))
+ {
+ KdPrint(("PMNTVideoDump: cannot write to VIDEOHW.DMP, rc= %d\n",rc));
+ DosClose((ULONG)hfile);
+ return;
+ }
+
+ DosClose((ULONG)hfile);
+ KdPrint(("PMNTVideoDump: C:\\OS2\\VIDEOHW.DMP was created\n"));
+ return;
+}
+
+//
+// This routine modifies the videostate buffer in the case that
+// c:\os2\videohw.dmp exists
+// returns TRUE if and only if the file exists and is readable
+//
+
+BOOL PMNTReadVideoDump(void)
+{
+
+ ULONG rc;
+ USHORT hfile,Action,cbRead;
+ CHAR tmp_name_buf[PMNTREGQUERYVALMAX];
+
+ if (PMNTDisplayAdapterLen == 0)
+ return FALSE;
+
+ if (Dos16Open("C:\\OS2\\VIDEOHW.DMP",
+ &hfile,
+ &Action,
+ 0L,
+ 0L,
+ 0x00000001, /* FILE_OPEN */
+ 0x00000020, /* OPEN_SHARE_DENYWRITE */
+ 0L))
+ {
+ // file_not_found is the normal case
+ return(FALSE);
+ }
+
+ if (rc=Dos16Read((ULONG)hfile,
+ tmp_name_buf,
+ PMNTDisplayAdapterLen,
+ &cbRead))
+ {
+ KdPrint(("PMNTReadVideoDump: cannot read VIDEOHW.DMP, rc= %d\n",rc));
+ DosClose((ULONG)hfile);
+ return(FALSE);
+ }
+
+ if (cbRead != PMNTDisplayAdapterLen)
+ {
+ KdPrint(("PMNTReadVideoDump: cannot read enough from VIDEOHW.DMP, cbRead= %d\n",
+ cbRead));
+ DosClose((ULONG)hfile);
+ return(FALSE);
+ }
+
+ if (memcmp(tmp_name_buf, PMNTDisplayAdapterName, PMNTDisplayAdapterLen))
+ {
+ KdPrint(("PMNTReadVideoDump: got name=%s instead of actual name=%s\n",
+ tmp_name_buf, PMNTDisplayAdapterName));
+ DosClose((ULONG)hfile);
+ return(FALSE);
+ }
+
+ if (rc=Dos16Read((ULONG)hfile,videoState,0x0000ffff,&cbRead))
+ {
+ KdPrint(("PMNTReadVideoDump: cannot read VIDEOHW.DMP, rc= %d\n",rc));
+ DosClose((ULONG)hfile);
+ return(FALSE);
+ }
+
+ KdPrint(("PMNTReadVideoDump() modified videoState from C:\\OS2\\VIDEOHW.DMP\n"));
+
+ DosClose((ULONG)hfile);
+ return(TRUE);
+}
+
+//
+// This routine modifies the videostate buffer in the case of
+// a QVision Adapter
+//
+void PMNTChkQVision(void)
+{
+ char *ptr,*ptr_base;
+
+ if (!(strstr(PMNTDisplayAdapterName,"\\qv\\")))
+ {
+ // Not QVision
+ return;
+ }
+
+ KdPrint(("This machine uses QVision Video Adapter\n"));
+
+ videoState->Length = 0x9c;
+ videoState->PortValue[0x1e] = 0x57;
+ videoState->BasicSequencerOffset = 0x9c;
+ videoState->BasicCrtContOffset = 0xa1;
+ videoState->BasicGraphContOffset = 0xba;
+ videoState->BasicAttribContOffset= 0xc3;
+ videoState->BasicDacOffset = 0xd8;
+ videoState->BasicLatchesOffset = 0x3d8;
+#if 0
+ videoState->ExtendedSequencerOffset = 0x3dc;
+ videoState->ExtendedCrtContOffset = 0x3dc;
+ videoState->ExtendedGraphContOffset = 0x429;
+ videoState->ExtendedAttribContOffset= 0x48a;
+ videoState->ExtendedDacOffset = 0x48a;
+ videoState->ExtendedValidatorStateOffset = 0x0;
+ videoState->ExtendedMiscDataOffset = 0x0;
+
+ videoState->PlaneLength = 0x10000;
+ videoState->Plane1Offset = 0x95a;
+ videoState->Plane2Offset = 0x1095a;
+ videoState->Plane3Offset = 0x2095a;
+ videoState->Plane4Offset = 0x3095a;
+ videoState->VGAStateFlags = 0x0;
+ videoState->DIBOffset = 0x0;
+ videoState->DIBBitsPerPixel = 0x0;
+ videoState->DIBXResolution = 0x0;
+ videoState->DIBYResolution = 0x0;
+ videoState->DIBXlatOffset = 0x0;
+ videoState->DIBXlatLength = 0x0;
+#endif //0
+
+ ptr_base = (char *)( videoState);
+
+ ptr = ptr_base + videoState->BasicSequencerOffset;
+ memcpy(ptr,InitStateBasicSequencer,sizeof(InitStateBasicSequencer));
+
+ ptr = ptr_base + videoState->BasicCrtContOffset;
+ memcpy(ptr,InitStateBasicCrtCont,sizeof(InitStateBasicCrtCont));
+
+ ptr = ptr_base + videoState->BasicGraphContOffset;
+ memcpy(ptr,InitStateBasicGraphCont,sizeof(InitStateBasicGraphCont));
+
+ ptr = ptr_base + videoState->BasicAttribContOffset;
+ memcpy(ptr,InitStateBasicAttribCont,sizeof(InitStateBasicAttribCont));
+
+ ptr = ptr_base + videoState->BasicDacOffset;
+ memcpy(ptr,InitStateBasicDac,sizeof(InitStateBasicDac));
+
+ ptr = ptr_base + videoState->BasicLatchesOffset;
+ memcpy(ptr,InitStateBasicLatches,sizeof(InitStateBasicLatches));
+#if 0
+ ptr = ptr_base + videoState->ExtendedCrtContOffset;
+ memcpy(ptr,InitStateExtendedCrtCont,sizeof(InitStateExtendedCrtCont));
+ ptr = ptr_base + videoState->ExtendedGraphContOffset;
+ memcpy(ptr,InitStateExtendedGraphCont,sizeof(InitStateExtendedGraphCont));
+#endif //0
+
+ return;
+}
+
+//
+// This routine reads the name of the display driver into a buffer
+//
+void PMNTReadDisplayAdapterName(void)
+{
+ char VideoKeyName[] = "HARDWARE\\DEVICEMAP\\VIDEO";
+ char VideoValName[] = "\\Device\\Video0";
+
+ LONG ValType,rc;
+ HKEY hKey;
+
+ if (rc = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,VideoKeyName,(DWORD)0,KEY_QUERY_VALUE,&hKey))
+ {
+ KdPrint(("PMNTReadDisplayAdapterName: RegOpenKeyEx() failed rc = %d\n",rc));
+ PMNTDisplayAdapterLen = 0;
+ return;
+ }
+
+ PMNTDisplayAdapterLen = PMNTREGQUERYVALMAX;
+
+ if (rc = RegQueryValueEx(
+ hKey,VideoValName,NULL,&ValType,
+ PMNTDisplayAdapterName,
+ &PMNTDisplayAdapterLen))
+ {
+ KdPrint(("PMNTReadDisplayAdapterName: RegQueryValEx() failed rc = %d\n",rc));
+ PMNTDisplayAdapterLen = 0;
+ RegCloseKey(hKey);
+ return;
+ }
+
+ RegCloseKey(hKey);
+
+ KdPrint(("This machine uses %s Video Adapter\n",
+ PMNTDisplayAdapterName));
+
+ return;
+}
+
+PMNTSetFocus(HWND FocusHwnd)
+{
+ BOOLEAN rc;
+
+// Code below doesn't work when the PM window which has been clicked on (which
+// is closing itself) causes PMShell to be selected (next in focus chain)
+#if 0
+ HWND tmp;
+
+ tmp = GetForegroundWindow();
+
+ // Try to ignore FOCUS event which arrives after we already set the focus
+ // on PMShell (for example, for the second spurious FOCUS event sent by
+ // the Console)
+ if (tmp == FocusHwnd)
+ {
+ return NO_ERROR;
+ }
+#endif //0
+
+#if DBG
+ DbgPrint("PMNTSetFocus: passing handle=%x\n", FocusHwnd);
+#endif
+
+ rc = SetForegroundWindow(FocusHwnd);
+
+ // PatrickQ 4/26/96: CBA fix, don't call OpenIcon if the
+ // SetForegroundWindow call failed. This prevents the PMShell window from
+ // being in a restored state when we attempt this code while a screen such
+ // as CTRL-ALT-DEL is on the desktop
+ if (!rc)
+ {
+#if DBG
+ DbgPrint("SetForegroundWindow failed, rc=0\n");
+#endif
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ rc = OpenIcon(FocusHwnd);
+// rc = ShowWindow(FocusHwnd, SW_SHOWMAXIMIZED);
+ if (!rc)
+ {
+#if DBG
+ DbgPrint("OpenIcon failed, rc=0\n");
+#endif
+ return ERROR_INVALID_PARAMETER;
+ }
+ else
+ return NO_ERROR;
+}
+
+void PMNTSetFullScreen(USHORT Register)
+{
+ CONSOLE_GRAPHICS_BUFFER_INFO GraphicsInfo;
+ HANDLE Handle;
+ COORD NewCoord;
+ /* Size of video save block. */
+ DWORD stateLength;
+ /* Video save block pointer. */
+ CHAR_INFO *textBuffer;
+ COORD textBufferSize; // Dimensions of the shared buffer
+ DWORD ModeFlags;
+ int i;
+ HANDLE ThreadHandle;
+ ULONG Tid;
+
+#if DBG
+ DbgPrint("PMNTSetFullScreen was called\n");
+#endif
+
+ if (Register)
+ {
+ // Create PMNTVDMEvent event objects
+ if (!Os2InitializeVDMEvents())
+ {
+#if DBG
+ DbgPrint("Os2: PMNTSetFullScreen, ERROR - Os2InitializeVDMEvents() failed\n");
+#endif // DBG
+ printf("Os2: PMNTSetFullScreen, ERROR - Os2InitializeVDMEvents() failed\n");
+ DosExit(0, 0);
+ }
+
+ PMNTReadDisplayAdapterName();
+
+ if (Register == 2)
+ {
+ HWDumpVersion = TRUE;
+ PMNTSetFullScreenDump();
+ return;
+ }
+ }
+ else // !Register
+ {
+ /**********************************************************************
+ * Un-register VDM: called by PMSHELL as part of its exit-list
+ **********************************************************************/
+ textBufferSize.X = 80;
+ textBufferSize.Y = 50;
+ stateLength = sizeof(CHAR_INFO)*80*50;
+
+ if (!RegisterConsoleVDM( FALSE,
+ hStartHardwareEvent,
+ hEndHardwareEvent,
+ (LPWSTR) NULL,
+ (DWORD) 0,
+ &stateLength,
+ (PVOID *) &videoState,
+ (LPWSTR) NULL,
+ (DWORD) 0,
+ textBufferSize,
+ (PVOID *) &textBuffer
+ )
+ )
+ {
+#if DBG
+ DbgPrint("PMNTSetFullScreen: ERROR, UnRegisterConsoleVDM() failed\n");
+#endif
+ }
+ return;
+ }
+
+ //
+ // open a new console
+ //
+
+ GraphicsInfo.dwBitMapInfoLength = sizeof(bmiPat);
+ GraphicsInfo.lpBitMapInfo = (LPBITMAPINFO)&bmiPat;
+ GraphicsInfo.dwUsage = DIB_RGB_COLORS;
+
+ // Set some fields according to the display resolution
+ GraphicsInfo.lpBitMapInfo->bmiHeader.biWidth = ScreenX;
+ // For some weird reason, the Console wants a negative value,
+ // otherwise it prints a: "****** Negating biHeight" message.
+ GraphicsInfo.lpBitMapInfo->bmiHeader.biHeight = -ScreenY;
+ GraphicsInfo.lpBitMapInfo->bmiHeader.biSizeImage = ScreenX*ScreenY/8;
+
+ Handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CONSOLE_GRAPHICS_BUFFER,
+ &GraphicsInfo
+ );
+ if (Handle == (HANDLE)-1)
+ {
+#if DBG
+ DbgPrint("PMNTSetFullScreen: ERROR, CreateConsoleScreenBuffer() failed, error=0x%x\n",
+ GetLastError());
+#endif
+ printf("PMSS: Internal error, CreateConsoleScreenBuffer() failed, error=0x%x\n",
+ GetLastError());
+ DosExit(0, 0);
+ return;
+ }
+
+ //
+ // make it current
+ //
+
+ if (!SetConsoleActiveScreenBuffer(Handle))
+ {
+#if DBG
+ DbgPrint("PMNTSetFullScreen: ERROR, SetConsoleActiveScreenBuffer() failed, error=0x%x\n",
+ GetLastError());
+#endif
+ printf("PMSS: Internal error, SetConsoleActiveScreenBuffer() failed, error=0x%x\n",
+ GetLastError());
+ DosExit(0, 0);
+ return;
+ }
+
+ if (!SetConsoleKeyShortcuts(
+ TRUE,
+ CONSOLE_ALTENTER,
+ NULL,
+ 0
+ )
+ )
+ {
+#if DBG
+ DbgPrint("PMNTSetFullScreen: ERROR, SetConsoleKetShortcuts() failed, error=0x%x\n",
+ GetLastError());
+#endif
+ }
+
+ if (!GetConsoleDisplayMode(&ModeFlags))
+ {
+#if DBG
+ DbgPrint("PMNTSetFullScreen: ERROR, GetConsoleDisplayMode() failed, error=0x%x\n",
+ GetLastError());
+#endif
+ printf("PMSS: Internal error, GetConsoleDisplayMode() failed, error=0x%x\n",
+ GetLastError());
+ DosExit(0, 0);
+ return;
+ }
+
+ // Is the Console already full-screen ?
+ if ((ModeFlags & CONSOLE_FULLSCREEN) != 0)
+ {
+#if DBG
+ DbgPrint("Os2: PMNTSetFullScreen, ERROR - trying to run PMShell from full-screen session !\n");
+#endif // DBG
+ SetConsoleKeyShortcuts(
+ TRUE,
+ 0,
+ NULL,
+ 0);
+ Ow2PMShellErrorPopup(Od2PgmFilePath, ERROR_PMSHELL_FULLSCREEN);
+ DosExit(0, 0);
+ return;
+ }
+
+ /*
+ * Register start and end events with the console. These events are used
+ * when gaining or losing control of the hardware.
+ */
+ hStartHardwareEvent = CreateEventW((LPSECURITY_ATTRIBUTES) NULL,
+ FALSE,
+ FALSE,
+ NULL);
+ hEndHardwareEvent = CreateEventW((LPSECURITY_ATTRIBUTES) NULL,
+ FALSE,
+ FALSE,
+ NULL);
+ if ((hStartHardwareEvent == NULL) || (hEndHardwareEvent == NULL))
+ {
+#if DBG
+ DbgPrint("PMNTSetFullScreen: ERROR, Cannot create start or end events\n");
+#endif
+ printf("PMSS: Internal error, cannot create start or end events\n");
+ DosExit(0, 0);
+ return;
+ }
+ /* Poll the event to try and get rid of any console queued sets
+ * This shouldn't be needed (or shouldn't work) but something along
+ * those lines seems to be happening at the moment.
+ */
+ WaitForSingleObject(hStartHardwareEvent, 0);
+
+ // Get rid of any events at that point
+ FlushConsoleInputBuffer(hConsoleInput);
+
+ textBufferSize.X = 80;
+ textBufferSize.Y = 50;
+ stateLength = sizeof(CHAR_INFO)*80*50;
+
+ if (!RegisterConsoleVDM( TRUE,
+ hStartHardwareEvent,
+ hEndHardwareEvent,
+ (LPWSTR) NULL,
+ (DWORD) 0,
+ &stateLength,
+ (PVOID *) &videoState,
+ (LPWSTR) NULL,
+ (DWORD) 0,
+ textBufferSize,
+ (PVOID *) &textBuffer
+ ) ||
+ (!stateLength)
+ )
+ {
+#if DBG
+ DbgPrint("PMNTSetFullScreen: ERROR, RegisterConsoleVDM() failed, error=0x%x\n",
+ GetLastError());
+#endif
+ printf("PMSS: Internal error, RegisterConsoleVDM() failed\n");
+ // Restore Console state
+ SetConsoleKeyShortcuts(
+ TRUE,
+ 0,
+ NULL,
+ 0);
+ DosExit(0, 0);
+ return;
+ }
+
+ // Set values for PortValue[]
+ for (i=0; i<0x30; i++)
+ videoState->PortValue[i] = InitStatePortValue[i];
+
+ // Initial value for AttribIndexDataState
+ videoState->AttribIndexDataState = 1;
+
+ if (!PMNTReadVideoDump())
+ {
+ PMNTChkQVision();
+ }
+
+ ThreadHandle = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)Os2VDMThread,
+ NULL,
+ 0,
+ &Tid);
+
+ if (!ThreadHandle)
+ {
+#if DBG
+ DbgPrint("OS2: PMNTSetFullScreen, fail to CreateThread, error %d\n",GetLastError());
+#endif
+ }
+ else
+ {
+ DWORD Status;
+ Status = NtClose(ThreadHandle);
+#if DBG
+ if (!(Status >= 0))
+ {
+ DbgPrint("PMNTSetFullScreen: NtClose(%x) failed, status=%x\n",
+ ThreadHandle, Status);
+ }
+#endif // DBG
+ }
+
+ if (!SetConsoleDisplayMode(
+ Handle,
+ CONSOLE_FULLSCREEN_MODE,
+ &NewCoord
+ ))
+ {
+#if DBG
+ DbgPrint("SetConsoleDisplayMode() 0x%x %d failed\n", GetLastError(),
+ GetLastError());
+#endif
+ }
+
+ // Work-around for cases where the Console doesn't make us full-screen
+ PMNTSetFocus(Ow2ForegroundWindow);
+
+ // Wait for Os2VDMThread() to get events from the Console signifying we
+ // went full-screen
+ Os2WaitForVDMThread(0);
+
+#if DBG
+ DbgPrint("Os2: PMNTSetFullScreen returning\n");
+#endif
+}
+
+/******************************************************************************
+* PMNTCloseWindow:
+*
+* Minimize the current window. This function is called when switching from
+* one of the CMD windows representing a PM app to the PMShell window.
+*
+******************************************************************************/
+
+PMNTCloseWindow()
+{
+ if (ProcessIsPMShell())
+ {
+ DWORD Dummy;
+
+
+#if DBG
+ DbgPrint("PMNTCloseWindow\n");
+#endif
+
+ // Special case: minimize PMShell window
+ if (!VDMConsoleOperation(
+ 1, //VDM_HIDE_WINDOW
+ (LPVOID)&Dummy))
+ {
+#if DBG
+ DbgPrint("PMNTCloseWindow: VDMConsoleOperation() 1 failed, error=0x%x\n",
+ GetLastError());
+#endif
+ return ERROR_INVALID_PARAMETER;
+ }
+ ShowWindow(Ow2ForegroundWindow, SW_HIDE);
+ if (!VDMConsoleOperation(
+ 1, //VDM_HIDE_WINDOW
+ (LPVOID)&Dummy))
+ {
+#if DBG
+ DbgPrint("PMNTCloseWindow: VDMConsoleOperation() 2 failed, error=0x%x\n",
+ GetLastError());
+#endif
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ return NO_ERROR;
+ }
+
+#if 0
+ The code below results in setting the window size to the size of an icon.
+ This is done so that double-clicking on such a window next time
+ produces the smallest possible transient restored window.
+ Unfortunately, this is not feasible because the current CMD window may be
+ a CMD window which the user expects to get back unharmed after the PM app
+ terminates (i.e. we shouldn't change its size) !
+
+ static int FirstTime = 0;
+
+ if (FirstTime < 2)
+ {
+ if (!SetWindowPos(
+ Ow2ForegroundWindow,
+ HWND_TOP,
+ 0, // X (ignored)
+ 0, // Y (ignored)
+ GetSystemMetrics(SM_CXICON), // CX
+ GetSystemMetrics(SM_CYICON), // CY
+ SWP_NOMOVE))
+ {
+#if DBG
+ DbgPrint("SetWindowPos failed, rc=%d\n",
+ GetLastError());
+#endif
+ }
+
+ FirstTime++;
+ }
+#endif //0
+
+#if DBG
+ DbgPrint("PMNTCloseWindow: passing handle=%x\n", Ow2ForegroundWindow);
+#endif
+
+ // PatrickQ 4/26/96: Upon closing the current window, take the opportunity
+ // to correct situations where we remember a 0 Ow2ForeGroundWindow
+ // because, for example, the PM app was started when a CTRL-ALT-DEL screen
+ // was active. This change is prompted by the CBA problem when starting
+ // PM apps while screen is locked
+ if (Ow2ForegroundWindow == 0)
+ {
+ // Re-acquire Ow2ForegroundWindow
+ Ow2ForegroundWindow = GetForegroundWindow();
+ }
+
+ if (!CloseWindow(Ow2ForegroundWindow))
+ {
+#if DBG
+ DbgPrint("CloseWindow failed, rc=%d\n",
+ GetLastError());
+#endif
+ }
+
+ return NO_ERROR;
+}
+
+VOID
+PMNTGetFullScreen(
+ ULONG Operation
+ )
+{
+#ifdef JAPAN
+ DWORD dwNlsMode;
+#endif // JAPAN
+#ifndef PMNT_DAYTONA
+ HANDLE ThreadHandle = NULL;
+ ULONG Tid;
+#endif // PMNT_DAYTONA
+ ULONG rc;
+
+ switch (Operation)
+ {
+ case 1: // Wait till we must loose focus
+#if DBG
+ DbgPrint("PMNTGetFullScreen(1): waiting for notification of lost focus\n");
+#endif
+#ifdef JAPAN // MSKK [ShigeO] Aug 18, 1993
+ //
+ // Disable Win32 IME on PM desktop
+ //
+ if(!GetConsoleNlsMode(hConsoleInput, &dwNlsMode)) {
+#if DBG
+ DbgPrint("GetConsoleNlsMode() 0x%x %d failed\n", GetLastError(), GetLastError());
+#endif
+ } else {
+#if DBG
+ DbgPrint("PMNTGetFullScreen: We are calling SetConsoleNlsMode\n");
+#endif
+ if(!SetConsoleNlsMode(hConsoleInput, dwNlsMode | NLS_IME_DISABLE)) {
+#if DBG
+ DbgPrint("SetConsoleNlsMode() 0x%x %d failed\n", GetLastError(), GetLastError());
+#endif
+ }
+ }
+#endif // JAPAN
+ if (rc = WaitForSingleObject(hStartHardwareEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("PMNTGetFullScreen(1): WaitForSingleObject(hStartHardwareEvent, INFINITE) failed, error=%x\n",
+ GetLastError());
+#endif
+ return;
+ }
+#if DBG
+ DbgPrint("PMNTGetFullScreen(1): got notification of lost focus, returning\n");
+#endif
+ PMNTInFocus = FALSE;
+ return;
+ case 2: // Notify Console it can take the focus away from us
+#if DBG
+ DbgPrint("PMNTGetFullScreen(2): sending event to console\n");
+#endif
+ if (!SetEvent(hEndHardwareEvent))
+ {
+#if DBG
+ DbgPrint("PMNTGetFullScreen(2): SetEvent(hEndHardwareEvent) #1 failed, error=%x\n",
+ GetLastError());
+#endif
+ return;
+ }
+#if DBG
+ DbgPrint("PMNTGetFullScreen(2): about to wait#2\n");
+#endif
+
+ if (rc = WaitForSingleObject(hStartHardwareEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("PMNTGetFullScreen(2): WaitForSingleObject(hStartHardwareEvent, INFINITE) failed, error=%x\n",
+ GetLastError());
+#endif
+ return;
+ }
+
+#if DBG
+ DbgPrint("PMNTGetFullScreen(2): wait#2 succeeded\n");
+#endif
+
+ if (!SetEvent(hEndHardwareEvent))
+ {
+#if DBG
+ DbgPrint("PMNTGetFullScreen(2): SetEvent(hEndHardwareEvent) #2 failed, error=%x\n",
+ GetLastError());
+#endif
+ return;
+ }
+#if DBG
+ DbgPrint("PMNTGetFullScreen(2): SetEvent(hEndHardwareEvent#2) succeeded, returning\n");
+#endif
+ return;
+ case 3: // Wait till we gain focus
+#if DBG
+ DbgPrint("PMNTGetFullScreen(3): waiting for notification of gain focus\n");
+#endif
+ if (rc = WaitForSingleObject(hStartHardwareEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("PMNTGetFullScreen(3): WaitForSingleObject(hStartHardwareEvent, INFINITE) #1 failed, error=%x\n",
+ GetLastError());
+#endif
+ return;
+ }
+
+#if DBG
+ DbgPrint("PMNTGetFullScreen(3): wait#1 succeeded (got focus)\n");
+#endif
+
+#if 0
+ {
+ ULONG offset;
+ int i;
+
+ DbgPrint("------------------------------------------------------\n");
+ DbgPrint("Hardware state header:\n");
+ DbgPrint("- Length=%x\n", videoState->Length);
+ DbgPrint("- PortValues:\n");
+ for (i=0; i<0x30; i++)
+ DbgPrint(" %d: %x\n", i, videoState->PortValue[i]);
+ DbgPrint("- AttribIndexDataState=%x\n", videoState->AttribIndexDataState);
+ DbgPrint("- BasicSequencerOffset=%x\n", videoState->BasicSequencerOffset);
+ for (offset = videoState->BasicSequencerOffset, i=0;
+ offset < videoState->BasicCrtContOffset;
+ offset++,i++)
+ {
+ if (!(i % 16))
+ DbgPrint("\n %2x: ", i);
+ DbgPrint("%2x ", *(BYTE *)((ULONG)videoState + offset));
+ }
+ DbgPrint("\n");
+ DbgPrint("- BasicCrtContOffset=%x\n", videoState->BasicCrtContOffset);
+ for (offset = videoState->BasicCrtContOffset, i=0;
+ offset < videoState->BasicGraphContOffset;
+ offset++,i++)
+ {
+ if (!(i % 16))
+ DbgPrint("\n %2x: ", i);
+ DbgPrint("%2x ", *(BYTE *)((ULONG)videoState + offset));
+ }
+ DbgPrint("\n");
+ DbgPrint("- BasicGraphContOffset=%x\n", videoState->BasicGraphContOffset);
+ for (offset = videoState->BasicGraphContOffset, i=0;
+ offset < videoState->BasicAttribContOffset;
+ offset++,i++)
+ {
+ if (!(i % 16))
+ DbgPrint("\n %2x: ", i);
+ DbgPrint("%2x ", *(BYTE *)((ULONG)videoState + offset));
+ }
+ DbgPrint("\n");
+ DbgPrint("- BasicAttribContOffset=%x\n", videoState->BasicAttribContOffset);
+ for (offset = videoState->BasicAttribContOffset, i=0;
+ offset < videoState->BasicDacOffset;
+ offset++,i++)
+ {
+ if (!(i % 16))
+ DbgPrint("\n %2x: ", i);
+ DbgPrint("%2x ", *(BYTE *)((ULONG)videoState + offset));
+ }
+ DbgPrint("\n");
+ DbgPrint("- BasicDacOffset=%x\n", videoState->BasicDacOffset);
+ for (offset = videoState->BasicDacOffset, i=0;
+ offset < videoState->BasicLatchesOffset;
+ offset++,i++)
+ {
+ if (!(i % 16))
+ DbgPrint("\n %2x: ", i);
+ DbgPrint("%2x ", *(BYTE *)((ULONG)videoState + offset));
+ }
+ DbgPrint("\n");
+ DbgPrint("- BasicLatchesOffset=%x\n", videoState->BasicLatchesOffset);
+ for (offset = videoState->BasicLatchesOffset, i=0;
+ offset < min(videoState->ExtendedSequencerOffset,0);
+ offset++,i++)
+ {
+ if (!(i % 16))
+ DbgPrint("\n %2x: ", i);
+ DbgPrint("%2x ", *(BYTE *)((ULONG)videoState + offset));
+ }
+ DbgPrint("\n");
+ DbgPrint("- ExtendedSequencerOffset=%x\n", videoState->ExtendedSequencerOffset);
+ DbgPrint("- ExtendedCrtContOffset=%x\n", videoState->ExtendedCrtContOffset);
+ DbgPrint("- ExtendedGraphContOffset=%x\n", videoState->ExtendedGraphContOffset);
+ DbgPrint("- ExtendedAttribContOffset=%x\n", videoState->ExtendedAttribContOffset);
+ DbgPrint("- ExtendedDacOffset=%x\n", videoState->ExtendedDacOffset);
+ DbgPrint("- ExtendedValidatorStateOffset=%x\n", videoState->ExtendedValidatorStateOffset);
+ DbgPrint("- ExtendedMiscDataOffset=%x\n", videoState->ExtendedMiscDataOffset);
+ DbgPrint("- PlaneLength=%x\n", videoState->PlaneLength);
+ DbgPrint("- Plane1Offset=%x\n", videoState->Plane1Offset);
+ DbgPrint("- Plane2Offset=%x\n", videoState->Plane2Offset);
+ DbgPrint("- Plane3Offset=%x\n", videoState->Plane3Offset);
+ DbgPrint("- Plane4Offset=%x\n", videoState->Plane4Offset);
+ DbgPrint("- VGAStateFlags=%x\n", videoState->VGAStateFlags);
+ DbgPrint("- DIBOffset=%x\n", videoState->DIBOffset);
+ DbgPrint("- DIBBitsPerPixel=%x\n", videoState->DIBBitsPerPixel);
+ DbgPrint("- DIBXResolution=%x\n", videoState->DIBXResolution);
+ DbgPrint("- DIBYResolution=%x\n", videoState->DIBYResolution);
+ DbgPrint("- DIBXlatOffset=%x\n", videoState->DIBXlatOffset);
+ DbgPrint("- DIBXlatLength=%x\n", videoState->DIBXlatLength);
+ DbgPrint("------------------------------------------------------\n");
+ }
+#endif // 0
+
+ if (HWDumpVersion)
+ {
+ // Workaround for unknown video adapters
+ // Dump videoState into c:\os2\videohw.dmp
+ if (!VideoDumped)
+ {
+ VideoDumped=TRUE;
+ PMNTVideoDump();
+ }
+ }
+
+#ifndef PMNT_DAYTONA
+ // Create a thread that will wait on the StartHardware event before
+ // we release the Console. This will prevent the Console from
+ // setting the event twice without letting us sense it twice
+
+ ThreadHandle = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)Os2VDMGetStartThread,
+ NULL,
+ 0,
+ &Tid);
+
+#if DBG
+ DbgPrint("PMNTGetFullScreen(3): Create Os2VDMGetStartThread(), handle = %x\n", ThreadHandle);
+#endif
+ Sleep(50L); // Sleep 50 miliseconds to make sure the above thread is
+ // waiting on the event
+ if (ThreadHandle)
+ {
+ DWORD Status;
+ Status = NtClose(ThreadHandle);
+#if DBG
+ if (!(Status >= 0))
+ {
+ DbgPrint("PMNTGetFullScreen(3): NtClose(%x) failed, status=%x\n",
+ ThreadHandle, Status);
+ }
+#endif // DBG
+ if (!Os2WaitForVDMThreadReady())
+ {
+#if DBG
+ DbgPrint("PMNTGetFullScreen(3): Os2WaitForVDMThread isn't useful, ThreadHandle = NULL\n");
+#endif // DBG
+ ThreadHandle = NULL;
+ }
+#if DBG
+ else
+ DbgPrint("PMNTGetFullScreen(3): Os2VDMGetStartThread is ready\n");
+#endif
+ }
+#if DBG
+ else
+ {
+ DbgPrint("PMNTGetFullScreen(3): CreateThread for Os2VDMGetStartThread failed, error=%x\n",
+ GetLastError());
+ }
+#endif // DBG
+#endif // not PMNT_DAYTONA
+
+ // Restore PM/NT mouse position
+ if (LastMousePosition.X != -1)
+ SetCursorPos(LastMousePosition.X,
+ LastMousePosition.Y);
+
+ if (!SetEvent(hEndHardwareEvent))
+ {
+#if DBG
+ DbgPrint("PMNTGetFullScreen(3): SetEvent(hEndHardwareEvent) #1 failed, error=%x\n",
+ GetLastError());
+#endif
+ return;
+ }
+
+#if DBG
+ DbgPrint("PMNTGetFullScreen(3): about to wait#2\n");
+#endif
+
+#ifndef PMNT_DAYTONA
+ if (ThreadHandle != NULL)
+ {
+#if DBG
+ DbgPrint("PMNTGetFullScreen(3): waiting for Os2VDMGetStartThread()\n");
+#endif
+ // Wait for Os2VDMGetStartThread() to get events from the
+ // Console signifying we went full-screen
+ if (!Os2WaitForVDMThread(0))
+ {
+#if DBG
+ DbgPrint("PMNTGetFullScreen(3): Os2WaitForVDMThread failed, return\n");
+#endif
+ return;
+ }
+ }
+ else
+ {
+ if (rc = WaitForSingleObject(hStartHardwareEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("PMNTGetFullScreen(3): WaitForSingleObject(hStartHardwareEvent, INFINITE) #2 failed, error=%x\n",
+ GetLastError());
+#endif
+ return;
+ }
+ }
+#else // PMNT_DAYTONA
+ if (rc = WaitForSingleObject(hStartHardwareEvent, INFINITE))
+ {
+#if DBG
+ DbgPrint("PMNTGetFullScreen(3): WaitForSingleObject(hStartHardwareEvent, INFINITE) #2 failed, error=%x\n",
+ GetLastError());
+#endif
+ return;
+ }
+ if (!SetEvent(hEndHardwareEvent))
+ {
+#if DBG
+ DbgPrint("PMNTGetFullScreen(3): SetEvent(hEndHardwareEvent) #2 failed, error=%x\n",
+ GetLastError());
+#endif
+ return;
+ }
+
+#endif // PMNT_DAYTONA
+
+#if DBG
+ DbgPrint("PMNTGetFullScreen(3): returning\n");
+#endif
+ PMNTInFocus = TRUE;
+ return;
+ default:
+#if DBG
+ DbgPrint("PMNTGetFullScreen: bad command %d\n", Operation);
+#endif
+ return;
+ }
+}
+
+BOOLEAN
+Ow2WriteBackCloseEvent()
+{
+ INPUT_RECORD InputRecord;
+ BOOLEAN WriteSucceeded;
+ DWORD RecordsWritten;
+
+ if (!ProcessIsPMProcess()) {
+ return(FALSE);
+ }
+ InputRecord.EventType = MENU_EVENT;
+ InputRecord.Event.MenuEvent.dwCommandId = WM_USER;
+ WriteSucceeded = WriteConsoleInput(hConsoleInput,
+ &InputRecord, 1, &RecordsWritten);
+ if (!WriteSucceeded || (RecordsWritten != 1)) {
+#if DBG
+ DbgPrint("OS2: Ow2WriteBackCloseEvent - failed to write into input queue\n");
+#endif // DBG
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+#endif // PMNT
diff --git a/private/os2/os2ses/event.h b/private/os2/os2ses/event.h
new file mode 100644
index 000000000..055f7007a
--- /dev/null
+++ b/private/os2/os2ses/event.h
@@ -0,0 +1,203 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ Event.h
+
+Abstract:
+
+ Prototypes for functions & macros in in event.c
+
+Author:
+
+ Michael Jarus (mjarus) 5-Nov-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include "monitor.h"
+
+/*
+ * event to sync access to monitor chain
+ */
+
+HANDLE MonitorEvent;
+
+/*
+ * abort flag indicator
+ */
+
+BOOL EventLoop;
+
+/*
+ * state for the monitor queue: open, reg & read
+ */
+
+#define MON_STAT_OPEN 0
+#define MON_STAT_REG 1
+#define MON_STAT_READ 2
+
+/*
+ * Last keyboard pressed: for KBD_MULTIMAKE bit of monitor
+ */
+
+WORD KbdLastKey;
+BOOL KbdLastKeyDown;
+KBDREQUEST KbdRequestSaveArea;
+BOOL KbdAsciiMode;
+PTRLOC MouPtrLoc;
+
+/*
+ * Monitor Header for all devices
+ * ------------------------------
+ * 0. Save ares for proposed relpies (pointed by MemoryStartAddress)
+ *
+ * 1. device type
+ * 2. MonReg info (exclude the MONITOR_SPECIEL) & the MONITOR_SPECIEL
+ * 3. Status of monitor (as define above)
+ * 4. flag to indicate if there is waiting request on empty queue
+ * 5. handle of semaphore to sync between direct MonRead & ReadThread
+ * 6. pointer for next MonReg for the same MonOpen
+ * 7. pointer for the next MonReg in the device
+ */
+
+typedef struct _MON_HEADER
+{
+// UCHAR ReadPortMessage[32]; // BUGBUG
+// UCHAR WritePortMessage[32]; // BUGBUG
+ MONDEVNUMBER DevType;
+ MON_REG MonReg;
+ ULONG Flag; // 1 - for MONITOR_SPECIEL Position
+ USHORT MonStat;
+ ULONG WaitForEvent;
+ CRITICAL_SECTION SyncCriticalSection;
+ PVOID MemoryStartAddress;
+ struct _MON_HEADER *NextMon;
+ struct _MON_HEADER *NextQueue;
+} MON_HEADER, *PMON_HEADER;
+
+typedef struct _KEYEVENTINFO
+{
+ WORD wRepeatCount;
+ KBD_MON_PACKAGE KeyInfo[1];
+} KEYEVENTINFO, *PKEYEVENTINFO;
+
+/*
+ * Queue for all devices
+ * ---------------------
+ * 1. Monitor header
+ * 2. Semaphore to wait on for first data (when empty)
+ * 3. In/Out/End pointer to data for Read/Write/Queue-End
+ * 4. Info - depends on the device
+ * 5. LastData which was not used and flag for it
+ * 6. Data records
+ */
+
+typedef struct _KEY_EVENT_QUEUE
+{
+ MON_HEADER MonHdr;
+ PKEYEVENTINFO In;
+ PKEYEVENTINFO Out;
+ PKEYEVENTINFO End;
+ KBDINFO Setup;
+ UCHAR bNlsShift;
+ USHORT Count;
+ USHORT Cp;
+ BOOL LastKeyFlag;
+ KEYEVENTINFO LastKey;
+ KEYEVENTINFO Event[1];
+} KEY_EVENT_QUEUE, *PKEY_EVENT_QUEUE;
+
+PKEY_EVENT_QUEUE KbdQueue, PhyKbdQueue, KbdMonQueue, MonQueue, LastKbdMon;
+
+typedef struct _MOU_EVENT_QUEUE
+{
+ MON_HEADER MonHdr;
+ // semaphore to wait on
+ PMOU_MON_PACKAGE In;
+ PMOU_MON_PACKAGE Out;
+ PMOU_MON_PACKAGE End;
+ BOOL LastMouFlag;
+ MOU_MON_PACKAGE LastEvent;
+ MOU_MON_PACKAGE Event[1];
+} MOU_EVENT_QUEUE, *PMOU_EVENT_QUEUE;
+
+PMOU_EVENT_QUEUE MouQueue, MouMonQueue, LastMouMon;
+
+#define HANDLE_HEAP_SIZE 64*1024 // Initial size of heap is 64K
+
+#define KEYBOARD_QUEUE_LENGTH 257
+#define KEYBOARD_QUEUE_SIZE (sizeof(KEY_EVENT_QUEUE) + sizeof(KEYEVENTINFO) * (KEYBOARD_QUEUE_LENGTH-1))
+
+#define MOUSE_QUEUE_LENGTH 11
+#define MOUSE_QUEUE_SIZE (sizeof(MOU_EVENT_QUEUE) + sizeof(MOU_MON_PACKAGE) * (MOUSE_QUEUE_LENGTH-1))
+
+/*
+ * flags for GetKeyboardInput
+ */
+
+#define WAIT_MASK 0x01
+#define ENABLE_KEY_DOWN 0x02
+#define ENABLE_NON_ASCII_KEY 0x04
+#define ENABLE_LN_EDITOR_KEY 0x08
+#define ENABLE_KEYS_ON_KEY 0x10
+
+DWORD KbdInit(IN VOID);
+DWORD MouInit(IN VOID);
+DWORD InitMonitor(IN VOID);
+DWORD InitVio(IN VOID);
+
+DWORD InitQueue(IN PKEY_EVENT_QUEUE *pKbdQueue);
+DWORD InitMouQueue(IN PMOU_EVENT_QUEUE *pMouQueue);
+
+DWORD CheckForBreakEvent(IN PKEYEVENTINFO KbdEvent);
+DWORD GetOs2MouEvent(IN USHORT WaitFlag, OUT PMOUEVENTINFO Event,
+ IN PVOID pMsg, OUT PULONG pReply);
+DWORD GetKeyboardInput(IN ULONG Flag, OUT PKEYEVENTINFO Event,
+ IN PVOID pMsg, OUT PULONG pReply);
+DWORD KbdHandlePackage(IN PKEY_EVENT_QUEUE NextKbdMon,
+ IN PKBD_MON_PACKAGE MonPackage);
+DWORD KbdCheckPackage(IN PKBD_MON_PACKAGE KbdPackage);
+
+/*
+ * Read/Write Monitor event from/to the device queue
+ */
+
+DWORD GetMonInput(IN USHORT MaxLength,
+ IN PKEY_EVENT_QUEUE KbdMon,
+ IN OUT PMON_RW rwParms,
+ IN PVOID pMsg,
+ OUT PULONG pReply);
+
+DWORD PutMonInput(IN USHORT MaxLength,
+ IN PKEY_EVENT_QUEUE KbdMon,
+ IN WORD RepeatCount,
+ //IN OUT PMON_RW rwParms,
+ IN PKBD_MON_PACKAGE MonPackage,
+ IN PVOID pMsg,
+ OUT PULONG pReply);
+
+DWORD MapWin2Os2KbdInfo(IN PKEY_EVENT_RECORD WinKey,
+ OUT PKEYEVENTINFO Os2Key);
+
+DWORD NewKbdQueue(IN PKEY_EVENT_QUEUE NewKbdQueue);
+
+USHORT MouNumber;
+USHORT MouLastEvent;
+DWORD MouEventMask;
+ULONG MouDevStatus;
+
+#ifdef DBCS
+// MSKK Jun.15.1992 KazuM
+// MSKK Aug.10.1992 V-AKihiS
+ULONG MapWinToOs2KbdNlsChar(IN PKEY_EVENT_RECORD WinKey,
+ OUT PKBD_MON_PACKAGE Os2KeyInfo);
+#endif
+
diff --git a/private/os2/os2ses/i386/bekbd.asm b/private/os2/os2ses/i386/bekbd.asm
new file mode 100644
index 000000000..24f464713
--- /dev/null
+++ b/private/os2/os2ses/i386/bekbd.asm
@@ -0,0 +1,778 @@
+;; SCCSID = @(#)bekbd.asm 12.2 89/04/07
+;MJ- Page 58,132
+ Title BEKBD - Translate Table Structure for CP/DOS 1.1
+ Name BEKBD
+
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: BEKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for Belgium *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;* Change Activity: *
+;* *
+;* PTM 3567 - Add support for e-circumflex for AT keyboards, *
+;* (reference FRKBD.ASM). pjr *
+;* *
+;* PTM 5609 - Add superscript n to 437 EN scan code 41 decimal.pjr*
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK BEKBD; **
+;** RELOC BEKBD.EXE BEKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+Public _Ow2BE437001 ;***************
+_Ow2BE437001 Label Byte ;Beginning of the table. BE 437 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,1,1,1,1,0,0,AT,Len1,'BE','120'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '&', '1', 0, 0, 0 ; 2 & 1
+ KeyDef 4, 0,0,0,0,0,0,0, 82h, '2', '@', 0, 0 ; 3 82h 2
+ KeyDef 4, 0,0,0,0,0,0,0, '"', '3', '#', 0, 0 ; 4 " 3
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '4', 0, 0, 0 ; 5 ' 4
+ KeyDef 4, 0,0,0,0,0,0,0, '(', '5', 0, 0, 0 ; 6 ( 5
+ KeyDef 4, 0,0,0,0,0,0,0, 15h, '6', '^', 0, 0 ; 7 15h 6
+ KeyDef 4, 0,0,0,0,0,0,0, 8Ah, '7', 0, 0, 0 ; 8 8Ah 7
+ KeyDef 4, 0,0,0,0,0,0,0, '!', '8', 0, 0, 0 ; 9 ! 8
+ KeyDef 4, 0,0,0,0,0,0,0, 87h, '9', 0, 0, 0 ; 10 87h 9
+ KeyDef 4, 0,0,0,0,0,0,0, 85h, '0', 0, 0, 0 ; 11 85h 0
+ KeyDef 4, 0,0,0,0,0,0,0, ')',0F8h, 0, 0, 0 ; 12 ) F8h
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 13 - _
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 1,1,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 16 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 17 z Z
+ KeyDef 1, 1,1,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, '[', 0, 1 ; 26 ^ umlaut
+ KeyDef 4, 0,0,0,0,0,0,0, '$', '*', ']', 0, 0 ; 27 $ *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 30 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 39 m M
+ KeyDef 4, 0,0,0,0,0,0,0, 97h, '%', 0, 0, 0 ; 40 97h %
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, 0E6h, 9Ch, 0, 0, 0 ; 43 E6h 9Ch
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 44 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 2, 0,0,0,0,0,0,0, ',', '?', 0, 0, 0 ; 50 , ?
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '.', 0, 0, 0 ; 51 ; .
+ KeyDef 4, 0,0,0,0,0,0,0, ':', '/', 0, 0, 0 ; 52 : /
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 53 = +
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'^',26,27,26,0,26,'a',83h,'i',8Ch,'e',88h,'o',93h,'u',96h,' ','^'>
+
+AccEnt <0F9h,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2BE437001
+
+;******************************************************************************
+
+Public _Ow2BE437011 ;***************
+_Ow2BE437011 Label Byte ;Beginning of the table. BE 437 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,1,1,0,1,0,0,EN,Len2,'BE','120'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '&', '1', 7Ch, 0, 0 ; 2 & 1
+ KeyDef 4, 0,0,0,0,0,0,0, 82h, '2', '@', 0, 0 ; 3 82h 2
+ KeyDef 4, 0,0,0,0,0,0,0, '"', '3', '#', 0, 0 ; 4 " 3
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '4', 0, 0, 0 ; 5 ' 4
+ KeyDef 4, 0,0,0,0,0,0,0, '(', '5', 0, 0, 0 ; 6 ( 5
+ KeyDef 4, 0,0,0,0,0,0,0, 15h, '6', '^', 0, 0 ; 7 15h 6
+ KeyDef 4, 0,0,0,0,0,0,0, 8Ah, '7', 0, 0, 0 ; 8 8Ah 7
+ KeyDef 4, 0,0,0,0,0,0,0, '!', '8', 0, 0, 0 ; 9 ! 8
+ KeyDef 4, 0,0,0,0,0,0,0, 87h, '9', '{', 0, 0 ; 10 87h 9
+ KeyDef 4, 0,0,0,0,0,0,0, 85h, '0', '}', 0, 0 ; 11 85h 0
+ KeyDef 4, 0,0,0,0,0,0,0, ')',0F8h, 0, 0, 0 ; 12 ) F8h
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 13 - _
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 16 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 17 z Z
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, '[', 0, 1 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, '$', '*', ']', 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 30 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 39 m M
+ KeyDef 11, 0,0,0,0,0,0,0, 97h, '%', 3, 0, 3 ; 40 97h %
+ KeyDef 4, 0,0,0,0,0,0,0, 0FDh, 0, 0, 0, 0 ; 41 superscript 2
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 11, 0,0,0,0,0,0,0, 0E6h, 9Ch, 4, 0, 4 ; 43 E6h 9Ch
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 44 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,1,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 2, 0,0,0,0,0,0,0, ',', '?', 0, 0, 0 ; 50 , ?
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '.', 0, 0, 0 ; 51 ; .
+ KeyDef 4, 0,0,0,0,0,0,0, ':', '/', 0, 0, 0 ; 52 : /
+ KeyDef 11, 0,0,0,0,0,0,0, '=', '+', 5, 0, 5 ; 53 = +
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,0,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'^',26,27,26,0,26,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <0FEh,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <0FEh,26,0,0,0,40,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h>
+
+AccEnt <'`',43,28,43,0,43,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <'~',53,0,0,0,53,'n',0A4h,'N',0A5h,' ','~'>
+
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2BE437011
+
+;******************************************************************************
+
+Public _Ow2BE850000 ;***************
+_Ow2BE850000 Label Byte ;Beginning of the table. BE 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,0,1,0,1,1,0,0,AT,Len3,'BE','120'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '&', '1', 0, 0, 0 ; 2 & 1
+ KeyDef 4, 0,0,0,0,0,0,0, 82h, '2', '@', 0, 0 ; 3 82h 2
+ KeyDef 4, 0,0,0,0,0,0,0, '"', '3', '#', 0, 0 ; 4 " 3
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '4', 0, 0, 0 ; 5 ' 4
+ KeyDef 4, 0,0,0,0,0,0,0, '(', '5', 0, 0, 0 ; 6 ( 5
+ KeyDef 4, 0,0,0,0,0,0,0, 0F5h, '6', '^', 0, 0 ; 7 F5h 6
+ KeyDef 4, 0,0,0,0,0,0,0, 8Ah, '7', 0, 0, 0 ; 8 8Ah 7
+ KeyDef 4, 0,0,0,0,0,0,0, '!', '8', 0, 0, 0 ; 9 ! 8
+ KeyDef 4, 0,0,0,0,0,0,0, 87h, '9', 0, 0, 0 ; 10 87h 9
+ KeyDef 4, 0,0,0,0,0,0,0, 85h, '0', 0, 0, 0 ; 11 85h 0
+ KeyDef 4, 0,0,0,0,0,0,0, ')',0F8h, 0, 0, 0 ; 12 ) F8h
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 13 - _
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 1,1,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 16 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 17 z Z
+ KeyDef 1, 1,1,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, '[', 0, 1 ; 26 ^ umlaut
+ KeyDef 4, 0,0,0,0,0,0,0, '$', '*', ']', 0, 0 ; 27 $ *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 30 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 39 m M
+ KeyDef 4, 0,0,0,0,0,0,0, 97h, '%', 0, 0, 0 ; 40 97h %
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, 0E6h, 9Ch, 0, 0, 0 ; 43 E6h 9Ch
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 44 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 2, 0,0,0,0,0,0,0, ',', '?', 0, 0, 0 ; 50 , ?
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '.', 0, 0, 0 ; 51 ; .
+ KeyDef 4, 0,0,0,0,0,0,0, ':', '/', 0, 0, 0 ; 52 : /
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 53 = +
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'^',26,27,26,0,26,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <0F9h,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2BE850000
+
+;******************************************************************************
+
+Public _Ow2BE850010 ;***************
+_Ow2BE850010 Label Byte ;Beginning of the table. BE 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,1,0,0,1,0,0,EN,Len4,'BE','120'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '&', '1', 7Ch, 0, 0 ; 2 & 1
+ KeyDef 4, 0,0,0,0,0,0,0, 82h, '2', '@', 0, 0 ; 3 82h 2
+ KeyDef 4, 0,0,0,0,0,0,0, '"', '3', '#', 0, 0 ; 4 " 3
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '4', 0, 0, 0 ; 5 ' 4
+ KeyDef 4, 0,0,0,0,0,0,0, '(', '5', 0, 0, 0 ; 6 ( 5
+ KeyDef 4, 0,0,0,0,0,0,0, 0F5h, '6', '^', 0, 0 ; 7 F5h 6
+ KeyDef 4, 0,0,0,0,0,0,0, 8Ah, '7', 0, 0, 0 ; 8 8Ah 7
+ KeyDef 4, 0,0,0,0,0,0,0, '!', '8', 0, 0, 0 ; 9 ! 8
+ KeyDef 4, 0,0,0,0,0,0,0, 87h, '9', '{', 0, 0 ; 10 87h 9
+ KeyDef 4, 0,0,0,0,0,0,0, 85h, '0', '}', 0, 0 ; 11 85h 0
+ KeyDef 4, 0,0,0,0,0,0,0, ')',0F8h, 0, 0, 0 ; 12 ) F8h
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 13 - _
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 1,1,1,1,1,0,0, 'a', 'A', 0, 0, 0 ; 16 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 17 z Z
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,1,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, '[', 0, 1 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, '$', '*', ']', 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 30 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 39 m M
+ KeyDef 11, 0,0,0,0,0,0,0, 97h, '%', 3, 0, 3 ; 40 97h %
+ KeyDef 4, 0,0,0,0,0,0,0, 0FDh,0FCh, 0, 0, 0 ; 41 FDh FCh
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 11, 0,0,0,0,0,0,0, 0E6h, 9Ch, 4, 0, 4 ; 43 E6h 9Ch
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 44 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,1,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 2, 0,0,0,0,0,0,0, ',', '?', 0, 0, 0 ; 50 , ?
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '.', 0, 0, 0 ; 51 ; .
+ KeyDef 4, 0,0,0,0,0,0,0, ':', '/', 0, 0, 0 ; 52 : /
+ KeyDef 11, 0,0,0,0,0,0,0, '=', '+', 5, 0, 5 ; 53 = +
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt<'^',26,27,26,0,26,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <0F9h,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <0EFh,40,0,0,0,40,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'A',0B5h,'E',90h,'I',0D6h,'O',0E0h,'U',0E9h,'y',0ECh,'Y',0EDh,' ',0EFh>
+
+AccEnt <'`',43,28,43,0,43,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <'~',53,0,0,0,53,'a',0C6h,'o',0E4h,'n',0A4h,'A',0C7h,'O',0E5h,'N',0A5h,' ','~'>
+
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2BE850010
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/cfkbd.asm b/private/os2/os2ses/i386/cfkbd.asm
new file mode 100644
index 000000000..7a457ef91
--- /dev/null
+++ b/private/os2/os2ses/i386/cfkbd.asm
@@ -0,0 +1,794 @@
+;; SCCSID = @(#)cfkbd.asm 12.1 88/03/18
+; Page 58,132
+ Title CFKBD - Translate Table Structure for CP/DOS 1.1
+ Name CFKBD
+
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: CFKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for Canadian French *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;* Change Activity: *
+;* *
+;* Added L/R angle quotes to Enhanced kbd scan *
+;* codes 2Fh and 30h, and the degree symbol to scan *
+;* code 31h for code pages 863 and 850 (PTM 186). pjr *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK CFKBD; **
+;** RELOC CFKBD.EXE CFKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+Public _Ow2CF863001 ;******
+_Ow2CF863001 Label Byte ;Beginning of the table. CF 863 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 863,1,0,0,0,1,0,0,0,0,AT,Len1,'CF','058'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!',0F1h, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '/', 9Ch, 0, 0 ; 4 3 /
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 9Bh, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 98h, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '?',0AAh, 0, 0 ; 7 6 ?
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&',0A0h, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*',0FDh, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(',0A6h, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')',0ACh, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_',0ABh, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+',0ADh, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,0,1,1,1,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,0,1,1,1,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,0,1,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,0,0,0,1,0,0, 'o', 'O', 8Fh, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 86h, 0, 0 ; 25 p P
+ KeyDef 11, 1,0,0,0,0,0,0, 1, 1, '[', 0, 1 ; 26 circumflex
+ KeyDef 11, 0,1,1,0,0,0,0, 2, 3, ']', 0, 2 ; 27 cedilla diaresis
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,0,0,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', '~', 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', '{', 0, 0 ; 39 ; :
+ KeyDef 11, 0,0,0,1,0,0,0, 4, 4, '}', 0, 4 ; 40 grave
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', '#', 0, 0 ; 43 \ |
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,1,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V',0AEh, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B',0AFh, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N',0F8h, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M',0E6h, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', "'",0A7h, 0, 0 ; 51 , '
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '.', 0, 0, 0 ; 52 . .
+ KeyDef 3, 0,0,0,0,1,0,0, 82h, 90h, 5, 0, 0 ; 53 e E (acute)
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'^',26,27,26,0,26,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',84h,'E',92h,'I',0A8h,'O',99h,'U',9Eh,1,'^',' ','^'>
+
+AccEnt <0A5h,27,29,27,0,27,'c',87h,'C',80h,2,0A5h,' ',0A5h>
+
+AccEnt <0A4h,27,29,27,0,0,'e',89h,'i',8Bh,'u',81h,'E',94h,'I',95h,'U',9Ah,3,0A4h,' ',0A4h>
+
+AccEnt <'`',40,0,0,0,40,'a',85h,'e',8Ah,'u',97h,'A',8Eh,'E',91h,'U',9Dh,4,'`',' ','`'>
+
+AccEnt <0A1h,53,0,0,0,0,'e',82h,'o',0A2h,'u',0A3h,'E',90h,5,0A1h,' ',0A1h>
+
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2CF863001
+
+;******************************************************************************
+
+Public _Ow2CF863011 ;******
+_Ow2CF863011 Label Byte ;Beginning of the table. CF 863 EN Kbd
+ ;***************
+
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 863,0,0,1,0,1,0,0,0,0,EN,Len2,'CF','058'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!',0F1h, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '/', 9Ch, 0, 0 ; 4 3 /
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 9Bh, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 98h, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '?',0AAh, 0, 0 ; 7 6 ?
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&',0A0h, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*',0FDh, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(',0A6h, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')',0ACh, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_',0ABh, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+',0ADh, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,0,1,1,1,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,0,1,1,1,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,0,1,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,0,0,0,1,0,0, 'o', 'O', 8Fh, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 86h, 0, 0 ; 25 p P
+ KeyDef 11, 1,0,0,0,0,0,0, 1, 1, '[', 0, 1 ; 26 circumflex
+ KeyDef 11, 0,1,1,0,0,0,0, 2, 3, ']', 0, 2 ; 27 cedilla diaresis
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,0,0,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', '~', 0, 0 ; 39 ; :
+ KeyDef 11, 0,0,0,1,0,0,0, 4, 4, '{', 0, 4 ; 40 grave
+ KeyDef 4, 0,0,0,0,0,0,0, '#', '|', '\', 0, 0 ; 41 # |
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '}', 0, 0 ; 43 < >
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,1,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V',0AEh, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B',0AFh, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N',0F8h, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M',0E6h, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', "'",0A7h, 0, 0 ; 51 , '
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '.', 0, 0, 0 ; 52 . .
+ KeyDef 3, 0,0,0,0,1,0,0, 82h, 90h, 5, 0, 0 ; 53 e E (acute)
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, 0AEh,0AFh,0F8h, 0, 0 ; 86 AEh AFh
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'^',26,27,26,0,26,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',84h,'E',92h,'I',0A8h,'O',99h,'U',9Eh,1,'^',' ','^'>
+
+AccEnt <0A5h,27,29,27,0,27,'c',87h,'C',80h,2,0A5h,' ',0A5h>
+
+AccEnt <0A4h,27,29,27,0,0,'e',89h,'i',8Bh,'u',81h,'E',94h,'I',95h,'U',9Ah,3,0A4h,' ',0A4h>
+
+AccEnt <'`',40,0,0,0,40,'a',85h,'e',8Ah,'u',97h,'A',8Eh,'E',91h,'U',9Dh,4,'`',' ','`'>
+
+AccEnt <0A1h,53,0,0,0,0,'e',82h,'o',0A2h,'u',0A3h,'E',90h,5,0A1h,' ',0A1h>
+
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2CF863011
+
+;*****************************************************************************
+
+Public _Ow2CF850000 ;******
+_Ow2CF850000 Label Byte ;Beginning of the table. CF 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,1,0,0,0,0,0,0,0,0,AT,Len3,'CF','058'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!',0F1h, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '/', 9Ch, 0, 0 ; 4 3 /
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$',0BDh, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%',0CFh, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '?',0AAh, 0, 0 ; 7 6 ?
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&',0DDh, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*',0FDh, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(',0FCh, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')',0ACh, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_',0ABh, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+',0F3h, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,0,1,1,1,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,1,0,1,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,0,1,1,1,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,0,1,1,1,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,0,1,1,1,0,0, 'o', 'O',0F5h, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P',0F4h, 0, 0 ; 25 p P
+ KeyDef 11, 1,0,0,0,0,0,0, 1, 1, '[', 0, 1 ; 26 circumflex
+ KeyDef 11, 0,1,1,0,0,0,0, 2, 3, ']', 0, 2 ; 27 cedilla diaresis
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,0,1,1,1,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', '~', 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', '{', 0, 0 ; 39 ; :
+ KeyDef 11, 0,0,0,1,0,0,0, 4, 4, '}', 0, 4 ; 40 grave
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', '#', 0, 0 ; 43 \ |
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,1,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V',0AEh, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B',0AFh, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N',0F8h, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M',0E6h, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', "'",0EEh, 0, 0 ; 51 , '
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '.', 0, 0, 0 ; 52 . .
+ KeyDef 3, 0,0,0,0,1,0,0, 82h, 90h, 5, 0, 0 ; 53 e E (acute)
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'^',26,27,26,0,26,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,1,'^',' ','^'>
+
+AccEnt <0F7h,27,29,27,0,27,'c',87h,'C',80h,2,0F7h,' ',0F7h>
+
+AccEnt <0F9h,27,29,27,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,3,0F9h,' ',0F9h>
+
+AccEnt <'`',40,0,0,0,40,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,4,'`',' ','`'>
+
+;AccEnt #5
+db 0EFh,53, 0,0, 0,0
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh
+db 5,0EFh, ' ',0EFh, 0,0, 0,0, 0,0, 0,0
+db 0,0, 0,0
+
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2CF850000
+
+;*****************************************************************************
+
+Public _Ow2CF850010 ;******
+_Ow2CF850010 Label Byte ;Beginning of the table. CF 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,0,0,0,EN,Len4,'CF','058'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!',0F1h, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '/', 9Ch, 0, 0 ; 4 3 /
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$',0BDh, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%',0CFh, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '?',0AAh, 0, 0 ; 7 6 ?
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&',0DDh, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*',0FDh, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(',0FCh, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')',0ACh, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_',0ABh, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+',0F3h, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,0,1,1,1,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,1,0,1,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,0,1,1,1,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,0,1,1,1,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,0,1,1,1,0,0, 'o', 'O',0F5h, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P',0F4h, 0, 0 ; 25 p P
+ KeyDef 11, 1,0,0,0,0,0,0, 1, 1, '[', 0, 1 ; 26 circumflex
+ KeyDef 11, 0,1,1,0,0,0,0, 2, 3, ']', 0, 2 ; 27 cedilla diaresis
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,0,1,1,1,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', '~', 0, 0 ; 39 ; :
+ KeyDef 11, 0,0,0,1,0,0,0, 4, 4, '{', 0, 4 ; 40 grave
+ KeyDef 4, 0,0,0,0,0,0,0, '#', '|', '\', 0, 0 ; 41 # |
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '}', 0, 0 ; 43 < >
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,1,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V',0AEh, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B',0AFh, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N',0F8h, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M',0E6h, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', "'",0EEh, 0, 0 ; 51 , '
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '.', 0, 0, 0 ; 52 . .
+ KeyDef 3, 0,0,0,0,1,0,0, 82h, 90h, 5, 0, 0 ; 53 e E (acute)
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, 0AEh,0AFh,0F8h, 0, 0 ; 86 AEh AFh
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'^',26,27,26,0,26,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,1,'^',' ','^'>
+
+AccEnt <0F7h,27,29,27,0,27,'c',87h,'C',80h,2,0F7h,' ',0F7h>
+
+AccEnt <0F9h,27,29,27,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,3,0F9h,' ',0F9h>
+
+AccEnt <'`',40,0,0,0,40,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,4,'`',' ','`'>
+
+;AccEnt #5
+db 0EFh,53, 0,0, 0,0
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh
+db 5,0EFh, ' ',0EFh, 0,0, 0,0, 0,0, 0,0
+db 0,0, 0,0
+
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2CF850010
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/dkkbd.asm b/private/os2/os2ses/i386/dkkbd.asm
new file mode 100644
index 000000000..d8304d115
--- /dev/null
+++ b/private/os2/os2ses/i386/dkkbd.asm
@@ -0,0 +1,790 @@
+;; SCCSID = @(#)dkkbd.asm 12.2 89/02/16
+ Page 58,132
+ Title DKKBD - Translate Table Structure for CP/DOS 1.1
+ Name DKKBD
+
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: DKKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for Denmark *
+;* *
+;* *
+;* Status: OS/2 Version 1.2 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;* Changes: *
+;* Added AltAcChar of 0/27 for Accent 3 in EN 850. PTM *
+;* 5674. pjr *
+;* *
+;* Fixed stand-alone acute accent for codepage 865. PTR *
+;* 3081. wak *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK DKKBD; **
+;** RELOC DKKBD.EXE DKKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-.286
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;AltPadMap Label Byte
+Public _Ow2DK865001 ;***************
+_Ow2DK865001 Label Byte ;Beginning of the table. DK 865 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 865,1,0,0,0,1,0,1,0,0,AT,Len1,'DK','159'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4',0AFh, '$', 0, 0 ; 5 4 monetary
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', '^', 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '&', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '*', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', '(', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', ')', 0, 0 ; 11 0 =
+ KeyDef 21, 0,0,0,0,0,0,0, '+', '?', '_', '-', 0 ; 12 + ?
+ KeyDef 21, 0,0,0,0,0,0,0, 1, 2, '+', '=', 0 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, '{', '[', 0 ; 26 a A (overcircle)
+ KeyDef 21, 0,0,0,0,0,0,0, 3, 4, '}', ']', 0 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 91h, 92h, ':', ';', 0 ; 39 oE dipthong
+ KeyDef 3, 0,0,0,0,0,0,0, 9Bh, 9Dh, '"', "'", 0 ; 40 o O (slash)
+ KeyDef 21, 0,0,0,0,0,0,0, '<', '>', 7Ch, '\', 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 21, 0,0,0,0,0,0,0, "'", '*', '~', '`', 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', '<', 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', '>', 0, 0 ; 52 . :
+ KeyDef 21, 0,0,0,0,0,0,0, '-', '_', '?', '/', 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,0,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <0FEh,13,0,0,0,131,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h>
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <0FEh,27,29,27,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2DK865001
+
+;******************************************************************************
+
+Public _Ow2DK865011 ;***************
+_Ow2DK865011 Label Byte ;Beginning of the table. DK 865 EN Kbd
+ ;***************
+
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 865,0,0,1,0,1,0,1,0,0,EN,Len2,'DK','159'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 9Ch, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4',0AFh, '$', 0, 0 ; 5 4 monetary symbol
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '{', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '[', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', ']', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', '}', 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '?', 0, 0, 0 ; 12 + ?
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, 7Ch, 0, 1 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, 0, 0, 0 ; 26 a A (overcircle)
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, 5, 0, 3 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 91h, 92h, 0, 0, 0 ; 39 aE dipthong
+ KeyDef 3, 0,0,0,0,0,0,0, 9Bh, 9Dh, 0, 0, 0 ; 40 o O (slash)
+ KeyDef 4, 0,0,0,0,0,0,0, 0ABh, 15h, 0, 0, 0 ; 41 one-half section
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '*', 0, 0, 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,1,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,0,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del ,
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <0FEh,13,0,0,0,131,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h>
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <0FEh,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <'~',27,29,27,0,0,'n',0A4h,'N',0A5h,' ','~'>
+
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2DK865011
+
+;*****************************************************************************
+
+Public _Ow2DK850000 ;***************
+_Ow2DK850000 Label Byte ;Beginning of the table. DK 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,1,0,0,0,0,0,1,0,0,AT,Len3,'DK','159'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4',0CFh, '$', 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', '^', 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '&', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '*', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', '(', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', ')', 0, 0 ; 11 0 =
+ KeyDef 21, 0,0,0,0,0,0,0, '+', '?', '_', '-', 0 ; 12 + ?
+ KeyDef 21, 0,0,0,0,0,0,0, 1, 2, '+', '=', 0 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 1,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, '{', '[', 0 ; 26 a A (overcircle)
+ KeyDef 21, 0,0,0,0,0,0,0, 3, 4, '}', ']', 0 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 91h, 92h, ':', ';', 0 ; 39 aE dipthong
+ KeyDef 3, 0,0,0,0,0,0,0, 9Bh, 9Dh, '"', "'", 0 ; 40 o O (slash)
+ KeyDef 21, 0,0,0,0,0,0,0, '<', '>', 7Ch, '\', 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 21, 0,0,0,0,0,0,0, "'", '*', '~', '`', 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', '<', 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', '>', 0, 0 ; 52 . :
+ KeyDef 21, 0,0,0,0,0,0,0, '-', '_', '?', '/', 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+;AccEnt #1
+db 0EFh,13, 0,0, 0,131
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh, ' ',0EFh
+db 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <0F9h,27,29,27,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2DK850000
+
+;*****************************************************************************
+
+Public _Ow2DK850010 ;***************
+_Ow2DK850010 Label Byte ;Beginning of the table. DK 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,1,0,0,EN,Len4,'DK','159'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 9Ch, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4',0CFh, '$', 0, 0 ; 5 4 monetary symbol
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '{', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '[', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', ']', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', '}', 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '?', 0, 0, 0 ; 12 + ?
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, 7Ch, 0, 1 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 1,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,1,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, 0, 0, 0 ; 26 a A (overcircle)
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, 5, 0, 3 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,1,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 91h, 92h, 0, 0, 0 ; 39 aE dipthong
+ KeyDef 3, 0,0,0,0,0,0,0, 9Bh, 9Dh, 0, 0, 0 ; 40 o O (slash)
+ KeyDef 4, 0,0,0,0,0,0,0, 0ABh,0F5h, 0, 0, 0 ; 41 one-half section
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '*', 0, 0, 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,1,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del ,
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+;AccEnt #1
+db 0EFh,13, 0,0, 0,131
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh, ' ',0EFh
+db 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <0F9h,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <'^',27,29,27,0,27,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <'~',27,29,27,0,0,'a',0C6h,'n',0A4h,'o',0E4h,'A',0C7h,'N',0A5h,'O',0E5h,' ','~'>
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2DK850010
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/frkbd.asm b/private/os2/os2ses/i386/frkbd.asm
new file mode 100644
index 000000000..62d3e8b83
--- /dev/null
+++ b/private/os2/os2ses/i386/frkbd.asm
@@ -0,0 +1,1153 @@
+;; SCCSID = @(#)frkbd.asm 12.3 89/06/30
+ Page 58,132
+ Title FRKBD - Translate Table Structure for CP/DOS 1.1
+ Name FRKBD
+
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: FRKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for France *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;* Change Activity: *
+;* *
+;* PTM 3317 - Changed Char1 for Scan Code 40d from A3h (accent *
+;* acute) to 97h (accent grave) for the 437 EN and *
+;* 850 EN keyboard tables. pjr *
+;* *
+;* PTM 3567 - Add support for e circumflex to all tables. pjr *
+;* *
+;* PTM 5609 - Add superscript n to 437 EN scan code 41 decimal.pjr*
+;* *
+;* lt (10/9/87) - changed decimal point to comma on DEL key *
+;* for 120 layout && PTM 883 *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK FRKBD; **
+;** RELOC FRKBD.EXE FRKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-.286
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;AltPadMap Label Byte
+; db 7,8,9,-1
+
+Public _Ow2FR437001 ;***************
+_Ow2FR437001 Label Byte ;Beginning of the table. FR 437 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,1,1,1,1,0,1,AT,Len1,'FR','189'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '&', '1', 0, 0, 0 ; 2 & 1
+ KeyDef 4, 0,0,0,0,0,0,0, 82h, '2', '@', 0, 0 ; 3 82h 2
+ KeyDef 4, 0,0,0,0,0,0,0, '"', '3', '#', 0, 0 ; 4 " 3
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '4', 0, 0, 0 ; 5 ' 4
+ KeyDef 4, 0,0,0,0,0,0,0, '(', '5', 0, 0, 0 ; 6 ( 5
+ KeyDef 4, 0,0,0,0,0,0,0, 15h, '6', '^', 0, 0 ; 7 15h 6
+ KeyDef 4, 0,0,0,0,0,0,0, 8Ah, '7', 0, 0, 0 ; 8 8Ah 7
+ KeyDef 4, 0,0,0,0,0,0,0, '!', '8', 0, 0, 0 ; 9 ! 8
+ KeyDef 4, 0,0,0,0,0,0,0, 87h, '9', 0, 0, 0 ; 10 87h 9
+ KeyDef 4, 0,0,0,0,0,0,0, 85h, '0', 0, 0, 0 ; 11 85h 0
+ KeyDef 4, 0,0,0,0,0,0,0, ')',0F8h, 0, 0, 0 ; 12 ) F8h
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 13 - _
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 1,1,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 16 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 17 z Z
+ KeyDef 1, 1,1,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, '[', 0, 1 ; 26 ^ umlaut
+ KeyDef 4, 0,0,0,0,0,0,0, '$', '*', ']', 0, 0 ; 27 $ *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 30 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 39 m M
+ KeyDef 4, 0,0,0,0,0,0,0, 97h, '%', 0, 0, 0 ; 40 97h %
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, 0E6h, 9Ch, 0, 0, 0 ; 43 E6h 9Ch
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 44 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 2, 0,0,0,0,0,0,0, ',', '?', 0, 0, 0 ; 50 , ?
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '.', 0, 0, 0 ; 51 ; .
+ KeyDef 4, 0,0,0,0,0,0,0, ':', '/', 0, 0, 0 ; 52 : /
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 53 = +
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'^',26,27,26,0,26,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <0F9h,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2FR437001
+
+;******************************************************************************
+
+Public _Ow2FR437011 ;***************
+_Ow2FR437011 Label Byte ;Beginning of the table. FR 437 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,1,1,0,1,0,1,EN,Len2,'FR','189'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '&', '1', 0, 0, 0 ; 2 & 1
+ KeyDef 3, 0,0,1,0,0,0,0, 82h, '2', 3, 0, 3 ; 3 82h 2
+ KeyDef 4, 0,0,0,0,0,0,0, '"', '3', '#', 0, 0 ; 4 " 3
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '4', '{', 0, 0 ; 5 ' 4
+ KeyDef 4, 0,0,0,0,0,0,0, '(', '5', '[', 0, 0 ; 6 ( 5
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '6', '|', 0, 0 ; 7 - 6
+ KeyDef 3, 0,0,0,1,0,0,0, 8Ah, '7', 4, 0, 4 ; 8 8Ah 7
+ KeyDef 4, 0,0,0,0,0,0,0, '_', '8', '\', 0, 0 ; 9 _ 8
+ KeyDef 4, 0,0,0,0,0,0,0, 87h, '9', '^', 0, 0 ; 10 87h 9
+ KeyDef 4, 0,0,0,0,0,0,0, 85h, '0', '@', 0, 0 ; 11 85h 0
+ KeyDef 4, 0,0,0,0,0,0,0, ')', 'ø', ']', 0, 0 ; 12 ) ø
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', '}', 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 1,1,0,1,0,0,0, 'a', 'A', 0, 0, 0 ; 16 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 17 z Z
+ KeyDef 1, 1,1,0,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,0,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,0,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,0,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, 0, 0, 1 ; 26 ^ diaresis
+ KeyDef 4, 0,0,0,0,0,0,0, '$', 'œ', 0, 0, 0 ; 27 $ œ
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 30 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 39 m M
+ KeyDef 4, 0,0,0,0,0,0,0, 097h, '%', 0, 0, 0 ; 40 u-grave %
+ KeyDef 4, 0,0,0,0,0,0,0, 0FDh, 0, 0, 0, 0 ; 41 superscript 2
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '*',0E6h, 0, 0, 0 ; 43 * micro
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 44 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,1,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 2, 0,0,0,0,0,0,0, ',', '?', 0, 0, 0 ; 50 , ?
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '.', 0, 0, 0 ; 51 ; .
+ KeyDef 4, 0,0,0,0,0,0,0, ':', '/', 0, 0, 0 ; 52 : /
+ KeyDef 4, 0,0,0,0,0,0,0, '!', 15h, 0, 0, 0 ; 53 ! 15h
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,0,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'^',26,27,26,0,26,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <0F9h,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <'~',53,0,0,0,53,'n',0A4h,'N',0A5h,' ','~'>
+
+AccEnt <'`',43,28,43,0,43,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2FR437011
+
+
+;******************************************************************************
+
+Public _Ow2FR437111 ;**************************
+_Ow2FR437111 Label Byte ;Beginning of the table. FR 437 EN Kbd New Std
+ ;**************************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,1,1,0,1,0,1,EN,Len3,'FR','120'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '&', '1', 7Ch, 0, 0 ; 2 & 1
+ KeyDef 4, 0,0,0,0,0,0,0, 82h, '2', '@', 0, 0 ; 3 82h 2
+ KeyDef 4, 0,0,0,0,0,0,0, '"', '3', '#', 0, 0 ; 4 " 3
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '4', 0, 0, 0 ; 5 ' 4
+ KeyDef 4, 0,0,0,0,0,0,0, '(', '5', 0, 0, 0 ; 6 ( 5
+ KeyDef 4, 0,0,0,0,0,0,0, 15h, '6', '^', 0, 0 ; 7  6
+ KeyDef 4, 0,0,0,0,0,0,0, 8Ah, '7', 0, 0, 0 ; 8 8Ah 7
+ KeyDef 4, 0,0,0,0,0,0,0, '!', '8', 0, 0, 0 ; 9 ! 8
+ KeyDef 4, 0,0,0,0,0,0,0, 87h, '9', '{', 0, 0 ; 10 87h 9
+ KeyDef 4, 0,0,0,0,0,0,0, 85h, '0', '}', 0, 0 ; 11 85h 0
+ KeyDef 4, 0,0,0,0,0,0,0, ')', 'ø', 0, 0, 0 ; 12 ) ø
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 13 - _
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 16 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 17 z Z
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, '[', 0, 1 ; 26 ^ diaresis
+ KeyDef 4, 0,0,0,0,0,0,0, '$', '*', ']', 0, 0 ; 27 $ *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 30 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 39 m M
+ KeyDef 11, 0,0,0,0,0,0,0, 97h, '%', 3, 0, 3 ; 40 u-grave %
+ KeyDef 4, 0,0,0,0,0,0,0, 0FDh, 0, 0, 0, 0 ; 41 FDh FCh
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 11, 0,0,0,0,0,0,0, 0E6h, 'œ', 4, 0, 4 ; 43 micro œ
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 44 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,1,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 2, 0,0,0,0,0,0,0, ',', '?', 0, 0, 0 ; 50 , ?
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '.', 0, 0, 0 ; 51 ; .
+ KeyDef 4, 0,0,0,0,0,0,0, ':', '/', 0, 0, 0 ; 52 : /
+ KeyDef 11, 0,0,0,0,0,0,0, '=', '+', 5, 0, 5 ; 53 = +
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,0,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'^',26,27,26,0,26,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <0F9h,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <0FEh,40,0,0,0,40,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h>
+
+AccEnt <'`',43,28,43,0,43,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <'~',53,0,0,0,53,'n',0A4h,'N',0A5h,' ','~'>
+
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2FR437111
+
+
+;******************************************************************************
+
+Public _Ow2FR850000 ;***************
+_Ow2FR850000 Label Byte ;Beginning of the table. FR 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,0,1,0,1,1,0,1,AT,Len4,'FR','189'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '&', '1', 0, 0, 0 ; 2 & 1
+ KeyDef 4, 0,0,0,0,0,0,0, 82h, '2', '@', 0, 0 ; 3 82h 2
+ KeyDef 4, 0,0,0,0,0,0,0, '"', '3', '#', 0, 0 ; 4 " 3
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '4', 0, 0, 0 ; 5 ' 4
+ KeyDef 4, 0,0,0,0,0,0,0, '(', '5', 0, 0, 0 ; 6 ( 5
+ KeyDef 4, 0,0,0,0,0,0,0, 0F5h, '6', '^', 0, 0 ; 7 F5h 6
+ KeyDef 4, 0,0,0,0,0,0,0, 8Ah, '7', 0, 0, 0 ; 8 8Ah 7
+ KeyDef 4, 0,0,0,0,0,0,0, '!', '8', 0, 0, 0 ; 9 ! 8
+ KeyDef 4, 0,0,0,0,0,0,0, 87h, '9', 0, 0, 0 ; 10 87h 9
+ KeyDef 4, 0,0,0,0,0,0,0, 85h, '0', 0, 0, 0 ; 11 85h 0
+ KeyDef 4, 0,0,0,0,0,0,0, ')',0F8h, 0, 0, 0 ; 12 ) F8h
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 13 - _
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 1,1,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 16 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 17 z Z
+ KeyDef 1, 1,1,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, '[', 0, 1 ; 26 ^ umlaut
+ KeyDef 4, 0,0,0,0,0,0,0, '$', '*', ']', 0, 0 ; 27 $ *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 30 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 39 m M
+ KeyDef 4, 0,0,0,0,0,0,0, 97h, '%', 0, 0, 0 ; 40 97h %
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, 0E6h, 9Ch, 0, 0, 0 ; 43 E6h 9Ch
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 44 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 2, 0,0,0,0,0,0,0, ',', '?', 0, 0, 0 ; 50 , ?
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '.', 0, 0, 0 ; 51 ; .
+ KeyDef 4, 0,0,0,0,0,0,0, ':', '/', 0, 0, 0 ; 52 : /
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 53 = +
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'^',26,27,26,0,26,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <0F9h,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2FR850000
+
+;******************************************************************************
+
+Public _Ow2FR850010 ;***************
+_Ow2FR850010 Label Byte ;Beginning of the table. FR 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,1,0,0,1,0,1,EN,Len5,'FR','189'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '&', '1', 0, 0, 0 ; 2 & 1
+ KeyDef 3, 0,0,1,0,0,0,0, 82h, '2', 3, 0, 3 ; 3 82h 2
+ KeyDef 4, 0,0,0,0,0,0,0, '"', '3', '#', 0, 0 ; 4 " 3
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '4', '{', 0, 0 ; 5 ' 4
+ KeyDef 4, 0,0,0,0,0,0,0, '(', '5', '[', 0, 0 ; 6 ( 5
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '6',07Ch, 0, 0 ; 7 - 6
+ KeyDef 3, 0,0,0,1,0,0,0, 8Ah, '7', 4, 0, 4 ; 8 8Ah 7
+ KeyDef 4, 0,0,0,0,0,0,0, '_', '8', '\', 0, 0 ; 9 _ 8
+ KeyDef 4, 0,0,0,0,0,0,0, 87h, '9', '^', 0, 0 ; 10 87h 9
+ KeyDef 4, 0,0,0,0,0,0,0, 85h, '0', '@', 0, 0 ; 11 85h 0
+ KeyDef 4, 0,0,0,0,0,0,0, ')', 'ø', ']', 0, 0 ; 12 ) ø
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', '}', 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 16 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 17 z Z
+ KeyDef 1, 1,1,0,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,0,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,0,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, 0, 0, 1 ; 26 ^ diaresis
+ KeyDef 4, 0,0,0,0,0,0,0, '$', 'œ',0CFh, 0, 0 ; 27 $ œ
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 30 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 39 m M
+ KeyDef 4, 0,0,0,0,0,0,0, 097h, '%', 0, 0, 0 ; 40 u-grave %
+ KeyDef 4, 0,0,0,0,0,0,0, 0FDh, 0, 0, 0, 0 ; 41 FDh FCh
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '*',0E6h, 0, 0, 0 ; 43 * micro
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 44 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,1,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 2, 0,0,0,0,0,0,0, ',', '?', 0, 0, 0 ; 50 , ?
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '.', 0, 0, 0 ; 51 ; .
+ KeyDef 4, 0,0,0,0,0,0,0, ':', '/', 0, 0, 0 ; 52 : /
+ KeyDef 4, 0,0,0,0,0,0,0, '!',0F5h, 0, 0, 0 ; 53 ! F5h
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'^',26,27,26,0,26,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <0F9h,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <'~',53,0,0,0,53,'a',0C6h,'o',0E4h,'n',0A4h,'A',0C7h,'O',0E5h,'N',0A5h,' ','~'>
+AccEnt <'`',43,28,43,0,43,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len5 EQU $ - _Ow2FR850010
+
+;******************************************************************************
+
+Public _Ow2FR850011 ;*************************
+_Ow2FR850011 Label Byte ;Beginning of the table. FR 850 EN Kbd New Std
+ ;*************************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,1,0,0,1,0,1,EN,Len6,'FR','120'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '&', '1', 7Ch, 0, 0 ; 2 & 1
+ KeyDef 4, 0,0,0,0,0,0,0, 82h, '2', '@', 0, 0 ; 3 82h 2
+ KeyDef 4, 0,0,0,0,0,0,0, '"', '3', '#', 0, 0 ; 4 " 3
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '4', 0, 0, 0 ; 5 ' 4
+ KeyDef 4, 0,0,0,0,0,0,0, '(', '5', 0, 0, 0 ; 6 ( 5
+ KeyDef 4, 0,0,0,0,0,0,0, 0F5h, '6', '^', 0, 0 ; 7  6
+ KeyDef 4, 0,0,0,0,0,0,0, 8Ah, '7', 0, 0, 0 ; 8 8Ah 7
+ KeyDef 4, 0,0,0,0,0,0,0, '!', '8', 0, 0, 0 ; 9 _ 8
+ KeyDef 4, 0,0,0,0,0,0,0, 87h, '9', '{', 0, 0 ; 10 87h 9
+ KeyDef 4, 0,0,0,0,0,0,0, 85h, '0', '}', 0, 0 ; 11 85h 0
+ KeyDef 4, 0,0,0,0,0,0,0, ')', 'ø', 0, 0, 0 ; 12 ) ø
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 13 - _
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 1,1,1,1,1,0,0, 'a', 'A', 0, 0, 0 ; 16 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 17 z Z
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,1,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, '[', 0, 1 ; 26 ^ diaresis
+ KeyDef 4, 0,0,0,0,0,0,0, '$', '*', ']', 0, 0 ; 27 $ *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 30 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 39 m M
+ KeyDef 11, 0,0,0,0,0,0,0, 97h, '%', 3, 0, 3 ; 40 u-grave %
+ KeyDef 4, 0,0,0,0,0,0,0, 0FDh,0FCh, 0, 0, 0 ; 41 ý ü
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 11, 0,0,0,0,0,0,0, 0E6h, 9Ch, 4, 0, 4 ; 43 micro œ
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 44 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,1,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 2, 0,0,0,0,0,0,0, ',', '?', 0, 0, 0 ; 50 , ?
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '.', 0, 0, 0 ; 51 ; .
+ KeyDef 4, 0,0,0,0,0,0,0, ':', '/', 0, 0, 0 ; 52 : /
+ KeyDef 11, 0,0,0,0,0,0,0, '=', '+', 5, 0, 5 ; 53 = +
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'^',26,27,26,0,26,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <0F9h,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <0EFh,40,0,0,0,40,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'A',0B5h,'E',90h,'I',0D6h,'O',0E0h,'U',0E9h,'y',0ECh,'Y',0EDh,' ',0EFh>
+
+AccEnt <'`',43,28,43,0,43,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <'~',53,0,0,0,53,'a',0C6h,'o',0E4h,'n',0A4h,'A',0C7h,'O',0E5h,'N',0A5h,' ','~'>
+
+AccEnt <>
+AccEnt <>
+
+Len6 EQU $ - _Ow2FR850011
+
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/grkbd.asm b/private/os2/os2ses/i386/grkbd.asm
new file mode 100644
index 000000000..eb4101961
--- /dev/null
+++ b/private/os2/os2ses/i386/grkbd.asm
@@ -0,0 +1,768 @@
+;; SCCSID = @(#)grkbd.asm 12.1 88/03/18
+ Page 58,132
+ Title GRKBD - Translate Table Structure for CP/DOS 1.1
+ Name GRKBD
+
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: GRKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for Germany *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK GRKBD; **
+;** RELOC GRKBD.EXE GRKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-.286
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ db 7,8,9,-1
+ db 4,5,6,-1
+
+Public _Ow2GR437001 ;***************
+_Ow2GR437001 Label Byte ;Beginning of the table. GR 437 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,0,1,0,1,0,0,AT,Len1,'GR','129'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 15h, 0, 0, 0 ; 4 3 15h
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 0, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, 0E1h, '?', 0, 0, 0 ; 12 E1h ?
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, 0, 0, 1 ; 13 (accents)
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 21 z Z
+ KeyDef 1, 1,1,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 81h, 9Ah, '[', 0, 0 ; 26 81h 9Ah
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '*', ']', 0, 0 ; 27 + *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 94h, 99h, 0, 0, 0 ; 39 94h 99h
+ KeyDef 3, 0,0,0,0,0,0,0, 84h, 8Eh, 0, 0, 0 ; 40 84h 8Eh
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '#', '^', 0, 0, 0 ; 43 # *
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 44 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtS
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLoc
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pa
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pa
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefine
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefine
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",13,0,0,0,131,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h,' ',"'">
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2GR437001
+
+;******************************************************************************
+
+Public _Ow2GR437011 ;***************
+_Ow2GR437011 Label Byte ;Beginning of the table. GR 437 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,1,1,0,1,0,0,EN,Len2,'GR','129'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"',0FDh, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 15h,0FCh, 0, 0 ; 4 3 15h
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '{', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '[', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', ']', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', '}', 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, 0E1h, '?', '\', 0, 0 ; 12 1Eh ?
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, 0, 0, 1 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', '@', 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 21 z Z
+ KeyDef 1, 1,1,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 81h, 9Ah, 0, 0, 0 ; 26 u U (diaresis)
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '*', '~', 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 94h, 99h, 0, 0, 0 ; 39 o O (diaresis)
+ KeyDef 3, 0,0,0,0,0,0,0, 84h, 8Eh, 0, 0, 0 ; 40 a A (diaresis)
+ KeyDef 4, 0,0,0,0,0,0,0, '^',0F8h, 0, 0, 0 ; 41 ^ F8h
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '#', "'", 0, 0, 0 ; 43 # '
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 44 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M',0E6h, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del ,
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', '|', 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",13,0,0,0,131,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h,' ',"'">
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2GR437011
+
+;******************************************************************************
+
+Public _Ow2GR850000 ;***************
+_Ow2GR850000 Label Byte ;Beginning of the table. GR 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,0,0,0,0,1,0,0,AT,Len3,'GR','129'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3',0F5h, 0, 0, 0 ; 4 3 F5h
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 0, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, 0E1h, '?', 0, 0, 0 ; 12 E1h ?
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, 0, 0, 1 ; 13 (accents)
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 21 z Z
+ KeyDef 1, 1,1,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 81h, 9Ah, '[', 0, 0 ; 26 81h 9Ah
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '*', ']', 0, 0 ; 27 + *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 94h, 99h, 0, 0, 0 ; 39 94h 99h
+ KeyDef 3, 0,0,0,0,0,0,0, 84h, 8Eh, 0, 0, 0 ; 40 84h 8Eh
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '#', '^', 0, 0, 0 ; 43 # ^
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 44 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtS
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLoc
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pa
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pa
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefine
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefine
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <0EFh,13,0,0,0,131,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'A',0B5h,'E',90h,'I',0D6h,'O',0E0h,'U',0E9h,' ',0EFh>
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2GR850000
+
+;******************************************************************************
+
+Public _Ow2GR850010 ;***************
+_Ow2GR850010 Label Byte ;Beginning of the table. GR 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,1,0,0,1,0,0,EN,Len4,'GR','129'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"',0FDh, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3',0F5h,0FCh, 0, 0 ; 4 3 F5h
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '{', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '[', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', ']', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', '}', 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, 0E1h, '?', '\', 0, 0 ; 12 1Eh ?
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, 0, 0, 1 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', '@', 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 21 z Z
+ KeyDef 1, 1,1,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 81h, 9Ah, 0, 0, 0 ; 26 u U (diaresis)
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '*', '~', 0, 0 ; 27 + *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 94h, 99h, 0, 0, 0 ; 39 o O (diaresis)
+ KeyDef 3, 0,0,0,0,0,0,0, 84h, 8Eh, 0, 0, 0 ; 40 a A (diaresis)
+ KeyDef 4, 0,0,0,0,0,0,0, '^',0F8h, 0, 0, 0 ; 41 ^ F8h
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '#', "'", 0, 0, 0 ; 43 # '
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 44 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M',0E6h, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del ,
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', '|', 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <0EFh,13,0,0,0,131,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'A',0B5h,'E',90h,'I',0D6h,'O',0E0h,'U',0E9h,' ',0EFh>
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2GR850010
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/itkbd.asm b/private/os2/os2ses/i386/itkbd.asm
new file mode 100644
index 000000000..3d77bb37e
--- /dev/null
+++ b/private/os2/os2ses/i386/itkbd.asm
@@ -0,0 +1,1127 @@
+; SCCSID = @(#)itkbd.asm 12.1 88/03/18
+ Page 58,132
+ Title ITKBD - Translate Table Structure for CP/DOS 1.1
+ Name ITKBD
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: ITKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for Italy *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;* Changes: *
+;* *
+;* wak (10/9/87) - corrected EN,850,141 && PTM 802 *
+;* lt (10/9/87) - changed decimal point to comma on DEL key *
+;* for 142 layout && PTM 883 *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK ITKBD; **
+;** RELOC ITKBD.EXE ITKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-.286
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ db 4,5,6,-1
+ db 1,2,3
+
+Public _Ow2IT437001 ;***************
+_Ow2IT437001 Label Byte ;Beginning of the table. IT 437 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,0,1,0,0,0,1,AT,Len1,'IT','141'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, 0, 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 0, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '?', 0, 0, 0 ; 12 ' ?
+ KeyDef 4, 0,0,0,0,0,0,0, 8Dh, '^', 0, 0, 0 ; 13 8Dh ^
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, 8Ah, 82h, '[', 0, 0 ; 26 8Ah 82h
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '*', ']', 0, 0 ; 27 + *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, 95h, '@', 0, 0, 0 ; 39 95h @
+ KeyDef 4, 0,0,0,0,0,0,0, 85h, '#', 0, 0, 0 ; 40 85h #
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, 97h, 15h, 0, 0, 0 ; 43 97h 15h
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2IT437001
+
+;****************************************************************************
+
+Public _Ow2IT437011 ;***************
+_Ow2IT437011 Label Byte ;Beginning of the table. IT 437 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,0,1,0,0,0,1,EN,Len2,'IT','141'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, 0, 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 0, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '?', 0, 0, 0 ; 12 ' ?
+ KeyDef 4, 0,0,0,0,0,0,0, 8Dh, '^', 0, 0, 0 ; 13 8Dh ^
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, 8Ah, 82h, '[', 0, 0 ; 26 8Ah 82h
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '*', ']', 0, 0 ; 27 + *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, 95h, 87h, '@', 0, 0 ; 39 95h 87h
+ KeyDef 4, 0,0,0,0,0,0,0, 85h,0F8h, '#', 0, 0 ; 40 85h F8h
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 41 \ |
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, 97h, 15h, 0, 0, 0 ; 43 97h 15h
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2IT437011
+
+
+;****************************************************************************
+
+Public _Ow2IT437111 ;***********************
+_Ow2IT437111 Label Byte ;Beginning of the table. IT 437 EN Kbd New Std
+ ;***********************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,0,1,0,0,0,1,EN,Len3,'IT','142'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, '#', 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '{', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '[', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', ']', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', '}', 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '?', 0, 0, 0 ; 12 ' ?
+ KeyDef 4, 0,0,0,0,0,0,0, 8Dh, '^', 0, 0, 0 ; 13 8Dh ^
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', '@', 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, 8Ah, 82h, 0, 0, 0 ; 26 8Ah 82h
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '*', '~', 0, 0 ; 27 + *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, 95h, 87h, 0, 0, 0 ; 39 95h 87h
+ KeyDef 4, 0,0,0,0,0,0,0, 85h,0F8h, 0, 0, 0 ; 40 85h F8h
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 41 \ |
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, 97h, 15h, "`", 0, 0 ; 43 97h 15h
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <> ; Grave accent (see scan code 43)
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2IT437111
+
+
+;****************************************************************************
+
+Public _Ow2IT850000 ;***************
+_Ow2IT850000 Label Byte ;Beginning of the table. IT 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,0,0,0,0,0,0,1,AT,Len4,'IT','141'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, 0, 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 0, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '?', 0, 0, 0 ; 12 ' ?
+ KeyDef 4, 0,0,0,0,0,0,0, 8Dh, '^', 0, 0, 0 ; 13 8Dh ^
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, 8Ah, 82h, '[', 0, 0 ; 26 8Ah 82h
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '*', ']', 0, 0 ; 27 + *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, 95h, '@', 0, 0, 0 ; 39 95h @
+ KeyDef 4, 0,0,0,0,0,0,0, 85h, '#', 0, 0, 0 ; 40 85h #
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, 97h,0F5h, 0, 0, 0 ; 43 97h F5h
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2IT850000
+
+;****************************************************************************
+
+Public _Ow2IT850010 ;***************
+_Ow2IT850010 Label Byte ;Beginning of the table. IT 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,0,0,1,EN,Len5,'IT','141'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, 0, 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 0, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '?', 0, 0, 0 ; 12 ' ?
+ KeyDef 4, 0,0,0,0,0,0,0, 8Dh, '^', 0, 0, 0 ; 13 8Dh ^
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, 8Ah, 82h, '[', 0, 0 ; 26 8Ah 82h
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '*', ']', 0, 0 ; 27 + *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, 95h, 87h, '@', 0, 0 ; 39 95h 87h
+ KeyDef 4, 0,0,0,0,0,0,0, 85h,0F8h, '#', 0, 0 ; 40 85h F8h
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 41 \ |
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, 97h,0F5h, 0, 0, 0 ; 43 97h F5h
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <> ; Grave accent (see scan code 43)
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len5 EQU $ - _Ow2IT850010
+
+
+;****************************************************************************
+
+Public _Ow2IT850011 ;***********************
+_Ow2IT850011 Label Byte ;Beginning of the table. IT 850 EN Kbd New Std
+ ;***********************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,0,0,1,EN,Len6,'IT','142'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, '#', 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '{', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '[', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', ']', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', '}', 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '?', 0, 0, 0 ; 12 ' ?
+ KeyDef 4, 0,0,0,0,0,0,0, 8Dh, '^', 0, 0, 0 ; 13 8Dh ^
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', '@', 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, 8Ah, 82h, 0, 0, 0 ; 26 8Ah 82h
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '*', '~', 0, 0 ; 27 + *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, 95h, 87h, 0, 0, 0 ; 39 95h 87h
+ KeyDef 4, 0,0,0,0,0,0,0, 85h,0F8h, 0, 0, 0 ; 40 85h F8h
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 41 \ |
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, 97h,0F5h, "`", 0, 0 ; 43 97h F5h
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len6 EQU $ - _Ow2IT850011
+
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/jpkbd.asm b/private/os2/os2ses/i386/jpkbd.asm
new file mode 100644
index 000000000..a5e54c118
--- /dev/null
+++ b/private/os2/os2ses/i386/jpkbd.asm
@@ -0,0 +1,1482 @@
+;; SCCSID = @(#)jpkbd.asm 5.3 88/08/03
+; Page 58,132
+
+; Feb.28 : KazuM
+; MS OS/2-J BAK Final version
+
+ Title JPKBD - Translate Table Structure for OS/2 1.1
+ Name JPKBD
+
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: JPKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for Japan. *
+;* *
+;* Status: OS/2 Version 1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;* Changes: *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK JPKBD; **
+;** RELOC JPKBD.EXE JPKBD.TBL **
+;** **
+;***********************************************************************
+
+ifdef JAPAN
+.386p ; V-AkihiS
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+Public _Ow2JP932011AX ;******
+_Ow2JP932011AX Label Byte ;Begging of the table. JP 932 AX Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+; cp a b c d e f g h i kb l cc cs oem id oem key
+; | | | | | | | | | | | | | | | |
+XtHeader 932,0,0,0,0,1,0,0,0,0,JP_OEM,Len1,'JP','103'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 27, 27 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 'Ç', 'Ç' ; 2 1 ! Ç
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '@', 0, 'Ì', 'Ì' ; 3 2 @ Ì
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, '±', '§' ; 4 3 # ± §
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, '³', '©' ; 5 4 $ ³ ©
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, '´', 'ª' ; 6 5 % ´ ª
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 'µ', '«' ; 7 6 ^ µ «
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 'Ô', '¬' ; 8 7 & Ô ¬
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 'Õ', '­' ; 9 8 * Õ ­
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 'Ö', '®' ; 10 9 ( Ö ®
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 'Ü', '¦' ; 11 0 ) Ü ¦
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 'Î', 'Î' ; 12 - _ Î
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 'Í', 'Í' ; 13 = + Í
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 8, 127 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 9, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 'À', 'À' ; 16 q Q À
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 'Ã', 'Ã' ; 17 w W Ã
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, '²', '¨' ; 18 e E ² ¨
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, '½', '½' ; 19 r R ½
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, '¶', '¶' ; 20 t T ¶
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 'Ý', 'Ý' ; 21 y Y Ý
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 'Å', 'Å' ; 22 u U Å
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 'Æ', 'Æ' ; 23 i I Æ
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, '×', '×' ; 24 o O ×
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, '¾', '¾' ; 25 p P ¾
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 'Þ', 'Þ' ; 26 [ { Þ
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 'ß', '¢' ; 27 ] } ß ¢
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 13, 10 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 'Á', 'Á' ; 30 a A Á
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 'Ä', 'Ä' ; 31 s S Ä
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, '¼', '¼' ; 32 d D ¼
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 'Ê', 'Ê' ; 33 f F Ê
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, '·', '·' ; 34 g G ·
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, '¸', '¸' ; 35 h H ¸
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 'Ï', 'Ï' ; 36 j J Ï
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 'É', 'É' ; 37 k K É
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 'Ø', 'Ø' ; 38 l L Ø
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 'Ú', 'Ú' ; 39 ; : Ú
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, '¹', '¹' ; 40 ' " ¹
+ KeyDef 4, 0,0,0,0,0,0,0, '`', '~', 0, 'Ñ', '£' ; 41 ` ~ Ñ £
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, '°', '°' ; 43 \ | °
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 'Â', '¯' ; 44 z Z Â ¯
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, '»', '»' ; 45 x X »
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, '¿', '¿' ; 46 c C ¿
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 'Ë', 'Ë' ; 47 v V Ë
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 'º', 'º' ; 48 b B º
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 'Ð', 'Ð' ; 49 n N Ð
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 'Ó', 'Ó' ; 50 m M Ó
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 'È', '¤' ; 51 , < È
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 'Ù', '¡' ; 52 . > Ù ¡
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 'Ò', '¥' ; 53 / ? Ò ¥
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, ' ', ' ' ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 'Û', 'Û' ; 86 \ | Û
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 21, 0,0,0,0,0,0,0, 0abh,0ach,0adh,0aeh, 0 ; 90 mu-henkan (3xBox)
+ KeyDef 21, 0,0,0,0,0,0,0, 0a7h,0a8h,0a9h,0aah, 0 ; 91 henkan (3xBox)
+ KeyDef 21, 0,0,0,0,0,0,0, 0d2h,0d3h,0d4h,0d5h, 0 ; 92 ax (3xBox)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 ax (ProtMode)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 18, 0,0,0,0,0,0,0, 80h, 01h, 0, 0, 0 ; 104 Kanji Shift
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 19, 0,0,0,0,0,0,0, 02h, 04h, 40h, 02h, 0 ; 112 Kana Shift
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 20, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 115 \ | Kana RO
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 21, 0,0,0,0,0,0,0, 0a7h,0a8h,0a9h,0aah, 0 ; 121 henkan
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 (undefined)
+ KeyDef 21, 0,0,0,0,0,0,0, 0abh,0ach,0adh,0aeh, 0 ; 123 mu-henkan
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 (undefined)
+ KeyDef 21, 0,0,0,0,0,0,0, 03ah,03ah, 0, 0, 0 ; 125 3xBox Kanji
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2JP932011AX
+
+;******************************************************************************
+
+Public _Ow2JP437011AX ;******
+_Ow2JP437011AX Label Byte ;Beginning of the table. JP 437 AX Kbd
+ ;***************
+
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+; cp a b c d e f g h i kb l cc cs oem id oem key
+; | | | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,0,1,0,0,0,0,JP_OEM,Len2,'JP','103'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '@', 0, 0, 0 ; 3 2 @
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, 0, 0 ; 40 ' "
+ KeyDef 4, 0,0,0,0,0,0,0, '`', '~', 0, 0, 0 ; 41 ` ~
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 43 \ |
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 86 \ | (3xBox)
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 ax (3xBox)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 ax (ProtMode)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 18, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 Kanji Shift
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 19, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 Kana Shift
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 115 \ | Kana RO
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 121 Space (Xfer)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 (undefined)
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 123 Space (Nfer)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 (undefined)
+ KeyDef 21, 0,0,0,0,0,0,0, 03ah,03ah, 0, 0, 0 ; 125 3xBox Kanji
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2JP437011AX
+
+;*****************************************************************************
+
+
+Public _Ow2JP932011IBM101 ;******
+_Ow2JP932011IBM101 Label Byte ;Begging of the table. JP 932 101 Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+; cp a b c d e f g h i kb l cc cs oem id oem key
+; | | | | | | | | | | | | | | | |
+XtHeader 932,0,0,0,0,1,0,0,0,0,JP_OEM,Len3,'JP','103'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 27, 27 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 'Ç', 'Ç' ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '@', 0, 'Ì', 'Ì' ; 3 2 @
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, '±', '§' ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, '³', '©' ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, '´', 'ª' ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 'µ', '«' ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 'Ô', '¬' ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 'Õ', '­' ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 'Ö', '®' ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 'Ü', '¦' ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 'Î', 'Î' ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 'Í', 'Í' ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 8, 127 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 9, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 'À', 'À' ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 'Ã', 'Ã' ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, '²', '¨' ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, '½', '½' ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, '¶', '¶' ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 'Ý', 'Ý' ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 'Å', 'Å' ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 'Æ', 'Æ' ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, '×', '×' ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, '¾', '¾' ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 'Þ', 'Þ' ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 'ß', '¢' ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 13, 10 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 'Á', 'Á' ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 'Ä', 'Ä' ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, '¼', '¼' ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 'Ê', 'Ê' ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, '·', '·' ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, '¸', '¸' ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 'Ï', 'Ï' ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 'É', 'É' ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 'Ø', 'Ø' ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 'Ú', 'Ú' ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, '¹', '¹' ; 40 ' "
+ KeyDef 4, 0,0,0,0,0,0,0, '`', '~', 0, 'Ñ', '£' ; 41 ` ~
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, '°', '°' ; 43 \ |
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 'Â', '¯' ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, '»', '»' ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, '¿', '¿' ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 'Ë', 'Ë' ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 'º', 'º' ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 'Ð', 'Ð' ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 'Ó', 'Ó' ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 'È', '¤' ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 'Ù', '¡' ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 'Ò', '¥' ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, ' ', ' ' ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2JP932011IBM101
+
+;*****************************************************************************
+
+
+Public _Ow2JP437011IBM101 ;******
+_Ow2JP437011IBM101 Label Byte ;Beginning of the table. JP 437 101 Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+; cp a b c d e f g h i kb l cc cs oem id oem key
+; | | | | | | | | | | | | | | | |
+XtHeader 932,0,0,0,0,1,0,0,0,0,JP_OEM,Len4,'JP','103'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '@', 0, 0, 0 ; 3 2 @
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, 0, 0 ; 40 ' "
+ KeyDef 4, 0,0,0,0,0,0,0, '`', '~', 0, 0, 0 ; 41 ` ~
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 43 \ |
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2JP437011IBM101
+
+;*****************************************************************************
+
+
+Public _Ow2JP932011IBM002 ;******
+_Ow2JP932011IBM002 Label Byte ;Begging of the table. JP 932 IBM02 Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+; cp a b c d e f g h i kb l cc cs oem id oem key
+; | | | | | | | | | | | | | | | |
+XtHeader 932,0,0,0,0,1,0,0,0,0,JP_OEM,Len5,'JP','103'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 27, 27 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 'Ç', 'Ç' ; 2 1 ! Ç
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 'Ì', 'Ì' ; 3 2 " Ì
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, '±', '§' ; 4 3 # ± §
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, '³', '©' ; 5 4 $ ³ ©
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, '´', 'ª' ; 6 5 % ´ ª
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 'µ', '«' ; 7 6 & µ «
+ KeyDef 4, 0,0,0,0,0,0,0, '7', "'", 0, 'Ô', '¬' ; 8 7 ' Ô ¬
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 'Õ', '­' ; 9 8 ( Õ ­
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 'Ö', '®' ; 10 9 ) Ö ®
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '~', 0, 'Ü', '¦' ; 11 0 ~ Ü ¦
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '=', 0, 'Î', 'Î' ; 12 - = Î
+ KeyDef 4, 0,0,0,0,0,0,0, '^', '_', 0, 'Í', 'Í' ; 13 ^ _ Í
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 8, 127 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 9, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 'À', 'À' ; 16 q Q À
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 'Ã', 'Ã' ; 17 w W Ã
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, '²', '¨' ; 18 e E ² ¨
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, '½', '½' ; 19 r R ½
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, '¶', '¶' ; 20 t T ¶
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 'Ý', 'Ý' ; 21 y Y Ý
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 'Å', 'Å' ; 22 u U Å
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 'Æ', 'Æ' ; 23 i I Æ
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, '×', '×' ; 24 o O ×
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, '¾', '¾' ; 25 p P ¾
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 'ß', '¢' ; 26 [ { ß ¢
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 'Ñ', '£' ; 27 ] } Ñ £
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 13, 10 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 'Á', 'Á' ; 30 a A Á
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 'Ä', 'Ä' ; 31 s S Ä
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, '¼', '¼' ; 32 d D ¼
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 'Ê', 'Ê' ; 33 f F Ê
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, '·', '·' ; 34 g G ·
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, '¸', '¸' ; 35 h H ¸
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 'Ï', 'Ï' ; 36 j J Ï
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 'É', 'É' ; 37 k K É
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 'Ø', 'Ø' ; 38 l L Ø
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '+', 0, 'Ú', 'Ú' ; 39 ; + Ú
+ KeyDef 4, 0,0,0,0,0,0,0, ":", '*', 0, '¹', '¹' ; 40 : * ¹
+ KeyDef 4, 0,0,0,0,0,0,0, '@', '`', 0, 'Þ', 'Þ' ; 41 @ ` Þ
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, '°', '°' ; 43 \ | °
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 'Â', '¯' ; 44 z Z Â ¯
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, '»', '»' ; 45 x X »
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, '¿', '¿' ; 46 c C ¿
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 'Ë', 'Ë' ; 47 v V Ë
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 'º', 'º' ; 48 b B º
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 'Ð', 'Ð' ; 49 n N Ð
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 'Ó', 'Ó' ; 50 m M Ó
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 'È', '¤' ; 51 , < È
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 'Ù', '¡' ; 52 . > Ù ¡
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 'Ò', '¥' ; 53 / ? Ò ¥
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, ' ', ' ' ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '_', 0, 'Û', 'Û' ; 115 \ _ Û
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len5 EQU $ - _Ow2JP932011IBM002
+
+;*****************************************************************************
+
+Public _Ow2JP437011IBM002 ;******
+_Ow2JP437011IBM002 Label Byte ;Begging of the table. JP 437 IBM02 Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+; cp a b c d e f g h i kb l cc cs oem id oem key
+; | | | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,0,1,0,0,0,0,JP_OEM,Len6,'JP','103'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', "'", 0, 0, 0 ; 8 7 '
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '~', 0, 0, 0 ; 11 0 ~
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '=', 0, 0, 0 ; 12 - =
+ KeyDef 4, 0,0,0,0,0,0,0, '^', '_', 0, 0, 0 ; 13 ^ _
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 9, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '+', 0, 0, 0 ; 39 ; +
+ KeyDef 4, 0,0,0,0,0,0,0, ":", '*', 0, 0, 0 ; 40 : *
+ KeyDef 4, 0,0,0,0,0,0,0, '@', '`', 0, 0, 0 ; 41 @ `
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 43 \ |
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '_', 0, 0, 0 ; 115 \ _
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len6 EQU $ - _Ow2JP437011IBM002
+
+;*****************************************************************************
+
+Public _Ow2JP932011IBMA01 ;******
+_Ow2JP932011IBMA01 Label Byte ;Begging of the table. JP 932 106 Kbd
+ ;****************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+; cp a b c d e f g h i kb l cc cs oem id oem key
+; | | | | | | | | | | | | | | | |
+XtHeader 932,0,0,0,0,1,0,0,0,0,JP_OEM,Len7,'JP','103'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 27, 27 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 'Ç', 'Ç' ; 2 1 ! Ç
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 'Ì', 'Ì' ; 3 2 " Ì
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, '±', '§' ; 4 3 # ± §
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, '³', '©' ; 5 4 $ ³ ©
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, '´', 'ª' ; 6 5 % ´ ª
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 'µ', '«' ; 7 6 & µ «
+ KeyDef 4, 0,0,0,0,0,0,0, '7', "'", 0, 'Ô', '¬' ; 8 7 ' Ô ¬
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 'Õ', '­' ; 9 8 ( Õ ­
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 'Ö', '®' ; 10 9 ) Ö ®
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '~', 0, 'Ü', '¦' ; 11 0 ~ Ü ¦
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '=', 0, 'Î', 'Î' ; 12 - = Î
+ KeyDef 4, 0,0,0,0,0,0,0, '^', '_', 0, 'Í', 'Í' ; 13 ^ _ Í
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 8, 127 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 9, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 'À', 'À' ; 16 q Q À
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 'Ã', 'Ã' ; 17 w W Ã
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, '²', '¨' ; 18 e E ² ¨
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, '½', '½' ; 19 r R ½
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, '¶', '¶' ; 20 t T ¶
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 'Ý', 'Ý' ; 21 y Y Ý
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 'Å', 'Å' ; 22 u U Å
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 'Æ', 'Æ' ; 23 i I Æ
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, '×', '×' ; 24 o O ×
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, '¾', '¾' ; 25 p P ¾
+ KeyDef 4, 0,0,0,0,0,0,0, '@', '`', 0, 'Þ', 'Þ' ; 26 @ ` Þ
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 'ß', '¢' ; 27 [ { ß ¢
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 13, 10 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 'Á', 'Á' ; 30 a A Á
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 'Ä', 'Ä' ; 31 s S Ä
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, '¼', '¼' ; 32 d D ¼
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 'Ê', 'Ê' ; 33 f F Ê
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, '·', '·' ; 34 g G ·
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, '¸', '¸' ; 35 h H ¸
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 'Ï', 'Ï' ; 36 j J Ï
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 'É', 'É' ; 37 k K É
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 'Ø', 'Ø' ; 38 l L Ø
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '+', 0, 'Ú', 'Ú' ; 39 ; + Ú
+ KeyDef 4, 0,0,0,0,0,0,0, ":", '*', 0, '¹', '¹' ; 40 : * ¹
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 41 (undefined)
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 'Ñ', '£' ; 43 ] } Ñ £
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 'Â', '¯' ; 44 z Z Â ¯
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, '»', '»' ; 45 x X »
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, '¿', '¿' ; 46 c C ¿
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 'Ë', 'Ë' ; 47 v V Ë
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 'º', 'º' ; 48 b B º
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 'Ð', 'Ð' ; 49 n N Ð
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 'Ó', 'Ó' ; 50 m M Ó
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 'È', '¤' ; 51 , < È
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 'Ù', '¡' ; 52 . > Ù ¡
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 'Ò', '¥' ; 53 / ? Ò ¥
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, ' ', ' ' ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '_', 0, 'Û', 'Û' ; 115 \ _ Û
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, '°', '°' ; 125 \ | °
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len7 EQU $ - _Ow2JP932011IBMA01
+
+;*****************************************************************************
+
+Public _Ow2JP437011IBMA01 ;******
+_Ow2JP437011IBMA01 Label Byte ;Begging of the table. JP 437 106 Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+; cp a b c d e f g h i kb l cc cs oem id oem key
+; | | | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,0,1,0,0,0,0,JP_OEM,Len8,'JP','103'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', "'", 0, 0, 0 ; 8 7 '
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '~', 0, 0, 0 ; 11 0 ~
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '=', 0, 0, 0 ; 12 - =
+ KeyDef 4, 0,0,0,0,0,0,0, '^', '_', 0, 0, 0 ; 13 ^ _
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 9, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '@', '`', 0, 0, 0 ; 26 @ `
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 27 [ {
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '+', 0, 0, 0 ; 39 ; +
+ KeyDef 4, 0,0,0,0,0,0,0, ":", '*', 0, 0, 0 ; 40 : *
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 41 (undefined)
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 43 ] }
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '_', 0, 0, 0 ; 115 \ _
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 125 \ |
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len8 EQU $ - _Ow2JP437011IBMA01
+
+_TEXT ends
+endif
+ END
diff --git a/private/os2/os2ses/i386/kbdxlat.asm b/private/os2/os2ses/i386/kbdxlat.asm
new file mode 100644
index 000000000..5f282b9be
--- /dev/null
+++ b/private/os2/os2ses/i386/kbdxlat.asm
@@ -0,0 +1,2470 @@
+; SCCSID = @(#)kbdxlat.asm 12.21 89/07/25
+;OS2SS- Page 58,132
+
+;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+;$$
+;$$ Module: kbdxlat.asm Version: 1.2 ABIOS
+;$$
+;$$ History: This module was derived from the 1.2 AT source code.
+;$$ ABIOS changes were made according to the deltas between
+;$$ the 1.1 ABIOS and 1.1 AT drivers. The 1.1 ABIOS driver
+;$$ was done by John Nels Fuller (Wyse). The 1.2 ABIOS
+;$$ driver was done by Alan J. Cotterman (NCR).
+;$$
+;$$ Notes: Wherever possible the original 1.2 AT code is preserved.
+;$$ All changes are marked with ";$$".
+;$$
+;$$ The only modification to this module is in testing for
+;$$ keyboard type. References to "IDFlags" have been
+;$$ replaced with tests of the contents of "KbdHWIDs".
+;$$
+;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+
+ Title KBDXLAT - Translation Process
+ Name KBDXLAT
+;***********************************************************************
+;** **
+;** Keyboard Device Driver Scan Code Translation **
+;** **
+;** **
+;** This file contains the scan code to character translation process **
+;** code. The code in this file is only called once by KBDDD and is **
+;** not accessed by anyone else. So the entire translation process **
+;** can be replaced by replacing the routine in this file. The data **
+;** that is only used by the code in this file is in the file **
+;** KBDXDATA.ASM and it too would be replaced if this code is to be **
+;** replaced. **
+;** **
+;** 6/22/93 MJarus line with os2ss were modified by os2ss. **
+;***********************************************************************
+.386p ;OS2SS-.286
+.sall
+.xcref
+;@@ The following files are included, but xlist'd out:
+
+.xlist
+ Include struc.inc ;Structured assembly macros.
+ Include kbddd.inc ;Keyboard Device Driver structures & equates.
+ Include kbdxlat.inc ;Translation structures & equates.
+.list
+
+ Extrn _Ow2MiscFlags:Byte ; 704,747,771,931,1188 (EnhancedKbd)
+ Extrn _Ow2MiscFlags3:Byte ; 1089,1154,1166,...(AltPacket SecAltNumPad PauseLatch E0Packet)
+ Extrn _Ow2KCBShFlgs:Word ; 2299
+ Extrn _Ow2KbdHWIDs:Word ;$$ Extrn IDFlags:Word
+ ;Extrn OtherFlags:Byte ; (Test OtherFlags,InterruptTime) moved to [EDI]
+ ;Extrn AltTable:Byte ; 275
+ ;Extrn AltPadMap:Byte ; 562
+ ;Extrn CtlPadMap:Byte ; 601
+ ;Extrn NewExtSC:Byte ; only CheckExtended()
+ ;Extrn NewExtSCLen:ABS ; only CheckExtended()
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+AltPadMap Label Byte
+ db 7,8,9,-1
+ db 4,5,6,-1
+ db 1,2,3
+ db 0,-1
+
+CtlPadMap Label Byte
+; db 119,-1,132,-1
+; db 115,-1,116,-1
+; db 117,-1,118
+; db -1,-1
+ db 119,141,132,142 ;@@ Keypad 7, 8, 9, - (PTM 5024)
+ db 115,143,116,144 ;@@ Keypad 4, 5, 6, + (PTM 5024)
+ db 117,145,118 ;@@ Keypad 1, 2, 3 (PTM 5024)
+ db 146,147 ;@@ Keypad 0, . (PTM 5024)
+
+;*****
+;* Translation for keypresses on AlphaKeys with Alt pressed. This
+;* translation is ALWAYS indexed by the Char1 value less 96 (which
+;* is ascii "a"). The translation value is the scan code that
+;* would come in on a regular PC keyboard (or PC/AT keyboard in
+;* compatability mode).
+;*****
+AltTable Label Byte
+; a, b, c, d, e, f, g, h, i, j, k, l, m
+ db 30,48,46,32,18,33,34,35,23,36,37,38,50 ;
+; n, o, p, q, r, s, t, u, v, w, x, y, z
+ db 49,24,25,16,19,31,20,22,47,17,45,21,44 ;
+
+NewExtSC LABEL BYTE
+
+;@@ ALT+
+;@@ [ ] ; ' ` \ , . / Tab
+ db 1Ah,1Bh,27h,28h,29h,2Bh,33h,34h,35h,0Fh
+
+NewExtSCLen equ $-NewExtSC ;@@ Used by interrupt handler.
+
+Even ;Make sure we're an even number of bytes. *
+; *
+; *
+;*** END OF THE TRANSLATION TABLE **********************************
+
+
+;OS2SS-...
+; ULONG
+; Ow2KbdXlate(
+; ULONG ScanCode,
+; PKBD_XLATE_VARS pFlagArea,
+; PKBD_MON_PACKAGE pMonitorPack,
+; PVOID pTransTable
+; );
+
+Public _Ow2KbdXlate@16
+_Ow2KbdXlate@16 Proc ;------------------------------------------------------\
+
+ push ebp
+ mov ebp,esp
+ sub esp,8 ; for local arguments
+ push ebx
+ push ecx
+ push edx
+ push edi
+ push esi
+
+;
+; now:
+;
+; ebp-8 Pointer to DD of XlateTable entry for this scan code.
+; ebp-4 Pointer to DD holding Offset of top of XlateTable
+;
+; ebp+0 old ebp
+; ebp+4 Return Address
+; ebp+8 ScanCode
+; ebp+12 pFlagArea
+; ebp+16 pMonitorPack
+; ebp+20 pTransTable
+;
+
+ mov eax, [ebp+8]
+ mov edi, [ebp+12]
+ mov esi, [ebp+16]
+ mov ebx, [ebp+20]
+; cmp ebx,0
+; jnz HaveTable
+; ; if no translate table
+; mov ebx,Offset XlateTable ; set the default one
+;
+;HaveTable:
+ call KbdXlate
+ mov al,0 ; Error ?
+ jnc EndXlate ; yes - no packet
+ test [esi].DDFlags,MultiMake
+ jnz EndXlate ; ignore multiple make of toggle key
+ test [edi].XPSGFlags, PrevAccent
+ jnz EndXlate ; ignore accent char till next keystroke
+ mov ah,byte ptr [esi].DDFlags
+ and ah,KeyTypeMask
+ cmp ah,UndefKey ; Is this key undefined?
+ je EndXlate ; yes - ignore
+ cmp byte Ptr [esi+KeyPacketLen].MonFlags,-1 ; do we have two packets?
+ mov al,1 ; assume not
+ jnz EndXlate
+ mov al,2 ; 2 packets
+
+EndXlate:
+ and eax,0FFh ; returns in al number of packets
+ pop esi
+ pop edi
+ pop edx
+ pop ecx
+ pop ebx
+ mov esp,ebp
+ pop ebp
+ ret 16
+
+_Ow2KbdXlate@16 Endp ;-------------------------------------------------------/
+
+KbdXlate Proc ;------------------------------------------------------\
+
+;***********************************************************************
+;* *
+;* Subroutine Name: KbdXlate *
+;* *
+;* Descriptive Name: Keyboard Scan Code Translation *
+;* *
+;* Function: This routine translates the scan code received from *
+;* the keyboard and places it in the Monitor Key Packet. *
+;* It also sets all flags that are based on the scan code *
+;* received. *
+;* *
+;* Entry Point: KbdXlate Linkage: Near *
+;* *
+;* Input: AL=Raw Scan Code EDI = Ptr to translation flag area *
+;* ESI = Ptr to Monitor KeyPacket *
+;* EBX = Ptr to Translate Table *
+;* *
+;* Exit-Normal: Monitor Key Packet filled in *
+;* AL=Raw scan code if translation successful *
+;* *
+;* Exit-Error: If found a break of a shift key that had seen no *
+;* make, returns 0 and CX hold the unexpected shift bits. *
+;* *
+;* Effects: All regs except SI, DI and the Seg regs may be altered *
+;* Key Packet filled in *
+;* *
+;* Internal References: *
+;* Routines: UnPauseChk *
+;* AccCheckout *
+;* *
+;* External References: *
+;* Routines: None. *
+;* *
+;* *
+;***********************************************************************
+ Or Byte Ptr [ESI].MonFlags,NotInserted ;OS2SS-Key isn't monitor inserted.
+ And [EDI].XlateFlags,Not NormalAlt ;OS2SS-@@ Turn flag off to start
+ Mov AH,AL ;Copy scan code into AH
+ Or AH,AH ;Check if key break bit in
+ .If <s> ;If it is
+ Or [ESI].DDFlags,KeyBreak ;OS2SS-Set Flag
+ And AH,Not BreakBit ;Clear the break bit from the scan code
+ .Endif ;Endif key break bit on
+
+ Mov DL,AL ;OS2SS-Now calculate...
+ And EDX,07Fh ;OS2SS-...the index into...
+ Dec EDX ;OS2SS- ...XlateTable for...
+ IMul EDX,KDefLen ;OS2SS- ...this scan code.
+ Add EDX,KDefs ;OS2SS-Point past header to keydefs.
+ Add EDX,EBX ;OS2SS-Add offset into table.
+ Mov [EBP-8],EDX ;OS2SS-Save Pointer to XlateTable entry for this scan code.
+ Mov [EBP-4],EBX ;OS2SS-Put table start offset on the stack.
+ Mov BX,[EDX].XlateOp ;OS2SS-Get Xlate Operation word.
+ And EBX,ActionMask ;OS2SS-Isolate translate action field.
+
+ Mov [ESI].Key.Scan,AH ;OS2SS-Put scan code in key packet
+ Test [EDI].XlateFlags,SecPrefix ;OS2SS-@@ Check if saw E0 prefix last time
+ .If <nz> ;If we did
+ Or [ESI].DDFlags,SecondaryKey ;OS2SS-@@ Indicate so.
+ ;@@ PTM 4359
+ .If <AL eq 53> ;@@ If this is '/' on Numpad
+ Test [ESI].Key.Shift,AltFlag ;OS2SS-@@ PTM 5024
+ .If <nz> ;@@ If ALT Key is down
+ Mov [ESI].Key.Scan,0A4h ;OS2SS-@@ Set extended scan code
+ .Else ;@@ Else no Alt down
+ Test [ESI].Key.Shift,CtlFlag ;OS2SS-@@ Check if Ctl key down
+ .If <nz> ;@@ If it is
+ Mov [ESI].Key.Scan,095h ;OS2SS-@@ Set extended scan code
+ .Else ;@@ Else no Alt or Ctl key down
+ Mov [ESI].Key.Char,'/' ;OS2SS-@@ then it is always '/' regardless
+ Mov [ESI].Key.Scan,OtherKey ;OS2SS-@@ and the scan code is EO
+ .Endif ;@@ Endif Ctl key down
+ .Endif ;@@ End PTM 5024
+ Jmp EndActionCase ;@@ of country/code page.
+ .Endif
+ .Endif
+
+ ;From now on, ES:EDX (;OS2SS-)points to the Xlate table entry. If running in
+ ;3xBox(;OS2SS-can't be), that pointer may have been created by a LOADALL, so don't
+ ;allow interrupts, nor change Seg Regs. Also, the beginning offset
+ ;of the translate table itself is on the top of stack.
+
+ Mov CX,Word Ptr [EDX+2] ;OS2SS-@@ Get Char1 and Char2 values.
+ Mov DX,[ESI].Key.Shift ;OS2SS-Get the current shift status from Key.
+
+ .If <BX ne 7> AND ;@@ If not a padkey clear possible Alt-nnn entry.
+ .If <BX ne 14> ;@@ Don't clear on Alt key, either.
+ Mov [EDI].XAltKeyPad,0 ;OS2SS-@@ Clear Alt-nnn entry.
+ .Endif
+ Mov AL,CL ;Copy Char1 for use later.
+ .If <BX gt MaxAct> ;@@ Was the action number too big?
+ Jmp NoXlate ;Yes, so don't try to translate.
+ .Endif
+ Shl BX,2 ;Make action number an offset.
+ Add EBX,Offset XJumpTable ;OS2SS-@@ Point to processor address.
+ Jmp [EBX] ;OS2SS-Go translate.
+
+ ;Following is the branch table for the various actions that
+ ;can be performed on a keystroke. Processing re-merges at the
+ ;bottom of this CASE structure, at label "EndActionCase".
+
+Public NoXlate, AlphaKey, SpecKey, SpecKeyC, SpecKeyA, SpecKeyCA
+Public FuncKey, PadKey, SpecCtlKey, PrtScr, SysReq, AccentKeyType
+Public ShiftKeys, ToggleKey, AltKey, NumLock, CapsLock, ScrollLock
+Public XShiftKey, XToggleKey, SpecKeyCS, SpecKeyAS
+Even
+XJumpTable:
+ dd NoXlate ;0 Invalid action code, no translate done.
+ dd AlphaKey ;1 Alphabetical character key.
+ dd SpecKey ;2 Special non-alpha key, no CAPSLOCK or ALT.
+ dd SpecKeyC ;3 Special non-alpha key, with CAPSLOCK.
+ dd SpecKeyA ;4 Special non-alpha key, with ALT.
+ dd SpecKeyCA ;5 Special non-alpha key, w/CAPSLOCK and ALT.
+ dd FuncKey ;6 Function keys.
+ dd PadKey ;7 Numeric keypad keys.
+ dd SpecCtlKey ;8 Keys that do special things with CTL.
+ dd PrtScr ;9 The print screen key.
+ dd SysReq ;A The system request key.
+ dd AccentKeyType ;B A key that affects the NEXT key (dead key).
+ dd ShiftKeys ;C The LSHIFT, RSHIFT, and CTL keys.
+ dd ToggleKey ;D General Toggle key.
+ dd AltKey ;E The ALT key.
+ dd NumLock ;F The NUMLOCK key.
+ dd CapsLock ;10 The CAPSLOCK key.
+ dd ScrollLock ;11 The SCROLL LOCK key.
+ dd XShiftKey ;12 Extended shift key (for DBCS use).
+ dd XToggleKey ;13 Extended toggle key (for DBCS use).
+ dd SpecKeyCS ;14 Special key for NLS support.
+ dd SpecKeyAS ;15 Special key for NLS support.
+
+; On entering the following routines, the following regs are set:
+;
+; CL = Char1 and CH = Char2 (both from XlateTable entry)
+; DX = ShiftFlags (same as in Key CharData record)
+; AL = Char1 also AH = Received scan code (Breakbit cleared)
+;OS2SS- ESI = Pointer to Key Packet
+;OS2SS- EDI = Pointer to current PSG
+;OS2SS- [EBP-8] = Pointer to XlateTable entry for this scan code.
+;OS2SS- [EBP-4] = Pointer to Offset of top of XlateTable
+;
+; Also, Key.Scan = AH and Key.Char = 0 on entry to the routines.
+
+AlphaKey: ;Alphabetical character key.
+ifdef JAPAN
+; MSKK Aug.15.1993 V-AkihiS
+; Support SBCS katakana
+ Test [ESI].Key.DShift, Katakana ;OS2SS Check if Katakana or not
+ .If <nz>
+ Mov EBX,[EBP-8] ;OS2SS-
+ Mov AL,[EBX].Char4 ;OS2SS-Get Char4 and Char5 values.
+ Mov CX,Word Ptr [EBX+5] ;OS2SS-
+ .Endif
+endif
+ Test DL,AltFlag ;Check if Alt key is pressed.
+ .If <nz> ;Is it?
+ And [EDI].XlateFlags,Not Use3Index ;OS2SS-@@ Use Char3 if AltGraph
+ Call AltGraphCheck ;@@ Process if AltGraph
+ Test [EDI].XlateFlags,NormalAlt ;OS2SS-@@ Check if it's not the AltGraph
+ .If <nz> ;@@ If alt key is normal Alt
+ Xor EBX,EBX ;OS2SS-Yes, so make Char1 an offset.
+ Mov BL,AL ;OS2SS-Now make it the base.
+ Mov AH,[AltTable+EBX-"a"] ;OS2SS-Fetch Alt-[] mapped code.
+ Mov [ESI].Key.Scan,AH ;OS2SS-Put in Key record.
+ Xor AL,AL ;Set `extended char' code.
+ .Endif
+ Jmp NewLbl1
+ .Endif ;OS2SS- (A2053)## Endif Alt is down.
+ ;OS2SS- .Else
+ Test DL,CtlFlag ;Else, check if Ctl key is pressed.
+ ;@@ for this KCB
+ ;@@ PTM 5992 - Begin
+ .If <nz> OR ;@@ Is it OR?
+ Test [EDI].XHotKeyShift,CtlFlag ;OS2SS-@@ Also check in interrupt shift
+ ;@@ state
+ .If <nz> AND ;@@ Is it being held down at all
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ .If <nz> ;&& translations are independent.
+ ;@@ PTM 5992 - End
+ ;Check limit on char1 value!
+ Sub AL,"a"-1 ;Yes, so convert Char1 to control code.
+ .If <CL eq 'c'> ;Is this Ctrl-C?
+ ;@@ Tell dd it's the PSUEDO-BREAK KEY.
+ Or [ESI].DDFlags,PSBreakKey ;OS2SS-
+ Jmp NoPauseCheck ;@@ Do not check if paused, Ctl-C
+ ;@@ has priority over resuming output
+ .ElseIf <CL eq 'p'> ;Is this Ctrl-P?
+ ;@@ Tell dd it's PSUEDO-PRTECHO KEY.
+ Or [ESI].DDFlags,PSPrintEchoKey ;OS2SS-
+ Jmp NoPauseCheck ;@@ Do not check if paused, Ctl-P
+ ;@@ has priority over resuming output
+ .ElseIf <CL eq 's'> ;Is this Ctrl-S?
+ ;1.3-## PTR b790266
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-1.3-## Make sure it isn't key break
+ .If <z> AND ;1.3-## If zero, then its a make
+ .If <[EDI].XInputMode eq 0> ;OS2SS-@@ Right, are we in cooked mode?
+ ;@@ Yes, tell dd it's PSUEDO-PAUSE KEY.
+ Or [ESI].DDFlags,PSPauseKey ;OS2SS-
+ .Endif
+ .Endif
+ .Else ;Check for regular shifts/capslock.
+ifdef JAPAN
+; MSKK Aug.15.1993 V-AkihiS
+; When Mode is katakana, CapsLock has no affect on this key.
+ Test [ESI].Key.DShift, Katakana ;OS2SS Check if Katakana or not
+ .If <nz> ;OS2SS
+ Mov BL,0 ;OS2SS indicate that CapsTogl has no
+ ;OS2SS affect on this key.
+ .Else
+ Mov BL, CapsTogl ;OS2SS Set indicator that CapsLock and
+ ;OS2SS ShiftLock affect key.
+ .Endif
+else
+ Mov BL, CapsTogl ;## Set indicator that CapsLock and
+ ;## ShiftLock affect key.
+endif
+ Call CapsCheck ;## Determine the shifting of the char.
+ .Endif ;## Endif Ctrl or Interrupt time.
+ ;OS2SS- .Endif ;## Endif Alt is down.
+NewLbl1: ;OS2SS-
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-@@ If it's interrupt time
+ .If <nz> ;@@
+ Call UnPauseChk ;Go check if in pause state.
+ .Endif ;@@
+
+NoPauseCheck:
+ Mov [ESI].Key.Char,AL ;OS2SS-Put xlated character into Key rec.
+ ;&& PTM 2217 BEGIN:
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-&& Check if this a break or make.
+ .If <z> ;&& If it isn't then go and check accent.
+ ;@@ PTM 6860 - Begin
+ Call AccCheckout ;Go check if accent combo going on.
+ ;@@ PTM 6860 - End
+ .Endif ;&& Endif this is a make.
+ ;&& PTM 2217 END:
+ Jmp EndActionCase ;Go to bottom of Xlate Action case table.
+
+SpecKey: ;Special non-alpha key, no CAPSLOCK or ALT.
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-@@ If it's interrupt time
+ .If <nz> ;@@
+ Call UnPauseChk ;Go check if in pause state.
+ .Endif ;@@
+ Test DL,AltFlag ;Check if Alt key is pressed.
+ .If <nz> ;Is it?
+ And [EDI].XlateFlags,Not Use3Index ;OS2SS-@@ Use Char3 if AltGraph
+ Call AltGraphCheck ;@@ Process if AltGraph
+ Test [EDI].XlateFlags,NormalAlt ;OS2SS-## Check if it's the AltGraph
+ .If <z> ;## If alt key is AltGraph
+ ;## which is undefined for this key
+ Mov [ESI].Key.Char,AL ;OS2SS-## put it in CDR
+ Call AccCheckout ;## Go check if acc. combo going on.
+ Jmp EndActionCase ;## Go to bottom of Xlate Action
+ .Endif ;## case table
+ Jmp NoXlate ;## then Key combo is undefined
+ .Endif ;@@ Endif Alt Key down
+ ;## PTM 2287: BEGIN
+ Mov EBX,[EBP-8] ;OS2SS-## Put it in BX
+ Test [EBX].XTFlags1,ShiftLock ;OS2SS-## Check if SHIFTLOCK keyboard.
+ .If <nz> ;## If it is
+ Mov BL,CapsTogl ;## Indicate a CAPSLOCK check.
+ .Endif ;## PTM 2287: END
+ Test DL, CtlFlag ;## Check if Ctrl key down.
+ .If <nz> ;## If so ...
+ Call SKCtlCheck ;## check if char has special
+ ;## control code.
+ .Else ;## Else Ctrl key not down,
+ Mov BL,0 ;1.3-@@ PTR B713838 Clear ShifLock Flag
+ Call CapsCheck ;## Check for shifting.
+ .Endif ;## Endif Ctrl down.
+ Mov [ESI].Key.Char,AL ;OS2SS-## Put Char in Key rec.
+ Call AccCheckout ;## PTR B705184
+ Jmp EndActionCase ;## Go to bottom of Xlate Action.
+
+SpecKeyC: ;Special non-alpha key, with CAPSLOCK.
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-@@ If it's interrupt time
+ .If <nz> ;@@
+ Call UnPauseChk ;Go check if in pause state.
+ .Endif ;@@
+ Test DL,AltFlag ;Check if Alt key is pressed.
+ .If <nz> ;Is it?
+ And [EDI].XlateFlags,Not Use3Index ;OS2SS-@@ Use Char3 if AltGraph
+ Call AltGraphCheck ;@@ Process if AltGraph
+ Test [EDI].XlateFlags,NormalAlt ;OS2SS-@@ Check if it's not the AltGraph
+ .If <nz> ;@@ If alt key is normal Alt
+ Mov EBX,[EBP-8] ;OS2SS-
+ .If <[EBX].Char4 eq 0> ;OS2SS-@@ then check if char 4 is 0
+ ;@@ PTM 5024 - Begin
+ Call CheckExtended ;@@ See if new extended code
+ ;@@ is defined
+ .If <c> ;## If it is defined.
+ Call AccCheckout ;## Go check if acc. combo going on.
+ Jmp EndActionCase ;## Go to bottom of Xlate Action
+ .Endif ;@@ PTM 5024 - End
+ Jmp NoXlate ;## the key combo is undefined
+ .Else ;@@ else if char 4 isn't 0
+ Mov AL,[EBX].Char4 ;OS2SS-@@ then use it
+ .Endif ;@@ Endif Char 4 is 0
+ .Endif ;@@ Endif Alt key is normal Alt.
+ Jmp SpecAccent ;@@ Go check if this is an accent
+ .Endif ;@@ Endif Alt Key down
+ Test DL, CtlFlag ;## Check if Ctrl key down.
+ .If <nz> ;## If so ...
+ Call SKCtlCheck ;## check if char has special
+ ;## control code.
+ .Else ;## Else Ctrl is not down.
+ ;## PTR B704944 CapsCheck in Else
+ Mov BL,CapsTogl ;Indicate check CAPSLOCK.
+ Call CapsCheck ;## Check for shifting.
+ .Endif
+
+SpecAccent:
+ .If <AL b 8> ;@@ Indicate this is unprocessed
+ Or [ESI].DDFlags,AccentKey ;OS2SS-@@ accent.
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-@@ Check for the key BREAK.
+ .If <z> ;@@ Is it?
+ And [EDI].XPSGFlags,Not PrevAccent ;OS2SS-@@ No, clear previous
+ ;@@ accent number.
+ Or Byte Ptr [EDI].XPSGFlags,AL ;OS2SS-&& Save accent number
+ ;&& for the next key.
+ .Endif
+ Jmp EndActionCase ;## Go to bottom of Xlate Action case table.
+ .Endif
+ Mov [ESI].Key.Char,AL ;OS2SS-## Put Char in Key rec.
+ Call AccCheckout ;## PTR B705184
+ Jmp EndActionCase ;@@ Go to bottom of Xlate Action case table.
+
+SpecKeyA: ;Special non-alpha key, with ALT.
+ifdef JAPAN
+; MSKK Aug.15.1993 V-AkihiS
+; Support SBCS katakana
+ Test [ESI].Key.DShift, Katakana ;OS2SS Check if Katakana or not
+ .If <nz>
+ Mov EBX,[EBP-8] ;OS2SS-
+ Mov AL,[EBX].Char4 ;OS2SS-Get Char4 and Char5 values.
+ Mov CX,Word Ptr [EBX+5] ;OS2SS-
+ .Endif
+endif
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-@@ If it's interrupt time
+ .If <nz> ;@@
+ Call UnPauseChk ;Go check if in pause state.
+ .Endif ;@@
+ ;## PTM 2287: BEGIN
+ Mov EBX,[EBP-8] ;OS2SS-## Put it in BX
+ Test [EBX].XTFlags1,ShiftLock ;OS2SS-## Check if SHIFTLOCK keyboard.
+ .If <nz> ;## If it is
+ Mov BL,CapsTogl ;## Indicate a CAPSLOCK check.
+ .Endif ;## PTM 2287: END
+ Test DL, AltFlag ;## Check if Alt is down,
+ .If <nz> ;## If it is...
+ Call SKAltCheck ;## Check for extended code.
+ .Else ;## If it is not down,
+ .if <bit dl nz CtlFlag> ;## PTM 3327 start
+ Call SKCtlCheck ;## Check for spec. Ctrl code.
+ .else
+ Mov BL,0 ;1.3-@@ PTR B713838 Clear ShifLock Flag
+ Call CapsCheck ;## Check for Shifting.
+ .endif ;## PTM 3327 end
+ Mov [ESI].Key.Char,AL ;OS2SS-## Put Char in Key rec.
+ .Endif ;## Endif Alt is down.
+ Call AccCheckout ;## PTM 3126 fix stand alone accent
+ Jmp EndActionCase ;## Go to bottom of Xlate Action.
+
+SpecKeyCA: ;Special non-alpha key, w/CAPSLOCK and ALT.
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-@@ If it's interrupt time
+ .If <nz> ;@@
+ Call UnPauseChk ;Go check if in pause state.
+ .Endif ;@@
+ Mov BL,CapsTogl ;Indicate check CAPSLOCK.
+ Test DL, AltFlag ;## Check if Alt is down,
+ .If <nz> ;## If it is...
+ Call SKAltCheck ;## Check for extended code.
+ .Else ;## If it is not down,
+ Call CapsCheck ;## Check for Shifting.
+ Test DL, CtlFlag ;## Check if Ctrl is down,
+ .If <nz> ;## If it is then...
+ Call SKCtlCheck ;## Check for spec. Ctrl code.
+ .Endif ;## Endif Ctrl is down.
+ .Endif ;## Endif Alt is down.
+ Mov [ESI].Key.Char,AL ;OS2SS-## Put Char in Key rec.
+ Jmp EndActionCase ;## Go to bottom of Xlate Action.
+
+FuncKey: ;Function keys.
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-@@ If it's interrupt time
+ .If <nz> ;@@
+ Call UnPauseChk ;Go check if in pause state.
+ .Endif ;@@
+ Test DL,AltFlag ;Check Alt Key.
+ .If <nz> ;Is it down?
+ And [EDI].XlateFlags,Not Use3Index ;OS2SS-@@ Use Char3 if AltGraph
+ Call AltGraphCheck ;@@ Process if AltGraph
+ Test [EDI].XlateFlags,NormalAlt ;OS2SS-@@ Check if it's not the AltGraph
+ .If <nz> ;@@ If alt key is normal Alt
+ .If <CL gt 10> ;Yes, so check if F11 or F12.
+ Add CL,128 ;If so, extended code is 139 or 140
+ .Else
+ Add CL,103 ;Extended code is range 104-113.
+ .Endif ;@@
+ .Else ;@@ Else ALt key was Atl-Graph
+ ;@@ PTM 6860 - Begin
+ Mov [ESI].Key.Char,AL ;OS2SS-@@ Move char 3 to key packet
+ Mov CL,[ESI].Key.Scan ;OS2SS-@@ Move scan to CL
+ ;@@ PTM 6860 - End
+ .Endif ;@@ Endif Alt or AltGraph check
+ .Else ;@@ Endif no Alt key down
+ Test DL,CtlFlag ;Check Ctl Key.
+ .If <nz> ;Is it down?
+ .If <CL gt 10> ;Yes, so check if F11 or F12.
+ Add CL,126 ;If so, extended code is 137 or 138.
+ .Else
+ Add CL,93 ;Extended code is range 94-103.
+ .Endif
+ .Else
+ Test DL,RShiftFlag+LShiftFlag ;Check Shift Keys.
+ .If <nz> ;Is one down?
+ .If <CL gt 10> ;Yes, so check if F11 or F12.
+ Add CL,124 ;If so, extended code is 135 or 136.
+ .Else
+ Add CL,83 ;Extended code is range 84-93.
+ .Endif
+ .Else ;Else this is a non-shifted FKey.
+ .If <CL gt 10> ;Check if F11 or F12.
+ Add CL,122 ;If so, extended code is 133 or 134.
+ .Else
+ Add CL,58 ;Extended code is range 59-68.
+ .Endif
+ .Endif
+ .Endif
+ .Endif
+ Mov [ESI].Key.Scan,CL ;OS2SS-Put code in CharData rec.
+ ;@@ PTM 6860 - Begin
+ Call AccCheckout ;Go check if accent combo going on.
+ ;@@ PTM 6860 - End
+ Jmp EndActionCase ;Go to bottom of Xlate Action case table.
+
+
+PadKey: ;Numeric keypad keys.
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-@@ If it's interrupt time
+ .If <nz> ;@@
+ Call UnPauseChk ;Go check if in pause state.
+ .Endif ;@@
+ Xor EBX,EBX ;OS2SS-Clear for use later.
+ Test DL,AltFlag ;Check if Alt key down.
+ .If <nz> NEAR ;Are we entering Alt-nnn?
+ ;Maybe. First check for reboot request.
+ .If <CL eq 12> AND ;@@ And is current key mapped to Del?
+ ;@@ PTM 6350 - Begin
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-@@ Check if this a break
+ .If <z> AND ;@@ If it isn't (only reboot on make of Del)
+ ;@@ PTM 6350 - End
+ Test DL,CtlFlag ;Maybe. First check for reboot request.
+ .If <nz> OR ;Is Ctl down too
+ ;@@ for this KCB OR
+ ;@@ PTM 5992 - Begin
+ Test [EDI].XHotKeyShift,CtlFlag ;OS2SS-@@ Also check in interrupt shift
+ ;@@ state
+ .If <nz> AND ;@@ Is it being held down at all
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ .If <nz> ;&& translations are independent.
+ ;@@ PTM 5992 - End
+ ;@@ Tell dd it's the REBOOT KEY.
+ ;OS2SS-BUGBUG shouldn't get here
+ Or [ESI].DDFlags,RebootKey ;OS2SS-@@
+ Jmp EndActionCase ;Quit now.
+ .Endif
+ And [EDI].XlateFlags,Not Use3Index ;OS2SS-@@ Use Char3 if AltGraph
+ Call AltGraphCheck ;@@ Process if AltGraph
+ Test [EDI].XlateFlags,NormalAlt ;OS2SS-@@ Check if it's not the AltGraph
+ .If <nz> ;@@ If alt key is normal Alt
+ ;@@ PTM 5024 - BEGIN
+ Test [EDI].XlateFlags,SecPrefix ;OS2SS-@@ Check if secondary key
+ .If <nz> ;@@ If it is
+ Add [ESI].Key.Scan,50h ;OS2SS-@@ Make scan extended code
+ Mov [ESI].Key.Char,0 ;OS2SS-@@ Make char extended code
+ .Else ;@@ Else primary pad key
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-Check if is a key break.
+ .If <z> ;Is it?
+ Mov BL,CL ;No, so make Char1 value the index.
+ Mov CL,[EBX+AltPadMap] ;OS2SS-Get numeric value of the key.
+ Or CL,CL ;Check if value is -1.
+ .If <s> ;Is it.
+ Mov [EDI].XAltKeyPad,0 ;OS2SS-@@ Not numeric, reset.
+ .If <AH eq 83> ;@@ If this is DEL key
+ Jmp NoXlate ;@@ No extended value, undefined
+ .Else ;@@ Else extended char
+ Jmp EndActionCase ;@@ Mark char defined
+ .Endif ;@@ Endif Extended Char exists
+ .Else
+ Mov AL,10 ;Else multiply old...
+ Mul [EDI].XAltKeyPad ;OS2SS-@@ ...accumulator by 10.
+ Add AL,CL ;And add new key.
+ Mov [EDI].XAltKeyPad,AL ;OS2SS-@@ Save modified accum.
+ Jmp NoXlate ;Mark keystroke undefined
+ .Endif
+ .Else ;@@ PTM 6860 - Begin Else a break
+ Jmp NoXlate ;@@ Mark keystroke undefined
+ .Endif
+ .Endif ;@@ Endif primary or secondary key
+ ;@@ End PTM 5024
+ .Else ;@@
+ Mov [ESI].Key.Char,AL ;OS2SS-@@ Put Char into Key rec.
+ Test [ESI].DDFlags,SecondaryKey ;OS2SS-@@ Check if G keyboard dup key.
+ .If <nz> ;@@ Is it?
+ Mov [ESI].Key.Scan,OtherKey ;OS2SS-@@ Yes, so mark it so.
+ .Endif ;@@
+ .Endif ;@@ Endif normal ALT
+ .Else NEAR ;No Alt key down.
+ ;@@ PTM 5024
+ Test [EDI].XlateFlags,SecPrefix ;OS2SS-@@ Check if secondary key
+ .If <nz> ;@@ If it is
+ Mov AL,OtherKey ;@@ Set Char to E0
+ .Else ;@@ Else regular pad key
+ Xor AL,AL ;@@ Set Char to "extended"
+ .Endif ;@@ End PTM 5024
+ Test DL,CtlFlag ;Check if Ctl key down.
+ .If <nz> ;Is it?
+ Mov BL,CL ;Yes, so make Char1 value the index.
+ Mov AH,[EBX+CtlPadMap] ;OS2SS-Get extended value of the key.
+ Mov [ESI].Key.Scan,AH ;OS2SS-Set extended code for this key.
+ .Else ;Not Alt- or Ctl-, so figure out Num status.
+ .If <CL eq 3> OR ;Is this the minus key?
+ .If <CL eq 7> ;Or is this the plus key?
+ Mov AL,CH ;Yes, so use Char2 regarless of shifts.
+ .Else
+ Test DL,RShiftFlag+LShiftFlag ;Check for shift key.
+ .If <nz> ;Is one down?
+ Or BL,NumTogl ;Yes, so set NumLock bit.
+ .Endif
+ And DL,NumTogl ;Clear all shift bits but NumLock.
+ Xor DL,BL ;Flip it if shift key was down.
+ .If <nz> ;Is the case Num Lock?
+ Mov AL,CH ;Yes, so use Char2.
+ .Endif
+ ;@@ PTM 7358 - Begin
+ .If <z> OR ;@@ If we should not shift
+ Test [ESI].DDFlags,SecondaryKey ;OS2SS-@@ if G keyboard dup key.
+ .If <nz> ;@@ If it is
+ .If <CL eq 11> ;Is this the Ins key?
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-Yes check if key BREAK.
+ .If <nz> ;Is it?
+ And [EDI].ToggleFlags,Not InsKeyDown ;OS2SS-@@ Yes clear latch.
+ .Else ;Not Ins Key Break.
+ Test [EDI].ToggleFlags,InsKeyDown ;OS2SS-@@ Check if seen Ins.
+ .If <z> ;Have we?
+ Or [EDI].ToggleFlags,InsKeyDown ;OS2SS-@@ No, so set latch.
+ Xor Byte Ptr [ESI].Key.Shift,InsTogl ;OS2SS-Toggle in CDR
+ .Else ;Otherwise this is a repeat of the make.
+ Or [ESI].DDFlags,MultiMake ;OS2SS-So indicate so.
+ .Endif
+ .Endif
+ .Endif
+ .Endif ;@@ Endif we should set/clear insert toggle
+ ;@@ PTM 7358 - End
+ .Endif
+ .Endif
+ Mov [ESI].Key.Char,AL ;OS2SS-Put character value in Key rec.
+ Test [ESI].DDFlags,SecondaryKey ;OS2SS-Check if G keyboard dup key.
+ .If <nz> ;Is it?
+ Mov [ESI].Key.Char,OtherKey ;OS2SS-Yes, so mark it so.
+ .Endif
+ .Endif ;Endif Alt key down or not check
+ ;@@ PTM 6860 - Begin
+ Call AccCheckout ;Go check if accent combo going on.
+ ;@@ PTM 6860 - End
+ Jmp EndActionCase ;Go to bottom of Xlate Action case table.
+
+
+SpecCtlKey: ;Keys that do special things with CTL.
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-@@ If it's interrupt time
+ .If <nz> ;@@
+ Call UnPauseChk ;Go check if in pause state.
+ .Endif ;@@
+ Test DL,AltFlag ;Check if Alt key down.
+ .If <nz> ;Is it?
+ And [EDI].XlateFlags,Not Use3Index ;OS2SS-@@ Use Char3 if AltGraph
+ Call AltGraphCheck ;@@ Process if AltGraph
+ Test [EDI].XlateFlags,NormalAlt ;OS2SS-@@ Check if it's not the AltGraph
+ .If <nz> ;@@ If alt key is normal Alt
+ ;@@ PTM 5024 - Begin
+ Xor AL,AL ;@@ Set Char to be extended
+ .If <AH eq 1Ch> AND ;@@ If this is the Enter key
+ Test [ESI].DDFlags,SecondaryKey ;OS2SS-
+ .If <nz> ;@@ on the pad keys
+ ;&& PTM 1270 - Don't overwrite scan
+ Mov [ESI].Key.Scan,0A6h ;OS2SS-@@ Set extended code
+ .Endif
+ .Endif ;@@ PTM 5024 End
+
+ Jmp SetCharField ;&& PTM 1520 now go set char field
+ .Endif
+ ;&& PTM 1270 - Begin
+ Test [ESI].DDFlags,SecondaryKey ;OS2SS-@@ Check if G keyboard dup key.
+ .If <nz> ;@@ Is it?
+ Mov [ESI].Key.Scan,OtherKey ;OS2SS-@@ Yes, so mark it so.
+ .Endif
+ Test DL,CtlFlag ;Check if Ctl key down.
+ .If <nz> ;Is it?
+ Mov AL,CH ;Yes, so use Char2.
+ .Endif
+ SetCharField: ;&& PTM 1520 Alt should have
+ ;&& precedence when Ctrl and Alt
+ ;&& are down.
+
+ Mov [ESI].Key.Char,AL ;OS2SS-Put Char into Key rec.
+ ;&& PTM 1270 - End
+ ;@@ PTM 6860 - Begin
+ Call AccCheckout ;Go check if accent combo going on.
+ ;@@ PTM 6860 - End
+ Jmp EndActionCase ;Go to bottom of Xlate Action case table.
+
+;OS2SS-BUGBUG-shouldn't get here
+PrtScr: ;The print screen key.
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-@@ If it's interrupt time
+ .If <nz> ;@@
+ Call UnPauseChk ;Go check if in pause state.
+ .Endif ;@@
+ Test DL,AltFlag ;Check if Alt key down.
+ .If <nz> ;Is it?
+ Test [EDI].XlateFlags,SecPrefix ;OS2SS-@@ Check if secondary key
+ .If <nz> OR ;@@ If it is OR...
+ Test _Ow2MiscFlags,EnhancedKbd ;@@ Check if enhanced kbd
+ .If <z> OR ;@@ OR...If it's a regular kbd
+;$$
+;$$ 'IDFlags' does not exist in the 1.2 ABIOS
+;$$ version. We need to get this information from KbdHWIDs.
+;$$
+
+;$$ Test IDFlags, SuperSport ;## Check if it is a 122 kbd
+
+ .If < _Ow2KbdHWIDs e 0AB85h > ;$$ If it is a 122 kbd
+ Test DL,CtlFlag ;@@ Check if Ctl key is down
+ .If <nz> OR ;@@ If it is
+ ;@@ for this KCB
+ ;@@ PTM 5992 - Begin
+ Test [EDI].XHotKeyShift,CtlFlag ;OS2SS-@@ Also check in interrupt shift
+ ;@@ state
+ .If <nz> AND ;@@ Is it being held down at all
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ .If <nz> ;&& translations are independent.
+ ;@@ PTM 5992 - End
+ Or [ESI].DDFlags,PrintFlushKey ;OS2SS-@@ Indicate this is FlushPrtbuf
+ Jmp EndActionCase ;@@ Go to bottom of Xlate Action
+ ;@@ case table.
+ .Endif
+ Jmp NoXlate ;Else that's undefined for this key.
+ ;@@ PTM 5024 begin
+ .Else ;@@ Else it Pad Key * on G kbd
+ Xor AL,AL ;@@ Set extended code
+ .Endif ;@@ Endif PrtScr or *
+ .Else NEAR ;@@ Else no Alt key down
+ Test DL,CtlFlag ;Check if Ctl key down.
+ ;@@ for this KCB
+ ;@@ PTM 5992 - Begin
+ .If <nz> OR ;@@ Is it OR?
+ Test [EDI].XHotKeyShift,CtlFlag ;OS2SS-@@ Also check in interrupt shift
+ ;@@ state
+ .If <nz> AND ;@@ Is it being held down at all
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ ;@@ PTM 5992 - End
+ Test [EDI].XlateFlags,SecPrefix ;OS2SS-@@ Check if secondary key
+ .If <nz> OR ;@@ If it is OR...
+ Test _Ow2MiscFlags,EnhancedKbd ;@@ Check if enhanced kbd
+ .If <z> OR ;@@ OR...If it's a regular kbd
+;$$
+;$$ 'IDFlags' does not exist in the 1.2 ABIOS
+;$$ version. We need to get this information from KbdHWIDs.
+;$$
+
+;$$ Test IDFlags, SuperSport ;## Check if it is a 122 kbd
+
+ .If < _Ow2KbdHWIDs e 0AB85h > ;$$ If it is a 122 kbd
+ Xor AL,AL ;Yes so set extended code...
+ Mov [ESI].Key.Scan,CH ;OS2SS-...for the Ctl-PrSc combination.
+ Or [ESI].DDFlags,PrintEchoKey ;OS2SS-@@ Tell dd it's the PRINT
+ ;@@ ECHO KEY.
+ ;@@ PTM 5024 - Begin
+ .Else ;@@ Else its the keypad *
+ Xor AL,AL ;@@ so set extended code...
+ Mov [ESI].Key.Scan,96h ;OS2SS-@@ for scan and char
+ .Endif ;@@ PTM 5024 - end
+ .Else ;@@ Else Ctrl key not down.
+ Test [EDI].XlateFlags,SecPrefix ;OS2SS-@@ Check if secondary key
+ .If <nz> OR ;@@ If it is OR...
+ Test DL,RShiftFlag+LShiftFlag ;@@ Check if a shift flag down.
+ .If <nz> AND ;@@ If a shift key is down AND...
+ Test _Ow2MiscFlags,EnhancedKbd ;@@ Check if enhanced kbd
+ .If <z> OR ;@@ AND...If it's a regular kbd
+
+;$$ Test IDFlags, SuperSport ;## Check if it is a 122 kbd
+;$$
+;$$ 'IDFlags' does not exist in the 1.2 ABIOS
+;$$ version. We need to get this information from KbdHWIDs.
+;$$
+ .If < _Ow2KbdHWIDs e 0AB85h > ;$$ If it is a 122 kbd
+
+ Xor AL,AL ;Yes, so clear char code.
+ Or [ESI].DDFlags,PrtScrKey ;OS2SS-@@ Tell dd it's PRINT SCREEN KEY.
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-Check for the key BREAK.
+ .If <nz> ;Is it?
+ And [EDI].XlateFlags,Not PSKeyDown ;OS2SS-@@ Yes, clear PS Key latch
+ .Else
+ Test [EDI].XlateFlags,PSKeyDown ;OS2SS-@@ Check if seen PS key yet.
+ .If <z> ;Have we?
+ Or [EDI].XlateFlags,PSKeyDown ;OS2SS-@@ No, set latch saying have.
+ .Else ;Otherwise this is a repeat of the make.
+ Or [ESI].DDFlags,MultiMake ;OS2SS-So indicate so.
+ .Endif ;Endif no PS key yet check
+ .Endif ;Endif Key break or not check
+ .Else ;@@ PTM 2606: Shift keys not
+ ;@@ down or not enhanced kbd.
+ Test [ESI].DDFlags, KeyBreak ;OS2SS-@@ If this is a break of the
+ .If < nz > ;@@ PrtScr key,
+ And [EDI].XlateFlags,Not PSKeyDown ;OS2SS-@@ Ensure latch is
+ ;@@ cleared.
+ .Endif ;@@ Endif PrtScr break.
+ .Endif ;Endif shift key down
+ .Endif ;Endif Ctl down or not check
+ .Endif ;@@ Endif Alt key down check
+ Mov [ESI].Key.Char,AL ;OS2SS-Put character in Key rec.
+ ;@@ PTM 6860 - Begin
+ Call AccCheckout ;Go check if accent combo going on.
+ ;@@ PTM 6860 - End
+ Jmp EndActionCase ;Go to bottom of Xlate Action case table.
+
+
+AccentKeyType: ;A key that affects the NEXT key (dead key).
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-@@ If it's interrupt time
+ .If <nz> ;@@
+ Call UnPauseChk ;Go check if in pause state.
+ .Endif ;@@
+ Test DL,AltFlag ;Check if ALT down.
+ .If <nz> ;Is one?
+ Or [EDI].XlateFlags,Use3Index ;OS2SS-@@ Use Char3 if AltGraph
+ Call AltGraphCheck ;@@ Process if AltGraph
+ Test [EDI].XlateFlags,NormalAlt ;OS2SS-@@ check if it was Altgraph key
+ .If <z> ;@@ If it was AltGraph key
+ .If <CL a 7> ;@@ If char 3 wasn't accent
+ Mov [ESI].Key.Char,CL ;OS2SS-@@ Put char in CDR
+ Mov [ESI].Key.Scan,AH ;OS2SS-@@ Put scan in CDR
+ Call AccCheckOut ;@@ Go check if accent combo (p6860)
+ Jmp EndActionCase ;@@ And quit now
+ .Else ;@@ Else char3 was an accent or 0
+ .If <CL eq 0> ;@@ If Char 3 was 0
+ Jmp NoXlate ;@@ Mark Key packet undefined
+ .Else ;@@ Else it was an accent
+ Xor BH,BH ;@@ Flag no shift check
+ Jmp ShiftAccent
+ .Endif ;@@ Endif Char3 was 0 or not
+ .Endif ;@@ Endif Char3 accent or not
+ .Endif ;@@ Endif Altgraph key down
+ .Endif ;@@ Endif ANY Alt key down
+ Test [EDI].XlateFlags,NormalAlt ;OS2SS-@@ Check if it's not the AltGraph
+ .If <nz> OR ;@@ If alt key is normal Alt
+ Test DL,CtlFlag
+ .If <nz> ;@@ OR CTL key is down
+ Mov EBX,[EBP-8] ;OS2SS-
+ Mov CL,[EBX].Char5 ;OS2SS-@@ Get accent entry index
+ ;@@ for CTL or ALT character
+ XOR EBX,EBX ;OS2SS-
+ Test [EDI].XlateFlags,NormalAlt ;OS2SS-@@ Check if it's not the AltGraph
+ .If <nz> ;@@ If alt key is normal Alt
+ Mov EBX,AltAcChar ;OS2SS-@@ So get Alt-Accent offset.
+ .Endif
+ Test DL,CtlFlag
+ .If <nz> ;@@ If its the CTL key
+ Mov EBX,CtlAcChar ;OS2SS-@@ So get Ctl-Accent offset.
+ .Endif
+ And ECX,0FFh ;OS2SS-Make accent number a word.
+ Dec ECX ;OS2SS-Accent 1 is offset zero.
+ IMul ECX,AccEntryLen ;OS2SS-Set offset of accent table entry.
+ Add ECX,Accents ;OS2SS-Add offset of accent entries.
+ Add ECX,EBX ;OS2SS-@@ Add offset for Ctl or Alt
+ ;@@ accent
+ Add ECX,[EBP-4] ;OS2SS-Point into translate table.
+ Mov EBX,ECX ;OS2SS-Put pointer in base reg.
+ Mov BX,Word Ptr [EBX] ;OS2SS-Fetch char and scan.
+ Or BX,BX ;Check if a Scan/Char mapping for this key.
+ .If <z> ;Is there?
+ Jmp NoXlate ;No, so go mark untranslated.
+ .Endif ;Else, use the mapping.
+ Mov Word Ptr [ESI].Key.Char,BX ;OS2SS-Put them into Key.
+ ;@@ PTM 6860
+ Call AccCheckout ;Go check if accent combo going on
+ Jmp EndActionCase ;Quit now.
+ .Endif
+ ;## PTR B700738 Move 0 into BL to
+ Mov BL,0 ;## indicate that CapsTogl has no
+ ;## affect on this key.
+ Call CapsCheck ;## Determine shifting of character.
+
+ShiftAccent: ;@@ Merge here for accent process
+ .If <nz> ;@@ If we should shift
+ Mov CL,CH
+ .Endif
+ .If <CL a 7> ;@@ Is translate table entry
+ ;@@ actually a character
+ Mov [ESI].Key.Char,CL ;OS2SS-@@ Put character in CDR
+
+ .IF <bit [ESI].DDFlags z KeyBreak> ;OS2SS-## PTM 3324 start
+ Call AccCheckOut ;@@ Go check if accent combo
+ .ENDIF ;## PTM 3324 end
+
+ Jmp EndActionCase ;Go to bottom of Xlate Action case table.
+
+ .Else ;@@ Else actually an accent
+ Or CL,CL ;@@ check if accent defined.
+ .If <z> ;@@ Is it?
+ Jmp NoXlate ;@@ No, so go mark undefined.
+ .Endif
+ Xor CH,CH ;Make accent number a word.
+ Mov BX,[EDI].XPSGFlags ;OS2SS-&& Get the translation flags
+ And BX,PrevAccent ;&& Clear all bits but previous
+ ;&& accent number (in BL)
+ Mov AL,CL ;@@ Save accent number
+ .If <BL eq CL> AND ;@@ If this is same accent number
+ ;@@ as last time AND
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-@@ Check if this is a BREAK
+ .If <z> AND ;@@ AND it is not a break
+
+ Mov EBX,[EBP-8] ;OS2SS-
+ Mov BX,[EBX].XlateOp ;OS2SS-@@ Get accent flags
+ Mov CL,7 ;@@ Set highest accent number
+ Sub CL,AL ;@@ Subtract actual accent number
+ Shl BX,CL ;@@ Put accent flag in high bit
+ .If <s> ;@@ AND if an accent is defined
+ Mov DX,[ESI].Key.Shift ;OS2SS-@@ Get the current shift status from Key.
+ Call AccCheckOut ;@@ Go process this key
+ .Endif
+ ;Indicate this is an unprocessed accent.
+ Or [ESI].DDFlags,AccentKey ;OS2SS-@@
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-Check for the key BREAK.
+ .If <z> NEAR ;Is it?
+ And [EDI].XPSGFlags,Not PrevAccent ;OS2SS-@@ No, clear prev accent
+ Or Byte Ptr [EDI].XPSGFlags,AL ;OS2SS-&& Save accent number for next
+ ;&& key.
+ .Endif
+ Jmp EndActionCase ;Go to bottom of Xlate Action case table.
+ .Endif ;@@
+SysReq: ;The system request key.
+
+ ;@@ PTM 4247 - the PrtScr key on an Enhanced Keyboard
+ ;@@ sends the SysReq scan code if the Alt Key is down
+ ;@@ which it must be for the Print Buffer flush key combo
+ ;@@ (Ctl-Alt-PrtScr). Therefore we must check for it here.
+
+ Test _Ow2MiscFlags,EnhancedKbd ;@@ Check if enhanced kbd
+ .If <nz> AND ;@@ If it is AND....
+ Test [ESI].DDFlags,KeyBreak ;@@ Check if this is a break
+ .If <z> AND ;@@ ...AND If it's NOT (a make)
+ Test DL,AltFlag ;@@ Check if Alt key down.
+ .If <nz> AND ;@@ If it is AND....
+ Test DL,CtlFlag ;@@ Check if Ctl key is down
+ ;@@ for this KCB
+ ;@@ PTM 5992 - Begin
+ .If <nz> OR ;@@ Is it OR?
+ Test [EDI].XHotKeyShift,CtlFlag ;OS2SS-@@ Also check in interrupt shift
+ ;@@ state
+ .If <nz> AND ;@@ Is it being held down at all
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz> ;@@ PTM 5992 - End
+ ;@@ No, so make sure this shift key's flag is set.
+ Or [ESI].Key.Shift,CX ;OS2SS-
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ Or [EDI].XHotKeyShift,CX ;OS2SS-@@ Also set in hot key shift state
+ .Endif
+ ;@@ Indicate this is Flush Prt buf
+ Or [ESI].DDFlags,PrintFlushKey ;OS2SS-
+ Jmp EndActionCase ;@@ Go to bottom of Xlate Action
+ ;@@ case table.
+ .Else ;@@ Else (PTM 4990)
+ Or [ESI].DDFlags,SysReqKey ;OS2SS-@@ Indicate this is SysReq key
+ .Endif
+
+
+ShiftKeys: ;The LSHIFT, RSHIFT, and CTL keys.
+AltKey: ;And the ALT key.
+ Test [EDI].XlateFlags,E1Prefix ;OS2SS-@@ CHeck if scan code proceeded
+ .If <nz> AND ;@@ by E1, if so AND
+ Test CX,CtlFlag ;@@ check if this is Ctrl key
+ .If <nz> ;@@ AND if it is Ctrl
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-@@ Check if this is a break
+ .If <z> ;@@ if it is not
+ Or [EDI].XlateFlags,PseudoCtl ;OS2SS-@@ Flag this as not actually
+ ;@@ a Ctrl key but a code
+ ;@@ sent by Enhanced Kbd
+ .Endif
+ Jmp NoXlate ;@@ Mark key packet undefined
+ .Endif
+ ;&& PTM 3002 BEGIN:
+ ;&& Setup alternate shift bits
+ ;&& before checking for MultiMake.
+ Mov EBX,[EBP-8] ;OS2SS-Put XlateTable offset into a base reg.
+ Mov AH,[EBX].Char3 ;OS2SS-Get alternate shift bits from entry.
+ Mov EBX,[EBP-4] ;OS2SS-
+ Mov BX,[EBX].XTFlags1 ;OS2SS-@@ Get the XT header flags
+ Test [ESI].DDFlags,SecondaryKey ;OS2SS-Check if G keyboard dup key.
+ .If <nz> ;Is it?
+ Test CX,RShiftFlag+LShiftFlag ;@@ Is the key a shift key
+ .If <nz> ;@@ If so....
+
+ ;@@ If it is then this is coming from a "G" keyboard secondary
+ ;@@ pad key, and NUMLOCK is on. This combination sends
+ ;@@ the following scan codes: E0, left shift make, E0,
+ ;@@ pad key make, E0, pad key break, E0, left shift break.
+ ;@@ In this case, we don't want to change the shift flags
+ ;@@ anywhere.
+
+ Jmp NoXlate ;@@ Mark key packet undefined
+
+ .Endif ;@@ Endif shift key
+
+ Xchg CH,AH ;Yes, so swap shift bit mask with alternate.
+ .Endif ;&& PTM 3002 END:
+ ;@@ PTM 6446 - BEGIN
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-@@ Check if this is a MAKE
+ .If <z> ;@@ If it is
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz> AND
+ Test Byte Ptr [EDI].XHotKeyShift+1,CH ;OS2SS-@@ Check if this key down
+ ;@@ In the system already
+ ;@@ for Ctl and Alt
+ .If <nz> OR ;@@ If it is OR
+ Test CX,RShiftFlag+LShiftFlag ;@@ Is the key a shift key
+ .If <nz> AND ;@@ If so AND....
+ Test [ESI].DDFlags,SecondaryKey ;OS2SS-@@ And if this is NOT a secondary
+ .If <z> AND ;@@ shift key code sent by a pad
+ ;@@ key (PTM 7506)
+ Test Byte Ptr [EDI].XHotKeyShift,CL ;OS2SS-@@ Check if this key down
+ .If <nz> ;@@ If it is
+ ;@@ In the system already
+ ;@@ PTM 3138 BEGIN: Flag as shift
+ ;@@ key also, do not put in KIB.
+ Or [ESI].DDFlags,MultiMake+ShiftMask ;OS2SS-@@ Indicate so and do not
+ ;@@ update shift state.
+ ;@@ PTM 3138 END:
+ Jmp EndActionCase ;@@ Complete translation
+ .Endif ;@@ Endif this is a multimake
+ .Endif ;@@ Endif this is a key make
+ ;@@ PTM 6446 - END
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-Check if this is key break.
+ .If <nz> AND ;If it is AND...
+ Test DX,CX ;And is a key make pending for this shift flag?
+ .If <z> ;If not, this key belongs in another SG.
+ Xor AL,AL ;Indicate not our keystroke.
+ ClC ;Differentiate from other key-break return above.
+ Ret ;Quit now.
+ .Endif
+ Test CX,RShiftFlag+LShiftFlag+SysRqFlag ;Is the key other...
+ .If <nz> ;...than Ctl or Alt?
+ And [EDI].XlateFlags,NOT DumpKeyOnce ;OS2SS-@@ Cancel Dump sequence.
+ .Endif
+ Or [ESI].DDFlags,ShiftMask ;OS2SS-@@ Indicate this is a shift key.
+ Test BX,ShiftLock ;@@ ShiftLock keyboard?
+ .If <nz> AND ;Is it shift lock and...
+ Test BX,ShiftToggle ;@@ ShiftToggle Kbd?
+ .If <z> AND ;@@ Is it NOT shift toggle and..
+ Test CL,RShiftFlag+LShiftFlag ;...is this key one of..
+ .If <nz> AND ; ...two shift keys?
+ Test [ESI].DDFlags,KeyBreak ;Check for the key BREAK.
+ .If <z> ;If not, make sure ShiftLock is off.
+ And DL,Not CapsTogl ;Turn it off.
+
+ ;@@ Turn it off in the interrupt driven shift state for
+ ;@@ hot keys also
+
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ And Byte Ptr [EDI].XHotKeyShift+1,Not CapsTogl ;OS2SS-
+ .Endif
+ .Endif
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-Check for the key BREAK.
+ .If <z> ;Is it?
+ Test CX,DX ;@@ No, its a MAKE
+ .If <nz> ;@@ So check if we've seen it
+ Or [ESI].DDFlags,MultiMake ;@@ If we have, indicate so.
+ .Endif ;@@ Endif Multimake
+ Or DX,CX ;No, so make sure this shift key's flag is set.
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ Or [EDI].XHotKeyShift,CX ;OS2SS-@@ Also set in hot key shift state
+ .Endif
+ jmp NewLbl2
+ .Endif ;OS2SS- (A2053)## Endif Alt is down.
+ ;OS2SS- .Else ;Else process key-break.
+ .If <AL eq AltFlag> ;Check is this the AltKey?
+ Xor AL,AL ;@@ Clear out a reg
+ Xchg AL,[EDI].XAltKeyPad ;OS2SS-@@ Swap with the ALT-nnn accumulator.
+ Or AL,AL ;Check if any accumulation going on.
+ .If <nz> ;Was there?
+ Mov [ESI].Key.Char,AL ;OS2SS-Yes so make a Char from total.
+ Mov [ESI].Key.Scan,0 ;OS2SS-And make the scan code zero.
+ ;## PTR AK00370
+ Test [ESI].DDFlags,SecondaryKey ;OS2SS-## If this isn't an AltPad seq.
+ .If <z> ;## with right (secondary) Alt key.
+ And [ESI].DDFlags,Not (KeyBreak+KeyTypeMask) ;OS2SS-Fix flags.
+ .Endif ;## Endif right Alt key.
+ ;## PTR AK00370
+ Or _Ow2MiscFlags3,AltPacket ;&& DCR 1713 : Indicate that
+ ;&& we will send two packets.
+ ;@@ PTM 6860 - Begin
+ Call AccCheckout ;@@ check if accent combo going on.
+ ;@@ PTM 6860 - End
+ .Endif ;Endif accumulation going on
+ .Endif ;@@ Endif this was an ALT key
+ Mov BX,CX ;Save shift key values
+ Not CX ;Make shift flags into a mask.
+ ;@@ PTM 3905 - Topview does not send cursor key scan codes through
+ ;@@ and if this is a Ferrari keyboard, we only get E0s from the
+ ;@@ secondary cursor keys. Then if the left ALT is pressed
+ ;@@ to remove the popup, we think the ALT make was actually
+ ;@@ the right alt make because it was preceded by an E0 from a
+ ;@@ cursor key. And the break does not clear things up.
+
+ Test BL,RShiftFlag+LShiftFlag ;...is this key one of..
+ .If <z> ; ...two shift keys?
+ Test DH,BH ;@@ Check if this key is actually
+ ;@@ the one that's down
+ .If <z> ;@@ If it isn't
+ And DH,CL ;@@ Clear bit for key actually down
+ .Else ;@@ Else we've got the right key
+ And DH,CH ;Clear upper byte shift flag for this shift key.
+ .Endif
+ Test DH,AH ;Check if other shift key is down.
+ .If <z> ;Is primary or secondary shift key still down?
+ And DL,CL ;No, so clear lower byte shift flag.
+ .Endif
+
+ ;@@ PTM 4075 - A system wide word for the shift state
+ ;@@ must be maintained that is only modified by interrupts
+ ;@@ and is only used for Hot Key Checking
+
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent. ;&& translations are independent.
+ .If <nz>
+ Push EDX ;OS2SS-@@ Save new key packet shift
+ Mov DX,[EDI].XHotKeyShift ;OS2SS-@@ Get hot key shift state
+ Test DH,BH ;@@ Check if this key is actually
+ ;@@ the one that's down
+ .If <z> ;@@ If it isn't
+ And DH,CL ;@@ Clear bit for key actually down
+ .Else ;@@ Else we've got the right key
+ And DH,CH ;Clear upper byte shift flag for this shift
+ .Endif
+ Test DH,AH ;Check if other shift key is down.
+ .If <z> ;Is primary or secondary shift key still down?
+ And DL,CL ;No, so clear lower byte shift flag.
+ .Endif
+ Mov [EDI].XHotKeyShift,DX ;OS2SS-
+ Pop EDX ;OS2SS-
+ .Endif
+ .Else
+ And DL,CL ;No, so clear lower byte shift flag.
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ And Byte Ptr [EDI].XHotKeyShift,CL ;OS2SS-
+ .Endif
+ .Endif
+ ;OS2SS- .Endif
+NewLbl2: ;OS2SS-
+ Mov [ESI].Key.Shift,DX ;OS2SS-Also save in Key rec.
+
+ Test _Ow2MiscFlags3,AltPacket ;&& DCR 1713 BEGIN: Check to see if an
+ ;&& Alt-Num operation was completed.
+ .If <nz> ;&& If so then..
+ ;## PTR AK00370: BEGIN
+ Test [ESI].DDFlags,SecondaryKey ;OS2SS-## If this is an AltPad seq.
+ .If <z> ;## with Left (normal) Alt key.
+ Call AltPadPacket ;&& setup second of two packets for
+ ;&& Alt-Numpad sequence.
+ .Else ;## Else this is an AltPad seq. with
+ ;## the right (secondary) Alt key.
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-## If this is a break for the right
+ .If <nz> ;## Alt key then...
+ Or _Ow2MiscFlags3, SecAltNumPad ;## Flag that we will have to send an
+ .Endif ;## accumulation packet after break
+ ;## of the Alt key in Int Handler.
+ .Endif ;## PTR AK00370: END
+ .Endif ;&& DCR 1713: END
+ ;## AltPadPacket is only called for
+ ;## AltNumPad seq. with left Alt. key.
+ ;## PTR AK00370: END
+
+ Jmp EndActionCase ;Go to bottom of Xlate Action case table.
+
+ScrollLock: ;The SCROLL LOCK key.
+ ;@@ This is special case of ToggleKeys because of Ctl-Break.
+ ;@@ On an Enhanced keyboard, the Ctl-Break sends the following
+ ;@@ set of scan codes:
+ ;@@ Ctrl make-E0-ScrollLock make-E0-ScrollLock break-Ctrl break
+ ;@@ so we must check if it was an AT keyboard or preceded by EO
+ ;@@ before identifying it as Ctl-Break.
+
+ And [EDI].XlateFlags,NOT DumpKeyOnce ;OS2SS-@@ Cancel Dump sequence.
+ Test [EDI].XlateFlags,SecPrefix ;OS2SS-@@ Check if secondary key
+ .If <nz> OR ;@@ If it is OR...
+ Test _Ow2MiscFlags,EnhancedKbd ;@@ Check if enhanced kbd
+ .If <z> OR ;@@ OR...If it's a regular kbd
+;$$
+;$$ 'IDFlags' does not exist in the 1.2 ABIOS
+;$$ version. We need to get this information from KbdHWIDs.
+;$$
+
+;$$ Test IDFlags, SuperSport ;## Check if it is a 122 kbd
+
+ .If < _Ow2KbdHWIDs e 0AB85h > ;$$ If it is a 122 kbd
+
+ Test DL,CtlFlag ;Check if Ctl also pressed.
+ ;@@ for this KCB
+ ;@@ PTM 5992 - Begin
+ .If <nz> OR ;@@ Is it OR?
+ Test [EDI].XHotKeyShift,CtlFlag ;OS2SS-@@ Also check in interrupt shift
+ ;@@ state
+ .If <nz> AND ;@@ Is it being held down at all
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ ;@@ PTM 5992 - End
+ Mov [ESI].Key.Scan,0 ;OS2SS-Set Ctl-Break extended code.
+ ;Tell dev driver it's the BREAK KEY.
+ Or [ESI].DDFlags,BreakKey ;OS2SS-@@
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-Check if this is the key break.
+ .If <nz> ;If so, clear Scroll Lock down bit in Packet & PSG.
+ And Byte Ptr [ESI].Key.Shift+1,Not (ScrollFlag ShR 8)
+ ;OS2SS-@@ Clear bit in hot key shift status also
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ And Byte Ptr [EDI].XHotKeyShift+1,Not (ScrollFlag ShR 8) ;OS2SS-
+ .Endif
+ .Else ;Set Scroll Lock down bit in packet & PSG.
+ Or Byte Ptr [ESI].Key.Shift+1,(ScrollFlag ShR 8)
+ ;OS2SS-@@ Set bit in hot key shift status also
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ Or Byte Ptr [EDI].XHotKeyShift+1,(ScrollFlag ShR 8) ;OS2SS-
+ .Endif
+ .Endif
+ Jmp EndActionCase ;@@ PTM 4106: Leave translation.
+ .Else ;Not Ctl-Break, fall thru to ToggleKey processing.
+ Jmp ToggleKey ;@@
+ .Endif
+ .Else ;Not Ctl-Break, fall thru to ToggleKey processing.
+ Jmp ToggleKey ;@@
+ .Endif
+NumLock: ;The NUMLOCK key.
+ ;@@ We must check if this is the Enhanced keyboard
+ ;@@ which will emulate Ctrl being down (PseudoCtl Flag
+ ;@@ will be set) for the PAUSE key or an AT kbd w/ Ctl down.
+
+ Test [EDI].XlateFlags,PseudoCtl ;OS2SS-@@ Check if secondary kbd
+ ;@@ emuating the Ctl key
+ .If <nz> OR ;@@ If it is OR...
+ ;## PTM 3128 BEGIN:
+ .If <_Ow2KbdHWIDs ne FERRARI_P> AND ;## If it's not an 88/89 AND
+ .If <_Ow2KbdHWIDs ne FERRARI_G> AND ;## If it's not a 101/102 AND
+ .If <BX ne JAGUAR> AND ;1.3-## If it's not a 122 Key JAGUAR
+ ;## PTM 3128 END:
+ Test DL,CtlFlag ;@@ Check if Ctl also pressed.
+ ;@@ for this KCB
+ ;@@ PTM 5992 - Begin
+ .If <nz> OR ;@@ Is it OR?
+ Test [EDI].XHotKeyShift,CtlFlag ;OS2SS-@@ Also check in interrupt shift
+ ;@@ state
+ .If <nz> AND ;@@ Is it being held down at all
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ ;@@ PTM 5992 - End
+ ;@@ PTM 4004:
+ Test DL, AltFlag ;@@ Check for Alt key down.
+ .If < z > ;@@ No alt key, process Ctl-NumLk,
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-@@ Check if this is a key break
+ .If <nz>
+ And [EDI].XlateFlags,Not PseudoCtl ;OS2SS-@@ Clear flag
+
+ Test _Ow2MiscFlags3,PauseLatch ;&& PTM 2344 BEGIN: If the NumLock
+ ;&& make preceded the Ctrl make
+ .If <z> ;&& then this is not the break of
+ ;&& of a Pause. Therefore do not
+ ;&& throw the key away. Treat it
+ Jmp ToggleKey ;&& as a normal shift break.
+ .Endif ;&& Endif this was not the Pause.
+ And _Ow2MiscFlags3,Not PauseLatch ;&& Reset the Pause sequence flag.
+ ;&& PTM 2344 END:
+
+ Jmp NoXlate ;@@ Mark Key Packet undefined
+ .Else ;@@ Else it's a make scan code
+ Or [ESI].DDFlags,PauseKey ;OS2SS-@@ So tell dd it's the PAUSE KEY.
+ Or _Ow2MiscFlags3,PauseLatch ;&& PTM 2344: Flag the make of the
+ ;&& NumLock to be used as a latch.
+ Jmp EndActionCase ;@@ Completed translation
+ .Endif ;@@ Endif key break or not
+ .Else ;&& PTM 2383: Else Alt is down
+ And [EDI].XlateFlags,Not PseudoCtl ;OS2SS-@@ Clear flag
+ Test DL,CtlFlag ;&& so test if Ctrl is also down.
+ .If <z> ;&& If Ctrl is not down then the
+ Jmp NoXlate ;&& key sequence Alt-Pause Key
+ ;&& is undefined.
+ .Endif ;&& Endif Ctrl is down with Alt.
+ .Endif ;@@ End alt key down check. PTM 4004
+ .Endif
+ Test DL,CtlFlag ;Check if Ctl also pressed.
+ ;@@ for this KCB
+ ;@@ PTM 5992 - Begin
+ .If <nz> OR ;@@ Is it OR?
+ Test [EDI].XHotKeyShift,CtlFlag ;@@ Also check in interrupt shift
+ ;@@ state
+ .If <nz> AND ;@@ Is it being held down at all
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ ;@@ PTM 5992 - End
+ Test DL,AltFlag ;Yes, check Alt key also.
+ .If <nz> ;Is it?
+ Test [EDI].XlateFlags,DumpKeyOnce ;OS2SS-@@ Yes check if second time.
+ .If <nz> ;Is it?
+ Or [ESI].DDFlags,DumpKey ;OS2SS-@@ So tell dd it's the DUMP KEY.
+ .Else
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-Check if this's key break.
+ .If <nz> ;Is it?
+ Or [EDI].XlateFlags,DumpKeyOnce ;OS2SS-@@ Yes indicate seen once.
+ .Endif
+ .Endif
+ .Endif
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-Check if this's the key break.
+ .If <nz> ;If so, clear Num Lock down bit in Packet & PSG.
+ And Byte Ptr [ESI].Key.Shift+1,Not (NumFlag ShR 8)
+ ;@@ Clear bit in hot key shift status also
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ And Byte Ptr [EDI].XHotKeyShift+1,Not (NumFlag ShR 8) ;OS2SS-
+ .Endif
+ Test [EDI].XlateFlags,DumpKeyOnce ;OS2SS-@@ PTM 7078 - Begin
+ .If <z> ;@@ If this wasn't the dump key
+ Or [ESI].DDFlags,ShiftMask ;OS2SS-@@ PTM 6937
+ ;@@ Indicate this is a shift key.
+ .Endif ;@@ PTM 7078 - End
+
+ Test _Ow2MiscFlags3,PauseLatch ;&& PTM 2344 BEGIN: If the NumLock
+ ;&& make preceded the Ctrl make
+ .If <z> ;&& then this is not the break of
+ ;&& of a Pause. Therefore do not
+ ;&& throw the key away. Treat it
+ Jmp ToggleKey ;&& as a normal shift break.
+ .Endif ;&& Endif this was not the Pause.
+ And _Ow2MiscFlags3,Not PauseLatch ;&& Reset the Pause sequence flag.
+ ;&& PTM 2344 END:
+
+ .Else ;Set Num Lock down bit in packet & PSG.
+ Or Byte Ptr [ESI].Key.Shift+1,(NumFlag ShR 8) ;OS2SS-
+ ;@@ Set bit in hot key shift status also
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ Or Byte Ptr [EDI].XHotKeyShift+1, (NumFlag ShR 8) ;OS2SS-
+ .Endif
+ Test [EDI].XlateFlags,DumpKeyOnce ;OS2SS-@@ PTM 7078 - Begin
+ .If <z> ;@@ If this wasn't the dump key
+ Or [ESI].DDFlags,ShiftMask ;OS2SS-@@ PTM 6937
+ ;@@ Indicate this is a shift key.
+ .Endif ;@@ PTM 7078 - End
+ Or _Ow2MiscFlags3,PauseLatch ;&& PTM 2344: Flag the make of the
+ ;&& NumLock to be used as a latch.
+ .Endif
+ .Else NEAR ;Not Ctl-Numlock, fall thru to common Toggle key check.
+
+CapsLock: ;The CapsLock key itself.
+ToggleKey: ;Or any general Toggle key.
+ Mov EBX,[EBP-8] ;OS2SS-Get translate table offset.
+ Test [ESI].DDFlags,SecondaryKey ;OS2SS-Check if G kbd dup key.
+ .If <nz> ;Is it?
+ Mov CH,[EBX].Char3 ;OS2SS-Yes, so get mask for that key.
+ .Endif
+ And [EDI].XlateFlags,NOT DumpKeyOnce ;OS2SS-@@ Cancel Dump sequence.
+ Mov EBX,[EBP-4] ;OS2SS-Get translate table offset.
+ Or [ESI].DDFlags,ShiftMask ;OS2SS-@@ Indicate this is a shift key.
+ Test Word Ptr [EBX+XTFlags1],ShiftLock ;OS2SS-ShiftLock type?
+ .If <nz> AND ;Is it shift lock and...
+ Test Word Ptr [EBX+XTFlags1],ShiftToggle ;OS2SS-@@ ShiftLock Toggle?
+ .If <z> AND ;@@ Is it shift lock latch and...
+ .If <AL eq CapsTogl> ;...is it the CapsLock key?
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-Check for the key BREAK.
+ .If <z> ;If not, set ShiftLock on.
+ Or [ESI].Key.Shift,CX ;OS2SS-And in the Key rec.
+ ;@@ Set bit in hot key shift status also
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ Or [EDI].XHotKeyShift,CX ;OS2SS-
+ .Endif
+ .Else ;On key-break, only clear DOWN bit.
+ Not CX ;Make shift bits a mask.
+ And Byte Ptr [ESI].Key.Shift+1,CH ;OS2SS-And in the Key rec.
+ ;@@ Clear bit in hot key shift status also
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ And Byte Ptr [EDI].XHotKeyShift+1,CH ;OS2SS-
+ .Endif
+ .Endif
+ .Else ;This is not a shift-lock keyboard.
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-Check for the key BREAK.
+ .If <nz> ;Is it?
+ Not CX ;Yes, so make shift bits a mask.
+ And Byte Ptr [ESI].Key.Shift+1,CH ;OS2SS-And in the Key rec.
+
+ ;@@ Clear bit in hot key shift status also
+
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ And Byte Ptr [EDI].XHotKeyShift+1,CH ;OS2SS-
+ .Endif
+ And [EDI].ToggleFlags,CL ;OS2SS-@@ Clear latch for this key.
+ .Else
+ Or Byte Ptr [ESI].Key.Shift+1,CH ;OS2SS-And in the Key rec.
+
+ ;@@ Set bit in hot key shift status also
+
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ Or Byte Ptr [EDI].XHotKeyShift+1,CH ;OS2SS-
+ .Endif
+ Test [EDI].ToggleFlags,CL ;OS2SS-@@ Check if seen this key yet.
+ .If <z> ;Have we?
+ Or [EDI].ToggleFlags,CL ;OS2SS-@@ No so set latch saying we have.
+ Xor Byte Ptr [ESI].Key.Shift,CL ;OS2SS-And in the Key rec.
+ ;@@ Set Latch in hot key shift status also
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-&& PTM 3191: Make sure KBDXlate
+ ;&& translations are independent.
+ .If <nz>
+ Xor Byte Ptr [EDI].XHotKeyShift,CL
+ .Endif
+ .Else ;Otherwise this is a repeat of the make.
+ Or [ESI].DDFlags,MultiMake ;OS2SS-So indicate so.
+ .Endif
+ .Endif
+ .Endif
+ .Endif ;Endif from NumLock plus Ctl test above.
+ Jmp EndActionCase ;Go bottom of Xlate Action case table.
+
+SpecKeyCS: ;@@ Special key for NLS support.
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-@@ If it's interrupt time
+ .If <nz> ;@@
+ Call UnPauseChk ;Go check if in pause state.
+ .Endif ;@@
+ Test DL,AltFlag ;@@ Check if Alt key down.
+ .If <nz> ;@@ Is it?
+ And [EDI].XlateFlags,Not Use3Index ;OS2SS-@@ Use Char3 if AltGraph
+ Call AltGraphCheck ;@@ Process if AltGraph
+ Test [EDI].XlateFlags,NormalAlt ;OS2SS-@@ Check if it's not the AltGraph
+ .If <nz> ;@@ If alt key is normal Alt
+ ;@@ PTM 5024 - Begin
+ Call CheckExtended ;@@ See if new extended code
+ ;@@ is defined
+ .If <c> ;## If it is ...
+ Jmp EndActionCase ;## the key combo is defined
+ .Endif ;## Endif there was one defined
+ Jmp NoXlate ;## get out now.
+ .Endif ;## Endif normal Alt.
+ Jmp SKCSEnd ;##
+ .Else NEAR ;@@ Else no Alt key down
+ Test DL,RShiftFlag+LShiftFlag ;@@ Is a shift key down
+ Mov EBX,[EBP-8] ;OS2SS-Get translate table offset.
+ .If <nz> ;@@ Yes so,
+ Test DL,CapsTogl ;@@ See if capslock is on
+ .If <nz> ;@@ If it is
+ Mov AL,[EBX].Char5 ;OS2SS-@@ Use character 5
+ .Else ;@@ If it is not then...
+ Mov AL,CH ;@@ Use char 2
+ .Endif ;@@ Endif CapsLock is on.
+ .Else NEAR ;@@ Else no shift key down
+ Test DL,CapsTogl ;@@ See if capslock is on
+ .If <nz> ;@@ If it is
+ Mov AL,[EBX].Char4 ;OS2SS-@@ Use character 4
+ .Endif
+ .Endif ;## Endif shift key down.
+ Test DL, CtlFlag ;## Check if Ctrl is down,
+ .If <nz> ;## If it is then...
+ Call SKCtlCheck ;## Check for spec. Ctrl code.
+ .Endif ;## Endif Ctrl is down.
+ .Endif ;## Endif Alt is down.
+SKCSEnd:
+ .If <AL b 8> AND ;## If this was an accent key index
+ .If <AL a 0> ;##
+ Or [ESI].DDFlags,AccentKey ;OS2SS-## Indicate this is an
+ ;## unprocessed accent.
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-## Check for the key BREAK.
+ .If <z> ;## Is it?
+ And [EDI].XPSGFlags,Not PrevAccent;OS2SS-## No, clear prev accent num
+ Or Byte Ptr [EDI].XPSGFlags,AL ;OS2SS-## Save accent num for next key
+ .Endif
+ .Else ;## Else this is not an accent table entry
+ Mov [ESI].Key.Char,AL ;OS2SS-## Put character into key packet
+ Call AccCheckOut ;## Check for valid accent
+ .Endif ;## Endif this is an accent index.
+ Jmp EndActionCase ;## Go to bottom of Xlate Action case table.
+
+SpecKeyAS: ;@@ Special key for NLS support.
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-@@ If it's interrupt time
+ .If <nz> ;@@
+ Call UnPauseChk ;Go check if in pause state.
+ .Endif ;@@
+ Test DL,AltFlag ;@@ Check if Alt key down.
+ .If <nz> ;@@ Is it?
+ And [EDI].XlateFlags,Not Use3Index ;OS2SS-@@ Use Char3 if AltGraph
+ Call AltGraphCheck ;@@ Process if AltGraph
+ Test [EDI].XlateFlags,NormalAlt ;OS2SS-@@ Check if it's not the AltGraph
+ .If <nz> ;@@ If alt key is normal Alt
+ Mov EBX,[EBP-8] ;OS2SS-Get translate table offset.
+ Mov AL,[EBX].Char4 ;OS2SS-@@ Use char4
+ Mov [ESI].Key.Scan,AL ;OS2SS-@@ Put it in the scan code field to
+ Jmp SpecKeyEnd ;@@ Go to merge
+ .Endif
+ .Else ;@@ Else no Alt key down
+ Test DL,RShiftFlag+LShiftFlag ;@@ Is a shift key down
+ .If <nz> ;@@ Yes so,
+ Mov AL,CH ;@@ Use char 2
+ Jmp SpecKeyEnd ;@@ Go to merge
+ .Endif ;@@ Else no shift key down
+ .Endif ;## Endif Alt key down.
+ Test DL, CtlFlag ;## Check if Ctrl is down
+ .If <nz> ;## If it is then...
+ Call SKCtlCheck ;## Check for special control code.
+ .Endif ;## Endif Ctrl is down
+
+SpecKeyEnd:
+ .If <AL b 8> AND ;@@ If this was an accent key index
+ .If <AL a 0>
+ Or [ESI].DDFlags,AccentKey ;OS2SS-@@ Indicate this is an
+ ;@@ unprocessed accent.
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-@@ Check for the key BREAK.
+ .If <z> ;@@ Is it?
+ And [EDI].XPSGFlags,Not PrevAccent ;OS2SS-## No, clear prev accent num
+ Or Byte Ptr [EDI].XPSGFlags,AL ;OS2SS-## Save accent num for next key
+ .Endif
+ .Else ;## Else this is not an accent table entry
+ Mov [ESI].Key.Char,AL ;OS2SS-## Put character into key packet
+ Call AccCheckOut ;## Check for vaild accent.
+ .Endif ;## Endif this is an accent table entry.
+ Jmp EndActionCase ;## Go to bottom of Xlate Action case table.
+
+XShiftKey: ;Extended shift key (for DBCS use).
+XToggleKey: ;Extended toggle key (for DBCS use).
+
+NoXlate: ;Invalid action code, no translate done.
+ And [EDI].XlateFlags,NOT DumpKeyOnce ;OS2SS-@@ Cancel Dump sequence.
+ Or [ESI].DDFlags,UndefKey ;OS2SS-@@ Mark this key undefined.
+
+
+EndActionCase: ;*** This is the end of the Xlate Action case table ***.
+
+ Test [ESI].DDFlags, UndefKey ;OS2SS-## DCR 357: BEGIN
+ .If <z> AND ;## This logic tests to see if the
+ Test _Ow2MiscFlags3, AltPacket ;## current keypacket is for an
+ .If <z> ;## extended keystroke or not.
+ Mov BL,[ESI].Key.Char ;OS2SS-## If it is then bit 1 of the Status
+ .If <BL eq 0> OR ;## field in the keypacket is turned
+ Test [EDI].XlateFlags, SecPrefix ;OS2SS-## on.
+ .If <nz> ;##
+ Or [ESI].Key.Status, EXTENDEDCODE ;OS2SS-## Turn the bit on in the Status.
+ .Endif ;##
+ .Endif ;## DCR 357: END
+ ;## PTR B702484: BEGIN
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-@@ If it's interrupt time
+ ;## create an extra packet for the E0.
+ .If <nz> AND ;## PTR B702484: END
+ Test [EDI].XlateFlags,SecPrefix ;OS2SS-&& PTM 2382: Test to see if an E0 or E1
+ ;&& came before this packet.
+ .If <nz> AND ;&& If E0 or E1 did precede then,
+ Test [EDI].XlateFlags, E1Prefix ;OS2SS-&& Check to see if it was an E0.
+ .If <z> ;&& If it was the E0 then,
+ Or _Ow2MiscFlags3, E0Packet ;&& signal an E0 packet coming up.
+ Call MakeE0Packet ;&& Call MakeE0Packet to manufacture an
+ ;&& extra packet to precede this one.
+ .Endif ;&& Endif an E0 preceded this packet.
+
+
+ Mov BX,[ESI].DDFlags ;OS2SS-&& PTM 965 - Always zero out
+ .If <BX eq ShiftMask> OR ;&& char and scan fields for
+ .If <BX eq ShiftMask+KeyBreak> OR ;&& shift packets
+ .If <BX eq ShiftMask+SecondaryKey> OR
+ .If <BX eq ShiftMask+KeyBreak+SecondaryKey>
+ Mov Word Ptr [ESI].Key.Char, 0 ;OS2SS-@@ PTM 2244: Zero out Character/
+ ;@@ Scan Code fields in CharData
+ ;@@ Record for Japan compatability.
+ And [ESI].Key.Status, NOT EXTENDEDCODE
+ ;OS2SS-## DCR 357: Do NOT indicate that this
+ ;## is an extended scan instead of
+ ;## an E0 char., if this is a shift pac.
+ Test [EDI].XInputMode,SHIFTREPORT ;OS2SS-&& (P13303) Are we in Shift rep. mode?
+ .If <nz> ;@@ If so......
+ Or [ESI].Key.Status,1 ;OS2SS-@@ Flag as shift report packet
+ .Endif ;@@ Endif Shift Report
+ .Endif ;@@ Endif Shift Report
+ And [EDI].XlateFlags,Not SecPrefix+E1Prefix ;OS2SS-Clear indicator.
+ Mov AL,Byte Ptr [ESI].MonFlags+1 ;OS2SS-Get the original scan code back.
+ Stc ;OS2SS-
+ Ret
+
+KbdXlate Endp ;-------------------------------------------------------/
+
+Public CapsCheck
+CapsCheck Proc ;-----------------------------------------------------\
+;************** START OF SPECIFICATIONS ********************************
+;* *
+;* Subroutine Name: CapsCheck *
+;* *
+;* Descriptive Name: Check IF character should be shifted *
+;* *
+;* Function: This routine checks IF a characer should be shifted. *
+;* It checks IF CapsLock, ShiftLock or the shift key *
+;* effect this key. IF the char should be shifted, *
+;* then it places Char2 in AL. *
+;* *
+;* Notes: *
+;* *
+;* Entry Point: CapsCheck Linkage: Near *
+;* *
+;* Input: AL = CHAR1 from translate table *
+;* CH = CHAR2 from translate table *
+;* DX = ShiftFlags *
+;* AH = Scan code w/ break bit cleared *
+;* BX = SHIFTLOCK & CAPSLOCK effect indicators *
+;* *
+;* Exit-Normal: AL = ASCII character after shift checking *
+;* *
+;* Exit-Error: None *
+;* *
+;* Effects: AX, BX, registers, carry flag changed. *
+;* *
+;* Internal References: *
+;* Routines: None *
+;* *
+;* External References: *
+;* Routines: None *
+;* *
+;***********************************************************************
+
+ Xor BH,BH ;## Prepare a byte.
+ Test DL,RShiftFlag+LShiftFlag ;## Check if Shift key down.
+ .If <nz> ;## Is one of them?
+ Or BH,CapsTogl ;## Yes, so prepare to check Capslock.
+ .Endif ;## Endif a shift key is down
+ And DL,BL ;## Isolate Capslock flag.
+ Push EBX ;OS2SS-## Save BX for now
+ Mov EBX,[EBP-4] ;OS2SS-## And put it in BX
+ Test [EBX].XTFlags1,ShiftLock ;OS2SS-## Check if Shiftlock kbd
+ Pop EBX ;OS2SS-## Restore BX
+ .If <nz> ;## If it is then...
+ Test BL, CapsTogl ;## Check if shift lock effects key type.
+ .If <nz> ;## If it does then...
+ Or BH,DL ;## either Capslock, Shift,
+ ;## or both will cause shifting
+ .Else ;## If it does not
+ Or BH,BH ;## fix the zero flag.
+ .Endif ;## Endif shift lock effects key type.
+ .Else ;## Else its a CapsLock kbd
+ Test BL, CapsTogl ;## Check if CapsLock effects key type.
+ .If <nz> ;## If it does then...
+ Xor BH,DL ;## Add Capslock & ShiftFlag to decide state.
+ .Else ;## If it does not
+ Or BH,BH ;## fix the zero flag.
+ .Endif ;## Endif CapsLock effects key type.
+ .Endif ;## Endif shift lock keyboard.
+ .If <nz> ;## Should key be capitalized?
+ Mov AL,CH ;## Yes, so use Char2.
+ .Endif ;##
+ Ret
+
+CapsCheck Endp ;-------------------------------------------------------/
+
+Public SKCtlCheck
+SKCtlCheck Proc ;-----------------------------------------------------\
+;************** START OF SPECIFICATIONS ********************************
+;* *
+;* Subroutine Name: SKCtlCheck *
+;* *
+;* Descriptive Name: Check IF character has special control code *
+;* *
+;* Function: This routine checks IF a character or scan code has a *
+;* special control code associated with it. *
+;* IF it does then it sets the appropriate ASCII/scan *
+;* codes. *
+;* *
+;* Notes: Ctl key is already known to be down *
+;* *
+;* Entry Point: SKCtlCheck Linkage: Near *
+;* *
+;* Input: AH = Scan code w/ break bit cleared *
+;* *
+;* Exit-Normal: AL = ASCII character after special control code check *
+;* *
+;* Exit-Error: None *
+;* *
+;* Effects: AX *
+;* *
+;* Internal References: *
+;* Routines: None *
+;* *
+;* External References: *
+;* Routines: None *
+;* *
+;***********************************************************************
+
+ .If <AH eq 3> ;@@ Is this Ctl-2?
+ Xor AL,AL ;@@ Yes, so set extended code.
+ .ElseIf <AH eq 7> ;@@ Is this Ctl-6?
+ Mov AL,30 ;@@ Yes, so set ASCII "RS" code.
+ ;@@ PTR B702484 and PTM 5024 - Begin
+ .ElseIf <AH eq 15> ;@@ Is this Ctl-Tab?
+ Xor AL,AL ;@@ Yes, so set extended code.
+ Mov [ESI].Key.Scan,94h ;OS2SS-@@ Yes, so set extended code.
+ ;@@ PTR B702484 and PTM 5024 - End
+ .ElseIf <AH eq 26> ;@@ Is this Ctl-[?
+ Mov AL,27 ;@@ Yes, so set "Esc" code.
+ .ElseIf <AH eq 27> ;@@ Is this Ctl-]?
+ Mov AL,29 ;@@ Yes, so set ASCII "GS" code.
+ .ElseIf <AH eq 43> ;@@ Is this Ctl-\?
+ Mov AL,28 ;@@ Yes, so set ASCII "FS" code.
+ .ElseIf <AL eq "-"> ;@@ Is this Ctl-dash?
+ Mov AL,31 ;@@ Yes, so set ASCII "US" code.
+ ;1.3-## PTR 4862 BEGIN:
+ .ElseIf <AH eq 12> ;1.3-## Is this the key for scan code 12.
+ Mov AL,31 ;1.3-## Yes, so set ASCII "US" code.
+ ;1.3-## PTR 4862 END.
+ .ElseIf <AL eq " "> ;@@ Is this the space key?
+ ;Value in AL is correct. ;@@ Yes, so leave as is.
+ .Else ;@@ If here, combo is undefined.
+ Mov AL, -1 ;@@ Go mark Undefined.
+ Or [ESI].DDFlags,UndefKey ;OS2SS-## PTR B702142 Mark this key undefined.
+ .Endif ;@@
+ Ret ;@@ Endif Ctl key down check
+
+SKCtlCheck Endp ;-------------------------------------------------------/
+
+Public SKAltCheck
+SKAltCheck Proc ;-----------------------------------------------------\
+;************** START OF SPECIFICATIONS ********************************
+;* *
+;* Subroutine Name: SKAltCheck *
+;* *
+;* Descriptive Name: Check IF character has extended code *
+;* *
+;* Function: This routine checks IF a characer or scan code has a *
+;* special extended code associated with it. *
+;* IF it does then it sets the appropriate ASCII/scan *
+;* codes. *
+;* *
+;* Notes: Alt key is already known to be down *
+;* *
+;* Entry Point: SKAltCheck Linkage: Near *
+;* *
+;* Input: DI = Per Session Data Area Address *
+;* SI = Key Packet Address *
+;* DX = ShiftFlags *
+;* AH = Scan code w/ break bit cleared *
+;* *
+;* Exit-Normal: AL = ASCII character after special control code check *
+;* *
+;* Exit-Error: None *
+;* *
+;* Effects: AX, BX, registers, carry flag changed. *
+;* *
+;* Internal References: *
+;* Routines: AltGraphCheck CheckExtended *
+;* *
+;* External References: *
+;* Routines: None *
+;* *
+;***********************************************************************
+
+ And [EDI].XlateFlags,Not Use3Index ;OS2SS-@@ Use Char3 if AltGraph
+ Call AltGraphCheck ;@@ Process if AltGraph
+ Test [EDI].XlateFlags,NormalAlt ;OS2SS-@@ Check if it's not the AltGraph
+ .If <nz> ;@@ If alt key is normal Alt
+ .If <AL eq " "> ;@@ Is this the space key?
+ Mov [ESI].Key.Char,AL ;OS2SS-@@ Yes, so leave as is.
+ ;@@ PTM 5024 - Begin
+ .Else ;@@ Set extended code for others
+ Call CheckExtended ;@@ Go check if this is new extended
+ ;@@ scan code
+ .If <nc> ;@@ If it is, everything is set up
+ ;@@ otherwise it's old so
+ Add AH,118 ;@@ calculate extended code.
+ Mov [ESI].Key.Scan,AH ;OS2SS-@@ Put extended code in Key rec.
+ .Endif
+ ;@@ PTM 5024 - End
+ .Endif
+ .Else ;@@ else it was AltGraph
+ Mov [ESI].Key.Char,AL ;OS2SS-@@ Yes, so leave as is.
+ .Endif ;@@ Endif UNDEFINED or normal ALT
+ Ret
+
+SKAltCheck Endp ;-----------------------------------------------------/
+
+Public AccCheckOut
+AccCheckout Proc ;-----------------------------------------------------\
+;***********************************************************************
+;* *
+;* Subroutine Name: AccCheckout *
+;* *
+;* Descriptive Name: Check and Process Valid Accents *
+;* *
+;* Function: This routine is called from KbdXlate and checks if an *
+;* accent key was hit prior to the current key. If so, *
+;* a check is made to see if the key is affected by that *
+;* accent and if it is *
+;* the value specified by the accent table entry is put in *
+;* the key packet and control returns to KbdXlate. *
+;* If the key is not affected by that accent, then it is *
+;* put in a seperate keypacket and control returns to *
+;* KbdXlate to process the current key. *
+;* *
+;* Entry Point: AccCheckout Linkage: Near *
+;* *
+;* Input: Beginning offset of translate table on the stack *
+;* *
+;* Exit-Normal: Monitor Key Packet filled in *
+;* *
+;* Exit-Error: N/A *
+;* *
+;* Effects: BX *
+;* *
+;* Internal References: *
+;* Routines: BadAccent *
+;* *
+;* External References: *
+;* Routines: None *
+;* *
+;***********************************************************************
+
+
+ ;Check if last key seen was an accent key.
+ Push EBX ;OS2SS-@@ Save BX
+ Mov BX,[EDI].XPSGFlags ;OS2SS-&& Get flags from PSG.
+ And BX,PrevAccent ;&& Isolate previous accent number
+ ;&& field.
+ .If <nz> NEAR ;Was there one?
+ Push EDI ;OS2SS-Yes, save index reg for now.
+
+ ;Translate table offset now four words back on the stack.
+
+ And EBX,0FFh ;OS2SS-Clear upper byte of accent number.
+ Mov EDI,EBX ;OS2SS-Put accent number in index reg.
+ Dec EDI ;OS2SS-Accent entry 1 has offset zero.
+ IMul EDI,AccEntryLen ;OS2SS-Set offset of correct accent table entry.
+ Add EDI,Accents ;OS2SS-Set offset within overall translate table.
+ Add EDI,[EBP-4] ;OS2SS-Add offset of translate table itself.
+ Push ECX ;OS2SS-And save...
+ Push EDX ;OS2SS-..other regs.
+ Mov EDX,[EBP-8] ;OS2SS-Get Xlate Operation word.
+ Mov DX,[EDX].XlateOp ;OS2SS-Get Xlate Operation word.
+ Mov CL,7 ;Set # of bits to highest accent no.
+ Sub CL,BL ;Subtract actual accent number.
+ Mov EBX,EDI ;OS2SS-Save accent table entry offset.
+ Or DX,DX ;## PTM 2329: Make sure that if the max. number
+ ;## of accents are used that the flags bits are
+ ;## correctly for DX.
+ Shl DX,CL ;Shift Accent Flags left by calculated count.
+ .If <ns> ;So is this key affected by the previous accent?
+ Mov ECX,[EBP-4] ;OS2SS-@@ Get the XT header
+ Mov CX,[ECX].XTFlags1 ;OS2SS-@@ Get the XT header flags.
+ Mov EDI,[ESP+8] ;OS2SS- Restore OtherFlag index.
+ Call BadAccent ;No! Go take care of things.
+ .Else ;Accent flags say this key is accented.
+ Pop EDX ;OS2SS-Restore shift flags for now.
+ Push EDX ;OS2SS-But leave them saved.
+ Push EAX ;OS2SS-Save AX for now.
+ Mov AL,[ESI].Key.Char ;OS2SS-@@ PTM 6860
+ Mov ECX,20 ;OS2SS-Set max pairs in Accent table entry.
+ Add EDI,AcMap1 ;Point to first pair in accent table entry.
+TLoop: ;Top of loop looking for current scan code in accent table entry.
+ Mov DX,[EDI] ;OS2SS-Pick up next pair.
+ .If <DX eq 0> ;@@ PTM 6860 - Begin If we are at the end
+ ;@@ of the list
+ Mov ECX,1 ;OS2SS-@@ Set end of loop condition
+ .ElseIf <AL eq DL> ;@@ Else Have we found a match?
+ Jmp Short XLoop ;Yes, so exit from loop.
+ .Endif
+ Add EDI,2 ;Increment our pointer.
+ Loop TLoop ;Repeat.
+XLoop: Or CX,CX ;Check if no match before end of entry.
+ .If <z> ;Is that true?
+ Mov ECX,[EBP-4] ;OS2SS-@@ Get the XT header
+ Mov CX,[ECX].XTFlags1 ;OS2SS-@@ Get the XT header flags.
+ Mov EDI,[ESP+12] ;OS2SS- Restore OtherFlag index.
+ Call BadAccent ;No! Go take care of things.
+ .Else ;Else we found our accented character value!
+ Mov [ESI].Key.Char,DH ;OS2SS-Put it in CharData rec.
+; Mov [ESI].Key.Scan,0 ;OS2SS-Zero scan code for accented chars.
+ Or [ESI].DDFlags,AccentedKey ;OS2SS-Indicate accent affected key.
+ .Endif
+ Pop EAX ;Restore AX.
+ .Endif
+ Pop EDX ;Restore the...
+ Pop ECX ;..altered regs.
+ Pop EDI ;Restore PSG index.
+ And [EDI].XPSGFlags,Not PrevAccent ;OS2SS-@@ Clear previous accent field.
+ .Endif
+ Pop EBX ;@@ Restore BX
+ Test [ESI].DDFlags,AccentedKey ;OS2SS-Check if accent affected key.
+ .If <nz> OR ;Did it?
+ .If <[ESI].DDFlags e BadKeyCombo> ;OS2SS-@@ check if this was an invalid combo?
+ Pop EBX ;OS2SS-Throw away original return address.
+ Jmp EndActionCase ;And quit now.
+ .Endif
+ Ret ;Else return.
+
+AccCheckout Endp ;-----------------------------------------------------/
+
+Public BadAccent
+BadAccent Proc ;------------------------------------------------------\
+
+;***********************************************************************
+;* *
+;* Subroutine Name: BadAccent *
+;* *
+;* Descriptive Name: Process an Accent that does Not Apply to a Char *
+;* *
+;* Function: Set up a KeyPacket that must be passed as a standalone *
+;* character *
+;* *
+;* Entry Point: BadAccent Linkage: Near *
+;* *
+;* Input: SI = @ of KeyPacket *
+;* Empty KeyPacket2 immediately follows KeyPacket *
+;* ES:BX = @ of Accent Table Entry for accent to pass *
+;* CX = Translate Table Header Flags *
+;* *
+;* Exit-Normal: Monitor Key Packet filled in *
+;* *
+;* Exit-Error: N/A *
+;* *
+;* Effects: CX *
+;* *
+;* Internal References: *
+;* Routines: CopyPacket *
+;* *
+;* External References: *
+;* Routines: None *
+;* *
+;***********************************************************************
+ Push ESI ;OS2SS-
+ Push EDI ;OS2SS-
+ Test CX,AccentPass ;@@ Check if key packets should be passed
+ .If <z> OR ;@@ If not... OR
+ Test [EDI].OtherFlags,InterruptTime ;OS2SS-@@ If it's interrupt time
+ .If <z> ;@@ Tell Int Handler to beep
+ Mov [ESI].DDFlags,BadKeyCombo ;OS2SS-@@ or strategy proc to return invalid parm.
+ .Else ;@@ Else key packets should be passed
+ Call CopyPacket ;&& PTM 2382: Make a copy of the first
+ ;&& packet into the extra packet.
+
+ ;Now ESI has incremented to point to KeyPacket2.
+ Mov Byte Ptr [ESI].MonFlags+1,0 ;OS2SS-Zero the original scan code field.
+ Mov [ESI].DDFlags,AccentedKey+AccentKey ;OS2SS-@@ Indicate printable accent char.
+ Mov CX,[EBX] ;OS2SS-Get char/scan to pass from accent entry.
+ Mov Word Ptr [ESI].Key.Char,CX ;OS2SS-Put in KeyPacket2.
+ Mov Byte Ptr [ESI].MonFlags,-1 ;OS2SS-Tell KBDDD to pass two packets.
+ .Endif
+ Pop EDI
+ Pop ESI
+ Ret
+
+BadAccent Endp ;------------------------------------------------------/
+
+Public AltPadPacket
+AltPadPacket Proc ;---------------------------------------------\
+
+;***********************************************************************
+;* *
+;* Subroutine Name: AltPadPacket *
+;* *
+;* Descriptive Name: Set up a KeyPacket for the Break of the Alt Key *
+;* *
+;* Function: A monitor packet is set up so that on Alt-Numpad *
+;* sequences the break of the Alt key is not lost. *
+;* *
+;* Entry Point: AltPadPacket Linkage: Near *
+;* *
+;* Input: SI = @ of KeyPacket *
+;* Empty KeyPacket2 immediately follows KeyPacket *
+;* *
+;* Exit-Normal: Monitor Key Packet filled in *
+;* *
+;* Exit-Error: N/A *
+;* *
+;* Effects: None, Registers are preserved. *
+;* *
+;* Internal References: *
+;* Routines: CopyPacket *
+;* *
+;* External References: *
+;* Routines: None *
+;* *
+;***********************************************************************
+ ;&& DCR 1713 BEGIN:
+ Push ESI ;OS2SS-&& Save the registers
+ Push EDI ;OS2SS-&& that we will use here
+ Push ECX ;OS2SS-&& to duplicate the first packet.
+ Call CopyPacket ;&& PTM 2382: Make a copy of the first
+ ;&& packet into the extra packet.
+
+ ;&& Now ESI has been incremented to point to KeyPacket2.
+
+ Or [ESI].DDFlags,ShiftMask+KeyBreak ;OS2SS-&& Indicate that this is shift packet.
+ Mov word ptr [ESI].Key.Char,0 ;OS2SS-&& Zero out the original char field.
+ Mov Byte Ptr [ESI].MonFlags,-1 ;OS2SS-&& Tell KBDDD to pass two packets.
+ Pop ECX ;OS2SS-&& Restore registers.
+ Pop EDI ;OS2SS-&&
+ Test [EDI].XInputMode,SHIFTREPORT ;OS2SS-&& Are we in shift report mode ?
+ .If <nz> ;&& If so then...
+ Or [ESI].Key.Status,1 ;OS2SS-&& flag this as a shift report packet.
+ .Endif ;&& Endif a shift report packet.
+ Pop ESI ;OS2SS-&&
+ Ret ;&& DCR 1713 END:
+
+AltPadPacket Endp ;------------------------------------------------------/
+
+Public MakeE0Packet
+MakeE0Packet Proc ;---------------------------------------------\
+
+;***********************************************************************
+;* *
+;* Subroutine Name: MakeE0Packet *
+;* *
+;* Descriptive Name: Set up a KeyPacket for the E0 scan code *
+;* *
+;* Function: A monitor packet is set up for the E0 scan code packet *
+;* that should have preceded the current scan code. *
+;* *
+;* Note: This routine added for CP111 PTM 2382. An E0 keypacket *
+;* is now manufactured and passed in combination with the *
+;* packet that follows the E0 scan code. This change was *
+;* made in order to ensure that the E0 packet would always *
+;* end up in the correct screen group. *
+;* *
+;* Entry Point: MakeE0Packet Linkage: Near *
+;* *
+;* Input: SI = @ of KeyPacket *
+;* Empty KeyPacket2 immediately follows KeyPacket *
+;* *
+;* Exit-Normal: Monitor Key Packet filled in *
+;* *
+;* Exit-Error: N/A *
+;* *
+;* Effects: None, Registers are preserved. *
+;* *
+;* Internal References: *
+;* Routines: CopyPacket *
+;* *
+;* External References: *
+;* Routines: None *
+;* *
+;***********************************************************************
+ ;&& PTM 2382 BEGIN:
+ Push ESI ;OS2SS-&& Save the registers
+ Push EDI ;OS2SS-&& that we will use here
+ Push ECX ;OS2SS-&& to duplicate the first packet.
+
+ Call CopyPacket ;&& PTM 2382: Make a copy of the first
+ ;&& packet into the extra packet.
+
+ ;&& Now ESI has been incremented to point to KeyPacket2.
+
+ Mov Byte Ptr [ESI].MonFlags,0 ;OS2SS-&& Init monitor flags low byte to zero.
+ Mov Byte Ptr [ESI].MonFlags+1,OtherKey ;OS2SS-&& Put Scan Code in MonFlags high byte.
+ Mov [ESI].DDFlags, 0 ;OS2SS-&& Clear the flag bits for new packet.
+ Or [ESI].DDFlags, SecPrefixCode ;OS2SS-&& Indicate this is a secondary prefix.
+ Mov CX, [_Ow2KCBShFlgs] ;&& Get the saved Shift Flags.
+ Mov [ESI].Key.Shift,CX ;OS2SS-&& Put Shift Flags in packet.
+ Mov [ESI].Key.Char,0 ;OS2SS-&& Zero out the original char field.
+ Mov [ESI].Key.Scan,0 ;OS2SS-&& Zero out the original Scan field.
+
+ Mov Byte Ptr [ESI].MonFlags,-1 ;OS2SS-&& Tell KBDDD to pass two packets.
+
+ Pop ECX ;OS2SS-&& Restore registers.
+ Pop EDI ;OS2SS-&&
+ Pop ESI ;OS2SS-&&
+ Ret ;&& PTM 2382 END:
+
+MakeE0Packet Endp ;------------------------------------------------------/
+
+Public CopyPacket
+CopyPacket Proc ;-----------------------------------------------------\
+;***********************************************************************
+;* *
+;* Subroutine Name: CopyPacket *
+;* *
+;* Descriptive Name: Copy KeyPacket1 to KeyPacket2 *
+;* *
+;* Function: This routine is called from BadAccent, AltPadPacket, *
+;* and MakeE0Packet. It's purpose is to duplicate the *
+;* first keypacket to the extra keypacket which follows *
+;* the first. This is done so that the Interrupt Handler *
+;* can pass both keypackets on the same interrupt. *
+;* *
+;* Entry Point: CopyPacket Linkage: Near *
+;* *
+;* Input: SI = @ of KeyPacket *
+;* Empty KeyPacket2 immediately follows KeyPacket *
+;* *
+;* Exit-Normal: Monitor Key Packet copyed *
+;* *
+;* Exit-Error: N/A *
+;* *
+;* Effects: *
+;* *
+;* Internal References: *
+;* Routines: None *
+;* *
+;* External References: *
+;* Routines: None *
+;* *
+;***********************************************************************
+
+ Mov ECX,KeyPacketLen ;OS2SS-&& Set length of packets.
+ Mov EDI,ESI ;OS2SS-&& Point to...
+ Add EDI,ECX ;OS2SS-&& ...KeyPacket2.
+CopyLoop: ;&& Loop copying packet.
+ Mov CH,[ESI] ;OS2SS-&& Get byte from first packet.
+ Mov [EDI],CH ;OS2SS-&& Put in Packet2.
+ Xor CH,CH ;&& Fix counter reg.
+ Inc ESI ;OS2SS-&& Increment source ptr.
+ Inc EDI ;OS2SS-&& Increment dest ptr.
+ Loop CopyLoop ;&& Repeat for all bytes.
+ Ret
+
+CopyPacket Endp ;------------------------------------------------------/
+
+
+Public UnPauseChk
+UnPauseChk Proc ;-----------------------------------------------------\
+;***********************************************************************
+;* *
+;* Subroutine Name: UnPauseChk *
+;* *
+;* Descriptive Name: Check For Key to End Pause Mode *
+;* *
+;* Function: Checks if key signalled the end of Pause mode. *
+;* If it did, this routine resets the flag and *
+;* returns to the the end of KbdXlate. Otherwise *
+;* it just returns *
+;* *
+;* Entry Point: UnPauseChk Linkage: Near *
+;* *
+;* Input: None *
+;* *
+;* Exit-Normal: Nothing affected *
+;* *
+;* Exit-Error: N/A *
+;* *
+;* Effects: Nothing *
+;* *
+;* Internal References: *
+;* Routines: None *
+;* *
+;* External References: *
+;* Routines: None *
+;* *
+;***********************************************************************
+
+ And [EDI].XlateFlags,NOT DumpKeyOnce ;OS2SS-@@ If here, also cancels Dump sequence.
+ Test [EDI].XPSGFlags,NowPaused ;OS2SS-@@ Check if in paused state.
+ .If <nz> AND ;Are we?
+ Test [ESI].DDFlags,KeyBreak ;OS2SS-Yes, and is this a key Make?
+ .If <z> ;Is it?
+ And [ESI].DDFlags, NOT KeyTypeMask ;OS2SS-&& PTM 3940: Indicate Wake-Up key.
+ Or [ESI].DDFlags,WakeUpKey ;OS2SS-&& PTM 3940:
+ Pop ECX ;OS2SS-Purge return address.
+ Jmp EndActionCase ;That's all.
+ .Endif
+ Ret
+
+UnPauseChk Endp ;-----------------------------------------------------/
+
+Public AltGraphCheck
+AltGraphCheck Proc ;@@ ------------------------------------------\
+;@@ B
+;************** START OF SPECIFICATIONS ********************************
+;* *
+;* Subroutine Name: AtlGraphCheck *
+;* *
+;* Descriptive Name: Process an Alt-Graph character input *
+;* *
+;* Function: This routine processes a key type that is affected *
+;* by Alt-Graph if an Alt key is down. If the Alt key *
+;* down is not the Alt-Graph key or the Alt-Graph combo, *
+;* it will set the carry and return. *
+;* *
+;* Notes: Upon entry to this routine, an Alt key is known to be *
+;* down *
+;* *
+;* Entry Point: AltGraphCheck Linkage: Near *
+;* *
+;* Input: DI = Per Session Data Area Address *
+;* SI = Key Packet Address *
+;* ES = Translate Table Selector *
+;* SS:SP+2 = Offset of translate table *
+;* BP = Offset of scan code entry in translate table *
+;* DX = ShiftFlags *
+;* CharToUse = Which character to use if Alt-Graph is down *
+;* *
+;* Exit-Normal: Carry set = process as normal Alt key down *
+;* Carry clear = key has been processed *
+;* AL= ASCII character to use *
+;* OR *
+;* CharToUse = UNDEFINED *
+;* Exit-Error: None *
+;* *
+;* Effects: AX, registers, carry flag changed. *
+;* *
+;* Internal References: *
+;* Routines: None *
+;* *
+;* External References: *
+;* Routines: None *
+;* *
+;***********************************************************************
+;@@ E
+ Push EBX ;OS2SS-
+ Push ESI ;OS2SS-
+ Mov EBX, [EBP-8] ;OS2SS-Pointer to XlateTable entry for this scan code.
+ Mov ESI, [EBP-4] ;OS2SS-Pointer to XlateTable top
+
+ .If <[EBX].Char3 eq 0> ;OS2SS-@@ If Char 3 is 0
+ Or [EDI].XlateFlags,NormalAlt ;OS2SS-@@ indicate that only Normal ALT is down
+ .Else NEAR ;@@ Else Alt-Graph character is defined
+ Mov AL,[EBX].Char3 ;OS2SS-@@ Get Char3 from translate table
+ .If <[ESI].XTKbdType eq ATKbd> ;OS2SS-@@ If an AT kbd translate table
+ Test [ESI].XTFlags1,ShftAlt ;OS2SS-@@ check if we should use Shift-Alt as
+ .If <nz> ;@@ as the Alt-Graph combo, if so...
+ Test DL,RShiftFlag+LShiftFlag ;@@ Check if a shift key is down
+ .If <nz> ;@@ If it is
+ And [EDI].XlateFlags,Not NormalAlt ;OS2SS-@@ specify to caller
+ ;@@ that it's Alt-Graph
+ Test [EDI].XlateFlags,Use3Index ;OS2SS-@@ if we're supposed to use it
+ .If <nz> ;@@ as an index
+ Mov CL,AL
+ Xor AL,AL
+ .Endif
+ .Else ;@@ supposed to use Shift-Alt combo, but shift isn't down
+ Mov AL,[EBX].Char1 ;OS2SS-@@ Restore Char1
+ Or [EDI].XlateFlags,NormalAlt ;OS2SS-@@ indicate that only Normal ALT is down
+ .Endif ;@@ Endif shift key down check
+ .Else ;@@ Shift-Alt is not Alt-Graph combo, so it is Ctl-Alt
+ Test DL,CtlFlag ;@@ Check if a ctl key is down
+ .If <nz> ;@@ If it is
+ And [EDI].XlateFlags,Not NormalAlt ;OS2SS-@@ specify to caller
+ ;@@ that it's Alt-Graph
+ Test [EDI].XlateFlags,Use3Index ;OS2SS-@@ if we're supposed to use it
+ .If <nz> ;@@ as an index
+ Mov CL,AL
+ Xor AL,AL
+ .Endif
+ .Else ;@@ supposed to use Ctl-Alt combo, but Ctl isn't down
+ Or [EDI].XlateFlags,NormalAlt ;OS2SS-@@ indicate only Normal ALT is down
+ Mov AL,[EBX].Char1 ;OS2SS-@@ Restore Char1
+ .Endif ;@@ Endif Ctlt key down check
+ .Endif ;@@ Endif Shift-Alt is Alt-Graph combo or not check
+ .Else ;@@ Else it's an Enhanced Keyboard
+ Test [ESI].XTFlags1,AltGrafL ;OS2SS-@@ check if we should use Left Alt key
+ .If <nz> ;@@ as the Alt-Graph key, if so...
+ Test DX,LAltFlag ;@@ Check if left Alt key is down
+ .If <nz> ;@@ If it is
+ And [EDI].XlateFlags,Not NormalAlt ;OS2SS-@@ specify to caller
+ ;@@ that it's Alt-Graph
+ Test [EDI].XlateFlags,Use3Index ;OS2SS-@@ if we're supposed to use it
+ .If <nz> ;@@ as an index
+ Mov CL,AL
+ Xor AL,AL
+ .Endif
+ .Else ;@@ supposed to use Left Alt key, but it isn't the one down
+ Or [EDI].XlateFlags,NormalAlt ;OS2SS-@@ indicate that only
+ ;@@ Normal ALT is down
+ Mov AL,[EBX].Char1 ;OS2SS-@@ Restore Char1
+ .Endif ;@@ Endif Left Alt key down check
+ .Else ;@@ Left Alt Key is not Alt-Graph key, so check if it is Right
+
+ Test [ESI].XTFlags1,AltGrafR ;OS2SS-@@ check if we should use Right Alt key
+ .If <nz> ;@@ as the Alt-Graph key, if so...
+ Test DX,RAltFlag ;@@ Check if right Alt Key is down
+ .If <nz> ;@@ If it is
+ And [EDI].XlateFlags,Not NormalAlt ;OS2SS-@@ specify that it's Alt-Graph
+ Test [EDI].XlateFlags,Use3Index ;OS2SS-@@ if we're supposed to use it
+ .If <nz> ;@@ as an index
+ Mov CL,AL
+ Xor AL,AL
+ .Endif
+ .Else ;@@ supposed to use Right Alt Key, but it isn't down
+ Or [EDI].XlateFlags,NormalAlt ;OS2SS-@@ indicate that only Normal
+ Mov AL,[EBX].Char1 ;@@ Restore Char1
+ .Endif ;@@ Endif Right Alt Key down check
+ .Else ;@@ Else Alt-Graph is neither Left nor Right Alt Key
+ Or [EDI].XlateFlags,NormalAlt ;OS2SS-@@ indicate that only Normal
+ Mov AL,[EBX].Char1 ;@@ Restore Char1
+ .Endif ;@@ Endif Right key is Alt-Graph or not check
+ .Endif ;@@ Endif Left ALt key is Alt-Graph or not check
+ .Endif ;@@ Endif At or Enhanced Keyboard
+ .Endif ;@@ Endif Char 3 is 0 or not
+ Pop ESI ;OS2SS-
+ Pop EBX ;OS2SS-
+ Ret
+
+AltGraphCheck Endp ;@@-------------------------------------------/
+
+Public CheckExtended
+CheckExtended Proc ;@@ ------------------------------------------\
+;@@ B
+;************** START OF SPECIFICATIONS ********************************
+;* *
+;* Subroutine Name: CheckExtended *
+;* *
+;* Descriptive Name: Checks for extended codes. *
+;* *
+;* Function: This routine checks if a scan code has an associated *
+;* extended scan code that goes with it. If it does, *
+;* it sets the appropriate fields (scan & char) in the *
+;* key packet and returns. *
+;* *
+;* Notes: Upon entry to this routine, an Alt key is known to be *
+;* down *
+;* *
+;* Entry Point: CheckExtended Linkage: Near *
+;* *
+;* Input: DI = Per Session Data Area Address *
+;* SI = Key Packet Address *
+;* DX = ShiftFlags *
+;* AH = Scan code w/ break bit cleared *
+;* *
+;* Exit-Normal: Carry set = Key has new extended code associated w/ it *
+;* Carry clear = Key does not have new extended code *
+;* *
+;* Exit-Error: None *
+;* *
+;OS2SS- Effects: AX, registers, carry flag changed. *
+;* *
+;* Internal References: *
+;* Routines: None *
+;* *
+;* External References: *
+;* Routines: None *
+;* *
+;***********************************************************************
+ Push EBX ;OS2SS-
+ ;@@ PTM 5024 - BEGIN
+ Mov EBX, Offset NewExtSC ;OS2SS-@@ Get the offset of the table that
+ ;@@ contains the scan codes that have new
+ ;@@ extended codes associated with them
+ Mov CX,0 ;@@ Start at beginning of table
+ .While <CX ne NewExtSCLen> ;@@ While we haven't searched entire table
+ .If <AH eq [EBX]> ;OS2SS-@@ If we found the scan code
+ Mov [ESI].Key.Char,0 ;OS2SS-@@ Say its an extended
+ Mov CX,NewExtSCLen ;@@ Set end of loop condition
+ Mov EBX,0 ;OS2SS-@@ Set found indicator
+ .Else ;@@ Else this isn't the scan code
+ Inc CX ;@@ Increment loop counter
+ Inc EBX ;OS2SS-@@ Increment pointer into table
+ .Endif ;@@ Endif found scan code we're looking for
+ .EndWhile ;@@ EndWhile we haven't searched entire table
+ .If <EBX eq 0> ;OS2SS-@@ If we found the scan code
+ .If <AH eq 0Fh> ;@@ If it's the tab key
+ Mov [ESI].Key.Scan,0A5h ;OS2SS-@@ Set extended code for tab key
+ .Endif ;@@ Endif it's the tab key
+ Stc ;@@ Tell caller extended char. exists.
+ .Else ;@@ Else we didn't find Scan code in table
+ Clc ;@@ tell caller
+ .Endif ;@@
+ Pop EBX ;OS2SS-
+ Ret ;@@
+ ;@@ PTM 5024 - END
+;@@ E
+CheckExtended Endp ;@@-------------------------------------------/
+
+_TEXT ends
+ End
diff --git a/private/os2/os2ses/i386/lakbd.asm b/private/os2/os2ses/i386/lakbd.asm
new file mode 100644
index 000000000..74ee8d807
--- /dev/null
+++ b/private/os2/os2ses/i386/lakbd.asm
@@ -0,0 +1,788 @@
+;; SCCSID = @(#)lakbd.asm 12.1 88/03/18
+ Page 58,132
+ Title LAKBD - Translate Table Structure for CP/DOS 1.1
+ Name LAKBD
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: LAKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for Latin America *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;* Change Activity: *
+;* *
+;* PTM 3114 - Changed incorrect AccEnt definition of I-Acute *
+;* in the 850 AT table (from DEh to D6h). pjr *
+;* *
+;* PTM 3378 - Moved definition of L3 '@' char from scan code 2 *
+;* to scan code 3 in the 437 AT table. pjr *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK LAKBD; **
+;** RELOC LAKBD.EXE LAKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-.286
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ db 1,2,3
+ db 0,-1
+
+Public _Ow2LA437001 ;***************
+_Ow2LA437001 Label Byte ;Beginning of the table. LA 437 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,0,1,0,1,0,0,AT,Len1,'LA','171'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1',0ADh, 0, 0, 0 ; 2 1 ADh
+ KeyDef 4, 0,0,0,0,0,0,0, '2',0A8h, '@', 0, 0 ; 3 2 A8h
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '/', 0, 0, 0 ; 7 6 /
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, '[', 0, 1 ; 26 (accents)
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, ']', 0, 3 ; 27 (accents)
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 0A4h,0A5h, 0, 0, 0 ; 39 A4h A5h
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 40 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 3, 0,0,0,0,0,0,0, 87h, 80h, 0, 0, 0 ; 43 87h 80h
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '?', 0, 0, 0 ; 51 , ?
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '!', 0, 0, 0 ; 52 . !
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, 0, 0 ; 53 ' "
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '^', 114, 0, 0, 0 ; 55 ^ PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,0,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",26,27,26,0,26,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h,' ',"'">
+
+AccEnt <0FEh,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <'`',27,29,27,0,27,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2LA437001
+
+;*****************************************************************************
+
+Public _Ow2LA437011 ;***************
+_Ow2LA437011 Label Byte ;Beginning of the table. LA 437 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,0,1,0,1,0,0,EN,Len2,'LA','171'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 FAh
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 0, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '?', '\', 0, 0 ; 12 ' ?
+ KeyDef 4, 0,0,0,0,0,0,0, 0A8h,0ADh, 0, 0, 0 ; 13 A8h ADh
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', '@', 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, 0, 0, 1 ; 26 acute diaresis
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '*', '~', 0, 0 ; 27 + *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 0A4h,0A5h, 0, 0, 0 ; 39 n N (tilde)
+ KeyDef 11, 0,0,0,0,0,0,0, '{', '[', 3, 0, 3 ; 40 { [
+ KeyDef 4, 0,0,0,0,0,0,0, 7Ch,0F8h,0AAh, 0, 0 ; 41 7Ch F8h
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 11, 0,0,0,0,0,0,0, '}', ']', 4, 0, 4 ; 43 } ]
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,0,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",26,27,26,0,26,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h,' ',"'">
+
+AccEnt <0FEh,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <'^',40,0,0,0,40,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <'`',43,28,43,0,43,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2LA437011
+
+;*****************************************************************************
+
+Public _Ow2LA850000 ;***************
+_Ow2LA850000 Label Byte ;Beginning of the table. LA 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,0,0,0,0,1,0,0,AT,Len3,'LA','171'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1',0ADh, 0, 0, 0 ; 2 1 ADh
+ KeyDef 4, 0,0,0,0,0,0,0, '2',0A8h, '@', 0, 0 ; 3 2 A8h
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '/', 0, 0, 0 ; 7 6 /
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, '[', 0, 1 ; 26 (accents)
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, ']', 0, 3 ; 27 (accents)
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 0A4h,0A5h, 0, 0, 0 ; 39 A4h A5h
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 40 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 3, 0,0,0,0,0,0,0, 87h, 80h, 0, 0, 0 ; 43 87h 80h
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '?', 0, 0, 0 ; 51 , ?
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '!', 0, 0, 0 ; 52 . !
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, 0, 0 ; 53 ' "
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '^', 114, 0, 0, 0 ; 55 ^ PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <0EFh,26,27,26,0,26,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'A',0B5h,'E',90h,'I',0D6h,'O',0E0h,'U',0E9h,' ',0EFh>
+
+AccEnt <0F9h,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <'`',27,29,27,0,27,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2LA850000
+
+;*****************************************************************************
+
+Public _Ow2LA850010 ;***************
+_Ow2LA850010 Label Byte ;Beginning of the table. LA 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,1,0,0,EN,Len4,'LA','171'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 FAh
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 0, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '?', '\', 0, 0 ; 12 ' ?
+ KeyDef 4, 0,0,0,0,0,0,0, 0A8h,0ADh, 0, 0, 0 ; 13 A8h ADh
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', '@', 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 1,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, 0, 0, 1 ; 26 acute diaresis
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '*', '~', 0, 0 ; 27 + *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 0A4h,0A5h, 0, 0, 0 ; 39 n N (tilde)
+ KeyDef 11, 0,0,0,0,0,0,0, '{', '[', 3, 0, 3 ; 40 { [
+ KeyDef 4, 0,0,0,0,0,0,0, 7Ch,0F8h,0AAh, 0, 0 ; 41 7Ch F8h
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 11, 0,0,0,0,0,0,0, '}', ']', 4, 0, 4 ; 43 } ]
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+;AccEnt #1
+db 0EFh,26, 27,26, 0,26
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh
+db ' ',0EFh, 0,0, 0,0, 0,0, 0,0, 0,0
+db 0,0, 0,0
+
+AccEnt <0F9h,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <'^',40,0,0,0,40,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <'`',43,28,43,0,43,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2LA850010
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/nlkbd.asm b/private/os2/os2ses/i386/nlkbd.asm
new file mode 100644
index 000000000..3a1c1daf5
--- /dev/null
+++ b/private/os2/os2ses/i386/nlkbd.asm
@@ -0,0 +1,784 @@
+;; SCCSID = @(#)nlkbd.asm 10.3 87/06/12
+ Page 58,132
+ Title NLKBD - Translate Table Structure for CP/DOS 1.1
+ Name NLKBD
+
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: NLKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for the Netherlands *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;* Changes: *
+;* *
+;* 2/13/87 - Corrected 850 AT LED key keydefs per PTM 2270. pjr *
+;* *
+;* 3/13/87 - PTM 3234: Corrected "bracket" key problem in *
+;* Enhanced keyboards (unshifted/shifted reversed). pjr *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK NLKBD; **
+;** RELOC NLKBD.EXE NLKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-.286
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ db 0,-1
+
+Public _Ow2NL437001 ;***************
+_Ow2NL437001 Label Byte ;Beginning of the table. NL 437 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,0,1,0,0,0,0,AT,Len1,'NL','143'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '@', 0, 0, 0 ; 3 2 @
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, 0, 0 ; 40 ' "
+ KeyDef 4, 0,0,0,0,0,0,0, '`', '~', 0, 0, 0 ; 41 ` ~
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 43 \ |
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2NL437001
+
+;******************************************************************************
+
+Public _Ow2NL437011 ;***************
+_Ow2NL437011 Label Byte ;Beginning of the table. NL 437 EN Kbd
+ ;***************
+
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,0,1,0,1,0,0,EN,Len2,'NL','143'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!',0FBh, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"',0FDh, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#',0FCh, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$',0ACh, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%',0ABh, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&',0F3h, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '_', 9Ch, 0, 0 ; 8 7 _
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '{', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', '}', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', "'", 0, 0, 0 ; 11 0 '
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', '\', 0, 0 ; 12 / ?
+ KeyDef 11, 0,0,0,0,0,0,0, 0F8h, 1, 2, 0, 1 ; 13 F8h tilde
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,1,1,1,1,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 14h, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,1,1,1,1,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,1,1,1,1,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,1,1,1,1,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, 0, 0, 3 ; 26 diaresis circumflex
+ KeyDef 4, 0,0,0,0,0,0,0, '*',0B3h, 0, 0, 0 ; 27 * unbroken bar
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,1,1,1,1,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S',0E1h, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, '+',0F1h, 0, 0, 0 ; 39 + ñ
+ KeyDef 11, 0,0,0,0,0,0,0, 5, 6, 0, 0, 5 ; 40 acute grave
+ KeyDef 4, 0,0,0,0,0,0,0, '@', 15h,0AAh, 0, 0 ; 41 @ 15h
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 43 < >
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z',0AEh, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X',0AFh, 0, 0 ; 45 x X
+ KeyDef 1, 0,1,0,0,0,0,0, 'c', 'C', 9Bh, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 1,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M',0E6h, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':',0FAh, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '=', 0, 0, 0 ; 53 - =
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,1,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del ,
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, ']', '[', '|', 0, 0 ; 86 ] [
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'~',13,0,0,0,131,'n',0A4h,'N',0A5h,' ','~'>
+
+AccEnt <0F7h,13,0,0,0,131,'c',87h,'C',80h,' ',0F7h>
+
+AccEnt <0F9h,26,27,26,0,26,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <'^',26,27,26,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <"'",40,0,0,0,40,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h,' ',"'">
+
+AccEnt <'`',40,0,0,0,0,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <>
+
+Len2 EQU $ - _Ow2NL437011
+
+;*****************************************************************************
+
+Public _Ow2NL850000 ;***************
+_Ow2NL850000 Label Byte ;Beginning of the table. NL 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,0,0,0,0,0,0,0,AT,Len3,'NL','143'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '@', 0, 0, 0 ; 3 2 @
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, 0, 0 ; 40 ' "
+ KeyDef 4, 0,0,0,0,0,0,0, '`', '~', 0, 0, 0 ; 41 ` ~
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 43 \ |
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2NL850000
+
+;*****************************************************************************
+
+Public _Ow2NL850010 ;***************
+_Ow2NL850010 Label Byte ;Beginning of the table. NL 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,1,0,0,EN,Len4,'NL','143'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!',0FBh, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"',0FDh, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#',0FCh, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$',0ACh, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%',0ABh, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&',0F3h, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '_', 9Ch, 0, 0 ; 8 7 _
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '{', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', '}', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', "'", 0, 0, 0 ; 11 0 '
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', '\', 0, 0 ; 12 / ?
+ KeyDef 11, 0,0,0,0,0,0,0, 0F8h, 1, 2, 0, 1 ; 13 F8h tilde
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,1,1,1,1,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R',0F4h, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,1,0,1,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,1,1,1,1,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,1,1,1,1,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,0,1,1,1,1,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, 0, 0, 3 ; 26 diaresis circumflex
+ KeyDef 4, 0,0,0,0,0,0,0, '*', '|', 0, 0, 0 ; 27 * |
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,0,1,1,1,1,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S',0E1h, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, '+',0F1h, 0, 0, 0 ; 39 + ñ
+ KeyDef 11, 0,0,0,0,0,0,0, 5, 6, 0, 0, 5 ; 40 acute grave
+ KeyDef 4, 0,0,0,0,0,0,0, '@',0F5h,0AAh, 0, 0 ; 41 @ F5h
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 43 < >
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z',0AEh, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X',0AFh, 0, 0 ; 45 x X
+ KeyDef 1, 0,1,0,0,0,0,0, 'c', 'C',0BDh, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 1,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M',0E6h, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':',0FAh, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '=', 0, 0, 0 ; 53 - =
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,1,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del ,
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, ']', '[',0DDh, 0, 0 ; 86 ] [
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'~',13,0,0,0,131,'a',0C6h,'n',0A4h,'o',0E4h,'A',0C7h,'N',0A5h,'O',0E5h,' ','~'>
+
+AccEnt <0F7h,13,0,0,0,131,'c',87h,'C',80h,' ',0F7h>
+
+AccEnt <0F9h,26,27,26,0,26,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <'^',26,27,26,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+;AccEnt #5
+db 0EFh,40, 0,0, 0,40
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh
+db ' ',0EFh, 0,0, 0,0, 0,0, 0,0, 0,0
+db 0,0, 0,0
+
+AccEnt <'`',40,0,0,0,0,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <>
+
+Len4 EQU $ - _Ow2NL850010
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/nokbd.asm b/private/os2/os2ses/i386/nokbd.asm
new file mode 100644
index 000000000..88dbcf3c0
--- /dev/null
+++ b/private/os2/os2ses/i386/nokbd.asm
@@ -0,0 +1,791 @@
+;; SCCSID = @(#)nokbd.asm 12.1 88/03/18
+ Page 58,132
+ Title NOKBD - Translate Table Structure for CP/DOS 1.1
+ Name NOKBD
+
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: NOKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for Norway *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK NOKBD; **
+;** RELOC NOKBD.EXE NOKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-.286
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;CtlPadMap Label Byte
+Public _Ow2NO865001 ;***************
+_Ow2NO865001 Label Byte ;Beginning of the table. NO 865 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 865,1,0,0,0,1,0,1,0,0,AT,Len1,'NO','155'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, '#', 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', '^', 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '&', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '*', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', '(', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', ')', 0, 0 ; 11 0 =
+ KeyDef 21, 0,0,0,0,0,0,0, '+', '?', '_', '-', 0 ; 12 + ?
+ KeyDef 21, 0,0,0,0,0,0,0, 1, 2, '+', '=', 0 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, '{', '[', 0 ; 26 a A (overcircle)
+ KeyDef 21, 0,0,0,0,0,0,0, 3, 4, '}', ']', 0 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 9Bh, 9Dh, ':', ';', 0 ; 39 o O (slash)
+ KeyDef 3, 0,0,0,0,0,0,0, 91h, 92h, '"', "'", 0 ; 40 aE dipthong
+ KeyDef 21, 0,0,0,0,0,0,0, '<', '>', 7Ch, '\', 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 21, 0,0,0,0,0,0,0, "'", '*', '~', '`', 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', '<', 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', '>', 0, 0 ; 52 . :
+ KeyDef 21, 0,0,0,0,0,0,0, '-', '_', '?', '/', 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,0,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",13,0,0,0,131,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h,' ',"'">
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <0FEh,27,29,27,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2NO865001
+
+;******************************************************************************
+
+Public _Ow2NO865011 ;***************
+_Ow2NO865011 Label Byte ;Beginning of the table. NO 865 EN Kbd
+ ;***************
+
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 865,0,0,1,0,1,0,1,0,0,EN,Len2,'NO','155'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 9Ch, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4',0AFh, '$', 0, 0 ; 5 4 monetary symbol
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '{', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '[', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', ']', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', '}', 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '?', 0, 0, 0 ; 12 + ?
+ KeyDef 11, 0,0,0,0,0,0,0, '\', 2, 1, 0, 1 ; 13 \ grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, 0, 0, 0 ; 26 a A (overcircle)
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, 5, 0, 3 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 9Bh, 9Dh, 0, 0, 0 ; 39 o O (slash)
+ KeyDef 3, 0,0,0,0,0,0,0, 91h, 92h, 0, 0, 0 ; 40 aE dipthong
+ KeyDef 4, 0,0,0,0,0,0,0, 7Ch, 15h, 0, 0, 0 ; 41 | section
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '*', 0, 0, 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,1,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,0,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del ,
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",13,0,0,0,131,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h,' ',"'">
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+
+
+; Accent #3
+db 0FEh,27, 29,27, 0,27
+db 'a',84h, 'e',89h, 'i',8Bh , 'o',94h
+db 'u',81h, 'y',98h, 'A',8Eh, 'O',99h, 'U',9Ah
+db 0,0, 0,0, 0,0, 0,0, 0,0
+db 0,0, 0,0, 0,0, 0,0, 0,0, 0,0
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <'~',27,29,27,0,0,'n',0A4h,'N',0A5h,' ','~'>
+
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2NO865011
+
+;*****************************************************************************
+
+Public _Ow2NO850000 ;***************
+_Ow2NO850000 Label Byte ;Beginning of the table. NO 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,1,0,0,0,0,0,1,0,0,AT,Len3,'NO','155'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, '#', 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', '^', 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '&', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '*', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', '(', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', ')', 0, 0 ; 11 0 =
+ KeyDef 21, 0,0,0,0,0,0,0, '+', '?', '_', '-', 0 ; 12 + ?
+ KeyDef 21, 0,0,0,0,0,0,0, 1, 2, '+', '=', 0 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 1,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, '{', '[', 0 ; 26 a A (overcircle)
+ KeyDef 21, 0,0,0,0,0,0,0, 3, 4, '}', ']', 0 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 9Bh, 9Dh, ':', ';', 0 ; 39 o O (slash)
+ KeyDef 3, 0,0,0,0,0,0,0, 91h, 92h, '"', "'", 0 ; 40 aE dipthong
+ KeyDef 21, 0,0,0,0,0,0,0, '<', '>', 7Ch, '\', 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 21, 0,0,0,0,0,0,0, "'", '*', '~', '`', 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', '<', 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', '>', 0, 0 ; 52 . :
+ KeyDef 21, 0,0,0,0,0,0,0, '-', '_', '?', '/', 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+;AccEnt #1
+db 0EFh,13, 0,0, 0,131
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh, ' ',0EFh
+db 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <0F9h,27,29,27,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2NO850000
+
+;*****************************************************************************
+
+Public _Ow2NO850010 ;***************
+_Ow2NO850010 Label Byte ;Beginning of the table. NO 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,1,0,0,EN,Len4,'NO','155'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 9Ch, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4',0CFh, '$', 0, 0 ; 5 4 monetary symbol
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '{', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '[', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', ']', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', '}', 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '?', 0, 0, 0 ; 12 + ?
+ KeyDef 11, 0,0,0,0,0,0,0, '\', 2, 1, 0, 1 ; 13 \ grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 1,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,1,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, 0, 0, 0 ; 26 a A (overcircle)
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, 5, 0, 3 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,1,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 9Bh, 9Dh, 0, 0, 0 ; 39 o O (slash)
+ KeyDef 3, 0,0,0,0,0,0,0, 91h, 92h, 0, 0, 0 ; 40 aE dipthong
+ KeyDef 4, 0,0,0,0,0,0,0, 7Ch,0F5h, 0, 0, 0 ; 41 | section
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '*', 0, 0, 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,1,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del ,
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+;AccEnt #1
+db 0EFh,13, 0,0, 0,131
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh, ' ',0EFh
+db 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <0F9h,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <'~',27,29,27,0,0,'a',0C6h,'n',0A4h,'o',0E4h,'A',0C7h,'N',0A5h,'O',0E5h,' ','~'>
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2NO850010
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/pokbd.asm b/private/os2/os2ses/i386/pokbd.asm
new file mode 100644
index 000000000..70da908fc
--- /dev/null
+++ b/private/os2/os2ses/i386/pokbd.asm
@@ -0,0 +1,773 @@
+;; SCCSID = @(#)pokbd.asm 12.1 88/03/18
+ Page 58,132
+ Title POKBD - Translate Table Structure for CP/DOS 1.1
+ Name POKBD
+
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: POKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for Portugal *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK POKBD; **
+;** RELOC POKBD.EXE POKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-.286
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;CtlPadMap Label Byte
+; db 119,-1,132,-1
+Public _Ow2PO860001 ;***************
+_Ow2PO860001 Label Byte ;Beginning of the table. PO 860 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 860,0,0,0,0,1,0,0,0,0,AT,Len1,'PO','163'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '@', 0, 0, 0 ; 3 2 @
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, 0, 0 ; 40 ' "
+ KeyDef 4, 0,0,0,0,0,0,0, '`', '~', 0, 0, 0 ; 41 ` ~
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 43 \ |
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2PO860001
+
+;******************************************************************************
+
+Public _Ow2PO860011 ;***************
+_Ow2PO860011 Label Byte ;Beginning of the table. PO 860 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 860,0,0,1,0,1,0,1,0,0,EN,Len2,'PO','163'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 9Ch, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 15h, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '{', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '[', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', ']', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', '}', 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '?', 0, 0, 0 ; 12 ' ?
+ KeyDef 4, 0,0,0,0,0,0,0, 0AEh,0AFh, 0, 0, 0 ; 13 . /
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,1,1,0,1,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,1,1,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,1,1,1,1,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, '+', '*', 1, 0, 1 ; 26 + * diaresis
+ KeyDef 11, 0,0,0,0,0,0,0, 2, 3, 0, 0, 2 ; 27 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,1,1,1,1,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 87h, 80h, 0, 0, 0 ; 39 c C (cedilla)
+ KeyDef 4, 0,0,0,0,0,0,0, 0A7h,0A6h, 0, 0, 0 ; 40 A7h A6h
+ KeyDef 4, 0,0,0,0,0,0,0, '\', 7Ch, 0, 0, 0 ; 41 \ |
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 11, 0,0,0,0,0,0,0, 4, 5, 0, 0, 4 ; 43 tilde circumflex
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,1,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <0FEh,26,27,26,0,26,'u',81h,'U',9Ah>
+
+AccEnt <"'",27,29,27,0,27,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'A',86h,'E',90h,'I',8Bh,'O',9Fh,'U',96h,' ',"'">
+
+AccEnt <"`",27,29,27,0,0,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',91h,'E',92h,'I',98h,'O',0A9h,'U',9Dh,' ',"`">
+
+AccEnt <'~',43,28,43,0,43,'a',84h,'o',94h,'n',0A4h,'A',8Eh,'O',99h,'N',0A5h,' ','~'>
+
+AccEnt <'^',43,28,43,0,0,'a',83h,'e',88h,'o',93h,'A',8Fh,'E',89h,'O',8Ch,' ','^'>
+
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2PO860011
+
+;*****************************************************************************
+
+Public _Ow2PO850000 ;***************
+_Ow2PO850000 Label Byte ;Beginning of the table. PO 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,0,0,0,0,0,0,0,AT,Len3,'PO','163'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '@', 0, 0, 0 ; 3 2 @
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, 0, 0 ; 40 ' "
+ KeyDef 4, 0,0,0,0,0,0,0, '`', '~', 0, 0, 0 ; 41 ` ~
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 43 \ |
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2PO850000
+
+;*****************************************************************************
+
+Public _Ow2PO850010 ;***************
+_Ow2PO850010 Label Byte ;Beginning of the table. PO 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,1,0,0,EN,Len4,'PO','163'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 9Ch, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$',0F5h, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '{', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '[', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', ']', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', '}', 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '?', 0, 0, 0 ; 12 ' ?
+ KeyDef 4, 0,0,0,0,0,0,0, 0AEh,0AFh, 0, 0, 0 ; 13 . /
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,0,1,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 1,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,0,1,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,0,1,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,1,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, '+', '*', 1, 0, 1 ; 26 + * diaresis
+ KeyDef 11, 0,0,0,0,0,0,0, 2, 3, 0, 0, 2 ; 27 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,1,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 87h, 80h, 0, 0, 0 ; 39 c C (cedilla)
+ KeyDef 4, 0,0,0,0,0,0,0, 0A7h,0A6h, 0, 0, 0 ; 40 A7h A6h
+ KeyDef 4, 0,0,0,0,0,0,0, '\', 7Ch, 0, 0, 0 ; 41 \ |
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 11, 0,0,0,0,0,0,0, 4, 5, 0, 0, 4 ; 43 tilde circumflex
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,1,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <0F9h,26,27,26,0,26,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+; AccEnt #2
+db 0EFh,27, 29,27, 0,27
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh
+db ' ',0EFh, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0
+
+AccEnt <"`",27,29,27,0,0,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ',"`">
+
+AccEnt <'~',43,28,43,0,43,'a',0C6h,'o',0E4h,'n',0A4h,'A',0C7h,'O',0E5h,'N',0A5h,' ','~'>
+
+AccEnt <'^',43,28,43,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2PO850010
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/sfkbd.asm b/private/os2/os2ses/i386/sfkbd.asm
new file mode 100644
index 000000000..8c3af0ea3
--- /dev/null
+++ b/private/os2/os2ses/i386/sfkbd.asm
@@ -0,0 +1,788 @@
+;; SCCSID = @(#)sfkbd.asm 12.1 88/03/18
+ Page 58,132
+ Title SFKBD - Translate Table Structure for CP/DOS 1.1
+ Name SFKBD
+
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: SFKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for Swiss French *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK SFKBD; **
+;** RELOC SFKBD.EXE SFKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-.286
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+; db 119,-1,132,-1
+; db 115,-1,116,-1
+Public _Ow2SF437001 ;***************
+_Ow2SF437001 Label Byte ;Beginning of the table. SF 437 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,0,1,0,1,1,0,AT,Len1,'SF','150F'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '+', 0, 0, 0 ; 2 1 +
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '*', '#', 0, 0 ; 4 3 *
+ KeyDef 4, 0,0,0,0,0,0,0, '4', 87h,0F8h, 0, 0 ; 5 4 c cedilla
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 15h, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 7Ch, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 11, 0,0,0,0,0,0,0, "'", '?', 1, 0, 1 ; 12 ' ?
+ KeyDef 11, 0,0,0,0,0,0,0, 2, 3, 4, 0, 2 ; 13 circumflex grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,0,1,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 21 z Z
+ KeyDef 1, 1,1,1,0,1,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,0,1,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,0,1,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 20, 0,0,0,0,0,0,0, 8Ah, 81h, '[', 8Ah, 81h ; 26 8Ah 81h
+ KeyDef 11, 0,0,0,0,0,0,0, 5, '!', ']', 0, 5 ; 27 diaresis !
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,0,1,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 20, 0,0,0,0,0,0,0, 82h, 94h, '{', 82h, 94h ; 39 82h 94h
+ KeyDef 20, 0,0,0,0,0,0,0, 85h, 84h, '}', 85h, 84h ; 40 85h 84h
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '$', 9Ch, 0, 0, 0 ; 43 $ 9Ch
+ KeyDef 1, 0,0,0,0,1,0,0, 'y', 'Y', 0, 0, 0 ; 44 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,1,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,1,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",12,0,0,0,130,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h>
+
+AccEnt <'^',13,0,0,0,131,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <'~',13,0,0,0,131,'n',0A4h,'N',0A5h,' ','~'>
+
+AccEnt <22h,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2SF437001
+
+;******************************************************************************
+
+Public _Ow2SF437011 ;***************
+_Ow2SF437011 Label Byte ;Beginning of the table. SF 437 EN Kbd
+ ;***************
+
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,0,1,0,1,1,0,EN,Len2,'SF','150F'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '+',0B3h, 0, 0 ; 2 1 +
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '*', '#', 0, 0 ; 4 3 *
+ KeyDef 4, 0,0,0,0,0,0,0, '4', 87h, 0, 0, 0 ; 5 4 c cedilla
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&',0AAh, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 7Ch, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 9Bh, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 11, 0,0,0,0,0,0,0, "'", '?', 1, 0, 1 ; 12 ' ?
+ KeyDef 11, 0,0,0,0,0,0,0, 2, 3, 4, 0, 2 ; 13 circumflex grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,0,1,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 21 z Z
+ KeyDef 1, 1,1,1,0,1,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,0,1,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,0,1,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 20, 0,0,0,0,0,0,0, 8Ah, 81h, '[', 8Ah, 81h ; 26 8Ah 81h
+ KeyDef 11, 0,0,0,0,0,0,0, 5, '!', ']', 0, 5 ; 27 diaresis !
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,0,1,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 20, 0,0,0,0,0,0,0, 82h, 94h, 0, 82h, 94h ; 39 82h 94h
+ KeyDef 20, 0,0,0,0,0,0,0, 85h, 84h, '{', 85h, 84h ; 40 85h 84h
+ KeyDef 4, 0,0,0,0,0,0,0, 15h,0F8h, 0, 0, 0 ; 41 15h F8h
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '$', 9Ch, '}', 0, 0 ; 43 $ 9Ch
+ KeyDef 1, 0,0,0,0,1,0,0, 'y', 'Y', 0, 0, 0 ; 44 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,1,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,1,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",12,0,0,0,130,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h>
+
+AccEnt <'^',13,0,0,0,131,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <'~',13,0,0,0,131,'n',0A4h,'N',0A5h,' ','~'>
+
+AccEnt <22h,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2SF437011
+
+;*****************************************************************************
+
+Public _Ow2SF850000 ;***************
+_Ow2SF850000 Label Byte ;Beginning of the table. SF 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,0,0,0,0,1,1,0,AT,Len3,'SF','150F'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '+', 0, 0, 0 ; 2 1 +
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '*', '#', 0, 0 ; 4 3 *
+ KeyDef 4, 0,0,0,0,0,0,0, '4', 87h,0F8h, 0, 0 ; 5 4 c cedilla
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%',0F5h, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 7Ch, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 11, 0,0,0,0,0,0,0, "'", '?', 1, 0, 1 ; 12 ' ?
+ KeyDef 11, 0,0,0,0,0,0,0, 2, 3, 4, 0, 2 ; 13 circumflex grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,0,1,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 21 z Z
+ KeyDef 1, 1,1,1,0,1,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,0,1,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,1,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 20, 0,0,0,0,0,0,0, 8Ah, 81h, '[',0D4h, 9Ah ; 26 8Ah 81h
+ KeyDef 11, 0,0,0,0,0,0,0, 5, '!', ']', 0, 5 ; 27 diaresis !
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,1,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 20, 0,0,0,0,0,0,0, 82h, 94h, '{', 90h, 99h ; 39 82h 94h
+ KeyDef 20, 0,0,0,0,0,0,0, 85h, 84h, '}',0B7h, 8Eh ; 40 85h 84h
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '$', 9Ch, 0, 0, 0 ; 43 $ 9Ch
+ KeyDef 1, 1,0,0,0,1,0,0, 'y', 'Y', 0, 0, 0 ; 44 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,1,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+;AccEnt #1
+db 0EFh,12, 0,0, 0,130
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh, ' ',0EFh
+db 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0
+
+AccEnt <'^',13,0,0,0,131,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <'~',13,0,0,0,131,'a',0C6h,'n',0A4h,'o',0E4h,'A',0C7h,'N',0A5h,'O',0E5h,' ','~'>
+
+AccEnt <0F9h,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2SF850000
+
+;*****************************************************************************
+
+Public _Ow2SF850010 ;***************
+_Ow2SF850010 Label Byte ;Beginning of the table. SF 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,1,1,0,EN,Len4,'SF','150F'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '+', 7Ch, 0, 0 ; 2 1 +
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '*', '#', 0, 0 ; 4 3 *
+ KeyDef 4, 0,0,0,0,0,0,0, '4', 87h, 0, 0, 0 ; 5 4 c cedilla
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&',0AAh, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/',0DDh, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(',0BDh, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 11, 0,0,0,0,0,0,0, "'", '?', 1, 0, 1 ; 12 ' ?
+ KeyDef 11, 0,0,0,0,0,0,0, 2, 3, 4, 0, 2 ; 13 circumflex grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,0,1,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 21 z Z
+ KeyDef 1, 1,1,1,0,1,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,0,1,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,1,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 20, 0,0,0,0,0,0,0, 8Ah, 81h, '[',0D4h, 9Ah ; 26 8Ah 81h
+ KeyDef 11, 0,0,0,0,0,0,0, 5, '!', ']', 0, 5 ; 27 diaresis !
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,1,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 20, 0,0,0,0,0,0,0, 82h, 94h, 0, 90h, 99h ; 39 82h 94h
+ KeyDef 20, 0,0,0,0,0,0,0, 85h, 84h, '{',0B7h, 8Eh ; 40 85h 84h
+ KeyDef 4, 0,0,0,0,0,0,0, 0F5h,0F8h, 0, 0, 0 ; 41 F5h F8h
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '$', 9Ch, '}', 0, 0 ; 43 $ 9Ch
+ KeyDef 1, 1,0,0,0,1,0,0, 'y', 'Y', 0, 0, 0 ; 44 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,1,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+;AccEnt #1
+db 0EFh,12, 0,0, 0,130
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh, ' ',0EFh
+db 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0
+
+AccEnt <'^',13,0,0,0,131,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <'~',13,0,0,0,131,'a',0C6h,'n',0A4h,'o',0E4h,'A',0C7h,'N',0A5h,'O',0E5h,' ','~'>
+
+AccEnt <0F9h,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2SF850010
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/sgkbd.asm b/private/os2/os2ses/i386/sgkbd.asm
new file mode 100644
index 000000000..52d04e206
--- /dev/null
+++ b/private/os2/os2ses/i386/sgkbd.asm
@@ -0,0 +1,788 @@
+;; SCCSID = @(#)sgkbd.asm 12.2E%
+ Page 58,132
+ Title SGKBD - Translate Table Structure for CP/DOS 1.2
+ Name SGKBD
+
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: SGKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for Swiss German *
+;* *
+;* *
+;* Status: OS/2 Version 1.2 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK SGKBD; **
+;** RELOC SGKBD.EXE SGKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-.286
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+; db 115,-1,116,-1
+; db 117,-1,118
+Public _Ow2SG437001 ;***************
+_Ow2SG437001 Label Byte ;Beginning of the table. SG 437 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,0,1,0,1,1,0,AT,Len1,'SG','150G'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '+', 0, 0, 0 ; 2 1 +
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '*', '#', 0, 0 ; 4 3 *
+ KeyDef 4, 0,0,0,0,0,0,0, '4', 87h,0F8h, 0, 0 ; 5 4 c cedilla
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 15h, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 7Ch, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 11, 0,0,0,0,0,0,0, "'", '?', 1, 0, 1 ; 12 ' ?
+ KeyDef 11, 0,0,0,0,0,0,0, 2, 3, 4, 0, 2 ; 13 circumflex grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,0,1,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 21 z Z
+ KeyDef 1, 1,1,1,0,1,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,0,1,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,0,1,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 20, 0,0,0,0,0,0,0, 81h, 8Ah, '[', 9Ah, 8Ah ; 26 81h 8Ah
+ KeyDef 11, 0,0,0,0,0,0,0, 5, '!', ']', 0, 5 ; 27 diaresis !
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,0,1,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 20, 0,0,0,0,0,0,0, 94h, 82h, '{', 99h, 82h ; 39 94h 82h
+ KeyDef 20, 0,0,0,0,0,0,0, 84h, 85h, '}', 8Eh, 85h ; 40 84h 85h
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '$', 9Ch, 0, 0, 0 ; 43 $ 9Ch
+ KeyDef 1, 0,0,0,0,1,0,0, 'y', 'Y', 0, 0, 0 ; 44 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,1,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,1,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",12,0,0,0,130,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h>
+
+AccEnt <'^',13,0,0,0,131,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <'~',13,0,0,0,131,'n',0A4h,'N',0A5h,' ','~'>
+
+AccEnt <22h,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2SG437001
+
+;******************************************************************************
+
+Public _Ow2SG437011 ;***************
+_Ow2SG437011 Label Byte ;Beginning of the table. SG 437 EN Kbd
+ ;***************
+
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,0,1,0,1,1,0,EN,Len2,'SG','150G'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '+',0B3h, 0, 0 ; 2 1 +
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '*', '#', 0, 0 ; 4 3 *
+ KeyDef 4, 0,0,0,0,0,0,0, '4', 87h, 0, 0, 0 ; 5 4 c cedilla
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&',0AAh, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 7Ch, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 9Bh, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 11, 0,0,0,0,0,0,0, "'", '?', 1, 0, 1 ; 12 ' ?
+ KeyDef 11, 0,0,0,0,0,0,0, 2, 3, 4, 0, 2 ; 13 circumflex grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,0,1,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 21 z Z
+ KeyDef 1, 1,1,1,0,1,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,0,1,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,0,1,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 20, 0,0,0,0,0,0,0, 81h, 8Ah, '[', 9Ah, 8Ah ; 26 81h 8Ah
+ KeyDef 11, 0,0,0,0,0,0,0, 5, '!', ']', 0, 5 ; 27 diaresis !
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,0,1,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 20, 0,0,0,0,0,0,0, 94h, 82h, 0, 94h, 82h ; 39 94h 82h
+ KeyDef 20, 0,0,0,0,0,0,0, 84h, 85h, '{', 8Eh, 85h ; 40 84h 85h
+ KeyDef 4, 0,0,0,0,0,0,0, 15h,0F8h, 0, 0, 0 ; 41 15h F8h
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '$', 9Ch, '}', 0, 0 ; 43 $ 9Ch
+ KeyDef 1, 0,0,0,0,1,0,0, 'y', 'Y', 0, 0, 0 ; 44 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,1,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,1,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",12,0,0,0,130,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h>
+
+AccEnt <'^',13,0,0,0,131,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <'~',13,0,0,0,131,'n',0A4h,'N',0A5h,' ','~'>
+
+AccEnt <22h,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2SG437011
+
+;*****************************************************************************
+
+Public _Ow2SG850000 ;***************
+_Ow2SG850000 Label Byte ;Beginning of the table. SG 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,0,0,0,0,1,1,0,AT,Len3,'SG','150G'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '+', 0, 0, 0 ; 2 1 +
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '*', '#', 0, 0 ; 4 3 *
+ KeyDef 4, 0,0,0,0,0,0,0, '4', 87h,0F8h, 0, 0 ; 5 4 c cedilla
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%',0F5h, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 7Ch, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 11, 0,0,0,0,0,0,0, "'", '?', 1, 0, 1 ; 12 ' ?
+ KeyDef 11, 0,0,0,0,0,0,0, 2, 3, 4, 0, 2 ; 13 circumflex grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,0,1,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 21 z Z
+ KeyDef 1, 1,1,1,0,1,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,0,1,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,1,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 20, 0,0,0,0,0,0,0, 81h, 8Ah, '[', 9Ah,0D4h ; 26 81h 8Ah
+ KeyDef 11, 0,0,0,0,0,0,0, 5, '!', ']', 0, 5 ; 27 diaresis !
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,1,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 20, 0,0,0,0,0,0,0, 94h, 82h, '{', 99h, 90h ; 39 94h 82h
+ KeyDef 20, 0,0,0,0,0,0,0, 84h, 85h, '}', 8Eh,0B7h ; 40 84h 85h
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '$', 9Ch, 0, 0, 0 ; 43 $ 9Ch
+ KeyDef 1, 1,0,0,0,1,0,0, 'y', 'Y', 0, 0, 0 ; 44 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,1,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+;AccEnt #1
+db 0EFh,12, 0,0, 0,130
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh, ' ',0EFh
+db 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0
+
+AccEnt <'^',13,0,0,0,131,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <'~',13,0,0,0,131,'a',0C6h,'n',0A4h,'o',0E4h,'A',0C7h,'N',0A5h,'O',0E5h,' ','~'>
+
+AccEnt <0F9h,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2SG850000
+
+;*****************************************************************************
+
+Public _Ow2SG850010 ;***************
+_Ow2SG850010 Label Byte ;Beginning of the table. SG 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,1,1,0,EN,Len4,'SG','150G'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '+', 7Ch, 0, 0 ; 2 1 +
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '*', '#', 0, 0 ; 4 3 *
+ KeyDef 4, 0,0,0,0,0,0,0, '4', 87h, 0, 0, 0 ; 5 4 c cedilla
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&',0AAh, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/',0DDh, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(',0BDh, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 11, 0,0,0,0,0,0,0, "'", '?', 1, 0, 1 ; 12 ' ?
+ KeyDef 11, 0,0,0,0,0,0,0, 2, 3, 4, 0, 2 ; 13 circumflex grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,0,1,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 21 z Z
+ KeyDef 1, 1,1,1,0,1,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,0,1,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,1,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 20, 0,0,0,0,0,0,0, 81h, 8Ah, '[', 9Ah,0D4h ; 26 81h 8Ah
+ KeyDef 11, 0,0,0,0,0,0,0, 5, '!', ']', 0, 5 ; 27 diaresis !
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,1,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 20, 0,0,0,0,0,0,0, 94h, 82h, 0, 99h, 90h ; 39 94h 82h
+ KeyDef 20, 0,0,0,0,0,0,0, 84h, 85h, '{', 8Eh,0B7h ; 40 84h 85h
+ KeyDef 4, 0,0,0,0,0,0,0, 0F5h,0F8h, 0, 0, 0 ; 41 F5h F8h
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '$', 9Ch, '}', 0, 0 ; 43 $ 9Ch
+ KeyDef 1, 1,0,0,0,1,0,0, 'y', 'Y', 0, 0, 0 ; 44 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,1,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+;AccEnt #1
+db 0EFh,12, 0,0, 0,130
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh, ' ',0EFh
+db 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0
+
+AccEnt <'^',13,0,0,0,131,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <'~',13,0,0,0,131,'a',0C6h,'n',0A4h,'o',0E4h,'A',0C7h,'N',0A5h,'O',0E5h,' ','~'>
+
+AccEnt <0F9h,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2SG850010
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/spkbd.asm b/private/os2/os2ses/i386/spkbd.asm
new file mode 100644
index 000000000..ac49ff1fa
--- /dev/null
+++ b/private/os2/os2ses/i386/spkbd.asm
@@ -0,0 +1,786 @@
+;; SCCSID = @(#)spkbd.asm 10.2 87/06/07
+ Page 58,132
+ Title SPKBD - Translate Table Structure for CP/DOS 1.1
+ Name SPKBD
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: SPKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for Spain *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;* Change history: *
+;* *
+;* PTM 3020: Corrected small o circumflex in accent entry for *
+;* the 437 Enhanced table. pjr *
+;* *
+;* PTM 3317: Moved '@' Char3 value from scan code 2 to scan 3 *
+;* on the 437 AT table. pjr *
+;* *
+;* PTM 3625: Changed I-grave (DEh) to I-acute (D6h) in AT 850 *
+;* table AccEnt #1. pjr *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK SPKBD; **
+;** RELOC SPKBD.EXE SPKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-.286
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+; db 117,-1,118
+; db -1,-1
+
+Public _Ow2SP437001 ;***************
+_Ow2SP437001 Label Byte ;Beginning of the table. SP 437 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,0,1,0,1,0,0,AT,Len1,'SP','172'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1',0ADh, 0, 0, 0 ; 2 1 ADh
+ KeyDef 4, 0,0,0,0,0,0,0, '2',0A8h, '@', 0, 0 ; 3 2 A8h
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '/', 0, 0, 0 ; 7 6 /
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, '[', 0, 1 ; 26 (accents)
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, ']', 0, 3 ; 27 (accents)
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 0A4h,0A5h, 0, 0, 0 ; 39 A4h A5h
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 40 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 3, 0,0,0,0,0,0,0, 87h, 80h, 0, 0, 0 ; 43 87h 80h
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '?', 0, 0, 0 ; 51 , ?
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '!', 0, 0, 0 ; 52 . !
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, 0, 0 ; 53 ' "
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '^', 114, 0, 0, 0 ; 55 ^ PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,0,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",26,27,26,0,26,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h,' ',"'">
+
+AccEnt <0FEh,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <'`',27,29,27,0,27,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2SP437001
+
+;*****************************************************************************
+
+Public _Ow2SP437011 ;***************
+_Ow2SP437011 Label Byte ;Beginning of the table. SP 437 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,0,1,0,1,0,0,EN,Len2,'SP','172'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 7Ch, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3',0FAh, '#', 0, 0 ; 4 3 FAh
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 'ª', 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 0, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '?', 0, 0, 0 ; 12 ' ?
+ KeyDef 4, 0,0,0,0,0,0,0, 0ADh,0A8h, 0, 0, 0 ; 13 ADh A8h
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,1,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, '[', 0, 1 ; 26 grave circumflex
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '*', ']', 0, 0 ; 27 + *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 0A4h,0A5h, 0, 0, 0 ; 39 n N (tilde)
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, '{', 0, 3 ; 40 acute diaresis
+ KeyDef 4, 0,0,0,0,0,0,0, 0A7h,0A6h, '\', 0, 0 ; 41 A7h A6h
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 3, 0,0,0,0,0,0,0, 87h, 80h, '}', 0, 0 ; 43 c C (cedilla)
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'`',26,27,26,0,26,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <'^',26,27,26,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <"'",40,0,0,0,40,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h,' ',"'">
+
+AccEnt <0FEh,40,0,0,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2SP437011
+
+;*****************************************************************************
+
+Public _Ow2SP850000 ;***************
+_Ow2SP850000 Label Byte ;Beginning of the table. SP 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,0,0,0,0,1,0,0,AT,Len3,'SP','172'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1',0ADh, 0, 0, 0 ; 2 1 ADh
+ KeyDef 4, 0,0,0,0,0,0,0, '2',0A8h, '@', 0, 0 ; 3 2 A8h
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '/', 0, 0, 0 ; 7 6 /
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,1,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, '[', 0, 1 ; 26 (accents)
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, ']', 0, 3 ; 27 (accents)
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 0A4h,0A5h, 0, 0, 0 ; 39 A4h A5h
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 40 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, '<', '>', '\', 0, 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 3, 0,0,0,0,0,0,0, 87h, 80h, 0, 0, 0 ; 43 87h 80h
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '?', 0, 0, 0 ; 51 , ?
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '!', 0, 0, 0 ; 52 . !
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, 0, 0 ; 53 ' "
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '^', 114, 0, 0, 0 ; 55 ^ PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <0EFh,26,27,26,0,26,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'A',0B5h,'E',90h,'I',0D6h,'O',0E0h,'U',0E9h,' ',0EFh>
+
+AccEnt <0F9h,26,27,26,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <'`',27,29,27,0,27,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2SP850000
+
+;*****************************************************************************
+
+Public _Ow2SP850010 ;***************
+_Ow2SP850010 Label Byte ;Beginning of the table. SP 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,1,0,0,EN,Len4,'SP','172'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 7Ch, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3',0FAh, '#', 0, 0 ; 4 3 FAh
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 'ª', 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', 0, 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', 0, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', 0, 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '?', 0, 0, 0 ; 12 ' ?
+ KeyDef 4, 0,0,0,0,0,0,0, 0ADh,0A8h, 0, 0, 0 ; 13 ADh A8h
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,1,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, '[', 0, 1 ; 26 grave circumflex
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '*', ']', 0, 0 ; 27 + *
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 0A4h,0A5h, 0, 0, 0 ; 39 n N (tilde)
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, '{', 0, 3 ; 40 acute diaresis
+ KeyDef 4, 0,0,0,0,0,0,0, 0A7h,0A6h, '\', 0, 0 ; 41 A7h A6h
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 3, 0,0,0,0,0,0,0, 87h, 80h, '}', 0, 0 ; 43 c C (cedilla)
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 0, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <'`',26,27,26,0,26,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <'^',26,27,26,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <0EFh,40,0,0,0,40,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'A',0B5h,'E',90h,'I',0D6h,'O',0E0h,'U',0E9h,' ',0EFh>
+
+AccEnt <0F9h,40,0,0,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2SP850010
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/sukbd.asm b/private/os2/os2ses/i386/sukbd.asm
new file mode 100644
index 000000000..fd4051224
--- /dev/null
+++ b/private/os2/os2ses/i386/sukbd.asm
@@ -0,0 +1,785 @@
+;; SCCSID = @(#)sukbd.asm 12.1 88/03/18
+ Page 58,132
+ Title SUKBD - Translate Table Structure for CP/DOS 1.1
+ Name SUKBD
+
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: SUKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for Finland *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK SUKBD; **
+;** RELOC SUKBD.EXE SUKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-.286
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+; db -1,-1
+ db 119,141,132,142 ;@@ Keypad 7, 8, 9, - (PTM 5024)
+Public _Ow2SU437001 ;***************
+_Ow2SU437001 Label Byte ;Beginning of the table. SU 437 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,1,0,0,0,1,0,1,0,0,AT,Len1,'SU','153'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, '#', 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', '^', 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '&', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '*', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', '(', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', ')', 0, 0 ; 11 0 =
+ KeyDef 21, 0,0,0,0,0,0,0, '+', '?', '_', '-', 0 ; 12 + ?
+ KeyDef 21, 0,0,0,0,0,0,0, 1, 2, '+', '=', 0 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, '{', '[', 0 ; 26 a A (overcircle)
+ KeyDef 21, 0,0,0,0,0,0,0, 3, 4, '}', ']', 0 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 94h, 99h, ':', ';', 0 ; 39 o O (diaresis)
+ KeyDef 3, 0,0,0,0,0,0,0, 84h, 8Eh, '"', "'", 0 ; 40 a A (diaresis)
+ KeyDef 21, 0,0,0,0,0,0,0, '<', '>', 7Ch, '\', 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 21, 0,0,0,0,0,0,0, "'", '*', '~', '`', 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', '<', 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', '>', 0, 0 ; 52 . :
+ KeyDef 21, 0,0,0,0,0,0,0, '-', '_', '?', '/', 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,0,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",13,0,0,0,131,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h,' ',"'">
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <0FEh,27,29,27,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2SU437001
+
+;******************************************************************************
+
+Public _Ow2SU437011 ;***************
+_Ow2SU437011 Label Byte ;Beginning of the table. SU 437 EN Kbd
+ ;***************
+
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,0,1,0,1,0,0,EN,Len2,'SU','153'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 9Ch, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', 0, '$', 0, 0 ; 5 4 monetary symbol
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '{', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '[', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', ']', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', '}', 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '?', '\', 0, 0 ; 12 + ?
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, 0, 0, 1 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, 0, 0, 0 ; 26 a A (overcircle)
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, 5, 0, 3 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 94h, 99h, 0, 0, 0 ; 39 o O (diaresis)
+ KeyDef 3, 0,0,0,0,0,0,0, 84h, 8Eh, 0, 0, 0 ; 40 a A (diaresis)
+ KeyDef 4, 0,0,0,0,0,0,0, 15h,0ABh, 0, 0, 0 ; 41 section one-half
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '*', 0, 0, 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,1,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,0,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del ,
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 7Ch, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",13,0,0,0,131,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h,' ',"'">
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <0FEh,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <'~',27,29,27,0,0,'n',0A4h,'N',0A5h,' ','~'>
+
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2SU437011
+
+;*****************************************************************************
+
+Public _Ow2SU850000 ;***************
+_Ow2SU850000 Label Byte ;Beginning of the table. SU 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,1,0,0,0,0,0,1,0,0,AT,Len3,'SU','153'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, '#', 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', '^', 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '&', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '*', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', '(', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', ')', 0, 0 ; 11 0 =
+ KeyDef 21, 0,0,0,0,0,0,0, '+', '?', '_', '-', 0 ; 12 + ?
+ KeyDef 21, 0,0,0,0,0,0,0, 1, 2, '+', '=', 0 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 1,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, '{', '[', 0 ; 26 a A (overcircle)
+ KeyDef 21, 0,0,0,0,0,0,0, 3, 4, '}', ']', 0 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 94h, 99h, ':', ';', 0 ; 39 o O (diaresis)
+ KeyDef 3, 0,0,0,0,0,0,0, 84h, 8Eh, '"', "'", 0 ; 40 a A (diaresis)
+ KeyDef 21, 0,0,0,0,0,0,0, '<', '>', 7Ch, '\', 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 21, 0,0,0,0,0,0,0, "'", '*', '~', '`', 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', '<', 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', '>', 0, 0 ; 52 . :
+ KeyDef 21, 0,0,0,0,0,0,0, '-', '_', '?', '/', 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+;AccEnt #1
+db 0EFh,13, 0,0, 0,131
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh, ' ',0EFh
+db 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <0F9h,27,29,27,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2SU850000
+
+;*****************************************************************************
+
+Public _Ow2SU850010 ;***************
+_Ow2SU850010 Label Byte ;Beginning of the table. SU 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,1,0,0,EN,Len4,'SU','153'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 9Ch, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4',0CFh, '$', 0, 0 ; 5 4 monetary symbol
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '{', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '[', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', ']', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', '}', 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '?', '\', 0, 0 ; 12 + ?
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, 0, 0, 1 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 1,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, 0, 0, 0 ; 26 a A (overcircle)
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, 5, 0, 3 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 94h, 99h, 0, 0, 0 ; 39 o O (diaresis)
+ KeyDef 3, 0,0,0,0,0,0,0, 84h, 8Eh, 0, 0, 0 ; 40 a A (diaresis)
+ KeyDef 4, 0,0,0,0,0,0,0, 0F5h,0ABh, 0, 0, 0 ; 41 section one-half
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '*', 0, 0, 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,1,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del ,
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 7Ch, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+;AccEnt #1
+db 0EFh,13, 0,0, 0,131
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh, ' ',0EFh
+db 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <0F9h,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <'~',27,29,27,0,0,'n',0A4h,'N',0A5h,' ','~'>
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2SU850010
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/svkbd.asm b/private/os2/os2ses/i386/svkbd.asm
new file mode 100644
index 000000000..d79bd5426
--- /dev/null
+++ b/private/os2/os2ses/i386/svkbd.asm
@@ -0,0 +1,785 @@
+;; SCCSID = @(#)svkbd.asm 12.1 88/03/18
+ Page 58,132
+ Title SVKBD - Translate Table Structure for CP/DOS 1.1
+ Name SVKBD
+
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: SVKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for Sweden *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK SVKBD; **
+;** RELOC SVKBD.EXE SVKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-.286
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ db 119,141,132,142 ;@@ Keypad 7, 8, 9, - (PTM 5024)
+ db 115,143,116,144 ;@@ Keypad 4, 5, 6, + (PTM 5024)
+Public _Ow2SV437001 ;***************
+_Ow2SV437001 Label Byte ;Beginning of the table. SV 437 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,1,0,0,0,1,0,1,0,0,AT,Len1,'SV','153'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, '#', 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', '^', 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '&', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '*', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', '(', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', ')', 0, 0 ; 11 0 =
+ KeyDef 21, 0,0,0,0,0,0,0, '+', '?', '_', '-', 0 ; 12 + ?
+ KeyDef 21, 0,0,0,0,0,0,0, 1, 2, '+', '=', 0 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, '{', '[', 0 ; 26 a A (overcircle)
+ KeyDef 21, 0,0,0,0,0,0,0, 3, 4, '}', ']', 0 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 94h, 99h, ':', ';', 0 ; 39 o O (diaresis)
+ KeyDef 3, 0,0,0,0,0,0,0, 84h, 8Eh, '"', "'", 0 ; 40 a A (diaresis)
+ KeyDef 21, 0,0,0,0,0,0,0, '<', '>', 7Ch, '\', 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 21, 0,0,0,0,0,0,0, "'", '*', '~', '`', 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', '<', 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', '>', 0, 0 ; 52 . :
+ KeyDef 21, 0,0,0,0,0,0,0, '-', '_', '?', '/', 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,0,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",13,0,0,0,131,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h,' ',"'">
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <0FEh,27,29,27,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2SV437001
+
+;******************************************************************************
+
+Public _Ow2SV437011 ;***************
+_Ow2SV437011 Label Byte ;Beginning of the table. SV 437 EN Kbd
+ ;***************
+
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,0,1,0,1,0,0,EN,Len2,'SV','153'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 9Ch, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', 0, '$', 0, 0 ; 5 4 monetary symbol
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '{', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '[', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', ']', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', '}', 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '?', '\', 0, 0 ; 12 + ?
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, 0, 0, 1 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, 0, 0, 0 ; 26 a A (overcircle)
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, 5, 0, 3 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 94h, 99h, 0, 0, 0 ; 39 o O (diaresis)
+ KeyDef 3, 0,0,0,0,0,0,0, 84h, 8Eh, 0, 0, 0 ; 40 a A (diaresis)
+ KeyDef 4, 0,0,0,0,0,0,0, 15h,0ABh, 0, 0, 0 ; 41 section one-half
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '*', 0, 0, 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,1,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,0,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del ,
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 7Ch, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <"'",13,0,0,0,131,'a',0A0h,'e',82h,'i',0A1h,'o',0A2h,'u',0A3h,'E',90h,' ',"'">
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,' ','`'>
+
+AccEnt <0FEh,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'O',99h,'U',9Ah>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,' ','^'>
+
+AccEnt <'~',27,29,27,0,0,'n',0A4h,'N',0A5h,' ','~'>
+
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2SV437011
+
+;*****************************************************************************
+
+Public _Ow2SV850000 ;***************
+_Ow2SV850000 Label Byte ;Beginning of the table. SV 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,1,0,0,0,0,0,1,0,0,AT,Len3,'SV','153'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, '#', 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', '^', 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '&', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '*', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', '(', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', ')', 0, 0 ; 11 0 =
+ KeyDef 21, 0,0,0,0,0,0,0, '+', '?', '_', '-', 0 ; 12 + ?
+ KeyDef 21, 0,0,0,0,0,0,0, 1, 2, '+', '=', 0 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 1,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, '{', '[', 0 ; 26 a A (overcircle)
+ KeyDef 21, 0,0,0,0,0,0,0, 3, 4, '}', ']', 0 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 94h, 99h, ':', ';', 0 ; 39 o O (diaresis)
+ KeyDef 3, 0,0,0,0,0,0,0, 84h, 8Eh, '"', "'", 0 ; 40 a A (diaresis)
+ KeyDef 21, 0,0,0,0,0,0,0, '<', '>', 7Ch, '\', 0 ; 41 < >
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 21, 0,0,0,0,0,0,0, "'", '*', '~', '`', 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', '<', 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', '>', 0, 0 ; 52 . :
+ KeyDef 21, 0,0,0,0,0,0,0, '-', '_', '?', '/', 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+;AccEnt #1
+db 0EFh,13, 0,0, 0,131
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh, ' ',0EFh
+db 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <0F9h,27,29,27,0,0,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2SV850000
+
+;*****************************************************************************
+
+Public _Ow2SV850010 ;***************
+_Ow2SV850010 Label Byte ;Beginning of the table. SV 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,1,0,0,EN,Len4,'SV','153'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', '@', 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 9Ch, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4',0CFh, '$', 0, 0 ; 5 4 monetary symbol
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '/', '{', 0, 0 ; 8 7 /
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', '[', 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')', ']', 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '=', '}', 0, 0 ; 11 0 =
+ KeyDef 4, 0,0,0,0,0,0,0, '+', '?', '\', 0, 0 ; 12 + ?
+ KeyDef 11, 0,0,0,0,0,0,0, 1, 2, 0, 0, 1 ; 13 acute grave
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 1,1,1,1,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 1,0,1,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 1,1,1,1,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 1,1,1,1,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 1,1,1,1,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 3, 0,0,0,0,0,0,0, 86h, 8Fh, 0, 0, 0 ; 26 a A (overcircle)
+ KeyDef 11, 0,0,0,0,0,0,0, 3, 4, 5, 0, 3 ; 27 diaresis circumflex
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 1,1,1,1,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 3, 0,0,0,0,0,0,0, 94h, 99h, 0, 0, 0 ; 39 o O (diaresis)
+ KeyDef 3, 0,0,0,0,0,0,0, 84h, 8Eh, 0, 0, 0 ; 40 a A (diaresis)
+ KeyDef 4, 0,0,0,0,0,0,0, 0F5h,0ABh, 0, 0, 0 ; 41 section one-half
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '*', 0, 0, 0 ; 43 ' *
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,1,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', ';', 0, 0, 0 ; 51 , ;
+ KeyDef 4, 0,0,0,0,0,0,0, '.', ':', 0, 0, 0 ; 52 . :
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 53 - _
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 1,1,1,1,1,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, ',', 0, 0, 0 ; 83 Del ,
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '<', '>', 7Ch, 0, 0 ; 86 < >
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+;AccEnt #1
+db 0EFh,13, 0,0, 0,131
+db 'a',0A0h, 'e',82h, 'i',0A1h, 'o',0A2h, 'u',0A3h, 'y',0ECh
+db 'A',0B5h, 'E',90h, 'I',0D6h, 'O',0E0h, 'U',0E9h, 'Y',0EDh, ' ',0EFh
+db 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0
+
+AccEnt <'`',13,0,0,0,131,'a',85h,'e',8Ah,'i',8Dh,'o',95h,'u',97h,'A',0B7h,'E',0D4h,'I',0DEh,'O',0E3h,'U',0EBh,' ','`'>
+
+AccEnt <0F9h,27,29,27,0,27,'a',84h,'e',89h,'i',8Bh,'o',94h,'u',81h,'y',98h,'A',8Eh,'E',0D3h,'I',0D8h,'O',99h,'U',9Ah,' ',0F9h>
+
+AccEnt <'^',27,29,27,0,0,'a',83h,'e',88h,'i',8Ch,'o',93h,'u',96h,'A',0B6h,'E',0D2h,'I',0D7h,'O',0E2h,'U',0EAh,' ','^'>
+
+AccEnt <'~',27,29,27,0,0,'n',0A4h,'N',0A5h,' ','~'>
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2SV850010
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/ukkbd.asm b/private/os2/os2ses/i386/ukkbd.asm
new file mode 100644
index 000000000..dbc3c35e6
--- /dev/null
+++ b/private/os2/os2ses/i386/ukkbd.asm
@@ -0,0 +1,1129 @@
+;; SCCSID = @(#)ukkbd.asm 12.1 88/03/18
+ Page 58,132
+ Title UKKBD - Translate Table Structure for CP/DOS 1.1
+ Name UKKBD
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: UKKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for UK. *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;* Changes: *
+;* Changed 7Ch to B3h for scan code 29h in ENH 437, all *
+;* cs IDs (PTM 186). pjr *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK UKKBD; **
+;** RELOC UKKBD.EXE UKKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-.286
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+; db 115,143,116,144 ;@@ Keypad 4, 5, 6, + (PTM 5024)
+; db 117,145,118 ;@@ Keypad 1, 2, 3 (PTM 5024)
+
+Public _Ow2UK437001 ;***************
+_Ow2UK437001 Label Byte ;Beginning of the table. UK 437 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,0,1,0,0,0,1,AT,Len1,'UK','166' ;&&
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, 0, 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '@', 0, 0, 0 ; 40 ' @
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 41 \ |
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '#', '~', 0, 0, 0 ; 43 # ~
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2UK437001
+
+;***************************************************************************
+
+Public _Ow2UK437011 ;***************
+_Ow2UK437011 Label Byte ;Beginning of the table. UK 437 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,0,1,0,0,0,1,EN,Len2,'UK','166'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, 0, 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '@', 0, 0, 0 ; 40 ' @
+ KeyDef 4, 0,0,0,0,0,0,0, '`', 'ª',0B3h, 0, 0 ; 41 ` ª
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '#', '~', 0, 0, 0 ; 43 # ~
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 86 \ |
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2UK437011
+
+
+;***************************************************************************
+;&&B
+Public _Ow2UK437111 ;***********************
+_Ow2UK437111 Label Byte ;Beginning of the table. UK 437 EN Kbd New Std
+ ;***********************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,1,0,1,0,0,0,1,EN,Len3,'UK','168'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"',0FDh, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, 0, 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%',0ABh, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', "'", 0, 0, 0 ; 8 7 '
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')',0F1h, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '#',0F8h, 0, 0 ; 11 0 #
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '=', 0, 0, 0 ; 12 - =
+ KeyDef 4, 0,0,0,0,0,0,0, 'ª',0C4h, 0, 0, 0 ; 13 _ ª
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '@', '`', 0, 0, 0 ; 26 @ grave accent
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', '~', 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '+', 0, 0, 0 ; 39 ; +
+ KeyDef 4, 0,0,0,0,0,0,0, ':', '*', '^', 0, 0 ; 40 ' @
+ KeyDef 4, 0,0,0,0,0,0,0, '\',0B3h, 0, 0, 0 ; 41 \ ³
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 43 # ~
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 'æ', 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '|', '_', 0, 0, 0 ; 86 | _
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2UK437111
+;&&E
+
+
+
+;***************************************************************************
+
+Public _Ow2UK850000 ;***************
+_Ow2UK850000 Label Byte ;Beginning of the table. UK 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,0,0,0,0,0,0,1,AT,Len4,'UK','166'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, 0, 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '@', 0, 0, 0 ; 40 ' @
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 41 \ |
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '#', '~', 0, 0, 0 ; 43 # ~
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2UK850000
+
+;***************************************************************************
+
+Public _Ow2UK850010 ;***************
+_Ow2UK850010 Label Byte ;Beginning of the table. UK 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,0,0,1,EN,Len5,'UK','166'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"', 0, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch, 0, 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '@', 0, 0, 0 ; 40 ' @
+ KeyDef 4, 0,0,0,0,0,0,0, '`', 'ª', 7Ch, 0, 0 ; 41 ` ª
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '#', '~', 0, 0, 0 ; 43 # ~
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, '\',0DDh, 0, 0, 0 ; 86 \ |
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len5 EQU $ - _Ow2UK850010
+
+
+
+;***************************************************************************
+;&&B
+
+Public _Ow2UK850011 ;***********************
+_Ow2UK850011 Label Byte ;Beginning of the table. UK 850 EN Kbd New Std
+ ;***********************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,1,0,0,0,0,0,1,EN,Len6,'UK','168'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '"',0FDh, 0, 0 ; 3 2 "
+ KeyDef 4, 0,0,0,0,0,0,0, '3', 9Ch,0FCh, 0, 0 ; 4 3 9Ch
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%',0ABh, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '&', 0, 0, 0 ; 7 6 &
+ KeyDef 4, 0,0,0,0,0,0,0, '7', "'", 0, 0, 0 ; 8 7 '
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '(', 0, 0, 0 ; 9 8 (
+ KeyDef 4, 0,0,0,0,0,0,0, '9', ')',0F1h, 0, 0 ; 10 9 )
+ KeyDef 4, 0,0,0,0,0,0,0, '0', '#',0F8h, 0, 0 ; 11 0 #
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '=', 0, 0, 0 ; 12 - =
+ KeyDef 4, 0,0,0,0,0,0,0, 'ª',0EEh, 0, 0, 0 ; 13 ª overline
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '@', '`', 0, 0, 0 ; 26 @ `
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', '~', 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', '+', 0, 0, 0 ; 39 ; +
+ KeyDef 4, 0,0,0,0,0,0,0, ':', '*', '^', 0, 0 ; 40 ' @
+ KeyDef 4, 0,0,0,0,0,0,0, '\', 7Ch, 0, 0, 0 ; 41 \ 7C
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 43 ] }
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 'æ', 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 2, 0,0,0,0,0,0,0, 0DDh, '_', 0, 0, 0 ; 86 | _
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,a1,s2,a2..c20,a20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,a1 - c20,a20 are the char/char code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len6 EQU $ - _Ow2UK850011
+;&&E
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/i386/uskbd.asm b/private/os2/os2ses/i386/uskbd.asm
new file mode 100644
index 000000000..8ec338b9f
--- /dev/null
+++ b/private/os2/os2ses/i386/uskbd.asm
@@ -0,0 +1,761 @@
+;; SCCSID = @(#)uskbd.asm 12.1 88/03/18
+; Page 58,132
+ Title USKBD - Translate Table Structure for CP/DOS 1.1
+ Name USKBD
+
+;********************* Start of Specifications *************************
+;* *
+;* Source File Name: USKBD.ASM *
+;* *
+;* Descriptive Name: Keyboard translate tables for US. *
+;* *
+;* *
+;* Status: CP/DOS Version 1.1.1 *
+;* *
+;* Function: N/A *
+;* *
+;* Notes: *
+;* Dependencies: see linkage instructions below *
+;* Restrictions: None *
+;* Patch Label: None *
+;* *
+;* Entry Points: None *
+;* *
+;* External References: None *
+;* *
+;* Changes: *
+;* *
+;* 2/13/87 - Corrected 850 AT LED key keydefs per PTM 2270. pjr *
+;* *
+;********************** End of Specifications **************************
+;***********************************************************************
+;** **
+;** Linkage instructions: **
+;** LINK USKBD; **
+;** RELOC USKBD.EXE USKBD.TBL **
+;** **
+;***********************************************************************
+
+.386p ;MJ-
+
+include kbdxlat.inc
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+Public _Ow2US437001 ;******
+_Ow2US437001 Label Byte ;Beginning of the table. US 437 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,0,1,0,0,0,0,AT,Len1,'US','103'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '@', 0, 0, 0 ; 3 2 @
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, 0, 0 ; 40 ' "
+ KeyDef 4, 0,0,0,0,0,0,0, '`', '~', 0, 0, 0 ; 41 ` ~
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 43 \ |
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len1 EQU $ - _Ow2US437001
+
+;******************************************************************************
+
+Public _Ow2US437011 ;******
+_Ow2US437011 Label Byte ;Beginning of the table. US 437 EN Kbd
+ ;***************
+
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 437,0,0,0,0,1,0,0,0,0,EN,Len2,'US','103'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '@', 0, 0, 0 ; 3 2 @
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, 0, 0 ; 40 ' "
+ KeyDef 4, 0,0,0,0,0,0,0, '`', '~', 0, 0, 0 ; 41 ` ~
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 43 \ |
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len2 EQU $ - _Ow2US437011
+
+;*****************************************************************************
+
+Public _Ow2US850000 ;******
+_Ow2US850000 Label Byte ;Beginning of the table. US 850 AT Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,0,0,0,0,0,0,0,AT,Len3,'US','103'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '@', 0, 0, 0 ; 3 2 @
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, 0, 0 ; 40 ' "
+ KeyDef 4, 0,0,0,0,0,0,0, '`', '~', 0, 0, 0 ; 41 ` ~
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 43 \ |
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccentEntry <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len3 EQU $ - _Ow2US850000
+
+;*****************************************************************************
+
+Public _Ow2US850010 ;******
+_Ow2US850010 Label Byte ;Beginning of the table. US 850 EN Kbd
+ ;***************
+;&& Form of XtHeader "XtHeader cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs"
+;&& where cp is the code page, a,b,c,d,e,f,g,h,i are the flags:
+; a - ShiftAlt (use shift-alt for Char 3)
+; b - AltGrafL (use left alt key for Char 3)
+; c - AltGrafR (use right alt key for Char 3)
+; d - ShiftLock (all core keys are shifted when Capslock active)
+; e - DefaultTable (default table for language)
+; f - ShiftToggle (ShiftLock is toggle operated, not latched)
+; g - AccentPass (invalid dead key/char combination outputs both and beeps)
+; h - CapsShift (use Char 5 for Caps-Shift combination)
+;&& i - MachineDep (table is machine dependent)
+; kb is the keyboard type, l is the length of the table in bytes,
+;&& cc is the country layout ID, and cs is the subcountry layout ID
+
+;&& cp a b c d e f g h i kb l cc cs
+;&& | | | | | | | | | | | | | |
+XtHeader 850,0,0,0,0,0,0,0,0,0,EN,Len4,'US','103'
+
+; Form of XlateTable KeyDefs: "KeyDef f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+; where a,b,c,d,e are Char1 - Char5, f is the Action number to
+; apply in translating this key, and g1-7 are 1 or 0 flags if
+; accents 1 - 7 apply to the key.
+
+; +--Key Type number. +---Chars-+----+----+ Scan Legend
+; | +AccentFlags+ 1 2 3 4 5 Code |
+; | | | | | | | | | | | | | | |
+ KeyDef 8, 0,0,0,0,0,0,0, 27, 27, 0, 0, 0 ; 1 ESC
+ KeyDef 4, 0,0,0,0,0,0,0, '1', '!', 0, 0, 0 ; 2 1 !
+ KeyDef 4, 0,0,0,0,0,0,0, '2', '@', 0, 0, 0 ; 3 2 @
+ KeyDef 4, 0,0,0,0,0,0,0, '3', '#', 0, 0, 0 ; 4 3 #
+ KeyDef 4, 0,0,0,0,0,0,0, '4', '$', 0, 0, 0 ; 5 4 $
+ KeyDef 4, 0,0,0,0,0,0,0, '5', '%', 0, 0, 0 ; 6 5 %
+ KeyDef 4, 0,0,0,0,0,0,0, '6', '^', 0, 0, 0 ; 7 6 ^
+ KeyDef 4, 0,0,0,0,0,0,0, '7', '&', 0, 0, 0 ; 8 7 &
+ KeyDef 4, 0,0,0,0,0,0,0, '8', '*', 0, 0, 0 ; 9 8 *
+ KeyDef 4, 0,0,0,0,0,0,0, '9', '(', 0, 0, 0 ; 10 9 (
+ KeyDef 4, 0,0,0,0,0,0,0, '0', ')', 0, 0, 0 ; 11 0 )
+ KeyDef 4, 0,0,0,0,0,0,0, '-', '_', 0, 0, 0 ; 12 - _
+ KeyDef 4, 0,0,0,0,0,0,0, '=', '+', 0, 0, 0 ; 13 = +
+ KeyDef 8, 0,0,0,0,0,0,0, 8, 127, 0, 0, 0 ; 14 BkSp
+ KeyDef 4, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 15 Tabs
+ KeyDef 1, 0,0,0,0,0,0,0, 'q', 'Q', 0, 0, 0 ; 16 q Q
+ KeyDef 1, 0,0,0,0,0,0,0, 'w', 'W', 0, 0, 0 ; 17 w W
+ KeyDef 1, 0,0,0,0,0,0,0, 'e', 'E', 0, 0, 0 ; 18 e E
+ KeyDef 1, 0,0,0,0,0,0,0, 'r', 'R', 0, 0, 0 ; 19 r R
+ KeyDef 1, 0,0,0,0,0,0,0, 't', 'T', 0, 0, 0 ; 20 t T
+ KeyDef 1, 0,0,0,0,0,0,0, 'y', 'Y', 0, 0, 0 ; 21 y Y
+ KeyDef 1, 0,0,0,0,0,0,0, 'u', 'U', 0, 0, 0 ; 22 u U
+ KeyDef 1, 0,0,0,0,0,0,0, 'i', 'I', 0, 0, 0 ; 23 i I
+ KeyDef 1, 0,0,0,0,0,0,0, 'o', 'O', 0, 0, 0 ; 24 o O
+ KeyDef 1, 0,0,0,0,0,0,0, 'p', 'P', 0, 0, 0 ; 25 p P
+ KeyDef 4, 0,0,0,0,0,0,0, '[', '{', 0, 0, 0 ; 26 [ {
+ KeyDef 4, 0,0,0,0,0,0,0, ']', '}', 0, 0, 0 ; 27 ] }
+ KeyDef 8, 0,0,0,0,0,0,0, 13, 10, 0, 0, 0 ; 28 Enter
+ KeyDef 12, 0,0,0,0,0,0,0, 4, 1, 4, 0, 0 ; 29 Ctrl
+ KeyDef 1, 0,0,0,0,0,0,0, 'a', 'A', 0, 0, 0 ; 30 a A
+ KeyDef 1, 0,0,0,0,0,0,0, 's', 'S', 0, 0, 0 ; 31 s S
+ KeyDef 1, 0,0,0,0,0,0,0, 'd', 'D', 0, 0, 0 ; 32 d D
+ KeyDef 1, 0,0,0,0,0,0,0, 'f', 'F', 0, 0, 0 ; 33 f F
+ KeyDef 1, 0,0,0,0,0,0,0, 'g', 'G', 0, 0, 0 ; 34 g G
+ KeyDef 1, 0,0,0,0,0,0,0, 'h', 'H', 0, 0, 0 ; 35 h H
+ KeyDef 1, 0,0,0,0,0,0,0, 'j', 'J', 0, 0, 0 ; 36 j J
+ KeyDef 1, 0,0,0,0,0,0,0, 'k', 'K', 0, 0, 0 ; 37 k K
+ KeyDef 1, 0,0,0,0,0,0,0, 'l', 'L', 0, 0, 0 ; 38 l L
+ KeyDef 4, 0,0,0,0,0,0,0, ';', ':', 0, 0, 0 ; 39 ; :
+ KeyDef 4, 0,0,0,0,0,0,0, "'", '"', 0, 0, 0 ; 40 ' "
+ KeyDef 4, 0,0,0,0,0,0,0, '`', '~', 0, 0, 0 ; 41 ` ~
+ KeyDef 12, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 42 Shift(L)
+ KeyDef 4, 0,0,0,0,0,0,0, '\', '|', 0, 0, 0 ; 43 \ |
+ KeyDef 1, 0,0,0,0,0,0,0, 'z', 'Z', 0, 0, 0 ; 44 z Z
+ KeyDef 1, 0,0,0,0,0,0,0, 'x', 'X', 0, 0, 0 ; 45 x X
+ KeyDef 1, 0,0,0,0,0,0,0, 'c', 'C', 0, 0, 0 ; 46 c C
+ KeyDef 1, 0,0,0,0,0,0,0, 'v', 'V', 0, 0, 0 ; 47 v V
+ KeyDef 1, 0,0,0,0,0,0,0, 'b', 'B', 0, 0, 0 ; 48 b B
+ KeyDef 1, 0,0,0,0,0,0,0, 'n', 'N', 0, 0, 0 ; 49 n N
+ KeyDef 1, 0,0,0,0,0,0,0, 'm', 'M', 0, 0, 0 ; 50 m M
+ KeyDef 4, 0,0,0,0,0,0,0, ',', '<', 0, 0, 0 ; 51 , <
+ KeyDef 4, 0,0,0,0,0,0,0, '.', '>', 0, 0, 0 ; 52 . >
+ KeyDef 4, 0,0,0,0,0,0,0, '/', '?', 0, 0, 0 ; 53 / ?
+ KeyDef 12, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 54 Shift(R)
+ KeyDef 9, 0,0,0,0,0,0,0, '*', 114, 0, 0, 0 ; 55 * PrtSc
+ KeyDef 14, 0,0,0,0,0,0,0, 8, 2, 8, 0, 0 ; 56 Alt
+ KeyDef 4, 0,0,0,0,0,0,0, ' ', ' ', 0, 0, 0 ; 57 Space
+ KeyDef 16, 0,0,0,0,0,0,0, 40h, 40h, 40h, 0, 0 ; 58 CapsLock
+ KeyDef 6, 0,0,0,0,0,0,0, 1, 0, 0, 0, 0 ; 59 F1
+ KeyDef 6, 0,0,0,0,0,0,0, 2, 0, 0, 0, 0 ; 60 F2
+ KeyDef 6, 0,0,0,0,0,0,0, 3, 0, 0, 0, 0 ; 61 F3
+ KeyDef 6, 0,0,0,0,0,0,0, 4, 0, 0, 0, 0 ; 62 F4
+ KeyDef 6, 0,0,0,0,0,0,0, 5, 0, 0, 0, 0 ; 63 F5
+ KeyDef 6, 0,0,0,0,0,0,0, 6, 0, 0, 0, 0 ; 64 F6
+ KeyDef 6, 0,0,0,0,0,0,0, 7, 0, 0, 0, 0 ; 65 F7
+ KeyDef 6, 0,0,0,0,0,0,0, 8, 0, 0, 0, 0 ; 66 F8
+ KeyDef 6, 0,0,0,0,0,0,0, 9, 0, 0, 0, 0 ; 67 F9
+ KeyDef 6, 0,0,0,0,0,0,0, 10, 0, 0, 0, 0 ; 68 F10
+ KeyDef 15, 0,0,0,0,0,0,0, 20h, 20h, 20h, 0, 0 ; 69 NumLock
+ KeyDef 17, 0,0,0,0,0,0,0, 10h, 10h, 10h, 0, 0 ; 70 ScrollLock
+ KeyDef 7, 0,0,0,0,0,0,0, 0, '7', 0, 0, 0 ; 71 Home 7
+ KeyDef 7, 0,0,0,0,0,0,0, 1, '8', 0, 0, 0 ; 72 'Up' 8
+ KeyDef 7, 0,0,0,0,0,0,0, 2, '9', 0, 0, 0 ; 73 PgUp 9
+ KeyDef 7, 0,0,0,0,0,0,0, 3, '-', 0, 0, 0 ; 74 - (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 4, '4', 0, 0, 0 ; 75 'Left'4
+ KeyDef 7, 0,0,0,0,0,0,0, 5, '5', 0, 0, 0 ; 76 5
+ KeyDef 7, 0,0,0,0,0,0,0, 6, '6', 0, 0, 0 ; 77'Right'6
+ KeyDef 7, 0,0,0,0,0,0,0, 7, '+', 0, 0, 0 ; 78 + (on pad)
+ KeyDef 7, 0,0,0,0,0,0,0, 8, '1', 0, 0, 0 ; 79 End 1
+ KeyDef 7, 0,0,0,0,0,0,0, 9, '2', 0, 0, 0 ; 80 'Down'2
+ KeyDef 7, 0,0,0,0,0,0,0, 10, '3', 0, 0, 0 ; 81 PgDn 3
+ KeyDef 7, 0,0,0,0,0,0,0, 11, '0', 0, 0, 0 ; 82 Ins 0
+ KeyDef 7, 0,0,0,0,0,0,0, 12, '.', 0, 0, 0 ; 83 Del .
+ KeyDef 10, 0,0,0,0,0,0,0, 0, 80h, 80h, 0, 0 ; 84 SysReq
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 85 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 86 '
+ KeyDef 6, 0,0,0,0,0,0,0, 11, 0, 0, 0, 0 ; 87 F11
+ KeyDef 6, 0,0,0,0,0,0,0, 12, 0, 0, 0, 0 ; 88 F12
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 89 (undefined)
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 90 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 91 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 92 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 93 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 94 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 95 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 96 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 97 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 98 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 99 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 100 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 101 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 102 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 103 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 104 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 105 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 106 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 107 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 108 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 109 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 110 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 111 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 112 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 113 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 114 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 115 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 116 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 117 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 118 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 119 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 120 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 121 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 122 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 123 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 124 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 125 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 126 '
+ KeyDef 0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0 ; 127 '
+
+; Form of AccEnt's below is:
+; "AccEnt <a,b,c,d,e,f,c1,s1,c2,s2..c20,s20>"
+; where a & b are the scan code & char to use when the key following this accent
+; isn't affected by the accent so the accent itself must be used,
+; c & d are the scan code & char to use when Ctl-[accent] is pressed,
+; and e & f do the same for Alt-[accent]. c1,s1 - c20,s20 are the char/scan code
+; mapping for accented translation.
+
+;Accent key definitions and mappings.
+
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+AccEnt <>
+
+Len4 EQU $ - _Ow2US850010
+
+_TEXT ends
+ END
diff --git a/private/os2/os2ses/imrqust.c b/private/os2/os2ses/imrqust.c
new file mode 100644
index 000000000..804c57d5f
--- /dev/null
+++ b/private/os2/os2ses/imrqust.c
@@ -0,0 +1,261 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ imrqust.c
+
+Abstract:
+
+ This module contains the Immon requests thread and
+ the handler for Immon requests.
+
+Author:
+
+ Akihiko Sasaki (v-akihis) 18-Dec-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#ifdef DBCS
+
+// If NLS module for console doesn't present, then NO_CONSOLE_NLS switch should be enable
+// difinition.
+// If NLS module for User doesn't present, then NO_IME switch should be enable difinition.
+//#define NO_CONSOLE_NLS
+//#define NO_IME
+
+#define WIN32_ONLY
+#include "os2ses.h"
+#include <stdio.h>
+#ifndef NO_IME
+#include <winnls32.h>
+#endif
+
+
+// From immonerr.h
+#define IM_NO_ERROR 0 /* IMMonitor No Error Code */
+#define IM_GENERAL_ERROR 3081 /* IMMonitor General Error (Internal) */
+#define IM_INVALID_SEG 3082 /* Cannot access application segment */
+#define IM_INVALID_SESSION 3083 /* Cannot register into Monitor chain */
+
+#define IM_IME_NOT_FOUND 3084 /* specified IME is not found */
+#define IM_IME_INV_ENTRY 3085 /* IME doesnot have all IMExxx entries */
+#define IM_NO_DEFAULT_IME 3086 /* there is no default IMEdit */
+#define IM_IME_NOT_INSTALL 3087 /* IME is not installed in this SG */
+#define IM_IME_FAIL_INSTALL 3088 /* fail to install requested IMEdit */
+#define IM_INVALID_LEN 3089 /* Data Length is invalid. (name.....) */
+
+#define IM_NOT_ENOUGH_BUFF 3090 /* buffer is not enough to save data */
+
+#define IM_INVALID_COMMAND 3091 /* invalid command on IMMxxx calls */
+#define IM_RESERVED_COMMAND 3092 /* command is reserved for system use */
+
+#define IM_INVALID_HANDLE 3093 /* invalid handle */
+
+#define IM_NO_XVIO_WINDOW 3094 /* there is no XVIO windows */
+#define IM_WINDOW_HIDDEN 3095 /* cannot make window visible */
+
+#ifndef NO_IME
+USHORT GetEditLen(IMEPRO *);
+#endif
+
+BOOL
+ServeImmonRequest(IN PIMMONREQUEST PReq,
+ OUT PVOID PStatus)
+{
+ DWORD Rc;
+ DWORD dwNlsMode;
+
+ Rc = 0;
+
+ switch (PReq->Request)
+ {
+ case IMMONStatus:
+ if (PReq->d.MonStatBlk.cb != sizeof(MONSTATBLK))
+ {
+#if DBG
+ KdPrint(("OS2SES(ImmonRequest): invalid parameter\n"));
+#endif
+ Rc = ERROR_INVALID_PARAMETER;
+ } else
+ {
+ switch (PReq->d.MonStatBlk.usInfoLevel)
+ {
+ case 0x21:
+#ifndef NO_IME
+ {
+ IMEPRO ImeInfo;
+ PUSHORT pInfoBuf, dst;
+ USHORT BufLen, len;
+
+
+ if (!IMPGetIME( NULL, &ImeInfo ))
+ {
+#if DBG
+ KdPrint(("OS2SES(ImmonRequest): Can not get IME info\n"));
+#endif
+ Rc = IM_IME_NOT_INSTALL;
+ break;
+
+ }
+
+ BufLen = PReq->d.MonStatBlk.cbInfoBuf;
+ if ((GetEditLen(&ImeInfo) + 10) > BufLen)
+ {
+ BufLen = 2;
+ Rc = IM_NOT_ENOUGH_BUFF;
+ } else
+ {
+ pInfoBuf = dst = (PUSHORT)Os2SessionCtrlDataBaseAddress;
+
+ len = strlen(ImeInfo.szName) + 1;
+ *dst++ = len + 2;
+ RtlMoveMemory(dst, ImeInfo.szName, len);
+ (PCHAR) dst += len;
+
+
+ len = strlen(ImeInfo.szDescription) + 1;
+ *dst++ = len + 2;
+ RtlMoveMemory(dst, ImeInfo.szDescription, len);
+ (PCHAR) dst += len;
+
+ len = strlen(ImeInfo.szOptions) + 1;
+ *dst++ = len + 2;
+ RtlMoveMemory(dst, ImeInfo.szOptions, len);
+ (PCHAR) dst += len;
+
+ *dst++ = 3;
+ *(PUCHAR) dst = '\0';
+ }
+ }
+#endif
+ break;
+ case 0x23:
+ if (PReq->d.MonStatBlk.cbInfoBuf < 2)
+ {
+ Rc = ERROR_BUFFER_OVERFLOW;
+ break;
+ }
+#ifndef NO_CONSOLE_NLS
+ if (!GetConsoleNlsMode(hConsoleInput,&dwNlsMode))
+ {
+#if DBG
+ KdPrint(("OS2SES(ImmonRequest): Can not get CONIN NLS Mode\n"));
+#endif
+ dwNlsMode = 0;
+ }
+#else
+ dwNlsMode = 0;
+#endif
+
+#ifndef NO_IME
+ if (dwNlsMode & NLS_IME_DISABLE)
+ *(PUSHORT)Os2SessionCtrlDataBaseAddress = 0;
+ else
+ *(PUSHORT)Os2SessionCtrlDataBaseAddress = 1;
+#endif
+
+ break;
+ default:
+ Rc = IM_INVALID_COMMAND;
+ }
+ }
+ break;
+
+ case IMMONActive:
+
+#ifndef NO_CONSOLE_NLS
+ if (!GetConsoleNlsMode(hConsoleInput,&dwNlsMode))
+ {
+#if DBG
+ KdPrint(("OS2SES(ImmonRequest): Can not get CONIN NLS Mode\n"));
+#endif
+ dwNlsMode = 0;
+ }
+
+ dwNlsMode &= ~NLS_IME_DISABLE;
+
+ if (!SetConsoleNlsMode(hConsoleInput,dwNlsMode))
+ {
+#if DBG
+ KdPrint(("OS2SES(ImmonRequest): Can not set CONIN NLS Mode\n"));
+#endif
+ }
+
+#endif
+ break;
+
+ case IMMONInactive:
+#ifndef NO_CONSOLE_NLS
+ if (!GetConsoleNlsMode(hConsoleInput,&dwNlsMode))
+ {
+#if DBG
+ KdPrint(("OS2SES(ImmonRequest): Can not get CONIN NLS Mode\n"));
+#endif
+ dwNlsMode = 0;
+ }
+
+ dwNlsMode |= NLS_IME_DISABLE;
+
+ if (!SetConsoleNlsMode(hConsoleInput,dwNlsMode))
+ {
+#if DBG
+ KdPrint(("OS2SES(ImmonRequst): Can not set CONIN NLS Mode\n"));
+#endif
+ }
+
+#endif
+ break;
+
+ default:
+ Rc = (DWORD)-1L; //STATUS_INVALID_PARAMETER;
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE)
+ {
+ KdPrint(("OS2SES(ImmonRequest): Unknown Immon request = %lC\n",
+ PReq->Request));
+ }
+#endif
+ }
+
+ if ( Rc == 1 )
+ {
+ Rc = GetLastError();
+ }
+
+ *(PDWORD) PStatus = Rc;
+
+ return(TRUE); // Continue
+}
+
+#ifndef NO_IME
+USHORT
+GetEditLen(IMEPRO *ImeInfo)
+{
+ USHORT Length, Total;
+ CHAR *Str;
+
+ Str = (PUCHAR) ImeInfo->szName;
+ for (Length = 1; *Str++; Length++) ;
+
+ Total = Length;
+
+ Str = (PUCHAR) ImeInfo->szDescription;
+ for (Length = 1; *Str++; Length++) ;
+
+ Total += Length;
+
+ Str = (PUCHAR) ImeInfo->szOptions;
+ for (Length = 1; *Str++; Length++) ;
+
+ return (Total + Length);
+}
+#endif
+#endif
diff --git a/private/os2/os2ses/kbd.h b/private/os2/os2ses/kbd.h
new file mode 100644
index 000000000..8959e7706
--- /dev/null
+++ b/private/os2/os2ses/kbd.h
@@ -0,0 +1,27 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ kbd.h
+
+Abstract:
+
+ Prototypes for functions & macros in kbdrqust.c
+
+Author:
+
+ Michael Jarus (mjarus) 27-Oct-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+
+DWORD KbdNewCp( IN ULONG CodePage);
+
diff --git a/private/os2/os2ses/kbddd.inc b/private/os2/os2ses/kbddd.inc
new file mode 100644
index 000000000..638d3a2af
--- /dev/null
+++ b/private/os2/os2ses/kbddd.inc
@@ -0,0 +1,269 @@
+;; SCCSID = @(#)kbddd.inc 13.1 90/12/14
+;; SCCSID = @(#)kbddd.inc 12.2E%
+;;***********************************************************************
+;;* *
+;;@@ 1.1 Keyboard Device Driver Common Structures and Equates *
+;;* *
+;;***********************************************************************
+
+;*****
+;* Definition of a Character Data record.
+;*****
+CharData Struc ;Format of character data record.
+ Char db ? ;The translated character.
+ Scan db ? ;The original scan code (unless "extended" char).
+ Status db ? ;Status bits (init to "char available", and
+ ;@@ Shift Report off).
+ DShift db ? ;DBCS Shift state at time of keystroke.
+ Shift dw ? ;Shift state at time of keystroke.
+ Time dd ? ;@@ PTM 2233: Timestamp of keystroke in ms since IPL.
+CharData Ends
+ChDaRecLen Equ Size CharData ;Length of a CharData record.
+
+;*****
+;* Definition of the packet to send to the monitors, if any registered.
+;* Even when none registered, is used during and after translation.
+;* See just below for bit equates for the flagwords in the packet.
+;*****
+KPacket Struc ;This is the packet.
+ MonFlags dw 0 ;Flagword for mon's to see with key.
+ Key db ChDaRecLen Dup(0) ;Space for a CharData record.
+ DDFlags dw 0 ;Device driver flags for the packet.
+ ;@@ See DDFlags equates below.
+KPacket Ends
+KeyPacketLen Equ Size KPacket ;Length of this packet.
+
+;***
+;* Following equates apply to the low byte of the MonFlags word in
+;* a Key Packet:
+;***
+;OpenPacket Equ 01h ;Packet is an open request (we don't use this).
+;ClosePacket Equ 02h ;Packet is a close request (we don't use this).
+;FlushPacket Equ 04h ;Packet is a flush request.
+;;NOTE: following must match bit being defined by Mike Peters!!!
+NotInserted Equ 80h ;Key wasn't inserted by a monitor.
+
+;***
+;* Following equates apply to the DDFlags word in a Key Packet:
+;***
+NotSQPacket Equ 0400h ;&& Don't put this packet in SQ buffer
+AccentedKey Equ 0200h ;Key was translated using previous accent.
+MultiMake Equ 0100h ;Key was repeated make of a toggle key.
+SecondaryKey Equ 0080h ;Previous scan code was the E0 prefix code.
+KeyBreak Equ 0040h ;This is the break of the key.
+KeyTypeMask Equ 003Fh ;Isolates the Key Type field of DDFlags.
+UndefKey Equ 003Fh ;@@ Key packet is undefined
+SysReqKey Equ 0017h ;@@ This key packet is the SysReq key (4990)
+PrintFlushKey Equ 0016h ;@@ This packet is Ct-Alt-PrtScr
+PSPrintEchoKey Equ 0015h ;@@ This packet is Ctl-P
+PrintEchoKey Equ 0014h ;@@ This packet is Ctl-PrtScr
+PrtScrKey Equ 0013h ;@@ This packet is PrtScr
+PSBreakKey Equ 0012h ;@@ This packet is Ctl-C
+BreakKey Equ 0011h ;@@ This packet is Ctl-Break
+AccentKey Equ 0010h ;@@ This packet is an accent key
+XRorPNot Equ 000Dh ;## This packet is a Read or Peek Notification Pct.
+HotKeyPacket Equ 000Ch ;&& This packet is the hot key.
+BadKeyCombo Equ 000Bh ;@@ Accent/char combo undefined, beep only.
+WakeUpKey Equ 000Ah ;@@ This packet is one following PAUSEKEY
+PSPauseKey Equ 0009h ;@@ This packet is Ctl-S
+PauseKey Equ 0008h ;@@ This packet is Ctl-Numlock or PAUSE
+ShiftMask Equ 0007h ;@@ Key is a shift Key
+DumpKey Equ 0006h ;@@ This packet is Ctl-Numlock-NumLock
+RebootKey Equ 0005h ;@@ This packet is Ctl-Alt-Del
+ResendCode Equ 0004h ;@@ This packet is resend code from controller
+OverRunCode Equ 0003h ;@@ This packet is overrun code from controller
+SecPrefixCode Equ 0002h ;@@ This packet is E0/E1 scan code
+AckCode Equ 0001h ;@@ This packet is ack code from keyboard
+
+
+;*****
+;* SFlags - Equates to use when accessing the ShiftFlags word in a Char-
+;* Data rec. These equates are used when accessing Key Packets, etc.
+;*****
+SysRqFlag = 8000h ;SysRq key down.
+CapsFlag = 4000h ;Capslock key down.
+NumFlag = 2000h ;Numlock key down.
+ScrollFlag = 1000h ;Scroll lock key down.
+RAltFlag = 0800h ;Right Alt key down.
+RCtlFlag = 0400h ;Right Ctrl key down.
+LAltFlag = 0200h ;Left Alt key down.
+LCtlFlag = 0100h ;Left Ctrl key down.
+
+;Following can be used when accessing low-byte only, also.
+
+InsTogl = 0080h ;Insert key toggled on.
+CapsTogl = 0040h ;Capslock key toggled on.
+NumTogl = 0020h ;Numlock key toggled on.
+ScrollTogl = 0010h ;Scroll lock key toggled on.
+AltFlag = 0008h ;An Alt key is down.
+CtlFlag = 0004h ;A Ctrl key is down.
+LShiftFlag = 0002h ;Left shift key down.
+RShiftFlag = 0001h ;Right shift key down.
+
+ifdef JAPAN
+; MSKK Aug.15.1993 V-AKihiS
+;*****
+;* DSFlags - Equates to use when accessing the DShiftFlags word in a Char-
+;* Data rec. These equates are used when accessing Key Packets, etc.
+;*****
+
+KanaToKanji = 10000000b ;Kana to Kanji transfar mode.
+RomanMode = 01000000b ;Roman character mode.
+ShiftDisp = 00011000b ;Display of shift status line.
+CharMode = 00000110b ;Character mode.
+DoubleChar = 00000001b ;Double byte character (Zen-Kaku).
+
+Katakana = 010b ;CharMode is katakana mode.
+Hiragana = 100b ;CharMode is Hiragana mode.
+CMResMask Equ RomanMode+Katakana+Hiragana+DoubleChar
+ToggleMake Equ 01h ;Key was repeated make of a toggle key.
+endif
+
+;@@ PTM 3377: Following equate used for checking reserved bits for Set
+;@@ SM Hot Key IOCTL (56h):
+
+HKResMask Equ InsTogl+CapsTogl+NumTogl+ScrollTogl+AltFlag+CtlFlag ;@@
+
+;@@ *****
+;@@ Following is the structure of the Flag variable data areas used
+;@@ by KbdXlate, for both interrupt- and strategy- time translation.
+;@@ *****
+
+XlateVars Struc ;@@ The flag area structure.
+ XDRFlags dw 0 ;@@ See XCOMPLETE below. Not
+ ;@@ used at interrupt time.
+ XHotKeyShift dw 0 ;@@ ;OS2SS-Moved to here, Interrupt driven shift status
+ XPSGFlags dw 0 ;@@ ;OS2SS-Moved to here, Copy of caller's PSG flags.
+ ;&& (changed byte->word and position
+ ;&& in structure per DCR8)
+ XlateFlags db 0 ;@@ See equates below.
+ ToggleFlags db 0 ;@@ See equates below.
+ XInputMode db 0 ;@@ Copy of desired input mode.
+ XAltKeyPad db 0 ;@@ Accumulator for Alt-nnn entry
+ OtherFlags db 0 ;Misc flags (should be zeroed on a session switch).
+XlateVars Ends ;@@ End flag area stucture.
+
+XLATEVARSIZE Equ Size XlateVars ;@@ Get the size of this area.
+ ;@@ NOTE! Beware of XDRSIZE
+ ;@@ adjustment of XlateVars in
+ ;@@ KBDDATA.ASM!
+
+;XCOMPLETE Equ 0001h ;@@ Indicates strategy time
+; ;@@ translation is complete.
+
+;Equates for using XlateFlags byte in translation data area:
+
+DumpKeyOnce Equ 01h ;Dump key sequence has been hit once.
+PSKeyDown Equ 02h ;Print Screen key is down right now.
+SecPrefix Equ 04h ;G keyboard E0 prefix scan code just seen.
+NormalAlt Equ 08h ;@@ Normal Alt (not AltGraph) is down
+Use3Index Equ 10h ;@@ Use character 3 in translate table as index into
+ ;@@ accent table
+PseudoCtl Equ 20h ;@@ Ctl key was emulated by Enhanced kbd
+E1Prefix Equ 40h ;@@ Enhanced keyboard E1 prefix just seen
+
+;Equates for using ToggleFlags byte in translation data area:
+
+TKeyDown = ScrollTogl+NumTogl+CapsTogl ;Latches for toggle keys.
+InsKeyDown Equ 80h ;Insert key is down right now.
+
+;*****
+;* Equates for accessing the XtableFlags1 translate table flagword:
+;*****
+;;XTFlags1 Equ 2 ;Offset of XTableFlags1 in XTHead. ??? NEEDED?
+ShftAlt Equ 0001h ;Use Shift+Alt instead of Ctl+Alt in CtlAltRemap.
+AltGrafL Equ 0002h ;Use left Alt Key as an Alt-Graphics shift key.
+AltGrafR Equ 0004h ;Use right Alt Key as an Alt-Graphics shift key.
+ShiftLock Equ 0008h ;Keyboard uses ShiftLock rather than CapsLock.
+DefTable Equ 0010h ;@@ Default Table for the Language
+ShiftToggle Equ 0020h ;@@ ShiftLock Toggle keyboard
+AccentPass Equ 0040h ;@@ Pass Accent key packet and beep
+CapsShift Equ 0080h ;@@ If CapsShift down, use character 5 from XTable
+
+ATKbd Equ 0000h ;@@ XTKbdType it an AT kbd.
+FERRARI_P Equ 0AB54h ;## PTM 3128 Equate for 88/89 key keyboard.
+FERRARI_G Equ 0AB41h ;## PTM 3128 Equate for 101/102 key keyboard.
+JAGUAR Equ 0AB86h ;%% DCR 1085 Equate for Jaguar 122 key keyboard.
+PCATKBD Equ 0100h ;## ID byte indication for an AT kbd.
+
+;*****
+;* Masks for accessing the XlateOp fields in a keydef.
+;*****
+AccFlagsMask Equ 0FE00h ;@@ Accent flags is now high 7 bits
+ActionMask Equ 01FFh ;@@ KeyType is now low 9 bits
+
+;******
+;* Values for special keyboard scan codes ;@@
+;******
+BufferFull Equ 0FFh ;Keyboard overrun code sent by keyboard.
+Resend Equ 0FEh ;Resend command request from keyboard.
+Ack Equ 0FAh ;Command acknowledge from keyboard.
+OtherKey Equ 0E0h ;Enhanced keyboard's secondary key prefix.
+OtherKey2 Equ 0E1h ;Another secondary key prefix.
+BreakBit Equ 80h ;Mask for break bit in a scan code.
+
+;*****
+;* Equates for PSGFlags - misc flags used by individual screen group.
+;* (Should be zeroed on session termination.)
+;* DCR8: Changed from byte to word to add single queue support.
+;*****
+SQMODE Equ 0200h ;&& Indicates Single Queue mode processing.
+SGInUse Equ 0080h ;This session has been initialized & not terminated.
+;OS2SS-SG3xBox Equ 0040h ;This session is the 3xBox.
+ActiveSG Equ 0020h ;This session is the currently active one.
+Flushing Equ 0010h ;Currently flushing monitors in this PSG.
+NowPaused Equ 0008h ;This session currently paused.
+PrevAccent Equ 0007h ;Bits where accent number saved til next keystroke.
+WakeUpSent Equ 0100h ;## B790266 The WakeUpKey flag has been set ON in the DDFlags
+
+;;*****
+;;* Misc Equates used by various routines:
+;;*****
+;INPUTMODE Equ 80h ;@@ Input mode flag. 1=Binary, 0=ASCII.
+EXTENDEDCODE Equ 2 ;## DCR 357: Define status bit for secondary keys.
+SHIFTREPORT Equ 1 ;@@ Shift Report, input mode flag.
+
+;*****
+;* OtherFlags: Misc flags (should be zeroed on a session switch).
+;* Use following equates to access the OtherFlags byte:
+;*****
+OFlags Record a7:1,a6:1,a5:1,a4:1,a3:1,a2:1,a1:1,a0:1
+;Note: leave HotKeyDown & MHotKeyDown in bits 0 and 1!!!
+;HotKeyDown = Mask a0 ;SM HotKey is down right now.
+;MHotKeyDown = Mask a1 ;Monitor inserted SM HotKey down now.
+InterruptTime = Mask a2 ;Currently processing an interrupt.
+;HotKeyFound = Mask a3 ;@@ Hot key was found in table
+;RecvdPMode = Mask a4 ;@@ PTM 7582 - Interrupt time mode flag.
+;AlreadySwitch = Mask a5 ;@@ PTM 7582 - Interrupt time mode flag.
+;IntInProgress = Mask a6 ;@@ PTM 5336 - Int is in progress.
+;NestedInt = Mask a7 ;@@ PTM 5336 - Interrupt is nested.
+
+;;*****
+;;* MiscFlags: Misc flags, mostly just used once by KBDDD.
+;;* Use following equates to access the MiscFlags byte:
+;;*****
+MFlags Record m7:1,m6:1,m5:1,m4:1,m3:1,m2:1,m1:1,m0:1
+EnhancedKbd = Mask m4 ;Enhanced Kbd is out there (must be Bit 4!).
+
+;&& PTM 291: BEGIN
+;&& *****
+;&& * MiscFlags3:
+;&& * Use following equates to access the MiscFlags3 byte:
+;&& *****
+;&& Define the bits...
+MFlags3 Record mb7:1,mb6:1,mb5:1,mb4:1,mb3:1,mb2:1,mb1:1,mb0:1
+;SQon = Mask mb0 ;&& DCR 75: indicates whether any SG is in SQ.
+AltPacket = Mask mb1 ;&& DCR 1713: indicates that Alt-Numpad
+ ;&& accumulation is finished.
+PauseLatch = Mask mb2 ;&& PTM 2344: indicates correct keystroke
+ ;&& sequence for a Ctrl-NumLock.
+;IOCTl1st = Mask mb3 ;&& PTM 2189: indicates first keyboard IOCTl for
+ ;&& SetCurrentSG received.
+E0Packet = Mask mb4 ;&& PTM 2382: indicates that an E0 packet is
+ ;&& to be sent with the next packet.
+;SENDTIMERNEEDED = Mask mb5 ;&& PTM 291 indicates whether we need the
+ ;&& timer handler to flag an error.
+;SETSENDTIMER = Mask mb6 ;&& PTM 291 indicates whether we need to reset
+ ;&& the ticks for the timer handler.
+SecAltNumPad = Mask mb7 ;## PTR AK00370: indicates AltNumpad with R-Alt.
+
diff --git a/private/os2/os2ses/kbdnls.c b/private/os2/os2ses/kbdnls.c
new file mode 100644
index 000000000..26d6c5207
--- /dev/null
+++ b/private/os2/os2ses/kbdnls.c
@@ -0,0 +1,191 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ kbdnls.c
+
+Abstract:
+
+ This module contains the NLS support for Kbd.
+
+Author:
+
+ KazuM 15-May-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#ifdef DBCS
+
+// If NLS module for console doesn't present, then NO_CONSOLE_NLS switch should be enable
+// difinition.
+// If NLS module for User doesn't present, then NO_IME switch should be enable difinition.
+//#define NO_CONSOLE_NLS
+//#define NO_IME
+
+#include <stdio.h>
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "event.h"
+#include "trans.h"
+#ifndef NO_IME
+#include <ime.h>
+#endif
+
+#ifndef NO_CONSOLE_NLS
+typedef struct _NLS_SHIFT_REPORT {
+ WORD wVirtualKeyCode;
+ BYTE NlsShiftKeyCode;
+} NLS_SHIFT_REPORT, *PNLS_SHIFT_REPORT;
+
+NLS_SHIFT_REPORT NlsShiftReport[] = {
+ {VK_DBE_ALPHANUMERIC, 0x80},
+ {VK_DBE_KATAKANA, 0x40},
+ {VK_DBE_HIRAGANA, 0x20},
+ {VK_KANJI, 0x10},
+ {VK_DBE_SBCSCHAR, 0x08},
+ {VK_DBE_DBCSCHAR, 0x08}
+};
+#endif
+
+BYTE
+MapWinToOs2KbdNlsShift(IN PKEY_EVENT_RECORD WinKey)
+{
+ BYTE bNlsShift = LOBYTE(HIWORD(WinKey->dwControlKeyState));
+
+// MSKK Aug.23.1993 V-AkihiS
+// if (bNlsShift & OS2_NLS_IME_CONVERSION)
+// return bNlsShift;
+// else
+// return 0;
+ return bNlsShift;
+}
+
+BYTE
+MapWinToOs2KbdInterim(IN PKEY_EVENT_RECORD WinKey)
+{
+ return (BYTE)(HIBYTE(HIWORD(WinKey->dwControlKeyState))+0x40);
+}
+
+// MSKK Aug.10.1993 V-AkihiS
+ULONG
+MapWinToOs2KbdNlsChar(IN PKEY_EVENT_RECORD WinKey,
+ OUT PKBD_MON_PACKAGE Os2KeyInfo)
+{
+// MSKK Oct.30.1992 V-AkihiS
+// MSKK Aug.05.1993 V-AkihiS
+ BOOL Dummy;
+ BYTE AsciiDbcs[2];
+ PBYTE Asc;
+ ULONG NumBytes, i;
+
+ NumBytes = sizeof(AsciiDbcs);
+ NumBytes = WideCharToMultiByte(SesGrp->KbdCP,
+ 0,
+ &WinKey->uChar.UnicodeChar,
+ 1,
+ AsciiDbcs,
+ NumBytes,
+ NULL,
+ &Dummy);
+ Asc = AsciiDbcs;
+ for (i = 0; i < NumBytes; i ++) {
+ Os2KeyInfo[i].KeyInfo.chChar = *Asc++;
+ Os2KeyInfo[i].KeyInfo.chScan = 0;
+ Os2KeyInfo[i].KeyInfo.fbStatus = MapWinToOs2KbdInterim(WinKey);
+ }
+
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ KdPrint(("MapWinToOs2KbdNlsChar: ASCII %x, Uni %x, VKey %x, VScan %x, Ctrl %lx =>\n ASCII %x, Scan %x\n",
+ WinKey->uChar.AsciiChar, WinKey->uChar.UnicodeChar,
+ WinKey->wVirtualKeyCode, WinKey->wVirtualScanCode,
+ WinKey->dwControlKeyState,
+ Os2KeyInfo[0].KeyInfo.chChar, Os2KeyInfo[0].KeyInfo.chScan));
+ }
+#endif
+ return NumBytes;
+}
+
+BYTE
+MapWinToOs2KbdNlsShiftReport(IN PKEY_EVENT_RECORD WinKey,
+ IN PKBDKEYINFO Os2Key)
+{
+ int i;
+
+#ifndef NO_CONSOLE_NLS
+ if (Os2Key->bNlsShift & OS2_NLS_IME_CONVERSION)
+ {
+ for (i=0; i < sizeof(NlsShiftReport)/sizeof(NLS_SHIFT_REPORT); i++)
+ if (NlsShiftReport[i].wVirtualKeyCode == WinKey->wVirtualKeyCode)
+ if (WinKey->bKeyDown)
+ return NlsShiftReport[i].NlsShiftKeyCode;
+ }
+#endif
+ return 0;
+}
+
+VOID
+GetNlsMode(IN PKBDINFO KbdInfo)
+{
+ DWORD dwNlsMode;
+ BYTE NlsShift;
+ BYTE Interim;
+
+#ifndef NO_CONSOLE_NLS
+ if (!GetConsoleNlsMode(hConsoleInput,&dwNlsMode)) {
+#if DBG
+ IF_OD2_DEBUG2( KBD, OS2_EXE )
+ KdPrint(("GetNlsMode: Can not get CONIN NLS Mode\n"));
+#endif
+ dwNlsMode = 0;
+ }
+#else
+ dwNlsMode = 0;
+#endif
+
+ NlsShift = LOBYTE(HIWORD(dwNlsMode));
+ Interim = HIBYTE(HIWORD(dwNlsMode));
+ KbdInfo->fsInterim = MAKEWORD((KbdInfo->fsInterim | Interim),NlsShift);
+}
+
+VOID
+SetNlsMode(IN KBDINFO KbdInfo)
+{
+ DWORD dwNlsMode;
+ BYTE NlsShift;
+ BYTE Interim;
+
+ NlsShift = HIBYTE(KbdInfo.fsInterim);
+ Interim = LOBYTE(KbdInfo.fsInterim);
+ dwNlsMode = MAKELONG(0, MAKEWORD(NlsShift,Interim));
+
+#ifndef NO_CONSOLE_NLS
+// MSKK Apr.04.1993 V-AkihiS
+// MSKK Aug.23.1993 V-AkihiS
+ //
+ // When hiragana or sbcsdbcs is set, set IME enable flag too.
+ //
+ if (dwNlsMode & (NLS_DBCSCHAR | NLS_HIRAGANA)) {
+ dwNlsMode |= NLS_IME_CONVERSION;
+ }
+
+ if (!SetConsoleNlsMode(hConsoleInput,dwNlsMode)) {
+#if DBG
+ IF_OD2_DEBUG2( KBD, OS2_EXE )
+ KdPrint(("SetNlsMode: Can not set CONIN NLS Mode\n"));
+#endif
+ dwNlsMode = 0;
+ }
+#endif
+
+}
+#endif
diff --git a/private/os2/os2ses/kbdrqust.c b/private/os2/os2ses/kbdrqust.c
new file mode 100644
index 000000000..3c17e9332
--- /dev/null
+++ b/private/os2/os2ses/kbdrqust.c
@@ -0,0 +1,4046 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ kbdrqust.c
+
+Abstract:
+
+ This module contains the Kbd requests thread and
+ the handler for Kbd requests.
+
+Author:
+
+ Michael Jarus (mjarus) 23-Oct-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "trans.h"
+#include "event.h"
+#include "kbd.h"
+#include "os2win.h"
+#include <stdio.h>
+
+#define OS2_SCAN_INSERT_0 0x52
+#define OS2_SCAN_END_1 0x4F
+#define OS2_SCAN_CTRL_END_1 0x75
+#define OS2_SCAN_DOWN_2 0x50
+#define OS2_SCAN_LEFT_4 0x4B
+#define OS2_SCAN_CTRL_LEFT_4 0x73
+#define OS2_SCAN_RIGHT_6 0x4D
+#define OS2_SCAN_CTRL_RIGHT_6 0x74
+#define OS2_SCAN_HOME_7 0x47
+#define OS2_SCAN_CTRL_HOME_7 0x77
+#define OS2_SCAN_UP_8 0x48
+#define OS2_SCAN_DEL 0x53
+
+DWORD
+Ow2GetOs2KbdEventIntoQueue();
+
+DWORD
+Ow2VioUpdateCurPos(
+ IN COORD CurPos
+ );
+
+DWORD
+Ow2VioReadCurPos(
+ );
+
+DWORD
+Ow2VioReadCurType();
+
+VOID
+KbdSetTable(
+ IN ULONG KbdCP
+ );
+
+#if DBG
+BYTE KbdEchoCharToConsoleStr[] = "KbdEchoCharToConsole";
+BYTE KbdEchoCharStr[] = "KbdEchoChar";
+BYTE KbdEchoStringToConsoleStr[] = "KbdEchoStringToConsole";
+BYTE KbdEchoAStringStr[] = "KbdEchoAString";
+BYTE KbdEchoBSAndFillSpacesStr[] = "KbdEchoBSAndFillSpaces";
+BYTE KbdEchoESCStr[] = "KbdEchoESC";
+BYTE KbdCueMoveToRightStr[] = "KbdCueMoveToRight";
+#endif
+
+#define KEYBOARD_NEW_MASK (USHORT)(KEYBOARD_2B_TURNAROUND | KEYBOARD_SHIFT_REPORT)
+#define KEYBOARD_ECHO (USHORT)(KEYBOARD_ECHO_ON | KEYBOARD_ECHO_OFF)
+#define KEYBOARD_INPUT (USHORT)(KEYBOARD_ASCII_MODE | KEYBOARD_BINARY_MODE)
+
+#define KEYBOARD_BINARY_SHIFT (KEYBOARD_BINARY_MODE | KEYBOARD_SHIFT_REPORT)
+#define MODE_BINARY_SHIFT (SHIFT_REPORT_MODE | BINARY_MODE)
+
+#define KEYBOARD_SHIFT_ASCII_INPUT (USHORT)(KEYBOARD_ASCII_MODE | KEYBOARD_SHIFT_REPORT)
+#define KEYBOARD_INPUT_RESERVED \
+ ~( KEYBOARD_ECHO_ON | KEYBOARD_ECHO_OFF | KEYBOARD_BINARY_MODE | \
+ KEYBOARD_ASCII_MODE | KEYBOARD_MODIFY_STATE | KEYBOARD_MODIFY_INTERIM | \
+ KEYBOARD_MODIFY_TURNAROUND | KEYBOARD_2B_TURNAROUND | KEYBOARD_SHIFT_REPORT )
+
+#define KbdBuffSize 256
+#define KBD_BUFFER_ADDRESS ((PUCHAR)KbdAddress) // used for ECHO to console
+#define KBD_BUFFER_SIZE OS2_KBD_PORT_MSG_SIZE
+
+#define ALPHANUM_CHAR(BuffIndex) \
+ ((((Char = LineInputBuff[BuffIndex].Char) >= '0') && \
+ (Char <= '9')) || \
+ ((Char >= 'a') && (Char <= 'z')) || \
+ ((Char >= 'A') && (Char <= 'Z'))) \
+
+#define GET_CURRENT_COORD (SesGrp->WinCoord)
+
+typedef struct _LINE_EDIT_KBD
+{
+ UCHAR Char;
+ SHORT X_Pos; // Used as X Coordinate for edit
+ // Used as offset for CUE
+} LINE_EDIT_KBD;
+
+typedef enum
+{
+ CharMode,
+ AsciiMode,
+ BinaryMode
+} KBDMODE;
+
+//CONSOLE_SCREEN_BUFFER_INFO KbdConsoleInfo;
+KBDMODE KbdState; // state for HandleKeyboardInput
+ULONG KbdWaitFlag; // flags for KbdCheckPackage and
+ // arg to GetKeyboardInput
+/* (from event.h)
+ CharIn Peek String Read
+ ------ ---- ------ ----
+ WAIT_MASK 0x01 User NOWAIT User WAIT (0 IO_WAIT, 1 IO_NOWAIT)
+ ENABLE_SHIFT_KEY 0x02 <if SHIFT report>
+ ENABLE_NON_ASCII_KEY 0x04 + + <if BINARY>
+ ENABLE_LN_EDITOR_KEY 0x08 <if ASCII (for KEYS OFF)>
+ ENABLE_KEYS_ON_KEY 0x10 <if ASCII and KEYS ON>
+ */
+
+#define ENABLE_SHIFT_KEY 0x02 /* enable shift report keys (and break for them) */
+
+/*
+ * for Command line editing
+ */
+
+PUCHAR KbdCueBuffer = NULL; // 64K CUE buffer for KEYS ON
+ // This is a cyclic bufffer and all
+ // pointers are index of type USHORT.
+BOOL KbdLineWasEdited; // TRUE if user edited the current line
+USHORT KbdNextLinePointer; // where to put next input line
+USHORT KbdCurrentLine; // index of current line in KbdCueBuffer
+USHORT KbdIndexInLine; // index of current char in input line
+BOOL KbdCueUpRowIsCurrent; // flag set after CR to indicate UP arrow
+ // returns the current line
+
+/*
+ * for GetOs2KbdRead
+ */
+
+USHORT KbdBuffNextPtr; // when string typed was longer the size (ASCII read only)
+ // it points to the remain string
+USHORT KbdBuffNextLen; // remaining bytes in the string
+
+/*
+ * for for HandleKeyboardInput.CharMode:
+ */
+
+BOOL KbdPeekFlag; // called by CharIn (0) or Peek(1)
+
+/*
+ * for for HandleKeyboardInput.Ascii/BinaryMode:
+ */
+
+USHORT KbdInputLength; // the current string length (num of chars
+ // already in input buffer for the user)
+ULONG KbdMaxLength; // maximun input length (String.cb
+ // for StringIn, KbdBuffSize for Read)
+USHORT KbdLength; // On enter: the requested length,
+ // On exit: the returned string length
+USHORT KbdEndLength; // length of Turn Around string
+
+/*
+ * for for HandleKeyboardInput.AsciiMode:
+ */
+
+LINE_EDIT_KBD LineInputBuff[KbdBuffSize]; // the current input buffer
+UCHAR KbdLastBuff[KbdBuffSize]; // holds the previous "Buff"
+USHORT KbdLastBuffPtr; // points to the char in KbdLastBuff to take (if F1)
+USHORT LastStringLength; // length of the previous "Buff"
+USHORT KbdEditFlag; // support EDIT line (F1 .. F4, ->, <-, Ins, Del)
+USHORT KbdReadMode; // called by StringIn (0) or Read(1)
+USHORT KbdFxWaitForChar; // waiting for char after F2(1) or F4(2)
+BOOL KbdEchoFlag; // set if ECHO ON
+BOOL KbdInsertOn; // INSERT key current state (1 - ON)
+BOOL KbdEchoString; // copy string from last buffer (F2 and F3)
+USHORT KbdTurnAroundChar; // turn around char to look for
+BOOLEAN KbdTurnAroundCharTwo; // 2-byte turn around char (KEYBOARD_2B_TURNAROUND)
+USHORT KbdDelIndex;
+SHORT KbdFirstColumn; // first column for this input request
+SHORT KbdStartOfLine; // first column on this line
+
+BOOLEAN KbdSetupTurnAroundCharTwo; // KbsSetStatus of KbdTurnAroundCharTwo:
+ // before new read KbdTurnAroundCharTwo
+ // is updated from this.
+
+#ifdef JAPAN
+// MSKK May.07.1993 V-AkihiS
+/*
+ * for KBDGetKbdType
+ */
+extern USHORT KbdType, KbdSubType;
+extern BYTE OemId, OemSubType;
+#endif
+
+/*
+ * internal functions
+ */
+
+DWORD
+GetOs2KbdKey(
+ IN BOOL PeekFlag,
+ IN USHORT WaitFlag,
+ OUT PKBDKEYINFO KeyInfo,
+ IN PVOID pMsg,
+ OUT PULONG pReply
+ );
+
+DWORD
+GetOs2KbdString(
+ IN USHORT WaitFlag,
+ IN OUT PKBDREQUEST PReq,
+ IN PVOID pMsg,
+ OUT PULONG pReply
+ );
+
+DWORD
+GetOs2KbdRead(
+ IN PULONG Length,
+ IN PVOID pMsg,
+ OUT PULONG pReply
+ );
+
+VOID
+KbdNewSetup(
+ IN PKBDINFO LastSetup
+ );
+
+DWORD
+GetOs2KbdStringRead(
+ IN USHORT WaitFlag,
+ IN USHORT EditFlag,
+ IN USHORT ReadMode,
+ IN ULONG MaxLength,
+ IN OUT PUSHORT Length,
+ IN PVOID pMsg,
+ OUT PULONG pReply
+ );
+
+DWORD
+HandleKeyboardInput(
+ IN PKEYEVENTINFO pKbd
+ );
+
+DWORD
+Ow2KbdSetStatus(
+ IN PKBDREQUEST PReq
+ );
+
+BOOL
+KbdKeyIsTurnAround(
+ IN UCHAR Char,
+ IN UCHAR Scan
+ );
+
+/*
+ * Echo functions for KbdStringIn/Read (ASCII)
+ */
+
+DWORD
+KbdEchoNL(
+ IN ULONG Count
+ );
+
+DWORD
+KbdEchoESC(
+ IN ULONG Count,
+ IN ULONG HorzMove
+ );
+
+DWORD
+KbdEchoBSAndFillSpaces(
+ IN ULONG BSCount,
+ IN ULONG SpaceCount
+ );
+
+DWORD
+KbdEchoBeep(
+ IN ULONG Count
+ );
+
+DWORD
+KbdEchoChar(
+ IN UCHAR Char,
+ IN ULONG Count
+ );
+
+DWORD
+KbdEchoAString(
+ IN PUCHAR String,
+ IN ULONG Length
+ );
+
+/*
+ * CUE functions
+ */
+
+VOID
+KbdCueEraseAndDisplayLine(
+ IN ULONG NewLineIndex
+ );
+
+VOID
+KbdCueMoveToRight(
+ IN ULONG StartIndex,
+ IN ULONG StringLength,
+ IN ULONG UpdateLVB
+ );
+
+VOID
+KbdCueMoveToLeft(
+ IN ULONG StartIndex,
+ IN ULONG MoveLength
+ );
+
+VOID
+KbdCueUpdateBufferOffset(
+ IN ULONG StartIndex,
+ IN ULONG StringLength,
+ IN ULONG StartOffset
+ );
+
+VOID
+KbdCueDeleteCharAndShift(
+ IN ULONG StartIndex,
+ IN ULONG NumChar
+ );
+
+VOID
+KbdCueHandleChar(
+ IN UCHAR Char,
+ IN ULONG Count
+ );
+
+VOID
+KbdCueSetCurTypeToHalf();
+
+VOID
+KbdCueSetCurTypeToQuater();
+
+
+DWORD
+KbdInit(IN VOID)
+{
+ KBDINFO LastSetup;
+
+ if (InitQueue(&KbdQueue))
+ {
+ return(TRUE);
+ }
+
+ KbdMonQueue = PhyKbdQueue = KbdQueue;
+
+ KbdQueue->Setup.cb = sizeof(KBDINFO);
+ KbdQueue->Setup.fsMask = KEYBOARD_ECHO_ON | KEYBOARD_ASCII_MODE;
+ KbdQueue->Setup.chTurnAround = 0x0D; /* default: <ENTER>/<CR> */
+ KbdQueue->Setup.fsInterim = 0;
+ KbdQueue->Setup.fsState = 0;
+ KbdQueue->bNlsShift = 0;
+ KbdQueue->LastKeyFlag = FALSE;
+
+ LastSetup.fsMask = KEYBOARD_BINARY_MODE;
+ KbdNewSetup(&LastSetup);
+
+ KbdAddress = ((PCHAR)Os2SessionCtrlDataBaseAddress) + KBD_OFFSET;
+
+ Ow2KbdXlateVars.OtherFlags = InterruptTime;
+
+ return(FALSE);
+}
+
+
+DWORD
+KbdInitAfterSesGrp(IN VOID)
+{
+ if (SesGrp->KeysOnFlag)
+ {
+ KbdCueBuffer = HeapAlloc(HandleHeap, 0, 64 * 1024);
+ if ( KbdCueBuffer == NULL )
+ {
+#if DBG
+ KdPrint(("OS2SES(KbdRequset): unable to allocate Cue buffer\n"));
+#endif
+ return ERROR_KBD_NO_MORE_HANDLE;
+ }
+ }
+ return(FALSE);
+}
+
+
+BOOL
+ServeKbdRequest(IN PKBDREQUEST PReq,
+ OUT PVOID PStatus,
+ IN PVOID pMsg,
+ OUT PULONG pReply)
+{
+ DWORD Rc;
+ KBDINFO LastSetup;
+ PKEY_EVENT_QUEUE TempKbdQueue;
+ KEYEVENTINFO In;
+
+ Rc = 0;
+ TempKbdQueue = (PKEY_EVENT_QUEUE) PReq->hKbd;
+
+#if DBG
+ if (( PReq->Request != KBDNewFocus ) &&
+ ( PReq->Request != KBDNewCountry ) &&
+ ( PReq->Request != KBDOpen ) &&
+ (KbdQueue != TempKbdQueue))
+ {
+ KdPrint(("OS2SES(KbdRequest-%u): illegal handle\n",
+ PReq->Request));
+ }
+#endif
+
+ switch (PReq->Request)
+ {
+ case KBDOpen:
+ if((Rc = InitQueue(&TempKbdQueue)) == NO_ERROR)
+ {
+ PReq->hKbd = TempKbdQueue;
+ }
+ break;
+
+ case KBDClose:
+ if (( TempKbdQueue != PhyKbdQueue) && TempKbdQueue->Count )
+ {
+ if ( !--TempKbdQueue->Count )
+ {
+ HeapFree(HandleHeap, 0,
+ (LPSTR) TempKbdQueue->MonHdr.MemoryStartAddress);
+ }
+ }
+ break;
+
+ case KBDDupLogHandle:
+ if (TempKbdQueue != PhyKbdQueue)
+ {
+ TempKbdQueue->Count++ ;
+ }
+ break;
+
+ case KBDReadStdIn:
+ if (!hStdInConsoleType)
+ {
+#if DBG
+ KdPrint(("OS2SES(KbdRequest-KbdReadStdIn): illegal request\n"));
+#endif
+ Rc = ERROR_INVALID_HANDLE;
+ break;
+ }
+ // falls into KBDRead
+
+ case KBDRead:
+ Rc = GetOs2KbdRead(&PReq->Length,
+ pMsg,
+ pReply);
+ break;
+
+
+ case KBDCharIn:
+ Rc = GetOs2KbdKey(0, /* CharIn/Peek flag */
+ (USHORT)PReq->fWait,
+ &PReq->d.KeyInfo,
+ pMsg,
+ pReply);
+ break;
+
+ case KBDStringIn:
+ Rc = GetOs2KbdString((USHORT)PReq->fWait,
+ PReq,
+ pMsg,
+ pReply);
+ break;
+
+ case KBDPeek:
+ Rc = GetOs2KbdKey(1, /* CharIn/Peek flag */
+ IO_NOWAIT,
+ &PReq->d.KeyInfo,
+ pMsg,
+ pReply);
+ break;
+
+ case KBDFlushBuffer:
+ In.wRepeatCount = 0x7FFF;
+ while (TRUE)
+ {
+ KbdQueue->LastKeyFlag = FALSE;
+ KbdQueue->Out == KbdQueue->In;
+
+ Rc = GetKeyboardInput( IO_NOWAIT,
+ &In,
+ pMsg,
+ pReply);
+
+ if ( !Rc ) /* no char & NO_WAIT */
+ break;
+ }
+ break;
+
+ case KBDGetStatus:
+ if (PReq->d.KbdInfo.cb < 10 )
+ { Rc = ERROR_KBD_INVALID_LENGTH;
+ break;
+ }
+ Ow2GetOs2KbdEventIntoQueue();
+ PReq->d.KbdInfo = KbdQueue->Setup;
+#ifdef DBCS
+// MSKK May.18.1992 KazuM
+ GetNlsMode(&KbdQueue->Setup);
+#endif
+ PReq->d.KbdInfo.fsState &= KBDINFO_STATE_MASK;
+ break;
+
+ case KBDSetStatus:
+ Rc = Ow2KbdSetStatus(PReq);
+ break;
+
+ case KBDFreeFocus:
+ LastSetup = KbdQueue->Setup;
+ KbdQueue = PhyKbdQueue;
+ NewKbdQueue(KbdQueue);
+ KbdNewSetup(&LastSetup);
+ break;
+
+ case KBDNewFocus:
+ LastSetup = KbdQueue->Setup;
+ KbdQueue = TempKbdQueue;
+ NewKbdQueue(KbdQueue);
+ KbdNewSetup(&LastSetup);
+ break;
+
+// BUGBUG?? - do the following requests working on the current/last-focused
+// logical keyboard, on the physical keyboard or on a logical
+// keyboard passed as a parameter
+
+ case KBDGetInputMode:
+ switch (KbdQueue->Setup.fsMask & KEYBOARD_BINARY_SHIFT)
+ {
+ case KEYBOARD_BINARY_SHIFT:
+ PReq->d.InputMode = MODE_BINARY_SHIFT;
+ break;
+
+ case KEYBOARD_BINARY_MODE:
+ PReq->d.InputMode = BINARY_MODE;
+ break;
+
+ default:
+ PReq->d.InputMode = ASCII_MODE;
+ break;
+ }
+ break;
+
+ case KBDGetInterimFlag:
+#ifdef DBCS
+// MSKK May.18.1992 KazuM
+ GetNlsMode(&KbdQueue->Setup);
+#endif
+ PReq->d.Interim = (UCHAR)(KbdQueue->Setup.fsInterim &
+ (CONVERSION_REQUEST | INTERIM_CHAR));
+ break;
+
+ case KBDGetKbdType:
+#ifdef JAPAN
+// MSKK May.07.1993 V-AkihiS
+ if (KbdType == KBD_TYPE_JAPAN && OemId == SUB_KBD_TYPE_MICROSOFT)
+ {
+ switch(OemSubType)
+ {
+ case MICROSOFT_KBD_101_TYPE:
+ PReq->d.KbdType[0] = 0x0001;
+ PReq->d.KbdType[1] = 0x0000;
+ PReq->d.KbdType[2] = 0x0000;
+ break;
+ case MICROSOFT_KBD_AX_TYPE:
+ PReq->d.KbdType[0] = 0x0010;
+ PReq->d.KbdType[1] = 0x0000;
+ PReq->d.KbdType[2] = 0x0001;
+ break;
+ case MICROSOFT_KBD_106_TYPE:
+ PReq->d.KbdType[0] = 0x0001;
+ PReq->d.KbdType[1] = 0x82B3;
+ PReq->d.KbdType[2] = 0x0032;
+ break;
+ case MICROSOFT_KBD_002_TYPE:
+ PReq->d.KbdType[0] = 0x0006;
+ PReq->d.KbdType[1] = 0x82B3;
+ PReq->d.KbdType[2] = 0x0032;
+ break;
+ default:
+ PReq->d.KbdType[0] = 0x0001;
+ PReq->d.KbdType[1] = 0x0000;
+ PReq->d.KbdType[2] = 0x0000;
+#if DBG
+ KdPrint(("OS2SES(Kbd) This keyboard isn't supported yet.\n"));
+#endif
+ }
+ } else
+ {
+ PReq->d.KbdType[0] = 0x0001;
+ PReq->d.KbdType[1] = 0x0000;
+ PReq->d.KbdType[2] = 0x0000;
+#if DBG
+ KdPrint(("OS2SES(Kbd) This keyboard isn't supported yet.\n"));
+#endif
+ }
+#else
+ PReq->d.KbdType = 0x0001; // BUGBUG
+#endif
+ break;
+
+ case KBDGetHotKey:
+ // BUGBUG PReq->d.HotKey =
+ /*
+
+ if ((*pParm != HOTKEY_MAX_COUNT) &&
+ (*pParm != HOTKEY_CURRENT_COUNT))
+ {
+ }
+#define HOTKEY_MAX_COUNT 0x0000
+#define HOTKEY_CURRENT_COUNT 0x0001
+ */
+
+ break;
+
+ case KBDGetShiftState:
+#ifdef DBCS
+// MSKK Oct.20.1992 V-AkihiS
+ GetNlsMode(&KbdQueue->Setup);
+ PReq->d.Shift.fNLS = HIBYTE(KbdQueue->Setup.fsInterim);
+#else
+ PReq->d.Shift.fNLS = KbdQueue->bNlsShift;
+#endif
+ PReq->d.Shift.fsState = KbdQueue->Setup.fsState;
+ break;
+
+ case KBDSetInputMode:
+ LastSetup = KbdQueue->Setup;
+ KbdQueue->Setup.fsMask = (USHORT)
+ ((KbdQueue->Setup.fsMask & ~(KEYBOARD_INPUT | KEYBOARD_SHIFT_REPORT)) |
+ ((PReq->d.InputMode & SHIFT_REPORT_MODE) ? KEYBOARD_SHIFT_REPORT : 0) |
+ ((PReq->d.InputMode & BINARY_MODE ) ?
+ KEYBOARD_BINARY_MODE : KEYBOARD_ASCII_MODE));
+ KbdNewSetup(&LastSetup);
+ break;
+
+ case KBDSetShiftState:
+ LastSetup = KbdQueue->Setup;
+ KbdQueue->Setup.fsState = PReq->d.Shift.fsState;
+ // BUGBUG : SHIFTSTATE.fbNLS PReq->d.Shift.fNLS
+#ifdef DBCS
+// MSKK Oct.20.1992 V-AkihiS
+ KbdQueue->Setup.fsInterim = MAKEWORD(
+ KbdQueue->Setup.fsInterim,
+ PReq->d.Shift.fNLS
+ );
+ SetNlsMode(KbdQueue->Setup);
+#endif
+ KbdNewSetup(&LastSetup);
+ break;
+
+ case KBDSetTypamaticRate:
+ Rc = !SystemParametersInfo(
+ SPI_SETKEYBOARDDELAY,
+ PReq->d.RateDelay.usDelay,
+ NULL,
+ 0);
+ if (!Rc)
+ {
+ Rc = !SystemParametersInfo(
+ SPI_SETKEYBOARDSPEED,
+ PReq->d.RateDelay.usRate,
+ NULL,
+ 0
+ );
+ }
+ break;
+
+ case KBDSetInTerimFlag:
+ LastSetup = KbdQueue->Setup;
+#ifdef DBCS
+// MSKK Mar.03.1993 V-AkihiS
+ KbdQueue->Setup.fsInterim = MAKEWORD(
+ PReq->d.Interim,
+ HIBYTE(KbdQueue->Setup.fsInterim)
+ );
+ SetNlsMode(KbdQueue->Setup);
+#else
+ KbdQueue->Setup.fsInterim = (USHORT)PReq->d.Interim;
+#endif
+ KbdNewSetup(&LastSetup);
+ break;
+
+ case KBDGetCp:
+ PReq->d.CodePage = SesGrp->KbdCP;
+ break;
+
+ case KBDSetCp:
+ Rc = KbdNewCp(PReq->d.CodePage);
+ break;
+
+ case KBDNewCountry:
+ SesGrp->KeyboardCountry = PReq->d.CodePage; //Hack - Not Really CodePage
+ KbdSetTable(SesGrp->KbdCP);
+ *pReply = 0;
+
+ break;
+
+ case KBDXlate:
+ /*
+ {
+ KBD_XLATE_VARS XlateVars;
+ KBD_MON_PACKAGE KeyInfo[3];
+ PKBDTRANS pKbdXlate = &PReq->d.KbdTrans;
+
+ RtlZeroMemory(&XlateVars, sizeof(KBD_XLATE_VARS));
+ if (pKbdXlate->fsShift != 0)
+ {
+ // continue translation
+
+ //? = pKbdXlate->fsShift;
+ }
+
+ RtlZeroMemory(&Os2KeyInfo[0], 3 * sizeof(KBD_MON_PACKAGE));
+
+ //KeyInfo[0].MonitorFlag = pKbdXlate->...;
+ //KeyInfo[0].DeviceFlag = pKbdXlate->...;
+ KeyInfo[0].KeyInfo.chChar = pKbdXlate->chChar;
+ KeyInfo[0].KeyInfo.chScan = pKbdXlate->chScan;
+ KeyInfo[0].KeyInfo.fbStatus = pKbdXlate->fbStatus;
+ KeyInfo[0].KeyInfo.bNlsShift = pKbdXlate->bNlsShift;
+ KeyInfo[0].KeyInfo.fsState = pKbdXlate->fsState;
+ KeyInfo[0].KeyBoardFlag = pKbdXlate->fsDD;
+
+ KeyInfo[0].KeyInfo.fbStatus = 0x40;
+
+ //? XlateVars.XlateFlags |= SecPrefix; // Have seen E0 prefix
+
+ Rc = Ow2KbdXlate(
+ pKbdXlate->chScan, // ScanCode,
+ &XlateVars, // pFlagArea,
+ &KeyInfo[0], // pMonitorPack,
+ Ow2KbdScanTable // pTransTable
+ );
+
+ //? which packet - KeyInfo[?]
+ pKbdXlate->chChar = KeyInfo[0].KeyInfo.chChar;
+ pKbdXlate->chScan = KeyInfo[0].KeyInfo.chScan;
+ pKbdXlate->fbStatus = KeyInfo[0].KeyInfo.fbStatus;
+ pKbdXlate->bNlsShift = KeyInfo[0].KeyInfo.bNlsShift;
+ pKbdXlate->fsState = KeyInfo[0].KeyInfo.fsState;
+ pKbdXlate->fsDD = KeyInfo[0].KeyBoardFlag;
+ //? pKbdXlate->fsXlate = ;
+ //? pKbdXlate->fsShift = ;
+ }
+ */
+ case KBDSetCustXt:
+ /* from ??? */
+ default:
+ Rc = (DWORD)-1L; //STATUS_INVALID_PARAMETER;
+#if DBG
+ IF_OD2_DEBUG2( KBD, OS2_EXE )
+ KdPrint(("OS2SES(KbdRequest): Unknown Kbd request = %X\n", PReq->Request));
+#endif
+ }
+
+ if ( Rc == 1 )
+ {
+ Rc = GetLastError();
+ }
+
+ *(PDWORD) PStatus = Rc;
+ return(TRUE); // Continue
+}
+
+
+DWORD
+Ow2KbdSetStatus(IN PKBDREQUEST PReq)
+{
+ KBDINFO LastSetup, *pKbdSetup;
+ USHORT KbdMask, Mask;
+
+ /*
+ * check legalty of parameters:
+ *
+ * 1. sizeof structure
+ * 2. reserved bits
+ * 3. mutuex bits (ECHO_ON & ECHO_OFF, ASCII & BINARY, ASCII & SHIFT)
+ */
+
+ LastSetup = KbdQueue->Setup;
+ if (PReq->d.KbdInfo.cb != 10 )
+ {
+ return ERROR_KBD_INVALID_LENGTH;
+ }
+
+ KbdMask = PReq->d.KbdInfo.fsMask;
+ pKbdSetup = &KbdQueue->Setup;
+
+ if (KbdMask & KEYBOARD_INPUT_RESERVED)
+ {
+ return ERROR_KBD_INVALID_INPUT_MASK;
+ }
+
+ if ((KbdMask & KEYBOARD_ECHO ) == KEYBOARD_ECHO)
+ {
+ return ERROR_KBD_INVALID_ECHO_MASK;
+ }
+
+ if ((KbdMask & KEYBOARD_INPUT) == KEYBOARD_INPUT)
+ {
+ return ERROR_KBD_INVALID_INPUT_MASK;
+ }
+
+ if ((KbdMask & KEYBOARD_SHIFT_ASCII_INPUT) == KEYBOARD_SHIFT_ASCII_INPUT)
+ {
+ return ERROR_KBD_INVALID_INPUT_MASK;
+ }
+
+ /*
+ * check modified bits and set the flags according:
+ *
+ * 1. STATE - set fsState
+ * 2. INTERIM - set fsInterim
+ * 3. TURNAROUND - set chTurnAround
+ */
+
+#ifdef DBCS
+// MSKK Jul.1993 V-AKihiS
+ if (KbdMask & KEYBOARD_MODIFY_STATE)
+ {
+ pKbdSetup->fsState = PReq->d.KbdInfo.fsState;
+ pKbdSetup->fsInterim = MAKEWORD(
+ LOBYTE(pKbdSetup->fsInterim),
+ HIBYTE(PReq->d.KbdInfo.fsInterim)
+ );
+ SetNlsMode(*pKbdSetup);
+ }
+
+ if (KbdMask & KEYBOARD_MODIFY_INTERIM)
+ pKbdSetup->fsInterim = MAKEWORD(
+ LOBYTE(PReq->d.KbdInfo.fsInterim),
+ HIBYTE(pKbdSetup->fsInterim)
+ );
+#else
+ if (KbdMask & KEYBOARD_MODIFY_STATE)
+ pKbdSetup->fsState = PReq->d.KbdInfo.fsState;
+
+ if (KbdMask & KEYBOARD_MODIFY_INTERIM)
+ pKbdSetup->fsInterim = PReq->d.KbdInfo.fsInterim;
+#endif
+
+ if (KbdMask & KEYBOARD_MODIFY_TURNAROUND)
+ pKbdSetup->chTurnAround = PReq->d.KbdInfo.chTurnAround;
+
+ /*
+ * update mask:
+ *
+ * 1. update mask of new bits SHIFT_REPORT & 2B_TURNAROUND
+ * 2. if new mask includes new ECHO then update mask
+ * 3. if new mask includes new INPUT then update mask
+ */
+
+ Mask = KEYBOARD_NEW_MASK;
+
+ if (KbdMask & KEYBOARD_ECHO)
+ {
+ Mask |= KEYBOARD_ECHO;
+ }
+
+ if (KbdMask & KEYBOARD_INPUT)
+ {
+ Mask |= KEYBOARD_INPUT;
+ }
+
+ pKbdSetup->fsMask =
+ (pKbdSetup->fsMask & ~Mask) | (KbdMask & Mask);
+
+ KbdNewSetup(&LastSetup);
+
+ return (0L);
+}
+
+
+DWORD
+GetOs2KbdKey( IN BOOL PeekFlag,
+ IN USHORT WaitFlag,
+ OUT PKBDKEYINFO KeyInfo,
+ IN PVOID pMsg,
+ OUT PULONG pReply)
+/*++
+
+Routine Description:
+
+ This routine get kbd char for KbdCharIn and KbdPeek
+
+Arguments:
+
+ PeekFlag - TRUE if peek (0 - CharIn, 1 - Peek)
+
+ WaitFlag - Wait if no input (IO_WAIT or IO_NOWAIT)
+
+ KeyInfo - Where to return the key input record
+
+ pMsg - Pointer to the LPC message
+
+ pReply - Pointer to flag if return reply on LPC
+
+Return Value:
+
+
+Note:
+
+ If no event and IO_WAIT: save pMsg, put 0 into *pReply and
+ the reply is postponed.
+
+--*/
+{
+
+ DWORD Rc;
+ KEYEVENTINFO In;
+
+
+ RtlZeroMemory(KeyInfo, sizeof(KBDKEYINFO));
+ KeyInfo->fsState = 1;
+
+ if ( KbdQueue->Setup.fsMask & KEYBOARD_ASCII_MODE )
+ {
+ KbdAsciiMode = 1;
+ } else
+ {
+ KbdAsciiMode = 0;
+ if ((KbdQueue->Setup.fsMask & KEYBOARD_BINARY_SHIFT) == KEYBOARD_BINARY_SHIFT)
+ {
+ WaitFlag |= ENABLE_SHIFT_KEY;
+ }
+ }
+
+ WaitFlag |= ENABLE_NON_ASCII_KEY;
+
+ KbdState = CharMode;
+ KbdWaitFlag = (ULONG)WaitFlag;
+ KbdPeekFlag = PeekFlag;
+
+ for(;;)
+ {
+ if (KbdQueue->LastKeyFlag)
+ {
+ In = KbdQueue->LastKey;
+ KbdQueue->LastKeyFlag = FALSE;
+ } else
+ {
+ In.wRepeatCount = 0x7FFF;
+ Rc = GetKeyboardInput( KbdWaitFlag,
+ &In,
+ pMsg,
+ pReply);
+
+ if ( !Rc ) /* no char & (NO_WAIT or postponed reply) */
+ return(Rc);
+ }
+
+ if (( HandleKeyboardInput(
+ &In
+ )) == NO_ERROR )
+ {
+ *KeyInfo = In.KeyInfo[0].KeyInfo;
+ return(0L);
+ }
+ }
+}
+
+
+DWORD
+GetOs2KbdString( IN USHORT WaitFlag,
+ //IN OUT KBDRW *Length,
+ IN OUT PKBDREQUEST PReq,
+ IN PVOID pMsg,
+ OUT PULONG pReply)
+{
+
+ DWORD Rc;
+ USHORT EditFlag = 0;
+ STRINGINBUF String = PReq->d.String;
+
+ KbdAsciiMode = (BOOL)(( KbdQueue->Setup.fsMask & KEYBOARD_ASCII_MODE ) ? 1 : 0);
+
+ if ( String.cchIn && ( String.cchIn <= String.cb ) &&
+ ( KbdLastBuff[String.cchIn] == '\r' ))
+ {
+ EditFlag = 1;
+ }
+
+ String.cchIn = String.cb;
+
+ Rc = GetOs2KbdStringRead( WaitFlag,
+ EditFlag,
+ 0,
+ (ULONG)String.cb,
+ &String.cchIn,
+ pMsg,
+ pReply);
+ if ( pReply )
+ {
+ PReq->Length = (ULONG)KbdLength;
+ String.cchIn = KbdLength;
+ if ( String.cchIn != String.cb )
+ PReq->Length++ ; // ASCII mode - copy the CR
+ }
+
+ return(Rc);
+
+}
+
+
+DWORD
+GetOs2KbdRead(IN PULONG Length,
+ IN PVOID pMsg,
+ OUT PULONG pReply)
+{
+ DWORD Rc, i;
+
+ KbdAsciiMode = (BOOL)(( KbdQueue->Setup.fsMask & KEYBOARD_ASCII_MODE ) ? 1 : 0);
+
+ /*
+ * ignore previously-typed-but-not-returned character in binary mode
+ */
+
+ if ( !KbdAsciiMode || !KbdBuffNextLen)
+ {
+
+ Rc = GetOs2KbdStringRead( IO_WAIT,
+ TRUE,
+ 1,
+ KbdBuffSize - 2,
+ (PUSHORT)Length,
+ pMsg,
+ pReply);
+
+ return(Rc);
+
+ }
+
+ /*
+ *
+ * Copy from kbd buffer
+ *
+ */
+
+ if (*Length > (ULONG)KbdBuffNextLen)
+ *Length = KbdBuffNextLen;
+
+ for (i = 0 ; i < *Length ; i++ )
+ {
+ if ((KBD_BUFFER_ADDRESS[i] = KbdLastBuff[i + KbdBuffNextPtr]) == '\n')
+ {
+ *Length = i + 1;
+ break;
+ }
+ }
+
+ KbdBuffNextLen -= *((PUSHORT)Length);
+ KbdBuffNextPtr += (USHORT)*Length;
+
+ return(0L);
+}
+
+
+DWORD
+GetOs2KbdStringRead(IN USHORT WaitFlag,
+ IN USHORT EditFlag,
+ IN USHORT ReadMode,
+ IN ULONG MaxLength,
+ IN OUT PUSHORT Length,
+ IN PVOID pMsg,
+ OUT PULONG pReply)
+/*++
+
+Routine Description:
+
+ This routine get kbd string for KbdStringIn and Read("KBD$" or non-redirected
+ STD-IN).
+
+Arguments:
+
+ WaitFlag - Wait if no input (IO_WAIT or IO_NOWAIT)
+
+ EditFlag - TRUE if edit last line(0/1 according to cchIn - StringIn, 1 - Read)
+
+ ReadMode - Called by StringIn (0) or Read(1)
+
+ MaxLength - Maximun input length (String.cb for StringIn, KbdBuffSize
+ for Read)
+
+ Length - On enter: the requested length, on exit: the returned string
+ length (String.cchIn for StringIn, Length field in LPC for Read)
+
+ pMsg - Pointer to the LPC message
+
+ pReply - Pointer to flag if return reply on LPC
+
+Return Value:
+
+
+Note:
+
+ If no event and IO_WAIT: save pMsg, put 0 into *pReply and
+ the reply is postponed.
+
+--*/
+{
+ KEYEVENTINFO In;
+ DWORD Rc;
+
+ KbdLastBuffPtr = KbdInputLength = KbdFxWaitForChar = KbdDelIndex = 0;
+ KbdIndexInLine = 0;
+ KbdInsertOn = KbdEchoString = KbdLineWasEdited = FALSE;
+ //KbdSecondTurnAround = KbdEndFlag = FALSE;
+ KbdLength = *Length;
+
+ if ( KbdAsciiMode )
+ {
+ /*
+ * ASCII mode
+ */
+
+ KbdWaitFlag = (ULONG)(WaitFlag | ENABLE_LN_EDITOR_KEY);
+
+ /*
+ *
+ * Get Start Cursor-Position
+ *
+ */
+
+ // force SesGrp->WinCoord and CurType params to get updated
+
+ Ow2VioReadCurPos();
+ Ow2VioReadCurType();
+
+ if (SesGrp->KeysOnFlag)
+ {
+ KbdWaitFlag |= ENABLE_KEYS_ON_KEY;
+ KbdCueSetCurTypeToQuater();
+ }
+ KbdMaxLength = MaxLength - 1; /* leave space for the TurnAround char at the end */
+ KbdEndLength = 1;
+ KbdReadMode = ReadMode;
+
+ KbdEchoFlag = (BOOL)(( KbdQueue->Setup.fsMask & KEYBOARD_ECHO_ON ) ? 1 : 0);
+ KbdTurnAroundChar = KbdQueue->Setup.chTurnAround;
+ KbdTurnAroundCharTwo = KbdSetupTurnAroundCharTwo;
+
+ //if (KbdQueue->Setup.chTurnAround & 0x80)
+ if(KbdTurnAroundCharTwo)
+ { KbdMaxLength--; /* need another space for 2-byte-TurnAround */
+ KbdEndLength++;
+ }
+
+ KbdEditFlag = EditFlag;
+
+ LineInputBuff[KbdInputLength].X_Pos = KbdStartOfLine = KbdFirstColumn =
+ GET_CURRENT_COORD.X;
+
+ KbdState = AsciiMode;
+
+ } else
+ {
+ KbdWaitFlag = (ULONG)(WaitFlag | ENABLE_NON_ASCII_KEY);
+ KbdState = BinaryMode;
+ }
+
+ for(;;)
+ {
+ /*
+ *
+ * Restore saved Input Key if any
+ *
+ */
+
+ if (KbdQueue->LastKeyFlag)
+ {
+ In = KbdQueue->LastKey;
+ KbdQueue->LastKeyFlag = FALSE;
+ } else
+ {
+ /*
+ *
+ * Get Input Key if any
+ *
+ */
+
+ In.wRepeatCount = 0x7FFF;
+ Rc = GetKeyboardInput( KbdWaitFlag,
+ &In,
+ pMsg,
+ pReply);
+
+ if ( !Rc ) /* no char & NO_WAIT */
+ return(Rc);
+ }
+
+ if (( HandleKeyboardInput(
+ &In
+ )) == NO_ERROR )
+ {
+ *Length = KbdLength;
+ return(0L);
+ }
+ }
+}
+
+
+DWORD
+HandleKeyboardInput(IN PKEYEVENTINFO pKbd)
+{
+ DWORD NumChar = 0;
+ UCHAR Char, Scan, *puchLastString;
+ USHORT i, usIndex, StringLengthToEcho, NumBeep = 0;
+ SHORT X_Pos, Offset;
+
+ Scan = pKbd->KeyInfo[0].KeyInfo.chScan;
+ Char = pKbd->KeyInfo[0].KeyInfo.chChar;
+
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ KdPrint(("HandleKeyboardInput: %s - Char %x, Scan %x, Status %x, State %x, Flag %x\n",
+ (KbdState == CharMode) ? "CharMode" :
+ (KbdState == AsciiMode) ? "AsciiMode" : "BinaryMode",
+ Char, Scan, pKbd->KeyInfo[0].KeyInfo.fbStatus,
+ pKbd->KeyInfo[0].KeyInfo.fsState, pKbd->KeyInfo[0].KeyboardFlag));
+ }
+#endif
+ switch (KbdState)
+ {
+ case CharMode:
+ if ( KbdPeekFlag || (pKbd->wRepeatCount > 1))
+ {
+ KbdQueue->LastKey = *pKbd;
+ KbdQueue->LastKeyFlag = TRUE;
+ if (!KbdPeekFlag)
+ {
+ KbdQueue->LastKey.wRepeatCount--;
+ }
+ }
+
+ return (NO_ERROR);
+ break;
+
+ case AsciiMode:
+
+ KbdQueue->LastKey = *pKbd; // prepare it in case we read only one copy of the char
+ KbdQueue->LastKey.wRepeatCount--;
+
+ /*
+ *
+ * Handle CR (TurnAround Char)
+ *
+ * 1. put in buffer (if there is a room), beep otherwise
+ * 2. echo if echo_on
+ * 3. (READ only) add LF to CR (if there is a place)
+ *
+ */
+
+ if ( !KbdFxWaitForChar && KbdKeyIsTurnAround(Char, Scan) )
+ {
+ if ( pKbd->wRepeatCount > 1 )
+ {
+ KbdQueue->LastKeyFlag = TRUE;
+ }
+
+ if (( KbdReadMode == 1 ) && KbdInputLength &&
+ ( LineInputBuff[0].Char == 0x1A )) // ^Z
+ {
+ NumChar = KbdInputLength = 0;
+ } else
+ {
+ NumChar = KbdInputLength;
+
+ /*
+ * Add the TurnAround char at the end of the buffer
+ */
+
+ LineInputBuff[KbdInputLength++].Char = Char;
+
+ if (KbdTurnAroundCharTwo)
+ {
+ if ( KbdReadMode == 1 )
+ {
+ LineInputBuff[KbdInputLength - 1].Char = '\r';
+ Scan = '\n';
+ }
+ LineInputBuff[KbdInputLength++].Char = Scan;
+ } else if (( KbdReadMode == 1 ) && ( Char == '\r' ) &&
+ ( KbdInputLength <= (USHORT)KbdMaxLength ))
+ {
+ LineInputBuff[KbdInputLength++].Char = '\n';
+ }
+
+ }
+
+ /*
+ * Echo the TurnAround char to console
+ */
+
+ if (KbdEchoFlag && !KbdTurnAroundCharTwo)
+ {
+ KbdEchoNL(1);
+ }
+
+ /*
+ *
+ * Save string length and data in buffer for editing keys
+ *
+ */
+
+ for ( i = 0 ; i < KbdInputLength ; i++ )
+ {
+ KbdLastBuff[i] = LineInputBuff[i].Char;
+ }
+
+ if (KbdReadMode == 0)
+ {
+ KbdInputLength = (USHORT)NumChar;
+ }
+ LastStringLength = (USHORT)NumChar; // not include the TurnAround char
+
+ /*
+ *
+ * Copy to application buffer
+ *
+ */
+
+ if ( KbdLength > KbdInputLength )
+ KbdLength = KbdInputLength;
+
+ RtlMoveMemory(KbdAddress, KbdLastBuff, KbdLength);
+
+ if ( KbdReadMode == 0 )
+ KBD_BUFFER_ADDRESS[KbdLength] = Char; // add the CR at the end
+
+ /*
+ *
+ * Keep info for Read in case we don't return all the string
+ *
+ */
+
+ KbdBuffNextPtr = KbdLength;
+ KbdBuffNextLen = KbdInputLength - KbdLength;
+
+ /*
+ *
+ * Copy string to CUE buffer if active
+ *
+ */
+
+ if ( SesGrp->KeysOnFlag )
+ {
+ if( KbdLineWasEdited && NumChar )
+ {
+ KbdCurrentLine = KbdNextLinePointer;
+
+ for ( i = 0, usIndex = KbdNextLinePointer ;
+ i < NumChar ; i++, usIndex++ )
+ {
+ KbdCueBuffer[usIndex] = KbdLastBuff[i];
+ }
+
+ KbdNextLinePointer = usIndex + 1;
+
+ while (KbdCueBuffer[usIndex])
+ {
+ // zero the end of the last string we copy the new
+ // one on (fill with NULL till start of next line)
+
+ KbdCueBuffer[usIndex++] = 0;
+ }
+ }
+
+ KbdCueUpRowIsCurrent = TRUE;
+ }
+
+ return(0L);
+ }
+
+ /*
+ *
+ * Check for Speciel Keys (PFx, enhanced ...)
+ *
+ */
+
+ if (( Char == 0 ) || ( Char == 0xE0 ))
+ {
+ if (SesGrp->KeysOnFlag)
+ {
+ if ( Scan == OS2_SCAN_RIGHT_6 ) // Right
+ {
+ if (( NumChar = KbdInputLength - KbdIndexInLine ) >
+ pKbd->wRepeatCount )
+ {
+ NumChar = pKbd->wRepeatCount;
+ }
+
+ KbdCueMoveToRight(
+ KbdIndexInLine,
+ (USHORT)NumChar,
+ FALSE
+ );
+
+ } else if ( Scan == OS2_SCAN_LEFT_4 ) // Left
+ {
+ NumChar = ( KbdIndexInLine < pKbd->wRepeatCount ) ?
+ KbdIndexInLine : pKbd->wRepeatCount;
+
+ KbdCueMoveToLeft(
+ KbdIndexInLine,
+ (USHORT)NumChar
+ );
+
+ } else if ( Scan == OS2_SCAN_UP_8 ) // Up
+ {
+ /*
+ * Find previous command in the command queue
+ */
+
+ if (KbdCueBuffer[KbdCurrentLine]) // if anything at the CUE buffer
+ {
+ if (KbdCueUpRowIsCurrent)
+ {
+ pKbd->wRepeatCount--;
+ KbdCueUpRowIsCurrent = FALSE;
+ }
+
+ usIndex = KbdCurrentLine;
+ for ( i = 0 ; i < pKbd->wRepeatCount ; i++ )
+ {
+ usIndex--;
+ while (!KbdCueBuffer[--usIndex]); // skip all null
+ while (KbdCueBuffer[--usIndex]); // go to start of command
+
+ usIndex++;
+ }
+ KbdCurrentLine = usIndex;
+ } else
+ {
+ usIndex = KbdCurrentLine;
+ }
+
+ KbdCueEraseAndDisplayLine(usIndex);
+ } else if ( Scan == OS2_SCAN_DOWN_2 ) // Down
+ {
+ /*
+ * Find next command in the command queue
+ */
+
+ if (KbdCueBuffer[KbdCurrentLine]) // if anything at the CUE buffer
+ {
+ usIndex = KbdCurrentLine;
+ KbdCueUpRowIsCurrent = FALSE;
+
+ for ( i = 0 ; i < pKbd->wRepeatCount ; i++ )
+ {
+ while (KbdCueBuffer[++usIndex]);
+ while (!KbdCueBuffer[++usIndex]);
+ }
+ KbdCurrentLine = usIndex;
+ } else
+ {
+ usIndex = KbdCurrentLine;
+ }
+
+ KbdCueEraseAndDisplayLine(usIndex);
+ } else if ( Scan == OS2_SCAN_HOME_7 ) // Home
+ {
+ KbdCueMoveToLeft(
+ KbdIndexInLine,
+ KbdIndexInLine
+ );
+ } else if ( Scan == OS2_SCAN_END_1 ) // End
+ {
+ KbdCueMoveToRight(
+ KbdIndexInLine,
+ (USHORT)(KbdInputLength - KbdIndexInLine),
+ FALSE
+ );
+
+ } else if ( Scan == OS2_SCAN_CTRL_LEFT_4 ) // ^Left
+ {
+ USHORT PrevIndex = KbdIndexInLine;
+
+ for ( i = 0;
+ (i < pKbd->wRepeatCount) && PrevIndex ;
+ i++ )
+ {
+ /* for each char:
+ * go one char left
+ * skip all non-alphanumeric chars
+ * akip all alphanumeric chars
+ * while points to alpha, which is not the original
+ */
+
+ usIndex = PrevIndex - 1;
+
+ while (usIndex && !ALPHANUM_CHAR(usIndex))
+ {
+ usIndex--;
+ }
+
+ while (usIndex && ALPHANUM_CHAR(usIndex))
+ {
+ usIndex--;
+ }
+
+ if (usIndex || !ALPHANUM_CHAR(usIndex))
+ {
+ usIndex++;
+ }
+
+ if (!ALPHANUM_CHAR(usIndex) ||
+ (PrevIndex == usIndex))
+ {
+ break;
+ }
+
+ PrevIndex = usIndex;
+ }
+ if (NumChar = KbdIndexInLine - PrevIndex)
+ {
+ KbdCueMoveToLeft(
+ KbdIndexInLine,
+ (USHORT)NumChar
+ );
+ }
+ } else if ( Scan == OS2_SCAN_CTRL_RIGHT_6 ) // ^Right
+ {
+ USHORT PrevIndex = KbdIndexInLine;
+
+ for ( i = 0;
+ (i < pKbd->wRepeatCount) && (PrevIndex < KbdInputLength);
+ i++ )
+ {
+ /* for each char:
+ * go one char right
+ * akip all alphanumeric chars
+ * skip all non-alphanumeric chars
+ * while points to alpha, which is not the original
+ */
+
+ usIndex = PrevIndex;
+
+ while ((usIndex < KbdInputLength) &&
+ ALPHANUM_CHAR(usIndex))
+ {
+ usIndex++;
+ }
+
+ while ((usIndex < KbdInputLength) &&
+ !ALPHANUM_CHAR(usIndex))
+ {
+ usIndex++;
+ }
+
+ if ((usIndex >= KbdInputLength) ||
+ !ALPHANUM_CHAR(usIndex))
+ {
+ break;
+ }
+
+ PrevIndex = usIndex;
+ }
+ if (NumChar = PrevIndex - KbdIndexInLine)
+ {
+ KbdCueMoveToRight(
+ KbdIndexInLine,
+ (USHORT)NumChar,
+ FALSE
+ );
+ }
+ } else if ( Scan == OS2_SCAN_CTRL_END_1 ) // ^End
+ {
+ KbdLineWasEdited = TRUE;
+ KbdEchoBSAndFillSpaces(0, LineInputBuff[KbdInputLength].X_Pos -
+ LineInputBuff[KbdIndexInLine].X_Pos);
+
+ KbdInputLength = KbdIndexInLine;
+ } else if ( Scan == OS2_SCAN_DEL ) // Del
+ {
+ KbdLineWasEdited = TRUE;
+ if (( NumChar = KbdInputLength - KbdIndexInLine ) >
+ pKbd->wRepeatCount )
+ {
+ NumChar = pKbd->wRepeatCount;
+ }
+
+ KbdCueDeleteCharAndShift(
+ KbdIndexInLine,
+ (USHORT)NumChar
+ );
+ } else if ( Scan == OS2_SCAN_CTRL_HOME_7 ) // ^Home
+ {
+ if (NumChar = KbdIndexInLine)
+ {
+ KbdLineWasEdited = TRUE;
+ KbdCueMoveToLeft(
+ KbdIndexInLine,
+ (USHORT)NumChar
+ );
+
+ KbdCueDeleteCharAndShift(
+ KbdIndexInLine,
+ (USHORT)NumChar
+ );
+ }
+ } else if ( Scan == OS2_SCAN_INSERT_0 ) // Ins
+ {
+ if ( pKbd->wRepeatCount % 2 )
+ {
+ if( KbdInsertOn = ~KbdInsertOn )
+ {
+ KbdCueSetCurTypeToHalf();
+ } else
+ {
+ KbdCueSetCurTypeToQuater();
+ }
+ }
+ }
+
+ break;
+ } else
+ {
+ if ( KbdFxWaitForChar )
+ {
+ KbdFxWaitForChar = 0;
+ if (--pKbd->wRepeatCount)
+ {
+ KbdQueue->LastKey.wRepeatCount--;
+ KbdQueue->LastKeyFlag = TRUE;
+ } else
+ {
+ break;
+ }
+ }
+
+ if ( Scan == 0x40 )
+ {
+ Char = 0x1A; // F6 => ^Z
+ } else if ( Scan == 0x41 )
+ {
+ Char = 0x00; // F7 => ^@
+ } else if (KbdEditFlag)
+ {
+ if (( Scan == 0x3B ) || // F1
+ ( Scan == OS2_SCAN_RIGHT_6 )) // Right
+ {
+ KbdInsertOn = FALSE;
+ if ((USHORT)(KbdDelIndex + KbdLastBuffPtr) < LastStringLength)
+ {
+ Char = KbdLastBuff[KbdDelIndex + KbdLastBuffPtr]; // => previous char
+ } else
+ break;
+
+ } else if ( Scan == 0x3C ) // F2
+ {
+ KbdInsertOn = FALSE;
+ if (pKbd->wRepeatCount % 2)
+ {
+ KbdFxWaitForChar = 1;
+ }
+ break;
+ } else if ( Scan == 0x3D ) // F3
+ {
+ KbdInsertOn = FALSE;
+ if ((USHORT)(KbdDelIndex + KbdLastBuffPtr) < LastStringLength)
+ {
+ StringLengthToEcho = LastStringLength - KbdDelIndex - KbdLastBuffPtr;
+ KbdEchoString = TRUE;
+ } else
+ break;
+
+ } else if ( Scan == 0x3E ) // F4
+ {
+ KbdInsertOn = FALSE;
+ if (pKbd->wRepeatCount % 2)
+ {
+ KbdFxWaitForChar = 2;
+ }
+ break;
+ } else if ( Scan == OS2_SCAN_DEL ) // Del
+ {
+ KbdDelIndex += pKbd->wRepeatCount;
+ if(KbdDelIndex > LastStringLength)
+ {
+ KbdDelIndex = LastStringLength;
+ }
+ break;
+ } else if ( Scan == OS2_SCAN_INSERT_0 ) // Ins
+ {
+ if (pKbd->wRepeatCount % 2)
+ {
+ KbdInsertOn = ~KbdInsertOn;
+ }
+
+ break;
+
+ } else if ( Scan == OS2_SCAN_LEFT_4 ) // Left
+ {
+ Char = '\b'; // => BS
+ KbdInsertOn = FALSE;
+ } else
+ break;
+ } else
+ break;
+ }
+ }
+
+ /*
+ *
+ * Search for char in KbdLastBuff (for F2 & F4)
+ *
+ */
+
+ if (KbdFxWaitForChar)
+ {
+ if (pKbd->wRepeatCount > 1)
+ {
+ KbdQueue->LastKeyFlag = TRUE;
+ }
+ for ( i = KbdDelIndex + KbdLastBuffPtr ;
+ (i < LastStringLength) && (KbdLastBuff[i] != Char) ; i++ );
+ if ((i == (USHORT)(KbdDelIndex + KbdLastBuffPtr)) ||
+ (KbdLastBuff[i] != Char))
+ {
+ KbdFxWaitForChar = 0;
+ break;
+ }
+
+ StringLengthToEcho = i - (KbdDelIndex + KbdLastBuffPtr);
+
+ if (KbdFxWaitForChar == 1) // F2
+ {
+ KbdFxWaitForChar = 0;
+ KbdEchoString = TRUE;
+ } else // F4
+ {
+ KbdDelIndex += i;
+ KbdFxWaitForChar = 0;
+ break;
+ }
+ }
+
+ /*
+ *
+ * Echo string from KbdLastBuff (for F2 & F3)
+ *
+ * StringLengthToEcho - is the string length
+ */
+
+ if (KbdEchoString)
+ {
+ X_Pos = GET_CURRENT_COORD.X;
+ NumChar = 0;
+
+ for ( i = KbdDelIndex + KbdLastBuffPtr, puchLastString = &KbdLastBuff[i] ;
+ StringLengthToEcho && (KbdInputLength < (USHORT)KbdMaxLength) ; StringLengthToEcho-- )
+ {
+ Char = KbdLastBuff[i++];
+ NumChar++ ;
+
+ LineInputBuff[KbdInputLength++].Char = Char;
+ if (Char == '\t') // TAB
+ {
+ X_Pos += 8 - (X_Pos % 8);
+ } else if (Char < ' ')
+ {
+ X_Pos += 2;
+ } else
+ {
+ X_Pos++;
+ }
+
+ if (X_Pos >= SesGrp->ScreenColNum)
+ {
+ X_Pos -= SesGrp->ScreenColNum;
+ KbdStartOfLine = 0;
+ }
+
+ LineInputBuff[KbdInputLength].X_Pos = X_Pos;
+ }
+
+ if (KbdEchoFlag && NumChar)
+ {
+ KbdEchoAString(puchLastString, NumChar);
+ }
+
+ KbdLastBuffPtr += (USHORT)NumChar;
+
+ if (StringLengthToEcho)
+ {
+ KbdEchoBeep(i);
+ }
+
+ KbdEchoString = FALSE;
+ break;
+ }
+
+ /*
+ *
+ * Handle BS
+ *
+ */
+
+ if (( Char == '\b' ) || ( Char == 0x7F ))
+ {
+ if (SesGrp->KeysOnFlag)
+ {
+ if ( NumChar = KbdIndexInLine )
+ {
+ if ( NumChar > pKbd->wRepeatCount )
+ {
+ NumChar = pKbd->wRepeatCount;
+ }
+
+ KbdCueMoveToLeft(
+ KbdIndexInLine,
+ (USHORT)NumChar
+ );
+
+ KbdCueDeleteCharAndShift(
+ KbdIndexInLine,
+ (USHORT)NumChar
+ );
+
+ KbdLineWasEdited = TRUE;
+ }
+
+ break;
+ } else
+ {
+ KbdInsertOn = FALSE;
+
+ for ( i = 0 ; (i < pKbd->wRepeatCount) && KbdInputLength &&
+ (LineInputBuff[KbdInputLength].X_Pos != KbdStartOfLine) ; i++ )
+ {
+ if (KbdLastBuffPtr)
+ {
+ KbdLastBuffPtr--;
+ } else if (KbdDelIndex)
+ {
+ KbdDelIndex--;
+ }
+
+ KbdInputLength--;
+ }
+
+ NumChar = GET_CURRENT_COORD.X - LineInputBuff[KbdInputLength].X_Pos;
+
+ if(KbdEchoFlag && NumChar)
+ {
+ KbdEchoBSAndFillSpaces(NumChar, NumChar);
+ }
+
+ break;
+ }
+ }
+
+ if (!SesGrp->KeysOnFlag)
+ {
+ /*
+ *
+ * Handle LF
+ *
+ */
+
+ if (Char == '\n')
+ {
+ if (KbdEchoFlag)
+ {
+ KbdEchoNL(pKbd->wRepeatCount);
+ }
+
+ LineInputBuff[KbdInputLength].X_Pos = 0;
+ KbdStartOfLine = 0;
+
+ break;
+ }
+
+ /*
+ *
+ * Handle ^W
+ *
+ */
+
+ if (Char == 0x17)
+ {
+ USHORT PrevIndex = KbdIndexInLine;
+
+ KbdInsertOn = FALSE;
+
+ for ( i = 0;
+ (i < pKbd->wRepeatCount) && ( PrevIndex > KbdStartOfLine ) ;
+ i++ )
+ {
+ /* for each char:
+ * go one char left
+ * skip all non-alphanumeric chars
+ * akip all alphanumeric chars
+ * while points to alpha, which is not the original
+ */
+
+ usIndex = PrevIndex - 1;
+
+ while (( usIndex > KbdStartOfLine ) &&
+ !ALPHANUM_CHAR(usIndex))
+ {
+ usIndex--;
+ }
+
+ while (( usIndex > KbdStartOfLine ) &&
+ ALPHANUM_CHAR(usIndex))
+ {
+ usIndex--;
+ }
+
+ if (( usIndex > KbdStartOfLine ) ||
+ !ALPHANUM_CHAR(usIndex))
+ {
+ usIndex++;
+ }
+
+ if (!ALPHANUM_CHAR(usIndex) ||
+ (PrevIndex == usIndex))
+ {
+ break;
+ }
+
+ PrevIndex = usIndex;
+ }
+
+ NumChar = LineInputBuff[KbdIndexInLine].X_Pos -
+ LineInputBuff[PrevIndex].X_Pos ;
+
+ if(KbdEchoFlag && NumChar)
+ {
+ KbdEchoBSAndFillSpaces(NumChar, NumChar);
+ }
+
+ KbdIndexInLine = KbdInputLength = PrevIndex;
+ //KbdLastBuffPtr = 0;
+ break;
+ }
+ }
+
+ /*
+ *
+ * Handle ESC
+ *
+ */
+
+ if (Char == 0x1B)
+ {
+ // ^[ => Write '\'<NL> & Clear Buff
+
+ KbdInsertOn = FALSE;
+
+ KbdLastBuffPtr = KbdDelIndex = 0;
+ if (SesGrp->KeysOnFlag)
+ {
+ if (KbdCueBuffer[KbdCurrentLine])
+ {
+ usIndex = KbdCurrentLine - 1;
+ } else
+ {
+ usIndex = KbdCurrentLine;
+ }
+
+ KbdCueEraseAndDisplayLine(usIndex); // don't display anything
+ } else if (KbdEchoFlag)
+ {
+ KbdEchoESC(pKbd->wRepeatCount, KbdFirstColumn);
+ }
+
+ KbdStartOfLine = LineInputBuff[0].X_Pos = KbdFirstColumn;
+ KbdInputLength = 0;
+ break;
+ }
+
+ /*
+ *
+ * Handle ^F
+ *
+ */
+
+ if (Char == 0x6)
+ {
+ break;
+ }
+
+ /*
+ *
+ * Handle char :
+ *
+ * 1. put in buffer (if there is a room), beep otherwise
+ * 2. save in buffer cursor position of next char
+ * 3. echo if echo_on
+ *
+ */
+
+ NumChar = 0;
+
+ if (SesGrp->KeysOnFlag)
+ {
+ KbdCueHandleChar(Char, pKbd->wRepeatCount);
+ } else
+ {
+ X_Pos = GET_CURRENT_COORD.X;
+
+ if (Char < ' ')
+ {
+ if (Char == '\t') // TAB
+ {
+ Offset = 8;
+ X_Pos &= ~7;
+ } else
+ {
+ Offset = 2;
+ }
+ } else
+ {
+ Offset = 1;
+ }
+
+ for ( i = 0 ; (i < pKbd->wRepeatCount) &&
+ (KbdInputLength < (USHORT)KbdMaxLength) ; i++ )
+ {
+ if (!KbdInsertOn)
+ {
+ KbdLastBuffPtr++;
+ }
+
+ LineInputBuff[KbdInputLength++].Char = Char;
+ X_Pos += Offset;
+
+ if (X_Pos >= SesGrp->ScreenColNum)
+ {
+ X_Pos -= SesGrp->ScreenColNum;
+ KbdStartOfLine = 0;
+ }
+ LineInputBuff[KbdInputLength].X_Pos = X_Pos;
+ }
+
+ if (KbdEchoFlag && i)
+ {
+ KbdEchoChar(Char, i);
+ }
+
+ if (i < pKbd->wRepeatCount)
+ {
+ KbdEchoBeep(pKbd->wRepeatCount - i);
+ }
+ }
+ break;
+
+ case BinaryMode:
+ /*
+ *
+ * Binary mode
+ *
+ */
+
+ /*
+ *
+ * Handle char :
+ *
+ * put in buffer (if a place exist)
+ * if enhanced - put also scan code
+ *
+ */
+
+ for ( i = 0 ; (i < pKbd->wRepeatCount) && (KbdInputLength < KbdLength); i++ )
+ {
+ KBD_BUFFER_ADDRESS[KbdInputLength++] = Char;
+
+ if ((Char == 0x0) && (KbdInputLength < KbdLength))
+ {
+ KBD_BUFFER_ADDRESS[KbdInputLength++] = Scan;
+ }
+ }
+
+ if ( KbdInputLength < KbdLength )
+ {
+ break;
+ } else if ( i < pKbd->wRepeatCount )
+ {
+ KbdQueue->LastKey = *pKbd; // prepare it in case we read only one copy of the char
+ KbdQueue->LastKey.wRepeatCount -= i;
+ KbdQueue->LastKeyFlag = TRUE;
+ }
+
+ /*
+ *
+ * Copy to application buffer
+ *
+ */
+
+ if ( KbdLength > KbdInputLength )
+ KbdLength = KbdInputLength;
+
+ /*
+ *
+ * Keep info for Read in case we don't return all the string
+ *
+ */
+
+ KbdBuffNextPtr = KbdLength;
+ KbdBuffNextLen = KbdInputLength - KbdLength;
+
+ /*
+ *
+ * No editing keys in binary mode
+ *
+ */
+
+ LastStringLength = 0;
+
+ return(0L);
+
+ default:
+ break;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ {
+ if ( KbdState == AsciiMode )
+ {
+ USHORT CurrentIdx;
+ CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
+
+ CurrentIdx = (SesGrp->KeysOnFlag) ? KbdIndexInLine : KbdInputLength;
+
+ if (!GetConsoleScreenBufferInfo(
+ hConOut,
+ &ConsoleScreenBufferInfo
+ ))
+ {
+ ConsoleScreenBufferInfo.dwCursorPosition.X =
+ ConsoleScreenBufferInfo.dwCursorPosition.Y = 255;
+ KdPrint(("OS2SES(Ow2VioReadCurPos): Rc %lu\n", GetLastError()));
+ ASSERT( FALSE ); // should not happend
+ }
+ KdPrint(("HandleKeyboardInput: Len %u, CUE-Idx %u, Cur-Offset %u, Prev-Offset %u, Col %u, Pos %u:%u\n",
+ KbdInputLength, KbdIndexInLine,
+ LineInputBuff[CurrentIdx].X_Pos,
+ (CurrentIdx) ? LineInputBuff[CurrentIdx - 1].X_Pos : 255,
+ SesGrp->WinCoord.X,
+ ConsoleScreenBufferInfo.dwCursorPosition.Y,
+ ConsoleScreenBufferInfo.dwCursorPosition.X
+ ));
+ if (KbdEchoFlag)
+ {
+ ASSERT( ConsoleScreenBufferInfo.dwCursorPosition.X == SesGrp->WinCoord.X );
+ ASSERT( ConsoleScreenBufferInfo.dwCursorPosition.Y == SesGrp->WinCoord.Y );
+ ASSERT( (LineInputBuff[CurrentIdx].X_Pos % SesGrp->ScreenColNum) ==
+ SesGrp->WinCoord.X );
+ }
+ }
+ }
+#endif
+
+ return(1L);
+}
+
+
+DWORD
+KbdHandlePackage(IN PKEY_EVENT_QUEUE NextKbdMon,
+ IN PKBD_MON_PACKAGE KbdPackage)
+{
+ KEYEVENTINFO In;
+
+ if ( KbdCheckPackage( KbdPackage ))
+ {
+ return (0L); // ignore key
+ }
+
+#ifdef DBCS
+// MSKK Jul.23.1992 KazuM
+ In.wRepeatCount = NextKbdMon->In->wRepeatCount;
+#else
+ In.wRepeatCount = 1;
+#endif
+ In.KeyInfo[0] = *KbdPackage;
+
+ if ( HandleKeyboardInput( &In ))
+ {
+ return (0L); // not time to send reply yet
+ }
+
+ NextKbdMon->MonHdr.WaitForEvent = FALSE;
+
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ {
+ KdPrint(("KbdHandlePackage: %s respond\n",
+ (KbdRequestSaveArea.Request == KBDCharIn) ? "KbdCharIn" :
+ (KbdRequestSaveArea.Request == KBDStringIn) ? "KbdStringIn" :
+ "KbdRead"));
+ }
+#endif
+ if ( KbdRequestSaveArea.Request == KBDCharIn )
+ {
+ KbdRequestSaveArea.d.KeyInfo = In.KeyInfo[0].KeyInfo;
+
+ SendKbdReply((PVOID)NextKbdMon->MonHdr.MemoryStartAddress,
+ (PVOID)&KbdRequestSaveArea,
+ KbdAddress,
+ 0);
+ } else
+ {
+ KbdRequestSaveArea.Length = (ULONG)KbdLength;
+
+ if ( KbdRequestSaveArea.Request == KBDStringIn )
+ {
+ KbdRequestSaveArea.d.String.cchIn = KbdLength;
+ if ( KbdRequestSaveArea.d.String.cchIn != KbdRequestSaveArea.d.String.cb )
+ KbdRequestSaveArea.Length++ ; // ASCII mode - copy the CR
+ }
+
+ SendKbdReply ((PVOID)NextKbdMon->MonHdr.MemoryStartAddress,
+ (PVOID)&KbdRequestSaveArea,
+ KbdAddress,
+ 0);
+ }
+
+ return (1L);
+}
+
+
+DWORD
+KbdCheckPackage(IN PKBD_MON_PACKAGE KbdPackage)
+{
+ BOOL IgnoreKey = FALSE;
+ UCHAR Scan, Char;
+
+ Char = KbdPackage->KeyInfo.chChar;
+ Scan = KbdPackage->KeyInfo.chScan;
+
+ if (( Char == 0 ) && ( Scan == 0 ))
+ {
+ if(!( ENABLE_SHIFT_KEY & KbdWaitFlag ))
+ {
+ /*
+ * Ignore shift keys if { in ASCII mode or shift report off }
+ */
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ KdPrint((" - ignore since shift report disable\n"));
+ }
+#endif
+ IgnoreKey = TRUE; // ignore shift report
+ } else if(!( KbdPackage->KeyInfo.fbStatus & 1))
+ {
+ /*
+ * Ignore non-shift keys
+ */
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ KdPrint((" - ignore since non-shift key\n"));
+ }
+#endif
+ IgnoreKey = TRUE;
+ }
+ } else if ( KbdPackage->KeyboardFlag & KBD_KEY_BREAK )
+ {
+ /*
+ * Ignore Break if non-shift
+ */
+
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ {
+ KdPrint(("KbdCheckPackage: ignore key release\n"));
+ }
+#endif
+ IgnoreKey = TRUE; // ignore KEY_UP
+ } else if (( KbdWaitFlag & ENABLE_LN_EDITOR_KEY ) &&
+ KbdKeyIsTurnAround(Char, Scan) )
+ {
+ // don't ignore the turn around char in ASCII mode
+
+ } else if ( !( KbdWaitFlag & ENABLE_NON_ASCII_KEY ) &&
+ (( Char == 0 ) || ( Char == 0xE0 )))
+ {
+ IgnoreKey = TRUE; // ignore NON_ASCII
+
+ if ( KbdWaitFlag & ENABLE_KEYS_ON_KEY )
+ {
+ if (( Scan == OS2_SCAN_HOME_7 ) || // Home
+ ( Scan == OS2_SCAN_CTRL_HOME_7 ) || // ^Home
+ ( Scan == OS2_SCAN_END_1 ) || // End
+ ( Scan == OS2_SCAN_CTRL_END_1 ) || // ^End
+ ( Scan == OS2_SCAN_LEFT_4 ) || // Left
+ ( Scan == OS2_SCAN_CTRL_LEFT_4 ) || // ^Left
+ ( Scan == OS2_SCAN_RIGHT_6 ) || // Right
+ ( Scan == OS2_SCAN_CTRL_RIGHT_6 ) || // ^Right
+ ( Scan == OS2_SCAN_UP_8 ) || // Up
+ ( Scan == OS2_SCAN_DOWN_2 ) || // Down
+ ( Scan == OS2_SCAN_DEL ) || // Del
+ ( Scan == OS2_SCAN_INSERT_0 )) // Ins
+ {
+ IgnoreKey = FALSE; // don't ignore CUE keys
+ }
+ } else if ( KbdWaitFlag & ENABLE_LN_EDITOR_KEY )
+ {
+ if (( Scan == 0x3B ) || // F1
+ ( Scan == 0x3C ) || // F2
+ ( Scan == 0x3D ) || // F3
+ ( Scan == 0x3E ) || // F4
+ ( Scan == 0x40 ) || // F6
+ ( Scan == 0x41 ) || // F7
+ ( Scan == OS2_SCAN_LEFT_4 ) || // Left
+ ( Scan == OS2_SCAN_RIGHT_6 ) || // Right
+ ( Scan == OS2_SCAN_DEL ) || // Del
+ ( Scan == OS2_SCAN_INSERT_0 )) // Ins
+ {
+ IgnoreKey = FALSE; // don't ignore editing keys
+ }
+ }
+
+ if (IgnoreKey)
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ {
+ KdPrint(("KbdCheckPackage: ignore non-ASCII key\n"));
+ }
+#endif
+ }
+ } else if ( KbdAsciiMode )
+ {
+ /*
+ *
+ * Ignore speciel CTRL-Keys in ASCII mode
+ *
+ */
+
+ if (( Char == 0x03 ) || // ^C
+ ( Char == 0x10 ) || // ^P
+ // ^Q: in non-US kbd(AZARTY) ^Q is passed
+ // and ^A not (mjarus 7/5/93)
+ (( Scan == 0x10 ) &&
+ ((KbdPackage->KeyInfo.fsState & (OS2_CONTROL | OS2_ALT)) == OS2_CONTROL)) ||
+ ( Char == 0x13 )) // ^S
+ {
+#if DBG
+ IF_OD2_DEBUG(KBD)
+ {
+ KdPrint((" - ignore Char %x in ASCII\n",
+ Char));
+ }
+#endif
+ IgnoreKey = TRUE; // ignore NON_ASCII
+ }
+ }
+
+ return ( (DWORD)IgnoreKey );
+}
+
+
+VOID
+KbdNewSetup(
+ IN PKBDINFO LastSetup
+ )
+{
+ PKBDINFO NewSetup = &KbdQueue->Setup;
+ USHORT Mask;
+
+// if (*LastSetup == *NewSetup)
+// return;
+
+ /* BUGBUG=> handle new setup */
+
+ SesGrp->ModeFlag = (USHORT)((NewSetup->fsMask & KEYBOARD_BINARY_MODE ) ? 1 : 0);
+
+ Mask = NewSetup->fsMask & (KEYBOARD_BINARY_MODE | KEYBOARD_SHIFT_REPORT);
+
+ Ow2KbdXlateVars.XInputMode = (Mask) ?
+ ((Mask & KEYBOARD_SHIFT_REPORT) ? (BINARY_MODE | SHIFT_REPORT_MODE) :
+ BINARY_MODE) : 0;
+
+ if ((NewSetup->fsMask & KEYBOARD_ASCII_MODE ) &&
+ (LastSetup->fsMask & KEYBOARD_BINARY_MODE ))
+ {
+ LastStringLength = 0;
+ KbdBuffNextPtr = 0;
+ KbdBuffNextLen = 0;
+ }
+
+ KbdAsciiMode = (BOOL)(( NewSetup->fsMask & KEYBOARD_ASCII_MODE ) ? 1 : 0);
+
+ if (NewSetup->fsMask & KEYBOARD_2B_TURNAROUND)
+ {
+ KbdSetupTurnAroundCharTwo = (BOOLEAN)TRUE;
+ } else
+ {
+ KbdSetupTurnAroundCharTwo = (BOOLEAN)FALSE;
+ }
+
+ return;
+}
+
+
+VOID
+KbdCueEraseAndDisplayLine(
+ IN ULONG NewLineIndex
+ )
+/*++
+
+Routine Description:
+
+ This routine erase the current input line and display new one.
+
+Arguments:
+
+ NewLineIndex - pointer in CUE buffer for new line (or to NULL
+ if nothing to diaply).
+
+Return Value:
+
+
+Note:
+
+ ASCII CUE string mode.
+
+ Used by UP-ARROW, DOWN-ARROW and ESC.
+
+ 1. Erase the active command line being displayed and
+ 2. Display the new command in the command queue.
+
+ Uses:
+
+ - KbdInputLength - active command line length.
+ - KbdIndexInLine - current index in command line.
+ - LineInputBuff[0, KbdIndexInLine, KbdInputLength].X_Pos
+ - KbdCueBuffer[NewLineIndex..]
+
+ Updates:
+
+ - KbdInputLength - new line length.
+ - KbdIndexInLine - 0.
+ - LineInputBuff[0..KbdInputLength].Char and .X_Pos
+ - console display
+ - LVB
+ - SesGrp->WinCoord - by other routines.
+
+ Calls:
+
+ - KbdEchoBSAndFillSpaces
+ - KbdCueUpdateBufferOffset
+ - KbdCueMoveToRight
+ - KbdCueMoveToLeft
+
+--*/
+{
+ /*
+ * Erase the active command line being displayed.
+ */
+
+ if ( KbdInputLength )
+ {
+ KbdEchoBSAndFillSpaces(
+ LineInputBuff[KbdIndexInLine].X_Pos - LineInputBuff[0].X_Pos,
+ LineInputBuff[KbdInputLength].X_Pos - LineInputBuff[0].X_Pos
+ );
+
+ KbdIndexInLine = 0;
+ KbdInputLength = 0;
+ }
+
+ /*
+ * Display the new command in the command queue
+ */
+
+ for ( KbdInputLength = 0 ;
+ LineInputBuff[KbdInputLength].Char = KbdCueBuffer[NewLineIndex + KbdInputLength] ;
+ KbdInputLength++ );
+
+ if (KbdInputLength)
+ {
+ KbdCueUpdateBufferOffset(
+ 0,
+ KbdInputLength,
+ LineInputBuff[0].X_Pos
+ );
+
+ KbdCueMoveToRight(
+ 0,
+ KbdInputLength,
+ TRUE
+ );
+
+ KbdCueMoveToLeft(
+ KbdInputLength,
+ KbdInputLength
+ );
+ }
+}
+
+
+VOID
+KbdCueMoveToRight(
+ IN ULONG StartIndex,
+ IN ULONG StringLength,
+ IN ULONG UpdateLVB
+ )
+/*++
+
+Routine Description:
+
+ This routine moves the console cursor position to the right
+ while sending the active command line to the console.
+
+Arguments:
+
+ StartIndex - index in LineInputBuff[] (the active command line) to start
+ moving right from.
+
+ StringLength - number of character to move right.
+
+ UpdateLVB - flag if to set LVB also (for new info)
+
+Return Value:
+
+
+Note:
+
+ ASCII CUE string mode.
+
+ Used by RIGHT-ARROW, END, ^RIGHT-ARROW, KbdCueEraseAndDisplayLine,
+ KbdCueDeleteCharAndShift and KbdCueHandleChar.
+
+ 1. Send to console
+ 2. Update Coord
+ 3. Update LVB
+ 4. Update position
+
+ Uses:
+
+ - LineInputBuff[0..KbdInputLength].Char and .X_Pos
+
+ Updates:
+
+ - KbdInputLength - NO.
+ - KbdIndexInLine - add StringLength.
+ - LineInputBuff[0..KbdInputLength].Char and .X_Pos - NO
+ - console display
+ - LVB (if UpdateLVB)
+ - SesGrp->WinCoord - add StringLength.
+
+ Calls:
+
+ - Or2WinWriteConsoleA
+ - Ow2VioUpdateCurPos
+ - VioLVBScrollBuff
+ - VioLVBCopyStr
+
+--*/
+{
+ UCHAR Char;
+ ULONG NumChar, NumBytes, NumWritten, NumLines = 0;
+ COORD OldCoord, Coord;
+
+ OldCoord = Coord = GET_CURRENT_COORD;
+
+ /*
+ * Copy to temp buffer
+ */
+
+ for ( NumBytes = 0, NumChar = 0 ; NumChar < StringLength ; NumChar++ )
+ {
+ if ((Char = LineInputBuff[StartIndex + NumChar].Char) < ' ')
+ {
+ KBD_BUFFER_ADDRESS[NumBytes++] = '^';
+ KBD_BUFFER_ADDRESS[NumBytes++] = (UCHAR)(Char + '@');
+ } else
+ {
+ KBD_BUFFER_ADDRESS[NumBytes++] = Char;
+ }
+ }
+
+ if (!NumBytes)
+ {
+ return ;
+ }
+
+ if ( KbdEchoFlag )
+ {
+ /*
+ * Send to console
+ */
+
+ if(!Or2WinWriteConsoleA(
+ #if DBG
+ KbdCueMoveToRightStr,
+ #endif
+ hConOut,
+ (LPSTR)KBD_BUFFER_ADDRESS,
+ NumBytes,
+ &NumWritten,
+ NULL
+ ))
+ {
+#if DBG
+ ASSERT1("OS2SES(KbdCueMoveToRight): failed on WriteConsoleA", FALSE);
+#endif
+ }
+
+#if DBG
+ if ( NumBytes != NumWritten )
+ {
+ KdPrint(("OS2SES(KbdCueMoveToRight): partial data WriteConsoleA (%u from %u)\n",
+ NumWritten, NumBytes));
+ ASSERT( FALSE );
+ }
+#endif
+
+ /*
+ * Update Coord
+ */
+
+ Coord.X += (SHORT)NumWritten;
+ while ( Coord.X >= SesGrp->ScreenColNum )
+ {
+ Coord.Y++;
+ Coord.X -= SesGrp->ScreenColNum;
+ }
+
+ if ( Coord.Y >= SesGrp->ScreenRowNum )
+ {
+ NumLines = Coord.Y - SesGrp->ScreenRowNum + 1;
+ Coord.Y = SesGrp->ScreenRowNum - 1;
+ }
+
+ Ow2VioUpdateCurPos(Coord);
+
+ /*
+ * Update LVB
+ */
+
+ if ( UpdateLVB )
+ {
+ if ( NumLines && ( SesGrp->ScreenSize < 512 ))
+ {
+ ULONG NumChar1 = SesGrp->ScreenRowNum - OldCoord.X;
+ UCHAR *Ptr = &KBD_BUFFER_ADDRESS[0];
+
+ while ( NumWritten )
+ {
+ VioLVBCopyStr(
+ Ptr,
+ OldCoord,
+ NumChar1
+ );
+
+ VioLVBFillAtt(
+ SesGrp->AnsiCellAttr,
+ OldCoord,
+ NumChar1
+ );
+
+ OldCoord.X = 0;
+
+ if ( ++OldCoord.Y >= SesGrp->ScreenRowNum )
+ {
+ OldCoord.Y--;
+ VioLVBScrollBuff(1);
+ NumLines--;
+ }
+
+ NumWritten -= NumChar1;
+
+ if (( NumChar1 = NumWritten ) > (ULONG)SesGrp->ScreenColNum )
+ {
+ NumChar1 = SesGrp->ScreenColNum;
+ }
+ }
+
+ ASSERT( NumLines == 0 );
+ } else
+ {
+ if ( NumLines )
+ {
+ OldCoord.Y -= (SHORT)NumLines;
+ VioLVBScrollBuff(NumLines);
+ }
+
+ VioLVBCopyStr(
+ KBD_BUFFER_ADDRESS,
+ OldCoord,
+ NumWritten
+ );
+
+ VioLVBFillAtt(
+ SesGrp->AnsiCellAttr,
+ OldCoord,
+ NumWritten
+ );
+ }
+ }
+ }
+
+ /*
+ * Update position index
+ */
+
+ KbdIndexInLine += (USHORT)StringLength;
+}
+
+
+VOID
+KbdCueMoveToLeft(
+ IN ULONG StartIndex,
+ IN ULONG MoveLength
+ )
+/*++
+
+Routine Description:
+
+ This routine moves the console cursor position to the left
+ using '\b'.
+
+Arguments:
+
+ StartIndex - index in LineInputBuff[] (the active command line) to start
+ moving left from.
+
+ MoveLength - number of character to move left.
+
+Return Value:
+
+
+Note:
+
+ ASCII CUE string mode.
+
+ Used by LEFT-ARROW, HOME, ^LEFT-ARROW, ^HOME, BS, KbdCueEraseAndDisplayLine,
+ KbdCueDeleteCharAndShift and KbdCueHandleChar.
+
+ 1. Send to console
+ 2. Update position
+
+ Uses:
+
+ - LineInputBuff[StartIndex - MoveLength,StartIndex].X_Pos
+ - LineInputBuff[StartIndex - MoveLength..StartIndex].Char
+
+ Updates:
+
+ - KbdInputLength - NO.
+ - KbdIndexInLine - sub MoveLength.
+ - LineInputBuff[0..KbdInputLength].Char and .X_Pos - NO
+ - console display - NO
+ - LVB - NO
+ - SesGrp->WinCoord - by other routines.
+
+ Calls:
+
+ - KbdEchoBSAndFillSpaces
+
+--*/
+{
+ ULONG NumBytes;
+
+ /*
+ * Calculate byte count
+ */
+
+ NumBytes = LineInputBuff[StartIndex].X_Pos - LineInputBuff[StartIndex - MoveLength].X_Pos;
+
+ if (!NumBytes)
+ {
+ return ;
+ }
+
+ if ( KbdEchoFlag )
+ {
+ if ( SesGrp->ScreenSize < 512 )
+ {
+ ULONG Row1, Row2;
+
+ Row1 = LineInputBuff[StartIndex - MoveLength].X_Pos / SesGrp->ScreenColNum;
+ Row2 = LineInputBuff[KbdInputLength].X_Pos / SesGrp->ScreenColNum;
+
+ if (( Row2 - Row1 + 1 ) > (ULONG)SesGrp->ScreenRowNum )
+ {
+ NumBytes += LineInputBuff[StartIndex - MoveLength].X_Pos % SesGrp->ScreenColNum;
+ NumBytes -= (Row2 - Row1 + 1 - SesGrp->ScreenRowNum) * SesGrp->ScreenColNum;
+ }
+ }
+
+ /*
+ * Send to console and update coord
+ */
+
+ KbdEchoBSAndFillSpaces(NumBytes, 0);
+ }
+
+ /*
+ * Update position index
+ */
+
+ KbdIndexInLine -= (USHORT)MoveLength;
+}
+
+
+VOID
+KbdCueUpdateBufferOffset(
+ IN ULONG StartIndex,
+ IN ULONG StringLength,
+ IN ULONG StartOffset
+ )
+/*++
+
+Routine Description:
+
+ This routine updates the offset in buffer for the active command line.
+ This is done from StartIndex for StringLength + 1 (to update the offset
+ of the next char according to the last char in string). The StartIndex
+ gets X_Pos of StartOffset and the following are updated according the
+ char type (char under 0x20 holds two columns for ^X).
+
+Arguments:
+
+ StartIndex - index in LineInputBuff[] (the active command line) to start
+ updaing the X_Pos field from.
+
+ StringLength - number of character to update X_Pos for.
+
+ StartOffset - X_Pos for the first character.
+
+Return Value:
+
+
+Note:
+
+ ASCII CUE string mode.
+
+ Used by KbdCueEraseAndDisplayLine, KbdCueDeleteCharAndShift and
+ KbdCueHandleChar.
+
+ 1. Updates the X_Pos field in LineInputBuff[].
+
+ Uses:
+
+ - KbdInputLength - active command line length.
+ - KbdIndexInLine - current index in command line.
+ - LineInputBuff[0, KbdIndexInLine, KbdInputLength].X_Pos
+ - KbdCueBuffer[NewLineIndex..]
+
+--*/
+{
+ ULONG NumChar, Index, Offset;
+
+ /*
+ * Update the offset in buffer. This is done for StringLength + 1
+ * to update the offset of the next char according to the last char
+ * in string.
+ */
+
+ for ( Index = StartIndex, Offset = StartOffset, NumChar = 0 ;
+ NumChar <= StringLength ; NumChar++ )
+ {
+ LineInputBuff[Index].X_Pos = (USHORT)Offset++;
+
+ if ( LineInputBuff[Index++].Char < ' ' )
+ {
+ Offset++;
+ }
+ }
+}
+
+
+VOID
+KbdCueDeleteCharAndShift(
+ IN ULONG StartIndex,
+ IN ULONG NumChar
+ )
+/*++
+
+Routine Description:
+
+ This routine delete character and shift the remaining command line
+ input to the left.
+
+Arguments:
+
+ StartIndex - index in LineInputBuff[] (the active command line) to start
+ deleting from.
+
+ NumChar - number of character to delete.
+
+Return Value:
+
+
+Note:
+
+ ASCII CUE string mode.
+
+ Used by DEL, ^HOME and BS.
+
+ 1 Shift buffer info (Char field)
+ 2 Update X_Pos (Offset) field in the shifted area
+ 3 Send the shifted string to console and LVB
+ 4 Clear remaining line
+ 5 Return to the cursor position
+
+ Uses:
+
+ - LineInputBuff[].X_Pos and Char
+
+ Updates:
+
+ - KbdInputLength - sub NumChar.
+ - KbdIndexInLine - NO
+ - LineInputBuff[0..KbdInputLength].Char and .X_Pos
+ - console display
+ - LVB
+ - SesGrp->WinCoord - by other routines.
+
+ Calls:
+
+ - KbdCueUpdateBufferOffset
+ - KbdCueMoveToRight
+ - KbdEchoBSAndFillSpaces
+ - KbdCueMoveToLeft
+
+--*/
+{
+ if (NumChar)
+ {
+ ULONG Offset = LineInputBuff[StartIndex].X_Pos;
+ ULONG Delta = LineInputBuff[StartIndex + NumChar].X_Pos - Offset;
+ ULONG NumShift = KbdInputLength - StartIndex - NumChar;
+
+ if ( NumShift )
+ {
+ /*
+ * Shift buffer info (Char field)
+ */
+
+ RtlMoveMemory(
+ &LineInputBuff[StartIndex].Char,
+ &LineInputBuff[StartIndex + NumChar].Char,
+ NumShift * sizeof(LINE_EDIT_KBD)
+ );
+
+ /*
+ * Update X_Pos (Offset) field in the shifted area
+ */
+
+ KbdCueUpdateBufferOffset(
+ StartIndex,
+ NumShift,
+ Offset
+ );
+
+ /*
+ * Send the shifted string to console and LVB
+ */
+
+ KbdCueMoveToRight(
+ StartIndex,
+ NumShift,
+ TRUE
+ );
+ }
+
+ /*
+ * Clear remaining line
+ */
+
+ KbdEchoBSAndFillSpaces(0, Delta);
+
+ /*
+ * Return to the cursor position
+ */
+
+ KbdCueMoveToLeft(
+ StartIndex + NumShift,
+ NumShift
+ );
+
+ KbdInputLength -= (USHORT)NumChar;
+ }
+}
+
+
+VOID
+KbdCueHandleChar(
+ IN UCHAR Char,
+ IN ULONG Count
+ )
+/*++
+
+Routine Description:
+
+ This routine handle new char at CUE mode.
+
+Arguments:
+
+ Char - char to handle.
+
+ NumChar - number of character.
+
+Return Value:
+
+
+Note:
+
+ ASCII CUE string mode.
+
+ Used by CHAR.
+
+ For INSERT:
+ 1 Shift buffer info (Char field)
+ 2 Fill new char
+ 3 Update X_Pos (Offset) field
+ 4 Send the new+old string to console and LVB
+ 5 Return to the cursor position
+ 6 Beep if no place
+ Else:
+ 1 Shift buffer info (Char field)
+ 2 Fill new char
+ 3 Update X_Pos (Offset) field
+ 4 Send the shifted string to console and LVB
+ 5 Clear remaining line
+ 6 Return to the cursor position
+ 7 Beep if no place
+
+ Uses:
+
+ - LineInputBuff[].X_Pos and Char
+ - KbdInsertOn
+ - KbdIndexInLine
+ - KbdMaxLength
+ - KbdInputLength
+
+ Updates:
+
+ - KbdInputLength
+ - KbdIndexInLine
+ - LineInputBuff[0..KbdInputLength].Char and .X_Pos
+ - console display
+ - LVB
+ - SesGrp->WinCoord - by other routines.
+
+ Calls:
+
+ - KbdCueUpdateBufferOffset
+ - KbdCueMoveToRight
+ - KbdCueMoveToLeft
+ - KbdEchoBSAndFillSpaces
+ - KbdEchoBeep
+ - RtlMoveMemory
+
+--*/
+{
+ ULONG NumChar, NumBeep = 0, NumShift, UpdateRight, i;
+ ULONG LastOffset = LineInputBuff[KbdInputLength].X_Pos;
+
+ if ( KbdInsertOn )
+ {
+ if (( NumChar = KbdMaxLength - KbdInputLength ) > Count )
+ {
+ NumChar = Count;
+ } else
+ {
+ NumBeep = Count - NumChar;
+ }
+
+ /*
+ * Shift buffer info (Char field) to free space for new char
+ */
+
+ NumShift = KbdInputLength - KbdIndexInLine;
+
+ RtlMoveMemory(
+ &LineInputBuff[KbdIndexInLine + NumChar].Char,
+ &LineInputBuff[KbdIndexInLine].Char,
+ NumShift * sizeof(LINE_EDIT_KBD)
+ );
+ /*
+ * Fill new char
+ */
+
+ for ( i = 0 ; i < NumChar ; i++ )
+ {
+ LineInputBuff[KbdIndexInLine + i].Char = Char;
+ }
+
+ /*
+ * Update X_Pos (Offset) field in the shifted and new areas
+ */
+
+ KbdCueUpdateBufferOffset(
+ KbdIndexInLine,
+ NumChar + NumShift,
+ LineInputBuff[KbdIndexInLine].X_Pos
+ );
+
+ /*
+ * Send the shifted string to console and LVB
+ */
+
+ KbdCueMoveToRight(
+ KbdIndexInLine,
+ NumChar + NumShift,
+ TRUE
+ );
+
+ /*
+ * Return to the cursor position
+ */
+
+ KbdCueMoveToLeft(
+ KbdIndexInLine,
+ NumShift
+ );
+
+ KbdInputLength += (USHORT)NumChar;
+ } else
+ {
+ if (( NumChar = KbdMaxLength - KbdIndexInLine ) > Count )
+ {
+ NumChar = Count;
+ } else
+ {
+ NumBeep = Count - NumChar;
+ }
+
+ UpdateRight = max(NumChar, (ULONG)(KbdInputLength - KbdIndexInLine));
+
+ /*
+ * Fill new char
+ */
+
+ for ( i = 0 ; i < NumChar ; i++ )
+ {
+ LineInputBuff[KbdIndexInLine + i].Char = Char;
+ }
+
+ /*
+ * Update X_Pos (Offset) field in the old and new areas
+ */
+
+ KbdCueUpdateBufferOffset(
+ KbdIndexInLine,
+ UpdateRight,
+ LineInputBuff[KbdIndexInLine].X_Pos
+ );
+
+ /*
+ * Send the shifted string to console and LVB
+ */
+
+ KbdCueMoveToRight(
+ KbdIndexInLine,
+ UpdateRight,
+ TRUE
+ );
+
+ if ( LastOffset > (ULONG)LineInputBuff[KbdIndexInLine].X_Pos )
+ {
+ /*
+ * Fill spaces at the EOL if needed
+ */
+
+ KbdEchoBSAndFillSpaces(
+ 0,
+ LastOffset - LineInputBuff[KbdIndexInLine].X_Pos
+ );
+ }
+
+ if ( UpdateRight != NumChar )
+ {
+ /*
+ * Return to the cursor position
+ */
+
+ KbdCueMoveToLeft(
+ KbdIndexInLine,
+ UpdateRight - NumChar
+ );
+ }
+
+ if ( KbdIndexInLine > KbdInputLength )
+ {
+ KbdInputLength = KbdIndexInLine;
+ }
+ }
+
+ if ( NumBeep != Count )
+ {
+ KbdLineWasEdited = TRUE;
+ }
+
+ if ( NumBeep )
+ {
+ KbdEchoBeep(NumBeep);
+ }
+}
+
+
+VOID
+KbdCueSetCurTypeToHalf()
+{
+ VIOCURSORINFO CurType;
+
+ //Ow2VioGetCurType((PVOID)&CurType);
+ //CurType = SesGrp->CursorInfo;
+
+ //CurType.cEnd = SesGrp->CellVSize;
+ CurType.cEnd = SesGrp->CursorInfo.cEnd;
+ CurType.yStart = (CurType.cEnd + 1 ) / 2;
+ CurType.cx = 1;
+ CurType.attr = 0;
+
+ Ow2VioSetCurType((PVOID)&CurType);
+}
+
+
+VOID
+KbdCueSetCurTypeToQuater()
+{
+ VIOCURSORINFO CurType;
+
+ //Ow2VioGetCurType((PVOID)&CurType);
+ //CurType = SesGrp->CursorInfo;
+
+ //CurType.cEnd = SesGrp->CellVSize;
+ CurType.cEnd = SesGrp->CursorInfo.cEnd;
+ CurType.yStart = (CurType.cEnd + 1 ) * 3 / 4;
+ CurType.cx = 1;
+ CurType.attr = 0;
+
+ Ow2VioSetCurType((PVOID)&CurType);
+}
+
+
+DWORD
+KbdEchoCharToConsole(
+ IN UCHAR Char,
+ IN ULONG Count
+ )
+/*++
+
+Routine Description:
+
+ This routine write <Char> to console <Count> times.
+
+Arguments:
+
+ Char - character to write.
+
+ Count - number of times to write char
+
+Return Value:
+
+
+Note:
+
+ ASCII CUE/EDIT string mode.
+
+ Used by KbdEchoNL, KbdEchoBSAndFillSpaces, KbdEchoBeep and KbdEchoChar.
+
+ Calls:
+
+ - Or2WinWriteConsoleA
+
+--*/
+{
+ ULONG NumChar, NumWritten, MaxCount = Count;
+
+ NumChar = (MaxCount > KBD_BUFFER_SIZE) ? KBD_BUFFER_SIZE : MaxCount;
+ memset(KBD_BUFFER_ADDRESS, Char, NumChar);
+
+ while (MaxCount)
+ {
+ if(!Or2WinWriteConsoleA(
+ #if DBG
+ KbdEchoCharToConsoleStr,
+ #endif
+ hConOut,
+ (LPSTR)KBD_BUFFER_ADDRESS,
+ NumChar,
+ &NumWritten,
+ NULL))
+ {
+#if DBG
+ ASSERT1("OS2SES(KbdEchoCharToConsole): failed on WriteConsoleA", FALSE);
+#endif
+ }
+
+#if DBG
+ if ( NumChar != NumWritten )
+ {
+ KdPrint(("OS2SES(KbdEchoCharToConsole): partial data WriteConsoleA %u from %u\n",
+ NumWritten, NumChar));
+ ASSERT( FALSE );
+ }
+#endif
+
+ MaxCount -= NumChar;
+ NumChar = (MaxCount > KBD_BUFFER_SIZE) ? KBD_BUFFER_SIZE : MaxCount;
+ }
+
+ return(NO_ERROR);
+}
+
+
+DWORD
+KbdEchoNL(
+ IN ULONG Count
+ )
+/*++
+
+Routine Description:
+
+ This routine write NL to console <Count> times and update LVB.
+
+Arguments:
+
+ Count - number of times to write char
+
+Return Value:
+
+
+Note:
+
+ ASCII CUE/EDIT string mode.
+
+ Used by LF (EDIT only) and CR.
+
+ Updates:
+
+ - SesGrp->WinCoord
+ - LVB
+
+ Calls:
+
+ - KbdEchoCharToConsole
+ - VioLVBScrollBuff
+
+--*/
+{
+ ULONG NumLines = 0;
+ COORD Coord = GET_CURRENT_COORD;
+
+ Coord.X = 0;
+ Coord.Y += (SHORT)Count;
+ if ( Coord.Y >= SesGrp->ScreenRowNum )
+ {
+ NumLines = Coord.Y - SesGrp->ScreenRowNum + 1;
+ Coord.Y = SesGrp->ScreenRowNum - 1;
+ }
+
+ KbdEchoCharToConsole('\n', Count);
+ Ow2VioUpdateCurPos(Coord);
+
+ if (NumLines)
+ {
+ VioLVBScrollBuff(NumLines);
+ }
+
+ return(NO_ERROR);
+}
+
+
+DWORD
+KbdEchoESC(
+ IN ULONG Count,
+ IN ULONG HorzMove
+ )
+/*++
+
+Routine Description:
+
+ This routine write <ESC> to console <Count> times with <HorzMove>
+ number of spaces on the next line. It also update LVB.
+
+Arguments:
+
+ Count - number of times to write char
+
+ HorzMove - number of spaces on the start of the new line.
+
+Return Value:
+
+
+Note:
+
+ ASCII EDIT string mode.
+
+ Used by ESC.
+
+ Updates:
+
+ - SesGrp->WinCoord
+ - LVB
+
+ Calls:
+
+ - Or2WinWriteConsoleA
+ - VioLVBScrollBuff
+
+--*/
+{
+ ULONG NumChar, NumWritten, MaxCount = Count, NumLines = 0, Length = HorzMove + 1;
+ COORD OldCoord, Coord;
+
+ OldCoord = Coord = GET_CURRENT_COORD;
+
+ KBD_BUFFER_ADDRESS[0] = '\\';
+ KBD_BUFFER_ADDRESS[1] = '\n';
+ memset(&KBD_BUFFER_ADDRESS[2], ' ', HorzMove);
+ KBD_BUFFER_ADDRESS[HorzMove + 2] = '\\';
+ NumChar = HorzMove + 2;
+
+ Coord.Y += (SHORT)Count;
+ Coord.X = (SHORT)HorzMove;
+
+ if ( Coord.Y >= SesGrp->ScreenRowNum )
+ {
+ NumLines = Coord.Y - SesGrp->ScreenRowNum + 1;
+ Coord.Y = SesGrp->ScreenRowNum - 1;
+ }
+
+ while ( MaxCount )
+ {
+ if(!Or2WinWriteConsoleA(
+ #if DBG
+ KbdEchoESCStr,
+ #endif
+ hConOut,
+ (LPSTR)KBD_BUFFER_ADDRESS,
+ NumChar,
+ &NumWritten,
+ NULL))
+ {
+#if DBG
+ ASSERT1("OS2SES(KbdEchoESC): failed on WriteConsoleA", FALSE);
+#endif
+ //return (1);
+ }
+
+#if DBG
+ if ( NumChar != NumWritten )
+ {
+ KdPrint(("OS2SES(KbdEchoESC): partial data WriteConsoleA %u from %u\n",
+ NumWritten, NumChar));
+ ASSERT( FALSE );
+ }
+#endif
+
+ MaxCount--;
+ }
+
+ Ow2VioUpdateCurPos(Coord);
+
+ VioLVBFillChar(
+#ifdef DBCS
+// MSKK Oct.14.1993 V-AkihiS
+ "\\",
+#else
+ '\\',
+#endif
+ OldCoord,
+ 1
+ );
+
+ VioLVBFillAtt(
+ SesGrp->AnsiCellAttr,
+ OldCoord,
+ 1
+ );
+
+ OldCoord.X = 0;
+
+ for ( NumChar = 0 ; NumChar < Count ; NumChar++ )
+ {
+ if ( ++OldCoord.Y >= SesGrp->ScreenRowNum )
+ {
+ OldCoord.Y--;
+ VioLVBScrollBuff(1);
+ NumLines--;
+ }
+
+ if ( NumChar == ( Count - 1 ))
+ {
+ Length--; // don't put the slash at the last line
+ }
+
+ VioLVBCopyStr(
+ &KBD_BUFFER_ADDRESS[2],
+ OldCoord,
+ Length
+ );
+
+ VioLVBFillAtt(
+ SesGrp->AnsiCellAttr,
+ OldCoord,
+ Length
+ );
+ }
+
+ ASSERT( NumLines == 0 );
+ return(NO_ERROR);
+}
+
+
+DWORD
+KbdEchoBSAndFillSpaces(
+ IN ULONG BSCount,
+ IN ULONG SpaceCount
+ )
+/*++
+
+Routine Description:
+
+ This routine write BS ('\b') to console <BSCount> times and fill
+ <SpaceCount> times spaces in console and LVB.
+
+Arguments:
+
+ BSCount - number of times to write \b char to console
+
+ SpaceCount - number of times to fill space char to console and LVB
+
+Return Value:
+
+
+Note:
+
+ ASCII EDIT/CUE string mode.
+
+ Used by ^END, BS (EDIT only), LF (EDIT only), KbdCueEraseAndDisplayLine,
+ KbdCueMoveToLeft, KbdCueDeleteCharAndShift and KbdCueHandleChar.
+
+ Updates:
+
+ - SesGrp->WinCoord (for BSCount only)
+ - LVB (for SpaceCount only)
+
+ Calls:
+
+ - KbdEchoCharToConsole
+ - Or2WinFillConsoleOutputCharacterA
+ - VioLVBFillChar
+
+--*/
+{
+ ULONG NumFilled;
+ COORD OldCoord, Coord;
+
+ if ( !KbdEchoFlag )
+ {
+ return (0L);
+ }
+
+ if (((long) BSCount < 0) || ((long) SpaceCount < 0)) {
+#if DBG
+ DbgPrint("KbdEchoBSAndFillSpaces: BSCount %d or SpaceCount %d are negative\n",
+ (long)BSCount, (long)SpaceCount);
+#endif
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ OldCoord = Coord = GET_CURRENT_COORD;
+
+ Coord.X -= (SHORT)BSCount;
+ while ( Coord.X < 0 )
+ {
+ if ( Coord.Y )
+ {
+ Coord.Y--;
+ Coord.X += SesGrp->ScreenColNum;
+ } else
+ {
+ if ( SpaceCount )
+ {
+ if ( SpaceCount > (ULONG)abs(Coord.X) )
+ {
+ SpaceCount += (ULONG)Coord.X;
+ } else
+ {
+ SpaceCount = 0;
+ }
+ }
+
+ BSCount += (ULONG)Coord.X; // sub the negative value
+ Coord.X = 0;
+ }
+ }
+
+ KbdEchoCharToConsole('\b', BSCount);
+ Ow2VioUpdateCurPos(Coord);
+
+ if ( SpaceCount )
+ {
+ if (!Or2WinFillConsoleOutputCharacterA(
+ #if DBG
+ KbdEchoBSAndFillSpacesStr,
+ #endif
+ hConOut,
+ ' ',
+ SpaceCount,
+ Coord,
+ &NumFilled))
+ {
+#if DBG
+ ASSERT1("OS2SES(KbdEchoBSAndFillSpaces): failed on FillConsoleOutputCharacterA\n", FALSE);
+#endif
+ }
+
+#if DBG
+ if ( NumFilled != SpaceCount )
+ {
+ KdPrint(("OS2SES(KbdEchoBSAndFillSpaces): partial data %u from %u\n",
+ NumFilled, SpaceCount));
+ ASSERT( FALSE );
+ }
+#endif
+ VioLVBFillChar(
+#ifdef DBCS
+// MSKK Oct.14.1993 V-AkihiS
+ " ",
+#else
+ ' ',
+#endif
+ Coord,
+ SpaceCount
+ );
+
+ VioLVBFillAtt(
+ SesGrp->AnsiCellAttr,
+ Coord,
+ SpaceCount
+ );
+ }
+ return(NO_ERROR);
+}
+
+
+DWORD
+KbdEchoBeep(
+ IN ULONG Count
+ )
+/*++
+
+Routine Description:
+
+ This routine send BEPP ('\07') to console <Count> times.
+
+Arguments:
+
+ Count - number of times to write \g char to console
+
+Return Value:
+
+
+Note:
+
+ ASCII EDIT/CUE string mode.
+
+ Used when no place in the active command line by KbdEchoString,
+ Char and KbdCueHandleChar.
+
+ Calls:
+
+ - KbdEchoCharToConsole
+
+--*/
+{
+ KbdEchoCharToConsole('\07', Count);
+ return(NO_ERROR);
+}
+
+
+DWORD
+KbdEchoChar(
+ IN UCHAR Char,
+ IN ULONG Count
+ )
+/*++
+
+Routine Description:
+
+ This routine echo <Char> to console <Count> times and update LVB.
+
+Arguments:
+
+ Char - char to send to console
+
+ Count - number of times to send char to console
+
+Return Value:
+
+
+Note:
+
+ ASCII EDIT string mode.
+
+ Updates:
+
+ - SesGrp->WinCoord
+ - LVB
+
+ Calls:
+
+ - KbdEchoCharToConsole
+ - VioLVBScrollBuff
+
+--*/
+{
+ COORD OldCoord, Coord;
+ BOOL SendByLine = FALSE;
+ UCHAR FillChar;
+ ULONG Offset;
+
+ OldCoord = Coord = GET_CURRENT_COORD;
+ if (( Char >= ' ' ) || ( Char == '\t' ))
+ {
+ KbdEchoCharToConsole(Char, Count);
+
+ if ( Char == '\t' )
+ {
+ Offset = 8 * Count - (Coord.X & 7);
+ FillChar = ' ';
+ } else
+ {
+ FillChar = Char;
+ Offset = Count;
+ }
+
+ if ((ULONG)( Offset + 2 * SesGrp->ScreenColNum ) > SesGrp->ScreenSize )
+ {
+ SendByLine = TRUE;
+ } else
+ {
+ Coord.X += (SHORT)Offset;
+ while ( Coord.X >= SesGrp->ScreenColNum )
+ {
+ Coord.Y++;
+ Coord.X -= SesGrp->ScreenColNum;
+ }
+
+ if ( Coord.Y >= SesGrp->ScreenRowNum )
+ {
+ VioLVBScrollBuff(Coord.Y - SesGrp->ScreenRowNum + 1);
+ OldCoord.Y -= Coord.Y - SesGrp->ScreenRowNum + 1;
+ Coord.Y = SesGrp->ScreenRowNum - 1;
+ }
+
+ Ow2VioUpdateCurPos(Coord);
+
+ VioLVBFillChar(
+#ifdef DBCS
+// MSKK Oct.14.1993 V-AkihiS
+ &FillChar,
+#else
+ FillChar,
+#endif
+ OldCoord,
+ Offset
+ );
+
+ VioLVBFillAtt(
+ SesGrp->AnsiCellAttr,
+ OldCoord,
+ Offset
+ );
+ }
+ }
+
+ if ( SendByLine || (( Char < ' ' ) && ( Char != '\t' )))
+ {
+ ULONG NumChar, NumWritten, MaxCount, Pattern;
+
+ if ( SendByLine )
+ {
+ Pattern = (ULONG)((FillChar << 24) |
+ (FillChar << 16) |
+ (FillChar << 8) |
+ (FillChar));
+
+ MaxCount = 0;
+ } else
+ {
+ MaxCount = Offset = 2 * Count;
+ FillChar = (UCHAR)(Char + '@');
+
+ Pattern = (ULONG)((FillChar << 24) |
+ ('^' << 16) |
+ (FillChar << 8) |
+ ('^'));
+ }
+
+ NumChar = ( Offset > KBD_BUFFER_SIZE ) ? KBD_BUFFER_SIZE : Offset;
+
+ RtlFillMemoryUlong(
+ KBD_BUFFER_ADDRESS,
+ (NumChar + 3) & ~3,
+ Pattern
+ );
+
+ while ( MaxCount )
+ {
+ if(!Or2WinWriteConsoleA(
+ #if DBG
+ KbdEchoCharStr,
+ #endif
+ hConOut,
+ (LPSTR)KBD_BUFFER_ADDRESS,
+ NumChar,
+ &NumWritten,
+ NULL))
+ {
+#if DBG
+ ASSERT1("OS2SES(KbdEchoChar): failed on WriteConsoleA", FALSE);
+#endif
+ //return (1);
+ }
+
+#if DBG
+ if ( NumChar != NumWritten )
+ {
+ KdPrint(("OS2SES(KbdEchoChar): partial data WriteConsoleA %u from %u\n",
+ NumWritten, NumChar));
+ ASSERT( FALSE );
+ }
+#endif
+
+ MaxCount -= NumChar;
+ NumChar = ( MaxCount > KBD_BUFFER_SIZE ) ? KBD_BUFFER_SIZE : MaxCount;
+ }
+
+ if (( NumChar = SesGrp->ScreenColNum - Coord.X ) > Offset )
+ {
+ NumChar = Offset;
+ }
+
+ while ( Offset )
+ {
+ VioLVBCopyStr(
+ &KBD_BUFFER_ADDRESS[0],
+ Coord,
+ NumChar
+ );
+
+
+ VioLVBFillAtt(
+ SesGrp->AnsiCellAttr,
+ Coord,
+ NumChar
+ );
+ Coord.X += (SHORT)NumChar;
+ if ( Coord.X >= SesGrp->ScreenColNum )
+ {
+ Coord.X -= SesGrp->ScreenColNum;
+ if ( ++Coord.Y >= SesGrp->ScreenRowNum )
+ {
+ VioLVBScrollBuff(1);
+ Coord.Y--;
+ }
+ }
+
+ Offset -= NumChar;
+ if (( NumChar = SesGrp->ScreenColNum - Coord.X ) > Offset )
+ {
+ NumChar = Offset;
+ }
+ }
+
+ Ow2VioUpdateCurPos(Coord);
+ }
+
+ return(NO_ERROR);
+}
+
+
+DWORD
+KbdEchoAString(
+ IN PUCHAR String,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine echo <String>, which size is <Lenght> to console and update LVB.
+
+Arguments:
+
+ String - char string to send to console
+
+ Length - string length
+
+Return Value:
+
+
+Note:
+
+ ASCII EDIT string mode.
+
+ Updates:
+
+ - SesGrp->WinCoord
+ - LVB
+
+ Calls:
+
+ - Or2WinWriteConsoleA
+
+--*/
+{
+ ULONG NumWritten, NumChar, NumBytes, Num;
+ COORD OldCoord, Coord;
+ UCHAR Char;
+
+ OldCoord = Coord = GET_CURRENT_COORD;
+
+ for ( NumChar = 0, NumBytes = 0 ; NumChar < Length ; NumChar++ )
+ {
+ Char = String[NumChar];
+ if ( Char >= ' ' )
+ {
+ KBD_BUFFER_ADDRESS[NumBytes++] = Char;
+ } else if ( Char = '\t' )
+ {
+ Num = 8 - ((Coord.X + NumBytes) & 7);
+ memset(&KBD_BUFFER_ADDRESS[NumBytes], ' ', Num);
+ NumBytes += Num;
+ } else
+ {
+ KBD_BUFFER_ADDRESS[NumBytes++] = '^';
+ KBD_BUFFER_ADDRESS[NumBytes++] = (UCHAR)(Char + '@');
+ }
+
+ if (((ULONG)( Coord.X + NumBytes ) >= (ULONG)SesGrp->ScreenColNum ) ||
+ ( NumChar == ( Length - 1 )))
+ {
+ if(!Or2WinWriteConsoleA(
+ #if DBG
+ KbdEchoAStringStr,
+ #endif
+ hConOut,
+ (LPSTR)KBD_BUFFER_ADDRESS,
+ NumBytes,
+ &NumWritten,
+ NULL))
+ {
+#if DBG
+ ASSERT1("OS2SES(KbdEchoAString): failed on WriteConsoleA", FALSE);
+#endif
+ }
+
+#if DBG
+ if ( NumBytes != NumWritten )
+ {
+ KdPrint(("OS2SES(KbdEchoAString): partial data WriteConsoleA %u from %u\n",
+ NumWritten, NumBytes));
+ ASSERT( FALSE );
+ }
+#endif
+ OldCoord = Coord;
+ Coord.X += (SHORT)NumBytes;
+ if ( Coord.X >= SesGrp->ScreenColNum )
+ {
+ Coord.Y++;
+ Coord.X -= SesGrp->ScreenColNum;
+
+ if ( Coord.Y >= SesGrp->ScreenRowNum )
+ {
+ Coord.Y = SesGrp->ScreenRowNum - 1;
+ OldCoord.Y--;
+ }
+ }
+
+ Ow2VioUpdateCurPos(Coord);
+
+ VioLVBCopyStr(
+ &KBD_BUFFER_ADDRESS[0],
+ OldCoord,
+ NumBytes
+ );
+
+ VioLVBFillAtt(
+ SesGrp->AnsiCellAttr,
+ OldCoord,
+ NumBytes
+ );
+ NumBytes = 0;
+ }
+ }
+ return(NO_ERROR);
+}
+
+
+BOOL
+KbdKeyIsTurnAround(
+ IN UCHAR Char,
+ IN UCHAR Scan
+ )
+{
+ if ( KbdTurnAroundCharTwo )
+ {
+ if ( Scan == (UCHAR)KbdTurnAroundChar )
+ {
+ if ((( KbdReadMode == 0 ) &&
+ (( Char == 0 ) || ( Char == 0xE0 ))) ||
+ (( KbdReadMode == 1 ) && ( Char == HIBYTE(KbdTurnAroundChar) )))
+ {
+ return(TRUE);
+ }
+ }
+ } else
+ {
+ if ( Char == (UCHAR)KbdTurnAroundChar )
+ {
+ return(TRUE);
+ }
+ }
+
+ return(FALSE);
+}
+
diff --git a/private/os2/os2ses/kbdtable.c b/private/os2/os2ses/kbdtable.c
new file mode 100644
index 000000000..f1e39119e
--- /dev/null
+++ b/private/os2/os2ses/kbdtable.c
@@ -0,0 +1,653 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ kbdtabl.c
+
+Abstract:
+
+ This module contains the translation table for KBD according to CP
+
+Author:
+
+ Michael Jarus (mjarus) 28-Apr-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "event.h"
+#include "trans.h"
+#include "kbd.h"
+#include <stdio.h>
+
+#ifdef JAPAN
+// MSKK May.07.1993 V-AkihiS
+// Support IOCtl KBD_KETKEYBDTYPE and KBD_GETHARDWAREID
+USHORT KbdType, KbdSubType;
+BYTE OemId, OemSubType;
+#endif
+
+USHORT Ow2KbdHWIDs = 1; // BUGBUG -?
+USHORT Ow2KCBShFlgs = 0; // BUGBUG -?
+
+UCHAR Ow2MiscFlags = 0;
+#define EnhancedKbd 0x10 // bit 4 - Enhanced Kbd is out there (must be Bit 4!).
+
+UCHAR Ow2MiscFlags3 = 0;
+#define AltPacket 2 // bit 1 - DCR 1713: indicates that Alt-Numpad accumulation is finished.
+#define PauseLatch 4 // bit 2 - PTM 2344: indicates correct keystroke sequence for a Ctrl-NumLock.
+#define E0Packet 0x10 // bit 4 - PTM 2382: indicates that an E0 packet is to be sent with the next packet.
+#define SecAltNumPad 0x80 // bit 7 - PTR AK00370: indicates AltNumpad with R-Alt.
+
+
+extern PVOID Ow2US437001, Ow2US437011, Ow2US850000, Ow2US850010;
+extern PVOID Ow2BE437001, Ow2BE437011, Ow2BE850000, Ow2BE850010;
+extern PVOID Ow2CF863001, Ow2CF863011, Ow2CF850000, Ow2CF850010;
+extern PVOID Ow2DK865001, Ow2DK865011, Ow2DK850000, Ow2DK850010;
+extern PVOID Ow2FR437001, Ow2FR437011, Ow2FR437111, Ow2FR850000, Ow2FR850010, Ow2FR850011;
+extern PVOID Ow2GR437001, Ow2GR437011, Ow2GR850000, Ow2GR850010;
+extern PVOID Ow2IT437001, Ow2IT437011, Ow2IT437111, Ow2IT850000, Ow2IT850010, Ow2IT850011;
+extern PVOID Ow2LA437001, Ow2LA437011, Ow2LA850000, Ow2LA850010;
+extern PVOID Ow2NL437001, Ow2NL437011, Ow2NL850000, Ow2NL850010;
+extern PVOID Ow2NO865001, Ow2NO865011, Ow2NO850000, Ow2NO850010;
+extern PVOID Ow2PO860001, Ow2PO860011, Ow2PO850000, Ow2PO850010;
+extern PVOID Ow2SF437001, Ow2SF437011, Ow2SF850000, Ow2SF850010;
+extern PVOID Ow2SG437001, Ow2SG437011, Ow2SG850000, Ow2SG850010;
+extern PVOID Ow2SP437001, Ow2SP437011, Ow2SP850000, Ow2SP850010;
+extern PVOID Ow2SU437001, Ow2SU437011, Ow2SU850000, Ow2SU850010;
+extern PVOID Ow2SV437001, Ow2SV437011, Ow2SV850000, Ow2SV850010;
+extern PVOID Ow2UK437001, Ow2UK437011, Ow2UK437111, Ow2UK850000, Ow2UK850010, Ow2UK850011;
+#ifdef JAPAN
+// MSKK Aug.02.1993 V-AkihiS
+extern PVOID Ow2JP932011AX, Ow2JP437011AX;
+extern PVOID Ow2JP932011IBM002, Ow2JP437011IBM002;
+extern PVOID Ow2JP932011IBMA01, Ow2JP437011IBMA01;
+extern PVOID Ow2JP932011IBM101, Ow2JP437011IBM101;
+#endif
+
+typedef struct _KBD_TYPE_TABLE
+{
+ PVOID CP1Table;
+ PVOID CP2Table;
+} KBD_TYPE_TABLE, *PKBD_TYPE_TABLE;
+
+typedef struct _KBD_LANG_TABLE
+{
+ ULONG Country;
+ ULONG CodePage1;
+ ULONG CodePage2;
+ KBD_TYPE_TABLE AtTable;
+ KBD_TYPE_TABLE EnTable;
+ KBD_TYPE_TABLE EnNewTable;
+} KBD_LANG_TABLE;
+
+KBD_LANG_TABLE KbdNlsTable[] =
+ {
+ {
+ CTRY_BELGIUM,
+ 437,
+ 850,
+ {
+ &Ow2BE437001, // BE 437 AT Kbd
+ &Ow2BE850000, // BE 850 AT Kbd
+ },
+ {
+ &Ow2BE437011, // BE 437 EN Kbd
+ &Ow2BE850010, // BE 850 EN Kbd
+ },
+ {
+ &Ow2BE437011, // BE 437 EN Kbd (for New Std as Old)
+ &Ow2BE850010 // BE 850 EN Kbd (for New Std as Old)
+ }
+ },
+ {
+ CTRY_CANADA,
+ 863,
+ 850,
+ {
+ &Ow2CF863001, // CF 863 AT Kbd
+ &Ow2CF850000, // CF 850 AT Kbd
+ },
+ {
+ &Ow2CF863011, // CF 863 EN Kbd
+ &Ow2CF850010, // CF 850 EN Kbd
+ },
+ {
+ &Ow2CF863011, // CF 863 EN Kbd (for New Std as Old)
+ &Ow2CF850010 // CF 850 EN Kbd (for New Std as Old)
+ }
+ },
+ {
+ CTRY_DENMARK,
+ 865,
+ 850,
+ {
+ &Ow2DK865001, // DK 865 AT Kbd
+ &Ow2DK850000, // DK 850 AT Kbd
+ },
+ {
+ &Ow2DK865011, // DK 865 EN Kbd
+ &Ow2DK850010, // DK 850 EN Kbd
+ },
+ {
+ &Ow2DK865011, // DK 865 EN Kbd (for New Std as Old)
+ &Ow2DK850010 // DK 850 EN Kbd (for New Std as Old)
+ }
+ },
+ {
+ CTRY_FRANCE,
+ 437,
+ 850,
+ {
+ &Ow2FR437001, // FR 437 AT Kbd
+ &Ow2FR850000, // FR 850 AT Kbd
+ },
+ {
+ &Ow2FR437011, // FR 437 EN Kbd
+ &Ow2FR850010, // FR 850 EN Kbd
+ },
+ {
+ &Ow2FR437111, // FR 437 EN Kbd New Std
+ &Ow2FR850011 // FR 850 EN Kbd New Std
+ }
+ },
+ {
+ CTRY_GERMANY,
+ 437,
+ 850,
+ {
+ &Ow2GR437001, // GR 437 AT Kbd
+ &Ow2GR850000, // GR 850 AT Kbd
+ },
+ {
+ &Ow2GR437011, // GR 437 EN Kbd
+ &Ow2GR850010, // GR 850 EN Kbd
+ },
+ {
+ &Ow2GR437011, // GR 437 EN Kbd (for New Std as Old)
+ &Ow2GR850010 // GR 850 EN Kbd (for New Std as Old)
+ }
+ },
+ {
+ CTRY_ITALY,
+ 437,
+ 850,
+ {
+ &Ow2IT437001, // IT 437 AT Kbd
+ &Ow2IT850000, // IT 850 AT Kbd
+ },
+ {
+ &Ow2IT437011, // IT 437 EN Kbd
+ &Ow2IT850010, // IT 850 EN Kbd
+ },
+ {
+ &Ow2IT437111, // IT 437 EN Kbd New Std
+ &Ow2IT850011 // IT 850 EN Kbd New Std
+ }
+ },
+ {
+ COUNTRY_LATIN_AMERICA,
+ 437,
+ 850,
+ {
+ &Ow2LA437001, // LA 437 AT Kbd
+ &Ow2LA850000, // LA 850 AT Kbd
+ },
+ {
+ &Ow2LA437011, // LA 437 EN Kbd
+ &Ow2LA850010, // LA 850 EN Kbd
+ },
+ {
+ &Ow2LA437011, // LA 437 EN Kbd (for New Std as Old)
+ &Ow2LA850010 // LA 850 EN Kbd (for New Std as Old)
+ }
+ },
+ {
+ CTRY_NETHERLANDS,
+ 437,
+ 850,
+ {
+ &Ow2NL437001, // NL 437 AT Kbd
+ &Ow2NL850000, // NL 850 AT Kbd
+ },
+ {
+ &Ow2NL437011, // NL 437 EN Kbd
+ &Ow2NL850010, // NL 850 EN Kbd
+ },
+ {
+ &Ow2NL437011, // NL 437 EN Kbd (for New Std as Old)
+ &Ow2NL850010 // NL 850 EN Kbd (for New Std as Old)
+ }
+ },
+ {
+ CTRY_NORWAY,
+ 865,
+ 850,
+ {
+ &Ow2NO865001, // NO 865 AT Kbd
+ &Ow2NO850000, // NO 850 AT Kbd
+ },
+ {
+ &Ow2NO865011, // NO 865 EN Kbd
+ &Ow2NO850010, // NO 850 EN Kbd
+ },
+ {
+ &Ow2NO865011, // NO 865 EN Kbd (for New Std as Old)
+ &Ow2NO850010 // NO 850 EN Kbd (for New Std as Old)
+ }
+ },
+ {
+ CTRY_PORTUGAL,
+ 860,
+ 850,
+ {
+ &Ow2PO860001, // PO 860 AT Kbd
+ &Ow2PO850000, // PO 850 AT Kbd
+ },
+ {
+ &Ow2PO860011, // PO 860 EN Kbd
+ &Ow2PO850010, // PO 850 EN Kbd
+ },
+ {
+ &Ow2PO860011, // PO 860 EN Kbd (for New Std as Old)
+ &Ow2PO850010 // PO 850 EN Kbd (for New Std as Old)
+ }
+ },
+ {
+ CTRY_SWITZERLAND,
+ 437,
+ 850,
+ {
+ &Ow2SF437001, // SF 437 AT Kbd
+ &Ow2SF850000, // SF 850 AT Kbd
+ },
+ {
+ &Ow2SF437011, // SF 437 EN Kbd
+ &Ow2SF850010, // SF 850 EN Kbd
+ },
+ {
+ &Ow2SF437011, // SF 437 EN Kbd (for New Std as Old)
+ &Ow2SF850010 // SF 850 EN Kbd (for New Std as Old)
+ }
+ },
+ {
+ CTRY_SWITZERLAND,
+ 437,
+ 850,
+ {
+ &Ow2SG437001, // SG 437 AT Kbd
+ &Ow2SG850000, // SG 850 AT Kbd
+ },
+ {
+ &Ow2SG437011, // SG 437 EN Kbd
+ &Ow2SG850010, // SG 850 EN Kbd
+ },
+ {
+ &Ow2SG437011, // SG 437 EN Kbd (for New Std as Old)
+ &Ow2SG850010 // SG 850 EN Kbd (for New Std as Old)
+ }
+ },
+ {
+ CTRY_SPAIN,
+ 437,
+ 850,
+ {
+ &Ow2SP437001, // SP 437 AT Kbd
+ &Ow2SP850000, // SP 850 AT Kbd
+ },
+ {
+ &Ow2SP437011, // SP 437 EN Kbd
+ &Ow2SP850010, // SP 850 EN Kbd
+ },
+ {
+ &Ow2SP437011, // SP 437 EN Kbd (for New Std as Old)
+ &Ow2SP850010 // SP 850 EN Kbd (for New Std as Old)
+ }
+ },
+ {
+ CTRY_FINLAND,
+ 437,
+ 850,
+ {
+ &Ow2SU437001, // SU 437 AT Kbd
+ &Ow2SU850000, // SU 850 AT Kbd
+ },
+ {
+ &Ow2SU437011, // SU 437 EN Kbd
+ &Ow2SU850010, // SU 850 EN Kbd
+ },
+ {
+ &Ow2SU437011, // SU 437 EN Kbd (for New Std as Old)
+ &Ow2SU850010 // SU 850 EN Kbd (for New Std as Old)
+ }
+ },
+ {
+ CTRY_SWEDEN,
+ 437,
+ 850,
+ {
+ &Ow2SV437001, // SV 437 AT Kbd
+ &Ow2SV850000, // SV 850 AT Kbd
+ },
+ {
+ &Ow2SV437011, // SV 437 EN Kbd
+ &Ow2SV850010, // SV 850 EN Kbd
+ },
+ {
+ &Ow2SV437011, // SV 437 EN Kbd (for New Std as Old)
+ &Ow2SV850010 // SV 850 EN Kbd (for New Std as Old)
+ }
+ },
+ {
+ CTRY_UNITED_KINGDOM,
+ 437,
+ 850,
+ {
+ &Ow2UK437001, // UK 437 AT Kbd
+ &Ow2UK850000, // UK 850 AT Kbd
+ },
+ {
+ &Ow2UK437011, // UK 437 EN Kbd
+ &Ow2UK850010, // UK 850 EN Kbd
+ },
+ {
+ &Ow2UK437111, // UK 437 EN Kbd New Std
+ &Ow2UK850011 // UK 850 EN Kbd New Std
+ }
+ },
+ {
+ /* Must be last as the default */
+
+ CTRY_UNITED_STATES,
+ 437,
+ 850,
+ {
+ &Ow2US437001, // US 437 AT Kbd
+ &Ow2US850000, // US 850 AT Kbd
+ },
+ {
+ &Ow2US437011, // US 437 EN Kbd
+ &Ow2US850010, // US 850 EN Kbd
+ },
+ {
+ &Ow2US437011, // US 437 EN Kbd (for New Std as Old)
+ &Ow2US850010 // US 850 EN Kbd (for New Std as Old)
+ }
+ },
+ {
+ 0,
+ 0,
+ 0,
+ {
+ NULL,
+ NULL,
+ },
+ {
+ NULL,
+ NULL,
+ },
+ {
+ NULL,
+ NULL
+ }
+ }
+ };
+
+#ifdef JAPAN
+// MSKK Aug.03.1993 V-AkihiS
+typedef struct _KBD_TYPE_TABLE_OEM
+{
+ BYTE OemSubType;
+ KBD_TYPE_TABLE EnTable;
+ #if DBG
+ PBYTE OemSubTypeStr;
+ #endif
+} KBD_TYPE_TABLE_OEM, *PKBD_TYPE_TABLE_OEM;
+
+typedef struct _KBD_TYPE_TABLE_JP
+{
+ BYTE OemId;
+ PKBD_TYPE_TABLE_OEM pKbdTableOEM;
+ #if DBG
+ PBYTE OemIdStr;
+ #endif
+} KBD_TYPE_TABLE_JP;
+
+#if DBG
+BYTE SubKbdTypeMicrosoftStr[] = "Microsoft";
+
+BYTE AXKbdDesktopTypeStr[] = "AX KeyBoard";
+BYTE IBMKbd002TypeStr[] = "IBM-002 Keyboard";
+BYTE IBMKbdA01TypeStr[] = "106 keyboard";
+BYTE IBM101KbdTypeStr[] = "101 keyboard";
+#endif
+
+KBD_TYPE_TABLE_OEM KbdTypeTableMicrosoft[] =
+ {
+ {
+ MICROSOFT_KBD_101_TYPE,
+ {
+ &Ow2JP932011IBM101, // 101 keybaord 932
+ &Ow2JP437011IBM101 // 101 keyboard 437
+ }
+ #if DBG
+ , (PBYTE)&IBM101KbdTypeStr
+ #endif
+ },
+ {
+ MICROSOFT_KBD_AX_TYPE,
+ {
+ &Ow2JP932011AX, // AX keybaord 932
+ &Ow2JP437011AX // AX keyboard 437
+ }
+ #if DBG
+ , (PBYTE)&AXKbdDesktopTypeStr
+ #endif
+ },
+ {
+ MICROSOFT_KBD_106_TYPE,
+ {
+ &Ow2JP932011IBMA01, // 106 keybaord 932
+ &Ow2JP437011IBMA01 // 106 keyboard 437
+ }
+ #if DBG
+ , (PBYTE)&IBMKbdA01TypeStr
+ #endif
+ },
+ {
+ MICROSOFT_KBD_002_TYPE,
+ {
+ &Ow2JP932011IBM002, // IBM-002 keybaord 932
+ &Ow2JP437011IBM002 // IBM-002 keyboard 437
+ }
+ #if DBG
+ , (PBYTE)&IBMKbd002TypeStr
+ #endif
+ },
+ {
+ 0xFF,
+ {
+ NULL,
+ NULL
+ }
+ #if DBG
+ , NULL
+ #endif
+ }
+ };
+
+
+KBD_TYPE_TABLE_JP KbdTableJp[] =
+ {
+ {
+ SUB_KBD_TYPE_MICROSOFT,
+ (PKBD_TYPE_TABLE_OEM)&KbdTypeTableMicrosoft
+ #if DBG
+ , (PBYTE)&SubKbdTypeMicrosoftStr
+ #endif
+ },
+ {
+ 0xFF,
+ NULL
+ #if DBG
+ , NULL
+ #endif
+ }
+ };
+#endif
+
+VOID
+KbdSetTable(
+ IN ULONG KbdCP
+ )
+{
+ ULONG i;
+ ULONG Ctry = SesGrp->KeyboardCountry;
+ PKBD_TYPE_TABLE pKbdType;
+#ifdef JAPAN
+// MSKK Aug.03.1993 V-AkihiS
+ ULONG j;
+#endif
+
+#ifdef JAPAN
+// MSKK Jul.29.1993 V-AkihiS
+ if (Ctry == COUNTRY_JAPAN)
+ {
+ //
+ // Get keyboard type to decide translation table
+ //
+ KbdType = GetKeyboardType(0);
+ KbdSubType = GetKeyboardType(1);
+ OemId = HIBYTE(KbdSubType);
+ OemSubType = LOBYTE(KbdSubType);
+
+ for ( i = 0 ;
+ (KbdTableJp[i].OemId != OemId) && KbdTableJp[i+1].OemId != 0xFF;
+ i++ );
+ for ( j = 0 ;
+ ((KbdTableJp[i].pKbdTableOEM)[j].OemSubType != OemSubType) &&
+ (KbdTableJp[i].pKbdTableOEM)[j+1].OemSubType !=0xFF;
+ j++ );
+
+ switch(KbdCP) {
+ case CODEPAGE_JAPAN:
+ case 0:
+ Ow2KbdScanTable = (KbdTableJp[i].pKbdTableOEM)[j].EnTable.CP1Table;
+ break;
+ default:
+ Ow2KbdScanTable = (KbdTableJp[i].pKbdTableOEM)[j].EnTable.CP2Table;
+ break;
+ }
+ Ow2MiscFlags = EnhancedKbd;
+#if DBG
+ IF_OS2_DEBUG2( OS2_EXE, KBD )
+ {
+ KdPrint(("KbdSetTable: Country %d, CP %u, OemId %s, OemSubType %s\n",
+ Ctry,
+ KbdCP,
+ KbdTableJp[i].OemIdStr,
+ (KbdTableJp[i].pKbdTableOEM)[j].OemSubTypeStr));
+ }
+#endif
+ return;
+ }
+#endif
+
+ for ( i = 0 ;
+ (KbdNlsTable[i].Country != Ctry) && KbdNlsTable[i+1].Country ;
+ i++ );
+
+ if (SesGrp->KeyboardType == OS2SS_AT_KBD)
+ {
+ pKbdType = &KbdNlsTable[i].AtTable;
+ Ow2MiscFlags = 0;
+ } else if (SesGrp->KeyboardType == OS2SS_ENNEW_KBD)
+ {
+ pKbdType = &KbdNlsTable[i].EnNewTable;
+ Ow2MiscFlags = EnhancedKbd;
+ } else // OS2SS_EN_KBD
+ {
+ pKbdType = &KbdNlsTable[i].EnTable;
+ Ow2MiscFlags = EnhancedKbd;
+ }
+
+ if (KbdNlsTable[i].CodePage2 == KbdCP)
+ {
+ Ow2KbdScanTable = pKbdType->CP2Table;
+ } else
+ {
+ // use CodePage 1 as the default
+
+ Ow2KbdScanTable = pKbdType->CP1Table;
+ }
+
+#if DBG
+ IF_OS2_DEBUG2( OS2_EXE, KBD )
+ {
+ KdPrint(("KbdSetTable: Country %d, CP %u, Type %s\n",
+ KbdNlsTable[i].Country,
+ (KbdNlsTable[i].CodePage2 == KbdCP) ? KbdCP : KbdNlsTable[i].CodePage1,
+ (SesGrp->KeyboardType == OS2SS_AT_KBD) ? "AT" :
+ ((SesGrp->KeyboardType == OS2SS_ENNEW_KBD) ? "EN-NEW" : "EN")));
+ }
+#endif
+
+ return;
+}
+
+
+DWORD
+KbdInitForNLS(
+ IN ULONG KbdCP
+ )
+{
+ SesGrp->KbdCP = KbdCP;
+ KbdQueue->Cp = (USHORT)KbdCP;
+ KbdSetTable(KbdCP);
+ return (NO_ERROR);
+}
+
+
+DWORD
+KbdNewCp( IN ULONG CodePage)
+{
+ DWORD Rc = NO_ERROR;
+
+#ifdef DBCS
+// MSKK Apr.16.1993 V-AkihiS
+ ULONG CPTmp;
+#endif
+
+#ifdef DBCS
+// MSKK Apr.16.1993 V-AkihiS
+ CPTmp = CodePage ? CodePage : SesGrp->PrimaryCP;
+#endif
+ if (SesGrp->KbdCP != CodePage)
+ {
+#ifdef DBCS
+// MSKK Apr.16.1993 V-AkihiS
+ Rc = !SetConsoleCP((UINT)CPTmp);
+#else
+ Rc = !SetConsoleCP((UINT)CodePage);
+#endif
+ if (Rc)
+ {
+ ASSERT1("KbdNewCp: Cannot set ConsoelCP", FALSE);
+ } else
+ {
+ KbdQueue->Cp = (USHORT)CodePage;
+ SesGrp->KbdCP = CodePage;
+ KbdSetTable(CodePage);
+ }
+ }
+ return (Rc);
+}
diff --git a/private/os2/os2ses/kbdxlat.inc b/private/os2/os2ses/kbdxlat.inc
new file mode 100644
index 000000000..981324253
--- /dev/null
+++ b/private/os2/os2ses/kbdxlat.inc
@@ -0,0 +1,164 @@
+;; SCCSID = @(#)kbdxlat.inc 12.1 88/03/18
+
+;******************************************************************
+;*
+;* EQUATES,STRUCS & MACROS FOR ACCESSING TRANSLATE TABLE FIELDS.
+;*
+
+MaxAct Equ 15h ;Highest Action number allowed in Action field.
+AT Equ 00h ; AT Keyboard
+EN Equ 01h ; ENhanced Keyboard
+
+ifdef JAPAN
+; MSKK Aug.04.1993 V-AKihiS
+; BUGBUG - should investigate OEM ID and OEM keyboard type of other keyboards.
+ JP_OEM Equ 10h ; Japan OEMs reserved keyboard ID.
+;;;; JP_OEM Equ 01h ; Japan OEMs reserved keyboard ID.
+OEM_AX Equ 00h ; OEMs ID (0=AX maker)
+AX_DESKTOP Equ 01h ; AX desktop type keyboard.
+endif
+
+
+;******************************************************************
+;* *
+;* EQUATES & STRUCS FOR ACCESSING TRANSLATE TABLE FIELDS. *
+;* *
+;***** *
+;* The KeyDef Structure: *
+;******
+KDef Struc ;Structure definition for a XlateTable KeyDef entry.
+ XlateOp dw 0 ;Accent flags & Action number.
+ Char1 db 0 ;Usually the unshifted character for a key.
+ Char2 db 0 ;Usually the left/right/Caps shifted char for a key.
+ Char3 db 0 ;Usually the Alt-Graphics shift char for a key.
+ Char4 db 0 ;Only used by a couple of keytypes.
+ Char5 db 0 ;Only used by a one of keytype (14h)
+KDef Ends
+KDefLen Equ Size KDef
+
+;*****
+;* Structure of the Translate Table itself.
+;*****
+Header Struc
+
+ ; Following is the Xlate Table Header:
+
+ XT_CP dw ? ;The translate table code page value.
+ XTFlags1 dw ? ;First flagword (use equates below for access).
+ XTFlags2 dw ? ;Second flagword.
+ XTKbdType dw ? ;FUTURE (keyboard type that uses this table).
+ XTKbdSubType dw ? ;FUTURE (keyboard sub-type that uses this table).
+ XTLength dw ? ;Length of table in bytes.
+ XTEntryCount dw 127 ;Number of scan codes (= keydef entries).
+ XTEntryWidth dw 7 ;Width of each entry.
+ XTCountry dw 'US' ;@@ Language this table represents.
+ XTTableID dw 1 ;@@ DCR031/PTM1730, added for use by Winthorne.
+ XTSubCountry db ' ' ;&& DCR #17 Add kbd kayout ID
+ XTRes dw 8 dup(?) ;&& RESERVED words (changed from 11, see
+ ;&& above).
+Header Ends
+HeaderLen Equ Size Header
+
+;*****
+;* The Accent Entry Structure:
+;*****
+AccEntry Struc ;Definition for entries in the AccentTable below.
+ NonAcChar db 0 ;Char code to pass when next char isn't accented.
+ NonAcScan db 0 ;Scan " " " " " " " "
+ CtlAcChar db 0 ;Char code to pass on Ctl-[accent key] keystroke.
+ CtlAcScan db 0 ;Scan " " " " " "
+ AltAcChar db 0 ;Char code to pass on Atl-[accent key] keystroke.
+ AltAcScan db 0 ;Scan " " " " " "
+;20 pairs of "from"(chars to be accented) and "to"(result char) values:
+ AcMap1 db 0 ;
+ db 0 ;
+ AcMap2 db 0 ;
+ db 0 ;
+ AcMap3 db 0 ;
+ db 0 ;
+ AcMap4 db 0 ;
+ db 0 ;
+ AcMap5 db 0 ;
+ db 0 ;
+ AcMap6 db 0 ;
+ db 0 ;
+ AcMap7 db 0 ;
+ db 0 ;
+ AcMap8 db 0 ;
+ db 0 ;
+ AcMap9 db 0 ;
+ db 0 ;
+ AcMap10 db 0 ;
+ db 0 ;
+ AcMap11 db 0 ;
+ db 0 ;
+ AcMap12 db 0 ;
+ db 0 ;
+ AcMap13 db 0 ;
+ db 0 ;
+ AcMap14 db 0 ;
+ db 0 ;
+ AcMap15 db 0 ;
+ db 0 ;
+ AcMap16 db 0 ;
+ db 0 ;
+ AcMap17 db 0 ;
+ db 0 ;
+ AcMap18 db 0 ;
+ db 0 ;
+ AcMap19 db 0 ;
+ db 0 ;
+ AcMap20 db 0 ;
+ db 0 ;
+AccEntry Ends ;
+AccEntryLen Equ Size AccEntry ;
+
+;*****
+;* Structure of the Translate Table itself.
+;*****
+XTSTRUC Struc
+ XTHead db HeaderLen dup(?)
+ ;@@ Following are the key definitions themselves.
+
+ KDefs db 127*KDefLen dup (?) ;The keydefs.
+
+ ;@@ Following are the accent entries.
+
+ Accents db 7*46 dup (?) ;The accent entries.
+
+XTSTRUC Ends
+
+;********
+;* AccEnt - Accent Entry Macro:
+;********
+
+AccEnt Macro PARMS
+.xlist
+ AccEntry <PARMS>
+.list
+ Endm
+
+;********
+;* KeyDef - Key definition entry macro:
+;********
+
+KeyDef Macro f,g1,g2,g3,g4,g5,g6,g7,a,b,c,d,e
+.erre f LE MaxAct ;Error if Action number is too big.
+z = g7*8000h+g6*4000h+g5*2000h+g4*1000h+g3*800h+g2*400h+g1*200h+f
+.xlist
+ KDef <z,&a,&b,&c,&d,&e>
+.list
+ Endm
+
+;*******
+;* XtHeader - Header definition Macro:
+;*******
+
+XtHeader Macro cp,a,b,c,d,e,f,g,h,i,kb,l,cc,cs ;&& DCR #17 - Machine
+z = i*256+h*128+g*64+f*32+e*16+d*8+c*4+b*2+a ;&& flag added and CS
+ Header <&cp,z,,&kb,,&l,,,cc,,cs> ;&& for subcountryID
+ Endm
+
+; *
+;***** END OF TRANSLATE TABLE DEFINITIONS ****************
+
diff --git a/private/os2/os2ses/makefile b/private/os2/os2ses/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/os2/os2ses/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/os2/os2ses/mon.h b/private/os2/os2ses/mon.h
new file mode 100644
index 000000000..eca918589
--- /dev/null
+++ b/private/os2/os2ses/mon.h
@@ -0,0 +1,82 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ mon.h
+
+Abstract:
+
+ Prototypes for functions & macros in monrqust.c
+
+Author:
+
+ Michael Jarus (mjarus) 2-Feb-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+/*
+ * Table for all (registered) monitor buffers
+ * <ProcessId>+<Buffer> must be unique.
+ */
+
+typedef struct _MON_BUFFER_TABLE
+{
+ PMON_HEADER MonHeader;
+ ULONG ProcessId;
+ PVOID Buffer;
+} MON_BUFFER_TABLE, *PMON_BUFFER_TABLE;
+
+#define MON_BUFFER_TABLE_SIZE 30
+
+MON_BUFFER_TABLE MonBuffTable[MON_BUFFER_TABLE_SIZE];
+
+/*
+ * Find/Add/Delete a Buffer in/to/from the monitor-buffer-table
+ */
+
+DWORD FindMonitorBuffer(IN PVOID Buffer,
+ IN ULONG ProcessId);
+
+DWORD AddMonitorBuffer(IN PVOID Buffer,
+ IN PMON_HEADER MonHeader,
+ IN ULONG ProcessId);
+
+DWORD DelMonitorBuffer(IN PMON_HEADER MonHeader);
+
+/*
+ * Add/Remove the monitor-queue to/from the device chain
+ */
+
+DWORD AddMonitor(IN PMON_HEADER NewMonHeader,
+ IN PMON_HEADER *pMonQueue);
+
+DWORD RemoveMonitor(IN PMON_HEADER OldMonHeader,
+ IN PMON_HEADER *pMonQueue);
+
+/*
+ * Mon internal functions to serve the client requsets.
+ */
+
+DWORD MonOpen(IN MONDEVNUMBER DevType,
+ OUT PHANDLE hMon);
+
+DWORD MonReg(IN PMON_REG MonReg);
+
+DWORD MonRead(IN OUT PMON_RW rwParms,
+ OUT PULONG pReply,
+ IN PVOID pMsg);
+
+DWORD MonWrite(IN PMON_RW rwParms,
+ OUT PULONG pReply,
+ IN PVOID pMsg);
+
+DWORD MonClose(IN HANDLE hMon);
+
diff --git a/private/os2/os2ses/monrqust.c b/private/os2/os2ses/monrqust.c
new file mode 100644
index 000000000..08c260829
--- /dev/null
+++ b/private/os2/os2ses/monrqust.c
@@ -0,0 +1,793 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ monrqust.c
+
+Abstract:
+
+ This module contains the Mon requests thread and
+ the handler for Mon requests.
+
+Author:
+
+ Michael Jarus (mjarus) 21-Jan-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "event.h"
+#include "trans.h"
+#include "monitor.h"
+#include "mon.h"
+#include <stdio.h>
+
+
+USHORT RegSize[] = { MIN_KBD_MON_BUFFER, 127 };
+USHORT RWSize[] = { sizeof(KBD_MON_PACKAGE),
+ sizeof(MOU_MON_PACKAGE) };
+
+extern CRITICAL_SECTION QueueInputCriticalSection;
+
+DWORD
+MonQueueClose(IN HANDLE hMon);
+
+DWORD
+InitMonitor()
+{
+ RtlZeroMemory(&MonBuffTable[0].MonHeader, sizeof(MonBuffTable));
+ MonQueue = NULL;
+
+ MonitorEvent = CreateEventW(
+ NULL,
+ FALSE, /* auto reset */
+ TRUE,
+ NULL);
+
+ if (MonitorEvent == NULL)
+ {
+#if DBG
+ DbgPrint("OS2SES(InitMonitor): unable to create event for Monitor\n");
+#endif
+ return 1L;
+ }
+
+ KbdLastKeyDown = FALSE;
+
+ LastKbdMon = NULL;
+ LastMouMon = NULL;
+
+ return(0L);
+}
+
+
+BOOL
+ServeMonRequest(IN PMONREQUEST PReq,
+ OUT PVOID PStatus,
+ IN PVOID pMsg,
+ OUT PULONG pReply)
+{
+ DWORD Rc;
+
+ Rc = *(PDWORD) PStatus = 0;
+
+ switch (PReq->Request)
+ {
+ case MONOpen:
+ Rc = *(PDWORD) PStatus = MonOpen(PReq->d.OpenClose.MonDevice,
+ &(PReq->d.OpenClose.hMON));
+ break;
+
+ case MONReg:
+ Rc = *(PDWORD) PStatus = MonReg(&(PReq->d.Reg));
+ break;
+
+ case MONRead:
+ Rc = *(PDWORD) PStatus = MonRead(&(PReq->d.rwParms),
+ pReply,
+ pMsg);
+ break;
+
+ case MONWrite:
+ Rc = *(PDWORD) PStatus = MonWrite(&(PReq->d.rwParms),
+ pReply,
+ pMsg);
+ break;
+
+ case MONClose:
+ Rc = *(PDWORD) PStatus = MonClose(PReq->d.OpenClose.hMON);
+ break;
+
+ default:
+ Rc = *(PDWORD) PStatus = ERROR_MON_INVALID_PARMS;
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ DbgPrint("OS2SES(MonRequest): Unknown Mon request = %X\n",
+ PReq->Request);
+ }
+#endif
+ }
+
+ return(TRUE); // Continue
+}
+
+
+DWORD
+MonOpen(IN MONDEVNUMBER DevType,
+ OUT PHANDLE hMon)
+{
+ DWORD Rc;
+
+ /*
+ * allocate buffer for header & queue
+ */
+
+ if (DevType == KbdDevice)
+ {
+ Rc = InitQueue((PKEY_EVENT_QUEUE *)hMon);
+ } else if (DevType == MouseDevice)
+ {
+ Rc = InitMouQueue((PMOU_EVENT_QUEUE *)hMon);
+ } else /* if (DevType == Lpt1Device) */
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ IF_OD2_DEBUG( OS2_EXE )
+ DbgPrint("OS2SES(MonOpen): illegal device\n");
+#endif
+
+ return(ERROR_MONITOR_NOT_SUPPORTED);
+ }
+
+ if (Rc)
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ DbgPrint("OS2SES(MonOpen): unable to allocate handle\n");
+#endif
+
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ ((PKEY_EVENT_QUEUE)*hMon)->MonHdr.DevType = DevType;
+ ((PKEY_EVENT_QUEUE)*hMon)->MonHdr.MonStat = MON_STAT_OPEN; // Mon-Open
+ ((PKEY_EVENT_QUEUE)*hMon)->MonHdr.NextMon = NULL;
+
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ DbgPrint("OS2SES(MonOpen): return address %lx\n", *hMon);
+ }
+#endif
+
+ return(0L);
+}
+
+
+DWORD
+MonReg(IN PMON_REG MonReg)
+{
+ DWORD Rc;
+ BOOL NewReg = FALSE;
+ PMON_HEADER NextMon, NewMonHeader;
+ PKEY_EVENT_QUEUE hMon;
+
+ /*
+ * make sure buffer are not used for other monitor
+ */
+
+ if ((FindMonitorBuffer(MonReg->In, MonReg->ProcessId)) ||
+ (FindMonitorBuffer(MonReg->Out, MonReg->ProcessId)))
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ DbgPrint("OS2SES(MonReg): buffer already reg\n");
+#endif
+
+ return ERROR_MON_INVALID_PARMS;
+ }
+
+ hMon = (PKEY_EVENT_QUEUE)MonReg->hMON;
+
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ DbgPrint("OS2SES(MonReg): hMon address %lx\n", hMon);
+ }
+#endif
+
+ if ((MonReg->InSize < RegSize[hMon->MonHdr.DevType]) ||
+ (MonReg->OutSize < RegSize[hMon->MonHdr.DevType]))
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ DbgPrint("OS2SES(MonReg): buffer too small\n");
+#endif
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ if (hMon->MonHdr.MonStat != MON_STAT_OPEN)
+ {
+ /*
+ * queue in use, allocate new one
+ */
+
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ DbgPrint("OS2SES(MonReg): allocate new queue\n");
+ }
+#endif
+
+ NewReg = TRUE;
+
+ if ((Rc = MonOpen(hMon->MonHdr.DevType,
+ (PHANDLE)&NewMonHeader)))
+ {
+#if DBG
+ DbgPrint("OS2SES(MonReg): unable to allocate handle\n");
+#endif
+ return Rc;
+ }
+
+ NextMon = (PMON_HEADER)hMon;
+
+ while (NextMon->NextMon != NULL)
+ {
+ NextMon = NextMon->NextMon;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ DbgPrint("OS2SES(MonReg): find place\n");
+ }
+#endif
+
+ } else
+ NewMonHeader = (PMON_HEADER)hMon;
+
+ NewMonHeader->MonReg = *MonReg;
+
+ /*
+ * add monitor to the device-queue
+ */
+
+ Rc = AddMonitor(NewMonHeader, (PMON_HEADER *)
+ ((NewMonHeader->DevType == KbdDevice) ?
+ (PMON_HEADER *) &KbdMonQueue : (PMON_HEADER *) &MouMonQueue));
+
+ if (Rc)
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ DbgPrint("OS2SES(MonReg): unable to register\n");
+#endif
+
+ if (NewReg)
+ {
+ HeapFree(HandleHeap, 0,
+ (LPSTR) NewMonHeader->MemoryStartAddress);
+ }
+
+ return(Rc);
+ }
+
+ /*
+ * add buffer to table of monitor-buffer
+ */
+
+ AddMonitorBuffer(MonReg->In, NewMonHeader, MonReg->ProcessId);
+ AddMonitorBuffer(MonReg->Out, NewMonHeader, MonReg->ProcessId);
+
+ NewMonHeader->MonStat = MON_STAT_REG; // Mon-Open-And-Reg
+
+ if (NewReg)
+ {
+ NextMon->NextMon = NewMonHeader;
+ }
+
+ MonReg->InSize = RWSize[NewMonHeader->DevType];
+ MonReg->OutSize = RWSize[NewMonHeader->DevType];
+
+ return(0L);
+}
+
+
+DWORD
+MonRead(IN OUT PMON_RW rwParms,
+ OUT PULONG pReply,
+ IN PVOID pMsg)
+{
+ PMON_HEADER MonHeader;
+ USHORT Length = 0;
+ DWORD MonBuf, Rc;
+
+ /*
+ * check legalty of BUFFER-In, Size of DataBuffer and Monitor state
+ */
+
+ if (!(MonBuf = FindMonitorBuffer(rwParms->MonBuffer, rwParms->ProcessId)) ||
+ (MonBuf == -1L))
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ DbgPrint("OS2SES(MonRead): unable to find buffer\n");
+#endif
+
+ return(ERROR_MON_INVALID_PARMS);
+ }
+
+ MonHeader = (PMON_HEADER)MonBuf;
+
+ if (MonHeader->MonReg.In != rwParms->MonBuffer)
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ DbgPrint("OS2SES(MonRead): illegal monitor buffer\n");
+#endif
+
+ return(ERROR_MON_INVALID_PARMS);
+ }
+
+ if (rwParms->Length < RWSize[MonHeader->DevType])
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ DbgPrint("OS2SES(MonRead): buffer too small\n");
+#endif
+
+ return(ERROR_MON_BUFFER_TOO_SMALL);
+ }
+
+ if (MonHeader->MonStat != MON_STAT_REG)
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ DbgPrint("OS2SES(MonRead): state not ok\n");
+#endif
+
+ //ASSERT(FALSE);
+
+// return(ERROR_MON_INVALID_PARMS);
+ }
+
+ /*
+ * read event if available
+ */
+
+ MonHeader->MonStat = MON_STAT_READ;
+
+ Rc = GetMonInput(
+ RWSize[MonHeader->DevType],
+ (PKEY_EVENT_QUEUE)MonHeader,
+ rwParms,
+ pMsg,
+ pReply
+ );
+
+ if ( *pReply != 0 )
+ {
+ MonHeader->MonStat = MON_STAT_REG;
+ }
+
+ return (Rc);
+}
+
+
+DWORD
+MonWrite(IN PMON_RW rwParms,
+ OUT PULONG pReply,
+ IN PVOID pMsg)
+{
+ PMON_HEADER MonHeader;
+ USHORT Length = 0;
+ DWORD MonBuf, Rc;
+
+ UNREFERENCED_PARAMETER(pMsg);
+ UNREFERENCED_PARAMETER(pReply);
+
+ /*
+ * check legalty of BUFFER-Out, Size of DataBuffer and Monitor state
+ */
+
+ if (!(MonBuf = FindMonitorBuffer(rwParms->MonBuffer, rwParms->ProcessId)) ||
+ (MonBuf == -1L))
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ DbgPrint("OS2SES(MonWrite): unable to find buffer\n");
+#endif
+
+ return(ERROR_MON_INVALID_PARMS);
+ }
+
+ MonHeader = (PMON_HEADER)MonBuf;
+
+ if (MonHeader->MonReg.Out != rwParms->MonBuffer)
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ DbgPrint("OS2SES(MonWrite): illegal monitor buffer\n");
+#endif
+
+ return(ERROR_MON_INVALID_PARMS);
+ }
+
+ if (rwParms->Length < RWSize[MonHeader->DevType])
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ DbgPrint("OS2SES(MonWrite): buffer too small\n");
+#endif
+
+ return(ERROR_MON_INVALID_PARMS);
+ }
+
+ if (rwParms->Length > RWSize[MonHeader->DevType]) // BUGBUG
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ DbgPrint("OS2SES(MonWrite): buffer too big\n");
+#endif
+
+ return(ERROR_MON_DATA_TOO_LARGE);
+ }
+
+ if (MonHeader->MonStat == MON_STAT_OPEN)
+ {
+#if DBG
+ IF_OD2_DEBUG( MON )
+ DbgPrint("OS2SES(MonWrite): state not ok\n");
+#endif
+
+ return(ERROR_MON_INVALID_PARMS);
+ }
+
+ /*
+ * write event
+ */
+
+#if DBG
+ IF_OD2_DEBUG( MON )
+ {
+ DbgPrint("OS2SES(MonWrite): (before) from queue %lx, to queue %lx\n",
+ MonHeader, MonHeader->NextQueue );
+ }
+#endif
+
+ Rc = PutMonInput(
+ RWSize[MonHeader->DevType],
+ (PKEY_EVENT_QUEUE)MonHeader->NextQueue,
+ 1,
+ //rwParms,
+ (PKBD_MON_PACKAGE)&(rwParms->ioBuff[0]),
+ pMsg,
+ pReply);
+
+ // BUGBUG if not enough place
+
+ return( Rc );
+}
+
+
+DWORD
+MonClose(IN HANDLE hMon)
+{
+ PMON_HEADER NextMon, MonHeader = (PMON_HEADER)hMon;
+
+ while (MonHeader)
+ {
+ NextMon = MonHeader->NextMon;
+ MonQueueClose((HANDLE)MonHeader);
+ MonHeader = NextMon;
+ }
+
+ return(0L);
+}
+
+
+DWORD
+MonQueueClose(IN HANDLE hMon)
+{
+ PMON_HEADER MonHeader = (PMON_HEADER)hMon;
+
+ if (MonHeader->MonStat >= MON_STAT_REG)
+ {
+ /*
+ * Monitor are reg - DeReg :
+ * remove monitor & delete entried in table
+ */
+
+ RemoveMonitor(MonHeader, (PMON_HEADER *)
+ ((MonHeader->DevType == KbdDevice) ?
+ (PMON_HEADER *) &KbdMonQueue :
+ (PMON_HEADER *) &MouMonQueue));
+
+ DelMonitorBuffer(MonHeader);
+ }
+
+ /*
+ * Free header from heap
+ */
+
+ HeapFree(HandleHeap, 0,
+ (LPSTR) MonHeader->MemoryStartAddress);
+
+ return(0L);
+}
+
+
+DWORD
+FindMonitorBuffer(IN PVOID Buffer,
+ IN ULONG ProcessId)
+{
+ ULONG i, FreeCount = 0;
+
+ for ( i = 0 ; i < MON_BUFFER_TABLE_SIZE ; i++ )
+ {
+ if ((MonBuffTable[i].Buffer == Buffer) &&
+ (MonBuffTable[i].ProcessId == ProcessId))
+ {
+ return((DWORD)MonBuffTable[i].MonHeader);
+ } else if (!MonBuffTable[i].Buffer)
+ {
+ FreeCount++;
+ }
+
+ }
+
+ if (FreeCount < 2)
+ {
+ return((DWORD)-1L); // no place for new 2 buffers
+ }
+
+ return(0L);
+}
+
+
+DWORD
+AddMonitorBuffer(IN PVOID Buffer,
+ IN PMON_HEADER MonHeader,
+ IN ULONG ProcessId)
+{
+ ULONG i, FindCount = 0;
+
+ for ( i = 0 ; i < MON_BUFFER_TABLE_SIZE ; i++ )
+ {
+ if (!MonBuffTable[i].Buffer)
+ {
+ MonBuffTable[i].Buffer = Buffer;
+ MonBuffTable[i].MonHeader = MonHeader;
+ MonBuffTable[i].ProcessId = ProcessId;
+
+ return((DWORD)MonBuffTable[i].MonHeader);
+ }
+ }
+
+ ASSERT( FALSE );
+
+ return(0L);
+}
+
+
+DWORD
+DelMonitorBuffer(IN PMON_HEADER MonHeader)
+{
+ ULONG i, FindCount = 0;
+
+ for ( i = 0 ; i < MON_BUFFER_TABLE_SIZE ; i++ )
+ {
+ if (MonBuffTable[i].MonHeader == MonHeader)
+ {
+ RtlZeroMemory(&(MonBuffTable[i]), sizeof(MON_BUFFER_TABLE));
+ FindCount++;
+ }
+ }
+
+ ASSERT( FindCount == 2 );
+
+ return(0L);
+}
+
+
+DWORD
+NewKbdQueue(IN PKEY_EVENT_QUEUE NewKbdQueue)
+{
+
+ if (WaitForSingleObject( MonitorEvent, INFINITE ))
+ {
+ return(ERROR_MONITOR_NOT_SUPPORTED);
+ }
+
+ if (LastKbdMon != NULL)
+ {
+ LastKbdMon->MonHdr.NextQueue = (PMON_HEADER)NewKbdQueue;
+ } else
+ KbdMonQueue = NewKbdQueue;
+
+ SetEvent( MonitorEvent );
+
+ return(0L);
+}
+
+
+DWORD AddMonitor(IN PMON_HEADER NewMonHeader,
+ IN PMON_HEADER *pMonQueue)
+{
+ PMON_HEADER MonHeader, LastMonHeader = NULL;
+ USHORT Index;
+#if DBG
+ PMON_HEADER DbgMonHeader;
+#endif
+
+ /*
+ * Positioning in chain
+ * --------------------
+ * 1st registered as FIRST
+ * ...
+ * last registered as FIRST
+ * last registered as DEFAULT
+ * ...
+ * 1st registered as DEFAULT
+ * last registered as END
+ * ...
+ * 1st registered as END
+ */
+
+ if (NewMonHeader->MonReg.Pos > MONITOR_END)
+ {
+ /*
+ * ignore MONITOR_SPECIAL
+ */
+
+ NewMonHeader->MonReg.Pos -= 3;
+ NewMonHeader->Flag = 1;
+ }
+
+ /*
+ * Translate Position:
+ * FIRST = 0
+ * DEFAULT = 1
+ * END = 2
+ * device (kbd/mouse) = 3
+ *
+ * when looking for the place, DEFAULT is assign also to FIRST
+ */
+
+ if (NewMonHeader->MonReg.Pos < MONITOR_END)
+ {
+ /*
+ * XOR MONITOR_FIRST & MONITOR_DEFAULT
+ */
+
+ NewMonHeader->MonReg.Pos = 1 - NewMonHeader->MonReg.Pos;
+ }
+
+ Index = (USHORT)NewMonHeader->MonReg.Pos;
+
+ if (Index == 0)
+ {
+ Index = 1; // last FIRST is equivalent to 1st DEFAULT
+ }
+
+ if (WaitForSingleObject( MonitorEvent, INFINITE ))
+ {
+ return(ERROR_MONITOR_NOT_SUPPORTED);
+ }
+
+ MonHeader = *pMonQueue;
+
+ /*
+ * find the place in chain
+ */
+
+ while (MonHeader->MonReg.Pos < (ULONG)Index)
+ {
+ LastMonHeader = MonHeader;
+ MonHeader = MonHeader->NextQueue;
+
+ }
+
+ NewMonHeader->NextQueue = MonHeader;
+
+ if (LastMonHeader == NULL)
+ {
+ NewMonHeader->NextQueue = *pMonQueue;
+ *pMonQueue = NewMonHeader;
+ } else
+ {
+ NewMonHeader->NextQueue = LastMonHeader->NextQueue;
+ LastMonHeader->NextQueue = NewMonHeader;
+ }
+
+ if ((MonHeader->MonReg.Pos == 3) && // we add the last queue in chain for Kbd
+ (*pMonQueue == (PMON_HEADER)KbdMonQueue ))
+ {
+ LastKbdMon = (PKEY_EVENT_QUEUE)NewMonHeader;
+ }
+
+ SetEvent( MonitorEvent );
+
+#if DBG
+ DbgMonHeader = *pMonQueue;
+
+ IF_OD2_DEBUG( MON )
+ {
+ while (DbgMonHeader->NextQueue)
+ {
+ DbgPrint("OS2SES(AddMonitor): Current %lx, next %lx\n", DbgMonHeader, DbgMonHeader->NextQueue);
+
+ DbgMonHeader = DbgMonHeader->NextQueue;
+ }
+
+ DbgPrint("OS2SES(MonReg): %lx ... %lx, (%lx) %lx, %lx (%lx) ... %lx, %lx\n",
+ KbdMonQueue, LastMonHeader,
+ (LastMonHeader) ? LastMonHeader->NextQueue : NULL,
+ NewMonHeader, NewMonHeader->NextQueue, MonHeader, LastKbdMon, KbdQueue);
+ }
+#endif
+
+ return(0L);
+}
+
+
+DWORD
+RemoveMonitor(IN PMON_HEADER OldMonHeader,
+ IN PMON_HEADER *pMonQueue)
+{
+ PMON_HEADER MonHeader, LastMonHeader = NULL;
+
+ if (WaitForSingleObject( MonitorEvent, INFINITE ))
+ {
+ return(ERROR_MONITOR_NOT_SUPPORTED);
+ }
+
+ MonHeader = *pMonQueue;
+
+ /*
+ * find the place in chain
+ */
+
+ while (MonHeader != NULL && MonHeader != OldMonHeader)
+ {
+ LastMonHeader = MonHeader;
+ MonHeader = MonHeader->NextQueue;
+ }
+
+ if (MonHeader == NULL)
+ {
+ return(0);
+ }
+
+ if (LastMonHeader == NULL)
+ {
+ *pMonQueue = MonHeader->NextQueue;
+ } else
+ LastMonHeader->NextQueue = MonHeader->NextQueue;
+
+ if ((OldMonHeader->NextQueue->MonReg.Index == 3) && // we remove the last queue in chain for Kbd
+ (*pMonQueue == (PMON_HEADER)KbdMonQueue ))
+ {
+ if (LastMonHeader == NULL)
+ {
+ LastKbdMon = NULL;
+ } else
+ LastKbdMon = (PKEY_EVENT_QUEUE)LastMonHeader;
+ }
+
+ SetEvent( MonitorEvent );
+
+ return(0L);
+}
diff --git a/private/os2/os2ses/mou.h b/private/os2/os2ses/mou.h
new file mode 100644
index 000000000..39144c09e
--- /dev/null
+++ b/private/os2/os2ses/mou.h
@@ -0,0 +1,28 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ mou.h
+
+Abstract:
+
+ Prototypes for functions & macros in mourqust.c
+
+Author:
+
+ Michael Jarus (mjarus) 27-Oct-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+
+DWORD
+MouReaderThread(IN PMOU_EVENT_QUEUE MonQueue);
+
diff --git a/private/os2/os2ses/mourqust.c b/private/os2/os2ses/mourqust.c
new file mode 100644
index 000000000..37359e88a
--- /dev/null
+++ b/private/os2/os2ses/mourqust.c
@@ -0,0 +1,235 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ mourqust.c
+
+Abstract:
+
+ This module contains the Mou requests thread and
+ the handler for Mou requests.
+
+Author:
+
+ Michael Jarus (mjarus) 23-Oct-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "event.h"
+#include "trans.h"
+#include "mou.h"
+#include <stdio.h>
+
+#if DBG
+BYTE ServeMouRequestStr[] = "ServeMouRequest";
+#endif
+
+DWORD
+GetOs2MouEventIntoQueue();
+
+VOID
+Ow2MouOn();
+
+VOID
+Ow2MouOff();
+
+BOOL
+ServeMouRequest(IN PMOUREQUEST PReq,
+ OUT PVOID PStatus,
+ IN PVOID pMsg,
+ OUT PULONG pReply)
+{
+// COORD dwMousePosition;
+ DWORD Rc, NumEvent;
+ MOUEVENTINFO MouEvent;
+
+ UNREFERENCED_PARAMETER(pMsg);
+
+ Rc = *(PDWORD) PStatus = 0;
+ switch (PReq->Request)
+ {
+ case MOUOpen:
+ if (!MouNumber)
+ {
+ Ow2MouOn();
+ }
+ MouNumber++;
+ break;
+
+ case MOUClose:
+ MouNumber--;
+ if (!MouNumber)
+ {
+ Ow2MouOff();
+ MouQueue->Out = MouQueue->In;
+ }
+ break;
+
+ case MOUFlushQue:
+ Or2WinGetNumberOfConsoleInputEvents(
+ #if DBG
+ ServeMouRequestStr,
+ #endif
+ hConsoleInput,
+ &NumEvent
+ );
+ while (NumEvent)
+ {
+ MouQueue->Out = MouQueue->In;
+
+ GetOs2MouEvent( MOU_NOWAIT,
+ &MouEvent,
+ pMsg,
+ pReply);
+
+ MouQueue->Out = MouQueue->In;
+
+ Or2WinGetNumberOfConsoleInputEvents(
+ #if DBG
+ ServeMouRequestStr,
+ #endif
+ hConsoleInput,
+ &NumEvent
+ );
+ }
+ break;
+
+ case MOUGetNumQueEl:
+ GetOs2MouEventIntoQueue();
+ PReq->d.NumEvent.cEvents = (USHORT)((MouQueue->In >= MouQueue->Out) ?
+ (MouQueue->In - MouQueue->Out) :
+ (MouQueue->End - MouQueue->Out) +
+ (MouQueue->In - &(MouQueue->Event[0])) + (USHORT) 1);
+
+ PReq->d.NumEvent.cmaxEvents = MOUSE_QUEUE_LENGTH - 1;
+ break;
+
+ case MOUGetEventMask:
+ PReq->d.Setup = MouEventMask;
+ break;
+
+ case MOUSetEventMask:
+ if (PReq->d.Setup & ~OS2_MOUSE_LEGAL_EVENT_MASK)
+ Rc = *(PDWORD) PStatus = ERROR_MOUSE_INV_PARMS;
+ else
+ MouEventMask = PReq->d.Setup;
+ break;
+
+ case MOUGetNumButtons:
+ Rc = !Or2WinGetNumberOfConsoleMouseButtons(
+ #if DBG
+ ServeMouRequestStr,
+ #endif
+ &PReq->d.Setup
+ );
+ break;
+
+ case MOUReadEventQue:
+ RtlZeroMemory(&PReq->d.MouInfo, sizeof(MOUEVENTINFO));
+ Rc = *(PDWORD) PStatus = GetOs2MouEvent(PReq->fWait,
+ &PReq->d.MouInfo,
+ pMsg,
+ pReply);
+ break;
+
+ case MOUGetDevStatus:
+ PReq->d.Setup = MouDevStatus;
+ break;
+
+ case MOUGetScaleFact:
+ PReq->d.ScalFact.rowScale = 1;
+ PReq->d.ScalFact.colScale = 1;
+ break;
+
+ case MOUGetNumMickeys:
+ PReq->d.Setup = 80;
+ break;
+
+ case MOUGetPtrPos:
+ PReq->d.Loc = MouPtrLoc;
+ break;
+
+ case MOUSetDevStatus:
+ if (PReq->d.Setup & ~(MOUSE_DISABLED | MOUSE_MICKEYS))
+ {
+ Rc = *(PDWORD) PStatus = ERROR_MOUSE_INV_PARMS;
+ } else
+ {
+ if ((MouDevStatus = PReq->d.Setup) & MOUSE_DISABLED)
+ {
+ MouQueue->Out = MouQueue->In;
+ }
+ }
+ break;
+
+ case MOUGetPtrShape:
+ PReq->d.Shape.cb = 4;
+ PReq->d.Shape.col = 1;
+ PReq->d.Shape.row = 1;
+ PReq->d.Shape.colHot = 1;
+ PReq->d.Shape.rowHot = 1;
+ // we return the default mask of OS/2 (0xffff, 0x7700) after the lpc
+ break;
+
+ case MOUDrawPtr:
+ case MOURemovePtr:
+ case MOUSetPtrPos:
+ case MOUSetPtrShape:
+ case MOUSetScaleFact:
+ break;
+
+ default:
+ *(PDWORD) PStatus = (DWORD)-1L; //STATUS_INVALID_PARAMETER;
+ Rc = 1;
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ KdPrint(("OS2SES(MouRqust): Unknown Mou request = %X\n",
+ PReq->Request));
+ }
+#endif
+ }
+
+ if ( !Rc )
+ {
+ *(PDWORD) PStatus = 0;
+ } else if (*(PDWORD) PStatus == 0)
+/* BUGBUG=> BUGBUG! error code and returned Status are wrong */
+ {
+ *(PDWORD) PStatus = GetLastError();
+ }
+ return(TRUE); // Continue
+}
+
+
+DWORD
+MouInit(IN VOID)
+{
+
+ if (InitMouQueue(&MouQueue))
+ {
+ return(TRUE);
+ }
+
+ MouMonQueue = MouQueue;
+
+ MouNumber = 0;
+ MouLastEvent = 0;
+ MouEventMask = OS2_MOUSE_DEAFULT_EVENT_MASK;
+ MouDevStatus = 0;
+
+ MouPtrLoc.row = MouPtrLoc.col = 0;
+
+ return(FALSE);
+}
+
diff --git a/private/os2/os2ses/nls.c b/private/os2/os2ses/nls.c
new file mode 100644
index 000000000..f3a4d3ef4
--- /dev/null
+++ b/private/os2/os2ses/nls.c
@@ -0,0 +1,349 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ nls.c
+
+Abstract:
+
+ This module contains the support for NLS
+
+Author:
+
+ Michael Jarus (mjarus) 28-Jul-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include <stdio.h>
+#include <string.h>
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "os2nls.h"
+#include "trans.h"
+#include "os2win.h"
+
+
+
+ULONG
+NlsCountryToLoacle(
+ IN ULONG NlsCountryCode,
+ IN LCID *NlsLocaleID
+ );
+
+#if DBG
+BYTE NLSInitStr[] = "NLSInit";
+#endif
+
+DWORD
+NLSInit()
+{
+ ULONG i, Win32LCID, CurrentVioCP, CurrentKbdCP;
+ USHORT LocaleLang;
+
+ /*
+ * Get Current Console CP
+ */
+
+ CurrentVioCP = (ULONG)Or2WinGetConsoleOutputCP(
+ #if DBG
+ NLSInitStr
+ #endif
+ );
+
+ CurrentKbdCP = (ULONG)Or2WinGetConsoleCP(
+ #if DBG
+ NLSInitStr
+ #endif
+ );
+
+#ifdef DBCS
+// MSKK Jun.16.1993 V-AkihiS
+ SesGrp->DosCP = (ULONG)Or2WinGetConsoleCP(
+ #if DBG
+ NLSInitStr
+ #endif
+ );
+#endif
+
+ Win32LCID = (ULONG)Or2WinGetThreadLocale(
+ #if DBG
+ NLSInitStr
+ #endif
+ );
+
+ if ((Win32LCID != SesGrp->Win32LCID) &&
+ (SesGrp->Os2srvUseRegisterInfo ||
+ (Win32LCID != SesGrp->Os2ssLCID)))
+ {
+ /*
+ * Inherit NLS definitions from Win32
+ * We get here if the LOCALE inherit by Os2srv is different
+ * from the LOCALE inherit by the os2.exe
+ * We handle only COUNTRY and LOCALE parms. (not CP, which are equal)
+ */
+
+ //SesGrp->Win32OEMCP = GetOEMCP();
+ //SesGrp->Win32ACP = GetACP();
+ SesGrp->Win32LCID = Win32LCID;
+ SesGrp->Win32LANGID = (ULONG)Or2WinGetUserDefaultLangID(
+ #if DBG
+ NLSInitStr
+ #endif
+ );
+
+ Or2NlsGetCountryFromLocale((LCID)SesGrp->Win32LCID, &SesGrp->Win32CountryCode);
+
+ //SesGrp->PrimaryCP = SesGrp->Win32OEMCP;
+ SesGrp->CountryCode = SesGrp->Win32CountryCode;
+ SesGrp->Os2ssLCID = SesGrp->Win32LCID;
+#ifdef JAPAN
+// MSKK Nov.04.1992 V-AkihiS
+ SesGrp->LanguageID = LANG_JAPANESE;
+#else
+ SesGrp->LanguageID = LANG_ENGLISH;
+#endif
+
+ LocaleLang = PRIMARYLANGID(LANGIDFROMLCID(Win32LCID));
+ for ( i = 0 ; Or2NlsLangIdTable[i] ; i++ )
+ {
+ if (Or2NlsLangIdTable[i] == LocaleLang)
+ {
+ SesGrp->LanguageID = Or2NlsLangIdTable[i];
+ break;
+ }
+ }
+
+ /*
+ * Get CtryInfo, DBCSEv, CollateTable, CaseMapTable for the default
+ * (We don't have to update CP-depent parms since CP,s are equal)
+ */
+
+ Or2NlsGetCtryInfo(
+ (LCID)SesGrp->Os2ssLCID,
+ (UINT)SesGrp->PrimaryCP,
+ (PCOUNTRYINFO)&SesGrp->CountryInfo
+ );
+
+#if DBG
+ /*
+ * Dump specail NLS info to the debugger
+ */
+
+ IF_OD2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES(Os2-NLS): "));
+ }
+#endif
+
+ //SesGrp->VioCP = SesGrp->KbdCP = SesGrp->DosCP = SesGrp->PrimaryCP;
+ } else
+ {
+ if (Win32LCID != SesGrp->Win32LCID)
+ {
+ Or2WinSetThreadLocale(
+ #if DBG
+ NLSInitStr,
+ #endif
+ (LCID)SesGrp->Win32LCID
+ );
+ }
+#if DBG
+ /*
+ * Dump specail NLS info to the debugger
+ */
+
+ IF_OD2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES(Os2-NLS): using OS2SRV NLS definitions\n "));
+ }
+#endif
+ }
+
+#if DBG
+ /*
+ * Dump all NLS info to the debugger
+ */
+
+ IF_OD2_DEBUG( NLS )
+ {
+ KdPrint(("CP %lu (%lu,%lu), Country %lu, LangID %lx ,LCID %lx\n",
+ SesGrp->DosCP, SesGrp->PrimaryCP, SesGrp->SecondaryCP,
+ SesGrp->CountryCode, SesGrp->LanguageID, SesGrp->Os2ssLCID));
+
+ KdPrint(("OS2SES(Win32-NLS): OEMCP %lu, ACP %lu, Country %lu, LangID %lx\n",
+ SesGrp->Win32OEMCP, SesGrp->Win32ACP, SesGrp->Win32CountryCode,
+ SesGrp->Win32LANGID));
+
+ KdPrint((" LCID %lx, ConCP %lu, ConOutCP %lu\n",
+ SesGrp->Win32LCID, CurrentKbdCP, CurrentVioCP));
+ }
+#endif
+
+ /*
+ * Complete the NLS initialization for Vio and KBD
+ */
+
+ KbdInitForNLS(CurrentKbdCP);
+ VioInitForNLS(CurrentVioCP);
+
+ return (NO_ERROR);
+}
+
+
+DWORD
+Ow2NlsGetCtryInfo(
+ IN ULONG NlsCodePage,
+ IN ULONG NlsCountryCode,
+ OUT PVOID NlsCountryInfo
+ )
+{
+ ULONG Rc;
+ LCID NlsLocaleID;
+
+ Rc = NlsCountryToLoacle(
+ NlsCountryCode,
+ &NlsLocaleID
+ );
+
+ if (Rc)
+ {
+#if DBG
+ IF_OD2_DEBUG2( NLS, OS2_EXE )
+ KdPrint(("OS2SES(NlsRequest-GetCtryInfo): cannot find LocaleID Rc %lu\n",
+ Rc));
+#endif
+ return(Rc);
+ }
+
+ return (Or2NlsGetCtryInfo(
+ NlsLocaleID,
+ (UINT)NlsCodePage,
+ (PCOUNTRYINFO)NlsCountryInfo
+ ));
+}
+
+
+DWORD
+Ow2NlsGetCollateTable(
+ IN ULONG NlsCodePage,
+ IN ULONG NlsCountryCode,
+ OUT PVOID NlsColateTable
+ )
+{
+ DWORD Rc;
+ LCID NlsLocaleID;
+
+ Rc = NlsCountryToLoacle(
+ NlsCountryCode,
+ &NlsLocaleID
+ );
+
+ if (Rc)
+ {
+#if DBG
+ IF_OD2_DEBUG2( NLS, OS2_EXE )
+ KdPrint(("OS2SES(NlsRequest-GetCtryInfo): cannot find LocaleID Rc %lu\n",
+ Rc));
+#endif
+ return(Rc);
+ }
+
+ Rc = Or2NlsGetMapTable(
+ NlsLocaleID,
+ (UINT)NlsCodePage,
+ LCMAP_SORTKEY,
+ (PUCHAR)NlsColateTable
+ );
+ if (Rc)
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OD2_DEBUG2( NLS, OS2_EXE )
+ KdPrint(("OS2SES(NlsRequest-GetColateTable): Rc %lu\n",
+ Rc));
+#endif
+ }
+ return(Rc);
+}
+
+
+DWORD
+Ow2NlsGetCaseMapTable(
+ IN ULONG NlsCodePage,
+ IN ULONG NlsCountryCode,
+ OUT PVOID NlsColateTable
+ )
+{
+ DWORD Rc;
+ LCID NlsLocaleID;
+
+ Rc = NlsCountryToLoacle(
+ NlsCountryCode,
+ &NlsLocaleID
+ );
+
+ if (Rc)
+ {
+#if DBG
+ IF_OD2_DEBUG2( NLS, OS2_EXE )
+ KdPrint(("OS2SES(NlsRequest-GetCtryInfo): cannot find LocaleID Rc %lu\n",
+ Rc));
+#endif
+ return(Rc);
+ }
+
+ Rc = Or2NlsGetMapTable(
+ NlsLocaleID,
+ (UINT)NlsCodePage,
+ LCMAP_UPPERCASE,
+ (PUCHAR)NlsColateTable
+ );
+ if (Rc)
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OD2_DEBUG2( NLS, OS2_EXE )
+ KdPrint(("OS2SES(NlsRequest-GetCaseMap): Rc %lu\n",
+ Rc));
+#endif
+ }
+ return(Rc);
+}
+
+
+DWORD
+Ow2NlsGetDBCSEn(
+ IN ULONG NlsCodePage,
+ OUT PVOID NlsDBCSVec
+ )
+{
+ POD2_DBCS_VECTOR_ENTRY DBCSVec = (POD2_DBCS_VECTOR_ENTRY) NlsDBCSVec;
+
+ return(Or2NlsGetCPInfo(
+ (UINT)NlsCodePage,
+ (POD2_DBCS_VECTOR_ENTRY) NlsDBCSVec
+ ));
+}
+
+
+ULONG
+NlsCountryToLoacle(
+ IN ULONG NlsCountryCode,
+ IN LCID *NlsLocaleID
+ )
+{
+ // BUGBUG: find LocalId from CountryCode
+
+ *NlsLocaleID = (LCID) -1;
+
+ return (ERROR_NLS_NO_CTRY_CODE);
+}
+
diff --git a/private/os2/os2ses/ntinitss.c b/private/os2/os2ses/ntinitss.c
new file mode 100644
index 000000000..449c81c34
--- /dev/null
+++ b/private/os2/os2ses/ntinitss.c
@@ -0,0 +1,1650 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ntinitss.c
+
+Abstract:
+
+ This module contains the code to establish the connection between
+ the session console process and the OS2 Emulation Subsystem.
+
+Author:
+
+ Avi Nathan (avin) 17-Jul-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#define NTOS2_ONLY
+#include "os2ses.h"
+#include "os2tile.h"
+#if PMNT
+#define INCL_32BIT
+#include "pmnt.h"
+#endif
+#include <winerror.h>
+
+#define OD2_PORT_MEMORY_SIZE 0x10000
+
+extern PVOID Od2PortHeap;
+extern ULONG Od2PortMemoryRemoteDelta;
+extern PSZ Od2PgmFilePath;
+extern HANDLE Od2PortHandle;
+
+#if PMNT
+extern ULONG PMSubprocSem32;
+extern BOOLEAN Ow2WriteBackCloseEvent();
+extern APIRET DosSemClear(ULONG hsem);
+#endif //PMNT
+
+HANDLE
+CreateEventW(
+ PVOID lpEventAttributes,
+ BOOL bManualReset,
+ BOOL bInitialState,
+ LPCWSTR lpName
+ );
+
+ULONG
+KbdInitAfterSesGrp(IN VOID);
+
+APIRET
+Od2WaitForSingleObject(
+ IN HANDLE Handle,
+ IN BOOLEAN Alertable,
+ IN PLARGE_INTEGER Timeout OPTIONAL
+ );
+
+BOOLEAN
+Od2InitCreateProcessMessage(
+ OUT PSCREQ_CREATE pCreate
+ );
+
+VOID
+Od2HandleCreateProcessRespond(
+ IN PSCREQ_CREATE pCreate
+ );
+
+VOID
+ExitThread(
+ ULONG dwExitCode
+ );
+
+APIRET
+OpenLVBsection(VOID);
+
+DWORD
+GetCurrentDirectoryW(
+ DWORD nBufferLength,
+ LPWSTR lpBuffer
+ );
+
+BOOLEAN
+InitializeSecurityDescriptor (
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ DWORD dwRevision
+ );
+
+BOOLEAN
+SetSecurityDescriptorDacl (
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ BOOLEAN bDaclPresent,
+ PACL pDacl,
+ BOOLEAN bDaclDefaulted
+ );
+
+// Defined in <winbase.h> but we can't include it in this file
+typedef struct _SECURITY_ATTRIBUTES {
+ DWORD nLength;
+ PVOID lpSecurityDescriptor;
+ BOOL bInheritHandle;
+} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
+
+BOOLEAN Ow2ExitInProcess = (BOOLEAN)FALSE;
+HANDLE hOs2Srv;
+ULONG Ow2bNewSession = 0;
+OEM_STRING Ow2CommandLineString;
+
+HANDLE CtrlDataSemaphore;
+HANDLE KbdDataSemaphore;
+HANDLE FocusSemaphore;
+HANDLE MouDataSemaphore;
+HANDLE PopUpSemaphore;
+HANDLE ScreenLockSemaphore;
+HANDLE Od2StdHandleLockHandle;
+HANDLE Od2VioWriteSemHandle;
+
+BOOLEAN Od2ReceivedSignalAtInit = FALSE;
+ULONG Od2InitSignalType;
+
+BYTE NtInitssFail[] = "OS2SES(ntinitss) - error %X at %s\n";
+
+/*
+ * This is the table of Secions to initialize.
+ *
+ * Section
+ * SectionSize - the size of the section (0 - no section, -1 - for LVB)
+ * DataNamePrefix - the prefix added to get section name
+ * SectionDataBaseAddress - where to put the base address of the section
+ * SectionDataHandle - where to put the handle of the section
+ */
+
+struct
+{
+ ULONG SectionSize;
+ WCHAR DataNamePrefix;
+ PVOID *SectionDataBaseAddress;
+ HANDLE *SectionDataHandle;
+} PORT_TABLE[] =
+ {
+ {
+ OS2SES_CTRL_SECTION_SIZE,
+ U_OS2_SES_BASE_DATA_PREFIX,
+ &Os2SessionCtrlDataBaseAddress,
+ &Os2SessionCtrlDataSectionHandle
+ },
+ {
+ OS2SES_GROUP_SECTION_SIZE,
+ U_OS2_SES_GROUP_PREFIX,
+ &Os2SessionDataBaseAddress,
+ &Os2SessionSesGrpDataSectionHandle
+ },
+ {
+ // Warning: MUST BE THE LAST ENTRY OF THE TABLE
+
+ (ULONG)(-1L),
+ U_OS2_SES_BASE_LVB_PREFIX,
+ &(PVOID)(LVBBuffer),
+ &LVBHandle
+ },
+ {
+ 0, // End of Table
+ 0,
+ NULL,
+ NULL
+ }
+ };
+
+/*
+ * This is a table of semaphores to create (and close).
+ * All (but PauseEvent which is Event) are Semaphores.
+ */
+
+struct
+{
+ WCHAR NamePrefix;
+ HANDLE * SemaphoreHandle;
+} SEMAPHORE_TABLE [] =
+{
+ {
+ U_OS2_SES_CTRL_PORT_SEMAPHORE_PREFIX,
+ &CtrlDataSemaphore,
+ },
+ {
+ U_OS2_SES_KBD_PORT_SEMAPHORE_PREFIX,
+ &KbdDataSemaphore,
+ },
+ {
+ U_OS2_SES_KBD_FOCUS_SEMAPHORE_PREFIX,
+ &FocusSemaphore,
+ },
+ {
+ U_OS2_SES_MOU_PORT_SEMAPHORE_PREFIX,
+ &MouDataSemaphore,
+ },
+ {
+ U_OS2_SES_POPUP_SEMAPHORE_PREFIX,
+ &PopUpSemaphore,
+ },
+ {
+ U_OS2_SES_SLOCK_SEMAPHORE_PREFIX,
+ &ScreenLockSemaphore,
+ },
+ {
+ U_OS2_SES_STD_HANDLE_LOCK_PREFIX,
+ &Od2StdHandleLockHandle,
+ },
+ {
+ U_OS2_SES_PAUSE_EVENT_PREFIX,
+ &PauseEvent,
+ },
+ {
+ U_OS2_SES_VIOWRITE_SEMAPHORE_PREFIX,
+ &Od2VioWriteSemHandle,
+ },
+ {
+ 0,
+ NULL
+ }
+};
+
+#if DBG
+PSZ SEMAPHORE_NAME_TABLE[] =
+ {
+ "CtrlDataSemaphore",
+ "KbdDataSemaphore",
+ "FocusSemaphore",
+ "MouDataSemaphore",
+ "PopUpSemaphore",
+ "ScreenLockSemaphore",
+ "PauseEvent",
+ "VioWriteSemaphore",
+ NULL
+ };
+#endif
+
+ //
+ // A routine that wait for os2srv to connect
+ //
+
+NTSTATUS
+CtrlListen()
+{
+ NTSTATUS Status;
+ PSCCONNECTINFO ConnectionInfo;
+ SCREQUESTMSG ConnectionRequest;
+ HANDLE CommPortHandle;
+
+
+ /*
+ * Listen to the os2ss connection and then too all
+ * processes created in this session.
+ */
+
+ // Non-alertable, indefinite wait listen
+ Status = NtListenPort( Ow2hOs2sesPort,
+ (PPORT_MESSAGE) &ConnectionRequest);
+ if (!NT_SUCCESS( Status ))
+ {
+ KdPrint(( NtInitssFail, Status, "NtListenPort"));
+ return Status;
+ } else
+ {
+
+ // ??? Any reply
+ ConnectionInfo = &ConnectionRequest.ConnectionRequest;
+ ConnectionInfo->dummy = 0;
+
+ // BUGBUG!
+ // ServerView.Length = sizeof(ServerView);
+ // ServerView.SectionOffset = 0L;
+ // ServerView.ViewSize = 0L;
+
+ Status = NtAcceptConnectPort(
+ & CommPortHandle,
+ NULL,
+ (PPORT_MESSAGE) &ConnectionRequest,
+ (BOOLEAN)TRUE,
+ NULL, // &ServerView,
+ NULL);
+
+ if ( !NT_SUCCESS(Status) )
+ {
+#if DBG
+ KdPrint(( NtInitssFail, Status, "NtAcceptConnectPort"));
+#endif
+ return Status;
+ } else
+ {
+ /*
+ * Record the view section address in a global variable.
+ */
+ // BUGBUG! Os2SesConPortBaseAddress = ServerView.ViewBase;
+ Status = NtCompleteConnectPort( CommPortHandle );
+ ASSERT( NT_SUCCESS( Status) );
+
+ return Status;
+ }
+ }
+}
+
+
+DWORD
+SessionRequestThread(IN PVOID Parameter)
+{
+ NTSTATUS Status;
+
+ UNREFERENCED_PARAMETER(Parameter);
+
+ try {
+ //
+ // Listen and accept session request port
+ //
+
+ Status = CtrlListen();
+ if ( !NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(( NtInitssFail, Status, "CtrlListen"));
+ ASSERT( FALSE );
+#endif
+ Ow2Exit( 0, NULL, 1);
+ }
+
+ ServeSessionRequests();
+ }
+ //
+ // if Os2Debug is on, and ntsd is attached, it will get the second chance
+ //
+#if DBG
+ except( (Os2Debug ? Ow2FaultFilter(EXCEPTION_CONTINUE_SEARCH, GetExceptionInformation()):
+
+ Ow2FaultFilter(EXCEPTION_EXECUTE_HANDLER, GetExceptionInformation())) ) {
+#else
+ except( Ow2FaultFilter(EXCEPTION_EXECUTE_HANDLER, GetExceptionInformation()) ) {
+#endif
+
+#if DBG
+ KdPrint(("OS2SES: Internal error - Exception occured in EventServerThread\n"));
+#endif
+ Ow2DisplayExceptionInfo();
+ ExitThread(1L);
+ }
+ ExitThread(0L);
+ return(0L);
+}
+
+CONST WCHAR OS2SSInitializationEvent[] = U_OS2_SS_INITIALIZATION_EVENT;
+
+/*
+ * OS2 Session console - protocol with OS2SS
+ *
+ * Connect
+ * 1. OS2SES ----------> OS2SRV
+ *
+ *
+ * Accept
+ * 2. OS2SES <---------- OS2SRV
+ * session
+ *
+ *
+ * Create process
+ * (also checkport for root process)
+ * 3. OS2SES ----------> OS2SRV
+ * session
+ *
+ * / Connect
+ * | 4. OS2SES <---------- OS2SRV
+ * root only by |
+ * ServerRequest|
+ * | Accept
+ * | 5. OS2SES ----------> OS2SRV
+ * \
+ *
+ * Returns:
+ * 0L - problem with resources, like memory
+ * -1L - problem connecting to os2srv
+ * 01L - OK
+ *
+ */
+
+DWORD
+InitOs2ssSessionPort()
+{
+ NTSTATUS Status;
+ ULONG ConnectionInfoLen, i, j, ViewSize = 0L;
+ HANDLE SessionUniqueId;
+ OS2SESCONNECTINFO ConnectionInfo;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ LARGE_INTEGER SectionSize;
+ UNICODE_STRING Name_U;
+ HANDLE SectionHandle;
+ HANDLE hCurrentProcess;
+ HANDLE hOs2srvProcess = NULL;
+ PWSTR BasePrefix;
+ PVOID PhyKbd;
+ REMOTE_PORT_VIEW ServerView;
+ PORT_VIEW ClientView;
+ OS2SESREQUESTMSG RequestMsg, ReplyMsg;
+ WCHAR SessionName_U[U_OS2_SES_BASE_PORT_NAME_LENGTH];
+ SECURITY_QUALITY_OF_SERVICE DynamicQos;
+ ULONG Length;
+#if DBG
+ BOOLEAN DebugOnStartup = FALSE;
+#endif
+ HANDLE InitialEventHandle;
+ DWORD NonFirstClient;
+ DWORD WaitState;
+ SECURITY_ATTRIBUTES Sa;
+ CHAR localSecurityDescriptor[SECURITY_DESCRIPTOR_MIN_LENGTH];
+
+ //
+ // Create a section to contain the Port Memory. Port Memory is private
+ // memory that is shared between the OS/2 client and server processes.
+ // This allows data that is too large to fit into an API request message
+ // to be passed to the OS/2 server.
+ //
+ // Create the client section now, to pass is to the server on the
+ // connection request.
+ //
+
+ SectionSize.HighPart = 0L;
+ SectionSize.LowPart = OD2_PORT_MEMORY_SIZE;
+ Status = NtCreateSection( &SectionHandle,
+ SECTION_ALL_ACCESS,
+ NULL,
+ &SectionSize,
+ PAGE_READWRITE,
+ SEC_RESERVE,
+ NULL
+ );
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(( NtInitssFail, Status, "NtCreateSection"));
+ ASSERT( FALSE );
+#endif
+ return( 0L );
+ }
+
+ /*
+ * connect to OS2SS and notify of the new session and the port associated
+ * with it.
+ */
+
+#if DBG
+ if ( fBrkOnStart )
+ {
+ ConnectionInfo.In.SessionDbg = TRUE;
+ } else
+ {
+ ConnectionInfo.In.SessionDbg = FALSE;
+ }
+#else
+ ConnectionInfo.In.SessionDbg = FALSE;
+#endif
+ ConnectionInfo.In.ExpectedVersion = OS2_SS_VERSION;
+ ConnectionInfo.In.Win32ForegroundWindow = Ow2ForegroundWindow;
+ ConnectionInfoLen = sizeof(ConnectionInfo);
+
+ RtlInitUnicodeString( &Name_U, U_OS2_SS_SESSION_PORT_NAME );
+
+ //
+ // Set up the security quality of service parameters to use over the
+ // port. Use the most efficient (least overhead) - which is dynamic
+ // rather than static tracking.
+ //
+
+ DynamicQos.ImpersonationLevel = SecurityImpersonation;
+ DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
+ DynamicQos.EffectiveOnly = TRUE;
+
+ ClientView.Length = sizeof( ClientView );
+ ClientView.SectionHandle = SectionHandle;
+ ClientView.SectionOffset = 0;
+ ClientView.ViewSize = OD2_PORT_MEMORY_SIZE;
+ ClientView.ViewBase = 0;
+ ClientView.ViewRemoteBase = 0;
+
+ ServerView.Length = sizeof( ServerView );
+ ServerView.ViewSize = 0;
+ ServerView.ViewBase = 0;
+
+ // Create security attribute record granting access to all
+ Sa.nLength = sizeof(Sa);
+ Sa.bInheritHandle = TRUE;
+
+ Status = RtlCreateSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION );
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(("OS2SES: failed at RtlCreateSecurityDescriptor %x\n", Status));
+ ASSERT(FALSE);
+#endif
+ return 0L;
+ }
+
+ Status = RtlSetDaclSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ (BOOLEAN)TRUE,
+ (PACL) NULL,
+ (BOOLEAN)FALSE );
+
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(("OS2SES: failed at RtlSetDaclSecurityDescriptor %x\n", Status));
+ ASSERT(FALSE);
+#endif
+ return 0L;
+ }
+ Sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) &localSecurityDescriptor;
+
+ InitialEventHandle = CreateEventW(
+ &Sa,
+ TRUE, // Notification event
+ FALSE, // Nonsignaled
+ OS2SSInitializationEvent
+ );
+ if ((NonFirstClient = GetLastError()) || !InitialEventHandle) {
+ if (NonFirstClient != ERROR_ALREADY_EXISTS) {
+#if DBG
+ KdPrint(("OS2SES: Cannot create initialization event, error %d\n", NonFirstClient));
+#endif
+ return 0L;
+ }
+ }
+
+ if (!NonFirstClient) {
+ Status = (NTSTATUS) CreateOS2SRV(&hOs2srvProcess);
+ if (!NT_SUCCESS(Status) || !hOs2srvProcess) {
+#if DBG
+ KdPrint(("OS2SES: Fail to start server process, status %x\n", Status));
+#endif
+ return 0L;
+ }
+ NtClose(hOs2srvProcess);
+ }
+
+ //
+ // Wait for server. We want to see messages printed in debugger in the case that
+ // client waits too much (or may be it will wait forever).
+ //
+
+ while (TRUE) {
+ WaitState = WaitForSingleObject(
+ InitialEventHandle,
+ (DWORD) 4900L
+ );
+ if (WaitState == STATUS_TIMEOUT) {
+#ifdef DBG
+ KdPrint(("OS2SES: Waiting for server\n"));
+#endif
+ }
+ else {
+ break;
+ }
+ }
+
+ if (WaitState != WAIT_OBJECT_0) {
+#if DBG
+ KdPrint(("OS2SES: Initialization event wasn't set by the server, wait_state %d\n", WaitState));
+#endif
+ return (DWORD) -1L;
+ }
+
+ CloseHandle(InitialEventHandle);
+
+ Status = NtConnectPort(
+ &Ow2hOs2srvPort,
+ &Name_U,
+ &DynamicQos, // Security Quality
+ &ClientView,
+ &ServerView,
+ NULL, // MaxMessageLength,
+ (PVOID) &ConnectionInfo,
+ &ConnectionInfoLen
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("OS2SES: Fail to connect to port, status %x\n", Status));
+#endif
+ return (DWORD) -1L;
+ }
+
+ NtClose( SectionHandle );
+
+ //
+ // Now capture the fact if we were exec'd with the DEBUG command
+ //
+#if DBG
+ if (ConnectionInfo.Out.Od2Debug)
+ {
+ Os2Debug |= ConnectionInfo.Out.Od2Debug;
+ DebugOnStartup = TRUE;
+ }
+#endif
+
+ Od2PortMemoryRemoteDelta = (ULONG)ClientView.ViewRemoteBase -
+ (ULONG)ClientView.ViewBase;
+
+#if DBG
+ IF_OD2_DEBUG( LPC )
+ {
+ KdPrint(( "OS2: ClientView: Base=%lX RemoteBase=%lX Delta: %lX Size=%lX\n",
+ (ULONG)ClientView.ViewBase, (ULONG)ClientView.ViewRemoteBase,
+ Od2PortMemoryRemoteDelta, (ULONG)ClientView.ViewSize
+ ));
+ }
+#endif
+
+ SessionUniqueId = (HANDLE)(ConnectionInfo.Out.SessionUniqueID);
+ Ow2bNewSession = ConnectionInfo.Out.IsNewSession;
+
+ Od2PortHeap = RtlCreateHeap( 0,
+ ClientView.ViewBase,
+ ClientView.ViewSize,
+ 0,
+ 0,
+ 0
+ );
+ if (Od2PortHeap == NULL)
+ {
+#if DBG
+ KdPrint(( NtInitssFail, Status, "RtlCreateHeap"));
+ ASSERT( FALSE );
+#endif
+ return 0L;
+ }
+
+ hOs2Srv = OpenProcess(
+ PROCESS_DUP_HANDLE,
+ FALSE, // no inherit
+ (DWORD)(ConnectionInfo.Out.Os2SrvId));
+ if (!hOs2Srv){
+#if DBG
+ KdPrint(( NtInitssFail, GetLastError(), "OpenProcess"));
+#endif
+ return((DWORD)-1L);
+ }
+
+#if DBG
+ if ( fVerbose )
+ {
+ KdPrint(("OS2SES: id =%d, Unique id=%d\n",
+ ConnectionInfo.Out.ProcessUniqueID, (ULONG)SessionUniqueId));
+ }
+#endif
+
+ CONSTRUCT_U_OS2_SES_NAME(SessionName_U, U_OS2_SES_BASE_PORT_PREFIX, (ULONG)SessionUniqueId);
+ RtlInitUnicodeString( &Name_U, SessionName_U );
+
+ /*
+ * used later to fix to the data section/port name
+ */
+
+ BasePrefix = &Name_U.Buffer[sizeof(U_OS2_SES_BASE_PORT_NAME) / 2];
+
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ PRTL_USER_PROCESS_PARAMETERS ProcessParameters =
+ (NtCurrentPeb())->ProcessParameters;
+
+ KdPrint(( "OS2SES(Win-Handles): hConsole %lx, StdIn %lx, StdOut %lx, StdErr %lx\n",
+ ProcessParameters->ConsoleHandle,
+ ProcessParameters->StandardInput,
+ ProcessParameters->StandardOutput,
+ ProcessParameters->StandardError ));
+ }
+#endif
+
+ /*
+ * Create 7 NT Semaphore and 1 Event that will be used to:
+ *
+ * 1. mutex use of CtrlDataSection
+ * 2. mutex use of KbdDataSection
+ * 3. focus the Kbd-handle
+ * 4. mutex enable PopUp
+ * 5. mutex screen lock
+ * 6. Pause event
+ * 7. mutex read Mouse Event
+ */
+
+ for ( i = 0, j = 0 ; SEMAPHORE_TABLE[i].NamePrefix ;)
+ {
+ *BasePrefix = SEMAPHORE_TABLE[i].NamePrefix;
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &Name_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ if ( OS2SS_IS_SESSION( Ow2bNewSession ))
+ {
+ if (*BasePrefix == U_OS2_SES_PAUSE_EVENT_PREFIX)
+ {
+ Status = NtCreateEvent( SEMAPHORE_TABLE[i].SemaphoreHandle,
+ EVENT_ALL_ACCESS,
+ &ObjectAttributes,
+ 1,
+ (BOOLEAN)1);
+ } else if ((*BasePrefix == U_OS2_SES_VIOWRITE_SEMAPHORE_PREFIX) ||
+ (*BasePrefix == U_OS2_SES_KBD_PORT_SEMAPHORE_PREFIX) ||
+ (*BasePrefix == U_OS2_SES_MOU_PORT_SEMAPHORE_PREFIX))
+ {
+ Status = NtCreateMutant( SEMAPHORE_TABLE[i].SemaphoreHandle,
+ MUTANT_ALL_ACCESS,
+ &ObjectAttributes,
+ FALSE); // not owned
+ } else
+ {
+ Status = NtCreateSemaphore( SEMAPHORE_TABLE[i].SemaphoreHandle,
+ SEMAPHORE_ALL_ACCESS,
+ &ObjectAttributes,
+ 1,
+ 1);
+ }
+ } else
+ {
+ if (*BasePrefix == U_OS2_SES_PAUSE_EVENT_PREFIX)
+ {
+ Status = NtOpenEvent( SEMAPHORE_TABLE[i].SemaphoreHandle,
+ EVENT_ALL_ACCESS,
+ &ObjectAttributes);
+ } else if ((*BasePrefix == U_OS2_SES_VIOWRITE_SEMAPHORE_PREFIX) ||
+ (*BasePrefix == U_OS2_SES_KBD_PORT_SEMAPHORE_PREFIX) ||
+ (*BasePrefix == U_OS2_SES_MOU_PORT_SEMAPHORE_PREFIX))
+ {
+ Status = NtOpenMutant( SEMAPHORE_TABLE[i].SemaphoreHandle,
+ MUTANT_ALL_ACCESS,
+ &ObjectAttributes);
+ } else
+ {
+ Status = NtOpenSemaphore( SEMAPHORE_TABLE[i].SemaphoreHandle,
+ SEMAPHORE_ALL_ACCESS,
+ &ObjectAttributes);
+ }
+ }
+
+ if ( ! NT_SUCCESS( Status ) )
+ {
+ if (i==0 && OS2SS_IS_SESSION( Ow2bNewSession ) &&
+ Status == STATUS_OBJECT_NAME_COLLISION )
+ {
+ //
+ // A previous sesssion with the same cookie is being cleaned up - wait
+ // 30 seconds (600 times 50 ms is 30 seconds)
+ //
+ j++;
+ if (j<600)
+ {
+#if DBG
+ if (j == 1)
+ {
+ KdPrint(( "OS2SES(ntinitss) - waiting for previous os2 session cleanup\n"));
+ }
+ else {
+ KdPrint(( "."));
+
+ }
+#endif
+ Sleep(50L);
+ continue;
+ }
+
+ }
+#if DBG
+ KdPrint(( "OS2SES(ntinitss) - error %X at NtCreate/OpenSemaphore/Event #%u (%c-%s)\n",
+ Status, i, SEMAPHORE_TABLE[i].NamePrefix, SEMAPHORE_NAME_TABLE[i]));
+ ASSERT( FALSE );
+#endif
+ return(0L);
+ }
+ //
+ // increment i only if the create/open above was successful
+ //
+ i++;
+ }
+
+ /*
+ * Map the the whole section to virtual address.
+ * Let MM locate the view.
+ *
+ * The Vio case is different, since it has to be mapped
+ * into app space below 512M
+ */
+
+ Os2SessionCtrlDataBaseAddress = 0L;
+ Os2SessionDataBaseAddress = 0L;
+ LVBBuffer = (PUCHAR)(VIOSECTION_BASE);
+
+ for ( i = 0 ; PORT_TABLE[i].SectionSize ; i++ )
+ {
+
+ /*
+ * create 3 sections to be shared by all client processes runing in this
+ * session: Ctrl, SesGrp & LVB.
+ */
+
+ //
+ // Only for LVB the section size is unknon until OS2 is started.
+ // For the LVB< there is -1 at the SectionSize field in the table
+ //
+
+ if ( PORT_TABLE[i].SectionSize != -1L )
+ {
+ SectionSize.LowPart = PORT_TABLE[i].SectionSize;
+ } else
+ {
+ //
+ // This is the time to continue initiliziation: SesGrp
+ // is available.
+ //
+
+ SesGrp = (POS2_SES_GROUP_PARMS)Os2SessionDataBaseAddress;
+ PortMessageHeaderSize = sizeof(PORT_MESSAGE);
+
+ if (OS2SS_IS_PROCESS( Ow2bNewSession ))
+ {
+ if ((PhyKbd = StartEventHandler()) == NULL)
+ {
+ return(0);
+ }
+ } else
+ {
+ RtlZeroMemory(SesGrp, sizeof(OS2_SES_GROUP_PARMS));
+ if ((PhyKbd = StartEventHandlerForSession()) == NULL)
+ {
+ return(0);
+ }
+ SesGrp->PhyKbd = PhyKbd;
+ }
+ SectionSize.LowPart = SesGrp->MaxLVBsize; // LVB Buffer
+ }
+
+ ViewSize = 0L;
+
+ /*
+ * Get a private ID for the session data.
+ */
+
+ *BasePrefix = PORT_TABLE[i].DataNamePrefix;
+
+ /*
+ * create a 64k section.
+ * BUGBUG! - cruiser apis allow io of more then 64k
+ */
+
+ if (OS2SS_IS_SESSION( Ow2bNewSession ))
+ {
+ SECURITY_DESCRIPTOR SecurityDescriptor;
+
+ Status = RtlCreateSecurityDescriptor( &SecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(( NtInitssFail, Status, "RtlCreateSecurityDescriptor"));
+ ASSERT( FALSE );
+#endif
+ return(0L);
+ }
+
+ Status = RtlSetDaclSecurityDescriptor( &SecurityDescriptor,
+ TRUE,
+ NULL,
+ FALSE );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(( NtInitssFail, Status, "RtlSetDaclSecurityDescriptor"));
+ ASSERT(FALSE);
+#endif
+ return(0L);
+ }
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &Name_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ &SecurityDescriptor);
+
+ Status = NtCreateSection ( &SectionHandle,
+ /* BUGBUG! SECTION_ALL_ACCESS, */ SECTION_MAP_WRITE,
+ &ObjectAttributes,
+ &SectionSize,
+ PAGE_READWRITE,
+ SEC_COMMIT,
+ NULL);
+ } else
+ {
+ InitializeObjectAttributes(&ObjectAttributes,
+ &Name_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenSection ( &SectionHandle,
+ SECTION_MAP_WRITE,
+ &ObjectAttributes);
+
+ }
+
+ if ( !NT_SUCCESS( Status ) )
+ {
+#if DBG
+ KdPrint(( NtInitssFail, Status, "NtCreate/OpenSection"));
+ ASSERT( FALSE );
+#endif
+ return(0L);
+ }
+
+ //
+ // Map the the whole section to virtual address.
+ //
+
+ Status = NtMapViewOfSection( SectionHandle,
+ NtCurrentProcess(),
+ PORT_TABLE[i].SectionDataBaseAddress,
+ 0L,
+ 0L,
+ NULL,
+ &ViewSize,
+ ViewUnmap,
+ 0L,
+ PAGE_READWRITE);
+
+ if ( !NT_SUCCESS( Status ) )
+ {
+#if DBG
+ KdPrint(( NtInitssFail, Status, "NtMapViewOfSection"));
+ ASSERT( FALSE );
+#endif
+ return(0L);
+ }
+
+ *(PORT_TABLE[i].SectionDataHandle) = SectionHandle;
+ }
+
+ OpenLVBsection();
+
+ Ow2hOs2sesPort = NULL;
+
+ //
+ // Connect to the OS/2 Emulation Subsystem server. Also pass information
+ // the OS/2 server needs in the connection information structure.
+ //
+
+ /*
+ * Set Header info
+ */
+
+ PORT_MSG_DATA_LENGTH(RequestMsg) = sizeof(RequestMsg) - sizeof(PORT_MESSAGE);
+ PORT_MSG_TOTAL_LENGTH(RequestMsg) = sizeof(RequestMsg); // BUGBUG! too much
+ PORT_MSG_ZERO_INIT(RequestMsg) = 0L;
+
+ RequestMsg.PortType = 1;
+ RequestMsg.Request = SesConCreate;
+ RequestMsg.d.Create.d.In.IsNewSession = Ow2bNewSession;
+
+ if ( !Od2InitCreateProcessMessage(&RequestMsg.d.Create) )
+ {
+#if DBG
+ KdPrint(( NtInitssFail, Status, "Od2InitCreateProcessMessage"));
+#endif
+ return(0L);
+ }
+
+ /*
+ * for all request pass the session handle
+ */
+
+ RequestMsg.Session = SessionUniqueId;
+
+ strncpy(&RequestMsg.d.Create.d.In.ApplName[0],
+ Od2PgmFilePath,
+ OS2_MAX_APPL_NAME
+ );
+ RequestMsg.d.Create.d.In.ApplName[OS2_MAX_APPL_NAME - 1] = '\0';
+
+ // server doesn't need the LPC, except for
+ // the root process in the session, so we'll create port only for it.
+
+ if (OS2SS_IS_SESSION( Ow2bNewSession ))
+ {
+ CHAR sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
+ PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR)&sd;
+
+ *BasePrefix = U_OS2_SES_BASE_PORT_PREFIX;
+
+ /*
+ * create (session) LPC port to be connected to all client processes
+ * runing in this session for Kbd, Mou, Mon, Tm and Prt.
+ */
+
+ InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
+ SetSecurityDescriptorDacl(psd, TRUE, NULL, FALSE); // NULL DACL means access free to all
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &Name_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ psd);
+
+ Status = NtCreatePort( &Ow2hOs2sesPort,
+ &ObjectAttributes,
+ sizeof( SCCONNECTINFO ),
+ U_OS2_SES_BASE_PORT_PREFIX,
+ 32 * U_OS2_SES_BASE_PORT_PREFIX);
+
+ if ( ! NT_SUCCESS( Status ) )
+ {
+#if DBG
+ KdPrint(( NtInitssFail, Status, "NtCreatePort"));
+ ASSERT( FALSE );
+#endif
+ return(0L);
+ }
+
+ //
+ // create 2 threads: one to read input from console
+ // and second to server requsets thru LPC
+ //
+
+ if (timing)
+ {
+ printf("Os2 time before CreateServerThreads is %d\n", (GetTickCount()) - timing);
+ }
+ if (CreateServerThreads())
+ {
+#if DBG
+ KdPrint(( NtInitssFail, GetLastError(), "CreateServerThread"));
+ ASSERT( FALSE );
+#endif
+ return(0L);
+ }
+
+ /*
+ * Set request info
+ */
+
+ RequestMsg.Request = SesCheckPortAndConCreate;
+
+ //
+ // duplicate handles for os2srv,
+ //
+
+ if (timing)
+ {
+ printf("Os2 time before DuplicateHandle is %d\n", (GetTickCount()) - timing);
+ }
+ hCurrentProcess = GetCurrentProcess();
+ //
+ // duplicate process and thread handles for os2srv
+ //
+
+ if (OS2SS_IS_NEW_SESSION( Ow2bNewSession ))
+ {
+ /*
+ * a new session, which isn't a child session
+ */
+
+ if (!DuplicateHandle(
+ hCurrentProcess,
+ hCurrentProcess,
+ hOs2Srv,
+ &RequestMsg.d.Create.d.In.hProcess,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS
+ ))
+ {
+#if DBG
+ KdPrint(( NtInitssFail, GetLastError(), "DuplicateHandle(Process)"));
+#endif
+ }
+ if (!DuplicateHandle(
+ hCurrentProcess,
+ GetCurrentThread(),
+ hOs2Srv,
+ &RequestMsg.d.Create.d.In.hThread,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS
+ ))
+ {
+#if DBG
+ KdPrint(( NtInitssFail, GetLastError(), "DuplicateHandle(Thread)"));
+#endif
+ }
+ }
+ //
+ // Duplicate the event thread handle, so os2srv can debug it
+ //
+ if (!DuplicateHandle(
+ hCurrentProcess,
+ EventServerThreadHandle,
+ hOs2Srv,
+ &RequestMsg.d.Create.d.In.hEventThread,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS
+ ))
+ {
+#if DBG
+ KdPrint(( NtInitssFail, GetLastError(), "DuplicateHandle(EventServerThread)"));
+#endif
+ }
+ //
+ // Duplicate the session request thread handle, so os2srv can debug it
+ //
+ if (!DuplicateHandle(
+ hCurrentProcess,
+ Ow2hSessionRequestThread,
+ hOs2Srv,
+ &RequestMsg.d.Create.d.In.hSessionRequestThread,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS
+ ))
+ {
+#if DBG
+ KdPrint(( NtInitssFail, GetLastError(), "DuplicateHandle(SessionRequestTread)"));
+#endif
+ }
+ }
+
+ Status = NtRequestWaitReplyPort( Ow2hOs2srvPort,
+ (PPORT_MESSAGE) &RequestMsg,
+ (PPORT_MESSAGE) &ReplyMsg);
+
+ if ( !NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(( NtInitssFail, Status, "NtRequestWaitReplyPort"));
+ ASSERT( FALSE );
+#endif
+ return((DWORD)-1L );
+ }
+
+ if (!NT_SUCCESS(ReplyMsg.Status)){
+ //
+ // Could not initiate with os2srv - exit
+ //
+#if DBG
+ KdPrint(( NtInitssFail, ReplyMsg.Status, "Os2ConCreate"));
+#endif
+ return( (DWORD)-1L );
+ }
+
+ //
+ // Now capture the fact if we were exec'd with the DEBUG command
+ //
+#if DBG
+ if (DebugOnStartup)
+ {
+ DbgBreakPoint();
+ }
+#endif
+
+ Od2HandleCreateProcessRespond(&ReplyMsg.d.Create);
+
+ Ow2hSession = SessionUniqueId;
+
+ if (OS2SS_IS_SESSION( Ow2bNewSession ))
+ {
+ /*
+ * Complete all initializations that are depend on SesGrp from os2srv
+ */
+
+ if (timing)
+ {
+ printf("Os2 time before KbdInitAfterSesGrp is %d\n", (GetTickCount()) - timing);
+ }
+ if( KbdInitAfterSesGrp() )
+ {
+#if DBG
+ KdPrint(( NtInitssFail, GetLastError(), "KbdInitAfterSesGrp"));
+ ASSERT( FALSE );
+#endif
+ return( 0L );
+ }
+
+ /*
+ * Complete NLS initialization
+ */
+
+ if (timing)
+ {
+ printf("Os2 time before NlsInit is %d\n", (GetTickCount()) - timing);
+ }
+ if( NLSInit() )
+ {
+#if DBG
+ KdPrint(( NtInitssFail, GetLastError(), "NlsInit"));
+ ASSERT( FALSE );
+#endif
+ return( 0L );
+ }
+
+ //
+ // resume remaining threads
+ //
+
+ if (timing)
+ {
+ printf("Os2 time before ResumeServerThreads is %d\n", (GetTickCount()) - timing);
+ }
+ if (ResumeServerThreads())
+ {
+#if DBG
+ KdPrint(( NtInitssFail, GetLastError(), "ReleaseServerThreads"));
+ ASSERT( FALSE );
+#endif
+ return( 0L );
+ }
+ }
+
+ Length = SesGrp->LVBsize;
+ Ow2VioGetLVBBuf(&Length);
+
+ /*
+ * Don't put parameters into SesGrp before this point
+ * (since it's clear by the server when coping the NLS definitions).
+ */
+
+ return ( 1L );
+}
+
+
+VOID TerminateSession(VOID)
+{
+ //NTSTATUS Status;
+
+ Ow2ExitInProcess = (BOOLEAN)TRUE;
+ if (timing)
+ {
+ printf("Os2 main->Exit time is %d\n", (GetTickCount()) - timing);
+ }
+
+ /*
+ * remove event handler so we don't try to send a message
+ * for a dying session.
+ */
+
+ SetEventHandlers( FALSE );
+
+ if (OS2SS_IS_SESSION( Ow2bNewSession ))
+ {
+ RestoreWin32ParmsBeforeTermination();
+ }
+
+ // Close the named objects: port, section
+
+ NtClose(Ow2hOs2srvPort);
+ NtClose(Os2SessionCtrlDataSectionHandle);
+ NtClose(Os2SessionSesGrpDataSectionHandle);
+ NtClose(Ow2hOs2sesPort);
+ NtClose(hOs2Srv);
+ // Jul-2-1995 YosefD:
+ // Od2PortHandle is the same value as Ow2hOs2srvPort. This handle is already closed. An
+ // attemt to close it once more is a bug. On build 1096 this cause exception and
+ // process termination. The return value of the terminated process isn't right in this
+ // case.
+ //NtClose(Od2PortHandle);
+
+ /* =>? what about the following handles:
+
+HANDLE hConsoleInput;
+HANDLE hConsoleOutput;
+HANDLE hConsoleStdIn; if diff from hConsoleInput
+HANDLE hConsoleStdOut; if diff from hConsoleOutput
+HANDLE hConsoleStdErr;
+HANDLE hPopUpOutput; if not NULL
+HANDLE LVBHandle;
+HANDLE PauseEvent;
+HANDLE CtrlDataSemaphore;
+HANDLE KbdDataSemaphore;
+HANDLE FocusSemaphore;
+HANDLE MouDataSemaphore;
+HANDLE PopUpSemaphore;
+HANDLE ScreenLockSemaphore;
+HANDLE EventServerThreadHandle;
+HANDLE Ow2hSessionRequestThread;
+
+ */
+ // notify OS2SS
+
+ // Cleanup TaskMan stuff
+
+}
+
+
+BOOL
+SendSignalToOs2Srv(
+ IN int SignalType
+ )
+{
+ OS2SESREQUESTMSG RequestMsg;
+ OS2SESREQUESTMSG ReplyMsg;
+ NTSTATUS Status;
+
+#if DBG
+ IF_OD2_DEBUG2( OS2_EXE, SIG )
+ {
+ KdPrint(("OS2SES(SendSignalToOs2Srv): Signal %u\n", SignalType));
+ }
+#endif
+ /*
+ * Set Header info
+ */
+ PORT_MSG_DATA_LENGTH(RequestMsg) = sizeof(RequestMsg) - sizeof(PORT_MESSAGE);
+ PORT_MSG_TOTAL_LENGTH(RequestMsg) = sizeof(RequestMsg); // BUGBUG! too much
+ PORT_MSG_ZERO_INIT(RequestMsg) = 0L;
+ RequestMsg.PortType = 1;
+
+ RequestMsg.Request = SesConSignal;
+ RequestMsg.Session = Ow2hSession;
+ RequestMsg.d.Signal.Type = SignalType;
+
+ Status = NtRequestWaitReplyPort( Ow2hOs2srvPort,
+ (PPORT_MESSAGE) &RequestMsg,
+ (PPORT_MESSAGE) &ReplyMsg);
+
+ if ( !NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(( "OS2SES: Unable to send signal - Status == %X\n",
+ Status));
+#endif
+
+ TerminateSession();
+ Ow2Exit(0, NULL, 15);
+ }
+
+ ASSERT ( PORT_MSG_TYPE(ReplyMsg) == LPC_REPLY );
+
+ if ( Ow2ExitInProcess )
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL
+EventHandlerRoutine (IN ULONG CtrlType)
+{
+ int SignalType;
+ BOOL Rc;
+ ULONG i=0;
+
+ //
+ // If Ow2hSession is null - os2srv is not ready yet to kill,
+ // wait so we don't loose the signal
+ //
+
+ if (!Od2SignalEnabled)
+ {
+#if DBG
+ IF_OD2_DEBUG2( OS2_EXE, SIG )
+ {
+ KdPrint(("OS2SES(EventHandlerRoutine): Ctr-Type %u before loading completed, handle later\n", CtrlType));
+ }
+#endif
+ Od2ReceivedSignalAtInit = TRUE;
+ Od2InitSignalType = CtrlType;
+ return(TRUE);
+ }
+
+#if DBG
+ IF_OD2_DEBUG2( OS2_EXE, SIG )
+ {
+ KdPrint(("OS2SES(EventHandlerRoutine): Ctr-Type %u\n", CtrlType));
+ }
+#endif
+
+ switch (CtrlType) {
+ case CTRL_C_EVENT:
+ if ((SesGrp->ModeFlag & 1 ) || // ^C in binary mode
+ SesGrp->WinProcessNumberInSession ) // There is a child Win process
+ {
+ return (TRUE);
+ }
+ SignalType = XCPT_SIGNAL_INTR;
+ break;
+ case CTRL_BREAK_EVENT:
+ if (SesGrp->WinProcessNumberInSession ) // There is a child Win process
+ {
+ return (TRUE);
+ }
+ SignalType = XCPT_SIGNAL_BREAK;
+ break;
+ case CTRL_CLOSE_EVENT:
+ SignalType = XCPT_SIGNAL_KILLPROC;
+#if PMNT
+CloseApp:
+ //
+ // PM apps handling
+ //
+ if (ProcessIsPMProcess())
+ {
+ // Regular app (i.e. not PMShell)
+ if (!ProcessIsPMShell())
+ {
+ if (Ow2WriteBackCloseEvent())
+ {
+ Sleep(7900L);
+ if (Ow2ExitInProcess)
+ return(FALSE);
+ else
+ return(TRUE);
+ }
+ else
+ {
+ // We failed to write-back a close event:
+ // must be DosExecPgm proc; Pass event through semaphore
+ DosSemClear(PMSubprocSem32);
+ Sleep(7900L);
+ if (Ow2ExitInProcess)
+ return(FALSE);
+ else
+ return(TRUE);
+ }
+ return(TRUE);
+ }
+ else // PMSHELL
+ {
+ if (Ow2WriteBackCloseEvent())
+ {
+ return(TRUE);
+ }
+ }
+ }
+#endif // PMNT
+ break;
+ case CTRL_LOGOFF_EVENT:
+ if (fService) // Are we running as a service ?
+ {
+#if DBG
+ DbgPrint("OS2: service - ignoring CTRL_LOGOFF_EVENT !\n");
+#endif
+ return FALSE;
+ }
+ SignalType = XCPT_SIGNAL_KILLPROC;
+#if PMNT
+ // Jump to CloseApp only for PM apps !
+ if (ProcessIsPMProcess())
+ goto CloseApp;
+#endif // PMNT
+ break;
+ case CTRL_SHUTDOWN_EVENT:
+ SignalType = XCPT_SIGNAL_KILLPROC;
+#if PMNT
+ // Jump to CloseApp only for PM apps !
+ if (ProcessIsPMProcess())
+ goto CloseApp;
+#endif // PMNT
+ break;
+ default:
+#if DBG
+ IF_OD2_DEBUG2( OS2_EXE, SIG )
+ {
+ KdPrint(("OS2SES(EventHandlerRoutine): Unknown CtrlType %lu\n", CtrlType));
+ }
+#endif
+ SignalType = CtrlType;
+ break;
+ }
+ //if (OS2SS_IS_SESSION( Ow2bNewSession )){
+ if (SesGrp->InTermination == 0){
+
+ //
+ // The root process of a session handles singals with os2srv
+ // always. child processes in the session only need to send
+ // the signal if they where in initialization when a CtrlC/CtrlBrk
+ // happened (server ignore signal in this case)
+ //
+
+ Rc = SendSignalToOs2Srv(SignalType);
+ } else{
+ Rc = TRUE;
+ }
+
+ if (Rc && ((CtrlType == CTRL_CLOSE_EVENT) ||
+ (CtrlType == CTRL_LOGOFF_EVENT) ||
+ (CtrlType == CTRL_SHUTDOWN_EVENT)))
+ {
+ //
+ // Cmd wait 10 sec before it popup a time-out fail message
+ // We are waiting 5 sec to give the application (client)
+ // time to clean-up before we return TRUE.
+
+ Sleep(5000);
+ if ( Ow2ExitInProcess )
+ {
+ Rc = FALSE;
+ }
+ } else if (Rc && SesGrp->InTermination && Od2SignalEnabled) {
+ Rc = SendSignalToOs2Srv(SignalType);
+ }
+
+ return (Rc);
+}
+
+
+ULONG
+Ow2GetProcessIdFromLPCMessage(
+ IN PVOID LPCMessage
+ )
+{
+ return((ULONG) ((PPORT_MESSAGE)LPCMessage)->ClientId.UniqueProcess);
+}
+
+
+DWORD
+Ow2CommandLineWToCommandLineA(
+ IN LPWSTR CommandLineW,
+ OUT PSZ *CommandLineA
+ )
+{
+ UNICODE_STRING CommandLine_U;
+ UNICODE_STRING CommandLineUpcase;
+ UNICODE_STRING CurrentDir_U;
+ UNICODE_STRING CurrentDirUpcase;
+ WCHAR CurrentDirectory[MAX_PATH];
+ WCHAR *pWchar;
+ NTSTATUS Status;
+
+ RtlInitUnicodeString(
+ &CommandLine_U,
+ CommandLineW
+ );
+
+ if (GetCurrentDirectoryW((DWORD)MAX_PATH, CurrentDirectory))
+ {
+ RtlInitUnicodeString(
+ &CurrentDir_U,
+ CurrentDirectory
+ );
+
+ //
+ // Prepare the structures for upcase strings and then upcase.
+ //
+ if (NULL == (CommandLineUpcase.Buffer =
+ RtlAllocateHeap(RtlProcessHeap(), 0, CommandLine_U.MaximumLength))) {
+ KdPrint(( NtInitssFail, 0, "RtlAllocateHeap(CommandLine)"));
+ return ((DWORD)-1L);
+ }
+ if (NULL == (CurrentDirUpcase.Buffer =
+ RtlAllocateHeap(RtlProcessHeap(), 0, CurrentDir_U.MaximumLength))) {
+ KdPrint(( NtInitssFail, 0, "RtlAllocateHeap(CurrentDir)"));
+ RtlFreeHeap(RtlProcessHeap(), 0, CommandLineUpcase.Buffer);
+ return ((DWORD)-1L);
+ }
+
+ CurrentDirUpcase.Length = CurrentDir_U.Length;
+ CurrentDirUpcase.MaximumLength = CurrentDir_U.MaximumLength;
+ Status = RtlUpcaseUnicodeString(&CurrentDirUpcase, &CurrentDir_U, FALSE);
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(( NtInitssFail, 0, "RtlUpcaseUnicodeString(CurrentDirUpcase)"));
+ RtlFreeHeap(RtlProcessHeap(), 0, CommandLineUpcase.Buffer);
+ RtlFreeHeap(RtlProcessHeap(), 0, CurrentDirUpcase.Buffer);
+ return ((DWORD)-1L);
+ }
+
+ CommandLineUpcase.Length = CommandLine_U.Length;
+ CommandLineUpcase.MaximumLength = CommandLine_U.MaximumLength;
+ Status = RtlUpcaseUnicodeString(&CommandLineUpcase, &CommandLine_U, FALSE);
+ if (!NT_SUCCESS(Status)) {
+ KdPrint(( NtInitssFail, 0, "RtlUpcaseUnicodeString(CommandLineUpcase)"));
+ RtlFreeHeap(RtlProcessHeap(), 0, CommandLineUpcase.Buffer);
+ RtlFreeHeap(RtlProcessHeap(), 0, CurrentDirUpcase.Buffer);
+ return ((DWORD)-1L);
+ }
+
+ //
+ // Initialize pWchar and append NULL to the end of the upcased strings
+ // for the search of wsstr().
+ //
+ pWchar = CommandLineUpcase.Buffer;
+ CurrentDirUpcase.Buffer[CurrentDirUpcase.Length / 2] = (WCHAR)NULL;
+ CommandLineUpcase.Buffer[CommandLineUpcase.Length / 2] = (WCHAR)NULL;
+
+ //
+ // Replace every prefix of the current directory in the command
+ // line with what GetCurrentDirectoryW() returned. This resolves
+ // problems caused by apps transfering the command line in
+ // apper/lower case.
+ //
+ while ((pWchar < &CommandLineUpcase.Buffer[CommandLineUpcase.Length / 2]) &&
+ (pWchar = wcsstr(pWchar, CurrentDirUpcase.Buffer))) {
+ wcsncpy(&CommandLine_U.Buffer[pWchar - CommandLineUpcase.Buffer],
+ CurrentDirectory,
+ CurrentDirUpcase.Length / 2);
+ pWchar += CurrentDirUpcase.Length / 2;
+ }
+
+ //
+ // Free the allocated buffers.
+ //
+ RtlFreeHeap(RtlProcessHeap(), 0, CommandLineUpcase.Buffer);
+ RtlFreeHeap(RtlProcessHeap(), 0, CurrentDirUpcase.Buffer);
+ }
+
+ Status = RtlUnicodeStringToOemString(
+ &Ow2CommandLineString,
+ &CommandLine_U,
+ TRUE
+ );
+ if (!NT_SUCCESS( Status ))
+ {
+ KdPrint(( NtInitssFail, Status, "CommandLine-UnicodeToOemString"));
+ return ((DWORD)-1L);
+ }
+
+ *CommandLineA = Ow2CommandLineString.Buffer;
+
+ return(0L);
+}
+#if PMNT
+
+
+// Returns true if process is the root process of a session
+// otherwise returns false
+// This procedure was written to enable 16 Bit dll init routine (PMWIN)
+// to check if the it is executed from the root process of a session.
+APIRET PMNTIsSessionRoot()
+{
+
+ if ( OS2SS_IS_SESSION( Ow2bNewSession ))
+ return(TRUE);
+ else
+ return(FALSE);
+}
+
+#endif // PMNT
diff --git a/private/os2/os2ses/ntrqust.c b/private/os2/os2ses/ntrqust.c
new file mode 100644
index 000000000..d0955428d
--- /dev/null
+++ b/private/os2/os2ses/ntrqust.c
@@ -0,0 +1,402 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ntrqust.c
+
+Abstract:
+
+ This module contains the session requests threads and the listen threads.
+
+Author:
+
+ Avi Nathan (avin) 17-Jul-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include "string.h"
+#include <stdlib.h>
+#define NTOS2_ONLY
+#include "os2ses.h"
+
+
+VOID ServeSessionRequests(VOID)
+{
+
+ SCREQUESTMSG ReceiveMsg, *PReplyMsg;
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL fCont=TRUE;
+ ULONG Reply;
+
+ PReplyMsg = NULL;
+
+ for ( ; Status != STATUS_INVALID_HANDLE ; )
+ {
+ if ( fCont )
+ {
+ Status = NtReplyWaitReceivePort(Ow2hOs2sesPort,
+ NULL,
+ (PPORT_MESSAGE) PReplyMsg,
+ (PPORT_MESSAGE) &ReceiveMsg);
+
+#if DBG
+ IF_OD2_DEBUG( LPC )
+ {
+ KdPrint(("OS2SES: NtRequst: Msg %u, Request %u (%u), Status %lx\n",
+ PORT_MSG_TYPE(ReceiveMsg), ReceiveMsg.Request,
+ ReceiveMsg.d.Kbd.Request, Status));
+ } else if (!NT_SUCCESS(Status))
+ {
+ KdPrint(("OS2SES: NtRequst: Msg %u, Request %u, Status %lx\n",
+ PORT_MSG_TYPE(ReceiveMsg), ReceiveMsg.Request, Status));
+ }
+#endif
+ } else
+ {
+#if 0
+ Status = NtReplyPort(Ow2hOs2sesPort,
+ (PPORT_MESSAGE) PReplyMsg);
+#endif
+ }
+
+#if DBG
+ if ( fTrace )
+ {
+ _asm int 3;
+ }
+#endif
+
+ if (!NT_SUCCESS(Status)) {
+ PReplyMsg = NULL;
+ continue;
+ }
+
+ if ( PORT_MSG_TYPE(ReceiveMsg) == LPC_PORT_CLOSED )
+ {
+ break;
+ }
+
+ if ( !fCont )
+ {
+ break;
+ }
+
+ Reply = 1;
+
+ try
+ {
+ switch ( ReceiveMsg.Request)
+ {
+ case MouRequest:
+ fCont = ServeMouRequest( &ReceiveMsg.d.Mou,
+ &ReceiveMsg.Status,
+ (PVOID)&ReceiveMsg,
+ &Reply);
+ break;
+
+ case MonRequest:
+ fCont = ServeMonRequest( &ReceiveMsg.d.Mon,
+ &ReceiveMsg.Status,
+ (PVOID)&ReceiveMsg,
+ &Reply);
+ break;
+
+ case KbdRequest:
+ fCont = ServeKbdRequest( &ReceiveMsg.d.Kbd,
+ &ReceiveMsg.Status,
+ (PVOID)&ReceiveMsg,
+ &Reply);
+ break;
+
+ case PrtRequest:
+ fCont = ServePrtRequest( &ReceiveMsg.d.Prt,
+ &ReceiveMsg.Status);
+ break;
+
+ case TaskManRequest:
+ fCont = ServeTmRequest( &ReceiveMsg.d.Tm,
+ &ReceiveMsg.Status);
+ if (ReceiveMsg.d.Tm.Request == TmReleaseLPC) {
+ Reply = 0;
+ }
+ break;
+
+ case WinCreateProcess:
+ fCont = ServeWinCreateProcess( &ReceiveMsg.d.WinExecPgm,
+ &ReceiveMsg.Status
+ );
+ break;
+
+ default:
+#if DBG
+ KdPrint(( "OS2SES: Unknown NT request = %X\n",
+ ReceiveMsg.Request));
+#endif
+ break;
+ }
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+#if DBG
+ KdPrint(("OS2SES: Exception in request server thread, terminating\n"));
+#endif
+ NtTerminateProcess(NtCurrentProcess(), Status);
+ // BUGBUG! The client should kill the process
+ }
+
+#if DBG
+ IF_OD2_DEBUG( LPC )
+ {
+ KdPrint(("OS2SES: NtRequst: Msg %u, Reply %s, Status %lx\n",
+ PORT_MSG_TYPE(ReceiveMsg), (Reply) ? "Yes" : "No",
+ ReceiveMsg.Status));
+ }
+#endif
+ if (Reply)
+ {
+ PReplyMsg = &ReceiveMsg;
+ } else
+ PReplyMsg = NULL;
+ }
+ Ow2Exit(0, NULL, Os2ReturnCode);
+}
+
+
+VOID
+SavePortMessegeInfo(OUT PVOID MonHeader,
+ IN PVOID pMsg)
+{
+ RtlMoveMemory(MonHeader,
+ pMsg,
+ sizeof(PORT_MESSAGE));
+}
+
+
+VOID
+SaveKbdPortMessegeInfo(OUT PVOID MonHeader,
+ OUT PVOID KbdRequestArea,
+ IN PVOID pMsg)
+{
+ RtlMoveMemory(MonHeader,
+ pMsg,
+ sizeof(PORT_MESSAGE));
+ RtlMoveMemory(KbdRequestArea,
+ &((PSCREQUESTMSG)pMsg)->d.Kbd,
+ sizeof(KBDREQUEST));
+}
+
+
+VOID
+SendMonReply(IN PVOID MonHeader,
+ IN PVOID pData,
+ IN USHORT Length)
+{
+ SCREQUESTMSG SendMsg;
+ NTSTATUS Status;
+
+ RtlMoveMemory(&SendMsg,
+ MonHeader,
+ sizeof(PORT_MESSAGE));
+
+ if ( pData )
+ {
+ SendMsg.Status = 0L;
+ RtlMoveMemory((PVOID)&(SendMsg.d.Mon.d.rwParms.ioBuff[0]), pData, Length);
+ } else
+ {
+ /*
+ * This call is from EventReleaseLPC
+ * return -2 to terminate thread
+ */
+
+ SendMsg.Status = -2L;
+ RtlZeroMemory((PVOID)&(SendMsg.d.Mon.d.rwParms.ioBuff[0]), Length);
+ }
+
+ SendMsg.Request = MonRequest;
+ SendMsg.d.Mon.Request = MONRead;
+ SendMsg.d.Mon.d.rwParms.Length = Length;
+
+ Status = NtReplyPort(Ow2hOs2sesPort,
+ (PPORT_MESSAGE) &SendMsg);
+
+ if ( !NT_SUCCESS( Status ) )
+ {
+#if DBG
+ IF_OD2_DEBUG2( MON, OS2_EXE )
+ /* KdPrint(("OS2SES(NtRqust-SendMonReply): fail to send reply\n")) */;
+#endif
+ }
+}
+
+
+VOID
+SendMouReply(IN PVOID MonHeader,
+ IN PVOID pData)
+{
+ SCREQUESTMSG SendMsg;
+ NTSTATUS Status;
+
+ RtlMoveMemory(&SendMsg,
+ MonHeader,
+ sizeof(PORT_MESSAGE));
+
+ if ( pData )
+ {
+ SendMsg.Status = 0L;
+ SendMsg.d.Mou.d.MouInfo = *(PMOUEVENTINFO)pData;
+ } else
+ {
+ /*
+ * This call is from EventReleaseLPC
+ * return -2 to terminate thread
+ */
+
+ SendMsg.Status = -2L;
+ RtlZeroMemory((PVOID)&SendMsg.d.Mou.d.MouInfo, sizeof(MOUEVENTINFO));
+ }
+
+ SendMsg.d.Mou.Request = MOUReadEventQue;
+
+ Status = NtReplyPort(Ow2hOs2sesPort,
+ (PPORT_MESSAGE) &SendMsg);
+
+ if ( !NT_SUCCESS( Status ) )
+ {
+#if DBG
+ IF_OD2_DEBUG2( MOU, OS2_EXE )
+ /* KdPrint(("OS2SES(NtRqust-SendMouseReply): fail to send reply\n")) */;
+#endif
+ }
+}
+
+
+VOID
+SendKbdReply(IN PVOID MonHeader,
+ IN PVOID KbdRequestArea,
+ IN PVOID pData,
+ IN USHORT Length)
+{
+ SCREQUESTMSG SendMsg;
+ NTSTATUS Status;
+
+ RtlMoveMemory(&SendMsg,
+ MonHeader,
+ sizeof(PORT_MESSAGE));
+ RtlMoveMemory(&SendMsg.d.Kbd,
+ KbdRequestArea,
+ sizeof(KBDREQUEST));
+
+ if ( pData )
+ {
+ SendMsg.Status = 0L;
+ RtlMoveMemory( KbdAddress, pData, Length );
+ } else
+ {
+ /*
+ * This call is from EventReleaseLPC
+ * return -2 to terminate thread
+ */
+
+ SendMsg.Status = -2L;
+ }
+
+ SendMsg.Request = KbdRequest;
+
+ Status = NtReplyPort(Ow2hOs2sesPort,
+ (PPORT_MESSAGE) &SendMsg);
+
+ if ( !NT_SUCCESS( Status ) )
+ {
+#if DBG
+ IF_OD2_DEBUG2( KBD, OS2_EXE )
+ /* KdPrint(("OS2SES(NtRqust-SendKbdReply): fail to send reply\n")) */;
+#endif
+ }
+}
+
+
+VOID
+Os2sesTerminateThread(VOID)
+{
+ Os2sesTerminateThreadRc(0);
+}
+
+
+VOID
+Os2sesTerminateThreadRc(IN ULONG Rc)
+{
+ //NTSTATUS Status = (NTSTATUS)Rc;
+
+ NtTerminateThread( NtCurrentThread(), (NTSTATUS)Rc );
+}
+
+
+VOID EnableScreenUpdate()
+{
+ NTSTATUS Status;
+
+ Status = NtSetEvent(PauseEvent,
+ NULL);
+
+ SesGrp->PauseScreenUpdate = FALSE;
+}
+
+
+VOID DisableScreenUpdate()
+{
+ NTSTATUS Status;
+
+ Status = NtResetEvent(PauseEvent,
+ NULL);
+
+ SesGrp->PauseScreenUpdate = TRUE;
+}
+
+
+VOID SendNewFocusSet(IN ULONG WindowFocus)
+{
+ OS2SESREQUESTMSG RequestMsg;
+ DWORD Status;
+
+ /*
+ * Set Header info
+ */
+
+ PORT_MSG_DATA_LENGTH(RequestMsg) = sizeof(RequestMsg) - sizeof(PORT_MESSAGE);
+ PORT_MSG_TOTAL_LENGTH(RequestMsg) = sizeof(RequestMsg); // BUGBUG! too much
+ PORT_MSG_ZERO_INIT(RequestMsg) = 0L;
+ RequestMsg.PortType = 1;
+
+ RequestMsg.Request = SesConFocus;
+ RequestMsg.Session = Ow2hSession;
+ RequestMsg.d.FocusSet = WindowFocus;
+
+ Status = NtRequestWaitReplyPort( Ow2hOs2srvPort,
+ (PPORT_MESSAGE) &RequestMsg,
+ (PPORT_MESSAGE) &RequestMsg);
+
+ if ( !NT_SUCCESS( Status ))
+ {
+ PTEB Teb = NtCurrentTeb();
+#if DBG
+ KdPrint(( "OS2SES: Unable to send focus - Status == %X\n",
+ Status));
+#endif
+ EventReleaseLPC((ULONG)(Teb->ClientId.UniqueProcess));
+ TerminateSession();
+ Ow2Exit(0, NULL, 15);
+
+ }
+
+// ASSERT ( PORT_MSG_TYPE(RequestMsg) == LPC_REPLY );
+}
+
+
diff --git a/private/os2/os2ses/os2.c b/private/os2/os2ses/os2.c
new file mode 100644
index 000000000..f69f05aa0
--- /dev/null
+++ b/private/os2/os2ses/os2.c
@@ -0,0 +1,1750 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2.c
+
+Abstract:
+
+ This module contains the main of the session console process (OS2.EXE).
+
+Author:
+
+ Avi Nathan (avin) 17-Jul-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include <stdio.h>
+#include <io.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "trans.h"
+#include "os2res.h"
+#include "os2win.h"
+#include "conapi.h"
+#ifdef PMNT
+#define INCL_32BIT
+#include "pmnt.h"
+extern ULONG PMNTGetOurWindow(void);
+extern ULONG PMSubprocSem32;
+extern BOOLEAN Ow2WriteBackCloseEvent();
+extern APIRET DosSemClear(ULONG hsem);
+#endif
+
+BOOLEAN fService = FALSE; // Are we running as a service ?
+BOOLEAN fRootService = FALSE; // Directly invoked by the service
+
+/*
+ * External prototypes
+ */
+
+#undef InitOs2SessionPort
+DWORD InitOs2ssSessionPort();
+
+DWORD
+Ow2CommandLineWToCommandLineA(
+ IN LPWSTR CommandLineW,
+ OUT PSZ *CommandLineA
+ );
+
+BOOLEAN
+Od2DllInitialize(
+ IN PVOID DllHandle,
+ IN ULONG Reason,
+ IN PCONTEXT Context OPTIONAL
+ );
+
+BOOLEAN
+Od2ProcessIsDetached(VOID);
+
+int
+Loader_main(VOID);
+
+VOID
+ Od2FinalProcessCleanup();
+/*
+ * Internal prototypes
+ */
+
+UINT
+GetPgmName(
+ int argc
+ );
+
+UINT
+InitStdConout();
+
+#define OS2_VIO_MAX_ROW 100
+
+WORD StartUpwAttributes = 0x7;
+CONSOLE_SCREEN_BUFFER_INFO StartUpScreenInfo;
+CONSOLE_CURSOR_INFO StartUpCursorInfo;
+PVOID BASE_TILE;
+HANDLE handOS2 = NULL;
+
+ //
+ // Environment related global variables
+ //
+PSZ Od2CommandLinePtr; // to be used by dllinit.c
+char Od2PgmFullPathBuf[MAX_PATH + 1];
+ULONG Od2PgmFullPathBufLength;
+PSZ Od2PgmFilePath;
+DWORD Od2ForegroundWindow;
+
+ULONG Od2DosExitIsDone = 0;
+
+#if DBG
+BYTE SetEventHandlerStr[] = "SetEventHandler";
+BYTE InitStdConoutStr[] = "InitStdConout";
+BYTE SesGrpInitStr[] = "SesGrpInit";
+BYTE RestoreWin32ParmsBeforeTerminationStr[] = "RestoreWin32ParmsBeforeTermination";
+BYTE CreateServerThreadsStr[] = "CreateServerThreads";
+BYTE ResumeServerThreadsStr[] = "ResumeServerThreads";
+#endif
+
+extern BOOLEAN Od2ReceivedSignalAtInit;
+extern DWORD Od2InitSignalType;
+BOOL
+EventHandlerRoutine (IN ULONG CtrlType);
+
+extern PVOID Od2Process;
+PVOID IsOs2Thread();
+ULONG Od2ThreadId();
+ULONG Od2ProcessId();
+PSZ Od2ApplName();
+PSZ Od2GetLastAPI();
+
+// global variable to keep exception information
+
+EXCEPTION_POINTERS ExPtrs;
+EXCEPTION_RECORD ExRec;
+WORD wSavedFpStatus = 0, wSavedFpCtrl = 0;
+
+/*
+ * Os2ServiceThread:
+ * Created to allow the service who started this copy of OS2.EXE to terminate
+ * the process tree.
+ */
+VOID
+Os2ServiceThread(
+ IN PVOID Parameter
+ )
+{
+ CHAR SemName[MAX_PATH];
+ HANDLE hServiceEvent;
+
+ wsprintf(SemName, "OS2SSService-%d", GetCurrentProcessId());
+
+ //
+ // Create the service event for this process
+ //
+ hServiceEvent = CreateEventA(
+ NULL,
+ FALSE, // automatic reset
+ FALSE, // initial state = non-signaled
+ SemName);
+
+ if (hServiceEvent == NULL)
+ {
+#if DBG
+ DbgPrint("OS2: Os2ServiceThread(), error at CreateEvent, error=%d\n",
+ GetLastError());
+#endif
+ }
+
+ // Wait on the Service semaphore
+ if (WaitForSingleObject(
+ hServiceEvent,
+ INFINITE) == WAIT_FAILED)
+ {
+#if DBG
+ DbgPrint("OS2: Os2ServiceThread(), failed to NtWaitForSingleObject PMShellEvent, error=%d\n",
+ GetLastError());
+#endif
+ }
+
+#if DBG
+ DbgPrint("OS2: Os2ServiceThread() - event signaled\n");
+#endif
+#if PMNT
+ //
+ // PM apps handling
+ //
+ if (ProcessIsPMProcess())
+ {
+ // Regular app (i.e. not PMShell)
+ if (!ProcessIsPMShell())
+ {
+ if (!Ow2WriteBackCloseEvent())
+ {
+ // We failed to write-back a close event:
+ // must be DosExecPgm proc; Pass event through semaphore
+ DosSemClear(PMSubprocSem32);
+ Sleep(7900L);
+ }
+ }
+ else // PMSHELL
+ {
+#if DBG
+ DbgPrint("OS2: Os2ServiceThread(), ignoring signal - process is PMShell\n");
+#endif
+ }
+ return;
+ }
+#endif // PMNT
+ SendSignalToOs2Srv(XCPT_SIGNAL_KILLPROC);
+}
+
+DWORD Ow2FaultFilter(ULONG wFaultFilter, PEXCEPTION_POINTERS lpExP)
+{
+
+ // copy the exception record to global variable
+ ExPtrs = *lpExP;
+ ExRec = *lpExP->ExceptionRecord;
+
+ _asm {
+ fnstcw wSavedFpCtrl
+ fnstsw wSavedFpStatus
+ }
+ return(wFaultFilter);
+}
+
+void Ow2DisplayExceptionInfo()
+{
+ char ErrMsg[512];
+
+ wsprintf(ErrMsg,
+ "OS2: Internal Exception 0x%lx occured at %lx\nApplication Name=%s\nLast OS/2 API=%s\nTID=%d PID=%d\nFP: Ctrl=%lx, Status=%lx\nEAX=%lx EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\nESP=%lx EBP=%lx",
+ ExRec.ExceptionCode,
+ ExRec.ExceptionAddress,
+ Od2Process ? Od2ApplName() : "None",
+ (IsOs2Thread()) ? (Od2GetLastAPI()) : "None",
+ (IsOs2Thread()) ? (Od2ThreadId()) : 0,
+ Od2Process ? Od2ProcessId() : 0,
+ (DWORD) wSavedFpCtrl,
+ (DWORD) wSavedFpStatus,
+ (ExPtrs.ContextRecord)->Eax,
+ (ExPtrs.ContextRecord)->Ebx,
+ (ExPtrs.ContextRecord)->Ecx,
+ (ExPtrs.ContextRecord)->Edx,
+ (ExPtrs.ContextRecord)->Esi,
+ (ExPtrs.ContextRecord)->Edi,
+ (ExPtrs.ContextRecord)->Esp,
+ (ExPtrs.ContextRecord)->Ebp
+ );
+
+ MessageBox(NULL, ErrMsg, "Error", MB_OK | MB_ICONSTOP | MB_SYSTEMMODAL | MB_SETFOREGROUND);
+}
+
+void __cdecl
+main (int argc,
+ char *argv[],
+ char *envp[])
+{
+ UINT StringCode;
+ ULONG tmp, ConStringCode;
+#if PMNT
+ HANDLE NewForegroundWindow;
+#endif //PMNT
+
+ //
+ // Get the handle of the foreground window which is the window of the
+ // curent process.
+ // BUGBUG - This value is not neccessarily the right value because
+ // the user might immediately switch to another window which
+ // results in OS2.EXE having the handle of some other window
+ //
+ // Do not remove this statement without consulting with PM/NT team - the
+ // Ow2ForegroundWindow below is used by PM/NT call(s).
+ Ow2ForegroundWindow = GetForegroundWindow();
+
+ //
+ // Put the entire execution of the os/2 program inside a try/except.
+ // This way we ensure that we recover from 32 bit exceptions
+ //
+ // Note that the above is done only for RETAIL build. For DBG builds,
+ // it is better to let NTSD handle the exception so that we can debug
+ // the problem right away.
+ //
+ try {
+ timing = 0;
+#if DBG
+ Os2Debug = 0;
+ fVerbose = FALSE;
+ fTrace = FALSE;
+ fBrkOnStart = FALSE;
+#endif
+ //timing = GetTickCount();
+ //printf("Os2 main init time is %d\n", timing);
+ //Os2Debug = OS2_DEBUG_OS2_EXE;
+ Os2ReturnCode = 0;
+ Od2SignalEnabled = FALSE;
+
+ SetErrorMode(1);
+ /*
+ * get the full path of the program to execute
+ */
+
+ if (timing)
+ {
+ printf("Os2 time before GetPgmName is %d\n", (GetTickCount()) - timing);
+ }
+ if (StringCode = GetPgmName(argc))
+ {
+ Ow2Exit(StringCode, Od2PgmFullPathBuf, 1);
+ }
+
+ if (!fService)
+ {
+ char TmpBuffer[256];
+
+ // OS/2 child processes of OS/2 apps started from a service don't
+ // have the /S switch but they should find a variable 'Os2SSService'
+ // in their environment
+
+ if (GetEnvironmentVariable(
+ "Os2SSService",
+ &TmpBuffer[0],
+ 256))
+ {
+ // non-zero return code means variable was found
+ fService = TRUE;
+ }
+ }
+ else
+ {
+ if (!SetEnvironmentVariable(
+ "Os2SSService",
+ "1"))
+ {
+#if DBG
+ KdPrint(("OS2: failed to SetEnvironment variable Os2SSService, error=%d\n",
+ GetLastError()));
+#endif
+ }
+ }
+
+#if DBG
+ if (fService)
+ KdPrint(("Os2: Loading %s (as a service)\n", Od2PgmFullPathBuf));
+ else
+ KdPrint(("Os2: Loading %s\n", Od2PgmFullPathBuf));
+#endif
+ /*
+ * Set event handlers to handle Ctrl-C etc.
+ */
+
+ if (timing)
+ {
+ printf("Os2 time before SetEventHandlers is %d\n", (GetTickCount()) - timing);
+ }
+
+ SetEventHandlers(TRUE);
+
+ /*
+ * Set Std-Handles and open CONOUT$
+ */
+
+ if (timing)
+ {
+ printf("Os2 time before InitStdConout is %d\n", (GetTickCount()) - timing);
+ }
+
+ ConStringCode = InitStdConout();
+
+
+ /*
+ * Connect with OS2SS
+ */
+
+ if (timing)
+ {
+ printf("Os2 time before InitOs2ssSessionPort is %d\n", (GetTickCount()) - timing);
+ }
+ tmp = InitOs2ssSessionPort();
+
+ //
+ // InitOs2ssSessionPort returns:
+ // 0L - problem with resources, like memory
+ // -1L - problem connecting to os2srv
+ // otherwise - OK
+ //
+ if (tmp == -1L)
+ {
+ Ow2Exit(IDS_OS2_NOCONNECT, NULL, 1);
+ }
+ else if (tmp == 0)
+ {
+ Ow2Exit(IDS_OS2_NOMEMORY, NULL, 1);
+ }
+
+ Sleep(2);
+
+#if PMNT
+ NewForegroundWindow = (HANDLE)PMNTGetOurWindow();
+ if ((NewForegroundWindow != 0) &&
+ (NewForegroundWindow != Ow2ForegroundWindow))
+ {
+#if DBG
+ DbgPrint("Os2:main(), warning Ow2ForeGroundWindow changed from %x to %x\n",
+ Ow2ForegroundWindow,
+ NewForegroundWindow);
+#endif // DBG
+ Ow2ForegroundWindow = NewForegroundWindow;
+ }
+#endif // PMNT
+
+ if (timing)
+ {
+ printf("Os2 time before calling Od2DllInitialize is %d\n", (GetTickCount()) - timing);
+ }
+
+ if (!Od2DllInitialize(NULL, DLL_PROCESS_ATTACH, NULL))
+ {
+#if DBG
+ KdPrint(("OS2SES: Od2DllInitialize failed\n"));
+#endif
+ Ow2Exit(IDS_OS2_INITFAIL, NULL, 1);
+ // Ow2Exit(0, NULL, 1);
+ }
+
+ if (Od2CommandLinePtr)
+ if (LocalFree(Od2CommandLinePtr) != NULL)
+ {
+#if DBG
+ KdPrint(("OS2SES: Failed to free PsevdoArgv\n"));
+#endif
+ }
+
+ if ( ConStringCode )
+ {
+
+ if (!Od2ProcessIsDetached())
+ {
+#if DBG
+ KdPrint(("Os2: InitStdConout returned error %d\n", ConStringCode));
+#endif
+/**
+ For now, we do nothing, because the code below popup a window for a second.
+ if we find a better way, we'll use it, otherwise do nothing.
+ //
+ // Two cases - created with DETACH_PROCESS by non-OS/2 app
+ // OR
+ // failed somehow to create the console.
+ //
+ // No official way to test it, so we allocate console,
+ // if we succeed, this is the 1st case, free it and continue.
+ // if we fail, it means we already have one but can't access
+ // it somehow, fail the app.
+ //
+ if (AllocConsole())
+ {
+ FreeConsole();
+ }
+ else
+ Ow2Exit(ConStringCode, NULL, 1);
+**/
+ }
+ }
+
+ if (fRootService)
+ {
+ HANDLE ThreadHandle;
+ ULONG Tid;
+
+ ThreadHandle = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)Os2ServiceThread,
+ NULL,
+ 0,
+ &Tid);
+
+ if (!ThreadHandle)
+ {
+#if DBG
+ DbgPrint("OS2: main(), fail to create service thread, error %d\n",
+ GetLastError());
+#endif
+ }
+ else
+ {
+ if (!CloseHandle(ThreadHandle))
+ {
+#if DBG
+ DbgPrint("OS2: main(), CloseHandle(service thread=%x) failed, error=%d\n",
+ ThreadHandle, GetLastError());
+#endif // DBG
+ }
+ }
+ }
+
+ if (timing)
+ {
+ printf("Os2 time before calling loader_main is %d\n", (GetTickCount()) - timing);
+ }
+ Loader_main();
+ if (Od2ReceivedSignalAtInit) {
+ //
+ // OS2.EXE received a signal before complete loading,
+ // handle it now
+ //
+ EventHandlerRoutine(Od2InitSignalType);
+ }
+ }
+
+ //
+ // if Os2Debug is on, and ntsd is attached, it will get the second chance
+ //
+#if DBG
+ except( (Os2Debug ? Ow2FaultFilter(EXCEPTION_CONTINUE_SEARCH, GetExceptionInformation()):
+
+ Ow2FaultFilter(EXCEPTION_EXECUTE_HANDLER, GetExceptionInformation())) ) {
+#else
+ except( Ow2FaultFilter(EXCEPTION_EXECUTE_HANDLER, GetExceptionInformation()) ) {
+#endif
+#if DBG
+ KdPrint(("OS2SES: Internal error - Exception occured in 32bit os2ss code\n"));
+#endif
+ Ow2DisplayExceptionInfo();
+
+ //
+ // Cleanup client state, server will get notified
+ // via the exitprocess debug event
+ //
+ Od2FinalProcessCleanup();
+ Ow2Exit(IDS_OS2_INTERNAL_ERROR, NULL, 1);
+ }
+}
+
+
+VOID SetEventHandlers(IN BOOL fSet)
+{
+
+ Or2WinSetConsoleCtrlHandler(
+ #if DBG
+ SetEventHandlerStr,
+ #endif
+ EventHandlerRoutine,
+ fSet
+ );
+}
+
+struct
+{
+ LPTHREAD_START_ROUTINE lpStartAddress;
+ int Priority;
+ HANDLE *hServerThread;
+} SERVER_THREAD_TABLE[] =
+ {
+ {
+ EventServerThread,
+ OS2_EVENT_THREAD_PRIORITY,
+ &EventServerThreadHandle
+ },
+ {
+ SessionRequestThread,
+ OS2_SERVER_THREAD_PRIORITY,
+ &Ow2hSessionRequestThread
+ },
+ {
+ NULL,
+ 0,
+ NULL
+ }
+ };
+
+
+DWORD
+CreateServerThreads(VOID)
+{
+ HANDLE tHandle;
+ DWORD Tid, i;
+
+ /*
+ * create 1 for getting Input Event and dispatch them to 2 seperate
+ * queues for Kbd & Mou
+ */
+
+ for ( i = 0 ; SERVER_THREAD_TABLE[i].lpStartAddress ; i++ )
+ {
+
+ if((tHandle = Or2WinCreateThread(
+ #if DBG
+ CreateServerThreadsStr,
+ #endif
+ NULL,
+ 0,
+ SERVER_THREAD_TABLE[i].lpStartAddress,
+ NULL,
+ CREATE_SUSPENDED,
+ &Tid
+ )) == NULL)
+ {
+#if DBG
+ KdPrint(("OS2SES(Os2-CreateServerThreads): error %lu CreateThread %u\n",
+ GetLastError(), i));
+ ASSERT( FALSE );
+#endif
+ return(1L);
+ }
+
+ *SERVER_THREAD_TABLE[i].hServerThread = tHandle;
+ }
+
+ if(Or2WinResumeThread(
+ #if DBG
+ CreateServerThreadsStr,
+ #endif
+ Ow2hSessionRequestThread
+ ) == -1)
+ {
+#if DBG
+ KdPrint(("OS2SES(Os2-CreateServerThreads): error %lu ResumeThread ServerRequest\n",
+ GetLastError()));
+ ASSERT( FALSE );
+#endif
+ return(1L);
+ }
+
+ if (!Or2WinSetThreadPriority(
+ #if DBG
+ CreateServerThreadsStr,
+ #endif
+ Ow2hSessionRequestThread,
+ OS2_SERVER_THREAD_PRIORITY
+ ))
+ {
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ KdPrint(("OS2SES(Os2-CreateServerThreads): error %lu SetThreadPriority RequestThread\n",
+ GetLastError()));
+#endif
+ }
+ return(0L);
+}
+
+
+DWORD
+ResumeServerThreads(VOID)
+{
+ HANDLE tHandle;
+ DWORD i;
+
+ for ( i = 0 ; SERVER_THREAD_TABLE[i].lpStartAddress ; i++ )
+ {
+ if ((tHandle = *SERVER_THREAD_TABLE[i].hServerThread) !=
+ Ow2hSessionRequestThread)
+ {
+ if(Or2WinResumeThread(
+ #if DBG
+ ResumeServerThreadsStr,
+ #endif
+ tHandle
+ ) == -1)
+ {
+#if DBG
+ KdPrint(("OS2SES(Os2-CreateServerThreads): error %lu CreateThread %u\n",
+ GetLastError(), i));
+ ASSERT( FALSE );
+#endif
+ return(1L);
+ }
+
+ if (!Or2WinSetThreadPriority(
+ #if DBG
+ ResumeServerThreadsStr,
+ #endif
+ tHandle,
+ SERVER_THREAD_TABLE[i].Priority
+ ))
+ {
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ KdPrint(("OS2SES(Os2-CreateServerThreads): error %lu SetThreadPriority %u\n",
+ GetLastError(), i));
+#endif
+ }
+ }
+ }
+ return(0L);
+}
+
+
+#define SKIP_ARG( Ptr ) \
+{ \
+ register char ch; \
+ argc --; \
+ while( ch = *Ptr++ ) \
+ { \
+ if(( ch == ' ' ) || ( ch == '\t' )) \
+ { \
+ break; \
+ } \
+ } \
+} \
+
+UINT
+GetPgmName(
+ int argc
+ )
+{
+ char *lpPgmName = NULL, CurChar, *ArgvPtr;
+ DWORD Rc;
+ int i;
+ CHAR ch;
+
+ /*
+ * Get the command line in OEM code page.
+ * Format is : "OS2 /P <full path> /C <original CommandLine>"
+ */
+
+ Rc = Ow2CommandLineWToCommandLineA(
+ GetCommandLineW(),
+ &ArgvPtr
+ );
+
+ //RtlProcessHeap
+ if ( Rc )
+ {
+ return(IDS_OS2_NOMEMORY);
+ }
+
+ /*
+ * skip program name ("OS2.EXE")
+ */
+
+ SKIP_ARG( ArgvPtr )
+
+ /*
+ * look for flags for os2 up to /C
+ *
+ */
+
+ while ( argc )
+ {
+ if ( ArgvPtr[0] == '/' )
+ {
+ CurChar = ArgvPtr[1] | ('a'-'A');
+ ArgvPtr += 2;
+ if ( CurChar == 'c' )
+ {
+ /*
+ * Skip the /C and break from the while loop
+ */
+
+ ArgvPtr++;
+ break;
+
+ } else switch ( CurChar )
+ {
+ case 'p':
+ SKIP_ARG(ArgvPtr);
+ lpPgmName = ArgvPtr;
+ break;
+#if DBG
+ case 'b':
+ fBrkOnStart = TRUE;
+ KdPrint((
+ "OS2: Breakpoint caused by /B switch!\n"));
+ _asm int 3;
+ break;
+
+ case 'v':
+ fVerbose = TRUE;
+ break;
+
+ case 't':
+ fTrace = TRUE;
+ break;
+#endif
+ case 's':
+ fService = TRUE;
+#if PMNT
+ // Don't consider PMSHELL a root service, i.e. don't
+ // create a termination thread for it. We don't want
+ // PMSHELL to terminate even if the service which started it
+ // is stopped because there may be PM apps out there which
+ // weren't started by services.
+ if (!ProcessIsPMShell())
+ fRootService = TRUE;
+#else
+ fRootService = TRUE;
+#endif
+ break;
+
+ default:
+ strncpy(Od2PgmFullPathBuf, ArgvPtr, MAX_PATH);
+ Od2PgmFullPathBuf[MAX_PATH - 1] = '\0';
+ return(IDS_OS2_WHATFLAG);
+ }
+ } else
+ {
+ return(IDS_OS2_USAGE);
+ }
+
+ SKIP_ARG(ArgvPtr);
+ }
+
+ /*
+ * We exit the loop when "/C" was found or when "argc=0".
+ * Make sure "/C" was found and "/P <appl_full_path>" had been
+ * found.
+ */
+
+ if (( CurChar != 'c' ) || !lpPgmName )
+ {
+ return(IDS_OS2_NOCMD);
+ }
+
+ /*
+ * The full path of the program to execute is pointed by lpPgmName
+ * but is space terminated. ArgvPtr points to the original command
+ * line.
+ */
+
+ for ( i = 0 ;
+ ( lpPgmName[i] != '\0' ) &&
+ ( lpPgmName[i] != ' ' ) &&
+ ( lpPgmName[i] != '\t' ) &&
+ ( i < MAX_PATH )
+ ; Od2PgmFullPathBuf[i] = lpPgmName[i], i++ );
+
+ if ( i == MAX_PATH )
+ {
+ return(IDS_OS2_NOMEMORY);
+ }
+
+ Od2PgmFullPathBuf[i] = '\0';
+ Od2PgmFullPathBufLength = i;
+
+ // Code below replaces the program name with the full-path. This caused
+ // the PM Deskpic screen-saver to GP because it looked for '\'
+ // (31-May-94, RAID bug#2932)
+
+ SKIP_ARG(ArgvPtr);
+
+ ch = lpPgmName[i];
+
+ if (argc > 1)
+ {
+ Od2CommandLinePtr =
+ (PSZ)LocalAlloc(0,
+ // Path + SPACE + arguments + /0
+ Od2PgmFullPathBufLength + 1 + strlen(ArgvPtr) + 1);
+ }
+ else
+ {
+ Od2CommandLinePtr =
+ (PSZ)LocalAlloc(0,
+ // Path + /0
+ Od2PgmFullPathBufLength + 1);
+ }
+
+ if (Od2CommandLinePtr == NULL)
+ {
+ return(IDS_OS2_NOMEMORY);
+ }
+
+ strcpy(Od2CommandLinePtr, Od2PgmFullPathBuf);
+
+ if (argc > 1)
+ {
+ strncat(Od2CommandLinePtr, &ch, 1); // Cat the argv0-1 seperating char
+ strcat(Od2CommandLinePtr, ArgvPtr); // Fill in all the rest (argvs)
+ }
+
+ // Find the program name by skipping up to (and include) '\', '/' and ':'
+
+ Od2PgmFilePath = &Od2PgmFullPathBuf[0];
+
+ for ( i = 0 ; ( Od2PgmFullPathBuf[i] != '\0' ) ; i++ )
+ {
+ if (( Od2PgmFullPathBuf[i] == ':' ) ||
+ ( Od2PgmFullPathBuf[i] == '/' ) ||
+ ( Od2PgmFullPathBuf[i] == '\\' ))
+ {
+ Od2PgmFilePath = &Od2PgmFullPathBuf[i+1];
+ }
+ }
+
+ return(0);
+}
+
+
+UINT
+InitStdConout()
+{
+// SECURITY_ATTRIBUTES SecurityAttributes;
+#if DBG
+ DWORD Status;
+#endif
+
+ /*
+ * Get a handle to CONIN$ & CONOUT$ for KBD & VIO requests
+ */
+
+ hConsoleStdIn = GetStdHandle(STD_INPUT_HANDLE);
+ hConsoleStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ hConsoleStdErr = GetStdHandle(STD_ERROR_HANDLE);
+
+ hStdInConsoleType = (USHORT)(CONSOLE_HANDLE(hConsoleStdIn) &&
+ VerifyConsoleIoHandle(hConsoleStdIn));
+ hStdOutConsoleType = (USHORT)(CONSOLE_HANDLE(hConsoleStdOut) &&
+ VerifyConsoleIoHandle(hConsoleStdOut));
+ hStdErrConsoleType = (USHORT)(CONSOLE_HANDLE(hConsoleStdErr) &&
+ VerifyConsoleIoHandle(hConsoleStdErr));
+
+// SecurityAttributes.bInheritHandle = FALSE;
+// SecurityAttributes.lpSecurityDescriptor = NULL;
+// SecurityAttributes.nLength = sizeof (SECURITY_ATTRIBUTES);
+
+ /*
+ * Open CONOUT$ if StdOut id redirected
+ */
+
+ if (hStdOutConsoleType)
+ {
+ hConsoleOutput = hConsoleStdOut;
+ } else
+ {
+ hConsoleOutput = Or2WinCreateFileW(
+ #if DBG
+ InitStdConoutStr,
+ #endif
+ L"CONOUT$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL, /* &SecurityAttributes, */
+ OPEN_EXISTING, /* CREATE_ALWAYS, */
+ 0,
+ NULL
+ );
+
+// hConsoleOutput = Or2WinCreateConsoleScreenBuffer(
+// #if DBG
+// InitStdConoutStr,
+// #endif
+// GENERIC_READ | GENERIC_WRITE,
+// FILE_SHARE_READ|FILE_SHARE_WRITE,
+// NULL, /* &SecurityAttributes */
+// CONSOLE_TEXTMODE_BUFFER,
+// NULL);
+
+ if (hConsoleOutput == INVALID_HANDLE_VALUE)
+ {
+ return (IDS_OS2_CREATECONOUT);
+ }
+
+ if (!Or2WinSetConsoleActiveScreenBuffer(
+ #if DBG
+ InitStdConoutStr,
+ #endif
+ hConsoleOutput
+ ))
+ {
+#if DBG
+// return (IDS_OS2_ACTIVECONOUT);
+ Status = GetLastError();
+ IF_OD2_DEBUG( ANY )
+ {
+ KdPrint(("OS2SES(Os2-SetConsoleActiveScreenBuffer): can't activate CONOUT(%lu) in Full-Screen\n", Status));
+ }
+#endif
+ }
+ }
+
+ hConOut = hConsoleOutput;
+
+ SetConsoleInputModeAgain = 0;
+ SetConsoleOutputModeAgain = 0;
+
+ return(0);
+}
+
+
+DWORD
+SesGrpInit()
+{
+ DWORD Type, Rc, i;
+ HANDLE *Handle;
+ USHORT *fType, FileType;
+ COORD Coord;
+ CONSOLE_FONT_INFO ConsoleCurrentFont;
+#if DBG
+ UCHAR ErrBuff[ERROR_BUFFER_SIZE];
+#endif
+
+ //SesGrp->WinProcessNumberInSession = 0;
+ //SesGrp->WinSyncProcessNumberInSession = 0;
+
+ SesGrp->hConsoleInput = hConsoleInput;
+ SesGrp->hConsoleOutput = hConsoleOutput;
+
+ SesGrp->StdIn = hConsoleStdIn;
+ SesGrp->StdOut = hConsoleStdOut;
+ SesGrp->StdErr = hConsoleStdErr;
+
+ SesGrp->StdInFlag = hStdInConsoleType;
+ SesGrp->StdOutFlag = hStdOutConsoleType;
+ SesGrp->StdErrFlag = hStdErrConsoleType;
+
+ //SesGrp->KbdInFocus = 0;
+ SesGrp->NoKbdFocus = TRUE;
+ SesGrp->FirstProcess = TRUE;
+ SesGrp->StdInHandleCount = 1;
+ SesGrp->StdOutHandleCount = 1;
+ SesGrp->StdErrHandleCount = 1;
+ //SesGrp->hConsolePopUp = NULL;
+
+ for ( i=0, Handle = &(SesGrp->StdIn),
+ fType = &(SesGrp->StdInFileType) ;
+ i<3 ; i++, Handle++, fType++ )
+ {
+ Type = GetFileType(*Handle);
+ // BUGBUG maybe call NtQueryVolumeInformationFile directly (base\client\filehops.h)
+ switch (Type)
+ {
+ case FILE_TYPE_DISK:
+ FileType = 0x0000; // FILE_TYPE_FILE
+ break;
+
+ case FILE_TYPE_CHAR:
+ FileType = 0x0001; // FILE_TYPE_DEV
+ break;
+
+ case FILE_TYPE_PIPE:
+ FileType = 0x0002; // FILE_TYPE_PIPE
+ break;
+
+ //case FILE_TYPE_UNKNOWN:
+ default:
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ DbgPrint("OS2SES(SesGrpInit): GetFileType(handle %lx) failed, LastError = %ld\n",
+ *Handle, GetLastError());
+ }
+#endif
+ FileType = 0x0001; // FILE_TYPE_DEV - to be safety
+ break;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ KdPrint(("OS2SES(HandlesTypes): Handle %lx(%lu), WinType %lx, Os2Type %lx\n",
+ *Handle, i, Type, FileType ));
+ }
+#endif
+ *fType = FileType;
+ }
+
+ Or2WinGetConsoleScreenBufferInfo(
+ #if DBG
+ SesGrpInitStr,
+ #endif
+ hConsoleOutput,
+ &StartUpScreenInfo
+ );
+
+ SesGrp->ScreenColNum = StartUpScreenInfo.dwSize.X;
+ if ((SesGrp->ScreenRowNum = StartUpScreenInfo.dwSize.Y) > OS2_VIO_MAX_ROW)
+ {
+#if DBG
+ IF_OD2_DEBUG( ANY )
+ {
+ KdPrint(("OS2SES: Screen size is bigger than the maximum for OS/2.\n"));
+ KdPrint((" OS2SS will use only first %d rows of the %d available\n",
+ OS2_VIO_MAX_ROW, StartUpScreenInfo.dwSize.Y));
+ }
+#endif
+ SesGrp->ScreenRowNum = OS2_VIO_MAX_ROW;
+ }
+ SesGrp->CellVSize = SesGrp->CellHSize = 8;
+
+ if (!GetCurrentConsoleFont(hConsoleOutput,
+ TRUE, /* maximize window */
+ &ConsoleCurrentFont))
+ {
+#if DBG
+ Rc = GetLastError();
+ if ( Rc == ERROR_FULLSCREEN_MODE )
+ {
+ IF_OD2_DEBUG( ANY )
+ {
+ KdPrint(("OS2SES(Os2-GetCurrentConsoleFont): can't query current font(%lu) in Full-Screen\n",
+ Rc));
+ }
+ } else
+ {
+ sprintf(ErrBuff, "OS2SES(Os2-GetCurrentConsoleFont): can't query current font(%lu)\n", Rc);
+ ASSERT1( ErrBuff, FALSE );
+ }
+#endif
+ } else
+ {
+ Coord = GetConsoleFontSize(hConsoleOutput,
+ ConsoleCurrentFont.nFont);
+
+#if DBG
+ if ((!Coord.X) && (!Coord.Y))
+ {
+ Rc = GetLastError();
+ sprintf(ErrBuff, "OS2SES(Os2-GetConsoelFontSize): can't query font Size(%lu)\n", Rc);
+ ASSERT1( ErrBuff, FALSE );
+ }
+#endif
+
+ SesGrp->CellVSize = Coord.Y;
+ SesGrp->CellHSize = Coord.X;
+ }
+
+ StartUpwAttributes = StartUpScreenInfo.wAttributes;
+
+ if (!Or2WinGetConsoleMode(
+ #if DBG
+ SesGrpInitStr,
+ #endif
+ hConsoleOutput,
+ &SesGrp->DefaultWinOutputMode
+ ))
+ {
+ Rc = GetLastError();
+#if DBG
+ ASSERT1( "Can not get CONOUT for default Mode\n", FALSE );
+#endif
+ SesGrp->DefaultWinOutputMode = WINDOW_DEFAULT_OUTPUT_MODE;
+ }
+
+ SesGrp->OutputModeFlags = WINDOW_DEFAULT_OUTPUT_MODE;
+
+ if (!Or2WinSetConsoleMode(
+ #if DBG
+ SesGrpInitStr,
+ #endif
+ hConsoleOutput,
+ OS2_DEFAULT_OUTPUT_MODE
+ ))
+ {
+ Rc = GetLastError();
+#if DBG
+ ASSERT1( "Can not set CONOUT for default Mode\n", FALSE );
+#endif
+ }
+ else
+ SesGrp->OutputModeFlags = OS2_DEFAULT_OUTPUT_MODE;
+
+ SesGrp->MaxLVBsize =
+ (SesGrp->ScreenColNum * SesGrp->ScreenRowNum * 4 );
+
+ if (SesGrp->MaxLVBsize < 80 * 100 * 4) /* buffer for 100x80 window */
+ {
+ SesGrp->MaxLVBsize = 80 * 100 * 4;
+ }
+
+ if (SesGrp->MaxLVBsize > (64 * 1024)) /* more than 64K */
+ {
+ SesGrp->MaxLVBsize = 64 * 1024;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ KdPrint(("OS2SES(Os2-Handles): hIn %lx, hOut %lx, StdIn %lx (%s), StdOut %lx(%s), StdErr %lx(%s)\n",
+ hConsoleInput, hConsoleOutput,
+ hConsoleStdIn, ((hStdInConsoleType) ? "Std" : "Rdr" ),
+ hConsoleStdOut, ((hStdOutConsoleType) ? "Std" : "Rdr" ),
+ hConsoleStdErr, ((hStdErrConsoleType) ? "Std" : "Rdr" )
+ ));
+ }
+#endif
+
+#if DBG
+// KdPrint(("OS2SES(Os2-ConInfo): Size %x:%x, Pos %x:%x, Attr %x, Win %x:%x-%x:%x, Max %x:%x\n",
+// StartUpScreenInfo.dwSize.Y, StartUpScreenInfo.dwSize.X,
+// StartUpScreenInfo.dwCursorPosition.Y, StartUpScreenInfo.dwCursorPosition.X,
+// StartUpScreenInfo.wAttributes,
+// StartUpScreenInfo.srWindow.Top, StartUpScreenInfo.srWindow.Left,
+// StartUpScreenInfo.srWindow.Bottom, StartUpScreenInfo.srWindow.Right,
+// StartUpScreenInfo.dwMaximumWindowSize.Y, StartUpScreenInfo.dwMaximumWindowSize.X ));
+#endif
+
+ return(0L);
+}
+
+
+VOID
+RestoreWin32ParmsBeforeTermination()
+{
+ Or2WinSetConsoleMode(
+ #if DBG
+ RestoreWin32ParmsBeforeTerminationStr,
+ #endif
+ hConsoleInput,
+ DefaultWinInputMode
+ );
+
+ Or2WinSetConsoleMode(
+ #if DBG
+ RestoreWin32ParmsBeforeTerminationStr,
+ #endif
+ hConsoleOutput,
+ SesGrp->DefaultWinOutputMode
+ );
+
+ /*
+ * This is a workaround since the CMD doesn't restore its CurType
+ *
+ * Bug #4323 (OS2SS: CURSOR DISAPPEARS AFTER EXITING WORD5.0)
+ */
+
+ Or2WinSetConsoleCursorInfo(
+ #if DBG
+ RestoreWin32ParmsBeforeTerminationStr,
+ #endif
+ hConsoleOutput,
+ &StartUpCursorInfo
+ );
+}
+
+
+VOID
+Ow2Exit(
+ IN UINT StringCode,
+ IN PCHAR ErrorText,
+ IN int ExitCode
+ )
+/*++
+
+Routine Description:
+
+ This routine performs the exit from OS2.EXE for OS/2 application.
+
+Arguments:
+
+ StringCode - A code to retrieve an error message from the string RC file
+ (os2.rc). It's printed to the stderr. If zero - no message will be
+ printed.
+
+ ErrorText - test to use in the error message (in place of %s, like
+ DLL name, ordinal number, etc.)
+
+ ExitCode - code to return to Win32 CRT
+
+Return Value:
+
+
+Note:
+
+ This routine calls CRT's exit() and doesn't return.
+
+--*/
+{
+ WCHAR ErrBuffW[ERROR_BUFFER_SIZE];
+ CHAR ErrBuff[ERROR_BUFFER_SIZE];
+ DWORD Count;
+ DWORD Rc;
+
+ //if ((handOS2 = GetModuleHandle("os2.exe")) == NULL)
+ if (StringCode)
+ {
+ if ((handOS2 == NULL) &&
+ ((handOS2 = GetModuleHandle(NULL)) == NULL))
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2 ended! (error %lu on GetModuleHandle for ExitCode %lu)\n",
+ Rc, StringCode));
+#endif
+ } else
+ {
+ if ((Count = LoadStringW(handOS2,
+ StringCode,
+ ErrBuffW,
+ ERROR_BUFFER_SIZE)) == 0L)
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2 ended! (error %lu on LoadStringW for ExitCode %lu)\n",
+ Rc, StringCode));
+#endif
+ } else
+ {
+ Count = WideCharToMultiByte(
+ CP_OEMCP,
+ 0L,
+ ErrBuffW,
+ Count,
+ ErrBuff,
+ ERROR_BUFFER_SIZE,
+ NULL,
+ NULL);
+
+ if (Count != 0) {
+
+ ErrBuff[Count] = '\0';
+ fprintf(stderr, ErrBuff, ErrorText);
+#if DBG
+ KdPrint((ErrBuff, ErrorText));
+#endif
+ } else {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2 ended! (error %lu on WideCharToMultiByte for ExitCode %lu)\n",
+ Rc, StringCode));
+#endif
+ }
+ }
+ }
+ }
+
+#if DBG
+ IF_OD2_DEBUG( ANY )
+ {
+ KdPrint(( "OS2 ended! (%lx)\n", ExitCode ));
+ }
+#endif
+
+ ExitProcess(ExitCode);
+}
+
+
+#define CAP_BUFFER_SIZE 80
+#define TEXT_BUFFER_SIZE 256
+
+CHAR DefaultConfigSysAccessCap[] = "OS/2 Subsystem -- CONFIG.SYS Access";
+CHAR DefaultConfigSysAccessText[] = "An OS/2 Application requested access to CONFIG.SYS - Read Only access is granted. In order to modify OS/2 CONFIG.SYS, logon as ADMINISTRATOR.\n";
+CHAR DriveNotReadyDefaultMsg[] = "There is no disk in the drive.\nPlease insert a disk into drive%s.\n" ;
+CHAR WriteProtectDefaultMsg[] = "The disk cannot be written to because it is write protected.\nPlease remove the write protection from the volume\nin drive%s.\n" ;
+CHAR DriveNotReadyDefaultHdr[] = "%s.EXE - No Disk";
+CHAR WriteProtectDefaultHdr[] = "%s.EXE - Write Protect Error";
+
+CHAR DefaultBoundAppLoadCap[] = "%s - OS/2 Subsystem Bound Application Load Failure";
+CHAR DefaultBoundAppLoadText[] =
+ "This application uses an unsupported OS/2 API, and therefore "
+ "cannot be executed by the OS/2 Subsystem. "
+ "After the application terminates, you may try re-running it "
+ "using forcedos, as the DOS Subsystem may be able to support it. "
+ "Press Enter to terminate the application.";
+
+VOID
+Ow2ConfigSysPopup(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Pops up a window informing the user that s/he cannot update the registry due
+ to insufficient privilege.
+
+ The message is only popped up once per program.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ static MessageAlreadyShown = FALSE;
+ CHAR TextBuff[TEXT_BUFFER_SIZE];
+ CHAR CapBuff[CAP_BUFFER_SIZE];
+
+ if (MessageAlreadyShown) {
+ return;
+ }
+
+ MessageAlreadyShown = TRUE;
+
+ if ((handOS2 == NULL) &&
+ ((handOS2 = GetModuleHandle(NULL)) == NULL))
+ {
+#if DBG
+ KdPrint(("Ow2ConfigSysPopup: error %lu on GetModuleHandle\n",
+ GetLastError()));
+#endif
+ }
+
+ if (( handOS2 == NULL) ||
+ !LoadString(handOS2,
+ IDS_OS2_CONFIGSYS_ACCESS_TXT,
+ TextBuff,
+ TEXT_BUFFER_SIZE))
+ {
+#if DBG
+ if ( handOS2 != NULL)
+ {
+ KdPrint(("Ow2ConfigSysPopup: error %lu on LoadString1\n",
+ GetLastError()));
+ }
+#endif
+ strncpy(TextBuff, DefaultConfigSysAccessText, TEXT_BUFFER_SIZE - 1);
+ }
+
+ if (( handOS2 == NULL) ||
+ !LoadString(handOS2,
+ IDS_OS2_CONFIGSYS_ACCESS_CAP,
+ CapBuff,
+ CAP_BUFFER_SIZE))
+ {
+#if DBG
+ if ( handOS2 != NULL)
+ {
+ KdPrint(("Ow2ConfigSysPopup: error %lu on LoadString2\n",
+ GetLastError()));
+ }
+#endif
+ strncpy(CapBuff, DefaultConfigSysAccessCap, CAP_BUFFER_SIZE - 1);
+ }
+
+ MessageBoxEx( NULL,
+ TextBuff,
+ CapBuff,
+ MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK | MB_SETFOREGROUND,
+ 0
+ );
+}
+
+
+int
+Ow2DisplayHardErrorPopup(
+ IN int Drive,
+ IN BOOLEAN WriteProtectError,
+ IN PUCHAR AppName
+ )
+{
+ int size;
+ char CaptionMessage[CAP_BUFFER_SIZE], TextMessage[TEXT_BUFFER_SIZE];
+ char CaptionBuffer[CAP_BUFFER_SIZE], TextBuffer[TEXT_BUFFER_SIZE];
+ char ApplNameBuff[OS2_MAX_APPL_NAME], DriveBuf[4];
+ char *ErrMsg, *ErrHdr;
+ UINT CapCode, TextCode;
+
+
+ strncpy(ApplNameBuff, AppName, OS2_MAX_APPL_NAME);
+ size = strlen(ApplNameBuff);
+ if ((size > 4 ) && !stricmp(&ApplNameBuff[size-4], ".exe")) {
+ ApplNameBuff[size-4] = '\0';
+ }
+ strupr(ApplNameBuff);
+
+ if (Drive != 0)
+ {
+ sprintf(DriveBuf, " %c:", ('A' - 1) + Drive );
+ } else
+ {
+ DriveBuf[0] = '\0';
+ }
+
+ if (WriteProtectError)
+ {
+ ErrMsg = WriteProtectDefaultMsg;
+ ErrHdr = WriteProtectDefaultHdr;
+ CapCode = IDS_OS2_WRITE_PROTECT_CAP;
+ TextCode = IDS_OS2_WRITE_PROTECT_TXT;
+ } else
+ {
+ ErrMsg = DriveNotReadyDefaultMsg;
+ ErrHdr = DriveNotReadyDefaultHdr;
+ CapCode = IDS_OS2_DEVIVE_NOT_READY_CAP;
+ TextCode = IDS_OS2_DEVIVE_NOT_READY_TXT;
+ }
+
+ if ((handOS2 == NULL) &&
+ ((handOS2 = GetModuleHandle(NULL)) == NULL))
+ {
+#if DBG
+ KdPrint(("Ow2DisplayHardErrorPopup: error %lu on GetModuleHandle\n",
+ GetLastError()));
+#endif
+ }
+
+ if (( handOS2 == NULL) ||
+ !LoadString(handOS2,
+ TextCode,
+ TextMessage,
+ TEXT_BUFFER_SIZE))
+ {
+#if DBG
+ if ( handOS2 != NULL)
+ {
+ KdPrint(("Ow2DispalyardErrorPopup: error %lu on LoadString1\n",
+ GetLastError()));
+ }
+#endif
+ strncpy(TextMessage, ErrMsg, TEXT_BUFFER_SIZE - 1);
+ }
+
+ if (( handOS2 == NULL) ||
+ !LoadString(handOS2,
+ CapCode,
+ CaptionMessage,
+ CAP_BUFFER_SIZE))
+ {
+#if DBG
+ if ( handOS2 != NULL)
+ {
+ KdPrint(("Ow2DispalyardErrorPopup: error %lu on LoadString2\n",
+ GetLastError()));
+ }
+#endif
+ strncpy(CaptionMessage, ErrHdr, CAP_BUFFER_SIZE - 1);
+ }
+
+ sprintf(CaptionBuffer, CaptionMessage, ApplNameBuff);
+ sprintf(TextBuffer, TextMessage, DriveBuf);
+
+ return (MessageBox(
+ GetActiveWindow(),
+ TextBuffer,
+ CaptionBuffer,
+ MB_ABORTRETRYIGNORE | MB_DEFBUTTON2 | MB_ICONSTOP | MB_SYSTEMMODAL | MB_SETFOREGROUND
+ ));
+}
+
+VOID
+Ow2BoundAppLoadPopup(
+ IN PSZ AppName
+ )
+
+/*++
+
+Routine Description:
+
+ Pops up a window informing the user that an attempt to load a bound app has
+ failed, and that s/he may try to use forcedos.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHAR TextBuff[512];
+ CHAR CapBuff[CAP_BUFFER_SIZE];
+ CHAR CapBuff2[CAP_BUFFER_SIZE];
+
+ if ((handOS2 == NULL) &&
+ ((handOS2 = GetModuleHandle(NULL)) == NULL))
+ {
+#if DBG
+ KdPrint(("Ow2BoundAppLoadPopup: error %lu on GetModuleHandle\n",
+ GetLastError()));
+#endif
+ }
+
+ if (( handOS2 == NULL) ||
+ !LoadString(handOS2,
+ IDS_OS2_BOUND_APP_LOAD_TXT,
+ TextBuff,
+ 512))
+ {
+#if DBG
+ if ( handOS2 != NULL)
+ {
+ KdPrint(("Ow2BoundAppLoadPopup: error %lu on LoadString1\n",
+ GetLastError()));
+ }
+#endif
+ strncpy(TextBuff, DefaultBoundAppLoadText, 511);
+ }
+
+ if (( handOS2 == NULL) ||
+ !LoadString(handOS2,
+ IDS_OS2_BOUND_APP_LOAD_CAP,
+ CapBuff,
+ CAP_BUFFER_SIZE))
+ {
+#if DBG
+ if ( handOS2 != NULL)
+ {
+ KdPrint(("Ow2BoundAppLoadPopup: error %lu on LoadString2\n",
+ GetLastError()));
+ }
+#endif
+ strncpy(CapBuff, DefaultBoundAppLoadCap, CAP_BUFFER_SIZE - 1);
+ }
+
+ sprintf(CapBuff2, CapBuff, AppName);
+
+ MessageBoxEx( NULL,
+ TextBuff,
+ CapBuff2,
+ MB_APPLMODAL | MB_ICONSTOP | MB_OK | MB_SETFOREGROUND,
+ 0
+ );
+}
+
+#ifdef PMNT
+
+CHAR DefaultPMShellNotUpCap[] = "%s - PM Subsystem Application Load Failure";
+CHAR DefaultPMShellNotUpText[] = "You are attempting to execute an application under the PM Subsystem. \
+PM Shell needs to be running before this application. \
+Click on OK, or press ENTER to terminate the application, \
+then start PM Shell and re-try.";
+CHAR Default2ndPMShellCap[] = "%s - PM Subsystem 2nd PM Shell Failure";
+CHAR Default2ndPMShellText[] = "You are attempting to execute PM Shell. \
+Another copy of PM shell is already running, and therefore \
+this copy cannot be executed by the PM Subsystem.";
+CHAR DefaultPMShellFullScreenCap[] = "%s - PM Subsystem PM Shell Load Failure";
+CHAR DefaultPMShellFullScreenText[] = "PM Shell cannot be started from a full-screen CMD session. \
+Please start it from the Program Manager or from a windowed CMD session.";
+
+VOID
+Ow2PMShellErrorPopup(
+ IN PSZ AppName,
+ IN int error_flag
+ )
+
+/*++
+
+Routine Description:
+
+ Pops up a window informing the user that:
+ 1. an attempt to load a PM has failed because PM Shell is not up
+ 2. an attemp to load PM Shelll has failed because another copy
+ of PM Shell is already up.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHAR TextBuff[512];
+ CHAR CapBuff[CAP_BUFFER_SIZE];
+ CHAR CapBuff2[CAP_BUFFER_SIZE];
+ UINT ids_txt,ids_cap;
+ CHAR *default_txt,*default_cap;
+
+ if (error_flag == ERROR_PMSHELL_NOT_UP) {
+ ids_txt = IDS_OS2_PMSHELL_NOT_UP_TXT;
+ ids_cap = IDS_OS2_PMSHELL_NOT_UP_CAP;
+ default_txt = DefaultPMShellNotUpText;
+ default_cap = DefaultPMShellNotUpCap;
+ }
+ else if (error_flag == ERROR_PMSHELL_FULLSCREEN)
+ {
+ ids_txt = IDS_OS2_PMSHELL_FULLSCREEN_TXT;
+ ids_cap = IDS_OS2_PMSHELL_FULLSCREEN_CAP;
+ default_txt = DefaultPMShellFullScreenText;
+ default_cap = DefaultPMShellFullScreenCap;
+ }
+ else {
+ ids_txt = IDS_OS2_2ND_PMSHELL_TXT;
+ ids_cap = IDS_OS2_2ND_PMSHELL_CAP;
+ default_txt = Default2ndPMShellText;
+ default_cap = Default2ndPMShellCap;
+ }
+
+ if ((handOS2 == NULL) &&
+ ((handOS2 = GetModuleHandle(NULL)) == NULL))
+ {
+#if DBG
+ KdPrint(("Ow2PMShellErrorPopup: error %lu on GetModuleHandle\n",
+ GetLastError()));
+#endif
+ }
+
+ if (( handOS2 == NULL) ||
+ !LoadString(handOS2,
+ ids_txt,
+ TextBuff,
+ 512))
+ {
+#if DBG
+ if ( handOS2 != NULL)
+ {
+ KdPrint(("Ow2PMShellErrorPopup: error %lu on LoadString1\n",
+ GetLastError()));
+ }
+#endif
+ strncpy(TextBuff, default_txt, 511);
+ }
+
+ if (( handOS2 == NULL) ||
+ !LoadString(handOS2,
+ ids_cap,
+ CapBuff,
+ CAP_BUFFER_SIZE))
+ {
+#if DBG
+ if ( handOS2 != NULL)
+ {
+ KdPrint(("Ow2PMShellErrorPopup: error %lu on LoadString2\n",
+ GetLastError()));
+ }
+#endif
+ strncpy(CapBuff, default_cap, CAP_BUFFER_SIZE - 1);
+ }
+
+ sprintf(CapBuff2, CapBuff, AppName);
+
+ MessageBoxEx( NULL,
+ TextBuff,
+ CapBuff2,
+ MB_APPLMODAL | MB_ICONSTOP | MB_OK | MB_SETFOREGROUND,
+ 0
+ );
+}
+
+// PatrickQ: This function is called from another module (client\dllpmnt.c) and
+// is here just because os2ses\os2.c has the right set of include files for
+// WIN32 calls.
+
+VOID PMNTRemoveCloseMenuItem()
+{
+ HMENU SystemMenu;
+ DWORD rc;
+
+ SystemMenu = GetSystemMenu(Ow2ForegroundWindow, FALSE);
+ if (SystemMenu == 0)
+ {
+#if DBG
+ DbgPrint("Failed to get system menu !\n");
+#endif
+ return;
+ }
+
+ rc = DeleteMenu(
+ SystemMenu,
+ SC_CLOSE,
+ MF_BYCOMMAND);
+
+#if DBG
+ if (!rc)
+ {
+ DbgPrint("Failed to delete menu - last error=%d\n",
+ GetLastError());
+ }
+#endif
+}
+
+#endif //PMNT
diff --git a/private/os2/os2ses/os2.rc b/private/os2/os2ses/os2.rc
new file mode 100644
index 000000000..3c51f3822
--- /dev/null
+++ b/private/os2/os2ses/os2.rc
@@ -0,0 +1,155 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2.rc
+
+Abstract:
+
+ This module contains the resource for OS2.EXE.
+
+Author:
+
+ Michael Jarus (mjarus) 19-Jul-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DLL
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "OS2 Subsystem Client"
+#define VER_INTERNALNAME_STR "OS2.EXE"
+#define VER_ORIGINALFILENAME_STR "OS2.EXE"
+
+#include "common.ver"
+
+#include "os2res.h"
+
+STRINGTABLE PRELOAD
+ BEGIN
+ IDS_OS2_WHATFLAG "Unknown flag : %s\n"
+ IDS_OS2_USAGE "Usage : OS2 /P <full path> /C <original CommandLine>\n"
+ IDS_OS2_NOCMD "Command missing from syntax\nUsage : OS2 /P <full path> /C <original CommandLine>\n"
+ IDS_OS2_NOCONNECT "Cannot connect to OS2 SubSystem\n"
+ IDS_OS2_STARTPROCESS "Cannot Start Process\n"
+ IDS_OS2_CREATECONOUT "Cannot Create CONOUT\n"
+ IDS_OS2_CREATETHREAD "Cannot Create Thread \n"
+
+ IDS_OS2_INITFAIL "Error Init routine failed\n"
+ IDS_OS2_SEGNUMBER "Error invalid segment number\n"
+ IDS_OS2_EXEINVALID "Error module marked invalid\n"
+ IDS_OS2_STACKSEG "The file %s has an invalid stack address\n"
+ IDS_OS2_NOFILE "The system cannot find the file %s\n"
+ IDS_OS2_NOPROC "Error procedure not found %s\n"
+ IDS_OS2_NOORDINAL "Error ordinal not found %s\n"
+ IDS_OS2_CODESEG "The file %s has an invalid starting address\n"
+ IDS_OS2_MODULETYPE "The module %s has an invalid module type\n"
+ IDS_OS2_EXEFORMAT "The file %s has a bad executable format\n"
+ IDS_OS2_NOMEMORY "Insufficient Memory\n"
+ IDS_OS2_RELOCCHAIN "Relocation Chain Exceeds Limit\n"
+ IDS_OS2_OS2CODE "Error OS/2 error code %s\n"
+ IDS_OS2_BADFORMAT "The file %s has a bad format\n"
+
+ IDS_OS2_CONFIGSYS_ACCESS_CAP "OS/2 Subsystem -- CONFIG.SYS Access"
+ IDS_OS2_CONFIGSYS_ACCESS_TXT "An OS/2 Application requested access to CONFIG.SYS - Read Only access is granted. In order to modify OS/2 CONFIG.SYS, logon as ADMINISTRATOR.\n"
+ IDS_OS2_WRITE_PROTECT_CAP "%s.EXE - Write Protect Error"
+ IDS_OS2_WRITE_PROTECT_TXT "The disk cannot be written to because it is write protected.\nPlease remove the write protection from the volume\nin drive%s.\n"
+ IDS_OS2_DEVIVE_NOT_READY_CAP "%s.EXE - No Disk"
+ IDS_OS2_DEVIVE_NOT_READY_TXT "There is no disk in the drive.\nPlease insert a disk into drive%s.\n"
+ IDS_OS2_INTERNAL_ERROR "Internal OS/2 Subsystem Error - application terminated"
+ IDS_OS2_BOUND_APP_LOAD_CAP "%s - OS/2 Subsystem Bound Application Load Failure"
+ IDS_OS2_BOUND_APP_LOAD_TXT "You are attempting to execute a bound DOS - OS/2 application. \
+This application uses an unsupported OS/2 API, and therefore \
+cannot be executed by the OS/2 Subsystem. \
+After the application terminates, you may try re-running it \
+using forcedos, as the DOS Subsystem may be able to support it. \
+Press Enter to terminate the application."
+
+#if PMNT
+ IDS_OS2_PMSHELL_NOT_UP_CAP "%s - PM Subsystem Application Load Failure"
+ IDS_OS2_PMSHELL_NOT_UP_TXT "You are attempting to execute an application under the PM Subsystem. \
+PM Shell needs to be running before this application. \
+Click on OK, or press ENTER to terminate the application, \
+then start PM Shell and re-try."
+ IDS_OS2_2ND_PMSHELL_CAP "%s - PM Subsystem 2nd PM Shell Failure"
+ IDS_OS2_2ND_PMSHELL_TXT "You are attempting to execute PM Shell. \
+Another instance of PM Shell is already running, and therefore \
+this copy cannot be executed by the PM Subsystem."
+ IDS_OS2_PMSHELL_FULLSCREEN_CAP "%s - PM Subsystem PM Shell Load Failure"
+ IDS_OS2_PMSHELL_FULLSCREEN_TXT "PM Shell cannot be started from a full-screen CMD session. \
+Please start it from the Program Manager or from a windowed CMD session."
+#endif
+ END
+
+//LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US
+// This table is idendical to the default (NEUTRAL)
+
+// Add tables to all supported languages.
+//
+// The translation must leave the appearence of "%s" in the strings.
+// Tables that are identical to the default (i.e. no translation needed),
+// don't have to be copied.
+//
+// LANGUAGE LANG_FRENCH,SUBLANG_FRENCH
+// STRINGTABLE PRELOAD
+// BEGIN
+// IDS_OS2_WHATFLAG "French string for Unknown flag : %s\n"
+// IDS_OS2_USAGE "French string for Usage : OS2 /P <full path> /C <original CommandLine>\n"
+// IDS_OS2_NOCMD ...
+// .
+// .
+// .
+// IDS_OS2_EXEFORMAT "French string for The file %s has a bad executable format\n"
+// END
+//
+// LANGUAGE LANG_DUTCH,SUBLANG_DUTCH
+// STRINGTABLE PRELOAD
+// BEGIN
+// IDS_OS2_WHATFLAG "Dutch string for Unknown flag : %s\n"
+// IDS_OS2_USAGE "Dutch string for Usage : OS2 /P <full path> /C <original CommandLine>\n"
+// IDS_OS2_NOCMD ...
+// .
+// .
+// .
+// IDS_OS2_EXEFORMAT "Dutch string for The file %s has a bad executable format\n"
+// END
+//
+// ... (all other language tables)
diff --git a/private/os2/os2ses/os2ses.h b/private/os2/os2ses/os2ses.h
new file mode 100644
index 000000000..6dcf4c856
--- /dev/null
+++ b/private/os2/os2ses/os2ses.h
@@ -0,0 +1,324 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2ses.h
+
+Abstract:
+
+ Main header file for OS2SES module.
+ This module contains includes for both WIN32 and native NT modules.
+ Most files are clean WIN32 sources. files named nt* contain NT
+ calls and provides the interaction with os2 server and client.
+
+Author:
+
+ Avi Nathan (avin) 17-Jul-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+
+#ifdef NTOS2_ONLY
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include "os2win.h"
+#endif // NTOS2_ONLY
+
+#include "os2dbg.h"
+
+#ifdef WIN32_ONLY
+#include <windows.h>
+#include "os2nt.h"
+#endif // WIN32_ONLY
+
+#include "os2crt.h"
+
+#if DBG
+extern ULONG Os2Debug;
+
+#ifdef NTOS2_ONLY
+#define ASSERT1( str, exp ) \
+ if (!(exp)) \
+ { \
+ UCHAR WinErrBuf[100]; \
+ \
+ sprintf(WinErrBuf, "%s NtStatus %lx\n", str, Status); \
+ \
+ RtlAssert( #exp, __FILE__, __LINE__, WinErrBuf ); \
+ }
+
+#endif // NTOS2_ONLY
+#ifdef WIN32_ONLY
+#define ASSERT1( str, exp ) \
+ if (!(exp)) \
+ { \
+ UCHAR WinErrBuf[100]; \
+ \
+ sprintf(WinErrBuf, "%s WinError %lx\n", str, GetLastError()); \
+ \
+ RtlAssert( #exp, __FILE__, __LINE__, WinErrBuf ); \
+ }
+
+#endif // WIN32_ONLY
+#else // DBG
+#define ASSERT1( str, exp )
+#endif // DBG
+
+extern BOOLEAN fService; // Are we running as a service ?
+
+#include "sesport.h"
+
+#define WINDOW_DEFAULT_INPUT_MODE (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | ENABLE_PROCESSED_INPUT)
+#define WINDOW_DEFAULT_OUTPUT_MODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT)
+#define OS2_DEFAULT_INPUT_MODE 0
+#define OS2_DEFAULT_OUTPUT_MODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT)
+#define OS2_MOUSE_DEAFULT_EVENT_MASK (OS2_MOUSE_MOTION | OS2_MOUSE_MOTION_WITH_BN1_DOWN | OS2_MOUSE_BN1_DOWN | OS2_MOUSE_MOTION_WITH_BN2_DOWN | OS2_MOUSE_BN2_DOWN)
+#define OS2_MOUSE_LEGAL_EVENT_MASK (OS2_MOUSE_MOTION | OS2_MOUSE_MOTION_WITH_BN1_DOWN | OS2_MOUSE_BN1_DOWN | OS2_MOUSE_MOTION_WITH_BN2_DOWN | OS2_MOUSE_BN2_DOWN | OS2_MOUSE_MOTION_WITH_BN3_DOWN | OS2_MOUSE_BN3_DOWN)
+
+#define CONSOLE_HANDLE_SIGNATURE 0x00000003
+#define CONSOLE_HANDLE(HANDLE) (((ULONG)(HANDLE) & CONSOLE_HANDLE_SIGNATURE) == CONSOLE_HANDLE_SIGNATURE)
+#define LONG_MINUS_ONE 0xFFFFFFFF
+
+#define OS2_SERVER_THREAD_PRIORITY THREAD_PRIORITY_NORMAL
+#define OS2_EVENT_THREAD_PRIORITY THREAD_PRIORITY_TIME_CRITICAL
+#define OS2_WAITER_THREAD_PRIORITY THREAD_PRIORITY_HIGHEST
+
+
+HANDLE Ow2hOs2srvPort; /* handle for the port with OS2SRV */
+HANDLE Ow2hSession; /* handle for the session (return from OS2SRV) */
+
+/* os2ses side listner and reply for Vio, Kbd, Mou, Mon & Ctrl ports */
+
+HANDLE Ow2hOs2sesPort; /* handle for the LPC port */
+
+/* SectionHandle & Base Address of Vio, Kbd and Ctrl shared data section
+ *
+ * address of the shared memory section of the console ports.
+ */
+
+PVOID Os2SessionCtrlDataBaseAddress;
+HANDLE Os2SessionCtrlDataSectionHandle;
+PVOID Os2SessionDataBaseAddress;
+HANDLE Os2SessionSesGrpDataSectionHandle;
+
+POS2_SES_GROUP_PARMS SesGrp;
+
+#define Os2SessionNetDataBaseAddress Os2SessionCtrlDataBaseAddress
+
+PVOID KbdAddress;
+
+/* handles of Win-Console */
+
+HANDLE hConsoleInput; /* Input Handle */
+HANDLE hConsoleOutput; /* Output Handle */
+HANDLE hPopUpOutput; /* PopUp Handle */
+HANDLE hConOut; /* Current Output Handle: hConsoleOutput or hPopUpOutput */
+HANDLE hConsoleStdIn; /* Standart Input Handle */
+HANDLE hConsoleStdOut; /* Standart Output Handle */
+HANDLE hConsoleStdErr; /* Standart Error Handle */
+
+USHORT hStdInConsoleType; /* IS_CONSOLE StdHandle flag */
+USHORT hStdOutConsoleType; /* IS_CONSOLE StdHandle flag */
+USHORT hStdErrConsoleType; /* IS_CONSOLE StdHandle flag */
+
+/* handles of threads */
+
+HANDLE hCtrlListenThread;
+HANDLE EventServerThreadHandle;
+HANDLE Ow2hSessionRequestThread;
+
+/*
+ * Handle & Base Address of LVB (LogicalVideoBuffer)
+ */
+
+HANDLE LVBHandle;
+PUCHAR LVBBuffer;
+
+/*
+ * Handle of Pause(^S) event
+ */
+
+HANDLE PauseEvent;
+
+HANDLE HandleHeap; /* address of heap space for KBD handles */
+
+ULONG timing;
+BOOLEAN Od2SignalEnabled;
+ULONG Os2srvCountryCode;
+ULONG Os2srvCodePage[2];
+UCHAR Os2srvKeyboardLayout[2];
+ULONG PortMessageHeaderSize;
+ULONG KbdEventQueueSize;
+ULONG MouEventQueueSize;
+ULONG Os2WindowFocus;
+DWORD InputModeFlags; /* Console Input Mode */
+DWORD DefaultWinInputMode; /* Default Win Console Output Mode */
+DWORD ReturnCode;
+DWORD SetConsoleInputModeAgain; /* need to set console mode after Win CreateProcess */
+DWORD SetConsoleOutputModeAgain;
+ULONG ApplicationNcbAddress;
+ULONG ApplicationPostAddress;
+DWORD Os2ReturnCode;
+#ifdef DBCS
+// MSKK Jan.14.1993 V-AkihiS
+UCHAR OldWinAttr[3]; /* Win32 attr at entry point (OS2 format) */
+#else
+UCHAR OldWinAttr; /* Win32 attr at entry point (OS2 format) */
+#endif
+
+
+#if DBG
+BOOL fVerbose;
+BOOL fTrace;
+BOOL fBrkOnStart;
+#endif
+
+/*
+ * initialize procedures
+ */
+
+DWORD InitOs2SessionPort(
+ char *PgmName,
+ char **envp
+ );
+DWORD AnsiInit(VOID);
+DWORD AnsiInitForSession(VOID);
+DWORD VioInit(IN VOID);
+DWORD VioInitForSession(IN VOID);
+DWORD NLSInit();
+DWORD KbdInitForNLS(IN ULONG KbdCP);
+DWORD VioInitForNLS(IN ULONG VioCP);
+ULONG NtGetIntegerFromUnicodeString(IN WCHAR *sCountryCode);
+DWORD CreateServerThreads(VOID);
+DWORD ResumeServerThreads(VOID);
+DWORD SesGrpInit(VOID);
+ULONG
+Ow2GetProcessIdFromLPCMessage(
+ IN PVOID LPCMessage
+ );
+
+/*
+ * ServerThreads to serve all port requests
+ */
+
+VOID ServeSessionRequests(VOID);
+DWORD SessionRequestThread(IN PVOID Parameter);
+DWORD EventServerThread(IN PVOID Parameter);
+
+/*
+ * ServerRoutine to handle the requests
+ */
+
+BOOL ServeTmRequest(IN PSCTMREQUEST PReq, OUT PVOID PStatus);
+BOOL ServeWinCreateProcess(IN PWINEXECPGM_MSG PReq, OUT PVOID PStatus);
+BOOL ServeKbdRequest(IN PKBDREQUEST PReq, OUT PVOID PStatus,
+ IN PVOID pMsg, OUT PULONG pReply);
+BOOL ServeMouRequest(IN PMOUREQUEST PReq, OUT PVOID PStatus,
+ IN PVOID pMsg, OUT PULONG pReply);
+BOOL ServeMonRequest(IN PMONREQUEST PReq, OUT PVOID PStatus,
+ IN PVOID pMsg, OUT PULONG pReply);
+BOOL ServeNetRequest(IN PNETREQUEST PReq, OUT PVOID PStatus);
+BOOL ServePrtRequest(IN PPRTREQUEST PReq, OUT PVOID PStatus);
+#ifdef DBCS
+// MSKK Dec.23.1992 V-AkihiS
+BOOL ServeImmonRequest(IN PIMMONREQUEST PReq, OUT PVOID PStatus);
+#endif
+
+/*
+ * routine to save requests for proposed replies
+ */
+
+VOID SavePortMessegeInfo(OUT PVOID MonHeader,
+ IN PVOID pMsg);
+VOID SaveKbdPortMessegeInfo(OUT PVOID MonHeader,
+ OUT PVOID KbdRequestArea,
+ IN PVOID pMsg);
+VOID SendMonReply(IN PVOID MonHeader,
+ IN PVOID pData,
+ IN USHORT Length);
+VOID SendMouReply(IN PVOID MonHeader,
+ IN PVOID pData);
+VOID SendKbdReply(IN PVOID MonHeader,
+ IN PVOID KbdRequestArea,
+ IN PVOID pData,
+ IN USHORT Length);
+
+VOID DisableScreenUpdate();
+VOID EnableScreenUpdate();
+VOID SendNewFocusSet(IN ULONG WindowFocus);
+
+VOID RestartEventServerThread(VOID);
+
+VOID RestoreWin32ParmsBeforeTermination();
+VOID TerminateSession(VOID);
+VOID Os2sesTerminateThread(VOID);
+VOID Os2sesTerminateThreadRc(IN ULONG Rc);
+
+VOID
+EventReleaseLPC(
+ IN ULONG ProcessId
+ );
+
+VOID
+Ow2Exit(
+ IN UINT StringCode,
+ IN PCHAR ErrorText,
+ IN int ExitCode
+ );
+
+BOOL EventHandlerRoutine (IN ULONG CtrlType);
+BOOL SendSignalToOs2Srv(IN int SignalType);
+VOID SetEventHandlers(IN BOOL fSet);
+
+PVOID StartEventHandler(VOID);
+PVOID StartEventHandlerForSession(VOID);
+
+DWORD CreateOS2SRV(OUT PHANDLE hProcess);
+
+DWORD RemoveConForWinProcess();
+DWORD AddConAfterWinProcess();
+
+/*
+ * OS2 error used in OS2.EXE
+ *
+ * cannot include os2err.h because of collapstion wirh Nt/Win error def.
+ */
+
+#define ERROR_MONITOR_NOT_SUPPORTED 165
+#define NO_ERROR_MOUSE_NO_DATA 393
+#define ERROR_VIO_MODE 355
+#define ERROR_VIO_WIDTH 356
+#define ERROR_VIO_ROW 358
+#define ERROR_VIO_COL 359
+#define ERROR_KBD_INVALID_LENGTH 376
+#define ERROR_KBD_INVALID_ECHO_MASK 377
+#define ERROR_KBD_INVALID_INPUT_MASK 378
+#define ERROR_MOUSE_INV_PARMS 387
+#define ERROR_VIO_NO_POPUP 405
+#define ERROR_VIO_INVALID_PARMS 421
+#define ERROR_VIO_INVALID_LENGTH 438
+#define ERROR_KBD_NO_MORE_HANDLE 440
+#define ERROR_MON_INVALID_PARMS 379
+#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_NLS_NO_CTRY_CODE 398
+
+/*
+ * Signal subtypes for XCPT_SIGNAL
+ */
+#define XCPT_SIGNAL_INTR 1
+#define XCPT_SIGNAL_KILLPROC 3
+#define XCPT_SIGNAL_BREAK 4
+
+HANDLE Ow2ForegroundWindow;
diff --git a/private/os2/os2ses/prtrqust.c b/private/os2/os2ses/prtrqust.c
new file mode 100644
index 000000000..1990255ad
--- /dev/null
+++ b/private/os2/os2ses/prtrqust.c
@@ -0,0 +1,327 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ prtrqust.c
+
+Abstract:
+
+ This module contains the PRT request handler.
+
+Author:
+
+ Michael Jarus (mjarus) 1-Oct-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "trans.h"
+#include "event.h"
+#include "os2win.h"
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+
+
+/* DosOpen/DosQueryFHState/DosQueryFileInfo et al file attributes; also */
+/* known as Dos File Mode bits... */
+
+#define FILE_READONLY 0x0001
+#define FILE_HIDDEN 0x0002
+#define FILE_SYSTEM 0x0004
+#define FILE_DIRECTORY 0x0010
+#define FILE_ARCHIVED 0x0020
+
+#define ATTR_CHANGEABLE (FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_ARCHIVED)
+#define ATTR_ALL (FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY | FILE_ARCHIVED)
+#define ATTR_NOT_NORM 0x8000 // do not find normal files
+
+/* DosOpen() actions */
+
+#define FILE_EXISTED 0x0001
+#define FILE_CREATED 0x0002
+#define FILE_TRUNCATED 0x0003
+
+/* DosOpen() open flags */
+
+#define FILE_OPEN_EXISTING_FILE 0x0001
+#define FILE_TRUNCATE_EXISTING_FILE 0x0002
+#define FILE_CREATE_NEW_FILE 0x0010
+#define OPEN_ACTION_FAIL_IF_EXISTS 0x0000 /* ---- ---- ---- 0000 */
+#define OPEN_ACTION_OPEN_IF_EXISTS 0x0001 /* ---- ---- ---- 0001 */
+#define OPEN_ACTION_REPLACE_IF_EXISTS 0x0002 /* ---- ---- ---- 0010 */
+#define OPEN_ACTION_FAIL_IF_NEW 0x0000 /* ---- ---- 0000 ---- */
+#define OPEN_ACTION_CREATE_IF_NEW 0x0010 /* ---- ---- 0001 ---- */
+
+/* DosOpen/DosSetFHState flags */
+
+#define OPEN_ACCESS_READONLY 0x00000000 /* ---- ---- ---- -000 */
+#define OPEN_ACCESS_WRITEONLY 0x00000001 /* ---- ---- ---- -001 */
+#define OPEN_ACCESS_READWRITE 0x00000002 /* ---- ---- ---- -010 */
+#define OPEN_SHARE_DENYREADWRITE 0x00000010 /* ---- ---- -001 ---- */
+#define OPEN_SHARE_DENYWRITE 0x00000020 /* ---- ---- -010 ---- */
+#define OPEN_SHARE_DENYREAD 0x00000030 /* ---- ---- -011 ---- */
+#define OPEN_SHARE_DENYNONE 0x00000040 /* ---- ---- -100 ---- */
+#define OPEN_FLAGS_WRITE_THROUGH 0x00004000 /* -1-- ---- ---- ---- */
+
+#define ACCESS_FLAGS (OPEN_ACCESS_READONLY | OPEN_ACCESS_WRITEONLY | \
+ OPEN_ACCESS_READWRITE)
+#define SHARE_FLAGS (OPEN_SHARE_DENYREADWRITE | OPEN_SHARE_DENYWRITE | \
+ OPEN_SHARE_DENYREAD | OPEN_SHARE_DENYNONE)
+
+BOOL
+ServePrtRequest(IN PPRTREQUEST PReq,
+ OUT PVOID PStatus)
+{
+ DWORD Rc = 0;
+
+ switch (PReq->Request)
+ {
+ case PRTOpen:
+ Rc = Ow2PrintOpen(
+ PReq->d.Open.Attribute,
+ PReq->d.Open.OpenFlags,
+ PReq->d.Open.OpenMode,
+ PReq->d.Open.PrinterName,
+ &PReq->hPrinter,
+ &PReq->d.Open.Action
+ );
+ break;
+
+ case PRTClose:
+ Rc = Ow2PrintClose(
+ PReq->hPrinter
+ );
+ break;
+
+ case PRTWrite:
+ Rc = Ow2PrintWrite(
+ PReq->hPrinter,
+ PReq->d.Write.Offset,
+ &PReq->d.Write.Length
+ );
+ break;
+
+ default:
+ Rc = (DWORD)-1L; //STATUS_INVALID_PARAMETER;
+#if DBG
+ IF_OD2_DEBUG( OS2_EXE )
+ {
+ DbgPrint("OS2SES(VioRequest): Unknown Vio request = %X\n",
+ PReq->Request);
+ }
+#endif
+ }
+
+ if ( Rc == 1 )
+ {
+ Rc = GetLastError(); /* BUGBUG! error code and returned Status are wrong */
+ }
+
+ *(PDWORD) PStatus = Rc;
+
+ return(TRUE); // Continue
+}
+
+
+DWORD
+Ow2PrintOpen(
+ IN ULONG Attribute,
+ IN ULONG OpenFlags,
+ IN ULONG OpenMode,
+ IN PUCHAR PrinterName,
+ IN OUT PHANDLE phPrinter,
+ IN OUT PULONG Action
+ )
+{
+ DWORD Rc = 0, Access, Share = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ DWORD Create = 0, Attr = FILE_ATTRIBUTE_NORMAL;
+ ULONG Os2Share;
+
+ /*
+ * Set CreateFile.fdwAttribute from DosOpen.Attribute
+ */
+
+ if (Attribute && FILE_READONLY)
+ {
+ Attr |= FILE_ATTRIBUTE_READONLY;
+ }
+ if (Attribute && FILE_ARCHIVED)
+ {
+ Attr |= FILE_ATTRIBUTE_ARCHIVE;
+ }
+ if (Attribute && FILE_HIDDEN)
+ {
+ Attr |= FILE_ATTRIBUTE_HIDDEN;
+ }
+ if (Attribute && FILE_SYSTEM)
+ {
+ Attr |= FILE_ATTRIBUTE_SYSTEM;
+ }
+
+ /*
+ * Set CreateFile.fdwCreate from DosOpen.OpenFlags
+ */
+
+ if (OpenFlags == OPEN_ACTION_CREATE_IF_NEW)
+ {
+ Create = CREATE_NEW;
+ } else if (OpenFlags == OPEN_ACTION_OPEN_IF_EXISTS)
+ {
+ Create = OPEN_EXISTING;
+ } else if (OpenFlags == OPEN_ACTION_REPLACE_IF_EXISTS)
+ {
+ Create = TRUNCATE_EXISTING;
+ } else if (OpenFlags ==
+ (OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW))
+ {
+ Create = OPEN_ALWAYS;
+ } else if (OpenFlags ==
+ (OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS))
+ {
+ Create = CREATE_ALWAYS;
+ } else
+ {
+#if DBG
+ IF_OD2_DEBUG2( MISC, OS2_EXE )
+ DbgPrint("OS2SES(PrtRequest-PrintOpen): illegal Create %lu\n",
+ Create);
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ /*
+ * Set CreateFile.fdwShare from DosOpen.OpenMode
+ */
+
+ Os2Share = OpenMode && SHARE_FLAGS;
+
+ if ((Os2Share == OPEN_SHARE_DENYWRITE) ||
+ (Os2Share == OPEN_SHARE_DENYREADWRITE))
+ {
+ Share &= ~FILE_SHARE_WRITE;
+ }
+ if ((Os2Share == OPEN_SHARE_DENYREAD) ||
+ (Os2Share == OPEN_SHARE_DENYREADWRITE))
+ {
+ Share &= ~FILE_SHARE_READ;
+ }
+
+ /*
+ * Set CreateFile.fdwAccess from DosOpen.OpenMode
+ */
+
+ Os2Share = OpenMode && ACCESS_FLAGS;
+
+ if ((OpenMode && ACCESS_FLAGS) == OPEN_ACCESS_WRITEONLY)
+ {
+ Access = GENERIC_WRITE;
+ } else if ((OpenMode && ACCESS_FLAGS) == OPEN_ACCESS_READONLY)
+ {
+ Access = GENERIC_READ;
+ } else if ((OpenMode && ACCESS_FLAGS) == OPEN_ACCESS_READWRITE)
+ {
+ Access = GENERIC_READ | GENERIC_WRITE;
+ }
+
+ /*
+ * Set CreateFile.fdwAttribute.FILE_FLAG_WRITE_THROUGH
+ * from DosOpen.Attribute.OPEN_FLAGS_WRITE_THROUGH
+ */
+
+ if (OpenMode & OPEN_FLAGS_WRITE_THROUGH)
+ {
+ Attr |= FILE_FLAG_WRITE_THROUGH;
+ }
+
+ *phPrinter = CreateFile(
+ PrinterName,
+ Access,
+ Share,
+ NULL,
+ Create,
+ Attr,
+ NULL
+ );
+
+ if (*phPrinter != NULL)
+ {
+ // BUGBUG: set Action
+
+ *Action = FILE_EXISTED;
+ return(NO_ERROR);
+ }
+ if (Rc)
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OD2_DEBUG2( MISC, OS2_EXE )
+ DbgPrint("OS2SES(PrtRequest-PrintOpen): Rc %lu\n",
+ Rc);
+#endif
+ }
+ return(Rc);
+}
+
+
+DWORD
+Ow2PrintClose(
+ IN HANDLE hPrinter
+ )
+{
+ DWORD Rc;
+
+ Rc = CloseHandle(
+ hPrinter
+ );
+
+ if (Rc)
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OD2_DEBUG2( MISC, OS2_EXE )
+ DbgPrint("OS2SES(PrtRequest-PrintClose): Rc %lu\n",
+ Rc);
+#endif
+ }
+ return(Rc);
+}
+
+
+DWORD
+Ow2PrintWrite(
+ IN HANDLE hPrinter,
+ IN PVOID Buffer,
+ IN OUT PULONG Length
+ )
+{
+ DWORD Rc;
+
+ Rc = WriteFile(
+ hPrinter,
+ Buffer,
+ *Length,
+ Length,
+ NULL
+ );
+
+ if (Rc)
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OD2_DEBUG2( MISC, OS2_EXE )
+ DbgPrint("OS2SES(PrtRequest-PrintWrite): Rc %lu\n",
+ Rc);
+#endif
+ }
+ return(Rc);
+}
diff --git a/private/os2/os2ses/sources b/private/os2/os2ses/sources
new file mode 100644
index 000000000..348afd65a
--- /dev/null
+++ b/private/os2/os2ses/sources
@@ -0,0 +1,90 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Avi Nathan 15-Jul-1991
+
+!ENDIF
+
+MAJORCOMP=os2
+MINORCOMP=os2ses
+
+TARGETNAME=os2
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=..\inc
+
+NO_READONLY_STRINGS=1
+
+SOURCES=os2.rc \
+ prtrqust.c \
+ os2.c \
+ nls.c \
+ util.c \
+ viotty.c \
+ kbdtable.c \
+ trans.c \
+ violvb.c \
+ ntinitss.c \
+ ntrqust.c \
+ conrqust.c \
+ tmrqust.c \
+ event.c \
+ kbdrqust.c \
+ mourqust.c \
+ monrqust.c \
+ viorqust.c \
+ imrqust.c \
+ kbdnls.c \
+ vionls.c
+
+i386_SOURCES=i386\kbdxlat.asm i386\bekbd.asm i386\cfkbd.asm i386\dkkbd.asm \
+ i386\frkbd.asm i386\grkbd.asm i386\itkbd.asm i386\lakbd.asm \
+ i386\nlkbd.asm i386\nokbd.asm i386\pokbd.asm i386\sfkbd.asm \
+ i386\sgkbd.asm i386\spkbd.asm i386\sukbd.asm i386\svkbd.asm \
+ i386\ukkbd.asm i386\uskbd.asm i386\jpkbd.asm
+
+!IFDEF PMNT
+C_DEFINES=-DWIN32=1 -DPMNT=1
+!ELSE
+C_DEFINES=-DWIN32=1
+!ENDIF
+USE_CRTDLL=1
+
+UMTYPE=console
+UMAPPL=os2
+UMLIBS=obj\*\os2.lib \
+ obj\*\os2.res \
+ ..\loader\obj\*\loader.lib \
+ ..\obj\*\os2ssrtl.lib \
+ ..\client\obj\*\os2dll.lib \
+ $(BASEDIR)\Public\Sdk\Lib\*\netlib.lib \
+ $(BASEDIR)\Public\Sdk\Lib\*\NetRap.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\Public\SDK\Lib\*\rpcrt4.lib \
+ $(BASEDIR)\Public\SDK\Lib\*\rxcommon.lib \
+ $(BASEDIR)\Public\SDK\Lib\*\rxapi.lib \
+!IFDEF PMNT
+ $(BASEDIR)\public\sdk\lib\*\gdi32.lib \
+!ENDIF
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+!IFDEF PMNT
+COFFBASE=os2pm
+!ENDIF
diff --git a/private/os2/os2ses/struc.inc b/private/os2/os2ses/struc.inc
new file mode 100644
index 000000000..f76dd9280
--- /dev/null
+++ b/private/os2/os2ses/struc.inc
@@ -0,0 +1,513 @@
+;; SCCSID = @(#)struc.inc 12.1 88/03/18
+;;STRUC.INC--Stucture Macro Library
+;;Version 2.20 08/08/86
+;;Written by Eric C. Rasmussen
+
+ if @Version GE 600
+ option nokeyword: <.if, .elseif, .else, .endif, .while>
+ endif
+
+if1
+$noconj equ 0
+$and equ 1
+$or equ 2
+$short equ 3
+$near equ 4
+$andor = 0
+$temp = 0
+$temp2 = 0
+$dist = 0
+
+$notype equ 10
+$conjif equ 11
+$iftype equ 12
+$elsetype equ 13
+$whiletype equ 14
+$conjwhile equ 15
+$repeattype equ 16
+$conjuntil equ 17
+$fortype equ 18
+$conjleave equ 19
+
+$StrucErr macro text
+ Structure error -- text
+endm
+
+j macro
+endm
+jn macro
+endm
+
+jbuild macro j1,j2
+ j1 macro tgt
+ .xcref j1
+ j2 tgt
+ endm
+endm
+
+irp x,<<jeq,je>,<jlt,jl>,<jgt,jg>,<jneq,jne>,<jnlt,jnl>,<jngt,jng>,<jnpe,jpo>,<jnpo,jpe>>
+ jbuild x
+endm
+irp x,<<jzero,jz>,<jnzero,jnz>,<jnonzero,jnz>,<jnnonzero,jz>,<jand,jnz>,<jnand,jz>,<jnnand,jnz>>
+ jbuild x
+endm
+irp x,<a,ae,b,be,c,e,g,ge,l,le,o,p,s,z,cxz>
+ jbuild jnn&x,j&x
+endm
+
+jncxz macro tgt
+ local skip
+ jcxz skip
+ jmp short tgt
+skip:
+endm
+
+purge jbuild
+
+$getconj macro p1,p2
+ $andor = $noconj
+ irp parm,<p1,p2>
+ ifnb <&parm>
+ irp x,<and,AND,or,OR>
+ ifidn <parm>,<x>
+ $andor = $&&&x
+ exitm
+ endif
+ endm
+ endif
+ endm
+endm
+
+$getdist macro p1,p2
+ irp parm,<p1,p2>
+ ifnb <parm>
+ irp x,<short,SHORT,near,NEAR>
+ ifidn <parm>,<x>
+ $dist = $&&&x
+ exitm
+ endif
+ endm
+ endif
+ endm
+endm
+
+
+$poke macro num,value
+ $st&num = value
+.xcref $st&num
+endm
+
+$peek macro sym,num
+ sym = $st&num
+endm
+
+$push macro value
+ $st = $st+1
+ $poke %$st,value
+endm
+
+$pop macro sym
+ $peek sym,%$st
+ $st = $st-1
+endm
+
+$labl macro num
+$l&num:
+endm
+
+$cjump macro lnum,tf,cond
+ local skip
+ if $dist eq $short
+ ifb <cond>
+ jmp short $l&lnum
+ else
+ ifidn <tf>,<f>
+ jn&cond $l&lnum
+ else
+ j&cond $l&lnum
+ endif
+ endif
+ else
+ ifnb <cond>
+ ifidn <tf>,<f>
+ j&cond skip
+ else
+ jn&cond skip
+ endif
+ endif
+ jmp $l&lnum
+ ifnb <cond>
+skip:
+ endif
+ endif
+endm
+
+
+$cloop macro lnum,cond
+ loop&cond $l&lnum
+endm
+
+$test macro tgt,a1,a2,a3,a4,x1
+ ifb <a1>
+ $StrucErr <invalid condition>
+ else
+ ifb <a2>
+ $cjump %&tgt,a1
+ else
+ ifb <a3>
+ ifdif <a1>,<zero>
+ ifdif <a1>,<nonzero>
+ ifdif <a1>,<ZERO>
+ ifdif <a1>,<NONZERO>
+ $StrucErr <invalid condition>
+ exitm
+ endif
+ endif
+ endif
+ endif
+ or a2,a2
+ $cjump %&tgt,a1
+ else
+ ifb <a4>
+ cmp a1,a3
+ $cjump %&tgt,a2
+ else
+ ifb <x1>
+ ifdif <a1>,<bit>
+ ifdif <a1>,<BIT>
+ $StrucErr <invalid condition>
+ exitm
+ endif
+ endif
+ test a2,a4
+ $cjump %&tgt,a3
+ else
+ $StrucErr <invalid condition>
+ endif
+ endif
+ endif
+ endif
+ endif
+endm
+
+$toptest macro args,ntype,ctype,p4,p5
+ $getconj p4,p5
+ $dist = $defdist
+ $getdist p4,p5
+ if $andor eq $noconj
+ $test <$sn-1,f>,args
+ $pop $temp
+ if $orfound
+ $labl %$temp
+ endif
+ $push ntype
+ else
+ if $andor eq $and
+ $test <$sn-1,f>,args
+ else
+ $orfound = 1
+ $test <$sn,t>,args
+ endif
+ $push ctype
+ endif
+endm
+;;*****************************************************************************
+.if macro tst,p2,p3
+ $peek $temp,%$st
+ if $temp eq $conjif
+ $pop $temp
+ else
+ $push $elseiffound
+ $elseiffound = 0
+ $orfound = 0
+ $sn = $sn+1
+ $push $sn
+ $sn = $sn+1
+ $push $sn
+ $sn = $sn+1
+ $push $sn
+ endif
+ $toptest <tst>,$iftype,$conjif,p2,p3
+endm
+;;*****************************************************************************
+.then macro
+ $peek $temp,%$st
+ if $temp ne $iftype
+ $StrucErr <then without if>
+ endif
+endm
+;;*****************************************************************************
+.elseif macro tst,p2,p3
+ $pop $temp
+ if $temp ne $iftype
+ $StrucErr <elseif without if>
+ exitm
+ endif
+ $elseiffound = 1
+ $orfound = 0
+ $pop $temp
+ $peek $temp2,%$st
+ $dist = $near
+ $cjump %$temp2
+ $labl %$temp
+ $sn = $sn+1
+ $push $sn
+ $sn = $sn+1
+ $push $sn
+ $toptest <tst>,$iftype,$conjif,p2,p3
+endm
+;;*****************************************************************************
+.else macro dist
+ $pop $temp
+ if $temp ne $iftype
+ $StrucErr <else without if>
+ exitm
+ endif
+ $sn = $sn+1
+ $dist = $defdist
+ $getdist dist
+ $cjump %$sn
+ $pop $temp
+ $labl %$temp
+ $push $sn
+ $push $elsetype
+endm
+;;*****************************************************************************
+.endif macro
+ $pop $temp
+ if $temp ne $iftype
+ if $temp ne $elsetype
+ $StrucErr <endif without if>
+ exitm
+ endif
+ endif
+ $pop $temp
+ $labl %$temp
+ $pop $temp
+ if $elseiffound
+ $labl %$temp
+ endif
+ $pop $elseiffound
+endm
+;;*****************************************************************************
+.while macro tst,p2,p3
+ $peek $temp,%$st
+ if $temp eq $conjwhile
+ $pop $temp
+ else
+ $push $endloop
+ $orfound = 0
+ $sn = $sn + 1
+ $push $sn
+ $labl %$sn
+ $sn = $sn + 2
+ $push $sn
+ $endloop = $sn - 1
+ endif
+ $toptest <tst>,$whiletype,$conjwhile,p2,p3
+endm
+;;*****************************************************************************
+.endwhile macro
+ $pop $temp
+ if $temp ne $whiletype
+ $StrucErr <endwhile without while>
+ exitm
+ endif
+ $pop $temp
+ $dist = $near
+ $cjump %$temp
+ $labl %$temp+1
+ $pop $endloop
+endm
+;;*****************************************************************************
+;OS2SS-.repeat macro
+;OS2SS- $push $endloop
+;OS2SS- $push $leavefound
+;OS2SS- $sn = $sn+1
+;OS2SS- $labl %$sn
+;OS2SS- $push $sn
+;OS2SS- $push $repeattype
+;OS2SS- $sn = $sn+1
+;OS2SS- $endloop = $sn
+;OS2SS- $leavefound = 0
+;OS2SS-endm
+;;*****************************************************************************
+;OS2SS-.until macro tst,p2,p3
+;OS2SS- $until_2 p2,p3,tst
+;OS2SS-endm
+;OS2SS-$until_2 macro p2,p3,a1,a2,a3,a4,x1
+;OS2SS- $pop $temp
+;OS2SS- if $temp ne $repeattype
+;OS2SS- if $temp ne $conjuntil
+;OS2SS- $StrucErr <until without repeat>
+;OS2SS- exitm
+;OS2SS- endif
+;OS2SS- else
+;OS2SS- $orfound = 0
+;OS2SS- endif
+;OS2SS- $dist = $defdist
+;OS2SS- $getdist p2,p3
+;OS2SS- $getconj p2,p3
+;OS2SS-
+;OS2SS- if $andor eq $noconj
+;OS2SS- $pop $temp
+;OS2SS- ifb <a1>
+;OS2SS- $dist = $near
+;OS2SS- $cjump %$temp,f
+;OS2SS- else
+;OS2SS- $test <$temp,f>,<a1>,<a2>,<a3>,<a4>,<x1>
+;OS2SS- endif
+;OS2SS- if $orfound or $leavefound
+;OS2SS- $labl %$temp+1
+;OS2SS- endif
+;OS2SS- $pop $leavefound
+;OS2SS- $pop $endloop
+;OS2SS- else
+;OS2SS- $peek $temp,%$st
+;OS2SS- if $andor eq $and
+;OS2SS- $test <$temp,f>,<a1>,<a2>,<a3>,<a4>,<x1>
+;OS2SS- else
+;OS2SS- $orfound = 1
+;OS2SS- $test <$temp+1,t>,<a1>,<a2>,<a3>,<a4>,<x1>
+;OS2SS- endif
+;OS2SS- $push $conjuntil
+;OS2SS- endif
+;OS2SS-endm
+;;*****************************************************************************
+;OS2SS-.loop macro cond
+;OS2SS- $pop $temp
+;OS2SS- if $temp ne $repeattype
+;OS2SS- $StrucErr <loop without repeat>
+;OS2SS- exitm
+;OS2SS- endif
+;OS2SS- $pop $temp
+;OS2SS- $cloop %$temp,cond
+;OS2SS- if $leavefound
+;OS2SS- $labl %$temp+1
+;OS2SS- endif
+;OS2SS- $pop $leavefound
+;OS2SS- $pop $endloop
+;OS2SS-endm
+;;*****************************************************************************
+;OS2SS-.for macro index,equals,start,to,stop,by,step,dist
+;OS2SS- mov index,start
+;OS2SS- $push $endloop
+;OS2SS- $sn = $sn+1
+;OS2SS- $push $sn
+;OS2SS- $labl %$sn
+;OS2SS- $sn = $sn+1
+;OS2SS- $endloop = $sn
+;OS2SS- cmp index,stop
+;OS2SS- $dist = $defdist
+;OS2SS- ifb <step>
+;OS2SS- $push 1
+;OS2SS- $getdist by
+;OS2SS- $cjump %$sn,t,gt
+;OS2SS- else
+;OS2SS- $getdist dist
+;OS2SS- $push %(step)
+;OS2SS- if step lt 0
+;OS2SS- $cjump %$sn,t,lt
+;OS2SS- else
+;OS2SS- $cjump %$sn,t,gt
+;OS2SS- endif
+;OS2SS- endif
+;OS2SS- $push $fortype
+;OS2SS-endm
+;;*****************************************************************************
+;OS2SS-.next macro index
+;OS2SS- $pop $temp
+;OS2SS- if $temp ne $fortype
+;OS2SS- $StrucErr <next without for>
+;OS2SS- exitm
+;OS2SS- endif
+;OS2SS- $pop $temp
+;OS2SS- if $temp eq 1
+;OS2SS- inc index
+;OS2SS- else
+;OS2SS- if $temp eq -1
+;OS2SS- dec index
+;OS2SS- else
+;OS2SS- add index,$temp
+;OS2SS- endif
+;OS2SS- endif
+;OS2SS- $pop $temp
+;OS2SS- $dist = $near
+;OS2SS- $cjump %$temp
+;OS2SS- $labl %$temp+1
+;OS2SS- $pop $endloop
+;OS2SS-endm
+;;*****************************************************************************
+;OS2SS-.leave macro tst,p2,p3
+;OS2SS- $leave_2 p2,p3,tst
+;OS2SS-endm
+;OS2SS-$leave_2 macro p2,p3,a1,a2,a3,a4,x1
+;OS2SS- ife $endloop
+;OS2SS- $StrucErr <leave outside a loop>
+;OS2SS- exitm
+;OS2SS- endif
+;OS2SS- $leavefound = 1
+;OS2SS- $peek $temp,%$st
+;OS2SS- if $temp eq $conjleave
+;OS2SS- $pop $temp
+;OS2SS- else
+;OS2SS- $orfound = 0
+;OS2SS- $sn = $sn + 1
+;OS2SS- endif
+;OS2SS- $dist = 0
+;OS2SS- $getdist <a1>
+;OS2SS- if $dist
+;OS2SS- $cjump %$endloop
+;OS2SS- if $orfound
+;OS2SS- $labl %$sn
+;OS2SS- endif
+;OS2SS- else
+;OS2SS- $dist = $defdist
+;OS2SS- $getdist p2,p3
+;OS2SS- $getconj p2,p3
+;OS2SS-
+;OS2SS- if $andor eq $noconj
+;OS2SS- ifb <a1>
+;OS2SS- $cjump %$endloop,t
+;OS2SS- else
+;OS2SS- $test <$endloop,t>,<a1>,<a2>,<a3>,<a4>,<x1>
+;OS2SS- endif
+;OS2SS- if $orfound
+;OS2SS- $labl %$sn
+;OS2SS- endif
+;OS2SS- else
+;OS2SS- if $andor eq $and
+;OS2SS- $orfound = 1
+;OS2SS- $test <$sn,f>,<a1>,<a2>,<a3>,<a4>,<x1>
+;OS2SS- else
+;OS2SS- $test <$endloop,t>,<a1>,<a2>,<a3>,<a4>,<x1>
+;OS2SS- endif
+;OS2SS- $push $conjleave
+;OS2SS- endif
+;OS2SS- endif
+;OS2SS-endm
+;;*****************************************************************************
+else
+ $pop $temp
+ if $temp ne $notype
+ $StrucErr <open structure(s)>
+ endif
+.xcref $noconj,$and,$or,$short,$near,$andor,$temp,$temp2,$dist
+.xcref $notype,$conjif,$iftype,$elsetype,$whiletype,$conjwhile
+.xcref $repeattype,$conjuntil,$fortype,$conjleave,jncxz
+.xcref jeq,jgt,jlt,jneq,jngt,jnlt,jnna,jnnae,jnnb,jnnbe,jnnc,jnncxz
+.xcref jnne,jnng,jnnge,jnnl,jnnle,jnno,jnnp,jnns,jnnz,jnpe,jnpo,jbuild
+.xcref $getconj,$getdist,$poke,$peek,$push,$pop,$labl,$cjump,$cloop,$test
+;OS2SS-.xcref $toptest,$leave_2,$until_2,$strucerr,j,jn,jand,jnand,jnnand
+.xcref $toptest,$strucerr,j,jn,jand,jnand,jnnand
+.xcref jnnonzero,jnonzero,jnzero,jzero
+.xcref $st,$sn,$orfound,$elseiffound,$endloop,$leavefound,$defdist
+endif
+$st = 0
+$sn = 0
+$orfound = 0
+$elseiffound = 0
+$endloop = 0
+$leavefound = 0
+$defdist = $short
+$push %$notype
diff --git a/private/os2/os2ses/tmrqust.c b/private/os2/os2ses/tmrqust.c
new file mode 100644
index 000000000..85094dd94
--- /dev/null
+++ b/private/os2/os2ses/tmrqust.c
@@ -0,0 +1,125 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ tmrqust.c
+
+Abstract:
+
+ This module contains the handler for task manager requests.
+
+Author:
+
+ Avi Nathan (avin) 17-Jul-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+#include <stdio.h>
+#include <stdlib.h>
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "os2res.h"
+
+extern DWORD Os2ReturnCode;
+
+BOOL ServeTmRequest(PSCTMREQUEST PReq, PVOID PStatus)
+{
+ UINT StringCode = 0;
+
+#if DBG
+ IF_OD2_DEBUG( SESSIONMGR )
+ {
+ KdPrint(("ServeTmRequest: Request %u\n", PReq->Request));
+ }
+#endif
+ *(PDWORD) PStatus = 0;
+
+ switch (PReq->Request) {
+ case TmExit:
+ Os2ReturnCode = PReq->ExitResults;
+ if ((PReq->ExitResults & 0x80000000) != 0) {
+ switch (PReq->ExitResults & 0x7fffffff) {
+ case 295:
+ StringCode = IDS_OS2_INITFAIL;
+ break;
+
+ case ERROR_INVALID_SEGMENT_NUMBER:
+ StringCode = IDS_OS2_SEGNUMBER;
+ break;
+
+ case ERROR_EXE_MARKED_INVALID:
+ StringCode = IDS_OS2_EXEINVALID;
+ break;
+
+ case ERROR_INVALID_STACKSEG:
+ StringCode = IDS_OS2_STACKSEG;
+ break;
+
+ case ERROR_FILE_NOT_FOUND:
+ StringCode = IDS_OS2_NOFILE;
+ break;
+
+ case ERROR_PROC_NOT_FOUND:
+ StringCode = IDS_OS2_NOPROC;
+ break;
+
+ case ERROR_INVALID_ORDINAL:
+ StringCode = IDS_OS2_NOORDINAL;
+ break;
+
+ case ERROR_INVALID_STARTING_CODESEG:
+ StringCode = IDS_OS2_CODESEG;
+ break;
+
+ case ERROR_INVALID_MODULETYPE:
+ StringCode = IDS_OS2_MODULETYPE;
+ break;
+
+ case ERROR_BAD_EXE_FORMAT:
+ StringCode = IDS_OS2_EXEFORMAT;
+ break;
+
+ case ERROR_RELOC_CHAIN_XEEDS_SEGLIM:
+ StringCode = IDS_OS2_RELOCCHAIN;
+ break;
+
+ case ERROR_BAD_FORMAT:
+ StringCode = IDS_OS2_BADFORMAT;
+ break;
+
+ default:
+ _itoa(PReq->ExitResults & 0x7fffffff, PReq->ErrorText, 10);
+ StringCode = IDS_OS2_OS2CODE;
+ break;
+
+ }
+ }
+ TerminateSession();
+ Ow2Exit(StringCode, &PReq->ErrorText[0], Os2ReturnCode);
+ //*(PDWORD) PStatus = 0;
+ return(FALSE);
+ break;
+
+ case TmReleaseLPC:
+ EventReleaseLPC(PReq->ExitResults);
+ break;
+
+ default:
+ *(PDWORD) PStatus = (DWORD) -1; // STATUS_INVALID_PARAMETER;
+#if DBG
+ KdPrint(( "OS2SES: Unknown TaskMan request = %X\n",
+ PReq->Request
+ ));
+#endif
+ break;
+ }
+
+ return(TRUE); // Do reply
+}
diff --git a/private/os2/os2ses/trans.c b/private/os2/os2ses/trans.c
new file mode 100644
index 000000000..3aed693fd
--- /dev/null
+++ b/private/os2/os2ses/trans.c
@@ -0,0 +1,463 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ trans.c
+
+Abstract:
+
+ This module contains the translation procedures
+ for Vio, Kbd and Mou.
+
+Author:
+
+ Michael Jarus (mjarus) 28-Oct-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "event.h"
+#include "trans.h"
+#include <io.h>
+#include <stdio.h>
+#ifdef DBCS
+// MSKK Jun.28.1992 KazuM
+#include "vio.h"
+// MSKK Oct.01.1993 V-AkihiS
+// If NLS module for console doesn't present, then NO_CONSOLE_NLS switch
+// should be enable difinition.
+//#define NO_CONSOLE_NLS
+#endif
+
+
+MOUEVENTINFO LastMouseEvent = {0, 0L, 0, 0};
+KBD_MON_PACKAGE Os2KeyInfo[3];
+WORD LastVirtualKeyCode;
+WORD LastVirtualScanCode;
+WCHAR LastUnicodeChar;
+DWORD LastControlKeyState;
+
+ULONG
+Ow2KbdXlate(
+ ULONG ScanCode,
+ PKBD_XLATE_VARS pFlagArea,
+ PKBD_MON_PACKAGE pMonitorPack,
+ PVOID pTransTable
+ );
+
+USHORT
+MapWin2Os2KbdState(
+ IN DWORD WinState
+ )
+{
+ USHORT Os2Status = 0;
+
+ if ( WinState & RIGHT_ALT_PRESSED )
+ Os2Status |= OS2_ALT | OS2_RIGHTALT;
+
+ if ( WinState & LEFT_ALT_PRESSED )
+ Os2Status |= OS2_ALT | OS2_LEFTALT;
+
+ if ( WinState & RIGHT_CTRL_PRESSED)
+ Os2Status |= OS2_CONTROL | OS2_RIGHTCONTROL;
+
+ if ( WinState & LEFT_CTRL_PRESSED )
+ Os2Status |= OS2_CONTROL | OS2_LEFTCONTROL;
+
+ //if ( WinState & SHIFT_PRESSED )
+ // Os2Status |= OS2_RIGHTSHIFT | OS2_LEFTSHIFT;
+
+ if ( WinState & NUMLOCK_ON )
+ Os2Status |= OS2_NUMLOCK_ON;
+
+ if ( WinState & SCROLLLOCK_ON )
+ Os2Status |= OS2_SCROLLLOCK_ON;
+
+ if ( WinState & CAPSLOCK_ON )
+ Os2Status |= OS2_CAPSLOCK_ON;
+
+ return(Os2Status);
+}
+
+#define MAPOS2STATE (OS2_ALT | OS2_CONTROL | OS2_SCROLLLOCK_ON | OS2_NUMLOCK_ON | OS2_CAPSLOCK_ON | OS2_ANYCONTRL | OS2_ANYALT)
+
+DWORD
+MapWin2Os2KbdInfo(IN PKEY_EVENT_RECORD WinKey,
+ OUT PKEYEVENTINFO Os2Key)
+{
+ ULONG Rc;
+ BOOL DupPack = FALSE, ControlPack = FALSE;
+ USHORT Os2State, OldState;
+
+ /*
+ * This is a workaround for a console (TS) "feature": sometimes the
+ * make or nreak of shift/control/alt keys are not passed (eg. after
+ * pressing CTRL-ESC and returning to the window, no CTRL-UP is generated.
+ * (mjarus 9/7/93):
+ */
+
+ Os2State = MapWin2Os2KbdState(WinKey->dwControlKeyState);
+
+ if (( Os2State !=
+ (KbdQueue->Setup.fsState & MAPOS2STATE)) ||
+ ((WinKey->dwControlKeyState & SHIFT_PRESSED) &&
+ !(KbdQueue->Setup.fsState & (OS2_LEFTSHIFT | OS2_RIGHTSHIFT))) ||
+ (!(WinKey->dwControlKeyState & SHIFT_PRESSED) &&
+ (KbdQueue->Setup.fsState & (OS2_LEFTSHIFT | OS2_RIGHTSHIFT)))
+ )
+ {
+ if ((WinKey->wVirtualKeyCode != VK_SHIFT) &&
+ (WinKey->wVirtualKeyCode != VK_CONTROL) &&
+ (WinKey->wVirtualKeyCode != VK_MENU))
+ {
+ ControlPack = TRUE; // BUGBUG: generate another 1 or more packages
+ OldState = KbdQueue->Setup.fsState;
+ KbdQueue->Setup.fsState =
+ (KbdQueue->Setup.fsState & ~MAPOS2STATE) | Os2State;
+ Ow2KbdXlateVars.XHotKeyShift =
+ (Ow2KbdXlateVars.XHotKeyShift & ~MAPOS2STATE) | Os2State;
+
+ if (((WinKey->dwControlKeyState & SHIFT_PRESSED) &&
+ !(KbdQueue->Setup.fsState & (OS2_LEFTSHIFT | OS2_RIGHTSHIFT))) ||
+ (!(WinKey->dwControlKeyState & SHIFT_PRESSED) &&
+ (KbdQueue->Setup.fsState & (OS2_LEFTSHIFT | OS2_RIGHTSHIFT))))
+ {
+ KbdQueue->Setup.fsState &= ~OS2_ANYSHIFT;
+ Ow2KbdXlateVars.XHotKeyShift &= ~OS2_ANYSHIFT;
+ if (WinKey->dwControlKeyState & SHIFT_PRESSED)
+ {
+ KbdQueue->Setup.fsState |= OS2_RIGHTSHIFT;
+ Ow2KbdXlateVars.XHotKeyShift |= OS2_RIGHTSHIFT;
+ }
+ }
+ }
+ }
+
+ /*
+ * This is a workaround for a console (TS) "feature": sometimes after an
+ * accent, the console generates another package with the same VK and
+ * ScanCode but different ASCII/Unicode. (mjarus 5/7/93):
+ * eg. (for BE):
+ * [{ - VK DD, Scan 1A, Unicode 0
+ * zZ - 57, 2C 5E (^)
+ * 57, 2C 77 (w)
+ */
+
+ if (WinKey->bKeyDown)
+ {
+ if ((LastVirtualKeyCode == WinKey->wVirtualKeyCode) &&
+ (LastVirtualScanCode == WinKey->wVirtualScanCode) &&
+ (LastControlKeyState == WinKey->dwControlKeyState) &&
+ (LastUnicodeChar != WinKey->uChar.UnicodeChar))
+ {
+#if defined(DBCS) && !defined(NO_CONSOLE_NLS)
+// MSKK Aug.10.1993 V-AkihiS
+// When IME is active, WinKey->wVirtualScanCode is always 0.
+// So we should check IME is active or not.
+ if (!(WinKey->dwControlKeyState & NLS_IME_CONVERSION))
+ DupPack = TRUE;
+#else
+ DupPack = TRUE;
+#endif
+ }
+
+ LastVirtualKeyCode = WinKey->wVirtualKeyCode;
+ LastVirtualScanCode = WinKey->wVirtualScanCode;
+ LastUnicodeChar = WinKey->uChar.UnicodeChar;
+ LastControlKeyState = WinKey->dwControlKeyState;
+ }
+
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ {
+ if (WinKey->bKeyDown && !DupPack)
+ {
+ KdPrint(("***************************************************************************\n"));
+ } else
+ {
+ KdPrint(("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"));
+ }
+ KdPrint(("KbdInfo: VKey %x, VScan %x, Control %x, char(W) %x %s(count %u)\n",
+ WinKey->wVirtualKeyCode, WinKey->wVirtualScanCode,
+ WinKey->dwControlKeyState, WinKey->uChar.UnicodeChar,
+ (WinKey->bKeyDown ? "" : "(Up)"), WinKey->wRepeatCount));
+
+ if (ControlPack)
+ {
+ KdPrint((" => Adding control package, from %x to %x\n",
+ OldState, KbdQueue->Setup.fsState));
+ }
+ }
+#endif
+
+ if (DupPack)
+ {
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ {
+ KdPrint((" => Duplicate package\n"));
+ }
+#endif
+ return(0);
+ }
+
+ RtlZeroMemory(&Os2KeyInfo[0], 3 * sizeof(KBD_MON_PACKAGE));
+ Os2KeyInfo[0].KeyInfo.fbStatus = 0x40;
+ Os2KeyInfo[0].KeyInfo.fsState = KbdQueue->Setup.fsState;
+ Os2KeyInfo[0].DeviceFlag = WinKey->wVirtualScanCode;
+ if (!WinKey->bKeyDown)
+ {
+ Os2KeyInfo[0].DeviceFlag |= 0x80; // BREAK key
+ }
+
+ if ( WinKey->dwControlKeyState & ENHANCED_KEY )
+ {
+ Ow2KbdXlateVars.XlateFlags |= SecPrefix; // Have seen E0 prefix
+ }
+
+#ifdef DBCS
+// MSKK Aug.04.1993 V-AkihiS
+ //
+ // Get NlsShift
+ //
+ Os2KeyInfo[0].KeyInfo.bNlsShift = MapWinToOs2KbdNlsShift(WinKey);
+
+ if ((Os2KeyInfo[0].KeyInfo.bNlsShift & OS2_NLS_IME_CONVERSION) &&
+ (! WinKey->wVirtualScanCode))
+ {
+ Rc = MapWinToOs2KbdNlsChar(WinKey, &Os2KeyInfo[0]);
+ if (Rc == 2)
+ {
+ Os2Key->KeyInfo[0] = Os2KeyInfo[0];
+ (Os2Key + 1)->KeyInfo[0] = Os2KeyInfo[1];
+ } else
+ {
+ Os2Key->KeyInfo[0] = Os2KeyInfo[0];
+ }
+ } else
+ {
+ Rc = Ow2KbdXlate(
+ Os2KeyInfo[0].DeviceFlag, // ScanCode,
+ &Ow2KbdXlateVars, // pFlagArea,
+ &Os2KeyInfo[0], // pMonitorPack,
+ Ow2KbdScanTable // pTransTable
+ );
+ if (Rc == 2)
+ {
+ Os2Key->KeyInfo[0] = Os2KeyInfo[1];
+ (Os2Key + 1)->KeyInfo[0] = Os2KeyInfo[0];
+ } else
+ {
+ Os2Key->KeyInfo[0] = Os2KeyInfo[0];
+ //
+ // If SBCS katakana, set scan code to 0.
+ //
+ if ((SesGrp->KbdCP == 932) &&
+ (Os2Key->KeyInfo[0].KeyInfo.chChar >= 0xa0) &&
+ (Os2Key->KeyInfo[0].KeyInfo.chChar <= 0xdf))
+ Os2Key->KeyInfo[0].KeyInfo.chScan = 0;
+ }
+ }
+#else
+ Rc = Ow2KbdXlate(
+ Os2KeyInfo[0].DeviceFlag, // ScanCode,
+ &Ow2KbdXlateVars, // pFlagArea,
+ &Os2KeyInfo[0], // pMonitorPack,
+ Ow2KbdScanTable // pTransTable
+ );
+ if (Rc == 2)
+ {
+ Os2Key->KeyInfo[0] = Os2KeyInfo[1];
+ (Os2Key + 1)->KeyInfo[0] = Os2KeyInfo[0];
+ } else
+ {
+ Os2Key->KeyInfo[0] = Os2KeyInfo[0];
+ }
+#endif
+
+
+ if (!WinKey->bKeyDown)
+ Os2Key->KeyInfo[0].DeviceFlag |= 0x80;
+
+ /*
+ * keep Win info of RepeatCount
+ */
+
+ Os2Key->wRepeatCount = WinKey->wRepeatCount;
+
+ KbdQueue->Setup.fsState = Os2KeyInfo[0].KeyInfo.fsState;
+
+#if DBG
+ IF_OD2_DEBUG( KBD )
+ {
+ KdPrint((" Rc %lu\n", Rc));
+ KdPrint((" 1. Ch %x, Sc %x, fbStatus %x, NLS %x, fsState %x MF %x, DF %x, KF %x\n",
+ Os2Key->KeyInfo[0].KeyInfo.chChar,
+ Os2Key->KeyInfo[0].KeyInfo.chScan,
+ Os2Key->KeyInfo[0].KeyInfo.fbStatus,
+ Os2Key->KeyInfo[0].KeyInfo.bNlsShift,
+ Os2Key->KeyInfo[0].KeyInfo.fsState,
+ Os2Key->KeyInfo[0].MonitorFlag,
+ Os2Key->KeyInfo[0].DeviceFlag,
+ Os2Key->KeyInfo[0].KeyboardFlag
+ ));
+
+ if (Rc == 2)
+ {
+ KdPrint((" 2. Ch %x, Sc %x, fbStatus %x, NLS %x, fsState %x MF %x, DF %x, KF %x\n",
+ (Os2Key + 1)->KeyInfo[0].KeyInfo.chChar,
+ (Os2Key + 1)->KeyInfo[0].KeyInfo.chScan,
+ (Os2Key + 1)->KeyInfo[0].KeyInfo.fbStatus,
+ (Os2Key + 1)->KeyInfo[0].KeyInfo.bNlsShift,
+ (Os2Key + 1)->KeyInfo[0].KeyInfo.fsState,
+ (Os2Key + 1)->KeyInfo[0].MonitorFlag,
+ (Os2Key + 1)->KeyInfo[0].DeviceFlag,
+ (Os2Key + 1)->KeyInfo[0].KeyboardFlag
+ ));
+ }
+ if (Ow2KbdXlateVars.XlateFlags)
+ {
+ /*
+ * DumpKeyOnce Equ 01h
+ * PSKeyDown Equ 02h
+ * SecPrefix Equ 04h
+ * NormalAlt Equ 08h
+ * Use3Index Equ 10h
+ * PseudoCtl Equ 20h
+ * E1Prefix Equ 40h
+ */
+
+ KdPrint((" XlateFlags - %x\n", Ow2KbdXlateVars.XlateFlags));
+ }
+ if (Ow2KbdXlateVars.XPSGFlags)
+ {
+ /*
+ * SQMODE Equ 0200h
+ * SGInUse Equ 0080h
+ * SG3xBox Equ 0040h
+ * ActiveSG Equ 0020h
+ * Flushing Equ 0010h
+ * NowPaused Equ 0008h
+ * PrevAccent Equ 0007h
+ * WakeUpSent Equ 0100h
+ */
+
+ KdPrint((" XPSGFlags - %x\n", Ow2KbdXlateVars.XPSGFlags));
+ }
+ }
+#endif
+
+ if (!Rc)
+ {
+ return(Rc);
+ }
+
+ /*
+ * save info for next kbd
+ */
+
+ KbdLastKey = WinKey->wVirtualKeyCode;
+ KbdLastKeyDown = WinKey->bKeyDown;
+ return(Rc);
+}
+
+
+BOOL
+MapWin2Os2MouEvent(OUT PMOUEVENTINFO Mou,
+ IN PMOUSE_EVENT_RECORD Event)
+{
+ USHORT State = 0;
+
+ if (Event->dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED)
+ State |= OS2_MOUSE_BN1_DOWN;
+ if (Event->dwButtonState & RIGHTMOST_BUTTON_PRESSED)
+ State |= OS2_MOUSE_BN2_DOWN;
+ if (Event->dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED)
+ State |= OS2_MOUSE_BN3_DOWN;
+ if (Event->dwEventFlags & MOUSE_MOVED)
+ { if (State)
+ State >>= 1; /* shift right to set motion */
+ else
+ State = OS2_MOUSE_MOTION;
+ }
+ /* BUGBUG=> Double-Click */
+ /* BUGBUG=> ignore other buttons */
+
+ /* State==0 => releae */
+
+ if (State && !(State & MouEventMask))
+ {
+ // not-release-event which is 'mask-out' - ignore it
+
+#if DBG
+ IF_OD2_DEBUG( MOU )
+ {
+ KdPrint(("MapWin2Os2MouEvent: mask out event fs %x, Mask %x (Button %x, Flag %x)\n",
+ State, MouEventMask, Event->dwButtonState, Event->dwEventFlags));
+ }
+#endif
+ return (0L);
+ }
+
+ if (!State && (!LastMouseEvent.fs ||
+ (LastMouseEvent.fs == OS2_MOUSE_MOTION)))
+ {
+ // this event breaks (release) 'masked-out' event - ignore it
+
+#if DBG
+ IF_OD2_DEBUG( MOU )
+ {
+ KdPrint(("MapWin2Os2MouEvent: release of mask out event fs %x, Mask %x (Button %x, Flag %x)\n",
+ State, MouEventMask, Event->dwButtonState, Event->dwEventFlags));
+ }
+#endif
+ return (0L);
+ }
+
+ Mou->fs = State;
+
+ /* BUGBUG=> support mickeys and pels */
+
+ Mou->row = Event->dwMousePosition.Y;
+ Mou->col = Event->dwMousePosition.X;
+
+ if ((Event->dwEventFlags & MOUSE_MOVED) &&
+ (LastMouseEvent.row == Mou->row) &&
+ (LastMouseEvent.col == Mou->col))
+ {
+ // this events are "noises" that the console doesn't mask
+ // (i.e. the same action with the same position)
+
+#if DBG
+ IF_OD2_DEBUG( MOU )
+ {
+ KdPrint(("MapWin2Os2MouEvent: noise event - fs %x, Pos %u:%u (Button %x, Flag %x)\n",
+ Mou->fs, Mou->row, Mou->col,
+ Event->dwButtonState, Event->dwEventFlags));
+ }
+#endif
+ return (0L);
+ }
+
+ LastMouseEvent = *Mou;
+
+#if DBG
+ IF_OD2_DEBUG( MOU )
+ {
+ KdPrint(("MapWin2Os2MouEvent: Button %x, Flag %x => fs %x, Pos %u:%u\n",
+ Event->dwButtonState, Event->dwEventFlags,
+ Mou->fs, Mou->row, Mou->col));
+ }
+#endif
+ return (1L);
+}
+
diff --git a/private/os2/os2ses/trans.h b/private/os2/os2ses/trans.h
new file mode 100644
index 000000000..44a4cda00
--- /dev/null
+++ b/private/os2/os2ses/trans.h
@@ -0,0 +1,491 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ trans.h
+
+Abstract:
+
+ Prototypes for functions & macros in trans.c
+
+Author:
+
+ Michael Jarus (mjarus) 27-Oct-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+
+PVOID Ow2KbdScanTable;
+
+CONSOLE_CURSOR_INFO OldWinCurInfo; /* Win Cursor Info (saved in PopUp) */
+
+typedef struct _KBD_XLATE_VARS
+{
+ USHORT XDRFlags; // => delete: See XCOMPLETE below. Not
+ // used at interrupt time.
+ USHORT XHotKeyShift; // Interrupt driven shift status
+ USHORT XPSGFlags; // Copy of caller's PSG flags.
+ // (changed byte->word and position in structure per DCR8)
+ UCHAR XlateFlags; // See equates below.
+ UCHAR ToggleFlags; // See equates below.
+ UCHAR XInputMode; // Copy of desired input mode. 0 - cooked, SHIFTREPORT - to test this mode
+ UCHAR XAltKeyPad; // Accumulator for Alt-nnn entry
+ UCHAR OtherFlags; // NEW: for InterruptTime
+} KBD_XLATE_VARS, *PKBD_XLATE_VARS;
+
+// XPSGFlags
+#define PrevAccent 7 // Bits where accent number saved til next keystroke.
+// XlateFlags
+#define SecPrefix 4 // G keyboard E0 prefix scan code just seen.
+// OtherFlags
+#define InterruptTime 4 // bit 2 - Currently processing an interrupt.
+
+KBD_XLATE_VARS Ow2KbdXlateVars;
+
+DWORD VioSetScreenSize(IN SHORT Row, IN SHORT Col, IN HANDLE hConsole);
+DWORD SetScreenSizeParm(IN SHORT Row, IN SHORT Col);
+
+/* macros for char translation */
+
+/*
+ * OS2-->WIN : VIO-Character
+ * =============
+ */
+
+#ifdef DBCS
+// MSKK Jun.26.1992 KazuM
+// MSKK Oct.26.1992 V-AKihiS
+#define MapOs2ToWinChar(Os2Char, NumLen, WinChar) \
+ MultiByteToWideChar( \
+ (UINT)SesGrp->VioCP, \
+ OS2SS_NLS_MB_DEFAULT, \
+ (LPSTR)&Os2Char, \
+ (int)NumLen, \
+ (LPWSTR)&WinChar, \
+ (int)1);
+
+#else
+#define MapOs2ToWinChar(Os2Char, WinChar) \
+ MultiByteToWideChar( \
+ (UINT)SesGrp->VioCP, \
+ OS2SS_NLS_MB_DEFAULT, \
+ (LPSTR)&Os2Char, \
+ (int)1, \
+ (LPWSTR)&WinChar, \
+ (int)1);
+#endif
+
+/*
+ * OS2-->WIN : VIO-Attribute
+ * =============
+ */
+
+#ifdef DBCS
+// MSKK Jun.28.1992 KazuM
+WORD
+MapOs2ToWinAttr(
+ IN PBYTE Os2Attr
+ );
+#else
+#define MapOs2ToWinAttr(Os2Attr) \
+ ((WORD) Os2Attr)
+// ((WORD) (Os2Attr & ~OS2_BACKGROUND_BLINKING))
+#endif
+
+/*** Nt WinCon attribute flags
+
+#define FOREGROUND_BLUE 0x0001 // text color contains blue.
+#define FOREGROUND_GREEN 0x0002 // text color contains green.
+#define FOREGROUND_RED 0x0004 // text color contains red.
+#define FOREGROUND_INTENSITY 0x0008 // text color is intensified.
+#define BACKGROUND_BLUE 0x0010 // background color contains blue.
+#define BACKGROUND_GREEN 0x0020 // background color contains green.
+#define BACKGROUND_RED 0x0040 // background color contains red.
+#define BACKGROUND_INTENSITY 0x0080 // background color is intensified. ***/
+
+/*** OS/2 screen attributes ***/
+
+#define OS2_FOREGROUND_BLUE 0x0001 // text color contains blue.
+#define OS2_FOREGROUND_GREEN 0x0002 // text color contains green.
+#define OS2_FOREGROUND_RED 0x0004 // text color contains red.
+#define OS2_FOREGROUND_INTENSITY 0x0008 // text color is intensified.
+#define OS2_BACKGROUND_BLUE 0x0010 // background color contains blue.
+#define OS2_BACKGROUND_GREEN 0x0020 // background color contains green.
+#define OS2_BACKGROUND_RED 0x0040 // background color contains red.
+#define OS2_BACKGROUND_BLINKING 0x0080 // blinking character.
+#ifdef DBCS
+// MSKK Oct.13.1993 V-AkihiS
+#define OS2_COMMON_LVB_SBCS 0x00 // SBCS character
+#define OS2_COMMON_LVB_LEADING_BYTE 0x01 // DBCS leading byte
+#define OS2_COMMON_LVB_TRAILING_BYTE 0x81 // DBCS trailing byte
+#endif
+
+/*
+ * OS2-->WIN : VIO-Character-string
+ * ====================
+ */
+
+/*
+ * OS2-->WIN : VIO-Cell-string
+ * ===============
+ */
+
+#ifdef DBCS
+// MSKK Oct.26.1992 V-AkihiS
+#define MapOs2ToWinCellStr(DestChar, DestAttr, Sour, Length, NumWide) \
+ { int i, j; \
+ PBYTE os2Cell; \
+ PWORD winAttr; \
+ PBYTE winChar; \
+ \
+ os2Cell = Sour; \
+ winChar = (PBYTE)DestChar; \
+ winAttr = DestAttr; \
+ for (i=j=0; i<(int)Length; winChar[i]=(os2Cell[j]), \
+ winAttr[i++]=MapOs2ToWinAttr(&os2Cell[j+1]), \
+ j += (SesGrp->VioLength2CellShift<<1)\
+ ); \
+ if (CheckBisectStringA((DWORD)SesGrp->VioCP, \
+ (PCHAR)Ow2VioDataAddress, \
+ (DWORD)Length)) { \
+ *((PCHAR)Ow2VioDataAddress+Length-1) = ' '; \
+ } \
+ NumWide = Length; \
+ }
+#else
+#define MapOs2ToWinCellStr(DestChar, DestAttr, Sour, Length, NumWide) \
+ { int i, j; \
+ PBYTE os2Cell; \
+ PWORD winAttr; \
+ PBYTE winChar; \
+ \
+ os2Cell = Sour; \
+ winChar = (PBYTE)DestChar; \
+ winAttr = DestAttr; \
+ for (i=j=0; i<(int)Length; winChar[i]=(os2Cell[j++]), \
+ winAttr[i++]=MapOs2ToWinAttr(os2Cell[j++])); \
+ NumWide = Length; \
+ }
+#endif
+
+/*
+ * OS2-->WIN : VIO-CursorPosition
+ * ==================
+ */
+
+DWORD MapOs2ToWinCursor(IN OUT PVIOCURSORINFO pCursorInfo,
+ OUT PCONSOLE_CURSOR_INFO lpCursorInfo);
+/*
+ * WIN-->OS2 : VIO-Character
+ * =============
+ */
+
+#define MapWin2Os2Char(WinChar, Os2Char) \
+ { \
+ BOOL Bool; \
+ \
+ WideCharToMultiByte( \
+ (UINT)SesGrp->VioCP, \
+ OS2SS_NLS_WC_DEFAULT, \
+ (LPWSTR)&WinChar, \
+ (int)1, \
+ (LPSTR)&Os2Char, \
+ (int)1, \
+ NULL, \
+ &Bool); \
+ } \
+
+/*
+ * WIN-->OS2 : VIO-Attribute
+ * =============
+ */
+
+#ifdef DBCS
+// MSKK Jun.24.1992 KazuM
+VOID
+MapWin2Os2Attr(
+ IN WORD NtAttr,
+ OUT PBYTE Os2Attr
+ );
+#else
+#define MapWin2Os2Attr(NtAttr) \
+ ((BYTE)NtAttr)
+// ((BYTE)(NtAttr & ~OS2_BACKGROUND_BLINKING))
+#endif
+
+/*
+ * WIN-->OS2 : VIO-Character-string
+ * ====================
+ */
+
+/* BUGBUG=> Add support for NLS & UNICODE */
+
+#define MapWin2Os2CharStr(Dest, Sour, Length, NumChar) \
+ { \
+ BOOL Bool; \
+ \
+ NumChar = WideCharToMultiByte( \
+ (UINT)SesGrp->VioCP, \
+ OS2SS_NLS_WC_DEFAULT, \
+ (LPWSTR)Sour, \
+ (int)(Length), \
+ (LPSTR)Dest, \
+ (int)(KBD_OFFSET - WIDE_OFFSET), \
+ NULL, \
+ &Bool); \
+ } \
+
+/*
+ * WIN-->OS2 : VIO-Cell-string
+ * ===============
+ */
+
+#ifdef DBCS
+// MSKK Oct.26.1992 V-AkihiS
+// MSKK Nov.07.1992 V-AkihiS
+#define MapWin2Os2CellStr(Dest, SourChar, SourAttr, Length, NumChar) \
+ { int i, j; \
+ PBYTE os2Cell; \
+ PWORD winAttr; \
+ PBYTE winChar; \
+ BOOL Bool; \
+ BYTE c; \
+ BYTE Os2Attr[3]; \
+ \
+ os2Cell = Dest; \
+ winChar = (PBYTE)SourChar; \
+ winAttr = SourAttr; \
+ \
+ for (i=j=0; i<(int)Length;) \
+ { \
+ MapWin2Os2Attr(winAttr[i],Os2Attr); \
+ if (Ow2NlsIsDBCSLeadByte(c=winChar[i], SesGrp->VioCP)) { \
+ if (i <(int) (NumChar-1)) { \
+ if (SesGrp->VioLength2CellShift == 1) { \
+ os2Cell[j++]=c; \
+ os2Cell[j++]=Os2Attr[0]; \
+ i++; \
+ MapWin2Os2Attr(winAttr[i],Os2Attr); \
+ os2Cell[j++]=winChar[i]; \
+ os2Cell[j++]=Os2Attr[0]; \
+ i++; \
+ } \
+ else { \
+ os2Cell[j++]=c; \
+ os2Cell[j++]=Os2Attr[0]; \
+ os2Cell[j++]=Os2Attr[1]; \
+ os2Cell[j++]=Os2Attr[2]; \
+ i++; \
+ MapWin2Os2Attr(winAttr[i],Os2Attr); \
+ os2Cell[j++]=winChar[i]; \
+ os2Cell[j++]=Os2Attr[0]; \
+ os2Cell[j++]=Os2Attr[1]; \
+ os2Cell[j++]=Os2Attr[2]; \
+ i++; \
+ } \
+ } \
+ else { \
+ if (SesGrp->VioLength2CellShift == 1) { \
+ os2Cell[j++]=' '; \
+ os2Cell[j++]=Os2Attr[0]; \
+ i++; \
+ } \
+ else { \
+ os2Cell[j++]=' '; \
+ os2Cell[j++]=Os2Attr[0]; \
+ os2Cell[j++]=Os2Attr[1]; \
+ os2Cell[j++]=Os2Attr[2]; \
+ i++; \
+ } \
+ } \
+ } \
+ else { \
+ if (SesGrp->VioLength2CellShift == 1) { \
+ os2Cell[j++]=c; \
+ os2Cell[j++]=Os2Attr[0]; \
+ i++; \
+ } \
+ else { \
+ os2Cell[j++]=c; \
+ os2Cell[j++]=Os2Attr[0]; \
+ os2Cell[j++]=Os2Attr[1]; \
+ os2Cell[j++]=Os2Attr[2]; \
+ i++; \
+ } \
+ } \
+ } \
+ }
+#else
+#define MapWin2Os2CellStr(Dest, SourChar, SourAttr, Length, NumChar) \
+ { int i, j; \
+ PBYTE os2Cell; \
+ PWORD winAttr; \
+ PBYTE winChar; \
+ \
+ os2Cell = Dest; \
+ winChar = (PBYTE)SourChar; \
+ winAttr = SourAttr; \
+ \
+ NumChar = Length; \
+ for (i=j=0; i<(int)NumChar;) \
+ { os2Cell[j++]=winChar[i]; \
+ os2Cell[j++]=MapWin2Os2Attr(winAttr[i++]); \
+ } \
+ }
+#endif
+
+/*
+ * WIN-->OS2 : VIO-CursorPosition
+ * ==================
+ */
+
+DWORD MapWin2Os2Cursor( IN CONSOLE_CURSOR_INFO lpCursorInfo,
+ OUT PVIOCURSORINFO CursorInfo);
+
+/*
+ * WIN-->OS2 : KBD-KeyInfo
+ * ===========
+ * 1. KBD-Status
+ * 2. KBD-Character
+ */
+
+// DWORD MapWin2Os2KbdInfo(IN PKEY_EVENT_RECORD WinKey, in event.h
+// OUT PKEYEVENTINFO Os2Key);
+#ifdef DBCS
+// MSKK May.18.1992 KazuM
+BYTE MapWinToOs2KbdNlsShift(IN PKEY_EVENT_RECORD WinKey);
+BYTE MapWinToOs2KbdInterim(IN PKEY_EVENT_RECORD WinKey);
+BYTE MapWinToOs2KbdNlsShiftReport(IN PKEY_EVENT_RECORD WinKey,
+ IN PKBDKEYINFO Os2Key);
+VOID GetNlsMode(IN PKBDINFO KbdInfo);
+VOID SetNlsMode(IN KBDINFO KbdInfo);
+#endif
+
+/* NT win KBD definitions
+
+#define RIGHT_ALT_PRESSED 0x0001 // the right alt key is pressed.
+#define LEFT_ALT_PRESSED 0x0002 // the left alt key is pressed.
+#define RIGHT_CTRL_PRESSED 0x0004 // the right ctrl key is pressed.
+#define LEFT_CTRL_PRESSED 0x0008 // the left ctrl key is pressed.
+#define SHIFT_PRESSED 0x0010 // the shift key is pressed.
+#define NUMLOCK_ON 0x0020 // the numlock light is on.
+#define SCROLLLOCK_ON 0x0040 // the scrolllock light is on.
+#define CAPSLOCK_ON 0x0080 // the capslock light is on.
+#define ENHANCED_KEY 0x0100 // the key is enhanced. ***/
+
+/* OS2 Kbd definitions (bsedev.h) */
+
+#define OS2_RIGHTSHIFT 0x0001
+#define OS2_LEFTSHIFT 0x0002
+#define OS2_CONTROL 0x0004
+#define OS2_ALT 0x0008
+#define OS2_SCROLLLOCK_ON 0x0010
+#define OS2_NUMLOCK_ON 0x0020
+#define OS2_CAPSLOCK_ON 0x0040
+#define OS2_INSERT_ON 0x0080
+#define OS2_LEFTCONTROL 0x0100
+#define OS2_LEFTALT 0x0200
+#define OS2_RIGHTCONTROL 0x0400
+#define OS2_RIGHTALT 0x0800
+#define OS2_SCROLLLOCK 0x1000
+#define OS2_NUMLOCK 0x2000
+#define OS2_CAPSLOCK 0x4000
+#define OS2_SYSREQ 0x8000
+
+#define OS2_ANYSHIFT (OS2_RIGHTSHIFT | OS2_LEFTSHIFT)
+#define OS2_ANYALT (OS2_RIGHTALT | OS2_LEFTALT)
+#define OS2_ANYCONTRL (OS2_RIGHTCONTROL | OS2_LEFTCONTROL)
+
+#define KBDINFO_STATE_MASK (USHORT)(OS2_RIGHTSHIFT | OS2_LEFTSHIFT | OS2_CONTROL | OS2_ALT | OS2_SCROLLLOCK_ON | OS2_NUMLOCK_ON | OS2_CAPSLOCK_ON | OS2_INSERT_ON | OS2_SYSREQ)
+
+#ifdef DBCS
+// MSKK May.15.1992 KazuM
+#define OS2_NLS_IME_CONVERSION 0x80
+#endif
+
+/*
+ * WIN-->OS2 : MOU-Event
+ * =========
+ */
+
+BOOL MapWin2Os2MouEvent(OUT PMOUEVENTINFO Mou, IN PMOUSE_EVENT_RECORD Event);
+
+/*** NT win mouse definitions
+ //
+ // ButtonState flags
+ //
+
+#define FROM_LEFT_1ST_BUTTON_PRESSED 0x0001
+#define RIGHTMOST_BUTTON_PRESSED 0x0002
+#define FROM_LEFT_2ND_BUTTON_PRESSED 0x0004
+#define FROM_LEFT_3RD_BUTTON_PRESSED 0x0008
+#define FROM_LEFT_4TH_BUTTON_PRESSED 0x0010
+
+ //
+ // EventFlags
+ //
+
+#define MOUSE_MOVED 0x0001
+#define DOUBLE_CLICK 0x0002 ***/
+
+/* OS2 Mouse definitions (bsedev.h) */
+
+#define OS2_MOUSE_MOTION 0x0001
+#define OS2_MOUSE_MOTION_WITH_BN1_DOWN 0x0002
+#define OS2_MOUSE_BN1_DOWN 0x0004
+#define OS2_MOUSE_MOTION_WITH_BN2_DOWN 0x0008
+#define OS2_MOUSE_BN2_DOWN 0x0010
+#define OS2_MOUSE_MOTION_WITH_BN3_DOWN 0x0020
+#define OS2_MOUSE_BN3_DOWN 0x0040
+
+#define WIN_BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | RIGHTMOST_BUTTON_PRESSED | FROM_LEFT_2ND_BUTTON_PRESSED)
+
+/*
+ * routines to update Vio LVB (in violvb.c)
+ */
+
+VOID VioLVBCopyStr( IN PUCHAR Sour,
+ IN COORD Coord,
+ IN ULONG Length);
+
+VOID VioLVBFillAtt( IN PBYTE pAttr,
+ IN COORD Coord,
+ IN ULONG Length);
+
+#ifdef DBCS
+// MSKK Oct.13.1993 V-AkihiS
+VOID VioLVBFillChar(IN PBYTE Char,
+ IN COORD Coord,
+ IN ULONG Length);
+#else
+VOID VioLVBFillChar(IN BYTE Char,
+ IN COORD Coord,
+ IN ULONG Length);
+#endif
+
+VOID VioLVBFillCharAndScroll(IN BYTE Char,
+ IN COORD Coord,
+ IN ULONG Length);
+
+VOID VioLVBFill2CharsAndScroll(IN BYTE Char1,
+ IN BYTE Char2,
+ IN COORD Coord,
+ IN ULONG Length);
+
+VOID VioLVBFillCell(IN PBYTE pCell,
+ IN COORD Coord,
+ IN ULONG Length);
+
+VOID VioLVBCopyCellStr(IN PUCHAR Sour,
+ IN COORD Coord,
+ IN ULONG Length);
+
+VOID VioLVBScrollBuff(IN DWORD Count);
diff --git a/private/os2/os2ses/util.c b/private/os2/os2ses/util.c
new file mode 100644
index 000000000..47ce35dbe
--- /dev/null
+++ b/private/os2/os2ses/util.c
@@ -0,0 +1,899 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ util.c
+
+Abstract:
+
+ This module contains the common utilities used in OS2SES module
+
+Author:
+
+ Avi Nathan (avin) 17-Jul-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "os2win.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <direct.h>
+#include <string.h>
+#include <ctype.h>
+
+#if PMNT
+#define INCL_32BIT
+#include "pmnt.h"
+#endif
+
+/* ExitReason values (from os2v12.h/os2v20.h) */
+
+#define TC_EXIT 0
+#define TC_HARDERROR 1
+#define TC_TRAP 2
+#define TC_KILLPROCESS 3
+
+typedef struct _UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Buffer;
+} UNICODE_STRING, *PUNICODE_STRING;
+
+typedef struct _STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PCHAR Buffer;
+} STRING, *PSTRING;
+
+BOOL
+Or2CreateUnicodeStringFromMBz(
+ OUT PUNICODE_STRING DestinationString,
+ IN PSZ SourceString
+ );
+
+DWORD
+Or2MBStringToUnicodeString(
+ PUNICODE_STRING DestinationString,
+ PSTRING SourceString,
+ BOOL AllocateDestinationString
+ );
+
+VOID
+RtlFreeUnicodeString(
+ PUNICODE_STRING UnicodeString
+ );
+
+DWORD
+Ow2VioReadCurPos(
+ );
+
+DWORD
+Ow2VioReadCurType();
+
+DWORD
+Ow2LvbUpdateLVBBuffer();
+
+VOID
+SetSessionParameters(
+ IN PVOID SessionStartData,
+ OUT PDWORD pCreateFlags,
+ IN PSZ ImageFileName,
+#if PMNT
+ IN ULONG IsPMApp,
+#endif // PMNT
+ OUT LPSTARTUPINFO pStartInfo
+ );
+
+int
+Ow2DisplayHardErrorPopup(
+ IN int Drive,
+ IN BOOLEAN WriteProtectError,
+ IN PUCHAR AppName
+ );
+
+DWORD
+Ow2HardErrorPopup(
+ IN int Drive,
+ IN BOOLEAN WriteProtectError,
+ OUT int * ReturnedAction,
+ IN PUCHAR AppName
+ )
+{
+ int RetVal;
+
+ RetVal = Ow2DisplayHardErrorPopup(
+ Drive,
+ WriteProtectError,
+ AppName
+ );
+
+ switch (RetVal) {
+ case IDABORT:
+ *ReturnedAction = OS2SS_IDABORT;
+ break;
+
+ case IDRETRY:
+ *ReturnedAction = OS2SS_IDRETRY;
+ break;
+
+ default:
+ *ReturnedAction = OS2SS_IDIGNORE;
+ break;
+ }
+ return (0L);
+}
+
+
+HANDLE
+Ow2GetNulDeviceHandle(
+ VOID
+ )
+//
+// NULL is returned if there is some system error
+// and we can't open the nul device
+//
+{
+ //
+ // used to hold a handle to the win32 NUL device
+ // this is needed to pass NUL redirections to win32 processes
+ //
+ static HANDLE Ow2NulDeviceHandle = NULL;
+ HANDLE Hand;
+ SECURITY_ATTRIBUTES Sa;
+
+ if (Ow2NulDeviceHandle != NULL) {
+ return(Ow2NulDeviceHandle);
+ }
+
+ Sa.nLength = sizeof(Sa);
+ Sa.lpSecurityDescriptor = NULL;
+ Sa.bInheritHandle = TRUE;
+
+ Hand = CreateFileA("NUL",
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ &Sa,
+ OPEN_EXISTING,
+ 0L,
+ NULL);
+
+ if (Hand == INVALID_HANDLE_VALUE) {
+#if DBG
+ KdPrint(("OS2SES: Ow2GetNulDeviceHandle -- can't open NUL device, Error = %lx\n", GetLastError()));
+#endif
+ return(NULL);
+ } else {
+ Ow2NulDeviceHandle = Hand;
+ return(Hand);
+ }
+}
+
+ //
+ // Interface for a direct call from client\conrqust.c
+ //
+DWORD
+Ow2ExecPgm(
+ IN ULONG Flags,
+ IN PSZ Arguments OPTIONAL,
+ IN PSZ Variables OPTIONAL,
+ IN PSZ ImageFileName,
+#if PMNT
+ IN ULONG IsPMApp,
+#endif // PMNT
+ IN PVOID SessionStartData OPTIONAL,
+ IN POS2_STDHANDLES StdStruc,
+ OUT HANDLE *pHandle,
+ OUT HANDLE *tHandle,
+ OUT ULONG *dwProcessId
+ )
+{
+ STARTUPINFO StartInfo;
+ STARTUPINFOW StartInfoW;
+ PROCESS_INFORMATION ProcessInfo;
+ BOOL b;
+ DWORD dwCreateFlags, status = 0;
+ UNICODE_STRING ImageString_U;
+ UNICODE_STRING ArgString_U;
+ UNICODE_STRING TitleString_U;
+
+ RtlZeroMemory(&StartInfo, sizeof(STARTUPINFO));
+ StartInfo.cb = sizeof(STARTUPINFO);
+ StartInfo.dwFlags = STARTF_USESHOWWINDOW;
+ StartInfo.wShowWindow = SW_SHOWDEFAULT;
+
+ dwCreateFlags = CREATE_SUSPENDED;
+
+ if (Flags & EXEC_WINDOW_PROGRAM) {
+
+ // This is a window program, so create it with CREATE_NEW_PROCESS_GROUP
+ // (it will enable us to send CTRL_EVENT to all the group)
+
+ // dwCreateFlags |= CREATE_NEW_PROCESS_GROUP;
+
+ //
+ // redirect standard handles if we need to
+ //
+
+ if (StdStruc->Flags & STDFLAG_ALL) {
+
+ if (StdStruc->Flags & STDFLAG_IN) {
+ StartInfo.hStdInput = StdStruc->StdIn;
+ } else {
+ StartInfo.hStdInput = SesGrp->StdIn;
+ }
+
+ if (StdStruc->Flags & STDFLAG_OUT) {
+ StartInfo.hStdOutput = StdStruc->StdOut;
+ } else {
+ StartInfo.hStdOutput = SesGrp->StdOut;
+ }
+
+ if (StdStruc->Flags & STDFLAG_ERR) {
+ StartInfo.hStdError = StdStruc->StdErr;
+ } else {
+ StartInfo.hStdError = SesGrp->StdErr;
+ }
+
+ StartInfo.dwFlags |= STARTF_USESTDHANDLES;
+ }
+
+ Flags &= ~EXEC_WINDOW_PROGRAM;
+ }
+
+ if (Flags == 4) {
+ // EXEC_BACKGROUND == 4
+ dwCreateFlags |= DETACHED_PROCESS;
+ }
+
+ if (SessionStartData)
+ {
+ SetSessionParameters(
+ SessionStartData,
+ &dwCreateFlags,
+ ImageFileName,
+#if PMNT
+ IsPMApp,
+#endif // PMNT
+ &StartInfo
+ );
+ }
+
+#if DBG
+ IF_OD2_DEBUG(TEMP)
+ {
+ KdPrint(("OS2SES(util-Ow2ExecPgm): CreateProcess %s\n Arg %s\n",
+ ImageFileName, Arguments));
+ }
+#endif
+
+ //
+ // Translate all the OEM parameters (MB) to Unicode
+ //
+
+ //
+ // ImageFileName
+ //
+
+ if (!(Or2CreateUnicodeStringFromMBz(
+ &ImageString_U,
+ ImageFileName
+ ))) {
+ status = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(util-Ow2ExecPgm): Fail to translate ImageFileName %s OEM to Unicode\n",
+ ImageFileName));
+#endif
+ return(status);
+ }
+
+ //
+ // Arguments
+ //
+
+ if (!(Or2CreateUnicodeStringFromMBz(
+ &ArgString_U,
+ Arguments
+ ))) {
+ status = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(util-Ow2ExecPgm): Fail to translate Arguments %s OEM to Unicode\n",
+ Arguments));
+#endif
+ if (ImageFileName)
+ RtlFreeUnicodeString(&ImageString_U);
+ return(status);
+ }
+
+ //
+ // StartupInfo
+ //
+
+ RtlMoveMemory(&StartInfoW, &StartInfo, sizeof(StartInfo));
+
+ TitleString_U.Buffer = NULL;
+ if (!(Or2CreateUnicodeStringFromMBz(
+ &TitleString_U,
+ StartInfo.lpTitle
+ ))) {
+ status = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(util-Ow2ExecPgm): Fail to translate Title %s OEM to Unicode\n",
+ StartInfo.lpTitle ));
+#endif
+ if (ImageFileName)
+ RtlFreeUnicodeString(&ImageString_U);
+ if (Arguments)
+ RtlFreeUnicodeString(&ArgString_U);
+ return(status);
+ }
+
+ StartInfoW.lpTitle = TitleString_U.Buffer;
+
+
+ b = CreateProcessW(ImageString_U.Buffer,
+ ArgString_U.Buffer,
+ NULL,
+ NULL,
+ TRUE, // inherit all handles
+ dwCreateFlags,
+ Variables,
+ NULL,
+ &StartInfoW,
+ &ProcessInfo
+ );
+
+ //
+ // Free Unicode Strings
+ //
+ if (ImageFileName)
+ RtlFreeUnicodeString(&ImageString_U);
+ if (Arguments)
+ RtlFreeUnicodeString(&ArgString_U);
+ if (TitleString_U.Buffer)
+ RtlFreeUnicodeString(&TitleString_U);
+
+ //
+ // check for error
+ //
+ if (!b) {
+ status = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(util-Ow2ExecPgm): CreateProcess of %s failed status = %x \n",
+ ImageFileName, status));
+#endif
+
+ return(status);
+ }
+
+ *pHandle = ProcessInfo.hProcess;
+ *tHandle = ProcessInfo.hThread;
+ *dwProcessId = ProcessInfo.dwProcessId;
+
+ return(status);
+}
+
+
+DWORD
+CreateOS2SRV(
+ OUT PHANDLE hProcess
+ )
+{
+ STARTUPINFOW StartInfo;
+ PROCESS_INFORMATION ProcessInfo;
+ BOOL b;
+ DWORD status = 0;
+ WCHAR Path[MAX_PATH];
+ UNICODE_STRING CdString_U;
+
+ *hProcess = NULL;
+
+ GetSystemDirectoryW((LPWSTR) &Path, MAX_PATH);
+
+ if (!(Or2CreateUnicodeStringFromMBz(
+ &CdString_U,
+ getenv("SYSTEMROOT")
+ ))) {
+ status = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(util-CreateOS2SRV): Fail to translate curdir %s to Unicode, status %lx\n",
+ getenv("SYSTEMROOT"), status));
+#endif
+ return(status);
+ }
+
+
+ /*
+ for ( i = 0 ; Path[i] ; i++ ) {
+ Path[i] = toupper(Path[i]);
+ }
+ */
+
+ wcscat(Path, L"\\OS2SRV.EXE");
+
+ RtlZeroMemory(&StartInfo, sizeof(STARTUPINFOW));
+ StartInfo.cb = sizeof(STARTUPINFOW);
+ StartInfo.wShowWindow = SW_SHOWDEFAULT;
+
+ if (fService)
+ b = CreateProcessW(Path,
+ L"OS2SRV /S",
+ NULL,
+ NULL,
+ FALSE,
+ DETACHED_PROCESS,
+ NULL,
+ CdString_U.Buffer, //getenv("SYSTEMROOT"),
+ &StartInfo,
+ &ProcessInfo
+ );
+ else
+ b = CreateProcessW(Path,
+ L"",
+ NULL,
+ NULL,
+ FALSE,
+ DETACHED_PROCESS,
+ NULL,
+ CdString_U.Buffer, //getenv("SYSTEMROOT"),
+ &StartInfo,
+ &ProcessInfo
+ );
+ if (!b) {
+ status = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(util-CreateOS2SRV): CreateProcess of OS2SRV failed status = %x \n",
+ status));
+#endif
+ return(status);
+ }
+
+ *hProcess = ProcessInfo.hProcess;
+ SetPriorityClass(*hProcess, REALTIME_PRIORITY_CLASS);
+ RtlFreeUnicodeString(&CdString_U);
+
+ return(status);
+
+}
+
+
+BOOL
+ServeWinCreateProcess(PWINEXECPGM_MSG PReq, PVOID PStatus)
+{
+ DWORD Rc = 0;
+
+#if DBG
+ IF_OD2_DEBUG( TASKING )
+ {
+ KdPrint(("OS2SES: ServeWinCreateProcess: Request: %u\n",
+ PReq->Request));
+ }
+#endif
+
+ switch (PReq->Request)
+ {
+ case RemoveConsoleThread:
+ if ( SesGrp->WinSyncProcessNumberInSession == 0 )
+ {
+ Rc = RemoveConForWinProcess();
+ }
+ if (!Rc)
+ {
+ SesGrp->WinSyncProcessNumberInSession++ ;
+ SesGrp->WinProcessNumberInSession++ ;
+ }
+ break;
+
+ case RestartConsoleThread:
+
+ // force CurPos, CurType and LVB to get updated
+
+ Ow2VioReadCurPos();
+ Ow2VioReadCurType();
+ Ow2LvbUpdateLVBBuffer();
+
+ if(SesGrp->WinSyncProcessNumberInSession == 1)
+ {
+ Rc = AddConAfterWinProcess();
+ }
+
+ SesGrp->WinSyncProcessNumberInSession--;
+ SesGrp->WinProcessNumberInSession--;
+ break;
+
+ case AddWin32ChildProcess:
+ SesGrp->WinProcessNumberInSession++;
+ break;
+
+ case RemWin32ChildProcess:
+
+ // force CurPos, CurType and LVB to get updated
+
+ Ow2VioReadCurPos();
+ Ow2VioReadCurType();
+ Ow2LvbUpdateLVBBuffer();
+
+ SesGrp->WinProcessNumberInSession--;
+ break;
+
+ default:
+ Rc = (DWORD) -1; //STATUS_INVALID_PARAMETER;
+#if DBG
+ KdPrint(("OS2SES(util-ServeWinCreateProcess): Unknown WinExec request = %X\n",
+ PReq->Request));
+#endif
+ }
+
+ if ( Rc == 1 )
+ {
+/* BUGBUG=> BUGBUG! error code and returned Status are wrong */
+ if (!(Rc = GetLastError()))
+ {
+#if DBG
+ KdPrint(("OS2SES(util-ServeWinCreateProcess): Unknown LastError\n"));
+#endif
+ Rc = (DWORD) -1;
+ }
+ }
+
+ *(PDWORD) PStatus = Rc;
+
+ return(TRUE); // Continue
+}
+
+
+VOID
+Ow2WinExitCode2ResultCode(
+ IN DWORD Status,
+ OUT PDWORD pReturnCode,
+ OUT PDWORD pExitReason)
+
+/*++
+
+Routine Description:
+
+ This routine translate the ExitCode from Win32's GetExitCodeProcess
+ to the OS/2 structure RESULTCODES fields: ExitReason and ExitResult.
+
+Arguments:
+
+ Status - the ExitCode from Win32 process.
+
+ pReturnCode - where to put the translated ExitResult
+
+ pExitReason - where to put the translated ExitReason
+
+Return Value:
+
+
+Note:
+
+
+--*/
+{
+ *pReturnCode = Status;
+ *pExitReason = TC_EXIT;
+
+ if (*pReturnCode == STATUS_WAIT_0)
+ {
+ /*
+ Success:
+
+ STATUS_WAIT_O 0x00000000L) 0
+ */
+
+ } else if (*pReturnCode == STATUS_CONTROL_C_EXIT)
+ {
+ /*
+ STATUS_CONTROL_C_EXIT 0xC000013AL) 0
+ */
+
+ *pExitReason = TC_TRAP;
+ *pReturnCode = 0;
+ } else if (((ULONG)*pReturnCode >= (ULONG)STATUS_ARRAY_BOUNDS_EXCEEDED) &&
+ ((ULONG)*pReturnCode <= (ULONG)STATUS_PRIVILEGED_INSTRUCTION))
+ {
+ /*
+ STATUS_ARRAY_BOUNDS_EXCEEDED 0xC000008CL) 5
+ STATUS_FLOAT_DENORMAL_OPERAND 0xC000008DL) 16
+ STATUS_FLOAT_DIVIDE_BY_ZERO 0xC000008EL) 16
+ STATUS_FLOAT_INEXACT_RESULT 0xC000008FL) 16
+ STATUS_FLOAT_INVALID_OPERATION 0xC0000090L) 16
+ STATUS_FLOAT_OVERFLOW 0xC0000091L) 16
+ STATUS_FLOAT_STACK_CHECK 0xC0000092L) 16
+ STATUS_FLOAT_UNDERFLOW 0xC0000093L) 16
+ STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094L) 0
+ STATUS_INTEGER_OVERFLOW 0xC0000095L) 4
+ STATUS_PRIVILEGED_INSTRUCTION 0xC0000096L) 13
+ */
+
+ if (*pReturnCode == STATUS_INTEGER_DIVIDE_BY_ZERO)
+ {
+ *pReturnCode = 0;
+ } else if (*pReturnCode == STATUS_INTEGER_OVERFLOW)
+ {
+ *pReturnCode = 4;
+ } else if (*pReturnCode == STATUS_PRIVILEGED_INSTRUCTION)
+ {
+ *pReturnCode = 13;
+ } else if (*pReturnCode == STATUS_ARRAY_BOUNDS_EXCEEDED)
+ {
+ *pReturnCode = 5;
+ } else
+ {
+ *pReturnCode = 16;
+ }
+ *pExitReason = TC_TRAP;
+ } else if (*pReturnCode == STATUS_STACK_OVERFLOW)
+ {
+ /*
+ STATUS_STACK_OVERFLOW 0xC00000FDL) 12
+ */
+
+ *pExitReason = TC_TRAP;
+ *pReturnCode = 12;
+ } else if (*pReturnCode == STATUS_DATATYPE_MISALIGNMENT)
+ {
+ /*
+ STATUS_DATATYPE_MISALIGNMENT 0x80000002L) 17
+ */
+
+ *pExitReason = TC_TRAP;
+ *pReturnCode = 17;
+ } else if (*pReturnCode == STATUS_BREAKPOINT)
+ {
+ /*
+ STATUS_BREAKPOINT 0x80000003L) 3
+ */
+
+ *pExitReason = TC_TRAP;
+ *pReturnCode = 3;
+ } else if (*pReturnCode == STATUS_SINGLE_STEP)
+ {
+ /*
+ STATUS_SINGLE_STEP 0x80000004L) 1
+ */
+
+ *pExitReason = TC_TRAP;
+ *pReturnCode = 1;
+ } else if (*pReturnCode == STATUS_ACCESS_VIOLATION)
+ {
+ /*
+ STATUS_ACCESS_VIOLATION 0xC0000005L) 13
+ */
+
+ *pExitReason = TC_TRAP;
+ *pReturnCode = 13;
+ } else if (*pReturnCode == STATUS_ILLEGAL_INSTRUCTION)
+ {
+ /*
+ STATUS_ILLEGAL_INSTRUCTION 0xC000001DL) 6
+ */
+
+ *pExitReason = TC_TRAP;
+ *pReturnCode = 6;
+ } else if ((*pReturnCode == STATUS_ABANDONED_WAIT_0) ||
+ (*pReturnCode == STATUS_USER_APC) ||
+ (*pReturnCode == STATUS_TIMEOUT) ||
+ (*pReturnCode == STATUS_PENDING) ||
+ (*pReturnCode == STATUS_NONCONTINUABLE_EXCEPTION) ||
+ (*pReturnCode == STATUS_INVALID_DISPOSITION))
+ {
+ /*
+ STATUS_WAIT_0 0x00000000L) ??
+ STATUS_ABANDONED_WAIT_0 0x00000080L) 255
+ STATUS_USER_APC 0x000000C0L) 255
+ STATUS_TIMEOUT 0x00000102L) 255
+ STATUS_PENDING 0x00000103L) 255
+ STATUS_NONCONTINUABLE_EXCEPTION 0xC0000025L) 255
+ STATUS_INVALID_DISPOSITION 0xC0000026L) 255
+ */
+
+ *pExitReason = TC_TRAP;
+ *pReturnCode = 255;
+ }
+#if DBG
+ IF_OD2_DEBUG3( OS2_EXE, TASKING, WIN )
+ {
+ KdPrint(("Ow2WinExitCode2ResultCode: Status %lu => Result %lu, Reason %lu\n",
+ Status, *pReturnCode, *pExitReason));
+ }
+#endif
+
+ return;
+}
+
+
+typedef struct _STARTDATA {
+ USHORT Length;
+ USHORT Related;
+ USHORT FgBg;
+ USHORT TraceOpt;
+ PSZ PgmTitle;
+ PSZ PgmName;
+ PBYTE PgmInputs;
+ PBYTE TermQ;
+ PBYTE Environment;
+ USHORT InheritOpt;
+ USHORT SessionType;
+ PSZ IconFile;
+ ULONG PgmHandle;
+ USHORT PgmControl;
+ USHORT InitXPos;
+ USHORT InitYPos;
+ USHORT InitXSize;
+ USHORT InitYSize;
+ USHORT Reserved;
+ PSZ ObjectBuffer;
+ ULONG ObjectBuffLen;
+} STARTDATA, *PSTARTDATA;
+
+
+VOID
+SetSessionParameters(
+ IN PVOID SessionStartData,
+ OUT PDWORD pCreateFlags,
+ IN PSZ ImageFileName,
+#if PMNT
+ IN ULONG IsPMApp,
+#endif // PMNT
+ OUT LPSTARTUPINFO pStartInfo
+ )
+{
+ PSTARTDATA pStartData = (PSTARTDATA)SessionStartData;
+ ULONG Length = pStartData->Length, i;
+ PUCHAR Title;
+
+#if PMNT
+ //
+ // Don't create console for PM process that is the child session of other PM
+ // process.
+ //
+ if (!ProcessIsPMApp() || (!IsPMApp) || (!pStartData->Related)) {
+#endif
+ *pCreateFlags |= CREATE_NEW_CONSOLE;
+#if PMNT
+ }
+#endif
+
+ Title = (pStartData->PgmTitle) ? pStartData->PgmTitle : ImageFileName;
+ i = strlen(Title);
+ if (i > 32)
+ {
+ Title += ( i - 32 );
+ i = 32;
+ }
+
+ if (!pStartData->PgmTitle)
+ //
+ // we give the pathname, strip out the last component
+ //
+ {
+#ifdef DBCS
+// MSKK Jun.16.1993 V-AkihiS
+ {
+ ULONG LastComponentPos = 0;
+ ULONG j;
+
+ for (j = 0; j < i; )
+ {
+ if (Ow2NlsIsDBCSLeadByte(Title[j], SesGrp->DosCP)) {
+ j++;
+ if (j < i) {
+ j++;
+ }
+ } else {
+ if ((Title[j] == '\\' ) ||
+ (Title[j] == '/' ) ||
+ (Title[j] == ':' )) {
+ LastComponentPos = j;
+ }
+ j++;
+ }
+ }
+ Title += j + 1;
+ }
+#else
+ for ( ; i ; i-- )
+ {
+ if ((Title[i - 1] == '\\' ) ||
+ (Title[i - 1] == '/' ) ||
+ (Title[i - 1] == ':' ))
+ {
+ Title += i;
+ break;
+ }
+ }
+#endif
+ }
+
+ pStartInfo->lpTitle = Title;
+ pStartInfo->dwXSize = (DWORD)SesGrp->ScreenColNum;
+ pStartInfo->dwYSize = (DWORD)SesGrp->ScreenRowNum;
+
+ if (Length > 40)
+ {
+ if (pStartData->PgmControl & 0x8000) // window position & size
+ {
+ if (Length > 42)
+ {
+ pStartInfo->dwX = (DWORD)(pStartData->InitXPos / SesGrp->CellHSize);
+ }
+ if (Length > 44)
+ {
+ pStartInfo->dwY = (DWORD)(pStartData->InitYPos / SesGrp->CellVSize);
+ }
+ if (Length > 46)
+ {
+ pStartInfo->dwXSize = (DWORD)(pStartData->InitXSize / SesGrp->CellHSize);
+ }
+ if (Length > 48)
+ {
+ pStartInfo->dwYSize = (DWORD)(pStartData->InitYSize / SesGrp->CellVSize);
+ }
+ pStartInfo->dwFlags |= (STARTF_USESIZE | STARTF_USEPOSITION);
+ }
+
+ if (!pStartData->FgBg) // window ForeGround
+ {
+ if (pStartData->PgmControl == 0) // invisible
+ {
+ //pStartInfo->dwFlags |= (STARTF_USESIZE | STARTF_USEPOSITION);
+ } else
+ {
+ if (pStartData->PgmControl & 2) // maximize
+ {
+ pStartInfo->wShowWindow = SW_SHOWMAXIMIZED;
+ }
+
+ if (pStartData->PgmControl & 4) // minimize
+ {
+ pStartInfo->wShowWindow = SW_SHOWMINIMIZED;
+ }
+ }
+ } else // window BackGround
+ {
+ if (pStartData->PgmControl == 0) // invisible
+ {
+ //pStartInfo->dwFlags |= (STARTF_USESIZE | STARTF_USEPOSITION);
+ } else
+ {
+ if (pStartData->PgmControl & 2) // maximize
+ {
+ pStartInfo->wShowWindow = SW_MAXIMIZE;
+ }
+
+ if (pStartData->PgmControl & 4) // minimize
+ {
+ pStartInfo->wShowWindow = SW_MINIMIZE;
+ }
+ }
+ }
+ } else
+ {
+ if (!pStartData->FgBg) // window ForeGround
+ {
+ //pStartInfo->wShowWindow |= STARTF_USESIZE;
+ }
+
+ }
+
+ if (pStartInfo->wShowWindow)
+ {
+ pStartInfo->dwFlags |= STARTF_USESHOWWINDOW;
+ }
+
+ // ((Length > 30 ) ? pStartData->SessionType : 0);
+ // TmpInheritOpt;
+}
diff --git a/private/os2/os2ses/vio.h b/private/os2/os2ses/vio.h
new file mode 100644
index 000000000..b3f854a96
--- /dev/null
+++ b/private/os2/os2ses/vio.h
@@ -0,0 +1,83 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ vio.h
+
+Abstract:
+
+ Prototypes for functions & macros in viorqust.c
+
+Author:
+
+ Michael Jarus (mjarus) 27-Oct-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+
+PVOID Ow2VioDataAddress;
+
+/*
+ * LVB vio routine to perform:
+ *
+ * init
+ *
+*/
+
+DWORD
+VioLVBInit();
+
+VOID
+VioLVBInitForSession();
+
+PUCHAR
+Ow2LvbGetPtr(
+ IN COORD Coord
+ );
+
+VOID
+LVBUpdateTTYCharWithAttrAndCurPos(
+ IN CHAR c,
+ IN PCHAR * LVBPtr
+ );
+
+#ifdef DBCS
+// MSKK Oct.13.1993 V-AkihiS
+VOID
+LVBUpdateTTYCharWithAttrAndCurPosDBCS(
+ IN CHAR c,
+ IN PCHAR * LVBPtr,
+ IN USHORT State
+ );
+#endif
+
+/*
+ * LVB vio routine to test LVB:
+ *
+ * VioLVBTestBuf (after VioReadCellStr)
+ * VioLVBTestScroll (after VioScrollXx)
+*/
+
+#if DBG
+VOID VioLVBTestBuff(IN PVOID DestBuffer);
+VOID VioLVBTestScroll();
+#endif
+
+#ifdef DBCS
+// MSKK Jun.23.1992 KazuM
+BOOL
+CheckBisectStringA(
+ IN DWORD CodePage,
+ IN PCHAR Buffer,
+ IN DWORD NumBytes
+ );
+#endif
+
diff --git a/private/os2/os2ses/violvb.c b/private/os2/os2ses/violvb.c
new file mode 100644
index 000000000..baab23403
--- /dev/null
+++ b/private/os2/os2ses/violvb.c
@@ -0,0 +1,770 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ violvb.c
+
+Abstract:
+
+ This module contains the Vio LVB routines
+
+Author:
+
+ Michael Jarus (mjarus) 28-Apr-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "trans.h"
+#include "vio.h"
+#include "os2win.h"
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+
+
+#define GET_LVB_PTR( row, col ) &LVBBuffer[((row) * SesGrp->ScreenColNum + (col)) << SesGrp->VioLength2CellShift]
+#define GET_LVB_ATT_PTR( row, col ) &LVBBuffer[(((row) * SesGrp->ScreenColNum + (col)) << SesGrp->VioLength2CellShift) + 1]
+
+typedef struct _attr_3_bytes
+{
+ UCHAR Attr[3];
+} ATTR_3_BYTES, *PATTR_3_BYTES;
+
+#if DBG
+//#define TEST_VIO_LVB 1
+BOOL Ow2VioLvbIgnoreTest = FALSE;
+#endif
+
+PUCHAR Ow2VioLvbTestBuff = NULL;
+
+DWORD
+VioLVBInit()
+{
+#if DBG
+#if TEST_VIO_LVB
+
+ if((Ow2VioLvbTestBuff = HeapAlloc(HandleHeap, 0, SesGrp->MaxLVBsize)) == NULL)
+ {
+ ASSERT1( "VioLVBInit: unable to allocate from heap to test VIO-LVB", FALSE );
+ return(1L);
+ }
+#endif
+#endif
+ return(0L);
+}
+
+
+VOID
+VioLVBInitForSession()
+{
+#if DBG
+#if TEST_VIO_LVB
+ ULONG Length = (ULONG)SesGrp->LVBsize;
+
+ Ow2VioGetLVBBuf(&Length);
+
+#endif
+#endif
+}
+
+
+DWORD
+Ow2VioGetLVBBuf(
+ IN PULONG Length
+ )
+{
+#if DBG
+ if ((*Length >> SesGrp->VioLength2CellShift) != SesGrp->ScreenSize)
+ KdPrint(("OS2SES(VioLVB-VioGetBuf): partial length %lu form %lu\n",
+ *Length >> SesGrp->VioLength2CellShift, SesGrp->ScreenSize));
+#endif
+
+ SesGrp->LVBOn = TRUE; // start echo to LVB buffer
+ return(Ow2VioReadCellStr(
+ Length,
+ 0,
+ 0,
+ LVBBuffer
+ ));
+}
+
+
+DWORD
+Ow2LvbUpdateLVBBuffer()
+{
+ if (SesGrp->LVBOn)
+ {
+ IN ULONG Length = SesGrp->LVBsize;
+
+ return(Ow2VioGetLVBBuf(&Length));
+ }
+
+ return(NO_ERROR);
+}
+
+
+DWORD
+Ow2VioShowLVBBuf(
+ IN ULONG Length,
+ IN ULONG Offset
+ )
+{
+ DWORD Rc;
+ ULONG VioMask = ~(ULONG)SesGrp->VioLengthMask;
+
+ if ( Offset & VioMask )
+ {
+ Length += Offset & VioMask;
+ Offset = Offset & (ULONG)SesGrp->VioLengthMask;
+ }
+
+ if ( Length & VioMask )
+ {
+ Length = (Length + SesGrp->BytesPerCell) & SesGrp->VioLengthMask;
+ }
+
+ if (( Length + Offset) > (ULONG)SesGrp->LVBsize)
+ {
+ Length = SesGrp->LVBsize - Offset;
+ }
+
+ Rc = Ow2VioWriteCellStr(
+ Length,
+ ((Offset >> SesGrp->VioLength2CellShift) / SesGrp->ScreenColNum),
+ ((Offset >> SesGrp->VioLength2CellShift) % SesGrp->ScreenColNum),
+ ((PBYTE)LVBBuffer) + Offset
+ );
+ return(Rc);
+}
+
+
+#if DBG
+VOID
+VioLVBTestBuff(IN PVOID DestBuffer)
+{
+#if TEST_VIO_LVB
+ if(!Ow2VioLvbIgnoreTest &&
+ memcmp( DestBuffer, LVBBuffer, SesGrp->LVBsize))
+ {
+ KdPrint(("Ow2VioReadCellStr: diff buffer\n"));
+ memmove( LVBBuffer, DestBuffer, SesGrp->LVBsize);
+ }
+#else
+ UNREFERENCED_PARAMETER(DestBuffer);
+#endif
+}
+
+
+VOID
+VioLVBTestScroll()
+{
+#if TEST_VIO_LVB
+ ULONG Length = SesGrp->ScreenSize << SesGrp->VioLength2CellShift;
+ ULONG LineLength = SesGrp->ScreenColNum << SesGrp->VioLength2CellShift;
+ UCHAR *Buffer = &Ow2VioLvbTestBuff[0], *Ptr, *Ptr1, *Offset;
+ ULONG i, j, k;
+
+ if (Ow2VioLvbTestBuff)
+ {
+ Ow2VioLvbIgnoreTest = TRUE;
+ Ow2VioReadCellStr(
+ &Length,
+ 0,
+ 0,
+ Ow2VioLvbTestBuff
+ );
+ Ow2VioLvbIgnoreTest = FALSE;
+
+ for ( i = 0, Offset = &LVBBuffer[0] ;
+ i < (ULONG)SesGrp->ScreenRowNum ;
+ i++, Buffer += LineLength, Offset += LineLength )
+ {
+ if(memcmp( Buffer, Offset, LineLength))
+ {
+ Ptr = Buffer;
+ Ptr1 = Offset;
+ for (j = 0 ; j < LineLength ; j++ )
+ {
+ if (Ptr[j] != Ptr1[j])
+ {
+ break;
+ }
+ }
+ KdPrint(("VioScroll: diff buffer line %d, Pos %d\n", i, j));
+ KdPrint((" LVB: %2.2x%2.2x%2.2x%2.2x, ... %2.2x; Screen: %2.2x%2.2x%2.2x%2.2x, ... %2.2x\n",
+ Ptr1[0], Ptr1[1], Ptr1[2], Ptr1[3], Ptr1[j],
+ Ptr[0], Ptr[1], Ptr[2], Ptr[3], Ptr[j]));
+
+ for ( j = 0, k = 0 ; j < 5 ; j++, k += 0x20 )
+ {
+ Ptr = Offset + k;
+ KdPrint((" LVB-%d: %2.2x%2.2x%2.2x%2.2x,%2.2x%2.2x%2.2x%2.2x,%2.2x%2.2x%2.2x%2.2x,%2.2x%2.2x%2.2x%2.2x,%2.2x%2.2x%2.2x%2.2x,%2.2x%2.2x%2.2x%2.2x,%2.2x%2.2x%2.2x%2.2x,%2.2x%2.2x%2.2x%2.2x\n", j,
+ Ptr[0], Ptr[1], Ptr[2], Ptr[3], Ptr[4], Ptr[5], Ptr[6], Ptr[7], Ptr[8], Ptr[9],
+ Ptr[10], Ptr[11], Ptr[12], Ptr[13], Ptr[14], Ptr[15], Ptr[16], Ptr[17], Ptr[18], Ptr[19],
+ Ptr[20], Ptr[21], Ptr[22], Ptr[23], Ptr[24], Ptr[25], Ptr[26], Ptr[27], Ptr[28], Ptr[29],
+ Ptr[30], Ptr[31]));
+ Ptr = Buffer + k;
+ KdPrint((" Scr-%d: %2.2x%2.2x%2.2x%2.2x,%2.2x%2.2x%2.2x%2.2x,%2.2x%2.2x%2.2x%2.2x,%2.2x%2.2x%2.2x%2.2x,%2.2x%2.2x%2.2x%2.2x,%2.2x%2.2x%2.2x%2.2x,%2.2x%2.2x%2.2x%2.2x,%2.2x%2.2x%2.2x%2.2x\n", j,
+ Ptr[0], Ptr[1], Ptr[2], Ptr[3], Ptr[4], Ptr[5], Ptr[6], Ptr[7], Ptr[8], Ptr[9],
+ Ptr[10], Ptr[11], Ptr[12], Ptr[13], Ptr[14], Ptr[15], Ptr[16], Ptr[17], Ptr[18], Ptr[19],
+ Ptr[20], Ptr[21], Ptr[22], Ptr[23], Ptr[24], Ptr[25], Ptr[26], Ptr[27], Ptr[28], Ptr[29],
+ Ptr[30], Ptr[31]));
+ }
+
+ memmove( Offset, Buffer, LineLength);
+ }
+ }
+ }
+#endif
+}
+#endif
+
+
+VOID
+VioLVBCopyStr( IN PUCHAR Sour,
+ IN COORD Coord,
+ IN ULONG Length)
+{
+
+ if(SesGrp->LVBOn && Length)
+ {
+ register UCHAR *Ptr;
+ register ULONG Offset = (ULONG)SesGrp->BytesPerCell;
+ register ULONG Len = Length;
+ register PUCHAR Sou = Sour;
+
+ Ptr = GET_LVB_PTR( Coord.Y, Coord.X );
+
+#ifdef DBCS
+// MSKK Oct.13.1993 V-AkihiS
+ if (Offset == 2)
+ {
+ for (;Len-- ; )
+ {
+ *Ptr = *Sou++;
+ Ptr += Offset;
+ }
+ } else
+ {
+ for (;Len-- ; )
+ {
+ *Ptr = *Sou; // copy character to lvb
+ Ptr += Offset-1; // skip to 3rd byte attr
+ if (Ow2NlsIsDBCSLeadByte(*Sou++, SesGrp->VioCP))
+ {
+ *Ptr++ = OS2_COMMON_LVB_LEADING_BYTE;
+ if (Len)
+ {
+ //
+ // Copy trailing byte charater, and mark
+ // this char as trailing byte
+ //
+ *Ptr = *Sou++;
+ Ptr += Offset-1; // skip to 3rd byte attr
+ *Ptr++ = OS2_COMMON_LVB_TRAILING_BYTE;
+ Len--;
+ } else
+ {
+ //
+ // If last written character was a lead byte,
+ // erase it.
+ //
+ *(Ptr-Offset) = ' ';
+ *(Ptr-1) = OS2_COMMON_LVB_SBCS;
+ }
+ } else
+ {
+ //
+ // Copy SBCS charater, and mark this char
+ // as SBCS
+ //
+ *Ptr++ = OS2_COMMON_LVB_SBCS;
+ }
+ }
+ }
+#else
+ for (;Len-- ; )
+ {
+ *Ptr = *Sou++;
+ Ptr += Offset;
+ }
+#endif
+ }
+}
+
+
+VOID
+VioLVBCopyCellStr( IN PUCHAR Sour,
+ IN COORD Coord,
+ IN ULONG LengthInCell)
+{
+ if(SesGrp->LVBOn && LengthInCell)
+ {
+#ifdef DBCS
+// MSKK Oct.13.1993 V-AkihiS
+ if (SesGrp->BytesPerCell == 2)
+ {
+ memmove(
+ GET_LVB_PTR( Coord.Y, Coord.X ),
+ Sour,
+ LengthInCell << SesGrp->VioLength2CellShift);
+ } else
+ {
+ register UCHAR *Ptr;
+ register ULONG Len = LengthInCell;
+ register PUCHAR Sou = Sour;
+
+ Ptr = GET_LVB_PTR( Coord.Y, Coord.X );
+
+ for (;Len-- ; )
+ {
+ if (Ow2NlsIsDBCSLeadByte(*Sou, SesGrp->VioCP))
+ {
+ //
+ // Copy leading byte charater, 1st attr and 2nd attr
+ // and put leading byte attr to 3rd attr
+ //
+ *Ptr++ = *Sou++; *Ptr++ = *Sou++; *Ptr++ = *Sou++;
+ *Ptr++ = OS2_COMMON_LVB_LEADING_BYTE;
+ Sou++; // skip source 3rd attr.
+ if (Len)
+ {
+ //
+ // Copy trailing byte charater, and mark
+ // this char as trailing byte
+ //
+ *Ptr++ = *Sou++; *Ptr++ = *Sou++; *Ptr++ = *Sou++;
+ *Ptr++ = OS2_COMMON_LVB_TRAILING_BYTE;
+ Sou++; // skip source 3rd attr.
+ Len--;
+ } else
+ {
+ //
+ // If last written chell was a lead byte,
+ // erase it.
+ //
+ *(Ptr-4) = ' ';
+ *(Ptr-1) = OS2_COMMON_LVB_SBCS;
+ }
+ } else
+ {
+ //
+ // Copy SBCS charater, and mark this char
+ // as SBCS
+ //
+ *Ptr++ = *Sou++; *Ptr++ = *Sou++; *Ptr++ = *Sou++;
+ *Ptr++ = OS2_COMMON_LVB_SBCS;
+ Sou++; // skip source 3rd attr.
+ }
+ }
+ }
+#else
+ memmove(
+ GET_LVB_PTR( Coord.Y, Coord.X ),
+ Sour,
+ LengthInCell << SesGrp->VioLength2CellShift);
+#endif
+ }
+}
+
+
+#ifdef DBCS
+// MSKK Oct.13.1993 V-AkihiS
+VOID VioLVBFillChar(IN PBYTE pChar,
+ IN COORD Coord,
+ IN ULONG LengthInCell)
+{
+ if(SesGrp->LVBOn && LengthInCell)
+ {
+ register UCHAR *Ptr;
+ register ULONG Offset = (ULONG)SesGrp->BytesPerCell;
+ register ULONG Len = LengthInCell;
+ register PBYTE pCha = pChar;
+
+ Ptr = GET_LVB_PTR( Coord.Y, Coord.X );
+
+ if (Offset == 2)
+ {
+ if (Ow2NlsIsDBCSLeadByte(*pCha, SesGrp->VioCP))
+ {
+ Len /= 2;
+ for ( ;Len-- ; )
+ {
+ *Ptr = *pCha;
+ Ptr += Offset;
+ *Ptr = *(pCha+1);
+ Ptr += Offset;
+ }
+ } else
+ {
+ for ( ;Len-- ; )
+ {
+ *Ptr = *pCha;
+ Ptr += Offset;
+ }
+ }
+ } else
+ {
+ if (Ow2NlsIsDBCSLeadByte(*pCha, SesGrp->VioCP))
+ {
+ Len /= 2;
+ for ( ;Len--; )
+ {
+ *Ptr = *pCha;
+ Ptr += Offset-1;
+ *Ptr++ = OS2_COMMON_LVB_LEADING_BYTE;
+ *Ptr = *(pCha+1);
+ Ptr += Offset-1;
+ *Ptr++ = OS2_COMMON_LVB_TRAILING_BYTE;
+ }
+ } else
+ {
+ for ( ;Len-- ; )
+ {
+ *Ptr = *pCha;
+ Ptr += Offset -1;
+ *Ptr++ = OS2_COMMON_LVB_SBCS;
+ }
+ }
+ }
+ }
+}
+#else
+VOID VioLVBFillChar(IN BYTE Char,
+ IN COORD Coord,
+ IN ULONG LengthInCell)
+{
+ if(SesGrp->LVBOn && LengthInCell)
+ {
+ register UCHAR *Ptr;
+ register ULONG Offset = (ULONG)SesGrp->BytesPerCell;
+ register ULONG Len = LengthInCell;
+ register BYTE Cha = Char;
+
+ Ptr = GET_LVB_PTR( Coord.Y, Coord.X );
+
+ for ( ;Len-- ; )
+ {
+ *Ptr = Cha;
+ Ptr += Offset;
+ }
+ }
+}
+#endif
+
+
+VOID VioLVBFillAtt( IN PBYTE pAttr,
+ IN COORD Coord,
+ IN ULONG LengthInCell)
+{
+ if(SesGrp->LVBOn && LengthInCell)
+ {
+ if ( SesGrp->BytesPerCell == 2 )
+ {
+ register PUCHAR Ptr;
+ register ULONG Offset = (ULONG)SesGrp->BytesPerCell;
+ register ULONG Len = LengthInCell;
+ register BYTE Att = *pAttr;
+
+ Ptr = GET_LVB_ATT_PTR( Coord.Y, Coord.X );
+
+ for ( ;Len-- ; )
+ {
+ *Ptr = Att;
+ Ptr += Offset;
+ }
+ } else
+ {
+ register PATTR_3_BYTES Ptr;
+ register ULONG Offset = (ULONG)SesGrp->BytesPerCell;
+ register ULONG Len = LengthInCell;
+ register ATTR_3_BYTES Att = *(PATTR_3_BYTES)pAttr;
+
+ Ptr = (PATTR_3_BYTES)GET_LVB_ATT_PTR( Coord.Y, Coord.X );
+
+ for ( ;Len-- ; )
+ {
+#ifdef DBCS
+// MSKK Jun.28.1992 KazuM
+// MSKK Oct.13.1993 V-AkihiS
+ //
+ // retain char type attribute in 3rd byte attriute.
+ //
+ Att.Attr[2] = Ptr->Attr[2];
+ *Ptr = Att;
+ Ptr = (PATTR_3_BYTES)((PUCHAR)Ptr + Offset);
+#else
+ *Ptr = Att;
+ Ptr += Offset;
+#endif
+ }
+ }
+ }
+}
+
+
+VOID VioLVBFillCell(IN PBYTE pCell,
+ IN COORD Coord,
+ IN ULONG LengthInCell)
+{
+ UCHAR *Ptr;
+ ULONG Pattern;
+
+ if(SesGrp->LVBOn && LengthInCell)
+ {
+ Ptr = GET_LVB_PTR( Coord.Y, Coord.X );
+
+#ifdef DBCS
+// MSKK Oct.14.1993 V-AkihiS
+ if ( SesGrp->BytesPerCell == 4 )
+ {
+ if (Ow2NlsIsDBCSLeadByte(pCell[0], SesGrp->VioCP))
+ {
+ register ATTR_3_BYTES LeadAttr = *(PATTR_3_BYTES)(&pCell[1]);
+ register ATTR_3_BYTES TrailAttr = *(PATTR_3_BYTES)(&pCell[5]);
+ register ULONG Len = LengthInCell / 2;
+
+ LeadAttr.Attr[2] = OS2_COMMON_LVB_LEADING_BYTE;
+ TrailAttr.Attr[2] = OS2_COMMON_LVB_TRAILING_BYTE;
+ for ( ; Len-- ; ) {
+ //
+ // Put leading byte cell
+ //
+ *Ptr++ = pCell[0];
+ *(PATTR_3_BYTES)Ptr = LeadAttr;
+ Ptr += 3;
+
+ //
+ // Put trailing byte cell
+ //
+ *Ptr++ = pCell[4];
+ *(PATTR_3_BYTES)Ptr = TrailAttr;
+ Ptr += 3;
+ }
+ } else
+ {
+ Pattern = (ULONG)((pCell[3] << 24) |
+ (pCell[2] << 16) |
+ (pCell[1] << 8) |
+ (pCell[0]));
+
+ RtlFillMemoryUlong(
+ Ptr,
+ LengthInCell << SesGrp->VioLength2CellShift,
+ Pattern);
+
+ }
+ } else {
+ if (Ow2NlsIsDBCSLeadByte(pCell[0], SesGrp->VioCP))
+ {
+ Pattern = (ULONG)((pCell[3] << 24) |
+ (pCell[2] << 16) |
+ (pCell[1] << 8) |
+ (pCell[0]));
+ } else
+ {
+ Pattern = (ULONG)((pCell[1] << 24) |
+ (pCell[0] << 16) |
+ (pCell[1] << 8) |
+ (pCell[0]));
+
+ if (LengthInCell & 1)
+ {
+ *(Ptr++) = pCell[0];
+ *(Ptr++) = pCell[1];
+ LengthInCell-- ;
+ }
+ }
+
+ RtlFillMemoryUlong(
+ Ptr,
+ LengthInCell << SesGrp->VioLength2CellShift,
+ Pattern);
+
+ }
+#else
+// for (;Length-- ; )
+// {
+// *(Ptr++) = pCell[0];
+// *(Ptr++) = pCell[1];
+// }
+
+ if ( SesGrp->BytesPerCell == 4 )
+ {
+ Pattern = (ULONG)((pCell[3] << 24) |
+ (pCell[2] << 16) |
+ (pCell[1] << 8) |
+ (pCell[0]));
+ } else
+ {
+ Pattern = (ULONG)((pCell[1] << 24) |
+ (pCell[0] << 16) |
+ (pCell[1] << 8) |
+ (pCell[0]));
+
+ if ((ULONG)Ptr & 3) {
+ LengthInCell--;
+ *(Ptr++) = pCell[0];
+ *(Ptr++) = pCell[1];
+ }
+
+ if (LengthInCell & 1)
+ {
+ LengthInCell-- ;
+ *(Ptr + (LengthInCell << 1)) = pCell[0];
+ *(Ptr + (LengthInCell << 1) + 1) = pCell[1];
+ }
+ }
+
+ RtlFillMemoryUlong(
+ Ptr,
+ LengthInCell << SesGrp->VioLength2CellShift,
+ Pattern);
+#endif
+ }
+
+}
+
+
+VOID
+VioLVBScrollBuff(IN DWORD LineNum)
+{
+ DWORD Size;
+ ULONG Pattern;
+
+ if (SesGrp->LVBOn && LineNum)
+ {
+ if ( LineNum > (DWORD)SesGrp->ScreenRowNum )
+ {
+ LineNum = SesGrp->ScreenRowNum;
+ }
+
+#ifdef DBCS
+// MSKK Oct.20.1993 V-AkihiS
+ Size = SesGrp->BytesPerCell * SesGrp->ScreenColNum * LineNum;
+ if (SesGrp->BytesPerCell == 2)
+ {
+ Pattern = (ULONG)((SesGrp->AnsiCellAttr[0] << 24) |
+ (' ' << 16) |
+ (SesGrp->AnsiCellAttr[0] << 8) |
+ (' '));
+ } else
+ {
+ Pattern = (ULONG)((SesGrp->AnsiCellAttr[2] << 24) |
+ (SesGrp->AnsiCellAttr[1] << 16) |
+ (SesGrp->AnsiCellAttr[0] << 8) |
+ (' '));
+ }
+#else
+ Size = 2 * SesGrp->ScreenColNum * LineNum;
+ Pattern = (ULONG)((SesGrp->AnsiCellAttr[0] << 24) |
+ (' ' << 16) |
+ (SesGrp->AnsiCellAttr[0] << 8) |
+ (' '));
+#endif
+
+ RtlMoveMemory(LVBBuffer,
+ LVBBuffer + Size,
+ SesGrp->LVBsize - Size);
+
+
+#ifdef DBCS
+// MSKK Oct.20.1993 V-AkihiS
+ if (SesGrp->BytesPerCell == 4)
+ {
+ Size = SesGrp->ScreenColNum * LineNum;
+ }
+#endif
+ RtlFillMemoryUlong(LVBBuffer + SesGrp->LVBsize - Size,
+ Size,
+ Pattern);
+
+ }
+}
+
+
+PUCHAR
+Ow2LvbGetPtr(
+ IN COORD Coord
+ )
+{
+ return(GET_LVB_PTR( Coord.Y, Coord.X));
+}
+
+
+VOID
+LVBUpdateTTYCharWithAttrAndCurPos(
+ IN CHAR c,
+ IN PCHAR * LVBPtr
+ )
+{
+ PCHAR Ptr = *LVBPtr;
+ USHORT i;
+
+ if(SesGrp->LVBOn)
+ {
+ *Ptr++ = c;
+
+ for ( i = 1 ; i < SesGrp->BytesPerCell ; i++ )
+ {
+ *Ptr++ = SesGrp->AnsiCellAttr[i - 1];
+ }
+
+ *LVBPtr = Ptr;
+ }
+}
+
+#ifdef DBCS
+// MSKK Oct.13.1993 V-AkihiS
+/* states of the finite state machine */
+
+#define NOCMD 1 /* type of crt state - most chars will go onto screen */
+#define ESCED 2 /* we've seen an ESC, waiting for rest of CSI */
+#define EQCMD 3 /* if '=' goto MODPARAMS else PARAMS */
+#define PARAMS 4 /* we're building the parameter list for ansicmd */
+#define MODPARAMS 5 /* we're building the parameter list for MODCMD */
+#define MODCMD 6 /* we've seen "ESC[=Num" waiting for #h or #l (# in {0..7}) */
+#define MODDBCS 7 /* we've seen DBCS lead-in char */
+
+VOID
+LVBUpdateTTYCharWithAttrAndCurPosDBCS(
+ IN CHAR c,
+ IN PCHAR * LVBPtr,
+ IN USHORT State
+ )
+{
+ PUCHAR Ptr = *LVBPtr;
+
+ if(SesGrp->LVBOn)
+ {
+ *Ptr++ = c;
+
+ if (SesGrp->BytesPerCell == 2)
+ {
+ *Ptr++ = SesGrp->AnsiCellAttr[0];
+ } else {
+ *Ptr++ = SesGrp->AnsiCellAttr[0];
+ *Ptr++ = SesGrp->AnsiCellAttr[1];
+ if (State == MODDBCS)
+ {
+ *Ptr++ = OS2_COMMON_LVB_TRAILING_BYTE;
+ } else
+ {
+ *Ptr++ = OS2_COMMON_LVB_LEADING_BYTE;
+ }
+ }
+
+ *LVBPtr = Ptr;
+ }
+}
+#endif
diff --git a/private/os2/os2ses/vionls.c b/private/os2/os2ses/vionls.c
new file mode 100644
index 000000000..a9223a88c
--- /dev/null
+++ b/private/os2/os2ses/vionls.c
@@ -0,0 +1,196 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ vionls.c
+
+Abstract:
+
+ This module contains the NLS support for Vio.
+
+Author:
+
+ KazuM 23-Jun-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#ifdef DBCS
+
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "trans.h"
+#include "vio.h"
+#include "event.h"
+#include "os2win.h"
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+
+// MSKK Feb.05.1993 V-AkihiS
+// If NLS module for console doesn't present, then NO_CONSOLE_NLS switch should be enable
+// difinition.
+//#define NO_CONSOLE_NLS
+
+/*
+ * internal vio routine to perform:
+ */
+
+DWORD
+Ow2VioSetCoordAndCheck(
+ OUT PCOORD pVioCoord,
+ IN ULONG ulRow,
+ IN ULONG ulColumn
+ );
+
+DWORD
+Ow2VioCheckCharType(
+ OUT PVOID pchType,
+ IN ULONG Row,
+ IN ULONG Column
+ )
+{
+ DWORD Rc;
+ COORD rwCoord;
+
+ if (Rc = Ow2VioSetCoordAndCheck(&rwCoord, Row, Column))
+ {
+ return(Rc);
+ }
+
+// MSKK Feb.05.1993 V-AkihiS
+#ifndef NO_CONSOLE_NLS
+ Rc = GetConsoleCharType(hConOut, rwCoord, pchType);
+#endif
+
+ return (!Rc);
+}
+
+BOOL
+CheckBisectStringA(
+ IN DWORD CodePage,
+ IN PCHAR Buffer,
+ IN DWORD NumBytes
+ )
+
+/*++
+
+Routine Description:
+
+ This routine check bisected on Ascii string end.
+
+Arguments:
+
+ CodePage - Value of code page.
+
+ Buffer - Pointer to Ascii string buffer.
+
+ NumBytes - Number of Ascii string.
+
+Return Value:
+
+ TRUE - Bisected character.
+
+ FALSE - Correctly.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(CodePage);
+
+ while(NumBytes) {
+ if (Ow2NlsIsDBCSLeadByte(*Buffer, SesGrp->VioCP)) {
+ if (NumBytes <= 1)
+ return TRUE;
+ else {
+ Buffer += 2;
+ NumBytes -= 2;
+ }
+ }
+ else {
+ Buffer++;
+ NumBytes--;
+ }
+ }
+ return FALSE;
+}
+
+// MSKK Sep.29.1993 V-AkihiS
+#ifdef NO_CONSOLE_NLS
+#define OS2VIOATTRMASK 0xFFFF
+#else
+#define OS2VIOATTRMASK (FOREGROUND_BLUE | \
+ FOREGROUND_GREEN | \
+ FOREGROUND_RED | \
+ FOREGROUND_INTENSITY | \
+ BACKGROUND_BLUE | \
+ BACKGROUND_GREEN | \
+ BACKGROUND_RED | \
+ BACKGROUND_INTENSITY | \
+ COMMON_LVB_GRID_HORIZONTAL | \
+ COMMON_LVB_GRID_LVERTICAL | \
+ COMMON_LVB_REVERSE_VIDEO | \
+ COMMON_LVB_UNDERSCORE)
+#endif
+
+WORD
+MapOs2ToWinAttr(
+ IN PBYTE Os2Attr
+ )
+{
+ WORD Tmp;
+
+ if (SesGrp->VioLength2CellShift == 1) {
+ return (WORD)*(Os2Attr);
+ }
+ else {
+// MSKK Sep.29.1993 V-AKihiS
+ return (*((PWORD) Os2Attr) & OS2VIOATTRMASK);
+ }
+}
+
+VOID
+MapWin2Os2Attr(
+ IN WORD NtAttr,
+ OUT PBYTE Os2Attr
+ )
+{
+ if (SesGrp->VioLength2CellShift == 1) {
+ *(Os2Attr) = (BYTE)NtAttr;
+ }
+ else {
+// MSKK Sep.29.1993 V-AkihiS
+ *((PWORD) Os2Attr) = NtAttr & OS2VIOATTRMASK;
+
+#ifndef NO_CONSOLE_NLS
+ switch(NtAttr & COMMON_LVB_SBCSDBCS)
+ {
+ case 0: // SBCS
+ *(Os2Attr+2) = OS2_COMMON_LVB_SBCS;
+ break;
+ case COMMON_LVB_LEADING_BYTE: // DBCS leading byte
+ *(Os2Attr+2) = OS2_COMMON_LVB_LEADING_BYTE;
+ break;
+ case COMMON_LVB_TRAILING_BYTE: // DBCS trailing byte
+ *(Os2Attr+2) = OS2_COMMON_LVB_TRAILING_BYTE;
+ break;
+ default:
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("OS2SES(MapWin2Os2Attr): Unknown attribute\n"));
+ }
+#endif
+ *(Os2Attr+2) = OS2_COMMON_LVB_SBCS;
+ }
+#endif
+ }
+}
+#endif
diff --git a/private/os2/os2ses/viorqust.c b/private/os2/os2ses/viorqust.c
new file mode 100644
index 000000000..0aac33460
--- /dev/null
+++ b/private/os2/os2ses/viorqust.c
@@ -0,0 +1,2809 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ viorqust.c
+
+Abstract:
+
+ This module contains the Vio requests thread and
+ the handler for Vio requests.
+
+Author:
+
+ Michael Jarus (mjarus) 23-Oct-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "trans.h"
+#include "event.h"
+#include "vio.h"
+#include "os2win.h"
+#include "conapi.h"
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+
+#if DBG
+BYTE VioInitStr[] = "VioInit";
+BYTE Ow2VioSetNewCpStr[] = "Ow2VioSetNewCp";
+BYTE Ow2VioPopUpStr[] = "Ow2VioPopUp";
+BYTE Ow2VioEndPopUpStr[] = "Ow2VioEndPopUp";
+BYTE Ow2VioWriteCharStrStr[] = "Ow2VioWriteCharSt";
+BYTE Ow2VioWriteCharStrAttStr[] = "Ow2VioWriteCharStrAt";
+BYTE Ow2VioWriteCellStrStr[] = "Ow2VioWriteCellStr";
+BYTE Ow2VioFillNCharStr[] = "Ow2VioFillNChar";
+BYTE Ow2VioFillNAttrStr[] = "Ow2VioFillNAttr";
+BYTE Ow2VioFillNCellStr[] = "Ow2VioFillNCell";
+BYTE Ow2ClearAllRegionStr[] = "Ow2ClearAllRegion";
+BYTE Ow2VioWriteCurPosStr[] = "Ow2VioWriteCurPos";
+BYTE Ow2VioReadCurPosStr[] = "Ow2VioReadCurPos";
+BYTE Ow2VioSetCurTypeStr[] = "Ow2VioSetCurType";
+BYTE Ow2VioReadCurTypeStr[] = "Ow2VioReadCurType";
+BYTE VioSetScreenSizeStr[] = "VioSetScreenSize";
+#endif
+
+VOID
+Od2ProbeForWrite(
+ IN PVOID Address,
+ IN ULONG Length,
+ IN ULONG Alignment
+ );
+
+VOID
+Od2ProbeForRead(
+ IN PVOID Address,
+ IN ULONG Length,
+ IN ULONG Alignment
+ );
+
+VOID
+Od2ExitGP();
+
+/*
+ * internal vio routine to perform:
+ */
+
+DWORD
+VioInit1(IN VOID);
+
+DWORD
+Ow2VioSetCoordAndCheck(
+ OUT PCOORD pVioCoord,
+ IN ULONG ulRow,
+ IN ULONG ulColumn
+ );
+
+DWORD
+Ow2VioSetCoordLengthAndCheck(
+ OUT PCOORD pVioCoord,
+ IN OUT PULONG pulLength,
+ IN ULONG ulRow,
+ IN ULONG ulColumn
+ );
+
+DWORD
+Ow2ClearAllRegion(
+ IN PSMALL_RECT ScrollRect,
+ IN PCHAR_INFO ScrollChar,
+ IN PUCHAR pCell
+ );
+
+DWORD
+Ow2VioUpdateCurPos(
+ IN COORD CurPos
+ );
+
+DWORD
+Ow2VioWriteCurPos(
+ IN COORD CurPos
+ );
+
+DWORD
+Ow2VioReadCurPos(
+ );
+
+DWORD
+Ow2VioMapOs2CurType2Win(
+ IN OUT PVIOCURSORINFO pCursorInfo,
+ OUT PCONSOLE_CURSOR_INFO lpCursorInfo
+ );
+
+DWORD
+Ow2VioReadCurType();
+
+#define OS2_VIO_MAX_ROW 100
+#define ADAPTER_MEMORY 0x40000 /* (ULONG)SesGrp->ScreenRowNum * SesGrp->ScreenColNum */
+
+/*
+ * This section is used for Vio R/W cell operation, to seperate/compine the
+ * cell into/from data and attribute bytes.
+ */
+
+#define OS2_VIO_MSG_SIZE 0x10000L
+#define OS2_VIO_SECTION_SIZE (2 * OS2_VIO_MSG_SIZE)
+#define DATA_OFFSET 0
+#define ATTR_OFFSET OS2_VIO_MSG_SIZE /* for cell's attr only */
+#define ATTR3_OFFSET (OS2_VIO_MSG_SIZE / 2) /* MSKK: 3 attr per cell */
+
+extern CONSOLE_SCREEN_BUFFER_INFO StartUpScreenInfo;
+extern CONSOLE_CURSOR_INFO StartUpCursorInfo;
+
+PVOID Ow2SessionVioDataBaseAddress;
+PVOID Ow2VioAttrAddress;
+
+WCHAR WindowTitle[256];
+SHORT OldScreenCol; /* col number (saved in PopUp) */
+SHORT OldScreenRow; /* row number (saved in PopUp) */
+COORD OldCurPos; /* CurPos (saved in PopUp) */
+VIOCURSORINFO OldCursorInfo; /* Cursor Info (saved in PopUp) */
+CONSOLE_CURSOR_INFO OldWinCursorInfo;
+
+DWORD
+VioInitForSession(IN VOID)
+{
+ SesGrp->Os2ModeInfo.fbType = VGMT_OTHER;
+ SesGrp->Os2ModeInfo.color = COLORS_16;
+ SesGrp->Os2ModeInfo.col = SesGrp->ScreenColNum;
+ SesGrp->Os2ModeInfo.row = SesGrp->ScreenRowNum;
+ SesGrp->Os2ModeInfo.hres = SesGrp->ScreenColNum * SesGrp->CellHSize;
+ SesGrp->Os2ModeInfo.vres = SesGrp->ScreenRowNum * SesGrp->CellVSize;
+ SesGrp->Os2ModeInfo.buf_addr = 0xFFFFFFFF;
+ SesGrp->Os2ModeInfo.buf_length = 0L;
+ SesGrp->Os2ModeInfo.full_length = 0L;
+ SesGrp->Os2ModeInfo.partial_length = 0L;
+ SesGrp->Os2ModeInfo.ext_data_addr = (CHAR *)0xFFFFFFFF;
+
+ SesGrp->MinRowNum = SesGrp->ScreenRowNum;
+
+ Ow2VioReadCurType();
+ StartUpCursorInfo.bVisible = SesGrp->bWinCursorVisible;
+ StartUpCursorInfo.dwSize = SesGrp->dwWinCursorSize;
+
+ SesGrp->CursorInfo.yStart = 6;
+ SesGrp->CursorInfo.cEnd = 7;
+ SesGrp->CursorInfo.cx = 1;
+
+ SesGrp->ScreenRect.Left = SesGrp->ScreenRect.Top = 0;
+ SesGrp->ScreenRect.Right = (SHORT)(SesGrp->ScreenColNum - 1);
+ SesGrp->ScreenRect.Bottom = (SHORT)(SesGrp->ScreenRowNum - 1);
+ SesGrp->ScreenSize = SesGrp->ScreenRowNum * SesGrp->ScreenColNum;
+
+ if (StartUpScreenInfo.dwCursorPosition.Y >= OS2_VIO_MAX_ROW )
+ {
+ StartUpScreenInfo.dwCursorPosition.Y = OS2_VIO_MAX_ROW - 1;
+ }
+ Ow2VioUpdateCurPos(StartUpScreenInfo.dwCursorPosition);
+
+ return (VioInit1());
+}
+
+
+DWORD
+VioInit(IN VOID)
+{
+ Or2WinGetConsoleScreenBufferInfo(
+ #if DBG
+ VioInitStr,
+ #endif
+ hConsoleOutput,
+ &StartUpScreenInfo
+ );
+
+ return (VioInit1());
+}
+
+
+DWORD
+VioInit1(IN VOID)
+{
+ if ((Ow2SessionVioDataBaseAddress = HeapAlloc(HandleHeap, 0, OS2_VIO_SECTION_SIZE)) == NULL)
+ {
+#if DBG
+ ASSERT1( "VioInit: unable to create heap for VIO", FALSE );
+#endif
+ return(1L);
+ }
+
+ Ow2VioDataAddress = ((PCHAR)Ow2SessionVioDataBaseAddress) + DATA_OFFSET;
+ Ow2VioAttrAddress = ((PCHAR)Ow2SessionVioDataBaseAddress) + ATTR_OFFSET;
+ if (VioLVBInit())
+ {
+ return(1L);
+ }
+
+ return (0L);
+}
+
+
+DWORD
+VioInitForNLS(IN ULONG VioCP)
+{
+ SesGrp->VioCP = VioCP;
+
+ SesGrp->Os2ModeInfo.fmt_ID = 0; // MSKK
+#ifdef DBCS
+// MSKK Jun.28.1992 KazuM
+ SesGrp->Os2ModeInfo.attrib = 1; // MSKK
+#else
+ SesGrp->Os2ModeInfo.attrib = 0; // MSKK
+#endif
+ SesGrp->BytesPerCell = 2; // MSKK
+
+ SesGrp->LVBsize = SesGrp->ScreenSize * (ULONG)SesGrp->BytesPerCell;
+ if (SesGrp->LVBsize > SesGrp->MaxLVBsize)
+ {
+ SesGrp->LVBsize = SesGrp->MaxLVBsize;
+ }
+ SesGrp->VioLengthMask = (USHORT)(0x0 - SesGrp->BytesPerCell);
+
+ if ( SesGrp->BytesPerCell == 2 )
+ {
+ SesGrp->VioLength2CellShift = 1;
+ } else /* ( SesGrp->BytesPerCell == 4 ) */
+ {
+ SesGrp->VioLength2CellShift = 2;
+ }
+
+ VioLVBInitForSession();
+ SesGrp->WinSpaceChar = L' ';
+ SesGrp->WinBlankChar = L'\0';
+ Ow2VioSetNewCp(SesGrp->VioCP);
+
+ return(0L);
+}
+
+
+DWORD
+Ow2VioSetNewCp( IN ULONG CodePage)
+{
+ UCHAR Os2Char;
+ DWORD Rc = NO_ERROR;
+
+#ifdef DBCS
+// MSKK Apr.16.1993 V-AkihiS
+// MSKK Apr.24.1993 V-AkihiS
+// Clear screen before code page is changed.
+ ULONG CPTmp;
+ CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
+ SMALL_RECT ClearRect;
+ CHAR_INFO FillChar;
+ UCHAR LVBFillCell[2] = {0x20, 0x07};
+#endif
+
+#ifdef DBCS
+// MSKK Apr.16.1993 V-AkihiS
+ CPTmp = CodePage ? CodePage : SesGrp->PrimaryCP;
+
+ if (SesGrp->VioCP != CPTmp)
+#else
+ if (SesGrp->VioCP != CodePage)
+#endif
+ {
+#ifdef DBCS
+// MSKK Apr.24.1993 V-AkihiS
+ //
+ // If code page will be changed actually,
+ // clear screen, before codepage is changed.
+ //
+
+ Ow2VioSetCurPos(0, 0);
+ if (Or2WinGetConsoleScreenBufferInfo(
+ #if DBG
+ Ow2VioSetNewCpStr,
+ #endif
+ hConOut,
+ &ConsoleScreenBufferInfo
+ ))
+ {
+ ClearRect.Top = ClearRect.Left = 0;
+ ClearRect.Right = (USHORT)( ConsoleScreenBufferInfo.dwSize.X - 1 );
+ ClearRect.Bottom = (USHORT)( ConsoleScreenBufferInfo.dwSize.Y - 1 );
+
+ FillChar.Char.AsciiChar = ' ';
+ FillChar.Attributes = MapOs2ToWinAttr(&LVBFillCell[1]);
+ Ow2ClearAllRegion(&ClearRect,
+ &FillChar,
+ LVBFillCell);
+ }
+#endif
+ Rc = !Or2WinSetConsoleOutputCP(
+ #if DBG
+ Ow2VioSetNewCpStr,
+ #endif
+#ifdef DBCS
+// MSKK Apr.16.1993 V-AkihiS
+ (UINT)CPTmp
+#else
+ (UINT)CodePage
+#endif
+ );
+
+ if (Rc)
+ {
+ ASSERT1("VioSetNewCp: Cannot set ConsoelOutputCP", FALSE);
+ } else
+ {
+ SesGrp->VioCP = CodePage;
+#ifdef DBCS
+// MSKK Jul.17.1992 KazuM
+ Os2Char = ' ';
+ MapOs2ToWinChar(Os2Char, 1, SesGrp->WinSpaceChar);
+ Os2Char = '\0';
+ MapOs2ToWinChar(Os2Char, 1, SesGrp->WinBlankChar);
+#else
+ Os2Char = ' ';
+ MapOs2ToWinChar(Os2Char, SesGrp->WinSpaceChar);
+ Os2Char = '\0';
+ MapOs2ToWinChar(Os2Char, SesGrp->WinBlankChar);
+#endif
+ }
+ }
+#ifdef DBCS
+// MSKK Apr.16.1993 V-AkihiS
+ else
+ {
+ SesGrp->VioCP = CodePage;
+ }
+#endif
+
+ return (Rc);
+}
+
+
+DWORD
+Ow2VioGetMode(
+ IN OUT PVOID VioMode
+ )
+{
+ PVIOMODEINFO Mode = (PVIOMODEINFO) VioMode;
+
+ if (Mode->cb == 2 )
+ {
+ Mode->cb = sizeof(VIOMODEINFO);
+ } else
+ {
+
+ RtlMoveMemory(&Mode->fbType,
+ &SesGrp->Os2ModeInfo.fbType,
+ Mode->cb - 2);
+ }
+
+ return(NO_ERROR);
+}
+
+
+DWORD
+Ow2VioSetMode(
+ IN PVOID VioMode
+ )
+{
+ PVIOMODEINFO pMode = (PVIOMODEINFO) VioMode;
+ SHORT Row, Col;
+
+ if ((pMode->cb <= 2 ) ||
+ ((pMode->cb > 4) && (pMode->cb & 1)))
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("OS2SES(Ow2VioSetMode): invalid mode (cb %u)\n",
+ pMode->cb));
+ }
+#endif
+ return (ERROR_VIO_INVALID_LENGTH);
+ }
+
+ IF_OD2_DEBUG( VIO )
+ ; //ASSERT((pMode->fbType & VGMT_GRAPHICS) == 0);
+
+ if (pMode->fbType > 7)
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("OS2SES(Ow2VioSetMode): invalid fbType %u\n",
+ pMode->fbType));
+ }
+#endif
+ return (ERROR_VIO_MODE);
+ }
+
+ if (pMode->cb == 3)
+ {
+ if ((pMode->fbType & VGMT_OTHER) == 0)
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("OS2SES(Ow2VioSetMode): invalid fbType %u for cb==3\n",
+ pMode->fbType));
+ }
+#endif
+ return (ERROR_VIO_MODE);
+ }
+
+ SesGrp->Os2ModeInfo.fbType = pMode->fbType;
+ }
+
+ Row = 25/*SesGrp->ScreenRowNum*/;
+ Col = 80/*SesGrp->ScreenColNum*/;
+
+ if (pMode->cb >= 4)
+ {
+ if ((((pMode->fbType & VGMT_OTHER) == 0) && pMode->color) ||
+ (((pMode->fbType & 3) == 1) && (pMode->color != COLORS_16)) ||
+ (((pMode->fbType & 3) == 3) && ((pMode->color != COLORS_16) &&
+ (pMode->color != COLORS_4))))
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("OS2SES(Ow2VioSetMode): error - fbType %u color %u\n",
+ pMode->fbType, pMode->color));
+ }
+#endif
+ return (ERROR_VIO_MODE);
+ }
+
+ SesGrp->Os2ModeInfo.fbType = pMode->fbType;
+ SesGrp->Os2ModeInfo.color = pMode->color;
+
+ if (pMode->cb >= 6)
+ {
+ // if ((pMode->col != 40) && (pMode->col != 80))
+ // {
+#if DBG //
+ // IF_OD2_DEBUG( VIO )
+ // {
+ // KdPrint(("OS2SES(Ow2VioSetMode): illegal col %u\n",
+ // pMode->col));
+ // }
+#endif //
+ // return (ERROR_VIO_MODE);
+ // }
+
+ if (pMode->col < 40)
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("OS2SES(Ow2VioSetMode): illegal col %u\n",
+ pMode->col));
+ }
+#endif
+ return (ERROR_VIO_MODE);
+ }
+
+ if (pMode->cb == 6) // no row
+ {
+ //pMode->row = SesGrp->ScreenRowNum;
+ } else if (( pMode->row < 25 ) &&
+ ( pMode->row < (USHORT)SesGrp->MinRowNum ))
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("OS2SES(Ow2VioSetMode): illegal row %u\n",
+ pMode->row));
+ }
+#endif
+ return (ERROR_VIO_MODE);
+ } else
+ {
+ Row = (SHORT)pMode->row;
+ }
+
+ Col = (SHORT)pMode->col;
+
+#ifdef DBCS
+// MSKK Jun.28.1992 KazuM
+ if (pMode->cb >= 13) {
+ if (pMode->attrib == 1 ||
+ pMode->attrib == 3 ) {
+ SesGrp->BytesPerCell = pMode->attrib+1;
+ SesGrp->Os2ModeInfo.fmt_ID = pMode->fmt_ID;
+ SesGrp->Os2ModeInfo.attrib = pMode->attrib;
+ }
+ else
+ return (ERROR_VIO_MODE);
+ }
+#endif
+
+ if ( SesGrp->BytesPerCell == 2 )
+ {
+ SesGrp->VioLength2CellShift = 1;
+ } else /* ( BytesPerCell == 4 ) */
+ {
+ SesGrp->VioLength2CellShift = 2;
+ }
+
+ // maybe update all remainming fields
+ }
+ }
+
+ if (VioSetScreenSize(Row,
+ Col,
+ hConOut))
+ {
+ return (ERROR_VIO_MODE);
+ }
+
+ if ( SesGrp->ScreenRowNum < SesGrp->MinRowNum )
+ {
+ SesGrp->MinRowNum = SesGrp->ScreenRowNum;
+ }
+
+ //BUGBUG=> keep Color#
+
+ return (NO_ERROR);
+}
+
+
+DWORD
+Ow2VioReadCharStr(
+ IN OUT PULONG pLength,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID DestBuffer
+ )
+{
+ DWORD Rc, NumToFill = *pLength;
+ COORD rwCoord;
+
+ if (Rc = Ow2VioSetCoordLengthAndCheck(&rwCoord, &NumToFill, Row, Col))
+ {
+ return(Rc);
+ }
+ try
+ {
+ Od2ProbeForWrite(DestBuffer, NumToFill, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if(ReadConsoleOutputCharacterA(
+ hConOut,
+ DestBuffer,
+ NumToFill,
+ rwCoord,
+ &NumToFill))
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ if (NumToFill != *pLength)
+ {
+ KdPrint(("OS2SES(VioRequest-VioReadeCharStr): partial data %lu from %lu, in Coord %u:%u\n",
+ NumToFill, *pLength, rwCoord.Y, rwCoord.X));
+ }
+ }
+#endif
+ *pLength = NumToFill;
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(VioRequest-VioReadCharStr): Rc %lu\n", Rc));
+#endif
+ }
+ return (Rc);
+}
+
+
+DWORD
+Ow2VioReadCellStr(
+ IN OUT PULONG pLength,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID DestBuffer
+ )
+{
+ DWORD Rc, NumToFill, NumFilled;
+ COORD rwCoord;
+
+ NumToFill = (DWORD)(*pLength >> SesGrp->VioLength2CellShift);
+ if (Rc = Ow2VioSetCoordLengthAndCheck(&rwCoord, &NumToFill, Row, Col))
+ {
+ return(Rc);
+ }
+
+ if (DestBuffer != LVBBuffer)
+ {
+ try
+ {
+ Od2ProbeForWrite(DestBuffer, NumToFill << SesGrp->VioLength2CellShift, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+ }
+
+ if (!(Rc = !ReadConsoleOutputCharacterA(
+ hConOut,
+ Ow2VioDataAddress,
+ NumToFill,
+ rwCoord,
+ &NumFilled)))
+ {
+#ifdef DBCS
+// MSKK Jun.24.1992 KazuM
+ DWORD NumTmp;
+
+ Rc = !ReadConsoleOutputAttribute(
+ hConOut,
+ Ow2VioAttrAddress,
+ NumToFill,
+ rwCoord,
+ &NumTmp);
+#else
+ Rc = !ReadConsoleOutputAttribute(
+ hConOut,
+ Ow2VioAttrAddress,
+ NumFilled,
+ rwCoord,
+ &NumFilled);
+#endif
+ }
+
+ if (!Rc)
+ {
+#ifdef DBCS
+// MSKK Jun.24.1992 KazuM
+ MapWin2Os2CellStr(
+ DestBuffer,
+ Ow2VioDataAddress,
+ Ow2VioAttrAddress,
+ NumFilled,
+ NumToFill);
+#else
+ MapWin2Os2CellStr(
+ DestBuffer,
+ Ow2VioDataAddress,
+ Ow2VioAttrAddress,
+ NumFilled,
+ NumFilled);
+#endif
+
+ *pLength = NumFilled << SesGrp->VioLength2CellShift;
+
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ if (NumToFill != NumFilled)
+ {
+ if (DestBuffer != LVBBuffer)
+ KdPrint(("OS2SES(VioRequest-VioReadCellStr): partial data %lu from %lu, in Coord %u:%u\n",
+ NumFilled, NumToFill, rwCoord.Y, rwCoord.X));
+ else
+ KdPrint(("OS2SES(VioRequest-VioGetBuffStr): partial data %lu from %lu, in Coord %u:%u\n",
+ NumFilled, NumToFill, rwCoord.Y, rwCoord.X));
+ }
+ }
+#endif
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(VioRequest-VioReadCellStr): Rc %lu\n", Rc));
+#endif
+ }
+
+#if DBG
+ if ( !Rc && ( *pLength == SesGrp->LVBsize ) &&
+ (DestBuffer != LVBBuffer))
+ {
+ VioLVBTestBuff(DestBuffer);
+ }
+#endif
+
+ return (Rc);
+}
+
+
+DWORD
+Ow2VioWriteCharStr(
+ IN ULONG Length,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID SourBuffer
+ )
+{
+ DWORD Rc, NumToFill = Length;
+ COORD rwCoord;
+
+ if (Rc = Ow2VioSetCoordLengthAndCheck(&rwCoord, &NumToFill, Row, Col))
+ {
+ return(Rc);
+ }
+ try
+ {
+ Od2ProbeForRead(SourBuffer, NumToFill, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if (Or2WinWriteConsoleOutputCharacterA(
+ #if DBG
+ Ow2VioWriteCharStrStr,
+ #endif
+ hConOut,
+ SourBuffer,
+ NumToFill,
+ rwCoord,
+ &NumToFill))
+ {
+ VioLVBCopyStr(
+ SourBuffer,
+ rwCoord,
+ NumToFill);
+
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ if (NumToFill != Length)
+ {
+ KdPrint(("OS2SES(VioRequest-VioWriteCharStr): partial data %lu from %lu, in Coord %u:%u\n",
+ NumToFill, Length, rwCoord.Y, rwCoord.X));
+ }
+ }
+#endif
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(VioWriteCharStr): Rc %lu\n", Rc));
+#endif
+ }
+
+ return (Rc);
+}
+
+
+DWORD
+Ow2VioWriteCharStrAtt(
+ IN ULONG Length,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID SourBuffer,
+ IN PBYTE AttrBuffer
+ )
+{
+ DWORD Rc, NumToFill = Length;
+ COORD rwCoord;
+
+ if (Rc = Ow2VioSetCoordLengthAndCheck(&rwCoord, &NumToFill, Row, Col))
+ {
+ return(Rc);
+ }
+ try
+ {
+ Od2ProbeForRead(SourBuffer, NumToFill, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ if (!(Rc = !Or2WinWriteConsoleOutputCharacterA(
+ #if DBG
+ Ow2VioWriteCharStrAttStr,
+ #endif
+ hConOut,
+ SourBuffer,
+ NumToFill,
+ rwCoord,
+ &NumToFill)))
+
+ {
+ VioLVBCopyStr(
+ SourBuffer,
+ rwCoord,
+ NumToFill);
+
+#ifdef DBCS
+// MSKK Jan.15.1993 V-AkihiS
+ Rc = !Or2WinFillConsoleOutputAttribute(
+ #if DBG
+ Ow2VioWriteCharStrAttStr,
+ #endif
+ hConOut,
+ MapOs2ToWinAttr(AttrBuffer),
+ NumToFill,
+ rwCoord,
+ &NumToFill);
+#else
+ Rc = !Or2WinFillConsoleOutputAttribute(
+ #if DBG
+ Ow2VioWriteCharStrAttStr,
+ #endif
+ hConOut,
+ MapOs2ToWinAttr(*AttrBuffer), // BUGBUG: MSKK
+ NumToFill,
+ rwCoord,
+ &NumToFill);
+#endif
+ }
+
+ if (!Rc)
+ {
+ VioLVBFillAtt(
+ AttrBuffer,
+ rwCoord,
+ NumToFill);
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ if (NumToFill != Length)
+ {
+ KdPrint(("OS2SES(VioRequest-VioWriteCharStrAtt): partial data %lu from %lu, in Coord %u:%u\n",
+ NumToFill, Length, rwCoord.Y, rwCoord.X));
+ }
+ }
+#endif
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(VioRequest-VioWriteCharStrAtt): Rc %lu\n", Rc));
+#endif
+ }
+ return (Rc);
+}
+
+
+DWORD
+Ow2VioWriteCellStr(
+ IN ULONG Length,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID SourBuffer
+ )
+{
+ DWORD Rc, NumToFill, NumFilled;
+ COORD rwCoord;
+
+ NumToFill = (DWORD)(Length >> SesGrp->VioLength2CellShift);
+ if (Rc = Ow2VioSetCoordLengthAndCheck(&rwCoord, &NumToFill, Row, Col))
+ {
+ return(Rc);
+ }
+ try
+ {
+ Od2ProbeForRead(SourBuffer, NumToFill << SesGrp->VioLength2CellShift, 1);
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Od2ExitGP();
+ }
+
+ MapOs2ToWinCellStr(
+ Ow2VioDataAddress,
+ Ow2VioAttrAddress,
+ SourBuffer,
+ NumToFill,
+ NumFilled);
+
+ if (!(Rc = !Or2WinWriteConsoleOutputCharacterA(
+ #if DBG
+ Ow2VioWriteCellStrStr,
+ #endif
+ hConOut,
+ Ow2VioDataAddress,
+ NumFilled,
+ rwCoord,
+ &NumFilled)))
+ {
+ Rc = !Or2WinWriteConsoleOutputAttribute(
+ #if DBG
+ Ow2VioWriteCellStrStr,
+ #endif
+ hConOut,
+ Ow2VioAttrAddress,
+ NumFilled,
+ rwCoord,
+ &NumFilled);
+ }
+
+ if (!Rc)
+ {
+ if (SourBuffer != LVBBuffer)
+ {
+ VioLVBCopyCellStr(
+ SourBuffer,
+ rwCoord,
+ NumFilled);
+ }
+
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ if (NumToFill != NumFilled)
+ {
+ if (SourBuffer != LVBBuffer)
+ KdPrint(("OS2SES(VioRequest-VioWriteCellStr): partial data %lu from %lu, in Coord %u:%u\n",
+ NumFilled, NumToFill, rwCoord.Y, rwCoord.X));
+ else
+ KdPrint(("OS2SES(VioRequest-VioShowBuff): partial data %lu from %lu, in Coord %u:%u\n",
+ NumFilled, NumToFill, rwCoord.Y, rwCoord.X));
+ }
+ }
+#endif
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(VioRequest-VioWriteCellStr): Rc %lu\n", Rc));
+#endif
+ }
+ return (Rc);
+}
+
+
+DWORD
+Ow2VioFillNChar(
+ IN ULONG Number,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID SourBuffer
+ )
+{
+ DWORD Rc, NumToFill = Number;
+ COORD rwCoord;
+#ifdef DBCS
+// MSKK Nov.16.1992 V-AkihiS
+// MSKK Jan.27.1993 V-AkihiS
+ BOOL DbcsFlag = FALSE;
+ DWORD NumTmp;
+#endif
+
+ if (Rc = Ow2VioSetCoordLengthAndCheck(&rwCoord, &NumToFill, Row, Col))
+ {
+ return(Rc);
+ }
+
+#ifdef DBCS
+// MSKK Nov.16.1992 V-AkihiS
+ //
+ // To output DBCS with FillConsoleOutputCharacterA,
+ // call this API twice. First time for DBCS Leadbyte,
+ // and second time for DBCS Trailbyte.
+ //
+ if (Ow2NlsIsDBCSLeadByte(*(PCHAR)SourBuffer, SesGrp->VioCP)) {
+ DbcsFlag = TRUE;
+ NumToFill *= 2;
+ }
+#endif
+
+ if (Or2WinFillConsoleOutputCharacterA(
+ #if DBG
+ Ow2VioFillNCharStr,
+ #endif
+ hConOut,
+ *(PCHAR)SourBuffer,
+ NumToFill,
+ rwCoord,
+#ifdef DBCS
+// MSKK Jan.27.1993 V-AkihiS
+ &NumTmp))
+#else
+ &NumToFill))
+#endif
+ {
+#ifdef DBCS
+// MSKK Nov.16.1992 V-AkihiS
+ if (DbcsFlag) {
+ Rc = !Or2WinFillConsoleOutputCharacterA(
+ #if DBG
+ Ow2VioFillNCharStr,
+ #endif
+ hConOut,
+ *((PCHAR)SourBuffer + 1),
+ NumToFill,
+ rwCoord,
+ &NumToFill);
+ } else {
+ NumToFill = NumTmp;
+ }
+ VioLVBFillChar(
+ (PBYTE)SourBuffer,
+ rwCoord,
+ NumToFill);
+#else
+ VioLVBFillChar(
+ *(PBYTE)SourBuffer,
+ rwCoord,
+ NumToFill);
+#endif
+
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ if (NumToFill != Number)
+ {
+ KdPrint(("OS2SES(VioRequest-VioFillNChar): partial data %lu from %lu, in Coord %u:%u\n",
+ NumToFill, Number, rwCoord.Y, rwCoord.X));
+ }
+ }
+#endif
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(VioRequest-VioFillNChar): Rc %lu\n", Rc));
+#endif
+ }
+ return (Rc);
+}
+
+
+DWORD
+Ow2VioFillNAttr(
+ IN ULONG Number,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID SourBuffer
+ )
+{
+ DWORD Rc, NumToFill = Number;
+ COORD rwCoord;
+
+ if (Rc = Ow2VioSetCoordLengthAndCheck(&rwCoord, &NumToFill, Row, Col))
+ {
+ return(Rc);
+ }
+
+#ifdef DBCS
+// MSKK Jun.28.1992 KazuM
+ if (Or2WinFillConsoleOutputAttribute(
+ #if DBG
+ Ow2VioFillNAttrStr,
+ #endif
+ hConOut,
+ MapOs2ToWinAttr((PCHAR)SourBuffer),
+ NumToFill,
+ rwCoord,
+ &NumToFill))
+#else
+ if (Or2WinFillConsoleOutputAttribute(
+ #if DBG
+ Ow2VioFillNAttrStr,
+ #endif
+ hConOut,
+ MapOs2ToWinAttr(*(PCHAR)SourBuffer),
+ NumToFill,
+ rwCoord,
+ &NumToFill))
+#endif
+ {
+ VioLVBFillAtt(
+ SourBuffer,
+ rwCoord,
+ NumToFill);
+
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ if (NumToFill != Number)
+ {
+ KdPrint(("OS2SES(VioRequest-VioFillNAttr): partial data %lu from %lu, in Coord %u:%u\n",
+ NumToFill, Number, rwCoord.Y, rwCoord.X));
+ }
+ }
+#endif
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(VioRequest-VioFillNAttr): Rc %lu\n", Rc));
+#endif
+ }
+ return (Rc);
+}
+
+
+DWORD
+Ow2VioFillNCell(
+ IN ULONG Number,
+ IN ULONG Row,
+ IN ULONG Col,
+ IN PVOID SourBuffer
+ )
+{
+ DWORD Rc, NumToFill = Number;
+ COORD rwCoord;
+#ifdef DBCS
+// MSKK Nov.16.1992 V-AkihiS
+// MSKK Jan.27.1993 V-AkihiS
+// MSKK Apr.25.1993 V-AkihiS
+ BOOL DbcsFlag = FALSE;
+ DWORD NumTmp;
+ USHORT i;
+ WORD LeadAttr, TrailAttr;
+ PWORD WinAttr;
+#endif
+
+ if (Rc = Ow2VioSetCoordLengthAndCheck(&rwCoord, &NumToFill, Row, Col))
+ {
+ return(Rc);
+ }
+
+#ifdef DBCS
+// MSKK Jun.27.1992 KazuM
+// MSKK Nov.16.1992 V-AkihiS
+ //
+ // To output DBCS with FillConsoleOutputCharacterA,
+ // call this API twice. First time for DBCS Leadbyte,
+ // and second time for DBCS Trailbyte.
+ //
+ if (Ow2NlsIsDBCSLeadByte(*(PCHAR)SourBuffer, SesGrp->VioCP)) {
+ DbcsFlag = TRUE;
+ NumToFill *= 2;
+ }
+#endif
+
+ if (!(Rc = !Or2WinFillConsoleOutputCharacterA(
+ #if DBG
+ Ow2VioFillNCellStr,
+ #endif
+ hConOut,
+ *(PCHAR)SourBuffer,
+ NumToFill,
+ rwCoord,
+#ifdef DBCS
+// MSKK Jan.27.1993 V-AkihiS
+ &NumTmp)))
+#else
+ &NumToFill)))
+#endif
+ {
+#ifdef DBCS
+// MSKK Nov.16.1992 V-AkihiS
+// MSKK Apr.26.1993 V-AkihiS
+// Bug fix.
+// When the attributes of DBCS leading byte and trailing byte are different,
+// We cannot use FillConsoleOutputAttribute. So in this kind of case,
+// We should make attributes string and use WriteConsoleOutputAttribute.
+ if (DbcsFlag) {
+ //
+ // If DBCS, Write DBCS trailing byte.
+ //
+ Rc = !Or2WinFillConsoleOutputCharacterA(
+ #if DBG
+ Ow2VioFillNCellStr,
+ #endif
+ hConOut,
+ *((PCHAR)SourBuffer + (1 << SesGrp->VioLength2CellShift)),
+ NumToFill,
+ rwCoord,
+ &NumToFill);
+
+ //
+ // Make DBCS attributes and write them.
+ //
+ LeadAttr = MapOs2ToWinAttr((PUCHAR)SourBuffer + 1);
+ TrailAttr = MapOs2ToWinAttr((PUCHAR)SourBuffer +
+ (1 << SesGrp->VioLength2CellShift) + 1);
+ WinAttr = Ow2VioAttrAddress;
+ for (i = 0; i < NumToFill / 2; i++) {
+ WinAttr[i * 2] = LeadAttr;
+ WinAttr[i * 2 + 1] = TrailAttr;
+ }
+
+ Rc = !Or2WinWriteConsoleOutputAttribute(
+ #if DBG
+ Ow2VioFillNCellStr,
+ #endif
+ hConOut,
+ Ow2VioAttrAddress,
+ NumToFill,
+ rwCoord,
+ &NumTmp);
+ } else {
+
+ NumToFill = NumTmp;
+ Rc = !Or2WinFillConsoleOutputAttribute(
+ #if DBG
+ Ow2VioFillNCellStr,
+ #endif
+ hConOut,
+ MapOs2ToWinAttr((PUCHAR)SourBuffer + 1),
+ NumToFill,
+ rwCoord,
+ &NumTmp);
+ }
+#else
+ Rc = !Or2WinFillConsoleOutputAttribute(
+ #if DBG
+ Ow2VioFillNCellStr,
+ #endif
+ hConOut,
+ MapOs2ToWinAttr(*((PUCHAR)SourBuffer + 1)),
+ NumToFill,
+ rwCoord,
+ &NumToFill);
+#endif
+ }
+
+ if (!Rc)
+ {
+ VioLVBFillCell(
+ SourBuffer,
+ rwCoord,
+ NumToFill);
+
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ if (NumToFill != Number)
+ {
+ KdPrint(("OS2SES(VioRequest-VioFillNCell): partial data %lu from %lu, in Coord %u:%u\n",
+ NumToFill, Number, rwCoord.Y, rwCoord.X));
+ }
+ }
+#endif
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(VioRequest-VioFillNAttr): Rc %lu\n", Rc));
+#endif
+ }
+ return (Rc);
+}
+
+
+DWORD
+Ow2VioPopUp(
+ IN ULONG PopUpMode,
+ IN PUCHAR AppName
+ )
+{
+ DWORD Rc = 0;
+ DWORD NumFilledA, NumFilledC, NumToFill = SesGrp->ScreenSize;
+ DWORD Rc1, Rc2, Rc3, Rc4;
+ COORD Coord;
+ UCHAR TitleBuffer[80];
+ int size;
+ VIOCURSORINFO CurType;
+
+
+#if DBG
+ if (hConOut != hConsoleOutput)
+ IF_OD2_DEBUG( ANY )
+ KdPrint(("OS2SES(Ow2VioPopUp): hConOut != hConsoleOutPut\n"));
+#endif
+
+ hPopUpOutput = Or2WinCreateConsoleScreenBuffer(
+ #if DBG
+ Ow2VioPopUpStr,
+ #endif
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL, /* &SecurityAttributes, */
+ CONSOLE_TEXTMODE_BUFFER, // 1
+ NULL);
+
+ if (hPopUpOutput == INVALID_HANDLE_VALUE)
+ {
+#if DBG
+ ASSERT1( "OS2SES(Ow2VioPopUp): Can not create CONOUT for PopUp\n", FALSE );
+#endif
+ return(ERROR_VIO_NO_POPUP);
+ }
+
+ if (!Or2WinSetConsoleActiveScreenBuffer(
+ #if DBG
+ Ow2VioPopUpStr,
+ #endif
+ hPopUpOutput
+ ))
+ {
+#if DBG
+ KdPrint(("OS2SES(Ow2VioPopUp): Can not activate CONOUT PopUp %u\n",
+ GetLastError()));
+#endif
+ }
+
+ /*
+ * save parameters for the screen: coord, cur-pos & cur-type.
+ *
+ */
+
+ OldScreenCol = SesGrp->ScreenColNum;
+ OldScreenRow = SesGrp->ScreenRowNum;
+
+ Rc = Ow2VioReadCurPos();
+ ASSERT( Rc == NO_ERROR );
+ OldCurPos = SesGrp->WinCoord;
+
+ Ow2VioGetCurType(&CurType);
+ OldCursorInfo = SesGrp->CursorInfo;
+ OldWinCursorInfo.dwSize = SesGrp->dwWinCursorSize;
+ OldWinCursorInfo.bVisible = SesGrp->bWinCursorVisible;
+
+ Coord.X = Coord.Y = 0;
+ Ow2VioUpdateCurPos(Coord);
+
+ if(PopUpMode & VP_TRANSPARENT) // VP_TRANSPARENT
+ {
+ /*
+ * Copy screen char and attr to new one
+ */
+
+ LPWSTR ScreenBuff;
+
+ if ((ScreenBuff = (LPWSTR)HeapAlloc(
+ HandleHeap,
+ 0,
+ (sizeof(WCHAR) + sizeof(WORD)) * NumToFill)) == NULL)
+ {
+ CloseHandle(hPopUpOutput);
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(Ow2VioPopUP): can't AllocHeap, Rc %lu\n", Rc));
+#endif
+ return(Rc);
+ }
+
+ Rc1 = Or2WinReadConsoleOutputCharacterW(
+ #if DBG
+ Ow2VioPopUpStr,
+ #endif
+ hConOut,
+ ScreenBuff,
+ NumToFill,
+ Coord,
+ &NumFilledC);
+
+ ASSERT1( "OS2SES(Ow2VioPopUp): ReadConsoleOutputCharacter", Rc1 );
+ ASSERT( NumFilledC == NumToFill );
+
+ Rc2 = Or2WinReadConsoleOutputAttribute(
+ #if DBG
+ Ow2VioPopUpStr,
+ #endif
+ hConOut,
+ (LPWORD)(ScreenBuff + NumToFill),
+ NumToFill,
+ Coord,
+ &NumFilledA);
+
+ ASSERT1( "OS2SES(Ow2VioPopUp): ReadConsoleOutputAttribute", Rc2 );
+ ASSERT( NumFilledA == NumToFill );
+
+ Rc3 = Or2WinWriteConsoleOutputCharacterW(
+ #if DBG
+ Ow2VioPopUpStr,
+ #endif
+ hPopUpOutput,
+ ScreenBuff,
+ NumFilledC,
+ Coord,
+ &NumFilledC);
+
+ ASSERT1( "OS2SES(Ow2VioPopUp): WriteConsoleOutputCharacter", Rc3 );
+ ASSERT( NumFilledC == NumToFill );
+
+ Rc4 = Or2WinWriteConsoleOutputAttribute(
+ #if DBG
+ Ow2VioPopUpStr,
+ #endif
+ hPopUpOutput,
+ (LPWORD)(ScreenBuff + NumToFill),
+ NumFilledA,
+ Coord,
+ &NumFilledA);
+
+ ASSERT1( "OS2SES(Ow2VioPopUp): WriteConsoleOutputAttribute", Rc4 );
+ ASSERT( NumFilledA == NumToFill );
+
+ if (!(Rc1 && Rc2 && Rc3 && Rc4))
+ {
+ CloseHandle(hPopUpOutput);
+ Rc = GetLastError();
+ HeapFree(HandleHeap, 0, (LPSTR)ScreenBuff);
+#if DBG
+ KdPrint(("OS2SES(VioPopUP): can't build PopUp screen, Rc %lu\n", Rc));
+#endif
+ return(Rc);
+ }
+
+ HeapFree(HandleHeap, 0, (LPSTR)ScreenBuff);
+
+ /*
+ * restore parameters for the screen: coord, cur-pos & cur-type.
+ *
+ */
+
+ VioSetScreenSize(OldScreenRow, OldScreenCol, hPopUpOutput);
+
+ Ow2VioWriteCurPos(OldCurPos);
+
+ Or2WinSetConsoleCursorInfo(
+ #if DBG
+ Ow2VioPopUpStr,
+ #endif
+ hPopUpOutput,
+ &OldWinCurInfo
+ );
+
+ } else // VP_OPAQUE
+ {
+ VioSetScreenSize(25, 80, hPopUpOutput);
+ }
+
+ /*
+ * Set title
+ *
+ * "ApplName : POPUP"
+ */
+
+ Rc1 = Or2WinGetConsoleTitleW(
+ #if DBG
+ Ow2VioPopUpStr,
+ #endif
+ WindowTitle,
+ sizeof(WindowTitle)
+ );
+
+ ASSERT1( "OS2SES(Ow2VioPopUp): GetConsoleTitle", Rc1 );
+
+ /*Rc1 = Or2WinSetConsoleTitleW(
+ #if DBG
+ Ow2VioPopUpStr,
+ #endif
+ L"== POPUP == OS/2 PopUP Window == POPUP =="
+ );
+ */
+ strncpy(TitleBuffer, AppName, OS2_MAX_APPL_NAME);
+ size = strlen(TitleBuffer);
+ if ((size > 4 ) && !_stricmp(&TitleBuffer[size-4], ".exe")) {
+ TitleBuffer[size-4] = '\0';
+ }
+ strcat(TitleBuffer, " : POPUP" );
+ Rc1 = Or2WinSetConsoleTitleA(
+ #if DBG
+ Ow2VioPopUpStr,
+ #endif
+ TitleBuffer
+ );
+
+ ASSERT1( "OS2SES(Ow2VioPopUp): SetConsoleTitle", Rc1 );
+
+ SesGrp->hConsolePopUp = hConOut = hPopUpOutput;
+
+ return(NO_ERROR);
+}
+
+
+DWORD
+Ow2VioEndPopUp()
+{
+ if (hConOut != hConsoleOutput)
+ {
+ if (!CloseHandle(hPopUpOutput))
+ {
+#if DBG
+ KdPrint(("OS2SES(VioRequest-VioEndPopUp): Can not close CONOUT PopUp %lu\n",
+ GetLastError()));
+#endif
+ }
+ hConOut = hConsoleOutput;
+
+ /*
+ * restore parameters for the screen: coord, cur-pos & cur-type.
+ *
+ */
+
+ SetScreenSizeParm(OldScreenRow, OldScreenCol);
+
+ SesGrp->dwWinCursorSize = OldWinCursorInfo.dwSize;
+ SesGrp->bWinCursorVisible = OldWinCursorInfo.bVisible;
+ SesGrp->CursorInfo = OldCursorInfo;
+ Ow2VioUpdateCurPos(OldCurPos);
+
+ if ( !Or2WinSetConsoleTitleW(
+ #if DBG
+ Ow2VioEndPopUpStr,
+ #endif
+ WindowTitle
+ ) )
+ {
+ ASSERT( FALSE );
+ }
+ }
+
+ SesGrp->hConsolePopUp = hPopUpOutput = (HANDLE) NULL;
+
+ return(NO_ERROR);
+}
+
+
+DWORD
+Ow2VioScroll(
+ IN PVOID VioScroll,
+ IN ULONG ScrollDirection
+ )
+{
+ PVIOSCROLL pScroll = (PVIOSCROLL) VioScroll;
+ COORD ScrollCoord, DestCoord, SourCoord, FillCoord;
+ SMALL_RECT ScrollRect, ClearRect, Clear1Rect;
+ CHAR_INFO ScrollChar;
+// BOOL ScrollBrk;
+ USHORT cbCheck;
+ DWORD Rc, Offset;
+ UCHAR *Ptr;
+ ULONG LineLength, LineNum, i, FillLineNum, FillLineLength;
+ SHORT DestLineIndexInc;
+
+ /*
+ * 1. Set ScrollRect dimenations to their max values
+ * 2. Check ScrollRect and cbLines legalty
+ * 3. Init all parms for default (ScrollChar, *Rect, *Coord, ...)
+ * 4. Set parms according to direction
+ * 5. Scrolling: (cbCheck)
+ * 5A. Clear all ClearRect (if should)
+ * or
+ * 5B1.(if overlapped) Clear the overlapping area (Clear1Rect)
+ * 5B2.Scroll (ScrollRect & ScrollCoord)
+ * 5B3.(if LVB) Update scroll area in LVB (SourCoord, DestCoord, LineNum,
+ * LineLength, Offset, DestLineIndexInc)
+ * 5B4.(if LVB) Clear the "fill char" area in LVB (FillCoord, FillLineNum,
+ * FillLineLength)
+ * BUGBUG: we fill again the area was cleared by Ow2ClearAllRegion for overlapping
+ * 6. code for checking the LVB updated
+ *
+ * ClearRect - are for CleaAllRegion
+ * Clear1Rect - are for overlapping CleaAllRegion
+ * ScrollRect, ScrollCoord - are for Win ScrollConsoleScreenBuffer
+ * SourCoord - Coord in LVB where to start scrolling from
+ * DestCoord - Coord in LVB where to start scrolling to
+ * FillCoord - Coord in LVB where to start filling cell (clearing)
+ * cbCheck - length of the dimention of the scrolling direction
+ * (to check if Ow2ClearAllRegion or overlapping)
+ * LineNum - number of lines of scrolling region (for LVB)
+ * LineLength - length of line to move in LVB
+ * FillLineNum - number of lines of filling region (for LVB)
+ * FillLineLength - length of line to fill in LVB
+ * Offset - the offset between 2 lines in LVB (sccording to direction)
+ * DestLineIndexInc - inc value for Row when updating LVB
+ */
+
+ ScrollRect = pScroll->ScrollRect;
+// ScrollBrk = FALSE;
+
+ if ((USHORT)ScrollRect.Left >= (USHORT)SesGrp->ScreenColNum)
+ {
+ ScrollRect.Left = (SHORT)(SesGrp->ScreenColNum - 1);
+// ScrollBrk = TRUE;
+ }
+
+ if ((USHORT)ScrollRect.Right >= (USHORT)SesGrp->ScreenColNum)
+ ScrollRect.Right = (SHORT)(SesGrp->ScreenColNum - 1);
+
+ if ((USHORT)ScrollRect.Top >= (USHORT)SesGrp->ScreenRowNum)
+ {
+ ScrollRect.Top = (SHORT)(SesGrp->ScreenRowNum - 1);
+// ScrollBrk = TRUE;
+ }
+
+ if ((USHORT)ScrollRect.Bottom >= (USHORT)SesGrp->ScreenRowNum)
+ ScrollRect.Bottom = (SHORT)(SesGrp->ScreenRowNum - 1);
+
+ if (ScrollRect.Top > ScrollRect.Bottom)
+ {
+ return ERROR_VIO_ROW;
+ }
+
+ if (ScrollRect.Left > ScrollRect.Right)
+ {
+ return ERROR_VIO_COL;
+ }
+
+// if (ScrollBrk)
+// break;
+
+ if ( !pScroll->cbLines )
+ {
+ return (NO_ERROR);
+ }
+
+ ScrollChar.Char.AsciiChar = pScroll->Cell[0];
+#ifdef DBCS
+// MSKK Oct.26.1992 V-AkihiS
+ ScrollChar.Attributes = MapOs2ToWinAttr(&pScroll->Cell[1]);
+#else
+ ScrollChar.Attributes = MapOs2ToWinAttr(pScroll->Cell[1]);
+#endif
+ ScrollCoord.X = ScrollRect.Left;
+ ScrollCoord.Y = ScrollRect.Top;
+
+ FillCoord = SourCoord = DestCoord = ScrollCoord;
+ Clear1Rect = ClearRect = ScrollRect;
+
+ Offset = SesGrp->ScreenColNum << SesGrp->VioLength2CellShift;
+ DestLineIndexInc = 1;
+
+ switch (ScrollDirection)
+ {
+ case 1: /* Down */
+ cbCheck = (USHORT)(ScrollRect.Bottom - ScrollRect.Top + 1);
+ DestCoord.Y = ScrollRect.Bottom;
+ ScrollRect.Bottom -= pScroll->cbLines;
+ Clear1Rect.Top = (SHORT)(ScrollRect.Bottom + 1);
+ Clear1Rect.Bottom = (SHORT)(ScrollRect.Top + pScroll->cbLines - 1);
+ ScrollCoord.Y += pScroll->cbLines;
+ FillLineLength = LineLength = (ScrollRect.Right - ScrollRect.Left + 1);
+ LineNum = ScrollRect.Bottom - ScrollRect.Top + 1;
+ SourCoord.Y = ScrollRect.Bottom;
+ FillLineNum = (ULONG)pScroll->cbLines;
+ Offset = - (SesGrp->ScreenColNum << SesGrp->VioLength2CellShift);
+ DestLineIndexInc = -1;
+ break;
+
+ case 2: /* Right */
+ cbCheck = (USHORT)(ScrollRect.Right - ScrollRect.Left + 1);
+ ScrollRect.Right -= pScroll->cbLines;
+ Clear1Rect.Left = (SHORT)(ScrollRect.Right + 1);
+ Clear1Rect.Right = (SHORT)(ScrollRect.Left + pScroll->cbLines - 1);
+ ScrollCoord.X += pScroll->cbLines;
+ LineLength = ScrollRect.Right - ScrollRect.Left + 1;
+ FillLineNum = LineNum = (ScrollRect.Bottom - ScrollRect.Top + 1);
+ FillLineLength = pScroll->cbLines;
+ DestCoord.X += pScroll->cbLines;
+ break;
+
+ case 3: /* Up */
+ cbCheck = (USHORT)(ScrollRect.Bottom - ScrollRect.Top + 1);
+ ScrollRect.Top += pScroll->cbLines;
+ Clear1Rect.Top = (SHORT)(Clear1Rect.Bottom - pScroll->cbLines + 1);
+ Clear1Rect.Bottom = (SHORT)(ScrollRect.Top - 1);
+ FillLineLength = LineLength = (ScrollRect.Right - ScrollRect.Left + 1);
+ LineNum = ScrollRect.Bottom - ScrollRect.Top + 1;
+ SourCoord.Y += pScroll->cbLines;
+ FillCoord.Y = (USHORT)(ScrollRect.Bottom - pScroll->cbLines + 1);
+ FillLineNum = (ULONG)pScroll->cbLines;
+ break;
+
+ case 4: /* Left */
+ cbCheck = (USHORT)(ScrollRect.Right - ScrollRect.Left + 1);
+ ScrollRect.Left += pScroll->cbLines;
+ Clear1Rect.Left = (SHORT)(Clear1Rect.Right - pScroll->cbLines + 1);
+ Clear1Rect.Right = (SHORT)(ScrollRect.Left - 1);
+ LineLength = ScrollRect.Right - ScrollRect.Left + 1;
+ FillLineNum = LineNum = (ScrollRect.Bottom - ScrollRect.Top + 1);
+ SourCoord.X += pScroll->cbLines;
+ FillLineLength = pScroll->cbLines;
+ FillCoord.X = (USHORT)(ScrollRect.Right - pScroll->cbLines + 1);
+ break;
+
+ }
+
+ if ((USHORT)pScroll->cbLines >= cbCheck)
+ {
+ /* clear all region */
+
+ Rc = Ow2ClearAllRegion(&ClearRect,
+ &ScrollChar,
+ pScroll->Cell);
+ } else
+ {
+ /* scroll region */
+
+ if ((USHORT)pScroll->cbLines > (USHORT)( cbCheck / 2 ))
+ {
+ /* clear the region of overlapping before scrolling */
+
+ Rc = Ow2ClearAllRegion(&Clear1Rect,
+ &ScrollChar,
+ pScroll->Cell);
+
+ }
+
+ Rc = !ScrollConsoleScreenBufferA( hConOut,
+ &ScrollRect,
+ NULL,
+ ScrollCoord,
+ &ScrollChar);
+
+ ASSERT1("OS2SES(Ow2VioScroll): ScrollConsoleScreenBufferA", !Rc);
+
+ if (!Rc && SesGrp->LVBOn)
+ {
+ Ptr = Ow2LvbGetPtr(SourCoord);
+
+ for ( i = 0 ; i < LineNum ; i++ )
+ {
+ VioLVBCopyCellStr(
+ Ptr,
+ DestCoord,
+ LineLength);
+
+ Ptr += Offset;
+ DestCoord.Y += DestLineIndexInc;
+ }
+
+ for ( i = 0 ; i < FillLineNum ; i++ )
+ {
+ VioLVBFillCell(
+ pScroll->Cell,
+ FillCoord,
+ FillLineLength);
+
+ FillCoord.Y++ ;
+ }
+ }
+ }
+
+#if DBG
+ if ( !Rc )
+ {
+ VioLVBTestScroll();
+ }
+#endif
+
+ if (Rc)
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(VioRequest-VioScroll): Rc %lu\n", Rc));
+#endif
+ }
+ return (Rc);
+}
+
+
+DWORD
+Ow2ClearAllRegion(
+ IN SMALL_RECT *ClearRect,
+ IN CHAR_INFO *FillChar,
+ IN PUCHAR pCell
+ )
+{
+ //SHORT i;
+ DWORD Rc, NumToFill, NumFilled;
+ COORD Address;
+
+ NumToFill = ClearRect->Right - ClearRect->Left + 1;
+ Address.X = ClearRect->Left;
+ Address.Y = ClearRect->Top;
+
+ if (NumToFill == (DWORD)SesGrp->ScreenColNum)
+ {
+ NumToFill *= (ClearRect->Bottom - ClearRect->Top + 1);
+
+ if (Rc = !Or2WinFillConsoleOutputCharacterA(
+ #if DBG
+ Ow2ClearAllRegionStr,
+ #endif
+ hConOut,
+ FillChar->Char.AsciiChar,
+ NumToFill,
+ Address,
+ &NumFilled
+ ))
+ {
+ ASSERT1("OS2SES(Ow2ClearAllRegion): FillConsoleOutputCharacterA1", FALSE);
+ return(Rc);
+ }
+
+ if (Rc = !Or2WinFillConsoleOutputAttribute(
+ #if DBG
+ Ow2ClearAllRegionStr,
+ #endif
+ hConOut,
+ FillChar->Attributes,
+ NumFilled,
+ Address,
+ &NumFilled
+ ))
+ {
+ ASSERT1("OS2SES(Ow2ClearAllRegion): FillConsoleOutputAttribute1", FALSE);
+ return(Rc);
+ }
+
+#if DBG
+ if ( NumToFill != NumFilled )
+ IF_OD2_DEBUG( ANY )
+ {
+ KdPrint(("OS2SES(VioRequest-Ow2ClearAllRegion): partial data\n"));
+ ASSERT( FALSE );
+ }
+#endif
+
+ VioLVBFillCell(
+ pCell,
+ Address,
+ NumFilled);
+
+ return(NO_ERROR);
+ }
+
+ for ( ; Address.Y <= ClearRect->Bottom ; Address.Y++)
+ {
+ if (Rc = !Or2WinFillConsoleOutputCharacterA(
+ #if DBG
+ Ow2ClearAllRegionStr,
+ #endif
+ hConOut,
+ FillChar->Char.AsciiChar,
+ NumToFill,
+ Address,
+ &NumFilled
+ ))
+ {
+ ASSERT1("OS2SES(Ow2ClearAllRegion): FillConsoleOutputCharacterA2", FALSE);
+ return(Rc);
+ }
+
+ if (Rc = !Or2WinFillConsoleOutputAttribute(
+ #if DBG
+ Ow2ClearAllRegionStr,
+ #endif
+ hConOut,
+ FillChar->Attributes,
+ NumToFill,
+ Address,
+ &NumFilled
+ ))
+ {
+ ASSERT1("OS2SES(Ow2ClearAllRegion): FillConsoleOutputAttribute2", FALSE);
+ return(Rc);
+ }
+
+ VioLVBFillCell(
+ pCell,
+ Address,
+ NumFilled);
+#if DBG
+ if ( NumToFill != NumFilled )
+ IF_OD2_DEBUG( ANY )
+ KdPrint(("OS2SES(VioRequest-Ow2ClearAllRegion): partial data1\n"));
+#endif
+
+ }
+
+ return(0L);
+}
+
+
+DWORD
+Ow2VioGetConfig(
+ IN OUT PVOID VioConfig
+ )
+{
+ VIOCONFIGINFO LocalConfig;
+ PVIOCONFIGINFO Config = (PVIOCONFIGINFO) VioConfig;
+
+ LocalConfig.cb = (Config->cb > sizeof(VIOCONFIGINFO)) ?
+ sizeof(VIOCONFIGINFO) : Config->cb;
+
+ LocalConfig.adapter = DISPLAY_VGA;
+ LocalConfig.display = MONITOR_851X_COLOR;
+ LocalConfig.cbMemory = ADAPTER_MEMORY;
+ if (LocalConfig.cb == sizeof(VIOCONFIGINFO))
+ {
+ // more to set
+ }
+
+ RtlMoveMemory(Config, &LocalConfig, LocalConfig.cb);
+ return(NO_ERROR);
+}
+
+
+/*
+ * VIO Cursor Position
+ *
+ * SesGrp->WinCoord hold the current Cursor Position for the all session
+ *
+ * Ow2VioReadCurPos - calls a Win32 API to retrive the CurPos (and update
+ * SesGrp->WinCoord)
+ * Ow2VioGetCurPos - gets CurPos from internal parameter (SesGrp->WinCoord).
+ * If there's a child Win32 process, Read it before.
+ * Ow2VioWriteCurPos - calls a Win32 API to change the CurPos
+ * Ow2VioUpdateCurPos - updates the current value (SesGrp->WinCoord)
+ * Ow2VioSetCurPos - if new CurPos (different from SesGrp->WinCoord) or
+ * there's a child Win32 process, calls Write and Update
+ *
+ * Init => Read
+ * OS/2 Get API => Get
+ * OS/2 Set API => Set
+ * TTY new Coord => Set
+ * VioPopUp => Set
+ * New screen mode (VioSetMode, VioPopup, VioWrtTTY(Set Mode)) => Write
+ * VioEndPopup => Update
+ * Last Win32 child process termination => Read
+ *
+ * Read => Update
+ * Get => Read
+ * Write => Update
+ * Set => Write
+ */
+
+
+DWORD
+Ow2VioUpdateCurPos(
+ IN COORD CurPos
+ )
+{
+ SesGrp->WinCoord = CurPos;
+ return (NO_ERROR);
+}
+
+
+DWORD
+Ow2VioWriteCurPos(
+ IN COORD CurPos
+ )
+{
+ DWORD Rc = NO_ERROR;
+
+ if(!Or2WinSetConsoleCursorPosition(
+ #if DBG
+ Ow2VioWriteCurPosStr,
+ #endif
+ hConOut,
+ CurPos
+ ))
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(Ow2VioWriteCurPos): Rc %lu (Y %d, X %d)\n",
+ Rc, CurPos.Y, CurPos.X));
+ ASSERT( FALSE ); // should not happend
+#endif
+ } else
+ {
+ Rc = Ow2VioUpdateCurPos(CurPos);
+ }
+ return (Rc);
+}
+
+
+DWORD
+Ow2VioSetCurPos(
+ IN ULONG Row,
+ IN ULONG Col
+ )
+{
+ DWORD Rc;
+ COORD CurPos;
+
+ if (Rc = Ow2VioSetCoordAndCheck(&CurPos, Row, Col))
+ {
+ return(Rc);
+ }
+
+ if(SesGrp->WinProcessNumberInSession ||
+ (CurPos.X != SesGrp->WinCoord.X) || (CurPos.Y != SesGrp->WinCoord.Y))
+ {
+ Rc = Ow2VioWriteCurPos(CurPos);
+ }
+
+ return (Rc);
+}
+
+
+DWORD
+Ow2VioReadCurPos(
+ )
+{
+ DWORD Rc;
+ CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
+
+ if (Or2WinGetConsoleScreenBufferInfo(
+ #if DBG
+ Ow2VioReadCurPosStr,
+ #endif
+ hConOut,
+ &ConsoleScreenBufferInfo
+ ))
+ {
+ if (ConsoleScreenBufferInfo.dwCursorPosition.Y >= SesGrp->ScreenRowNum ) {
+ ConsoleScreenBufferInfo.dwCursorPosition.Y = SesGrp->ScreenRowNum - 1;
+ }
+ Rc = Ow2VioUpdateCurPos(ConsoleScreenBufferInfo.dwCursorPosition);
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(Ow2VioReadCurPos): Rc %lu\n", Rc));
+ ASSERT( FALSE ); // should not happend
+#endif
+ }
+
+ return (Rc);
+}
+
+
+DWORD
+Ow2VioGetCurPos(
+ IN PUSHORT pRow,
+ IN PUSHORT pColumn
+ )
+{
+ DWORD Rc;
+
+ if(SesGrp->WinProcessNumberInSession)
+ {
+ if(Rc = Ow2VioReadCurPos())
+ {
+ return (Rc);
+ }
+ }
+
+ *pRow = (USHORT)SesGrp->WinCoord.Y;
+ *pColumn = (USHORT)SesGrp->WinCoord.X;
+
+ return (NO_ERROR);
+}
+
+
+/*
+ * VIO Cursor Type
+ *
+ * The current Cursor Type for the all session is held:
+ * SesGrp->dwWinCursorSize and SesGrp->bWinCursorVisible - Win32 Type
+ * SesGrp->CursorInfo - OS/2 Type
+ *
+ * Ow2VioReadCurType - calls a Win32 API to retrive the CurType (and update
+ * SesGrp->dwWinCursorSize and SesGrp->bWinCursorVisible).
+ * Ow2VioGetCurType - gets CurType from internal parameter (SesGrp->CursorInfo).
+ * If there's a child Win32 process, Reads it before.
+ * Ow2VioMapOs2CurType2Win - maps the OS/2 CurType to Win32 format
+ * Ow2VioSetCurType - if new CurType or there's a child Win32 process,
+ * maps the CurType and calls Win32 API
+ *
+ * BUGBUG - to add:
+ * Ow2VioMapWinCurType2Os2 - maps the Win32 CurType (from SesGrp) to OS/2 format
+ *
+ * Init => Read
+ * OS/2 Get API => Get
+ * OS/2 Set API => Set
+ * VioPopUp => Set
+ * New screen mode (VioSetMode, VioPopup, VioWrtTTY(Set Mode)) => Set
+ * VioEndPopup => Update SesGrp parms directly
+ * Last Win32 child process termination => Read
+ *
+ * Read =>
+ * Get => Read
+ * Map =>
+ * Set => Map
+ */
+
+
+DWORD
+Ow2VioMapOs2CurType2Win(
+ IN OUT PVIOCURSORINFO pCursorInfo,
+ OUT PCONSOLE_CURSOR_INFO lpCursorInfo)
+{
+ DWORD Diff;
+ USHORT LocalCellVSize = (USHORT)SesGrp->CellVSize;
+
+ if (pCursorInfo->cEnd >= LocalCellVSize)
+
+ if (pCursorInfo->cx > 1)
+ return (ERROR_VIO_WIDTH);
+
+ if (((pCursorInfo->yStart >= LocalCellVSize) &&
+ (pCursorInfo->yStart < 65436)) ||
+ ((pCursorInfo->cEnd >= LocalCellVSize) &&
+ (pCursorInfo->cEnd < 65436)))
+ {
+ // BUGBUG: this is a temporary fix until appl will know we're window !!!
+ // (i.e. SAF has no cursor, CT)
+ // When fix: return the error code always
+
+ if ((pCursorInfo->yStart > 15) ||
+ (pCursorInfo->cEnd > 15))
+ {
+ return (ERROR_VIO_INVALID_PARMS);
+ }
+
+ LocalCellVSize = 16;
+ }
+
+ if (pCursorInfo->yStart >= LocalCellVSize)
+ {
+ pCursorInfo->yStart = (USHORT)((((0 - pCursorInfo->yStart)) * LocalCellVSize - 1)/ 100);
+ }
+
+ if (pCursorInfo->cEnd >= LocalCellVSize)
+ {
+ pCursorInfo->cEnd = (USHORT)((((0 - pCursorInfo->cEnd)) * LocalCellVSize - 1)/ 100);
+ }
+
+ Diff = (DWORD)(pCursorInfo->cEnd - pCursorInfo->yStart);
+ if (Diff >= (DWORD)LocalCellVSize)
+ {
+ Diff += LocalCellVSize;
+ }
+ lpCursorInfo->dwSize = 100 * (Diff + 1) / LocalCellVSize;
+ if (lpCursorInfo->dwSize == 12)
+ { // avoid disappearance
+ lpCursorInfo->dwSize++;
+ }
+ lpCursorInfo->bVisible = (pCursorInfo->attr != 0xffff);
+
+ return (0L);
+}
+
+
+DWORD
+Ow2VioSetCurType(
+ IN PVOID VioCurType
+ )
+{
+ DWORD Rc;
+ PVIOCURSORINFO pCurType = (PVIOCURSORINFO) VioCurType;
+ CONSOLE_CURSOR_INFO lpCursorInfo;
+
+ if( !SesGrp->WinProcessNumberInSession &&
+ !memcmp(VioCurType, (PVOID)&SesGrp->CursorInfo.yStart, sizeof(VIOCURSORINFO)))
+ {
+ /*
+ * No change - ignore request
+ */
+
+ return (NO_ERROR);
+ }
+
+ Rc = Ow2VioMapOs2CurType2Win(
+ pCurType,
+ &lpCursorInfo
+ );
+ if (Rc)
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("OS2SES(Ow2VioSetCurType): Rc %lu\n", Rc));
+ }
+#endif
+ return (Rc);
+ }
+
+ if (!Or2WinSetConsoleCursorInfo(
+ #if DBG
+ Ow2VioSetCurTypeStr,
+ #endif
+ hConOut,
+ &lpCursorInfo
+ ))
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(Ow2VioSetCurType): SetConsoleCursorInfo Rc %lu\n",
+ Rc));
+ ASSERT( FALSE ); // should not happend
+#endif
+ return (Rc);
+ }
+
+ SesGrp->CursorInfo = *pCurType;
+ SesGrp->dwWinCursorSize = lpCursorInfo.dwSize;
+ SesGrp->bWinCursorVisible = lpCursorInfo.bVisible;
+
+ return (NO_ERROR);
+}
+
+
+DWORD
+Ow2VioReadCurType(
+ )
+{
+ DWORD Rc = NO_ERROR;
+ CONSOLE_CURSOR_INFO lpCursorInfo;
+
+ if (Or2WinGetConsoleCursorInfo(
+ #if DBG
+ Ow2VioReadCurTypeStr,
+ #endif
+ hConOut,
+ &lpCursorInfo
+ ))
+ {
+ SesGrp->bWinCursorVisible = lpCursorInfo.bVisible;
+ SesGrp->CursorInfo.attr = (USHORT)((lpCursorInfo.bVisible) ? 0 : 0xffff);
+
+ if ( SesGrp->dwWinCursorSize != lpCursorInfo.dwSize )
+ {
+ SesGrp->dwWinCursorSize = lpCursorInfo.dwSize;
+
+ // BUGBUG
+
+ //MapWin2Os2Cursor(lpCursorInfo, &SesGrp->CursorInfo);
+ }
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ KdPrint(("OS2SES(Ow2VioReadCurType): Rc %lu\n", Rc));
+ ASSERT( FALSE ); // should not happend
+#endif
+ return (Rc);
+ }
+
+ return(NO_ERROR);
+}
+
+
+DWORD
+Ow2VioGetCurType(
+ IN OUT PVOID VioCurType
+ )
+{
+ DWORD Rc = NO_ERROR;
+ PVIOCURSORINFO pCurType = (PVIOCURSORINFO) VioCurType;
+
+ if( SesGrp->WinProcessNumberInSession )
+ {
+ if(Rc = Ow2VioReadCurType())
+ {
+ return (Rc);
+ }
+ }
+
+ *pCurType = SesGrp->CursorInfo;
+ return(NO_ERROR);
+}
+
+#if DBG
+//#define DUMP_VIO_SET_MODE 1
+
+#if DUMP_VIO_SET_MODE
+VOID
+DumpScreenInfo(
+ IN PSZ String,
+ IN HANDLE hConsole
+ )
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScreenInfo1;
+
+ Or2WinGetConsoleScreenBufferInfo(
+ VioSetScreenSizeStr,
+ hConsole,
+ &ScreenInfo1
+ );
+
+ KdPrint((" (%s): Size %x:%x, Pos %x:%x, Attr %x, Win %x:%x-%x:%x, Max %x:%x\n",
+ String,
+ ScreenInfo1.dwSize.Y, ScreenInfo1.dwSize.X,
+ ScreenInfo1.dwCursorPosition.Y, ScreenInfo1.dwCursorPosition.X,
+ ScreenInfo1.wAttributes,
+ ScreenInfo1.srWindow.Top, ScreenInfo1.srWindow.Left,
+ ScreenInfo1.srWindow.Bottom, ScreenInfo1.srWindow.Right,
+ ScreenInfo1.dwMaximumWindowSize.Y, ScreenInfo1.dwMaximumWindowSize.X ));
+}
+#endif
+#endif
+
+
+struct
+{
+ SHORT RowNum;
+ COORD Resolution;
+ COORD Font;
+} HW_MODE_TABLE[] =
+ {
+ {21, {640, 350}, {8, 16}},
+ {25, {720, 400}, {8, 16}},
+ {28, {720, 400}, {8, 14}},
+ {43, {640, 350}, {8, 8}},
+ {00, {720, 400}, {8, 8}} // default to 50 lines
+ };
+
+
+DWORD
+VioSetScreenSize(
+ IN SHORT Row,
+ IN SHORT Col,
+ IN HANDLE hConsole
+ )
+{
+ BOOL SetModeOn = FALSE, Rc = 0;
+ DWORD Status, Err = 0, DisplayMode, OldLVBsize;
+ int i = -1;
+ SMALL_RECT Rect;
+ COORD Coord;
+ CONSOLE_SCREEN_BUFFER_INFO lpScreenBufferInfo;
+
+ Rc = !Or2WinGetConsoleScreenBufferInfo(
+ #if DBG
+ VioSetScreenSizeStr,
+ #endif
+ hConsole,
+ &lpScreenBufferInfo
+ );
+
+ if (Rc)
+ {
+#if DBG
+ KdPrint(("OS2SES(VioSetScreenSize): error %lx\n", Rc));
+#endif
+ ASSERT(FALSE);
+ Status = GetLastError();
+
+ return(1L);
+ }
+
+ if ((Row != SesGrp->ScreenRowNum) ||
+ (Col != SesGrp->ScreenColNum) ||
+ (Row != lpScreenBufferInfo.dwMaximumWindowSize.Y) ||
+ (Col != lpScreenBufferInfo.dwMaximumWindowSize.X))
+ {
+ if ((GetConsoleDisplayMode(&DisplayMode)) &&
+ (DisplayMode & CONSOLE_FULLSCREEN))
+ {
+ for ( i = 0 ; (Row > HW_MODE_TABLE[i].RowNum) && HW_MODE_TABLE[i].RowNum ; i++ );
+ }
+#if DUMP_VIO_SET_MODE
+ KdPrint(("=============================================\n"));
+ KdPrint(("OS2SES(VioSetScreenSize): from %x:%x to %x:%x\n",
+ SesGrp->ScreenRowNum, SesGrp->ScreenColNum, Row, Col));
+ KdPrint(("---------------------------------------------\n"));
+#endif
+
+#if DUMP_VIO_SET_MODE
+ DumpScreenInfo("enter ", hConsole);
+#endif
+
+ Rect.Top = Rect.Left = 0;
+ Rect.Right = (USHORT)( lpScreenBufferInfo.dwMaximumWindowSize.X - 1 );
+ Rect.Bottom = (USHORT)( lpScreenBufferInfo.dwMaximumWindowSize.Y - 1 );
+
+ if ((lpScreenBufferInfo.dwMaximumWindowSize.X > Col) ||
+ (lpScreenBufferInfo.dwMaximumWindowSize.Y > Row ))
+ {
+ if ((lpScreenBufferInfo.dwMaximumWindowSize.X >= Col) &&
+ (lpScreenBufferInfo.dwMaximumWindowSize.Y >= Row ))
+ {
+ SetModeOn = TRUE;
+#if DUMP_VIO_SET_MODE
+ KdPrint((" set Mode ON\n"));
+#endif
+ }
+
+ if (lpScreenBufferInfo.dwMaximumWindowSize.X > Col)
+ Rect.Right = (SHORT)(Col - 1);
+
+ if (lpScreenBufferInfo.dwMaximumWindowSize.Y > Row)
+ Rect.Bottom = (SHORT)(Row - 1);
+
+#if DUMP_VIO_SET_MODE
+ KdPrint((" SetWindowInfo to Size %x:%x-%x:%x\n",
+ Rect.Top, Rect.Left, Rect.Bottom, Rect.Right));
+#endif
+
+ Rc = !Or2WinSetConsoleWindowInfo(
+ #if DBG
+ VioSetScreenSizeStr,
+ #endif
+ hConsole,
+ (BOOL)TRUE,
+ &Rect
+ );
+
+#if DUMP_VIO_SET_MODE
+ DumpScreenInfo("new size ", hConsole);
+#endif
+
+ if (Rc)
+ {
+#if DBG
+ Status = GetLastError();
+ KdPrint(("OS2SES(VioSetScreenSize): SetConsoleWindowInfo error %lu(size %x:%x-%x:%x)\n",
+ Status, Rect.Top, Rect.Left, Rect.Bottom, Rect.Right));
+#endif
+ Err = 1;
+
+// ASSERT(FALSE); // maybe FullScreen
+// return(1L);
+ }
+
+ }
+
+ Rect.Right = (SHORT)(Col - 1);
+ Rect.Bottom = (SHORT)(Row - 1);
+
+ Coord.X = Col;
+ Coord.Y = Row;
+
+#if DUMP_VIO_SET_MODE
+ KdPrint((" SetBufferSize to Size %x:%x\n",
+ Coord.Y, Coord.X));
+#endif
+
+ if (i != -1)
+ {
+ SetConsoleHardwareState(
+ hConsole,
+ HW_MODE_TABLE[i].Resolution,
+ HW_MODE_TABLE[i].Font
+ );
+
+#if DUMP_VIO_SET_MODE
+ DumpScreenInfo("new HW state ", hConsole);
+#endif
+ }
+
+ Rc = !Or2WinSetConsoleScreenBufferSize(
+ #if DBG
+ VioSetScreenSizeStr,
+ #endif
+ hConsole,
+ Coord
+ );
+
+#if DUMP_VIO_SET_MODE
+ DumpScreenInfo("new buffer", hConsole);
+#endif
+
+ if (Rc)
+ {
+#if DBG
+ Status = GetLastError();
+ KdPrint(("OS2SES(VioSetScreenSize): SetConsoleBufferSize error %lu\n", Status));
+
+ if ((Rect.Right != (USHORT)( lpScreenBufferInfo.dwMaximumWindowSize.X - 1 )) ||
+ (Rect.Bottom != (USHORT)( lpScreenBufferInfo.dwMaximumWindowSize.Y - 1 )))
+ {
+ // restore window info
+
+ Rect.Right = (USHORT)( lpScreenBufferInfo.dwMaximumWindowSize.X - 1 );
+ Rect.Bottom = (USHORT)( lpScreenBufferInfo.dwMaximumWindowSize.Y - 1 );
+
+#if DUMP_VIO_SET_MODE
+ KdPrint((" Restore WindowInfo to Size %x:%x-%x:%x\n",
+ Rect.Top, Rect.Left, Rect.Bottom, Rect.Right));
+#endif
+
+ Rc = !Or2WinSetConsoleWindowInfo(
+ #if DBG
+ VioSetScreenSizeStr,
+ #endif
+ hConsole,
+ (BOOL)TRUE,
+ &Rect
+ );
+
+#if DUMP_VIO_SET_MODE
+ DumpScreenInfo("restore size", hConsole);
+#endif
+
+ if (Rc)
+ {
+#if DBG
+ Status = GetLastError();
+ KdPrint(("OS2SES(VioSetScreenSize): restore SetConsoleWindowInfo error %lu(size %x:%x-%x:%x)\n",
+ Status, Rect.Top, Rect.Left, Rect.Bottom, Rect.Right));
+#endif
+ Err = 1;
+
+// ASSERT(FALSE); // maybe FullScreen
+// return(1L);
+ }
+
+ }
+#endif
+
+// ASSERT(FALSE);
+ return(1L);
+ }
+
+ SesGrp->ScreenColNum = Coord.X;
+ SesGrp->ScreenRowNum = Coord.Y;
+ SesGrp->ScreenRect.Right = (SHORT)(SesGrp->ScreenColNum - 1);
+ SesGrp->ScreenRect.Bottom = (SHORT)(SesGrp->ScreenRowNum - 1);
+
+ SesGrp->Os2ModeInfo.col = SesGrp->ScreenColNum;
+ SesGrp->Os2ModeInfo.row = SesGrp->ScreenRowNum;
+ SesGrp->Os2ModeInfo.hres = SesGrp->ScreenColNum * SesGrp->CellHSize;
+ SesGrp->Os2ModeInfo.vres = SesGrp->ScreenRowNum * SesGrp->CellVSize;
+
+ SesGrp->ScreenSize = SesGrp->ScreenRowNum * SesGrp->ScreenColNum;
+ OldLVBsize = SesGrp->LVBsize;
+ SesGrp->LVBsize = (USHORT)(SesGrp->ScreenSize * SesGrp->BytesPerCell);
+ //
+ // if LVB size are changed, update lvb.
+ //
+ if (SesGrp->LVBOn && (SesGrp->LVBsize > OldLVBsize))
+ {
+ ULONG Length = SesGrp->LVBsize;
+ Ow2VioGetLVBBuf(&Length);
+ }
+
+ if (!SetModeOn)
+ {
+ if (i != -1) // FULL SCREEN
+ {
+ Rect.Right = Col - 1;
+ Rect.Bottom = Row - 1;
+ } else
+ {
+ if (Rect.Right >= (StartUpScreenInfo.srWindow.Right - StartUpScreenInfo.srWindow.Left))
+ Rect.Right = StartUpScreenInfo.srWindow.Right - StartUpScreenInfo.srWindow.Left;
+
+ if (Rect.Bottom > (StartUpScreenInfo.srWindow.Bottom - StartUpScreenInfo.srWindow.Top))
+ Rect.Bottom = StartUpScreenInfo.srWindow.Bottom - StartUpScreenInfo.srWindow.Top;
+ }
+
+#if DUMP_VIO_SET_MODE
+ KdPrint((" SetWindowInfo to Size %x:%x-%x:%x\n",
+ Rect.Top, Rect.Left,
+ Rect.Bottom, Rect.Right));
+#endif
+
+ Rc = !Or2WinSetConsoleWindowInfo(
+ #if DBG
+ VioSetScreenSizeStr,
+ #endif
+ hConsole,
+ (BOOL)TRUE,
+ &Rect
+ );
+
+#if DUMP_VIO_SET_MODE
+ DumpScreenInfo("new size ", hConsole);
+#endif
+
+ if (Rc)
+ {
+#if DBG
+ Status = GetLastError();
+ DbgPrint("OS2SES(VioSetScreenSize): SetConsoleWindowInfo error %lu\n", Status);
+#endif
+
+// ASSERT(FALSE);
+// return(1L);
+ }
+ }
+#ifdef DBCS
+// MSKK Jun.28.1992 KazuM
+#if DUMP_VIO_SET_MODE
+ KdPrint(("=============================================\n"));
+ } else
+ {
+ SetScreenSizeParm(Row,Col);
+ KdPrint(("OS2SES(VioSetScreenSize): same screen size %x:%x\n",
+ Row, Col));
+#else
+ } else
+ {
+ SetScreenSizeParm(Row,Col);
+#endif
+#else
+#if DUMP_VIO_SET_MODE
+ KdPrint(("=============================================\n"));
+ } else
+ {
+ KdPrint(("OS2SES(VioSetScreenSize): same screen size %x:%x\n",
+ Row, Col));
+#endif
+#endif
+ }
+
+ if (!Err)
+ {
+ // init CurPos to HOME
+
+ if(Err = Ow2VioSetCurPos(0, 0))
+ {
+ ASSERT( FALSE );
+ return(Err);
+ }
+
+ //BUGBUG=> init CurType
+ }
+
+ return(Err);
+}
+
+
+DWORD
+SetScreenSizeParm(IN SHORT Row,
+ IN SHORT Col)
+{
+ DWORD Status, OldLVBsize;
+ CONSOLE_SCREEN_BUFFER_INFO lpScreenBufferInfo;
+
+ if(!GetConsoleScreenBufferInfo(hConOut,
+ &lpScreenBufferInfo))
+ {
+ ASSERT(FALSE);
+ Status = GetLastError();
+ return(1L);
+ }
+
+ ASSERT( lpScreenBufferInfo.dwSize.X == Col );
+ ASSERT( lpScreenBufferInfo.dwSize.Y == Row );
+
+ SesGrp->ScreenColNum = lpScreenBufferInfo.dwSize.X;
+ SesGrp->ScreenRowNum = lpScreenBufferInfo.dwSize.Y;
+ SesGrp->ScreenRect.Right = (SHORT)(SesGrp->ScreenColNum - 1);
+ SesGrp->ScreenRect.Bottom = (SHORT)(SesGrp->ScreenRowNum - 1);
+
+ SesGrp->Os2ModeInfo.col = SesGrp->ScreenColNum;
+ SesGrp->Os2ModeInfo.row = SesGrp->ScreenRowNum;
+ SesGrp->Os2ModeInfo.hres = SesGrp->ScreenColNum * SesGrp->CellHSize;
+ SesGrp->Os2ModeInfo.vres = SesGrp->ScreenRowNum * SesGrp->CellVSize;
+
+ SesGrp->ScreenSize = SesGrp->ScreenRowNum * SesGrp->ScreenColNum;
+ OldLVBsize = SesGrp->LVBsize;
+ SesGrp->LVBsize = SesGrp->ScreenSize * (ULONG)(SesGrp->BytesPerCell);
+ //
+ // if LVB size are changed, update lvb.
+ //
+ if (SesGrp->LVBOn && (SesGrp->LVBsize > OldLVBsize))
+ {
+ ULONG Length = SesGrp->LVBsize;
+ Ow2VioGetLVBBuf(&Length);
+ }
+
+ return(0L);
+}
+
+
+DWORD
+Ow2VioSetCoordLengthAndCheck(
+ OUT PCOORD pVioCoord,
+ IN OUT PULONG pulLength,
+ IN ULONG ulRow,
+ IN ULONG ulColumn
+ )
+/*++
+
+Routine Description:
+
+ This routine set coord and length of VioRead/Write opeartion after
+ checking argument legally.
+
+Arguments:
+
+ pVioCoord - Where to put the Win32 coordinate for the Vio R/W operation.
+
+ pulLength - Vio R/W operation length. This value is updates to its maximum
+ according the coordinate and screen parameters on output.
+
+ ulRow - Row number
+
+ ulColumn - Column number
+
+Return Value:
+
+ ERROR_VIO_COL - illegal column (returns by Ow2VioSetCoordAndCheck)
+
+ ERROR_VIO_ROW - illegal row (returns by Ow2VioSetCoordAndCheck)
+
+Note:
+
+
+--*/
+{
+ DWORD Rc;
+ ULONG MaxLength;
+
+ if (Rc = Ow2VioSetCoordAndCheck(pVioCoord, ulRow, ulColumn))
+ {
+ return(Rc);
+ }
+
+ MaxLength = SesGrp->ScreenSize - (ulRow * SesGrp->ScreenColNum + ulColumn);
+ if (MaxLength < *pulLength)
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO)
+ KdPrint(("OS2SES(VioRequest): too long %u (%u at %u:%u)\n",
+ *pulLength, MaxLength, ulRow, ulColumn));
+#endif
+ *pulLength = MaxLength;
+ }
+
+ return(NO_ERROR);
+}
+
+
+DWORD
+Ow2VioSetCoordAndCheck(
+ OUT PCOORD pVioCoord,
+ IN ULONG ulRow,
+ IN ULONG ulColumn
+ )
+/*++
+
+Routine Description:
+
+ This routine set coord Vio opeartion after checking argument legally.
+
+Arguments:
+
+ pVioCoord - Where to put the start address coordinates.
+
+ ulRow - Row number
+
+ ulColumn - Column number
+
+Return Value:
+
+ ERROR_VIO_COL - illegal column
+
+ ERROR_VIO_ROW - illegal row
+
+Note:
+
+
+--*/
+{
+ if ( ulColumn >= (ULONG)SesGrp->ScreenColNum )
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO)
+ KdPrint(("OS2SES(VioRequest): illegal Col %u (%u)\n",
+ ulColumn, SesGrp->ScreenColNum));
+#endif
+ return ERROR_VIO_COL;
+ }
+
+ if ( ulRow >= (ULONG)SesGrp->ScreenRowNum )
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO)
+ KdPrint(("OS2SES(VioRequest): illegal Row %u (%u)\n",
+ ulRow, SesGrp->ScreenRowNum));
+#endif
+ return ERROR_VIO_ROW;
+ }
+
+ pVioCoord->X = (SHORT)ulColumn;
+ pVioCoord->Y = (SHORT)ulRow;
+
+ return(NO_ERROR);
+}
+
+
+#if 0
+#if DBG
+ IF_OD2_DEBUG2( VIO, OS2_EXE )
+ {
+ if (PReq->Request == VIOWrtStdOut)
+ {
+ if (PReq->hVio != hConsoleStdOut)
+ KdPrint(("OS2SES(VioRequest): illegal StdOut handle\n"));
+ } else if (PReq->Request == VIOWrtStdErr)
+ {
+ if (PReq->hVio != hConsoleStdErr)
+ KdPrint(("OS2SES(VioRequest): illegal StdErr handle\n"));
+ } else
+ {
+ if (PReq->hVio != hConOut)
+ KdPrint(("OS2SES(VioRequest): illegal handle\n"));
+ }
+ }
+#endif
+
+ if (!EventLoop)
+ {
+#if DBG
+ IF_OD2_DEBUG3( VIO, OS2_EXE, CLEANUP )
+ {
+ KdPrint(("OS2SES(VioRequest): vio request after termination event\n"));
+ }
+#endif
+
+// *(PDWORD) PStatus = -1L; //STATUS_INVALID_PARAMETER;
+// return(TRUE); // Continue
+ }
+#endif
+
+
diff --git a/private/os2/os2ses/viotty.c b/private/os2/os2ses/viotty.c
new file mode 100644
index 000000000..feea87215
--- /dev/null
+++ b/private/os2/os2ses/viotty.c
@@ -0,0 +1,1538 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ viotty.c
+
+Abstract:
+
+ This module contains the VIO-TTY utilities procedures
+
+Author:
+
+ Michael Jarus (mjarus) 12-Apr-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#define WIN32_ONLY
+#include "os2ses.h"
+#include "event.h"
+#include "trans.h"
+#include "vio.h"
+#include "os2win.h"
+#include <io.h>
+#include <stdio.h>
+#include <limits.h>
+
+
+/*
+ * - character definitions for ANSI 3.64
+ */
+
+#define ANSI_ESC 0x1b /* ESC - escape */
+#define ANSI_CUU 0x41 /* ESC[<n>A - cursor up */
+#define ANSI_CUD 0x42 /* ESC[<n>B - cursor down */
+#define ANSI_CUF 0x43 /* ESC[<n>C - cursor forward */
+#define ANSI_CUB 0x44 /* ESC[<n>D - cursor back */
+#define ANSI_CUP 0x48 /* ESC[<row>;<col>H - cursor position */
+#define ANSI_ED 0x4a /* ESC[2J - erase display */
+#define ANSI_EL 0x4b /* ESC[K - erase line */
+#define ANSI_CUP1 0x66 /* ESC[<row>;<col>f - cursor position */
+#define ANSI_SMOD 0x68 /* ESC[=<s>h - set mode */
+#define ANSI_RMOD 0x6c /* ESC[=<s>l - reset mode */
+#define ANSI_SGR 0x6d /* ESC[<g1>;...;<gn>m - select graphic rendition */
+#define ANSI_SCP 0x73 /* ESC[s - save cursor position */
+#define ANSI_RCP 0x75 /* ESC[u - restore cursor position */
+//#define ANSI_ICH 0x40 /* ESC[@ insert character */
+//#define ANSI_CNL 0x45 /* ESC[E cursor to next line */
+//#define ANSI_CPL 0x46 /* ESC[F cursor to previous line */
+//#define ANSI_IL 0x4c /* ESC[L insert line */
+//#define ANSI_DL 0x4d /* ESC[M delete line */
+//#define ANSI_DCH 0x50 /* ESC[P delete character */
+//#define ANSI_SU 0x53 /* ESC[S scroll up */
+//#define ANSI_SD 0x54 /* ESC[T scroll down */
+//#define ANSI_ECH 0x58 /* ESC[X erase character */
+//#define ANSI_CBT 0x5a /* ESC[Z backward tabulation */
+
+/* states of the finite state machine */
+
+#define NOCMD 1 /* type of crt state - most chars will go onto screen */
+#define ESCED 2 /* we've seen an ESC, waiting for rest of CSI */
+#define EQCMD 3 /* if '=' goto MODPARAMS else PARAMS */
+#define PARAMS 4 /* we're building the parameter list for ansicmd */
+#define MODPARAMS 5 /* we're building the parameter list for MODCMD */
+#define MODCMD 6 /* we've seen "ESC[=Num" waiting for #h or #l (# in {0..7}) */
+#define MODDBCS 7 /* we've seen DBCS lead-in char */
+
+#define NPARMS 4 /* max # of params */
+
+#define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)
+#define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
+#define OS2_BACKGROUND_MASK (OS2_BACKGROUND_BLUE | OS2_BACKGROUND_GREEN | OS2_BACKGROUND_RED)
+#define OS2_FOREGROUND_MASK (OS2_FOREGROUND_BLUE | OS2_FOREGROUND_GREEN | OS2_FOREGROUND_RED)
+#define OS2_BACKGROUND_WHITE (OS2_BACKGROUND_BLUE | OS2_BACKGROUND_GREEN | OS2_BACKGROUND_RED)
+#define OS2_FOREGROUND_WHITE (OS2_FOREGROUND_BLUE | OS2_FOREGROUND_GREEN | OS2_FOREGROUND_RED)
+#define OS2_BACKGROUND_BLACK 0
+#define OS2_FOREGROUND_BLACK 0
+#define OS2_DEFAULT (OS2_FOREGROUND_WHITE | OS2_BACKGROUND_BLACK)
+
+#define TTY_LAST_PARMS_MAX ((USHRT_MAX - 10) / 10)
+
+#define TTY_DEST_BUFFER ((PCHAR)Ow2VioDataAddress)
+
+extern CONSOLE_SCREEN_BUFFER_INFO StartUpScreenInfo;
+
+extern HANDLE Od2VioWriteSemHandle;
+
+DWORD
+Od2AcquireMutant(
+ IN HANDLE handle
+ );
+
+DWORD
+Od2ReleaseMutant(
+ IN HANDLE handle
+ );
+
+DWORD
+Ow2VioUpdateCurPos(
+ IN COORD CurPos
+ );
+
+COORD Ow2TtySavedCursorPosition; /* CurPos for saving */
+USHORT Ow2TtyParmList[NPARMS]; /* parameter list */
+ULONG Ow2TtyParmNum; /* index of parameter we're building */
+USHORT Ow2TtyAnsiState; /* state of machine */
+USHORT Ow2TtyIgnoreNextChar;
+COORD Ow2TtyCoord;
+DWORD Ow2TtyNumBytes;
+
+
+DWORD
+Ow2TtyScreen(
+ IN LPSTR SourStr,
+ IN DWORD cnt
+ );
+
+VOID
+Ow2TtyClrParam();
+
+DWORD
+Ow2TtyAnsiCmd(
+ IN CHAR c,
+ OUT BOOL *NewCoord
+ );
+
+USHORT
+Ow2TtyRange(
+ USHORT val,
+ USHORT def,
+ USHORT min,
+ USHORT max
+ );
+
+DWORD
+Ow2TtyFlushStr();
+
+DWORD
+Ow2TtySetAttr();
+
+
+static BYTE ColorTable[8] = { 0, /* Black */
+ 4, /* Red */
+ 2, /* Green */
+ 6, /* Yellow */
+ 1, /* Blue */
+ 5, /* Magenta */
+ 3, /* Cyan */
+ 7}; /* White */
+
+#if DBG
+BYTE Ow2TtyScreenStr[] = "Ow2TtyScreen";
+BYTE Ow2TtyAnsiCmdStr[] = "Ow2TtyAnsiCmd";
+BYTE Ow2TtySetAttrStr[] = "Ow2TtySetAttr";
+BYTE Ow2TtyFlushStrStr[] = "Ow2TtyFlushStr";
+#endif
+
+DWORD
+AnsiInitForSession()
+{
+ SesGrp->AnsiMode = ANSI_ON;
+ SesGrp->WinAttr = (USHORT)StartUpScreenInfo.wAttributes;
+#ifdef DBCS
+// MSKK Feb.2.1993 V-AkihiS
+ MapWin2Os2Attr(SesGrp->WinAttr, &(SesGrp->AnsiCellAttr[0]));
+#else
+ SesGrp->AnsiCellAttr[0] = MapWin2Os2Attr(SesGrp->WinAttr);
+ SesGrp->AnsiCellAttr[1] = SesGrp->AnsiCellAttr[2] = 0;
+#endif
+ SesGrp->ansi_background = SesGrp->AnsiCellAttr[0] & OS2_BACKGROUND_MASK;
+ SesGrp->ansi_foreground = SesGrp->AnsiCellAttr[0] & OS2_FOREGROUND_MASK;
+ SesGrp->ansi_bold = (SesGrp->AnsiCellAttr[0] & OS2_FOREGROUND_INTENSITY) ? 1 : 0;
+ SesGrp->ansi_blink = (SesGrp->AnsiCellAttr[0] & OS2_BACKGROUND_BLINKING) ? 1 : 0;
+
+ return(AnsiInit());
+}
+
+
+DWORD
+AnsiInit()
+{
+ Ow2TtySavedCursorPosition = /*ansi_coord*/SesGrp->WinCoord;
+ Ow2TtyAnsiState = NOCMD; /* state of machine */
+ Ow2TtyIgnoreNextChar = 0;
+
+ return(0L);
+}
+
+
+DWORD
+Ow2VioWriteTTYStr(
+ IN PUCHAR SourStr,
+ IN ULONG Length,
+ IN ULONG ExtRequestType
+ )
+{
+ DWORD Rc;
+ VIOREQUESTNUMBER RequestType = (VIOREQUESTNUMBER) ExtRequestType;
+ USHORT Row, Col;
+
+ if (RequestType == VIOWrtStdOut)
+ {
+ if (!hStdOutConsoleType)
+ {
+ return (ERROR_INVALID_HANDLE);
+ }
+ } else if (RequestType == VIOWrtStdErr)
+ {
+ if (!hStdErrConsoleType)
+ {
+ return (ERROR_INVALID_HANDLE);
+ }
+ }
+
+ Od2AcquireMutant(Od2VioWriteSemHandle);
+
+ if (Rc = Ow2VioGetCurPos(&Row, &Col))
+ {
+#if DBG
+ ASSERT1("OS2SES(VioTTY)-Ow2VioGetCurPos failed\n", FALSE);
+#endif
+ Od2ReleaseMutant(Od2VioWriteSemHandle);
+ return(Rc);
+ }
+
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ UCHAR Buffer[256], *Ptr = SourStr, *Ptr1;
+ ULONG Count = Length, CurCount, i;
+
+ for ( ; Count ; Count -= CurCount, Ptr += CurCount )
+ {
+ CurCount = ( Count > 10 ) ? 10 : Count;
+
+ sprintf(Buffer, "%s %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x ",
+ (Count == Length) ? "OS2SES(VioTTY):" : " " ,
+ Ptr[0], Ptr[1], Ptr[2], Ptr[3], Ptr[4],
+ Ptr[5], Ptr[6], Ptr[7], Ptr[8], Ptr[9]
+ );
+
+ Ptr1 = &Buffer[48];
+ for ( i = 0 ; i < 10 ; i++ )
+ {
+ if ( i >= CurCount )
+ {
+ Buffer[15 + i * 3] = Buffer[16 + i * 3] = Buffer[17 + i * 3] = ' ';
+ } else if (Ptr[i] < 0x20)
+ {
+ if (Ptr[i] == ANSI_ESC)
+ {
+ *Ptr1++ = '<';
+ *Ptr1++ = 'E';
+ *Ptr1++ = 'S';
+ *Ptr1++ = 'C';
+ *Ptr1++ = '>';
+ } else if (Ptr[i] == '\n')
+ {
+ *Ptr1++ = '<';
+ *Ptr1++ = 'N';
+ *Ptr1++ = 'L';
+ *Ptr1++ = '>';
+ } else if (Ptr[i] == '\r')
+ {
+ *Ptr1++ = '<';
+ *Ptr1++ = 'C';
+ *Ptr1++ = 'R';
+ *Ptr1++ = '>';
+ } else if (Ptr[i] == '\b')
+ {
+ *Ptr1++ = '<';
+ *Ptr1++ = 'B';
+ *Ptr1++ = 'S';
+ *Ptr1++ = '>';
+ } else if (Ptr[i] == '\t')
+ {
+ *Ptr1++ = '<';
+ *Ptr1++ = 'T';
+ *Ptr1++ = 'A';
+ *Ptr1++ = 'B';
+ *Ptr1++ = '>';
+ } else if (Ptr[i] == '\07')
+ {
+ *Ptr1++ = '<';
+ *Ptr1++ = 'B';
+ *Ptr1++ = 'E';
+ *Ptr1++ = 'L';
+ *Ptr1++ = 'L';
+ *Ptr1++ = '>';
+ } else
+ {
+ *Ptr1++ = '<';
+ *Ptr1++ = '0';
+ *Ptr1++ = 'x';
+ *Ptr1++ = ((Ptr[i] & 0xF0) >> 4) + '0';
+ *Ptr1++ = (Ptr[i] & 0x0F) + '0';
+ *Ptr1++ = '>';
+ }
+ } else
+ {
+ *Ptr1++ = Ptr[i];
+ }
+ }
+
+ *Ptr1++ = '\n';
+ *Ptr1 = '\0';
+
+ KdPrint((Buffer));
+ }
+ }
+#endif
+
+ Rc = Ow2TtyScreen(
+ SourStr,
+ Length
+ );
+
+ Od2ReleaseMutant(Od2VioWriteSemHandle);
+
+ if (Rc == 1)
+ {
+ Rc = GetLastError();
+ }
+
+ if (Rc)
+ {
+#if DBG
+ KdPrint(("OS2SES(VioTTY-VioWriteTTYStr): Rc %lu\n"));
+ ASSERT( FALSE );
+#endif
+ }
+ return (Rc);
+}
+
+
+/*
+** Basic concepts:
+** The screen consists of rows and columns
+** columns are numbered from the left, starting with one.
+** rows on the screen are numbered from the top, starting with one.
+** Thus, the home position in the upper left corner is row one, column one.
+**
+** Associated with each screen is the 'current active position'.
+** It corresponds roughly to the cursor; in fact, after each call to screen
+** the cursor will indicate the active position. Thus,
+** the cursor movements really change the active position, and
+** the cursor follows the change.
+**
+** This code implements a finite state machine that reads a stream of
+** characters, and emits commands that alter the screen. All of these
+** commands are issued via calls through the 'crtsw' array. Each element
+** of this array consists of an aggregate of functions which are
+** responsible for making the appropriate changes to the actual screen.
+**
+** The functions in the aggregate and their responsibities are:
+**
+** v_scroll(i)
+** scroll the text on the screen i lines.
+** This will move some lines off the screen, and some blank lines
+** onto the screen. i may be negative, indicating that the text
+** moves downward, and blank lines appear at the top.
+** v_copy(sr, sc, dr, dc, cnt)
+** sr and sc specify a source row and column.
+** dr and dc specify a destination row and column.
+** Count characters are copied from the source to the dest,
+** with the copy proceeding from left to right, and top to bottom.
+** If the source and destination overlap, the copy is done
+** correctly.
+** v_clear(r, c, cnt)
+** Characters starting at row r and column are cleared to the
+** space character.
+** v_pchar(r, c, ch)
+** The character ch is placed on the screen at row r, column c,
+** using the current graphic rendition.
+** return value is number of character positions to adjust active
+** position by - zero means the character has no graphic
+** representation.
+** v_scurs(r, c)
+** The cursor is moved to row r, column c.
+** v_init()
+** The screen and all data structures are initialized.
+** v_sgr(i)
+** The current graphic rendition (e. g. font, color) is set to
+** that specified by i. See ANSI x3.64 for encoding.
+*/
+
+DWORD
+Ow2TtyScreen(
+ IN LPSTR SourStr,
+ IN DWORD cnt
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the TTY string and pass characters to the finite
+ state machine
+
+Arguments:
+
+ SourStr - points to the array of characters
+
+ cnt - indicates how many characters are being passed.
+
+Return Value:
+
+
+Note:
+
+
+--*/
+{
+ register CHAR c;
+ BOOL NewCoord = FALSE; // for GET_LVB_PTR
+ BOOL OldWrap, NewWrap, NewParms, ignoreBSFlag;
+ PCHAR LVBPtr;
+ SHORT LFchar = FALSE;
+ DWORD Rc;
+
+
+ Ow2TtyCoord = SesGrp->WinCoord;
+ Ow2TtyNumBytes = 0;
+ LVBPtr = Ow2LvbGetPtr(Ow2TtyCoord);
+
+ while ( cnt-- )
+ {
+ c = *SourStr++;
+
+// if (Ow2TtyIgnoreNextChar)
+// {
+// Ow2TtyIgnoreNextChar = 0;
+// continue;
+// }
+
+ switch ( Ow2TtyAnsiState )
+ {
+ case NOCMD:
+ if (( c == ANSI_ESC ) && SesGrp->AnsiMode)
+ {
+ /*
+ * Found ESC when ASNI_ON
+ * wait for remaining string
+ */
+
+ Ow2TtyAnsiState = ESCED;
+ break;
+ } else
+ {
+#ifdef DBCS
+// MSKK Nov.17.1992 V-AkihiS
+ if (Ow2NlsIsDBCSLeadByte(c, SesGrp->VioCP)) {
+ TTY_DEST_BUFFER[Ow2TtyNumBytes++] = c;
+ Ow2TtyCoord.X++;
+ LVBUpdateTTYCharWithAttrAndCurPosDBCS(c, &LVBPtr, Ow2TtyAnsiState);
+ Ow2TtyAnsiState = MODDBCS;
+ }
+ else
+#endif
+ if( c >= ' ' )
+ {
+ TTY_DEST_BUFFER[Ow2TtyNumBytes++] = c;
+ Ow2TtyCoord.X++;
+ LVBUpdateTTYCharWithAttrAndCurPos(c, &LVBPtr);
+ }else
+ {
+ ignoreBSFlag = FALSE;
+
+ switch(c)
+ {
+ /*
+ * For each char:
+ * - check if to handle (BS at first column, etc.)
+ * - update cursor position (different according to the char)
+ * - update LVB pointer
+ * - put charcater in output buffer
+ */
+
+ case '\n':
+ Ow2TtyCoord.Y++;
+ NewCoord = 1;
+ LFchar = Ow2TtyCoord.X;
+ Ow2TtyCoord.X = 0;
+ break;
+
+ case '\r':
+ if (Ow2TtyCoord.X > 0)
+ {
+ Ow2TtyCoord.X = 0;
+ NewCoord = 1;
+ }
+ break;
+
+ case '\b':
+ if ( Ow2TtyCoord.X > 0 )
+ {
+ Ow2TtyCoord.X--;
+ NewCoord = 1;
+ } else
+ {
+ // wincon move to previous line so don't
+ // pass this char.
+
+ ignoreBSFlag = TRUE;
+ }
+ break;
+
+ case '\t':
+ Ow2TtyCoord.X += (8 - (Ow2TtyCoord.X % 8));
+ NewCoord = 1;
+ break;
+
+ case '\07':
+ break;
+
+ default:
+ Ow2TtyCoord.X++;
+ LVBUpdateTTYCharWithAttrAndCurPos(c, &LVBPtr);
+ break;
+ } /* end switch */
+
+ if (!ignoreBSFlag)
+ {
+ TTY_DEST_BUFFER[Ow2TtyNumBytes++] = c;
+ }
+ }
+ }
+ break;
+
+ case ESCED:
+ switch(c)
+ {
+ case '[':
+ Ow2TtyAnsiState = EQCMD;
+ Ow2TtyClrParam();
+ break;
+
+ default:
+ Ow2TtyAnsiState = NOCMD;
+
+ /*
+ * invalid string -
+ * put back last char and handle it in NOCMD mode
+ */
+
+ cnt++ ;
+ SourStr--;
+ break;
+ }
+ break;
+
+ case EQCMD:
+ if (c == '=')
+ {
+ Ow2TtyAnsiState = MODPARAMS;
+ break;
+ }
+
+ Ow2TtyAnsiState = PARAMS;
+ NewParms = FALSE;
+
+ /* fall down into PARAMS mode */
+
+ case PARAMS:
+ if ( c >= '0' && c <= '9' )
+ {
+ if (Ow2TtyParmList[Ow2TtyParmNum] < TTY_LAST_PARMS_MAX)
+ {
+ Ow2TtyParmList[Ow2TtyParmNum] *= 10;
+ Ow2TtyParmList[Ow2TtyParmNum] += (c - '0');
+ NewParms = TRUE;
+ }
+ } else if (c == ';')
+ {
+ if ( Ow2TtyParmNum < (NPARMS - 1) )
+ {
+ NewParms = FALSE;
+ Ow2TtyParmNum++;
+ //NewParms = TRUE;
+ } else
+ { Ow2TtyAnsiState = NOCMD;
+
+ /*
+ * invalid string -
+ * put back last char and handle it in NOCMD mode
+ */
+
+ cnt++ ;
+ SourStr--;
+ }
+ } else
+ {
+ Ow2TtyAnsiState = NOCMD;
+ if (NewParms || (Ow2TtyParmNum == 0))
+ {
+ Ow2TtyParmNum++;
+ }
+
+ if ((Rc = Ow2TtyAnsiCmd(
+ c,
+ &NewCoord)) == 1)
+ {
+#if DBG
+ KdPrint(("OS2SES(VIOTTY): failed on Ow2TtyAnsiCmd\n"));
+#endif
+ return(1);
+ } else if ( Rc == 2 )
+ {
+ /*
+ * invalid string -
+ * put back last char and handle it in NOCMD mode
+ */
+
+ cnt++ ;
+ SourStr--;
+ }
+ }
+ break;
+
+ case MODPARAMS:
+ if ( c >= '0' && c <= '9' )
+ {
+ if (Ow2TtyParmList[Ow2TtyParmNum] < TTY_LAST_PARMS_MAX)
+ {
+ Ow2TtyParmList[0] *= 10;
+ Ow2TtyParmList[0] += (c - '0');
+ break;
+ }
+ }
+
+ /* fall down into MODCMD mode */
+
+ case MODCMD:
+ Ow2TtyAnsiState = NOCMD;
+ if ( c == 'h' || c == 'l' )
+ {
+ if (Ow2TtyParmList[0] == 7)
+ {
+ OldWrap = ((SesGrp->OutputModeFlags & ENABLE_WRAP_AT_EOL_OUTPUT) != 0);
+ NewWrap = (c == 'h');
+ if (OldWrap != NewWrap)
+ {
+ if(Ow2TtyFlushStr())
+ {
+#if DBG
+ KdPrint(("OS2SES(TTY): failed on FlushStr1\n"));
+#endif
+ return(1);
+ }
+
+ if (!Or2WinSetConsoleMode(
+ #if DBG
+ Ow2TtyScreenStr,
+ #endif
+ hConOut,
+ SesGrp->OutputModeFlags^ENABLE_WRAP_AT_EOL_OUTPUT))
+ {
+#if DBG
+ ASSERT1("OS2SES(TTY): failed on SetConsoleMode\n", FALSE);
+#endif
+ return (1);
+ }
+
+ SesGrp->OutputModeFlags ^= ENABLE_WRAP_AT_EOL_OUTPUT;
+ }
+ break;
+ } else if (Ow2TtyParmList[0] < 7)
+ {
+ if(Ow2TtyFlushStr())
+ {
+#if DBG
+ KdPrint(("OS2SES(TTY): failed on FlushStr2\n"));
+#endif
+ return(1);
+ }
+
+ /* According to the spec
+ =====================
+ 0 => 40x25 black and white
+ 1 => 40x25 color
+ 2 => 80x25 black and white
+ 3 => 80x25 color
+ 4 => 320x200 color
+ 5 => 320x200 black and white
+ 6 => 640x200 black and white
+
+ 0,1,4,5 => 40 col (2,3,6 => 80 col)
+ 1,3,4, => color (0,2,5,6 =>b&w)
+
+ According to OS/2 1.21 (for WIN COM)
+ ====================================
+ 0,1 => 80x50 (2-6 => 80x25)
+ */
+
+ VioSetScreenSize(
+ (SHORT)((Ow2TtyParmList[0] <= 1) ? 50 : 25),
+ (SHORT)80,
+ hConOut);
+
+ Ow2TtyCoord.X = Ow2TtyCoord.Y = 0;
+ NewCoord = TRUE;
+ break;
+ } else
+ {
+ // illegal parameter
+ break;
+ }
+ } // else - illegal character
+
+ /*
+ * invalid string -
+ * put back last char and handle it in NOCMD mode
+ */
+
+ cnt++ ;
+ SourStr--;
+ break;
+
+ case MODDBCS:
+#ifdef DBCS
+// MSKK Feb.06.1992 V-AkihiS
+ TTY_DEST_BUFFER[Ow2TtyNumBytes++] = c;
+ Ow2TtyCoord.X++;
+ LVBUpdateTTYCharWithAttrAndCurPosDBCS(c, &LVBPtr, Ow2TtyAnsiState);
+ Ow2TtyAnsiState = NOCMD;
+#else
+ TTY_DEST_BUFFER[Ow2TtyNumBytes++] = ' ';
+ Ow2TtyCoord.X++;
+ LVBPtr += SesGrp->BytesPerCell;
+ Ow2TtyAnsiState = NOCMD;
+#endif
+ break;
+
+ }
+
+ /*
+ * if past right hand edge
+ * move left and down
+ */
+
+ if ( Ow2TtyCoord.X >= SesGrp->ScreenColNum )
+ {
+ if (SesGrp->OutputModeFlags & ENABLE_WRAP_AT_EOL_OUTPUT)
+ {
+ //Ow2TtyCoord.Y += (Ow2TtyCoord.X / SesGrp->ScreenColNum);
+ //Ow2TtyCoord.X = (Ow2TtyCoord.X % SesGrp->ScreenColNum);
+
+ //if (Ow2TtyCoord.X == 0)
+ //{
+ // Ow2TtyCoord.Y++;
+ //}
+
+ /*
+ * It happends only with '\n', so only one line at a time
+ */
+
+ Ow2TtyCoord.Y++;
+ Ow2TtyCoord.X -= SesGrp->ScreenColNum;
+ } else
+ {
+ Ow2TtyCoord.X = SesGrp->ScreenColNum - 1;
+ NewCoord = TRUE;
+ }
+ } else if ( Ow2TtyCoord.X < 0 )
+ {
+ ASSERT(FALSE);
+ Ow2TtyCoord.X = 0;
+ }
+
+ /* if off screen, scroll */
+
+ if ( Ow2TtyCoord.Y >= SesGrp->ScreenRowNum )
+ {
+ //VioLVBScrollBuff((DWORD)(Ow2TtyCoord.Y - SesGrp->ScreenRowNum + 1));
+
+ /*
+ * It happends only with '\n', so only one line at a time
+ */
+
+ //ASSERT(Ow2TtyCoord.Y == SesGrp->ScreenRowNum);
+
+ VioLVBScrollBuff(1);
+
+ Ow2TtyCoord.Y = SesGrp->ScreenRowNum - 1;
+ NewCoord = TRUE;
+ }
+
+ if (LFchar)
+ {
+ /*
+ * The console doesn't support LF but treats it as CR-LF.
+ * We send LF (does the scroll if necessary) and than move
+ * to the desire column
+ */
+ if(Ow2TtyFlushStr())
+ {
+#if DBG
+ KdPrint(("OS2SES(TTY): failed on FlushStr3\n"));
+#endif
+ return(1);
+ }
+
+ if(Ow2VioSetCurPos((ULONG)Ow2TtyCoord.Y, (ULONG)LFchar))
+ {
+ ASSERT1( "OS2SES(VIOTTY): LF error on Ow2VioSetCurPos", FALSE );
+ }
+
+ Ow2TtyCoord = SesGrp->WinCoord;
+ LFchar = 0;
+ }
+
+ if ( NewCoord )
+ {
+ LVBPtr = Ow2LvbGetPtr(Ow2TtyCoord);
+ NewCoord = FALSE;
+ }
+ }
+
+ /* Flush */
+
+ if(Ow2TtyFlushStr())
+ {
+#if DBG
+ KdPrint(("OS2SES(TTY): failed on FlushStr4\n"));
+#endif
+ return(1);
+ }
+
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ ASSERT( Ow2TtyCoord.X == SesGrp->WinCoord.X );
+ ASSERT( Ow2TtyCoord.Y == SesGrp->WinCoord.Y );
+ }
+#endif
+
+ return(0L);
+}
+
+
+/*
+** Ow2TtyClrParam(lp) - clear the parameters for a screen
+*/
+
+VOID
+Ow2TtyClrParam()
+{
+ register USHORT i;
+
+ for ( i = 0; i < NPARMS; i += 1)
+ Ow2TtyParmList[i] = 0;
+ Ow2TtyParmNum = 0;
+}
+
+
+DWORD
+Ow2TtyAnsiCmd(
+ IN CHAR c,
+ OUT BOOL *NewCoord
+ )
+/*++
+
+Routine Description:
+
+ This routine performs some ANSI 3.64 function, using the parameters
+ we've just gathered.
+
+Arguments:
+
+ c - the character that indicates the function to be performed
+
+ NewCoord = where to flag if new coordinates were set
+
+Return Value:
+
+ Should return 0.
+
+ 1 - for any error (after ASSERT), RetCode from GetLastError().
+
+Note:
+
+ Ow2TtyParmNum - length of parameter list
+
+ Ow2TtyParmList - list of Set Graphics Rendition values
+
+ Ow2TtyCoord - pointer to current screen coordinates
+
+ Ow2TtyCoord is updated if new coordinates were set and it also calls
+ Ow2TtyFlushStr to flush the TTY output buffer to the console.
+
+ hConOut is used for console handle.
+
+ If data/attr is written to the screen (erase line/display), the
+ LVB is updated.
+
+
+--*/
+{
+ DWORD NumFilled;
+ COORD Coord = Ow2TtyCoord;
+ BYTE Cell[4];
+ BOOL ValidCmd = TRUE;
+
+ //if (((Ow2TtyParmNum >= 3) && (c != ANSI_SGR)) ||
+ // ((Ow2TtyParmNum == 2) && (c != ANSI_CUP) && (c != ANSI_CUP1)) ||
+ // ((Ow2TtyParmNum == 1) && ((c == ANSI_SCP) || (c == ANSI_RCP))))
+ //{
+ // ValidCmd = FALSE;
+ //} else
+ switch ( c )
+ {
+ case ANSI_CUB: /* cursor backward */
+ Coord.X -= Ow2TtyRange(Ow2TtyParmList[0], 1, 0, Coord.X);
+ break;
+
+ case ANSI_CUF: /* cursor forward */
+ Coord.X += (SHORT)Ow2TtyRange(Ow2TtyParmList[0], 1, 0, (USHORT)(SesGrp->ScreenColNum - Coord.X - 1));
+ break;
+
+ case ANSI_CUU: /* cursor up */
+ Coord.Y -= Ow2TtyRange(Ow2TtyParmList[0], 1, 0, Coord.Y);
+ break;
+
+ case ANSI_CUD: /* cursor down */
+ Coord.Y += (SHORT)Ow2TtyRange(Ow2TtyParmList[0], 1, 0, (USHORT)(SesGrp->ScreenRowNum - Coord.Y - 1));
+ break;
+
+ case ANSI_CUP: /* cursor position */
+ case ANSI_CUP1: /* cursor position */
+ Coord.Y = (USHORT)Ow2TtyRange(Ow2TtyParmList[0], 1, 1, SesGrp->ScreenRowNum) - 1;
+ Coord.X = (USHORT)Ow2TtyRange(Ow2TtyParmList[1], 1, 1, SesGrp->ScreenColNum) - 1;
+ break;
+
+ case ANSI_ED: /* erase display */
+#if 0
+ switch(Ow2TtyParmList[0])
+ {
+ case 2:
+#endif
+ Coord.X = Coord.Y = 0;
+ if(Ow2TtyFlushStr())
+ {
+ return(1);
+ }
+
+ if (!Or2WinFillConsoleOutputCharacterA(
+ #if DBG
+ Ow2TtyAnsiCmdStr,
+ #endif
+ hConOut,
+ ' ',
+ SesGrp->ScreenSize,
+ Coord,
+ &NumFilled))
+ {
+#if DBG
+ ASSERT1("OS2SES(Ow2TtyAnsiCmd(ED)): failed on FillConsoleOutputCharacterA\n", FALSE);
+#endif
+ return (1);
+ }
+
+ if (!Or2WinFillConsoleOutputAttribute(
+ #if DBG
+ Ow2TtyAnsiCmdStr,
+ #endif
+ hConOut,
+ (WORD)SesGrp->WinAttr,
+ NumFilled,
+ Coord,
+ &NumFilled))
+ {
+#if DBG
+ ASSERT1("OS2SES(Ow2TtyAnsiCmd(ED)): failed on FillConsoleOutputAttribute\n", FALSE);
+#endif
+ return (1);
+ }
+#if DBG
+ ASSERT1("OS2SES(Ow2TtyAnsiCmd(ED)): partial data\n", NumFilled == SesGrp->ScreenSize );
+#endif
+ Cell[0] = ' ';
+ Cell[1] = SesGrp->AnsiCellAttr[0];
+ Cell[2] = SesGrp->AnsiCellAttr[1];
+ Cell[3] = SesGrp->AnsiCellAttr[2];
+ VioLVBFillCell(&Cell[0],
+ Coord,
+ NumFilled);
+ //return(0);
+#if 0
+ break;
+
+ case 0:
+ lclear(hConOut, Coord.X, Coord.Y,
+ ((SesGrp->ScreenRowNum - Coord.X) * SesGrp->ScreenColNum) +
+ ((SesGrp->ScreenColNum - Coord.X) + 1 ), SA_BONW);
+ break;
+ case 1:
+ lclear(hConOut, 0, 0, (Coord.Y)*SesGrp->ScreenColNum+Coord.X, SA_BONW);
+ break;
+
+ default:
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("OS2SES(Ow2TtyAnsiCmd): unknown value(%u) for ED\n",
+ Ow2TtyParmList[0]));
+ }
+#endif
+ ValidCmd = FALSE;
+ break;
+ }
+#endif
+ break;
+
+ case ANSI_EL:
+#if 0
+ switch(Ow2TtyParmList[0])
+ {
+ case 0:
+#endif
+ if(Ow2TtyFlushStr())
+ {
+ return(1);
+ }
+
+ if (!Or2WinFillConsoleOutputCharacterA(
+ #if DBG
+ Ow2TtyAnsiCmdStr,
+ #endif
+ hConOut,
+ ' ',
+ (DWORD)(SesGrp->ScreenColNum - Coord.X),
+ Coord,
+ &NumFilled))
+ {
+#if DBG
+ ASSERT1("OS2SES(Ow2TtyAnsiCmd(EL)): failed on FillConsoleOutputCharacterA\n", FALSE);
+#endif
+ return (1);
+ }
+
+ if (!Or2WinFillConsoleOutputAttribute(
+ #if DBG
+ Ow2TtyAnsiCmdStr,
+ #endif
+ hConOut,
+ (WORD)SesGrp->WinAttr,
+ NumFilled,
+ Coord,
+ &NumFilled))
+ {
+#if DBG
+ ASSERT1("OS2SES(Ow2TtyAnsiCmd(EL)): failed on FillConsoleOutputAttribute\n", FALSE);
+#endif
+ return (1);
+ }
+
+#if DBG
+ ASSERT1("OS2SES(Ow2TtyAnsiCmd(EL)): partial data\n",
+ NumFilled == (DWORD)(SesGrp->ScreenColNum - Coord.X));
+#endif
+ Cell[0] = ' ';
+ Cell[1] = SesGrp->AnsiCellAttr[0];
+ Cell[2] = SesGrp->AnsiCellAttr[1];
+ Cell[3] = SesGrp->AnsiCellAttr[2];
+ VioLVBFillCell(&Cell[0],
+ Coord,
+ NumFilled);
+ //return(0);
+#if 0
+ break;
+
+ break;
+ case 1: /* start to ap */
+ lclear(hConOut, 0, Coord.Y, Coord.X, SA_BONW);
+ break;
+ case 2: /* whole line */
+ lclear(hConOut, 0, Coord.Y, SesGrp->ScreenColNum, SA_BONW);
+ break;
+ default:
+
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("OS2SES(Ow2TtyAnsiCmd): unknown value(%u) for ED\n",
+ Ow2TtyParmList[0]));
+ }
+#endif
+ ValidCmd = FALSE;
+ break;
+ }
+#endif
+ break;
+
+ case ANSI_SGR:
+ if(Ow2TtySetAttr())
+ {
+ return(1);
+ }
+ return(0);
+
+ case ANSI_SCP:
+ Ow2TtySavedCursorPosition = Coord;
+ break;
+
+ case ANSI_RCP:
+ Coord = Ow2TtySavedCursorPosition;
+ break;
+
+#if 0
+
+ case ANSI_CPL: /* cursor to previous line */
+ Coord.Y -= Ow2TtyRange(Ow2TtyParmList[0], 1, 1, SesGrp->ScreenRowNum);
+ Coord.X = 1;
+ break;
+
+ case ANSI_CNL: /* cursor to next line */
+ Coord.Y += Ow2TtyRange(Ow2TtyParmList[0], 1, 1, SesGrp->ScreenRowNum);
+ Coord.X = 1;
+ break;
+
+ case ANSI_CBT: /* tab backwards */
+ col = Coord.X;
+ i = Ow2TtyRange(Ow2TtyParmList[0], 1, 1, (col + 7) >> 3);
+ if (col & 7)
+ {
+ Coord.X = (col & ~7) + 1;
+ --i;
+ }
+ Coord.X -= (i << 3);
+ break;
+
+ case ANSI_DCH: /* delete character */
+ Ow2TtyParmList[0] = Ow2TtyRange(Ow2TtyParmList[0], 1, 1, (SesGrp->ScreenColNum - Coord.X) + 1);
+ if ( Coord.X + Ow2TtyParmList[0] <= SesGrp->ScreenColNum ) {
+ lcopy(hConOut, Coord.X+Ow2TtyParmList[0]-1, Coord.Y-1,
+ Coord.X-1, Coord.Y-1, SesGrp->ScreenColNum-(Coord.X+Ow2TtyParmList[0]-1));
+ }
+ lclear(hConOut, SesGrp->ScreenColNum-Ow2TtyParmList[0], Coord.Y-1,
+ Ow2TtyParmList[0], SA_BONW);
+ break;
+
+ case ANSI_DL: /* delete line */
+ Ow2TtyParmList[0] = Ow2TtyRange(Ow2TtyParmList[0], 1, 1, (SesGrp->ScreenRowNum - Coord.Y) + 1);
+ /* copy lines up */
+ if ( Coord.Y + Ow2TtyParmList[0] <= SesGrp->ScreenRowNum ) {
+ lcopy(hConOut, 0, Coord.Y+Ow2TtyParmList[0]-1, 0, Coord.Y-1,
+ SesGrp->ScreenColNum*(SesGrp->ScreenRowNum-(Coord.Y+Ow2TtyParmList[0]-1)));
+ }
+ /* clear new stuff */
+ lclear(hConOut, 0, SesGrp->ScreenRowNum-Ow2TtyParmList[0],
+ SesGrp->ScreenColNum*Ow2TtyParmList[0], SA_BONW);
+ break;
+
+ case ANSI_ECH: /* erase character */
+ Ow2TtyParmList[0] = Ow2TtyRange( Ow2TtyParmList[0], 1, 1, (SesGrp->ScreenColNum - Coord.X) + 1);
+ lclear(hConOut, Coord.X-1, Coord.Y-1, Ow2TtyParmList[0], SA_BONW);
+ break;
+
+ case ANSI_ICH: /* insert character */
+ Ow2TtyParmList[0] = Ow2TtyRange( Ow2TtyParmList[0], 1, 1, (SesGrp->ScreenColNum - Coord.X) + 1);
+ if ( Coord.X + Ow2TtyParmList[0] <= SesGrp->ScreenColNum ) {
+ lcopy(hConOut, Coord.X-1, Coord.Y-1, Coord.X+Ow2TtyParmList[0]-1,
+ Coord.Y-1, SesGrp->ScreenColNum-(Coord.X+Ow2TtyParmList[0]-1));
+ }
+ lclear(hConOut, Coord.X-1, Coord.Y-1, Ow2TtyParmList[0], SA_BONW);
+ break;
+
+ case ANSI_IL: /* insert line */
+ Ow2TtyParmList[0] = Ow2TtyRange(Ow2TtyParmList[0], 1, 1, (SesGrp->ScreenRowNum - Coord.Y) + 1);
+ /* copy lines down */
+ if ( Coord.Y + Ow2TtyParmList[0] <= SesGrp->ScreenRowNum ) {
+ lcopy(hConOut, 0, Coord.Y-1, 0, Coord.Y+Ow2TtyParmList[0]-1,
+ SesGrp->ScreenColNum * ( SesGrp->ScreenRowNum-(Coord.Y+Ow2TtyParmList[0]-1)));
+ }
+ /* clear new stuff */
+ lclear(hConOut, 0, Coord.Y-1, SesGrp->ScreenColNum * Ow2TtyParmList[0], SA_BONW);
+ break;
+
+ case ANSI_SU: /* scroll up */
+ Ow2TtyParmList[0] = Ow2TtyRange(Ow2TtyParmList[0], 1, 1, SesGrp->ScreenRowNum);
+ lscroll(hConOut, Ow2TtyParmList[0], SA_BONW);
+ break;
+
+ case ANSI_SD: /* scroll down */
+ Ow2TtyParmList[0] = -Ow2TtyRange(Ow2TtyParmList[0], 1, 1, SesGrp->ScreenRowNum);
+ lscroll(hConOut, Ow2TtyParmList[0], SA_BONW);
+ break;
+#endif
+
+ default:
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("OS2SES(Ow2TtyAnsiCmd): unknown cmd 0x%x\n", c));
+ }
+#endif
+ ValidCmd = FALSE;
+ break;
+ }
+
+ if (!ValidCmd)
+ {
+ return(2);
+ } else if ((Coord.X != Ow2TtyCoord.X) ||
+ (Coord.Y != Ow2TtyCoord.Y))
+ {
+ if(Ow2TtyFlushStr())
+ {
+ return(1);
+ }
+
+ if(Ow2VioSetCurPos((ULONG)Coord.Y, (ULONG)Coord.X))
+ {
+ ASSERT1( "OS2SES(VIOTTY): AnsiCmd error on Ow2VioSetCurPos", FALSE );
+ }
+
+ Ow2TtyCoord= SesGrp->WinCoord;
+ *NewCoord = TRUE;
+ }
+
+ return (0);
+}
+
+
+USHORT
+Ow2TtyRange(
+ IN USHORT val,
+ IN USHORT def,
+ IN USHORT min,
+ IN USHORT max
+ )
+/*++
+
+Routine Description:
+
+ This routine restrict a value to range or supply a default.
+
+Arguments:
+
+ val - the value to be restricted.
+
+ default - the value to use if val is zero
+
+ min - the minimum value
+
+ max - the maximum value
+
+Return Value:
+
+
+Note:
+
+
+--*/
+{
+ if ( val == 0 )
+ val = def;
+ if ( val >= max )
+ return max;
+ if ( val < min )
+ return min;
+ return val;
+}
+
+
+DWORD
+Ow2TtySetAttr(
+ )
+/*++
+
+Routine Description:
+
+ This routine set new attribute ("ESC[g;...;gm").
+
+Arguments:
+
+
+Return Value:
+
+ Should return 0.
+
+ 1 - for any error (after ASSERT), RetCode from GetLastError().
+
+Note:
+
+ Ow2TtyParmNum - length of parameter list
+
+ Ow2TtyParmList - list of Set Graphics Rendition values
+
+ Ow2TtyCoord - pointer to current screen coordinates
+
+ If new attributes is set, it also calls Ow2TtyFlushStr to flush the TTY
+ output buffer to the console.
+
+ hConOut is used for console handle.
+
+ Uses and updates: SesGrp->AnsiCellAttr, SesGrp->ansi_bold, SesGrp->ansi_blink,
+ SesGrp->ansi_background, SesGrp->ansi_foreground, SesGrp->WinAttr
+
+--*/
+{
+ BYTE NewAttr, LastAttr = SesGrp->AnsiCellAttr[0]; /* attribute of TTY */
+ ULONG i;
+ USHORT AnsiParm;
+ WORD WinAttr;
+#ifdef DBCS
+// MSKK Jun.28.1992 KazuM
+ BYTE CommonAttr[3];
+#endif
+
+ for ( i = 0 ; i < Ow2TtyParmNum ; i++ )
+ {
+ AnsiParm = Ow2TtyParmList[i];
+
+ if (AnsiParm == 0)
+ {
+ /* ATTRIBUTE OFF */
+ /*****************/
+
+ // The default is according to Win. This sequence reset
+ // all the attribute only but doesn't change the color.
+ // According to VI.exe (set term-ibmans, fail on find-string
+ // and Jump to next line till end of screen, #2221, 5/2/93)
+ // and the updated os2tst\viowrt.
+
+ SesGrp->ansi_blink = SesGrp->ansi_bold = 0;
+ SesGrp->ansi_background = OS2_BACKGROUND_BLACK;
+ SesGrp->ansi_foreground = OS2_FOREGROUND_WHITE;
+
+ } else if (AnsiParm <= 8)
+ {
+ if (AnsiParm == 1)
+ {
+ /* BOLD */
+ /********/
+
+ SesGrp->ansi_bold = 1;
+
+ } else if (AnsiParm == 2)
+ {
+ /* FAINT */
+ /**********/
+
+ } else if (AnsiParm == 3)
+ {
+ /* ITALIC */
+ /**********/
+
+ } else if (AnsiParm == 4)
+ {
+ /* ?BLUE? */
+ /**********/
+
+ SesGrp->ansi_foreground = OS2_FOREGROUND_BLUE;
+
+ } else if (AnsiParm == 5)
+ {
+ /* BLINK */
+ /*********/
+
+ SesGrp->ansi_blink |= 1;
+
+ } else if (AnsiParm == 6)
+ {
+ /* RAPID-BLINK */
+ /***************/
+
+ } else if (AnsiParm == 7)
+ {
+ /* REVERSE VIDEO */
+ /*****************/
+
+ // BLACK over WHITE
+
+ SesGrp->ansi_foreground = OS2_FOREGROUND_BLACK;
+ SesGrp->ansi_background = OS2_BACKGROUND_WHITE;
+
+ } else if (AnsiParm == 8)
+ {
+ /* CONCEALED */
+ /*************/
+
+ SesGrp->ansi_background = OS2_BACKGROUND_BLACK;
+ SesGrp->ansi_foreground = OS2_FOREGROUND_BLACK;
+ }
+
+ } else if (((AnsiParm >= 30) &&
+ (AnsiParm <= 37)) ||
+ ((AnsiParm >= 40) &&
+ (AnsiParm <= 47)))
+ {
+ /* FORE/BACKGROUND COLOR */
+ /*************************/
+
+ if (AnsiParm >= 40 )
+ {
+ SesGrp->ansi_background = (BYTE)( ColorTable[AnsiParm%10] << 4);
+ } else
+ {
+ SesGrp->ansi_foreground = (BYTE)ColorTable[AnsiParm%10];
+ }
+ }
+ }
+
+ NewAttr = SesGrp->ansi_background | SesGrp->ansi_foreground;
+ if ( SesGrp->ansi_bold )
+ {
+ NewAttr |= OS2_FOREGROUND_INTENSITY;
+ }
+ if ( SesGrp->ansi_blink )
+ {
+ NewAttr |= OS2_BACKGROUND_BLINKING;
+ }
+
+ if (LastAttr != NewAttr)
+ {
+ /* new attribute */
+
+ if(Ow2TtyFlushStr())
+ {
+ return(1);
+ }
+
+#ifdef DBCS
+// MSKK Jun.28.1992 KazuM
+ CommonAttr[0] = NewAttr;
+ CommonAttr[1] = CommonAttr[2] = 0;
+ if (!Or2WinSetConsoleTextAttribute(
+ #if DBG
+ Ow2TtySetAttrStr,
+ #endif
+ hConOut,
+ (WinAttr = MapOs2ToWinAttr(&CommonAttr[0]))))
+#else
+ if (!Or2WinSetConsoleTextAttribute(
+ #if DBG
+ Ow2TtySetAttrStr,
+ #endif
+ hConOut,
+ (WinAttr = MapOs2ToWinAttr(NewAttr))))
+#endif
+ {
+#if DBG
+ ASSERT1("OS2SES(trans-TTY): failed on SetTextAttribute\n", FALSE);
+#endif
+ return (1);
+ } else
+ {
+#if DBG
+ IF_OD2_DEBUG( VIO )
+ {
+ KdPrint(("Ow2TtySetAttr: New attr %x(win %x), Last %x(win %x)\n",
+ NewAttr, WinAttr, LastAttr, SesGrp->WinAttr));
+ }
+#endif
+ SesGrp->AnsiCellAttr[0] = NewAttr;
+ SesGrp->WinAttr = (USHORT)WinAttr;
+ }
+ }
+ return (NO_ERROR);
+}
+
+
+DWORD
+Ow2TtyFlushStr(
+ )
+/*++
+
+Routine Description:
+
+ This routine flush the TTY output string (from TTY_DEST_BUFFER)
+ to the console.
+
+Arguments:
+
+
+Return Value:
+
+ Should return 0.
+
+ 1 - for any error (after ASSERT), RetCode from GetLastError().
+
+Note:
+
+ Ow2TtyCoord - pointer to current screen coordinates after the
+ flush.
+
+ According to Ow2TtyNumBytes, which is reset.
+
+ hConOut is used for console handle.
+
+--*/
+{
+ DWORD NumWritten;
+
+ if ( Ow2TtyNumBytes )
+ {
+ if(!Or2WinWriteConsoleA(
+ #if DBG
+ Ow2TtyFlushStrStr,
+ #endif
+ hConOut,
+ (LPSTR)TTY_DEST_BUFFER,
+ Ow2TtyNumBytes,
+ &NumWritten,
+ NULL))
+ {
+#if DBG
+ ASSERT1("OS2SES(VIOTTY): flush string failed on WriteConsoleA", FALSE);
+#endif
+ return (1);
+ }
+
+#if DBG
+ if ( Ow2TtyNumBytes != NumWritten )
+ {
+ ASSERT1("OS2SES(VIOTTY): flush string partial data WriteConsoleA", FALSE);
+ //IF_OD2_DEBUG2( VIO, OS2_EXE )
+ //{
+ // KdPrint(("OS2SES(VIOTTY): flush string partial data WriteConsoleA from %u to %u\n",
+ // Ow2TtyNumBytes, NumWritten));
+ //}
+ }
+#endif
+
+ Ow2TtyNumBytes = 0;
+ Ow2VioUpdateCurPos(Ow2TtyCoord);
+ }
+
+ return (0L);
+}
+
diff --git a/private/os2/os2ss/makefile b/private/os2/os2ss/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/os2/os2ss/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/os2/os2ss/os2ss.c b/private/os2/os2ss/os2ss.c
new file mode 100644
index 000000000..c61b8bb62
--- /dev/null
+++ b/private/os2/os2ss/os2ss.c
@@ -0,0 +1,165 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2srv.c
+
+Abstract:
+
+ This is the main startup module for the OS/2 Emulation Subsystem Server
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include "os2srv.h"
+
+static WCHAR Os2InitName[] = L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\OS/2 Subsystem for NT\\1.0\\os2.ini";
+
+void __cdecl
+main(
+ IN ULONG argc,
+ IN PCH argv[],
+ IN PCH envp[],
+ IN ULONG DebugFlag OPTIONAL
+ )
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING DirectoryName_U;
+ UNICODE_STRING Os2Init_U;
+ HANDLE Os2IniKeyHandle;
+ CHAR localSecurityDescriptor[SECURITY_DESCRIPTOR_MIN_LENGTH];
+ PSECURITY_DESCRIPTOR securityDescriptor;
+ NTSTATUS Status;
+#if PMNT
+ extern VOID Os2SbProbeForInitialSetup(VOID);
+#endif
+
+ UNREFERENCED_PARAMETER(argc);
+ UNREFERENCED_PARAMETER(argv);
+ UNREFERENCED_PARAMETER(envp);
+ UNREFERENCED_PARAMETER(DebugFlag);
+
+#ifdef PMNT
+ //
+ // Check out if this is the first time after system setup that the OS/2 SS
+ // has been run. If so, do the necessary privileged initialization of the
+ // registry for the OS/2 SS
+ //
+ // Note -- This code has been moved to WINLOGON. It's only duplicated here
+ // (in an older and outdated version) so PMNT can be based on NT build 438.
+ //
+ //
+
+ Os2SbProbeForInitialSetup();
+#endif
+
+ //
+ // Create a root directory in the object name space that will be used
+ // to contain all of the named objects created by the OS/2 Emulation
+ // subsystem.
+ //
+
+ RtlInitUnicodeString( &DirectoryName_U, OS2_SS_ROOT_OBJECT_DIRECTORY );
+
+ Status = RtlCreateSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION );
+ ASSERT( NT_SUCCESS( Status ) );
+
+ Status = RtlSetDaclSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ TRUE,
+ (PACL) NULL,
+ FALSE );
+
+ securityDescriptor = (PSECURITY_DESCRIPTOR) &localSecurityDescriptor;
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &DirectoryName_U,
+ OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
+ NULL,
+ securityDescriptor
+ );
+
+ Status = NtCreateDirectoryObject( &Os2RootDirectory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes
+ );
+
+ ASSERT( NT_SUCCESS( Status ) );
+
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(( "OS2SRV: Unable to initialize server. Status == %X\n",
+ Status
+ ));
+#endif
+ }
+
+ //
+ // Reset OS2.INI key security descriptor (winlogon sets it to admin only)
+ //
+ RtlInitUnicodeString( &Os2Init_U, Os2InitName );
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &Os2Init_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ Status = NtOpenKey(&Os2IniKeyHandle,
+ KEY_ALL_ACCESS,
+ &ObjectAttributes
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("Os2ss: Can't open os2.ini key, rc = %lx\n", Status));
+#endif
+ }
+
+ Status = NtSetSecurityObject(Os2IniKeyHandle,
+ DACL_SECURITY_INFORMATION,
+ securityDescriptor
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ KdPrint(("Os2ss: Can't set security on os2.ini key, rc = %lx\n", Status));
+#endif
+ }
+
+ //
+ // Initialize the OS2 Server Session Manager API Port, the listen thread
+ // one request thread.
+ //
+
+ Status = Os2SbApiPortInitialize();
+ ASSERT( NT_SUCCESS( Status ) );
+
+
+
+ //
+ // Connect to the session manager so we can start foreign sessions
+ //
+
+ Status = SmConnectToSm( &Os2SbApiPortName_U,
+ Os2SbApiPort,
+ IMAGE_SUBSYSTEM_OS2_CUI,
+ &Os2SmApiPort
+ );
+ ASSERT( NT_SUCCESS( Status ) );
+
+ NtTerminateThread( NtCurrentThread(), STATUS_SUCCESS);
+}
diff --git a/private/os2/os2ss/os2ss.rc b/private/os2/os2ss/os2ss.rc
new file mode 100644
index 000000000..e5c5e7d5b
--- /dev/null
+++ b/private/os2/os2ss/os2ss.rc
@@ -0,0 +1,52 @@
+/*
+** Template for version resources. Place this in your .rc file,
+** editing the values for VER_FILETYPE, VER_FILESUBTYPE,
+** VER_FILEDESCRIPTION_STR and VER_INTERNALNAME_STR as needed.
+** See winver.h for possible values.
+**
+** Ntverp.h defines several global values that don't need to be
+** changed except for official releases such as betas, sdk updates, etc.
+**
+** Common.ver has the actual version resource structure that all these
+** #defines eventually initialize.
+*/
+
+#include <windows.h>
+
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DLL
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "OS/2 System Server"
+#define VER_INTERNALNAME_STR "OS2SS.EXE"
+#define VER_ORIGINALFILENAME_STR "OS2SS.EXE"
+
+#include "common.ver"
diff --git a/private/os2/os2ss/sbcnfg.c b/private/os2/os2ss/sbcnfg.c
new file mode 100644
index 000000000..f93a567d9
--- /dev/null
+++ b/private/os2/os2ss/sbcnfg.c
@@ -0,0 +1,1674 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sbcnfg.c
+
+Abstract:
+
+ This module contains the code necessary to initialize the
+ OS/2 SS entries in the registry. Since the SS modifies the
+ system environment, we need a privileged process to do this,
+ and so we run it in os2ss.exe. This initialization takes
+ place the 1st time that os2ss.exe is run after system setup,
+ or whenever the CONFIG.SYS entry in the registry disappears.
+
+Author:
+
+ Ofer Porat (oferp) 16-Mar-1993
+
+Environment:
+
+ User Mode only
+
+Revision History:
+
+ Code was originally in server\srvcnfg.c.
+
+--*/
+
+//
+// Only compiled for PMNT
+//
+
+#ifdef PMNT
+
+#include <wchar.h>
+#include "os2srv.h"
+
+#define PATHLIST_MAX 1024 // max length of pathlists such as Os2LibPath (in characters)
+#define MAX_CONSYS_SIZE 16384 // max size of config.sys buffers (in bytes)
+#define DOS_DEV_LEN 12 // length of "\\DosDevices\\"
+
+static WCHAR Os2SoftwareDirectory[] = L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft";
+static WCHAR Os2ProductDirectory[] = L"OS/2 Subsystem for NT";
+static WCHAR Os2VersionDirectory[] = L"1.0";
+static WCHAR Os2IniName[] = L"os2.ini";
+static WCHAR Os2ConfigSysName[] = L"config.sys";
+static WCHAR Os2Class[] = L"OS2SS";
+static CHAR Os2ConfigSysDefaultValue[] =
+//
+// The '\a' in the following strings will be replaced by the SystemDirectory Value
+//
+"NTREM Here is a summary of what is allowed to appear in this registry entry:\0"
+"NTREM Comments starting with REM will be visible to the user when s/he opens\0"
+"NTREM c:\\config.sys.\0"
+"NTREM Comments starting with NTREM are only visible by direct access to the\0"
+"NTREM registry.\0"
+"NTREM The following OS/2 configuration commands are significant:\0"
+"NTREM COUNTRY=\0"
+"NTREM CODEPAGE=\0"
+"NTREM DEVINFO=KBD,\0"
+"NTREM Any other commands apart from the exceptions listed below will be\0"
+"NTREM visible to an OS/2 program that opens c:\\config.sys, however they are\0"
+"NTREM not used internally by the NT OS/2 SubSystem.\0"
+"NTREM Exceptions:\0"
+"NTREM The following commands are completely ignored. Their true values\0"
+"NTREM appear in the system environment and should be modified using the\0"
+"NTREM Control Panel System applet. Note that LIBPATH is called Os2LibPath\0"
+"NTREM in the NT system environment.\0"
+"SET PATH=<ignored>\0"
+"LIBPATH=<ignored>\0"
+"NTREM In addition, any \"SET=\" commands (except COMSPEC) will be\0"
+"NTREM completely ignored. You should set OS/2 environment variables just\0"
+"NTREM like any other Windows NT environment variables by using the Control\0"
+"NTREM Panel System applet.\0"
+"NTREM If you have an OS/2 editor available, it is highly recommended that you\0"
+"NTREM modify NT OS/2 config.sys coniguration by editing c:\\config.sys with\0"
+"NTREM this editor. This is the documented way to make such modification, and\0"
+"NTREM is therefore less error-prone.\0"
+"NTREM Now comes the actual text.\0"
+"REM\0"
+"REM This is a fake OS/2 config.sys file used by the NT OS/2 SubSystem.\0"
+"REM The following information resides in the Registry and NOT in a disk file.\0"
+"REM OS/2 Apps that access c:\\config.sys actually manipulate this information.\0"
+"REM\0"
+"PROTSHELL=c:\\os2\\pmshell.exe c:\\os2\\os2.ini c:\\os2\\os2sys.ini \a\\cmd.exe\0"
+"SET COMSPEC=\a\\cmd.exe\0"
+;
+
+static WCHAR Os2ConfigSysKeyName[] =
+L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\OS/2 Subsystem for NT\\1.0\\config.sys";
+static WCHAR Os2EnvironmentDirectory[] =
+L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
+static HANDLE Os2EnvironmentKeyHandle = NULL;
+
+static WCHAR Os2OriginalCanonicalConfigSys[] = L"\\DosDevices\\C:\\CONFIG.SYS";
+
+static BOOLEAN Os2LibPathFound = FALSE;
+static WCHAR Os2LibPathValueName[] = L"Os2LibPath";
+static UNICODE_STRING Os2LibPathValueData_U;
+
+static PWSTR pOs2ConfigSys = NULL;
+static ULONG Os2SizeOfConfigSys = 0;
+static PWSTR pOs2UpperCaseConfigSys = NULL;
+
+static WCHAR Os2SystemDirectory[DOS_MAX_PATH_LENGTH];
+
+
+VOID
+Os2InitMBString(
+ PANSI_STRING DestinationString,
+ PCSZ SourceString
+ )
+/*++
+
+Routine Description:
+
+ This routine init an ASCII character string (buffer and length)
+
+Arguments:
+
+ DestinationString - pointer to ansi string to put the result in
+
+ SourceString - pointer to ansi null terminated string to read from
+
+Return Value:
+
+
+Note:
+
+ Od2ProcessCodePage is used as the code page for the mapping.
+
+ Od2CurrentCodePageIsOem is check to see if RtlOem NLS routines
+ can be used.
+--*/
+
+{
+
+ // BUGBUG: add support if Code Page is diff from OEMCP
+
+ RtlInitAnsiString(
+ DestinationString,
+ SourceString);
+
+ return ;
+}
+
+
+NTSTATUS
+Os2MBStringToUnicodeString(
+ PUNICODE_STRING DestinationString,
+ PANSI_STRING SourceString,
+ BOOLEAN AllocateDestinationString
+ )
+/*++
+
+Routine Description:
+
+ This routine map a multibyte character string to its unicode character
+ counterpart.
+
+Arguments:
+
+ DestinationString - pointer to unicode string to get the mapping result
+
+ SourceString - pointer to ansi string to read string to map from
+
+ AllocateDestinationString - flag indicating if need to allocate space
+ for destination string
+
+Return Value:
+
+
+Note:
+
+ Od2ProcessCodePage is used as the code page for the mapping.
+
+ Od2CurrentCodePageIsOem is check to see if RtlOem NLS routines
+ can be used.
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ // BUGBUG: add support if Code Page is diff from OEMCP (use Od2CurrentCodePageIsOem)
+
+ Status = RtlOemStringToUnicodeString(
+ DestinationString,
+ (POEM_STRING)SourceString,
+ AllocateDestinationString
+ );
+
+ return(Status);
+}
+
+
+BOOLEAN
+Os2InitOriginalConfigSysProcessing(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function checks if there is an OS/2 config.sys configuration file on the
+ disk. If so, it opens it and reads it in. The file is converted to UNICODE,
+ and an upper case copy of it is made.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if there's an OS/2 config.sys, and all the operations needed to prepare
+ it have succeeded. FALSE otherwise.
+
+Notes:
+ On success Sets global variables as follows:
+ pOs2ConfigSys - a null-terminated UNICODE copy of the OS/2 config.sys.
+ pOs2UpperCaseConfigSys - an upper case copy of pOs2ConfigSys.
+ Os2SizeOfConfigSys - the number of characters in the above strings.
+
+--*/
+
+{
+ UNICODE_STRING CanonicalConfigDotSys_U;
+ UNICODE_STRING Tmp_U;
+ ANSI_STRING Tmp_MB;
+ OBJECT_ATTRIBUTES Obja;
+ FILE_STANDARD_INFORMATION FileStandardInfo;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ HANDLE ConfigSysFileHandle;
+ PSZ pTempOs2ConfigSys;
+
+ // Try opening OS/2's config.sys file
+
+ RtlInitUnicodeString(&CanonicalConfigDotSys_U, Os2OriginalCanonicalConfigSys);
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalConfigDotSys_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(&ConfigSysFileHandle,
+ FILE_GENERIC_READ,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT )
+ {
+ KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - NtOpenFile-1 %lx\n", Status));
+ }
+#endif
+ return (FALSE);
+ }
+
+ // Get the file length
+
+ Status = NtQueryInformationFile(ConfigSysFileHandle,
+ &IoStatus,
+ &FileStandardInfo,
+ sizeof(FileStandardInfo),
+ FileStandardInformation
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT )
+ {
+ KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - NtQueryInformationFile %lx\n", Status));
+ }
+#endif
+ NtClose(ConfigSysFileHandle);
+ return (FALSE);
+ }
+
+ Os2SizeOfConfigSys = FileStandardInfo.EndOfFile.LowPart;
+
+ // Allocate space for reading it in
+
+ // the + 1 in following parameter is for inserting the NUL character
+
+ pTempOs2ConfigSys = (PSZ) RtlAllocateHeap(Os2Heap, 0, Os2SizeOfConfigSys + 1);
+
+ if (pTempOs2ConfigSys == NULL) {
+#if DBG
+ IF_OS2_DEBUG( INIT )
+ {
+ KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - RtlAllocateHeap pTempOs2ConfigSys\n"));
+ }
+#endif
+ Os2SizeOfConfigSys = 0;
+ NtClose(ConfigSysFileHandle);
+ return (FALSE);
+ }
+
+ pOs2ConfigSys = (PWSTR) RtlAllocateHeap(Os2Heap, 0, (Os2SizeOfConfigSys + 1) * sizeof(WCHAR));
+
+ if (pOs2ConfigSys == NULL) {
+#if DBG
+ IF_OS2_DEBUG( INIT )
+ {
+ KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - RtlAllocateHeap pOs2ConfigSys\n"));
+ }
+#endif
+ Os2SizeOfConfigSys = 0;
+ RtlFreeHeap(Os2Heap, 0, pTempOs2ConfigSys);
+ NtClose(ConfigSysFileHandle);
+ return (FALSE);
+ }
+
+ // Read it in
+
+ Status = NtReadFile(ConfigSysFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ (PVOID)pTempOs2ConfigSys,
+ Os2SizeOfConfigSys,
+ NULL,
+ NULL
+ );
+ NtClose(ConfigSysFileHandle);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT )
+ {
+ KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - NtReadFile %lx\n", Status));
+ }
+#endif
+ Os2SizeOfConfigSys = 0;
+ RtlFreeHeap(Os2Heap, 0, pTempOs2ConfigSys);
+ RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
+ pOs2ConfigSys = NULL;
+ return (FALSE);
+ }
+
+ pTempOs2ConfigSys[Os2SizeOfConfigSys] = '\0';
+
+ // Convert to UNICODE
+
+ Os2InitMBString(&Tmp_MB, pTempOs2ConfigSys);
+
+ Tmp_U.Buffer = pOs2ConfigSys;
+ Tmp_U.MaximumLength = (USHORT) ((Os2SizeOfConfigSys + 1) * sizeof(WCHAR));
+
+ Os2MBStringToUnicodeString(&Tmp_U, &Tmp_MB ,FALSE);
+
+ Os2SizeOfConfigSys = Tmp_U.Length / sizeof(WCHAR);
+
+ pOs2ConfigSys[Os2SizeOfConfigSys] = UNICODE_NULL;
+
+ RtlFreeHeap(Os2Heap, 0, pTempOs2ConfigSys);
+
+ // Prepare the upper case copy
+
+ pOs2UpperCaseConfigSys = (PWSTR) RtlAllocateHeap(Os2Heap, 0, (Os2SizeOfConfigSys + 1) * sizeof(WCHAR));
+ if (pOs2UpperCaseConfigSys == NULL) {
+#if DBG
+ IF_OS2_DEBUG( INIT )
+ {
+ KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - RtlAllocateHeap pOs2UpperConfigSys\n"));
+ }
+#endif
+ Os2SizeOfConfigSys = 0;
+ RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
+ pOs2ConfigSys = NULL;
+ return (FALSE);
+ }
+
+ wcscpy(pOs2UpperCaseConfigSys, pOs2ConfigSys);
+ Or2UnicodeStrupr(pOs2UpperCaseConfigSys);
+
+ //
+ // Verify that the CONFIG.SYS file is really an OS/2 file and not a
+ // DOS file.
+ // Look for certain strings that MUST appear in an OS/2 CONFIG.SYS
+ // file and don't appear in DOS CONFIG.SYS files
+ //
+
+ if ((wcsstr(pOs2UpperCaseConfigSys, L"LIBPATH") == NULL) ||
+ (wcsstr(pOs2UpperCaseConfigSys, L"PROTSHELL") == NULL) ||
+ (wcsstr(pOs2UpperCaseConfigSys, L"PROTECTONLY") == NULL)
+ ) {
+ Os2SizeOfConfigSys = 0;
+ RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
+ RtlFreeHeap(Os2Heap, 0, pOs2UpperCaseConfigSys);
+ pOs2UpperCaseConfigSys = pOs2ConfigSys = NULL;
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+
+VOID
+Os2SetDirectiveProcessingDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ )
+
+/*++
+
+Routine Description:
+
+ This is a Dispatch Routine that is used to process SET directives in OS/2's config.sys
+ file. The directives are entered into the system environment.
+
+Arguments:
+
+ Standard arguments passed to a Dispatch Function, see the description of
+ Or2IterateEnvironment in ssrtl\consys.c
+
+ UserParameter - points to a pointer which indicates the current position in the
+ config.sys registry entry we're building.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UNICODE_STRING VarName_U; // for setting up variable name
+ UNICODE_STRING VarValue_U; // for setting up variable value
+ PWSTR Dest = *(PWSTR *) UserParameter;
+ NTSTATUS Status;
+ ULONG ResultLength;
+ WCHAR wch;
+ KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
+
+ // Set up variable name
+
+ VarName_U.Buffer = Value;
+ VarName_U.Length = 0;
+
+ while ((ValueLen > 0) && (*Value != L'=')) {
+ Value++;
+ VarName_U.Length += sizeof(WCHAR);
+ ValueLen--;
+ }
+
+ if (ValueLen == 0 || // End of line reached without finding '='
+ VarName_U.Length == 0) { // Empty name
+ return;
+ }
+
+ VarName_U.MaximumLength = VarName_U.Length;
+
+ // Following SET directives are ignored
+
+ if (Or2UnicodeEqualCI(VarName_U.Buffer, L"COMSPEC=", 8) ||
+ Or2UnicodeEqualCI(VarName_U.Buffer, L"PATH=", 5) ||
+ Or2UnicodeEqualCI(VarName_U.Buffer, L"VIDEO_DEVICES=", 14) ||
+ Or2UnicodeEqualCI(VarName_U.Buffer, L"VIO_IBMVGA=", 11) ||
+ Or2UnicodeEqualCI(VarName_U.Buffer, L"VIO_VGA=", 8) ||
+ Or2UnicodeEqualCI(VarName_U.Buffer, L"PROMPT=", 7)
+ ) {
+ return;
+ }
+
+ // Here, we have a valid name, followed by '='
+ Value++; // Skip the '='
+ ValueLen--;
+
+ // Set up variable value
+
+ VarValue_U.Buffer = Value;
+ VarValue_U.Length = (USHORT) (ValueLen * sizeof(WCHAR)); // what's left of the line
+ VarValue_U.MaximumLength = VarValue_U.Length;
+
+ //
+ // Update the information in the registry with the info
+ // in the file
+ //
+
+#if 0
+ // not in effect anymore
+ //
+ // The KEYS variable is handled in a special way.
+ // It's put in the registry config.sys in order to prevent possible
+ // conflict.
+ //
+
+ if (Or2UnicodeEqualCI(VarName_U.Buffer, L"KEYS=", 5)) {
+ RtlMoveMemory(Dest, L"SET ", 8);
+ Dest += 4;
+ RtlMoveMemory(Dest, VarName_U.Buffer, VarName_U.Length);
+ Dest += VarName_U.Length / sizeof(WCHAR);
+ *Dest++ = L'=';
+ RtlMoveMemory(Dest, VarValue_U.Buffer, VarValue_U.Length);
+ Dest += VarValue_U.Length / sizeof(WCHAR);
+ *Dest++ = UNICODE_NULL;
+ *(PWSTR *) UserParameter = Dest;
+ return;
+ }
+#endif
+
+ //
+ // Otherwise, it's stored in the system environment
+ //
+
+ //
+ // If Os2EnvironmentKeyHandle is NULL, we don't have
+ // write access to the system environment, and we skip
+ // setting the variable.
+ //
+
+ if (Os2EnvironmentKeyHandle == NULL) {
+ return;
+ }
+
+ //
+ // If a value key of the same name already exists,
+ // don't replace it. This is done in order to prevent
+ // the OS/2 SS from overriding possible NT definitions
+ //
+
+ Status = NtQueryValueKey(Os2EnvironmentKeyHandle,
+ &VarName_U,
+ KeyValuePartialInformation,
+ &KeyValueInfo,
+ sizeof(KeyValueInfo),
+ &ResultLength
+ );
+
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
+
+ //
+ // Set the system wide variable to the value specified
+ // in the original OS/2 config.sys
+ //
+
+ wch = Value[ValueLen];
+ Value[ValueLen] = UNICODE_NULL;
+
+ Status = NtSetValueKey(Os2EnvironmentKeyHandle,
+ &VarName_U,
+ (ULONG)0,
+ REG_EXPAND_SZ,
+ VarValue_U.Buffer,
+ VarValue_U.Length + sizeof(WCHAR)
+ );
+
+ Value[ValueLen] = wch;
+
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SetDirectiveProcessingDispatchFunction: Unable to NtSetValueKey() system env, rc = %X\n",
+ Status));
+ }
+#endif
+ return;
+ }
+
+ } else {
+#if DBG
+ if (Status != STATUS_BUFFER_OVERFLOW) {
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SetDirectiveProcessingDispatchFunction: Unable to NtQueryValueKey() system env, rc = %X\n",
+ Status));
+ }
+ }
+#endif
+ return;
+ }
+}
+
+
+VOID
+Os2CommaProcessingDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ )
+
+/*++
+
+Routine Description:
+
+ This is a Dispatch Routine that is used to process certain directives in OS/2's config.sys
+ file. The directives are copied into the config.sys registry entry we're building.
+ Some directives are truncated after a certain number of commas.
+
+Arguments:
+
+ Standard arguments passed to a Dispatch Function, see the description of
+ Or2IterateEnvironment in ssrtl\consys.c
+
+ UserParameter - points to a pointer which indicates the current position in the
+ config.sys registry entry we're building.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+//
+// Lines passed to this dispatch function need to be copied to the output as are
+// except they should be truncated after a certain number of commas. The
+// following table lists the number of commas. 0 means no truncation.
+//
+ ULONG ItemTable[] = { 1, // COUNTRY
+ 0, // CODEPAGE
+ 2 // DEVINFO (only with KBD)
+ };
+ PWSTR Dest = *(PWSTR *) UserParameter;
+ ULONG CommaCtr;
+
+ if (DispatchTableIndex== 2 && !Or2UnicodeEqualCI(Value, L"KBD,", 4)) {
+ return;
+ }
+
+ // First, copy the Name
+
+ RtlMoveMemory(Dest, Name, NameLen * sizeof(WCHAR));
+ Dest += NameLen;
+ *Dest++ = L'=';
+
+ // Now, copy the value for the right number of commas
+
+ CommaCtr = 0;
+
+ while (ValueLen > 0) {
+ if (ItemTable[DispatchTableIndex] != 0 && *Value == L',') {
+ CommaCtr++;
+ if (CommaCtr == ItemTable[DispatchTableIndex]) {
+ break;
+ }
+ }
+
+ *Dest++ = *Value++;
+ ValueLen--;
+ }
+ *Dest++ = UNICODE_NULL;
+ *(PWSTR *) UserParameter = Dest;
+}
+
+
+VOID
+Os2ProcessOriginalConfigSys(
+ IN OUT PWSTR *DestPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This function processes OS/2's config.sys file after it has been properly initialized
+ by Os2InitOriginalConfigSysProcessing.
+
+Arguments:
+
+ DestPtr - points to a pointer which indicates the current position in the
+ config.sys registry entry we're building.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ static ENVIRONMENT_DISPATCH_TABLE_ENTRY DispatchTable[] =
+ {
+ { L"COUNTRY", L"=", Os2CommaProcessingDispatchFunction, NULL },
+ { L"CODEPAGE", L"=", Os2CommaProcessingDispatchFunction, NULL },
+ { L"DEVINFO", L"=", Os2CommaProcessingDispatchFunction, NULL },
+ { L"LIBPATH", L"=", Or2FillInSearchRecordDispatchFunction, NULL },
+ { L"SET", L" \t", Os2SetDirectiveProcessingDispatchFunction, NULL }
+ };
+ ENVIRONMENT_SEARCH_RECORD LibPathRecord;
+ ULONG i;
+ PWSTR p;
+ WCHAR ch;
+
+ //
+ // Most of the job is done by Or2IterateEnvironment which processes the file
+ // according to a dispatch table.
+ //
+ // LibPath needs to be handled a little differently. We need to process only
+ // the *last* occurence of LIBPATH= in the file (this is the same as OS/2).
+ // Therefore we only record the position of the LIBPATH= statments as we run
+ // into them. After we're finished we'll have the position of the last one,
+ // and we can process that line.
+ //
+
+ for (i = 0; i < 5; i++) {
+ DispatchTable[i].UserParameter = (PVOID) DestPtr;
+ }
+
+ DispatchTable[3].UserParameter = (PVOID)&LibPathRecord;
+ LibPathRecord.DispatchTableIndex = (ULONG)-1;
+
+ Or2IterateEnvironment(pOs2ConfigSys,
+ DispatchTable,
+ 5,
+ CRLF_DELIM);
+
+
+ if (Os2LibPathFound && LibPathRecord.DispatchTableIndex != (ULONG)-1) {
+
+ // handle LIBPATH if there was one
+
+ // get a pointer to the upper case version, so we can append it
+
+ p = pOs2UpperCaseConfigSys + (LibPathRecord.Value - pOs2ConfigSys);
+
+ ch = p[LibPathRecord.ValueLen];
+ p[LibPathRecord.ValueLen] = UNICODE_NULL;
+
+ Or2AppendPathToPath(Os2Heap,
+ p,
+ &Os2LibPathValueData_U,
+ TRUE);
+ p[LibPathRecord.ValueLen] = ch;
+ }
+}
+
+
+VOID
+Os2TerminateOriginalConfigSysProcessing(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Cleans up processing of OS/2's config.sys. Releases the storage used to store the
+ file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
+ RtlFreeHeap(Os2Heap, 0, pOs2UpperCaseConfigSys);
+ pOs2UpperCaseConfigSys = pOs2ConfigSys = NULL;
+}
+
+
+NTSTATUS
+Os2SbBuildSD(
+ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ PACL *pDacl
+ )
+
+/*++
+
+Routine Description:
+
+ Builds a security descriptor for creating our registry keys.
+
+ Administrators -- all access
+ everyone -- read access
+
+Arguments:
+
+ SecurityDescriptor -- supplies a pointer to a preallocated SD that will be built
+ pDacl -- returns a pointer to a dacl that should be released from Os2Heap after
+ we're finished using the security descriptor.
+
+Return Value:
+
+ NT error code.
+
+--*/
+
+{
+ PACL Dacl;
+ PACE_HEADER Pace;
+ PSID AdminAliasSid;
+ ULONG DaclSize;
+ SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
+ SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
+ PSID WorldSid;
+ NTSTATUS Status;
+
+ //
+ // Create the SIDs for local admin and World.
+ //
+
+ Status = RtlAllocateAndInitializeSid(
+ &NtAuthority,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &AdminAliasSid
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAllocateAndInitializeSid(Admin), Status = %lx\n", Status));
+ }
+#endif
+ return (Status);
+ }
+
+ Status = RtlAllocateAndInitializeSid(
+ &WorldSidAuthority,
+ 1,
+ SECURITY_WORLD_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &WorldSid
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAllocateAndInitializeSid(World), Status = %lx\n", Status));
+ }
+#endif
+ return (Status);
+ }
+
+ Status = RtlCreateSecurityDescriptor( SecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlCreateSecurityDescriptor, Status = %lx\n", Status));
+ }
+#endif
+ return (Status);
+ }
+
+
+ //
+ // Compute the size of the buffer needed for the
+ // DACL.
+ //
+
+ DaclSize = sizeof( ACL ) +
+ 2 * (sizeof( ACCESS_ALLOWED_ACE ) - sizeof( ULONG ))
+ +
+ RtlLengthSid( AdminAliasSid ) +
+ RtlLengthSid( WorldSid );
+
+ Dacl = (PACL) RtlAllocateHeap(Os2Heap, 0, DaclSize);
+
+ if (Dacl == NULL) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAllocateHeap failed\n"));
+ }
+#endif
+ return(STATUS_NO_MEMORY);
+ }
+
+ //
+ // Build the ACL
+ //
+
+ Status = RtlCreateAcl ( Dacl, DaclSize, ACL_REVISION2 );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlCreateAcl, Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ return (Status);
+ }
+
+ Status = RtlAddAccessAllowedAce (
+ Dacl,
+ ACL_REVISION2,
+ GENERIC_ALL,
+ AdminAliasSid
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAddAccessAllowedAce(Admin), Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ return (Status);
+ }
+
+ Status = RtlAddAccessAllowedAce (
+ Dacl,
+ ACL_REVISION2,
+ GENERIC_READ,
+ WorldSid
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAddAccessAllowedAce(World), Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ return (Status);
+ }
+
+ Status = RtlGetAce(
+ Dacl,
+ 0L,
+ &Pace
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlGetAce(Admin), Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ return (Status);
+ }
+
+ Pace->AceFlags |= CONTAINER_INHERIT_ACE;
+
+ Status = RtlGetAce(
+ Dacl,
+ 1L,
+ &Pace
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlGetAce(World), Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ return (Status);
+ }
+
+ Pace->AceFlags |= CONTAINER_INHERIT_ACE;
+
+ //
+ // Add the ACL to the security descriptor
+ //
+
+ Status = RtlSetDaclSecurityDescriptor(
+ SecurityDescriptor,
+ TRUE,
+ Dacl, // put (PACL) NULL to allow everyone all access
+ FALSE );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlSetDaclSecurityDescriptor, Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ return (Status);
+ }
+
+ //
+ // These have been copied into the security descriptor, so
+ // we can free them.
+ //
+
+ RtlFreeSid( AdminAliasSid );
+
+ RtlFreeSid( WorldSid );
+
+ *pDacl = Dacl;
+
+ return(STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+Os2SbInitializeRegistryKeys(
+ OUT PHANDLE phConfigSysKeyHandle,
+ OUT PHANDLE phEnvironmentKeyHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates the OS/2 subsystem key hierarchy in the registry. It also opens
+ the config.sys key, and opens the system environment key.
+
+Arguments:
+
+ phConfigSysKeyHandle - Returns a READ/WRITE handle to the config.sys key in the registry.
+
+ phEnvironmentKeyHandle - Returns a READ/WRITE handle to the system environment key.
+ If this key can't be opened due to access denied, NULL is returned and the
+ return value will be STATUS_SUCCESS.
+
+ Note --- If the return value is not a success return value, none of the above return
+ variables can be considered to be valid.
+
+Return Value:
+
+ The value is an NTSTATUS type that is returned when some failure occurs. It may
+ indicate any of several errors that occur during the APIs called in this function.
+ The return value should be tested with NT_SUCCESS().
+
+--*/
+
+{
+ OBJECT_ATTRIBUTES Obja;
+ UNICODE_STRING Class_U;
+ UNICODE_STRING SoftwareDirectory_U;
+ UNICODE_STRING ProductDirectory_U;
+ UNICODE_STRING VersionDirectory_U;
+ UNICODE_STRING Os2IniName_U;
+ UNICODE_STRING ConfigSysName_U;
+ UNICODE_STRING EnvRegDir_U;
+ HANDLE SoftwareKeyHandle;
+ HANDLE ProductKeyHandle;
+ HANDLE VersionKeyHandle;
+ HANDLE Os2IniKeyHandle;
+ HANDLE ConfigSysKeyHandle;
+ HANDLE EnvironmentKeyHandle;
+ ULONG Disposition;
+ NTSTATUS Status;
+ SECURITY_DESCRIPTOR localSecurityDescriptor;
+ PSECURITY_DESCRIPTOR securityDescriptor;
+ PACL Dacl = NULL;
+
+
+ *phConfigSysKeyHandle = NULL;
+ *phEnvironmentKeyHandle = NULL;
+
+ // We start off by creating/opening the registry key hierarchy for our subsystem
+
+ securityDescriptor = &localSecurityDescriptor;
+
+ Status = Os2SbBuildSD(securityDescriptor,
+ &Dacl);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Os2SbBuildSD failed, Status = %lx\n", Status));
+ }
+#endif
+ return (Status);
+ }
+
+ RtlInitUnicodeString(&Class_U, Os2Class);
+
+ RtlInitUnicodeString(&SoftwareDirectory_U, Os2SoftwareDirectory);
+ InitializeObjectAttributes(&Obja,
+ &SoftwareDirectory_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&SoftwareKeyHandle,
+ KEY_CREATE_SUB_KEY,
+ &Obja
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't open software key, rc = %lx\n", Status));
+ }
+#endif
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ return (Status);
+ }
+
+ RtlInitUnicodeString(&ProductDirectory_U, Os2ProductDirectory);
+ InitializeObjectAttributes(&Obja,
+ &ProductDirectory_U,
+ OBJ_CASE_INSENSITIVE,
+ SoftwareKeyHandle,
+ securityDescriptor);
+
+ Status = NtCreateKey(&ProductKeyHandle,
+ KEY_CREATE_SUB_KEY,
+ &Obja,
+ 0,
+ &Class_U,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition
+ );
+ NtClose(SoftwareKeyHandle);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't create product key, rc = %lx\n", Status));
+ }
+#endif
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ return (Status);
+ }
+
+ RtlInitUnicodeString(&VersionDirectory_U, Os2VersionDirectory);
+ InitializeObjectAttributes(&Obja,
+ &VersionDirectory_U,
+ OBJ_CASE_INSENSITIVE,
+ ProductKeyHandle,
+ securityDescriptor);
+
+ Status = NtCreateKey(&VersionKeyHandle,
+ KEY_CREATE_SUB_KEY,
+ &Obja,
+ 0,
+ &Class_U,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition
+ );
+ NtClose(ProductKeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't create version key, rc = %lx\n", Status));
+ }
+#endif
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ return (Status);
+ }
+
+ RtlInitUnicodeString(&Os2IniName_U, Os2IniName);
+ InitializeObjectAttributes(&Obja,
+ &Os2IniName_U,
+ OBJ_CASE_INSENSITIVE,
+ VersionKeyHandle,
+ securityDescriptor);
+
+ Status = NtCreateKey(&Os2IniKeyHandle,
+ KEY_CREATE_SUB_KEY,
+ &Obja,
+ 0,
+ &Class_U,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition
+ );
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't create os2ini key, rc = %lx\n", Status));
+ }
+#endif
+ NtClose(VersionKeyHandle);
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ return (Status);
+ }
+ NtClose(Os2IniKeyHandle);
+
+ RtlInitUnicodeString(&ConfigSysName_U, Os2ConfigSysName);
+ InitializeObjectAttributes(&Obja,
+ &ConfigSysName_U,
+ OBJ_CASE_INSENSITIVE,
+ VersionKeyHandle,
+ securityDescriptor);
+
+ Status = NtCreateKey(&ConfigSysKeyHandle,
+ KEY_READ | KEY_WRITE,
+ &Obja,
+ 0,
+ &Class_U,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition
+ );
+
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ NtClose(VersionKeyHandle);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't create/open config.sys key, rc = %lx\n",
+ Status));
+ }
+#endif
+ return(Status);
+ }
+
+ // Open the environment.
+
+ RtlInitUnicodeString(&EnvRegDir_U, Os2EnvironmentDirectory);
+ InitializeObjectAttributes(&Obja,
+ &EnvRegDir_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&EnvironmentKeyHandle,
+ KEY_READ | KEY_WRITE,
+ &Obja
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Unable to NtOpenKey() the system environment, rc = %lx\n",
+ Status));
+ }
+#endif
+ if (Status != STATUS_ACCESS_DENIED) {
+ NtClose(ConfigSysKeyHandle);
+ return(Status);
+ }
+
+ //
+ // on denied access, return with no error so we can at least create the
+ // config.sys value entry
+ // The caller will know this occured because the environment handle is null.
+ //
+
+ } else {
+ *phEnvironmentKeyHandle = EnvironmentKeyHandle;
+ }
+
+ *phConfigSysKeyHandle = ConfigSysKeyHandle;
+ return (STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+Os2SbInitializeRegistry(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function is responsible for initializing the entire Registry component of the
+ Subsystem. It generates the key hierarchy in the registry.
+
+ In the generation of the key hierarchy, it also generates a config.sys entry.
+ The information in this entry is taken from the following sources:
+
+ -- some default strings we put in (see Os2ConfigSysDefaultValue).
+ -- Information from OS/2's config.sys file is added as follows:
+
+ > SET commands are put in the system environment.
+ Some SET commands are ignored (see Os2SetDirectiveProcessingDispatchFunction)
+ > LIBPATH commands are merged to the Os2LibPath variable in the
+ system environment. A terminating semicolon is added if there
+ is only one path in the path list.
+ > SET PATH= is ignored, and the system path remains the same.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The value is an NTSTATUS type that is returned when some failure occurs. It may
+ indicate any of several errors that occur during the APIs called in this function.
+ The return value should be tested with NT_SUCCESS(). If an unsuccessful value
+ is returned, it means the registry component was not properly initialized.
+
+--*/
+
+{
+ UNICODE_STRING Os2LibPathValueName_U;
+ HANDLE ConfigSysKeyHandle;
+ NTSTATUS Status;
+ UNICODE_STRING ConfigSysName_U;
+ PWCHAR pInfo;
+ PUCHAR Src;
+ PWCHAR Src1;
+ PWCHAR Dest;
+ WCHAR ch, ch1;
+
+ // Create the key hierarchy
+
+ Status = Os2SbInitializeRegistryKeys(&ConfigSysKeyHandle,
+ &Os2EnvironmentKeyHandle);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("OS2SS - Os2SbInitializeRegistry: failed Os2SbInitializeRegistryKeys, rc = %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+
+ //
+ // This is the 1st time the subsystem is running, create the config.sys entry
+ // and migrate information from os/2's config.sys file.
+ //
+
+ Os2LibPathFound = FALSE;
+ Os2LibPathValueData_U.Buffer = NULL;
+
+ if (Os2EnvironmentKeyHandle == NULL) { // we have no write access to the environment
+ goto Os2NoEnvAccess; // skip over the Os2LibPath stuff
+ }
+
+ // Get Os2LibPath from sys env so we can update it.
+
+ if (!Or2GetEnvPath(&Os2LibPathValueData_U,
+ Os2Heap,
+ PATHLIST_MAX,
+ Os2EnvironmentKeyHandle,
+ Os2LibPathValueName,
+ FALSE)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistry: Unable to fetch Os2LibPath from sys env\n"));
+ }
+#endif
+ } else {
+
+ // make sure there's at lease one semicolon
+
+ Or2CheckSemicolon(&Os2LibPathValueData_U);
+
+ Os2LibPathFound = TRUE;
+ }
+
+ if (Os2LibPathFound && Os2LibPathValueData_U.Length == 0) { // it's empty (or nonexistent)
+ // set up a default
+ UNICODE_STRING tmp;
+
+ RtlInitUnicodeString(&tmp, Os2SystemDirectory);
+
+ RtlCopyUnicodeString(&Os2LibPathValueData_U, &tmp);
+
+ RtlAppendUnicodeToString(&Os2LibPathValueData_U, L"\\os2\\dll;");
+
+ Os2LibPathValueData_U.Buffer[Os2LibPathValueData_U.Length/sizeof(WCHAR)] = UNICODE_NULL;
+ }
+
+Os2NoEnvAccess:
+
+ // Now set up the initial regisry config.sys entry.
+
+ // Allocate a buffer to build the config.sys entry in. (it's a multi-string)
+
+ pInfo = (PWCHAR) RtlAllocateHeap(Os2Heap, 0, MAX_CONSYS_SIZE);
+ if (pInfo == NULL)
+ {
+ if (Os2LibPathValueData_U.Buffer != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Os2LibPathValueData_U.Buffer);
+ Os2LibPathValueData_U.Buffer = NULL;
+ Os2LibPathFound = FALSE;
+ }
+ if (Os2EnvironmentKeyHandle != NULL) {
+ NtClose(Os2EnvironmentKeyHandle);
+ Os2EnvironmentKeyHandle = NULL;
+ }
+ NtClose(ConfigSysKeyHandle);
+
+ return (STATUS_BUFFER_TOO_SMALL);
+ }
+
+ // Initially, copy our default value into the entry.
+
+ Src = (PUCHAR) Os2ConfigSysDefaultValue;
+ Dest = pInfo;
+ do
+ {
+ ch = (WCHAR) *Src++;
+ if (ch == L'\a')
+ {
+ Src1 = Os2SystemDirectory;
+ ch1 = *Src1++;
+ while (ch1 != UNICODE_NULL)
+ {
+ *Dest++ = ch1;
+ ch1 = *Src1++;
+ }
+ }
+ else
+ {
+ *Dest++ = ch;
+ }
+ } while (!((ch == UNICODE_NULL) && (*Src == '\0')));
+
+
+ // check if the an OS/2 CONFIG.SYS file already exists on
+ // the drive. Its name will be C:\CONFIG.SYS
+ // If it exists, process it for additional information
+ // The system env will also be updated
+
+ if (Os2InitOriginalConfigSysProcessing()) {
+
+ if (Os2EnvironmentKeyHandle == NULL) { // we have no write access to the environment
+
+ //
+ // We couldn't open a write key to the sys env for some reason, so we
+ // won't be able to migrate SET variables to NT from config.sys.
+ // Perhaps a popup should be generated to notify the user of this at
+ // this point.
+ // Anyway, we go on and only write the config.sys entry, skipping
+ // variable migration.
+ //
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistry: Initializing registry without writing system env\n"));
+ }
+#endif
+ }
+
+ Os2ProcessOriginalConfigSys(&Dest);
+ Os2TerminateOriginalConfigSysProcessing();
+ } else {
+
+ //
+ // add a default "COUNTRY=" line
+ //
+
+ RtlMoveMemory(Dest, L"COUNTRY=", 16);
+ Dest += 8;
+#if 0
+ Dest += swprintf(Dest, L"%.3hu", LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale));
+#else
+ RtlMoveMemory(Dest, L"001", 6);
+ Dest += 3;
+#endif
+ *Dest++ = UNICODE_NULL;
+
+ }
+
+ // Write the new Os2LibPath
+
+ if (Os2LibPathFound) {
+
+ RtlInitUnicodeString(&Os2LibPathValueName_U, Os2LibPathValueName);
+ Status = NtSetValueKey(Os2EnvironmentKeyHandle,
+ &Os2LibPathValueName_U,
+ (ULONG)0,
+ REG_EXPAND_SZ,
+ Os2LibPathValueData_U.Buffer,
+ Os2LibPathValueData_U.Length + sizeof(WCHAR)
+ );
+
+#if DBG
+ if (!NT_SUCCESS(Status))
+ {
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistry: Unable to NtSetValueKey() system environment, rc = %X\n",
+ Status));
+ }
+ }
+#endif
+
+ Os2LibPathFound = FALSE;
+ RtlFreeHeap(Os2Heap, 0, Os2LibPathValueData_U.Buffer);
+ Os2LibPathValueData_U.Buffer = NULL;
+ }
+
+ if (Os2EnvironmentKeyHandle != NULL) {
+ NtClose(Os2EnvironmentKeyHandle);
+ Os2EnvironmentKeyHandle = NULL;
+ }
+
+ // set the REG_MULTI_SZ terminating NUL
+
+ *Dest++ = UNICODE_NULL;
+
+ // Finally, write the config.sys multi-string entry into the registry.
+
+ RtlInitUnicodeString(&ConfigSysName_U, Os2ConfigSysName);
+ Status = NtSetValueKey(ConfigSysKeyHandle,
+ &ConfigSysName_U,
+ (ULONG)0,
+ REG_MULTI_SZ,
+ (PVOID)pInfo,
+ (PBYTE)Dest - (PBYTE)pInfo
+ );
+ RtlFreeHeap(Os2Heap, 0, pInfo);
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistry: Unable to NtSetValueKey() registry config.sys, rc = %X\n",
+ Status));
+ }
+#endif
+ NtClose(ConfigSysKeyHandle);
+ return (Status);
+ }
+
+ NtClose(ConfigSysKeyHandle);
+ return (STATUS_SUCCESS);
+}
+
+
+VOID
+Os2SbProbeForInitialSetup(
+ VOID
+ )
+{
+ OBJECT_ATTRIBUTES Obja;
+ UNICODE_STRING ConfigSysKeyName_U;
+ UNICODE_STRING ConfigSysName_U;
+ PUNICODE_STRING SysDir_U;
+ HANDLE ConfigSysKeyHandle;
+ ULONG ResultLength;
+ USHORT Counter;
+ KEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
+ NTSTATUS Status;
+
+#if DBG
+ Os2Debug |= OS2_DEBUG_INIT;
+#endif
+
+ RtlInitUnicodeString(&ConfigSysKeyName_U, Os2ConfigSysKeyName);
+ InitializeObjectAttributes(&Obja,
+ &ConfigSysKeyName_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&ConfigSysKeyHandle,
+ KEY_READ,
+ &Obja
+ );
+
+ if (NT_SUCCESS(Status)) {
+
+ RtlInitUnicodeString(&ConfigSysName_U, Os2ConfigSysName);
+ Status = NtQueryValueKey(ConfigSysKeyHandle,
+ &ConfigSysName_U,
+ KeyValuePartialInformation,
+ &ValuePartialInformation,
+ 0,
+ &ResultLength
+ );
+
+ NtClose(ConfigSysKeyHandle);
+
+ //
+ // The 2 expected status results are:
+ //
+ // STATUS_OBJECT_NAME_NOT_FOUND - config.sys not yet defined
+ // STATUS_BUFFER_TOO_SMALL - config.sys already defined
+ //
+
+ if (Status == STATUS_BUFFER_TOO_SMALL) {
+ return;
+ }
+
+ if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("OS2SS: Can't Read CONFIG.SYS registry value, Status = %lx\n", Status));
+ }
+#endif
+ return;
+ }
+
+ } else {
+ if (Status != STATUS_OBJECT_PATH_NOT_FOUND &&
+ Status != STATUS_OBJECT_NAME_NOT_FOUND &&
+ Status != STATUS_OBJECT_PATH_INVALID) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("OS2SS: Can't Read CONFIG.SYS registry key, Status = %lx\n", Status));
+ }
+#endif
+ return;
+ }
+ }
+
+
+ //
+ // We need to install the registry stuff
+ //
+
+ //
+ // Create a heap to use for dynamic memory allocation.
+ //
+
+ Os2Heap = RtlCreateHeap( HEAP_GROWABLE,
+ NULL,
+ 0x10000L, // Initial size of heap is 64K
+ 0x1000L, // Commit an initial page
+ NULL,
+ NULL // Reserved
+ );
+ if (Os2Heap == NULL) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("OS2SS: Error at RtlCreateHeap of Os2Heap\n"));
+ }
+#endif
+ return;
+ }
+
+ //
+ // Figure out the system directory by cutting it out of our ImagePathName
+ // (should be something like \DosDevices\%SystemRoot%\system32\os2ss.exe)
+ //
+
+ SysDir_U = (PUNICODE_STRING) &NtCurrentPeb()->ProcessParameters->ImagePathName;
+ for (Counter = (SysDir_U->Length / sizeof(WCHAR)) - 1; SysDir_U->Buffer[Counter] != L'\\'; Counter--) {
+ }
+
+ Counter -= DOS_DEV_LEN;
+
+ RtlMoveMemory(Os2SystemDirectory,
+ SysDir_U->Buffer + DOS_DEV_LEN,
+ Counter * sizeof(WCHAR));
+
+ Os2SystemDirectory[Counter] = UNICODE_NULL;
+
+#if 0
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("\nOS2SS: System Directory is "));
+
+ for (Counter = 0; Os2SystemDirectory[Counter] != UNICODE_NULL; Counter++) {
+ KdPrint(("%c", (CHAR) Os2SystemDirectory[Counter]));
+ }
+
+ KdPrint(("|\n"));
+ }
+#endif
+#endif
+
+ Status = Os2SbInitializeRegistry();
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("OS2SS: Os2SbInitializeRegistry() failed, Status = %lx\n", Status));
+ }
+#endif
+ }
+
+ RtlDestroyHeap(Os2Heap);
+}
+
+#endif // PMNT
diff --git a/private/os2/os2ss/sbinit.c b/private/os2/os2ss/sbinit.c
new file mode 100644
index 000000000..393888dc1
--- /dev/null
+++ b/private/os2/os2ss/sbinit.c
@@ -0,0 +1,96 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sbinit.c
+
+Abstract:
+
+ This module contains the code to initialize the SbApiPort of the OS/2
+ Emulation Subsystem.
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include "os2srv.h"
+
+NTSTATUS
+Os2SbApiPortInitialize( VOID )
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+
+ RtlInitUnicodeString( &Os2SbApiPortName_U, OS2_SS_SBAPI_PORT_NAME );
+
+#if DBG
+ IF_OS2_DEBUG( LPC ) {
+ KdPrint(( "OS2SRV: Creating %wZ port and associated thread\n",
+ &Os2SbApiPortName_U ));
+ }
+#endif
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &Os2SbApiPortName_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtCreatePort( &Os2SbApiPort,
+ &ObjectAttributes,
+ sizeof( SBCONNECTINFO ),
+ sizeof( SBAPIMSG ),
+ sizeof( SBAPIMSG ) * 16
+ );
+
+ ASSERT( NT_SUCCESS( Status ) );
+
+ Status = RtlCreateUserThread( NtCurrentProcess(),
+ NULL,
+ TRUE,
+ 0,
+ 0,
+ 0,
+ Os2SbApiRequestThread,
+ NULL,
+ &Os2ServerThreadHandles[ OS2_SS_SBAPI_REQUEST_THREAD ],
+ &Os2ServerThreadClientIds[ OS2_SS_SBAPI_REQUEST_THREAD ]
+ );
+ ASSERT( NT_SUCCESS( Status ) );
+
+ Status = NtResumeThread( Os2ServerThreadHandles[ OS2_SS_SBAPI_REQUEST_THREAD ], NULL );
+ ASSERT( NT_SUCCESS( Status ) );
+
+ return( Status );
+}
+
+
+VOID
+Os2SbApiPortTerminate(
+ NTSTATUS Status
+ )
+{
+#if DBG
+ IF_OS2_DEBUG( LPC ) {
+ KdPrint(( "OS2SRV: Closing %wZ port and associated thread\n",
+ &Os2SbApiPortName_U
+ ));
+ }
+#endif
+ NtTerminateThread( Os2ServerThreadHandles[ OS2_SS_SBAPI_REQUEST_THREAD ],
+ Status
+ );
+
+ NtClose( Os2SbApiPort );
+ NtClose( Os2SmApiPort );
+}
diff --git a/private/os2/os2ss/sbreqst.c b/private/os2/os2ss/sbreqst.c
new file mode 100644
index 000000000..5b16d5cd7
--- /dev/null
+++ b/private/os2/os2ss/sbreqst.c
@@ -0,0 +1,181 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sbreqst.c
+
+Abstract:
+
+ This module contains the Server Request thread procedure for the Sb
+ API calls exported by the OS/2 Emulation SubSystem to the Session
+ Manager SubSystem.
+
+Author:
+
+ Steve Wood (stevewo) 20-Sep-1989
+
+Revision History:
+
+--*/
+
+#include "os2srv.h"
+
+//PSB_API_ROUTINE Os2ServerSbApiDispatch[ SbMaxApiNumber+1 ] = {
+// Os2SbCreateSession,
+// Os2SbTerminateSession,
+// Os2SbForeignSessionComplete,
+// NULL
+//};
+
+#if DBG
+PSZ Os2ServerSbApiName[ SbMaxApiNumber+1 ] = {
+ "SbCreateSession",
+ "SbTerminateSession",
+ "SbForeignSessionComplete",
+ "Unknown Os2 Sb Api Number"
+};
+#endif // DBG
+
+
+NTSTATUS
+Os2SbApiHandleConnectionRequest(
+ IN PSBAPIMSG Message
+ );
+
+NTSTATUS
+Os2SbApiRequestThread(
+ IN PVOID Parameter
+ )
+{
+ NTSTATUS Status;
+ SBAPIMSG ReceiveMsg;
+ PSBAPIMSG ReplyMsg;
+
+ UNREFERENCED_PARAMETER(Parameter);
+
+ ReplyMsg = NULL;
+ while (TRUE) {
+#if DBG
+ IF_OS2_DEBUG( LPC ) {
+ KdPrint(( "OS2SRV: Sb Api Request Thread waiting...\n" ));
+ }
+#endif
+ Status = NtReplyWaitReceivePort( Os2SbApiPort,
+ NULL,
+ (PPORT_MESSAGE)ReplyMsg,
+ (PPORT_MESSAGE)&ReceiveMsg
+ );
+
+ if (Status != 0) {
+ if (NT_SUCCESS( Status )) {
+ continue; // Try again if alerted or a failure
+ }
+ else {
+#if DBG
+ KdPrint(( "OS2SRV: ReceivePort failed - Status == %X\n", Status ));
+#endif
+ break;
+ }
+ }
+
+ //
+ // Check to see if this is a connection request and handle
+ //
+
+ if (ReceiveMsg.h.u2.s2.Type == LPC_CONNECTION_REQUEST) {
+ Os2SbApiHandleConnectionRequest( &ReceiveMsg );
+ ReplyMsg = NULL;
+ continue;
+ }
+
+ if (ReceiveMsg.ApiNumber >= SbMaxApiNumber) {
+#if DBG
+ KdPrint(( "OS2SRV: %lx is invalid Sb ApiNumber\n",
+ ReceiveMsg.ApiNumber
+ ));
+#endif
+
+ ReceiveMsg.ApiNumber = SbMaxApiNumber;
+ }
+
+#if DBG
+ IF_OS2_DEBUG( LPC ) {
+ KdPrint(( "OS2SRV: %s Sb Api Request received from %lx.%lx\n",
+ Os2ServerSbApiName[ ReceiveMsg.ApiNumber ],
+ ReceiveMsg.h.ClientId.UniqueProcess,
+ ReceiveMsg.h.ClientId.UniqueThread
+ ));
+ }
+#endif // DBG
+
+ ReplyMsg = &ReceiveMsg;
+ if (ReceiveMsg.ApiNumber < SbMaxApiNumber) {
+// if (!(*Os2ServerSbApiDispatch[ ReceiveMsg.ApiNumber ])( &ReceiveMsg )) {
+ ReplyMsg = NULL;
+ // }
+// }
+// else {
+// ReplyMsg->ReturnedStatus = STATUS_NOT_IMPLEMENTED;
+ }
+
+#if DBG
+ IF_OS2_DEBUG( LPC ) {
+ if (ReplyMsg != NULL) {
+ KdPrint(( "OS2SRV: %s Sb Api sending %lx status reply to %lx.%lx\n",
+ Os2ServerSbApiName[ ReceiveMsg.ApiNumber ],
+ ReplyMsg->ReturnedStatus,
+ ReplyMsg->h.ClientId.UniqueProcess,
+ ReplyMsg->h.ClientId.UniqueThread
+ ));
+ }
+ }
+#endif // DBG
+ }
+
+ NtTerminateThread( NtCurrentThread(), Status );
+ //
+ // This line should never be executed
+ //
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+Os2SbApiHandleConnectionRequest(
+ IN PSBAPIMSG Message
+ )
+{
+ NTSTATUS st;
+ REMOTE_PORT_VIEW ClientView;
+ HANDLE CommunicationPort;
+
+ //
+ // The protocol for a subsystem is to connect to the session manager,
+ // then to listen and accept a connection from the session manager
+ //
+
+ ClientView.Length = sizeof(ClientView);
+ st = NtAcceptConnectPort(
+ &CommunicationPort,
+ NULL,
+ (PPORT_MESSAGE)Message,
+ TRUE,
+ NULL,
+ &ClientView
+ );
+
+ if ( !NT_SUCCESS(st) ) {
+ KdPrint(("OS2SS: Sb Accept Connection failed %lx\n",st));
+ return st;
+ }
+
+ st = NtCompleteConnectPort(CommunicationPort);
+
+ if ( !NT_SUCCESS(st) ) {
+ KdPrint(("OS2SS: Sb Complete Connection failed %lx\n",st));
+ }
+
+ return st;
+}
diff --git a/private/os2/os2ss/sources b/private/os2/os2ss/sources
new file mode 100644
index 000000000..fd4ef88eb
--- /dev/null
+++ b/private/os2/os2ss/sources
@@ -0,0 +1,68 @@
+!IF 0
+*****************************************************************************
+Copyright (c) 1989, 1990 Microsoft Corporation
+
+Module Name: SOURCES for OS/2 'mini subsystem'. Real functionality
+ is in ..\server
+
+Author: yarons
+
+Revision History:
+ 04-19-91 larrys original version
+*****************************************************************************
+!ENDIF
+
+#------------------------------------------------
+# INFO FOR CREATING LIBRARY
+#------------------------------------------------
+MAJORCOMP=os2
+MINORCOMP=os2ss
+
+TARGETNAME=os2ss
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+NO_READONLY_STRINGS=1
+
+#------------------------------------------------
+# INCLUDE PATH
+#------------------------------------------------
+
+INCLUDES=..\inc
+
+#------------------------------------------------
+# SOURCE FILES (used to make library)
+#------------------------------------------------
+
+SOURCES= sbinit.c \
+ sbreqst.c \
+ sbcnfg.c \
+ os2ss.rc
+
+#------------------------------------------------
+# FLAGS
+#------------------------------------------------
+
+!IFDEF PMNT
+C_DEFINES=-DPMNT
+!ENDIF
+
+#------------------------------------------------
+# EXECUTABLES
+#------------------------------------------------
+
+UMTYPE=ntss
+UMTEST=os2ss
+
+#------------------------------------------------
+# LIBRARIES created by the SOURCES= line (above)
+# (currently commented out - not used)
+#
+# $(BASEDIR)\public\sdk\lib\*\smdll.lib
+#------------------------------------------------
+
+UMAPPL=os2ss
+UMLIBS= obj\*\os2ss.lib \
+ ..\obj\*\os2ssrtl.lib
+UMRES= obj\*\os2ss.res
+COFFBASE=os2ss
diff --git a/private/os2/server/apiinit.c b/private/os2/server/apiinit.c
new file mode 100644
index 000000000..1f70c7f2c
--- /dev/null
+++ b/private/os2/server/apiinit.c
@@ -0,0 +1,98 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ apiinit.c
+
+Abstract:
+
+ This module contains the code to initialize the ApiPort of the OS/2
+ Emulation Subsystem.
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include "os2srv.h"
+#include "os2win.h"
+#define NTOS2_ONLY
+#include "sesport.h"
+
+
+BOOLEAN
+Os2TerminationThreadInitialize( VOID );
+
+NTSTATUS
+Os2DebugPortInitialize( VOID )
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ ULONG Tid;
+
+ RtlInitUnicodeString( &Os2DebugPortName_U, OS2_SS_DEBUG_PORT_NAME );
+
+#if DBG
+ IF_OS2_DEBUG( LPC ) {
+ KdPrint(( "OS2SRV: Creating %wZ port and associated thread\n",
+ &Os2DebugPortName_U ));
+ }
+#endif
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &Os2DebugPortName_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(( "OS2SRV: Creating %wZ port and associated threads, sizeof( API_MSG ) == %ld\n",
+ &Os2DebugPortName_U, sizeof( OS2_API_MSG )));
+ }
+#endif
+
+ Status = NtCreatePort( &Os2DebugPort,
+ &ObjectAttributes,
+ sizeof( OS2SESCONNECTINFO ),
+ sizeof( OS2_API_MSG ),
+ 4096 * 16
+ );
+ ASSERT( NT_SUCCESS( Status ) );
+
+ //
+ // use same port for exception handling and debugger
+ //
+
+ Os2DebugThreadHandle = CreateThread( NULL,
+ 0,
+ (PFNTHREAD)Os2DebugRequestThread,
+ NULL,
+ 0,
+ &Tid);
+ if (!Os2DebugThreadHandle){
+ ASSERT( FALSE );
+#if DBG
+ KdPrint(("Os2DebugPortInitialize - fail at win32 CreateThread, %d\n",GetLastError()));
+#endif
+ return( STATUS_NO_MEMORY );
+ }
+
+ if (!Os2TerminationThreadInitialize()) {
+#if DBG
+ ASSERT( FALSE );
+ KdPrint(("Os2DebugPortInitialize - fail at Os2TerminationThreadInitialize, %d\n",
+ GetLastError()));
+#endif
+ }
+ return( Status );
+}
diff --git a/private/os2/server/apireqst.c b/private/os2/server/apireqst.c
new file mode 100644
index 000000000..5f79ae431
--- /dev/null
+++ b/private/os2/server/apireqst.c
@@ -0,0 +1,754 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ apireqst.c
+
+Abstract:
+
+ This module contains the Server Request thread procedure
+
+Author:
+
+ Steve Wood (stevewo) 20-Sep-1989
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_ERRORS
+#include "os2srv.h"
+#define NTOS2_ONLY
+#include "sesport.h"
+
+POS2_API_ROUTINE Os2ServerApiDispatch[ Os2MaxApiNumber+1 ] = {
+ Os2InternalNullApiCall,
+ Os2InternalAlertMuxWaiter,
+ Os2InternalCopyHandleTable,
+ Os2InternalDeviceShare,
+ Os2InternalTerminateThread,
+ Os2InternalTerminateProcess,
+ Os2InternalQueryVirtualMemory,
+ Os2InternalMarkSharedMemAsHuge,
+ Os2InternalReallocSharedHuge,
+ Os2DosCreateThread,
+ Os2DosExit,
+ Os2DosWaitChild,
+ Os2DosWaitThread,
+ Os2DosExecPgm,
+ Os2DosKillProcess,
+ Os2DosSetPriority,
+ Os2DosFreeMem,
+ Os2DosGiveSharedMem,
+ Os2DosGetSharedMem,
+ Os2DosGetNamedSharedMem,
+ Os2DosAllocSharedMem,
+ Os2DosCreateEventSem,
+ Os2DosOpenEventSem,
+ Os2DosCloseEventSem,
+ Os2DosCreateMutexSem,
+ Os2DosOpenMutexSem,
+ Os2DosCloseMutexSem,
+ Os2DosCreateMuxWaitSem,
+ Os2DosOpenMuxWaitSem,
+ Os2DosCloseMuxWaitSem,
+ Os2DosWaitMuxWaitSem,
+ Os2DosAddMuxWaitSem,
+ Os2DosDeleteMuxWaitSem,
+ Os2DosQueryMuxWaitSem,
+ Os2DosStartSession,
+ Os2DosSelectSession,
+ Os2DosSetSession,
+ Os2DosStopSession,
+ Os2DosSmSetTitle,
+ Os2DosCreateQueue,
+ Os2DosOpenQueue,
+ Os2DosCloseQueue,
+ Os2DosPurgeQueue,
+ Os2DosQueryQueue,
+ Os2DosPeekQueue,
+ Os2DosReadQueue,
+ Os2DosWriteQueue,
+ Os2DosEnterMustComplete,
+ Os2DosExitMustComplete,
+ Os2DosSetSignalExceptionFocus,
+ Os2DosSendSignalException,
+ Os2DosAcknowledgeSignalException,
+ Os2DosDispatch16Signal,
+ Os2DosGetPriority,
+ Os2DosGetPPID,
+ Os2DosError,
+ Os2DosRegisterCtrlHandler,
+ Os2DosGetCtrlPortForSessionID,
+ Os2DosExitGP,
+ Os2DosCloseHandle,
+ Os2ConfigSysCreator,
+ Os2Netbios2Request,
+ Os2DosReallocSharedMem,
+ Os2DosGetSeg,
+ Os2DosGiveSeg,
+ Os2DosGetShrSeg,
+ Os2DosPTrace,
+ LDRNewExe,
+ LDRDosLoadModule,
+ LDRDosFreeModule,
+ LDRDosGetModName,
+ LDRDosGetModHandle,
+ LDRDosGetProcAddr,
+ LDRDosQAppType,
+ LDRDosGetResource,
+ LDRDosFreeResource,
+#if PMNT
+ LDRIdentifyCodeSelector,
+ PMSetPMshellFlag,
+#endif
+#if PMNT
+ LDRDumpSegments,
+#endif
+ NULL
+};
+
+#if DBG
+PSZ Os2ServerApiName[ Os2MaxApiNumber+1 ] = {
+ "NullApiCall",
+ "AlertMuxWaiter",
+ "CopyHandleTable",
+ "InternalDeviceShare",
+ "InternalTerminateThread",
+ "InternalTerminateProcess",
+ "InternalQueryVirtualMemory",
+ "InternalMarkSharedMemAsHuge",
+ "Os2InternaleReallocSharedHuge",
+ "DosCreateThread",
+ "DosExit",
+ "DosWaitChild",
+ "DosWaitThread",
+ "DosExecPgm",
+ "DosKillProcess",
+ "DosSetPriority",
+ "DosFreeMem",
+ "DosGiveSharedMem",
+ "DosGetSharedMem",
+ "DosGetNamedSharedMem",
+ "DosAllocSharedMem",
+ "DosCreateEventSem",
+ "DosOpenEventSem",
+ "DosCloseEventSem",
+ "DosCreateMutexSem",
+ "DosOpenMutexSem",
+ "DosCloseMutexSem",
+ "DosCreateMuxWaitSem",
+ "DosOpenMuxWaitSem",
+ "DosCloseMuxWaitSem",
+ "DosWaitMuxWaitSem",
+ "DosAddMuxWaitSem",
+ "DosDeleteMuxWaitSem",
+ "DosQueryMuxWaitSem",
+ "DosStartSession",
+ "DosSelectSession",
+ "DosSetSession",
+ "DosStopSession",
+ "DosSmSetTitle",
+ "DosCreateQueue",
+ "DosOpenQueue",
+ "DosCloseQueue",
+ "DosPurgeQueue",
+ "DosQueryQueue",
+ "DosPeekQueue",
+ "DosReadQueue",
+ "DosWriteQueue",
+ "DosEnterMustComplete",
+ "DosExitMustComplete",
+ "DosSetSignalExceptionFocus",
+ "DosSendSignalException",
+ "DosAcknowledgeSignalException",
+ "Dispatch16Signal",
+ "DosGetPriority",
+ "DosGetPPID",
+ "DosError",
+ "DosRegisterCtrlHandler",
+ "DosGetCtrlPortForSessionID",
+ "DosExitGP",
+ "DosCloseHandle",
+ "ConfigSysCreator",
+ "Netbios2Request",
+ "DosReallocSseg",
+ "DosGetSeg",
+ "DosGiveSeg",
+ "Os2DosGetShrSeg",
+ "Os2DosPTrace",
+ "LDRNewExe",
+ "LDRLoadModule",
+ "LDRFreeModule",
+ "LDRGetModuleName",
+ "LDRGetModuleHandle",
+ "LDRGetProcAddr",
+ "LDRQAppType",
+ "LDRGetResource",
+ "LDRFreeResource",
+#if PMNT
+ "LDRIdentifyCodeSelector",
+ "PMSetPMshellFlag",
+#endif
+#if PMNT && DBG
+ "LDRDumpSegments",
+#endif
+ "Unknown Os2 Api Number"
+};
+#endif // DBG
+
+
+NTSTATUS
+Os2ApiRequestThread(
+ IN PVOID Parameter
+ )
+{
+ NTSTATUS Status;
+ POS2_THREAD Thread;
+ POS2_PROCESS Process;
+ UCHAR ReceiveMsgData [sizeof(OS2SESREQUESTMSG) + sizeof(OS2_API_MSG)];
+ OS2_API_MSG *pReceiveMsg = (POS2_API_MSG)ReceiveMsgData;
+ POS2_API_MSG ReplyMsg;
+
+ UNREFERENCED_PARAMETER(Parameter);
+ ReplyMsg = NULL;
+
+ //
+ // At init time - we sync with other server threads
+ //
+ Os2AcquireStructureLock();
+ while (TRUE)
+ {
+
+WaitAgain:
+ //Process = NULL;
+ //
+ // Let other server threads get in after we are done with the request
+ //
+ Os2ReleaseStructureLock();
+ Status = NtReplyWaitReceivePort( Os2SessionPort,
+ NULL,
+ (PPORT_MESSAGE)ReplyMsg,
+ (PPORT_MESSAGE)pReceiveMsg
+ );
+ //
+ // Sync with any other server thread before we take care of request
+ //
+ Os2AcquireStructureLock();
+
+ if (Status != 0)
+ {
+#if DBG
+ KdPrint(("OS2SRV: NtReplyWaitReceivePort() returned Status %x\n", Status));
+#endif
+ if (NT_SUCCESS( Status ))
+ {
+ continue; // Try again if alerted or a failure
+ }
+ else
+ {
+ ReplyMsg = NULL;
+ goto WaitAgain;
+ }
+ }
+
+ //
+ // Check for connection request
+ //
+ if ( pReceiveMsg->h.u2.s2.Type == LPC_CONNECTION_REQUEST )
+ {
+ Os2SessionHandleConnectionRequest( (POS2SESREQUESTMSG)pReceiveMsg );
+ ReplyMsg = NULL;
+ goto WaitAgain;
+ }
+
+ //
+ // Check for debugger event
+ //
+ if ( pReceiveMsg->h.u2.s2.Type == LPC_DEBUG_EVENT )
+ {
+#if DBG
+ KdPrint(("OS2SRV: LPC_DEBUG_EVENT received in API thread"));
+ ASSERT(FALSE);
+#endif
+ ReplyMsg = NULL;
+ goto WaitAgain;
+ }
+
+ //
+ // if this is an exception message, assert.
+ //
+ if ( pReceiveMsg->h.u2.s2.Type == LPC_EXCEPTION )
+ {
+#if DBG
+ KdPrint(("OS2SRV: LPC_EXCEPTION received in API thread"));
+ ASSERT(FALSE);
+#endif
+ ReplyMsg = NULL;
+ goto WaitAgain;
+ }
+
+ //
+ // Check for error event
+ //
+ if ( pReceiveMsg->h.u2.s2.Type == LPC_ERROR_EVENT )
+ {
+ PHARDERROR_MSG m;
+
+ m = (PHARDERROR_MSG) pReceiveMsg;
+ Status = m->Status;
+ m->Response = (ULONG) ResponseReturnToCaller;
+#if DBG
+ KdPrint(( "OS2SRV: LPC_ERROR_EVENT in API Thread - Status == %X\n", Status ));
+#endif
+ ASSERT(FALSE);
+
+ ReplyMsg = NULL;
+ goto WaitAgain;
+ }
+
+ //
+ // Check for a terminated process, port closed
+ //
+ if ( pReceiveMsg->h.u2.s2.Type == LPC_PORT_CLOSED)
+ {
+#if DBG
+ IF_OS2_DEBUG( MISC )
+ {
+ KdPrint(( "OS2SRV: LPC_PORT_CLOSED, pReceiveMsg == %X, App will be terminated\n", pReceiveMsg));
+ }
+#endif
+ ReplyMsg = NULL;
+ goto WaitAgain;
+ }
+
+ //
+ // Check for a terminated process, client died
+ //
+ if ( pReceiveMsg->h.u2.s2.Type == LPC_CLIENT_DIED)
+ {
+#if DBG
+ KdPrint(( "OS2SRV: LPC_CLIENT_DIED in API Thread - Status == %X, pReceiveMsg == %X, \n", Status, pReceiveMsg));
+#endif
+ ReplyMsg = NULL;
+ goto WaitAgain;
+ }
+
+ if(pReceiveMsg->PortType == 1)
+ {
+ HandleOs2ConRequest(
+ (PVOID)pReceiveMsg,
+ (PVOID *)&ReplyMsg
+ );
+ continue;
+ }
+
+ ASSERT(pReceiveMsg->PortType == 0);
+
+ if (pReceiveMsg->ApiNumber >= Os2MaxApiNumber)
+ {
+#if DBG
+ KdPrint(( "OS2SRV: %lx is invalid ApiNumber\n",
+ pReceiveMsg->ApiNumber
+ ));
+#endif
+ pReceiveMsg->ApiNumber = Os2MaxApiNumber;
+ }
+
+#if DBG
+ IF_OS2_DEBUG( LPC )
+ {
+ if (pReceiveMsg->ApiNumber != Os2ExitMustComplete &&
+ pReceiveMsg->ApiNumber != Os2EnterMustComplete)
+ {
+ KdPrint(( "OS2SRV: %s Api Request received from %lx.%lx\n",
+ Os2ServerApiName[ pReceiveMsg->ApiNumber ],
+ pReceiveMsg->h.ClientId.UniqueProcess,
+ pReceiveMsg->h.ClientId.UniqueThread
+ ));
+ }
+ }
+#endif // DBG
+
+ ReplyMsg = pReceiveMsg;
+ if (pReceiveMsg->ApiNumber < Os2MaxApiNumber)
+ {
+ Thread = Os2LocateThreadByClientId( NULL /*Process*/, &pReceiveMsg->h.ClientId );
+ if (!Thread)
+ {
+ switch (pReceiveMsg->ApiNumber) {
+ case Os2CreateThread :
+ // Thats right, the thread isn't known yet by the server
+ Process = Os2LocateProcessByClientId(&pReceiveMsg->h.ClientId);
+ break;
+ case Os2CloseHandle :
+ // This API may be called from the thread startup. It might
+ // be done while exit in progress too. In any case, close
+ // the handles.
+ Os2DosCloseHandle(NULL, pReceiveMsg);
+ ReplyMsg->ReturnedErrorValue = NO_ERROR;
+ goto failit;
+ case Os2Exit :
+ case Os2ExitGP :
+ case Oi2TerminateProcess :
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ DbgPrint("OS2SRV: Api Request (exit) - illegal client\n");
+ }
+#endif // DBG
+ ReplyMsg = NULL;
+ goto failit;
+ default:
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ DbgPrint("OS2SRV: Api Request - illegal client\n");
+ }
+#endif // DBG
+ ReplyMsg->ReturnedErrorValue = ERROR_INVALID_FUNCTION;
+ goto failit;
+ }
+ }
+ else
+ Process = Thread->Process;
+
+ ReplyMsg->ReturnedErrorValue = NO_ERROR;
+
+ if (Process->ExitStatus & OS2_EXIT_IN_PROGRESS)
+ {
+ //
+ // We started termination. Don't let new threads come in
+ //
+ if (pReceiveMsg->ApiNumber == Os2CreateThread) {
+ // Thread strcuture will not be allocated by the server, but
+ // the handle that was duplicated by the client must be closed.
+ NtClose(pReceiveMsg->u.DosCreateThread.ThreadHandle);
+ ReplyMsg->ReturnedErrorValue = ERROR_INVALID_FUNCTION;
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ KdPrint(( "OS2SRV: in termination, don't allow new threads in\n"));
+ }
+#endif // DBG
+ goto failit;
+ }
+ }
+
+ if (pReceiveMsg->CaptureBuffer != NULL)
+ {
+ if (!Os2CaptureArguments( Thread, pReceiveMsg ))
+ {
+ goto failit;
+ }
+ }
+
+ if ((*Os2ServerApiDispatch[ pReceiveMsg->ApiNumber ])( Thread, pReceiveMsg ))
+ {
+ //if (!Thread) {
+ //
+ // Attaching a Win32 Thread to OS/2, take ClientPort from Process
+ //
+ // Process = Os2LocateProcessByClientId(&(pReceiveMsg->h.ClientId));
+ //}
+ } else
+ {
+ ReplyMsg = NULL;
+ if ((pReceiveMsg->ApiNumber == Os2ExecPgm) ||
+ (pReceiveMsg->ApiNumber == Os2StartSession))
+ goto failit;
+ }
+
+ if (pReceiveMsg->CaptureBuffer != NULL)
+ {
+ Os2ReleaseCapturedArguments( pReceiveMsg );
+ }
+failit:
+ ;
+ } else
+ {
+ ReplyMsg->ReturnedErrorValue = ERROR_INVALID_FUNCTION;
+ }
+#if DBG
+ IF_OS2_DEBUG( LPC )
+ {
+ if (ReplyMsg != NULL)
+ {
+ if (pReceiveMsg->ApiNumber != Os2ExitMustComplete &&
+ pReceiveMsg->ApiNumber != Os2EnterMustComplete)
+ {
+ KdPrint(( "OS2SRV: %s Api sending %lX error code reply to %lx.%lx\n",
+ Os2ServerApiName[ pReceiveMsg->ApiNumber ],
+ ReplyMsg->ReturnedErrorValue,
+ ReplyMsg->h.ClientId.UniqueProcess,
+ ReplyMsg->h.ClientId.UniqueThread
+ ));
+ }
+ }
+ }
+#endif // DBG
+ }
+
+ NtTerminateThread( NtCurrentThread(), Status );
+ return( Status );
+}
+
+
+BOOLEAN
+Os2CaptureArguments(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_CAPTURE_HEADER ClientCaptureBuffer;
+ POS2_CAPTURE_HEADER ServerCaptureBuffer;
+ PULONG PointerOffsets;
+ ULONG PointerDelta, Length, CountPointers, Pointer;
+
+ ClientCaptureBuffer = m->CaptureBuffer;
+ Length = ClientCaptureBuffer->Length;
+ if ((PCH)ClientCaptureBuffer < t->Process->ClientViewBase ||
+ ((PCH)ClientCaptureBuffer + Length) >= t->Process->ClientViewBounds
+ ) {
+#if DBG
+ KdPrint(( "*** OS2SRV: CaptureBuffer %lx (len %lx) outside of ClientView %lx-%lx\n",
+ ClientCaptureBuffer, Length,
+ t->Process->ClientViewBase, t->Process->ClientViewBounds
+ ));
+ DbgBreakPoint();
+#endif
+ m->ReturnedErrorValue = ERROR_INVALID_PARAMETER;
+ return( FALSE );
+ }
+
+ ServerCaptureBuffer = RtlAllocateHeap( Os2Heap, 0, Length );
+ if (ServerCaptureBuffer == NULL) {
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ return( FALSE );
+ }
+
+ RtlMoveMemory( ServerCaptureBuffer, ClientCaptureBuffer, Length );
+ PointerDelta = (ULONG)ServerCaptureBuffer - (ULONG)ClientCaptureBuffer;
+
+ PointerOffsets = ServerCaptureBuffer->MessagePointerOffsets;
+ CountPointers = ServerCaptureBuffer->CountMessagePointers;
+ while (CountPointers--) {
+ Pointer = *PointerOffsets++;
+ if (Pointer != 0) {
+ Pointer += (ULONG)m;
+ if ((PCH)*(PULONG)Pointer >= t->Process->ClientViewBase &&
+ (PCH)*(PULONG)Pointer < t->Process->ClientViewBounds
+ ) {
+ *(PULONG)Pointer += PointerDelta;
+ }
+ else {
+#if DBG
+ KdPrint(( "*** OS2SRV: CaptureBuffer MessagePointer %d of '%s' outside of ClientView\n",
+ ServerCaptureBuffer->CountMessagePointers - CountPointers,
+ Os2ServerApiName[ m->ApiNumber ] ));
+ DbgBreakPoint();
+#endif
+ m->ReturnedErrorValue = ERROR_INVALID_PARAMETER;
+ }
+ }
+ }
+ PointerOffsets = ServerCaptureBuffer->CapturePointerOffsets;
+ CountPointers = ServerCaptureBuffer->CountCapturePointers;
+ while (CountPointers--) {
+ Pointer = *PointerOffsets++;
+ if (Pointer != 0) {
+ Pointer += (ULONG)ServerCaptureBuffer;
+ if ((PCH)*(PULONG)Pointer >= t->Process->ClientViewBase &&
+ (PCH)*(PULONG)Pointer < t->Process->ClientViewBounds
+ ) {
+ *(PULONG)Pointer += PointerDelta;
+ }
+ else {
+#if DBG
+ KdPrint(( "*** OS2SRV: CaptureBuffer CapturePointer outside of ClientView\n" ));
+ DbgBreakPoint();
+#endif
+ m->ReturnedErrorValue = ERROR_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if (m->ReturnedErrorValue != NO_ERROR) {
+ RtlFreeHeap( Os2Heap, 0, ServerCaptureBuffer );
+ return( FALSE );
+ }
+ else {
+ ServerCaptureBuffer->RelatedCaptureBuffer = ClientCaptureBuffer;
+ m->CaptureBuffer = ServerCaptureBuffer;
+ return( TRUE );
+ }
+}
+
+VOID
+Os2ReleaseCapturedArguments(
+ IN POS2_API_MSG m
+ )
+{
+ POS2_CAPTURE_HEADER ClientCaptureBuffer;
+ POS2_CAPTURE_HEADER ServerCaptureBuffer;
+ PULONG PointerOffsets;
+ ULONG PointerDelta, CountPointers, Pointer;
+
+ ServerCaptureBuffer = m->CaptureBuffer;
+ ClientCaptureBuffer = ServerCaptureBuffer->RelatedCaptureBuffer;
+ if (ServerCaptureBuffer == NULL) {
+ return;
+ }
+ ServerCaptureBuffer->RelatedCaptureBuffer = NULL;
+
+ PointerDelta = (ULONG)ClientCaptureBuffer - (ULONG)ServerCaptureBuffer;
+
+ PointerOffsets = ServerCaptureBuffer->MessagePointerOffsets;
+ CountPointers = ServerCaptureBuffer->CountMessagePointers;
+ while (CountPointers--) {
+ Pointer = *PointerOffsets++;
+ if (Pointer != 0) {
+ Pointer += (ULONG)m;
+ *(PULONG)Pointer += PointerDelta;
+ }
+ }
+
+ PointerOffsets = ServerCaptureBuffer->CapturePointerOffsets;
+ CountPointers = ServerCaptureBuffer->CountCapturePointers;
+ while (CountPointers--) {
+ Pointer = *PointerOffsets++;
+ if (Pointer != 0) {
+ Pointer += (ULONG)ServerCaptureBuffer;
+ *(PULONG)Pointer += PointerDelta;
+ }
+ }
+
+ RtlMoveMemory( ClientCaptureBuffer,
+ ServerCaptureBuffer,
+ ServerCaptureBuffer->Length
+ );
+
+ RtlFreeHeap( Os2Heap, 0, ServerCaptureBuffer );
+
+ return;
+}
+
+
+
+BOOLEAN
+Os2InternalNullApiCall(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_NULLAPICALL_MSG a = &m->u.NullApiCall;
+ ULONG i, j;
+ LONG CountArguments;
+ PCHAR *Arguments;
+
+ UNREFERENCED_PARAMETER(t);
+ CountArguments = a->CountArguments;
+ if (CountArguments > 0) {
+ Arguments = a->Arguments;
+ j = 0;
+ for (i=0; i<(ULONG)CountArguments; i++) {
+ if (Arguments[ i ] != NULL && *Arguments[ i ] != '\0') {
+ j++;
+ }
+ }
+ }
+ else {
+ j = 0;
+ CountArguments = -CountArguments;
+ Arguments = (PCHAR *)(&a->FastArguments[ 0 ]);
+ for (i=0; i<(ULONG)CountArguments; i++) {
+ if (Arguments[ i ]) {
+ j++;
+ }
+ }
+ }
+
+ return( TRUE );
+}
+
+NTSTATUS
+Os2DebugRequestThread(
+ IN PVOID Parameter
+ )
+{
+ NTSTATUS Status;
+ POS2_PROCESS Process;
+ OS2_API_MSG ReceiveMsg;
+ POS2_API_MSG ReplyMsg;
+
+ UNREFERENCED_PARAMETER(Parameter);
+ ReplyMsg = NULL;
+
+ //
+ // At init time - we sync with other server threads
+ //
+ Os2AcquireStructureLock();
+
+ //
+ // Let other server threads get in after we are in sync
+ //
+ Os2ReleaseStructureLock();
+
+ while (TRUE) {
+
+ Status = NtReplyWaitReceivePort( Os2DebugPort,
+ (PVOID *)&Process,
+ (PPORT_MESSAGE)ReplyMsg,
+ (PPORT_MESSAGE)&ReceiveMsg
+ );
+ if (Status != 0) {
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(( "OS2SRV: DebugPort failed - Status == %X\n", Status ));
+ DbgBreakPoint();
+#endif
+// NtTerminateThread( NtCurrentThread(), Status );
+ }
+ ReplyMsg = NULL;
+ continue; // Try again if alerted or a failure
+ }
+
+ //
+ // Check for debugger event
+ //
+ if ( ReceiveMsg.h.u2.s2.Type != LPC_DEBUG_EVENT ) {
+#if DBG
+ KdPrint(("OS2SRV: LPC_DEBUG_EVENT not received"));
+ ASSERT(FALSE);
+#endif
+ }
+ else {
+ if ( (((PDBGKM_APIMSG)&ReceiveMsg)->ApiNumber == DbgKmExceptionApi) ) {
+ //
+ // sync with other server threads before we muck with global
+ // structures
+ //
+ Os2AcquireStructureLock();
+ Os2HandleDebugEvent(Process,(PDBGKM_APIMSG)&ReceiveMsg);
+ //
+ // Let other server threads get in after we are done with the request
+ //
+ Os2ReleaseStructureLock();
+ }
+ else {
+ //
+ // Don't lock for other kernel notifications, which do not require
+ // mucking with server structures
+ // (thread creation/termination etc.)
+ //
+ Os2HandleDebugEvent(Process,(PDBGKM_APIMSG)&ReceiveMsg);
+ }
+ }
+
+ ReplyMsg = NULL;
+ continue;
+
+ }
+
+ NtTerminateThread( NtCurrentThread(), Status );
+ return( Status );
+}
diff --git a/private/os2/server/concreat.c b/private/os2/server/concreat.c
new file mode 100644
index 000000000..8c1ee23df
--- /dev/null
+++ b/private/os2/server/concreat.c
@@ -0,0 +1,343 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ concreat.c
+
+Abstract:
+
+ This module handles the request to create a session form OS2SES.
+
+Author:
+
+ Avi Nathan (avin) 17-Jul-1991
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_ERRORS
+#include "os2srv.h"
+
+#define NTOS2_ONLY
+#include "sesport.h"
+
+extern ULONG Os2GlobalInfoSeg;
+extern HANDLE Os2GlobalInfoSegHandle;
+
+extern HANDLE FirstOs2ProcessHandle;
+extern CLIENT_ID FirstOs2ProcessClientId;
+
+NTSTATUS
+Os2CreateConSession(
+ IN OUT PVOID RequestMsg
+ )
+{
+ PSCREQ_CREATE Create = & ((POS2SESREQUESTMSG)RequestMsg)->d.Create;
+ OS2_DOSEXECPGM_MSG ExecInfo;
+ OS2_DOSSTARTSESSION_INFO SessionInfo;
+ POS2_THREAD NewThread = NULL;
+ POS2_PROCESS Process;
+ POS2_SESSION Session, SessionForCreate;
+ APIRET Rc = 0;
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOLEAN NewSession = FALSE;
+ ULONG RegionSize = 0, Length;
+
+ RtlZeroMemory(&ExecInfo, sizeof( ExecInfo ) );
+ RtlZeroMemory(&SessionInfo, sizeof( SessionInfo ) );
+
+ try
+ {
+ Session = (POS2_SESSION)((POS2SESREQUESTMSG)RequestMsg)->Session;
+
+ /*
+ * Set ExecPgm information
+ */
+
+ ExecInfo.Flags = EXEC_ASYNC;
+
+ Length = 1 + strlen(Create->d.In.ApplName);
+ RtlMoveMemory(
+ &ExecInfo.ApplName[0],
+ &Create->d.In.ApplName[0],
+ Length
+ );
+ ExecInfo.ApplNameLength = Length;
+
+ RtlInitAnsiString( &ExecInfo.ErrorText, "Default error text");
+
+ /*
+ * Set StartSession information
+ */
+ /* USHORT */ // SessionInfo.FgBg;
+ /* USHORT */ // SessionInfo.InheritOpt;
+ /* USHORT */ // SessionInfo.PgmControl;
+
+ NewThread = Os2LocateThreadByClientId( NULL, &((POS2SESREQUESTMSG)RequestMsg)->h.ClientId );
+ if (NewThread == NULL)
+ {
+ if( ((POS2SESREQUESTMSG)RequestMsg)->Request != SesCheckPortAndConCreate)
+ {
+
+ //
+ // Not a root process of a session, still NewThread is NULL - return
+ // failure
+ //
+#if DBG
+ KdPrint(("Os2CreateConSession: Process already killed by signal\n"));
+#endif
+ return( STATUS_UNSUCCESSFUL );
+ }
+
+ /*
+ * create a process for the new session. OS2SS is the parent
+ * of this process.
+ */
+
+ ASSERT(Create->d.In.IsNewSession == OS2SS_NEW_SESSION);
+ SessionForCreate = Session;
+ NewSession = TRUE;
+
+ } else if (OS2SS_IS_PROCESS( Create->d.In.IsNewSession ))
+ {
+ /*
+ * a child process
+ */
+
+ SessionForCreate = NULL;
+ } else
+ {
+ ASSERT(Create->d.In.IsNewSession == OS2SS_CHILD_SESSION);
+
+ /*
+ * a child session
+ */
+
+ SessionForCreate = Session;
+ }
+
+ Rc = Os2CreateProcess(
+ RequestMsg,
+ NULL, // ParentThread or (POS2_THREAD)Session->Thread,
+ &ExecInfo,
+ SessionForCreate,
+ &NewThread
+ );
+
+ if (FirstOs2ProcessHandle == 0 && Rc == 0) {
+ //
+ // First OS/2 application - remember for logoff/shutdown
+ //
+ FirstOs2ProcessHandle = NewThread->Process->ProcessHandle;
+ FirstOs2ProcessClientId = NewThread->Process->ClientId;
+
+ }
+ } except ( EXCEPTION_EXECUTE_HANDLER ){
+ Rc = (APIRET)STATUS_UNSUCCESSFUL; // BUGBUG!
+ /*
+ * fall thru to close the section.
+ */
+ }
+
+ if ( Rc == NO_ERROR )
+ {
+ Process = NewThread->Process;
+ if (( Process == NULL ) ||
+ ( Create->d.In.ExitListDispatcher == NULL ) ||
+ ( Create->d.In.InfiniteSleep == NULL) ||
+ ( Create->d.In.SignalDeliverer == NULL ) ||
+ ( Create->d.In.FreezeThread == NULL ) ||
+ ( Create->d.In.UnfreezeThread == NULL ) ||
+ ( Create->d.In.ClientPib == NULL ) ||
+ ( Create->d.In.InitialPebOs2Length !=
+ Process->InitialPebOs2Data.Length ))
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ } else
+ {
+ Process->SignalDeliverer = Create->d.In.SignalDeliverer;
+ Process->ExitListDispatcher = Create->d.In.ExitListDispatcher;
+ Process->InfiniteSleep = Create->d.In.InfiniteSleep;
+ Process->FreezeThread = Create->d.In.FreezeThread;
+ Process->UnfreezeThread = Create->d.In.UnfreezeThread;
+ Process->VectorHandler = Create->d.In.VectorHandler;
+ Process->CritSectionAddr = Create->d.In.CritSectionAddr;
+
+ Process->ClientPib = Create->d.In.ClientPib;
+ NewThread->ClientOs2Tib = Create->d.In.ClientOs2Tib;
+
+ Create->d.Out.PibProcessId = (HANDLE)Process->ProcessId;
+ Create->d.Out.PibParentProcessId = (HANDLE)Process->Parent->ProcessId;
+ Create->d.Out.PibImageFileHandle = (HANDLE)-1;
+ Create->d.Out.PibStatus = 0;
+ if (Process->Flags & OS2_PROCESS_BACKGROUND)
+ {
+ Create->d.Out.PibType = PT_DETACHED;
+ }
+ else
+ Create->d.Out.PibType = PT_PM;
+
+
+ Create->d.Out.Os2TibThreadId = (ULONG)NewThread->ThreadId;
+ Create->d.Out.Os2TibVersion = OS2_VERSION;
+
+ Os2SetThreadPriority( NewThread, NewThread->Os2Class, NewThread->Os2Level );
+
+ *((PPEB_OS2_DATA)&Create->d.Out.InitialPebOs2Data[0]) = Process->InitialPebOs2Data;
+ Create->d.Out.BootDrive = Os2BootDrive;
+ Create->d.Out.SystemDrive = Os2DefaultDrive;
+ Create->d.Out.SessionNumber = Process->Session->SessionId;
+ Create->d.Out.GInfoAddr = (PVOID)Os2GlobalInfoSeg;
+
+ while (NT_SUCCESS(Status))
+ {
+ Status = NtDuplicateObject( NtCurrentProcess(),
+ Os2DevicesDirectory,
+ Process->ProcessHandle,
+ &Create->d.Out.DeviceDirectory,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS |
+ DUPLICATE_SAME_ATTRIBUTES
+ );
+ if (!NT_SUCCESS(Status) )
+ {
+#if DBG
+ KdPrint(("Os2CreateConSession: NtDuplicateObject-1 Failed %lx\n",Status));
+#endif
+ break;
+ }
+
+ Status = NtDuplicateObject( NtCurrentProcess(),
+ Process->Session->ConsolePort,
+ Process->ProcessHandle,
+ &Create->d.Out.CtrlPortHandle,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS |
+ DUPLICATE_SAME_ATTRIBUTES
+ );
+ if (!NT_SUCCESS(Status) )
+ {
+#if DBG
+ KdPrint(("Os2CreateConSession: NtDuplicateObject-2 Failed %lx\n",Status));
+#endif
+ break;
+ }
+
+ //
+ // Map view the global info seg into the new client
+ //
+
+ Status = NtMapViewOfSection( Os2GlobalInfoSegHandle,
+ Process->ProcessHandle,
+ (PVOID) &Os2GlobalInfoSeg,
+ 0,
+ 0,
+ NULL,
+ &RegionSize,
+ ViewUnmap,
+ 0,
+ PAGE_READONLY
+ );
+ if (!NT_SUCCESS(Status) )
+ {
+#if DBG
+ KdPrint(("Os2CreateConSession: NtMapViewOfSection Failed %lx\n",Status));
+#endif
+ }
+ break;
+ }
+ }
+
+ if (!NT_SUCCESS(Status) )
+ {
+ ASSERT( FALSE );
+
+ // fall into Os2DereferenceSession
+
+ } else if (SessionForCreate)
+ {
+ /*
+ * now that the session is allocated set the console port
+ * and reply the session handle to OS2SES
+ */
+
+ OS2SESREQUESTMSG FocusMsg;
+ ASSERT(NewThread->Process->Session == Session);
+
+ //
+ // Set the new session to be foreground
+ //
+ FocusMsg.d.FocusSet = TRUE;
+ FocusMsg.Session = Session;
+ Os2SessionFocusSet(&FocusMsg);
+
+ return(Status);
+ } else
+ {
+ //
+ // os2.exe that was created by DosExecPgm
+ //
+ return(Status);
+ }
+ }
+
+ Os2DereferenceSession(Session, NULL, (BOOLEAN)TRUE);
+ return( STATUS_UNSUCCESSFUL ); // BUGBUG!
+}
+
+
+NTSTATUS
+Os2TerminateConSession (
+ IN POS2_SESSION Session,
+ IN POS2_TERMINATEPROCESS_MSG a
+ )
+{
+ HANDLE SessionPort;
+ NTSTATUS Status;
+ SCREQUESTMSG Request;
+ OS2SESREQUESTMSG FocusMsg;
+
+
+ Request.Request = TaskManRequest;
+ Request.d.Tm.Request = TmExit;
+ Request.d.Tm.ExitResults = a->ExitResult;
+ strcpy(&Request.d.Tm.ErrorText[0], &a->ErrorText[0]);
+
+ PORT_MSG_TOTAL_LENGTH(Request) = sizeof(SCREQUESTMSG);
+ PORT_MSG_DATA_LENGTH(Request) = sizeof(SCREQUESTMSG) - sizeof(PORT_MESSAGE);
+ PORT_MSG_ZERO_INIT(Request) = 0L;
+
+ SessionPort = Session->ConsolePort;
+
+ Status = NtRequestPort(
+ SessionPort,
+ (PPORT_MESSAGE) &Request
+ );
+
+ if ( !NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(( "OS2SS: Unable to send terminate request - Status == %X\n",
+ Status
+ ));
+#endif
+
+ return( Status );
+ }
+
+ //
+ // Reset foreground session (nop if the terminating session is not in foreground)
+ //
+ FocusMsg.d.FocusSet = FALSE;
+ FocusMsg.Session = Session;
+ Os2SessionFocusSet(&FocusMsg);
+
+ return( STATUS_SUCCESS );
+
+}
+
diff --git a/private/os2/server/coninit.c b/private/os2/server/coninit.c
new file mode 100644
index 000000000..0970b5613
--- /dev/null
+++ b/private/os2/server/coninit.c
@@ -0,0 +1,166 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ coninit.c
+
+Abstract:
+
+ This module contains the code to initialize the Console Port of the OS/2
+ Emulation Subsystem.
+
+Author:
+
+ Avi Nathan (avin) 17-Jul-1991
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include "os2srv.h"
+#define NTOS2_ONLY
+#include "sesport.h"
+#include "os2win.h"
+
+BYTE Os2InitializeConsolePortFailStr[] = "Os2InitializeConsolePort - fail at %s, %x\n";
+
+NTSTATUS
+Os2InitializeConsolePort( VOID )
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING Os2SessionPortName_U;
+ HANDLE Os2SessionDirectory;
+ CHAR localSecurityDescriptor[SECURITY_DESCRIPTOR_MIN_LENGTH];
+ PSECURITY_DESCRIPTOR securityDescriptor;
+ ULONG MessageLength;
+ ULONG Tid;
+
+ /*
+ * Create a directory in the object name space for the session port
+ * names
+ */
+
+ RtlInitUnicodeString( &Os2SessionPortName_U, U_OS2_SES_BASE_PORT_NAME );
+
+ Status = RtlCreateSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION );
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ DbgPrint(Os2InitializeConsolePortFailStr, "RtlCreateSecurityDescriptor" ,Status);
+#endif
+ ASSERT( FALSE );
+ return( Status );
+ }
+
+ Status = RtlSetDaclSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ TRUE,
+ (PACL) NULL,
+ FALSE );
+
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ DbgPrint(Os2InitializeConsolePortFailStr, "RtlSetDaclSecurityDescriptor", Status);
+#endif
+ ASSERT( FALSE );
+ return( Status );
+ }
+
+
+ securityDescriptor = (PSECURITY_DESCRIPTOR) &localSecurityDescriptor;
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &Os2SessionPortName_U,
+ // OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ securityDescriptor
+ );
+
+ Status = NtCreateDirectoryObject( &Os2SessionDirectory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes
+ );
+
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ DbgPrint(Os2InitializeConsolePortFailStr, "NtCreateDirectoryObject", Status);
+#endif
+ ASSERT( FALSE );
+ return( Status );
+ }
+
+ RtlInitUnicodeString( &Os2SessionPortName_U, U_OS2_SS_SESSION_PORT_NAME );
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &Os2SessionPortName_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ securityDescriptor
+ );
+
+ MessageLength = (sizeof( OS2SESREQUESTMSG ) > sizeof( OS2_API_MSG )) ?
+ sizeof( OS2SESREQUESTMSG ) : sizeof( OS2_API_MSG );
+
+#if DBG
+ IF_OS2_DEBUG( LPC )
+ {
+ DbgPrint( "OS2SRV: Creating %wZ port and associated threads\n",
+ &Os2SessionPortName_U );
+ DbgPrint( "OS2SRV: sizeof( CONNECTINFO ) == %ld sizeof( REQ_MSG ) == %ld (Con %ld, Api %ld)\n",
+ sizeof( OS2SESCONNECTINFO ), MessageLength,
+ sizeof( OS2SESREQUESTMSG ), sizeof( OS2_API_MSG )
+ );
+ }
+#endif
+
+ Status = NtCreatePort( &Os2SessionPort,
+ &ObjectAttributes,
+ sizeof( OS2SESCONNECTINFO ),
+ MessageLength,
+ sizeof( OS2SESREQUESTMSG ) * 32
+ );
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ DbgPrint(Os2InitializeConsolePortFailStr, "NtCreatePort", Status);
+#endif
+ ASSERT( FALSE );
+ return( Status );
+ }
+
+ Os2SessionRequestThreadHandle = CreateThread(
+ NULL,
+ 0,
+ (PFNTHREAD)Os2ApiRequestThread,
+ NULL,
+ 0,
+ &Tid
+ );
+ if (!Os2SessionRequestThreadHandle)
+ {
+#if DBG
+ DbgPrint(Os2InitializeConsolePortFailStr, "CreateThread (Win32)", GetLastError());
+#endif
+ ASSERT( FALSE );
+ return( STATUS_NO_MEMORY );
+ }
+
+ // BUGBUG! this guy is going to spin for quite a while until
+ // it does something
+
+ return( STATUS_SUCCESS );
+}
diff --git a/private/os2/server/consignl.c b/private/os2/server/consignl.c
new file mode 100644
index 000000000..cb76e4f35
--- /dev/null
+++ b/private/os2/server/consignl.c
@@ -0,0 +1,348 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ consignl.c
+
+Abstract:
+
+ This module contains the handler for signals received from OS2SES.
+
+Author:
+
+ Avi Nathan (avin) 17-Jul-1991
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_EXCEPTIONS
+#include "os2srv.h"
+#include "os2win.h"
+
+#define NTOS2_ONLY
+
+#define XCPT_REPLACE_CMD 12
+
+#include "sesport.h"
+
+VOID
+Os2PrepareCmdSignals(POS2_PROCESS Process)
+{
+
+/*++
+
+ This routine installs a dummy signal handler, to mimique the signal
+ behavior of OS/2 CMD.EXE, in cases where we shortcut cmd /c for performance
+
+--*/
+
+ POS2_SESSION Session;
+ POS2_REGISTER_HANDLER_REC pRec;
+ POS2_REGISTER_HANDLER_REC pPRec;
+
+ Session = Process->Session;
+
+ pPRec = (POS2_REGISTER_HANDLER_REC)
+ RtlAllocateHeap(Os2Heap, 0,
+ sizeof(OS2_REGISTER_HANDLER_REC));
+ if ((PVOID)pPRec == NULL) {
+#if DBG
+ DbgPrint("Os2PrepareCmdSingals, no memory for heap, return with no action\n");
+#endif
+ return;
+ }
+ pPRec->Signal = XCPT_REPLACE_CMD;
+ pPRec->fAction = XCPT_REPLACE_CMD;
+ pPRec->Process = Process;
+
+
+ if (Session->RegisterCtrlHandler == NULL) {
+ Session->RegisterCtrlHandler = pPRec;
+ pPRec->Link = NULL;
+ }
+ else {
+ pRec = Session->RegisterCtrlHandler;
+ Session->RegisterCtrlHandler = pPRec;
+ pPRec->Link = pRec;
+ }
+}
+
+VOID
+Os2SigKillProcess(
+ POS2_PROCESS Process)
+{
+ POS2_THREAD Thread = NULL;
+ PLIST_ENTRY ListHead, ListNext;
+ OS2_API_MSG m;
+ POS2_TERMINATEPROCESS_MSG a = &m.u.TerminateProcess;
+
+ PORT_MSG_DATA_LENGTH(m) = sizeof(m) - sizeof(PORT_MESSAGE);
+ PORT_MSG_TOTAL_LENGTH(m) = sizeof(m);
+ PORT_MSG_ZERO_INIT(m) = 0L;
+
+ //
+ // Kill the process by issuing an Os2DosExit on it's behalf, then
+ // resume it to terminate gracefully
+ //
+#if DBG
+ IF_OS2_DEBUG(SIG) {
+ DbgPrint("Os2SigKillProcess, Process %x\n", Process);
+ }
+#endif
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ Thread = NULL;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD(ListNext, OS2_THREAD, Link);
+ if (Thread->Flags & OS2_THREAD_THREAD1) {
+ break;
+ }
+ else {
+ ListNext = ListNext->Flink;
+ }
+ }
+
+ if (Thread != NULL) {
+ a->ExitReason = TC_EXIT;
+ a->ExitResult = ERROR_INTERRUPT;
+ ((POS2_DOSEXIT_MSG)a)->ExitAction = EXIT_PROCESS;
+
+ if (Process->CtrlHandlerFlag) {
+
+ if (Process->ResultCodes.ExitReason != TC_TRAP) {
+ ULONG killed = TRUE;
+ NTSTATUS Status;
+ Status = NtWriteVirtualMemory( Process->ProcessHandle,
+ &Process->ClientPib->Killed,
+ &killed,
+ sizeof( Process->ClientPib->Killed ),
+ NULL
+ );
+#if DBG
+ if (!(NT_SUCCESS(Status))) {
+ KdPrint(( "Os2SigKillProcess, failed to write to client, Status %lx\n", Status));
+ }
+#endif // DBG
+ }
+
+ //
+ // set flag to create a separate thread for Os2DosExit
+ //
+ m.ApiNumber = Os2MaxApiNumber;
+ Os2DosExit (Thread, &m);
+#if DBG
+ IF_OS2_DEBUG(SIG) {
+ DbgPrint("now resuming thread1\n");
+ }
+#endif
+// NtResumeThread(Thread->ThreadHandle, NULL);
+
+// There is no need to alert thread here. It will be executed later
+// by Os2TerminationThread.
+//
+//#if DBG
+// DbgPrint("[%d,%d]: Os2SigKillProcess NtAlertThread(%x)\n",
+// Thread->Process->ProcessId,
+// Thread->ThreadId,
+// Thread->ThreadHandle);
+//#endif
+// NtAlertThread(Thread->ThreadHandle);
+ }
+ else {
+#if DBG
+ IF_OS2_DEBUG(SIG) {
+ DbgPrint("OS2SRV: Handling a signal before loading completed\n");
+ }
+#endif
+ Process->ExitStatus |= OS2_EXIT_IN_PROGRESS;
+ Os2InternalTerminateProcess(Thread, &m);
+ }
+ }
+}
+
+VOID
+Os2SigKillProcessTree(
+ IN POS2_PROCESS RootProcess,
+ IN BOOLEAN IncludeRoot
+ )
+
+/*++
+
+Routine Description:
+
+ This routine recursively kills each subtree inside it
+
+Arguments:
+
+ RootProcess - root process of tree to issue Signal to
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ PLIST_ENTRY ListHead, ListNext;
+
+ if (IncludeRoot){
+#if DBG
+ IF_OS2_DEBUG(SIG) {
+ DbgPrint("SigKillProcessTree, killing parent\n");
+ }
+#endif
+ Os2SigKillProcess(RootProcess);
+ }
+
+ ListHead = &RootProcess->ChildrenList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+#if DBG
+ IF_OS2_DEBUG(SIG) {
+ DbgPrint("SigKillProcessTree, getting into recursion\n");
+ }
+#endif
+ Os2SigKillProcessTree( CONTAINING_RECORD( ListNext,OS2_PROCESS,SiblingLink),
+ TRUE
+ );
+ ListNext = ListNext->Flink;
+ }
+}
+
+NTSTATUS
+Os2CtrlSignalHandler(
+ IN OUT PVOID RequestMsg,
+ IN POS2_PROCESS RecievingProcess
+ )
+{
+ POS2_PROCESS Process, Parent = NULL;
+ POS2_THREAD Thread = NULL;
+ PLIST_ENTRY ListHead, ListNext;
+ int Signal = ((POS2SESREQUESTMSG)RequestMsg)->d.Signal.Type;
+ POS2_SESSION Session = (POS2_SESSION)(((POS2SESREQUESTMSG)RequestMsg)->Session);
+ POS2_REGISTER_HANDLER_REC pRec;
+
+
+#if DBG
+ IF_OS2_DEBUG(SIG) {
+ DbgPrint("Os2CtrlSignalHandler: Signal %x for Session %p\n", Signal, Session);
+ }
+#endif
+
+ if (Session == NULL) {
+#if DBG
+ DbgPrint("Os2CtrlSignalHandler: NULL Session Passed\n");
+#endif
+ return STATUS_INVALID_HANDLE;
+ }
+
+ if ((Signal != XCPT_SIGNAL_INTR ) &&
+ (Signal != XCPT_SIGNAL_KILLPROC ) &&
+ (Signal != XCPT_SIGNAL_BREAK )){
+#if DBG
+ DbgPrint("Os2CtrlSignalHandler: Unknown Signal %x\n", Signal);
+#endif
+ return (0L);
+ }
+
+ if (Session->InTermination)
+ {
+#if DBG
+ IF_OS2_DEBUG(SIG) {
+ DbgPrint("Os2CtrlSignalHandler: session in termination already\n");
+ }
+#endif
+ return (0L);
+ }
+
+ //
+ // If a process in this session has registered a handler for Ctrl-c,
+ // Kill process or Ctrl-break dispatch only to this one otherwise
+ // send a signal to each process
+ //
+ if ((pRec = Session->RegisterCtrlHandler) != NULL) {
+ while (pRec != NULL) {
+ if (pRec->Signal == (ULONG) Signal) {
+ //
+ // Since we receive a debug message for each process
+ // in the session, no need to forward except for
+ // the process who actually handles the Signal
+ //
+ if ((pRec->Process == RecievingProcess) || (RecievingProcess == NULL)) {
+ if (pRec->fAction != SIGA_IGNORE){
+ Os2IssueSignal(pRec->Process, Signal);
+ }
+ }
+ return(0L);
+ }
+ else if (pRec->Signal == XCPT_REPLACE_CMD) {
+ //
+ // We replaced (performance) exec of cmd /c with direct
+ // exec of it's children, and none of them registered
+ // A handler for this signal - kill the subtree
+ //
+ Os2SigKillProcessTree(pRec->Process, TRUE);
+ return(0L);
+ }
+ pRec = pRec->Link;
+ }
+ }
+
+ //
+ // We need to send a signal to each process in this session. First
+ // suspend each process in this session.
+ //
+
+ for (
+ ListHead = &Os2RootProcess->ListLink,
+ ListNext = ListHead->Flink;
+ ListNext != ListHead ;
+ ListNext = ListNext->Flink
+ ) {
+ Process = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
+ if ( Process->Session == Session ) {
+ Os2SuspendProcess(Process);
+ }
+
+ }
+
+ //
+ // After each process has been suspended kill each one
+ //
+ ListHead = &Os2RootProcess->ListLink;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+
+ Process = CONTAINING_RECORD(ListNext, OS2_PROCESS, ListLink);
+ ListNext = ListNext->Flink;
+
+ if ( Process->Session == Session ) {
+ Os2SigKillProcess(Process);
+ }
+ }
+
+ //
+ // This Session should not respond to any more signals until it terminates
+ //
+ try {
+ Session->InTermination = TRUE;
+ if (Session->ReferenceCount != -1L)
+ {
+ ((POS2_SES_GROUP_PARMS)Session->SesGrpAddress)->InTermination |= 1;
+ }
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+#if DBG
+ IF_OS2_DEBUG(SIG) {
+ DbgPrint("OS2SRV: Os2CtrlSignalHandler Got an Exception, recovery ok\n");
+ }
+#endif
+ ;
+ }
+ return(0L);
+}
+
diff --git a/private/os2/server/conthrds.c b/private/os2/server/conthrds.c
new file mode 100644
index 000000000..a59e78ebe
--- /dev/null
+++ b/private/os2/server/conthrds.c
@@ -0,0 +1,400 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ conthrds.c
+
+Abstract:
+
+ This module contains the Server Listen&Request threads
+ procedures for the Console Session.
+
+Author:
+
+ Avi Nathan (avin) 17-Jul-1991
+
+Revision History:
+
+--*/
+
+#include "os2srv.h"
+#define NTOS2_ONLY
+#include "sesport.h"
+#include "os2win.h"
+
+
+extern OS2_SES_GROUP_PARMS ServerSesGrp;
+
+VOID
+Os2SessionHandleConnectionRequest(
+ POS2SESREQUESTMSG Message
+ )
+{
+ NTSTATUS Status;
+ HANDLE Os2SessionCommPortHandle;
+ APIRET Rc;
+ POS2_THREAD Thread;
+ POS2_SESSION Session;
+ POS2_PROCESS Process;
+ BOOLEAN AcceptConnection;
+ POS2SESCONNECTINFO ConnectionInfoIn = &Message->ConnectionRequest;
+ REMOTE_PORT_VIEW ClientView;
+ HANDLE TmpWin32ForegroundWindow;
+
+ //
+ // sync with other server threads
+ //
+ Os2AcquireStructureLock();
+
+ TmpWin32ForegroundWindow = ConnectionInfoIn->In.Win32ForegroundWindow;
+ if (ConnectionInfoIn->In.ExpectedVersion > OS2_SS_VERSION)
+ {
+ KdPrint(( "OS2SRV: Os2SessionHandleConnectionRequest received old version (%u intead of %u)\n",
+ ConnectionInfoIn->In.ExpectedVersion, OS2_SS_VERSION));
+ AcceptConnection = FALSE;
+ } else
+ {
+ AcceptConnection = TRUE;
+#if DBG
+ if (ConnectionInfoIn->In.SessionDbg)
+ {
+ Os2Debug |= OS2_DEBUG_BRK;
+ KdPrint(( "OS2SRV: Breakpoint caused by OS2 /B\n" ));
+ DbgBreakPoint();
+ } else
+ {
+ Os2Debug &= ~(OS2_DEBUG_BRK);
+ }
+#endif // DBG
+ ConnectionInfoIn->Out.CurrentVersion = OS2_SS_VERSION;
+ }
+
+ if ( !AcceptConnection )
+ {
+ // Reject
+failConnect:
+ Status = NtAcceptConnectPort(
+ &Os2SessionCommPortHandle,
+ NULL,
+ (PPORT_MESSAGE)Message,
+ (BOOLEAN)FALSE,
+ NULL,
+ NULL
+ );
+ } else
+ {
+ //
+ // See if this Unique Id already exist (execed by DosExecPgm)
+ // if not, create a new session and give it as a port handle
+ //
+
+ Thread = Os2LocateThreadByClientId( NULL, &Message->h.ClientId );
+ if (Thread == NULL)
+ {
+ //
+ // new session
+ //
+ Session = Os2AllocateSession(NULL, 0L, &Rc);
+ ConnectionInfoIn->Out.SessionUniqueID = (ULONG)Session;
+ if (Session == NULL)
+ {
+ KdPrint(( "OS2SRV: Os2SessionHandleConnectionRequest fails to allocate session\n"));
+ goto failConnect;
+ }
+ ConnectionInfoIn->Out.IsNewSession = OS2SS_NEW_SESSION;
+ if ((Process = Os2AllocateProcess()) == NULL)
+ {
+ // free the session
+ KdPrint(( "OS2SRV: Os2SessionHandleConnectionRequest fails to allocate process\n"));
+ goto failConnect;
+ }
+ Session->Process = Process;
+ ConnectionInfoIn->Out.ProcessUniqueID = (ULONG)Process;
+ } else
+ {
+ /*
+ * a child session
+ */
+
+ if ((Process = Thread->Process) == NULL)
+ {
+ // free the session
+ KdPrint(( "OS2SRV: Os2SessionHandleConnectionRequest fails to find process for child session\n"));
+ goto failConnect;
+ }
+ Session = Process->Session;
+ if (Session == NULL)
+ {
+ KdPrint(( "OS2SRV: Os2SessionHandleConnectionRequestfails to find child session\n"));
+ goto failConnect;
+ }
+
+ //
+ // This process was execed by os/2, use process handle as uniqueid
+ //
+ ConnectionInfoIn->Out.SessionUniqueID = (ULONG)Session;
+ ConnectionInfoIn->Out.ProcessUniqueID = (ULONG)Process;
+ //
+ // indicate to os2.exe that this is not a new session
+ //
+ if( Session->Process == NULL )
+ {
+ /*
+ * a child session
+ */
+
+ ASSERT(Session->ReferenceCount == 1);
+
+ Session->Process = Process;
+ ConnectionInfoIn->Out.IsNewSession = OS2SS_CHILD_SESSION;
+ } else
+ {
+ /*
+ * a child process
+ */
+
+ //
+ // indicate to os2.exe that this is not a new session
+ //
+ ConnectionInfoIn->Out.IsNewSession = OS2SS_CHILD_PROCESS;
+ }
+ }
+ Session->Win32ForegroundWindow = TmpWin32ForegroundWindow;
+ ConnectionInfoIn->Out.Os2SrvId = GetCurrentProcessId();
+ ConnectionInfoIn->Out.Od2Debug = 0;
+#if DBG
+ ConnectionInfoIn->Out.Od2Debug = Os2Debug;
+#endif
+
+ /*
+ * Os2SessionCommPortHandle is not used for Reply. Instead,
+ * the port is created with ReceiveAny==TRUE and we wait
+ * on the connection port.
+ */
+
+ ClientView.Length = sizeof( ClientView );
+ ClientView.ViewSize = 0;
+ ClientView.ViewBase = 0;
+ Status = NtAcceptConnectPort(
+ & Os2SessionCommPortHandle,
+ (PVOID)Process,
+ (PPORT_MESSAGE)Message,
+ (BOOLEAN)TRUE,
+ NULL,
+ &ClientView
+ );
+#if DBG
+ IF_OS2_DEBUG( LPC )
+ {
+ KdPrint(( "OS2SRV: listen - ClientView: Base=%lx, Size=%lx, PortHandle %lx\n",
+ ClientView.ViewBase, ClientView.ViewSize, Os2SessionCommPortHandle));
+ }
+#endif
+ Process->ClientPort = Os2SessionCommPortHandle;
+ Process->ClientViewBase = (PCH)ClientView.ViewBase;
+ Process->ClientViewBounds = (PCH)ClientView.ViewBase + ClientView.ViewSize;
+
+ if ( !NT_SUCCESS(Status) )
+ {
+ // free the session
+
+ Os2DereferenceSession((POS2_SESSION)ConnectionInfoIn->Out.SessionUniqueID, NULL, (BOOLEAN)TRUE);
+ if ((Thread != NULL) && (Thread->Process->Session->ReferenceCount != 1))
+ {
+ // BUGBUG: free the process
+ }
+ } else
+ {
+ Status = NtCompleteConnectPort( Os2SessionCommPortHandle );
+ ASSERT( NT_SUCCESS( Status) );
+ }
+ }
+ Os2ReleaseStructureLock();
+}
+
+
+NTSTATUS
+CheckOs2Port(POS2SESREQUESTMSG pReceiveMsg)
+{
+ NTSTATUS Status;
+ SCCONNECTINFO ConnectionInfoOut;
+ ULONG ConnectionInfoOutLength, i;
+ UNICODE_STRING SessionPortName_U;
+ SECURITY_QUALITY_OF_SERVICE DynamicQos;
+ WCHAR SessionName_U[U_OS2_SES_BASE_PORT_NAME_LENGTH];
+ POS2_SES_GROUP_PARMS SesGrp;
+ HANDLE SectionHandle;
+ ULONG ViewSize;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ POS2_SESSION Session = (POS2_SESSION)(pReceiveMsg->Session);
+ HANDLE SessionPortHandle;
+
+ //
+ // Connect to the OS2SES port, then call it with
+ // the ommunication to be used during the session
+ // to call os2ses
+ //
+
+ ConnectionInfoOutLength = sizeof( ConnectionInfoOut );
+
+ CONSTRUCT_U_OS2_SES_NAME(SessionName_U, U_OS2_SES_BASE_PORT_PREFIX, (ULONG)(pReceiveMsg->Session));
+ RtlInitUnicodeString( &SessionPortName_U, SessionName_U );
+
+ DynamicQos.ImpersonationLevel = SecurityImpersonation;
+ DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
+ DynamicQos.EffectiveOnly = TRUE;
+
+ //
+ // get the session communication port handle. this handle will be used
+ // to send session requests to os2ses.exe for this session.
+ //
+
+ Status = NtConnectPort( &SessionPortHandle,
+ &SessionPortName_U,
+ &DynamicQos,
+ NULL,
+ NULL,
+ NULL,
+ (PVOID) &ConnectionInfoOut,
+ & ConnectionInfoOutLength
+ );
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(( "OS2SS: Unable to connect to OS2 - Status == %X\n",
+ Status
+ ));
+#endif
+ Os2DereferenceSession(Session, NULL, (BOOLEAN)TRUE);
+ return(Status);
+ }
+
+ //
+ // A new session - save handles to process and thread
+ //
+
+ Session->ConsolePort = SessionPortHandle;
+
+ SessionPortName_U.Buffer[sizeof(U_OS2_SES_BASE_PORT_NAME) / 2] = U_OS2_SES_GROUP_PREFIX;
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &SessionPortName_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenSection ( &SectionHandle,
+ SECTION_MAP_WRITE,
+ &ObjectAttributes);
+
+ if ( !NT_SUCCESS( Status ) )
+ {
+#if DBG
+ KdPrint(( "OS2SRV: Os2CheckPort can't open SesGrp section - Status == %X\n",
+ Status));
+#endif
+ Os2DereferenceSession(Session, NULL, (BOOLEAN)TRUE);
+ return(Status);
+ }
+
+ /*
+ * Let MM locate the view
+ */
+
+ SesGrp = (POS2_SES_GROUP_PARMS)NULL;
+ ViewSize = 0L;
+
+ Status = NtMapViewOfSection( SectionHandle,
+ NtCurrentProcess(),
+ (PVOID *)&SesGrp,
+ 0L,
+ 0L,
+ NULL,
+ &ViewSize,
+ ViewUnmap,
+ 0L,
+ PAGE_READWRITE);
+
+ if ( !NT_SUCCESS( Status ) )
+ {
+#if DBG
+ KdPrint(( "OS2SRV: Os2CheckPort can't map view of SesGrp section - Status == %X\n",
+ Status));
+#endif
+ Os2DereferenceSession(Session, NULL, (BOOLEAN)TRUE);
+ NtClose (SectionHandle);
+ return(Status);
+ }
+
+ /*
+ * copy data to session
+ */
+
+ for ( i = 0 ; i < sizeof(OS2_SES_GROUP_PARMS) ; i++ )
+ {
+ if (((PUCHAR)&ServerSesGrp)[i])
+ {
+ ((PUCHAR)SesGrp)[i] = ((PUCHAR)&ServerSesGrp)[i];
+ }
+ }
+
+ Session->SesGrpAddress = (PVOID)SesGrp;
+ Session->SesGrpHandle = SectionHandle;
+ return(Status);
+}
+
+
+VOID
+HandleOs2ConRequest(IN PVOID pApiReceiveMsg,
+ OUT PVOID *PReplyMsg
+ )
+{
+ POS2SESREQUESTMSG pReceiveMsg = pApiReceiveMsg;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ *PReplyMsg = pApiReceiveMsg;
+
+ switch ( pReceiveMsg->Request)
+ {
+ case SesCheckPortAndConCreate:
+ //
+ // Connect to the OS2SES port, then call it with
+ // the ommunication to be used during the session
+ // to call os2ses
+ //
+ Status = CheckOs2Port(pReceiveMsg);
+ if ( !NT_SUCCESS( Status ) )
+ {
+ break;
+ }
+
+ case SesConCreate:
+ Status = Os2CreateConSession(
+ pReceiveMsg
+ );
+ break;
+
+ case SesConSignal:
+ Status = Os2CtrlSignalHandler(
+ pReceiveMsg,
+ NULL);
+ break;
+
+ case SesConFocus:
+ Status = Os2SessionFocusSet(
+ pReceiveMsg);
+ break;
+
+ default:
+ Status = 0;
+#if DBG
+ KdPrint(( "OS2SS: Unknown Session request = %X\n",
+ pReceiveMsg->Request));
+#endif
+ }
+
+ pReceiveMsg->Status = Status;
+ return;
+}
diff --git a/private/os2/server/makefile b/private/os2/server/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/os2/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/os2/server/os2srv.c b/private/os2/server/os2srv.c
new file mode 100644
index 000000000..3aed1aca6
--- /dev/null
+++ b/private/os2/server/os2srv.c
@@ -0,0 +1,256 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2srv.c
+
+Abstract:
+
+ This is the main startup module for the OS/2 Emulation Subsystem Server
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include "os2srv.h"
+#include "os2win.h"
+#define NTOS2_ONLY
+#include "sesport.h"
+#include <winerror.h>
+
+ULONG
+GetKeyboardRegistryChange(
+ VOID
+ );
+
+HANDLE
+CreateEventW(
+ PVOID lpEventAttributes,
+ BOOL bManualReset,
+ BOOL bInitialState,
+ LPCWSTR lpName
+ );
+
+BOOL
+SetEvent(
+ HANDLE hEvent
+ );
+
+// Defined in <winbase.h> but we can't include it in this file
+typedef struct _SECURITY_ATTRIBUTES {
+ DWORD nLength;
+ PVOID lpSecurityDescriptor;
+ BOOL bInheritHandle;
+} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
+
+// Flag to let OS2SRV know whether or not to ignore LOGOFF (when started as a service)
+BOOLEAN fService = FALSE;
+
+int __cdecl
+main(
+ IN ULONG argc,
+ IN PCH argv[],
+ IN PCH envp[],
+ IN ULONG DebugFlag OPTIONAL
+ )
+{
+ LARGE_INTEGER TimeOut;
+ PLARGE_INTEGER pTimeOut;
+ NTSTATUS Status;
+ HANDLE SmPort;
+ UNICODE_STRING Os2Name;
+ SCREQUESTMSG Request;
+ ULONG Rc, i;
+ HANDLE InitialEventHandle;
+ SECURITY_ATTRIBUTES Sa;
+ CHAR localSecurityDescriptor[SECURITY_DESCRIPTOR_MIN_LENGTH];
+
+ if ((argc > 1) && (!_stricmp(argv[1], "/S")))
+ {
+ fService = TRUE;
+ }
+
+ // Check whether Os2SSService environment variable is set
+ if (!fService)
+ {
+ char TmpBuffer[256];
+
+ if (GetEnvironmentVariableA(
+ "Os2SSService",
+ &TmpBuffer[0],
+ 256))
+ {
+ // non-zero return code means variable was found
+ fService = TRUE;
+ }
+ }
+ else
+ {
+ if (!SetEnvironmentVariableA(
+ "Os2SSService",
+ "1"))
+ {
+#if DBG
+ KdPrint(("OS2SRV: failed to SetEnvironment variable Os2SSService, error=%x\n",
+ GetLastError()));
+#endif
+ }
+ }
+
+ UNREFERENCED_PARAMETER(DebugFlag);
+
+ environ = envp;
+
+ //
+ // Create Win32 event to ensure that there is only one os2srv in system.
+ //
+
+ if (CreateEventW(
+ NULL,
+ TRUE, // Notification event
+ FALSE, // Nonsignaled
+ L"OS2SRVONLY1EVENT"
+ )) {
+ if (GetLastError() == ERROR_ALREADY_EXISTS) {
+#if DBG
+ KdPrint(( "OS2SRV: Unable to initialize server. Another server exists\n"));
+#endif
+ ExitProcess(1);
+ }
+ }
+ else {
+#if DBG
+ KdPrint(( "OS2SRV: Unable to initialize server - failed to create first event, error=%d\n",
+ GetLastError()));
+#endif
+ ExitProcess(1);
+ }
+
+ // Create security attribute record granting access to all
+ Sa.nLength = sizeof(Sa);
+ Sa.bInheritHandle = TRUE;
+
+ Status = RtlCreateSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION );
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(("OS2SRV: failed at RtlCreateSecurityDescriptor %x\n", Status));
+ ASSERT(FALSE);
+#endif
+ ExitProcess(1);
+ }
+
+ Status = RtlSetDaclSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ (BOOLEAN)TRUE,
+ (PACL) NULL,
+ (BOOLEAN)FALSE );
+
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(("OS2SRV: failed at RtlSetDaclSecurityDescriptor %x\n", Status));
+ ASSERT(FALSE);
+#endif
+ ExitProcess(1);
+ }
+ Sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) &localSecurityDescriptor;
+
+ //
+ // Try to open handle to event that was created by the 1st client. If the
+ // server was invoked before clients it will create the event.
+ //
+ InitialEventHandle = CreateEventW(
+ &Sa,
+ TRUE, // Notification event
+ FALSE, // Nonsignaled
+ U_OS2_SS_INITIALIZATION_EVENT
+ );
+
+ if (!InitialEventHandle) {
+#if DBG
+ KdPrint(("OS2SRV: Fail to open initialization event, error %d\n", GetLastError()));
+#endif
+ ExitProcess(1);
+ }
+
+ Status = SmConnectToSm(NULL,NULL,0,&SmPort);
+ if ( NT_SUCCESS(Status) ) {
+ RtlInitUnicodeString(&Os2Name,L"Os2");
+ SmLoadDeferedSubsystem(SmPort,&Os2Name);
+ }
+
+ Status = Os2Initialize();
+
+ //
+ // Notify all clients that server is up and running.
+ //
+
+ if (!SetEvent(InitialEventHandle)) {
+#if DBG
+ KdPrint(("OS2SRV: Fail to set initialization event, error %d\n", GetLastError()));
+#endif
+ }
+
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(( "OS2SRV: Unable to initialize server. Status == %X\n",
+ Status
+ ));
+#endif
+
+ NtTerminateProcess( NtCurrentProcess(), Status );
+ }
+
+ Request.Request = KbdRequest;
+ Request.d.Kbd.Request = KBDNewCountry;
+
+ PORT_MSG_TOTAL_LENGTH(Request) = sizeof(SCREQUESTMSG);
+ PORT_MSG_DATA_LENGTH(Request) = sizeof(SCREQUESTMSG) - sizeof(PORT_MESSAGE);
+ PORT_MSG_ZERO_INIT(Request) = 0L;
+
+ while ( TRUE )
+ {
+ Rc = GetKeyboardRegistryChange();
+
+ if (Rc == 0)
+ {
+ break;
+ }
+
+ Request.d.Kbd.d.CodePage = Rc;
+
+ for ( i = 1 ; (i < OS2_MAX_SESSION) ; i++ )
+ {
+ if (SessionTable[i].Session)
+ {
+ NtRequestPort(
+ ((POS2_SESSION)SessionTable[i].Session)->ConsolePort,
+ (PPORT_MESSAGE) &Request
+ );
+ }
+ }
+ }
+
+ TimeOut.LowPart = 0x0;
+ TimeOut.HighPart = 0x80000000;
+ pTimeOut = &TimeOut;
+
+rewait:
+ NtDelayExecution(TRUE, pTimeOut);
+ goto rewait;
+
+ return( 0 );
+}
diff --git a/private/os2/server/os2srv.rc b/private/os2/server/os2srv.rc
new file mode 100644
index 000000000..e33b68a02
--- /dev/null
+++ b/private/os2/server/os2srv.rc
@@ -0,0 +1,90 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ os2srv.rc
+
+Abstract:
+
+ This module contains the resource for OS2SRV.EXE.
+
+Author:
+
+ Michael Jarus (mjarus) 15-Feb-1993
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DLL
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "OS2 Subsystem Server"
+#define VER_INTERNALNAME_STR "OS2SRV.EXE"
+#define VER_ORIGINALFILENAME_STR "OS2SRV.EXE"
+
+#include "common.ver"
+
+#include "os2res.h"
+
+STRINGTABLE PRELOAD
+ BEGIN
+ IDS_OS2SRV_ACCESS_API_GP_CAP "%s.EXE - General Protection"
+ IDS_OS2SRV_ACCESS_GP_TXT "An OS/2 program caused a protection violation.\
+\n\nCS\t= 0x%04lx\
+\nIP\t= 0x%04lx\
+\nAX\t= 0x%04lx\
+\nBX\t= 0x%04lx\
+\nCX\t= 0x%04lx\
+\nDX\t= 0x%04lx\
+\nSI\t= 0x%04lx\
+\nDI\t= 0x%04lx\
+\nBP\t= 0x%04lx\
+\nSP\t= 0x%04lx\
+\nSS\t= 0x%04lx\
+\nDS\t= 0x%04lx\
+\nES\t= 0x%04lx\
+\n\nThe program will be terminated."
+ IDS_OS2SRV_API_GP_TXT "An OS/2 program called %s()\nwith a bad pointer argument.\n\nThe application will be terminated.\n"
+ END
+
+//LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US
+// This table is idendical to the default (NEUTRAL)
+
+// Add tables to all supported languages.
diff --git a/private/os2/server/process.c b/private/os2/server/process.c
new file mode 100644
index 000000000..4ebfa9e82
--- /dev/null
+++ b/private/os2/server/process.c
@@ -0,0 +1,813 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ process.c
+
+Abstract:
+
+ This module contains the worker routines called to create and maintain
+ the OS/2 process structure.
+
+Author:
+
+ Steve Wood (stevewo) 04-Oct-1989
+
+Revision History:
+
+--*/
+
+
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_TASKING
+#include "os2srv.h"
+#include "os2tile.h"
+
+#define THREAD_PRIORITY_LOWEST THREAD_BASE_PRIORITY_MIN
+#define THREAD_PRIORITY_BELOW_NORMAL (THREAD_PRIORITY_LOWEST+1)
+#define THREAD_PRIORITY_NORMAL 0
+#define THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX
+#define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST-1)
+
+#define THREAD_PRIORITY_TIME_CRITICAL THREAD_BASE_PRIORITY_LOWRT
+#define THREAD_PRIORITY_IDLE THREAD_BASE_PRIORITY_IDLE
+
+BOOLEAN
+SetThreadPriority(
+ HANDLE hThread,
+ LONG priority
+ );
+
+NTSTATUS
+Os2InitializeProcessStructure( VOID )
+{
+ NTSTATUS Status;
+ ULONG i;
+ APIRET rc;
+
+
+ Status = RtlInitializeCriticalSection( &Os2StructureLock );
+ ASSERT( NT_SUCCESS( Status ) );
+
+// // Obsolete code below: OS/2 ss was keeping processes around as zombie so
+// // that DosCWait doesn't fail when father calls it after child termination.
+// // However, it turns out that OS/2 doesn't do this.
+// InitializeListHead( &Os2ZombieList );
+
+ for (i=0; i<MaxWaitReason; i++) {
+ InitializeListHead( &Os2WaitLists[ i ] );
+ }
+
+ for ( i = 0 ; (i < OS2_MAX_SESSION) ; i++ ) {
+ SessionTable[i].Session = NULL;
+ }
+
+ Os2LastProcessId = (PID)0;
+ Os2NextHigherProcessId = MAXIMUM_PROCESS_ID;
+ Os2RootProcess = NULL;
+ Os2RootProcess = Os2AllocateProcess();
+ ASSERT( Os2RootProcess != NULL );
+ InitializeListHead( &Os2SessionList );
+ InitializeListHead( &Os2RootProcess->ListLink );
+ Os2RootProcess->ProcessHandle = (HANDLE)0xFFFFFFFF;
+ Os2RootProcess->ClientId.UniqueProcess = (HANDLE)0xFFFFFFFF;
+ Os2RootProcess->ClientId.UniqueThread = (HANDLE)0xFFFFFFFF;
+ Os2RootProcess->Session = Os2AllocateSession(NULL, 0, &rc);
+ ASSERT(Os2RootProcess->Session);
+
+ return( Status );
+}
+
+PVOID
+Os2CreateTidBitmap(
+ )
+{
+ PVOID TidBMHeap;
+ PRTL_BITMAP TidBitMapHeader = (PRTL_BITMAP)RtlAllocateHeap( Os2Heap, 0,
+ sizeof( RTL_BITMAP )
+ );
+/* TidBMHeap = RtlCreateHeap( HEAP_GROWABLE,
+ NULL,
+ (_64K + 7) / 8, // 8 bits per byte
+ (_64K + 7) / 8, // 8 bits per byte
+ NULL,
+ 0
+ );
+*/
+ TidBMHeap = RtlAllocateHeap(Os2Heap, 0, (_64K + 7) / 8);
+ if (TidBMHeap == NULL) {
+ return(NULL);
+ }
+
+ RtlInitializeBitMap(TidBitMapHeader ,TidBMHeap, _64K);
+ RtlClearAllBits(TidBitMapHeader);
+ RtlSetBits (TidBitMapHeader,0,1); // We don't use TID 0.
+#ifdef PMNT
+ RtlSetBits (TidBitMapHeader,
+ PMNTFIRSTHIDDENTHREAD,
+ PMNTMAXHIDDENTHREADS); //PMNT Hidden thread
+#endif
+ return(TidBitMapHeader);
+}
+
+ULONG
+Os2AllocateTid(
+#ifdef PMNT
+ IN ULONG Flags,
+#endif
+ POS2_PROCESS Process
+ )
+{
+#ifdef PMNT
+ //
+ // BUGBUG - PMNT Hidden thread do not exit so there is no reason to resycle
+ // the numbers of the hidden thread.
+ //
+ if (Flags == DCT_RUNABLE_HIDDEN){
+ if (Process->LastHiddenThreadId == 0) {
+ Process->LastHiddenThreadId=PMNTFIRSTHIDDENTHREAD-1;
+ }
+ if (Process->LastHiddenThreadId >=
+ (PMNTFIRSTHIDDENTHREAD+PMNTMAXHIDDENTHREADS))
+ return(0xFFFFFFFF);
+ return(++Process->LastHiddenThreadId);
+ }
+ else
+ return((RtlFindClearBitsAndSet( Process->TidBitMapHeader,
+ 1,
+ 0
+ )));
+#else
+ return((RtlFindClearBitsAndSet( Process->TidBitMapHeader,
+ 1,
+ 0
+ )));
+#endif
+}
+
+VOID
+Os2FreeTid(
+ ULONG Index,
+ POS2_PROCESS Process
+ )
+{
+ if (Index > (_64K)) {
+ return;
+ }
+ RtlClearBits( Process->TidBitMapHeader,
+ Index,
+ 1
+ );
+}
+
+POS2_PROCESS
+Os2AllocateProcess( VOID )
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_PROCESS Process = NULL;
+ POS2_PROCESS ScanProcess;
+ BOOLEAN SearchMode;
+ BOOLEAN NextHigherWasSet;
+
+ //
+ // Allocate an OS/2 Process Object
+ //
+
+ Process = (POS2_PROCESS)RtlAllocateHeap( Os2Heap, 0,
+ sizeof( OS2_PROCESS )
+ );
+ if (Process == NULL) {
+ return( NULL );
+ }
+
+ //
+ // Initialize the fields of the process object
+ //
+
+ RtlZeroMemory( Process, sizeof( OS2_PROCESS ) );
+
+ InitializeListHead( &Process->ChildrenList );
+ InitializeListHead( &Process->ThreadList );
+ InitializeListHead( &Process->SharedMemoryList );
+
+ //
+ // if there are 64K-1 processes in the system and there are two process
+ // creates occuring at the same time, they would both end up with the
+ // same pid, if the first to find it was not inserted in the process tree
+ // before the second found the pid. we don't worry about this case.
+ //
+
+ if (Os2RootProcess == NULL) {
+ Process->ProcessId = (PID)0; // root process has ProcessId 0
+ return( Process );
+ }
+
+ Process->TidBitMapHeader = Os2CreateTidBitmap();
+
+ if (Process->TidBitMapHeader == NULL) {
+ RtlFreeHeap(Os2Heap, 0, (PVOID)Process);
+ return( NULL );
+ }
+ SearchMode = FALSE;
+ while (TRUE) {
+ if (Os2LastProcessId == MAXIMUM_PROCESS_ID) {
+ Os2LastProcessId = MINIMUM_PROCESS_ID;
+ SearchMode = TRUE;
+ }
+ else if (!SearchMode && (Os2LastProcessId == Os2NextHigherProcessId)) {
+ Os2LastProcessId = (PID)((ULONG)Os2LastProcessId + 1);
+ SearchMode = TRUE;
+ }
+ else {
+ Os2LastProcessId = (PID)((ULONG)Os2LastProcessId + 1);
+ if (!SearchMode) {
+ break;
+ }
+ }
+
+ // verify that the ProcessID is not allocated to another process
+
+ ListHead = &Os2RootProcess->ListLink;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ ScanProcess = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
+ if ((ScanProcess->ProcessId == Os2LastProcessId) ||
+ (ScanProcess->CommandSubTreeId == Os2LastProcessId)
+ ) {
+ break;
+ }
+ ListNext = ListNext->Flink;
+ }
+ if (ListNext != ListHead) { // This ProcessId is already allocated
+ continue; // to another process.
+ }
+
+ // find the next maximum available free number
+
+ NextHigherWasSet = FALSE;
+ Os2NextHigherProcessId = MAXIMUM_PROCESS_ID;
+ ListHead = &Os2RootProcess->ListLink;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ ScanProcess = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
+ if ((ScanProcess->ProcessId > Os2LastProcessId) &&
+ (Os2NextHigherProcessId >= ScanProcess->ProcessId)) {
+ Os2NextHigherProcessId = ScanProcess->ProcessId;
+ NextHigherWasSet = TRUE;
+ }
+ if ((ScanProcess->CommandSubTreeId > Os2LastProcessId) &&
+ (Os2NextHigherProcessId >= ScanProcess->CommandSubTreeId)) {
+ Os2NextHigherProcessId = ScanProcess->CommandSubTreeId;
+ NextHigherWasSet = TRUE;
+ }
+ ListNext = ListNext->Flink;
+ }
+ if (NextHigherWasSet) {
+ Os2NextHigherProcessId = (PID)((ULONG)Os2NextHigherProcessId - 1);
+ }
+ break;
+ }
+
+ Process->ProcessId = Os2LastProcessId;
+ Process->CommandSubTreeId = Os2LastProcessId;
+ Process->ErrorAction = OS2_ENABLE_ACCESS_VIO_POPUP | OS2_ENABLE_HARD_ERROR_POPUP;
+ Process->FirstPtrace = TRUE;
+ Process->LinkMte = RtlAllocateHeap(Os2Heap, 0, sizeof(LinkMTE));
+ if (Process->LinkMte == NULL) {
+ RtlFreeHeap(Os2Heap, 0, ((PRTL_BITMAP)(Process->TidBitMapHeader))->Buffer);
+ RtlFreeHeap(Os2Heap, 0, Process->TidBitMapHeader);
+ RtlFreeHeap(Os2Heap, 0, (PVOID)(Process));
+ return(NULL);
+ }
+ ((LinkMTE *)Process->LinkMte)->MTE = 0;
+ ((LinkMTE *)Process->LinkMte)->NextMTE = NULL;
+ ((LinkMTE *)Process->LinkMte)->NeedToTransfer = FALSE;
+
+ return( Process );
+}
+
+
+VOID
+Os2DeallocateProcess(
+ IN POS2_PROCESS Process
+ )
+{
+ LinkMTE *pLinkMte, *tmpMte;
+
+ if (Process->TidBitMapHeader) {
+ RtlFreeHeap(Os2Heap, 0, ((PRTL_BITMAP)(Process->TidBitMapHeader))->Buffer);
+ RtlFreeHeap(Os2Heap, 0, Process->TidBitMapHeader);
+ }
+
+ //
+ // Free LinkMTE list
+ //
+ pLinkMte = ((LinkMTE *)Process->LinkMte);
+ while ((tmpMte = pLinkMte) != NULL) {
+ pLinkMte = pLinkMte->NextMTE;
+ RtlFreeHeap(Os2Heap, 0, tmpMte);
+ }
+
+ RtlFreeHeap( Os2Heap, 0, Process );
+}
+
+VOID
+Os2InsertProcess(
+ IN POS2_PROCESS ParentProcess,
+ IN POS2_PROCESS Process
+ )
+{
+
+ if (!ARGUMENT_PRESENT( ParentProcess )) {
+ ParentProcess = Os2RootProcess;
+ }
+ ASSERT( Process->Parent == NULL );
+ ASSERT( IsListEmpty( &Process->ChildrenList ) );
+
+ Process->Parent = ParentProcess;
+ InsertTailList( &ParentProcess->ChildrenList, &Process->SiblingLink );
+ InsertTailList( &Os2RootProcess->ListLink, &Process->ListLink );
+}
+
+
+VOID
+Os2RemoveProcess(
+ IN POS2_PROCESS Process
+ )
+{
+ PLIST_ENTRY ListHead, ListNext, NextNext;
+
+ RemoveEntryList( &Process->SiblingLink );
+ RemoveEntryList( &Process->ListLink );
+
+ if ( !IsListEmpty( &Process->ChildrenList ) ) {
+ //
+ // Process is about to die and some childrent are still
+ // alive - Link all children into parent process
+ //
+ ListHead = &Process->ChildrenList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ NextNext = ListNext->Flink;
+ InsertTailList( &Process->Parent->ChildrenList, ListNext );
+ (CONTAINING_RECORD( ListNext,OS2_PROCESS,SiblingLink))->Parent = Process->Parent;
+ ListNext = NextNext;
+ }
+ }
+ Os2FreeAllSharedMemoryForProcess( Process );
+
+ Os2DeRegisterCtrlHandler(Process);
+}
+
+
+NTSTATUS
+Os2SetProcessContext(
+ IN POS2_PROCESS Process,
+ IN POS2_THREAD Thread,
+ IN BOOLEAN StartedBySm,
+ IN ULONG HandleTableLength,
+ IN ULONG CurrentDrive,
+ IN ULONG CodePage
+ )
+{
+ UNREFERENCED_PARAMETER(Thread);
+ Process->InitialPebOs2Data.Length = sizeof( Process->InitialPebOs2Data );
+ Process->InitialPebOs2Data.ClientStartAddress = NULL;
+ Process->InitialPebOs2Data.StartedBySm = StartedBySm;
+ Process->InitialPebOs2Data.SizeOfInheritedHandleTable = HandleTableLength;
+ Process->InitialPebOs2Data.InitialDefaultDrive = CurrentDrive;
+ Process->InitialPebOs2Data.CodePage = CodePage;
+
+ return( STATUS_SUCCESS );
+}
+
+
+POS2_THREAD
+Os2AllocateThread(
+#ifdef PMNT
+ IN ULONG Flags,
+#endif
+ IN POS2_PROCESS Process
+ )
+{
+ POS2_THREAD Thread;
+
+ //
+ // Allocate an OS/2 Thread Object
+ //
+
+ Thread = (POS2_THREAD)RtlAllocateHeap( Os2Heap, 0,
+ sizeof( OS2_THREAD )
+ );
+ if (Thread == NULL) {
+ return( NULL );
+ }
+
+ //
+ // Initialize the fields of the thread object
+ //
+
+ RtlZeroMemory( Thread, sizeof( OS2_THREAD ) );
+
+ Thread->Process = Process;
+
+ Thread->ThreadId = (TID)Os2AllocateTid(
+#ifdef PMNT
+ Flags,
+#endif
+ Thread->Process);
+ if (Thread->ThreadId == (TID)(0xFFFFFFFF))
+ return (NULL);
+ return( Thread );
+}
+
+
+VOID
+Os2DeallocateThread(
+ IN POS2_THREAD Thread
+ )
+{
+ if (Thread->WaitBlock != NULL) {
+ Os2DestroyWait( Thread->WaitBlock );
+ Thread->WaitBlock = NULL;
+ }
+
+ Os2FreeTid(
+ (ULONG)(Thread->ThreadId),
+ Thread->Process );
+
+ RtlFreeHeap( Os2Heap, 0, Thread );
+}
+
+VOID
+Os2InsertThread(
+ IN POS2_PROCESS Process,
+ IN POS2_THREAD Thread
+ )
+{
+
+ InsertTailList( &Process->ThreadList, &Thread->Link );
+}
+
+VOID
+Os2RemoveThread(
+ IN POS2_PROCESS Process,
+ IN POS2_THREAD Thread
+ )
+{
+ RemoveEntryList( &Thread->Link );
+}
+
+
+VOID
+Os2SetThreadPriority(
+ IN POS2_THREAD Thread,
+ IN ULONG NewClass,
+ IN ULONG Delta
+ )
+{
+ NTSTATUS Status;
+ CHAR Level;
+ ULONG Os2Priority;
+
+ if (Thread->Dying == TRUE) {
+ return;
+ }
+ if (NewClass != PRTYC_NOCHANGE) {
+ Thread->Os2Class = (UCHAR)NewClass;
+ Level = (CHAR)Delta;
+
+ }
+ else {
+ Level = Thread->Os2Level + (CHAR)Delta;
+ if (Level < PRTYD_MINIMUM) {
+ Level = PRTYD_MINIMUM;
+ }
+ else if (Level > PRTYD_MAXIMUM) {
+ Level = PRTYD_MAXIMUM;
+ }
+ }
+
+ Thread->Os2Level = Level;
+ Thread->Priority = (KPRIORITY)(((Level + PRTYD_MAXIMUM) >> 3) |
+ ((Thread->Os2Class-1) << 3));
+
+ if (Thread->Priority == 0) {
+ Thread->Priority = 1;
+ }
+
+ if (Thread->Os2Class == PRTYC_FOREGROUNDSERVER){
+ Thread->Priority = 15;
+ }
+
+ Os2Priority = (Thread->Os2Class << 8) | (UCHAR)Level;
+ Status = NtWriteVirtualMemory( Thread->Process->ProcessHandle,
+ &Thread->ClientOs2Tib->Priority,
+ &Os2Priority,
+ sizeof( Thread->ClientOs2Tib->Priority ),
+ NULL
+ );
+ ASSERT( NT_SUCCESS( Status ) );
+
+ //
+ // Write the priority into the 32-bit local info seg
+ // If the thread is in 16 bit, the next time it does
+ // an API, its local info seg will be updated
+ //
+
+ Status = NtWriteVirtualMemory( Thread->Process->ProcessHandle,
+ &Thread->ClientOs2Tib->LInfoSeg.prtyCurrent,
+ &Os2Priority,
+ sizeof( Thread->ClientOs2Tib->LInfoSeg.prtyCurrent ),
+ NULL
+ );
+ ASSERT( NT_SUCCESS( Status ) );
+
+ //
+ // YS - 6-21-93 - since os2 processes are win32 processes, csrss plays
+ // with their priorities. We can't set the process class to anything but
+ // normal, or we stop the system. Therefor - we have to set the priorities
+ // by win32 apis, as opposed to NT apis used so far.
+ // The way we map is clear from the code below. We are leaving the
+ // THREAD_PRIORITY_TIME_CRITICIAL to our service threads (os2ses\os2.c).
+ //
+
+
+ switch (Thread->Os2Class) {
+
+ case PRTYC_IDLETIME:
+ SetThreadPriority(Thread->ThreadHandle,
+ THREAD_PRIORITY_IDLE);
+ break;
+
+ case PRTYC_REGULAR:
+ //
+ // Set base level by priority, mapping from range (-31 , +31).
+ //
+ if (Level < -15) {
+ SetThreadPriority(Thread->ThreadHandle,
+ THREAD_PRIORITY_LOWEST);
+ }
+ else if (Level < 0) {
+ SetThreadPriority(Thread->ThreadHandle,
+ THREAD_PRIORITY_BELOW_NORMAL);
+ }
+ else if (Level < 15) {
+ SetThreadPriority(Thread->ThreadHandle,
+ THREAD_PRIORITY_NORMAL);
+ }
+ else {
+ SetThreadPriority(Thread->ThreadHandle,
+ THREAD_PRIORITY_ABOVE_NORMAL);
+ }
+ break;
+
+ case PRTYC_FOREGROUNDSERVER:
+ SetThreadPriority(Thread->ThreadHandle,
+ THREAD_PRIORITY_HIGHEST);
+ break;
+
+ case PRTYC_TIMECRITICAL:
+ SetThreadPriority(Thread->ThreadHandle,
+ THREAD_PRIORITY_HIGHEST);
+ break;
+
+ default:
+ break;
+ }
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(("Os2SetThreadPriority - Set PID:TID %x:%x to priority %d. Class=%x, Level=%x\n",
+ Thread->Process->ProcessId, Thread->ThreadId, Thread->Priority, Thread->Os2Class, Level));
+ }
+#endif
+}
+
+
+VOID
+Os2SetProcessPriority(
+ IN POS2_PROCESS Process,
+ IN ULONG NewClass,
+ IN ULONG Delta
+ )
+{
+ PLIST_ENTRY ListHead, ListNext;
+
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Os2SetThreadPriority( CONTAINING_RECORD( ListNext, OS2_THREAD, Link ),
+ NewClass,
+ Delta
+ );
+ ListNext = ListNext->Flink;
+ }
+}
+
+
+VOID
+Os2SetProcessTreePriority(
+ IN POS2_PROCESS RootProcess,
+ IN ULONG NewClass,
+ IN ULONG Delta
+ )
+{
+ PLIST_ENTRY ListHead, ListNext;
+
+ Os2SetProcessPriority( RootProcess, NewClass, Delta );
+
+ ListHead = &RootProcess->ChildrenList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Os2SetProcessTreePriority( CONTAINING_RECORD( ListNext,
+ OS2_PROCESS,
+ SiblingLink
+ ),
+ NewClass,
+ Delta
+ );
+ ListNext = ListNext->Flink;
+ }
+
+}
+
+
+POS2_PROCESS
+Os2LocateProcessByProcessId(
+ IN POS2_API_MSG m OPTIONAL,
+ IN POS2_PROCESS CurrentProcess,
+ IN PID ProcessId,
+ IN BOOLEAN MustBeChild
+ )
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_PROCESS Process;
+ POS2_PROCESS Parent;
+ POS2_THREAD Thread;
+
+ UNREFERENCED_PARAMETER(Thread);
+
+ if (ProcessId == 0) {
+ return( CurrentProcess );
+ }
+
+ ListHead = &Os2RootProcess->ListLink;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Process = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
+ if (Process->ProcessId == ProcessId) {
+ Parent = Process;
+ if (MustBeChild) {
+ while (Parent) {
+ if (Parent == CurrentProcess) {
+ break;
+ }
+ else {
+ Parent = Parent->Parent;
+ }
+ }
+ break;
+ }
+ else {
+ return( Process );
+ }
+ }
+
+ ListNext = ListNext->Flink;
+ }
+
+ if (ListNext != ListHead) {
+ if (Parent == CurrentProcess) {
+ return( Process );
+ }
+ else {
+ if (m != NULL) {
+ m->ReturnedErrorValue = ERROR_NOT_DESCENDANT;
+ }
+
+ return( NULL );
+ }
+ }
+ else {
+ if (m != NULL) {
+ m->ReturnedErrorValue = ERROR_INVALID_PROCID;
+ }
+
+ return( NULL );
+ }
+}
+
+
+POS2_THREAD
+Os2LocateThreadByThreadId(
+ IN POS2_API_MSG m OPTIONAL,
+ IN POS2_THREAD CurrentThread,
+ IN TID ThreadId
+ )
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_PROCESS Process;
+ POS2_THREAD Thread;
+
+ if (ThreadId == 0) {
+ return( CurrentThread );
+ }
+
+ Process = CurrentThread->Process;
+
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
+ if (Thread->ThreadId == ThreadId) {
+ break;
+ }
+
+ ListNext = ListNext->Flink;
+ }
+
+
+ if (ListNext != ListHead) {
+ if (Thread->Dying == FALSE) {
+ return( Thread );
+ }
+ }
+ if (m != NULL) {
+ //
+ // No, this is not suppose to be ERROR_INVALID_TID. Look in
+ // the Cruiser sources, src\dos\task\tkforce.c and you will see.
+ //
+
+ m->ReturnedErrorValue = ERROR_INVALID_THREADID;
+ }
+
+ return( NULL );
+}
+
+POS2_PROCESS
+Os2LocateProcessByClientId(
+ IN PCLIENT_ID ClientId
+ )
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_PROCESS Process = NULL;
+
+ ListHead = &Os2RootProcess->ListLink;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Process = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
+ if (Process->ClientId.UniqueProcess == ClientId->UniqueProcess) {
+ break;
+ }
+
+ Process = NULL;
+ ListNext = ListNext->Flink;
+ }
+
+ return (Process);
+}
+
+POS2_THREAD
+Os2LocateThreadByClientId(
+ POS2_PROCESS Process,
+ IN PCLIENT_ID ClientId
+ )
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_THREAD Thread;
+
+ if (Process == NULL) {
+
+ ListHead = &Os2RootProcess->ListLink;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Process = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
+ if (Process->ClientId.UniqueProcess == ClientId->UniqueProcess) {
+ break;
+ }
+
+ Process = NULL;
+ ListNext = ListNext->Flink;
+ }
+ }
+
+ if (Process != NULL) {
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
+ if (Thread->ClientId.UniqueThread == ClientId->UniqueThread) {
+ break;
+ }
+
+ ListNext = ListNext->Flink;
+ }
+ if (ListNext != ListHead) {
+ return( Thread );
+ }
+ }
+
+ return( NULL );
+}
diff --git a/private/os2/server/sources b/private/os2/server/sources
new file mode 100644
index 000000000..7f896b996
--- /dev/null
+++ b/private/os2/server/sources
@@ -0,0 +1,88 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=os2
+MINORCOMP=server
+
+TARGETNAME=os2srv
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=..\inc
+
+NO_READONLY_STRINGS=1
+
+SOURCES=srvdebug.c \
+ srvnls.c \
+ srvevent.c \
+ srvinit.c \
+ srvcnfg.c \
+ srvnet.c \
+ srvfile.c \
+ srvmutex.c \
+ srvmuxwt.c \
+ srvname.c \
+ srvobjmn.c \
+ srvque.c \
+ srvsem.c \
+ srvsm.c \
+ srvtask.c \
+ srvvm.c \
+ srvxcpt.c \
+ srvwin.c \
+ apiinit.c \
+ apireqst.c \
+ process.c \
+ wait.c \
+ coninit.c \
+ conthrds.c \
+ concreat.c \
+ consignl.c \
+ os2srv.rc
+
+# sbinit.c \
+# sbreqst.c \
+# sbapi.c \
+
+USE_CL860_LARGE_MODEL=1
+
+!IFDEF PMNT
+
+C_DEFINES=-DOS2_SERVER -DWIN32=1 -DPMNT
+
+!ELSE
+
+C_DEFINES=-DOS2_SERVER -DWIN32=1
+
+!ENDIF
+
+UMTYPE=console
+UMAPPL=os2srv
+UMLIBS=obj\*\os2srv.lib \
+ obj\*\os2srv.res \
+ ..\ldr\obj\*\os2ldr.lib \
+ ..\obj\*\os2ssrtl.lib \
+ $(BASEDIR)\public\sdk\lib\*\smdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
diff --git a/private/os2/server/srvcnfg.c b/private/os2/server/srvcnfg.c
new file mode 100644
index 000000000..d90c0d531
--- /dev/null
+++ b/private/os2/server/srvcnfg.c
@@ -0,0 +1,2589 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvcnfg.c
+
+Abstract:
+
+ This module contains the code related to the processing of
+ CONFIG.SYS in the server.
+
+Author:
+
+ Ofer Porat (oferp) 5-Jan-1993
+
+Environment:
+
+ User Mode only
+
+Revision History:
+
+ This code was originally in srvinit.c.
+ 18-3-93 -- initialization code was moved to os2ss\sbcnfg.c so it can run
+ in a privileged process.
+
+--*/
+
+#define INCL_OS2V20_FILESYS
+#include "os2srv.h"
+#include "os2win.h"
+#include "os2err.h"
+#include "os2res.h"
+
+#define PATHLIST_MAX 1024 // max length of pathlists such as Os2LibPath (in characters)
+#define MAX_CONSYS_SIZE 16384 // max size of config.sys buffers (in bytes)
+
+static WCHAR Os2ConfigSysName[] = L"config.sys";
+
+static WCHAR Os2EnvironmentDirectory[] =
+L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
+
+static WCHAR Os2LibPathValueName[] = L"Os2LibPath";
+static WCHAR PathValueName[] = L"Path";
+
+extern WCHAR Os2SystemDirectory[];
+
+// The following stuff is for managing the creation of os2conf.nt
+
+static ULONG Os2ConfigSysUsageCount = 0;
+static ULONG Os2ConfigSysAllowedAccess; // either OPEN_ACCESS_READONLY or .._READWRITE
+static LARGE_INTEGER Os2ConfigSysTimeStamp;
+static LARGE_INTEGER Os2ConfigSysSizeStamp;
+
+WCHAR Os2CanonicalConfigDotSys[MAX_PATH] = L"\\OS2SS\\DRIVES\\";
+
+static WCHAR Os2ConfigSysKeyName[] =
+L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\OS/2 Subsystem for NT\\1.0\\config.sys";
+
+//
+// The following structure is used for passing a character buffer around
+// dispatch functions.
+//
+
+typedef struct _BUFFER_PASSAROUND {
+ PSZ Buffer; // pointer to start of buffer
+ ULONG Index; // current index in buffer to add stuff
+ ULONG MaxSize; // max size of buffer
+} BUFFER_PASSAROUND, *PBUFFER_PASSAROUND;
+
+
+NTSTATUS
+Os2EnvironmentKeysRoutine(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This query routine is used to grab the KEYS setting from the environment.
+
+Arguments:
+
+ Standard parameter set for PRTL_QUERY_REGISTRY_ROUTINE, see <ntrtl.h>.
+
+Return Value:
+
+ NT Error code.
+
+--*/
+
+{
+ if (Or2UnicodeEqualCI(ValueData, L"ON", 2)) {
+ *(PULONG) Context = 1;
+ }
+ return(STATUS_SUCCESS);
+}
+
+
+VOID
+Os2InitializeInternalsFromRegistryDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ )
+
+/*++
+
+Routine Description:
+
+ This is a Dispatch Routine that is used to initialize internal NLS variables from the
+ values contained in the config.sys entry in the registry.
+
+ The values processed are:
+ COUNTRY=
+ CODEPAGE=
+ DEVINFO=KBD,
+
+Arguments:
+
+ Standard arguments passed to a Dispatch Function, see the description of
+ Or2IterateEnvironment in ssrtl\consys.c
+
+ UserParameter - NULL.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNICODE_STRING Value_U;
+ PWSTR wp;
+ WCHAR wch;
+
+ switch (DispatchTableIndex) {
+
+ case 0:
+ Value_U.Buffer = Value;
+ Value_U.MaximumLength = Value_U.Length = (USHORT) (ValueLen * sizeof(WCHAR));
+ RtlUnicodeStringToInteger(&Value_U, 10L, &Os2ssCountryCode);
+ break;
+
+ case 1:
+ for (wp = Value; ValueLen > 0 && *wp != L','; wp++, ValueLen--) {
+ }
+
+ wch = *wp;
+ *wp = UNICODE_NULL;
+
+ RtlInitUnicodeString(&Value_U, Value);
+ RtlUnicodeStringToInteger(&Value_U, 10L, &Os2ssCodePage[0]);
+
+ *wp = wch;
+
+ if (ValueLen > 0) {
+
+ wp++;
+ ValueLen--;
+ Value_U.Buffer = wp;
+ Value_U.MaximumLength = Value_U.Length = (USHORT) (ValueLen * sizeof(WCHAR));
+ RtlUnicodeStringToInteger(&Value_U, 10L, &Os2ssCodePage[1]);
+ }
+
+ break;
+
+ case 2:
+ if (Or2UnicodeEqualCI(Value, L"KBD,", 4)) {
+#if PMNT
+ int i;
+#endif
+
+ Os2ssKeyboardLayout[0] = (CHAR) Value[4];
+ Os2ssKeyboardLayout[1] = (CHAR) Value[5];
+#if PMNT
+ for (i=0,ValueLen -= 6;
+ (i < 4) && (ValueLen > 0) && ((CHAR)Value[6+i] != ',');
+ ValueLen--,i++)
+ {
+ Os2ssKeyboardName[i] = (CHAR) Value[6+i];
+ }
+ // Pad the rest of the array with blanks. A null char at end is
+ // not required.
+ for (; i < 4; i++)
+ Os2ssKeyboardName[i] = ' ';
+#endif // PMNT
+ }
+ break;
+ }
+}
+
+
+VOID
+Os2InitializeInternalsFromRegistry(
+ IN PWSTR RegConSys
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to initialize internal variables from the
+ values contained in the config.sys entry in the registry.
+
+ Note: The "KEYS" setting is picked up from the system environment.
+
+ The processing is done using the dispatch function above.
+
+Arguments:
+
+ RegConSys - a pointer to a UNICODE string containing the config.sys multistring entry.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ static ENVIRONMENT_DISPATCH_TABLE_ENTRY DispatchTable[] =
+ {
+ { L"COUNTRY", L"=", Os2InitializeInternalsFromRegistryDispatchFunction, NULL },
+ { L"CODEPAGE", L"=", Os2InitializeInternalsFromRegistryDispatchFunction, NULL },
+ { L"DEVINFO", L"=", Os2InitializeInternalsFromRegistryDispatchFunction, NULL }
+ };
+
+ static RTL_QUERY_REGISTRY_TABLE QueryTable[] =
+ {
+ { Os2EnvironmentKeysRoutine, RTL_QUERY_REGISTRY_NOEXPAND, L"KEYS", NULL, REG_NONE, NULL, 0 },
+ { NULL, 0, NULL, NULL, REG_NONE, NULL, 0 }
+ };
+
+ Or2IterateEnvironment(RegConSys,
+ DispatchTable,
+ 3,
+ NULL_DELIM);
+
+ //
+ // grab the KEYS setting from the environment
+ //
+
+ Os2ssKeysOnFlag = 0;
+
+ RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+ L"Session Manager\\Environment",
+ QueryTable,
+ &Os2ssKeysOnFlag,
+ NULL
+ );
+
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("Os2ssCountryCode = %lu\n", Os2ssCountryCode));
+ KdPrint(("Os2ssCodePage = %lu, %lu\n", Os2ssCodePage[0], Os2ssCodePage[1]));
+ KdPrint(("Os2ssKeyboardLayout = %c%c\n", Os2ssKeyboardLayout[0], Os2ssKeyboardLayout[1]));
+ KdPrint(("Os2ssKeysOnFlag = %lu\n", Os2ssKeysOnFlag));
+ }
+#endif
+}
+
+
+NTSTATUS
+Os2InitializeRegistry(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This initialization function reads NLS info from the config.sys entry and system
+ environment in the registry to internal variables. It also initializes some
+ internal variables that are used for config.sys file handling.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The value is an NTSTATUS type that is returned when some failure occurs. It may
+ indicate any of several errors that occur during the APIs called in this function.
+ The return value should be tested with NT_SUCCESS(). If an unsuccessful value
+ is returned, it means the NLS read from the registry was not fully initialized.
+
+--*/
+
+{
+ HANDLE ConfigSysKeyHandle;
+ NTSTATUS Status;
+ ULONG ResultLength;
+ PKEY_VALUE_PARTIAL_INFORMATION ExistingConfigSysValueData;
+ KEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
+ UNICODE_STRING ConfigSysName_U;
+ UNICODE_STRING ConfigSysKeyName_U;
+ OBJECT_ATTRIBUTES Obja;
+
+ // These will be intialized later from the registry
+ // zero them just in case we return with an error earlier
+
+ Os2ssCountryCode = 0;
+ Os2ssCodePage[0] = 0;
+ Os2ssCodePage[1] = 0;
+ Os2ssKeyboardLayout[0] = '\0';
+ Os2ssKeyboardLayout[1] = '\0';
+ Os2ssKeysOnFlag = 0;
+
+ // Initialize an internal name
+
+#if OS2CONF_NAME_OPT
+ wcscat(Os2CanonicalConfigDotSys, Os2SystemDirectory);
+#else
+ wcscat(Os2CanonicalConfigDotSys, L"C:");
+#endif
+
+ wcscat(Os2CanonicalConfigDotSys, OS2CONF_NAMEW);
+
+
+ // Get the config.sys entry to read the NLS parms.
+
+ RtlInitUnicodeString(&ConfigSysKeyName_U, Os2ConfigSysKeyName);
+ InitializeObjectAttributes(&Obja,
+ &ConfigSysKeyName_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&ConfigSysKeyHandle,
+ KEY_READ,
+ &Obja
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2InitializeRegistry: Can't open config.sys key, rc = %lx\n",
+ Status));
+ }
+#endif
+ return(Status);
+ }
+
+ RtlInitUnicodeString(&ConfigSysName_U, Os2ConfigSysName);
+ Status = NtQueryValueKey(ConfigSysKeyHandle,
+ &ConfigSysName_U,
+ KeyValuePartialInformation,
+ &ValuePartialInformation,
+ 0,
+ &ResultLength
+ );
+
+ if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2InitializeRegistry: Can't read config.sys value, rc = %lx\n",
+ Status));
+ }
+#endif
+ NtClose(ConfigSysKeyHandle);
+ return(Status);
+ }
+
+ ExistingConfigSysValueData = (PKEY_VALUE_PARTIAL_INFORMATION)
+ RtlAllocateHeap(Os2Heap, 0, ResultLength);
+
+ if (ExistingConfigSysValueData == NULL) { // no mem -- give up
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2InitializeRegistry: Failed allocation for registry config.sys\n"));
+ }
+#endif
+ NtClose(ConfigSysKeyHandle);
+ return (STATUS_NO_MEMORY);
+ }
+
+ Status = NtQueryValueKey(ConfigSysKeyHandle,
+ &ConfigSysName_U,
+ KeyValuePartialInformation,
+ ExistingConfigSysValueData,
+ ResultLength,
+ &ResultLength
+ );
+
+ if (!NT_SUCCESS(Status)) { // give up
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2InitializeRegistry: Failed to read registry config.sys, rc = %lx\n", Status));
+ }
+#endif
+ NtClose(ConfigSysKeyHandle);
+ return (Status);
+ }
+
+ // process the entry
+
+ Os2InitializeInternalsFromRegistry((PWSTR) ExistingConfigSysValueData->Data);
+
+ RtlFreeHeap(Os2Heap, 0, ExistingConfigSysValueData);
+
+ NtClose(ConfigSysKeyHandle);
+ return (STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+Os2AddToBuffer(
+ IN OUT PBUFFER_PASSAROUND BufP,
+ IN PSZ PreString,
+ IN PWSTR String,
+ IN BOOLEAN ExpandFirst
+ )
+
+/*++
+
+Routine Description:
+
+ This is a general routine used to copy strings to the os2conf.nt file
+ buffer. It is used by the routines below. It makes sure not to
+ overflow the buffer.
+
+Arguments:
+
+ BufP -- The buffer to which the information should be appended.
+ PreString -- The 1st string to be appended to BufP.
+ String -- The 2nd string to be appended.
+ ExpandFirst -- If this is true then the 2nd string is expanded for
+ environment variables before it's copied over into the buffer.
+
+Return Value:
+
+ NT Error code.
+
+--*/
+
+{
+ UNICODE_STRING Tmp_U, Tmp_DestU;
+ ANSI_STRING Tmp_A;
+ ULONG l;
+ NTSTATUS Status;
+ APIRET rc;
+
+ l = strlen(PreString);
+
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2AddToBuffer: Entered\n"));
+ }
+#endif
+ if (BufP->Index + l + 3 > BufP->MaxSize) { // 3 for CR,LF,\0
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2AddToBuffer: Out of buffer space-1\n"));
+ }
+#endif
+ return(STATUS_BUFFER_OVERFLOW);
+ }
+
+ RtlInitUnicodeString(&Tmp_U, String);
+
+ if (!ExpandFirst) {
+
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2AddToBuffer: Not expanding first\n"));
+ }
+#endif
+ Tmp_A.Buffer = BufP->Buffer + BufP->Index + l;
+ Tmp_A.MaximumLength = (USHORT) (BufP->MaxSize - BufP->Index - l - 3);
+
+ rc = Or2UnicodeStringToMBString(&Tmp_A, &Tmp_U, FALSE);
+
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2AddToBuffer: Out of buffer space-2, UnicodeStringtoMBString rc = %x\n", rc));
+ }
+#endif
+ return(STATUS_BUFFER_OVERFLOW);
+ }
+
+ } else {
+
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2AddToBuffer: Expanding first\n"));
+ }
+#endif
+ Tmp_A.Buffer = BufP->Buffer + BufP->Index + l;
+ Tmp_A.MaximumLength = (USHORT)(BufP->MaxSize - BufP->Index - l - 3);
+
+ Tmp_DestU.MaximumLength = Tmp_A.MaximumLength;
+ Tmp_DestU.Buffer = RtlAllocateHeap(RtlProcessHeap(), 0, Tmp_DestU.MaximumLength * sizeof(WCHAR));
+ if (!Tmp_DestU.Buffer) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2AddToBuffer: RtlAllocateHeap rc = %lx\n", STATUS_NO_MEMORY));
+ }
+#endif
+ return(STATUS_NO_MEMORY);
+ }
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2AddToBuffer: Ready to call Expand: <%ws> to %08x(%d)\n", Tmp_U.Buffer, Tmp_DestU.Buffer, Tmp_DestU.MaximumLength));
+ }
+#endif
+
+ Status = RtlExpandEnvironmentStrings_U(NULL,
+ &Tmp_U,
+ &Tmp_DestU,
+ NULL);
+ if (NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2AddToBuffer: Expand succeeded: <%ws>\n", Tmp_DestU.Buffer));
+ }
+#endif
+ Status = RtlUnicodeStringToOemString((POEM_STRING)&Tmp_A, &Tmp_DestU, FALSE);
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2AddToBuffer: After CV2OEM: <%s>\n", Tmp_A.Buffer));
+ }
+#endif
+ }
+
+ RtlFreeHeap(RtlProcessHeap(), 0, Tmp_DestU.Buffer);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2AddToBuffer: Out of buffer space-3, RtlExpandEnvStrings rc = %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+ }
+
+
+ if (l != 0) {
+ RtlMoveMemory(BufP->Buffer + BufP->Index, PreString, l);
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2AddToBuffer: MoveMemory <%s>\n", BufP->Buffer));
+ }
+#endif
+ }
+ BufP->Index += l + Tmp_A.Length;
+
+ BufP->Buffer[BufP->Index++] = '\r';
+ BufP->Buffer[BufP->Index++] = '\n';
+
+ return(STATUS_SUCCESS);
+}
+
+
+
+VOID
+Os2ProcessConfigSysSetDirectivesDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ )
+
+/*++
+
+Routine Description:
+
+ This dispatch function copy set directives from the config.sys entry
+ in the registry to the os2conf.nt file buffer. Only special SET
+ commands are copied.
+
+Arguments:
+
+ Standard arguments passed to a Dispatch Function, see the description of
+ Or2IterateEnvironment in ssrtl\consys.c
+
+ UserParameter - Buffer for os2conf.nt file.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PBUFFER_PASSAROUND BufP = (PBUFFER_PASSAROUND) UserParameter;
+
+ if (Or2UnicodeEqualCI(Value, L"COMSPEC=", 8)) {
+
+ Os2AddToBuffer(BufP, "", Name, FALSE);
+
+ }
+}
+
+
+VOID
+Os2ProcessConfigSysGeneralDirectivesDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ )
+
+/*++
+
+Routine Description:
+
+ This dispatch function copies general directives from the config.sys
+ entry in the registry into the os2conf.nt file buffer.
+
+Arguments:
+
+ Standard arguments passed to a Dispatch Function, see the description of
+ Or2IterateEnvironment in ssrtl\consys.c
+
+ UserParameter - Buffer for os2conf.nt file.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PBUFFER_PASSAROUND BufP = (PBUFFER_PASSAROUND) UserParameter;
+
+ Os2AddToBuffer(BufP, "", Value, FALSE);
+}
+
+
+NTSTATUS
+Os2EnvironmentQueryRoutine(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This is the query routine used to process the system environment.
+ It copies the variables into the os2conf.nt file in the correct
+ OS/2 config.sys format.
+
+Arguments:
+
+ Standard parameter set for PRTL_QUERY_REGISTRY_ROUTINE, see <ntrtl.h>.
+
+Return Value:
+
+ NT Error code.
+
+--*/
+
+{
+ PBUFFER_PASSAROUND BufP = (PBUFFER_PASSAROUND) Context;
+ ULONG SaveIndex;
+ NTSTATUS Status;
+
+ if (Or2UnicodeEqualCI(ValueName, L"COMSPEC", 8) ||
+ Or2UnicodeEqualCI(ValueName, L"LIBPATH", 8)) {
+ return(STATUS_SUCCESS);
+ }
+
+ // BUGBUG: we should probably do a semicolon check on PATH and LIBPATH at this point.
+
+ if (Or2UnicodeEqualCI(ValueName, L"OS2LIBPATH", 11)) {
+ return(Os2AddToBuffer(BufP, "LIBPATH=", (PWSTR) ValueData, TRUE));
+ } else if (Or2UnicodeEqualCI(ValueName, L"PATH", 5)) {
+ return(Os2AddToBuffer(BufP, "SET PATH=", (PWSTR) ValueData, TRUE));
+ }
+
+ SaveIndex = BufP->Index;
+
+ Status = Os2AddToBuffer(BufP, "SET ", ValueName, FALSE);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2EnvironmentQueryRoutine: Os2AddToBuffer-1 rc = %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+
+ BufP->Index -= 2; // remove the CRLF
+
+ Status = Os2AddToBuffer(BufP, "=", (PWSTR) ValueData, FALSE);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2EnvironmentQueryRoutine: Os2AddToBuffer-2 rc = %lx\n", Status));
+ }
+#endif
+ BufP->Index = SaveIndex;
+ }
+
+ return(Status);
+}
+
+
+NTSTATUS
+Os2ProcessConfigSys(
+ IN HANDLE EnvironmentKeyHandle,
+ IN PUNICODE_STRING ConfigSysValueData_U,
+ OUT PSZ Buffer,
+ IN OUT PULONG BufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine prepares the contents of os2conf.nt from the info in
+ the environment.
+
+Arguments:
+
+ EnvironmentKeyHandle -- an open (READ) handle to the system environment.
+ ConfigSysValueData_U -- The contents of the config.sys entry in the registry.
+ Buffer -- A buffer to put the contents of os2conf.nt in.
+ BufferLength -- on entry, the maximum size of Buffer. On exit, the
+ final size of the info in Buffer.
+
+Return Value:
+
+ An NT error code.
+
+--*/
+
+{
+ static ENVIRONMENT_DISPATCH_TABLE_ENTRY DispatchTable[] =
+ {
+ { L"NTRE", L"M", NULL, NULL },
+ { L"LIBPATH", L"=", NULL, NULL },
+ { L"SET", L" \t", Os2ProcessConfigSysSetDirectivesDispatchFunction, NULL },
+ { L"*", NULL, Os2ProcessConfigSysGeneralDirectivesDispatchFunction, NULL },
+ };
+
+ static RTL_QUERY_REGISTRY_TABLE QueryTable[] =
+ {
+ { Os2EnvironmentQueryRoutine, RTL_QUERY_REGISTRY_NOEXPAND, NULL, NULL, REG_NONE, NULL, 0 },
+ { NULL, 0, NULL, NULL, REG_NONE, NULL, 0 }
+ };
+
+ BUFFER_PASSAROUND BufP;
+ NTSTATUS Status;
+
+ BufP.Buffer = Buffer;
+ BufP.Index = 0;
+ BufP.MaxSize = *BufferLength;
+
+ DispatchTable[2].UserParameter = (PVOID) &BufP;
+ DispatchTable[3].UserParameter = (PVOID) &BufP;
+
+ Or2IterateEnvironment(ConfigSysValueData_U->Buffer,
+ DispatchTable,
+ 4,
+ NULL_DELIM);
+
+ //
+ // now we enumerate the system environment and enter variables from there.
+ //
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
+ (PWSTR)EnvironmentKeyHandle,
+ QueryTable,
+ (PVOID) &BufP,
+ NULL
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2ProcessConfigSys: Os2EnvironmentQueryRoutine rc = %lx\n", Status));
+ }
+#endif
+ }
+
+ Buffer[BufP.Index] = '\0';
+ *BufferLength = BufP.Index;
+ return(STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+Os2GetFileStamps(
+ IN HANDLE hFile,
+ OUT PLARGE_INTEGER pTimeStamp,
+ OUT PLARGE_INTEGER pSizeStamp
+ )
+
+/*++
+
+Routine Description:
+
+ This function reads a file's size and time of last write.
+
+Arguments:
+
+ hFile -- handle of file to read.
+ pTimeStamp -- returns file time of last write.
+ pSizeStamp -- returns file size.
+
+Return Value:
+
+ NT error code. The return parameters are valid only if this is
+ success.
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ FILE_BASIC_INFORMATION BasicInfo;
+ FILE_STANDARD_INFORMATION StandardInfo;
+
+ Status = NtQueryInformationFile(hFile,
+ &IoStatus,
+ &BasicInfo,
+ sizeof(BasicInfo),
+ FileBasicInformation);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2GetFileStamps: Unable to query file time, rc = %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+
+ *pTimeStamp = BasicInfo.LastWriteTime;
+
+ Status = NtQueryInformationFile(hFile,
+ &IoStatus,
+ &StandardInfo,
+ sizeof(StandardInfo),
+ FileStandardInformation);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2GetFileStamps: Unable to query file size, rc = %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+
+ *pSizeStamp = StandardInfo.EndOfFile;
+
+ return(STATUS_SUCCESS);
+}
+
+
+BOOLEAN
+Os2ConfigSysCreator(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+ This function implements the server API which creates the os2conf.nt
+ file for OS/2 apps to use.
+
+Arguments:
+
+ t -- client thread that generated this API.
+ m -- an OS2_CONFIGSYS_MSG message type containing the request.
+
+ The message fields are as follows:
+
+ IN ULONG RequiredAccess -- access user desires
+ OUT ULONG AllowedAccess -- access allowed
+ OUT NTSTATUS ReturnStatus -- an error code
+
+ All access values are either OPEN_ACCESS_READONLY or OPEN_ACCESS_READWRITE.
+
+ Notes:
+ -- The os2conf.nt file has been created only if ReturnStatus is success
+ -- AllowedAccess is valid on return only if ReturnStatus is success or STATUS_ACCESS_DENIED
+ -- if RequiredAccess is READWRITE and only READONLY is available, the
+ os2conf.nt won't be created, ReturnStatus will be STATUS_ACCESS_DENIED,
+ and AllowedAccess will be READONLY.
+
+Return Value:
+
+ TRUE to tell server to answer client.
+
+--*/
+
+{
+ POS2_CONFIGSYS_MSG a = &m->u.CreateConfigSysRequest;
+ NTSTATUS Status;
+ UNICODE_STRING ConfigSysKeyName_U;
+ UNICODE_STRING ConfigSysValueName_U;
+ UNICODE_STRING EnvironmentKeyName_U;
+ UNICODE_STRING ConfigSysValueData_U;
+ UNICODE_STRING CanonicalConfigDotSys_U;
+ HANDLE ConfigSysKeyHandle = NULL;
+ HANDLE EnvironmentKeyHandle = NULL;
+ HANDLE ConfigSysFileHandle;
+ ULONG ResultLength;
+ KEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
+ PKEY_VALUE_PARTIAL_INFORMATION pInfo = NULL;
+ FILE_BASIC_INFORMATION FileBasicInfo;
+ OBJECT_ATTRIBUTES Obja;
+ PSZ pMem = NULL;
+ IO_STATUS_BLOCK IoStatus;
+
+ //
+ // Validate parameters
+ //
+
+ if (a->RequiredAccess != OPEN_ACCESS_READONLY &&
+ a->RequiredAccess != OPEN_ACCESS_READWRITE) {
+ a->ReturnStatus = STATUS_INVALID_PARAMETER;
+ return(TRUE);
+ }
+
+ //
+ // if UsageCount for config.sys is > 0, then it already exists, and
+ // there is not much to do.
+ //
+
+ if (Os2ConfigSysUsageCount > 0) {
+
+ a->AllowedAccess = Os2ConfigSysAllowedAccess;
+
+ if (a->RequiredAccess == OPEN_ACCESS_READWRITE &&
+ Os2ConfigSysAllowedAccess == OPEN_ACCESS_READONLY) {
+
+ //
+ // we can't supply the required access
+ //
+
+ a->ReturnStatus = STATUS_ACCESS_DENIED;
+ } else {
+
+ if (!t->Process->ConfigSysUsageFlag) {
+ Os2ConfigSysUsageCount++;
+ t->Process->ConfigSysUsageFlag = TRUE;
+ }
+
+ a->ReturnStatus = STATUS_SUCCESS;
+ }
+
+ return(TRUE);
+ }
+
+ //
+ // Now for the real job --
+ // create a fresh os2conf.nt file from the registry information.
+ //
+
+ do { // A 1-time loop to allow break upon error
+
+ Os2ConfigSysAllowedAccess = a->AllowedAccess = OPEN_ACCESS_READONLY;
+
+ //
+ // First, allocate a large buffer for us to build config.sys for the
+ // user in.
+ //
+
+ pMem = (PSZ) RtlAllocateHeap(Os2Heap, 0, MAX_CONSYS_SIZE);
+ if (pMem == NULL) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2ConfigSysCreator: Unable to RtlAllocateHeap space for user file generation\n"));
+ }
+#endif
+ Status = STATUS_NO_MEMORY;
+ break;
+ }
+
+ //
+ // Next, attempt to open the system environment and see if we have
+ // access of the desired type
+ //
+
+ RtlInitUnicodeString(&EnvironmentKeyName_U, Os2EnvironmentDirectory);
+ InitializeObjectAttributes(&Obja,
+ &EnvironmentKeyName_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&EnvironmentKeyHandle,
+ KEY_READ | KEY_WRITE,
+ &Obja
+ );
+
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2ConfigSysCreator: Unable to NtOpenKey() the system environment for writing, rc = %lx\n",
+ Status));
+ }
+#endif
+
+ if (Status != STATUS_ACCESS_DENIED ||
+ a->RequiredAccess == OPEN_ACCESS_READWRITE) {
+ break;
+ }
+
+ //
+ // retry opening it for reading
+ //
+
+ Status = NtOpenKey(&EnvironmentKeyHandle,
+ KEY_READ,
+ &Obja
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2ConfigSysCreator: Unable to NtOpenKey() the system environment for reading, rc = %lx\n",
+ Status));
+ }
+#endif
+ break;
+ }
+
+ } else {
+ Os2ConfigSysAllowedAccess = a->AllowedAccess = OPEN_ACCESS_READWRITE;
+ }
+
+ //
+ // Attempt to open the config.sys key and read in the key
+ //
+
+ RtlInitUnicodeString(&ConfigSysKeyName_U, Os2ConfigSysKeyName);
+ InitializeObjectAttributes(&Obja,
+ &ConfigSysKeyName_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&ConfigSysKeyHandle,
+ KEY_READ,
+ &Obja
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC){
+ KdPrint(("Os2ConfigSysCreator: Unable to NtOpenKey() of config.sys %lx\n",
+ Status));
+ }
+#endif
+
+ //
+ // If the config.sys entry has disappeared for some reason, we return
+ // STATUS_ACCESS_DENIED. This way the os/2 program will get a less
+ // confusing error code (ERROR_ACCESS_DENIED) than ERROR_FILE_NOT_FOUND.
+ // (note that ERROR_FILE_NOT_FOUND would've been returned even if the
+ // os/2 program had tried to create the file!)
+ //
+
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
+ Status == STATUS_OBJECT_PATH_NOT_FOUND ||
+ Status == STATUS_OBJECT_PATH_INVALID) {
+ Status = STATUS_ACCESS_DENIED;
+ }
+
+ break;
+ }
+
+ RtlInitUnicodeString(&ConfigSysValueName_U, Os2ConfigSysName);
+ Status = NtQueryValueKey(ConfigSysKeyHandle,
+ &ConfigSysValueName_U,
+ KeyValuePartialInformation,
+ &KeyValuePartialInfo,
+ sizeof(KeyValuePartialInfo),
+ &ResultLength
+ );
+
+ if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_OVERFLOW)) {
+#if DBG
+ IF_OS2_DEBUG(MISC){
+ KdPrint(("Os2ConfigSysCreator: Unable to NtQueryValueKey()-1 config.sys %lx\n",
+ Status));
+ }
+#endif
+ //
+ // same error code translation as the openkey above
+ //
+
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
+ Status == STATUS_OBJECT_PATH_NOT_FOUND ||
+ Status == STATUS_OBJECT_PATH_INVALID) {
+ Status = STATUS_ACCESS_DENIED;
+ }
+
+ break;
+ }
+
+ pInfo = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(Os2Heap, 0, ResultLength);
+ if (pInfo == NULL) {
+#if DBG
+ IF_OS2_DEBUG(MISC){
+ KdPrint(("Os2ConfigSysCreator: Unable to RtlAllocateHeap space for config.sys entry\n"));
+ }
+#endif
+ break;
+ }
+
+ Status = NtQueryValueKey(ConfigSysKeyHandle,
+ &ConfigSysValueName_U,
+ KeyValuePartialInformation,
+ pInfo,
+ ResultLength,
+ &ResultLength
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC){
+ KdPrint(("Os2ConfigSysCreator: Unable to NtQueryValueKey()-2 config.sys %lx\n",
+ Status));
+ }
+#endif
+ break;
+ }
+
+ ConfigSysValueData_U.Buffer = (PWSTR) pInfo->Data;
+ ConfigSysValueData_U.MaximumLength = ConfigSysValueData_U.Length = (USHORT) pInfo->DataLength;
+
+ NtClose(ConfigSysKeyHandle);
+ ConfigSysKeyHandle = NULL;
+
+ //
+ // We now have all we need:
+ // an open handle to the system environment
+ // a copy of the config.sys registry entry.
+ // a buffer to build the user's file in.
+
+ ResultLength = MAX_CONSYS_SIZE;
+
+ Status = Os2ProcessConfigSys(EnvironmentKeyHandle,
+ &ConfigSysValueData_U,
+ pMem,
+ &ResultLength
+ );
+
+ RtlFreeHeap(Os2Heap, 0, pInfo);
+ pInfo = NULL;
+ NtClose(EnvironmentKeyHandle);
+ EnvironmentKeyHandle = NULL;
+
+ if (!NT_SUCCESS(Status)) { // Od2ProcessConfigSys failed?
+#if DBG
+ IF_OS2_DEBUG(MISC){
+ KdPrint(("Os2ConfigSysCreator: Os2ProcessConfigSys has faild, rc = %lx\n",
+ Status));
+ }
+#endif
+ break;
+ }
+
+ //
+ // The user's file is now ready in pMem
+ // Write it to a file.
+ //
+
+ RtlInitUnicodeString(&CanonicalConfigDotSys_U, Os2CanonicalConfigDotSys);
+ InitializeObjectAttributes(&Obja,
+ &CanonicalConfigDotSys_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtCreateFile(&ConfigSysFileHandle,
+ FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES,
+ &Obja,
+ &IoStatus,
+ NULL,
+ Os2ConfigSysAllowedAccess == OPEN_ACCESS_READWRITE ?
+ FILE_ATTRIBUTE_NORMAL :
+ FILE_ATTRIBUTE_READONLY,
+ 0,
+ FILE_OVERWRITE_IF,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC){
+ KdPrint(("Os2ConfigSysCreator: Unable to NtCreateFile-1() os2conf.nt, rc = %lx\n",
+ Status));
+ }
+#endif
+ if (Status != STATUS_ACCESS_DENIED) {
+ break;
+ }
+
+ //
+ // The file may be a read-only file. We'll attempt to overwrite it.
+ //
+
+ Status = NtOpenFile(&ConfigSysFileHandle,
+ STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE |
+ SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_VALID_FLAGS,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC){
+ KdPrint(("Os2ConfigSysCreator: Unable to NtOpenFile-2() os2conf.nt, rc = %lx\n",
+ Status));
+ }
+#endif
+ break;
+ }
+
+ Status = NtQueryInformationFile(ConfigSysFileHandle,
+ &IoStatus,
+ &FileBasicInfo,
+ sizeof(FileBasicInfo),
+ FileBasicInformation
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Os2ConfigSysCreator: Rc from NtQueryInformationFile(Attrib) %lx\n", Status));
+ }
+#endif
+ NtClose(ConfigSysFileHandle);
+ break;
+ }
+
+ if ((FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_READONLY) != 0) {
+
+ FileBasicInfo.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
+
+ Status = NtSetInformationFile(ConfigSysFileHandle,
+ &IoStatus,
+ &FileBasicInfo,
+ sizeof(FileBasicInfo),
+ FileBasicInformation
+ );
+
+ NtClose(ConfigSysFileHandle);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Os2ConfigSysCreator: Rc from NtSetInformationFile(Attrib) %lx\n", Status));
+ }
+#endif
+ break;
+ }
+ } else {
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Os2ConfigSysCreator: NtCreateFile-1() did not fail because of readonly\n"));
+ }
+#endif
+ NtClose(ConfigSysFileHandle);
+ Status = STATUS_ACCESS_DENIED;
+ break;
+ }
+
+ //
+ // We made the file read-write, now try recreating.
+ //
+
+ Status = NtCreateFile(&ConfigSysFileHandle,
+ FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES,
+ &Obja,
+ &IoStatus,
+ NULL,
+ Os2ConfigSysAllowedAccess == OPEN_ACCESS_READWRITE ?
+ FILE_ATTRIBUTE_NORMAL :
+ FILE_ATTRIBUTE_READONLY,
+ 0,
+ FILE_OVERWRITE_IF,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC){
+ KdPrint(("Os2ConfigSysCreator: Unable to NtCreateFile-3() os2conf.nt, rc = %lx\n",
+ Status));
+ }
+#endif
+ break;
+ }
+
+ //
+ // finally succeeded
+ //
+ }
+
+ Status = NtWriteFile(ConfigSysFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ pMem,
+ ResultLength,
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC){
+ KdPrint(("Os2ConfigSysCreator: Unable to NtWriteFile() os2conf.nt, rc = %lx\n",
+ Status));
+ }
+#endif
+ NtClose(ConfigSysFileHandle);
+ break;
+ }
+
+ RtlFreeHeap(Os2Heap, 0, pMem);
+ pMem = NULL;
+
+ //
+ // Get file and size stamps for the file
+ //
+
+ Status = Os2GetFileStamps(ConfigSysFileHandle, &Os2ConfigSysTimeStamp, &Os2ConfigSysSizeStamp);
+
+ NtClose(ConfigSysFileHandle);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC){
+ KdPrint(("Os2ConfigSysCreator: Os2GetFileStamps() on os2conf.nt has failed, rc = %lx\n",
+ Status));
+ }
+#endif
+ break;
+ }
+
+ //
+ // We've succeeded.
+ //
+
+ Os2ConfigSysUsageCount++;
+ t->Process->ConfigSysUsageFlag = TRUE;
+ a->ReturnStatus = STATUS_SUCCESS;
+
+ } while (FALSE);
+
+ if (Os2ConfigSysUsageCount == 0)
+ {
+ // Creation of os2conf.nt failed
+ // Close all handles and buffers
+ // returns TRUE and sends the last error to the caller
+
+ if (EnvironmentKeyHandle != NULL)
+ {
+ NtClose(EnvironmentKeyHandle);
+ }
+ if (ConfigSysKeyHandle != NULL)
+ {
+ NtClose(ConfigSysKeyHandle);
+ }
+ if (pInfo != NULL)
+ {
+ RtlFreeHeap(Os2Heap, 0, pInfo);
+ }
+ if (pMem != NULL)
+ {
+ RtlFreeHeap(Os2Heap, 0, pMem);
+ }
+
+ a->ReturnStatus = Status;
+ }
+
+ return(TRUE);
+}
+
+
+VOID
+Os2PreProcessingDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ )
+
+/*++
+
+Routine Description:
+
+ This dispatch function is used to copy some standard stuff which resides in the registry
+ config.sys to the new registry config.sys that is being built from os2conf.nt.
+
+Arguments:
+
+ Standard arguments passed to a Dispatch Function, see the description of
+ Or2IterateEnvironment in ssrtl\consys.c
+
+ UserParameter - a pointer to the pointer that indicates where in the new config.sys
+ buffer we should fill in the information.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PWSTR *BufferPtr = (PWSTR *) UserParameter;
+
+ if (DispatchTableIndex == 1 &&
+ !Or2UnicodeEqualCI(Value, L"PATH=", 5)) {
+ return;
+ }
+
+ wcscpy(*BufferPtr, Name);
+ *BufferPtr += wcslen(Name) + 1;
+}
+
+
+VOID
+Os2PreProcessExistingConfigSys(
+ IN OUT PWSTR *BufferPtr,
+ IN PUNICODE_STRING ConfigSysValueData_U
+ )
+
+/*++
+
+Routine Description:
+
+ This routine goes over the old config.sys entry and copies over some old stuff
+ to the new config.sys entry.
+
+Arguments:
+
+ BufferPtr -- a pointer into the buffer that receives the new config.sys info.
+ ConfigSysValueData_U -- a counted unicode string containing the old MULTI-SZ
+ config.sys registry value.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG i;
+
+ static ENVIRONMENT_DISPATCH_TABLE_ENTRY DispatchTable[] =
+ {
+ { L"NTRE", L"M", Os2PreProcessingDispatchFunction, NULL },
+ { L"SET", L" \t", Os2PreProcessingDispatchFunction, NULL },
+ { L"LIBPATH", L"=", Os2PreProcessingDispatchFunction, NULL }
+ };
+
+ for (i = 0; i < 3; i++) {
+ DispatchTable[i].UserParameter = (PVOID) BufferPtr;
+ }
+
+ Or2IterateEnvironment(ConfigSysValueData_U->Buffer,
+ DispatchTable,
+ 3,
+ NULL_DELIM);
+}
+
+
+NTSTATUS
+Os2WipeOutEnvironmentQueryRoutine(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used in conjunction with the next one in order to wipe out the
+ system environment of the old variables.
+
+Arguments:
+
+ Standard parameter set for PRTL_QUERY_REGISTRY_ROUTINE, see <ntrtl.h>.
+
+Return Value:
+
+ NT Error code.
+
+--*/
+
+{
+ NTSTATUS Status;
+ UNICODE_STRING ValueName_U;
+
+ if (Or2UnicodeEqualCI(ValueName, L"COMSPEC", 8) ||
+ Or2UnicodeEqualCI(ValueName, L"LIBPATH", 8) ||
+ Or2UnicodeEqualCI(ValueName, L"PATH", 5) ||
+ Or2UnicodeEqualCI(ValueName, L"OS2LIBPATH", 11)) {
+
+ return(STATUS_SUCCESS);
+ }
+
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2WipeOutEnvironmentQueryRoutine: calling NtDeleteValueKey(%lx, %ws)\n", (ULONG)Context, ValueName));
+ }
+#endif
+
+ RtlInitUnicodeString(&ValueName_U, ValueName);
+ Status = NtDeleteValueKey((HANDLE)Context,
+ &ValueName_U
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2WipeOutEnvironmentQueryRoutine: Rc from NtDeleteValueKey = %lx\n", Status));
+ }
+#endif
+ } else {
+ *(PBOOLEAN) EntryContext = TRUE;
+ }
+
+ return(Status);
+}
+
+
+VOID
+Os2WipeOutEnvironment(
+ IN HANDLE EnvironmentKeyHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to wipe out the system environment variables in preparation for setting
+ new ones from os2conf.nt.
+
+Arguments:
+
+ EnvironmentKeyHandle -- a writable handle to the system env key in the registry.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BOOLEAN SomeDeleted;
+ NTSTATUS Status;
+
+ static RTL_QUERY_REGISTRY_TABLE QueryTable[] =
+ {
+ { Os2WipeOutEnvironmentQueryRoutine, RTL_QUERY_REGISTRY_NOEXPAND, NULL, NULL, REG_NONE, NULL, 0 },
+ { NULL, 0, NULL, NULL, REG_NONE, NULL, 0 }
+ };
+
+ //
+ // We do it in a loop until we finally get all variables deleted.
+ // The reason we need a loop and that one time is not enough is
+ // that we're deleting values while they're being enumerated.
+ // This causes the enumeration to work incorrectly, and the effect
+ // is that not all variables that should be deleted are deleted.
+ // However, each run thru the loop deletes at least one variable,
+ // and so we'll finally get all of them deleted.
+ //
+
+ QueryTable[0].EntryContext = (PVOID) &SomeDeleted;
+
+ do {
+
+ SomeDeleted = FALSE;
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
+ (PWSTR)EnvironmentKeyHandle,
+ QueryTable,
+ (PVOID)EnvironmentKeyHandle,
+ NULL
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2WipeOutEnvironment: Rc from RtlQueryRegistryValues = %lx\n", Status));
+ }
+#endif
+ break;
+ }
+
+ } while (SomeDeleted);
+
+ //
+ // ignore errors when wiping out environment
+ //
+}
+
+
+VOID
+Os2UpdateRegistryDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to process the contents of the os2conf.nt file. SET variables are entered
+ into the system environment. Most other directives are entered in the registry config.sys value.
+ PATH and LIBPATH are recorded so they can later be processed and entered into the environment.
+
+ (actually, LIBPATH is processed directly by Or2FillInSearchRecordDispatchFunction)
+
+Arguments:
+
+ Standard arguments passed to a Dispatch Function, see the description of
+ Or2IterateEnvironment in ssrtl\consys.c
+
+ UserParameter - a pointer to an array Params of ULONGs containing the following info:
+
+ Params[0] : (PWSTR *) BufferPtr -- a pointer to the buffer for filling in the new config.sys key
+ Params[1] : (HANDLE) EnvironmentKeyHandle -- a handle with WRITE access to the sys env
+ Params[2] : (PENVIRONMENT_SEARCH_RECORD) PRec -- a search record for filling info about PATH statement
+ Params[3] : (BOOLEAN) RetVal -- will receive the final success status of the operation
+ (should be preinitialized to TRUE)
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PULONG UP = (PULONG) UserParameter;
+ PWSTR *BufferPtr;
+ PWSTR NewV; // for preparing new subvalue of "SET PATH="
+ HANDLE EnvironmentKeyHandle;
+ PVOID PRec;
+ UNICODE_STRING Name_U;
+ NTSTATUS Status;
+ WCHAR wch;
+
+ switch (DispatchTableIndex) {
+
+ case 1:
+
+ //
+ // process SET
+ //
+
+ if (Or2UnicodeEqualCI(Value, L"LIBPATH=", 8) || // ignore "SET LIBPATH="
+ Or2UnicodeEqualCI(Value, L"OS2LIBPATH=", 11)) { // and "SET OS2LIBPATH="
+ break;
+ }
+
+ if (Or2UnicodeEqualCI(Value, L"PATH=", 5)) { // special handling of path
+
+ PRec = (PVOID) (UP[2]);
+
+ NewV = Value + 5; // skip over "PATH="
+ ValueLen -= 5;
+
+ //
+ // skip over whitespace
+ //
+
+ while (ValueLen > 0 && (*NewV == L' ' || *NewV == L'\t')) {
+ NewV++;
+ ValueLen--;
+ }
+
+ Or2FillInSearchRecordDispatchFunction(DispatchTableIndex,
+ PRec,
+ Value,
+ 4, // length of "PATH"
+ NewV,
+ ValueLen
+ );
+ break;
+ }
+
+ if (Or2UnicodeEqualCI(Value, L"COMSPEC=", 8)) {
+
+ //
+ // these special variables should be copied to config.sys
+ // instead of the system environment
+ //
+
+ BufferPtr = (PWSTR *) (UP[0]);
+ RtlMoveMemory(*BufferPtr, L"SET ", 8);
+ *BufferPtr += 4;
+ RtlMoveMemory(*BufferPtr, Value, ValueLen * sizeof(WCHAR));
+ *BufferPtr += ValueLen;
+ **BufferPtr = UNICODE_NULL;
+ (*BufferPtr)++;
+ break;
+ }
+
+ //
+ // The rest of the variables are just put into the sys env as they are
+ //
+
+ Name_U.Buffer = Value;
+ Name_U.Length = 0;
+
+ while (ValueLen > 0 &&
+ *Value != L'=')
+ {
+ Value++;
+ ValueLen--;
+ Name_U.Length += sizeof(WCHAR);
+ }
+
+ if (Name_U.Length == 0 || // empty name
+ ValueLen == 0) { // no "=" in string
+ break;
+ }
+
+ Name_U.MaximumLength = Name_U.Length;
+
+ // Here, we have a valid name, followed by '='
+ Value++; // Skip the '='
+ ValueLen--;
+
+ wch = Value[ValueLen];
+ Value[ValueLen] = UNICODE_NULL;
+
+ //
+ // Set the system wide variable to the value specified
+ // in the config.sys by the OS/2 program
+ //
+
+ EnvironmentKeyHandle = (HANDLE) (UP[1]);
+
+ Status = NtSetValueKey(EnvironmentKeyHandle,
+ &Name_U,
+ (ULONG)0,
+ REG_EXPAND_SZ,
+ Value,
+ (ValueLen + 1) * sizeof(WCHAR)
+ );
+
+ Value[ValueLen] = wch;
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2UpdateRegistryDispatchFunction: Unable to NtSetValueKey() system env from config.sys, Status = %X\n", Status));
+ }
+#endif
+ UP[3] = (ULONG) FALSE;
+ break;
+ }
+
+ break;
+
+ case 2:
+
+ //
+ // process everything else -- copy it to buffer
+ //
+
+ BufferPtr = (PWSTR *) (UP[0]);
+ RtlMoveMemory(*BufferPtr, Value, ValueLen * sizeof(WCHAR));
+ *BufferPtr += ValueLen;
+ **BufferPtr = UNICODE_NULL;
+ (*BufferPtr)++;
+ break;
+ }
+}
+
+
+BOOLEAN
+Os2UpdateRegistryFromSource(
+ IN OUT PWSTR *BufferPtr,
+ IN HANDLE EnvironmentKeyHandle,
+ IN PUNICODE_STRING ConfigSysSrc
+ )
+
+/*++
+
+Routine Description:
+
+ This routine prepares the new config.sys entry, and enters new system environment variables
+ from the os2conf.nt file source.
+
+Arguments:
+
+ BufferPtr -- a pointer into the new config.sys buffer where the stuff is to be appended.
+ EnvironmentKeyHandle -- a handle to the sys env for setting new vars.
+ ConfigSysSrc -- a counted unicode string containing the os2conf.nt source.
+
+Return Value:
+
+ TRUE on success, FALSE on failure.
+
+--*/
+
+{
+ //
+ // Most of the work is done by the dispatch routine above.
+ //
+
+ static ENVIRONMENT_DISPATCH_TABLE_ENTRY DispatchTable[] =
+ {
+ { L"LIBPATH", L"=", Or2FillInSearchRecordDispatchFunction, NULL },
+ { L"SET", L" \t", Os2UpdateRegistryDispatchFunction, NULL },
+ { L"*", NULL, Os2UpdateRegistryDispatchFunction, NULL },
+ };
+
+ ENVIRONMENT_SEARCH_RECORD LPRec;
+ ENVIRONMENT_SEARCH_RECORD PRec;
+ UNICODE_STRING LPData;
+ UNICODE_STRING PData;
+ UNICODE_STRING LPathValueName_U;
+ UNICODE_STRING PathValueName_U;
+ ULONG i;
+ ULONG Params[4];
+ NTSTATUS Status;
+ WCHAR ch;
+
+ Params[0] = (ULONG) BufferPtr;
+ Params[1] = (ULONG) EnvironmentKeyHandle;
+ Params[2] = (ULONG) &PRec;
+ Params[3] = (ULONG) TRUE;
+
+ DispatchTable[0].UserParameter = (PVOID)&LPRec;
+ LPRec.DispatchTableIndex = (ULONG)-1;
+ PRec.DispatchTableIndex = (ULONG)-1;
+
+ for (i = 1; i < 3; i++) {
+ DispatchTable[i].UserParameter = (PVOID) Params;
+ }
+
+ Or2IterateEnvironment(ConfigSysSrc->Buffer,
+ DispatchTable,
+ 3,
+ CRLF_DELIM);
+
+ //
+ // add the terminating null
+ //
+
+ **BufferPtr = UNICODE_NULL;
+ (*BufferPtr)++;
+
+ //
+ // process LIBPATH and PATH
+ //
+
+ if (LPRec.DispatchTableIndex != (ULONG)-1) {
+
+ // handle LIBPATH if there was one
+
+ if (Or2GetEnvPath(&LPData,
+ Os2Heap,
+ PATHLIST_MAX,
+ EnvironmentKeyHandle,
+ Os2LibPathValueName,
+ FALSE)) {
+
+ ch = LPRec.Value[LPRec.ValueLen];
+ LPRec.Value[LPRec.ValueLen] = UNICODE_NULL;
+
+ Or2ReplacePathByPath(Os2Heap, LPRec.Value, &LPData);
+
+ LPRec.Value[LPRec.ValueLen] = ch;
+
+ Or2CheckSemicolon(&LPData);
+
+ RtlInitUnicodeString(&LPathValueName_U, Os2LibPathValueName);
+ Status = NtSetValueKey(EnvironmentKeyHandle,
+ &LPathValueName_U,
+ (ULONG)0,
+ REG_EXPAND_SZ,
+ LPData.Buffer,
+ LPData.Length + sizeof(WCHAR)
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2UpdateRegistryFromSource: Unable to NtSetValueKey() Environment Os2LibPath, Status = %X\n", Status));
+ }
+#endif
+ Params[3] = (ULONG) FALSE;
+ }
+
+ RtlFreeHeap(Os2Heap, 0, LPData.Buffer);
+ } else {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2UpdateRegistryFromSource: Unable to get system Os2LibPath, skipping\n"));
+ }
+#endif
+ Params[3] = (ULONG) FALSE;
+ }
+ }
+
+ if (PRec.DispatchTableIndex != (ULONG)-1) {
+
+ // handle PATH if there was one
+
+ if (Or2GetEnvPath(&PData,
+ Os2Heap,
+ PATHLIST_MAX,
+ EnvironmentKeyHandle,
+ PathValueName,
+ FALSE)) {
+
+ ch = PRec.Value[PRec.ValueLen];
+ PRec.Value[PRec.ValueLen] = UNICODE_NULL;
+
+ Or2ReplacePathByPath(Os2Heap, PRec.Value, &PData);
+
+ PRec.Value[PRec.ValueLen] = ch;
+
+ Or2CheckSemicolon(&PData);
+
+ RtlInitUnicodeString(&PathValueName_U, PathValueName);
+ Status = NtSetValueKey(EnvironmentKeyHandle,
+ &PathValueName_U,
+ (ULONG)0,
+ REG_EXPAND_SZ,
+ PData.Buffer,
+ PData.Length + sizeof(WCHAR)
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2UpdateRegistryFromSource: Unable to NtSetValueKey() Environment Path, Status = %X\n", Status));
+ }
+#endif
+ Params[3] = (ULONG) FALSE;
+ }
+
+ RtlFreeHeap(Os2Heap, 0, PData.Buffer);
+ } else {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2UpdateRegistryFromSource: Unable to get system Path, skipping\n"));
+ }
+#endif
+ Params[3] = (ULONG) FALSE;
+ }
+ }
+
+ return((BOOLEAN)Params[3]);
+}
+
+
+BOOLEAN
+Os2UpdateRegistryAll(
+ IN PUNICODE_STRING Src
+ )
+
+/*++
+
+Routine Description:
+
+ This routine actually updates the registry after initial preparation by
+ Os2UpdateRegistryFromConfigSys.
+
+Arguments:
+
+ Src -- supplies a counted unicode string that contains the contents of os2conf.nt
+ The registry is updated with these contents.
+
+Return Value:
+
+ TRUE on success. FALSE on failure (in which case the registry was either not updated at
+ all or partially updated).
+
+--*/
+
+{
+ PWSTR NewConfigSys;
+ PWSTR NewConfigSysPtr;
+ HANDLE ConfigSysKeyHandle;
+ HANDLE EnvironmentKeyHandle;
+ UNICODE_STRING EnvironmentRegDir_U;
+ UNICODE_STRING ConfigSysKeyName_U;
+ UNICODE_STRING ConfigSysValueName_U;
+ UNICODE_STRING ConfigSysValueData_U;
+ OBJECT_ATTRIBUTES Obja;
+ NTSTATUS Status;
+ ULONG ResultLength;
+ KEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
+ PKEY_VALUE_PARTIAL_INFORMATION pConfigSysOldValue;
+
+ //
+ // Allocate a buffer for building a new config.sys key
+ //
+
+ NewConfigSys = (PWSTR) RtlAllocateHeap(Os2Heap, 0, MAX_CONSYS_SIZE);
+
+ if (NewConfigSys == NULL) {
+#if DBG
+ IF_OS2_DEBUG( MISC ) {
+ KdPrint(("Os2UpdateRegistryAll: Unable to allocate space for new config.sys entry\n"));
+ }
+#endif
+ return(FALSE);
+ }
+
+ //
+ // Read in the old config.sys registry entry
+ //
+
+ RtlInitUnicodeString(&ConfigSysKeyName_U, Os2ConfigSysKeyName);
+ InitializeObjectAttributes(&Obja,
+ &ConfigSysKeyName_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&ConfigSysKeyHandle,
+ KEY_READ | KEY_WRITE,
+ &Obja
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC){
+ KdPrint(("Os2UpdateRegistryAll: Unable to NtOpenKey() of config.sys %lx\n",
+ Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, NewConfigSys);
+ return(FALSE);
+ }
+
+ RtlInitUnicodeString(&ConfigSysValueName_U, Os2ConfigSysName);
+ Status = NtQueryValueKey(ConfigSysKeyHandle,
+ &ConfigSysValueName_U,
+ KeyValuePartialInformation,
+ &KeyValuePartialInfo,
+ sizeof(KeyValuePartialInfo),
+ &ResultLength
+ );
+
+ if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_OVERFLOW)) {
+#if DBG
+ IF_OS2_DEBUG(MISC){
+ KdPrint(("Os2UpdateRegistryAll: Unable to NtQueryValueKey()-1 config.sys %lx\n",
+ Status));
+ }
+#endif
+ NtClose(ConfigSysKeyHandle);
+ RtlFreeHeap(Os2Heap, 0, NewConfigSys);
+ return(FALSE);
+ }
+
+ pConfigSysOldValue = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(Os2Heap, 0, ResultLength);
+ if (pConfigSysOldValue == NULL) {
+#if DBG
+ IF_OS2_DEBUG(MISC){
+ KdPrint(("Os2UpdateRegistryAll: Unable to RtlAllocateHeap space for old config.sys entry\n"));
+ }
+#endif
+ NtClose(ConfigSysKeyHandle);
+ RtlFreeHeap(Os2Heap, 0, NewConfigSys);
+ return(FALSE);
+ }
+
+ Status = NtQueryValueKey(ConfigSysKeyHandle,
+ &ConfigSysValueName_U,
+ KeyValuePartialInformation,
+ pConfigSysOldValue,
+ ResultLength,
+ &ResultLength
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG(MISC){
+ KdPrint(("Os2UpdateRegistryAll: Unable to NtQueryValueKey()-2 config.sys %lx\n",
+ Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, pConfigSysOldValue);
+ NtClose(ConfigSysKeyHandle);
+ RtlFreeHeap(Os2Heap, 0, NewConfigSys);
+ return(FALSE);
+ }
+
+ ConfigSysValueData_U.Buffer = (PWSTR) pConfigSysOldValue->Data;
+ ConfigSysValueData_U.MaximumLength = ConfigSysValueData_U.Length = (USHORT) pConfigSysOldValue->DataLength;
+
+ //
+ // Now open the system environment
+ //
+
+ RtlInitUnicodeString(&EnvironmentRegDir_U, Os2EnvironmentDirectory);
+ InitializeObjectAttributes(&Obja,
+ &EnvironmentRegDir_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&EnvironmentKeyHandle,
+ KEY_READ | KEY_WRITE,
+ &Obja
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( MISC ) {
+ KdPrint(("Os2UpdateRegistryAll: Unable to NtOpenKey() System Environment, Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, pConfigSysOldValue);
+ NtClose(ConfigSysKeyHandle);
+ RtlFreeHeap(Os2Heap, 0, NewConfigSys);
+ return(FALSE);
+ }
+
+ //
+ // Now Proprocess the existing config.sys
+ //
+
+ NewConfigSysPtr = NewConfigSys;
+
+ Os2PreProcessExistingConfigSys(&NewConfigSysPtr, &ConfigSysValueData_U);
+
+ RtlFreeHeap(Os2Heap, 0, pConfigSysOldValue);
+
+ //
+ // Now wipe out old environment.
+ //
+
+ Os2WipeOutEnvironment(EnvironmentKeyHandle);
+
+ //
+ // Now go through the source text, updating the environment
+ // and config.sys registry value with the contents
+ //
+
+ if (!Os2UpdateRegistryFromSource(&NewConfigSysPtr, EnvironmentKeyHandle, Src)) {
+#if DBG
+ IF_OS2_DEBUG( MISC ) {
+ KdPrint(("Os2UpdateRegistryAll: FAILED to Os2UpdateRegistryFromSource\n"));
+ }
+#endif
+ NtClose(EnvironmentKeyHandle);
+ NtClose(ConfigSysKeyHandle);
+ RtlFreeHeap(Os2Heap, 0, NewConfigSys);
+ return(FALSE);
+ }
+
+ //
+ // finished with the environment
+ //
+
+ NtClose(EnvironmentKeyHandle);
+
+ //
+ // write the new config.sys entry.
+ //
+
+ Status = NtSetValueKey(ConfigSysKeyHandle,
+ &ConfigSysValueName_U,
+ (ULONG)0,
+ REG_MULTI_SZ,
+ NewConfigSys,
+ (PSZ)NewConfigSysPtr - (PSZ)NewConfigSys
+ );
+
+ NtClose(ConfigSysKeyHandle);
+ RtlFreeHeap(Os2Heap, 0, NewConfigSys);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( MISC ) {
+ KdPrint(("Os2UpdateRegistryAll: Unable to write new config.sys key value, Status = %lx\n", Status));
+ }
+#endif
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+
+NTSTATUS
+Os2MarkFileForDeletion(
+ IN HANDLE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine marks an open file for deletion. It makes sure the file is not R/O before
+ doing so. The file must have been opened with FILE_WRITE_ATTRIBUTES and DELETE access
+ permissions.
+
+Arguments:
+
+ FileHandle -- supplies the file to process
+
+Return Value:
+
+ NT Error Code.
+
+--*/
+
+{
+ IO_STATUS_BLOCK IoStatus;
+ FILE_DISPOSITION_INFORMATION FileDispositionInfo;
+ FILE_BASIC_INFORMATION FileBasicInfo;
+ NTSTATUS Status;
+
+ //
+ // make sure file is not readonly
+ //
+
+ Status = NtQueryInformationFile(FileHandle,
+ &IoStatus,
+ &FileBasicInfo,
+ sizeof(FileBasicInfo),
+ FileBasicInformation
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Os2MarkFileForDeletion: Rc from NtQueryInformationFile(Attrib) %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+
+ if ((FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_READONLY) != 0) {
+
+ FileBasicInfo.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
+
+ Status = NtSetInformationFile(FileHandle,
+ &IoStatus,
+ &FileBasicInfo,
+ sizeof(FileBasicInfo),
+ FileBasicInformation
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Os2MarkFileForDeletion: Rc from NtSetInformationFile(Attrib) %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+ }
+
+ //
+ // mark the file for deletion
+ //
+
+ FileDispositionInfo.DeleteFile = TRUE;
+ Status = NtSetInformationFile(FileHandle,
+ &IoStatus,
+ &FileDispositionInfo,
+ sizeof(FileDispositionInfo),
+ FileDispositionInformation
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Os2MarkFileForDeletion: Rc from NtSetInformationFile(Delete) %lx\n", Status));
+ }
+#endif
+ }
+
+ return(Status);
+}
+
+
+VOID
+Os2UpdateRegistryFromConfigSys(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes the os2conf.nt file and updates the information in the registry. It is
+ called every time a client that opened os2conf.nt terminates. It also updates the usage
+ count. If the usage count is zero, os2conf.nt is deleted.
+
+ Upon errors, the usage counted is updated, but the registry may not be updated.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ HANDLE ConfigSysFileHandle;
+ UNICODE_STRING CanonicalConfigDotSys_U;
+ LARGE_INTEGER NewConfigSysTimeStamp;
+ LARGE_INTEGER NewConfigSysSizeStamp;
+ ULONG SizeOfConfigSys;
+ OBJECT_ATTRIBUTES Obja;
+ PSZ pInfo;
+ ANSI_STRING Info_A;
+ UNICODE_STRING Info_U;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ BOOLEAN DeleteFlag = FALSE;
+ APIRET RetCode;
+
+ //
+ // update usage count
+ //
+
+ if (Os2ConfigSysUsageCount == 0) {
+ return;
+ }
+
+ Os2ConfigSysUsageCount--;
+
+ if (Os2ConfigSysAllowedAccess == OPEN_ACCESS_READONLY &&
+ Os2ConfigSysUsageCount > 0) {
+ return;
+ }
+
+ RtlInitUnicodeString(&CanonicalConfigDotSys_U, Os2CanonicalConfigDotSys);
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalConfigDotSys_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(&ConfigSysFileHandle,
+ FILE_GENERIC_READ |
+ ( Os2ConfigSysUsageCount == 0 ? (FILE_WRITE_ATTRIBUTES | DELETE) : 0 ),
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_VALID_FLAGS,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Os2UpdateRegistryFromConfigSys: FAILED - NtOpenFile-1 %lx\n", Status));
+ }
+#endif
+
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND || Os2ConfigSysUsageCount > 0) {
+
+ //
+ // can't update the registry, abandon
+ //
+
+ return;
+ }
+
+ Status = NtOpenFile(&ConfigSysFileHandle,
+ FILE_GENERIC_READ,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_VALID_FLAGS,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Os2UpdateRegistryFromConfigSys: FAILED - NtOpenFile-2 %lx\n", Status));
+ }
+#endif
+ //
+ // can't update the registry, abandon
+ //
+
+ return;
+ }
+ } else if (Os2ConfigSysUsageCount == 0) {
+ DeleteFlag = TRUE; // flag file for deletion
+ }
+
+ //
+ // If our access is READONLY, we mark the file for deletion,
+ // close it, and quit.
+ //
+
+ if (Os2ConfigSysAllowedAccess == OPEN_ACCESS_READONLY) {
+
+ if (DeleteFlag) {
+ (VOID) Os2MarkFileForDeletion(ConfigSysFileHandle);
+
+ //
+ // ignore deletion errors
+ //
+ }
+
+ NtClose(ConfigSysFileHandle);
+ return;
+ }
+
+ Status = Os2GetFileStamps(ConfigSysFileHandle, &NewConfigSysTimeStamp, &NewConfigSysSizeStamp);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Os2UpdateRegistryFromConfigSys: failed to query config.sys size and time %lx\n", Status));
+ }
+#endif
+ //
+ // we cancel the update operation. however, we still mark the
+ // file for deletion if necessary.
+ //
+
+ if (DeleteFlag) {
+ (VOID) Os2MarkFileForDeletion(ConfigSysFileHandle);
+
+ //
+ // ignore deletion errors
+ //
+ }
+
+ NtClose(ConfigSysFileHandle);
+ return;
+ }
+
+ //
+ // Now find out if we need to update the registry.
+ // We update in all except the following cases:
+ // 1 - os2conf.nt doesn't exist (handled above)
+ // 2 - os2conf.nt has zero length
+ // 3 - the file time and size have not changed since last update
+ //
+
+ if ((NewConfigSysSizeStamp.HighPart == 0 &&
+ NewConfigSysSizeStamp.LowPart == 0) ||
+ (NewConfigSysTimeStamp.HighPart == Os2ConfigSysTimeStamp.HighPart &&
+ NewConfigSysTimeStamp.LowPart == Os2ConfigSysTimeStamp.LowPart &&
+ NewConfigSysSizeStamp.HighPart == Os2ConfigSysSizeStamp.HighPart &&
+ NewConfigSysSizeStamp.LowPart == Os2ConfigSysSizeStamp.LowPart)) {
+
+ if (DeleteFlag) {
+ (VOID) Os2MarkFileForDeletion(ConfigSysFileHandle);
+
+ //
+ // ignore deletion errors
+ //
+ }
+ NtClose(ConfigSysFileHandle);
+ return;
+ }
+
+ //
+ // Now comes the code that actually updates the registry
+ //
+
+ SizeOfConfigSys = NewConfigSysSizeStamp.LowPart;
+ // the + 1 in following parameter is for inserting the NUL character
+ pInfo = (PSZ)RtlAllocateHeap(Os2Heap, 0, SizeOfConfigSys + 1);
+ if (pInfo == NULL) {
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Os2UpdateRegistryFromConfigSys: failed RtlAllocateHeap for os2conf.nt content\n"));
+ }
+#endif
+ if (DeleteFlag) {
+ (VOID) Os2MarkFileForDeletion(ConfigSysFileHandle);
+
+ //
+ // ignore deletion errors
+ //
+ }
+ NtClose(ConfigSysFileHandle);
+ return;
+ }
+ Status = NtReadFile(ConfigSysFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ (PVOID)pInfo,
+ SizeOfConfigSys,
+ NULL,
+ NULL
+ );
+
+ if (DeleteFlag) {
+ (VOID) Os2MarkFileForDeletion(ConfigSysFileHandle);
+
+ //
+ // ignore deletion errors
+ //
+ }
+ NtClose(ConfigSysFileHandle);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Os2UpdateRegistryFromConfigSys: FAILED - NtReadFile %lx\n",
+ Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, pInfo);
+ return;
+ }
+
+ pInfo[SizeOfConfigSys] = '\0';
+
+ Or2InitMBString(&Info_A, pInfo);
+
+ RetCode = Or2MBStringToUnicodeString(&Info_U,
+ &Info_A,
+ TRUE);
+
+ RtlFreeHeap(Os2Heap, 0, pInfo);
+
+ if (RetCode != NO_ERROR) {
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Os2UpdateRegistryFromConfigSys: no memory for Unicode Conversion\n"));
+ }
+#endif
+ return;
+ }
+
+ if (!Os2UpdateRegistryAll(&Info_U)) {
+#if DBG
+ IF_OD2_DEBUG( MISC ) {
+ KdPrint(("Os2UpdateRegistryFromConfigSys: Os2UpdateRegistryAll FAILED\n"));
+ }
+#endif
+ }
+
+ RtlFreeUnicodeString(&Info_U);
+}
+
diff --git a/private/os2/server/srvdebug.c b/private/os2/server/srvdebug.c
new file mode 100644
index 000000000..87152f2d9
--- /dev/null
+++ b/private/os2/server/srvdebug.c
@@ -0,0 +1,717 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvdebug.c
+
+Abstract:
+
+ This module contains debugging routines for the OS/2 Subsystem
+ Server
+
+Author:
+
+ Steve Wood (stevewo) 20-Sep-1989
+
+Revision History:
+
+--*/
+
+#include "os2srv.h"
+#include "ntdbg.h"
+#include "ntrtl.h"
+
+VOID
+Os2OpenLdrEntry(
+ IN POS2_PROCESS Process,
+ IN PLDR_DATA_TABLE_ENTRY LdrEntry,
+ OUT PHANDLE FileHandle
+ );
+
+VOID
+Os2ComputeImageInformation(
+ IN POS2_PROCESS Process,
+ IN PLDR_DATA_TABLE_ENTRY LdrEntry,
+ OUT PVOID *BaseOfImage,
+ OUT PULONG DebugInfoFileOffset,
+ OUT PULONG DebugInfoSize
+ );
+
+PIMAGE_DEBUG_DIRECTORY
+Os2LocateDebugSection(
+ IN HANDLE ProcessHandle,
+ IN PVOID Base
+ );
+
+VOID
+Os2AttachProcessAndThread(
+ IN POS2_PROCESS Process,
+ IN POS2_THREAD Thread,
+ IN HANDLE ReplyEvent);
+
+NTSTATUS
+Os2UiLookup(PCLIENT_ID AppClientId,
+ PCLIENT_ID DebugUiClientId)
+
+{
+
+ UNREFERENCED_PARAMETER(AppClientId);
+
+ if (Os2DebugUserClientId.UniqueProcess != NULL) {
+ *DebugUiClientId = Os2DebugUserClientId;
+
+ return(STATUS_SUCCESS);
+ }
+ else {
+ return(STATUS_UNSUCCESSFUL);
+ }
+}
+
+
+NTSTATUS
+Os2DebugThread(
+ IN HANDLE hThread,
+ IN HANDLE ReplyEvent)
+{
+
+ NTSTATUS Status;
+ DBGKM_APIMSG m;
+ PDBGKM_CREATE_THREAD CreateThreadArgs;
+ THREAD_BASIC_INFORMATION ThreadInfo;
+
+
+ Status = NtQueryInformationThread(
+ hThread,
+ ThreadBasicInformation,
+ (PVOID)(&ThreadInfo),
+ sizeof(ThreadInfo),
+ NULL);
+ ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2DebugThread failed: NtQueryThreadInformation Status == %X\n",
+ Status
+ );
+#endif // DBG
+ return(Status);
+ }
+
+
+ //
+ // Send the CreateThread Message
+ //
+
+ CreateThreadArgs = &m.u.CreateThread;
+ CreateThreadArgs->SubSystemKey = 0;
+ CreateThreadArgs->StartAddress = NULL;
+
+ DBGKM_FORMAT_API_MSG(m, DbgKmCreateThreadApi,sizeof(*CreateThreadArgs));
+
+
+ m.h.ClientId = ThreadInfo.ClientId;
+
+ DbgSsHandleKmApiMsg(&m,ReplyEvent);
+ Status = NtWaitForSingleObject(ReplyEvent,FALSE,NULL);
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2DebugThread failed: NtWaitForSingleObject Status == %X\n",
+ Status
+ );
+#endif // DBG
+ }
+ return Status;
+}
+
+NTSTATUS
+Os2DebugProcess(
+ IN PCLIENT_ID DebugUserInterface,
+ IN POS2_THREAD Thread,
+ IN HANDLE ReplyEvent)
+{
+ POS2_PROCESS Process = Thread->Process;
+ NTSTATUS Status;
+
+ //
+ // Process is being debugged, so set up debug port
+ //
+
+ Status = NtSetInformationProcess(
+ Process->ProcessHandle,
+ ProcessDebugPort,
+ (PVOID)(&Os2DebugPort),
+ sizeof(HANDLE)
+ );
+// ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2DebugProcess failed to assign debug port: NtSetProcessInformation Status == %X\n",
+ Status
+ );
+#endif // DBG
+ return(Status);
+ }
+ if (Os2DebugUserClientId.UniqueProcess != NULL) {
+ //
+ // OS/2 Server is run under ntsd -doz
+ //
+ Os2AttachProcessAndThread(Process, Thread, ReplyEvent);
+ return STATUS_SUCCESS;
+
+ }
+
+ return STATUS_UNSUCCESSFUL;
+
+}
+
+
+VOID
+Os2AttachProcessAndThread(
+ IN POS2_PROCESS Process,
+ IN POS2_THREAD Thread,
+ IN HANDLE ReplyEvent)
+
+/*++
+
+Routine Description:
+
+ This procedure sends the create process and create thread
+ debug events to the debug subsystem.
+
+Arguments:
+
+ Process - Supplies the address of the process being debugged.
+
+ Tread - Supplies the address of the Thread being debugged.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PPEB Peb;
+ NTSTATUS Status;
+ PROCESS_BASIC_INFORMATION BasicInfo;
+ PLDR_DATA_TABLE_ENTRY LdrEntry;
+ LDR_DATA_TABLE_ENTRY LdrEntryData;
+ PLIST_ENTRY LdrHead,LdrNext;
+ PPEB_LDR_DATA Ldr;
+ DBGKM_APIMSG m;
+ PDBGKM_CREATE_THREAD CreateThreadArgs;
+ PDBGKM_CREATE_PROCESS CreateProcessArgs;
+ PDBGKM_LOAD_DLL LoadDllArgs;
+ PVOID ImageBaseAddress;
+
+ Status = NtQueryInformationProcess(
+ Process->ProcessHandle,
+ ProcessBasicInformation,
+ &BasicInfo,
+ sizeof(BasicInfo),
+ NULL
+ );
+ ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2AttachProcessAndThread failed: NtQueryProcessInformation Status == %X\n",
+ Status
+ );
+#endif // DBG
+ }
+
+ Peb = BasicInfo.PebBaseAddress;
+
+ //
+ // Ldr = Peb->Ldr
+ //
+
+ Status = NtReadVirtualMemory(
+ Process->ProcessHandle,
+ &Peb->Ldr,
+ &Ldr,
+ sizeof(Ldr),
+ NULL
+ );
+ ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2AttachProcessAndThread failed: NtReadVirtualMemory Status == %X\n",
+ Status
+ );
+#endif // DBG
+ }
+
+ LdrHead = &Ldr->InLoadOrderModuleList;
+
+ //
+ // LdrNext = Head->Flink;
+ //
+
+ Status = NtReadVirtualMemory(
+ Process->ProcessHandle,
+ &LdrHead->Flink,
+ &LdrNext,
+ sizeof(LdrNext),
+ NULL
+ );
+ ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2AttachProcessAndThread failed: NtReadVirtualMemory Status == %X\n",
+ Status
+ );
+#endif // DBG
+ }
+
+ if ( LdrNext != LdrHead ) {
+
+ //
+ // This is the entry data for the image.
+ //
+
+ LdrEntry = CONTAINING_RECORD(LdrNext,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);
+ Status = NtReadVirtualMemory(
+ Process->ProcessHandle,
+ LdrEntry,
+ &LdrEntryData,
+ sizeof(LdrEntryData),
+ NULL
+ );
+ ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2AttachProcessAndThread failed: NtReadVirtualMemory Status == %X\n",
+ Status
+ );
+#endif // DBG
+ }
+ Status = NtReadVirtualMemory(
+ Process->ProcessHandle,
+ &Peb->ImageBaseAddress,
+ &ImageBaseAddress,
+ sizeof(ImageBaseAddress),
+ NULL
+ );
+ ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2AttachProcessAndThread failed: NtReadVirtualMemory Status == %X\n",
+ Status
+ );
+#endif // DBG
+ }
+ ASSERT(ImageBaseAddress == LdrEntryData.DllBase);
+
+ LdrNext = LdrEntryData.InLoadOrderLinks.Flink;
+
+ }
+ else {
+ LdrEntry = NULL;
+ }
+
+
+ //
+ // Send the CreateProcess Message
+ //
+
+ CreateThreadArgs = &m.u.CreateProcessInfo.InitialThread;
+ CreateThreadArgs->SubSystemKey = 0;
+
+ CreateProcessArgs = &m.u.CreateProcessInfo;
+ CreateProcessArgs->SubSystemKey = 0;
+
+ Os2ComputeImageInformation(
+ Process,
+ &LdrEntryData,
+ &CreateProcessArgs->BaseOfImage,
+ &CreateProcessArgs->DebugInfoFileOffset,
+ &CreateProcessArgs->DebugInfoSize
+ );
+
+ Os2OpenLdrEntry(
+ Process,
+ &LdrEntryData,
+ &CreateProcessArgs->FileHandle
+ );
+
+ CreateThreadArgs->StartAddress = NULL;
+
+ DBGKM_FORMAT_API_MSG(m,DbgKmCreateProcessApi,sizeof(*CreateProcessArgs));
+
+ m.h.ClientId = Thread->ClientId;
+ DbgSsHandleKmApiMsg(&m,ReplyEvent);
+ Status = NtWaitForSingleObject(ReplyEvent,FALSE,NULL);
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2AttachProcessAndThread failed: NtWaitForSingleObject Status == %X\n",
+ Status
+ );
+#endif // DBG
+ }
+
+ //
+ // Send all of the load module messages
+ //
+
+ while ( LdrNext != LdrHead ) {
+ LdrEntry = CONTAINING_RECORD(LdrNext,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);
+ Status = NtReadVirtualMemory(
+ Process->ProcessHandle,
+ LdrEntry,
+ &LdrEntryData,
+ sizeof(LdrEntryData),
+ NULL
+ );
+ ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2AttachProcessAndThread failed: NtReadVirtualMemory Status == %X\n",
+ Status
+ );
+#endif // DBG
+ }
+
+ LoadDllArgs = &m.u.LoadDll;
+
+ Os2ComputeImageInformation(
+ Process,
+ &LdrEntryData,
+ &LoadDllArgs->BaseOfDll,
+ &LoadDllArgs->DebugInfoFileOffset,
+ &LoadDllArgs->DebugInfoSize
+ );
+
+ Os2OpenLdrEntry(
+ Process,
+ &LdrEntryData,
+ &LoadDllArgs->FileHandle
+ );
+ if ( LoadDllArgs->FileHandle ) {
+ DBGKM_FORMAT_API_MSG(m,DbgKmLoadDllApi,sizeof(*LoadDllArgs));
+ m.h.ClientId = Thread->ClientId;
+ DbgSsHandleKmApiMsg(&m, ReplyEvent);
+ Status = NtWaitForSingleObject(ReplyEvent,FALSE,NULL);
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2AttachProcessAndThread failed: NtWaitForSingleObject Status == %X\n",
+ Status
+ );
+#endif // DBG
+ }
+ }
+
+ LdrNext = LdrEntryData.InLoadOrderLinks.Flink;
+ }
+}
+
+VOID
+Os2ComputeImageInformation(
+ IN POS2_PROCESS Process,
+ IN PLDR_DATA_TABLE_ENTRY LdrEntry,
+ OUT PVOID *BaseOfImage,
+ OUT PULONG DebugInfoFileOffset,
+ OUT PULONG DebugInfoSize
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called to compute the image base and
+ debug information from a ldr entry.
+
+Arguments:
+
+ Process - Supplies the address of the process whose context this
+ information is to be calculated from.
+
+ LdrEntry - Supplies the address of the loader data table entry
+ whose info is being computed relative to. This pointer is
+ valid in the callers (current) context.
+
+ BaseOfImage - Returns the image's base.
+
+ DebugInfoFileOffset - Returns the offset of the debug info.
+
+ DebugInfoSize - Returns the size of the debug info.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIMAGE_DEBUG_DIRECTORY pDebugDir;
+ IMAGE_DEBUG_DIRECTORY DebugDir;
+ IMAGE_COFF_SYMBOLS_HEADER DebugInfo;
+ NTSTATUS Status;
+
+ *BaseOfImage = LdrEntry->DllBase;
+
+ pDebugDir = Os2LocateDebugSection(
+ Process->ProcessHandle,
+ LdrEntry->DllBase
+ );
+
+ if ( pDebugDir ) {
+
+ Status = NtReadVirtualMemory(
+ Process->ProcessHandle,
+ pDebugDir,
+ &DebugDir,
+ sizeof(IMAGE_DEBUG_DIRECTORY),
+ NULL
+ );
+
+ ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2ComputeImageInformation failed: NtReadVirtualMemory Status == %X\n",
+ Status
+ );
+#endif // DBG
+ }
+
+ Status = NtReadVirtualMemory(
+ Process->ProcessHandle,
+ (PVOID)((ULONG)LdrEntry->DllBase + DebugDir.AddressOfRawData),
+ &DebugInfo,
+ sizeof(DebugInfo),
+ NULL
+ );
+ ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2ComputeImageInformation failed: NtReadVirtualMemory Status == %X\n",
+ Status
+ );
+#endif // DBG
+ }
+
+ *DebugInfoFileOffset = DebugDir.PointerToRawData + DebugInfo.LvaToFirstSymbol;
+ *DebugInfoSize = DebugInfo.NumberOfSymbols;
+ }
+ else {
+ *DebugInfoFileOffset = 0;
+ *DebugInfoSize = 0;
+ }
+}
+
+PIMAGE_DEBUG_DIRECTORY
+Os2LocateDebugSection(
+ IN HANDLE ProcessHandle,
+ IN PVOID Base
+ )
+
+{
+ PVOID ImageHeaderRawData;
+ PIMAGE_DOS_HEADER DosHeaderRawData;
+ PIMAGE_NT_HEADERS NtHeaders;
+ ULONG AllocSize, Addr;
+ NTSTATUS Status;
+
+ //
+ // Allocate a buffer, and read the image header from the
+ // target process
+ //
+
+ DosHeaderRawData = RtlAllocateHeap(Os2Heap, 0,
+ sizeof(IMAGE_DOS_HEADER));
+
+ if ( !DosHeaderRawData ) {
+#if DBG
+ DbgPrint( "Os2LocateDebugSection: fail to allocate from Os2heap\n");
+#endif // DBG
+ ASSERT(FALSE);
+ return NULL;
+ }
+
+ Status = NtReadVirtualMemory(
+ ProcessHandle,
+ Base,
+ DosHeaderRawData,
+ sizeof(IMAGE_DOS_HEADER),
+ NULL
+ );
+
+ ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2LocateDebugSection failed: NtReadVirtualMemory Status == %X\n",
+ Status
+ );
+ RtlFreeHeap(Os2Heap, 0, DosHeaderRawData);
+ return(NULL);
+#endif // DBG
+ }
+
+ AllocSize = DosHeaderRawData->e_lfanew + sizeof(IMAGE_NT_HEADERS);
+ RtlFreeHeap(Os2Heap, 0, DosHeaderRawData);
+
+ ImageHeaderRawData = RtlAllocateHeap(Os2Heap, 0, AllocSize);
+ if ( !ImageHeaderRawData ) {
+#if DBG
+ DbgPrint( "Os2LocateDebugSection: fail to allocate from Os2heap\n");
+#endif // DBG
+ ASSERT(FALSE);
+ return NULL;
+ }
+ Status = NtReadVirtualMemory(
+ ProcessHandle,
+ Base,
+ ImageHeaderRawData,
+ AllocSize,
+ NULL
+ );
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2LocateDebugSection failed: NtReadVirtualMemory Status == %X\n",
+ Status
+ );
+#endif // DBG
+ ASSERT(FALSE);
+ RtlFreeHeap(Os2Heap, 0, ImageHeaderRawData);
+ }
+
+ NtHeaders = (PIMAGE_NT_HEADERS)RtlImageNtHeader(ImageHeaderRawData);
+ Addr = (ULONG)NtHeaders->OptionalHeader.DataDirectory
+ [IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
+
+ if ( Addr ) {
+ Addr += (ULONG)Base;
+ }
+
+ RtlFreeHeap(Os2Heap, 0, ImageHeaderRawData);
+ return((PIMAGE_DEBUG_DIRECTORY)Addr);
+}
+
+VOID
+Os2OpenLdrEntry(
+ IN POS2_PROCESS Process,
+ IN PLDR_DATA_TABLE_ENTRY LdrEntry,
+ OUT PHANDLE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This function opens a handle to the image/dll file described
+ by the ldr entry in the context of the specified process.
+
+Arguments:
+
+ Process - Supplies the address of the process whose context this
+ file is to be opened in.
+
+ LdrEntry - Supplies the address of the loader data table entry
+ whose file is to be opened.
+
+ FileHandle - Returns a handle to the associated file
+ valid in the context of the process being attached to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UNICODE_STRING DosName;
+ UNICODE_STRING FileName;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES Obja;
+ HANDLE LocalHandle;
+ IO_STATUS_BLOCK IoStatusBlock;
+ BOOLEAN TranslationStatus;
+
+ DosName.Length = LdrEntry->FullDllName.Length;
+ DosName.MaximumLength = LdrEntry->FullDllName.MaximumLength;
+ DosName.Buffer = RtlAllocateHeap(Os2Heap, 0, DosName.MaximumLength);
+ if ( !DosName.Buffer ) {
+ return;
+ }
+
+ Status = NtReadVirtualMemory(
+ Process->ProcessHandle,
+ LdrEntry->FullDllName.Buffer,
+ DosName.Buffer,
+ DosName.MaximumLength,
+ NULL
+ );
+ ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2OpenLdrEntry failed: NtReadVirtualMemory Status == %X\n",
+ Status
+ );
+#endif // DBG
+ }
+
+ TranslationStatus = RtlDosPathNameToNtPathName_U(
+ DosName.Buffer,
+ &FileName,
+ NULL,
+ NULL
+ );
+
+ if ( !TranslationStatus ) {
+ RtlFreeHeap(Os2Heap,0,DosName.Buffer);
+ return;
+ }
+
+ InitializeObjectAttributes(
+ &Obja,
+ &FileName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ Status = NtOpenFile(
+ &LocalHandle,
+ (ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE),
+ &Obja,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ RtlFreeHeap(Os2Heap,0,DosName.Buffer);
+ RtlFreeHeap(RtlProcessHeap(),0,FileName.Buffer);
+ if ( !NT_SUCCESS(Status) ) {
+ return;
+ }
+
+ //
+ // The file is open in our context. Dup this to target processes context
+ // so that dbgss can dup it to the user interface
+ //
+
+ Status = NtDuplicateObject(
+ NtCurrentProcess(),
+ LocalHandle,
+ Process->ProcessHandle,
+ FileHandle,
+ 0L,
+ 0L,
+ DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES |
+ DUPLICATE_CLOSE_SOURCE
+ );
+ ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2OpenLdrEntry failed: NtDuplicateObject Status == %X\n",
+ Status
+ );
+#endif // DBG
+ }
+//
+// The NtDuplicateObject was called with DUPLICATE_CLOSE_SOURCE
+//
+// NtClose(LocalHandle);
+}
diff --git a/private/os2/server/srvevent.c b/private/os2/server/srvevent.c
new file mode 100644
index 000000000..538297e61
--- /dev/null
+++ b/private/os2/server/srvevent.c
@@ -0,0 +1,180 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvevent.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 Shared Event Semaphore API Calls.
+
+Author:
+
+ Steve Wood (stevewo) 07-Feb-1990
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_ERRORS
+#include "os2srv.h"
+
+BOOLEAN
+Os2DosCreateEventSem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ NTSTATUS Status;
+ POS2_DOSCREATEEVENTSEM_MSG a = &m->u.DosCreateEventSem;
+ OS2_SEMAPHORE Semaphore;
+ APIRET rc;
+
+ Semaphore.PointerCount = 0;
+ Semaphore.OpenCount = 1;
+ Semaphore.Type = Os2EventSem;
+ rc = Os2ProcessSemaphoreName( &a->ObjectName,
+ &Semaphore,
+ NULL
+ );
+
+ if (rc != NO_ERROR) {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+ }
+
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ Status = NtCreateEvent( &Semaphore.u.EventHandle,
+ EVENT_ALL_ACCESS,
+ NULL,
+ NotificationEvent,
+ a->InitialState
+ );
+ if (NT_SUCCESS( Status )) {
+ if (Or2CreateHandle( Os2SharedSemaphoreTable,
+ &a->HandleIndex,
+ (PVOID)&Semaphore
+ )
+ ) {
+ Status = NtDuplicateObject( NtCurrentProcess(),
+ Semaphore.u.EventHandle,
+ t->Process->ProcessHandle,
+ &a->NtEventHandle,
+ EVENT_ALL_ACCESS,
+ 0,
+ 0
+ );
+
+ if (NT_SUCCESS( Status )) {
+ rc = NO_ERROR;
+ }
+ else {
+ NtClose( (HANDLE)Os2DestroySemaphore( &Semaphore,
+ a->HandleIndex
+ )
+ );
+ }
+ }
+ else {
+ NtClose( Semaphore.u.EventHandle );
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ }
+ }
+ else {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ }
+
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosOpenEventSem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ NTSTATUS Status;
+ POS2_DOSOPENEVENTSEM_MSG a = &m->u.DosOpenEventSem;
+ POS2_SEMAPHORE Semaphore;
+ APIRET rc;
+
+ rc = Os2ProcessSemaphoreName( &a->ObjectName,
+ NULL,
+ &a->HandleIndex
+ );
+
+ if (rc != NO_ERROR || a->ObjectName.Length != 0) {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+ }
+
+ Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
+ a->HandleIndex,
+ TRUE
+ );
+ if (Semaphore == NULL) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+ else {
+ Status = NtDuplicateObject( NtCurrentProcess(),
+ Semaphore->u.EventHandle,
+ t->Process->ProcessHandle,
+ &a->NtEventHandle,
+ EVENT_ALL_ACCESS,
+ 0,
+ 0
+ );
+ if (NT_SUCCESS( Status )) {
+ Semaphore->OpenCount++;
+ }
+ else {
+ rc = Or2MapNtStatusToOs2Error( Status, ERROR_ALREADY_EXISTS );
+ }
+ }
+
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosCloseEventSem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSCLOSEEVENTSEM_MSG a = &m->u.DosCloseEventSem;
+ POS2_SEMAPHORE Semaphore;
+ APIRET rc;
+
+ UNREFERENCED_PARAMETER(t);
+ Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
+ a->HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+ else {
+ rc = NO_ERROR;
+
+ if (--Semaphore->OpenCount == 0) {
+ NtClose( (HANDLE)Os2DestroySemaphore( Semaphore, a->HandleIndex ) );
+ }
+ else {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ }
+ }
+
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+}
diff --git a/private/os2/server/srvfile.c b/private/os2/server/srvfile.c
new file mode 100644
index 000000000..c37e53b76
--- /dev/null
+++ b/private/os2/server/srvfile.c
@@ -0,0 +1,638 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvfile.c
+
+Abstract:
+
+ Support for copying file system variables during exec
+
+Author:
+
+ Therese Stowell (thereses) 6-Nov-1989
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_FILESYS
+#define INCL_OS2V20_ERRORS
+#include "os2srv.h"
+
+NTSTATUS
+DeviceAddShare(
+ IN ULONG DesiredAccess,
+ IN ULONG DesiredShareAccess,
+ IN OUT PSHARE_ACCESS ShareAccess
+ );
+
+NTSTATUS
+DeviceDupShare(
+ IN ULONG DesiredAccess,
+ IN ULONG DesiredShareAccess,
+ IN OUT PSHARE_ACCESS ShareAccess
+ );
+
+NTSTATUS
+DeviceRemoveShare(
+ IN ULONG DesiredAccess,
+ IN ULONG DesiredShareAccess,
+ IN OUT PSHARE_ACCESS ShareAccess
+ );
+
+SHARE_ACCESS DeviceSharer[NUMBER_OF_DEVICES];
+
+
+APIRET
+DupHandleTable(
+ IN PFILE_HANDLE ParentHandleTable,
+ IN ULONG ParentTableLength,
+ IN HANDLE ParentProcess, // NT process handle
+ IN HANDLE ChildProcess, // NT process handle
+ POS2_PROCESS Process, // OS/2 child process
+ IN POS2_DOSEXECPGM_MSG pExecPgmMsg
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called during an exec. It reads the handle table of
+ the parent and then creates the handle table for the child by duping
+ any inheritable handles and clearing some flags (as OS/2 does). The
+ resulting table will be read by the child process.
+
+Arguments:
+
+ ParentHandleTable - pointer to parent handle table
+
+ ParentTableLength - length of parent handle table
+
+ ParentProcess - NT process handle of parent
+
+ ChildProcess - NT process handle of child
+
+ Process - OS/2 child process
+
+ pExecPgmMsg - DosExecPgm message:
+
+ CmdLineFlag - flag to process the file handle
+
+ 1 - change StdOut to NULL
+ 2 - change StdOut to RedirectedFileName
+
+ RedirectedFileName - file name for STD_OUT (1)
+
+Return Value:
+
+ ??
+
+--*/
+
+{
+ NTSTATUS Status;
+ ULONG i, CmdLineFlag = pExecPgmMsg->CmdLineFlag;
+ ULONG BytesRead;
+
+ Process->HandleTableLength = ParentTableLength;
+ Process->HandleTable = (PFILE_HANDLE)RtlAllocateHeap( Os2Heap, 0,
+ ParentTableLength * sizeof(FILE_HANDLE)
+ );
+ if (Process->HandleTable == NULL) {
+#if DBG
+ KdPrint(( "Os2DupHandleTable, no memory in Os2Heap\n" ));
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ Status = NtReadVirtualMemory( ParentProcess,
+ ParentHandleTable,
+ Process->HandleTable,
+ ParentTableLength * sizeof(FILE_HANDLE),
+ &BytesRead
+ );
+ if ((!NT_SUCCESS(Status)) || (BytesRead != ParentTableLength * sizeof(FILE_HANDLE))) {
+ RtlFreeHeap(Os2Heap,0,Process->HandleTable);
+ return ERROR_INVALID_HANDLE;
+ }
+
+ for (i=0;i<ParentTableLength;i++)
+ {
+ if ((i == 1) && CmdLineFlag )
+ {
+ if (CmdLineFlag & REDIR_NUL)
+ {
+ Process->HandleTable[1].IoVectorType = NulVectorType;
+ Process->HandleTable[1].FileType = FILE_TYPE_DEV;
+ Process->HandleTable[1].DeviceAttribute = DEVICE_ATTRIBUTE_NUL | DEVICE_ATTRIBUTE_CHAR | 0x80;
+ /* 0x80 stands for LEVEL 1 which makes it OS/2 1.x compatible */
+ //Process->HandleTable[1].NtHandle =
+ Process->HandleTable[1].Flags = FILE_HANDLE_ALLOCATED | FILE_HANDLE_VALID |
+ OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE;
+ } else if (CmdLineFlag & REDIR_FILE)
+ {
+
+ Process->HandleTable[1].IoVectorType = FileVectorType;
+ Process->HandleTable[1].FileType = pExecPgmMsg->RedirectedFileType;
+ Process->HandleTable[1].DeviceAttribute = 0;
+ Process->HandleTable[1].NtHandle = pExecPgmMsg->hRedirectedFile;
+ Process->HandleTable[1].Flags = FILE_HANDLE_ALLOCATED | FILE_HANDLE_VALID |
+ OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE;
+ }
+ } else
+
+ if ((Process->HandleTable[i].Flags & FILE_HANDLE_ALLOCATED) &&
+ (!(Process->HandleTable[i].Flags & OPEN_FLAGS_NOINHERIT))) {
+ //
+ // all NT handles are non-inherited. to inherit OS/2 handles, dup handles to
+ // child.
+ //
+ if (Process->HandleTable[i].IoVectorType == MonitorVectorType)
+ {
+ continue;
+ }
+
+ // For VIO-devices, NtHandle field holds an OS2.EXE handle.
+ // Od2InitializeFileSystemForExec(fileinit.c) will handle it.
+
+ if ((Process->HandleTable[i].IoVectorType != ConVectorType) &&
+ (Process->HandleTable[i].IoVectorType != KbdVectorType) &&
+ (Process->HandleTable[i].IoVectorType != MouseVectorType) &&
+ (Process->HandleTable[i].IoVectorType != ScreenVectorType) &&
+ (Process->HandleTable[i].IoVectorType != RemoteVectorType))
+ {
+
+ Status = NtDuplicateObject(ParentProcess,
+ Process->HandleTable[i].NtHandle,
+ ChildProcess,
+ &(Process->HandleTable[i].NtHandle),
+ (ACCESS_MASK) NULL,
+ OBJ_CASE_INSENSITIVE,
+ DUPLICATE_SAME_ACCESS
+ );
+ // if dup fails, the child process will die and the system will release all
+ // the already-duped handles.
+
+// if (!NT_SUCCESS(Status)) {
+// RtlFreeHeap(Os2Heap,0,Process->HandleTable);
+// return ERROR_INVALID_HANDLE; // BUGBUG bogus error value
+// }
+
+ }
+ // os2 clears the write-through flag when duping the handle table
+
+ Process->HandleTable[i].Flags &= ~(OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_NO_CACHE);
+ }
+ else {
+ Process->HandleTable[i].Flags = FILE_HANDLE_FREE;
+ }
+ }
+ return( NO_ERROR );
+}
+
+
+APIRET
+InitializeFileSystemForExec(
+ IN POS2_FILE_SYSTEM_PARAMETERS FileSystemParameters,
+ IN HANDLE ParentProcessHandle, // NT process handle
+ IN HANDLE ChildProcessHandle, // NT process handle
+ POS2_PROCESS ParentProcess, // OS/2 parent process
+ POS2_PROCESS ChildProcess, // OS/2 child process
+ IN POS2_DOSEXECPGM_MSG pExecPgmMsg
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called during an exec. It calls the routines to
+ initialize various components of the filesystem.
+
+Arguments:
+
+ FileSystemParameters - values needed to initialize the file system
+
+ ParentProcessHandle - NT process handle to parent process
+
+ ChildProcessHandle - NT process handle to child process
+
+ ParentProcess - OS/2 parent process
+
+ ChildProcess - OS/2 child process
+
+ pExecPgmMsg - the message passed from the client
+
+Return Value:
+
+ ??
+
+--*/
+
+{
+ APIRET RetCode;
+
+ RetCode = DupHandleTable(FileSystemParameters->ParentHandleTable,
+ FileSystemParameters->ParentTableLength,
+ ParentProcessHandle,
+ ChildProcessHandle,
+ ChildProcess,
+ pExecPgmMsg
+ );
+ return RetCode;
+}
+
+
+BOOLEAN
+Os2InternalCopyHandleTable(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called during an exec by the child process. It copies
+ the handle table into the child's context.
+
+Arguments:
+
+ t - calling thread
+
+ m - message
+
+Return Value:
+
+ TRUE - create a return message
+
+--*/
+
+{
+ POS2_COPYHANDLETABLE_MSG a = &m->u.CopyHandleTable;
+ NTSTATUS Status;
+ ULONG BytesWritten;
+
+// DbgBreakPoint();
+ Status = NtWriteVirtualMemory( t->Process->ProcessHandle,
+ a->ChildHandleTable,
+ t->Process->HandleTable,
+ a->ChildTableLength * sizeof(FILE_HANDLE),
+ &BytesWritten
+ );
+
+ RtlFreeHeap(Os2Heap,0,t->Process->HandleTable);
+ if ((!NT_SUCCESS(Status)) || (BytesWritten != a->ChildTableLength * sizeof(FILE_HANDLE))) {
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE; // BUGBUG bogus error value
+ return( TRUE );
+ }
+ m->ReturnedErrorValue = NO_ERROR;
+ return( TRUE );
+}
+
+
+VOID
+InitializeFileSystemForSesMgr(
+ IN POS2_PROCESS Process
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called during an create session. It allocates space
+ for the current directory table and initializes each entry to the
+ root directory.
+
+Arguments:
+
+ Process - process being created
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ int i;
+
+ for (i=0;i<NUMBER_OF_DEVICES;i++) {
+ DeviceSharer[i].OpenCount = 0;
+ DeviceSharer[i].Readers = 0;
+ DeviceSharer[i].Writers = 0;
+ DeviceSharer[i].Deleters = 0;
+ DeviceSharer[i].SharedRead = 0;
+ DeviceSharer[i].SharedWrite = 0;
+ DeviceSharer[i].SharedDelete = 0;
+ }
+}
+
+
+APIRET
+InitializeFileSystemForChildSesMgr(
+ IN POS2_FILE_SYSTEM_PARAMETERS FileSystemParameters,
+ IN HANDLE ParentProcessHandle, // NT process handle
+ IN HANDLE ChildProcessHandle, // NT process handle
+ POS2_PROCESS ParentProcess, // OS/2 parent process
+ POS2_PROCESS ChildProcess, // OS/2 child process
+ IN POS2_DOSEXECPGM_MSG pExecPgmMsg
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called during an create session of a child session.
+ It calls the routines to initialize various components of the filesystem.
+
+Arguments:
+
+ FileSystemParameters - values needed to initialize the file system
+
+ ParentProcessHandle - NT process handle to parent process
+
+ ChildProcessHandle - NT process handle to child process
+
+ ParentProcess - OS/2 parent process
+
+ ChildProcess - OS/2 child process
+
+ pExecPgmMsg - the message passed from the client
+
+Return Value:
+
+ ??
+
+--*/
+
+{
+ APIRET RetCode;
+ int i;
+
+ RetCode = DupHandleTable(FileSystemParameters->ParentHandleTable,
+ FileSystemParameters->ParentTableLength,
+ ParentProcessHandle,
+ ChildProcessHandle,
+ ChildProcess,
+ pExecPgmMsg
+ );
+
+ if (RetCode == NO_ERROR) {
+
+ for (i=0;i<NUMBER_OF_DEVICES;i++) {
+ DeviceSharer[i].OpenCount = 0;
+ DeviceSharer[i].Readers = 0;
+ DeviceSharer[i].Writers = 0;
+ DeviceSharer[i].Deleters = 0;
+ DeviceSharer[i].SharedRead = 0;
+ DeviceSharer[i].SharedWrite = 0;
+ DeviceSharer[i].SharedDelete = 0;
+ }
+ }
+ return RetCode;
+}
+
+
+BOOLEAN
+Os2InternalDeviceShare(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to add, dup, or remove the sharing of a particular
+ device.
+
+Arguments:
+
+ t - calling thread
+
+ m - message
+
+Return Value:
+
+ TRUE - create a return message
+
+--*/
+
+{
+ POS2_SHARE_MSG a = &m->u.DeviceShare;
+ PSHARE_ACCESS ShareRecord;
+
+ UNREFERENCED_PARAMETER(t);
+ if (a->VectorType > MAXIMUM_DEVICE_VECTOR_TYPE) {
+ ASSERT (FALSE);
+ m->ReturnedErrorValue = (ULONG)STATUS_INVALID_PARAMETER;
+ return TRUE;
+ }
+ ShareRecord = &DeviceSharer[a->VectorType];
+
+ switch (a->Operation) {
+ case AddShare:
+ m->ReturnedErrorValue = DeviceAddShare(a->DesiredAccess,
+ a->ShareAccess,
+ ShareRecord
+ );
+ break;
+ case DupShare:
+ m->ReturnedErrorValue = DeviceDupShare(a->DesiredAccess,
+ a->ShareAccess,
+ ShareRecord
+ );
+ break;
+ case RemoveShare:
+ m->ReturnedErrorValue = DeviceRemoveShare(a->DesiredAccess,
+ a->ShareAccess,
+ ShareRecord
+ );
+ break;
+ default:
+ ASSERT (FALSE);
+ m->ReturnedErrorValue = (ULONG)STATUS_INVALID_PARAMETER;
+ break;
+ }
+ return TRUE;
+}
+
+NTSTATUS
+DeviceAddShare(
+ IN ULONG DesiredAccess,
+ IN ULONG DesiredShareAccess,
+ IN OUT PSHARE_ACCESS ShareAccess
+ )
+
+{
+ ULONG Ocount;
+ ULONG ReadAccess;
+ ULONG WriteAccess;
+ ULONG DeleteAccess;
+ ULONG SharedRead;
+ ULONG SharedWrite;
+ ULONG SharedDelete;
+
+ //
+ // Set the access type in the file object for the current accessor.
+ // Note that reading and writing attributes are not included in the
+ // access check.
+ //
+
+ ReadAccess = (DesiredAccess & (READ_CONTROL | FILE_EXECUTE
+ | FILE_READ_DATA | FILE_READ_EA)) != 0;
+ WriteAccess = (DesiredAccess & (WRITE_DAC | WRITE_OWNER
+ | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA)) != 0;
+ DeleteAccess = (DesiredAccess & DELETE) != 0;
+
+ SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
+ SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
+ SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
+
+ //
+ // Now check to see whether or not the desired accesses are compatible
+ // with the way that the file is currently open.
+ //
+
+ Ocount = ShareAccess->OpenCount;
+
+ if ( (ReadAccess && (ShareAccess->SharedRead < Ocount))
+ ||
+ (WriteAccess && (ShareAccess->SharedWrite < Ocount))
+ ||
+ (DeleteAccess && (ShareAccess->SharedDelete < Ocount))
+ ||
+ ((ShareAccess->Readers != 0) && !SharedRead)
+ ||
+ ((ShareAccess->Writers != 0) && !SharedWrite)
+ ||
+ ((ShareAccess->Deleters != 0) && !SharedDelete)
+ ) {
+
+ //
+ // The check failed. Simply return to the caller indicating that the
+ // current open cannot access the file.
+ //
+
+ return STATUS_SHARING_VIOLATION;
+
+ } else {
+
+ //
+ // The check was successful. Update the counter information in the
+ // shared access structure for this open request if the caller
+ // specified that it should be updated.
+ //
+
+ ShareAccess->OpenCount++;
+
+ ShareAccess->Readers += ReadAccess;
+ ShareAccess->Writers += WriteAccess;
+ ShareAccess->Deleters += DeleteAccess;
+
+ ShareAccess->SharedRead += SharedRead;
+ ShareAccess->SharedWrite += SharedWrite;
+ ShareAccess->SharedDelete += SharedDelete;
+
+ return STATUS_SUCCESS;
+ }
+}
+
+NTSTATUS
+DeviceDupShare(
+ IN ULONG DesiredAccess,
+ IN ULONG DesiredShareAccess,
+ IN OUT PSHARE_ACCESS ShareAccess
+ )
+
+{
+ ULONG ReadAccess;
+ ULONG WriteAccess;
+ ULONG DeleteAccess;
+ ULONG SharedRead;
+ ULONG SharedWrite;
+ ULONG SharedDelete;
+
+ //
+ // Set the access type in the file object for the current accessor.
+ // Note that reading and writing attributes are not included in the
+ // access check.
+ //
+
+ ReadAccess = (DesiredAccess & (READ_CONTROL | FILE_EXECUTE
+ | FILE_READ_DATA | FILE_READ_EA)) != 0;
+ WriteAccess = (DesiredAccess & (WRITE_DAC | WRITE_OWNER
+ | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA)) != 0;
+ DeleteAccess = (DesiredAccess & DELETE) != 0;
+
+ SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
+ SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
+ SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
+
+#if DBG
+ if (ShareAccess->OpenCount == 0)
+ ASSERT (FALSE);
+#endif
+ ShareAccess->OpenCount++;
+
+ ShareAccess->Readers += ReadAccess;
+ ShareAccess->Writers += WriteAccess;
+ ShareAccess->Deleters += DeleteAccess;
+
+ ShareAccess->SharedRead += SharedRead;
+ ShareAccess->SharedWrite += SharedWrite;
+ ShareAccess->SharedDelete += SharedDelete;
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+DeviceRemoveShare(
+ IN ULONG DesiredAccess,
+ IN ULONG DesiredShareAccess,
+ IN OUT PSHARE_ACCESS ShareAccess
+ )
+
+{
+ ULONG ReadAccess;
+ ULONG WriteAccess;
+ ULONG DeleteAccess;
+ ULONG SharedRead;
+ ULONG SharedWrite;
+ ULONG SharedDelete;
+
+ //
+ // Set the access type in the file object for the current accessor.
+ // Note that reading and writing attributes are not included in the
+ // access check.
+ //
+
+ ReadAccess = (DesiredAccess & (READ_CONTROL | FILE_EXECUTE
+ | FILE_READ_DATA | FILE_READ_EA)) != 0;
+ WriteAccess = (DesiredAccess & (WRITE_DAC | WRITE_OWNER
+ | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA)) != 0;
+ DeleteAccess = (DesiredAccess & DELETE) != 0;
+
+ SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
+ SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
+ SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
+
+//#if DBG
+// if (ShareAccess->OpenCount == 0)
+// ASSERT (FALSE);
+//#endif
+ ShareAccess->OpenCount--;
+
+ ShareAccess->Readers -= ReadAccess;
+ ShareAccess->Writers -= WriteAccess;
+ ShareAccess->Deleters -= DeleteAccess;
+
+ ShareAccess->SharedRead -= SharedRead;
+ ShareAccess->SharedWrite -= SharedWrite;
+ ShareAccess->SharedDelete -= SharedDelete;
+
+ return STATUS_SUCCESS;
+}
diff --git a/private/os2/server/srvinit.c b/private/os2/server/srvinit.c
new file mode 100644
index 000000000..a1511a511
--- /dev/null
+++ b/private/os2/server/srvinit.c
@@ -0,0 +1,736 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvinit.c
+
+Abstract:
+
+ This is the main initialization module for the OS/2 Subsystem Server
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include "os2srv.h"
+#include "os2tile.h"
+#include "os2win.h"
+#include "os2err.h"
+#define NTOS2_ONLY
+#include "sesport.h"
+#include "os2ldr.h"
+
+
+extern HANDLE FirstOs2ProcessHandle;
+
+BOOLEAN
+SetProcessShutdownParameters(
+ DWORD dwLevel,
+ DWORD dwFlags
+ );
+
+BOOLEAN
+InitializeSecurityDescriptor (
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ DWORD dwRevision
+ );
+
+BOOLEAN
+SetSecurityDescriptorDacl (
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ BOOLEAN bDaclPresent,
+ PACL pDacl,
+ BOOLEAN bDaclDefaulted
+ );
+
+BOOLEAN
+SetKernelObjectSecurity (
+ HANDLE Handle,
+ SECURITY_INFORMATION SecurityInformation,
+ PSECURITY_DESCRIPTOR SecurityDescriptor
+ );
+
+WCHAR Os2SystemDirectory[MAX_PATH];
+ULONG Os2GlobalInfoSeg;
+HANDLE Os2GlobalInfoSegHandle;
+HANDLE UpDateInfoSegThreadHandle;
+HANDLE Os2SyncSem;
+
+
+APIRET
+Os2GetSysInfo(VOID)
+{
+ APIRET RetCode;
+ GINFOSEG *pGlobalInfo;
+ TIME_FIELDS NtDateTime;
+ LARGE_INTEGER nttime, LocalTime;
+ SYSTEM_TIMEOFDAY_INFORMATION SystemInformation;
+ ULONG utemp = 0xFFFFFFFF/10000;
+ SHORT TimeZone;
+
+ pGlobalInfo = (GINFOSEG *) Os2GlobalInfoSeg;
+
+ //
+ // fill in global info fields
+ //
+
+ RetCode = Or2GetDateTimeInfo(
+ &nttime,
+ &LocalTime,
+ &NtDateTime,
+ (PVOID)&SystemInformation,
+ &TimeZone
+ );
+
+ if (RetCode)
+ {
+#if DBG
+ IF_OS2_DEBUG( MISC )
+ {
+ KdPrint(( "Os2GetSysInfo: Error at Or2GetDateTimeInfo %lu\n",
+ RetCode));
+ }
+#endif
+ return (RetCode);
+ }
+
+ pGlobalInfo->year = NtDateTime.Year;
+ pGlobalInfo->month = (UCHAR)(NtDateTime.Month);
+ pGlobalInfo->day = (UCHAR)(NtDateTime.Day);
+ pGlobalInfo->weekday = (UCHAR)(NtDateTime.Weekday);
+ pGlobalInfo->hour = (UCHAR)(NtDateTime.Hour);
+ pGlobalInfo->minutes = (UCHAR)(NtDateTime.Minute);
+ pGlobalInfo->seconds = (UCHAR)(NtDateTime.Second);
+ pGlobalInfo->hundredths = (UCHAR)(NtDateTime.Milliseconds / 10);
+ pGlobalInfo->weekday = (UCHAR)NtDateTime.Weekday;
+ pGlobalInfo->timezone = TimeZone;
+
+ RtlTimeToSecondsSince1970 ( &LocalTime, &(pGlobalInfo->time) );
+
+ //
+ // Convert UTC to Local time: no need beacuse the subtract between 2 UTCs
+ //
+
+ SystemInformation.BootTime = RtlLargeIntegerSubtract(nttime,
+ SystemInformation.BootTime);
+ pGlobalInfo->msecs = SystemInformation.BootTime.LowPart/10000 +
+ ((ULONG)SystemInformation.BootTime.HighPart)*utemp;
+
+ return(0);
+}
+
+
+VOID
+UpdateInfoSegThread(
+ ULONG param
+ )
+{
+ APIRET rc;
+ NTSTATUS Status;
+ LARGE_INTEGER DelayInterval;
+
+ UNREFERENCED_PARAMETER(param);
+
+
+#if DBG
+ IF_OS2_DEBUG( MISC ) {
+ KdPrint(("Entering UpdateInfoSeg.\n"));
+ }
+#endif
+
+ DelayInterval = RtlEnlargedIntegerMultiply( 10, -10000 );
+ for (;;) {
+ rc = Os2GetSysInfo();
+ if (rc) {
+#if DBG
+ KdPrint(("UpdateInfoSegThread: error at Os2GetSysInfo %d\n", rc));
+#endif
+ ASSERT (FALSE);
+ NtTerminateThread(UpDateInfoSegThreadHandle, rc);
+ }
+ Status = NtDelayExecution( TRUE, &DelayInterval );
+ DelayInterval = RtlEnlargedIntegerMultiply( 10, -10000 );
+ }
+}
+
+
+NTSTATUS
+Os2InitializeGlobalInfoSeg( VOID )
+{
+
+ NTSTATUS Status;
+ ULONG AllocationAttributes;
+ LARGE_INTEGER SectionSize;
+ ULONG RegionSize = 0;
+ GINFOSEG *pGlobalInfoSeg;
+ CLIENT_ID ClientId;
+
+ AllocationAttributes = SEC_COMMIT;
+ SectionSize.LowPart = sizeof(GINFOSEG);
+ SectionSize.HighPart = 0;
+ Status = NtCreateSection( &Os2GlobalInfoSegHandle,
+ SECTION_ALL_ACCESS,
+ NULL,
+ &SectionSize,
+ PAGE_READWRITE,
+ AllocationAttributes,
+ NULL
+ );
+
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2SRV: unable to create the GINFOSEG section, Status=%x\n", Status));
+#endif
+ return( Status );
+ }
+
+ Os2GlobalInfoSeg = GINFOSEG_BASE;
+ Status = NtMapViewOfSection( Os2GlobalInfoSegHandle,
+ NtCurrentProcess(),
+ (PVOID) &Os2GlobalInfoSeg,
+ 0,
+ 0,
+ NULL,
+ &RegionSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE
+ );
+
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2SRV: unable to Map View of the GINFOSEG section, Status=%x\n", Status));
+#endif
+ return( Status );
+ }
+
+ pGlobalInfoSeg = (GINFOSEG *) Os2GlobalInfoSeg;
+
+// pGlobalInfoSeg->pidForeground = (USHORT)(Od2Process->Pib.ProcessId);
+// pGlobalInfoSeg->sgCurrent = (UCHAR)Od2SessionNumber;
+
+ //
+ // Set Fixed Global Information Fields
+ //
+ pGlobalInfoSeg->uchMajorVersion = 10;
+ pGlobalInfoSeg->uchMinorVersion = 21;
+ pGlobalInfoSeg->cHugeShift = 3;
+
+ pGlobalInfoSeg->fProtectModeOnly = 1;
+
+ //
+ // GINFOSEG fields that are set arbitrarily or not
+ // set at all for now
+ //
+ pGlobalInfoSeg->chRevisionLetter = 0;
+// pGlobalInfoSeg->sgCurrent = 0;
+ pGlobalInfoSeg->sgMax = 16;
+ pGlobalInfoSeg->fDynamicSched = 1;
+ pGlobalInfoSeg->csecMaxWait = (UCHAR)-1;
+ pGlobalInfoSeg->cmsecMinSlice = 100;
+ pGlobalInfoSeg->cmsecMaxSlice = 100;
+ pGlobalInfoSeg->timezone = (USHORT)(-1);
+// pGlobalInfoSeg->amecRAS
+// pGlobalInfoSeg->WindowableVioMax
+// pGlobalInfoSeg->csgPMMax
+#ifdef PMNT
+// probably this PMNT can be removed because this is th
+// value of global info seg field in OS2 (LiorM)
+ pGlobalInfoSeg->csgWindowableVioMax = 16;
+ pGlobalInfoSeg->csgPMMax = 16;
+#endif
+
+ pGlobalInfoSeg->bootdrive = (USHORT)Os2BootDrive + 1;
+
+ //
+ // Get timer resolution
+ //
+
+ {
+ SYSTEM_BASIC_INFORMATION sysinfo;
+
+ Status = NtQuerySystemInformation(
+ SystemBasicInformation,
+ &sysinfo,
+ sizeof(sysinfo),
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( MISC ) {
+ KdPrint(("OS2SRV: unable to query system timer resolution, Status = %lx\n", Status));
+ }
+#endif
+ pGlobalInfoSeg->cusecTimerInterval = 310; // default value, comes from OS/2
+ } else {
+ pGlobalInfoSeg->cusecTimerInterval = (USHORT) (sysinfo.TimerResolution / 1000L);
+ }
+ }
+
+ Status = RtlCreateUserThread( NtCurrentProcess(),
+ NULL,
+ TRUE,
+ 0,
+ 0x10000,
+ 0, // Default to one page
+ (PUSER_THREAD_START_ROUTINE)UpdateInfoSegThread,
+ 0, // param
+ &UpDateInfoSegThreadHandle,
+ &ClientId
+ );
+ if(!NT_SUCCESS(Status)){
+#if DBG
+ KdPrint(("Os2InitializeGlobalInfoSeg: can't Create update thread %lx\n", Status));
+#endif
+ return Status;
+ }
+
+ Status = NtResumeThread( UpDateInfoSegThreadHandle, NULL );
+ if(!NT_SUCCESS(Status)){
+#if DBG
+ KdPrint(("Os2InitializeGlobalInfoSeg: can't Resume update thread %lx\n", Status));
+#endif
+ return Status;
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+NTSTATUS Os2InitializeSyncSem()
+{
+ NTSTATUS Status;
+ UNICODE_STRING SemString_U;
+ OBJECT_ATTRIBUTES Obja;
+ CHAR sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
+ PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR)&sd;
+
+ InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
+ SetSecurityDescriptorDacl(psd, TRUE, NULL, FALSE); // NULL DACL means access free to all
+
+ RtlInitUnicodeString( &SemString_U, OS2_SS_SYNCHRONIZATION_SEM);
+ InitializeObjectAttributes(
+ &Obja,
+ &SemString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ psd);
+
+ //
+ // Create the global subsystem synchronization Nt semaphore
+ //
+ Status = NtCreateMutant(&Os2SyncSem,
+ MUTANT_ALL_ACCESS,
+ &Obja,
+ FALSE);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG ( SEMAPHORES ) {
+ DbgPrint("Os2InitSyncSem: error at NtCreateSemaphore, Status %x\n", Status);
+ }
+#endif
+ }
+ return(Status);
+}
+
+#if PMNT
+NTSTATUS Os2InitializePMShellEvent()
+{
+ NTSTATUS Status;
+ UNICODE_STRING EventString_U;
+ OBJECT_ATTRIBUTES Obja;
+ HANDLE hPMShellEvent;
+ CHAR sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
+ PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR)&sd;
+
+ InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
+ SetSecurityDescriptorDacl(psd, TRUE, NULL, FALSE); // NULL DACL means access free to all
+
+ RtlInitUnicodeString( &EventString_U, OS2_SS_PMSHELL_EVENT);
+ InitializeObjectAttributes(
+ &Obja,
+ &EventString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ psd);
+
+ //
+ // Create the global subsystem PMShell synchronization Nt event
+ // (create in the unsignalled state - when PMShell comes up, it will
+ // signal it)
+ //
+ Status = NtCreateEvent(&hPMShellEvent,
+ EVENT_ALL_ACCESS,
+ &Obja,
+ NotificationEvent,
+ FALSE);
+
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ DbgPrint("Os2InitializePMShellEvent: error at NtCreateEvent, Status %x\n", Status);
+#endif
+ }
+ return(Status);
+}
+#endif // PMNT
+
+NTSTATUS
+Os2Initialize( VOID )
+{
+ NTSTATUS Status;
+ APIRET Rc;
+ CHAR sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
+ PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR)&sd;
+
+#if DBG
+ if (fService)
+ KdPrint(("Started OS2SRV init (as a service)\n"));
+ else
+ KdPrint(("Started OS2SRV init\n"));
+#endif
+
+ //
+ // We have just created os2srv - set it's security so all clients
+ // can open it regardless of logon
+ //
+
+ InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
+ SetSecurityDescriptorDacl(psd, TRUE, NULL, FALSE); // NULL DACL means access free to all
+ SetKernelObjectSecurity(GetCurrentProcess(), DACL_SECURITY_INFORMATION, psd);
+
+ SetEventHandlersAndErrorMode(TRUE);
+
+ //
+ // Create a heap for the OS/2 Server to use for dynamic memory allocation.
+ //
+
+ Os2Heap = RtlCreateHeap( HEAP_GROWABLE,
+ NULL,
+ 64 * 1024, // Initial size of heap is 64K
+ 4 * 1024,
+ 0,
+ NULL // reserved
+ );
+ if (Os2Heap == NULL) {
+#if DBG
+ KdPrint(("OS2SRV: Error at RtlCreateHeap of Os2Heap\n"));
+ ASSERT(FALSE);
+#endif
+ return STATUS_NO_MEMORY;
+ }
+
+ //
+ // Initialize the Process List
+ //
+
+ Status = Os2InitializeProcessStructure();
+ if (! NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2SRV: Cannot initialize process structure, Status = %X\n", Status));
+ ASSERT(FALSE);
+#endif
+ }
+
+ //
+ // Initialize the Object Manager
+ //
+
+ Status = Os2InitializeLocalObjectManager();
+ if (! NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2SRV: Cannot initialize local object manager, Status = %X\n", Status));
+ ASSERT(FALSE);
+#endif
+ }
+
+ //
+ // Initialize the Memory Management
+ //
+
+ Status = Os2InitializeMemory();
+ if (! NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2SRV: Cannot initialize shared memory, Status = %X\n", Status));
+ ASSERT(FALSE);
+#endif
+ }
+
+ //
+ // Initialize the Semaphore Table
+ //
+
+ Status = Os2InitializeSemaphores();
+ if (! NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2SRV: Cannot initialize semaphores, Status = %X\n", Status));
+ ASSERT(FALSE);
+#endif
+ }
+
+ //
+ // Initialize the Queue Table
+ //
+
+ Status = Os2InitializeQueues();
+ if (! NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2SRV: Cannot initialize queues, Status = %X\n", Status));
+ ASSERT(FALSE);
+#endif
+ }
+
+ //
+ // Initialize the Name Space
+ //
+
+ Status = Os2InitializeNameSpace();
+ if (! NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2SRV: Cannot initialize name space, Status = %X\n", Status));
+#endif
+ ExitProcess(1);
+ }
+
+ Status = Os2InitializeSyncSem();
+ if (! NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2SRV: Status %lx from Os2InitializeSyncSem\n", Status));
+ ASSERT(FALSE);
+#endif
+ return Status;
+ }
+
+#if PMNT
+ Status = Os2InitializePMShellEvent();
+ if (! NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(("OS2SRV: Status %lx from Os2InitializePMShellSem\n", Status));
+ ASSERT(FALSE);
+#endif
+ return Status;
+ }
+#endif // PMNT
+
+ // Make it so that OS2SRV gets the shutdown/logoff message last. Default
+ // is 0x280, minimum range for app is 0x100
+ if (!SetProcessShutdownParameters(
+ 0x27e, // Just below the priority of PMShell
+ 0))
+ {
+#if DBG
+ DbgPrint("Os2srv: SetProcessShutdownParameters failed !\n");
+#endif
+ }
+
+ //
+ // Initialize the registry
+ //
+
+ if (GetSystemDirectoryW(Os2SystemDirectory, MAX_PATH) == 0) {
+#if DBG
+ KdPrint(("OS2SRV: Cannot obtain name of system directory\n"));
+ ASSERT(FALSE);
+#endif
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ Status = Os2InitializeRegistry();
+ if (! NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2SRV: Cannot initialize registry, Status = %X\n", Status));
+#endif
+ }
+
+ //
+ // Initialize the NLS
+ //
+
+ if( Rc = Os2InitializeNLS() )
+ {
+#if DBG
+ KdPrint(("OS2SRV: Cannot initialize NLS, Rc = %d\n", Rc ));
+ ASSERT(FALSE);
+#endif
+ }
+
+ //
+ // Initialize the loader
+ //
+ if (!ldrInit()) {
+#if DBG
+ KdPrint(("OS2SRV: Cannot initialize Loader\n"));
+ ASSERT(FALSE);
+#endif
+ }
+
+ //
+ // Initialize the Global info seg
+ //
+
+ if( Status = Os2InitializeGlobalInfoSeg() )
+ {
+#if DBG
+ KdPrint(("OS2SRV: Cannot initialize Global Info, Status = %d\n", Status ));
+ ASSERT(FALSE);
+#endif
+ }
+
+ //
+ // Initialize the OS2 Server Console Session Port, the listen thread and one
+ // request threads.
+ //
+
+ Status = Os2InitializeConsolePort();
+
+ if (! NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2SRV: Cannot initialize Console Port, Status = %X\n", Status ));
+ ASSERT(FALSE);
+#endif
+ return Status;
+ }
+
+ //
+ // Initialize the OS2 Server API Port, the listen thread and one or more
+ // request threads.
+ //
+
+ Status = Os2DebugPortInitialize();
+ if (! NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2SRV: Cannot initialize Debug Port, Status = %X\n", Status ));
+ ASSERT(FALSE);
+#endif
+ return Status;
+ }
+
+ Status = DbgSsInitialize(Os2SessionPort, Os2UiLookup, NULL, NULL);
+ if (! NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2SRV: Status %lx from DbgSsInitialize\n", Status));
+ ASSERT(FALSE);
+#endif
+ return Status;
+ }
+
+ if (! NT_SUCCESS(Os2GetClientId())) {
+#if DBG
+ KdPrint(("OS2SRV: Can not debug\n"));
+#endif
+ }
+
+
+ return( Status );
+}
+
+
+ULONG
+NtGetIntegerFromUnicodeString(IN WCHAR *WString)
+{
+ ULONG Code = 0;
+ NTSTATUS Status;
+ UNICODE_STRING UnicodeString;
+
+ RtlInitUnicodeString(
+ &UnicodeString,
+ WString);
+
+ Status = RtlUnicodeStringToInteger(
+ &UnicodeString,
+ 10,
+ &Code);
+
+#if DBG
+ if (! NT_SUCCESS( Status ))
+ {
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("InitNLS: RtlUnicodeStringToInteger failed, Status %lu\n",
+ Status ));
+ }
+ }
+#endif
+ return(Code);
+}
+
+
+BOOLEAN
+Os2SrvHandleCtrlEvent(
+ IN int CtrlType
+ )
+{
+ BOOLEAN Wait = FALSE/*, Rc*/;
+ OS2SESREQUESTMSG RequestMsg;
+ ULONG i;
+ LARGE_INTEGER DelayInterval;
+
+#if DBG
+ IF_OS2_DEBUG( SIG )
+ {
+ KdPrint(("OS2SRV(EventHandlerRoutine): Ctr-Type %u\n", CtrlType));
+ }
+#endif
+
+ Os2AcquireStructureLock();
+ for ( i = 1 ; ( i < OS2_MAX_SESSION ) ; i++ )
+ {
+ if ( SessionTable[i].Session != NULL )
+ {
+ RequestMsg.Session = SessionTable[i].Session;
+ RequestMsg.d.Signal.Type = CtrlType;
+ Os2CtrlSignalHandler(&RequestMsg, NULL);
+ Wait = TRUE;
+ }
+ }
+ Os2ReleaseStructureLock();
+
+ while (Wait)
+ {
+#if DBG
+ KdPrint(("OS2SRV(EventHandlerRoutine): Waiting 2 seconds for all sessions to clear\n"));
+#endif
+ DelayInterval = RtlEnlargedIntegerMultiply( 2000, -10000 );
+ NtDelayExecution( (BOOLEAN)TRUE, &DelayInterval );
+ Wait = FALSE;
+
+ for ( i = 1 ; ( i < OS2_MAX_SESSION ) ; i++ )
+ {
+ if ( SessionTable[i].Session != NULL )
+ {
+ Wait = TRUE;
+ }
+ }
+
+ }
+ //
+ // Wait for the first application that created the server -
+ // The logoff/shutdown logic is LIFO, so we want to prevent
+ // os2srv from exiting if that app is not gone yet, otherwise
+ // the kernel hangs because of debug port handshake
+ //
+ if ( FirstOs2ProcessHandle != 0 && FirstOs2ProcessHandle != (HANDLE)-1 ) {
+ NtWaitForSingleObject(
+ FirstOs2ProcessHandle,
+ TRUE, // Alertable
+ NULL
+ );
+ }
+ //
+ // Now we can exit the server
+ //
+ Os2SrvExitProcess(0);
+ return(TRUE);
+}
diff --git a/private/os2/server/srvmutex.c b/private/os2/server/srvmutex.c
new file mode 100644
index 000000000..c7822ca1a
--- /dev/null
+++ b/private/os2/server/srvmutex.c
@@ -0,0 +1,159 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvmutex.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 Shared Mutex Semaphore API Calls.
+
+Author:
+
+ Steve Wood (stevewo) 07-Feb-1990
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_ERRORS
+#include "os2srv.h"
+
+BOOLEAN
+Os2DosCreateMutexSem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ NTSTATUS Status;
+ POS2_DOSCREATEMUTEXSEM_MSG a = &m->u.DosCreateMutexSem;
+ OS2_SEMAPHORE Semaphore;
+ APIRET rc;
+
+ Semaphore.PointerCount = 0;
+ Semaphore.OpenCount = 1;
+ Semaphore.Type = Os2MutexSem;
+
+ Status = NtDuplicateObject( t->Process->ProcessHandle,
+ a->NtMutantHandle,
+ NtCurrentProcess(),
+ &Semaphore.u.MutantHandle,
+ MUTANT_ALL_ACCESS,
+ 0,
+ 0
+ );
+
+ if (!NT_SUCCESS( Status )) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else {
+ rc = Os2ProcessSemaphoreName( &a->ObjectName,
+ &Semaphore,
+ NULL
+ );
+
+ }
+
+ if (rc == NO_ERROR) {
+ if (!Or2CreateHandle( Os2SharedSemaphoreTable,
+ &a->HandleIndex,
+ (PVOID)&Semaphore
+ )
+ ) {
+ NtClose( Semaphore.u.MutantHandle );
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosOpenMutexSem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ NTSTATUS Status;
+ POS2_DOSOPENMUTEXSEM_MSG a = &m->u.DosOpenMutexSem;
+ POS2_SEMAPHORE Semaphore;
+ APIRET rc;
+
+ rc = Os2ProcessSemaphoreName( &a->ObjectName,
+ NULL,
+ &a->HandleIndex
+ );
+
+ if (rc != NO_ERROR || a->ObjectName.Length != 0) {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+ }
+
+ Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
+ a->HandleIndex,
+ TRUE
+ );
+ if (Semaphore == NULL) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+ else {
+ Status = NtDuplicateObject( NtCurrentProcess(),
+ Semaphore->u.MutantHandle,
+ t->Process->ProcessHandle,
+ &a->NtMutantHandle,
+ MUTANT_ALL_ACCESS,
+ 0,
+ 0
+ );
+ if (NT_SUCCESS( Status )) {
+ Semaphore->OpenCount++;
+ }
+ }
+
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosCloseMutexSem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSCLOSEMUTEXSEM_MSG a = &m->u.DosCloseMutexSem;
+ POS2_SEMAPHORE Semaphore;
+ APIRET rc;
+
+ UNREFERENCED_PARAMETER(t);
+ Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
+ a->HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+ else {
+ rc = NO_ERROR;
+
+ if (--Semaphore->OpenCount == 0) {
+ NtClose( (HANDLE)Os2DestroySemaphore( Semaphore, a->HandleIndex ) );
+ }
+ else {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ }
+ }
+
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+}
diff --git a/private/os2/server/srvmuxwt.c b/private/os2/server/srvmuxwt.c
new file mode 100644
index 000000000..9a1c265d6
--- /dev/null
+++ b/private/os2/server/srvmuxwt.c
@@ -0,0 +1,613 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvmuxwt.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 Shared MuxWait Semaphore API Calls.
+
+Author:
+
+ Steve Wood (stevewo) 07-Feb-1990
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_ERRORS
+#include "os2srv.h"
+
+APIRET
+Os2AddMuxWait(
+ IN POS2_MUXWAIT_SEMAPHORE MuxWait,
+ IN PSEMRECORD MuxWaitEntry
+ )
+{
+ POS2_MUXWAIT_RECORD MuxWaitRecord;
+ POS2_SEMAPHORE Semaphore;
+ USHORT i;
+
+ if (MuxWait->CountMuxWaitRecords == DCMW_MAX_SEMRECORDS) {
+ return( ERROR_TOO_MANY_SEMAPHORES );
+ }
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside the
+ // current limits of the table. If the mapping is successful then the
+ // semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POS2_SEMAPHORE)Or2MapHandle(
+ Os2SharedSemaphoreTable,
+ (ULONG)MuxWaitEntry->hsemCur,
+ TRUE
+ );
+ if (Semaphore == NULL) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ //
+ // Now see if this semaphore is already in the MuxWait semaphore.
+ // Return an error if it is.
+ //
+
+ MuxWaitRecord = &MuxWait->MuxWaitRecords[ 0 ];
+ for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
+ if (MuxWaitRecord->Semaphore == Semaphore) {
+ return( ERROR_DUPLICATE_HANDLE );
+ }
+
+ MuxWaitRecord++;
+ }
+
+
+ //
+ // Entry in semaphore table exists, so make sure it is not a MuxWait
+ // semaphore. Also make sure it is that same type of semaphore as the
+ // first semaphore. Also make sure if the MuxWait semaphore that all
+ // the component semaphores are also shared. Return an error if any
+ // of these conditions are not met.
+ //
+
+ if (Semaphore->Type == Os2MuxWaitSem) {
+ return( ERROR_WRONG_TYPE );
+ }
+
+ if (MuxWait->CountMuxWaitRecords == 0) {
+ MuxWait->Type = Semaphore->Type;
+ }
+ else
+ if (Semaphore->Type != MuxWait->Type) {
+ return( ERROR_WRONG_TYPE );
+ }
+
+ //
+ // At this point everything is copasthetic, so fill in the next available
+ // record in the MuxWait semaphore.
+ //
+
+ MuxWaitRecord->SemHandleIndex = (ULONG)MuxWaitEntry->hsemCur;
+ MuxWaitRecord->UserKey = MuxWaitEntry->ulUser;
+ MuxWaitRecord->Semaphore = Os2ReferenceSemaphore( Semaphore );
+ MuxWait->CountMuxWaitRecords++;
+
+ return( NO_ERROR );
+}
+
+
+APIRET
+Os2DeleteMuxWait(
+ IN POS2_MUXWAIT_SEMAPHORE MuxWait,
+ IN ULONG MuxWaitEntryIndex,
+ IN ULONG SemHandleIndex OPTIONAL
+ )
+{
+ POS2_MUXWAIT_RECORD MuxWaitRecord;
+ USHORT i;
+
+ if (MuxWait->CountMuxWaitRecords == 0) {
+ return( ERROR_EMPTY_MUXWAIT );
+ }
+
+ MuxWaitRecord = &MuxWait->MuxWaitRecords[ 0 ];
+ for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
+ if (ARGUMENT_PRESENT( SemHandleIndex )) {
+ if (MuxWaitRecord->SemHandleIndex == SemHandleIndex) {
+ break;
+ }
+ }
+ else
+ if ((ULONG)i == MuxWaitEntryIndex) {
+ break;
+ }
+
+ MuxWaitRecord++;
+ }
+
+ if (i == MuxWait->CountMuxWaitRecords) {
+ return( ERROR_INVALID_HANDLE );
+ }
+
+ Os2DereferenceSemaphore( MuxWaitRecord->Semaphore );
+ for (; i<MuxWait->CountMuxWaitRecords-1; i++) {
+ *MuxWaitRecord = *(MuxWaitRecord+1);
+ MuxWaitRecord++;
+ }
+ MuxWaitRecord->Semaphore = NULL;
+ MuxWaitRecord->SemHandleIndex = 0;
+ MuxWaitRecord->UserKey = 0;
+ MuxWait->CountMuxWaitRecords -= 1;
+
+ return( NO_ERROR );
+}
+
+
+BOOLEAN
+Os2DosCreateMuxWaitSem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSCREATEMUXWAITSEM_MSG a = &m->u.DosCreateMuxWaitSem;
+ OS2_SEMAPHORE Semaphore;
+ POS2_MUXWAIT_SEMAPHORE MuxWait;
+ PSEMRECORD MuxWaitEntries;
+ APIRET rc;
+ ULONG i;
+
+ UNREFERENCED_PARAMETER(t);
+ Semaphore.PointerCount = 0;
+ Semaphore.OpenCount = 1;
+ Semaphore.Type = Os2MuxWaitSem;
+ rc = Os2ProcessSemaphoreName( &a->ObjectName,
+ &Semaphore,
+ NULL
+ );
+
+ if (rc != NO_ERROR) {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+ }
+
+ //
+ // Private semaphore. Allocate the muxwait semaphore structure.
+ // Return error if not enough memory to allocate the structure.
+ //
+
+ MuxWait = RtlAllocateHeap( Os2Heap, 0, sizeof( *MuxWait ) );
+ if (MuxWait == NULL) {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ return( TRUE );
+ }
+
+ //
+ // Initialize the muxwait semaphore sturcture to contain zero records.
+ //
+
+ MuxWait->CountMuxWaitRecords = 0;
+ MuxWait->Type = 0;
+ MuxWait->WaitAll = (USHORT)((a->CreateAttributes & DCMW_WAIT_ALL) != 0);
+ MuxWait->Reserved = 0;
+
+
+ //
+ // Loop over the input array of SEMRECORDs adding them one at a time
+ // to the muxwait semaphore. Bail out of loop if any errors occur.
+ //
+
+ MuxWaitEntries = a->MuxWaitEntries;
+ for (i=0; i<a->CountMuxWaitEntries; i++) {
+ rc = Os2AddMuxWait( MuxWait,
+ MuxWaitEntries
+ );
+ if (rc != NO_ERROR) {
+ break;
+ }
+ else {
+ MuxWaitEntries++;
+ }
+ }
+
+
+ //
+ // All done. If successful, store the address of the muxwait structure
+ // in the semaphore structure.
+ //
+
+ if (rc == NO_ERROR) {
+ Semaphore.u.MuxWait = MuxWait;
+ }
+
+ if (rc != NO_ERROR ||
+ !Or2CreateHandle( Os2SharedSemaphoreTable,
+ &a->HandleIndex,
+ (PVOID)&Semaphore
+ )
+ ) {
+ RtlFreeHeap( Os2Heap, 0, MuxWait );
+ if (rc == NO_ERROR) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosOpenMuxWaitSem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSOPENMUXWAITSEM_MSG a = &m->u.DosOpenMuxWaitSem;
+ POS2_SEMAPHORE Semaphore;
+ APIRET rc;
+
+ UNREFERENCED_PARAMETER(t);
+ rc = Os2ProcessSemaphoreName( &a->ObjectName,
+ NULL,
+ &a->HandleIndex
+ );
+
+ if (rc != NO_ERROR || a->ObjectName.Length != 0) {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+ }
+
+ Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
+ a->HandleIndex,
+ TRUE
+ );
+ if (Semaphore == NULL) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+ else {
+ Semaphore->OpenCount++;
+ }
+
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosCloseMuxWaitSem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSCLOSEMUXWAITSEM_MSG a = &m->u.DosCloseMuxWaitSem;
+ POS2_SEMAPHORE Semaphore;
+ POS2_MUXWAIT_SEMAPHORE MuxWait;
+ USHORT i;
+ APIRET rc;
+
+ UNREFERENCED_PARAMETER(t);
+ Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
+ a->HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ rc = ERROR_INVALID_HANDLE;
+ }
+ else {
+ rc = NO_ERROR;
+
+ if (--Semaphore->OpenCount == 0) {
+ MuxWait = (POS2_MUXWAIT_SEMAPHORE)Os2DestroySemaphore(
+ Semaphore,
+ a->HandleIndex
+ );
+
+ for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
+ Os2DeleteMuxWait( MuxWait, i, 0 );
+ }
+ RtlFreeHeap( Os2Heap, 0, MuxWait );
+ }
+ else {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ }
+ }
+
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosWaitMuxWaitSem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ NTSTATUS Status;
+ POS2_DOSWAITMUXWAITSEM_MSG a = &m->u.DosWaitMuxWaitSem;
+ POS2_MUXWAIT_SEMAPHORE MuxWait;
+ POS2_MUXWAIT_RECORD MuxWaitRecord;
+ POS2_SEMAPHORE Semaphore;
+ APIRET rc;
+ USHORT i;
+ HANDLE NtHandles[ MAXIMUM_WAIT_OBJECTS ];
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+retry:
+ Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
+ a->HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ return( TRUE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is an MuxWait semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Os2MuxWaitSem) {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ return( TRUE );
+ }
+
+ MuxWait = Semaphore->u.MuxWait;
+
+ if (MuxWait->CountMuxWaitRecords == 0) {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ m->ReturnedErrorValue = ERROR_EMPTY_MUXWAIT;
+ return( TRUE );
+ }
+
+ MuxWaitRecord = &MuxWait->MuxWaitRecords[ 0 ];
+ for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
+ NtHandles[ i ] = MuxWaitRecord->Semaphore->u.Value;
+ MuxWaitRecord++;
+ }
+
+ Os2ThreadWaitingOnSemaphore( t, Semaphore, TRUE );
+
+ Status = NtWaitForMultipleObjects(
+ (CHAR)i,
+ NtHandles,
+ MuxWait->WaitAll ? WaitAll : WaitAny,
+ TRUE,
+ &a->Timeout
+ );
+ if (NT_SUCCESS( Status )) {
+ if (Status <= STATUS_WAIT_63) {
+ a->UserValue = MuxWait->MuxWaitRecords[ (ULONG)(Status & 0x3F)
+ ].UserKey;
+ rc = NO_ERROR;
+ }
+ else
+ if (Status == STATUS_ABANDONED) {
+ rc = ERROR_SEM_OWNER_DIED;
+ }
+ else
+ if (Status == STATUS_TIMEOUT) {
+ rc = ERROR_TIMEOUT;
+ }
+ else
+ if (Status == STATUS_USER_APC || Status == STATUS_ALERTED) {
+ rc = ERROR_SS_RETRY;
+ }
+ else {
+ rc = Or2MapNtStatusToOs2Error(Status, ERROR_SEM_TIMEOUT);
+ }
+ }
+ else {
+ rc = Or2MapNtStatusToOs2Error( Status, ERROR_SEM_TIMEOUT );
+ }
+
+ Os2ThreadWaitingOnSemaphore( t, Semaphore, FALSE );
+
+ if (rc == ERROR_SS_RETRY) {
+ goto retry;
+ }
+
+ m->ReturnedErrorValue = rc;
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosAddMuxWaitSem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSADDMUXWAITSEM_MSG a = &m->u.DosAddMuxWaitSem;
+ POS2_SEMAPHORE Semaphore;
+
+ UNREFERENCED_PARAMETER(t);
+
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
+ a->HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ return( TRUE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is an MuxWait semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Os2MuxWaitSem) {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ return( TRUE );
+ }
+
+ m->ReturnedErrorValue = Os2AddMuxWait( Semaphore->u.MuxWait,
+ &a->MuxWaitEntry
+ );
+
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosDeleteMuxWaitSem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSDELETEMUXWAITSEM_MSG a = &m->u.DosDeleteMuxWaitSem;
+ POS2_SEMAPHORE Semaphore;
+
+ UNREFERENCED_PARAMETER(t);
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
+ a->HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ return( TRUE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is an MuxWait semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Os2MuxWaitSem) {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ return( TRUE );
+ }
+
+ m->ReturnedErrorValue = Os2DeleteMuxWait( Semaphore->u.MuxWait,
+ 0,
+ a->EntryHandleIndex
+ );
+
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2InternalAlertMuxWaiter(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_ALERTMUXWAITER_MSG a = &m->u.AlertMuxWaiter;
+ POS2_THREAD Thread;
+ NTSTATUS Status;
+
+ Thread = Os2LocateThreadByThreadId( m, t, a->ThreadId );
+ Status = NtAlertThread( Thread->ThreadHandle );
+ if (!NT_SUCCESS( Status )) {
+ m->ReturnedErrorValue = Or2MapNtStatusToOs2Error( Status, ERROR_SEM_TIMEOUT );
+ }
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosQueryMuxWaitSem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSQUERYMUXWAITSEM_MSG a = &m->u.DosQueryMuxWaitSem;
+ PSEMRECORD MuxWaitEntries;
+ POS2_MUXWAIT_SEMAPHORE MuxWait;
+ POS2_MUXWAIT_RECORD MuxWaitRecord;
+ POS2_SEMAPHORE Semaphore;
+ USHORT i;
+
+
+ UNREFERENCED_PARAMETER(t);
+ //
+ // Map the semaphore handle into a pointer to the semaphore structure
+ // contained in the table. Return an error if the handle is outside
+ // the current limits of the table. If the mapping is successful then
+ // the semaphore table is left locked while we use the pointer.
+ //
+
+ Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
+ a->HandleIndex,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ return( TRUE );
+ }
+
+ //
+ // Entry in semaphore table exists, so make sure it is an MuxWait semaphore.
+ // Return an error if not, after unlock the table first.
+ //
+
+ if (Semaphore->Type != Os2MuxWaitSem) {
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ return( TRUE );
+ }
+
+ MuxWait = Semaphore->u.MuxWait;
+ if (a->CountMuxWaitEntries < (ULONG)(MuxWait->CountMuxWaitRecords)) {
+ m->ReturnedErrorValue = ERROR_PARAM_TOO_SMALL;
+ }
+ else {
+ a->CreateAttributes = DC_SEM_SHARED |
+ (MuxWait->WaitAll ? DCMW_WAIT_ALL : DCMW_WAIT_ANY);
+ MuxWaitEntries = a->MuxWaitEntries;
+ MuxWaitRecord = &MuxWait->MuxWaitRecords[ 0 ];
+ for (i=0; i<MuxWait->CountMuxWaitRecords; i++) {
+ MuxWaitEntries->hsemCur = (HSEM)MuxWaitRecord->SemHandleIndex;
+ MuxWaitEntries->ulUser = MuxWaitRecord->UserKey;
+ MuxWaitEntries++;
+ MuxWaitRecord++;
+ }
+ }
+ a->CountMuxWaitEntries = MuxWait->CountMuxWaitRecords;
+
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+
+ return( TRUE );
+}
diff --git a/private/os2/server/srvname.c b/private/os2/server/srvname.c
new file mode 100644
index 000000000..5f4251de1
--- /dev/null
+++ b/private/os2/server/srvname.c
@@ -0,0 +1,820 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvname.c
+
+Abstract:
+
+ This is the name space module for the OS/2 Subsystem Server
+
+Author:
+
+ Steve Wood (stevewo) 22-Aug-1989
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+ Yaron Shamir (yarons) 4-Apr-91: Added Os2ComputeValidDrives, to
+ fix initialization and computation of valid drives, to cope
+ with new SM initialization and with redirected drives .
+ Yaron Shamir (yarons) 6-May-91: changed the way we get at default
+ and boot drives (matches Dos now).
+ Yaron Shamir (yarons) 6-Aug-91: support named pipes.
+ Yaron Shamir (yarons) 26-Aug-91: support UNC names.
+ Beni Lavi (benil) 3-Mar-92: support mailslots
+ Michael Jarus (mjaruss) 31-Mar-93: Remove Os2ComputeValidDrives
+ Patrick Questembert (PatrickQ) 19-Mar-1995: Add COM10-16
+
+--*/
+
+#include "os2srv.h"
+#include "os2win.h"
+
+char * __cdecl getenv(char *varname);
+
+PSECURITY_DESCRIPTOR securityDescriptor;
+
+struct _INITIAL_OBJDIRS {
+ PWSTR Name;
+ PHANDLE Handle;
+} InitialObjectDirectories[] = {
+ {L"DEVICES", &Os2DevicesDirectory},
+ {L"QUEUES", NULL},
+ {L"SHAREMEM", NULL},
+ {L"SEMAPHORES", NULL},
+ {NULL, NULL}
+};
+
+
+struct _INITIAL_OBJDIRS Os2Drives =
+ {L"DRIVES", &Os2DrivesDirectory};
+
+HANDLE Os2NamedPipesDirectory;
+HANDLE Os2UNCDirectory;
+HANDLE Os2MailslotDirectory;
+HANDLE Os2RegistryDirectory;
+
+struct _INITIAL_RMT_OBJDIRS {
+ PWSTR Name;
+ PHANDLE Handle;
+ PWSTR TargetName;
+} InitialRmtObjectDirectories[] = {
+ {L"PIPE", &Os2NamedPipesDirectory, L"\\DosDevices\\PIPE" },
+ {L"UNC", &Os2UNCDirectory, L"\\DosDevices\\UNC" },
+ {L"MAILSLOT", &Os2MailslotDirectory, L"\\DosDevices\\MAILSLOT" },
+ {NULL, NULL, NULL}
+};
+
+//
+// The InitialDevices table contains the values of symbolic links for
+// special OS/2 files (devices).
+// The first character of the Target field is used to specifiy the type
+// of the device so that Od2Canonicalize() (in client\dllname.c) can
+// determine and return it. Following characters are the value of the
+// symbolic link which Od2Canonicalize returns as the canonicalized
+// file name.
+//
+// Current defined types (first character of the Target field) are:
+//
+// @ FILE_TYPE_PSDEV
+// # FILE_TYPE_COM
+// (space) FILE_TYPE_DEV
+//
+
+struct _INITIAL_DEVICES {
+ PWSTR Name;
+ PWSTR Target;
+} InitialDevices[] = {
+ {L"NUL" , L"@@0"},
+ {L"CON" , L"@@1"},
+ {L"AUX" , L"#\\DosDevices\\COM1"},
+ {L"COM1" , L"#\\DosDevices\\COM1"},
+ {L"COM2" , L"#\\DosDevices\\COM2"},
+ {L"COM3" , L"#\\DosDevices\\COM3"},
+ {L"COM4" , L"#\\DosDevices\\COM4"},
+ {L"COM5" , L"#\\DosDevices\\COM5"},
+ {L"COM6" , L"#\\DosDevices\\COM6"},
+ {L"COM7" , L"#\\DosDevices\\COM7"},
+ {L"COM8" , L"#\\DosDevices\\COM8"},
+ {L"COM9" , L"#\\DosDevices\\COM9"},
+ {L"COM10" , L"#\\DosDevices\\COM10"},
+ {L"COM11" , L"#\\DosDevices\\COM11"},
+ {L"COM12" , L"#\\DosDevices\\COM12"},
+ {L"COM13" , L"#\\DosDevices\\COM13"},
+ {L"COM14" , L"#\\DosDevices\\COM14"},
+ {L"COM15" , L"#\\DosDevices\\COM15"},
+ {L"COM16" , L"#\\DosDevices\\COM16"},
+ {L"PRN" , L" \\DosDevices\\LPT1"},
+ {L"LPT1" , L" \\DosDevices\\LPT1"},
+ {L"LPT2" , L" \\DosDevices\\LPT2"},
+ {L"LPT3" , L" \\DosDevices\\LPT3"},
+ {L"LPT4" , L" \\DosDevices\\LPT4"},
+ {L"LPT5" , L" \\DosDevices\\LPT5"},
+ {L"LPT6" , L" \\DosDevices\\LPT6"},
+ {L"LPT7" , L" \\DosDevices\\LPT7"},
+ {L"LPT8" , L" \\DosDevices\\LPT8"},
+ {L"LPT9" , L" \\DosDevices\\LPT9"},
+ {L"KBD$" , L"@@4"},
+ {L"MOUSE$" , L"@@5"},
+ {L"CLOCK$" , L"@@6"},
+ {L"SCREEN$" , L"@@7"},
+ {L"POINTER$" , L"@@8"},
+ {NULL, NULL}
+};
+
+CHAR DeviceDirectoryName[] = "\\Device\\";
+CHAR DeviceNameStr[] = "DEVICENAME";
+
+//
+// Information relevant for config.sys processing by the server
+//
+static WCHAR ConfigSysRegDir[] =
+L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\OS/2 Subsystem for NT\\1.0\\config.sys";
+static WCHAR ConfigSysValue[] = L"Config.Sys";
+
+// BUGBUG - Beni, move those to GetNextDeviceNameFromConfigDotSys
+static BOOLEAN ConfigDotSysWasRead = FALSE;
+static ULONG FileSize = 0;
+static ULONG CurrentOffset = 0;
+static ANSI_STRING ConfigSysValueData_A = {0, 0, NULL};
+
+//
+// Process the config.sys file
+// Returns TRUE if a line of the form:
+//
+// DEVICENAME=xxx [yyy]
+//
+// was detected in config.sys
+// The string 'xxx' is returned in DeviceName
+// If string 'yyy' is present its value is returned in TargetName
+// Otherwise, a NUL string is returned in TargetName
+//
+// This routine may be called multiple time. Each time it returns the next
+// DEVICENAME value string. When there are no more such values, the routine
+// returns FALSE.
+//
+// The information read from the registry is of type REG_MULTI_SZ
+// It used to be REG_SZ with CR-LF separating the lines. Therefore,
+// the code accepts both lines that terminate with CR-LF and lined
+// that terminate with NUL.
+//
+BOOLEAN
+GetNextDeviceNameFromConfigDotSys(
+ PSZ DeviceName,
+ PSZ TargetName
+ )
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES Obja;
+ PSZ Name;
+ PSZ TName;
+ CHAR ch;
+ UNICODE_STRING ConfigSysRegDir_U;
+ UNICODE_STRING ConfigSysValue_U;
+ UNICODE_STRING ConfigSysValueData_U;
+ HANDLE ConfigSysKeyHandle;
+ ULONG ResultLength;
+ KEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
+ PKEY_VALUE_PARTIAL_INFORMATION pInfo;
+
+ if (!ConfigDotSysWasRead)
+ {
+ //
+ // Copy the config.sys image from the registry to memory
+ //
+ RtlInitUnicodeString(&ConfigSysRegDir_U, ConfigSysRegDir);
+ InitializeObjectAttributes(&Obja,
+ &ConfigSysRegDir_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&ConfigSysKeyHandle,
+ KEY_READ,
+ &Obja
+ );
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG(CLEANUP)
+ {
+ KdPrint(("OS2SRV: FAILED - NtOpenKey() of config.sys %lx\n",
+ Status));
+ }
+#endif
+ return (FALSE);
+ }
+ RtlInitUnicodeString(&ConfigSysValue_U, ConfigSysValue);
+ Status = NtQueryValueKey(ConfigSysKeyHandle,
+ &ConfigSysValue_U,
+ KeyValuePartialInformation,
+ &KeyValuePartialInfo,
+ sizeof(KeyValuePartialInfo),
+ &ResultLength
+ );
+ if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_OVERFLOW))
+ {
+#if DBG
+ IF_OS2_DEBUG(CLEANUP) {
+ KdPrint(("OS2SRV: FAILED - NtQueryValueKey-1 %lx\n",
+ Status));
+ }
+#endif
+ return (FALSE);
+ }
+
+ pInfo = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(Os2Heap, 0, ResultLength);
+ if (pInfo == NULL)
+ {
+#if DBG
+ IF_OS2_DEBUG(CLEANUP)
+ {
+ KdPrint(("OS2SRV: FAILED - RtlAllocateHeap\n"));
+ }
+#endif
+ return (FALSE);
+ }
+
+ Status = NtQueryValueKey(ConfigSysKeyHandle,
+ &ConfigSysValue_U,
+ KeyValuePartialInformation,
+ pInfo,
+ ResultLength,
+ &ResultLength
+ );
+ NtClose(ConfigSysKeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG(CLEANUP)
+ {
+ KdPrint(("OS2SRV: FAILED - NtQueryValueKey %lx\n",
+ Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, pInfo);
+ return (FALSE);
+ }
+
+ //
+ // The information in the registry is Unicode.
+ // Convert it to ANSI. Initialize explicity the UNICODE_STRING
+ // structure since the data in the registry is of type REG_MULTI_SZ
+ // and hence contains embedded NULs.
+ //
+
+ ConfigSysValueData_U.Buffer = (PWSTR)pInfo->Data;
+ ConfigSysValueData_U.Length = (USHORT)pInfo->DataLength - 2;
+ ConfigSysValueData_U.MaximumLength = (USHORT)pInfo->DataLength;
+
+ Status = RtlUnicodeStringToAnsiString(&ConfigSysValueData_A,
+ &ConfigSysValueData_U, TRUE);
+ RtlFreeHeap(Os2Heap, 0, pInfo);
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG(CLEANUP)
+ {
+ KdPrint(("OS2SRV: FAILED - RtlUnicodeStringToAnsiString %lx\n",
+ Status));
+ }
+#endif
+ return (FALSE);
+ }
+
+ FileSize = ConfigSysValueData_A.Length;
+ CurrentOffset = 0;
+ ConfigDotSysWasRead = TRUE;
+ }
+
+ while (CurrentOffset < FileSize)
+ {
+ // skip leading blanks
+ while ((ConfigSysValueData_A.Buffer[CurrentOffset] == ' ') ||
+ (ConfigSysValueData_A.Buffer[CurrentOffset] == '\t'))
+ {
+ CurrentOffset++;
+ if (CurrentOffset >= FileSize)
+ {
+ RtlFreeAnsiString(&ConfigSysValueData_A);
+ return (FALSE);
+ }
+ }
+ if ((CurrentOffset + sizeof(DeviceNameStr) - 1) >= FileSize)
+ {
+ RtlFreeAnsiString(&ConfigSysValueData_A);
+ return (FALSE);
+ }
+ // check if the first name in the line is DEVICENAME
+ if (_strnicmp(&ConfigSysValueData_A.Buffer[CurrentOffset], DeviceNameStr, sizeof(DeviceNameStr)-1)) {
+ while ((ConfigSysValueData_A.Buffer[CurrentOffset] != '\n') &&
+ (ConfigSysValueData_A.Buffer[CurrentOffset] != '\0'))
+ {
+ CurrentOffset++;
+ if (CurrentOffset >= FileSize)
+ {
+ RtlFreeAnsiString(&ConfigSysValueData_A);
+ return (FALSE);
+ }
+ }
+ CurrentOffset++;
+ continue;
+ }
+ CurrentOffset += sizeof(DeviceNameStr)-1;
+ // skip possible blanks between DEVICENAME and =
+ while ((ConfigSysValueData_A.Buffer[CurrentOffset] == ' ') ||
+ (ConfigSysValueData_A.Buffer[CurrentOffset] == '\t'))
+ {
+ CurrentOffset++;
+ if (CurrentOffset >= FileSize)
+ {
+ RtlFreeAnsiString(&ConfigSysValueData_A);
+ return (FALSE);
+ }
+ }
+ // verify that there is an = after the DEVICENAME
+ if (ConfigSysValueData_A.Buffer[CurrentOffset] != '=')
+ {
+ while ((ConfigSysValueData_A.Buffer[CurrentOffset] != '\n') &&
+ (ConfigSysValueData_A.Buffer[CurrentOffset] != '\0'))
+ {
+ CurrentOffset++;
+ if (CurrentOffset >= FileSize)
+ {
+ RtlFreeAnsiString(&ConfigSysValueData_A);
+ return (FALSE);
+ }
+ }
+ CurrentOffset++;
+ continue;
+ }
+ else
+ {
+ CurrentOffset++; // skip the '='
+ if (CurrentOffset >= FileSize)
+ {
+ RtlFreeAnsiString(&ConfigSysValueData_A);
+ return (FALSE);
+ }
+ }
+ // skip possible blanks between = and the device name
+ while ((ConfigSysValueData_A.Buffer[CurrentOffset] == ' ') ||
+ (ConfigSysValueData_A.Buffer[CurrentOffset] == '\t'))
+ {
+ CurrentOffset++;
+ if (CurrentOffset >= FileSize)
+ {
+ RtlFreeAnsiString(&ConfigSysValueData_A);
+ return (FALSE);
+ }
+ }
+ // process the device name
+
+ Name = DeviceName;
+ while (((ch = ConfigSysValueData_A.Buffer[CurrentOffset]) != '\r') &&
+ (ch != '\n') &&
+ (ch != ' ') &&
+ (ch != '\t') &&
+ (ch != '\0')
+ )
+ {
+ *Name++ = ch;
+ CurrentOffset++;
+ if (CurrentOffset >= FileSize)
+ {
+ *Name = '\0';
+ return (TRUE);
+ }
+ }
+ *Name = '\0';
+ if (*DeviceName == '\0')
+ {
+ //
+ // Null device name, return false
+ //
+ RtlFreeAnsiString(&ConfigSysValueData_A);
+ return (FALSE);
+ }
+ // skip possible blanks and commas between the Device name and the Target name
+ while ((ConfigSysValueData_A.Buffer[CurrentOffset] == ' ') ||
+ (ConfigSysValueData_A.Buffer[CurrentOffset] == ',') ||
+ (ConfigSysValueData_A.Buffer[CurrentOffset] == '\t'))
+ {
+ CurrentOffset++;
+ if (CurrentOffset >= FileSize)
+ {
+ RtlFreeAnsiString(&ConfigSysValueData_A);
+ return (FALSE);
+ }
+ }
+ // process the device target name
+ TName = TargetName;
+ // first put a blank to match the rest of the devices
+ *TName++ = ' ';
+ while (((ch = ConfigSysValueData_A.Buffer[CurrentOffset]) != '\r') &&
+ (ch != '\n') &&
+ (ch != ' ') &&
+ (ch != '\t') &&
+ (ch != '\0')
+ )
+ {
+ *TName++ = ch;
+ CurrentOffset++;
+ if (CurrentOffset >= FileSize)
+ {
+ *TName = '\0';
+ return (TRUE);
+ }
+ }
+ *TName = '\0';
+ // did we have a target name?
+ if (TName == (TargetName+1))
+ {
+ // No - it's only the space we had put - nullify
+ *TargetName = '\0';
+ }
+
+ while ((ConfigSysValueData_A.Buffer[CurrentOffset] != '\n') &&
+ (ConfigSysValueData_A.Buffer[CurrentOffset] != '\0'))
+ {
+ CurrentOffset++;
+ if (CurrentOffset >= FileSize)
+ {
+ return (TRUE);
+ }
+ }
+ CurrentOffset++;
+ return (TRUE);
+ }
+
+ RtlFreeAnsiString(&ConfigSysValueData_A);
+ return (FALSE);
+}
+
+
+NTSTATUS
+Os2InitializeNameSpace( VOID )
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING DirectoryName_U;
+ HANDLE DirectoryHandle;
+ PHANDLE Directory;
+ UNICODE_STRING LinkTarget_U, LinkName_U;
+ HANDLE LinkHandle;
+ CHAR localSecurityDescriptor[SECURITY_DESCRIPTOR_MIN_LENGTH];
+ ULONG i;
+ ANSI_STRING DeviceName_A;
+ ANSI_STRING TargetDeviceName_A;
+ CHAR DeviceName[32];
+ CHAR TargetDeviceName[48];
+
+ //
+ // Create a root directory in the object name space that will be used
+ // to contain all of the named objects created by the OS/2 Emulation
+ // subsystem.
+ //
+
+ RtlInitUnicodeString( &DirectoryName_U, OS2_SS_ROOT_OBJECT_DIRECTORY );
+
+ Status = RtlCreateSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION );
+ ASSERT( NT_SUCCESS( Status ) );
+ if (! NT_SUCCESS( Status )) {
+ return Status;
+ }
+
+ Status = RtlSetDaclSecurityDescriptor( (PSECURITY_DESCRIPTOR)
+ &localSecurityDescriptor,
+ (BOOLEAN)TRUE,
+ (PACL) NULL,
+ (BOOLEAN)FALSE );
+ ASSERT (NT_SUCCESS(Status));
+ if (! NT_SUCCESS( Status )) {
+ return Status;
+ }
+
+ securityDescriptor = (PSECURITY_DESCRIPTOR) &localSecurityDescriptor;
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &DirectoryName_U,
+ OBJ_CASE_INSENSITIVE,
+// OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
+ NULL,
+ securityDescriptor
+ );
+
+ Status = NtOpenDirectoryObject( &Os2RootDirectory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes
+ );
+
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+ {
+ ULONG i = 100; // 10 seconds
+
+#if DBG
+ KdPrint(("OS2SRV: wait for os2ss to initialize\n"));
+#endif
+ while (Status == STATUS_OBJECT_NAME_NOT_FOUND && i > 0)
+ {
+ //
+ // Wait 0.1 sec for os2ss to complete initialization
+ //
+ Sleep (100L);
+#if DBG
+ KdPrint(("."));
+#endif
+ Status = NtOpenDirectoryObject( &Os2RootDirectory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes
+ );
+ i--;
+ }
+ }
+ if (! NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(("OS2SRV: SubSystem = Can't open \\os2ss directory object\n"));
+#endif
+ return Status;
+ }
+
+ //
+ // Make the Drives directory a symbolic link
+ // of \DosDevices
+ //
+ RtlInitUnicodeString( &DirectoryName_U, Os2Drives.Name );
+ RtlInitUnicodeString( &LinkTarget_U, L"\\DosDevices" );
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &DirectoryName_U,
+ // OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
+ OBJ_CASE_INSENSITIVE,
+ Os2RootDirectory,
+ securityDescriptor
+ );
+ Status = NtCreateSymbolicLinkObject( Os2Drives.Handle,
+ SYMBOLIC_LINK_ALL_ACCESS,
+ &ObjectAttributes,
+ &LinkTarget_U
+ );
+ if (Status == STATUS_OBJECT_NAME_COLLISION) {
+ //
+ // An os2srv is already present, print out and exit
+ //
+#if DBG
+ KdPrint(( "OS2SRV: Unable to initialize server. An instance of OS2SRV already runs. Status == %X\n",
+ Status
+ ));
+#endif
+
+ NtTerminateProcess( NtCurrentProcess(), Status );
+ }
+
+ ASSERT (NT_SUCCESS(Status));
+ if (! NT_SUCCESS( Status )) {
+ return Status;
+ }
+
+ for (i=0; InitialObjectDirectories[ i ].Name; i++) {
+ RtlInitUnicodeString( &DirectoryName_U, InitialObjectDirectories[ i ].Name );
+ Directory = InitialObjectDirectories[ i ].Handle;
+ if (Directory == NULL) {
+ Directory = &DirectoryHandle;
+ }
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &DirectoryName_U,
+ // OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
+ OBJ_CASE_INSENSITIVE,
+ Os2RootDirectory,
+ securityDescriptor
+ );
+ Status = NtCreateDirectoryObject( Directory,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes
+ );
+ ASSERT( NT_SUCCESS( Status ) );
+ if (! NT_SUCCESS( Status )) {
+ KdPrint(("OS2SRV: FAILED - NtCreateDirectoryObject stts= %lx\n",
+ Status));
+ return Status;
+ }
+
+ if (Directory == &DirectoryHandle) {
+ NtClose( DirectoryHandle );
+ }
+ }
+
+ for (i=0; InitialDevices[ i ].Name; i++) {
+ RtlInitUnicodeString( &LinkName_U, InitialDevices[ i ].Name );
+ RtlInitUnicodeString( &LinkTarget_U, InitialDevices[ i ].Target );
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &LinkName_U,
+ // OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
+ OBJ_CASE_INSENSITIVE,
+ Os2DevicesDirectory,
+ securityDescriptor
+ );
+ Status = NtCreateSymbolicLinkObject( &LinkHandle,
+ SYMBOLIC_LINK_ALL_ACCESS,
+ &ObjectAttributes,
+ &LinkTarget_U
+ );
+ ASSERT( NT_SUCCESS( Status ) );
+ if (! NT_SUCCESS( Status )) {
+ return Status;
+ }
+
+// NtClose( LinkHandle );
+ }
+
+ //
+ // Make the remote directories a symbolic link of \DosDevices\*
+ //
+ for (i =0; InitialRmtObjectDirectories[i].Name != NULL; i++) {
+ RtlInitUnicodeString( &DirectoryName_U, InitialRmtObjectDirectories[i].Name );
+ RtlInitUnicodeString( &LinkTarget_U, InitialRmtObjectDirectories[i].TargetName);
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &DirectoryName_U,
+ OBJ_CASE_INSENSITIVE,
+ // OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
+ Os2RootDirectory,
+ securityDescriptor
+ );
+ Status = NtCreateSymbolicLinkObject( InitialRmtObjectDirectories[i].Handle,
+ SYMBOLIC_LINK_ALL_ACCESS,
+ &ObjectAttributes,
+ &LinkTarget_U
+ );
+ ASSERT( NT_SUCCESS( Status ) );
+ if (! NT_SUCCESS( Status )) {
+ return Status;
+ }
+ }
+
+ //
+ // Process config.sys for the DEVICENAME= definitions
+ //
+
+ while (GetNextDeviceNameFromConfigDotSys(DeviceName, TargetDeviceName))
+ {
+#if DBG
+ if (TargetDeviceName[0] == '\0') {
+ KdPrint(("OS2SRV: Read DEVICENAME=%s from config.sys\n", DeviceName));
+ }
+ else {
+ KdPrint(("OS2SRV: Read DEVICENAME=%s %s from config.sys\n",
+ DeviceName, TargetDeviceName));
+ }
+#endif
+ RtlInitAnsiString(&DeviceName_A, DeviceName);
+ RtlAnsiStringToUnicodeString( &LinkName_U, &DeviceName_A, (BOOLEAN)TRUE );
+ if (TargetDeviceName[0] == '\0') {
+ strcpy(TargetDeviceName, DeviceDirectoryName);
+ strcat(TargetDeviceName, DeviceName);
+ }
+ RtlInitAnsiString(&TargetDeviceName_A, TargetDeviceName);
+ RtlAnsiStringToUnicodeString( &LinkTarget_U, &TargetDeviceName_A, (BOOLEAN)TRUE );
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &LinkName_U,
+ OBJ_CASE_INSENSITIVE,
+ Os2DevicesDirectory,
+ securityDescriptor
+ );
+ Status = NtCreateSymbolicLinkObject( &LinkHandle,
+ SYMBOLIC_LINK_ALL_ACCESS,
+ &ObjectAttributes,
+ &LinkTarget_U
+ );
+ RtlFreeUnicodeString(&LinkName_U);
+ RtlFreeUnicodeString(&LinkTarget_U);
+
+ if (! NT_SUCCESS( Status )) {
+#if DBG
+ KdPrint(("OS2SRV: Could not Link Device '%s' to target devices\n", DeviceName));
+#endif
+ }
+ }
+
+ return( Os2InitializeDriveLetters() );
+}
+
+
+BOOLEAN
+Os2CheckValidCDrives(VOID)
+{
+ NTSTATUS Status;
+ HANDLE LinkHandle;
+ UNICODE_STRING DriveName_U;
+ WCHAR DriveString[15] = L"\\DosDevices\\C:";
+ OBJECT_ATTRIBUTES Attributes;
+
+ //
+ // compute the valid drives from scratch, since
+ // redirected drives appear and disappear dynamically
+ //
+
+ RtlInitUnicodeString(&DriveName_U, DriveString);
+
+ InitializeObjectAttributes(
+ &Attributes,
+ &DriveName_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtOpenSymbolicLinkObject( &LinkHandle,
+ SYMBOLIC_LINK_QUERY,
+ &Attributes
+ );
+ if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
+
+ NtClose( LinkHandle );
+ return(TRUE);
+ }
+ return (FALSE);
+}
+
+
+NTSTATUS
+Os2InitializeDriveLetters( VOID )
+{
+ //
+ // Set the SystemDrive number from the environment
+ //
+
+ SystemRootValuePtr = getenv("SYSTEMROOT");
+ if (SystemRootValuePtr == NULL) {
+ SystemRootValuePtr = "C:\\";
+ }
+ Os2DefaultDrive = (ULONG)(RtlUpperChar(*SystemRootValuePtr) - 'A');
+
+ Os2BootDrive = 2; // C:
+
+ //
+ // check if not C:
+ //
+
+ if (!Os2CheckValidCDrives()) {
+ Os2BootDrive = 0; // A:
+ if (Os2DefaultDrive == 2) {
+ Os2DefaultDrive = 0; // A:
+ }
+ }
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+Os2GetClientId( VOID )
+{
+ NTSTATUS Status;
+ HANDLE LinkHandle;
+ OBJECT_ATTRIBUTES Attributes;
+ UNICODE_STRING DebugClientId_U;
+ UNICODE_STRING ClientIdString_U;
+
+ Os2DebugUserClientId.UniqueProcess = NULL;
+
+ RtlInitUnicodeString(&DebugClientId_U, L"DebugClientId");
+ InitializeObjectAttributes(
+ &Attributes,
+ &DebugClientId_U,
+ OBJ_CASE_INSENSITIVE,
+ Os2RootDirectory,
+ NULL);
+ Status = NtOpenSymbolicLinkObject( &LinkHandle,
+ SYMBOLIC_LINK_QUERY,
+ &Attributes
+ );
+
+ if (!NT_SUCCESS( Status )) {
+ return Status;
+ }
+
+ ClientIdString_U.Buffer = (PWSTR)&Os2DebugUserClientId;
+ ClientIdString_U.Length = 0;
+ ClientIdString_U.MaximumLength = sizeof( Os2DebugUserClientId );
+ Status = NtQuerySymbolicLinkObject( LinkHandle,
+ &ClientIdString_U,
+ NULL
+ );
+
+ if (!NT_SUCCESS( Status )) {
+ return Status;
+ }
+
+ return Status;
+}
diff --git a/private/os2/server/srvnet.c b/private/os2/server/srvnet.c
new file mode 100644
index 000000000..dcfa71b8c
--- /dev/null
+++ b/private/os2/server/srvnet.c
@@ -0,0 +1,415 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvnet.c
+
+Abstract:
+
+ Net related code.
+
+Author:
+
+ Ofer Porat (oferp) 5-10-93
+
+Revision History:
+
+--*/
+
+#include "os2srv.h"
+#include "os2win.h"
+#define CALLBACK
+#include <nb30.h>
+#include "nb30p.h"
+
+static BOOLEAN Os2Netbios2Initialized = FALSE; // server nb 2.0 initialization flag
+static HANDLE Os2NbDev; // holds handle to netbios device
+static HANDLE Os2NbEvent; // holds event for issuing NCBs
+static LANA_ENUM Os2LanaEnum; // holds enumeration of lana numbers in the system
+static UCHAR Os2LanaState[MAX_LANA]; // indicates whether lana has been reset
+
+
+NTSTATUS
+Os2NetbiosDirect(
+ PNCB pNcb,
+ HANDLE hDev,
+ HANDLE hEvent
+ )
+{
+ //
+ // a direct sync request. does not support chain sends.
+ //
+
+ IO_STATUS_BLOCK iosb;
+ NTSTATUS Status;
+ PVOID buffer;
+ ULONG length;
+
+ Status = NtResetEvent(
+ hEvent,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( NET ) {
+ KdPrint(("Os2NetbiosDirect: NtResetEvent failed, Status = %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+
+ pNcb->ncb_retcode = 0xff;
+ pNcb->ncb_cmd_cplt = 0xff;
+ buffer = (PVOID) pNcb->ncb_buffer;
+ length = (ULONG) pNcb->ncb_length;
+
+ Status = NtDeviceIoControlFile(
+ hDev,
+ hEvent, // private event
+ NULL, // APC Routine
+ NULL, // APC Context
+ &iosb, // IO Status block
+ IOCTL_NB_NCB,
+ pNcb, // InputBuffer
+ sizeof(NCB),
+ buffer, // Outputbuffer
+ length);
+
+ if (Status != STATUS_PENDING) {
+ pNcb->ncb_cmd_cplt = pNcb->ncb_retcode;
+ return(Status);
+ }
+
+ Status = NtWaitForSingleObject(
+ hEvent,
+ TRUE,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( NET ) {
+ KdPrint(("Os2NetbiosDirect: NtWaitForSingleObject failed, Status = %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+
+ pNcb->ncb_cmd_cplt = pNcb->ncb_retcode;
+ return(STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+Os2InitializeNetbios2(
+ VOID
+ )
+{
+ //
+ // opens \device\netbios
+ // enumerates lana numbers
+ // zeros lanastate
+ //
+
+ NCB ncb;
+ PNCB pNcb = &ncb;
+ IO_STATUS_BLOCK iosb;
+ OBJECT_ATTRIBUTES objattr;
+ UNICODE_STRING unicode;
+ NTSTATUS Status;
+ HANDLE hDev;
+ HANDLE hEvent;
+
+ if (((ULONG)pNcb & 3) != 0) { // pointer must be DWORD aligned
+ return(STATUS_DATATYPE_MISALIGNMENT);
+ }
+
+ Status = NtCreateEvent(
+ &hEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ NotificationEvent,
+ TRUE);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( NET ) {
+ KdPrint(("Os2InitializeNetbios2: NtCreateEvent failed, Status = %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+
+ RtlInitUnicodeString( &unicode, NB_DEVICE_NAME);
+ InitializeObjectAttributes(
+ &objattr, // obj attr to initialize
+ &unicode, // string to use
+ OBJ_CASE_INSENSITIVE, // Attributes
+ NULL, // Root directory
+ NULL); // Security Descriptor
+
+ Status = NtCreateFile(
+ &hDev, // ptr to handle
+ GENERIC_READ // desired...
+ | GENERIC_WRITE, // ...access
+ &objattr, // name & attributes
+ &iosb, // I/O status block.
+ NULL, // alloc size.
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_DELETE // share...
+ | FILE_SHARE_READ
+ | FILE_SHARE_WRITE, // ...access
+ FILE_OPEN_IF, // create disposition
+ 0, // ...options
+ NULL, // EA buffer
+ 0L ); // Ea buffer len
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( NET ) {
+ KdPrint(("Os2InitializeNetbios2: NtCreateFile failed, Status = %lx\n", Status));
+ }
+#endif
+ NtClose(hEvent);
+ return(Status);
+ }
+
+ RtlZeroMemory(pNcb, sizeof(NCB));
+
+ pNcb->ncb_command = NCBENUM;
+ pNcb->ncb_buffer = (PUCHAR) &Os2LanaEnum;
+ pNcb->ncb_length = sizeof(LANA_ENUM);
+
+ Status = Os2NetbiosDirect(pNcb, hDev, hEvent);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( NET ) {
+ KdPrint(("Os2InitializeNetbios2: Lana enumeration failed, Status = %lx\n", Status));
+ }
+#endif
+ NtClose(hDev);
+ NtClose(hEvent);
+ return(Status);
+ }
+
+ if (pNcb->ncb_retcode != NRC_GOODRET ||
+ Os2LanaEnum.length == 0) {
+#if DBG
+ IF_OS2_DEBUG( NET ) {
+ KdPrint(("Os2InitializeNetbios2: Lana enumeration failed, ncb_retcode = 0x%x, num of lanas = %d\n",
+ pNcb->ncb_retcode, Os2LanaEnum.length));
+ }
+#endif
+ NtClose(hDev);
+ NtClose(hEvent);
+ return(STATUS_NETWORK_ACCESS_DENIED);
+ }
+
+ RtlZeroMemory(Os2LanaState, sizeof(Os2LanaState));
+ Os2NbEvent = hEvent;
+ Os2NbDev = hDev;
+ Os2Netbios2Initialized = TRUE;
+ return(STATUS_SUCCESS);
+}
+
+
+VOID
+Os2Nb2InitUser(
+ IN HANDLE ClientProcess,
+ OUT POS2_NETBIOS_MSG a
+ )
+{
+ NTSTATUS Status;
+ HANDLE TargetHandle;
+
+ a->LanaEnumLength = Os2LanaEnum.length;
+ RtlMoveMemory(a->LanaEnum, Os2LanaEnum.lana, MAX_LANA);
+
+ Status = NtDuplicateObject(
+ NtCurrentProcess(),
+ Os2NbDev,
+ ClientProcess,
+ &TargetHandle,
+ 0L,
+ 0L,
+ DUPLICATE_SAME_ACCESS
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( NET ) {
+ KdPrint(("Os2Nb2InitUser: NtDuplicateObject failed, Status = %lx\n", Status));
+ }
+#endif
+ a->ReturnStatus = Status;
+ return;
+ }
+
+ a->hDev = TargetHandle;
+
+ return;
+}
+
+
+NTSTATUS
+Os2ResetLana(
+ IN UCHAR LanaNum
+ )
+{
+ NCB ncb;
+ PNCB pNcb = &ncb;
+ NTSTATUS Status;
+
+ if (LanaNum >= Os2LanaEnum.length) {
+ return(STATUS_INVALID_PARAMETER);
+ }
+
+ if (((ULONG)pNcb & 3) != 0) { // pointer must be DWORD aligned
+ return(STATUS_DATATYPE_MISALIGNMENT);
+ }
+
+ RtlZeroMemory(pNcb, sizeof(NCB));
+
+ pNcb->ncb_command = NCBRESET;
+ pNcb->ncb_callname[0] = 0xff;
+ pNcb->ncb_callname[1] = 0xff;
+ pNcb->ncb_callname[2] = 0xff;
+ pNcb->ncb_callname[3] = 1;
+ pNcb->ncb_lana_num = Os2LanaEnum.lana[LanaNum];
+
+ Status = Os2NetbiosDirect(pNcb, Os2NbDev, Os2NbEvent);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( NET ) {
+ KdPrint(("Os2ResetLana: Os2NetbiosDirect failed, Status = %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+
+ if (pNcb->ncb_retcode != NRC_GOODRET) {
+#if DBG
+ IF_OS2_DEBUG( NET ) {
+ KdPrint(("Os2ResetLana: Os2NetbiosDirect failed, ncb_retcode = 0x%x\n", pNcb->ncb_retcode));
+ }
+#endif
+ return(STATUS_NETWORK_ACCESS_DENIED);
+ }
+
+ Os2LanaState[LanaNum] = 0x1;
+
+ return(STATUS_SUCCESS);
+}
+
+
+VOID
+Os2Nb2InitLana(
+ IN OUT POS2_NETBIOS_MSG a
+ )
+{
+ UCHAR Net;
+ NTSTATUS Status;
+
+ if (a->NetNumber == 0) { // use default net ?
+ if (Os2LanaEnum.length >= DEFAULT_NET) {
+ Net = DEFAULT_NET - 1;
+ } else {
+ Net = 0;
+ }
+ } else {
+ if (Os2LanaEnum.length >= a->NetNumber) {
+ Net = a->NetNumber - 1;
+ } else {
+#if DBG
+ IF_OS2_DEBUG( NET ) {
+ KdPrint(("Os2Nb2InitLana: Got request for invalid Net = %d\n", a->NetNumber));
+ }
+#endif
+ a->RetCode = NB2ERR_INVALID_LANA;
+ return;
+ }
+ }
+
+ if (Os2LanaState[Net] == 0x1) {
+
+ //
+ // already reset
+ //
+
+ return;
+ }
+
+ Status = Os2ResetLana(Net);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( NET ) {
+ KdPrint(("Os2Nb2InitLana: Os2ResetLana failed, Status = %lx\n", Status));
+ }
+#endif
+
+ a->ReturnStatus = Status;
+ }
+}
+
+
+BOOLEAN
+Os2Netbios2Request(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_NETBIOS_MSG a = &m->u.Netbios2Request;
+ NTSTATUS Status;
+
+ a->RetCode = NB2ERR_SUCCESS;
+ a->ReturnStatus = STATUS_SUCCESS;
+
+ if (!Os2Netbios2Initialized) {
+
+ Status = Os2InitializeNetbios2();
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( NET ) {
+ KdPrint(("Os2Netbios2Request: Os2InitializeNetbios2 failed, Status = %lx\n", Status));
+ }
+#endif
+ a->ReturnStatus = Status;
+ return(TRUE);
+ }
+ }
+
+ switch (a->RequestType) {
+
+ case NB2_INIT:
+
+ Os2Nb2InitUser(t->Process->ProcessHandle, a);
+ break;
+
+ case NB2_INIT_LANA:
+
+ Os2Nb2InitUser(t->Process->ProcessHandle, a);
+ if (NT_SUCCESS(a->ReturnStatus) &&
+ a->RetCode == NB2ERR_SUCCESS) {
+ Os2Nb2InitLana(a);
+ }
+ break;
+
+ case NB2_LANA:
+
+ Os2Nb2InitLana(a);
+ break;
+
+ default:
+
+ a->RetCode = NB2ERR_INVALID_REQUEST;
+ break;
+ }
+
+ return(TRUE);
+}
+
diff --git a/private/os2/server/srvnls.c b/private/os2/server/srvnls.c
new file mode 100644
index 000000000..52ad539dc
--- /dev/null
+++ b/private/os2/server/srvnls.c
@@ -0,0 +1,1410 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvnls.c
+
+Abstract:
+
+ This module contains the support for NLS for the OS/2 Subsystem Server
+
+Author:
+
+ Michael Jarus (mjarus) 25-Aug-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include <windows.h>
+#define WIN32_ONLY
+#include "sesport.h"
+#include "os2nt.h"
+#include "os2dbg.h"
+#include <stdio.h>
+#include <string.h>
+
+#include "os2crt.h"
+
+// Flag to let OS2SRV know whether or not to ignore LOGOFF (when started as a service)
+extern BOOLEAN fService;
+
+//
+// Counted String
+//
+
+typedef struct _STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+#ifdef MIDL_PASS
+ [size_is(MaximumLength), length_is(Length) ]
+#endif // MIDL_PASS
+ PCHAR Buffer;
+} STRING;
+typedef STRING *PSTRING;
+
+typedef STRING ANSI_STRING;
+typedef PSTRING PANSI_STRING;
+
+//
+// Unicode strings are counted 16-bit character strings. If they are
+// NULL terminated, Length does not include trailing NULL.
+//
+
+typedef struct _UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+#ifdef MIDL_PASS
+ [size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
+#else // MIDL_PASS
+ PWSTR Buffer;
+#endif // MIDL_PASS
+} UNICODE_STRING;
+typedef UNICODE_STRING *PUNICODE_STRING;
+
+VOID
+RtlInitUnicodeString(
+ PUNICODE_STRING DestinationString,
+ PCWSTR SourceString
+ );
+
+APIRET
+Or2UnicodeStringToMBString(
+ PANSI_STRING DestinationString,
+ PUNICODE_STRING SourceString,
+ BOOLEAN AllocateDestinationString);
+
+ULONG Or2ProcessCodePage;
+ULONG Or2CurrentCodePageIsOem;
+PSZ Os2ServerSystemDirectory;
+HKEY KeyboardLayoutKeyHandle = NULL;
+HANDLE hKeyEvent;
+BOOL KeyboardFromConfigSysRegistry = FALSE;
+OS2_SES_GROUP_PARMS ServerSesGrp;
+
+#define XCPT_SIGNAL_KILLPROC 3
+#define WBUFFER_SIZE 6
+
+BOOL
+Os2SrvHandleCtrlEvent(
+ IN int CtrlType
+ );
+
+ULONG
+Or2NlsUnicodeStringToInteger(
+ IN WCHAR *WString,
+ IN ULONG Base
+ );
+
+extern WCHAR Os2SystemDirectory[];
+extern ULONG Os2Debug;
+extern ULONG Os2ssCountryCode;
+extern ULONG Os2ssCodePage[2];
+extern UCHAR Os2ssKeyboardLayout[2];
+#if PMNT
+extern UCHAR Os2ssKeyboardName[4];
+#endif
+extern ULONG Os2ssKeysOnFlag;
+extern ULONG Os2SrvExitNow;
+
+#if DBG
+BYTE SetEventHandlersAndErrorModeStr[] = "SetEventHandlersAndErrorMode";
+BYTE Os2InitializeNLSStr[] = "Os2InitializeNLS";
+#endif
+
+typedef struct _LANG_TABLE_ENTRY {
+ ULONG Ctry;
+ ULONG Lang;
+ ULONG SubLang;
+ ULONG Cp1;
+ ULONG Cp2;
+ ULONG MessageLanguage;
+} LANG_TABLE_ENTRY, *PLANG_TABLE_ENTRY;
+
+
+PLANG_TABLE_ENTRY
+CheckCountryCodePage(
+ IN ULONG CountryCode,
+ IN ULONG *Os2srvCodePages,
+ OUT ULONG *CodePages
+ );
+
+ULONG
+InitKeyboardRegistry(
+ VOID
+ );
+
+ULONG
+ReadKeyboardLayoutFromRegistry(
+ OUT PULONG pKeyBoardCountry
+ );
+
+LANG_TABLE_ENTRY LANG_TABLE [] =
+ {
+ { /* United States */
+
+ CTRY_UNITED_STATES,
+ LANG_ENGLISH,
+ SUBLANG_ENGLISH_US,
+ CODEPAGE_US,
+ CODEPAGE_MULTI,
+ LANG_ENGLISH,
+ },
+ { /* Canadian-French */
+
+ CTRY_CANADA,
+ LANG_FRENCH,
+ SUBLANG_FRENCH_CANADIAN,
+ CODEPAGE_CANADIAN,
+ CODEPAGE_MULTI,
+ LANG_ENGLISH,
+ },
+ { /* Latin-America */
+
+ COUNTRY_LATIN_AMERICA,
+ LANG_SPANISH,
+ SUBLANG_SPANISH_MEXICAN,
+ CODEPAGE_US,
+ CODEPAGE_MULTI,
+ LANG_SPANISH,
+ },
+ { /* Netherlands */
+
+ CTRY_NETHERLANDS,
+ LANG_DUTCH,
+ SUBLANG_DUTCH,
+ CODEPAGE_MULTI,
+ CODEPAGE_US,
+ LANG_DUTCH,
+ },
+ { /* Belgiun */
+
+ CTRY_BELGIUM,
+ LANG_FRENCH,
+ SUBLANG_FRENCH_BELGIAN,
+ CODEPAGE_MULTI,
+ CODEPAGE_US,
+ LANG_DUTCH,
+ },
+ { /* France */
+
+ CTRY_FRANCE,
+ LANG_FRENCH,
+ SUBLANG_FRENCH,
+ CODEPAGE_US,
+ CODEPAGE_MULTI,
+ LANG_FRENCH,
+ },
+ { /* Spain */
+
+ CTRY_SPAIN,
+ LANG_SPANISH,
+ SUBLANG_SPANISH,
+ CODEPAGE_MULTI,
+ CODEPAGE_US,
+ LANG_SPANISH,
+ },
+ { /* Italy */
+
+ CTRY_ITALY,
+ LANG_ITALIAN,
+ SUBLANG_ITALIAN,
+ CODEPAGE_US,
+ CODEPAGE_MULTI,
+ LANG_ITALIAN,
+ },
+ { /* Switzerland */
+
+ CTRY_SWITZERLAND,
+ LANG_GERMAN,
+ SUBLANG_GERMAN_SWISS,
+ CODEPAGE_MULTI,
+ CODEPAGE_US,
+ LANG_GERMAN,
+ },
+ { /* Austria */
+
+ CTRY_AUSTRIA,
+ LANG_GERMAN,
+ SUBLANG_GERMAN_AUSTRIAN,
+ CODEPAGE_US,
+ CODEPAGE_MULTI,
+ LANG_GERMAN,
+ },
+ { /* United Kingdom */
+
+ CTRY_UNITED_KINGDOM,
+ LANG_ENGLISH,
+ SUBLANG_ENGLISH_UK,
+ CODEPAGE_US,
+ CODEPAGE_MULTI,
+ LANG_ENGLISH,
+ },
+ { /* Denmark */
+
+ CTRY_DENMARK,
+ LANG_DANISH,
+ SUBLANG_NEUTRAL,
+ CODEPAGE_MULTI,
+ CODEPAGE_NORDIC,
+ LANG_DANISH,
+ },
+ { /* Sweden */
+
+ CTRY_SWEDEN,
+ LANG_SWEDISH,
+ SUBLANG_NEUTRAL,
+ CODEPAGE_US,
+ CODEPAGE_MULTI,
+ LANG_SWEDISH,
+ },
+ { /* Norway */
+
+ CTRY_NORWAY,
+ LANG_NORWEGIAN,
+ SUBLANG_NORWEGIAN_BOKMAL, /* or SUBLANG_NORWEGIAN_NYNORSK */
+ CODEPAGE_MULTI,
+ CODEPAGE_NORDIC,
+ LANG_NORWEGIAN,
+ },
+ { /* Germany */
+
+ CTRY_GERMANY,
+ LANG_GERMAN,
+ SUBLANG_GERMAN,
+ CODEPAGE_US,
+ CODEPAGE_MULTI,
+ LANG_GERMAN,
+ },
+ { /* Mexico */
+
+ CTRY_MEXICO,
+ LANG_SPANISH,
+ SUBLANG_SPANISH_MEXICAN,
+ CODEPAGE_US,
+ CODEPAGE_MULTI,
+ LANG_SPANISH,
+ },
+ { /* Brazil */
+
+ CTRY_BRAZIL,
+ LANG_PORTUGUESE,
+ SUBLANG_PORTUGUESE_BRAZILIAN,
+ CODEPAGE_PORTUGESE,
+ CODEPAGE_MULTI,
+ LANG_PORTUGUESE,
+ },
+ { /* Australia */
+
+ CTRY_AUSTRALIA,
+ LANG_ENGLISH,
+ SUBLANG_ENGLISH_AUS,
+ CODEPAGE_US,
+ CODEPAGE_MULTI,
+ LANG_ENGLISH,
+ },
+ { /* New Zeland */
+
+ CTRY_NEW_ZEALAND,
+ LANG_ENGLISH,
+ SUBLANG_ENGLISH_NZ,
+ CODEPAGE_US,
+ CODEPAGE_MULTI,
+ LANG_ENGLISH,
+ },
+ { /* Portugal */
+
+ CTRY_PORTUGAL,
+ LANG_PORTUGUESE,
+ SUBLANG_PORTUGUESE,
+ CODEPAGE_PORTUGESE,
+ CODEPAGE_MULTI,
+ LANG_PORTUGUESE,
+ },
+ { /* Ireland */
+
+ CTRY_IRELAND,
+ LANG_ENGLISH,
+ SUBLANG_ENGLISH_UK,
+ CODEPAGE_US,
+ CODEPAGE_MULTI,
+ LANG_ENGLISH,
+ },
+ { /* Iceland */
+
+ CTRY_ICELAND,
+ LANG_ICELANDIC,
+ SUBLANG_NEUTRAL,
+ CODEPAGE_MULTI,
+ CODEPAGE_NORDIC,
+ LANG_DANISH,
+ },
+ { /* Finland */
+
+ CTRY_FINLAND,
+ LANG_FINNISH,
+ SUBLANG_NEUTRAL,
+ CODEPAGE_MULTI,
+ CODEPAGE_US,
+ LANG_FINNISH,
+ },
+ { /* Japan */
+
+ CTRY_JAPAN,
+ LANG_JAPANESE,
+ SUBLANG_NEUTRAL,
+ CODEPAGE_JAPAN,
+ CODEPAGE_US,
+ LANG_JAPANESE,
+ },
+ { /* Korea */
+
+ CTRY_SOUTH_KOREA,
+ LANG_KOREAN,
+ SUBLANG_NEUTRAL,
+ CODEPAGE_KOREA,
+ CODEPAGE_US,
+ LANG_KOREAN,
+ },
+#if 0
+ { /* Taiwan */
+
+ CTRY_TAIWAN,
+ LANG_THAI,
+ SUBLANG_NEUTRAL,
+ CODEPAGE_TAIWAN,
+ CODEPAGE_US,
+ LANG_THAI,
+ },
+ { /* Taiwan */
+
+ COUNTRY_TAIWAN,
+ LANG_THAI,
+ SUBLANG_NEUTRAL,
+ CODEPAGE_TAIWAN,
+ CODEPAGE_US,
+ LANG_THAI,
+ },
+#ifdef OS2SS_INCLUDE_HEBREW
+ { /* Hebrew speaking */
+
+ COUNTRY_HEBREW,
+ LANG_HEBREW,
+ SUBLANG_NEUTRAL,
+ CODEPAGE_HEBREW,
+ CODEPAGE_MULTI,
+ LANG_ENGLISH,
+ },
+#endif
+#ifdef OS2SS_INCLUDE_ARABIC
+ { /* Arabic speaking */
+
+ COUNTRY_ARABIC,
+ LANG_ARABIC,
+ SUBLANG_NEUTRAL,
+ CODEPAGE_ARABIC,
+ CODEPAGE_MULTI,
+ LANG_ENGLISH,
+ },
+#endif
+#endif
+#ifdef OS2SS_INCLUDE_PRCHINA
+ { /* Peoples Republic of China */
+
+ CTRY_PRCHINA,
+ LANG_CHINESE,
+ SUBLANG_NEUTRAL,
+ CODEPAGE_PRC,
+ CODEPAGE_US,
+ LANG_CHINESE,
+ },
+#endif
+ { /* End of Table */
+
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ }
+ };
+
+
+#ifdef JAPAN
+// MSKK Nov.02.1992 V-AkihiS
+UINT CPTable[] =
+{
+ 932, 437, 850
+ , 0 /* end */
+};
+#else
+UINT CPTable[] =
+{
+ 437, 850
+ , 860, 862, 863, 864, 865, 932, 934, 936, 938 //WinNLS doesn't support NLS yet
+ , 0 /* end */
+};
+#endif
+
+
+VOID
+Os2SrvExitProcess(
+ IN ULONG uExitCode
+ )
+{
+ ExitProcess((UINT) uExitCode);
+}
+
+
+BOOL
+Os2SrvEventHandlerRoutine(
+ IN DWORD CtrlType
+ )
+{
+ BOOL Rc = TRUE;
+ int Signal = XCPT_SIGNAL_KILLPROC;
+
+#if DBG
+ IF_OS2_DEBUG( SIG )
+ {
+ KdPrint(("OS2SRV(EventHandlerRoutine): Ctr-Type %u\n", CtrlType));
+ }
+#endif
+
+ if ((CtrlType == CTRL_LOGOFF_EVENT) && fService)
+ {
+#if DBG
+ DbgPrint("OS2SRV: running as a service - ignoring CTRL_LOGOFF_EVENT !\n");
+#endif //DBG
+ return FALSE;
+ }
+
+ if ((CtrlType == CTRL_CLOSE_EVENT) ||
+ (CtrlType == CTRL_LOGOFF_EVENT) ||
+ (CtrlType == CTRL_SHUTDOWN_EVENT))
+ {
+ Rc = Os2SrvHandleCtrlEvent(Signal);
+ }
+
+ return(Rc);
+}
+
+
+VOID
+SetEventHandlersAndErrorMode(
+ IN BOOL fSet
+ )
+{
+ if (fSet)
+ {
+ Os2SrvExitNow = 0;
+ SetErrorMode(1);
+ }
+
+ Or2WinSetConsoleCtrlHandler(
+ #if DBG
+ SetEventHandlersAndErrorModeStr,
+ #endif
+ Os2SrvEventHandlerRoutine,
+ fSet
+ );
+}
+
+
+APIRET
+Os2InitializeNLS()
+{
+ PLANG_TABLE_ENTRY pLangEntry;
+ ULONG i, j, AvailableCp[256], NumAvailableCp, TestCountry;
+ USHORT LocaleLang;
+ ANSI_STRING SystemDirectory_A;
+ UNICODE_STRING SystemDirectory_U;
+
+ memset(&ServerSesGrp,
+ 0,
+ sizeof(OS2_SES_GROUP_PARMS));
+ /*
+ * Get Current CP, Country, Language and Console CP
+ */
+
+ ServerSesGrp.Win32OEMCP = Or2WinGetOEMCP(
+ #if DBG
+ Os2InitializeNLSStr
+ #endif
+ );
+ ServerSesGrp.Win32ACP = Or2WinGetACP(
+ #if DBG
+ Os2InitializeNLSStr
+ #endif
+ );
+ ServerSesGrp.Win32LANGID = (ULONG)Or2WinGetUserDefaultLangID(
+ #if DBG
+ Os2InitializeNLSStr
+ #endif
+ );
+ ServerSesGrp.Win32LCID = (ULONG)Or2WinGetThreadLocale(
+ #if DBG
+ Os2InitializeNLSStr
+ #endif
+ );
+
+ Or2NlsGetCountryFromLocale((LCID)ServerSesGrp.Win32LCID, &ServerSesGrp.Win32CountryCode);
+
+ /*
+ * find all available CPs
+ */
+
+ for ( i = 0, NumAvailableCp = 0 ; CPTable[i] && (NumAvailableCp < 200) ; i++ )
+ {
+ if( Or2WinIsValidCodePage(
+ #if DBG
+ Os2InitializeNLSStr,
+ #endif
+ CPTable[i]
+ ))
+ {
+ AvailableCp[NumAvailableCp++] = CPTable[i];
+ }
+ }
+
+ /*
+ * Try to work with the definitions in the registry
+ */
+
+ ServerSesGrp.Os2srvUseRegisterInfo = TRUE;
+
+ if (pLangEntry = CheckCountryCodePage(Os2ssCountryCode,
+ Os2ssCodePage,
+ &ServerSesGrp.PrimaryCP))
+ {
+ while (TRUE) // this is done to enable break
+ {
+ if (ServerSesGrp.SecondaryCP)
+ {
+ for ( i = 0 ; (i < NumAvailableCp) &&
+ (AvailableCp[i] != ServerSesGrp.SecondaryCP) ; i++ ) ;
+
+ if ( i == NumAvailableCp )
+ {
+ ServerSesGrp.SecondaryCP = 0;
+ }
+ }
+
+ for ( i = 0 ; (i < NumAvailableCp) &&
+ (AvailableCp[i] != ServerSesGrp.PrimaryCP) ; i++ ) ;
+
+ if ( i == NumAvailableCp )
+ {
+ ServerSesGrp.PrimaryCP = ServerSesGrp.SecondaryCP;
+ ServerSesGrp.SecondaryCP = 0;
+ }
+
+ if (ServerSesGrp.PrimaryCP)
+ {
+ ServerSesGrp.CountryCode = Os2ssCountryCode;
+ ServerSesGrp.LanguageID = pLangEntry->MessageLanguage;
+ ServerSesGrp.Os2ssLCID = (ULONG)
+ MAKELANGID(pLangEntry->Lang, pLangEntry->SubLang);
+
+ // check CTRY, LANG legalty. (fall down if fail)
+
+ Or2NlsGetCountryFromLocale(
+ (LCID)ServerSesGrp.Os2ssLCID,
+ &TestCountry
+ );
+
+ if (TestCountry == Os2ssCountryCode)
+ {
+ // BUGBUG: change locale
+
+ Or2WinSetThreadLocale(
+ #if DBG
+ Os2InitializeNLSStr,
+ #endif
+ (LCID)ServerSesGrp.Os2ssLCID
+ );
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("InitNls: user NLS definitions: Ctry %lu, CP %lu & %lu\n",
+ Os2ssCountryCode, Os2ssCodePage[0], Os2ssCodePage[1]));
+ }
+#endif
+ break; // SUCCESS
+ }
+ }
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("InitNls: illegal NLS definitions: Ctry %lu, CP %lu & %lu\n",
+ Os2ssCountryCode, Os2ssCodePage[0], Os2ssCodePage[1]));
+ }
+#endif
+ pLangEntry = NULL;
+ break; // FAIL
+ }
+ }
+
+ /*
+ * Inherit NLS definitions from Win32
+ */
+
+ if (pLangEntry == NULL)
+ {
+ ServerSesGrp.Os2srvUseRegisterInfo = FALSE;
+ ServerSesGrp.PrimaryCP = ServerSesGrp.Win32OEMCP;
+ ServerSesGrp.CountryCode = ServerSesGrp.Win32CountryCode;
+ ServerSesGrp.Os2ssLCID = ServerSesGrp.Win32LCID;
+#ifdef JAPAN
+// MSKK Nov.04.1992 V-AkihiS
+ ServerSesGrp.LanguageID = LANG_JAPANESE;
+#else
+ ServerSesGrp.LanguageID = LANG_ENGLISH;
+#endif
+
+ /*
+ * Find if we can second code page to this country
+ */
+
+ for ( j = 0 ; (LANG_TABLE[j].Ctry) && // find the country entry
+ (LANG_TABLE[j].Ctry != ServerSesGrp.CountryCode) ; j++ );
+
+ if (LANG_TABLE[j].Ctry == ServerSesGrp.CountryCode)
+ {
+ if (ServerSesGrp.PrimaryCP != LANG_TABLE[j].Cp1)
+ {
+ // OEM CP is not the Cp1, so if Cp1 is available add it as secondary CP
+
+ for ( i = 0 ; (i < NumAvailableCp) &&
+ (AvailableCp[i] != LANG_TABLE[j].Cp1) ; i++ ) ;
+
+ if ( i < NumAvailableCp )
+ {
+ ServerSesGrp.SecondaryCP = LANG_TABLE[j].Cp1;
+ }
+ }
+
+ if ((ServerSesGrp.SecondaryCP == 0) &&
+ (ServerSesGrp.PrimaryCP != LANG_TABLE[j].Cp2))
+ {
+ // OEM CP is not the Cp2, so if Cp2 is available add it as secondary CP
+
+ for ( i = 0 ; (i < NumAvailableCp) &&
+ (AvailableCp[i] != LANG_TABLE[j].Cp2) ; i++ ) ;
+
+ if ( i < NumAvailableCp )
+ {
+ ServerSesGrp.SecondaryCP = LANG_TABLE[j].Cp2;
+ }
+
+ }
+ }
+
+ LocaleLang = PRIMARYLANGID(LANGIDFROMLCID(ServerSesGrp.Win32LCID));
+ for ( i = 0 ; Or2NlsLangIdTable[i] ; i++ )
+ {
+ if (Or2NlsLangIdTable[i] == LocaleLang)
+ {
+ ServerSesGrp.LanguageID = Or2NlsLangIdTable[i];
+ break;
+ }
+ }
+ }
+
+ ServerSesGrp.VioCP = ServerSesGrp.KbdCP = ServerSesGrp.DosCP = ServerSesGrp.PrimaryCP;
+
+ /*
+ * Get CtryInfo, DBCSEv, CollateTable, CaseMapTable for the default
+ */
+
+ Or2NlsGetCPInfo(
+ (UINT)ServerSesGrp.PrimaryCP,
+ &ServerSesGrp.PriDBCSVec
+ );
+
+ Or2NlsGetMapTable(
+ (LCID)ServerSesGrp.Os2ssLCID,
+ ServerSesGrp.PrimaryCP,
+ LCMAP_SORTKEY,
+ ServerSesGrp.PriCollateTable
+ );
+
+ Or2NlsGetMapTable(
+ (LCID)ServerSesGrp.Os2ssLCID,
+ ServerSesGrp.PrimaryCP,
+ LCMAP_UPPERCASE,
+ ServerSesGrp.PriCaseMapTable
+ );
+
+ if ( ServerSesGrp.SecondaryCP )
+ {
+ Or2NlsGetCPInfo(
+ (UINT)ServerSesGrp.SecondaryCP,
+ &ServerSesGrp.SecDBCSVec
+ );
+
+ Or2NlsGetMapTable(
+ (LCID)ServerSesGrp.Os2ssLCID,
+ ServerSesGrp.SecondaryCP,
+ LCMAP_SORTKEY,
+ ServerSesGrp.SecCollateTable
+ );
+
+ Or2NlsGetMapTable(
+ (LCID)ServerSesGrp.Os2ssLCID,
+ ServerSesGrp.SecondaryCP,
+ LCMAP_UPPERCASE,
+ ServerSesGrp.SecCaseMapTable
+ );
+ }
+
+ Or2NlsGetCtryInfo(
+ (LCID)ServerSesGrp.Os2ssLCID,
+ (UINT)ServerSesGrp.PrimaryCP,
+ &ServerSesGrp.CountryInfo
+ );
+
+ if (ServerSesGrp.PriDBCSVec.Vector[0] || ServerSesGrp.PriDBCSVec.Vector[1] ||
+ ServerSesGrp.SecDBCSVec.Vector[0] || ServerSesGrp.SecDBCSVec.Vector[1])
+ {
+ ServerSesGrp.DBCSCountryFlag = TRUE;
+ }
+
+ ServerSesGrp.KeysOnFlag = Os2ssKeysOnFlag;
+
+ InitKeyboardRegistry();
+
+ // BugBug: maybe according to ServerSesGrp.PrimaryCP or in the future
+ // according to the Process' CodePage
+
+ Or2CurrentCodePageIsOem = TRUE;
+ Or2ProcessCodePage = ServerSesGrp.Win32OEMCP;
+
+ RtlInitUnicodeString(&SystemDirectory_U, Os2SystemDirectory);
+
+ SystemDirectory_A.Buffer = ServerSesGrp.SystemDirectory;
+ SystemDirectory_A.MaximumLength = CCHMAXSYSTEMPATH;
+ SystemDirectory_A.Length = 0;
+
+ Os2ServerSystemDirectory = &ServerSesGrp.SystemDirectory[0];
+
+ Or2UnicodeStringToMBString(
+ &SystemDirectory_A,
+ &SystemDirectory_U,
+ FALSE
+ );
+
+#if DBG
+
+ /*
+ * Dump all NLS info to the debugger
+ */
+
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SRV(Os2-NLS): CP %lu (%lu,%lu), Country %lu, LangID %lx ,LCID %lx\n",
+ ServerSesGrp.DosCP, ServerSesGrp.PrimaryCP,
+ ServerSesGrp.SecondaryCP, ServerSesGrp.CountryCode,
+ ServerSesGrp.LanguageID, ServerSesGrp.Os2ssLCID));
+
+ KdPrint(("OS2SRV(Win32-NLS): OEMCP %lu, ACP %lu, Country %lu, LangID %lx\n",
+ ServerSesGrp.Win32OEMCP, ServerSesGrp.Win32ACP,
+ ServerSesGrp.Win32CountryCode, ServerSesGrp.Win32LANGID));
+
+ KdPrint((" LCID %lx, ConCP %lu, ConOutCP %lu\n",
+ ServerSesGrp.Win32LCID, Or2WinGetConsoleCP(Os2InitializeNLSStr),
+ Or2WinGetConsoleOutputCP(Os2InitializeNLSStr)));
+
+ KdPrint((" SystemDirectory %s\n",
+ ServerSesGrp.SystemDirectory));
+ }
+#endif
+
+ return (NO_ERROR);
+}
+
+
+PLANG_TABLE_ENTRY
+CheckCountryCodePage(
+ IN ULONG CountryCode,
+ IN ULONG *Os2srvCodePages,
+ OUT ULONG *CodePages
+ )
+{
+ ULONG i, j = 0;
+
+ if (!CountryCode)
+ {
+ return(NULL);
+ }
+
+ for ( i = 0 ; LANG_TABLE[i].Ctry ; i++ )
+ {
+ if (LANG_TABLE[i].Ctry == CountryCode)
+ {
+ if (Os2srvCodePages[0] != 0)
+ {
+ if (Os2srvCodePages[1] == 0)
+ {
+ if ((Os2srvCodePages[0] == LANG_TABLE[i].Cp1) ||
+ (Os2srvCodePages[0] == LANG_TABLE[i].Cp2))
+ {
+ CodePages[0] = Os2srvCodePages[0];
+ return(&LANG_TABLE[i]);
+ }
+ } else if (((Os2srvCodePages[0] == LANG_TABLE[i].Cp1) &&
+ (Os2srvCodePages[1] == LANG_TABLE[i].Cp2)) ||
+ ((Os2srvCodePages[1] == LANG_TABLE[i].Cp1) &&
+ (Os2srvCodePages[0] == LANG_TABLE[i].Cp2)))
+ {
+ CodePages[0] = Os2srvCodePages[0];
+ CodePages[1] = Os2srvCodePages[1];
+ return(&LANG_TABLE[i]);
+ } else if ((Os2srvCodePages[0] == LANG_TABLE[i].Cp1) ||
+ (Os2srvCodePages[0] == LANG_TABLE[i].Cp2))
+ {
+ CodePages[0] = Os2srvCodePages[0];
+ return(&LANG_TABLE[i]);
+ } else if ((Os2srvCodePages[1] == LANG_TABLE[i].Cp1) ||
+ (Os2srvCodePages[1] == LANG_TABLE[i].Cp2))
+ {
+ CodePages[0] = Os2srvCodePages[1];
+ return(&LANG_TABLE[i]);
+ }
+ }
+
+ CodePages[0] = LANG_TABLE[i].Cp1;
+ CodePages[1] = LANG_TABLE[i].Cp2;
+ return(&LANG_TABLE[i]);
+ }
+ }
+
+ // end of table
+ return(NULL);
+}
+
+
+struct
+{
+ ULONG Country;
+ UCHAR Prefix[2];
+} KBD_PREFIX_TABLE[] =
+ {
+ { CTRY_BELGIUM, "BE" },
+ { CTRY_CANADA, "CF" },
+ { CTRY_DENMARK, "DK" },
+ { CTRY_FRANCE, "FR" },
+ { CTRY_GERMANY, "GR" },
+ { CTRY_ITALY, "IT" },
+ { COUNTRY_LATIN_AMERICA, "LA" },
+ { CTRY_NETHERLANDS, "NL" },
+ { CTRY_NORWAY, "NO" },
+ { CTRY_PORTUGAL, "PO" },
+ { CTRY_SWITZERLAND, "SF" },
+ { CTRY_SWITZERLAND, "SG" },
+ { CTRY_SPAIN, "SP" },
+ { CTRY_FINLAND, "SU" },
+ { CTRY_SWEDEN, "SV" },
+ { CTRY_UNITED_KINGDOM, "UK" },
+ { CTRY_UNITED_STATES, "US" },
+ { 0, "XX" }
+ };
+
+ULONG
+InitKeyboardRegistry(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This initialization function reads the keybaord layout from the registry
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The value is an ULONG type that is returned when some failure occurs. It
+ may indicate any of several errors that occur during the APIs called in
+ this function. The return value should be tested if NZ.
+
+--*/
+
+{
+#ifdef JAPAN
+// MSKK Aug.10.1993 V-AkihiS
+ ServerSesGrp.KeyboardCountry = CTRY_JAPAN;
+ ServerSesGrp.KeyboardType = OS2SS_EN_KBD;
+#else
+ LONG Rc;
+ int KbdType, i;
+ ULONG KeyBoardCountry = CTRY_UNITED_STATES;
+
+
+ if (((KbdType = GetKeyboardType(0)) == 2) || (KbdType == 4))
+ {
+ ServerSesGrp.KeyboardType = OS2SS_EN_KBD; // EN
+ } else
+ {
+ ServerSesGrp.KeyboardType = OS2SS_AT_KBD; // AT
+ }
+
+ ServerSesGrp.KeyboardCountry = CTRY_UNITED_STATES;
+
+#if PMNT
+ // Keyboard sub-code must be 3 digits or 4 (Swiss-german 150G + 150F only)
+ // Check that we have at least 3 valid digits.
+ // Note that the string is padded with blanks (not null-terminated)
+ if (isdigit(Os2ssKeyboardName[0])
+ && isdigit(Os2ssKeyboardName[1])
+ && isdigit(Os2ssKeyboardName[2]))
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ &Os2ssKeyboardName[0],
+ 4);
+ }
+ else
+ {
+ // Keyboard layout not specified or in incorrect format. Pick default
+ // layout according to specified keyboard layout. See OS/2
+ // documentation (user's guide)
+ if (!strnicmp(&Os2ssKeyboardLayout[0], "BE", 2)) // Belgium
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "120 ",
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "CF", 2)) // Canada (French)
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "058 ",
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "DK", 2)) // Denmark
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "159 ",
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "FR", 2)) // France
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "189 ", // Other possible choice is 120
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "GR", 2)) // Germany
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "129 ",
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "IT", 2)) // Italy
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "141 ", // Other possible choice is 142
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "LA", 2)) // Latin America
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "171 ",
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "NL", 2)) // Netherlands
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "143 ",
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "NO", 2)) // Norway
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "155 ",
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "PO", 2)) // Poland
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "163 ",
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "SF", 2)) // Switerland (FR)
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "150F",
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "SG", 2)) // Switzerland (GR)
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "150G",
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "SP", 2)) // Spain
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "172 ",
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "SU", 2)) // Finland
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "153 ",
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "SV", 2)) // Sweden
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "153 ",
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "UK", 2)) // UK
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "166 ", // Other possible choice is 168
+ 4);
+ }
+ else if (!strnicmp(&Os2ssKeyboardLayout[0], "US", 2)) // US
+ {
+ memcpy(&ServerSesGrp.KeyboardName[0],
+ "103 ",
+ 4);
+ }
+ else
+ {
+ // Use US default keyboard
+ strcpy(&ServerSesGrp.KeyboardName[0], "103 ");
+ }
+ }
+#endif
+
+ if (Os2ssKeyboardLayout[0] && Os2ssKeyboardLayout[1])
+ {
+ for ( i = 0 ; KBD_PREFIX_TABLE[i].Country ; i++ )
+ {
+ if ((KBD_PREFIX_TABLE[i].Prefix[0] == Os2ssKeyboardLayout[0]) &&
+ (KBD_PREFIX_TABLE[i].Prefix[1] == Os2ssKeyboardLayout[1]))
+ {
+ break;
+ }
+ }
+
+ if (KBD_PREFIX_TABLE[i].Country)
+ {
+ ServerSesGrp.KeyboardCountry = KBD_PREFIX_TABLE[i].Country;
+ KeyboardFromConfigSysRegistry = TRUE;
+ ServerSesGrp.KeyboardLayout[0] = Os2ssKeyboardLayout[0];
+ ServerSesGrp.KeyboardLayout[1] = Os2ssKeyboardLayout[1];
+ return(0);
+ }
+ }
+
+#if PMNT
+ // Keyboard layout not found, use default (US)
+ ServerSesGrp.KeyboardLayout[0] = 'U';
+ ServerSesGrp.KeyboardLayout[1] = 'S';
+#endif // PMNT
+
+ Rc = RegOpenKeyExW(
+ HKEY_CURRENT_USER,
+ L"Keyboard Layout",
+ 0,
+ KEY_READ,
+ &KeyboardLayoutKeyHandle
+ );
+
+ if (Rc != ERROR_SUCCESS)
+ {
+#if DBG
+ IF_OS2_DEBUG3( INIT, KBD, NLS )
+ {
+ KdPrint(("InitKeyboardRegistry: Can't open key, rc %lx\n",
+ Rc));
+ }
+#endif
+ return((ULONG)Rc);
+ }
+
+ hKeyEvent = CreateEventW(
+ NULL,
+ FALSE, /* auto reset */
+ FALSE,
+ NULL
+ );
+
+ if (hKeyEvent == NULL)
+ {
+ ULONG Rc1 = GetLastError();
+
+#if DBG
+ IF_OS2_DEBUG3( INIT, KBD, NLS )
+ {
+ KdPrint(("InitKeyboardRegistry: Can't create event, rc %lx\n",
+ Rc1));
+ }
+#endif
+ return(Rc1);
+ }
+
+ Rc = ReadKeyboardLayoutFromRegistry(&KeyBoardCountry);
+
+ if (Rc == 0)
+ {
+ ServerSesGrp.KeyboardCountry = KeyBoardCountry;
+ }
+
+#if DBG
+ IF_OS2_DEBUG3( NLS, INIT, KBD )
+ {
+ KdPrint(("InitKeyboardRegistry: Country %d, Type %s (%d)\n",
+ ServerSesGrp.KeyboardCountry,
+ (ServerSesGrp.KeyboardType == OS2SS_AT_KBD) ? "AT" :
+ ((ServerSesGrp.KeyboardType == OS2SS_ENNEW_KBD) ? "EN-NEW" : "EN"),
+ KbdType));
+ }
+#endif
+#endif
+ return(0);
+}
+
+
+ULONG
+ReadKeyboardLayoutFromRegistry(
+ OUT PULONG pKeyBoardCountry
+ )
+{
+ LONG Rc;
+ DWORD ValueType;
+ DWORD DataSize = 40;
+ WCHAR DataBuffer[40];
+#ifdef JAPAN
+// MSKK Jul.29.1993 V-AkihiS
+ LCID KeyBoardLayOut = MAKELCID(MAKELANGID(LANG_JAPANESE, SUBLANG_NEUTRAL), 0);
+#else
+ LCID KeyBoardLayOut = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 0);
+#endif
+ int CountryLength;
+ WCHAR sCountryCode[WBUFFER_SIZE];
+
+ Rc = RegQueryValueExW(
+ KeyboardLayoutKeyHandle,
+ L"Active",
+ NULL,
+ &ValueType,
+ (LPBYTE)&DataBuffer[0],
+ &DataSize
+ );
+
+ if ((Rc == ERROR_FILE_NOT_FOUND) || (Rc == ERROR_KEY_DELETED))
+ {
+ if (KeyboardLayoutKeyHandle)
+ {
+ RegCloseKey(KeyboardLayoutKeyHandle);
+ KeyboardLayoutKeyHandle = NULL;
+ }
+
+ //
+ // In NT4 the key was changed - try it.
+ //
+ Rc = RegOpenKeyExW(
+ HKEY_CURRENT_USER,
+ L"Keyboard Layout\\Preload",
+ 0,
+ KEY_READ,
+ &KeyboardLayoutKeyHandle
+ );
+ if (Rc == ERROR_SUCCESS)
+ {
+ Rc = RegQueryValueExW(
+ KeyboardLayoutKeyHandle,
+ L"1",
+ NULL,
+ &ValueType,
+ (LPBYTE)&DataBuffer[0],
+ &DataSize
+ );
+ }
+ }
+
+ if (Rc != ERROR_SUCCESS)
+ {
+#if DBG
+ IF_OS2_DEBUG3( NLS, KBD, INIT )
+ {
+ KdPrint(("ReadKeyboardLayoutFromRegistry: Can't query value, rc %lx\n",
+ Rc));
+ }
+#endif
+ return((ULONG)Rc);
+ }
+
+ if (ValueType != REG_SZ)
+ {
+ return((ULONG)-1);
+ }
+
+ KeyBoardLayOut = (LCID)Or2NlsUnicodeStringToInteger(
+ DataBuffer,
+ 16
+ );
+
+ CountryLength = GetLocaleInfoW(
+ KeyBoardLayOut,
+ LOCALE_ICOUNTRY,
+ sCountryCode,
+ WBUFFER_SIZE
+ );
+
+ *pKeyBoardCountry = Or2NlsUnicodeStringToInteger(
+ sCountryCode,
+ 10
+ );
+
+ if ((*pKeyBoardCountry == CTRY_AUSTRALIA) ||
+ (*pKeyBoardCountry == CTRY_NEW_ZEALAND))
+ {
+ *pKeyBoardCountry = CTRY_UNITED_STATES;
+ } else if (*pKeyBoardCountry == CTRY_AUSTRIA)
+ {
+ *pKeyBoardCountry = CTRY_GERMANY;
+ } else if (*pKeyBoardCountry == CTRY_BRAZIL)
+ {
+ *pKeyBoardCountry = CTRY_PORTUGAL;
+ } else if (*pKeyBoardCountry == CTRY_ICELAND)
+ {
+ *pKeyBoardCountry = CTRY_NORWAY; // BUGBUG: or CTRY_DENMARK
+ } else if (*pKeyBoardCountry == CTRY_IRELAND)
+ {
+ *pKeyBoardCountry = CTRY_UNITED_KINGDOM;
+ } else if (*pKeyBoardCountry == CTRY_MEXICO)
+ {
+ *pKeyBoardCountry = COUNTRY_LATIN_AMERICA;
+ }
+
+#if DBG
+ IF_OS2_DEBUG2( NLS, KBD )
+ {
+ KdPrint(("ReadKeyboardLayoutFromRegistry: Value %ws-%x, Country %d\n",
+ DataBuffer, KeyBoardLayOut, *pKeyBoardCountry));
+ }
+#endif
+
+ return(0);
+}
+
+
+ULONG
+GetKeyboardRegistryChange(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This initialization function wait for a change in the keybaord layout
+ in the registry and update all sessions.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The Keyboard Country code
+
+--*/
+
+{
+ LONG Rc;
+ ULONG KeyBoardCountry = ServerSesGrp.KeyboardCountry;
+
+
+ if (KeyboardFromConfigSysRegistry)
+ {
+ return(0);
+ }
+
+ if (KeyboardLayoutKeyHandle == NULL)
+ {
+ return(0);
+ }
+
+ while ( 1 )
+ {
+ Rc = RegNotifyChangeKeyValue(
+ KeyboardLayoutKeyHandle,
+ TRUE,
+ REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME,
+ hKeyEvent, // hEvent (async)
+ TRUE // aSync
+ );
+
+ if (Rc != ERROR_SUCCESS)
+ {
+#if DBG
+ IF_OS2_DEBUG2( KBD, NLS )
+ {
+ KdPrint(("GetKeyboardRegistryChange: Can't wait for notify, rc %lx\n",
+ Rc));
+ }
+#endif
+ return(0);
+ }
+
+ WaitForSingleObject( hKeyEvent, INFINITE );
+
+ Rc = ReadKeyboardLayoutFromRegistry(&KeyBoardCountry);
+
+ if ((Rc == 0) && KeyBoardCountry &&
+ (KeyBoardCountry != ServerSesGrp.KeyboardCountry))
+ {
+ break;
+ }
+
+ while ((Rc == ERROR_FILE_NOT_FOUND) || (Rc == ERROR_KEY_DELETED))
+ {
+ //
+ // In NT4 the when the key is being updated, it's actually
+ // being deleted and recreated. We may have to wait for its
+ // recreaction.
+ //
+#if DBG
+ IF_OS2_DEBUG2( KBD, NLS )
+ {
+ KdPrint(("GetKeyboardRegistryChange: Waiting for registry key to be created.\n"));
+ }
+#endif // DBG
+ Sleep(200L); // 0.2 sec
+ Rc = ReadKeyboardLayoutFromRegistry(&KeyBoardCountry);
+
+ if ((Rc == 0) && KeyBoardCountry &&
+ (KeyBoardCountry != ServerSesGrp.KeyboardCountry))
+ {
+ goto Change;
+ }
+ }
+ }
+
+Change:
+#if DBG
+ IF_OS2_DEBUG2( KBD, NLS )
+ {
+ KdPrint(("GetKeyboardRegistryChange: KbdCountry %u, Old %lu\n",
+ KeyBoardCountry, ServerSesGrp.KeyboardCountry));
+ }
+#endif
+ ServerSesGrp.KeyboardCountry = KeyBoardCountry;
+
+ return(KeyBoardCountry);
+}
diff --git a/private/os2/server/srvobjmn.c b/private/os2/server/srvobjmn.c
new file mode 100644
index 000000000..595094cab
--- /dev/null
+++ b/private/os2/server/srvobjmn.c
@@ -0,0 +1,338 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvobjmn.c
+
+Abstract:
+
+ This is the local object manager module for the OS/2 Subsystem Server
+
+Author:
+
+ Mark Lucovsky (markl) 10-Jul-1990
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include "os2srv.h"
+
+NTSTATUS
+Os2InitializeLocalObjectManager( VOID )
+
+/*++
+
+Routine Description:
+
+ This function initializes the local object manager for
+ named Os2 objects.
+
+ The local object directory is used to translate an object
+ name/type into an object handle.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ NT_SUCCESS() - Function completed without error
+ !NT_SUCCESS() - Function failed
+
+--*/
+
+{
+ //
+ // Create a generic table for object names.
+ //
+
+ RtlInitializeGenericTable (
+ &Os2LocalObjectNames,
+ Os2LocalObjectCompare,
+ Os2LocalObjectDirentAllocate,
+ Os2LocalObjectDirentDeallocate,
+ NULL
+ );
+
+ return(STATUS_SUCCESS);
+}
+
+RTL_GENERIC_COMPARE_RESULTS
+Os2LocalObjectCompare(
+ IN struct _RTL_GENERIC_TABLE *Table,
+ IN PVOID FirstStruct,
+ IN PVOID SecondStruct
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called during local object name lookup to
+ determine if an object is in the local object directory.
+
+Arguments:
+
+ Table - Not used
+
+ FirstStruct - Supplies the address of a local object directory entry
+ whose name is compared against the equvalent value in
+ SecondStruct.
+
+ SecondStruct - Supplies the address of a local object directory entry
+ whose name is compared against the equvalent value in
+ FirstStruct.
+
+Return Value:
+
+ GenericLessThan - FirstStruct is less than SecondStruct
+
+ GenericGreaterThan - FirstStruct is greater than SecondStruct
+
+ GenericEqual - FirstStruct and SecondStruct are equal
+
+--*/
+
+{
+
+ POS2_LOCAL_OBJECT_DIRENT FirstDirent;
+ POS2_LOCAL_OBJECT_DIRENT SecondDirent;
+ LONG CompareResult;
+
+ UNREFERENCED_PARAMETER(Table);
+ FirstDirent = (POS2_LOCAL_OBJECT_DIRENT) FirstStruct;
+ SecondDirent = (POS2_LOCAL_OBJECT_DIRENT) SecondStruct;
+
+ CompareResult = RtlCompareString(
+ &FirstDirent->ObjectName,
+ &SecondDirent->ObjectName,
+ TRUE
+ );
+
+ if ( CompareResult ) {
+ if ( CompareResult < 0 ) {
+ return GenericLessThan;
+ } else {
+ return GenericGreaterThan;
+ }
+ } else {
+ return GenericEqual;
+ }
+
+}
+
+PVOID
+Os2LocalObjectDirentAllocate(
+ IN struct _RTL_GENERIC_TABLE *Table,
+ IN CLONG ByteSize
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called during local object directory entry
+ creation to allocate space for an object directory entry.
+
+Arguments:
+
+ Table - Not used.
+
+ ByteSize - Supplies the amount of space to allocate to store the
+ directory entry.
+
+Return Value:
+
+ NON-NULL - returns the address of the allocated dirent
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(Table);
+ return RtlAllocateHeap( Os2Heap, 0, ByteSize );
+}
+
+VOID
+Os2LocalObjectDirentDeallocate(
+ IN struct _RTL_GENERIC_TABLE *Table,
+ IN PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called to deallocate a local object dirent.
+
+Arguments:
+
+ Table - Not Used.
+
+ Buffer - Supplies the address of the dirent to deallocate
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(Table);
+ RtlFreeHeap( Os2Heap, 0, Buffer );
+}
+
+POS2_LOCAL_OBJECT_DIRENT
+Os2LookupLocalObjectByName(
+ IN PSTRING ObjectName,
+ IN OS2_LOCAL_OBJECT_TYPE ObjectType
+ )
+
+/*++
+
+Routine Description:
+
+ This function looks up the specified object name in the
+ local object directory. If a matching object is found,
+ its type is checked against the specified type and the
+ address of the directory entry is returned.
+
+
+Arguments:
+
+ ObjectName - Supplies the name of the object to lookup
+ in the local object directory.
+
+ ObjectType - Supplies the object type to match against. A value
+ of LocalObjectAnyType matches all object types (just performs
+ a name lookup).
+
+Return Value:
+
+ NULL - The object was not found, or the object was found but its type
+ did not match.
+
+ NON-NULL - Returns a pointer to the matching directory entry.
+
+
+--*/
+
+{
+ POS2_LOCAL_OBJECT_DIRENT Match;
+ OS2_LOCAL_OBJECT_DIRENT Template;
+
+ Template.ObjectName = *ObjectName;
+
+ Match = RtlLookupElementGenericTable(
+ &Os2LocalObjectNames,
+ &Template
+ );
+
+ if ( Match ) {
+ if (ObjectType != LocalObjectAnyType) {
+ if ( ObjectType != Match->ObjectType ) {
+ Match = NULL;
+ }
+ }
+ }
+
+ return Match;
+}
+
+POS2_LOCAL_OBJECT_DIRENT
+Os2InsertLocalObjectName(
+ IN PSTRING ObjectName,
+ IN OS2_LOCAL_OBJECT_TYPE ObjectType,
+ IN ULONG ObjectHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This function inserts an object name into the local object
+ directory creating a directory entry. Duplicate names are
+ not supported (assertion). description-of-function.
+
+
+Arguments:
+
+ ObjectName - Supplies the name of the object to insert
+ in the local object directory.
+
+ ObjectType - Supplies the object type to match against.
+
+ Handle - Supplies a handle to the object.
+
+Return Value:
+
+ NON-NULL - Returns the address of the inserted dirent.
+
+ NULL - No memory to allocate the dirent exists.
+
+--*/
+
+{
+ POS2_LOCAL_OBJECT_DIRENT Match;
+ OS2_LOCAL_OBJECT_DIRENT Template;
+ BOOLEAN Inserted;
+
+ Template.ObjectType = ObjectType;
+ Template.ObjectName = *ObjectName;
+ Template.ObjectHandle = ObjectHandle;
+
+ try {
+ Match = RtlInsertElementGenericTable(
+ &Os2LocalObjectNames,
+ &Template,
+ sizeof(Template),
+ &Inserted
+ );
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+ return NULL;
+ }
+
+ ASSERT(Inserted);
+
+ return Match;
+}
+
+VOID
+Os2DeleteLocalObject(
+ IN POS2_LOCAL_OBJECT_DIRENT Dirent
+ )
+
+/*++
+
+Routine Description:
+
+ This function deletes an object directory entry (name, handle, type)
+ from the local object directory.
+
+
+Arguments:
+
+ Dirent - Supplies the directory entry of the object to
+ remove from the table.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BOOLEAN ret;
+
+ ret = RtlDeleteElementGenericTable(
+ &Os2LocalObjectNames,
+ Dirent
+ );
+ ASSERT(ret);
+}
diff --git a/private/os2/server/srvque.c b/private/os2/server/srvque.c
new file mode 100644
index 000000000..abaeef2dd
--- /dev/null
+++ b/private/os2/server/srvque.c
@@ -0,0 +1,1256 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvque.c
+
+Abstract:
+
+ Queues API
+
+Author:
+
+ Mark Lucovsky (markl) 10-Jul-1990
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_QUEUES
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_TASKING
+#include "os2srv.h"
+
+NTSTATUS
+Os2InitializeQueues( VOID )
+{
+// Os2Debug |= OS2_DEBUG_QUEUES;
+ Os2QueueTable =
+ Or2CreateQHandleTable( Os2Heap, sizeof( OS2_QUEUE ), 8 );
+
+ if (Os2QueueTable == NULL) {
+ return( STATUS_NO_MEMORY );
+ } else {
+ return( STATUS_SUCCESS );
+ }
+}
+
+
+BOOLEAN
+Os2DosCreateQueue( IN POS2_THREAD t, IN POS2_API_MSG m )
+{
+ POS2_DOSCREATEQUEUE_MSG a = &m->u.DosCreateQueue;
+ POS2_LOCAL_OBJECT_DIRENT Dirent;
+ STRING QueueName;
+ OS2_QUEUE LQueue;
+ POS2_QUEUE Queue;
+
+ AcquireLocalObjectLock(Os2QueueTable);
+
+ Dirent = Os2LookupLocalObjectByName(
+ &a->QueueName,
+ LocalObjectQueue
+ );
+
+ if (Dirent) {
+ m->ReturnedErrorValue = ERROR_QUE_DUPLICATE;
+ } else {
+
+ m->ReturnedErrorValue = ERROR_QUE_NO_MEMORY;
+
+ //
+ // allocate and create the queue
+ //
+
+ a->QueueHandle = (HQUEUE) -1;
+
+ if ( Or2CreateQHandle(
+ Os2QueueTable,
+ (PULONG)&a->QueueHandle,
+ (PVOID)&LQueue
+ ) ) {
+
+ Queue = Or2MapQHandle(
+ Os2QueueTable,
+ (ULONG)a->QueueHandle,
+ TRUE
+ );
+
+ if (Queue != NULL) {
+
+ Queue->QueueType = a->QueueType;
+ Queue->OpenCount = 1;
+ Queue->EntryIdCounter = 1;
+ Queue->CreatorPid = t->Process->ProcessId;
+ QueueName = a->QueueName;
+ QueueName.Buffer = RtlAllocateHeap( Os2Heap, 0, QueueName.Length);
+ InitializeListHead(&Queue->Entries);
+ InitializeListHead(&Queue->Waiters);
+ InitializeListHead(&Queue->SemBlocks);
+
+ if ( QueueName.Buffer ) {
+
+ RtlMoveMemory(QueueName.Buffer,a->QueueName.Buffer,QueueName.Length);
+
+ Dirent = Os2InsertLocalObjectName(
+ &QueueName,
+ LocalObjectQueue,
+ (ULONG)a->QueueHandle
+ );
+ if ( !Dirent ) {
+
+ RtlFreeHeap( Os2Heap, 0, QueueName.Buffer);
+
+ //
+ // Destroy will unlock the queue table
+ //
+
+ Or2DestroyQHandle(Os2QueueTable,(ULONG)a->QueueHandle);
+ return (TRUE);
+ } else {
+
+ Queue->Dirent = Dirent;
+ m->ReturnedErrorValue = NO_ERROR;
+ }
+ }
+#if DBG
+ else {
+ KdPrint(( "Os2Srv: no memory for QueueName.Buffer\n" ));
+ ASSERT(FALSE);
+ }
+#endif
+
+ }
+#if DBG
+ else {
+ KdPrint(( "Os2Srv: Or2MapQHandle returned NULL\n" ));
+ ASSERT(FALSE);
+ }
+#endif
+ }
+ }
+
+ ReleaseLocalObjectLock(Os2QueueTable);
+
+ return TRUE;
+}
+
+POS2_QUEUE
+Os2OpenQueueByHandle(
+ IN HQUEUE QueueHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This function is used to open a queue once the queues index is
+ known.
+
+Arguments:
+
+ QueueHandle - Supplies the handle to the queue being opened.
+
+Return Value:
+
+ NON-NULL - Returns the address of the opened queue.
+ NULL - The queue could not be opened.
+
+--*/
+
+{
+
+ POS2_QUEUE Queue;
+
+ Queue = Or2MapQHandle(
+ Os2QueueTable,
+ (ULONG)QueueHandle,
+ TRUE
+ );
+
+ ASSERT(Queue);
+
+ Queue->OpenCount++;
+
+ return Queue;
+}
+
+BOOLEAN
+Os2DosOpenQueue( IN POS2_THREAD t, IN POS2_API_MSG m )
+{
+ POS2_DOSOPENQUEUE_MSG a = &m->u.DosOpenQueue;
+ POS2_LOCAL_OBJECT_DIRENT Dirent;
+ POS2_QUEUE Queue;
+
+ UNREFERENCED_PARAMETER(t);
+ AcquireLocalObjectLock(Os2QueueTable);
+
+ Dirent = Os2LookupLocalObjectByName(
+ &a->QueueName,
+ LocalObjectQueue
+ );
+
+ if (!Dirent) {
+ m->ReturnedErrorValue = ERROR_QUE_NAME_NOT_EXIST;
+ } else {
+
+ Queue = Os2OpenQueueByHandle((HQUEUE)Dirent->ObjectHandle);
+ ASSERT(Queue);
+ a->QueueHandle = (HQUEUE) Dirent->ObjectHandle;
+ a->OwnerProcessId = Queue->CreatorPid;
+ }
+
+ ReleaseLocalObjectLock(Os2QueueTable);
+
+ return TRUE;
+}
+
+APIRET
+Os2CloseQueueByHandle(
+ IN HQUEUE QueueHandle,
+ IN ULONG CloseCount,
+ IN PID OwnerPid,
+ IN POS2_PROCESS Process
+ )
+
+/*++
+
+Routine Description:
+
+ This function is used to close a queue. It is used by both
+ DosCloseQueue and session rundown.
+
+Arguments:
+
+ QueueHandle - Supplies the handle to the queue being closed.
+
+ CloseCount - Supplies the close count for the queue.
+
+ Process - Supplies the address of the process doing the close
+
+Return Value:
+
+ None.
+
+--*/
+
+
+{
+
+ APIRET rc;
+ POS2_LOCAL_OBJECT_DIRENT Dirent;
+ POS2_QUEUE Queue;
+
+ Queue = (POS2_QUEUE)Or2MapQHandle( Os2QueueTable,
+ (ULONG)QueueHandle,
+ FALSE
+ );
+ if (!Queue) {
+ rc = ERROR_QUE_INVALID_HANDLE;
+ }
+ else if ((OwnerPid != (PID)(-1)) && (OwnerPid != Queue->CreatorPid)) {
+ rc = ERROR_QUE_INVALID_HANDLE;
+ }
+ else {
+ rc = NO_ERROR;
+
+ Queue->OpenCount -= CloseCount;
+ if (Queue->OpenCount < 0) {
+ ASSERT(Queue->OpenCount >= 0);
+ Queue->OpenCount = 0;
+ }
+
+ //
+ // Check to see if close is from owner of the queue.
+ // If so, purge the queue
+ //
+
+ if ( Queue->CreatorPid == Process->ProcessId ) {
+
+ //
+ // Destroy the queue and then free remove the dirent from the
+ // name table
+ // When destroying the queue, you must hold the lock and then
+ // nuke the dirent.
+ //
+
+ Dirent = Queue->Dirent;
+ Os2DeleteLocalObject(Dirent);
+
+ //
+ // Now no-one can reference the queue since it's dirent is gone
+ // and no-operations are going on on the queue since we hold the
+ // lock. Release the queue lock and free the queue.
+ //
+
+ //
+ // purge queue. free all asynch reads,
+ //
+
+ Os2PurgeQueueEntries(Queue);
+
+ Os2NotifyWait(WaitQueue,(PVOID)Queue,(PVOID)ERROR_SYS_INTERNAL);
+ Os2ProcessSemBlocks(Queue);
+
+ Or2DestroyQHandle(Os2QueueTable, (ULONG)QueueHandle);
+ }
+ else {
+ ReleaseHandleTableLock( Os2QueueTable );
+ }
+ }
+
+ return rc;
+}
+
+
+
+BOOLEAN
+Os2DosCloseQueue( IN POS2_THREAD t, IN POS2_API_MSG m )
+{
+
+ POS2_DOSCLOSEQUEUE_MSG a = &m->u.DosCloseQueue;
+ APIRET rc;
+
+ rc = Os2CloseQueueByHandle( a->QueueHandle,
+ a->CloseCount,
+ a->OwnerProcessId,
+ t->Process
+ );
+
+ m->ReturnedErrorValue = rc;
+ return TRUE;
+}
+
+
+BOOLEAN
+Os2DosPurgeQueue( IN POS2_THREAD t, IN POS2_API_MSG m )
+{
+ POS2_DOSPURGEQUEUE_MSG a = &m->u.DosPurgeQueue;
+ POS2_QUEUE Queue;
+ APIRET rc;
+
+ Queue = (POS2_QUEUE)Or2MapQHandle( Os2QueueTable,
+ (ULONG)a->QueueHandle,
+ FALSE
+ );
+ if (!Queue) {
+ rc = ERROR_QUE_INVALID_HANDLE;
+ }
+ else {
+
+ if ( Queue->CreatorPid != t->Process->ProcessId ) {
+ rc = ERROR_QUE_PROC_NOT_OWNED;
+ }
+ else {
+ rc = NO_ERROR;
+ ReleaseHandleTableLock( Os2QueueTable );
+ Os2PurgeQueueEntries(Queue);
+ }
+ }
+
+ if ( rc != NO_ERROR ) {
+ ReleaseHandleTableLock( Os2QueueTable );
+ }
+
+ m->ReturnedErrorValue = rc;
+ return TRUE;
+}
+
+BOOLEAN
+Os2DosQueryQueue( IN POS2_THREAD t, IN POS2_API_MSG m )
+{
+
+ POS2_DOSQUERYQUEUE_MSG a = &m->u.DosQueryQueue;
+ POS2_QUEUE Queue;
+ APIRET rc;
+ PLIST_ENTRY NextEntry;
+ ULONG ElementCount;
+
+ UNREFERENCED_PARAMETER(t);
+ Queue = (POS2_QUEUE)Or2MapQHandle( Os2QueueTable,
+ (ULONG)a->QueueHandle,
+ FALSE
+ );
+ if (!Queue) {
+ rc = ERROR_QUE_INVALID_HANDLE;
+ }
+ else if (Queue->CreatorPid != a->OwnerProcessId) {
+ rc = ERROR_QUE_INVALID_HANDLE;
+ }
+ else {
+
+ //
+ // Lock the queue and release the queue table.
+ // Then simply walk the queue elements and count
+ // them.
+ //
+
+ ReleaseHandleTableLock( Os2QueueTable );
+
+ rc = NO_ERROR;
+ ElementCount = 0;
+
+ NextEntry = Queue->Entries.Flink;
+ while ( NextEntry != &Queue->Entries ) {
+ IF_OS2_DEBUG( QUEUES ) {
+ POS2_QUEUE_ENTRY QueueEntry;
+ QueueEntry = CONTAINING_RECORD(NextEntry,OS2_QUEUE_ENTRY,Links);
+ DumpQueueEntry("Query",QueueEntry);
+ }
+ ElementCount++;
+ NextEntry = NextEntry->Flink;
+ }
+ a->CountQueueElements = ElementCount;
+ }
+
+ m->ReturnedErrorValue = rc;
+ return TRUE;
+}
+
+BOOLEAN
+Os2DosPeekQueue( IN POS2_THREAD t, IN POS2_API_MSG m )
+{
+ POS2_DOSPEEKQUEUE_MSG a = &m->u.DosPeekQueue;
+ POS2_QUEUE Queue;
+ APIRET rc;
+ POS2_QUEUE_ENTRY QueueEntry, QueueEntry2;
+ BOOL32 WaitFlag;
+ BOOLEAN ret;
+ ULONG ReadPosition;
+
+ //
+ // Check NoWait flag and map the queue handle
+ //
+
+ switch ((WaitFlag = a->NoWait)) {
+ case DCWW_WAIT :
+ case DCWW_NOWAIT :
+ rc = ERROR_QUE_INVALID_HANDLE;
+ Queue = (POS2_QUEUE)Or2MapQHandle( Os2QueueTable,
+ (ULONG)a->QueueHandle,
+ FALSE
+ );
+ break;
+ default:
+ Queue = NULL;
+ rc = ERROR_QUE_INVALID_WAIT;
+ }
+
+ if (Queue) {
+
+ //
+ // Lock the queue agains modifications/deletions by
+ // locking the queue and then dropping the queuetable/namespace
+ // lock.
+ //
+
+ ReleaseHandleTableLock( Os2QueueTable );
+ rc = NO_ERROR;
+
+ //
+ // If the queue is empty, then wait/register request
+ // based on wait flag or event handle
+ //
+
+ if ( IsListEmpty(&Queue->Entries) ) {
+
+ //
+ // If the queue is empty and DCWW_WAIT was specified, then
+ // setup a wait block and cause thread to wait. Otherwise,
+ // return ERROR_QUE_EMPTY and possibly register an event to
+ // set.
+ //
+
+ if (WaitFlag == DCWW_WAIT) {
+ ret = Os2CreateWait( WaitQueue,
+ Os2WaitQueueEntries,
+ t,
+ m,
+ Queue,
+ &Queue->Waiters
+ );
+ if ( ret ) {
+
+ //
+ // The wait is completely registered.
+ // Return false to signal that reply will be
+ // generated later.
+ //
+
+ return FALSE;
+
+ }
+ else {
+
+ //
+ // If we fail to create a wait block and register the
+ // wait, then translate into no memory.
+ //
+
+ rc = ERROR_QUE_NO_MEMORY;
+ }
+ }
+ else {
+
+ if ( a->SemIndex ) {
+
+ //
+ // If the queue is empty during a read/peek, and the
+ // caller is not waiting and has specified an event
+ // semaphore, then locate the semaphore and create a
+ // sem block. Otherwise, just return ERROR_QUE_EMPTY
+ //
+
+ POS2_SEMAPHORE Semaphore;
+ POS2_QUEUE_SEM_BLOCK SemBlock;
+
+ Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
+ a->SemIndex & 0x7fffffff,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ rc = ERROR_QUE_INVALID_HANDLE;
+ }
+ else {
+ SemBlock = RtlAllocateHeap( Os2Heap, 0, sizeof(*SemBlock) );
+ if ( !SemBlock ) {
+ rc = ERROR_QUE_NO_MEMORY;
+ }
+ else {
+ InsertTailList(&Queue->SemBlocks,&SemBlock->Links);
+ SemBlock->NtEvent = Semaphore->u.EventHandle;
+ rc = ERROR_QUE_EMPTY;
+ }
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ }
+ }
+ else {
+ rc = ERROR_QUE_EMPTY;
+ }
+ }
+ }
+ else {
+
+ //
+ // If the queue has some entries, then either look for the
+ // next entry, or use list head. Remember, if the entry positon
+ // is specified we peek the NEXT item. Not the specified item as
+ // in the case of a call to DosReadQueue.
+ //
+
+ //
+ // Compute the next entry read position. If we are peeking
+ // the last entry, then read position is 0. Otherwise it is
+ // the entry id of the next entry.
+ //
+
+ QueueEntry = Os2LocateQueueEntry(Queue, a->ReadPosition);
+
+ if (a->ReadPosition != 0)
+ {
+ if ( QueueEntry->Links.Flink == &Queue->Entries )
+ {
+ ReadPosition = 0;
+ }
+ else {
+ QueueEntry2 = CONTAINING_RECORD(QueueEntry->Links.Flink,OS2_QUEUE_ENTRY,Links);
+ ReadPosition = QueueEntry2->EntryId;
+ }
+
+ QueueEntry = Os2LocateQueueEntry(Queue, ReadPosition);
+ }
+
+ if ( !QueueEntry ) {
+ rc = ERROR_QUE_ELEMENT_NOT_EXIST;
+ }
+ else {
+ Os2PeekQueueEntry(Queue,QueueEntry,a);
+ }
+ }
+ }
+ m->ReturnedErrorValue = rc;
+ return TRUE;
+}
+
+BOOLEAN
+Os2DosReadQueue( IN POS2_THREAD t, IN POS2_API_MSG m )
+{
+ POS2_DOSREADQUEUE_MSG a = &m->u.DosReadQueue;
+ POS2_QUEUE Queue;
+ APIRET rc;
+ POS2_QUEUE_ENTRY QueueEntry;
+ BOOL32 WaitFlag;
+ BOOLEAN ret;
+
+ //
+ // Check NoWait flag and map the queue handle
+ //
+
+ switch ((WaitFlag = a->NoWait)) {
+ case DCWW_WAIT :
+ case DCWW_NOWAIT :
+ rc = ERROR_QUE_INVALID_HANDLE;
+ Queue = (POS2_QUEUE)Or2MapQHandle( Os2QueueTable,
+ (ULONG)a->QueueHandle,
+ FALSE
+ );
+ break;
+ default:
+ Queue = NULL;
+ rc = ERROR_QUE_INVALID_WAIT;
+ }
+
+ if (Queue) {
+
+ //
+ // Lock the queue agains modifications/deletions by
+ // locking the queue and then dropping the queuetable/namespace
+ // lock.
+ //
+
+ ReleaseHandleTableLock( Os2QueueTable );
+ rc = NO_ERROR;
+
+ //
+ // If the queue is empty, then wait/register request
+ // based on wait flag or event handle
+ //
+
+ if ( IsListEmpty(&Queue->Entries) ) {
+
+ //
+ // If the queue is empty and DCWW_WAIT was specified, then
+ // setup a wait block and cause thread to wait. Otherwise,
+ // return ERROR_QUE_EMPTY and possibly register an event to
+ // set.
+ //
+
+ if (WaitFlag == DCWW_WAIT) {
+ ret = Os2CreateWait( WaitQueue,
+ Os2WaitQueueEntries,
+ t,
+ m,
+ Queue,
+ &Queue->Waiters
+ );
+ if ( ret ) {
+
+ //
+ // The wait is completely registered.
+ // Return false to signal that reply will be
+ // generated later.
+ //
+
+ return FALSE;
+
+ }
+ else {
+
+ //
+ // If we fail to create a wait block and register the
+ // wait, then translate into no memory.
+ //
+
+ rc = ERROR_QUE_NO_MEMORY;
+ }
+ }
+ else {
+
+ if ( a->SemIndex ) {
+ //
+ // If the queue is empty during a read/peek, and the
+ // caller is not waiting and has specified an event
+ // semaphore, then locate the semaphore and create a
+ // sem block. Otherwise, just return ERROR_QUE_EMPTY
+ //
+
+ POS2_SEMAPHORE Semaphore;
+ POS2_QUEUE_SEM_BLOCK SemBlock;
+
+ Semaphore = (POS2_SEMAPHORE)Or2MapHandle( Os2SharedSemaphoreTable,
+ a->SemIndex & 0x7fffffff,
+ FALSE
+ );
+ if (Semaphore == NULL) {
+ rc = ERROR_QUE_INVALID_HANDLE;
+ }
+ else {
+ SemBlock = RtlAllocateHeap( Os2Heap, 0, sizeof(*SemBlock) );
+ if ( !SemBlock ) {
+ rc = ERROR_QUE_NO_MEMORY;
+ }
+ else {
+ InsertTailList(&Queue->SemBlocks,&SemBlock->Links);
+ SemBlock->NtEvent = Semaphore->u.EventHandle;
+ rc = ERROR_QUE_EMPTY;
+ }
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ }
+ }
+ else {
+ rc = ERROR_QUE_EMPTY;
+ }
+ }
+ }
+ else {
+
+ //
+ // If the queue has some entries, then either look for the
+ // specified entry, or use list head.
+ //
+
+ QueueEntry = Os2LocateQueueEntry(Queue, a->ReadPosition);
+
+ if ( !QueueEntry ) {
+ rc = ERROR_QUE_ELEMENT_NOT_EXIST;
+ }
+ else {
+ Os2ReadQueueEntry(QueueEntry,a);
+ }
+ }
+ }
+ m->ReturnedErrorValue = rc;
+ return TRUE;
+}
+
+
+APIRET
+Os2WriteQueueByHandle(
+ POS2_DOSWRITEQUEUE_MSG a,
+ PID ProcessId
+ )
+
+/*++
+
+Routine Description:
+
+ This function writes the specified message to the
+ specified queue. It is normally called by DosWriteQueue, but
+ is also used to send a session termination message.
+
+Arguments:
+
+ a - Supplies a formatted write queue message
+
+ ProcessId - Supplies the process id of the writer.
+
+Return Value:
+
+ Returns the OS/2 error value associated with the write.
+
+--*/
+
+{
+
+ POS2_QUEUE Queue;
+ APIRET rc;
+ POS2_QUEUE_ENTRY QueueEntry;
+ POS2_QUEUE_ENTRY NextQueueEntry;
+ PLIST_ENTRY Pred;
+ PLIST_ENTRY NextEntry;
+
+ Queue = (POS2_QUEUE)Or2MapQHandle( Os2QueueTable,
+ (ULONG)a->QueueHandle,
+ FALSE
+ );
+ if (!Queue) {
+ rc = ERROR_QUE_INVALID_HANDLE;
+ }
+ //
+ // If not called by the server (ProcessId == 0), check against
+ // the creator of the queue
+ //
+ else if (ProcessId != 0 && Queue->CreatorPid != a->OwnerProcessId) {
+ ReleaseHandleTableLock( Os2QueueTable );
+ rc = ERROR_QUE_INVALID_HANDLE;
+ }
+ else {
+
+ //
+ // Now allocate space for a queue entry. Then lock the
+ // queue and release queue table lock. Then insert entry
+ // in queue and release queue lock.
+ //
+
+ QueueEntry = RtlAllocateHeap( Os2Heap, 0, sizeof(*QueueEntry) );
+
+ if ( !QueueEntry ) {
+ ReleaseHandleTableLock( Os2QueueTable );
+ rc = ERROR_QUE_NO_MEMORY;
+ }
+ else {
+
+ ReleaseHandleTableLock( Os2QueueTable );
+ rc = NO_ERROR;
+
+ QueueEntry->RequestData.SenderProcessId = ProcessId;
+ QueueEntry->RequestData.SenderData = a->SenderData;
+ QueueEntry->ElementAddress = (PVOID) a->Data;
+ QueueEntry->ElementLength = a->DataLength;
+
+ if (a->ElementPriority>15) a->ElementPriority = 15;
+
+ QueueEntry->Priority = (Queue->QueueType == QUE_PRIORITY ? a->ElementPriority : 0);
+ QueueEntry->EntryId = Queue->EntryIdCounter++;
+
+ if ( Queue->EntryIdCounter == 0 ) {
+ Queue->EntryIdCounter++;
+ }
+
+ //
+ // Insert Entry in queue
+ //
+
+ switch ( Queue->QueueType ) {
+ case QUE_FIFO :
+ Pred = Queue->Entries.Blink;
+ break;
+
+ case QUE_LIFO :
+ Pred = &Queue->Entries;
+ break;
+
+ case QUE_PRIORITY :
+ Pred = &Queue->Entries;
+ while (Pred->Flink != &Queue->Entries) {
+ NextEntry = Pred->Flink;
+ NextQueueEntry = CONTAINING_RECORD(NextEntry, OS2_QUEUE_ENTRY, Links);
+ if (QueueEntry->Priority > NextQueueEntry->Priority) {
+ break;
+ }
+ Pred = NextEntry;
+ }
+ break;
+ }
+
+ IF_OS2_DEBUG( QUEUES ) DumpQueueEntry("Write",QueueEntry);
+
+ InsertHeadList(Pred,&QueueEntry->Links);
+ Os2ProcessSemBlocks(Queue);
+ Os2QueueWaitCheck(Queue);
+
+ }
+ }
+
+ return rc;
+}
+
+
+BOOLEAN
+Os2DosWriteQueue( IN POS2_THREAD t, IN POS2_API_MSG m )
+{
+
+ POS2_DOSWRITEQUEUE_MSG a = &m->u.DosWriteQueue;
+
+ m->ReturnedErrorValue = Os2WriteQueueByHandle(a,t->Process->ProcessId);
+
+ return TRUE;
+}
+
+VOID
+Os2PurgeQueueEntries(
+ IN POS2_QUEUE Queue
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called during DosCloseQueue and DosPurgeQueue
+ to empty the queue.
+
+ This function must be called with the queue locked !
+
+Arguments:
+
+ Queue - Supplies the address of the queue to purge.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY NextEntry;
+ POS2_QUEUE_ENTRY QueueEntry;
+
+ while ( !IsListEmpty(&Queue->Entries) ) {
+ NextEntry = RemoveHeadList(&Queue->Entries);
+ QueueEntry = CONTAINING_RECORD(NextEntry,OS2_QUEUE_ENTRY,Links);
+ RtlFreeHeap( Os2Heap, 0, QueueEntry);
+ }
+}
+
+POS2_QUEUE_ENTRY
+Os2LocateQueueEntry(
+ IN POS2_QUEUE Queue,
+ IN ULONG ReadPosition
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called during DosReadQueue and DosPeekQueue
+ to determine if the specified queue contains an entry whose
+ entry id matches ReadPosition. Note that a read position of
+ 0 matches the entry at the head of the queue.
+
+ This function must be called with the queue locked !
+
+Arguments:
+
+ Queue - Supplies the address of the queue to search.
+
+ ReadPosition - Supplies the key of the queue entry to
+ locate.
+
+Return Value:
+
+ NON-NULL - Returns the address of the queue entry that matches
+ ReadPosition.
+
+ NULL - The queue does not contain the specified entry.
+
+--*/
+
+{
+ PLIST_ENTRY NextEntry;
+ POS2_QUEUE_ENTRY QueueEntry;
+
+ if ( IsListEmpty(&Queue->Entries) ) {
+ return NULL;
+ }
+
+ if ( ReadPosition == 0 ) {
+ QueueEntry = CONTAINING_RECORD(Queue->Entries.Flink,OS2_QUEUE_ENTRY,Links);
+ IF_OS2_DEBUG( QUEUES ) DumpQueueEntry("LocateReturn",QueueEntry);
+ return QueueEntry;
+ }
+
+ NextEntry = Queue->Entries.Flink;
+
+ while ( NextEntry != &Queue->Entries ) {
+ QueueEntry = CONTAINING_RECORD(NextEntry,OS2_QUEUE_ENTRY,Links);
+ if ( QueueEntry->EntryId == ReadPosition ) {
+ return QueueEntry;
+ }
+ NextEntry = NextEntry->Flink;
+ }
+ return NULL;
+}
+
+VOID
+Os2ProcessSemBlocks(
+ IN POS2_QUEUE Queue
+ )
+
+/*++
+
+Routine Description:
+
+ This function processes the semaphore blocks for the specified
+ queue. This function is called whenever an entry is placed in the
+ queue. Its function is to signal all waiting semaphores and
+ to deallocate the semaphore block.
+
+Arguments:
+
+ Queue - Supplies the queue whose semaphore blocks need processing.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PLIST_ENTRY NextEntry;
+ POS2_QUEUE_SEM_BLOCK SemBlock;
+
+ while ( !IsListEmpty(&Queue->SemBlocks) ) {
+ NextEntry = RemoveHeadList(&Queue->SemBlocks);
+ SemBlock = CONTAINING_RECORD(NextEntry,OS2_QUEUE_SEM_BLOCK,Links);
+ NtSetEvent(SemBlock->NtEvent,NULL);
+ RtlFreeHeap( Os2Heap, 0, SemBlock);
+ }
+
+}
+
+
+BOOLEAN
+Os2WaitQueueEntries(
+ IN OS2_WAIT_REASON WaitReason,
+ IN POS2_THREAD WaitingThread,
+ IN POS2_API_MSG WaitReplyMessage,
+ IN PVOID WaitParameter,
+ IN PVOID SatisfyParameter1,
+ IN PVOID SatisfyParameter2
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the Os2NotifyWait function whenever
+ a queue waiter is awakened. This is typically due to a queue write
+ where there are waiters present and a write occurs. Os2 Exception
+ logic may also cause this routine to be entered.
+
+Arguments:
+
+ WaitReason - Supplies the reason this wait is being satisfied.
+
+ WaitingThread - Supplies the address of the thread waiting being
+ unwaited.
+
+ WaitReplyMessage - Supplies the API message that originally caused
+ the thread to wait.
+
+ WaitParameter - Supplies the address of the queue that the waiter is
+ waiting on.
+
+ SatisfyParameter1 - Supplies the address of the queue that has an
+ entry to satisfy the wait. The queue is locked by the wait
+ notifier.
+
+ SatisfyParameter2 - If not null, then supplies the error code
+ for the wait. Used when a queue is being closed.
+
+Return Value:
+
+ TRUE - A reply should be generated
+
+ FALSE - A reply should not be generated
+
+--*/
+
+{
+
+ POS2_DOSREADQUEUE_MSG read = &WaitReplyMessage->u.DosReadQueue;
+ POS2_DOSPEEKQUEUE_MSG peek = &WaitReplyMessage->u.DosPeekQueue;
+ POS2_QUEUE Queue;
+ APIRET rc;
+ POS2_QUEUE_ENTRY QueueEntry;
+ ULONG ReadPosition;
+ BOOLEAN Peek;
+
+ UNREFERENCED_PARAMETER(WaitingThread);
+ if (WaitReason == WaitInterrupt) {
+ return TRUE;
+ }
+ else {
+ ASSERT(WaitReason == WaitQueue);
+ }
+
+ if ( WaitParameter != SatisfyParameter1 ) {
+ return FALSE;
+ }
+
+ //
+ // If we are being waked due to queue closure, then return
+ // with error.
+ //
+
+ if ( SatisfyParameter2 ) {
+ rc = (APIRET)SatisfyParameter2;
+ }
+ else {
+
+ Queue = (POS2_QUEUE)SatisfyParameter1;
+
+ if ( WaitReplyMessage->ApiNumber == Os2PeekQueue ) {
+ Peek = TRUE;
+ ReadPosition = peek->ReadPosition;
+ }
+ else {
+ Peek = FALSE;
+ ReadPosition = read->ReadPosition;
+ }
+
+ QueueEntry = Os2LocateQueueEntry(Queue, ReadPosition);
+
+ if ( !QueueEntry ) {
+ if ( ReadPosition ) {
+ rc = ERROR_QUE_ELEMENT_NOT_EXIST;
+ }
+ else {
+ return FALSE;
+ }
+ }
+ else {
+
+ rc = NO_ERROR;
+ if ( Peek ) {
+ Os2PeekQueueEntry(Queue,QueueEntry,peek);
+ }
+ else {
+ Os2ReadQueueEntry(QueueEntry,read);
+ }
+ IF_OS2_DEBUG( QUEUES ) DumpQueueEntry("WaitReturn",QueueEntry);
+ }
+ }
+
+ WaitReplyMessage->ReturnedErrorValue = rc;
+
+ return TRUE;
+}
+
+VOID
+Os2QueueWaitCheck(
+ POS2_QUEUE Queue
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called to check to see if there are queue waiters
+ whose waits might be satisfied if entries exist on the queue.
+
+Arguments:
+
+ Queue - Supplies the address of the queue to check.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ POS2_WAIT_BLOCK WaitBlock;
+
+ //
+ // If there are no entries on the list, then there is nothing to
+ // do.
+ //
+
+ if ( IsListEmpty(&Queue->Entries) ) {
+ return;
+ }
+
+ //
+ // If there are entries in the queue, but no waiters, then return
+ // since there is no-one to wake.
+ //
+
+ if ( IsListEmpty(&Queue->Waiters) ) {
+
+ //
+ // actually, we need to deal w/ semaphores...
+ //
+ return;
+ }
+
+ //
+ // There are waiters, so pop the first waiter
+ //
+
+ WaitBlock = CONTAINING_RECORD(Queue->Waiters.Flink,OS2_WAIT_BLOCK,UserLink);
+
+ Os2NotifyWait(WaitQueue,(PVOID)Queue,NULL);
+}
+
+VOID
+Os2ReadQueueEntry(
+ IN POS2_QUEUE_ENTRY QueueEntry,
+ OUT POS2_DOSREADQUEUE_MSG ReadMsg
+ )
+
+/*++
+
+Routine Description:
+
+ This function reads the specified queue entry from its queue
+
+Arguments:
+
+ QueueEntry - Supplies the address of the queue entry to read from the
+ queue.
+
+ ReadMsg - Supplies the read queue api message to fill in.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Remove the queue entry, capture all the data,
+ // and free the entry;
+ //
+
+ RemoveEntryList(&QueueEntry->Links);
+
+ ReadMsg->RequestInfo = QueueEntry->RequestData;
+ ReadMsg->DataLength = QueueEntry->ElementLength;
+ ReadMsg->Data = QueueEntry->ElementAddress;
+ ReadMsg->ElementPriority = (BYTE)QueueEntry->Priority;
+ RtlFreeHeap( Os2Heap, 0, QueueEntry);
+}
+
+VOID
+Os2PeekQueueEntry(
+ IN POS2_QUEUE Queue,
+ IN POS2_QUEUE_ENTRY QueueEntry,
+ OUT POS2_DOSPEEKQUEUE_MSG PeekMsg
+ )
+
+/*++
+
+Routine Description:
+
+ This function peeks the specified queue entry from its queue. It
+ also computes the next queue entry.
+
+Arguments:
+
+ Queue - Supplies the queue to peek from.
+
+ QueueEntry - Supplies the address of the queue entry to read from the
+ queue.
+
+ PeekMsg - Supplies the read queue api message to fill in.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PeekMsg->RequestInfo = QueueEntry->RequestData;
+ PeekMsg->DataLength = QueueEntry->ElementLength;
+ PeekMsg->Data = QueueEntry->ElementAddress;
+ PeekMsg->ElementPriority = (BYTE)QueueEntry->Priority;
+
+ PeekMsg->ReadPosition=QueueEntry->EntryId;
+
+}
+
+VOID
+DumpQueueEntry(
+ IN PSZ Str,
+ IN POS2_QUEUE_ENTRY QueueEntry
+ )
+{
+#if DBG
+ KdPrint(("\n*** %s QUEUE ENTRY st 0x%lx***\n",Str,QueueEntry));
+ KdPrint(("RequestData.SenderProcessId 0x%lx\n",QueueEntry->RequestData.SenderProcessId));
+ KdPrint(("RequestData.SenderData 0x%lx\n",QueueEntry->RequestData.SenderData ));
+ KdPrint(("EntryId; 0x%lx\n",QueueEntry->EntryId ));
+ KdPrint(("ElementAddress 0x%lx\n",QueueEntry->ElementAddress ));
+ KdPrint(("ElementLength 0x%lx\n",QueueEntry->ElementLength ));
+ KdPrint(("Priority 0x%lx\n",QueueEntry->Priority ));
+ KdPrint(("*******************\n"));
+#endif
+}
diff --git a/private/os2/server/srvsem.c b/private/os2/server/srvsem.c
new file mode 100644
index 000000000..e58f0354e
--- /dev/null
+++ b/private/os2/server/srvsem.c
@@ -0,0 +1,260 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvsem.c
+
+Abstract:
+
+ Semaphore API
+
+Author:
+
+ Steve Wood (stevewo) 11-Oct-1989
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_SEMAPHORES
+#define INCL_OS2V20_ERRORS
+#include "os2srv.h"
+
+//
+// These are dummy variable & dummy routine for the use of two macros
+// AcquireHandleTableLock and ReleaseHandleTableLock. In the server,
+// these macros should always work, so we set them both to NULL.
+//
+BOOLEAN Od2SigHandlingInProgress = (BOOLEAN)NULL;
+ULONG Od2ThreadId()
+{
+ return((ULONG)NULL);
+}
+
+NTSTATUS
+Os2InitializeSemaphores( VOID )
+{
+ Os2SharedSemaphoreTable =
+ Or2CreateHandleTable( Os2Heap, sizeof( OS2_SEMAPHORE ), 32 );
+
+ if (Os2SharedSemaphoreTable == NULL) {
+ return( STATUS_NO_MEMORY );
+ }
+ else {
+ return( STATUS_SUCCESS );
+ }
+}
+
+BOOLEAN
+Os2SemaphoreCreateProcedure(
+ IN POS2_SEMAPHORE Semaphore,
+ IN POS2_SEMAPHORE NewSemaphore
+ )
+{
+ if (Semaphore->Name.Length != 0) {
+ if (RtlEqualString( &Semaphore->Name, &NewSemaphore->Name, FALSE )) {
+ return( TRUE );
+ }
+ }
+
+ return( FALSE );
+}
+
+BOOLEAN
+Os2SemaphoreOpenProcedure(
+ IN POS2_SEMAPHORE Semaphore,
+ IN POS2_SEMAPHORE OpenSemaphore
+ )
+{
+ if (Semaphore->Name.Length != 0) {
+ if (RtlEqualString( &Semaphore->Name, &OpenSemaphore->Name, FALSE )) {
+ return( TRUE );
+ }
+ }
+ return( FALSE );
+}
+
+
+APIRET
+Os2ProcessSemaphoreName(
+ IN PSTRING ObjectName,
+ IN POS2_SEMAPHORE Semaphore OPTIONAL,
+ OUT PULONG ExistingHandleIndex OPTIONAL
+ )
+{
+ OS2_SEMAPHORE ExistingSemaphore;
+ PSZ src, dst;
+ USHORT n;
+ APIRET rc;
+
+ AcquireHandleTableLock( Os2SharedSemaphoreTable );
+
+ if (ARGUMENT_PRESENT( ExistingHandleIndex )) {
+ Semaphore = &ExistingSemaphore;
+ }
+
+ rc = NO_ERROR;
+ if ((n = ObjectName->Length) == 0) {
+ Semaphore->Name.Length = 0;
+ Semaphore->Name.MaximumLength = 0;
+ Semaphore->Name.Buffer = NULL;
+ }
+ else {
+ dst = RtlAllocateHeap( Os2Heap, 0, n );
+ if (dst == NULL) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else {
+ src = ObjectName->Buffer;
+ Semaphore->Name.Length = n;
+ Semaphore->Name.MaximumLength = n;
+ Semaphore->Name.Buffer = dst;
+ while (n--) {
+ *dst++ = *src++;
+ }
+
+ if (Or2EnumHandleTable(
+ Os2SharedSemaphoreTable,
+ (OR2_ENUMERATE_HANDLE_ROUTINE)
+ (ARGUMENT_PRESENT( ExistingHandleIndex ) ?
+ Os2SemaphoreOpenProcedure :
+ Os2SemaphoreCreateProcedure),
+ (PVOID)Semaphore,
+ ExistingHandleIndex
+ )
+ ) {
+ if (!ARGUMENT_PRESENT( ExistingHandleIndex )) {
+ rc = ERROR_DUPLICATE_NAME;
+ }
+ }
+ else {
+ if (ARGUMENT_PRESENT( ExistingHandleIndex )) {
+ rc = ERROR_SEM_NOT_FOUND;
+ }
+ }
+
+ if (ARGUMENT_PRESENT( ExistingHandleIndex ) || rc != NO_ERROR) {
+ RtlFreeHeap( Os2Heap, 0,
+ Semaphore->Name.Buffer
+ );
+ }
+ }
+ }
+
+ return( rc );
+}
+
+
+PVOID
+Os2DestroySemaphore(
+ IN POS2_SEMAPHORE Semaphore,
+ IN ULONG HandleIndex
+ )
+{
+ PVOID Value;
+
+ Value = Semaphore->u.Value;
+
+ if (Semaphore->Name.Length != 0) {
+ RtlFreeHeap( Os2Heap, 0,
+ Semaphore->Name.Buffer
+ );
+ }
+
+ Or2DestroyHandle( Os2SharedSemaphoreTable,
+ HandleIndex
+ );
+
+ return( Value );
+}
+
+
+POS2_SEMAPHORE
+Os2ReferenceSemaphore(
+ IN POS2_SEMAPHORE Semaphore
+ )
+{
+ Semaphore->PointerCount++;
+
+ return( Semaphore );
+}
+
+
+VOID
+Os2DereferenceSemaphore(
+ IN POS2_SEMAPHORE Semaphore
+ )
+{
+ Semaphore->PointerCount--;
+
+ return;
+}
+
+
+VOID
+Os2ThreadWaitingOnSemaphore(
+ IN POS2_THREAD t,
+ IN POS2_SEMAPHORE Semaphore,
+ IN BOOLEAN AboutToWait
+ )
+{
+ if (AboutToWait) {
+ t->WaitingForSemaphore = Os2ReferenceSemaphore( Semaphore );
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ }
+ else {
+ AcquireHandleTableLock( Os2SharedSemaphoreTable );
+ t->WaitingForSemaphore = NULL;
+ Os2DereferenceSemaphore( Semaphore );
+ ReleaseHandleTableLock( Os2SharedSemaphoreTable );
+ }
+}
+
+
+#if DBG
+
+VOID
+Os2SemaphoreDumpProcedure(
+ IN POS2_SEMAPHORE Semaphore,
+ IN ULONG HandleIndex,
+ IN PVOID DumpParameter
+ )
+{
+ UNREFERENCED_PARAMETER(DumpParameter);
+ DbgPrint( " %3ld %2ld %4ld %4ld %8lx %.*s\n",
+ HandleIndex,
+ (ULONG)Semaphore->Type,
+ (ULONG)Semaphore->OpenCount,
+ (ULONG)Semaphore->PointerCount,
+ (ULONG)Semaphore->u.Value,
+ Semaphore->Name.Length,
+ Semaphore->Name.Buffer
+ );
+ return;
+}
+
+VOID
+Os2DumpSemaphoreTable(
+ IN PCHAR Title
+ )
+{
+ ULONG n;
+
+ if (Os2SharedSemaphoreTable->CountEntries >
+ Os2SharedSemaphoreTable->CountFreeEntries
+ ) {
+ DbgPrint( "\nDump Of OS/2 Server Shared Semaphore Table: %s\n", Title );
+ DbgPrint( "Index Type Ocnt Pcnt Value Name\n" );
+ n = Or2DumpHandleTable(
+ Os2SharedSemaphoreTable,
+ (OR2_DUMP_HANDLE_ROUTINE)Os2SemaphoreDumpProcedure,
+ NULL
+ );
+
+ DbgPrint( "Total number of valid shared semaphores: %ld\n", n );
+ }
+}
+
+#endif // DBG
diff --git a/private/os2/server/srvsm.c b/private/os2/server/srvsm.c
new file mode 100644
index 000000000..3256f9dd5
--- /dev/null
+++ b/private/os2/server/srvsm.c
@@ -0,0 +1,1091 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvsm.c
+
+Abstract:
+
+ Session API
+
+Author:
+
+ Mark Lucovsky (markl) 10-Jul-1990
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_SESSIONMGR
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_EXCEPTIONS
+#include "os2srv.h"
+#define NTOS2_ONLY
+#include "sesport.h"
+#include "os2win.h"
+
+
+extern ULONG Os2GlobalInfoSeg;
+
+ULONG
+WaitOnWinSessionObject(
+ IN ULONG Parm
+ );
+
+VOID
+StopSessionAndChildSessions(
+ IN POS2_SESSION Session
+ );
+
+BOOLEAN
+CheckSessionIfChild(
+ IN POS2_SESSION ParentSession,
+ IN POS2_SESSION ChildSession
+ );
+
+BOOLEAN
+Os2WaitNewSession(
+ IN OS2_WAIT_REASON WaitReason,
+ IN POS2_THREAD WaitingThread,
+ IN POS2_API_MSG WaitReplyMessage,
+ IN PVOID WaitParameter,
+ IN PVOID SatisfyParameter1,
+ IN PVOID SatisfyParameter2
+ );
+
+VOID
+Os2SessionWaitCheck(
+ POS2_SESSION Session,
+ ULONG RetCode
+ );
+
+APIRET
+Os2CheckIfSessionTreeInFG(
+ IN POS2_SESSION Session
+ );
+
+#if DBG
+VOID
+DumpSessionEntry(
+ IN PSZ Str,
+ IN POS2_SESSION Session
+ );
+
+VOID
+DumpSessionTable(
+ IN PSZ Str
+ );
+#endif
+
+POS2_SESSION
+Os2AllocateSession(
+ POS2_DOSSTARTSESSION_INFO SessionInfo OPTIONAL,
+ ULONG UniqueId,
+ PAPIRET ApiRet
+ )
+
+/*++
+
+Routine Description:
+
+ This function allocates and initializes an OS/2 session control
+ block.
+
+Arguments:
+
+ SessionInfo - Supplies the session information
+
+ ApiRet - If a session was not created, ApiRet returns the reason the
+ session creation failed.
+
+Return Value:
+
+ NON-NULL - Returns the address of the referenced and allocated session.
+ NULL - No session was created
+
+--*/
+
+{
+ POS2_SESSION Session;
+ POS2_QUEUE TerminationQueue = NULL;
+ ULONG i;
+
+ *ApiRet = NO_ERROR;
+
+ if (UniqueId && (Session = Os2GetSessionByUniqueId(UniqueId)))
+ {
+ // This call is done by conthrds.c for session which was started
+ // by DosStartSession. Instead of allocating a new session, returns
+ // the session with the same UniqueId.
+
+ return(Session);
+ }
+
+ Session = RtlAllocateHeap( Os2Heap, 0, sizeof( OS2_SESSION ) );
+ if ( Session == NULL )
+ {
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ KdPrint(("Os2AllocateSession: cannot allocate session\n"));
+#endif
+ *ApiRet = ERROR_NOT_ENOUGH_MEMORY;
+ return NULL;
+ }
+
+ RtlZeroMemory(Session, sizeof( OS2_SESSION ));
+ Session->ReferenceCount = 1;
+
+ //
+ // Needs more work...
+ // session attributes, termination queue...
+ //
+
+ if ( ARGUMENT_PRESENT(SessionInfo) )
+ {
+ if ( SessionInfo->QueueHandleIndex )
+ {
+ SessionInfo->QueueHandleIndex &= 0x7fffffff;
+ TerminationQueue = Os2OpenQueueByHandle( (HQUEUE)SessionInfo->QueueHandleIndex );
+
+ if ( TerminationQueue )
+ {
+ Session->TerminationQueue = TerminationQueue;
+ Session->TerminationQueueHandle = SessionInfo->QueueHandleIndex;
+ } else
+ {
+ *ApiRet = ERROR_QUE_NAME_NOT_EXIST;
+ RtlFreeHeap( Os2Heap, 0, Session );
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ KdPrint(("Os2AllocateSession: cannot open queue 0x%lx\n",
+ SessionInfo->QueueHandleIndex));
+#endif
+ return NULL;
+ }
+ }
+ }
+
+
+ for ( i = 0 ; (i < OS2_MAX_SESSION) && SessionTable[i].Session ; i++ ) ;
+
+ if (i == OS2_MAX_SESSION)
+ {
+ *ApiRet = ERROR_TOO_MANY_SESS;
+
+ if ( TerminationQueue )
+ {
+ Os2CloseQueueByHandle(
+ (HQUEUE)Session->TerminationQueueHandle,
+ 1,
+ (PID)(-1), // (-1) means ignore this parameter
+ Os2RootProcess);
+ }
+
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ KdPrint(("Os2AllocateSession: too many session 0x%lx\n",
+ OS2_MAX_SESSION));
+#endif
+ RtlFreeHeap( Os2Heap, 0, Session );
+ return NULL;
+ }
+
+ SessionTable[i].Session = Session;
+ Session->SessionId = i + 1;
+ Session->Selectable = TRUE;
+ //Session->ProcessId = 0;
+ //Session->BindSession = NULL;
+ //Session->RelatedSession = NULL;
+ //Session->InheritOpt = 0;
+ //Session->FgBg = 0;
+ //Session->ChildSession = FALSE;
+ //Session->ConsolePort = NULL;
+ //Session->Thread = NULL;
+ InitializeListHead(&(SessionTable[i].Waiters));
+
+ InsertHeadList( &Os2SessionList, &Session->SessionLink );
+
+ if ( ARGUMENT_PRESENT(SessionInfo) )
+ {
+ SessionInfo->ResultSessionId = Session->SessionId;
+ //Session->InheritOpt = SessionInfo->InheritOpt;
+ //Session->FgBg = SessionInfo->FgBg;
+ }
+
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ {
+ DumpSessionEntry("Os2AllocateSession", Session);
+ DumpSessionTable("Os2AllocateSession");
+ }
+#endif
+
+ return( Session );
+}
+
+
+VOID
+Os2ReferenceSession(
+ POS2_SESSION Session
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called for each new process that does not create
+ a new session. Its function is to increment the sessions reference
+ count to account for the new process.
+
+Arguments:
+
+ Session - Supplies the address of the session being referenced.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ APIRET Rc = NO_ERROR;
+
+ try
+ {
+ if (( Session->SessionId == 0 ) ||
+ ( Session->SessionId > OS2_MAX_SESSION ) ||
+ ( Session->ReferenceCount == 0 ) ||
+ ( SessionTable[Session->SessionId - 1].Session != Session ))
+ {
+ ASSERT( FALSE );
+ Rc = ERROR_SMG_SESSION_NOT_FOUND;
+ }
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Rc = ERROR_SMG_SESSION_NOT_FOUND;
+ }
+
+ if (Rc)
+ {
+ return ;
+ }
+
+ Session->ReferenceCount++;
+
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ DumpSessionEntry("Os2ReferenceSession", Session);
+#endif
+
+}
+
+
+POS2_SESSION
+Os2DereferenceSession(
+ POS2_SESSION Session,
+ POS2_TERMINATEPROCESS_MSG msg,
+ BOOLEAN Bailout
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called for each process termination to release the
+ processes reference to the session. If this is the last process in
+ a session to terminate, the reference count will go to zero freeing
+ the session and sending a session termination status code.
+
+Arguments:
+
+ Session - Supplies the address of the session being dereferenced.
+
+ msg - Exit message from Client
+
+ Bailout - Supplies a flag which if set inhibits reporting of
+ session termination.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ OS2_DOSWRITEQUEUE_MSG a;
+ ULONG i;
+ APIRET Rc = NO_ERROR;
+ ULONG SessionId;
+
+ if (Session == NULL)
+ {
+ return NULL;
+ }
+
+ try
+ {
+ if (( Session->SessionId == 0 ) ||
+ ( Session->SessionId > OS2_MAX_SESSION ) ||
+ ( Session->ReferenceCount == 0 ) ||
+ ( SessionTable[Session->SessionId - 1].Session != Session ))
+ {
+ ASSERT( FALSE );
+ Rc = ERROR_SMG_SESSION_NOT_FOUND;
+ }
+ } except ( EXCEPTION_EXECUTE_HANDLER )
+ {
+ Rc = ERROR_SMG_SESSION_NOT_FOUND;
+ }
+
+ if (Rc)
+ {
+ return NULL;
+ }
+
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ DumpSessionEntry("Os2DereferenceSession", Session);
+#endif
+
+ if (--Session->ReferenceCount == 0)
+ {
+
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ KdPrint(("Os2DereferenceSession - exit\n"));
+#endif
+
+ SessionTable[Session->SessionId - 1].Session = NULL;
+ Session->ProcessId = 0;
+ SessionId = Session->SessionId;
+ Session->SessionId = 0;
+ Session->ReferenceCount = (ULONG)-1;
+ RemoveEntryList( &Session->SessionLink );
+
+ //if (Session->hWaitThread)
+ //{
+ //NtAlertThread(Session->hWaitThread);
+ //TerminateThread(Session->hWaitThread, 0L);
+ //WaitForSingleObject(Session->hWaitThread, (ULONG) SEM_INDEFINITE_WAIT);
+ //CloseHandle(Session->hWaitThread);
+ //Session->hWaitThread = NULL;
+ //}
+
+ if (( Session->RelatedSession ) && ( Session->RelatedSession->BindSession == Session ))
+ {
+ Session->RelatedSession->BindSession = NULL;
+ }
+
+ for ( i = 0 ; i < OS2_MAX_SESSION ; i++ )
+ {
+ if ( SessionTable[i].Session &&
+ ( SessionTable[i].Session->RelatedSession == Session ))
+ {
+ SessionTable[i].Session->RelatedSession = NULL;
+ StopSessionAndChildSessions(SessionTable[i].Session);
+ }
+ }
+
+ //
+ // If it's a win32 session, terminate child sessions, by pid.
+ //
+ if (Session->WinSession)
+ {
+ for ( i = 0 ; i < OS2_MAX_SESSION ; i++ )
+ {
+ if ( SessionTable[i].Session &&
+ ( SessionTable[i].Session->dwParentProcessId == Session->dwProcessId ))
+ {
+ StopSessionAndChildSessions(SessionTable[i].Session);
+ }
+ }
+ }
+ Session->dwProcessId = 0;
+ Session->dwParentProcessId = 0;
+
+ if ( Session->TerminationQueue )
+ {
+
+ if ( !Bailout )
+ {
+
+ //
+ // I guess I really have to allocate vm. This is
+ // dumb. I would propose using data/data length as
+ // sid, result code
+ //
+
+ a.QueueHandle = (HQUEUE)Session->TerminationQueueHandle;
+ a.SenderData = 0L;
+ a.DataLength = 0x80000000 | SessionId;
+ a.Data = (PVOID) msg->ExitResult;
+ a.ElementPriority = 0;
+
+ Os2WriteQueueByHandle(&a,Os2RootProcess->ProcessId);
+ }
+
+ Os2CloseQueueByHandle( (HQUEUE)Session->TerminationQueueHandle,
+ 1,
+ (PID)(-1), // (-1) means ignore this parameter
+ Os2RootProcess
+ );
+ }
+
+ if (Session->SesGrpAddress)
+ {
+ NtUnmapViewOfSection( NtCurrentProcess(),
+ Session->SesGrpAddress);
+ }
+
+ if (Session->SesGrpHandle)
+ {
+ NtClose( Session->SesGrpHandle );
+ }
+
+ if ( Session->ConsolePort != NULL )
+ {
+ if ( msg != NULL )
+ {
+ Os2TerminateConSession(Session, msg);
+ }
+ NtClose(Session->ConsolePort);
+ }
+
+ if ( !IsListEmpty(&(SessionTable[Session->SessionId - 1].Waiters)) )
+ {
+ Os2NotifyWait(WaitSession, (PVOID)ERROR_SYS_INTERNAL, (PVOID)ERROR_SYS_INTERNAL);
+ }
+
+ if (Os2SrvExitNow)
+ {
+ for ( i = 0 ; (i < OS2_MAX_SESSION) && SessionTable[i].Session ; i++ ) ;
+
+ if ( i == OS2_MAX_SESSION )
+ {
+ Os2SrvExitProcess(0);
+ }
+ }
+
+ RtlFreeHeap( Os2Heap, 0, Session );
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ DumpSessionTable("Os2DereferenceSession");
+#endif // DBG
+ return NULL;
+ }
+ return Session;
+}
+
+
+POS2_SESSION
+Os2GetSessionByUniqueId(
+ ULONG UniqueId
+ )
+{
+ ULONG i;
+
+ for ( i = 0 ; ( i < OS2_MAX_SESSION ) ; i++ )
+ {
+ if ( SessionTable[i].Session == (POS2_SESSION)UniqueId )
+ {
+ return (SessionTable[i].Session);
+ }
+ }
+
+ return (NULL);
+}
+
+
+BOOLEAN
+Os2DosStartSession(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSEXECPGM_MSG a = &m->u.DosStartSession.ExecPgmInformation;
+ POS2_DOSSTARTSESSION_INFO b = &m->u.DosStartSession.StartSessionInformation;
+ POS2_THREAD NewThread = NULL;
+ POS2_SESSION Session;
+ NTSTATUS Status;
+ APIRET RetCode;
+ ULONG Tid;
+
+ Session = Os2AllocateSession(b, 0, &RetCode);
+
+ if ( !Session )
+ {
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ KdPrint(("Os2DosStartSession: can't allocate\n"));
+#endif
+ m->ReturnedErrorValue = RetCode;
+ return( TRUE );
+ }
+
+ Session->ChildSession = TRUE;
+ Session->Thread = (PVOID)t;
+ Session->WinSession = b->WinSession;
+
+ m->ReturnedErrorValue = Os2CreateProcess(
+ NULL,
+ t,
+ a,
+ Session,
+ &NewThread
+ );
+
+ if ( m->ReturnedErrorValue == NO_ERROR )
+ {
+#if DBG
+ KdPrint(( "OS2SRV: Starting new session for 16-bit program - %s\n",
+ a->ApplName));
+#endif // DBG
+
+ if (b->Related)
+ {
+ Session->RelatedSession = t->Process->Session;
+ t->Process->Session->BindSession = Session;
+ }
+
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ DumpSessionEntry("Os2DosStartSession(after Os2CreateProcess)", Session);
+#endif
+
+ if(Session->WinSession)
+ {
+ Session->hProcess = a->hProcess;
+ Session->dwProcessId = b->dwProcessId;
+
+ if((Session->hWaitThread = CreateThread(
+ NULL,
+ 0,
+ WaitOnWinSessionObject,
+ (PVOID)Session,
+ 0,
+ &Tid )) == NULL)
+ {
+#if DBG
+ KdPrint(("OS2SRV: CreateThread for WinSession error %lu\n",
+ m->ReturnedErrorValue = GetLastError()));
+ ASSERT( FALSE );
+#endif
+ return( TRUE );
+ }
+ }
+
+ if (!b->FgBg)
+ {
+ // ForeGround
+
+ OS2SESREQUESTMSG RequestMsg;
+
+ RequestMsg.Session = Session;
+ RequestMsg.d.FocusSet = 1;
+ Os2SessionFocusSet(&RequestMsg);
+ }
+
+ Status = NtResumeThread( NewThread->ThreadHandle, NULL );
+ ASSERT(NT_SUCCESS(Status));
+ return( TRUE );
+ } else
+ {
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ KdPrint(("Os2DosStartSession: can't Os2CreateProcesst\n"));
+#endif
+ //m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ //Os2DeallocateThread( NewThread );
+ //Os2DeallocateProcess( NewThread->Process );
+ //NtClose(m->u.DosExecPgm.hThread);
+ //NtClose(m->u.DosExecPgm.hProcess);
+
+ Os2DereferenceSession(Session, 0, (BOOLEAN)TRUE);
+ return( TRUE );
+ }
+}
+
+
+ULONG
+WaitOnWinSessionObject(
+ IN ULONG Parm
+ )
+{
+ POS2_SESSION Session = (POS2_SESSION)Parm;
+ ULONG ExitCode = 0;
+ HANDLE hCurrThread = Session->hWaitThread;
+ OS2_TERMINATEPROCESS_MSG a;
+ NTSTATUS Status;
+
+ if (NtTestAlert() != STATUS_ALERTED)
+ {
+ Status = NtWaitForSingleObject( Session->hProcess, TRUE, NULL );
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ KdPrint(("WaitOnWinSessionObject: Wait for Win32 process, status=0x%0X\n", Status));
+#endif // DBG
+ if (Status != STATUS_ALERTED)
+ {
+ if (!GetExitCodeProcess(Session->hProcess, &ExitCode))
+ {
+ ExitCode = GetLastError();
+ }
+ }
+ else
+ {
+ TerminateProcess(Session->hProcess, 0);
+ }
+ }
+
+ CloseHandle(Session->hProcess);
+
+ if (Session->ReferenceCount)
+ {
+ Session->hWaitThread = NULL;
+ a.ExitResult = ExitCode;
+ a.ExitReason = 0;
+ a.ErrorText[0] = '\0';
+ Os2DereferenceSession(Session, &a, FALSE);
+ }
+
+ CloseHandle(hCurrThread);
+ ExitThread(0L);
+ return(0L);
+}
+
+
+BOOLEAN
+Os2DosSelectSession(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ ULONG SessionId = m->u.DosSelectSession.SessionId;
+ POS2_SESSION Session;
+ //NTSTATUS Status;
+ //SCREQUESTMSG Request;
+ BOOLEAN RetVal;
+
+ if ( SessionId == 0 )
+ {
+ Session = t->Process->Session;
+ } else
+ {
+ if (( SessionId > OS2_MAX_SESSION ) ||
+ (( Session = SessionTable[SessionId - 1].Session ) == NULL ) ||
+ ( Session->RelatedSession != t->Process->Session ))
+ {
+ m->ReturnedErrorValue = ERROR_SMG_SESSION_NOT_PARENT;
+ return( TRUE );
+ }
+ }
+
+ if (m->ReturnedErrorValue = Os2CheckIfSessionTreeInFG(t->Process->Session))
+ {
+ return( TRUE );
+ }
+
+ m->ReturnedErrorValue = NO_ERROR;
+
+ if (!Session->WinSession)
+ {
+ if (Session->Win32ForegroundWindow != NULL) {
+ RetVal = OpenIcon(Session->Win32ForegroundWindow) &&
+ SetForegroundWindow(Session->Win32ForegroundWindow);
+ if (RetVal) {
+ // ForeGround
+
+ OS2SESREQUESTMSG RequestMsg;
+
+ RequestMsg.Session = Session;
+ RequestMsg.d.FocusSet = 1;
+ Os2SessionFocusSet(&RequestMsg);
+ }
+ }
+ }
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosSetSession(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSSETSESSION_MSG a = &m->u.DosSetSession;
+ POS2_SESSION Session;
+ BOOLEAN Selectable;
+
+ if ( !a->SessionId ||
+ ( a->SessionId > OS2_MAX_SESSION ) ||
+ (( Session = SessionTable[a->SessionId - 1].Session ) == NULL ) ||
+ ( Session->RelatedSession != t->Process->Session ))
+ {
+ m->ReturnedErrorValue = ERROR_SMG_SESSION_NOT_PARENT;
+ return( TRUE );
+ }
+
+ if (m->ReturnedErrorValue = Os2CheckIfSessionTreeInFG(Session))
+ {
+ return( TRUE );
+ }
+
+ m->ReturnedErrorValue = NO_ERROR;
+
+ if (( a->StatusData.Length >= 4 ) &&
+ ( a->StatusData.SelectInd != TARGET_UNCHANGED ))
+ {
+ Selectable = (BOOLEAN)((a->StatusData.SelectInd == TARGET_SELECTABLE ) ?
+ TRUE : FALSE);
+ if ( Selectable != Session->Selectable )
+ {
+ Session->Selectable = Selectable;
+
+ // BUGBUG - send request to OS2.EXE
+ }
+ }
+
+ if (( a->StatusData.Length >= 6 ) &&
+ ( a->StatusData.BondInd != BOND_UNCHANGED ))
+ {
+ if ( a->StatusData.BondInd == BOND_CHILD )
+ {
+ if ( t->Process->Session->BindSession != Session )
+ {
+ // BUGBUG - send request to OS2.EXE
+
+ t->Process->Session->BindSession = Session;
+ }
+ } else
+ {
+ if ( t->Process->Session->BindSession == NULL )
+ {
+ m->ReturnedErrorValue = ERROR_SMG_NOT_BOUND;
+ } else
+ {
+
+ // BUGBUG - send request to OS2.EXE
+
+ t->Process->Session->BindSession = NULL;
+ }
+ }
+ }
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosStopSession(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSSTOPSESSION_MSG a = &m->u.DosStopSession;
+ POS2_SESSION Session = t->Process->Session;
+ ULONG i;
+
+ if ( a->fScope == DSS_SESSION )
+ {
+ if ( !a->SessionId ||
+ ( a->SessionId > OS2_MAX_SESSION ) ||
+ (( Session = SessionTable[a->SessionId - 1].Session ) == NULL ) ||
+ ( Session->RelatedSession != t->Process->Session ))
+ {
+ m->ReturnedErrorValue ==ERROR_SMG_INVALID_SESSION_ID;
+ //m->ReturnedErrorValue ==ERROR_SMG_SESSION_NOT_FOUND;
+ return( TRUE );
+ }
+
+ StopSessionAndChildSessions(Session);
+ m->ReturnedErrorValue = NO_ERROR;
+ } else
+ {
+ m->ReturnedErrorValue = ERROR_SMG_SESSION_NOT_FOUND;
+
+ for ( i = 0 ; i < OS2_MAX_SESSION ; i++ )
+ {
+ if (( SessionTable[i].Session != NULL ) &&
+ ( SessionTable[i].Session->RelatedSession == Session ))
+ {
+ StopSessionAndChildSessions(SessionTable[i].Session);
+ m->ReturnedErrorValue = NO_ERROR;
+ }
+ }
+
+ }
+
+ return( TRUE );
+}
+
+
+VOID
+StopSessionAndChildSessions(
+ IN POS2_SESSION Session
+ )
+{
+ ULONG i;
+ OS2SESREQUESTMSG RequestMsg;
+ HANDLE hThread;
+
+ /*
+ * stop all child sessions
+ */
+
+ if (!Session->WinSession)
+ {
+ for ( i = 0 ; i < OS2_MAX_SESSION ; i++ )
+ {
+ if (( SessionTable[i].Session != NULL ) &&
+ ( SessionTable[i].Session->RelatedSession == Session ))
+ {
+ StopSessionAndChildSessions(SessionTable[i].Session);
+ }
+ }
+
+ /*
+ * stop current session
+ */
+
+ if (Session->SesGrpAddress)
+ ((POS2_SES_GROUP_PARMS)Session->SesGrpAddress)->InTermination |= 2;
+ RequestMsg.d.Signal.Type = XCPT_SIGNAL_KILLPROC;
+ RequestMsg.Session = Session;
+
+ Os2CtrlSignalHandler(&RequestMsg, NULL);
+ } else
+ {
+ //TerminateProcess(Session->hProcess, 0);
+ GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, Session->dwProcessId);
+ if (hThread = Session->hWaitThread)
+ {
+
+#if DBG
+ DbgPrint("OS2SRV: ALERT !!! StopSessionAndChildSessions NtAlertThread(%x)\n",
+ hThread);
+#endif
+ NtAlertThread(hThread);
+ }
+ }
+}
+
+
+BOOLEAN
+Os2DosSmSetTitle(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+// POS2_SESSION Session;
+// NTSTATUS Status;
+// APIRET RetCode;
+// ULONG UniqueId;
+// HANDLE SessionPort;
+// SCREQUESTMSG Request;
+
+ UNREFERENCED_PARAMETER(t);
+
+ m->ReturnedErrorValue = NO_ERROR;
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosGetCtrlPortForSessionID(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+/*++
+
+Routine Description:
+
+ This function finds and returns an OS/2 session according to the session
+ ID and duplicate the control port handle for the process.
+
+Arguments:
+
+Return Value:
+
+ hControlPort field <= NULL - No session was found
+ NON-NULL - Returns the address of the required session
+
+--*/
+
+{
+ POS2_DOSGETCTRLPORTFORSESSION_MSG a = &m->u.DosGetCtrlPortForSession;
+ POS2_SESSION Session;
+ NTSTATUS Status;
+
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ {
+ DumpSessionTable("Os2DosGetCtrlPortForSessionID");
+ }
+#endif
+
+ Session = Os2GetSessionByUniqueId(a->SessionUniqueId);
+
+ if ( Session == NULL )
+ {
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ {
+ KdPrint(("Os2DosGetCtrlPortForSessionID: not found 0x%lx\n",
+ a->SessionUniqueId));
+ }
+#endif
+ a->hControlPort = NULL;
+ } else
+ {
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ {
+ KdPrint(("Os2DosGetCtrlPortForSessionID: Session %lx for Id 0x%lx\n",
+ Session, a->SessionUniqueId));
+ }
+#endif
+ Status = NtDuplicateObject( NtCurrentProcess(),
+ Session->ConsolePort,
+ t->Process->ProcessHandle,
+ &a->hControlPort,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS |
+ DUPLICATE_SAME_ATTRIBUTES
+ );
+
+ if( !NT_SUCCESS( Status ) )
+ {
+ ASSERT( FALSE );
+ a->hControlPort = NULL;
+ }
+ }
+
+ return( TRUE );
+}
+
+
+NTSTATUS
+Os2SessionFocusSet(
+ IN OUT PVOID RequestMsg
+ )
+{
+ POS2_SESSION Session = (POS2_SESSION) ((POS2SESREQUESTMSG)RequestMsg)->Session;
+ ULONG FocusSet = ((POS2SESREQUESTMSG)RequestMsg)->d.FocusSet;
+ GINFOSEG *pGlobalInfo = (GINFOSEG *) Os2GlobalInfoSeg;
+
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ {
+ KdPrint(("Os2SessionFocusSet: Session %d (%p), state %x (%s), sgCurrent %d\n",
+ Session->SessionId, Session,
+ FocusSet, ((FocusSet) ? "Set" : "Reset"),
+ pGlobalInfo->sgCurrent));
+ }
+#endif
+
+ if (FocusSet)
+ {
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ {
+ KdPrint(("Os2SessionFocusSet: set focus\n"));
+ }
+#endif
+ pGlobalInfo->sgCurrent = (UCHAR)Session->SessionId;
+ } else if (pGlobalInfo->sgCurrent == (UCHAR)Session->SessionId)
+ {
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ {
+ KdPrint(("Os2SessionFocusSet: reset focus to none\n"));
+ }
+#endif
+ pGlobalInfo->sgCurrent = 0;
+ } else
+ {
+#if DBG
+ IF_OS2_DEBUG( SESSIONMGR )
+ {
+ KdPrint(("Os2SessionFocusSet: no reset focus\n"));
+ }
+#endif
+ }
+
+ return(0L);
+}
+
+
+APIRET
+Os2CheckIfSessionTreeInFG(
+ IN POS2_SESSION Session
+ )
+{
+ // BUGBUG - check if any of the descendant is currently in the foreground
+
+ POS2_SESSION NextSession;
+ ULONG SessionId = (ULONG)((GINFOSEG *) Os2GlobalInfoSeg)->sgCurrent;
+
+ if (( SessionId > OS2_MAX_SESSION ) || !SessionId ||
+ (( NextSession = SessionTable[SessionId - 1].Session ) == NULL ))
+ {
+ return( ERROR_SMG_SESSION_NOT_PARENT );
+ }
+
+ while (( NextSession != Session ) &&
+ ( NextSession->RelatedSession ))
+ {
+ NextSession = NextSession->RelatedSession;
+ }
+
+ if ( NextSession == Session )
+ {
+ return( NO_ERROR );
+ }
+ return( ERROR_SMG_PROCESS_NOT_PARENT );
+}
+
+
+#if DBG
+VOID
+DumpSessionEntry(
+ IN PSZ Str,
+ IN POS2_SESSION Session
+ )
+{
+ ULONG Id = Session->SessionId;
+ KdPrint(("\n*** %s SESSION ENTRY st 0x%lx (%lx) ***\n", Str, Session, Id));
+ KdPrint((" Id 0x%lx, RefCnt 0x%lx, Related 0x%lx, Port 0x%lx, PId 0x%lx\n",
+ Session->SessionId, Session->ReferenceCount, Session->RelatedSession ,
+ Session->ConsolePort, Session->ProcessId));
+ if (( Id && (Id <= OS2_MAX_SESSION ) && SessionTable[Id].Session ))
+ {
+ KdPrint((" SessionTable-Waiters 0x%lx\n", SessionTable[Id - 1].Waiters.Flink->Flink));
+ }
+}
+
+
+VOID
+DumpSessionTable(
+ IN PSZ Str
+ )
+{
+ ULONG i;
+
+ KdPrint(("\n*** %s SESSION TABLE st ***\n", Str));
+ KdPrint(("Ent Session Waiters\n"));
+ for ( i = 0 ; i < 8 ; i++ )
+ {
+ KdPrint(("%1.1lx. %8.8lx %8.8lx\n",
+ i + 1, SessionTable[i].Session,
+ (SessionTable[i].Session) ? SessionTable[i].Waiters.Flink->Flink : NULL));
+ }
+ KdPrint(("*** End Table ***\n"));
+}
+#endif
diff --git a/private/os2/server/srvtask.c b/private/os2/server/srvtask.c
new file mode 100644
index 000000000..8c73c1911
--- /dev/null
+++ b/private/os2/server/srvtask.c
@@ -0,0 +1,4982 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvtask.c
+
+Abstract:
+
+ Tasking API
+
+Author:
+
+ Steve Wood (stevewo) 11-Oct-1989
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_ERRORS
+#define INCL_OS2V20_EXCEPTIONS
+#include "os2srv.h"
+#include "os2tile.h"
+#define NTOS2_ONLY
+#include "sesport.h"
+#include "os2win.h"
+#include <stdio.h>
+#if PMNT
+#define INCL_32BIT
+#include "pmnt.h"
+extern PID PMNTPMShellPid;
+#endif // PMNT
+
+extern HANDLE Os2SyncSem;
+
+#define TRC_C_ReadMem_I 1
+#define TRC_C_ReadMem_D 2
+#define TRC_C_ReadReg 3
+#define TRC_C_WriteMem_I 4
+#define TRC_C_WriteMem_D 5
+#define TRC_C_WriteReg 6
+#define TRC_C_Go 7
+#define TRC_C_Term 8
+#define TRC_C_SStep 9
+#define TRC_C_Stop 10
+#define TRC_C_Freeze 11
+#define TRC_C_Resume 12
+#define TRC_C_NumToSel 13
+#define TRC_C_GetFPRegs 14
+#define TRC_C_SetFPRegs 15
+#define TRC_C_GetLibName 16
+#define TRC_C_ThrdStat 17
+#define TRC_C_SUC_ret 0
+#define TRC_C_ERR_ret -1
+#define TRC_C_SIG_ret -2
+#define TRC_C_TBT_ret -3
+#define TRC_C_BPT_ret -4
+#define TRC_C_NMI_ret -5
+#define TRC_C_KIL_ret -6
+#define TRC_C_GPF_ret -7
+#define TRC_C_LIB_ret -8
+#define TRC_C_FPE_ret -9
+#define TRC_C_THD_ret -10
+#define TRC_C_STP_ret -11
+#define TRC_C_NEW_ret -12
+#define TRC_C_AFR_ret -13
+#define TRC_C_Thawed 0
+#define TRC_C_Frozen 1
+#define TRC_C_Runnable 0
+#define TRC_C_Suspended 1
+#define TRC_C_Blocked 2
+#define TRC_C_CritSec 3
+
+#define TRC_MustBeFrozen 1
+#define TRC_Frozen 2
+
+typedef struct _DbgThreadStatus {
+ UCHAR DebugState;
+ UCHAR ThreadState;
+ USHORT Priority;
+} DBGTHREADSTATUS;
+
+typedef struct _Os2ExitParam {
+ POS2_THREAD t;
+ POS2_API_MSG m;
+} OS2_EXIT_PARAM, POS2_EXIT_PARAM;
+
+HANDLE Os2hWritePipe;
+
+BOOLEAN Os2CLI = FALSE;
+POS2_THREAD Os2CLIThread;
+
+HANDLE FirstOs2ProcessHandle = (HANDLE)0;
+CLIENT_ID FirstOs2ProcessClientId;
+
+PVOID
+ldrFindMTEForHandle(
+ USHORT mte_handle);
+
+VOID
+Os2SigKillProcess(
+ POS2_PROCESS Process);
+
+VOID
+Os2SigKillProcessTree(
+ IN POS2_PROCESS RootProcess,
+ IN BOOLEAN IncludeRoot
+ );
+
+VOID
+Os2PrepareCmdSignals(
+ POS2_PROCESS Process);
+
+NTSTATUS
+Os2SendTmReleaseThreadOnLPC(IN POS2_SESSION Session, IN POS2_PROCESS Process);
+
+
+USHORT ldrFindSegForHandleandNum(
+ USHORT mte,
+ USHORT handle,
+ USHORT segnum);
+
+VOID
+ldrRestoreEntryPoint(
+ IN POS2_PROCESS Process
+ );
+
+UCHAR
+ldrGetEntryPoint(
+ IN POS2_PROCESS Process
+ );
+
+BOOLEAN
+ldrGetModName(
+ PVOID mte,
+ USHORT hmod,
+ PCHAR buf,
+ USHORT bc
+ );
+
+VOID
+ldrReturnProgramAndLibMTE(
+ IN POS2_PROCESS Process,
+ OUT USHORT *ProgramMTE,
+ OUT USHORT *LibMTE,
+ OUT USHORT *Cmd
+ );
+
+#if DBG
+PSZ DbgpKmApiName[ DbgKmMaxApiNumber+1 ] = {
+ "DbgKmException",
+ "DbgKmCreateThread",
+ "DbgKmCreateProcess",
+ "DbgKmExitThread",
+ "DbgKmExitProcess",
+ "DbgKmLoadDll",
+ "DbgKmUnloadDll",
+ "Unknown DbgKm Api Number"
+};
+#endif
+
+#if PMNT
+
+HANDLE hPMNTDevice = NULL;
+
+APIRET
+InitPMNTDevice()
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ STRING NameString;
+ UNICODE_STRING UnicodeString;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+
+ RtlInitString( &NameString, PMNTDD_DEVICE_NAME );
+
+ Status = RtlAnsiStringToUnicodeString(&UnicodeString,
+ &NameString,
+ TRUE );
+ ASSERT( NT_SUCCESS( Status ) );
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &UnicodeString,
+ 0,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile( &hPMNTDevice,
+ SYNCHRONIZE, // | FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttributes,
+ &IoStatus,
+ 0,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+
+ RtlFreeUnicodeString( &UnicodeString );
+
+ if ( !NT_SUCCESS( Status ) )
+ {
+#if DBG
+ KdPrint(("InitPMNTDevice: NtOpenFile failed, ret=%x\n", Status));
+#endif
+ return (Status);
+ }
+
+ return( NO_ERROR );
+}
+
+APIRET
+PMNTDDIOMap(
+ HANDLE ThreadHandle
+ )
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+
+ if (hPMNTDevice == NULL)
+ {
+ if (InitPMNTDevice() != NO_ERROR)
+ {
+#if DBG
+ DbgPrint("PMNT_IOCTL: failed to open PMNTDD\n");
+#endif
+
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ Status = NtDeviceIoControlFile( hPMNTDevice,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_PMNTDD_IO_MAP,
+ (PVOID)&ThreadHandle,
+ sizeof(ThreadHandle),
+ NULL, // output buffer
+ 0 // output buffer length
+ );
+
+ if NT_SUCCESS(Status)
+ {
+ return NO_ERROR;
+ }
+ else
+ {
+ DbgPrint("PMNTDDIOMap: Error, failed to call PMNTDD.SYS, Status=%x\n",
+ Status);
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_ACCESS_DENIED));
+ }
+
+ return NO_ERROR;
+}
+
+#endif // PMNT
+
+
+BOOLEAN
+PMHandledInOut(
+ POS2_THREAD Thread)
+{
+#if PMNT
+#if DBG
+ DbgPrint("WARNING: IN/OUT exception at [%x,%x], Handle=%x!!!\n",
+ Thread->Process->ProcessId,
+ Thread->ThreadId,
+ Thread->Process->ProcessHandle);
+#endif // DBG
+
+ if (PMNTDDIOMap(Thread->Process->ProcessHandle) == NO_ERROR)
+ {
+ return TRUE;
+ }
+ else
+ {
+#if DBG
+ DbgPrint("PMHandledInOut: returning FALSE !\n");
+#endif
+ return FALSE;
+ }
+#else
+ return(FALSE);
+#endif // not PMNT
+}
+
+
+VOID
+Os2SuspendProcess(
+ IN POS2_PROCESS Process
+ )
+
+/*+++
+
+Routine Description:
+
+ This routine is used to suspend an entire Os/2 client process
+
+Arguments:
+
+ Process - Process to suspend
+
+--*/
+{
+ POS2_THREAD Thread;
+ PLIST_ENTRY ListHead, ListNext;
+
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ Thread = NULL;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD(ListNext,
+ OS2_THREAD,
+ Link );
+ if (Thread == NULL)
+ break;
+ NtSuspendThread( Thread->ThreadHandle, NULL );
+ ListNext = ListNext->Flink;
+ }
+}
+
+VOID
+Os2ResumeProcess(
+ IN POS2_PROCESS Process
+ )
+
+/*+++
+
+Routine Description:
+
+ This routine is used to resume an entire Os/2 client process
+
+Arguments:
+
+ Process - Process to suspend
+
+--*/
+{
+ POS2_THREAD Thread;
+ PLIST_ENTRY ListHead, ListNext;
+
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ Thread = NULL;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD(ListNext,
+ OS2_THREAD,
+ Link );
+ if (Thread == NULL)
+ break;
+ NtResumeThread( Thread->ThreadHandle, NULL );
+ ListNext = ListNext->Flink;
+ }
+}
+
+NTSTATUS
+Os2CompleteResumeThread(
+ IN POS2_THREAD Thread
+ )
+{
+ ULONG SuspendCount;
+ NTSTATUS Status;
+
+ do {
+ Status = NtResumeThread (Thread->ThreadHandle, &SuspendCount);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("OS2SRV: [%d,%d] NtResumeThread Status=%x\n",
+ Thread->Process->ProcessId,
+ Thread->ThreadId,
+ Status);
+ ASSERT(FALSE);
+#endif // DBG
+ break;
+ }
+ } while (SuspendCount > 1);
+
+ return Status;
+}
+
+VOID
+Os2SetNewContext(
+ IN POS2_THREAD Thread,
+ PVOID CallSite)
+{
+ CONTEXT Context;
+ NTSTATUS Status;
+ POS2_PROCESS Process = Thread->Process;
+
+ Context.ContextFlags = CONTEXT_FULL;
+#if DBG
+ do {
+#endif // DBG
+
+ Status = NtGetContextThread(Thread->ThreadHandle, &Context);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("OS2SRV: [%d,%d] Fail to get context, Status=%x\n",
+ Process->ProcessId,
+ Thread->ThreadId,
+ Status);
+ ASSERT(FALSE);
+#endif // DBG
+ return;
+ }
+
+#if DBG
+ //
+ // Hack that avoid exit list (or infinite sleep) handler execution if the thread is
+ // using INT 3 instruction. Relevant for checked build only.
+ //
+ if (Context.SegCs == 0x1b && Context.SegSs == 0x23) {
+ BYTE opcode;
+
+ Status = NtReadVirtualMemory( Process->ProcessHandle,
+ (PVOID)(Context.Eip - 1), // previous byte
+ &opcode,
+ 1,
+ NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d]Os2SetNewContext: Fail to read instruction, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+ break;
+ }
+ if (opcode == 0xcc) { // INT 3
+
+ DbgPrint("[%d]Os2SetNewContext: after INT 3\n",
+ Process->ProcessId);
+
+ Os2CompleteResumeThread(Thread);
+ Sleep(100L); // 0.1 sec
+ NtSuspendThread(Thread->ThreadHandle, NULL);
+ }
+ else
+ break;
+ }
+ else
+ break;
+ } while (TRUE);
+#endif // DBG
+
+ Context.SegSs = Context.SegDs = Context.SegEs = 0x23;
+ Context.SegCs = 0x1b;
+ Context.Eip = (ULONG) CallSite;
+ Context.Esp = Thread->InitialStack;
+ Context.EFlags &= 0xfffffbff; // Clear direction flag. By default run-time
+ // library assume that direction flag is cleared.
+ // RtlMoveMemory, for example, don't clear this
+ // flag on entry, but assume it 0.
+
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ DbgPrint("Os2SetNewContext [%d]: Stack=%x\n",
+ Process->ProcessId,
+ Context.Esp);
+ }
+#endif //DBG
+
+ Status = NtSetContextThread(Thread->ThreadHandle, &Context);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("OS2SRV: [%d,%d] Fail to set context, Status=%x\n",
+ Process->ProcessId,
+ Thread->ThreadId,
+ Status);
+ ASSERT(FALSE);
+#endif // DBG
+ return;
+ }
+}
+
+VOID
+Os2ForceProcessToSleep(
+ IN POS2_PROCESS Process
+ )
+{
+ POS2_THREAD Thread;
+ PLIST_ENTRY ListHead, ListNext;
+
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ Thread = NULL;
+
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD(ListNext,
+ OS2_THREAD,
+ Link );
+ if (Thread == NULL)
+ break;
+
+ if (!Thread->MustComplete) {
+
+ Os2SetNewContext(Thread, Process->InfiniteSleep);
+
+ //
+ // Resume thread. It will wait in the infinite alertable wait.
+ //
+
+ Os2CompleteResumeThread(Thread);
+ }
+
+ ListNext = ListNext->Flink;
+ }
+}
+
+VOID SetDebuggeeContextInMsg(
+ IN PCONTEXT pContext,
+ pPTRACEBUF pptracebuf)
+{
+ //
+ // set ptracbuf value from context
+ //
+ pptracebuf->rAX = (USHORT) pContext->Eax;
+ pptracebuf->rBX = (USHORT) pContext->Ebx;
+ pptracebuf->rCX = (USHORT) pContext->Ecx;
+ pptracebuf->rDX = (USHORT) pContext->Edx;
+ pptracebuf->rSI = (USHORT) pContext->Esi;
+ pptracebuf->rDI = (USHORT) pContext->Edi;
+ pptracebuf->rBP = (USHORT) pContext->Ebp;
+ pptracebuf->rDS = (USHORT) pContext->SegDs;
+ pptracebuf->rES = (USHORT) pContext->SegEs;
+ pptracebuf->rIP = (USHORT) pContext->Eip;
+ pptracebuf->rCS = (USHORT) pContext->SegCs;
+ pptracebuf->rF = (USHORT) pContext->EFlags; // BUGBUG ???
+ pptracebuf->rSP = (USHORT) pContext->Esp;
+ pptracebuf->rSS = (USHORT) pContext->SegSs;
+}
+
+BOOLEAN
+Os2CreateExitThread(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m,
+ PFNTHREAD pTerminationThread
+ )
+{
+ //
+ // Create a thread and pass it the parameters. The message
+ // is created internally, so we copy it to a new structure.
+ //
+ ULONG Tid;
+ HANDLE ExitThreadHandle;
+ POS2_DOSEXIT_MSG b;
+ POS2_API_MSG m1 = RtlAllocateHeap(Os2Heap, 0, sizeof(OS2_API_MSG));
+ POS2_DOSEXIT_MSG a = &m->u.DosExit;
+
+ m->ApiNumber = Os2Exit;
+
+ if (!m1)
+ return FALSE;
+
+ PORT_MSG_DATA_LENGTH(*m1) = PORT_MSG_DATA_LENGTH(*m);
+ PORT_MSG_TOTAL_LENGTH(*m1) = PORT_MSG_TOTAL_LENGTH(*m);
+ PORT_MSG_ZERO_INIT(*m1) = 0L;
+ b = &m1->u.DosExit;
+ b->ExitAction = a->ExitAction;
+ b->ExitResult = a->ExitResult;
+ m1->ApiNumber = Os2Exit;
+ m1->h.ClientId = t->ClientId;
+
+ ExitThreadHandle = CreateThread( NULL,
+ 0,
+ pTerminationThread,
+ m1,
+ 0,
+ &Tid);
+ if (!ExitThreadHandle){
+#if DBG
+ DbgPrint("OS2SRV: - fail with error %d at win32 CreateThread - Extend your non-paged pool\n",
+ GetLastError());
+#endif
+ ASSERT(FALSE);
+ RtlFreeHeap(Os2Heap, 0, m1);
+ return (FALSE);
+ }
+
+ //
+ // Suspend the process, so when we return it does not
+ // do anything until Os2DosExitThread finishes it
+ //
+ Os2SuspendProcess(t->Process);
+ NtClose(ExitThreadHandle);
+
+ //
+ // return to the internal server thread
+ //
+ return(TRUE);
+}
+
+VOID
+Os2DosExitThread(
+ IN PVOID Parameter
+ )
+{
+ //
+ // This thread is created in Os2DosExit, to free up internal server
+ // threads so
+ // they don't lock when trying to terminate threads/processes
+ //
+
+ POS2_API_MSG m = (POS2_API_MSG)Parameter;
+ POS2_THREAD t;
+
+ Os2AcquireStructureLock();
+ t = Os2LocateThreadByClientId( NULL /*Process*/, &m->h.ClientId );
+ if (t != NULL) {
+ Os2DosExit( t,m );
+ }
+ Os2ReleaseStructureLock();
+ RtlFreeHeap( Os2Heap, 0, m );
+ ExitThread(0);
+}
+
+VOID
+Os2WaitSyncAndExitThread(
+ IN PVOID Parameter
+ )
+{
+ POS2_API_MSG m = (POS2_API_MSG)Parameter;
+ POS2_THREAD t;
+ NTSTATUS Status;
+
+ Status = NtWaitForSingleObject(
+ Os2SyncSem,
+ TRUE,
+ NULL);
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DbgPrint("OS2SRV: Wait to Sync Sem, Status=%x\n",
+ Status);
+ }
+#endif // DBG
+ Os2AcquireStructureLock();
+ t = Os2LocateThreadByClientId( NULL /*Process*/, &m->h.ClientId );
+ if (t != NULL) {
+ Os2SuspendProcess(t->Process);
+ }
+ else
+ {
+#if DBG
+ DbgPrint("OS2SRV: Can't find the thread that cause process termination\n");
+ ASSERT(FALSE);
+#endif // DBG
+ }
+ Status = NtReleaseMutant(Os2SyncSem, NULL);
+#if DBG
+ if (!NT_SUCCESS(Status)){
+ DbgPrint("OS2SRV: Fail to release Sync Sem, Status=%x\n",
+ Status);
+ }
+#endif // DBG
+ if (t != NULL) {
+ Os2DosExit( t,m );
+ }
+ Os2ReleaseStructureLock();
+ RtlFreeHeap( Os2Heap, 0, m );
+ ExitThread(0);
+}
+
+BOOLEAN
+Os2DosExit(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the DosExit API.
+
+Arguments:
+
+ t - calling thread
+
+ m - message
+
+Return Value:
+
+ TRUE - create a return message
+
+Note:
+ the flow of control for terminating a process is
+ DosExit
+ Call Os2InternalTerminateThread for each thread
+ when only thread 1 is left, exit list processing is done
+ when exit list processing is done, it calls Oi2TerminateProcess
+
+--*/
+
+{
+ POS2_DOSEXIT_MSG a = &m->u.DosExit;
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_PROCESS Process = t->Process;
+ POS2_THREAD Thread, Thread1;
+ ULONG SyncOwner;
+ NTSTATUS Status;
+
+ //
+ // Allow for asynchronous execution of Os2DosExit - in the case
+ // it is called by an internal server thread, not by the OS/2 application
+ // the flag for this is that m->ApiNumber = Os2MaxApiNumber; This would
+ // not pass the test in server\apireqst.c
+ //
+
+ if (m->ApiNumber == Os2MaxApiNumber) {
+ if ((t->Flags & OS2_THREAD_THREAD1) &&
+ (Process->ExitStatus & OS2_EXIT_IN_PROGRESS)) {
+ return FALSE;
+ }
+ if (Os2CreateExitThread(
+ t,
+ m,
+ (PFNTHREAD)Os2DosExitThread)) {
+ return FALSE;
+ }
+ // Try to perform the Os2DosExit synchronsously
+ }
+
+ m->ReturnedErrorValue = a->ExitResult;
+
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Entering Os2DosExit - PID %d, TID %d\n", t->Process->ProcessId, t->ThreadId));
+ }
+#endif
+
+ if (a->ExitAction == EXIT_THREAD && (t->Flags & OS2_THREAD_THREAD1)) {
+ a->ExitAction = EXIT_PROCESS;
+ }
+
+ //
+ // Guard against races between abrupt exit (signal) and programmatic
+ // exit
+ //
+ if (!(Process->ExitStatus & OS2_EXIT_WAIT_FOR_SYNC)) {
+ if (Process->ExitStatus & OS2_EXIT_IN_PROGRESS){
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Os2DosExit, Exit already in progress, quit\n"));
+ }
+#endif
+ return(FALSE);
+ }
+ else {
+ //
+ // if we start to exit a process, mark it appropriately
+ //
+ if(a->ExitAction == EXIT_PROCESS) {
+ Process->ExitStatus |= OS2_EXIT_IN_PROGRESS;
+ }
+ }
+ }
+
+ if (a->ExitAction == EXIT_PROCESS) {
+
+ Os2SuspendProcess(Process);
+
+ Status = NtReadVirtualMemory( Process->ProcessHandle,
+ &Process->ClientPib->SyncOwner,
+ &SyncOwner,
+ sizeof( Process->ClientPib->SyncOwner ),
+ NULL
+ );
+
+ if (NT_SUCCESS(Status)) {
+ if (SyncOwner != 0) {
+
+ // There is the thread that owns SyncSem. We must wait until it
+ // will free it. For this reason create new thread that will
+ // perform actual termination.
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ DbgPrint("OS2SRV: Termination from [%d,%d] find that SYNC was owned by %d\n",
+ Process->ProcessId,
+ t->ThreadId,
+ SyncOwner);
+ }
+#endif // DBG
+#if DBG
+ if (Process->ExitStatus & OS2_EXIT_WAIT_FOR_SYNC) {
+ DbgPrint("OS2SRV: Process own Sync Sem once more\n");
+ ASSERT(FALSE);
+ }
+#endif // DBG
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
+ ListNext = ListNext->Flink;
+ if ((ULONG) Thread->ThreadId == SyncOwner) {
+ break;
+ }
+ continue;
+ }
+#if DBG
+ if ((ULONG) Thread->ThreadId != SyncOwner) {
+ DbgPrint("OS2SRV: Can't find thread owner SyncSem\n");
+ ASSERT(FALSE);
+ }
+#endif // DBG
+ if (Os2CreateExitThread(
+ t,
+ m,
+ (PFNTHREAD)Os2WaitSyncAndExitThread)) {
+
+ Process->ExitStatus |= OS2_EXIT_WAIT_FOR_SYNC;
+
+ Os2CompleteResumeThread(Thread);
+
+ return FALSE; // Don't reply
+ }
+ // Try to continue termination without waiting to Sync Sem
+#if DBG
+ DbgPrint("OS2SRV: WARNING!!! Process owner Sync Sem will be terminated\n");
+#endif // DBG
+ }
+ }
+ else
+ {
+#if DBG
+ DbgPrint("OS2SRV: Fail to read PIB of the client, Status=%x\n",
+ Status);
+#endif // DBG
+ }
+
+ //
+ // Change context of each thread to infinite sleep routine. The threads
+ // will be resumed so the kernel process lock will be free. This will
+ // permit to perform actions on the process such as threads termination.
+ // On other hand all threads will be in the wait stat and they can't harm.
+ //
+ Os2ForceProcessToSleep(Process);
+
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
+ ListNext = ListNext->Flink;
+ if (Thread->Dying || (Thread->Flags & OS2_THREAD_THREAD1)) {
+ Thread1 = Thread;
+ continue;
+ }
+ if (!Thread->MustComplete) {
+ Thread->CurrentSignals |= SIGNAL_TO_FLAG(SIGAPTERM);
+ if (Thread->WaitBlock != NULL) {
+ Thread->WaitBlock->WaitReplyMessage.ReturnedErrorValue = ERROR_INTERRUPT;
+ Os2NotifyWaitBlock(Thread->WaitBlock,WaitInterrupt,NULL,NULL);
+ }
+ Os2InternalTerminateThread(Thread, m);
+ }
+ else {
+#if DBG
+ KdPrint(( "Os2DosExit, ThreadMustComplete %d\n", Thread->ThreadId));
+#endif
+ Thread->PendingSignals |= SIGNAL_TO_FLAG(SIGAPTERM);
+ }
+ }
+ //
+ // Terminate Thread1 last
+ //
+ Thread = Thread1;
+ if (!Thread->MustComplete) {
+ Thread->CurrentSignals |= SIGNAL_TO_FLAG(SIGAPTERM);
+ if (Thread->WaitBlock != NULL) {
+ Thread->WaitBlock->WaitReplyMessage.ReturnedErrorValue = ERROR_INTERRUPT;
+ Os2NotifyWaitBlock(Thread->WaitBlock,WaitInterrupt,NULL,NULL);
+ }
+ Os2InternalTerminateThread(Thread, m);
+ }
+ }
+ else if (a->ExitAction == EXIT_THREAD) {
+
+ Thread = t;
+ if (Thread->Dying) {
+ }
+ else {
+ if (!Thread->MustComplete) {
+
+ Thread->CurrentSignals |= SIGNAL_TO_FLAG(SIGAPTERM);
+ if (Thread->WaitBlock != NULL) {
+ Thread->WaitBlock->WaitReplyMessage.ReturnedErrorValue = ERROR_INTERRUPT;
+ Os2NotifyWaitBlock(Thread->WaitBlock,WaitInterrupt,NULL,NULL);
+ }
+
+ Os2InternalTerminateThread(Thread, m);
+ }
+ else {
+ Thread->PendingSignals |= SIGNAL_TO_FLAG(SIGAPTERM);
+ }
+ }
+ }
+ else {
+ m->ReturnedErrorValue = ERROR_INVALID_PARAMETER;
+ }
+
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Leaving Os2DosExit. rc is %ld\n",m->ReturnedErrorValue));
+ }
+#endif
+
+ return( FALSE );
+}
+
+VOID
+Os2ForceClientCleanup(
+ IN POS2_THREAD t
+ )
+{
+ //
+ // This routine is used in the case where a 16b ExitList Routine
+ // encounters a GP while we close an app. We want the exitlistdispatcher
+ // to cleanup the client state
+ //
+ Os2SetNewContext(t, t->Process->ExitListDispatcher);
+
+ //
+ // Now resume and alert the thread (came in suspended)
+ // get the chance now to execute the ExitList Dispatcher
+ //
+ Os2CompleteResumeThread(t);
+}
+
+VOID
+Os2ApiGPPopupThread(
+ IN PVOID Parameter
+ )
+{
+ POS2_THREAD t;
+ POS2_API_MSG m = (POS2_API_MSG)Parameter;
+ UCHAR ApplName[OS2_PROCESS_MAX_APPL_NAME];
+
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Os2ApiGPPopupThread\n"));
+ }
+#endif
+
+ __try {
+
+ Os2AcquireStructureLock();
+ t = Os2LocateThreadByClientId( NULL /*Process*/, &m->h.ClientId );
+
+ if (t == NULL){
+ //
+ // Another event caused this thread to be removed before we got the lock
+ //
+#if DBG
+ DbgPrint("OS2SRV: ApiGPPopupThread occurred while executing API %s, thread terminated, cancel popup\n", &m->u.DosExitGP.ApiName[0]);
+#endif
+ Os2ReleaseStructureLock();
+ __leave;
+ }
+
+ RtlCopyMemory(ApplName, t->Process->ApplName, OS2_PROCESS_MAX_APPL_NAME);
+#if PMNT
+ Os2ReleaseStructureLock();
+#endif // PMNT
+
+#if DBG
+ DbgPrint("OS2SRV: GP occurred while executing API %s\n", &m->u.DosExitGP.ApiName[0]);
+#endif
+
+ Os2ApiGPPopup(
+ ApplName,
+ &m->u.DosExitGP.ApiName[0]
+ );
+
+#if PMNT
+ Os2AcquireStructureLock();
+ t = Os2LocateThreadByClientId( NULL /*Process*/, &m->h.ClientId );
+
+ if (t == NULL){
+ //
+ // Another event caused this thread to be removed before we got the lock
+ //
+#if DBG
+ DbgPrint("OS2SRV: Os2ApiGPPopupThread: thread terminated already\n");
+#endif
+ Os2ReleaseStructureLock();
+ __leave;
+ }
+#endif // PMNT
+
+ if ((t->Flags & OS2_THREAD_THREAD1) &&
+ (t->Process->ExitStatus & OS2_EXIT_IN_PROGRESS)){
+ //
+ // An Exception happened while processing exit list - terminate the process
+ //
+#if DBG
+ DbgPrint("OS2SRV: GP occurred while executing exitlist routine\n");
+#endif
+ Os2ForceClientCleanup(t);
+ Os2ReleaseStructureLock();
+ __leave;
+ }
+
+ {
+ POS2_DOSEXIT_MSG b = &m->u.DosExit;
+ b->ExitAction = EXIT_PROCESS;
+ b->ExitResult = 13;
+ ASSERT(m->h.ClientId.UniqueProcess == t->ClientId.UniqueProcess);
+ ASSERT(m->h.ClientId.UniqueThread == t->ClientId.UniqueThread);
+ Os2DosExit(t, m);
+ }
+
+ Os2ReleaseStructureLock();
+ }
+ __finally {
+ RtlFreeHeap(Os2Heap, 0, m);
+ ExitThread(0);
+ }
+}
+
+BOOLEAN
+Os2DosExitGP(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ t - calling thread
+
+ m - message
+
+Return Value:
+
+ TRUE - create a return message
+
+Note:
+ After Popup the message, this routine calls Os2DosExit.
+
+--*/
+
+{
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Entering Os2DosExitGP\n"));
+ }
+#endif
+
+ if (t->Process->ErrorAction & OS2_ENABLE_ACCESS_VIO_POPUP) {
+
+ //
+ // Create a separate thread to do the popup and kill the process
+ //
+ ULONG Tid;
+ POS2_API_MSG pm1;
+
+ pm1 = RtlAllocateHeap(Os2Heap, 0, sizeof(OS2_API_MSG));
+
+ if (pm1) {
+ HANDLE GPThreadHandle;
+
+ RtlCopyMemory(pm1, m, sizeof(OS2_API_MSG));
+ GPThreadHandle = CreateThread( NULL,
+ 0,
+ (PFNTHREAD)Os2ApiGPPopupThread,
+ pm1,
+ 0,
+ &Tid);
+ if (!GPThreadHandle){
+#if DBG
+ KdPrint(("Os2ExitGP - fail at win32 CreateThread, %d\n",GetLastError()));
+#endif
+ RtlFreeHeap(Os2Heap, 0, pm1);
+ }
+ else {
+ Os2SuspendProcess(t->Process);
+ NtClose(GPThreadHandle);
+ return (FALSE);
+ }
+ }
+ else {
+#if DBG
+ KdPrint(("Os2ExitGP - fail at RtlAllocateHeap\n"));
+#endif
+ }
+ }
+
+ if ((t->Flags & OS2_THREAD_THREAD1) &&
+ (t->Process->ExitStatus & OS2_EXIT_IN_PROGRESS)){
+ //
+ // An Exception happened while processing exit list - terminate the process
+ //
+#if DBG
+ DbgPrint("OS2SRV: GP occurred while executing exitlist routine\n");
+#endif
+ Os2ForceClientCleanup(t);
+ return(FALSE);
+ }
+
+ {
+ OS2_API_MSG m1;
+ POS2_DOSEXIT_MSG b = &m1.u.DosExit;
+ m1.h.ClientId = t->ClientId;
+ b->ExitAction = EXIT_PROCESS;
+ b->ExitResult = 13;
+ return Os2DosExit(t, &m1);
+ }
+}
+
+BOOLEAN
+Os2InternalTerminateProcess(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+ This routine terminates a process. It is called after exit list processing
+ has completed. It frees thread one and the process and alerts anyone
+ waiting on the thread or process.
+
+Arguments:
+
+ t - thread one of process to terminate.
+
+ m - message
+
+Return Value:
+
+ FALSE - do not return message
+
+--*/
+
+{
+ POS2_TERMINATEPROCESS_MSG a = &m->u.TerminateProcess;
+ POS2_PROCESS Process = t->Process;
+ POS2_PROCESS RootProcessInSession;
+ OS2_TERMCMD Os2TermCmd;
+ ULONG nNumberOfBytesWritten;
+ BOOLEAN LoadingFailed = FALSE;
+ BOOLEAN CheckForBackgound = FALSE;
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Entering Os2InternalTerminateProcess\n"));
+ }
+#endif
+
+#if PMNT
+ //
+ // Check for termination of PMShell
+ //
+ if (PMNTPMShellPid == t->Process->ProcessId)
+ {
+ UNICODE_STRING EventString_U;
+ OBJECT_ATTRIBUTES Obja;
+ NTSTATUS Status;
+ HANDLE Od2PMShellEvent;
+
+ PMNTPMShellPid = 0;
+
+ // Now reset the PMShell event to the not-signaled state
+
+ RtlInitUnicodeString( &EventString_U, OS2_SS_PMSHELL_EVENT);
+ InitializeObjectAttributes(
+ &Obja,
+ &EventString_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ //
+ // Open the global subsystem synchronization Nt semaphore
+ //
+ Status = NtOpenEvent(&Od2PMShellEvent,
+ EVENT_ALL_ACCESS,
+ &Obja);
+
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ DbgPrint("OS2SRV: Od2DosExit(), failed to open PMShellEvent, Status %x\n", Status);
+#endif // DBG
+ }
+ else
+ {
+ Status = NtResetEvent (
+ Od2PMShellEvent,
+ NULL);
+#if DBG
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("OS2SRV: Od2DosExit(), failed to NtResetEvent PMShellEvent, Status %x\n", Status);
+ }
+#endif // DBG
+ }
+ }
+#endif // PMNT
+
+// printf("Os2 time at start of Os2InternalTerminateProcess is %d\n", (GetTickCount()));
+ NtClose(Process->ClientPort);
+ if (Process->ResultCodes.ExitReason != TC_TRAP) {
+ Process->ResultCodes.ExitReason = a->ExitReason;
+ Process->ResultCodes.ExitResult = ~0x80000000 & a->ExitResult;
+ if ((a->ExitResult & 0x80000000) != 0) {
+ LoadingFailed = TRUE;
+ }
+ }
+#if DBG
+ if (!(t->Flags & OS2_THREAD_THREAD1))
+ KdPrint(("OS2SRV: Os2InternalTerminateProcess - OS2_THREAD_THREAD1=0 \n"));
+#endif
+ Os2RemoveThread( Process, t );
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(("OS2SRV: Os2InternalTerminateProcess - 1 \n"));
+ }
+#endif
+
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(("OS2SRV: Os2InternalTerminateProcess - 2 \n"));
+ }
+#endif
+
+ RootProcessInSession = Process->Session->Process;
+
+ if (Process->Parent != Os2RootProcess || RootProcessInSession != Process) {
+ //
+ // Terminate the thread only in the case of
+ // a process that was created as a result of an OS/2 API.
+ // Otherwise the client itself issues ExitProcess
+ // as a result of ServeTmRequest.
+ //
+ Os2TermCmd.Param1 = 0;
+ Os2TermCmd.op = Os2TerminateThread;
+ Os2TermCmd.Handle = t->ThreadHandle;
+ if (!WriteFile(
+ Os2hWritePipe,
+ (VOID *)&Os2TermCmd,
+ sizeof(Os2TermCmd),
+ &nNumberOfBytesWritten,
+ NULL)) {
+ //
+ // The Pipe of Os2TerminationThread is full
+ //
+ ASSERT(FALSE);
+#if DBG
+ KdPrint(("OS2SRV: Os2InternalTerminateProcess: can't post thread termination command, status %d, ignore\n",
+ GetLastError()));
+#endif
+
+ }
+ }
+ else {
+ NtClose( t->ThreadHandle );
+ }
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(("OS2SRV: Os2InternalTerminateProcess - 3 \n"));
+ }
+#endif
+ if (Process->Flags & OS2_PROCESS_TRACE){
+ Os2NotifyWait( WaitProcess, Process, (PVOID) a);
+ }
+
+ Os2DeallocateThread( t );
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(("OS2SRV: Os2InternalTerminateProcess - 4 \n"));
+ }
+#endif
+ if (Process->Session->ReferenceCount > 1){
+ CheckForBackgound = TRUE;
+ }
+ if(Os2DereferenceSession(Process->Session, a, (BOOLEAN)FALSE)==NULL){
+ Process->Session=NULL;
+ }
+
+ if (Process->Parent == Os2RootProcess && RootProcessInSession == Process) {
+ //
+ // Root Process of a Session
+ //
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_PROCESS Process1;
+ BOOLEAN FoundForeground = FALSE;
+
+ NtClose( Process->ProcessHandle );
+ //
+ // check if all of the remaining processes in the session are detached
+ // if so - let the root process of the session go
+ //
+ if (CheckForBackgound){
+ for (
+ ListHead = &Os2RootProcess->ListLink,
+ ListNext = ListHead->Flink;
+ ListNext != ListHead ;
+ ListNext = ListNext->Flink
+ ) {
+ Process1 = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
+ if ( Process1->Session == Process->Session && Process1 != Process) {
+ //
+ // check if detach
+ //
+ if (!(Process1->Flags & OS2_PROCESS_BACKGROUND)) {
+ FoundForeground = TRUE;
+ break;
+ }
+ }
+
+ }
+ if (!FoundForeground){
+ //
+ // Scanned the whole list - no foreground child - allow
+ // root process to quit
+ //
+ Os2TerminateConSession ( Process->Session,
+ a);
+ //
+ // No more calls to sesssion->consoleport
+ //
+ NtClose(Process->Session->ConsolePort);
+ Process->Session->ConsolePort = NULL;
+ }
+ }
+ }
+
+ Os2RemoveProcess( Process );
+ if (!LoadingFailed) {
+ LDRUnloadExe(Process);
+ }
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(("OS2SRV: Os2InternalTerminateProcess - 5 \n"));
+ }
+#endif
+ //
+ // Now do config.sys cleanup processing
+ //
+ if (Process->ConfigSysUsageFlag) {
+ Os2UpdateRegistryFromConfigSys();
+ Process->ConfigSysUsageFlag = FALSE;
+ }
+
+ if (Process->Parent == Os2RootProcess && RootProcessInSession == Process) {
+ //
+ // This process was created from win32 - can safely free structure
+ // at this point
+ //
+ Os2DeallocateProcess( Process );
+ }
+ else {
+ //
+ // This is a process that was created as a result of an OS/2 API.
+ // We have to terminate it. The RootProcess of each session is quiting
+ // by itself as a result of the last Os2DereferenceSession
+ // The termination thread will call Os2NotifyDeathOfProcess which will
+ // deallocate the process
+ //
+ Os2TermCmd.op = Os2TerminateProcess;
+ Os2TermCmd.Handle = Process->ProcessHandle;
+ Os2TermCmd.Param1 = m;
+ Os2TermCmd.Param2 = Process;
+
+ if (!WriteFile(
+ Os2hWritePipe,
+ (VOID *)&Os2TermCmd,
+ sizeof(Os2TermCmd),
+ &nNumberOfBytesWritten,
+ NULL)){
+
+ //
+ // The Pipe of Os2TerminationThread is full
+ //
+ ASSERT(FALSE);
+#if DBG
+ KdPrint(("OS2SRV: Os2InternalTerminateProcess: can't post process termination command, status %d, ignore\n",
+ GetLastError()));
+#endif
+
+ }
+ }
+
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Leaving Os2InternalTerminateProcess\n"));
+ }
+#endif
+
+ return (FALSE);
+}
+
+VOID
+Os2NotifyDeathOfProcess(
+ IN PVOID m,
+ IN PVOID Proc)
+{
+
+ POS2_PROCESS Process = (POS2_PROCESS)Proc;
+ POS2_TERMINATEPROCESS_MSG a = &((POS2_API_MSG)m)->u.TerminateProcess;
+
+ //
+ // Now notify processes waiting on this process termination
+ //
+ Os2NotifyWait( WaitProcess, Process, (PVOID) a);
+ Os2DeallocateProcess( Process );
+}
+
+BOOLEAN
+Os2WaitDeadThreadSatisfy(
+ IN OS2_WAIT_REASON WaitReason,
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m,
+ IN PVOID WaitParameter,
+ IN PVOID SatisfyParameter1,
+ IN PVOID SatisfyParameter2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used by thread one when waiting for all other threads
+ in the process to die.
+
+Arguments:
+
+ N/A
+
+Return Value:
+
+ TRUE - create a return message
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(WaitReason);
+ UNREFERENCED_PARAMETER(t);
+ UNREFERENCED_PARAMETER(m);
+ UNREFERENCED_PARAMETER(WaitParameter);
+ UNREFERENCED_PARAMETER(SatisfyParameter1);
+ UNREFERENCED_PARAMETER(SatisfyParameter2);
+ return TRUE;
+}
+
+// This routine will be called from TerminationThread to set the context
+// of thread1 to exit list dispatcher.
+
+VOID
+Os2SwitchContextToExitListDispatcher(
+ IN PVOID Thread
+ )
+{
+ NtSuspendThread(((POS2_THREAD)Thread)->ThreadHandle, NULL);
+ Os2SetNewContext((POS2_THREAD)Thread,
+ ((POS2_THREAD)Thread)->Process->ExitListDispatcher);
+
+ //
+ // Now "alert" the thread - in case it is blocked, it'll
+ // get the chance now to execute the ExitList Dispatcher
+ //
+ NtAlertThread(((POS2_THREAD)Thread)->ThreadHandle);
+
+ if (!(((POS2_THREAD)Thread)->Process->Flags & OS2_PROCESS_TRACE) ||
+ (((POS2_THREAD)Thread)->Process->Flags & OS2_PROCESS_TERMINATE)) {
+ Os2CompleteResumeThread((POS2_THREAD)Thread);
+ }
+}
+
+BOOLEAN
+Os2InternalTerminateThread(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+ This routine terminates a thread. If it is thread one, it dispatches
+ exit list processing. Otherwise, it frees the thread and alerts
+ anyone waiting on the thread.
+
+Arguments:
+
+ t - thread to terminate
+
+ m - message
+
+Return Value:
+
+ TRUE - create a return message
+
+--*/
+
+{
+ POS2_DOSEXIT_MSG a = &m->u.DosExit;
+ POS2_THREAD Thread1;
+ POS2_PROCESS Process;
+ POS2_WAIT_BLOCK WaitBlock;
+ BOOLEAN ReturnValue;
+
+ OS2_TERMCMD Os2TermCmd;
+ ULONG nNumberOfBytesWritten;
+
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Entering Os2InternalTerminateThread - TID %d\n", t->ThreadId));
+ }
+#endif
+
+ Process = t->Process;
+
+ //
+ // if we're thread 1, dispatch exit list processing.
+ //
+ // note: thread 1 must notify any waits before it waits for other
+ // threads to complete. otherwise, the other threads will never finish.
+ //
+
+ if (t->Flags & OS2_THREAD_THREAD1) {
+ Os2NotifyWait( WaitThread, t, NULL );
+ if (t->Dying) {
+#if DBG
+ KdPrint(("InternalTerminateThread - Thread1 died already\n"));
+#endif
+ }
+ t->Dying = TRUE;
+ //
+ // dispatch exitlist processing
+ //
+
+ Process->Flags |= OS2_PROCESS_EXIT;
+
+ Os2SendTmReleaseThreadOnLPC(Process->Session, Process);
+ if (t->Link.Flink == t->Link.Blink) { // no other threads exist
+ ReturnValue = TRUE;
+ }
+ else {
+ if (!Os2InitializeWait((OS2_WAIT_ROUTINE) Os2WaitDeadThreadSatisfy,
+ t,
+ m,
+ 0,
+ &WaitBlock)) {
+ ASSERT (FALSE);
+ }
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Os2InternalTerminateThread: Thread1 handled, Wait Initialized\n"));
+ }
+#endif
+ ReturnValue = TRUE;
+ }
+ Os2TermCmd.Param1 = (PVOID)1; // mean resume this thread for exitlist processing
+ Os2TermCmd.Param2 = (PVOID)t; // used to set new context for the thread.
+ Os2TermCmd.op = Os2TerminateThread;
+ Os2TermCmd.Handle = t->ThreadHandle;
+ if (!WriteFile(
+ Os2hWritePipe,
+ (VOID *)&Os2TermCmd,
+ sizeof(Os2TermCmd),
+ &nNumberOfBytesWritten,
+ NULL)){
+ //
+ // The Pipe of Os2TerminationThread is full
+ //
+ ASSERT(FALSE);
+#if DBG
+ KdPrint(("OS2SRV: Os2InternalTerminateThread: can't post thread termination command, status %d, ignore\n",
+ GetLastError()));
+#endif
+ }
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Leaving Os2InternalTerminateThread\n"));
+ }
+#endif
+ return( ReturnValue );
+ }
+ else {
+ //
+ // Find Thread1
+ //
+ POS2_THREAD ThreadTmp;
+ PLIST_ENTRY ListHead2, ListNext2;
+
+ ListHead2 = &Process->ThreadList;
+ ListNext2 = ListHead2->Flink;
+ Thread1 = NULL;
+ while (ListNext2 != ListHead2) {
+ ThreadTmp = CONTAINING_RECORD(ListNext2,
+ OS2_THREAD,
+ Link );
+ if (ThreadTmp->Flags & OS2_THREAD_THREAD1) {
+ Thread1 = ThreadTmp;
+ break;
+ }
+ else
+ ListNext2 = ListNext2->Flink;
+ }
+ Os2RemoveThread( Process, t );
+ Os2NotifyWait( WaitThread, t, NULL );
+
+ if (t->Flags & OS2_THREAD_ATTACHED) {
+
+ //
+ // Don't actually terminate an attached
+ // thread, only detach it from the os/2ss
+ //
+
+ CloseHandle(t->ThreadHandle);
+
+ } else if (a->ExitAction == EXIT_THREAD) {
+
+ //
+ // We are terminating a single thread as result of DosExit
+ // with EXIT_THREAD semantics, The thread will kill itself,
+ // all we need to do is close the handle.
+ //
+ CloseHandle(t->ThreadHandle);
+
+ } else {
+ //
+ // We are killing a thread that did not call DosExit and
+ // is not thread 1
+ //
+
+ Os2TermCmd.Param1 = 0;
+ Os2TermCmd.op = Os2TerminateThread;
+ Os2TermCmd.Handle = t->ThreadHandle;
+ if (!WriteFile(
+ Os2hWritePipe,
+ (VOID *)&Os2TermCmd,
+ sizeof(Os2TermCmd),
+ &nNumberOfBytesWritten,
+ NULL)){
+ //
+ // The Pipe of Os2TerminationThread is full
+ //
+ ASSERT(FALSE);
+#if DBG
+ KdPrint(("OS2SRV: Os2InternalTerminateThread: can't post thread termination command, status %d, ignore\n",
+ GetLastError()));
+#endif
+ }
+ }
+
+ Os2DeallocateThread( t );
+
+ if (Process->ThreadList.Flink == Process->ThreadList.Blink && // only thread 1 is left and
+ Thread1->Dying == TRUE) { // it has already called this
+ // routine.
+ //
+ // dispatch exitlist processing
+ //
+
+ Os2NotifyWaitBlock(Thread1->WaitBlock,0,NULL,NULL);
+ }
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Leaving Os2InternalTerminateThread\n"));
+ }
+#endif
+ return (FALSE);
+ }
+}
+
+VOID
+Os2ExceptionTerminateProcess(
+ POS2_THREAD Thread,
+ PDBGKM_APIMSG ReceiveMsg
+ )
+{
+ // The TC_TRAP value which is put in the process
+ // ResultCodes structure prevents from further setting
+ // this structure and is returned to the parent process.
+
+ Thread->Process->ResultCodes.ExitReason = TC_TRAP;
+ switch (ReceiveMsg->u.Exception.ExceptionRecord.ExceptionCode) {
+ case STATUS_ACCESS_VIOLATION:
+ Thread->Process->ResultCodes.ExitResult = 13;
+ break;
+
+ case STATUS_ILLEGAL_FLOAT_CONTEXT:
+ Thread->Process->ResultCodes.ExitResult = 7;
+ break;
+
+ default:
+ Thread->Process->ResultCodes.ExitResult = 0;
+ }
+
+ if ((Thread->Flags & OS2_THREAD_THREAD1) &&
+ (Thread->Process->ExitStatus & OS2_EXIT_IN_PROGRESS)){
+ //
+ // An Exception happened while processing exit list - terminate the process
+ //
+#if DBG
+ DbgPrint("OS2SRV: GP occurred while executing exitlist routine\n");
+#endif
+ Os2ForceClientCleanup(Thread);
+ }
+ else {
+ Os2SigKillProcess(Thread->Process);
+ }
+}
+
+VOID
+Os2AccessGPPopupThread(
+ IN PVOID Parameter
+ )
+{
+ POS2_THREAD Thread;
+ PDBGKM_APIMSG ReceiveMsg = (PDBGKM_APIMSG)Parameter;
+ CONTEXT Context;
+ NTSTATUS Status;
+ UCHAR ApplName[OS2_PROCESS_MAX_APPL_NAME];
+
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Os2AccessGPPopupThread\n"));
+ }
+#endif
+
+ __try {
+
+ Os2AcquireStructureLock();
+ Thread = Os2LocateThreadByClientId( NULL /*Process*/, &ReceiveMsg->h.ClientId );
+
+ if (Thread == NULL){
+ //
+ // Another event caused this thread to be removed before we got the lock
+ //
+#if DBG
+ DbgPrint("OS2SRV: AccessGPPopupThread: thread terminated, cancel popup\n");
+#endif
+ Os2ReleaseStructureLock();
+ __leave;
+ }
+
+ //
+ // Get the context record for the target thread.
+ //
+ Context.ContextFlags = CONTEXT_FULL;
+ Status = NtGetContextThread(Thread->ThreadHandle, &Context);
+
+ if (NT_SUCCESS(Status)) {
+
+#if DBG
+ DbgPrint("OS2SRV: GP occurred at CS=%x, IP=%x\n", Context.SegCs, Context.Eip & 0xffff);
+#endif
+ RtlCopyMemory(ApplName, Thread->Process->ApplName, OS2_PROCESS_MAX_APPL_NAME);
+#if PMNT
+ Os2ReleaseStructureLock();
+#endif // PMNT
+ Os2AccessGPPopup(
+ Context.SegCs,
+ Context.Eip & 0xffff,
+ Context.Eax & 0xffff,
+ Context.Ebx & 0xffff,
+ Context.Ecx & 0xffff,
+ Context.Edx & 0xffff,
+ Context.Esi & 0xffff,
+ Context.Edi & 0xffff,
+ Context.Ebp & 0xffff,
+ Context.Esp & 0xffff,
+ Context.SegSs & 0xffff,
+ Context.SegDs & 0xffff,
+ Context.SegEs & 0xffff,
+ ApplName
+ );
+
+#if PMNT
+ Os2AcquireStructureLock();
+ Thread = Os2LocateThreadByClientId( NULL /*Process*/, &ReceiveMsg->h.ClientId );
+
+ if (Thread == NULL){
+ //
+ // Another event caused this thread to be removed before we got the lock
+ //
+#if DBG
+ DbgPrint("OS2SRV: AccessGPPopupThread: thread terminated already\n");
+#endif
+ Os2ReleaseStructureLock();
+ __leave;
+ }
+#endif // PMNT
+ }
+ else {
+#if DBG
+ DbgPrint("OS2SRV: GP occurred at 16bit. Fail to get context, Status=0x%X", Status);
+#endif
+ ASSERT(FALSE);
+ }
+
+ Os2ExceptionTerminateProcess(Thread, ReceiveMsg);
+ Os2ReleaseStructureLock();
+ }
+ __finally {
+ RtlFreeHeap(Os2Heap, 0, ReceiveMsg);
+ ExitThread(0);
+ }
+}
+
+VOID
+Os2HandleException(
+ IN POS2_PROCESS Process,
+ IN PDBGKM_APIMSG ReceiveMsg
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an exception occurs and there is no stack
+ frame to handle it. It terminates the thread and the process.
+
+Arguments:
+
+ Process - process in which exception occurred
+
+ ReceiveMsg - exception message passed by debugger
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ CONTEXT Context;
+ NTSTATUS Status;
+ POS2_THREAD Thread;
+
+ Thread = Os2LocateThreadByClientId( Process, &(ReceiveMsg->h.ClientId) );
+
+ if (Thread == NULL) {
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("Os2srv: Os2HandleException Null Thread handle\n"));
+ }
+#endif
+ ReceiveMsg->ReturnedStatus = DBG_CONTINUE;
+ NtReplyPort(Os2DebugPort, (PPORT_MESSAGE) ReceiveMsg);
+ return;
+ }
+
+ //
+ // Get the context record for the target thread.
+ //
+ Context.ContextFlags = CONTEXT_FULL;
+ Status = NtGetContextThread(Thread->ThreadHandle, &Context);
+
+#if DBG
+ KdPrint(("Os2srv: Exception %x at cs:ip = %x:%x , program terminated\n",
+ ReceiveMsg->u.Exception.ExceptionRecord.ExceptionCode,
+ Context.SegCs,
+ Context.Eip));
+#endif
+
+ if ( Context.SegCs != 0x1B) {
+ if (Thread->Process->ErrorAction & OS2_ENABLE_ACCESS_VIO_POPUP) {
+ //
+ // Create a separate thread to do the popup and kill the process
+ //
+ ULONG Tid;
+ PDBGKM_APIMSG ReceiveMsg1;
+
+ ReceiveMsg1 = RtlAllocateHeap(Os2Heap, 0, sizeof(DBGKM_APIMSG));
+
+ if (ReceiveMsg1) {
+ HANDLE GPThreadHandle;
+
+ RtlCopyMemory(ReceiveMsg1, ReceiveMsg, sizeof(DBGKM_APIMSG));
+
+ GPThreadHandle = CreateThread( NULL,
+ 0,
+ (PFNTHREAD)Os2AccessGPPopupThread,
+ ReceiveMsg1,
+ 0,
+ &Tid);
+ if (GPThreadHandle){
+ //
+ // Success, the thread will do the popup
+ //
+ NtClose(GPThreadHandle);
+ //
+ // Suspend the falted process and let debugger go
+ //
+ Os2SuspendProcess(Thread->Process);
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_HANDLED;
+ NtReplyPort(Os2DebugPort, (PPORT_MESSAGE) ReceiveMsg);
+ return;
+ }
+ else {
+ RtlFreeHeap(Os2Heap, 0, ReceiveMsg1);
+#if DBG
+ KdPrint(("Os2HandleException - fail at win32 CreateThread, %d\n",GetLastError()));
+#endif
+ }
+ }
+ else {
+#if DBG
+ KdPrint(("Os2HandleException - fail at RtlAllocateHeap\n"));
+#endif
+ }
+ // fall thru, handle the exception with no popup
+ }
+ }
+
+#if DBG
+ DbgPrint("OS2SRV: GP occurred at CS=%x, IP=%x\n", Context.SegCs, Context.Eip & 0xffff);
+#endif
+
+ Os2ExceptionTerminateProcess(Thread, ReceiveMsg);
+
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_HANDLED;
+ NtReplyPort(Os2DebugPort, (PPORT_MESSAGE) ReceiveMsg);
+}
+
+#if DBG
+// DbgPrint already defined
+#else
+// DbgPrint is used in free build to handle DbgPrint exception
+#undef DbgPrint
+ULONG
+DbgPrint(
+ PCH Format,
+ ...
+ );
+#endif
+
+VOID
+Os2HandleDebugEvent(
+ IN POS2_PROCESS Process,
+ IN PDBGKM_APIMSG ReceiveMsg
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an debug event occurs.
+
+Arguments:
+
+ Process - process in which exception occurred
+
+ ReceiveMsg - exception message passed by debugger
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ OS2_API_MSG m;
+ POS2_TERMINATETHREAD_MSG a = &m.u.TerminateThread;
+ POS2_THREAD Thread;
+ CONTEXT Context;
+ NTSTATUS Status, ExceptionCode;
+ POS2_SES_GROUP_PARMS SesGrp;
+ ULONG FlatCliAddress;
+ UCHAR ucInst;
+
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("OS2SRV: Received message on debug port - %s \n",
+ DbgpKmApiName[ReceiveMsg->ApiNumber]));
+ KdPrint(("OS2SRV: Os2DebugUserClientId.UniqueProcess = %x\n",
+ Os2DebugUserClientId.UniqueProcess));
+ KdPrint(("OS2SRV: ClientId.UniqueProcess = %x\n",
+ ReceiveMsg->h.ClientId.UniqueProcess));
+ KdPrint(("OS2SRV: ClientId.UniqueThread = %x\n",
+ ReceiveMsg->h.ClientId.UniqueThread));
+ KdPrint(("OS2SRV: HandleDebugEvent: ExceptionCode = %x\n",
+ ReceiveMsg->u.Exception.ExceptionRecord.ExceptionCode));
+
+ }
+#endif
+
+ if (ReceiveMsg->ApiNumber == DbgKmExceptionApi) {
+ ExceptionCode = ReceiveMsg->u.Exception.ExceptionRecord.ExceptionCode;
+
+ if (ExceptionCode == DBG_PRINTEXCEPTION_C) {
+ PEXCEPTION_RECORD pExceptionRecord = &(ReceiveMsg->u.Exception.ExceptionRecord);
+
+ if (pExceptionRecord->NumberParameters == 2) {
+
+#define DBG_PRINTEXCEPTION_BUFFER_LEN 512
+ UCHAR buffer[DBG_PRINTEXCEPTION_BUFFER_LEN];
+ LONG length = pExceptionRecord->ExceptionInformation[0] > DBG_PRINTEXCEPTION_BUFFER_LEN ?
+ DBG_PRINTEXCEPTION_BUFFER_LEN :
+ pExceptionRecord->ExceptionInformation[0];
+
+ Process = Os2LocateProcessByClientId(&(ReceiveMsg->h.ClientId));
+
+ if (Process) {
+ Status = NtReadVirtualMemory(
+ Process->ProcessHandle,
+ (PVOID) pExceptionRecord->ExceptionInformation[1],
+ buffer,
+ length,
+ &length);
+
+ if (NT_SUCCESS(Status) && length > 1) {
+ buffer[length - 1] = '\0';
+ DbgPrint(buffer);
+ }
+ }
+ else {
+ //
+ // Process already died. Ignore this DbgPrint
+ //
+ DbgPrint("OS2SRV: DbgPrint called during process termination\n");
+ }
+#if DBG
+// DbgPrint remain defined
+#else
+#undef DbgPrint
+#define DbgPrint(_x_) Or2DbgPrintFunctionNeverExisted(_x_)
+#endif
+ }
+
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_HANDLED;
+ NtReplyPort(Os2DebugPort, (PPORT_MESSAGE) ReceiveMsg);
+ return;
+ }
+
+ Thread = Os2LocateThreadByClientId(Process,
+ &(ReceiveMsg->h.ClientId));
+
+ if (Thread == NULL) {
+ //
+ // Look for A Ctrl C message was sent from the console
+ //
+ if (ExceptionCode == DBG_CONTROL_C ||
+ ExceptionCode == DBG_CONTROL_BREAK ) {
+ OS2SESREQUESTMSG CtrlMsg;
+ POS2_PROCESS CtrlProcess;
+ CtrlProcess = Os2LocateProcessByClientId(&(ReceiveMsg->h.ClientId));
+
+ //
+ // We got CtrlC/CtrlBrk BUGBUG - don't send it when in RAW mode
+ //
+ if (CtrlProcess != NULL){
+ if (CtrlProcess->Session != NULL &&
+ !CtrlProcess->Session->InTermination &&
+ !Os2CLI) {
+
+ CtrlMsg.Session = CtrlProcess->Session;
+ SesGrp = (POS2_SES_GROUP_PARMS)CtrlProcess->Session->SesGrpAddress;
+ if ((SesGrp->hConsolePopUp == NULL ) && // PopUp - ignore
+ !SesGrp->WinProcessNumberInSession && // Win child - ignore
+ (((ExceptionCode == DBG_CONTROL_C) &&
+ !(SesGrp->ModeFlag & 1 )) || // ^C in binary (RAW) mode - ignore
+#if PMNT
+ // Don't propagate CTRL-BREAK in case of a PM process !
+ ((ExceptionCode == DBG_CONTROL_BREAK) &&
+ !Os2srvProcessIsPMProcess(CtrlProcess))))
+#else
+ (ExceptionCode == DBG_CONTROL_BREAK)))
+#endif
+ {
+ if (ExceptionCode == DBG_CONTROL_C){
+#if DBG
+ IF_OS2_DEBUG(SIG) {
+ KdPrint(("Ctrl C Received, Process Id %d\n", CtrlProcess->ProcessId));
+ }
+#endif
+ CtrlMsg.d.Signal.Type = XCPT_SIGNAL_INTR;
+ }
+ else {
+#if DBG
+ IF_OS2_DEBUG(SIG) {
+ KdPrint(("Ctrl Break Received, Process Id %d\n", CtrlProcess->ProcessId));
+ }
+#endif
+ CtrlMsg.d.Signal.Type = XCPT_SIGNAL_BREAK;
+ }
+ Status = Os2CtrlSignalHandler(&CtrlMsg, CtrlProcess);
+ }
+ }
+ }
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_HANDLED;
+ NtReplyPort(Os2DebugPort,
+ (PPORT_MESSAGE) ReceiveMsg);
+ return;
+ }
+ else {
+ if (Os2DebugUserClientId.UniqueProcess != NULL &&
+ (ExceptionCode == STATUS_BREAKPOINT || ExceptionCode == STATUS_SINGLE_STEP)
+ ){
+ //
+ // BreakPoint in one of the service threads of
+ // OS2.exe, under ntsd
+ //
+ DbgSsHandleKmApiMsg(ReceiveMsg, NULL);
+ return;
+ }
+#if DBG
+ KdPrint(("OS2SRV: Exception Happened within app termination in win32\n"));
+#endif
+ if (!ReceiveMsg->u.Exception.FirstChance) {
+ //
+ // Second Chance message in 32 bit code - break to debugger
+ //
+ if (Os2DebugUserClientId.UniqueProcess != NULL) {
+ DbgSsHandleKmApiMsg(ReceiveMsg, NULL);
+ return;
+ }
+ }
+
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_NOT_HANDLED;
+ NtReplyPort(Os2DebugPort,
+ (PPORT_MESSAGE) ReceiveMsg);
+ return;
+ }
+ }
+
+ //
+ // Get the context record for the target thread.
+ //
+ Context.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
+ Status = NtGetContextThread(Thread->ThreadHandle,
+ &Context);
+ ASSERT(NT_SUCCESS(Status));
+
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("OS2SRV, HandleDebugEvent: ExceptionCode = %x\n",
+ ExceptionCode));
+ KdPrint(("OS2SRV: HandleDebugEvent: Exception occurred at cs:eip = %x:%x\n",
+ Context.SegCs,
+ Context.Eip));
+ }
+#endif
+
+ switch (ExceptionCode) {
+
+ case STATUS_BREAKPOINT:
+ case STATUS_SINGLE_STEP:
+
+ Process = Thread->Process;
+
+ if (Process->Flags & OS2_PROCESS_TRACE &&
+ Process->ProcessMTE &&
+ Context.SegCs != 0x1B) {
+
+ //
+ // The process is being traced by an OS/2 debugger,
+ // it is completed loading, and it is in 16 bit code -
+ // need to wake the 16bit debugger, waiting on DosPtrace
+ //
+ if (!Os2NotifyWait( WaitThread, Thread, (PVOID)ExceptionCode)) {
+ if (!Os2NotifyWait( WaitProcess, Thread, (PVOID)ExceptionCode)) {
+#if DBG
+ KdPrint(("OS2SRV, HandleDebugEvent: debuggee signaled %lx, fail to notify debugger\n",
+ ExceptionCode));
+#endif
+ }
+ }
+
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_HANDLED;
+ NtReplyPort(Os2DebugPort,
+ (PPORT_MESSAGE) ReceiveMsg);
+ return;
+ }
+
+ //
+ // if running under the ntsd debugger, break in, else
+ // GP popup
+ //
+ if (Os2DebugUserClientId.UniqueProcess != NULL){
+#if DBG
+ IF_OS2_DEBUG(MISC) {
+ KdPrint(("OS2SRV: Received breakpoint at cs:eip = %x:%x, ignored\n",
+ Context.SegCs,
+ Context.Eip));
+ }
+#endif
+ break;
+ }
+ else {
+ Os2HandleException(Process,ReceiveMsg);
+ return;
+ }
+
+ case STATUS_ILLEGAL_FLOAT_CONTEXT:
+ if (Os2DispatchVector(ReceiveMsg, Thread, Context)) {
+#if DBG
+ KdPrint(("OS2SRV: Floating point instruction executed with no floating point emulator installed*\n"));
+#endif
+ Os2HandleException(Process,ReceiveMsg);
+ return;
+ }
+ else {
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_HANDLED;
+ NtReplyPort(Os2DebugPort,
+ (PPORT_MESSAGE) ReceiveMsg);
+ return;
+ }
+ case STATUS_INTEGER_DIVIDE_BY_ZERO:
+ case STATUS_INTEGER_OVERFLOW:
+ case STATUS_ARRAY_BOUNDS_EXCEEDED:
+ case STATUS_ILLEGAL_INSTRUCTION:
+ case STATUS_FLOAT_DENORMAL_OPERAND:
+ case STATUS_FLOAT_DIVIDE_BY_ZERO:
+ case STATUS_FLOAT_INEXACT_RESULT:
+ case STATUS_FLOAT_INVALID_OPERATION:
+ case STATUS_FLOAT_OVERFLOW:
+ case STATUS_FLOAT_STACK_CHECK:
+ case STATUS_FLOAT_UNDERFLOW:
+ if (Os2DispatchVector(ReceiveMsg, Thread, Context)) {
+ Os2HandleException(Process,ReceiveMsg);
+ return;
+ }
+ else {
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_HANDLED;
+ NtReplyPort(Os2DebugPort,
+ (PPORT_MESSAGE) ReceiveMsg);
+ return;
+ }
+ case STATUS_PRIVILEGED_INSTRUCTION:
+ //
+ // Check to see if client or server raised the exception
+ // if so return as not handled so the stack based handler
+ // will handle it.
+ //
+ if (Context.SegCs == 0x1b) {
+#if DBG
+ IF_OS2_DEBUG( EXCEPTIONS ) {
+ KdPrint(( "Os2HandleDebugEvent - STATUS_PRIVELEGED_INSTRUCTION at 32 bit code %X:%X, let stack based handler deal with it\n",
+ Context.SegCs,Context.Eip));
+ }
+#endif
+ if (!ReceiveMsg->u.Exception.FirstChance) {
+ //
+ // Second Chance message in 32 bit code - break to debugger
+ //
+ if (Os2DebugUserClientId.UniqueProcess != NULL) {
+ DbgSsHandleKmApiMsg(ReceiveMsg, NULL);
+ return;
+ }
+ }
+
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_NOT_HANDLED;
+ NtReplyPort(Os2DebugPort,
+ (PPORT_MESSAGE) ReceiveMsg);
+ return;
+ }
+
+ FlatCliAddress = (ULONG)(SELTOFLAT((USHORT)Context.SegCs)) | (ULONG)(Context.Eip);
+ Status = NtReadVirtualMemory( Thread->Process->ProcessHandle,
+ (PVOID) FlatCliAddress,
+ (PVOID) &(ucInst),
+ 1,
+ NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ KdPrint(( "Os2HandleDebugEvent - Read Instruction, failed to read %x:%x Status %lx\n", Context.SegCs,Context.Eip, Status));
+#endif
+ }
+
+ if (ucInst == 0xFA) {
+
+ POS2_PROCESS TmpProcess = NULL;
+ PLIST_ENTRY ListHead, ListNext;
+#if DBG
+ KdPrint(( "Os2HandleDebugEvent - CLI instruction got STATUS_PRIVILEGED_INSTRUCTION\n"));
+#endif
+ //
+ // for a CLI we freeze all os/2 threads
+ //
+
+ if (!Os2CLI){
+
+ Os2CLI = TRUE;
+ Os2CLIThread = Thread;
+ for (
+ ListHead = &Os2RootProcess->ListLink,
+ ListNext = ListHead->Flink;
+ ListNext != ListHead ;
+ ListNext = ListNext->Flink
+ ) {
+ TmpProcess = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
+ if ( TmpProcess != Thread->Process ) {
+ Os2SuspendProcess(TmpProcess);
+ }
+ else {
+ //
+ // for the calling process, freeze other threads
+ //
+ POS2_THREAD TmpThread = NULL;
+ PLIST_ENTRY ThreadListHead, ThreadListNext;
+ ThreadListHead = &TmpProcess->ThreadList;
+ ThreadListNext = ThreadListHead->Flink;
+ while (ThreadListNext != ThreadListHead) {
+ TmpThread = CONTAINING_RECORD( ThreadListNext, OS2_THREAD, Link );
+ ThreadListNext = ThreadListNext->Flink;
+ if (TmpThread != Thread) {
+ NtSuspendThread(TmpThread->ThreadHandle, NULL);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // A second CLI can come before all threads are suspended
+ // we let the latter, if not from the same thread,
+ // to get the exception next time, by not incrementing
+ // his eip
+ //
+ if (Os2CLIThread == Thread){
+ Context.Eip += 1;
+ Status = NtSetContextThread(Thread->ThreadHandle, &Context);
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ KdPrint(( "Os2HandleDebugEvent - Read Instruction, failed to write %x:%x Status %lx\n", Context.SegCs,Context.Eip, Status));
+#endif
+ }
+ }
+ else {
+#if DBG
+ KdPrint(( "Os2HandleDebugEvent - Second CLI from another thread\n"));
+#endif
+ }
+ //
+ // let the kernel continue
+ //
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_HANDLED;
+ NtReplyPort(Os2DebugPort,
+ (PPORT_MESSAGE) ReceiveMsg);
+ return;
+ }
+#if PMNT
+ else if (ucInst == 0xE4 || ucInst == 0xE5 || ucInst == 0xEC || ucInst == 0xED) {
+
+#if DBG
+ KdPrint(( "Os2HandleDebugEvent - IN instruction got STATUS_PRIVILEGED_INSTRUCTION\n"));
+#endif
+ //
+ // See if PM can handle by mapping ports
+ //
+ if (Os2srvProcessIsPMProcess(Thread->Process) &&
+ PMHandledInOut(Thread))
+ {
+
+ //
+ // let the kernel continue
+ //
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_HANDLED;
+ NtReplyPort(Os2DebugPort,
+ (PPORT_MESSAGE) ReceiveMsg);
+ }
+ else {
+ Os2HandleException(Process,ReceiveMsg);
+ }
+ }
+ else if (ucInst == 0xE6 || ucInst == 0xE7 || ucInst == 0xEE || ucInst == 0xEF) {
+
+#if DBG
+ KdPrint(( "Os2HandleDebugEvent - OUT instruction got STATUS_PRIVILEGED_INSTRUCTION\n"));
+#endif
+ //
+ // See if PM can handle by mapping ports
+ //
+ if (Os2srvProcessIsPMProcess(Thread->Process) &&
+ PMHandledInOut(Thread))
+ {
+
+ //
+ // let the kernel continue
+ //
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_HANDLED;
+ NtReplyPort(Os2DebugPort,
+ (PPORT_MESSAGE) ReceiveMsg);
+ }
+ else {
+ Os2HandleException(Process,ReceiveMsg);
+ }
+ }
+#endif // PMNT
+ else {
+ Os2HandleException(Process,ReceiveMsg);
+ }
+ return;
+ break;
+
+ case STATUS_ACCESS_VIOLATION:
+
+ //
+ // Check to see if client or server raised the exception
+ // if so return as not handled so the stack based handler
+ // will handle it.
+ //
+ if (Context.SegCs == 0x1b) {
+#if DBG
+ IF_OS2_DEBUG( EXCEPTIONS ) {
+ KdPrint(( "Os2HandleDebugEvent - STATUS_ACCESS_VIOLATION at 32 bit code %X:%X, let stack based handler deal with it\n",
+ Context.SegCs,Context.Eip));
+ }
+#endif
+ if (!ReceiveMsg->u.Exception.FirstChance) {
+ //
+ // Second Chance message in 32 bit code - break to debugger
+ //
+ if (Os2DebugUserClientId.UniqueProcess != NULL) {
+ DbgSsHandleKmApiMsg(ReceiveMsg, NULL);
+ return;
+ }
+ }
+
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_NOT_HANDLED;
+ NtReplyPort(Os2DebugPort,
+ (PPORT_MESSAGE) ReceiveMsg);
+ return;
+ }
+
+ FlatCliAddress = (ULONG)(SELTOFLAT((USHORT)Context.SegCs)) | (ULONG)(Context.Eip);
+ Status = NtReadVirtualMemory( Thread->Process->ProcessHandle,
+ (PVOID) FlatCliAddress,
+ (PVOID) &(ucInst),
+ 1,
+ NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ KdPrint(( "Os2HandleDebugEvent - Read Instruction, failed to read %x:%x Status %lx\n", Context.SegCs,Context.Eip, Status));
+#endif
+ }
+
+ if (ucInst == 0xFB) {
+
+ POS2_PROCESS TmpProcess = NULL;
+ PLIST_ENTRY ListHead, ListNext;
+
+#if DBG
+ KdPrint(( "Os2HandleDebugEvent - STI instruction got STATUS_ACCESS_VIOLATION\n"));
+#endif
+ //
+ // for STI we resume all os/2 threads
+ //
+
+ if (Os2CLI){
+ //
+ // Need to resume all threads, otherwise STI is mute
+ //
+ Os2CLI = FALSE;
+ for (
+ ListHead = &Os2RootProcess->ListLink,
+ ListNext = ListHead->Flink;
+ ListNext != ListHead ;
+ ListNext = ListNext->Flink
+ ) {
+ TmpProcess = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
+ if ( TmpProcess != Thread->Process ) {
+ Os2ResumeProcess(TmpProcess);
+ }
+ else {
+ //
+ // for the calling process, freeze other threads
+ //
+ POS2_THREAD TmpThread = NULL;
+ PLIST_ENTRY ThreadListHead, ThreadListNext;
+ ThreadListHead = &TmpProcess->ThreadList;
+ ThreadListNext = ThreadListHead->Flink;
+ while (ThreadListNext != ThreadListHead) {
+ TmpThread = CONTAINING_RECORD( ThreadListNext, OS2_THREAD, Link );
+ ThreadListNext = ThreadListNext->Flink;
+ if (TmpThread != Thread) {
+ NtResumeThread(TmpThread->ThreadHandle, NULL);
+ }
+ }
+ }
+ }
+ }
+
+ Context.Eip += 1;
+ Status = NtSetContextThread(Thread->ThreadHandle, &Context);
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ KdPrint(( "Os2HandleDebugEvent - Read Instruction, failed to write %x:%x Status %lx\n", Context.SegCs,Context.Eip, Status));
+#endif
+ }
+ //
+ // let the kernel continue
+ //
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_HANDLED;
+ NtReplyPort(Os2DebugPort,
+ (PPORT_MESSAGE) ReceiveMsg);
+ return;
+ }
+ else {
+ Os2HandleException(Process,ReceiveMsg);
+ }
+ return;
+ break;
+ default:
+
+ //
+ // Check to see if client or server raised the exception
+ // if so return as not handled so the stack based handler
+ // will handle it.
+ //
+ if (Context.SegCs == 0x1b) {
+#if DBG
+ IF_OS2_DEBUG( EXCEPTIONS ) {
+ KdPrint(( "Os2HandleDebugEvent - Exception %X at 32 bit code %X:%X, let stack based handler deal with it\n",
+ ReceiveMsg->u.Exception.ExceptionRecord.ExceptionCode,
+ Context.SegCs,Context.Eip));
+ }
+#endif
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_NOT_HANDLED;
+ NtReplyPort(Os2DebugPort,
+ (PPORT_MESSAGE) ReceiveMsg);
+ return;
+ }
+ Os2HandleException(Process,ReceiveMsg);
+ return;
+ }
+ }
+
+ if (ReceiveMsg->ApiNumber == DbgKmExitProcessApi) {
+
+ POS2_PROCESS CtrlProcess;
+ CLIENT_ID CtrlProcessCid = ReceiveMsg->h.ClientId;
+
+ if (ReceiveMsg->h.ClientId.UniqueProcess == FirstOs2ProcessClientId.UniqueProcess) {
+ //
+ // The os2 client that started os2srv is gone,
+ // the logoff/shutdown logic of os2srv needs to know
+ // it,mark it.
+ //
+ FirstOs2ProcessHandle = (HANDLE)-1;
+ }
+
+ //
+ // Let the kernel go so other os2srv threads are not blocked
+ // on this process.
+ if (Os2DebugUserClientId.UniqueProcess != NULL){
+ DbgSsHandleKmApiMsg(ReceiveMsg, NULL);
+ }
+ else {
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_HANDLED;
+ NtReplyPort(Os2DebugPort,
+ (PPORT_MESSAGE) ReceiveMsg);
+ }
+ //
+ // now acquire the lock so we can handle os2srv structures
+ //
+ Os2AcquireStructureLock();
+ //
+ // No living threads - just cleanup after the process if it still exists
+ // in our structures
+ //
+ CtrlProcess = Os2LocateProcessByClientId(&CtrlProcessCid);
+ if (CtrlProcess != NULL){
+ //
+ // Like Os2DosExit, but no xtlremotecall
+ //
+ OS2_API_MSG m;
+ POS2_TERMINATEPROCESS_MSG a = &m.u.TerminateProcess;
+ POS2_THREAD Thread, Thread1;
+ PLIST_ENTRY ListHead, ListNext;
+ PORT_MSG_DATA_LENGTH(m) = sizeof(m) - sizeof(PORT_MESSAGE);
+ PORT_MSG_TOTAL_LENGTH(m) = sizeof(m);
+ PORT_MSG_ZERO_INIT(m) = 0L;
+
+#if DBG
+ IF_OS2_DEBUG( EXCEPTIONS ) {
+ KdPrint(( "Os2HandleDebugEvent - Process Terminated message, but Process structure still exists" ));
+ KdPrint(( "\tProcess %X. Application will be terminated\n", CtrlProcess));
+ }
+#endif
+ a->ExitReason = TC_EXIT;
+ a->ExitResult = ERROR_INTERRUPT;
+ ((POS2_DOSEXIT_MSG)a)->ExitAction = EXIT_PROCESS;
+
+ ListHead = &CtrlProcess->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
+ ListNext = ListNext->Flink;
+ if (Thread->Dying || (Thread->Flags & OS2_THREAD_THREAD1)) {
+ Thread1 = Thread;
+ continue;
+ }
+ Os2InternalTerminateThread(Thread, &m);
+ }
+ Os2InternalTerminateProcess(Thread1, &m);
+ }
+ Os2ReleaseStructureLock();
+ return;
+ }
+
+ if (Os2DebugUserClientId.UniqueProcess != NULL){
+ DbgSsHandleKmApiMsg(ReceiveMsg, NULL);
+ }
+ else {
+ ReceiveMsg->ReturnedStatus = DBG_EXCEPTION_HANDLED;
+ NtReplyPort(Os2DebugPort,
+ (PPORT_MESSAGE) ReceiveMsg);
+ }
+ return;
+}
+
+
+BOOLEAN
+Os2DosKillProcess(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the DosKillProcess API.
+
+Arguments:
+
+ t - calling thread
+
+ m - message
+
+Return Value:
+
+ TRUE - create a return message
+
+--*/
+
+{
+ POS2_DOSKILLPROCESS_MSG a = &m->u.DosKillProcess;
+ POS2_PROCESS Process;
+ BOOLEAN NoHandler = TRUE;
+
+
+ //
+ // for (each process to be killed)
+ // look up thread 1
+ // if (dying)
+ // ERROR_INVALID_PROC_ID
+ // issues SIGTERM
+ //
+
+ Process = Os2LocateProcessByProcessId( m,
+ t->Process,
+ (PID)a->ProcessId,
+ (BOOLEAN)FALSE
+ );
+
+ if (Process != NULL) {
+ POS2_SESSION Session = Process->Session;
+ POS2_REGISTER_HANDLER_REC pRec;
+
+ if ((pRec = Session->RegisterCtrlHandler) != NULL) {
+ while (pRec != NULL) {
+ if (pRec->Signal == (ULONG)XCPT_SIGNAL_KILLPROC &&
+ pRec->fAction != SIGA_IGNORE ) {
+ //
+ // See if a the registered handler
+ // is child of Process
+ //
+ POS2_PROCESS p = pRec->Process;
+ while (p != Process && p != Os2RootProcess){
+ p = p->Parent;
+ }
+ if (p == Process){
+ NoHandler = FALSE;
+ }
+ break;
+ }
+ pRec = pRec->Link;
+ }
+ }
+ if (a->KillTarget == DKP_PROCESS) {
+ if (NoHandler || (pRec->Process != Process)){
+ Os2SigKillProcess(Process);
+ m->ReturnedErrorValue = NO_ERROR;
+ }
+ else {
+ m->ReturnedErrorValue = Os2IssueSignal(Process, XCPT_SIGNAL_KILLPROC);
+ }
+ }
+ else {
+ if (NoHandler){
+ Os2SigKillProcessTree(Process, TRUE);
+ }
+ else
+ Os2IssueSignalTree(Process, XCPT_SIGNAL_KILLPROC);
+ m->ReturnedErrorValue = NO_ERROR;
+ }
+ }
+ return (TRUE);
+}
+
+
+VOID
+Os2FillErrorTextBuffer(
+ IN OUT PSTRING ErrorText,
+ IN PSTRING Contents,
+ IN ULONG ContentsIndex
+ )
+{
+ ULONG n;
+
+ if (ErrorText->MaximumLength != 0) {
+ n = Contents->Length - ContentsIndex;
+ if (n > (ULONG)ErrorText->MaximumLength) {
+ n = ErrorText->MaximumLength;
+ }
+
+ ErrorText->Length = (USHORT)n;
+ RtlMoveMemory( ErrorText->Buffer,
+ Contents->Buffer + ContentsIndex,
+ n);
+ }
+}
+
+
+VOID
+Os2FillErrorTextBufferFile(
+ IN OUT PSTRING ErrorText,
+ IN PUCHAR Contents
+ )
+{
+ ULONG n;
+
+ n = strlen(Contents);
+ if (n != 0) {
+ if (n > (ULONG)ErrorText->MaximumLength) {
+ n = ErrorText->MaximumLength;
+ }
+
+ ErrorText->Length = (USHORT)n;
+ RtlMoveMemory( ErrorText->Buffer,
+ Contents,
+ n);
+ }
+}
+
+
+APIRET
+Os2CreateProcess(
+ IN PVOID RequestMsg OPTIONAL,
+ IN POS2_THREAD t OPTIONAL,
+ POS2_DOSEXECPGM_MSG a,
+ POS2_SESSION Session OPTIONAL,
+ POS2_THREAD *NewThread
+ )
+{
+ // New Child Child Dos Dos
+ // Session Session Process ExecPgm StartSession
+ // _______ _______ _______ _______ ____________
+ // RequestMsg + + +
+ // t + +
+ // a + + + + +
+ // Session + + +
+ // *NewThread NULL + + NULL NULL
+ //
+ // if RequestMsg -> new/child session/process (from ConCreat.c)
+ // if t -> ExecPgm/StartSession (from ApiReqst.c)
+ // if !Session -> ExecPgm/child process
+ // if *NewThread -> child process/session
+ //
+ // if Session == NULL and RequestMsg == NULL ->DosExecPgm
+ // else if Session == NULL *NewThread != NULL ->ConCreate that is not a session root
+ // else if Session->ChildSession ->DosStartSession (receive also t parm) ??
+ // else if Session && RequestMsg -> NewSession
+ //
+
+ NTSTATUS Status;
+ POS2_PROCESS ParentProcess, Process = NULL;
+ HANDLE ParentProcessHandle;
+ POS2_THREAD Thread;
+ APIRET RetCode;
+ CONTEXT Context;
+ HANDLE ReplyEvent;
+ ULONG Length;
+ PROCESS_BASIC_INFORMATION BasicInfo;
+
+ // uses stuff from the parent process
+ if ( ARGUMENT_PRESENT(t) ) // && !ARGUMENT_PRESENT(Session) )
+ {
+ ParentProcess = t->Process;
+ ParentProcessHandle = t->Process->ProcessHandle;
+ } else
+ {
+ ParentProcess = NULL;
+ ParentProcessHandle = NULL;
+ }
+
+ if (*NewThread != NULL)
+ {
+ //
+ // This is a child process/session that was already created
+ // by DosExecPgm/DosStartSession
+ //
+ Process = (*NewThread)->Process;
+ } else
+ {
+
+ //
+ // Initialize the Process and Thread strucutures
+ //
+ if (ARGUMENT_PRESENT(RequestMsg))
+ {
+ Process = (POS2_PROCESS)Session->Process;
+ } else
+ {
+ Process = Os2AllocateProcess();
+ }
+ if (Process == NULL)
+ {
+ Os2DereferenceSession(Session, 0, (BOOLEAN)TRUE);
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ switch( a->Flags )
+ {
+ case EXEC_TRACETREE:
+ Process->Flags |= OS2_PROCESS_TRACETREE;
+ // fall through
+
+ case EXEC_TRACE:
+ Process->Flags |= OS2_PROCESS_TRACE;
+ // fall through
+
+ case EXEC_ASYNCRESULT:
+ Process->Flags |= OS2_PROCESS_SAVERESULT;
+ // fall through
+
+ case EXEC_ASYNC:
+ break;
+
+ case EXEC_FROZEN:
+ Process->Flags |= OS2_PROCESS_FROZEN;
+ break;
+
+ case EXEC_BACKGROUND:
+ Process->Flags |= OS2_PROCESS_BACKGROUND;
+ break;
+
+ case EXEC_SYNC:
+ Process->Flags |= OS2_PROCESS_SYNCHRONOUS;
+ break;
+ }
+
+ if ((Thread = Os2AllocateThread(
+#ifdef PMNT
+ DCT_RUNABLE,
+#endif
+ Process )) == NULL)
+ {
+ Os2DeallocateProcess( Process );
+ Os2DereferenceSession(Session, 0, (BOOLEAN)TRUE);
+
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+ }
+
+ if (*NewThread != NULL)
+ {
+ //
+ // case of os2.exe calling after a DosExecPgm was executed
+ // everything was set by Parent DosExecPgm - return to ConCreate
+ //
+ Thread = *NewThread;
+ } else
+ {
+ //
+ // Setup the Process and Thread structures
+ //
+
+ Length = (ULONG)a->ApplNameLength;
+ if (( Length >= 5 ) &&
+ (!strnicmp(&a->ApplName[Length - 5], ".exe", 4)))
+ {
+ Length -= 4; // remove the ".EXE from the appl name
+ }
+ strncpy(Process->ApplName,
+ &a->ApplName[0],
+ Length);
+
+ Process->ApplName[Length - 1] = '\0';
+ strupr(Process->ApplName);
+ Process->ApplNameLength = Length;
+
+ if (ARGUMENT_PRESENT(RequestMsg))
+ {
+ POS2SESREQUESTMSG pReceiveMsg = (POS2SESREQUESTMSG)RequestMsg;
+
+ //
+ // A new session is created
+ //
+ Process->ClientId = Thread->ClientId = pReceiveMsg->h.ClientId;
+ Process->ProcessHandle = pReceiveMsg->d.Create.d.In.hProcess;
+ Thread->ThreadHandle = pReceiveMsg->d.Create.d.In.hThread;
+ Process->Session = Session;
+ } else
+ {
+ //
+ // DosExecPgm or DosStartSession
+ //
+ Thread->ThreadHandle = a->hThread;
+ Thread->ClientId = a->ClientId;
+ Process->ProcessHandle = a->hProcess;
+ Process->ClientId = a->ClientId;
+ if (ARGUMENT_PRESENT(Session))
+ {
+ Process->Session = Session;
+ } else
+ {
+ Process->Session = ParentProcess->Session;
+ Os2ReferenceSession(Process->Session);
+ }
+ }
+
+ Thread->Flags = OS2_THREAD_THREAD1;
+ Thread->Os2Class = PRTYC_REGULAR;
+ Thread->Os2Level = 0;
+
+ if (Process->Flags & OS2_PROCESS_FROZEN ||
+ Process->Flags & OS2_PROCESS_TRACE)
+ {
+ NtSuspendThread( Thread->ThreadHandle, NULL );
+ }
+
+ if ( !ARGUMENT_PRESENT(Session) )
+ {
+ // DosExecPgm
+
+ RetCode = InitializeFileSystemForExec(&(a->FileSystemParameters),
+ ParentProcessHandle,
+ Process->ProcessHandle,
+ ParentProcess,
+ Process,
+ a
+ );
+ } else if (ARGUMENT_PRESENT(t) )
+ {
+ // DosStartSession
+
+ RetCode = InitializeFileSystemForChildSesMgr(
+ &(a->FileSystemParameters),
+ ParentProcessHandle,
+ Process->ProcessHandle,
+ ParentProcess,
+ Process,
+ a
+ );
+ } else
+ {
+ // New Session
+
+ InitializeFileSystemForSesMgr(Process);
+ RetCode = NO_ERROR;
+ }
+
+ if (RetCode)
+ {
+ try
+ {
+ NtTerminateProcess( Process->ProcessHandle,
+ STATUS_INVALID_IMAGE_FORMAT
+ );
+ NtWaitForSingleObject( Process->ProcessHandle, (BOOLEAN)TRUE, NULL );
+ NtClose( Thread->ThreadHandle );
+ NtClose( Process->ProcessHandle );
+
+ Os2DereferenceSession(Session, 0, (BOOLEAN)TRUE);
+ Os2DeallocateThread( Thread );
+ Os2DeallocateProcess( Process );
+
+ Os2FillErrorTextBufferFile( &a->ErrorText,
+ &a->ApplName[0]
+ );
+
+ } except( EXCEPTION_EXECUTE_HANDLER )
+ {
+#if DBG
+ KdPrint(("OS2SRV: Got Error %d from InitializeFileSystemForExec\n",
+ RetCode));
+#endif
+ }
+ return(RetCode);
+ }
+ Os2InsertThread( Process, Thread );
+
+ Os2SetProcessContext( Process,
+ Thread,
+ (BOOLEAN)(( (ARGUMENT_PRESENT(Session)) && !(ARGUMENT_PRESENT(t)) ) ?
+ (BOOLEAN) TRUE :
+ (BOOLEAN) FALSE),
+ Process->HandleTableLength,
+ a->FileSystemParameters.CurrentDrive,
+ ARGUMENT_PRESENT(Session) ? 0L : a->CodePage
+ );
+
+ }
+ //
+ // Attach the process to the os2srv debug port (process created by csr)
+ //
+ if (ARGUMENT_PRESENT(RequestMsg))
+ {
+ PSCREQ_CREATE Create = & ((POS2SESREQUESTMSG)RequestMsg)->d.Create;
+
+ Status = NtCreateEvent(
+ &ReplyEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE
+ );
+ ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) )
+ {
+#if DBG
+ KdPrint(( "Os2CreateProcess failed: NtCreateEvent Status == %X\n",
+ Status
+ ));
+#endif // DBG
+ return(Status);
+ }
+
+ Status = Os2DebugProcess(
+ &(Thread->ClientId),
+ Thread,
+ ReplyEvent);
+ if (!NT_SUCCESS( Status ) )
+ {
+ if (Status != STATUS_UNSUCCESSFUL){
+#if DBG
+ KdPrint(( "Os2CreateProcess, Error at Os2DebugProcess, Status==%X\n", Status));
+#endif
+ }
+ } else if (ARGUMENT_PRESENT(Session))
+ {
+ //
+ // This is a root process of a session, attach os2srv debug port to
+ // the win32 threads of it
+ //
+ Status = Os2DebugThread(
+ Create->d.In.hEventThread,
+ ReplyEvent);
+ if (!NT_SUCCESS( Status ) )
+ {
+#if DBG
+ KdPrint(( "Os2CreateProcess, Error attaching to EventThread, Status==%X\n", Status));
+#endif
+ }
+
+ Status = Os2DebugThread(
+ Create->d.In.hSessionRequestThread,
+ ReplyEvent);
+ if (!NT_SUCCESS( Status ) )
+ {
+#if DBG
+ KdPrint(( "Os2CreateProcess, Error attaching to SessionRequestThread, Status==%X\n", Status));
+#endif
+ }
+ }
+
+ if (ARGUMENT_PRESENT(Session))
+ {
+ NtClose(Create->d.In.hSessionRequestThread);
+ NtClose(Create->d.In.hEventThread);
+ }
+ NtClose(ReplyEvent);
+ }
+
+ if (*NewThread)
+ {
+ //
+ // At this place, DosExecPgm that came before set it all up,
+ // so return
+ return(STATUS_SUCCESS);
+ }
+ Os2InsertProcess( Session ? (POS2_PROCESS)NULL : ParentProcess,
+ Process
+ );
+
+ a->ResultProcessId = Process->ProcessId;
+
+ if (Session)
+ {
+ Session->ProcessId = (ULONG)Process->ProcessId;
+
+ //
+ // Save the process unique id, and the process parent unique
+ // id. We will use it in Os2DereferenceSession, when a win32 process
+ // is about to terminate, and we have to terminate its children.
+ //
+ Status = NtQueryInformationProcess(
+ Process->ProcessHandle,
+ ProcessBasicInformation,
+ &BasicInfo,
+ sizeof(BasicInfo),
+ NULL
+ );
+ ASSERT(NT_SUCCESS(Status));
+ if ( !NT_SUCCESS( Status ) ) {
+#if DBG
+ DbgPrint( "Os2CreateProcess failed: NtQueryProcessInformation Status == %X\n",
+ Status
+ );
+#endif // DBG
+ }
+ else
+ {
+ Session->dwProcessId = BasicInfo.UniqueProcessId;
+ Session->dwParentProcessId = BasicInfo.InheritedFromUniqueProcessId;
+ }
+ }
+
+ if (!(Process->Flags & OS2_PROCESS_SYNCHRONOUS))
+ {
+ a->ResultCodes.ExitReason = (ULONG)a->ResultProcessId;
+ }
+
+ *NewThread = Thread;
+
+ //
+ // Get the context record for the new thread. Save Esp for Exception
+ // Handling
+ //
+ Context.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
+ Status = NtGetContextThread(Thread->ThreadHandle, &Context);
+ //
+ // mask FP exceptions, just in case...
+ //
+ Context.FloatSave.ControlWord |= 0x3f; // mask exceptions
+ Status = NtSetContextThread(Thread->ThreadHandle, &Context);
+ //
+ // Remember Initial Stack, for Cleanup in case of exception (os2handleexception())
+ //
+ Thread->InitialStack = Context.Esp;
+
+ return( NO_ERROR );
+}
+
+
+BOOLEAN
+Os2DosExecPgm(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_THREAD NewThread = NULL;
+ NTSTATUS Status;
+ ULONG CmdLineFlag;
+
+ CmdLineFlag = m->u.DosExecPgm.CmdLineFlag;
+ m->u.DosExecPgm.CmdLineFlag &= (~CMD_SHORTCUT);
+
+ m->ReturnedErrorValue = Os2CreateProcess(
+ NULL,
+ t,
+ &m->u.DosExecPgm,
+ NULL,
+ &NewThread
+ );
+
+ if ( m->ReturnedErrorValue == NO_ERROR ) {
+ if (CmdLineFlag){
+ Os2PrepareCmdSignals(NewThread->Process);
+ }
+ if (NewThread->Process->Flags & OS2_PROCESS_SYNCHRONOUS) {
+ if (Os2CreateWait( WaitProcess,
+ (OS2_WAIT_ROUTINE)Os2WaitChildSatisfy,
+ t,
+ m,
+ NULL,
+ NULL )
+ ) {
+ if (!Os2CLI){
+ Status = NtResumeThread( NewThread->ThreadHandle, NULL );
+ ASSERT(NT_SUCCESS(Status));
+ }
+ return( FALSE );
+ }
+ else {
+ POS2_PROCESS p = NewThread->Process;
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ Os2DeallocateThread( NewThread );
+ Os2DereferenceSession(p->Session, 0, (BOOLEAN)TRUE);
+ Os2DeallocateProcess( p );
+ NtClose(m->u.DosExecPgm.hThread);
+ NtClose(m->u.DosExecPgm.hProcess);
+ return( TRUE );
+ }
+ }
+
+ if (!Os2CLI){
+ Status = NtResumeThread( NewThread->ThreadHandle, NULL );
+ ASSERT(NT_SUCCESS(Status));
+ }
+ return( TRUE );
+ }
+ else {
+ return( TRUE );
+ }
+}
+
+
+BOOLEAN
+Os2DosCreateThread(
+ IN POS2_THREAD argt,
+ IN POS2_API_MSG m
+ )
+{
+ NTSTATUS Status = NO_ERROR;
+ POS2_DOSCREATETHREAD_MSG a = &m->u.DosCreateThread;
+ POS2_THREAD Thread, t;
+ CONTEXT Context;
+ POS2_PROCESS Process;
+
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Entering Os2DosCreateThread\n"));
+ }
+#endif
+
+ Process = Os2LocateProcessByClientId(&(m->h.ClientId));
+ if (Process == NULL) {
+#if DBG
+ KdPrint(( "Os2DosCreateThread, Unknown Thread and Process\n"));
+#endif
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ return( TRUE );
+ }
+ //
+ // Take parameters from Thread1 of the Process
+ //
+ t = CONTAINING_RECORD( Process->ThreadList.Flink, OS2_THREAD, Link );
+
+ if (Thread = Os2AllocateThread(
+#ifdef PMNT
+ a->Flags,
+#endif
+ t->Process )) {
+ Thread->ClientOs2Tib = a->ClientOs2Tib;
+ Thread->Os2Class = t->Os2Class;
+ Thread->Os2Level = t->Os2Level;
+
+ Thread->ThreadHandle = a->ThreadHandle;
+ Thread->ClientId = a->ClientId;
+
+ //
+ // If we're attaching a win32 thread, mark
+ // it with a special flag.
+ //
+
+ if (a->Flags & DCT_ATTACHED) {
+ Thread->Flags |= OS2_THREAD_ATTACHED;
+ }
+
+ }
+ else {
+ Status = STATUS_NO_MEMORY;
+ }
+
+ if (NT_SUCCESS( Status )) {
+ a->ThreadId = Thread->ThreadId;
+
+ Os2SetThreadPriority( Thread, Thread->Os2Class, Thread->Os2Level );
+
+ Status = NtWriteVirtualMemory( Thread->Process->ProcessHandle,
+ &Thread->ClientOs2Tib->ThreadId,
+ (PVOID)&Thread->ThreadId,
+ sizeof( Thread->ClientOs2Tib->ThreadId ),
+ NULL
+ );
+ ASSERT( NT_SUCCESS( Status ) );
+
+ Os2InsertThread( t->Process, Thread );
+ Context.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
+ Status = NtGetContextThread(Thread->ThreadHandle, &Context);
+ Context.FloatSave.ControlWord |= 0x3f; //mask exceptions, just in case
+ Status = NtSetContextThread(Thread->ThreadHandle, &Context);
+ //
+ // Remember Initial Stack, for Cleanup in case of exception
+ // (os2handleexception())
+ //
+ Thread->InitialStack = Context.Esp;
+
+ if (Os2CLI){
+ //
+ // don't let new threads get in while CLI is in progress
+ //
+ Status = NtSuspendThread( Thread->ThreadHandle, NULL );
+ ASSERT(NT_SUCCESS(Status));
+ }
+ }
+ else {
+ if (Thread != NULL) {
+ Os2DeallocateThread( Thread );
+ }
+
+ m->ReturnedErrorValue = Or2MapNtStatusToOs2Error(Status, ERROR_NO_PROC_SLOTS);
+ }
+
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Leaving Os2DosCreateThread. rc is %ld\n",m->ReturnedErrorValue));
+ }
+#endif
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosSetPriority(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSSETPRIORITY_MSG a = &m->u.DosSetPriority;
+ POS2_PROCESS Process;
+ POS2_THREAD Thread;
+
+ switch( a->Scope ) {
+ case PRTYS_PROCESS:
+ Process = Os2LocateProcessByProcessId( m,
+ t->Process,
+ (PID)a->TargetId,
+ (BOOLEAN)TRUE
+ );
+ if (Process != NULL) {
+ Os2SetProcessPriority( Process, a->Class, a->Delta );
+ }
+ break;
+
+ case PRTYS_PROCESSTREE:
+ Process = Os2LocateProcessByProcessId( m,
+ t->Process,
+ (PID)a->TargetId,
+ (BOOLEAN)TRUE
+ );
+ if (Process != NULL) {
+ Os2SetProcessTreePriority( Process, a->Class, a->Delta );
+ }
+ break;
+
+ case PRTYS_THREAD:
+ Thread = Os2LocateThreadByThreadId( m, t, (TID)a->TargetId );
+ if (Thread != NULL) {
+ Os2SetThreadPriority( Thread, a->Class, a->Delta );
+ }
+ break;
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosGetPriority(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSGETPRIORITY_MSG a = &m->u.DosGetPriority;
+ POS2_PROCESS Process;
+ POS2_THREAD Thread;
+ PLIST_ENTRY ListHead, ListNext;
+
+ switch( a->Scope ) {
+ case PRTYS_PROCESS:
+ Process = Os2LocateProcessByProcessId( m,
+ t->Process,
+ (PID)a->TargetId,
+ //
+ // We put FALSE for MustBeChild parameter below
+ // because on OS/2 you can call DosStartSession
+ // and then DosGetPriority on the PID and we don't
+ // keep track
+ //
+ (BOOLEAN)FALSE
+ );
+ if (Process != NULL) {
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ Thread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
+ if (Thread->Dying) {
+ m->ReturnedErrorValue = ERROR_INVALID_THREADID;
+ }
+ a->Priority = (Thread->Os2Class << 8) | (UCHAR)Thread->Os2Level;
+ }
+ break;
+
+ case PRTYS_THREAD:
+ Thread = Os2LocateThreadByThreadId( m, t, (TID)a->TargetId );
+ if (Thread != NULL) {
+ a->Priority = (Thread->Os2Class << 8) | (UCHAR)Thread->Os2Level;
+ }
+ break;
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosGetPPID(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSGETPPID_MSG a = &m->u.DosGetPPID;
+ POS2_PROCESS Process;
+
+ Process = Os2LocateProcessByProcessId( m,
+ t->Process,
+ (PID)a->ChildPid,
+ (BOOLEAN)FALSE
+ );
+ if (Process != NULL) {
+ a->ParentPid = Process->Parent->ProcessId;
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2DosError(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSERROR_MSG a = &m->u.DosError;
+
+ t->Process->ErrorAction = a->ErrorAction;
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+Os2WaitChildSatisfy(
+ IN OS2_WAIT_REASON WaitReason,
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m,
+ IN PVOID WaitParameter,
+ IN POS2_PROCESS TerminatingProcess,
+ IN POS2_TERMINATEPROCESS_MSG a
+ )
+{
+ PID ProcessId;
+ TID ThreadId;
+ ULONG len;
+ STRING ErrorString;
+ POS2_PROCESS Process;
+
+ UNREFERENCED_PARAMETER(WaitParameter);
+ if (WaitReason == WaitInterrupt) {
+ return TRUE;
+ }
+
+ //
+ // this routine is only called as a result of thread termination or
+ // debuggee event
+ //
+
+ if (m->ApiNumber == Os2WaitChild) {
+ ProcessId = m->u.DosWaitChild.ProcessId;
+ if (ProcessId == 0) {
+ Process = TerminatingProcess;
+ while ((Process = Process->Parent) != NULL) {
+ if (Process == t->Process) {
+ ProcessId = TerminatingProcess->ProcessId;
+ break;
+ }
+ }
+ }
+ }
+ else
+ if (m->ApiNumber == Os2ExecPgm) {
+ ProcessId = m->u.DosExecPgm.ResultProcessId;
+ }
+ else
+ if (m->ApiNumber == Os2Ptrace) {
+
+ POS2_THREAD Thread;
+ CONTEXT Context;
+ NTSTATUS Status;
+
+ ProcessId = (PID)(m->u.DosPTrace.PtraceBuf.pid);
+ ThreadId = (TID)(m->u.DosPTrace.PtraceBuf.tid);
+ Thread = (POS2_THREAD)(TerminatingProcess);
+ if ((NTSTATUS)(a) != STATUS_SINGLE_STEP && (NTSTATUS)(a) != STATUS_BREAKPOINT) {
+ //
+ // This is not a single step or breakpoint message then it
+ // must be a termination event.
+ //
+ if (WaitReason == WaitThread) {
+ if ((Thread->Process->ProcessId == ProcessId) &&
+ (Thread->ThreadId == (TID) 1)) {
+ m->u.DosPTrace.PtraceBuf.cmd = (USHORT)TRC_C_THD_ret;
+
+ //
+ // return - debugger will be waked up
+ //
+ return(TRUE);
+ }
+ else {
+ return(FALSE);
+ }
+ }
+ else if (TerminatingProcess->ProcessId == ProcessId) {
+ m->u.DosPTrace.PtraceBuf.cmd = (USHORT)TRC_C_KIL_ret;
+ //
+ // return - debugger will be waked up
+ //
+ return(TRUE);
+ }
+ else {
+ return(FALSE);
+ }
+ }
+
+ Thread->Process->DebugThreadId = Thread->ThreadId;
+ if (Thread->Process->ProcessId == ProcessId) {
+
+ //
+ // set values in return message, return TRUE
+ //
+#if DBG
+ IF_OS2_DEBUG(TASKING) {
+ KdPrint(("Os2srv: Os2WaitChildSatisfy of debuggee. PID %d, Status/msg %lx\n", ProcessId, a));
+ }
+#endif
+
+ m->u.DosPTrace.PtraceBuf.tid = (USHORT)(Thread->ThreadId);
+ //
+ // Get the context record for the target thread.
+ //
+ Context.ContextFlags = CONTEXT_FULL;
+ Status = NtGetContextThread(Thread->ThreadHandle, &Context);
+ if (!NT_SUCCESS(Status)){
+#if DBG
+ IF_OS2_DEBUG(TASKING) {
+ KdPrint(("Os2srv: Os2WaitChildStatify of Debugee fail at NtGetContextThread %lx\n", Status));
+ }
+#endif
+ m->u.DosPTrace.PtraceBuf.value = 0x0005; // Child process not traceable
+ m->u.DosPTrace.PtraceBuf.cmd = 0xFFFF; // Error
+ m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
+ return(TRUE);
+ }
+ if ((NTSTATUS)(a) == STATUS_SINGLE_STEP) {
+ m->u.DosPTrace.PtraceBuf.cmd = 0xFFFD; // singlestep
+ //
+ // reset TF bit in Eflags
+ //
+ //Context.EFlags &= ~(0x00000100);
+ Context.EFlags |= 0x10000; // RF
+ }
+ else if ((NTSTATUS)(a) == STATUS_BREAKPOINT) {
+ m->u.DosPTrace.PtraceBuf.cmd = 0xFFFC; // breakpoint
+ //
+ // reverse the thread one step back
+ //
+ Context.Eip--;
+ }
+ else {
+ //
+ // Unknown message
+ //
+#if DBG
+ IF_OS2_DEBUG(TASKING) {
+ KdPrint(("Os2srv: Os2WaitChildStatify of Debugee - Unknown message %lx\n", a));
+ }
+#endif
+ }
+
+ //
+ // Check if it is the first time - where we need to
+ // restore original entry point.
+ //
+ if (ldrGetEntryPoint(Thread->Process) == (UCHAR)0xCC) {
+ ldrRestoreEntryPoint(Thread->Process);
+ }
+
+ //
+ // Check if there are mtes to transfer to the debugger.
+ //
+ if (((LinkMTE *)Thread->Process->LinkMte)->NeedToTransfer) {
+ //
+ // Start the protocol of TRC_C_LIB_ret until TRC_C_SUC_ret.
+ //
+ ldrReturnProgramAndLibMTE(Thread->Process,
+ &(m->u.DosPTrace.PtraceBuf.mte),
+ &(m->u.DosPTrace.PtraceBuf.value),
+ &(m->u.DosPTrace.PtraceBuf.cmd)
+ );
+ }
+
+ Status = NtSetContextThread(Thread->ThreadHandle, &Context);
+ if (!NT_SUCCESS(Status)){
+#if DBG
+ IF_OS2_DEBUG(TASKING) {
+ KdPrint(("Os2srv: Os2WaitChildStatify of Debugee fail at NtSetContextThread %lx\n", Status));
+ }
+#endif
+ }
+ //
+ // Suspend the debuggee. The debugger will then resume it
+ //
+ Os2SuspendProcess(Thread->Process);
+
+ if ((NTSTATUS)(a) != STATUS_SINGLE_STEP) {
+ SetDebuggeeContextInMsg(&Context, &(m->u.DosPTrace.PtraceBuf));
+ }
+
+ //
+ // return - debugger will be waked up
+ //
+ return(TRUE);
+ }
+ else {
+#if DBG
+ IF_OS2_DEBUG(TASKING) {
+ KdPrint(("Os2srv: Os2WaitChildSatisfy of debuggee. different PID %d, msg %lx\n", ProcessId, a));
+ }
+#endif
+ return(FALSE);
+ }
+ }
+ else {
+ ASSERT(FALSE);
+#if DBG
+ KdPrint(("Os2srv: Os2WaitChildSatisfy. illegal api number %d\n", m->ApiNumber));
+#endif
+ return( FALSE );
+ }
+
+
+ if ((NTSTATUS)(a) == STATUS_SINGLE_STEP || (NTSTATUS)(a) == STATUS_BREAKPOINT) {
+ //
+ // This is a single step or breakpoint message, but the waiting
+ // message is not Os2DosPtrace, quit
+ //
+ return(FALSE);
+ }
+
+ if (TerminatingProcess->ProcessId == ProcessId) {
+ if (m->ApiNumber == Os2WaitChild) {
+ m->u.DosWaitChild.ResultCodes = TerminatingProcess->ResultCodes;
+ m->u.DosWaitChild.ResultProcessId = ProcessId;
+ return( TRUE );
+ }
+ else
+ if (m->ApiNumber == Os2ExecPgm) {
+ m->u.DosExecPgm.ResultCodes = TerminatingProcess->ResultCodes;
+ m->u.DosExecPgm.ResultProcessId = 0;
+ len = strlen(a->ErrorText);
+ if (len != 0) {
+ ErrorString.Length = (USHORT) len + (USHORT) 1;
+ ErrorString.MaximumLength = (USHORT) len + (USHORT) 2;
+ ErrorString.Buffer = a->ErrorText;
+ Os2FillErrorTextBuffer(&m->u.DosExecPgm.ErrorText,
+ &ErrorString,
+ 0);
+ m->ReturnedErrorValue =
+ TerminatingProcess->ResultCodes.ExitResult;
+ }
+ if (m->CaptureBuffer != NULL) {
+ Os2ReleaseCapturedArguments(m);
+ }
+ return( TRUE );
+ }
+ }
+
+ return( FALSE );
+}
+
+
+BOOLEAN
+Os2DosWaitChild(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSWAITCHILD_MSG a = &m->u.DosWaitChild;
+ POS2_PROCESS Process;
+ PLIST_ENTRY ListHead, ListNext;
+
+// // Obsolete code below: was keeping processes around as zombie so that
+// // DosCWait doesn't fail when father calls it after child termination.
+// // However, it turns out that OS/2 doesn't do this.
+// Process = NULL;
+// ListHead = &Os2ZombieList;
+// ListNext = ListHead->Flink;
+// while (ListNext != ListHead) {
+// Process = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
+// if (a->ProcessId == 0) {
+// if (t->Process->Parent->ProcessId == Process->CommandSubTreeId) {
+// break;
+// }
+// }
+// else
+// if (Process->ProcessId == a->ProcessId) {
+// break;
+// }
+//
+// Process = NULL;
+// ListNext = ListNext->Flink;
+// }
+//
+// if (Process != NULL) {
+// a->ResultCodes = Process->ResultCodes;
+// a->ResultProcessId = Process->ProcessId;
+// RemoveEntryList( &Process->ListLink );
+//
+// Os2DeallocateProcess( Process );
+// return( TRUE );
+// }
+
+ ListHead = &t->Process->ChildrenList;
+ ListNext = ListHead->Flink;
+ if (ListNext == ListHead) {
+ m->ReturnedErrorValue = ERROR_WAIT_NO_CHILDREN;
+ return( TRUE );
+ }
+
+ while (ListNext != ListHead) {
+ Process = CONTAINING_RECORD( ListNext, OS2_PROCESS, SiblingLink );
+ if (a->ProcessId == 0) {
+ break;
+ }
+ else
+ if (Process->ProcessId == a->ProcessId) {
+ break;
+ }
+
+ Process = NULL;
+ ListNext = ListNext->Flink;
+ }
+
+ if (Process == NULL) {
+ m->ReturnedErrorValue = ERROR_INVALID_PROCID;
+ return(TRUE);
+ }
+
+ if (a->WaitOption == DCWW_NOWAIT) {
+ m->ReturnedErrorValue = ERROR_CHILD_NOT_COMPLETE;
+ return( TRUE );
+ }
+
+ if (Os2CreateWait( WaitProcess,
+ (OS2_WAIT_ROUTINE)Os2WaitChildSatisfy,
+ t,
+ m,
+ NULL,
+ NULL )
+ ) {
+ return( FALSE );
+ }
+ else {
+ return( TRUE );
+ }
+}
+
+
+BOOLEAN
+Os2WaitThreadSatisfy(
+ IN OS2_WAIT_REASON WaitReason,
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m,
+ IN PVOID WaitParameter,
+ IN POS2_THREAD TerminatingThread,
+ IN PVOID SatisfyParameter2
+ )
+{
+ UNREFERENCED_PARAMETER(WaitParameter);
+ UNREFERENCED_PARAMETER(SatisfyParameter2);
+ if (WaitReason == WaitInterrupt) {
+ return TRUE;
+ }
+
+ //
+ // the ThreadLock is held on entry to this routine. this
+ // routine is only called as a result of thread termination.
+ //
+
+ if (t->Process == TerminatingThread->Process &&
+ (m->u.DosWaitThread.ThreadId == 0 ||
+ m->u.DosWaitThread.ThreadId == TerminatingThread->ThreadId
+ )
+ ) {
+ m->u.DosWaitThread.ThreadId = TerminatingThread->ThreadId;
+ return( TRUE );
+ }
+ else {
+ return( FALSE );
+ }
+}
+
+
+BOOLEAN
+Os2DosWaitThread(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSWAITTHREAD_MSG a = &m->u.DosWaitThread;
+ POS2_PROCESS Process;
+ POS2_THREAD Thread;
+
+ Process = t->Process;
+
+ if (a->ThreadId == (TID)0) {
+ //
+ // Waiting for any thread in this process to die.
+ //
+
+ if (t->Link.Flink == t->Link.Blink) {
+ //
+ // If we are the only thread in the list then waiting for any
+ // thread is invalid
+ //
+
+ m->ReturnedErrorValue = ERROR_INVALID_THREADID;
+ }
+ }
+ else
+ if (a->ThreadId == (TID)1) {
+ //
+ // Waiting on thread 1 is not allowed.
+ //
+
+ m->ReturnedErrorValue = ERROR_INVALID_THREADID;
+ }
+ else {
+ //
+ // Waiting for a specific thread in this process to die. See if
+ // it is a valid thread id.
+ //
+
+ Thread = Os2LocateThreadByThreadId( m, t, a->ThreadId );
+ if (Thread == NULL || Thread == t) {
+ m->ReturnedErrorValue = ERROR_INVALID_THREADID;
+ }
+ }
+
+ if (m->ReturnedErrorValue == NO_ERROR) {
+ if (a->WaitOption == DCWW_NOWAIT) {
+ m->ReturnedErrorValue = ERROR_THREAD_NOT_TERMINATED;
+ }
+ else {
+ Os2CreateWait( WaitThread,
+ (OS2_WAIT_ROUTINE)Os2WaitThreadSatisfy,
+ t,
+ m,
+ NULL,
+ NULL
+ );
+ }
+ }
+
+ return (BOOLEAN)( m->ReturnedErrorValue != NO_ERROR );
+}
+
+NTSTATUS
+Os2DispatchFreezeUnfreeze(
+ POS2_THREAD Thread,
+ PCONTEXT pContext,
+ ULONG NewEsp
+ )
+{
+ POS2_PROCESS Process = Thread->Process;
+ NTSTATUS Status;
+
+ //
+ // Save the current context of the thread on the stack.
+ //
+ Status = NtWriteVirtualMemory(
+ Process->ProcessHandle,
+ (PVOID)NewEsp,
+ pContext,
+ sizeof(CONTEXT),
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("Os2DispatchFreezeUnfreeze[%d,%d]: Fail write context, Status=%x\n",
+ Process->ProcessId,
+ Thread->ThreadId,
+ Status
+ );
+ ASSERT(FALSE);
+#endif // DBG
+ return(Status);
+ }
+
+ pContext->Esp = NewEsp - sizeof(ULONG);
+
+ pContext->SegCs = 0x1b;
+ pContext->SegSs = pContext->SegDs = pContext->SegEs = 0x23;
+
+ //
+ // Save the pointer the the context on the stack.
+ //
+ Status = NtWriteVirtualMemory(
+ Process->ProcessHandle,
+ (PVOID)pContext->Esp,
+ &NewEsp,
+ sizeof(ULONG),
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("Os2DispatchFreezeUnfreeze[%d,%d]: Fail write context address, Status=%x\n",
+ Process->ProcessId,
+ Thread->ThreadId,
+ Status
+ );
+ ASSERT(FALSE);
+#endif // DBG
+ return(Status);
+ }
+
+ //
+ // Set the new Eip to point to the currect routine, and set the new
+ // context.
+ //
+ if (Thread->DebugState & TRC_Frozen) {
+ pContext->Eip = (ULONG)Process->FreezeThread;
+ } else {
+ pContext->Eip = (ULONG)Process->UnfreezeThread;
+ }
+
+ Status = NtSetContextThread(
+ Thread->ThreadHandle,
+ pContext
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("Os2DispatchFreezeUnfreeze[%d,%d]: Fail set context, Status=%x\n",
+ Process->ProcessId,
+ Thread->ThreadId,
+ Status
+ );
+ ASSERT(FALSE);
+#endif // DBG
+ return(Status);
+ }
+
+ //
+ // If the thread is in wait state, it must be alerted.
+ // If it's not in wait state, no harm was done (the dispatch routine
+ // call NtTestAlert() to clear the alert kernel flag in this case).
+ //
+ NtAlertThread(Thread->ThreadHandle);
+ Os2CompleteResumeThread(Thread);
+
+ return(STATUS_SUCCESS);
+}
+
+VOID
+Os2FreezeUnfreezeThread(
+ IN POS2_THREAD Thread
+ )
+{
+ NTSTATUS Status;
+ CONTEXT Context;
+ POS2_PROCESS Process = Thread->Process;
+ ULONG NewEsp;
+
+ if ((Thread->DebugState & TRC_MustBeFrozen) &&
+ ! (Thread->DebugState & TRC_Frozen)) {
+ //
+ // The thread need to be frozen and it's not yet.
+ //
+ Thread->DebugState |= TRC_Frozen;
+ }
+ else if (!(Thread->DebugState & TRC_MustBeFrozen) &&
+ (Thread->DebugState & TRC_Frozen)) {
+ //
+ // The thread is frozen and it should not be.
+ //
+ Thread->DebugState &= ~TRC_Frozen;
+ }
+ else {
+ //
+ // Thread state is ok, we need not do enything.
+ //
+ return;
+ }
+
+ __try
+ {
+ Context.ContextFlags = CONTEXT_FULL;
+ Status = NtGetContextThread(
+ Thread->ThreadHandle,
+ &Context
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("Os2FreezeUnfreezeThread[%d,%d]: Fail get context, Status=%x\n",
+ Process->ProcessId,
+ Thread->ThreadId,
+ Status
+ );
+ ASSERT(FALSE);
+#endif // DBG
+ return;
+ }
+
+ if (Context.SegCs == 0x1b && Context.SegSs == 0x23) {
+ //
+ // The thread is in 32bit context.
+ // Switch the context of the thread to the client freeze/unfreeze
+ // routines.
+ //
+ NewEsp = Context.Esp - sizeof(CONTEXT);
+ Context.SegDs = Context.SegEs = 0x23;
+
+ Status = Os2DispatchFreezeUnfreeze(
+ Thread,
+ &Context,
+ NewEsp
+ );
+ return;
+ }
+ else
+ if (Thread->ThreadId == Process->DebugThreadId) {
+ //
+ // This thread is the one that the breakpoint occured in its
+ // context. The context must be in 16bit, not in 32bit context
+ // nor the thunk.
+ //
+#if DBG
+ if (Context.SegCs == 0x1b || Context.SegSs == 0x23) {
+ DbgPrint("Os2FreezeUnfreezeThread[%d,%d]: Breakpoint not in 16bit CS=%x, SS=%x\n",
+ Process->ProcessId,
+ Thread->ThreadId,
+ Context.SegCs,
+ Context.SegSs
+ );
+ ASSERT(FALSE);
+ }
+#endif // DBG
+ if (Thread->ThreadId == (TID) 1) {
+ //
+ // For thread 1, the 32bit stack pointer is taken from
+ // the Process structure. This sp is changing because of
+ // signals.
+ //
+ Status = NtReadVirtualMemory(
+ Process->ProcessHandle,
+ &(Process->ClientPib->Saved32Esp),
+ &NewEsp,
+ sizeof(ULONG),
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("Os2FreezeUnfreezeThread[%d,%d]: Fail read 32bit stack, Status=%x\n",
+ Process->ProcessId,
+ Thread->ThreadId,
+ Status
+ );
+ ASSERT(FALSE);
+#endif // DBG
+ return;
+ }
+ }
+ else {
+ //
+ // For thread that is not thread 1, take the sp from the
+ // InitialzeStack pointer.
+ //
+ NewEsp = Thread->InitialStack;
+ }
+
+ //
+ // Switch the context of the thread to the client freeze/unfreeze
+ // routines.
+ //
+ NewEsp -= sizeof(Context);
+
+ Status = Os2DispatchFreezeUnfreeze(
+ Thread,
+ &Context,
+ NewEsp
+ );
+ return;
+ }
+ else {
+ //
+ // The thread is in 16bit context or in the thunk, and it is
+ // not the thread that the breakpoint occured in it.
+ //
+ if (Thread->DebugState & TRC_Frozen) {
+ Status = NtSuspendThread(
+ Thread->ThreadHandle,
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("Os2FreezeUnfreezeThread[%d,%d]: Fail suspend, Status=%x\n",
+ Process->ProcessId,
+ Thread->ThreadId,
+ Status
+ );
+ ASSERT(FALSE);
+#endif // DBG
+ return;
+ }
+ }
+ else {
+ Status = NtResumeThread(
+ Thread->ThreadHandle,
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("Os2FreezeUnfreezeThread[%d,%d]: Fail resume, Status=%x\n",
+ Process->ProcessId,
+ Thread->ThreadId,
+ Status
+ );
+ ASSERT(FALSE);
+#endif // DBG
+ return;
+ }
+ }
+ }
+ }
+ __finally
+ {
+ //
+ // We didn't succeed to finish the freeze/unfreeze, so restore
+ // the state of the thread.
+ //
+ if (!NT_SUCCESS(Status)) {
+ Thread->DebugState ^= (TRC_MustBeFrozen | TRC_Frozen);
+ }
+ }
+}
+
+VOID
+Os2ExecuteFreezeUnfreeze(
+ POS2_PROCESS Process
+ )
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_THREAD Thread;
+
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+
+ //
+ // For every thread in the process, check if we need to change
+ // from frozen state to unfrozen, or vise versa.
+ //
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
+ Os2FreezeUnfreezeThread(Thread);
+ ListNext = ListNext->Flink;
+ }
+}
+
+BOOLEAN
+Os2DosPTrace(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ PTRACEBUF *a = &(m->u.DosPTrace.PtraceBuf);
+ POS2_PROCESS Process;
+ CONTEXT Context;
+ NTSTATUS Status;
+ POS2_THREAD Thread, NextThread, PrevThread;
+ PLIST_ENTRY ListHead, ListNext, ListPrev;
+ UCHAR NameBuf[256];
+ ULONG FlatDebugeeAddress;
+ DBGTHREADSTATUS DbgThreadStatus;
+ OS2_WAIT_REASON WaitReason;
+ USHORT mte = 0;
+
+ m->ReturnedErrorValue = NO_ERROR;
+ //
+ // Find the debugee process
+ //
+ ListHead = &Os2RootProcess->ListLink;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Process = CONTAINING_RECORD( ListNext, OS2_PROCESS, ListLink );
+ if (Process->ProcessId == (PID)(a->pid)) {
+ break;
+ }
+ ListNext = ListNext->Flink;
+ }
+
+ if (ListNext == ListHead) {
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ a->value = 0x0002; // Child process not found
+ m->ReturnedErrorValue = ERROR_INVALID_PROCID;
+ return(TRUE);
+ }
+
+ if (!(Process->Flags & (OS2_PROCESS_TRACE | OS2_PROCESS_TRACETREE))) {
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ a->value = 0x0005; // Child process not traceable
+ m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
+ return(TRUE);
+
+ }
+
+ if ((a->cmd == TRC_C_ReadReg) || (a->cmd == TRC_C_WriteReg) ||
+ (a->cmd == TRC_C_SStep) ||
+ ((a->tid != 0) && ((a->cmd == TRC_C_Freeze) || (a->cmd == TRC_C_Resume) || (a->cmd == TRC_C_ThrdStat))) ) {
+
+ //
+ // Locate the thread in the debuggee process
+ //
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+
+ //
+ // Save NextThread for later use
+ //
+ NextThread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
+
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
+ if (Thread->ThreadId == (TID)(a->tid)) {
+ break;
+ }
+ ListNext = ListNext->Flink;
+ }
+
+ if (ListNext == ListHead) {
+#if DBG
+ IF_OS2_DEBUG(TASKING) {
+ KdPrint(("Os2srv: Os2DosPTrace invalid thread id %hd for cmd %hd\n", a->tid, a->cmd));
+ }
+#endif
+ m->ReturnedErrorValue = ERROR_INVALID_TID;
+ a->value = 0x0001; // Bad Command
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ return(TRUE);
+ }
+ //
+ // Get the context record for the target thread.
+ //
+ Context.ContextFlags = CONTEXT_FULL;
+ Status = NtGetContextThread(Thread->ThreadHandle, &Context);
+ if (!NT_SUCCESS(Status)){
+#if DBG
+ IF_OS2_DEBUG(TASKING) {
+ KdPrint(("Os2srv: Os2DosPTrace fail at NtGetContextThread %lx\n", Status));
+ }
+#endif
+ a->value = 0x0005; // Child process not traceable
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
+ return(TRUE);
+ }
+ }
+
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "DosPTrace - command %hd. PID %d, TID %hd\n", a->cmd, Process->ProcessId, a->tid));
+ }
+#endif
+ switch (a->cmd) {
+ case 0x0001: // Read memory I-Space
+ //
+ // Read Memory from debuggee
+ //
+ if (a->segv == 0x1b){
+ //
+ // 32 bit segment - BUGBUG need to skip over
+ //
+ FlatDebugeeAddress = (ULONG)(a->offv);
+ }
+ else {
+ FlatDebugeeAddress = (ULONG)(SELTOFLAT(a->segv)) | (ULONG)(a->offv);
+ }
+ Status = NtReadVirtualMemory( Process->ProcessHandle,
+ (PVOID) FlatDebugeeAddress,
+ (PVOID) &(a->value),
+ 2,
+ NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "DosPTrace - Read I-Space, failed to read %x:%x Status %lx\n", a->segv, a->offv, Status));
+ }
+#endif
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else {
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "DosPTrace - Read I-Space, %x:%x == %hx\n", a->segv, a->offv, a->value));
+ }
+#endif
+ a->cmd = (USHORT)TRC_C_SUC_ret;
+ }
+ break;
+
+ case 0x0002: // Read memory D-Space
+ //
+ // Read Memory from debuggee
+ //
+ if (a->segv == 0x23){
+ //
+ // 32 bit segment - BUGBUG need to skip over
+ //
+ FlatDebugeeAddress = (ULONG)(a->offv);
+ }
+ else {
+ FlatDebugeeAddress = (ULONG)(SELTOFLAT(a->segv)) | (ULONG)(a->offv);
+ }
+ Status = NtReadVirtualMemory( Process->ProcessHandle,
+ (PVOID) FlatDebugeeAddress,
+ (PVOID) &(a->value),
+ 2,
+ NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "DosPTrace - Read D-Space, failed to read %x:%x Status %lx\n", a->segv, a->offv, Status));
+ }
+#endif
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else {
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "DosPTrace - Read D-Space, %x:%x == %hx\n", a->segv, a->offv, a->value));
+ }
+#endif
+ a->cmd = (USHORT)TRC_C_SUC_ret;
+ }
+ break;
+
+ case 0x0003: // Read registers
+ SetDebuggeeContextInMsg(&Context, a);
+ a->cmd = (USHORT)TRC_C_SUC_ret;
+ break;
+
+ case 0x0004: // Write memory I-Space
+ //
+ // Write Memory from debuggee
+ //
+ if (a->segv == 0x1b){
+ //
+ // 32 bit segment - BUGBUG need to skip over
+ //
+ FlatDebugeeAddress = (ULONG)(a->offv);
+ }
+ else {
+ FlatDebugeeAddress = (ULONG)(SELTOFLAT(a->segv)) | (ULONG)(a->offv);
+ }
+
+ Status = NtWriteVirtualMemory( Process->ProcessHandle,
+ (PVOID) FlatDebugeeAddress,
+ (PVOID) &(a->value),
+ 2,
+ NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "DosPTrace - Write I-Space, failed to write %x:%x Status %lx\n", a->segv, a->offv, Status));
+ }
+#endif
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else {
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "DosPTrace - Write I-Space, %x:%x == %hx\n", a->segv, a->offv, a->value));
+ }
+#endif
+ a->cmd = (USHORT)TRC_C_SUC_ret;
+ }
+ break;
+
+ case 0x0005: // Write memory D-Space
+ //
+ // Write Memory from debuggee
+ //
+ if (a->segv == 0x23){
+ //
+ // 32 bit segment - BUGBUG need to skip over
+ //
+ FlatDebugeeAddress = (ULONG)(a->offv);
+ }
+ else {
+ FlatDebugeeAddress = (ULONG)(SELTOFLAT(a->segv)) | (ULONG)(a->offv);
+ }
+ Status = NtWriteVirtualMemory( Process->ProcessHandle,
+ (PVOID) FlatDebugeeAddress,
+ (PVOID) &(a->value),
+ 2,
+ NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "DosPTrace - Write D-Space, failed to write %x:%x Status %lx\n", a->segv, a->offv, Status));
+ }
+#endif
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else {
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "DosPTrace - Write D-Space, %x:%x == %hx\n", a->segv, a->offv, a->value));
+ }
+#endif
+ a->cmd = (USHORT)TRC_C_SUC_ret;
+ }
+ break;
+
+ case 0x0006: // Write registers
+ //
+ // set ptracbuf value from context
+ //
+ Context.Eax = a->rAX;
+ Context.Ebx = a->rBX;
+ Context.Ecx = a->rCX;
+ Context.Edx = a->rDX;
+ Context.Esi = a->rSI;
+ Context.Edi = a->rDI;
+ Context.Ebp = a->rBP;
+ Context.SegDs = a->rDS;
+ Context.SegEs = a->rES;
+ Context.Eip = a->rIP;
+ Context.SegCs = a->rCS;
+ Context.EFlags |= a->rF;
+ Context.Esp = a->rSP;
+ Context.SegSs = a->rSS;
+ Status = NtSetContextThread(Thread->ThreadHandle, &Context);
+ if (!NT_SUCCESS(Status)){
+#if DBG
+ IF_OS2_DEBUG(TASKING) {
+ KdPrint(("Os2srv: Os2DosPTrace fail at NtSetContextThread %lx\n", Status));
+ }
+#endif
+ a->value = 0x0005; // Child process not traceable
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
+ return(TRUE);
+ }
+ a->cmd = (USHORT)TRC_C_SUC_ret;
+ break;
+
+ case 0x0007: // Go (with signal)
+
+ //
+ // If all the debugee threads are frozen, just return error.
+ //
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
+ if (!(Thread->DebugState & TRC_MustBeFrozen)) {
+ break;
+ }
+ ListNext = ListNext->Flink;
+ }
+
+ if (ListNext == ListHead) {
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ a->value = 0x0001; // Bad Command
+ break;
+ }
+
+ Os2ExecuteFreezeUnfreeze(Process);
+
+ //
+ // Block debugger process for a breakpoint, single step
+ // or thread/process termination.
+ //
+ if ((Thread->Flags & OS2_THREAD_THREAD1) && (Thread->Dying)) {
+ WaitReason = WaitProcess;
+ }
+ else {
+ WaitReason = WaitThread;
+ }
+ if (Os2CreateWait( WaitReason,
+ (OS2_WAIT_ROUTINE)Os2WaitChildSatisfy,
+ t,
+ m,
+ NULL,
+ NULL )
+ ) {
+ Os2ResumeProcess(Process);
+ return(FALSE);
+ }
+ else {
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
+ }
+ break;
+
+ case 0x0008: // Terminate Child Process
+ Process->Flags |= OS2_PROCESS_TERMINATE;
+ if (Process->Flags & OS2_EXIT_IN_PROGRESS) {
+ Os2ResumeProcess(Process);
+ }
+ Os2SigKillProcess(Process);
+ a->cmd = (USHORT)TRC_C_SUC_ret;
+ break;
+
+ case 0x0009: // Single Step
+ //
+ // set TF bit in Eflags
+ //
+ Context.EFlags |= 0x100;
+ Status = NtSetContextThread(Thread->ThreadHandle, &Context);
+ if (!NT_SUCCESS(Status)){
+#if DBG
+ IF_OS2_DEBUG(TASKING) {
+ KdPrint(("Os2srv: Os2DosPTrace fail at NtSetContextThread %lx\n", Status));
+ }
+#endif
+ a->value = 0x0005; // Child process not traceable
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
+ return(TRUE);
+ }
+
+ //
+ // Don't allow single step if the current thread is frozen.
+ // This is not a problem to code-view, since it unfreezes
+ // the thread first, then sstep, and the freezes it again.
+ //
+ if (Thread->DebugState & TRC_MustBeFrozen) {
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ a->value = 0x0001; // Bad Command
+ break;
+ }
+
+ Os2ExecuteFreezeUnfreeze(Process);
+
+ //
+ // Block debugger process for a breakpoint, single step
+ // or thread/process termination.
+ //
+ if ((Thread->Flags & OS2_THREAD_THREAD1) && (Thread->Dying)) {
+ WaitReason = WaitProcess;
+ }
+ else {
+ WaitReason = WaitThread;
+ }
+ if (Os2CreateWait( WaitReason,
+ (OS2_WAIT_ROUTINE)Os2WaitChildSatisfy,
+ t,
+ m,
+ NULL,
+ NULL )
+ ) {
+ Os2ResumeProcess(Process);
+ return(FALSE);
+ }
+ else {
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ return(TRUE);
+ }
+ break;
+
+ case 0x000A: // Stop Child Process
+ if (Process->FirstPtrace) {
+ //
+ // Block debugger process until debuggee gets to it's
+ // 16 bit entry point.
+ // Os2WaitChildSatisfy will start the protocol of
+ // TRC_C_LIB_ret and will restore the 16 bit entry point.
+ //
+ //
+
+ // If all the debugee threads are frozen, just return error.
+ //
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
+ if (!(Thread->DebugState & TRC_MustBeFrozen)) {
+ break;
+ }
+ ListNext = ListNext->Flink;
+ }
+
+ if (ListNext == ListHead) {
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ a->value = 0x0001; // Bad Command
+ break;
+ }
+
+ Os2ExecuteFreezeUnfreeze(Process);
+
+ Process->FirstPtrace = FALSE;
+
+ if ((Thread->Flags & OS2_THREAD_THREAD1) && (Thread->Dying)) {
+ WaitReason = WaitProcess;
+ }
+ else {
+ WaitReason = WaitThread;
+ }
+ if (Os2CreateWait( WaitReason,
+ (OS2_WAIT_ROUTINE)Os2WaitChildSatisfy,
+ t,
+ m,
+ NULL,
+ NULL )
+ ) {
+ Os2ResumeProcess(Process);
+ return(FALSE);
+ }
+ else {
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ return(TRUE);
+ }
+ }
+ else {
+ //
+ // Continue the protocol of TRC_C_LIB_ret until TRC_C_SUC_ret.
+ //
+ ldrReturnProgramAndLibMTE(Process,
+ &(a->mte),
+ &(a->value),
+ &(a->cmd)
+ );
+ }
+ break;
+
+ case 0x000B: // Freeze Thread
+ a->cmd = (USHORT)TRC_C_SUC_ret;
+ if (a->tid == 0) {
+ //
+ // Freeze all threads
+ //
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD(ListNext,
+ OS2_THREAD,
+ Link );
+ Thread->DebugState |= TRC_MustBeFrozen;
+ ListNext = ListNext->Flink;
+ }
+ }
+ else {
+ Thread->DebugState |= TRC_MustBeFrozen;
+ }
+ break;
+
+ case 0X000C: // Unfreeze Thread
+ a->cmd = (USHORT)TRC_C_SUC_ret;
+ if (a->tid == 0) {
+ //
+ // Unfreeze all threads
+ //
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD(ListNext,
+ OS2_THREAD,
+ Link );
+ Thread->DebugState &= ~TRC_MustBeFrozen;
+ ListNext = ListNext->Flink;
+ }
+ }
+ else {
+ Thread->DebugState &= ~TRC_MustBeFrozen;
+ }
+ break;
+
+ case 0x000D: // Convert Seg number to Selector
+
+ if (a->mte == 0){
+ //
+ // want the name of the EXE itself
+ //
+ mte = ((LinkMTE *)Process->LinkMte)->NextMTE->MTE;
+ }
+
+ a->value = ldrFindSegForHandleandNum(mte, a->mte, a->value);
+
+ if (a->value == 0){
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "DosPTrace - convertnumtoseg failed for mte %hx, num %hx\n", a->mte, a->segv));
+ }
+#endif
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ }
+ else {
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "DosPTrace - convertnumtoseg mte %hx, num %hx --> seg %hx\n", a->mte, a->segv, a->value));
+ }
+#endif
+ a->cmd = (USHORT)TRC_C_SUC_ret;
+ }
+ break;
+
+ case 0x000E: // Get FP registers (segv, offv has 94 bytes buf pointer)
+ a->cmd = (USHORT)TRC_C_SUC_ret;
+ break;
+
+ case 0x000F: // Set FP registers (segv, offv has 94 bytes buf pointer)
+ a->cmd = (USHORT)TRC_C_SUC_ret;
+ break;
+
+ case 0x0010: // Get Library module name (value had lib module handle,
+ // segv, offv is buffer to receive name
+ if (a->value == 0){
+ //
+ // want the name of the EXE itself
+ //
+ if (((LinkMTE *)Process->LinkMte)->NextMTE != NULL) {
+ mte = ((LinkMTE *)Process->LinkMte)->NextMTE->MTE;
+ }
+ else {
+ //
+ // EXE failed to load.
+ //
+ a->cmd = (USHORT)TRC_C_ERR_ret; // Failed to get module name
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ break;
+ }
+ }
+
+ if (ldrGetModName(
+ (a->value ? NULL : ldrFindMTEForHandle(mte)),
+ a->value,
+ NameBuf,
+ 256
+ )) {
+ //
+ // Write the name into debugger address space
+ //
+ FlatDebugeeAddress = (ULONG)(SELTOFLAT(a->segv)) | (ULONG)(a->offv);
+ Status = NtWriteVirtualMemory( t->Process->ProcessHandle,
+ (PVOID) FlatDebugeeAddress,
+ (PVOID) NameBuf,
+ (strlen(NameBuf))+1,
+ NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "DosPTrace - cmd GetModName, failed to write result Status %lx\n", Status));
+ }
+#endif
+ m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ }
+ else {
+ a->cmd = (USHORT)TRC_C_SUC_ret;
+ }
+
+ }
+ else {
+ a->cmd = (USHORT)TRC_C_ERR_ret; // Failed to get module name
+ m->ReturnedErrorValue = ERROR_INVALID_HANDLE;
+ }
+
+ break;
+
+ case 0x0011: // Get Thread Status
+ if (a->tid == 0) {
+ //
+ // Locate the 1st thread in the debuggee process
+ //
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ NextThread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
+ a->value = (USHORT)(NextThread->ThreadId);
+ }
+ else {
+ //
+ // return the previous id in value (in a circular way).
+ // --------
+ //
+ ListPrev = (&Thread->Link)->Blink;
+ PrevThread = CONTAINING_RECORD( ListPrev, OS2_THREAD, Link );
+ if (PrevThread == (POS2_THREAD) &Process->ThreadList) {
+ ListPrev = (&PrevThread->Link)->Blink;
+ PrevThread = CONTAINING_RECORD( ListPrev, OS2_THREAD, Link );
+ }
+ a->value = (USHORT)(PrevThread->ThreadId);
+ }
+
+ //
+ // Write the thread status into debugger memory at address segv:offv
+ //
+ DbgThreadStatus.DebugState =
+ (Thread->DebugState & TRC_MustBeFrozen) ? TRC_C_Frozen : TRC_C_Thawed;
+ DbgThreadStatus.ThreadState = 0; // BUGBUG - always runnable
+ DbgThreadStatus.Priority = (Thread->Os2Class << 8) | (UCHAR)Thread->Os2Level;
+ FlatDebugeeAddress = (ULONG)(SELTOFLAT(a->segv)) | (ULONG)(a->offv);
+ Status = NtWriteVirtualMemory( t->Process->ProcessHandle,
+ (PVOID) FlatDebugeeAddress,
+ (PVOID) &DbgThreadStatus,
+ sizeof(DbgThreadStatus),
+ NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "DosPTrace - cmd GetThreadStatus, failed to write result Status %lx\n", Status));
+ }
+#endif
+ m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ }
+ else {
+ a->cmd = (USHORT)TRC_C_SUC_ret;
+ }
+ break;
+
+ case 0x0012: // get r/o segment alias - not supported yet
+ a->value = 0x0001; // Bad Command
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ m->ReturnedErrorValue = ERROR_NOT_SUPPORTED;
+ break;
+
+ case 0x0013: // get r/w segment alias - not supported yet
+ a->value = 0x0001; // Bad Command
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ m->ReturnedErrorValue = ERROR_NOT_SUPPORTED;
+ break;
+
+ case 0x0014: // free alias - not supported yet
+ a->value = 0x0001; // Bad Command
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ m->ReturnedErrorValue = ERROR_NOT_SUPPORTED;
+ break;
+
+ default:
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "DosPTrace - invalid command %hd. PID %d, TID %d\n", a->cmd, t->Process->ProcessId, t->ThreadId));
+ }
+#endif
+ m->ReturnedErrorValue = ERROR_INVALID_PARAMETER;
+ a->value = 0x0001; // Bad Command
+ a->cmd = (USHORT)TRC_C_ERR_ret;
+ }
+
+ return (TRUE);
+}
+
+NTSTATUS
+Os2SendTmReleaseThreadOnLPC(
+ IN POS2_SESSION Session,
+ IN POS2_PROCESS Process
+ )
+{
+ NTSTATUS Status;
+ SCREQUESTMSG Request;
+
+ Request.Request = TaskManRequest;
+ Request.d.Tm.Request = TmReleaseLPC;
+ Request.d.Tm.ExitResults = (ULONG)Process->ClientId.UniqueProcess;
+
+ PORT_MSG_TOTAL_LENGTH(Request) = sizeof(SCREQUESTMSG);
+ PORT_MSG_DATA_LENGTH(Request) = sizeof(SCREQUESTMSG) - sizeof(PORT_MESSAGE);
+ PORT_MSG_ZERO_INIT(Request) = 0L;
+
+ Status = NtRequestPort(
+ Session->ConsolePort,
+ (PPORT_MESSAGE) &Request);
+
+ if ( !NT_SUCCESS( Status ))
+ {
+#if DBG
+ KdPrint(( "OS2SS: Unable to send release LPC request - Status == %X\n",
+ Status));
+#endif
+
+ return( Status );
+ }
+
+ // ASSERT ( PORT_MSG_TYPE(Request) == LPC_REPLY );
+
+ return( Request.Status );
+}
+
+
+BOOLEAN
+Os2DosCloseHandle(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes a list of handles (had been opened/duplicated for
+ the server by client before an error had occured).
+
+Arguments:
+
+ t - calling thread
+
+ m - message
+
+Return Value:
+
+ TRUE - create a return message
+
+Note:
+
+--*/
+
+{
+ POS2_DOSCLOSE_HANDLE_MSG b = &m->u.DosCloseHandle;
+ ULONG i = b->HandleNumber;
+
+ UNREFERENCED_PARAMETER(t);
+#if DBG
+ IF_OS2_DEBUG( TASKING ) {
+ KdPrint(( "Entering Os2CloseHandle\n"));
+ }
+#endif
+
+ for ( ; i ; i-- )
+ {
+ CloseHandle(b->HandleTable[i - 1]);
+ }
+ return (FALSE);
+}
+
+#if PMNT
+BOOLEAN
+PMSetPMshellFlag(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is not in use.
+
+Arguments:
+
+ t - calling thread
+
+ m - message
+
+Return Value:
+
+ TRUE - always
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(t);
+ UNREFERENCED_PARAMETER(m);
+ return(TRUE);
+}
+#endif
+
diff --git a/private/os2/server/srvvm.c b/private/os2/server/srvvm.c
new file mode 100644
index 000000000..f9b3aaf99
--- /dev/null
+++ b/private/os2/server/srvvm.c
@@ -0,0 +1,2775 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvvm.c
+
+Abstract:
+
+ Memory Management API
+
+Author:
+
+ Steve Wood (stevewo) 11-Oct-1989
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_ERRORS
+#include "os2srv.h"
+#include "os2tile.h"
+#include "os2ldr.h"
+
+//
+// Masks used to determine the correct action to be taken
+// for DosReallocHuge()
+//
+#define H_NEW_PARTIAL 1
+#define H_CUR_PARTIAL 2
+#define H_SEG_INC 4
+#define H_SEG_DEC 8
+#define H_SAME_SEG_NO_PARTIAL 0
+#define H_SAME_SEG_NEW_PARTIAL H_NEW_PARTIAL
+#define H_SAME_SEG_DEL_PARTIAL H_CUR_PARTIAL
+#define H_SAME_SEG_CHG_PARTIAL (H_NEW_PARTIAL | H_CUR_PARTIAL)
+#define H_INC_SEG_NO_PARTIAL H_SEG_INC
+#define H_INC_SEG_NEW_PARTIAL (H_SEG_INC | H_NEW_PARTIAL)
+#define H_INC_SEG_DEL_PARTIAL (H_SEG_INC | H_CUR_PARTIAL)
+#define H_INC_SEG_CHG_PARTIAL (H_SEG_INC | H_NEW_PARTIAL | H_CUR_PARTIAL)
+#define H_DEC_SEG_NO_PARTIAL H_SEG_DEC
+#define H_DEC_SEG_NEW_PARTIAL (H_SEG_DEC | H_NEW_PARTIAL)
+#define H_DEC_SEG_DEL_PARTIAL (H_SEG_DEC | H_CUR_PARTIAL)
+#define H_DEC_SEG_CHG_PARTIAL (H_SEG_DEC | H_NEW_PARTIAL | H_CUR_PARTIAL)
+
+#define ROUND_UP_TO_PAGES(x) (((ULONG)(x)+0xfff)&(~0xfff))
+
+NTSTATUS
+Os2InitializeMemory( VOID )
+
+/*++
+
+Routine Description:
+
+ This function performs the global initialization for the shared memory
+ component of the OS/2 Subsystem.
+
+ Each shared memory object allocated with the DosAllocSharedMem API call
+ has an associated shared memory object descriptor created that contains
+ the NT section handle that points to the memory for the object, the
+ page level protection that is associated with the memory, along with
+ a reference count of the number of processes that have attached to this
+ shared memory object. The descriptors are linked together on a doubly
+ linked list, the head of which is the global variable Os2SharedMemoryList.
+
+ For each process that has attached to a shared memory object, there is
+ a process reference object created that points to the shared memory
+ object descriptor. Each OS/2 process object contains the head of a
+ doubly linked list of process reference objects. This list is used
+ to detect multiple references to the same shared memory object from
+ the same process. This list is also used during process termination
+ to free all of a processes references to shared memory objects.
+
+ Any process reference object that points to a named shared memory
+ object descriptor also contains a reference count of the number of
+ times the process has referenced the object's name. This allows the
+ DosFreeMem API to know when to actually unmap a view of a shared
+ memory object from the caller's address space (i.e. when the
+ reference count goes to zero).
+
+ Both linked lists are protected by the ProcessStructureLock, so that
+ nothing relevant can changed while we are playing with the lists.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Status value - STATUS_SUCCESS always.
+
+--*/
+
+{
+ //
+ // Initialize the global list of shared memory object descriptors
+ // to be the empty list.
+ //
+
+ InitializeListHead( &Os2SharedMemoryList );
+
+
+ //
+ // Always return success.
+ //
+
+ return( STATUS_SUCCESS );
+}
+
+
+POS2_SHARED_MEMORY_OBJECT
+Os2CreateSharedMemoryObject(
+ IN POS2_API_MSG m,
+ IN PVOID BaseAddress,
+ IN ULONG Index,
+ IN ULONG RegionSize,
+ IN HANDLE SectionHandle,
+ IN ULONG AllocationFlags,
+ IN PSTRING SecName
+ )
+/*++
+
+Routine Description:
+
+ This function creates a shared memory object descriptor and appends
+ it to the global linked list of shared memory object descriptors.
+ It sets the reference count to zero, as no process reference objects
+ are pointing to this shared memory object descriptor yet.
+
+ This function must be called within the scope of the
+ ProcessStructureLock.
+
+Arguments:
+
+ m - pointer to an OS/2 API message structure where any error code is
+ returned in the ReturnedErrorValue field.
+
+ BaseAddress - base address of the shared memory object for all processes
+ that attach to this shared memory object.
+
+ Index - An index into the BitMap to allocate the shared memory object.
+
+ RegionSize - Size of the shared memory object.
+
+ SectionHandle - an NT handle to the section object that describes the
+ shared memory. This is always a SEC_BASED section.
+
+ AllocationFlags - any of the following flags:
+
+ OBJ_GETTABLE and/or OBJ_GIVEABLE
+
+ if neither is set, then must be named shared memory
+ that will be reference counted by process.
+
+Return Value:
+
+ Point to the shared memory object descriptor or NULL if unsuccessful.
+
+--*/
+
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+
+ //
+ // First see if the specified base address is already in the list
+ // of shared memory objects. If it is, then return an error.
+ //
+
+ ListHead = &Os2SharedMemoryList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ MemoryObject = CONTAINING_RECORD( ListNext,
+ OS2_SHARED_MEMORY_OBJECT,
+ Link
+ );
+ if (MemoryObject->BaseAddress == BaseAddress) {
+ m->ReturnedErrorValue = ERROR_ALREADY_EXISTS;
+ return( NULL );
+ }
+
+ ListNext = ListNext->Flink;
+ }
+
+ //
+ // Not in the list, so allocate the shared memory object descriptor,
+ // initialize it and append it to the global list of shared memory
+ // objects. Return an error if not enough memory to allocated the
+ // shared memory object descriptor.
+ //
+
+ MemoryObject = RtlAllocateHeap( Os2Heap, 0, sizeof( *MemoryObject ) );
+ if (MemoryObject != NULL) {
+ MemoryObject->IsHuge = FALSE;
+ MemoryObject->RefCount = 0;
+ MemoryObject->BaseAddress = BaseAddress;
+ MemoryObject->Index = Index;
+ MemoryObject->RegionSize = RegionSize;
+ MemoryObject->SectionHandle = SectionHandle;
+ MemoryObject->AllocationFlags = AllocationFlags;
+ if (SecName == NULL || SecName->Buffer == NULL) {
+ MemoryObject->SectionName.Buffer = NULL;
+ }
+ else {
+ MemoryObject->SectionName.Buffer = (PCHAR)RtlAllocateHeap (Os2Heap, 0, SecName->Length);
+ if (MemoryObject->SectionName.Buffer == NULL) {
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ RtlFreeHeap (Os2Heap, 0, MemoryObject);
+ return(NULL);
+ }
+ MemoryObject->SectionName.Length = SecName->Length;
+ MemoryObject->SectionName.MaximumLength = SecName->Length;
+ RtlMoveMemory( MemoryObject->SectionName.Buffer,
+ SecName->Buffer,
+ SecName->Length);
+ }
+ InsertTailList( &Os2SharedMemoryList, &MemoryObject->Link );
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: CreateSharedMemoryObject (%lX) ->BaseAddress = %lX\n",
+ MemoryObject, MemoryObject->BaseAddress
+ );
+ }
+#endif
+ }
+ else {
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+
+ //
+ // Return a pointer to the newly created shared memory object descriptor
+ // or NULL if unable to allocate.
+ //
+ return( MemoryObject );
+}
+
+
+VOID
+Os2FreeSharedMemoryObject(
+ POS2_SHARED_MEMORY_OBJECT MemoryObject
+ )
+/*++
+
+Routine Description:
+
+ This function removes the passed shared memory object descriptor from
+ the global list, closes the NT section handle stored in the descriptor,
+ and returns the space occupied by the descriptor to the heap.
+
+ This function must be called within the scope of the
+ ProcessStructureLock.
+
+Arguments:
+
+ MemoryObject - pointer to the shared memory object descriptor to free.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Free the buffer used for holding the shared memory name
+ //
+
+ if (MemoryObject->SectionName.Buffer != NULL) {
+ RtlFreeHeap(Os2Heap, 0, MemoryObject->SectionName.Buffer);
+ }
+
+ //
+ // Remove the descriptor from the global linked list.
+ //
+
+ RemoveEntryList( &MemoryObject->Link );
+
+ //
+ // Close the NT Section Handle that points to the memory. The memory
+ // and any associated name, will actually be freed when the last view
+ // of the memory is unmap, which will be real soon now since the caller
+ // of this function is going to do it or process termination will.
+ //
+
+ NtClose( MemoryObject->SectionHandle );
+
+ //
+ // Return the space for the descriptor back to the heap.
+ //
+
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: FreeSharedMemoryObject (%lX) ->BaseAddress = %lX\n",
+ MemoryObject, MemoryObject->BaseAddress
+ );
+ }
+#endif
+
+ RtlFreeHeap( Os2Heap, 0, MemoryObject );
+
+ return;
+}
+
+
+POS2_SHARED_MEMORY_PROCESS_REF
+Os2CreateProcessRefToSharedMemory(
+ IN POS2_PROCESS Process,
+ IN POS2_SHARED_MEMORY_OBJECT MemoryObject
+ )
+/*++
+
+Routine Description:
+
+ This function creates a shared memory reference object that points
+ to the specified shared memory object descriptor. The shared memory
+ reference object will be appended to the linked list rooted in the
+ specified OS/2 process.
+
+ If the specified process already contains a shared memory reference
+ object for the specified shared memory, then just bump the reference
+ count in the shared memory reference object.
+
+ This function must be called within the scope of the
+ ProcessStructureLock.
+
+Arguments:
+
+ Process - points to an OS/2 process structure that is the process
+ that is making the reference to the shared memory object.
+
+ MemoryObject - points to the shared memory object descriptor being
+ referenced by the specified process.
+
+Return Value:
+
+ Returns a pointer to the shared memory reference object or NULL if
+ unable to allocate heap space for it.
+
+--*/
+
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
+
+ //
+ // First search the list of shared memory reference objects for the
+ // specified process. If a shared memory reference object is found
+ // for this shared memory descriptor, then just return a pointer to
+ // the reference object.
+ //
+
+ ListHead = &Process->SharedMemoryList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ MemoryProcessRef = CONTAINING_RECORD( ListNext,
+ OS2_SHARED_MEMORY_PROCESS_REF,
+ Link
+ );
+ if (MemoryProcessRef->SharedMemoryObject == MemoryObject) {
+ ++MemoryProcessRef->RefCount;
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: Pid: %lX - MemoryRefObject (%lX) ->BaseAddress = %lX Count = %ld\n",
+ Process->ProcessId,
+ MemoryProcessRef,
+ MemoryProcessRef->SharedMemoryObject->BaseAddress,
+ MemoryProcessRef->RefCount
+ );
+ }
+#endif
+ return( MemoryProcessRef );
+ }
+
+ ListNext = ListNext->Flink;
+ }
+
+ //
+ // Process is attaching to this shared memory for the first time, so
+ // allocated the shared memory reference object and fill it in. Return
+ // NULL if unable to allocate the space. Otherwise, append to the
+ // list reference objects pointed to by the specified process and
+ // increment the reference count in the shared memory object descriptor.
+ //
+
+ MemoryProcessRef = RtlAllocateHeap( Os2Heap, 0, sizeof( *MemoryProcessRef ) );
+ if (MemoryProcessRef == NULL) {
+ return( NULL );
+ }
+ MemoryProcessRef->SharedMemoryObject = MemoryObject;
+ MemoryProcessRef->RefCount = 1;
+ MemoryProcessRef->AllocationFlags = 0;
+
+ InsertTailList( &Process->SharedMemoryList, &MemoryProcessRef->Link );
+
+ //
+ // Count the number of processes that contain pointers to this shared
+ // memory object descriptor.
+ //
+
+ ++MemoryObject->RefCount;
+
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: Pid: %lX - MemoryRefObject (%lX) ->BaseAddress = %lX Count = %ld\n",
+ Process->ProcessId,
+ MemoryProcessRef,
+ MemoryObject->BaseAddress,
+ MemoryProcessRef->RefCount
+ );
+ DbgPrint( " MemoryObject (%lX) ->RefCount = %ld\n",
+ MemoryObject,
+ MemoryObject->RefCount
+ );
+ }
+#endif
+
+ //
+ // Return a pointer to the shared memory reference object.
+ //
+
+ return( MemoryProcessRef );
+}
+
+
+BOOLEAN
+Os2FreeProcessRefToSharedMemory(
+ IN POS2_PROCESS Process,
+ IN POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef
+ )
+/*++
+
+Routine Description:
+
+ This function frees a process's reference to a shared memory object.
+ It does so by first decrementing the count of the number of references
+ the process has made to the shared memory object and if the count goes
+ to zero, it removes the shared memory reference object from the list
+ pointed to by the referencing process, frees the shared memory reference object and
+ then decrements the reference count in the shared memory object descriptor
+ pointed to by this reference object. If that reference count goes to
+ zero then free the shared memory object descriptor as well.
+
+ This function must be called within the scope of the
+ ProcessStructureLock.
+
+Arguments:
+
+ MemoryProcessRef - points to the shared memory reference object to free.
+
+Return Value:
+
+ Boolean value, where TRUE means that this was the last reference for
+ the process to this shared memory object and that the process's view
+ of the shared memory can thus be unmapped. Returns FALSE if the
+ reference count for this shared memory reference object is still not
+ zero.
+
+--*/
+
+{
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+
+ //
+ // Decrement the reference count for the process.
+ //
+
+ if (--MemoryProcessRef->RefCount == 0) {
+ //
+ // If the count goes to zero, then remove the reference object from
+ // its list and return the space occupied by the reference object
+ // to the heap.
+ //
+
+ MemoryObject = MemoryProcessRef->SharedMemoryObject;
+
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: Pid: %lX - freeing MemoryRefObject (%lX) ->BaseAddress = %lX Count = %ld\n",
+ Process->ProcessId,
+ MemoryProcessRef,
+ MemoryObject->BaseAddress,
+ MemoryProcessRef->RefCount
+ );
+ DbgPrint( " MemoryObject (%lX) ->RefCount = %ld\n",
+ MemoryObject,
+ MemoryObject->RefCount
+ );
+ }
+#endif
+
+ RemoveEntryList( &MemoryProcessRef->Link );
+ RtlFreeHeap( Os2Heap, 0, MemoryProcessRef );
+
+ //
+ // Decrement the reference count in the shared memory object descriptor
+ // pointed to by the reference object just freed. If the count goes
+ // to zero then free the shared memory object descriptor.
+ //
+
+ if (--MemoryObject->RefCount == 0) {
+
+ ldrFreeSel(MemoryObject->Index,
+ (MemoryObject->RegionSize + (_64K - 1)) / _64K
+ );
+
+ Os2FreeSharedMemoryObject( MemoryObject );
+ }
+
+ //
+ // Return TRUE to indicate to caller that the process no longer
+ // has a reference object for the shared memory object descriptor.
+ //
+
+ return( TRUE );
+ }
+ else {
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: Pid: %lX - decrementing MemoryRefObject (%lX) ->BaseAddress = %lX Count = %ld\n",
+ Process->ProcessId,
+ MemoryProcessRef,
+ MemoryProcessRef->SharedMemoryObject->BaseAddress,
+ MemoryProcessRef->RefCount
+ );
+ }
+#endif
+
+ //
+ // Return FALSE to indicate to caller that the process still has
+ // a reference object for the shared memory object descriptor.
+ //
+
+ return( FALSE );
+ }
+}
+
+
+VOID
+Os2FreeAllSharedMemoryForProcess(
+ IN POS2_PROCESS Process
+ )
+/*++
+
+Routine Description:
+
+ This function is called during process termination to free all
+ shared memory reference objects for the specified process.
+
+ This function must be called within the scope of the
+ ProcessStructureLock.
+
+Arguments:
+
+ Process - points to an OS/2 process structure that is the process
+ that is terminating.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
+
+ //
+ // Walk the list of shared memory reference objects for this process
+ // and free each one. Force the free by setting the reference count
+ // in the reference object to 1.
+ //
+
+ ListHead = &Process->SharedMemoryList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ MemoryProcessRef = CONTAINING_RECORD( ListNext,
+ OS2_SHARED_MEMORY_PROCESS_REF,
+ Link
+ );
+ ListNext = ListNext->Flink;
+ MemoryProcessRef->RefCount = 1;
+#if DBG
+ IF_OS2_DEBUG( CLEANUP ) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosFreeMem( %lX )\n",
+ Process->ProcessId,
+ MemoryProcessRef->SharedMemoryObject->BaseAddress
+ );
+ }
+#endif
+
+ Os2FreeProcessRefToSharedMemory( Process, MemoryProcessRef );
+ }
+
+ return;
+}
+
+
+POS2_SHARED_MEMORY_OBJECT
+Os2FindSharedMemoryObject(
+ IN PVOID BaseAddress,
+ IN POS2_PROCESS Process
+ )
+/*++
+
+Routine Description:
+
+ This function searchs the global list of shared memory object descriptors
+ to see if the passed base address is described by one of them.
+
+ This function must be called within the scope of the
+ ProcessStructureLock.
+
+Arguments:
+
+ BaseAddress - Supplies the base address of the shared memory we are
+ looking for.
+
+ Process - Optional pointer to the process that will be used to restrict
+ the search. If specified, this function succeeds only if the process
+ has a reference outstanding to the shared memory.
+
+Return Value:
+
+ Pointer to the shared memory object descriptor if found or NULL if
+ not found.
+
+--*/
+
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+ POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
+
+ if (ARGUMENT_PRESENT( Process )) {
+ //
+ // Search the list of shared memory reference objects for the
+ // specified process. If a shared memory reference object is found
+ // for this shared memory descriptor, then just return a pointer to
+ // the shared memory object descriptor.
+ //
+
+ ListHead = &Process->SharedMemoryList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ MemoryProcessRef = CONTAINING_RECORD( ListNext,
+ OS2_SHARED_MEMORY_PROCESS_REF,
+ Link
+ );
+ MemoryObject = MemoryProcessRef->SharedMemoryObject;
+ if (MemoryObject->BaseAddress == BaseAddress) {
+ return( MemoryObject );
+ }
+
+ ListNext = ListNext->Flink;
+ }
+
+ return( NULL );
+ }
+
+ ListHead = &Os2SharedMemoryList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ MemoryObject = CONTAINING_RECORD( ListNext,
+ OS2_SHARED_MEMORY_OBJECT,
+ Link
+ );
+ if (MemoryObject->BaseAddress == BaseAddress) {
+ return( MemoryObject );
+ }
+
+ ListNext = ListNext->Flink;
+ }
+
+ return( NULL );
+}
+
+
+POS2_SHARED_MEMORY_OBJECT
+Os2FindNamedSharedMemoryObject(
+ PSTRING SecName
+ )
+/*++
+
+Routine Description:
+
+ This function searchs the global list of shared memory object descriptors
+ to see if the passed shared memory name is described by one of them.
+
+ This function must be called within the scope of the
+ ProcessStructureLock.
+
+Arguments:
+
+ SecName - Supplies the name of the shared memory we are
+ looking for.
+
+
+Return Value:
+
+ Pointer to the shared memory object descriptor if found or NULL if
+ not found.
+
+--*/
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+
+ //
+ // find a shared memory object with the desired name
+ //
+
+ ListHead = &Os2SharedMemoryList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ MemoryObject = CONTAINING_RECORD(ListNext, OS2_SHARED_MEMORY_OBJECT, Link);
+ if (MemoryObject->SectionName.Buffer != NULL) {
+ if (RtlEqualString(&MemoryObject->SectionName, SecName, TRUE)) {
+ return (MemoryObject);
+ }
+ }
+ ListNext = ListNext->Flink;
+ }
+ return(NULL);
+}
+
+
+APIRET
+Os2MapViewOfSharedMemoryObject(
+ POS2_SHARED_MEMORY_OBJECT MemoryObject,
+ POS2_PROCESS Process,
+ BOOLEAN ProcessIsSelf,
+ ULONG RequiredAccess,
+ ULONG Protection
+ )
+/*++
+
+Routine Description:
+
+ This function maps a view of the specified memory object into the
+ specified process. Creates a shared memory reference object to
+ keep track of the reference.
+
+ This function must be called within the scope of the
+ ProcessStructureLock.
+
+Arguments:
+
+ MemoryObject - Points to the shared memory object descriptor that
+ describes the shared memory being mapped.
+
+ Process - points to an OS/2 process structure that is the process
+ that is to receive the mapped view of the shared memory.
+
+ ProcessIsSelf - boolean parameter that specifies that the calling
+ application process is manipulating his own address.
+
+ RequiredAccess - one or neither of the following flags:
+
+ OBJ_GETTABLE and/or OBJ_GIVEABLE
+
+ if neither is set, access if always granted.
+
+ Protection - specifies the NT Page level protection for pages in
+ this view of the shared memory object.
+
+Return Value:
+
+ OS/2 Error code or NO_ERROR if successful.
+
+--*/
+{
+ APIRET rc;
+ NTSTATUS Status;
+ MEMORY_BASIC_INFORMATION MemoryInformation;
+ PVOID BaseAddress = NULL;
+ ULONG RegionSize = 0;
+ ULONG OldProtection;
+ ULONG OldFlags, NewFlags;
+ POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
+
+ //
+ // Return access denied if gettable bits. Must be consistent with
+ // how the shared memory object was created. So:
+ //
+ // - if named shared memory, can only get by name.
+ // - if unnamed shared memory, can only give and/or get.
+ //
+
+ RequiredAccess &= (OBJ_GIVEABLE | OBJ_GETTABLE);
+ if (RequiredAccess != 0 &&
+ (MemoryObject->AllocationFlags & RequiredAccess) == 0
+ ) {
+ return( ERROR_ACCESS_DENIED );
+ }
+
+
+ rc = Or2MapProtectionToFlags( Protection, &NewFlags );
+ if (rc != NO_ERROR) {
+ return( rc );
+ }
+
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: MapSharedMem( ToPid=%lX ) - MemoryObject (%lX)->BaseAddress = %lX\n",
+ Process->ProcessId,
+ MemoryObject,
+ MemoryObject->BaseAddress
+ );
+ }
+#endif
+
+ //
+ // Create a shared memory reference object for this process and
+ // shared memory object descriptor.
+ //
+
+ MemoryProcessRef = Os2CreateProcessRefToSharedMemory( Process,
+ MemoryObject
+ );
+ //
+ // If unsuccessful, free the shared memory object descriptor if newly
+ // created by caller and return an error code.
+ //
+
+ if (MemoryProcessRef == NULL) {
+ if (MemoryObject->RefCount == 0) {
+ ldrFreeSel(
+ MemoryObject->Index,
+ (MemoryObject->RegionSize + (_64K - 1)) / _64K
+ );
+ Os2FreeSharedMemoryObject( MemoryObject );
+ }
+
+ return( ERROR_NOT_ENOUGH_MEMORY );
+ }
+
+ //
+ // Assume success and attempt to map a view of the shared memory
+ // into the specified process's address space.
+ //
+
+ rc = NO_ERROR;
+ BaseAddress = MemoryObject->BaseAddress;
+ Status = NtMapViewOfSection( MemoryObject->SectionHandle,
+ Process->ProcessHandle,
+ &BaseAddress,
+ 0,
+ 0,
+ NULL,
+ &RegionSize,
+ ViewUnmap,
+ 0,
+ Protection
+ );
+
+ //
+ // If unsuccessful, special logic.
+ //
+
+ if (!NT_SUCCESS( Status )) {
+ if (Status == STATUS_CONFLICTING_ADDRESSES &&
+ (ProcessIsSelf || MemoryProcessRef->RefCount > 1)
+ ) {
+ //
+ // If reason for failure is already mapped, then change the
+ // page protection instead.
+ //
+
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: ProtectSharedMem( ToPid=%lX ) - MemoryObject (%lX)->BaseAddress = %lX Flags= %lX\n",
+ Process->ProcessId,
+ MemoryObject,
+ MemoryObject->BaseAddress,
+ Protection
+ );
+ }
+#endif
+
+
+
+ //
+ // First figure out how big the memory object is, and the page
+ // protection it was allocated with.
+ //
+
+ BaseAddress = MemoryObject->BaseAddress;
+ Status = NtQueryVirtualMemory( Process->ProcessHandle,
+ BaseAddress,
+ MemoryBasicInformation,
+ &MemoryInformation,
+ sizeof( MemoryInformation ),
+ NULL
+ );
+ if (NT_SUCCESS( Status ) && MemoryInformation.State != MEM_RESERVE) {
+ //
+ // New protection flags are the OR of the old and new flags.
+ //
+
+ rc = Or2MapProtectionToFlags( MemoryInformation.Protect,
+ &OldFlags
+ );
+ NewFlags |= OldFlags;
+
+ //
+ // Now change the page protection for those pages.
+ //
+
+ Or2MapFlagsToProtection( NewFlags, &Protection );
+ Status = NtProtectVirtualMemory( Process->ProcessHandle,
+ &BaseAddress,
+ &MemoryInformation.RegionSize,
+ Protection,
+ &OldProtection
+ );
+ }
+ }
+ else {
+ //
+ // Not already mapped, so free the shared memory reference
+ // object we created.
+ //
+
+ Os2FreeProcessRefToSharedMemory( Process, MemoryProcessRef );
+ }
+
+ //
+ // If unsuccessful, map status code.
+ //
+
+ if (!NT_SUCCESS( Status )) {
+ switch (Status) {
+ case STATUS_OBJECT_NAME_COLLISION:
+ rc = ERROR_ALREADY_EXISTS;
+ break;
+
+ default:
+ rc = Or2MapNtStatusToOs2Error(Status, ERROR_ALREADY_EXISTS);
+ }
+ }
+ }
+
+ if (rc == NO_ERROR) {
+ MemoryProcessRef->AllocationFlags |= NewFlags;
+ }
+
+ //
+ // Return OS/2 error code.
+ //
+
+ return( rc );
+}
+
+
+typedef enum _LDTENTRY_TYPE {
+ INVALID, EXECUTE_CODE, EXECUTE_READ_CODE, READ_DATA, READ_WRITE_DATA
+} LDTENTRY_TYPE;
+
+
+NTSTATUS
+Os2SetLDT
+ (
+ HANDLE Process,
+ LDTENTRY_TYPE Type,
+ PVOID BaseAddress,
+ ULONG Limit
+ )
+{
+ /* Descriptor definition */
+
+ struct desctab {
+ USHORT d_limit; /* Segment limit */
+ USHORT d_loaddr; /* Low word of physical address */
+ UCHAR d_hiaddr; /* High byte of physical address */
+ UCHAR d_access; /* Access byte */
+ UCHAR d_attr; /* Attributes/extended limit */
+ UCHAR d_extaddr; /* Extended physical address byte */
+ } *LDTDesc;
+ PULONG tmp;
+ PROCESS_LDT_INFORMATION LdtInformation;
+ NTSTATUS Status;
+ ULONG Sel = FLATTOSEL(BaseAddress);
+
+ LDTDesc = (struct desctab *)(&LdtInformation.LdtEntries[0]);
+ tmp = (PULONG)(LDTDesc);
+ //
+ // zero the descriptor
+ //
+ *tmp++ = 0;
+ *tmp = 0;
+
+ switch (Type) {
+
+ case INVALID:
+ break;
+
+ case READ_WRITE_DATA:
+ LDTDesc->d_access = 0xf3; // read/write, present, ring 3
+ LDTDesc->d_limit = (USHORT)(Limit);
+ LDTDesc->d_loaddr = (USHORT)((ULONG)BaseAddress & 0xffff);
+ LDTDesc->d_hiaddr = (UCHAR)(((ULONG)BaseAddress >> 16) & 0xff);
+ LDTDesc->d_extaddr = (UCHAR)(((ULONG)BaseAddress >> 24) & 0xff);
+ break;
+
+ default:
+ {
+#if DBG
+ DbgPrint ("OS2SRV: Os2SetLDT - Invalid type request\n");
+#endif
+ return (STATUS_INVALID_PARAMETER);
+ }
+ }
+ //
+ // adjust LDTDesc by the LDT base and the index of this selector
+ //
+
+ LdtInformation.Length = sizeof(LDT_ENTRY);
+ LdtInformation.Start = Sel & 0xfffffff8;
+ Status = NtSetInformationProcess( Process,
+ ProcessLdtInformation,
+ &LdtInformation,
+ sizeof(PROCESS_LDT_INFORMATION)
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("OS2SRV: Os2SetLDT - Invalid request, status=%x\n", Status);
+#endif
+ return (Status);
+ }
+
+ return (STATUS_SUCCESS);
+}
+
+// This function remove memory object, but not remove LDT entry.
+
+ULONG Os2FreeMemory(
+ IN POS2_THREAD t,
+ PVOID BaseAddress,
+ PBOOLEAN pUnmapped
+ )
+{
+ NTSTATUS Status;
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
+ ULONG ReturnedErrorValue = ERROR_INVALID_ADDRESS;
+
+ *pUnmapped = FALSE;
+
+ ListHead = &t->Process->SharedMemoryList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ MemoryProcessRef = CONTAINING_RECORD( ListNext,
+ OS2_SHARED_MEMORY_PROCESS_REF,
+ Link
+ );
+ ListNext = ListNext->Flink;
+ if (MemoryProcessRef->SharedMemoryObject->BaseAddress == BaseAddress ) {
+ ReturnedErrorValue = NO_ERROR;
+
+ //
+ // Force free if unnamed shared memory. Otherwise only free if
+ // this is last reference to named shared memory by this process.
+ //
+
+ if (MemoryProcessRef->SharedMemoryObject->SectionName.Buffer == NULL) {
+ MemoryProcessRef->RefCount = 1;
+ }
+
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: Pid: %lX - Os2FreeMememory( %lX ) - MemoryRefObject = %lX Count = %ld\n",
+ t->Process->ProcessId,
+ BaseAddress,
+ MemoryProcessRef,
+ MemoryProcessRef->RefCount
+ );
+ }
+#endif
+
+ if (Os2FreeProcessRefToSharedMemory( t->Process, MemoryProcessRef )) {
+ Status = NtUnmapViewOfSection( t->Process->ProcessHandle,
+ BaseAddress
+ );
+ if (!NT_SUCCESS( Status )) {
+ switch (Status) {
+ case STATUS_OBJECT_NAME_COLLISION:
+ ReturnedErrorValue = ERROR_ALREADY_EXISTS;
+ break;
+
+ default:
+ ReturnedErrorValue = Or2MapNtStatusToOs2Error(Status, ERROR_ALREADY_EXISTS);
+ }
+ }
+ *pUnmapped = TRUE;
+ }
+
+ break;
+ }
+ }
+
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ if (ReturnedErrorValue != NO_ERROR) {
+ DbgPrint( "OS2SRV: Pid: %lX - Os2FreeMemory( %lX ) - failed, rc = %ld\n",
+ t->Process->ProcessId,
+ BaseAddress,
+ ReturnedErrorValue
+ );
+ }
+ }
+#endif
+
+ return( ReturnedErrorValue );
+}
+
+// Remove memory object and LDT entry if the client process ask for the last
+// service.
+
+BOOLEAN Os2DosFreeMem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSFREEMEM_MSG a = &m->u.DosFreeMem;
+ BOOLEAN Unmapped;
+ NTSTATUS Status;
+
+ m->ReturnedErrorValue = Os2FreeMemory(t, a->BaseAddress, &Unmapped);
+
+ if (Unmapped && a->RemoveLDTEntry && (m->ReturnedErrorValue == NO_ERROR)) {
+
+ Status = Os2SetLDT(
+ t->Process->ProcessHandle,
+ INVALID,
+ a->BaseAddress,
+ 0L);
+
+ if (!NT_SUCCESS(Status)) {
+ m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
+ }
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN Os2DosGiveSharedMem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSGIVESHAREDMEM_MSG a = &m->u.DosGiveSharedMem;
+ POS2_PROCESS Process;
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+ NTSTATUS Status;
+ MEMORY_BASIC_INFORMATION MemoryInformation;
+
+ Process = Os2LocateProcessByProcessId( m,
+ t->Process,
+ a->ProcessId,
+ FALSE
+ );
+ if (Process == NULL) {
+ return( TRUE );
+ }
+
+ MemoryObject = Os2FindSharedMemoryObject( a->BaseAddress, t->Process );
+ if (MemoryObject != NULL) {
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosGiveMem( %lX, ToPid=%lX ) - MemoryObject = %lX\n",
+ t->Process->ProcessId,
+ a->BaseAddress,
+ Process->ProcessId,
+ MemoryObject
+ );
+ }
+#endif
+
+ m->ReturnedErrorValue =
+ Os2MapViewOfSharedMemoryObject( MemoryObject,
+ Process,
+ (BOOLEAN)(t->Process == Process),
+ OBJ_GIVEABLE,
+ a->PageProtection
+ );
+ }
+ else {
+ Status = NtQueryVirtualMemory( t->Process->ProcessHandle,
+ a->BaseAddress,
+ MemoryBasicInformation,
+ &MemoryInformation,
+ sizeof( MemoryInformation ),
+ NULL
+ );
+ if (NT_SUCCESS( Status ) && MemoryInformation.State == MEM_PRIVATE) {
+ m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
+ }
+ else {
+ m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
+ }
+ }
+
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ if (m->ReturnedErrorValue != NO_ERROR) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosGiveMem( %lX, ToPid=%lX ) - failed, rc = %ld\n",
+ t->Process->ProcessId,
+ a->BaseAddress,
+ Process->ProcessId,
+ m->ReturnedErrorValue
+ );
+ }
+ }
+#endif
+
+ return( TRUE );
+}
+
+
+BOOLEAN Os2DosGetSharedMem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSGETSHAREDMEM_MSG a = &m->u.DosGetSharedMem;
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+
+ MemoryObject = Os2FindSharedMemoryObject( a->BaseAddress, NULL );
+ if (MemoryObject != NULL) {
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosGetMem( %lX ) - MemoryObject = %lX\n",
+ t->Process->ProcessId,
+ a->BaseAddress,
+ MemoryObject
+ );
+ }
+#endif
+
+ m->ReturnedErrorValue =
+ Os2MapViewOfSharedMemoryObject( MemoryObject,
+ t->Process,
+ TRUE,
+ OBJ_GETTABLE,
+ a->PageProtection
+ );
+ }
+ else {
+ m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
+ }
+
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ if (m->ReturnedErrorValue != NO_ERROR) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosGetMem( %lX ) - failed, rc = %ld\n",
+ t->Process->ProcessId,
+ a->BaseAddress,
+ m->ReturnedErrorValue
+ );
+ }
+ }
+#endif
+
+ return( TRUE );
+}
+
+
+BOOLEAN Os2DosGetNamedSharedMem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSGETNAMEDSHAREDMEM_MSG a = &m->u.DosGetNamedSharedMem;
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+
+ if (a->ObjectName.Buffer == NULL) {
+ m->ReturnedErrorValue = ERROR_INVALID_PARAMETER;
+ return( TRUE );
+ }
+
+ MemoryObject = Os2FindNamedSharedMemoryObject (&a->ObjectName);
+ if (MemoryObject == NULL) {
+ m->ReturnedErrorValue = ERROR_FILE_NOT_FOUND;
+ return(TRUE);
+ }
+
+ a->BaseAddress = MemoryObject->BaseAddress;
+ MemoryObject = Os2FindSharedMemoryObject( a->BaseAddress, NULL );
+
+ if (MemoryObject != NULL) {
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosGetNamedSharedMem( %Z ) - MemoryObject (%lX)->BaseAddress = %lX\n",
+ t->Process->ProcessId,
+ &a->ObjectName,
+ MemoryObject,
+ MemoryObject->BaseAddress
+ );
+ }
+#endif
+
+ m->ReturnedErrorValue =
+ Os2MapViewOfSharedMemoryObject( MemoryObject,
+ t->Process,
+ TRUE,
+ 0,
+ a->PageProtection
+ );
+ }
+ else {
+ m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
+ }
+
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ if (m->ReturnedErrorValue != NO_ERROR) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosGetNamedSharedMem( %Z ) - failed, rc = %ld\n",
+ t->Process->ProcessId,
+ &a->ObjectName,
+ m->ReturnedErrorValue
+ );
+ }
+ }
+#endif
+
+ return( TRUE );
+}
+
+
+BOOLEAN Os2DosAllocSharedMem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSALLOCSHAREDMEM_MSG a = &m->u.DosAllocSharedMem;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE SectionHandle;
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+ ULONG AllocationAttributes;
+ UNICODE_STRING ObjectName_U;
+ LARGE_INTEGER SectionSize;
+ PVOID BaseAddress;
+ ULONG Index;
+ ULONG ReserveSize;
+
+ // Resurve 64K for the non-huge segment. For the huge segment resurve
+ // the amount that the client asks.
+
+ ReserveSize = a->RegionSize < _64K ? _64K : a->RegionSize;
+
+ InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
+ if (a->ObjectName.Buffer != NULL) {
+ //
+ // UNICODE conversion -
+ //
+ Status = Or2MBStringToUnicodeString(
+ &ObjectName_U,
+ &a->ObjectName,
+ TRUE);
+ ASSERT (NT_SUCCESS(Status));
+
+ ObjectAttributes.ObjectName = &ObjectName_U;
+ }
+
+ if (a->Flags & PAG_COMMIT) {
+ AllocationAttributes = SEC_COMMIT;
+ }
+ else {
+ AllocationAttributes = SEC_RESERVE;
+ }
+
+ SectionSize.LowPart = ReserveSize;
+ SectionSize.HighPart = 0;
+ Status = NtCreateSection( &SectionHandle,
+ SECTION_ALL_ACCESS,
+ &ObjectAttributes,
+ &SectionSize,
+ PAGE_EXECUTE_READWRITE,
+ AllocationAttributes,
+ NULL
+ );
+
+ if (a->ObjectName.Buffer != NULL) {
+ RtlFreeUnicodeString (&ObjectName_U);
+ }
+
+ if (!NT_SUCCESS( Status )) {
+ switch (Status) {
+ case STATUS_OBJECT_NAME_COLLISION:
+ m->ReturnedErrorValue = ERROR_ALREADY_EXISTS;
+ break;
+
+ default:
+ m->ReturnedErrorValue = Or2MapNtStatusToOs2Error(Status, ERROR_ALREADY_EXISTS);
+ }
+ return( TRUE );
+ }
+
+ Index = ldrAllocateSel((a->RegionSize + (_64K - 1)) / _64K,
+ TRUE // Top down allocation
+ );
+
+ if (Index == 0xffffffff) {
+ // selector allocation failed
+ NtClose( SectionHandle );
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ return( TRUE );
+ }
+
+ BaseAddress = SELTOFLAT(Index);
+ a->BaseAddress = BaseAddress;
+
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosAllocSharedMem( %s, %ld ), BaseAddress = %lX\n",
+ t->Process->ProcessId,
+ ObjectAttributes.ObjectName ? a->ObjectName.Buffer : "(null)",
+ ReserveSize,
+ a->BaseAddress
+ );
+ }
+#endif
+
+ MemoryObject = Os2CreateSharedMemoryObject( m,
+ a->BaseAddress,
+ Index,
+ ReserveSize,
+ SectionHandle,
+ a->Flags,
+ &a->ObjectName
+ );
+ if (MemoryObject != NULL) {
+ m->ReturnedErrorValue =
+ Os2MapViewOfSharedMemoryObject( MemoryObject,
+ t->Process,
+ TRUE,
+ 0,
+ a->PageProtection
+ );
+ }
+
+ if (m->ReturnedErrorValue != NO_ERROR) {
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosAllocSharedMem( %s, %ld ) - failed, rc = %ld\n",
+ t->Process->ProcessId,
+ ObjectAttributes.ObjectName ? a->ObjectName.Buffer : "(null)",
+ a->RegionSize,
+ m->ReturnedErrorValue
+ );
+ }
+#endif
+
+ NtClose( SectionHandle );
+ }
+ else {
+ // Memory was allocated successfully
+
+ if (a->CreateLDTEntry) {
+
+ BOOLEAN Unmapped;
+
+ Status = Os2SetLDT(
+ t->Process->ProcessHandle,
+ READ_WRITE_DATA,
+ BaseAddress,
+ a->RegionSize - 1);
+
+ if (!NT_SUCCESS(Status)) {
+ Os2FreeMemory(t, BaseAddress, &Unmapped);
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+ }
+
+ return( TRUE );
+}
+
+BOOLEAN Os2InternalQueryVirtualMemory(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_QUERYVIRTUALMEMORY_MSG a = &m->u.QueryVirtualMemory;
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+
+ a->SharedMemory = FALSE;
+
+ ListHead = &t->Process->SharedMemoryList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ MemoryProcessRef = CONTAINING_RECORD( ListNext,
+ OS2_SHARED_MEMORY_PROCESS_REF,
+ Link
+ );
+ ListNext = ListNext->Flink;
+ if (MemoryProcessRef->SharedMemoryObject->BaseAddress == a->BaseAddress) {
+ MemoryObject = MemoryProcessRef->SharedMemoryObject;
+ a->SharedMemory = TRUE;
+ a->AllocationFlags = MemoryProcessRef->AllocationFlags;
+ a->IsHuge = MemoryObject->IsHuge;;
+ a->MaxSegments = MemoryObject->MaxSegments;
+ a->NumOfSegments = MemoryObject->NumOfSegments;
+ a->SizeOfPartialSeg = MemoryObject->SizeOfPartialSeg;
+ a->Sizeable = MemoryObject->Sizeable;
+ break;
+ }
+ }
+ return( TRUE );
+}
+
+BOOLEAN Os2InternalMarkSharedMemAsHuge(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_MARKSHAREDMEMASHUGE_MSG a = &m->u.MarkSharedMemAsHuge;
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+
+ //
+ // Find a shared memory object with the specified base address
+ // in the list of shared memory objects.
+ //
+
+ ListHead = &Os2SharedMemoryList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ MemoryObject = CONTAINING_RECORD( ListNext,
+ OS2_SHARED_MEMORY_OBJECT,
+ Link
+ );
+ if (MemoryObject->BaseAddress == a->BaseAddress) {
+ MemoryObject->IsHuge = TRUE;
+ MemoryObject->MaxSegments = a->MaxSegments;
+ MemoryObject->NumOfSegments = a->NumOfSegments;
+ MemoryObject->SizeOfPartialSeg = a->SizeOfPartialSeg;
+ MemoryObject->Sizeable = a->Sizeable;
+ m->ReturnedErrorValue = NO_ERROR;
+ return( TRUE );
+ }
+
+ ListNext = ListNext->Flink;
+ }
+
+ m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
+ return( TRUE );
+}
+
+
+APIRET Os2CopyLDT(
+ HANDLE SourceProcessHandle,
+ HANDLE TargetProcessHandle,
+ ULONG Index,
+ ULONG NumOfEntriesToCopy
+)
+{
+ PROCESS_LDT_INFORMATION LdtInfo;
+ struct desctab {
+ USHORT d_limit; /* Segment limit */
+ USHORT d_loaddr; /* Low word of physical address */
+ UCHAR d_hiaddr; /* High byte of physical address */
+ UCHAR d_access; /* Access byte */
+ UCHAR d_attr; /* Attributes/extended limit */
+ UCHAR d_extaddr; /* Extended physical address byte */
+ } *LDTDesc;
+ NTSTATUS Status;
+ ULONG i;
+
+ //
+ // get source LDT entry
+ //
+ LDTDesc = (struct desctab *)(&LdtInfo.LdtEntries[0]);
+ for (i = 0; i < NumOfEntriesToCopy; i++) {
+ LdtInfo.Length = sizeof(LDT_ENTRY);
+ LdtInfo.Start = (Index + (i*8)) & 0xfffffff8;
+ Status = NtQueryInformationProcess(
+ SourceProcessHandle,
+ ProcessLdtInformation,
+ &LdtInfo,
+ sizeof(PROCESS_LDT_INFORMATION),
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("Os2DosCopySeg NtQueryInformationProcess failed. \n");
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+ //
+ // Copy of a non huge entry should always be for a valid segment
+ //
+ if ((i == 0) && ((LDTDesc->d_access & 0x80) != 0x80)) {
+ return(ERROR_INVALID_SEGMENT_NUMBER);
+ }
+ //
+ // Update The Target LDT
+ //
+ LdtInfo.Length = sizeof(LDT_ENTRY);
+ LdtInfo.Start = (Index + (i*8)) & 0xfffffff8;
+ Status = NtSetInformationProcess(
+ TargetProcessHandle,
+ ProcessLdtInformation,
+ &LdtInfo,
+ sizeof(PROCESS_LDT_INFORMATION)
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("Os2DosReallocSharedMem NtSetInformationProcess failed. %lx\n",
+ Status);
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+ }
+ return(NO_ERROR);
+}
+
+
+BOOLEAN Os2DosGiveSeg(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_GIVESEG_MSG a = &m->u.DosGiveSeg;
+ POS2_PROCESS Process;
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+ NTSTATUS Status;
+ MEMORY_BASIC_INFORMATION MemoryInformation;
+ PVOID BaseAddress;
+ ULONG EntriesToCopy;
+
+ m->ReturnedErrorValue = NO_ERROR;
+
+ Process = Os2LocateProcessByProcessId( m,
+ t->Process,
+ a->TargetPid,
+ FALSE
+ );
+ if (Process == NULL) {
+ m->ReturnedErrorValue = ERROR_INVALID_PARAMETER;
+ return( TRUE );
+ }
+
+ BaseAddress = SELTOFLAT((a->Selector));
+
+ MemoryObject = Os2FindSharedMemoryObject( BaseAddress, t->Process );
+ if (MemoryObject != NULL) {
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosGiveSeg( %lX, ToPid=%lX ) - MemoryObject = %lX\n",
+ t->Process->ProcessId,
+ BaseAddress,
+ Process->ProcessId,
+ MemoryObject
+ );
+ }
+#endif
+
+ Status = NtQueryVirtualMemory( t->Process->ProcessHandle,
+ BaseAddress,
+ MemoryBasicInformation,
+ &MemoryInformation,
+ sizeof( MemoryInformation ),
+ NULL
+ );
+
+ if (!NT_SUCCESS( Status )){
+ m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
+ return( TRUE );
+ }
+
+ m->ReturnedErrorValue =
+ Os2MapViewOfSharedMemoryObject(
+ MemoryObject,
+ Process,
+ (BOOLEAN)(t->Process == Process),
+ OBJ_GIVEABLE,
+ MemoryInformation.Protect
+ );
+ }
+ else {
+ Status = NtQueryVirtualMemory( t->Process->ProcessHandle,
+ BaseAddress,
+ MemoryBasicInformation,
+ &MemoryInformation,
+ sizeof( MemoryInformation ),
+ NULL
+ );
+ if (NT_SUCCESS( Status ) && MemoryInformation.State == MEM_PRIVATE) {
+ m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
+ }
+ else {
+ m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
+ }
+ }
+
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ if (m->ReturnedErrorValue != NO_ERROR) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosGiveMem( %lX, ToPid=%lX ) - failed, rc = %ld\n",
+ t->Process->ProcessId,
+ BaseAddress,
+ Process->ProcessId,
+ m->ReturnedErrorValue
+ );
+ }
+ }
+#endif
+ if (m->ReturnedErrorValue == NO_ERROR) {
+ if (MemoryObject->IsHuge) {
+ if (MemoryObject->MaxSegments != 0)
+ EntriesToCopy = MemoryObject->MaxSegments;
+ else {
+ EntriesToCopy = MemoryObject->NumOfSegments;
+ if (MemoryObject->SizeOfPartialSeg) {
+ ++EntriesToCopy;
+ }
+ }
+ }
+ else
+ EntriesToCopy = 1;
+
+
+ m->ReturnedErrorValue = Os2CopyLDT(
+ t->Process->ProcessHandle,
+ Process->ProcessHandle,
+ a->Selector,
+ EntriesToCopy
+ );
+ }
+
+ return( TRUE );
+}
+
+
+BOOLEAN Os2DosGetSeg(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ PLIST_ENTRY ProcListHead, ProcListNext;
+ POS2_GETSEG_MSG a = &m->u.DosGetSeg;
+ POS2_PROCESS ProcessRef;
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+ PVOID BaseAddress;
+ MEMORY_BASIC_INFORMATION MemoryInformation;
+ BOOLEAN found;
+ NTSTATUS Status;
+ ULONG Index;
+ ULONG EntriesToCopy;
+ PROCESS_LDT_INFORMATION LdtInfo;
+ struct desctab {
+ USHORT d_limit; /* Segment limit */
+ USHORT d_loaddr; /* Low word of physical address */
+ UCHAR d_hiaddr; /* High byte of physical address */
+ UCHAR d_access; /* Access byte */
+ UCHAR d_attr; /* Attributes/extended limit */
+ UCHAR d_extaddr; /* Extended physical address byte */
+ } *LDTDesc;
+
+ BaseAddress = SELTOFLAT(a->Selector);
+
+ MemoryObject = Os2FindSharedMemoryObject( BaseAddress, NULL );
+ if (MemoryObject != NULL) {
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosGetSeg( %lX ) - MemoryObject = %lX\n",
+ t->Process->ProcessId,
+ BaseAddress,
+ MemoryObject
+ );
+ }
+#endif
+ Index = FLATTOSEL(BaseAddress);
+ //
+ // find a process that owns this segment.
+ //
+ found = FALSE;
+ ProcListHead = &Os2RootProcess->ListLink;
+ ProcListNext = ProcListHead->Flink;
+ while (ProcListNext != ProcListHead) {
+
+ ProcessRef = CONTAINING_RECORD( ProcListNext,
+ OS2_PROCESS,
+ ListLink
+ );
+
+ // get LDT entry
+
+ LdtInfo.Length = sizeof(LDT_ENTRY);
+ LdtInfo.Start = Index & 0xfffffff8;
+ LDTDesc = (struct desctab *)(&LdtInfo.LdtEntries[0]);
+ Status = NtQueryInformationProcess(
+ ProcessRef->ProcessHandle,
+ ProcessLdtInformation,
+ &LdtInfo,
+ sizeof(PROCESS_LDT_INFORMATION),
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+ m->ReturnedErrorValue = ERROR_INVALID_PARAMETER;
+#if DBG
+ DbgPrint("Os2DosGetSeg NtQueryInformationProcess failed\n");
+#endif
+ return(TRUE);
+ }
+ if (LDTDesc->d_access & 0x80) {
+ Status = NtQueryVirtualMemory( ProcessRef->ProcessHandle,
+ BaseAddress,
+ MemoryBasicInformation,
+ &MemoryInformation,
+ sizeof( MemoryInformation ),
+ NULL
+ );
+ if ( NT_SUCCESS(Status) &&
+ ((MemoryInformation.Protect & PAGE_NOACCESS) != PAGE_NOACCESS)) {
+ found = TRUE;
+ break;
+ }
+ }
+ ProcListNext = ProcListNext->Flink;
+ } // process loop
+
+
+ if ((!NT_SUCCESS( Status )) || (!found)){
+ m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
+ return( TRUE );
+ }
+
+ m->ReturnedErrorValue =
+ Os2MapViewOfSharedMemoryObject( MemoryObject,
+ t->Process,
+ (BOOLEAN)(t->Process == ProcessRef),
+ OBJ_GETTABLE,
+ MemoryInformation.Protect
+ );
+ }
+ else {
+ m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
+ }
+
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ if (m->ReturnedErrorValue != NO_ERROR) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosGetMem( %lX ) - failed, rc = %ld\n",
+ t->Process->ProcessId,
+ BaseAddress,
+ m->ReturnedErrorValue
+ );
+ }
+ }
+#endif
+
+ if (m->ReturnedErrorValue == NO_ERROR) {
+
+ if (MemoryObject->IsHuge) {
+ if (MemoryObject->MaxSegments != 0)
+ EntriesToCopy = MemoryObject->MaxSegments;
+ else {
+ EntriesToCopy = MemoryObject->NumOfSegments;
+ if (MemoryObject->SizeOfPartialSeg) {
+ ++EntriesToCopy;
+ }
+ }
+ }
+ else
+ EntriesToCopy = 1;
+
+ m->ReturnedErrorValue = Os2CopyLDT(
+ ProcessRef->ProcessHandle,
+ t->Process->ProcessHandle,
+ a->Selector,
+ EntriesToCopy
+ );
+ }
+ return(TRUE);
+}
+
+BOOLEAN Os2DosGetShrSeg(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DOSGETSHRSEG_MSG a = &m->u.DosGetShrSeg;
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+ BOOLEAN Shared;
+ PLIST_ENTRY MemListHead, MemListNext, ProcListHead, ProcListNext;
+ POS2_PROCESS ProcessRef;
+ MEMORY_BASIC_INFORMATION MemoryInformation;
+ NTSTATUS Status;
+ POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
+
+ if (a->ObjectName.Buffer == NULL) {
+ m->ReturnedErrorValue = ERROR_INVALID_PARAMETER;
+ return( TRUE );
+ }
+
+ MemoryObject = Os2FindNamedSharedMemoryObject (&a->ObjectName);
+ if (MemoryObject == NULL) {
+ m->ReturnedErrorValue = ERROR_FILE_NOT_FOUND;
+ return(TRUE);
+ }
+
+ a->Selector = MemoryObject->Index;
+ MemoryObject = Os2FindSharedMemoryObject( SELTOFLAT(a->Selector), NULL );
+
+ Shared = FALSE;
+
+ if (MemoryObject != NULL) {
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosGetNamedSharedMem( %Z ) - MemoryObject (%lX)->BaseAddress = %lX\n",
+ t->Process->ProcessId,
+ &a->ObjectName,
+ MemoryObject,
+ MemoryObject->BaseAddress
+ );
+ }
+#endif
+
+ m->ReturnedErrorValue = NO_ERROR;
+
+
+ // Loop on all OS/2 Process
+
+ ProcListHead = &Os2RootProcess->ListLink;
+ ProcListNext = ProcListHead->Flink;
+ while (ProcListNext != ProcListHead) {
+
+ // Loop on all Shared Memory references of an OS/2 process
+
+ ProcessRef = CONTAINING_RECORD( ProcListNext,
+ OS2_PROCESS,
+ ListLink
+ );
+ MemListHead = &ProcessRef->SharedMemoryList;
+ MemListNext = MemListHead->Flink;
+ while (MemListNext != MemListHead){
+
+ MemoryProcessRef = CONTAINING_RECORD( MemListNext,
+ OS2_SHARED_MEMORY_PROCESS_REF,
+ Link
+ );
+
+
+ if (MemoryProcessRef->SharedMemoryObject == MemoryObject) {
+ Status = NtQueryVirtualMemory( ProcessRef->ProcessHandle,
+ MemoryObject->BaseAddress,
+ MemoryBasicInformation,
+ &MemoryInformation,
+ sizeof( MemoryInformation ),
+ NULL
+ );
+ if ( NT_SUCCESS(Status) &&
+ ((MemoryInformation.Protect & PAGE_NOACCESS) !=
+ PAGE_NOACCESS)) {
+ Shared = TRUE;
+ break;
+ }
+ }
+ MemListNext = MemListNext->Flink;
+ } // process memory objects loop
+ if (Shared) {
+ break;
+ }
+ ProcListNext = ProcListNext->Flink;
+ } // process loop
+ }
+ else {
+ m->ReturnedErrorValue = ERROR_INVALID_ADDRESS;
+ }
+ if (Shared) {
+ m->ReturnedErrorValue =
+ Os2MapViewOfSharedMemoryObject( MemoryObject,
+ t->Process,
+ TRUE,
+ 0,
+ MemoryInformation.Protect
+ );
+ }
+ if (m->ReturnedErrorValue == NO_ERROR) {
+ m->ReturnedErrorValue = Os2CopyLDT(
+ ProcessRef->ProcessHandle,
+ t->Process->ProcessHandle,
+ MemoryObject->Index,
+ 1
+ );
+ }
+
+#if DBG
+ IF_OS2_DEBUG( MEMORY ) {
+ if (m->ReturnedErrorValue != NO_ERROR) {
+ DbgPrint( "OS2SRV: Pid: %lX - DosGetShrSeg( %Z ) - failed, rc = %ld\n",
+ t->Process->ProcessId,
+ &a->ObjectName,
+ m->ReturnedErrorValue
+ );
+ }
+ }
+#endif
+
+ return( TRUE );
+}
+
+
+APIRET Os2ResizeSharedMemory(
+ HANDLE ProcessHandle,
+ PVOID AllocFreeBaseAddress, // start address of new allocation/free
+ ULONG Index, // Selector of resized segment
+ ULONG CurrentSize, // ldt limit rounded to pages
+ USHORT NewLdtLimit, // New segment size in bytes
+ ULONG NewRegionSize, // New segment size rounded to pages
+ ULONG Flags // Flags of new allocated memory
+)
+{
+ PVOID TmpAllocFreeBaseAddress;
+ PROCESS_LDT_INFORMATION LdtInfo;
+ struct desctab {
+ USHORT d_limit; /* Segment limit */
+ USHORT d_loaddr; /* Low word of physical address */
+ UCHAR d_hiaddr; /* High byte of physical address */
+ UCHAR d_access; /* Access byte */
+ UCHAR d_attr; /* Attributes/extended limit */
+ UCHAR d_extaddr; /* Extended physical address byte */
+ } *LDTDesc;
+ ULONG RegionSize;
+ NTSTATUS Status;
+ APIRET rc;
+ rc = NO_ERROR;
+ // according to the new size allocate/free memory
+
+ // get current LDT entry
+ LdtInfo.Length = sizeof(LDT_ENTRY);
+ LdtInfo.Start = Index & 0xfffffff8;
+ LDTDesc = (struct desctab *)(&LdtInfo.LdtEntries[0]);
+ Status = NtQueryInformationProcess(
+ ProcessHandle,
+ ProcessLdtInformation,
+ &LdtInfo,
+ sizeof(PROCESS_LDT_INFORMATION),
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("Os2DosReallocSharedMem NtQueryInformationProcess failed. \n");
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+ if ((LDTDesc->d_access & 0x80) == 0) {
+ return(ERROR_INVALID_SEGMENT_NUMBER); // This is an internal error code
+ // passed to the caller of this
+ // procedure to notify that the
+ // segment was not updated since
+ // it was not in use.
+ }
+
+
+ // Update The Segment Size in LDT
+
+ if (LDTDesc->d_limit != NewLdtLimit) {
+ LDTDesc->d_limit = NewLdtLimit;
+ LdtInfo.Length = sizeof(LDT_ENTRY);
+ LdtInfo.Start = Index & 0xfffffff8;
+ Status = NtSetInformationProcess(
+ ProcessHandle,
+ ProcessLdtInformation,
+ &LdtInfo,
+ sizeof(PROCESS_LDT_INFORMATION)
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("Os2DosReallocSharedMem NtSetInformationProcess failed. %lx\n",
+ Status);
+#endif
+ return(ERROR_INVALID_PARAMETER);
+ }
+ }
+ else
+ return(NO_ERROR);
+
+ if (CurrentSize < NewRegionSize) {
+ // alloc mem
+ RegionSize = NewRegionSize - CurrentSize;
+ TmpAllocFreeBaseAddress = AllocFreeBaseAddress;
+ Status = NtAllocateVirtualMemory(
+ ProcessHandle,
+ &TmpAllocFreeBaseAddress,
+ 1,
+ &RegionSize,
+ MEM_COMMIT,
+ Flags
+ );
+ if (NT_SUCCESS(Status) || (Status == STATUS_ALREADY_COMMITTED)) {
+ rc = NO_ERROR;
+ }
+ else
+ rc = ERROR_ACCESS_DENIED;
+ }
+ else
+ {
+ if (CurrentSize > NewRegionSize) {
+ // freemem
+ RegionSize = CurrentSize - NewRegionSize;
+ TmpAllocFreeBaseAddress =
+ (PVOID)((long)AllocFreeBaseAddress - (long)RegionSize);
+ Status = NtFreeVirtualMemory(
+ ProcessHandle,
+ &TmpAllocFreeBaseAddress,
+ &RegionSize,
+ MEM_DECOMMIT
+ );
+ //
+ // The STATUS_UNABLE_TO_FREE_VM status is returned when
+ // trying to decommit pages of mapped sections. This error
+ // should not be reported to the user program.
+ //
+ if ((NT_SUCCESS(Status)) ||
+ (Status == STATUS_UNABLE_TO_FREE_VM) ||
+ (Status == STATUS_UNABLE_TO_DELETE_SECTION))
+ rc = NO_ERROR;
+ else
+ rc = ERROR_ACCESS_DENIED;
+ }
+ }
+ return(rc);
+}
+
+
+
+
+BOOLEAN Os2DosReallocSharedMem(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ PLIST_ENTRY MemListHead, MemListNext, ProcListHead, ProcListNext;
+ POS2_PROCESS ProcessRef;
+ POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+ ULONG Index;
+ APIRET rc;
+ BOOLEAN LdrModified;
+ POS2_REALLOCSHAREDMEM_MSG a = &m->u.ReallocSharedMem;
+
+ // mark as not shared
+
+ a->SharedMemory = FALSE;
+ m->ReturnedErrorValue = NO_ERROR;
+ rc = NO_ERROR;
+
+ // Loop on all OS/2 Process
+
+ ProcListHead = &Os2RootProcess->ListLink;
+ ProcListNext = ProcListHead->Flink;
+ while (ProcListNext != ProcListHead) {
+
+ // Loop on all Shared Memory references of an OS/2 process
+
+ ProcessRef = CONTAINING_RECORD( ProcListNext,
+ OS2_PROCESS,
+ ListLink
+ );
+ MemListHead = &ProcessRef->SharedMemoryList;
+ MemListNext = MemListHead->Flink;
+ while (MemListNext != MemListHead){
+
+ MemoryProcessRef = CONTAINING_RECORD( MemListNext,
+ OS2_SHARED_MEMORY_PROCESS_REF,
+ Link
+ );
+
+ MemoryObject = MemoryProcessRef->SharedMemoryObject;
+ if (MemoryObject->BaseAddress == a->BaseAddress) {
+
+ a->SharedMemory = TRUE;
+ rc = Os2ResizeSharedMemory(
+ ProcessRef->ProcessHandle,
+ a->AllocFreeBaseAddress,
+ MemoryObject->Index,
+ a->CurrentSize,
+ a->NewLdtLimit,
+ a->NewRegionSize,
+ a->Flags
+ );
+
+ break;
+ }
+ MemListNext = MemListNext->Flink;
+ } // process memory objects loop
+ if (rc != NO_ERROR) {
+ if (ProcessRef->ProcessHandle == t->Process->ProcessHandle) {
+#if DBG
+ DbgPrint ("OS2SRV: Os2DosReallocSharedMem failed due to current process (PID %d). \n",
+ ProcessRef->ProcessId );
+#endif
+ m->ReturnedErrorValue = rc;
+ return(TRUE);
+ } else {
+#if DBG
+ DbgPrint ("OS2SRV: Os2ResizeSharedMem failed due to other process (PID %d). \n",
+ ProcessRef->ProcessId );
+#endif
+ }
+ }
+ ProcListNext = ProcListNext->Flink;
+ } // process loop
+ if (a->SharedMemory == FALSE) {
+ //
+ // This is a shared segment of the loader so loop on all process
+ // and fix all the references
+ //
+ ProcListHead = &Os2RootProcess->ListLink;
+ ProcListNext = ProcListHead->Flink;
+ while (ProcListNext != ProcListHead) {
+
+ ProcessRef = CONTAINING_RECORD( ProcListNext,
+ OS2_PROCESS,
+ ListLink
+ );
+ Index = FLATTOSEL((a->BaseAddress));
+ rc = Os2ResizeSharedMemory(
+ ProcessRef->ProcessHandle,
+ a->AllocFreeBaseAddress,
+ Index,
+ a->CurrentSize,
+ a->NewLdtLimit,
+ a->NewRegionSize,
+ a->Flags
+ );
+ //
+ // ERROR_INVALID_SEGMENT_NUMBER is an internal status returned
+ // by Os2ResizeSharedMemory when the P bit in the ldt is 0.
+ // This marks that the ldt entry is not in use
+ //
+ if (rc == NO_ERROR) {
+ //
+ // Check if the shared data segment of the loader was already
+ // modified for this segment.
+ // If not, modify it. Otherwise, skip the modification
+ //
+ if (a->SharedMemory == FALSE) {
+ LdrModified = LDRModifySizeOfSharedSegment(t, Index, a->NewLdtLimit);
+ ASSERT(LdrModified == TRUE);
+ }
+ a->SharedMemory = TRUE;
+ }
+ else if (rc == ERROR_INVALID_SEGMENT_NUMBER) {
+ rc = NO_ERROR;
+ }
+ ProcListNext = ProcListNext->Flink;
+ } // process loop
+ if (a->SharedMemory) {
+ m->ReturnedErrorValue = NO_ERROR;
+ } else {
+ m->ReturnedErrorValue = ERROR_ACCESS_DENIED;
+ }
+ }
+ return( TRUE );
+}
+
+APIRET
+AllocHugeMem(
+ HANDLE ProcessHandle,
+ ULONG BaseAddress,
+ ULONG Size,
+ ULONG Protect
+)
+{
+ NTSTATUS Status;
+ PVOID TmpAllocFreeBaseAddress = (PVOID)BaseAddress;
+
+ Status = NtAllocateVirtualMemory(
+ ProcessHandle,
+ &TmpAllocFreeBaseAddress,
+ 1,
+ &Size,
+ MEM_COMMIT,
+ Protect
+ );
+ if (NT_SUCCESS(Status) || (Status == STATUS_ALREADY_COMMITTED)) {
+ return(NO_ERROR);
+ }
+ else {
+ return(ERROR_ACCESS_DENIED);
+ }
+}
+
+//
+// Utility routines to handle LDT setting
+//
+NTSTATUS
+SetEntryLDT(
+ HANDLE ProcessHandle,
+ ULONG BaseAddress,
+ ULONG Size
+)
+{
+ /* Descriptor definition */
+
+ struct desctab {
+ USHORT d_limit; /* Segment limit */
+ USHORT d_loaddr; /* Low word of physical address */
+ UCHAR d_hiaddr; /* High byte of physical address */
+ UCHAR d_access; /* Access byte */
+ UCHAR d_attr; /* Attributes/extended limit */
+ UCHAR d_extaddr; /* Extended physical address byte */
+ } *LDTDesc;
+ PULONG tmp;
+ ULONG Sel;
+ PROCESS_LDT_INFORMATION LdtInformation;
+ NTSTATUS Status;
+
+ Sel = FLATTOSEL(BaseAddress);
+
+ LDTDesc = (struct desctab *)(&LdtInformation.LdtEntries[0]);
+ tmp = (PULONG)(LDTDesc);
+ //
+ // zero the descriptor
+ //
+ *tmp++ = 0;
+ *tmp = 0;
+
+ LDTDesc->d_access = 0xf3; // read/write, present, ring 3
+ LDTDesc->d_limit = (USHORT)(Size-1);
+ LDTDesc->d_loaddr = (USHORT)(BaseAddress & 0xffff);
+ LDTDesc->d_hiaddr = (UCHAR)((BaseAddress >> 16) & 0xff);
+ LDTDesc->d_extaddr = (UCHAR)((BaseAddress >> 24) & 0xff);
+ //
+ // adjust LDTDesc by the LDT base and the index of this selector
+ //
+ LdtInformation.Length = sizeof(LDT_ENTRY);
+ LdtInformation.Start = Sel & 0xfffffff8;
+ Status = NtSetInformationProcess( ProcessHandle,
+ ProcessLdtInformation,
+ &LdtInformation,
+ sizeof(PROCESS_LDT_INFORMATION)
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("OS2SRV: SetEntryLDT failed, Status=%x\n", Status);
+#endif
+ return (STATUS_INVALID_PARAMETER);
+ }
+
+ return (STATUS_SUCCESS);
+}
+
+NTSTATUS
+ClearEntryLDT(
+ HANDLE ProcessHandle,
+ ULONG BaseAddress
+)
+{
+ /* Descriptor definition */
+
+ struct desctab {
+ USHORT d_limit; /* Segment limit */
+ USHORT d_loaddr; /* Low word of physical address */
+ UCHAR d_hiaddr; /* High byte of physical address */
+ UCHAR d_access; /* Access byte */
+ UCHAR d_attr; /* Attributes/extended limit */
+ UCHAR d_extaddr; /* Extended physical address byte */
+ } *LDTDesc;
+ PULONG tmp;
+ ULONG Sel;
+ PROCESS_LDT_INFORMATION LdtInformation;
+ NTSTATUS Status;
+
+ Sel = FLATTOSEL(BaseAddress);
+
+ LDTDesc = (struct desctab *)(&LdtInformation.LdtEntries[0]);
+ tmp = (PULONG)(LDTDesc);
+ //
+ // zero the descriptor
+ //
+ *tmp++ = 0;
+ *tmp = 0;
+ //
+ // adjust LDTDesc by the LDT base and the index of this selector
+ //
+ LdtInformation.Length = sizeof(LDT_ENTRY);
+ LdtInformation.Start = Sel & 0xfffffff8;
+ Status = NtSetInformationProcess( ProcessHandle,
+ ProcessLdtInformation,
+ &LdtInformation,
+ sizeof(PROCESS_LDT_INFORMATION)
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("OS2SRV: ClearEntryLDT failed, Status=%x\n", Status);
+#endif
+ return (STATUS_INVALID_PARAMETER);
+ }
+
+ return (STATUS_SUCCESS);
+}
+
+APIRET Os2ResizeSharedHuge(
+ HANDLE ProcessHandle,
+ POS2_SHARED_MEMORY_OBJECT MemoryObject,
+ ULONG NewNumOfSegments,
+ ULONG NewSizeOfPartialSeg
+)
+{
+ ULONG BaseAddress;
+ ULONG cNewSegs;
+ ULONG CommitSize;
+ ULONG cDelSegs;
+ ULONG RoundedUpCurrentPartial;
+ ULONG RoundedUpNewPartial;
+ ULONG Op = 0;
+ ULONG i;
+ APIRET rc = NO_ERROR;
+
+ // according to the new size allocate/free memory
+
+ if (MemoryObject->SizeOfPartialSeg != 0) {
+ Op |= H_CUR_PARTIAL;
+ }
+ if (NewSizeOfPartialSeg != 0) {
+ Op |= H_NEW_PARTIAL;
+ }
+ if (NewNumOfSegments > MemoryObject->NumOfSegments) {
+ Op |= H_SEG_INC;
+ }
+ else if (NewNumOfSegments < MemoryObject->NumOfSegments) {
+ Op |= H_SEG_DEC;
+ }
+
+ switch (Op) {
+ case H_SAME_SEG_NO_PARTIAL:
+
+ break;
+
+ case H_SAME_SEG_NEW_PARTIAL:
+
+ BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * MemoryObject->NumOfSegments);
+ rc = AllocHugeMem(ProcessHandle, BaseAddress,
+ NewSizeOfPartialSeg, PAGE_READWRITE);
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OS2_DEBUG ( MEMORY ) {
+ DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ //
+ // Set LDT entry
+ //
+ SetEntryLDT(ProcessHandle, BaseAddress, NewSizeOfPartialSeg);
+ break;
+
+ case H_SAME_SEG_DEL_PARTIAL:
+
+ BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * MemoryObject->NumOfSegments);
+ //
+ // Set LDT entry
+ //
+ ClearEntryLDT(ProcessHandle, BaseAddress);
+ break;
+
+ case H_SAME_SEG_CHG_PARTIAL:
+
+ BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * MemoryObject->NumOfSegments);
+ RoundedUpCurrentPartial = ROUND_UP_TO_PAGES(MemoryObject->SizeOfPartialSeg);
+ RoundedUpNewPartial = ROUND_UP_TO_PAGES(NewSizeOfPartialSeg);
+ if (RoundedUpNewPartial > RoundedUpCurrentPartial) {
+ rc = AllocHugeMem(ProcessHandle,
+ BaseAddress + RoundedUpCurrentPartial,
+ RoundedUpNewPartial - RoundedUpCurrentPartial,
+ PAGE_READWRITE
+ );
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OS2_DEBUG ( MEMORY ) {
+ DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ }
+ //
+ // Set LDT entry
+ //
+ SetEntryLDT(ProcessHandle, BaseAddress, NewSizeOfPartialSeg);
+ break;
+
+ case H_INC_SEG_NO_PARTIAL:
+
+ BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * MemoryObject->NumOfSegments);
+ cNewSegs = NewNumOfSegments - MemoryObject->NumOfSegments;
+ CommitSize = cNewSegs * _64K;
+ rc = AllocHugeMem(ProcessHandle,
+ BaseAddress,
+ CommitSize,
+ PAGE_READWRITE
+ );
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OS2_DEBUG ( MEMORY ) {
+ DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ for (i = 0; i < cNewSegs; i++, BaseAddress += _64K) {
+ SetEntryLDT(ProcessHandle, BaseAddress, _64K);
+ }
+ break;
+
+ case H_INC_SEG_NEW_PARTIAL:
+
+ BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * MemoryObject->NumOfSegments);
+ cNewSegs = NewNumOfSegments - MemoryObject->NumOfSegments;
+ CommitSize = cNewSegs * _64K + NewSizeOfPartialSeg;
+ rc = AllocHugeMem(ProcessHandle,
+ BaseAddress,
+ CommitSize,
+ PAGE_READWRITE
+ );
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OS2_DEBUG ( MEMORY ) {
+ DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ for (i = 0; i < cNewSegs; i++, BaseAddress += _64K) {
+ SetEntryLDT(ProcessHandle, BaseAddress, _64K);
+ }
+ SetEntryLDT(ProcessHandle, BaseAddress, NewSizeOfPartialSeg);
+ break;
+
+ case H_INC_SEG_DEL_PARTIAL:
+
+ BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * MemoryObject->NumOfSegments);
+ RoundedUpCurrentPartial = ROUND_UP_TO_PAGES(MemoryObject->SizeOfPartialSeg);
+ RoundedUpNewPartial = ROUND_UP_TO_PAGES(NewSizeOfPartialSeg);
+ if (_64K - RoundedUpCurrentPartial) {
+ rc = AllocHugeMem(ProcessHandle,
+ BaseAddress + RoundedUpCurrentPartial,
+ _64K - RoundedUpCurrentPartial,
+ PAGE_READWRITE
+ );
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OS2_DEBUG ( MEMORY ) {
+ DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ }
+ SetEntryLDT(ProcessHandle, BaseAddress, _64K);
+ cNewSegs = NewNumOfSegments - (MemoryObject->NumOfSegments + 1);
+ if (cNewSegs == 0) {
+ return(NO_ERROR);
+ }
+ BaseAddress += _64K;
+ CommitSize = cNewSegs * _64K;
+ rc = AllocHugeMem(ProcessHandle,
+ BaseAddress,
+ CommitSize,
+ PAGE_READWRITE
+ );
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OS2_DEBUG ( MEMORY ) {
+ DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ for (i = 0; i < cNewSegs; i++, BaseAddress += _64K) {
+ SetEntryLDT(ProcessHandle, BaseAddress, _64K);
+ }
+ break;
+
+ case H_INC_SEG_CHG_PARTIAL:
+
+ BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * MemoryObject->NumOfSegments);
+ RoundedUpCurrentPartial = ROUND_UP_TO_PAGES(MemoryObject->SizeOfPartialSeg);
+ RoundedUpNewPartial = ROUND_UP_TO_PAGES(NewSizeOfPartialSeg);
+ if (_64K - RoundedUpCurrentPartial) {
+ rc = AllocHugeMem(ProcessHandle,
+ BaseAddress + RoundedUpCurrentPartial,
+ _64K - RoundedUpCurrentPartial,
+ PAGE_READWRITE
+ );
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OS2_DEBUG ( MEMORY ) {
+ DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ }
+ SetEntryLDT(ProcessHandle, BaseAddress, _64K);
+ cNewSegs = NewNumOfSegments - (MemoryObject->NumOfSegments + 1);
+ BaseAddress += _64K;
+ if (cNewSegs != 0) {
+ CommitSize = cNewSegs * _64K;
+ rc = AllocHugeMem(ProcessHandle,
+ BaseAddress,
+ CommitSize,
+ PAGE_READWRITE
+ );
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OS2_DEBUG ( MEMORY ) {
+ DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ for (i = 0; i < cNewSegs; i++, BaseAddress += _64K) {
+ SetEntryLDT(ProcessHandle, BaseAddress, _64K);
+ }
+ }
+ rc = AllocHugeMem(ProcessHandle,
+ BaseAddress,
+ NewSizeOfPartialSeg,
+ PAGE_READWRITE
+ );
+ if (rc != NO_ERROR) {
+#if DBG
+ IF_OS2_DEBUG ( MEMORY ) {
+ DbgPrint ("OS2SRV: Os2ResizeSharedHuge: Can't Commit, rc=%d\n", rc);
+ }
+#endif
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ SetEntryLDT(ProcessHandle, BaseAddress, NewSizeOfPartialSeg);
+ break;
+
+ case H_DEC_SEG_NO_PARTIAL:
+
+ BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * NewNumOfSegments);
+ cDelSegs = MemoryObject->NumOfSegments - NewNumOfSegments;
+ //
+ // Clear LDT entry
+ //
+ for (i = 0; i < cDelSegs; i++, BaseAddress += _64K) {
+ ClearEntryLDT(ProcessHandle, BaseAddress);
+ }
+ break;
+
+ case H_DEC_SEG_NEW_PARTIAL:
+
+ BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * (NewNumOfSegments+1));
+ cDelSegs = MemoryObject->NumOfSegments - (NewNumOfSegments+1);
+
+ if (cDelSegs != 0) {
+ //
+ // Clear LDT entry
+ //
+ for (i = 0; i < cDelSegs; i++, BaseAddress += _64K) {
+ ClearEntryLDT(ProcessHandle, BaseAddress);
+ }
+ }
+ BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * NewNumOfSegments);
+ //
+ // Set LDT entry
+ //
+ SetEntryLDT(ProcessHandle, BaseAddress, NewSizeOfPartialSeg);
+ break;
+
+ case H_DEC_SEG_DEL_PARTIAL:
+
+ BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * NewNumOfSegments);
+ cDelSegs = MemoryObject->NumOfSegments - NewNumOfSegments;
+ //
+ // Clear LDT entry
+ //
+ for (i = 0; i <= cDelSegs; i++, BaseAddress += _64K) {
+ ClearEntryLDT(ProcessHandle, BaseAddress);
+ }
+ break;
+
+ case H_DEC_SEG_CHG_PARTIAL:
+
+ BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * (NewNumOfSegments+1));
+ cDelSegs = MemoryObject->NumOfSegments - (NewNumOfSegments+1);
+ //
+ // Clear LDT entry
+ //
+ for (i = 0; i <= cDelSegs; i++, BaseAddress += _64K) {
+ ClearEntryLDT(ProcessHandle, BaseAddress);
+ }
+ BaseAddress = (ULONG)MemoryObject->BaseAddress + (_64K * NewNumOfSegments);
+ //
+ // Set LDT entry
+ //
+ SetEntryLDT(ProcessHandle, BaseAddress, NewSizeOfPartialSeg);
+ break;
+ }
+ return(rc);
+}
+
+BOOLEAN Os2InternalReallocSharedHuge(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ PLIST_ENTRY MemListHead, MemListNext, ProcListHead, ProcListNext;
+ POS2_PROCESS ProcessRef;
+ POS2_SHARED_MEMORY_PROCESS_REF MemoryProcessRef;
+ POS2_SHARED_MEMORY_OBJECT MemoryObject;
+ APIRET rc;
+ POS2_REALLOCSHAREDHUGE_MSG a = &m->u.ReallocSharedHuge;
+
+ m->ReturnedErrorValue = NO_ERROR;
+ rc = NO_ERROR;
+
+ // Loop on all OS/2 Process
+
+ ProcListHead = &Os2RootProcess->ListLink;
+ ProcListNext = ProcListHead->Flink;
+ while (ProcListNext != ProcListHead) {
+
+ // Loop on all Shared Memory references of an OS/2 process
+
+ ProcessRef = CONTAINING_RECORD( ProcListNext,
+ OS2_PROCESS,
+ ListLink
+ );
+ MemListHead = &ProcessRef->SharedMemoryList;
+ MemListNext = MemListHead->Flink;
+ while (MemListNext != MemListHead){
+
+ MemoryProcessRef = CONTAINING_RECORD( MemListNext,
+ OS2_SHARED_MEMORY_PROCESS_REF,
+ Link
+ );
+
+ MemoryObject = MemoryProcessRef->SharedMemoryObject;
+ if (MemoryObject->BaseAddress == a->BaseAddress) {
+
+ rc = Os2ResizeSharedHuge(
+ ProcessRef->ProcessHandle,
+ MemoryObject,
+ a->NumOfSegments,
+ a->SizeOfPartialSeg
+ );
+
+ break;
+ }
+ MemListNext = MemListNext->Flink;
+ } // process memory objects loop
+ if (rc != NO_ERROR) {
+#if DBG
+ DbgPrint ("Os2InternalReallocSharedHuge Memory Reallocation failed.\n");
+#endif
+ m->ReturnedErrorValue = rc;
+ return(TRUE);
+ }
+ ProcListNext = ProcListNext->Flink;
+ } // process loop
+ //
+ // Update the MemoryObject information to contain the new size of the
+ // Huge shared segment
+ //
+ MemoryObject->NumOfSegments = a->NumOfSegments;
+ MemoryObject->SizeOfPartialSeg = a->SizeOfPartialSeg;
+ return( TRUE );
+}
diff --git a/private/os2/server/srvwin.c b/private/os2/server/srvwin.c
new file mode 100644
index 000000000..6e76ea9f2
--- /dev/null
+++ b/private/os2/server/srvwin.c
@@ -0,0 +1,330 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvwin.c
+
+Abstract:
+
+ This module contains routines for direct os2srv->win32 interface.
+
+Author:
+
+ Yaron Shamir (yarons) 2-Nov-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include <windows.h>
+#define WIN32_ONLY
+#include "sesport.h"
+#include "..\os2ses\os2ses.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <direct.h>
+#include <string.h>
+#include <ctype.h>
+#include <os2win.h>
+#include "os2res.h"
+
+HANDLE Os2hReadPipe;
+HANDLE Os2hWritePipe;
+HANDLE Os2hOs2SrvInstance;
+
+ //
+ // Termination commands - communication to Os2TerminationThread (srvwin.c)
+ // BUGBUG - this is defined in os2srv.h as well, for non-windows files
+ //
+typedef enum _OS2_TERMCMD_TYPE {
+ Os2TerminateProcess = 1,
+ Os2TerminateThread,
+ Os2MaxTermCmd
+} OS2_TERMCMD_TYPE;
+
+typedef struct _OS2_TERMCMD {
+ OS2_TERMCMD_TYPE op;
+ HANDLE Handle;
+ PVOID Param1;
+ PVOID Param2;
+} OS2_TERMCMD, *POS2_TERMCMD;
+
+
+VOID
+Os2NotifyDeathOfProcess(
+ IN PVOID m,
+ IN PVOID Proc);
+
+VOID
+Os2SwitchContextToExitListDispatcher(
+ IN PVOID Thread
+ );
+
+#define CAP_BUFFER_SIZE 64
+#define TEXT_BUFFER_SIZE 512
+#define REG_TEXT_BUFFER_SIZE 640
+
+CHAR DefaultAccessApiGPCap[] = "%s.EXE - General Protection";
+CHAR DefaultAccessGPText[] = "An OS/2 program caused a protection violation.\
+\n\nCS\t= 0x%04lx\
+\nIP\t= 0x%04lx\
+\nAX\t= 0x%04lx\
+\nBX\t= 0x%04lx\
+\nCX\t= 0x%04lx\
+\nDX\t= 0x%04lx\
+\nSI\t= 0x%04lx\
+\nDI\t= 0x%04lx\
+\nBP\t= 0x%04lx\
+\nSP\t= 0x%04lx\
+\nSS\t= 0x%04lx\
+\nDS\t= 0x%04lx\
+\nES\t= 0x%04lx\
+\n\nThe program will be terminated.";
+CHAR DefaultApiGPText[] = "An OS/2 program called %s()\nwith a bad pointer argument.\n\nThe application will be terminated.\n";
+
+
+DWORD
+Os2AccessGPPopup(
+ IN ULONG CS,
+ IN ULONG IP,
+ IN ULONG AX,
+ IN ULONG BX,
+ IN ULONG CX,
+ IN ULONG DX,
+ IN ULONG SI,
+ IN ULONG DI,
+ IN ULONG BP,
+ IN ULONG SP,
+ IN ULONG SS,
+ IN ULONG DS,
+ IN ULONG ES,
+ IN PUCHAR AppName
+ )
+{
+ char MessageCaption[CAP_BUFFER_SIZE];
+ char MessageText[TEXT_BUFFER_SIZE];
+ CHAR TextString[TEXT_BUFFER_SIZE];
+ CHAR CapString[CAP_BUFFER_SIZE];
+
+ if ((Os2hOs2SrvInstance == NULL) &&
+ ((Os2hOs2SrvInstance = GetModuleHandle(NULL)) == NULL))
+ {
+#if DBG
+ KdPrint(("Os2AccessGPPopup: error %lu on GetModuleHandle\n",
+ GetLastError()));
+#endif
+ }
+
+ if (( Os2hOs2SrvInstance == NULL) ||
+ !LoadString(Os2hOs2SrvInstance,
+ IDS_OS2SRV_ACCESS_GP_TXT,
+ TextString,
+ TEXT_BUFFER_SIZE))
+ {
+#if DBG
+ if ( Os2hOs2SrvInstance == NULL )
+ {
+ KdPrint(("Os2AccessGPPopup: error %lu on LoadString1\n",
+ GetLastError()));
+ }
+#endif
+ strncpy(TextString, DefaultAccessGPText, TEXT_BUFFER_SIZE - 1);
+ }
+
+ if (( Os2hOs2SrvInstance == NULL) ||
+ !LoadString(Os2hOs2SrvInstance,
+ IDS_OS2SRV_ACCESS_API_GP_CAP,
+ CapString,
+ CAP_BUFFER_SIZE))
+ {
+#if DBG
+ if ( Os2hOs2SrvInstance == NULL )
+ {
+ KdPrint(("Os2AccessGPPopup: error %lu on LoadString2\n",
+ GetLastError()));
+ }
+#endif
+ strncpy(CapString, DefaultAccessApiGPCap, CAP_BUFFER_SIZE - 1);
+ }
+
+ sprintf(MessageCaption, CapString, AppName);
+ sprintf(MessageText, TextString, CS, IP, AX, BX, CX, DX, SI, DI, BP, SP, SS, DS, ES);
+ MessageBox(GetActiveWindow(), MessageText, MessageCaption, MB_OK | MB_ICONSTOP | MB_SYSTEMMODAL | MB_SETFOREGROUND);
+ return (0L);
+}
+
+
+DWORD
+Os2ApiGPPopup(
+ IN PUCHAR AppName,
+ IN PUCHAR Text
+ )
+{
+ char MessageCaption[CAP_BUFFER_SIZE];
+ char MessageText[TEXT_BUFFER_SIZE];
+ CHAR TextString[TEXT_BUFFER_SIZE];
+ CHAR CapString[CAP_BUFFER_SIZE];
+
+ if ((Os2hOs2SrvInstance == NULL) &&
+ ((Os2hOs2SrvInstance = GetModuleHandle(NULL)) == NULL))
+ {
+#if DBG
+ KdPrint(("Os2ApiGPPopup: error %lu on GetModuleHandle\n",
+ GetLastError()));
+#endif
+ }
+
+ if (( Os2hOs2SrvInstance == NULL) ||
+ !LoadString(Os2hOs2SrvInstance,
+ IDS_OS2SRV_API_GP_TXT,
+ TextString,
+ TEXT_BUFFER_SIZE))
+ {
+#if DBG
+ if ( Os2hOs2SrvInstance == NULL )
+ {
+ KdPrint(("Os2ApiGPPopup: error %lu on LoadString1\n",
+ GetLastError()));
+ }
+#endif
+ strncpy(TextString, DefaultApiGPText, TEXT_BUFFER_SIZE - 1);
+ }
+
+ if (( Os2hOs2SrvInstance == NULL) ||
+ !LoadString(Os2hOs2SrvInstance,
+ IDS_OS2SRV_ACCESS_API_GP_CAP,
+ CapString,
+ CAP_BUFFER_SIZE))
+ {
+#if DBG
+ if ( Os2hOs2SrvInstance == NULL )
+ {
+ KdPrint(("Os2ApiGPPopup: error %lu on LoadString2\n",
+ GetLastError()));
+ }
+#endif
+ strncpy(CapString, DefaultAccessApiGPCap, CAP_BUFFER_SIZE - 1);
+ }
+
+ sprintf(MessageCaption, CapString, AppName);
+ sprintf(MessageText, TextString, Text);
+ MessageBox(GetActiveWindow(), MessageText, MessageCaption, MB_OK | MB_ICONSTOP | MB_SYSTEMMODAL | MB_SETFOREGROUND);
+ return (0L);
+}
+
+
+LPTHREAD_START_ROUTINE
+Os2TerminationThread(
+ LPVOID lpThreadParameter)
+
+{
+ OS2_TERMCMD Buffer;
+ DWORD nNumberOfBytesRead;
+
+ UNREFERENCED_PARAMETER(lpThreadParameter);
+
+ for (; ; ){
+ if (!ReadFile(
+ Os2hReadPipe,
+ (LPVOID)&Buffer,
+ sizeof(Buffer),
+ &nNumberOfBytesRead,
+ NULL)){
+
+ ASSERT( FALSE );
+#if DBG
+ DbgPrint("Os2erminateThread - fail to Read pipe, %d\n, ignore",GetLastError());
+#endif
+ }
+ else {
+ //
+ // Read succesfully a command to execute
+ //
+ switch (Buffer.op){
+ case Os2TerminateProcess:
+ TerminateProcess( Buffer.Handle, 0L );
+ WaitForSingleObject( Buffer.Handle, 1000 );
+ CloseHandle( Buffer.Handle );
+ Os2NotifyDeathOfProcess(Buffer.Param1, Buffer.Param2);
+ break;
+
+ case Os2TerminateThread:
+
+ if (Buffer.Param1 == (PVOID)1) {
+ //
+ // This message means
+ // resume thread1 and alert it, to process exit list
+ //
+ // Switch thread1 context to ExitListDispatcher.
+ Os2SwitchContextToExitListDispatcher(Buffer.Param2);
+ }
+ else {
+ TerminateThread( Buffer.Handle, 0L );
+ WaitForSingleObject( Buffer.Handle, 1000 );
+ CloseHandle( Buffer.Handle );
+ }
+
+ break;
+
+ default:
+ ASSERT(FALSE);
+#if DBG
+ DbgPrint("Os2erminateThread - Unknown Termination Cmd, %d\n",
+ Buffer.op);
+#endif
+ break;
+ }
+ }
+ }
+ //
+ // will never get here
+ //
+ return(0); // for the compiler to shutdown his warnings.
+}
+
+
+BOOL
+Os2TerminationThreadInitialize( VOID )
+{
+ HANDLE hThreadHandle;
+ ULONG Tid;
+
+ if (!CreatePipe(
+ &Os2hReadPipe,
+ &Os2hWritePipe,
+ NULL,
+ 0)) {
+ ASSERT( FALSE );
+#if DBG
+ DbgPrint("Os2erminateThreadInitialize - fail at win32 CreatePipe, %d\n",GetLastError());
+#endif
+ return( FALSE );
+ }
+
+ //
+ // use same port for exception handling and debugger
+ //
+
+ hThreadHandle = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE )Os2TerminationThread,
+ NULL,
+ 0,
+ &Tid);
+ if (!hThreadHandle){
+ ASSERT( FALSE );
+#if DBG
+ DbgPrint("Os2erminateThreadInitialize - fail at win32 CreateThread, %d\n",GetLastError());
+#endif
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
+
diff --git a/private/os2/server/srvxcpt.c b/private/os2/server/srvxcpt.c
new file mode 100644
index 000000000..8827f6613
--- /dev/null
+++ b/private/os2/server/srvxcpt.c
@@ -0,0 +1,1885 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ srvxcpt.c
+
+Abstract:
+
+ This module implements the OS/2 V2.0 exception handling API calls.
+
+Author:
+
+ Therese Stowell (thereses) 29-June-1990
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_EXCEPTIONS
+#define INCL_OS2V20_ERRORS
+#define SIG_CTRLC 1
+#define SIG_CTRLBREAK 4
+#include "os2srv.h"
+#include "os2tile.h"
+
+APIRET
+SendSignalException(
+ IN POS2_THREAD Thread,
+ IN int Signal
+ );
+
+NTSTATUS
+Os2CompleteResumeThread(
+ IN POS2_THREAD Thread
+ );
+
+
+BOOLEAN
+Os2DosEnterMustComplete(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the DosEnterMustComplete API.
+
+Arguments:
+
+ t - calling thread
+
+ m - message
+
+Return Value:
+
+ TRUE - create a return message
+
+--*/
+
+{
+ POS2_DOSENTERMUSTCOMPLETE_MSG a = &m->u.DosEnterMustComplete;
+
+ if (t->MustComplete == MAXIMUM_MUST_COMPLETE) { /* Counter wrapped */
+ m->ReturnedErrorValue = ERROR_NESTING_TOO_DEEP;
+ }
+ else {
+ m->ReturnedErrorValue = NO_ERROR;
+ a->NestingLevel = ++t->MustComplete;
+ }
+ return (TRUE);
+}
+
+
+BOOLEAN
+Os2DosExitMustComplete(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the DosExitMustComplete API.
+
+Arguments:
+
+ t - calling thread
+
+ m - message
+
+Return Value:
+
+ TRUE - create a return message
+
+--*/
+
+{
+ POS2_DOSEXITMUSTCOMPLETE_MSG a = &m->u.DosExitMustComplete;
+
+ if (t->MustComplete == 0) { /* Counter wrapped */
+ m->ReturnedErrorValue = ERROR_ALREADY_RESET;
+ }
+ else {
+ m->ReturnedErrorValue = NO_ERROR;
+ a->NestingLevel = --t->MustComplete;
+ if ((t->MustComplete == 0) && (t->PendingSignals != 0)) {
+
+ //
+ // if we are no longer in a MustComplete region, we need to
+ // issue any pending signals.
+ //
+ // possible pending signals are:
+ // SIG_APTERM
+ // SIG_KILLPROC
+ // SIG_INTR
+ // SIG_BREAK
+ //
+
+ if (t->PendingSignals & SIGNAL_TO_FLAG(XCPT_SIGNAL_INTR)) {
+ t->PendingSignals &= ~SIGNAL_TO_FLAG(XCPT_SIGNAL_INTR);
+ SendSignalException(t,XCPT_SIGNAL_INTR);
+ }
+ if (t->PendingSignals & SIGNAL_TO_FLAG(XCPT_SIGNAL_KILLPROC)) {
+ t->PendingSignals &= ~SIGNAL_TO_FLAG(XCPT_SIGNAL_KILLPROC);
+ SendSignalException(t,XCPT_SIGNAL_KILLPROC);
+ }
+ if (t->PendingSignals & SIGNAL_TO_FLAG(XCPT_SIGNAL_BREAK)) {
+ t->PendingSignals &= ~SIGNAL_TO_FLAG(XCPT_SIGNAL_BREAK);
+ SendSignalException(t,XCPT_SIGNAL_BREAK);
+ }
+ if (t->PendingSignals & SIGNAL_TO_FLAG(SIGAPTERM)) {
+ ASSERT(FALSE);
+ t->PendingSignals &= ~SIGNAL_TO_FLAG(SIGAPTERM);
+ SendSignalException(t,SIGAPTERM);
+ }
+ }
+ }
+ return (TRUE);
+}
+
+
+BOOLEAN
+Os2DosSetSignalExceptionFocus(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the DosSetSignalExceptionFocus API.
+
+Arguments:
+
+ t - calling thread
+
+ m - message
+
+Return Value:
+
+ TRUE - create a return message
+
+--*/
+
+{
+ POS2_DOSSETSIGNALEXCEPTIONFOCUS_MSG a = &m->u.DosSetSignalExceptionFocus;
+ if (a->Flag == SIG_SETFOCUS) {
+ if (t->Process->ExceptionFocus == SIG_MAXSF) {
+ m->ReturnedErrorValue = ERROR_NESTING_TOO_DEEP;
+ }
+ else {
+ m->ReturnedErrorValue = NO_ERROR;
+ a->NestingLevel = ++t->Process->ExceptionFocus;
+ }
+ }
+ else if (a->Flag == SIG_UNSETFOCUS) {
+ if (t->Process->ExceptionFocus == 0) {
+ m->ReturnedErrorValue = ERROR_ALREADY_RESET;
+ }
+ else {
+ m->ReturnedErrorValue = NO_ERROR;
+ a->NestingLevel = --t->Process->ExceptionFocus;
+ }
+ }
+ else
+ ASSERT (FALSE);
+ return (TRUE);
+}
+
+
+VOID
+FindExceptionFocus(
+ IN POS2_PROCESS RootProcess,
+ IN ULONG CurrentDepth,
+ IN OUT POS2_PROCESS *CurrentFocus,
+ IN OUT PULONG CurrentFocusDepth
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds the leafmost child of the current process that has
+ requested the signal exception focus (DosSetSignalExceptionFocus).
+
+Arguments:
+
+ RootProcess - the process from which to begin the search
+
+ CurrentDepth - the depth of the rootprocess from the original root process
+
+ CurrentFocus - the process which is currently the leafmost with the signal focus
+
+ CurrentFocusDepth - the depth of the current focus from the original root process
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_THREAD Thread1;
+
+ Thread1 = CONTAINING_RECORD( RootProcess->ThreadList.Flink, OS2_THREAD, Link );
+ if (Thread1->Dying == FALSE) {
+
+ //
+ // if the process we're looking at has requested the focus and it's
+ // leafward of the current focus, choose it as the current focus.
+ //
+
+ if ((RootProcess->ExceptionFocus != 0) &&
+ (*CurrentFocusDepth < CurrentDepth)) { // to pick the last created process, make this a <=
+ *CurrentFocus = RootProcess;
+ *CurrentFocusDepth = CurrentDepth;
+ }
+ }
+
+ ListHead = &RootProcess->ChildrenList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ FindExceptionFocus( CONTAINING_RECORD( ListNext,
+ OS2_PROCESS,
+ SiblingLink
+ ),
+ CurrentDepth+1,
+ CurrentFocus,
+ CurrentFocusDepth
+ );
+ ListNext = ListNext->Flink;
+ }
+}
+
+
+APIRET
+Os2SignalGetThreadContext(
+ POS2_THREAD Thread,
+ PCONTEXT pContext,
+ PULONG pNewSp,
+ PULONG pSuspendTimes
+ )
+{
+ NTSTATUS Status;
+ ULONG SuspendCount;
+ POS2_PROCESS Process = Thread->Process;
+ BOOLEAN SignalWasntDelivered;
+
+ *pSuspendTimes = 0;
+
+ Status = NtReadVirtualMemory( Process->ProcessHandle,
+ &(Process->ClientPib->SignalWasntDelivered),
+ &SignalWasntDelivered,
+ sizeof(BOOLEAN),
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("[%d]Os2SignalGetThreadContext: Fail to read from client, Status=%x\n",
+ Process->ProcessId,
+ Status);
+#endif // DBG
+ ASSERT(FALSE);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ if (SignalWasntDelivered) {
+ //
+ // Thread1 wan't execute the entry code of signal handler, yet.
+ //
+#if DBG
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d]Os2SignalGetThreadContext: Previous signal wasn't delivered yet\n",
+ Process->ProcessId);
+ }
+#endif // DBG
+ return ERROR_SIGNAL_REFUSED;
+ }
+
+ __try {
+
+ //
+ // Thread1 will be suspended 3 times. There is the possibility that the thread will
+ // be resumed by the client process, but only 2 times (in DosSuspend/ResumeThread and
+ // DosEnter/ExitCritSect). By suspending for 3 times we insure that the the thread
+ // will be suspended.
+ // The thread might be resumed by client in the case that signal handler was executed
+ // and the flag that indicates that signal handler in progress already cleared. But
+ // any subsequent DosSuspendThread or DosEnterCritSect will actually suspend the
+ // thread and thier spouses will resume it with the same suspend count.
+ //
+
+ do {
+ Status = NtSuspendThread(Thread->ThreadHandle, &SuspendCount);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("[%d]Os2SignalGetThreadContext: Fail to suspend thread, Status=%x\n",
+ Process->ProcessId,
+ Status);
+#endif // DBG
+ ASSERT(FALSE);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+#if DBG
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d]Os2SignalGetThreadContext: suspend thread, count = %d\n",
+ Process->ProcessId,
+ SuspendCount);
+ }
+#endif // DBG
+ (*pSuspendTimes)++;
+
+ } while (SuspendCount < 2);
+
+ pContext->ContextFlags = CONTEXT_FULL;
+ Status = NtGetContextThread(Thread->ThreadHandle, pContext);
+ if (Status != STATUS_SUCCESS) {
+#if DBG
+ DbgPrint("[%d]Os2SignalGetThreadContext: Fail to get context, Status=%x\n",
+ Process->ProcessId,
+ Status);
+#endif //DBG
+ ASSERT(FALSE);
+ return ERROR_SIGNAL_REFUSED;
+ }
+
+#if DBG
+ //
+ // Hack that avoid signal handler execution if the thread is using INT 3
+ // instruction. Relevant for checked build only.
+ //
+ if (pContext->SegCs == 0x1b && pContext->SegSs == 0x23) {
+ BYTE opcode;
+
+ Status = NtReadVirtualMemory( Process->ProcessHandle,
+ (PVOID)(pContext->Eip - 1), // previous byte
+ &opcode,
+ 1,
+ NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d]Os2SignalGetThreadContext: Fail to read instruction, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ if (opcode == 0xcc) { // INT 3
+ //
+ // Refuse to signal if the thread in INT 3 handler. It will not use
+ // the context to return, so there is no point to set new context and
+ // no possibility to perform signal handler. INT 3 is ised by
+ // ntdll!DebugService (from DbgPrint).
+ //
+ DbgPrint("[%d]Os2SignalGetThreadContext: after INT 3\n",
+ Process->ProcessId);
+ Status = 0xc0000000;
+ return ERROR_SIGNAL_REFUSED;
+ }
+ }
+#endif // DBG
+
+ if (pContext->SegCs == 0x1b) {
+ //
+ // The values of DS and ES might be invalid in the context. Kernel don't update
+ // them if the thread was in 32bit (CS==1b).
+ //
+ pContext->SegDs = pContext->SegEs = 0x23;
+ }
+
+ if (pContext->SegSs != 0x23) {
+ //
+ // The thread was in 16 bit
+ //
+ Status = NtReadVirtualMemory( Process->ProcessHandle,
+ &(Process->ClientPib->Saved32Esp),
+ pNewSp,
+ sizeof(ULONG),
+ NULL);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("[%d]Os2SignalGetThreadContext: Fail to read from client, Status=%x\n",
+ Process->ProcessId,
+ Status);
+#endif // DBG
+ ASSERT(FALSE);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // There are 8 bytes beyond the 32bit stack (that was saved) that are used by
+ // Od2JumpTo16SignalDispatch to store the jump instruction to 16bit signal
+ // handler.
+ //
+ *pNewSp -= 8;
+#if DBG
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d]Os2GetThreadContext: Signal on 16bit(%x:%x) -- Stack=%x\n",
+ Process->ProcessId,
+ pContext->SegCs,
+ pContext->Eip,
+ *pNewSp);
+ }
+#endif // DBG
+ }
+ else {
+ //
+ // 8 bytes beyond the stack are used by Od2Continue to return to original
+ // context.
+ //
+ *pNewSp = pContext->Esp - 8;
+#if DBG
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d]Os2GetThreadContext: Signal on 32bit(%x) -- Stack=%x\n",
+ Process->ProcessId,
+ pContext->Eip,
+ *pNewSp);
+ }
+#endif // DBG
+ }
+ (*pNewSp) &= 0xfffffffc;
+ }
+ __finally {
+ if (!NT_SUCCESS(Status)) {
+ while (*pSuspendTimes) {
+ Status = NtResumeThread(Thread->ThreadHandle, &SuspendCount);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d]Os2SignalGetThreadContext: Fail to resume thread, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+ }
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d]Os2SignalGetThreadContext: resume thread, count = %d\n",
+ Process->ProcessId,
+ SuspendCount);
+ }
+#endif // DBG
+ (*pSuspendTimes)--;
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+APIRET
+Os2SignalSetThreadContext(
+ POS2_THREAD Thread,
+ PCONTEXT pContext
+ )
+{
+ BOOLEAN true = TRUE;
+ POS2_PROCESS Process = Thread->Process;
+ NTSTATUS Status;
+
+ Status = NtWriteVirtualMemory( Process->ProcessHandle,
+ &(Process->ClientPib->SigHandInProgress),
+ &true,
+ sizeof(BOOLEAN),
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("[%d]Os2SignalSetThreadContext: Fail to write SigInProgress, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+#endif // DBG
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ Status = NtWriteVirtualMemory( Process->ProcessHandle,
+ &(Process->ClientPib->SignalWasntDelivered),
+ &true,
+ sizeof(BOOLEAN),
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint("[%d]Os2SignalSetThreadContext: Fail to write SigWasntDelivered, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+#endif // DBG
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+#if DBG
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d]Os2SetThreadContext: Going to set new context, Eip=%x\n",
+ Process->ProcessId,
+ pContext->Eip);
+ }
+#endif // DBG
+
+ pContext->ContextFlags = CONTEXT_FULL;
+ pContext->EFlags &= 0xfffffbff; // Clear direction flag. By defualt run-time
+ // library assume that direction flag is cleared.
+ // RtlMoveMemory, for example, don't clear this
+ // flag on entry, but assume it 0.
+ Status = NtSetContextThread(Thread->ThreadHandle, pContext);
+ if (Status != STATUS_SUCCESS) {
+#if DBG
+ DbgPrint("[%d]Os2SignalSetThreadContext: Fail to set context, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(NT_SUCCESS(Status));
+#endif // DBG
+ return ERROR_SIGNAL_REFUSED;
+ }
+ return NO_ERROR;
+}
+
+VOID
+DeliverSignal(
+ IN POS2_THREAD Thread,
+ IN ULONG Signal
+ )
+
+/*++
+
+Routine Description:
+
+ This function is used to deliver a signal to a process. It
+ can safely assume that the target process is inside the client.
+
+Arguments:
+
+ Thread - Supplies the handle of the thread to be signaled
+
+ Signal - Supplies the index of the signal to be delivered to the
+ process
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS Status;
+ ULONG Args[2];
+ CONTEXT Context;
+ ULONG NewSp;
+ POS2_PROCESS Process = Thread->Process;
+ ULONG SuspendCount;
+ APIRET rc;
+ ULONG SuspendTimes;
+
+#if DBG
+ IF_OS2_DEBUG( EXCEPTIONS ) {
+ DbgPrint("Thread 0x%lx delivered signal %ld\n",Thread,Signal);
+ }
+#endif
+ //
+ // Suspend the thread and get it's context
+ //
+ if ((rc = Os2SignalGetThreadContext(Thread, &Context, &NewSp, &SuspendTimes)) != NO_ERROR) {
+ //
+ // Continue without context switch. The signal will not be delivered.
+ //
+ return;
+ }
+ __try {
+
+ NewSp -= sizeof( CONTEXT );
+ Status = NtWriteVirtualMemory(
+ Process->ProcessHandle,
+ (PVOID)NewSp,
+ &Context,
+ sizeof( CONTEXT ),
+ NULL);
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint("[%d]DeliverSignal: Fail to write old context to client stack, Status=%x\n",
+ Process->ProcessId,
+ Status);
+#endif // DBG
+ ASSERT(FALSE);
+ __leave;
+ }
+
+ Args[0] = NewSp; // pass pointer to context
+ Args[1] = Signal;
+
+ NewSp -= 2 * sizeof( ULONG );
+ Status = NtWriteVirtualMemory(
+ Process->ProcessHandle,
+ (PVOID)NewSp,
+ Args,
+ 2 * sizeof( ULONG ),
+ NULL);
+
+ if (!NT_SUCCESS( Status )) {
+#if DBG
+ DbgPrint("[%d]DeliverSignal: Fail to write parameters to client stack, Status=%x\n",
+ Process->ProcessId,
+ Status);
+#endif // DBG
+ ASSERT(FALSE);
+ __leave;
+ }
+ //
+ // Set the address of the target code into Eip, the new target stack
+ // into Esp, and reload context to make it happen.
+ //
+ Context.SegSs = Context.SegDs = Context.SegEs = 0x23;
+ Context.SegCs = 0x1b;
+ Context.Esp = NewSp;
+ Context.Eip = (ULONG)Process->SignalDeliverer;
+ rc = Os2SignalSetThreadContext(Thread, &Context);
+ }
+ __finally {
+ if (rc != NO_ERROR || !NT_SUCCESS(Status)) {
+ while (SuspendTimes) {
+ Status = NtResumeThread(Thread->ThreadHandle, &SuspendCount);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d]DeleverSignal: Fail to resume thread, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+ }
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d]DeliverSignal: resume thread, count = %d\n",
+ Process->ProcessId,
+ SuspendCount);
+ }
+#endif // DBG
+ SuspendTimes--;
+ }
+ }
+ else {
+ //
+ // Now alert the thread - in case it is blocked it will
+ // get the chance now to execute the signal handler
+ //
+#if DBG
+ IF_OD2_DEBUG( TASKING ) {
+ DbgPrint("[%d,%d]DeliverSignal: Going to NtAlertThread(%x.%x)\n",
+ Process->ProcessId,
+ Thread->ThreadId,
+ Thread->ClientId.UniqueProcess,
+ Thread->ClientId.UniqueThread);
+ }
+#endif
+ Status = NtAlertThread(Thread->ThreadHandle);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ //
+ // We can do nothing but to try to continue execution
+ //
+ DbgPrint("[%d]DeliverSignal: Fail to alert thread, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+ }
+#endif // DBG
+ Os2CompleteResumeThread(Thread);
+ }
+ }
+}
+
+APIRET
+SendSignalException(
+ IN POS2_THREAD Thread,
+ IN int Signal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a signal to a particular thread. It will do the
+ correct thing based on whether the thread is in a mustcomplete section
+ or has signals pending.
+
+Arguments:
+
+ Thread - thread to signal
+
+ Signal - signal to send
+
+Return Value:
+
+ ERROR_SIGNAL_PENDING - the specified signal is already pending for the
+ thread.
+
+--*/
+
+{
+ ULONG SignalFlag;
+
+ //
+ // convert signal to bitmap value
+ //
+
+ SignalFlag = SIGNAL_TO_FLAG(Signal);
+
+ //
+ // if a signal of this type is already queued, return error.
+ //
+
+ if (Thread->PendingSignals & SignalFlag) {
+ return ERROR_SIGNAL_PENDING;
+ }
+
+ //
+ // if a signal of this type is currently being processed or
+ // the thread is in a mustcomplete region, queue the signal.
+ // otherwise, issue it.
+ //
+ // if the thread is in a wait block, wake it up.
+ //
+
+ if (!(Thread->CurrentSignals & SignalFlag) && !Thread->MustComplete) {
+// Thread->CurrentSignals |= SignalFlag;
+ if (Thread->WaitBlock != NULL) {
+ Thread->WaitBlock->WaitReplyMessage.ReturnedErrorValue = ERROR_INTERRUPT;
+ Os2NotifyWaitBlock(Thread->WaitBlock,WaitInterrupt,NULL,NULL);
+ }
+ DeliverSignal(Thread,Signal);
+ }
+ else {
+ Thread->PendingSignals |= SignalFlag;
+ }
+ return NO_ERROR;
+}
+
+
+BOOLEAN
+Os2DosSendSignalException(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the DosSendSignalException API.
+
+Arguments:
+
+ t - calling thread
+
+ m - message
+
+Return Value:
+
+ TRUE - create a return message
+
+--*/
+
+{
+ POS2_DOSSENDSIGNALEXCEPTION_MSG a = &m->u.DosSendSignalException;
+ POS2_PROCESS Process;
+ POS2_PROCESS FocusProcess;
+ POS2_THREAD Thread;
+ ULONG Depth;
+
+#if DBG
+ IF_OS2_DEBUG( EXCEPTIONS ) {
+ DbgPrint("entering Os2DosSendSignalException\n");
+ }
+#endif
+
+ //
+ // find the specified process
+ //
+
+ Process = Os2LocateProcessByProcessId( m,
+ t->Process,
+ (PID)a->ProcessId,
+ (BOOLEAN)FALSE
+ );
+ if (Process == NULL) {
+ return( TRUE );
+ }
+
+ //
+ // verify that specified process is direct child of caller
+ // believe it or not, ERROR_INVALID_FUNCTION is the same error code
+ // as is returned by OS/2 v2.0
+ //
+
+ if (Process->Parent != t->Process) {
+ m->ReturnedErrorValue = ERROR_INVALID_FUNCTION;
+ return( TRUE );
+ }
+
+ //
+ // find the leafmost process that has requested the exception focus
+ //
+
+ FocusProcess = NULL;
+ Depth = 0;
+ FindExceptionFocus(Process,
+ (ULONG) 1,
+ &FocusProcess,
+ &Depth);
+
+ if (FocusProcess == NULL) {
+ m->ReturnedErrorValue = ERROR_NO_SIGNAL_SENT;
+ return (TRUE);
+ }
+
+ //
+ // find thread 1 of the exception focus process
+ //
+
+ Thread = CONTAINING_RECORD( FocusProcess->ThreadList.Flink, OS2_THREAD, Link );
+
+ if (Thread->Dying) {
+#if DBG
+ ASSERT (FALSE);
+ DbgPrint( "Os2DosSendSignalException, Thread is dying\n");
+#endif
+ }
+
+ //
+ // send the signal. this routine releases the Thread lock.
+ //
+
+ m->ReturnedErrorValue = SendSignalException(Thread,a->Exception);
+
+#if DBG
+ IF_OS2_DEBUG( EXCEPTIONS ) {
+ DbgPrint("leaving Os2DosSendSignalException. rc is %ld\n",m->ReturnedErrorValue);
+ }
+#endif
+ return (TRUE);
+}
+
+
+BOOLEAN
+Os2DosAcknowledgeSignalException(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the DosAcknowledgeSignalException API.
+
+Arguments:
+
+ t - calling thread
+
+ m - message
+
+Return Value:
+
+ TRUE - create a return message
+
+--*/
+
+{
+ POS2_DOSACKNOWLEDGESIGNALEXCEPTION_MSG a = &m->u.DosAcknowledgeSignalException;
+
+
+ //
+ // make sure this signal has been delivered to this thread
+ //
+
+ if (!(t->CurrentSignals & SIGNAL_TO_FLAG(a->SignalNumber))) {
+ m->ReturnedErrorValue = ERROR_INVALID_SIGNAL_NUMBER;
+ return (TRUE);
+ }
+
+ //
+ // turn off signal bit
+ //
+
+ t->CurrentSignals &= ~SIGNAL_TO_FLAG(a->SignalNumber);
+
+ if (t->PendingSignals & SIGNAL_TO_FLAG(a->SignalNumber)) {
+ t->PendingSignals &= ~SIGNAL_TO_FLAG(a->SignalNumber);
+//
+// LTS - 4/22/92 : Check for XCPT_SIGNAL_KILLPROC, don't send signal back to
+// client.
+ if (a->SignalNumber != XCPT_SIGNAL_KILLPROC) {
+ SendSignalException(t,a->SignalNumber);
+ }
+ }
+
+ return (TRUE);
+}
+
+BOOLEAN
+Os2GetSigHandlerRec(
+ IN POS2_API_MSG m,
+ POD2_SIG_HANDLER_REC psighandler,
+ POS2_PROCESS *pProcess
+ )
+
+{
+ POS2_DISPATCH16_SIGNAL a = &m->u.Dispatch16Signal;
+ POS2_PROCESS Parent;
+ POS2_PROCESS prvProcess;
+ POS2_PROCESS curProcess;
+ POS2_PROCESS Process;
+ NTSTATUS Status;
+
+ Process = Parent = *pProcess;
+
+ //
+ // For ctrl-c and ctrl-break send signal to the last descendant process
+ // that has a corresponding signal handler installed
+ //
+ if (a->usFlagNum == SIG_CTRLC || a->usFlagNum == SIG_CTRLBREAK) {
+ //
+ // find leafmost process for SIG_CTRLC & SIG_CTRLBREAK which has
+ // a signal handler installed
+ //
+ // Get leaf-most process
+ //
+ while (!IsListEmpty( &Process->ChildrenList )) {
+ prvProcess = Process;
+ Process = CONTAINING_RECORD(Process->ChildrenList.Flink,
+ OS2_PROCESS,
+ SiblingLink );
+ }
+ }
+
+ while(TRUE) {
+ *pProcess = Process;
+ //
+ // Read signal handler Record for this process to check if
+ // signal handler installed.
+ //
+ Status = NtReadVirtualMemory( Process->ProcessHandle,
+ (PVOID) a->sighandleraddr,
+ (PVOID) psighandler,
+ sizeof(OD2_SIG_HANDLER_REC),
+ NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ ASSERT(NT_SUCCESS(Status));
+ return TRUE;
+ }
+
+ //
+ // Check signature of signal handler record for this process
+ //
+ if (psighandler->signature == 0xdead) {
+
+ //
+ // For all other signals we are done
+ //
+ if (a->usFlagNum != SIG_CTRLC && a->usFlagNum != SIG_CTRLBREAK) {
+ return FALSE;
+ }
+
+ //
+ // Check if default signal handler still installed (Doscalls
+ // selector is present)
+ //
+ if ((psighandler->sighandler[a->usFlagNum - 1] >> 16) !=
+ (psighandler->doscallssel >> 16)) {
+ return FALSE;
+ }
+ }
+ else {
+#if DBG
+ DbgPrint("Os2GetSigHandlerRec: Hi There, I am not dead\n");
+#endif
+ return TRUE;
+ }
+
+ if (Process == Parent ||
+ (a->usFlagNum != SIG_CTRLC && a->usFlagNum != SIG_CTRLBREAK)) {
+ break;
+ }
+
+ Process = Parent;
+ while (Process != prvProcess) {
+ curProcess = Process;
+ Process = CONTAINING_RECORD(Process->ChildrenList.Flink,
+ OS2_PROCESS,
+ SiblingLink );
+ }
+ prvProcess = curProcess;
+ }
+
+ m->ReturnedErrorValue = ERROR_SIGNAL_REFUSED;
+ ASSERT(NT_SUCCESS(Status));
+ return TRUE;
+
+}
+
+APIRET
+Os2DispatchToHandler(
+ IN POS2_THREAD Thread,
+ IN POS2_DISPATCH16_SIGNAL a
+ )
+{
+ APIRET rc;
+ NTSTATUS Status;
+ CONTEXT Context;
+ ULONG NewSp;
+ PVOID address = NULL;
+ ULONG Length;
+ POS2_PROCESS Process = Thread->Process;
+ OS2_REGISTER16_SIGNAL b;
+ ULONG SuspendCount;
+ ULONG SuspendTimes;
+ //
+ // Suspend the thread and get it's context
+ //
+ if ((rc = Os2SignalGetThreadContext(Thread, &Context, &NewSp, &SuspendTimes)) !=
+ NO_ERROR) {
+ //
+ // Continue without context switch. The signal will not be delivered.
+ //
+ return rc;
+ }
+
+ __try {
+ //
+ // Allocate memory in address space of process and copy context of process
+ // who called DosFlagProcess or DosSendSignal and context of thread we are
+ // going to run in.
+ //
+ Length = sizeof(OS2_REGISTER16_SIGNAL) + sizeof(CONTEXT);
+ address = 0;
+ Status = NtAllocateVirtualMemory(Process->ProcessHandle,
+ &address,
+ 0,
+ &Length,
+ MEM_RESERVE|MEM_COMMIT,
+ PAGE_READWRITE);
+ if (!(NT_SUCCESS(Status))) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+#if DBG
+ DbgPrint("[%d]Os2DispatchToHandler: Fail to allocate memory for client, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+#endif // DBG
+ __leave;
+ }
+
+ //
+ // Write dummy register set of process who called us.
+ //
+ b.usFlagNum = a->usFlagNum;
+ b.usFlagArg = a->usFlagArg;
+ Status = NtWriteVirtualMemory( Process->ProcessHandle,
+ address,
+ (PVOID) &b.regSP,
+ sizeof(OS2_REGISTER16_SIGNAL),
+ NULL);
+ if (!(NT_SUCCESS(Status))) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+#if DBG
+ DbgPrint("[%d]Os2DispatchToHandler: Fail to write 16bit registes block, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+#endif // DBG
+ __leave;
+ }
+
+ Status = NtWriteVirtualMemory( Process->ProcessHandle,
+ (PVOID) ((PCHAR) address +
+ sizeof(OS2_REGISTER16_SIGNAL)),
+ (PVOID) &Context,
+ sizeof(CONTEXT),
+ NULL);
+ if (!(NT_SUCCESS(Status))) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+#if DBG
+ DbgPrint("[%d]Os2DispatchToHandler: Fail to write context, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+#endif // DBG
+ __leave;
+ }
+
+ Context.SegSs = Context.SegDs = Context.SegEs = 0x23;
+ Context.SegCs = 0x1b;
+
+ NewSp -= sizeof(ULONG);
+ Status = NtWriteVirtualMemory( Process->ProcessHandle,
+ (PVOID)NewSp,
+ &address,
+ sizeof(ULONG),
+ NULL);
+ if (!NT_SUCCESS( Status )) {
+ rc = ERROR_NOT_ENOUGH_MEMORY;
+#if DBG
+ DbgPrint("[%d]Os2DispatchToHandler: Fail to write parameter, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+#endif // DBG
+ __leave;
+ }
+
+ //
+ // Set the address of the target code into Eip, the new target stack
+ // into Esp, and reload context to make it happen.
+ //
+ Context.Esp = NewSp;
+ Context.Eip = a->routine;
+ Context.ContextFlags = CONTEXT_FULL;
+ rc = Os2SignalSetThreadContext(Thread, &Context);
+ }
+ __finally {
+ if (rc != NO_ERROR) {
+ if (address) {
+ Status = NtFreeVirtualMemory(
+ Process->ProcessHandle,
+ &address,
+ &Length,
+ MEM_RESERVE|MEM_COMMIT);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d]Os2DispatchToHandler: Fail to free memory for client, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+ }
+#endif // DBG
+ }
+ while (SuspendTimes) {
+ Status = NtResumeThread(Thread->ThreadHandle, &SuspendCount);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d]Os2DispatchToHandler: Fail to resume thread, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+ }
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d]Os2DispatchToHandler: resume thread, count = %d\n",
+ Process->ProcessId,
+ SuspendCount);
+ }
+#endif // DBG
+ SuspendTimes--;
+ }
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d]Os2DispatchToHandler: Fail to resume thread, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+ }
+#endif // DBG
+ }
+ }
+ return rc;
+}
+
+POS2_THREAD
+Os2GetThread1(
+ POS2_PROCESS Process
+ )
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_THREAD Thread = NULL;
+
+ ListHead = &Process->ThreadList;
+ ListNext = ListHead->Flink;
+ Thread = NULL;
+ while (ListNext != ListHead) {
+ Thread = CONTAINING_RECORD( ListNext, OS2_THREAD, Link );
+ if (Thread->Flags & OS2_THREAD_THREAD1)
+ return Thread;
+ else
+ ListNext = ListNext->Flink;
+ }
+ return NULL;
+}
+
+BOOLEAN
+Os2DosDispatch16Signal(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+ POS2_DISPATCH16_SIGNAL a = &m->u.Dispatch16Signal;
+
+ POS2_THREAD Thread1 = NULL;
+ OD2_SIG_HANDLER_REC sighandler;
+ POS2_PROCESS NextProcess;
+ POS2_PROCESS Process;
+ POS2_PROCESS ParentProcess;
+ LARGE_INTEGER timeout;
+ PLARGE_INTEGER ptimeout = &timeout;
+ NTSTATUS Status;
+ OS2_API_MSG mhold;
+ ULONG SuspendCount;
+
+ //
+ // Get process which sent message
+ //
+ Process = Os2LocateProcessByProcessId( NULL,
+ t->Process,
+ (PID)a->pidProcess,
+ (BOOLEAN)FALSE
+ );
+
+ if (Process == NULL) {
+ m->ReturnedErrorValue = ERROR_INVALID_PROCID;
+ return TRUE;
+ }
+
+ ParentProcess = Process;
+ //
+ // Scan list of childern see if any exist
+ //
+ if (!IsListEmpty( &Process->ChildrenList )) {
+ NextProcess = CONTAINING_RECORD(Process->ChildrenList.Flink,
+ OS2_PROCESS,
+ SiblingLink);
+ }
+ else {
+ NextProcess = NULL;
+ }
+
+doanother:
+ //
+ // Read Signal handler record from address space of process which is
+ // to receive the signal
+ //
+
+ Thread1 = Os2GetThread1(Process);
+
+ Status = NtSuspendThread(Thread1->ThreadHandle, &SuspendCount);
+#if DBG
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d]Os2DosDispatch16Signal: suspend thread, count = %d, Status=%x\n",
+ Process->ProcessId,
+ SuspendCount,
+ Status);
+ }
+#endif // DBG
+
+ if (!NT_SUCCESS(Status)) {
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ ASSERT(FALSE);
+ }
+ else {
+
+ __try {
+
+ if (Os2GetSigHandlerRec(m, &sighandler, &Process)) {
+ __leave;
+ }
+ //
+ // Check to see if this is a Hold Signal message
+ //
+ if (a->usFlagNum == HOLD_SIGNAL_CLEARED) {
+#if DBG
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d,%d]Os2DosDispatch16Signal: accept outstanding signal\n",
+ t->Process->ProcessId,
+ t->ThreadId);
+ }
+#endif // DBG
+ mhold.u.Dispatch16Signal.usFlagNum =
+ sighandler.outstandingsig[a->usFlagArg - 1].usFlagNum;
+ sighandler.outstandingsig[a->usFlagArg - 1].usFlagNum = 0;
+ mhold.u.Dispatch16Signal.usFlagArg =
+ sighandler.outstandingsig[a->usFlagArg - 1].usFlagArg;
+ sighandler.outstandingsig[a->usFlagArg - 1].usFlagArg = 0;
+ mhold.u.Dispatch16Signal.pidProcess =
+ sighandler.outstandingsig[a->usFlagArg - 1].pidProcess;
+ sighandler.outstandingsig[a->usFlagArg - 1].pidProcess = 0;
+ mhold.u.Dispatch16Signal.routine =
+ sighandler.outstandingsig[a->usFlagArg - 1].routine;
+ sighandler.outstandingsig[a->usFlagArg - 1].routine = 0;
+ mhold.u.Dispatch16Signal.sighandleraddr =
+ sighandler.outstandingsig[a->usFlagArg - 1].sighandleraddr;
+ sighandler.outstandingsig[a->usFlagArg - 1].sighandleraddr = 0;
+ //
+ // Write Signal table back to process
+ //
+ Status = NtWriteVirtualMemory(Process->ProcessHandle,
+ (PVOID) a->sighandleraddr,
+ (PVOID) &sighandler,
+ sizeof(sighandler),
+ NULL);
+ if (!(NT_SUCCESS(Status))) {
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ ASSERT(FALSE);
+ __leave;
+ }
+ if (Os2GetSigHandlerRec(&mhold, &sighandler, &Process)) {
+ __leave;
+ }
+ if (sighandler.action[a->usFlagArg - 1] == SIGA_ACKNOWLEDGE_AND_ACCEPT) {
+ sighandler.action[a->usFlagArg - 1] = SIGA_ACCEPT;
+ }
+ a = &mhold.u.Dispatch16Signal;
+ }
+ else if (sighandler.action[a->usFlagNum - 1] == SIGA_ACKNOWLEDGE ||
+ sighandler.action[a->usFlagNum - 1] == SIGA_ACKNOWLEDGE_AND_ACCEPT ||
+ sighandler.fholdenable) {
+ //
+ // See if we already are holding an unacknowleged signal or a hold
+ // signal
+ //
+ if (sighandler.outstandingsig[a->usFlagNum - 1].sighandleraddr != 0) {
+#if DBG
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d,%d]Os2DosDispatch16Signal: Outstanding signal wasn't pended, refuse\n",
+ t->Process->ProcessId,
+ t->ThreadId);
+ }
+#endif // DBG
+ m->ReturnedErrorValue = ERROR_SIGNAL_PENDING;
+ __leave;
+ }
+#if DBG
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d,%d]Os2DosDispatch16Signal: Save outstanding signal\n",
+ t->Process->ProcessId,
+ t->ThreadId);
+ }
+#endif // DBG
+ //
+ // Save this signal till other is processed
+ //
+ sighandler.outstandingsig[a->usFlagNum - 1].usFlagNum = a->usFlagNum;
+ sighandler.outstandingsig[a->usFlagNum - 1].usFlagArg = a->usFlagArg;
+ sighandler.outstandingsig[a->usFlagNum - 1].pidProcess = a->pidProcess;
+ sighandler.outstandingsig[a->usFlagNum - 1].routine = a->routine;
+ sighandler.outstandingsig[a->usFlagNum - 1].sighandleraddr =
+ a->sighandleraddr;
+ //
+ // Write Signal table back to process
+ //
+ Status = NtWriteVirtualMemory(Process->ProcessHandle,
+ (PVOID) a->sighandleraddr,
+ (PVOID) &sighandler,
+ sizeof(sighandler),
+ NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ ASSERT(FALSE);
+ }
+ __leave;
+ }
+
+ //
+ // Check if we should ignore signal
+ //
+ if (sighandler.action[a->usFlagNum - 1] == SIGA_IGNORE) {
+ m->ReturnedErrorValue = NO_ERROR;
+ __leave;
+ }
+ //
+ // Check to see if we can accept the signal
+ //
+ if (sighandler.action[a->usFlagNum - 1] != SIGA_ACCEPT) {
+ m->ReturnedErrorValue = ERROR_SIGNAL_REFUSED;
+ __leave;
+ }
+#if DBG
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d,%d]Os2DosDispatch16Signal: Accept signal\n",
+ t->Process->ProcessId,
+ t->ThreadId);
+ }
+#endif // DBG
+ //
+ // Disable this signal till we get a SIGA_ACKNOWLEDGE
+ //
+ sighandler.action[a->usFlagNum - 1] = SIGA_ACKNOWLEDGE;
+ //
+ // Write Signal table back to process
+ //
+ Status = NtWriteVirtualMemory(Process->ProcessHandle,
+ (PVOID) a->sighandleraddr,
+ (PVOID) &sighandler,
+ sizeof(sighandler),
+ NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ ASSERT(FALSE);
+ __leave;
+ }
+ //
+ // Search list to find thread 1. The signal handler function has to
+ // run in thread 1's context
+ //
+ if (Thread1 == NULL){
+ m->ReturnedErrorValue = ERROR_INVALID_PROCID;
+#if DBG
+ IF_OS2_DEBUG( EXCEPTIONS ) {
+ DbgPrint("Os2Dispatch16Signal: Thread1 is already gone\n");
+ }
+#endif
+ ASSERT(FALSE);
+ __leave;
+ }
+ if (Thread1->Dying == TRUE || !(Thread1->Flags & OS2_THREAD_THREAD1)) {
+ m->ReturnedErrorValue = ERROR_INVALID_PROCID;
+#if DBG
+ IF_OS2_DEBUG( EXCEPTIONS ) {
+ DbgPrint("Os2Dispatch16Signal: Thread1->Dying\n");
+ }
+#endif
+ __leave;
+ }
+ if((m->ReturnedErrorValue = Os2DispatchToHandler(Thread1,a)) != NO_ERROR) {
+#if DBG
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d,%d]Os2DosDispatch16Signal: Skip signal\n",
+ t->Process->ProcessId,
+ t->ThreadId);
+ }
+#endif // DBG
+ sighandler.action[a->usFlagNum - 1] = SIGA_ACCEPT;
+ Status = NtWriteVirtualMemory(Process->ProcessHandle,
+ (PVOID) a->sighandleraddr,
+ (PVOID) &sighandler,
+ sizeof(sighandler),
+ NULL);
+ if (!(NT_SUCCESS(Status))) {
+ m->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ ASSERT(FALSE);
+ }
+ }
+ }
+ __finally {
+ Status = NtResumeThread(Thread1->ThreadHandle, &SuspendCount);
+#if DBG
+ IF_OS2_DEBUG( SIG ) {
+ DbgPrint("[%d]Os2DosDispatch16Signal: resume thread, count = %d, Status=%x\n",
+ Process->ProcessId,
+ SuspendCount,
+ Status);
+ }
+#endif // DBG
+ }
+ }
+
+ //
+ // Check for error return if found
+ //
+ if (m->ReturnedErrorValue != 0) {
+ return TRUE;
+ }
+
+ if (Thread1 != NULL) {
+ Status = NtAlertThread(Thread1->ThreadHandle);
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("[%d]Os2DosDispatch16Signal: Fail to alert thread, Status=%x\n",
+ Process->ProcessId,
+ Status);
+ ASSERT(FALSE);
+ }
+#endif // DBG
+ Os2CompleteResumeThread(Thread1);
+ }
+
+ //
+ // For any other signal other than kill process & flag process
+ // we are done
+ //
+ if (a->usFlagNum == SIG_CTRLC || a->usFlagNum == SIG_CTRLBREAK) {
+ return TRUE;
+ }
+
+ //
+ // Check scope of signal, if scope is flag subtree continue sending
+ // signal to childern processes otherwise return
+ //
+ if (a->fscope) {
+ return TRUE;
+ }
+
+ if (NextProcess != NULL) {
+ Process = NextProcess;
+ if (ParentProcess == CONTAINING_RECORD(Process->SiblingLink.Flink,
+ OS2_PROCESS,
+ ChildrenList)) {
+ NextProcess = NULL;
+ }
+ else {
+ NextProcess = CONTAINING_RECORD(Process->SiblingLink.Flink,
+ OS2_PROCESS,
+ SiblingLink);
+ }
+ goto doanother;
+ }
+ else {
+ return TRUE;
+ }
+}
+
+
+BOOLEAN
+Os2DispatchVector(
+ IN PDBGKM_APIMSG ReceiveMsg,
+ POS2_THREAD Thread,
+ CONTEXT Context
+ )
+{
+
+ struct VectorHandlerRec {
+ ULONG VecHandler[6];
+ ULONG doscallssel;
+ };
+ struct VectorHandlerRec VectorHandler;
+ ULONG NewSp;
+ USHORT Args[4];
+ USHORT FPUStatus = 0;
+ NTSTATUS Status;
+
+ //
+ // Read Vector handler Record for this process
+ //
+ Status = NtReadVirtualMemory(Thread->Process->ProcessHandle,
+ Thread->Process->VectorHandler,
+ (PVOID) &VectorHandler,
+ sizeof(struct VectorHandlerRec),
+ NULL
+ );
+ if (!(NT_SUCCESS(Status))) {
+ return TRUE; // Dispatch failed
+ }
+ //
+ // Place on stack of process the machine status word and the return
+ // CS:IP of the process which is running before changing the CS:IP
+ // to the vector handler.
+ //
+ Args[3] = (USHORT) Context.EFlags; // flags
+ Args[2] = (USHORT) Context.SegCs; // CS
+ Args[1] = (USHORT) (Context.Eip & 0xffff); // IP
+
+ //
+ // Change CS:IP to vector handler address
+ //
+ switch(ReceiveMsg->u.Exception.ExceptionRecord.ExceptionCode) {
+ case STATUS_INTEGER_DIVIDE_BY_ZERO:
+ Context.SegCs = VectorHandler.VecHandler[0] >> 16;
+ Context.Eip = VectorHandler.VecHandler[0] & 0xffff;
+ break;
+ case STATUS_INTEGER_OVERFLOW:
+ Context.SegCs = VectorHandler.VecHandler[1] >> 16;
+ Context.Eip = VectorHandler.VecHandler[1] & 0xffff;
+ break;
+ case STATUS_ARRAY_BOUNDS_EXCEEDED:
+ Context.SegCs = VectorHandler.VecHandler[2] >> 16;
+ Context.Eip = VectorHandler.VecHandler[2] & 0xffff;
+ break;
+ case STATUS_ILLEGAL_INSTRUCTION:
+ Context.SegCs = VectorHandler.VecHandler[3] >> 16;
+ Context.Eip = VectorHandler.VecHandler[3] & 0xffff;
+ break;
+ case STATUS_ILLEGAL_FLOAT_CONTEXT:
+ Context.SegCs = VectorHandler.VecHandler[4] >> 16;
+ Context.Eip = VectorHandler.VecHandler[4] & 0xffff;
+ break;
+ case STATUS_FLOAT_DENORMAL_OPERAND:
+ FPUStatus = (USHORT) Context.FloatSave.StatusWord;
+ Context.SegCs = VectorHandler.VecHandler[5] >> 16;
+ Context.Eip = VectorHandler.VecHandler[5] & 0xffff;
+ break;
+ case STATUS_FLOAT_DIVIDE_BY_ZERO:
+ FPUStatus = (USHORT) Context.FloatSave.StatusWord;
+ Context.SegCs = VectorHandler.VecHandler[5] >> 16;
+ Context.Eip = VectorHandler.VecHandler[5] & 0xffff;
+ break;
+ case STATUS_FLOAT_INEXACT_RESULT:
+ FPUStatus = (USHORT) Context.FloatSave.StatusWord;
+ Context.SegCs = VectorHandler.VecHandler[5] >> 16;
+ Context.Eip = VectorHandler.VecHandler[5] & 0xffff;
+ break;
+ case STATUS_FLOAT_INVALID_OPERATION:
+ FPUStatus = (USHORT) Context.FloatSave.StatusWord;
+ Context.SegCs = VectorHandler.VecHandler[5] >> 16;
+ Context.Eip = VectorHandler.VecHandler[5] & 0xffff;
+ break;
+ case STATUS_FLOAT_OVERFLOW:
+ FPUStatus = (USHORT) Context.FloatSave.StatusWord;
+ Context.SegCs = VectorHandler.VecHandler[5] >> 16;
+ Context.Eip = VectorHandler.VecHandler[5] & 0xffff;
+ break;
+ case STATUS_FLOAT_STACK_CHECK:
+ FPUStatus = (USHORT) Context.FloatSave.StatusWord;
+ Context.SegCs = VectorHandler.VecHandler[5] >> 16;
+ Context.Eip = VectorHandler.VecHandler[5] & 0xffff;
+ break;
+ case STATUS_FLOAT_UNDERFLOW:
+ FPUStatus = (USHORT) Context.FloatSave.StatusWord;
+ Context.SegCs = VectorHandler.VecHandler[5] >> 16;
+ Context.Eip = VectorHandler.VecHandler[5] & 0xffff;
+ break;
+ }
+
+ //
+ // Check to see if a vector handler exists
+ //
+ if (Context.SegCs == (VectorHandler.doscallssel >> 16)) {
+ return TRUE; // Dispatch failed
+ }
+
+ if (FPUStatus != 0) {
+ //
+ // mask floating point exceptions
+ //
+ Context.FloatSave.ControlWord |= 0x3f;
+
+ Args[0] = FPUStatus;
+ }
+
+ //
+ // Remove 32-bit eip, cs, Eflags from stack put on 16-bit ip, cs, flags
+ //
+ NewSp = (ULONG)(SELTOFLAT(Context.SegSs)) + (USHORT) Context.Esp;
+ Context.Esp += (FPUStatus == 0 ? 3 : 4) * sizeof(USHORT);
+ NewSp += (FPUStatus == 0 ? 3 : 4) * sizeof(USHORT);
+ Status = NtWriteVirtualMemory( Thread->Process->ProcessHandle,
+ (PVOID) NewSp,
+ (FPUStatus == 0 ? &Args[1] : &Args[0]),
+ (FPUStatus == 0 ? 3 : 4) * sizeof(USHORT),
+ NULL
+ );
+ if (!NT_SUCCESS( Status )) {
+ return TRUE; // Dispatch failed
+ }
+
+ Context.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
+ Status = NtSetContextThread(Thread->ThreadHandle, &Context);
+
+ if (!NT_SUCCESS( Status )) {
+ return TRUE; // Dispatch failed
+ }
+
+ return FALSE; // Dispatch completed
+
+}
+
+
+VOID
+Os2IssueSignalTree(
+ IN POS2_PROCESS RootProcess,
+ IN int Signal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine recursively issues a "Signal" signal to thread one
+ of each process in a tree.
+
+Arguments:
+
+ RootProcess - root process of tree to issue Signal to
+
+ Signal - signal to send
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ PLIST_ENTRY ListHead, ListNext;
+
+ Os2IssueSignal( RootProcess, Signal );
+
+ ListHead = &RootProcess->ChildrenList;
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ Os2IssueSignalTree( CONTAINING_RECORD( ListNext,
+ OS2_PROCESS,
+ SiblingLink
+ ),
+ Signal
+ );
+ ListNext = ListNext->Flink;
+ }
+}
+
+
+APIRET
+Os2IssueSignal(
+ IN POS2_PROCESS Process,
+ IN int Signal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine recursively issues a "Signal" signal to thread one
+ of a process.
+
+Arguments:
+
+ Process - process to Signal
+
+ Signal - signal to send
+
+Return Value:
+
+ ERROR_INVALID_PROCID - the specified process is dying.
+
+ ERROR_SIGNAL_PENDING - the specified signal is already pending for the
+ thread.
+
+--*/
+
+{
+ POS2_THREAD Thread1;
+ APIRET rc;
+ Thread1 = CONTAINING_RECORD( Process->ThreadList.Flink, OS2_THREAD, Link );
+ if (IsListEmpty( &Process->ThreadList )) {
+ //
+ // Process Termination in progress, no threads left to signal
+ //
+
+#if DBG
+ IF_OS2_DEBUG( EXCEPTIONS ) {
+ DbgPrint("Os2IssueSignal: Process is dying\n");
+ }
+#endif
+ return(ERROR_INVALID_PROCID);
+ }
+ if (Thread1->Dying == TRUE) {
+ rc = ERROR_INVALID_PROCID;
+ }
+ else {
+ rc = SendSignalException(Thread1, Signal);
+ }
+
+ return rc;
+}
+
+
+BOOLEAN
+Os2DosRegisterCtrlHandler(
+ IN POS2_THREAD t,
+ IN POS2_API_MSG m
+ )
+{
+
+ POS2_REGISTER_HANDLER a = &m->u.DosRegisterCtrlHandler;
+ POS2_PROCESS Process;
+ POS2_SESSION Session;
+ POS2_REGISTER_HANDLER_REC pRec;
+ POS2_REGISTER_HANDLER_REC pPRec;
+
+ Process = t->Process;
+ Session = Process->Session;
+
+ if (a->fAction == SIGA_ENABLE_HANDLING) {
+ Process->CtrlHandlerFlag = TRUE;
+ return TRUE;
+ }
+
+ if (a->fAction == SIGA_KILL) {
+ pRec = Session->RegisterCtrlHandler;
+ pPRec = pRec;
+ while (pRec != NULL) {
+ if (pRec->Process == Process && pRec->Signal == a->usFlagNum) {
+ if (pPRec != Session->RegisterCtrlHandler) {
+ pPRec->Link = pRec->Link;
+ }
+ else {
+ Session->RegisterCtrlHandler = pRec->Link;
+ }
+ RtlFreeHeap(Os2Heap, 0, pRec);
+ break;
+ }
+ pPRec = pRec;
+ pRec = pRec->Link;
+ }
+ return(TRUE);
+ }
+
+ pPRec = (POS2_REGISTER_HANDLER_REC)
+ RtlAllocateHeap(Os2Heap, 0,
+ sizeof(OS2_REGISTER_HANDLER_REC));
+ if (pPRec == NULL) {
+#if DBG
+ DbgPrint("Os2DosRegisterCtrlHandler, no memory for heap\n");
+#endif
+ ASSERT(FALSE);
+ return (TRUE);
+ }
+ pPRec->Signal = a->usFlagNum;
+ pPRec->fAction = a->fAction;
+ pPRec->Process = Process;
+
+
+ if (Session->RegisterCtrlHandler == NULL) {
+ Session->RegisterCtrlHandler = pPRec;
+ pPRec->Link = NULL;
+ }
+ else {
+ pRec = Session->RegisterCtrlHandler;
+ Session->RegisterCtrlHandler = pPRec;
+ pPRec->Link = pRec;
+ }
+
+ return(TRUE);
+
+}
+
+VOID
+Os2DeRegisterCtrlHandler(
+ POS2_PROCESS Process
+ )
+{
+
+ POS2_REGISTER_HANDLER_REC pRec;
+ POS2_REGISTER_HANDLER_REC pPRec;
+ POS2_REGISTER_HANDLER_REC pRecTmp;
+
+ POS2_SESSION Session;
+
+ Session = Process->Session;
+ if(Session!=NULL) {
+ pRec = Session->RegisterCtrlHandler;
+ pPRec = pRec;
+
+ while (pRec != NULL) {
+ if (pRec->Process == Process) {
+ if (pRec == Session->RegisterCtrlHandler) {
+ Session->RegisterCtrlHandler = pRec->Link;
+ pPRec = pRec->Link;
+ }
+ else {
+ pPRec->Link = pRec->Link;
+ }
+ pRecTmp = pRec->Link;
+ RtlFreeHeap(Os2Heap, 0, pRec);
+ pRec = pRecTmp;
+
+ }
+ else {
+ pPRec = pRec;
+ pRec = pRec->Link;
+ }
+
+ }
+ }
+ return;
+
+}
diff --git a/private/os2/server/wait.c b/private/os2/server/wait.c
new file mode 100644
index 000000000..2d88260c2
--- /dev/null
+++ b/private/os2/server/wait.c
@@ -0,0 +1,187 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ wait.c
+
+Abstract:
+
+ This module contains the primitives to implement the OS/2 Wait functions
+
+Author:
+
+ Steve Wood (stevewo) 23-Oct-1989
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_ERRORS
+#include "os2srv.h"
+
+BOOLEAN
+Os2InitializeWait(
+ IN OS2_WAIT_ROUTINE WaitRoutine,
+ IN POS2_THREAD WaitingThread,
+ IN OUT POS2_API_MSG WaitReplyMessage,
+ IN PVOID WaitParameter,
+ OUT POS2_WAIT_BLOCK *WaitBlockPtr
+ )
+
+{
+ ULONG Length;
+ POS2_WAIT_BLOCK WaitBlock;
+
+ Length = sizeof( *WaitBlock ) - sizeof( WaitBlock->WaitReplyMessage ) +
+ WaitReplyMessage->h.u1.s1.TotalLength;
+
+ WaitBlock = RtlAllocateHeap( Os2Heap, 0, Length );
+ if (WaitBlock == NULL) {
+ WaitReplyMessage->ReturnedErrorValue = ERROR_NOT_ENOUGH_MEMORY;
+ return( FALSE );
+ }
+
+ WaitBlock->Length = Length;
+ WaitBlock->WaitingThread = WaitingThread;
+ WaitBlock->WaitParameter = WaitParameter;
+ WaitingThread->WaitBlock = WaitBlock;
+ WaitBlock->WaitRoutine = WaitRoutine;
+ InitializeListHead( &WaitBlock->UserLink );
+ InitializeListHead( &WaitBlock->Link );
+ RtlMoveMemory( &WaitBlock->WaitReplyMessage,
+ WaitReplyMessage,
+ WaitReplyMessage->h.u1.s1.TotalLength
+ );
+ *WaitBlockPtr = WaitBlock;
+ return TRUE;
+}
+
+BOOLEAN
+Os2CreateWait(
+ IN OS2_WAIT_REASON WaitReason,
+ IN OS2_WAIT_ROUTINE WaitRoutine,
+ IN POS2_THREAD WaitingThread,
+ IN OUT POS2_API_MSG WaitReplyMessage,
+ IN PVOID WaitParameter,
+ IN PLIST_ENTRY UserLinkListHead OPTIONAL
+ )
+{
+ POS2_WAIT_BLOCK WaitBlock;
+
+ ASSERT( WaitReason < MaxWaitReason );
+
+ if (WaitingThread->CurrentSignals != 0) {
+ WaitReplyMessage->ReturnedErrorValue = ERROR_INTERRUPT;
+ return( FALSE );
+ }
+
+ if (!Os2InitializeWait(WaitRoutine,
+ WaitingThread,
+ WaitReplyMessage,
+ WaitParameter,
+ &WaitBlock))
+ return FALSE;
+
+ InsertTailList( &Os2WaitLists[ WaitReason ], &WaitBlock->Link );
+
+ if ( ARGUMENT_PRESENT(UserLinkListHead) ) {
+ InsertTailList( UserLinkListHead, &WaitBlock->UserLink );
+ }
+
+ return( TRUE );
+}
+
+BOOLEAN
+Os2NotifyWaitBlock(
+ IN POS2_WAIT_BLOCK WaitBlock,
+ IN OS2_WAIT_REASON WaitReason,
+ IN PVOID SatisfyParameter1,
+ IN PVOID SatisfyParameter2
+ )
+{
+ if (WaitBlock == NULL){
+#if DBG
+ DbgPrint("Os2NotifyWaitBlockRoutine - NULL Block\n");
+#endif
+ return(FALSE);
+ }
+
+ if ((*WaitBlock->WaitRoutine)( WaitReason,
+ WaitBlock->WaitingThread,
+ &WaitBlock->WaitReplyMessage,
+ WaitBlock->WaitParameter,
+ SatisfyParameter1,
+ SatisfyParameter2
+ )
+ ) {
+
+ if ( WaitBlock->Link.Flink ) {
+ RemoveEntryList( &WaitBlock->Link );
+ }
+ if ( WaitBlock->UserLink.Flink ) {
+ RemoveEntryList( &WaitBlock->UserLink );
+ }
+ WaitBlock->WaitingThread->WaitBlock = NULL;
+ // NtReplyPort( WaitBlock->WaitingThread->Process->ClientPort,
+ NtReplyPort( Os2SessionPort,
+ (PPORT_MESSAGE)&WaitBlock->WaitReplyMessage
+ );
+ RtlFreeHeap( Os2Heap, 0, WaitBlock );
+ return( TRUE );
+ } else {
+ return( FALSE );
+ }
+}
+
+BOOLEAN
+Os2NotifyWait(
+ IN OS2_WAIT_REASON WaitReason,
+ IN PVOID SatisfyParameter1,
+ IN PVOID SatisfyParameter2
+ )
+{
+ PLIST_ENTRY ListHead, ListNext;
+ POS2_WAIT_BLOCK WaitBlock;
+ BOOLEAN Result;
+
+ ASSERT( WaitReason < MaxWaitReason );
+
+ Result = FALSE;
+
+ ListHead = &Os2WaitLists[ WaitReason ];
+ ListNext = ListHead->Flink;
+ while (ListNext != ListHead) {
+ WaitBlock = CONTAINING_RECORD( ListNext, OS2_WAIT_BLOCK, Link );
+ ListNext = ListNext->Flink;
+ Result |= Os2NotifyWaitBlock( WaitBlock,
+ WaitReason,
+ SatisfyParameter1,
+ SatisfyParameter2
+ );
+ }
+
+ return( Result );
+}
+
+
+VOID
+Os2DestroyWait(
+ IN POS2_WAIT_BLOCK WaitBlock
+ )
+{
+
+ try {
+ WaitBlock->WaitingThread->WaitBlock = NULL;
+ RemoveEntryList( &WaitBlock->Link );
+
+ if ( WaitBlock->UserLink.Flink ) {
+ RemoveEntryList( &WaitBlock->UserLink );
+ }
+
+ RtlFreeHeap( Os2Heap, 0, WaitBlock );
+ } except( EXCEPTION_EXECUTE_HANDLER ) {
+ return;
+ }
+}
diff --git a/private/os2/server/xtlexec.c b/private/os2/server/xtlexec.c
new file mode 100644
index 000000000..fd70d203a
--- /dev/null
+++ b/private/os2/server/xtlexec.c
@@ -0,0 +1,256 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ xtlexec.c
+
+Abstract:
+
+ User Mode routines for creating user mode processes and threads.
+
+Author:
+
+ Steve Wood (stevewo) 18-Aug-1989
+
+Revision History:
+
+ Yaron Shamir (YaronS) 18-June-1991
+ Cut a lot and modify to the needs of os2ss. User mode only
+
+--*/
+
+#define INCL_OS2V20_TASKING
+#define INCL_OS2V20_ERRORS
+#include "os2srv.h"
+#include <nturtl.h>
+#define NTOS2_ONLY
+#include "sesport.h"
+#include "os2tile.h"
+
+
+NTSTATUS
+XtlRemoteCall(
+ HANDLE Process,
+ HANDLE Thread,
+ PVOID CallSite,
+ ULONG ArgumentCount,
+ PULONG Arguments,
+ BOOLEAN PassContext,
+ BOOLEAN AlreadySuspended,
+ PVOID CritSectionAddr
+ )
+
+/*++
+
+Routine Description:
+
+ This function calls a procedure in another thread/process, using
+ NtGetContext and NtSetContext. Parameters are passed to the
+ target procedure via its stack.
+
+Arguments:
+
+ Process - Handle of the target process
+
+ Thread - Handle of the target thread within that process
+
+ CallSite - Address of the procedure to call in the target process.
+
+ ArgumentCount - Number of 32 bit parameters to pass to the target
+ procedure.
+
+ Arguments - Pointer to the array of 32 bit parameters to pass.
+
+ PassContext - TRUE if an additional parameter is to be passed that
+ points to a context record.
+
+ AlreadySuspended - TRUE if the target thread is already in a suspended
+ or waiting state.
+
+ CritSectionAddr - Address of critical section of code that we should
+ not suspend process in.
+
+Return Value:
+
+ Status - Status value
+
+--*/
+
+{
+ NTSTATUS Status;
+ CONTEXT Context;
+ ULONG NewSp;
+ LARGE_INTEGER timeout;
+ PLARGE_INTEGER ptimeout = &timeout;
+ ULONG Count;
+ ULONG ArgumentsCopy[5];
+ ULONG SuspendCount;
+
+ if (ArgumentCount > 4)
+ return STATUS_INVALID_PARAMETER;
+
+ //
+ // If necessary, suspend the guy before with we mess with his stack.
+ //
+ if (!AlreadySuspended) {
+ Status = NtSuspendThread(Thread, NULL);
+ if (!NT_SUCCESS(Status)) {
+ return( Status );
+ }
+ }
+
+ //
+ // Get the context record for the target thread.
+ //
+ Count = 0;
+ while (TRUE) {
+ Context.ContextFlags = CONTEXT_FULL;
+ Status = NtGetContextThread(Thread, &Context);
+ if (!NT_SUCCESS(Status)) {
+ if (!AlreadySuspended) {
+ NtResumeThread(Thread, NULL);
+ }
+ if (!NT_SUCCESS(Status)) {
+ return(Status);
+ }
+ }
+
+ //
+ // Check that process context not in the middle of thunking
+ // between 16-bit & 32-bit code. We can not be any were between
+ // EntryFlat and the start of the first thunk. That means we can not
+ // be in the ExitFlat code. But we can be in the code for any of the
+ // thunks or beyond "Od2SignalDeliverer"
+ //
+ if ((Context.SegCs != 0x1b) || (Context.SegSs == 0x23)){
+
+/*
+ (Context.Eip < (ULONG) CritSectionAddr) ||
+ (Context.Eip > (ULONG) CritSectionAddr + 0x66C0)) {
+*/
+ if (Context.SegCs == 0x1b) {
+ Context.SegSs = Context.SegDs = Context.SegEs = 0x23;
+ }
+ break;
+ }
+
+ //
+ // At this point process is in thunk see if it was suspended, if it
+ // is not much we can do.
+ //
+ if (AlreadySuspended) {
+ ASSERT(FALSE);
+ return(TRUE);
+ }
+
+ do {
+ NtResumeThread(Thread, &SuspendCount);
+ } while (SuspendCount);
+
+ //
+ // Let process run.
+ //
+ timeout.LowPart = 0x989680; // wait one second
+ timeout.HighPart = 0;
+ NtWaitForSingleObject(Thread, (BOOLEAN)TRUE, ptimeout);
+
+ if (Count++ == 10) {
+ ASSERT(FALSE);
+ return TRUE;
+ }
+
+ //
+ // Try again
+ //
+ Status = NtSuspendThread(Thread, NULL);
+ if (!NT_SUCCESS(Status)) {
+ ASSERT(NT_SUCCESS(Status));
+ }
+ }
+
+ //
+ // Pass all parameters on the stack, regardless of whether a
+ // a context record is passed.
+ //
+
+ //
+ // Put Context Record on stack first, so it is above other args.
+ //
+ if (Context.SegSs != 0x23) {
+ NewSp = ((ULONG)(SELTOFLAT(Context.SegSs)) + (USHORT) Context.Esp) & 0xfffffffc;
+ }
+ else {
+ NewSp = Context.Esp;
+ }
+
+ if (PassContext) {
+ NewSp -= sizeof( CONTEXT );
+ Status = NtWriteVirtualMemory( Process,
+ (PVOID)NewSp,
+ &Context,
+ sizeof( CONTEXT ),
+ NULL
+ );
+ if (!NT_SUCCESS( Status )) {
+ if (!AlreadySuspended) {
+ NtResumeThread( Thread, NULL );
+ }
+ return( Status );
+ }
+ ArgumentsCopy[0] = NewSp; // pass pointer to context
+ RtlMoveMemory(&(ArgumentsCopy[1]),Arguments,ArgumentCount*sizeof( ULONG ));
+ ArgumentCount++;
+ }
+ else {
+ RtlMoveMemory(ArgumentsCopy,Arguments,ArgumentCount*sizeof( ULONG ));
+ }
+
+ //
+ // Copy the arguments onto the target stack
+ //
+ if (ArgumentCount) {
+ NewSp -= ArgumentCount * sizeof( ULONG );
+ Status = NtWriteVirtualMemory( Process,
+ (PVOID)NewSp,
+ ArgumentsCopy,
+ ArgumentCount * sizeof( ULONG ),
+ NULL
+ );
+ if (!NT_SUCCESS( Status )) {
+ if (!AlreadySuspended) {
+ NtResumeThread( Thread, NULL );
+ }
+ return( Status );
+ }
+ }
+
+ //
+ // Set the address of the target code into Eip, the new target stack
+ // into Esp, and reload context to make it happen.
+ //
+ Context.SegSs = Context.SegDs = Context.SegEs = 0x23;
+ Context.SegCs = 0x1b;
+ Context.Esp = NewSp;
+ Context.Eip = (ULONG)CallSite;
+ Status = NtSetContextThread( Thread, &Context );
+
+ // Don't resume the thread here. It will be resumed by the caller. The
+ // reason for this is that that sometimes caller wan't to perform some
+ // operations on suspended thread. For example it might be want to alert
+ // the thread. In such cases (signal deliverer is the case, actually)
+ // the thread will call to NtTestAlert in order to remove alert flag
+ // just in the case that it wasn't waiting for any alertable object.
+ // If the thread will be not suspended, the call to NtTestAlert might be
+ // executed before the server will alert it. Further, it will cause that
+ // for the first time the thread will wait on any alertable object
+ // NtWaitForSingleObject will return STATUS_ALERT (not good, but this is
+ // NT bug).
+ //if (!AlreadySuspended) {
+ // NtResumeThread( Thread, NULL );
+ //}
+
+ return( Status );
+}
+
diff --git a/private/os2/ssrtl/consys.c b/private/os2/ssrtl/consys.c
new file mode 100644
index 000000000..fabc68d51
--- /dev/null
+++ b/private/os2/ssrtl/consys.c
@@ -0,0 +1,966 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ consys.c
+
+Abstract:
+
+ This module contains CONFIG.SYS related parsing routines.
+
+Author:
+
+ Ofer Porat (oferp) 8-Nov-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include "os2ssrtl.h"
+
+
+#define WBLANK(ch) ((ch) == L' ' || (ch) == L'\t')
+
+
+typedef struct _INDEX_T {
+
+ UNICODE_STRING Src;
+ UNICODE_STRING Dest;
+
+} INDEX_T, *PINDEX_T;
+
+
+
+//
+// This routine skips over white space in a unicode string
+// either forward or backward.
+// Str -- address of pointer to string.
+// Direction -- either FWD or BWD.
+//
+
+VOID
+Or2SkipWWS(
+ IN OUT PWSTR *Str,
+ IN LONG Direction
+ )
+{
+ PWSTR q = *Str;
+
+ while (WBLANK(*q)) {
+ q += Direction;
+ }
+ *Str = q;
+}
+
+
+//
+// This routine converts a null terminated unicode string to upper case.
+// It is similar to wcsupr(). It exists because I'm not sure wcsupr()
+// actually uses the Unicode convention.
+//
+// Str -- string to convert.
+//
+
+VOID
+Or2UnicodeStrupr(
+ IN OUT PWSTR Str
+ )
+{
+ while (*Str != UNICODE_NULL) {
+ *Str = RtlUpcaseUnicodeChar(*Str);
+ Str++;
+ }
+}
+
+
+//
+// This routine compares 2 null-terminated unicode strings. The comparison
+// has a count limiting the number of chars compared, and the comparison is
+// case insensitive. It is similar to wcsnicmp(). It exists because I'm not
+// sure wcsnicmp() actually uses the Unicode convention.
+//
+// Str1, Str2 -- strings to compare.
+// Count -- max # of chars to compare.
+// return value -- TRUE if they're equal to within Count characters. FALSE otherwise.
+//
+
+BOOLEAN
+Or2UnicodeEqualCI(
+ IN PWSTR Str1,
+ IN PWSTR Str2,
+ IN ULONG Count
+ )
+{
+ while (Count != 0) {
+
+ if (*Str1 == UNICODE_NULL) {
+
+ if (*Str2 == UNICODE_NULL) {
+ return(TRUE);
+ }
+
+ return(FALSE);
+ }
+
+ if (RtlUpcaseUnicodeChar(*Str1) != RtlUpcaseUnicodeChar(*Str2)) {
+
+ return(FALSE);
+ }
+
+ Str1++; Str2++; Count--;
+ }
+ return(TRUE);
+}
+
+
+//
+// This routine appends a source path list to a destination path list. multiple occurences
+// of the same path are removed.
+//
+// HeapHandle -- a handle to a heap for temporary allocations
+// SrcPath -- a null terminated unicode string. It must be in uppercase for elimination of
+// multiple paths to occur. This path list is appended to DestPath.
+// DestPath -- an already existing counted unicode string containing the path list to be appended
+// to. The case is unimportant. The result is stored back in this string.
+// ExpandIt -- Should be TRUE in DestPath contains unexpanded %...% type strings. FALSE otherwise.
+// return value -- TRUE on success, FALSE otherwise.
+//
+// Possible Errors Effect
+// =============== ======
+// allocation failure Does nothing, return value FALSE
+// can't expand the
+// DestPath Does nothing, return value FALSE
+// DestPath MaxLen
+// exceeded during
+// append Stop on the last path that fits, return value TRUE
+//
+
+BOOLEAN
+Or2AppendPathToPath(
+ IN PVOID HeapHandle,
+ IN PWSTR SrcPath,
+ IN OUT PUNICODE_STRING DestPath,
+ IN BOOLEAN ExpandIt
+ )
+{
+ WCHAR wch;
+ WCHAR wch1;
+ WCHAR wch2;
+ PWSTR p;
+ PWSTR q;
+ PWSTR r;
+ PWSTR t;
+ USHORT l;
+ USHORT addsemi;
+ UNICODE_STRING Expanded;
+ UNICODE_STRING Tmp;
+ BOOLEAN Found;
+ NTSTATUS Status;
+
+ Expanded.Buffer = (PWSTR) RtlAllocateHeap(HeapHandle, 0, DestPath->MaximumLength + sizeof(WCHAR));
+
+ if (Expanded.Buffer == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2AppendPathPath: can't allocate Expanded from heap\n"));
+ }
+#endif
+ return(FALSE);
+ }
+
+ Expanded.MaximumLength = DestPath->MaximumLength;
+
+ if (ExpandIt) {
+
+ Status = RtlExpandEnvironmentStrings_U(NULL,
+ DestPath,
+ &Expanded,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2AppendPathToPath: can't expand environment strings, rc = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(HeapHandle, 0, Expanded.Buffer);
+ return(FALSE);
+ }
+
+ } else {
+
+ RtlCopyUnicodeString(&Expanded, DestPath);
+ }
+
+ Expanded.Buffer[Expanded.Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ Or2UnicodeStrupr(Expanded.Buffer);
+
+ addsemi = 2;
+
+ if (Expanded.Length == 0 ||
+ Expanded.Buffer[Expanded.Length/sizeof(WCHAR) - 1] == L';') {
+
+ addsemi = 0;
+ }
+
+ while (TRUE) {
+
+ Or2SkipWWS(&SrcPath, FWD);
+
+ wch = *SrcPath;
+
+ if (wch == UNICODE_NULL) {
+ break;
+ }
+
+ if (wch == L';') {
+ SrcPath++;
+ continue;
+ }
+
+ p = wcschr(SrcPath, L';');
+
+ if (p == NULL) {
+
+ p = SrcPath + wcslen(SrcPath);
+ q = p - 1;
+
+ } else {
+
+ q = p - 1;
+ p++;
+ }
+
+ Or2SkipWWS(&q, BWD);
+
+ l = q - SrcPath + 1;
+
+ wch = *(q+1);
+ *(q+1) = UNICODE_NULL;
+ t = Expanded.Buffer;
+ Found = FALSE;
+
+ while (TRUE) {
+
+ r = wcsstr(t, SrcPath);
+
+ if (r == NULL) {
+ break;
+ }
+
+ if (r == Expanded.Buffer) {
+ wch1 = L';';
+ } else {
+ wch1 = *(r-1);
+ }
+
+ wch2 = r[l];
+
+ if ((wch1 == L';' || WBLANK(wch1)) &&
+ (wch2 == L';' || WBLANK(wch2) || wch2 == UNICODE_NULL)) {
+
+ Found = TRUE;
+ break;
+ }
+
+ t = r + l;
+ }
+
+ *(q+1) = wch;
+
+ if (Found) {
+ SrcPath = p;
+ continue;
+ }
+
+ Tmp.Buffer = SrcPath;
+ Tmp.Length = l * sizeof(WCHAR);
+ Tmp.MaximumLength = Tmp.Length;
+
+ if (Expanded.Length + addsemi + Tmp.Length > Expanded.MaximumLength ||
+ DestPath->Length + addsemi + Tmp.Length > DestPath->MaximumLength) {
+
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2AppendPathToPath: Path buffer overflow\n"));
+ }
+#endif
+ break; // out of string space, terminate processing.
+ }
+
+ if (addsemi) {
+
+ RtlAppendUnicodeToString(&Expanded, L";");
+ RtlAppendUnicodeToString(DestPath, L";");
+
+ } else {
+
+ addsemi = 2;
+ }
+
+ RtlAppendUnicodeStringToString(&Expanded, &Tmp);
+ RtlAppendUnicodeStringToString(DestPath, &Tmp);
+
+ Expanded.Buffer[Expanded.Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ SrcPath = p;
+ }
+
+ DestPath->Buffer[DestPath->Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+ RtlFreeHeap(HeapHandle, 0, Expanded.Buffer);
+ return(TRUE);
+}
+
+
+//
+// This routine takes a counted unicode string containing a path-list with %...% type strings in it.
+// It prepares a pool of characters containing the expansions of paths with %...% strings in them.
+// Also prepared is an index table. Each entry in the index table contains a counted string pointing
+// to the point in DestPath where the unexpanded path is, and a counted string pointing to the the pool
+// where the expanded path is.
+//
+// SrcPath -- a counted unicode string containing the path-list to generate an index for.
+// Pool -- a buffer containing space for SrcPath.MaximumLength wide characters. This is where
+// the expanded strings will be stored.
+// Ind -- a buffer containing enough space to allocate as many index entries as necessary to index
+// the path list. One way to know how many may be necessary is to count the # of semicolons in
+// SrcPath.
+// IndSize -- will contain the number of entries placed in Ind on exit.
+//
+// Possible Errors Effect
+// =============== ======
+// SrcPath.MaximumLength
+// characters are not
+// enough to store the
+// pool of expanded env
+// strings. Stops after the last expanded env string that fits in the pool.
+//
+
+static
+VOID
+Or2IndexPath(
+ IN PUNICODE_STRING SrcPath,
+ OUT PWSTR Pool,
+ OUT PINDEX_T Ind,
+ OUT PULONG IndSize
+ )
+{
+ PWSTR CurPool = Pool;
+ USHORT PoolQuota = SrcPath->MaximumLength;
+ ULONG IndEx = 0;
+ PWCHAR wp = SrcPath->Buffer;
+ PWCHAR wq, wr;
+ BOOLEAN HasPercent;
+ NTSTATUS Status;
+
+ for (; ; ) {
+
+ Or2SkipWWS(&wp, FWD);
+
+ if (*wp == UNICODE_NULL) {
+ break;
+ }
+
+ HasPercent = FALSE;
+
+ wq = wp;
+
+ while (*wq != L';' && *wq != UNICODE_NULL) {
+ if (*wq == L'%') {
+ HasPercent = TRUE;
+ }
+ wq++;
+ }
+
+ if (*wq == L';') {
+ wr = wq + 1;
+ } else {
+ wr = wq;
+ }
+
+ if (!HasPercent) {
+ wp = wr;
+ continue;
+ }
+
+ wq--;
+
+ Or2SkipWWS(&wq, BWD);
+
+ Ind[IndEx].Dest.Buffer = wp;
+ Ind[IndEx].Dest.Length = (wq - wp + 1) * sizeof(WCHAR);
+ Ind[IndEx].Dest.MaximumLength = Ind[IndEx].Dest.Length;
+
+ wp = wr;
+
+ Ind[IndEx].Src.Buffer = CurPool;
+ Ind[IndEx].Src.MaximumLength = PoolQuota;
+
+ Status = RtlExpandEnvironmentStrings_U(NULL,
+ &Ind[IndEx].Dest,
+ &Ind[IndEx].Src,
+ NULL);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2IndexPath: can't expand environment strings, rc = %lx\n", Status));
+ }
+#endif
+ break;
+ }
+
+ PoolQuota -= Ind[IndEx].Src.Length;
+ CurPool += Ind[IndEx].Src.Length / sizeof(WCHAR);
+
+ Ind[IndEx].Src.MaximumLength = Ind[IndEx].Src.Length;
+
+ IndEx++;
+ }
+
+ *IndSize = IndEx;
+}
+
+
+//
+// This routine takes a destination path-list and a source path list. The destination path-list
+// is completely replaced with the source path list. The destination list may contain %...% strings.
+// The source list is not expected to contain %...% strings. While the replacement is done, any
+// paths in the source which already exist in the destination in a form containing %...% strings, are
+// retained with their original %...% form.
+//
+// HeapHandle -- a handle to a heap for temporary allocations
+// SrcPath -- a null terminated unicode string containing the replacing path-list.
+// DestPath -- an already existing counted unicode string containing the path list to be replaced
+// to. The result is stored back in this string.
+// return value -- TRUE on success, FALSE otherwise.
+//
+// Possible Errors Effect
+// =============== ======
+// allocation failure Does nothing, return value FALSE
+// DestPath MaxLen
+// exceeded during
+// replace Stop on the last path that fits, return value TRUE
+//
+
+BOOLEAN
+Or2ReplacePathByPath(
+ IN PVOID HeapHandle,
+ IN PWSTR SrcPath,
+ IN OUT PUNICODE_STRING DestPath
+ )
+{
+ PINDEX_T Ind;
+ PWSTR Pool;
+ PWSTR p;
+ PWSTR q;
+ WCHAR wch;
+ ULONG IndSize;
+ ULONG SemiCount;
+ ULONG i;
+ USHORT addsemi;
+ UNICODE_STRING Target;
+ UNICODE_STRING Tmp;
+
+ Target.Buffer = (PWSTR) RtlAllocateHeap(HeapHandle, 0, DestPath->MaximumLength + sizeof(WCHAR));
+
+ if (Target.Buffer == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2ReplacePathByPath: can't allocate Target from heap\n"));
+ }
+#endif
+ return(FALSE);
+ }
+
+ Target.MaximumLength = DestPath->MaximumLength;
+ Target.Length = 0;
+
+ Pool = (PWSTR) RtlAllocateHeap(HeapHandle, 0, (ULONG) DestPath->MaximumLength);
+
+ if (Pool == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2ReplacePathByPath: can't allocate Pool from heap\n"));
+ }
+#endif
+ RtlFreeHeap(HeapHandle, 0, Target.Buffer);
+ return(FALSE);
+ }
+
+ SemiCount = 1;
+
+ for (i = 0; i < DestPath->Length/sizeof(WCHAR); i++) {
+ if (DestPath->Buffer[i] == L';') {
+ SemiCount++;
+ }
+ }
+
+ Ind = (PINDEX_T) RtlAllocateHeap(HeapHandle, 0, SemiCount * sizeof(INDEX_T));
+
+ if (Ind == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2ReplacePathByPath: can't allocate Ind from heap\n"));
+ }
+#endif
+ RtlFreeHeap(HeapHandle, 0, Pool);
+ RtlFreeHeap(HeapHandle, 0, Target.Buffer);
+ return(FALSE);
+ }
+
+ Or2IndexPath(DestPath, Pool, Ind, &IndSize);
+
+ addsemi = 0;
+
+ while (TRUE) {
+
+ Or2SkipWWS(&SrcPath, FWD);
+
+ wch = *SrcPath;
+
+ if (wch == UNICODE_NULL) {
+ break;
+ }
+
+ if (wch == L';') {
+ SrcPath++;
+ continue;
+ }
+
+ p = wcschr(SrcPath, L';');
+
+ if (p == NULL) {
+
+ p = SrcPath + wcslen(SrcPath);
+ q = p - 1;
+
+ } else {
+
+ q = p - 1;
+ p++;
+ }
+
+ Or2SkipWWS(&q, BWD);
+
+ Tmp.Buffer = SrcPath;
+ Tmp.Length = (q - SrcPath + 1) * sizeof(WCHAR);
+ Tmp.MaximumLength = Tmp.Length;
+
+ for (i = 0; i < IndSize; i++) {
+
+ if (RtlEqualUnicodeString(&Tmp, &Ind[i].Src, TRUE)) {
+
+ Tmp = Ind[i].Dest;
+ break;
+ }
+ }
+
+ if (Target.Length + addsemi + Tmp.Length > Target.MaximumLength) {
+
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2ReplacePathByPath: Path buffer overflow\n"));
+ }
+#endif
+ break; // out of string space, terminate processing.
+ }
+
+ if (addsemi) {
+
+ RtlAppendUnicodeToString(&Target, L";");
+
+ } else {
+
+ addsemi = 2;
+ }
+
+ RtlAppendUnicodeStringToString(&Target, &Tmp);
+
+ SrcPath = p;
+ }
+
+ RtlCopyUnicodeString(DestPath, &Target);
+
+ DestPath->Buffer[DestPath->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ RtlFreeHeap(HeapHandle, 0, Ind);
+ RtlFreeHeap(HeapHandle, 0, Pool);
+ RtlFreeHeap(HeapHandle, 0, Target.Buffer);
+ return(TRUE);
+}
+
+
+//
+// This routine appends a terminating semicolon to a path list, if that path list
+// does not have a semicolon in it (in other words, if the path list contains only
+// one path).
+//
+// Str - The string to do semicolon processing on.
+//
+
+VOID
+Or2CheckSemicolon(
+ IN OUT PUNICODE_STRING Str
+ )
+{
+ USHORT i;
+ BOOLEAN flag;
+
+ if (Str->Length == 0 || Str->Length >= Str->MaximumLength) {
+ return;
+ }
+
+ flag = FALSE;
+
+ for(i = 0; i < Str->Length/ (USHORT) sizeof(WCHAR); i++) {
+ if (Str->Buffer[i] == L';') {
+ flag = TRUE;
+ break;
+ }
+ }
+
+ if (!flag) {
+ Str->Buffer[i++] = L';';
+ Str->Buffer[i] = UNICODE_NULL;
+ Str->Length += sizeof(WCHAR);
+ }
+}
+
+
+//
+// This routine fetches a path-list type environment variable from the registry.
+//
+// Data - an unallocated counted unicode string to hold the result.
+// HeapHandle -- a handle to a heap where we allocate from.
+// MaxSiz -- The MaximumLength Data should be given.
+// EnvKey -- a handle to the registry key in which the environment to be searched is.
+// ValueName -- a null-terminated unicode name of the registry value to fetch.
+// ExpandIt -- If TRUE, the registry value is expanded for %..% type strings before returning it.
+// return value -- TRUE on success, FALSE otherwise.
+//
+// Possible Errors Effect
+// =============== ======
+// allocation failure Data.Buffer = NULL, return value FALSE
+// requested env variable
+// doesn't exist, or
+// can't query its value Data is allocated and given 0 length, return value TRUE
+// can't expand the
+// env variable Data is allocated and given 0 length, return value TRUE
+//
+
+BOOLEAN
+Or2GetEnvPath(
+ OUT PUNICODE_STRING Data,
+ IN PVOID HeapHandle,
+ IN USHORT MaxSiz,
+ IN HANDLE EnvKey,
+ IN PWSTR ValueName,
+ IN BOOLEAN ExpandIt
+ )
+{
+ PKEY_VALUE_PARTIAL_INFORMATION Buf;
+ UNICODE_STRING ExpBuf;
+ UNICODE_STRING ValueName_U;
+ UNICODE_STRING tmp;
+ ULONG ResultLength;
+ ULONG l1, l2;
+ NTSTATUS Status;
+
+ Data->Buffer = NULL;
+
+ l1 = ((ULONG) MaxSiz + 1) * sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION);
+
+ Buf = (PKEY_VALUE_PARTIAL_INFORMATION) RtlAllocateHeap(HeapHandle, 0, l1);
+
+ if (Buf == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2GetEnvPath: can't allocate Buf from heap\n"));
+ }
+#endif
+ return(FALSE);
+ }
+
+ if (ExpandIt) {
+
+ l2 = ((ULONG) MaxSiz + 1) * sizeof(WCHAR);
+
+ ExpBuf.Buffer = (PWSTR) RtlAllocateHeap(HeapHandle, 0, l2);
+
+ if (ExpBuf.Buffer == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2GetEnvPath: can't allocate ExpBuf from heap\n"));
+ }
+#endif
+ RtlFreeHeap(HeapHandle, 0, Buf);
+ return(FALSE);
+ }
+
+ ExpBuf.MaximumLength = MaxSiz * sizeof(WCHAR);
+ }
+
+ RtlInitUnicodeString(&ValueName_U, ValueName);
+ Status = NtQueryValueKey(EnvKey,
+ &ValueName_U,
+ KeyValuePartialInformation,
+ Buf,
+ l1,
+ &ResultLength
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("OS2SSRTL(Or2GetEnvPath): FAILED - NtQueryValueKey %lx\n", Status));
+ }
+#endif
+ if (ExpandIt) {
+ RtlFreeHeap(HeapHandle, 0, Buf);
+ ExpBuf.Length = 0;
+ ExpBuf.Buffer[0] = UNICODE_NULL;
+ *Data = ExpBuf;
+ } else {
+ *((PWSTR) Buf) = UNICODE_NULL;
+ Data->Buffer = (PWSTR) Buf;
+ Data->Length = 0;
+ Data->MaximumLength = MaxSiz * sizeof(WCHAR);
+ }
+
+ return(TRUE);
+ }
+
+ if (ExpandIt) {
+ RtlInitUnicodeString(&tmp, (PWSTR) Buf->Data);
+
+ Status = RtlExpandEnvironmentStrings_U(NULL,
+ &tmp,
+ &ExpBuf,
+ NULL);
+
+ RtlFreeHeap(HeapHandle, 0, Buf);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("OS2SSRTL(Or2GetEnvPath): FAILED - RtlExpandEnvironmentStrings_U %lx\n", Status));
+ }
+#endif
+ ExpBuf.Buffer[0] = UNICODE_NULL;
+ ExpBuf.Length = 0;
+ *Data = ExpBuf;
+ return(TRUE);
+ }
+
+ ExpBuf.Buffer[ExpBuf.Length/sizeof(WCHAR)] = UNICODE_NULL;
+ *Data = ExpBuf;
+
+ } else {
+
+ l2 = Buf->DataLength;
+ RtlMoveMemory(Buf, Buf->Data, l2);
+ Data->Buffer = (PWSTR) Buf;
+ Data->Length = (USHORT) (l2 - sizeof(WCHAR));
+ Data->MaximumLength = MaxSiz * sizeof(WCHAR);
+ }
+
+ return(TRUE);
+}
+
+
+//
+// This is a general routine to parse an environment. It loops over the lines in the environment, and
+// identifies the variable in each line. For each variable, it searches a user dispatch table, and if
+// that dispatch table contains an entry for this variable, it calls the user supplied routine with the
+// name and value of the variable.
+//
+// Environment -- The environment to process. This is either in multi-string format, or a
+// (null|^Z)-terminated string consisting of lines separated by crlfs.
+// DispatchTable -- A dispatch table used to process the environment.
+// NumberOfDispatchItems -- Contains the number of entries in DispatchTable.
+// DelimOption -- specifies whether Environment is a multi-string (NULL_DELIM) or a string of crlf
+// separated lines (CRLF_DELIM).
+//
+// Description of the DispatchTable:
+// This is an array of structures of type ENVIRONMENT_DISPATCH_TABLE_ENTRY.
+// Each entry specifies a particular variable which should be handled.
+// an entry contains:
+// -- the name of the variable to operate on (this is case-insensitive).
+// -- a string of possible characters that serve as delimiters for the variable name (e.g. =, space, tab).
+// -- a DispatchFunction. This function is dispatched with 6 parameters:
+// -- the index in the dispatch table which triggered this call.
+// -- a user defined pointer, see below.
+// -- a pointer to the variable name in the environment.
+// -- length of the variable name (in chars).
+// -- a pointer to the variable value in the environment.
+// -- length of the variable value (in chars).
+// -- a user defined pointer that is passed to the dispatch function.
+//
+// The dispatch function may do anything it likes with the information it gets, and it
+// is not expected to return any value.
+//
+// A special value of "*" in the variable name field of an entry indicates that any variable name
+// is to be processed by the DispatchFunction. The DispatchFunction can figure out the name of
+// the variable it was called for by examining its parameters. If this option is used together
+// with a Delimeters value of NULL, no delimiter will be searched for, the line will be passed
+// as is with Name and Value both pointing to the beginning of the line (and ValueLen containing
+// its length)
+//
+
+VOID
+Or2IterateEnvironment(
+ IN PWSTR Environment,
+ IN ENVIRONMENT_DISPATCH_TABLE DispatchTable,
+ IN ULONG NumberOfDispatchItems,
+ IN ULONG DelimOption
+ )
+{
+ PWSTR Src;
+ PWSTR Tmp;
+ PWSTR Eol;
+ PWSTR NextLine;
+ ULONG i, m;
+ LONG l;
+ BOOLEAN Flag;
+
+ if (NumberOfDispatchItems == 0 || Environment == NULL || DispatchTable == NULL) {
+ return;
+ }
+
+ Src = Environment;
+ while (*Src != UNICODE_NULL) {
+ Or2SkipWWS(&Src, FWD);
+
+ if (DelimOption == CRLF_DELIM &&
+ *Src == L'\32') { // ^Z terminates file on CRLF delim texts
+ break;
+ }
+
+ for (i = 0; i < NumberOfDispatchItems; i++) {
+
+ if (DispatchTable[i].VarName[0] == L'*') {
+
+ if (DispatchTable[i].Delimiters == NULL) {
+
+ //
+ // No delimeter required. If the line is empty
+ // we don't process it.
+ //
+
+ if (*Src == UNICODE_NULL) {
+ continue;
+ }
+
+ if (DelimOption == CRLF_DELIM &&
+ (*Src == L'\r' || *Src == L'\n')) {
+ continue;
+ }
+
+ l = -1; // process the line from start
+ break;
+ }
+
+ Tmp = Src;
+ l = 0;
+ while (TRUE) {
+ if (*Tmp == UNICODE_NULL ||
+ (DelimOption == CRLF_DELIM && (*Tmp == L'\r' || *Tmp == L'\n' || *Tmp == L'\32'))) {
+ Flag = FALSE;
+ break;
+ }
+ if (wcschr(DispatchTable[i].Delimiters, RtlUpcaseUnicodeChar(*Tmp)) != NULL) {
+ Flag = TRUE;
+ break;
+ }
+ Tmp++;
+ l++;
+ }
+
+ if (Flag) {
+ break;
+ }
+ continue;
+ }
+
+ l = wcslen(DispatchTable[i].VarName);
+
+ if (Or2UnicodeEqualCI(Src, DispatchTable[i].VarName, (ULONG)l) &&
+ Src[l] != UNICODE_NULL &&
+ wcschr(DispatchTable[i].Delimiters, RtlUpcaseUnicodeChar(Src[l])) != NULL) {
+ break;
+ }
+ }
+
+ if (DelimOption == NULL_DELIM) {
+ Eol = Src + wcslen(Src);
+ NextLine = Eol + 1;
+ } else {
+ Eol = wcspbrk(Src, L"\r\n\32");
+ if (Eol == NULL) {
+ NextLine = Eol = Src + wcslen(Src);
+ } else {
+ NextLine = Eol;
+ if (*Eol != L'\32') {
+ while (*NextLine == L'\r' || *NextLine == L'\n') {
+ NextLine++;
+ }
+ }
+ }
+ }
+
+ if (i == NumberOfDispatchItems || DispatchTable[i].DispatchFunction == NULL) {
+ Src = NextLine;
+ continue;
+ }
+
+ Tmp = Src + l + 1;
+ Or2SkipWWS(&Tmp, FWD);
+ if (Eol != Tmp) {
+ Eol--;
+ Or2SkipWWS(&Eol, BWD);
+ m = (Eol - Tmp) + 1;
+ } else {
+ m = 0;
+ }
+
+ DispatchTable[i].DispatchFunction(i, DispatchTable[i].UserParameter, Src, l, Tmp, m);
+
+ Src = NextLine;
+ }
+}
+
+
+//
+// Following is useful Dispatch Function for use with Or2IterateEnvironment.
+// It copies the parameters passed to it into a structure of type
+// ENVIRONMENT_SEARCH_RECORD. A pointer to the structure to fill must be
+// passed through the UserParameter in the Dispatch Table.
+//
+
+VOID
+Or2FillInSearchRecordDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ )
+{
+ PENVIRONMENT_SEARCH_RECORD p = (PENVIRONMENT_SEARCH_RECORD) UserParameter;
+
+ p->DispatchTableIndex = DispatchTableIndex;
+ p->Name = Name;
+ p->NameLen = NameLen;
+ p->Value = Value;
+ p->ValueLen = ValueLen;
+}
+
diff --git a/private/os2/ssrtl/datetime.c b/private/os2/ssrtl/datetime.c
new file mode 100644
index 000000000..f7b90c9f0
--- /dev/null
+++ b/private/os2/ssrtl/datetime.c
@@ -0,0 +1,130 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ datetime.c
+
+Abstract:
+
+ This module contains the function to retrive time and date information.
+
+Author:
+
+ Michael Jarus (mjarus) 04-Jan-1993
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_ERRORS
+#include "os2ssrtl.h"
+
+#if DBG
+extern ULONG Os2Debug;
+#endif
+
+
+APIRET
+Or2GetDateTimeInfo(
+ PLARGE_INTEGER pSystemTime,
+ PLARGE_INTEGER pLocalTime,
+ PTIME_FIELDS pNtDateTime,
+ PVOID pSystemInformation,
+ PSHORT pTimeZone
+ )
+{
+ NTSTATUS Status;
+ ULONG Remainder;
+ BOOLEAN Sign;
+ LARGE_INTEGER ZoneTime;
+ PSYSTEM_TIMEOFDAY_INFORMATION pLocalSystemInformation =
+ (PSYSTEM_TIMEOFDAY_INFORMATION)pSystemInformation;
+
+ Status = NtQuerySystemTime(
+ pSystemTime
+ );
+
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ IF_OS2_DEBUG ( TIMERS )
+ {
+ KdPrint(("Or2GetDateTimeInfo: NtQuerySystemTime rc %lx\n",
+ Status));
+ }
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_PARAMETER ));
+ }
+
+ //
+ // Convert UTC to Local time
+ //
+
+ Status = RtlSystemTimeToLocalTime (
+ pSystemTime,
+ pLocalTime
+ );
+
+ if (!NT_SUCCESS( Status ))
+ {
+#if DBG
+ IF_OS2_DEBUG ( TIMERS )
+ {
+ KdPrint(("Or2GetDateTimeInfo: RtlSystemTimeToLocalTime rc %lx\n",
+ Status));
+ }
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_PARAMETER ));
+ }
+
+ RtlTimeToTimeFields( pLocalTime, pNtDateTime );
+
+ Status = NtQuerySystemInformation (
+ SystemTimeOfDayInformation,
+ pSystemInformation,
+ sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
+ NULL
+ );
+
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG ( TIMERS )
+ {
+ KdPrint(("Or2sGetDateTimInfoe: NtQuerySystemInformation rc %lx\n",
+ Status));
+ }
+#endif
+ return (Or2MapNtStatusToOs2Error(Status, ERROR_INVALID_PARAMETER ));
+ }
+
+ if (pLocalSystemInformation->TimeZoneBias.HighPart < 0)
+ {
+ Sign = TRUE;
+ pLocalSystemInformation->TimeZoneBias = RtlLargeIntegerNegate(
+ pLocalSystemInformation->TimeZoneBias
+ );
+ } else
+ {
+ Sign = FALSE;
+ }
+
+ ZoneTime = RtlExtendedLargeIntegerDivide (
+ pLocalSystemInformation->TimeZoneBias,
+ 60*1000*10000, /* converts 100nSec to Min */
+ &Remainder
+ );
+
+ if (Sign)
+ {
+ *pTimeZone = -(SHORT)ZoneTime.LowPart;
+ } else
+ {
+ *pTimeZone = (SHORT)ZoneTime.LowPart;
+ }
+
+ return(0);
+}
+
diff --git a/private/os2/ssrtl/i386/setjmp.asm b/private/os2/ssrtl/i386/setjmp.asm
new file mode 100644
index 000000000..7e4c622d7
--- /dev/null
+++ b/private/os2/ssrtl/i386/setjmp.asm
@@ -0,0 +1,157 @@
+ page ,132
+ title setjmp - set and do long jump
+;***
+;setjmp.asm - set and do a long jump
+;
+; Copyright (c) 1985-1988, Microsoft Corporation. All rights reserved.
+;
+;Purpose:
+; defines setjmp() and longjmp() - set and do a long jump.
+; Stores machine state in a user-supplied buffer to set a jump
+; and then retores that state to perform a long jump.
+;
+; format of the buffer 'env':
+; -----------
+; | ebp | env+0
+; -----------
+; | edi | env+4
+; -----------
+; | esi | env+8
+; -----------
+; | ebx | env+12
+; -----------
+; | esp | env+16 (8)
+; -----------
+; | retaddr | env+20
+; -----------
+;
+; Calling longjmp(env,val); will generate a return of val to
+; the last call of setjmp(env) by restoring sp, bp, pc, and
+; other regs from buffer 'env' and doing a return. If val
+; is 0, 1 is returned; else val is returned.
+;
+;Revision History:
+; 10-19-83 RN initial version
+; 08-08-88 JCR 386 version
+; 10-24-88 JCR Cleaned up code for 386 only
+;
+;*******************************************************************************
+
+.386p
+ .xlist
+include ks386.inc
+ .list
+
+ OFFBP = 0
+ OFFBX = OFFBP + 4
+ OFFDI = OFFBX + 4
+ OFFSI = OFFDI + 4
+ OFFSP = OFFSI + 4
+ OFFRET = OFFSP + 4
+
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ page , 132
+ subttl "setjmp"
+
+;***
+;int setjmp(env) - save the current stack environment
+;
+;Purpose:
+; Saves the current stack environment in env so that longjmp
+; can jump back here at some later time.
+;
+;Entry:
+; jmp_buf env - buffer to save stack environment in
+;
+;Exit:
+; returns 0 after setting a jump point (saving environment)
+; if returns as a result of longjmp call, returns value that
+; that longjmp passed (1 if longjmp passed 0).
+;
+;Uses:
+;
+;Exceptions:
+;
+;*******************************************************************************
+
+ public _setjmp
+_setjmp proc
+ ; remember where we are now, so we can
+ ; come back later if we have to
+
+ mov eax,ebp ; save ebp
+ mov ebp,esp
+
+ mov edx,[ebp+4] ; edx=pointer to env
+
+ mov [edx+OFFBP],eax ; save ebp
+ mov [edx+OFFBX],ebx ; save ebx
+ mov [edx+OFFDI],edi ; save edi
+ mov [edx+OFFSI],esi ; save esi
+ mov [edx+OFFSP],esp ; save esp
+ mov ecx,[ebp]
+ mov [edx+OFFRET],ecx; save ret addr
+
+ mov ebp,eax ; restore ebp
+ xor eax,eax ; return 0
+
+ ret
+
+_setjmp endp
+
+
+page
+;***
+;longjmp(env, val) - Do a long jump
+;
+;Purpose:
+; Restores the stack environment set by setjmp(), thereby transfering
+; control to the point at which setjmp() was called. The specified
+; value will be returned by the setjmp() call.
+;
+;Entry:
+; jmp_buf env - buffer environment was previously stored in
+; int val - value setjmp() returns (0 will be returned as 1)
+;
+;Exit:
+; Routine does not exit - transfers control to place where
+; setjmp() was called.
+;
+;Uses:
+;
+;Exceptions:
+;
+;*******************************************************************************
+
+ public _longjmp
+_longjmp proc
+
+ mov ebp,esp
+ mov eax,[ebp+4+4]
+ ; return value; get it before we lose bp
+ or eax,eax ; see if arg is 0; if so, return 1
+ jnz short not0 ; return value != 0, so return it
+ inc eax ; set ax to 1
+not0:
+
+ mov edx,[ebp+4] ; ebx=pointer to env
+ mov ebx,[edx+OFFBX] ; restore ebx
+ mov edi,[edx+OFFDI] ; restore edi
+ mov esi,[edx+OFFSI] ; restore esi
+ mov esp,[edx+OFFSP] ; restore esp
+ mov ebp,esp ; ...to get into the old stack frame
+ mov ecx,[edx+OFFRET]; ret addr
+ mov [ebp],ecx ; restored
+ mov ebp,[edx+OFFBP]; restore ebp
+
+; now everything is completely set up for a return to the old context
+
+ ret
+
+_longjmp endp
+
+_TEXT ends
+ end
diff --git a/private/os2/ssrtl/makefile b/private/os2/ssrtl/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/os2/ssrtl/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/os2/ssrtl/nls.c b/private/os2/ssrtl/nls.c
new file mode 100644
index 000000000..71d666cb0
--- /dev/null
+++ b/private/os2/ssrtl/nls.c
@@ -0,0 +1,1136 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ nls.c
+
+Abstract:
+
+ This module implements the NLS string function for the OS2SS
+
+Author:
+
+ Michael Jarus (mjarus) 31-Mar-1993
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+
+#define OS2SS_SKIP_INCL_OS2V20
+#include "os2ssrtl.h"
+#include <windows.h>
+#include "os2win.h"
+#include "os2nls.h"
+#include "os2nt.h"
+
+
+
+int
+Or2NlsGetLocaleInfoA(
+ IN LCID LocaleID,
+ IN UINT CodePage,
+ IN LCTYPE LCType,
+ OUT LPSTR Buffer,
+ IN int Size
+ );
+
+ULONG
+Or2NlsGetULONGFromLocaleInfoW(
+ IN LCID LocaleID,
+ IN LCTYPE LCType,
+ IN int Size,
+ OUT PDWORD pRc
+ );
+
+ULONG
+Or2NlsUnicodeStringToInteger(
+ IN WCHAR *WString,
+ IN ULONG Base
+ );
+
+#if DBG
+BYTE Or2NlsGetCtryInfoStr[] = "Or2NlsGetCtryInfo";
+BYTE Or2NlsGetMapTableStr[] = "Or2NlsGetMapTable";
+BYTE Or2NlsGetLocaleInfoAStr[] = "Or2NlsGetLocaleInfoA";
+BYTE Or2NlsGetCountryFromLocaleStr[] = "Or2NlsGetCountryFromLocale";
+BYTE Or2NlsGetCPInfoStr[] = "Or2NlsGetCPInfo";
+BYTE Or2NlsGetULONGFromLocaleInfoWStr[] = "Or2NlsGetULONGFromLocaleInfoW";
+#endif
+
+
+//VOID
+//Or2InitMBString(
+// PANSI_STRING DestinationString,
+// PCSZ SourceString
+// )
+///*++
+//
+//Routine Description:
+//
+// This routine init an ASCII character string (buffer and length)
+//
+//Arguments:
+//
+// DestinationString - pointer to ansi string to put the result in
+//
+// SourceString - pointer to ansi null terminated string to read from
+//
+//Return Value:
+//
+//
+//Note:
+//
+//--*/
+//
+//{
+// RtlInitAnsiString(
+// DestinationString,
+// SourceString);
+//
+// return ;
+//}
+
+
+APIRET
+Or2MBStringToUnicodeString(
+ PUNICODE_STRING DestinationString,
+ PANSI_STRING SourceString,
+ BOOLEAN AllocateDestinationString
+ )
+/*++
+
+Routine Description:
+
+ This routine map a multibyte character string to its unicode character
+ counterpart.
+
+Arguments:
+
+ DestinationString - pointer to unicode string to get the mapping result
+
+ SourceString - pointer to ansi string to read string to map from
+
+ AllocateDestinationString - flag indicating if need to allocate space
+ for destination string
+
+Return Value:
+
+
+Note:
+
+ Or2ProcessCodePage is used as the code page for the mapping.
+
+ Or2CurrentCodePageIsOem is check to see if RtlOem NLS routines
+ can be used.
+
+--*/
+
+{
+ NTSTATUS Status;
+ int BufSize;
+ ULONG Rc;
+ WCHAR *Buffer;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "Or2MBStringToUnicodeString";
+
+ IF_OS2_DEBUG(NLS)
+ {
+ KdPrint(("%s: Code Page %lu(OEM flag %lu), String %s, Allocate %u\n",
+ FuncName, Or2ProcessCodePage, Or2CurrentCodePageIsOem,
+ SourceString->Buffer, AllocateDestinationString));
+ }
+#endif
+
+ if ( Or2CurrentCodePageIsOem )
+ {
+ /*
+ * if current CP is the OEM use the standart (and optimized)
+ * Rtl routine
+ */
+
+ Status = RtlOemStringToUnicodeString(
+ DestinationString,
+ (POEM_STRING)SourceString,
+ AllocateDestinationString
+ );
+
+ if (!NT_SUCCESS(Status))
+ {
+ return Or2MapNtStatusToOs2Error(Status, ERROR_NOT_ENOUGH_MEMORY);
+ }
+ } else
+ {
+ /*
+ * This is a replacement code for RtlOemStringToUnicodeString
+ * when code page is not the OEM one.
+ * The code allocates buffer from RtlProcessHeap() to behave
+ * idendical to the Rtl routine, so the RtlFreeUnicodeString
+ * can be called on both.
+ */
+
+ //
+ // handle empty string
+ //
+
+ if (SourceString->Length == 0 ||
+ SourceString->Buffer == NULL) {
+
+ if (AllocateDestinationString) {
+
+ DestinationString->Buffer = NULL;
+ DestinationString->MaximumLength = 0;
+ }
+
+ DestinationString->Length = 0;
+
+ return(NO_ERROR);
+ }
+
+ if (AllocateDestinationString)
+ {
+ BufSize = MultiByteToWideChar(
+ (UINT) Or2ProcessCodePage,
+ 0,
+ SourceString->Buffer,
+ SourceString->Length,
+ NULL,
+ 0);
+
+ if (BufSize == 0)
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG(NLS)
+ {
+ KdPrint(("%s: cannot query BufSize %lu\n", FuncName, Rc));
+ }
+#endif
+ return(Rc);
+ }
+
+ BufSize++;
+ BufSize *= sizeof(WCHAR);
+
+ Buffer = RtlAllocateHeap(RtlProcessHeap(), 0, BufSize);
+ if (Buffer == NULL)
+ {
+#if DBG
+ IF_OS2_DEBUG(NLS)
+ {
+ KdPrint(("%s: cannot allocate from heap\n", FuncName));
+ }
+#endif
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ DestinationString->MaximumLength = BufSize;
+ DestinationString->Length = BufSize - sizeof(WCHAR);
+ DestinationString->Buffer = Buffer;
+ }
+
+ BufSize = MultiByteToWideChar(
+ (UINT) Or2ProcessCodePage,
+ 0,
+ SourceString->Buffer,
+ //Copy terminating NULL char
+ SourceString->Length + 1,
+ DestinationString->Buffer,
+ DestinationString->MaximumLength / sizeof(WCHAR));
+
+ if (BufSize == 0)
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG(NLS)
+ {
+ KdPrint(("%s: cannot translate %lu\n", FuncName, Rc));
+ }
+#endif
+ if (AllocateDestinationString)
+ {
+ //RtlFreeUnicodeString(Buffer);
+ RtlFreeHeap(RtlProcessHeap(), 0, Buffer);
+ }
+
+ return(Rc);
+ }
+
+ DestinationString->Length = (BufSize - 1) * sizeof(WCHAR);
+ }
+
+ return (NO_ERROR);
+}
+
+
+BOOLEAN
+Or2CreateUnicodeStringFromMBz(
+ OUT PUNICODE_STRING DestinationString,
+ IN PCSZ SourceString
+ )
+/*++
+
+Routine Description:
+
+ This routine map a multibyte character string to its unicode character
+ counterpart.
+
+Arguments:
+
+ DestinationString - pointer to unicode string to get the mapping result
+
+ SourceString - pointer to ansi string to read string to map from
+
+Return Value:
+
+ TRUE - success
+
+Note:
+
+ Or2ProcessCodePage is used as the code page for the mapping.
+
+ Or2CurrentCodePageIsOem is check to see if RtlOem NLS routines
+ can be used.
+
+--*/
+
+{
+ ANSI_STRING String_A;
+
+ Or2InitMBString(&String_A, SourceString);
+
+ if ( Or2MBStringToUnicodeString(
+ DestinationString,
+ &String_A,
+ TRUE ))
+ {
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+
+APIRET
+Or2UnicodeStringToMBString(
+ PANSI_STRING DestinationString,
+ PUNICODE_STRING SourceString,
+ BOOLEAN AllocateDestinationString
+ )
+/*++
+
+Routine Description:
+
+ This routine map an unicode character string to its multibyte character
+ counterpart.
+
+Arguments:
+
+ DestinationString - pointer to ansi string to get the mapping result
+
+ SourceString - pointer to unicode string to read string to map from
+
+ AllocateDestinationString - flag indicating if need to allocate space
+ for destination string
+
+Return Value:
+
+
+Note:
+
+ Or2ProcessCodePage is used as the code page for the mapping.
+
+ Or2CurrentCodePageIsOem is check to see if RtlOem NLS routines
+ can be used.
+
+--*/
+
+{
+ NTSTATUS Status;
+ int BufSize;
+ ULONG Rc;
+ CHAR *Buffer;
+ BOOL UsedDefaultChar;
+#if DBG
+ PSZ FuncName;
+
+ FuncName = "Or2UnicodeStringToMBString";
+
+ IF_OS2_DEBUG(NLS)
+ {
+ KdPrint(("%s: Code Page %lu(OEM flag %lu), String %ws, Allocate %u\n",
+ FuncName, Or2ProcessCodePage, Or2CurrentCodePageIsOem,
+ SourceString->Buffer, AllocateDestinationString));
+ }
+#endif
+
+ if ( Or2CurrentCodePageIsOem )
+ {
+ /*
+ * if current CP is the OEM use the standart (and optimized)
+ * Rtl routine
+ */
+
+ Status = RtlUnicodeStringToOemString(
+ (POEM_STRING)DestinationString,
+ SourceString,
+ AllocateDestinationString
+ );
+
+ if (!NT_SUCCESS(Status))
+ {
+ return Or2MapNtStatusToOs2Error(Status, ERROR_NOT_ENOUGH_MEMORY);
+ }
+ } else
+ {
+ /*
+ * This is a replacement code for RtlUnicodeStringToOemString
+ * when code page is not the OEM one.
+ * The code allocates buffer from RtlProcessHeap() to behave
+ * idendical to the Rtl routine, so the RtlFreeOemString
+ * can be called on both.
+ */
+
+ //
+ // handle empty string
+ //
+
+ if (SourceString->Length == 0 ||
+ SourceString->Buffer == NULL) {
+
+ if (AllocateDestinationString) {
+
+ DestinationString->Buffer = NULL;
+ DestinationString->MaximumLength = 0;
+ }
+
+ DestinationString->Length = 0;
+
+ return(NO_ERROR);
+ }
+
+ if (AllocateDestinationString)
+ {
+ BufSize = WideCharToMultiByte(
+ (UINT) Or2ProcessCodePage,
+ 0,
+ SourceString->Buffer,
+ SourceString->Length / sizeof(WCHAR),
+ NULL,
+ 0,
+ NULL,
+ &UsedDefaultChar
+ );
+
+ if (BufSize == 0)
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG(NLS)
+ {
+ KdPrint(("%s: cannot query BufSize %lu\n", FuncName, Rc));
+ }
+#endif
+ return(Rc);
+ }
+
+ BufSize++;
+
+ Buffer = RtlAllocateHeap(RtlProcessHeap(), 0, BufSize);
+ if (Buffer == NULL)
+ {
+#if DBG
+ IF_OS2_DEBUG(NLS)
+ {
+ KdPrint(("%s: cannot allocate from heap\n", FuncName));
+ }
+#endif
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ }
+ DestinationString->MaximumLength = BufSize;
+ DestinationString->Length = BufSize - 1;
+ DestinationString->Buffer = Buffer;
+ }
+
+ BufSize = WideCharToMultiByte(
+ (UINT) Or2ProcessCodePage,
+ 0,
+ SourceString->Buffer,
+ //Copy terminating NULL char
+ SourceString->Length / sizeof(WCHAR) + 1,
+ DestinationString->Buffer,
+ DestinationString->MaximumLength,
+ NULL,
+ &UsedDefaultChar
+ );
+
+ if (BufSize == 0)
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG(NLS)
+ {
+ KdPrint(("%s: cannot translate %lu\n", FuncName, Rc));
+ }
+#endif
+ if (AllocateDestinationString)
+ {
+ //RtlFreeOemString(Buffer);
+ RtlFreeHeap(RtlProcessHeap(), 0, Buffer);
+ }
+
+ return(Rc);
+ }
+
+ DestinationString->Length = BufSize - 1;
+ }
+
+ return (NO_ERROR);
+}
+
+
+//VOID
+//Or2FreeMBString(
+// PANSI_STRING AnsiString
+// )
+///*++
+//
+//Routine Description:
+//
+// This routine free ansi string
+//
+//Arguments:
+//
+// AnsiString - pointer to ansi string
+//
+//Return Value:
+//
+//
+//Note:
+//
+//
+//--*/
+//
+//{
+// RtlFreeOemString(
+// (POEM_STRING)AnsiString
+// );
+//
+// return ;
+//}
+
+
+USHORT Or2NlsLangIdTable[] =
+{
+ LANG_GERMAN, LANG_ENGLISH, LANG_SPANISH,
+ LANG_FRENCH, LANG_ITALIAN, LANG_SWEDISH,
+#if 0 // no system message files yet(?)
+ LANG_DUTCH, LANG_DANISH, LANG_NORWEGIAN, LANG_PORTUGUESE,
+ LANG_FINNISH, LANG_JAPANESE, LANG_KOREAN, LANG_THAI,
+#endif
+#ifdef OS2SS_INCLUDE_HEBREW
+ LANG_HEBREW,
+#endif
+#ifdef OS2SS_INCLUDE_ARABIC
+ LANG_ARABIC,
+#endif
+#ifdef OS2SS_INCLUDE_PRCHINA
+ LANG_CHINESE,
+#endif
+ 0
+};
+
+
+DWORD
+Or2NlsGetCtryInfo(
+ IN LCID LocaleID,
+ IN UINT CodePage,
+ OUT PCOUNTRYINFO pCountryInfo
+ )
+{
+ int CountryLength;
+ DWORD Rc = 0;
+
+ memset(pCountryInfo, 0, sizeof(COUNTRYINFO));
+
+ /*
+ * country
+ */
+
+ pCountryInfo->country = Or2NlsGetULONGFromLocaleInfoW(
+ LocaleID,
+#ifdef JAPAN
+// MSKK Jun.24.1993 V-Akihis
+ LOCALE_IDEFAULTCOUNTRY,
+#else
+ LOCALE_ICOUNTRY,
+#endif
+ 6,
+ &Rc
+ );
+
+ /*
+ * code page
+ */
+
+ pCountryInfo->codepage = Or2NlsGetULONGFromLocaleInfoW(
+ LocaleID,
+ LOCALE_IDEFAULTCODEPAGE,
+ 6,
+ &Rc
+ );
+
+ /*
+ * fsDateFmt
+ */
+
+ pCountryInfo->fsDateFmt = Or2NlsGetULONGFromLocaleInfoW(
+ LocaleID,
+ LOCALE_IDATE,
+ 2,
+ &Rc
+ );
+
+ /*
+ * szCurrency
+ */
+
+ if (!(CountryLength = Or2NlsGetLocaleInfoA(
+ LocaleID,
+ CodePage,
+ LOCALE_SCURRENCY,
+ pCountryInfo->szCurrency,
+ 5)))
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES: Or2NlsGetCtryInfo cannot retrive currency indicator, rc %u\n",
+ Rc));
+ }
+#endif
+ }
+
+ /*
+ * szThousandsSeparator
+ */
+
+ if (!(CountryLength = Or2NlsGetLocaleInfoA(
+ LocaleID,
+ CodePage,
+ LOCALE_STHOUSAND,
+ pCountryInfo->szThousandsSeparator,
+ 2)))
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES: Or2NlsGetCtryInfo cannot retrive thousands separator, rc %u\n",
+ Rc));
+ }
+#endif
+ }
+
+ /*
+ * szDecimal
+ */
+
+ if (!(CountryLength = Or2NlsGetLocaleInfoA(
+ LocaleID,
+ CodePage,
+ LOCALE_SDECIMAL,
+ pCountryInfo->szDecimal,
+ 2)))
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES: Or2NlsGetCtryInfo cannot retrive decimal separator, rc %u\n",
+ Rc));
+ }
+#endif
+ }
+
+ /*
+ * szDateSeparator
+ */
+
+ if (!(CountryLength = Or2NlsGetLocaleInfoA(
+ LocaleID,
+ CodePage,
+ LOCALE_SDATE,
+ pCountryInfo->szDateSeparator,
+ 2)))
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES: Or2NlsGetCtryInfo cannot retrive date separator, rc %u\n",
+ Rc));
+ }
+#endif
+ }
+
+ /*
+ * szTimeSeparator
+ */
+
+ if (!(CountryLength = Or2NlsGetLocaleInfoA(
+ LocaleID,
+ CodePage,
+ LOCALE_STIME,
+ pCountryInfo->szTimeSeparator,
+ 2)))
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES: Or2NlsGetCtryInfo cannot retrive time separator, rc %u\n",
+ Rc));
+ }
+#endif
+ }
+
+ /*
+ * fsCurrencyFmt
+ */
+
+ pCountryInfo->fsCurrencyFmt = (UCHAR)Or2NlsGetULONGFromLocaleInfoW(
+ LocaleID,
+ LOCALE_ICURRENCY,
+ 2,
+ &Rc
+ );
+
+ /*
+ * cDecimalPlace
+ */
+
+ pCountryInfo->cDecimalPlace = (UCHAR)Or2NlsGetULONGFromLocaleInfoW(
+ LocaleID,
+ LOCALE_ICURRDIGITS,
+ 3,
+ &Rc
+ );
+
+ /*
+ * fsTimeFmt
+ */
+
+ pCountryInfo->fsTimeFmt = (UCHAR)Or2NlsGetULONGFromLocaleInfoW(
+ LocaleID,
+ LOCALE_ITIME,
+ 2,
+ &Rc
+ );
+
+ /*
+ * szDataSeparator
+ */
+
+ if (!(CountryLength = Or2NlsGetLocaleInfoA(
+ LocaleID,
+ CodePage,
+ LOCALE_SLIST,
+ pCountryInfo->szDataSeparator,
+ 2)))
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES: Or2NlsGetCtryInfo cannot retrive data separator, rc %u\n",
+ Rc));
+ }
+#endif
+ }
+
+ return(Rc);
+}
+
+
+DWORD
+Or2NlsGetMapTable(
+ IN LCID LocaleID,
+ IN UINT CodePage,
+ IN DWORD dwFlag,
+ OUT PUCHAR pTable
+ )
+{
+ int Length;
+ WCHAR SrcBuff[256], DestBuff[256];
+ DWORD Rc = 0, i;
+ UCHAR Buffer[256];
+ BOOL Bool;
+
+ for ( i = 0 ; i < 256 ; i++ )
+ {
+ //Buffer[i] = pTable[i] = (UCHAR)i;
+ Buffer[i] = (UCHAR)i;
+ }
+
+ if (Length = Or2WinMultiByteToWideChar(
+ #if DBG
+ Or2NlsGetMapTableStr,
+ #endif
+ CodePage,
+ OS2SS_NLS_MB_DEFAULT,
+ Buffer,
+ 256,
+ SrcBuff,
+ 256))
+ {
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ if (Length != 256)
+ {
+ KdPrint(("OS2SES: Or2NlsGetMapTable wrong length from MultByteToWideChar, Length %u, rc %u\n",
+ Length, GetLastError()));
+ }
+ }
+#endif
+ if(Length = Or2WinLCMapStringW (
+ #if DBG
+ Or2NlsGetMapTableStr,
+ #endif
+ LocaleID,
+ dwFlag,
+ SrcBuff,
+ 256,
+ DestBuff,
+ 256))
+ {
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ if (Length != 256)
+ {
+ KdPrint(("OS2SES: Or2NlsGetMapTable wrong length from LCMapStringW, Length %u, rc %u\n",
+ Length, GetLastError()));
+ }
+ }
+#endif
+ if (Length = Or2WinWideCharToMultiByte(
+ #if DBG
+ Or2NlsGetMapTableStr,
+ #endif
+ CodePage,
+ OS2SS_NLS_WC_DEFAULT,
+ DestBuff,
+ 256,
+ pTable,
+ 256,
+ NULL,
+ &Bool))
+ {
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ if (Length != 256)
+ {
+ KdPrint(("OS2SES: Or2NlsGetMapTable wrong length from WideCharToMultiByte, Length %u, rc %u\n",
+ Length, GetLastError()));
+ }
+ }
+#endif
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES: Or2NlsGetMapTable cannot WideCharToMultiByte, rc %u\n",
+ Rc));
+ }
+#endif
+ }
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES: Or2NlsGetMapTable cannot LCMapStringW, rc %u\n",
+ Rc));
+ }
+#endif
+ }
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES: Or2NlsGetMapTable cannot MultByteToWideChar, rc %u\n",
+ Rc));
+ }
+#endif
+ }
+
+ return(Rc);
+}
+
+
+int
+Or2NlsGetLocaleInfoA(
+ IN LCID LocaleID,
+ IN UINT CodePage,
+ IN LCTYPE LCType,
+ OUT LPSTR Buffer,
+ IN int Size
+ )
+{
+ int Length;
+ WCHAR WBuffer[10];
+ BOOL Bool;
+
+ Length = Or2WinGetLocaleInfoW(
+ #if DBG
+ Or2NlsGetLocaleInfoAStr,
+ #endif
+ LocaleID,
+ LCType,
+ WBuffer,
+ Size);
+
+ if (!Length)
+ {
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES: Or2NlsGetLocaleInfoA no info from GetLocaleInfoW, rc %u\n",
+ GetLastError()));
+ }
+#endif
+ } else
+ {
+ Length = Or2WinWideCharToMultiByte(
+ #if DBG
+ Or2NlsGetLocaleInfoAStr,
+ #endif
+ CodePage,
+ OS2SS_NLS_WC_DEFAULT,
+ WBuffer,
+ Length >> 1,
+ Buffer,
+ Size,
+ NULL,
+ &Bool);
+
+ if (!Length)
+ {
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES: Or2NlsGetLocaleInfoA no info from WideCharToMultiByte, rc %u\n",
+ GetLastError()));
+ }
+#endif
+ }
+ }
+
+ return(Length);
+}
+
+
+ULONG
+Or2NlsGetULONGFromLocaleInfoW(
+ IN LCID LocaleID,
+ IN LCTYPE LCType,
+ IN int Size,
+ OUT PDWORD pRc
+ )
+{
+ ULONG Length;
+ WCHAR WBuffer[10];
+
+ Length = Or2WinGetLocaleInfoW(
+ #if DBG
+ Or2NlsGetULONGFromLocaleInfoWStr,
+ #endif
+ LocaleID,
+ LCType,
+ WBuffer,
+ Size);
+
+ if (!Length)
+ {
+ *pRc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES: Or2NlsGetULONGFromLocaleInfoW no info from GetLocaleInfoW (type %x), rc %u\n",
+ LCType, *pRc));
+ }
+#endif
+ } else
+ {
+ Length = Or2NlsUnicodeStringToInteger(WBuffer, 10);
+ }
+
+ return(Length);
+}
+
+
+DWORD
+Or2NlsGetCountryFromLocale(
+ IN LCID LocaleID,
+ OUT PULONG pCountry
+ )
+{
+ int CountryLength;
+ WCHAR sCountryCode[7];
+ DWORD Rc = 0;
+
+ /*
+ * country
+ */
+
+#ifdef JAPAN
+// MSKK Jun.16.1993 V-AkihiS
+ *pCountry = 81;
+#else
+ *pCountry = 1;
+#endif
+
+ CountryLength = Or2WinGetLocaleInfoW(
+ #if DBG
+ Or2NlsGetCountryFromLocaleStr,
+ #endif
+ LocaleID,
+#ifdef JAPAN
+// MSKK Jun.24.1993 V-Akihis
+ LOCALE_IDEFAULTCOUNTRY,
+#else
+ LOCALE_ICOUNTRY,
+#endif
+ sCountryCode,
+ 6);
+
+ if (CountryLength)
+ {
+ *pCountry = Or2NlsUnicodeStringToInteger(sCountryCode, 10);
+
+ if (!*pCountry)
+ {
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES: Or2NlsGetCountryFromLocale cannot GetInteger for country code, rc %u\n",
+ GetLastError()));
+ }
+#endif
+#ifdef JAPAN
+// MSKK Jun.16.1993 V-AkihiS
+ *pCountry = 81;
+#else
+ *pCountry = 1;
+#endif
+ Rc = 1;
+ }
+ } else
+ {
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("OS2SES: Or2NlsGetCountryFromLocale cannot retrive country code, rc %u\n",
+ GetLastError()));
+ }
+#endif
+ Rc = 1;
+ }
+
+ return(Rc);
+}
+
+
+DWORD
+Or2NlsGetCPInfo(
+ IN UINT CP,
+ OUT POD2_DBCS_VECTOR_ENTRY pDBCSVec
+ )
+{
+ CPINFO CpInfo;
+ ULONG i;
+ DWORD Rc = NO_ERROR;
+
+ memset(pDBCSVec->Vector, 0, 12);
+ if ( Or2WinGetCPInfo(
+ #if DBG
+ Or2NlsGetCPInfoStr,
+ #endif
+ CP,
+ &CpInfo
+ ))
+ {
+ memmove(pDBCSVec->Vector, CpInfo.LeadByte, 12);
+ } else
+ {
+ Rc = GetLastError();
+#if DBG
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("Or2NlsGetCPInfo->GetCPInfo: Rc %lu\n",
+ Rc));
+ }
+#endif
+ }
+
+ for ( i = 0 ; i < 10 ; i += 2)
+ {
+ if (!pDBCSVec->Vector[i] && !pDBCSVec->Vector[i + 1])
+ {
+ break;
+ }
+ }
+ pDBCSVec->VectorSize = i + 2;
+
+ return(Rc);
+}
+
+
+ULONG
+Or2NlsUnicodeStringToInteger(
+ IN WCHAR *WString,
+ IN ULONG Base
+ )
+{
+ ULONG Code = 0;
+ NTSTATUS Status;
+ UNICODE_STRING UnicodeString;
+
+ RtlInitUnicodeString(
+ &UnicodeString,
+ WString);
+
+ Status = RtlUnicodeStringToInteger(
+ &UnicodeString,
+ Base,
+ &Code);
+
+#if DBG
+ if (! NT_SUCCESS( Status ))
+ {
+ IF_OS2_DEBUG( NLS )
+ {
+ KdPrint(("Or2NlsUnicodeStringToInteger: RtlUnicodeStringToInteger failed, Status %lu\n",
+ Status ));
+ }
+ }
+#endif
+ return(Code);
+}
+
diff --git a/private/os2/ssrtl/ntmap.c b/private/os2/ssrtl/ntmap.c
new file mode 100644
index 000000000..d2e0cf87f
--- /dev/null
+++ b/private/os2/ssrtl/ntmap.c
@@ -0,0 +1,606 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ntmap.c
+
+Abstract:
+
+ This module contains the functions to map NT values into OS/2 values
+ and/or vice versa. So far there are two functions defined:
+
+ Or2MapStatus - maps NT Status Code into an OS/2 Error Code
+
+ Or2MapProtectionToFlags - maps NT page protection flags into OS/2
+ page protection flags
+
+ Or2MapFlagsToProtection - maps OS/2 page protection flags into NT
+ page protection flags
+
+Author:
+
+ Steve Wood (stevewo) 07-Jul-1990
+
+Revision History:
+
+--*/
+
+#define INCL_OS2V20_MEMORY
+#define INCL_OS2V20_ERRORS
+#include "os2ssrtl.h"
+
+
+APIRET
+Or2MapStatus(
+ IN NTSTATUS Status
+ )
+{
+ //
+ // Map all warning and error status codes to comparable OS/2 error codes.
+ // Mappings that are defined, but probably incorrect, are marked with
+ // FIX, FIX. Mappings that are currently not defined are marked with
+ // the ERROR_SS_UNKNOWN_STATUS symbol. These later should be left as is
+ // unless you know of a case where the status code is legitimate for the
+ // OS/2 Subsystem and needs a defined mapping.
+ //
+
+ switch ( Status ) {
+ case STATUS_SUCCESS:
+ return( NO_ERROR);
+
+ case STATUS_GUARD_PAGE_VIOLATION:
+ return( ERROR_GUARDPAGE );
+
+ case STATUS_DATATYPE_MISALIGNMENT:
+ return( ERROR_NOACCESS ); // FIX, FIX - wait for new XCPT stuff
+
+ case STATUS_BREAKPOINT:
+ case STATUS_SINGLE_STEP:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_INTEGER_OVERFLOW:
+ return( ERROR_ARITHMETIC_OVERFLOW );
+
+ case STATUS_BUFFER_OVERFLOW:
+ return( ERROR_BUFFER_OVERFLOW );
+
+ case STATUS_NO_MORE_FILES:
+ return( ERROR_NO_MORE_FILES );
+
+ case STATUS_WAS_LOCKED:
+ case STATUS_NOT_LOCKED:
+ case STATUS_FILE_LOCK_CONFLICT:
+ case STATUS_LOCK_NOT_GRANTED:
+ case STATUS_RANGE_NOT_LOCKED:
+ case STATUS_WAS_UNLOCKED:
+ return( ERROR_LOCK_VIOLATION );
+
+ case STATUS_NO_MORE_EAS:
+ return( ERROR_NO_MORE_ITEMS ); // FIX, FIX - is this right?
+
+ case STATUS_UNSUCCESSFUL:
+ return( ERROR_GEN_FAILURE );
+
+ case STATUS_NOT_IMPLEMENTED:
+ return( ERROR_INVALID_FUNCTION );
+
+ case STATUS_INVALID_INFO_CLASS:
+ case STATUS_INFO_LENGTH_MISMATCH:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_ACCESS_VIOLATION:
+ return( ERROR_PROTECTION_VIOLATION ); // FIX, FIX - wait for new XCPT stuff
+
+ case STATUS_IN_PAGE_ERROR:
+ return( ERROR_SWAPERROR );
+
+ case STATUS_PAGEFILE_QUOTA:
+ return( ERROR_NOT_ENOUGH_MEMORY );
+
+ case STATUS_PAGEFILE_QUOTA_EXCEEDED:
+ return( ERROR_SWAP_FILE_FULL );
+
+ case STATUS_DISK_FULL:
+ case STATUS_COMMITMENT_LIMIT:
+ return( ERROR_DISK_FULL );
+
+ case STATUS_INVALID_HANDLE:
+ case STATUS_FILE_CLOSED:
+ case STATUS_FILE_FORCED_CLOSED:
+ return( ERROR_INVALID_HANDLE );
+
+ case STATUS_BAD_INITIAL_STACK:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_BAD_INITIAL_PC:
+ return( ERROR_BAD_EXE_FORMAT ); // FIX, FIX - should this be unknown?
+
+ case STATUS_INVALID_CID:
+ case STATUS_TIMER_NOT_CANCELED:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_INVALID_PARAMETER:
+ return( ERROR_INVALID_PARAMETER );
+
+ case STATUS_NO_SUCH_DEVICE:
+ return( ERROR_INVALID_PATH );
+
+ case STATUS_INVALID_DEVICE_REQUEST:
+ return( ERROR_INVALID_FUNCTION );
+
+ case STATUS_END_OF_FILE:
+ return( ERROR_HANDLE_EOF );
+
+ case STATUS_WRONG_VOLUME:
+ case STATUS_UNRECOGNIZED_MEDIA:
+ case STATUS_FILE_INVALID:
+ return( ERROR_WRONG_DISK );
+
+ case STATUS_NONEXISTENT_SECTOR:
+ return( ERROR_SECTOR_NOT_FOUND );
+
+ case STATUS_MORE_PROCESSING_REQUIRED:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_NO_MEMORY:
+ return( ERROR_NOT_ENOUGH_MEMORY );
+
+ case STATUS_NOT_MAPPED_VIEW:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_CONFLICTING_ADDRESSES:
+ case STATUS_UNABLE_TO_FREE_VM:
+ case STATUS_UNABLE_TO_DELETE_SECTION:
+ return( ERROR_INVALID_ADDRESS );
+
+ case STATUS_INVALID_SYSTEM_SERVICE:
+ return( ERROR_INVALID_FUNCTION );
+
+ case STATUS_ILLEGAL_INSTRUCTION:
+ return( NO_ERROR ); // FIX, FIX - wait for new XCPT stuff
+
+ case STATUS_INVALID_LOCK_SEQUENCE:
+ case STATUS_INVALID_VIEW_SIZE:
+ case STATUS_INVALID_FILE_FOR_SECTION:
+ case STATUS_ALREADY_COMMITTED:
+ case STATUS_ACCESS_DENIED:
+ case STATUS_CANNOT_DELETE:
+ case STATUS_NOT_A_DIRECTORY:
+ return( ERROR_ACCESS_DENIED );
+
+ case STATUS_DIRECTORY_NOT_EMPTY:
+ return( ERROR_CURRENT_DIRECTORY );
+
+ case STATUS_BUFFER_TOO_SMALL:
+ return( ERROR_INSUFFICIENT_BUFFER );
+
+ case STATUS_OBJECT_TYPE_MISMATCH:
+ return( ERROR_FILE_NOT_FOUND ); // FIX, FIX - is this bogus or not?
+
+ case STATUS_NONCONTINUABLE_EXCEPTION:
+ case STATUS_INVALID_DISPOSITION:
+ case STATUS_UNWIND:
+ case STATUS_BAD_STACK:
+ case STATUS_INVALID_UNWIND_TARGET:
+ return( NO_ERROR ); // FIX, FIX - wait for new XCPT stuff
+
+ case STATUS_PARITY_ERROR:
+ return( NO_ERROR ); // FIX, FIX - wait for new XCPT stuff
+
+ case STATUS_UNABLE_TO_DECOMMIT_VM:
+ return( ERROR_INVALID_ADDRESS );
+ break;
+
+ case STATUS_NOT_COMMITTED:
+ case STATUS_INVALID_PORT_ATTRIBUTES:
+ case STATUS_PORT_MESSAGE_TOO_LONG:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_INVALID_PARAMETER_MIX:
+ return( ERROR_INVALID_PARAMETER );
+
+ case STATUS_INVALID_QUOTA_LOWER:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_DISK_CORRUPT_ERROR:
+ return( ERROR_NOT_DOS_DISK ); // FIX, FIX - is this the best choice?
+
+ case STATUS_OBJECT_NAME_INVALID:
+ return( ERROR_INVALID_NAME );
+
+ case STATUS_OBJECT_PATH_NOT_FOUND:
+ case STATUS_OBJECT_PATH_INVALID:
+ case STATUS_OBJECT_PATH_SYNTAX_BAD:
+ case STATUS_REDIRECTOR_NOT_STARTED:
+ return( ERROR_PATH_NOT_FOUND );
+
+ case STATUS_NOT_SUPPORTED:
+ return( ERROR_NOT_SUPPORTED );
+
+ case STATUS_REMOTE_NOT_LISTENING:
+ return( ERROR_REM_NOT_LIST );
+
+ case STATUS_DUPLICATE_NAME:
+ return( ERROR_DUP_NAME );
+
+ case STATUS_BAD_NETWORK_PATH:
+ return( ERROR_BAD_NETPATH );
+
+ case STATUS_NETWORK_BUSY:
+ return( ERROR_NETWORK_BUSY );
+
+ case STATUS_DEVICE_DOES_NOT_EXIST:
+ return( ERROR_DEV_NOT_EXIST );
+
+ case STATUS_TOO_MANY_COMMANDS:
+ return( ERROR_TOO_MANY_CMDS );
+
+ case STATUS_ADAPTER_HARDWARE_ERROR:
+ return( ERROR_ADAP_HDW_ERR );
+
+ case STATUS_INVALID_NETWORK_RESPONSE:
+ return( ERROR_BAD_NET_RESP );
+
+ case STATUS_UNEXPECTED_NETWORK_ERROR:
+ return( ERROR_UNEXP_NET_ERR );
+
+ case STATUS_BAD_REMOTE_ADAPTER:
+ return( ERROR_BAD_REM_ADAP );
+
+ case STATUS_OBJECT_NAME_NOT_FOUND:
+ case STATUS_NO_SUCH_FILE:
+ case STATUS_DLL_NOT_FOUND:
+ case STATUS_FILE_IS_A_DIRECTORY:
+ case STATUS_DELETE_PENDING:
+ return( ERROR_FILE_NOT_FOUND );
+
+
+ case STATUS_OBJECT_NAME_COLLISION:
+ return( ERROR_FILE_EXISTS );
+
+ case STATUS_INVALID_PIPE_STATE:
+ case STATUS_PIPE_DISCONNECTED:
+ return( ERROR_PIPE_NOT_CONNECTED );
+
+ case STATUS_PIPE_BROKEN:
+ return( ERROR_BROKEN_PIPE );
+
+ case STATUS_BAD_NETWORK_NAME:
+ return( ERROR_BAD_NET_NAME );
+
+ case STATUS_VIRTUAL_CIRCUIT_CLOSED:
+ return( ERROR_VC_DISCONNECTED );
+
+ case STATUS_NET_WRITE_FAULT:
+ return( ERROR_NET_WRITE_FAULT );
+
+ case STATUS_PIPE_NOT_AVAILABLE:
+ return( ERROR_PIPE_BUSY );
+
+ case STATUS_PORT_DISCONNECTED:
+ case STATUS_DEVICE_ALREADY_ATTACHED:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_DATA_OVERRUN:
+ case STATUS_DATA_LATE_ERROR:
+ case STATUS_DATA_ERROR:
+ return( ERROR_BAD_LENGTH ); // FIX, FIX - is there a better choice?
+
+ case STATUS_CRC_ERROR:
+ return( ERROR_CRC );
+
+ case STATUS_SECTION_TOO_BIG:
+ case STATUS_PORT_CONNECTION_REFUSED:
+ case STATUS_INVALID_PORT_HANDLE:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_SHARING_VIOLATION:
+ return( ERROR_SHARING_VIOLATION );
+
+ case STATUS_QUOTA_EXCEEDED:
+ return( ERROR_NOT_ENOUGH_MEMORY );
+
+ case STATUS_INVALID_PAGE_PROTECTION:
+ return( ERROR_PMM_INVALID_FLAGS );
+
+ case STATUS_MUTANT_NOT_OWNED:
+ return( ERROR_NOT_OWNER );
+
+ case STATUS_SEMAPHORE_LIMIT_EXCEEDED:
+ return( ERROR_TOO_MANY_POSTS );
+
+ case STATUS_PORT_ALREADY_SET:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_SECTION_NOT_IMAGE:
+ case STATUS_SUSPEND_COUNT_EXCEEDED:
+ case STATUS_THREAD_IS_TERMINATING:
+ case STATUS_BAD_WORKING_SET_LIMIT:
+ case STATUS_INCOMPATIBLE_FILE_MAP:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_SECTION_PROTECTION:
+ return( ERROR_PMM_INVALID_FLAGS );
+
+ case STATUS_EAS_NOT_SUPPORTED:
+ return( ERROR_EAS_NOT_SUPPORTED );
+
+ case STATUS_NONEXISTENT_EA_ENTRY:
+ return( ERROR_INVALID_EA_NAME );
+
+ case STATUS_EA_TOO_LARGE:
+ return( ERROR_EA_LIST_TOO_LONG );
+
+ case STATUS_EA_CORRUPT_ERROR:
+ return( ERROR_EA_FILE_CORRUPT );
+
+ case STATUS_CTL_FILE_NOT_SUPPORTED:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_UNKNOWN_REVISION:
+ case STATUS_REVISION_MISMATCH:
+ case STATUS_INVALID_OWNER:
+ case STATUS_INVALID_PRIMARY_GROUP:
+ case STATUS_NO_IMPERSONATION_TOKEN:
+ case STATUS_CANT_DISABLE_MANDATORY:
+ case STATUS_NO_LOGON_SERVERS:
+ case STATUS_NO_SUCH_LOGON_SESSION:
+ case STATUS_NO_SUCH_PRIVILEGE:
+ case STATUS_PRIVILEGE_NOT_HELD:
+ case STATUS_INVALID_ACCOUNT_NAME:
+ case STATUS_USER_EXISTS:
+ case STATUS_NO_SUCH_USER:
+ case STATUS_GROUP_EXISTS:
+ case STATUS_NO_SUCH_GROUP:
+ case STATUS_SPECIAL_GROUP:
+ case STATUS_MEMBER_IN_GROUP:
+ case STATUS_MEMBER_NOT_IN_GROUP:
+ case STATUS_LAST_ADMIN:
+// return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+ return( ERROR_ACCESS_DENIED );
+
+ case STATUS_WRONG_PASSWORD:
+ return( ERROR_INVALID_PASSWORD );
+
+ case STATUS_ILL_FORMED_PASSWORD:
+ return( ERROR_INVALID_PASSWORD );
+
+ case STATUS_PASSWORD_RESTRICTION:
+ return( ERROR_INVALID_PASSWORD );
+
+ case STATUS_LOGON_FAILURE:
+ case STATUS_ACCOUNT_RESTRICTION:
+ case STATUS_INVALID_LOGON_HOURS:
+ case STATUS_INVALID_WORKSTATION:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_PASSWORD_EXPIRED:
+ return( ERROR_INVALID_PASSWORD );
+
+ case STATUS_ACCOUNT_DISABLED:
+ case STATUS_NONE_MAPPED:
+ case STATUS_TOO_MANY_LUIDS_REQUESTED:
+ case STATUS_LUIDS_EXHAUSTED:
+ case STATUS_INVALID_SUB_AUTHORITY:
+ case STATUS_INVALID_ACL:
+ case STATUS_INVALID_SID:
+ case STATUS_INVALID_SECURITY_DESCR:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_PROCEDURE_NOT_FOUND:
+ return( ERROR_PROC_NOT_FOUND );
+
+ case STATUS_INVALID_IMAGE_FORMAT:
+ return( ERROR_BAD_EXE_FORMAT );
+
+ case STATUS_INVALID_IMAGE_NE_FORMAT:
+ case STATUS_INVALID_IMAGE_LE_FORMAT:
+ return ( ERROR_BAD_FORMAT );
+
+ case STATUS_NO_TOKEN:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_INVALID_EA_NAME:
+ /*
+ BUBUG: Some cases where NT expects STATUS_INVALID_EA_NAME instead -
+ see filio204, variation 1
+ */
+ return( ERROR_INVALID_EA_NAME );
+
+ case STATUS_EA_LIST_INCONSISTENT:
+ return( ERROR_EA_LIST_INCONSISTENT );
+
+ case STATUS_NO_EAS_ON_FILE:
+ return( ERROR_NEED_EAS_FOUND ); // FIX, FIX - is there a mapping?
+
+ case STATUS_SERVER_DISABLED:
+ case STATUS_SERVER_NOT_DISABLED:
+ case STATUS_TOO_MANY_GUIDS_REQUESTED:
+ case STATUS_GUIDS_EXHAUSTED:
+ case STATUS_INVALID_ID_AUTHORITY:
+ case STATUS_AGENTS_EXHAUSTED:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_INVALID_VOLUME_LABEL:
+ case STATUS_SECTION_NOT_EXTENDED:
+ case STATUS_NOT_MAPPED_DATA:
+
+ case STATUS_RESOURCE_DATA_NOT_FOUND:
+ case STATUS_RESOURCE_TYPE_NOT_FOUND:
+ case STATUS_RESOURCE_NAME_NOT_FOUND:
+ return( ERROR_INVALID_PARAMETER );
+
+ case STATUS_ARRAY_BOUNDS_EXCEEDED:
+ case STATUS_FLOAT_DENORMAL_OPERAND:
+ case STATUS_FLOAT_DIVIDE_BY_ZERO:
+ case STATUS_FLOAT_INEXACT_RESULT:
+ case STATUS_FLOAT_INVALID_OPERATION:
+ case STATUS_FLOAT_OVERFLOW:
+ case STATUS_FLOAT_STACK_CHECK:
+ case STATUS_FLOAT_UNDERFLOW:
+ case STATUS_INTEGER_DIVIDE_BY_ZERO:
+ case STATUS_PRIVILEGED_INSTRUCTION:
+ return( NO_ERROR ); // FIX, FIX - wait for new XCPT stuff
+
+ case STATUS_TOO_MANY_PAGING_FILES:
+ case STATUS_ALLOTTED_SPACE_EXCEEDED:
+ case STATUS_INSUFFICIENT_RESOURCES:
+ return( ERROR_NOT_ENOUGH_MEMORY );
+
+ case STATUS_DFS_EXIT_PATH_FOUND:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+
+ case STATUS_DEVICE_PAPER_EMPTY:
+ return( ERROR_OUT_OF_PAPER );
+
+ case STATUS_NO_MEDIA_IN_DEVICE:
+ case STATUS_DEVICE_NOT_READY:
+ case STATUS_DEVICE_POWERED_OFF:
+ case STATUS_DEVICE_OFF_LINE:
+ case STATUS_DEVICE_NOT_CONNECTED:
+ case STATUS_DEVICE_POWER_FAILURE:
+ return( ERROR_NOT_READY );
+
+ case STATUS_MEDIA_WRITE_PROTECTED:
+ return( ERROR_WRITE_PROTECT );
+
+ case STATUS_DEVICE_DATA_ERROR:
+ return( ERROR_BAD_LENGTH ); // FIX, FIX - is there a better choice?
+
+ case STATUS_DEVICE_BUSY:
+ return( ERROR_BUSY ); // FIX, FIX - is there a better choice?
+
+ case STATUS_FREE_VM_NOT_AT_BASE:
+ case STATUS_MEMORY_NOT_ALLOCATED:
+ return( ERROR_INVALID_ADDRESS );
+
+ case STATUS_IO_TIMEOUT:
+ return( ERROR_SEM_TIMEOUT );
+
+ case STATUS_INSTANCE_NOT_AVAILABLE:
+ return( ERROR_PIPE_BUSY );
+
+ case STATUS_NOT_SAME_DEVICE:
+ return( ERROR_NOT_SAME_DEVICE );
+
+ default:
+ return( ERROR_SS_UNKNOWN_STATUS | (USHORT)Status );
+ }
+}
+
+
+UCHAR Or2MapFlagsTable[ 8 ] = {
+ 0, // 0
+ PAGE_READONLY, // PAG_READ
+ PAGE_READWRITE, // PAG_WRITE
+ PAGE_READWRITE, // PAG_READ | PAG_WRITE
+ PAGE_EXECUTE, // PAG_EXECUTE
+ PAGE_EXECUTE_READ, // PAG_EXECUTE | PAG_READ
+ PAGE_EXECUTE_READWRITE, // PAG_EXECUTE | PAG_WRITE
+ PAGE_EXECUTE_READWRITE // PAG_EXECUTE | PAG_READ | PAG_WRITE
+};
+
+#if (PAG_EXECUTE | PAG_READ | PAG_WRITE) != 0x7
+#error PAG_EXECUTE | PAG_READ | PAG_WRITE incorrectly defined.
+#endif
+
+UCHAR Or2MapProtectionTable[ 16 ] = {
+ 0, // 0 (0x0)
+ 0, // PAGE_NOACCESS (0x1)
+ PAG_READ, // PAGE_READONLY (0x2)
+ 0, // 0 (0x3)
+ PAG_READ | PAG_WRITE, // PAGE_READWRITE (0x4)
+ 0, // 0 (0x5)
+ 0, // 0 (0x6)
+ 0, // 0 (0x7)
+ 0, // PAGE_WRITECOPY (0x8)
+ 0, // 0 (0x9)
+ 0, // 0 (0xA)
+ 0, // 0 (0xB)
+ 0, // 0 (0xC)
+ 0, // 0 (0xD)
+ 0, // 0 (0xE)
+ 0 // 0 (0xF)
+};
+
+#if (PAGE_NOACCESS | PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY) != 0xF
+#error PAGE_NOACCESS | PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY incorrectly defined.
+#endif
+
+#if (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) != 0xF0
+#error PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY incorrectly defined.
+#endif
+
+APIRET
+Or2MapFlagsToProtection(
+ ULONG Flags,
+ PULONG Protection
+ )
+{
+ *Protection = Or2MapFlagsTable[ Flags & ( PAG_EXECUTE |
+ PAG_READ |
+ PAG_WRITE
+ )
+ ];
+ if (*Protection == 0) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+ else {
+ if (Flags & PAG_GUARD) {
+ *Protection |= PAGE_GUARD;
+ }
+
+ return( NO_ERROR );
+ }
+}
+
+APIRET
+Or2MapProtectionToFlags(
+ ULONG Protection,
+ PULONG Flags
+ )
+{
+ if (Protection & 0x0F) {
+ *Flags = Or2MapProtectionTable[ Protection & 0x0F ];
+ }
+ else
+ if (Protection & 0xF0) {
+ *Flags = Or2MapProtectionTable[ (Protection & 0xF0) >> 4 ] |
+ PAG_EXECUTE;
+ }
+ else {
+ *Flags = 0;
+ }
+
+ if (*Flags == 0) {
+ return( ERROR_INVALID_PARAMETER );
+ }
+ else {
+ if (Protection & PAGE_GUARD) {
+ *Flags |= PAG_GUARD;
+ }
+
+ return( NO_ERROR );
+ }
+}
+
+APIRET
+Or2MapNtStatusToOs2Error(
+ IN NTSTATUS Status,
+ IN APIRET DefaultRetCode
+ )
+{
+ APIRET RetCode;
+
+ RetCode = Or2MapStatus(Status);
+ if ((RetCode & ERROR_SS_UNKNOWN_STATUS) == ERROR_SS_UNKNOWN_STATUS) {
+#if DBG
+ DbgPrint("OS2SSRTL: Or2MapNtStatusToOs2Error: Using default mapping: 0x%x => %d\n",
+ Status, DefaultRetCode);
+#endif
+ return DefaultRetCode;
+ }
+ return (RetCode);
+}
diff --git a/private/os2/ssrtl/qhandle.c b/private/os2/ssrtl/qhandle.c
new file mode 100644
index 000000000..436d3c39c
--- /dev/null
+++ b/private/os2/ssrtl/qhandle.c
@@ -0,0 +1,314 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ qhandle.c
+
+Abstract:
+
+ This module contains the queue handle primitives shared by
+ the OS/2 Client and Server. This file was created because the
+ file shandle.c which used to handle the queues was not suitable
+ for the job and caused the system to break.
+
+Author:
+
+ Beni Lavi (BeniL) 9-Jun-92
+
+Revision History:
+
+--*/
+
+#include "os2ssrtl.h"
+
+#define ALLOCATION_UNITS 32 // ALLOCATION_UNITS must be a power of 2
+
+POR2_QHANDLE_TABLE
+Or2CreateQHandleTable(
+ IN PVOID Heap,
+ IN ULONG SizeOfEntry,
+ IN ULONG Reserved
+ )
+{
+ POR2_QHANDLE_TABLE HandleTable;
+ POR2_QHANDLE_ENTRY QHandles;
+ PCHAR Entries;
+ int i;
+ NTSTATUS Status;
+
+ HandleTable = (POR2_QHANDLE_TABLE)RtlAllocateHeap(Heap, 0,
+ sizeof( *HandleTable ));
+ if (HandleTable == NULL) {
+ return (NULL);
+ }
+
+ QHandles = (POR2_QHANDLE_ENTRY)RtlAllocateHeap( Heap, 0,
+ ALLOCATION_UNITS * sizeof(OR2_QHANDLE_ENTRY));
+ if (QHandles == NULL) {
+ RtlFreeHeap(Heap, 0, (PVOID)HandleTable);
+ return (NULL);
+ }
+
+ Entries = (PCHAR)RtlAllocateHeap(Heap, 0, ALLOCATION_UNITS * SizeOfEntry);
+ if (Entries == NULL) {
+ RtlFreeHeap(Heap, 0, (PVOID)QHandles);
+ RtlFreeHeap(Heap, 0, (PVOID)HandleTable);
+ return (NULL);
+ }
+ for (i = 0; i < ALLOCATION_UNITS; i++) {
+ QHandles[i].Entry = (PVOID)(Entries + (i * SizeOfEntry));
+ QHandles[i].EntryIsAllocated = FALSE;
+ QHandles[i].EntryIsChunkPointer = FALSE;
+ }
+ QHandles[0].EntryIsChunkPointer = TRUE;
+ HandleTable->Heap = Heap;
+ HandleTable->EntrySize = SizeOfEntry;
+ HandleTable->CountEntries = ALLOCATION_UNITS;
+ HandleTable->CountFreeEntries = ALLOCATION_UNITS;
+ HandleTable->NextToAllocate = 0;
+ HandleTable->QHandles = QHandles;
+
+ Status = RtlInitializeCriticalSection( &HandleTable->Lock );
+ ASSERT( NT_SUCCESS( Status ) );
+ if (!NT_SUCCESS(Status)) {
+ RtlFreeHeap(Heap, 0, (PVOID)Entries);
+ RtlFreeHeap(Heap, 0, (PVOID)QHandles);
+ RtlFreeHeap(Heap, 0, (PVOID)HandleTable);
+ return( NULL );
+ }
+
+ return( HandleTable );
+}
+
+BOOLEAN
+Or2DestroyQHandleTable(
+ IN POR2_QHANDLE_TABLE HandleTable,
+ IN OR2_DESTROY_QHANDLE_ROUTINE DestroyQHandleProcedure
+ )
+{
+ PVOID Heap;
+ POR2_QHANDLE_ENTRY QHandles;
+ int i; // must be int - Don't change to ULONG
+
+ Heap = HandleTable->Heap;
+ QHandles = HandleTable->QHandles;
+ //
+ // Scan in reverse order so that we don't free memory before
+ // all handles which access this memory are destroyed.
+ //
+ for (i = (int)HandleTable->CountEntries - 1; i >= 0; i--) {
+ if (QHandles[i].EntryIsAllocated) {
+ //
+ // Pass i+1, because outside world enumerate handles starting from 1 and not 0.
+ //
+ (*DestroyQHandleProcedure)(QHandles[i].Entry, (ULONG)i+1);
+ }
+ if (QHandles[i].EntryIsChunkPointer) {
+ RtlFreeHeap(Heap, 0, QHandles[i].Entry);
+ }
+ }
+ RtlFreeHeap(Heap, 0, (PVOID)HandleTable->QHandles);
+
+ RtlDeleteCriticalSection( &HandleTable->Lock );
+
+ RtlFreeHeap(Heap, 0, (PVOID)HandleTable);
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+Or2CreateQHandle(
+ IN POR2_QHANDLE_TABLE HandleTable,
+ IN OUT PULONG Handle,
+ IN PVOID Value
+ )
+{
+ PVOID Heap;
+ ULONG NewHandle;
+ ULONG NewMaxHandles;
+ POR2_QHANDLE_ENTRY QHandles;
+ POR2_QHANDLE_ENTRY NewQHandles;
+ PCHAR Entries;
+ ULONG NewNextToAllocate;
+ ULONG i,j;
+
+ //
+ // The handle can be or valid ( >=1 ) or -1 (means - create the new one).
+ //
+ ASSERT(*Handle);
+ //
+ // Outside world enumerate handles starting from 1 and not 0.
+ //
+ NewHandle = *Handle - 1;
+ Heap = HandleTable->Heap;
+
+ AcquireHandleTableLock( HandleTable );
+
+ //
+ // If the handle passed as parameter wasn't valid, create new handle.
+ //
+ if ((LONG)NewHandle >= 0) {
+ if (NewHandle < HandleTable->CountEntries) {
+ if (HandleTable->QHandles[NewHandle].EntryIsAllocated) {
+ ReleaseHandleTableLock(HandleTable);
+ return (FALSE);
+ }
+ else {
+ HandleTable->QHandles[NewHandle].EntryIsAllocated = TRUE;
+ RtlMoveMemory(HandleTable->QHandles[NewHandle].Entry,
+ Value, HandleTable->EntrySize);
+ ReleaseHandleTableLock(HandleTable);
+ return (TRUE);
+ }
+ }
+ else {
+ NewMaxHandles = (NewHandle + ALLOCATION_UNITS) &
+ ~(ALLOCATION_UNITS - 1);
+ }
+ }
+ else {
+ if (HandleTable->CountFreeEntries != 0) {
+ while (TRUE) {
+ j = HandleTable->NextToAllocate;
+ NewNextToAllocate = j + 1;
+ if (NewNextToAllocate == HandleTable->CountEntries) {
+ NewNextToAllocate = 0;
+ }
+ HandleTable->NextToAllocate = NewNextToAllocate;
+ if (!HandleTable->QHandles[j].EntryIsAllocated) {
+ HandleTable->QHandles[j].EntryIsAllocated = TRUE;
+ HandleTable->CountFreeEntries--;
+ //
+ // For the outside world the enumeration of handles is starting from 1 and not from 0.
+ //
+ *Handle = j + 1;
+ ReleaseHandleTableLock(HandleTable);
+ return (TRUE);
+ }
+ }
+ }
+ else {
+ NewMaxHandles = HandleTable->CountEntries + ALLOCATION_UNITS;
+ NewHandle = HandleTable->CountEntries;
+ }
+ }
+ NewQHandles = (POR2_QHANDLE_ENTRY)RtlAllocateHeap(Heap, 0,
+ NewMaxHandles * sizeof(OR2_QHANDLE_ENTRY));
+ if (NewQHandles == NULL) {
+ ReleaseHandleTableLock(HandleTable);
+ return (FALSE);
+ }
+ QHandles = HandleTable->QHandles;
+ Entries = (PCHAR)RtlAllocateHeap(Heap, 0,
+ (NewMaxHandles - HandleTable->CountEntries) *
+ HandleTable->EntrySize);
+ if (Entries == NULL) {
+ RtlFreeHeap(Heap, 0, (PVOID)QHandles);
+ ReleaseHandleTableLock(HandleTable);
+ return (FALSE);
+ }
+ RtlMoveMemory(NewQHandles, QHandles,
+ HandleTable->CountEntries * sizeof(OR2_QHANDLE_ENTRY));
+ for (i = HandleTable->CountEntries, j = 0;
+ i < NewMaxHandles;
+ i++, j++) {
+ NewQHandles[i].Entry = (PVOID)(Entries + (j * HandleTable->EntrySize));
+ NewQHandles[i].EntryIsAllocated = FALSE;
+ NewQHandles[i].EntryIsChunkPointer = FALSE;
+ }
+ NewQHandles[HandleTable->CountEntries].EntryIsChunkPointer = TRUE;
+ HandleTable->CountFreeEntries +=
+ NewMaxHandles - HandleTable->CountEntries - 1;
+ HandleTable->CountEntries = NewMaxHandles;
+ RtlFreeHeap(Heap, 0, HandleTable->QHandles);
+ HandleTable->QHandles = NewQHandles;
+ HandleTable->QHandles[NewHandle].EntryIsAllocated = TRUE;
+ RtlMoveMemory(HandleTable->QHandles[NewHandle].Entry,
+ Value, HandleTable->EntrySize);
+ //
+ // For the outside world the enumeration of handles is starting from 1 and not from 0.
+ //
+ *Handle = NewHandle + 1;
+ NewNextToAllocate = NewHandle + 1;
+ if (NewNextToAllocate == HandleTable->CountEntries) {
+ NewNextToAllocate = 0;
+ }
+ HandleTable->NextToAllocate = NewNextToAllocate;
+ ReleaseHandleTableLock(HandleTable);
+ return (TRUE);
+}
+
+
+PVOID
+Or2MapQHandle(
+ IN POR2_QHANDLE_TABLE HandleTable,
+ IN ULONG Handle,
+ IN BOOLEAN TableLocked
+ )
+{
+ PVOID HandleTableEntry;
+
+ //
+ // For the outside world the enumeration of handles is starting from 1 and not from 0.
+ //
+ Handle--;
+
+ if (!TableLocked) {
+ AcquireHandleTableLock( HandleTable );
+ }
+
+ if (Handle >= HandleTable->CountEntries) {
+ HandleTableEntry = NULL;
+ if (!TableLocked) {
+ ReleaseHandleTableLock( HandleTable );
+ }
+ }
+ else if (HandleTable->QHandles[Handle].EntryIsAllocated) {
+ HandleTableEntry = HandleTable->QHandles[Handle].Entry;
+ }
+ else {
+ HandleTableEntry = NULL;
+ if (!TableLocked) {
+ ReleaseHandleTableLock( HandleTable );
+ }
+ }
+
+ return( HandleTableEntry );
+}
+
+
+BOOLEAN
+Or2DestroyQHandle(
+ IN POR2_QHANDLE_TABLE HandleTable,
+ IN ULONG Handle
+ )
+{
+ BOOLEAN Result;
+ PVOID HandleTableEntry;
+
+ //
+ // For the outside world the enumeration of handles is starting from 1 and not from 0.
+ //
+ Handle--;
+
+ if (Handle >= HandleTable->CountEntries) {
+ Result = FALSE;
+ }
+ else if (HandleTable->QHandles[Handle].EntryIsAllocated) {
+ HandleTableEntry = HandleTable->QHandles[Handle].Entry;
+ RtlZeroMemory(HandleTableEntry, HandleTable->EntrySize);
+ HandleTable->QHandles[Handle].EntryIsAllocated = FALSE;
+ HandleTable->CountFreeEntries++;
+ Result = TRUE;
+ }
+ else {
+ Result = FALSE;
+ }
+
+ ReleaseHandleTableLock( HandleTable );
+
+ return Result;
+}
diff --git a/private/os2/ssrtl/shandle.c b/private/os2/ssrtl/shandle.c
new file mode 100644
index 000000000..f7e6b14ee
--- /dev/null
+++ b/private/os2/ssrtl/shandle.c
@@ -0,0 +1,498 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ shandle.c
+
+Abstract:
+
+ This module contains the semaphore handle primitives shared by
+ the OS/2 Client and Server.
+
+Author:
+
+ Steve Wood (stevewo) 07-Nov-1989
+
+Revision History:
+
+--*/
+
+#include "os2ssrtl.h"
+
+CCHAR ByteLog2Table[256] = {
+ 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, // 00
+ 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 10
+ 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 20
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 30
+ 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 40
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 50
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 60
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 70
+ 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 80
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 90
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // A0
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // B0
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // C0
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // D0
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // E0
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}; // F0
+
+ULONG
+RtlLog2(
+ IN ULONG Value
+ )
+{
+ if (Value & 0xFF000000) {
+ return( 24 + ByteLog2Table[ Value >> 24 ] );
+ }
+ else
+ if (Value & 0x00FF0000) {
+ return( 16 + ByteLog2Table[ Value >> 16 ] );
+ }
+ else
+ if (Value & 0x0000FF00) {
+ return( 8 + ByteLog2Table[ Value >> 8 ] );
+ }
+ else {
+ return( ByteLog2Table[ Value ] );
+ }
+}
+
+POR2_HANDLE_TABLE
+Or2CreateHandleTable(
+ IN PVOID Heap,
+ IN ULONG SizeOfEntry,
+ IN ULONG CountFixedEntries
+ )
+{
+ POR2_HANDLE_TABLE HandleTable;
+ ULONG LogSizeOfEntry;
+ PVOID HandleEntries;
+ NTSTATUS Status;
+
+ LogSizeOfEntry = RtlLog2( (UCHAR)SizeOfEntry );
+ SizeOfEntry = 1 << LogSizeOfEntry;
+ HandleTable = RtlAllocateHeap( Heap, 0,
+ sizeof( *HandleTable ) +
+ (CountFixedEntries * SizeOfEntry)
+ );
+ if (HandleTable == NULL) {
+ return( NULL );
+ }
+
+ HandleEntries = (PVOID)(HandleTable+1);
+ if (CountFixedEntries != 0) {
+ RtlZeroMemory( HandleEntries, CountFixedEntries * SizeOfEntry );
+ }
+
+ Status = RtlInitializeCriticalSection( &HandleTable->Lock );
+ ASSERT( NT_SUCCESS( Status ) );
+ if (!NT_SUCCESS( Status )) {
+ RtlFreeHeap( Heap, 0,
+ HandleTable
+ );
+ return( NULL );
+ }
+
+ HandleTable->Length = sizeof( *HandleTable );
+ HandleTable->Heap = Heap;
+ HandleTable->LogEntrySize = LogSizeOfEntry;
+ HandleTable->CountEntries = CountFixedEntries;
+ HandleTable->CountFixedEntries = CountFixedEntries;
+ HandleTable->CountFreeEntries = CountFixedEntries;
+ HandleTable->FixedEntries = HandleEntries;
+ HandleTable->Entries = 0;
+ return( HandleTable );
+}
+
+BOOLEAN
+Or2DestroyHandleTable(
+ IN POR2_HANDLE_TABLE HandleTable,
+ IN OR2_DESTROY_HANDLE_ROUTINE DestroyHandleProcedure
+ )
+{
+ PULONG HandleTableEntry;
+ ULONG SizeOfEntry;
+ ULONG CurrentHandle;
+
+ SizeOfEntry = 1 << HandleTable->LogEntrySize;
+ CurrentHandle = 0;
+ HandleTableEntry = HandleTable->FixedEntries;
+ while (CurrentHandle < HandleTable->CountFixedEntries) {
+ if (*HandleTableEntry) {
+ (*DestroyHandleProcedure)( HandleTableEntry, CurrentHandle );
+ }
+
+ HandleTableEntry = (PVOID)((PCH)HandleTableEntry + SizeOfEntry);
+ CurrentHandle++;
+ }
+
+ if ((HandleTableEntry = HandleTable->Entries) != NULL) {
+ while (CurrentHandle < HandleTable->CountEntries) {
+ if (*HandleTableEntry) {
+ (*DestroyHandleProcedure)( HandleTableEntry, CurrentHandle );
+ }
+
+ HandleTableEntry = (PVOID)((PCH)HandleTableEntry + SizeOfEntry);
+ CurrentHandle++;
+ }
+
+ RtlFreeHeap( HandleTable->Heap, 0,
+ HandleTable->Entries
+ );
+ }
+
+ RtlDeleteCriticalSection( &HandleTable->Lock );
+
+ RtlFreeHeap( HandleTable->Heap, 0,
+ HandleTable
+ );
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+Or2CreateHandle(
+ IN POR2_HANDLE_TABLE HandleTable,
+ IN OUT PULONG Handle,
+ IN PVOID Value
+ )
+{
+ PVOID HandleEntries;
+ PULONG HandleTableEntry;
+ ULONG NewHandle;
+ ULONG CountOldEntries;
+ ULONG CountNewEntries;
+ ULONG SizeOfEntry;
+ ULONG cbOldEntries;
+ ULONG cbNewEntries;
+ BOOLEAN Result;
+
+ NewHandle = *Handle;
+
+ AcquireHandleTableLock( HandleTable );
+
+ SizeOfEntry = 1 << HandleTable->LogEntrySize;
+ if ((NewHandle == -1 && HandleTable->CountFreeEntries == 0) ||
+ (NewHandle != -1 && NewHandle >= HandleTable->CountEntries)
+ ) {
+ CountOldEntries = HandleTable->CountEntries -
+ HandleTable->CountFixedEntries;
+ if (NewHandle == -1) {
+ NewHandle = HandleTable->CountEntries;
+ if (CountOldEntries) {
+ CountNewEntries = CountOldEntries << 1;
+ }
+ else {
+ CountNewEntries = 16;
+ }
+ }
+ else {
+ CountNewEntries = NewHandle -
+ HandleTable->CountFixedEntries + 1;
+ }
+
+ cbNewEntries = CountNewEntries << HandleTable->LogEntrySize;
+ cbOldEntries = CountOldEntries << HandleTable->LogEntrySize;
+
+ HandleEntries = RtlAllocateHeap( HandleTable->Heap, 0,
+ cbNewEntries
+ );
+ if (HandleEntries == NULL) {
+ ReleaseHandleTableLock( HandleTable );
+ return( FALSE );
+ }
+
+ RtlZeroMemory( (PCH)HandleEntries + cbOldEntries,
+ cbNewEntries - cbOldEntries
+ );
+
+ if (cbOldEntries) {
+ RtlMoveMemory( HandleEntries,
+ HandleTable->Entries,
+ cbOldEntries
+ );
+
+ RtlFreeHeap( HandleTable->Heap, 0,
+ HandleTable->Entries
+ );
+ }
+
+ HandleTable->Entries = HandleEntries;
+
+ HandleTable->CountEntries =
+ CountNewEntries + HandleTable->CountFixedEntries;
+
+ HandleTable->CountFreeEntries += CountNewEntries -
+ CountOldEntries;
+
+ HandleTableEntry = (PVOID)((PCH)HandleEntries +
+ ((NewHandle - HandleTable->CountFixedEntries)
+ << HandleTable->LogEntrySize) );
+ }
+ else {
+ if (NewHandle == -1) {
+ NewHandle = 0;
+ HandleTableEntry = HandleTable->FixedEntries;
+ while (NewHandle < HandleTable->CountFixedEntries) {
+ if (*(PULONG)HandleTableEntry == 0) {
+ break;
+ }
+ else {
+ HandleTableEntry = (PVOID)((PCH)HandleTableEntry + SizeOfEntry);
+ NewHandle++;
+ }
+ }
+
+ if (NewHandle == HandleTable->CountFixedEntries) {
+ HandleTableEntry = HandleTable->Entries;
+ while (NewHandle < HandleTable->CountEntries) {
+ if (*(PULONG)HandleTableEntry == 0) {
+ break;
+ }
+ else {
+ HandleTableEntry = (PVOID)((PCH)HandleTableEntry + SizeOfEntry);
+ NewHandle++;
+ }
+ }
+ }
+ }
+ else {
+ if (NewHandle < HandleTable->CountFixedEntries) {
+ HandleTableEntry =
+ (PVOID)((PCH)HandleTable->FixedEntries +
+ (SizeOfEntry * NewHandle)
+ );
+ }
+ else
+ if (NewHandle < HandleTable->CountEntries) {
+ HandleTableEntry =
+ (PVOID)((PCH)HandleTable->Entries +
+ (SizeOfEntry * (NewHandle -
+ HandleTable->CountFixedEntries
+ )
+ )
+ );
+ }
+ else {
+ HandleTableEntry = NULL;
+ }
+ }
+ }
+
+ if (HandleTableEntry != NULL && *(PULONG)HandleTableEntry == 0) {
+ if (*Handle != -1 && *Handle != NewHandle) {
+ Result = FALSE;
+ }
+ else {
+ RtlMoveMemory( HandleTableEntry, Value, SizeOfEntry );
+ HandleTable->CountFreeEntries -= 1;
+ *Handle = NewHandle;
+ Result = TRUE;
+ }
+ }
+ else {
+ Result = FALSE;
+ }
+
+ ReleaseHandleTableLock( HandleTable );
+ return( Result );
+}
+
+
+PVOID
+Or2MapHandle(
+ IN POR2_HANDLE_TABLE HandleTable,
+ IN ULONG Handle,
+ IN BOOLEAN TableLocked
+ )
+{
+ PVOID HandleTableEntry;
+
+ if (!TableLocked) {
+ AcquireHandleTableLock( HandleTable );
+ }
+
+ if (Handle < HandleTable->CountFixedEntries) {
+ HandleTableEntry = (PVOID)((PCH)HandleTable->FixedEntries +
+ (Handle << HandleTable->LogEntrySize));
+ }
+ else
+ if (Handle < HandleTable->CountEntries) {
+ Handle -= HandleTable->CountFixedEntries;
+ HandleTableEntry = (PVOID)((PCH)HandleTable->Entries +
+ (Handle << HandleTable->LogEntrySize)
+ );
+ }
+ else {
+ if (!TableLocked) {
+ ReleaseHandleTableLock( HandleTable );
+ }
+
+ HandleTableEntry = NULL;
+ }
+
+ return( HandleTableEntry );
+}
+
+
+BOOLEAN
+Or2DestroyHandle(
+ IN POR2_HANDLE_TABLE HandleTable,
+ IN ULONG Handle
+ )
+{
+ BOOLEAN Result;
+ PULONG HandleTableEntry;
+
+ if (Handle < HandleTable->CountFixedEntries) {
+ HandleTableEntry = (PULONG)((PCH)HandleTable->FixedEntries +
+ (Handle << HandleTable->LogEntrySize));
+ }
+ else
+ if (Handle < HandleTable->CountEntries) {
+ Handle -= HandleTable->CountFixedEntries;
+ HandleTableEntry = (PULONG)((PCH)HandleTable->Entries +
+ (Handle << HandleTable->LogEntrySize)
+ );
+ }
+ else {
+ HandleTableEntry = NULL;
+ }
+
+ if (HandleTableEntry != NULL) {
+ RtlZeroMemory( HandleTableEntry,
+ 1 << HandleTable->LogEntrySize
+ );
+ HandleTable->CountFreeEntries++;
+ Result = TRUE;
+ }
+ else {
+ Result = FALSE;
+ }
+
+ ReleaseHandleTableLock( HandleTable );
+
+ return( Result );
+}
+
+
+
+BOOLEAN
+Or2EnumHandleTable(
+ IN POR2_HANDLE_TABLE HandleTable,
+ IN OR2_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
+ IN PVOID EnumParameter,
+ OUT PULONG Handle OPTIONAL
+ )
+{
+ PULONG HandleTableEntry;
+ ULONG SizeOfEntry;
+ ULONG CurrentHandle;
+ BOOLEAN Result;
+
+ AcquireHandleTableLock( HandleTable );
+
+ Result = FALSE;
+ SizeOfEntry = 1 << HandleTable->LogEntrySize;
+ CurrentHandle = 0;
+ HandleTableEntry = HandleTable->FixedEntries;
+ while (CurrentHandle < HandleTable->CountFixedEntries) {
+ if ((*EnumHandleProcedure)( HandleTableEntry,
+ EnumParameter ? EnumParameter :
+ (PVOID)CurrentHandle
+ )
+ ) {
+ if (ARGUMENT_PRESENT( Handle )) {
+ *Handle = CurrentHandle;
+ }
+
+ Result = TRUE;
+ break;
+ }
+ else {
+ HandleTableEntry = (PVOID)((PCH)HandleTableEntry + SizeOfEntry);
+ CurrentHandle++;
+ }
+ }
+
+ if (!Result && CurrentHandle == HandleTable->CountFixedEntries) {
+ HandleTableEntry = HandleTable->Entries;
+ while (CurrentHandle < HandleTable->CountEntries) {
+ if ((*EnumHandleProcedure)( HandleTableEntry,
+ EnumParameter ? EnumParameter :
+ (PVOID)CurrentHandle
+ )
+ ) {
+ if (ARGUMENT_PRESENT( Handle )) {
+ *Handle = CurrentHandle;
+ }
+
+ Result = TRUE;
+ break;
+ }
+ else {
+ HandleTableEntry = (PVOID)((PCH)HandleTableEntry + SizeOfEntry);
+ CurrentHandle++;
+ }
+ }
+ }
+
+ ReleaseHandleTableLock( HandleTable );
+
+ return( Result );
+}
+
+
+#if DBG
+
+ULONG
+Or2DumpHandleTable(
+ IN POR2_HANDLE_TABLE HandleTable,
+ IN OR2_DUMP_HANDLE_ROUTINE DumpHandleProcedure,
+ IN PVOID DumpParameter
+ )
+{
+ PULONG HandleTableEntry;
+ ULONG SizeOfEntry;
+ ULONG CurrentHandle;
+ ULONG NumberOfHandles = 0;
+
+ SizeOfEntry = 1 << HandleTable->LogEntrySize;
+ CurrentHandle = 0;
+ HandleTableEntry = HandleTable->FixedEntries;
+ while (CurrentHandle < HandleTable->CountFixedEntries) {
+ if (*HandleTableEntry) {
+ (*DumpHandleProcedure)( HandleTableEntry,
+ CurrentHandle,
+ DumpParameter
+ );
+ NumberOfHandles++;
+ }
+
+ HandleTableEntry = (PVOID)((PCH)HandleTableEntry + SizeOfEntry);
+ CurrentHandle++;
+ }
+
+ if ((HandleTableEntry = HandleTable->Entries) != NULL) {
+ while (CurrentHandle < HandleTable->CountEntries) {
+ if (*HandleTableEntry) {
+ (*DumpHandleProcedure)( HandleTableEntry,
+ CurrentHandle,
+ DumpParameter
+ );
+ NumberOfHandles++;
+ }
+
+ HandleTableEntry = (PVOID)((PCH)HandleTableEntry + SizeOfEntry);
+ CurrentHandle++;
+ }
+ }
+
+ return( NumberOfHandles );
+}
+
+#endif // DBG
diff --git a/private/os2/ssrtl/sources b/private/os2/ssrtl/sources
new file mode 100644
index 000000000..e2624fe58
--- /dev/null
+++ b/private/os2/ssrtl/sources
@@ -0,0 +1,47 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=os2
+MINORCOMP=ssrtl
+
+TARGETNAME=os2ssrtl
+TARGETPATH=..\obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=..\inc
+
+WIMPYMASM=1
+
+NO_READONLY_STRINGS=1
+
+SOURCES=shandle.c \
+ qhandle.c \
+ nls.c \
+ ntmap.c \
+ consys.c \
+ sswinapi.c \
+ datetime.c
+
+USE_CRTDLL=1
+i386_SOURCES=i386\setjmp.asm
diff --git a/private/os2/ssrtl/sswinapi.c b/private/os2/ssrtl/sswinapi.c
new file mode 100644
index 000000000..e37625530
--- /dev/null
+++ b/private/os2/ssrtl/sswinapi.c
@@ -0,0 +1,2265 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sswinapi.c
+
+Abstract:
+
+ This module contains the Win32 API calls with DBG shared by
+ the OS/2 Client and Server.
+
+Author:
+
+ Michael Jarus (mjarus) 28-Dec-1992
+
+Revision History:
+
+--*/
+
+
+#include <windows.h>
+#include "os2dbg.h"
+#include "os2nt.h"
+#include "conapi.h"
+#include <io.h>
+
+/*
+ * Debug Win32 API (from inc\os2nt.h)
+ */
+
+#if DBG
+extern ULONG Os2Debug;
+
+BYTE PeekConsoleInputAStr[] = "PeekConsoleInputA";
+BYTE ReadConsoleInputAStr[] = "ReadConsoleInputA";
+BYTE WriteConsoleInputAStr[] = "WriteConsoleInputA";
+BYTE ReadConsoleOutputCharacterAStr[] = "ReadConsoleOutputCharacterA";
+BYTE ReadConsoleOutputCharacterWStr[] = "ReadConsoleOutputCharacterW";
+BYTE ReadConsoleOutputAttributeStr[] = "ReadConsoleOutputAttribute";
+BYTE WriteConsoleOutputCharacterAStr[] = "WriteConsoleOutputCharacterA";
+BYTE WriteConsoleOutputCharacterWStr[] = "WriteConsoleOutputCharacterW";
+BYTE WriteConsoleOutputAttributeStr[] = "WriteConsoleOutputAttribute";
+BYTE FillConsoleOutputCharacterAStr[] = "FillConsoleOutputCharacterA";
+BYTE FillConsoleOutputAttributeStr[] = "FillConsoleOutputAttribute";
+BYTE GetConsoleModeStr[] = "GetConsoleMode";
+BYTE GetNumberOfConsoleInputEventsStr[] = "GetNumberOfConsoleInputEvents";
+BYTE GetConsoleScreenBufferInfoStr[] = "GetConsoleScreenBufferInfo";
+BYTE GetLargestConsoleWindowSizeStr[] = "GetLargestConsoleWindowSize";
+BYTE GetConsoleCursorInfoStr[] = "GetConsoleCursorInfo";
+BYTE GetNumberOfConsoleMouseButtonsStr[] = "GetNumberOfConsoleMouseButtons";
+BYTE SetConsoleModeStr[] = "SetConsoleMode";
+BYTE SetConsoleActiveScreenBufferStr[] = "SetConsoleActiveScreenBuffer";
+BYTE SetConsoleScreenBufferSizeStr[] = "SetConsoleScreenBufferSize";
+BYTE SetConsoleCursorPositionStr[] = "SetConsoleCursorPosition";
+BYTE SetConsoleCursorInfoStr[] = "SetConsoleCursorInfo";
+BYTE ScrollConsoleScreenBufferAStr[] = "ScrollConsoleScreenBufferA";
+BYTE ScrollConsoleScreenBufferWStr[] = "ScrollConsoleScreenBufferW";
+BYTE SetConsoleWindowInfoStr[] = "SetConsoleWindowInfo";
+BYTE SetConsoleTextAttributeStr[] = "SetConsoleTextAttribute";
+BYTE SetConsoleCtrlHandlerStr[] = "SetConsoleCtrlHandler";
+BYTE GetConsoleTitleWStr[] = "GetConsoleTitleW";
+BYTE SetConsoleTitleAStr[] = "SetConsoleTitleA";
+BYTE SetConsoleTitleWStr[] = "SetConsoleTitleW";
+BYTE WriteConsoleAStr[] = "WriteConsoleA";
+BYTE CreateConsoleScreenBufferStr[] = "CreateConsoleScreenBuffer";
+BYTE GetConsoleCPStr[] = "GetConsoleCP";
+BYTE SetConsoleCPStr[] = "SetConsoleCP";
+BYTE GetConsoleOutputCPStr[] = "GetConsoleOutputCP";
+BYTE SetConsoleOutputCPStr[] = "SetConsoleOutputCP";
+BYTE BeepStr[] = "Beep";
+BYTE CloseHandleStr[] = "CloseHandle";
+BYTE CreateEventWStr[] = "CreateEventW";
+BYTE CreateFileAStr[] = "CreateFileA";
+BYTE CreateFileWStr[] = "CreateFileW";
+BYTE CreateProcessAStr[] = "CreateProcessA";
+BYTE CreateThreadStr[] = "CreateThread";
+BYTE DuplicateHandleStr[] = "DuplicateHandle";
+BYTE EnterCriticalSectionStr[] = "EnterCriticalSection";
+BYTE GetCommandLineAStr[] = "GetCommandLineA";
+BYTE GetConsoleFontSizeStr[] = "GetConsoleFontSize";
+BYTE GetCurrentConsoleFontStr[] = "GetCurrentConsoleFont";
+BYTE GetFileTypeStr[] = "GetFileType";
+BYTE GetFullPathNameAStr[] = "GetFullPathNameA";
+BYTE GetModuleHandleAStr[] = "GetModuleHandleA";
+BYTE GetStdHandleStr[] = "GetStdHandle";
+BYTE GetSystemDirectoryAStr[] = "GetSystemDirectoryA";
+BYTE InitializeCriticalSectionStr[] = "InitializeCriticalSection";
+BYTE LeaveCriticalSectionStr[] = "LeaveCriticalSection";
+BYTE LoadStringAStr[] = "LoadStringA";
+BYTE MessageBoxAStr[] = "MessageBoxA";
+BYTE OpenProcessStr[] = "OpenProcess";
+BYTE ResumeThreadStr[] = "ResumeThread";
+BYTE SetErrorModeStr[] = "SetErrorMode";
+BYTE SetEventStr[] = "SetEvent";
+BYTE SetStdHandleStr[] = "SetStdHandle";
+BYTE SetThreadLocaleStr[] = "SetThreadLocale";
+BYTE GetThreadLocaleStr[] = "GetThreadLocale";
+BYTE SetThreadPriorityStr[] = "SetThreadPriority";
+BYTE SystemParametersInfoAStr[] = "SystemParametersInfoA";
+BYTE TerminateThreadStr[] = "TerminateThread";
+BYTE VerifyConsoleIoHandleStr[] = "VerifyConsoleIoHandle";
+BYTE WaitForSingleObjectStr[] = "WaitForSingleObject";
+BYTE WriteFileStr[] = "WriteFile";
+BYTE _readStr[] = "_read";
+BYTE ReadFileStr[] = "ReadFile";
+BYTE IsValidCodePageStr[] = "IsValidCodePage";
+BYTE GetACPStr[] = "GetACP";
+BYTE GetOEMCPStr[] = "GetOEMCP";
+BYTE GetCPInfoStr[] = "GetCPInfo";
+BYTE IsDBCSLeadByteStr[] = "IsDBCSLeadByte";
+BYTE MultiByteToWideCharStr[] = "MultiByteToWideChar";
+BYTE WideCharToMultiByteStr[] = "WideCharToMultiByte";
+BYTE CompareStringWStr[] = "CompareStringW";
+BYTE LCMapStringWStr[] = "LCMapStringW";
+BYTE GetLocaleInfoWStr[] = "GetLocaleInfoW";
+BYTE GetSystemDefaultLangIDStr[] = "GetSystemDefaultLangID";
+BYTE GetUserDefaultLangIDStr[] = "GetUserDefaultLangID";
+BYTE GetSystemDefaultLCIDStr[] = "GetSystemDefaultLCID";
+BYTE GetUserDefaultLCIDStr[] = "GetUserDefaultLCID";
+BYTE GetStringTypeWStr[] = "GetStringTypeW";
+BYTE FoldStringWStr[] = "FoldStringW";
+BYTE HeapCreateStr[] = "HeapCreate";
+BYTE HeapAllocStr[] = "HeapAlloc";
+BYTE HeapFreeStr[] = "HeapFree";
+
+BOOL
+Or2WinPeekConsoleInputA(
+ PSZ FuncName,
+ HANDLE hConsoleInput,
+ PINPUT_RECORD lpBuffer,
+ DWORD nLength,
+ LPDWORD lpNumberOfEventsRead
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, PeekConsoleInputAStr));
+ }
+ bRc = PeekConsoleInputA(hConsoleInput, lpBuffer, nLength,
+ lpNumberOfEventsRead);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, PeekConsoleInputAStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinReadConsoleInputA(
+ PSZ FuncName,
+ HANDLE hConsoleInput,
+ PINPUT_RECORD lpBuffer,
+ DWORD nLength,
+ LPDWORD lpNumberOfEventsRead
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, ReadConsoleInputAStr));
+ }
+ bRc = ReadConsoleInputA(hConsoleInput, lpBuffer, nLength,
+ lpNumberOfEventsRead);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, ReadConsoleInputAStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinWriteConsoleInputA(
+ PSZ FuncName,
+ HANDLE hConsoleInput,
+ PINPUT_RECORD lpBuffer,
+ DWORD nLength,
+ LPDWORD lpNumberOfEventsWritten
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, WriteConsoleInputAStr));
+ }
+ bRc = WriteConsoleInputA(hConsoleInput, lpBuffer, nLength,
+ lpNumberOfEventsWritten);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, WriteConsoleInputAStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinReadConsoleOutputCharacterA(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ LPSTR lpCharacter,
+ DWORD nLength,
+ COORD dwReadCoord,
+ LPDWORD lpNumberOfCharsRead
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, ReadConsoleOutputCharacterAStr));
+ }
+ bRc = ReadConsoleOutputCharacterA(hConsoleOutput, lpCharacter, nLength,
+ dwReadCoord, lpNumberOfCharsRead);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, ReadConsoleOutputCharacterAStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinReadConsoleOutputCharacterW(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ LPWSTR lpCharacter,
+ DWORD nLength,
+ COORD dwReadCoord,
+ LPDWORD lpNumberOfCharsRead
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, ReadConsoleOutputCharacterWStr));
+ }
+ bRc = ReadConsoleOutputCharacterW(hConsoleOutput, lpCharacter, nLength,
+ dwReadCoord, lpNumberOfCharsRead);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, ReadConsoleOutputCharacterWStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinReadConsoleOutputAttribute(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ LPWORD lpAttribute,
+ DWORD nLength,
+ COORD dwReadCoord,
+ LPDWORD lpNumberOfAttrsRead
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, ReadConsoleOutputAttributeStr));
+ }
+ bRc = ReadConsoleOutputAttribute(hConsoleOutput, lpAttribute, nLength,
+ dwReadCoord, lpNumberOfAttrsRead);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, ReadConsoleOutputAttributeStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinWriteConsoleOutputCharacterA(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ LPSTR lpCharacter,
+ DWORD nLength,
+ COORD dwWriteCoord,
+ LPDWORD lpNumberOfCharsWritten
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, WriteConsoleOutputCharacterAStr));
+ }
+ bRc = WriteConsoleOutputCharacterA(hConsoleOutput, lpCharacter, nLength,
+ dwWriteCoord, lpNumberOfCharsWritten);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, WriteConsoleOutputCharacterAStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinWriteConsoleOutputCharacterW(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ LPWSTR lpCharacter,
+ DWORD nLength,
+ COORD dwWriteCoord,
+ LPDWORD lpNumberOfCharsWritten
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, WriteConsoleOutputCharacterWStr));
+ }
+ bRc = WriteConsoleOutputCharacterW(hConsoleOutput, lpCharacter, nLength,
+ dwWriteCoord, lpNumberOfCharsWritten);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, WriteConsoleOutputCharacterWStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinWriteConsoleOutputAttribute(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ LPWORD lpAttribute,
+ DWORD nLength,
+ COORD dwWriteCoord,
+ LPDWORD lpNumberOfAttrsWritten
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, WriteConsoleOutputAttributeStr));
+ }
+ bRc = WriteConsoleOutputAttribute(hConsoleOutput, lpAttribute, nLength,
+ dwWriteCoord, lpNumberOfAttrsWritten);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, WriteConsoleOutputAttributeStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinFillConsoleOutputCharacterA(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ CHAR cCharacter,
+ DWORD nLength,
+ COORD dwWriteCoord,
+ LPDWORD lpNumberOfCharsWritten
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, FillConsoleOutputCharacterAStr));
+ }
+ bRc = FillConsoleOutputCharacterA(hConsoleOutput, cCharacter, nLength,
+ dwWriteCoord, lpNumberOfCharsWritten);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, FillConsoleOutputCharacterAStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinFillConsoleOutputAttribute(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ WORD wAttribute,
+ DWORD nLength,
+ COORD dwWriteCoord,
+ LPDWORD lpNumberOfAttrsWritten
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, FillConsoleOutputAttributeStr));
+ }
+ bRc = FillConsoleOutputAttribute(hConsoleOutput, wAttribute, nLength,
+ dwWriteCoord, lpNumberOfAttrsWritten);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, FillConsoleOutputAttributeStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinGetConsoleMode(
+ PSZ FuncName,
+ HANDLE hConsoleHandle,
+ LPDWORD lpMode
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetConsoleModeStr));
+ }
+ bRc = GetConsoleMode(hConsoleHandle, lpMode);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetConsoleModeStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinGetNumberOfConsoleInputEvents(
+ PSZ FuncName,
+ HANDLE hConsoleInput,
+ LPDWORD lpNumberOfEvents
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetNumberOfConsoleInputEventsStr));
+ }
+ bRc = GetNumberOfConsoleInputEvents(hConsoleInput, lpNumberOfEvents);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetNumberOfConsoleInputEventsStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinGetConsoleScreenBufferInfo(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetConsoleScreenBufferInfoStr));
+ }
+ bRc = GetConsoleScreenBufferInfo(hConsoleOutput, lpConsoleScreenBufferInfo);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetConsoleScreenBufferInfoStr));
+ }
+ }
+ return(bRc);
+}
+
+COORD
+Or2WinGetLargestConsoleWindowSize(
+ PSZ FuncName,
+ HANDLE hConsoleOutput
+ )
+{
+ COORD bCoord;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetLargestConsoleWindowSizeStr));
+ }
+ bCoord = GetLargestConsoleWindowSize(hConsoleOutput);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bCoord.X && !bCoord.Y)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetConsoleScreenBufferInfoStr));
+ }
+ }
+ return(bCoord);
+}
+
+BOOL
+Or2WinGetConsoleCursorInfo(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetConsoleCursorInfoStr));
+ }
+ bRc = GetConsoleCursorInfo(hConsoleOutput, lpConsoleCursorInfo);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetConsoleCursorInfoStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinGetNumberOfConsoleMouseButtons(
+ PSZ FuncName,
+ LPDWORD lpNumberOfMouseButtons
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetNumberOfConsoleMouseButtonsStr));
+ }
+ bRc = GetNumberOfConsoleMouseButtons(lpNumberOfMouseButtons);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetNumberOfConsoleMouseButtonsStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinSetConsoleMode(
+ PSZ FuncName,
+ HANDLE hConsoleHandle,
+ DWORD dwMode
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetConsoleModeStr));
+ }
+ bRc = SetConsoleMode(hConsoleHandle, dwMode);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetConsoleModeStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinSetConsoleActiveScreenBuffer(
+ PSZ FuncName,
+ HANDLE hConsoleOutput
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetConsoleActiveScreenBufferStr));
+ }
+ bRc = SetConsoleActiveScreenBuffer(hConsoleOutput);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetConsoleActiveScreenBufferStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinSetConsoleScreenBufferSize(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ COORD dwSize
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetConsoleScreenBufferSizeStr));
+ }
+ bRc = SetConsoleScreenBufferSize(hConsoleOutput, dwSize);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetConsoleScreenBufferSizeStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinSetConsoleCursorPosition(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ COORD dwCursorPosition
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetConsoleCursorPositionStr));
+ }
+ bRc = SetConsoleCursorPosition(hConsoleOutput, dwCursorPosition);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetConsoleCursorPositionStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinSetConsoleCursorInfo(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetConsoleCursorInfoStr));
+ }
+ bRc = SetConsoleCursorInfo(hConsoleOutput, lpConsoleCursorInfo);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetConsoleCursorInfoStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinScrollConsoleScreenBufferA(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ PSMALL_RECT lpScrollRectangle,
+ PSMALL_RECT lpClipRectangle,
+ COORD dwDestinationOrigin,
+ PCHAR_INFO lpFill
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, ScrollConsoleScreenBufferAStr));
+ }
+ bRc = ScrollConsoleScreenBufferA(hConsoleOutput, lpScrollRectangle,
+ lpClipRectangle, dwDestinationOrigin, lpFill);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, ScrollConsoleScreenBufferAStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinScrollConsoleScreenBufferW(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ PSMALL_RECT lpScrollRectangle,
+ PSMALL_RECT lpClipRectangle,
+ COORD dwDestinationOrigin,
+ PCHAR_INFO lpFill
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, ScrollConsoleScreenBufferWStr));
+ }
+ bRc = ScrollConsoleScreenBufferW(hConsoleOutput, lpScrollRectangle,
+ lpClipRectangle, dwDestinationOrigin, lpFill);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, ScrollConsoleScreenBufferWStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinSetConsoleWindowInfo(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ BOOL bAbsolute,
+ PSMALL_RECT lpConsoleWindow
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetConsoleWindowInfoStr));
+ }
+ bRc = SetConsoleWindowInfo(hConsoleOutput, bAbsolute, lpConsoleWindow);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetConsoleWindowInfoStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinSetConsoleTextAttribute(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ WORD wAttributes
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetConsoleTextAttributeStr));
+ }
+ bRc = SetConsoleTextAttribute(hConsoleOutput, wAttributes);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetConsoleTextAttributeStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinSetConsoleCtrlHandler(
+ PSZ FuncName,
+ PHANDLER_ROUTINE HandlerRoutine,
+ BOOL Add
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetConsoleCtrlHandlerStr));
+ }
+ bRc = SetConsoleCtrlHandler(HandlerRoutine, Add);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetConsoleCtrlHandlerStr));
+ }
+ }
+ return(bRc);
+}
+
+DWORD
+Or2WinGetConsoleTitleW(
+ PSZ FuncName,
+ LPWSTR lpConsoleTitle,
+ DWORD nSize
+ )
+{
+ DWORD dwLength;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetConsoleTitleWStr));
+ }
+ dwLength = GetConsoleTitleW(lpConsoleTitle, nSize);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (dwLength == 0)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetConsoleTitleWStr));
+ }
+ }
+ return(dwLength);
+}
+
+BOOL
+Or2WinSetConsoleTitleA(
+ PSZ FuncName,
+ LPSTR lpConsoleTitle
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetConsoleTitleAStr));
+ }
+ bRc = SetConsoleTitleA(lpConsoleTitle);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetConsoleTitleAStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinSetConsoleTitleW(
+ PSZ FuncName,
+ LPWSTR lpConsoleTitle
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetConsoleTitleWStr));
+ }
+ bRc = SetConsoleTitleW(lpConsoleTitle);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetConsoleTitleWStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinWriteConsoleA(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ CONST VOID *lpBuffer,
+ DWORD nNumberOfCharsToWrite,
+ LPDWORD lpNumberOfCharsWritten,
+ LPVOID lpReserved
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, WriteConsoleAStr));
+ }
+ bRc = WriteConsoleA(hConsoleOutput, lpBuffer, nNumberOfCharsToWrite,
+ lpNumberOfCharsWritten, lpReserved);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, WriteConsoleAStr));
+ }
+ }
+ return(bRc);
+}
+
+HANDLE
+Or2WinCreateConsoleScreenBuffer(
+ PSZ FuncName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwFlags,
+ PVOID lpScreenBufferData
+ )
+{
+ HANDLE hBuffer;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, CreateConsoleScreenBufferStr));
+ }
+ hBuffer = CreateConsoleScreenBuffer(dwDesiredAccess, dwShareMode,
+ lpSecurityAttributes, dwFlags, lpScreenBufferData);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (hBuffer == INVALID_HANDLE_VALUE)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetConsoleCtrlHandlerStr));
+ }
+ }
+ return(hBuffer);
+}
+
+UINT
+Or2WinGetConsoleCP(
+ PSZ FuncName
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetConsoleCPStr));
+ }
+ return(GetConsoleCP());
+}
+
+BOOL
+Or2WinSetConsoleCP(
+ PSZ FuncName,
+ UINT wCodePageID
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetConsoleCPStr));
+ }
+ bRc = SetConsoleCP(wCodePageID);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetConsoleCPStr));
+ }
+ }
+ return(bRc);
+}
+
+UINT
+Or2WinGetConsoleOutputCP(
+ PSZ FuncName
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetConsoleOutputCPStr));
+ }
+ return(GetConsoleOutputCP());
+}
+
+BOOL
+Or2WinSetConsoleOutputCP(
+ PSZ FuncName,
+ UINT wCodePageID
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetConsoleOutputCPStr));
+ }
+ bRc = SetConsoleOutputCP(wCodePageID);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetConsoleOutputCPStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinBeep(
+ PSZ FuncName,
+ DWORD dwFreq,
+ DWORD dwDuration
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, BeepStr));
+ }
+ bRc = Beep(dwFreq, dwDuration);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, BeepStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinCloseHandle(
+ PSZ FuncName,
+ HANDLE hObject
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, CloseHandleStr));
+ }
+ bRc = CloseHandle(hObject);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, CloseHandleStr));
+ }
+ }
+ return(bRc);
+}
+
+HANDLE
+Or2WinCreateEventW(
+ PSZ FuncName,
+ LPSECURITY_ATTRIBUTES lpEventAttributes,
+ BOOL bManualReset,
+ BOOL bInitialState,
+ LPWSTR lpName
+ )
+{
+ HANDLE hEvent;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, CreateEventWStr));
+ }
+ hEvent = CreateEventW(lpEventAttributes, bManualReset, bInitialState, lpName);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (hEvent == NULL)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetConsoleCtrlHandlerStr));
+ }
+ }
+ return(hEvent);
+}
+
+HANDLE
+Or2WinCreateFileA(
+ PSZ FuncName,
+ LPCSTR lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile
+ )
+{
+ HANDLE hFile;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, CreateFileAStr));
+ }
+ hFile = CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
+ dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, CreateFileAStr));
+ }
+ }
+ return(hFile);
+}
+
+HANDLE
+Or2WinCreateFileW(
+ PSZ FuncName,
+ LPCWSTR lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile
+ )
+{
+ HANDLE hFile;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, CreateFileWStr));
+ }
+ hFile = CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
+ dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, CreateFileWStr));
+ }
+ }
+ return(hFile);
+}
+
+BOOL
+Or2WinCreateProcessA(
+ PSZ FuncName,
+ LPCSTR lpApplicationName,
+ LPCSTR lpCommandLine,
+ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ BOOL bInheritHandles,
+ DWORD dwCreationFlags,
+ LPVOID lpEnvironment,
+ LPSTR lpCurrentDirectory,
+ LPSTARTUPINFOA lpStartupInfo,
+ LPPROCESS_INFORMATION lpProcessInformation
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, CreateProcessAStr));
+ }
+ bRc = CreateProcessA(lpApplicationName, lpCommandLine, lpProcessAttributes,
+ lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
+ lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, CreateProcessAStr));
+ }
+ }
+ return(bRc);
+}
+
+HANDLE
+Or2WinCreateThread(
+ PSZ FuncName,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ DWORD dwStackSize,
+ LPTHREAD_START_ROUTINE lpStartAddress,
+ LPVOID lpParameter,
+ DWORD dwCreationFlags,
+ LPDWORD lpThreadId
+ )
+{
+ HANDLE hThread;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, CreateThreadStr));
+ }
+ hThread = CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
+ lpParameter, dwCreationFlags, lpThreadId);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (hThread == NULL)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, CreateThreadStr));
+ }
+ }
+ return(hThread);
+}
+
+BOOL
+Or2WinDuplicateHandle(
+ PSZ FuncName,
+ HANDLE hSourceProcessHandle,
+ HANDLE hSourceHandle,
+ HANDLE hTargetProcessHandle,
+ LPHANDLE lpTargetHandle,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ DWORD dwOptions
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, DuplicateHandleStr));
+ }
+ bRc = DuplicateHandle(hSourceProcessHandle, hSourceHandle, hTargetProcessHandle,
+ lpTargetHandle, dwDesiredAccess, bInheritHandle, dwOptions);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, DuplicateHandleStr));
+ }
+ }
+ return(bRc);
+}
+
+VOID
+Or2WinEnterCriticalSection(
+ PSZ FuncName,
+ LPCRITICAL_SECTION lpCriticalSection
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, EnterCriticalSectionStr));
+ }
+ EnterCriticalSection(lpCriticalSection);
+}
+
+LPSTR
+Or2WinGetCommandLineA(
+ PSZ FuncName
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetCommandLineAStr));
+ }
+ return(GetCommandLineA());
+}
+
+COORD
+Or2WinGetConsoleFontSize(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ DWORD nFont
+ )
+{
+ COORD bCoord;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetConsoleFontSizeStr));
+ }
+ bCoord = GetConsoleFontSize(hConsoleOutput, nFont);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bCoord.X && !bCoord.Y)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetConsoleFontSizeStr));
+ }
+ }
+ return(bCoord);
+}
+
+BOOL
+Or2WinGetCurrentConsoleFont(
+ PSZ FuncName,
+ HANDLE hConsoleOutput,
+ BOOL bMaximumWindow,
+ PCONSOLE_FONT_INFO lpConsoleCurrentFont
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetCurrentConsoleFontStr));
+ }
+ bRc = GetCurrentConsoleFont(hConsoleOutput, bMaximumWindow,
+ lpConsoleCurrentFont);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetCurrentConsoleFontStr));
+ }
+ }
+ return(bRc);
+}
+
+DWORD
+Or2WinGetFileType(
+ PSZ FuncName,
+ HANDLE hFile
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetFileTypeStr));
+ }
+ return(GetFileType(hFile));
+}
+
+DWORD
+Or2WinGetFullPathNameA(
+ PSZ FuncName,
+ LPCSTR lpFileName,
+ DWORD nBufferLength,
+ LPSTR lpBuffer,
+ LPSTR *lpFilePart
+ )
+{
+ DWORD dwLength;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetFullPathNameAStr));
+ }
+ dwLength = GetFullPathNameA(lpFileName, nBufferLength, lpBuffer, lpFilePart);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (dwLength == 0)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetFullPathNameAStr));
+ } else if (dwLength > nBufferLength)
+ {
+ KdPrint((" *** FAIL *** %s => %s size\n", FuncName, GetFullPathNameAStr));
+ }
+ }
+ return(dwLength);
+}
+
+HANDLE
+Or2WinGetModuleHandleA(
+ PSZ FuncName,
+ LPCSTR lpModuleName
+ )
+{
+ HANDLE hModule;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetModuleHandleAStr));
+ }
+ hModule = GetModuleHandleA(lpModuleName);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (hModule == NULL)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetModuleHandleAStr));
+ }
+ }
+ return(hModule);
+}
+
+HANDLE
+Or2WinGetStdHandle(
+ PSZ FuncName,
+ DWORD nStdHandle
+ )
+{
+ HANDLE hStd;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetStdHandleStr));
+ }
+ hStd = GetStdHandle(nStdHandle);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (hStd == NULL)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetStdHandleStr));
+ }
+ }
+ return(hStd);
+}
+
+UINT
+Or2WinGetSystemDirectoryA(
+ PSZ FuncName,
+ LPSTR lpBuffer,
+ UINT uSize
+ )
+{
+ UINT uiLength;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetSystemDirectoryAStr));
+ }
+ uiLength = GetSystemDirectoryA(lpBuffer, uSize);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (uiLength == 0)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetSystemDirectoryAStr));
+ } else if (uiLength > uSize)
+ {
+ KdPrint((" *** FAIL *** %s => %s size\n", FuncName, GetSystemDirectoryAStr));
+ }
+ }
+ return(uiLength);
+}
+
+VOID
+Or2WinInitializeCriticalSection(
+ PSZ FuncName,
+ LPCRITICAL_SECTION lpCriticalSection
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, InitializeCriticalSectionStr));
+ }
+ InitializeCriticalSection(lpCriticalSection);
+}
+
+VOID
+Or2WinLeaveCriticalSection(
+ PSZ FuncName,
+ LPCRITICAL_SECTION lpCriticalSection
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, LeaveCriticalSectionStr));
+ }
+ LeaveCriticalSection(lpCriticalSection);
+}
+
+int
+Or2WinLoadStringA(
+ PSZ FuncName,
+ HINSTANCE hInstance,
+ UINT uID,
+ LPSTR lpBuffer,
+ int nBufferMax
+ )
+{
+ int iLength;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, LoadStringAStr));
+ }
+ iLength = LoadStringA(hInstance, uID, lpBuffer, nBufferMax);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (iLength == 0)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, LoadStringAStr));
+ }
+ }
+ return(iLength);
+}
+
+int
+Or2WinMessageBoxA(
+ PSZ FuncName,
+ HWND hWnd,
+ LPCSTR lpText,
+ LPCSTR lpCaption,
+ UINT uType
+ )
+{
+ int iButton;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, MessageBoxAStr));
+ }
+ iButton = MessageBoxA(hWnd , lpText, lpCaption , uType);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (iButton == 0)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, MessageBoxAStr));
+ }
+ }
+ return(iButton);
+}
+
+HANDLE
+Or2WinOpenProcess(
+ PSZ FuncName,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ DWORD dwProcessId
+ )
+{
+ HANDLE hProcess;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, OpenProcessStr));
+ }
+ hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (hProcess == NULL)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, OpenProcessStr));
+ }
+ }
+ return(hProcess);
+}
+
+DWORD
+Or2WinResumeThread(
+ PSZ FuncName,
+ HANDLE hThread
+ )
+{
+ DWORD dwCount;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, ResumeThreadStr));
+ }
+ dwCount = ResumeThread(hThread);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (dwCount == -1)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, ResumeThreadStr));
+ }
+ }
+ return(dwCount);
+}
+
+UINT
+Or2WinSetErrorMode(
+ PSZ FuncName,
+ UINT uMode
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetErrorModeStr));
+ }
+ return(SetErrorMode(uMode));
+}
+
+BOOL
+Or2WinSetEvent(
+ PSZ FuncName,
+ HANDLE hEvent
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetEventStr));
+ }
+ bRc = SetEvent(hEvent);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetEventStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinSetStdHandle(
+ PSZ FuncName,
+ DWORD nStdHandle,
+ HANDLE hHandle
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetStdHandleStr));
+ }
+ bRc = SetStdHandle(nStdHandle, hHandle);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetStdHandleStr));
+ }
+ }
+ return(bRc);
+}
+
+LCID
+Or2WinGetThreadLocale(
+ PSZ FuncName
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetThreadLocaleStr));
+ }
+ return(GetThreadLocale());
+}
+
+BOOL
+Or2WinSetThreadLocale(
+ PSZ FuncName,
+ LCID Locale
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetThreadLocaleStr));
+ }
+ bRc = SetThreadLocale(Locale);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetThreadLocaleStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinSetThreadPriority(
+ PSZ FuncName,
+ HANDLE hThread,
+ int nPriority
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SetThreadPriorityStr));
+ }
+ bRc = SetThreadPriority(hThread, nPriority);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SetThreadPriorityStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinSystemParametersInfoA(
+ PSZ FuncName,
+ UINT uiAction,
+ UINT uiParam,
+ PVOID pvParam,
+ UINT fWinIni
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, SystemParametersInfoAStr));
+ }
+ bRc = SystemParametersInfoA(uiAction, uiParam, pvParam, fWinIni);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, SystemParametersInfoAStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinTerminateThread(
+ PSZ FuncName,
+ HANDLE hThread,
+ DWORD dwExitCode
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, TerminateThreadStr));
+ }
+ bRc = TerminateThread(hThread, dwExitCode);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, TerminateThreadStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinVerifyConsoleIoHandle(
+ PSZ FuncName,
+ HANDLE hIoHandle
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, VerifyConsoleIoHandleStr));
+ }
+ bRc = VerifyConsoleIoHandle(hIoHandle);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, VerifyConsoleIoHandleStr));
+ }
+ }
+ return(bRc);
+}
+
+DWORD
+Or2WinWaitForSingleObject(
+ PSZ FuncName,
+ HANDLE hHandle,
+ DWORD dwMilliseconds
+ )
+{
+ DWORD dwEvent;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, WaitForSingleObjectStr));
+ }
+ dwEvent = WaitForSingleObject(hHandle, dwMilliseconds);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (dwEvent == -1)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, WaitForSingleObjectStr));
+ }
+ }
+ return(dwEvent);
+}
+
+BOOL
+Or2WinWriteFile(
+ PSZ FuncName,
+ HANDLE hFile,
+ CONST VOID *lpBuffer,
+ DWORD nNumberOfBytesToWrite,
+ LPDWORD lpNumberOfBytesWritten,
+ LPOVERLAPPED lpOverlapped
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, WriteFileStr));
+ }
+ bRc = WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite,
+ lpNumberOfBytesWritten, lpOverlapped);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, WriteFileStr));
+ }
+ }
+ return(bRc);
+}
+
+/* YOSEFD Apr-1-1996 Not in use
+int
+Or2Win_read(
+ PSZ FuncName,
+ int hFile,
+ void *Buffer,
+ unsigned int Length
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, _readStr));
+ }
+ return(_read(hFile, Buffer, Length));
+}
+*/
+
+BOOL
+Or2WinReadFile(
+ PSZ FuncName,
+ HANDLE hFile,
+ LPVOID lpBuffer,
+ DWORD nNumberOfBytesToRead,
+ LPDWORD lpNumberOfBytesRead,
+ LPOVERLAPPED lpOverlapped
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, ReadFileStr));
+ }
+ bRc = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,
+ lpOverlapped);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, ReadFileStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinIsValidCodePage(
+ PSZ FuncName,
+ UINT CodePage
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, IsValidCodePageStr));
+ }
+ bRc = IsValidCodePage(CodePage);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, IsValidCodePageStr));
+ }
+ }
+ return(bRc);
+}
+
+UINT
+Or2WinGetACP(
+ PSZ FuncName
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetACPStr));
+ }
+ return(GetACP());
+}
+
+UINT
+Or2WinGetOEMCP(
+ PSZ FuncName
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetOEMCPStr));
+ }
+ return(GetOEMCP());
+}
+
+BOOL
+Or2WinGetCPInfo(
+ PSZ FuncName,
+ UINT CodePage,
+ LPCPINFO lpCPInfo
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetCPInfoStr));
+ }
+ bRc = GetCPInfo(CodePage, lpCPInfo );
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetCPInfoStr));
+ }
+ }
+ return(bRc);
+}
+
+BOOL
+Or2WinIsDBCSLeadByte(
+ PSZ FuncName,
+ BYTE TestChar
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, IsDBCSLeadByteStr));
+ }
+ bRc = IsDBCSLeadByte(TestChar);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, IsDBCSLeadByteStr));
+ }
+ }
+ return(bRc);
+}
+
+int
+Or2WinMultiByteToWideChar(
+ PSZ FuncName,
+ UINT CodePage,
+ DWORD dwFlags,
+ LPCSTR lpMultiByteStr,
+ int cchMultiByte,
+ LPWSTR lpWideCharStr,
+ int cchWideChar
+ )
+{
+ int iLength;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, MultiByteToWideCharStr));
+ }
+ iLength = MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cchMultiByte,
+ lpWideCharStr, cchWideChar);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!iLength)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, MultiByteToWideCharStr));
+ }
+ }
+ return(iLength);
+}
+
+int
+Or2WinWideCharToMultiByte(
+ PSZ FuncName,
+ UINT CodePage,
+ DWORD dwFlags,
+ LPCWSTR lpWideCharStr,
+ int cchWideChar,
+ LPSTR lpMultiByteStr,
+ int cchMultiByte,
+ LPSTR lpDefaultChar,
+ LPBOOL lpUsedDefaultChar
+ )
+{
+ int iLength;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, WideCharToMultiByteStr));
+ }
+ iLength = WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar,
+ lpMultiByteStr, cchMultiByte, lpDefaultChar, lpUsedDefaultChar);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!iLength)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, WideCharToMultiByteStr));
+ }
+ }
+ return(iLength);
+}
+
+int
+Or2WinCompareStringW(
+ PSZ FuncName,
+ LCID Locale,
+ DWORD dwCmpFlags,
+ LPCWSTR lpString1,
+ int cchCount1,
+ LPCWSTR lpString2,
+ int cchCount2
+ )
+{
+ int iLength;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, CompareStringWStr));
+ }
+ iLength = CompareStringW(Locale, dwCmpFlags, lpString1, cchCount1, lpString2,
+ cchCount2);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!iLength)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, CompareStringWStr));
+ }
+ }
+ return(iLength);
+}
+
+int
+Or2WinLCMapStringW(
+ PSZ FuncName,
+ LCID Locale,
+ DWORD dwMapFlags,
+ LPCWSTR lpSrcStr,
+ int cchSrc,
+ LPWSTR lpDestStr,
+ int cchDest
+ )
+{
+ int iLength;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, LCMapStringWStr));
+ }
+ iLength = LCMapStringW(Locale, dwMapFlags, lpSrcStr, cchSrc, lpDestStr,
+ cchDest);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!iLength)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, LCMapStringWStr));
+ }
+ }
+ return(iLength);
+}
+
+int
+Or2WinGetLocaleInfoW(
+ PSZ FuncName,
+ LCID Locale,
+ LCTYPE LCType,
+ LPWSTR lpLCData,
+ int cchData
+ )
+{
+ int iLength;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetLocaleInfoWStr));
+ }
+ iLength = GetLocaleInfoW(Locale, LCType, lpLCData, cchData);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!iLength)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetLocaleInfoWStr));
+ }
+ }
+ return(iLength);
+}
+
+LANGID
+Or2WinGetSystemDefaultLangID(
+ PSZ FuncName
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetSystemDefaultLangIDStr));
+ }
+ return(GetSystemDefaultLangID());
+}
+
+LANGID
+Or2WinGetUserDefaultLangID(
+ PSZ FuncName
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetUserDefaultLangIDStr));
+ }
+ return(GetUserDefaultLangID());
+}
+
+LCID
+Or2WinGetSystemDefaultLCID(
+ PSZ FuncName
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetSystemDefaultLCIDStr));
+ }
+ return(GetSystemDefaultLCID());
+}
+
+LCID
+Or2WinGetUserDefaultLCID(
+ PSZ FuncName
+ )
+{
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetUserDefaultLCIDStr));
+ }
+ return(GetUserDefaultLCID());
+}
+
+BOOL
+Or2WinGetStringTypeW(
+ PSZ FuncName,
+ DWORD dwInfoType,
+ LPCWSTR lpSrcStr,
+ int cchSrc,
+ LPWORD lpCharType
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, GetStringTypeWStr));
+ }
+ bRc = GetStringTypeW(dwInfoType, lpSrcStr, cchSrc, lpCharType);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, GetStringTypeWStr));
+ }
+ }
+ return(bRc);
+}
+
+int
+Or2WinFoldStringW(
+ PSZ FuncName,
+ DWORD dwMapFlags,
+ LPCWSTR lpSrcStr,
+ int cchSrc,
+ LPWSTR lpDestStr,
+ int cchDest
+ )
+{
+ int iLength;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, FoldStringWStr));
+ }
+ iLength = FoldStringW(dwMapFlags, lpSrcStr, cchSrc, lpDestStr, cchDest);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!iLength)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, FoldStringWStr));
+ }
+ }
+ return(iLength);
+}
+
+HANDLE
+Or2WinHeapCreate(
+ PSZ FuncName,
+ DWORD flOptions,
+ DWORD dwInitialSize,
+ DWORD dwMaximumSize
+ )
+{
+ HANDLE hHeap;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, HeapCreateStr));
+ }
+ hHeap = HeapCreate(flOptions, dwInitialSize, dwMaximumSize);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (hHeap == NULL)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, HeapCreateStr));
+ }
+ }
+ return(hHeap);
+}
+
+LPSTR
+Or2WinHeapAlloc(
+ PSZ FuncName,
+ HANDLE hHeap,
+ DWORD dwFlags,
+ DWORD dwBytes
+ )
+{
+ LPSTR lpStr;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, HeapAllocStr));
+ }
+ lpStr = HeapAlloc(hHeap, dwFlags, dwBytes);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!lpStr)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, HeapAllocStr));
+ }
+ }
+ return(lpStr);
+}
+
+BOOL
+Or2WinHeapFree(
+ PSZ FuncName,
+ HANDLE hHeap,
+ DWORD dwFlags,
+ LPSTR lpMem
+ )
+{
+ BOOL bRc;
+
+ IF_OS2_DEBUG( WIN )
+ {
+ KdPrint(("%s => %s\n", FuncName, HeapFreeStr));
+ }
+ bRc = HeapFree(hHeap, dwFlags, lpMem);
+ IF_OS2_DEBUG( WIN )
+ {
+ if (!bRc)
+ {
+ KdPrint((" *** FAIL *** %s => %s\n", FuncName, HeapFreeStr));
+ }
+ }
+ return(bRc);
+}
+
+
+#endif