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 / PC2.C < prev    next >
Text File  |  1993-03-09  |  63KB  |  1,158 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.  * PC/2 - Program Commander/2 is a configurable program starter for    *
  8.  * OS/2 2.0 PM. If the user clicks button 1 on the DESKTOP, a user     *
  9.  * modifyable popup menu is displayed. The user then selects a program *
  10.  * to be started, or configuration of PC/2 or dismisses it.            *
  11.  * PC/2 is an alternative method of starting programs compared to      *
  12.  * icons and uses no space on DESKTOP, and no folder must be opended   *
  13.  * to start a program. For frequently used programs, this reduces the  *
  14.  * time to start an application.                                       *
  15.  *                                                                     *
  16. \***********************************************************************/
  17.  
  18. static char RCSID[]="@(#) $Header: PC2.c/PC2.h Version 1.20 01,1993 $ (LBL)";
  19.  
  20. #define         _FILE_  "PC/2 - PC2.c V1.20"
  21.  
  22. #include        "PC2.h"                 /* User include files */
  23. #include        "Error.h"
  24.  
  25.                                         /* Pc/2 semaphore to avoid loading PC/2 twice */
  26. #define         PC2_SEM "\\SEM32\\PC2_SEM.SEM"
  27. #define         DESKTOP_CLASS   "#37"   /* Class name of the "Desktop" window handle (which
  28.                                            is reserved in the Toolkit */
  29.  
  30. HEV             hevPc2;                 /* Handle of PC/2 semaphore */
  31. BOOL            InstallHelp;            /* True if we're installing */
  32. UCHAR           *CfgBuffer;             /* The buffer holding the filename of the profile */
  33. HMODULE         hDllPc2;                /* Handle of PC/2 DLL */
  34. PFFUNCPTR1      *pPC2DLL_SetHwnd;       /* Pointer to DLL-Functions */
  35. PFFUNCPTR2      *pPC2DLL_Hook;
  36. /*                                                                                      *\
  37.  * Reserve data referenced generally through all modules. This isn't the best way, hope *
  38.  * that C++ comes out soon...                                                           *
  39. \*                                                                                      */
  40. HAB             hab;                    /* Handle of PM anchor block */
  41. HMQ             hmq;                    /* Handle of message queue */
  42. HWND            hwndFrame;              /* Frame handle of window */
  43. HWND            hwndClient;             /* Client handle of window */
  44. HWND            hwndPopupMenu;          /* Handel of popup menu window */
  45.                                         /* Input options: mouse button 1 depressed,
  46.                                            Input devices keyboard or mouse button 1,
  47.                                            popup menu allways visible on DESKTOP,
  48.                                            position so that ID_CONFIGDIALOG is under the
  49.                                            pointer */
  50. HWND            hwndHelp;               /* Help window handle */
  51. SESSIONDATA     SessionData;            /* Used by Menu Installation dialog and by
  52.                                            Program Installation dialog to store menu or
  53.                                            program data, to be filled from the user or
  54.                                            to be presented to the user. */
  55. MENUDATA        *pPopupMenu=NULL;       /* Used by all procedures as the starting point
  56.                                            of a linked list of menu entries. */
  57. MENUDATA        *pMenuData;             /* This pointer points to the current level of
  58.                                            Submenus and Menuitems within the configuration
  59.                                            dialog procedure */
  60.                                         /* Create linked list by starting with this ID */
  61. USHORT          MenuDataId=ID_POPUPMENU;
  62. USHORT          DialogResult;           /* Each dialog procedure returns the result in
  63.                                            this variable to enable the calling routine to
  64.                                            check, if there is valid data or not. */
  65. FILE            *Pc2Profile;            /* Open the profile, where the user entered menu
  66.                                            data is stored, with this handle */
  67. SWP             swpScreen;              /* The screen dimensions */
  68.  
  69. /*--------------------------------------------------------------------------------------*\
  70.  * The main procedure.                                                                  *
  71.  * Req:                                                                                 *
  72.  *      argc, argv, envp                                                                *
  73.  * Returns:                                                                             *
  74.  *      int ........... Exitcode (0, or errorlevel)                                     *
  75. \*--------------------------------------------------------------------------------------*/
  76. int main(int argc, char *argv[], char *envp[])
  77. {
  78. QMSG    qmsg;                           /* Message queue */
  79. ULONG   counter;                        /* Temporary counter */
  80.                                         /* Frame creation control flag */
  81. ULONG   flCreate=FCF_TASKLIST | FCF_ACCELTABLE;
  82.  
  83. /*                                                                                      *\
  84.  * Get the full path and filename of the running copy of PC/2 and change the extension  *
  85.  * .EXE into .cfg to open the configuration file under this name. If the user supplies  *
  86.  * [-,/Profile filename.ext] then use this filename as the Profile.                     *
  87. \*                                                                                      */
  88. CfgBuffer=malloc(strlen(argv[0])+64);   /* Long enough to hold user Profile name */
  89. strcpy(CfgBuffer, argv[0]);
  90. strcpy(strchr(CfgBuffer, '.'), ".cfg");
  91. InstallHelp=FALSE;                      /* Assume no installation */
  92. for(counter=1; counter<argc; counter++)
  93.     {
  94.     strupr(argv[counter]);              /* Convert to uppercase */
  95.     if((strstr(argv[counter], "/PROFILE")!=NULL) ||
  96.         (strstr(argv[counter], "-PROFILE")!=NULL))
  97.                                         /* Test for /PROFILE or -PROFILE to get a
  98.                                            profile name */
  99.         strcpy((CfgBuffer+strlen(CfgBuffer)-7), argv[counter+1]);
  100.     if((strstr(argv[counter], "/INSTALL")!=NULL) ||
  101.         (strstr(argv[counter], "-INSTALL")!=NULL))
  102.                                         /* Test for /INSTALL or -HELP to start the help
  103.                                            panels during initialization */
  104.         InstallHelp=TRUE;
  105.     }
  106. do
  107. {
  108.                                         /* Initialize anchor block and message queue */
  109.     if(WinStartUp(&hab, &hmq)==FALSE) break;
  110.     if(!WinRegisterClass(               /* Register window class */
  111.         hab,                            /* Handle of anchor block */
  112.         (PSZ)PC2_CLASSNAME,             /* Window class name */
  113.         (PFNWP)PC2_MainWindowProc,      /* Address of window procedure */
  114.         CS_SAVEBITS,                    /* Class style */
  115.         0))                             /* Extra window words */
  116.         {
  117.         GEN_ERR(hab, (HWND)NULL, (HWND)NULL);
  118.         break;
  119.         }
  120.     if((hwndFrame=WinCreateStdWindow(   /* Create a standart window */
  121.         HWND_DESKTOP,                   /* DESKTOP is parent */
  122.         0,                              /* Standard window styles */
  123.         &flCreate,                      /* Frame control flags */
  124.         (PSZ)PC2_CLASSNAME,             /* Client window class name */
  125.         "",                             /* No window text */
  126.         0,                              /* No special class style */
  127.         (HMODULE)0,                     /* Ressource is in .EXE file */
  128.         ID_PC2MAINWINDOW,               /* Frame window identifier */
  129.         &hwndClient)                    /* Client window handle */
  130.         )==NULLHANDLE)
  131.         {
  132.         GEN_ERR(hab, (HWND)NULL, (HWND)NULL);
  133.         break;
  134.         }
  135. /*                                                                                      *\
  136.  * Check if we are allready loaded before by querying a semaphore that is defined the   *
  137.  * first time PC/2 runs.                                                                *
  138. \*                                                                                      */
  139.     if(DosCreateEventSem(               /* Create a semaphore */
  140.         PC2_SEM,                        /* Name */
  141.         &hevPc2,                        /* Handle */
  142.         (ULONG)0,                       /* Named semaphores are allways shared */
  143.         (BOOL32)FALSE))                 /* Initially set */
  144.         {                               /* If an error occurs, either we can't create
  145.                                            the semaphore or it allready exists. We assume
  146.                                            that it exists, meaning PC/2 allready loaded */
  147.         USR_ERR("PC/2 allready loaded - exiting...", hwndFrame, hwndClient);
  148.         break;
  149.         }
  150. /*                                                                                      *\
  151.  * Load the Pc2Hook DLL and obtain the addresses of the entrypoints.                    *
  152. \*                                                                                      */
  153.     {
  154.     UCHAR   Buffer[80];
  155.  
  156.     if(DosLoadModule(                   /* Load the DLL of PC/2 */
  157.         Buffer,                         /* Save failure there */
  158.         sizeof(Buffer)-1,               /* Length of save area */
  159.         "PC2HOOK",                      /* Library name */
  160.         &hDllPc2)!=NO_ERROR)            /* DLL module handle */
  161.         {                               /* An error occured */
  162.         USR_ERR("Can't find PC2HOOK.DLL, please check DLL and LIBPATH - exiting...",
  163.             hwndFrame, hwndClient);
  164.         break;
  165.         }
  166.     if(DosQueryProcAddr(                /* Now get the address of the functions within the DLL */
  167.         hDllPc2,                        /* DLL module handle */
  168.         1,                              /* Ordinal number of procedure whose address is desired */
  169.         "PC2DLL_SetHwnd",               /* Procedure name being referenced */
  170.                                         /* Procedure address returned */
  171.         (PFN *)(&pPC2DLL_SetHwnd))!=NO_ERROR)
  172.         {                               /* An error occured */
  173.         DosFreeModule(hDllPc2);         /* Free DLL reference */
  174.         USR_ERR("Can't load from PC2HOOK.DLL - exiting...", hwndFrame, hwndClient);
  175.         break;
  176.         }
  177.     if(DosQueryProcAddr(
  178.         hDllPc2,
  179.         2,
  180.         "PC2DLL_Hook",
  181.         (PFN *)(&pPC2DLL_Hook))!=NO_ERROR)
  182.         {
  183.         DosFreeModule(hDllPc2);
  184.         USR_ERR("Can't load from PC2HOOK.DLL - exiting...", hwndFrame, hwndClient);
  185.         break;
  186.         }
  187.     }
  188. /*                                                                                      *\
  189.  * Now initilize Help, if it can't be initialized the we get no help but that's no      *
  190.  * reason to terminate.                                                                 *
  191. \*                                                                                      */
  192.     if(WinStartHelp(hab, &hwndHelp)==FALSE)
  193.         USR_ERR("Sorry, Help couldn't be started - maybe Pc2.HLP is missing",
  194.             hwndFrame, hwndClient);
  195.                                         /* Query and save the device resolution */
  196.     swpScreen.cx=WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
  197.     swpScreen.cy=WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
  198.     if(!WinSetWindowPos(                /* Set window postion */
  199.         hwndFrame,                      /* Window handle */
  200.         HWND_BOTTOM,                    /* Window position at background */
  201.         0, 0, 0, 0,                     /* Window size */
  202.                                         /* Window control */
  203.         SWP_ZORDER | SWP_SHOW | SWP_DEACTIVATE))
  204.         GEN_ERR(hab, (HWND)NULL, (HWND)NULL);
  205.     WinSetWindowText(hwndFrame, "PC/2 - Program Commander/2");
  206. /*                                                                                      *\
  207.  * Now setup the Popup-Menu by loading the data from the profile and install the hook   *
  208.  * into the system input queue.                                                         *
  209. \*                                                                                      */
  210.     hwndPopupMenu=WinLoadMenu(          /* Load popup menu */
  211.         hwndClient,                     /* Owner window handle */
  212.         (HMODULE)0,                     /* Ressource in .EXE file */
  213.         ID_PC2MAINWINDOW);              /* Menu identifier in ressource file */
  214.                                         /* Load the data from the profile */
  215.     WinPostMsg(hwndClient, WM_SETPOPUPMENU, NULL, NULL);
  216.                                         /* Now install the hook */
  217.     WinPostMsg(hwndClient, WM_LOADHOOK, NULL, NULL);
  218. /*                                                                                      *\
  219.  * Here we loop dispatching the messages...                                             *
  220. \*                                                                                      */
  221.     while(WinGetMsg(hab, &qmsg, 0, 0, 0))
  222.         WinDispatchMsg(hab, &qmsg);     /* Dispatch messages to window procedure */
  223.     WinDestroyWindow(hwndFrame);        /* Close window */
  224. } while (FALSE);
  225.  
  226. if(WinCloseDown(&hwndHelp, &hab, &hmq)==FALSE) return(1);
  227. else return(0);
  228. }
  229.  
  230. /*--------------------------------------------------------------------------------------*\
  231.  * This procedure is the PC/2 window procedure.                                         *
  232. \*--------------------------------------------------------------------------------------*/
  233. MRESULT EXPENTRY PC2_MainWindowProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  234. {
  235. switch(msg)
  236. {
  237. case WM_CREATE:                         /* Create window by WinCreateStdWindow() */
  238.  
  239.                                         /* First call default window procedure */
  240.     WinDefWindowProc(hwnd, msg, mp1, mp2);
  241.     if(InstallHelp==TRUE)               /* For installation display help panels */
  242.         WinPostMsg(hwnd, WM_COMMAND, MPFROMSHORT(ID_HELP), NULL);
  243.     break;
  244.  
  245. /*                                                                                      *\
  246.  * Syntax: WM_SETPOPUPMENU, NULL, NULL                                                  *
  247. \*                                                                                      */
  248. case WM_SETPOPUPMENU:
  249. /*                                                                                      *\
  250.  * Open the profile for reading the linked list containing the popup menu data. If the  *
  251.  * profile can't be opened, the file is assumed to be empty so the popup menu is empty. *
  252. \*                                                                                      */
  253.     if((Pc2Profile=fopen(CfgBuffer, "r"))==NULL)
  254.         {
  255.         pPopupMenu=AllocateMenuData();  /* Allocate an empty MENUDATA structure used as
  256.                                            the first element of linked list */
  257.         fclose(Pc2Profile);
  258.         USR_ERR("Cannot open confguration file - assuming empty file", hwndFrame, hwndClient);
  259.         }
  260.     else
  261.         {
  262.         static UCHAR    Buffer[256];
  263.  
  264.         pPopupMenu=AllocateMenuData();  /* Allocate an empty MENUDATA structure used as
  265.                                            the first element of linked list */
  266.         fgets(Buffer, sizeof(Buffer), Pc2Profile);
  267.         if(strcmp(Buffer, "PROFILE START\n")==0)
  268.             LoadMenu(pPopupMenu);       /* Load the rest by calling a recursive procedure */
  269.         fclose(Pc2Profile);
  270.         }
  271.     pMenuData=pPopupMenu;               /* Initialize *MENUDATA for Configuration dialog
  272.                                            procedure to a known value */
  273. /*                                                                                      *\
  274.  * Open the profile for writing the linked list containing the popup menu data. Don't   *
  275.  * forget to write the PROFILE START and PROFILE END headers.                           *
  276. \*                                                                                      */
  277. //    if((Pc2Profile=fopen(CfgBuffer, "w"))==NULL)
  278. //        fclose(Pc2Profile);
  279. //    else
  280. //        {
  281. //        fprintf(Pc2Profile, "PROFILE START\n");
  282. //        SaveMenu(pPopupMenu);           /* Save the menu linked list */
  283. //        fprintf(Pc2Profile, "PROFILE END\n");
  284. //        fclose(Pc2Profile);
  285. //        }
  286.     break;
  287.  
  288. /*                                                                                      *\
  289.  * Syntax: WM_LOADHOOK, NULL, NULL                                                      *
  290. \*                                                                                      */
  291. case WM_LOADHOOK:
  292. /*                                                                                      *\
  293.  * Install the hook into the system input queue pointing to the PC2DLL_Hook() procedure *
  294.  * in the DLL PC2HOOK.DLL. If we can't do this we exit after an error message box.      *
  295. \*                                                                                      */
  296.     {
  297.     UCHAR       ucClass[33];            /* Save class name here */
  298.     HWND        hwndDesktop;            /* Save "Desktop" window handle, where the user
  299.                                            clicks with mouse button 1 */
  300.     HENUM       henumWindows;           /* Enumerate windows */
  301.     BOOL        bMatch;                 /* True if correct "Desktop" window handle was found */
  302.  
  303.                                         /* Get to bottommost window handle of the "Desktop" */
  304.     hwndDesktop=WinQueryWindow(HWND_DESKTOP, QW_BOTTOM);
  305.                                         /* Enumerate all windows at "Desktop" z-order */
  306.     henumWindows=WinBeginEnumWindows(hwndDesktop);
  307.     bMatch=FALSE;
  308.     while(hwndDesktop=WinGetNextWindow(henumWindows))
  309.         {
  310.                                         /* Now get the class name of that window handle */
  311.         WinQueryClassName(hwndDesktop, sizeof(ucClass)-1, (PCH)ucClass);
  312.                                         /* If we find the required "Desktop" window (it
  313.                                            has a class name of #37, which is reserved in the
  314.                                            Toolkit) set this value into the Hook DLL */
  315.         if(!strcmp(ucClass, DESKTOP_CLASS))
  316.             {
  317.             bMatch=TRUE;
  318.             pPC2DLL_SetHwnd(hwndDesktop, hwnd);
  319.             }
  320.         }
  321.     WinEndEnumWindows(henumWindows);    /* End enumeration */
  322. /*                                                                                      *\
  323.  * If bMatch==TRUE then we have found the required "Desktop" window, but this is only   *
  324.  * available if the WPS is running. If the WPS is not running (PM running alone, then   *
  325.  * bMatch==FALSE will be set. Thus bMatch will be used to differentiate between PM      *
  326.  * running with WPS and without WPS - however I don't know if this holds true for all   *
  327.  * OS/2 2.x releases.                                                                   *
  328. \*                                                                                      */
  329.     if(bMatch==FALSE)
  330.         {
  331.                                         /* Without WPS installed we can get the "Desktop"
  332.                                            window handle easyly */
  333.         hwndDesktop=WinQueryDesktopWindow(hab, NULLHANDLE);
  334.         pPC2DLL_SetHwnd(hwndDesktop, hwnd);
  335.         }
  336.     if(WinSetHook(                      /* Set a hook */
  337.         hab,                            /* Handle of anchor block */
  338.         NULLHANDLE,                     /* Hook into system message queue */
  339.         HK_INPUT,                       /* Hook of system input queue */
  340.         (PFN)pPC2DLL_Hook,              /* Pointer to hook procedure */
  341.         hDllPc2)==FALSE)
  342.         {
  343.         USR_ERR("Hooking the system input queue failed - exiting...", hwndFrame, hwndClient);
  344.         WinPostMsg(hwnd, WM_QUIT, NULL, NULL);
  345.         }
  346.     }
  347.     break;
  348.  
  349. /*                                                                                      *\
  350.  * Syntax: WM_SAVEPOPUPMENU, (x,y), NULL                                                 *
  351. \*                                                                                      */
  352. case WM_POPUPMENU:
  353. /*                                                                                      *\
  354.  * The hook found that button 1 was clicked on the Desktop and sent us this message. It *
  355.  * is the save as WM_BUTTON1CLICK but the name. First we obtain the focus, to be able   *
  356.  * to start our programs in the foreground.                                             *
  357. \*                                                                                      */
  358.     {
  359.     ULONG        flOptions=PU_MOUSEBUTTON1DOWN | PU_KEYBOARD | PU_MOUSEBUTTON1 |
  360.                            PU_POSITIONONITEM | PU_HCONSTRAIN | PU_VCONSTRAIN;
  361.  
  362.     WinSetFocus(HWND_DESKTOP, hwnd);    /* Set focus to our window */
  363.     if(!WinPopupMenu(                   /* Pop up the popup menu */
  364.         HWND_DESKTOP,                   /* Parent window handle */
  365.         hwnd,                           /* Owner window handle that receives all the
  366.                                            notification messages generated by the pop-up
  367.                                            menu */
  368.         hwndPopupMenu,                  /* Popup menu window handle */
  369.         SHORT1FROMMP(mp1),              /* x-coordinate of popup menu */
  370.         SHORT2FROMMP(mp1),              /* y-coordinate of popup menu */
  371.         ID_PC2SETUP,                    /* Input item identity, if PU_POSITIONONITEM or
  372.                                            PU_SELECTITEM is set */
  373.         flOptions)                      /* Input options */
  374.     ) GEN_ERR(hab, (HWND)NULL, (HWND)NULL);
  375.     break;
  376.     }
  377.  
  378. case WM_CLOSE:
  379.     if(WinMessageBox(                   /* Ask the user if he really wants to exit */
  380.         HWND_DESKTOP, HWND_DESKTOP,
  381.         "Are you sure you want to close PC/2?",
  382.         "PC/2 - Program Commander/2",
  383.         ID_PC2MAINWINDOW,
  384.         MB_OKCANCEL | MB_ICONQUESTION | MB_DEFBUTTON2)!=MBID_OK)
  385.         return((MRESULT)TRUE);          /* Only exit if OK is pressed */
  386.     if(WinReleaseHook(                  /* Release hook */
  387.         hab,                            /* Handle  of anchor block */
  388.         NULLHANDLE,                     /* Release from system hook chain */
  389.         HK_INPUT,                       /* Hook of system input queue */
  390.         (PFN)pPC2DLL_Hook,              /* Pointer to hook procedure */
  391.         hDllPc2)==FALSE)
  392.         {
  393.         USR_ERR("Unhooking the system input queue failed, System ShutDown suggested - exiting...",
  394.             hwndFrame, hwndClient);
  395.         WinPostMsg(hwnd, WM_QUIT, NULL, NULL);
  396.         }
  397.     DosFreeModule(hDllPc2);             /* Free DLL reference */
  398.     WinPostMsg(hwnd, WM_QUIT, NULL, NULL);
  399.     break;
  400.  
  401. case HM_ERROR:
  402.    {
  403.    ULONG        command;
  404.    command=LONGFROMMP(mp1);
  405.  
  406.    GEN_ERR(hab, hwndFrame, hwndClient);
  407.    break;
  408.    }
  409.  
  410. case WM_COMMAND:
  411.     {
  412.     USHORT      command;
  413.  
  414.     command=SHORT1FROMMP(mp1);          /* Extract the command value */
  415. /*                                                                                      *\
  416.  * Filter the IDs of the user defined items of the Popup-Menu. If one is found, call    *
  417.  * SearchItem() to search for the corresponding MENUDATA structure, copy it to a        *
  418.  * SESSIONDATA structure and start the session.                                         *
  419. \*                                                                                      */
  420.     if((command>=USERITEMFIRST) && (command<=USERITEMLAST))
  421.         {
  422.         ULONG           id=(ULONG)command;
  423.         MENUDATA        *pMD=NULL;
  424.  
  425.                                         /* Search in the linked list for this entry */
  426.         if((pMD=SearchItem(pPopupMenu, &id))!=NULL)
  427.         if(pMD->Item==ENTRYMENUITEM)
  428.             {
  429.                                         /* Load SessionData with MENUDATA structure */
  430.             LoadMenuData2SessionData(FALSE, pMD, &SessionData);
  431.                                         /* Start the session */
  432.             StartSession(&SessionData);
  433.             }
  434.         }
  435.     switch(command)
  436.     {
  437.  
  438.     case ID_HELP:                       /* Display general help panel */
  439.         if(hwndHelp!=NULLHANDLE) WinSendMsg(
  440.             hwndHelp,                   /* Help window */
  441.             HM_DISPLAY_HELP,            /* Display a help panel */
  442.             MPFROMSHORT(ID_HELP),       /* Panel ID in ressource file */
  443.             HM_RESOURCEID);             /* MP1 points to the help window identity */
  444.         break;
  445.  
  446.     case ID_CONFIGDIALOG:               /* Popup menuitem Configure PC/2 selected */
  447.     if(!WinDlgBox(                      /* Start Configure PC/2 dialog box */
  448.         HWND_DESKTOP,                   /* DESKTOP is parent */
  449.         HWND_DESKTOP,                   /* DESKTOP is owner */
  450.         CD_DialogProcedure,             /* Dialog procedure of Program Installation
  451.                                            dialog */
  452.         0,                              /* Ressource is .EXE file */
  453.         CDID_CONFIGDIALOG,              /* ID of Configure PC/2 dialog */
  454.         0))                             /* No initialization data */
  455.         GEN_ERR(hab, hwndFrame, hwndClient);
  456.         break;
  457.  
  458.     case ID_EXIT:                       /* User selected F3 to shutdown PC/2 */
  459.         WinPostMsg(hwnd, WM_CLOSE, 0, 0);
  460.         break;
  461.  
  462.     case ID_ABOUTDIALOG:                /* User selected About PC/2 dialog */
  463.         if(!WinDlgBox(                  /* Start About PC/2 dialog box */
  464.             HWND_DESKTOP,               /* DESKTOP is parent */
  465.             HWND_DESKTOP,               /* DESKTOP is owner */
  466.             AD_DialogProcedure,         /* Dialog procedure of Program Installation
  467.                                            dialog */
  468.             0,                          /* Ressource is .EXE file */
  469.             ADID_ABOUTDIALOG,           /* ID of Program Installation dialog */
  470.             0))                         /* No initialization data */
  471.             GEN_ERR(hab, hwndFrame, hwndClient);
  472.         break;
  473.     }
  474.     }
  475.  
  476. default:                                /* Default window procedure must be called */
  477.     return((MRESULT)WinDefWindowProc(hwnd, msg, mp1, mp2));
  478. }
  479. return((MRESULT)FALSE);                 /* We have handled the message */
  480. }
  481.  
  482. /*--------------------------------------------------------------------------------------*\
  483.  * This dialog procedure handles the PC/2 - Configuration (Setup) dialog.               *
  484.  * Req: none                                                                            *
  485. \*--------------------------------------------------------------------------------------*/
  486. MRESULT  EXPENTRY CD_DialogProcedure(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
  487. {
  488. switch(msg)
  489. {
  490. case WM_INITDLG:
  491.     {
  492.     SWP         swp;
  493.  
  494.     WinQueryWindowPos(                  /* Query position of dialog window */
  495.         hwndDlg,                        /* Handle of dialog window */
  496.         &swp);                          /* Fill with position */
  497.     WinSetWindowPos(                    /* Set dialog window position */
  498.         hwndDlg,                        /* Handle of dialog window */
  499.         HWND_TOP,                       /* Position on top and center of DESKTOP */
  500.         (swpScreen.cx-swp.cx)/2,
  501.         (swpScreen.cy-swp.cy)/2,
  502.         0,
  503.         0,
  504.         SWP_MOVE);
  505.                                         /* Initialize the listbox */
  506.     WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  507.     break;
  508.     }
  509.  
  510. /*                                                                                      *\
  511.  * Syntax: WM_LOADPOPUPMENU, *MENUDATA, NULL                                            *
  512. \*                                                                                      */
  513. case WM_LOADPOPUPMENU:                  /* Load the current level of the Popup-Menu in
  514.                                            the listbox after removing the old items */
  515.     {
  516.     MENUDATA    *pMD;
  517.  
  518.     pMD=PVOIDFROMMP(mp1);               /* Get the pointer to the first MENUDATA of the
  519.                                            current level */
  520.     WinSendDlgItemMsg(                  /* Send message to listbox */
  521.         hwndDlg,                        /* Handle of dialog window */
  522.         CDLB_MENUPROGRAM,               /* Submenu & Program listbox */
  523.         LM_DELETEALL,                   /* Delete all list box items */
  524.         (MPARAM)NULL,
  525.         (MPARAM)NULL);
  526.     if(pMD==NULL) break;                /* If linked list is empty break out */
  527.     do
  528.     {
  529.         if(pMD->Item==ENTRYSUBMENU)     /* It is a Submenu */
  530.             {
  531.             UCHAR       Buffer[EF_SIZE60+4];
  532.                                         /* Add >> for a Submenu */
  533.             sprintf(Buffer, "%s >>", pMD->PgmTitle);
  534.             WinSendDlgItemMsg(
  535.                 hwndDlg,
  536.                 CDLB_MENUPROGRAM,
  537.                 LM_INSERTITEM,          /* Insert Submenu Title at the end */
  538.                 MPFROMSHORT(LIT_END),
  539.                 MPFROMP(Buffer));
  540.             }
  541.         if(pMD->Item==ENTRYMENUITEM)    /* It's a Menuitem */
  542.             WinSendDlgItemMsg(
  543.                 hwndDlg,
  544.                 CDLB_MENUPROGRAM,
  545.                 LM_INSERTITEM,          /* Insert Menuitem Title at the end */
  546.                 MPFROMSHORT(LIT_END),
  547.                 MPFROMP(pMD->PgmTitle));
  548.                                         /* It may also be an empty entry, but then we
  549.                                            ignore it, because it must be filled with
  550.                                            Menuitem or Submenu data first */
  551.         if(pMD->Next!=NULL)             /* Get through linked list without diving into
  552.                                            Submenus */
  553.                 pMD=pMD->Next;
  554.         else break;                     /* We're at the end of the linked list */
  555.     }while(TRUE);
  556.     break;
  557.     }
  558.  
  559. /*                                                                                      *\
  560.  * Syntax: WM_SAVEPOPUPMENU, NULL, NULL                                                 *
  561. \*                                                                                      */
  562. case WM_SAVEPOPUPMENU:                  /* Save the Popup-Menu to the configuraion file */
  563.     if((Pc2Profile=fopen(CfgBuffer, "w"))==NULL)
  564.         fclose(Pc2Profile);
  565.     else
  566.         {
  567.         fprintf(Pc2Profile, "PROFILE START\n");
  568.         SaveMenu(pPopupMenu);           /* Save the menu linked list */
  569.         fprintf(Pc2Profile, "PROFILE END\n");
  570.         fclose(Pc2Profile);
  571.         }
  572.     break;
  573.  
  574. case WM_HELP:                           /* Help pressed */
  575.     WinSendMsg(
  576.         hwndHelp,                       /* Help window */
  577.         HM_DISPLAY_HELP,                /* Display a help panel */
  578.         MPFROMSHORT(ID_CONFIGDIALOG),   /* Panel ID in ressource file */
  579.         HM_RESOURCEID);                 /* MP1 points to the help window identity */
  580.     break;
  581.  
  582. case WM_COMMAND:                        /* Button pressed */
  583.     switch(SHORT1FROMMP(mp1))
  584.     {
  585. /*                                                                                      *\
  586.  * Chain up the linked list until we find the node, where this part-list comes from or  *
  587.  * the beginning of the complete list. The pointer pMenuData is adjusted.               *
  588. \*                                                                                      */
  589.     case CDID_LEVELUP:                  /* Get up one level in the linked list */
  590.         {
  591.         MENUDATA        *pMD;           /* Pointer to a MENUDATA structure to find the
  592.                                            Submenu where this part-list starts */
  593.  
  594.         pMD=pMenuData;                  /* Point to the first element of the linked list
  595.                                            at the current level */
  596.         if(pMD->Back==NULL)             /* If we're at the beginning of the complete linked
  597.                                            list ignore button */
  598.             return((MRESULT)FALSE);
  599.         else pMD=pMD->Back;             /* Submenu which started current level */
  600.                                         /* Now chain back through the linked list and find
  601.                                            the element, where the pointer to a Submenu
  602.                                            equals the back pointer of the first element
  603.                                            in this Submenu. Then we've found the node */
  604.         while(TRUE)
  605.             {
  606.             if(pMD->Back==NULL)         /* If we're now at the beginning break */
  607.                 break;
  608.             if((pMD->Back)->Submenu==pMD)
  609.                 break;
  610.             else pMD=pMD->Back;
  611.             }
  612.         pMenuData=pMD;                  /* Load as the top element of the current item */
  613.                                         /* Now redraw items in listbox */
  614.         WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  615.         return((MRESULT)FALSE);         /* We handled this button */
  616.         break;
  617.         }
  618.  
  619. /*                                                                                      *\
  620.  * Test the user selection for being a Submenu. If one found chain into this submenu    *
  621.  * and adjust the pointer pMenuData.                                                    *
  622. \*                                                                                      */
  623.     case CDID_LEVELDOWN:                /* Get down one level in the linked list */
  624.         {
  625.         MENUDATA        *pMD;           /* Pointer to a MENUDATA structure to find the
  626.                                            Submenu to chain into */
  627.         SHORT           sCount;
  628.  
  629.         pMD=pMenuData;                  /* Point to the first element of the linked list
  630.                                            at the current level */
  631.                                         /* Send message to listbox */
  632.         sCount=(SHORT)WinSendDlgItemMsg(
  633.             hwndDlg,                    /* Handle of dialog window */
  634.             CDLB_MENUPROGRAM,           /* Submenu & Program listbox */
  635.             LM_QUERYSELECTION,          /* Query first selected list box item */
  636.             MPFROMSHORT(LIT_FIRST),
  637.             (MPARAM)NULL);
  638.                                         /* If no item selected, ignore this button */
  639.         if(sCount==LIT_NONE)
  640.             return((MRESULT)FALSE);
  641.         for( ;sCount>0; sCount--)       /* Walk through the linked list to the selected
  642.                                            item */
  643.             pMD=pMD->Next;
  644.         if(pMD->Item!=ENTRYSUBMENU)     /* It's not a Submenu that's selected, ignore */
  645.             return((MRESULT)FALSE);
  646.         pMenuData=pMD->Submenu;         /* Otherwise chain into this part-list */
  647.                                         /* Now redraw items in listbox */
  648.         WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  649.         return((MRESULT)FALSE);         /* We handled this button */
  650.         break;
  651.         }
  652.  
  653. /*                                                                                      *\
  654.  * The user selected to add a (Sub)Menu. Thus dismiss the PC/2 Configuration dialog and *
  655.  * load the (Sub)Menu Installation dialog. The new (Sub)Menu is entered in a            *
  656.  * STARTSESSION structure named StartSession. Save the changes and reload the PC/2      *
  657.  * Configuration dialog again.                                                          *
  658. \*                                                                                      */
  659.     case CDID_ADDMENU:                  /* Add a Menu to PC/2 Configuration selected */
  660. /*                                                                                      *\
  661.  * The user selected to add a Program. Thus dismiss the PC/2 Configuration dialog and   *
  662.  * load the Program Installation dialog. The new session data is entered in a           *
  663.  * STARTSESSION structure named StartSession. Save the changes and reload the PC/2      *
  664.  * Configuration dialog again.                                                          *
  665. \*                                                                                      */
  666.     case CDID_ADDPROGRAM:               /* Add a Program to PC/2 Configuration selected */
  667.         {
  668.         UCHAR           *pU;            /* Temporary character pointer */
  669.         MENUDATA        *pMD;           /* Pointer to a MENUDATA structure to insert a
  670.                                            new MENUDATA stucture after */
  671.         MENUDATA        *pMDNew;        /* Temporary pointer for the new item to be inserted
  672.                                            after pMD */
  673.         SHORT           sCount;
  674.  
  675.         pMD=pMenuData;                  /* Point to the first element of the linked list
  676.                                            at the current level */
  677.                                         /* Send message to listbox */
  678.         sCount=(SHORT)WinSendDlgItemMsg(
  679.             hwndDlg,                    /* Handle of dialog window */
  680.             CDLB_MENUPROGRAM,           /* Submenu & Program listbox */
  681.             LM_QUERYSELECTION,          /* Query first selected list box item */
  682.             MPFROMSHORT(LIT_FIRST),
  683.             (MPARAM)NULL);
  684.                                         /* If no item selected, and there exists one,
  685.                                            ignore this button. If none exists, none can be
  686.                                            selected, so accept button without selection */
  687.         if((sCount==LIT_NONE) && (pMenuData->Item!=ENTRYEMPTY))
  688.             return((MRESULT)FALSE);
  689.         for( ;sCount>0; sCount--)       /* Walk through the linked list to the selected
  690.                                            item */
  691.             pMD=pMD->Next;
  692.                                         /* Allocate a new item */
  693.         pMDNew=AllocateMenuData();
  694.         strcpy(pU=malloc(strlen("Insert here please")+1), "Insert here please");
  695.         free(pMDNew->PgmTitle);
  696.         pMDNew->PgmTitle=pU;
  697.         pMDNew->id=MenuDataId++;        /* Increment ID */
  698.                                         /* Load SessionData with empty pMDNew structure */
  699.         LoadMenuData2SessionData(TRUE, pMDNew, &SessionData);
  700.         WinDismissDlg(hwndDlg, TRUE);   /* Clear up Configuration dialog */
  701.         if(SHORT1FROMMP(mp1)==CDID_ADDMENU)
  702.             {
  703.             if(!WinDlgBox(              /* Start Addmenu PC/2 dialog box */
  704.                 HWND_DESKTOP,           /* DESKTOP is parent */
  705.                 HWND_DESKTOP,           /* DESKTOP is owner */
  706.                 MI_DialogProcedure,     /* Dialog procedure of Program Installation
  707.                                            dialog */
  708.                 0,                      /* Ressource is .EXE file */
  709.                 MIID_MENUDIALOG,        /* ID of Addmenu PC/2 dialog */
  710.                 0))                     /* No initialization data */
  711.                 GEN_ERR(hab, hwndFrame, hwndClient);
  712.             }
  713.         else
  714.             {
  715.             if(!WinDlgBox(              /* Start Program Installation dialog box */
  716.                 HWND_DESKTOP,           /* DESKTOP is parent */
  717.                 HWND_DESKTOP,           /* DESKTOP is owner */
  718.                 PI_DialogProcedure,     /* Dialog procedure of Program Installation
  719.                                            dialog */
  720.                 0,                      /* Ressource is .EXE file */
  721.                 PIID_PROGRAMDIALOG,     /* ID of Addprogram PC/2 dialog */
  722.                 0))                     /* No initialization data */
  723.                 GEN_ERR(hab, hwndFrame, hwndClient);
  724.             }
  725.         if(DialogResult==DID_OK)        /* If manipulation is done successfully, then load
  726.                                            the SESSIONDATA structure back to the MENUDATA
  727.                                            structure and save the changes */
  728.             {
  729.             LoadSessionData2MenuData(pMDNew, &SessionData);
  730.             if(pMD->Item!=ENTRYEMPTY)   /* Add new entry, if the current entry isn't empty */
  731.                 {
  732.                 if(SHORT1FROMMP(mp1)==CDID_ADDMENU)
  733.                     {                   /* It it is a Submenu, we also must add an empty
  734.                                            first item for it */
  735.                     MENUDATA    *pMDTemp;
  736.  
  737.                     pMDTemp=AllocateMenuData();
  738.                     pMDNew->Submenu=pMDTemp;
  739.                     pMDTemp->Back=pMDNew;
  740.                     pMDNew->Item=ENTRYSUBMENU;
  741.                     }
  742.                 else pMDNew->Item=ENTRYMENUITEM;
  743.                 if(pMD->Next!=NULL) (pMD->Next)->Back=pMDNew;
  744.                 pMDNew->Next=pMD->Next;
  745.                 pMDNew->Back=pMD;
  746.                 pMD->Next=pMDNew;
  747.                                         /* Insert item after the existing item */
  748.                 SetPopupMenu(pMDNew, MM_INSERTITEMMENUITEM, pMD->id);
  749.                 }
  750.             else                        /* If it is an empty entry fill it with user data */
  751.                 {
  752.                 UCHAR   *pU;            /* Temporary character pointer */
  753.  
  754.                 pMD->id=pMDNew->id;
  755.                 if(SHORT1FROMMP(mp1)==CDID_ADDMENU)
  756.                     {                   /* It it is a Submenu, we also must add an empty
  757.                                            first item for it */
  758.                     MENUDATA    *pMDTemp;
  759.  
  760.                     pMDTemp=AllocateMenuData();
  761.                     pMD->Submenu=pMDTemp;
  762.                     pMDTemp->Back=pMD;
  763.                     pMD->Item=ENTRYSUBMENU;
  764.                     }
  765.                 else pMD->Item=ENTRYMENUITEM;
  766.                 strcpy(pU=malloc(strlen(pMDNew->PgmTitle)+1), pMDNew->PgmTitle);
  767.                 free(pMD->PgmTitle);
  768.                 pMD->PgmTitle=pU;
  769.                 strcpy(pU=malloc(strlen(pMDNew->PgmName)+1), pMDNew->PgmName);
  770.                 free(pMD->PgmName);
  771.                 pMD->PgmName=pU;
  772.                 strcpy(pU=malloc(strlen(pMDNew->PgmDirectory)+1), pMDNew->PgmDirectory);
  773.                 free(pMD->PgmDirectory);
  774.                 pMD->PgmDirectory=pU;
  775.                 strcpy(pU=malloc(strlen(pMDNew->PgmInputs)+1), pMDNew->PgmInputs);
  776.                 free(pMD->PgmInputs);
  777.                 pMD->PgmInputs=pU;
  778.                 pMD->SessionType=pMDNew->SessionType;
  779.                 pMD->PgmControl=pMDNew->PgmControl;
  780.                 pMD->FgBg=pMDNew->FgBg;
  781.                 pMD->InitXPos=pMDNew->InitXPos;
  782.                 pMD->InitYPos=pMDNew->InitYPos;
  783.                 pMD->InitXSize=pMDNew->InitXSize;
  784.                 pMD->InitYSize=pMDNew->InitYSize;
  785.                 pMD->PriorityClass=pMDNew->PriorityClass;
  786.                 pMD->PriorityDelta=pMDNew->PriorityDelta;
  787.                 if(pMD->Back!=NULL)     /* This is the first item of a Submenu, then
  788.                                            insert it there */
  789.                     SetPopupMenu(pMD, MM_INSERTITEMSUBMENU, (pMD->Back)->id);
  790.                 else                    /* This is the complete first item of the linked
  791.                                            list, so insert at the end */
  792.                     SetPopupMenu(pMD, MM_INSERTITEMMENUITEM, MIT_END);
  793.                 free(pMDNew->PgmTitle); /* Free temporary used structure */
  794.                 free(pMDNew->PgmName);
  795.                 free(pMDNew->PgmDirectory);
  796.                 free(pMDNew->PgmInputs);
  797.                 free(pMDNew);
  798.                 }
  799.             }
  800.         else
  801.             {
  802.             free(pMDNew->PgmTitle);     /* Free temporary MENUDATA structure */
  803.             free(pMDNew->PgmName);
  804.             free(pMDNew->PgmDirectory);
  805.             free(pMDNew->PgmInputs);
  806.             free(pMDNew);
  807.             }
  808.                                         /* Initialize the listbox */
  809.         WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  810.         if(!WinDlgBox(                  /* Now reload the Configuration dialog */
  811.             HWND_DESKTOP,
  812.             HWND_DESKTOP,
  813.             CD_DialogProcedure,
  814.             0,
  815.             CDID_CONFIGDIALOG,
  816.             0)) GEN_ERR(hab, hwndFrame, hwndClient);
  817.         break;                          /* We never get here because of calling WinDlgBox() */
  818.         }
  819.  
  820. /*                                                                                      *\
  821.  * The user selected to change an item. Thus dismiss the PC/2 Configuration dialog and  *
  822.  * load the Menu or Program Installation dialog. The new session data is entered in a   *
  823.  * STARTSESSION structure named StartSession.                                           *
  824.  * Then reload the PC/2 Configuration dialog again.                                     *
  825. \*                                                                                      */
  826.     case CDID_CHANGEENTRY:              /* Change a Menu or Program configuration selected */
  827.         {
  828.         MENUDATA        *pMD;
  829.         SHORT           sCount;
  830.  
  831.         pMD=pMenuData;                  /* Point to the first element of the linked list
  832.                                            at the current level */
  833.                                         /* Send message to listbox */
  834.         sCount=(SHORT)WinSendDlgItemMsg(
  835.             hwndDlg,                    /* Handle of dialog window */
  836.             CDLB_MENUPROGRAM,           /* Submenu & Program listbox */
  837.             LM_QUERYSELECTION,          /* Query first selected list box item */
  838.             MPFROMSHORT(LIT_FIRST),
  839.             (MPARAM)NULL);
  840.         if(sCount==LIT_NONE)            /* If no item selected ignore this button */
  841.             return((MRESULT)FALSE);
  842.         for( ;sCount>0; sCount--)       /* Walk through the linked list to the selected
  843.                                            item */
  844.             pMD=pMD->Next;
  845.                                         /* Now load the MENUDATA to SESSIONDATA structure
  846.                                            where the manipulations will take effect */
  847.         LoadMenuData2SessionData(FALSE, pMD, &SessionData);
  848.         WinDismissDlg(hwndDlg, TRUE);   /* Clear up Configuration dialog */
  849.         if(pMD->Submenu==NULL)          /* It's a Menuitem so call the Program Installation
  850.                                            dialog box */
  851.             {
  852.             if(!WinDlgBox(              /* Start Program Installation dialog box */
  853.                 HWND_DESKTOP,           /* DESKTOP is parent */
  854.                 HWND_DESKTOP,           /* DESKTOP is owner */
  855.                 PI_DialogProcedure,     /* Dialog procedure of Program Installation
  856.                                            dialog */
  857.                 0,                      /* Ressource is .EXE file */
  858.                 PIID_PROGRAMDIALOG,     /* ID of Program Installation PC/2 dialog */
  859.                 0))                     /* No initialization data */
  860.                 GEN_ERR(hab, hwndFrame, hwndClient);
  861.             }
  862.         else                            /* It's a Submenu so call the Menu Installation
  863.                                            dialog box */
  864.             {
  865.             if(!WinDlgBox(              /* Start Addmenu PC/2 dialog box */
  866.                 HWND_DESKTOP,           /* DESKTOP is parent */
  867.                 HWND_DESKTOP,           /* DESKTOP is owner */
  868.                 MI_DialogProcedure,     /* Dialog procedure of Program Installation
  869.                                            dialog */
  870.                 0,                      /* Ressource is .EXE file */
  871.                 MIID_MENUDIALOG,        /* ID of Addmenu PC/2 dialog */
  872.                 0))                     /* No initialization data */
  873.                 GEN_ERR(hab, hwndFrame, hwndClient);
  874.             }
  875.         if(DialogResult==DID_OK)        /* If manipulation is done successfully, then load
  876.                                            the SESSIONDATA structure back to the MENUDATA
  877.                                            structure and save the changes */
  878.             {
  879.             LoadSessionData2MenuData(pMD, &SessionData);
  880.                                         /* Now change the menuitem text to the new one */
  881.             SetPopupMenu(pMD, MM_SETITEMTEXT, pMD->id);
  882.                                         /* Initialize the listbox */
  883.             WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  884.             }
  885.         if(!WinDlgBox(                  /* Now reload the Configuration dialog */
  886.             HWND_DESKTOP,
  887.             HWND_DESKTOP,
  888.             CD_DialogProcedure,
  889.             0,
  890.             CDID_CONFIGDIALOG,
  891.             0)) GEN_ERR(hab, hwndFrame, hwndClient);
  892.         break;                          /* We never get here because of calling WinDlgBox() */
  893.         }
  894.  
  895. /*                                                                                      *\
  896.  * The user selected to remove an item. If thist item is the only one in the linked     *
  897.  * list or the first item of a submenu set it to empty otherwise free it's ressources   *
  898.  * and remove the entry.                                                                *
  899. \*                                                                                      */
  900.     case CDID_REMOVEENTRY:              /* Remove a item of the PC/2 Configuration selected */
  901.         {
  902.         UCHAR           *pU;
  903.         MENUDATA        *pMD;
  904.         SHORT           sCount;
  905.  
  906.         pMD=pMenuData;                  /* Point to the first element of the linked list
  907.                                            at the current level */
  908.                                         /* Send message to listbox */
  909.         sCount=(SHORT)WinSendDlgItemMsg(
  910.             hwndDlg,                    /* Handle of dialog window */
  911.             CDLB_MENUPROGRAM,           /* Submenu & Program listbox */
  912.             LM_QUERYSELECTION,          /* Query first selected list box item */
  913.             MPFROMSHORT(LIT_FIRST),
  914.             (MPARAM)NULL);
  915.         if(sCount==LIT_NONE)            /* If no item selected ignore this button */
  916.             return((MRESULT)FALSE);
  917.         for( ;sCount>0; sCount--)       /* Walk through the linked list to the selected
  918.                                            item */
  919.             pMD=pMD->Next;
  920.         if((pMD->Back==NULL) && (pMD->Next!=NULL))
  921.             {                           /* Remove the first item of the complete linked list */
  922.             if(pMD->Item==ENTRYSUBMENU)
  923.             if((pMD->Submenu)->Item==ENTRYEMPTY)
  924.                 {                       /* If it is an empty Submenu remove it completely */
  925.                                         /* Remove the Submenu and the empty first item
  926.                                            from the Popup-Menu */
  927.                 SetPopupMenu(pMD, MM_DELETEITEM, pMD->id);
  928.                 free((pMD->Submenu)->PgmTitle);
  929.                 free((pMD->Submenu)->PgmName);
  930.                 free((pMD->Submenu)->PgmDirectory);
  931.                 free((pMD->Submenu)->PgmInputs);
  932.                 free(pMD->Submenu);
  933.                 (pMD->Next)->Back=NULL;
  934.                 pPopupMenu=pMD->Next;   /* Now next element is the first one */
  935.                 pMenuData=pMD->Next;
  936.                 free(pMD->PgmTitle);
  937.                 free(pMD->PgmName);
  938.                 free(pMD->PgmDirectory);
  939.                 free(pMD->PgmInputs);
  940.                 free(pMD);
  941.                 }
  942.             if(pMD->Item==ENTRYMENUITEM)
  943.                 {                       /* If it is an empty Menuitem remove it completly */
  944.                 (pMD->Next)->Back=NULL;
  945.                 pPopupMenu=pMD->Next;   /* Now next element is the first one */
  946.                 pMenuData=pMD->Next;
  947.                                         /* Remove the item from the Popup-Menu */
  948.                 SetPopupMenu(pMD, MM_DELETEITEM, pMD->id);
  949.                 free(pMD->PgmTitle);
  950.                 free(pMD->PgmName);
  951.                 free(pMD->PgmDirectory);
  952.                 free(pMD->PgmInputs);
  953.                 free(pMD);
  954.                 }
  955.             }
  956.         if((pMD->Back==NULL) && (pMD->Next==NULL))
  957.             {                           /* If it is the one and only item of the linked list
  958.                                            set it to empty */
  959.             if(pMD->Item==ENTRYSUBMENU)
  960.             if((pMD->Submenu)->Item==ENTRYEMPTY)
  961.                 {                       /* If it is an empty Submenu remove the empty
  962.                                            item completely */
  963.                                         /* Remove the item from the Popup-Menu */
  964.                 SetPopupMenu(pMD, MM_DELETEITEM, pMD->id);
  965.                 free((pMD->Submenu)->PgmTitle);
  966.                 free((pMD->Submenu)->PgmName);
  967.                 free((pMD->Submenu)->PgmDirectory);
  968.                 free((pMD->Submenu)->PgmInputs);
  969.                 free(pMD->Submenu);
  970.                 free(pMD->PgmTitle);
  971.                 strcpy(pU=malloc(strlen("")+1), "");
  972.                 pMD->PgmTitle=pU;
  973.                 free(pMD->PgmName);
  974.                 strcpy(pU=malloc(strlen("")+1), "");
  975.                 pMD->PgmName=pU;
  976.                 free(pMD->PgmDirectory);
  977.                 strcpy(pU=malloc(strlen("")+1), "");
  978.                 pMD->PgmDirectory=pU;
  979.                 free(pMD->PgmInputs);
  980.                 strcpy(pU=malloc(strlen("")+1), "");
  981.                 pMD->PgmInputs=pU;
  982.                 pMD->Item=ENTRYEMPTY;
  983.                 pMD->Back=NULL;
  984.                 pMD->Submenu=NULL;
  985.                 pMD->Next=NULL;
  986.                 }
  987.             if(pMD->Item==ENTRYMENUITEM)
  988.                 {                       /* If it is a Menuitem set it to empty */
  989.                                         /* Remove the item from the Popup-Menu */
  990.                 SetPopupMenu(pMD, MM_DELETEITEM, pMD->id);
  991.                 strcpy(pU=malloc(strlen("")+1), "");
  992.                 pMD->PgmTitle=pU;
  993.                 free(pMD->PgmName);
  994.                 strcpy(pU=malloc(strlen("")+1), "");
  995.                 pMD->PgmName=pU;
  996.                 free(pMD->PgmDirectory);
  997.                 strcpy(pU=malloc(strlen("")+1), "");
  998.                 pMD->PgmDirectory=pU;
  999.                 free(pMD->PgmInputs);
  1000.                 strcpy(pU=malloc(strlen("")+1), "");
  1001.                 pMD->PgmInputs=pU;
  1002.                 pMD->Item=ENTRYEMPTY;
  1003.                 pMD->Back=NULL;
  1004.                 pMD->Submenu=NULL;
  1005.                 pMD->Next=NULL;
  1006.                 }
  1007.             }
  1008.         if(pMD->Back!=NULL)
  1009.             {                           /* It is any item of more than one item and not
  1010.                                            the first one */
  1011.             if(((pMD->Back)->Submenu==pMD) && (pMD->Submenu==NULL) && (pMD->Next==NULL))
  1012.                 {                       /* If it is the first item of a Submenu not followed
  1013.                                            by any item, set it to empty */
  1014.                                         /* Remove the item from the Popup-Menu */
  1015.                 SetPopupMenu(pMD, MM_DELETEITEM, pMD->id);
  1016.                 strcpy(pU=malloc(strlen("")+1), "");
  1017.                 pMD->PgmTitle=pU;
  1018.                 free(pMD->PgmName);
  1019.                 strcpy(pU=malloc(strlen("")+1), "");
  1020.                 pMD->PgmName=pU;
  1021.                 free(pMD->PgmDirectory);
  1022.                 strcpy(pU=malloc(strlen("")+1), "");
  1023.                 pMD->PgmDirectory=pU;
  1024.                 free(pMD->PgmInputs);
  1025.                 strcpy(pU=malloc(strlen("")+1), "");
  1026.                 pMD->Item=ENTRYEMPTY;
  1027.                 }
  1028.             if(pMD->Item==ENTRYSUBMENU)
  1029.             if((pMD->Submenu)->Item==ENTRYEMPTY)
  1030.                 {                       /* If it is an empty Submenu so also remove the
  1031.                                            first item in the Submenu */
  1032.                                         /* Remove the Submenu and the empty first item
  1033.                                            from the Popup-Menu */
  1034.                 SetPopupMenu(pMD, MM_DELETEITEM, pMD->id);
  1035.                 free((pMD->Submenu)->PgmTitle);
  1036.                 free((pMD->Submenu)->PgmName);
  1037.                 free((pMD->Submenu)->PgmDirectory);
  1038.                 free((pMD->Submenu)->PgmInputs);
  1039.                 free(pMD->Submenu);
  1040.                 if(((pMD->Back)->Submenu==pMD) && (pMD->Next==NULL))
  1041.                     {                   /* If the previous item is a Submenu, this item is
  1042.                                            the first item of it. If none item follows, set
  1043.                                            this item to empty */
  1044.                     strcpy(pU=malloc(strlen("")+1), "");
  1045.                     pMD->PgmTitle=pU;
  1046.                     free(pMD->PgmName);
  1047.                     strcpy(pU=malloc(strlen("")+1), "");
  1048.                     pMD->PgmName=pU;
  1049.                     free(pMD->PgmDirectory);
  1050.                     strcpy(pU=malloc(strlen("")+1), "");
  1051.                     pMD->PgmDirectory=pU;
  1052.                     free(pMD->PgmInputs);
  1053.                     strcpy(pU=malloc(strlen("")+1), "");
  1054.                     pMD->Item=ENTRYEMPTY;
  1055.                     pMD->Submenu=NULL;
  1056.                     pMD->Next=NULL;
  1057.                     }
  1058.                 if(((pMD->Back)->Submenu==pMD) && (pMD->Next!=NULL))
  1059.                     {                   /* If the previous item is a Submenu, this item ist
  1060.                                            the first item of it. If one item follows adjust
  1061.                                            the pointer to the current level of items */
  1062.                     pMenuData=pMD->Next;
  1063.                     (pMD->Back)->Submenu=pMD->Next;
  1064.                     if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back;
  1065.                     free(pMD->PgmTitle);
  1066.                     free(pMD->PgmName);
  1067.                     free(pMD->PgmDirectory);
  1068.                     free(pMD->PgmInputs);
  1069.                     free(pMD);
  1070.                     }
  1071.                 if((pMD->Back)->Submenu!=pMD)
  1072.                     {                   /* If this item isn't the first item of a Submenu */
  1073.                     (pMD->Back)->Next=pMD->Next;
  1074.                     if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back;
  1075.                     free(pMD->PgmTitle);
  1076.                     free(pMD->PgmName);
  1077.                     free(pMD->PgmDirectory);
  1078.                     free(pMD->PgmInputs);
  1079.                     free(pMD);
  1080.                     }
  1081.                 }
  1082.             if(pMD->Item==ENTRYMENUITEM)
  1083.                 {                       /* If it is a Menuitem, just remove it completly */
  1084.                                         /* Remove the item from the Popup-Menu */
  1085.                 SetPopupMenu(pMD, MM_DELETEITEM, pMD->id);
  1086.                 if(((pMD->Back)->Submenu==pMD) && (pMD->Next==NULL))
  1087.                     {                   /* If the previous item is a Submenu, this item is
  1088.                                            the first item of it. If none item follows, set
  1089.                                            this item to empty */
  1090.                     strcpy(pU=malloc(strlen("")+1), "");
  1091.                     pMD->PgmTitle=pU;
  1092.                     free(pMD->PgmName);
  1093.                     strcpy(pU=malloc(strlen("")+1), "");
  1094.                     pMD->PgmName=pU;
  1095.                     free(pMD->PgmDirectory);
  1096.                     strcpy(pU=malloc(strlen("")+1), "");
  1097.                     pMD->PgmDirectory=pU;
  1098.                     free(pMD->PgmInputs);
  1099.                     strcpy(pU=malloc(strlen("")+1), "");
  1100.                     pMD->Item=ENTRYEMPTY;
  1101.                     pMD->Submenu=NULL;
  1102.                     pMD->Next=NULL;
  1103.                     }
  1104.                 if(((pMD->Back)->Submenu==pMD) && (pMD->Next!=NULL))
  1105.                     {                   /* If the previous item is a Submenu, this item ist
  1106.                                            the first item of it. If one item follows adjust
  1107.                                            the pointer to the current level of items */
  1108.                     pMenuData=pMD->Next;
  1109.                     (pMD->Back)->Submenu=pMD->Next;
  1110.                     if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back;
  1111.                     free(pMD->PgmTitle);
  1112.                     free(pMD->PgmName);
  1113.                     free(pMD->PgmDirectory);
  1114.                     free(pMD->PgmInputs);
  1115.                     free(pMD);
  1116.                     }
  1117.                 if((pMD->Back)->Submenu!=pMD)
  1118.                     {                   /* If this item isn't the first item of a Submenu */
  1119.                     (pMD->Back)->Next=pMD->Next;
  1120.                     if(pMD->Next!=NULL) (pMD->Next)->Back=pMD->Back;
  1121.                     free(pMD->PgmTitle);
  1122.                     free(pMD->PgmName);
  1123.                     free(pMD->PgmDirectory);
  1124.                     free(pMD->PgmInputs);
  1125.                     free(pMD);
  1126.                     }
  1127.                 }
  1128.             }
  1129.                                         /* Initialize the listbox */
  1130.         WinSendMsg(hwndDlg, WM_LOADPOPUPMENU, MPFROMP(pMenuData), NULL);
  1131.         return((MRESULT)FALSE);         /* We have done everything */
  1132.         }
  1133.         break;
  1134.  
  1135.     case DID_OK:                        /* Enter key pressed */
  1136.                                         /* Save the changes */
  1137.         WinSendMsg(hwndDlg, WM_SAVEPOPUPMENU, NULL, NULL);
  1138.         DialogResult=DID_OK;            /* Dialog terminated with DID_OK */
  1139.         break;
  1140.  
  1141.     case DID_CANCEL:                    /* Escape or Cancel pressed */
  1142.         DialogResult=DID_CANCEL;        /* Dialog terminated with DID_CANCEL */
  1143.         break;
  1144.  
  1145.     default:
  1146.         return(WinDefDlgProc(hwndDlg, msg, mp1, mp2));
  1147.     }
  1148.     WinDismissDlg(hwndDlg, TRUE);       /* Clear up dialog */
  1149.     break;
  1150.  
  1151. default:                                /* Default window procedure must be called */
  1152.     return(WinDefDlgProc(hwndDlg, msg, mp1, mp2));
  1153. }
  1154. return((MRESULT)FALSE);                 /* We have handled the message */
  1155. }
  1156.  
  1157.  
  1158.