home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1995 November / PCWK1195.iso / inne / podstawy / os2 / nakladki / pc2v190.exe / SOURCE.ZIP / Source / Utility.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-01  |  152.6 KB  |  2,858 lines

  1. /***********************************************************************\
  2.  *                                PC2.c                                *
  3.  *           Copyright (C) by Stangl Roman, 1993, 1994, 1995           *
  4.  * This Code may be freely distributed, provided the Copyright isn't   *
  5.  * removed, under the conditions indicated in the documentation.       *
  6.  *                                                                     *
  7.  * Utility.c    General functions that are not window procedures.      *
  8.  *                                                                     *
  9. \***********************************************************************/
  10.  
  11. static char RCSID[]="@(#) $Header: Utility.c Version 1.90 05,1995 $ (LBL)";
  12.  
  13. #define         _FILE_  "PC/2 - Utility.c V1.90"
  14.  
  15. #define         INCL_DOSDEVICES
  16.  
  17. #include        "PC2.h"                 /* User include files */
  18. #include        "Error.h"
  19. #ifndef __EMX__
  20. #include        <bsedev.h>
  21. #endif /* __EMX__ */
  22.  
  23. #ifdef __EMX__                          /* For compiling with EMX C/C++ Rolf Knebel suggested
  24.                                            to define constants not defined by the EMX package */
  25. #define         IOCTL_DISK          0x08
  26. #define         DSK_BLOCKREMOVABLE  0x20
  27.                                         /* Thanks to Roland Emmerich for testing EMX and GCC
  28.                                            compatibility */
  29. define          DosSetPrty          DosSetPriority
  30. #endif /* __EMX__ */
  31.                                         /* IOCTL constants missing in BSEDEV.H ? */
  32. #define         IOCTL_DRIVEANDDISK  0x80
  33. #define         IOCTL_CHARDEVICE    0x82
  34. #define         DSK_DEVICESTATUS    0x60
  35.  
  36. typedef struct  _SESSIONTYPE        SESSIONTYPE;
  37. typedef struct  _PGMCONTROL         PGMCONTROL;
  38.  
  39. struct  _SESSIONTYPE                    /* Structure to convert binary SessionTypes to ASCII and
  40.                                            vice versa */
  41. {
  42. USHORT  usSessionType;                  /* Binary PROG_* values */
  43. UCHAR   *pucSessionType;                /* ASCII PROG_* strings */
  44. };
  45.  
  46. SESSIONTYPE     SessionType[]=          /* Map 1.80 session types to 1.90 when reading PC2.CFG */
  47. {
  48.     { 1, "PROG_FULLSCREEN"},
  49.     { 2, "PROG_WINDOWABLEVIO"},
  50.     { 3, "PROG_PM"},
  51.     { 4, "PROG_VDM"},
  52.     { 7, "PROG_WINDOWEDVDM"},
  53.     {10, "PROG_WINDOW_REAL"},
  54.     {11, "PROG_WINDOW_PROT"},
  55.     {16, "PROG_31_STDSEAMLESSCOMMON"},
  56.     {18, "PROG_31_ENHSEAMLESSCOMMON"},
  57.     {19, "PROG_31_ENH"},
  58.     {21, "PROG_WPSOBJECT"}
  59. };
  60.  
  61. #define SESSIONTYPESIZE         (sizeof(SessionType)/sizeof(SessionType[0]))
  62.  
  63. struct  _PGMCONTROL                     /* Structure to convert bitmapped PgmControl style to ASCII and
  64.                                            vice versa */
  65. {
  66. USHORT  usPgmControl;                   /* Bitmapped SSF_* values */
  67. UCHAR   *pucPgmControl;                 /* ASCII SSF_* strings */
  68. };
  69.  
  70. PGMCONTROL      PgmControl[]=
  71. {
  72.     {0x0000, "SSF_CONTROL_VISIBLE"},
  73.     {0x0001, "SSF_CONTROL_INVISIBLE"},
  74.     {0x0002, "SSF_CONTROL_MAXIMIZE"},
  75.     {0x0004, "SSF_CONTROL_MINIMIZE"},
  76.     {0x0008, "SSF_CONTROL_NOAUTOCLOSE"},
  77.     {0x4000, "SSF_CONTROL_AUTOSTART"},
  78.     {0x8000, "SSF_CONTROL_SETPOS"}
  79. };
  80.  
  81. #define PGMCONTROLSIZE          (sizeof(PgmControl)/sizeof(PgmControl[0]))
  82.  
  83. /*--------------------------------------------------------------------------------------*\
  84.  * Procedure to initialize a window and its message queue.                              *
  85.  * Req:                                                                                 *
  86.  *      pHab .......... A pointer to be filled with the anchor block of the window      *
  87.  *      pHmq .......... A pointer to be filled with the message queue of the window     *
  88.  * Returns:                                                                             *
  89.  *      TRUE/FALSE .... If called sucessfully/unsucessfully                             *
  90. \*--------------------------------------------------------------------------------------*/
  91. BOOL    WinStartUp(HAB *pHab, HMQ *pHmq)
  92. {
  93.                                         /* Initialize handle of anchor block */
  94. if((*pHab=WinInitialize(0))==NULLHANDLE)
  95.     return(FALSE);
  96.                                         /* Initialize handle of message queue */
  97. if((*pHmq=WinCreateMsgQueue(*pHab, 50))==NULLHANDLE)
  98.     return(FALSE);
  99. return(TRUE);
  100. }
  101.  
  102. /*--------------------------------------------------------------------------------------*\
  103.  * Procedure to initialize HELP.                                                        *
  104.  * Req:                                                                                 *
  105.  *      hab ........... Anchor block handle                                             *
  106.  *      pHelpFile ..... A pointer to helppanel filename, located in PC/2's directory    *
  107.  *      pHwndHelp ..... A pointer to a HWND structure                                   *
  108.  *      pHwndFrame .... Frame window handle to associate help with                      *
  109.  * Returns:                                                                             *
  110.  *      pHwndHelp ..... If called sucessfully/unsucessfully hwnd/NULL                   *
  111. \*--------------------------------------------------------------------------------------*/
  112. BOOL    WinStartHelp(HAB hab, UCHAR *pHelpFile, HWND *pHwndHelp, HWND HwndFrame)
  113. {
  114. HELPINIT        HelpInit;
  115.  
  116. HelpInit.cb=sizeof(HELPINIT);           /* Size of HELPINIT structure */
  117. HelpInit.ulReturnCode=0;                /* Returnvalue from HelpManager */
  118. HelpInit.pszTutorialName=NULL;          /* No tutorial */
  119.                                         /* Ressource of Helptable */
  120. HelpInit.phtHelpTable=(PHELPTABLE)MAKEULONG(MAIN_HELP_TABLE, 0xffff);
  121.                                         /* Ressource in .EXE */
  122. HelpInit.hmodHelpTableModule=NULLHANDLE;
  123.                                         /* No handle */
  124. HelpInit.hmodAccelActionBarModule=NULLHANDLE;
  125. HelpInit.idAccelTable=0;                /* None */
  126. HelpInit.idActionBar=0;                 /* None */
  127.                                         /* Window title of help window */
  128. HelpInit.pszHelpWindowTitle="PC/2 - Program Commander/2 Help";
  129. HelpInit.pszHelpLibraryName=pHelpFile;  /* Library name of help panel via PC/2 directory */
  130. HelpInit.fShowPanelId=0;                /* Panel ID not displayed */
  131. /*                                                                                      *\
  132.  * First assume PC2.HLP where the fully qualified path passed here points to, which is  *
  133.  * the directory PC/2 started from.                                                     *
  134. \*                                                                                      */
  135. *pHwndHelp=WinCreateHelpInstance(       /* Create help */
  136.     hab,                                /* Anchor block */
  137.     &HelpInit);
  138.                                         /* Test for successful help creation */
  139. if((*pHwndHelp) && (!HelpInit.ulReturnCode))
  140.                                         /* Associate HELP with frame window */
  141.     if(WinAssociateHelpInstance(*pHwndHelp, HwndFrame)!=FALSE)
  142.         return(TRUE);
  143. /*                                                                                      *\
  144.  * Second assume PC2.HLP in a directory pointed to by the HELP environment variable,    *
  145.  * and try to create it from there.                                                     *
  146. \*                                                                                      */
  147. HelpInit.ulReturnCode=0;                /* Returnvalue from HelpManager */
  148. HelpInit.pszHelpLibraryName="PC2.HLP";  /* Library name of help panel via HELP path */
  149. *pHwndHelp=WinCreateHelpInstance(hab, &HelpInit);
  150. if((*pHwndHelp) && (!HelpInit.ulReturnCode))
  151.     if(WinAssociateHelpInstance(*pHwndHelp, HwndFrame)!=FALSE)
  152.         return(TRUE);
  153. *pHwndHelp=NULLHANDLE;
  154. return(FALSE);
  155. }
  156.  
  157. /*--------------------------------------------------------------------------------------*\
  158.  * Procedure to close a window and its message queue.                                   *
  159.  * Req:                                                                                 *
  160.  *      pHwndHelp ..... A pointer to HELP window handle                                 *
  161.  *      pHab .......... A pointer to extract the anchor block of the window             *
  162.  *      pHmq .......... A pointer to extract message queue of the window                *
  163.  * Returns:                                                                             *
  164.  *      TRUE/FALSE .... If called sucessfully/unsucessfully                             *
  165. \*--------------------------------------------------------------------------------------*/
  166. BOOL    WinCloseDown(HWND *pHwndHelp, HAB *pHab, HMQ *pHmq)
  167. {
  168. if(!*pHwndHelp)                         /* Release HELP */
  169.     WinDestroyHelpInstance(*pHwndHelp);
  170. if(*pHmq!=NULLHANDLE)                   /* Release handle of message queue */
  171.     WinDestroyMsgQueue(*pHmq);
  172. if(*pHab!=NULLHANDLE)                   /* Release handle of anchor block */
  173.     WinTerminate(*pHab);
  174.                                         /* Any error during WinStartUp */
  175. if((*pHab==NULLHANDLE) || (*pHmq==NULLHANDLE)) return(FALSE);
  176. else return(TRUE);
  177. }
  178.  
  179. /*--------------------------------------------------------------------------------------*\
  180.  * Allocate a storage area that contains the environment of PC/2 inclusive additions/   *
  181.  * replacements made from the data entered in the Envrionment notebook page.            *
  182.  * Req:                                                                                 *
  183.  *      PgmEnvironment  A pointer to the user entered Environment in the form of:       *
  184.  *                      EnvVar1=Value1\r\nEnvVar2=Value2\r\n...\0                       *
  185.  *      pib_pchenv      The entry from PC/2's process information block, which has the  *
  186.  *                      same form as the returned composite environment pucEnvironment. *
  187.  * Returns:                                                                             *
  188.  *      pucEnvironment  A pointer to the Environment to inherit from PC/2, which must   *
  189.  *                      be freed after the session was started, in the form of:         *
  190.  *                      EnvVar1=Value1\0EnvVar2=Value2\0...EnvVarn=Valuen\0\0           *
  191. \*--------------------------------------------------------------------------------------*/
  192. UCHAR   *CreateEnvironment(PSZ PgmEnvironment)
  193. {
  194. UCHAR   *pucEnvironment;                /* Merge of PC/2's and user added/replaced environment */
  195. UCHAR   *pucEnvironmentEntry;           /* Pointer within pucEnvironment to add next entry */
  196. UCHAR   **ppucEnvironment;              /* Temporary table containing all EnvironmentVariable=Value */
  197. UCHAR   **ppucEnvironmentEntry;         /* Pointer within ppucEnvironment to add next entry
  198.                                            entry pointers */
  199. ULONG   ulEnvironmentSize;              /* Number of bytes required for all EnvironmentVariable=Value
  200.                                            strings that get inherited by PC/2 */
  201. ULONG   ulEnvironmentEntries;           /* Number of EnvironmentVariable=Value entries that are
  202.                                            to be returned in pucEnvironment at maximum */
  203. UCHAR   *pucPC2EnvironmentEntry;        /* Pointer to an entry in PC/2's environment */
  204. UCHAR   *pucUserEnvironmentEntry;       /* Pointer to an EnvironmentVariable in user's environment
  205.                                            additions/replacements */
  206. UCHAR   *pucUserEnvironmentEntryValue;  /* Pointer to an Value in user's environment additions/replacements */
  207. UCHAR   *pucTemp;
  208.  
  209.  
  210.                                         /* PC/2's environment in the process information block
  211.                                            is separated by \0, and terminated by \0\0 */
  212.                                         /* Note: During testing the condition of the for-loop, we
  213.                                            assume that when pucPC2EnvironmentEntry is not true,
  214.                                            *pucPC2EnvironmentEntry is not evaluated, which would
  215.                                            be typically for modern compilers */
  216. for(ulEnvironmentEntries=0, ulEnvironmentSize=sizeof('\0'), pucPC2EnvironmentEntry=(UCHAR *)pHP->pPib->pib_pchenv;
  217.     (pucPC2EnvironmentEntry && *pucPC2EnvironmentEntry);
  218.     ulEnvironmentEntries++, pucPC2EnvironmentEntry=strchr(pucPC2EnvironmentEntry, '\0'),
  219.         (pucPC2EnvironmentEntry ? pucPC2EnvironmentEntry++ : pucPC2EnvironmentEntry))
  220.     {
  221.     ulEnvironmentSize+=strlen(pucPC2EnvironmentEntry);
  222.     }
  223.                                         /* Count entries of user's environment additions/replacements */
  224. for(pucUserEnvironmentEntry=PgmEnvironment;
  225.     pucUserEnvironmentEntry;
  226.     ulEnvironmentEntries++, pucUserEnvironmentEntry=strstr(pucUserEnvironmentEntry, "\r\n"),
  227.         (pucUserEnvironmentEntry ? pucUserEnvironmentEntry+=2 : pucUserEnvironmentEntry))
  228.     {
  229.     pucTemp=strstr(pucUserEnvironmentEntry, "\r\n");
  230.     if(pucTemp) ulEnvironmentSize+=(pucTemp-pucUserEnvironmentEntry+1);
  231.     }
  232.                                         /* Allocate the temporary table to merge PC/2's and
  233.                                            user entered environment entries */
  234. ppucEnvironment=ppucEnvironmentEntry=(UCHAR **)malloc(ulEnvironmentEntries*sizeof(UCHAR *));
  235.                                         /* Copy PC/2's environment into temporary table, from which
  236.                                            additional user environment entries will be added or
  237.                                            existing one will be replaced */
  238. for(pucPC2EnvironmentEntry=pHP->pPib->pib_pchenv;
  239.     (pucPC2EnvironmentEntry && *pucPC2EnvironmentEntry);
  240.     pucPC2EnvironmentEntry=strchr(pucPC2EnvironmentEntry, '\0'),
  241.         (pucPC2EnvironmentEntry ? pucPC2EnvironmentEntry++ : pucPC2EnvironmentEntry))
  242.     {
  243.     *ppucEnvironmentEntry=strdup(pucPC2EnvironmentEntry);
  244.     *(++ppucEnvironmentEntry)=NULL;
  245.     }
  246.                                         /* Now add user environment entries which can't be found
  247.                                            in PC/2's environment at the bottom of the temporary table
  248.                                            or replace matching entries */
  249. for(pucUserEnvironmentEntry=PgmEnvironment;
  250.     (pucUserEnvironmentEntry && *pucUserEnvironmentEntry);
  251.     pucUserEnvironmentEntry=strstr(pucUserEnvironmentEntry, "\r\n"),
  252.         (pucUserEnvironmentEntry ? pucUserEnvironmentEntry+=2 : pucUserEnvironmentEntry))
  253.     {
  254.     ULONG   ulUserEnvironmentEntrySize;
  255.     ULONG   ulUserEnvironmentVariableSize;
  256.  
  257.     ulUserEnvironmentEntrySize=ulUserEnvironmentVariableSize=0;
  258.                                         /* Get the length of current EnvironmentVariable=Value
  259.                                            entry in user environment */
  260.     pucTemp=strstr(pucUserEnvironmentEntry, "\r\n");
  261.     if(pucTemp) ulUserEnvironmentEntrySize=pucTemp-pucUserEnvironmentEntry;
  262.                                         /* Get the length of current EnvironmentVariable in user
  263.                                            environment */
  264.     pucTemp=strstr(pucUserEnvironmentEntry, "=");
  265.     if(pucTemp) ulUserEnvironmentVariableSize=pucTemp-pucUserEnvironmentEntry;
  266.     pucUserEnvironmentEntryValue=pucTemp+1;
  267.                                         /* Now test for EnvironmentVariables named BEGINLIBPATH and
  268.                                            ENDLIBPATH. It these are found, than they are not added
  269.                                            to the environment, but DosSetExtLIBPATH are called
  270.                                            to write them into PC/2's process information block
  271.                                            to inherit them. Both are not environment variables, CMD.EXE
  272.                                            and PC/2 just treat them this way because the user
  273.                                            should set them consistent with environment variables for
  274.                                            simplicity */
  275.     if((strstr(pucUserEnvironmentEntry, "BEGINLIBPATH=")) ||
  276.         (strstr(pucUserEnvironmentEntry, "ENDLIBPATH=")))
  277.         {
  278.         UCHAR   ucDynamicLibPath[LENENVENTRY];
  279.  
  280.  
  281.         memset(ucDynamicLibPath, '\0', sizeof(ucDynamicLibPath));
  282.         strncpy(ucDynamicLibPath, pucUserEnvironmentEntryValue,
  283.             ulUserEnvironmentEntrySize-ulUserEnvironmentVariableSize-1);
  284.         if(strstr(pucUserEnvironmentEntry, "BEGINLIBPATH="))
  285.             if(pHP->DosSetExtLIBPATH)
  286.                 pHP->DosSetExtLIBPATH(ucDynamicLibPath, BEGINLIBPATH);
  287.         if(strstr(pucUserEnvironmentEntry, "ENDLIBPATH="))
  288.             if(pHP->DosSetExtLIBPATH)
  289.                 pHP->DosSetExtLIBPATH(ucDynamicLibPath, ENDLIBPATH);
  290.         continue;                       /* We don't set them into the environment */
  291.         }
  292.                                         /* Now try to locate the EnvironmentVariable just found
  293.                                            in PC/2's environment. If it is found replace it, otherwise
  294.                                            add it at the bottom of the temporary table */
  295.     for(ppucEnvironmentEntry=ppucEnvironment; *ppucEnvironmentEntry; ppucEnvironmentEntry++)
  296.         {
  297.                                         /* Is the current user EnvironmentVariable the current
  298.                                            EnvironmentVariable of PC/2's environment iterated.
  299.                                            We compare the strings EnvironmentVariable= including
  300.                                            "=", because otherwise we could match substrings too */
  301.         if(strncmp(*ppucEnvironmentEntry, pucUserEnvironmentEntry, ulUserEnvironmentVariableSize+1)==0)
  302.             {
  303.                                         /* We also accept %EnvironmentVariable% in the value of the
  304.                                            current user EnvironmentVariable */
  305.             UCHAR   ucCompositeEnvironmentEntry[LENENVENTRY];
  306.  
  307.                                         /* Create a temporary %EnvrionmentVariable% string to search
  308.                                            the Value string of the user EnvironmentVariable */
  309.             memset(ucCompositeEnvironmentEntry, '\0', sizeof(ucCompositeEnvironmentEntry));
  310.             strcpy(ucCompositeEnvironmentEntry, "%");
  311.             strncpy(&ucCompositeEnvironmentEntry[1], pucUserEnvironmentEntry, ulUserEnvironmentVariableSize);
  312.             strcat(ucCompositeEnvironmentEntry, "%");
  313.             if((pucTemp=strstr(pucUserEnvironmentEntryValue, ucCompositeEnvironmentEntry))!=NULL)
  314.                 {                       /* We found a %EnvironmentVariable% so concatenate it */
  315.                 UCHAR   *pucRealloc;
  316.  
  317.                 memset(ucCompositeEnvironmentEntry, '\0', sizeof(ucCompositeEnvironmentEntry));
  318.                                         /* First add all up to %EnvironmentVariable% from user entry */
  319.                 strncpy(ucCompositeEnvironmentEntry, pucUserEnvironmentEntry, pucTemp-pucUserEnvironmentEntry);
  320.                 pucRealloc=strchr(*ppucEnvironmentEntry, '=');
  321.                 if(pucRealloc)
  322.                     strcat(ucCompositeEnvironmentEntry, ++pucRealloc);
  323.                                         /* Add all after %EnvironmentVariable% from user entry (but
  324.                                            subtract out both "%" signs */
  325.                 strncat(ucCompositeEnvironmentEntry, pucTemp+ulUserEnvironmentVariableSize+2,
  326.                     ulUserEnvironmentEntrySize-(pucTemp-pucUserEnvironmentEntry)-ulUserEnvironmentVariableSize-2);
  327.                 free(*ppucEnvironmentEntry);
  328.                 *ppucEnvironmentEntry=(UCHAR *)malloc(strlen(ucCompositeEnvironmentEntry+1));
  329.                 strcpy(*ppucEnvironmentEntry, ucCompositeEnvironmentEntry);
  330.                 }
  331.             else
  332.                 {
  333.                                         /* We found the environment variable in PC/2's environment,
  334.                                            so replace it */
  335.                 free(*ppucEnvironmentEntry);
  336.                 *ppucEnvironmentEntry=(UCHAR *)malloc(ulUserEnvironmentEntrySize+1);
  337.                 memset(*ppucEnvironmentEntry, '\0', ulUserEnvironmentEntrySize+1);
  338.                 strncpy(*ppucEnvironmentEntry, pucUserEnvironmentEntry, ulUserEnvironmentEntrySize);
  339.                 }
  340.             break;
  341.             }
  342.         }
  343.                                         /* We didn't find the environment variable in PC/2's environment,
  344.                                            so add it at the bottom of the temporary table */
  345.     if(!*ppucEnvironmentEntry)
  346.         {
  347.         *ppucEnvironmentEntry=(UCHAR *)malloc(ulUserEnvironmentEntrySize+1);
  348.         memset(*ppucEnvironmentEntry, '\0', ulUserEnvironmentEntrySize+1);
  349.         strncpy(*ppucEnvironmentEntry, pucUserEnvironmentEntry, ulUserEnvironmentEntrySize);
  350.         *(++ppucEnvironmentEntry)=NULL;
  351.         }
  352.     }
  353.  
  354.                                         /* Allocate environment to inherit to session being
  355.                                            started and reserve for terminating \0\0 */
  356. pucEnvironment=pucEnvironmentEntry=(UCHAR *)malloc(ulEnvironmentSize+2);
  357. memset(pucEnvironment, '\x5a', ulEnvironmentSize);
  358.                                         /* Now copy new Environment from table into a flat
  359.                                            strings terminating an entry with \0 and all entries
  360.                                            with \0\0 and free the table entries */
  361. for(ppucEnvironmentEntry=ppucEnvironment; *ppucEnvironmentEntry; ppucEnvironmentEntry++)
  362.     {
  363.     ULONG   ulLength;
  364.  
  365.     ulLength=strlen(*ppucEnvironmentEntry)+1;
  366.     strcpy(pucEnvironmentEntry, *ppucEnvironmentEntry);
  367.     pucEnvironmentEntry+=ulLength;
  368.                                         /* Free table entry */
  369.     free(*ppucEnvironmentEntry);
  370.     }
  371.                                         /* Add \0\0 because this terminates the whole Environment */
  372. *pucEnvironmentEntry='\0';
  373. *(pucEnvironmentEntry+1)='\0';
  374.                                         /* Free table of entries */
  375. free(ppucEnvironment);
  376.                                         /* Return the Environment which comsists of PC/2's with
  377.                                            additions/replacement from the user */
  378. return(pucEnvironment);
  379. }
  380.  
  381. /*--------------------------------------------------------------------------------------*\
  382.  * A SESSIONDATA data structure is used to extract the parameters to start a new        *
  383.  * session. If sucessfull, additional parameters are extracted to set the priority of   *
  384.  * the new session.                                                                     *
  385.  * Req:         A SessionData structure to start session from                           *
  386. \*--------------------------------------------------------------------------------------*/
  387. void    StartSession(SESSIONDATA *pSessionData)
  388. {
  389. UCHAR           ucMessageBuffer[513];
  390. UCHAR           ucPgmTitle[EF_SIZE255+1];
  391. UCHAR           *pucDestination, *pucSource;
  392. UCHAR           ucPgmInputs[EF_SIZE255+1];
  393.                                         /* If DosStartSession() fails, display current directory */
  394. ULONG           ulCurrentDrive;         /* Current drive (1=A, 2=B, ...) */
  395. ULONG           ulLogicalDriveMap;      /* Bitmap of available drives (Bit 0=A, 1=B, ...) */
  396. UCHAR           ucCurrentDirectory[CCHMAXPATH];
  397. ULONG           ulCurrentDirectoryLen=sizeof(ucCurrentDirectory);
  398. STARTDATA       StartData;              /* Control structure for DosStartSession() */
  399. PROGDETAILS     ProgDetails;            /* Control structure for WinStartApp() */
  400. ULONG           SessID;
  401. PID             Pid;
  402. APIRET          rc;
  403.  
  404. /*                                                                                      *\
  405.  * Change to the root directory of all non-removable drives when a drive was added or   *
  406.  * removed since last change to all drives root directory.                              *
  407. \*                                                                                      */
  408.  
  409.                                         /* Query drive bit map */
  410. DosQueryCurrentDisk(&ulCurrentDrive, &ulLogicalDriveMap);
  411.                                         /* If drive map changed query drives and change to root
  412.                                            directories */
  413. if(pHP->ulLogicalDriveMap!=ulLogicalDriveMap)
  414.     SetDriveRoot();
  415. /*                                                                                      *\
  416.  * Test for x:(...] where x is a drive and set the current working directory to this    *
  417.  * drive.                                                                               *
  418. \*                                                                                      */
  419. if((strlen(pSessionData->PgmDirectory)>=2)
  420.     && (pSessionData->PgmDirectory[1]==':'))
  421.     {
  422.     UCHAR       ucDrive;
  423.                                         /* Then get drive letter (only if one's there */
  424.     ucDrive=tolower(pSessionData->PgmDirectory[0]);
  425.                                         /* 1=A, 2=B, 3=C,... */
  426.     rc=DosSetDefaultDisk(++ucDrive-'a');
  427.     if(rc!=NO_ERROR)
  428.         {
  429.         sprintf(ucMessageBuffer, "Can't change into the directory %s to invoke %s - continuing...",
  430.             pSessionData->PgmDirectory, pSessionData->PgmTitle);
  431.         DOS_ERR(rc, pHP->hwndFrame, HELP_SETPATH, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  432.             ucMessageBuffer);
  433.         }
  434.     }
  435. /*                                                                                      *\
  436.  * Test for a directory and set the current working directory to it, if one exists,     *
  437.  * set to root directory.                                                               *
  438. \*                                                                                      */
  439. if(strlen(pSessionData->PgmDirectory)>2)
  440.     {                                   /* Only if there's one */
  441.     rc=DosSetCurrentDir(pSessionData->PgmDirectory);
  442.     if(rc!=NO_ERROR)
  443.         {
  444.         sprintf(ucMessageBuffer, "Can't change into the directory %s to invoke %s - continuing...",
  445.             pSessionData->PgmDirectory, pSessionData->PgmTitle);
  446.         DOS_ERR(rc, pHP->hwndFrame, HELP_SETPATH, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  447.             ucMessageBuffer);
  448.         }
  449.     }
  450. else
  451.     {                                   /* Set to root directory */
  452.     rc=DosSetCurrentDir("\\");
  453.     if(rc!=NO_ERROR)
  454.         {
  455.         sprintf(ucMessageBuffer, "Can't change into the directory %s to invoke %s - continuing...",
  456.             "\\", pSessionData->PgmTitle);
  457.         DOS_ERR(rc, pHP->hwndFrame, HELP_SETPATH, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  458.             ucMessageBuffer);
  459.         }
  460.     }
  461. memset(&StartData, 0, sizeof(StartData));
  462. StartData.Length=sizeof(StartData);     /* Length of StartData */
  463.                                         /* Buffer containing the module contributed to
  464.                                            an error that the session could not be started */
  465. StartData.ObjectBuffer=malloc(CCHMAXPATH);
  466. memset(StartData.ObjectBuffer, 0, CCHMAXPATH);
  467. StartData.ObjectBuffLen=CCHMAXPATH;
  468.                                         /* Independent session */
  469. StartData.Related=SSF_RELATED_INDEPENDENT;
  470. StartData.FgBg=pSessionData->FgBg;      /* Foreground application */
  471.                                         /* No trace */
  472. StartData.TraceOpt=SSF_TRACEOPT_NONE;
  473.                                         /* Session title string */
  474. for(pucSource=pSessionData->PgmTitle, pucDestination=ucPgmTitle; *pucSource; pucSource++)
  475.                                         /* Remove ~ (tilde) */
  476.     if(*pucSource!='~') *pucDestination++=*pucSource;
  477. *pucDestination='\0';                   /* Add 0-termination */
  478. StartData.PgmTitle=ucPgmTitle;
  479.                                         /* Program path-name string */
  480. StartData.PgmName=pSessionData->PgmName;
  481.                                         /* Input arguments */
  482. if(*pSessionData->PgmInputs=='\0')
  483.     StartData.PgmInputs=0;
  484. else
  485.     StartData.PgmInputs=pSessionData->PgmInputs;
  486. StartData.TermQ=0;                      /* No termination queue */
  487. if(*pSessionData->PgmEnvironment=='\0') /* Has the user overwritten the environment? */
  488.     StartData.Environment=0;            /* Inherit environment from PC/2 */
  489. else
  490.                                         /* Create a modified environment to inherit */
  491.     StartData.Environment=CreateEnvironment(pSessionData->PgmEnvironment);
  492.                                         /* Inherit from PC/2's environment to change to
  493.                                            requested drive & directory */
  494. StartData.InheritOpt=SSF_INHERTOPT_PARENT;
  495.                                         /* Session type */
  496. StartData.SessionType=pSessionData->SessionType;
  497. StartData.IconFile=0;                   /* No icon, use default */
  498. StartData.PgmHandle=0;                  /* Don't use installation file */
  499.                                         /* Session initial state */
  500. StartData.PgmControl=(pSessionData->PgmControl & ~SSF_CONTROL_AUTOSTART);
  501.                                         /* Initial window size */
  502. if(StartData.PgmControl & SSF_CONTROL_SETPOS)
  503.     {                                   /* Position relative to (0|0) of virtual Desktop */
  504.     StartData.InitXPos=0-pHP->VirtualDesktopPos.x+pSessionData->InitXPos;
  505.     StartData.InitYPos=0-pHP->VirtualDesktopPos.y+pSessionData->InitYPos;
  506.     StartData.InitXSize=pSessionData->InitXSize;
  507.     StartData.InitYSize=pSessionData->InitYSize;
  508.     }
  509. /*                                                                                      *\
  510.  * Search for user-addable commandline parameter. If one found, display dialog and get  *
  511.  * it. It will be added to the current arguments.                                       *
  512. \*                                                                                      */
  513. while(TRUE)
  514.     {
  515.     COMMANDLINEPARAMS   CLPParams;
  516.     ULONG               ulResult;       /* Value returned by WinDismissDlg() */
  517.     INT                 iTemp;
  518.     UCHAR               *pucTemp;
  519.  
  520.                                         /* Copy application to add CLPs for */
  521.     strcpy(CLPParams.ucPgmTitle, StartData.PgmTitle);
  522.     strcpy(ucPgmInputs, pSessionData->PgmInputs);
  523.                                         /* Search for [, break if not found */
  524.     if((pucTemp=strchr(ucPgmInputs, '['))==NULL) break;
  525.                                         /* Search for ], break if not found */
  526.     if(strchr(pucTemp, ']')==NULL) break;
  527.                                         /* Break commandline parameters into three parts */
  528.     for(iTemp=0, pucTemp=StartData.PgmInputs; *pucTemp!='['; iTemp++, pucTemp++)
  529.         CLPParams.ucPBefore[iTemp]=*pucTemp;
  530.     CLPParams.ucPBefore[iTemp]='\0';
  531.     pucTemp++;                          /* Skip [ */
  532.     for(iTemp=0; *pucTemp!=']'; iTemp++, pucTemp++)
  533.         CLPParams.ucPUser[iTemp]=*pucTemp;
  534.     CLPParams.ucPUser[iTemp]='\0';
  535.     pucTemp++;                          /* Skip ] */
  536.     for(iTemp=0; *pucTemp!='\0'; iTemp++, pucTemp++)
  537.         CLPParams.ucPAfter[iTemp]=*pucTemp;
  538.     CLPParams.ucPAfter[iTemp]='\0';
  539.     if(!(ulResult=WinDlgBox(            /* Start Startup Parameters dialog box */
  540.         HWND_DESKTOP, HWND_DESKTOP, SU_DialogProcedure, 0, SUID_STARTUPDIALOG,
  541.         &CLPParams)))                   /* Initialization data */
  542.         {
  543.         PM_ERR(pHP->habPc2, pHP->hwndFrame, HELP_CREATEDIALOG, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  544.             "Creation of a dialog box failed - continuing...");
  545.         break;
  546.         }
  547.                                         /* Replace existing commandline parameters with
  548.                                            user-edited ones if OK was pressed */
  549.     if(ulResult==DID_OK)
  550.         {
  551.         sprintf(ucPgmInputs, "%s%s %s",CLPParams.ucPBefore, CLPParams.ucPUser, CLPParams.ucPAfter);
  552.         StartData.PgmInputs=ucPgmInputs;
  553.         }
  554.                                         /* If Cancel was pressed, leave empty string */
  555.     break;                              /* Break out ! */
  556.     }
  557. /*                                                                                      *\
  558.  * If we're to start a DOS session, then set the DOS-Settings via the Environment. This *
  559.  * is an undocumented feature (the toolkit says that the Environment is reserved and    *
  560.  * must be 0 for a DOS session. To use the DOS Settings each Setting must be followed   *
  561.  * by \0 and the last Setting must be followed by two \0s. It seems that the settings   *
  562.  * must replace OFF by 0 and ON by 1.                                                   *
  563.  * Any WIN-OS2 session is hereto equivalent to a DOS session.                           *
  564. \*                                                                                      */
  565. switch(StartData.SessionType)
  566. {
  567. case PROG_VDM:
  568. case PROG_WINDOWEDVDM:
  569. case PROG_WINDOW_REAL:
  570. case PROG_WINDOW_PROT:
  571. case PROG_31_ENH:
  572. case PROG_31_STDSEAMLESSCOMMON:
  573. case PROG_31_ENHSEAMLESSCOMMON:
  574.     {
  575.     ULONG       ulLength=strlen(pSessionData->PgmDosSettings)+1;
  576.     UCHAR       *pucDosSettings;
  577.  
  578.                                         /* Convert to format used by OS/2 in environment of session
  579.                                            to start (same as used for WINDOWS32PROPERTYDIALOG) */
  580.     pucDosSettings=ImportDosSettings(pSessionData->PgmDosSettings, &ulLength, FALSE);
  581.     StartData.Environment=pucDosSettings;
  582.     }
  583.     break;
  584. }
  585. switch(StartData.SessionType)
  586. {
  587. case PROG_WINDOW_REAL:
  588. case PROG_WINDOW_PROT:
  589. case PROG_31_ENH:
  590.     {
  591.     UCHAR   ucTemp[EF_SIZE255+1];
  592.  
  593.     strcpy(ucTemp, ucPgmInputs);
  594.     if(StartData.SessionType==PROG_WINDOW_REAL)
  595.         strcpy(ucPgmInputs, "/r ");     /* WIN-OS2 real mode */
  596.     if(StartData.SessionType==PROG_WINDOW_PROT)
  597.         strcpy(ucPgmInputs, "/s ");     /* WIN-OS2 standard mode */
  598.     if(StartData.SessionType==PROG_31_ENH)
  599.         strcpy(ucPgmInputs, "/3 ");     /* WIN-OS2 386 enhanced mode */
  600.                                         /* Now add the WIN application to invoke */
  601.     strcat(ucPgmInputs, StartData.PgmName);
  602.     strcat(ucPgmInputs, " ");
  603.     strcat(ucPgmInputs, ucTemp);        /* Copy optional commandline parameters as
  604.                                            parameters to the WIN application to be
  605.                                            invoked */
  606.     StartData.PgmName="WIN.COM";        /* For WIN-OS2 sessions we use WIH.COM to start
  607.                                            the WIN-application */
  608.     StartData.PgmInputs=ucPgmInputs;    /* Pass the WIN application to be invoked */
  609.                                         /* Now invoke a WIN-OS2 session. Although it is named
  610.                                            common, it will invoke a seperate VDM */
  611.     StartData.SessionType=PROG_SEAMLESSCOMMON;
  612.     }                                   /* Fall through, cause the Dos Settings are the same */
  613.     break;
  614.  
  615. case PROG_31_STDSEAMLESSCOMMON:
  616. case PROG_31_ENHSEAMLESSCOMMON:
  617.     {
  618.     memset(&ProgDetails, 0, sizeof(ProgDetails));
  619.                                         /* Start a common VDM */
  620.     ProgDetails.Length=sizeof(PROGDETAILS);
  621.     ProgDetails.progt.progc=StartData.SessionType;
  622.     ProgDetails.progt.fbVisible=SHE_VISIBLE;
  623.     ProgDetails.pszTitle=StartData.PgmTitle;
  624.     ProgDetails.pszExecutable=StartData.PgmName;
  625.     ProgDetails.pszParameters=StartData.PgmInputs;
  626.     ProgDetails.pszStartupDir=pSessionData->PgmDirectory;
  627.     ProgDetails.pszEnvironment=StartData.Environment;
  628.     }
  629.     break;
  630. }
  631. /*                                                                                      *\
  632.  * Now set the requested priority, the started session will inherit these settings (at  *
  633.  * least non-WPS-object sessions. Afterwards reset to default priority. For DOS         *
  634.  * sessions changing priority will hang the system, so DOS sessions have the default    *
  635.  * priority only.                                                                       *
  636. \*                                                                                      */
  637. if((pSessionData->PriorityClass!=PRTYC_NOCHANGE) || (pSessionData->PriorityDelta!=PRTYC_NOCHANGE))
  638.     {
  639.     rc=DosSetPrty(PRTYS_PROCESSTREE, (ULONG)pSessionData->PriorityClass, (LONG)pSessionData->PriorityDelta,
  640.         pHP->ProcessId);
  641.     if(rc!=NO_ERROR)
  642.         {
  643.         sprintf(ucMessageBuffer, "Can't change the priority while invoking %s - continuing...",
  644.             pSessionData->PgmTitle);
  645.         DOS_ERR(rc, pHP->hwndFrame, HELP_PRIORITY, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  646.             ucMessageBuffer);
  647.         }
  648.     }
  649. /*                                                                                      *\
  650.  * Now start the session, but beware of the error code ERROR_SMG_START_IN_BACKGROUND,   *
  651.  * which isn't actually an error code, but an informational message we ignore.          *
  652. \*                                                                                      */
  653. switch(StartData.SessionType)
  654. {
  655. case PROG_WPSOBJECT:
  656.     {
  657.     HOBJECT     hWPSObject;
  658.  
  659.                                         /* Find the handle of the WPS object */
  660.     hWPSObject=WinQueryObject(pSessionData->PgmName);
  661.     if(hWPSObject!=NULLHANDLE)
  662.         WinSetObjectData(hWPSObject, "OPEN=DEFAULT");
  663.     else rc=ERROR_INVALID_HANDLE;
  664.     rc=NO_ERROR;                        /* WPS object can't be started when WPS is not running */
  665.     }
  666.     break;
  667.  
  668. case PROG_31_STDSEAMLESSCOMMON:
  669. case PROG_31_ENHSEAMLESSCOMMON:
  670.     {
  671.     HAPP    hApp;
  672.  
  673.     hApp=WinStartApp(NULLHANDLE, &ProgDetails, "", NULL, SAF_INSTALLEDCMDLINE);
  674.     if(hApp==NULLHANDLE)
  675.         {
  676.         sprintf(ucMessageBuffer, "An error occured while invoking %s - continuing...",
  677.             pSessionData->PgmTitle);
  678.         PM_ERR(pHP->habPc2, pHP->hwndFrame, HELP_LAUNCH, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  679.             ucMessageBuffer);
  680.         }
  681.     rc=NO_ERROR;
  682.     }
  683.     break;
  684.  
  685. default:
  686.     DosQueryCurrentDisk(&ulCurrentDrive, &ulLogicalDriveMap);
  687.     DosQueryCurrentDir(ulCurrentDrive, ucCurrentDirectory, &ulCurrentDirectoryLen);
  688.     rc=DosStartSession(                 /* Start the new session */
  689.         &StartData,                     /* Session data */
  690.         &SessID,                        /* Session ID of new session */
  691.         &Pid);                          /* Process ID of new session */
  692. }
  693. switch(rc)
  694. {
  695. case NO_ERROR:                          /* Error codes for errors that are informational */
  696. case ERROR_SMG_START_IN_BACKGROUND:
  697.     break;
  698.  
  699. default:
  700.     {
  701.     sprintf(ucMessageBuffer, "An error occured while invoking %s from directory %c:\\%s. "\
  702.         "Module %s contributed to the failure - continuing...",
  703.         pSessionData->PgmTitle, 'A'+((char)ulCurrentDrive-1), ucCurrentDirectory, StartData.ObjectBuffer);
  704.     DOS_ERR(rc, pHP->hwndFrame, HELP_LAUNCH, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  705.         ucMessageBuffer);
  706.     }
  707. }
  708.                                         /* Set PC/2's startup priority */
  709. if((pSessionData->PriorityClass!=PRTYC_NOCHANGE) || (pSessionData->PriorityDelta!=PRTYC_NOCHANGE))
  710.     {
  711.     rc=DosSetPrty(PRTYS_PROCESSTREE, (ULONG)PRTYC_REGULAR, (LONG)(-pSessionData->PriorityDelta),
  712.         pHP->ProcessId);
  713.     if(rc!=NO_ERROR)
  714.         {
  715.         sprintf(ucMessageBuffer, "Can't change the priority back to default after invoking %s - continuing...",
  716.             pSessionData->PgmTitle);
  717.         DOS_ERR(rc, pHP->hwndFrame, HELP_PRIORITY, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  718.             ucMessageBuffer);
  719.         }
  720.     }
  721.                                         /* Clear extended LIBPATH to prevent inheritance
  722.                                            of unwanted data from a previous launch that set
  723.                                            the extended LIBPATH */
  724. if(pHP->DosSetExtLIBPATH)
  725.     pHP->DosSetExtLIBPATH("", BEGINLIBPATH);
  726. if(pHP->DosSetExtLIBPATH)
  727.     pHP->DosSetExtLIBPATH("", ENDLIBPATH);
  728. /*                                                                                      *\
  729.  * Release memory allocated for the DOS Settings.                                       *
  730. \*                                                                                      */
  731. switch(StartData.SessionType)
  732. {
  733. case PROG_VDM:
  734. case PROG_WINDOWEDVDM:
  735. case PROG_WINDOW_REAL:
  736. case PROG_WINDOW_PROT:
  737. case PROG_31_ENH:
  738. case PROG_31_STDSEAMLESSCOMMON:
  739. case PROG_31_ENHSEAMLESSCOMMON:
  740.     if(StartData.Environment) free(StartData.Environment);
  741.     break;
  742. }
  743.                                         /* If PC/2 inherited a customized environment,
  744.                                            its now time to deallocate it */
  745. if(StartData.Environment) free(StartData.Environment);
  746.                                         /* Set empty dynamic LIBPATH (WARP+) */
  747. if(pHP->DosSetExtLIBPATH)
  748.     pHP->DosSetExtLIBPATH(NULL, BEGINLIBPATH);
  749. if(pHP->DosSetExtLIBPATH)
  750.     pHP->DosSetExtLIBPATH(NULL, ENDLIBPATH);
  751. free(StartData.ObjectBuffer);
  752. }
  753.  
  754. /*--------------------------------------------------------------------------------------*\
  755.  * Procedure to load a SESSIONDATA structure from a MENUDATA structure.                 *
  756.  * Req:                                                                                 *
  757.  *      pMenuData ..... A pointer to a MENUDATA structure to extract the data required  *
  758.  *                      for a Menu/Program Installation dialog.                         *
  759.  *      pSessionData .. A pointer to a SESSIONDATA structure to write the extracted     *
  760.  *                      data into, which is then used in subsequent Menu/Program        *
  761.  *                      Installation dialogs window procedures.                         *
  762.  * Returns:                                                                             *
  763.  *      TRUE/FALSE .... If called sucessfully/unsucessfully                             *
  764. \*--------------------------------------------------------------------------------------*/
  765. BOOL    LoadMenuData2SessionData(MENUDATA *pMenuData, SESSIONDATA *pSessionData)
  766. {
  767. strcpy(pSessionData->PgmTitle, pMenuData->PgmTitle);
  768. strcpy(pSessionData->WindowTitle, pMenuData->WindowTitle);
  769. strcpy(pSessionData->PgmName, pMenuData->PgmName);
  770. strcpy(pSessionData->PgmDirectory, pMenuData->PgmDirectory);
  771. strcpy(pSessionData->PgmInputs, pMenuData->PgmInputs);
  772. pSessionData->PgmDosSettings=pMenuData->PgmDosSettings;
  773. pSessionData->PgmEnvironment=pMenuData->PgmEnvironment;
  774. /*                                                                                      *\
  775.  * Just straight forward copy of data from MENUDATA structure to SESSIONDATA structure. *
  776.  * The allocated MENUDATA structure is filled during allocation with default values,    *
  777.  * we don't differentiate between empty and non-empty structures any more.              *
  778. \*                                                                                      */
  779. pSessionData->SessionType=pMenuData->SessionType;
  780. pSessionData->PgmControl=pMenuData->PgmControl;
  781. pSessionData->FgBg=pMenuData->FgBg;
  782. pSessionData->InitXPos=pMenuData->InitXPos;
  783. pSessionData->InitYPos=pMenuData->InitYPos;
  784. pSessionData->InitXSize=pMenuData->InitXSize;
  785. pSessionData->InitYSize=pMenuData->InitYSize;
  786. (pSessionData->KeyData).usFlags=(pMenuData->KeyData).usFlags;
  787. (pSessionData->KeyData).usCh=(pMenuData->KeyData).usCh;
  788. (pSessionData->KeyData).pMenuData=pMenuData;
  789. pSessionData->SwpFlag=pMenuData->SwpFlag;
  790. pSessionData->PriorityClass=pMenuData->PriorityClass;
  791. pSessionData->PriorityDelta=pMenuData->PriorityDelta;
  792. return(TRUE);
  793. }
  794.  
  795. /*--------------------------------------------------------------------------------------*\
  796.  * Procedure to save a MENUDATA structure to a SESSIONDATA structure.                   *
  797.  * Req:                                                                                 *
  798.  *      pMenuData ..... A pointer to a MENUDATA structure to write the data from a      *
  799.  *                      Menu/Program Installation dialog.                               *
  800.  *      pSessionData .. A pointer to a SESSIONDATA structure to extract the data from,  *
  801.  *                      which the user entered.                                         *
  802.  * Returns:                                                                             *
  803.  *      TRUE/FALSE .... If called sucessfully/unsucessfully                             *
  804. \*--------------------------------------------------------------------------------------*/
  805. BOOL    LoadSessionData2MenuData(MENUDATA *pMenuData, SESSIONDATA *pSessionData)
  806. {
  807.                                         /* Ignore if not changed otherwise release memory
  808.                                            and allocate a new one */
  809. if(strcmp(pMenuData->PgmTitle, pSessionData->PgmTitle)!=0)
  810.     {
  811.     free(pMenuData->PgmTitle);
  812.     pMenuData->PgmTitle=malloc(1+strlen(pSessionData->PgmTitle));
  813.     strcpy(pMenuData->PgmTitle, pSessionData->PgmTitle);
  814.     }
  815. if(strcmp(pMenuData->WindowTitle, pSessionData->WindowTitle)!=0)
  816.     {
  817.     free(pMenuData->WindowTitle);
  818.     pMenuData->WindowTitle=malloc(1+strlen(pSessionData->WindowTitle));
  819.     strcpy(pMenuData->WindowTitle, pSessionData->WindowTitle);
  820.     }
  821. if(strcmp(pMenuData->PgmName, pSessionData->PgmName)!=0)
  822.     {
  823.     free(pMenuData->PgmName);
  824.     pMenuData->PgmName=malloc(1+strlen(pSessionData->PgmName));
  825.     strcpy(pMenuData->PgmName, pSessionData->PgmName);
  826.     }
  827. if(strcmp(pMenuData->PgmDirectory, pSessionData->PgmDirectory)!=0)
  828.     {
  829.     free(pMenuData->PgmDirectory);
  830.     pMenuData->PgmDirectory=malloc(1+strlen(pSessionData->PgmDirectory));
  831.     strcpy(pMenuData->PgmDirectory, pSessionData->PgmDirectory);
  832.     }
  833. if(strcmp(pMenuData->PgmInputs, pSessionData->PgmInputs)!=0)
  834.     {
  835.     free(pMenuData->PgmInputs);
  836.     pMenuData->PgmInputs=malloc(1+strlen(pSessionData->PgmInputs));
  837.     strcpy(pMenuData->PgmInputs, pSessionData->PgmInputs);
  838.     }
  839. switch(pSessionData->SessionType)
  840. {                                       /* Save DOS settings for DOS type sessions */
  841. case PROG_VDM:
  842. case PROG_WINDOWEDVDM:
  843. case PROG_WINDOW_REAL:
  844. case PROG_WINDOW_PROT:
  845. case PROG_31_ENH:
  846. case PROG_31_STDSEAMLESSCOMMON:
  847. case PROG_31_ENHSEAMLESSCOMMON:
  848.                                         /* Accept DOS sessings */
  849.     pMenuData->PgmDosSettings=pSessionData->PgmDosSettings;
  850.     break;
  851.  
  852. default:
  853.                                         /* For all other we load empty DOS settings.
  854.                                            Normally they are empty, but default IDLE_SECONDS
  855.                                            and IDLE_SENSITIVITY are added or if someone
  856.                                            modifys the profile there may be some, which
  857.                                            we force to be cleared */
  858.     free(pSessionData->PgmDosSettings);
  859.     pSessionData->PgmDosSettings=malloc(1+strlen(""));
  860.     pMenuData->PgmDosSettings=pSessionData->PgmDosSettings;
  861.     break;
  862. }
  863. switch(pSessionData->SessionType)
  864. {
  865. case PROG_PM:
  866. case PROG_FULLSCREEN:
  867. case PROG_WINDOWABLEVIO:
  868.                                         /* Accept environment modifications */
  869.     pMenuData->PgmEnvironment=pSessionData->PgmEnvironment;
  870.     break;
  871.  
  872. default:
  873.                                         /* For all DOS base sessions, don't accept an environment */
  874.     free(pSessionData->PgmEnvironment);
  875.     pSessionData->PgmEnvironment=malloc(1+strlen(""));
  876.     pMenuData->PgmEnvironment=pSessionData->PgmEnvironment;
  877. }
  878. pMenuData->PgmEnvironment=pSessionData->PgmEnvironment;
  879. pMenuData->SessionType=pSessionData->SessionType;
  880. pMenuData->PgmControl=pSessionData->PgmControl;
  881. pMenuData->FgBg=pSessionData->FgBg;
  882. pMenuData->InitXPos=pSessionData->InitXPos;
  883. pMenuData->InitYPos=pSessionData->InitYPos;
  884. pMenuData->InitXSize=pSessionData->InitXSize;
  885. pMenuData->InitYSize=pSessionData->InitYSize;
  886. (pMenuData->KeyData).usFlags=(pSessionData->KeyData).usFlags;
  887. (pMenuData->KeyData).usCh=(pSessionData->KeyData).usCh;
  888. pMenuData->SwpFlag=pSessionData->SwpFlag;
  889. pMenuData->PriorityClass=pSessionData->PriorityClass;
  890. pMenuData->PriorityDelta=pSessionData->PriorityDelta;
  891. return(TRUE);
  892. }
  893.  
  894. /*--------------------------------------------------------------------------------------*\
  895.  * This procedure allocates a MENUDATA structure and initializes it to the default      *
  896.  * values of an empty structure.                                                        *
  897.  * Req:                                                                                 *
  898.  *      none                                                                            *
  899.  * Returns:                                                                             *
  900.  *      pMenuData ..... A pointer to an MENUDATA structure.                             *
  901. \*--------------------------------------------------------------------------------------*/
  902. MENUDATA *AllocateMenuData(void)
  903. {
  904. UCHAR           *pU;
  905. MENUDATA        *pMD;
  906.  
  907. pMD=malloc(sizeof(MENUDATA));     /* Allocate a MENUDATA structure */
  908. pMD->Item=ENTRYEMPTY;             /* It's an empty structure */
  909. pMD->id=0;
  910. pMD->hwndItem=NULLHANDLE;
  911. strcpy(pU=malloc(strlen("")+1), "");
  912. pMD->PgmTitle=pU;                 /* Load default values */
  913. strcpy(pU=malloc(strlen("")+1), "");
  914. pMD->WindowTitle=pU;
  915. strcpy(pU=malloc(strlen("")+1), "");
  916. pMD->PgmName=pU;
  917. strcpy(pU=malloc(strlen("")+1), "");
  918. pMD->PgmDirectory=pU;
  919. strcpy(pU=malloc(strlen("")+1), "");
  920. pMD->PgmInputs=pU;
  921. strcpy(pU=malloc(strlen("")+1), "");
  922. pMD->PgmDosSettings=pU;
  923. strcpy(pU=malloc(strlen("")+1), "");
  924. pMD->PgmEnvironment=pU;
  925. pMD->SessionType=PROG_DEFAULT;
  926. pMD->PgmControl=SSF_CONTROL_VISIBLE;
  927. pMD->FgBg=SSF_FGBG_FORE;
  928. pMD->InitXPos=pHP->swpScreen.cx*0.15;
  929. pMD->InitYPos=pHP->swpScreen.cy*0.15;
  930. pMD->InitXSize=pHP->swpScreen.cx*0.70;
  931. pMD->InitYSize=pHP->swpScreen.cy*0.70;
  932. (pMD->KeyData).usFlags=KC_CTRL;
  933. (pMD->KeyData).usCh=0;
  934. (pMD->KeyData).pMenuData=NULL;
  935. pMD->SwpFlag=SWP_RESTORE;
  936. pMD->PriorityClass=PRTYC_NOCHANGE;
  937. pMD->PriorityDelta=PRTYC_NOCHANGE;
  938. pMD->Back=NULL;
  939. pMD->Submenu=NULL;
  940. pMD->Next=NULL;
  941. return(pMD);
  942. }
  943.  
  944. /*--------------------------------------------------------------------------------------*\
  945.  * This recursive procedure loads the popup menu from the profile.                      *
  946.  * Req:                                                                                 *
  947.  *      pMenuData ..... A pointer to an MENUDATA structure.                             *
  948.  * Returns:                                                                             *
  949.  *      none                                                                            *
  950. \*--------------------------------------------------------------------------------------*/
  951. void LoadMenu(MENUDATA *pMenuData)
  952. {
  953. static UCHAR    Buffer[512];
  954. static UCHAR    *Match;
  955. static USHORT   Flag;
  956.  
  957. fgets(Buffer, sizeof(Buffer), pHP->Pc2Profile);
  958. do
  959. {
  960.                                         /* Should read MENUITEM or MENUCONTROL or
  961.                                            SUBMENU BEGIN or SUBMENU END */
  962.     if(strstr(Buffer, "SUBMENU END"))
  963.         {
  964.         fgets(Buffer, sizeof(Buffer), pHP->Pc2Profile);
  965.         return;                         /* We are at an end of the list, terminate it
  966.                                            and shell up one level by return() */
  967.         }
  968.     pMenuData->id=pHP->MenuDataId++;    /* Fill with current id and increment id */
  969.     if(strstr(Buffer, "PROFILE END")) return;
  970.     if(strstr(Buffer, "MENUITEM")) Flag=ENTRYMENUITEM;
  971.     else if(strstr(Buffer, "MENUCONTROL")) Flag=ENTRYCONTROL;
  972.         else Flag=ENTRYSUBMENU;
  973. /*                                                                                      *\
  974.  * Get the entry from the profile, but remove the heading description and the \n from   *
  975.  * the strings.                                                                         *
  976. \*                                                                                      */
  977.                                         /* Get the session title */
  978.     fgets(Buffer, sizeof(Buffer), pHP->Pc2Profile);
  979.                                         /* Replace CRLF with \0 */
  980.     Buffer[strlen(Buffer)-1]='\0';
  981.     if((Match=strchr(Buffer, ' '))==NULL) Match=strchr(Buffer, '\0');
  982.     else for( ; (*Match==' ') && (*Match!='\0'); /* Match++ */)
  983.         Match++;
  984.     free(pMenuData->PgmTitle);
  985.     pMenuData->PgmTitle=malloc(strlen(Match)+1);
  986.     strcpy(pMenuData->PgmTitle, Match);
  987.     if(Flag==ENTRYMENUITEM)
  988.         {
  989.         pMenuData->Item=ENTRYMENUITEM;  /* It's a Menuitem */
  990.         do                              /* Do until a complete MENUITEM was read */
  991.             {
  992.                                         /* Get a new line */
  993.             fgets(Buffer, sizeof(Buffer), pHP->Pc2Profile);
  994.                                         /* Replace CRLF with \0 */
  995.             Buffer[strlen(Buffer)-1]='\0';
  996.                                         /* Find first space after a ':' or NULL, if
  997.                                            none can be found */
  998.             Match=strchr(Buffer, ':');
  999.             if(Match=='\0') Match=strchr(Buffer, '\0');
  1000.             else                        /* We found a ':', so we search for ' ' and
  1001.                                            return it or NULL, if none can be found */
  1002.                 if((Match=strchr(Match, ' '))==NULL) Match=strchr(Buffer, '\0');
  1003.                 else for( ; (*Match==' ') && (*Match!='\0'); /* Match++ */)
  1004.                     Match++;;
  1005.                                         /* Now fill in the characters after the
  1006.                                            space, according for what structure
  1007.                                            element it is given */
  1008.             if(strstr(Buffer, "WindowTitle"))
  1009.                 {
  1010.                 free(pMenuData->WindowTitle);
  1011.                 pMenuData->WindowTitle=malloc(strlen(Match)+1);
  1012.                 strcpy(pMenuData->WindowTitle, Match);
  1013.                 }
  1014.             if(strstr(Buffer, "PgmName"))
  1015.                 {
  1016.                 free(pMenuData->PgmName);
  1017.                 pMenuData->PgmName=malloc(strlen(Match)+1);
  1018.                 strcpy(pMenuData->PgmName, Match);
  1019.                 }
  1020.             if(strstr(Buffer, "PgmDirectory"))
  1021.                 {
  1022.                 free(pMenuData->PgmDirectory);
  1023.                 pMenuData->PgmDirectory=malloc(strlen(Match)+1);
  1024.                 strcpy(pMenuData->PgmDirectory, Match);
  1025.                 }
  1026.             if(strstr(Buffer, "PgmInputs"))
  1027.                 {
  1028.                 free(pMenuData->PgmInputs);
  1029.                 pMenuData->PgmInputs=malloc(strlen(Match)+1);
  1030.                 strcpy(pMenuData->PgmInputs, Match);
  1031.                 }
  1032.             if(strstr(Buffer, "DOSSETTINGS BEGIN"))
  1033.                 {
  1034.                 UCHAR       ucBuffer[LENDOSSETTINGS]="";
  1035.  
  1036.                 fgets(Buffer, sizeof(Buffer), pHP->Pc2Profile);
  1037.                 while(!strstr(Buffer, "DOSSETTINGS END"))
  1038.                     {                   /* Add all DOS Settings to temporary buffer */
  1039.                     UCHAR   *pucTemp;
  1040.  
  1041.                                         /* Ensure that \r\n (CRLF) terminates DOS setting */
  1042.                     if(*((pucTemp=strchr(Buffer, '\n'))-1)!='\r')
  1043.                         {
  1044.                         *pucTemp++='\r';
  1045.                         *pucTemp++='\n';
  1046.                         *pucTemp='\0';
  1047.                         }
  1048.                     if(strlen(ucBuffer)+strlen(Buffer)+2 < LENDOSSETTINGS)
  1049.                                         /* Don't copy just a line of only CFLF */
  1050.                         if(strcmp(Buffer, "\r\n"))
  1051.                             strcat(ucBuffer, Buffer);
  1052.                     fgets(Buffer, sizeof(Buffer), pHP->Pc2Profile);
  1053.                     }
  1054.                                         /* Now allocate the exactly required buffer and
  1055.                                            copy all DOS Settings there */
  1056.                 free(pMenuData->PgmDosSettings);
  1057.                 pMenuData->PgmDosSettings=strdup(ucBuffer);
  1058.                 }
  1059.             if(strstr(Buffer, "ENVIRONMENT BEGIN"))
  1060.                 {
  1061.                 UCHAR       ucBuffer[LENENVSETTINGS]="";
  1062.  
  1063.                 fgets(Buffer, sizeof(Buffer), pHP->Pc2Profile);
  1064.                 while(!strstr(Buffer, "ENVIRONMENT END"))
  1065.                     {                   /* Add all Environment settings to temporary buffer */
  1066.                     UCHAR   *pucTemp;
  1067.  
  1068.                                         /* Ensure that \r\n (CRLF) terminates Environment setting */
  1069.                     if(*((pucTemp=strchr(Buffer, '\n'))-1)!='\r')
  1070.                         {
  1071.                         *pucTemp++='\r';
  1072.                         *pucTemp++='\n';
  1073.                         *pucTemp='\0';
  1074.                         }
  1075.                     if(strlen(ucBuffer)+strlen(Buffer)+2 < LENENVSETTINGS)
  1076.                                         /* Don't copy just a line of only CFLF */
  1077.                         if(strcmp(Buffer, "\r\n"))
  1078.                             strcat(ucBuffer, Buffer);
  1079.                     fgets(Buffer, sizeof(Buffer), pHP->Pc2Profile);
  1080.                     }
  1081.                                         /* Now allocate the exactly required buffer and
  1082.                                            copy all Environment settings there */
  1083.                 free(pMenuData->PgmEnvironment);
  1084.                 pMenuData->PgmEnvironment=strdup(ucBuffer);
  1085.                 }
  1086.             if(strstr(Buffer, "SessionType"))
  1087.                 {
  1088.                 ULONG   ulTemp;
  1089.  
  1090.                 pMenuData->SessionType=(USHORT)-1;
  1091.                 for(ulTemp=0; ulTemp<SESSIONTYPESIZE; ulTemp++)
  1092.                     if(strstr(Match, SessionType[ulTemp].pucSessionType))
  1093.                         {
  1094.                         pMenuData->SessionType=SessionType[ulTemp].usSessionType;
  1095.                         }
  1096.                 if(pMenuData->SessionType==(USHORT)-1)
  1097.                     pMenuData->SessionType=(USHORT)atol(Match);
  1098.                 }
  1099.             if(strstr(Buffer, "PgmControl"))
  1100.                 {
  1101.                 ULONG   ulTemp;
  1102.  
  1103.                 for(ulTemp=0; ulTemp<PGMCONTROLSIZE; ulTemp++)
  1104.                     if(strstr(Match, PgmControl[ulTemp].pucPgmControl))
  1105.                         pMenuData->PgmControl|=PgmControl[ulTemp].usPgmControl;
  1106.                 if(pMenuData->PgmControl==0)
  1107.                     pMenuData->PgmControl=(USHORT)atol(Match);
  1108.                 }
  1109.             if(strstr(Buffer, "FgBg"))
  1110.                 {
  1111.                 if(strstr(Match, "SSF_FGBG_BACK"))
  1112.                     pMenuData->FgBg=SSF_FGBG_BACK;
  1113.                 else
  1114.                     pMenuData->FgBg=SSF_FGBG_FORE;
  1115.                 }
  1116.             if(strstr(Buffer, "InitXPos"))
  1117.                 {
  1118.                 pMenuData->InitXPos=(SHORT)atol(Match);
  1119.                 }
  1120.             if(strstr(Buffer, "InitYPos"))
  1121.                 {
  1122.                 pMenuData->InitYPos=(SHORT)atol(Match);
  1123.                 }
  1124.             if(strstr(Buffer, "InitXSize"))
  1125.                 {
  1126.                 pMenuData->InitXSize=(USHORT)atol(Match);
  1127.                 }
  1128.             if(strstr(Buffer, "InitYSize"))
  1129.                 {
  1130.                 pMenuData->InitYSize=(USHORT)atol(Match);
  1131.                 }
  1132.             if(strstr(Buffer, "KeyControl"))
  1133.                 {
  1134.                 if(strstr(Match, "KC_CTRL"))
  1135.                     (pMenuData->KeyData).usFlags=KC_CTRL;
  1136.                 if(strstr(Match, "KC_ALT"))
  1137.                     (pMenuData->KeyData).usFlags=KC_ALT;
  1138.                 }
  1139.             if(strstr(Buffer, "KeyData"))
  1140.                 {
  1141.                 KEYDATA *pKeyDataIndex;
  1142.                 ULONG   ulTemp;
  1143.  
  1144.                                         /* Find first char from end of string, which
  1145.                                            must be our hotkey */
  1146.                 Match=strrchr(Buffer, ' ');
  1147.                 if(Match!=NULL)
  1148.                     {
  1149.                     (pMenuData->KeyData).usCh=(USHORT)*(++Match);
  1150.                     pKeyDataIndex=pHP->pKeyData;
  1151.                                         /* If we found a key set it to used */
  1152.                     for(ulTemp=0; ulTemp<KEYDATACOUNT; pKeyDataIndex++, ulTemp++)
  1153.                         if((pKeyDataIndex->usCh==(pMenuData->KeyData).usCh) &&
  1154.                             (pKeyDataIndex->usFlags==(pMenuData->KeyData).usFlags))
  1155.                             {
  1156.                             pKeyDataIndex->bUsed=TRUE;
  1157.                             pKeyDataIndex->pMenuData=pMenuData;
  1158.                             }
  1159.                     }
  1160.                 }
  1161.             if(strstr(Buffer, "WindowControl"))
  1162.                 {
  1163.                 if(strstr(Match, "SWP_MAXIMIZE"))
  1164.                     pMenuData->SwpFlag=(pMenuData->SwpFlag | SWP_MAXIMIZE) & ~SWP_RESTORE;
  1165.                 if(strstr(Match, "SWP_RESTORE"))
  1166.                     pMenuData->SwpFlag=(pMenuData->SwpFlag | SWP_RESTORE) & ~SWP_MAXIMIZE;
  1167.                 if(strstr(Match, "SWP_NOMOVE"))
  1168.                     pMenuData->SwpFlag|=SWP_NOMOVE;
  1169.                 }
  1170.             if(strstr(Buffer, "PriorityClass"))
  1171.                 {
  1172.                 pMenuData->PriorityClass=(USHORT)atol(Match);
  1173.                 }
  1174.             if(strstr(Buffer, "PriorityDelta"))
  1175.                 {
  1176.                 pMenuData->PriorityDelta=(SHORT)atol(Match);
  1177.                 }
  1178.             } while((!strstr(Buffer, "MENUITEM")) &&
  1179.                 (!strstr(Buffer, "MENUCONTROL")) &&
  1180.                 (!strstr(Buffer, "SUBMENU BEGIN")) &&
  1181.                 (!strstr(Buffer, "SUBMENU END")) &&
  1182.                 (!strstr(Buffer, "PROFILE END")) &&
  1183.                 !feof(pHP->Pc2Profile));
  1184.         if(!strcmp(pMenuData->WindowTitle, ""))
  1185.             {                           /* If no string to match with titlebar or Task List is
  1186.                                            defined, use the sessions title */
  1187.             free(pMenuData->WindowTitle);
  1188.             pMenuData->WindowTitle=malloc(strlen(pMenuData->PgmTitle)+1);
  1189.             strcpy(pMenuData->WindowTitle, pMenuData->PgmTitle);
  1190.             }
  1191.  
  1192.         switch(pMenuData->SessionType)  /* The user may manipulate the profile, so ensure
  1193.                                            that bad things are prevented */
  1194.         {
  1195.         case PROG_WINDOWEDVDM:
  1196.         case PROG_VDM:
  1197.         case PROG_WINDOW_REAL:
  1198.         case PROG_WINDOW_PROT:
  1199.         case PROG_31_ENH:
  1200.                                         /* Priority for DOS sessions lock PM, so ignore */
  1201.             pMenuData->PriorityClass=PRTYC_NOCHANGE;
  1202.             pMenuData->PriorityDelta=PRTYC_NOCHANGE;
  1203.             break;
  1204.         }
  1205.                                         /* Insert this Menuitem at the end of the Popup-Menu */
  1206.         if(pMenuData->Back!=NULL)
  1207.             {                           /* This isn't the first item, insert after an
  1208.                                            existing item */
  1209.             if((pMenuData->Back)->Submenu==pMenuData)
  1210.                                         /* If this is the first item of a Submenu, then
  1211.                                            insert it as this */
  1212.                 SetPopupMenu(MM_INSERTITEMSUBMENU, MPFROMP(pMenuData), MPFROMP(pMenuData->Back));
  1213.             else
  1214.                                         /* Insert item after the existing item */
  1215.                 SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMenuData), MPFROMP(pMenuData->Back));
  1216.             }
  1217.         else                            /* This is the first item, insert at the end */
  1218.                 SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMenuData), MPFROMP(NULL));
  1219.         }
  1220.     if(Flag==ENTRYCONTROL)
  1221.         {
  1222.         pHP->MenuDataId--;              /* Don't use the default ID, because controls have
  1223.                                            their own */
  1224.         pMenuData->Item=ENTRYCONTROL;   /* It's a Menucontrol */
  1225.                                         /* For conversion from version 1.70 to 1.80 we support
  1226.                                            also a string containing no mnemonic during read.
  1227.                                            For non-mnemonic strings we just scan for substrings.
  1228.                                            Written is always the new style */
  1229.         if(!strcmp(pMenuData->PgmTitle, CTRL_CONFIGMENU) ||
  1230.             strstr(pMenuData->PgmTitle, "Menu"))
  1231.                 { strcpy(pMenuData->PgmTitle, CTRL_CONFIGMENU); pMenuData->id=ID_CONFIGDIALOG; }
  1232.         if(!strcmp(pMenuData->PgmTitle, CTRL_CONFIGDESKTOP) ||
  1233.             strstr(pMenuData->PgmTitle, "Desktop"))
  1234.                 { strcpy(pMenuData->PgmTitle, CTRL_CONFIGDESKTOP); pMenuData->id=ID_DESKTOPDIALOG; }
  1235.         if(!strcmp(pMenuData->PgmTitle, CTRL_ABOUT) ||
  1236.             strstr(pMenuData->PgmTitle, "About"))
  1237.                 { strcpy(pMenuData->PgmTitle, CTRL_ABOUT); pMenuData->id=ID_ABOUTDIALOG; }
  1238.         if(!strcmp(pMenuData->PgmTitle, CTRL_SHUTDOWN) ||
  1239.             strstr(pMenuData->PgmTitle, "ShutDown"))
  1240.                 { strcpy(pMenuData->PgmTitle, CTRL_SHUTDOWN); pMenuData->id=ID_SHUTDOWN; }
  1241.         if(!strcmp(pMenuData->PgmTitle, CTRL_HELP) ||
  1242.             strstr(pMenuData->PgmTitle, "Help"))
  1243.                 { strcpy(pMenuData->PgmTitle, CTRL_HELP); pMenuData->id=ID_HELP; }
  1244.         if(!strcmp(pMenuData->PgmTitle, CTRL_SPOOLER) ||
  1245.             strstr(pMenuData->PgmTitle, "Spooler"))
  1246.                 { strcpy(pMenuData->PgmTitle, CTRL_SPOOLER); pMenuData->id=ID_SPOOLER; }
  1247.         if(!strcmp(pMenuData->PgmTitle, CTRL_EXIT) ||
  1248.             strstr(pMenuData->PgmTitle, "Exit"))
  1249.                 { strcpy(pMenuData->PgmTitle, CTRL_EXIT); pMenuData->id=ID_EXIT; }
  1250.                                         /* We assume that more than 1 separator may occur
  1251.                                            so to be able add, modify or delete on menuitems
  1252.                                            define a unique one */
  1253.         if(!strcmp(pMenuData->PgmTitle, CTRL_BREAKSEPARATOR)) pMenuData->id=pHP->MenuDataId++;
  1254.         if(!strcmp(pMenuData->PgmTitle, CTRL_SEPARATOR)) pMenuData->id=pHP->MenuDataId++;
  1255.                                         /* Get a new line */
  1256.         fgets(Buffer, sizeof(Buffer), pHP->Pc2Profile);
  1257.                                         /* Replace CRLF with \0 */
  1258.         Buffer[strlen(Buffer)-1]='\0';
  1259.                                         /* Insert this Menuitem at the end of the Popup-Menu */
  1260.         if(pMenuData->Back!=NULL)
  1261.             {                           /* This isn't the first item, insert after an
  1262.                                            existing item */
  1263.             if((pMenuData->Back)->Submenu==pMenuData)
  1264.                                         /* If this is the first item of a Submenu, then
  1265.                                            insert it as this */
  1266.                 SetPopupMenu(MM_INSERTITEMSUBMENU, MPFROMP(pMenuData), MPFROMP(pMenuData->Back));
  1267.             else
  1268.                                         /* Insert item after the existing item */
  1269.                 SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMenuData), MPFROMP(pMenuData->Back));
  1270.             }
  1271.         else                            /* This is the first item, insert at the end */
  1272.                 SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMenuData), MPFROMP(NULL));
  1273.         }
  1274.     if(Flag==ENTRYSUBMENU)
  1275.         {                               /* If we load a SUBMENU BEGIN, fill with empty strings */
  1276.         MENUDATA        *pMenuDataTemp;
  1277.  
  1278.         pMenuData->Item=ENTRYSUBMENU;   /* It's a Submenu */
  1279.                                         /* Now obtain a entry for a submenu, adjust the
  1280.                                            linked list to it and call this procedure with
  1281.                                            the new entry recursivly again */
  1282.         pMenuDataTemp=AllocateMenuData();
  1283.         pMenuData->Submenu=pMenuDataTemp;
  1284.         pMenuDataTemp->Back=pMenuData;
  1285.                                         /* Insert this Menuitem at the end of the Popup-Menu */
  1286.         if(pMenuData->Back!=NULL)
  1287.             {                           /* This isn't the first item, insert after an
  1288.                                            existing item */
  1289.             if((pMenuData->Back)->Submenu==pMenuData)
  1290.                                         /* If this is the first item of a Submenu, then
  1291.                                            insert it as this */
  1292.                 SetPopupMenu(MM_INSERTITEMSUBMENU, MPFROMP(pMenuData), MPFROMP(pMenuData->Back));
  1293.             else
  1294.                                         /* Insert item after the existing item */
  1295.                 SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMenuData), MPFROMP(pMenuData->Back));
  1296.             }
  1297.         else                            /* This is the first item, insert at the end */
  1298.                 SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMenuData), MPFROMP(NULL));
  1299.         LoadMenu(pMenuDataTemp);        /* It's assumed to be an empty entry, which will
  1300.                                            be corrected, if the first entry of the Submenu
  1301.                                            is found. As after recursion into we continue
  1302.                                            here, the next statement must be the test
  1303.                                            for the end of the profile */
  1304.         }
  1305. /*                                                                                      *\
  1306.  * Now see if we're at the end of the profile. If so, then terminate linked list with   *
  1307.  * 2 Null pointers, otherwise abtain a new menu space and adjust the menu pointer       *
  1308.  * pMenuData to the newly created menu.                                                 *
  1309. \*                                                                                      */
  1310.     if(strstr(Buffer, "PROFILE END"))
  1311.         break;                          /* Empty lines may follow and feof() then is FALSE
  1312.                                            and we loop again, reading invalid input. Avoid
  1313.                                            this by breaking out of the loop */
  1314.     else
  1315.         {                               /* If a SUBMENU END follows ignore it, because
  1316.                                            execution will return at beginning of the loop
  1317.                                            otherwise add a new item to the end of the
  1318.                                            linked list */
  1319.         if(!strstr(Buffer, "SUBMENU END"))
  1320.             {
  1321.             MENUDATA    *pMenuDataTemp;
  1322.  
  1323.             pMenuDataTemp=AllocateMenuData();
  1324.             pMenuData->Next=pMenuDataTemp;
  1325.             pMenuDataTemp->Back=pMenuData;
  1326.             pMenuData=pMenuData->Next;
  1327.             }
  1328.         }
  1329. } while(!feof(pHP->Pc2Profile));
  1330. return;
  1331. }
  1332.  
  1333. /*--------------------------------------------------------------------------------------*\
  1334.  * This recursive procedure saves the popup menu into the profile.                      *
  1335.  * Req:                                                                                 *
  1336.  *      pMenuData ..... A pointer to an MENUDATA structure.                             *
  1337.  * Returns:                                                                             *
  1338.  *      none                                                                            *
  1339. \*--------------------------------------------------------------------------------------*/
  1340. void SaveMenu(MENUDATA *pMenuData)
  1341. {
  1342. do
  1343. {
  1344.     if(pMenuData->Item==ENTRYSUBMENU)
  1345.         {
  1346. /*                                                                                      *\
  1347.  * If this is a SUBMENU, then write the header SUBMENU BEGIN and then write the profile *
  1348.  * data from teh MENUDATA structure pointet by pMenuData. Then increment the depth      *
  1349.  * counter and call this procedure recursivly again. After coming back, restore the     *
  1350.  * depth counter and write the header SUBMENU END.                                      *
  1351. \*                                                                                      */
  1352.         fprintf(pHP->Pc2Profile, "SUBMENU BEGIN\n");
  1353.         fprintf(pHP->Pc2Profile, "PgmTitle: %s\n", pMenuData->PgmTitle);
  1354.         SaveMenu(pMenuData->Submenu);
  1355.         fprintf(pHP->Pc2Profile, "SUBMENU END\n");
  1356.         }
  1357.     if(pMenuData->Item==ENTRYMENUITEM)
  1358.         {
  1359. /*                                                                                      *\
  1360.  * If it is a MENUITEM, so write the header MENUITEM and then write the profile data    *
  1361.  * from the MENUDATA structure pointed by pMenuData.                                    *
  1362. \*                                                                                      */
  1363.         fprintf(pHP->Pc2Profile, "MENUITEM\n");
  1364.         fprintf(pHP->Pc2Profile, "PgmTitle: %s\n", pMenuData->PgmTitle);
  1365.                                         /* Window's title only written if defined */
  1366.         if(strcmp(pMenuData->WindowTitle, pMenuData->PgmTitle))
  1367.             fprintf(pHP->Pc2Profile, "WindowTitle: %s\n", pMenuData->WindowTitle);
  1368.         if(strcmp(pMenuData->PgmName, ""))
  1369.             fprintf(pHP->Pc2Profile, "PgmName: %s\n", pMenuData->PgmName);
  1370.         if(strcmp(pMenuData->PgmDirectory, ""))
  1371.             fprintf(pHP->Pc2Profile, "PgmDirectory: %s\n", pMenuData->PgmDirectory);
  1372.         if(strcmp(pMenuData->PgmInputs, ""))
  1373.             fprintf(pHP->Pc2Profile, "PgmInputs: %s\n", pMenuData->PgmInputs);
  1374.                                         /* Write DOS Settings only if available */
  1375.         if(strlen(pMenuData->PgmDosSettings)!=0)
  1376.             {
  1377.             if((pMenuData->SessionType==PROG_VDM) ||
  1378.                 (pMenuData->SessionType==PROG_WINDOWEDVDM) ||
  1379.                 (pMenuData->SessionType==PROG_WINDOW_REAL) ||
  1380.                 (pMenuData->SessionType==PROG_WINDOW_PROT) ||
  1381.                 (pMenuData->SessionType==PROG_31_STDSEAMLESSCOMMON) ||
  1382.                 (pMenuData->SessionType==PROG_31_ENHSEAMLESSCOMMON) ||
  1383.                 (pMenuData->SessionType==PROG_31_ENH))
  1384.                 {
  1385.                 fprintf(pHP->Pc2Profile, "DOSSETTINGS BEGIN\n");
  1386.                                         /* The required \n is already part of the string */
  1387.                 fprintf(pHP->Pc2Profile, "%s", pMenuData->PgmDosSettings);
  1388.                 fprintf(pHP->Pc2Profile, "DOSSETTINGS END\n");
  1389.                 }
  1390.             }
  1391.                                         /* Write Environment settings only if available */
  1392.         if(strlen(pMenuData->PgmEnvironment)!=0)
  1393.             {
  1394.             if((pMenuData->SessionType==PROG_FULLSCREEN) ||
  1395.                 (pMenuData->SessionType==PROG_WINDOWABLEVIO) ||
  1396.                 (pMenuData->SessionType==PROG_PM))
  1397.                 {
  1398.                 fprintf(pHP->Pc2Profile, "ENVIRONMENT BEGIN\n");
  1399.                                         /* The required \n is already part of the string */
  1400.                 fprintf(pHP->Pc2Profile, "%s", pMenuData->PgmEnvironment);
  1401.                 fprintf(pHP->Pc2Profile, "ENVIRONMENT END\n");
  1402.                 }
  1403.             }
  1404.         if(pMenuData->SessionType!=PROG_DEFAULT)
  1405.             {
  1406.             ULONG   ulTemp;
  1407.  
  1408.             fprintf(pHP->Pc2Profile, "SessionType: ");
  1409.             for(ulTemp=0; ulTemp<SESSIONTYPESIZE; ulTemp++)
  1410.                 if(pMenuData->SessionType==SessionType[ulTemp].usSessionType)
  1411.                     {
  1412.                     fprintf(pHP->Pc2Profile, "%s", SessionType[ulTemp].pucSessionType);
  1413.                     break;
  1414.                     }
  1415.             fprintf(pHP->Pc2Profile, "\n");
  1416.             }
  1417.         if(pMenuData->PgmControl!=SSF_CONTROL_VISIBLE)
  1418.             {
  1419.             ULONG   ulTemp;
  1420.  
  1421.             fprintf(pHP->Pc2Profile, "PgmControl:");
  1422.             for(ulTemp=0; ulTemp<PGMCONTROLSIZE; ulTemp++)
  1423.                 if(pMenuData->PgmControl&PgmControl[ulTemp].usPgmControl)
  1424.                     fprintf(pHP->Pc2Profile, " %s", PgmControl[ulTemp].pucPgmControl);
  1425.             fprintf(pHP->Pc2Profile, "\n");
  1426.             }
  1427.         if(pMenuData->FgBg & SSF_FGBG_BACK)
  1428.             fprintf(pHP->Pc2Profile, "FgBg: SSF_FGBG_BACK\n");
  1429.         if(pMenuData->PgmControl & SSF_CONTROL_SETPOS)
  1430.             {
  1431.             fprintf(pHP->Pc2Profile, "InitXPos: %ld\n", (LONG)pMenuData->InitXPos);
  1432.             fprintf(pHP->Pc2Profile, "InitYPos: %ld\n", (LONG)pMenuData->InitYPos);
  1433.             fprintf(pHP->Pc2Profile, "InitXSize: %lu\n", (ULONG)pMenuData->InitXSize);
  1434.             fprintf(pHP->Pc2Profile, "InitYSize: %lu\n", (ULONG)pMenuData->InitYSize);
  1435.             }
  1436.         if(pMenuData->SwpFlag & SWP_NOMOVE)
  1437.             fprintf(pHP->Pc2Profile, "WindowControl: SWP_NOMOVE\n");
  1438.         if((pMenuData->KeyData).usCh!=0)
  1439.             {                           /* KC_CTRL and/or KC_ALT may be set */
  1440.             if((pMenuData->KeyData).usFlags==KC_CTRL)
  1441.                 fprintf(pHP->Pc2Profile, "KeyControl: KC_CTRL\n");
  1442.             if((pMenuData->KeyData).usFlags==KC_ALT)
  1443.                 fprintf(pHP->Pc2Profile, "KeyControl: KC_ALT\n");
  1444.             if(pMenuData->SwpFlag & SWP_MAXIMIZE)
  1445.                 fprintf(pHP->Pc2Profile, "WindowControl: SWP_MAXIMIZE\n");
  1446.             if(pMenuData->SwpFlag & SWP_RESTORE)
  1447.                 fprintf(pHP->Pc2Profile, "WindowControl: SWP_RESTORE\n");
  1448.             fprintf(pHP->Pc2Profile, "KeyData: %c\n", (UCHAR)(pMenuData->KeyData).usCh);
  1449.             }
  1450.         if((pMenuData->PriorityClass!=PRTYC_NOCHANGE) || (pMenuData->PriorityDelta!=PRTYC_NOCHANGE))
  1451.             {
  1452.             fprintf(pHP->Pc2Profile, "PriorityClass: %lu\n", (ULONG)pMenuData->PriorityClass);
  1453.             fprintf(pHP->Pc2Profile, "PriorityDelta: %ld\n", (ULONG)pMenuData->PriorityDelta);
  1454.             }
  1455.         }
  1456.     if(pMenuData->Item==ENTRYCONTROL)
  1457.         {
  1458. /*                                                                                      *\
  1459.  * If it is a CONTROL so write the header MENUCONTROL and then write the profile data   *
  1460.  * from the MENUDATA structure pointed by pMenuData.                                    *
  1461. \*                                                                                      */
  1462.         fprintf(pHP->Pc2Profile, "MENUCONTROL\n");
  1463.         fprintf(pHP->Pc2Profile, "PgmTitle: %s\n", pMenuData->PgmTitle);
  1464.         }
  1465. /*                                                                                      *\
  1466.  * If one is available, get the next element in the linked list, else we are at the end *
  1467.  * either at a leaf or at the real last element, in both cases shell back one level.    *
  1468.  * Shell back either exits this procedure completle (we have written the complete       *
  1469.  * linked list) or on level (we have written a complete submenu leaf).                  *
  1470. \*                                                                                      */
  1471.     if(pMenuData->Next!=NULL) pMenuData=pMenuData->Next;
  1472.     else break;
  1473. } while(TRUE);
  1474. }
  1475.  
  1476. /*--------------------------------------------------------------------------------------*\
  1477.  * This recursive procedure searches through the linked list for an element.            *
  1478.  * Req:                                                                                 *
  1479.  *      pMD ........... A pointer to the first element to search on                     *
  1480.  *      id ............ Pointer to the ID to search for (pointer because we don't want  *
  1481.  *                      to get a copy during recursion                                  *
  1482.  *                      The ID is destroyed, so only pass the address of a copy of ID   *
  1483.  * Returns:                                                                             *
  1484.  *      MENUDATA * .... Pointer to match or NULL if not found                           *
  1485. \*--------------------------------------------------------------------------------------*/
  1486. MENUDATA        *SearchItem(MENUDATA *pMD, ULONG *id)
  1487. {
  1488. static MENUDATA *pMDReturn;
  1489.  
  1490. do
  1491. {
  1492.                                         /* If found, save the pointer of it, set ID to the
  1493.                                            value 1 which never occures in the linked list
  1494.                                            to detect the match at the end of the recursion */
  1495.     if(pMD->id==*id) { pMDReturn=pMD; *id=TRUE; break; }
  1496.                                         /* Shell into the Submenus */
  1497.     if(pMD->Item==ENTRYSUBMENU)
  1498.         SearchItem(pMD->Submenu, id);
  1499.     if(pMD->Next!=NULL) pMD=pMD->Next;  /* Keep on searching until found or end of linked list */
  1500.     else
  1501.         {                               /* We're at the end of the linked list */
  1502.         if(*id!=TRUE) pMDReturn=NULL;   /* If we didn't find the item return NULL */
  1503.         break;
  1504.         }
  1505. } while(TRUE);
  1506. return(pMDReturn);
  1507. }
  1508.  
  1509. /*--------------------------------------------------------------------------------------*\
  1510.  * This recursive procedure searches through the linked list for an element.            *
  1511.  * Req:                                                                                 *
  1512.  *      pMD ........... A pointer to the first element to search on                     *
  1513.  *      pWD ........... Pointer to the a WINDOWDATA structure containing the session    *
  1514.  *                      and titlebar title to compare with during recursion             *
  1515.  *      pbFlag ........ A pointer to a flag which is set from FALSE to TRUE, if the     *
  1516.  *                      item was found, the flag is destroyed, so pass a copy.          *
  1517.  * Returns:                                                                             *
  1518.  *      MENUDATA * .... Pointer to match or NULL if not found                           *
  1519. \*--------------------------------------------------------------------------------------*/
  1520. MENUDATA        *SearchTitle(MENUDATA *pMD, WINDOWDATA *pWD, BOOL *pbFlag)
  1521. {
  1522. static MENUDATA *pMDReturn;
  1523.  
  1524. do
  1525. {
  1526.                                         /* Break if pointer is invalid or item was found */
  1527.     if((pMD==NULL) || (*pbFlag==TRUE)) break;
  1528.                                         /* If found, save the pointer of match */
  1529.     if(strlen(pMD->WindowTitle))
  1530.         {
  1531.         if(strstr(pWD->ucPgmTitle, pMD->WindowTitle) ||
  1532.             strstr(pWD->ucWindowTitle, pMD->WindowTitle))
  1533.             {
  1534.             pMDReturn=pMD;
  1535.             *pbFlag=TRUE;               /* Indicate we found and won't search further */
  1536.             break;
  1537.             }
  1538.         else
  1539.                                         /* We haven't found it yet */
  1540.             if(*pbFlag!=TRUE) pMDReturn=NULL;
  1541.         }
  1542.                                         /* We haven't found it yet */
  1543.     else if (*pbFlag!=TRUE) pMDReturn=NULL;
  1544.                                         /* Shell into the Submenus */
  1545.     if(pMD->Item==ENTRYSUBMENU)
  1546.         SearchTitle(pMD->Submenu, pWD, pbFlag);
  1547.     if(pMD->Next!=NULL) pMD=pMD->Next;  /* Keep on searching until found or end of linked list */
  1548.     else break;                         /* We're at the end of the linked list */
  1549. } while(TRUE);
  1550. return(pMDReturn);
  1551. }
  1552.  
  1553. /*--------------------------------------------------------------------------------------*\
  1554.  * This recursive procedure searches through the linked list for all applications that  *
  1555.  * have the autostart flag set and start it by simulating the applications selection    *
  1556.  * from the Popup-Menu.                                                                 *
  1557.  * Req:                                                                                 *
  1558.  *      pMD ........... A pointer to the first element to search on                     *
  1559.  * Returns:                                                                             *
  1560. \*--------------------------------------------------------------------------------------*/
  1561. void    SearchAutoStartItem(MENUDATA *pMD)
  1562. {
  1563. do
  1564. {
  1565.                                         /* If it is a Sub-Menu recurse into */
  1566.     if(pMD->Item==ENTRYSUBMENU)
  1567.         SearchAutoStartItem(pMD->Submenu);
  1568.                                         /* If the autostart flag is set simulate selection
  1569.                                            from Popup-Menu by simulating its message */
  1570.     if(pMD->PgmControl & SSF_CONTROL_AUTOSTART)
  1571.                                         /* Why on the hell using WinPostMsg() does not work,
  1572.                                            that is DosStartSession() fails because its implicit
  1573.                                            call of DosExecPgm() is sometimes not able to load
  1574.                                            a statically linked DLL, even if the working directory
  1575.                                            is set up correctly, I don know.
  1576.                                            Even using WinPostMsg() and calling SearchAutoStartItem()
  1577.                                            from the main thread fails with the same symptom. By the
  1578.                                            way, it even doesn't fail consistent, sometimes it works
  1579.                                            and the failing sessions are not always the same, not
  1580.                                            always the same count of sessions started...very peculiar */
  1581.         WinSendMsg(pHP->hwndClient, WM_COMMAND,
  1582.                                         /* Get ID and set it as posted by a menu control */
  1583.             MPFROM2SHORT((USHORT)(pMD->id), CMDSRC_MENU),
  1584.                                         /* Simulate Message a result of a keyboard operation */
  1585.             MPFROMCHAR(FALSE));
  1586.     if(pMD->Next!=NULL) pMD=pMD->Next;  /* Keep on searching until found end of linked list */
  1587.     else break;
  1588. } while(TRUE);
  1589. }
  1590.  
  1591. /*--------------------------------------------------------------------------------------*\
  1592.  * This procedure adds/changes/query/removes an item to/from the Popup-Menu.            *
  1593.  * Req:                                                                                 *
  1594.  *      msg ........... What to do                                                      *
  1595.  *      mp1 ........... Parameter 1                                                     *
  1596.  *      mp2 ........... Parameter 2                                                     *
  1597.  * Returns:                                                                             *
  1598.  *      MRESULT ....... Returned value of function                                      *
  1599. \*--------------------------------------------------------------------------------------*/
  1600. MRESULT SetPopupMenu(ULONG msg, MPARAM mp1, MPARAM mp2)
  1601. {
  1602. MENUDATA        *pMDChange;             /* Pointer to menuentry to change within menu */
  1603. MENUDATA        *pMD;                   /* Pointer to menuentry where changed menuentry gets
  1604.                                            modified afterwards */
  1605. ULONG           id;                     /* ID of the menuentry pointed to bz pMD */
  1606. MENUITEM        miMI;                   /* Update menus with this structure */
  1607. HWND            hwndMenu;               /* Menu window handle */
  1608. HWND            hwndSubMenu;            /* Window handle of a pulldown menu within the menu bar */
  1609. MRESULT         mr;                     /* PM API result */
  1610. BOOL            bResult;
  1611.  
  1612. bResult=FALSE;
  1613. switch(msg)
  1614. {
  1615. /*                                                                                      *\
  1616.  * Syntax: MM_INSERTITEM(MENUITEM|SUBMENU), MENUDATA *pMDChange, MENUDATA *pMD          *
  1617. \*                                                                                      */
  1618. /*                                                                                      *\
  1619.  * Insert a Menuitem, a Submenu, Menuentry or Control, into a (Sub)menu, even if it is  *
  1620.  * empty.                                                                               *
  1621. \*                                                                                      */
  1622. case MM_INSERTITEMMENUITEM:
  1623. /*                                                                                      *\
  1624.  * Insert a Menuitem, a Submenu or Menuentry as the first child entry of a parent       *
  1625.  * Submenu.                                                                             *
  1626. \*                                                                                      */
  1627. case MM_INSERTITEMSUBMENU:
  1628.     pMDChange=PVOIDFROMMP(mp1);         /* Get pointer to MENUDATA structure to insert */
  1629.     pMD=PVOIDFROMMP(mp2);               /* Get pointer to MENUDATA structure insert afterwards */
  1630.     if(pMD==NULL)
  1631.         id=MIT_END;                     /* Insert at end */
  1632.     else if(!strcmp(pMD->PgmTitle, CTRL_BREAKSEPARATOR))
  1633.         id=pMD->Back->id;               /* If we insert after a break separator, we effectifely
  1634.                                            insert after the menu entry before the break separator,
  1635.                                            because the break separator is only a style */
  1636.     else
  1637.         id=pMD->id;                     /* Get id of menuentry insert afterwards */
  1638.                                         /* If the Configuration dialog is added set flag
  1639.                                            to true */
  1640.     if(pMDChange->id==ID_CONFIGDIALOG) pHP->ulStatusFlag&=(~DISPLAYCONFIGDIALOG);
  1641.  
  1642. /*                                                                                      *\
  1643.  * An item (Menuitem or Submenu) is to be inserted into the Popup-Menu, either after    *
  1644.  * a Menuitem or as the first item of a/the (Sub)menu.                                  *
  1645. \*                                                                                      */
  1646.     if(WinSendMsg(
  1647.         pHP->hwndPopupMenu,
  1648.         MM_QUERYITEM,                   /* Query a menuitem */
  1649.         MPFROM2SHORT(id, TRUE),         /* Identifier, include submenus */
  1650.         (MPARAM)&miMI)==FALSE)          /* Into MENUITEM structure */
  1651.         miMI.hwndSubMenu=0;
  1652.                                         /* If we're going to insert a break separator, we don't
  1653.                                            insert a functional menu entry, but have to change the
  1654.                                            style of the menu we "insert" break separator afterwards */
  1655.     if(!strcmp(pMDChange->PgmTitle, CTRL_BREAKSEPARATOR))
  1656.         {
  1657.                                         /* Modify style */
  1658.         miMI.afStyle|=MIS_BREAKSEPARATOR;
  1659.         if(WinSendMsg(
  1660.             pHP->hwndPopupMenu,
  1661.             MM_SETITEM,                 /* Set a menuitem's attribute */
  1662.                                         /* Identifier, include submenus */
  1663.             MPFROM2SHORT(miMI.id, TRUE),
  1664.                                         /* Attributes to set */
  1665.             (MPARAM)&miMI)==FALSE)
  1666.             PM_ERR(pHP->habPc2, pHP->hwndFrame, HELP_CREATEDIALOG, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  1667.                 "Can't modify PC/2's Popup-Menu - continuing...");
  1668.                                         /* Save the menu window handle the item belongs to */
  1669.         pMDChange->hwndItem=pMDChange->Back->hwndItem;
  1670.         break;
  1671.         }
  1672.                                         /* If the item after we insert is a Submenu, then
  1673.                                            use the Submenu handle to insert new items,
  1674.                                            otherwise use the handle of the previous item */
  1675.     if((miMI.hwndSubMenu!=0) && (msg==MM_INSERTITEMSUBMENU))
  1676.         {
  1677.         hwndMenu=miMI.hwndSubMenu;
  1678.         id=MIT_END;
  1679.         }
  1680.     if(msg==MM_INSERTITEMMENUITEM)
  1681.         {                               /* If this is the first item, use the Popup-Menu
  1682.                                            window handle */
  1683.         if(pMDChange->Back==NULL) hwndMenu=pHP->hwndPopupMenu;
  1684.                                         /* If we insert after an available item, get it's
  1685.                                            window handle */
  1686.         else hwndMenu=(pMDChange->Back)->hwndItem;
  1687.         }
  1688.                                         /* If previous exists, insert after the item with
  1689.                                            ID id */
  1690.     if(id!=(ULONG)MIT_END) miMI.iPosition++;
  1691.     else miMI.iPosition=id;             /* Insert at end MIT_END */
  1692.     miMI.afAttribute=0;                 /* Special attribute */
  1693.     miMI.id=pMDChange->id;              /* Item identifier */
  1694.     miMI.hItem=0;                       /* No handle */
  1695.     if(pMDChange->Item==ENTRYSUBMENU)
  1696.         {                               /* If we insert a Submenu, than we need to obtain
  1697.                                            a handle to create one */
  1698.         hwndSubMenu=WinCreateMenu(      /* Create a submenu menuitem */
  1699.             hwndMenu,                   /* Owner- and parent-window handle */
  1700.             NULL);                      /* Binary menu template */
  1701.         miMI.afStyle=MIS_SUBMENU;       /* Style to insert */
  1702.         miMI.hwndSubMenu=hwndSubMenu;   /* Pulldown menu */
  1703.         }
  1704.     if(pMDChange->Item==ENTRYMENUITEM)
  1705.         {                               /* We insert a Menuitem */
  1706.         miMI.afStyle=MIS_TEXT;          /* Style to insert */
  1707.         miMI.hwndSubMenu=0;             /* No pulldown menu */
  1708.         }
  1709.     if(pMDChange->Item==ENTRYCONTROL)
  1710.         {                               /* We insert a Control */
  1711.         if(!strcmp(pMDChange->PgmTitle, CTRL_SEPARATOR))
  1712.             miMI.afStyle=MIS_SEPARATOR; /* For a seperator insert a separator */
  1713.         else
  1714.             miMI.afStyle=MIS_TEXT;
  1715.         miMI.hwndSubMenu=0;
  1716.         }
  1717.     pMDChange->hwndItem=hwndMenu;       /* Save the window handle of the item */
  1718.     mr=WinSendMsg(
  1719.         hwndMenu,
  1720.         MM_INSERTITEM,                  /* Insert a menu item */
  1721.         &miMI,                          /* Item to insert */
  1722.         pMDChange->PgmTitle);           /* Text to insert */
  1723.     if(((SHORT)mr==MIT_ERROR) || ((SHORT)mr==MIT_MEMERROR))
  1724.         PM_ERR(pHP->habPc2, pHP->hwndFrame, HELP_CREATEDIALOG, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  1725.             "Can't modify PC/2's Popup-Menu - continuing...");
  1726.     else bResult=TRUE;
  1727.     break;
  1728.  
  1729. /*                                                                                      *\
  1730.  * Syntax: MM_MOVEMENUITEM, MENUDATA *pMDSource, MENUDATA *pMDDestination               *
  1731. \*                                                                                      */
  1732. case MM_MOVEMENUITEM:
  1733. /*                                                                                      *\
  1734.  * Move a MENUITEM structure with idSource after the idDestination.                     *
  1735. \*                                                                                      */
  1736.     {
  1737.     MENUDATA    *pMDSource;
  1738.     MENUDATA    *pMDDestination;
  1739.     ULONG       idSource;               /* Id of Menuitem to be moved */
  1740.     ULONG       idDestination;          /* Id of Menuitem after which the removed Menuitem
  1741.                                            will be inserted */
  1742.     MENUITEM    miSource;               /* MENUITEM structure of to be moved Menuitem */
  1743.     MENUITEM    miDestination;          /* MENUITEM structure of Menuitem after which
  1744.                                            the removed Menuitem will be inserted */
  1745.  
  1746.     pMDSource=PVOIDFROMMP(mp1);
  1747.     pMDDestination=PVOIDFROMMP(mp2);
  1748.     idSource=pMDSource->id;             /* Get id of to be removed Menuitem */
  1749.                                         /* If a menuitem has to be moved after a break separator
  1750.                                            move it after previous menu entry, because a break
  1751.                                            separator is just a style of this entry */
  1752.     if(!strcmp(pMDDestination->PgmTitle, CTRL_BREAKSEPARATOR))
  1753.         idDestination=pMDDestination->Back->id;
  1754.     else
  1755.                                         /* Get id of Menuitem after which removed Menuitem
  1756.                                            will be inserted */
  1757.         idDestination=pMDDestination->id;
  1758. /*                                                                                      *\
  1759.  * If the source and destination Menuitem are elements of the same level then they have *
  1760.  * the same item handle.                                                                *
  1761. \*                                                                                      */
  1762.     if(pMDSource->hwndItem==pMDDestination->hwndItem)
  1763.         bResult=TRUE;
  1764.     else
  1765.         bResult=FALSE;
  1766.                                         /* Query all (Sub)menus for to be moved Menuitem */
  1767.     WinSendMsg(pHP->hwndPopupMenu, MM_QUERYITEM,
  1768.         MPFROM2SHORT(idSource, TRUE), (MPARAM)&miSource);
  1769.                                         /* Delete the to be moved Menuitem. Don't use MM_DELETEITEM
  1770.                                            because it frees all OS/2 internal structures,
  1771.                                            whereas MM_REMOVEITEM doesn't free them */
  1772.     WinSendMsg(pHP->hwndPopupMenu, MM_REMOVEITEM,
  1773.         MPFROM2SHORT(idSource, TRUE), (MPARAM)NULL);
  1774.                                         /* Query all (Sub)menus for Menuitem after which
  1775.                                            the removed Menuitem will be inserted */
  1776.     WinSendMsg(pHP->hwndPopupMenu, MM_QUERYITEM,
  1777.         MPFROM2SHORT(idDestination, TRUE), (MPARAM)&miDestination);
  1778.  
  1779.     if(bResult==TRUE)
  1780.         {                               /* If the destination of the Source Menuitem follows
  1781.                                            any previous Menuitem in the same level, just
  1782.                                            insert it one position behind */
  1783.         miSource.iPosition=++miDestination.iPosition;
  1784.         hwndMenu=pMDDestination->hwndItem;
  1785.         mr=WinSendMsg(hwndMenu, MM_INSERTITEM, &miSource, pMDSource->PgmTitle);
  1786.         }
  1787.     else
  1788.         {                               /* If the destination of the source Menuitem is the
  1789.                                            first position of a Submenu, insert it at 0-based
  1790.                                            position 0 */
  1791.         hwndMenu=miDestination.hwndSubMenu;
  1792.         miSource.iPosition=0;
  1793.         mr=WinSendMsg(hwndMenu, MM_INSERTITEM, &miSource, pMDSource->PgmTitle);
  1794.         }
  1795.  
  1796.     }
  1797.     break;
  1798.  
  1799. /*                                                                                      *\
  1800.  * Syntax: MM_SETITEMTEXT, MENUDATA *pMDChange, ULONG id                                *
  1801. \*                                                                                      */
  1802. case MM_SETITEMTEXT:
  1803.     pMDChange=PVOIDFROMMP(mp1);         /* Get pointer to MENUDATA structure to update */
  1804.     id=LONGFROMMP(mp2);                 /* Get id to update */
  1805. /*                                                                                      *\
  1806.  * A available menuitem was selected to change. Change the text of the menuitem to the  *
  1807.  * new one.                                                                             *
  1808. \*                                                                                      */
  1809.     if(WinSendMsg(
  1810.         pHP->hwndPopupMenu,
  1811.         MM_SETITEMTEXT,                 /* Set the text of a menuitem */
  1812.         MPFROMSHORT(id),                /* Item ID */
  1813.                                         /* New menuitem text */
  1814.         (MPARAM)pMDChange->PgmTitle)==FALSE)
  1815.         PM_ERR(pHP->habPc2, pHP->hwndFrame, HELP_CREATEDIALOG, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  1816.             "Can't modify PC/2's Popup-Menu - continuing...");
  1817.     else bResult=TRUE;
  1818.     break;
  1819.  
  1820. /*                                                                                      *\
  1821.  * Syntax: MM_DELETEITEM, MENUDATA *pMDChange, MENUDATA *pMD                            *
  1822. \*                                                                                      */
  1823. case MM_DELETEITEM:
  1824.     pMDChange=PVOIDFROMMP(mp1);         /* Get pointer to MENUDATA structure to delete */
  1825.     pMD=PVOIDFROMMP(mp2);               /* Get pointer to MENUDATA structure insert afterwards */
  1826.     if(!strcmp(pMD->PgmTitle, CTRL_BREAKSEPARATOR))
  1827.         id=pMD->Back->id;               /* If we delete a break separator, we effectifely
  1828.                                            delete the style of the previous menu entry */
  1829.     else
  1830.         id=pMD->id;                     /* Get id to delete */
  1831.                                         /* If the Configuration dialog is removed set flag
  1832.                                            to false */
  1833.     if(pMDChange->id==ID_CONFIGDIALOG) pHP->ulStatusFlag|=DISPLAYCONFIGDIALOG;
  1834. /*                                                                                      *\
  1835.  * A available menuitem was selected to delete. Delete the specified menuitem.          *
  1836. \*                                                                                      */
  1837.                                         /* If we're going to delete a break separator, we don't
  1838.                                            insert a functional menu entry, but have to change the
  1839.                                            style of the menu we "delete" break separator afterwards */
  1840.     if(!strcmp(pMDChange->PgmTitle, CTRL_BREAKSEPARATOR))
  1841.         {
  1842.         if(WinSendMsg(
  1843.             pHP->hwndPopupMenu,
  1844.             MM_QUERYITEM,               /* Query a menuitem */
  1845.             MPFROM2SHORT(id, TRUE),     /* Identifier, include submenus */
  1846.             (MPARAM)&miMI)==FALSE)      /* Into MENUITEM structure */
  1847.             miMI.hwndSubMenu=0;
  1848.                                         /* Modify style */
  1849.         miMI.afStyle&=(~MIS_BREAKSEPARATOR);
  1850.         if(WinSendMsg(
  1851.             pHP->hwndPopupMenu,
  1852.             MM_SETITEM,                 /* Set a menuitem's attribute */
  1853.                                         /* Identifier, include submenus */
  1854.             MPFROM2SHORT(pMD->id, TRUE),
  1855.                                         /* Attributes to set */
  1856.             (MPARAM)&miMI)==FALSE)
  1857.             PM_ERR(pHP->habPc2, pHP->hwndFrame, HELP_CREATEDIALOG, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  1858.                 "Can't modify PC/2's Popup-Menu - continuing...");
  1859.         break;
  1860.         }
  1861.     if(pMDChange->Item==ENTRYSUBMENU)
  1862.         {                               /* It the menuitem is a Submenu, also delete the
  1863.                                            first item of it (which should be empty) */
  1864.         mr=WinSendMsg(
  1865.             pHP->hwndPopupMenu,
  1866.             MM_DELETEITEM,              /* Delete a menuitem */
  1867.                                         /* Item ID, include Submenus */
  1868.             MPFROM2SHORT((pMDChange->Submenu->id), TRUE),
  1869.             (MPARAM)NULL);
  1870.         }
  1871.     mr=WinSendMsg(
  1872.         pHP->hwndPopupMenu,
  1873.         MM_DELETEITEM,                  /* Delete a menuitem */
  1874.         MPFROM2SHORT(id, TRUE),         /* Item ID, include Submenus */
  1875.         (MPARAM)NULL);
  1876.     bResult=TRUE;
  1877.     break;
  1878. }
  1879. return(MPFROMSHORT(bResult));
  1880. }
  1881.  
  1882. /*--------------------------------------------------------------------------------------*\
  1883.  * This procedure handles to copy a fully qualified path & filename into the corres-    *
  1884.  * ponding entryfields of the Program Installation dialog.                              *
  1885.  * Req:                                                                                 *
  1886.  *      hwndDlg ....... handle of Program installation dialog                           *
  1887.  *      pucFullFileName fully qualified path & filename of application to add           *
  1888.  *                      the name of an object to add                                    *
  1889.  *      bObject ....... TRUE if it is an WPS object                                     *
  1890. \*--------------------------------------------------------------------------------------*/
  1891. void InstallFilename2Dialog(HWND hwndDlg, UCHAR *pucFullFileName, BOOL bObject)
  1892. {
  1893. UCHAR   ucBuffer[CCHMAXPATH+6];         /* Longer than 260 because of "s */
  1894. UCHAR   ucFullFileName[EF_SIZE255+1];
  1895. UCHAR   *pucTemp;
  1896. BOOL    bBatchFile=FALSE;
  1897. ULONG   ulAppType;                      /* Type of application we're installing */
  1898. USHORT  usSessionType;
  1899.  
  1900. if(bObject==TRUE)
  1901.     {
  1902.     usSessionType=PROG_WPSOBJECT;       /* It is an WPS object */
  1903.                                         /* Set title and object name info entryfields */
  1904.     if(!WinQueryWindowTextLength(WinWindowFromID(hwndDlg, PIEF_PROGRAMTITLE)))
  1905.         {
  1906.         if((pucTemp=strrchr(pucFullFileName, '\\'))!=NULL)
  1907.             WinSetDlgItemText(hwndDlg, PIEF_PROGRAMTITLE, ++pucTemp);
  1908.         else
  1909.             WinSetDlgItemText(hwndDlg, PIEF_PROGRAMTITLE, pucFullFileName);
  1910.         }
  1911.     WinSetDlgItemText(hwndDlg, PIEF_PATHFILENAME, pucFullFileName);
  1912.     WinSetDlgItemText(hwndDlg, PIEF_PARAMETERS, "");
  1913.     WinSetDlgItemText(hwndDlg, PIEF_DIRECTORY, "");
  1914.     }
  1915. else
  1916.     {                                   /* It is a file */
  1917.                                         /* Get the type of application */
  1918.     DosQueryAppType(pucFullFileName, &ulAppType);
  1919.     usSessionType=PROG_DEFAULT;         /* Assume Shell determined for default */
  1920.     if((ulAppType & 0x7)==FAPPTYP_WINDOWAPI) usSessionType=PROG_PM;
  1921.     if((ulAppType & 0x7)==FAPPTYP_WINDOWCOMPAT) usSessionType=PROG_WINDOWABLEVIO;
  1922.     if(ulAppType & FAPPTYP_DOS) usSessionType=PROG_WINDOWEDVDM;
  1923.     if(ulAppType & FAPPTYP_WINDOWSREAL) usSessionType=PROG_WINDOW_REAL;
  1924.     if(ulAppType & FAPPTYP_WINDOWSPROT) usSessionType=PROG_WINDOW_PROT;
  1925.     if(ulAppType & FAPPTYP_WINDOWSPROT31) usSessionType=PROG_31_ENH;
  1926.     }
  1927. if(bObject==FALSE)
  1928.     {
  1929.                                         /* Convert to uppercase to test for .CMD extension */
  1930.     strcpy(ucFullFileName, pucFullFileName);
  1931.     strupr(ucFullFileName);
  1932.                                         /* Now test for a OS/2 batch file */
  1933.     if(strstr(ucFullFileName, ".CMD")!=NULL)
  1934.         {
  1935.         usSessionType=PROG_WINDOWABLEVIO;
  1936.         bBatchFile=TRUE;
  1937.         if(strchr(pucFullFileName, ' ')!=NULL)
  1938.             {                           /* If path and filename contains spaces, insert
  1939.                                            two quotation marks */
  1940.             strcpy(ucBuffer, "/c \"\"");
  1941.             strcat(ucBuffer, pucFullFileName);
  1942.             strcat(ucBuffer, "\"\"");
  1943.             }
  1944.         else
  1945.             {                           /* Else add just /c to [path]filename.cmd */
  1946.             strcpy(ucBuffer, "/c ");
  1947.             strcat(ucBuffer, pucFullFileName);
  1948.             }
  1949.         }
  1950.                                         /* Now test for a DOS batch file */
  1951.     if(strstr(ucFullFileName, ".BAT")!=NULL)
  1952.         {
  1953.         usSessionType=PROG_WINDOWEDVDM;
  1954.         bBatchFile=TRUE;
  1955.         strcpy(ucBuffer, "/c ");        /* Add just /c to [path]filename.cmd */
  1956.         strcat(ucBuffer, pucFullFileName);
  1957.         }
  1958.     if(bBatchFile==TRUE)
  1959.         {                               /* Set batchfile as parameter and empty path & filename */
  1960.         WinSetDlgItemText(hwndDlg, PIEF_PARAMETERS, ucBuffer);
  1961.         WinSetDlgItemText(hwndDlg, PIEF_PATHFILENAME, "");
  1962.         }
  1963.     else
  1964.         {                               /* Set full qualified path and empty parameters */
  1965.         WinSetDlgItemText(hwndDlg, PIEF_PATHFILENAME, pucFullFileName);
  1966.         WinSetDlgItemText(hwndDlg, PIEF_PARAMETERS, "");
  1967.         }
  1968.     strcpy(ucBuffer, pucFullFileName);  /* Save full path & filename */
  1969.                                         /* Extract filename */
  1970.     pucTemp=pucFullFileName+strlen(pucFullFileName);
  1971.     for( ; (*pucTemp!='\\') && (pucTemp>=pucFullFileName); /* pucTemp-- */)
  1972.         pucTemp--;
  1973.                                         /* Set filename */
  1974.     if(!WinQueryWindowTextLength(WinWindowFromID(hwndDlg, PIEF_PROGRAMTITLE)))
  1975.         WinSetDlgItemText(hwndDlg, PIEF_PROGRAMTITLE, (pucTemp+1));
  1976.     *pucTemp='\0';                      /* Get path as working directory */
  1977.                                         /* Set working directory */
  1978.     WinSetDlgItemText(hwndDlg, PIEF_DIRECTORY, pucFullFileName);
  1979.     }
  1980.                                         /* Reflect the application type with the Program
  1981.                                            Type radiobuttons */
  1982. WinSendMsg(hwndDlg, WM_SETUPPROGRAMTYPE,
  1983.     MPFROMSHORT(usSessionType), (MPARAM)NULL);
  1984. }
  1985.  
  1986. /*--------------------------------------------------------------------------------------*\
  1987.  * This procedure disables or enables child windows of a dialog window according to the *
  1988.  * bDisable flag.                                                                       *
  1989.  * Req:                                                                                 *
  1990.  *      hwndDlg ....... handle of Program installation dialog                           *
  1991.  *      usDialogIDs ... array of IDs of the child windows of a dialog                   *
  1992.  *      usItemCount ... number of IDs in the array                                      *
  1993.  *      ulStyle ....... WS_VISIBLE | WS_DISABLED or not                                 *
  1994. \*--------------------------------------------------------------------------------------*/
  1995. void    DisableDialogItem(HWND hwndDlg, USHORT usDialogIDs[], USHORT usItemCount, ULONG ulStyle)
  1996. {
  1997. USHORT  usTemp;
  1998.  
  1999. if(ulStyle&WS_DISABLED)
  2000.                                         /* Enumerate and disable all child windows */
  2001.     for(usTemp=0; usTemp<usItemCount; usTemp++)
  2002.         WinEnableWindow(WinWindowFromID(hwndDlg, usDialogIDs[usTemp]), FALSE);
  2003. else
  2004.                                         /* Enumerate and enable all child windows */
  2005.     for(usTemp=0; usTemp<usItemCount; usTemp++)
  2006.         WinEnableWindow(WinWindowFromID(hwndDlg, usDialogIDs[usTemp]), TRUE);
  2007. if(ulStyle&WS_VISIBLE)
  2008.                                         /* Enumerate and show all child windows */
  2009.     for(usTemp=0; usTemp<usItemCount; usTemp++)
  2010.         WinSetWindowPos(WinWindowFromID(hwndDlg, usDialogIDs[usTemp]),
  2011.             0, 0, 0, 0, 0, SWP_SHOW);
  2012. else
  2013.                                         /* Enumerate and hide all child windows */
  2014.     for(usTemp=0; usTemp<usItemCount; usTemp++)
  2015.         WinSetWindowPos(WinWindowFromID(hwndDlg, usDialogIDs[usTemp]),
  2016.             0, 0, 0, 0, 0, SWP_HIDE);
  2017. }
  2018.  
  2019. #define APPLICATIONNAMEPC2              "PC/2 Desktop Configuration"
  2020. #define APPLICATIONNAMEPC2SPOOLER       "PC/2 Spooler Configuration"
  2021.  
  2022. /*--------------------------------------------------------------------------------------*\
  2023.  * This procedure accesses the PC2.INI configuration file.                              *
  2024.  * Req:                                                                                 *
  2025.  *      pucFilenameINI. pointer to path of PC2.INI                                      *
  2026.  *      bRead ......... TRUE/FALSE if read/write from/to PC2.INI                        *
  2027.  * Ref:                                                                                 *
  2028.  *      HookParameters. read/write from/to PC2.INI                                      *
  2029.  * Ret:                                                                                 *
  2030.  *      NULL .......... Error occured, otherwise no error occured                       *
  2031. \*--------------------------------------------------------------------------------------*/
  2032. ULONG   INIAccess(UCHAR *pucFilenameINI, BOOL bRead)
  2033. {
  2034. HINI    hiniPC2INI;
  2035. ULONG   ulTemp;
  2036. ULONG   ulRc=(ULONG)TRUE;
  2037.  
  2038.                                         /* Open PC2.INI */
  2039. hiniPC2INI=PrfOpenProfile(pHP->habPc2, pucFilenameINI);
  2040. if(hiniPC2INI!=NULLHANDLE)
  2041.     {                                   /* Only try to access a valid PC2.INI */
  2042.     if(bRead==TRUE)
  2043.         {
  2044.         ULONG   ulReadStatusFlag;
  2045.  
  2046.         ulTemp=sizeof(ULONG);
  2047.         if(PrfQueryProfileData(         /* Query binary data from profile */
  2048.             hiniPC2INI,                 /* Handle of profile */
  2049.                                         /* Application name */
  2050.             APPLICATIONNAMEPC2,
  2051.             "Desktop Status",           /* Key name */
  2052.             &ulReadStatusFlag,
  2053.             &ulTemp)==FALSE)            /* Size of value data */
  2054.             {
  2055.             ulRc=0L;
  2056.             pHP->ulStatusFlag=VIRTUALDESKTOP|CLICK2MOVE|OVERVIEW|SHOWSPOOLERWINDOW|BUTTON2ZORDER|NORMALSHUTDOWN;
  2057.             ulReadStatusFlag=pHP->ulStatusFlag;
  2058.             }
  2059.         pHP->ulStatusFlag=(ulReadStatusFlag & WRITEMASK);
  2060.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "Debug Flag",
  2061.             &pHP->ulDebug, &ulTemp)==FALSE)
  2062.             {
  2063.             ulRc=0L;
  2064.             pHP->ulDebug=DEBUG_NO;
  2065.             }
  2066.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "Scroll Percentage",
  2067.             &pHP->ulScrollPercentage, &ulTemp)==FALSE)
  2068.             {
  2069.             ulRc=0L;
  2070.             pHP->ulScrollPercentage=100;
  2071.             }
  2072.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "Click Flag",
  2073.             &pHP->ulClickFlag, &ulTemp)==FALSE)
  2074.             {
  2075.             ulRc=0L;
  2076.             pHP->ulClickFlag=WM_BUTTON1DBLCLK;
  2077.             }
  2078.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "X Position",
  2079.             &pHP->swpPC2.x, &ulTemp)==FALSE)
  2080.             {
  2081.             ulRc=0L;
  2082.             pHP->swpPC2.x=0;
  2083.             }
  2084.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "Y Position",
  2085.             &pHP->swpPC2.y, &ulTemp)==FALSE)
  2086.             {
  2087.             ulRc=0L;
  2088.             pHP->swpPC2.y=0;
  2089.             }
  2090.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "X Size",
  2091.             &pHP->swpPC2.cx, &ulTemp)==FALSE)
  2092.             {
  2093.             ulRc=0L;
  2094.             pHP->swpPC2.cx=-1;
  2095.             }
  2096.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "Y Size",
  2097.             &pHP->swpPC2.cy, &ulTemp)==FALSE)
  2098.             {
  2099.             ulRc=0L;
  2100.             pHP->swpPC2.cy=-1;
  2101.             }
  2102.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2SPOOLER, "X Position",
  2103.             &pHP->swpPC2Spooler.x, &ulTemp)==FALSE)
  2104.             {
  2105.             ulRc=0L;
  2106.             pHP->swpPC2Spooler.x=0;
  2107.             }
  2108.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2SPOOLER, "Y Position",
  2109.             &pHP->swpPC2Spooler.y, &ulTemp)==FALSE)
  2110.             {
  2111.             ulRc=0L;
  2112.             pHP->swpPC2Spooler.y=0;
  2113.             }
  2114.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2SPOOLER, "X Size",
  2115.             &pHP->swpPC2Spooler.cx, &ulTemp)==FALSE)
  2116.             {
  2117.             ulRc=0L;
  2118.             pHP->swpPC2Spooler.cx=-1;
  2119.             }
  2120.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2SPOOLER, "Y Size",
  2121.             &pHP->swpPC2Spooler.cy, &ulTemp)==FALSE)
  2122.             {
  2123.             ulRc=0L;
  2124.             pHP->swpPC2Spooler.cy=-1;
  2125.             }
  2126.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2SPOOLER, "Splitbar Position",
  2127.             &pHP->lSplitbarPosition, &ulTemp)==FALSE)
  2128.             {
  2129.             ulRc=0L;
  2130.             pHP->lSplitbarPosition=100;
  2131.             }
  2132.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "X Desktop Count",
  2133.             &pHP->ulHorizontalDesktops, &ulTemp)==FALSE)
  2134.             {
  2135.             ulRc=0L;
  2136.             pHP->ulHorizontalDesktops=3;
  2137.             }
  2138.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "Y Desktop Count",
  2139.             &pHP->ulVerticalDesktops, &ulTemp)==FALSE)
  2140.             {
  2141.             ulRc=0L;
  2142.             pHP->ulVerticalDesktops=1;
  2143.             }
  2144.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "Overview FCF",
  2145.             &pHP->ulOverviewFCF, &ulTemp)==FALSE)
  2146.             {
  2147.             ulRc=0L;
  2148.             pHP->ulOverviewFCF=FCF_OVERVIEWWINDOW;
  2149.             }
  2150.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "Background Bitmap Flag",
  2151.             &pHP->ulBackgroundBitmapFlag, &ulTemp)==FALSE)
  2152.             {
  2153.             ulRc=0L;
  2154.                                         /* Low USHORT of ulBackgroundBitmapFlag contains tile count */
  2155.             pHP->ulBackgroundBitmapFlag=BITMAPNORMAL | 3;
  2156.             }
  2157.                                         /* The length of Desktop name and Window List name
  2158.                                            is the same namely MAXNAMEL+1 */
  2159.         ulTemp=sizeof(pHP->ucDesktopName);
  2160.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "Desktop Name",
  2161.             pHP->ucDesktopName, &ulTemp)==FALSE)
  2162.             {
  2163.             ulRc=0L;
  2164.             strcpy(pHP->ucDesktopName, "Desktop");
  2165.             }
  2166.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "Window List Name",
  2167.             pHP->ucWindowListName, &ulTemp)==FALSE)
  2168.             {
  2169.             ulRc=0L;
  2170.             strcpy(pHP->ucWindowListName, "Window List");
  2171.             }
  2172.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "Background Bitmap",
  2173.             pHP->ucBackgroundBitmap, &ulTemp)==FALSE)
  2174.             {
  2175.             ulRc=0L;
  2176.             strcpy(pHP->ucBackgroundBitmap, "\\OS2\\BITMAP\\OS2LOGO.BMP");
  2177.             }
  2178.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "Window Font",
  2179.             pHP->ucPC2WindowFont, &ulTemp)==FALSE)
  2180.             {
  2181.             ulRc=0L;
  2182.             strcpy(pHP->ucPC2WindowFont, "8.Helv");
  2183.             }
  2184.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "Popup-Menu Font",
  2185.             pHP->ucPopupMenuFont, &ulTemp)==FALSE)
  2186.             {
  2187.             ulRc=0L;
  2188.             strcpy(pHP->ucPopupMenuFont, "8.Helv");
  2189.             }
  2190.         if(PrfQueryProfileData(hiniPC2INI, APPLICATIONNAMEPC2, "Spooler Font",
  2191.             pHP->ucPC2SpoolerFont, &ulTemp)==FALSE)
  2192.             {
  2193.             ulRc=0L;
  2194.             strcpy(pHP->ucPC2SpoolerFont, "8.Helv");
  2195.             }
  2196.         }
  2197.     else
  2198.         {
  2199.         ULONG   ulWriteStatusFlag;
  2200.  
  2201.                                         /* Write only permanent status bits, ignore
  2202.                                            temporary ones */
  2203.         ulWriteStatusFlag=pHP->ulStatusFlag & WRITEMASK;
  2204.         WinSetPointer(                  /* Set wait pointer */
  2205.             HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE));
  2206.                                         /* Write binary data to profile */
  2207.         if(!PrfWriteProfileData(
  2208.             hiniPC2INI,                 /* Handle of profile */
  2209.                                         /* Application name */
  2210.             APPLICATIONNAMEPC2,
  2211.             "Desktop Status",           /* Key name */
  2212.                                         /* Value data */
  2213.             &ulWriteStatusFlag,
  2214.             sizeof(ULONG)))              /* Size of value data */
  2215.             ulRc=0L;
  2216.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2217.             "Debug Flag", &pHP->ulDebug, sizeof(ULONG)))
  2218.             ulRc=0L;
  2219.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2220.             "Scroll Percentage", &pHP->ulScrollPercentage, sizeof(ULONG)))
  2221.             ulRc=0L;
  2222.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2223.             "Click Flag", &pHP->ulClickFlag, sizeof(ULONG)))
  2224.             ulRc=0L;
  2225.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2226.             "X Position", &pHP->swpPC2.x, sizeof(LONG)))
  2227.             ulRc=0L;
  2228.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2229.             "Y Position", &pHP->swpPC2.y, sizeof(LONG)))
  2230.             ulRc=0L;
  2231.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2232.             "X Size", &pHP->swpPC2.cx, sizeof(LONG)))
  2233.             ulRc=0L;
  2234.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2235.             "Y Size", &pHP->swpPC2.cy, sizeof(LONG)))
  2236.             ulRc=0L;
  2237.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2SPOOLER,
  2238.             "X Position", &pHP->swpPC2Spooler.x, sizeof(LONG)))
  2239.             ulRc=0L;
  2240.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2SPOOLER,
  2241.             "Y Position", &pHP->swpPC2Spooler.y, sizeof(LONG)))
  2242.             ulRc=0L;
  2243.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2SPOOLER,
  2244.             "X Size", &pHP->swpPC2Spooler.cx, sizeof(LONG)))
  2245.             ulRc=0L;
  2246.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2SPOOLER,
  2247.             "Y Size", &pHP->swpPC2Spooler.cy, sizeof(LONG)))
  2248.             ulRc=0L;
  2249.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2SPOOLER,
  2250.             "Splitbar Position", &pHP->lSplitbarPosition, sizeof(LONG)))
  2251.             ulRc=0L;
  2252.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2253.             "X Desktop Count", &pHP->ulHorizontalDesktops, sizeof(ULONG)))
  2254.             ulRc=0L;
  2255.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2256.             "Y Desktop Count", &pHP->ulVerticalDesktops, sizeof(ULONG)))
  2257.             ulRc=0L;
  2258.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2259.             "Overview FCF", &pHP->ulOverviewFCF, sizeof(ULONG)))
  2260.             ulRc=0L;
  2261.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2262.             "Background Bitmap Flag", &pHP->ulBackgroundBitmapFlag, sizeof(ULONG)))
  2263.             ulRc=0L;
  2264.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2265.             "Desktop Name", pHP->ucDesktopName, sizeof(pHP->ucDesktopName)))
  2266.             ulRc=0L;
  2267.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2268.             "Window List Name", pHP->ucWindowListName,
  2269.             sizeof(pHP->ucWindowListName)))
  2270.             ulRc=0L;
  2271.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2272.             "Background Bitmap", pHP->ucBackgroundBitmap,
  2273.             sizeof(pHP->ucBackgroundBitmap)))
  2274.             ulRc=0L;
  2275.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2276.             "Window Font", pHP->ucPC2WindowFont,
  2277.             sizeof(pHP->ucPC2WindowFont)))
  2278.             ulRc=0L;
  2279.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2280.             "Popup-Menu Font", pHP->ucPopupMenuFont,
  2281.             sizeof(pHP->ucPopupMenuFont)))
  2282.             ulRc=0L;
  2283.         if(!PrfWriteProfileData(hiniPC2INI, APPLICATIONNAMEPC2,
  2284.             "Spooler Font", pHP->ucPC2SpoolerFont,
  2285.             sizeof(pHP->ucPC2SpoolerFont)))
  2286.             ulRc=0L;
  2287.         WinSetPointer(                  /* Set arrow pointer */
  2288.             HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
  2289.         }
  2290.                                         /* Close PC2.INI */
  2291.     if(PrfCloseProfile(hiniPC2INI)==FALSE)
  2292.         USR_ERR(pHP->hwndFrame, HELP_PC2INI, MB_INFORMATION|MB_OK|MB_MOVEABLE|MB_DEFBUTTON1,
  2293.             "Can't save configuration data into PC2.INI - continuing... ");
  2294.     }
  2295. else
  2296.     USR_ERR(pHP->hwndFrame, HELP_PC2INI, MB_INFORMATION|MB_OK|MB_MOVEABLE|MB_DEFBUTTON1,
  2297.         "Can't save configuration data into PC2.INI - continuing... ");
  2298. return(ulRc);
  2299. }
  2300.  
  2301. /*--------------------------------------------------------------------------------------*\
  2302.  * This procedure draws a representation of an window onto the overview window.         *
  2303.  * Req:                                                                                 *
  2304.  *      hpsClient ..... Presentation space to draw in                                   *
  2305.  *      pswpWindow .... Pointer to SWP structure containing the size & position to draw *
  2306.  *      ulWindowColor . Color to fill rectangle with                                    *
  2307.  *      ulTextColor ... Color to draw rectangle text                                    *
  2308.  *      ulStyle ....... BACKGROUND_WND if it is a background window                     *
  2309.  *                      FOREGROUND_WND if it is a foreground window                     *
  2310.  *                      BORDERONLY_WND if the border should be drawn only               *
  2311.  *      pszWindowName . Pointer to the window's Window List entry or titlebar text      *
  2312.  * Ref:                                                                                 *
  2313.  *      none                                                                            *
  2314. \*--------------------------------------------------------------------------------------*/
  2315. void    DrawWindow(HPS hpsClient, SWP *pswpWindow, ULONG ulWindowColor, ULONG ulTextColor, ULONG ulStyle, PSZ pszWindowName)
  2316. {
  2317. POINTL          pointl[5];              /* Coordinates of edges of one window */
  2318.                                         /* Dimensions of window's name */
  2319. POINTL          pointlFnt[TXTBOX_COUNT];
  2320. ULONG           ulNameLength;           /* Count of characters of window's name used to display */
  2321.                                         /* Window's name textbox size */
  2322. ULONG           ulFntHeight, ulFntLength;
  2323.  
  2324. pointl[0].x=pswpWindow->x;               /* Lower left starting point */
  2325. pointl[0].y=pswpWindow->y;
  2326. pointl[1].x=pointl[0].x;                /* Upper left point */
  2327. pointl[1].y=pswpWindow->y+pswpWindow->cy;
  2328.                                         /* Upper right ending and starting point */
  2329. pointl[2].x=pswpWindow->x+pswpWindow->cx;
  2330. pointl[2].y=pointl[1].y;
  2331. pointl[3].x=pointl[2].x;                /* Lower right point */
  2332. pointl[3].y=pointl[0].y;
  2333. pointl[4].x=pointl[0].x;                /* Lower left ending point */
  2334. pointl[4].y=pointl[0].y;
  2335. if(!(ulStyle & BORDERONLY_WND))
  2336.     {
  2337.                                         /* Fill Window background */
  2338.     GpiSetColor(hpsClient, ulWindowColor);
  2339.     GpiMove(hpsClient, &pointl[0]);
  2340.     GpiBox(hpsClient, DRO_OUTLINEFILL, &pointl[2], 0, 0);
  2341.     }
  2342.                                         /* Set 3D border color */
  2343. GpiSetColor(hpsClient,
  2344.     WinQuerySysColor(HWND_DESKTOP, ((ulStyle & FOREGROUND_WND) ? SYSCLR_APPWORKSPACE : SYSCLR_SHADOW), 0L));
  2345. GpiMove(hpsClient, &pointl[0]);
  2346.                                         /* Draw 3D border lines */
  2347. GpiPolyLine(hpsClient, 2L, &pointl[1]);
  2348.                                         /* Set 3D border color */
  2349. GpiSetColor(hpsClient,
  2350.     WinQuerySysColor(HWND_DESKTOP, ((ulStyle & FOREGROUND_WND) ? SYSCLR_SHADOW : SYSCLR_APPWORKSPACE), 0L));
  2351. GpiMove(hpsClient, &pointl[2]);
  2352.                                         /* Draw 3D border lines */
  2353. GpiPolyLine(hpsClient, 2L, &pointl[3]);
  2354. if(ulStyle & FOREGROUND_WND)
  2355.     {
  2356.                                         /* Get dimensions of window's name */
  2357.     GpiQueryTextBox(hpsClient, 1L, pszWindowName, TXTBOX_COUNT, pointlFnt);
  2358.     ulFntHeight=pointlFnt[TXTBOX_TOPLEFT].y;
  2359.     ulFntLength=pointlFnt[TXTBOX_CONCAT].x;
  2360.                                         /* If the text is too high or long, don't display it and exit */
  2361.     if((ulFntHeight>(pswpWindow->cy-2)) || (ulFntLength>(pswpWindow->cx-4))) return;
  2362.     for(ulNameLength=2; ulNameLength<=strlen(pszWindowName); ulNameLength++)
  2363.         {
  2364.                                         /* Get dimensions of window's name */
  2365.         GpiQueryTextBox(hpsClient, ulNameLength, pszWindowName, TXTBOX_COUNT, pointlFnt);
  2366.                                         /* If current number of characters don't fit anymore
  2367.                                            into the window, break */
  2368.         if(pointlFnt[TXTBOX_CONCAT].x>=(pswpWindow->cx-4))
  2369.             break;
  2370.                                         /* Get valid dimensions */
  2371.         ulFntHeight=pointlFnt[TXTBOX_TOPLEFT].y;
  2372.         ulFntLength=pointlFnt[TXTBOX_CONCAT].x;
  2373.         }
  2374.     ulNameLength--;                     /* Adjust for not fitting/last character */
  2375.                                         /* Display windows title from Window List or titlebar */
  2376.     GpiSetColor(hpsClient, ulTextColor);
  2377.     pointl[0].x=pswpWindow->x+(pswpWindow->cx-ulFntLength)/2+2;
  2378.     pointl[0].y=pswpWindow->y+pswpWindow->cy-ulFntHeight+1;
  2379.     GpiMove(hpsClient, &pointl[0]);
  2380.     GpiCharString(hpsClient, ulNameLength, pszWindowName);
  2381.     }
  2382. }
  2383.  
  2384. /*--------------------------------------------------------------------------------------*\
  2385.  * This procedure converts DOS settings used in the configuration file and Program      *
  2386.  * Installation dialog to the format required by the WINDOWS32PROPERTYDIALOG in the     *
  2387.  * OS/2 PMVDMP.DLL.                                                                     *
  2388.  * Req:                                                                                 *
  2389.  *      pucSettings ... Pointer to the DOS Settings                                     *
  2390.  *      pulLength ..... Length of the DOS Settings buffer pucSettings on entry/exit     *
  2391.  *      bImport ....... TRUE if we convert data retured by WINDOWS32PROPERTYDIALOG      *
  2392.  *                      FALSE if we convert data into WINDOWS32PROPERTYDIALOG format    *
  2393.  * Ret:                                                                                 *
  2394.  *      pucBuffer ..... Buffer when successfull containing the converted DOS Settings   *
  2395.  *                      NULL on error                                                   *
  2396.  *                      This buffer is allocated as required by ImportDosSettings().    *
  2397.  * Ref:                                                                                 *
  2398.  *      <string>\n<string>\n<string>            Format of a DOS setting that contains   *
  2399.  *                                              more than one entry, e.g. DOS_VERSION   *
  2400.  *      <string>\0h                             One complete DOS setting, whereby       *
  2401.  *                                              <string> may of the above format        *
  2402.  *      \0h\0h                                  End of DOS settings buffer              *
  2403. \*--------------------------------------------------------------------------------------*/
  2404. UCHAR   *ImportDosSettings(UCHAR *pucSettings, ULONG *pulLength, BOOL bImport)
  2405. {
  2406. UCHAR   *pucBuffer;                     /* Return buffer */
  2407. UCHAR   *pucChar;
  2408. ULONG   ulIndex;
  2409. ULONG   ulCounter;
  2410.  
  2411. if(bImport==TRUE)
  2412.     {
  2413.                                         /* Count all \0 characters */
  2414.     for(ulIndex=0, ulCounter=0, pucChar=pucSettings; ulIndex<*pulLength; ulIndex++, pucChar++)
  2415.         if(*pucChar=='\0') ulCounter++;
  2416.     *pulLength+=++ulCounter;            /* Double because all \0 are replaced by \r\n which
  2417.                                            is CRLF, and add \0 termination */
  2418.     pucBuffer=malloc(*pulLength);       /* Allocate return buffer */
  2419.                                         /* Copy DOS settings into return buffer by replacing
  2420.                                            \0 by \r\n (CRLF), replace \n by *. Reserve last
  2421.                                            char for terminating \0 */
  2422.     for(ulIndex=0, pucChar=pucBuffer; ulIndex+1<*pulLength; ulIndex++, pucChar++, pucSettings++)
  2423.         {
  2424.         if(*pucSettings=='\n') *pucChar='*';
  2425.         else if(*pucSettings=='\0')
  2426.             {
  2427.             *pucChar++='\r';
  2428.             *pucChar='\n';
  2429.             ulIndex++;
  2430.             }
  2431.         else
  2432.             *pucChar=*pucSettings;
  2433.         }
  2434.     *pucChar='\0';                      /* Zero termination */
  2435.     }
  2436. else
  2437.     {
  2438.                                         /* Count all \r characters */
  2439.     for(ulIndex=0, ulCounter=0, pucChar=pucSettings; ulIndex<*pulLength; ulIndex++, pucChar++)
  2440.         if(*pucChar=='\r') ulCounter++;
  2441.     *pulLength-=++ulCounter;            /* Half because all \r\n (CRLF) are replaced by \0, remove
  2442.                                            trailing \0 termination */
  2443.     if(!*pulLength) return(NULL);
  2444.     pucBuffer=malloc(*pulLength);       /* Allocate return buffer */
  2445.                                         /* Copy DOS settings into return buffer by replacing
  2446.                                            \r\n by \0 and * by \n */
  2447.     for(ulIndex=0, pucChar=pucBuffer; ulIndex<*pulLength; ulIndex++, pucChar++, pucSettings++)
  2448.         {
  2449.         if(*pucSettings=='*') *pucChar='\n';
  2450.         else if(*pucSettings=='\r')
  2451.             {
  2452.             *pucChar='\0';
  2453.             pucSettings++;
  2454.             }
  2455.         else
  2456.             *pucChar=*pucSettings;
  2457.         }
  2458.     }
  2459. return(pucBuffer);
  2460. }
  2461.  
  2462. /*--------------------------------------------------------------------------------------*\
  2463.  * This procedure fills a program MENUDATA structure from a PROGDETAILS structure.      *
  2464.  * Req:                                                                                 *
  2465.  *      pMenuData ..... MENUDATA structure to be filled from pProgDetails               *
  2466.  *      pProgDetails .. PROGDETAILS structure of WPS Object extracted to fill a program *
  2467.  *                      MENUDATA Menuitem from                                          *
  2468.  * Ret:                                                                                 *
  2469.  *      ulRc .......... Return code: NO_ERROR for no error, errorcode otherwise         *
  2470.  * Ref:                                                                                 *
  2471. \*--------------------------------------------------------------------------------------*/
  2472. ULONG   LoadProgDetails2MenuData(MENUDATA *pMenuData, PROGDETAILS *pProgDetails)
  2473. {
  2474. UCHAR   pszExecutable[CCHMAXPATH];
  2475. UCHAR   ucBuffer[CCHMAXPATH*2];
  2476. BOOL    bCommandFile=FALSE;
  2477.  
  2478. pMenuData->Item=ENTRYMENUITEM;          /* Its a executable, therefor a Menuitem */
  2479.                                         /* Get the programs's name from WPSOBJECTLIST as
  2480.                                            the Menuitem's title */
  2481. if(pProgDetails->pszTitle)
  2482.     {
  2483.     free(pMenuData->PgmTitle);
  2484.     pMenuData->PgmTitle=malloc(strlen(pProgDetails->pszTitle)+1);
  2485.     strcpy(pMenuData->PgmTitle, pProgDetails->pszTitle);
  2486.                                         /* Get the program's session title */
  2487.     free(pMenuData->WindowTitle);
  2488.     pMenuData->WindowTitle=malloc(strlen(pProgDetails->pszTitle)+1);
  2489.     strcpy(pMenuData->WindowTitle, pProgDetails->pszTitle);
  2490.     }
  2491. else
  2492.     {
  2493.     free(pMenuData->PgmTitle);          /* At least a title is required */
  2494.     pMenuData->PgmTitle=malloc(strlen("Unknown")+1);
  2495.     strcpy(pMenuData->PgmTitle, "Unknown");
  2496.     }
  2497.                                         /* Get the program's worling directory */
  2498. if(pProgDetails->pszStartupDir)
  2499.     {
  2500.     free(pMenuData->PgmDirectory);
  2501.     pMenuData->PgmDirectory=malloc(strlen(pProgDetails->pszStartupDir)+1);
  2502.     strcpy(pMenuData->PgmDirectory, pProgDetails->pszStartupDir);
  2503.     }
  2504. if(pProgDetails->pszExecutable)
  2505.     {
  2506.                                         /* Test for *.CMD or *.BAT as program's executable,
  2507.                                            which we must move to the MENUDATA.PgmInputs field */
  2508.     strcpy(pszExecutable, pProgDetails->pszExecutable);
  2509.     strupr(pszExecutable);
  2510.     if((strstr(pszExecutable, ".CMD")) || (strstr(pszExecutable, ".BAT")))
  2511.         {
  2512.         bCommandFile=TRUE;
  2513.         if(strchr(pszExecutable, ' '))
  2514.             {                           /* If filename contains spaces, insert two
  2515.                                            quotation marks */
  2516.             strcpy(ucBuffer, "/c \"");
  2517.             strcat(ucBuffer, pProgDetails->pszExecutable);
  2518.             strcat(ucBuffer, "\"\"");
  2519.             }
  2520.         else
  2521.             {
  2522.             strcpy(ucBuffer, "/c ");
  2523.             strcat(ucBuffer, pProgDetails->pszExecutable);
  2524.             }
  2525.         if(pProgDetails->pszParameters)
  2526.             {                           /* Add additional parameters too */
  2527.             strcat(ucBuffer, " ");
  2528.             strcat(ucBuffer, pProgDetails->pszParameters);
  2529.             }
  2530.         free(pMenuData->PgmInputs);
  2531.         pMenuData->PgmInputs=malloc(strlen(ucBuffer)+1);
  2532.         strcpy(pMenuData->PgmInputs, ucBuffer);
  2533.         }
  2534.     else
  2535.         {
  2536.                                         /* Get the program's executable name */
  2537.         free(pMenuData->PgmName);
  2538.         pMenuData->PgmName=malloc(strlen(pProgDetails->pszExecutable)+1);
  2539.         strcpy(pMenuData->PgmName, pProgDetails->pszExecutable);
  2540.         }
  2541.     }
  2542.                                         /* Get the program's commandline parameters */
  2543. if((pProgDetails->pszParameters) && (bCommandFile==FALSE))
  2544.     {
  2545.     free(pMenuData->PgmInputs);
  2546.     pMenuData->PgmInputs=malloc(strlen(pProgDetails->pszParameters)+1);
  2547.     strcpy(pMenuData->PgmInputs, pProgDetails->pszParameters);
  2548.     }
  2549.                                         /* Get the program's environment, which is usually
  2550.                                            used to store the DOS settings */
  2551. if(pProgDetails->pszEnvironment)
  2552.     {
  2553.     ULONG   ulLengthOut;                /* Lenght of DOS Settings returned by
  2554.                                            ImportDosSettings() */
  2555.     UCHAR   *pucTemp;                   /* Used to find terminating \0\0 in DOS Settings
  2556.                                            used in PROGDETAILS */
  2557.     UCHAR   *pucDosSettingsOut;         /* DOS Settings converted from \0 terminated
  2558.                                            form used in PROGDETAILS to \n\r terminated
  2559.                                            form used in MENUDATA structure */
  2560.  
  2561.     free(pMenuData->PgmDosSettings);
  2562.                                         /* Count size of DOS Settings by counting all characters
  2563.                                            until terminating \0\0 is found */
  2564.     for(ulLengthOut=1, pucTemp=pProgDetails->pszEnvironment;
  2565.         !((*pucTemp=='\0') && (*(pucTemp+1)=='\0'));
  2566.         pucTemp++)
  2567.         {
  2568.                                         /* \n appeares for DOS Settings that may have multiple
  2569.                                            lines, e.g. DOS_DEVICE=x.sys\ny.sys\0 */
  2570.         if(*pucTemp=='\n') *pucTemp='*';
  2571.         ulLengthOut++;
  2572.         }
  2573.     free(pMenuData->PgmDosSettings);
  2574.     pucDosSettingsOut=ImportDosSettings(pProgDetails->pszEnvironment, &ulLengthOut , TRUE);
  2575.                                         /* ImportDosSettings() allocated a buffer of length
  2576.                                            ulLengthOut, in which the DOS Settings have been
  2577.                                            copied. */
  2578.     pMenuData->PgmDosSettings=pucDosSettingsOut;
  2579.     }
  2580.                                         /* Set program's session control */
  2581. if(pProgDetails->progt.fbVisible & SHE_INVISIBLE)
  2582.     pMenuData->PgmControl|=SSF_CONTROL_INVISIBLE;
  2583.                                         /* Set program's session type */
  2584. pMenuData->SessionType=pProgDetails->progt.progc;
  2585. return(NO_ERROR);
  2586. }
  2587.  
  2588. /*--------------------------------------------------------------------------------------*\
  2589.  * This procedure adds recursively a LIST of WPSOBJECTLIST elements to the Popup-Menu.  *
  2590.  * Req:                                                                                 *
  2591.  *      pMenuData ..... "Root" level of Popup-Menu to insert                            *
  2592.  *      pListRoot ..... Pointer to LIST of WPSOBJECTLIST to insert a pMenuData          *
  2593.  * Ret:                                                                                 *
  2594.  *      ulRc .......... Return code: NO_ERROR for no error, errorcode otherwise         *
  2595.  * Ref:                                                                                 *
  2596. \*--------------------------------------------------------------------------------------*/
  2597. ULONG   ConvertWPSObjectList2MenuData(MENUDATA *pMenuData, WPSOBJECTLIST *pListRoot)
  2598. {
  2599. WPSOBJECTLIST   *pWPOLCurrent;          /* Current LIST element of pListRoot for current list level */
  2600. MENUDATA        *pMDInsertAfter;        /* Last MENUDATA structure of current list level pMenuData */
  2601. MENUDATA        *pMDInsert;             /* Current MENUDATA structure to insert */
  2602.  
  2603.                                         /* Find last elment of current MENUDATA LIST pMenuData */
  2604. for(pMDInsertAfter=pMenuData; pMDInsertAfter->Next; /* pMDInsertAfter=pMDInsertAfter->Next */)
  2605.     pMDInsertAfter=pMDInsertAfter->Next;;
  2606.                                         /* Enumerate current level of WPSOBJECTLIST LIST pListRoot */
  2607. pWPOLCurrent=pListRoot;
  2608. while(pWPOLCurrent)
  2609.     {
  2610.     if(pMDInsertAfter->Item==ENTRYEMPTY)
  2611.         {                               /* An emtpy MENUDATA LIST item is the first item of a Submenu,
  2612.                                            so we have to fill this one */
  2613.                                         /* Fill this one from WPSOBJECTLIST LIST and assign it the
  2614.                                            next free id */
  2615.         pMDInsert=pMDInsertAfter;
  2616.         pMDInsert->id=pHP->MenuDataId++;
  2617.         }
  2618.     else
  2619.         {                               /* For any nonempty MENUDATA LIST item, we have to append a
  2620.                                            new MENUDATA item */
  2621.                                         /* Allocate a MENUDATA structure for current list
  2622.                                            element we are going to extract from the LIST and
  2623.                                            assign it the next free identifier */
  2624.         pMDInsert=AllocateMenuData();
  2625.         pMDInsert->id=pHP->MenuDataId++;
  2626.                                         /* Link the newly created in */
  2627.         pMDInsert->Back=pMDInsertAfter;
  2628.         pMDInsertAfter->Next=pMDInsert;
  2629.         }
  2630.     pMDInsertAfter=pMDInsert;           /* Next iteration we insert after the MENUDATA item
  2631.                                            we currently insert/replace */
  2632. /*                                                                                      *\
  2633.  * If the current element is a WPProgram Object extracted from the WPS, we have to      *
  2634.  * convert a PROGDETAILS structure into a ENTRYMENUITEM type MENUDATA structure.        *
  2635. \*                                                                                      */
  2636.     if(pWPOLCurrent->ulType==WPSOBJECTPROGRAM)
  2637.         {
  2638.         pMDInsert->Item=ENTRYMENUITEM;  /* It's a Menuitem */
  2639.         LoadProgDetails2MenuData(pMDInsert, (PROGDETAILS *)pWPOLCurrent->pData);
  2640.                                         /* Insert this Menuitem at the end of the current level
  2641.                                            pMenuData of the Popup-Menu */
  2642.         if(pMDInsert->Back!=NULL)
  2643.             {                           /* This isn't the first item, insert after an
  2644.                                            existing item */
  2645.             if((pMDInsert->Back)->Submenu==pMDInsert)
  2646.                                         /* If this is the first item of a Submenu, then
  2647.                                            insert it as this */
  2648.                 SetPopupMenu(MM_INSERTITEMSUBMENU, MPFROMP(pMDInsert), MPFROMP(pMDInsert->Back));
  2649.             else
  2650.                                         /* Insert item after the existing item */
  2651.                 SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMDInsert), MPFROMP(pMDInsert->Back));
  2652.             }
  2653.         else                            /* This is the first item, insert at the end */
  2654.                 SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMDInsert), MPFROMP(NULL));
  2655.         }
  2656. /*                                                                                      *\
  2657.  * If the current element is a WPFolder Object extracted from the WPS, we have to       *
  2658.  * convert a character pointer into a ENTRYSUBMENU type MENUDATA structure.             *
  2659. \*                                                                                      */
  2660.     if(pWPOLCurrent->ulType==WPSOBJECTFOLDER)
  2661.         {
  2662.         MENUDATA    *pMDSubmenu;        /* First Menuitem within the Submenu */
  2663.  
  2664.         pMDInsert->Item=ENTRYSUBMENU;   /* It's a Submenu */
  2665.                                         /* Get the folder's name from WPSOBJECTLIST as
  2666.                                            the Submenu's title */
  2667.         free(pMDInsert->PgmTitle);
  2668.         pMDInsert->PgmTitle=malloc(strlen((UCHAR *)pWPOLCurrent->pData)+1);
  2669.         strcpy(pMDInsert->PgmTitle, (UCHAR *)pWPOLCurrent->pData);
  2670.                                         /* Now obtein a entry for a submenu, adjust the
  2671.                                            linked list to it and call this procedure with
  2672.                                            the new entry recursively again */
  2673.         pMDSubmenu=AllocateMenuData();
  2674.         pMDInsert->Submenu=pMDSubmenu;
  2675.         pMDSubmenu->Back=pMDInsert;
  2676.                                         /* Insert this Menuitem at the end of the current level
  2677.                                            pMenuData of Popup-Menu */
  2678.         if(pMDInsert->Back!=NULL)
  2679.             {                           /* This isn't the first item, insert after an
  2680.                                            existing item */
  2681.             if((pMDInsert->Back)->Submenu==pMDInsert)
  2682.                                         /* If this is the first item of a Submenu, then
  2683.                                            insert it as this */
  2684.                 SetPopupMenu(MM_INSERTITEMSUBMENU, MPFROMP(pMDInsert), MPFROMP(pMDInsert->Back));
  2685.             else
  2686.                                         /* Insert item after the existing item */
  2687.                 SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMDInsert), MPFROMP(pMDInsert->Back));
  2688.             }
  2689.         else                            /* This is the first item, insert at the end */
  2690.                 SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMDInsert), MPFROMP(NULL));
  2691.                                         /* Recursively add the folder's contents to the
  2692.                                            Submenu Menuitem */
  2693.         ConvertWPSObjectList2MenuData(pMDSubmenu, pWPOLCurrent->pFolder);
  2694.         }
  2695. /*                                                                                      *\
  2696.  * If the current element is a WPObject Object extracted from the WPS, we have to       *
  2697.  * convert a character pointer of the Object's ObjectID into a ENTRYMENUITEM type       *
  2698.  * MENUDATA structure.                                                                  *
  2699. \*                                                                                      */
  2700.     if(pWPOLCurrent->ulType==WPSOBJECTOBJECT)
  2701.         {
  2702.         UCHAR   *pucSeparator;          /* We expect pData point to a string of
  2703.                                            pszObjectTitle@<ObjectID> where @ is our
  2704.                                            separator. This format is reliable, because
  2705.                                            WPS 2 PC/2 ensures it */
  2706.  
  2707.         pMDInsert->Item=ENTRYMENUITEM;  /* It's a Menuitem */
  2708.                                         /* And it's a WPS Object */
  2709.         pMDInsert->SessionType=PROG_WPSOBJECT;
  2710.         pucSeparator=strrchr((UCHAR *)pWPOLCurrent->pData, '@');
  2711.         *pucSeparator++='\0';           /* Separate pszObjectTitle from <ObjectID> */
  2712.                                         /* Get the ObjectID from WPSOBJECTLIST as
  2713.                                            the Menuitem's title and path & filename */
  2714.         free(pMDInsert->PgmTitle);
  2715.         pMDInsert->PgmTitle=malloc(strlen((UCHAR *)pWPOLCurrent->pData)+1);
  2716.         strcpy(pMDInsert->PgmTitle, (UCHAR *)pWPOLCurrent->pData);
  2717.         free(pMDInsert->WindowTitle);
  2718.         pMDInsert->WindowTitle=malloc(strlen((UCHAR *)pWPOLCurrent->pData)+1);
  2719.         strcpy(pMDInsert->WindowTitle, (UCHAR *)pWPOLCurrent->pData);
  2720.         free(pMDInsert->PgmName);
  2721.         pMDInsert->PgmName=malloc(strlen(pucSeparator)+1);
  2722.         strcpy(pMDInsert->PgmName, pucSeparator);
  2723.                                         /* Insert this Menuitem at the end of the current level
  2724.                                            pMenuData of the Popup-Menu */
  2725.         if(pMDInsert->Back!=NULL)
  2726.             {                           /* This isn't the first item, insert after an
  2727.                                            existing item */
  2728.             if((pMDInsert->Back)->Submenu==pMDInsert)
  2729.                                         /* If this is the first item of a Submenu, then
  2730.                                            insert it as this */
  2731.                 SetPopupMenu(MM_INSERTITEMSUBMENU, MPFROMP(pMDInsert), MPFROMP(pMDInsert->Back));
  2732.             else
  2733.                                         /* Insert item after the existing item */
  2734.                 SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMDInsert), MPFROMP(pMDInsert->Back));
  2735.             }
  2736.         else                            /* This is the first item, insert at the end */
  2737.                 SetPopupMenu(MM_INSERTITEMMENUITEM, MPFROMP(pMDInsert), MPFROMP(NULL));
  2738.         }
  2739.                                         /* Adjust to next WPSOBJECTLIST LIST element */
  2740.     pWPOLCurrent=pWPOLCurrent->pNext;
  2741.     }
  2742. return(NO_ERROR);
  2743. }
  2744.  
  2745. /*--------------------------------------------------------------------------------------*\
  2746.  * This procedure changes to the root directory of all local drives. This includes also *
  2747.  * networked drives. But it avoids to change the directory on drives that have no       *
  2748.  * file system attached, e.g. CD-ROM drives playing music CDs.                          *
  2749. \*--------------------------------------------------------------------------------------*/
  2750. ULONG   SetDriveRoot(void)
  2751. {
  2752. /*                                                                                      *\
  2753.  * Change to the root directory of all non-removable drives.                            *
  2754. \*                                                                                      */
  2755. ULONG   ulDriveNumber;                  /* Current drive (1=A, 2=B, ...) */
  2756. ULONG   ulLogicalDriveMap;              /* Bitmap of available drives (Bit 0=A, 1=B, ...) */
  2757. UCHAR   ucDrive[]="C:";                 /* Current drive */
  2758. ULONG   ulParamLengthInOut;             /* Parameter Packet Length */
  2759. ULONG   ulDataLengthInOut;              /* Data Packet Length */
  2760. ULONG   ulTemp;
  2761. HFILE   hfDiskHandle;                   /* File handle of current drive */
  2762. ULONG   ulActionTaken;                  /* Action taken on opened file (drive) */
  2763. APIRET  rc;
  2764.  
  2765.                                         /* Query drive bit map */
  2766. DosQueryCurrentDisk(&ulDriveNumber, &ulLogicalDriveMap);
  2767.                                         /* Save current drive map to detect added local drives */
  2768. pHP->ulLogicalDriveMap=ulLogicalDriveMap;
  2769. if(!DosOpen("\\DEV\\CD-ROM2$", &hfDiskHandle, &ulActionTaken, 0, FILE_NORMAL,
  2770.     OPEN_ACTION_OPEN_IF_EXISTS, OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, 0))
  2771.     {
  2772.     struct _DPF                         /* Data Packet Format */
  2773.     {
  2774.     USHORT      usCDCount;              /* Number of CD-ROMs */
  2775.     USHORT      usCDFirst;              /* Number of drive of first CD-ROM (0...A, 1...B, ...) */
  2776.     } DPF;
  2777.  
  2778.     ulDataLengthInOut=sizeof(DPF);
  2779.                                         /* Get the first CD-ROM and number of CD-ROM drives */
  2780.     rc=DosDevIOCtl(hfDiskHandle, IOCTL_CHARDEVICE, DSK_DEVICESTATUS,
  2781.         NULL, 0, NULL,
  2782.         &DPF, ulDataLengthInOut, &ulDataLengthInOut);
  2783.     DosClose(hfDiskHandle);
  2784.     if(rc!=NO_ERROR)
  2785.         DOS_ERR(rc, pHP->hwndFrame, HELP_MEDIA, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  2786.             "Can't request media parameters - continuing...");
  2787.                                         /* Mark all CD-ROMs out of logical drive map to avoid
  2788.                                            changing to its root directory */
  2789.                                         /* Get first CD-ROM, Bit 0=A, 1=B, ... */
  2790.     for(ucDrive[0]='A', ulTemp=0x00000001; DPF.usCDFirst; DPF.usCDFirst--)
  2791.         {
  2792.         ucDrive[0]++;
  2793.         ulTemp<<=1;
  2794.         }
  2795.                                         /* For all CD-ROMs map them out */
  2796.     for( ; DPF.usCDCount; DPF.usCDCount--)
  2797.         {
  2798.         ulLogicalDriveMap&=(~ulTemp);
  2799.         ulTemp<<=1;
  2800.         }
  2801.     DosClose(hfDiskHandle);
  2802.     }
  2803. for(ucDrive[0]='C', ulTemp=(ULONG)ucDrive[0]-'A', ulLogicalDriveMap>>=2; ulTemp<=(ULONG)('Z'-'A');
  2804.     ulTemp++, ucDrive[0]++, ulLogicalDriveMap>>=1)
  2805.     {                                   /* Loop for drive C: to Z: (blocks of 0s must be
  2806.                                            expected because of network drives) */
  2807.                                         /* If drive is not attached ignore drive letter */
  2808.         if((ulLogicalDriveMap&0x00000001)==0) continue;
  2809.                                         /* Open drive device readonly and fail call on error */
  2810.         rc=DosOpen(ucDrive, &hfDiskHandle, &ulActionTaken, 0, FILE_NORMAL,
  2811.             OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR |
  2812.             OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READONLY, 0);
  2813.         if(rc==NO_ERROR)
  2814.             {                           /* On non-removeable media close it and change to the
  2815.                                            root directory of it. Don't change to root directory
  2816.                                            on removable media that isn't inserted or to not
  2817.                                            attached  drives */
  2818.             struct _PPF                 /* Parameter Packet Format */
  2819.             {
  2820.             BYTE        bCommandInformation;
  2821.             BYTE        bDriveUnit;
  2822.             } PPF={0, 0};
  2823.             struct _DPF                 /* Data Packet Format */
  2824.             {
  2825.             BYTE        bData;
  2826.             } DPF;
  2827.  
  2828.             ulParamLengthInOut=sizeof(PPF);
  2829.             ulDataLengthInOut=sizeof(DPF);
  2830.                                         /* Now query if the media is removable. The media
  2831.                                            needs not to be inserted */
  2832.             rc=DosDevIOCtl(hfDiskHandle, IOCTL_DISK, DSK_BLOCKREMOVABLE,
  2833.                 &PPF, ulParamLengthInOut, &ulParamLengthInOut,
  2834.                 &DPF, ulDataLengthInOut, &ulDataLengthInOut);
  2835.                                         /* Only Error 0 (no error) or Error 50
  2836.                                            (Network request not supported) are
  2837.                                            not treated as errors */
  2838.             if((rc!=NO_ERROR) && (rc!=ERROR_NOT_SUPPORTED))
  2839.                 DOS_ERR(rc, pHP->hwndFrame, HELP_MEDIA, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  2840.                     "Can't request media parameters - continuing...");
  2841.             DosClose(hfDiskHandle);
  2842.             if(DPF.bData)
  2843.                 {                       /* If it is a nonremovable media, change to its root */
  2844.                                         /* 1=A, 2=B, 3=C,... */
  2845.                 rc=DosSetDefaultDisk((ucDrive[0]+1)-'A');
  2846.                 if(rc!=NO_ERROR)
  2847.                     DOS_ERR(rc, pHP->hwndFrame, HELP_SETPATH, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  2848.                         "Can't change current directory - continuing...");
  2849.                 rc=DosSetCurrentDir("\\");
  2850.                 if(rc!=NO_ERROR)
  2851.                     DOS_ERR(rc, pHP->hwndFrame, HELP_SETPATH, MB_ERROR|MB_OK|MB_HELP|MB_MOVEABLE|MB_DEFBUTTON1,
  2852.                         "Can't change current directory - continuing...");
  2853.                 }
  2854.             }
  2855.     }
  2856. return(NO_ERROR);
  2857. }
  2858.