/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Lexmark Corporation, 1989                                   */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = PRDGHEAP
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   prdg_CreateHeap
 *             prdg_DeleteHeap
 *             prdg_AllocHeapItem
 *             prdg_FreeHeapItem
 *             prdg_AllocGlobalHeapItem
 *             prdg_FreeGlobalHeapItem
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define INCL_32                   /* CON3201 */
#define INCL_DOSPROCESS           /* CON3201 */
#define INCL_DOSSEMAPHORES        /* CON3201 */
#define INCL_DOSMEMMGR            /* CON3201 */
#define INCL_GPIERRORS
#define INCL_GPIPRIMITIVES
#define INCL_WINHEAP
#define INCL_GPIBITMAPS
#define INCL_DOSMEMMGR
#include <os2.h>
#undef INCL_DOSPROCESS            /* CON3201 */
#undef INCL_DOSSEMAPHORES         /* CON3201 */
#undef INCL_DOSMEMMGR             /* CON3201 */
#undef INCL_GPIERRORS
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS
#undef INCL_DOSMEMMGR

#define INCL_DDIBUNDLES
#define INCL_DDIFONTSTRUCS
#define INCL_DDIDEFS
#include <pmddi.h>
#undef INCL_DDIBUNDLES
#undef INCL_DDIFONTSTRUCS
#undef INCL_DDIDEFS

#define INCL_WINP_SELECTIVE
#define INCL_WINP_SEI
/* #define INCL_WINP_MISC         CON3201 */
/* #define INCL_WINP_SELSERVER    CON3201 */
#include <pmwinx.h>
#undef INCL_WINP_SELECTIVE
#undef INCL_WINP_SEI
#undef INCL_32                    /* CON3201 */
/* #undef INCL_WINP_MISC          CON3201 */
/* #undef INCL_WINP_SELSERVER     CON3201 */

#include <prdconse.h>
#include <prdecone.h>
#include <prdgcone.h>

#define PRDMTYPE_INCL
#define NO_CONSTANT_INCL
#include <prdinclt.h>
#undef NO_CONSTANT_INCL
#undef PRDMTYPE_INCL


#include <prdeextf.h>
#include <prdgextf.h>
#ifdef PRD_DEBUG
#include <prdyextf.h>
#endif

/* CON3201
**extern SHORT   GlobalHeapSegCount;
**extern SHORT   LoadingProcId;
**extern HHEAP    GlobalHeapArray [10];
**extern SHORT   GlobalSelectorArray [10];
*/

/**********************************************************************/
/* Set up external accesses.                                          */
/**********************************************************************/
/* CON3201
**extern HHEAP                HeapHandle;
**extern SHORT               HeapSelector;
**extern PFSRSEM              lpGlobalHeapSem;
*/

/* CON3201 many of the Global variable are defined in PRDDATA.C */
extern USHORT     GlobalHeapSegCount;      /* CON3201 */
extern PBYTE      GlobalHeapArray [10];    /* CON3201 */
extern PBYTE      pbGlobalHeap;            /* CON3201 */
extern HMTX       hmtxGlobalHeapSem;       /* CON3201 */

/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdg_CreateHeap                                        */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   HHEAP far      *lpHeapHandle;     Pointer to heap handle         */
/*   PSHORT         lpHeapSelector;   Pointer to heap selector       */
/*   SHORT          ShareOption;      Share option for heap          */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function acquires a DOS segment and initialises it as a     */
/*   Winthorn Heap.                                                   */
/*                                                                    */
/**********************************************************************/

SHORT prdg_CreateHeap (PPVOID Heap)

{
#define TFUNC "prdg_CreateHeap"
    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/


   ULONG      DosResult;         /* The result of a Dos call        */
   PBYTE      pvLocalHeap;

    TRACE6(TFUNC, "Entry", FNULL, 0);
    /******************************************************************/
    /* Create a DOS segment for use as a Winthorn Heap.               */
    /* If no segment acquired, return null values and error.          */
    /* Note that local values are used throughout, so that the real   */
    /* values (via the parameters) are not partially updated.         */
    /******************************************************************/


    DosResult = DosAllocMem ((PPVOID)&pvLocalHeap, WIN_HEAP_SIZE, PAG_EXECUTE |
                                  PAG_COMMIT | PAG_READ | PAG_WRITE );
    if (DosResult != DOS_OK)
    {
        LOGDOSERR(TFUNC, "DosAllocMem Error",
                                              &DosResult, 1, DosResult);
        return(ERROR_NEG);
    }
    TRACE6(TFUNC, "SSAllocMem Heap", pvLocalHeap,1);

    /******************************************************************/
    /* Got the memory, now initialise the heap.                       */
    /* If heap has not been initialised, need to free the already     */
    /* acquired DOS segment before returning null values and error.   */
    /******************************************************************/
    DosResult = DosSubSetMem((PVOID) pvLocalHeap, DOSSUB_INIT,
                                   WIN_HEAP_SIZE);
    if (DosResult)
    {
        TRACE6(TFUNC, "Free DOS seg", pvLocalHeap, 1);
        (void)SSFREEMEM(pvLocalHeap);
        return(ERROR_NEG);
    }

    /******************************************************************/
    /* Successfully allocated a DOS segment for the Heap, and         */
    /* initialised it (via Winthorn). Copy local values into params   */
    /* and return.                                                    */
    /******************************************************************/
    *Heap = pvLocalHeap;
    TRACE6(TFUNC, "HEAP", Heap, 1);
    TRACE6(TFUNC, "Exit OK", FNULL, 0);

#ifdef DEBUG_HEAP
    OutputValueLen( (ULONG)(*(PUSHORT)pvLocalHeap) , 16, 4 );
    OutputPrompt("Create Heap: return OK");
#endif

    return (OK);
}
#undef TFUNC




/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdg_DeleteHeap                                        */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   SHORT   HeapSelector;  The selector for printer driver's heap   */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function deletes the heap in the segment specified by       */
/*   HeapSelector.                                                    */
/*                                                                    */
/**********************************************************************/

SHORT prdg_DeleteHeap ( PVOID Heap )

{
#define TFUNC "prdg_DeleteHeap"
    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
     ULONG    DosResult;       /* Result of Dos call to free segment  */

    TRACE6(TFUNC, "Entry", FNULL, 0);
    TRACE6(TFUNC, "Heap", Heap, 1);

#ifdef DEBUG_HEAP
    OutputValueLen( (ULONG)Heap, 16, 4 );
#endif
    /******************************************************************/
    /* CON3201 First have to Unset the memory, before we free memory  */
    /******************************************************************/
    DosResult = DosSubUnsetMem(Heap);                             /* CON3201 */
    if (DosResult != DOS_OK)                                      /* CON3201 */
    {                                                             /* CON3201 */
        LOGDOSERR(TFUNC, "DosSubUnsetMem Failed", &DosResult, 0,  /* CON3201 */
                                                      DosResult); /* CON3201 */
        return(ERROR_NEG);                                        /* CON3201 */
    }

    /******************************************************************/
    /* Free the segment.                                              */
    /******************************************************************/
    DosResult = DosFreeMem(Heap);
    if (DosResult != DOS_OK)
    {
        LOGDOSERR(TFUNC, "DosFreeMem Failed", &DosResult, 0,
                                                             DosResult);
        return(ERROR_NEG);
    }

#ifdef DEBUG_HEAP
    OutputPrompt("    Delete Heap: return OK");
#endif

    TRACE6(TFUNC, "Exit OK", FNULL, 0);
    return (OK);
}
#undef TFUNC





/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdg_AllocHeapItem                                     */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   lpDCI           DCIData;      Pointer to DC Instance Data        */
/*   SHORT          ItemSize;     Amount of storage required for     */
/*                                 item                               */
/*   PSHORT         ItemPointer;  Returned as pointer to space       */
/*                                 allocated or as NULL if allocation */
/*                                 fails                              */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function allocates space from the heap specified by the     */
/*   HeapSelector and returns a pointer to the space allocated.  If   */
/*   the allocation is unsuccessful then the pointer is returned as   */
/*   NULL and the function returns NO_HEAP_LEFT.                      */
/*                                                                    */
/**********************************************************************/

SHORT prdg_AllocHeapItem ( lpDCI DCIData, USHORT ItemSize,
                                         PUSHORT *ItemPointer )
{
#define TFUNC "prdg_AllocHeapItem"
    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/

    ULONG       DosResult;
    PVOID       pvLocalHeap;
    PVOID       pvItem;
    HeapListType *HeapEntryPtr;
    /******************************************************************/
    /* Try and get the memory from the current heap.                  */
    /******************************************************************/
    TRACE6(TFUNC,"Alloc: size",&ItemSize,1);
    TRACE6(TFUNC,"Alloc: Ptr",&ItemPointer,1);

    DosResult = DosSubAllocMem (DCIData->DCICurrHeap, &pvItem, (ULONG)ItemSize);
    TRACE6(TFUNC, "DosSubAlloc return", DosResult, 1);


    /******************************************************************/
    /* If the allocate attempt failed, then we need to try and get a  */
    /* new heap.                                                      */
    /******************************************************************/
    if (DosResult)
    {
       TRACE6(TFUNC, "Create a new DC Heap", FNULL, 0);
       if (prdg_CreateHeap(&pvLocalHeap) != OK)
       {
           /***********************************************************/
           /* Error already logged by CreateHeap function so just exit*/
           /***********************************************************/
           TRACE6(TFUNC, "create heap failed", FNULL, 0);
           ItemPointer = FNULL;
           return(ERROR_ZERO);
       };

       /***************************************************************/
       /* Chain in the new heap to the end of the heap list and make  */
       /* it the new current heap.                                    */
       /***************************************************************/
       HeapEntryPtr = &(DCIData->DCIHeapList);
       while ((*HeapEntryPtr).Next != FNULL)
       {
           HeapEntryPtr = (*HeapEntryPtr).Next;
       };

       /***************************************************************/
       /* Try and allocate space for the new heap list entry          */
       /***************************************************************/
       DosResult = DosSubAllocMem (pvLocalHeap, &pvItem, sizeof(HeapListType));
       TRACE6(TFUNC, "DosSubAlloc return", &pvItem, 1);
       TRACE6(TFUNC, "DosSUbAlloc return", pvLocalHeap, 1);

       /***************************************************************/
       /* if fails then return an error                               */
       /***************************************************************/
       if (DosResult)
       {
           TRACE6(TFUNC, "Failed to Alloc", &pvItem, 1);
           ItemPointer = FNULL;
           return (ERROR_ZERO);
       };

       /***************************************************************/
       /* Chain in the new entry. TempPtr is a pointer to the 'Next'  */
       /* field of the last entry in the heap list (pointed to by     */
       /* HeapEntryPtr)                                               */
       /***************************************************************/
       /***************************************************************/
       /* Initialise the fields in the new entry. Note that the 'Next'*/
       /* field is now a pointer to the new entry.                    */
       /***************************************************************/
       HeapEntryPtr->Next = pvItem;
       HeapEntryPtr->Next->pbHLEHeap = pvLocalHeap;
       HeapEntryPtr->Next->Next = FNULL;

       DCIData->DCICurrHeap = pvLocalHeap;

       /***************************************************************/
       /* Try and allocate the required space for the original request*/
       /***************************************************************/
       DosResult = DosSubAllocMem (pvLocalHeap, &pvItem, (ULONG)ItemSize);
       TRACE6(TFUNC, "DosSubAlloc return", &pvItem, 1);
       TRACE6(TFUNC, "DosSubAlloc return", pvLocalHeap, 1);

       /***************************************************************/
       /* if fails then return an error                               */
       /***************************************************************/

       if (DosResult)
       {
           TRACE6(TFUNC, "Failed to Alloc", &pvItem, 1);
           ItemPointer = FNULL;
           return (ERROR_ZERO);
       };
    };

    /******************************************************************/
    /* Fill in address of new Item.                                   */
    /******************************************************************/
    *ItemPointer = (PUSHORT)pvItem;

#ifdef DEBUG_HEAP
    OutputValueLen( (ULONG)ItemPointer, 16, 4 );
    OutputStringNoCRLF( " ,Size : " );
    OutputValueLen( (ULONG)ItemSize, 16, 4 );
    OutputString( " - AllocHeapItem OK" );
#endif

    TRACE6(TFUNC, "Address of Item", ItemPointer, 1);
    TRACE6(TFUNC, "Exit OK", FNULL, 0);
    return (OK);
}
#undef TFUNC





/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdg_FreeHeapItem                                      */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   lpDCI           DCIData;      DC Instance data pointer           */
/*   SHORT          ItemSize;     Size of item to remove             */
/*   PSHORT         ItemPointer;  Pointer to item to remove          */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function frees the space previously allocated to the item   */
/*   specified by ItemPointer. It uses the selector of ItemPointer    */
/*   to determine the heap from which the item came by scanning the   */
/*   heap list.                                                       */
/*                                                                    */
/**********************************************************************/

void  prdg_FreeHeapItem (lpDCI       DCIData,
                         USHORT      ItemSize,
                         PUSHORT     ItemPointer)

{
#define TFUNC "prdg_FreeHeapItem"
    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/

    HeapListType  *    HeapEntryPtr;
    PUSHORT            pusItem;              /* CON3201 */
    PBYTE             pbHeap;              /* CON3201 */

    TRACE8(TFUNC, "Entry", FNULL, 0);
    TRACE8(TFUNC, "Item Size", &ItemSize, 1);
    TRACE8(TFUNC, "Item Pointer", ItemPointer, 1);

#ifdef DEBUG_HEAP
    OutputValueLen( (ULONG)ItemPointer, 16, 4 );
    OutputStringNoCRLF( " ,Size : " );
    OutputValueLen( (ULONG)ItemSize, 16, 4 );
    OutputString( " - FreeHeapItem OK" );
#endif

    /******************************************************************/
    /* Free the Item if its size is non zero                          */
    /******************************************************************/
    if (ItemSize)
    {
        /**************************************************************/
        /* Get the selector of the item we're about to free           */
        /**************************************************************/
        pusItem = ItemPointer;
        /**************************************************************/
        /* Check if its the current heap (since in most cases it will */
        /* be)                                                        */
        /**************************************************************/
        /*************************************************************/
        /* CON3201 - We will do pointer math to find what heap the   */
        /*           the item was allocated from.  We know that it   */
        /*           fall in the address range of pbHeap +           */
        /*           WIN_HEAP_SIZE.  So we will go through the heap  */
        /*           and this address range for the item             */
        /*************************************************************/

        if ((pusItem >=  (PUSHORT)DCIData->DCICurrHeap) &&
            (pusItem < (PUSHORT)(DCIData->DCICurrHeap + WIN_HEAP_SIZE)))
        {
            pbHeap = DCIData->DCICurrHeap;
        }
        else
        {
            /**********************************************************/
            /* Have to scan the heap list till we find the required   */
            /* selector and then use that heap handle                 */
            /**********************************************************/
            HeapEntryPtr = &DCIData->DCIHeapList;


            while (!((pusItem >= (PUSHORT)HeapEntryPtr->pbHLEHeap) &&
                (pusItem < (PUSHORT)(HeapEntryPtr->pbHLEHeap + WIN_HEAP_SIZE))))
            {
                HeapEntryPtr = (*HeapEntryPtr).Next;

#ifdef PRD_DEBUG
                /******************************************************/
                /* Firewall to catch the place when the selector is   */
                /* not found.                                         */
                /******************************************************/
                if (!HeapEntryPtr)
                {
                    haltproc();
                    goto FAST_EXIT;
                }
#endif
            }

            pbHeap = (*HeapEntryPtr).pbHLEHeap;
        }

        /**************************************************************/
        /* Can now free the item                                      */
        /**************************************************************/
        TRACE6(TFUNC, "pbHeap", pbHeap, 1);
        TRACE6(TFUNC, "Item Size", &ItemSize, 1);
        TRACE6(TFUNC, "Item Pointer", ItemPointer, 1);


        DosSubFreeMem((PVOID)pbHeap, (PVOID)pusItem, ItemSize);


    }

FAST_EXIT:
    TRACE6(TFUNC, "Exit OK", FNULL, 0);
    return;
}
#undef TFUNC





/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdg_AllocGlobalHeapItem                               */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   SHORT          ItemSize;     Amount of storage required for     */
/*                                 item                               */
/*   PSHORT         ItemPointer;  Returned as pointer to space       */
/*                                 allocated or as NULL if allocation */
/*                                 fails                              */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function allocates space from the printer driver's global   */
/*   heap and returns a pointer to the space allocated.  If the       */
/*   allocation is unsuccessful then the pointer is returned as NULL  */
/*   and the function returns NO_HEAP_LEFT.  This function must       */
/*   obtain the global heap semaphore before it can allocate space    */
/*   for the item.                                                    */
/*                                                                    */
/**********************************************************************/

SHORT prdg_AllocGlobalHeapItem ( USHORT ItemSize, PBYTE * lpItemPointer)
{
#define TFUNC "prdg_AllcGloblHI"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/

    PUSHORT       pvItem;      /* CON3201 */
    PVOID         CurHeap;     /* CON3201 */
    ULONG         DosResult;   /* CON3201 */


    /******************************************************************/
    /* First get the semaphore.                                       */
    /******************************************************************/
    (void) prdg_RequestSemaphore( hmtxGlobalHeapSem, 0);

    CurHeap = pbGlobalHeap;

    DosResult = DosSubAllocMem(CurHeap, (PVOID)&pvItem, (ULONG)ItemSize+2);

    if (DosResult)
    {
        TRACE6(TFUNC, "Failed to Alloc", DosResult, 1);
#ifdef DEBUG_HEAP
    OutputPrompt("AllocGLOBAL fails");
#endif
        *lpItemPointer = (PBYTE)NULL;
        return (ERROR_ZERO);
     }
    /******************************************************************/
    /* Fill in address of new Item.                                   */
    /******************************************************************/
    *pvItem = ItemSize+2;
    pvItem++;
    *lpItemPointer = (PBYTE)pvItem;

#ifdef DEBUG_HEAP
    OutputValueLen( (ULONG)*lpItemPointer, 16, 8 );
    OutputStringNoCRLF( " ,Size : " );
    OutputValueLen( (ULONG)ItemSize, 16, 4 );
    OutputString( " - AllocGLOBAL" );
#endif

    TRACE8(TFUNC, "ALLOC:Heap ", CurHeap, 1);
    TRACE8(TFUNC, "ALLOC:Address of Item", lpItemPointer, 1);
    TRACE8(TFUNC, "ALLOC:Item size", &ItemSize, 1);

    /******************************************************************/
    /* Clear the semaphore.                                           */
    /******************************************************************/
    (void) prdg_ClearSemaphore(hmtxGlobalHeapSem);

    /******************************************************************/
    /* And return OK                                                  */
    /******************************************************************/
    return(OK);
}
#undef TFUNC





/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdg_FreeGlobalHeapItem                                */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   SHORT          ItemSize;     Size of item to remove             */
/*   PSHORT         ItemPointer;  Pointer to item to remove          */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function frees the space previously allocated to the item   */
/*   specified by ItemPointer in the heap specified by HeapHandle.    */
/*                                                                    */
/**********************************************************************/

void prdg_FreeGlobalHeapItem ( USHORT ItemSize, PUSHORT *ItemPointer)
{
#define TFUNC "prdg_FreeGlobalHeapItem"
    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    USHORT         i;          /* loop control variable               */
    PUSHORT        pbItem;     /* actual pointer to data being freed  */
    ULONG          DosResult;  /* CON3201 result of doscall           */
    ItemSize  = 0;

#ifdef DEBUG_HEAP
    OutputValueLen( (ULONG)*((PULONG)ItemPointer), 16, 8 );
    OutputStringNoCRLF( " ,Size : " );
    OutputValueLen( (ULONG)ItemSize, 16, 4 );
    OutputString( " - FreeGLOBAL" );
#endif
    pbItem = (PUSHORT) *ItemPointer;
    pbItem--;
    /******************************************************************/
    /* First get the semaphore.                                       */
    /******************************************************************/
    (void) prdg_RequestSemaphore( hmtxGlobalHeapSem, 0);
    if (pbItem)
        ItemSize = *pbItem;
    if (ItemSize)
    {
        DosResult = DosSubFreeMem(pbGlobalHeap, (PVOID)pbItem,
                                                             ItemSize);
        *ItemPointer = FNULL;
    }
    /**************************************************************************/
    /*  Clear the semaphore.                                                  */
    /**************************************************************************/
    (void) prdg_ClearSemaphore(hmtxGlobalHeapSem);
    return;
}
#undef TFUNC


/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdg_GetNewGlobalHeap                                  */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/**********************************************************************/



SHORT prdg_GetNewGlobalHeap( PBYTE * lpHeap)
{
#define TFUNC "prdg_GetNewGlobalHeap"
    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/

    ULONG       DosResult;
    PBYTE       pbHeap;

    /******************************************************************/
    /* We want to create a new heap which will be used to hold global */
    /* data. In order to make the heap global we need to ensure that  */
    /* owned by a process which is always present. Such a process is  */
    /* the process which loaded the driver.                           */
    /* The action which takes place in this routine varies depependant*/
    /* on the ID of the process. If the process is the loading process*/
    /* we need only alocate a new segment and create a heap.          */
    /* If the process is not the loading process we need to allocate a*/
    /* new segment and then give it to the loading process.           */
    /******************************************************************/

#ifdef DEBUG_HEAP
    OutputString(" GetNewGLOBAL: entry");
#endif

    /******************************************************************/
    /* Create a DOS segment for use as a Winthorn Heap.               */
    /* If no segment acquired, return null values and error.          */
    /******************************************************************/
    DosResult = SSAllocMem((PVOID)&pbHeap, WIN_HEAP_SIZE, 0L);
    if (DosResult)
    {
        LOGDOSERR(TFUNC, "DosAllocMem Error", &DosResult, 1, DosResult);
        return(FALSE);
    }
    TRACE6(TFUNC, "DosAllocMem Heap", pbHeap,1);

    /******************************************************************/
    /* Get the ID of the process which is currently running.          */
    /******************************************************************/

    /******************************************************************/
    /* Got the memory, now initialise the heap.                       */
    /* If heap has not been initialised, need to free the already     */
    /* acquired DOS segment before returning null values and error.   */
    /******************************************************************/
    DosResult = DosSubSetMem((PVOID)pbHeap, DOSSUB_INIT | DOSSUB_SERIALIZE,
                               WIN_HEAP_SIZE);
#ifdef DEBUG_HEAP
    OutputPair( "GetNewGLOBAL: DosSubSetMem returns ",
                 DosResult, HEX );
#endif

    if (DosResult)
    {
        TRACE6(TFUNC, "Free DOS mem", pbHeap, 1);
        (void)SSFreeMem((PVOID)pbHeap);
        return(FALSE);
    }

    /******************************************************************/
    /* Successfully allocated a DOS segment for the Heap, and         */
    /* initialised it (via Winthorn). Copy local values into params   */
    /* and return.                                                    */
    /******************************************************************/
    *lpHeap = pbHeap;
#ifdef DEBUG_HEAP
    OutputPair( "GetNewGLOBAL: selector", (ULONG)lpHeap, HEX );
#endif
    TRACE6(TFUNC, "pbHeap", lpHeap, 1);
    TRACE6(TFUNC, "Exit OK", FNULL, 0);
    return (OK);
}
#undef TFUNC
