/***********************************************************************\ * 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 /*--------------------------------------------------------------------------------------*\ * 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