home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: WPS_PM / WPS_PM.zip / xfld085s.zip / main / common.c < prev    next >
C/C++ Source or Header  |  1999-03-15  |  90KB  |  2,211 lines

  1.  
  2. /*
  3.  *@@sourcefile common.c:
  4.  *      common.c contains functions that are common to all
  5.  *      parts of XFolder. As opposed to /helpers/*, these
  6.  *      functions work with XFolder only, while the helper
  7.  *      functions will work with any PM application.
  8.  *
  9.  *      These functions mainly deal with the following features:
  10.  *      -- global settings;
  11.  *      -- NLS management;
  12.  *      -- folder hotkeys;
  13.  *      -- subclassing folder frame windows. The actual
  14.  *         window proc for that is fnwpSubclassedFolderFrame
  15.  *         in xfldr.c though;
  16.  *      -- extended XFolder message boxes (cmnMessageBox);
  17.  *      -- querying system sounds (cmnQuerySystemSound).
  18.  *
  19.  *@@include #define INCL_WINWINDOWMGR
  20.  *@@include #define INCL_DOSMODULEMGR
  21.  *@@include #include <os2.h>
  22.  *@@include #include "xfldr.h"  // only for some functions
  23.  *@@include #include "common.h"
  24.  */
  25.  
  26. /*
  27.  *      Copyright (C) 1997-99 Ulrich Möller.
  28.  *      This file is part of the XFolder source package.
  29.  *      XFolder is free software; you can redistribute it and/or modify
  30.  *      it under the terms of the GNU General Public License as published
  31.  *      by the Free Software Foundation, in version 2 as it comes in the
  32.  *      "COPYING" file of the XFolder main distribution.
  33.  *      This program is distributed in the hope that it will be useful,
  34.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  35.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  36.  *      GNU General Public License for more details.
  37.  */
  38.  
  39. /*
  40.  *  Suggested #include order:
  41.  *  1)  os2.h
  42.  *  2)  C library headers
  43.  *  3)  SOM headers which work with precompiled header files
  44.  *  4)  headers in /helpers
  45.  *  5)  headers in /main with dlgids.h and common.h first
  46.  *  6)  #pragma hdrstop to prevent VAC++ crashes
  47.  *  7)  other needed SOM headers
  48.  *  8)  for non-SOM-class files: corresponding header (e.g. classlst.h)
  49.  */
  50.  
  51. #define INCL_DOSMODULEMGR
  52. #define INCL_DOSEXCEPTIONS      // needed for except.h
  53. #define INCL_DOSSEMAPHORES      // needed for xthreads.h
  54. #define INCL_DOSMISC            // DosGetMessage etc.
  55. #define INCL_DOSERRORS
  56.  
  57. #define INCL_WINWINDOWMGR
  58. #define INCL_WINSHELLDATA       // profile funcs
  59. #define INCL_WINSYS             // presparams, WinQuerySysValue()
  60. #define INCL_WININPUT           // WM_BUTTON1DOWN etc.
  61.  
  62. #define INCL_WINDIALOGS
  63. #define INCL_WINBUTTONS
  64. #define INCL_WINSTDCNR          // needed for winh.h
  65. #define INCL_WINLISTBOXES
  66.  
  67. #define INCL_GPILOGCOLORTABLE
  68.  
  69. #include <os2.h>
  70.  
  71. // C library headers
  72. #include <stdio.h>
  73. #include <stdlib.h>
  74. #include <string.h>             // mem*, str* functions
  75. #include <setjmp.h>             // needed for except.h
  76. #include <assert.h>             // needed for except.h
  77. #include <io.h>
  78.  
  79. // headers in /helpers
  80. #include "dosh.h"               // Control Program helper routines
  81. #include "winh.h"               // PM helper routines
  82.  
  83. #include "linklist.h"           // linked list helper routines
  84. #include "undoc.h"              // some undocumented stuff
  85.  
  86. // SOM headers which don't crash with prec. header files
  87. #pragma hdrstop                 // VAC++ keeps crashing otherwise
  88. #include "xfldr.h"
  89.  
  90. // headers in /main
  91. #include "dlgids.h"             // all the IDs that are shared with NLS
  92. #include "common.h"             // the majestic XFolder include file
  93.  
  94. #include "module.h"             // XFolder main DLL information
  95. #include "sound.h"              // declarations for SOUND.DLL
  96. #include "except.h"             // XFolder exception handling
  97. #include "statbars.h"           // status bar translation logic
  98. #include "xshutdwn.h"           // needed for default settings
  99. #include "xwps.h"               // XFolder pseudo SOM functions
  100.  
  101. // other SOM headers
  102. #include  <wpdesk.h>            // WPDesktop
  103.  
  104.  
  105. CHAR            szHelpLibrary[CCHMAXPATH] = "";
  106. CHAR            szMessageFile[CCHMAXPATH] = "";
  107.  
  108. HMODULE         hmodNLS = NULLHANDLE;
  109. PVOID           pNLSStringsGlobal = NULL;
  110. PGLOBALSETTINGS pGlobalSettings = NULL;
  111.  
  112. HMODULE         hmodIconsDLL = NULLHANDLE;
  113. CHAR            szLanguageCode[20] = "";
  114.  
  115. ULONG           ulCurHelpPanel = 0;      // holds help panel for dialog
  116.  
  117. CHAR            szStatusBarFont[100];
  118. CHAR            szSBTextNoneSel[CCHMAXMNEMONICS],
  119.                 szSBTextMultiSel[CCHMAXMNEMONICS];
  120. ULONG           ulStatusBarHeight;
  121.  
  122. /*-------------------------------------------------------------------
  123.  *                                                                  *
  124.  *   XFolder debugging helpers                                      *
  125.  *                                                                  *
  126.  ********************************************************************/
  127.  
  128. #ifdef _PMPRINTF_
  129.  
  130. /*
  131.  *@@ cmnDumpMemoryBlock:
  132.  *      if _PMPRINTF_ has been #define'd in common.h,
  133.  *      this will dump a block of memory to the PMPRINTF
  134.  *      output window. Useful for debugging internal
  135.  *      structures.
  136.  *      If _PMPRINTF_ has been NOT #define'd in common.h,
  137.  *      no code will be produced. :-)
  138.  */
  139.  
  140. void cmnDumpMemoryBlock(PBYTE pb,       // in: start address
  141.                         ULONG ulSize,   // in: size of block
  142.                         ULONG ulIndent) // in: how many spaces to put
  143.                                         //     before each output line
  144. {
  145.     PBYTE   pbCurrent = pb;
  146.     ULONG   ulCount = 0,
  147.             ulLineCount = 0;
  148.     CHAR    szLine[400] = "",
  149.             szAscii[30] = "         ";
  150.     PSZ     pszLine = szLine,
  151.             pszAscii = szAscii;
  152.  
  153.     for (pbCurrent = pb;
  154.          ulCount < ulSize;
  155.          pbCurrent++, ulCount++)
  156.     {
  157.         if (ulLineCount == 0) {
  158.             memset(szLine, ' ', ulIndent);
  159.             pszLine += ulIndent;
  160.         }
  161.         pszLine += sprintf(pszLine, "%02lX ", *pbCurrent);
  162.  
  163.         if ((*pbCurrent > 31) && (*pbCurrent < 127))
  164.             *pszAscii = *pbCurrent;
  165.         else
  166.             *pszAscii = '.';
  167.         pszAscii++;
  168.  
  169.         ulLineCount++;
  170.         if ( (ulLineCount > 7) || (ulCount == ulSize-1) )
  171.         {
  172.             _Pmpf(("%04lX:  %s  %s",
  173.                     ulCount-7,
  174.                     szLine,
  175.                     szAscii));
  176.             pszLine = szLine;
  177.             pszAscii = szAscii;
  178.             ulLineCount = 0;
  179.         }
  180.     }
  181. }
  182. #else
  183.     // _PMPRINTF not #define'd: do nothing
  184.     #define cmnDumpMemoryBlock(pb, ulSize, ulIndent)
  185. #endif
  186.  
  187. /*-------------------------------------------------------------------
  188.  *                                                                  *
  189.  *   XFolder module handling                                        *
  190.  *                                                                  *
  191.  ********************************************************************/
  192.  
  193. /*
  194.  *  The following routines are for querying the XFolder
  195.  *  installation path and similiar routines, such as
  196.  *  querying the current NLS module, changing it, loading
  197.  *  strings, the help file and all that sort of stuff.
  198.  */
  199.  
  200.  
  201. /*
  202.  *@@ cmnQueryXFolderBasePath:
  203.  *      this routine returns the path of where XFolder was installed,
  204.  *      i.e. the parent directory of where the xfldr.dll file
  205.  *      resides, without a trailing backslash (e.g. "C:\XFolder").
  206.  *      The buffer to copy this to is assumed to be CCHMAXPATH in size.
  207.  *      As opposed to versions before V0.81, OS2.INI is no longer
  208.  *      needed for this to work. The path is retrieved from the
  209.  *      DLL directly by evaluating what was passed to _DLL_InitModule
  210.  *      (module.*).
  211.  */
  212.  
  213. BOOL cmnQueryXFolderBasePath(PSZ pszPath)
  214. {
  215.     BOOL brc = FALSE;
  216.     PSZ pszDLL = modQueryFile();
  217.     if (pszDLL) {
  218.         // copy until last backslash minus four characters
  219.         // (leave out "\bin\xfldr.dll")
  220.         PSZ pszLastSlash = strrchr(pszDLL, '\\');
  221.         #ifdef DEBUG_LANGCODES
  222.             _Pmpf(( "modQueryFile: %s", pszDLL));
  223.         #endif
  224.         strncpy(pszPath, pszDLL, (pszLastSlash-pszDLL)-4);
  225.         pszPath[(pszLastSlash-pszDLL-4)] = '\0';
  226.         brc = TRUE;
  227.     }
  228.     #ifdef DEBUG_LANGCODES
  229.         _Pmpf(( "cmnQueryXFolderBasePath: %s", pszPath ));
  230.     #endif
  231.     return (brc);
  232. }
  233.  
  234. /*
  235.  *@@ cmnQueryLanguageCode:
  236.  *      returns PSZ to three-digit language code (e.g. "001").
  237.  */
  238.  
  239. PSZ cmnQueryLanguageCode(VOID)
  240. {
  241.     if (szLanguageCode[0] == '\0')
  242.         PrfQueryProfileString(HINI_USERPROFILE,
  243.                INIAPP_XFOLDER, INIKEY_LANGUAGECODE,
  244.                DEFAULT_LANGUAGECODE,
  245.                (PVOID)szLanguageCode,
  246.                sizeof(szLanguageCode));
  247.  
  248.     szLanguageCode[3] = '\0';
  249.     #ifdef DEBUG_LANGCODES
  250.         _Pmpf(( "cmnQueryLanguageCode: %s", szLanguageCode ));
  251.     #endif
  252.     return (szLanguageCode);
  253. }
  254.  
  255. /*
  256.  *@@ cmnSetLanguageCode:
  257.  *      changes XFolder's language to three-digit language code in
  258.  *      pszLanguage (e.g. "001"). This does not reload the NLS DLL,
  259.  *      but only change the setting.
  260.  */
  261.  
  262. BOOL cmnSetLanguageCode(PSZ pszLanguage)
  263. {
  264.     strcpy(szLanguageCode, pszLanguage);
  265.  
  266.     return (PrfWriteProfileString(HINI_USERPROFILE, INIAPP_XFOLDER, INIKEY_LANGUAGECODE,
  267.         szLanguageCode));
  268. }
  269.  
  270. /*
  271.  *@@ cmnQueryHelpLibrary:
  272.  *      returns PSZ to full help library path in XFolder directory,
  273.  *      depending on where XFolder was installed and on the current
  274.  *      language (e.g. "C:\XFolder\help\xfldr001.hlp").
  275.  */
  276.  
  277. PSZ cmnQueryHelpLibrary(VOID)
  278. {
  279.     if (cmnQueryXFolderBasePath(szHelpLibrary)) {
  280.         // path found: append helpfile
  281.         sprintf(szHelpLibrary+strlen(szHelpLibrary),
  282.                 "\\help\\xfldr%s.hlp",
  283.                 cmnQueryLanguageCode());
  284.         #ifdef DEBUG_LANGCODES
  285.             _Pmpf(( "cmnQueryHelpLibrary: %s", szHelpLibrary ));
  286.         #endif
  287.         return (szHelpLibrary);
  288.     } else
  289.         return (NULL);
  290. }
  291.  
  292. /*
  293.  *@@ cmnQueryMessageFile:
  294.  *      returns PSZ to full message file path in XFolder directory,
  295.  *      depending on where XFolder was installed and on the current
  296.  *      language (e.g. "C:\XFolder\help\xfldr001.msg").
  297.  */
  298.  
  299. PSZ cmnQueryMessageFile(VOID)
  300. {
  301.     if (cmnQueryXFolderBasePath(szMessageFile)) {
  302.         // path found: append message file
  303.         sprintf(szMessageFile+strlen(szMessageFile),
  304.                 "\\help\\xfldr%s.msg",
  305.                 cmnQueryLanguageCode());
  306.         #ifdef DEBUG_LANGCODES
  307.             _Pmpf(( "cmnQueryMessageFile: %s", szMessageFile));
  308.         #endif
  309.         return (szMessageFile);
  310.     } else
  311.         return (NULL);
  312. }
  313.  
  314. /*
  315.  *@@ cmnQueryIconsDLL:
  316.  *      this returns the HMODULE of XFolder ICONS.DLL
  317.  *      (new with V0.84).
  318.  *      If this is queried for the first time, the DLL
  319.  *      is loaded from the /BIN directory.
  320.  *      In this case, this routine also checks if
  321.  *      ICONS.DLL exists in the /ICONS directory. If
  322.  *      so, it is copied to /BIN before loading the
  323.  *      DLL. This allows for replacing the DLL using
  324.  *      the REXX script in /ICONS.
  325.  *
  326.  *      New with V0.84.
  327.  */
  328.  
  329. HMODULE cmnQueryIconsDLL(VOID)
  330. {
  331.     // first query?
  332.     if (hmodIconsDLL == NULLHANDLE)
  333.     {
  334.         CHAR    szIconsDLL[CCHMAXPATH],
  335.                 szIconsDLL2[CCHMAXPATH];
  336.         cmnQueryXFolderBasePath(szIconsDLL);
  337.         strcpy(szIconsDLL2, szIconsDLL);
  338.  
  339.         sprintf(szIconsDLL+strlen(szIconsDLL),
  340.                 "\\bin\\icons.dll");
  341.         sprintf(szIconsDLL2+strlen(szIconsDLL2),
  342.                 "\\icons\\icons.dll");
  343.  
  344.         // first check for /ICONS/ICONS.DLL
  345.         if (access(szIconsDLL2, 0) == 0)
  346.         {
  347.             // exists: then move to /BIN
  348.             DosDelete(szIconsDLL);
  349.             DosMove(szIconsDLL2, szIconsDLL);
  350.         }
  351.  
  352.         // now load /BIN/ICONS.DLL
  353.         if (DosLoadModule(NULL,
  354.                            0,
  355.                            szIconsDLL,
  356.                            &hmodIconsDLL))
  357.             hmodIconsDLL = NULLHANDLE;
  358.     }
  359.     return (hmodIconsDLL);
  360. }
  361.  
  362. /*
  363.  *@@ cmnLoadString:
  364.  *      pretty similar to WinLoadString, but allocates
  365.  *      necessary memory as well. *ppsz is a pointer
  366.  *      to a PSZ; if this PSZ is != NULL, whatever it
  367.  *      points to will be free()d, so you should set this
  368.  *      to NULL if you initially call this function.
  369.  *      This is used at WPS startup and when XFolder's
  370.  *      language is changed later to load all the strings
  371.  *      from a NLS DLL.
  372.  */
  373.  
  374. void cmnLoadString(HAB habDesktop, HMODULE hmodResource, ULONG ulID, PSZ *ppsz)
  375. {
  376.     CHAR    szBuf[200];
  377.     if (*ppsz)
  378.         free(*ppsz);
  379.     if (WinLoadString(habDesktop, hmodResource, ulID , sizeof(szBuf), szBuf))
  380.         *ppsz = strcpy(malloc(strlen(szBuf)+1), szBuf);
  381.     else
  382.         *ppsz = "Error: String resource not found";
  383. }
  384.  
  385. /*
  386.  *@@ cmnQueryNLSModuleHandle:
  387.  *      returns the module handle of the language-dependent XFolder
  388.  *      national language support DLL.
  389.  *
  390.  *      This is called in two situations:
  391.  *          1) with fEnforceReload == FALSE everytime some part
  392.  *             of XFolder needs the NLS resources (e.g. for dialogs);
  393.  *             on the first call, the NLS DLL is loaded into memory.
  394.  *          2) with fEnforceReload == TRUE when the user changes
  395.  *             XFolder's language in the "Workplace Shell" object.
  396.  *
  397.  *      If the DLL is (re)loaded, this function also initializes
  398.  *      all language-dependent XFolder parts such as the NLSSTRINGS
  399.  *      structure, which can always be accessed using cmnQueryNLSStrings.
  400.  *      This function also checks for whether the NLS DLL has a
  401.  *      decent version level to support this XFolder version.
  402.  */
  403.  
  404. HMODULE cmnQueryNLSModuleHandle(BOOL fEnforceReload)
  405. {
  406.     CHAR    szResourceModuleName[CCHMAXPATH];
  407.     ULONG   ulCopied;
  408.     HMODULE hmodOldResource = hmodNLS;
  409.  
  410.     // load resource DLL if it's not loaded yet or a reload is enforced
  411.     if ((hmodNLS == NULLHANDLE) || (fEnforceReload))
  412.     {
  413.         PNLSSTRINGS pNLSStrings = cmnQueryNLSStrings();
  414.  
  415.         // get the XFolder path first
  416.         if (cmnQueryXFolderBasePath(szResourceModuleName))
  417.         {
  418.             // now compose module name from language code
  419.             strcat(szResourceModuleName, "\\bin\\xfldr");
  420.             strcat(szResourceModuleName, cmnQueryLanguageCode());
  421.             strcat(szResourceModuleName, ".dll");
  422.  
  423.             // try to load the module
  424.             if (DosLoadModule(NULL,
  425.                                0,
  426.                                szResourceModuleName,
  427.                                &hmodNLS))
  428.             {
  429.                 DebugBox("XFolder: Couldn't Find Resource DLL",
  430.                     szResourceModuleName);
  431.             } else {
  432.                 // module loaded alright!
  433.                 HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
  434.  
  435.                 if (habDesktop)
  436.                 {
  437.                     if (fEnforceReload) {
  438.                         // if fEnforceReload == TRUE, we will load a test string from
  439.                         // the module to see if it has at least the version level which
  440.                         // this XFolder version requires. This is done using a #define
  441.                         // in dlgids.h: XFOLDER_VERSION is compiled into both the NLS
  442.                         // DLL (as a string resource) and into the main DLL (this file),
  443.                         // so we always have the versions in there automatically.
  444.                         // MINIMUM_NLS_VERSION (dlgids.h too) contains the minimum
  445.                         // NLS version level that this XFolder version requires.
  446.                         CHAR   szTest[30] = "";
  447.                         LONG   lLength;
  448.                         lLength = WinLoadString(habDesktop,
  449.                                 hmodNLS,
  450.                                 ID_XSSI_XFOLDERVERSION,
  451.                                 sizeof(szTest), szTest);
  452.                         #ifdef DEBUG_LANGCODES
  453.                             _Pmpf(("%s version: %s", szResourceModuleName, szTest));
  454.                         #endif
  455.  
  456.                         if (    (lLength == 0)
  457.                             ||  (memcmp(szTest, MINIMUM_NLS_VERSION, 4) < 0)
  458.                                     // szTest has NLS version (e.g. "0.81 beta"),
  459.                                     // MINIMUM_NLS_VERSION has minimum version required
  460.                                     // (e.g. "0.90")
  461.                            )
  462.                         {
  463.                             DosBeep(1500, 100);
  464.                             cmnSetHelpPanel(-1);
  465.                             if (lLength == 0) {
  466.                                 // version string not found: complain
  467.                                 DebugBox("XFolder", "The requested file is not an XFolder National Language Support DLL.");
  468.                                 DosFreeModule(hmodNLS);
  469.                                 hmodNLS = hmodOldResource;
  470.                                 return NULLHANDLE;
  471.                             }
  472.                             else
  473.                             {
  474.                                 // version level not sufficient:
  475.                                 // load dialog from previous NLS DLL which says
  476.                                 // that the DLL is too old; if user presses
  477.                                 // "Cancel", we abort loading the DLL
  478.                                 DosBeep(1700, 100);
  479.                                 if (WinDlgBox(HWND_DESKTOP,
  480.                                          HWND_DESKTOP,
  481.                                          (PFNWP)fnwpDlgGeneric,
  482.                                          hmodOldResource,
  483.                                          ID_XFD_WRONGVERSION,
  484.                                          (PVOID)NULL)
  485.                                    == DID_CANCEL)
  486.                                 {
  487.                                     DebugBox("XFolder", "The new National Language Support DLL was not loaded.");
  488.                                     // unload new NLS DLL
  489.                                     DosFreeModule(hmodNLS);
  490.                                     hmodNLS = hmodOldResource;
  491.                                     return NULLHANDLE;
  492.                                 }
  493.                             }
  494.                         }
  495.                     }
  496.  
  497.                     // now let's load strings
  498.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_NOTDEFINED, &(pNLSStrings->pszNotDefined));
  499.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_PRODUCTINFO, &(pNLSStrings->pszProductInfo));
  500.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_REFRESHNOW, &(pNLSStrings->pszRefreshNow));
  501.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SNAPTOGRID, &(pNLSStrings->pszSnapToGrid));
  502.  
  503.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_FLDRCONTENT, &(pNLSStrings->pszFldrContent));
  504.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_COPYFILENAME, &(pNLSStrings->pszCopyFilename));
  505.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_BORED       , &(pNLSStrings->pszBored));
  506.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_FLDREMPTY   , &(pNLSStrings->pszFldrEmpty));
  507.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SELECTSOME  , &(pNLSStrings->pszSelectSome));
  508.  
  509.                     cmnLoadString(habDesktop, hmodNLS, ID_XFSI_QUICKSTATUS    , &(pNLSStrings->pszQuickStatus));
  510.  
  511.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SV_NAME     , &(pNLSStrings->pszSortByName));
  512.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SV_TYPE     , &(pNLSStrings->pszSortByType));
  513.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SV_CLASS    , &(pNLSStrings->pszSortByClass));
  514.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SV_REALNAME , &(pNLSStrings->pszSortByRealName));
  515.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SV_SIZE     , &(pNLSStrings->pszSortBySize));
  516.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SV_WRITEDATE, &(pNLSStrings->pszSortByWriteDate));
  517.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SV_ACCESSDATE, &(pNLSStrings->pszSortByAccessDate));
  518.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SV_CREATIONDATE, &(pNLSStrings->pszSortByCreationDate));
  519.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SV_EXT       , &(pNLSStrings->pszSortByExt));
  520.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SV_FOLDERSFIRST, &(pNLSStrings->pszSortFoldersFirst));
  521.  
  522.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_CTRL       , &(pNLSStrings->pszCtrl));
  523.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_Alt        , &(pNLSStrings->pszAlt));
  524.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_SHIFT      , &(pNLSStrings->pszShift));
  525.  
  526.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_BACKSPACE  , &(pNLSStrings->pszBackspace));
  527.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_TAB        , &(pNLSStrings->pszTab));
  528.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_BACKTABTAB , &(pNLSStrings->pszBacktab));
  529.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_ENTER      , &(pNLSStrings->pszEnter));
  530.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_ESC        , &(pNLSStrings->pszEsc));
  531.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_SPACE      , &(pNLSStrings->pszSpace));
  532.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_PAGEUP     , &(pNLSStrings->pszPageup));
  533.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_PAGEDOWN   , &(pNLSStrings->pszPagedown));
  534.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_END        , &(pNLSStrings->pszEnd));
  535.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_HOME       , &(pNLSStrings->pszHome));
  536.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_LEFT       , &(pNLSStrings->pszLeft));
  537.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_UP         , &(pNLSStrings->pszUp));
  538.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_RIGHT      , &(pNLSStrings->pszRight));
  539.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_DOWN       , &(pNLSStrings->pszDown));
  540.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_PRINTSCRN  , &(pNLSStrings->pszPrintscrn));
  541.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_INSERT     , &(pNLSStrings->pszInsert));
  542.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_DELETE     , &(pNLSStrings->pszDelete));
  543.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_SCRLLOCK   , &(pNLSStrings->pszScrlLock));
  544.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_NUMLOCK    , &(pNLSStrings->pszNumLock));
  545.  
  546.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_WINLEFT    , &(pNLSStrings->pszWinLeft));
  547.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_WINRIGHT   , &(pNLSStrings->pszWinRight));
  548.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_KEY_WINMENU    , &(pNLSStrings->pszWinMenu));
  549.  
  550.                     cmnLoadString(habDesktop, hmodNLS, ID_SDSI_FLUSHING       , &(pNLSStrings->pszSDFlushing));
  551.                     cmnLoadString(habDesktop, hmodNLS, ID_SDSI_CAD            , &(pNLSStrings->pszSDCAD));
  552.                     cmnLoadString(habDesktop, hmodNLS, ID_SDSI_REBOOTING      , &(pNLSStrings->pszSDRebooting));
  553.                     cmnLoadString(habDesktop, hmodNLS, ID_SDSI_CLOSING        , &(pNLSStrings->pszSDClosing));
  554.                     cmnLoadString(habDesktop, hmodNLS, ID_SDSI_SHUTDOWN       , &(pNLSStrings->pszShutdown));
  555.                     cmnLoadString(habDesktop, hmodNLS, ID_SDSI_RESTARTWPS     , &(pNLSStrings->pszRestartWPS));
  556.                     cmnLoadString(habDesktop, hmodNLS, ID_SDSI_RESTARTINGWPS  , &(pNLSStrings->pszSDRestartingWPS));
  557.                     cmnLoadString(habDesktop, hmodNLS, ID_SDSI_SAVINGDESKTOP  , &(pNLSStrings->pszSDSavingDesktop));
  558.                     cmnLoadString(habDesktop, hmodNLS, ID_SDSI_SAVINGPROFILES , &(pNLSStrings->pszSDSavingProfiles));
  559.  
  560.                     cmnLoadString(habDesktop, hmodNLS, ID_SDSI_STARTING       , &(pNLSStrings->pszStarting));
  561.  
  562.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_POPULATING     , &(pNLSStrings->pszPopulating));
  563.  
  564.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_1GENERIC       , &(pNLSStrings->psz1Generic));
  565.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_2REMOVEITEMS   , &(pNLSStrings->psz2RemoveItems));
  566.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_25ADDITEMS     , &(pNLSStrings->psz25AddItems));
  567.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_26CONFIGITEMS  , &(pNLSStrings->psz26ConfigFolderMenus));
  568.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_27STATUSBAR    , &(pNLSStrings->psz27StatusBar));
  569.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_3SNAPTOGRID    , &(pNLSStrings->psz3SnapToGrid));
  570.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_4ACCELERATORS  , &(pNLSStrings->psz4Accelerators));
  571.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_5INTERNALS     , &(pNLSStrings->psz5Internals));
  572.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_FILEOPS        , &(pNLSStrings->pszFileOps));
  573.  
  574.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SORT           , &(pNLSStrings->pszSort));
  575.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SV_ALWAYSSORT  , &(pNLSStrings->pszAlwaysSort));
  576.  
  577.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_INTERNALS      , &(pNLSStrings->pszInternals));
  578.  
  579.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SB_CLASSMNEMONICS   , &(pNLSStrings->pszSBClassMnemonics));
  580.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SB_CLASSNOTSUPPORTED, &(pNLSStrings->pszSBClassNotSupported));
  581.  
  582.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_WPSCLASSES     , &(pNLSStrings->pszWpsClasses));
  583.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_WPSCLASSLOADED , &(pNLSStrings->pszWpsClassLoaded));
  584.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_WPSCLASSLOADINGFAILED, &(pNLSStrings->pszWpsClassLoadingFailed));
  585.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_WPSCLASSREPLACEDBY, &(pNLSStrings->pszWpsClassReplacedBy));
  586.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_WPSCLASSORPHANS   , &(pNLSStrings->pszWpsClassOrphans));
  587.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_WPSCLASSORPHANSINFO, &(pNLSStrings->pszWpsClassOrphansInfo));
  588.  
  589.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_SCHEDULER      , &(pNLSStrings->pszScheduler));
  590.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_MEMORY         , &(pNLSStrings->pszMemory));
  591.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_ERRORS         , &(pNLSStrings->pszErrors));
  592.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_WPS            , &(pNLSStrings->pszWPS));
  593.  
  594.                     cmnLoadString(habDesktop, hmodNLS, ID_XSSI_PROCESSCONTENT , &(pNLSStrings->pszProcessContent));
  595.  
  596.                     cmnLoadString(habDesktop, hmodNLS, ID_XFSI_SETTINGS       , &(pNLSStrings->pszSettings));
  597.                     cmnLoadString(habDesktop, hmodNLS, ID_XFSI_SETTINGSNOTEBOOK,&(pNLSStrings->pszSettingsNotebook));
  598.                     cmnLoadString(habDesktop, hmodNLS, ID_XFSI_ATTRIBUTES     , &(pNLSStrings->pszAttributes));
  599.                     cmnLoadString(habDesktop, hmodNLS, ID_XFSI_ATTR_ARCHIVED  , &(pNLSStrings->pszAttrArchived));
  600.                     cmnLoadString(habDesktop, hmodNLS, ID_XFSI_ATTR_SYSTEM    , &(pNLSStrings->pszAttrSystem));
  601.                     cmnLoadString(habDesktop, hmodNLS, ID_XFSI_ATTR_HIDDEN    , &(pNLSStrings->pszAttrHidden));
  602.                     cmnLoadString(habDesktop, hmodNLS, ID_XFSI_ATTR_READONLY  , &(pNLSStrings->pszAttrReadOnly));
  603.  
  604.                     cmnLoadString(habDesktop, hmodNLS, ID_XFSI_FLDRSETTINGS   , &(pNLSStrings->pszWarp3FldrView));
  605.                     cmnLoadString(habDesktop, hmodNLS, ID_XFSI_SMALLICONS     , &(pNLSStrings->pszSmallIcons  ));
  606.                     cmnLoadString(habDesktop, hmodNLS, ID_XFSI_FLOWED         , &(pNLSStrings->pszFlowed));
  607.                     cmnLoadString(habDesktop, hmodNLS, ID_XFSI_NONFLOWED      , &(pNLSStrings->pszNonFlowed));
  608.                     cmnLoadString(habDesktop, hmodNLS, ID_XFSI_NOGRID         , &(pNLSStrings->pszNoGrid));
  609.  
  610.                     cmnLoadString(habDesktop, hmodNLS, ID_XFSI_SHOWSTATUSBAR  , &(pNLSStrings->pszShowStatusBar));
  611.                 }
  612.  
  613.                 // after all this, unload the old resource module
  614.                 DosFreeModule(hmodOldResource);
  615.  
  616.             } // end else
  617.  
  618.         }
  619.     }
  620.  
  621.     // return (new?) module handle
  622.     return (hmodNLS);
  623. }
  624.  
  625. /*
  626.  *@@ cmnQueryNLSStrings:
  627.  *      returns pointer to global NLSSTRINGS structure which contains
  628.  *      all the language-dependent XFolder strings from the resource
  629.  *      files.
  630.  */
  631.  
  632. PNLSSTRINGS cmnQueryNLSStrings(VOID)
  633. {
  634.     if (pNLSStringsGlobal == NULL) {
  635.         pNLSStringsGlobal = malloc(sizeof(NLSSTRINGS));
  636.         memset(pNLSStringsGlobal, 0, sizeof(NLSSTRINGS));
  637.     }
  638.     return (pNLSStringsGlobal);
  639. }
  640.  
  641. /*-------------------------------------------------------------------
  642.  *                                                                  *
  643.  *   XFolder Global Settings                                        *
  644.  *                                                                  *
  645.  ********************************************************************/
  646.  
  647. /*
  648.  *@@ cmnQueryStatusBarSetting:
  649.  *      returns a PSZ to a certain status bar setting, which
  650.  *      may be:
  651.  *      --      SBS_STATUSBARFONT       font (e.g. "9.WarpSans")
  652.  *      --      SBS_TEXTNONESEL         mnemonics for no-object mode
  653.  *      --      SBS_TEXTMULTISEL        mnemonics for multi-object mode
  654.  *
  655.  *      Note that there is no key for querying the mnemonics for
  656.  *      one-object mode, because this is now handled by the
  657.  *      functions in statbars.c
  658.  *      to provide different data depending on the
  659.  *      class of the selected object.
  660.  */
  661.  
  662. PSZ cmnQueryStatusBarSetting(USHORT usSetting)
  663. {
  664.     switch (usSetting) {
  665.         case SBS_STATUSBARFONT:
  666.                 return (szStatusBarFont);
  667.         case SBS_TEXTNONESEL:
  668.                 return (szSBTextNoneSel);
  669.         case SBS_TEXTMULTISEL:
  670.                 return (szSBTextMultiSel);
  671.         default:
  672.                 return (NULL);
  673.     }
  674. }
  675.  
  676. /*
  677.  *@@ cmnSetStatusBarSetting:
  678.  *      sets usSetting to pszSetting. If pszSetting == NULL, the
  679.  *      default value will be loaded from the XFolder NLS DLL.
  680.  *      usSetting works just like in cmnQueryStatusBarSetting.
  681.  */
  682.  
  683. BOOL cmnSetStatusBarSetting(USHORT usSetting, PSZ pszSetting)
  684. {
  685.     HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
  686.     HMODULE hmodResource = cmnQueryNLSModuleHandle(FALSE);
  687.  
  688.     switch (usSetting) {
  689.         case SBS_STATUSBARFONT: {
  690.                 CHAR szDummy[CCHMAXMNEMONICS];
  691.                 if (pszSetting) {
  692.                     strcpy(szStatusBarFont, pszSetting);
  693.                     PrfWriteProfileString(HINI_USERPROFILE, INIAPP_XFOLDER, INIKEY_STATUSBARFONT,
  694.                              szStatusBarFont);
  695.                 } else
  696.                     strcpy(szStatusBarFont, "8.Helv");
  697.                 sscanf(szStatusBarFont, "%d.%s", &(ulStatusBarHeight), &szDummy);
  698.                 ulStatusBarHeight += 15;
  699.         break; }
  700.         case SBS_TEXTNONESEL: {
  701.                 if (pszSetting) {
  702.                     strcpy(szSBTextNoneSel, pszSetting);
  703.                     PrfWriteProfileString(HINI_USERPROFILE, INIAPP_XFOLDER, INIKEY_SBTEXTNONESEL,
  704.                              szSBTextNoneSel);
  705.                 } else
  706.                     WinLoadString(habDesktop, hmodResource, ID_XSSI_SBTEXTNONESEL,
  707.                         sizeof(szSBTextNoneSel), szSBTextNoneSel);
  708.         break; }
  709.         case SBS_TEXTMULTISEL: {
  710.                 if (pszSetting) {
  711.                     strcpy(szSBTextMultiSel, pszSetting);
  712.                     PrfWriteProfileString(HINI_USERPROFILE, INIAPP_XFOLDER, INIKEY_SBTEXTMULTISEL,
  713.                              szSBTextMultiSel);
  714.                 } else
  715.                     WinLoadString(habDesktop, hmodResource, ID_XSSI_SBTEXTMULTISEL,
  716.                         sizeof(szSBTextMultiSel), szSBTextMultiSel);
  717.         break; }
  718.         default:
  719.                 return (FALSE);
  720.     }
  721.     return (TRUE);
  722. }
  723.  
  724. /*
  725.  *@@ cmnQueryStatusBarHeight:
  726.  *      returns the height of the status bars according to the
  727.  *      current settings in pixels. This was calculated when
  728.  *      the status bar font was set.
  729.  */
  730.  
  731. ULONG cmnQueryStatusBarHeight(VOID)
  732. {
  733.     return (ulStatusBarHeight);
  734. }
  735.  
  736. /*
  737.  *@@ cmnLoadGlobalSettings:
  738.  *      this loads the Global Settings from the INI files; should
  739.  *      not be called directly, because this is done automatically
  740.  *      by cmnQueryGlobalSettings, if necessary.
  741.  */
  742.  
  743. PGLOBALSETTINGS cmnLoadGlobalSettings(VOID)
  744. {
  745.     ULONG       ulCopied1;
  746.  
  747.     if (pGlobalSettings == NULL) {
  748.         pGlobalSettings = malloc(sizeof(GLOBALSETTINGS));
  749.         memset(pGlobalSettings, 0, sizeof(GLOBALSETTINGS));
  750.     }
  751.  
  752.     // first set default settings for each settings page;
  753.     // we only load the "real" settings from OS2.INI afterwards
  754.     // because the user might have updated XFolder, and the
  755.     // settings struct in the INIs might be too short
  756.     cmnSetDefaultSettings(SP_1GENERIC              );
  757.     cmnSetDefaultSettings(SP_2REMOVEITEMS          );
  758.     cmnSetDefaultSettings(SP_25ADDITEMS            );
  759.     cmnSetDefaultSettings(SP_26CONFIGITEMS         );
  760.     cmnSetDefaultSettings(SP_27STATUSBAR           );
  761.     cmnSetDefaultSettings(SP_3SNAPTOGRID           );
  762.     cmnSetDefaultSettings(SP_4ACCELERATORS         );
  763.     cmnSetDefaultSettings(SP_5INTERNALS            );
  764.     cmnSetDefaultSettings(SP_DTP1                  );
  765.     cmnSetDefaultSettings(SP_DTP2                  );
  766.     cmnSetDefaultSettings(SP_FLDRSORT_GLOBAL       );
  767.     cmnSetDefaultSettings(SP_FILEOPS               );
  768.  
  769.     // set global settings w/out settings page
  770.     pGlobalSettings->ShowBootupStatus = 0;
  771.     pGlobalSettings->WpsShowClassInfo = 1;
  772.  
  773.     PrfQueryProfileString(HINI_USERPROFILE, INIAPP_XFOLDER, INIKEY_STATUSBARFONT,
  774.              "8.Helv", &(szStatusBarFont), sizeof(szStatusBarFont));
  775.     sscanf(szStatusBarFont, "%d.*%s", &(ulStatusBarHeight));
  776.     ulStatusBarHeight += 15;
  777.  
  778.     PrfQueryProfileString(HINI_USERPROFILE, INIAPP_XFOLDER, INIKEY_SBTEXTNONESEL,
  779.                 NULL, &(szSBTextNoneSel), sizeof(szSBTextNoneSel));
  780.     PrfQueryProfileString(HINI_USERPROFILE, INIAPP_XFOLDER, INIKEY_SBTEXTMULTISEL,
  781.                 NULL, &(szSBTextMultiSel), sizeof(szSBTextMultiSel));
  782.  
  783.     ulCopied1 = sizeof(GLOBALSETTINGS);
  784.     // get global XFolder settings from OS2.INI
  785.     PrfQueryProfileData(HINI_USERPROFILE, INIAPP_XFOLDER, INIKEY_GLOBALSETTINGS,
  786.                 pGlobalSettings, &ulCopied1);
  787.  
  788.     return (pGlobalSettings);
  789. }
  790.  
  791. /*
  792.  *@@ cmnQueryGlobalSettings:
  793.  *      returns pointer to the GLOBALSETTINGS structure which
  794.  *      contains the XFolder Global Settings valid for all
  795.  *      classes. Loads the settings from the INI files if this
  796.  *      hasn't been done yet. Used all the time throughout XFolder.
  797.  */
  798.  
  799. PGLOBALSETTINGS cmnQueryGlobalSettings(VOID)
  800. {
  801.     if (pGlobalSettings == NULL) {
  802.         cmnLoadGlobalSettings();
  803.     }
  804.  
  805.     return (pGlobalSettings);
  806. }
  807.  
  808. /*
  809.  *@@ cmnStoreGlobalSettings:
  810.  *      stores the current Global Settings back into the INI files;
  811.  *      returns TRUE if successful.
  812.  */
  813.  
  814. BOOL cmnStoreGlobalSettings(VOID)
  815. {
  816.     return (PrfWriteProfileData(HINI_USERPROFILE, INIAPP_XFOLDER, INIKEY_GLOBALSETTINGS,
  817.         pGlobalSettings, sizeof(GLOBALSETTINGS)));
  818. }
  819.  
  820. /*
  821.  *@@ cmnSetDefaultSettings:
  822.  *      resets those Global Settings which correspond to usSettingsPage
  823.  *      in the System notebook to the default values; usSettingsPage
  824.  *      may have 1 thru the number of XFolder Settings pages in the
  825.  *      System notebook (SP_* flags). This is used to initialize
  826.  *      XFolder settings at startup and by the "Default" buttons on
  827.  *      the notebook settings pages.
  828.  */
  829.  
  830. BOOL cmnSetDefaultSettings(USHORT usSettingsPage)
  831. {
  832.     // HMODULE hmodResource = cmnQueryNLSModuleHandle(FALSE);
  833.  
  834.     switch(usSettingsPage) {
  835.         case SP_1GENERIC: {
  836.             pGlobalSettings->ShowInternals = 1;
  837.             pGlobalSettings->ReplIcons = 1;
  838.             pGlobalSettings->FullPath = 1;
  839.             pGlobalSettings->KeepTitle = 1;
  840.             pGlobalSettings->MaxPathChars = 25;
  841.             pGlobalSettings->TreeViewAutoScroll = 1;
  842.         break; }
  843.  
  844.         case SP_2REMOVEITEMS: {
  845.             pGlobalSettings->DefaultMenuItems = 0;
  846.             pGlobalSettings->RemoveLockInPlaceItem = 0;
  847.             pGlobalSettings->RemoveCheckDiskItem = 0;
  848.             pGlobalSettings->RemoveFormatDiskItem = 0;
  849.             pGlobalSettings->RemoveViewMenu = 0;
  850.             pGlobalSettings->RemovePasteItem = 0;
  851.         break; }
  852.  
  853.         case SP_25ADDITEMS: {
  854.             pGlobalSettings->FileAttribs = 1;
  855.             pGlobalSettings->AddCopyFilenameItem = 1;
  856.             pGlobalSettings->ExtendFldrViewMenu = 1;
  857.             pGlobalSettings->MoveRefreshNow = (doshIsWarp4() ? 1 : 0);
  858.             pGlobalSettings->AddSelectSomeItem = 1;
  859.             pGlobalSettings->AddFolderContentItem = 1;
  860.             pGlobalSettings->FCShowIcons = 0;
  861.         break; }
  862.  
  863.         case SP_26CONFIGITEMS: {
  864.             pGlobalSettings->MenuCascadeMode = 0;
  865.             pGlobalSettings->RemoveX = 1;
  866.             pGlobalSettings->AppdParam = 1;
  867.             pGlobalSettings->TemplatesOpenSettings = BM_INDETERMINATE;
  868.             pGlobalSettings->TemplatesReposition = 1;
  869.         break; }
  870.  
  871.         case SP_27STATUSBAR: {
  872.             pGlobalSettings->StatusBar = 0;
  873.             pGlobalSettings->SBStyle = (doshIsWarp4() ? SBSTYLE_WARP4MENU : SBSTYLE_WARP3RAISED);
  874.             pGlobalSettings->SBForViews = SBV_ICON | SBV_DETAILS;
  875.             pGlobalSettings->lSBBgndColor = WinQuerySysColor(HWND_DESKTOP, SYSCLR_INACTIVEBORDER, 0);
  876.             pGlobalSettings->lSBTextColor = WinQuerySysColor(HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0);
  877.             cmnSetStatusBarSetting(SBS_TEXTNONESEL, NULL);
  878.             cmnSetStatusBarSetting(SBS_TEXTMULTISEL, NULL);
  879.         break; }
  880.  
  881.         case SP_3SNAPTOGRID: {
  882.             pGlobalSettings->AddSnapToGridItem = 1;
  883.             pGlobalSettings->GridX = 15;
  884.             pGlobalSettings->GridY = 10;
  885.             pGlobalSettings->GridCX = 20;
  886.             pGlobalSettings->GridCY = 35;
  887.         break; }
  888.  
  889.         case SP_4ACCELERATORS: {
  890.             pGlobalSettings->Accelerators = 1;
  891.         break; }
  892.  
  893.         case SP_5INTERNALS: {
  894.             pGlobalSettings->VarMenuOffset = 300;
  895.             pGlobalSettings->NoWorkerThread = 0;
  896.             pGlobalSettings->NoSubclassing = 0;
  897.             pGlobalSettings->ShowXFolderAnim = 1;
  898.         break; }
  899.  
  900.         case SP_DTP1: { // shutdown page
  901.             pGlobalSettings->ulXShutdownFlags =
  902.                 XSD_RESTARTWPS | XSD_WPS_CLOSEWINDOWS | XSD_CONFIRM | XSD_REBOOT | XSD_ANIMATE;
  903.         break; }
  904.  
  905.         case SP_DTP2: {
  906.             pGlobalSettings->ShowStartupProgress = 1;
  907.             pGlobalSettings->ulStartupDelay = 1000;
  908.         break; }
  909.  
  910.         case SP_FLDRSORT_GLOBAL: {
  911.             pGlobalSettings->ReplaceSort = 0;
  912.             pGlobalSettings->DefaultSort = SV_NAME;
  913.             pGlobalSettings->AlwaysSort = 0;
  914.         break; }
  915.  
  916.         case SP_FILEOPS: {
  917.             pGlobalSettings->ReplConfirms = 1;
  918.             pGlobalSettings->CleanupINIs = 1;
  919.         break; }
  920.     }
  921.  
  922.     return (TRUE);
  923. }
  924.  
  925. /*-------------------------------------------------------------------
  926.  *                                                                  *
  927.  *   Folder hotkey functions                                        *
  928.  *                                                                  *
  929.  ********************************************************************/
  930.  
  931. /*
  932.  *  The folder hotkeys are stored in a static array which
  933.  *  is is FLDRHOTKEYCOUNT items in size. This is calculated
  934.  *  at compile time according to the items which were
  935.  *  declared in dlgids.h.
  936.  *
  937.  *  The following functions give the other XFolder parts
  938.  *  access to this data and/or manipulate it.
  939.  */
  940.  
  941. // XFolder folder hotkeys static array
  942. XFLDHOTKEY     FolderHotkeys[FLDRHOTKEYCOUNT];
  943.  
  944. /*
  945.  *@@ cmnQueryFldrHotkeys:
  946.  *      this returns the address of the static
  947.  *      folder hotkeys array in common.c. The
  948.  *      size of that array is FLDRHOTKEYSSIZE (common.h).
  949.  */
  950.  
  951. PXFLDHOTKEY cmnQueryFldrHotkeys(VOID) {
  952.     return (&FolderHotkeys[0]);
  953. }
  954.  
  955. /*
  956.  *@@ cmnLoadDefaultFldrHotkeys:
  957.  *      this resets the folder hotkeys to the default
  958.  *      values.
  959.  */
  960.  
  961. void cmnLoadDefaultFldrHotkeys(VOID)
  962. {
  963.     // Ctrl+A: Select all
  964.     FolderHotkeys[0].usKeyCode  = (USHORT)'a';
  965.     FolderHotkeys[0].usFlags    = KC_CTRL;
  966.     FolderHotkeys[0].usCommand  = WPMENUID_SELALL;
  967.  
  968.     // F5
  969.     FolderHotkeys[1].usKeyCode  = VK_F5;
  970.     FolderHotkeys[1].usFlags    = KC_VIRTUALKEY;
  971.     FolderHotkeys[1].usCommand  = WPMENUID_REFRESH,
  972.  
  973.     // Backspace
  974.     FolderHotkeys[2].usKeyCode  = VK_BACKSPACE;
  975.     FolderHotkeys[2].usFlags    = KC_VIRTUALKEY;
  976.     FolderHotkeys[2].usCommand  = ID_XFMI_OFS_OPENPARENT;
  977.  
  978.     //  Ctrl+D: De-select all
  979.     FolderHotkeys[3].usKeyCode  = (USHORT)'d';
  980.     FolderHotkeys[3].usFlags    = KC_CTRL;
  981.     FolderHotkeys[3].usCommand  = WPMENUID_DESELALL;
  982.  
  983.     // Ctrl+Shift+D: Details view
  984.     FolderHotkeys[4].usKeyCode  = (USHORT)'D';
  985.     FolderHotkeys[4].usFlags    = KC_CTRL+KC_SHIFT;
  986.     FolderHotkeys[4].usCommand  = WPMENUID_DETAILS;
  987.  
  988.     // Ctrl+Shift+I: Icon  view
  989.     FolderHotkeys[5].usKeyCode  = (USHORT)'I';
  990.     FolderHotkeys[5].usFlags    = KC_CTRL+KC_SHIFT;
  991.     FolderHotkeys[5].usCommand  = WPMENUID_ICON;
  992.  
  993.     // Ctrl+Shift+S: Open Settings
  994.     FolderHotkeys[6].usKeyCode  = (USHORT)'S';
  995.     FolderHotkeys[6].usFlags    = KC_CTRL+KC_SHIFT;
  996.     FolderHotkeys[6].usCommand  = WPMENUID_PROPERTIES;
  997.  
  998.     // Ctrl+N: Sort by name
  999.     FolderHotkeys[7].usKeyCode  = (USHORT)'n';
  1000.     FolderHotkeys[7].usFlags    = KC_CTRL;
  1001.     FolderHotkeys[7].usCommand  = ID_WPMI_SORTBYNAME;
  1002.  
  1003.     // Ctrl+Z: Sort by size
  1004.     FolderHotkeys[8].usKeyCode  = (USHORT)'z';
  1005.     FolderHotkeys[8].usFlags    = KC_CTRL;
  1006.     FolderHotkeys[8].usCommand  = ID_WPMI_SORTBYSIZE;
  1007.  
  1008.     // Ctrl+E: Sort by extension (NPS)
  1009.     FolderHotkeys[9].usKeyCode  = (USHORT)'e';
  1010.     FolderHotkeys[9].usFlags    = KC_CTRL;
  1011.     FolderHotkeys[9].usCommand  = ID_XFMI_OFS_SORTBYEXT;
  1012.  
  1013.     // Ctrl+W: Sort by write date
  1014.     FolderHotkeys[10].usKeyCode  = (USHORT)'w';
  1015.     FolderHotkeys[10].usFlags    = KC_CTRL;
  1016.     FolderHotkeys[10].usCommand  = ID_WPMI_SORTBYWRITEDATE;
  1017.  
  1018.     // Ctrl+Y: Sort by type
  1019.     FolderHotkeys[11].usKeyCode  = (USHORT)'y';
  1020.     FolderHotkeys[11].usFlags    = KC_CTRL;
  1021.     FolderHotkeys[11].usCommand  = ID_WPMI_SORTBYTYPE;
  1022.  
  1023.     // Shift+Backspace
  1024.     FolderHotkeys[12].usKeyCode  = VK_BACKSPACE;
  1025.     FolderHotkeys[12].usFlags    = KC_VIRTUALKEY+KC_SHIFT;
  1026.     FolderHotkeys[12].usCommand  = ID_XFMI_OFS_OPENPARENTANDCLOSE;
  1027.  
  1028.     // Ctrl+S: Select by name
  1029.     FolderHotkeys[13].usKeyCode  = (USHORT)'s';
  1030.     FolderHotkeys[13].usFlags    = KC_CTRL;
  1031.     FolderHotkeys[13].usCommand  = ID_XFMI_OFS_SELECTSOME;
  1032.  
  1033.     // Ctrl+insert: copy filename (w/out path)
  1034.     FolderHotkeys[14].usKeyCode  = VK_INSERT;
  1035.     FolderHotkeys[14].usFlags    = KC_VIRTUALKEY+KC_CTRL;
  1036.     FolderHotkeys[14].usCommand  = ID_XFMI_OFS_COPYFILENAME_SHORT;
  1037.  
  1038.     FolderHotkeys[15].usCommand = 0;
  1039. }
  1040.  
  1041. /*
  1042.  *@@ cmnLoadFolderHotkeys:
  1043.  *      this initializes the folder hotkey array with
  1044.  *      the data which was previously stored in OS2.INI.
  1045.  */
  1046.  
  1047. void cmnLoadFolderHotkeys(VOID)
  1048. {
  1049.     ULONG ulCopied2 = sizeof(FolderHotkeys);
  1050.     if (!PrfQueryProfileData(HINI_USERPROFILE, INIAPP_XFOLDER, INIKEY_ACCELERATORS,
  1051.                 &FolderHotkeys, &ulCopied2))
  1052.         cmnLoadDefaultFldrHotkeys();
  1053. }
  1054.  
  1055. /*
  1056.  *@@ cmnStoreFldrHotkeys:
  1057.  *       this stores the folder hotkeys in OS2.INI.
  1058.  */
  1059.  
  1060. void cmnStoreFldrHotkeys(VOID)
  1061. {
  1062.     SHORT i2 = 0;
  1063.  
  1064.     // store only the accels that are actually used
  1065.     while (FolderHotkeys[i2].usCommand)
  1066.         i2++;
  1067.  
  1068.     PrfWriteProfileData(HINI_USERPROFILE, INIAPP_XFOLDER, INIKEY_ACCELERATORS,
  1069.         &FolderHotkeys, (i2+1) * sizeof(XFLDHOTKEY));
  1070. }
  1071.  
  1072. /*
  1073.  *@@ cmnProcessFldrHotkey:
  1074.  *      this is called by the subclassed folder frame wnd proc
  1075.  *      to check for whether a given WM_CHAR message matches
  1076.  *      one of the folder hotkeys.
  1077.  *
  1078.  *      The parameters are those of the WM_CHAR message. This
  1079.  *      returns TRUE if the pressed key was a hotkey; in that
  1080.  *      case, the corresponding WM_COMMAND message is
  1081.  *      automatically posted to the folder frame, which will
  1082.  *      cause the defined action to occur.
  1083.  */
  1084.  
  1085. BOOL cmnProcessFldrHotkey(HWND hwndFrame, MPARAM mp1, MPARAM mp2)
  1086. {
  1087.     USHORT  us;
  1088.  
  1089.     USHORT usFlags    = SHORT1FROMMP(mp1);
  1090.     USHORT usch       = SHORT1FROMMP(mp2);
  1091.     USHORT usvk       = SHORT2FROMMP(mp2);
  1092.     USHORT usKeyCode  = 0;
  1093.  
  1094.     PGLOBALSETTINGS pGlobalSettings = cmnQueryGlobalSettings();
  1095.  
  1096.     // now check if the key is relevant: filter out KEY UP
  1097.     // messages and check if either a virtual key (such as F5)
  1098.     // or Ctrl or Alt was pressed
  1099.     if (    ((usFlags & KC_KEYUP) == 0)
  1100.         &&  (     ((usFlags & KC_VIRTUALKEY) != 0)
  1101.                   // Ctrl pressed?
  1102.                || ((usFlags & KC_CTRL) != 0)
  1103.                   // Alt pressed?
  1104.                || ((usFlags & KC_ALT) != 0)
  1105.                   // or one of the Win95 keys?
  1106.                || (   ((usFlags & KC_VIRTUALKEY) == 0)
  1107.                    && (     (usch == 0xEC00)
  1108.                         ||  (usch == 0xED00)
  1109.                         ||  (usch == 0xEE00)
  1110.                       )
  1111.                   )
  1112.             )
  1113.        )
  1114.     {
  1115.  
  1116.         if (usFlags & KC_VIRTUALKEY)
  1117.             usKeyCode = usvk;
  1118.         else
  1119.             usKeyCode = usch;
  1120.  
  1121.         usFlags &= (KC_VIRTUALKEY | KC_CTRL | KC_ALT | KC_SHIFT);
  1122.         us = 0;
  1123.  
  1124.         #ifdef DEBUG_KEYS
  1125.             _Pmpf(("cmnProcessFldrHotkey: usKeyCode: 0x%lX, usFlags: 0x%lX", usKeyCode, usFlags));
  1126.         #endif
  1127.  
  1128.         // now go through the global accelerator list and check
  1129.         // if the pressed key was assigned an action to
  1130.         while (FolderHotkeys[us].usCommand)
  1131.         {
  1132.             USHORT usCommand;
  1133.             if (
  1134.                    (  (FolderHotkeys[us].usFlags == usFlags)
  1135.                    && (FolderHotkeys[us].usKeyCode == usKeyCode)
  1136.                    )
  1137.                )
  1138.             {   // OK: this is a hotkey; find the corresponding
  1139.                 // "command" (= menu ID) and post it to the frame
  1140.                 // window, which will execute it
  1141.                 usCommand = FolderHotkeys[us].usCommand;
  1142.                 if ( (usCommand >= WPMENUID_USER) &&
  1143.                      (usCommand < WPMENUID_USER+FIRST_VARIABLE) )
  1144.                         usCommand += pGlobalSettings->VarMenuOffset;
  1145.                 WinPostMsg(hwndFrame,
  1146.                         WM_COMMAND,
  1147.                         (MPARAM)usCommand,
  1148.                         MPFROM2SHORT(CMDSRC_MENU,
  1149.                                 FALSE) );     // results from keyboard operation
  1150.  
  1151.                 #ifdef DEBUG_KEYS
  1152.                     _Pmpf(("  Posting command 0x%lX", usCommand));
  1153.                 #endif
  1154.  
  1155.                 return (TRUE);
  1156.             }
  1157.             us++;
  1158.         }
  1159.     }
  1160.     return (FALSE);
  1161. }
  1162.  
  1163. /*
  1164.  *@@ cmnDescribeKey:
  1165.  *      this stores a description of a certain
  1166.  *      key into pszBuf, using the NLS DLL strings.
  1167.  *      usFlags must contain usFlags from WM_CHAR,
  1168.  *      usKeyCode must be either usch (char code)
  1169.  *      or, with virtual keys, usvk (vk code).
  1170.  *      Returns TRUE if this was a valid key combo.
  1171.  */
  1172.  
  1173. BOOL cmnDescribeKey(PSZ pszBuf, USHORT usFlags, USHORT usKeyCode)
  1174. {
  1175.     BOOL rc = TRUE;
  1176.  
  1177.     PNLSSTRINGS pNLSStrings = cmnQueryNLSStrings();
  1178.  
  1179.     *pszBuf = 0;
  1180.     if (usFlags & KC_CTRL)
  1181.         strcpy(pszBuf, pNLSStrings->pszCtrl);
  1182.     if (usFlags & KC_SHIFT)
  1183.         strcat(pszBuf, pNLSStrings->pszShift);
  1184.     if (usFlags & KC_ALT)
  1185.         strcat(pszBuf, pNLSStrings->pszAlt);
  1186.  
  1187.     if (usFlags & KC_VIRTUALKEY) {
  1188.         switch (usKeyCode) {
  1189.             case VK_BACKSPACE: strcat(pszBuf, pNLSStrings->pszBackspace); break;
  1190.             case VK_TAB: strcat(pszBuf, pNLSStrings->pszTab); break;
  1191.             case VK_BACKTAB: strcat(pszBuf, pNLSStrings->pszBacktab); break;
  1192.             case VK_NEWLINE: strcat(pszBuf, pNLSStrings->pszEnter); break;
  1193.             case VK_ESC: strcat(pszBuf, pNLSStrings->pszEsc); break;
  1194.             case VK_SPACE: strcat(pszBuf, pNLSStrings->pszSpace); break;
  1195.             case VK_PAGEUP: strcat(pszBuf, pNLSStrings->pszPageup); break;
  1196.             case VK_PAGEDOWN: strcat(pszBuf, pNLSStrings->pszPagedown); break;
  1197.             case VK_END: strcat(pszBuf, pNLSStrings->pszEnd); break;
  1198.             case VK_HOME: strcat(pszBuf, pNLSStrings->pszHome); break;
  1199.             case VK_LEFT: strcat(pszBuf, pNLSStrings->pszLeft); break;
  1200.             case VK_UP: strcat(pszBuf, pNLSStrings->pszUp); break;
  1201.             case VK_RIGHT: strcat(pszBuf, pNLSStrings->pszRight); break;
  1202.             case VK_DOWN: strcat(pszBuf, pNLSStrings->pszDown); break;
  1203.             case VK_PRINTSCRN: strcat(pszBuf, pNLSStrings->pszPrintscrn); break;
  1204.             case VK_INSERT: strcat(pszBuf, pNLSStrings->pszInsert); break;
  1205.             case VK_DELETE: strcat(pszBuf, pNLSStrings->pszDelete); break;
  1206.             case VK_SCRLLOCK: strcat(pszBuf, pNLSStrings->pszScrlLock); break;
  1207.             case VK_NUMLOCK: strcat(pszBuf, pNLSStrings->pszNumLock); break;
  1208.             case VK_ENTER: strcat(pszBuf, pNLSStrings->pszEnter); break;
  1209.             case VK_F1: strcat(pszBuf, "F1"); break;
  1210.             case VK_F2: strcat(pszBuf, "F2"); break;
  1211.             case VK_F3: strcat(pszBuf, "F3"); break;
  1212.             case VK_F4: strcat(pszBuf, "F4"); break;
  1213.             case VK_F5: strcat(pszBuf, "F5"); break;
  1214.             case VK_F6: strcat(pszBuf, "F6"); break;
  1215.             case VK_F7: strcat(pszBuf, "F7"); break;
  1216.             case VK_F8: strcat(pszBuf, "F8"); break;
  1217.             case VK_F9: strcat(pszBuf, "F9"); break;
  1218.             case VK_F10: strcat(pszBuf, "F10"); break;
  1219.             case VK_F11: strcat(pszBuf, "F11"); break;
  1220.             case VK_F12: strcat(pszBuf, "F12"); break;
  1221.             case VK_F13: strcat(pszBuf, "F13"); break;
  1222.             case VK_F14: strcat(pszBuf, "F14"); break;
  1223.             case VK_F15: strcat(pszBuf, "F15"); break;
  1224.             case VK_F16: strcat(pszBuf, "F16"); break;
  1225.             case VK_F17: strcat(pszBuf, "F17"); break;
  1226.             case VK_F18: strcat(pszBuf, "F18"); break;
  1227.             case VK_F19: strcat(pszBuf, "F19"); break;
  1228.             case VK_F20: strcat(pszBuf, "F20"); break;
  1229.             case VK_F21: strcat(pszBuf, "F21"); break;
  1230.             case VK_F22: strcat(pszBuf, "F22"); break;
  1231.             case VK_F23: strcat(pszBuf, "F23"); break;
  1232.             case VK_F24: strcat(pszBuf, "F24"); break;
  1233.             default: break;
  1234.         }
  1235.     } // end virtualkeys
  1236.     else {
  1237.         switch (usKeyCode) {
  1238.             case 0xEC00: strcat(pszBuf, pNLSStrings->pszWinLeft); break;
  1239.             case 0xED00: strcat(pszBuf, pNLSStrings->pszWinRight); break;
  1240.             case 0xEE00: strcat(pszBuf, pNLSStrings->pszWinMenu); break;
  1241.             default: {
  1242.                 CHAR szTemp[2];
  1243.                 if (usKeyCode >= 'a')
  1244.                     szTemp[0] = (CHAR)usKeyCode-32;
  1245.                 else
  1246.                     szTemp[0] = (CHAR)usKeyCode;
  1247.                 szTemp[1] = '\0';
  1248.                 strcat(pszBuf, szTemp);
  1249.             }
  1250.         }
  1251.     }
  1252.  
  1253.     #ifdef DEBUG_KEYS
  1254.         _Pmpf(("Key: %s, usKeyCode: 0x%lX, usFlags: 0x%lX", pszBuf, usKeyCode, usFlags));
  1255.     #endif
  1256.  
  1257.     return (rc);
  1258. }
  1259.  
  1260. /*-------------------------------------------------------------------
  1261.  *                                                                  *
  1262.  *   Folder frame window subclassing                                *
  1263.  *                                                                  *
  1264.  ********************************************************************/
  1265.  
  1266. // root of linked list to remember original window
  1267. // procedures when subclassing frame windows for folder hotkeys;
  1268. // this list is maintained by wpOpen of XFolder
  1269. PSUBCLASSEDLISTITEM psliSubclassed = NULL;
  1270. // mutex semaphore for access to this list
  1271. HMTX                hmtxSubclassed = NULLHANDLE;
  1272.  
  1273. /*
  1274.  *@@ cmnInitPSLI:
  1275.  *      this is called once from M_XFolder::wpclsInitData
  1276.  *      to initialize the SUBCLASSEDLISTITEM list.
  1277.  */
  1278.  
  1279. VOID cmnInitPSLI(VOID)
  1280. {
  1281.     if (DosCreateMutexSem(NULL,
  1282.                         &hmtxSubclassed, 0, FALSE) != NO_ERROR)
  1283.     {
  1284.         DosBeep(100, 300);
  1285.         hmtxSubclassed = -1;
  1286.     }
  1287. }
  1288.  
  1289. /*
  1290.  *@@ cmnQueryPSLI:
  1291.  *      this retrieves the PSUBCLASSEDLISTITEM from the
  1292.  *      global linked list of subclassed frame windows,
  1293.  *      according to a given frame wnd handle. One of these
  1294.  *      structs is maintained for each open folder view
  1295.  *      to store window data which is needed everywhere.
  1296.  */
  1297.  
  1298. PSUBCLASSEDLISTITEM cmnQueryPSLI(HWND hwndFrame)
  1299. {
  1300.     PSUBCLASSEDLISTITEM psli = NULL;
  1301.     BOOL    fSemOwned = FALSE;
  1302.  
  1303.     TRY_QUIET(excpt1)
  1304.     {
  1305.         if (hwndFrame)
  1306.         {
  1307.             fSemOwned = (DosRequestMutexSem(hmtxSubclassed, 4000) == NO_ERROR);
  1308.             if (fSemOwned)
  1309.             {
  1310.                 psli = psliSubclassed;
  1311.                 while (psli) {
  1312.                     if (psli->hwndFrame == hwndFrame) {
  1313.                         /* pfnwpLast = pfnwpOriginal;
  1314.                         hwndLast = hwndFrame;
  1315.                         somSelfLast = somSelf; */
  1316.                         break; // while
  1317.                     }
  1318.                     else
  1319.                         psli = psli->pNext;
  1320.                 }
  1321.  
  1322.                 DosReleaseMutexSem(hmtxSubclassed);
  1323.                 fSemOwned = FALSE;
  1324.             }
  1325.         }
  1326.     }
  1327.     CATCH(excpt1)
  1328.     {
  1329.         if (fSemOwned) {
  1330.             DosReleaseMutexSem(hmtxSubclassed);
  1331.             fSemOwned = FALSE;
  1332.         }
  1333.     } END_CATCH;
  1334.  
  1335.     return (psli);
  1336. }
  1337.  
  1338. /*
  1339.  *@@ cmnSubclassFolderFrame:
  1340.  *      this routine is used by both XFolder::wpOpen and
  1341.  *      XFldDisk::wpOpen to subclass a new frame window
  1342.  *      to allow for extra XFolder features.
  1343.  *
  1344.  *      For this, this routines maintains a global linked
  1345.  *      list of subclassed windows (SUBCLASSEDLISTITEM
  1346.  *      structures), whose first item is stored in the global
  1347.  *      psliSubclassed variable. This is protected internally
  1348.  *      by a mutex semaphore; you should therefore always
  1349.  *      use cmnQueryPSLI to access that list.
  1350.  *
  1351.  *      Every list item contains (among other things) the
  1352.  *      original wnd proc of the subclassed window, which the
  1353.  *      subclassed wnd proc (fnwpSubclassedFolderFrame, xfldr.c)
  1354.  *      needs to call the the original folder wnd proc for a
  1355.  *      given frame window, because these procs might differ
  1356.  *      depending on the class or view type or installed WPS
  1357.  *      enhancers.
  1358.  *
  1359.  *      These list items are also used for various other frame
  1360.  *      data, such as the handles of the status bar and
  1361.  *      supplementary object windows.
  1362.  *      We cannot store this data elsewhere, because QWL_USER
  1363.  *      in the wnd data seems to be used by the WPS already.
  1364.  *
  1365.  *      Note: when called from XFolder::wpOpen, somSelf and
  1366.  *      pRealObject both point to the folder. However, when
  1367.  *      called from XFldDisk::wpOpen, somSelf has the
  1368.  *      disk object's root folder, while pRealObject has the
  1369.  *      disk object. Both are stored in the SUBCLASSEDLISTITEM
  1370.  *      structure.
  1371.  *
  1372.  *      This func returns the newly created SUBCLASSEDLISTITEM.
  1373.  */
  1374.  
  1375. PSUBCLASSEDLISTITEM cmnSubclassFolderFrame(HWND hwndFrame,
  1376.                                                 // in: frame wnd of new view (returned by wpOpen)
  1377.                                            XFolder *somSelf,
  1378.                                                 // in: folder; either XFolder's somSelf
  1379.                                                 // or XFldDisk's root folder
  1380.                                            WPObject *pRealObject,
  1381.                                                 // in: the "real" object; for XFolder, this is == somSelf,
  1382.                                                 // for XFldDisk, this is the disk object (needed for object handles)
  1383.                                            ULONG ulView)
  1384.                                                 // OPEN_CONTENTS et al.
  1385. {
  1386.     BOOL                fSemOwned = FALSE;
  1387.     PFNWP               pfnwpCurrent, pfnwpOriginal;
  1388.     HWND                hwndCnr;
  1389.     PSUBCLASSEDLISTITEM pNewItem = NULL;
  1390.     PGLOBALSETTINGS     pGlobalSettings = cmnQueryGlobalSettings();
  1391.  
  1392.     TRY_QUIET(excpt1)
  1393.     {
  1394.         // subclass only if the user hasn't disabled
  1395.         // subclassing globally
  1396.         if (pGlobalSettings->NoSubclassing == 0)
  1397.         {
  1398.             // exclude other views, such as settings notebooks and
  1399.             // possible user views
  1400.             if (    (hwndFrame)
  1401.                  && (   (ulView == OPEN_CONTENTS)
  1402.                      || (ulView == OPEN_TREE)
  1403.                      || (ulView == OPEN_DETAILS)
  1404.                     )
  1405.                )
  1406.             {
  1407.                 // get container wnd handle
  1408.                 hwndCnr = xwpsQueryCnrFromFrame(hwndFrame);
  1409.                 if (hwndCnr)
  1410.                 // only subclass frame window if it contains a container;
  1411.                 // just a security check
  1412.                 {
  1413.                     // now check if frame wnd has already been subclassed;
  1414.                     // just another security check
  1415.                     pfnwpCurrent = (PFNWP)WinQueryWindowPtr(hwndFrame, QWP_PFNWP);
  1416.                     if (pfnwpCurrent != (PFNWP)fnwpSubclassedFolderFrame)
  1417.                     {
  1418.                         if (!(pfnwpOriginal = WinSubclassWindow(hwndFrame, (PFNWP)fnwpSubclassedFolderFrame)))
  1419.                             // error occured subclassing:
  1420.                             DebugBox("XFolder", "Folder subclassing failed.");
  1421.                             // should never happen
  1422.                         else
  1423.                         {
  1424.                             // subclassing succeeded: now remember the old wnd proc
  1425.                             // and other data in the global linked list
  1426.                             pNewItem = malloc(sizeof(SUBCLASSEDLISTITEM));
  1427.                             pNewItem->pfnwpOriginal = pfnwpOriginal;
  1428.                             // store various other data here
  1429.                             pNewItem->hwndFrame = hwndFrame;
  1430.                             pNewItem->somSelf = somSelf;
  1431.                             pNewItem->pRealObject = pRealObject;
  1432.                             pNewItem->hwndCnr = hwndCnr;
  1433.                             pNewItem->ulView = ulView;
  1434.                             pNewItem->fRemoveSrcEmphasis = FALSE;
  1435.                             // set status bar hwnd to zero at this point;
  1436.                             // this will be created elsewhere
  1437.                             pNewItem->hwndStatusBar = NULLHANDLE;
  1438.                             // create a supplementary object window
  1439.                             // for this folder frame (see
  1440.                             // fnwpSupplObject for details)
  1441.                             pNewItem->hwndSupplObject = WinCreateWindow(
  1442.                                            HWND_OBJECT,
  1443.                                            WNDCLASS_SUPPLOBJECT, // class name
  1444.                                            (PSZ)"SupplObject",     // title
  1445.                                            0,           // style
  1446.                                            0,0,0,0,     // position
  1447.                                            0,           // owner
  1448.                                            HWND_BOTTOM, // z-order
  1449.                                            0,           // window id
  1450.                                            pNewItem,    // pass the struct to WM_CREATE
  1451.                                            NULL);       // pres params
  1452.                             // append to global list
  1453.                             fSemOwned = (DosRequestMutexSem(hmtxSubclassed, 4000) == NO_ERROR);
  1454.                             if (fSemOwned) {
  1455.                                 lstAppendItem((PLISTITEM*)&psliSubclassed, NULL,
  1456.                                             (PLISTITEM)pNewItem);
  1457.                                 DosReleaseMutexSem(hmtxSubclassed);
  1458.                                 fSemOwned = FALSE;
  1459.                             }
  1460.                         }
  1461.                     }
  1462.                 }
  1463.             }
  1464.         }
  1465.     }
  1466.     CATCH(excpt1)
  1467.     {
  1468.         if (fSemOwned) {
  1469.             DosReleaseMutexSem(hmtxSubclassed);
  1470.             fSemOwned = FALSE;
  1471.         }
  1472.     } END_CATCH;
  1473.     return (pNewItem);
  1474. }
  1475.  
  1476. /*
  1477.  *@@ cmnRemovePSLI:
  1478.  *      reverse to cmnSubclassFolderFrame, this removes
  1479.  *      a PSUBCLASSEDLISTITEM from the global list again.
  1480.  *      Called upon WM_CLOSE in folder frames.
  1481.  */
  1482.  
  1483. VOID cmnRemovePSLI(PSUBCLASSEDLISTITEM psli)
  1484. {
  1485.     BOOL fSemOwned = FALSE;
  1486.  
  1487.     TRY_QUIET(excpt1)
  1488.     {
  1489.         fSemOwned = (DosRequestMutexSem(hmtxSubclassed, 4000) == NO_ERROR);
  1490.         if (fSemOwned) {
  1491.             lstRemoveItem((PLISTITEM*)&psliSubclassed, NULL,
  1492.                     (PLISTITEM)psli);
  1493.             DosReleaseMutexSem(hmtxSubclassed);
  1494.             fSemOwned = FALSE;
  1495.         }
  1496.     }
  1497.     CATCH(excpt1)
  1498.     {
  1499.         if (fSemOwned) {
  1500.             DosReleaseMutexSem(hmtxSubclassed);
  1501.             fSemOwned = FALSE;
  1502.         }
  1503.     } END_CATCH;
  1504. }
  1505.  
  1506. /*-------------------------------------------------------------------
  1507.  *                                                                  *
  1508.  *   Miscellaneous                                                  *
  1509.  *                                                                  *
  1510.  ********************************************************************/
  1511.  
  1512. /*
  1513.  *@@ fnwpAutoSizeStatic:
  1514.  *      dlg proc for the subclassed static text control in msg box;
  1515.  *      automatically resizes the msg box window when text changes
  1516.  */
  1517.  
  1518. PFNWP pfnwpOrigStatic = NULL;
  1519.  
  1520. MRESULT EXPENTRY fnwpAutoSizeStatic(HWND hwndStatic, ULONG msg, MPARAM mp1, MPARAM mp2)
  1521. {
  1522.     MRESULT mrc = NULL;
  1523.     switch (msg) {
  1524.  
  1525.         /*
  1526.          * WM_SETLONGTEXT:
  1527.          *      this arrives here when the window text changes,
  1528.          *      especially when fnwpMessageBox sets the window
  1529.          *      text; we will now reposition all the controls.
  1530.          *      mp1 is a PSZ to the new text.
  1531.          */
  1532.  
  1533.         case WM_SETLONGTEXT: {
  1534.             CHAR szFont[300];
  1535.             PSZ p = (PSZ)WinQueryWindowULong(hwndStatic, QWL_USER);
  1536.             if (p)
  1537.                 free(p);
  1538.             p = strdup((PSZ)mp1);
  1539.             WinSetWindowULong(hwndStatic, QWL_USER, (ULONG)p);
  1540.             // WinPostMsg(hwndStatic, WM_UPDATE, MPNULL, MPNULL);
  1541.             PrfQueryProfileString(HINI_USER, INIAPP_XFOLDER, INIKEY_DLGFONT, "9.WarpSans",
  1542.                 szFont, sizeof(szFont)-1);
  1543.             WinSetPresParam(hwndStatic, PP_FONTNAMESIZE,
  1544.                  (ULONG)strlen(szFont) + 1, (PVOID)szFont);
  1545.             // this will also update the display
  1546.  
  1547.             /* PSZ pwp = (PWNDPARAMS)mp1;
  1548.             _Pmpf(( "WM_SETWINDOWPARAMS" ));
  1549.             mrc = (*pfnwpOrigStatic)(hwndStatic, msg, mp1, mp2);
  1550.             if (pwp) {
  1551.             } */
  1552.         break; }
  1553.  
  1554.         /*
  1555.          * WM_PRESPARAMCHANGED:
  1556.          *      if a font has been dropped on the window, store
  1557.          *      the information and enforce control repositioning
  1558.          *      also
  1559.          */
  1560.  
  1561.         case WM_PRESPARAMCHANGED: {
  1562.             // _Pmpf(( "PRESPARAMCHANGED" ));
  1563.             switch ((ULONG)mp1) {
  1564.                 case PP_FONTNAMESIZE: {
  1565.                     ULONG attrFound; //, abValue[32];
  1566.                     CHAR  szFont[100];
  1567.                     HWND  hwndDlg = WinQueryWindow(hwndStatic, QW_PARENT);
  1568.                     WinQueryPresParam(hwndStatic,
  1569.                                 PP_FONTNAMESIZE,
  1570.                                 0,
  1571.                                 &attrFound,
  1572.                                 (ULONG)sizeof(szFont),
  1573.                                 (PVOID)&szFont,
  1574.                                 0);
  1575.                     PrfWriteProfileString(HINI_USER, INIAPP_XFOLDER, INIKEY_DLGFONT,
  1576.                         szFont);
  1577.  
  1578.                     // now also change the buttons
  1579.                     WinSetPresParam(WinWindowFromID(hwndDlg, 1),
  1580.                         PP_FONTNAMESIZE,
  1581.                         (ULONG)strlen(szFont) + 1, (PVOID)szFont);
  1582.                     WinSetPresParam(WinWindowFromID(hwndDlg, 2),
  1583.                         PP_FONTNAMESIZE,
  1584.                         (ULONG)strlen(szFont) + 1, (PVOID)szFont);
  1585.                     WinSetPresParam(WinWindowFromID(hwndDlg, 3),
  1586.                         PP_FONTNAMESIZE,
  1587.                         (ULONG)strlen(szFont) + 1, (PVOID)szFont);
  1588.  
  1589.                     WinPostMsg(hwndStatic, WM_UPDATE, MPNULL, MPNULL);
  1590.                 break; }
  1591.             }
  1592.         break; }
  1593.  
  1594.         /*
  1595.          * WM_UPDATE:
  1596.          *      this actually does all the calculations to reposition
  1597.          *      all the msg box controls
  1598.          */
  1599.  
  1600.         case WM_UPDATE: {
  1601.             RECTL   rcl, rcl2;
  1602.             SWP     swp;
  1603.             HWND    hwndIcon, hwndDlg;
  1604.             PSZ     pszText;
  1605.  
  1606.             HPS hps = WinGetPS(hwndStatic);
  1607.  
  1608.             // _Pmpf(( "WM_UPDATE" ));
  1609.  
  1610.             pszText = (PSZ)WinQueryWindowULong(hwndStatic, QWL_USER);
  1611.             if (pszText) {
  1612.                 WinQueryWindowRect(hwndStatic, &rcl);         // get window dimensions
  1613.                 // rcl.yTop = 1000;
  1614.                 memcpy(&rcl2, &rcl, sizeof(rcl));
  1615.  
  1616.                 winhDrawFormattedText(hps, &rcl, pszText, DT_LEFT | DT_TOP | DT_QUERYEXTENT);
  1617.                 WinEndPaint(hps);
  1618.  
  1619.                 if ((rcl.yTop - rcl.yBottom) < 40)
  1620.                     rcl.yBottom -= 40 - (rcl.yTop - rcl.yBottom);
  1621.  
  1622.                 // printfRtl("  Original rect:", &rcl2);
  1623.                 // printfRtl("  New rect:     ", &rcl);
  1624.  
  1625.                 // reposition the text
  1626.                 WinQueryWindowPos(hwndStatic, &swp);
  1627.                 swp.cy -= rcl.yBottom;
  1628.                 WinSetWindowPos(hwndStatic, 0,
  1629.                     swp.x, swp.y, swp.cx, swp.cy,
  1630.                     SWP_SIZE);
  1631.  
  1632.                 // reposition the icon
  1633.                 hwndIcon = WinWindowFromID(WinQueryWindow(hwndStatic, QW_PARENT),
  1634.                                 ID_XFDI_GENERICDLGICON);
  1635.                 WinQueryWindowPos(hwndIcon, &swp);
  1636.                 swp.y -= rcl.yBottom;
  1637.                 WinSetWindowPos(hwndIcon, 0,
  1638.                     swp.x, swp.y, swp.cx, swp.cy,
  1639.                     SWP_MOVE);
  1640.  
  1641.                 // resize the dlg frame window
  1642.                 hwndDlg = WinQueryWindow(hwndStatic, QW_PARENT);
  1643.                 WinQueryWindowPos(hwndDlg, &swp);
  1644.                 swp.cy -= rcl.yBottom;
  1645.                 swp.y  += (rcl.yBottom / 2);
  1646.                 WinInvalidateRect(hwndDlg, NULL, FALSE);
  1647.                 WinSetWindowPos(hwndDlg, 0,
  1648.                     swp.x, swp.y, swp.cx, swp.cy,
  1649.                     SWP_SIZE | SWP_MOVE);
  1650.             }
  1651.         break; }
  1652.  
  1653.         /*
  1654.          * WM_PAINT:
  1655.          *      draw the formatted text
  1656.          */
  1657.  
  1658.         case WM_PAINT: {
  1659.             RECTL   rcl;
  1660.             PSZ pszText = (PSZ)WinQueryWindowULong(hwndStatic, QWL_USER);
  1661.             HPS hps = WinBeginPaint(hwndStatic, NULLHANDLE, &rcl);
  1662.             if (pszText) {
  1663.                 WinQueryWindowRect(hwndStatic, &rcl);         // get window dimensions
  1664.                 // switch to RGB mode
  1665.                 GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL);
  1666.                 // set "static text" color
  1667.                 GpiSetColor(hps,
  1668.                         WinQuerySysColor(HWND_DESKTOP, SYSCLR_WINDOWSTATICTEXT, 0));
  1669.                 winhDrawFormattedText(hps, &rcl, pszText, DT_LEFT | DT_TOP);
  1670.             }
  1671.             WinEndPaint(hps);
  1672.         break; }
  1673.  
  1674.         case WM_DESTROY: {
  1675.             PSZ pszText = (PSZ)WinQueryWindowULong(hwndStatic, QWL_USER);
  1676.             free(pszText);
  1677.             mrc = (*pfnwpOrigStatic)(hwndStatic, msg, mp1, mp2);
  1678.         break; }
  1679.         default:
  1680.             mrc = (*pfnwpOrigStatic)(hwndStatic, msg, mp1, mp2);
  1681.     }
  1682.     return (mrc);
  1683. }
  1684.  
  1685. /*
  1686.  *@@ fnwpMessageBox:
  1687.  *      dlg proc for cmnMessageBox below
  1688.  */
  1689.  
  1690. MRESULT EXPENTRY fnwpMessageBox(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
  1691. {
  1692.     MRESULT mrc = NULL;
  1693.     switch (msg) {
  1694.         case WM_INITDLG: {
  1695.             // CHAR szFont[CCHMAXPATH];
  1696.             HWND hwndStatic = WinWindowFromID(hwndDlg,
  1697.                                 ID_XFDI_GENERICDLGTEXT);
  1698.  
  1699.             /* PrfQueryProfileString(HINI_USER, INIAPP_XFOLDER, INIKEY_DLGFONT,
  1700.                     "9.WarpSans", szFont, sizeof(szFont)-1);
  1701.             WinSetPresParam(hwndStatic, PP_FONTNAMESIZE,
  1702.                  (ULONG)strlen(szFont)+1, (PVOID)szFont); */
  1703.  
  1704.             // set string to 0
  1705.             WinSetWindowULong(hwndStatic, QWL_USER, (ULONG)NULL);
  1706.             pfnwpOrigStatic = WinSubclassWindow(hwndStatic,
  1707.                     fnwpAutoSizeStatic);
  1708.             mrc = fnwpDlgGeneric(hwndDlg, msg, mp1, mp2);
  1709.         break; }
  1710.  
  1711.         default:
  1712.             mrc = fnwpDlgGeneric(hwndDlg, msg, mp1, mp2);
  1713.         break;
  1714.     }
  1715.     return (mrc);
  1716. }
  1717.  
  1718. /*
  1719.  *@@ cmnMessageBox:
  1720.  *      this is the generic function for displaying XFolder
  1721.  *      message boxes. This is very similar to WinMessageBox,
  1722.  *      but a few new features are introduced:
  1723.  *      -- an XFolder icon is displayed;
  1724.  *      -- fonts can be dropped on the window, upon which the
  1725.  *         window will resize itself and store the font in OS2.INI.
  1726.  *
  1727.  *      Returns MBID_* codes like WinMessageBox.
  1728.  */
  1729.  
  1730. ULONG cmnMessageBox(HWND hwndOwner,     // in: owner
  1731.                     PSZ pszTitle,       // in: msgbox title
  1732.                     PSZ pszMessage,     // in: msgbox text
  1733.                     ULONG flStyle)      // in: MB_* flags
  1734. {
  1735.     HAB     hab = WinQueryAnchorBlock(hwndOwner);
  1736.     HMODULE hmod = NLS_MODULE;
  1737.     HWND    hwndDlg = NULLHANDLE, hwndStatic = NULLHANDLE;
  1738.     PSZ     pszButton = NULL;
  1739.     ULONG   ulrcDlg, ulrc = DID_CANCEL;
  1740.  
  1741.     REGREC2               RegRec2;
  1742.     ULONG                 ulExcpt;
  1743.     APIRET                rc;
  1744.  
  1745.     // set our extended exception handler
  1746.     RegRec2.pfnHandler = (PFN)excHandlerQuiet;
  1747.     if ( rc = DosSetExceptionHandler((PEXCEPTIONREGISTRATIONRECORD)&RegRec2) )
  1748.         DosBeep(100, 1000);
  1749.     // store a known thread state
  1750.     ulExcpt = setjmp(RegRec2.jmpThread);
  1751.     if (ulExcpt)
  1752.     {
  1753.         DosBeep(100, 1000);
  1754.     } else {
  1755.         ULONG flButtons = flStyle & 0xF;        // low nibble contains MB_YESNO etc.
  1756.  
  1757.         hwndDlg = WinLoadDlg(HWND_DESKTOP, hwndOwner,
  1758.                         fnwpMessageBox,
  1759.                         hmod,
  1760.                         ID_XFD_GENERICDLG,
  1761.                         NULL);
  1762.  
  1763.         hwndStatic = WinWindowFromID(hwndDlg, ID_XFDI_GENERICDLGTEXT);
  1764.  
  1765.         // now work on the three buttons of the dlg template:
  1766.         // give them proper titles or hide them
  1767.         if (flButtons == MB_YESNO) {
  1768.             cmnLoadString(hab, hmod, ID_XSSI_DLG_YES, &pszButton);
  1769.             WinSetDlgItemText(hwndDlg, 1, pszButton);
  1770.             cmnLoadString(hab, hmod, ID_XSSI_DLG_NO, &pszButton);
  1771.             WinSetDlgItemText(hwndDlg, 2, pszButton);
  1772.             winhShowDlgItem(hwndDlg, 3, FALSE);
  1773.             free(pszButton);
  1774.         }
  1775.         else if (flButtons == MB_OK) {
  1776.             cmnLoadString(hab, hmod, ID_XSSI_DLG_OK, &pszButton);
  1777.             WinSetDlgItemText(hwndDlg, 1, pszButton);
  1778.             winhShowDlgItem(hwndDlg, 2, FALSE);
  1779.             winhShowDlgItem(hwndDlg, 3, FALSE);
  1780.             free(pszButton);
  1781.         }
  1782.         else if (flButtons == MB_CANCEL) {
  1783.             cmnLoadString(hab, hmod, ID_XSSI_DLG_CANCEL, &pszButton);
  1784.             WinSetDlgItemText(hwndDlg, 1, pszButton);
  1785.             winhShowDlgItem(hwndDlg, 2, FALSE);
  1786.             winhShowDlgItem(hwndDlg, 3, FALSE);
  1787.             free(pszButton);
  1788.         }
  1789.         else if (flButtons == MB_OKCANCEL) {
  1790.             cmnLoadString(hab, hmod, ID_XSSI_DLG_OK, &pszButton);
  1791.             WinSetDlgItemText(hwndDlg, 1, pszButton);
  1792.             cmnLoadString(hab, hmod, ID_XSSI_DLG_CANCEL, &pszButton);
  1793.             WinSetDlgItemText(hwndDlg, 2, pszButton);
  1794.             winhShowDlgItem(hwndDlg, 3, FALSE);
  1795.             free(pszButton);
  1796.         }
  1797.         else if (flButtons == MB_RETRYCANCEL) {
  1798.             cmnLoadString(hab, hmod, ID_XSSI_DLG_RETRY, &pszButton);
  1799.             WinSetDlgItemText(hwndDlg, 1, pszButton);
  1800.             cmnLoadString(hab, hmod, ID_XSSI_DLG_CANCEL, &pszButton);
  1801.             WinSetDlgItemText(hwndDlg, 2, pszButton);
  1802.             winhShowDlgItem(hwndDlg, 3, FALSE);
  1803.             free(pszButton);
  1804.         }
  1805.         else if (flButtons == MB_ABORTRETRYIGNORE) {
  1806.             cmnLoadString(hab, hmod, ID_XSSI_DLG_ABORT, &pszButton);
  1807.             WinSetDlgItemText(hwndDlg, 1, pszButton);
  1808.             cmnLoadString(hab, hmod, ID_XSSI_DLG_RETRY, &pszButton);
  1809.             WinSetDlgItemText(hwndDlg, 2, pszButton);
  1810.             cmnLoadString(hab, hmod, ID_XSSI_DLG_IGNORE, &pszButton);
  1811.             WinSetDlgItemText(hwndDlg, 3, pszButton);
  1812.             free(pszButton);
  1813.         }
  1814.  
  1815.         if (flStyle & MB_DEFBUTTON2)
  1816.             WinSetWindowBits(WinWindowFromID(hwndDlg, 2), QWL_STYLE,
  1817.                     BS_DEFAULT,
  1818.                     1);
  1819.         else if (flStyle & MB_DEFBUTTON3)
  1820.             WinSetWindowBits(WinWindowFromID(hwndDlg, 3), QWL_STYLE,
  1821.                     BS_DEFAULT,
  1822.                     1);
  1823.         else
  1824.             WinSetWindowBits(WinWindowFromID(hwndDlg, 1), QWL_STYLE,
  1825.                     BS_DEFAULT,
  1826.                     1);
  1827.  
  1828.         WinSetWindowText(hwndDlg, pszTitle);
  1829.         WinSendMsg(hwndStatic, WM_SETLONGTEXT, pszMessage, MPNULL);
  1830.  
  1831.         winhCenterWindow(hwndDlg);
  1832.         if (flStyle & MB_SYSTEMMODAL)
  1833.             WinSetSysModalWindow(HWND_DESKTOP, hwndDlg);
  1834.         ulrcDlg = WinProcessDlg(hwndDlg);
  1835.         WinDestroyWindow(hwndDlg);
  1836.  
  1837.         if (flButtons == MB_YESNO)
  1838.             switch (ulrcDlg) {
  1839.                 case 1:     ulrc = MBID_YES; break;
  1840.                 default:    ulrc = MBID_NO;  break;
  1841.             }
  1842.         else if (flButtons == MB_OK)
  1843.             ulrc = MBID_OK;
  1844.         else if (flButtons == MB_CANCEL)
  1845.             ulrc = MBID_CANCEL;
  1846.         else if (flButtons == MB_OKCANCEL)
  1847.             switch (ulrcDlg) {
  1848.                 case 1:     ulrc = MBID_OK; break;
  1849.                 default:    ulrc = MBID_CANCEL;  break;
  1850.             }
  1851.         else if (flButtons == MB_RETRYCANCEL)
  1852.             switch (ulrcDlg) {
  1853.                 case 1:     ulrc = MBID_RETRY; break;
  1854.                 default:    ulrc = MBID_CANCEL;  break;
  1855.             }
  1856.         else if (flButtons == MB_ABORTRETRYIGNORE)
  1857.             switch (ulrcDlg) {
  1858.                 case 2:     ulrc = MBID_RETRY;  break;
  1859.                 case 3:     ulrc = MBID_IGNORE; break;
  1860.                 default:    ulrc = MBID_ABORT; break;
  1861.             }
  1862.     }
  1863.  
  1864.     DosUnsetExceptionHandler((PEXCEPTIONREGISTRATIONRECORD)&RegRec2);
  1865.  
  1866.     return (ulrc);
  1867. }
  1868.  
  1869. /*
  1870.  *@@ cmnGetMessage:
  1871.  *      like DosGetMessage, but automatically uses the
  1872.  *      (NLS) XFolder message file.
  1873.  *      The parameters are exactly like with DosGetMessage.
  1874.  */
  1875.  
  1876. APIRET cmnGetMessage(PCHAR *pTable,     // in: replacement PSZ table or NULL
  1877.                      ULONG ulTable,     // in: size of that table or 0
  1878.                      PSZ pszBuf,        // out: buffer to hold message string
  1879.                      ULONG cbBuf,       // in: size of pszBuf
  1880.                      ULONG ulMsgNumber) // in: msg number to retrieve
  1881. {
  1882.     PSZ     pszMessageFile = cmnQueryMessageFile();
  1883.     ULONG   ulReturned;
  1884.     BOOL    fCont = FALSE;
  1885.     APIRET  arc;
  1886.     arc = DosGetMessage(pTable, ulTable,
  1887.                         pszBuf, cbBuf,
  1888.                         ulMsgNumber, pszMessageFile, &ulReturned);
  1889.     pszBuf[ulReturned] = '\0';
  1890.  
  1891.     // remove trailing newlines
  1892.     do {
  1893.         PSZ p = pszBuf + strlen(pszBuf) - 1;
  1894.         if (    (*p == '\n')
  1895.              || (*p == '\r')
  1896.            )
  1897.         {
  1898.             *p = '\0';
  1899.             fCont = TRUE;
  1900.         } else
  1901.             fCont = FALSE;
  1902.     } while (fCont);
  1903.  
  1904.     return (arc);
  1905. }
  1906.  
  1907. /*
  1908.  *@@ cmnMessageBoxMsg:
  1909.  *      calls cmnMessageBox, but this one accepts ULONG indices
  1910.  *      into the XFolder message file (XFLDRxxx.MSG) instead
  1911.  *      of real PSZs. This calls cmnGetMessage for retrieving
  1912.  *      the messages, but placeholder replacement does not work
  1913.  *      here (use cmnMessageBoxMsgExt for that).
  1914.  */
  1915.  
  1916. ULONG cmnMessageBoxMsg(HWND hwndOwner,
  1917.                        ULONG ulTitle,       // in: msg index for dlg title
  1918.                        ULONG ulMessage,     // in: msg index for message
  1919.                        ULONG flStyle)       // in: like cmnMsgBox
  1920. {
  1921.     CHAR    szTitle[200], szMessage[2000];
  1922.  
  1923.     cmnGetMessage(NULL, 0,
  1924.             szTitle, sizeof(szTitle)-1,
  1925.             ulTitle);
  1926.     cmnGetMessage(NULL, 0,
  1927.             szMessage, sizeof(szMessage)-1,
  1928.             ulMessage);
  1929.  
  1930.     return (cmnMessageBox(hwndOwner, szTitle, szMessage, flStyle));
  1931. }
  1932.  
  1933. /*
  1934.  *@@ cmnMessageBoxMsgExt:
  1935.  *      like cmnMessageBoxMsg, but with string substitution
  1936.  *      (see cmnGetMessage for more); substitution only
  1937.  *      takes place for the message specified with ulMessage,
  1938.  *      not for the title.
  1939.  */
  1940.  
  1941. ULONG cmnMessageBoxMsgExt(HWND hwndOwner,   // in: owner window
  1942.                           ULONG ulTitle,    // in: msg number for title
  1943.                           PCHAR *pTable,    // in: replacement table for ulMessage
  1944.                           ULONG ulTable,    // in: sizeof *pTable
  1945.                           ULONG ulMessage,  // in: msg number for message
  1946.                           ULONG flStyle)    // in: msg box style flags (cmnMessageBox)
  1947. {
  1948.     CHAR    szTitle[200], szMessage[2000];
  1949.  
  1950.     cmnGetMessage(NULL, 0,
  1951.             szTitle, sizeof(szTitle)-1,
  1952.             ulTitle);
  1953.     cmnGetMessage(pTable, ulTable,
  1954.             szMessage, sizeof(szMessage)-1,
  1955.             ulMessage);
  1956.  
  1957.     return (cmnMessageBox(hwndOwner, szTitle, szMessage, flStyle));
  1958. }
  1959.  
  1960. /*
  1961.  *@@ cmnSetHelpPanel:
  1962.  *      sets help panel before calling fnwpDlgGeneric.
  1963.  */
  1964.  
  1965. VOID cmnSetHelpPanel(ULONG ulHelpPanel)
  1966. {
  1967.     ulCurHelpPanel = ulHelpPanel;
  1968. }
  1969.  
  1970. /*
  1971.  *@@  fnwpDlgGeneric:
  1972.  *          this is the dlg procedure for XFolder dlg boxes;
  1973.  *          it can process WM_HELP messages
  1974.  */
  1975.  
  1976. MRESULT EXPENTRY fnwpDlgGeneric(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1977. {
  1978.     HOBJECT hobjRef = 0;
  1979.     HWND    hwndItem;
  1980.     MRESULT mrc = NULL;
  1981.  
  1982.     switch (msg) {
  1983.         case WM_INITDLG:
  1984.             if (hwndItem = WinWindowFromID(hwnd, ID_XFDI_XFLDVERSION)) {
  1985.                 CHAR    szTemp[100];
  1986.                 WinQueryWindowText(hwndItem, sizeof(szTemp), szTemp);
  1987.                 strcpy(strstr(szTemp, "%a"), XFOLDER_VERSION);
  1988.                 WinSetWindowText(hwndItem, szTemp);
  1989.             }
  1990.             mrc = WinDefDlgProc(hwnd, msg, mp1, mp2);
  1991.         break;
  1992.  
  1993.         case WM_HELP: {
  1994.             // HMODULE hmodResource = cmnQueryNLSModuleHandle(FALSE);
  1995.             /* WM_HELP is received by this function when F1 or a "help" button
  1996.                is pressed in a dialog window. */
  1997.             if (ulCurHelpPanel > 0) {
  1998.                 WPObject    *pHelpSomSelf = _wpclsQueryActiveDesktop(_WPDesktop);
  1999.                 /* ulCurHelpPanel is set by instance methods before creating a
  2000.                    dialog box in order to link help topics to the displayed
  2001.                    dialog box. Possible values are:
  2002.                         0: open online reference ("<XFOLDER_REF>", INF book)
  2003.                       > 0: open help topic in xfldr.hlp
  2004.                        -1: ignore WM_HELP */
  2005.                 if (pHelpSomSelf) {
  2006.                     PSZ pszHelpLibrary;
  2007.                     BOOL fProcessed = FALSE;
  2008.                     if (pszHelpLibrary = cmnQueryHelpLibrary())
  2009.                         // path found: display help panel
  2010.                         if (_wpDisplayHelp(pHelpSomSelf, ulCurHelpPanel, pszHelpLibrary))
  2011.                             fProcessed = TRUE;
  2012.  
  2013.                     if (!fProcessed)
  2014.                         cmnMessageBoxMsg(HWND_DESKTOP, 104, 134, MB_OK);
  2015.                 }
  2016.             } else if (ulCurHelpPanel == 0)
  2017.             { // open online reference
  2018.                 ulCurHelpPanel = -1; // ignore further WM_HELP messages: this one suffices
  2019.                 hobjRef = WinQueryObject("<XFOLDER_REF>");
  2020.                 if (hobjRef) {
  2021.                     WinOpenObject(hobjRef, OPEN_DEFAULT, TRUE);
  2022.                 } else {
  2023.                     cmnMessageBoxMsg(HWND_DESKTOP, 104, 137, MB_OK);
  2024.  
  2025.                     /* WinDlgBox(HWND_DESKTOP,
  2026.                               hwnd,                     // destroy with first msg box
  2027.                               (PFNWP)fnwpDlgGeneric,
  2028.                               hmodResource, // load from resource file
  2029.                               ID_XFD_NOREF,             // dialog resource id
  2030.                               (PVOID)NULL);             // no dialog parameters
  2031.                               */
  2032.                 }
  2033.             } // end else; if ulCurHelpPanel is < 0, nothing happens
  2034.             mrc = NULL;
  2035.         break; } // end case WM_HELP
  2036.  
  2037.         default:
  2038.             mrc = WinDefDlgProc(hwnd, msg, mp1, mp2);
  2039.         break;
  2040.     }
  2041.  
  2042.     return (mrc);
  2043. }
  2044.  
  2045. /*-------------------------------------------------------------------
  2046.  *                                                                  *
  2047.  *   System sounds                                                  *
  2048.  *                                                                  *
  2049.  ********************************************************************/
  2050.  
  2051. /*
  2052.  *@@ cmnQuerySystemSound:
  2053.  *      this gets a system sound from the MMPM.INI file.
  2054.  *      usIndex must be the sound to query.
  2055.  *      Default system sounds:
  2056.  *      --  MMSOUND_WARNING         0
  2057.  *      --  MMSOUND_INFORMATION     1
  2058.  *      --  MMSOUND_ERROR           2
  2059.  *      --  MMSOUND_ANIMATEOPEN     3
  2060.  *      --  MMSOUND_ANIMATECLOSE    4
  2061.  *      --  MMSOUND_DRAG            5
  2062.  *      --  MMSOUND_DROP            6
  2063.  *      --  MMSOUND_SYSTEMSTARTUP   7
  2064.  *      --  MMSOUND_SHUTDOWN        8
  2065.  *      --  MMSOUND_SHREDDER        9
  2066.  *      --  MMSOUND_LOCKUP          10
  2067.  *      --  MMSOUND_ALARMCLOCK      11
  2068.  *      --  MMSOUND_PRINTERROR      12
  2069.  *
  2070.  *      New XFolder system sounds:
  2071.  *      --  MMSOUND_XFLD_SHUTDOWN   555
  2072.  *      --  MMSOUND_XFLD_RESTARTWPS 556
  2073.  *      --  MMSOUND_XFLD_SORT       557
  2074.  *
  2075.  *      The string buffers are recommended to be at least
  2076.  *      CCHMAXPATH in size.
  2077.  */
  2078.  
  2079. BOOL cmnQuerySystemSound(USHORT usIndex,    // in: sound index to query
  2080.                          PSZ pszDescr,      // out: address of buffer where to
  2081.                                 // copy the sound description to, as displayed
  2082.                                 // in the "Sound" object (may be NULL)
  2083.                          PSZ pszFile,
  2084.                                 // address adress of buffer where to copy the
  2085.                                 // sound file to (may be NULL)
  2086.                          PULONG pulVolume)
  2087.                                 // address of ULONG where to copy the volume
  2088.                                 // to (0-100). If the "Global volume" flag is
  2089.                                 // set in MMPM.INI, this will return the global
  2090.                                 // volume instead. May be NULL also.
  2091. {
  2092.     // We inline this func because it's only used once.
  2093.     HAB     habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
  2094.     HINI    hiniMMPM;
  2095.     CHAR    szMMPM[CCHMAXPATH];
  2096.     BOOL    rc = FALSE;
  2097.  
  2098.     #ifdef DEBUG_SOUNDS
  2099.         _Pmpf(("cmnQuerySystemSound index %d", usIndex));
  2100.     #endif
  2101.  
  2102.     sprintf(szMMPM, "%c:\\MMOS2\\MMPM.INI", doshQueryBootDrive());
  2103.  
  2104.     // _Pmpf(( "cmnQuerySystemSound: %s", szMMPM ));
  2105.     hiniMMPM = PrfOpenProfile(habDesktop, szMMPM);
  2106.     #ifdef DEBUG_SOUNDS
  2107.         _Pmpf(("  hiniMMPM: 0x%lX", hiniMMPM));
  2108.     #endif
  2109.     if (hiniMMPM) {
  2110.         CHAR szData[1000];
  2111.         CHAR szData2[100];
  2112.         CHAR szKey[10];
  2113.         sprintf(szKey, "%d", usIndex);
  2114.         PrfQueryProfileString(hiniMMPM,
  2115.                 MMINIKEY_SOUNDSETTINGS, "EnableSounds",
  2116.                 "TRUE",    // default string
  2117.                 szData2, sizeof(szData2));
  2118.         #ifdef DEBUG_SOUNDS
  2119.             _Pmpf(("  sounds enabled: %s", szData2));
  2120.         #endif
  2121.         if (strcmp(szData2, "TRUE") == 0)
  2122.             // sounds enabled at all?
  2123.             if (PrfQueryProfileString(hiniMMPM,
  2124.                     MMINIKEY_SYSSOUNDS, szKey,
  2125.                     ".",
  2126.                     szData, sizeof(szData)-1) > 3)
  2127.             {
  2128.                 // each key data has the following format:
  2129.                 // <soundfile>#<description>#<volume>
  2130.                 PSZ p1 = szData, p2;
  2131.  
  2132.                 p2 = strchr(p1, '#');
  2133.                 if (pszFile) {
  2134.                     strncpy(pszFile, p1, p2-p1);
  2135.                     pszFile[p2-p1] = '\0';
  2136.                     #ifdef DEBUG_SOUNDS
  2137.                         _Pmpf(("  found soundfile: %s", pszFile));
  2138.                     #endif
  2139.                 }
  2140.                 p1 = p2+1;
  2141.  
  2142.                 // _Pmpf(( "  %s", p1 ));
  2143.                 p2 = strchr(p1, '#');
  2144.                 if (pszDescr) {
  2145.                     strncpy(pszDescr, p1, p2-p1);
  2146.                     pszDescr[p2-p1] = '\0';
  2147.                 }
  2148.                 p1 = p2+1;
  2149.  
  2150.                 if (pulVolume) {
  2151.                     // if "global volume" has been enabled,
  2152.                     // we do not return the value specified
  2153.                     // here, but the global value
  2154.                     PrfQueryProfileString(hiniMMPM,
  2155.                             MMINIKEY_SOUNDSETTINGS, "ApplyVolumeToAll",
  2156.                             "FALSE",
  2157.                             szData2, sizeof(szData2));
  2158.                     if (strcmp(szData2, "FALSE") == 0) {
  2159.                         // individual volume settings per sound
  2160.                         p2 = strchr(p1, '#');
  2161.                         sscanf(p1, "%d", pulVolume);
  2162.                     } else {
  2163.                         // global volume setting for all sounds
  2164.                         PrfQueryProfileString(hiniMMPM,
  2165.                                 MMINIKEY_SOUNDSETTINGS, "Volume",
  2166.                                 "100",
  2167.                                 szData2, sizeof(szData2));
  2168.                         sscanf(szData2, "%d", pulVolume);
  2169.                     }
  2170.                 }
  2171.  
  2172.                 rc = TRUE;
  2173.             }
  2174.  
  2175.         PrfCloseProfile(hiniMMPM);
  2176.     }
  2177.  
  2178.     return (rc);
  2179. }
  2180.  
  2181. /*
  2182.  *@@ cmnSetSystemSound:
  2183.  *      this sets a system sound in MMPM.INI.
  2184.  *      See cmnQuerySystemSound for the parameters.
  2185.  */
  2186.  
  2187. BOOL cmnSetSystemSound(USHORT usIndex, PSZ pszDescr, PSZ pszFile, BYTE bVolume)
  2188. {
  2189.     HAB     habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);
  2190.     HINI    hiniMMPM;
  2191.     CHAR    szMMPM[CCHMAXPATH];
  2192.  
  2193.     sprintf(szMMPM, "%c\\MMOS2\\MMPM.INI", doshQueryBootDrive());
  2194.  
  2195.     hiniMMPM = PrfOpenProfile(habDesktop, szMMPM);
  2196.     if (hiniMMPM) {
  2197.         CHAR szData[1000];
  2198.         CHAR szKey[10];
  2199.         sprintf(szKey, "%d", usIndex);
  2200.         sprintf(szData, "%s#%s#%d", pszFile, pszDescr, bVolume);
  2201.         PrfWriteProfileString(hiniMMPM,
  2202.                 MMINIKEY_SYSSOUNDS, szKey,
  2203.                 szData);
  2204.         PrfCloseProfile(hiniMMPM);
  2205.         return (TRUE);
  2206.     }
  2207.     return (FALSE);
  2208. }
  2209.  
  2210.  
  2211.