Managing DOS Settings: Difference between revisions
mNo edit summary |
mNo edit summary |
||
(4 intermediate revisions by the same user not shown) | |||
Line 2: | Line 2: | ||
== DOS Settings in OS/2 == | == 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 | 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]](). | ||
== The layout of DOS Settings == | == 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 | 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''' | 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. | ||
which terminated a DOS Settings string. | |||
== Displaying the DOS Settings dialog == | == Displaying the DOS Settings dialog == | ||
The DOS Settings dialog can be displayed by loading and calling entrypoint '''11''' from the VDM support DLL | The DOS Settings dialog can be displayed by loading and calling entrypoint '''11''' from the VDM support DLL [[PMVDMP.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: | 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: | 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> | |||
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 */ | |||
</code> | |||
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: | 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: | ||
<code> | |||
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 */ | |||
</code> | |||
==Converting from and to the DOS Settings format== | ==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: | 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 82: | 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 | * 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 | * 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(). * | ||
Line 106: | 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 | ulIndex<*pulLength; | ||
ulIndex++, pucChar++) | ulIndex++, pucChar++) | ||
if(*pucChar=='\0') ulCounter++; | if(*pucChar=='\0') ulCounter++; | ||
Line 116: | 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 | ulIndex+1<*pulLength; | ||
ulIndex++, pucChar++, pucSettings++) | ulIndex++, pucChar++, pucSettings++) | ||
{ | { | ||
Line 135: | 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 | ulIndex<*pulLength; | ||
ulIndex++, pucChar++) | ulIndex++, pucChar++) | ||
if(*pucChar=='\r') ulCounter++; | if(*pucChar=='\r') ulCounter++; | ||
Line 152: | Line 156: | ||
termination */ | termination */ | ||
for(ulIndex=2, pucChar=pucBuffer; | for(ulIndex=2, pucChar=pucBuffer; | ||
ulIndex | ulIndex<*pulLength; | ||
ulIndex++, pucChar++, pucSettings++) | ulIndex++, pucChar++, pucSettings++) | ||
{ | { | ||
Line 167: | Line 171: | ||
return(pucBuffer); | return(pucBuffer); | ||
} | } | ||
</code> | |||
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: | 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: | 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 == | == DOS Settings and launching DOS Sessions == | ||
Line 179: | Line 184: | ||
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()''': | 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()''': | ||
<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 186: | 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; | |||
or for '''WinStartApp()''' as: | or for '''WinStartApp()''' as: | ||
ProgDetails.pszEnvironment=StartData.Environment; | |||
One additional word about WIN-OS2 sessions. Though you can start | 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. | ||
==Credits== | ==Credits== |
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.