Index: trunk/src/helpers/cctl_checkcnr.c
===================================================================
--- trunk/src/helpers/cctl_checkcnr.c	(revision 158)
+++ trunk/src/helpers/cctl_checkcnr.c	(revision 159)
@@ -677,10 +677,10 @@
 
 /*
- *@@ ctlInitCheckboxContainer:
- *
- *@@added V0.9.18 (2002-03-03) [umoeller]
- */
-
-VOID ctlInitCheckboxContainer(HWND hwndCnr)
+ *@@ ctlQueryCheckboxSize:
+ *
+ *@@added V0.9.19 (2002-04-24) [umoeller]
+ */
+
+ULONG ctlQueryCheckboxSize(VOID)
 {
     if (G_hbmCheckboxes == NULLHANDLE)
@@ -692,12 +692,24 @@
                                           SBMP_CHECKBOXES);
 
-        // _Pmpf(("hbmCheckboxes: 0x%lX", G_hbmCheckboxes));
-
         // and compute size of one checkbox
         // (4 columns, 3 rows)
+        bmih.cbFix = sizeof(bmih);      // V0.9.19 (2002-04-24) [umoeller]
         GpiQueryBitmapParameters(G_hbmCheckboxes,
                                  &bmih);
         G_cxCheckbox = bmih.cx / 4;
     }
+
+    return G_cxCheckbox;
+}
+
+/*
+ *@@ ctlInitCheckboxContainer:
+ *
+ *@@added V0.9.18 (2002-03-03) [umoeller]
+ */
+
+VOID ctlInitCheckboxContainer(HWND hwndCnr)
+{
+    ctlQueryCheckboxSize();
 
     BEGIN_CNRINFO()
Index: trunk/src/helpers/dialog.c
===================================================================
--- trunk/src/helpers/dialog.c	(revision 158)
+++ trunk/src/helpers/dialog.c	(revision 159)
@@ -11,4 +11,8 @@
  *      dialog behavior in regular window procs (see
  *      dlghSetPrevFocus and others).
+ *
+ *      If you are out to find all workarounds to get certain
+ *      buggy PM controls aligned right, this file is definitely
+ *      the place.
  *
  *      Usage: All PM programs.
@@ -42,4 +46,6 @@
     // as unsigned char
 
+#define INCL_DOSPROCESS
+#define INCL_DOSEXCEPTIONS
 #define INCL_DOSERRORS
 
@@ -52,4 +58,5 @@
 #define INCL_WINBUTTONS
 #define INCL_WINENTRYFIELDS
+#define INCL_WINSTDCNR
 #define INCL_WINSYS
 
@@ -62,4 +69,5 @@
 #include <string.h>
 #include <stdio.h>
+#include <setjmp.h>
 
 #include "setup.h"                      // code generation and debugging options
@@ -67,4 +75,5 @@
 #include "helpers\comctl.h"
 #include "helpers\dialog.h"
+#include "helpers\except.h"
 #include "helpers\gpih.h"
 #include "helpers\linklist.h"
@@ -128,5 +137,16 @@
                 cyBorder;           // cached now V0.9.19 (2002-04-17) [umoeller]
 
+    double      dFactorX,           // correlation factors for dialog units
+                dFactorY;           // V0.9.19 (2002-04-24) [umoeller]
+
 } DLGPRIVATE, *PDLGPRIVATE;
+
+// macros for the dlg units conversion;
+#define FACTOR_X     (pDlgData->dFactorX)
+#ifdef USE_SQUARE_CORRELATION
+#define FACTOR_Y     (pDlgData->dFactorX)
+#else
+#define FACTOR_Y     (pDlgData->dFactorY)
+#endif
 
 typedef struct _COLUMNDEF *PCOLUMNDEF;
@@ -167,6 +187,18 @@
     PVOID       pvDefinition;       // either a PTABLEDEF or a PCONTROLDEF
 
-    CONTROLPOS  cpControl,          // real pos and size of control
-                cpColumn;           // pos and size of column; can be wider, spacings applied
+    CONTROLPOS  cpControl,          // real pos and size of control; if the control is
+                                    // a subtable, this receives the size of the table
+                                    // without spacings
+                cpColumn;           // pos and size of column; this is the size of the
+                                    // column plus the spacing from the CONTROLDEF
+                                    // applied
+                                    // For PM group controls around tables, this is
+                                    // receives the following spacings:
+                                    // x += GROUP_INNER_SPACING_X + CONTROLDEF.ulSpacing
+                                    // y += GROUP_INNER_SPACING_Y + CONTROLDEF.ulSpacing
+                                    // cx += 2 * GROUP_INNER_SPACING_X + 2 * CONTROLDEF.ulSpacing
+                                    // cy +=   2 * GROUP_INNER_SPACING_Y
+                                    //       + GROUP_INNER_SPACING_EXTRA_TOP
+                                    //       + 2 * CONTROLDEF.duSpacing
 
     HWND        hwndControl;        // created control; NULLHANDLE for tables always
@@ -338,6 +370,7 @@
             */
             rcl.xRight = ulWidth;
-            if (pControlDef->szlControlProposed.cy > 0)
-                rcl.yTop = pControlDef->szlControlProposed.cy;   // V0.9.12 (2001-05-31) [umoeller]
+            if (pControlDef->szlDlgUnits.cy > 0)
+                rcl.yTop = pControlDef->szlDlgUnits.cy * FACTOR_Y;
+                        // V0.9.12 (2001-05-31) [umoeller]
             else
                 rcl.yTop = winhQueryScreenCY() * 2 / 3;
@@ -402,5 +435,6 @@
                 {
                     // give a little extra width for the box bitmap
-                    pszlAuto->cx += 20;     // @@todo
+                    // V0.9.19 (2002-04-24) [umoeller]
+                    pszlAuto->cx += ctlQueryCheckboxSize() + 4;
                     // and height
                     pszlAuto->cy += 2;
@@ -476,4 +510,6 @@
  *@@changed V0.9.16 (2002-02-02) [umoeller]: added support for explicit group size
  *@@changed V0.9.19 (2002-04-17) [umoeller]: fixes for the STUPID drop-down comboboxes
+ *@@changed V0.9.19 (2002-04-24) [umoeller]: fixed PM groups alignment
+ *@@changed V0.9.19 (2002-04-24) [umoeller]: added resolution correlation
  */
 
@@ -484,6 +520,6 @@
     APIRET      arc = NO_ERROR;
     PCONTROLDEF pControlDef = NULL;
-    ULONG       ulExtraCX = 0,
-                ulExtraCY = 0;
+    ULONG       xExtraColumn = 0,
+                yExtraColumn = 0;
 
     if (pColumnDef->fIsNestedTable)
@@ -501,22 +537,33 @@
 
             // should we create a PM control around the table?
-            if (pTableDef->pCtlDef)
+            if (pControlDef = pTableDef->pCtlDef)
             {
                 // yes:
+                LONG cxCalc = pControlDef->szlDlgUnits.cx * FACTOR_X,
+                     cyCalc = pControlDef->szlDlgUnits.cy * FACTOR_Y;
 
                 // check if maybe an explicit size was specified
-                // for the group; if that is larger than what
+                // for the group; only if that is larger than what
                 // we've calculated above, use it instead
-                if (pTableDef->pCtlDef->szlControlProposed.cx > pColumnDef->cpControl.cx)
+                if (cxCalc > pColumnDef->cpControl.cx)
                         // should be -1 for auto-size
-                    pColumnDef->cpControl.cx = pTableDef->pCtlDef->szlControlProposed.cx;
-
-                if (pTableDef->pCtlDef->szlControlProposed.cy > pColumnDef->cpControl.cy)
+                    pColumnDef->cpControl.cx = cxCalc;
+
+                if (cyCalc > pColumnDef->cpControl.cy)
                         // should be -1 for auto-size
-                    pColumnDef->cpControl.cy = pTableDef->pCtlDef->szlControlProposed.cy;
-
-                // in any case, make this wider
-                ulExtraCX =    2 * PM_GROUP_SPACING_X;
-                ulExtraCY =    (PM_GROUP_SPACING_X + PM_GROUP_SPACING_TOP);
+                    pColumnDef->cpControl.cy = cyCalc;
+
+                // in any case, add the inner spacing so that the group
+                // will be large enough
+                // fixed V0.9.19 (2002-04-24) [umoeller]
+                xExtraColumn =  (   (2 * pControlDef->duSpacing)
+                                  + 2 * GROUP_INNER_SPACING_X
+                                ) * FACTOR_X;
+                yExtraColumn =  (   (2 * pControlDef->duSpacing)
+                                  + GROUP_OUTER_SPACING_BOTTOM
+                                  + GROUP_INNER_SPACING_BOTTOM
+                                  + GROUP_INNER_SPACING_TOP
+                                  + GROUP_OUTER_SPACING_TOP
+                                ) * FACTOR_Y;
             }
         }
@@ -533,13 +580,17 @@
         if (ProcessMode == PROCESS_1_CALC_SIZES)
         {
-            if (    (pControlDef->szlControlProposed.cx == -1)
-                 || (pControlDef->szlControlProposed.cy == -1)
+            // V0.9.19 (2002-04-24) [umoeller]: added resolution correlation
+            LONG cxCalc = pControlDef->szlDlgUnits.cx * FACTOR_X,
+                 cyCalc = pControlDef->szlDlgUnits.cy * FACTOR_Y;
+
+            if (    (pControlDef->szlDlgUnits.cx == -1)
+                 || (pControlDef->szlDlgUnits.cy == -1)
                )
             {
                 ULONG ulWidth;
-                if (pControlDef->szlControlProposed.cx == -1)
+                if (pControlDef->szlDlgUnits.cx == -1)
                     ulWidth = 1000;
                 else
-                    ulWidth = pControlDef->szlControlProposed.cx;
+                    ulWidth = cxCalc;
                 arc = CalcAutoSize(pControlDef,
                                    ulWidth,
@@ -548,6 +599,6 @@
             }
 
-            if (    (pControlDef->szlControlProposed.cx < -1)
-                 && (pControlDef->szlControlProposed.cx >= -100)
+            if (    (pControlDef->szlDlgUnits.cx < -1)
+                 && (pControlDef->szlDlgUnits.cx >= -100)
                )
             {
@@ -558,6 +609,6 @@
             }
 
-            if (    (pControlDef->szlControlProposed.cy < -1)
-                 && (pControlDef->szlControlProposed.cy >= -100)
+            if (    (pControlDef->szlDlgUnits.cy < -1)
+                 && (pControlDef->szlDlgUnits.cy >= -100)
                )
             {
@@ -570,26 +621,31 @@
             if (!arc)
             {
-                if (pControlDef->szlControlProposed.cx < 0)
+                if (pControlDef->szlDlgUnits.cx < 0)
+                    // this was autosize:
                     pColumnDef->cpControl.cx = szlAuto.cx;
                 else
-                    pColumnDef->cpControl.cx = pControlDef->szlControlProposed.cx;
-
-                if (pControlDef->szlControlProposed.cy < 0)
+                    // this was explicit: use converted size
+                    // V0.9.19 (2002-04-24) [umoeller]
+                    pColumnDef->cpControl.cx = cxCalc;
+
+                if (pControlDef->szlDlgUnits.cy < 0)
+                    // this was autosize:
                     pColumnDef->cpControl.cy = szlAuto.cy;
                 else
-                    pColumnDef->cpControl.cy = pControlDef->szlControlProposed.cy;
+                    // this was explicit: use converted size
+                    // V0.9.19 (2002-04-24) [umoeller]
+                    pColumnDef->cpControl.cy = cyCalc;
             }
 
         } // end if (ProcessMode == PROCESS_1_CALC_SIZES)
 
-        ulExtraCX
-        = ulExtraCY
-        = (2 * pControlDef->ulSpacing);
+        xExtraColumn = 2 * (pControlDef->duSpacing * FACTOR_X);
+        yExtraColumn = 2 * (pControlDef->duSpacing * FACTOR_Y);
     }
 
     pColumnDef->cpColumn.cx =   pColumnDef->cpControl.cx
-                               + ulExtraCX;
+                              + xExtraColumn;
     pColumnDef->cpColumn.cy =   pColumnDef->cpControl.cy
-                               + ulExtraCY;
+                              + yExtraColumn;
 
     if (    (pControlDef)
@@ -614,5 +670,5 @@
                   + pDlgData->fmLast.lExternalLeading
                   + 2 * cyMargin
-                  + ulExtraCY;
+                  + yExtraColumn;
         }
     }
@@ -628,4 +684,5 @@
  *@@added V0.9.15 (2001-08-26) [umoeller]
  *@@changed V0.9.16 (2001-10-15) [umoeller]: added APIRET
+ *@@changed V0.9.19 (2002-04-24) [umoeller]: fixed PM groups alignment
  */
 
@@ -638,6 +695,6 @@
 
     // calculate column position: this includes spacing
-    LONG   lSpacingX = 0,
-           lSpacingY = 0;
+    LONG   xSpacingControl = 0,
+           ySpacingControl = 0;
 
     // column position = *plX on ProcessRow stack
@@ -672,6 +729,12 @@
         {
             // yes:
-            lSpacingX = PM_GROUP_SPACING_X;     // V0.9.16 (2001-10-15) [umoeller]
-            lSpacingY = PM_GROUP_SPACING_X;     // V0.9.16 (2001-10-15) [umoeller]
+            // V0.9.19 (2002-04-24) [umoeller]
+            xSpacingControl = (   pTableDef->pCtlDef->duSpacing
+                                + GROUP_INNER_SPACING_X
+                              ) * FACTOR_X;
+            ySpacingControl = (   pTableDef->pCtlDef->duSpacing
+                                + GROUP_OUTER_SPACING_BOTTOM
+                                + GROUP_INNER_SPACING_BOTTOM
+                              ) * FACTOR_Y;
         }
     }
@@ -680,5 +743,6 @@
         // no nested table, but control:
         PCONTROLDEF pControlDef = (PCONTROLDEF)pColumnDef->pvDefinition;
-        lSpacingX = lSpacingY = pControlDef->ulSpacing;
+        xSpacingControl = pControlDef->duSpacing * FACTOR_X;
+        ySpacingControl = pControlDef->duSpacing * FACTOR_Y;
     }
 
@@ -688,7 +752,7 @@
     // calculate CONTROL pos from COLUMN pos by applying spacing
     pColumnDef->cpControl.x =   (LONG)pColumnDef->cpColumn.x
-                              + lSpacingX;
+                              + xSpacingControl;
     pColumnDef->cpControl.y =   (LONG)pColumnDef->cpColumn.y
-                              + lSpacingY;
+                              + ySpacingControl;
 
     if (pColumnDef->fIsNestedTable)
@@ -716,4 +780,5 @@
  *@@changed V0.9.16 (2001-12-08) [umoeller]: fixed entry field ES_MARGIN positioning
  *@@changed V0.9.19 (2002-04-17) [umoeller]: fixes for the STUPID drop-down comboboxes
+ *@@changed V0.9.19 (2002-04-24) [umoeller]: fixed PM groups alignment
  */
 
@@ -747,27 +812,39 @@
             // (do this AFTER the other controls from recursing,
             // otherwise the stupid container doesn't show up)
-            if (pTableDef->pCtlDef)
+            if (pControlDef = pTableDef->pCtlDef)
             {
                 // yes:
                 // pcp  = &pColumnDef->cpColumn;  // !! not control
-                pControlDef = pTableDef->pCtlDef;
                 pcszClass = pControlDef->pcszClass;
                 pcszTitle = pControlDef->pcszText;
                 flStyle = pControlDef->flStyle;
 
-                x  =   pColumnDef->cpColumn.x
+                // note: we do use cpControl, which is cpColumn plus
+                // spacings applied. But for groups, this is the
+                // following (see ColumnCalcPositions):
+                // V0.9.19 (2002-04-24) [umoeller]
+                // x is cpColumn.x plus GROUP_INNER_SPACING_X plus group control spacing
+                // y is cpColumn.y plus GROUP_INNER_SPACING_Y plus group control spacing
+                // cx is cpColumn.cx plus 2 * GROUP_INNER_SPACING_Y plus 2 * group control spacing
+                // cy is cpColumn.cy plus 2 * GROUP_INNER_SPACING_Y
+                //      plus GROUP_INNER_SPACING_TOP
+                //      plus 2 * group control spacing
+                // so this needs some hacks again
+                x  =   pColumnDef->cpControl.x
                      + pDlgData->ptlTotalOfs.x
-                     + PM_GROUP_SPACING_X / 2;
-                cx =   pColumnDef->cpColumn.cx
-                     - PM_GROUP_SPACING_X;
-                    // note, just one spacing: for the _column_ size,
-                    // we have specified 2 X spacings
-                y  =   pColumnDef->cpColumn.y
+                     - (GROUP_INNER_SPACING_X * FACTOR_X);
+                     ;
+                cx =   pColumnDef->cpControl.cx
+                     + (2 * (GROUP_INNER_SPACING_X * FACTOR_X));
+                     ;
+                y  =   pColumnDef->cpControl.y
                      + pDlgData->ptlTotalOfs.y
-                     + PM_GROUP_SPACING_X / 2;
-                // cy = pcp->cy - PM_GROUP_SPACING_X;
-                // cy = pcp->cy - /* PM_GROUP_SPACING_X - */ PM_GROUP_SPACING_TOP;
-                cy =   pColumnDef->cpColumn.cy
-                     - PM_GROUP_SPACING_X / 2; //  - PM_GROUP_SPACING_TOP / 2;
+                     - (GROUP_INNER_SPACING_BOTTOM * FACTOR_Y);
+                     ;
+                cy =   pColumnDef->cpControl.cy
+                     + ( (   GROUP_INNER_SPACING_BOTTOM
+                           + GROUP_INNER_SPACING_TOP
+                         ) * FACTOR_Y);
+                     ;
             }
 
@@ -848,5 +925,7 @@
                             pColumnDef->cpControl.cy));
                     _Pmpf(("   cyDelta = %d", cyDelta));
-                    y -= cyDelta + 3 * pDlgData->cyBorder + pControlDef->ulSpacing;
+                    y -=   cyDelta
+                         + 3 * pDlgData->cyBorder
+                         + pControlDef->duSpacing * FACTOR_Y;
                     // cy += cyDelta;
                 }
@@ -921,5 +1000,4 @@
                 winhSetPresColor(hwndDebug, PP_FOREGROUNDCOLOR, RGBCOL_DARKGREEN);
 
-                /*
                 // and another one for the control size
                 hwndDebug =
@@ -938,5 +1016,4 @@
                                 NULL);
                 winhSetPresColor(hwndDebug, PP_FOREGROUNDCOLOR, RGBCOL_RED);
-                */
             }
 #endif
@@ -1081,6 +1158,6 @@
                 PCONTROLDEF pControlDef = (PCONTROLDEF)pColumnDef->pvDefinition;
 
-                if (    (pControlDef->szlControlProposed.cx < -1)
-                     && (pControlDef->szlControlProposed.cx >= -100)
+                if (    (pControlDef->szlDlgUnits.cx < -1)
+                     && (pControlDef->szlDlgUnits.cx >= -100)
                    )
                 {
@@ -1088,17 +1165,18 @@
                     // this we ignored during PROCESS_1_CALC_SIZES
                     // (see ColumnCalcSizes); now set it to the
-                    // table width!
+                    // percentage of the table width!
                     ULONG cxThis = pOwningRow->pOwningTable->cpTable.cx
-                                    * -pControlDef->szlControlProposed.cx / 100;
+                                    * -pControlDef->szlDlgUnits.cx
+                                    / 100;
 
                     // but the table already has spacing applied,
                     // so reduce that
                     pColumnDef->cpControl.cx = cxThis
-                                            - (2 * pControlDef->ulSpacing);
+                                            - (2 * (pControlDef->duSpacing * FACTOR_X));
 
                     pColumnDef->cpColumn.cx = cxThis;
 
                     // now we might have to re-compute auto-size
-                    if (pControlDef->szlControlProposed.cy == -1)
+                    if (pControlDef->szlDlgUnits.cy == -1)
                     {
                         SIZEL   szlAuto;
@@ -1115,23 +1193,24 @@
 
                             pColumnDef->cpControl.cy = szlAuto.cy;
-                            pColumnDef->cpColumn.cy = szlAuto.cy
-                                        + (2 * pControlDef->ulSpacing);
+                            pColumnDef->cpColumn.cy =   szlAuto.cy
+                                                      + (2 * (pControlDef->duSpacing * FACTOR_Y));
                         }
                     }
                 }
 
-                if (    (pControlDef->szlControlProposed.cy < -1)
-                     && (pControlDef->szlControlProposed.cy >= -100)
+                if (    (pControlDef->szlDlgUnits.cy < -1)
+                     && (pControlDef->szlDlgUnits.cy >= -100)
                    )
                 {
                     // same thing for CY, but this time we
-                    // take the row height
+                    // take the percentage of the row height
                     ULONG cyThis = pOwningRow->cpRow.cy
-                                    * -pControlDef->szlControlProposed.cy / 100;
+                                    * -pControlDef->szlDlgUnits.cy
+                                    / 100;
 
                     // but the table already has spacing applied,
                     // so reduce that
-                    pColumnDef->cpControl.cy = cyThis
-                                            - (2 * pControlDef->ulSpacing);
+                    pColumnDef->cpControl.cy =   cyThis
+                                               - (2 * (pControlDef->duSpacing * FACTOR_Y));
 
                     pColumnDef->cpColumn.cy = cyThis;
@@ -1510,11 +1589,10 @@
 } STACKITEM, *PSTACKITEM;
 
-#define SPACING     10
-
 /*
  *@@ Dlg0_Init:
  *
  *@@added V0.9.15 (2001-08-26) [umoeller]
- *@@changed V0.9.18 (2002-03-03) [umoeller]: aded pllWindows
+ *@@changed V0.9.18 (2002-03-03) [umoeller]: added pllWindows
+ *@@changed V0.9.19 (2002-04-24) [umoeller]: added resolution correlation
  */
 
@@ -1523,5 +1601,7 @@
                         PLINKLIST pllControls)
 {
-    PDLGPRIVATE pDlgData;
+    PDLGPRIVATE     pDlgData;
+    POINTL          ptl = {100, 100};
+
     if (!(pDlgData = NEW(DLGPRIVATE)))
         return (ERROR_NOT_ENOUGH_MEMORY);
@@ -1537,4 +1617,27 @@
     pDlgData->cxBorder = WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
     pDlgData->cyBorder = WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);
+
+    // check how many pixels we get out of the
+    // dlgunits (100/100) for mapping all sizes
+    // V0.9.19 (2002-04-24) [umoeller]
+    if (WinMapDlgPoints(NULLHANDLE,
+                        &ptl,
+                        1,
+                        TRUE))
+    {
+        // this worked:
+        // for 1024x768, I get 200/250 out of the above,
+        // so calculate a factor from that; we multiply
+        // szlDlgUnits with this factor when calculating
+        // the sizes
+        pDlgData->dFactorX = (double)ptl.x / (double)100;       // 2   on 1024x768
+        pDlgData->dFactorY = (double)ptl.y / (double)100;       // 2.5 on 1024x768
+    }
+    else
+    {
+        // didn't work:
+        pDlgData->dFactorX = 2;
+        pDlgData->dFactorY = 2.5;
+    }
 
     *ppDlgData = pDlgData;
@@ -1777,7 +1880,6 @@
      */
 
-    pDlgData->ptlTotalOfs.x
-    = pDlgData->ptlTotalOfs.y
-    = SPACING;
+    pDlgData->ptlTotalOfs.x = DLG_OUTER_SPACING_X * FACTOR_X;
+    pDlgData->ptlTotalOfs.y = DLG_OUTER_SPACING_Y * FACTOR_Y;
 
     ProcessAll(pDlgData,
@@ -2088,4 +2190,5 @@
  *@@changed V0.9.14 (2001-08-21) [umoeller]: fixed default push button problems
  *@@changed V0.9.16 (2001-12-06) [umoeller]: fixed bad owner if not direct desktop child
+ *@@changed V0.9.19 (2002-04-24) [umoeller]: added excpt handling
  */
 
@@ -2102,143 +2205,152 @@
     APIRET      arc = NO_ERROR;
 
-    ULONG       ul;
-
-    PDLGPRIVATE  pDlgData = NULL;
-
-    HWND        hwndDesktop = WinQueryDesktopWindow(NULLHANDLE, NULLHANDLE);
-                                        // works with a null HAB
-
-    /*
-     *  1) parse the table and create structures from it
-     *
-     */
-
-    if (!(arc = Dlg0_Init(&pDlgData,
-                          pcszControlsFont,
-                          NULL)))
-    {
-        if (!(arc = Dlg1_ParseTables(pDlgData,
-                                     paDlgItems,
-                                     cDlgItems)))
-        {
-            /*
-             *  2) create empty dialog frame
-             *
-             */
-
-            FRAMECDATA      fcData = {0};
-            ULONG           flStyle = 0;
-            HWND            hwndOwnersParent;
-
-            fcData.cb = sizeof(FRAMECDATA);
-            fcData.flCreateFlags = flCreateFlags | 0x40000000L;
-
-            if (flCreateFlags & FCF_SIZEBORDER)
-                // dialog has size border:
-                // add "clip siblings" style
-                flStyle |= WS_CLIPSIBLINGS;
-
-            if (hwndOwner == HWND_DESKTOP)
-                // there's some dumb XWorkplace code left
-                // which uses this, and this disables the
-                // mouse for some reason
-                // V0.9.14 (2001-07-07) [umoeller]
-                hwndOwner = NULLHANDLE;
-
-            // now, make sure the owner window is child of
-            // HWND_DESKTOP... if it is not, we'll only disable
-            // some dumb child window, which is not sufficient
-            // V0.9.16 (2001-12-06) [umoeller]
-            while (    (hwndOwner)
-                    && (hwndOwnersParent = WinQueryWindow(hwndOwner, QW_PARENT))
-                    && (hwndOwnersParent != hwndDesktop)
-                  )
-                hwndOwner = hwndOwnersParent;
-
-            if (!(pDlgData->hwndDlg = WinCreateWindow(HWND_DESKTOP,
-                                                      WC_FRAME,
-                                                      (PSZ)pcszDlgTitle,
-                                                      flStyle,        // style; invisible for now
-                                                      0, 0, 0, 0,
-                                                      hwndOwner,
-                                                      HWND_TOP,
-                                                      0,              // ID
-                                                      &fcData,
-                                                      NULL)))          // presparams
-                arc = DLGERR_CANNOT_CREATE_FRAME;
-            else
+    TRY_LOUD(excpt1)
+    {
+        ULONG       ul;
+
+        PDLGPRIVATE  pDlgData = NULL;
+
+        HWND        hwndDesktop = WinQueryDesktopWindow(NULLHANDLE, NULLHANDLE);
+                                            // works with a null HAB
+
+        /*
+         *  1) parse the table and create structures from it
+         *
+         */
+
+        if (!(arc = Dlg0_Init(&pDlgData,
+                              pcszControlsFont,
+                              NULL)))
+        {
+            if (!(arc = Dlg1_ParseTables(pDlgData,
+                                         paDlgItems,
+                                         cDlgItems)))
             {
-                HWND    hwndDlg = pDlgData->hwndDlg;
-                HWND    hwndFocusItem = NULLHANDLE;
-                RECTL   rclClient;
-
                 /*
-                 *  3) compute size of all controls
+                 *  2) create empty dialog frame
                  *
                  */
 
-                if (!(arc = Dlg2_CalcSizes(pDlgData)))
+                FRAMECDATA      fcData = {0};
+                ULONG           flStyle = 0;
+                HWND            hwndOwnersParent;
+
+                fcData.cb = sizeof(FRAMECDATA);
+                fcData.flCreateFlags = flCreateFlags | 0x40000000L;
+
+                if (flCreateFlags & FCF_SIZEBORDER)
+                    // dialog has size border:
+                    // add "clip siblings" style
+                    flStyle |= WS_CLIPSIBLINGS;
+
+                if (hwndOwner == HWND_DESKTOP)
+                    // there's some dumb XWorkplace code left
+                    // which uses this, and this disables the
+                    // mouse for some reason
+                    // V0.9.14 (2001-07-07) [umoeller]
+                    hwndOwner = NULLHANDLE;
+
+                // now, make sure the owner window is child of
+                // HWND_DESKTOP... if it is not, we'll only disable
+                // some dumb child window, which is not sufficient
+                // V0.9.16 (2001-12-06) [umoeller]
+                while (    (hwndOwner)
+                        && (hwndOwnersParent = WinQueryWindow(hwndOwner, QW_PARENT))
+                        && (hwndOwnersParent != hwndDesktop)
+                      )
+                    hwndOwner = hwndOwnersParent;
+
+                if (!(pDlgData->hwndDlg = WinCreateWindow(HWND_DESKTOP,
+                                                          WC_FRAME,
+                                                          (PSZ)pcszDlgTitle,
+                                                          flStyle,        // style; invisible for now
+                                                          0, 0, 0, 0,
+                                                          hwndOwner,
+                                                          HWND_TOP,
+                                                          0,              // ID
+                                                          &fcData,
+                                                          NULL)))          // presparams
+                    arc = DLGERR_CANNOT_CREATE_FRAME;
+                else
                 {
-                    WinSubclassWindow(hwndDlg, pfnwpDialogProc);
+                    HWND    hwndDlg = pDlgData->hwndDlg;
+                    HWND    hwndFocusItem = NULLHANDLE;
+                    RECTL   rclClient;
 
                     /*
-                     *  4) compute size of dialog client from total
-                     *     size of all controls
-                     */
-
-                    // calculate the frame size from the client size
-                    rclClient.xLeft = 10;
-                    rclClient.yBottom = 10;
-                    rclClient.xRight = pDlgData->szlClient.cx + 2 * SPACING;
-                    rclClient.yTop = pDlgData->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);
-
-                    arc = Dlg3_PositionAndCreate(pDlgData,
-                                                 &hwndFocusItem);
-
-                    /*
-                     *  7) WM_INITDLG, set focus
+                     *  3) compute size of all controls
                      *
                      */
 
-                    if (!WinSendMsg(pDlgData->hwndDlg,
-                                    WM_INITDLG,
-                                    (MPARAM)hwndFocusItem,
-                                    (MPARAM)pCreateParams))
+                    if (!(arc = Dlg2_CalcSizes(pDlgData)))
                     {
-                        // if WM_INITDLG returns FALSE, this means
-                        // the dlg proc has not changed the focus;
-                        // we must then set the focus here
-                        WinSetFocus(HWND_DESKTOP, hwndFocusItem);
+                        WinSubclassWindow(hwndDlg, pfnwpDialogProc);
+
+                        /*
+                         *  4) compute size of dialog client from total
+                         *     size of all controls
+                         */
+
+                        // calculate the frame size from the client size
+                        rclClient.xLeft = 10;
+                        rclClient.yBottom = 10;
+                        rclClient.xRight =   pDlgData->szlClient.cx
+                                           + 2 * (DLG_OUTER_SPACING_X * FACTOR_X);
+                        rclClient.yTop   =   pDlgData->szlClient.cy
+                                           + 2 * (DLG_OUTER_SPACING_Y * FACTOR_Y);
+                        WinCalcFrameRect(hwndDlg,
+                                         &rclClient,
+                                         FALSE);            // frame from client
+
+                        WinSetWindowPos(hwndDlg,
+                                        0,
+                                        10,
+                                        10,
+                                        rclClient.xRight,
+                                        rclClient.yTop,
+                                        SWP_MOVE | SWP_SIZE | SWP_NOADJUST);
+
+                        arc = Dlg3_PositionAndCreate(pDlgData,
+                                                     &hwndFocusItem);
+
+                        /*
+                         *  7) WM_INITDLG, set focus
+                         *
+                         */
+
+                        if (!WinSendMsg(pDlgData->hwndDlg,
+                                        WM_INITDLG,
+                                        (MPARAM)hwndFocusItem,
+                                        (MPARAM)pCreateParams))
+                        {
+                            // if WM_INITDLG returns FALSE, this means
+                            // the dlg proc has not changed the focus;
+                            // we must then set the focus here
+                            WinSetFocus(HWND_DESKTOP, hwndFocusItem);
+                        }
                     }
                 }
             }
-        }
-
-        if (arc)
-        {
-            // error: clean up
-            if (pDlgData->hwndDlg)
+
+            if (arc)
             {
-                WinDestroyWindow(pDlgData->hwndDlg);
-                pDlgData->hwndDlg = NULLHANDLE;
+                // error: clean up
+                if (pDlgData->hwndDlg)
+                {
+                    WinDestroyWindow(pDlgData->hwndDlg);
+                    pDlgData->hwndDlg = NULLHANDLE;
+                }
             }
-        }
-        else
-            // no error: output dialog
-            *phwndDlg = pDlgData->hwndDlg;
-
-        Dlg9_Cleanup(&pDlgData);
-    }
+            else
+                // no error: output dialog
+                *phwndDlg = pDlgData->hwndDlg;
+
+            Dlg9_Cleanup(&pDlgData);
+        }
+    }
+    CATCH(excpt1)
+    {
+        arc = ERROR_PROTECTION_VIOLATION;
+    } END_CATCH();
 
     if (arc)
@@ -2287,4 +2399,5 @@
  *@@added V0.9.16 (2001-09-29) [umoeller]
  *@@changed V0.9.18 (2002-03-03) [umoeller]: added pszlClient, fixed output
+ *@@changed V0.9.19 (2002-04-24) [umoeller]: added excpt handling
  */
 
@@ -2299,57 +2412,66 @@
     APIRET      arc = NO_ERROR;
 
-    ULONG       ul;
-
-    PDLGPRIVATE  pDlgData = NULL;
-    PLINKLIST   pllControls = NULL;
-
-    /*
-     *  1) parse the table and create structures from it
-     *
-     */
-
-    if (ppllControls)
-        pllControls = *(PLINKLIST*)ppllControls = lstCreate(FALSE);
-
-    if (!(arc = Dlg0_Init(&pDlgData,
-                          pcszControlsFont,
-                          pllControls)))
-    {
-        if (!(arc = Dlg1_ParseTables(pDlgData,
-                                     paDlgItems,
-                                     cDlgItems)))
-        {
-            HWND hwndFocusItem;
-
-            /*
-             *  2) create empty dialog frame
-             *
-             */
-
-            pDlgData->hwndDlg = hwndDlg;
-
-            /*
-             *  3) compute size of all controls
-             *
-             */
-
-            Dlg2_CalcSizes(pDlgData);
-
-            if (pszlClient)
+    TRY_LOUD(excpt1)
+    {
+        ULONG       ul;
+
+        PDLGPRIVATE  pDlgData = NULL;
+        PLINKLIST   pllControls = NULL;
+
+        /*
+         *  1) parse the table and create structures from it
+         *
+         */
+
+        if (ppllControls)
+            pllControls = *(PLINKLIST*)ppllControls = lstCreate(FALSE);
+
+        if (!(arc = Dlg0_Init(&pDlgData,
+                              pcszControlsFont,
+                              pllControls)))
+        {
+            if (!(arc = Dlg1_ParseTables(pDlgData,
+                                         paDlgItems,
+                                         cDlgItems)))
             {
-                pszlClient->cx = pDlgData->szlClient.cx + 2 * SPACING;
-                pszlClient->cy = pDlgData->szlClient.cy + 2 * SPACING;
+                HWND hwndFocusItem;
+
+                /*
+                 *  2) create empty dialog frame
+                 *
+                 */
+
+                pDlgData->hwndDlg = hwndDlg;
+
+                /*
+                 *  3) compute size of all controls
+                 *
+                 */
+
+                Dlg2_CalcSizes(pDlgData);
+
+                if (pszlClient)
+                {
+                    pszlClient->cx =    pDlgData->szlClient.cx
+                                      + 2 * (DLG_OUTER_SPACING_X * FACTOR_X);
+                    pszlClient->cy =    pDlgData->szlClient.cy
+                                      + 2 * (DLG_OUTER_SPACING_Y * FACTOR_Y);
+                }
+
+                if (flFlags & DFFL_CREATECONTROLS)
+                {
+                    if (!(arc = Dlg3_PositionAndCreate(pDlgData,
+                                                       &hwndFocusItem)))
+                        WinSetFocus(HWND_DESKTOP, hwndFocusItem);
+                }
             }
 
-            if (flFlags & DFFL_CREATECONTROLS)
-            {
-                if (!(arc = Dlg3_PositionAndCreate(pDlgData,
-                                                   &hwndFocusItem)))
-                    WinSetFocus(HWND_DESKTOP, hwndFocusItem);
-            }
-        }
-
-        Dlg9_Cleanup(&pDlgData);
-    }
+            Dlg9_Cleanup(&pDlgData);
+        }
+    }
+    CATCH(excpt1)
+    {
+        arc = ERROR_PROTECTION_VIOLATION;
+    } END_CATCH();
 
     if (arc)
@@ -2470,5 +2592,5 @@
  +                       fnwpMyDialogProc,
  +                       "Title",
- +                       pArray->paDialogItems,     // dialog array!
+ +                       pArray->paDlgItems,        // dialog array!
  +                       pArray->cDlgItemsNow,      // real count of items!
  +                       NULL,
@@ -2588,8 +2710,32 @@
 
 /*
+ *@@ fnwpMessageBox:
+ *
+ *@@added V0.9.19 (2002-04-24) [umoeller]
+ */
+
+MRESULT EXPENTRY fnwpMessageBox(HWND hwndBox, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+    switch (msg)
+    {
+        case WM_HELP:
+        {
+            PFNHELP pfnHelp;
+            if (pfnHelp = (PFNHELP)WinQueryWindowPtr(hwndBox, QWL_USER))
+                pfnHelp(hwndBox);
+
+            return 0;
+        }
+    }
+
+    return WinDefDlgProc(hwndBox, msg, mp1, mp2);
+}
+
+/*
  *@@ dlghCreateMessageBox:
  *
  *@@added V0.9.13 (2001-06-21) [umoeller]
  *@@changed V0.9.14 (2001-07-26) [umoeller]: fixed missing focus on buttons
+ *@@changed V0.9.19 (2002-04-24) [umoeller]: added pfnHelp
  */
 
@@ -2599,4 +2745,5 @@
                             PCSZ pcszTitle,
                             PCSZ pcszMessage,
+                            PFNHELP pfnHelp,           // in: help callback or NULL
                             ULONG flFlags,
                             PCSZ pcszFont,
@@ -2604,61 +2751,20 @@
                             PULONG pulAlarmFlag)      // out: alarm sound to be played
 {
+    APIRET arc;
+
     CONTROLDEF
-        Icon = {
-                        WC_STATIC,
-                        NULL,           // text, set below
-                        WS_VISIBLE | SS_ICON,
-                        0,          // ID
-                        NULL,       // no font
-                        0,
-                        { SZL_AUTOSIZE, SZL_AUTOSIZE },
-                        5
-                    },
-        InfoText =
-                    {
-                        WC_STATIC,
-                        NULL,       // text, set below
-                        WS_VISIBLE | SS_TEXT | DT_WORDBREAK | DT_LEFT | DT_TOP,
-                        10,          // ID
-                        CTL_COMMON_FONT,
-                        0,
-                        { 400, SZL_AUTOSIZE },
-                        5
-                    },
-        Buttons[] = {
-                        {
-                            WC_BUTTON,
-                            NULL,       // text, set below
-                            WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
-                            1,          // ID
-                            CTL_COMMON_FONT,  // no font
-                            0,
-                            { 100, 30 },
-                            5
-                        },
-                        {
-                            WC_BUTTON,
-                            NULL,       // text, set below
-                            WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
-                            2,          // ID
-                            CTL_COMMON_FONT,  // no font
-                            0,
-                            { 100, 30 },
-                            5
-                        },
-                        {
-                            WC_BUTTON,
-                            NULL,       // text, set below
-                            WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
-                            3,          // ID
-                            CTL_COMMON_FONT,  // no font
-                            0,
-                            { 100, 30 },
-                            5
-                        }
-                    };
-
-    DLGHITEM MessageBox[] =
-                 {
+        Icon = CONTROLDEF_ICON(NULLHANDLE, 0),
+        Spacing = CONTROLDEF_TEXT(NULL, 0, 1, 1),
+        InfoText = CONTROLDEF_TEXT_WORDBREAK(NULL, 10, 200),
+        Buttons[] =
+        {
+            CONTROLDEF_PUSHBUTTON(NULL, 1, STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT),
+            CONTROLDEF_PUSHBUTTON(NULL, 2, STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT),
+            CONTROLDEF_PUSHBUTTON(NULL, 3, STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT),
+            CONTROLDEF_HELPPUSHBUTTON(NULL, 4, STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT)
+        };
+
+    DLGHITEM MessageBoxFront[] =
+                {
                     START_TABLE,
                         START_ROW(ROW_VALIGN_CENTER),
@@ -2666,14 +2772,26 @@
                         START_TABLE,
                             START_ROW(ROW_VALIGN_CENTER),
+                                CONTROL_DEF(&Spacing),
+                            START_ROW(ROW_VALIGN_CENTER),
                                 CONTROL_DEF(&InfoText),
+                            START_ROW(ROW_VALIGN_CENTER),
+                                CONTROL_DEF(&Spacing),
                             START_ROW(ROW_VALIGN_CENTER),
                                 CONTROL_DEF(&Buttons[0]),
                                 CONTROL_DEF(&Buttons[1]),
                                 CONTROL_DEF(&Buttons[2]),
+                },
+            MessageBoxHelp[] =
+                {
+                                CONTROL_DEF(&Buttons[3]),
+                },
+            MessageBoxTail[] =
+                {
                         END_TABLE,
                     END_TABLE
-                 };
+                };
 
     ULONG flButtons = flFlags & 0xF;        // low nibble contains MB_YESNO etc.
+    PDLGARRAY pArrayBox;
 
     PCSZ        p0 = "Error",
@@ -2764,13 +2882,42 @@
         *pulAlarmFlag = WA_WARNING;
 
-    return (dlghCreateDlg(phwndDlg,
-                          hwndOwner,
-                          FCF_TITLEBAR | FCF_SYSMENU | FCF_DLGBORDER | FCF_NOBYTEALIGN,
-                          WinDefDlgProc,
-                          pcszTitle,
-                          MessageBox,
-                          ARRAYITEMCOUNT(MessageBox),
-                          NULL,
-                          pcszFont));
+    if (pfnHelp)
+        Buttons[3].pcszText = pStrings->pcszHelp;
+
+    if (!(arc = dlghCreateArray(   ARRAYITEMCOUNT(MessageBoxFront)
+                                 + ARRAYITEMCOUNT(MessageBoxHelp)
+                                 + ARRAYITEMCOUNT(MessageBoxTail),
+                                &pArrayBox)))
+    {
+        if (    (!(arc = dlghAppendToArray(pArrayBox,
+                                           MessageBoxFront,
+                                           ARRAYITEMCOUNT(MessageBoxFront))))
+             && (    (!pfnHelp)
+                  || (!(arc = dlghAppendToArray(pArrayBox,
+                                                MessageBoxHelp,
+                                                ARRAYITEMCOUNT(MessageBoxHelp))))
+                )
+             && (!(arc = dlghAppendToArray(pArrayBox,
+                                           MessageBoxTail,
+                                           ARRAYITEMCOUNT(MessageBoxTail))))
+           )
+        {
+            if (!(arc = dlghCreateDlg(phwndDlg,
+                                      hwndOwner,
+                                      FCF_TITLEBAR | FCF_SYSMENU | FCF_DLGBORDER | FCF_NOBYTEALIGN,
+                                      fnwpMessageBox,
+                                      pcszTitle,
+                                      pArrayBox->paDlgItems,
+                                      pArrayBox->cDlgItemsNow,
+                                      NULL,
+                                      pcszFont)))
+                // added help callback V0.9.19 (2002-04-24) [umoeller]
+                WinSetWindowPtr(*phwndDlg, QWL_USER, (PVOID)pfnHelp);
+        }
+
+        dlghFreeArray(&pArrayBox);
+    }
+
+    return arc;
 }
 
@@ -2885,15 +3032,21 @@
  *      -- MB_ICONEXCLAMATION
  *
+ *      If (pfnHelp != NULL), a "Help" button is also added and
+ *      pfnHelp gets called when the user presses it or the F1
+ *      key.
+ *
  *      Returns MBID_* codes like WinMessageBox.
  *
  *@@added V0.9.13 (2001-06-21) [umoeller]
+ *@@changed V0.9.19 (2002-04-24) [umoeller]: added pfnHelp
  */
 
 ULONG dlghMessageBox(HWND hwndOwner,            // in: owner for msg box
                      HPOINTER hptrIcon,         // in: icon to display
-                     PCSZ pcszTitle,     // in: title
-                     PCSZ pcszMessage,   // in: message
+                     PCSZ pcszTitle,            // in: title
+                     PCSZ pcszMessage,          // in: message
+                     PFNHELP pfnHelp,           // in: help callback or NULL
                      ULONG flFlags,             // in: standard message box flags
-                     PCSZ pcszFont,      // in: font (e.g. "9.WarpSans")
+                     PCSZ pcszFont,             // in: font (e.g. "9.WarpSans")
                      const MSGBOXSTRINGS *pStrings) // in: strings array
 {
@@ -2905,4 +3058,5 @@
                                       pcszTitle,
                                       pcszMessage,
+                                      pfnHelp,
                                       flFlags,
                                       pcszFont,
@@ -2980,5 +3134,5 @@
                             CTL_COMMON_FONT,
                             0,
-                            { 300, SZL_AUTOSIZE },     // size
+                            { 150, SZL_AUTOSIZE },     // size
                             5               // spacing
                          },
@@ -2990,5 +3144,5 @@
                             CTL_COMMON_FONT,
                             0,
-                            { 300, SZL_AUTOSIZE },     // size
+                            { 150, SZL_AUTOSIZE },     // size
                             5               // spacing
                          },
@@ -3000,5 +3154,5 @@
                             CTL_COMMON_FONT,
                             0,
-                            { 100, 30 },    // size
+                            { STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT },    // size
                             5               // spacing
                          },
@@ -3010,5 +3164,5 @@
                             CTL_COMMON_FONT,
                             0,
-                            { 100, 30 },    // size
+                            { STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT },    // size
                             5               // spacing
                          };
Index: trunk/src/helpers/dosh.c
===================================================================
--- trunk/src/helpers/dosh.c	(revision 158)
+++ trunk/src/helpers/dosh.c	(revision 159)
@@ -1942,6 +1942,7 @@
  *
  *      In the pathological case of a dot in the path
- *      but not in the filename itself, this correctly
- *      returns NULL.
+ *      but not in the filename itself (e.g.
+ *      "C:\files.new\readme"), this correctly returns
+ *      NULL.
  *
  *@@added V0.9.6 (2000-10-16) [umoeller]
@@ -2008,5 +2009,5 @@
     CHAR szName[5];
 
-    APIRET rc              = NO_ERROR; // return code
+    APIRET arc;
     BYTE   fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
     ULONG  cbBuffer   = sizeof(fsqBuffer);        // Buffer length)
@@ -2017,11 +2018,9 @@
     szName[2] = '\0';
 
-    rc = DosQueryFSAttach(szName,          // logical drive of attached FS
-                          0,               // ulOrdinal, ignored for FSAIL_QUERYNAME
-                          FSAIL_QUERYNAME, // return data for a Drive or Device
-                          pfsqBuffer,      // returned data
-                          &cbBuffer);      // returned data length
-
-    if (rc == NO_ERROR)
+    if (!(arc = DosQueryFSAttach(szName,          // logical drive of attached FS
+                                 0,               // ulOrdinal, ignored for FSAIL_QUERYNAME
+                                 FSAIL_QUERYNAME, // return data for a Drive or Device
+                                 pfsqBuffer,      // returned data
+                                 &cbBuffer)))     // returned data length
     {
         // The data for the last three fields in the FSQBUFFER2
@@ -3434,4 +3433,65 @@
 
 /*
+ *@@ doshCanonicalize:
+ *      simplifies path specifications to remove '.'
+ *      and '..' entries and generates a fully
+ *      qualified path name where possible.
+ *      File specifications are left unchanged.
+ *
+ *      This returns:
+ *
+ *      --  NO_ERROR: the buffers were valid.
+ *
+ *      --  ERROR_INVALID_PARAMETER: the buffers
+ *          were invalid.
+ *
+ *@@added V0.9.19 (2002-04-22) [pr]
+ */
+
+APIRET doshCanonicalize(PCSZ pcszFileIn,        // in: path to canonicalize
+                        PSZ pszFileOut,         // out: canonicalized path if NO_ERROR
+                        ULONG cbFileOut)        // in: size of pszFileOut buffer
+{
+    APIRET ulrc = NO_ERROR;
+    CHAR szFileTemp[CCHMAXPATH];
+
+    if (pcszFileIn && pszFileOut && cbFileOut)
+    {
+        strncpy(szFileTemp, pcszFileIn, sizeof(szFileTemp) - 1);
+        szFileTemp[sizeof(szFileTemp) - 1] = 0;
+        if (    strchr(szFileTemp, '\\')
+             || strchr(szFileTemp, ':')
+           )
+        {
+            ULONG cbFileTemp = strlen(szFileTemp);
+
+            if (    (cbFileTemp > 3)
+                 && (szFileTemp[cbFileTemp - 1] == '\\')
+               )
+            {
+                szFileTemp[cbFileTemp - 1] = 0;
+            }
+
+            if (DosQueryPathInfo(szFileTemp,
+                                 FIL_QUERYFULLNAME,
+                                 pszFileOut,
+                                 cbFileOut))
+            {
+                pszFileOut[0] = 0;
+            }
+        }
+        else
+        {
+            strncpy(pszFileOut, pcszFileIn, cbFileOut - 1);
+            pszFileOut[cbFileOut - 1] = 0;
+        }
+    }
+    else
+        ulrc = ERROR_INVALID_PARAMETER;
+
+    return(ulrc);
+}
+
+/*
  *@@category: Helpers\Control program helpers\Module handling
  *      helpers for importing functions from a module (DLL).
Index: trunk/src/helpers/makefile
===================================================================
--- trunk/src/helpers/makefile	(revision 158)
+++ trunk/src/helpers/makefile	(revision 159)
@@ -145,5 +145,5 @@
 TESTCASE_DIR = testcase
 
-TESTCASE_CC = icc /c /ti+ /w2 /ss /se /i$(HELPERS_BASE)\include /DDEBUG_DIALOG_WINDOWS /Fo$(TESTCASE_DIR)\$(@B).obj $(@B).c
+TESTCASE_CC = icc /c /ti+ /w2 /ss /se /i$(HELPERS_BASE)\include /Fo$(TESTCASE_DIR)\$(@B).obj $(@B).c
 
 .c.{$(TESTCASE_DIR)}.obj:
@@ -165,4 +165,7 @@
 dosh.exe: $(DOSH_TEST_OBJS)
     ilink /debug /optfunc /pmtype:vio $(DOSH_TEST_OBJS) /o:$@
+
+$(TESTCASE_DIR)\dialog.obj: ..\..\include\helpers\dialog.h
+$(TESTCASE_DIR)\_test_dialog.obj: ..\..\include\helpers\dialog.h
 
 # dialog.exe
@@ -173,7 +176,11 @@
     $(TESTCASE_DIR)\xstring.obj \
     $(TESTCASE_DIR)\linklist.obj \
+    $(TESTCASE_DIR)\cctl_checkcnr.obj \
+    $(TESTCASE_DIR)\cnrh.obj \
     $(TESTCASE_DIR)\comctl.obj \
     $(TESTCASE_DIR)\stringh.obj \
     $(TESTCASE_DIR)\dosh.obj \
+    $(TESTCASE_DIR)\except.obj \
+    $(TESTCASE_DIR)\debug.obj \
     $(TESTCASE_DIR)\gpih.obj
 
Index: trunk/src/helpers/stringh.c
===================================================================
--- trunk/src/helpers/stringh.c	(revision 158)
+++ trunk/src/helpers/stringh.c	(revision 159)
@@ -1063,6 +1063,6 @@
 
     while(*p)
-        if (   (*p == '\r')
-            || (*p == '\n')
+        if (    (*p == '\r')
+             || (*p == '\n')
            )
         {
Index: trunk/src/helpers/winh.c
===================================================================
--- trunk/src/helpers/winh.c	(revision 158)
+++ trunk/src/helpers/winh.c	(revision 159)
@@ -4031,9 +4031,9 @@
  *      controls which should be moved such an ID.
  *
- *      You can also specify how many dialog units
- *      all the other controls will be moved downward in
- *      ulDownUnits; this is useful to fill up the space
- *      which was used by the buttons before moving them.
- *      Returns TRUE if anything was changed.
+ *      Note that this function will now automatically
+ *      find out the lowest y coordinate that was used
+ *      for a non-notebook button and move all controls
+ *      down accordingly. As a result, ulDownUnit must
+ *      no longer be specified (V0.9.19).
  *
  *      This function is useful if you wish to create
@@ -4044,9 +4044,9 @@
  *
  *@@changed V0.9.16 (2002-02-02) [umoeller]: fixed entry fields
+ *@@changed V0.9.19 (2002-04-24) [umoeller]: removed ulDownUnits
  */
 
 BOOL winhAssertWarp4Notebook(HWND hwndDlg,
-                             USHORT usIdThreshold,    // in: ID threshold
-                             ULONG ulDownUnits)       // in: dialog units or 0
+                             USHORT usIdThreshold)  // in: ID threshold
 {
     BOOL brc = FALSE;
@@ -4054,42 +4054,46 @@
     if (doshIsWarp4())
     {
-        POINTL ptl;
-        HWND hwndItem;
-        HENUM henum = 0;
-
-        BOOL    fIsVisible = WinIsWindowVisible(hwndDlg);
-        if (ulDownUnits)
+        LONG    yLowest = 10000;
+        HWND    hwndItem;
+        HENUM   henum = 0;
+        PSWP    paswp,
+                pswpThis;
+        ULONG   cWindows = 0,
+                ul;
+
+        BOOL    fIsVisible;
+
+        if (fIsVisible = WinIsWindowVisible(hwndDlg))
+            // avoid flicker
+            WinEnableWindowUpdate(hwndDlg, FALSE);
+
+        if (paswp = (PSWP)malloc(sizeof(SWP) * 100))
         {
-            ptl.x = 0;
-            ptl.y = ulDownUnits;
-            WinMapDlgPoints(hwndDlg, &ptl, 1, TRUE);
-        }
-
-        if (fIsVisible)
-            WinEnableWindowUpdate(hwndDlg, FALSE);
-
-        henum = WinBeginEnumWindows(hwndDlg);
-        while ((hwndItem = WinGetNextWindow(henum)))
-        {
-            USHORT usId = WinQueryWindowUShort(hwndItem, QWS_ID);
-            // _Pmpf(("hwndItem: 0x%lX, ID: 0x%lX", hwndItem, usId));
-            if (usId <= usIdThreshold)
+            pswpThis = paswp;
+
+            // loop 1: set notebook buttons, find lowest y used
+            henum = WinBeginEnumWindows(hwndDlg);
+            while ((hwndItem = WinGetNextWindow(henum)))
             {
-                // pushbutton to change:
-                // _Pmpf(("  Setting bit"));
-                WinSetWindowBits(hwndItem,
-                                 QWL_STYLE,
-                                 BS_NOTEBOOKBUTTON, BS_NOTEBOOKBUTTON);
-                brc = TRUE;
-            }
-            else
-                // no pushbutton to change: move downwards
-                // if desired
-                if (ulDownUnits)
+                USHORT usId = WinQueryWindowUShort(hwndItem, QWS_ID);
+                // _Pmpf(("hwndItem: 0x%lX, ID: 0x%lX", hwndItem, usId));
+                if (usId <= usIdThreshold)
                 {
+                    // pushbutton to change:
+                    WinSetWindowBits(hwndItem,
+                                     QWL_STYLE,
+                                     BS_NOTEBOOKBUTTON, BS_NOTEBOOKBUTTON);
+                    brc = TRUE;
+                }
+                else
+                {
+                    // no pushbutton to change:
                     CHAR szClass[10];
-                    SWP swp;
-                    LONG lDeltaX = 0,
-                         lDeltaY = 0;
+
+                    // check lowest y
+                    WinQueryWindowPos(hwndItem, pswpThis);
+                    if (pswpThis->y < yLowest)
+                        yLowest = pswpThis->y ;
+
                     // special handling for entry fields
                     // V0.9.16 (2002-02-02) [umoeller]
@@ -4097,17 +4101,33 @@
                     if (!strcmp(szClass, "#6"))
                     {
-                        lDeltaX = 3 * WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
-                        lDeltaY = 3 * WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);
+                        pswpThis->x += 3 * WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
+                        pswpThis->y += 3 * WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);
                     }
 
-                    WinQueryWindowPos(hwndItem, &swp);
-                    WinSetWindowPos(hwndItem, 0,
-                                    swp.x + lDeltaX,
-                                    swp.y - ptl.y + lDeltaY,
-                                    0, 0,
-                                    SWP_MOVE);
+                    ++pswpThis;
+                    if (++cWindows == 100)
+                        break;
                 }
+            } // end while ((hwndItem = WinGetNextWindow(henum)))
+            WinEndEnumWindows(henum);
+
+            // now adjust window positions
+            pswpThis = paswp;
+            for (ul = 0;
+                 ul < cWindows;
+                 ++ul, ++pswpThis)
+            {
+                pswpThis->y -= (yLowest - 8);
+                            // 8 is magic to match the lower border of the
+                            // standard WPS notebook pages V0.9.19 (2002-04-24) [umoeller]
+                pswpThis->fl = SWP_MOVE;
+            }
+
+            WinSetMultWindowPos(WinQueryAnchorBlock(hwndDlg),
+                                paswp,
+                                cWindows);
+
+            free(paswp);
         }
-        WinEndEnumWindows(henum);
 
         if (fIsVisible)
