Index: trunk/src/helpers/cnrh.c
===================================================================
--- trunk/src/helpers/cnrh.c	(revision 105)
+++ trunk/src/helpers/cnrh.c	(revision 106)
@@ -1962,102 +1962,145 @@
  *      cores.
  *
- *      Presently, this function supports drawing record
- *      cores in gray color if the record has the CRA_DISABLED
- *      style (which, AFAIK, PM ignores per default).
+ *      What this draws depends on flFlags:
+ *
+ *      --  If CODFL_DISABLEDTEXT is set, this function supports
+ *          drawing record cores in gray color if the record has
+ *          the CRA_DISABLED style (which, AFAIK, PM ignores per
+ *          default).
+ *
+ *      --  If CODFL_MINIICON is set, this function paints the
+ *          record's mini-icon properly. So far I have failed
+ *          to find out how to get a container to paint the
+ *          correct mini-icon if the CV_MINI style is set...
+ *          the container normally _does_ paint a small icon,
+ *          but it won't use the "real" mini icon data if that
+ *          is present.
+ *
+ *          For painting the mini-icon, WinDrawPointer is used
+ *          with DP_MINI set properly and the RECORDCORE's
+ *          hptrMiniIcon field.
  *
  *      This returns either TRUE or FALSE as an MPARAM, depending
  *      on whether we have drawn the item. This return value should
  *      also be the return value of your window procedure.
- */
-
-MRESULT cnrhOwnerDrawRecord(MPARAM mp2) // in: mp2 of WM_DRAWITEM (POWNERITEM)
-{
-    MRESULT mrc = 0;
+ *
+ *@@changed V0.9.16 (2001-09-29) [umoeller]: added flFlags, icon draw support
+ */
+
+MRESULT cnrhOwnerDrawRecord(MPARAM mp2,     // in: mp2 of WM_DRAWITEM (POWNERITEM)
+                            ULONG flFlags)  // in: CODFL_* flags
+{
+    MRESULT mrc = (MPARAM)FALSE; // tell cnr to draw the item
 
     // get generic DRAWITEM structure
-    POWNERITEM poi = (POWNERITEM)mp2;
-
-    // check if we're to draw the text
-    // (and not the icon)
-    if (poi->idItem == CMA_TEXT)
+    POWNERITEM poi;
+
+    if (poi = (POWNERITEM)mp2)
     {
         // get container-specific draw-item struct
         PCNRDRAWITEMINFO pcdii = (PCNRDRAWITEMINFO)poi->hItem;
 
-        if (((pcdii->pRecord->flRecordAttr) & CRA_DISABLED) == 0)
+        // check if we're to draw the text
+        // (and not the icon)
+        if (    (poi->idItem == CMA_TEXT)
+             && (flFlags & CODFL_DISABLEDTEXT)
+           )
         {
-            /*
-            // not disabled == valid WPS class
-            if ((pcdii->pRecord->flRecordAttr) & CRA_SELECTED)
+            if (((pcdii->pRecord->flRecordAttr) & CRA_DISABLED) == 0)
             {
-                // not disabled, but selected:
-                lBackground = winhQueryPresColor(hwndDlg, PP_HILITEBACKGROUNDCOLOR, SYSCLR_HILITEBACKGROUND);
-                lForeground = winhQueryPresColor(hwndDlg, PP_HILITEFOREGROUNDCOLOR, SYSCLR_HILITEFOREGROUND);
+                /*
+                // not disabled == valid WPS class
+                if ((pcdii->pRecord->flRecordAttr) & CRA_SELECTED)
+                {
+                    // not disabled, but selected:
+                    lBackground = winhQueryPresColor(hwndDlg, PP_HILITEBACKGROUNDCOLOR, SYSCLR_HILITEBACKGROUND);
+                    lForeground = winhQueryPresColor(hwndDlg, PP_HILITEFOREGROUNDCOLOR, SYSCLR_HILITEFOREGROUND);
+                }
+                else
+                {
+                    // not disabled, not selected:
+                    lBackground = winhQueryPresColor(hwndDlg, PP_BACKGROUNDCOLOR, SYSCLR_BACKGROUND);
+                    lForeground = winhQueryPresColor(hwndDlg, PP_FOREGROUNDCOLOR, SYSCLR_WINDOWTEXT);
+                } */
+                mrc = FALSE;
+                    // let cnr draw the thing
             }
             else
             {
-                // not disabled, not selected:
-                lBackground = winhQueryPresColor(hwndDlg, PP_BACKGROUNDCOLOR, SYSCLR_BACKGROUND);
-                lForeground = winhQueryPresColor(hwndDlg, PP_FOREGROUNDCOLOR, SYSCLR_WINDOWTEXT);
-            } */
-            mrc = FALSE;
-                // let cnr draw the thing
+                // CRA_DISABLED:
+
+                ULONG flCmd = DT_LEFT | DT_TOP | DT_ERASERECT;
+                RECTL rcl2;
+
+                // set draw colors
+                LONG  lBackground,
+                      lForeground;
+
+                // switch to RGB
+                GpiCreateLogColorTable(poi->hps, 0, LCOLF_RGB, 0, 0, NULL);
+
+                if ((pcdii->pRecord->flRecordAttr) & CRA_SELECTED)
+                {
+                    // disabled and selected:
+                    lBackground = WinQuerySysColor(HWND_DESKTOP,
+                                                   SYSCLR_SHADOWTEXT, 0);
+                    lForeground = winhQueryPresColor(poi->hwnd,
+                                                     PP_BACKGROUNDCOLOR,
+                                                     FALSE, // no inherit
+                                                     SYSCLR_WINDOW);
+                }
+                else
+                {
+                    // disabled and not selected:
+                    lBackground = winhQueryPresColor(poi->hwnd,
+                                                     PP_BACKGROUNDCOLOR,
+                                                     FALSE,
+                                                     SYSCLR_WINDOW);
+                    lForeground = WinQuerySysColor(HWND_DESKTOP,
+                                                   SYSCLR_SHADOWTEXT, 0);
+                }
+
+                memcpy(&rcl2, &(poi->rclItem), sizeof(rcl2));
+                /* WinDrawText(poi->hps,
+                            strlen(pcdii->pRecord->pszText),
+                            pcdii->pRecord->pszText,
+                            &rcl2,
+                            lForeground,  // foreground
+                            lBackground,
+                            flCmd); */
+
+                GpiSetBackColor(poi->hps, lBackground);
+                GpiSetColor(poi->hps, lForeground);
+
+                winhDrawFormattedText(poi->hps,
+                                      &rcl2,
+                                      pcdii->pRecord->pszText,
+                                      flCmd);
+
+                mrc = (MPARAM)TRUE;     // tell cnr that we've drawn the item
+            }
         }
-        else
+        else if (    (poi->idItem == CMA_ICON)
+                  && (flFlags & CODFL_MINIICON)
+                )
         {
-            // CRA_DISABLED:
-
-            ULONG flCmd = DT_LEFT | DT_TOP | DT_ERASERECT;
-            RECTL rcl2;
-
-            // set draw colors
-            LONG  lBackground,
-                  lForeground;
-
-            // switch to RGB
-            GpiCreateLogColorTable(poi->hps, 0, LCOLF_RGB, 0, 0, NULL);
-
-            if ((pcdii->pRecord->flRecordAttr) & CRA_SELECTED)
-            {
-                // disabled and selected:
-                lBackground = WinQuerySysColor(HWND_DESKTOP,
-                                               SYSCLR_SHADOWTEXT, 0);
-                lForeground = winhQueryPresColor(poi->hwnd,
-                                                 PP_BACKGROUNDCOLOR,
-                                                 FALSE, // no inherit
-                                                 SYSCLR_WINDOW);
-            }
-            else
-            {
-                // disabled and not selected:
-                lBackground = winhQueryPresColor(poi->hwnd,
-                                                 PP_BACKGROUNDCOLOR,
-                                                 FALSE,
-                                                 SYSCLR_WINDOW);
-                lForeground = WinQuerySysColor(HWND_DESKTOP,
-                                               SYSCLR_SHADOWTEXT, 0);
-            }
-
-            memcpy(&rcl2, &(poi->rclItem), sizeof(rcl2));
-            /* WinDrawText(poi->hps,
-                        strlen(pcdii->pRecord->pszText),
-                        pcdii->pRecord->pszText,
-                        &rcl2,
-                        lForeground,  // foreground
-                        lBackground,
-                        flCmd); */
-
-            GpiSetBackColor(poi->hps, lBackground);
-            GpiSetColor(poi->hps, lForeground);
-
-            winhDrawFormattedText(poi->hps,
-                                  &rcl2,
-                                  pcdii->pRecord->pszText,
-                                  flCmd);
-
-            mrc = (MPARAM)TRUE; // tell cnr that we've drawn the item
+            WinDrawPointer(poi->hps,
+                           // center the icon in the rectangle
+                           (   poi->rclItem.xLeft
+                             + (poi->rclItem.xRight - poi->rclItem.xLeft
+                                - WinQuerySysValue(HWND_DESKTOP, SV_CXICON) / 2
+                               ) / 2
+                           ),
+                           (   poi->rclItem.yBottom
+                             + (poi->rclItem.yTop - poi->rclItem.yBottom
+                                - WinQuerySysValue(HWND_DESKTOP, SV_CYICON) / 2
+                               ) / 2
+                           ),
+                           pcdii->pRecord->hptrMiniIcon,
+                           DP_MINI);
+
+            mrc = (MPARAM)TRUE;         // tell cnr that we've drawn the item
         }
-    } else
-        mrc = (MPARAM)FALSE; // tell cnr to draw the item
+    }
 
     return (mrc);
Index: trunk/src/helpers/dialog.c
===================================================================
--- trunk/src/helpers/dialog.c	(revision 105)
+++ trunk/src/helpers/dialog.c	(revision 106)
@@ -1778,6 +1778,130 @@
     {
         CHAR szErr[300];
-        sprintf(szErr, "Error %d occured in dlghCreateDlg.", arc);
+        sprintf(szErr, "Error %d occured in " __FUNCTION__ ".", arc);
         winhDebugBox(hwndOwner,
+                     "Error in Dialog Manager",
+                     szErr);
+    }
+
+    return (arc);
+}
+
+/*
+ *@@ dlghFormatDlg:
+ *      similar to dlghCreateDlg in that this can
+ *      dynamically format dialog items.
+ *
+ *      The differences however are the following:
+ *
+ *      --  This assumes that hwndDlg already points
+ *          to a valid dialog frame and that this
+ *          dialog should be modified according to
+ *          flFlags.
+ *
+ *      flFlags can be any combination of the following:
+ *
+ *      --  DFFL_CREATECONTROLS: paDlgItems points to
+ *          an array of cDlgItems DLGHITEM structures
+ *          (see dlghCreateDlg) which is used for creating
+ *          subwindows in hwndDlg. By using this flag, the
+ *          function will essentially work like dlghCreateDlg,
+ *          except that the frame is already created.
+ *
+ *      --  DFFL_RESIZEFRAME: hwndDlg should be resized so
+ *          that it will properly surround the controls.
+ *
+ *          This can only be used in conjunction with
+ *          DFFL_RESIZEFRAME.
+ *
+ *@@added V0.9.16 (2001-09-29) [umoeller]
+ */
+
+APIRET dlghFormatDlg(HWND hwndDlg,              // in: dialog frame to work on
+                     PDLGHITEM paDlgItems,      // in: definition array
+                     ULONG cDlgItems,           // in: array item count (NOT array size)
+                     const char *pcszControlsFont, // in: font for ctls with CTL_COMMON_FONT
+                     ULONG flFlags)             // in: DFFL_* flags
+{
+    APIRET      arc = NO_ERROR;
+
+    ULONG       ul;
+
+    PDLGPRIVATE  pDlgData = NULL;
+
+    /*
+     *  1) parse the table and create structures from it
+     *
+     */
+
+    if (!(arc = Dlg0_Init(&pDlgData,
+                          pcszControlsFont)))
+    {
+        if (!(arc = Dlg1_ParseTables(pDlgData,
+                                     paDlgItems,
+                                     cDlgItems)))
+        {
+            /*
+             *  2) create empty dialog frame
+             *
+             */
+
+            HWND    hwndFocusItem = NULLHANDLE;
+            SIZEL   szlClient = {0};
+            RECTL   rclClient;
+
+            pDlgData->hwndDlg = hwndDlg;
+
+            /*
+             *  3) compute size of all controls
+             *
+             */
+
+            Dlg2_CalcSizes(pDlgData,
+                           &szlClient);
+
+            // WinSubclassWindow(hwndDlg, pfnwpDialogProc);
+
+            /*
+             *  4) compute size of dialog client from total
+             *     size of all controls
+             */
+
+            if (flFlags & DFFL_RESIZEFRAME)
+            {
+                // calculate the frame size from the client size
+                rclClient.xLeft = 10;
+                rclClient.yBottom = 10;
+                rclClient.xRight = szlClient.cx + 2 * SPACING;
+                rclClient.yTop = szlClient.cy + 2 * SPACING;
+                WinCalcFrameRect(hwndDlg,
+                                 &rclClient,
+                                 FALSE);            // frame from client
+
+                WinSetWindowPos(hwndDlg,
+                                0,
+                                10,
+                                10,
+                                rclClient.xRight,
+                                rclClient.yTop,
+                                SWP_MOVE | SWP_SIZE | SWP_NOADJUST);
+            }
+
+            if (flFlags & DFFL_CREATECONTROLS)
+            {
+                if (!(arc = Dlg3_PositionAndCreate(pDlgData,
+                                                   &szlClient,
+                                                   &hwndFocusItem)))
+                    WinSetFocus(HWND_DESKTOP, hwndFocusItem);
+            }
+        }
+
+        Dlg9_Cleanup(&pDlgData);
+    }
+
+    if (arc)
+    {
+        CHAR szErr[300];
+        sprintf(szErr, "Error %d occured in " __FUNCTION__ ".", arc);
+        winhDebugBox(NULLHANDLE,
                      "Error in Dialog Manager",
                      szErr);
Index: trunk/src/helpers/tree.c
===================================================================
--- trunk/src/helpers/tree.c	(revision 105)
+++ trunk/src/helpers/tree.c	(revision 106)
@@ -304,4 +304,37 @@
     if (ul1 > ul2)
         return +1;
+    return (0);
+}
+
+/*
+ *@@ treeCompareStrings:
+ *      standard comparison func if the TREE.ulKey
+ *      field really is a string pointer (PCSZ).
+ *
+ *      This runs strcmp internally, but can handle
+ *      NULL pointers without crashing.
+ *
+ *@@added V0.9.16 (2001-09-29) [umoeller]
+ */
+
+int TREEENTRY treeCompareStrings(unsigned long  ul1, unsigned long ul2)
+{
+    #define p1 (const char*)(ul1)
+    #define p2 (const char*)(ul2)
+
+    if (p1 && p2)
+    {
+        int i = strcmp(p1, p2);
+        if (i < 0) return (-1);
+        if (i > 0) return (+1);
+    }
+    else if (p1)
+        // but p2 is NULL: p1 greater than p2 then
+        return (+1);
+    else if (p2)
+        // but p1 is NULL: p1 less than p2 then
+        return (-1);
+
+    // return 0 if strcmp returned 0 above or both strings are NULL
     return (0);
 }
Index: trunk/src/helpers/winh.c
===================================================================
--- trunk/src/helpers/winh.c	(revision 105)
+++ trunk/src/helpers/winh.c	(revision 106)
@@ -58,4 +58,5 @@
 #define INCL_WINSWITCHLIST
 #define INCL_WINBUTTONS
+#define INCL_WINSTATICS
 #define INCL_WINMENUS
 #define INCL_WINSCROLLBARS
@@ -84,4 +85,5 @@
 #include "helpers\prfh.h"
 #include "helpers\gpih.h"
+#include "helpers\standards.h"
 #include "helpers\stringh.h"
 #include "helpers\undoc.h"
@@ -4275,4 +4277,216 @@
 
 /*
+ *@@category: Helpers\PM helpers\Extended frame windows
+ */
+
+/* ******************************************************************
+ *
+ *   Extended frame
+ *
+ ********************************************************************/
+
+/*
+ *@@ fnwpSubclExtFrame:
+ *      subclassed frame window proc.
+ *
+ *@@added V0.9.16 (2001-09-29) [umoeller]
+ */
+
+MRESULT EXPENTRY fnwpSubclExtFrame(HWND hwndFrame, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+    MRESULT mrc = 0;
+
+    PEXTFRAMEDATA pData = (PEXTFRAMEDATA)WinQueryWindowPtr(hwndFrame, QWL_USER);
+
+    switch (msg)
+    {
+        case WM_QUERYFRAMECTLCOUNT:
+        {
+            // query the standard frame controls count
+            ULONG ulrc = (ULONG)pData->pfnwpOrig(hwndFrame, msg, mp1, mp2);
+
+            // if we have a status bar, increment the count
+            ulrc++;
+
+            mrc = (MPARAM)ulrc;
+        }
+        break;
+
+        case WM_FORMATFRAME:
+        {
+            // query the number of standard frame controls
+            ULONG ulCount = (ULONG)pData->pfnwpOrig(hwndFrame, msg, mp1, mp2);
+
+            // we have a status bar:
+            // format the frame
+            ULONG       ul;
+            PSWP        swpArr = (PSWP)mp1;
+
+            for (ul = 0; ul < ulCount; ul++)
+            {
+                if (WinQueryWindowUShort( swpArr[ul].hwnd, QWS_ID ) == 0x8008 )
+                                                                 // FID_CLIENT
+                {
+                    POINTL      ptlBorderSizes;
+                    ULONG       ulStatusBarHeight = 20;
+                    WinSendMsg(hwndFrame,
+                               WM_QUERYBORDERSIZE,
+                               (MPARAM)&ptlBorderSizes,
+                               0);
+
+                    // first initialize the _new_ SWP for the status bar.
+                    // Since the SWP array for the std frame controls is
+                    // zero-based, and the standard frame controls occupy
+                    // indices 0 thru ulCount-1 (where ulCount is the total
+                    // count), we use ulCount for our static text control.
+                    swpArr[ulCount].fl = SWP_MOVE | SWP_SIZE | SWP_NOADJUST | SWP_ZORDER;
+                    swpArr[ulCount].x  = ptlBorderSizes.x;
+                    swpArr[ulCount].y  = ptlBorderSizes.y;
+                    swpArr[ulCount].cx = swpArr[ul].cx;  // same as cnr's width
+                    swpArr[ulCount].cy = ulStatusBarHeight;
+                    swpArr[ulCount].hwndInsertBehind = HWND_BOTTOM; // HWND_TOP;
+                    swpArr[ulCount].hwnd = WinWindowFromID(hwndFrame, FID_STATUSBAR);
+
+                    // adjust the origin and height of the container to
+                    // accomodate our static text control
+                    swpArr[ul].y  += swpArr[ulCount].cy;
+                    swpArr[ul].cy -= swpArr[ulCount].cy;
+                }
+            }
+
+            // increment the number of frame controls
+            // to include our status bar
+            mrc = (MRESULT)(ulCount + 1);
+        }
+        break;
+
+        case WM_CALCFRAMERECT:
+        {
+            mrc = pData->pfnwpOrig(hwndFrame, msg, mp1, mp2);
+
+            // we have a status bar: calculate its rectangle
+            // CalcFrameRect(mp1, mp2);
+        }
+        break;
+
+        case WM_DESTROY:
+            WinSubclassWindow(hwndFrame, pData->pfnwpOrig);
+            free(pData);
+            WinSetWindowPtr(hwndFrame, QWL_USER, NULL);
+        break;
+
+        default:
+            mrc = pData->pfnwpOrig(hwndFrame, msg, mp1, mp2);
+    }
+
+    return (mrc);
+}
+
+/*
+ *@@ winhCreateStatusBar:
+ *      creates a status bar for a frame window.
+ *
+ *      Normally there's no need to call this manually,
+ *      this gets called by winhCreateExtStdWindow
+ *      automatically.
+ *
+ *@@added V0.9.16 (2001-09-29) [umoeller]
+ */
+
+HWND winhCreateStatusBar(HWND hwndFrame,
+                         HWND hwndOwner,
+                         const char *pcszText,      // in: initial status bar text
+                         const char *pcszFont,      // in: font to use for status bar
+                         LONG lColor)               // in: foreground color for status bar
+{
+    // create status bar
+    HWND        hwndReturn = NULLHANDLE;
+    PPRESPARAMS ppp = NULL;
+    winhStorePresParam(&ppp, PP_FONTNAMESIZE, strlen(pcszFont)+1, (PVOID)pcszFont);
+    lColor = WinQuerySysColor(HWND_DESKTOP, SYSCLR_DIALOGBACKGROUND, 0);
+    winhStorePresParam(&ppp, PP_BACKGROUNDCOLOR, sizeof(lColor), &lColor);
+    lColor = CLR_BLACK;
+    winhStorePresParam(&ppp, PP_FOREGROUNDCOLOR, sizeof(lColor), &lColor);
+    hwndReturn = WinCreateWindow(hwndFrame,
+                                 WC_STATIC,
+                                 (PSZ)pcszText,
+                                 SS_TEXT | DT_VCENTER | WS_VISIBLE,
+                                 0, 0, 0, 0,
+                                 hwndOwner,
+                                 HWND_TOP,
+                                 FID_STATUSBAR,
+                                 NULL,
+                                 ppp);
+    free(ppp);
+    return (hwndReturn);
+}
+
+/*
+ *@@ winhCreateExtStdWindow:
+ *      creates an extended frame window.
+ *
+ *      pData must point to an EXTFRAMECDATA structure
+ *      which contains a copy of the parameters to be
+ *      passed to winhCreateStdWindow. In addition,
+ *      this contains the flExtFlags field, which allows
+ *      you to automatically create a status bar for
+ *      the window.
+ *
+ *      Note that we subclass the frame here and require
+ *      QWL_USER for that. The frame's QWL_USER points
+ *      to an EXTFRAMEDATA structure whose pUser parameter
+ *      you may use for additional data, if you want to
+ *      do further subclassing.
+ *
+ *@@added V0.9.16 (2001-09-29) [umoeller]
+ */
+
+HWND winhCreateExtStdWindow(PEXTFRAMECDATA pData,        // in: extended frame data
+                            PHWND phwndClient)          // out: created client wnd
+{
+    HWND hwndFrame;
+
+    if (hwndFrame = winhCreateStdWindow(HWND_DESKTOP,
+                                        pData->pswpFrame,
+                                        pData->flFrameCreateFlags,
+                                        pData->ulFrameStyle,
+                                        pData->pcszFrameTitle,
+                                        pData->ulResourcesID,
+                                        pData->pcszClassClient,
+                                        pData->flStyleClient,
+                                        pData->ulID,
+                                        pData->pClientCtlData,
+                                        phwndClient))
+    {
+        if (pData->flExtFlags & XFCF_STATUSBAR)
+        {
+            // create status bar as child of the frame
+            HWND hwndStatusBar = winhCreateStatusBar(hwndFrame,
+                                                     hwndFrame,
+                                                     NULL,
+                                                     "9.WarpSans",
+                                                     CLR_BLACK);
+
+            // subclass frame for supporting status bar and msgs
+            PEXTFRAMEDATA pFrameData;
+            if (pFrameData = NEW(EXTFRAMEDATA))
+            {
+                ZERO(pFrameData),
+                memcpy(&pFrameData->CData, pData, sizeof(pFrameData->CData));
+                if (pFrameData->pfnwpOrig = WinSubclassWindow(hwndFrame,
+                                                              fnwpSubclExtFrame))
+                {
+                    WinSetWindowPtr(hwndFrame, QWL_USER, pFrameData);
+                }
+                else
+                    free(pFrameData);
+            }
+        }
+    }
+
+    return (hwndFrame);
+}
+
+/*
  *@@category: Helpers\PM helpers\Workplace Shell\WPS class list
  */
Index: trunk/src/helpers/wphandle.c
===================================================================
--- trunk/src/helpers/wphandle.c	(revision 105)
+++ trunk/src/helpers/wphandle.c	(revision 106)
@@ -12,6 +12,8 @@
  *      --  wph*   WPS object helper functions
  *
- *      This code is mostly written by Henk Kelder and published
- *      with his kind permission.
+ *      Thanks go out to Henk Kelder for telling me the
+ *      format of the WPS INI data. With V0.9.16, this
+ *      file was completely rewritten and no longer uses
+ *      his code though.
  *
  *      Note: Version numbering in this file relates to XWorkplace version
@@ -22,6 +24,5 @@
 
 /*
- *      This file Copyright (C) 1997-2000 Ulrich Mller,
- *                                        Henk Kelder.
+ *      This file Copyright (C) 1997-2001 Ulrich Mller,
  *      This file is part of the "XWorkplace helpers" source package.
  *      This is free software; you can redistribute it and/or modify
@@ -40,8 +41,10 @@
     // as unsigned char
 
+#define INCL_DOSEXCEPTIONS
+#define INCL_DOSPROCESS
+#define INCL_DOSERRORS
+
 #define INCL_WINSHELLDATA
 #include <os2.h>
-
-#define OPTIONS_SIZE 32767
 
 #include <stdio.h>
@@ -49,21 +52,15 @@
 #include <stdlib.h>
 #include <io.h>
+#include <setjmp.h>
 
 #include "setup.h"                      // code generation and debugging options
 
+#include "helpers\except.h"
+#include "helpers\prfh.h"
+#include "helpers\standards.h"
+#include "helpers\stringh.h"
+#define INCLUDE_WPHANDLE_PRIVATE
 #include "helpers\wphandle.h"
-
-/****************************************************
- *                                                  *
- *  helper functions                                *
- *                                                  *
- ****************************************************/
-
-static USHORT wphSearchBufferForHandle(PBYTE pHandlesBuffer, ULONG ulBufSize, USHORT usParent, PSZ pszFname);
-PNODE wphFindPartName(PBYTE pHandlesBuffer, ULONG ulBufSize, USHORT usID, PSZ pszFname, USHORT usMax);
-
-#define MakeDiskHandle(usObjID) (usObjID | 0x30000)
-
-#define IsObjectDisk(hObject) ((hObject & 0x30000) == 0x30000)
+#include "helpers\xstring.h"
 
 /*
@@ -74,73 +71,17 @@
 /* ******************************************************************
  *
- *   Helper functions
+ *   Load handles functions
  *
  ********************************************************************/
 
 /*
- *@@ wphQueryProfileData:
- *      like PrfQueryProfileData, but allocates sufficient
- *      memory and returns a pointer to that buffer.
- *      pulSize must point to a ULONG which will then
- *      contain the no. of copied bytes.
- */
-
-PBYTE wphQueryProfileData(HINI hIniSystem,    // in: can be HINI_USER or HINI_SYSTEM
-                          PSZ pApp, PSZ pKey, // in: load what?
-                          PULONG pulSize)     // out: bytes loaded
-{
-    PBYTE pData = NULL;
-    if (PrfQueryProfileSize(hIniSystem, pApp, pKey, pulSize))
-    {
-        pData = (PBYTE)malloc(*pulSize);
-        PrfQueryProfileData(hIniSystem, pApp, pKey, pData, pulSize);
-    }
-    // _Pmpf(("  wphQueryProfileData(%lX, %s, %s, %d)", hIniSystem, pApp, pKey, *pulSize));
-    return (pData);
-}
-
-/*
- *@@ wphEnumProfileKeys:
- *      allocates memory for a buffer and copies the keys
- *      for pApp into it.
- *      Returns the pointer to the buffer.
- *      pulKeysSize must point to a ULONG which will then
- *      contain the size of the returned buffer.
- */
-
-PBYTE wphEnumProfileKeys(HINI hIniSystem,       // in: can be HINI_USER or HINI_SYSTEM
-                         PSZ pApp,              // in: app to query
-                         PULONG pulKeysSize)    // out: sizeof(return buffer)
-{
-    PBYTE pszKeys = NULL;
-    if (PrfQueryProfileSize(hIniSystem, pApp, NULL, pulKeysSize))
-    {
-        pszKeys = (PBYTE)malloc(*pulKeysSize);
-        if (pszKeys)
-            PrfQueryProfileData(hIniSystem, pApp, NULL, pszKeys, pulKeysSize);
-    }
-    return (pszKeys);
-}
-
-/*
- * wphResetBlockBuffer:
- *      Reset the block buffer, make sure the buffer is re-read.
- */
-
-/* VOID wphResetBlockBuffer(VOID)
-{
-   if (pHandlesBuffer)
-   {
-       free(pHandlesBuffer);
-       pHandlesBuffer = NULL;
-   }
-} */
-
-/*
  *@@ wphQueryActiveHandles:
- *      this copies the contents of PM_Workplace:ActiveHandles
- *      in OS2SYS.INI into a given buffer. There are always two
- *      buffers in OS2SYS.INI for object handles, called
- *      "PM_Workplace:HandlesX" with "X" either being "0" or "1".
+ *      returns the value of PM_Workplace:ActiveHandles
+ *      in OS2SYS.INI as a new buffer.
+ *
+ *      There are always two buffers in OS2SYS.INI for object
+ *      handles, called "PM_Workplace:HandlesX" with "X" either
+ *      being "0" or "1".
+ *
  *      It seems that every time the WPS does something in the
  *      handles section, it writes the data to the inactive
@@ -149,30 +90,331 @@
  *      by creating a shadow on your Desktop.
  *
- *      This function copies the key only, but not the actual
- *      handles blocks (use wphReadAllBlocks for that).
+ *      This returns a new PSZ which the caller must free()
+ *      after use.
  *
  *      This gets called by the one-shot function
  *      wphQueryHandleFromPath.
- */
-
-BOOL wphQueryActiveHandles(HINI hIniSystem,       // in: can be HINI_USER or HINI_SYSTEM
-                           PSZ pszHandlesAppName, // out: active handles buffer.
-                           USHORT usMax)          // in:  sizeof(pszHandlesAppName)
-{
-    PBYTE pszHandles;
-    ULONG ulProfileSize;
-
-    pszHandles = wphQueryProfileData(hIniSystem,
-                                     ACTIVEHANDLES, HANDLESAPP,
-                                     &ulProfileSize);
-    if (!pszHandles)
-    {
-        strncpy(pszHandlesAppName, HANDLES, usMax-1);
-        return TRUE;
-    }
-    // fNewFormat = TRUE;
-    strncpy(pszHandlesAppName, pszHandles, usMax-1);
-    free(pszHandles);
-    return TRUE;
+ *
+ *@@changed V0.9.16 (2001-10-02) [umoeller]: rewritten
+ */
+
+APIRET wphQueryActiveHandles(HINI hiniSystem,
+                             PSZ *ppszActiveHandles)
+{
+    PSZ pszActiveHandles;
+    if (pszActiveHandles = prfhQueryProfileData(hiniSystem,
+                                                WPINIAPP_ACTIVEHANDLES,
+                                                WPINIAPP_HANDLESAPP,
+                                                NULL))
+    {
+        *ppszActiveHandles = pszActiveHandles;
+        return (NO_ERROR);
+    }
+
+    return (ERROR_WPH_NO_ACTIVEHANDLES_DATA);
+}
+
+/*
+ *@@ wphQueryBaseClassesHiwords:
+ *      returns the hiwords for the WPS base
+ *      classes. Unless the user's system is
+ *      really badly configured, this should
+ *      set
+ *
+ *      --  pusHiwordAbstract to 2;
+ *      --  pusHiwordFileSystem to 3.
+ *
+ *      Returns:
+ *
+ *      --  NO_ERROR
+ *
+ *      --  ERROR_WPH_NO_BASECLASS_DATA
+ *
+ *      --  ERROR_WPH_INCOMPLETE_BASECLASS_DATA
+ *
+ *      This gets called automatically from wphLoadHandles.
+ *
+ *@@added V0.9.16 (2001-10-02) [umoeller]
+ */
+
+APIRET wphQueryBaseClassesHiwords(HINI hiniUser,
+                                  PUSHORT pusHiwordAbstract,
+                                  PUSHORT pusHiwordFileSystem)
+{
+    APIRET arc = NO_ERROR;
+
+    // get the index of WPFileSystem from the base classes list...
+    // we need this to determine the hiword for file-system handles
+    // properly. Normally, this should be 3.
+    ULONG cbBaseClasses = 0;
+    PSZ pszBaseClasses;
+    if (pszBaseClasses = prfhQueryProfileData(hiniUser,
+                                              "PM_Workplace:BaseClass",
+                                              "ClassList",
+                                              &cbBaseClasses))
+    {
+        // parse that buffer... these has the base class names,
+        // separated by 0. List is terminated by two zeroes.
+        PSZ     pszClassThis = pszBaseClasses;
+        ULONG   ulHiwordThis = 1;
+        while (    (*pszClassThis)
+                && (pszClassThis - pszBaseClasses < cbBaseClasses)
+              )
+        {
+            if (!strcmp(pszClassThis, "WPFileSystem"))
+                *pusHiwordFileSystem = ulHiwordThis;
+            else if (!strcmp(pszClassThis, "WPAbstract"))
+                *pusHiwordAbstract = ulHiwordThis;
+
+            ulHiwordThis++;
+            pszClassThis += strlen(pszClassThis) + 1;
+        }
+
+        // now check if we found both
+        if (    (!(*pusHiwordFileSystem))
+             || (!(*pusHiwordAbstract))
+           )
+            arc = ERROR_WPH_INCOMPLETE_BASECLASS_DATA;
+
+        free(pszBaseClasses);
+    }
+    else
+        arc = ERROR_WPH_NO_BASECLASS_DATA;
+
+    return (arc);
+}
+
+/*
+ *@@ wphRebuildNodeHashTable:
+ *
+ *      Returns:
+ *
+ *      --  NO_ERROR
+ *
+ *      --  ERROR_INVALID_PARAMETER
+ *
+ *      --  ERROR_WPH_CORRUPT_HANDLES_DATA
+ *
+ *@@added V0.9.16 (2001-10-02) [umoeller]
+ */
+
+APIRET wphRebuildNodeHashTable(PHANDLESBUF pHandlesBuf)
+{
+    APIRET arc = NO_ERROR;
+
+    if (    (!pHandlesBuf)
+         || (!pHandlesBuf->pbData)
+         || (!pHandlesBuf->cbData)
+       )
+        arc = ERROR_INVALID_PARAMETER;
+    else
+    {
+        // start at beginning of buffer
+        PBYTE pCur = pHandlesBuf->pbData + 4;
+        PBYTE pEnd = pHandlesBuf->pbData + pHandlesBuf->cbData;
+
+        memset(pHandlesBuf->NodeHashTable, 0, sizeof(pHandlesBuf->NodeHashTable));
+
+        // now set up hash table
+        while (pCur < pEnd)
+        {
+            if (!memicmp(pCur, "DRIV", 4))
+            {
+                // pCur points to a DRIVE node:
+                // these never have handles, so skip this
+                PDRIV pDriv = (PDRIV)pCur;
+                pCur += sizeof(DRIV) + strlen(pDriv->szName);
+            }
+            else if (!memicmp(pCur, "NODE", 4))
+            {
+                // pCur points to a regular NODE: offset pointer first
+                PNODE pNode = (PNODE)pCur;
+                // store PNODE in hash table
+                pHandlesBuf->NodeHashTable[pNode->usHandle] = pNode;
+                pCur += sizeof (NODE) + pNode->usNameSize;
+            }
+            else
+            {
+                arc = ERROR_WPH_CORRUPT_HANDLES_DATA;
+                break;
+            }
+        }
+    }
+
+    if (!arc)
+        pHandlesBuf->fNodeHashTableValid = TRUE;
+
+    return (arc);
+}
+
+/*
+ *@@ wphLoadHandles:
+ *      returns a HANDLESBUF structure which will hold
+ *      all the handles from OS2SYS.INI. In addition,
+ *      this calls wphQueryBaseClassesHiwords and puts
+ *      the hiwords for WPAbstract and WPFileSystem into
+ *      the HANDLESBUF as well.
+ *
+ *      Prerequisite before using any of the other wph*
+ *      functions.
+ *
+ *      Call wphFreeHandles to free all data allocated
+ *      by this function.
+ *
+ *      Returns:
+ *
+ *      --  NO_ERROR
+ *
+ *      --  ERROR_NOT_ENOUGH_MEMORY
+ *
+ *      --  ERROR_INVALID_PARAMETER
+ *
+ *      --  ERROR_WPH_NO_HANDLES_DATA: cannot read handle blocks.
+ *
+ *      --  ERROR_WPH_CORRUPT_HANDLES_DATA: cannot read handle blocks.
+ *
+ *@@added V0.9.16 (2001-10-02) [umoeller]
+ */
+
+APIRET wphLoadHandles(HINI hiniUser,      // in: HINI_USER or other INI handle
+                      HINI hiniSystem,    // in: HINI_SYSTEM or other INI handle
+                      const char *pcszActiveHandles,
+                      PHANDLESBUF *ppHandlesBuf)
+{
+    APIRET arc = NO_ERROR;
+
+    if (!ppHandlesBuf)
+        arc = ERROR_INVALID_PARAMETER;
+    else
+    {
+        PSZ pszKeysList;
+        if (!(arc = prfhQueryKeysForApp(hiniSystem,
+                                        pcszActiveHandles,
+                                        &pszKeysList)))
+        {
+            PHANDLESBUF pReturn = NULL;
+
+            ULONG   ulHighestBlock = 0,
+                    ul,
+                    cbTotal;
+            PBYTE   pbData;
+
+            const char *pKey2 = pszKeysList;
+            while (*pKey2)
+            {
+                if (!memicmp((PVOID)pKey2, "BLOCK", 5))
+                {
+                    ULONG ulBlockThis = atoi(pKey2 + 5);
+                    if (ulBlockThis > ulHighestBlock)
+                        ulHighestBlock = ulBlockThis;
+                }
+
+                pKey2 += strlen(pKey2)+1; // next key
+            }
+
+            free(pszKeysList);
+
+            if (!ulHighestBlock)
+                arc = ERROR_WPH_NO_HANDLES_DATA;
+            else
+            {
+                // now go read the data
+                // (BLOCK1, BLOCK2, ..., BLOCKn)
+                cbTotal = 0;
+                pbData = NULL;
+                for (ul = 1;
+                     ul <= ulHighestBlock;
+                     ul++)
+                {
+                    ULONG   cbBlockThis;
+                    CHAR    szBlockThis[10];
+                    sprintf(szBlockThis, "BLOCK%d", ul);
+                    if (!PrfQueryProfileSize(hiniSystem,
+                                             (PSZ)pcszActiveHandles,
+                                             szBlockThis,
+                                             &cbBlockThis))
+                    {
+                        arc = ERROR_WPH_CORRUPT_HANDLES_DATA;
+                        break;
+                    }
+                    else
+                    {
+                        ULONG   cbTotalOld = cbTotal;
+                        cbTotal += cbBlockThis;
+                        if (!(pbData = realloc(pbData, cbTotal)))
+                                // on first call, pbData is NULL and this
+                                // behaves like malloc()
+                        {
+                            arc = ERROR_NOT_ENOUGH_MEMORY;
+                            break;
+                        }
+
+                        if (!PrfQueryProfileData(hiniSystem,
+                                                 (PSZ)pcszActiveHandles,
+                                                 szBlockThis,
+                                                 pbData + cbTotalOld,
+                                                 &cbBlockThis))
+                        {
+                            arc = ERROR_WPH_CORRUPT_HANDLES_DATA;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            if (!arc)
+            {
+                // all went OK:
+                if (pReturn = NEW(HANDLESBUF))
+                {
+                    ZERO(pReturn);
+
+                    pReturn->pbData = pbData;
+                    pReturn->cbData = cbTotal;
+
+                    // and load the hiwords too
+                    if (!(arc = wphQueryBaseClassesHiwords(hiniUser,
+                                                           &pReturn->usHiwordAbstract,
+                                                           &pReturn->usHiwordFileSystem)))
+                        *ppHandlesBuf = pReturn;
+                }
+                else
+                    arc = ERROR_NOT_ENOUGH_MEMORY;
+            }
+
+            if (arc)
+                // error:
+                wphFreeHandles(&pReturn);
+        }
+    }
+
+    return (arc);
+}
+
+/*
+ *@@ wphFreeHandles:
+ *      frees all data allocated by wphLoadHandles
+ *      and sets *ppHandlesBuf to NULL, for safety.
+ *
+ *@@added V0.9.16 (2001-10-02) [umoeller]
+ */
+
+APIRET wphFreeHandles(PHANDLESBUF *ppHandlesBuf)
+{
+    APIRET arc = NO_ERROR;
+
+    if (ppHandlesBuf && *ppHandlesBuf)
+    {
+        PBYTE pbData;
+        if (pbData = (*ppHandlesBuf)->pbData)
+            free(pbData);
+
+        free(*ppHandlesBuf);
+        *ppHandlesBuf = NULL;
+    }
+    else
+        arc = ERROR_INVALID_PARAMETER;
+
+    return (arc);
 }
 
@@ -195,5 +437,5 @@
  */
 
-BOOL wphReadAllBlocks(HINI hiniSystem,       // in: can be HINI_USER or HINI_SYSTEM
+/* BOOL wphReadAllBlocks(HINI hiniSystem,       // in: can be HINI_USER or HINI_SYSTEM
                       PSZ pszActiveHandles,  // in: active handles section
                       PBYTE* ppBlock,        // in/out: pointer to buffer, which
@@ -246,5 +488,4 @@
     if (!(*ppBlock))
     {
-       /* MessageBox("wphReadAllBlocks", "Not enough memory for profile data!"); */
          free(pbAllBlocks);
          return FALSE;
@@ -278,5 +519,5 @@
     free(pbAllBlocks);
     return TRUE;
-}
+} */
 
 /* ******************************************************************
@@ -289,5 +530,5 @@
  *@@ wphSearchBufferForHandle:
  *      returns the four-digit object handle which corresponds
- *      to pszFname, searching pHandlesBuffer. Note that you
+ *      to pszFilename, searching pHandlesBuffer. Note that you
  *      must OR the return value with 0x30000 to make this
  *      a valid WPS file-system handle.
@@ -304,5 +545,5 @@
                                 USHORT usParent,      // in: parent NODE ID;
                                                       //     must be 0 initially
-                                PSZ pszFname) // in: fully qlf'd filename to search for
+                                PSZ pszFilename) // in: fully qlf'd filename to search for
 {
     PDRIV pDriv;
@@ -313,5 +554,5 @@
     USHORT usPartSize;
 
-    // _Pmpf(("Entering wphSearchBufferForHandle for %s", pszFname));
+    // _Pmpf(("Entering wphSearchBufferForHandle for %s", pszFilename));
 
     // The composed BLOCKs in the handles buffer make up a tree of
@@ -334,10 +575,10 @@
     // So first find the length of the first filename part (which
     // should be 2 for the drive letter, "C:")
-    p = strchr(pszFname, '\\');
+    p = strchr(pszFilename, '\\');
     if (p)
         // backslash found:
-        usPartSize = p - pszFname;      // extract first part
+        usPartSize = p - pszFilename;      // extract first part
     else
-        usPartSize = strlen(pszFname);
+        usPartSize = strlen(pszFilename);
 
     // now set the pointer for the end of the BLOCKs buffer
@@ -348,5 +589,5 @@
     pCur = pHandlesBuffer + 4;
 
-    // _Pmpf(("  Searching for: %s, usPartSize: %d", pszFname, usPartSize));
+    // _Pmpf(("  Searching for: %s, usPartSize: %d", pszFilename, usPartSize));
 
     // go!
@@ -386,5 +627,5 @@
 
                     // do the partnames match too?
-                    if (memicmp(pszFname, pNode->szName, usPartSize) == 0)
+                    if (memicmp(pszFilename, pNode->szName, usPartSize) == 0)
                     {
                         // OK!! proper NODE found!
@@ -393,5 +634,5 @@
                         // now check if this was the last NODE
                         // we were looking for
-                        if (strlen(pszFname) == usPartSize)
+                        if (strlen(pszFilename) == usPartSize)
                            // yes: return ID
                            return (pNode->usHandle);
@@ -399,11 +640,11 @@
                         // else: update our status;
                         // get next partname
-                        pszFname += usPartSize + 1;
+                        pszFilename += usPartSize + 1;
                         // calc next partname length
-                        p = strchr(pszFname, '\\');
+                        p = strchr(pszFilename, '\\');
                         if (p)
-                           usPartSize = p - pszFname;
+                            usPartSize = p - pszFilename;
                         else
-                           usPartSize = strlen(pszFname);
+                            usPartSize = strlen(pszFilename);
 
                         // get next parent to search for
@@ -426,96 +667,70 @@
 /*
  *@@ wphQueryHandleFromPath:
- *      find the object handle for pszName; this
- *      can either be an object ID ("<WP_DESKTOP>")
- *      or a fully qualified filename.
+ *      finds the object handle for the given fully qualified
+ *      filename.
  *      This is a one-shot function, using wphQueryActiveHandles,
  *      wphReadAllBlocks, and wphSearchBufferForHandle.
  *
  *      Returns:
- *      --  -1:     file does not exist
- *      --  -2:     error querying handles buffer
- *      --  0:      object handle not found; might not exist
- *      --  other:  found object handle
- *
- *      NOTE: This function uses C runtime library
- *      string comparison functions. These only work
- *      properly if you have set the locale for the
- *      C runtime properly. This is, for example, a
- *      problem with file names containing German umlauts,
- *      which are not found properly.
- *      You should put some
- +          setlocale(LC_ALL, "");
- *      statement somewhere, which reacts to the LANG
- *      variable which OS/2 puts into CONFIG.SYS per
- *      default.
- */
-
-HOBJECT wphQueryHandleFromPath(HINI hIniUser,   // in: user ini file
-                               HINI hIniSystem, // in: system ini file
-                               PSZ pszName)     // in: fully qlf'd filename
-{
-    PBYTE       pHandlesBuffer = NULL;
-    ULONG       cbHandlesBuffer = 0,
-                cbLocation = 0;
-    USHORT      usObjID;
+ *
+ *      --  NO_ERROR: *phobj has received the object handle.
+ *
+ *      --  ERROR_FILE_NOT_FOUND: file does not exist.
+ *
+ *      plus the error codes of the other wph* functions called.
+ *
+ *@@changed V0.9.16 (2001-10-02) [umoeller]: rewritten
+ */
+
+APIRET wphQueryHandleFromPath(HINI hiniUser,      // in: HINI_USER or other INI handle
+                              HINI hiniSystem,    // in: HINI_SYSTEM or other INI handle
+                              const char *pcszName,    // in: fully qlf'd filename
+                              HOBJECT *phobj)      // out: object handle found if NO_ERROR
+{
+    APIRET      arc = NO_ERROR;
     PVOID       pvData;
-    HOBJECT     hObject = 0L;
-    BYTE        szFullPath[300];
-    CHAR        szActiveHandles[100];
-
-    // _Pmpf(("wphQueryHandleFromPath: %s", pszName));
-
-    // try to get the objectID via PM_Workplace:Location, since
-    // pszName might also be a "<WP_DESKTOP>" like thingy
-    pvData = wphQueryProfileData(hIniUser,
-                                 LOCATION,   // "PM_Workplace:Location" (<WP_DESKTOP> etc.)
-                                 pszName,
-                                 &cbLocation);
-    if (pvData)
-    {
-        // found there:
-        if (cbLocation >= sizeof(HOBJECT))
-            hObject = *(PULONG)pvData;
-        free(pvData);
-        // _Pmpf(("  object ID found, hObject: %lX", hObject));
-    }
-    if (hObject)
-        return (hObject);
-
-    // not found there: is pszName an existing pathname?
-    if (access(pszName, 0))  // check existence
-    {
-        // == -1: file does not exist
-        // _Pmpf(("  path not found, returning -1"));
-        return (-1);
-    }
-
-    // else: make full path for pszName
-    _fullpath(szFullPath, pszName, sizeof(szFullPath));
-
-    // check if the HandlesBlock is valid
-    wphQueryActiveHandles(hIniSystem, szActiveHandles, sizeof(szActiveHandles));
-    // _Pmpf(("  szActiveHandles: %s", szActiveHandles));
-
-    // now load all the BLOCKs into a common buffer
-    if (!wphReadAllBlocks(hIniSystem,
-                           szActiveHandles,
-                           &pHandlesBuffer, &cbHandlesBuffer))
-        // error:
-        return (-2);
-
-    // and search that buffer
-    usObjID = wphSearchBufferForHandle(pHandlesBuffer,
-                                       cbHandlesBuffer,
-                                       0,                  // usParent
-                                       szFullPath);
-
-    if (usObjID)
-        // found: OR 0x30000
-        hObject = MakeDiskHandle(usObjID);
-
-    free(pHandlesBuffer);
-
-    return (hObject);
+
+    TRY_LOUD(excpt1)
+    {
+        // not found there: check the handles then
+        PSZ pszActiveHandles;
+        if (arc = wphQueryActiveHandles(hiniSystem, &pszActiveHandles))
+            _Pmpf((__FUNCTION__ ": wphQueryActiveHandles returned %d", arc));
+        else
+        {
+            PHANDLESBUF pHandlesBuf;
+            if (arc = wphLoadHandles(hiniUser,
+                                     hiniSystem,
+                                     pszActiveHandles,
+                                     &pHandlesBuf))
+                _Pmpf((__FUNCTION__ ": wphLoadHandles returned %d", arc));
+            else
+            {
+                USHORT      usObjID;
+                CHAR        szFullPath[2*CCHMAXPATH];
+                _fullpath(szFullPath, (PSZ)pcszName, sizeof(szFullPath));
+
+                // search that buffer
+                if (usObjID = wphSearchBufferForHandle(pHandlesBuf->pbData,
+                                                       pHandlesBuf->cbData,
+                                                       0,                  // usParent
+                                                       szFullPath))
+                    // found: OR 0x30000
+                    *phobj = usObjID | (pHandlesBuf->usHiwordFileSystem << 16);
+                else
+                    arc = ERROR_FILE_NOT_FOUND;
+
+                wphFreeHandles(&pHandlesBuf);
+            }
+
+            free(pszActiveHandles);
+        }
+    }
+    CATCH(excpt1)
+    {
+        arc = ERROR_WPH_CRASHED;
+    } END_CATCH();
+
+    return (arc);
 }
 
@@ -527,64 +742,115 @@
 
 /*
- *@@ wphFindPartName:
- *      this searches pHandlesBuffer for usHandle and, if found,
- *      appends the object partname to pszFname.
- *      This function recurses, if neccessary.
- *
- *      This gets called by the one-shot function
- *      wphQueryPathFromHandle.
- */
-
-PNODE wphFindPartName(PBYTE pHandlesBuffer, // in: handles buffer
-                      ULONG ulBufSize,      // in: buffer size
-                      USHORT usHandle,      // in: handle to search for
-                      PSZ pszFname,         // out: object partname
-                      USHORT usMax)         // in: sizeof(pszFname)
-{
-    PDRIV pDriv;
+ *@@ ComposeThis:
+ *      helper for wphComposePath recursion.
+ *
+ *@@added V0.9.16 (2001-10-02) [umoeller]
+ */
+
+APIRET ComposeThis(PHANDLESBUF pHandlesBuf,
+                   USHORT usHandle,         // in: handle to search for
+                   PXSTRING pstrFilename,   // in/out: filename
+                   PNODE *ppNode)           // out: node found (ptr can be NULL)
+{
+    APIRET arc = NO_ERROR;
     PNODE pNode;
-    PBYTE p, pEnd;
-    USHORT usSize;
-
-    pEnd = pHandlesBuffer + ulBufSize;
-    p = pHandlesBuffer + 4;
-    while (p < pEnd)
-    {
-        if (!memicmp(p, "DRIV", 4))
-        {
-            pDriv = (PDRIV)p;
-            p += sizeof(DRIV) + strlen(pDriv->szName);
-        }
-        else if (!memicmp(p, "NODE", 4))
-        {
-            pNode = (PNODE)p;
-            p += sizeof (NODE) + pNode->usNameSize;
-            if (pNode->usHandle == usHandle)
-            {
-                usSize = usMax - strlen(pszFname);
-                if (usSize > pNode->usNameSize)
-                    usSize = pNode->usNameSize;
-                if (pNode->usParentHandle)
-                {
-                    if (!wphFindPartName(pHandlesBuffer, ulBufSize,
-                                         pNode->usParentHandle,
-                                         pszFname,
-                                         usMax))
-                       return (NULL);
-                    strcat(pszFname, "\\");
-                    strncat(pszFname, pNode->szName, usSize);
-                    return pNode;
-                }
+    if (pNode = pHandlesBuf->NodeHashTable[usHandle])
+    {
+        // handle exists:
+        if (pNode->usParentHandle)
+        {
+            // node has parent:
+            // recurse first
+            if (arc = ComposeThis(pHandlesBuf,
+                                  pNode->usParentHandle,
+                                  pstrFilename,
+                                  ppNode))
+            {
+                if (arc == ERROR_INVALID_HANDLE)
+                    // parent handle not found:
+                    arc = ERROR_WPH_INVALID_PARENT_HANDLE;
+                // else leave the APIRET, this might be dangerous
+            }
+            else
+            {
+                // no error:
+                xstrcatc(pstrFilename, '\\');
+                xstrcat(pstrFilename, pNode->szName, pNode->usNameSize);
+            }
+        }
+        else
+            // no parent:
+            xstrcpy(pstrFilename, pNode->szName, pNode->usNameSize);
+    }
+    else
+        arc = ERROR_INVALID_HANDLE;
+
+    if (!arc)
+        if (ppNode)
+            *ppNode = pNode;
+
+    return (arc);
+}
+
+/*
+ *@@ wphComposePath:
+ *      returns the fully qualified path name for the specified
+ *      file-system handle. This function is very fast because
+ *      it uses a hash table for all the handles internally.
+ *
+ *      Warning: This calls a helper, which recurses.
+ *
+ *      This returns:
+ *
+ *      --  NO_ERROR
+ *
+ *      --  ERROR_WPH_CORRUPT_HANDLES_DATA: buffer data cannot be parsed.
+ *
+ *      --  ERROR_WPH_INVALID_HANDLE: usHandle cannot be found.
+ *
+ *      --  ERROR_WPH_INVALID_PARENT_HANDLE: a handle was found
+ *          that has a broken parent handle.
+ *
+ *      --  ERROR_BUFFER_OVERFLOW: cbFilename is too small to
+ *          hold the full path that was composed.
+ *
+ *@@added V0.9.16 (2001-10-02) [umoeller]
+ */
+
+APIRET wphComposePath(PHANDLESBUF pHandlesBuf,
+                      USHORT usHandle,      // in: loword of handle to search for
+                      PSZ pszFilename,
+                      ULONG cbFilename,
+                      PNODE *ppNode)        // out: node found (ptr can be NULL)
+{
+    APIRET arc = NO_ERROR;
+
+    TRY_LOUD(excpt1)
+    {
+        if (!pHandlesBuf->fNodeHashTableValid)
+            arc = wphRebuildNodeHashTable(pHandlesBuf);
+
+        if (!arc)
+        {
+            XSTRING str;
+            xstrInit(&str, CCHMAXPATH);
+            if (!(arc = ComposeThis(pHandlesBuf,
+                                    usHandle,
+                                    &str,
+                                    ppNode)))
+                if (str.ulLength > cbFilename - 1)
+                    arc = ERROR_BUFFER_OVERFLOW;
                 else
-                {
-                    strncpy(pszFname, pNode->szName, usSize);
-                    return pNode;
-                }
-            }
-        }
-        else
-           return (NULL);
-    }
-    return (NULL);
+                    memcpy(pszFilename,
+                           str.psz,
+                           str.ulLength + 1);
+        }
+    }
+    CATCH(excpt1)
+    {
+        arc = ERROR_WPH_CRASHED;
+    } END_CATCH();
+
+    return (arc);
 }
 
@@ -596,185 +862,66 @@
  *      wphReadAllBlocks, and wphFindPartName.
  *
- *@@changed V0.9.4 (2000-08-03) [umoeller]: now returning BOOL
- */
-
-BOOL wphQueryPathFromHandle(HINI hIniSystem,    // in: HINI_SYSTEM or other INI handle
-                            HOBJECT hObject,    // in: five-digit object handle
-                            PSZ pszFname,       // out: filename, if found
-                            USHORT usMax)       // in: sizeof(*pszFname)
-{
-    BOOL        brc = FALSE;
-
-    if (IsObjectDisk(hObject))
-    {
-        // use lower byte only
-        USHORT      usObjID = LOUSHORT(hObject);
-
-        PBYTE       pHandlesBuffer = NULL;
-        ULONG       cbHandlesBuffer = 0;
-
-        CHAR        szActiveHandles[100];
-        // PNODE       pReturnNode = 0;
-
-        wphQueryActiveHandles(hIniSystem, szActiveHandles, sizeof(szActiveHandles));
-
-        if (wphReadAllBlocks(hIniSystem,
-                             szActiveHandles,
-                             &pHandlesBuffer,
-                             &cbHandlesBuffer))
-        {
-            memset(pszFname, 0, usMax);
-            if (wphFindPartName(pHandlesBuffer,
-                                cbHandlesBuffer,
-                                usObjID,
-                                pszFname,
-                                usMax))
-                brc = TRUE;
-
-            free(pHandlesBuffer);
-        }
-    }
-
-    return (brc);
+ *      Returns:
+ *
+ *      --  NO_ERROR
+ *
+ *      --  ERROR_INVALID_HANDLE: hObject is invalid.
+ *
+ *@@changed V0.9.16 (2001-10-02) [umoeller]: rewritten
+ */
+
+APIRET wphQueryPathFromHandle(HINI hiniUser,      // in: HINI_USER or other INI handle
+                              HINI hiniSystem,    // in: HINI_SYSTEM or other INI handle
+                              HOBJECT hObject,    // in: 32-bit object handle
+                              PSZ pszFilename,    // out: filename, if found
+                              ULONG cbFilename)   // in: sizeof(*pszFilename)
+{
+    APIRET arc = NO_ERROR;
+
+    TRY_LOUD(excpt1)
+    {
+        PSZ pszActiveHandles;
+        if (arc = wphQueryActiveHandles(hiniSystem, &pszActiveHandles))
+            _Pmpf((__FUNCTION__ ": wphQueryActiveHandles returned %d", arc));
+        else
+        {
+            PHANDLESBUF pHandlesBuf;
+            if (arc = wphLoadHandles(hiniUser,
+                                     hiniSystem,
+                                     pszActiveHandles,
+                                     &pHandlesBuf))
+                _Pmpf((__FUNCTION__ ": wphLoadHandles returned %d", arc));
+            else
+            {
+                // is this really a file-system object?
+                if (HIUSHORT(hObject) == pHandlesBuf->usHiwordFileSystem)
+                {
+                    // use loword only
+                    USHORT      usObjID = LOUSHORT(hObject);
+
+                    memset(pszFilename, 0, cbFilename);
+                    arc = wphComposePath(pHandlesBuf,
+                                         usObjID,
+                                         pszFilename,
+                                         cbFilename,
+                                         NULL);
+
+                    _Pmpf((__FUNCTION__ ": wphFindPartName returned %d", arc));
+                }
+
+                wphFreeHandles(&pHandlesBuf);
+            }
+
+            free(pszActiveHandles);
+        }
+    }
+    CATCH(excpt1)
+    {
+        arc = ERROR_WPH_CRASHED;
+    } END_CATCH();
+
+    return (arc);
 }
 
-/* ******************************************************************
- *
- *   Manipulation functions
- *
- ********************************************************************/
-
-/*
- *@@ WriteAllBlocks:
- *      writes all blocks back to OS2SYS.INI.
- *
- *@@added V0.9.5 (2000-08-20) [umoeller]
- */
-
-BOOL WriteAllBlocks(HINI hini, PSZ pszHandles, PBYTE pBuffer, ULONG ulSize)
-{
-    PSZ     p,
-            pEnd;
-    BYTE    szBlockName[10];
-    INT     iCurBlock;
-    ULONG   ulCurSize;
-    PBYTE   pStart;
-    PDRIV   pDriv;
-    PNODE   pNode;
-
-    pStart    = pBuffer;
-    ulCurSize = 4;
-    p    = pBuffer + 4;
-    pEnd = pBuffer + ulSize;
-    iCurBlock = 1;
-    while (p < pEnd)
-    {
-        // ULONG   cbWrite = 0;
-        while (p < pEnd)
-        {
-            ULONG   ulPartSize = 0;
-            if (!memicmp(p, "DRIV", 4))
-            {
-                pDriv = (PDRIV)p;
-                ulPartSize = sizeof(DRIV) + strlen(pDriv->szName);
-            }
-            else if (!memicmp(p, "NODE", 4))
-            {
-                pNode = (PNODE)p;
-                ulPartSize = sizeof (NODE) + pNode->usNameSize;
-            }
-
-            if (ulCurSize + ulPartSize > 0x0000FFFF)
-                break;
-
-            ulCurSize += ulPartSize;
-            p         += ulPartSize;
-        }
-        sprintf(szBlockName, "BLOCK%d", iCurBlock++);
-
-        PrfWriteProfileData(hini,
-                            pszHandles,     // app
-                            szBlockName,    // key
-                            pStart,
-                            ulCurSize);
-        pStart    = p;
-        ulCurSize = 0;
-    }
-
-    while (iCurBlock < 20)
-    {
-        ULONG ulBlockSize;
-
-        sprintf(szBlockName, "BLOCK%d", iCurBlock++);
-
-        if (PrfQueryProfileSize(hini,
-                                pszHandles,
-                                szBlockName,
-                                &ulBlockSize)
-                && ulBlockSize > 0)
-            // delete block:
-            PrfWriteProfileData(hini,
-                                pszHandles,
-                                szBlockName,
-                                NULL, 0);       // delete
-            // WriteProfileData(pszHandles, szBlockName, hini, NULL, 0);
-    }
-
-    return TRUE;
-}
-
-/*
- *@@ DeleteNode:
- *      deletes a NODE in the specified buffer.
- *
- *@@added V0.9.5 (2000-08-20) [umoeller]
- */
-
-ULONG DeleteNode(PBYTE pBuffer, PNODE pNode, ULONG ulSize)
-{
-    ULONG ulDelSize = sizeof (NODE) + pNode->usNameSize;
-    USHORT usID = pNode->usHandle; // pNode->usID;
-    ULONG ulMoveSize;
-
-    if (memcmp(pNode->chName, "NODE", 4))
-        return ulSize;
-
-    ulMoveSize = (pBuffer + ulSize) - ((PBYTE)pNode + ulDelSize);
-    ulSize -= ulDelSize;
-
-    memmove(pNode, (PBYTE)pNode + ulDelSize, ulMoveSize);
-
-    while (     (PBYTE)pNode < pBuffer + ulSize
-             && !memcmp(pNode->chName, "NODE", 4)
-             && pNode->usParentHandle == usID)
-        ulSize = DeleteNode(pBuffer, pNode, ulSize);
-
-    return ulSize;
- }
-
-/*
- *@@ DeleteDrive:
- *      delete all information about a drive.
- *      in the specified buffer.
- *
- *@@added V0.9.5 (2000-08-20) [umoeller]
- */
-
-ULONG DeleteDrive(PBYTE pBuffer, PDRIV pDriv, ULONG ulSize)
-{
-    ULONG ulDelSize;
-    ULONG ulMoveSize;
-
-    if (memcmp(pDriv->chName, "DRIV", 4))
-        return ulSize;
-
-    ulDelSize = sizeof (DRIV) + strlen(pDriv->szName);
-    ulMoveSize = (pBuffer + ulSize) - ((PBYTE)pDriv + ulDelSize);
-    ulSize -= ulDelSize;
-
-    memmove(pDriv, (PBYTE)pDriv + ulDelSize, ulMoveSize);
-    return ulSize;
-}
-
-
-
+
+
Index: trunk/src/helpers/xml.c
===================================================================
--- trunk/src/helpers/xml.c	(revision 105)
+++ trunk/src/helpers/xml.c	(revision 106)
@@ -2434,11 +2434,9 @@
 
         // create the document node
-        arc = xmlCreateDomNode(NULL, // no parent
-                               DOMNODE_DOCUMENT,
-                               NULL,
-                               0,
-                               &pDocument);
-
-        if (arc == NO_ERROR)
+        if (!(arc = xmlCreateDomNode(NULL, // no parent
+                                     DOMNODE_DOCUMENT,
+                                     NULL,
+                                     0,
+                                     &pDocument)))
         {
             // store the document in the DOM
@@ -2553,8 +2551,8 @@
  */
 
-APIRET xmlParse(PXMLDOM pDom,
-                const char *pcszBuf,
-                ULONG cb,
-                BOOL fIsLast)
+APIRET xmlParse(PXMLDOM pDom,               // in: DOM created by xmlCreateDOM
+                const char *pcszBuf,        // in: chunk of XML document data (or full document)
+                ULONG cb,                   // in: size of that chunk (required)
+                BOOL fIsLast)               // in: set to TRUE if this is the last chunk
 {
     APIRET arc = NO_ERROR;
