home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / p / pc2.zip / SOURCE.ZIP / SOURCE / UTILITY.C < prev    next >
Text File  |  1993-03-09  |  54KB  |  1,013 lines

  1. /***********************************************************************\
  2.  *                                PC2.c                                *
  3.  *                 Copyright (C) by Stangl Roman, 1993                 *
  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.20 03,1993 $ (LBL)";
  12.  
  13. #define         _FILE_  "PC/2 - Utility.c V1.20"
  14.  
  15. #include        "PC2.h"                 /* User include files */
  16. #include        "Error.h"
  17.  
  18. /*--------------------------------------------------------------------------------------*\
  19.  * The following definitions are from Rick Fishman's utility KILLEM20 available by      *
  20.  * anonymous ftp from ftp-os2.nmsu.edu.                                                 *
  21. \*--------------------------------------------------------------------------------------*/
  22. #pragma linkage( DosQProcStatus, far16 pascal )
  23. USHORT DosQProcStatus( PVOID pvBuf, USHORT cbBuf );
  24.  
  25. #define PROCESS_END_INDICATOR   3       // Indicates end of process structs
  26. #define BUFFER_SIZE             0x4000
  27.  
  28. #pragma pack(1)
  29.  
  30. typedef struct _SUMMARY
  31. {
  32.     ULONG   ulThreadCount;              // Number of threads in system
  33.     ULONG   ulProcessCount;             // Number of processes in system
  34.     ULONG   ulModuleCount;              // Number of modules in system
  35. } SUMMARY, *PSUMMARY;
  36.  
  37. typedef struct _THREADINFO
  38. {
  39.     UCHAR   uchDontKnow1;               //
  40.     UCHAR   uchDontKnow2;               //
  41.     USHORT  usDontKnow3;                //
  42.     USHORT  tidWithinProcess;           // TID within process (TID is 4 bytes!!)
  43.     USHORT  tidWithinSystem;            // TID within system
  44.     ULONG   ulBlockId;                  // Block ID (?)
  45.     USHORT  usPriority;                 // Priority
  46.     USHORT  usDontKnow4;                //
  47.     USHORT  usDontKnow5;                //
  48.     USHORT  usDontKnow6;                //
  49.     USHORT  usDontKnow7;                //
  50.     USHORT  usDontKnow8;                //
  51.     USHORT  usThreadStatus;             // 2=blocked or ready, 5=running
  52.     USHORT  usDontKnow9;                //
  53. } THREADINFO, *PTHREADINFO;
  54.  
  55. typedef struct _PROCESSINFO
  56. {
  57.     ULONG       ulEndIndicator;         // 1 means not end, 3 means last entry
  58.     PTHREADINFO ptiFirst;               // Address of the 1st Thread Control Blk
  59.     USHORT      pid;                    // Process ID (2 bytes - PID is 4 bytes)
  60.     USHORT      pidParent;              // Parent's process ID
  61.     USHORT      usDontKnow2;            //
  62.     USHORT      usDontKnow3;            //
  63.     USHORT      usDontKnow4;            //
  64.     USHORT      usDontKnow5;            //
  65.     USHORT      idSession;              // Session ID
  66.     USHORT      usDontKnow6;            //
  67.     USHORT      hModRef;                // Module handle of EXE
  68.     USHORT      usThreadCount;          // Number of threads in this process
  69.     USHORT      usSessionType;          // Session type (SSF_TYPE_xx)
  70.     CHAR        achDontKnow7[ 6 ];      //
  71.     USHORT      usThreadIdCount;        // Number of USHORTs in Thread id table?
  72.     USHORT      usModCount;             // Number of USHORTs in ModHandle table?
  73.     USHORT      usUshortCount;          // Number of USHORTs in Ushort table?
  74.     USHORT      usDontKnow8;            //
  75.     ULONG       ulThreadIdTableAddr;    // Maybe the address of a TID table
  76.     ULONG       ulModHandleTableAddr;   // Address of a ModHandle table (DLLS?)
  77.     ULONG       ulUshortTableAddr;      // Address of a table of USHORTs (?)
  78. } PROCESSINFO, *PPROCESSINFO;
  79.  
  80. typedef struct _SEMINFO
  81. {
  82.     struct _SEMINFO *pNext;             // Pointer to next block
  83.     USHORT   idOwningThread;            // ID of owning thread?
  84.     USHORT   fsFlags;                   // (MSB-LSB)
  85.     UCHAR    uchReferenceCount;         // Number of references
  86.     UCHAR    uchRequestCount;           // Number of requests
  87.     CHAR     achDontKnow1[ 7 ];         //
  88.     USHORT   usIndex;                   // Index (?)
  89.     CHAR     szSemName[ 1 ];            // ASCIIZ semaphore name
  90. } SEMINFO, *PSEMINFO;
  91.  
  92. typedef struct _SHRMEMINFO
  93. {
  94.     struct _SHRMEMINFO *pNext;           // Pointer to next block
  95.     USHORT      usMemHandle;             // Shared memory handle (?)
  96.     SEL         selMem;                  // Selector
  97.     USHORT      usReferenceCount;        // Number of references
  98.     CHAR        szMemName[ 1 ];          // ASCIIZ shared memory name
  99. } SHRMEMINFO, *PSHRMEMINFO;
  100.  
  101. typedef struct _MODINFO
  102. {
  103.     struct _MODINFO *pNext;              // Pointer to next block
  104.     USHORT   hMod;                       // Module handle
  105.     USHORT   usModType;                  // Module type (0=16bit,1=32bit)
  106.     ULONG    ulModRefCount;              // Count of module references
  107.     ULONG    ulSegmentCount;             // Number of segments in module
  108.     ULONG    ulDontKnow1;                //
  109.     PSZ      szModName;                  // Addr of fully qualified module name
  110.     USHORT   usModRef[ 1 ];              // Handles of module references
  111. } MODINFO, *PMODINFO;
  112.  
  113. typedef struct _BUFFHEADER
  114. {
  115.     PSUMMARY        psumm;               // Pointer to SUMMARY section
  116.     PPROCESSINFO    ppi;                 // Pointer to PROCESS section
  117.     PSEMINFO        psi;                 // Pointer to SEMAPHORE section
  118.     PVOID           pDontKnow1;          //
  119.     PSHRMEMINFO     psmi;                // Pointer to SHARED MEMORY section
  120.     PMODINFO        pmi;                 // Pointer to MODULE section
  121.     PVOID           pDontKnow2;          //
  122.     PVOID           pDontKnow3;          //
  123. } BUFFHEADER, *PBUFFHEADER;
  124.  
  125. #pragma pack()
  126.  
  127. /*--------------------------------------------------------------------------------------*\
  128.  * Set the priority of a process.                                                       *
  129.  * Warning: Routine exits immediately whenever a failure occurs, by return(FALSE);      *
  130.  * Req:                                                                                 *
  131.  *      pszProcess .... A pointer to an uppercase string of the process's name.         *
  132.  *      PriorityClass . The Priority Class to change the process to.                    *
  133.  *      PriorityDelta . The Priority Delta to change the process to.                    *
  134.  * Returns:                                                                             *
  135.  *      TRUE/FALSE .... If called sucessfully/unsucessfully                             *
  136. \*------------------------------------------------------------------------------------- */
  137. BOOL    SetPriority(PSZ pszProcess, ULONG PriorityClass, LONG PriorityDelta)
  138. {
  139. PBUFFHEADER     pbh;                    /* Get processinfo there */
  140. USHORT          hModule;                /* Module handle of process's priority to be adjusted */
  141. PID             Pid;                    /* Process id ot process to be adjusted */
  142. APIRET          rc;
  143. BOOL            result;
  144.  
  145. /*                                                                                      *\
  146.  * Allocate memory for the process-status information structure returned by OS/2.       *
  147. \*                                                                                      */
  148. if(!(pbh=malloc(BUFFER_SIZE)))
  149.     {
  150.     USR_ERR("Could not allocate enough memory!", hwndFrame, hwndClient);
  151.     return(FALSE);
  152.     }
  153. /*                                                                                      *\
  154.  * Now use the undocumented API DosQProcStatus to fill the information structure.       *
  155. \*                                                                                      */
  156. if(rc=DosQProcStatus(pbh, BUFFER_SIZE))
  157.     {
  158.     DOS_ERR(rc, hwndFrame, hwndClient);
  159.     free(pbh);
  160.     return(FALSE);
  161.     }
  162. /*                                                                                      *\
  163.  * Now get through the modules linked list, seek for the process name to adjust         *
  164.  * the priority.                                                                        *
  165. \*                                                                                      */
  166. {
  167. PMODINFO        pmi=pbh->pmi;           /* Start at first module */
  168.  
  169. result=FALSE;                           /* Assume not found */
  170. while(pmi)
  171.     {
  172.     if(strstr(strupr(pmi->szModName), pszProcess))
  173.         {
  174.         hModule=pmi->hMod;              /* We found it */
  175.         result=TRUE;
  176.         break;
  177.         }
  178.     pmi=pmi->pNext;                     /* Next element */
  179.     }
  180. }
  181. if(result==FALSE)
  182.     {
  183.     USR_ERR("Couldn't locate process in OS/2 system data", hwndFrame, hwndClient);
  184.     free(pbh);
  185.     return(FALSE);
  186.     }
  187. /*                                                                                      *\
  188.  * We have the module handle of the process to change priority. We use it to find the   *
  189.  * correcsponding module handle in the processinfo structure. There is then the process *
  190.  * id to be used to set the priority. Here also we walk through a linked list.          *
  191. \*                                                                                      */
  192. {
  193. PPROCESSINFO    ppi=pbh->ppi;           /* Start at first process */
  194.  
  195. result=FALSE;                           /* Assume not found */
  196. while(ppi->ulEndIndicator!=PROCESS_END_INDICATOR)
  197.     {
  198.     if(ppi->hModRef==hModule)
  199.         {
  200.         Pid=ppi->pid;                   /* We found the process id */
  201.         result=TRUE;
  202.         break;
  203.         }
  204. /*                                                                                      *\
  205.  * ppi->ptiFirst is a pointer to a THREADINFO structure, so if we add                   *
  206.  * ppi->usThreadCount, the number of threads within this process, we physically add the *
  207.  * number of threads * sizeof(THREADINFO), and point with ppi then correctly to the     *
  208.  * next PROCESSINFO structure, which immediately follows the previous process's         *
  209.  * THREADINFO structure(s).                                                             *
  210. \*                                                                                      */
  211.     ppi=(PPROCESSINFO)(ppi->ptiFirst+ppi->usThreadCount);
  212.     }
  213. }
  214. if(result==FALSE)
  215.     {
  216.     USR_ERR("Couldn't locate PID in OS/2 system data", hwndFrame, hwndClient);
  217.     free(pbh);
  218.     return(FALSE);
  219.     }
  220. free(pbh);
  221. /*                                                                                      *\
  222.  * Now we have everything to adjust the process's priority.                             *
  223. \*                                                                                      */
  224. rc=DosSetPriority(                      /* Set the priority of the session and all its childs */
  225.     PRTYS_PROCESS,                      /* Scope of change (all the treads of any process) */
  226.     PriorityClass,                      /* Priority class */
  227.     PriorityDelta,                      /* Priority delta to apply */
  228.     Pid);                               /* Process ID */
  229. if(rc!=NO_ERROR)
  230.     {
  231.     DOS_ERR(rc, hwndFrame, hwndClient);
  232.     return(FALSE);
  233.     }
  234. return(TRUE);
  235. }
  236.  
  237. /*--------------------------------------------------------------------------------------*\
  238.  * Procedure to initialize a window and its message queue.                              *
  239.  * Req:                                                                                 *
  240.  *      pHab .......... A pointer to be filled with the anchor block of the window      *
  241.  *      pHmq .......... A pointer to be filled with the message queue of the window     *
  242.  * Returns:                                                                             *
  243.  *      TRUE/FALSE .... If called sucessfully/unsucessfully                             *
  244. \*--------------------------------------------------------------------------------------*/
  245. BOOL    WinStartUp(HAB *pHab, HMQ *pHmq)
  246. {
  247.                                         /* Initialize handle of anchor block */
  248. if((*pHab=WinInitialize(0))==NULLHANDLE)
  249.     return(FALSE);
  250.                                         /* Initialize handle of message queue */
  251. if((*pHmq=WinCreateMsgQueue(*pHab, 0))==NULLHANDLE)
  252.     return(FALSE);
  253. return(TRUE);
  254. }
  255.  
  256. /*--------------------------------------------------------------------------------------*\
  257.  * Procedure to initialize HELP.                                                        *
  258.  * Req:                                                                                 *
  259.  *      hab ........... Anchor block handle                                             *
  260.  *      pHwndHelp  .... A pointer to a HWND structure                                   *
  261.  * Returns:                                                                             *
  262.  *      pHwndHelp ..... If called sucessfully/unsucessfully hwnd/NULL                   *
  263. \*--------------------------------------------------------------------------------------*/
  264. BOOL    WinStartHelp(HAB hab, HWND *pHwndHelp)
  265. {
  266. HELPINIT        HelpInit;
  267.  
  268. HelpInit.cb=sizeof(HELPINIT);           /* Size of HELPINIT structure */
  269. HelpInit.ulReturnCode=0;                /* Returnvalue from HelpManager */
  270. HelpInit.pszTutorialName=NULL;          /* No tutorial */
  271.                                         /* Ressource of Helptable */
  272. HelpInit.phtHelpTable=(PHELPTABLE)MAKEULONG(MAIN_HELP_TABLE, 0xffff);
  273.                                         /* Ressource in .EXE */
  274. HelpInit.hmodHelpTableModule=NULLHANDLE;
  275.                                         /* No handle */
  276. HelpInit.hmodAccelActionBarModule=NULLHANDLE;
  277. HelpInit.idAccelTable=0;                /* None */
  278. HelpInit.idActionBar=0;                 /* None */
  279.                                         /* Window title of help window */
  280. HelpInit.pszHelpWindowTitle="PC/2 - Program Commander/2 Help";
  281. HelpInit.fShowPanelId=0;                /* Panel ID not displayed */
  282. HelpInit.pszHelpLibraryName="PC2.HLP";  /* Library name of help panel */
  283. *pHwndHelp=WinCreateHelpInstance(       /* Create help */
  284.     hab,                                /* Anchor block */
  285.     &HelpInit);
  286. if((!*pHwndHelp) || (HelpInit.ulReturnCode))
  287.     {
  288.     *pHwndHelp=NULLHANDLE;
  289.     return(FALSE);
  290.     }
  291. else if(WinAssociateHelpInstance(       /* Associate HELP with frame window */
  292.         *pHwndHelp,
  293.         hwndFrame)==FALSE)
  294.         {
  295.         *pHwndHelp=NULLHANDLE;
  296.         return(FALSE);
  297.         }
  298. return(TRUE);
  299. }
  300.  
  301. /*--------------------------------------------------------------------------------------*\
  302.  * Procedure to close a window and its message queue.                                   *
  303.  * Req:                                                                                 *
  304.  *      pHwndHelp ..... A pointer to HELP window handle                                 *
  305.  *      pHab .......... A pointer to extract the anchor block of the window             *
  306.  *      pHmq .......... A pointer to extract message queue of the window                *
  307.  * Returns:                                                                             *
  308.  *      TRUE/FALSE .... If called sucessfully/unsucessfully                             *
  309. \*--------------------------------------------------------------------------------------*/
  310. BOOL    WinCloseDown(HWND *pHwndHelp, HAB *pHab, HMQ *pHmq)
  311. {
  312. if(!*pHwndHelp)                         /* Release HELP */
  313.     WinDestroyHelpInstance(*pHwndHelp);
  314. if(*pHmq!=NULLHANDLE)                   /* Release handle of message queue */
  315.     WinDestroyMsgQueue(*pHmq);
  316. if(*pHab!=NULLHANDLE)                   /* Release handle of anchor block */
  317.     WinTerminate(*pHab);
  318.                                         /* Any error during WinStartUp */
  319. if((*pHab==NULLHANDLE) || (*pHmq==NULLHANDLE)) return(FALSE);
  320. else return(TRUE);
  321. }
  322.  
  323. /*--------------------------------------------------------------------------------------*\
  324.  * A SESSIONDATA data structure is used to extract the parameters to start a new        *
  325.  * session. If sucessfull, additional parameters are extracted to set the priority of   *
  326.  * the new session.                                                                     *
  327.  * Req:         none                                                                    *
  328. \*--------------------------------------------------------------------------------------*/
  329. void    StartSession(SESSIONDATA *ptrSessionData)
  330. {
  331. STARTDATA       StartData;
  332. UCHAR           *pucDosSettings;
  333. ULONG           SessID;
  334. PID             Pid;
  335. APIRET          rc;
  336.  
  337. StartData.Length=50;                    /* Length of StartData */
  338.                                         /* Independent session */
  339. StartData.Related=SSF_RELATED_INDEPENDENT;
  340. StartData.FgBg=ptrSessionData->FgBg;    /* Foreground application */
  341.                                         /* No trace */
  342. StartData.TraceOpt=SSF_TRACEOPT_NONE;
  343.                                         /* Session title string */
  344. StartData.PgmTitle=ptrSessionData->PgmTitle;
  345. StartData.PgmName=ptrSessionData->PgmName; /* Program path-name string */
  346.                                         /* Input arguments */
  347. StartData.PgmInputs=ptrSessionData->PgmInputs;
  348. StartData.TermQ=0;                      /* No termination queue */
  349. StartData.Environment=0;                /* No environment */
  350.                                         /* Inherit from PC/2's environment */
  351. StartData.InheritOpt=SSF_INHERTOPT_PARENT;
  352.                                         /* Session type */
  353. StartData.SessionType=ptrSessionData->SessionType;
  354. StartData.IconFile=0;                   /* No icon, use default */
  355. StartData.PgmHandle=0;                  /* Don't use installation file */
  356.                                         /* Session initial state */
  357. StartData.PgmControl=ptrSessionData->PgmControl;
  358.                                         /* Initial window size */
  359. StartData.InitXPos=ptrSessionData->InitXPos;
  360. StartData.InitYPos=ptrSessionData->InitYPos;
  361. StartData.InitXSize=ptrSessionData->InitXSize;
  362. StartData.InitYSize=ptrSessionData->InitYSize;
  363. /*                                                                                      *\
  364.  * Test for x:(...] where x is a drive and set the current working drive to this        *
  365.  * drive.                                                                               *
  366. \*                                                                                      */
  367. if((strlen(ptrSessionData->PgmDirectory)>=2)
  368.     && (ptrSessionData->PgmDirectory[1]==':'))
  369.     {
  370.     UCHAR       ucDrive;
  371.                                         /* Then get drive letter (only if one's there */
  372.     ucDrive=tolower(ptrSessionData->PgmDirectory[0]);
  373.                                         /* 1=A, 2=B, 3=C,... */
  374.     rc=DosSetDefaultDisk(++ucDrive-'a');
  375.     if(rc!=NO_ERROR) DOS_ERR(rc, hwndFrame, hwndClient);
  376.     }
  377. /*                                                                                      *\
  378.  * Test for a directory and set the current working directory to it, if one exists.     *
  379. \*                                                                                      */
  380. if(strlen(ptrSessionData->PgmDirectory)>=1)
  381.     {                                   /* Only if there's one */
  382.     rc=DosSetCurrentDir(ptrSessionData->PgmDirectory);
  383.     if(rc!=NO_ERROR) DOS_ERR(rc, hwndFrame, hwndClient);
  384.     }
  385. /*                                                                                      *\
  386.  * If we're to start a DOS session, then set the DOS-Settings via the Environment. This *
  387.  * is an undocumented feature (the toolkit says that the Environment is reserved and    *
  388.  * must be 0 for a DOS session. To use the DOS Settings each Setting must be followed   *
  389.  * by \0 and the last Setting must be followed by two \0s. It seems that some settings  *
  390.  * won't be set f.e. HW_TIMER=ON, HW_NOSOUND=ON don't work.                             *
  391. \*                                                                                      */
  392. if((StartData.SessionType==SSF_TYPE_VDM) ||
  393.     (StartData.SessionType==SSF_TYPE_WINDOWEDVDM))
  394.     {
  395.     ULONG       ulTemp;
  396.     UCHAR       *pucTemp;
  397.  
  398.                                         /* Allocate a temporary space for the Dos Settings */
  399.     ulTemp=strlen(ptrSessionData->PgmDosSettings)+2;
  400.     pucDosSettings=(UCHAR *)malloc(ulTemp);
  401.     strcpy(pucDosSettings, ptrSessionData->PgmDosSettings);
  402.                                         /* Replace all \n by \0 */
  403.     for(pucTemp=pucDosSettings; *pucTemp!='\0'; pucTemp++)
  404.         if(*pucTemp=='\n') *pucTemp='\0';
  405.     *++pucTemp='\0';
  406.     StartData.Environment=pucDosSettings;
  407.     }
  408. /*                                                                                      *\
  409.  * Now start the session, but beware of the error code ERROR_SMG_START_IN_BACKGROUND,   *
  410.  * which isn't actually an error code, but an informational message we ignore.          *
  411. \*                                                                                      */
  412. rc=DosStartSession(                     /* Start the new session */
  413.     &StartData,                         /* Session data */
  414.     &SessID,                            /* Session ID of new session */
  415.     &Pid);                              /* Process ID of new session */
  416. switch(rc)
  417. {
  418. case NO_ERROR:                          /* Error codes for errors that are informational */
  419. case ERROR_SMG_START_IN_BACKGROUND:
  420.  
  421. /*                                                                                      *\
  422.  * Now obtain the PID of the process just started, and adjust the priority of all       *
  423.  * threads within this process to Priority Class and Priority Delta, entered by the     *
  424.  * user in the STARTSESSION structure StartSession. Convert the Program Name to upper-  *
  425.  * case, since OS/2 internally seems to use uppercase names.                            *
  426.  * Currently, the PID returned from OS/2 DosQProcStatus may not be used to change the   *
  427.  * priority. Error 305 - Not descendant is returned in this case.                       *
  428. \*                                                                                      */
  429.     if(StartData.Related==SSF_RELATED_INDEPENDENT)
  430. //    SetPriority(
  431. //        strupr(ptrSessionData->PgmName),/* Process name */
  432. //        ptrSessionData->PriorityClass,  /* Priority class */
  433. //        ptrSessionData->PriorityDelta); /* Priority delta to apply */
  434.     ;
  435.     else
  436.         {
  437.         rc=DosSetPriority(
  438.             PRTYS_PROCESS,              /* All the threads of any process */
  439.             ptrSessionData->PriorityClass,
  440.             ptrSessionData->PriorityDelta,
  441.             Pid);
  442.         if(rc!=NO_ERROR) DOS_ERR(rc, hwndFrame, hwndClient);
  443.         }
  444.  
  445.     break;
  446.  
  447. default:
  448.     DOS_ERR(rc, hwndFrame, hwndClient);
  449. }
  450. free(pucDosSettings);
  451. }
  452.  
  453. /*--------------------------------------------------------------------------------------*\
  454.  * Procedure to load a SESSIONDATA structure from a MENUDATA structure.                 *
  455.  * Req:                                                                                 *
  456.  *      Empty ......... A BOOL flag that is true if the MENUDATA structure is empty.    *
  457.  *      pMenuData ..... A pointer to a MENUDATA structure to extract the data required  *
  458.  *                      for a Menu/Program Installation dialog.                         *
  459.  *      pSessionData .. A pointer to a SESSIONDATA structure to write the extracted     *
  460.  *                      data into, which is then used in subsequent Menu/Program        *
  461.  *                      Installation dialogs window procedures.                         *
  462.  * Returns:                                                                             *
  463.  *      TRUE/FALSE .... If called sucessfully/unsucessfully                             *
  464. \*--------------------------------------------------------------------------------------*/
  465. BOOL    LoadMenuData2SessionData(BOOL Empty, MENUDATA *pMenuData, SESSIONDATA *pSessionData)
  466. {
  467. USHORT  DesktopSizeX=WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
  468. USHORT  DesktopSizeY=WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
  469.  
  470. strcpy(pSessionData->PgmTitle, pMenuData->PgmTitle);
  471. strcpy(pSessionData->PgmName, pMenuData->PgmName);
  472. strcpy(pSessionData->PgmDirectory, pMenuData->PgmDirectory);
  473. strcpy(pSessionData->PgmInputs, pMenuData->PgmInputs);
  474. strcpy(pSessionData->PgmDosSettings, pMenuData->PgmDosSettings);
  475. /*                                                                                      *\
  476.  * Just straight forward copy of data from MENUDATA structure to SESSIONDATA structure. *
  477. \*                                                                                      */
  478. if(Empty==FALSE)
  479.     {
  480.     pSessionData->SessionType=pMenuData->SessionType;
  481.     pSessionData->PgmControl=pMenuData->PgmControl;
  482.     pSessionData->FgBg=pMenuData->FgBg;
  483.     pSessionData->InitXPos=pMenuData->InitXPos;
  484.     pSessionData->InitYPos=pMenuData->InitYPos;
  485.     pSessionData->InitXSize=pMenuData->InitXSize;
  486.     pSessionData->InitYSize=pMenuData->InitYSize;
  487.     pSessionData->PriorityClass=pMenuData->PriorityClass;
  488.     pSessionData->PriorityDelta=pMenuData->PriorityDelta;
  489.     }
  490. if(Empty==TRUE)
  491.     {                                   /* Empty the pSessionData structure to the default
  492.                                            values of the fields */
  493.  
  494.     pSessionData->SessionType=SSF_TYPE_DEFAULT;
  495.     pSessionData->PgmControl=SSF_CONTROL_VISIBLE;
  496.     pSessionData->FgBg=SSF_FGBG_FORE;
  497.     pSessionData->InitXPos=DesktopSizeX*0.15;
  498.     pSessionData->InitYPos=DesktopSizeY*0.15;
  499.     pSessionData->InitXSize=DesktopSizeX*0.70;
  500.     pSessionData->InitYSize=DesktopSizeY*0.70;
  501.     pSessionData->PriorityClass=PRTYC_NOCHANGE;
  502.     pSessionData->PriorityDelta=0;
  503.     }
  504. return(TRUE);
  505. }
  506.  
  507. /*--------------------------------------------------------------------------------------*\
  508.  * Procedure to save a MENUDATA structure to a SESSIONDATA structure.                   *
  509.  * Req:                                                                                 *
  510.  *      pMenuData ..... A pointer to a MENUDATA structure to write the data from a      *
  511.  *                      Menu/Program Installation dialog.                               *
  512.  *      pSessionData .. A pointer to a SESSIONDATA structure to extract the data from,  *
  513.  *                      which the user entered.                                         *
  514.  * Returns:                                                                             *
  515.  *      TRUE/FALSE .... If called sucessfully/unsucessfully                             *
  516. \*--------------------------------------------------------------------------------------*/
  517. BOOL    LoadSessionData2MenuData(MENUDATA *pMenuData, SESSIONDATA *pSessionData)
  518. {
  519.                                         /* Ignore if not changed otherwise release menory
  520.                                            and allocate a new one */
  521. if(strcmp(pMenuData->PgmTitle, pSessionData->PgmTitle)!=0)
  522.     {
  523.     free(pMenuData->PgmTitle);
  524.     pMenuData->PgmTitle=malloc(1+strlen(pSessionData->PgmTitle));
  525.     strcpy(pMenuData->PgmTitle, pSessionData->PgmTitle);
  526.     }
  527. if(strcmp(pMenuData->PgmName, pSessionData->PgmName)!=0)
  528.     {
  529.     free(pMenuData->PgmName);
  530.     pMenuData->PgmName=malloc(1+strlen(pSessionData->PgmName));
  531.     strcpy(pMenuData->PgmName, pSessionData->PgmName);
  532.     }
  533. if(strcmp(pMenuData->PgmDirectory, pSessionData->PgmDirectory)!=0)
  534.     {
  535.     free(pMenuData->PgmDirectory);
  536.     pMenuData->PgmDirectory=malloc(1+strlen(pSessionData->PgmDirectory));
  537.     strcpy(pMenuData->PgmDirectory, pSessionData->PgmDirectory);
  538.     }
  539. if(strcmp(pMenuData->PgmInputs, pSessionData->PgmInputs)!=0)
  540.     {
  541.     free(pMenuData->PgmInputs);
  542.     pMenuData->PgmInputs=malloc(1+strlen(pSessionData->PgmInputs));
  543.     strcpy(pMenuData->PgmInputs, pSessionData->PgmInputs);
  544.     }
  545. if((SessionData.SessionType==SSF_TYPE_VDM) ||
  546.     (SessionData.SessionType==SSF_TYPE_WINDOWEDVDM))
  547.     if (strcmp(pMenuData->PgmDosSettings, pSessionData->PgmDosSettings)!=0)
  548.         {
  549.         free(pMenuData->PgmDosSettings);
  550.         pMenuData->PgmDosSettings=malloc(1+strlen(pSessionData->PgmDosSettings));
  551.         strcpy(pMenuData->PgmDosSettings, pSessionData->PgmDosSettings);
  552.         }
  553. pMenuData->SessionType=pSessionData->SessionType;
  554. pMenuData->PgmControl=pSessionData->PgmControl;
  555. pMenuData->FgBg=pSessionData->FgBg;
  556. pMenuData->InitXPos=pSessionData->InitXPos;
  557. pMenuData->InitYPos=pSessionData->InitYPos;
  558. pMenuData->InitXSize=pSessionData->InitXSize;
  559. pMenuData->InitYSize=pSessionData->InitYSize;
  560. pMenuData->PriorityClass=pSessionData->PriorityClass;
  561. pMenuData->PriorityDelta=pSessionData->PriorityDelta;
  562. return(TRUE);
  563. }
  564.  
  565. /*--------------------------------------------------------------------------------------*\
  566.  * This procedure allocates a MENUDATA structure and initializes it to the default      *
  567.  * values of an empty structure.                                                        *
  568.  * Req:                                                                                 *
  569.  *      none                                                                            *
  570.  * Returns:                                                                             *
  571.  *      pMenuData ..... A pointer to an MENUDATA structure.                             *
  572. \*--------------------------------------------------------------------------------------*/
  573. MENUDATA *AllocateMenuData(void)
  574. {
  575. UCHAR           *pU;
  576. MENUDATA        *pMenuData;
  577.  
  578. pMenuData=malloc(sizeof(MENUDATA));     /* Allocate a MENUDATA structure */
  579. pMenuData->Item=ENTRYEMPTY;             /* It's an empty structure */
  580. pMenuData->id=0;
  581. pMenuData->hwndItem=NULLHANDLE;
  582. strcpy(pU=malloc(strlen("")+1), "");
  583. pMenuData->PgmTitle=pU;                 /* Load default values */
  584. strcpy(pU=malloc(strlen("")+1), "");
  585. pMenuData->PgmName=pU;
  586. strcpy(pU=malloc(strlen("")+1), "");
  587. pMenuData->PgmDirectory=pU;
  588. strcpy(pU=malloc(strlen("")+1), "");
  589. pMenuData->PgmInputs=pU;
  590. strcpy(pU=malloc(strlen("")+1), "");
  591. pMenuData->PgmDosSettings=pU;
  592. pMenuData->SessionType=0;
  593. pMenuData->PgmControl=0;
  594. pMenuData->FgBg=0;
  595. pMenuData->InitXPos=0;
  596. pMenuData->InitYPos=0;
  597. pMenuData->InitXSize=0;
  598. pMenuData->InitYSize=0;
  599. pMenuData->PriorityClass=0;
  600. pMenuData->PriorityDelta=0;
  601. pMenuData->Back=NULL;
  602. pMenuData->Submenu=NULL;
  603. pMenuData->Next=NULL;
  604. return(pMenuData);
  605. }
  606.  
  607. #define GetEntry    fgets(Buffer, sizeof(Buffer), Pc2Profile);\
  608.                     if((Match=strchr(Buffer, ' '))==NULL) Match=strchr(Buffer, '\0');\
  609.                     else for( ; (*Match==' ') && (*Match!='\0'); Match++);
  610.  
  611. /*--------------------------------------------------------------------------------------*\
  612.  * This recursive procedure loads the popup menu from the profile.                      *
  613.  * Req:                                                                                 *
  614.  *      pMenuData ..... A pointer to an MENUDATA structure.                             *
  615.  * Returns:                                                                             *
  616.  *      none                                                                            *
  617. \*--------------------------------------------------------------------------------------*/
  618. void LoadMenu(MENUDATA *pMenuData)
  619. {
  620. static UCHAR    Buffer[256];
  621. static UCHAR    *Match;
  622. static USHORT   Flag;
  623.  
  624. fgets(Buffer, sizeof(Buffer), Pc2Profile);
  625. do
  626. {
  627.                                         /* Should read MENUITEM or SUBMENU BEGIN or
  628.                                            SUBMENU END */
  629.     if(strcmp(Buffer, "SUBMENU END\n")==0)
  630.         return;                         /* We are at an end of the list, terminate it
  631.                                            and shell up one level by return() */
  632.     pMenuData->id=MenuDataId++;         /* Fill with current id and increment id */
  633.     if(strcmp(Buffer, "PROFILE END\n")==0) return;
  634.     if(strcmp(Buffer, "MENUITEM\n")==0) Flag=ENTRYMENUITEM; else Flag=ENTRYSUBMENU;
  635. /*                                                                                      *\
  636.  * Get the entry from the profile, but remove the heading description and the \n from   *
  637.  * the strings.                                                                         *
  638. \*                                                                                      */
  639.                                         /* Get the session title */
  640.     fgets(Buffer, sizeof(Buffer), Pc2Profile);
  641.     Buffer[strlen(Buffer)-1]='\0';
  642.     if((Match=strchr(Buffer, ' '))==NULL) Match=strchr(Buffer, '\0');
  643.     else for( ; (*Match==' ') && (*Match!='\0'); Match++);
  644.     free(pMenuData->PgmTitle);
  645.     pMenuData->PgmTitle=malloc(strlen(Match)+1);
  646.     strcpy(pMenuData->PgmTitle, Match);
  647.     if(Flag==ENTRYMENUITEM)
  648.         {                               /* If we load a MENUITEM, then load the strings
  649.                                            from the profile */
  650.         pMenuData->Item=ENTRYMENUITEM;  /* It's a Menuitem */
  651.                                         /* Session path and filename */
  652.         fgets(Buffer, sizeof(Buffer), Pc2Profile);
  653.         Buffer[strlen(Buffer)-1]='\0';
  654.         if((Match=strchr(Buffer, ' '))==NULL) Match=strchr(Buffer, '\0');
  655.         else for( ; (*Match==' ') && (*Match!='\0'); Match++);
  656.         free(pMenuData->PgmName);
  657.         pMenuData->PgmName=malloc(strlen(Match)+1);
  658.         strcpy(pMenuData->PgmName, Match);
  659.                                         /* Session working directory */
  660.         fgets(Buffer, sizeof(Buffer), Pc2Profile);
  661.         Buffer[strlen(Buffer)-1]='\0';
  662.         if((Match=strchr(Buffer, ' '))==NULL) Match=strchr(Buffer, '\0');
  663.         else for( ; (*Match==' ') && (*Match!='\0'); Match++);
  664.         free(pMenuData->PgmDirectory);
  665.         pMenuData->PgmDirectory=malloc(strlen(Match)+1);
  666.         strcpy(pMenuData->PgmDirectory, Match);
  667.                                         /* Session parameter */
  668.         fgets(Buffer, sizeof(Buffer), Pc2Profile);
  669.         Buffer[strlen(Buffer)-1]='\0';
  670.         if((Match=strchr(Buffer, ' '))==NULL) Match=strchr(Buffer, '\0');
  671.         else for( ; (*Match==' ') && (*Match!='\0'); Match++);
  672.         free(pMenuData->PgmInputs);
  673.         pMenuData->PgmInputs=malloc(strlen(Match)+1);
  674.         strcpy(pMenuData->PgmInputs, Match);
  675.                                         /* Test for DOS Settings */
  676.         fgets(Buffer, sizeof(Buffer), Pc2Profile);
  677.         if(strcmp(Buffer, "DOSSETTINGS BEGIN\n")==0)
  678.             {
  679.             UCHAR       ucBuffer[2049]="";
  680.  
  681.             fgets(Buffer, sizeof(Buffer), Pc2Profile);
  682.             while(strcmp(Buffer, "DOSSETTINGS END\n")!=0)
  683.                 {                       /* Add all DOS Settings to temporary buffer */
  684.                 strcat(ucBuffer, Buffer);
  685.                 fgets(Buffer, sizeof(Buffer), Pc2Profile);
  686.                 }
  687.                                         /* Now allocate the exactly required buffer and
  688.                                            copy all DOS Settings there */
  689.             free(pMenuData->PgmDosSettings);
  690.             pMenuData->PgmDosSettings=malloc(strlen(ucBuffer)+1);
  691.                                         /* Read one line ahead */
  692.             strcpy(pMenuData->PgmDosSettings, ucBuffer);
  693.             fgets(Buffer, sizeof(Buffer), Pc2Profile);
  694.             }
  695.                                         /* Session type */
  696.         if((Match=strchr(Buffer, ' '))==NULL) Match=strchr(Buffer, '\0');\
  697.         else for( ; (*Match==' ') && (*Match!='\0'); Match++);
  698.         pMenuData->SessionType=(USHORT)atol(Match);
  699.                                         /* Session control */
  700.         GetEntry;
  701.         pMenuData->PgmControl=(USHORT)atol(Match);
  702.                                         /* Start session in fore/background */
  703.         GetEntry;
  704.         pMenuData->FgBg=(USHORT)atol(Match);
  705.                                         /* X Position */
  706.         GetEntry;
  707.         pMenuData->InitXPos=(USHORT)atol(Match);
  708.                                         /* Y Position */
  709.         GetEntry;
  710.         pMenuData->InitYPos=(USHORT)atol(Match);
  711.                                         /* X Size */
  712.         GetEntry;
  713.         pMenuData->InitXSize=(USHORT)atol(Match);
  714.                                         /* Y Size */
  715.         GetEntry;
  716.         pMenuData->InitYSize=(USHORT)atol(Match);
  717.                                         /* Priority of session */
  718.         GetEntry;
  719.         pMenuData->PriorityClass=(ULONG)atol(Match);
  720.                                         /* Delta priority of session */
  721.         GetEntry;
  722.         pMenuData->PriorityDelta=(LONG)atol(Match);
  723.                                         /* Insert this Menuitem at the end of the Popup-Menu */
  724.         if(pMenuData->Back!=NULL)
  725.             {                           /* This isn't the first item, insert after an
  726.                                            existing item */
  727.             if((pMenuData->Back)->Submenu==pMenuData)
  728.                                         /* If this is the first item of a Submenu, then
  729.                                            insert it as this */
  730.                 SetPopupMenu(pMenuData, MM_INSERTITEMSUBMENU, (pMenuData->Back)->id);
  731.             else
  732.                                         /* Insert item after the existing item */
  733.                 SetPopupMenu(pMenuData, MM_INSERTITEMMENUITEM, (pMenuData->Back)->id);
  734.             }
  735.         else                            /* This is the first item, insert at the end */
  736.                 SetPopupMenu(pMenuData, MM_INSERTITEMMENUITEM, MIT_END);
  737.         }
  738.     if(Flag==ENTRYSUBMENU)
  739.         {                               /* If we load a SUBMENU BEGIN, fill with empty strings */
  740.         MENUDATA        *pMenuDataTemp;
  741.  
  742.         pMenuData->Item=ENTRYSUBMENU;   /* It's a Submenu */
  743.                                         /* Now obtain a entry for a submenu, adjust the
  744.                                            linked list to it and call this procedure with
  745.                                            the new entry recursivly again */
  746.         pMenuDataTemp=AllocateMenuData();
  747.         pMenuData->Submenu=pMenuDataTemp;
  748.         pMenuDataTemp->Back=pMenuData;
  749.                                         /* Insert this Menuitem at the end of the Popup-Menu */
  750.         if(pMenuData->Back!=NULL)
  751.             {                           /* This isn't the first item, insert after an
  752.                                            existing item */
  753.             if((pMenuData->Back)->Submenu==pMenuData)
  754.                                         /* If this is the first item of a Submenu, then
  755.                                            insert it as this */
  756.                 SetPopupMenu(pMenuData, MM_INSERTITEMSUBMENU, (pMenuData->Back)->id);
  757.             else
  758.                                         /* Insert item after the existing item */
  759.                 SetPopupMenu(pMenuData, MM_INSERTITEMMENUITEM, (pMenuData->Back)->id);
  760.             }
  761.         else                            /* This is the first item, insert at the end */
  762.                 SetPopupMenu(pMenuData, MM_INSERTITEMMENUITEM, MIT_END);
  763.         LoadMenu(pMenuDataTemp);        /* It's assumed to be an empty entry, which will
  764.                                            be corrected, if the first entry of the Submenu
  765.                                            is found */
  766.         }
  767. /*                                                                                      *\
  768.  * Now see if we're at the end of the profile. If so, then terminate linked list with   *
  769.  * 2 Null pointers, otherwise abtain a new menu space and adjust the menu pointer       *
  770.  * pMenuData to the newly created menu.                                                 *
  771. \*                                                                                      */
  772.     fgets(Buffer, sizeof(Buffer), Pc2Profile);
  773.     if(strcmp(Buffer, "PROFILE END\n")==0)
  774.         break;                          /* Empty lines may follow and feof() then is FALSE
  775.                                            and we loop again, reading invalid input. Avoid
  776.                                            this by breaking out of the loop */
  777.     else
  778.         {                               /* If a SUBMENU END follows ignore it, because
  779.                                            execution will return at beginning of the loop
  780.                                            otherwise add a new item to the end of the
  781.                                            linked list */
  782.         if(strcmp(Buffer, "SUBMENU END\n")!=0)
  783.             {
  784.             MENUDATA    *pMenuDataTemp;
  785.  
  786.             pMenuDataTemp=AllocateMenuData();
  787.             pMenuData->Next=pMenuDataTemp;
  788.             pMenuDataTemp->Back=pMenuData;
  789.             pMenuData=pMenuData->Next;
  790.             }
  791.         }
  792. } while(!feof(Pc2Profile));
  793. return;
  794. }
  795.  
  796. /*--------------------------------------------------------------------------------------*\
  797.  * This recursive procedure saves the popup menu into the profile.                      *
  798.  * Req:                                                                                 *
  799.  *      pMenuData ..... A pointer to an MENUDATA structure.                             *
  800.  * Returns:                                                                             *
  801.  *      none                                                                            *
  802. \*--------------------------------------------------------------------------------------*/
  803. void SaveMenu(MENUDATA *pMenuData)
  804. {
  805. do
  806. {
  807.     if(pMenuData->Item==ENTRYSUBMENU)
  808.         {
  809. /*                                                                                      *\
  810.  * If this is a SUBMENU, then write the header SUBMENU BEGIN and then write the profile *
  811.  * data from teh MENUDATA structure pointet by pMenuData. Then increment the depth      *
  812.  * counter and call this procedure recursivly again. After coming back, restore the     *
  813.  * depth counter and write the header SUBMENU END.                                      *
  814. \*                                                                                      */
  815.         fprintf(Pc2Profile, "SUBMENU BEGIN\n");
  816.         fprintf(Pc2Profile, "PgmTitle: %s\n", pMenuData->PgmTitle);
  817.         SaveMenu(pMenuData->Submenu);
  818.         fprintf(Pc2Profile, "SUBMENU END\n");
  819.         }
  820.     if(pMenuData->Item==ENTRYMENUITEM)
  821.         {
  822. /*                                                                                      *\
  823.  * If it is a MENUITEM, so write the header MENUITEM and then write the profile data    *
  824.  * from the MENUDATA structure pointed by pMenuData.                                    *
  825. \*                                                                                      */
  826.         fprintf(Pc2Profile, "MENUITEM\n");
  827.         fprintf(Pc2Profile, "PgmTitle: %s\n", pMenuData->PgmTitle);
  828.         fprintf(Pc2Profile, "PgmName: %s\n", pMenuData->PgmName);
  829.         fprintf(Pc2Profile, "PgmDirectory: %s\n", pMenuData->PgmDirectory);
  830.         fprintf(Pc2Profile, "PgmInputs: %s\n", pMenuData->PgmInputs);
  831.                                         /* Write DOS Settings only if available */
  832.         if(strlen(pMenuData->PgmDosSettings)!=0)
  833.             {
  834.             fprintf(Pc2Profile, "DOSSETTINGS BEGIN\n");
  835.             fprintf(Pc2Profile, "%s", pMenuData->PgmDosSettings);
  836.             fprintf(Pc2Profile, "DOSSETTINGS END\n");
  837.             }
  838.         fprintf(Pc2Profile, "SessionType: %lu\n", (ULONG)pMenuData->SessionType);
  839.         fprintf(Pc2Profile, "PgmControl: %lu\n", (ULONG)pMenuData->PgmControl);
  840.         fprintf(Pc2Profile, "FgBg: %lu\n", (ULONG)pMenuData->FgBg);
  841.         fprintf(Pc2Profile, "InitXPos: %lu\n", (ULONG)pMenuData->InitXPos);
  842.         fprintf(Pc2Profile, "InitYPos: %lu\n", (ULONG)pMenuData->InitYPos);
  843.         fprintf(Pc2Profile, "InitXSize: %lu\n", (ULONG)pMenuData->InitXSize);
  844.         fprintf(Pc2Profile, "InitYSize: %lu\n", (ULONG)pMenuData->InitYSize);
  845.         fprintf(Pc2Profile, "PriorityClass: %lu\n", (ULONG)pMenuData->PriorityClass);
  846.         fprintf(Pc2Profile, "PriorityDelta: %ld\n", (LONG)pMenuData->PriorityDelta);;
  847.         }
  848. /*                                                                                      *\
  849.  * If one is available, get the next element in the linked list, else we are at the end *
  850.  * either at a leaf or at the real last element, in both cases shell back one level.    *
  851.  * Shell back either exits this procedure completle (we have written the complete       *
  852.  * linked list) or on level (we have written a complete submenu leaf).                  *
  853. \*                                                                                      */
  854.     if(pMenuData->Next!=NULL) pMenuData=pMenuData->Next;
  855.     else break;
  856. } while(TRUE);
  857. }
  858.  
  859. /*--------------------------------------------------------------------------------------*\
  860.  * This recursive procedure searches through the linked list for an element.            *
  861.  * Req:                                                                                 *
  862.  *      pMD ........... A pointer to the first element to search on                     *
  863.  *      id ............ Pointer to the ID to search for (pointer because we don't want  *
  864.  *                      to get a copy during recursion                                  *
  865.  * Returns:                                                                             *
  866.  *      MENUDATA * .... Pointer to match or NULL if not found                           *
  867. \*--------------------------------------------------------------------------------------*/
  868. MENUDATA        *SearchItem(MENUDATA *pMD, ULONG *id)
  869. {
  870. static MENUDATA *pMenuData;
  871.  
  872. do
  873. {
  874.                                         /* If found, save the pointer of it, set ID to the
  875.                                            value 1 which never occures in the linked list
  876.                                            to detect the match at the end of the recursion */
  877.     if(pMD->id==*id) { pMenuData=pMD; *id=TRUE; break; }
  878.                                         /* Shell into the Submenus */
  879.     if(pMD->Item==ENTRYSUBMENU)
  880.         SearchItem(pMD->Submenu, id);
  881.     if(pMD->Next!=NULL) pMD=pMD->Next;  /* Keep on searching until found or end of linked list */
  882.     else
  883.         {                               /* We're at the end of the linked list */
  884.         if(*id!=TRUE) pMenuData=NULL;   /* If we didn't find the item return NULL */
  885.         break;
  886.         }
  887. } while(TRUE);
  888. return(pMenuData);
  889. }
  890.  
  891. /*--------------------------------------------------------------------------------------*\
  892.  * This procedure adds/changes/removes an item to/from the Popup-Menu.                  *
  893.  * Req:                                                                                 *
  894.  *      pMD ........... A pointer to an MENUDATA structure to add/change/remove         *
  895.  *      msg ........... What to do                                                      *
  896.  *      id ............ Identifier on/after which the action occurs                     *
  897.  * Returns:                                                                             *
  898.  *      BOOL .......... TRUE/FALSE if sucessfull/unsucessfull                           *
  899. \*--------------------------------------------------------------------------------------*/
  900. BOOL    SetPopupMenu(MENUDATA *pMD, ULONG msg, LONG id)
  901. {
  902. MENUITEM        miMI;                   /* Update menus with this structure */
  903. HWND            hwndMenu;               /* Menu window handle */
  904. HWND            hwndSubMenu;            /* Window handle of a pulldown menu within the menu bar */
  905. MRESULT         mr;                     /* PM API result */
  906. BOOL            bResult;
  907.  
  908. bResult=FALSE;
  909. switch(msg)
  910. {
  911. case MM_INSERTITEMMENUITEM:
  912. case MM_INSERTITEMSUBMENU:
  913. /*                                                                                      *\
  914.  * An item (Menuitem or Submenu) is to be inserted into the Popup-Menu, either after    *
  915.  * a Menuitem or as the first item of a Submenu.                                        *
  916. \*                                                                                      */
  917.     if(WinSendMsg(
  918.         hwndPopupMenu,
  919.         MM_QUERYITEM,                   /* Query a menuitem */
  920.         MPFROM2SHORT(id, TRUE),         /* Identifier, include submenus */
  921.         (MPARAM)&miMI)==FALSE)          /* Into MENUITEM structure */
  922.         miMI.hwndSubMenu=0;
  923.                                         /* If the item after we insert is a Submenu, than
  924.                                            use the Submenu handle to insert new items,
  925.                                            otherwise use the handle of the previous item */
  926.     if((miMI.hwndSubMenu!=0) && (msg==MM_INSERTITEMSUBMENU))
  927.         {
  928.         hwndMenu=miMI.hwndSubMenu;
  929.         id=MIT_END;
  930.         }
  931.     if(msg==MM_INSERTITEMMENUITEM)
  932.         {                               /* If we insert after an available item, get it's
  933.                                            window handle */
  934.         if(pMD->Back==NULL) hwndMenu=hwndPopupMenu;
  935.                                         /* If this is the first item, use the Popup-Menu
  936.                                            window handle */
  937.         else hwndMenu=(pMD->Back)->hwndItem;
  938.         }
  939.     if(id!=MIT_END) miMI.iPosition++;   /* If previous exists, insert after the item with
  940.                                            ID id */
  941.     else miMI.iPosition=id;             /* Insert after the item with ID id (it may be
  942.                                            MIT_END ) */
  943.     miMI.afAttribute=0;                 /* Special attribute */
  944.     miMI.id=pMD->id;                    /* Item identifier */
  945.     miMI.hItem=0;                       /* No handle */
  946.     if(pMD->Item==ENTRYSUBMENU)
  947.         {                               /* If we insert a Submenu, than we need to obtain
  948.                                            a handle to create one */
  949.         hwndSubMenu=WinCreateMenu(      /* Create a submenu menuitem */
  950.             hwndMenu,                   /* Owner- and parent-window handle */
  951.             NULL);                      /* Binary menu template */
  952.         miMI.afStyle=MIS_SUBMENU;       /* Style to insert */
  953.         miMI.hwndSubMenu=hwndSubMenu;   /* Pulldown menu */
  954.         }
  955.     else
  956.         {                               /* We insert a Menuitem */
  957.         miMI.afStyle=MIS_TEXT;          /* Style to insert */
  958.         miMI.hwndSubMenu=0;             /* No pulldown menu */
  959.         }
  960.     pMD->hwndItem=hwndMenu;             /* Save the window handle of the item */
  961.     mr=WinSendMsg(
  962.         hwndMenu,
  963.         MM_INSERTITEM,                  /* Insert a menu item */
  964.         &miMI,                          /* Item to insert */
  965.         pMD->PgmTitle);                 /* Test to insert */
  966.     if(((SHORT)mr==MIT_ERROR) || ((SHORT)mr==MIT_MEMERROR))
  967.         GEN_ERR(hab, hwndFrame, hwndClient);
  968.     else bResult=TRUE;
  969.     break;
  970.  
  971. case MM_SETITEMTEXT:
  972. /*                                                                                      *\
  973.  * A available menuitem was selected to change. Change the text of the menuitem to the  *
  974.  * new one.                                                                             *
  975. \*                                                                                      */
  976.     if(WinSendMsg(
  977.         hwndPopupMenu,
  978.         MM_SETITEMTEXT,                 /* Set the text of a menuitem */
  979.         MPFROMSHORT(id),                /* Item ID */
  980.         (MPARAM)pMD->PgmTitle)==FALSE)  /* New menuitem text */
  981.         GEN_ERR(hab, hwndFrame, hwndClient);
  982.     else bResult=TRUE;
  983.     break;
  984.  
  985. case MM_DELETEITEM:
  986. /*                                                                                      *\
  987.  * A available menuitem was selected to delete. Delete the specified menuitem.          *
  988. \*                                                                                      */
  989.     {
  990.     if(pMD->Item==ENTRYSUBMENU)
  991.         {                               /* It the menuitem is a Submenu, also delete the
  992.                                            first item of it (which should be empty) */
  993.         mr=WinSendMsg(
  994.             hwndPopupMenu,
  995.             MM_DELETEITEM,              /* Delete a menuitem */
  996.                                         /* Item ID, include Submenus */
  997.             MPFROM2SHORT((pMD->Submenu->id), TRUE),
  998.             (MPARAM)NULL);
  999.         }
  1000.     mr=WinSendMsg(
  1001.         hwndPopupMenu,
  1002.         MM_DELETEITEM,                  /* Delete a menuitem */
  1003.         MPFROM2SHORT(id, TRUE),         /* Item ID, include Submenus */
  1004.         (MPARAM)NULL);
  1005.     bResult=TRUE;
  1006.     }
  1007.     break;
  1008. }
  1009. return(bResult);
  1010. }
  1011.  
  1012.  
  1013.