Index: trunk/src/win32k/include/OS2KPTDA.h
===================================================================
--- trunk/src/win32k/include/OS2KPTDA.h	(revision 3832)
+++ trunk/src/win32k/include/OS2KPTDA.h	(revision 3832)
@@ -0,0 +1,63 @@
+/* $Id: OS2KPTDA.h,v 1.1 2000-07-16 22:21:19 bird Exp $
+ *
+ * PTDA access functions.
+ *
+ * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+#ifndef _ptda_h_
+#define _ptda_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+typedef struct _PTDA
+{
+    struct _PTDA    *p1;
+    struct _PTDA    *p2;
+    struct _PTDA    *p3;
+    struct _PTDA    *pPTDAExecChild;    /* This offset is fixed for all supported OS/2 version. */
+} PTDA, *PPTDA, **PPPTDA;
+
+
+extern  PPPTDA      ppPTDACur;          /* Please access this only thru the ptdaGetCur() function. */
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/**
+ * Gets the current PTDA pointer.
+ * @returns     Pointer to the current PTDA.
+ * @remark      Using import stuff.
+ */
+//PPTDA   ptdaGetCur(void);
+#define ptdaGetCur()                    (*ppPTDACur)
+
+
+
+/**
+ * Gets the pPTDAExecChild member of the PTDA.
+ * @returns     Pointer to child being started. NULL if none.
+ * @param       pPTDA   Pointer to the ptda structure.
+ * @remark      This member is fixed for all the supported kernels (all 2.x kernels too?).
+ */
+//PPTDA   ptdaGet_pPTDAExecChild(PPTDA pPTDA);
+#define ptdaGet_pPTDAExecChild(pPTDA)   ((PPTDA)(pPTDA))->pPTDAExecChild
+
+
+
+USHORT  ptdaGet_ptda_environ(PPTDA pPTDA);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: trunk/src/win32k/include/OS2KSEM.h
===================================================================
--- trunk/src/win32k/include/OS2KSEM.h	(revision 3832)
+++ trunk/src/win32k/include/OS2KSEM.h	(revision 3832)
@@ -0,0 +1,64 @@
+/* $Id: OS2KSEM.h,v 1.1 2000-07-16 22:21:19 bird Exp $
+ *
+ * OS/2 kernel Semaphore functions.
+ *
+ * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+
+#ifndef _OS2KSEM_h_
+#define _OS2KSEM_h_
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#define KSEM_INDEFINITE_WAIT     -1L
+#define KSEM_IMMEDIATE_RETURN     0L
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+typedef ULONG  HKSEM;                   /* Handle to kernel semaphore. */
+typedef HKSEM  PHKSEM;                  /* Pointer to kernel semaphore handle. */
+typedef HKSEM  HKMTX;                   /* Handle to kernel mutex semaphore. */
+typedef HKSEM  HKEV;                    /* Handle to kernel event semaphore. */
+
+
+/*******************************************************************************
+*   Exported Functions                                                         *
+*******************************************************************************/
+/*
+ * Mutex semaphores.
+ * NOTE! Only is KSEMRequestMutex currently is imported!
+ */
+extern ULONG KRNLCALL KSEMRequestMutex(HKMTX hkmtx, ULONG ulTimeout);
+extern VOID  KRNLCALL KSEMReleaseMutex(HKMTX hkmtx);
+extern ULONG KRNLCALL KSEMQueryMutex(HKMTX hkmtx, PUSHORT pus);
+
+
+#if 0
+/*
+ * Event semaphores.
+ */
+extern VOID  KRNLCALL KSEMResetEvent(HKEV hkevent);
+extern VOID  KRNLCALL KSEMPostEvent(HKEV hkevent);
+extern ULONG KRNLCALL KSEMWaitEvent(HKEV hkevent);
+
+/*
+ * Some other KSEM prefixed functions - parameters's not that obvious...
+ */
+extern ULONG KRNLCALL KSEMAlloc(PHKSEM phksem, ULONG p1, ULONG p2);
+extern ULONG KRNLCALL KSEMCreate(PHKSEM phksem, ULONG type);
+extern ULONG KRNLCALL KSEMRequestExclusive(HKSEM hksem, ULONG );
+extern ULONG KRNLCALL KSEMRequestShared(HKSEM hksem, ULONG);
+extern VOID  KRNLCALL KSEMDestroy(HKSEM hksem);
+extern VOID  KRNLCALL KSEMInit(HKSEM hksem, ULONG p1, ULONG p2);
+extern VOID  KRNLCALL KSEMQuery(HKSEM hksem, ULONG p2)
+extern VOID  KRNLCALL KSEMRelease(HKSEM hksem);
+#endif
+#endif
+
Index: trunk/src/win32k/include/OS2KTCB.h
===================================================================
--- trunk/src/win32k/include/OS2KTCB.h	(revision 3832)
+++ trunk/src/win32k/include/OS2KTCB.h	(revision 3832)
@@ -0,0 +1,52 @@
+/* $Id: OS2KTCB.h,v 1.1 2000-07-16 22:21:18 bird Exp $
+ *
+ * TCB - Thread Control Block access methods.
+ *
+ * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+#ifndef _tcb_h_
+#define _tcb_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+typedef struct _TCB
+{
+    char    dummy;
+} TCB, *PTCB, **PPTCB;
+
+
+
+extern PPTCB    ppTCBCur;
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+
+/**
+ * Gets pointer to the current TCB.
+ * @returns     Pointer to the current thread control block (TCB).
+ *              NULL if not task-time.
+ */
+#define tcbGetCur()     *ppTCBCur
+
+
+USHORT  tcbGetTCBFailErr(PTCB pTCB);
+USHORT  tcbSetTCBFailErr(PTCB pTCB, USHORT TCBFailErr);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: trunk/src/win32k/include/OS2KTK.h
===================================================================
--- trunk/src/win32k/include/OS2KTK.h	(revision 3832)
+++ trunk/src/win32k/include/OS2KTK.h	(revision 3832)
@@ -0,0 +1,104 @@
+/* $Id: OS2KTK.h,v 1.1 2000-07-16 22:21:18 bird Exp $
+ *
+ * OS2KTK - OS/2 Kernel Task.
+ *
+ * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+#ifndef _OS2KTK_h_
+#define _OS2KTK_h_
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#define TK_FUSU_FATAL       0x3         /* Traps the task on failure. */
+#define TK_FUSU_NONFATAL    0x0         /* Returns error code to caller on failure. */
+
+
+
+#define TKFuChar(pch, pchUsr) \
+            TKFuBuff((PVOID)pch, (PVOID)pchUsr, sizeof(char), TK_FUSU_FATAL);
+#define TKSuChar(pchUsr, pch) \
+            TKSuBuff((PVOID)pchUsr, (PVOID)pch, sizeof(char), TK_FUSU_FATAL);
+
+#define TKFuCharNF(pch, pchUsr) \
+            TKFuBuff((PVOID)pch, (PVOID)pchUsr, sizeof(char), TK_FUSU_NONFATAL);
+#define TKSuCharNF(pchUsr, pch) \
+            TKSuBuff((PVOID)pchUsr, (PVOID)pch, sizeof(char), TK_FUSU_NONFATAL);
+
+
+#define TKFuUShort(pus, pusUsr) \
+            TKFuBuff((PVOID)pus, (PVOID)pusUsr, sizeof(USHORT), TK_FUSU_FATAL);
+#define TKSuUShort(pusUsr, pus) \
+            TKSuBuff((PVOID)pusUsr, (PVOID)pus, sizeof(USHORT), TK_FUSU_FATAL);
+
+#define TKFuUShortNF(pus, pusUsr) \
+            TKFuBuff((PVOID)pus, (PVOID)pusUsr, sizeof(USHORT), TK_FUSU_NONFATAL);
+#define TKSuUShortNF(pusUsr, pus) \
+            TKSuBuff((PVOID)pusUsr, (PVOID)pus, sizeof(USHORT), TK_FUSU_NONFATAL);
+
+
+#define TKFuULong(pul, pulUsr) \
+            TKFuBuff((PVOID)pul, (PVOID)pulUsr, sizeof(ULONG), TK_FUSU_FATAL);
+#define TKSuULong(pulUsr, pul) \
+            TKSuBuff((PVOID)pulUsr, (PVOID)pul, sizeof(ULONG), TK_FUSU_FATAL);
+
+#define TKFuULongNF(pul, pulUsr) \
+            TKFuBuff((PVOID)pul, (PVOID)pulUsr, sizeof(ULONG), TK_FUSU_NONFATAL);
+#define TKSuULongNF(pulUsr, pul) \
+            TKSuBuff((PVOID)pulUsr, (PVOID)pul, sizeof(ULONG), TK_FUSU_NONFATAL);
+
+
+#define TKFuStrLen(pcch, pvUsr, cchMax) \
+            TKFuBufLen(pcch, pvUsr, cchMax, TK_FUSU_FATAL, FALSE)
+#define TKFuStrLenNZ(pcch, pvUsr, cchMax) \
+            TKFuBufLenNZ(pcch, pvUsr, cchMax, TK_FUSU_NONFATAL, FALSE)
+
+#define TKFuStrLenZ(pcch, pvUsr, cchMax) \
+            TKFuBufLenZ(pcch, pvUsr, cchMax, TK_FUSU_FATAL, TRUE)
+#define TKFuStrLenZNZ(pcch, pvUsr, cchMax) \
+            TKFuBufLenZNZ(pcch, pvUsr, cchMax, TK_FUSU_NONFATAL, TRUE)
+
+
+
+
+
+/**
+ * Copy user memory into system memory.
+ * @returns   OS/2 return code. (NO_ERROR is success)
+ * @param     pv     Pointer to target (system) data area.
+ * @param     pvUsr  Pointer to source (user) data area.
+ * @param     cb     Count of bytes to copy.
+ * @param     fl     Flags.
+ */
+extern ULONG KRNLCALL   TKFuBuff(PVOID pv, PVOID pvUsr, ULONG cb, ULONG fl);
+
+
+/**
+ * Copy system memory to user memory.
+ * @returns   OS/2 return code. (NO_ERROR is success)
+ * @param     pvUsr  Pointer to target (user) data area.
+ * @param     pv     Pointer to source (system) data area.
+ * @param     cb     Count of bytes to copy.
+ * @param     fl     Flags.
+ */
+extern ULONG KRNLCALL   TKSuBuff(PVOID pvUsr, PVOID pv, ULONG cb, ULONG fl);
+
+
+/**
+ * String length.
+ * @returns   OS/2 return code. (NO_ERROR is success)
+ * @param     pcch      Pointer to length variable.
+ * @param     pvUsr     Pointer to user data to preform string length on.
+ * @param     cchMax    Max string length.
+ * @param     fl        Flags.
+ * @param     fDblNULL  TRUE:  Double '\0' (ie. '\0\0') terminated. Usefull for scanning environments.
+ *                      FALSE: Single string. (ie. one '\0').
+ */
+extern ULONG KRNLCALL   TKFuBufLen(PLONG pcch, PVOID pvUsr, ULONG cchMax, ULONG fl, BOOL fDblNULL);
+
+
+#endif
Index: trunk/src/win32k/include/test.h
===================================================================
--- trunk/src/win32k/include/test.h	(revision 3832)
+++ trunk/src/win32k/include/test.h	(revision 3832)
@@ -0,0 +1,128 @@
+/* $Id: test.h,v 1.1 2000-07-16 22:17:13 bird Exp $
+ *
+ * Definitions and declarations for test moduls.
+ *
+ * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+
+#ifndef _test_h_
+#define _test_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+VOID  _Optlink ThunkStack32To16(VOID);  /* dh.asm */
+VOID  _Optlink ThunkStack16To32(VOID);  /* dh.asm */
+VOID  _Optlink dhinit(VOID);            /* dh.asm */
+ULONG _Optlink getDHRouterFarPtr(VOID); /* dh.asm */
+ULONG _Optlink InitElf(PVOID);          /* init.asm */
+ULONG _Optlink InitWin32k(PVOID);       /* init.asm */
+ULONG _Optlink CalltkExecPgm(ULONG execFlags, PCSZ pArg, PCSZ pEnv, PCSZ pExecName); /* fakea.asm */
+
+USHORT  _Optlink GetSelectorCODE16(void);
+USHORT  _Optlink GetSelectorDATA16(void);
+USHORT  _Optlink GetSelectorCODE32(void);
+USHORT  _Optlink GetSelectorDATA32(void);
+
+
+#ifndef INCL_NO_FAKE
+/* fake functions */
+ULONG LDRCALL fakeldrOpen(PSFN phFile, PSZ pszFilename, PULONG pfl);
+ULONG LDRCALL fakeldrClose(SFN hFile);
+ULONG LDRCALL fakeldrRead(SFN hFile, ULONG ulOffset, PVOID pvBuffer, ULONG fpBuffer, ULONG cbToRead, PMTE pMTE);
+ULONG LDRCALL fakeLDRQAppType(PSZ pszFilename, PULONG pul);
+ULONG LDRCALL fakeldrEnum32bitRelRecs(
+    PMTE    pMTE,
+    ULONG   iObject,
+    ULONG   iPageTable,
+    PVOID   pvPage,
+    ULONG   ulPageAddress,
+    PVOID   pvPTDA
+    );
+APIRET KRNLCALL fakeIOSftOpen(
+    PSZ pszFilename,
+    ULONG flOpenFlags,
+    ULONG fsOpenMode,
+    PSFN phFile,
+    PULONG pulsomething
+    );
+APIRET KRNLCALL fakeIOSftClose(
+    SFN hFile
+    );
+APIRET KRNLCALL fakeIOSftTransPath(
+    PSZ pszPath
+    );
+APIRET KRNLCALL fakeIOSftReadAt(
+    SFN hFile,
+    PULONG pcbActual,
+    PVOID pvBuffer,
+    ULONG fpBuffer,
+    ULONG ulOffset
+    );
+APIRET KRNLCALL fakeIOSftWriteAt(
+    SFN hFile,
+    PULONG pcbActual,
+    PVOID pvBuffer,
+    ULONG fpBuffer,
+    ULONG ulOffset
+    );
+APIRET KRNLCALL fakeSftFileSize(
+    SFN hFile,
+    PULONG pcbFile
+    );
+HMTE KRNLCALL fakeVMGetOwner(
+    ULONG ulCS,
+    ULONG ulEIP);
+APIRET KRNLCALL fakeVMAllocMem(
+    ULONG   cbSize,
+    ULONG   cbCommit,
+    ULONG   flFlags1,
+    HPTDA   hPTDA,
+    USHORT  usVMOwnerId,
+    HMTE    hMTE,
+    ULONG   flFlags2,
+    ULONG   SomeArg2,
+    PVMAC   pvmac);
+APIRET KRNLCALL fakeVMObjHandleInfo(
+    USHORT  usHob,
+    PULONG  pulAddr,
+    PUSHORT pushPTDA);
+ULONG LDRCALL fakeldrOpenPath(PCHAR pachFilename, USHORT cchFilename, ldrlv_t *plv, PULONG pful);
+ULONG LDRCALL fakeLDRClearSem(void);
+ULONG KRNLCALL fakeKSEMRequestMutex(HKMTX hkmtx, ULONG ulTimeout);
+extern HKMTX        fakeLDRSem;
+ULONG KRNLCALL   fakeTKFuBuff(PVOID pv, PVOID pvUsr, ULONG cb, ULONG fl);
+ULONG KRNLCALL   fakeTKSuBuff(PVOID pvUsr, PVOID pv, ULONG cb, ULONG fl);
+ULONG KRNLCALL   fakeTKFuBufLen(PLONG pcch, PVOID pvUsr, ULONG cchMax, ULONG fl, BOOL fDblNULL);
+PMTE LDRCALL  fakeldrValidateMteHandle(HMTE hMTE);
+void _Optlink fakeg_tkExecPgm(void);    /* Not callable! (fakea.asm) */
+void _Optlink fakef_FuStrLenZ(void);    /* Not callable! (fakea.asm) */
+void _Optlink fakef_FuStrLen(void);     /* Not callable! (fakea.asm) */
+void _Optlink fakef_FuBuff(void);       /* Not callable! (fakea.asm) */
+extern PTCB     fakepTCBCur;
+extern PPTDA    fakepPTDACur;
+extern char     fakeptda_start;
+extern USHORT   fakeptda_environ;
+
+#endif /* INCL_NO_FAKE */
+
+#ifdef INCL_16
+extern USHORT  usFakeVerMajor;          /* define in probkrnl.c */
+extern USHORT  usFakeVerMinor;          /* define in probkrnl.c */
+#else
+extern USHORT  _usFakeVerMajor;
+extern USHORT  _usFakeVerMinor;
+#endif
+
+extern const char *pszInternalRevision; /* defined in win32ktst.c */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: trunk/src/win32k/ldr/myldrOpenPath.cpp
===================================================================
--- trunk/src/win32k/ldr/myldrOpenPath.cpp	(revision 3832)
+++ trunk/src/win32k/ldr/myldrOpenPath.cpp	(revision 3832)
@@ -0,0 +1,180 @@
+/* $Id: myldrOpenPath.cpp,v 1.1 2000-07-16 22:21:16 bird Exp $
+ *
+ * myldrOpenPath - ldrOpenPath used to open executables we'll override
+ * this to altern the search path for DLLs.
+ *
+ * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#define INCL_DOSERRORS
+#define INCL_NOPMAPI
+#define INCL_OS2KRNL_TCB
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <os2.h>
+
+#include <memory.h>
+#include <stdlib.h>
+
+#include "log.h"
+#include "dev32.h"
+#include "dev32hlp.h"
+#include <peexe.h>
+#include <exe386.h>
+#include "OS2Krnl.h"
+#include "avl.h"
+#include "ldrCalls.h"
+#include "ldr.h"
+#include "ModuleBase.h"
+
+
+
+/**
+ * myldrOpenPath - opens file eventually searching loader specific paths
+ *
+ * @returns   OS2 return code.
+ *            plv->lv_sfn  is set to filename handle.
+ * @param     pachFilename  Pointer to modulename. Not zero terminated!
+ * @param     cchFilename   Modulename length.
+ * @param     plv           Loader local variables? (Struct from KERNEL.SDF)
+ * @param     pful          Pointer to flags which are passed on to ldrOpen.
+ * @sketch
+ * This is roughly what the original ldrOpenPath does:
+ *      Save pTCBCur->TCBFailErr.
+ *      if !CLASS_GLOBAL or miniifs then
+ *          ldrOpen(pachFilename)
+ *      else
+ *          loop until no more libpath elements
+ *              get next libpath element and add it to the modname.
+ *              try open the modname
+ *              if successfull then break the loop.
+ *          endloop
+ *      endif
+ *      Restore pTCBCur->TCBFailErr.
+ * @remark    This function will change the "Loader state".
+ *
+ */
+ULONG LDRCALL myldrOpenPath( /* retd  0x10 */
+    PCHAR       pachFilename,       /* ebp + 0x08 */
+    USHORT      cchFilename,        /* ebp + 0x0c */
+    ldrlv_t *   plv,                /* ebp + 0x10 */
+    PULONG      pful                /* ebp + 0x14 */
+    )
+{
+
+    APIRET rc;
+
+    #ifdef DEBUG
+    /* !paranoia!
+     * Check that the passed in parameters are valid.
+     * If they aren't we'll log this situation and forward the call to ldrOpenPath.
+     */
+    if ((unsigned)pachFilename < 0x10000
+        || (unsigned)plv < 0x10000
+        || cchFilename == 0
+        || cchFilename >= CCHMAXPATH)
+    {
+        kprintf(("myldrOpenPath: Invalid parameters!!!!\n"
+                 "    pachFilename 0x%08x  cchFilename 0x%04x  plv 0x%08x  pful=0x%08x\n",
+                 pachFilename, cchFilename, plv, pful
+                 ));
+        return ldrOpenPath(pachFilename, cchFilename, plv, pful);
+    }
+    #endif
+
+
+    /*
+     * We'll check what type of image being opned and save that piece of
+     * information for use in (my)ldrOpen.
+     */
+    if (plv->lv_type == LVTYPE_EXE)
+        setLdrStateLoadingEXE();
+    else if (plv->lv_type == LVTYPE_DLL)
+        setLdrStateLoadingDLL();
+    else
+        setLdrStateLoadingUnsupported();
+
+    /*
+     * Overload the behaviour of ldrOpenPath?
+     *  - Currently only for DLL loading into the GLOBAL class
+     */
+    if (isLdrStateLoadingDLL()
+        && (plv->lv_class == CLASS_GLOBAL || plv->lv_class == CLASS_ALL))
+    {
+        /*
+         * If the executable being loaded is one of our executables we'll
+         * use our method for finding dynamic link libraries.
+         *
+         * At tkExecPgm time this is quite easy. The executable must have been
+         * opened allready and the OUREXE flag will be set if it's one of our
+         * executables.
+         *
+         * At non-tkExecPgm time it's a bit more difficult. We'll have to get
+         * the local infosegment for the process/thread running and check
+         * if the executable (EXE) hMTE is one of ours. We'll do a lookup in
+         * the AVL tree.
+         *
+         * In both cases the result will have to be a module pointer which we
+         * will invoke the overriding ldrOpenPath by.
+         */
+        PMODULE     pExe = NULL;        /* Pointer to executable which we're to invoke ldrOpenPath by. */
+        if (isLdrStateExecPgm())
+        {
+            if (isLdrStateLoadingOurEXE())
+                pExe = pExeModule;
+        }
+        else
+        {
+            struct InfoSegLDT *pInfoSeg;
+            pInfoSeg = (struct InfoSegLDT *)D32Hlp_GetDOSVar(DHGETDOSV_SYSINFOSEG, 0);
+            if (pInfoSeg == NULL)
+            {
+                pExe = getModuleByhMTE(pInfoSeg->LIS_DI); /* LIS_DI is the same as hmod in LINFOSEG from bsedos16.h.  */
+                #ifdef DEBUG            /* While testing! */
+                kprintf(("myldrOpenPath: getModuleByhMTE returned 0x%x08 for hmod=0x%04\n",
+                         pExe, pInfoSeg->LIS_DI));
+                #endif
+            }
+            #ifdef DEBUG                /* While testing! */
+            else
+                dprintf(("myldrOpenPath: D32Hlp_GetDOSVar(DHGETDOSV_SYSINFOSEG) failed.\n"));
+            #endif
+        }
+
+        /*
+         * If executable module was found the invoke the overriding ldrOpenPath function.
+         */
+        if (pExe != NULL)
+        {
+            /* We'll have to save the TCBFailErr since we don't want to cause
+             * Hard Errors while searching invalid paths, etc. (ldrOpenPath does this!)
+             */
+            USHORT  TCBFailErr_save = tcbGetTCBFailErr(tcbGetCur());
+            rc = pExe->Data.pModule->openPath(pachFilename, cchFilename, plv, pful);
+            tcbSetTCBFailErr(tcbGetCur(), TCBFailErr_save);
+        }
+        else
+            rc = ldrOpenPath(pachFilename, cchFilename, plv, pful);
+    }
+    else
+        rc = ldrOpenPath(pachFilename, cchFilename, plv, pful);
+
+
+    /*
+     * Change Loader State - Clear the type part of the loading bits.
+     */
+    setLdrStateClearLoadingType();
+
+    return rc;
+}
+
+
+
Index: trunk/src/win32k/misc/OS2KPTDA.c
===================================================================
--- trunk/src/win32k/misc/OS2KPTDA.c	(revision 3832)
+++ trunk/src/win32k/misc/OS2KPTDA.c	(revision 3832)
@@ -0,0 +1,43 @@
+/* $Id: OS2KPTDA.c,v 1.1 2000-07-16 22:21:17 bird Exp $
+ *
+ * PTDA access functions.
+ *
+ * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <os2.h>
+#include <OS2KPTDA.h>
+
+
+/*******************************************************************************
+*   External Data                                                              *
+*******************************************************************************/
+/*
+ * Requires the following imports:
+ *      pPTDACur
+ *      ptda_start
+ *      ptda_environ
+ */
+extern ULONG    pptda_start;
+extern ULONG    pptda_environ;
+
+
+/**
+ * Gets the ptda_environ PTDA member. This member holds the memory object handle
+ * for the environment block of the processes.
+ * @returns     Content of the pPTDA->ptda_environ member.
+ * @param       pPTDA   PTDA Pointer. (NULL is not allowed!)
+ * @sketch
+ */
+USHORT  ptdaGet_ptda_environ(PPTDA pPTDA)
+{
+    return *(PUSHORT)(void*)(((char*)(void*)pPTDA) + (pptda_environ - pptda_start));
+}
+
Index: trunk/src/win32k/misc/OS2KTCB.c
===================================================================
--- trunk/src/win32k/misc/OS2KTCB.c	(revision 3832)
+++ trunk/src/win32k/misc/OS2KTCB.c	(revision 3832)
@@ -0,0 +1,113 @@
+/* $Id: OS2KTCB.c,v 1.1 2000-07-16 22:21:17 bird Exp $
+ *
+ * TCB - Thread Control Block access methods.
+ *
+ * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <os2.h>
+#include <OS2KTCB.h>
+#include "options.h"
+
+
+/*******************************************************************************
+*   External Data                                                              *
+*******************************************************************************/
+/*
+ * Requires the following import(s):
+ *      pTCBCur
+ */
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+int     offTCBFailErr = 0;
+
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static  BOOL initTCB(void);
+
+
+/**
+ * Init the TCB offset(s).
+ * @returns     Success indicator. (TRUE = success; FALSE = failure)
+ */
+static BOOL initTCB(void)
+{
+    /*
+     * !!IMPORTANT!!
+     * Please note that when we don't define top limits here. New fixpack may have
+     * other values. But since they very seldom do, we'll gamble on no change!
+     * (Applies to Warp 3 and WS4eB)
+     * !!IMPORTANT!!
+     *
+     * These values are derived from the kernel[d].SDFs and SG24-4640-00.
+     */
+
+    /* WS4eB GA and above. */
+    if (options.ulBuild >= 14039)
+    {
+        offTCBFailErr = isSMPKernel() ? 0x1fa : 0x1ea;
+    }
+    else /* Warp 4 GA - fp12 */
+        if (options.ulBuild >= 9023 && options.ulBuild <= 9036)
+    {
+        offTCBFailErr = 0x18e;
+    }
+    else /* Warp 3 fp32 - fp62. */
+        if (options.ulBuild >= 8255 && options.ulBuild <= 8285)
+    {
+        offTCBFailErr = isSMPKernel() ? 0x1ba : 0x14e;
+    }
+    else
+        return FALSE;
+    return TRUE;
+}
+
+
+
+/**
+ * Get the content of the TCB data member TCBFailErr.
+ * Intended used to save and restore the value in ldrOpenPath.
+ * @returns     Value of TCBFaileErr. (0xffff on error)
+ * @param       pTCB    Pointer to TCB.
+ * @remark      Only known kernels are supported!
+ */
+USHORT  tcbGetTCBFailErr(PTCB pTCB)
+{
+    if (offTCBFailErr == 0 || !initTCB())
+        return 0xffff;
+
+    return *(PUSHORT)(void*)((char*)(void*)pTCB + offTCBFailErr);
+}
+
+
+
+/**
+ * Set the content of the TCB data member TCBFailErr.
+ * Intended used to save and restore the value in ldrOpenPath.
+ * @returns     New Value of TCBFaileErr. (0xffff on error)
+ * @param       pTCB            Pointer to TCB.
+ * @param       TCBFAileErr     New value. (or rather the old one in the save-restore case..)
+ * @remark      Only known kernels are supported!
+ */
+USHORT  tcbSetTCBFailErr(PTCB pTCB, USHORT TCBFailErr)
+{
+    if (offTCBFailErr == 0 || !initTCB())
+        return 0xffff;
+
+    return *(PUSHORT)(void*)((char*)(void*)pTCB + offTCBFailErr) = TCBFailErr;
+}
+
+
Index: trunk/src/win32k/test/dh.asm
===================================================================
--- trunk/src/win32k/test/dh.asm	(revision 3832)
+++ trunk/src/win32k/test/dh.asm	(revision 3832)
@@ -0,0 +1,689 @@
+; $Id: dh.asm,v 1.1 2000-07-16 22:18:13 bird Exp $
+;
+; Device Helper Router.
+; Stack Thunker.
+;
+; Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+;
+; Project Odin Software License can be found in LICENSE.TXT
+;
+    .386
+
+
+;
+; Include files
+;
+    include devsegdf.inc
+    include devhlp.inc
+
+
+;
+; Exported symbols
+;
+    public  ThunkStack16To32
+    public  ThunkStack32To16
+    public  TKSSBase
+    public  getDHRouterFarPtr
+    ;public  DHRouter
+
+
+;
+; extrns
+;
+    extrn DOS32ALLOCMEM:PROC
+    extrn DOS32FREEMEM:PROC
+    extrn DOS16GETINFOSEG:PROC
+    extrn _Device_Help:DWORD
+    extrn pulTKSSBase32:DWORD
+    extrn _TKSSBase16:DWORD
+    extrn _R0FlatCS16:WORD
+    extrn _R0FlatDS16:WORD
+
+
+
+
+CODE16 SEGMENT
+    ASSUME cs:CODE16, ds:FLAT
+
+
+
+;;
+; Devhelp routiner routine.
+; @cproto none
+; @param     dl     Devhelper routine.
+; @uses      none but the ones returned.
+; @sketch
+; @status
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+; @remark
+DHRouter PROC FAR
+    ASSUME cs:CODE16, ds:NOTHING, es:NOTHING, ss:NOTHING
+    ;
+    ; Preserve nearly everything (as a start)
+    ;
+    push    ds
+    push    es
+    push    fs
+    push    gs
+    push    edi
+    push    esi
+    push    ebp
+    push    edx
+    push    ecx
+    push    ebx
+
+    cmp     dl, DevHlp_VirtToLin
+    jne     dhr1
+    call    dh_VirtToLin
+    jmp     dhr_ret
+
+dhr1:
+    cmp     dl, DevHlp_VMAlloc
+    jne     dhr2
+    call    dh_VMAlloc
+    jmp     dhr_ret
+
+dhr2:
+    cmp     dl, DevHlp_VMFree
+    jne     dhr3
+    call    dh_VMFree
+    jmp     dhr_ret
+
+dhr3:
+    cmp     dl, DevHlp_GetDOSVar
+    jne     dhr4
+    call    dh_GetDOSVar
+    add     sp, 4                       ; remove ebx from stack
+    jmp     dhr_ret_ebx
+
+dhr4:
+    cmp     dl, DevHlp_VMLock
+    jne     dhr5
+    call    dh_VMLock
+    jmp     dhr_ret
+
+dhr5:
+    cmp     dl, DevHlp_VMUnlock
+    jne     dhr6
+    call    dh_VMUnlock
+    jmp     dhr_ret
+
+dhr6:
+
+dhr_notimplemented:
+    stc
+    mov     eax, 87 ;ERROR_INVALID_PARAMETER
+
+    ;
+    ; Restore nearly everything (as a start)
+    ;
+dhr_ret:
+    pop     ebx
+dhr_ret_ebx:
+    pop     ecx
+    pop     edx
+    pop     ebp
+    pop     esi
+    pop     edi
+    pop     gs
+    pop     fs
+    pop     es
+    pop     ds
+    ret
+DHRouter ENDP
+
+
+
+
+
+;;
+; Converts a virtual (sel:off) address to a linear address.
+; @cproto    none
+; @param     AX     Selector
+; @param     ESI    Offset
+; @param     DL     DevHelp_VirtToLin
+; @returns   Success:
+;               CF      clear
+;               EAX     Linear address
+;
+;            Failure:
+;               CF      set
+;               EAX     Error code.
+;
+; @uses      eax
+; @status    completely impelemented.
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+dh_VirtToLin PROC NEAR
+    ASSUME cs:CODE16, ds:NOTHING, es:NOTHING, ss:NOTHING
+    shl     eax, SEL_FLAT_SHIFT
+    and     eax, SEL_FLATMASK
+    add     eax, esi
+vtl_retok:
+    clc
+    ret
+
+vtl_reterr:
+    stc
+    ret
+dh_VirtToLin ENDP
+
+
+
+
+;;
+; Allocates virtual memory.
+; @cproto    none
+; @param     ECX    Amount of memory to allocate.
+; @param     EDI    Pointer to DD var containing physical address to be mapped.
+;                   -1 if not used.
+; @param     EAX    Flags. These flags are supported:
+;                       VMDHA_SWAP
+;                       VMDHA_USEHIGHMEM
+;                       VMDHA_RESERVE
+; @param     DH     DevHlp_VMAlloc
+;
+; @returns   Success:
+;               CF      Clear
+;               EAX     Linear address of object.
+;
+;            Failure:
+;               CF      Set.
+;               EAX     Error code. ERROR_INVALID_PARAMETER.
+;
+; @uses      edx, ecx, eax
+; @equiv
+; @time
+; @sketch    For it into an call to DosAllocMem
+; @status
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+; @remark
+dh_VMAlloc PROC NEAR
+    ASSUME cs:CODE16, ds:NOTHING, es:NOTHING, ss:NOTHING
+
+; define the flags which are used here
+VMDHA_SWAP          EQU 0004h
+VMDHA_RESERVE       EQU 0100h
+VMDHA_USEHIGHMEM    EQU 0800h
+
+    ;
+    ; Check input parametes.
+    ;
+    mov     edx, eax
+    and     edx, NOT (VMDHA_SWAP OR VMDHA_USEHIGHMEM OR VMDHA_RESERVE)
+    jnz     vma_reterr                  ; Jump if unsupported flag(s) are set.
+    cmp     edi, 0ffffffffh             ; Check that EDI is -1.
+    jne     vma_reterr                  ; Jump if EDI != -1
+
+    jmp     far ptr FLAT:Thunk32_dh_VMAlloc
+Thunk16_dh_VMAlloc::
+    or      eax, eax                    ; Successful return from Dos32AllocMem?
+    jnz     vma_reterr                  ; Jump on failure.
+    mov     eax, edx                    ; EAX is now 32-bit pointer to the allocated memory.
+
+vma_retok:
+    clc
+    ret
+
+vma_reterr:
+    mov     eax, 87                     ; ERROR_INVALID_PARAMETER
+    stc
+    ret
+dh_VMAlloc ENDP
+CODE16 ENDS
+
+
+CODE32 SEGMENT
+Thunk32_dh_VMAlloc::
+    ASSUME cs:CODE32, ds:NOTHING, es:NOTHING, ss:NOTHING
+    ;
+    ; Call Dos32AllocMem to allocate the requested memory.
+    ;
+    push    eax                         ; Make space for return pointer.
+    mov     edx, esp                    ; Take address of return pointer.
+    test    edx, 0ffff0000h
+    jnz     vma_stack32                 ; Jump if stack is 32-bit
+    xor     edx, edx
+    mov     dx, ss                      ; Make 32-bit pointer to return pointer.
+    shl     edx, SEL_FLAT_SHIFT
+    and     edx, SEL_FLATMASK
+    mov     dx,  sp                     ; EDX is now 32-bit pointer to return pointer.
+vma_stack32:
+
+    test    eax, VMDHA_RESERVE
+    jz      vma1
+    push    0043h                       ; Flags: OBJ_TILE | PAG_READ | PAG_WRITE
+    jmp     vma2
+vma1:
+    push    0053h                       ; Flags: OBJ_TILE | PAG_COMMIT | PAG_READ | PAG_WRITE
+vma2:
+    push    ecx                         ; Number of bytes to allocate.
+    push    edx                         ; Pointer to return pointer.
+    call    DOS32ALLOCMEM
+    add     esp, 12
+    pop     edx                         ; Pointer to allocated memory if any...
+
+    jmp     far ptr CODE16:Thunk16_dh_VMAlloc
+CODE32 ENDS
+
+
+CODE16 SEGMENT
+;;
+; Frees memory allocated with VMAlloc.
+; @cproto    none
+; @param     EAX        Linear address of the memory to be freed.
+; @returns   Success:
+;               CF      Clear
+;
+;            Failure:
+;               CF      Set
+;               EAX     Errorcode
+;                       ERROR_ACCESS_DENIED
+;                       ERROR_INVALID_PARAMETER
+;
+; @uses      eax, ecx, edx
+; @status    completely implemented.
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+dh_VMFree PROC NEAR
+    ASSUME cs:CODE16, ds:NOTHING, es:NOTHING, ss:NOTHING
+    jmp     far ptr FLAT:Thunk32_dh_VMFree
+Thunk16_dh_VMFree::
+    or      eax, eax
+    jnz     vmf_reterr
+
+vmf_retok:
+    clc
+    ret
+
+vmf_reterr:
+    stc
+    ret
+dh_VMFree ENDP
+CODE16 ENDS
+
+
+CODE32 SEGMENT
+; 32-bit part of the dh_VMFree worker
+Thunk32_dh_VMFree::
+    ASSUME cs:CODE32, ds:NOTHING, es:NOTHING, ss:NOTHING
+    push    eax
+    call    DOS32FREEMEM
+    sub     esp, 4
+    jmp     far ptr CODE16:Thunk16_dh_VMFree
+CODE32 ENDS
+
+
+CODE16 SEGMENT
+;;
+; Get addresses of kernel variables.
+; @cproto    none.
+; @param     AL     Index.
+;                   These indexes are supported:
+;                       DHGETDOSV_SYSINFOSEG     1
+;                       DHGETDOSV_LOCINFOSEG     2
+;                       DHGETDOSV_YIELDFLAG      7
+;                       DHGETDOSV_TCYIELDFLAG    8
+;                       DHGETDOSV_DOSTABLE       9
+;
+;
+; @param     CX     VarMember (only index 14 and 16)
+; @param     DL     DevHlp_GetDOSVar
+; @returns   Success:
+;               CF      Clear
+;               AX:BX   Points to the index.
+;
+;            Failure:
+;               CF      Set.
+;
+; @uses     eax, ebx, ecx, edx
+; @sketch
+; @status
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+; @remark
+dh_GetDOSVar PROC NEAR
+    ASSUME cs:CODE16, ds:NOTHING, es:NOTHING, ss:NOTHING
+    cmp     al, 1
+    je      gdv_12
+    cmp     al, 2
+    je      gdv_12
+    cmp     al, 7
+    je      gdv_8
+    cmp     al, 8
+    je      gdv_8
+    cmp     al, 9
+    je      gdv_9
+    jmp     gdv_reterr
+
+gdv_12:
+    push    ax
+    push    ax                          ; make space for selGIS
+    mov     ax, sp                      ; offset selGIS
+    push    ax                          ; make space for selLIS
+    mov     bx, sp                      ; offset selLIS
+    push    ss
+    push    ax                          ; &selGIS
+    push    ss
+    push    bx                          ; &selLIS
+    call    far ptr DOS16GETINFOSEG
+    pop     bx                          ; selLIS
+    pop     cx                          ; selGIS
+    pop     dx                          ; index parameter
+    or      ax, ax                      ; Did it fail?
+    jnz     gdv_reterr                  ; Jump if it failed.
+    cmp     dx, 1
+    je      gdv_12_1
+    mov     bx, cx                      ; bx <- selGIS
+gdv_12_1:
+    xor     ax, ax
+    jmp     gdv_retok
+
+gdv_7:
+    mov     ebx, offset YieldFlag
+    mov     ax, seg YieldFlag
+    jmp     gdv_retok
+
+gdv_8:
+    mov     ebx, offset TCYieldFlag
+    mov     ax, seg TCYieldFlag
+    jmp     gdv_retok
+
+gdv_9:
+    mov     ebx, offset DosTable
+    mov     ax, seg DosTable
+    jmp     gdv_retok
+
+gdv_retok:
+    clc
+    ret
+
+gdv_reterr:
+    stc
+    ret
+dh_GetDOSVar ENDP
+CODE16 ENDS
+
+
+DATA16 SEGMENT
+;; GetDosVar data
+;
+; The two YieldFlags
+;
+YieldFlag                       db 0
+TCYieldFlag                     db 0
+DATA16 ENDS
+
+
+DATA32 SEGMENT
+;
+; 32-bit flat stack base.
+;
+TKSSBase                        dd 0
+DATA32 ENDS
+
+DATA16 SEGMENT
+    ASSUME ds:NOTHING, es:NOTHING, ss:NOTHING
+;
+; The two dostables.
+;
+DosTable                        db 17
+  DosTable_fph_HardError        dd 0
+  DosTable_fph_UCase            dd 0
+  DosTable_UnknownOrReserved1   dd 0
+  DosTable_UnknownOrReserved2   dd 0
+  DosTable_UnknownOrReserved3   dd 0
+  DosTable_fph_MemMapAlias      dd 0
+  DosTable_fph_MemUnmapAlias    dd 0
+  DosTable_fph_GoProtAll        dd 0
+  DosTable_fph_GoRealAll        dd 0
+  DosTable_fph_doshlp_RedirDev  dd 0
+  DosTable_UnknownOrReserved4   dd 0
+  DosTable_UnknownOrReserved5   dd 0
+  DosTable_fph_SFFromSFN        dd 0
+  DosTable_fph_SegGetInfo       dd 0
+  DosTable_fph_AsgCheckDrive    dd 0
+  DosTable_UnknownOrReserved6   dd 0
+  DosTable_UnknownOrReserved7   dd 0
+
+DosTabel2                       db  19
+  DosTable2_fpErrMap24          dd 0
+  DosTable2_fpErrMap24End       dd 0
+  DosTable2_fpErr_Table_24      dd 0
+  DosTable2_fpCDSAddr           dd 0
+  DosTable2_fpGDT_RDR1          dd 0
+  DosTable2_fpInterrupLevel     dd 0
+  DosTable2_fp_cInDos           dd 0
+  DosTable2_UnknownOrReserved1  dd 0
+  DosTable2_UnknownOrReserved2  dd 0
+  DosTable2_R0FlatCS            dw seg FLAT:CODE32
+                                dw 0
+  DosTable2_R0FlatDS            dw seg FLAT:DATA32
+                                dw 0
+  DosTable2_pTKSSBase           dd offset FLAT:DATA32:TKSSBase
+  DosTable2_pintSwitchStack     dd 0
+  DosTable2_pprivatStack        dd 0
+  DosTable2_fpPhysDiskTablePtr  dd 0
+  DosTable2_pforceEMHandler     dd 0
+  DosTable2_pReserveVM          dd 0
+  DosTable2_p_pgpPageDir        dd 0
+  DosTable2_UnknownOrReserved3  dd 0
+DATA16 ENDS
+
+
+CODE16 SEGMENT
+
+
+;;
+; VMLock stub.
+; @returns  NO_ERROR. (0)
+; @param    ignored.
+; @uses     eax
+; @status   stub.
+; @author   knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+dh_VMLock PROC NEAR
+    xor     eax, eax
+    clc
+    ret
+dh_VMLock ENDP
+
+
+
+;;
+; VMUnlock stub.
+; @returns  NO_ERROR. (0)
+; @param    ignored.
+; @uses     eax
+; @status   stub.
+; @author   knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+dh_VMUnlock PROC NEAR
+    xor     eax, eax
+    clc
+    ret
+dh_VMUnlock ENDP
+
+
+CODE16 ENDS
+
+
+
+
+CODE32 SEGMENT
+;;
+; Initiates the Device_Help function pointer.
+;
+; During startup the C library startup routines needs to use the heap.
+; So the heap has to work before main is able to initiate it. The heap
+; uses device helpers so they have to be initiated too. So, this init
+; routine is called during heap init, _rmem_init.
+;
+; @cproto    void _Optlink dhinit(void)
+; @returns   NO_ERROR.
+; @param     none.
+; @uses      eax
+; @sketch
+; @status    completly implemented
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+; @remark
+dhinit PROC NEAR
+    ASSUME cs:CODE32, ds:FLAT, es:NOTHING, ss:NOTHING
+    ;
+    ; _Device_Help - d16globl.c
+    ;
+if 0 ;done during device init.
+    mov     ax, seg DHRouter
+    shl     eax, 16
+    mov     ax, offset DHRouter
+    mov     _Device_Help, eax
+endif
+
+    ;
+    ; pulTKSSBase32
+    ; DosTable2_pTKSSBase
+    ; DosTable2_R0FlatCS
+    ; DosTable2_R0FlatDS
+    ;
+    mov     eax, offset FLAT:TKSSBase
+    mov     pulTKSSBase32, eax          ; We need it as our testing subsystem uses it too.
+if 0 ; not neede any longer
+    ;mov     DosTable2_pTKSSBase, eax
+    ;mov     _TKSSBase16, eax
+
+    ;xor     eax, eax
+    ;mov     ax, seg FLAT:CODE32
+    ;mov     DosTable2_R0FlatCS, ax
+    ;mov     _R0FlatCS16, ax
+
+    ;mov     ax, seg FLAT:DATA32
+    ;mov     DosTable2_R0FlatDS, ax
+    ;mov     _R0FlatDS16, ax
+endif
+
+    ;
+    ; return NO_ERROR
+    ;
+    xor     eax, eax
+    ret
+dhinit ENDP
+
+
+;;
+; Gets the a 16-bit far pointer to the DHRouter routine.
+; @cproto    ULONG  _Optlink getDHRouterFarPtr(VOID); /* dh.asm */
+; @returns   16-bit far pointer to the DHRouter routine.
+; @uses      EAX
+; @status    completely implemented.
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+; @remark
+getDHRouterFarPtr PROC NEAR
+    ASSUME cs:CODE32, ds:FLAT, es:NOTHING, ss:NOTHING
+    mov     ax, seg CODE16:DHRouter
+    shl     eax, 16
+    mov     ax, offset CODE16:DHRouter
+    ret
+getDHRouterFarPtr ENDP
+
+
+
+
+
+;;
+; Thunks the stack from 16-bits to 32-bits.
+; !The stack has to be 16-bits on entry!
+; @cproto    VOID _Optlink ThunkStack16To32(VOID)
+; @returns   void
+;            Stack is 32-bits!
+;            EBP and SS:ESP is thunked
+;
+; @uses      EAX, EDX
+; @sketch
+; @status    completly implemented.
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+; @remark    RING 3 only.
+ThunkStack16To32 PROC NEAR
+    ASSUME cs:CODE32, ds:FLAT, es:NOTHING, ss:NOTHING
+    movzx   esp, sp                     ; Make sure high end of esp is zero.
+    mov     ax, ss                      ; Find the linary base of the segment addressed by ss.
+    shl     eax, SEL_FLAT_SHIFT
+    and     eax, SEL_FLATMASK
+    mov     ax, sp                      ; Add the segment offset, which is sp.
+                                        ; eax is now the linear stack address equal to ss:sp.
+
+    mov     dx, seg FLAT:DATA32         ; ALP bug? Can't: push seg FLAT:DATA32
+                                        ; Have to move it to dx before pushing it.
+    push    dx                          ; Make lss quad word: new ss, new esp
+    push    eax
+    lss     esp, ss:[esp]               ; load new ss and esp values.
+
+    ;
+    ; Fix ebp
+    ; Creates new ebp from high word of esp and low word of ebp.
+    ;
+    mov     eax, esp
+    mov     ax, bp
+    mov     ebp, eax
+
+    ;
+    ; Update TKSSBase
+    ;
+    push    ds
+    mov     ds, dx
+    ASSUME  ds:FLAT
+    mov     TKSSBase, 0
+    pop     ds
+    ret
+ThunkStack16To32 ENDP
+
+
+;;
+; Thunks the stack from 32-bits to 16-bits.
+; !The stack has to be 32-bits on entry!
+; @cproto    VOID _Optlink ThunkStack32To16(VOID)
+; @returns   void
+;            Stack is 16-bits!
+;            EBP and SS:ESP is thunked
+;
+; @uses      EAX, EDX
+; @sketch
+; @status    completly implemented.
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+; @remark    RING 3 only.
+ThunkStack32To16 PROC NEAR
+    ASSUME cs:CODE32, ds:FLAT, es:NOTHING, ss:NOTHING
+
+    mov     edx, esp                    ; save esp for later use (setting TKSSBase).
+
+    ;
+    ; calc LDT selector from linear esp and load new ss:esp.
+    ;
+    mov     eax, esp
+    shr     eax, SEL_FLAT_SHIFT
+    or      ax,  SEL_LDT_RPL3           ; ax new ss LDT (RING3).
+    rol     eax, 16
+    mov     ax, sp
+    push    eax
+    lss     sp, dword ptr [esp]         ; load ss:sp.
+    movzx   esp, sp                     ; Zero upper part of esp.
+                                        ; Stack is now 16 bits
+    ;
+    ; Fix ebp
+    ;
+    movzx   ebp, bp                     ; Zero upper part of ebp.
+
+    ;
+    ; Update TKSSBase
+    ;
+    push    ds
+    mov     ax, seg FLAT:DATA32
+    mov     ds, ax
+    ASSUME  ds:FLAT
+    xor     dx, dx                      ; zero lower word of dx to get linear
+                                        ; address of 16-bits stack base
+    mov     TKSSBase, edx
+    pop     ds
+
+    ret
+ThunkStack32To16 ENDP
+
+
+CODE32 ENDS
+
+end
+
Index: trunk/src/win32k/test/dos.c
===================================================================
--- trunk/src/win32k/test/dos.c	(revision 3832)
+++ trunk/src/win32k/test/dos.c	(revision 3832)
@@ -0,0 +1,52 @@
+/* $Id: dos.c,v 1.1 2000-07-16 22:18:14 bird Exp $
+ *
+ * Thunkers for OS/2 APIs.
+ *
+ * Some APIs requires Linear Stack, some have to overridden to
+ * emulate different things.
+ *
+ * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#define INCL_BASE
+#define INCL_NO_FAKE
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <os2.h>
+
+#include "test.h"
+
+
+/*******************************************************************************
+*   External Functions                                                         *
+* (These are prototypes for functions in the IMPORTS section of the def-file.) *
+*******************************************************************************/
+APIRET  APIENTRY        _DosWrite(HFILE hFile, PVOID pBuffer, ULONG cbWrite, PULONG pcbActual);
+
+
+/**
+ * DosWrite overload. Ensures that the stack is 32-bit!
+ */
+APIRET  APIENTRY        DosWrite(HFILE hFile, PVOID pBuffer, ULONG cbWrite, PULONG pcbActual)
+{
+    BOOL    f32Stack = ((int)&hFile > 0x10000);
+    APIRET  rc;
+    if (!f32Stack)
+        ThunkStack16To32();
+
+    rc = _DosWrite(hFile, pBuffer, cbWrite, pcbActual);
+
+    if (!f32Stack)
+        ThunkStack32To16();
+
+    return rc;
+}
+
Index: trunk/src/win32k/test/dosa.asm
===================================================================
--- trunk/src/win32k/test/dosa.asm	(revision 3832)
+++ trunk/src/win32k/test/dosa.asm	(revision 3832)
@@ -0,0 +1,290 @@
+; $Id: dosa.asm,v 1.1 2000-07-16 22:18:14 bird Exp $
+;
+; 16-bits Dos calls overloader
+;
+; Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+;
+; Project Odin Software License can be found in LICENSE.TXT
+;
+    .386
+
+
+;
+; Include files
+;
+    include devsegdf.inc
+    include os2.inc
+    include devsym.inc
+
+
+;
+; Exported symbols
+;
+    public  DOS16OPEN
+    public  DOS16CLOSE
+    public  DOS16DEVIOCTL
+
+
+;
+; extrns
+;
+    extrn   _strategyAsm0:FAR
+    extrn   _DOS16OPEN:FAR     ;70
+    extrn   _DOS16CLOSE:FAR    ;59
+
+    extrn   ThunkStack16To32:PROC
+    extrn   ThunkStack32To16:PROC
+    extrn   TKSSBase:PROC
+
+    extrn   _TKSSBase16:DWORD
+    extrn   _R0FlatCS16:WORD
+    extrn   _R0FlatDS16:WORD
+
+DATA16 SEGMENT
+DATA16 ENDS
+
+
+
+CODE16 SEGMENT
+    ASSUME cs:CODE16, ds:DATA16
+
+hElf    EQU      0fE1Fh                  ; Value of the elf handle
+
+;;
+; Fake opening of $elf.
+;
+; PASCAL convention: Parameters pushed left to right of C prototype.
+;                    We'll have to do the cleanup.
+;
+; @cproto APIRET  APIENTRY  DosOpen(
+;                               PSZ     pszFname,
+;                               PHFILE  phfOpen,
+;                               PUSHORT pusAction,
+;                               ULONG   ulFSize,
+;                               USHORT  usAttr,
+;                               USHORT  fsOpenFlags,
+;                               USHORT  fsOpenMode,
+;                               ULONG   ulReserved);
+;
+; @returns
+; @param     pszFname       bp +1c  dd
+; @param     phfOpen        bp +18  dd
+; @param     pusAction      bp +14  dd
+; @param     ulFSize        bp +10  dd
+; @param     usAttr         bp + e  dw
+; @param     fsOpenFlags    bp + c  dw
+; @param     fsOpenMode     bp + a  dw
+; @param     ulReserved     bp + 6  dd
+;
+; @uses
+; @equiv
+; @time
+; @sketch
+; @status
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+; @remark
+DOS16OPEN PROC FAR
+    ASSUME CS:CODE16, DS:NOTHING, ES:NOTHING, SS:NOTHING
+    push    bp
+    mov     bp, sp
+
+    ;
+    ; Is this an attempt to open the ELF device driver?
+    ;
+    push    ds
+    push    bx
+    xor     ebx, ebx
+    lds     bx, [bp + 1ch]
+    mov     eax, ds:[ebx]
+    cmp     eax, 'ved\'                 ;'\dev' assumes low-case!
+    jne     do_notelf
+    mov     eax, ds:[ebx+4]
+    cmp     eax, 'fle\'                 ;'\elf'
+    jne     do_notelf
+    mov     eax, ds:[ebx+8]
+    cmp     ax, '$'                     ; '$'\0
+    jnz     do_notelf
+
+    ;
+    ; found filename string equal to "\dev\$elf".
+    ;
+    ; return phFile equal to Elf handle and pusAction set to 1 (FILE EXISTED).
+    ;
+    lds     bx, [bp + 18h]
+    mov     word ptr ds:[bx], hElf      ; *phFile <- hElf
+    lds     bx, [bp + 14h]
+    mov     word ptr ds:[bx], 1         ; *pusAction <- File existed.
+
+do_ret:
+    ;
+    ; restore bx and ds and return successfully.
+    ;
+    pop     bx
+    pop     ds
+    xor     eax, eax
+    leave
+    ret     01ah
+
+do_notelf:
+    push    dword ptr [bp +01ch]
+    push    dword ptr [bp +018h]
+    push    dword ptr [bp +014h]
+    push    dword ptr [bp +010h]
+    push    word  ptr [bp + 0eh]
+    push    word  ptr [bp + 0ch]
+    push    word  ptr [bp + 0ah]
+    push    dword ptr [bp + 06h]
+    call far ptr _DOS16OPEN
+    pop     bx
+    pop     ds
+    leave
+    ret     01ah
+DOS16OPEN ENDP
+
+
+;;
+; Fake close of $elf
+; @cproto    APIRET  APIENTRY DosClose(HFILE hf);
+; @returns   OS/2 return code. (NO_ERROR)
+; @param     hFile  bp + 6
+; @uses      EAX
+; @status    completly implemented.
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+DOS16CLOSE PROC FAR
+    ASSUME CS:CODE16, DS:NOTHING, ES:NOTHING, SS:NOTHING
+    push    bp
+    mov     bp, sp
+
+    ;
+    ; Is it the elf handle?
+    ;
+    mov     ax, [bp + 6]
+    cmp     ax, hElf
+    jne     dc_notelf
+    xor     eax, eax
+    leave
+    ret     2
+
+dc_notelf:
+    push    word ptr [bp + 6]           ; can't jump to higher privilege
+    call    _DOS16CLOSE
+    leave
+    ret     2
+DOS16CLOSE ENDP
+
+
+
+;;
+;
+; @cproto    APIRET  APIENTRY   DosDevIOCtl(
+;                                   PVOID   pData,
+;                                   PVOID   pParms,
+;                                   USHORT  usFun,
+;                                   USHORT  usCategory,
+;                                   HFILE   hDev);
+; @returns
+; @param     pData       bp +10 dd
+; @param     pParms      bp + c dd
+; @param     usFun       bp + a dw
+; @param     usCategory  bp + 8 dw
+; @param     hDev        bp + 6 dw
+; @param
+; @uses      eax
+; @sketch
+; @status    completly implemented
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+; @remark
+DOS16DEVIOCTL PROC FAR
+    ASSUME CS:CODE16, DS:NOTHING, ES:NOTHING, SS:NOTHING
+    LOCAL   pkt:Packet
+
+    push    bx
+    push    es
+
+
+    ;
+    ; Check that it really is the elf handle.
+    ;
+    mov     ax, word ptr [bp + 6]
+    cmp     word ptr [bp + 6], hElf
+    jne     ddioc_invalidhandle
+
+    ;
+    ; Then we'll have to call _strategyAsm0. But first will have to
+    ; build a request packet for this IOCtl
+    ;
+    mov     pkt.PktLen, LENGenIOCTL     ; PktLen          db      ?               ; length in bytes of packet
+    mov     pkt.PktUnit, 0              ; PktUnit         db      ?               ; subunit number of block device
+    mov     pkt.PktCmd, CMDGenIOCTL     ; PktCmd          db      ?               ; command code
+    mov     pkt.PktStatus, 0            ; PktStatus       dw      ?               ; status word
+    mov     pkt.PktFlag, 0              ; PktFlag         db      ?               ; disk driver internal flags
+    mov     pkt.PktFlag+1, 0            ;                 db      3 dup(?)        ; reserved
+    mov     pkt.PktFlag+2, 0            ;
+    mov     pkt.PktFlag+3, 0            ;
+    mov     pkt.PktDevLink, 0           ; PktDevLink      dd      ?               ; device multiple-request link
+    mov     ax, [bp + 8]
+    mov     byte  ptr pkt.PktData + 0, al   ; Category Code
+    mov     ax, [bp + 0ah]
+    mov     byte ptr pkt.PktData + 1, al    ; Function code
+    mov     eax, [bp + 0ch]
+    mov     dword ptr pkt.PktData + 2, eax  ; pointer to parameter packet
+    mov     eax, [bp + 10h]
+    mov     dword ptr pkt.PktData + 6, eax  ; pointer to data packet
+    mov     word ptr  pkt.PktData + 10, 0   ; SFN of the driver.
+
+    ; do the call - who cleans up the stack?
+    mov     bx, ss
+    mov     es, bx
+    lea     bx, pkt
+    ;call    far ptr _strategyAsm0      ; why did this make it into a 16:32 call?
+    call    far ptr CODE16:_strategyAsm0
+
+    ;
+    ; We'll check if the status to see wether it failed or not.
+    ;
+    test    pkt.PktStatus, STERR
+    jnz     ddioc_error
+    test    pkt.PktStatus, STDON
+    jz      ddioc_notdone
+    test    pkt.PktStatus, STINTER
+    jnz     ddioc_interchar
+    test    pkt.PktStatus, STBUI
+    jnz     ddioc_busy
+    xor     eax, eax                    ; return NO_ERROR
+    jmp ddioc_ret
+
+ddioc_error:
+    mov     ax, pkt.PktStatus
+    and     ax, STECODE
+    jmp ddioc_ret
+
+ddioc_notdone:
+    mov     eax, 31                     ; ERROR_GEN_FAILURE
+    jmp ddioc_ret
+
+ddioc_interchar:
+    mov     eax, 31                     ; ERROR_GEN_FAILURE
+    jmp ddioc_ret
+
+ddioc_busy:
+    mov     eax, 31                     ; ERROR_GEN_FAILURE
+    jmp ddioc_ret
+
+ddioc_invalidhandle:
+    mov     eax, 6                      ; ERROR_INVALID_HANDLE
+    jmp     ddioc_ret
+
+ddioc_ret:
+    pop     es
+    pop     bx
+    leave
+    ret     0eh
+DOS16DEVIOCTL ENDP
+
+
+
+CODE16 ENDS
+
+END
+
+
Index: trunk/src/win32k/test/fake.c
===================================================================
--- trunk/src/win32k/test/fake.c	(revision 3832)
+++ trunk/src/win32k/test/fake.c	(revision 3832)
@@ -0,0 +1,1564 @@
+/* $Id: fake.c,v 1.1 2000-07-16 22:18:14 bird Exp $
+ *
+ * Fake stubs for the ldr and kernel functions we imports or overloads.
+ *
+ * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#define INCL_BASE
+#define FOR_EXEHDR 1                    /* To make all object flags OBJ???. */
+#define INCL_OS2KRNL_ALL
+#define DWORD  ULONG
+#define WORD   USHORT
+
+#define DUMMY()     int dummy; dummy = 0; dummy = dummy + 1;
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <os2.h>
+#include <newexe.h>                     /* OS/2 NE structs and definitions. */
+#include <exe386.h>                     /* OS/2 LX structs and definitions. */
+
+#include <string.h>
+
+#include "log.h"
+#include "OS2Krnl.h"
+#include "dev32.h"
+#include "ldrcalls.h"
+#include "test.h"
+#include "macros.h"
+
+#include "malloc.h"
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+typedef struct ldrrei_s /* #memb 7 size 20 (0x014) - from 14040W4 kernel.sdf */
+{
+    PVOID                   ei_startaddr;      /* off:   0(00)  size:  4(04) */
+    PVOID                   ei_stackaddr;      /* off:   4(04)  size:  4(04) */
+    PVOID                   ei_pstackmax;      /* off:   8(08)  size:  4(04) */
+    USHORT                  ei_ds;             /* off:  12(0c)  size:  2(02) */
+    USHORT                  ei_stacksize;      /* off:  14(0e)  size:  2(02) */
+    USHORT                  ei_heapsize;       /* off:  16(10)  size:  2(02) */
+    USHORT                  ei_loadtype;       /* off:  18(12)  size:  2(02) */
+} ldrrei_t;
+
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/*
+ * Pointer to the loader semaphore.
+ */
+static LONG     lfakeLDRSem = 0;        /* Used as a counter. */
+HKMTX           fakeLDRSem = (HKMTX)&lfakeLDRSem;
+
+static CHAR     achHeaderBuffer[256];   /* Buffer to read exe header into. */
+PVOID           pheaderbuf = &achHeaderBuffer[0];
+
+/*
+ * table use by fakeldrMTEValidatePtrs.
+ */
+USHORT          validatetbl[] =
+{
+    FIELDOFFSET(SMTE, smte_objmap),
+    FIELDOFFSET(SMTE, smte_rsrctab),
+    FIELDOFFSET(SMTE, smte_restab),
+    FIELDOFFSET(SMTE, smte_enttab),
+    FIELDOFFSET(SMTE, smte_fpagetab),
+    FIELDOFFSET(SMTE, smte_frectab),
+    FIELDOFFSET(SMTE, smte_impmod),
+    FIELDOFFSET(SMTE, smte_impproc),
+    0xDEAD
+};
+
+
+/*******************************************************************************
+*   External Functions                                                         *
+*******************************************************************************/
+#define QHINF_EXEINFO       1 /* NE exeinfo. */
+#define QHINF_READRSRCTBL   2 /* Reads from the resource table. */
+#define QHINF_READFILE      3 /* Reads from the executable file. */
+#define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */
+#define QHINF_LIBPATH       5 /* Gets the entire libpath. */
+#define QHINF_FIXENTRY      6 /* NE only */
+#define QHINF_STE           7 /* NE only */
+#define QHINF_MAPSEL        8 /* NE only */
+
+APIRET APIENTRY DosQueryHeaderInfo(HMODULE hmod,
+                                   ULONG   ulIndex,
+                                   PVOID   pvBuffer,
+                                   ULONG   cbBuffer,
+                                   ULONG   ulSubFunction);
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+ULONG LDRCALL   fakeLDRLoadExe(PSZ pszFilename, ldrrei_t *pEI);
+ULONG LDRCALL   fakeldrGetModule(PSZ pszFilename, ULONG ul);
+ULONG LDRCALL   fakeldrGetMte(PCHAR pachFilename, USHORT cchFilename, UCHAR fchType, UCHAR fchClass, PPMTE ppmte);
+ULONG LDRCALL   fakeldrOpenNewExe(PCHAR pachFilename, USHORT cchFilename, ldrlv_t *plv, PUSHORT pus);
+ULONG LDRCALL   fakeldrCreateMte(struct e32_exe * pe32, ldrlv_t *plv);
+ULONG LDRCALL   fakeldrLoadImports(PMTE pmte);
+VOID  LDRCALL   fakeldrUCaseString(PCHAR pachString, USHORT cchString);
+ULONG LDRCALL   fakeldrMTEValidatePtrs(PSMTE psmte, ULONG ulMaxAddr, ULONG off);
+
+
+/**
+ * Fake ldrClose
+ * @returns OS2 return code.
+ * @param   hFile    Filehandle of the file to be closed.
+ * @status  completely impelemented.
+ * @author  knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ * @remark
+ */
+ULONG LDRCALL fakeldrClose(SFN hFile)
+{
+    APIRET  rc;
+    BOOL    f32Stack = ((int)&hFile > 0x10000);
+
+    if (!f32Stack) ThunkStack16To32();
+
+    rc =  DosClose(hFile);
+
+    if (!f32Stack) ThunkStack32To16();
+
+    printf("fakeldrClose:                   hFile = 0x%04x, rc = %d\n", hFile, rc);
+
+    return rc;
+}
+
+/**
+ * Fake ldrOpen.
+ * @returns   OS2 return code.
+ * @param     phFile        Pointer to return handle.
+ * @param     pszFilename   Pointer to filename.
+ * @param     pfl           Pointer to media flags? *pfl is set to zero!
+ * @sketch    Do a DosOpen on the filename.
+ * @status    partially implemented.
+ * @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ * @remark
+ */
+ULONG LDRCALL fakeldrOpen(PSFN phFile, PSZ pszFilename, PULONG pfl)
+{
+    ULONG   ulAction;
+    HFILE   hFile;
+    APIRET  rc;
+    BOOL    f32Stack = ((int)&hFile > 0x10000);
+
+    if (!f32Stack) ThunkStack16To32();
+
+    hFile = 0;
+    ulAction = 0;
+    rc =  DosOpen(pszFilename, &hFile, &ulAction, 0, FILE_NORMAL,
+                  OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
+                  OPEN_ACCESS_READONLY | OPEN_SHARE_DENYWRITE,
+                  NULL);
+    if (rc == NO_ERROR)
+    {
+        *phFile = (USHORT)hFile;
+        if (pfl != NULL)
+            *pfl = 0;
+    }
+
+    if (!f32Stack) ThunkStack32To16();
+
+    printf("fakeldrOpen:                    phFile = %p; *phFile = 0x%04x, pszFilename = %s, pfl = %p, rc = %d\n",
+           phFile, *phFile, pszFilename, pfl, rc);
+
+    return rc;
+}
+
+
+/**
+ * ldrRead fake.
+ * @returns   OS/2 return code. (NO_ERROR on success...)
+ * @param     hFile     Handle to file.
+ * @param     ulOffset  Offset in the file to start reading at.
+ * @param     pvBuffer  Pointer to output buffer.
+ * @param     fpBuffer  Far pointer to buffer. (ignored)
+ * @param     cbToRead  Count of bytes to read.
+ * @param     pMTE      MTE pointer (used for caching?)
+ *
+ * @sketch    Set Change filepointer to ulOffset.
+ *            Read cbToRead into pvBufer.
+ * @status    completely tested.
+ * @author    knut st. osmundsen
+ * @remark
+ */
+ULONG LDRCALL fakeldrRead(SFN hFile, ULONG ulOffset, PVOID pvBuffer, ULONG fpBuffer, ULONG cbToRead, PMTE pMTE)
+{
+    ULONG   cbRead,
+            ulMoved;
+    APIRET  rc;
+    BOOL    f32Stack = ((int)&hFile > 0x10000);
+
+    if (!f32Stack) ThunkStack16To32();
+
+    rc = DosSetFilePtr(hFile, ulOffset, FILE_BEGIN, &ulMoved);
+    if (rc == NO_ERROR)
+        rc = DosRead(hFile, pvBuffer, cbToRead, &cbRead);
+    else
+        kprintf(("fakeldrRead: DosSetFilePtr(hfile, 0x%08x(%d),..) failed with rc = %d.\n",
+                 ulOffset, ulOffset, rc));
+
+    if (!f32Stack) ThunkStack32To16();
+
+    printf("fakeldrRead:                    hFile = 0x%04x, ulOffset = 0x%08x, pvBuffer = %p, fpBuffer = 0x%08x, cbToRead = 0x%08x, pMte = %p, rc = %d\n",
+           hFile, ulOffset, pvBuffer, fpBuffer, cbToRead, pMTE, rc);
+
+    return rc;
+}
+
+
+/**
+ * LDRQAppType faker.
+ * @returns   OS/2 return code.
+ * @param     pszFilename   Pointer to executable to query app type for.
+ * @param     pul           Pointer to flag variable to return apptype flags in.
+ * @sketch
+ * @status    stub.
+ * @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ * @remark
+ */
+ULONG LDRCALL fakeLDRQAppType(PSZ pszFilename, PULONG pul)
+{
+    DUMMY();
+    printf("fakeLDRQAppType:                pszFilename = %s, pul = %p, rc = 0\n", pszFilename, pul);
+    return NO_ERROR;
+}
+
+
+/**
+ * ldrEnum32bitRelRecs
+ * @param   pMTE           Pointer to MTE for this module.
+ * @param   iObject        Object index. 0-based!
+ * @param   iPageTabl      Page index. 0-based!
+ * @param   pvPage         Pointer to page buffer.
+ * @param   ulPageAddress  Note! Page is not present.
+ * @param   pPTDA
+ * @status  stub
+ */
+ULONG LDRCALL fakeldrEnum32bitRelRecs(
+    PMTE    pMTE,
+    ULONG   iObject,
+    ULONG   iPageTable,
+    PVOID   pvPage,
+    ULONG   ulPageAddress,
+    PVOID   pvPTDA
+    )
+{
+    DUMMY();
+    printf("fakeldrEnum32bitRelRecs:        pMTE = %p, iObject = 0x%08x, iPageTable = 0x%08x, pvPage = 0x%08x, ulPageAddress = 0x%08x, pvPTDA = %p\n",
+           pMTE, iObject, iPageTable, pvPage, ulPageAddress, pvPTDA);
+
+    return NO_ERROR;
+}
+
+/**
+ * Opens a given file.
+ * @returns  NO_ERROR on success. OS/2 error code on error.
+ * @param    pszFilename   Pointer to filename.
+ * @param    flOpenFlags   Open flags. (similar to DosOpen)
+ * @param    fsOpenMode    Open mode flags. (similar to DosOpen)
+ * @param    phFile        Pointer to filehandle.
+ * @param    pulsomething  16-bit near (?) pointer to a variable - unknown. NULL is allowed. EA?
+ */
+APIRET KRNLCALL fakeIOSftOpen(
+    PSZ pszFilename,
+    ULONG flOpenFlags,
+    ULONG fsOpenMode,
+    PSFN phFile,
+    PULONG pulsomething
+    )
+{
+    ULONG   ulAction;
+    HFILE   hFile;
+    APIRET  rc;
+    BOOL    f32Stack = ((int)&hFile > 0x10000);
+
+    if (!f32Stack) ThunkStack16To32();
+
+    hFile = 0;
+    ulAction = 0;
+    rc =  DosOpen(pszFilename, &hFile, &ulAction, 0, FILE_NORMAL,
+                  flOpenFlags,
+                  fsOpenMode,
+                  NULL);
+    if (rc == NO_ERROR)
+        *phFile = (USHORT)hFile;
+
+    if (!f32Stack) ThunkStack32To16();
+
+    printf("fakeIOSftOpen:                  pszFilename = %s, flOpenFlags = 0x%08x, fsOpenMode = 0x%08x, phFile = %p; *phFile = 0x%04, pulsomething = %p, rc = %d\n",
+           pszFilename, flOpenFlags, fsOpenMode, phFile, *phFile, pulsomething, rc);
+
+    return rc;
+}
+
+
+/**
+ * Closes the specified file.
+ * @returns  NO_ERROR on success. OS/2 error code on error.
+ * @param    hFile      File handle - System File Number.
+ */
+APIRET KRNLCALL fakeIOSftClose(
+    SFN hFile
+    )
+{
+    APIRET  rc;
+    BOOL    f32Stack = ((int)&hFile > 0x10000);
+
+    if (!f32Stack) ThunkStack16To32();
+
+    rc =  DosClose(hFile);
+
+    if (!f32Stack) ThunkStack32To16();
+
+    printf("fakeIOSftClose:                 hFile = 0x%04, rc = %d\n",
+           hFile, rc);
+
+    return rc;
+}
+
+
+/**
+ * Probably this function will expand a relative path to a full path.
+ * @returns  NO_ERROR on success. OS/2 error code on error.
+ * @param    pszPath  Pointer to path to expand. Contains the full path upon return. (?)
+ *                    This buffer should probably be of CCHMAXPATH length.
+ * @status   completely implemented.
+ */
+APIRET KRNLCALL fakeIOSftTransPath(
+    PSZ pszPath
+    )
+{
+    char    szBuffer[CCHMAXPATH];
+    APIRET  rc;
+    BOOL    f32Stack = ((int)&pszPath > 0x10000);
+
+    if (!f32Stack) ThunkStack16To32();
+
+    rc = DosQueryPathInfo(pszPath, FIL_QUERYFULLNAME, &szBuffer, sizeof(szBuffer));
+    printf("fakeIOSftTransPath:              pszPath(in) = %s, pszPath(out) = %s, rc = %d\n",
+           pszPath, szBuffer, rc);
+    if (rc == NO_ERROR)
+        strcpy(pszPath, szBuffer);
+    else
+        kprintf(("fakeIOSftTransPath: DosQueryPathInfo failed with rc=%d\n", rc));
+
+
+    if (!f32Stack) ThunkStack32To16();
+
+    return rc;
+}
+
+
+/**
+ * Read at a given offset in the a file.
+ * @returns  NO_ERROR on success. OS/2 error code on error.
+ * @param    hFile      File handle - System File Number.
+ * @param    pcbActual  Pointer to variable which upon input holds the number
+ *                      of bytes to read, on output the actual number of bytes read.
+ * @param    pvBuffer   Pointer to the read buffer.
+ * @param    fpBuffer   16 far pointer to buffer. (ignored)
+ * @param    ulOffset   File offset to read from. (0=start of file)
+ */
+APIRET KRNLCALL fakeIOSftReadAt(
+    SFN hFile,
+    PULONG pcbActual,
+    PVOID pvBuffer,
+    ULONG fpBuffer,
+    ULONG ulOffset
+    )
+{
+    ULONG   ulMoved;
+    APIRET  rc;
+    BOOL    f32Stack = ((int)&hFile > 0x10000);
+
+    if (!f32Stack) ThunkStack16To32();
+
+    rc = DosSetFilePtr(hFile, ulOffset, FILE_BEGIN, &ulMoved);
+    if (rc == NO_ERROR)
+        rc = DosRead(hFile, pvBuffer, *pcbActual, pcbActual);
+    else
+        kprintf(("fakeIOSftReadAt: DosSetFilePtr(hfile, 0x%08x(%d),..) failed with rc = %d.",
+                 ulOffset, ulOffset, rc));
+
+    if (!f32Stack) ThunkStack32To16();
+
+    printf("fakeIOSftReadAt:                hFile = 0x%04, pcbActual = %p; *pcbActual = 0x%08x, pvBuffer = %p, fpBuffer = %x, ulOffset = 0x%08x, rc = %d\n",
+           hFile, pcbActual, pvBuffer, fpBuffer, ulOffset, rc);
+
+    return rc;
+}
+
+
+/**
+ * Write at a given offset in the a file.
+ * @returns  NO_ERROR on success. OS/2 error code on error.
+ * @param    hFile      File handle - System File Number.
+ * @param    pcbActual  Pointer to variable which upon input holds the number
+ *                      of bytes to write, on output the actual number of bytes write.
+ * @param    pvBuffer   Pointer to the write buffer.
+ * @param    fpBuffer   16 far pointer to buffer. (ignored)
+ * @param    ulOffset   File offset to write from. (0=start of file)
+ */
+APIRET KRNLCALL fakeIOSftWriteAt(
+    SFN hFile,
+    PULONG pcbActual,
+    PVOID pvBuffer,
+    ULONG fpBuffer,
+    ULONG ulOffset
+    )
+{
+    ULONG   ulMoved;
+    APIRET  rc;
+    BOOL    f32Stack = ((int)&hFile > 0x10000);
+
+    if (!f32Stack) ThunkStack16To32();
+
+    rc = DosSetFilePtr(hFile, ulOffset, FILE_BEGIN, &ulMoved);
+    if (rc == NO_ERROR)
+        rc = DosWrite(hFile, pvBuffer, *pcbActual, pcbActual);
+    else
+        kprintf(("fakeIOSftWriteAt: DosSetFilePtr(hfile, 0x%08x(%d),..) failed with rc = %d.",
+                 ulOffset, ulOffset, rc));
+
+    if (!f32Stack) ThunkStack32To16();
+
+    printf("fakeIOSftWriteAt:               hFile = 0x%04, pcbActual = %p; *pcbActual = 0x%08x, pvBuffer = %p, fpBuffer = %x, ulOffset = 0x%08x, rc = %d\n",
+           hFile, pcbActual, pvBuffer, fpBuffer, ulOffset, rc);
+
+    return rc;
+}
+
+
+/**
+ * Gets the filesize.
+ * @returns   NO_ERROR on success; OS/2 error code on error.
+ * @param     hFile    File handle - System File Number.
+ * @param     pcbFile  Pointer to ULONG which will hold the file size upon return.
+ */
+APIRET KRNLCALL fakeSftFileSize(
+    SFN hFile,
+    PULONG pcbFile
+    )
+{
+    FILESTATUS3     fsts3;
+    APIRET          rc;
+    BOOL            f32Stack = ((int)&hFile > 0x10000);
+
+    if (!f32Stack) ThunkStack16To32();
+
+    rc = DosQueryFileInfo(hFile,
+                          FIL_STANDARD,
+                          &fsts3,
+                          sizeof(fsts3));
+    if (rc == NO_ERROR)
+        *pcbFile = fsts3.cbFile;
+    else
+        kprintf(("fakeSftFileSize: DosQueryFileInfo failed with rc=%d\n", rc));
+
+    if (!f32Stack) ThunkStack32To16();
+
+    printf("fakeSftFileSize:                hFile = 0x%04x, pcbFile = %p; *pcbFile = 0x%08x, rc = %d\n",
+           hFile, pcbFile, *pcbFile, rc);
+
+    return rc;
+}
+
+
+/**
+ * @status    stub
+ */
+HMTE KRNLCALL fakeVMGetOwner(
+    ULONG ulCS,
+    ULONG ulEIP)
+{
+    DUMMY();
+
+    printf("fakeVMGetOwner:                 ulCS = 0x%04x, ulEiP = 0x%08x, rc = %d\n",
+           ulCS, ulEIP, 0);
+
+    return 0;
+}
+
+
+/**
+ * @status    stub
+ */
+APIRET KRNLCALL fakeVMAllocMem(
+    ULONG   cbSize,
+    ULONG   cbCommit,
+    ULONG   flFlags1,
+    HPTDA   hPTDA,
+    USHORT  usVMOwnerId,
+    HMTE    hMTE,
+    ULONG   flFlags2,
+    ULONG   SomeArg2,
+    PVMAC   pvmac)
+{
+    DUMMY();
+    printf("fakeVMAllocMem:                 cbSize = 0x%08x, cbCommit = 0x%08x, flFlags1 = 0x%08x, hPTDA = 0x%04x, usVMOwnerId = 0x%04x, hMTE = 0x%04x, flFlags2 = 0x%08x, SomeArg2 = 0x%08x, pvmac = %p, rc = %d\n",
+           cbSize, cbCommit, flFlags1, hPTDA, usVMOwnerId, hMTE, flFlags2, SomeArg2, pvmac, 0);
+
+    return ERROR_NOT_SUPPORTED;
+}
+
+
+/**
+ * @status    stub
+ * @remark    Used by environment stuff...
+ */
+APIRET KRNLCALL fakeVMObjHandleInfo(
+    USHORT  usHob,
+    PULONG  pulAddr,
+    PUSHORT pushPTDA)
+{
+    APIRET          rc = NO_ERROR;
+    BOOL            f32Stack = ((int)&usHob > 0x10000);
+
+    if (!f32Stack) ThunkStack16To32();
+
+    if (pulAddr > (PULONG)0x10000 && pushPTDA > (PUSHORT)0x10000)
+    {
+        PTIB pTib;
+        PPIB pPib;
+        DosGetInfoBlocks(&pTib, &pPib);
+        switch (usHob)
+        {
+            case 1: *pulAddr = (ULONG)pPib->pib_pchenv; break; //PTDA environ (fakea.asm)
+            default:
+                printf("fakeVMObjHandleInfo:            Invalid handle! (usHob=0x%#4x)\n", usHob);
+                rc = ERROR_INVALID_HANDLE;
+        }
+        *pushPTDA = 10; //dummy
+    }
+    else
+        rc = ERROR_INVALID_PARAMETER;
+
+    if (!f32Stack) ThunkStack32To16();
+
+    printf("fakeVMObjHandleInfo:            usHob = 0x%04x, pulAddr = %p, pushPTDA = %p, rc = %d\n",
+           usHob, pulAddr, pushPTDA, rc);
+    return rc;
+}
+
+
+/**
+ * myldrOpenPath - opens file eventually searching loader specific paths
+ *
+ * @returns   OS2 return code.
+ *            pLdrLv->lv_sfn  is set to filename handle.
+ * @param     pachFilename  Pointer to modulename. Not zero terminated?
+ * @param     cchFilename   Modulename length.
+ * @param     plv           Loader local variables? (Struct from KERNEL.SDF)
+ * @param     pful          Pointer to flags which are passed on to ldrOpen.
+ * @status    stub
+ */
+ULONG LDRCALL fakeldrOpenPath(PCHAR pachFilename, USHORT cchFilename, ldrlv_t *plv, PULONG pful)
+{
+    static char     szPath[1024];       /* Path buffer. Used to store pathlists. 1024 should be enough */
+                                        /* for LIBPATH (which at had a limit of ca. 750 chars). */
+    static char     sz[CCHMAXPATH];     /* Filename/path buffer. (Normally used to build filenames */
+                                        /* which are passed in as search experessions to DosFindFirst.) */
+
+    APIRET          rc;                 /* Return value. (Pessimistic attitude! Init it to FALSE...) */
+
+    printf("fakeldrOpenPath:        *entry* pachFilename = %.*s, cchFilename = %d,  plv = %p, pful = %p\n",
+           cchFilename, pachFilename, cchFilename, plv, pful);
+
+    if (plv->lv_class != CLASS_GLOBAL)
+        rc = fakeldrOpen(&plv->lv_sfn, pachFilename, pful);
+    else
+    {
+        int iPath;                      /* Current path or pathlist being examined. This is the loop */
+                                        /* variable looping on the FINDDLL_* defines. */
+
+        /* These defines sets the order the paths and pathlists are examined. */
+        #define FINDDLL_BEGINLIBPATH    7
+        #define FINDDLL_LIBPATH         8
+        #define FINDDLL_ENDLIBPATH      9
+        #define FINDDLL_FIRST           FINDDLL_BEGINLIBPATH
+        #define FINDDLL_LAST            FINDDLL_ENDLIBPATH
+
+        /*
+         * Remove DLL extention from the filename.
+         */
+        if (cchFilename > 4 && !strncmp(&pachFilename[cchFilename - 4], ".DLL", 4))
+        {
+            cchFilename -= 4;
+            pachFilename[cchFilename] = '\0';
+        }
+
+        /** @sketch
+         * Loop thru the paths and pathlists searching them for the filename.
+         */
+        rc = ERROR_FILE_NOT_FOUND;
+        for (iPath = FINDDLL_FIRST; iPath <= FINDDLL_LAST; iPath++)
+        {
+            const char  *   pszPath;        /* Pointer to the path being examined. */
+
+            /** @sketch Get the path/dir to examin. (This is determined by the value if iPath.) */
+            switch (iPath)
+            {
+                case FINDDLL_BEGINLIBPATH:
+                    rc = DosQueryExtLIBPATH(szPath, BEGIN_LIBPATH);
+                    break;
+                case FINDDLL_LIBPATH:
+                    rc = DosQueryHeaderInfo(NULLHANDLE, 0, szPath, sizeof(szPath), QHINF_LIBPATH);
+                    break;
+                case FINDDLL_ENDLIBPATH:
+                    rc = DosQueryExtLIBPATH(szPath, END_LIBPATH);
+                    break;
+                default: /* !internalerror! */
+                    return ERROR_FILE_NOT_FOUND;
+            }
+            if (rc != NO_ERROR)
+            {
+                printf("fakeldrOpenPath: DosQueryExtLIBPATH/DosQueryHeadInfo failed with rc=%d, iPath=%d", rc, iPath);
+                continue;
+            }
+            pszPath = szPath;
+
+
+            /** @sketch
+             * pszPath is now set to the pathlist to be searched.
+             * So we'll loop thru all the paths in the list.
+             */
+            while (pszPath != NULL && *pszPath != '\0')
+            {
+                char *  pszNext;            /* Pointer to the next pathlist path */
+                int     cch;                /* Length of path (including the slash after the slash is added). */
+
+                /** @sketch
+                 * Find the end of the path.
+                 * Copy the path into the sz buffer.
+                 * Set pszNext.
+                 */
+                pszNext = strchr(pszPath, ';');
+                if (pszNext != NULL)
+                {
+                    cch = pszNext - pszPath;
+                    pszNext++;
+                }
+                else
+                    cch = strlen(pszPath);
+
+                if (cch + cchFilename + 1 >= sizeof(sz)) /* assertion */
+                {
+                    printf("fakeldrOpenPath: cch (%d) + cchFilename (%d) + 1 < sizeof(plv->sz) (%d) - paths too long!, iPath=%d",
+                           cch, cchFilename, sizeof(sz), iPath);
+                    pszPath = pszNext;
+                    continue;
+                }
+                memcpy(sz, pszPath, cch);
+
+                /** @sketch
+                 * Add a '\\' and the filename (pszFullname) to the path;
+                 * then we'll have a fullpath.
+                 */
+                sz[cch++] = '\\';
+                memcpy(&sz[cch], pachFilename, cchFilename);
+                memcpy(&sz[cch + cchFilename], ".DLL", 5);
+
+                rc = fakeldrOpen(&plv->lv_sfn, sz, pful);
+                switch (rc)
+                {
+                    case ERROR_FILE_NOT_FOUND:          case ERROR_PATH_NOT_FOUND:          case ERROR_ACCESS_DENIED:           case ERROR_INVALID_ACCESS:
+                    case ERROR_INVALID_DRIVE:           case ERROR_NOT_DOS_DISK:            case ERROR_REM_NOT_LIST:            case ERROR_BAD_NETPATH:
+                    case ERROR_NETWORK_BUSY:            case ERROR_DEV_NOT_EXIST:           case ERROR_TOO_MANY_CMDS:           case ERROR_ADAP_HDW_ERR:
+                    case ERROR_UNEXP_NET_ERR:           case ERROR_BAD_REM_ADAP:            case ERROR_NETNAME_DELETED:         case ERROR_BAD_DEV_TYPE:
+                    case ERROR_NETWORK_ACCESS_DENIED:   case ERROR_BAD_NET_NAME:            case ERROR_TOO_MANY_SESS:           case ERROR_REQ_NOT_ACCEP:
+                    case ERROR_INVALID_PASSWORD:        case ERROR_OPEN_FAILED:             case ERROR_INVALID_NAME:            case ERROR_FILENAME_EXCED_RANGE:
+                    case ERROR_VC_DISCONNECTED:
+                        rc = ERROR_FILE_NOT_FOUND;
+                        pszPath = pszNext;
+                        continue;
+                }
+
+                /*
+                 * Fatal error or success.
+                 */
+                printf("fakeldrOpenPath:        *exit*  plv->lv_sfn = 0x%04x, rc = %d\n", plv->lv_sfn, rc);
+                return rc;
+            }
+        } /* for iPath */
+    }
+
+    printf("fakeldrOpenPath:        *exit*  plv->lv_sfn = 0x%04x, rc = %d\n", plv->lv_sfn, rc);
+
+    return rc;
+}
+
+
+/**
+ * LDRClearSem - Clears the loader semaphore.
+ * (It does some garbage collection on release.)
+ * @returns   NO_ERROR on sucess.
+ *            OS/2 error on failure. (ERROR_INTERRUPT?)
+ * @status    completely implemented.
+ */
+ULONG LDRCALL fakeLDRClearSem(void)
+{
+    if (lfakeLDRSem == 0)
+        kprintf(("fakeLDRClearSem: lfakeLDRSem is 0 allready\n"));
+    else
+        lfakeLDRSem--;
+
+    printf("fakeLDRClearSem:                usage count = %d, rc = %d\n", lfakeLDRSem, NO_ERROR);
+
+    return NO_ERROR;
+}
+
+/**
+ * KSEMReuqestMutex faker.
+ * @returns   NO_ERROR
+ * @param     hkmtx
+ * @param     ulTimeout
+ * @status    completely implemented.
+ * @remark
+ */
+ULONG KRNLCALL fakeKSEMRequestMutex(HKMTX hkmtx, ULONG ulTimeout)
+{
+    (*(PLONG)hkmtx)++;
+
+    printf("fakeKSEMRequestMutex:           hkmtx = %p, ulTimeout = 0x%x, usage count = %d, rc = %d\n",
+           hkmtx, ulTimeout, *(PLONG)hkmtx, NO_ERROR);
+
+    return NO_ERROR;
+}
+
+
+/**
+ * Copy user memory into system memory.
+ * @returns   OS/2 return code. (NO_ERROR is success)
+ * @param     pv     Pointer to target (system) data area.
+ * @param     pvUsr  Pointer to source (user) data area.
+ * @param     cb     Count of bytes to copy.
+ * @param     fl     Flags.
+ * @status  Partially implemented.
+ * @remark  Ignores fl. Crashes on error.
+ */
+ULONG KRNLCALL   fakeTKFuBuff(PVOID pv, PVOID pvUsr, ULONG cb, ULONG fl)
+{
+    memcpy(pv, pvUsr, cb);
+
+    printf("fakeTKFuBuff:                   pv = %p, pvUsr = %p, cb = 0x%08x, fl = 0x%08x, rc = %d\n",
+           pv, pvUsr, cb, fl, NO_ERROR);
+
+    return NO_ERROR;
+}
+
+
+/**
+ * Copy system memory to user memory.
+ * @returns   OS/2 return code. (NO_ERROR is success)
+ * @param     pvUsr  Pointer to target (user) data area.
+ * @param     pv     Pointer to source (system) data area.
+ * @param     cb     Count of bytes to copy.
+ * @param     fl     Flags.
+ * @status  Partially implemented.
+ * @remark  Ignores fl. Crashes on error.
+ */
+ULONG KRNLCALL   fakeTKSuBuff(PVOID pvUsr, PVOID pv, ULONG cb, ULONG fl)
+{
+    memcpy(pvUsr, pv, cb);
+
+    printf("fakeTKSuBuff:                   pvUsr = %p, pv = %p, cb = 0x%08x, fl = 0x%08x, rc = %d\n",
+           pvUsr, pv, cb, fl, NO_ERROR);
+
+    return NO_ERROR;
+}
+
+
+/**
+ * String length. (includes NULL(s))
+ * @returns   OS/2 return code. (NO_ERROR is success)
+ *            ERROR_TERMINATOR_NOT_FOUND
+ * @param     pcch      Pointer to length variable.
+ * @param     pvUsr     Pointer to user data to preform string length on.
+ * @param     cchMax    Max string length.
+ * @param     fl        Flags.
+ * @param     fDblNULL  TRUE:  Double '\0' (ie. '\0\0') terminated. Usefull for scanning environments.
+ *                      FALSE: Single string. (ie. one '\0').
+ * @status  Partially implemented.
+ * @remark  Ignores fl. Crashes on error.
+ */
+ULONG KRNLCALL   fakeTKFuBufLen(PLONG pcch, PVOID pvUsr, ULONG cchMax, ULONG fl, BOOL fDblNULL)
+{
+    ULONG   rc;
+    PSZ     psz = pvUsr;
+
+    cchMax += (ULONG)pvUsr;
+
+    while ((ULONG)psz < cchMax)
+    {
+        if (*psz++ == '\0')
+            if (!fDblNULL || (ULONG)psz == cchMax || *psz++ != '\0')
+                break;
+    }
+
+    *pcch = (ULONG)psz - (ULONG)pvUsr;
+
+    /* Hope this is the correct definition of max length: Not inclusive. */
+    if ((ULONG)psz == cchMax)
+        rc = ERROR_TERMINATOR_NOT_FOUND;
+    else
+        rc = NO_ERROR;
+
+    printf("fakeTKFuBufLen:                 pcch = %p; *pcch = 0x%08x, pvUsr = %p, cchMax = 0x%08x, fl = 0x%08x, fDblNULL = %x, rc = %d\n",
+           pcch, *pcch, pvUsr, cchMax, fl, fDblNULL, NO_ERROR);
+
+    return rc;
+}
+
+
+/**
+ * Validates an hMTE and gets the MTE pointer - FAKE.
+ * @returns Pointer to MTE on success.
+ *          NULL on error.
+ * @param   hMTE  MTE handle.
+ * @remark  If you wan't to this faster:
+ *            Use the hMTE as a HOB and get the HOB address (by using VMGetHandleInfo).
+ * @status  stub.
+ */
+PMTE LDRCALL fakeldrValidateMteHandle(HMTE hMTE)
+{
+    DUMMY();
+
+    printf("fakeldrValidateMteHandle:       hMTE = 0x%04x, pMTE (rc) = %p\n",
+           hMTE, NULL);
+
+    return NULL;
+}
+
+
+/**
+ * C worker function for fakeg_tkExecPgm. This is called by fakeg_tkExecPgm (fakea.asm).
+ * @returns   OS/2 return code.
+ * @param     execFlag      Exec flag (DosExecPgm execFlag).
+ * @param     pArg          Pointer to arguments. (NULL allowed)
+ * @param     pEnv          Pointer to environment. (NULL allowed)
+ * @param     pszFilename   Pointer to filename.
+ * @sketch
+ * @status
+ * @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ * @remark
+ */
+ULONG _Optlink tkExecPgmWorker(ULONG execFlag, PSZ pArg, PSZ pEnv, PSZ pszFilename)
+{
+    APIRET      rc;
+    ldrrei_t    rei;
+
+    printf("tkExecPgmWorker:                execFlag = %d, pArg = %p, pEnv = %p, pszFilename = %s\n", execFlag, pArg, pEnv, pszFilename);
+
+    /*
+     * Simulate loading.
+     */
+    rc = fakeLDRLoadExe(pszFilename, SSToDS(&rei));
+
+    NOREF(pArg);
+    NOREF(pEnv);
+    NOREF(execFlag);
+
+    return rc;
+}
+
+
+/**
+ * Fake implementation of LDRLoadExe.
+ * Not currently overriden, but used by tkExecPgmWorker to load executables.
+ * @returns   OS/2 return code.
+ * @param     pszFilename   Name of executable image to load.
+ * @param     pEI           It seems this is a pointer to a ldrrei_s struct.
+ *                          (currently ignored)
+ * @sketch
+ * @status
+ * @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ * @remark
+ */
+ULONG LDRCALL fakeLDRLoadExe(PSZ pszFilename, ldrrei_t *pEI)
+{
+    APIRET  rc;
+    int     cchFilename = strlen(pszFilename);
+
+    printf("fakeLDRLoadExe:         *entry* pszFilename = %s, pEI = %p\n",
+           pszFilename, pEI);
+
+    rc = fakeldrGetModule(pszFilename, (cchFilename << 16) | (LVTYPE_EXE << 8) | CLASS_PROGRAM);
+
+    printf("fakeLDRLoadExe:         *exit*  pszFilename = %s, pEI = %p, rc = %d\n",
+           pszFilename, pEI, rc);
+
+    return rc;
+}
+
+
+
+/**
+ * Fake implementeation of ldrGetModule.
+ * Not currently overriden, but used by fakeLDRLoadExe to load executables.
+ * @returns   OS/2 return code.
+ * @param     pszFilename   Name of executable image to load.
+ * @param     ul            low 8 bits:     Module CLASS_*.
+ *                          high 8 bits:    Executable type LVTYPE_* ?
+ *                          high 16 bits:   Filename length.
+ * @sketch
+ *  OS/2 kernel seems to do:
+ *      Call Sec32GetModule
+ *      Call ldrGetMte which does the necessary loading / attaching.
+ *      Call ldrLoadImports for all imported DLLs. (and the exe?)
+ *      Call ldrProcessObjects for LX and ldrPreloadLDT for NE imported DLLs. (and the exe?)
+ *      Call ldrProcessImports.
+ *
+ *  We do:
+ *      Call fakeldrGetMte.
+ *      Call fakeldrLoadImports.
+ *
+ * @status
+ * @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ * @remark
+ */
+ULONG LDRCALL fakeldrGetModule(PSZ pszFilename, ULONG ul)
+{
+    APIRET  rc;
+    PMTE    pmte = NULL;
+
+    printf("fakeldrGetModule:       *entry* pszFilename = %s, ul = 0x%08x\n",
+           pszFilename, ul);
+
+    rc = fakeldrGetMte(pszFilename, (USHORT)(ul >> 16), (UCHAR)((ul & 0xff00) >> 8), (UCHAR)(ul & 0x00ff), SSToDS(&pmte));
+    if (rc == NO_ERROR)
+    {
+        rc = fakeldrLoadImports(pmte);
+    }
+
+    printf("fakeldrGetModule:       *exit*  pszFilename = %s, ul = 0x%08x, rc = %d\n",
+           pszFilename, ul, rc);
+
+    return rc;
+}
+
+
+/**
+ *
+ * @returns
+ * @param
+ * @equiv
+ * @time
+ * @sketch
+ *  OS/2 kernel seems to do:
+ *      IF not device driver THEN
+ *          Uppercase the name.
+ *          Call ldrFindModule to try find the module within currenly loaded modules.
+ *      ENDIF
+ *
+ *    tryagain:
+ *      IF found THEN
+ *          Set MTEGETMTEDONE flag in mte_flags2.
+ *          Call ldrChkLoadType to ensure correct load type.
+ *          IF attached or special modules (DOSMOD, VDDMOD, FSHMOD or MVDMMOD)
+ *              IF miniIFS and !FSHMOD THEN Fail with rc=ERROR_INVALID_NAME
+ *              return successfully.
+ *          ENDIF
+ *          lv_sfn <- mte_sfn
+ *          Set the USED flag in mte_flags1
+ *          Set the MTELOADORATTACH flag in mte_flags2
+ *          Some processing of packed segments???? Dll init flags???
+ *      ELSE *not found*
+ *          IF class is CLASS_SPECIFIC AND ldrCheckGlobal returned TRUE THEN
+ *              * this is because some specific modules is promoted to global
+ *              * modules for some reasons I haven't ivestigated. (ldrPrmoteMTE)
+ *              tryagain.
+ *          ENDIF
+ *          Set some flag to false.
+ *          Calls to ldrOpenNewExe to load the exectuble from disk.
+ *          IF this failes THEN fail.
+ *          IF class is CLASS_GLOBAL and module is loaded as specific
+ *              (ldrCheckSpecific returns TRUE) THEN
+ *              Close and retry with the mte returned ldrCheckSpecific
+ *              tryagain.
+ *          ENDIF
+ *          Sets some local variable to point at pheaderbuf, where ldrOpenNewExe
+ *              has put the executable header.
+ *          Call ldrCheckLoadType and fail if this failes.
+ *          Call ldrCreateMte and fail if this failes.
+ *          Set some local variables to lv_pmte and lv_pmte->mte_swapmte.
+ *          Set the MTELOADORATTACH and MTEGETMTEDONE flags.
+ *          Call ldrInvTgtErrTxt.
+ *          IF DDInitTime AND DEVDRVMOD OR FSDMOD THEN
+ *              ptda_module of current PTDA to the mtehandle of the module.
+ *          ENDIF
+ *          IF DOSCALL1 (checks name) THEN
+ *              Set DOSLIB flag of mte_flags1.
+ *              Set global pmteDoscall1 to point to the mte.
+ *              Set global hmteDoscall1 to the handle of the mte.
+ *          ENDIF
+ *      ENDIF
+ *      IF VDDMOD THEN
+ *          call VDMMLoadingVDD with the mte handle.
+ *      ENDIF
+ *      IF NE executable THEN
+ *          Call ldrAllocSegments
+ *      ELSE
+ *          Call ldrAllocObjects
+ *      ENDIF
+ *      IF failed THEN fail.
+ *      IF LVTYPE_EXE THEN
+ *          Set the ptda_module of the ExecChild PTDA to mtehandle.
+ *          IF MTELONGNAMES THEN
+ *              Set ptda_NewFiles to something.
+ *          ENDIF
+ *          Increment usage count, ie. mte_usecnt-
+ *      ELSE IF LVTYPE_DLL AND !somelocalflag AND NOINTERNFIXUPS THEN
+ *          Remove Internal fixups?
+ *          (Calls ldrIsInternalFixup and VMReallocKHB during this processing.)
+ *      ENDIF
+ *      Clears the MTEPROCESSED flag of mte_flags1.
+ *      Sets the return mte pointer. (ppmte)
+ *      return successfully.
+ *
+ *  We do:
+ *      Uppercase the string. (do we have to switch stack?)
+ *      Call fakeldrOpenNewExe to do it's work.
+ *      Call fakeldrCreateMte to create a fake mte.
+ *      return.
+ *
+ * @status
+ * @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ * @remark
+ */
+ULONG LDRCALL   fakeldrGetMte(PCHAR pachFilename, USHORT cchFilename, UCHAR fchType, UCHAR fchClass, PPMTE ppmte)
+{
+    ldrlv_t         lv;
+    APIRET          rc;
+
+    printf("fakeldrGetMte:          *entry* pachFilename = %.*s, cchFilename = %#02x, fchType %#2x, fchClass = %#2x, ppmte = %p\n",
+           cchFilename, pachFilename, cchFilename, fchType, fchClass, ppmte);
+
+    /*
+     * Initiate the local variables.
+     */
+    memset(SSToDS(&lv), 0, sizeof(lv));
+    lv.lv_sfn = (USHORT)-1;
+    lv.lv_type = fchType;
+    lv.lv_class = fchClass;
+
+    /*
+     * Uppercase the string.
+     */
+    fakeldrUCaseString(pachFilename, cchFilename);
+
+    /*
+     * Open the new executable.
+     */
+    rc = fakeldrOpenNewExe(pachFilename, cchFilename, SSToDS(&lv), NULL);
+    if (rc != NO_ERROR)
+    {
+        fakeldrClose(lv.lv_sfn);
+        printf("fakeldrGetMte:          *exit*  pachFilename = %.*s, ppmte = %p; *ppmte = %p, rc = %d\n",
+               cchFilename, pachFilename, ppmte, *ppmte, rc);
+        return rc;
+    }
+
+    /*
+     * Create MTE for the opened file.
+     */
+    rc = fakeldrCreateMte(pheaderbuf, SSToDS(&lv));
+    if (rc == NO_ERROR)
+    {
+        /*
+         * Set some flags... More?
+         */
+        lv.lv_pmte->mte_flags2 |= MTEGETMTEDONE | MTELOADORATTACH;
+        *ppmte = lv.lv_pmte;
+    }
+
+    printf("fakeldrGetMte:          *exit*  pachFilename = %.*s, ppmte = %p; *ppmte = %p, rc = %d\n",
+           cchFilename, pachFilename, ppmte, *ppmte, rc);
+
+    return rc;
+}
+
+
+
+/**
+ * Opens an executable module.
+ * @returns   OS2 error code.
+ * @param     pachFilename      Filename of the executable module to open.
+ * @param     cchFilename       Filename length.
+ * @param     plv               Pointer to local variables.
+ * @param     pus               Pointer to some flags (LDRQAppType flags?!).
+ * @sketch
+ *  OS/2 kernel seems to do:
+ *      Call ldrOpenPath to open the file.
+ *      IF this fail THEN
+ *          Set lv_sfn to -1 and return errorcode.
+ *      ENDIF
+ *      Set local variable to pheaderbuf.
+ *      IF pus THEN set *pus to 1
+ *      Call ldrRead to read the MZ header.
+ *      Fail if this failed. (Don't close file caller does that.)
+ *      IF LXMAGIC of NEMAGIC found THEN
+ *          lv_new_exe_off <- 0;
+ *      ELSE
+ *          IF !EMAGIC or 'OZ' THEN
+ *              Fail with rc=ERROR_INVALID_EXE_SIGNATURE.
+ *          ENDIF
+ *          IF pus THEN set *pus to 2.
+ *          lv_new_exe_off <- e_lfanew.
+ *      ENDIF
+ *      Call ldrRead to read LX/NE header at lv_new_exe_off.
+ *      Fail if this failed.
+ *      IF NOT  LXMAGIC OR NEMAGIC THEN
+ *          IF LEMAGIC AND pus THEN Set *pus to 0.
+ *          IF PEMAGIC and pus THEN Set *pus to 3.
+ *          Fail with rc=ERROR_INVALID_EXE_SIGNATURE.
+ *      ENDIF
+ *      IF pus THEN Set *pus to 0.
+ *      IF invalid LX exeheader THEN
+ *          Fail with rc=ERROR_INVALID_EXE_SIGNATURE.
+ *      ENDIF
+ *      IF NEMAGIC THEN
+ *          Call ldrExpandHeader
+ *      ELSE
+ *          Set the MTELONGNAMES flag in e32_mflags.
+ *      ENDIF
+ *      IF LDRINVALID (in e32_mflags) THEN
+ *          Fail with rc=ERROR_EXE_MARKED_INVALID.
+ *      ENDIF
+ *      Clear some e32_mflags, MTE_MEDIAFIXED, MTEMEDIACONTIG and MTEMEDIA16M.
+ *      Or in flags set by ldrOpenPath into e32_mflags. (media type flags?!)
+ *      Call ldrMungeFlags
+ *      return retur code from ldrMungeFlags.
+ *
+ *  We do:
+ *      Call fakeldrOpenPath to open the file.
+ *      IF this fail THEN
+ *          Set lv_sfn to -1 and return errorcode.
+ *      ENDIF
+ *      IF pus THEN set *pus to 1
+ *      Call ldrRead to read the MZ header.
+ *      Fail if this failed. (Don't close file caller does that.)
+ *      If MZ header Then
+ *          Set lv_new_exe_off to e_lfanew.
+ *      else
+ *          Set lv_new_exe_off to 0.
+ *      Call ldrRead to read the LX header.
+ *      Fail if this failed. (Don't close file caller does that.)
+ *      If Not LX signature Then
+ *          Fail.
+ *      return successfully.
+ *
+ * @status
+ * @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ * @remark
+ */
+ULONG LDRCALL   fakeldrOpenNewExe(PCHAR pachFilename, USHORT cchFilename, ldrlv_t *plv, PUSHORT pus)
+{
+    APIRET  rc;
+    ULONG   ful;
+
+    printf("fakeldrOpenNewExe:      *entry* pachFilename = %.*s, cchFilename = %#2, plv = %p, pus = %p\n",
+           cchFilename, pachFilename, cchFilename, plv, pus);
+
+    rc = fakeldrOpenPath(pachFilename, cchFilename, plv, SSToDS(&ful));
+    if (rc != NO_ERROR)
+    {
+        plv->lv_sfn = 0xffff;
+        printf("fakeldrOpenNewExe:      *exit*  pachFilename = %.*s, plv->lv_sfn = %#4x, rc = %d\n",
+               cchFilename, pachFilename, plv->lv_sfn, rc);
+        return rc;
+    }
+    if (pus) *pus = 1;
+
+    memset(pheaderbuf, 0, sizeof(struct exe_hdr)); //zero it just in case....
+    rc = fakeldrRead(plv->lv_sfn, 0, pheaderbuf, 0, sizeof(struct exe_hdr), NULL);
+    if (rc != NO_ERROR)
+    {
+        plv->lv_sfn = 0xffff;
+        printf("fakeldrOpenNewExe:      *exit*  pachFilename = %.*s, plv->lv_sfn = %#4x, rc = %d\n",
+               cchFilename, pachFilename, plv->lv_sfn, rc);
+        return rc;
+    }
+
+    if (*(PUSHORT)pheaderbuf == EMAGIC)
+        plv->lv_new_exe_off = ((struct exe_hdr *)pheaderbuf)->e_lfanew;
+    else
+        plv->lv_new_exe_off = 0;
+
+    memset(pheaderbuf, 0, sizeof(struct e32_exe)); //zero it just in case....
+    rc = fakeldrRead(plv->lv_sfn, plv->lv_new_exe_off, pheaderbuf, 0, sizeof(struct e32_exe), NULL);
+    if (rc != NO_ERROR)
+    {
+        plv->lv_sfn = 0xffff;
+        printf("fakeldrOpenNewExe:      *exit*  pachFilename = %.*s, plv->lv_sfn = %#4x, rc = %d\n",
+               cchFilename, pachFilename, plv->lv_sfn, rc);
+        return rc;
+    }
+
+    if (*(PUSHORT)pheaderbuf != E32MAGIC)
+    {
+        plv->lv_sfn = 0xffff;
+        rc = ERROR_INVALID_EXE_SIGNATURE;
+        printf("fakeldrOpenNewExe:      *exit*  pachFilename = %.*s, plv->lv_sfn = %#4x, rc = %d\n",
+               cchFilename, pachFilename, plv->lv_sfn, rc);
+        return rc;
+    }
+
+    printf("fakeldrOpenNewExe:      *exit*  pachFilename = %.*s, plv->lv_sfn = %#4x, rc = %d\n",
+           cchFilename, pachFilename, plv->lv_sfn, rc);
+
+    return NO_ERROR;
+}
+
+
+/**
+ * Fake ldrCreateMte implementation.
+ * @returns
+ * @param     pe32  Pointer to the LX/NE header we've just read.
+ * @param     plv   Pointer to local variables.
+ * @sketch    !This does a lot of thing!
+ *
+ *  OS/2 Kernel seems to do:
+ *      Allocate a kernel heap block for the MTE
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *  We do:
+ *
+ *
+ * @status
+ * @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ * @remark
+ */
+ULONG LDRCALL   fakeldrCreateMte(struct e32_exe *pe32, ldrlv_t *plv)
+{
+    ULONG   rc;
+    PMTE    pMte;
+    PSMTE   pSMte;
+    PCHAR   pch;
+
+    printf("fakeldrCreateMte:       *entry* pe32 = %p, plv = %d\n",
+           pe32, plv);
+
+    /*
+     * Allocate mte and smte.
+     * The MTE has an array of mte pointers at the end for imported modules + 1.
+     * The SMTE has the fullpath filename, loader section and fixup section.
+     */
+    pMte = malloc(sizeof(MTE) + sizeof(PMTE) + sizeof(PMTE)*pe32->e32_impmodcnt);
+    if (pMte == NULL)
+    {
+        rc = ERROR_NOT_ENOUGH_MEMORY;
+        goto createmte_exit;
+    }
+
+    plv->lv_csmte = sizeof(SMTE) + 260 + pe32->e32_ldrsize + pe32->e32_fixupsize;
+    pSMte = malloc(plv->lv_csmte);
+    if (pSMte == NULL)
+    {
+        rc = ERROR_NOT_ENOUGH_MEMORY;
+        goto createmte_exit;
+    }
+    pch = (PCHAR)(PVOID)pSMte + sizeof(SMTE) + 260;
+
+
+    /*
+     * Initialize the MTE.
+     */
+    pMte->mte_flags2    = MTEFORMATLX;
+    pMte->mte_handle    = 20;
+    pMte->mte_swapmte   = pSMte;
+    pMte->mte_link      = NULL;
+    pMte->mte_flags1    = pe32->e32_mflags;
+    pMte->mte_impmodcnt = pe32->e32_impmodcnt;
+    pMte->mte_sfn       = plv->lv_sfn;
+    pMte->mte_usecnt    = 0;
+    pMte->mte_modname[0]= '\0';
+
+    /*
+     * Initialize the SMTE.
+     */
+    pSMte->smte_mpages = pe32->e32_mpages;
+    /*- magic,border,worder,level,cpu,os,ver,mflags */
+    pSMte->smte_mpages      = pe32->e32_mpages;        /* 00  Module # pages */
+    pSMte->smte_startobj    = pe32->e32_startobj;      /* 04  Object # for instruction */
+    pSMte->smte_eip         = pe32->e32_eip;           /* 08  Extended instruction pointer */
+    pSMte->smte_stackobj    = pe32->e32_stackobj;      /* 0c  Object # for stack pointer */
+    pSMte->smte_esp         = pe32->e32_esp;           /* 10  Extended stack pointer */
+        /*- pagesize*/
+    pSMte->smte_pageshift   = pe32->e32_pageshift;     /* 14  Page alignment shift in .EXE */
+    pSMte->smte_fixupsize   = pe32->e32_fixupsize;     /* 18  Fixup section size */
+        /*- fixupsum,ldrsize,ldrsum*/
+    pSMte->smte_objtab      = (POTE)pe32->e32_objtab;  /* 1c  Object table offset - POINTER */
+    pSMte->smte_objcnt      = pe32->e32_objcnt;        /* 20  Number of objects in module */
+    pSMte->smte_objmap      = pe32->e32_objmap;        /* 24  Object page map offset - POINTER */
+    pSMte->smte_itermap     = pe32->e32_itermap;       /* 28  Object iterated data map offset */
+    pSMte->smte_rsrctab     = pe32->e32_rsrctab;       /* 2c  Offset of Resource Table */
+    pSMte->smte_rsrccnt     = pe32->e32_rsrccnt;       /* 30  Number of resource entries */
+    pSMte->smte_restab      = pe32->e32_restab;        /* 34  Offset of resident name table - POINTER */
+    pSMte->smte_enttab      = pe32->e32_enttab;        /* 38  Offset of Entry Table - POINTER */
+    pSMte->smte_fpagetab    = pe32->e32_fpagetab;      /* 3c  Offset of Fixup Page Table - POINTER */
+    pSMte->smte_frectab     = pe32->e32_frectab;       /* 40  Offset of Fixup Record Table - POINTER */
+    pSMte->smte_impmod      = pe32->e32_impmod;        /* 44  Offset of Import Module Name Table - POINTER */
+        /*- impmodcnt*/
+    pSMte->smte_impproc     = pe32->e32_impproc;       /* 48  Offset of Imp Procedure Name Tab - POINTER */
+        /*- pagesum*/
+    pSMte->smte_datapage    = pe32->e32_datapage;      /* 4c  Offset of Enumerated Data Pages */
+        /*- preload*/
+    pSMte->smte_nrestab     = pe32->e32_nrestab;       /* 50  Offset of Non-resident Names Table */
+    pSMte->smte_cbnrestab   = pe32->e32_cbnrestab;     /* 54  Size of Non-resident Name Table */
+        /*- nressum*/
+    pSMte->smte_autods      = pe32->e32_autodata;      /* 58  Object # for automatic data object */
+    pSMte->smte_debuginfo   = pe32->e32_debuginfo;     /* 5c  Offset of the debugging info */
+    pSMte->smte_debuglen    = pe32->e32_debuglen;      /* 60  The len of the debug info in */
+        /*- instpreload,instdemand*/
+    pSMte->smte_heapsize    = pe32->e32_heapsize;      /* 64  use for converted 16-bit modules */
+        /*- res3*/
+    /* extra */
+    pSMte->smte_path        = 0;                       /* 68  full pathname - POINTER */
+    pSMte->smte_semcount    = 0;                       /* 6c  Count of threads waiting on MTE semaphore. 0 => semaphore is free */
+    pSMte->smte_semowner    = 0;                       /* 6e  Slot number of the owner of MTE semahore */
+    pSMte->smte_pfilecache  = 0;                       /* 70  Pointer to file cache for Dos32CacheModule */
+    pSMte->smte_stacksize   = 0;                       /* 74  Thread 1 Stack size from the exe header */
+    pSMte->smte_alignshift  = 0;                       /* 78  use for converted 16-bit modules */
+    pSMte->smte_NEexpver    = 0;                       /* 7a  expver from NE header */
+    pSMte->smte_pathlen     = 0;                       /* 7c  length of full pathname */
+    pSMte->smte_NEexetype   = 0;                       /* 7e  exetype from NE header */
+    pSMte->smte_csegpack    = 0;                       /* 80  count of segs to pack */
+
+    /*
+     * Copy filename (from where?)
+     */
+    pSMte->smte_path        = (PCHAR)(PVOID)pSMte + sizeof(SMTE);
+    pSMte->smte_pathlen     = 0;
+    memcpy(pSMte->smte_path, "", pSMte->smte_pathlen);
+
+
+    /*
+     * Read loader and fixup sections.
+     */
+    rc = fakeldrRead(plv->lv_sfn,
+                     (ULONG)pSMte->smte_objtab + plv->lv_new_exe_off,
+                     pch,
+                     0,
+                     pe32->e32_ldrsize + pe32->e32_fixupsize,
+                     NULL);
+    if (rc)
+    {
+        goto createmte_exit;
+    }
+
+    /*
+     * Set pointers.
+     */
+    pSMte->smte_objtab = (POTE)(PVOID)pch;
+    rc = fakeldrMTEValidatePtrs(pSMte,
+                                (ULONG)pch + plv->lv_csmte,
+                                (ULONG)pch - (ULONG)pe32->e32_objtab);
+    if (rc)
+    {
+        goto createmte_exit;
+    }
+
+    /*
+     * Set mte pointer in plv.
+     * Set hobmte in plv.
+     */
+    plv->lv_pmte = pMte;
+    plv->lv_hobmte = pMte->mte_handle;
+
+    /*
+     * Fix flags...
+     */
+    pMte->mte_flags1 |= plv->lv_class;
+
+createmte_exit:
+    printf("fakeldrCreateMte:       *exit*  pe32 = %p, plv = %d, rc = %d\n",
+           pe32, plv, rc);
+
+    return rc;
+}
+
+
+
+/**
+ * Fake ldrLoadImports - loads the import modules for the given module (pmte).
+ * @returns   OS2 error code.
+ * @param     pmte  Pointer to mte to load imports for.
+ * @sketch
+ *  OS/2 kernel seems to do:
+ *      Loop thru the importe module table (reverse order for NE files)
+ *          IF VDD module THEN
+ *              Uppercase the name.
+ *              try find it using ldrFindModule
+ *              fail if error, not found, not VDDMOD/MVDMMOD.
+ *              Add to array of imported module.
+ *          ENDIF
+ *          IF Not found OR !MTEGETMTEDONE THEN
+ *              call ldrGetMte to load the module (class global).
+ *              fail if error.
+ *              set MTEGETMTEDONE
+ *              Add to array of imported module.
+ *          ENDIF
+ *          IF DOSMOD and !ldrMiniFileIOFlag THEN
+ *              Replace module pointer with doscall1 pmte.
+ *          ENDIF
+ *      ENDLOOP
+ *
+ *  We do:
+ *      Parameter validation.
+ *      Loop thru the imported module table issuing fakeldrGetMte on each entry.
+ *      'DOSCALLS' is ignored.
+ *
+ * @status
+ * @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ * @remark
+ */
+ULONG LDRCALL   fakeldrLoadImports(PMTE pmte)
+{
+    int     i;                          /* Module index. */
+    PSZ     psz;                        /* Module name pointer. (really pointer to pascal strings...) */
+    PPMTE   papmte;                     /* Pointer to array of PMTEs for imported modules. */
+    APIRET  rc;
+
+    printf("fakeldrLoadImport:      *entry* pmte = %p, pmte->mte_impmodcnt = %d\n",
+           pmte, pmte->mte_impmodcnt);
+
+    /*
+     * Parameter validation.
+     */
+    if (pmte == NULL)
+    {
+        kprintf(("fakeldrLoadImports: !ASSERTION! pmte == NULL\n"));
+        return ERROR_INVALID_PARAMETER;
+    }
+    if (pmte->mte_swapmte == NULL)
+    {
+        kprintf(("fakeldrLoadImports: !ASSERTION! pmte->mte_swapmte == NULL\n"));
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    /*
+     * Any imported modules?
+     */
+    if (pmte->mte_impmodcnt == 0)
+    {
+        printf("fakeldrLoadImport:      *exit*  pmte = %p, rc = %d\n",
+               pmte, rc);
+        return NO_ERROR;
+    }
+
+    /* We have reserved space for imported module pointers after the mte. */
+    papmte = (PPMTE)((unsigned)pmte  + sizeof(MTE));
+
+    /*
+     * Process the imported module table.
+     */
+    for (i = 0, rc = NO_ERROR, psz = (PSZ)pmte->mte_swapmte->smte_impmod;
+         i < pmte->mte_impmodcnt && rc == NO_ERROR;
+         i++, psz += 1 + *psz)
+    {
+        if (!memcmp(psz+1, "DOSCALLS", *psz))
+            continue;
+
+        rc = fakeldrGetMte(psz + 1, *psz, LVTYPE_DLL, CLASS_GLOBAL, &papmte[i]);
+    }
+
+    printf("fakeldrLoadImport:      *exit*  pmte = %p, rc = %d\n",
+           pmte, rc);
+
+    return rc;
+}
+
+
+
+/**
+ * Uppercases the string.
+ * @param     pachString    String to uppercase.
+ * @param     cchString     Length of string.
+ * @sketch    Loop thru the string converting all english letters to uppercase.
+ * @status    partially implemented.
+ * @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ * @remark    This is probably written in assembly and does DBCS checks...
+ */
+VOID LDRCALL    fakeldrUCaseString(PCHAR pachString, USHORT cchString)
+{
+    printf("fakeldrUCaseString:             pachString = %.*s, cchString = %#8x\n",
+           cchString, pachString, cchString);
+
+    while (cchString-- != 0)
+    {
+        if (*pachString >= 'a' && *pachString <= 'z')
+            *pachString -= ('a' - 'A');
+        pachString++;
+    }
+}
+
+
+
+
+/**
+ * Checks and updates the members of the swap-mte which is to be
+ * pointers into the loader/fixup section. An array, validatetbl, contains
+ * the offsets of the smte pointers.
+ *
+ * @returns     NO_ERROR    on success.
+ *              ERROR_BAD_EXE_FORMAT on error.
+ * @param       psmte
+ * @param       ulMaxAddr   Maximum (exclusive) address.
+ * @param       off         Offset delta to add to the pointer members (which
+ *                          are all offsets relative to the start of the new
+ *                          header) to make them pointers.
+ * @sketch
+ *  Loop thru the validatetbl and update each field (which isn't null) by adding
+ *  the off value, and validate that the pointer is ok.
+ * @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ * @remark
+ */
+ULONG LDRCALL   fakeldrMTEValidatePtrs(PSMTE psmte, ULONG ulMaxAddr, ULONG off)
+{
+    int     i;
+
+    printf("fakeldrMTEValidatePtrs: *entry* psmte = %p, ulMaxAddr = %p, off = %p\n",
+           psmte, ulMaxAddr, off);
+
+    for (i = 0; validatetbl[i] != 0xDEAD; i++)
+    {
+        PULONG  pul = (PULONG)(PVOID)((PCHAR)(PVOID)psmte + validatetbl[i]);
+        if (*pul != 0UL)
+        {
+            *pul += off;
+            if (*pul >= ulMaxAddr)
+            {
+                printf("fakeldrMTEValidatePtrs: *exit*  psmte = %p, ulMaxAddr = %p, off = %p, rc = %d\n",
+                       psmte, ulMaxAddr, off, ERROR_BAD_EXE_FORMAT);
+                return ERROR_BAD_EXE_FORMAT;
+            }
+        }
+    }
+
+    printf("fakeldrMTEValidatePtrs: *exit*  psmte = %p, ulMaxAddr = %p, off = %p, rc = %d\n",
+           psmte, ulMaxAddr, off, NO_ERROR);
+    return NO_ERROR;
+}
+
Index: trunk/src/win32k/test/fakea.asm
===================================================================
--- trunk/src/win32k/test/fakea.asm	(revision 3832)
+++ trunk/src/win32k/test/fakea.asm	(revision 3832)
@@ -0,0 +1,446 @@
+; $Id: fakea.asm,v 1.1 2000-07-16 22:18:15 bird Exp $
+;
+; Fake assembly imports.
+;
+; Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+;
+; Project Odin Software License can be found in LICENSE.TXT
+;
+
+    .386
+
+;
+;   Defined Constants And Macros
+;
+    INCL_BASE EQU 1
+
+;
+;   Include files
+;
+    include devsegdf.inc
+    include devhlp.inc
+    include os2.inc
+
+
+;
+;   Exported symbols
+;
+    public fakepTCBCur
+    public fakepPTDACur
+    public fakeptda_start
+    public fakeptda_environ
+    public fakef_FuStrLenZ
+    public fakef_FuStrLen
+    public fakef_FuBuff
+    public fakeg_tkExecPgm
+    public CalltkExecPgm
+
+
+;
+;   Imported Functions
+;
+    extrn tkExecPgmWorker:PROC          ; fake.c
+
+
+DATA16 SEGMENT
+; Fake data in 16-bit segment.
+fakepTCBCur         dd      offset FLAT:fakeTCB
+fakepPTDACur        dd      offset FLAT:fakeptda_start
+
+; PTDA - Only use environ and ExecChild.
+fakeptda_start              LABEL DWORD
+fakeptda_pPTDAParent        dd      0
+fakeptda_pPTDASelf          dd      offset FLAT:fakeptda_start
+fakeptda_pPTDAFirstChild    dd      0
+fakeptda_pPTDAExecChild     dd      offset FLAT:fakeptda_start
+fakeptda_dummy              db  123 dup (0)
+fakeptda_environ            dw      1   ; 1 is the hardcoded HOB of the win32ktst.exe's environment.
+
+
+; TCB - just needs some dummy data for reading and writing to the TCBFailErr.
+fakeTCB                     db 220h dup (0CCh)
+
+DATA16 ENDS
+
+
+CODE16 SEGMENT
+
+
+; Scans strings until empy-string is reached.
+; input:  bx:di
+; uses:   nearly all (save bp)
+; return: cx size - CF clear
+;         ax error- CF set
+fakef_FuStrLenZ PROC FAR
+    push    2                           ; required by all 16-bit far procedures.
+    push    2                           ; dummy code.
+    push    2                           ; dummy code.
+    push    2                           ; dummy code.
+    push    es
+
+    mov     dx, di                      ; save di pointer.
+    cmp     bx, 7                       ; check if NULL ptr.
+    jle     ffslz_badselector
+
+    mov     es, bx                      ; es:di -> string
+    mov     cx, di
+    not     cx                          ; maximum length is to segment end.
+    xor     ax, ax                      ; test against zero (scasb uses al to cmp with).
+
+ffslz_loop:
+    repnz scasb
+    jnz     ffslz_no_term               ; jump if cx = 0
+    dec     cx                          ; check if next is NULL too
+    scasb
+    jnz     ffslz_loop
+
+ffslz_retok:
+    mov     cx, di
+    sub     cx, dx                      ; cx <- size (end ptr - start ptr)
+    pop     es
+    add     sp, 8
+    clc
+    db      66h
+    retf
+
+ffslz_badselector:
+    mov     ax, ERROR_INVALID_SELECTOR
+    jmp     ffslz_reterr
+
+;ffslz_invalidptr:
+;    mov     ax, ERROR_INVALID_ACCESS
+;    jmp     ffslz_reterr
+
+ffslz_no_term:
+    mov     ax, ERROR_TERMINATOR_NOT_FOUND
+ffslz_reterr:
+    pop     es
+    add     sp, 8
+    stc
+    db      66h
+    retf
+fakef_FuStrLenZ ENDP
+
+
+;
+; Stringlength - Fake
+; input:  bx:di
+; uses:   nearly all (save bp)
+; return: cx size - CF clear
+;         ax error- CF set
+fakef_FuStrLen PROC FAR
+    push    2                           ; required by all 16-bit far procedures.
+    push    2                           ; dummy code.
+    push    2                           ; dummy code.
+    push    2                           ; dummy code.
+    push    es
+
+    mov     dx, di                      ; save di pointer.
+    cmp     bx, 7                       ; check if NULL ptr.
+    jle     ffslz_badselector
+
+    mov     es, bx                      ; es:di -> string
+    mov     cx, di
+    not     cx                          ; maximum length is to segment end.
+    xor     ax, ax                      ; test against zero (scasb uses al to cmp with).
+
+    repnz scasb
+    jnz     ffslz_no_term               ; jump if cx = 0
+
+ffslz_retok:
+    mov     cx, di
+    sub     cx, dx                      ; cx <- size (end ptr - start ptr)
+    pop     es
+    add     sp, 8
+    clc
+    db      66h
+    retf
+
+ffslz_badselector:
+    mov     ax, ERROR_INVALID_SELECTOR
+    jmp     ffslz_reterr
+
+;ffslz_invalidptr:
+;    mov     ax, ERROR_INVALID_ACCESS
+;    jmp     ffslz_reterr
+
+ffslz_no_term:
+    mov     ax, ERROR_TERMINATOR_NOT_FOUND
+ffslz_reterr:
+    pop     es
+    add     sp, 8
+    stc
+    db      66h
+    retf
+fakef_FuStrLen ENDP
+
+
+;memcpy
+;input:  bx:si pointer to source
+;        es:di pointer to target
+;        cx    count of bytes to copy
+;uses:   nearly all (save bp), es, ds
+;return: success CF clear
+;        failure CF set
+fakef_FuBuff PROC FAR
+    push    2                           ; required by all 16-bit far procedures.
+    push    2                           ; dummy code.
+    push    2                           ; dummy code.
+    push    2                           ; dummy code.
+    push    es
+
+    cmp     bx, 7                       ; check if NULL ptr.
+    jle     ffslz_badselector
+    mov     ax, es
+    cmp     bx, 7                       ; check if NULL ptr.
+    jle     ffslz_badselector
+
+    mov     ds, bx                      ; ds:si -> string
+    mov     ax, di
+    not     ax
+    cmp     ax, cx                      ; crosses segment boundrary...
+    jb      ffslz_invalidptr
+    mov     ax, si
+    not     ax
+    cmp     ax, cx                      ; crosses segment boundrary...
+    jb      ffslz_invalidptr
+
+;    movzx   esi, si
+;    movzx   edi, di
+;    movzx   ecx, cx
+;    db      66h                         ; force it use extended registers.
+    rep movsb
+
+ffslz_retok:
+    xor     ax, ax
+    mov     cx, di
+    sub     cx, dx                      ; cx <- size (end ptr - start ptr)
+    pop     es
+    add     sp, 8
+    clc
+    db      66h
+    retf
+
+ffslz_badselector:
+    mov     ax, ERROR_INVALID_SELECTOR
+    jmp     ffslz_reterr
+
+ffslz_invalidptr:
+    int     3
+    mov     ax, ERROR_INVALID_ACCESS
+    jmp     ffslz_reterr
+
+ffslz_no_term:
+    mov     ax, ERROR_TERMINATOR_NOT_FOUND
+ffslz_reterr:
+    pop     es
+    add     sp, 8
+    stc
+    db      66h
+    retf
+fakef_FuBuff ENDP
+
+
+
+
+CODE16 ENDS
+
+
+
+CODE32 SEGMENT
+;;
+; Fake g_tkExecPgm implementation.
+; @proto     none. (void _Optlink fakeg_tkExecPgm(void);)
+; @returns   same as tkExecPgm: eax, edx and carry flag
+; @param     ax     Exec flag
+;            ds:dx  Filename address. (String)
+;            es:bx  Environment address. (String)
+;            di:si  Argument address. (String)
+; @uses      all - bp
+; @sketch    Copy the filename and arguments into a buffer we
+;            may modify later if this is a UNIX shellscript or
+;            a PE-file started by pe.exe.
+; @status    completely implemented.
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+;
+;
+fakeg_tkExecPgm PROC NEAR
+    push    ebp
+    mov     ebp, esp
+
+    ;
+    ; We just have to make some common code...
+    ;
+    sub     esp, 10h
+    movzx   eax, ax
+    mov     [esp + 00h], eax            ; ExecFlag DWORD
+
+    mov     ax, es
+    SelToFlat
+    mov     [esp + 08h], eax            ; Environment ptr.
+    mov     ecx, eax
+
+    mov     ax, ds
+    mov     bx, dx
+    SelToFlat
+    mov     [esp + 0ch], eax            ; Filename ptr
+
+    mov     ax, di
+    mov     bx, si
+    SelToFlat
+    mov     [esp + 04h], eax            ; Argument ptr
+    mov     edx, eax
+
+    mov     eax, [esp + 00h]            ; ExecFlag DWORD in eax
+
+    mov     bx, seg FLAT:DATA32
+    mov     ds, bx                      ; Make ds flat
+    mov     es, bx                      ; Make es flat
+
+    call    tkExecPgmWorker             ;(ULONG flags, arg,    env,   prog)
+    add     esp, 10                     ;       eax,   edx,    ecx,
+                                        ;     ebp+8, ebp+c, ebp+10, ebp+14
+                                        ;     esp+0, esp+4, esp+08, esp+0c
+
+    leave
+    ret
+fakeg_tkExecPgm ENDP
+
+
+;;
+; Calls the fakeg_tkExecPgm procedure.
+; @cproto   ULONG _Optlink  CalltkExecPgm(
+;                               ULONG   execFlags,
+;                               PCSZ    pArg,
+;                               PCSZ    pEnv,
+;                               PCSZ    pExecName);
+; @returns
+; @param    eax (ebp +08h)  execFlags
+; @param    edx (ebp +0ch)  pArg
+; @param    ecx (ebp +10h)  pEnv
+; @param    ebp + 14h       pExecName
+; @uses     eax, ecx, edx
+; @status   completely implemented.
+; @author   knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+; @remark
+CalltkExecPgm PROC NEAR
+    push    ebp
+    mov     ebp, esp
+    push    ebx
+    push    edi
+    push    esi
+    push    es
+    push    ds
+
+    ; Save parameters
+    mov     [ebp+08h], eax
+
+    ;
+    ; create input for fakeg_tkExecPgm
+    ;
+    mov     eax, edx
+    xor     edi, edi
+    xor     esi, esi
+    or      eax, eax
+    jz      ctkep1
+    FlatToSel
+    mov     di, ax
+    mov     esi, ebx                    ; di:si -> arguments
+ctkep1:
+
+    mov     eax, [ebp + 14h]
+    xor     edx, edx
+    mov     ds, dx
+    or      eax, eax
+    jz      ctkep2
+    FlatToSel
+    mov     ds, ax
+    mov     edx, ebx                    ; ds:dx -> executable filename
+ctkep2:
+
+    mov     eax, ecx
+    xor     ebx, ebx
+    mov     es, bx
+    or      eax, eax
+    jz      ctkep3
+    FlatToSel
+    mov     es, ax
+    mov     eax, ebx                    ; es:bx -> environment.
+ctkep3:
+
+    mov     eax, [ebp+08h]              ; ax = exec flags.
+
+    call    far ptr FLAT:fakeg_tkExecPgm
+
+    ;
+    ; Restore and return.
+    ;
+    pop     ds
+    pop     es
+    pop     esi
+    pop     edi
+    pop     ebx
+    leave
+    ret
+CalltkExecPgm ENDP
+
+
+;;
+; Gets the selector for the CODE16 segment.
+; @cproto   USHORT  _Optlink GetSelectorCODE16(void)
+; @returns  Selector for the CODE16 segment.
+; @uses     eax
+; @status   completely implemented.
+; @author   knut st. osmundsen (knut.stange.osmundsen@mynd.no)
+GetSelectorCODE16 PROC NEAR
+    xor     eax, eax
+    mov     ax, seg CODE16
+    ret
+GetSelectorCODE16 ENDP
+
+
+;;
+; Gets the selector for the DATA16 segment.
+; @cproto   USHORT  _Optlink GetSelectorDATA16(void)
+; @returns  Selector for the DATA16 segment.
+; @uses     eax
+; @status   completely implemented.
+; @author   knut st. osmundsen (knut.stange.osmundsen@mynd.no)
+GetSelectorDATA16 PROC NEAR
+    xor     eax, eax
+    mov     ax, seg DATA16
+    ret
+GetSelectorDATA16 ENDP
+
+
+;;
+; Gets the selector for the CODE32 segment.
+; @cproto   USHORT  _Optlink GetSelectorCODE32(void)
+; @returns  Selector for the CODE32 segment.
+; @uses     eax
+; @status   completely implemented.
+; @author   knut st. osmundsen (knut.stange.osmundsen@mynd.no)
+GetSelectorCODE32 PROC NEAR
+    xor     eax, eax
+    mov     ax, seg FLAT:CODE32
+    ret
+GetSelectorCODE32 ENDP
+
+;;
+; Gets the selector for the DATA32 segment.
+; @cproto   USHORT  _Optlink GetSelectorDATA32(void)
+; @returns  Selector for the DATA32 segment.
+; @uses     eax
+; @status   completely implemented.
+; @author   knut st. osmundsen (knut.stange.osmundsen@mynd.no)
+GetSelectorDATA32 PROC NEAR
+    xor     eax, eax
+    mov     ax, seg FLAT:DATA32
+    ret
+GetSelectorDATA32 ENDP
+
+
+
+CODE32 ENDS
+
+END
Index: trunk/src/win32k/test/init.asm
===================================================================
--- trunk/src/win32k/test/init.asm	(revision 3832)
+++ trunk/src/win32k/test/init.asm	(revision 3832)
@@ -0,0 +1,142 @@
+; $Id: init.asm,v 1.1 2000-07-16 22:18:15 bird Exp $
+;
+; Thunks to call stratgy entry points with init packets.
+;
+; Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+;
+; Project Odin Software License can be found in LICENSE.TXT
+;
+    .386
+
+
+;
+; Include files
+;
+    include devsegdf.inc
+    include os2.inc
+
+
+;
+; Exported symbols
+;
+    public  InitElf
+    public  InitWin32k
+
+
+;
+; extrns
+;
+    extrn   _strategyAsm0:PROC
+    extrn   _strategyAsm1:PROC
+
+CODE32 SEGMENT
+;;
+; Initiates the $elf device driver.
+; @cproto    ULONG _Optlink InitElf(PVOID pvPacket);
+; @returns
+; @param     (ss:)eax    pvPacket
+;                   This parameter is pointer to a stack object which haven't
+;                   had SSToDS() applied. This is done in this way because it
+;                   lightens the job to make a far 16 bits pointer of it.
+; @uses      eax, ecx, edx
+; @sketch
+; @status
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+; @remark
+InitElf PROC NEAR
+    ASSUME ds:FLAT, es:NOTHING, ss:NOTHING
+    push    ebx
+    push    ds
+    push    es
+    ;
+    ; Make 16:16 ptr to packet pointed to by ss:eax
+    ;
+    mov     bx, ss
+    mov     es, bx
+    mov     bx, ax
+
+    ;
+    ; Set ds to DATA16
+    ;
+    mov     ax, seg DATA16
+    mov     ds, ax
+
+    ;
+    ; Call stratgy entry point.
+    ;
+    jmp far ptr CODE16:Thunk16_InitElf
+Thunk32_InitElf::
+    movzx   eax, ax                     ; Cast USHORT to ULONG.
+
+    pop     es
+    pop     ds
+    pop     ebx
+    ret
+InitElf ENDP
+CODE32 ENDS
+
+CODE16 SEGMENT
+    ; Call strategy entry point for $elf.
+Thunk16_InitElf::
+    call    far ptr CODE16:_strategyAsm0
+    jmp far ptr FLAT:Thunk32_InitElf
+CODE16 ENDS
+
+
+
+CODE32 SEGMENT
+;;
+; Initiates the $win32k device driver.
+; @cproto    ULONG _Optlink InitWin32k(PVOID pvPacket);
+; @returns
+; @param     (ss:)eax    pvPacket
+;                   This parameter is pointer to a stack object which haven't
+;                   had SSToDS() applied. This is done in this way because it
+;                   lightens the job to make a far 16 bits pointer of it.
+; @uses      eax, ecx, edx
+; @sketch
+; @status
+; @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+; @remark
+InitWin32k PROC NEAR
+    ASSUME ds:FLAT, es:NOTHING, ss:NOTHING
+    push    ebx
+    push    ds
+    push    es
+    ;
+    ; Make 16:16 ptr to packet pointed to by ss:eax
+    ;
+    mov     bx, ss
+    mov     es, bx
+    mov     bx, ax
+
+    ;
+    ; Set ds to DATA16
+    ;
+    mov     ax, seg DATA16
+    mov     ds, ax
+
+    ;
+    ; Call stratgy entry point.
+    ;
+    jmp far ptr CODE16:Thunk16_InitWin32k
+Thunk32_InitWin32k::
+    movzx   eax, ax                     ; Cast USHORT to ULONG.
+
+    pop     es
+    pop     ds
+    pop     ebx
+    ret
+InitWin32k ENDP
+CODE32 ENDS
+
+CODE16 SEGMENT
+    ; Call strategy entry point for $win32k.
+Thunk16_InitWin32k::
+    call    far ptr CODE16:_strategyAsm1
+    jmp far ptr FLAT:Thunk32_InitWin32k
+
+CODE16 ENDS
+
+
+END
Index: trunk/src/win32k/test/win32ktst.c
===================================================================
--- trunk/src/win32k/test/win32ktst.c	(revision 3832)
+++ trunk/src/win32k/test/win32ktst.c	(revision 3832)
@@ -0,0 +1,684 @@
+/* $Id: win32ktst.c,v 1.1 2000-07-16 22:18:16 bird Exp $
+ *
+ * Win32k test module.
+ *
+ * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#define INCL_BASE
+#define INCL_OS2KRNL_ALL
+#define INCL_SSTODS
+
+#define SEL_FLATMASK        0x01fff0000
+#define SEL_FLAT_SHIFT      0x0d
+#define SEL_LDT_RPL3        0x07
+
+#define SelToFlat(sel, off) \
+    (PVOID)( (((unsigned)(sel) << SEL_FLAT_SHIFT) & SEL_FLAT_MASK) + (unsigned)(off))
+
+#define FlatToSel(flataddr) \
+    (PVOID)( ( (((unsigned)(flataddr) << 3) & 0xfff80000) | (SEL_LDT_RPL3 << 16) ) | ((unsigned)(flataddr) & 0xffff) )
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+#include <os2.h>
+
+#include "malloc.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "options.h"
+#include "dev1632.h"
+#include "dev32.h"
+#include "devcmd.h"
+#include "os2krnl.h"
+#include "ldrCalls.h"
+#include "test.h"
+#include "asmutils.h"
+#include "macros.h"
+#include "log.h"
+
+
+/** @design Win32k Ring-3 Testing
+ * I'll try to make it possible to test parts or all the win32k code in ring-3.
+ * To archive this the interface against the kernel has to be faked/emulated.
+ * More precisely:
+ *      - DevHelps.
+ *      - Worker routines for imported kernel functions. (calltab.asm jumps to them.)
+ *      - 16-bit stack 1Kb.
+ *      - Strategy calls.
+ *      - Fake module loadings (= testcases).
+ *      - ?
+ *
+ * Some of the initstuff has to be omitted, at least in the start. The first
+ * goal is to be able to test _ldrOpenPath and _ldrOpen.
+ *
+ *
+ * @subsection  Device Helper Routines
+ *
+ * These I think we'll implemented by providing the kernel interface, a far 16:16
+ * pointer to a dh-router. Our router will in most cases thunk back to 32-bit
+ * code and implementet the required devhelp routines in pure C code.
+ *
+ * These are the needed routines:
+ *      - DevHelp_VirtToLin   - ok
+ *      - DevHelp_VMAlloc     - ok
+ *      - DevHelp_VMFree      - ok
+ *      - DevHelp_GetDOSVar   - ok
+ *      - DevHelp_VMLock
+ *      - DevHelp_VMUnLock  ?
+ *      - DevHelp_VMSetMem  ?
+ *      - DevHelp_Yield     ?
+ *
+ *
+ * @subsection  Worker routines for imported kernel functions
+ *
+ * Create worker routines for the imported kernel functions. Calltab will be
+ * set up to jump to them. This is done in d32init.c, in stead of using
+ * the importtab.
+ *
+ * Some of these workers will be parts of testcases. For example g_tkExecPgm
+ * and _LDRQAppType.
+ *
+ * Only the imported functions are implemented on demand. Initially these
+ * functions will be provided:
+ *      - ldrOpen
+ *      - ldrRead
+ *      - ldrClose
+ *      - ldrOpenPath
+ *      - SftFileSize
+ *
+ *
+ * @subsection  16-bit stack
+ *
+ * To make this test real the stack has to be 16-bit and _very_ small (1KB).
+ * TKSSBase have to be implemented by the DevHelp_GetDOSVar DosTable2 stuff.
+ * The stack will be thunked to 16-bit by a thunking procedure called from
+ * main. This procedure thunks the stack (quite easy, we're in tiled memory!),
+ * set the value of TKSSBase, calls a C function which does all the rest of
+ * the testing. When taht function returns, the stack will be thunked back
+ * to 32-bit, TKSSBase will be zeroed, and the procedure returns to main.
+ *
+ *
+ * @subsection  Straegy routine calls (not implemented)
+ *
+ * We'll call the strategy entry points with init request packets. The initiation
+ * will require a replacement for DosDevIOCtl (16-bit) which calls the
+ * $elf strategy routine. We'll also have to provide fakes for kernel probing,
+ * verifing and overloading in d32init.c.
+ *
+ *
+ * @subsection  Order of events
+ *
+ * This is the order this testing environment currently works:
+ *      1) init devhelp subsystem
+ *      2) init workers
+ *      3) thunk stack
+ *      4) Fake 16-bit init. Set TKSSBase, FlatDS, FlatCS, DevHelp pointer....
+ *      5) Call R0Init32().
+ *         (d32init.c is modified a bit to setup the calltab correctly.)
+ *      6) Start testing...
+ *      7) Testing finished - thunk stack back to 32-bit.
+ */
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+void    syntax(void);
+void    workersinit(void);
+void    initRPInit(RP32INIT *pRpInit, char *pszInitArgs);
+int     tests(int iTest, int argc, char **argv);
+int     TestCase1(void);
+int     TestCase2(void);
+int     TestCase3(void);
+int     TestCase4(void);
+int     TestCase5(void);
+int     CompareOptions(struct options *pOpt);
+int     TestCaseExeLoad1(void);
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+extern BOOL     fInited;                /* malloc.c */
+const char *    pszInternalRevision = "\r\nInternal revision 14.040_W4";
+int             cObjectsFake = 14;
+
+
+
+/**
+ * Main function. Arguments _currently_ unused.
+ */
+int main(int argc, char **argv)
+{
+    int         iTest;
+    int         rc;
+
+    /*
+     * Init devhelp subsystems.
+     */
+    dhinit();
+
+    /*
+     * Parse arguments.
+     * (printf don't work before dhinit is called...)
+     */
+    if (argc < 2 || (iTest = atoi(argv[1])) <= 0)
+    {
+        syntax();
+        printf("syntax error\n");
+        return -1;
+    }
+
+    /*
+     * Init workers if necessary.
+     */
+    workersinit();
+
+
+    /*
+     * Thunk Stack to 16-bits.
+     *
+     * IMPORTANT! From now on SSToDS have to be used when making pointers
+     *            to stack objects.
+     */
+    ThunkStack32To16();
+
+    rc = tests(iTest, argc, argv);
+
+    /*
+     * Thunk Stack back to 32-bits.
+     */
+    ThunkStack16To32();
+
+
+    /*
+     * To avoid a sfree error message we'll set fInited (heap init flag) to false.
+     */
+    fInited = FALSE;
+    return rc;
+}
+
+
+/**
+ * Prints syntax information.
+ * @status  partially implemented.
+ * @author  knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ */
+void    syntax(void)
+{
+    printf(
+        "Win32kTst.exe v%d.%d.%d - Ring 3 testing of win32k.sys\n"
+        "syntax: Win32kTst.exe <testcase number> [optional arguments]\n",
+        0,0,4
+           );
+}
+
+
+/**
+ * Initiate workers (imported kernel functions / vars)
+ * @status    partially implemented.
+ * @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ */
+void  workersinit(void)
+{
+    DosSetMem(&CODE16START, &CODE16END - &CODE16START, PAG_WRITE | PAG_READ);
+    DosSetMem(&CODE32START, &CODE32END - &CODE32START, PAG_WRITE | PAG_READ);
+}
+
+
+/**
+ * Initiates a init reqest packet.
+ * @param   pRpInit         Pointer to request packet to init.
+ * @param   pszInitArgs     Pointer to init arguments.
+ * @status  completely implemented.
+ * @author  knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ */
+void initRPInit(RP32INIT *pRpInit, char *pszInitArgs)
+{
+    /* $elf */
+    memset(pRpInit, 0, sizeof(RP32INIT));
+    pRpInit->rph.Len  = sizeof(RP32INIT);
+    pRpInit->rph.Cmd  = CMDInit;
+    pRpInit->DevHlpEP = getDHRouterFarPtr();
+    pRpInit->InitArgs = (PSZ)FlatToSel(pszInitArgs);
+}
+
+
+/**
+ * Testcase fan-out.
+ * @returns Testcase return value.
+ *          -2 if testcase not found.
+ * @param   iTest   Testcase number.
+ * @param   argc    main argc
+ * @param   argv    main argv
+ * @status  completely implemented.
+ * @author  knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ */
+int tests(int iTest, int argc, char **argv)
+{
+    int     rc;
+
+    printf("-------------------------------- Testcase %d:\n", iTest);
+    switch (iTest)
+    {
+        case 1:     rc = TestCase1();   break;
+        case 2:     rc = TestCase2();   break;
+        case 3:     rc = TestCase3();   break;
+        case 4:     rc = TestCase4();   break;
+        case 5:     rc = TestCase5();   break;
+
+        default:
+            printf("testcase no. %d is not found\n", iTest);
+            rc = -2;
+    }
+    printf("result %d -----------------------------------\n", rc);
+
+    NOREF(argc);
+    NOREF(argv);
+    return rc;
+}
+
+
+
+/**
+ * Test case 1.
+ * Checks that default initiation works fine for Aurora SMP kernels.
+ *
+ * @sketch  Create init packet with no arguments.
+ *          Initiate elf$
+ *          Create init packet with no arguments.
+ *          Initiate win32k$
+ * @returns 0 on success.
+ *          1 on failure.
+ * @status  completely implemented.
+ * @author  knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ */
+int TestCase1(void)
+{
+    int         rc = 1;
+    RP32INIT    rpinit;
+
+    /* init fake variabels */
+    pszInternalRevision ="\r\nInternal revision 14.040_SMP";
+    cObjectsFake = 15;
+    _usFakeVerMajor = 20;
+    _usFakeVerMinor = 45;
+
+    /* $elf */
+    initRPInit(SSToDS(&rpinit), "-w3");
+    rc = InitElf(&rpinit);              /* no SSToDS! */
+    printf("InitElf returned status=0x%04x\n", rpinit.rph.Status);
+    if ((rpinit.rph.Status & (STDON | STERR)) == STDON)
+    {
+        /* $win32k */
+        initRPInit(SSToDS(&rpinit), "-w3");
+        rc = InitWin32k(&rpinit);       /* no SSToDS! */
+        printf("InitWin32k returned status=0x%04x\n", rpinit.rph.Status);
+        if ((rpinit.rph.Status & (STDON | STERR)) == STDON)
+        {
+            struct options opt = DEFAULT_OPTION_ASSIGMENTS;
+            opt.fKernel = KF_SMP;
+            opt.ulBuild = 14040;
+            opt.usVerMajor = 20;
+            opt.usVerMinor = 45;
+            opt.ulInfoLevel = 3;
+
+            rc = CompareOptions(SSToDS(&opt));
+            if (rc == NO_ERROR)
+            {
+                rc = TestCaseExeLoad1();
+            }
+        }
+        else
+            printf("!failed!\n");
+    }
+    else
+        printf("!failed!\n");
+
+    return rc;
+}
+
+
+/**
+ * Test case 2.
+ * Checks that default initiation works fine for Aurora UNI kernels.
+ *
+ * @sketch  Create init packet with no arguments.
+ *          Initiate elf$
+ *          Create init packet with no arguments.
+ *          Initiate win32k$
+ * @returns 0 on success.
+ *          1 on failure.
+ * @status  completely implemented.
+ * @author  knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ */
+int TestCase2(void)
+{
+    int         rc = 1;
+    RP32INIT    rpinit;
+
+    /* init fake variabels */
+    pszInternalRevision ="\r\nInternal revision 14.040_UNI";
+    cObjectsFake = 14;
+    _usFakeVerMajor = 20;
+    _usFakeVerMinor = 45;
+
+    /* $elf */
+    initRPInit(SSToDS(&rpinit), "");
+    rc = InitElf(&rpinit);              /* no SSToDS! */
+    printf("InitElf returned status=0x%04x\n", rpinit.rph.Status);
+    if ((rpinit.rph.Status & (STDON | STERR)) == STDON)
+    {
+        /* $win32k */
+        initRPInit(SSToDS(&rpinit), "");
+        rc = InitWin32k(&rpinit);       /* no SSToDS! */
+        printf("InitWin32k returned status=0x%04x\n", rpinit.rph.Status);
+        if ((rpinit.rph.Status & (STDON | STERR)) == STDON)
+        {
+            struct options opt = DEFAULT_OPTION_ASSIGMENTS;
+            opt.fKernel = KF_UNI;
+            opt.ulBuild = 14040;
+            opt.usVerMajor = 20;
+            opt.usVerMinor = 45;
+
+            rc = CompareOptions(SSToDS(&opt));
+        }
+        else
+            printf("!failed!\n");
+    }
+    else
+        printf("!failed!\n");
+
+    return rc;
+}
+
+
+/**
+ * Test case 3.
+ * Checks that default initiation works fine for Warp FP13 kernel.
+ *
+ * @sketch  Create init packet with no arguments.
+ *          Initiate elf$
+ *          Create init packet with no arguments.
+ *          Initiate win32k$
+ * @returns 0 on success.
+ *          1 on failure.
+ * @status  completely implemented.
+ * @author  knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ */
+int TestCase3(void)
+{
+    int         rc = 1;
+    RP32INIT    rpinit;
+
+    /* init fake variabels */
+    pszInternalRevision ="\r\nInternal revision 14.040_W4";
+    cObjectsFake = 14;
+    _usFakeVerMajor = 20;
+    _usFakeVerMinor = 45;
+
+    /* $elf */
+    initRPInit(SSToDS(&rpinit), "");
+    rc = InitElf(&rpinit);              /* no SSToDS! */
+    printf("InitElf returned status=0x%04x\n", rpinit.rph.Status);
+    if ((rpinit.rph.Status & (STDON | STERR)) == STDON)
+    {
+        /* $win32k */
+        initRPInit(SSToDS(&rpinit), "");
+        rc = InitWin32k(&rpinit);       /* no SSToDS! */
+        printf("InitWin32k returned status=0x%04x\n", rpinit.rph.Status);
+        if ((rpinit.rph.Status & (STDON | STERR)) == STDON)
+        {
+            struct options opt = DEFAULT_OPTION_ASSIGMENTS;
+            opt.fKernel = KF_UNI | KF_W4;
+            opt.ulBuild = 14040;
+            opt.usVerMajor = 20;
+            opt.usVerMinor = 45;
+
+            rc = CompareOptions(SSToDS(&opt));
+        }
+        else
+            printf("!failed!\n");
+    }
+    else
+        printf("!failed!\n");
+
+    return rc;
+}
+
+
+/**
+ * Test case 4.
+ * Checks that default initiation works fine for Aurora SMP kernels.
+ *
+ * @sketch  Create init packet with no arguments.
+ *          Initiate elf$
+ *          Create init packet with no arguments.
+ *          Initiate win32k$
+ * @returns 0 on success.
+ *          1 on failure.
+ * @status  completely implemented.
+ * @author  knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ */
+int TestCase4(void)
+{
+    int         rc = 1;
+    RP32INIT    rpinit;
+
+    /* init fake variabels */
+    pszInternalRevision ="\r\nInternal revision 9.036";
+    cObjectsFake = 14;
+    _usFakeVerMajor = 20;
+    _usFakeVerMinor = 40;
+
+    /* $elf */
+    initRPInit(SSToDS(&rpinit), "");
+    rc = InitElf(&rpinit);              /* no SSToDS! */
+    printf("InitElf returned status=0x%04x\n", rpinit.rph.Status);
+    if ((rpinit.rph.Status & (STDON | STERR)) == STDON)
+    {
+        /* $win32k */
+        initRPInit(SSToDS(&rpinit), "");
+        rc = InitWin32k(&rpinit);       /* no SSToDS! */
+        printf("InitWin32k returned status=0x%04x\n", rpinit.rph.Status);
+        if ((rpinit.rph.Status & (STDON | STERR)) == STDON)
+        {
+            struct options opt = DEFAULT_OPTION_ASSIGMENTS;
+            opt.fKernel     = KF_UNI;
+            opt.ulBuild     = 9036;
+            opt.usVerMajor  = 20;
+            opt.usVerMinor  = 40;
+
+            rc = CompareOptions(SSToDS(&opt));
+        }
+        else
+            printf("!failed!\n");
+    }
+    else
+        printf("!failed!\n");
+
+    return rc;
+}
+
+
+/**
+ * Test case 5.
+ * Checks that all parameters are read correctly (1) (Warp FP13 kernel).
+ *
+ * @sketch  Create init packet with no arguments.
+ *          Initiate elf$
+ *          Create init packet with no arguments.
+ *          Initiate win32k$
+ * @returns 0 on success.
+ *          1 on failure.
+ * @status  completely implemented.
+ * @author  knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ */
+int TestCase5(void)
+{
+    int         rc = 1;
+    RP32INIT    rpinit;
+    char *      pszInitArgs = "-C1 -L:N -Verbose -Quiet -Elf:Yes -Pe:Mixed -Script:No -W4 -Heap:512000 -ResHeap:0256000 -HeapMax:4096000 -ResHeapMax:0x100000";
+
+    /* init fake variabels */
+    pszInternalRevision ="\r\nInternal revision 14.040_W4";
+    cObjectsFake = 14;
+    _usFakeVerMajor = 20;
+    _usFakeVerMinor = 45;
+
+    /* $elf */
+    initRPInit(SSToDS(&rpinit), pszInitArgs);
+    rc = InitElf(&rpinit);              /* no SSToDS! */
+    printf("InitElf returned status=0x%04x\n", rpinit.rph.Status);
+    if ((rpinit.rph.Status & (STDON | STERR)) == STDON)
+    {
+        /* $win32k */
+        initRPInit(SSToDS(&rpinit), pszInitArgs);
+        rc = InitWin32k(&rpinit);       /* no SSToDS! */
+        printf("InitWin32k returned status=0x%04x\n", rpinit.rph.Status);
+        if ((rpinit.rph.Status & (STDON | STERR)) == STDON)
+        {
+            struct options opt = DEFAULT_OPTION_ASSIGMENTS;
+            opt.fKernel         = KF_UNI | KF_W4;
+            opt.ulBuild         = 14040;
+            opt.usVerMajor      = 20;
+            opt.usVerMinor      = 45;
+            opt.cbSwpHeapInit   = 512000;
+            opt.cbSwpHeapMax    = 4096000;
+            opt.cbResHeapInit   = 0256000;
+            opt.cbResHeapMax    = 0x100000;
+            opt.fElf            = TRUE;
+            opt.fUNIXScript     = FALSE;
+            opt.fPE             = FLAGS_PE_MIXED;
+            opt.fQuiet          = TRUE;
+            opt.fLogging        = FALSE;
+            opt.usCom           = OUTPUT_COM1;
+            opt.ulInfoLevel     = INFOLEVEL_INFOALL;
+
+            rc = CompareOptions(SSToDS(&opt));
+        }
+        else
+            printf("!failed!\n");
+    }
+    else
+        printf("!failed!\n");
+
+    return rc;
+}
+
+/**
+ * Compares the options with the option struct passed in.
+ * @returns 0 on success.
+ *          number of mismatches on error.
+ * @param   pOpt
+ * @status  completely implemented.
+ * @author  knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ */
+int CompareOptions(struct options *pOpt)
+{
+    int rc = 0;
+    /*
+     *  Check that the option struct is correct.
+     */
+    if (options.fQuiet != pOpt->fQuiet)
+        printf("fQuiet = %d - should be %d\n", options.fQuiet, pOpt->fQuiet, rc++);
+    if (options.usCom != pOpt->usCom)
+        printf("usCom = %d - should be %d\n", options.usCom, pOpt->usCom, rc++);
+    if (options.fLogging != pOpt->fLogging)
+        printf("fLogging = %d - should be %d\n", options.fLogging, pOpt->fLogging, rc++);
+    if (options.fKernel != pOpt->fKernel)
+        printf("fKernel = %d - should be %d\n", options.fKernel, pOpt->fKernel, rc++);
+    if (options.ulBuild != pOpt->ulBuild)
+        printf("ulBuild = %d - should be %d\n", options.ulBuild, pOpt->ulBuild, rc++);
+    if (options.usVerMajor != pOpt->usVerMajor)
+        printf("usVerMajor = %d - should be %d\n", options.usVerMajor, pOpt->usVerMajor, rc++);
+    if (options.usVerMinor != pOpt->usVerMinor)
+        printf("usVerMinor = %d - should be %d\n", options.usVerMinor, pOpt->usVerMinor, rc++);
+    if (options.fPE != pOpt->fPE)
+        printf("fPE = %d - should be %d\n", options.fPE, pOpt->fPE, rc++);
+    if (options.ulInfoLevel != pOpt->ulInfoLevel)
+        printf("ulInfoLevel = %d - should be %d\n", options.ulInfoLevel, pOpt->ulInfoLevel, rc++);
+    if (options.fElf != pOpt->fElf)
+        printf("fElf = %d - should be %d\n", options.fElf, pOpt->fElf, rc++);
+    if (options.fUNIXScript != pOpt->fUNIXScript)
+        printf("fUNIXScript = %d - should be %d\n", options.fUNIXScript, pOpt->fUNIXScript, rc++);
+    if (options.fREXXScript != pOpt->fREXXScript)
+        printf("fREXXScript = %d - should be %d\n", options.fREXXScript, pOpt->fREXXScript, rc++);
+    if (options.fJava != pOpt->fJava)
+        printf("fJava = %d - should be %d\n", options.fJava, pOpt->fJava, rc++);
+    if (options.fNoLoader != pOpt->fNoLoader)
+        printf("fNoLoader = %d - should be %d\n", options.fNoLoader, pOpt->fNoLoader, rc++);
+    if (options.cbSwpHeapInit != pOpt->cbSwpHeapInit)
+        printf("cbSwpHeapInit = %d - should be %d\n", options.cbSwpHeapInit, pOpt->cbSwpHeapInit, rc++);
+    if (options.cbSwpHeapMax != pOpt->cbSwpHeapMax)
+        printf("cbSwpHeapMax = %d - should be %d\n", options.cbSwpHeapMax, pOpt->cbSwpHeapMax, rc++);
+    if (options.cbResHeapInit != pOpt->cbResHeapInit)
+        printf("cbResHeapInit = %d - should be %d\n", options.cbResHeapInit, pOpt->cbResHeapInit, rc++);
+    if (options.cbResHeapMax != pOpt->cbResHeapMax)
+        printf("cbResHeapMax = %d - should be %d\n", options.cbResHeapMax, pOpt->cbResHeapMax, rc++);
+
+    return rc;
+}
+
+
+
+
+/**
+ * Simulates a executable loading (no errors).
+ * This test requires a PE executable file named ExecLoad1.exe which
+ * imports the dll ExecLoad1d.dll.
+ *
+ * @returns 0 on success.
+ *          > 0 on failure.
+ * @sketch
+ * @status
+ * @author    knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ * @remark
+ */
+int TestCaseExeLoad1(void)
+{
+    APIRET rc;
+
+    /*
+     * Set global parameters... FIXME.
+     */
+
+    /*
+     * Do the real execution.
+     */
+    printf("--- TestcaseExeLoad1 - loading win32ktst.exe (LX image) ----\n");
+    rc = CalltkExecPgm(EXEC_LOAD, NULL, NULL, "win32ktst.exe");
+    if (rc == NO_ERROR)
+    {
+        printf("--- TestcaseExeLoad1 - loading libconv.exe (LX image) ----\n");
+        rc = CalltkExecPgm(EXEC_LOAD, NULL, NULL, "bin\\debug\\libconv.exe");
+    }
+
+    if (rc == NO_ERROR)
+    {
+        printf("--- TestcaseExeLoad1 - loading rexx\\tst.cmd (REXX script) ----\n");
+        rc = CalltkExecPgm(EXEC_LOAD, NULL, NULL, "rexx\\tst.cmd");
+    }
+
+    if (rc == NO_ERROR)
+    {
+        printf("--- TestcaseExeLoad1 - loading SOL.EXE (PE image) ----\n");
+        rc = CalltkExecPgm(EXEC_LOAD, NULL, NULL, "e:\\Win32Prog\\Sol\\Sol.exe");
+    }
+
+    /*
+     * The test is successful if rc == NO_ERROR (== 0).
+     */
+    return rc;
+}
Index: trunk/src/win32k/win32ktst.def
===================================================================
--- trunk/src/win32k/win32ktst.def	(revision 3832)
+++ trunk/src/win32k/win32ktst.def	(revision 3832)
@@ -0,0 +1,35 @@
+;******************************************************************************
+; Copyright 1998-2000 knut st. osmundsen
+; Definition file for Win32k
+; Project Odin Software License can be found in LICENSE.TXT
+;******************************************************************************
+NAME Grace WINDOWCOMPAT
+DESCRIPTION "$@#knut st. osmundsen:v0.5.0alpha#@Grace - Odin32 and OS2NIX Ring-0 part - Copyright (c) 1998-2000 knut st. osmundsen"
+
+STACKSIZE 4096
+;CODE PRELOAD EXECUTEREAD
+;DATA PRELOAD
+
+SEGMENTS
+    DATA16          class 'FAR_DATA'
+    DATA16_BSS      class 'FAR_DATA'
+    DATA16_CONST    class 'FAR_DATA'
+    CODE16          class 'CODE'
+    CODE32          class 'CODE'
+    CALLTAB         class 'DATA'
+    DATA32          class 'DATA'
+    c_common        class 'DATA'
+    DDE4_DATA32     class 'DATA'
+    CTOR_DTOR1      class 'DATA'
+    CTOR_DTOR2      class 'DATA'
+    CTOR_DTOR3      class 'DATA'
+    _VFT            class 'CONST'
+    CONST32_RO      class 'CONST'
+    EH_DATA         class 'CONST'
+    BSS32           class 'BSS'
+
+IMPORTS
+     _DosWrite        = DOSCALL1.282
+     _DOS16OPEN       = DOSCALL1.70
+     _DOS16CLOSE      = DOSCALL1.59
+
