summaryrefslogtreecommitdiffstats
path: root/private/os2/client
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/client
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
245 files changed, 176025 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
+ );