Metropoli BBS
VIEWER: utility.c MODE: TEXT (ASCII)
/***********************************************************************\
 *                                PC2.c                                *
 *                 Copyright (C) by Stangl Roman, 1993                 *
 * This Code may be freely distributed, provided the Copyright isn't   *
 * removed, under the conditions indicated in the documentation.       *
 *                                                                     *
 * Utility.c    General functions that are not window procedures.      *
 *                                                                     *
\***********************************************************************/

static char RCSID[]="@(#) $Header: Utility.c Version 1.60 06,1993 $ (LBL)";

#define         _FILE_  "PC/2 - Utility.c V1.60"

#define         INCL_DOSDEVICES

#include        "PC2.h"                 /* User include files */
#include        "Error.h"
#include        <bsedev.h>

/*--------------------------------------------------------------------------------------*\
 * Procedure to initialize a window and its message queue.                              *
 * Req:                                                                                 *
 *      pHab .......... A pointer to be filled with the anchor block of the window      *
 *      pHmq .......... A pointer to be filled with the message queue of the window     *
 * Returns:                                                                             *
 *      TRUE/FALSE .... If called sucessfully/unsucessfully                             *
\*--------------------------------------------------------------------------------------*/
BOOL    WinStartUp(HAB *pHab, HMQ *pHmq)
{
                                        /* Initialize handle of anchor block */
if((*pHab=WinInitialize(0))==NULLHANDLE)
    return(FALSE);
                                        /* Initialize handle of message queue */
if((*pHmq=WinCreateMsgQueue(*pHab, 0))==NULLHANDLE)
    return(FALSE);
return(TRUE);
}

/*--------------------------------------------------------------------------------------*\
 * Procedure to initialize HELP.                                                        *
 * Req:                                                                                 *
 *      hab ........... Anchor block handle                                             *
 *      pHelpFile ..... A pointer to helppanel filename in PC/2 directory               *
 *      pHwndHelp  .... A pointer to a HWND structure                                   *
 * Returns:                                                                             *
 *      pHwndHelp ..... If called sucessfully/unsucessfully hwnd/NULL                   *
\*--------------------------------------------------------------------------------------*/
BOOL    WinStartHelp(HAB hab, UCHAR *pHelpFile, HWND *pHwndHelp)
{
HELPINIT        HelpInit;

HelpInit.cb=sizeof(HELPINIT);           /* Size of HELPINIT structure */
HelpInit.ulReturnCode=0;                /* Returnvalue from HelpManager */
HelpInit.pszTutorialName=NULL;          /* No tutorial */
                                        /* Ressource of Helptable */
HelpInit.phtHelpTable=(PHELPTABLE)MAKEULONG(MAIN_HELP_TABLE, 0xffff);
                                        /* Ressource in .EXE */
HelpInit.hmodHelpTableModule=NULLHANDLE;
                                        /* No handle */
HelpInit.hmodAccelActionBarModule=NULLHANDLE;
HelpInit.idAccelTable=0;                /* None */
HelpInit.idActionBar=0;                 /* None */
                                        /* Window title of help window */
HelpInit.pszHelpWindowTitle="PC/2 - Program Commander/2 Help";
HelpInit.pszHelpLibraryName=pHelpFile;  /* Library name of help panel via PC/2 directory */
HelpInit.fShowPanelId=0;                /* Panel ID not displayed */
/*                                                                                      *\
 * First assume PC2.HLP in HELP path and try to create it from there.                   *
\*                                                                                      */
*pHwndHelp=WinCreateHelpInstance(       /* Create help */
    hab,                                /* Anchor block */
    &HelpInit);
                                        /* Test for successful help creation */
if((*pHwndHelp) && (!HelpInit.ulReturnCode))
                                        /* Associate HELP with frame window */
    if(WinAssociateHelpInstance(*pHwndHelp, hwndFrame)!=FALSE)
        return(TRUE);
/*                                                                                      *\
 * Second assume PC2.HLP in PC/2's directory and try to create it from there.           *
\*                                                                                      */
HelpInit.ulReturnCode=0;                /* Returnvalue from HelpManager */
HelpInit.pszHelpLibraryName="PC2.HLP";  /* Library name of help panel via HELP path */
*pHwndHelp=WinCreateHelpInstance(hab, &HelpInit);
if((*pHwndHelp) && (!HelpInit.ulReturnCode))
    if(WinAssociateHelpInstance(*pHwndHelp, hwndFrame)!=FALSE)
        return(TRUE);
*pHwndHelp=NULLHANDLE;
return(FALSE);
}

/*--------------------------------------------------------------------------------------*\
 * Procedure to close a window and its message queue.                                   *
 * Req:                                                                                 *
 *      pHwndHelp ..... A pointer to HELP window handle                                 *
 *      pHab .......... A pointer to extract the anchor block of the window             *
 *      pHmq .......... A pointer to extract message queue of the window                *
 * Returns:                                                                             *
 *      TRUE/FALSE .... If called sucessfully/unsucessfully                             *
\*--------------------------------------------------------------------------------------*/
BOOL    WinCloseDown(HWND *pHwndHelp, HAB *pHab, HMQ *pHmq)
{
if(!*pHwndHelp)                         /* Release HELP */
    WinDestroyHelpInstance(*pHwndHelp);
if(*pHmq!=NULLHANDLE)                   /* Release handle of message queue */
    WinDestroyMsgQueue(*pHmq);
if(*pHab!=NULLHANDLE)                   /* Release handle of anchor block */
    WinTerminate(*pHab);
                                        /* Any error during WinStartUp */
if((*pHab==NULLHANDLE) || (*pHmq==NULLHANDLE)) return(FALSE);
else return(TRUE);
}

/*--------------------------------------------------------------------------------------*\
 * A SESSIONDATA data structure is used to extract the parameters to start a new        *
 * session. If sucessfull, additional parameters are extracted to set the priority of   *
 * the new session.                                                                     *
 * Req:         none                                                                    *
\*--------------------------------------------------------------------------------------*/
void    StartSession(SESSIONDATA *ptrSessionData)
{
UCHAR           ucPgmInputs[EF_SIZE255+1];
STARTDATA       StartData;
UCHAR           *pucDosSettings;
ULONG           SessID;
PID             Pid;
APIRET          rc;

/*                                                                                      *\
 * Change to the root directory of all non-removable drives.                            *
\*                                                                                      */
{
ULONG   ulDriveNumber;                  /* Current drive (1=A, 2=B, ...) */
ULONG   ulLogicalDriveMap;              /* Bitmap of available drives (Bit 0=A, 1=B, ...) */
UCHAR   ucDrive[]="c:";                 /* Current drive */
ULONG   ulTemp;
HFILE   hfDiskHandle;                   /* File handle of current drive */
ULONG   ulActionTaken;                  /* Action taken on opened file (drive) */

                                        /* Query drive bit map */
rc=DosQueryCurrentDisk(&ulDriveNumber, &ulLogicalDriveMap);
if(rc!=NO_ERROR) DOS_ERR(rc, hwndFrame, hwndClient);
for(ulTemp=(ULONG)ucDrive[0]-'a', ulLogicalDriveMap>>=2; ulTemp<=(ULONG)('z'-'a');
    ulTemp++, ucDrive[0]++, ulLogicalDriveMap>>=1)
    {                                   /* Loop for drive C: to Z: (blocks of 0s must be
                                           expected because of network drives) */
                                        /* If drive is not attached ignore drive letter */
        if((ulLogicalDriveMap&0x1)==0) continue;
                                        /* Open drive device readonly and fail call on error */
        rc=DosOpen(ucDrive, &hfDiskHandle, &ulActionTaken, 0, FILE_NORMAL,
            OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR |
            OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READONLY, 0);
        if(rc==NO_ERROR)
            {                           /* On non-removeable media close it and change to the
                                           root directory of it. Don't change to root directory
                                           on removable media that isn't inserted or to not
                                           attached  drives */
            struct _PPF                 /* Parameter Packet Format */
            {
            BYTE        bCommandInformation;
            BYTE        bDriveUnit;
            } PPF={0, 0};
            struct _DDF                 /* Data Packet Format */
            {
            BYTE        bData;
            } DDF;
            ULONG       ulParamLengthInOut=sizeof(PPF);
            ULONG       ulDataLengthInOut=sizeof(DDF);

                                        /* Now query if the media is removable. The media
                                           needs not to be inserted */
            rc=DosDevIOCtl(hfDiskHandle, IOCTL_DISK, DSK_BLOCKREMOVABLE,
                &PPF, ulParamLengthInOut, &ulParamLengthInOut,
                &DDF, ulDataLengthInOut, &ulDataLengthInOut);
                                        /* Only Error 0 (no error) or Error 50
                                           (Network request not supported) are
                                           not treated as errors */
            if((rc!=NO_ERROR) && (rc!=ERROR_NOT_SUPPORTED)) DOS_ERR(rc, hwndFrame, hwndClient);
            DosClose(hfDiskHandle);
            if(DDF.bData)
                {                       /* If it is a nonremovable media, change to its root */
                                        /* 1=A, 2=B, 3=C,... */
                rc=DosSetDefaultDisk((ucDrive[0]+1)-'a');
                if(rc!=NO_ERROR) DOS_ERR(rc, hwndFrame, hwndClient);
                rc=DosSetCurrentDir("\\");
                if(rc!=NO_ERROR) DOS_ERR(rc, hwndFrame, hwndClient);
                }
            }
    }
}
/*                                                                                      *\
 * Test for x:(...] where x is a drive and set the current working directory to this    *
 * drive.                                                                               *
\*                                                                                      */
if((strlen(ptrSessionData->PgmDirectory)>=2)
    && (ptrSessionData->PgmDirectory[1]==':'))
    {
    UCHAR       ucDrive;
                                        /* Then get drive letter (only if one's there */
    ucDrive=tolower(ptrSessionData->PgmDirectory[0]);
                                        /* 1=A, 2=B, 3=C,... */
    rc=DosSetDefaultDisk(++ucDrive-'a');
    if(rc!=NO_ERROR) DOS_ERR(rc, hwndFrame, hwndClient);
    }
/*                                                                                      *\
 * Test for a directory and set the current working directory to it, if one exists,     *
 * set to root directory.                                                               *
\*                                                                                      */
if(strlen(ptrSessionData->PgmDirectory)>2)
    {                                   /* Only if there's one */
    rc=DosSetCurrentDir(ptrSessionData->PgmDirectory);
    if(rc!=NO_ERROR) DOS_ERR(rc, hwndFrame, hwndClient);
    }
else
    {                                   /* Set to root directory */
    rc=DosSetCurrentDir("\\");
    if(rc!=NO_ERROR) DOS_ERR(rc, hwndFrame, hwndClient);
    }
StartData.Length=50;                    /* Length of StartData */
                                        /* Independent session */
StartData.Related=SSF_RELATED_INDEPENDENT;
StartData.FgBg=ptrSessionData->FgBg;    /* Foreground application */
                                        /* No trace */
StartData.TraceOpt=SSF_TRACEOPT_NONE;
                                        /* Session title string */
StartData.PgmTitle=ptrSessionData->PgmTitle;
                                        /* Program path-name string */
StartData.PgmName=ptrSessionData->PgmName;
                                        /* Input arguments */
StartData.PgmInputs=ptrSessionData->PgmInputs;
StartData.TermQ=0;                      /* No termination queue */
StartData.Environment=0;                /* No environment */
                                        /* Inherit from PC/2's environment to change to
                                           requested drive & directory */
StartData.InheritOpt=SSF_INHERTOPT_PARENT;
                                        /* Session type */
StartData.SessionType=ptrSessionData->SessionType;
StartData.IconFile=0;                   /* No icon, use default */
StartData.PgmHandle=0;                  /* Don't use installation file */
                                        /* Session initial state */
StartData.PgmControl=ptrSessionData->PgmControl;
                                        /* Initial window size */
if(StartData.PgmControl & SSF_CONTROL_SETPOS)
    {                                   /* Position relative to (0|0) of virtual Desktop */
    StartData.InitXPos=0-HookParameters.VirtualDesktopPos.x+ptrSessionData->InitXPos;
    StartData.InitYPos=0-HookParameters.VirtualDesktopPos.y+ptrSessionData->InitYPos;
    StartData.InitXSize=ptrSessionData->InitXSize;
    StartData.InitYSize=ptrSessionData->InitYSize;
    }
/*                                                                                      *\
 * Search for user-addable commandline parameter. If one found, display dialog and get  *
 * it. It will be added to the current arguments.                                       *
\*                                                                                      */
while(TRUE)
    {
    COMMANDLINEPARAMS   CLPParams;
    INT                 iTemp;
    UCHAR               *pucTemp;

    strcpy(ucPgmInputs, StartData.PgmInputs);
                                        /* Search for [, break if not found */
    if((pucTemp=strchr(ucPgmInputs, '['))==NULL) break;
                                        /* Search for ], break if not found */
    if(strchr(pucTemp, ']')==NULL) break;
                                        /* Break commandline parameters into three parts */
    for(iTemp=0, pucTemp=StartData.PgmInputs; *pucTemp!='['; iTemp++, pucTemp++)
        CLPParams.ucPBefore[iTemp]=*pucTemp;
    CLPParams.ucPBefore[iTemp]='\0';
    pucTemp++;                          /* Skip [ */
    for(iTemp=0; *pucTemp!=']'; iTemp++, pucTemp++)
        CLPParams.ucPUser[iTemp]=*pucTemp;
    CLPParams.ucPUser[iTemp]='\0';
    pucTemp++;                          /* Skip ] */
    for(iTemp=0; *pucTemp!='\0'; iTemp++, pucTemp++)
        CLPParams.ucPAfter[iTemp]=*pucTemp;
    CLPParams.ucPAfter[iTemp]='\0';
    if(!WinDlgBox(                      /* Start Startup Parameters dialog box */
        HWND_DESKTOP, HWND_DESKTOP, SU_DialogProcedure, 0, SUID_STARTUPDIALOG,
        &CLPParams))                    /* Initialization data */
        {
        GEN_ERR(hab, hwndFrame, hwndClient);
        break;
        }
                                        /* Replace existing commandline parameters with
                                           user-edited ones if OK was pressed */
    if(DialogResult==DID_OK) sprintf(ucPgmInputs, "%s%s %s",CLPParams.ucPBefore,
        CLPParams.ucPUser, CLPParams.ucPAfter);
                                        /* If Cancel was pressed, replace by empty string */
    else strcpy(ucPgmInputs, "");
    StartData.PgmInputs=ucPgmInputs;
    break;                              /* Break out ! */
    }
/*                                                                                      *\
 * If we're to start a DOS session, then set the DOS-Settings via the Environment. This *
 * is an undocumented feature (the toolkit says that the Environment is reserved and    *
 * must be 0 for a DOS session. To use the DOS Settings each Setting must be followed   *
 * by \0 and the last Setting must be followed by two \0s. It seems that the settings   *
 * must replace OFF by 0 and ON by 1.                                                   *
 * Any WIN-OS2 session is hereto equivalent to a DOS session.                           *
\*                                                                                      */
switch(StartData.SessionType)
{
case PROG_WINDOW_REAL:
case PROG_WINDOW_PROT:
case PROG_31_ENH:
    {
    UCHAR   ucTemp[EF_SIZE255+1];

    strcpy(ucTemp, ucPgmInputs);
    if(StartData.SessionType==PROG_WINDOW_REAL)
        strcpy(ucPgmInputs, "/r ");     /* WIN-OS2 real mode */
    if(StartData.SessionType==PROG_WINDOW_PROT)
        strcpy(ucPgmInputs, "/s ");     /* WIN-OS2 standard mode */
    if(StartData.SessionType==PROG_31_ENH)
        strcpy(ucPgmInputs, "/3 ");     /* WIN-OS2 386 enhanced mode */
                                        /* Now add the WIN application to invoke */
    strcat(ucPgmInputs, StartData.PgmName);
    strcat(ucPgmInputs, " ");
    strcat(ucPgmInputs, ucTemp);        /* Copy optional commandline parameters as
                                           parameters to the WIN application to be
                                           invoked */
    StartData.PgmName="WIN.COM";        /* For WIN-OS2 sessions we use WIH.COM to start
                                           the WIN-application */
    StartData.PgmInputs=ucPgmInputs;    /* Pass the WIN application to be invoked */
                                        /* Now invoke a WIN-OS2 session. Although it is named
                                           common, it will invoke a seperate VDM for currently
                                           unknown reasons. */
    StartData.SessionType=PROG_SEAMLESSCOMMON;
    }                                   /* Fall through, cause the Dos Settings are the same */

case SSF_TYPE_VDM:
case SSF_TYPE_WINDOWEDVDM:
    {
    ULONG       ulTemp;
    UCHAR       *pucTemp;

                                        /* Allocate a temporary space for the Dos Settings */
    ulTemp=strlen(ptrSessionData->PgmDosSettings)+2;
    pucDosSettings=(UCHAR *)malloc(ulTemp);
    strcpy(pucDosSettings, ptrSessionData->PgmDosSettings);
                                        /* Replace all \n by \0 */
    for(pucTemp=pucDosSettings; *pucTemp!='\0'; pucTemp++)
        if(*pucTemp=='\n') *pucTemp='\0';
    *++pucTemp='\0';
    StartData.Environment=pucDosSettings;
    }
    break;
}
/*                                                                                      *\
 * Now start the session, but beware of the error code ERROR_SMG_START_IN_BACKGROUND,   *
 * which isn't actually an error code, but an informational message we ignore.          *
\*                                                                                      */
if(StartData.SessionType==SSF_TYPE_WPSOBJECT)
    {
    HOBJECT     hWPSObject;

                                        /* Find the handle of the WPS object */
    hWPSObject=WinQueryObject(SessionData.PgmName);
    if(hWPSObject!=NULLHANDLE)
        WinSetObjectData(hWPSObject, "OPEN=DEFAULT");
    else rc=ERROR_INVALID_HANDLE;
    rc=NO_ERROR;
    }
else
    rc=DosStartSession(                 /* Start the new session */
        &StartData,                     /* Session data */
        &SessID,                        /* Session ID of new session */
        &Pid);                          /* Process ID of new session */
switch(rc)
{
case NO_ERROR:                          /* Error codes for errors that are informational */
case ERROR_SMG_START_IN_BACKGROUND:
    break;

default:
    DOS_ERR(rc, hwndFrame, hwndClient);
}
/*                                                                                      *\
 * Release memory allocated for the DOS Settings.                                       *
\*                                                                                      */
switch(StartData.SessionType)
{
case SSF_TYPE_VDM:
case SSF_TYPE_WINDOWEDVDM:
case PROG_WINDOW_REAL:
case PROG_WINDOW_PROT:
case PROG_31_ENH:
    free(pucDosSettings);
    break;
}
}

/*--------------------------------------------------------------------------------------*\
 * Procedure to load a SESSIONDATA structure from a MENUDATA structure.                 *
 * Req:                                                                                 *
 *      Empty ......... A BOOL flag that is true if the MENUDATA structure is empty,    *
 *                      that is filled with default values from AllocateMenuData().     *
 *      pMenuData ..... A pointer to a MENUDATA structure to extract the data required  *
 *                      for a Menu/Program Installation dialog.                         *
 *      pSessionData .. A pointer to a SESSIONDATA structure to write the extracted     *
 *                      data into, which is then used in subsequent Menu/Program        *
 *                      Installation dialogs window procedures.                         *
 * Returns:                                                                             *
 *      TRUE/FALSE .... If called sucessfully/unsucessfully                             *
\*--------------------------------------------------------------------------------------*/
BOOL    LoadMenuData2SessionData(BOOL Empty, MENUDATA *pMenuData, SESSIONDATA *pSessionData)
{
strcpy(pSessionData->PgmTitle, pMenuData->PgmTitle);
strcpy(pSessionData->PgmName, pMenuData->PgmName);
strcpy(pSessionData->PgmDirectory, pMenuData->PgmDirectory);
strcpy(pSessionData->PgmInputs, pMenuData->PgmInputs);
strcpy(pSessionData->PgmDosSettings, pMenuData->PgmDosSettings);
/*                                                                                      *\
 * Just straight forward copy of data from MENUDATA structure to SESSIONDATA structure. *
 * The allocated MENUDATA structure is filled during allocation with default values,    *
 * we don't differentiate between empty and non-empty structures any more.              *
\*                                                                                      */
pSessionData->SessionType=pMenuData->SessionType;
pSessionData->PgmControl=pMenuData->PgmControl;
pSessionData->FgBg=pMenuData->FgBg;
pSessionData->InitXPos=pMenuData->InitXPos;
pSessionData->InitYPos=pMenuData->InitYPos;
pSessionData->InitXSize=pMenuData->InitXSize;
pSessionData->InitYSize=pMenuData->InitYSize;
return(TRUE);
}

/*--------------------------------------------------------------------------------------*\
 * Procedure to save a MENUDATA structure to a SESSIONDATA structure.                   *
 * Req:                                                                                 *
 *      pMenuData ..... A pointer to a MENUDATA structure to write the data from a      *
 *                      Menu/Program Installation dialog.                               *
 *      pSessionData .. A pointer to a SESSIONDATA structure to extract the data from,  *
 *                      which the user entered.                                         *
 * Returns:                                                                             *
 *      TRUE/FALSE .... If called sucessfully/unsucessfully                             *
\*--------------------------------------------------------------------------------------*/
BOOL    LoadSessionData2MenuData(MENUDATA *pMenuData, SESSIONDATA *pSessionData)
{
                                        /* Ignore if not changed otherwise release menory
                                           and allocate a new one */
if(strcmp(pMenuData->PgmTitle, pSessionData->PgmTitle)!=0)
    {
    free(pMenuData->PgmTitle);
    pMenuData->PgmTitle=malloc(1+strlen(pSessionData->PgmTitle));
    strcpy(pMenuData->PgmTitle, pSessionData->PgmTitle);
    }
if(strcmp(pMenuData->PgmName, pSessionData->PgmName)!=0)
    {
    free(pMenuData->PgmName);
    pMenuData->PgmName=malloc(1+strlen(pSessionData->PgmName));
    strcpy(pMenuData->PgmName, pSessionData->PgmName);
    }
if(strcmp(pMenuData->PgmDirectory, pSessionData->PgmDirectory)!=0)
    {
    free(pMenuData->PgmDirectory);
    pMenuData->PgmDirectory=malloc(1+strlen(pSessionData->PgmDirectory));
    strcpy(pMenuData->PgmDirectory, pSessionData->PgmDirectory);
    }
if(strcmp(pMenuData->PgmInputs, pSessionData->PgmInputs)!=0)
    {
    free(pMenuData->PgmInputs);
    pMenuData->PgmInputs=malloc(1+strlen(pSessionData->PgmInputs));
    strcpy(pMenuData->PgmInputs, pSessionData->PgmInputs);
    }
switch(SessionData.SessionType)
{                                       /* Save DOS settings for DOS type sessions */
case SSF_TYPE_VDM:
case SSF_TYPE_WINDOWEDVDM:
case PROG_WINDOW_REAL:
case PROG_WINDOW_PROT:
case PROG_31_ENH:
    if (strcmp(pMenuData->PgmDosSettings, pSessionData->PgmDosSettings)!=0)
        {
        free(pMenuData->PgmDosSettings);
                                        /* Last entry must contain a CR, LF */
        if(*(pSessionData->PgmDosSettings+strlen(pSessionData->PgmDosSettings))!='\n')
            strcat(pSessionData->PgmDosSettings, "\r\n");
        pMenuData->PgmDosSettings=malloc(1+strlen(pSessionData->PgmDosSettings));
        strcpy(pMenuData->PgmDosSettings, pSessionData->PgmDosSettings);
        }
    break;

default:                                /* For all other we load empty DOS settings.
                                           Normally they are empty, but if someone
                                           modifys the profile there may be some, which
                                           we force to be cleared */
    free(pMenuData->PgmDosSettings);
    pMenuData->PgmDosSettings=malloc(1+strlen(""));
    strcpy(pMenuData->PgmDosSettings, "");
    break;
}
pMenuData->SessionType=pSessionData->SessionType;
pMenuData->PgmControl=pSessionData->PgmControl;
pMenuData->FgBg=pSessionData->FgBg;
pMenuData->InitXPos=pSessionData->InitXPos;
pMenuData->InitYPos=pSessionData->InitYPos;
pMenuData->InitXSize=pSessionData->InitXSize;
pMenuData->InitYSize=pSessionData->InitYSize;
return(TRUE);
}

/*--------------------------------------------------------------------------------------*\
 * This procedure allocates a MENUDATA structure and initializes it to the default      *
 * values of an empty structure.                                                        *
 * Req:                                                                                 *
 *      none                                                                            *
 * Returns:                                                                             *
 *      pMenuData ..... A pointer to an MENUDATA structure.                             *
\*--------------------------------------------------------------------------------------*/
MENUDATA *AllocateMenuData(void)
{
UCHAR           *pU;
MENUDATA        *pMenuData;

pMenuData=malloc(sizeof(MENUDATA));     /* Allocate a MENUDATA structure */
pMenuData->Item=ENTRYEMPTY;             /* It's an empty structure */
pMenuData->id=0;
pMenuData->hwndItem=NULLHANDLE;
strcpy(pU=malloc(strlen("")+1), "");
pMenuData->PgmTitle=pU;                 /* Load default values */
strcpy(pU=malloc(strlen("")+1), "");
pMenuData->PgmName=pU;
strcpy(pU=malloc(strlen("")+1), "");
pMenuData->PgmDirectory=pU;
strcpy(pU=malloc(strlen("")+1), "");
pMenuData->PgmInputs=pU;
strcpy(pU=malloc(strlen("")+1), "");
pMenuData->PgmDosSettings=pU;
pMenuData->SessionType=SSF_TYPE_DEFAULT;
pMenuData->PgmControl=SSF_CONTROL_VISIBLE;
pMenuData->FgBg=SSF_FGBG_FORE;
pMenuData->InitXPos=swpScreen.cx*0.15;
pMenuData->InitYPos=swpScreen.cy*0.15;
pMenuData->InitXSize=swpScreen.cx*0.70;
pMenuData->InitYSize=swpScreen.cy*0.70;
pMenuData->Back=NULL;
pMenuData->Submenu=NULL;
pMenuData->Next=NULL;
return(pMenuData);
}

/*--------------------------------------------------------------------------------------*\
 * This recursive procedure loads the popup menu from the profile.                      *
 * Req:                                                                                 *
 *      pMenuData ..... A pointer to an MENUDATA structure.                             *
 * Returns:                                                                             *
 *      none                                                                            *
\*--------------------------------------------------------------------------------------*/
void LoadMenu(MENUDATA *pMenuData)
{
static UCHAR    Buffer[256];
static UCHAR    *Match;
static USHORT   Flag;

fgets(Buffer, sizeof(Buffer), Pc2Profile);
do
{
                                        /* Should read MENUITEM or SUBMENU BEGIN or
                                           SUBMENU END */
    if(strstr(Buffer, "SUBMENU END"))
        {
        fgets(Buffer, sizeof(Buffer), Pc2Profile);
        return;                         /* We are at an end of the list, terminate it
                                           and shell up one level by return() */
        }
    pMenuData->id=MenuDataId++;         /* Fill with current id and increment id */
    if(strstr(Buffer, "PROFILE END")) return;
    if(strstr(Buffer, "MENUITEM")) Flag=ENTRYMENUITEM; else Flag=ENTRYSUBMENU;
/*                                                                                      *\
 * Get the entry from the profile, but remove the heading description and the \n from   *
 * the strings.                                                                         *
\*                                                                                      */
                                        /* Get the session title */
    fgets(Buffer, sizeof(Buffer), Pc2Profile);
    Buffer[strlen(Buffer)-1]='\0';
    if((Match=strchr(Buffer, ' '))==NULL) Match=strchr(Buffer, '\0');
    else for( ; (*Match==' ') && (*Match!='\0'); Match++);
    free(pMenuData->PgmTitle);
    pMenuData->PgmTitle=malloc(strlen(Match)+1);
    strcpy(pMenuData->PgmTitle, Match);
    if(Flag==ENTRYMENUITEM)
        {
        pMenuData->Item=ENTRYMENUITEM;  /* It's a Menuitem */
        do                              /* Do until a complete MENUITEM was read */
            {
                                        /* Get a new line */
            fgets(Buffer, sizeof(Buffer), Pc2Profile);
                                        /* Replace CRLF with \0 */
            Buffer[strlen(Buffer)-1]='\0';
                                        /* Find first space after a ':' or NULL, if
                                           none can be found */
            Match=strchr(Buffer, ':');
            if(Match=='\0') Match=strchr(Buffer, '\0');
            else                        /* We found a ':', so we search for ' ' and
                                           return it or NULL, if none can be found */
                if((Match=strchr(Match, ' '))==NULL) Match=strchr(Buffer, '\0');
                else for( ; (*Match==' ') && (*Match!='\0'); Match++);
                                        /* Now fill in the characters after the
                                           space, according for what structure 
                                           element it is given */
            if(strstr(Buffer, "PgmName"))
                {
                free(pMenuData->PgmName);
                pMenuData->PgmName=malloc(strlen(Match)+1);
                strcpy(pMenuData->PgmName, Match);
                }
            if(strstr(Buffer, "PgmDirectory"))
                {
                free(pMenuData->PgmDirectory);
                pMenuData->PgmDirectory=malloc(strlen(Match)+1);
                strcpy(pMenuData->PgmDirectory, Match);
                }
            if(strstr(Buffer, "PgmInputs"))
                {
                free(pMenuData->PgmInputs);
                pMenuData->PgmInputs=malloc(strlen(Match)+1);
                strcpy(pMenuData->PgmInputs, Match);
                }
            if(strstr(Buffer, "DOSSETTINGS BEGIN"))
                {
                UCHAR       ucBuffer[2049]="";

                fgets(Buffer, sizeof(Buffer), Pc2Profile);
                while(!strstr(Buffer, "DOSSETTINGS END"))
                    {                   /* Add all DOS Settings to temporary buffer */
                    strcat(ucBuffer, Buffer);
                    fgets(Buffer, sizeof(Buffer), Pc2Profile);
                    }
                                        /* Now allocate the exactly required buffer and
                                           copy all DOS Settings there */
                free(pMenuData->PgmDosSettings);
                pMenuData->PgmDosSettings=malloc(strlen(ucBuffer)+1);
                strcpy(pMenuData->PgmDosSettings, ucBuffer);
                }
            if(strstr(Buffer, "SessionType"))
                {
                pMenuData->SessionType=(USHORT)atol(Match);
                }
            if(strstr(Buffer, "PgmControl"))
                {
                pMenuData->PgmControl=(USHORT)atol(Match);
                }
            if(strstr(Buffer, "FgBg"))
                {
                pMenuData->FgBg=(USHORT)atol(Match);
                }
            if(strstr(Buffer, "InitXPos"))
                {
                pMenuData->InitXPos=(SHORT)atol(Match);
                }
            if(strstr(Buffer, "InitYPos"))
                {
                pMenuData->InitYPos=(SHORT)atol(Match);
                }
            if(strstr(Buffer, "InitXSize"))
                {
                pMenuData->InitXSize=(USHORT)atol(Match);
                }
            if(strstr(Buffer, "InitYSize"))
                {
                pMenuData->InitYSize=(USHORT)atol(Match);
                }
            } while((!strstr(Buffer, "MENUITEM")) &&
                (!strstr(Buffer, "SUBMENU BEGIN")) &&
                (!strstr(Buffer, "SUBMENU END")) &&
                (!strstr(Buffer, "PROFILE END")) &&
                !feof(Pc2Profile));
                                        /* Insert this Menuitem at the end of the Popup-Menu */
        if(pMenuData->Back!=NULL)
            {                           /* This isn't the first item, insert after an
                                           existing item */
            if((pMenuData->Back)->Submenu==pMenuData)
                                        /* If this is the first item of a Submenu, then
                                           insert it as this */
                SetPopupMenu(MM_INSERTITEMSUBMENU, MPFROMP(pMenuData), MPFROMLONG((pMenuData->Back)->id));
            else
                                        /* Insert item after the existing item */
                SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMenuData), MPFROMLONG((pMenuData->Back)->id));
            }
        else                            /* This is the first item, insert at the end */
                SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMenuData), MPFROMLONG(MIT_END));
        }
    if(Flag==ENTRYSUBMENU)
        {                               /* If we load a SUBMENU BEGIN, fill with empty strings */
        MENUDATA        *pMenuDataTemp;

        pMenuData->Item=ENTRYSUBMENU;   /* It's a Submenu */
                                        /* Now obtain a entry for a submenu, adjust the
                                           linked list to it and call this procedure with
                                           the new entry recursivly again */
        pMenuDataTemp=AllocateMenuData();
        pMenuData->Submenu=pMenuDataTemp;
        pMenuDataTemp->Back=pMenuData;
                                        /* Insert this Menuitem at the end of the Popup-Menu */
        if(pMenuData->Back!=NULL)
            {                           /* This isn't the first item, insert after an
                                           existing item */
            if((pMenuData->Back)->Submenu==pMenuData)
                                        /* If this is the first item of a Submenu, then
                                           insert it as this */
                SetPopupMenu(MM_INSERTITEMSUBMENU, MPFROMP(pMenuData), MPFROMLONG((pMenuData->Back)->id));
            else
                                        /* Insert item after the existing item */
                SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMenuData), MPFROMLONG((pMenuData->Back)->id));
            }
        else                            /* This is the first item, insert at the end */
                SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMenuData), MPFROMLONG(MIT_END));
        LoadMenu(pMenuDataTemp);        /* It's assumed to be an empty entry, which will
                                           be corrected, if the first entry of the Submenu
                                           is found */
        }
/*                                                                                      *\
 * Now see if we're at the end of the profile. If so, then terminate linked list with   *
 * 2 Null pointers, otherwise abtain a new menu space and adjust the menu pointer       *
 * pMenuData to the newly created menu.                                                 *
\*                                                                                      */
    if(strstr(Buffer, "PROFILE END"))
        break;                          /* Empty lines may follow and feof() then is FALSE
                                           and we loop again, reading invalid input. Avoid
                                           this by breaking out of the loop */
    else
        {                               /* If a SUBMENU END follows ignore it, because
                                           execution will return at beginning of the loop
                                           otherwise add a new item to the end of the
                                           linked list */
        if(!strstr(Buffer, "SUBMENU END"))
            {
            MENUDATA    *pMenuDataTemp;

            pMenuDataTemp=AllocateMenuData();
            pMenuData->Next=pMenuDataTemp;
            pMenuDataTemp->Back=pMenuData;
            pMenuData=pMenuData->Next;
            }
        }
} while(!feof(Pc2Profile));
return;
}

/*--------------------------------------------------------------------------------------*\
 * This recursive procedure saves the popup menu into the profile.                      *
 * Req:                                                                                 *
 *      pMenuData ..... A pointer to an MENUDATA structure.                             *
 * Returns:                                                                             *
 *      none                                                                            *
\*--------------------------------------------------------------------------------------*/
void SaveMenu(MENUDATA *pMenuData)
{
do
{
    if(pMenuData->Item==ENTRYSUBMENU)
        {
/*                                                                                      *\
 * If this is a SUBMENU, then write the header SUBMENU BEGIN and then write the profile *
 * data from teh MENUDATA structure pointet by pMenuData. Then increment the depth      *
 * counter and call this procedure recursivly again. After coming back, restore the     *
 * depth counter and write the header SUBMENU END.                                      *
\*                                                                                      */
        fprintf(Pc2Profile, "SUBMENU BEGIN\n");
        fprintf(Pc2Profile, "PgmTitle: %s\n", pMenuData->PgmTitle);
        SaveMenu(pMenuData->Submenu);
        fprintf(Pc2Profile, "SUBMENU END\n");
        }
    if(pMenuData->Item==ENTRYMENUITEM)
        {
/*                                                                                      *\
 * If it is a MENUITEM, so write the header MENUITEM and then write the profile data    *
 * from the MENUDATA structure pointed by pMenuData.                                    *
\*                                                                                      */
        fprintf(Pc2Profile, "MENUITEM\n");
        fprintf(Pc2Profile, "PgmTitle: %s\n", pMenuData->PgmTitle);
        fprintf(Pc2Profile, "PgmName: %s\n", pMenuData->PgmName);
        if(strcmp(pMenuData->PgmDirectory, ""))
            fprintf(Pc2Profile, "PgmDirectory: %s\n", pMenuData->PgmDirectory);
        if(strcmp(pMenuData->PgmInputs, ""))
            fprintf(Pc2Profile, "PgmInputs: %s\n", pMenuData->PgmInputs);
                                        /* Write DOS Settings only if available */
        if(strlen(pMenuData->PgmDosSettings)!=0)
            {
            fprintf(Pc2Profile, "DOSSETTINGS BEGIN\n");
            fprintf(Pc2Profile, "%s", pMenuData->PgmDosSettings);
            fprintf(Pc2Profile, "DOSSETTINGS END\n");
            }
        if(pMenuData->SessionType!=SSF_TYPE_DEFAULT)
            fprintf(Pc2Profile, "SessionType: %lu\n", (ULONG)pMenuData->SessionType);
        if(pMenuData->PgmControl!=SSF_CONTROL_VISIBLE)
            fprintf(Pc2Profile, "PgmControl: %lu\n", (ULONG)pMenuData->PgmControl);
        if(pMenuData->FgBg & SSF_FGBG_BACK)
            fprintf(Pc2Profile, "FgBg: %lu\n", (ULONG)pMenuData->FgBg);
        if(pMenuData->PgmControl & SSF_CONTROL_SETPOS)
            {
            fprintf(Pc2Profile, "InitXPos: %ld\n", (LONG)pMenuData->InitXPos);
            fprintf(Pc2Profile, "InitYPos: %ld\n", (LONG)pMenuData->InitYPos);
            fprintf(Pc2Profile, "InitXSize: %lu\n", (ULONG)pMenuData->InitXSize);
            fprintf(Pc2Profile, "InitYSize: %lu\n", (ULONG)pMenuData->InitYSize);
            }
        }
/*                                                                                      *\
 * If one is available, get the next element in the linked list, else we are at the end *
 * either at a leaf or at the real last element, in both cases shell back one level.    *
 * Shell back either exits this procedure completle (we have written the complete       *
 * linked list) or on level (we have written a complete submenu leaf).                  *
\*                                                                                      */
    if(pMenuData->Next!=NULL) pMenuData=pMenuData->Next;
    else break;
} while(TRUE);
}

/*--------------------------------------------------------------------------------------*\
 * This recursive procedure searches through the linked list for an element.            *
 * Req:                                                                                 *
 *      pMD ........... A pointer to the first element to search on                     *
 *      id ............ Pointer to the ID to search for (pointer because we don't want  *
 *                      to get a copy during recursion                                  *
 * Returns:                                                                             *
 *      MENUDATA * .... Pointer to match or NULL if not found                           *
\*--------------------------------------------------------------------------------------*/
MENUDATA        *SearchItem(MENUDATA *pMD, ULONG *id)
{
static MENUDATA *pMDReturn;

do
{
                                        /* If found, save the pointer of it, set ID to the
                                           value 1 which never occures in the linked list
                                           to detect the match at the end of the recursion */
    if(pMD->id==*id) { pMDReturn=pMD; *id=TRUE; break; }
                                        /* Shell into the Submenus */
    if(pMD->Item==ENTRYSUBMENU)
        SearchItem(pMD->Submenu, id);
    if(pMD->Next!=NULL) pMD=pMD->Next;  /* Keep on searching until found or end of linked list */
    else
        {                               /* We're at the end of the linked list */
        if(*id!=TRUE) pMDReturn=NULL;   /* If we didn't find the item return NULL */
        break;
        }
} while(TRUE);
return(pMDReturn);
}

/*--------------------------------------------------------------------------------------*\
 * This procedure adds/changes/query/removes an item to/from the Popup-Menu.            *
 * Req:                                                                                 *
 *      msg ........... What to do                                                      *
 *      mp1 ........... Parameter 1                                                     *
 *      mp2 ........... Parameter 2                                                     *
 * Returns:                                                                             *
 *      MRESULT ....... Returned value of function                                      *
\*--------------------------------------------------------------------------------------*/
MRESULT SetPopupMenu(ULONG msg, MPARAM mp1, MPARAM mp2)
{
MENUDATA        *pMD;
ULONG           id;
MENUITEM        miMI;                   /* Update menus with this structure */
HWND            hwndMenu;               /* Menu window handle */
HWND            hwndSubMenu;            /* Window handle of a pulldown menu within the menu bar */
MRESULT         mr;                     /* PM API result */
BOOL            bResult;

bResult=FALSE;
switch(msg)
{
/*                                                                                      *\
 * Syntax: MM_INSERTITEM(MENUITEM|SUBMENU), MENUDATA *pMD, ULONG id                     *
\*                                                                                      */
/*                                                                                      *\
 * Insert a Menuitem, a Submenu or Menuentry, into a (Sub)menu, even if it is empty.    *
\*                                                                                      */
case MM_INSERTITEMMENUITEM:
/*                                                                                      *\
 * Insert a Menuitem, a Submenu or Menuentry as the first child entry of a parent       *
 * Submenu.                                                                             *
\*                                                                                      */
case MM_INSERTITEMSUBMENU:
    pMD=PVOIDFROMMP(mp1);               /* Get pointer to MENUDATA structure to insert */
    id=LONGFROMMP(mp2);                 /* Get id to insert after */
/*                                                                                      *\
 * An item (Menuitem or Submenu) is to be inserted into the Popup-Menu, either after    *
 * a Menuitem or as the first item of a/the  (Sub)menu.                                 *
\*                                                                                      */
    if(WinSendMsg(
        hwndPopupMenu,
        MM_QUERYITEM,                   /* Query a menuitem */
        MPFROM2SHORT(id, TRUE),         /* Identifier, include submenus */
        (MPARAM)&miMI)==FALSE)          /* Into MENUITEM structure */
        miMI.hwndSubMenu=0;
                                        /* If the item after we insert is a Submenu, then
                                           use the Submenu handle to insert new items,
                                           otherwise use the handle of the previous item */
    if((miMI.hwndSubMenu!=0) && (msg==MM_INSERTITEMSUBMENU))
        {
        hwndMenu=miMI.hwndSubMenu;
        id=MIT_END;
        }
    if(msg==MM_INSERTITEMMENUITEM)
        {                               /* If this is the first item, use the Popup-Menu
                                           window handle */
        if(pMD->Back==NULL) hwndMenu=hwndPopupMenu;
                                        /* If we insert after an available item, get it's
                                           window handle */
        else hwndMenu=(pMD->Back)->hwndItem;
        }
                                        /* If previous exists, insert after the item with
                                           ID id */
    if(id!=(ULONG)MIT_END) miMI.iPosition++;
    else miMI.iPosition=id;             /* Insert at end MIT_END */
    miMI.afAttribute=0;                 /* Special attribute */
    miMI.id=pMD->id;                    /* Item identifier */
    miMI.hItem=0;                       /* No handle */
    if(pMD->Item==ENTRYSUBMENU)
        {                               /* If we insert a Submenu, than we need to obtain
                                           a handle to create one */
        hwndSubMenu=WinCreateMenu(      /* Create a submenu menuitem */
            hwndMenu,                   /* Owner- and parent-window handle */
            NULL);                      /* Binary menu template */
        miMI.afStyle=MIS_SUBMENU;       /* Style to insert */
        miMI.hwndSubMenu=hwndSubMenu;   /* Pulldown menu */
        }
    else
        {                               /* We insert a Menuitem */
        miMI.afStyle=MIS_TEXT;          /* Style to insert */
        miMI.hwndSubMenu=0;             /* No pulldown menu */
        }
    pMD->hwndItem=hwndMenu;             /* Save the window handle of the item */
    mr=WinSendMsg(
        hwndMenu,
        MM_INSERTITEM,                  /* Insert a menu item */
        &miMI,                          /* Item to insert */
        pMD->PgmTitle);                 /* Text to insert */
    if(((SHORT)mr==MIT_ERROR) || ((SHORT)mr==MIT_MEMERROR))
        GEN_ERR(hab, hwndFrame, hwndClient);
    else bResult=TRUE;
    break;

/*                                                                                      *\
 * Syntax: MM_MOVEMENUITEM, MENUDATA *pMDSource, MENUDATA *pMDDestination               *
\*                                                                                      */
case MM_MOVEMENUITEM:
/*                                                                                      *\
 * Move a MENUITEM structure with idSource after the idDestination.                     *
\*                                                                                      */
    {
    MENUDATA    *pMDSource;
    MENUDATA    *pMDDestination;
    ULONG       idSource;               /* Id of Menuitem to be moved */
    ULONG       idDestination;          /* Id of Menuitem after which the removed Menuitem
                                           will be inserted */
    MENUITEM    miSource;               /* MENUITEM structure of to be moved Menuitem */
    MENUITEM    miDestination;          /* MENUITEM structure of Menuitem after which
                                           the removed Menuitem will be inserted */

    pMDSource=PVOIDFROMMP(mp1);
    pMDDestination=PVOIDFROMMP(mp2);
    idSource=pMDSource->id;             /* Get id of to be removed Menuitem */
    idDestination=pMDDestination->id;   /* Get id of Menuitem after which removed Menuitem
                                           will be inserted */
/*                                                                                      *\
 * If the source and destination Menuitem are elements of the same level then they have *
 * the same item handle.                                                                *
\*                                                                                      */
    if(pMDSource->hwndItem==pMDDestination->hwndItem)
        bResult=TRUE;
    else
        bResult=FALSE;
                                        /* Query all (Sub)menus for to be moved Menuitem */
    WinSendMsg(hwndPopupMenu, MM_QUERYITEM,
        MPFROM2SHORT(idSource, TRUE), (MPARAM)&miSource);
                                        /* Delete the to be moved Menuitem. Don't use MM_DELETEITEM
                                           because it frees all OS/2 internal structures,
                                           whereas MM_REMOVEITEM doesn't free them */
    WinSendMsg(hwndPopupMenu, MM_REMOVEITEM,
        MPFROM2SHORT(idSource, TRUE), (MPARAM)NULL);
                                        /* Query all (Sub)menus for Menuitem after which
                                           the removed Menuitem will be inserted */
    WinSendMsg(hwndPopupMenu, MM_QUERYITEM,
        MPFROM2SHORT(idDestination, TRUE), (MPARAM)&miDestination);
 
    if(bResult==TRUE)
        {                               /* If both are on the same current level of Menuitems
                                           insert removed Menuitem after destination Menuitem */
        if(pMDDestination==pPopupMenu)
                                        /* If the destination of the Source Menuitem is in the
                                           root of all(Sub)menus, than insert at 0-based
                                           position 2, because position 0 is used by PC/2
                                           Setup and position 1 is the seperator bar */
            miSource.iPosition=2;
        else                            /* If the destination of the Source Menuitem follows
                                           any previous Menuitem in the same level, just
                                           insert it one position behind */
            miSource.iPosition=++miDestination.iPosition;
        hwndMenu=pMDDestination->hwndItem;
        mr=WinSendMsg(hwndMenu, MM_INSERTITEM, &miSource, pMDSource->PgmTitle);
        }
    else
        {                               /* If the destination of the source Menuitem is the
                                           first position of a Submenu, insert is a 0-base
                                           posisition 0 */
        hwndMenu=miDestination.hwndSubMenu;
        miSource.iPosition=0;
        mr=WinSendMsg(hwndMenu, MM_INSERTITEM, &miSource, pMDSource->PgmTitle);
        }

    }
    break;

/*                                                                                      *\
 * Syntax: MM_SETITEMTEXT, MENUDATA *pMD, ULONG id                                      *
\*                                                                                      */
case MM_SETITEMTEXT:
    pMD=PVOIDFROMMP(mp1);               /* Get pointer to MENUDATA structure to update */
    id=LONGFROMMP(mp2);                 /* Get id to update */
/*                                                                                      *\
 * A available menuitem was selected to change. Change the text of the menuitem to the  *
 * new one.                                                                             *
\*                                                                                      */
    if(WinSendMsg(
        hwndPopupMenu,
        MM_SETITEMTEXT,                 /* Set the text of a menuitem */
        MPFROMSHORT(id),                /* Item ID */
        (MPARAM)pMD->PgmTitle)==FALSE)  /* New menuitem text */
        GEN_ERR(hab, hwndFrame, hwndClient);
    else bResult=TRUE;
    break;

case MM_DELETEITEM:
    pMD=PVOIDFROMMP(mp1);               /* Get pointer to MENUDATA structure to delete */
    id=LONGFROMMP(mp2);                 /* Get id to delete */
/*                                                                                      *\
 * A available menuitem was selected to delete. Delete the specified menuitem.          *
\*                                                                                      */
    {
    if(pMD->Item==ENTRYSUBMENU)
        {                               /* It the menuitem is a Submenu, also delete the
                                           first item of it (which should be empty) */
        mr=WinSendMsg(
            hwndPopupMenu,
            MM_DELETEITEM,              /* Delete a menuitem */
                                        /* Item ID, include Submenus */
            MPFROM2SHORT((pMD->Submenu->id), TRUE),
            (MPARAM)NULL);
        }
    mr=WinSendMsg(
        hwndPopupMenu,
        MM_DELETEITEM,                  /* Delete a menuitem */
        MPFROM2SHORT(id, TRUE),         /* Item ID, include Submenus */
        (MPARAM)NULL);
    bResult=TRUE;
    }
    break;
}
return(MPFROMSHORT(bResult));
}

/*--------------------------------------------------------------------------------------*\
 * This procedure handles to copy a fully qualified path & filename into the corres-    *
 * ponding entryfields of the Program Installation dialog.                              *
 * Req:                                                                                 *
 *      hwndDlg ....... handle of Program installation dialog                           *
 *      pucFullFileName fully qualified path & filename of application to add           *
 *                      the name of an object to add                                    *
 *      bObject ....... TRUE if it is an WPS object                                     *
\*--------------------------------------------------------------------------------------*/
void InstallFilename2Dialog(HWND hwndDlg, UCHAR *pucFullFileName, BOOL bObject)
{
UCHAR   ucBuffer[260];                  /* Longer than 256 because of "s */
UCHAR   *pucTemp;
BOOL    bBatchFile=FALSE;
ULONG   ulAppType;                      /* Type of application we're installing */
USHORT  usSessionType;

strupr(pucFullFileName);                /* First convert to uppercase to simplify compares */
if(bObject==TRUE)
    {
    usSessionType=SSF_TYPE_WPSOBJECT;   /* It is an WPS object */
                                        /* Set title and object name info entryfields */
    WinSetDlgItemText(hwndDlg, PIEF_PROGRAMTITLE, pucFullFileName);
    WinSetDlgItemText(hwndDlg, PIEF_PATHFILENAME, pucFullFileName);
    WinSetDlgItemText(hwndDlg, PIEF_PARAMETERS, "");
    WinSetDlgItemText(hwndDlg, PIEF_DIRECTORY, "");
    }
else
    {                                   /* It is a file */
                                        /* Get the type of application */
    DosQueryAppType(pucFullFileName, &ulAppType);
    usSessionType=SSF_TYPE_DEFAULT;     /* Assume Shell determined for default */
    if((ulAppType & 0x7)==FAPPTYP_WINDOWAPI) usSessionType=SSF_TYPE_PM;
    if((ulAppType & 0x7)==FAPPTYP_WINDOWCOMPAT) usSessionType=SSF_TYPE_WINDOWABLEVIO;
    if(ulAppType & FAPPTYP_DOS) usSessionType=SSF_TYPE_WINDOWEDVDM;
    if(ulAppType & FAPPTYP_WINDOWSREAL) usSessionType=PROG_WINDOW_REAL;
    if(ulAppType & FAPPTYP_WINDOWSPROT) usSessionType=PROG_WINDOW_PROT;
    if(ulAppType & FAPPTYP_WINDOWSPROT31) usSessionType=PROG_31_ENH;
    }
                                        /* Reflect the application type with the Program
                                           Type radiobuttons */
WinSendMsg(hwndDlg, WM_SETUPPROGRAMTYPE,
    MPFROMSHORT(usSessionType), (MPARAM)NULL);
if(bObject==FALSE)
    {
                                        /* Now test for a OS/2 batch file */
    if(strstr(pucFullFileName, ".CMD")!=NULL)
        {
        bBatchFile=TRUE;
        if(strchr(pucFullFileName, ' ')!=NULL)
            {                           /* If path and filename contains spaces, insert
                                           two quotation marks */
            strcpy(ucBuffer, "/c \"\"");
            strcat(ucBuffer, pucFullFileName);
            strcat(ucBuffer, "\"\"");
            }
        else
            {                           /* Else add just /c to [path]filename.cmd */
            strcpy(ucBuffer, "/c ");
            strcat(ucBuffer, pucFullFileName);
            }
        }
                                        /* Now test for a DOS batch file */
    if(strstr(pucFullFileName, ".BAT")!=NULL)
        {
        bBatchFile=TRUE;
        strcpy(ucBuffer, "/c ");        /* Add just /c to [path]filename.cmd */
        strcat(ucBuffer, pucFullFileName);
        }
    if(bBatchFile==TRUE)
        {                               /* Set batchfile as parameter and empty path & filename */
        WinSetDlgItemText(hwndDlg, PIEF_PARAMETERS, ucBuffer);
        WinSetDlgItemText(hwndDlg, PIEF_PATHFILENAME, "");
        }
    else
        {                               /* Set full qualified path and empty parameters */
        WinSetDlgItemText(hwndDlg, PIEF_PATHFILENAME, pucFullFileName);
        WinSetDlgItemText(hwndDlg, PIEF_PARAMETERS, "");
        }
    strcpy(ucBuffer, pucFullFileName);  /* Save full path & filename */
                                        /* Extract filename */
    pucTemp=pucFullFileName+strlen(pucFullFileName);
    for( ; (*pucTemp!='\\') && (pucTemp>=pucFullFileName); pucTemp--);
                                        /* Set filename */
    WinSetDlgItemText(hwndDlg, PIEF_PROGRAMTITLE, (pucTemp+1));
    *pucTemp='\0';                      /* Get path as working directory */
                                        /* Set working directory */
    WinSetDlgItemText(hwndDlg, PIEF_DIRECTORY, pucFullFileName);
    }
}

/*--------------------------------------------------------------------------------------*\
 * This procedure disables or enables child windows of a dialog window according to the *
 * bDisable flag.                                                                       *
 * Req:                                                                                 *
 *      hwndDlg ....... handle of Program installation dialog                           *
 *      usDialogIDs ... array of IDs of the child windows of a dialog                   *
 *      usItemCount ... number of IDs in the array                                      *
 *      ulStyle ....... WS_VISIBLE | WS_DISABLED or not                                 *
\*--------------------------------------------------------------------------------------*/
void    DisableDialogItem(HWND hwndDlg, USHORT usDialogIDs[], USHORT usItemCount, ULONG ulStyle)
{
USHORT  usTemp;

if(ulStyle&WS_DISABLED)
                                        /* Enumerate and disable all child windows */
    for(usTemp=0; usTemp<usItemCount; usTemp++)
        WinEnableWindow(WinWindowFromID(hwndDlg, usDialogIDs[usTemp]), FALSE);
else
                                        /* Enumerate and enable all child windows */
    for(usTemp=0; usTemp<usItemCount; usTemp++)
        WinEnableWindow(WinWindowFromID(hwndDlg, usDialogIDs[usTemp]), TRUE);
if(ulStyle&WS_VISIBLE)
                                        /* Enumerate and show all child windows */
    for(usTemp=0; usTemp<usItemCount; usTemp++)
        WinSetWindowPos(WinWindowFromID(hwndDlg, usDialogIDs[usTemp]),
            0, 0, 0, 0, 0, SWP_SHOW);
else
                                        /* Enumerate and hide all child windows */
    for(usTemp=0; usTemp<usItemCount; usTemp++)
        WinSetWindowPos(WinWindowFromID(hwndDlg, usDialogIDs[usTemp]),
            0, 0, 0, 0, 0, SWP_HIDE);
}

/*--------------------------------------------------------------------------------------*\
 * This procedure accesses the PC2.INI configuration file.                              *
 * Req:                                                                                 *
 *      pucFilenameINI. pointer to path of PC2.INI                                      *
 *      bRead ......... TRUE/FALSE if read/write from/to PC2.INI                        *
 * Ref:                                                                                 *
 *      HookParameters. read/write from/to PC2.INI                                      *
\*--------------------------------------------------------------------------------------*/
void    INIAccess(UCHAR *pucFilenameINI, BOOL bRead)
{
HINI    hiniPC2INI;
ULONG   ulTemp;
                                        /* Open PC2.INI */
hiniPC2INI=PrfOpenProfile(hab, pucFilenameINI);
if(hiniPC2INI!=NULLHANDLE)
    {                                   /* Only try to access a valid PC2.INI */
    if(bRead==TRUE)
        {
        ulTemp=sizeof(ULONG);
        if(PrfQueryProfileData(         /* Query binary data from profile */
            hiniPC2INI,                 /* Handle of profile */
                                        /* Application name */
            "PC/2 Desktop Configuration",
            "Desktop Status",           /* Key name */
            &HookParameters.ulStatusFlag,
            &ulTemp)==FALSE)            /* Size of value data */
            HookParameters.ulStatusFlag=0;
        if(PrfQueryProfileData(hiniPC2INI, "PC/2 Desktop Configuration", "Scroll Percentage",
            &HookParameters.ulScrollPercentage, &ulTemp)==FALSE)
            HookParameters.ulScrollPercentage=100;
        ulTemp=sizeof(HookParameters.ucDesktopName);
        if(PrfQueryProfileData(hiniPC2INI, "PC/2 Desktop Configuration", "Desktop Name",
            HookParameters.ucDesktopName, &ulTemp)==FALSE)
            strcpy(HookParameters.ucDesktopName, "OS/2 2.0 Desktop");
        }
    else
        {
        WinSetPointer(                  /* Set wait pointer */
            HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE));
        PrfWriteProfileData(            /* Write binary data to profile */
            hiniPC2INI,                 /* Handle of profile */
                                        /* Application name */
            "PC/2 Desktop Configuration",
            "Desktop Status",           /* Key name */
                                        /* Value data */
            &HookParameters.ulStatusFlag,
            sizeof(ULONG));             /* Size of value data */
        PrfWriteProfileData(hiniPC2INI, "PC/2 Desktop Configuration",
            "Scroll Percentage", &HookParameters.ulScrollPercentage, sizeof(ULONG));              /* Size of value data */
        PrfWriteProfileData(hiniPC2INI, "PC/2 Desktop Configuration",
            "Desktop Name", HookParameters.ucDesktopName, sizeof(HookParameters.ucDesktopName));
        WinSetPointer(                  /* Set arrow pointer */
            HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
        }
    }
else USR_ERR("Can't access PC2.INI - assuming default values...", hwndFrame, hwndClient);
}


[ RETURN TO DIRECTORY ]