Index: trunk/src/helpers/apps.c
===================================================================
--- trunk/src/helpers/apps.c	(revision 122)
+++ trunk/src/helpers/apps.c	(revision 123)
@@ -513,42 +513,89 @@
  *      --  PROG_WINDOWABLEVIO
  *
+ *      --  PROG_DEFAULT
+ *
  *@@added V0.9.9 (2001-03-07) [umoeller]
  *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from winh.c to apps.c
  *@@changed V0.9.14 (2001-08-07) [pr]: use FAPPTYP_* constants
+ *@@changed V0.9.16 (2001-12-08) [umoeller]: added checks for batch files, other optimizations
  */
 
 APIRET appQueryAppType(const char *pcszExecutable,
-                        PULONG pulDosAppType,
-                        PULONG pulWinAppType)
+                       PULONG pulDosAppType,
+                       PULONG pulWinAppType)
 {
-    APIRET arc = DosQueryAppType((PSZ)pcszExecutable, pulDosAppType);
-    if (arc == NO_ERROR)
-    {
-        ULONG _ulDosAppType = *pulDosAppType;
-
-        if (_ulDosAppType == 0)
-            *pulWinAppType = PROG_FULLSCREEN;
-        else if (_ulDosAppType & FAPPTYP_PHYSDRV)       // 0x40
-            *pulWinAppType = PROG_PDD;
-        else if (_ulDosAppType & FAPPTYP_VIRTDRV)       // 0x80)
-            *pulWinAppType = PROG_VDD;
-        else if ((_ulDosAppType & 0xF0) == FAPPTYP_DLL) // 0x10)
+    APIRET arc;
+
+/*
+   #define FAPPTYP_NOTSPEC         0x0000
+   #define FAPPTYP_NOTWINDOWCOMPAT 0x0001
+   #define FAPPTYP_WINDOWCOMPAT    0x0002
+   #define FAPPTYP_WINDOWAPI       0x0003
+   #define FAPPTYP_BOUND           0x0008
+   #define FAPPTYP_DLL             0x0010
+   #define FAPPTYP_DOS             0x0020
+   #define FAPPTYP_PHYSDRV         0x0040  // physical device driver
+   #define FAPPTYP_VIRTDRV         0x0080  // virtual device driver
+   #define FAPPTYP_PROTDLL         0x0100  // 'protected memory' dll
+   #define FAPPTYP_WINDOWSREAL     0x0200  // Windows real mode app
+   #define FAPPTYP_WINDOWSPROT     0x0400  // Windows protect mode app
+   #define FAPPTYP_WINDOWSPROT31   0x1000  // Windows 3.1 protect mode app
+   #define FAPPTYP_32BIT           0x4000
+*/
+
+    ULONG   ulWinAppType = PROG_DEFAULT;
+
+    if (!(arc = DosQueryAppType((PSZ)pcszExecutable, pulDosAppType)))
+    {
+        // clear the 32-bit flag
+        // V0.9.16 (2001-12-08) [umoeller]
+        ULONG ulDosAppType = (*pulDosAppType) & ~FAPPTYP_32BIT,
+              ulLoAppType = ulDosAppType & 0xFFFF;
+
+        if (ulDosAppType & FAPPTYP_PHYSDRV)            // 0x40
+            ulWinAppType = PROG_PDD;
+        else if (ulDosAppType & FAPPTYP_VIRTDRV)       // 0x80
+            ulWinAppType = PROG_VDD;
+        else if ((ulDosAppType & 0xF0) == FAPPTYP_DLL) // 0x10
             // DLL bit set
-            *pulWinAppType = PROG_DLL;
-        else if (_ulDosAppType & FAPPTYP_DOS)           // 0x20)
+            ulWinAppType = PROG_DLL;
+        else if (ulDosAppType & FAPPTYP_DOS)           // 0x20
             // DOS bit set?
-            *pulWinAppType = PROG_WINDOWEDVDM;
-        else if ((_ulDosAppType & FAPPTYP_WINDOWAPI) == FAPPTYP_WINDOWAPI) // 0x0003) // "Window-API" == PM
-            *pulWinAppType = PROG_PM;
-        else if (   ((_ulDosAppType & 0xFFFF) == FAPPTYP_WINDOWSPROT31) // 0x1000) // windows program (?!?)
-                 || ((_ulDosAppType & 0xFFFF) == FAPPTYP_WINDOWSPROT) // ) // windows program (?!?)
+            ulWinAppType = PROG_WINDOWEDVDM;
+        else if ((ulDosAppType & FAPPTYP_WINDOWAPI) == FAPPTYP_WINDOWAPI) // 0x0003)
+            // "Window-API" == PM
+            ulWinAppType = PROG_PM;
+        else if (ulLoAppType == FAPPTYP_WINDOWSREAL)
+            ulWinAppType = PROG_31_ENHSEAMLESSCOMMON;  // @@todo really?
+        else if (   (ulLoAppType == FAPPTYP_WINDOWSPROT31) // 0x1000) // windows program (?!?)
+                 || (ulLoAppType == FAPPTYP_WINDOWSPROT) // ) // windows program (?!?)
                 )
-            *pulWinAppType = PROG_31_ENHSEAMLESSCOMMON;  // PROG_31_ENH;
-            // *pulWinAppType = PROG_31_ENHSEAMLESSVDM;
-        else if ((_ulDosAppType & FAPPTYP_WINDOWAPI /* 0x03 */ ) == FAPPTYP_WINDOWCOMPAT) // 0x02)
-            *pulWinAppType = PROG_WINDOWABLEVIO;
-        else if ((_ulDosAppType & FAPPTYP_WINDOWAPI /* 0x03 */ ) == FAPPTYP_NOTWINDOWCOMPAT) // 0x01)
-            *pulWinAppType = PROG_FULLSCREEN;
-    }
+            ulWinAppType = PROG_31_ENHSEAMLESSCOMMON;  // PROG_31_ENH;
+        else if ((ulDosAppType & FAPPTYP_WINDOWAPI /* 0x03 */ ) == FAPPTYP_WINDOWCOMPAT) // 0x02)
+            ulWinAppType = PROG_WINDOWABLEVIO;
+        else if ((ulDosAppType & FAPPTYP_WINDOWAPI /* 0x03 */ ) == FAPPTYP_NOTWINDOWCOMPAT) // 0x01)
+            ulWinAppType = PROG_FULLSCREEN;
+    }
+
+    if (ulWinAppType == PROG_DEFAULT)
+    {
+        // added checks for batch files V0.9.16 (2001-12-08) [umoeller]
+        PCSZ pcszExt;
+        if (pcszExt = doshGetExtension(pcszExecutable))
+        {
+            if (!stricmp(pcszExt, "BAT"))
+            {
+                ulWinAppType = PROG_WINDOWEDVDM;
+                arc = NO_ERROR;
+            }
+            else if (!stricmp(pcszExt, "CMD"))
+            {
+                ulWinAppType = PROG_WINDOWABLEVIO;
+                arc = NO_ERROR;
+            }
+        }
+    }
+
+    *pulWinAppType = ulWinAppType;
 
     return (arc);
@@ -608,4 +655,7 @@
         case PROG_WIN_GAME: return "PROG_WIN_GAME";
         case PROG_DOS_MODE: return "PROG_DOS_MODE";
+
+        // added this V0.9.16 (2001-12-08) [umoeller]
+        case PROG_WIN32: return "PROG_WIN32";
     }
 
Index: trunk/src/helpers/cnrh.c
===================================================================
--- trunk/src/helpers/cnrh.c	(revision 122)
+++ trunk/src/helpers/cnrh.c	(revision 123)
@@ -1865,6 +1865,6 @@
 
     memset(&drgImage, 0, sizeof(drgImage));
-    pdrgInfo = DrgAllocDraginfo(1); // one item only
-    if (pdrgInfo)
+
+    if (pdrgInfo = DrgAllocDraginfo(1)) // one item only
     {
         DRAGITEM drgItem;
Index: trunk/src/helpers/comctl.c
===================================================================
--- trunk/src/helpers/comctl.c	(revision 122)
+++ trunk/src/helpers/comctl.c	(revision 123)
@@ -510,5 +510,4 @@
 
         case WM_MENUEND:
-        {
             if ((HWND)mp2 == pmbd->hwndMenu) // V0.9.14 (2001-07-31) [umoeller]
             {
@@ -548,5 +547,5 @@
                 pmbd->hwndMenu = NULLHANDLE;
             } // end if ((HWND)mp1 == pmbd->pmbd->hwndMenu) // V0.9.14 (2001-07-31) [umoeller]
-        break; }
+        break;
 
         /*
@@ -569,10 +568,10 @@
 
         case WM_DESTROY:
-            mrc = (*(pmbd->pfnwpButtonOriginal))(hwndButton, msg, mp1, mp2);
+            mrc = pmbd->pfnwpButtonOriginal(hwndButton, msg, mp1, mp2);
             free(pmbd);
         break;
 
         default:
-            mrc = (*(pmbd->pfnwpButtonOriginal))(hwndButton, msg, mp1, mp2);
+            mrc = pmbd->pfnwpButtonOriginal(hwndButton, msg, mp1, mp2);
     }
 
@@ -617,11 +616,10 @@
 {
     BOOL brc = FALSE;
-    PMENUBUTTONDATA pmbd = (PMENUBUTTONDATA)malloc(sizeof(MENUBUTTONDATA));
-    if (pmbd)
+    PMENUBUTTONDATA pmbd;
+    if (pmbd = (PMENUBUTTONDATA)malloc(sizeof(MENUBUTTONDATA)))
     {
         memset(pmbd, 0, sizeof(MENUBUTTONDATA));
-        pmbd->pfnwpButtonOriginal = WinSubclassWindow(hwndButton,
-                                                      ctl_fnwpSubclassedMenuButton);
-        if (pmbd->pfnwpButtonOriginal)
+        if (pmbd->pfnwpButtonOriginal = WinSubclassWindow(hwndButton,
+                                                          ctl_fnwpSubclassedMenuButton))
         {
             pmbd->hmodMenu = hmodMenu;
@@ -730,5 +728,4 @@
 
             case WM_TIMER:
-            {
                 pa->usAniCurrent++;
                 if (pa->usAniCurrent >= pa->usAniCount)
@@ -739,5 +736,5 @@
                            (MPARAM)pa->ahptrAniIcons[pa->usAniCurrent],
                            (MPARAM)NULL);
-            break; }
+            break;
 
             /*
@@ -793,78 +790,75 @@
                     // create a suitable bitmap w/ the size of the
                     // static control
-                    if ((pa->hbm = gpihCreateBitmap(hpsMem,
-                                                    szlPage.cx,
-                                                    szlPage.cy)))
+                    if (    ((pa->hbm = gpihCreateBitmap(hpsMem,
+                                                         szlPage.cx,
+                                                         szlPage.cy)))
+                            // associate the bit map with the memory PS
+                         && (GpiSetBitmap(hpsMem, pa->hbm) != HBM_ERROR)
+                       )
                     {
-                        // associate the bit map with the memory PS
-                        if (GpiSetBitmap(hpsMem, pa->hbm) != HBM_ERROR)
+                        // fill the bitmap with the current static
+                        // background color
+                        POINTL ptl = {0, 0};
+                        GpiMove(hpsMem, &ptl);
+                        ptl.x = pa->rclIcon.xRight;
+                        ptl.y = pa->rclIcon.yTop;
+                        GpiSetColor(hpsMem,
+                                    lBkgndColor);
+                        GpiBox(hpsMem,
+                               DRO_FILL, // interior only
+                               &ptl,
+                               0, 0);    // no corner rounding
+
+                        /*
+                         * ANF_ICON:
+                         *
+                         */
+
+                        if (pa->ulFlags & ANF_ICON)
                         {
-                            // fill the bitmap with the current static
-                            // background color
-                            POINTL ptl = {0, 0};
-                            GpiMove(hpsMem, &ptl);
-                            ptl.x = pa->rclIcon.xRight;
-                            ptl.y = pa->rclIcon.yTop;
-                            GpiSetColor(hpsMem,
-                                        lBkgndColor);
-                            GpiBox(hpsMem,
-                                   DRO_FILL, // interior only
-                                   &ptl,
-                                   0, 0);    // no corner rounding
-
-                            /*
-                             * ANF_ICON:
-                             *
-                             */
-
-                            if (pa->ulFlags & ANF_ICON)
+                            // store new icon in our own structure
+                            if (pa->hptr = (HPOINTER)mp1)
                             {
-                                // store new icon in our own structure
-                                pa->hptr = (HPOINTER)mp1;
-
-                                if (pa->hptr)
-                                {
-                                    // center the icon in the bitmap
-                                    // V0.9.16 (2001-10-15) [umoeller]
-                                    POINTL ptlOfs;
-                                    ptlOfs.x = (   (pa->rclIcon.xRight - pa->rclIcon.xLeft)
-                                                 - pa->lIconSize
-                                               ) / 2;
-                                    ptlOfs.y = (   (pa->rclIcon.yTop - pa->rclIcon.yBottom)
-                                                 - pa->lIconSize
-                                               ) / 2;
-
-                                    // paint icon into bitmap
-                                    gpihIcon2Bitmap(hpsMem,
-                                                    pa->hptr,
-                                                    lBkgndColor,
-                                                    &ptlOfs,
-                                                    pa->lIconSize);
-                                }
-
-                            } // end if (pa->ulFlags & ANF_ICON)
-
-                            /*
-                             * ANF_BITMAP:
-                             *
-                             */
-
-                            else if (pa->ulFlags & ANF_BITMAP)
-                            {
-                                // store passed bitmap
-                                HBITMAP     hbmSource = (HBITMAP)mp1;
-
-                                if (hbmSource)
-                                    gpihStretchBitmap(hpsMem,       // target
-                                                      hbmSource,    // source
-                                                      NULL,     // use size of bitmap
-                                                      &pa->rclIcon,
-                                                      ((pa->ulFlags & ANF_PROPORTIONAL)
-                                                            != 0));
-
-                            } // end if (pa->ulFlags & ANF_BITMAP)
-
-                        } // end if (GpiSetBitmap(...
-                    } // if (pa->hbm = gpihCreateBitmap(hpsMem, &(pa->rclIcon)))
+                                // center the icon in the bitmap
+                                // V0.9.16 (2001-10-15) [umoeller]
+                                POINTL ptlOfs;
+                                ptlOfs.x = (   (pa->rclIcon.xRight - pa->rclIcon.xLeft)
+                                             - pa->lIconSize
+                                           ) / 2;
+                                ptlOfs.y = (   (pa->rclIcon.yTop - pa->rclIcon.yBottom)
+                                             - pa->lIconSize
+                                           ) / 2;
+
+                                // paint icon into bitmap
+                                gpihIcon2Bitmap(hpsMem,
+                                                pa->hptr,
+                                                lBkgndColor,
+                                                &ptlOfs,
+                                                pa->lIconSize);
+                            }
+
+                        } // end if (pa->ulFlags & ANF_ICON)
+
+                        /*
+                         * ANF_BITMAP:
+                         *
+                         */
+
+                        else if (pa->ulFlags & ANF_BITMAP)
+                        {
+                            // store passed bitmap
+                            HBITMAP     hbmSource;
+                            if (hbmSource = (HBITMAP)mp1)
+                                gpihStretchBitmap(hpsMem,       // target
+                                                  hbmSource,    // source
+                                                  NULL,     // use size of bitmap
+                                                  &pa->rclIcon,
+                                                  ((pa->ulFlags & ANF_PROPORTIONAL)
+                                                        != 0));
+
+                        } // end if (pa->ulFlags & ANF_BITMAP)
+
+                    } // end if (GpiSetBitmap(...
+                      // && (pa->hbm = gpihCreateBitmap(hpsMem, &(pa->rclIcon)))
 
                     // in any case, clean up now
@@ -877,6 +871,6 @@
                 // enforce WM_PAINT
                 WinInvalidateRect(hwndStatic, NULL, FALSE);
-
-            break; }
+            }
+            break;
 
             /*
@@ -940,5 +934,6 @@
 
                 WinEndPaint(hps);
-            break; }
+            }
+            break;
 
             /*
@@ -948,5 +943,4 @@
 
             case WM_DESTROY:
-            {
                 // undo subclassing in case more WM_TIMERs come in
                 WinSubclassWindow(hwndStatic, OldStaticProc);
@@ -962,5 +956,5 @@
 
                 mrc = OldStaticProc(hwndStatic, msg, mp1, mp2);
-            break; }
+            break;
 
             default:
@@ -1117,6 +1111,6 @@
                          BOOL fStartAnimation)       // TRUE: start animation now
 {
-    PANIMATIONDATA paNew = ctlPrepareStaticIcon(hwndStatic, usAnimCount);
-    if (paNew)
+    PANIMATIONDATA paNew;
+    if (paNew = ctlPrepareStaticIcon(hwndStatic, usAnimCount))
     {
         paNew->ulDelay = ulDelay;
@@ -1132,7 +1126,9 @@
         if (fStartAnimation)
         {
-            WinStartTimer(WinQueryAnchorBlock(hwndStatic), hwndStatic,
-                    1, ulDelay);
-            WinPostMsg(hwndStatic, WM_TIMER, NULL, NULL);
+            WinStartTimer(paNew->hab,
+                          hwndStatic,
+                          1,
+                          ulDelay);
+            WinPostMsg(hwndStatic, WM_TIMER, (MPARAM)1, NULL);
         }
     }
@@ -1150,12 +1146,16 @@
 {
     BOOL brc = FALSE;
-    PANIMATIONDATA pa = (PANIMATIONDATA)WinQueryWindowULong(hwndStatic, QWL_USER);
-    if (pa)
-        if (WinStartTimer(WinQueryAnchorBlock(hwndStatic), hwndStatic,
-                        1, pa->ulDelay))
-        {
-            brc = TRUE;
-            WinPostMsg(hwndStatic, WM_TIMER, NULL, NULL);
-        }
+    PANIMATIONDATA pa;
+    if (    (pa = (PANIMATIONDATA)WinQueryWindowULong(hwndStatic, QWL_USER))
+         && (WinStartTimer(pa->hab,
+                           hwndStatic,
+                           1,
+                           pa->ulDelay))
+       )
+    {
+        brc = TRUE;
+        WinPostMsg(hwndStatic, WM_TIMER, (MPARAM)1, NULL);
+    }
+
     return (brc);
 }
@@ -1345,5 +1345,5 @@
                     // check flags:
                     // filter out those ugly composite key (accents etc.)
-               &&   ((usFlags & (KC_DEADKEY | KC_COMPOSITE | KC_INVALIDCOMP)) == 0)
+                 && ((usFlags & (KC_DEADKEY | KC_COMPOSITE | KC_INVALIDCOMP)) == 0)
                )
             {
@@ -1367,9 +1367,9 @@
 
                 flReturned = (ULONG)WinSendMsg(hwndOwner,
-                                          WM_CONTROL,
-                                          MPFROM2SHORT(WinQueryWindowUShort(hwndEdit,
-                                                                            QWS_ID),
-                                                       EN_HOTKEY),  // new notification code
-                                          (MPARAM)&hkn);
+                                               WM_CONTROL,
+                                               MPFROM2SHORT(WinQueryWindowUShort(hwndEdit,
+                                                                                 QWS_ID),
+                                                            EN_HOTKEY),  // new notification code
+                                               (MPARAM)&hkn);
                 if (flReturned & HEFL_SETTEXT)
                     WinSetWindowText(hwndEdit, hkn.szDescription);
@@ -1383,8 +1383,8 @@
                     WinSetWindowText(hwndEdit, "");
 
-
                 mrc = (MPARAM)TRUE; // WM_CHAR processed flag;
             }
-        break; }
+        }
+        break;
 
         default:
Index: trunk/src/helpers/configsys.c
===================================================================
--- trunk/src/helpers/configsys.c	(revision 122)
+++ trunk/src/helpers/configsys.c	(revision 123)
@@ -91,8 +91,6 @@
     }
 
-    arc = doshLoadTextFile(pcszFile,
-                           ppszContents);
-
-    if (arc == NO_ERROR)
+    if (!(arc = doshLoadTextFile(pcszFile,
+                                 ppszContents)))
     {
         // convert all \r\n to \n
@@ -316,8 +314,8 @@
                      ULONG cbCopyTo)            // out: sizeof(*pszCopyTo)
 {
-    PSZ     p = csysFindKey(pcszSearchIn, pcszKey, NULL, NULL),
+    PSZ     p,
             prc = NULL;
 
-    if (p)
+    if (p = csysFindKey(pcszSearchIn, pcszKey, NULL, NULL))
     {
         prc = p + strlen(pcszKey);
@@ -326,6 +324,6 @@
             // copy to pszCopyTo
             ULONG cb;
-            PSZ pEOL = strhFindEOL(prc, &cb);
-            if (pEOL)
+            PSZ pEOL;
+            if (pEOL = strhFindEOL(prc, &cb))
             {
                 if (cb > cbCopyTo)
@@ -370,10 +368,10 @@
 {
     BOOL    fIsAllUpperCase = FALSE;
-    PSZ     pKey = csysFindKey(*ppszBuf,
-                               pcszKey,
-                               NULL,
-                               &fIsAllUpperCase),
+    PSZ     pKey,
             pReturn = NULL;
-    if (pKey)
+    if (pKey = csysFindKey(*ppszBuf,
+                           pcszKey,
+                           NULL,
+                           &fIsAllUpperCase))
     {
         // key found in file:
@@ -381,17 +379,17 @@
 
         // replace existing parameter
-        PSZ pOldParam = pKey + strlen(pcszKey);
-        // pOldParam now has the old parameter, which we
-        // will overwrite now; pOldParam points into *ppszBuf
-
-        if (pOldParam)
-        {
+        PSZ pOldParam;
+        if (pOldParam = pKey + strlen(pcszKey))
+        {
+            // pOldParam now has the old parameter, which we
+            // will overwrite now; pOldParam points into *ppszBuf
+
             ULONG   ulOldParamOfs = pOldParam - *ppszBuf;
 
-            PSZ pEOL = strhFindEOL(pOldParam, NULL);
-            // pEOL now has first end-of-line after the parameter
-
-            if (pEOL)
+            PSZ pEOL;
+            if (pEOL = strhFindEOL(pOldParam, NULL))
             {
+                // pEOL now has first end-of-line after the parameter
+
                 // char count to replace
                 ULONG   ulToReplace = pEOL - pOldParam;
@@ -477,16 +475,16 @@
     BOOL    fIsAllUpperCase = FALSE;
     PSZ     pStartOfLine = NULL;
-    PSZ     pKey = csysFindKey(pszSearchIn,
-                               pszKey,
-                               &pStartOfLine,
-                               &fIsAllUpperCase);
+    PSZ     pKey;
     BOOL    brc = FALSE;
 
-    if (pKey)
-    {
-        PSZ pEOL = strhFindEOL(pKey, NULL);
-        // pEOL now has first end-of-line after the key
-        if (pEOL)
-        {
+    if (pKey = csysFindKey(pszSearchIn,
+                           pszKey,
+                           &pStartOfLine,
+                           &fIsAllUpperCase))
+    {
+        PSZ pEOL;
+        if (pEOL = strhFindEOL(pKey, NULL))
+        {
+            // pEOL now has first end-of-line after the key;
             // go to first character after EOL
             while (    (*pEOL)
@@ -604,6 +602,6 @@
 
     // First, check if the new-line string has a "=" char
-    PSZ pSep = strchr(pManip->pszNewLine, '=');
-    if (pSep)
+    PSZ pSep;
+    if (pSep = strchr(pManip->pszNewLine, '='))
     {
         // yes: separate in two strings
@@ -751,7 +749,7 @@
                 // Manip.pszSearchString has the search string
                 // before whose line we must insert
-                PSZ pFound = strhistr(*ppszContents,
-                                      pManip->pszVerticalSearchString);
-                if (pFound)
+                PSZ pFound;
+                if (pFound = strhistr(*ppszContents,
+                                      pManip->pszVerticalSearchString))
                 {
                     // search string found:
@@ -777,6 +775,7 @@
                 // Manip.pszSearchString has the search string
                 // after whose line we must insert
-                PSZ pFound = strhistr(*ppszContents, pManip->pszVerticalSearchString);
-                if (pFound)
+                PSZ pFound;
+                if (pFound = strhistr(*ppszContents,
+                                      pManip->pszVerticalSearchString))
                 {
                     // search string found:
Index: trunk/src/helpers/datetime.c
===================================================================
--- trunk/src/helpers/datetime.c	(revision 122)
+++ trunk/src/helpers/datetime.c	(revision 123)
@@ -230,5 +230,5 @@
  *      returns TRUE if yr is a leap year.
  *
- *      (c) Ray Gardner. Public domain.
+ *      (W) Ray Gardner. Public domain.
  */
 
@@ -260,5 +260,5 @@
  *      you then get 63.
  *
- *      (c) Ray Gardner. Public domain.
+ *      (W) Ray Gardner. Public domain.
  */
 
@@ -272,5 +272,5 @@
  *      converts a year to the no. of days passed.
  *
- *      (c) Ray Gardner. Public domain.
+ *      (W) Ray Gardner. Public domain.
  */
 
@@ -288,5 +288,5 @@
  *      the given date.
  *
- *      (c) Ray Gardner. Public domain.
+ *      (W) Ray Gardner. Public domain.
  */
 
@@ -308,5 +308,5 @@
  *
  *
- *      (c) Ray Gardner. Public domain.
+ *      (W) Ray Gardner. Public domain.
  */
 
@@ -343,5 +343,4 @@
                    ULONG year)    // in: year (e.g. 1999)
 {
-    BOOL brc = FALSE;
     if (day > 0)
     {
@@ -356,5 +355,5 @@
             case 12 :
                 if (day <= 31)
-                    brc = TRUE;
+                    return (TRUE);
             break;
 
@@ -364,17 +363,18 @@
             case 11 :
                 if (day <= 30)
-                    brc = TRUE;
+                    return (TRUE);
             break;
 
             case 2 :
                 if (day < 29)
-                    brc = TRUE;
+                    return (TRUE);
                 else
                     if (day == 29)
                         if (dtIsLeapYear(year))
-                            return 1 ;
+                            return (TRUE);
         }
     }
-    return (brc);
-}
-
+
+    return (FALSE);
+}
+
Index: trunk/src/helpers/dialog.c
===================================================================
--- trunk/src/helpers/dialog.c	(revision 122)
+++ trunk/src/helpers/dialog.c	(revision 123)
@@ -678,42 +678,49 @@
         cy = pcp->cy;
 
-        // change the title if this is a static with SS_BITMAP;
-        // we have used a HBITMAP in there!
-        if (    ((ULONG)pControlDef->pcszClass == 0xffff0005L) // WC_STATIC:
-             && (    ((flStyle & 0x0F) == SS_BITMAP)
-                  || ((flStyle & 0x0F) == SS_ICON)
-                )
-           )
-        {
-            // change style flag to not use SS_BITMAP nor SS_ICON;
-            // control creation fails otherwise (stupid, stupid PM)
-            flOld = flStyle;
-            flStyle = ((flStyle & ~0x0F) | SS_FGNDFRAME);
-            pcszTitle = "";
-            lHandleSet = (LHANDLE)pControlDef->pcszText;
-        }
-        // hack the stupid drop-down combobox which doesn't
-        // expand otherwise (the size of the drop-down is
-        // the full size of the control... duh)
-        else if (    ((ULONG)pControlDef->pcszClass == 0xffff0002L)
-                  && (flStyle & (CBS_DROPDOWN | CBS_DROPDOWNLIST))
-                )
-        {
-            y -= 100;
-            cy += 100;
-        }
-        // the stupid entry field resizes itself if it has
-        // the ES_MARGIN style, so correlate that too... dammit
-        // V0.9.16 (2001-12-08) [umoeller]
-        else if (    ((ULONG)pControlDef->pcszClass == 0xffff0006L)
-                  && (flStyle & ES_MARGIN)
-                )
-        {
-            LONG cxMargin = 3 * WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
-            LONG cyMargin = 3 * WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);
-
-            x += cxMargin;
-            y += cxMargin;
-        }
+        // now implement hacks for certain controls
+        switch ((ULONG)pControlDef->pcszClass)
+        {
+            case 0xffff0005L: // WC_STATIC:
+                // change the title if this is a static with SS_BITMAP;
+                // we have used a HBITMAP in there!
+                if (    (    ((flStyle & 0x0F) == SS_BITMAP)
+                          || ((flStyle & 0x0F) == SS_ICON)
+                        )
+                   )
+                {
+                    // change style flag to not use SS_BITMAP nor SS_ICON;
+                    // control creation fails otherwise (stupid, stupid PM)
+                    flOld = flStyle;
+                    flStyle = ((flStyle & ~0x0F) | SS_FGNDFRAME);
+                    pcszTitle = "";
+                    lHandleSet = (LHANDLE)pControlDef->pcszText;
+                }
+            break;
+
+            case 0xffff0002L:   // combobox
+                // hack the stupid drop-down combobox which doesn't
+                // expand otherwise (the size of the drop-down is
+                // the full size of the control... duh)
+                if (flStyle & (CBS_DROPDOWN | CBS_DROPDOWNLIST))
+                {
+                    y -= 100;
+                    cy += 100;
+                }
+            break;
+
+            case 0xffff0006L:   // entry field
+                // the stupid entry field resizes itself if it has
+                // the ES_MARGIN style, so correlate that too... dammit
+                // V0.9.16 (2001-12-08) [umoeller]
+                if (flStyle & ES_MARGIN)
+                {
+                    LONG cxMargin = 3 * WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
+                    LONG cyMargin = 3 * WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);
+
+                    x += cxMargin;
+                    y += cxMargin;
+                }
+            break;
+        } // end switch ((ULONG)pControlDef->pcszClass)
     }
 
Index: trunk/src/helpers/dosh.c
===================================================================
--- trunk/src/helpers/dosh.c	(revision 122)
+++ trunk/src/helpers/dosh.c	(revision 123)
@@ -127,17 +127,16 @@
     ULONG           ulAction;
 
-    arc = DosOpen("KBD$", &hfKbd, &ulAction, 0,
-                  FILE_NORMAL, FILE_OPEN,
-                  OPEN_ACCESS_READONLY | OPEN_SHARE_DENYWRITE,
-                  (PEAOP2)NULL);
-    if (arc == NO_ERROR)
+    if (!(arc = DosOpen("KBD$", &hfKbd, &ulAction, 0,
+                        FILE_NORMAL,
+                        FILE_OPEN,
+                        OPEN_ACCESS_READONLY | OPEN_SHARE_DENYWRITE,
+                        (PEAOP2)NULL)))
     {
         SHIFTSTATE      ShiftState;
         ULONG           cbDataLen = sizeof(ShiftState);
 
-        arc = DosDevIOCtl(hfKbd, IOCTL_KEYBOARD, KBD_GETSHIFTSTATE,
-                          NULL, 0, NULL,      // no parameters
-                          &ShiftState, cbDataLen, &cbDataLen);
-        if (arc == NO_ERROR)
+        if (!(arc = DosDevIOCtl(hfKbd, IOCTL_KEYBOARD, KBD_GETSHIFTSTATE,
+                                NULL, 0, NULL,      // no parameters
+                                &ShiftState, cbDataLen, &cbDataLen)))
             brc = ((ShiftState.fsState & 3) != 0);
 
@@ -308,4 +307,35 @@
 
     return (pv);
+}
+
+/*
+ *@@ doshAllocArray:
+ *      allocates c * cbArrayItem bytes.
+ *      Similar to calloc(), but returns
+ *      error codes:
+ *
+ *      --  NO_ERROR: *ppv and *pcbAllocated were set.
+ *
+ *      --  ERROR_NO_DATA: either c or cbArrayItem are
+ *          zero.
+ *
+ *      --  ERROR_NOT_ENOUGH_MEMORY: malloc() failed.
+ *
+ *@@added V0.9.16 (2001-12-08) [umoeller]
+ */
+
+APIRET doshAllocArray(ULONG c,              // in: array item count
+                      ULONG cbArrayItem,    // in: size of one array item
+                      PBYTE *ppv,           // out: memory ptr if NO_ERROR is returned
+                      PULONG pcbAllocated)  // out: # of bytes allocated
+{
+    if (!c || !cbArrayItem)
+        return ERROR_NO_DATA;
+
+    *pcbAllocated = c * cbArrayItem;
+    if (!(*ppv = malloc(*pcbAllocated)))
+        return ERROR_NOT_ENOUGH_MEMORY;
+
+    return NO_ERROR;
 }
 
@@ -1333,4 +1363,8 @@
  *      has no dot in it).
  *
+ *      In the pathological case of a dot in the path
+ *      but not in the filename itself, this correctly
+ *      returns NULL.
+ *
  *@@added V0.9.6 (2000-10-16) [umoeller]
  *@@changed V0.9.7 (2000-12-10) [umoeller]: fixed "F:filename.ext" case
@@ -1344,10 +1378,10 @@
     {
         // find filename
-        PCSZ    p2 = strrchr(pcszFilename + 2, '\\'),
-                            // works on "C:\blah" or "\\unc\blah"
+        PCSZ    p2,
                 pStartOfName = NULL,
                 pExtension = NULL;
 
-        if (p2)
+        if (p2 = strrchr(pcszFilename + 2, '\\'))
+                            // works on "C:\blah" or "\\unc\blah"
             pStartOfName = p2 + 1;
         else
@@ -1365,6 +1399,5 @@
 
         // find last dot in filename
-        pExtension = strrchr(pStartOfName, '.');
-        if (pExtension)
+        if (pExtension = strrchr(pStartOfName, '.'))
             pReturn = (PSZ)pExtension + 1;
     }
@@ -1418,8 +1451,7 @@
         // Each data field following fsqBuffer.szName begins
         // immediately after the previous item.
-        if (strncmp((PSZ)&(pfsqBuffer->szName) + pfsqBuffer->cbName + 1,
-                    "FAT",
-                    3)
-               == 0)
+        if (!strncmp((PSZ)&(pfsqBuffer->szName) + pfsqBuffer->cbName + 1,
+                     "FAT",
+                     3))
             brc = TRUE;
     }
@@ -1438,11 +1470,12 @@
  */
 
-APIRET doshQueryFileSize(HFILE hFile,
-                         PULONG pulSize)
+APIRET doshQueryFileSize(HFILE hFile,       // in: file handle
+                         PULONG pulSize)    // out: file size (ptr can be NULL)
 {
     APIRET arc;
     FILESTATUS3 fs3;
     if (!(arc = DosQueryFileInfo(hFile, FIL_STANDARD, &fs3, sizeof(fs3))))
-        *pulSize = fs3.cbFile;
+        if (pulSize)
+            *pulSize = fs3.cbFile;
     return (arc);
 }
@@ -1453,17 +1486,34 @@
  *      or 0 if the file could not be
  *      found.
+ *
  *      Use doshQueryFileSize instead to query the
  *      size if you have a HFILE.
  *
+ *      Otherwise this returns:
+ *
+ *      --  ERROR_FILE_NOT_FOUND
+ *      --  ERROR_PATH_NOT_FOUND
+ *      --  ERROR_SHARING_VIOLATION
+ *      --  ERROR_FILENAME_EXCED_RANGE
+ *      --  ERROR_INVALID_PARAMETER
+ *
  *@@changed V0.9.16 (2001-10-19) [umoeller]: now returning APIRET
  */
 
-APIRET doshQueryPathSize(PCSZ pcszFile,
-                         PULONG pulSize)
+APIRET doshQueryPathSize(PCSZ pcszFile,         // in: filename
+                         PULONG pulSize)        // out: file size (ptr can be NULL)
 {
     APIRET arc;
-    FILESTATUS3 fs3;
-    if (!(arc = DosQueryPathInfo((PSZ)pcszFile, FIL_STANDARD, &fs3, sizeof(fs3))))
-        *pulSize = fs3.cbFile;
+
+    if (pcszFile)      // V0.9.16 (2001-12-08) [umoeller]
+    {
+        FILESTATUS3 fs3;
+        if (!(arc = DosQueryPathInfo((PSZ)pcszFile, FIL_STANDARD, &fs3, sizeof(fs3))))
+            if (pulSize)
+                *pulSize = fs3.cbFile;
+    }
+    else
+        arc = ERROR_INVALID_PARAMETER;
+
     return (arc);
 }
@@ -1488,16 +1538,24 @@
  *      returned.
  *
+ *      Otherwise this returns:
+ *
+ *      --  ERROR_FILE_NOT_FOUND
+ *      --  ERROR_PATH_NOT_FOUND
+ *      --  ERROR_SHARING_VIOLATION
+ *      --  ERROR_FILENAME_EXCED_RANGE
+ *
  *@@added V0.9.0 [umoeller]
  */
 
 APIRET doshQueryPathAttr(const char* pcszFile,      // in: file or directory name
-                         PULONG pulAttr)            // out: attributes
+                         PULONG pulAttr)            // out: attributes (ptr can be NULL)
 {
     FILESTATUS3 fs3;
-    APIRET arc = DosQueryPathInfo((PSZ)pcszFile,
+    APIRET arc;
+
+    if (!(arc = DosQueryPathInfo((PSZ)pcszFile,
                                   FIL_STANDARD,
                                   &fs3,
-                                  sizeof(fs3));
-    if (arc == NO_ERROR)
+                                  sizeof(fs3))))
     {
         if (pulAttr)
@@ -1532,20 +1590,26 @@
                        ULONG ulAttr)            // in: new attributes
 {
-    FILESTATUS3 fs3;
-    APIRET rc = DosQueryPathInfo((PSZ)pcszFile,
+    APIRET arc;
+
+    if (pcszFile)
+    {
+        FILESTATUS3 fs3;
+        if (!(arc = DosQueryPathInfo((PSZ)pcszFile,
+                                      FIL_STANDARD,
+                                      &fs3,
+                                      sizeof(fs3))))
+        {
+            fs3.attrFile = ulAttr;
+            arc = DosSetPathInfo((PSZ)pcszFile,
                                  FIL_STANDARD,
                                  &fs3,
-                                 sizeof(fs3));
-
-    if (rc == NO_ERROR)
-    {
-        fs3.attrFile = ulAttr;
-        rc = DosSetPathInfo((PSZ)pcszFile,
-                            FIL_STANDARD,
-                            &fs3,
-                            sizeof(fs3),
-                            DSPI_WRTTHRU);
-    }
-    return (rc);
+                                 sizeof(fs3),
+                                 DSPI_WRTTHRU);
+        }
+    }
+    else
+        arc = ERROR_INVALID_PARAMETER;
+
+    return (arc);
 }
 
@@ -1640,17 +1704,24 @@
                   LONG lOffset,    // in: offset to write at (depends on ulMethod)
                   ULONG ulMethod,  // in: one of FILE_BEGIN, FILE_CURRENT, FILE_END
-                  ULONG cb,        // in: bytes to write
+                  PULONG pcb,      // in: bytes to read, out: bytes read
                   PBYTE pbData)    // out: read buffer (must be cb bytes)
 {
     APIRET arc;
+    ULONG cb = *pcb;
     ULONG ulDummy;
+
+    *pcb = 0;
+
     if (!(arc = DosSetFilePtr(hf,
                               lOffset,
                               ulMethod,
                               &ulDummy)))
-        arc = DosRead(hf,
-                      pbData,
-                      cb,
-                      &ulDummy);
+    {
+        if (!(arc = DosRead(hf,
+                            pbData,
+                            cb,
+                            &ulDummy)))
+            *pcb = ulDummy;     // bytes read
+    }
 
     return (arc);
@@ -1663,19 +1734,23 @@
  *
  *      ulOpenMode determines the mode to open the
- *      file in:
- *
- +      +-------------------------+------+-----------+-----------+
- +      |                         |      |           |           |
- +      |  ulOpenMode             | mode | if exists | if new    |
- +      +-------------------------+------+-----------+-----------+
- +      |  XOPEN_READ_EXISTING    | read | opens     | fails     |
- +      +-------------------------+------+-----------+-----------+
- +      |  XOPEN_READWRITE_APPEND | r/w  | opens,    | creates   |
- +      |                         |      | appends   |           |
- +      +-------------------------+------+-----------+-----------+
- +      |  XOPEN_READWRITE_NEW    | r/w  | replaces  | creates   |
- +      +-------------------------+------+-----------+-----------+
- *
- *      In addition, you can specify the XOPEN_BINARY flag:
+ *      file in (fptr specifies the position after
+ *      the open):
+ *
+ +      +-------------------------+------+------------+-----------+
+ +      |  ulOpenMode             | mode | if exists  | if new    |
+ +      +-------------------------+------+------------+-----------+
+ +      |  XOPEN_READ_EXISTING    | read | opens      | fails     |
+ +      |                         |      | fptr = 0   |           |
+ +      +-------------------------+------+------------+-----------+
+ +      |  XOPEN_READWRITE_APPEND | r/w  | opens,     | creates   |
+ +      |                         |      | appends    |           |
+ +      |                         |      | fptr = end | fptr = 0  |
+ +      +-------------------------+------+------------+-----------+
+ +      |  XOPEN_READWRITE_NEW    | r/w  | replaces   | creates   |
+ +      |                         |      | fptr = 0   | fptr = 0  |
+ +      +-------------------------+------+------------+-----------+
+ *
+ *      In addition, you can OR one of the above values with
+ *      the XOPEN_BINARY flag:
  *
  *      --  If XOPEN_BINARY is set, no conversion is performed
@@ -1687,4 +1762,19 @@
  *      *ppFile receives a new XFILE structure describing
  *      the open file, if NO_ERROR is returned.
+ *
+ *      The file pointer is then set to the beginning of the
+ *      file _unless_ XOPEN_READWRITE_APPEND was specified;
+ *      in that case only, the file pointer is set to the
+ *      end of the file so data can be appended (see above).
+ *
+ *      Otherwise this returns:
+ *
+ *      --  ERROR_FILE_NOT_FOUND
+ *      --  ERROR_PATH_NOT_FOUND
+ *      --  ERROR_SHARING_VIOLATION
+ *      --  ERROR_FILENAME_EXCED_RANGE
+ *
+ *      --  ERROR_NOT_ENOUGH_MEMORY
+ *      --  ERROR_INVALID_PARAMETER
  *
  *@@added V0.9.16 (2001-10-19) [umoeller]
@@ -1699,91 +1789,96 @@
     APIRET arc = NO_ERROR;
 
-    ULONG   fsOpenFlags = 0,
-            fsOpenMode =    OPEN_FLAGS_FAIL_ON_ERROR
-                          | OPEN_FLAGS_NO_LOCALITY
-                          | OPEN_FLAGS_NOINHERIT;
-
-    switch (flOpenMode & XOPEN_ACCESS_MASK)
-    {
-        case XOPEN_READ_EXISTING:
-            fsOpenFlags =   OPEN_ACTION_FAIL_IF_NEW
-                          | OPEN_ACTION_OPEN_IF_EXISTS;
-            fsOpenMode |=   OPEN_SHARE_DENYWRITE
-                          | OPEN_ACCESS_READONLY;
-            // _Pmpf((__FUNCTION__ ": opening XOPEN_READ_EXISTING"));
-        break;
-
-        case XOPEN_READWRITE_APPEND:
-            fsOpenFlags =   OPEN_ACTION_CREATE_IF_NEW
-                          | OPEN_ACTION_OPEN_IF_EXISTS;
-            fsOpenMode |=   OPEN_SHARE_DENYREADWRITE
-                          | OPEN_ACCESS_READWRITE;
-            // _Pmpf((__FUNCTION__ ": opening XOPEN_READWRITE_APPEND"));
-        break;
-
-        case XOPEN_READWRITE_NEW:
-            fsOpenFlags =   OPEN_ACTION_CREATE_IF_NEW
-                          | OPEN_ACTION_REPLACE_IF_EXISTS;
-            fsOpenMode |=   OPEN_SHARE_DENYREADWRITE
-                          | OPEN_ACCESS_READWRITE;
-            // _Pmpf((__FUNCTION__ ": opening XOPEN_READWRITE_NEW"));
-        break;
-
-        default:
-            arc = ERROR_INVALID_PARAMETER;
-    }
-
-    if ((!arc) && pcszFilename && fsOpenFlags && pcbFile && ppFile)
-    {
-        PXFILE pFile;
-        if (pFile = NEW(XFILE))
+    // run this first, because if the file doesn't
+    // exists, DosOpen only returns ERROR_OPEN_FAILED,
+    // which isn't that meaningful
+    // V0.9.16 (2001-12-08) [umoeller]
+    if (!(arc = doshQueryPathSize(pcszFilename,
+                                  pcbFile)))
+    {
+        ULONG   fsOpenFlags = 0,
+                fsOpenMode =    OPEN_FLAGS_FAIL_ON_ERROR
+                              | OPEN_FLAGS_NO_LOCALITY
+                              | OPEN_FLAGS_NOINHERIT;
+
+        switch (flOpenMode & XOPEN_ACCESS_MASK)
         {
-            ULONG ulAction;
-
-            ZERO(pFile);
-
-            // copy open flags
-            pFile->flOpenMode = flOpenMode;
-
-            if (!(arc = DosOpen((PSZ)pcszFilename,
-                                &pFile->hf,
-                                &ulAction,
-                                *pcbFile,
-                                FILE_ARCHIVED,
-                                fsOpenFlags,
-                                fsOpenMode,
-                                NULL)))       // EAs
+            case XOPEN_READ_EXISTING:
+                fsOpenFlags =   OPEN_ACTION_FAIL_IF_NEW
+                              | OPEN_ACTION_OPEN_IF_EXISTS;
+                fsOpenMode |=   OPEN_SHARE_DENYWRITE
+                              | OPEN_ACCESS_READONLY;
+                // _Pmpf((__FUNCTION__ ": opening XOPEN_READ_EXISTING"));
+            break;
+
+            case XOPEN_READWRITE_APPEND:
+                fsOpenFlags =   OPEN_ACTION_CREATE_IF_NEW
+                              | OPEN_ACTION_OPEN_IF_EXISTS;
+                fsOpenMode |=   OPEN_SHARE_DENYREADWRITE
+                              | OPEN_ACCESS_READWRITE;
+                // _Pmpf((__FUNCTION__ ": opening XOPEN_READWRITE_APPEND"));
+            break;
+
+            case XOPEN_READWRITE_NEW:
+                fsOpenFlags =   OPEN_ACTION_CREATE_IF_NEW
+                              | OPEN_ACTION_REPLACE_IF_EXISTS;
+                fsOpenMode |=   OPEN_SHARE_DENYREADWRITE
+                              | OPEN_ACCESS_READWRITE;
+                // _Pmpf((__FUNCTION__ ": opening XOPEN_READWRITE_NEW"));
+            break;
+        }
+
+        if ((!arc) && fsOpenFlags && pcbFile && ppFile)
+        {
+            PXFILE pFile;
+            if (pFile = NEW(XFILE))
             {
-                // alright, got the file:
-
-                if (    (ulAction == FILE_EXISTED)
-                     && ((flOpenMode & XOPEN_ACCESS_MASK) == XOPEN_READWRITE_APPEND)
-                   )
-                    // get its size and set ptr to end for append
-                    arc = DosSetFilePtr(pFile->hf,
-                                        0,
-                                        FILE_END,
-                                        pcbFile);
+                ULONG ulAction;
+
+                ZERO(pFile);
+
+                // copy open flags
+                pFile->flOpenMode = flOpenMode;
+
+                if (!(arc = DosOpen((PSZ)pcszFilename,
+                                    &pFile->hf,
+                                    &ulAction,
+                                    *pcbFile,
+                                    FILE_ARCHIVED,
+                                    fsOpenFlags,
+                                    fsOpenMode,
+                                    NULL)))       // EAs
+                {
+                    // alright, got the file:
+
+                    if (    (ulAction == FILE_EXISTED)
+                         && ((flOpenMode & XOPEN_ACCESS_MASK) == XOPEN_READWRITE_APPEND)
+                       )
+                        // get its size and set ptr to end for append
+                        arc = DosSetFilePtr(pFile->hf,
+                                            0,
+                                            FILE_END,
+                                            pcbFile);
+                    else
+                        arc = doshQueryFileSize(pFile->hf,
+                                                pcbFile);
+                        // file ptr is at beginning
+
+                    // store file size
+                    pFile->cbInitial
+                    = pFile->cbCurrent
+                    = *pcbFile;
+                }
+
+                if (arc)
+                    doshClose(&pFile);
                 else
-                    arc = doshQueryFileSize(pFile->hf,
-                                            pcbFile);
-                    // file ptr is at beginning
-
-                // store file size
-                pFile->cbInitial
-                = pFile->cbCurrent
-                = *pcbFile;
+                    *ppFile = pFile;
             }
-
-            if (arc)
-                doshClose(&pFile);
             else
-                *ppFile = pFile;
+                arc = ERROR_NOT_ENOUGH_MEMORY;
         }
         else
-            arc = ERROR_NOT_ENOUGH_MEMORY;
-    }
-    else
-        arc = ERROR_INVALID_PARAMETER;
+            arc = ERROR_INVALID_PARAMETER;
+    }
 
     return (arc);
@@ -2199,6 +2294,5 @@
         if (!pcszTemp)
         {
-            pcszTemp = getenv("TEMP");
-            if (!pcszTemp)
+            if (!(pcszTemp = getenv("TEMP")))
                 pcszTemp = getenv("TMP");
         }
@@ -2385,5 +2479,5 @@
  *@@ doshQueryDirExist:
  *      returns TRUE if the given directory
- *      exists.
+ *      exists and really is a directory.
  */
 
@@ -2391,9 +2485,10 @@
 {
     FILESTATUS3 fs3;
-    APIRET arc = DosQueryPathInfo((PSZ)pcszDir,
-                                  FIL_STANDARD,
-                                  &fs3,
-                                  sizeof(fs3));
-    if (arc == NO_ERROR)
+    APIRET arc;
+
+    if (!(arc = DosQueryPathInfo((PSZ)pcszDir,
+                                 FIL_STANDARD,
+                                 &fs3,
+                                 sizeof(fs3))))
         // file found:
         return ((fs3.attrFile & FILE_DIRECTORY) != 0);
@@ -2641,9 +2736,10 @@
 {
     CHAR    szName[CCHMAXPATH];
-    APIRET arc = DosLoadModule(szName,
-                               sizeof(szName),
-                               pszModuleName,
-                               phmod);
-    if (arc == NO_ERROR)
+    APIRET  arc;
+
+    if (!(arc = DosLoadModule(szName,
+                              sizeof(szName),
+                              pszModuleName,
+                              phmod)))
     {
         ULONG  ul;
@@ -2652,16 +2748,15 @@
              ul++)
         {
-            arc = DosQueryProcAddr(*phmod,
-                                   0,               // ordinal, ignored
-                                   (PSZ)paResolves[ul].pcszFunctionName,
-                                   paResolves[ul].ppFuncAddress);
-
-            /* _Pmpf(("Resolved %s to 0x%lX, rc: %d",
-                    paResolves[ul].pcszFunctionName,
-                    *paResolves[ul].ppFuncAddress,
-                    arc)); */
-            if (arc != NO_ERROR)
+            if (arc = DosQueryProcAddr(*phmod,
+                                       0,               // ordinal, ignored
+                                       (PSZ)paResolves[ul].pcszFunctionName,
+                                       paResolves[ul].ppFuncAddress))
+                // error:
                 break;
         }
+
+        if (arc)
+            // V0.9.16 (2001-12-08) [umoeller]
+            DosFreeModule(*phmod);
     }
 
Index: trunk/src/helpers/dosh2.c
===================================================================
--- trunk/src/helpers/dosh2.c	(revision 122)
+++ trunk/src/helpers/dosh2.c	(revision 123)
@@ -426,4 +426,6 @@
  *@@changed V0.9.10 (2001-04-08) [umoeller]: now setting ppExec only if NO_ERROR is returned
  *@@changed V0.9.12 (2001-05-03) [umoeller]: added support for NOSTUB newstyle executables
+ *@@changed V0.9.16 (2001-12-08) [umoeller]: now using OPEN_SHARE_DENYWRITE
+ *@@changed V0.9.16 (2001-12-08) [umoeller]: fLibrary was never set, works for LX and NE now
  */
 
@@ -440,6 +442,5 @@
         return (ERROR_INVALID_PARAMETER);
 
-    pExec = (PEXECUTABLE)malloc(sizeof(EXECUTABLE));
-    if (!(pExec))
+    if (!(pExec = (PEXECUTABLE)malloc(sizeof(EXECUTABLE))))
         return (ERROR_NOT_ENOUGH_MEMORY);
 
@@ -458,5 +459,6 @@
                            | OPEN_FLAGS_SEQUENTIAL
                            | OPEN_FLAGS_NOINHERIT
-                           | OPEN_SHARE_DENYNONE
+                           // | OPEN_SHARE_DENYNONE
+                           | OPEN_SHARE_DENYWRITE       // changed V0.9.16 (2001-12-08) [umoeller]
                            | OPEN_ACCESS_READONLY,      // read-only mode
                         NULL)))                         // no EAs
@@ -464,23 +466,15 @@
         // file opened successfully:
 
-        ULONG           ulLocal = 0;
-
         // read old DOS EXE header
-        pExec->pDosExeHeader = (PDOSEXEHEADER)malloc(sizeof(DOSEXEHEADER));
-        if (!(pExec->pDosExeHeader))
+        if (!(pExec->pDosExeHeader = (PDOSEXEHEADER)malloc(sizeof(DOSEXEHEADER))))
             arc = ERROR_NOT_ENOUGH_MEMORY;
         else
         {
-            ULONG   ulBytesRead = 0;
-
-            if (    (!(arc = DosSetFilePtr(hFile,
-                                           0L,
-                                           FILE_BEGIN,
-                                           &ulLocal)))      // out: new offset
-                 && (!(arc = DosRead(hFile,
-                                     pExec->pDosExeHeader,
-                                     sizeof(DOSEXEHEADER),
-                                     &(pExec->cbDosExeHeader))))
-               )
+            pExec->cbDosExeHeader = sizeof(DOSEXEHEADER);
+            if (!(arc = doshReadAt(hFile,
+                                   0,
+                                   FILE_BEGIN,
+                                   &pExec->cbDosExeHeader,      // in/out
+                                   (PBYTE)pExec->pDosExeHeader)))
             {
                 ULONG ulNewHeaderOfs = 0;       // V0.9.12 (2001-05-03) [umoeller]
@@ -530,40 +524,52 @@
                     // V0.9.12 (2001-05-03) [umoeller]
                     CHAR    achNewHeaderType[2] = "";
-
-                    if (    (!(arc = DosSetFilePtr(hFile,
-                                                   ulNewHeaderOfs,
-                                                   FILE_BEGIN,
-                                                   &ulLocal)))
-                            // read two chars to find out header type
-                         && (!(arc = DosRead(hFile,
-                                             &achNewHeaderType,
-                                             sizeof(achNewHeaderType),
-                                             &ulBytesRead)))
-                       )
+                    ULONG   cbRead;
+
+                    cbRead = sizeof(achNewHeaderType);
+                    if (!(arc = doshReadAt(hFile,
+                                           ulNewHeaderOfs,
+                                           FILE_BEGIN,
+                                           &cbRead,
+                                           achNewHeaderType)))
                     {
                         PBYTE   pbCheckOS = NULL;
 
                         // reset file ptr
-                        DosSetFilePtr(hFile,
+                        /* DosSetFilePtr(hFile,
                                       ulNewHeaderOfs,
                                       FILE_BEGIN,
                                       &ulLocal);
-
-                        if (memcmp(achNewHeaderType, "NE", 2) == 0)
+                           */
+
+                        if (!memcmp(achNewHeaderType, "NE", 2))
                         {
                             // New Executable:
                             pExec->ulExeFormat = EXEFORMAT_NE;
                             // allocate NE header
-                            pExec->pNEHeader = (PNEHEADER)malloc(sizeof(NEHEADER));
-                            if (!(pExec->pNEHeader))
+                            if (pExec->pNEHeader = (PNEHEADER)malloc(sizeof(NEHEADER)))
+                            {
+                                // read in NE header
+                                pExec->cbNEHeader = sizeof(NEHEADER);
+                                if (!(arc = doshReadAt(hFile,
+                                                       ulNewHeaderOfs,
+                                                       FILE_BEGIN,
+                                                       &pExec->cbNEHeader,
+                                                       (PBYTE)pExec->pNEHeader)))
+                                {
+                                    if (pExec->cbNEHeader == sizeof(NEHEADER))
+                                    {
+                                        pbCheckOS = &pExec->pNEHeader->bTargetOS;
+                                        // set library flag V0.9.16 (2001-12-08) [umoeller]
+                                        if (pExec->pNEHeader->usFlags & 0x8000)
+                                            // library:
+                                            pExec->fLibrary = TRUE;
+                                    }
+                                    else
+                                        // V0.9.16 (2001-12-08) [umoeller]
+                                        arc = ERROR_INVALID_EXE_SIGNATURE;
+                                }
+                            }
+                            else
                                 arc = ERROR_NOT_ENOUGH_MEMORY;
-                            else
-                                // read in NE header
-                                if (!(arc = DosRead(hFile,
-                                                    pExec->pNEHeader,
-                                                    sizeof(NEHEADER),
-                                                    &(pExec->cbNEHeader))))
-                                    if (pExec->cbNEHeader == sizeof(NEHEADER))
-                                        pbCheckOS = &(pExec->pNEHeader->bTargetOS);
                         }
                         else if (   (memcmp(achNewHeaderType, "LX", 2) == 0)
@@ -575,15 +581,29 @@
                             pExec->ulExeFormat = EXEFORMAT_LX;
                             // allocate LX header
-                            pExec->pLXHeader = (PLXHEADER)malloc(sizeof(LXHEADER));
-                            if (!(pExec->pLXHeader))
+                            if (pExec->pLXHeader = (PLXHEADER)malloc(sizeof(LXHEADER)))
+                            {
+                                // read in LX header
+                                pExec->cbLXHeader = sizeof(LXHEADER);
+                                if (!(arc = doshReadAt(hFile,
+                                                       ulNewHeaderOfs,
+                                                       FILE_BEGIN,
+                                                       &pExec->cbLXHeader,
+                                                       (PBYTE)pExec->pLXHeader)))
+                                {
+                                    if (pExec->cbLXHeader == sizeof(LXHEADER))
+                                    {
+                                        pbCheckOS = (PBYTE)(&pExec->pLXHeader->usTargetOS);
+                                        // set library flag V0.9.16 (2001-12-08) [umoeller]
+                                        if (pExec->pLXHeader->ulFlags & 0x8000)
+                                            // library:
+                                            pExec->fLibrary = TRUE;
+                                    }
+                                    else
+                                        // V0.9.16 (2001-12-08) [umoeller]
+                                        arc = ERROR_INVALID_EXE_SIGNATURE;
+                                }
+                            }
+                            else
                                 arc = ERROR_NOT_ENOUGH_MEMORY;
-                            else
-                                // read in LX header
-                                if (!(arc = DosRead(hFile,
-                                                    pExec->pLXHeader,
-                                                    sizeof(LXHEADER),
-                                                    &(pExec->cbLXHeader))))
-                                    if (pExec->cbLXHeader == sizeof(LXHEADER))
-                                        pbCheckOS = (PBYTE)(&(pExec->pLXHeader->usTargetOS));
                         }
                         else if (memcmp(achNewHeaderType, "PE", 2) == 0)
@@ -597,14 +617,13 @@
                             // V0.9.10 (2001-04-08) [lafaix]
                             // read in standard PE header
-                            if (!(arc = DosRead(hFile,
-                                                &PEHeader,
-                                                24,
-                                                &ulBytesRead)))
+                            cbRead = 24;
+                            if (!(arc = doshReadAt(hFile,
+                                                   ulNewHeaderOfs,
+                                                   FILE_BEGIN,
+                                                   &cbRead,
+                                                   (PBYTE)&PEHeader)))
                             {
                                 // allocate PE header
-                                pExec->pPEHeader = (PPEHEADER)malloc(24 + PEHeader.usHeaderSize);
-                                if (!(pExec->pPEHeader))
-                                    arc = ERROR_NOT_ENOUGH_MEMORY;
-                                else
+                                if (pExec->pPEHeader = (PPEHEADER)malloc(24 + PEHeader.usHeaderSize))
                                 {
                                     // copy standard PE header
@@ -615,9 +634,11 @@
                                     // read in optional PE header
                                     if (!(arc = DosRead(hFile,
-                                                        &(pExec->pPEHeader->usReserved3),
+                                                        &pExec->pPEHeader->usReserved3,
                                                         PEHeader.usHeaderSize,
-                                                        &(pExec->cbPEHeader))))
+                                                        &pExec->cbPEHeader)))
                                         pExec->cbPEHeader += 24;
                                 }
+                                else
+                                    arc = ERROR_NOT_ENOUGH_MEMORY;
                             }
                         }
@@ -661,48 +682,7 @@
     if (arc != NO_ERROR)
         // error: clean up
-        doshExecClose(pExec);
+        doshExecClose(&pExec);
     else
         *ppExec = pExec;
-
-    return (arc);
-}
-
-/*
- *@@ doshExecClose:
- *      this closes an executable opened with doshExecOpen.
- *      Always call this function if NO_ERROR was returned by
- *      doshExecOpen.
- *
- *@@added V0.9.0 [umoeller]
- */
-
-APIRET doshExecClose(PEXECUTABLE pExec)
-{
-    APIRET arc = NO_ERROR;
-    if (pExec)
-    {
-        if (pExec->pDosExeHeader)
-            free(pExec->pDosExeHeader);
-        if (pExec->pNEHeader)
-            free(pExec->pNEHeader);
-        if (pExec->pLXHeader)
-            free(pExec->pLXHeader);
-
-        if (pExec->pszDescription)
-            free(pExec->pszDescription);
-        if (pExec->pszVendor)
-            free(pExec->pszVendor);
-        if (pExec->pszVersion)
-            free(pExec->pszVersion);
-        if (pExec->pszInfo)
-            free(pExec->pszInfo);
-
-        if (pExec->hfExe)
-            arc = DosClose(pExec->hfExe);
-
-        free(pExec);
-    }
-    else
-        arc = ERROR_INVALID_PARAMETER;
 
     return (arc);
@@ -789,6 +769,5 @@
                     {
                         // date/time seems to be fixed 24 chars in length
-                        pExec->pszBuildDateTime = (PSZ)malloc(25);
-                        if (pExec->pszBuildDateTime)
+                        if (pExec->pszBuildDateTime = (PSZ)malloc(25))
                         {
                             memcpy(pExec->pszBuildDateTime,
@@ -1862,26 +1841,24 @@
         {
             // 32-bit OS/2 executable:
-            cResources = pExec->pLXHeader->ulResTblCnt;
-
-            if (cResources)
+            if (cResources = pExec->pLXHeader->ulResTblCnt)
             {
                 #pragma pack(1)     // V0.9.9 (2001-04-02) [umoeller]
-                struct rsrc32               /* Resource Table Entry */
+                struct rsrc32               // Resource Table Entry
                 {
-                    unsigned short  type;   /* Resource type */
-                    unsigned short  name;   /* Resource name */
-                    unsigned long   cb;     /* Resource size */
-                    unsigned short  obj;    /* Object number */
-                    unsigned long   offset; /* Offset within object */
+                    unsigned short  type;   // Resource type
+                    unsigned short  name;   // Resource name
+                    unsigned long   cb;     // Resource size
+                    unsigned short  obj;    // Object number
+                    unsigned long   offset; // Offset within object
                 } rs;
 
-                struct o32_obj                    /* Flat .EXE object table entry */
+                struct o32_obj                    // Flat .EXE object table entry
                 {
-                    unsigned long   o32_size;     /* Object virtual size */
-                    unsigned long   o32_base;     /* Object base virtual address */
-                    unsigned long   o32_flags;    /* Attribute flags */
-                    unsigned long   o32_pagemap;  /* Object page map index */
-                    unsigned long   o32_mapsize;  /* Number of entries in object page map */
-                    unsigned long   o32_reserved; /* Reserved */
+                    unsigned long   o32_size;     // Object virtual size
+                    unsigned long   o32_base;     // Object base virtual address
+                    unsigned long   o32_flags;    // Attribute flags
+                    unsigned long   o32_pagemap;  // Object page map index
+                    unsigned long   o32_mapsize;  // Number of entries in object page map
+                    unsigned long   o32_reserved; // Reserved
                 } ot;
                 #pragma pack() // V0.9.9 (2001-04-03) [umoeller]
@@ -1890,4 +1867,5 @@
                 ULONG ulDummy;
                 int i;
+                ULONG ulCurOfs;
 
                 paResources = (PFSYSRESOURCE)malloc(cb);
@@ -1956,10 +1934,10 @@
                     #pragma pack(1)     // V0.9.9 (2001-04-02) [umoeller]
                     struct {unsigned short type; unsigned short name;} rti;
-                    struct new_seg                          /* New .EXE segment table entry */
+                    struct new_seg                          // New .EXE segment table entry
                     {
-                        unsigned short      ns_sector;      /* File sector of start of segment */
-                        unsigned short      ns_cbseg;       /* Number of bytes in file */
-                        unsigned short      ns_flags;       /* Attribute flags */
-                        unsigned short      ns_minalloc;    /* Minimum allocation in bytes */
+                        unsigned short      ns_sector;      // File sector of start of segment
+                        unsigned short      ns_cbseg;       // Number of bytes in file
+                        unsigned short      ns_flags;       // Attribute flags
+                        unsigned short      ns_minalloc;    // Minimum allocation in bytes
                     } ns;
                     #pragma pack()
@@ -2183,4 +2161,205 @@
     free(paResources);
     return (NO_ERROR);
+}
+
+/*
+ *@@ doshLoadLXMaps:
+ *      loads the three main LX maps into the given
+ *      EXECUTABLE structure.
+ *
+ *      This loads:
+ *
+ *      1)  the LX resource table;
+ *
+ *      2)  the LX object table;
+ *
+ *      3)  the LX object _page_ table (object map).
+ *
+ *      Note that this is not automatically called
+ *      by doshExecOpen to save time, since the LX
+ *      maps are not needed for all the other exe
+ *      functions.
+ *
+ *      This returns:
+ *
+ *      --  NO_ERROR: all three LX maps were loaded,
+ *          and pExec->fLXMapsLoaded was set to TRUE.
+ *
+ *      --  ERROR_INVALID_PARAMETER
+ *
+ *      --  ERROR_INVALID_EXE_SIGNATURE: pExec does
+ *          not specify an LX executable.
+ *
+ *      --  ERROR_NO_DATA: at least one of the structs
+ *          does not exist.
+ *
+ *      --  ERROR_NOT_ENOUGH_MEMORY
+ *
+ *      plus the error codes of doshReadAt.
+ *
+ *      Call doshFreeLXMaps to clean up explicitly, but
+ *      that func automatically gets called by doshExecClose.
+ *
+ *@@added V0.9.16 (2001-12-08) [umoeller]
+ */
+
+APIRET doshLoadLXMaps(PEXECUTABLE pExec)
+{
+    APIRET arc;
+
+    if (!pExec)
+        arc = ERROR_INVALID_PARAMETER;
+    else if (pExec->ulExeFormat != EXEFORMAT_LX)
+        arc = ERROR_INVALID_EXE_SIGNATURE;
+    else if (pExec->fLXMapsLoaded)
+        // already loaded:
+        arc = NO_ERROR;
+    else
+    {
+        PLXHEADER pLXHeader = pExec->pLXHeader;
+        ULONG ulNewHeaderOfs = 0;
+        ULONG cb;
+
+        if (pExec->pDosExeHeader)
+            // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]
+            ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
+
+        // resource table
+        if (    (!(arc = doshAllocArray(pLXHeader->ulResTblCnt,
+                                        sizeof(RESOURCETABLEENTRY),
+                                        (PBYTE*)&pExec->pRsTbl,
+                                        &cb)))
+             && (!(arc = doshReadAt(pExec->hfExe,
+                                    pLXHeader->ulResTblOfs
+                                      + ulNewHeaderOfs,
+                                    FILE_BEGIN,
+                                    &cb,
+                                    (PBYTE)pExec->pRsTbl)))
+            )
+        {
+            // object table
+            if (    (!(arc = doshAllocArray(pLXHeader->ulObjCount,
+                                            sizeof(OBJECTTABLEENTRY),
+                                            (PBYTE*)&pExec->pObjTbl,
+                                            &cb)))
+                 && (!(arc = doshReadAt(pExec->hfExe,
+                                        pLXHeader->ulObjTblOfs
+                                          + ulNewHeaderOfs,
+                                        FILE_BEGIN,
+                                        &cb,
+                                        (PBYTE)pExec->pObjTbl)))
+               )
+            {
+                // object page table
+                if (    (!(arc = doshAllocArray(pLXHeader->ulPageCount,
+                                                sizeof(OBJECTPAGETABLEENTRY),
+                                                (PBYTE*)&pExec->pObjPageTbl,
+                                                &cb)))
+                     && (!(arc = doshReadAt(pExec->hfExe,
+                                            pLXHeader->ulObjPageTblOfs
+                                              + ulNewHeaderOfs,
+                                            FILE_BEGIN,
+                                            &cb,
+                                            (PBYTE)pExec->pObjPageTbl)))
+                   )
+                  ;
+            }
+        }
+
+        if (!arc)
+            pExec->fLXMapsLoaded = TRUE;
+        else
+            doshFreeLXMaps(pExec);
+    }
+
+    return (arc);
+}
+
+/*
+ *@@ doshFreeLXMaps:
+ *      frees only the LX maps allocated by doshLoadLXMaps.
+ *      This gets called automatically by doshExecClose.
+ *
+ *@@added V0.9.16 (2001-12-08) [umoeller]
+ */
+
+VOID doshFreeLXMaps(PEXECUTABLE pExec)
+{
+    FREE(pExec->pRsTbl);
+    FREE(pExec->pObjTbl);
+    FREE(pExec->pObjPageTbl);
+    pExec->fLXMapsLoaded = FALSE;
+}
+
+/*
+ *@@ doshExecClose:
+ *      this closes an executable opened with doshExecOpen.
+ *      Always call this function if NO_ERROR was returned by
+ *      doshExecOpen.
+ *
+ *      This automaticall calls doshFreeLXMaps.
+ *
+ *@@added V0.9.0 [umoeller]
+ *@@changed V0.9.16 (2001-12-08) [umoeller]: fixed memory leaks
+ *@@changed V0.9.16 (2001-12-08) [umoeller]: changed prototype to null the pExec ptr
+ */
+
+APIRET doshExecClose(PEXECUTABLE *ppExec)
+{
+    APIRET arc = NO_ERROR;
+    PEXECUTABLE pExec;
+    if (    (ppExec)
+         && (pExec = *ppExec)
+       )
+    {
+        char **papsz[] =
+            {
+                (char**)&pExec->pDosExeHeader,
+                (char**)&pExec->pNEHeader,
+                (char**)&pExec->pLXHeader,
+                (char**)&pExec->pPEHeader,
+
+                &pExec->pszDescription,
+                &pExec->pszVendor,
+                &pExec->pszVersion,
+                &pExec->pszInfo,
+
+                &pExec->pszBuildDateTime,
+                &pExec->pszBuildMachine,
+                &pExec->pszASD,
+                &pExec->pszLanguage,
+                &pExec->pszCountry,
+                &pExec->pszRevision,
+                &pExec->pszUnknown,
+                &pExec->pszFixpak
+            };
+        ULONG ul;
+
+        doshFreeLXMaps(pExec);
+
+        // fixed the memory leaks with the missing fields,
+        // turned this into a loop
+        for (ul = 0;
+             ul < sizeof(papsz) / sizeof(papsz[0]);
+             ul++)
+        {
+            PSZ pThis;
+            if (pThis = *papsz[ul])
+            {
+                free(pThis);
+                pThis = NULL;
+            }
+        }
+
+        if (pExec->hfExe)
+            arc = DosClose(pExec->hfExe);
+
+        free(pExec);
+        *ppExec = NULL;
+    }
+    else
+        arc = ERROR_INVALID_PARAMETER;
+
+    return (arc);
 }
 
Index: trunk/src/helpers/memdebug.c
===================================================================
--- trunk/src/helpers/memdebug.c	(revision 122)
+++ trunk/src/helpers/memdebug.c	(revision 123)
@@ -32,5 +32,6 @@
  *         is executed, the system might be in a global memory
  *         lock, so DON'T display a message box while in that
- *         function.
+ *         function, and DO NOT call malloc() or other memory
+ *         functions in there.
  *
  *         These debug functions have been added with V0.9.3
@@ -38,4 +39,7 @@
  *
  *         V0.9.6 added realloc() support and fixed a few bugs.
+ *
+ *         With V0.9.16, most of this was rewritten to be much
+ *         faster. This no longer slows down the system enormously.
  *
  *      -- A PM heap debugging window which shows the status
@@ -49,5 +53,6 @@
  *
  *      2) Include memdebug.h AFTER those two. This will remap
- *         the malloc() etc. calls.
+ *         the malloc() etc. calls to the debug functions in
+ *         this file by defining macros for them.
  *
  *         If you don't want those replaced, add
@@ -55,4 +60,7 @@
  *         before including memdebug.h.
  *
+ *         To avoid calling a debug function for a single call,
+ *         place the malloc call (or whatever) in brackets.
+ *
  *      That's all. XWorkplace's setup.h does this automatically
  *      if XWorkplace is compiled with debug code.
@@ -60,13 +68,10 @@
  *      A couple of WARNINGS:
  *
- *      1)  Memory debugging can greatly slow down the system
- *          after a while. When free() is invoked, the memory
- *          that was allocated is freed, but not the memory
- *          log entry (the HEAPITEM) to allow tracing what was
- *          freed. As a result, the linked list of memory items
- *          keeps growing longer, and free() becomes terribly
- *          slow after a while because it must traverse the
- *          entire list for each free() call. Use memdReleaseFreed
- *          from time to time.
+ *      1)  When free() is invoked, the memory that was allocated
+ *          is freed, but not the memory log entry (the HEAPITEM)
+ *          to allow tracing what was freed. As a result, the tree
+ *          of memory items keeps growing longer. Do not expect
+ *          this to work forever, even though things have greatly
+ *          improved with V0.9.16.
  *
  *      2)  The replacement functions in this file allocate
@@ -76,4 +81,6 @@
  *          memory overwrites. Two magic strings are allocated,
  *          one before the actual buffer, and one behind it.
+ *          The pointer returned is _not_ identical to the one
+ *          that was internally allocated.
  *
  *          As a result, YOU MUST NOT confuse the replacement
@@ -119,4 +126,6 @@
 #include <setjmp.h>
 
+#include "helpers\tree.h"
+
 #define DONT_REPLACE_MALLOC             // never do debug memory for this
 #define MEMDEBUG_PRIVATE
@@ -125,5 +134,7 @@
 #ifdef __XWPMEMDEBUG__
 
+#include "helpers\dosh.h"
 #include "helpers\except.h"
+
 #include "helpers\memdebug.h"        // included by setup.h already
 #include "helpers\stringh.h"
@@ -146,13 +157,13 @@
 #define MEMBLOCKMAGIC_TAIL     "\250\210&%/dfjsk%#,dlhf\223"
 
-HMTX            G_hmtxMallocList = NULLHANDLE;
-
-extern PHEAPITEM G_pHeapItemsRoot = NULL;
-PHEAPITEM       G_pHeapItemsLast = NULL;
-
-PFNCBMEMDLOG    G_pMemdLogFunc = NULL;
-
-extern ULONG    G_ulItemsReleased = 0;
-extern ULONG    G_ulBytesReleased = 0;
+HMTX                G_hmtxMallocList = NULLHANDLE;
+
+extern TREE         *G_pHeapItemsRoot = NULL;
+extern LONG         G_cHeapItems = 0;
+
+PFNCBMEMDLOG        G_pMemdLogFunc = NULL;
+
+extern ULONG        G_ulItemsReleased = 0;
+extern ULONG        G_ulBytesReleased = 0;
 
 /* ******************************************************************
@@ -175,16 +186,21 @@
 BOOL memdLock(VOID)
 {
-    APIRET arc = NO_ERROR;
-    if (G_hmtxMallocList == NULLHANDLE)
+    if (!G_hmtxMallocList)
+    {
         // first call:
-        arc = DosCreateMutexSem(NULL,
-                                &G_hmtxMallocList,
-                                0,          // unshared
-                                TRUE);      // request now!
+        if (!DosCreateMutexSem(NULL,
+                               &G_hmtxMallocList,
+                               0,          // unshared
+                               TRUE))      // request now!
+        {
+            treeInit(&G_pHeapItemsRoot, &G_cHeapItems);
+            return TRUE;
+        }
+    }
     else
-        arc = DosRequestMutexSem(G_hmtxMallocList,
-                                 SEM_INDEFINITE_WAIT);
-
-    return (arc == NO_ERROR);
+        return (!DosRequestMutexSem(G_hmtxMallocList,
+                                    SEM_INDEFINITE_WAIT));
+
+    return (FALSE);
 }
 
@@ -199,4 +215,111 @@
 {
     DosReleaseMutexSem(G_hmtxMallocList);
+}
+
+/*
+ *@@ LogError:
+ *
+ *@@added V0.9.16 (2001-12-08) [umoeller]
+ */
+
+VOID LogError(const char *pcszFormat,     // in: format string (like with printf)
+              ...)                        // in: additional stuff (like with printf)
+{
+    if (G_pMemdLogFunc)
+    {
+        CHAR        szMsg[1000];
+        va_list     args;
+
+        va_start(args, pcszFormat);
+        vsprintf(szMsg, pcszFormat, args);
+        va_end(args);
+        G_pMemdLogFunc(szMsg);
+    }
+}
+
+/*
+ *@@ FindHeapItem:
+ *
+ *@@added V0.9.16 (2001-12-08) [umoeller]
+ */
+
+PHEAPITEM FindHeapItem(void *p)
+{
+    return ((PHEAPITEM)treeFind(G_pHeapItemsRoot,
+                                (ULONG)p,
+                                treeCompareKeys));
+}
+
+/*
+ *@@ FillHeapItem:
+ *
+ *@@added V0.9.16 (2001-12-08) [umoeller]
+ */
+
+VOID FillHeapItem(PHEAPITEM pHeapItem,
+                  void *prc,
+                  size_t stSize,
+                  const char *pcszSourceFile, // in: source file name
+                  unsigned long ulLine,       // in: source line
+                  const char *pcszFunction)   // in: function name
+{
+    pHeapItem->ulSize = stSize;
+
+    pHeapItem->pcszSourceFile = pcszSourceFile;
+    pHeapItem->ulLine = ulLine;
+    pHeapItem->pcszFunction = pcszFunction;
+
+    DosGetDateTime(&pHeapItem->dtAllocated);
+
+    pHeapItem->ulTID = doshMyTID();
+
+    pHeapItem->fFreed = FALSE;
+
+    // use the return pointer as the tree sort key
+    // V0.9.16 (2001-12-08) [umoeller]
+    pHeapItem->Tree.ulKey = (ULONG)prc;
+}
+
+/*
+ *@@ CheckMagics:
+ *
+ *@@added V0.9.16 (2001-12-08) [umoeller]
+ */
+
+VOID CheckMagics(const char *pcszParentFunc,
+                 PHEAPITEM pHeapItem,
+                 PBYTE p,
+                 const char *pcszSourceFile, // in: source file name
+                 unsigned long ulLine,       // in: source line
+                 const char *pcszFunction)   // in: function name
+{
+    void    *pBeforeMagic = ((PBYTE)p) - sizeof(MEMBLOCKMAGIC_HEAD);
+    ULONG   ulError = 0;
+
+    // check magic string
+    if (memcmp(pBeforeMagic,
+               MEMBLOCKMAGIC_HEAD,
+               sizeof(MEMBLOCKMAGIC_HEAD)))
+        ulError = 1;
+    else if (memcmp(((PBYTE)p) + pHeapItem->ulSize,
+                    MEMBLOCKMAGIC_TAIL,
+                    sizeof(MEMBLOCKMAGIC_TAIL)))
+        ulError = 2;
+
+    if (ulError)
+    {
+        LogError("%s: Magic string %s memory block at 0x%lX has been overwritten.\n"
+                 "This was detected by the free() call at %s (%s, line %d).\n"
+                 "The block was allocated by %s (%s, line %d).",
+                 pcszParentFunc,
+                 (ulError == 1) ? "before" : "after",
+                 p,
+                 pcszFunction,
+                     pcszSourceFile,
+                     ulLine, // free
+                 pHeapItem->pcszFunction,
+                     pHeapItem->pcszSourceFile,
+                     pHeapItem->ulLine);
+    }
 }
 
@@ -217,4 +340,5 @@
  *
  *@@added V0.9.3 (2000-04-11) [umoeller]
+ *@@changed V0.9.16 (2001-12-08) [umoeller]: reworked to use trees now, much faster
  */
 
@@ -228,91 +352,68 @@
     if (stSize == 0)
         // malloc(0) called: report error
-        if (G_pMemdLogFunc)
+        LogError(__FUNCTION__ ": Function %s (%s, line %d) called malloc(0).",
+                 pcszFunction,
+                     pcszSourceFile,
+                     ulLine);
+    else
+        if (memdLock())
         {
-            CHAR szMsg[1000];
-            sprintf(szMsg,
-                    "Function %s (%s, line %d) called malloc(0).",
-                    pcszFunction,
-                        pcszSourceFile,
-                        ulLine);
-            G_pMemdLogFunc(szMsg);
-        }
-
-    if (memdLock())
-    {
-        // call default malloc(), but with the additional
-        // size of our MEMBLOCKMAGIC strings; we'll return
-        // the first byte after the "front" string so we can
-        // check for string overwrites
-        void *pObj = malloc(stSize
-                            + sizeof(MEMBLOCKMAGIC_HEAD)
-                            + sizeof(MEMBLOCKMAGIC_TAIL));
-        if (pObj)
-        {
-            PHEAPITEM   pHeapItem = (PHEAPITEM)malloc(sizeof(HEAPITEM));
-
-            // store "front" magic string
-            memcpy(pObj,
-                   MEMBLOCKMAGIC_HEAD,
-                   sizeof(MEMBLOCKMAGIC_HEAD));
-            // return address: first byte after "front" magic string
-            prc = ((PBYTE)pObj) + sizeof(MEMBLOCKMAGIC_HEAD);
-            // store "tail" magic string to block which
-            // will be returned plus the size which was requested
-            memcpy(((PBYTE)prc) + stSize,
-                   MEMBLOCKMAGIC_TAIL,
-                   sizeof(MEMBLOCKMAGIC_TAIL));
-
-            if (pHeapItem)
+            // call default malloc(), but with the additional
+            // size of our MEMBLOCKMAGIC strings; we'll return
+            // the first byte after the "front" string so we can
+            // check for string overwrites
+            void *pObj;
+
+            if (pObj = malloc(   sizeof(MEMBLOCKMAGIC_HEAD)
+                               + stSize
+                               + sizeof(MEMBLOCKMAGIC_TAIL)))
             {
-                PTIB        ptib;
-                PPIB        ppib;
-
-                pHeapItem->pNext = 0;
-
-                pHeapItem->pAfterMagic = prc;
-                pHeapItem->ulSize = stSize;
-                pHeapItem->pcszSourceFile = pcszSourceFile;
-                pHeapItem->ulLine = ulLine;
-                pHeapItem->pcszFunction = pcszFunction;
-
-                DosGetDateTime(&pHeapItem->dtAllocated);
-
-                pHeapItem->ulTID = 0;
-
-                if (DosGetInfoBlocks(&ptib, &ppib) == NO_ERROR)
-                    if (ptib)
-                        if (ptib->tib_ptib2)
-                            pHeapItem->ulTID = ptib->tib_ptib2->tib2_ultid;
-
-                pHeapItem->fFreed = FALSE;
-
-                // append heap item to linked list
-                if (G_pHeapItemsRoot == NULL)
-                    // first item:
-                    G_pHeapItemsRoot = pHeapItem;
+                PHEAPITEM pHeapItem;
+                BOOL fInsert = TRUE;
+
+                // store "front" magic string
+                memcpy(pObj,
+                       MEMBLOCKMAGIC_HEAD,
+                       sizeof(MEMBLOCKMAGIC_HEAD));
+                // return address: first byte after "front" magic string
+                prc = ((PBYTE)pObj) + sizeof(MEMBLOCKMAGIC_HEAD);
+                // store "tail" magic string to block which
+                // will be returned plus the size which was requested
+                memcpy(((PBYTE)prc) + stSize,
+                       MEMBLOCKMAGIC_TAIL,
+                       sizeof(MEMBLOCKMAGIC_TAIL));
+
+                if (!(pHeapItem = FindHeapItem(prc)))
+                    // not re-using old address:
+                    // create a new heap item
+                    pHeapItem = (PHEAPITEM)malloc(sizeof(HEAPITEM));
                 else
-                    // we have items already:
-                    if (G_pHeapItemsLast)
+                    fInsert = FALSE;
+
+                FillHeapItem(pHeapItem,
+                             prc,
+                             stSize,
+                             pcszSourceFile,
+                             ulLine,
+                             pcszFunction);
+
+                if (fInsert)
+                    // append heap item to linked list
+                    if (treeInsert(&G_pHeapItemsRoot,
+                                   &G_cHeapItems,
+                                   (TREE*)pHeapItem,
+                                   treeCompareKeys))
                     {
-                        // last item cached:
-                        G_pHeapItemsLast->pNext = pHeapItem;
-                        G_pHeapItemsLast = pHeapItem;
-                    }
-                    else
-                    {
-                        // not cached: find end of list
-                        PHEAPITEM phi = G_pHeapItemsRoot;
-                        while (phi->pNext)
-                            phi = phi->pNext;
-
-                        phi->pNext = pHeapItem;
-                        G_pHeapItemsLast = pHeapItem;
+                        LogError(__FUNCTION__ ": treeInsert failed for memory block at 0x%lX.\n"
+                                 "The block was allocated by %s (%s, line %d).",
+                                 prc,
+                                 pcszFunction,
+                                     pcszSourceFile,
+                                     ulLine);
                     }
             }
+
+            memdUnlock();
         }
-
-        memdUnlock();
-    }
 
     return (prc);
@@ -361,4 +462,5 @@
  *
  *@@added V0.9.3 (2000-04-10) [umoeller]
+ *@@changed V0.9.16 (2001-12-08) [umoeller]: reworked to use trees now, much faster
  */
 
@@ -368,86 +470,58 @@
               const char *pcszFunction)
 {
-    BOOL fFound = FALSE;
     if (memdLock())
     {
-        // PLISTNODE   pNode = lstQueryFirstNode(&G_llHeapItems);
-        PHEAPITEM pHeapItem = G_pHeapItemsRoot;
+        PHEAPITEM pHeapItem;
 
         // search the list with the pointer which was
         // really returned by the original malloc(),
-        // that is, the byte before the magic string
-        void *pBeforeMagic = ((PBYTE)p) - sizeof(MEMBLOCKMAGIC_HEAD);
-
-        while (pHeapItem)
+        // that is, the byte after the magic string
+        if (pHeapItem = FindHeapItem(p))
         {
-            if (pHeapItem->pAfterMagic == p)
+            // the same address may be allocated and freed
+            // several times, so check
+            if (!pHeapItem->fFreed)
             {
-                // the same address may be allocated and freed
-                // several times, so if this address has been
-                // freed, search on
-                if (!pHeapItem->fFreed)
-                {
-                    // found:
-                    ULONG   ulError = 0;
-                    // check magic string
-                    if (memcmp(pBeforeMagic,
-                               MEMBLOCKMAGIC_HEAD,
-                               sizeof(MEMBLOCKMAGIC_HEAD))
-                            != 0)
-                        ulError = 1;
-                    else if (memcmp(((PBYTE)pHeapItem->pAfterMagic) + pHeapItem->ulSize,
-                                    MEMBLOCKMAGIC_TAIL,
-                                    sizeof(MEMBLOCKMAGIC_TAIL))
-                            != 0)
-                        ulError = 2;
-
-                    if (ulError)
-                    {
-                        // magic block has been overwritten:
-                        if (G_pMemdLogFunc)
-                        {
-                            CHAR szMsg[1000];
-                            sprintf(szMsg,
-                                    "Magic string %s memory block at 0x%lX has been overwritten.\n"
-                                    "This was detected by the free() call at %s (%s, line %d).\n"
-                                    "The block was allocated by %s (%s, line %d).",
-                                    (ulError == 1) ? "before" : "after",
-                                    p,
-                                    pcszFunction,
-                                        pcszSourceFile,
-                                        ulLine, // free
-                                    pHeapItem->pcszFunction,
-                                        pHeapItem->pcszSourceFile,
-                                        pHeapItem->ulLine);
-                            G_pMemdLogFunc(szMsg);
-                        }
-                    }
-
-                    free(pBeforeMagic);
-                    pHeapItem->fFreed = TRUE;
-
-                    fFound = TRUE;
-                    break;
-                } // if (!pHeapItem->fFreed)
-            }
-
-            pHeapItem = pHeapItem->pNext;
+                // found:
+                void    *pBeforeMagic = ((PBYTE)p) - sizeof(MEMBLOCKMAGIC_HEAD);
+
+                CheckMagics(__FUNCTION__,
+                            pHeapItem,
+                            p,
+                            pcszSourceFile,
+                            ulLine,
+                            pcszFunction);
+
+                // free the real memory item
+                free(pBeforeMagic);
+
+                // mark the heap item as freed, but
+                // keep it in the list
+                pHeapItem->fFreed = TRUE;
+
+            } // if (!pHeapItem->fFreed)
+            else
+                // memory block has been freed twice:
+                LogError(__FUNCTION__ ": Memory block at 0x%lX has been freed twice.\n"
+                         "This was detected by the free() call at %s (%s, line %d).\n"
+                         "The block was originally allocated by %s (%s, line %d).",
+                         p,
+                         pcszFunction,
+                             pcszSourceFile,
+                             ulLine, // free
+                         pHeapItem->pcszFunction,
+                             pHeapItem->pcszSourceFile,
+                             pHeapItem->ulLine);
         }
+        else
+            // not found:
+            LogError(__FUNCTION__ ": free() called with invalid object 0x%lX from %s (%s, line %d).",
+                     p,
+                     pcszFunction,
+                         pcszSourceFile,
+                         ulLine);
 
         memdUnlock();
     }
-
-    if (!fFound)
-        if (G_pMemdLogFunc)
-        {
-            CHAR szMsg[1000];
-            sprintf(szMsg,
-                    "free() called with invalid object from %s (%s, line %d) for object 0x%lX.",
-                    pcszFunction,
-                        pcszSourceFile,
-                        ulLine,
-                    p);
-            G_pMemdLogFunc(szMsg);
-        }
 }
 
@@ -459,4 +533,5 @@
  *@@added V0.9.6 (2000-11-12) [umoeller]
  *@@changed V0.9.12 (2001-05-21) [umoeller]: this reported errors on realloc(0), which is a valid call, fixed
+ *@@changed V0.9.16 (2001-12-08) [umoeller]: reworked to use trees now, much faster
  */
 
@@ -468,5 +543,4 @@
 {
     void *prc = NULL;
-    BOOL fFound = FALSE;
 
     if (!p)
@@ -477,128 +551,117 @@
     if (memdLock())
     {
-        PHEAPITEM pHeapItem = G_pHeapItemsRoot;
-
         // search the list with the pointer which was
         // really returned by the original malloc(),
-        // that is, the byte before the magic string
-        void *pBeforeMagic = ((PBYTE)p) - sizeof(MEMBLOCKMAGIC_HEAD);
-
-        while (pHeapItem)
+        // that is, the byte after the magic string
+        PHEAPITEM pHeapItem, pExisting;
+        if (pHeapItem = FindHeapItem(p))
         {
-            if (pHeapItem->pAfterMagic == p)
-                // the same address may be allocated and freed
-                // several times, so if this address has been
-                // freed, search on
-                if (!pHeapItem->fFreed)
+            // found:
+            if (pHeapItem->fFreed)
+            {
+                LogError(__FUNCTION__ ": realloc() called with memory block at 0x%lX that was already freed.\n"
+                         "This was detected by the realloc() call at %s (%s, line %d).\n"
+                         "The block was originally allocated by %s (%s, line %d).",
+                         p,
+                         pcszFunction,
+                             pcszSourceFile,
+                             ulLine, // free
+                         pHeapItem->pcszFunction,
+                             pHeapItem->pcszSourceFile,
+                             pHeapItem->ulLine);
+            }
+            else
+            {
+                // block is valid:
+                void    *pBeforeMagic = ((PBYTE)p) - sizeof(MEMBLOCKMAGIC_HEAD);
+                PVOID   pObjNew = 0;
+                ULONG   ulError = 0;
+                ULONG   cbCopy = 0;
+
+                CheckMagics(__FUNCTION__,
+                            pHeapItem,
+                            p,
+                            pcszSourceFile,
+                            ulLine,
+                            pcszFunction);
+
+                // now reallocate!
+                pObjNew = malloc(   sizeof(MEMBLOCKMAGIC_HEAD)
+                                  + stSize   // new size
+                                  + sizeof(MEMBLOCKMAGIC_TAIL));
+
+                // store "front" magic string
+                memcpy(pObjNew,
+                       MEMBLOCKMAGIC_HEAD,
+                       sizeof(MEMBLOCKMAGIC_HEAD));
+                // return address: first byte after "front" magic string
+                prc = ((PBYTE)pObjNew) + sizeof(MEMBLOCKMAGIC_HEAD);
+
+                // bytes to copy: the smaller of the old and the new size
+                cbCopy = pHeapItem->ulSize;
+                if (stSize < pHeapItem->ulSize)
+                    cbCopy = stSize;
+
+                // copy buffer from old memory object
+                memcpy(prc,         // after "front" magic
+                       p,
+                       cbCopy);
+
+                // store "tail" magic string to block which
+                // will be returned plus the size which was requested
+                memcpy(((PBYTE)prc) + stSize,
+                       MEMBLOCKMAGIC_TAIL,
+                       sizeof(MEMBLOCKMAGIC_TAIL));
+
+                // free the old buffer
+                free(pBeforeMagic);
+
+                // update the tree, since prc has changed
+                treeDelete(&G_pHeapItemsRoot,
+                           &G_cHeapItems,
+                           (TREE*)pHeapItem);
+                // append heap item to linked list
+                if (pExisting = FindHeapItem(prc))
                 {
-                    // found:
-                    PVOID   pObjNew = 0;
-                    ULONG   ulError = 0;
-                    ULONG   cbCopy = 0;
-                    PTIB    ptib;
-                    PPIB    ppib;
-
-                    // check magic string
-                    if (memcmp(pBeforeMagic,
-                               MEMBLOCKMAGIC_HEAD,
-                               sizeof(MEMBLOCKMAGIC_HEAD))
-                            != 0)
-                        ulError = 1;
-                    else if (memcmp(((PBYTE)pHeapItem->pAfterMagic) + pHeapItem->ulSize,
-                                    MEMBLOCKMAGIC_TAIL,
-                                    sizeof(MEMBLOCKMAGIC_TAIL))
-                            != 0)
-                        ulError = 2;
-
-                    if (ulError)
+                    // a different heap item exists for this address:
+                    // delete this one and use that instead; there's
+                    // no need to re-insert either
+                    free(pHeapItem);
+                    pHeapItem = pExisting;
+                }
+
+                FillHeapItem(pHeapItem,
+                             prc,
+                             stSize,
+                             pcszSourceFile,
+                             ulLine,
+                             pcszFunction);
+
+                // insert only if we didn't use an existing item
+                if (!pExisting)
+                    if (treeInsert(&G_pHeapItemsRoot,
+                                   &G_cHeapItems,
+                                   (TREE*)pHeapItem,
+                                   treeCompareKeys))
                     {
-                        // magic block has been overwritten:
-                        if (G_pMemdLogFunc)
-                        {
-                            CHAR szMsg[1000];
-                            sprintf(szMsg,
-                                    "Magic string %s memory block at 0x%lX has been overwritten.\n"
-                                    "This was detected by the realloc() call at %s (%s, line %d).\n"
-                                    "The block was allocated by %s (%s, line %d).",
-                                    (ulError == 1) ? "before" : "after",
-                                    p,
-                                    pcszFunction,
-                                        pcszSourceFile,
-                                        ulLine, // free
-                                    pHeapItem->pcszFunction,
-                                        pHeapItem->pcszSourceFile,
-                                        pHeapItem->ulLine);
-                            G_pMemdLogFunc(szMsg);
-                        }
+                        LogError(__FUNCTION__ ": treeInsert failed for memory block at 0x%lX.\n"
+                                 "The block was allocated by %s (%s, line %d).",
+                                 prc,
+                                 pcszFunction,
+                                     pcszSourceFile,
+                                     ulLine);
                     }
 
-                    // now reallocate!
-                    pObjNew = malloc(stSize   // new size
-                                     + sizeof(MEMBLOCKMAGIC_HEAD)
-                                     + sizeof(MEMBLOCKMAGIC_TAIL));
-
-                    // store "front" magic string
-                    memcpy(pObjNew,
-                           MEMBLOCKMAGIC_HEAD,
-                           sizeof(MEMBLOCKMAGIC_HEAD));
-                    // return address: first byte after "front" magic string
-                    prc = ((PBYTE)pObjNew) + sizeof(MEMBLOCKMAGIC_HEAD);
-
-                    // bytes to copy: the smaller of the old and the new size
-                    cbCopy = pHeapItem->ulSize;
-                    if (stSize < pHeapItem->ulSize)
-                        cbCopy = stSize;
-
-                    // copy buffer from old memory object
-                    memcpy(prc,         // after "front" magic
-                           pHeapItem->pAfterMagic,
-                           cbCopy);
-
-                    // store "tail" magic string to block which
-                    // will be returned plus the size which was requested
-                    memcpy(((PBYTE)prc) + stSize,
-                           MEMBLOCKMAGIC_TAIL,
-                           sizeof(MEMBLOCKMAGIC_TAIL));
-
-                    // free the old buffer
-                    free(pBeforeMagic);
-
-                    // update the HEAPITEM
-                    pHeapItem->pAfterMagic = prc;       // new pointer!
-                    pHeapItem->ulSize = stSize;         // new size!
-                    pHeapItem->pcszSourceFile = pcszSourceFile;
-                    pHeapItem->ulLine = ulLine;
-                    pHeapItem->pcszFunction = pcszFunction;
-
-                    // update date, time, TID
-                    DosGetDateTime(&pHeapItem->dtAllocated);
-                    pHeapItem->ulTID = 0;
-                    if (DosGetInfoBlocks(&ptib, &ppib) == NO_ERROR)
-                        if (ptib)
-                            if (ptib->tib_ptib2)
-                                pHeapItem->ulTID = ptib->tib_ptib2->tib2_ultid;
-
-                    fFound = TRUE;
-                    break;
-                } // if (!pHeapItem->fFreed)
-
-            pHeapItem = pHeapItem->pNext;
+            } // if (!pHeapItem->fFreed)
         }
+        else
+            LogError(__FUNCTION__ ": realloc() called with invalid object from %s (%s, line %d) for object 0x%lX.",
+                     pcszFunction,
+                         pcszSourceFile,
+                         ulLine,
+                     p);
 
         memdUnlock();
     }
-
-    if (!fFound)
-        if (G_pMemdLogFunc)
-        {
-            CHAR szMsg[1000];
-            sprintf(szMsg,
-                    "realloc() called with invalid object from %s (%s, line %d) for object 0x%lX.",
-                    pcszFunction,
-                        pcszSourceFile,
-                        ulLine,
-                    p);
-            G_pMemdLogFunc(szMsg);
-        }
 
     return (prc);
@@ -624,11 +687,10 @@
     if (memdLock())
     {
-        PHEAPITEM pHeapItem = G_pHeapItemsRoot,
-                  pPrevious = NULL;
+        /* PHEAPITEM pHeapItem = treeFirst(G_pHeapItemsRoot);
 
         while (pHeapItem)
         {
             // store next first, because we can change the "next" pointer
-            PHEAPITEM   pNext = pHeapItem->pNext;       // can be NULL
+            PHEAPITEM   pNext = treeNext(pHeapItem);
 
             if (pHeapItem->fFreed)
@@ -658,5 +720,5 @@
             pHeapItem = pNext;
         }
-
+        */
         G_ulItemsReleased += ulItemsReleased;
         G_ulBytesReleased += ulBytesReleased;
Index: trunk/src/helpers/memdebug_win.c
===================================================================
--- trunk/src/helpers/memdebug_win.c	(revision 122)
+++ trunk/src/helpers/memdebug_win.c	(revision 123)
@@ -47,4 +47,6 @@
 #include <setjmp.h>
 
+#include "helpers\tree.h"
+
 #define DONT_REPLACE_MALLOC             // never do debug memory for this
 #define MEMDEBUG_PRIVATE
@@ -56,4 +58,5 @@
 #include "helpers\except.h"
 // #include "helpers\memdebug.h"        // included by setup.h already
+#include "helpers\nls.h"
 #include "helpers\stringh.h"
 #include "helpers\winh.h"
@@ -278,118 +281,126 @@
 {
     // count heap items
-    ULONG       ulHeapItemsCount1 = 0;
+    // ULONG       ulHeapItemsCount1 = 0;
     PMEMRECORD  pMemRecordFirst;
 
-    if (memdLock())
+    ULONG       cHeapItems = 0;
+    BOOL        fLocked = FALSE;
+
+    TRY_LOUD(excpt1)
     {
-        PHEAPITEM pHeapItem = G_pHeapItemsRoot;
-
-        *pulTotalItems = 0;
-        *pulAllocatedItems = 0;
-        *pulFreedItems = 0;
-
-        *pulTotalBytes = 0;
-        *pulAllocatedBytes = 0;
-        *pulFreedBytes = 0;
-
-        while (pHeapItem)
+        if (fLocked = memdLock())
         {
-            ulHeapItemsCount1++;
-            if (pHeapItem->fFreed)
+            PHEAPITEM pHeapItem = (PHEAPITEM)treeFirst(G_pHeapItemsRoot);
+
+            *pulTotalItems = 0;
+            *pulAllocatedItems = 0;
+            *pulFreedItems = 0;
+
+            *pulTotalBytes = 0;
+            *pulAllocatedBytes = 0;
+            *pulFreedBytes = 0;
+
+            *pulTotalItems = G_cHeapItems;
+
+            if (pMemRecordFirst = (PMEMRECORD)cnrhAllocRecords(hwndCnr,
+                                                               sizeof(MEMRECORD),
+                                                               G_cHeapItems))
             {
-                (*pulFreedItems)++;
-                (*pulFreedBytes) += pHeapItem->ulSize;
+                PMEMRECORD  pMemRecordThis = pMemRecordFirst;
+                pHeapItem = (PHEAPITEM)treeFirst(G_pHeapItemsRoot);
+
+                while ((pMemRecordThis) && (pHeapItem))
+                {
+                    if (pHeapItem->fFreed)
+                    {
+                        (*pulFreedItems)++;
+                        (*pulFreedBytes) += pHeapItem->ulSize;
+                    }
+                    else
+                    {
+                        (*pulAllocatedItems)++;
+                        (*pulAllocatedBytes) += pHeapItem->ulSize;
+                    }
+
+                    (*pulTotalBytes) += pHeapItem->ulSize;
+
+                    pMemRecordThis->ulIndex = cHeapItems++;
+
+                    cnrhDateTimeDos2Win(&pHeapItem->dtAllocated,
+                                        &pMemRecordThis->cdateAllocated,
+                                        &pMemRecordThis->ctimeAllocated);
+
+                    if (pHeapItem->fFreed)
+                        pMemRecordThis->pszFreed = "yes";
+
+                    pMemRecordThis->ulTID = pHeapItem->ulTID;
+
+                    strhcpy(pMemRecordThis->szSource, pHeapItem->pcszSourceFile);
+                    pMemRecordThis->pszSource = pMemRecordThis->szSource;
+
+                    pMemRecordThis->ulLine = pHeapItem->ulLine;
+
+                    strhcpy(pMemRecordThis->szFunction, pHeapItem->pcszFunction);
+                    pMemRecordThis->pszFunction = pMemRecordThis->szFunction;
+
+                    pMemRecordThis->ulAddress = pHeapItem->Tree.ulKey;
+
+                    sprintf(pMemRecordThis->szAddress,
+                            "0x%lX",
+                            pHeapItem->Tree.ulKey);
+                    pMemRecordThis->pszAddress = pMemRecordThis->szAddress;
+
+                    pMemRecordThis->ulSize = pHeapItem->ulSize;
+
+
+                    /* switch (pMemRecordThis->useflag)
+                    {
+                        case _USEDENTRY: pMemRecordThis->pszUseFlag = "Used"; break;
+                        case _FREEENTRY: pMemRecordThis->pszUseFlag = "Freed"; break;
+                    }
+
+                    switch (pMemRecordThis->status)
+                    {
+                        case _HEAPBADBEGIN: pMemRecordThis->pszStatus = "heap bad begin"; break;
+                        case _HEAPBADNODE: pMemRecordThis->pszStatus = "heap bad node"; break;
+                        case _HEAPEMPTY: pMemRecordThis->pszStatus = "heap empty"; break;
+                        case _HEAPOK: pMemRecordThis->pszStatus = "OK"; break;
+                    }
+
+                    sprintf(pMemRecordThis->szAddress, "0x%lX", pMemRecordThis->pObject);
+                    strhcpy(pMemRecordThis->szSource,
+                            (pMemRecordThis->filename)
+                                ? pMemRecordThis->filename
+                                : "?"); */
+
+                    pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
+                    pHeapItem = (PHEAPITEM)treeNext((TREE*)pHeapItem);
+                }
+
+                cnrhInsertRecords(hwndCnr,
+                                  NULL,         // parent
+                                  (PRECORDCORE)pMemRecordFirst,
+                                  TRUE,
+                                  NULL,
+                                  CRA_RECORDREADONLY,
+                                  cHeapItems);
             }
-            else
-            {
-                (*pulAllocatedItems)++;
-                (*pulAllocatedBytes) += pHeapItem->ulSize;
-            }
-
-            (*pulTotalBytes) += pHeapItem->ulSize;
-
-            pHeapItem = pHeapItem->pNext;
         }
-
-        *pulTotalItems = ulHeapItemsCount1;
-
-        pMemRecordFirst = (PMEMRECORD)cnrhAllocRecords(hwndCnr,
-                                                       sizeof(MEMRECORD),
-                                                       ulHeapItemsCount1);
-        if (pMemRecordFirst)
+    }
+    CATCH(excpt1)
+    {
+        if (G_pMemdLogFunc)
         {
-            ULONG       ulHeapItemsCount2 = 0;
-            PMEMRECORD  pMemRecordThis = pMemRecordFirst;
-            pHeapItem = G_pHeapItemsRoot;
-            // PLISTNODE   pMemNode = lstQueryFirstNode(&G_llHeapItems);
-
-            while ((pMemRecordThis) && (pHeapItem))
-            {
-                // PHEAPITEM pHeapItem = (PHEAPITEM)pMemNode->pItemData;
-
-                pMemRecordThis->ulIndex = ulHeapItemsCount2++;
-
-                cnrhDateTimeDos2Win(&pHeapItem->dtAllocated,
-                                    &pMemRecordThis->cdateAllocated,
-                                    &pMemRecordThis->ctimeAllocated);
-
-                if (pHeapItem->fFreed)
-                    pMemRecordThis->pszFreed = "yes";
-
-                pMemRecordThis->ulTID = pHeapItem->ulTID;
-
-                strhcpy(pMemRecordThis->szSource, pHeapItem->pcszSourceFile);
-                pMemRecordThis->pszSource = pMemRecordThis->szSource;
-
-                pMemRecordThis->ulLine = pHeapItem->ulLine;
-
-                strhcpy(pMemRecordThis->szFunction, pHeapItem->pcszFunction);
-                pMemRecordThis->pszFunction = pMemRecordThis->szFunction;
-
-                pMemRecordThis->ulAddress = (ULONG)pHeapItem->pAfterMagic;
-
-                sprintf(pMemRecordThis->szAddress,
-                        "0x%lX",
-                        pHeapItem->pAfterMagic);
-                pMemRecordThis->pszAddress = pMemRecordThis->szAddress;
-
-                pMemRecordThis->ulSize = pHeapItem->ulSize;
-
-
-                /* switch (pMemRecordThis->useflag)
-                {
-                    case _USEDENTRY: pMemRecordThis->pszUseFlag = "Used"; break;
-                    case _FREEENTRY: pMemRecordThis->pszUseFlag = "Freed"; break;
-                }
-
-                switch (pMemRecordThis->status)
-                {
-                    case _HEAPBADBEGIN: pMemRecordThis->pszStatus = "heap bad begin"; break;
-                    case _HEAPBADNODE: pMemRecordThis->pszStatus = "heap bad node"; break;
-                    case _HEAPEMPTY: pMemRecordThis->pszStatus = "heap empty"; break;
-                    case _HEAPOK: pMemRecordThis->pszStatus = "OK"; break;
-                }
-
-                sprintf(pMemRecordThis->szAddress, "0x%lX", pMemRecordThis->pObject);
-                strhcpy(pMemRecordThis->szSource,
-                        (pMemRecordThis->filename)
-                            ? pMemRecordThis->filename
-                            : "?"); */
-
-                pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;
-                pHeapItem = pHeapItem->pNext;
-            }
-
-            cnrhInsertRecords(hwndCnr,
-                              NULL,         // parent
-                              (PRECORDCORE)pMemRecordFirst,
-                              TRUE,
-                              NULL,
-                              CRA_RECORDREADONLY,
-                              ulHeapItemsCount2);
+            CHAR        szMsg[1000];
+            sprintf(szMsg,
+                    "Crash occured at object #%d out of %d",
+                    cHeapItems,
+                    G_cHeapItems);
+            G_pMemdLogFunc(szMsg);
         }
-
+    } END_CATCH();
+
+    if (fLocked)
         memdUnlock();
-    }
 }
 
@@ -625,26 +636,26 @@
                                 "    Total memory logs freed: %s items = %s bytes\n"
                                 "Total memory logs freed and discarded: %s items = %s bytes",
-                                strhThousandsDouble(szTotalItems,
+                                nlsThousandsDouble(szTotalItems,
                                                     ulTotalItems,
                                                     '.'),
-                                strhThousandsDouble(szTotalBytes,
+                                nlsThousandsDouble(szTotalBytes,
                                                     ulTotalBytes,
                                                     '.'),
-                                strhThousandsDouble(szAllocatedItems,
+                                nlsThousandsDouble(szAllocatedItems,
                                                     ulAllocatedItems,
                                                     '.'),
-                                strhThousandsDouble(szAllocatedBytes,
+                                nlsThousandsDouble(szAllocatedBytes,
                                                     ulAllocatedBytes,
                                                     '.'),
-                                strhThousandsDouble(szFreedItems,
+                                nlsThousandsDouble(szFreedItems,
                                                     ulFreedItems,
                                                     '.'),
-                                strhThousandsDouble(szFreedBytes,
+                                nlsThousandsDouble(szFreedBytes,
                                                     ulFreedBytes,
                                                     '.'),
-                                strhThousandsDouble(szReleasedItems,
+                                nlsThousandsDouble(szReleasedItems,
                                                     G_ulItemsReleased,
                                                     '.'),
-                                strhThousandsDouble(szReleasedBytes,
+                                nlsThousandsDouble(szReleasedBytes,
                                                     G_ulBytesReleased,
                                                     '.'));
Index: trunk/src/helpers/stringh.c
===================================================================
--- trunk/src/helpers/stringh.c	(revision 122)
+++ trunk/src/helpers/stringh.c	(revision 123)
@@ -42,4 +42,5 @@
 
 #define INCL_WINSHELLDATA
+#define INCL_DOSERRORS
 #include <os2.h>
 
@@ -68,4 +69,51 @@
  */
 
+#ifdef __DEBUG_MALLOC_ENABLED__
+
+/*
+ *@@ strhStoreDebug:
+ *      memory debug version of strhStore.
+ *
+ *@@added V0.9.16 (2001-12-08) [umoeller]
+ */
+
+APIRET strhStoreDebug(PSZ *ppszTarget,
+                      PCSZ pcszSource,
+                      PULONG pulLength,        // out: length of new string (ptr can be NULL)
+                      const char *pcszSourceFile,
+                      unsigned long ulLine,
+                      const char *pcszFunction)
+{
+    ULONG ulLength = 0;
+
+    if (ppszTarget)
+    {
+        if (*ppszTarget)
+            free(*ppszTarget);
+
+        if (    (pcszSource)
+             && (ulLength = strlen(pcszSource))
+           )
+        {
+            if (*ppszTarget = (PSZ)memdMalloc(ulLength + 1,
+                                              pcszSourceFile,
+                                              ulLine,
+                                              pcszFunction))
+                memcpy(*ppszTarget, pcszSource, ulLength + 1);
+            else
+                return (ERROR_NOT_ENOUGH_MEMORY);
+        }
+        else
+            *ppszTarget = NULL;
+    }
+
+    if (pulLength)
+        *pulLength = ulLength;
+
+    return (NO_ERROR);
+}
+
+#endif
+
 /*
  *@@ strhStore:
@@ -81,7 +129,7 @@
  */
 
-VOID strhStore(PSZ *ppszTarget,
-               PCSZ pcszSource,
-               PULONG pulLength)        // out: length of new string (ptr can be NULL)
+APIRET strhStore(PSZ *ppszTarget,
+                 PCSZ pcszSource,
+                 PULONG pulLength)        // out: length of new string (ptr can be NULL)
 {
     ULONG ulLength = 0;
@@ -98,4 +146,6 @@
             if (*ppszTarget = (PSZ)malloc(ulLength + 1))
                 memcpy(*ppszTarget, pcszSource, ulLength + 1);
+            else
+                return (ERROR_NOT_ENOUGH_MEMORY);
         }
         else
@@ -105,4 +155,6 @@
     if (pulLength)
         *pulLength = ulLength;
+
+    return (NO_ERROR);
 }
 
@@ -127,5 +179,5 @@
 
 /*
- *@@ strhdup:
+ *@@ strhdupDebug:
  *      memory debug version of strhdup.
  *
@@ -133,5 +185,5 @@
  */
 
-PSZ strhdupDebug(const char *pszSource,
+PSZ strhdupDebug(const char *pcszSource,
                  unsigned long *pulLength,
                  const char *pcszSourceFile,
@@ -147,5 +199,5 @@
     {
         if (pszReturn = (PSZ)memdMalloc(ulLength + 1,
-                                        pcszSourceFile,
+                                        pcszSourceFile,     // fixed V0.9.16 (2001-12-08) [umoeller]
                                         ulLine,
                                         pcszFunction))
Index: trunk/src/helpers/threads.c
===================================================================
--- trunk/src/helpers/threads.c	(revision 122)
+++ trunk/src/helpers/threads.c	(revision 123)
@@ -40,4 +40,5 @@
     // as unsigned char
 
+#define INCL_WINMESSAGEMGR
 #define INCL_DOSPROCESS
 #define INCL_DOSSEMAPHORES
@@ -130,4 +131,6 @@
     if (pti)
     {
+        HEV hevExitComplete;
+
         if (pti->flFlags & THRF_WAIT)
             // "Wait" flag set: thrCreate is then
@@ -168,7 +171,9 @@
         }
 
+        // copy event sem before freeing pti
+        hevExitComplete = pti->hevExitComplete;
+
         // set exit flags
         // V0.9.7 (2000-12-20) [umoeller]
-        pti->fExitComplete = TRUE;
         pti->tid = NULLHANDLE;
 
@@ -180,4 +185,9 @@
         if (pti->flFlags & THRF_TRANSIENT)
             free(pti);
+
+        if (hevExitComplete)
+            // caller wants notification:
+            DosPostEventSem(hevExitComplete);
+                    // V0.9.16 (2001-12-08) [umoeller]
     }
 
@@ -394,4 +404,5 @@
  *@@added V0.9.5 (2000-08-26) [umoeller]
  *@@changed V0.9.9 (2001-03-07) [umoeller]: added pcszThreadName
+ *@@changed V0.9.16 (2001-12-08) [umoeller]: fixed hang with thrWait
  */
 
@@ -417,11 +428,17 @@
     {
         THREADINFO  ti = {0};
+        volatile unsigned long tidRunning = 0;
         thrCreate(&ti,
                   pfn,
-                  NULL,
+                  &tidRunning,
                   pcszThreadName,
                   THRF_PMMSGQUEUE,
                   ulData);
         ti.hwndNotify = hwndNotify;
+        // create event sem to wait on V0.9.16 (2001-12-08) [umoeller]
+        DosCreateEventSem(NULL,
+                          &ti.hevExitComplete,
+                          0,
+                          FALSE);       // not posted
 
         while (WinGetMsg(hab,
@@ -445,5 +462,8 @@
         // otherwise THREADINFO is deleted from the stack
         // before the thread exits... will crash!
-        thrWait(&ti);
+        // thrWait(&ti);
+        // now using event sem V0.9.16 (2001-12-08) [umoeller]
+        WinWaitEventSem(ti.hevExitComplete, 5000);
+        DosCloseEventSem(ti.hevExitComplete);
 
         WinDestroyWindow(hwndNotify);
@@ -481,5 +501,4 @@
         PLISTNODE pNode;
         *pcThreads = lstCountItems(&G_llThreadInfos);
-        _Pmpf((__FUNCTION__ ": got %d threads", *pcThreads));
         pArray = (PTHREADINFO)malloc(*pcThreads * sizeof(THREADINFO));
         pThis = pArray;
@@ -561,4 +580,7 @@
  *      the thread will actually terminate.
  *
+ *      Update V0.9.16: Do not use this with PM theads at
+ *      all. DosWaitThread can hang the system then.
+ *
  *      Returns FALSE if the thread wasn't running or TRUE
  *      if it was and has terminated.
@@ -631,6 +653,5 @@
 {
     if (pti)
-        if (!(pti->fExitComplete))
-            return (pti->tid);
+        return (pti->tid);
 
     return (NULLHANDLE);
Index: trunk/src/helpers/timer.c
===================================================================
--- trunk/src/helpers/timer.c	(revision 122)
+++ trunk/src/helpers/timer.c	(revision 123)
@@ -540,6 +540,7 @@
                                 // window still valid:
                                 // get the window's window proc
-                                PFNWP pfnwp = (PFNWP)WinQueryWindowPtr(pTimer->hwndTarget,
-                                                                       QWP_PFNWP);
+                                QMSG qmsg;
+                                /* PFNWP pfnwp = (PFNWP)WinQueryWindowPtr(pTimer->hwndTarget,
+                                                                       QWP_PFNWP); */
 
                                 // moved this up V0.9.14 (2001-08-01) [umoeller]
@@ -547,8 +548,18 @@
 
                                 // call the window proc DIRECTLY
-                                pfnwp(pTimer->hwndTarget,
+                                qmsg.hwnd = pTimer->hwndTarget;
+                                qmsg.msg = WM_TIMER;
+                                qmsg.mp1 = (MPARAM)pTimer->usTimerID;
+                                qmsg.mp2 = (MPARAM)0;
+                                qmsg.time = 0;
+                                qmsg.ptl.x = 0;
+                                qmsg.ptl.y = 0;
+                                qmsg.reserved = 0;
+                                WinDispatchMsg(pSet->hab,
+                                               &qmsg);
+                                /* pfnwp(pTimer->hwndTarget,
                                       WM_TIMER,
                                       (MPARAM)pTimer->usTimerID,
-                                      0);
+                                      0); */
                                     // V0.9.12 (2001-05-24) [umoeller]
                                     // if the winproc chooses to start or
