Managing DOS Settings

From EDM2
Jump to: navigation, search

Written by Roman Stangl

DOS Settings in OS/2

Under the protected mode of OS/2, DOS Settings cross your way most likely in form of the DOS Settings dialog (which the WPS and applications like PC/2 use to allow a user to specify the settings of VDM sessions) and when passing them to DosStartSession() or WinStartApp().

The layout of DOS Settings

When using DOS Settings, a notation similar to the process' environment obtainable from the PIB (Process Information Block) is used, that is individual entries are terminated by a \0 and the complete block is terminated by an additional \0. In C/C++ you would specify for example:

 char *pcSettings="DPMI_MEMORY_LIMIT=16\0"
                  "EMS_MEMORY_LIMIT=0\0XMS_MEMORY_LIMIT=64\0";

Most importantly, you have to be cautious when using C runtime functions like strcpy(), because the end of C strings will be indicated by the first \0 and not by the \0\0 which terminated a DOS Settings string.

Displaying the DOS Settings dialog

The DOS Settings dialog can be displayed by loading and calling entrypoint 11 from the VDM support DLL PMVDMP

 PFFUNCPTR    *pWindows32PropertyDialog;

 if(DosLoadModule(ucBuffer, sizeof(ucBuffer)-1, "PMVDMP", &hDllPMVDMP)==NO_ERROR)
     DosQueryProcAddr(hDllPMVDMP, 11, NULL, (PFN *)(&pWindows32PropertyDialog));

The function prototype of that entrypoint is:

 typedef PCH (EXPENTRY PFFUNCPTR) (HWND hwndClient, HWND hwnd, PSZ pcIn, USHORT usIn,\
                                   USHORT *pusOut, USHORT *pusWinMode);

Assuming that you are using a multiline entryfield to specify the DOS Settings you have to convert the string returned by the MLE, where individual settings are terminated by \r\n, to the DOS Settings format before calling the entrypoint:

 UCHAR        *pucSettingsIn;
 UCHAR        *pucSettingsOut;
 USHORT        usLength, usWinMode=1;
 ULONG         ulLength;

                                       /* Get current listbox data length */
 ulLength=(ULONG)WinQueryWindowTextLength(
     WinWindowFromID(nbPINotebookPage[PI_PAGE_1].hwndNBPage,
     PIMLE_DOSSETTINGS));
                                       /* Get current DOS settings or at least a
                                          NULL string */
 if(ulLength==0)
     ulLength=1;
 pucSettingsOut=malloc(ulLength);
 WinQueryWindowText(                   /* Query data entered in DOS Settings MLE */
     WinWindowFromID(nbPINotebookPage[PI_PAGE_1].hwndNBPage, PIMLE_DOSSETTINGS),
     ulLength, pucSettingsOut);
                                       /* Convert to format used by
                                          WINDOWS32PROPERTYDIALOG */
 pucSettingsIn=ImportDosSettings(pucSettingsOut, &ulLength, FALSE);
                                       /* Free data read from DOS Settings MLE */
 free(pucSettingsOut);
                                       /* Call DOS Settings dialog by passing DOS
                                          Settings MLE data \0\0 terminated and
                                          expect a \0\0 terminated shared memory
                                          address containing the user changes */
 pucSettingsOut=pWindows32PropertyDialog(
     hwndDlg,                          /* Parent window handle ? */
     hwndDlg,                          /* Owner window handle ? */
     pucSettingsIn,                    /* In-buffer containing DOS settings */
     (USHORT)ulLength,                 /* Length of in-buffer containing DOS settings */
     &usLength,                        /* Length of out-buffer containing modified
                                          DOS settings, allocated by DosAllocateMem() */
     &usWinMode);                      /* 0 if no WIN-OS2 settings are included
                                          1 if WIN-OS2 settings are included */

Once the DOS Settings dialog returns, it has allocated memory where the modified DOS Settings are returned. Again, the DOS Settings format has to be converted into a format acceptable by the MLE:

 if(pucSettingsIn) free(pucSettingsIn);
 if(pucSettingsOut!=NULL)              /* NULL returned when Cancel was pressed */
     {
     ulLength=(ULONG)usLength;
                                       /* Convert to format used PC/2 configuration
                                          file and Program Installation dialog */
     pucSettingsIn=ImportDosSettings(pucSettingsOut, &ulLength, TRUE);
     DosFreeMem(pucSettingsOut);
                                       /* Insert data in DOS Settings MLE */
     WinSetWindowText(WinWindowFromID(nbPINotebookPage[PI_PAGE_1].hwndNBPage,
         PIMLE_DOSSETTINGS), pucSettingsIn);
     free(pucSettingsIn);
     }
 DosFreeModule(hDllPMVDMP);            /* Free DLL reference */

Converting from and to the DOS Settings format

As said previously, DOS Settings use a format which isn't comfortable handled by C runtime functions. The function ImportDosSettings() does perform the required conversions:

/*--------------------------------------------------------------------------------------*\
 * This procedure converts DOS settings used in the configuration file and Program      *
 * Installation dialog to the format required by the WINDOWS32PROPERTYDIALOG in the     *
 * OS/2 PMVDMP.DLL.                                                                     *
 * Req:                                                                                 *
 *      pucSettings ... Pointer to the DOS Settings                                     *
 *      pulLength ..... Length of the DOS Settings buffer pucSettings on entry/exit     *
 *      bImport ....... TRUE if we convert data retured by WINDOWS32PROPERTYDIALOG      *
 *                      FALSE if we convert data into WINDOWS32PROPERTYDIALOG format    *
 * Ret:                                                                                 *
 *      pucBuffer ..... Buffer when successfull containing the converted DOS Settings   *
 *                      NULL on error                                                   *
 *                      This buffer is allocated as required by ImportDosSettings().    *
 * Ref:                                                                                 *
 *      <string>\n<string>\n<string>            Format of a DOS setting that contains   *
 *                                              more than one entry, e.g. DOS_VERSION   *
 *      <string>\0h                             One complete DOS setting, whereby       *
 *                                              <string> may of the above format        *
 *      \0h\0h                                  End of DOS settings buffer              *
\*--------------------------------------------------------------------------------------*/
  UCHAR   *ImportDosSettings(UCHAR *pucSettings, ULONG *pulLength, BOOL bImport)
  {
  UCHAR  *pucBuffer;                    /* Return buffer */
  UCHAR  *pucChar;
  ULONG   ulIndex;
  ULONG   ulCounter;

  if(bImport==TRUE)
      {
                                        /* Count all \0 characters */
      for(ulIndex=0, ulCounter=0, pucChar=pucSettings;
          ulIndex&lt*pulLength;
          ulIndex++, pucChar++)
          if(*pucChar=='\0') ulCounter++;
      *pulLength+=++ulCounter;          /* Double because all \0 are replaced by \r\n
                                           which is CRLF, and add \0 termination */
      pucBuffer=malloc(*pulLength);     /* Allocate return buffer */
                                        /* Copy DOS settings into return buffer by
                                           replacing \0 by \r\n (CRLF), replace \n
                                           by *. Reserve last char for terminating \0 */
      for(ulIndex=0, pucChar=pucBuffer;
          ulIndex+1&lt*pulLength;
          ulIndex++, pucChar++, pucSettings++)
          {
          if(*pucSettings=='\n') *pucChar='*';
          else if(*pucSettings=='\0')
              {
              *pucChar++='\r';
              *pucChar='\n';
              ulIndex++;
              }
          else
              *pucChar=*pucSettings;
          }
      *pucChar='\0';                    /* Zero termination */
      }
  else
      {
                                        /* Count all \r characters */
      for(ulIndex=0, ulCounter=0, pucChar=pucSettings;
          ulIndex&lt*pulLength;
          ulIndex++, pucChar++)
          if(*pucChar=='\r') ulCounter++;
      (*pulLength)-=++ulCounter;        /* Half because all \r\n (CRLF) are replaced
                                           by \0, remove trailing \0 termination */
      if(!*pulLength) return(NULL);
                                        /* Add 2 to ensure to terminate DOS settings
                                           with \0\0 */
      (*pulLength)+=2;
      pucBuffer=malloc(*pulLength);     /* Allocate return buffer */
                                        /* Ensure \0\0 termination */
      memset(pucBuffer, '\0', *pulLength);
                                        /* Copy DOS settings into return buffer by
                                           replacing \r\n by \0 and * by \n, start
                                           with index 2 to keep place for \0\0
                                           termination */
      for(ulIndex=2, pucChar=pucBuffer;
          ulIndex&lt*pulLength;
          ulIndex++, pucChar++, pucSettings++)
          {
          if(*pucSettings=='*') *pucChar='\n';
          else if(*pucSettings=='\r')
              {
              *pucChar='\0';
              pucSettings++;
              }
          else
              *pucChar=*pucSettings;
          }
      }
  return(pucBuffer);
  }

In the above function you may note that we also check for an asterisk (*). This allows me to represent DOS Settings that may consist of multiple lines understandable to the user in the MLE. For example, DOS_VERSION may be displayed as:

 DOS_VERSION=EXE2BIN.EXE,5,02,255*MSD.EXE,5,00,255
 IDLE_SENSITIVITY=100
 IDLE_SECONDS=5

where the DOS Setting C string equivalent would be:

 "DOS_VERSION=EXE2BIN.EXE,5,02,255\nMSD.EXE,5,00,255\0"
 "IDLE_SENSITIVITY=100\0IDLE_SECONDS=5\0"

DOS Settings and launching DOS Sessions

Showing how to allow a user specifying DOS Settings with the standard OS/2 DOS Settings dialog is only half of the way to full DOS support, we're still missing how to specify DOS Settings when launching DOS executables (which of course includes WIN-OS2).

Though it is simple once one knows how, the DOS and PM programming references still don't specify that, but try to fool you with reserved fields. Fortunately it's quite easy, as ImportDosSettings() can be used once again to convert the DOS Settings. And as many of you may have anticipated, DOS Settings are specified for VDM sessions in the STARTDATA.Environment field for DosStartSession() and PROGDETAILS.pszEnvironment for WinStartApp():

 ULONG         ulLength=strlen(pSessionData->PgmDosSettings)+1;
 UCHAR        *pucDosSettings;

                                       /* Convert to format used by OS/2 in environment
                                          of session to start (same as used for
                                          WINDOWS32PROPERTYDIALOG) */
 pucDosSettings=ImportDosSettings(pSessionData->PgmDosSettings, &ulLength, FALSE);

Depending on the API used, you pass the DOS Settings to DosStartSession() as:

 StartData.Environment=pucDosSettings;

or for WinStartApp() as:

 ProgDetails.pszEnvironment=StartData.Environment;

One additional word about WIN-OS2 sessions. Though you can start fullscreen and seamless WIN-OS2 sessions with DosStartSession it is recommended to use WinStartApp() instead, because only the later API honours requests to start a WIN-OS2 application into an already running common WIN-OS2 session (program types PROG_31_STDSEAMLESSCOMMON and PROG_31_ENHSEAMLESSCOMMON). If you're more interested about starting WIN-OS2 sessions from an OS/2 program, you may take a look into the source of my PC/2 application.

Credits

Thanks to Monte Copeland, the author of TSHELL and MSHELL, for telling me about the undocumented entrypoint of the DOS Settings dialog. Passing DOS Settings to OS/2 API is based on some experiments influenced by discussions on Netnews and on IBMPC conference disk.