|
|
Microsoft OS/2 SDK 2.0 05-30-1990
/*==================================================================*\
* Vmm_user.c - routines for handling messages not processed *
* by the standard message processing routine *
* Created 1990, Microsoft, IBM Corp. *
*------------------------------------------------------------------*
* *
* This module contains the code for processing messages sent *
* to the standard window that the standard window does not *
* process. The application developer need only modify this *
* file in order to implement new menu items or process *
* messages not handled by the standard message routine. *
* *
* This module also contains some routines that demonstate the *
* various dialog box controls and message box types that can *
* be used. The sample code should be deleted when this *
* module is modified for an application. The demonstration *
* code is identified by comments. *
* *
*------------------------------------------------------------------*
* *
* This source file contains the following functions: *
* *
* UserWndProc(hwnd, msg, mp1, mp2) - user window procedure *
* UserCommand(mp1, mp2) - user WM_COMMAND processor *
* VMM_Error(pszFunction, ulErrorCode) - Error processing *
* CleanUpArray(pvAddress) - Page table maintenance *
* StoreInArray(pvAddress, ulNumPages) - Page table maintenance*
* *
\*==================================================================*/
/*------------------------------------------------------------------*\
* Include files, macros, defined constants, and externs *
\*------------------------------------------------------------------*/
#define LINT_ARGS
#define INCL_WIN
#define INCL_DOSPROCESS
#define INCL_DOSERRORS
#include <os2.h>
#include "stdio.h"
#include "vmm_main.h"
#include "vmm_dlg.h"
#include "vmm_xtrn.h"
#include "string.h"
extern ULONG clrBackground, clrForeground;
/*--------------------------------------------------------------*\
* Global variables *
\*--------------------------------------------------------------*/
ULONG ulFreePage = 0L; /* First free page entry in array */
PAGEENTRY apgentry[MAXPAGES]; /* Application page table */
OBJSTRUCT ObjAlloc;
char szBuffer[BUFF_SIZE];
MSGENTRY amsgentry[] =
{
{ ERROR_INVALID_PARAMETER,
"%s\n\nInvalid Parameter",
MB_ICONASTERISK
},
{ ERROR_ACCESS_DENIED,
"%s\n\nAccess to Memory Denied",
MB_ICONASTERISK
},
{ ERROR_NOT_ENOUGH_MEMORY,
"%s\n\nInsufficient Memory",
MB_ICONASTERISK
},
{ ERROR_INVALID_ACCESS,
"%s\n\nAn Invalid access to memory was"
" attempted.",
MB_ICONASTERISK
},
{ ERROR_INVALID_ADDRESS,
"%s\n\nAddress Given is Invalid",
MB_ICONASTERISK
},
{ ERROR_INTERRUPT,
"%s\n\nThe call was interrupted by an external"
" event and was not completed. Please retry the"
" operation.",
MB_ICONASTERISK
},
/* Errors following are application defined */
{ VMERR_MAX_ALLOCATED,
"%s\n\nThe allocation has surpassed"
" this application's maximum number of displayable"
" pages of %u. Each page contains 4096 bytes"
" of data.",
MB_ICONASTERISK
},
{ VMERR_ZERO_ALLOCATED,
"%s\n\nA minimum of 1 byte must be specified for"
" an allocation.",
MB_ICONASTERISK
},
{ VMERR_TILE_ONLY,
"%s\n\nAllocation attempted with"
" tiled attribute and no access"
" protection specifed. Access protection required to"
" properly allocate memory.",
MB_ICONASTERISK
},
{ VMERR_COMMIT_AND_TILE_ONLY,
"%s\n\nAllocation attempted with no access"
" protection specified. Access protection required to"
" properly allocate memory.",
MB_ICONASTERISK
},
{ VMERR_ALREADY_FREED,
"%s\n\nThe memory address specified to be"
" freed has not been allocated. Only previously"
" allocated memory may be freed.",
MB_ICONASTERISK
},
{ VMERR_NOT_BASEPAGE,
"%s\n\nThe memory address specified to be"
" freed is not a base-page address. Only"
" base pages"
" may be freed.",
MB_ICONASTERISK
},
{ VMERR_DECOMMIT_RESERVED,
"%s\n\nThe memory specified to be"
" decommitted is in a reserved"
" state. Memory must"
" be committed before it can be decommitted.",
MB_ICONASTERISK
},
{ VMERR_ACCESS_ON_RESERVED,
"%s\n\nAccess protection specified for"
" reserved memory. Access protection may "
" only be specified for committed memory.",
MB_ICONASTERISK
},
{ VMERR_ACCESS_AND_DECOMMIT,
"%s\n\nAccess protection specified when"
" attempting to decommit memory. No access protection"
" may be specified when decommitting memory.",
MB_ICONASTERISK
},
{ VMERR_COMMIT_ON_COMMITTED,
"%s\n\nCommit Memory specified for"
" previously"
" committed memory. Choose \"Default\" or \""
"Decommit\" for committed memory.",
MB_ICONASTERISK
},
{ VMERR_COMMIT_ONLY,
"%s\n\nCommit Memory specified with"
" no access"
" protection specifed. Access protection required when"
" committing memory.",
MB_ICONASTERISK
},
{ VMERR_SET_NO_PARMS,
"%s\n\nNo parameters specified. Parameters"
" must be specified when using %s.",
MB_ICONASTERISK
},
{ VMERR_SET_ZERO_SIZE,
"%s\n\nSetting allocation attributes and/or access protection"
" on zero bytes is not permitted."
" A minimum size of one byte must be specified to set"
" allocation attributes and/or access protection on memory.",
MB_ICONASTERISK
},
{ VMERR_SET_ON_FREE,
"%s\n\nSetting allocation attributes and/or access protection"
" on non-allocated memory is not"
" permitted. Memory must be allocated before allocation attributes"
" or access protection may be specified for it.",
MB_ICONASTERISK
},
{ VMERR_DEFAULT,
"%s\n\n Error #%u occured during the call.",
MB_ICONASTERISK
}
};
/*--------------------------------------------------------------*\
* Entry point declarations *
\*--------------------------------------------------------------*/
VOID VMM_Error(PSZ pszFunction, ULONG ulErrorCode);
VOID CleanUpArray(PVOID pvAddress);
VOID StoreInArray(PVOID pvAddress, ULONG ulNumPages);
MRESULT EXPENTRY ReadMemDlgProc(HWND hwnd, USHORT msg,
MPARAM mp1, MPARAM mp2);
MRESULT EXPENTRY WriteMemDlgProc(HWND hwnd, USHORT msg,
MPARAM mp1, MPARAM mp2);
MRESULT EXPENTRY FreeMemDlgProc(HWND hwnd, USHORT msg,
MPARAM mp1, MPARAM mp2);
MRESULT EXPENTRY SetMem1DlgProc(HWND hwnd, USHORT msg,
MPARAM mp1, MPARAM mp2);
MRESULT EXPENTRY SetMem2DlgProc(HWND hwnd, USHORT msg,
MPARAM mp1, MPARAM mp2);
MRESULT EXPENTRY AllocMemDlgProc(HWND hwnd, USHORT msg,
MPARAM mp1, MPARAM mp2);
/****************************************************************\
* Non-standard window message processing routine *
*--------------------------------------------------------------*
* *
* Name: UserWndProc(hwnd, msg, mp1, mp2) *
* *
* Purpose: Process any messages sent to hwndMain that *
* are not processed by the standard window *
* procedure *
* *
* Usage: Routine is called for each message MainWndProc *
* does not process *
* *
* Method: A switch statement branches control based upon *
* the message passed. Any messages not processed *
* here must be passed onto WinDefWindowProc() *
* *
* Returns: Return value depended upon the message processed *
\****************************************************************/
MRESULT UserWndProc(hwnd, msg, mp1, mp2)
HWND hwnd; /* handle of window */
USHORT msg; /* id of message */
MPARAM mp1; /* first message parameter */
MPARAM mp2; /* second message parameter */
{
switch(msg) {
/*--------------------------------------------------------------*\
* Add case statements for message ids you wish to process *
\*--------------------------------------------------------------*/
default: /* default must call WinDefWindowProc() */
return(WinDefWindowProc(hwnd, msg, mp1, mp2));
break;
}
return 0L;
} /* UserWndProc() */
/****************************************************************\
* DOS API and Application Specific Error reporting routine *
*--------------------------------------------------------------*
* *
* Name: VMM_Error(pszFunction, ulErrorCode) *
* *
* Purpose: Display errors returned by system calls to *
* the user when they occur. All other error handling *
* is done inside the functions themselves *
* *
* Usage: Routine is called for each error that the dialog *
* functions do not process *
* *
* Method: A switch statement branches control based upon *
* the error number passed. Any message that comes *
* in that is not known is given a generic message. *
* The message is displayed with WinMessageBox *
* *
* Returns: *
\****************************************************************/
VOID VMM_Error(pszFunction, ulErrorCode)
PSZ pszFunction;
ULONG ulErrorCode;
{
char szTempBuf[BUFF_SIZE];
ULONG ulMsgIndex;
ulMsgIndex = 0L;
while((amsgentry[ulMsgIndex].ulMsgNum != ulErrorCode) &&
(amsgentry[ulMsgIndex].ulMsgNum != VMERR_DEFAULT))
ulMsgIndex++;
strcpy(szTempBuf,amsgentry[ulMsgIndex].szMsgText);
if (amsgentry[ulMsgIndex].ulMsgNum == VMERR_DEFAULT)
{
sprintf(szBuffer,szTempBuf,pszFunction,ulErrorCode);
}
else if (amsgentry[ulMsgIndex].ulMsgNum == VMERR_MAX_ALLOCATED)
{
sprintf(szBuffer,szTempBuf,pszFunction,MAXPAGES);
}
else if (amsgentry[ulMsgIndex].ulMsgNum == VMERR_SET_NO_PARMS)
{
sprintf(szBuffer,szTempBuf,pszFunction,pszFunction);
}
else
{
sprintf(szBuffer,szTempBuf,pszFunction);
}
WinMessageBox(HWND_DESKTOP,
hwndMain,
szBuffer,
szAppName,
0,
MB_OK | amsgentry[ulMsgIndex].usMsgIcon);
}
/****************************************************************\
* Procedure to remove freed pages from array *
*--------------------------------------------------------------*
* *
* Name: CleanUpArray(pvAddress) *
* *
* Purpose: Remove pages that the user indicated from the *
* array of pages stored *
* *
* Usage: Routine is called after each successful free *
* memory call issued by the user *
* *
* Method: Pages are removed by finding the address in the *
* array that matches what the user input, and then *
* removing all subsequent pages until another base *
* page is found or the last stored page is reached *
* *
* Returns: *
\****************************************************************/
VOID CleanUpArray(pvAddress)
PVOID pvAddress;
{
ULONG ulIndexLow;
ULONG ulIndexHigh;
/* At entry, we know that the pvAddress page is a base page and we
need to free up the pages associated with the base page for the
object. To do this, we find the next base address. We then make
the copies. */
ulIndexLow = 0;
while((apgentry[ulIndexLow].pvAddress != pvAddress) &&
(ulIndexLow < ulFreePage))
ulIndexLow++;
/* If DosFreeMem worked but the address is not in our page array,
then don't modify the array or the ulFreePage count. */
if (ulIndexLow < ulFreePage)
{
apgentry[ulIndexLow].fBaseAddr = FALSE;
ulIndexHigh = ulIndexLow + 1;
while((apgentry[ulIndexHigh].fBaseAddr == FALSE) &&
(ulIndexHigh < ulFreePage))
ulIndexHigh++;
while(ulIndexHigh < ulFreePage)
apgentry[ulIndexLow++] = apgentry[ulIndexHigh++];
ulFreePage -= (ulIndexHigh-ulIndexLow);
}
}
/****************************************************************\
* Procedure to store allocated pages in array *
*--------------------------------------------------------------*
* *
* Name: StoreInArray(pvAddress,ulNumPages) *
* *
* Purpose: Store pages that were just successfully allocated *
* in our array so we can track them *
* *
* Usage: Routine is called after each successful allocation *
* of memory by the user *
* *
* Method: The pages are added to the end of the array based *
* upon the current status of our global end of array *
* index variable (ulFreePage) *
* *
* Returns: *
\****************************************************************/
VOID StoreInArray(pvAddress,ulNumPages)
PVOID pvAddress;
ULONG ulNumPages;
{
ULONG temp;
/* Set all base indicators for the new pages to FALSE, and set the
addresses for the pages. */
for(temp = 0L; temp < ulNumPages; temp++)
{
apgentry[temp+ulFreePage].pvAddress = (PVOID)((ULONG)pvAddress +
(PAGESIZE * temp));
apgentry[temp+ulFreePage].fBaseAddr = FALSE;
}
/* Set the base indicator of the first page in the object to be
TRUE */
apgentry[ulFreePage].fBaseAddr = TRUE;
ulFreePage += ulNumPages;
}
/****************************************************************\
* Non-standard menu item command processing procedure *
*--------------------------------------------------------------*
* *
* Name: UserCommand(mp1, mp2) *
* *
* Purpose: Process any WM_COMMAND messages send to hwndMain *
* that are not processed by MainCommand *
* *
* Usage: Routine is called for each WM_COMMAND that is *
* not posted by a standard menu item *
* *
* Method: A switch statement branches control based upon *
* the id of the control which posted the message *
* *
* Returns: *
\****************************************************************/
VOID UserCommand(mp1, mp2)
MPARAM mp1; /* first message parameter */
MPARAM mp2; /* second message parameter */
{
PVOID pvMemAddress;
ULONG ulRegionSize;
ULONG ulTempRegionSize;
ULONG flTempAttributes;
ULONG ulPages; /* Number of pages requested by user */
ULONG rc; /* Return Code variable from calls */
ULONG rc2; /* Return Code variable for investigative calls */
switch(SHORT1FROMMP(mp1))
{
/*--------------------------------------------------------------*\
* Add case statements for menuitem ids you wish to process *
\*--------------------------------------------------------------*/
case IDM_VMMALLOC:
ObjAlloc.ulSize = 5000; /* default size to allocate */
ObjAlloc.ulAttr = PAG_READ | PAG_WRITE | PAG_EXECUTE;
if(WinDlgBox( HWND_DESKTOP,
hwndMain,
(PFNWP) AllocMemDlgProc,
NULL,
(ULONG) IDD_ALLOCMEM,
(PVOID) &ObjAlloc ))
{
/* Figure out the number of pages requested. */
ulPages = (ObjAlloc.ulSize / PAGESIZE);
if ((ObjAlloc.ulSize % PAGESIZE) != 0L)
{
ulPages++;
}
/* If the number of pages requested is zero (zero
bytes specified), or the number of pages is greater
than the number left in the array, report the error
condition. Otherwise, make the DosAllocMem call and
set any error condition returned by the call. */
if (ulPages == 0L)
{
rc = VMERR_ZERO_ALLOCATED;
}
else if (ulPages + ulFreePage > MAXPAGES + 1)
{
rc = VMERR_MAX_ALLOCATED;
}
else
{
rc = DosAllocMem(&pvMemAddress,
ObjAlloc.ulSize,
ObjAlloc.ulAttr);
}
/* If an error has occured, display it. Otherwise,
process the request. */
if (rc != 0L)
{
if (ObjAlloc.ulAttr == 0L)
{
rc = VMERR_SET_NO_PARMS;
}
else if (ObjAlloc.ulAttr == PAG_COMMIT)
{
rc = VMERR_COMMIT_ONLY;
}
else if (ObjAlloc.ulAttr == (PAG_COMMIT | OBJ_TILE))
{
rc = VMERR_COMMIT_AND_TILE_ONLY;
}
else if (ObjAlloc.ulAttr == OBJ_TILE)
{
rc = VMERR_TILE_ONLY;
}
VMM_Error("DosAllocMem()",rc);
}
else
{
StoreInArray(pvMemAddress,ulPages);
WinInvalidateRect(hwndMain, NULL, TRUE);
}
}
break;
case IDM_VMMFREE:
if (WinDlgBox(HWND_DESKTOP,
hwndMain,
(PFNWP) FreeMemDlgProc,
NULL,
(ULONG) IDD_FREEMEM,
(PVOID) &ObjAlloc ) != 0)
{
rc = DosFreeMem(ObjAlloc.pvAddress);
if (rc != 0L)
{
ulRegionSize = 1L;
/* Try to figure out why the error occured based
on actual page attributes of page requested to be
freed. */
rc2 = DosQueryMem(ObjAlloc.pvAddress,
&ulTempRegionSize,
&flTempAttributes);
if (rc2 == 0L)
/* If the page requested to be freed was already
in the freed state, or the requested page in the
object to be freed is not the base page of the
object, set the appropriate error condition. */
{
if ((flTempAttributes & PAG_FREE) != 0L)
{
rc = VMERR_ALREADY_FREED;
}
else if ((flTempAttributes & PAG_BASE) == 0L)
{
rc = VMERR_NOT_BASEPAGE;
}
}
VMM_Error("DosFreeMem()",rc);
}
else
{
CleanUpArray(ObjAlloc.pvAddress);
WinInvalidateRect(hwndMain, NULL, TRUE);
}
}
break;
case IDM_VMMSET:
if (WinDlgBox(HWND_DESKTOP,
hwndMain,
(PFNWP) SetMem1DlgProc,
NULL,
(ULONG) IDD_SETMEM1,
(PVOID) &ObjAlloc ))
{
if (WinDlgBox(HWND_DESKTOP,
hwndMain,
(PFNWP) SetMem2DlgProc,
NULL,
(ULONG) IDD_SETMEM2,
(PVOID) &ObjAlloc ))
{
rc = DosSetMem(ObjAlloc.pvAddress,
ObjAlloc.ulSize,
ObjAlloc.ulAttr);
/* If an error occured making the DosSetMem call,
try to figure out the cause of the error by
studying the requested access and the access on
the memory prior to the DosSetMem call. */
if (rc != 0L)
{
ulTempRegionSize = 1L;
rc2 = DosQueryMem(ObjAlloc.pvAddress,
&ulTempRegionSize,
&flTempAttributes);
if (rc2 == 0L)
{
/* If no attributes, commit with no other
attributes, or a size of zero was
specified, set the appropriate error
condition. */
if (ObjAlloc.ulAttr == 0L)
{
rc = VMERR_SET_NO_PARMS;
}
else if (ObjAlloc.ulAttr == PAG_COMMIT)
{
rc = VMERR_COMMIT_ONLY;
}
else if (ObjAlloc.ulSize == 0L)
{
rc = VMERR_SET_ZERO_SIZE;
}
/* If memory is not allocated then set
error condition. */
else if ((ObjAlloc.ulAttr & PAG_FREE) != 0L)
{
rc = VMERR_SET_ON_FREE;
}
/* If the memory was already in the
reserved state and the user attempted to
decommit it or set attributes for it, set
the error condition. */
else if ((flTempAttributes & PAG_COMMIT) == 0L)
{
if ((ObjAlloc.ulAttr & PAG_DECOMMIT) != 0L)
{
rc = VMERR_DECOMMIT_RESERVED;
}
else if ((ObjAlloc.ulAttr & ~PAG_COMMIT) != 0L)
{
rc = VMERR_ACCESS_ON_RESERVED;
}
}
/* If the memory was in a committed state
and the user attempted to decommit it and
set attributes, or the user attempts to
commit the memory, set the appropriate
error condition. */
else
{
if (((ObjAlloc.ulAttr & PAG_DECOMMIT) != 0L)
&& ((ObjAlloc.ulAttr & ~PAG_DECOMMIT) != 0L))
{
rc = VMERR_ACCESS_AND_DECOMMIT;
}
else if ((ObjAlloc.ulAttr & PAG_COMMIT) != 0L)
{
rc = VMERR_COMMIT_ON_COMMITTED;
}
}
}
VMM_Error("DosSetMem()",rc);
}
else
{
WinInvalidateRect(hwndMain, NULL, TRUE);
}
}
}
break;
case IDM_VMMWRITE:
if (WinDlgBox(HWND_DESKTOP,
hwndMain,
(PFNWP) WriteMemDlgProc,
NULL,
(ULONG) IDD_WRITEMEM,
(PVOID) NULL))
{
WinInvalidateRect(hwndMain, NULL, TRUE);
}
break;
case IDM_VMMREAD:
if (WinDlgBox(HWND_DESKTOP,
hwndMain,
(PFNWP) ReadMemDlgProc,
NULL,
(ULONG) IDD_READMEM,
(PVOID) &ObjAlloc ))
{
sprintf(szBuffer, "Address %p contains %s",
ObjAlloc.pvAddress, ObjAlloc.pvAddress);
WinMessageBox(HWND_DESKTOP,
hwndMain,
szBuffer,
"Read Memory",
0,
MB_OK);
WinInvalidateRect(hwndMain, NULL, TRUE);
}
break;
default:
break;
}
/* This routine currently doesn't use the mp2 parameter but *\
* it is referenced here to prevent an 'Unreferenced Parameter' *
\* warning at compile time. */
mp2;
} /* UserCommand() */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.