Jump to content

Managing DOS Settings: Difference between revisions

From EDM2
123 (talk | contribs)
No edit summary
Ak120 (talk | contribs)
mNo edit summary
 
(8 intermediate revisions by 3 users not shown)
Line 1: Line 1:
Written by [[Roman Stangl]]
''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 [http://www.reocities.com/SiliconValley/Pines/7885/ PC/2] use to allow a user to specify the settings of VDM sessions) and when passing them to [[DosStartSession]]() or [[WinStartApp]]().


=== DOS Settings in OS/2 ===
== 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
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
[http://www.geocities.com/SiliconValley/Pines/7885/ PC/2] use to
allow a user to specify the settings of VDM sessions) and when passing
them to '''DosStartSession()''' or '''WinStartApp()'''.
<div style="overflow:auto; height: 1px; ">
[http://21jewelry.com Fine Jewelry]
[http://mrjeweller.us Gold Jewelry]
[http://detox-kit.com Drug detox]
[http://adipex.shengen.ru adipex]
[http://levitra.shengen.ru levitra]
[http://levitra.shengen.ru buy levitra]
[http://lortab.shengen.ru lortab]
[http://diazepam.shengen.ru diazepam]
[http://protonix.shengen.ru protonix]
[http://hydrocodone.shengen.ru hydrocodone]
[http://detox-kit.com/categories/marijuana-detox/ Marijuana detox]
[http://detox-kit.com/categories/detox-drinks/ Detox Drinks]
[http://detox-kit.com/categories/saliva-detox/ saliva drug detox]
[http://detox-kit.com/categories/saliva-detox/ saliva detox]
[http://detox-kit.com/categories/hair-detox/ hair detox]
[http://detox-kit.com/categories/hair-detox/ hair drug detox]
[http://tests-market.com/categories/first-aid/ first aid kit]
[http://tests-market.com/categories/drug-tests/ drug test]
[http://tests-market.com/categories/alcohol-tests/ alcohol test]
[http://tests-market.com/categories/ovulation-tests/ ovulation test]
[http://mrjeweller.us/categories/earrings/ earrings]
[http://mrjeweller.us/categories/earrings/ gold earrings]
[http://mrjeweller.us/categories/pearl-earrings/ pearl earrings]
[http://mrjeweller.us/categories/anklets/ anklet]
[http://mrjeweller.us/categories/cubic-zirconia/ cubic zirconia jewelry]
[http://mrjeweller.us/categories/mens-bracelets/ men's bracelet]
[http://mrjeweller.us/categories/mens-rings/ men's ring]
[http://mrjeweller.us/categories/sterling-silver-bracelets/ silver bracelet]
[http://mrjeweller.us/categories/sterling-silver-chains/ silver chains]
[http://mrjeweller.us/categories/anklets/ anklets]
[http://mrjeweller.us/categories/belly-piercings/ belly piercings]
[http://mrjeweller.us/categories/belly-piercings/ belly piercing]
[http://mrjeweller.us/categories/birthstones/ birthstone]
[http://mrjeweller.us/categories/birthstones/ birthstones]
[http://mrjeweller.us/categories/bracelets/ bracelets]
[http://mrjeweller.us/categories/bracelets/ bracelet]
[http://mrjeweller.us/categories/bracelets/ gold bracelet]
[http://mrjeweller.us/categories/bangle-bracelets/ bangle bracelet]
[http://mrjeweller.us/categories/rope-bracelets/ rope bracelets]
[http://mrjeweller.us/categories/rope-bracelets/ rope bracelet]
[http://mrjeweller.us/categories/chains/ gold chains]
[http://mrjeweller.us/categories/chains/ gold chain]
[http://mrjeweller.us/categories/beaded-chains/ beaded chains]
[http://mrjeweller.us/categories/charms/ charms]
[http://mrjeweller.us/categories/diamond-pendants/ diamond pendants]
[http://mrjeweller.us/categories/diamond-pendants/ diamond pendant]
[http://toe.shengen.ru toe rings]
[http://detox.shengen.ru drug detox]
[http://jewelry.shengen.ru fine gold jewelry]
</div>
=== 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:
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.


  char *pcSettings="DPMI_MEMORY_LIMIT=16\0"
== Displaying the DOS Settings dialog ==
                  "EMS_MEMORY_LIMIT=0\0XMS_MEMORY_LIMIT=64\0";
The DOS Settings dialog can be displayed by loading and calling entrypoint '''11''' from the VDM support DLL [[PMVDMP.DLL|PMVDMP]].
 
PFFUNCPTR    *pWindows32PropertyDialog;
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)
if(DosLoadModule(ucBuffer, sizeof(ucBuffer)-1, "PMVDMP", &hDllPMVDMP)==NO_ERROR)
      DosQueryProcAddr(hDllPMVDMP, 11, NULL, (PFN *)(&pWindows32PropertyDialog));
    DosQueryProcAddr(hDllPMVDMP, 11, NULL, (PFN *)(&pWindows32PropertyDialog));
 
The function prototype of that entrypoint is:
The function prototype of that entrypoint is:
 
typedef PCH (EXPENTRY PFFUNCPTR) (HWND hwndClient, HWND hwnd, PSZ pcIn, USHORT usIn,\
  typedef PCH (EXPENTRY PFFUNCPTR) (HWND hwndClient, HWND hwnd, PSZ pcIn, USHORT usIn,\
                                  USHORT *pusOut, USHORT *pusWinMode);
                                    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:
 
<code>
Assuming that you are using a multiline entryfield to specify the DOS
UCHAR        *pucSettingsIn;
Settings you have to convert the string returned by the MLE, where
UCHAR        *pucSettingsOut;
individual settings are terminated by '''\r\n''', to the DOS Settings format before
USHORT        usLength, usWinMode=1;
calling the entrypoint:
ULONG        ulLength;
 
  UCHAR        *pucSettingsIn;
  UCHAR        *pucSettingsOut;
  USHORT        usLength, usWinMode=1;
  ULONG        ulLength;
   
   
                                        /* Get current listbox data length */
                                      /* Get current listbox data length */
  ulLength=(ULONG)WinQueryWindowTextLength(
ulLength=(ULONG)WinQueryWindowTextLength(
      WinWindowFromID(nbPINotebookPage[PI_PAGE_1].hwndNBPage,
    WinWindowFromID(nbPINotebookPage[PI_PAGE_1].hwndNBPage,
      PIMLE_DOSSETTINGS));
    PIMLE_DOSSETTINGS));
                                        /* Get current DOS settings or at least a
                                      /* Get current DOS settings or at least a
                                          NULL string */
                                          NULL string */
  if(ulLength==0)
if(ulLength==0)
      ulLength=1;
    ulLength=1;
  pucSettingsOut=malloc(ulLength);
pucSettingsOut=malloc(ulLength);
  WinQueryWindowText(                  /* Query data entered in DOS Settings MLE */
WinQueryWindowText(                  /* Query data entered in DOS Settings MLE */
      WinWindowFromID(nbPINotebookPage[PI_PAGE_1].hwndNBPage, PIMLE_DOSSETTINGS),
    WinWindowFromID(nbPINotebookPage[PI_PAGE_1].hwndNBPage, PIMLE_DOSSETTINGS),
      ulLength, pucSettingsOut);
    ulLength, pucSettingsOut);
                                        /* Convert to format used by
                                      /* Convert to format used by
                                          WINDOWS32PROPERTYDIALOG */
                                          WINDOWS32PROPERTYDIALOG */
  pucSettingsIn=ImportDosSettings(pucSettingsOut, &ulLength, FALSE);
pucSettingsIn=ImportDosSettings(pucSettingsOut, &ulLength, FALSE);
                                        /* Free data read from DOS Settings MLE */
                                      /* Free data read from DOS Settings MLE */
  free(pucSettingsOut);
free(pucSettingsOut);
                                        /* Call DOS Settings dialog by passing DOS
                                      /* Call DOS Settings dialog by passing DOS
                                          Settings MLE data \0\0 terminated and
                                          Settings MLE data \0\0 terminated and
                                          expect a \0\0 terminated shared memory
                                          expect a \0\0 terminated shared memory
                                          address containing the user changes */
                                          address containing the user changes */
  pucSettingsOut=pWindows32PropertyDialog(
pucSettingsOut=pWindows32PropertyDialog(
      hwndDlg,                          /* Parent window handle ? */
    hwndDlg,                          /* Parent window handle ? */
      hwndDlg,                          /* Owner window handle ? */
    hwndDlg,                          /* Owner window handle ? */
      pucSettingsIn,                    /* In-buffer containing DOS settings */
    pucSettingsIn,                    /* In-buffer containing DOS settings */
      (USHORT)ulLength,                /* Length of in-buffer containing DOS settings */
    (USHORT)ulLength,                /* Length of in-buffer containing DOS settings */
      &usLength,                        /* Length of out-buffer containing modified
    &usLength,                        /* Length of out-buffer containing modified
                                          DOS settings, allocated by DosAllocateMem() */
                                          DOS settings, allocated by DosAllocateMem() */
      &usWinMode);                      /* 0 if no WIN-OS2 settings are included
    &usWinMode);                      /* 0 if no WIN-OS2 settings are included
                                          1 if WIN-OS2 settings are included */
                                          1 if WIN-OS2 settings are included */
 
</code>
Once the DOS Settings dialog returns, it has allocated memory where the
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:
modified DOS Settings are returned. Again, the DOS Settings format has to
<code>
be converted into a format acceptable by the MLE:
if(pucSettingsIn) free(pucSettingsIn);
 
if(pucSettingsOut!=NULL)              /* NULL returned when Cancel was pressed */
  if(pucSettingsIn) free(pucSettingsIn);
    {
  if(pucSettingsOut!=NULL)              /* NULL returned when Cancel was pressed */
    ulLength=(ULONG)usLength;
      {
                                      /* Convert to format used PC/2 configuration
      ulLength=(ULONG)usLength;
                                          file and Program Installation dialog */
                                        /* Convert to format used PC/2 configuration
    pucSettingsIn=ImportDosSettings(pucSettingsOut, &ulLength, TRUE);
                                          file and Program Installation dialog */
    DosFreeMem(pucSettingsOut);
      pucSettingsIn=ImportDosSettings(pucSettingsOut, &ulLength, TRUE);
                                      /* Insert data in DOS Settings MLE */
      DosFreeMem(pucSettingsOut);
    WinSetWindowText(WinWindowFromID(nbPINotebookPage[PI_PAGE_1].hwndNBPage,
                                        /* Insert data in DOS Settings MLE */
        PIMLE_DOSSETTINGS), pucSettingsIn);
      WinSetWindowText(WinWindowFromID(nbPINotebookPage[PI_PAGE_1].hwndNBPage,
    free(pucSettingsIn);
          PIMLE_DOSSETTINGS), pucSettingsIn);
    }
      free(pucSettingsIn);
DosFreeModule(hDllPMVDMP);            /* Free DLL reference */
      }
</code>
  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:


==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:
<code>
  /*--------------------------------------------------------------------------------------*\
  /*--------------------------------------------------------------------------------------*\
   * This procedure converts DOS settings used in the configuration file and Program      *
   * This procedure converts DOS settings used in the configuration file and Program      *
Line 165: Line 86:
   *      pucSettings ... Pointer to the DOS Settings                                    *
   *      pucSettings ... Pointer to the DOS Settings                                    *
   *      pulLength ..... Length of the DOS Settings buffer pucSettings on entry/exit    *
   *      pulLength ..... Length of the DOS Settings buffer pucSettings on entry/exit    *
   *      bImport ....... TRUE if we convert data retured by WINDOWS32PROPERTYDIALOG     *
   *      bImport ....... TRUE if we convert data returned by WINDOWS32PROPERTYDIALOG     *
   *                      FALSE if we convert data into WINDOWS32PROPERTYDIALOG format    *
   *                      FALSE if we convert data into WINDOWS32PROPERTYDIALOG format    *
   * Ret:                                                                                *
   * Ret:                                                                                *
   *      pucBuffer ..... Buffer when successfull containing the converted DOS Settings   *
   *      pucBuffer ..... Buffer when successfully containing the converted DOS Settings *
   *                      NULL on error                                                  *
   *                      NULL on error                                                  *
   *                      This buffer is allocated as required by ImportDosSettings().    *
   *                      This buffer is allocated as required by ImportDosSettings().    *
   * Ref:                                                                                *
   * Ref:                                                                                *
   *      &ltstring&gt\n&ltstring&gt\n&ltstring&gt           Format of a DOS setting that contains  *
   *      <string>\n<string>\n<string>           Format of a DOS setting that contains  *
   *                                              more than one entry, e.g. DOS_VERSION  *
   *                                              more than one entry, e.g. DOS_VERSION  *
   *      &ltstring&gt\0h                            One complete DOS setting, whereby      *
   *      <string>\0h                            One complete DOS setting, whereby      *
   *                                              &ltstring&gt may of the above format        *
   *                                              <string> may of the above format        *
   *      \0h\0h                                  End of DOS settings buffer              *
   *      \0h\0h                                  End of DOS settings buffer              *
  \*--------------------------------------------------------------------------------------*/
  \*--------------------------------------------------------------------------------------*/
Line 189: Line 110:
                                         /* Count all \0 characters */
                                         /* Count all \0 characters */
       for(ulIndex=0, ulCounter=0, pucChar=pucSettings;
       for(ulIndex=0, ulCounter=0, pucChar=pucSettings;
           ulIndex&lt*pulLength;
           ulIndex<*pulLength;
           ulIndex++, pucChar++)
           ulIndex++, pucChar++)
           if(*pucChar=='\0') ulCounter++;
           if(*pucChar=='\0') ulCounter++;
Line 199: Line 120:
                                             by *. Reserve last char for terminating \0 */
                                             by *. Reserve last char for terminating \0 */
       for(ulIndex=0, pucChar=pucBuffer;
       for(ulIndex=0, pucChar=pucBuffer;
           ulIndex+1&lt*pulLength;
           ulIndex+1<*pulLength;
           ulIndex++, pucChar++, pucSettings++)
           ulIndex++, pucChar++, pucSettings++)
           {
           {
Line 218: Line 139:
                                         /* Count all \r characters */
                                         /* Count all \r characters */
       for(ulIndex=0, ulCounter=0, pucChar=pucSettings;
       for(ulIndex=0, ulCounter=0, pucChar=pucSettings;
           ulIndex&lt*pulLength;
           ulIndex<*pulLength;
           ulIndex++, pucChar++)
           ulIndex++, pucChar++)
           if(*pucChar=='\r') ulCounter++;
           if(*pucChar=='\r') ulCounter++;
Line 235: Line 156:
                                             termination */
                                             termination */
       for(ulIndex=2, pucChar=pucBuffer;
       for(ulIndex=2, pucChar=pucBuffer;
           ulIndex&lt*pulLength;
           ulIndex<*pulLength;
           ulIndex++, pucChar++, pucSettings++)
           ulIndex++, pucChar++, pucSettings++)
           {
           {
Line 250: Line 171:
   return(pucBuffer);
   return(pucBuffer);
   }
   }
 
</code>
In the above function you may note that we also check for an asterisk (*).
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:
This allows me to represent DOS Settings that may consist of multiple
DOS_VERSION=EXE2BIN.EXE,5,02,255*MSD.EXE,5,00,255
lines understandable to the user in the MLE. For example, DOS_VERSION may
IDLE_SENSITIVITY=100
be displayed as:
IDLE_SECONDS=5
 
  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:
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_VERSION=EXE2BIN.EXE,5,02,255\nMSD.EXE,5,00,255\0"
== DOS Settings and launching DOS Sessions ==
  "IDLE_SENSITIVITY=100\0IDLE_SECONDS=5\0"
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).
 
=== 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;
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()''':
  UCHAR        *pucDosSettings;
<code>
ULONG        ulLength=strlen(pSessionData->PgmDosSettings)+1;
UCHAR        *pucDosSettings;
   
   
                                         /* Convert to format used by OS/2 in environment
                                         /* Convert to format used by OS/2 in environment
Line 287: Line 192:
                                           WINDOWS32PROPERTYDIALOG) */
                                           WINDOWS32PROPERTYDIALOG) */
   pucDosSettings=ImportDosSettings(pSessionData->PgmDosSettings, &ulLength, FALSE);
   pucDosSettings=ImportDosSettings(pSessionData->PgmDosSettings, &ulLength, FALSE);
 
</code>
Depending on the API used, you pass the DOS Settings to '''DosStartSession()''' as:
Depending on the API used, you pass the DOS Settings to '''DosStartSession()''' as:
 
StartData.Environment=pucDosSettings;
  StartData.Environment=pucDosSettings;
 
or for '''WinStartApp()''' as:
or for '''WinStartApp()''' as:
ProgDetails.pszEnvironment=StartData.Environment;
One additional word about WIN-OS2 sessions. Though you can start full-screen 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 [http://www.reocities.com/SiliconValley/Pines/7885/ PC/2] application.


  ProgDetails.pszEnvironment=StartData.Environment;
==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.
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 [http://www.geocities.com/SiliconValley/Pines/7885/ PC/2]
application.
 
=== Credits ===


Thanks to Monte Copeland, the author of TSHELL and MSHELL, for telling me
[[Category:Languages Articles]]
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.

Latest revision as of 22:04, 10 October 2022

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 returned by WINDOWS32PROPERTYDIALOG     *
 *                      FALSE if we convert data into WINDOWS32PROPERTYDIALOG format    *
 * Ret:                                                                                 *
 *      pucBuffer ..... Buffer when successfully 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<*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<*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<*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<*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 full-screen 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.