home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / xwplascr.zip / XWPL0208.ZIP / src / startshut / shutdown.c < prev    next >
C/C++ Source or Header  |  2002-08-10  |  253KB  |  6,452 lines

  1.  
  2. /*
  3.  *@@sourcefile shutdwn.c:
  4.  *      this file contains all the XShutdown code, which
  5.  *      was in xfdesk.c before V0.84.
  6.  *
  7.  *      XShutdown is a (hopefully) complete rewrite of what
  8.  *      WinShutdownSystem does. This code is also used for
  9.  *      "Restart Desktop", since it does in part the same thing.
  10.  *
  11.  *      This file implements (in this order):
  12.  *
  13.  *      --  Shutdown dialogs. See xsdConfirmShutdown and
  14.  *          xsdConfirmRestartWPS.
  15.  *
  16.  *      --  Shutdown interface. See xsdInitiateShutdown,
  17.  *          xsdInitiateRestartWPS, and xsdInitiateShutdownExt.
  18.  *
  19.  *      --  Shutdown settings notebook pages. See xsdShutdownInitPage
  20.  *          and below.
  21.  *
  22.  *      --  The Shutdown thread itself, which does the grunt
  23.  *          work of shutting down the system, together with
  24.  *          the Update thread, which monitors the window list
  25.  *          while shutting down. See fntShutdownThread and
  26.  *          fntUpdateThread.
  27.  *
  28.  *      All the functions in this file have the xsd* prefix.
  29.  *
  30.  *@@header "startshut\shutdown.h"
  31.  */
  32.  
  33. /*
  34.  *      Copyright (C) 1997-2002 Ulrich Möller.
  35.  *      This file is part of the XWorkplace source package.
  36.  *      XWorkplace is free software; you can redistribute it and/or modify
  37.  *      it under the terms of the GNU General Public License as published
  38.  *      by the Free Software Foundation, in version 2 as it comes in the
  39.  *      "COPYING" file of the XWorkplace main distribution.
  40.  *      This program is distributed in the hope that it will be useful,
  41.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  42.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  43.  *      GNU General Public License for more details.
  44.  */
  45.  
  46. #pragma strings(readonly)
  47.  
  48. /*
  49.  *  Suggested #include order:
  50.  *  1)  os2.h
  51.  *  2)  C library headers
  52.  *  3)  setup.h (code generation and debugging options)
  53.  *  4)  headers in helpers\
  54.  *  5)  at least one SOM implementation header (*.ih)
  55.  *  6)  dlgids.h, headers in shared\ (as needed)
  56.  *  7)  headers in implementation dirs (e.g. filesys\, as needed)
  57.  *  8)  #pragma hdrstop and then more SOM headers which crash with precompiled headers
  58.  */
  59.  
  60. #define INCL_DOSPROCESS
  61. #define INCL_DOSSESMGR
  62. #define INCL_DOSSEMAPHORES
  63. #define INCL_DOSEXCEPTIONS
  64. #define INCL_DOSDEVICES
  65. #define INCL_DOSDEVIOCTL
  66. #define INCL_DOSERRORS
  67.  
  68. #define INCL_WINWINDOWMGR
  69. #define INCL_WINMESSAGEMGR
  70. #define INCL_WINFRAMEMGR
  71. #define INCL_WINDIALOGS
  72. #define INCL_WINPOINTERS
  73. #define INCL_WINSHELLDATA
  74. #define INCL_WINPROGRAMLIST
  75. #define INCL_WINSWITCHLIST
  76. #define INCL_WINCOUNTRY
  77. #define INCL_WINSYS
  78. #define INCL_WINMENUS
  79. #define INCL_WINSTATICS
  80. #define INCL_WINENTRYFIELDS
  81. #define INCL_WINBUTTONS
  82. #define INCL_WINLISTBOXES
  83. #include <os2.h>
  84.  
  85. // C library headers
  86. #include <stdio.h>              // needed for except.h
  87. #include <setjmp.h>             // needed for except.h
  88. #include <assert.h>             // needed for except.h
  89. #include <stdarg.h>
  90.  
  91. // generic headers
  92. #include "setup.h"                      // code generation and debugging options
  93.  
  94. // headers in /helpers
  95. #include "helpers\animate.h"            // icon and other animations
  96. #include "helpers\comctl.h"             // common controls (window procs)
  97. #include "helpers\dialog.h"             // dialog helpers
  98. #include "helpers\dosh.h"               // Control Program helper routines
  99. #include "helpers\except.h"             // exception handling
  100. #include "helpers\exeh.h"               // executable helpers
  101. #include "helpers\gpih.h"               // GPI helper routines
  102. #include "helpers\linklist.h"           // linked list helper routines
  103. #include "helpers\prfh.h"               // INI file helper routines
  104. #include "helpers\procstat.h"           // DosQProcStat handling
  105. #include "helpers\standards.h"          // some standard macros
  106. #include "helpers\threads.h"            // thread helpers
  107. #include "helpers\winh.h"               // PM helper routines
  108. #include "helpers\wphandle.h"           // file-system object handles
  109. #include "helpers\xprf.h"               // replacement profile (INI) functions
  110.  
  111. // SOM headers which don't crash with prec. header files
  112. #include "xfldr.ih"                     // needed for shutdown folder
  113.  
  114. // XWorkplace implementation headers
  115. #include "dlgids.h"                     // all the IDs that are shared with NLS
  116. #include "shared\common.h"              // the majestic XWorkplace include file
  117. #include "shared\helppanels.h"          // all XWorkplace help panel IDs
  118. #include "shared\kernel.h"              // XWorkplace Kernel
  119. #include "shared\notebook.h"            // generic XWorkplace notebook handling
  120. #include "xwpapi.h"                     // public XWorkplace definitions
  121.  
  122. // headers in /hook
  123. #include "hook\xwphook.h"
  124.  
  125. #include "filesys\fdrmenus.h"           // shared folder menu logic
  126. #include "filesys\object.h"             // XFldObject implementation
  127. #include "filesys\xthreads.h"           // extra XWorkplace threads
  128.  
  129. #include "media\media.h"                // XWorkplace multimedia support
  130.  
  131. #include "security\xwpsecty.h"          // XWorkplace Security base
  132. #include "shared\xsecapi.h"             // XWorkplace Security API
  133.  
  134. #include "startshut\apm.h"              // APM power-off for XShutdown
  135. #include "startshut\archives.h"         // archiving declarations
  136. #include "startshut\shutdown.h"         // XWorkplace eXtended Shutdown
  137.  
  138. // other SOM headers
  139. #pragma hdrstop
  140. #include <wpdesk.h>                     // WPDesktop; includes WPFolder also
  141. #include "shared\wpsh.h"                // some pseudo-SOM functions (WPS helper routines)
  142.  
  143. /* ******************************************************************
  144.  *
  145.  *   Global variables
  146.  *
  147.  ********************************************************************/
  148.  
  149. // shutdown animation
  150. static SHUTDOWNANIM     G_sdAnim;
  151.  
  152. static THREADINFO       G_tiShutdownThread = {0},
  153.                         G_tiUpdateThread = {0};
  154.  
  155. static ULONG            G_ulShutdownState = XSD_IDLE;
  156.                 // V0.9.19 (2002-04-24) [umoeller]
  157.                 // -- XSD_* flag signalling status
  158.  
  159. static BOOL             G_fConfirmWindowExtended = TRUE;
  160. static BOOL             G_fConfirmDialogReady = FALSE;
  161. static ULONG            G_ulConfirmHelpPanel = NULLHANDLE;
  162.  
  163. static PFNWP            G_pfnwpFrameOrig = NULL;
  164. static PXBITMAP         G_pbmDim = NULLHANDLE;
  165.  
  166. // forward declarations
  167. MRESULT EXPENTRY fnwpShutdownThread(HWND hwndFrame, ULONG msg, MPARAM mp1, MPARAM mp2);
  168. void _Optlink fntUpdateThread(PTHREADINFO pti);
  169.  
  170. /* ******************************************************************
  171.  *
  172.  *   XShutdown dialogs
  173.  *
  174.  ********************************************************************/
  175.  
  176. /*
  177.  *@@ ReformatConfirmWindow:
  178.  *      depending on fExtended, the shutdown confirmation
  179.  *      dialog is extended to show the "reboot to" listbox
  180.  *      or not.
  181.  *
  182.  *@@added V0.9.0 [umoeller]
  183.  *@@changed V0.9.1 (2000-01-20) [umoeller]: reformat wasn't working right; fixed.
  184.  */
  185.  
  186. static VOID ReformatConfirmWindow(HWND hwndDlg,        // in: confirmation dlg window
  187.                                   BOOL fExtended)      // in: if TRUE, the list box will be shown
  188. {
  189.     // _Pmpf(("ReformatConfirmWindow: %d, ready: %d", fExtended, G_fConfirmDialogReady));
  190.  
  191.     if (G_fConfirmDialogReady)
  192.         if (fExtended != G_fConfirmWindowExtended)
  193.         {
  194.             HWND    hwndBootMgrListbox = WinWindowFromID(hwndDlg, ID_SDDI_BOOTMGR);
  195.             SWP     swpBootMgrListbox;
  196.             SWP     swpDlg;
  197.  
  198.             WinQueryWindowPos(hwndBootMgrListbox, &swpBootMgrListbox);
  199.             WinQueryWindowPos(hwndDlg, &swpDlg);
  200.  
  201.             if (fExtended)
  202.                 swpDlg.cx += swpBootMgrListbox.cx;
  203.             else
  204.                 swpDlg.cx -= swpBootMgrListbox.cx;
  205.  
  206.             WinShowWindow(hwndBootMgrListbox, fExtended);
  207.             WinSetWindowPos(hwndDlg,
  208.                             NULLHANDLE,
  209.                             0, 0,
  210.                             swpDlg.cx, swpDlg.cy,
  211.                             SWP_SIZE);
  212.  
  213.             G_fConfirmWindowExtended = fExtended;
  214.         }
  215. }
  216.  
  217. /*
  218.  * fnwpConfirm:
  219.  *      dlg proc for XShutdown confirmation windows.
  220.  *
  221.  *@@changed V0.9.0 [umoeller]: redesigned the whole confirmation window.
  222.  *@@changed V0.9.1 (2000-01-20) [umoeller]: reformat wasn't working right; fixed.
  223.  */
  224.  
  225. static MRESULT EXPENTRY fnwpConfirm(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
  226. {
  227.     MRESULT mrc = MPNULL;
  228.     switch (msg)
  229.     {
  230.         case WM_CONTROL:
  231.             /* _Pmpf(("WM_CONTROL %d: fConfirmWindowExtended: %d",
  232.                     SHORT1FROMMP(mp1), fConfirmWindowExtended)); */
  233.  
  234.             if (    (SHORT2FROMMP(mp1) == BN_CLICKED)
  235.                  || (SHORT2FROMMP(mp1) == BN_DBLCLICKED)
  236.                )
  237.                 switch (SHORT1FROMMP(mp1)) // usItemID
  238.                 {
  239.                     case ID_SDDI_SHUTDOWNONLY:
  240.                     case ID_SDDI_STANDARDREBOOT:
  241.                         ReformatConfirmWindow(hwndDlg, FALSE);
  242.                     break;
  243.  
  244.                     case ID_SDDI_REBOOTTO:
  245.                         ReformatConfirmWindow(hwndDlg, TRUE);
  246.                     break;
  247.                 }
  248.  
  249.             mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  250.         break;
  251.  
  252.         case WM_HELP:
  253.             cmnDisplayHelp(NULL,
  254.                            G_ulConfirmHelpPanel);
  255.         break;
  256.  
  257.         default:
  258.             mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  259.     }
  260.     return mrc;
  261. }
  262.  
  263. /*
  264.  *@@ fnwpDimScreen:
  265.  *
  266.  *@@added V0.9.16 (2002-01-04) [umoeller]
  267.  */
  268.  
  269. static MRESULT EXPENTRY fnwpDimScreen(HWND hwndFrame, ULONG msg, MPARAM mp1, MPARAM mp2)
  270. {
  271.     MRESULT mrc = 0;
  272.  
  273.     switch (msg)
  274.     {
  275.         case WM_PAINT:
  276.         {
  277.             HPS hps = WinBeginPaint(hwndFrame, NULLHANDLE, NULL);
  278.             POINTL ptl = {0,0};
  279.             if (G_pbmDim)
  280.                 WinDrawBitmap(hps,
  281.                               G_pbmDim->hbm,
  282.                               NULL,
  283.                               &ptl,
  284.                               0,
  285.                               0,
  286.                               DBM_NORMAL); // DBM_HALFTONE);
  287.             WinEndPaint(hps);
  288.         }
  289.         break;
  290.  
  291.         case WM_DESTROY:
  292.             gpihDestroyXBitmap(&G_pbmDim);
  293.             mrc = G_pfnwpFrameOrig(hwndFrame, msg, mp1, mp2);
  294.         break;
  295.  
  296.         default:
  297.             mrc = G_pfnwpFrameOrig(hwndFrame, msg, mp1, mp2);
  298.     }
  299.  
  300.     return mrc;
  301. }
  302.  
  303. /*
  304.  *@@ CreateDimScreenWindow:
  305.  *
  306.  *@@added V0.9.16 (2002-01-04) [umoeller]
  307.  */
  308.  
  309. static HWND CreateDimScreenWindow(VOID)
  310. {
  311.     HWND hwnd;
  312.  
  313.     FRAMECDATA  fcdata;
  314.  
  315.     HPS hpsScreen;
  316.     RECTL rcl;
  317.     HAB hab = winhMyAnchorBlock();      // expensive, but what the heck
  318.  
  319.     // before capturing the screen, sleep a millisecond,
  320.     // because otherwise windows are not fully repainted
  321.     // if the desktop menu was open, and we get that
  322.     // into the screenshot then... so give the windows
  323.     // time to repaint
  324.     winhSleep(10);
  325.  
  326.     // go capture screen
  327.     hpsScreen = WinGetScreenPS(HWND_DESKTOP);
  328.     rcl.xLeft = 0;
  329.     rcl.yBottom = 0;
  330.     rcl.xRight = winhQueryScreenCX();
  331.     rcl.yTop = winhQueryScreenCY();
  332.     if (G_pbmDim = gpihCreateBmpFromPS(hab,
  333.                                        hpsScreen,
  334.                                        &rcl))
  335.     {
  336.         POINTL  ptl = {0, 0};
  337.         GpiMove(G_pbmDim->hpsMem, &ptl);  // still 0, 0
  338.         ptl.x = rcl.xRight - 1;
  339.         ptl.y = rcl.yTop - 1;
  340.         GpiSetColor(G_pbmDim->hpsMem, RGBCOL_BLACK);
  341.         GpiSetPattern(G_pbmDim->hpsMem, PATSYM_HALFTONE);
  342.         GpiBox(G_pbmDim->hpsMem,
  343.                DRO_FILL, // interior only
  344.                &ptl,
  345.                0, 0);    // no corner rounding
  346.     }
  347.     WinReleasePS(hpsScreen);
  348.  
  349.     fcdata.cb            = sizeof(FRAMECDATA);
  350.     fcdata.flCreateFlags = FCF_NOBYTEALIGN;
  351.     fcdata.hmodResources = NULLHANDLE;
  352.     fcdata.idResources   = 0;
  353.  
  354.     hwnd = WinCreateWindow(HWND_DESKTOP,
  355.                            WC_FRAME,
  356.                            "",
  357.                            0,       // flags
  358.                            0,
  359.                            0,
  360.                            winhQueryScreenCX(),
  361.                            winhQueryScreenCY(),
  362.                            NULLHANDLE,
  363.                            HWND_TOP,
  364.                            0,
  365.                            &fcdata,
  366.                            NULL);
  367.  
  368.     G_pfnwpFrameOrig = WinSubclassWindow(hwnd, fnwpDimScreen);
  369.  
  370.     WinShowWindow(hwnd, TRUE);
  371.  
  372.     // WinSetSysModalWindow(HWND_DESKTOP, hwnd);
  373.         // sysmodal isn't good or the help button
  374.         // in the dialog can't bring up the help panel
  375.         // V0.9.19 (2002-04-24) [umoeller]
  376.  
  377.     return (hwnd);
  378. }
  379.  
  380. /*
  381.  *@@ xsdConfirmShutdown:
  382.  *      this displays the eXtended Shutdown (not Restart Desktop)
  383.  *      confirmation box. Returns MBID_YES/NO.
  384.  *
  385.  *@@changed V0.9.0 [umoeller]: redesigned the whole confirmation window.
  386.  *@@changed V0.9.1 (2000-01-20) [umoeller]: reformat wasn't working right; fixed.
  387.  *@@changed V0.9.1 (2000-01-30) [umoeller]: added exception handling.
  388.  *@@changed V0.9.4 (2000-08-03) [umoeller]: added "empty trash can"
  389.  *@@changed V0.9.7 (2000-12-13) [umoeller]: global settings weren't unlocked, fixed
  390.  */
  391.  
  392. ULONG xsdConfirmShutdown(PSHUTDOWNPARAMS psdParms)
  393. {
  394.     ULONG       ulReturn = MBID_NO;
  395.     BOOL        fStore = FALSE;
  396.     HWND        hwndConfirm = NULLHANDLE,
  397.                 hwndDim;
  398.  
  399.     TRY_LOUD(excpt1)
  400.     {
  401.         HMODULE     hmodResource = cmnQueryNLSModuleHandle(FALSE);
  402.         ULONG       ulKeyLength;
  403.         PSZ         p = NULL,
  404.                     pINI = NULL;
  405.         ULONG       ulCheckRadioButtonID = ID_SDDI_SHUTDOWNONLY;
  406.  
  407.         HPOINTER    hptrShutdown = WinLoadPointer(HWND_DESKTOP, hmodResource,
  408.                                                   ID_SDICON);
  409.  
  410.         hwndDim = CreateDimScreenWindow();
  411.  
  412.         G_fConfirmWindowExtended = TRUE;
  413.         G_fConfirmDialogReady = FALSE;
  414.         G_ulConfirmHelpPanel = ID_XSH_XSHUTDOWN_CONFIRM;
  415.         hwndConfirm = cmnLoadDlg(hwndDim,
  416.                                  fnwpConfirm,
  417.                                  ID_SDD_CONFIRM,
  418.                                  NULL);
  419.  
  420.         WinPostMsg(hwndConfirm,
  421.                    WM_SETICON,
  422.                    (MPARAM)hptrShutdown,
  423.                    NULL);
  424.  
  425.         // set radio buttons
  426. #ifndef __NOXSHUTDOWN__
  427.         winhSetDlgItemChecked(hwndConfirm, ID_SDDI_MESSAGEAGAIN, psdParms->optConfirm);
  428. #endif
  429.  
  430.         if (cmnTrashCanReady())
  431.         {
  432.             if (psdParms->optEmptyTrashCan)
  433.                 winhSetDlgItemChecked(hwndConfirm, ID_SDDI_EMPTYTRASHCAN, TRUE);
  434.         }
  435.         else
  436.             // trash can not ready: disable item
  437.             WinEnableControl(hwndConfirm, ID_SDDI_EMPTYTRASHCAN, FALSE);
  438.  
  439.         if (psdParms->optReboot)
  440.             ulCheckRadioButtonID = ID_SDDI_STANDARDREBOOT;
  441.  
  442.         // insert ext reboot items into combo box;
  443.         // check for reboot items in OS2.INI
  444.         if (PrfQueryProfileSize(HINI_USER,
  445.                                 (PSZ)INIAPP_XWORKPLACE,
  446.                                 (PSZ)INIKEY_BOOTMGR,
  447.                                 &ulKeyLength))
  448.         {
  449.             // items exist: evaluate
  450.             if (pINI = malloc(ulKeyLength))
  451.             {
  452.                 PrfQueryProfileData(HINI_USER,
  453.                                     (PSZ)INIAPP_XWORKPLACE,
  454.                                     (PSZ)INIKEY_BOOTMGR,
  455.                                     pINI,
  456.                                     &ulKeyLength);
  457.                 p = pINI;
  458.                 while (strlen(p))
  459.                 {
  460.                     WinSendDlgItemMsg(hwndConfirm, ID_SDDI_BOOTMGR,
  461.                                       LM_INSERTITEM,
  462.                                       (MPARAM)LIT_END,
  463.                                       (MPARAM)p);
  464.                      // skip description string
  465.                     p += (strlen(p)+1);
  466.                     // skip reboot command
  467.                     p += (strlen(p)+1);
  468.                 }
  469.             }
  470.  
  471.             // select reboot item from last time
  472.             if (cmnQuerySetting(susLastRebootExt) != 0xFFFF)
  473.             {
  474.                 if (WinSendDlgItemMsg(hwndConfirm, ID_SDDI_BOOTMGR,
  475.                                       LM_SELECTITEM,
  476.                                       (MPARAM)cmnQuerySetting(susLastRebootExt), // item index
  477.                                       (MPARAM)TRUE) // select (not deselect)
  478.                             == (MRESULT)FALSE)
  479.                     // error:
  480.                     // check first item then
  481.                     WinSendDlgItemMsg(hwndConfirm, ID_SDDI_BOOTMGR,
  482.                                       LM_SELECTITEM,
  483.                                       (MPARAM)0,
  484.                                       (MPARAM)TRUE); // select (not deselect)
  485.  
  486.                 if (ulCheckRadioButtonID == ID_SDDI_STANDARDREBOOT)
  487.                     ulCheckRadioButtonID = ID_SDDI_REBOOTTO;
  488.             }
  489.         }
  490.         else
  491.             // no items found: disable
  492.             WinEnableControl(hwndConfirm, ID_SDDI_REBOOTTO, FALSE);
  493.  
  494.         // check radio button
  495.         winhSetDlgItemChecked(hwndConfirm, ulCheckRadioButtonID, TRUE);
  496.         winhSetDlgItemFocus(hwndConfirm, ulCheckRadioButtonID);
  497.  
  498.         // make window smaller if we don't have "reboot to"
  499.         G_fConfirmDialogReady = TRUE;       // flag for ReformatConfirmWindow
  500.         if (ulCheckRadioButtonID != ID_SDDI_REBOOTTO)
  501.             ReformatConfirmWindow(hwndConfirm, FALSE);
  502.  
  503.         cmnSetControlsFont(hwndConfirm, 1, 5000);
  504.         winhCenterWindow(hwndConfirm);      // still hidden
  505.  
  506.         xsdLoadAnimation(&G_sdAnim);
  507.         ctlPrepareAnimation(WinWindowFromID(hwndConfirm, ID_SDDI_ICON),
  508.                             XSD_ANIM_COUNT,
  509.                             &(G_sdAnim.ahptr[0]),
  510.                             150,    // delay
  511.                             TRUE);  // start now
  512.  
  513.         // go!!
  514.         ulReturn = WinProcessDlg(hwndConfirm);
  515.  
  516.         ctlStopAnimation(WinWindowFromID(hwndConfirm, ID_SDDI_ICON));
  517.         xsdFreeAnimation(&G_sdAnim);
  518.  
  519.         if (ulReturn == DID_OK)
  520.         {
  521. #ifndef __NOXSHUTDOWN__
  522.             ULONG flShutdown = cmnQuerySetting(sflXShutdown);
  523.  
  524.             // check "show this msg again"
  525.             if (!(winhIsDlgItemChecked(hwndConfirm, ID_SDDI_MESSAGEAGAIN)))
  526.                 flShutdown |= XSD_NOCONFIRM;
  527. #endif
  528.  
  529.             // check empty trash
  530.             psdParms->optEmptyTrashCan
  531.                 = (winhIsDlgItemChecked(hwndConfirm, ID_SDDI_EMPTYTRASHCAN) != 0);
  532.  
  533.             // check reboot options
  534.             psdParms->optReboot = FALSE;
  535.             if (winhIsDlgItemChecked(hwndConfirm, ID_SDDI_REBOOTTO))
  536.             {
  537.                 USHORT usSelected = (USHORT)WinSendDlgItemMsg(hwndConfirm, ID_SDDI_BOOTMGR,
  538.                                                               LM_QUERYSELECTION,
  539.                                                               (MPARAM)LIT_CURSOR,
  540.                                                               MPNULL);
  541.                 USHORT us;
  542.                 psdParms->optReboot = TRUE;
  543.  
  544.                 p = pINI;
  545.                 for (us = 0; us < usSelected; us++)
  546.                 {
  547.                     // skip description string
  548.                     p += (strlen(p)+1);
  549.                     // skip reboot command
  550.                     p += (strlen(p)+1);
  551.                 }
  552.                 // skip description string to get to reboot command
  553.                 p += (strlen(p)+1);
  554.                 strcpy(psdParms->szRebootCommand, p);
  555.  
  556. #ifndef __NOXSHUTDOWN__
  557.                 flShutdown |= XSD_REBOOT;
  558. #endif
  559.                 cmnSetSetting(susLastRebootExt, usSelected);
  560.             }
  561.             else if (winhIsDlgItemChecked(hwndConfirm, ID_SDDI_STANDARDREBOOT))
  562.             {
  563.                 psdParms->optReboot = TRUE;
  564.                 // szRebootCommand is a zero-byte only, which will lead to
  565.                 // the standard reboot in the Shutdown thread
  566. #ifndef __NOXSHUTDOWN__
  567.                 flShutdown |= XSD_REBOOT;
  568. #endif
  569.                 cmnSetSetting(susLastRebootExt, 0xFFFF);
  570.             }
  571. #ifndef __NOXSHUTDOWN__
  572.             else
  573.                 // standard shutdown:
  574.                 flShutdown &= ~XSD_REBOOT;
  575. #endif
  576.  
  577. #ifndef __NOXSHUTDOWN__
  578.             cmnSetSetting(sflXShutdown, flShutdown);
  579. #endif
  580.         }
  581.  
  582.         if (pINI)
  583.             free(pINI);
  584.     }
  585.     CATCH(excpt1)
  586.     {
  587.     } END_CATCH();
  588.  
  589.     if (hwndConfirm)
  590.         WinDestroyWindow(hwndConfirm);
  591.     WinDestroyWindow(hwndDim);
  592.  
  593.  
  594.     return (ulReturn);
  595. }
  596.  
  597. static CONTROLDEF
  598.     TrafficLightIcon = CONTROLDEF_ICON(0, ID_SDDI_ICON),
  599.     ConfirmText = CONTROLDEF_TEXT_WORDBREAK(
  600.                             LOAD_STRING,
  601.                             ID_SDDI_CONFIRM_TEXT,
  602.                             100),
  603.     CloseAllSessionsCB = LOADDEF_AUTOCHECKBOX(ID_SDDI_WPS_CLOSEWINDOWS),
  604. #ifndef __NOXWPSTARTUP__
  605.     StartupFoldersCB = LOADDEF_AUTOCHECKBOX(ID_SDDI_WPS_STARTUPFOLDER),
  606. #endif
  607.     ArchiveOnceCB = LOADDEF_AUTOCHECKBOX(ID_SDDI_ARCHIVEONCE),
  608. #ifndef __NOXSHUTDOWN__
  609.     MessageAgainCB = LOADDEF_AUTOCHECKBOX(ID_SDDI_MESSAGEAGAIN),
  610. #endif
  611.     OKButton = CONTROLDEF_DEFPUSHBUTTON(
  612.                             0,
  613.                             DID_OK,
  614.                             STD_BUTTON_WIDTH,
  615.                             STD_BUTTON_HEIGHT),
  616.     CancelButton = CONTROLDEF_PUSHBUTTON(
  617.                             0,
  618.                             DID_CANCEL,
  619.                             STD_BUTTON_WIDTH,
  620.                             STD_BUTTON_HEIGHT),
  621.     HelpButton = CONTROLDEF_HELPPUSHBUTTON(
  622.                             LOAD_STRING,
  623.                             DID_HELP,
  624.                             STD_BUTTON_WIDTH,
  625.                             STD_BUTTON_HEIGHT);
  626.  
  627. static const DLGHITEM dlgConfirmRestartDesktop[] =
  628.     {
  629.         START_TABLE,            // root table, required
  630.             START_ROW(0),
  631.                 START_TABLE,            // root table, required
  632.                     START_ROW(ROW_VALIGN_CENTER),       // shared settings group
  633.                         CONTROL_DEF(&TrafficLightIcon),
  634.                         CONTROL_DEF(&ConfirmText),
  635.                 END_TABLE,
  636.             START_ROW(0),
  637.                 CONTROL_DEF(&CloseAllSessionsCB),
  638. #ifndef __NOXWPSTARTUP__
  639.             START_ROW(0),
  640.                 CONTROL_DEF(&StartupFoldersCB),
  641. #endif
  642.             START_ROW(0),
  643.                 CONTROL_DEF(&ArchiveOnceCB),
  644. #ifndef __NOXSHUTDOWN__
  645.             START_ROW(0),
  646.                 CONTROL_DEF(&MessageAgainCB),
  647. #endif
  648.             START_ROW(ROW_VALIGN_CENTER),
  649.                 CONTROL_DEF(&OKButton),
  650.                 CONTROL_DEF(&CancelButton),
  651.                 CONTROL_DEF(&HelpButton),
  652.         END_TABLE
  653.     };
  654.  
  655. /*
  656.  *@@ xsdConfirmRestartWPS:
  657.  *      this displays the "Restart Desktop"
  658.  *      confirmation box. Returns MBID_OK/CANCEL.
  659.  *
  660.  *@@changed V0.9.5 (2000-08-10) [umoeller]: added XWPSHELL.EXE interface
  661.  *@@changed V0.9.16 (2002-01-13) [umoeller]: rewritten to use dialog formatter
  662.  *@@changed V0.9.19 (2002-04-18) [umoeller]: added "archive once" feature
  663.  *@@changed V0.9.19 (2002-04-18) [umoeller]: added a decent help panel, finally
  664.  */
  665.  
  666. ULONG xsdConfirmRestartWPS(PSHUTDOWNPARAMS psdParms)
  667. {
  668.     ULONG       ulReturn = MBID_CANCEL;
  669.     HWND        hwndConfirm;
  670.     HMODULE     hmodResource = cmnQueryNLSModuleHandle(FALSE);
  671.  
  672.     HPOINTER    hptrShutdown = WinLoadPointer(HWND_DESKTOP,
  673.                                               hmodResource,
  674.                                               ID_SDICON);
  675.  
  676.     HWND        hwndDim = CreateDimScreenWindow();
  677.  
  678.     PDLGHITEM   paNew;
  679.  
  680.     G_ulConfirmHelpPanel = ID_XSH_RESTARTWPS_CONFIRM; // ID_XMH_RESTARTWPS;
  681.                                     // changed V0.9.19 (2002-04-18) [umoeller]
  682.  
  683.     if (!cmnLoadDialogStrings(dlgConfirmRestartDesktop,
  684.                               ARRAYITEMCOUNT(dlgConfirmRestartDesktop),
  685.                               &paNew))
  686.     {
  687.         OKButton.pcszText = cmnGetString(DID_OK);
  688.         CancelButton.pcszText = cmnGetString(DID_CANCEL);
  689.  
  690.         if (!dlghCreateDlg(&hwndConfirm,
  691.                            hwndDim,
  692.                            FCF_FIXED_DLG,
  693.                            fnwpConfirm,
  694.                            cmnGetString(ID_SDDI_CONFIRMWPS_TITLE),
  695.                            paNew,
  696.                            ARRAYITEMCOUNT(dlgConfirmRestartDesktop),
  697.                            NULL,
  698.                            cmnQueryDefaultFont()))
  699.         {
  700.             WinSendMsg(hwndConfirm,
  701.                        WM_SETICON,
  702.                        (MPARAM)hptrShutdown,
  703.                        NULL);
  704.  
  705.             // if (psdParms->ulRestartWPS == 2)
  706.             if (psdParms->ulCloseMode == SHUT_LOGOFF)
  707.             {
  708.                 // logoff:
  709.                 psdParms->optWPSCloseWindows = TRUE;
  710.                 psdParms->optWPSReuseStartupFolder = TRUE;
  711.                 WinEnableControl(hwndConfirm, ID_SDDI_WPS_CLOSEWINDOWS, FALSE);
  712.     #ifndef __NOXSHUTDOWN__
  713.                 WinEnableControl(hwndConfirm, ID_SDDI_WPS_STARTUPFOLDER, FALSE);
  714.     #endif
  715.                 // replace confirmation text
  716.                 WinSetDlgItemText(hwndConfirm, ID_SDDI_CONFIRM_TEXT,
  717.                                   cmnGetString(ID_XSSI_XSD_CONFIRMLOGOFFMSG)) ; // pszXSDConfirmLogoffMsg
  718.             }
  719.  
  720.             winhSetDlgItemChecked(hwndConfirm, ID_SDDI_WPS_CLOSEWINDOWS, psdParms->optWPSCloseWindows);
  721.     #ifndef __NOXWPSTARTUP__
  722.             winhSetDlgItemChecked(hwndConfirm, ID_SDDI_WPS_STARTUPFOLDER, psdParms->optWPSCloseWindows);
  723.     #endif
  724.     #ifndef __NOXSHUTDOWN__
  725.             winhSetDlgItemChecked(hwndConfirm, ID_SDDI_MESSAGEAGAIN, psdParms->optConfirm);
  726.     #endif
  727.  
  728.             xsdLoadAnimation(&G_sdAnim);
  729.             ctlPrepareAnimation(WinWindowFromID(hwndConfirm, ID_SDDI_ICON),
  730.                                 XSD_ANIM_COUNT,
  731.                                 G_sdAnim.ahptr,
  732.                                 150,    // delay
  733.                                 TRUE);  // start now
  734.  
  735.             winhCenterWindow(hwndConfirm);      // still hidden
  736.             WinShowWindow(hwndConfirm, TRUE);
  737.  
  738.             // *** go!
  739.             ulReturn = WinProcessDlg(hwndConfirm);
  740.  
  741.             ctlStopAnimation(WinWindowFromID(hwndConfirm, ID_SDDI_ICON));
  742.             xsdFreeAnimation(&G_sdAnim);
  743.  
  744.             if (ulReturn == DID_OK)
  745.             {
  746.     #ifndef __NOXSHUTDOWN__
  747.                 ULONG fl = cmnQuerySetting(sflXShutdown);
  748.     #endif
  749.  
  750.                 psdParms->optWPSCloseWindows = winhIsDlgItemChecked(hwndConfirm,
  751.                                                                     ID_SDDI_WPS_CLOSEWINDOWS);
  752.                 // if (psdParms->ulRestartWPS != 2)
  753.                 if (psdParms->ulCloseMode != SHUT_LOGOFF)
  754.                 {
  755.                     // regular restart Desktop:
  756.                     // save close windows/startup folder settings
  757.     #ifndef __NOXSHUTDOWN__
  758.                     if (psdParms->optWPSCloseWindows)
  759.                         fl |= XSD_WPS_CLOSEWINDOWS;
  760.                     else
  761.                         fl &= ~XSD_WPS_CLOSEWINDOWS;
  762.     #endif
  763.     #ifndef __NOXWPSTARTUP__
  764.                     psdParms->optWPSReuseStartupFolder = winhIsDlgItemChecked(hwndConfirm,
  765.                                                                               ID_SDDI_WPS_STARTUPFOLDER);
  766.     #endif
  767.                 }
  768.     #ifndef __NOXSHUTDOWN__
  769.                 if (!(winhIsDlgItemChecked(hwndConfirm,
  770.                                            ID_SDDI_MESSAGEAGAIN)))
  771.                     fl |= XSD_NOCONFIRM;
  772.  
  773.                 cmnSetSetting(sflXShutdown, fl);
  774.     #endif
  775.  
  776.                 // V0.9.19 (2002-04-17) [umoeller]
  777.                 if (winhIsDlgItemChecked(hwndConfirm,
  778.                                          ID_SDDI_ARCHIVEONCE))
  779.                 {
  780.                     PARCHIVINGSETTINGS pArcSettings = arcQuerySettings();
  781.                     pArcSettings->ulArcFlags |= ARCF_NEXT;
  782.                     arcSaveSettings();
  783.                 }
  784.             }
  785.  
  786.             WinDestroyWindow(hwndConfirm);
  787.         }
  788.  
  789.         free(paNew);
  790.     }
  791.  
  792.     WinDestroyWindow(hwndDim);
  793.  
  794.     return (ulReturn);
  795. }
  796.  
  797. /*
  798.  *@@ xsdLoadAutoCloseItems:
  799.  *      this gets the list of VIO windows which
  800.  *      are to be closed automatically from OS2.INI
  801.  *      and appends AUTOCLOSELISTITEM's to the given
  802.  *      list accordingly.
  803.  *
  804.  *      If hwndListbox != NULLHANDLE, the program
  805.  *      titles are added to that listbox as well.
  806.  *
  807.  *      Returns the no. of items which were added.
  808.  *
  809.  *@@added V0.9.1 (99-12-10) [umoeller]
  810.  */
  811.  
  812. USHORT xsdLoadAutoCloseItems(PLINKLIST pllItems,   // in: list of AUTOCLOSELISTITEM's to append to
  813.                              HWND hwndListbox)     // in: listbox to add items to or NULLHANDLE if none
  814. {
  815.     USHORT      usItemCount = 0;
  816.     ULONG       ulKeyLength;
  817.     PSZ         p, pINI;
  818.  
  819.     // get existing items from INI
  820.     if (PrfQueryProfileSize(HINI_USER,
  821.                             (PSZ)INIAPP_XWORKPLACE,
  822.                             (PSZ)INIKEY_AUTOCLOSE,
  823.                             &ulKeyLength))
  824.     {
  825.         // printf("Size: %d\n", ulKeyLength);
  826.         // items exist: evaluate
  827.         pINI = malloc(ulKeyLength);
  828.         if (pINI)
  829.         {
  830.             PrfQueryProfileData(HINI_USER,
  831.                                 (PSZ)INIAPP_XWORKPLACE,
  832.                                 (PSZ)INIKEY_AUTOCLOSE,
  833.                                 pINI,
  834.                                 &ulKeyLength);
  835.             p = pINI;
  836.             //printf("%s\n", p);
  837.             while (strlen(p))
  838.             {
  839.                 PAUTOCLOSELISTITEM pliNew = malloc(sizeof(AUTOCLOSELISTITEM));
  840.                 strcpy(pliNew->szItemName, p);
  841.                 lstAppendItem(pllItems, // pData->pllAutoClose,
  842.                               pliNew);
  843.  
  844.                 if (hwndListbox)
  845.                     WinSendMsg(hwndListbox,
  846.                                LM_INSERTITEM,
  847.                                (MPARAM)LIT_END,
  848.                                (MPARAM)p);
  849.  
  850.                 p += (strlen(p)+1);
  851.  
  852.                 if (strlen(p))
  853.                 {
  854.                     pliNew->usAction = *((PUSHORT)p);
  855.                     p += sizeof(USHORT);
  856.                 }
  857.  
  858.                 usItemCount++;
  859.             }
  860.             free(pINI);
  861.         }
  862.     }
  863.  
  864.     return (usItemCount);
  865. }
  866.  
  867. /*
  868.  *@@ xsdWriteAutoCloseItems:
  869.  *      reverse to xsdLoadAutoCloseItems, this writes the
  870.  *      auto-close items back to OS2.INI.
  871.  *
  872.  *      This returns 0 only if no error occured. If something
  873.  *      != 0 is returned, that's the index of the list item
  874.  *      which was found to be invalid.
  875.  *
  876.  *@@added V0.9.1 (99-12-10) [umoeller]
  877.  */
  878.  
  879. USHORT xsdWriteAutoCloseItems(PLINKLIST pllItems)
  880. {
  881.     USHORT  usInvalid = 0;
  882.     PSZ     pINI, p;
  883.     // BOOL    fValid = TRUE;
  884.     ULONG   ulItemCount = lstCountItems(pllItems);
  885.  
  886.     // store data in INI
  887.     if (ulItemCount)
  888.     {
  889.         pINI = malloc(
  890.                     sizeof(AUTOCLOSELISTITEM)
  891.                   * ulItemCount);
  892.         memset(pINI, 0,
  893.                     sizeof(AUTOCLOSELISTITEM)
  894.                   * ulItemCount);
  895.         if (pINI)
  896.         {
  897.             PLISTNODE pNode = lstQueryFirstNode(pllItems);
  898.             USHORT          usCurrent = 0;
  899.             p = pINI;
  900.             while (pNode)
  901.             {
  902.                 PAUTOCLOSELISTITEM pli = pNode->pItemData;
  903.                 if (strlen(pli->szItemName) == 0)
  904.                 {
  905.                     usInvalid = usCurrent;
  906.                     break;
  907.                 }
  908.  
  909.                 strcpy(p, pli->szItemName);
  910.                 p += (strlen(p)+1);
  911.                 *((PUSHORT)p) = pli->usAction;
  912.                 p += sizeof(USHORT);
  913.  
  914.                 pNode = pNode->pNext;
  915.                 usCurrent++;
  916.             }
  917.  
  918.             PrfWriteProfileData(HINI_USER,
  919.                                 (PSZ)INIAPP_XWORKPLACE,
  920.                                 (PSZ)INIKEY_AUTOCLOSE,
  921.                                 pINI,
  922.                                 (p - pINI + 2));
  923.  
  924.             free (pINI);
  925.         }
  926.     } // end if (pData->pliAutoClose)
  927.     else
  928.         // no items: delete INI key
  929.         PrfWriteProfileData(HINI_USER,
  930.                             (PSZ)INIAPP_XWORKPLACE,
  931.                             (PSZ)INIKEY_AUTOCLOSE,
  932.                             NULL, 0);
  933.  
  934.     return (usInvalid);
  935. }
  936.  
  937. /*
  938.  *@@ fnwpAutoCloseDetails:
  939.  *      dlg func for "Auto-Close Details".
  940.  *      This gets called from the notebook callbacks
  941.  *      for the "XDesktop" notebook page
  942.  *      (fncbDesktop1ItemChanged, xfdesk.c).
  943.  *
  944.  *@@changed V0.9.0 [umoeller]: adjusted for new linklist.c functions
  945.  *@@changed V0.9.19 (2002-05-23) [umoeller]: removed Ctrl+C option, which never worked
  946.  *@@changed V0.9.19 (2002-05-23) [umoeller]: now using dialog formatter
  947.  */
  948.  
  949. MRESULT EXPENTRY fnwpAutoCloseDetails(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
  950. {
  951.     MRESULT mrc = (MPARAM)NULL;
  952.  
  953.     PAUTOCLOSEWINDATA pData = (PAUTOCLOSEWINDATA)WinQueryWindowPtr(hwndDlg, QWL_USER);
  954.  
  955.     switch (msg)
  956.     {
  957.         case WM_INITDLG:
  958.         {
  959.             // create window data in QWL_USER
  960.             pData = malloc(sizeof(AUTOCLOSEWINDATA));
  961.             memset(pData, 0, sizeof(AUTOCLOSEWINDATA));
  962.             pData->pllAutoClose = lstCreate(TRUE);  // auto-free items
  963.  
  964.             // set animation
  965.             xsdLoadAnimation(&G_sdAnim);
  966.             ctlPrepareAnimation(WinWindowFromID(hwndDlg,
  967.                                                 ID_SDDI_ICON),
  968.                                 XSD_ANIM_COUNT,
  969.                                 &(G_sdAnim.ahptr[0]),
  970.                                 150,    // delay
  971.                                 TRUE);  // start now
  972.  
  973.             pData->usItemCount = 0;
  974.  
  975.             pData->usItemCount = xsdLoadAutoCloseItems(pData->pllAutoClose,
  976.                                                       WinWindowFromID(hwndDlg,
  977.                                                                       ID_XSDI_XRB_LISTBOX));
  978.  
  979.             winhSetEntryFieldLimit(WinWindowFromID(hwndDlg, ID_XSDI_XRB_ITEMNAME),
  980.                                    100-1);
  981.  
  982.             WinSetWindowULong(hwndDlg, QWL_USER, (ULONG)pData);
  983.  
  984.             WinPostMsg(hwndDlg, XM_UPDATE, MPNULL, MPNULL);
  985.         }
  986.         break;
  987.  
  988.         /*
  989.          * WM_CONTROL:
  990.          *
  991.          */
  992.  
  993.         case WM_CONTROL:
  994.             switch (SHORT1FROMMP(mp1))
  995.             {
  996.                 /*
  997.                  * ID_XSDI_XRB_LISTBOX:
  998.                  *      listbox was clicked on:
  999.                  *      update other controls with new data
  1000.                  */
  1001.  
  1002.                 case ID_XSDI_XRB_LISTBOX:
  1003.                     if (SHORT2FROMMP(mp1) == LN_SELECT)
  1004.                         WinSendMsg(hwndDlg, XM_UPDATE, MPNULL, MPNULL);
  1005.                 break;
  1006.  
  1007.                 /*
  1008.                  * ID_XSDI_XRB_ITEMNAME:
  1009.                  *      user changed item title: update data
  1010.                  */
  1011.  
  1012.                 case ID_XSDI_XRB_ITEMNAME:
  1013.                     if (SHORT2FROMMP(mp1) == EN_KILLFOCUS)
  1014.                     {
  1015.                         if (pData)
  1016.                         {
  1017.                             if (pData->pliSelected)
  1018.                             {
  1019.                                 WinQueryDlgItemText(hwndDlg, ID_XSDI_XRB_ITEMNAME,
  1020.                                                     sizeof(pData->pliSelected->szItemName)-1,
  1021.                                                     pData->pliSelected->szItemName);
  1022.                                 WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1023.                                                   LM_SETITEMTEXT,
  1024.                                                   (MPARAM)pData->sSelected,
  1025.                                                   (MPARAM)(pData->pliSelected->szItemName));
  1026.                             }
  1027.                         }
  1028.                     }
  1029.                 break;
  1030.  
  1031.                 // radio buttons
  1032.                 case ID_XSDI_ACL_WMCLOSE:
  1033.                 // case ID_XSDI_ACL_CTRL_C:     removed V0.9.19 (2002-05-23) [umoeller]
  1034.                 case ID_XSDI_ACL_KILLSESSION:
  1035.                 case ID_XSDI_ACL_SKIP:
  1036.                     if (SHORT2FROMMP(mp1) == BN_CLICKED)
  1037.                     {
  1038.                         if (pData)
  1039.                         {
  1040.                             if (pData->pliSelected)
  1041.                             {
  1042.                                 pData->pliSelected->usAction =
  1043.                                     (SHORT1FROMMP(mp1) == ID_XSDI_ACL_WMCLOSE)
  1044.                                         ? ACL_WMCLOSE
  1045.                                     // : (SHORT1FROMMP(mp1) == ID_XSDI_ACL_CTRL_C)
  1046.                                     //     ? ACL_CTRL_C
  1047.                                     : (SHORT1FROMMP(mp1) == ID_XSDI_ACL_KILLSESSION)
  1048.                                         ? ACL_KILLSESSION
  1049.                                     : ACL_SKIP;
  1050.                             }
  1051.                         }
  1052.                     }
  1053.                 break;
  1054.  
  1055.                 default:
  1056.                     mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  1057.             }
  1058.         break;
  1059.  
  1060.         case XM_UPDATE:
  1061.         {
  1062.             // posted from various locations to wholly update
  1063.             // the dlg items
  1064.             if (pData)
  1065.             {
  1066.                 pData->pliSelected = NULL;
  1067.                 pData->sSelected = (USHORT)WinSendDlgItemMsg(hwndDlg,
  1068.                         ID_XSDI_XRB_LISTBOX,
  1069.                         LM_QUERYSELECTION,
  1070.                         (MPARAM)LIT_CURSOR,
  1071.                         MPNULL);
  1072.                 //printf("  Selected: %d\n", pData->sSelected);
  1073.                 if (pData->sSelected != LIT_NONE)
  1074.                 {
  1075.                     pData->pliSelected = (PAUTOCLOSELISTITEM)lstItemFromIndex(
  1076.                                                pData->pllAutoClose,
  1077.                                                pData->sSelected);
  1078.                 }
  1079.  
  1080.                 if (pData->pliSelected)
  1081.                 {
  1082.                     WinSetDlgItemText(hwndDlg, ID_XSDI_XRB_ITEMNAME,
  1083.                             pData->pliSelected->szItemName);
  1084.  
  1085.                     switch (pData->pliSelected->usAction)
  1086.                     {
  1087.                         case ACL_WMCLOSE:
  1088.                             winhSetDlgItemChecked(hwndDlg,
  1089.                                 ID_XSDI_ACL_WMCLOSE, 1); break;
  1090.                         // case ACL_CTRL_C:     removed V0.9.19 (2002-05-23) [umoeller]
  1091.                         //     winhSetDlgItemChecked(hwndDlg,
  1092.                         //         ID_XSDI_ACL_CTRL_C, 1); break;
  1093.                         case ACL_KILLSESSION:
  1094.                             winhSetDlgItemChecked(hwndDlg,
  1095.                                 ID_XSDI_ACL_KILLSESSION, 1); break;
  1096.                         case ACL_SKIP:
  1097.                             winhSetDlgItemChecked(hwndDlg,
  1098.                                 ID_XSDI_ACL_SKIP, 1); break;
  1099.                     }
  1100.                 }
  1101.                 else
  1102.                     WinSetDlgItemText(hwndDlg,
  1103.                                       ID_XSDI_XRB_ITEMNAME,
  1104.                                       "");
  1105.  
  1106.                 WinEnableControl(hwndDlg, ID_XSDI_XRB_ITEMNAME,
  1107.                             (pData->pliSelected != NULL));
  1108.  
  1109.                 WinEnableControl(hwndDlg, ID_XSDI_ACL_WMCLOSE,
  1110.                             (pData->pliSelected != NULL));
  1111.                 // WinEnableControl(hwndDlg, ID_XSDI_ACL_CTRL_C,
  1112.                 //             (pData->pliSelected != NULL));
  1113.                 WinEnableControl(hwndDlg, ID_XSDI_ACL_KILLSESSION,
  1114.                             (pData->pliSelected != NULL));
  1115.                 WinEnableControl(hwndDlg, ID_XSDI_ACL_SKIP,
  1116.                             (pData->pliSelected != NULL));
  1117.  
  1118.                 WinEnableControl(hwndDlg,
  1119.                                   ID_XSDI_XRB_DELETE,
  1120.                                   (   (pData->usItemCount > 0)
  1121.                                    && (pData->pliSelected)
  1122.                                   ));
  1123.             }
  1124.         }
  1125.         break;
  1126.  
  1127.         case WM_COMMAND:
  1128.             switch (SHORT1FROMMP(mp1))
  1129.             {
  1130.  
  1131.                 /*
  1132.                  * ID_XSDI_XRB_NEW:
  1133.                  *      create new item
  1134.                  */
  1135.  
  1136.                 case ID_XSDI_XRB_NEW:
  1137.                 {
  1138.                     PAUTOCLOSELISTITEM pliNew = malloc(sizeof(AUTOCLOSELISTITEM));
  1139.                     strcpy(pliNew->szItemName, "???");
  1140.                     pliNew->usAction = ACL_SKIP;
  1141.                     lstAppendItem(pData->pllAutoClose,
  1142.                                   pliNew);
  1143.  
  1144.                     pData->usItemCount++;
  1145.                     WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1146.                                       LM_INSERTITEM,
  1147.                                       (MPARAM)LIT_END,
  1148.                                       (MPARAM)pliNew->szItemName);
  1149.                     WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1150.                                       LM_SELECTITEM, // will cause XM_UPDATE
  1151.                                       (MPARAM)(lstCountItems(
  1152.                                               pData->pllAutoClose)),
  1153.                                       (MPARAM)TRUE);
  1154.                     winhSetDlgItemFocus(hwndDlg, ID_XSDI_XRB_ITEMNAME);
  1155.                     WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_ITEMNAME,
  1156.                                       EM_SETSEL,
  1157.                                       MPFROM2SHORT(0, 1000), // select all
  1158.                                       MPNULL);
  1159.                 }
  1160.                 break;
  1161.  
  1162.                 /*
  1163.                  * ID_XSDI_XRB_DELETE:
  1164.                  *      delete selected item
  1165.                  */
  1166.  
  1167.                 case ID_XSDI_XRB_DELETE:
  1168.                 {
  1169.                     //printf("WM_COMMAND ID_XSDI_XRB_DELETE BN_CLICKED\n");
  1170.                     if (pData)
  1171.                     {
  1172.                         if (pData->pliSelected)
  1173.                         {
  1174.                             lstRemoveItem(pData->pllAutoClose,
  1175.                                           pData->pliSelected);
  1176.                             WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1177.                                               LM_DELETEITEM,
  1178.                                               (MPARAM)pData->sSelected,
  1179.                                               MPNULL);
  1180.                         }
  1181.                         WinPostMsg(hwndDlg, XM_UPDATE, MPNULL, MPNULL);
  1182.                     }
  1183.                     winhSetDlgItemFocus(hwndDlg, ID_XSDI_XRB_LISTBOX);
  1184.                 }
  1185.                 break;
  1186.  
  1187.                 /*
  1188.                  * DID_OK:
  1189.                  *      store data in INI and dismiss dlg
  1190.                  */
  1191.  
  1192.                 case DID_OK:
  1193.                 {
  1194.                     USHORT usInvalid;
  1195.                     if (usInvalid = xsdWriteAutoCloseItems(pData->pllAutoClose))
  1196.                     {
  1197.                         WinAlarm(HWND_DESKTOP, WA_ERROR);
  1198.                         WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1199.                                           LM_SELECTITEM,
  1200.                                           (MPARAM)usInvalid,
  1201.                                           (MPARAM)TRUE);
  1202.                     }
  1203.                     else
  1204.                         // dismiss dlg
  1205.                         mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  1206.                 }
  1207.                 break;
  1208.  
  1209.                 default:  // includes DID_CANCEL
  1210.                     mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  1211.                 break;
  1212.             }
  1213.         break;
  1214.  
  1215.         case WM_HELP:
  1216.             cmnDisplayHelp(NULL,
  1217.                            ID_XFH_AUTOCLOSEDETAILS);
  1218.         break;
  1219.  
  1220.         /*
  1221.          * WM_DESTROY:
  1222.          *      clean up allocated memory
  1223.          */
  1224.  
  1225.         case WM_DESTROY:
  1226.         {
  1227.             ctlStopAnimation(WinWindowFromID(hwndDlg, ID_SDDI_ICON));
  1228.             xsdFreeAnimation(&G_sdAnim);
  1229.             lstFree(&pData->pllAutoClose);
  1230.             free(pData);
  1231.             mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  1232.         }
  1233.         break;
  1234.  
  1235.         default:
  1236.             mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  1237.         break;
  1238.     }
  1239.     return mrc;
  1240. }
  1241.  
  1242. #define ACL_WIDTH       200
  1243. #define ACL_LB_WIDTH    (ACL_WIDTH - COMMON_SPACING - STD_BUTTON_WIDTH)
  1244.  
  1245. static const CONTROLDEF
  1246.     ACLIcon = CONTROLDEF_ICON(NULLHANDLE, ID_SDDI_ICON),
  1247.     ACLIntro = LOADDEF_TEXT_WORDBREAK(ID_XSDI_ACL_INTRO, ACL_WIDTH - 30),
  1248.     ACLListbox = CONTROLDEF_LISTBOX(ID_XSDI_XRB_LISTBOX, ACL_LB_WIDTH, 60),
  1249.     ACLNew = LOADDEF_NOFOCUSBUTTON(ID_XSDI_XRB_NEW),
  1250.     ACLDelete = LOADDEF_NOFOCUSBUTTON(ID_XSDI_XRB_DELETE),
  1251.     ACLSessionTitle = LOADDEF_TEXT(ID_XSDI_ACL_SESSIONTITLE),
  1252.     ACLEntryField = CONTROLDEF_ENTRYFIELD("", ID_XSDI_XRB_ITEMNAME, ACL_WIDTH, SZL_AUTOSIZE),
  1253.     ACLDoWhatGroup = LOADDEF_GROUP(ID_XSDI_ACL_DOWHATGROUP, SZL_AUTOSIZE),
  1254.     ACLSkipRadio = LOADDEF_FIRST_AUTORADIO(ID_XSDI_ACL_SKIP),
  1255.     ACLWMCloseRadio = LOADDEF_NEXT_AUTORADIO(ID_XSDI_ACL_WMCLOSE),
  1256.     ACLKillRadio = LOADDEF_NEXT_AUTORADIO(ID_XSDI_ACL_KILLSESSION);
  1257.  
  1258. static const DLGHITEM G_dlgAutoCloseDetails[] =
  1259.     {
  1260.         START_TABLE,
  1261.             START_ROW(ROW_VALIGN_CENTER),
  1262.                 CONTROL_DEF(&ACLIcon),
  1263.                 CONTROL_DEF(&ACLIntro),
  1264.             START_ROW(ROW_VALIGN_CENTER),
  1265.                 CONTROL_DEF(&ACLListbox),
  1266.                 START_TABLE,
  1267.                     START_ROW(0),
  1268.                         CONTROL_DEF(&ACLNew),
  1269.                     START_ROW(0),
  1270.                         CONTROL_DEF(&ACLDelete),
  1271.                 END_TABLE,
  1272.             START_ROW(0),
  1273.                 CONTROL_DEF(&ACLSessionTitle),
  1274.             START_ROW(0),
  1275.                 CONTROL_DEF(&ACLEntryField),
  1276.             START_ROW(0),
  1277.                 START_GROUP_TABLE(&ACLDoWhatGroup),
  1278.                     START_ROW(0),
  1279.                         CONTROL_DEF(&ACLSkipRadio),
  1280.                     START_ROW(0),
  1281.                         CONTROL_DEF(&ACLWMCloseRadio),
  1282.                     START_ROW(0),
  1283.                         CONTROL_DEF(&ACLKillRadio),
  1284.                 END_TABLE,
  1285.             START_ROW(0),
  1286.                 CONTROL_DEF(&G_OKButton),
  1287.                 CONTROL_DEF(&G_CancelButton),
  1288.                 CONTROL_DEF(&G_HelpButton),
  1289.         END_TABLE
  1290.     };
  1291.  
  1292. /*
  1293.  *@@ ShowAutoCloseDetails:
  1294.  *
  1295.  *@@added V0.9.19 (2002-05-23) [umoeller]
  1296.  */
  1297.  
  1298. static VOID ShowAutoCloseDetails(HWND hwndOwner)
  1299. {
  1300.     PDLGHITEM paNew;
  1301.     if (!cmnLoadDialogStrings(G_dlgAutoCloseDetails,
  1302.                               ARRAYITEMCOUNT(G_dlgAutoCloseDetails),
  1303.                               &paNew))
  1304.     {
  1305.         HWND hwndDlg;
  1306.         if (!dlghCreateDlg(&hwndDlg,
  1307.                            hwndOwner,
  1308.                            FCF_FIXED_DLG,
  1309.                            fnwpAutoCloseDetails,
  1310.                            cmnGetString(ID_XSD_AUTOCLOSE), // "Auto-Close Non-PM Sessions"
  1311.                            paNew,
  1312.                            ARRAYITEMCOUNT(G_dlgAutoCloseDetails),
  1313.                            NULL,
  1314.                            cmnQueryDefaultFont()))
  1315.         {
  1316.             winhCenterWindow(hwndDlg);      // still hidden
  1317.             WinProcessDlg(hwndDlg);
  1318.             WinDestroyWindow(hwndDlg);
  1319.         }
  1320.  
  1321.         free(paNew);
  1322.     }
  1323. }
  1324.  
  1325. /*
  1326.  *@@ fnwpUserRebootOptions:
  1327.  *      dlg proc for the "Extended Reboot" options.
  1328.  *      This gets called from the notebook callbacks
  1329.  *      for the "XDesktop" notebook page
  1330.  *      (fncbDesktop1ItemChanged, xfdesk.c).
  1331.  *
  1332.  *@@changed V0.9.0 [umoeller]: adjusted for new linklist.c functions
  1333.  *@@changed V0.9.0 [umoeller]: renamed from fnwpRebootExt
  1334.  *@@changed V0.9.0 [umoeller]: added "Partitions" button
  1335.  */
  1336.  
  1337. MRESULT EXPENTRY fnwpUserRebootOptions(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
  1338. {
  1339.     MRESULT mrc = (MPARAM)NULL;
  1340.  
  1341.     switch (msg)
  1342.     {
  1343.         /*
  1344.          * WM_INITDLG:
  1345.          *
  1346.          */
  1347.  
  1348.         case WM_INITDLG:
  1349.         {
  1350.             ULONG       ulKeyLength;
  1351.             PSZ         p, pINI;
  1352.  
  1353.             // create window data in QWL_USER
  1354.             PREBOOTWINDATA pData = malloc(sizeof(REBOOTWINDATA));
  1355.             memset(pData, 0, sizeof(REBOOTWINDATA));
  1356.             pData->pllReboot = lstCreate(TRUE);
  1357.  
  1358.             // set animation
  1359.             xsdLoadAnimation(&G_sdAnim);
  1360.             ctlPrepareAnimation(WinWindowFromID(hwndDlg, ID_SDDI_ICON),
  1361.                                 XSD_ANIM_COUNT,
  1362.                                 &(G_sdAnim.ahptr[0]),
  1363.                                 150,    // delay
  1364.                                 TRUE);  // start now
  1365.  
  1366.             pData->usItemCount = 0;
  1367.  
  1368.             // get existing items from INI
  1369.             if (PrfQueryProfileSize(HINI_USER,
  1370.                                     (PSZ)INIAPP_XWORKPLACE,
  1371.                                     (PSZ)INIKEY_BOOTMGR,
  1372.                                     &ulKeyLength))
  1373.             {
  1374.                 // _Pmpf(( "Size: %d", ulKeyLength ));
  1375.                 // items exist: evaluate
  1376.                 pINI = malloc(ulKeyLength);
  1377.                 if (pINI)
  1378.                 {
  1379.                     PrfQueryProfileData(HINI_USER,
  1380.                                         (PSZ)INIAPP_XWORKPLACE,
  1381.                                         (PSZ)INIKEY_BOOTMGR,
  1382.                                         pINI,
  1383.                                         &ulKeyLength);
  1384.                     p = pINI;
  1385.                     // _Pmpf(( "%s", p ));
  1386.                     while (strlen(p))
  1387.                     {
  1388.                         PREBOOTLISTITEM pliNew = malloc(sizeof(REBOOTLISTITEM));
  1389.                         strcpy(pliNew->szItemName, p);
  1390.                         lstAppendItem(pData->pllReboot,
  1391.                                     pliNew);
  1392.  
  1393.                         WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1394.                                         LM_INSERTITEM,
  1395.                                         (MPARAM)LIT_END,
  1396.                                         (MPARAM)p);
  1397.                         p += (strlen(p)+1);
  1398.  
  1399.                         if (strlen(p)) {
  1400.                             strcpy(pliNew->szCommand, p);
  1401.                             p += (strlen(p)+1);
  1402.                         }
  1403.                         pData->usItemCount++;
  1404.                     }
  1405.                     free(pINI);
  1406.                 }
  1407.             }
  1408.  
  1409.             WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_ITEMNAME,
  1410.                 EM_SETTEXTLIMIT, (MPARAM)(100-1), MPNULL);
  1411.             WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_COMMAND,
  1412.                 EM_SETTEXTLIMIT, (MPARAM)(CCHMAXPATH-1), MPNULL);
  1413.  
  1414.             WinSetWindowULong(hwndDlg, QWL_USER, (ULONG)pData);
  1415.  
  1416.             // create "menu button" for "Partitions..."
  1417.             ctlMakeMenuButton(WinWindowFromID(hwndDlg, ID_XSDI_XRB_PARTITIONS),
  1418.                               // set menu resource module and ID to
  1419.                               // 0; this will cause WM_COMMAND for
  1420.                               // querying the menu handle to be
  1421.                               // displayed
  1422.                               0, 0);
  1423.  
  1424.             WinPostMsg(hwndDlg, XM_UPDATE, MPNULL, MPNULL);
  1425.         }
  1426.         break;
  1427.  
  1428.         /*
  1429.          * WM_CONTROL:
  1430.          *
  1431.          */
  1432.  
  1433.         case WM_CONTROL:
  1434.             switch (SHORT1FROMMP(mp1))
  1435.             {
  1436.                 /*
  1437.                  * ID_XSDI_XRB_LISTBOX:
  1438.                  *      new reboot item selected.
  1439.                  */
  1440.  
  1441.                 case ID_XSDI_XRB_LISTBOX:
  1442.                     if (SHORT2FROMMP(mp1) == LN_SELECT)
  1443.                         WinSendMsg(hwndDlg, XM_UPDATE, MPNULL, MPNULL);
  1444.                 break;
  1445.  
  1446.                 /*
  1447.                  * ID_XSDI_XRB_ITEMNAME:
  1448.                  *      reboot item name changed.
  1449.                  */
  1450.  
  1451.                 case ID_XSDI_XRB_ITEMNAME:
  1452.                     if (SHORT2FROMMP(mp1) == EN_KILLFOCUS)
  1453.                     {
  1454.                         PREBOOTWINDATA pData =
  1455.                                 (PREBOOTWINDATA)WinQueryWindowPtr(hwndDlg, QWL_USER);
  1456.                         // _Pmpf(( "WM_CONTROL ID_XSDI_XRB_ITEMNAME EN_KILLFOCUS" ));
  1457.                         if (pData)
  1458.                         {
  1459.                             if (pData->pliSelected)
  1460.                             {
  1461.                                 WinQueryDlgItemText(hwndDlg, ID_XSDI_XRB_ITEMNAME,
  1462.                                                     sizeof(pData->pliSelected->szItemName)-1,
  1463.                                                     pData->pliSelected->szItemName);
  1464.                                 WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1465.                                                   LM_SETITEMTEXT,
  1466.                                                   (MPARAM)pData->sSelected,
  1467.                                                   (MPARAM)(pData->pliSelected->szItemName));
  1468.                             }
  1469.                         }
  1470.                     }
  1471.                 break;
  1472.  
  1473.                 /*
  1474.                  * ID_XSDI_XRB_COMMAND:
  1475.                  *      reboot item command changed.
  1476.                  */
  1477.  
  1478.                 case ID_XSDI_XRB_COMMAND:
  1479.                     if (SHORT2FROMMP(mp1) == EN_KILLFOCUS)
  1480.                     {
  1481.                         PREBOOTWINDATA pData =
  1482.                                 (PREBOOTWINDATA)WinQueryWindowPtr(hwndDlg, QWL_USER);
  1483.                         // _Pmpf(( "WM_CONTROL ID_XSDI_XRB_COMMAND EN_KILLFOCUS" ));
  1484.                         if (pData)
  1485.                             if (pData->pliSelected)
  1486.                                 WinQueryDlgItemText(hwndDlg, ID_XSDI_XRB_COMMAND,
  1487.                                                     sizeof(pData->pliSelected->szCommand)-1,
  1488.                                                     pData->pliSelected->szCommand);
  1489.                     }
  1490.                 break;
  1491.  
  1492.                 default:
  1493.                     mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  1494.             }
  1495.         break;
  1496.  
  1497.         /*
  1498.          * XM_UPDATE:
  1499.          *      updates the controls according to the
  1500.          *      currently selected list box item.
  1501.          */
  1502.  
  1503.         case XM_UPDATE:
  1504.         {
  1505.             PREBOOTWINDATA pData;
  1506.             if (pData = (PREBOOTWINDATA)WinQueryWindowPtr(hwndDlg, QWL_USER))
  1507.             {
  1508.                 pData->pliSelected = NULL;
  1509.                 pData->sSelected = (USHORT)WinSendDlgItemMsg(hwndDlg,
  1510.                                                              ID_XSDI_XRB_LISTBOX,
  1511.                                                              LM_QUERYSELECTION,
  1512.                                                              (MPARAM)LIT_CURSOR,
  1513.                                                              MPNULL);
  1514.                 if (pData->sSelected != LIT_NONE)
  1515.                     pData->pliSelected = (PREBOOTLISTITEM)lstItemFromIndex(
  1516.                             pData->pllReboot,
  1517.                             pData->sSelected);
  1518.  
  1519.                 if (pData->pliSelected)
  1520.                 {
  1521.                     WinSetDlgItemText(hwndDlg, ID_XSDI_XRB_ITEMNAME,
  1522.                             pData->pliSelected->szItemName);
  1523.                     WinSetDlgItemText(hwndDlg, ID_XSDI_XRB_COMMAND,
  1524.                             pData->pliSelected->szCommand);
  1525.                 }
  1526.                 else
  1527.                 {
  1528.                     WinSetDlgItemText(hwndDlg, ID_XSDI_XRB_ITEMNAME,
  1529.                             "");
  1530.                     WinSetDlgItemText(hwndDlg, ID_XSDI_XRB_COMMAND,
  1531.                             "");
  1532.                 }
  1533.                 WinEnableControl(hwndDlg, ID_XSDI_XRB_ITEMNAME,
  1534.                             (pData->pliSelected != NULL));
  1535.                 WinEnableControl(hwndDlg, ID_XSDI_XRB_COMMAND,
  1536.                             (pData->pliSelected != NULL));
  1537.                 WinEnableControl(hwndDlg, ID_XSDI_XRB_PARTITIONS,
  1538.                             (pData->pliSelected != NULL));
  1539.                 WinEnableControl(hwndDlg, ID_XSDI_XRB_UP,
  1540.                             (   (pData->pliSelected != NULL)
  1541.                              && (pData->usItemCount > 1)
  1542.                              && (pData->sSelected > 0)
  1543.                             ));
  1544.                 WinEnableControl(hwndDlg, ID_XSDI_XRB_DOWN,
  1545.                             (   (pData->pliSelected != NULL)
  1546.                              && (pData->usItemCount > 1)
  1547.                              && (pData->sSelected < (pData->usItemCount-1))
  1548.                             ));
  1549.  
  1550.                 WinEnableControl(hwndDlg, ID_XSDI_XRB_DELETE,
  1551.                             (   (pData->usItemCount > 0)
  1552.                              && (pData->pliSelected)
  1553.                             )
  1554.                         );
  1555.             }
  1556.         }
  1557.         break;
  1558.  
  1559.         /*
  1560.          * WM_COMMAND:
  1561.          *
  1562.          */
  1563.  
  1564.         case WM_COMMAND:
  1565.         {
  1566.             PREBOOTWINDATA pData =
  1567.                     (PREBOOTWINDATA)WinQueryWindowPtr(hwndDlg, QWL_USER);
  1568.             USHORT usItemID = SHORT1FROMMP(mp1);
  1569.             switch (usItemID)
  1570.             {
  1571.                 /*
  1572.                  * ID_XSDI_XRB_NEW:
  1573.                  *      create new item
  1574.                  */
  1575.  
  1576.                 case ID_XSDI_XRB_NEW:
  1577.                 {
  1578.                     PREBOOTLISTITEM pliNew = malloc(sizeof(REBOOTLISTITEM));
  1579.                     // _Pmpf(( "WM_COMMAND ID_XSDI_XRB_NEW BN_CLICKED" ));
  1580.                     strcpy(pliNew->szItemName, "???");
  1581.                     strcpy(pliNew->szCommand, "???");
  1582.                     lstAppendItem(pData->pllReboot,
  1583.                                   pliNew);
  1584.  
  1585.                     pData->usItemCount++;
  1586.                     WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1587.                                     LM_INSERTITEM,
  1588.                                     (MPARAM)LIT_END,
  1589.                                     (MPARAM)pliNew->szItemName);
  1590.                     WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1591.                                     LM_SELECTITEM,
  1592.                                     (MPARAM)(lstCountItems(
  1593.                                             pData->pllReboot)
  1594.                                          - 1),
  1595.                                     (MPARAM)TRUE);
  1596.                     winhSetDlgItemFocus(hwndDlg, ID_XSDI_XRB_ITEMNAME);
  1597.                     WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_ITEMNAME,
  1598.                             EM_SETSEL,
  1599.                             MPFROM2SHORT(0, 1000), // select all
  1600.                             MPNULL);
  1601.                 }
  1602.                 break;
  1603.  
  1604.                 /*
  1605.                  * ID_XSDI_XRB_DELETE:
  1606.                  *      delete delected item
  1607.                  */
  1608.  
  1609.                 case ID_XSDI_XRB_DELETE:
  1610.                     if (pData)
  1611.                     {
  1612.                         if (pData->pliSelected)
  1613.                         {
  1614.                             lstRemoveItem(pData->pllReboot,
  1615.                                     pData->pliSelected);
  1616.                             WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1617.                                     LM_DELETEITEM,
  1618.                                     (MPARAM)pData->sSelected,
  1619.                                     MPNULL);
  1620.                         }
  1621.                         WinPostMsg(hwndDlg, XM_UPDATE, MPNULL, MPNULL);
  1622.                     }
  1623.                     winhSetDlgItemFocus(hwndDlg, ID_XSDI_XRB_LISTBOX);
  1624.                 break;
  1625.  
  1626.                 /*
  1627.                  * ID_XSDI_XRB_UP:
  1628.                  *      move selected item up
  1629.                  */
  1630.  
  1631.                 case ID_XSDI_XRB_UP:
  1632.                     if (pData)
  1633.                     {
  1634.                         // _Pmpf(( "WM_COMMAND ID_XSDI_XRB_UP BN_CLICKED" ));
  1635.                         if (pData->pliSelected)
  1636.                         {
  1637.                             PREBOOTLISTITEM pliNew = malloc(sizeof(REBOOTLISTITEM));
  1638.                             *pliNew = *(pData->pliSelected);
  1639.                             // remove selected
  1640.                             lstRemoveItem(pData->pllReboot,
  1641.                                     pData->pliSelected);
  1642.                             WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1643.                                     LM_DELETEITEM,
  1644.                                     (MPARAM)pData->sSelected,
  1645.                                     MPNULL);
  1646.                             // insert item again
  1647.                             lstInsertItemBefore(pData->pllReboot,
  1648.                                                 pliNew,
  1649.                                                 (pData->sSelected-1));
  1650.                             WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1651.                                             LM_INSERTITEM,
  1652.                                             (MPARAM)(pData->sSelected-1),
  1653.                                             (MPARAM)pliNew->szItemName);
  1654.                             WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1655.                                             LM_SELECTITEM,
  1656.                                             (MPARAM)(pData->sSelected-1),
  1657.                                             (MPARAM)TRUE); // select flag
  1658.                         }
  1659.                         WinPostMsg(hwndDlg, XM_UPDATE, MPNULL, MPNULL);
  1660.                     }
  1661.                     winhSetDlgItemFocus(hwndDlg, ID_XSDI_XRB_LISTBOX);
  1662.                 break;
  1663.  
  1664.                 /*
  1665.                  * ID_XSDI_XRB_DOWN:
  1666.                  *      move selected item down
  1667.                  */
  1668.  
  1669.                 case ID_XSDI_XRB_DOWN:
  1670.                     if (pData)
  1671.                     {
  1672.                         // _Pmpf(( "WM_COMMAND ID_XSDI_XRB_DOWN BN_CLICKED" ));
  1673.                         if (pData->pliSelected)
  1674.                         {
  1675.                             PREBOOTLISTITEM pliNew = malloc(sizeof(REBOOTLISTITEM));
  1676.                             *pliNew = *(pData->pliSelected);
  1677.                             // remove selected
  1678.                             // _Pmpf(( "  Removing index %d", pData->sSelected ));
  1679.                             lstRemoveItem(pData->pllReboot,
  1680.                                           pData->pliSelected);
  1681.                             WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1682.                                     LM_DELETEITEM,
  1683.                                     (MPARAM)pData->sSelected,
  1684.                                     MPNULL);
  1685.                             // insert item again
  1686.                             lstInsertItemBefore(pData->pllReboot,
  1687.                                                 pliNew,
  1688.                                                 (pData->sSelected+1));
  1689.                             WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1690.                                             LM_INSERTITEM,
  1691.                                             (MPARAM)(pData->sSelected+1),
  1692.                                             (MPARAM)pliNew->szItemName);
  1693.                             WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1694.                                             LM_SELECTITEM,
  1695.                                             (MPARAM)(pData->sSelected+1),
  1696.                                             (MPARAM)TRUE); // select flag
  1697.                         }
  1698.                         WinPostMsg(hwndDlg, XM_UPDATE, MPNULL, MPNULL);
  1699.                     }
  1700.                     winhSetDlgItemFocus(hwndDlg, ID_XSDI_XRB_LISTBOX);
  1701.                 break;
  1702.  
  1703.                 /*
  1704.                  * ID_XSDI_XRB_PARTITIONS:
  1705.                  *      "Partitions" button.
  1706.                  *      Even though this is part of the WM_COMMAND
  1707.                  *      block, this is not really a command msg
  1708.                  *      like the other messages; instead, this
  1709.                  *      is sent (!) to us and expects a HWND for
  1710.                  *      the menu to be displayed on the button.
  1711.                  *
  1712.                  *      We create a menu containing bootable
  1713.                  *      partitions.
  1714.                  */
  1715.  
  1716.                 case ID_XSDI_XRB_PARTITIONS:
  1717.                 {
  1718.                     HPOINTER       hptrOld = winhSetWaitPointer();
  1719.                     HWND           hMenu = NULLHANDLE;
  1720.  
  1721.                     if (!pData->fPartitionsLoaded)  // V0.9.9 (2001-04-07) [umoeller]
  1722.                     {
  1723.                         // first time:
  1724.                         USHORT         usContext = 0;
  1725.                         APIRET arc = doshGetPartitionsList(&pData->pPartitionsList,
  1726.                                                            &usContext);
  1727.  
  1728.                         pData->fPartitionsLoaded = TRUE;
  1729.                     }
  1730.  
  1731.                     #ifdef DEBUG_SHUTDOWN
  1732.                         _PmpfF(("pData->pPartitionsList is 0x%lX",
  1733.                                 pData->pPartitionsList));
  1734.                     #endif
  1735.  
  1736.                     if (pData->pPartitionsList)
  1737.                     {
  1738.                         PPARTITIONINFO ppi = pData->pPartitionsList->pPartitionInfo;
  1739.                         SHORT          sItemId = ID_XSDI_PARTITIONSFIRST;
  1740.                         hMenu = WinCreateMenu(HWND_DESKTOP,
  1741.                                               NULL); // no menu template
  1742.                         while (ppi)
  1743.                         {
  1744.                             if (ppi->fBootable)
  1745.                             {
  1746.                                 CHAR szMenuItem[100];
  1747.                                 sprintf(szMenuItem,
  1748.                                         "%s (Drive %d, %c:)",
  1749.                                         ppi->szBootName,
  1750.                                         ppi->bDisk,
  1751.                                         ppi->cLetter);
  1752.                                 winhInsertMenuItem(hMenu,
  1753.                                                    MIT_END,
  1754.                                                    sItemId++,
  1755.                                                    szMenuItem,
  1756.                                                    MIS_TEXT,
  1757.                                                    0);
  1758.                             }
  1759.                             ppi = ppi->pNext;
  1760.                         }
  1761.                     }
  1762.  
  1763.                     WinSetPointer(HWND_DESKTOP, hptrOld);
  1764.  
  1765.                     mrc = (MRESULT)hMenu;
  1766.                 }
  1767.                 break;
  1768.  
  1769.                 /*
  1770.                  * DID_OK:
  1771.                  *      store data in INI and dismiss dlg
  1772.                  */
  1773.  
  1774.                 case DID_OK:
  1775.                 {
  1776.                     PSZ     pINI, p;
  1777.                     BOOL    fValid = TRUE;
  1778.                     ULONG   ulItemCount = lstCountItems(pData->pllReboot);
  1779.  
  1780.                     // _Pmpf(( "WM_COMMAND DID_OK BN_CLICKED" ));
  1781.                     // store data in INI
  1782.                     if (ulItemCount)
  1783.                     {
  1784.                         pINI = malloc(
  1785.                                     sizeof(REBOOTLISTITEM)
  1786.                                   * ulItemCount);
  1787.                         memset(pINI, 0,
  1788.                                     sizeof(REBOOTLISTITEM)
  1789.                                   * ulItemCount);
  1790.  
  1791.                         if (pINI)
  1792.                         {
  1793.                             PLISTNODE       pNode = lstQueryFirstNode(pData->pllReboot);
  1794.                             USHORT          usCurrent = 0;
  1795.                             p = pINI;
  1796.  
  1797.                             while (pNode)
  1798.                             {
  1799.                                 PREBOOTLISTITEM pli = pNode->pItemData;
  1800.  
  1801.                                 if (    (strlen(pli->szItemName) == 0)
  1802.                                      || (strlen(pli->szCommand) == 0)
  1803.                                    )
  1804.                                 {
  1805.                                     WinAlarm(HWND_DESKTOP, WA_ERROR);
  1806.                                     WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1807.                                                     LM_SELECTITEM,
  1808.                                                     (MPARAM)usCurrent,
  1809.                                                     (MPARAM)TRUE);
  1810.                                     fValid = FALSE;
  1811.                                     break;
  1812.                                 }
  1813.                                 strcpy(p, pli->szItemName);
  1814.                                 p += (strlen(p)+1);
  1815.                                 strcpy(p, pli->szCommand);
  1816.                                 p += (strlen(p)+1);
  1817.  
  1818.                                 pNode = pNode->pNext;
  1819.                                 usCurrent++;
  1820.                             }
  1821.  
  1822.                             PrfWriteProfileData(HINI_USER,
  1823.                                         (PSZ)INIAPP_XWORKPLACE,
  1824.                                         (PSZ)INIKEY_BOOTMGR,
  1825.                                         pINI,
  1826.                                         (p - pINI + 2));
  1827.  
  1828.                             free (pINI);
  1829.                         }
  1830.                     } // end if (pData->pliReboot)
  1831.                     else
  1832.                         PrfWriteProfileData(HINI_USER,
  1833.                                     (PSZ)INIAPP_XWORKPLACE,
  1834.                                     (PSZ)INIKEY_BOOTMGR,
  1835.                                     NULL, 0);
  1836.  
  1837.                     // dismiss dlg
  1838.                     if (fValid)
  1839.                         mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  1840.                 }
  1841.                 break;
  1842.  
  1843.                 default: // includes DID_CANCEL
  1844.                     if (    (pData->pPartitionsList)
  1845.                          && (pData->pPartitionsList->cPartitions)
  1846.                        )
  1847.                     {
  1848.                         // partitions valid:
  1849.                         ULONG cPartitions = pData->pPartitionsList->cPartitions;
  1850.                         if (    (usItemID >= ID_XSDI_PARTITIONSFIRST)
  1851.                              && (usItemID < ID_XSDI_PARTITIONSFIRST + cPartitions)
  1852.                              && (pData->pliSelected)
  1853.                            )
  1854.                         {
  1855.                             // partition item from "Partitions" menu button:
  1856.                             // search partitions list then
  1857.                             PPARTITIONINFO ppi = pData->pPartitionsList->pPartitionInfo;
  1858.                             SHORT sItemIDCompare = ID_XSDI_PARTITIONSFIRST;
  1859.                             while (ppi)
  1860.                             {
  1861.                                 if (ppi->fBootable)
  1862.                                 {
  1863.                                     // bootable item:
  1864.                                     // then we have inserted the thing into
  1865.                                     // the menu
  1866.                                     if (sItemIDCompare == usItemID)
  1867.                                     {
  1868.                                         // found our one:
  1869.                                         // insert into entry field
  1870.                                         CHAR szItem[20];
  1871.                                         // CHAR szCommand[100];
  1872.                                         ULONG ul = 0;
  1873.  
  1874.                                         // strip trailing spaces
  1875.                                         strcpy(szItem, ppi->szBootName);
  1876.                                         for (ul = strlen(szItem) - 1;
  1877.                                              ul > 0;
  1878.                                              ul--)
  1879.                                             if (szItem[ul] == ' ')
  1880.                                                 szItem[ul] = 0;
  1881.                                             else
  1882.                                                 break;
  1883.  
  1884.                                         // now set reboot item's data
  1885.                                         // according to the partition item
  1886.                                         strcpy(pData->pliSelected->szItemName,
  1887.                                                szItem);
  1888.                                         // compose new command
  1889.                                         sprintf(pData->pliSelected->szCommand,
  1890.                                                 "setboot /iba:\"%s\"",
  1891.                                                 szItem);
  1892.  
  1893.                                         // update list box item
  1894.                                         WinSendDlgItemMsg(hwndDlg, ID_XSDI_XRB_LISTBOX,
  1895.                                                           LM_SETITEMTEXT,
  1896.                                                           (MPARAM)pData->sSelected,
  1897.                                                           (MPARAM)(pData->pliSelected->szItemName));
  1898.                                         // update rest of dialog
  1899.                                         WinSendMsg(hwndDlg, XM_UPDATE, MPNULL, MPNULL);
  1900.  
  1901.                                         break; // while (ppi)
  1902.                                     }
  1903.                                     else
  1904.                                         // next item
  1905.                                         sItemIDCompare++;
  1906.                                 }
  1907.                                 ppi = ppi->pNext;
  1908.                             }
  1909.  
  1910.                             break;
  1911.                         }
  1912.                     }
  1913.                     mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  1914.                 break;
  1915.             }
  1916.         }
  1917.         break;
  1918.  
  1919.         case WM_HELP:
  1920.             cmnDisplayHelp(NULL,
  1921.                            ID_XFH_REBOOTEXT);
  1922.         break;
  1923.  
  1924.         /*
  1925.          * WM_DESTROY:
  1926.          *      clean up allocated memory
  1927.          */
  1928.  
  1929.         case WM_DESTROY:
  1930.         {
  1931.             PREBOOTWINDATA pData = (PREBOOTWINDATA)WinQueryWindowPtr(hwndDlg, QWL_USER);
  1932.             ctlStopAnimation(WinWindowFromID(hwndDlg, ID_SDDI_ICON));
  1933.             xsdFreeAnimation(&G_sdAnim);
  1934.             lstFree(&pData->pllReboot);
  1935.             if (pData->pPartitionsList)
  1936.                 doshFreePartitionsList(pData->pPartitionsList);
  1937.             free(pData);
  1938.             mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  1939.         }
  1940.         break;
  1941.  
  1942.         default:
  1943.             mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
  1944.         break;
  1945.     }
  1946.     return mrc;
  1947. }
  1948.  
  1949. /* ******************************************************************
  1950.  *
  1951.  *   Shutdown interface
  1952.  *
  1953.  ********************************************************************/
  1954.  
  1955. /*
  1956.  *@@ xsdQueryShutdownSettings:
  1957.  *      this fills the specified SHUTDOWNPARAMS array with
  1958.  *      the current shutdown settings, as specified by the
  1959.  *      user in the desktop's settings notebooks.
  1960.  *
  1961.  *      Notes:
  1962.  *
  1963.  *      -- psdp->optAnimate is set to the animation setting
  1964.  *         which applies according to whether reboot is enabled
  1965.  *         or not.
  1966.  *
  1967.  *      -- There is no "current setting" for the user reboot
  1968.  *         command. As a result, psdp->szRebootCommand is
  1969.  *         zeroed.
  1970.  *
  1971.  *      -- Neither is there a "current setting" for whether
  1972.  *         to use "restart Desktop" or "logoff" instead. To later use
  1973.  *         "restart Desktop", set psdp->ulRestartWPS and maybe
  1974.  *         psdp->optWPSReuseStartupFolder also.
  1975.  *
  1976.  *@@added V0.9.7 (2001-01-25) [umoeller]
  1977.  */
  1978.  
  1979. VOID xsdQueryShutdownSettings(PSHUTDOWNPARAMS psdp)
  1980. {
  1981.     ULONG flShutdown = 0;
  1982. #ifndef __NOXSHUTDOWN__
  1983.     flShutdown = cmnQuerySetting(sflXShutdown);
  1984. #endif
  1985.  
  1986.     memset(psdp, 0, sizeof(SHUTDOWNPARAMS));
  1987.     psdp->optReboot = ((flShutdown & XSD_REBOOT) != 0);
  1988.     psdp->optConfirm = (!(flShutdown & XSD_NOCONFIRM));
  1989.     psdp->optDebug = FALSE;
  1990.  
  1991.     // psdp->ulRestartWPS = 0;         // no, do shutdown
  1992.     psdp->ulCloseMode = SHUT_SHUTDOWN;
  1993.  
  1994.     psdp->optWPSCloseWindows = TRUE;
  1995.     psdp->optAutoCloseVIO = ((flShutdown & XSD_AUTOCLOSEVIO) != 0);
  1996.     psdp->optLog = ((flShutdown & XSD_LOG) != 0);
  1997.  
  1998.     /* if (psdp->optReboot)
  1999.         // animate on reboot? V0.9.3 (2000-05-22) [umoeller]
  2000.         psdp->optAnimate = ((flShutdown & XSD_ANIMATE_REBOOT) != 0);
  2001.     else
  2002.         psdp->optAnimate = ((flShutdown & XSD_ANIMATE_SHUTDOWN) != 0);
  2003.        */
  2004.  
  2005.     psdp->optAPMPowerOff = (  ((flShutdown & XSD_APMPOWEROFF) != 0)
  2006.                       && (apmPowerOffSupported())
  2007.                      );
  2008.     psdp->optAPMDelay = ((flShutdown & XSD_APM_DELAY) != 0);
  2009.  
  2010.     psdp->optWPSReuseStartupFolder = psdp->optWPSCloseWindows;
  2011.  
  2012.     psdp->optEmptyTrashCan = ((flShutdown & XSD_EMPTY_TRASH) != 0);
  2013.  
  2014.     psdp->optWarpCenterFirst = ((flShutdown & XSD_WARPCENTERFIRST) != 0);
  2015.  
  2016.     psdp->szRebootCommand[0] = 0;
  2017. }
  2018.  
  2019. /*
  2020.  *@@ xsdIsShutdownRunning:
  2021.  *      returns the XSD_* value that represents
  2022.  *      the current shutdown state:
  2023.  *
  2024.  *      --  XSD_IDLE                0
  2025.  *      --  XSD_CONFIRMING          1
  2026.  *      --  XSD_CLOSING             2
  2027.  *      --  XSD_CANCELLED           3
  2028.  *      --  XSD_ALLCLOSED_SAVING    4
  2029.  *      --  XSD_SAVEDONE_FLUSHING   5
  2030.  *
  2031.  *@@added V0.9.19 (2002-04-24) [umoeller]
  2032.  */
  2033.  
  2034. ULONG xsdQueryShutdownState(VOID)
  2035. {
  2036.     return G_ulShutdownState;
  2037. }
  2038.  
  2039. /*
  2040.  *@@ StartShutdownThread:
  2041.  *      starts the Shutdown thread with the specified
  2042.  *      parameters.
  2043.  *
  2044.  *@@added V0.9.9 (2001-03-07) [umoeller]
  2045.  */
  2046.  
  2047. static VOID StartShutdownThread(BOOL fStartShutdown,
  2048.                                 BOOL fPlayRestartDesktopSound,     // in: else: play shutdown sound
  2049.                                 PSHUTDOWNPARAMS psdp)
  2050. {
  2051.     if (psdp)
  2052.     {
  2053.         if (fStartShutdown)
  2054.         {
  2055.             // everything OK: create shutdown thread,
  2056.             // which will handle the rest
  2057.             thrCreate(&G_tiShutdownThread,
  2058.                       fntShutdownThread,
  2059.                       NULL, // running flag
  2060.                       "Shutdown",
  2061.                       THRF_PMMSGQUEUE,    // changed V0.9.12 (2001-05-29) [umoeller]
  2062.                       (ULONG)psdp);           // pass SHUTDOWNPARAMS to thread
  2063. #ifndef __NOXSYSTEMSOUNDS__
  2064.             cmnPlaySystemSound(fPlayRestartDesktopSound
  2065.                                     ? MMSOUND_XFLD_RESTARTWPS
  2066.                                     : MMSOUND_XFLD_SHUTDOWN);
  2067. #endif
  2068.  
  2069.             return;
  2070.         }
  2071.         else
  2072.             free(psdp);     // fixed V0.9.1 (99-12-12)
  2073.     }
  2074.  
  2075.     G_ulShutdownState = XSD_IDLE; // V0.9.19 (2002-04-24) [umoeller]
  2076. }
  2077.  
  2078. /*
  2079.  *@@ xsdInitiateShutdown:
  2080.  *      common shutdown entry point; checks sflXShutdown
  2081.  *      for all the XSD_* flags (shutdown options).
  2082.  *      If compiled with XFLDR_DEBUG defined (in common.h),
  2083.  *      debug mode will also be turned on if the SHIFT key is
  2084.  *      pressed at call time (that is, when the menu item is
  2085.  *      selected).
  2086.  *
  2087.  *      This routine will display a confirmation box,
  2088.  *      if the settings want it, and then start the
  2089.  *      main shutdown thread (xsd_fntShutdownThread),
  2090.  *      which will keep running even after shutdown
  2091.  *      is complete, unless the user presses the
  2092.  *      "Cancel shutdown" button.
  2093.  *
  2094.  *      Although this method does return almost
  2095.  *      immediately (after the confirmation dlg is dismissed),
  2096.  *      the shutdown will proceed in the separate thread
  2097.  *      after this function returns.
  2098.  *
  2099.  *@@changed V0.9.0 [umoeller]: global SHUTDOWNPARAMS removed
  2100.  *@@changed V0.9.0 [umoeller]: this used to be an XFldDesktop instance method
  2101.  *@@changed V0.9.1 (99-12-10) [umoeller]: fixed KERNELGLOBALS locks
  2102.  *@@changed V0.9.1 (99-12-12) [umoeller]: fixed memory leak when shutdown was cancelled
  2103.  *@@changed V0.9.3 (2000-05-22) [umoeller]: added animate on reboot
  2104.  *@@changed V0.9.4 (2000-08-03) [umoeller]: added "empty trash can"
  2105.  *@@changed V0.9.11 (2001-04-25) [umoeller]: changed pending spool jobs msg to always abort now
  2106.  */
  2107.  
  2108. BOOL xsdInitiateShutdown(VOID)
  2109. {
  2110.     BOOL                fStartShutdown = TRUE;
  2111.     PSHUTDOWNPARAMS     psdp = (PSHUTDOWNPARAMS)malloc(sizeof(SHUTDOWNPARAMS));
  2112.  
  2113.     if (G_ulShutdownState != XSD_IDLE)
  2114.         // shutdown thread already running: return!
  2115.         fStartShutdown = FALSE;
  2116.  
  2117.     // lock shutdown menu items
  2118.     G_ulShutdownState = XSD_CONFIRMING;
  2119.  
  2120.     if (fStartShutdown)
  2121.     {
  2122.         ULONG flShutdown = 0;
  2123. #ifndef __NOXSHUTDOWN__
  2124.         flShutdown = cmnQuerySetting(sflXShutdown);
  2125. #endif
  2126.  
  2127.         memset(psdp, 0, sizeof(SHUTDOWNPARAMS));
  2128.         psdp->optReboot = ((flShutdown & XSD_REBOOT) != 0);
  2129.         // psdp->ulRestartWPS = 0;
  2130.         psdp->ulCloseMode = SHUT_SHUTDOWN;
  2131.         psdp->optWPSCloseWindows = TRUE;
  2132.         psdp->optWPSReuseStartupFolder = psdp->optWPSCloseWindows;
  2133.         psdp->optConfirm = (!(flShutdown & XSD_NOCONFIRM));
  2134.         psdp->optAutoCloseVIO = ((flShutdown & XSD_AUTOCLOSEVIO) != 0);
  2135.         psdp->optWarpCenterFirst = ((flShutdown & XSD_WARPCENTERFIRST) != 0);
  2136.         psdp->optLog = ((flShutdown & XSD_LOG) != 0);
  2137.         /* if (psdp->optReboot)
  2138.             // animate on reboot? V0.9.3 (2000-05-22) [umoeller]
  2139.             psdp->optAnimate = ((flShutdown & XSD_ANIMATE_REBOOT) != 0);
  2140.         else
  2141.             psdp->optAnimate = ((flShutdown & XSD_ANIMATE_SHUTDOWN) != 0);
  2142.            */
  2143.  
  2144.         psdp->optAPMPowerOff = (  ((flShutdown & XSD_APMPOWEROFF) != 0)
  2145.                           && (apmPowerOffSupported())
  2146.                          );
  2147.         psdp->optAPMDelay = ((flShutdown & XSD_APM_DELAY) != 0);
  2148.         #ifdef DEBUG_SHUTDOWN
  2149.             psdp->optDebug = doshQueryShiftState();
  2150.         #else
  2151.             psdp->optDebug = FALSE;
  2152.         #endif
  2153.  
  2154.         psdp->optEmptyTrashCan = ((flShutdown & XSD_EMPTY_TRASH) != 0);
  2155.  
  2156.         psdp->szRebootCommand[0] = 0;
  2157.  
  2158.         if (psdp->optConfirm)
  2159.         {
  2160.             ULONG ulReturn = xsdConfirmShutdown(psdp);
  2161.             if (ulReturn != DID_OK)
  2162.                 fStartShutdown = FALSE;
  2163.         }
  2164.  
  2165.         if (fStartShutdown)
  2166.         {
  2167.             // check for pending spool jobs
  2168.             ULONG ulSpooled;
  2169.             if (ulSpooled = winhQueryPendingSpoolJobs())
  2170.             {
  2171.                 // if we have any, issue a warning message and
  2172.                 // tell the user to remove print jobs
  2173.                 CHAR szTemp[20];
  2174.                 PCSZ pTable[1];
  2175.                 sprintf(szTemp, "%d", ulSpooled);
  2176.                 pTable[0] = szTemp;
  2177.                 cmnMessageBoxExt(HWND_DESKTOP,
  2178.                                     114,
  2179.                                     pTable,
  2180.                                     1,
  2181.                                     115,            // tmf file updated V0.9.11 (2001-04-25) [umoeller]
  2182.                                     MB_CANCEL);
  2183.                 // changed this V0.9.11 (2001-04-25) [umoeller]:
  2184.                 // never allow the user to continue here... we used
  2185.                 // to have a yesno box here, but apparently continuing
  2186.                 // here hangs the system, so I changed the message to
  2187.                 // "please remove print jobs from the spooler".
  2188.                 fStartShutdown = FALSE;
  2189.             }
  2190.         }
  2191.     }
  2192.  
  2193.     StartShutdownThread(fStartShutdown,
  2194.                         FALSE,  // fPlayRestartDesktopSound
  2195.                         psdp);
  2196.  
  2197.     return (fStartShutdown);
  2198. }
  2199.  
  2200. /*
  2201.  *@@ xsdInitiateRestartWPS:
  2202.  *      pretty similar to xsdInitiateShutdown, i.e. this
  2203.  *      will also show a confirmation box and start the Shutdown
  2204.  *      thread, except that flags are set differently so that
  2205.  *      after closing all windows, no shutdown is performed, but
  2206.  *      only the WPS is restarted.
  2207.  *
  2208.  *@@changed V0.9.0 [umoeller]: global SHUTDOWNPARAMS removed
  2209.  *@@changed V0.9.0 [umoeller]: this used to be an XFldDesktop instance method
  2210.  *@@changed V0.9.1 (99-12-10) [umoeller]: fixed KERNELGLOBALS locks
  2211.  *@@changed V0.9.1 (99-12-12) [umoeller]: fixed memory leak when shutdown was cancelled
  2212.  *@@changed V0.9.5 (2000-08-10) [umoeller]: added logoff support
  2213.  *@@changed V0.9.7 (2001-01-25) [umoeller]: this played the wrong sound, fixed
  2214.  */
  2215.  
  2216. BOOL xsdInitiateRestartWPS(BOOL fLogoff)        // in: if TRUE, perform logoff also
  2217. {
  2218.     BOOL                fStartShutdown = TRUE;
  2219.     PSHUTDOWNPARAMS     psdp = (PSHUTDOWNPARAMS)malloc(sizeof(SHUTDOWNPARAMS));
  2220.  
  2221.     if (G_ulShutdownState != XSD_IDLE)
  2222.         // shutdown thread already running: return!
  2223.         fStartShutdown = FALSE;
  2224.  
  2225.     // lock shutdown menu items
  2226.     G_ulShutdownState = XSD_CONFIRMING;
  2227.  
  2228.     if (fStartShutdown)
  2229.     {
  2230.         ULONG flShutdown = 0;
  2231. #ifndef __NOXSHUTDOWN__
  2232.         flShutdown = cmnQuerySetting(sflXShutdown);
  2233. #endif
  2234.  
  2235.         memset(psdp, 0, sizeof(SHUTDOWNPARAMS));
  2236.         psdp->optReboot =  FALSE;
  2237.         // psdp->ulRestartWPS = (fLogoff) ? 2 : 1; // V0.9.5 (2000-08-10) [umoeller]
  2238.         psdp->ulCloseMode = (fLogoff) ? SHUT_LOGOFF : SHUT_RESTARTWPS;
  2239.         psdp->optWPSCloseWindows = ((flShutdown & XSD_WPS_CLOSEWINDOWS) != 0);
  2240.         psdp->optWPSReuseStartupFolder = psdp->optWPSCloseWindows;
  2241.         psdp->optConfirm = (!(flShutdown & XSD_NOCONFIRM));
  2242.         psdp->optAutoCloseVIO = ((flShutdown & XSD_AUTOCLOSEVIO) != 0);
  2243.         psdp->optWarpCenterFirst = ((flShutdown & XSD_WARPCENTERFIRST) != 0);
  2244.         psdp->optLog =  ((flShutdown & XSD_LOG) != 0);
  2245.         #ifdef DEBUG_SHUTDOWN
  2246.             psdp->optDebug = doshQueryShiftState();
  2247.         #else
  2248.             psdp->optDebug = FALSE;
  2249.         #endif
  2250.  
  2251.         if (psdp->optConfirm)
  2252.         {
  2253.             ULONG ulReturn = xsdConfirmRestartWPS(psdp);
  2254.             if (ulReturn != DID_OK)
  2255.                 fStartShutdown = FALSE;
  2256.         }
  2257.     }
  2258.  
  2259.     StartShutdownThread(fStartShutdown,
  2260.                         TRUE,  // fPlayRestartDesktopSound
  2261.                         psdp);
  2262.  
  2263.     return (fStartShutdown);
  2264. }
  2265.  
  2266. /*
  2267.  *@@ xsdInitiateShutdownExt:
  2268.  *      just like the XFldDesktop method, but this one
  2269.  *      allows setting all the shutdown parameters by
  2270.  *      using the SHUTDOWNPARAMS structure. This is used
  2271.  *      for calling XShutdown externally, which is done
  2272.  *      by sending T1M_EXTERNALSHUTDOWN to the thread-1
  2273.  *      object window (see kernel.c).
  2274.  *
  2275.  *      NOTE: The memory block pointed to by psdp is
  2276.  *      not released by this function.
  2277.  *
  2278.  *@@changed V0.9.2 (2000-02-28) [umoeller]: fixed KERNELGLOBALS locks
  2279.  *@@changed V0.9.7 (2001-01-25) [umoeller]: rearranged for setup strings
  2280.  */
  2281.  
  2282. BOOL xsdInitiateShutdownExt(PSHUTDOWNPARAMS psdpShared)
  2283. {
  2284.     BOOL                fStartShutdown = TRUE;
  2285.     PSHUTDOWNPARAMS     psdpNew = NULL;
  2286.  
  2287.     if (G_ulShutdownState != XSD_IDLE)
  2288.         // shutdown thread already running: return!
  2289.         fStartShutdown = FALSE;
  2290.  
  2291.     // lock shutdown menu items
  2292.     G_ulShutdownState = XSD_CONFIRMING;
  2293.  
  2294.     if (psdpShared == NULL)
  2295.         fStartShutdown = FALSE;
  2296.  
  2297.     if (fStartShutdown)
  2298.     {
  2299.         psdpNew = (PSHUTDOWNPARAMS)malloc(sizeof(SHUTDOWNPARAMS));
  2300.         if (!psdpNew)
  2301.             fStartShutdown = FALSE;
  2302.         else
  2303.         {
  2304.             memcpy(psdpNew, psdpShared, sizeof(SHUTDOWNPARAMS));
  2305.  
  2306.             if (psdpNew->optConfirm)
  2307.             {
  2308.                 // confirmations are on: display proper
  2309.                 // confirmation dialog
  2310.                 ULONG ulReturn;
  2311.                 if (psdpNew->ulCloseMode != SHUT_SHUTDOWN)
  2312.                     ulReturn = xsdConfirmRestartWPS(psdpNew);
  2313.                 else
  2314.                     ulReturn = xsdConfirmShutdown(psdpNew);
  2315.  
  2316.                 if (ulReturn != DID_OK)
  2317.                     fStartShutdown = FALSE;
  2318.             }
  2319.         }
  2320.     }
  2321.  
  2322.     StartShutdownThread(fStartShutdown,
  2323.                         FALSE,  // fPlayRestartDesktopSound
  2324.                         psdpNew);
  2325.  
  2326.     return (fStartShutdown);
  2327. }
  2328.  
  2329. /* ******************************************************************
  2330.  *
  2331.  *   Shutdown settings pages
  2332.  *
  2333.  ********************************************************************/
  2334.  
  2335. #ifndef __NOXSHUTDOWN__
  2336.  
  2337. #define COLUMN_WIDTH        100
  2338.  
  2339. static const CONTROLDEF
  2340.     ShutdownGroup = LOADDEF_GROUP(ID_SDDI_SHUTDOWNGROUP, SZL_AUTOSIZE),
  2341.     RebootAfterwardsCB = CONTROLDEF_AUTOCHECKBOX(
  2342.                             LOAD_STRING, // "~Reboot afterwards"
  2343.                             ID_SDDI_REBOOT,
  2344.                             COLUMN_WIDTH,
  2345.                             -1),
  2346.     RebootActionsButton = CONTROLDEF_PUSHBUTTON(
  2347.                             LOAD_STRING, // "Reboot actio~ns..."
  2348.                             ID_SDDI_REBOOTEXT,
  2349.                             COLUMN_WIDTH,
  2350.                             STD_BUTTON_HEIGHT),
  2351.     CanDesktopAltF4 = LOADDEF_AUTOCHECKBOX(ID_SDDI_CANDESKTOPALTF4),
  2352.     AnimationTxt = LOADDEF_TEXT(ID_SDDI_ANIMATE_TXT),
  2353.     AnimationBeforeShutdownCB = LOADDEF_AUTOCHECKBOX(ID_SDDI_ANIMATE_SHUTDOWN),
  2354.     AnimationBeforeRebootCB = LOADDEF_AUTOCHECKBOX(ID_SDDI_ANIMATE_REBOOT),
  2355.     PowerOffCB = CONTROLDEF_AUTOCHECKBOX(
  2356.                             LOAD_STRING, // "Attempt APM ~1.2 power-off"
  2357.                             ID_SDDI_APMPOWEROFF,
  2358.                             COLUMN_WIDTH,
  2359.                             -1),
  2360.     PowerOffDelayCB = LOADDEF_AUTOCHECKBOX(ID_SDDI_DELAY),
  2361.     APMLevelText1 = CONTROLDEF_TEXT(
  2362.                             LOAD_STRING, // "APM level:"
  2363.                             ID_SDDI_APMVERSION_TXT,
  2364.                             COLUMN_WIDTH / 2,
  2365.                             -1),
  2366.     APMLevelText2 = LOADDEF_TEXT(ID_SDDI_APMVERSION),
  2367.     APMDriverText1 = CONTROLDEF_TEXT(
  2368.                             LOAD_STRING, // "APM.SYS driver:"
  2369.                             ID_SDDI_APMSYS_TXT,
  2370.                             COLUMN_WIDTH / 2,
  2371.                             -1),
  2372.     APMDriverText2 = LOADDEF_TEXT(ID_SDDI_APMSYS),
  2373. #ifndef __EASYSHUTDOWN__
  2374.     SaveINIFilesText = LOADDEF_TEXT(ID_SDDI_SAVEINIS_TXT),
  2375.     SaveINIFilesCombo =
  2376.         {
  2377.             WC_COMBOBOX,
  2378.             "",
  2379.             CBS_DROPDOWNLIST | LS_HORZSCROLL | WS_TABSTOP | WS_VISIBLE,
  2380.             ID_SDDI_SAVEINIS_LIST,
  2381.             CTL_COMMON_FONT,
  2382.             0,
  2383.             {150, 40},     // size adjusted for new combo box support in dialog.c
  2384.             COMMON_SPACING
  2385.         },
  2386. #endif
  2387.     SharedGroup = LOADDEF_GROUP(ID_SDDI_SHAREDGROUP, SZL_AUTOSIZE),
  2388.     EmptyTrashCB = LOADDEF_AUTOCHECKBOX(ID_SDDI_EMPTYTRASHCAN),
  2389.     ConfirmCB = LOADDEF_AUTOCHECKBOX(ID_SDDI_CONFIRM),
  2390.     WarpCenterFirstCB = LOADDEF_AUTOCHECKBOX(ID_SDDI_WARPCENTERFIRST),
  2391.     AutoCloseVIOCB = CONTROLDEF_AUTOCHECKBOX(
  2392.                             LOAD_STRING, // "Auto-close non-~PM sessions"
  2393.                             ID_SDDI_AUTOCLOSEVIO,
  2394.                             COLUMN_WIDTH,
  2395.                             -1),
  2396.     AutoCloseButton = CONTROLDEF_PUSHBUTTON(
  2397.                             LOAD_STRING, // "Auto-close det~ails..."
  2398.                             ID_SDDI_AUTOCLOSEDETAILS,
  2399.                             COLUMN_WIDTH,
  2400.                             STD_BUTTON_HEIGHT),
  2401.     LogCB = LOADDEF_AUTOCHECKBOX(ID_SDDI_LOG),
  2402.     CreateShutdownFldrButton = CONTROLDEF_PUSHBUTTON(
  2403.                             LOAD_STRING, // "Create XShutdown folder"
  2404.                             ID_SDDI_CREATESHUTDOWNFLDR,
  2405.                             -1,
  2406.                             STD_BUTTON_HEIGHT);
  2407.  
  2408. static const DLGHITEM dlgShutdown[] =
  2409.     {
  2410.         START_TABLE,            // root table, required
  2411.             START_ROW(0),       // shared settings group
  2412.                 START_GROUP_TABLE(&SharedGroup),
  2413.                     START_ROW(0),
  2414.                         CONTROL_DEF(&EmptyTrashCB),
  2415.                     START_ROW(0),
  2416.                         CONTROL_DEF(&ConfirmCB),
  2417.                     START_ROW(0),
  2418.                         CONTROL_DEF(&WarpCenterFirstCB),
  2419.                     START_ROW(ROW_VALIGN_CENTER),
  2420.                         CONTROL_DEF(&AutoCloseVIOCB),
  2421.                         CONTROL_DEF(&AutoCloseButton),
  2422.                     START_ROW(0),
  2423.                         CONTROL_DEF(&LogCB),
  2424.                     START_ROW(0),
  2425.                         CONTROL_DEF(&CreateShutdownFldrButton),
  2426.                 END_TABLE,      // end of group
  2427.             START_ROW(0),       // shutdown only group
  2428.                 // create group on top
  2429.                 START_GROUP_TABLE(&ShutdownGroup),
  2430.                     START_ROW(0),
  2431.                         CONTROL_DEF(&CanDesktopAltF4),
  2432.                     START_ROW(ROW_VALIGN_CENTER),
  2433.                         CONTROL_DEF(&RebootAfterwardsCB),
  2434.                         CONTROL_DEF(&RebootActionsButton),
  2435.                     START_ROW(0),
  2436.                         CONTROL_DEF(&AnimationTxt),
  2437.                         CONTROL_DEF(&AnimationBeforeShutdownCB),
  2438.                         CONTROL_DEF(&AnimationBeforeRebootCB),
  2439.                     START_ROW(0),
  2440.                         START_TABLE,
  2441.                             START_ROW(0),
  2442.                                 CONTROL_DEF(&PowerOffCB),
  2443.                             START_ROW(0),
  2444.                                 CONTROL_DEF(&G_Spacing),        // notebook.c
  2445.                                 CONTROL_DEF(&PowerOffDelayCB),
  2446.                         END_TABLE,
  2447.                         START_TABLE,
  2448.                             START_ROW(0),
  2449.                                 CONTROL_DEF(&APMLevelText1),
  2450.                                 CONTROL_DEF(&APMLevelText2),
  2451.                             START_ROW(0),
  2452.                                 CONTROL_DEF(&APMDriverText1),
  2453.                                 CONTROL_DEF(&APMDriverText2),
  2454.                         END_TABLE,
  2455. #ifndef __EASYSHUTDOWN__
  2456.                     START_ROW(ROW_VALIGN_CENTER),
  2457.                         CONTROL_DEF(&SaveINIFilesText),
  2458.                         CONTROL_DEF(&SaveINIFilesCombo),
  2459. #endif
  2460.                 END_TABLE,      // end of group
  2461.             START_ROW(0),       // notebook buttons (will be moved)
  2462.                 CONTROL_DEF(&G_UndoButton),         // common.c
  2463.                 CONTROL_DEF(&G_DefaultButton),      // common.c
  2464.                 CONTROL_DEF(&G_HelpButton),         // common.c
  2465.         END_TABLE
  2466.     };
  2467.  
  2468. static const XWPSETTING G_ShutdownBackup[] =
  2469.     {
  2470.         sflXShutdown,
  2471. #ifndef __EASYSHUTDOWN__
  2472.         sulSaveINIS,
  2473. #endif
  2474.     };
  2475.  
  2476. /*
  2477.  * xsdShutdownInitPage:
  2478.  *      notebook callback function (notebook.c) for the
  2479.  *      "XShutdown" page in the Desktop's settings
  2480.  *      notebook.
  2481.  *      Sets the controls on the page according to the
  2482.  *      Global Settings.
  2483.  *
  2484.  *@@added V0.9.0 [umoeller]
  2485.  *@@changed V0.9.2 (2000-03-04) [umoeller]: added "APM delay" support
  2486.  *@@changed V0.9.3 (2000-05-22) [umoeller]: added animate on reboot
  2487.  *@@changed V0.9.4 (2000-08-03) [umoeller]: added "empty trash can"
  2488.  *@@changed V0.9.9 (2001-04-07) [pr]: added missing Undo and Default processing
  2489.  *@@changed V0.9.16 (2001-10-08) [umoeller]: now using dialog formatter
  2490.  *@@changed V0.9.16 (2002-01-04) [umoeller]: added "alt+f4 on desktop starts shutdown"
  2491.  */
  2492.  
  2493. VOID xsdShutdownInitPage(PNOTEBOOKPAGE pnbp,   // notebook info struct
  2494.                          ULONG flFlags)        // CBI_* flags (notebook.h)
  2495. {
  2496.     ULONG fl = cmnQuerySetting(sflXShutdown);
  2497.  
  2498.     if (flFlags & CBI_INIT)
  2499.     {
  2500.         // PNLSSTRINGS pNLSStrings = cmnQueryNLSStrings();
  2501.         APIRET      arc = NO_ERROR;
  2502.         HWND        hwndINICombo = NULLHANDLE;
  2503.         ULONG       ul;
  2504.         PEXECUTABLE pExec;
  2505.         CHAR        szAPMVersion[30];
  2506.         CHAR        szAPMSysFile[CCHMAXPATH];
  2507.  
  2508.         ULONG       aulIniStrings[3] =
  2509.             {
  2510.                 ID_XSSI_XSD_SAVEINIS_NEW,   // pszXSDSaveInisNew
  2511.                 ID_XSSI_XSD_SAVEINIS_OLD,   // pszXSDSaveInisOld
  2512.                 ID_XSSI_XSD_SAVEINIS_NONE   // pszXSDSaveInisNone
  2513.             };
  2514.  
  2515.         // first call: backup Global Settings for "Undo" button;
  2516.         // this memory will be freed automatically by the
  2517.         // common notebook window function (notebook.c) when
  2518.         // the notebook page is destroyed
  2519.         pnbp->pUser = cmnBackupSettings(G_ShutdownBackup,
  2520.                                          ARRAYITEMCOUNT(G_ShutdownBackup));
  2521.  
  2522.         // insert the controls using the dialog formatter
  2523.         // V0.9.16 (2001-10-08) [umoeller]
  2524.         ntbFormatPage(pnbp->hwndDlgPage,
  2525.                       dlgShutdown,
  2526.                       ARRAYITEMCOUNT(dlgShutdown));
  2527.  
  2528.         sprintf(szAPMVersion, "APM %s", apmQueryVersion());
  2529.         WinSetDlgItemText(pnbp->hwndDlgPage, ID_SDDI_APMVERSION, szAPMVersion);
  2530.         sprintf(szAPMSysFile,
  2531.                 "%c:\\OS2\\BOOT\\APM.SYS",
  2532.                 doshQueryBootDrive());
  2533.         #ifdef DEBUG_SHUTDOWN
  2534.             _Pmpf(("Opening %s", szAPMSysFile));
  2535.         #endif
  2536.  
  2537.         WinSetDlgItemText(pnbp->hwndDlgPage, ID_SDDI_APMSYS,
  2538.                           "Error");
  2539.  
  2540.         if (!(arc = exehOpen(szAPMSysFile,
  2541.                                  &pExec)))
  2542.         {
  2543.             if (!(arc = exehQueryBldLevel(pExec)))
  2544.             {
  2545.                 if (pExec->pszVersion)
  2546.                     WinSetDlgItemText(pnbp->hwndDlgPage, ID_SDDI_APMSYS,
  2547.                                       pExec->pszVersion);
  2548.  
  2549.             }
  2550.  
  2551.             exehClose(&pExec);
  2552.         }
  2553.  
  2554. #ifndef __EASYSHUTDOWN__
  2555.         hwndINICombo = WinWindowFromID(pnbp->hwndDlgPage, ID_SDDI_SAVEINIS_LIST);
  2556.         for (ul = 0;
  2557.              ul < 3;
  2558.              ul++)
  2559.         {
  2560.             WinInsertLboxItem(hwndINICombo,
  2561.                               ul,
  2562.                               cmnGetString(aulIniStrings[ul]));
  2563.         }
  2564. #endif
  2565.     }
  2566.  
  2567.     if (flFlags & CBI_SET)
  2568.     {
  2569.         winhSetDlgItemChecked(pnbp->hwndDlgPage, ID_SDDI_REBOOT,
  2570.                               (fl & XSD_REBOOT) != 0);
  2571.         winhSetDlgItemChecked(pnbp->hwndDlgPage, ID_SDDI_CANDESKTOPALTF4,
  2572.                               (fl & XSD_CANDESKTOPALTF4) != 0);
  2573.         winhSetDlgItemChecked(pnbp->hwndDlgPage, ID_SDDI_ANIMATE_SHUTDOWN,
  2574.                               (fl & XSD_ANIMATE_SHUTDOWN) != 0);
  2575.         winhSetDlgItemChecked(pnbp->hwndDlgPage, ID_SDDI_ANIMATE_REBOOT,
  2576.                               (fl & XSD_ANIMATE_REBOOT) != 0);
  2577.         winhSetDlgItemChecked(pnbp->hwndDlgPage, ID_SDDI_APMPOWEROFF,
  2578.                               (apmPowerOffSupported())
  2579.                                   ? ((fl & XSD_APMPOWEROFF) != 0)
  2580.                                   : FALSE
  2581.                               );
  2582.         winhSetDlgItemChecked(pnbp->hwndDlgPage, ID_SDDI_DELAY,
  2583.                               (fl & XSD_APM_DELAY) != 0);
  2584.         winhSetDlgItemChecked(pnbp->hwndDlgPage, ID_SDDI_EMPTYTRASHCAN,
  2585.                               (fl & XSD_EMPTY_TRASH) != 0);
  2586.         winhSetDlgItemChecked(pnbp->hwndDlgPage, ID_SDDI_CONFIRM,
  2587.                               ((fl & XSD_NOCONFIRM) == 0));
  2588.         winhSetDlgItemChecked(pnbp->hwndDlgPage, ID_SDDI_AUTOCLOSEVIO,
  2589.                               (fl & XSD_AUTOCLOSEVIO) != 0);
  2590.         winhSetDlgItemChecked(pnbp->hwndDlgPage, ID_SDDI_WARPCENTERFIRST,
  2591.                               (fl & XSD_WARPCENTERFIRST) != 0);
  2592.         winhSetDlgItemChecked(pnbp->hwndDlgPage, ID_SDDI_LOG,
  2593.                               (fl & XSD_LOG) != 0);
  2594.  
  2595. #ifndef __EASYSHUTDOWN__
  2596.         WinSendDlgItemMsg(pnbp->hwndDlgPage, ID_SDDI_SAVEINIS_LIST,
  2597.                           LM_SELECTITEM,
  2598.                           (MPARAM)(cmnQuerySetting(sulSaveINIS)),
  2599.                           (MPARAM)TRUE);        // select
  2600. #endif
  2601.     }
  2602.  
  2603.     if (flFlags & CBI_ENABLE)
  2604.     {
  2605.         PCKERNELGLOBALS pKernelGlobals = krnQueryGlobals();
  2606.         BOOL fXShutdownValid = TRUE; // (cmnQuerySetting(sNoWorkerThread) == 0);
  2607.         BOOL fXShutdownEnabled =
  2608.                 (   (fXShutdownValid)
  2609.                  && (cmnQuerySetting(sfXShutdown))
  2610.                 );
  2611.         BOOL fXShutdownOrWPSValid =
  2612.                 (   (   (cmnQuerySetting(sfXShutdown))
  2613.                      || (cmnQuerySetting(sfRestartDesktop))
  2614.                     )
  2615.                  // && (cmnQuerySetting(sNoWorkerThread) == 0)
  2616.                 );
  2617.  
  2618.         // WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_ENABLED, fXShutdownValid);
  2619.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_CANDESKTOPALTF4, fXShutdownEnabled);
  2620.  
  2621.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_REBOOT,  fXShutdownEnabled);
  2622.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_REBOOTEXT, fXShutdownEnabled);
  2623.  
  2624.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_ANIMATE_SHUTDOWN, fXShutdownEnabled);
  2625.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_ANIMATE_REBOOT, fXShutdownEnabled);
  2626.  
  2627.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_APMPOWEROFF,
  2628.                           ( fXShutdownEnabled && apmPowerOffSupported() ) );
  2629.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_DELAY,
  2630.                           (      fXShutdownEnabled
  2631.                               && (apmPowerOffSupported())
  2632.                               && ((fl & XSD_APMPOWEROFF) != 0)
  2633.                           ));
  2634.  
  2635.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_EMPTYTRASHCAN,
  2636.                           ( fXShutdownEnabled && (cmnTrashCanReady()) ) );
  2637.  
  2638.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_CONFIRM, fXShutdownOrWPSValid);
  2639.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_AUTOCLOSEVIO, fXShutdownOrWPSValid);
  2640.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_AUTOCLOSEDETAILS, fXShutdownOrWPSValid);
  2641.  
  2642.         // enable "warpcenter first" if shutdown or WPS have been enabled
  2643.         // AND if the WarpCenter was found
  2644.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_WARPCENTERFIRST,
  2645.                          (    (fXShutdownOrWPSValid)
  2646.                            && (G_pAwakeWarpCenter != NULL)
  2647.                                     // global variable (xfobj.c, kernel.h) V0.9.20 (2002-07-25) [umoeller]
  2648.                          ));
  2649.  
  2650.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_LOG, fXShutdownOrWPSValid);
  2651.  
  2652. #ifndef __EASYSHUTDOWN__
  2653.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_SAVEINIS_TXT, fXShutdownEnabled);
  2654.         WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_SAVEINIS_LIST, fXShutdownEnabled);
  2655. #endif
  2656.  
  2657.         if (WinQueryObject((PSZ)XFOLDER_SHUTDOWNID))
  2658.             // shutdown folder exists already: disable button
  2659.             WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_CREATESHUTDOWNFLDR, FALSE);
  2660.     }
  2661. }
  2662.  
  2663. /*
  2664.  * xsdShutdownItemChanged:
  2665.  *      notebook callback function (notebook.c) for the
  2666.  *      "XShutdown" page in the Desktop's settings
  2667.  *      notebook.
  2668.  *      Reacts to changes of any of the dialog controls.
  2669.  *
  2670.  *@@added V0.9.0 [umoeller]
  2671.  *@@changed V0.9.2 (2000-03-04) [umoeller]: added "APM delay" support
  2672.  *@@changed V0.9.3 (2000-05-22) [umoeller]: added animate on reboot
  2673.  *@@changed V0.9.4 (2000-08-03) [umoeller]: added "empty trash can"
  2674.  *@@changed V0.9.9 (2001-04-07) [pr]: added missing Undo and Default processing
  2675.  */
  2676.  
  2677. MRESULT xsdShutdownItemChanged(PNOTEBOOKPAGE pnbp,
  2678.                                ULONG ulItemID,
  2679.                                USHORT usNotifyCode,
  2680.                                ULONG ulExtra)      // for checkboxes: contains new state
  2681. {
  2682.     ULONG ulChange = 1;
  2683.     ULONG ulFlag = -1;
  2684. #ifndef __EASYSHUTDOWN__
  2685.     ULONG ulSaveINIS = -1;
  2686. #endif
  2687.  
  2688.     switch (ulItemID)
  2689.     {
  2690.         case ID_SDDI_REBOOT:
  2691.             ulFlag = XSD_REBOOT;
  2692.         break;
  2693.  
  2694.         case ID_SDDI_CANDESKTOPALTF4:
  2695.             ulFlag = XSD_CANDESKTOPALTF4;
  2696.         break;
  2697.  
  2698.         case ID_SDDI_ANIMATE_SHUTDOWN:
  2699.             ulFlag = XSD_ANIMATE_SHUTDOWN;
  2700.         break;
  2701.  
  2702.         case ID_SDDI_ANIMATE_REBOOT:
  2703.             ulFlag = XSD_ANIMATE_REBOOT;
  2704.         break;
  2705.  
  2706.         case ID_SDDI_APMPOWEROFF:
  2707.             ulFlag = XSD_APMPOWEROFF;
  2708.         break;
  2709.  
  2710.         case ID_SDDI_DELAY:
  2711.             ulFlag = XSD_APM_DELAY;
  2712.         break;
  2713.  
  2714.         case ID_SDDI_EMPTYTRASHCAN:
  2715.             ulFlag = XSD_EMPTY_TRASH;
  2716.         break;
  2717.  
  2718.         case ID_SDDI_CONFIRM:
  2719.             ulFlag = XSD_NOCONFIRM;
  2720.             ulExtra = 1 - ulExtra;          // this one is reverse now
  2721.                                             // V0.9.16 (2002-01-13) [umoeller]
  2722.         break;
  2723.  
  2724.         case ID_SDDI_AUTOCLOSEVIO:
  2725.             ulFlag = XSD_AUTOCLOSEVIO;
  2726.         break;
  2727.  
  2728.         case ID_SDDI_WARPCENTERFIRST:
  2729.             ulFlag = XSD_WARPCENTERFIRST;
  2730.         break;
  2731.  
  2732.         case ID_SDDI_LOG:
  2733.             ulFlag = XSD_LOG;
  2734.         break;
  2735.  
  2736. #ifndef __EASYSHUTDOWN__
  2737.         case ID_SDDI_SAVEINIS_LIST:
  2738.         {
  2739.             ULONG ul = (ULONG)WinSendDlgItemMsg(pnbp->hwndDlgPage, ID_SDDI_SAVEINIS_LIST,
  2740.                                                 LM_QUERYSELECTION,
  2741.                                                 MPFROMSHORT(LIT_FIRST),
  2742.                                                 0);
  2743.             if (ul >= 0 && ul <= 2)
  2744.                 ulSaveINIS = ul;
  2745.         }
  2746.         break;
  2747. #endif
  2748.  
  2749.         // Reboot Actions (Desktop page 1)
  2750.         case ID_SDDI_REBOOTEXT:
  2751.             WinDlgBox(HWND_DESKTOP,         // parent is desktop
  2752.                       pnbp->hwndFrame,                  // owner
  2753.                       (PFNWP)fnwpUserRebootOptions,     // dialog procedure
  2754.                       cmnQueryNLSModuleHandle(FALSE),
  2755.                       ID_XSD_REBOOTEXT,        // dialog resource id
  2756.                       (PVOID)NULL);            // no dialog parameters
  2757.             ulChange = 0;
  2758.         break;
  2759.  
  2760.         // Auto-close details (Desktop page 1)
  2761.         case ID_SDDI_AUTOCLOSEDETAILS:
  2762.             ShowAutoCloseDetails(pnbp->hwndFrame);
  2763.             /*
  2764.             WinDlgBox(HWND_DESKTOP,         // parent is desktop
  2765.                       pnbp->hwndFrame,             // owner
  2766.                       (PFNWP)fnwpAutoCloseDetails,    // dialog procedure
  2767.                       cmnQueryNLSModuleHandle(FALSE),  // from resource file
  2768.                       ID_XSD_AUTOCLOSE,        // dialog resource id
  2769.                       (PVOID)NULL);            // no dialog parameters
  2770.             */
  2771.             ulChange = 0;
  2772.         break;
  2773.  
  2774.         // "Create shutdown folder"
  2775.         case ID_SDDI_CREATESHUTDOWNFLDR:
  2776.         {
  2777.             CHAR    szSetup[500];
  2778.             HOBJECT hObj = 0;
  2779.             sprintf(szSetup,
  2780.                 "DEFAULTVIEW=ICON;ICONVIEW=NONFLOWED,MINI;"
  2781.                 "OBJECTID=%s;",
  2782.                 XFOLDER_SHUTDOWNID);
  2783.             if (hObj = WinCreateObject((PSZ)G_pcszXFldShutdown,
  2784.                                        "XFolder Shutdown",
  2785.                                        szSetup,
  2786.                                        (PSZ)WPOBJID_DESKTOP, // "<WP_DESKTOP>",
  2787.                                        CO_UPDATEIFEXISTS))
  2788.                 WinEnableControl(pnbp->hwndDlgPage, ID_SDDI_CREATESHUTDOWNFLDR, FALSE);
  2789.             else
  2790.                 cmnMessageBoxExt(pnbp->hwndFrame,
  2791.                                  104,
  2792.                                  NULL, 0,
  2793.                                  106,
  2794.                                  MB_OK);
  2795.             ulChange = 0;
  2796.         }
  2797.         break;
  2798.  
  2799.         case DID_UNDO:
  2800.             // "Undo" button: get pointer to backed-up Global Settings
  2801.             cmnRestoreSettings(pnbp->pUser,
  2802.                                ARRAYITEMCOUNT(G_ShutdownBackup));
  2803.             // update the display by calling the INIT callback
  2804.             pnbp->inbp.pfncbInitPage(pnbp, CBI_SET | CBI_ENABLE);
  2805.         break;
  2806.  
  2807.         case DID_DEFAULT:
  2808.             // set the default settings for this settings page
  2809.             // (this is in common.c because it's also used at
  2810.             // Desktop startup)
  2811.             cmnSetDefaultSettings(pnbp->inbp.ulPageID);
  2812.             // update the display by calling the INIT callback
  2813.             pnbp->inbp.pfncbInitPage(pnbp, CBI_SET | CBI_ENABLE);
  2814.         break;
  2815.  
  2816.         default:
  2817.             ulChange = 0;
  2818.     }
  2819.  
  2820.     if (   (ulFlag != -1)
  2821. #ifndef __EASYSHUTDOWN__
  2822.         || (ulSaveINIS != -1)
  2823. #endif
  2824.        )
  2825.     {
  2826.         if (ulFlag != -1)
  2827.         {
  2828.             ULONG flShutdown = cmnQuerySetting(sflXShutdown);
  2829.             if (ulExtra)
  2830.                 flShutdown |= ulFlag;
  2831.             else
  2832.                 flShutdown &= ~ulFlag;
  2833.             cmnSetSetting(sflXShutdown, flShutdown);
  2834.         }
  2835. #ifndef __EASYSHUTDOWN__
  2836.         if (ulSaveINIS != -1)
  2837.             cmnSetSetting(sulSaveINIS, ulSaveINIS);;
  2838. #endif
  2839.     }
  2840.  
  2841.     if (ulChange)
  2842.     {
  2843.         // enable/disable items
  2844.         xsdShutdownInitPage(pnbp, CBI_ENABLE);
  2845.     }
  2846.  
  2847.     return ((MPARAM)0);
  2848. }
  2849.  
  2850. #endif
  2851.  
  2852. /* ******************************************************************
  2853.  *
  2854.  *   Shutdown helper functions
  2855.  *
  2856.  ********************************************************************/
  2857.  
  2858. /*
  2859.  * xsdLog:
  2860.  *      common function for writing into the XSHUTDWN.LOG file.
  2861.  *
  2862.  *added V0.9.0 [umoeller]
  2863.  *removed V0.9.16 (2001-11-22) [umoeller]
  2864.  */
  2865.  
  2866. /* void xsdLog(FILE *File,
  2867.             const char* pcszFormatString,
  2868.             ...)
  2869. {
  2870.     if (File)
  2871.     {
  2872.         va_list vargs;
  2873.  
  2874.         DATETIME dt;
  2875.         // CHAR szTemp[2000];
  2876.         // ULONG   cbWritten;
  2877.         DosGetDateTime(&dt);
  2878.         fprintf(File, "Time: %02d:%02d:%02d.%02d ",
  2879.                 dt.hours, dt.minutes, dt.seconds, dt.hundredths);
  2880.  
  2881.         // get the variable parameters
  2882.         va_start(vargs, pcszFormatString);
  2883.         vfprintf(File, pcszFormatString, vargs);
  2884.         va_end(vargs);
  2885.         fflush(File);
  2886.     }
  2887. } */
  2888.  
  2889. /*
  2890.  *@@ xsdLoadAnimation:
  2891.  *      this loads the shutdown (traffic light) animation
  2892.  *      as an array of icons from the XFLDR.DLL module.
  2893.  */
  2894.  
  2895. VOID xsdLoadAnimation(PSHUTDOWNANIM psda)
  2896. {
  2897.     HMODULE hmod = cmnQueryMainResModuleHandle();
  2898.     (psda->ahptr)[0] = WinLoadPointer(HWND_DESKTOP, hmod, ID_ICONSDANIM1);
  2899.     (psda->ahptr)[1] = WinLoadPointer(HWND_DESKTOP, hmod, ID_ICONSDANIM2);
  2900.     (psda->ahptr)[2] = WinLoadPointer(HWND_DESKTOP, hmod, ID_ICONSDANIM3);
  2901.     (psda->ahptr)[3] = WinLoadPointer(HWND_DESKTOP, hmod, ID_ICONSDANIM4);
  2902.     (psda->ahptr)[4] = WinLoadPointer(HWND_DESKTOP, hmod, ID_ICONSDANIM5);
  2903.     (psda->ahptr)[5] = WinLoadPointer(HWND_DESKTOP, hmod, ID_ICONSDANIM4);
  2904.     (psda->ahptr)[6] = WinLoadPointer(HWND_DESKTOP, hmod, ID_ICONSDANIM3);
  2905.     (psda->ahptr)[7] = WinLoadPointer(HWND_DESKTOP, hmod, ID_ICONSDANIM2);
  2906. }
  2907.  
  2908. /*
  2909.  *@@ xsdFreeAnimation:
  2910.  *      this frees the animation loaded by xsdLoadAnimation.
  2911.  */
  2912.  
  2913. VOID xsdFreeAnimation(PSHUTDOWNANIM psda)
  2914. {
  2915.     USHORT us;
  2916.     for (us = 0; us < XSD_ANIM_COUNT; us++)
  2917.     {
  2918.         WinDestroyPointer((psda->ahptr)[us]);
  2919.         (psda->ahptr)[us] = NULLHANDLE;
  2920.     }
  2921. }
  2922.  
  2923. /*
  2924.  *@@ xsdRestartWPS:
  2925.  *      terminated the WPS process, which will lead
  2926.  *      to a Desktop restart.
  2927.  *
  2928.  *      If (fLogoff == TRUE), this will perform a logoff
  2929.  *      as well. If XWPShell is not running, this flag
  2930.  *      has no effect.
  2931.  *
  2932.  *      Runs on the Shutdown thread.
  2933.  *
  2934.  *@@changed V0.9.5 (2000-08-10) [umoeller]: added XWPSHELL.EXE interface
  2935.  */
  2936.  
  2937. VOID xsdRestartWPS(HAB hab,
  2938.                    BOOL fLogoff)    // in: if TRUE, perform logoff as well.
  2939. {
  2940.     ULONG ul;
  2941.  
  2942.     PCKERNELGLOBALS pcKernelGlobals = krnQueryGlobals();
  2943.  
  2944.     // wait a maximum of 2 seconds while there's still
  2945.     // a system sound playing
  2946.     for (ul = 0; ul < 20; ul++)
  2947.         if (xmmIsBusy())
  2948.             DosSleep(100);
  2949.         else
  2950.             break;
  2951.  
  2952.     // close leftover open devices
  2953.     xmmCleanup();
  2954.  
  2955.     if (pcKernelGlobals->pXWPShellShared)
  2956.     {
  2957.         // XWPSHELL.EXE running:
  2958.         PXWPSHELLSHARED pXWPShellShared
  2959.             = (PXWPSHELLSHARED)pcKernelGlobals->pXWPShellShared;
  2960.         // set flag in shared memory; XWPSHELL
  2961.         // will check this once the WPS has terminated
  2962.         pXWPShellShared->fNoLogonButRestart = !fLogoff;
  2963.     }
  2964.  
  2965.     // terminate the current process,
  2966.     // which is PMSHELL.EXE. We shouldn't use DosExit()
  2967.     // directly, because this might mess up the
  2968.     // C runtime library... even though this doesn't
  2969.     // help much with the rest of the WPS.
  2970.     exit(0);        // 0 == no error
  2971. }
  2972.  
  2973. /*
  2974.  *@@ xsdFlushWPS2INI:
  2975.  *      this forces the WPS to flush its internal buffers
  2976.  *      into OS2.INI/OS2SYS.INI. We call this function
  2977.  *      after we have closed all the WPS windows, before
  2978.  *      we actually save the INI files.
  2979.  *
  2980.  *      This undocumented semaphore was published in some
  2981.  *      newsgroup ages ago, I don't remember.
  2982.  *
  2983.  *      Returns APIRETs of event semaphore calls.
  2984.  *
  2985.  *@@added V0.9.0 (99-10-22) [umoeller]
  2986.  */
  2987.  
  2988. APIRET xsdFlushWPS2INI(VOID)
  2989. {
  2990.     APIRET arc  = 0;
  2991.     HEV hev = NULLHANDLE;
  2992.  
  2993.     if (!(arc = DosOpenEventSem("\\SEM32\\WORKPLAC\\LAZYWRIT.SEM", &hev)))
  2994.     {
  2995.         arc = DosPostEventSem(hev);
  2996.         DosCloseEventSem(hev);
  2997.     }
  2998.  
  2999.     return arc;
  3000. }
  3001.  
  3002. /* ******************************************************************
  3003.  *
  3004.  *   Additional declarations for Shutdown thread
  3005.  *
  3006.  ********************************************************************/
  3007.  
  3008. /*
  3009.  *@@ SHUTDOWNDATA:
  3010.  *      shutdown instance data allocated from the heap
  3011.  *      while the shutdown thread (fntShutdown) is
  3012.  *      running.
  3013.  *
  3014.  *      This replaces the sick set of global variables
  3015.  *      which used to be all over the place before V0.9.9
  3016.  *      and fixes a number of serialization problems on
  3017.  *      the way.
  3018.  *
  3019.  *@@added V0.9.9 (2001-03-07) [umoeller]
  3020.  */
  3021.  
  3022. typedef struct _SHUTDOWNDATA
  3023. {
  3024.     // shutdown parameters
  3025.     SHUTDOWNPARAMS  sdParams;
  3026.  
  3027.     ULONG           ulMaxItemCount,
  3028.                     ulLastItemCount;
  3029.  
  3030.     PXFILE          ShutdownLogFile;        // changed V0.9.16 (2001-11-22) [umoeller]
  3031.  
  3032.     HAB             habShutdownThread;
  3033.  
  3034.     HMODULE         hmodResource;
  3035.  
  3036.     HWND            hwndProgressBar;        // progress bar in status window
  3037.  
  3038.     // flags for whether we're currently owning semaphores
  3039.     BOOL            fShutdownSemOwned,
  3040.                     fSkippedSemOwned;
  3041.  
  3042.     ULONG           hPOC;
  3043.  
  3044.     // this is the global list of items to be closed (SHUTLISTITEMs)
  3045.     LINKLIST        llShutdown,
  3046.     // and the list of items that are to be skipped
  3047.                     llSkipped;
  3048.  
  3049.     HMTX            hmtxShutdown,
  3050.                     hmtxSkipped;
  3051.     HEV             hevUpdated;
  3052.  
  3053.     // temporary storage for closing VIOs
  3054.     CHAR            szVioTitle[1000];
  3055.     SHUTLISTITEM    VioItem;
  3056.  
  3057.     // global linked list of auto-close VIO windows (AUTOCLOSELISTITEM)
  3058.     LINKLIST        llAutoClose;
  3059.  
  3060.     ULONG           sidWPS,
  3061.                     sidPM;
  3062.  
  3063.     SHUTDOWNCONSTS  SDConsts;
  3064.  
  3065. } SHUTDOWNDATA, *PSHUTDOWNDATA;
  3066.  
  3067. VOID xsdFinishShutdown(PSHUTDOWNDATA pShutdownData);
  3068. VOID xsdFinishStandardMessage(PSHUTDOWNDATA pShutdownData);
  3069. VOID xsdFinishStandardReboot(PSHUTDOWNDATA pShutdownData);
  3070. VOID xsdFinishUserReboot(PSHUTDOWNDATA pShutdownData);
  3071. VOID xsdFinishAPMPowerOff(PSHUTDOWNDATA pShutdownData);
  3072.  
  3073. /* ******************************************************************
  3074.  *
  3075.  *   XShutdown data maintenance
  3076.  *
  3077.  ********************************************************************/
  3078.  
  3079. /*
  3080.  *@@ xsdGetShutdownConsts:
  3081.  *      prepares a number of constants in the specified
  3082.  *      SHUTDOWNCONSTS structure which are used throughout
  3083.  *      XShutdown.
  3084.  *
  3085.  *      SHUTDOWNCONSTS is part of SHUTDOWNDATA, so this
  3086.  *      func gets called once when fntShutdownThread starts
  3087.  *      up. However, since this is also used externally,
  3088.  *      we have put these fields into a separate structure.
  3089.  *
  3090.  *@@added V0.9.9 (2001-03-07) [umoeller]
  3091.  */
  3092.  
  3093. VOID xsdGetShutdownConsts(PSHUTDOWNCONSTS pConsts)
  3094. {
  3095.     XWPLOGGEDON lo;
  3096.  
  3097.     pConsts->pKernelGlobals = krnQueryGlobals();
  3098.     pConsts->pWPDesktop = _WPDesktop;
  3099.     pConsts->pActiveDesktop = _wpclsQueryActiveDesktop(pConsts->pWPDesktop);
  3100.     pConsts->hwndActiveDesktop = _wpclsQueryActiveDesktopHWND(pConsts->pWPDesktop);
  3101.     pConsts->hwndOpenWarpCenter = NULLHANDLE;
  3102.  
  3103.     WinQueryWindowProcess(pConsts->hwndActiveDesktop,
  3104.                           &pConsts->pidWPS,
  3105.                           NULL);
  3106.     WinQueryWindowProcess(HWND_DESKTOP,
  3107.                           &pConsts->pidPM,
  3108.                           NULL);
  3109.  
  3110.     if (G_pAwakeWarpCenter)     // global variable (xfobj.c, kernel.h) V0.9.20 (2002-07-25) [umoeller]
  3111.     {
  3112.         // WarpCenter is awake: check if it's open
  3113.         PUSEITEM pUseItem;
  3114.         for (pUseItem = _wpFindUseItem(G_pAwakeWarpCenter,
  3115.                                        USAGE_OPENVIEW,
  3116.                                        NULL);
  3117.              pUseItem;
  3118.              pUseItem = _wpFindUseItem(G_pAwakeWarpCenter,
  3119.                                        USAGE_OPENVIEW,
  3120.                                        pUseItem))
  3121.         {
  3122.             PVIEWITEM pViewItem = (PVIEWITEM)(pUseItem+1);
  3123.             if (pViewItem->view == OPEN_RUNNING)
  3124.             {
  3125.                 pConsts->hwndOpenWarpCenter = pViewItem->handle;
  3126.                 break;
  3127.             }
  3128.         }
  3129.     }
  3130.  
  3131.     // get uid and gid of currently logged on user, if xwpshell
  3132.     // is running V0.9.19 (2002-04-02) [umoeller]
  3133.     if (!xsecQueryLocalLoggedOn(&lo))
  3134.     {
  3135.         // running:
  3136.         // store uid
  3137.         pConsts->uid = lo.uid;
  3138.     }
  3139.     else
  3140.         pConsts->uid = -1;
  3141. }
  3142.  
  3143. /*
  3144.  *@@ xsdItemFromPID:
  3145.  *      searches a given LINKLIST of SHUTLISTITEMs
  3146.  *      for a process ID.
  3147.  *
  3148.  *@@changed V0.9.0 [umoeller]: adjusted for new linklist.c functions
  3149.  */
  3150.  
  3151. PSHUTLISTITEM xsdItemFromPID(PLINKLIST pList,
  3152.                              PID pid,
  3153.                              HMTX hmtx)
  3154. {
  3155.     PSHUTLISTITEM   pItem = NULL;
  3156.     BOOL            fAccess = FALSE,
  3157.                     fLocked = FALSE;
  3158.  
  3159.     TRY_QUIET(excpt1)
  3160.     {
  3161.         if (hmtx)
  3162.         {
  3163.             fLocked = !DosRequestMutexSem(hmtx, SEM_INDEFINITE_WAIT);
  3164.             fAccess = fLocked;
  3165.         }
  3166.         else
  3167.             fAccess = TRUE;
  3168.  
  3169.         if (fAccess)
  3170.         {
  3171.             PLISTNODE pNode = lstQueryFirstNode(pList);
  3172.             while (pNode)
  3173.             {
  3174.                 pItem = pNode->pItemData;
  3175.                 if (pItem->swctl.idProcess == pid)
  3176.                     break;
  3177.  
  3178.                 pNode = pNode->pNext;
  3179.                 pItem = 0;
  3180.             }
  3181.         }
  3182.     }
  3183.     CATCH(excpt1) { } END_CATCH();
  3184.  
  3185.     if (fLocked)
  3186.         DosReleaseMutexSem(hmtx);
  3187.  
  3188.     return (pItem);
  3189. }
  3190.  
  3191. /*
  3192.  *@@ xsdItemFromSID:
  3193.  *      searches a given LINKLIST of SHUTLISTITEMs
  3194.  *      for a session ID.
  3195.  *
  3196.  *@@changed V0.9.0 [umoeller]: adjusted for new linklist.c functions
  3197.  */
  3198.  
  3199. PSHUTLISTITEM xsdItemFromSID(PLINKLIST pList,
  3200.                              ULONG sid,
  3201.                              HMTX hmtx,
  3202.                              ULONG ulTimeout)
  3203. {
  3204.     PSHUTLISTITEM pItem = NULL;
  3205.     BOOL          fAccess = FALSE,
  3206.                   fLocked = FALSE;
  3207.  
  3208.     TRY_QUIET(excpt1)
  3209.     {
  3210.         if (hmtx)
  3211.         {
  3212.             fLocked = !DosRequestMutexSem(hmtx, ulTimeout);
  3213.             fAccess = fLocked;
  3214.         }
  3215.         else
  3216.             fAccess = TRUE;
  3217.  
  3218.         if (fAccess)
  3219.         {
  3220.             PLISTNODE pNode = lstQueryFirstNode(pList);
  3221.             while (pNode)
  3222.             {
  3223.                 pItem = pNode->pItemData;
  3224.                 if (pItem->swctl.idSession == sid)
  3225.                     break;
  3226.  
  3227.                 pNode = pNode->pNext;
  3228.                 pItem = 0;
  3229.             }
  3230.         }
  3231.     }
  3232.     CATCH(excpt1) { } END_CATCH();
  3233.  
  3234.     if (fLocked)
  3235.         DosReleaseMutexSem(hmtx);
  3236.  
  3237.     return (pItem);
  3238. }
  3239.  
  3240. /*
  3241.  *@@ xsdCountRemainingItems:
  3242.  *      counts the items left to be closed by counting
  3243.  *      the window list items and subtracting the items
  3244.  *      which were skipped by the user.
  3245.  *
  3246.  *@@changed V0.9.0 [umoeller]: adjusted for new linklist.c functions
  3247.  *@@changed V0.9.20 (2002-07-22) [umoeller]: fixed mutex release order
  3248.  */
  3249.  
  3250. ULONG xsdCountRemainingItems(PSHUTDOWNDATA pData)
  3251. {
  3252.     ULONG   ulrc = 0;
  3253.     BOOL    fShutdownSemOwned = FALSE,
  3254.             fSkippedSemOwned = FALSE;
  3255.  
  3256.     TRY_QUIET(excpt1)
  3257.     {
  3258.         if (    (fShutdownSemOwned = !DosRequestMutexSem(pData->hmtxShutdown, 4000))
  3259.              && (fSkippedSemOwned = !DosRequestMutexSem(pData->hmtxSkipped, 4000))
  3260.            )
  3261.             ulrc = (
  3262.                         lstCountItems(&pData->llShutdown)
  3263.                       - lstCountItems(&pData->llSkipped)
  3264.                    );
  3265.     }
  3266.     CATCH(excpt1) { } END_CATCH();
  3267.  
  3268.     // fixed release order V0.9.20 (2002-07-22) [umoeller]
  3269.     if (fSkippedSemOwned)
  3270.         DosReleaseMutexSem(pData->hmtxSkipped);
  3271.  
  3272.     if (fShutdownSemOwned)
  3273.         DosReleaseMutexSem(pData->hmtxShutdown);
  3274.  
  3275.     return (ulrc);
  3276. }
  3277.  
  3278. /*
  3279.  *@@ xsdLongTitle:
  3280.  *      creates a descriptive string in pszTitle from pItem
  3281.  *      (for the main (debug) window listbox).
  3282.  */
  3283.  
  3284. void xsdLongTitle(PSZ pszTitle,
  3285.                   PSHUTLISTITEM pItem)
  3286. {
  3287.     sprintf(pszTitle, "%s%s",
  3288.             pItem->swctl.szSwtitle,
  3289.             (pItem->swctl.uchVisibility == SWL_VISIBLE)
  3290.                 ? (", visible")
  3291.                 : ("")
  3292.         );
  3293.  
  3294.     strcat(pszTitle, ", ");
  3295.     switch (pItem->swctl.bProgType)
  3296.     {
  3297.         case PROG_DEFAULT: strcat(pszTitle, "default"); break;
  3298.         case PROG_FULLSCREEN: strcat(pszTitle, "OS/2 FS"); break;
  3299.         case PROG_WINDOWABLEVIO: strcat(pszTitle, "OS/2 win"); break;
  3300.         case PROG_PM:
  3301.             strcat(pszTitle, "PM, class: ");
  3302.             strcat(pszTitle, pItem->szClass);
  3303.         break;
  3304.         case PROG_VDM: strcat(pszTitle, "VDM"); break;
  3305.         case PROG_WINDOWEDVDM: strcat(pszTitle, "VDM win"); break;
  3306.         default:
  3307.             sprintf(pszTitle+strlen(pszTitle), "? (%lX)");
  3308.         break;
  3309.     }
  3310.     sprintf(pszTitle+strlen(pszTitle),
  3311.             ", hwnd: 0x%lX, pid: 0x%lX, sid: 0x%lX, pObj: 0x%lX",
  3312.             (ULONG)pItem->swctl.hwnd,
  3313.             (ULONG)pItem->swctl.idProcess,
  3314.             (ULONG)pItem->swctl.idSession,
  3315.             (ULONG)pItem->pObject
  3316.         );
  3317. }
  3318.  
  3319. /*
  3320.  *@@ xsdQueryCurrentItem:
  3321.  *      returns the next PSHUTLISTITEM to be
  3322.  *      closed (skipping the items that were
  3323.  *      marked to be skipped).
  3324.  *
  3325.  *@@changed V0.9.0 [umoeller]: adjusted for new linklist.c functions
  3326.  *@@changed V0.9.20 (2002-07-22) [umoeller]: fixed mutex release order
  3327.  */
  3328.  
  3329. PSHUTLISTITEM xsdQueryCurrentItem(PSHUTDOWNDATA pData)
  3330. {
  3331.     CHAR            szShutItem[1000],
  3332.                     szSkipItem[1000];
  3333.     BOOL            fShutdownSemOwned = FALSE,
  3334.                     fSkippedSemOwned = FALSE;
  3335.     PSHUTLISTITEM   pliShutItem = 0;
  3336.  
  3337.     TRY_QUIET(excpt1)
  3338.     {
  3339.         if (    (fShutdownSemOwned = !DosRequestMutexSem(pData->hmtxShutdown, 4000))
  3340.              && (fSkippedSemOwned = !DosRequestMutexSem(pData->hmtxSkipped, 4000))
  3341.            )
  3342.         {
  3343.             PLISTNODE pShutNode = lstQueryFirstNode(&pData->llShutdown);
  3344.             // pliShutItem = pliShutdownFirst;
  3345.             while (pShutNode)
  3346.             {
  3347.                 PLISTNODE pSkipNode = lstQueryFirstNode(&pData->llSkipped);
  3348.                 pliShutItem = pShutNode->pItemData;
  3349.  
  3350.                 while (pSkipNode)
  3351.                 {
  3352.                     PSHUTLISTITEM pliSkipItem = pSkipNode->pItemData;
  3353.                     xsdLongTitle(szShutItem, pliShutItem);
  3354.                     xsdLongTitle(szSkipItem, pliSkipItem);
  3355.                     if (!strcmp(szShutItem, szSkipItem))
  3356.                         /* current shut item is on skip list:
  3357.                            break (==> take next shut item */
  3358.                         break;
  3359.  
  3360.                     pSkipNode = pSkipNode->pNext;
  3361.                     pliSkipItem = 0;
  3362.                 }
  3363.  
  3364.                 if (pSkipNode == NULL)
  3365.                     // current item is not on the skip list:
  3366.                     // return this item
  3367.                     break;
  3368.  
  3369.                 // current item was skipped: take next one
  3370.                 pShutNode = pShutNode->pNext;
  3371.                 pliShutItem = 0;
  3372.             }
  3373.         }
  3374.     }
  3375.     CATCH(excpt1) { } END_CATCH();
  3376.  
  3377.     // fixed release order V0.9.20 (2002-07-22) [umoeller]
  3378.     if (fSkippedSemOwned)
  3379.         DosReleaseMutexSem(pData->hmtxSkipped);
  3380.  
  3381.     if (fShutdownSemOwned)
  3382.         DosReleaseMutexSem(pData->hmtxShutdown);
  3383.  
  3384.     return (pliShutItem);
  3385. }
  3386.  
  3387. /*
  3388.  *@@ xsdAppendShutListItem:
  3389.  *      this appends a new PSHUTLISTITEM to the given list
  3390.  *      and returns the address of the new item; the list
  3391.  *      to append to must be specified in *ppFirst / *ppLast.
  3392.  *
  3393.  *      NOTE: It is entirely the job of the caller to serialize
  3394.  *      access to the list, using mutex semaphores.
  3395.  *      The item to add is to be specified by swctl and possibly
  3396.  *      *pObject (if swctl describes an open Desktop object).
  3397.  *
  3398.  *      Since this gets called from xsdBuildShutList, this runs
  3399.  *      on both the Shutdown and Update threads.
  3400.  *
  3401.  *@@changed V0.9.0 [umoeller]: adjusted for new linklist.c functions
  3402.  *@@changed V0.9.4 (2000-07-11) [umoeller]: fixed bug in window class detection
  3403.  *@@changed V0.9.6 (2000-10-27) [umoeller]: fixed WarpCenter detection
  3404.  */
  3405.  
  3406. PSHUTLISTITEM xsdAppendShutListItem(PSHUTDOWNDATA pShutdownData,
  3407.                                     PLINKLIST pList,    // in/out: linked list to work on
  3408.                                     SWCNTRL* pswctl,    // in: tasklist entry to add
  3409.                                     WPObject *pObject,  // in: !=NULL: Desktop object
  3410.                                     LONG lSpecial)
  3411. {
  3412.     PSHUTLISTITEM  pNewItem = NULL;
  3413.  
  3414.     pNewItem = malloc(sizeof(SHUTLISTITEM));
  3415.  
  3416.     if (pNewItem)
  3417.     {
  3418.         pNewItem->pObject = pObject;
  3419.         memcpy(&pNewItem->swctl, pswctl, sizeof(SWCNTRL));
  3420.  
  3421.         strcpy(pNewItem->szClass, "unknown");
  3422.  
  3423.         pNewItem->lSpecial = lSpecial;
  3424.  
  3425.         if (pObject)
  3426.         {
  3427.             // for Desktop objects, store additional data
  3428.             if (wpshCheckObject(pObject))
  3429.             {
  3430.                 strncpy(pNewItem->szClass,
  3431.                         (PSZ)_somGetClassName(pObject),
  3432.                         sizeof(pNewItem->szClass)-1);
  3433.  
  3434.                 pNewItem->swctl.szSwtitle[0] = '\0';
  3435.                 strncpy(pNewItem->swctl.szSwtitle,
  3436.                         _wpQueryTitle(pObject),
  3437.                         sizeof(pNewItem->swctl.szSwtitle)-1);
  3438.  
  3439.                 // always set PID and SID to that of the WPS,
  3440.                 // because the tasklist returns garbage for
  3441.                 // Desktop objects
  3442.                 pNewItem->swctl.idProcess = pShutdownData->SDConsts.pidWPS;
  3443.                 pNewItem->swctl.idSession = pShutdownData->sidWPS;
  3444.  
  3445.                 // set HWND to object-in-use-list data,
  3446.                 // because the tasklist also returns garbage
  3447.                 // for that
  3448.                 if (_wpFindUseItem(pObject, USAGE_OPENVIEW, NULL))
  3449.                     pNewItem->swctl.hwnd = (_wpFindViewItem(pObject,
  3450.                                                             VIEW_ANY,
  3451.                                                             NULL))->handle;
  3452.             }
  3453.             else
  3454.             {
  3455.                 // invalid object:
  3456.                 pNewItem->pObject = NULL;
  3457.                 strcpy(pNewItem->szClass, "wpshCheckObject failed");
  3458.             }
  3459.         }
  3460.         else
  3461.         {
  3462.             // no Desktop object: get window class name
  3463.             WinQueryClassName(pswctl->hwnd,               // old V0.9.3 code
  3464.                               sizeof(pNewItem->szClass)-1,
  3465.                               pNewItem->szClass);
  3466.             /* PCKERNELGLOBALS pKernelGlobals = krnQueryGlobals();
  3467.             // strcpy(pNewItem->szClass, "pObj is NULL");
  3468.  
  3469.             if (pObject == pKernelGlobals->pAwakeWarpCenter)
  3470.             {
  3471.                 strcpy(pNewItem->szClass, "!!WarpCenter");
  3472.             }
  3473.             else
  3474.                 // no Desktop object: get window class name
  3475.                 WinQueryClassName(pswctl->hwnd,
  3476.                                   sizeof(pNewItem->szClass)-1,
  3477.                                   pNewItem->szClass); */
  3478.         }
  3479.  
  3480.         // append to list
  3481.         lstAppendItem(pList, pNewItem);
  3482.     }
  3483.  
  3484.     return (pNewItem);
  3485. }
  3486.  
  3487. /*
  3488.  *@@ xsdIsClosable:
  3489.  *      examines the given switch list entry and returns
  3490.  *      an XSD_* constant telling the caller what that
  3491.  *      item represents.
  3492.  *
  3493.  *      While we're at it, we also change some of the
  3494.  *      data in the switch list entry if needed.
  3495.  *
  3496.  *      If the switch list entry represents a Desktop object,
  3497.  *      *ppObject is set to that object's SOM pointer.
  3498.  *      Otherwise *ppObject receives NULL.
  3499.  *
  3500.  *      This returns:
  3501.  *      --  XSD_SYSTEM (-1)
  3502.  *
  3503.  *      --  XSD_INVISIBLE (-2)
  3504.  *
  3505.  *      --  XSD_DEBUGNEED (-3)
  3506.  *
  3507.  *      --  XSD_DESKTOP (-4) for the WPS desktop, which
  3508.  *          needs special handling anyway since it must
  3509.  *          be closed last;
  3510.  *
  3511.  *      --  XSD_WARPCENTER (-5)
  3512.  *
  3513.  *      --  XSD_WPSOBJECT_CLOSE (0) for any WPS object to
  3514.  *          be closed; for those, *ppObject is set to
  3515.  *          the SOM object pointer. These objects must
  3516.  *          be closed with all shutdown modes.
  3517.  *
  3518.  *      --  XSD_OTHER_OWNED (1): the program is owned by
  3519.  *          the current user, but is not a WPS object.
  3520.  *          Close this with shutdown and logoff, but
  3521.  *          with "Restart WPS", close it only if the
  3522.  *          user wants to have all sessions closed.
  3523.  *
  3524.  *      --  XSD_OTHER_FOREIGN (2): the program is not a
  3525.  *          WPS object, and it's not even owned by the
  3526.  *          current user. Close this with shutdown only;
  3527.  *          never close this with "restart desktop" or
  3528.  *          "logoff".
  3529.  *
  3530.  *      In other words, if this returns something >= 0,
  3531.  *      the object might have to be closed depending on
  3532.  *      the mode.
  3533.  *
  3534.  *@@added V0.9.4 (2000-07-15) [umoeller]
  3535.  *@@changed V0.9.6 (2000-10-27) [umoeller]: fixed WarpCenter detection
  3536.  *@@changed V0.9.19 (2002-04-02) [umoeller]: refined detection for the different modes
  3537.  */
  3538.  
  3539. LONG xsdIsClosable(HAB hab,                 // in: caller's anchor block
  3540.                    PSHUTDOWNCONSTS pConsts,
  3541.                    SWENTRY *pSwEntry,       // in/out: switch entry
  3542.                    WPObject **ppObject,     // out: the WPObject*, really, or NULL if the window is no object
  3543.                    PULONG pulUserID)       // out: user ID on whose behalf the user is running or -1 if XWPShell is not running
  3544. {
  3545.     LONG           lrc = 0;
  3546.     CHAR           szSwUpperTitle[100];
  3547.  
  3548.     *ppObject = NULL;
  3549.  
  3550.     strcpy(szSwUpperTitle,
  3551.            pSwEntry->swctl.szSwtitle);
  3552.     WinUpper(hab, 0, 0, szSwUpperTitle);
  3553.  
  3554.     if (    // skip if PID == 0:
  3555.             (pSwEntry->swctl.idProcess == 0)
  3556.             // skip the Shutdown windows:
  3557.          || (pSwEntry->swctl.hwnd == pConsts->hwndMain)
  3558.          || (pSwEntry->swctl.hwnd == pConsts->hwndVioDlg)
  3559.          || (pSwEntry->swctl.hwnd == pConsts->hwndShutdownStatus)
  3560.        )
  3561.         return (XSD_SYSTEM);
  3562.     // skip invisible tasklist entries; this
  3563.     // includes a PMWORKPLACE cmd.exe:
  3564.     else if (pSwEntry->swctl.uchVisibility != SWL_VISIBLE)
  3565.         return (XSD_INVISIBLE);
  3566.     // open WarpCenter (WarpCenter bar only):
  3567.     else if (   (pSwEntry->swctl.hwnd == pConsts->hwndOpenWarpCenter)
  3568.              && (pConsts->pKernelGlobals)
  3569.             )
  3570.     {
  3571.         *ppObject = G_pAwakeWarpCenter;     // global variable (xfobj.c, kernel.h) V0.9.20 (2002-07-25) [umoeller]
  3572.         return (XSD_WARPCENTER);
  3573.     }
  3574. #ifdef __DEBUG__
  3575.     // if we're in debug mode, skip the PMPRINTF window
  3576.     // because we want to see debug output
  3577.     else if (!strncmp(szSwUpperTitle, "PMPRINTF", 8))
  3578.         return (XSD_DEBUGNEED);
  3579.     // skip VAC debugger, which is probably debugging
  3580.     // PMSHELL.EXE
  3581.     else if (!strcmp(szSwUpperTitle, "ICSDEBUG.EXE"))
  3582.         return (XSD_DEBUGNEED);
  3583. #endif
  3584.  
  3585.     // now fix the data in the switch list entries,
  3586.     // if necessary
  3587.     if (pSwEntry->swctl.bProgType == PROG_DEFAULT)
  3588.     {
  3589.         // in this case, we need to find out what
  3590.         // type the program really has
  3591.         PQPROCSTAT16 pps;
  3592.         if (!prc16GetInfo(&pps))
  3593.         {
  3594.             PRCPROCESS prcp;
  3595.             // default for errors
  3596.             pSwEntry->swctl.bProgType = PROG_WINDOWABLEVIO;
  3597.             if (prc16QueryProcessInfo(pps, pSwEntry->swctl.idProcess, &prcp))
  3598.                 // according to bsedos.h, the PROG_* types are identical
  3599.                 // to the SSF_TYPE_* types, so we can use the data from
  3600.                 // DosQProcStat
  3601.                 pSwEntry->swctl.bProgType = prcp.ulSessionType;
  3602.             prc16FreeInfo(pps);
  3603.         }
  3604.     }
  3605.  
  3606.     if (pSwEntry->swctl.bProgType == PROG_WINDOWEDVDM)
  3607.         // DOS/Win-OS/2 window: get real PID/SID, because
  3608.         // the tasklist contains false data
  3609.         WinQueryWindowProcess(pSwEntry->swctl.hwnd,
  3610.                               &pSwEntry->swctl.idProcess,
  3611.                               &pSwEntry->swctl.idSession);
  3612.  
  3613.     if (pSwEntry->swctl.idProcess == pConsts->pidWPS)
  3614.     {
  3615.         // is Desktop window?
  3616.         if (pSwEntry->swctl.hwnd == pConsts->hwndActiveDesktop)
  3617.         {
  3618.             *ppObject = pConsts->pActiveDesktop;
  3619.             lrc = XSD_DESKTOP;
  3620.         }
  3621.         else
  3622.         {
  3623.             // PID == Workplace Shell PID: get SOM pointer from hwnd
  3624.             *ppObject = _wpclsQueryObjectFromFrame(pConsts->pWPDesktop, // _WPDesktop
  3625.                                                    pSwEntry->swctl.hwnd);
  3626.  
  3627.             if (*ppObject == pConsts->pActiveDesktop)
  3628.                 lrc = XSD_DESKTOP;
  3629.         }
  3630.     }
  3631.  
  3632.     // if this is not a WPS object, mark it so caller can decide whether to close it
  3633.     if (!*ppObject)
  3634.         lrc = XSD_OTHER_OWNED;
  3635.  
  3636.     if (pConsts->uid == -1)
  3637.         // XWPShell not running:
  3638.         *pulUserID = -2;
  3639.     else
  3640.     {
  3641.         // XWPShell running:
  3642.         if (*ppObject)
  3643.             // WPS object: use WPS pid (save time)
  3644.             *pulUserID = pConsts->uid;
  3645.         else
  3646.             if (xsecQueryProcessOwner(pSwEntry->swctl.idProcess,
  3647.                                       pulUserID))
  3648.                 // error:
  3649.                 *pulUserID = -2;
  3650.             else
  3651.                 if (*pulUserID != pConsts->uid)
  3652.                     lrc = XSD_OTHER_FOREIGN;
  3653.     }
  3654.  
  3655.     return (lrc);
  3656. }
  3657.  
  3658. /*
  3659.  *@@ xsdBuildShutList:
  3660.  *      this routine builds a new ShutList by evaluating the
  3661.  *      system task list; this list is built in pList.
  3662.  *      NOTE: It is entirely the job of the caller to serialize
  3663.  *      access to the list, using mutex semaphores.
  3664.  *      We call xsdAppendShutListItem for each task list entry,
  3665.  *      if that entry is to be closed, so we're doing a few checks.
  3666.  *
  3667.  *      This gets called from both xsdUpdateListBox (on the
  3668.  *      Shutdown thread) and the Update thread (fntUpdateThread)
  3669.  *      directly.
  3670.  *
  3671.  *@@changed V0.9.0 [umoeller]: adjusted for new linklist.c functions
  3672.  *@@changed V0.9.0 [umoeller]: PSHUTDOWNPARAMS added to prototype
  3673.  *@@changed V0.9.4 (2000-07-15) [umoeller]: PSHUTDOWNCONSTS added to prototype
  3674.  *@@changed V0.9.4 (2000-07-15) [umoeller]: extracted xsdIsClosable; fixed WarpCenter detection
  3675.  */
  3676.  
  3677. void xsdBuildShutList(HAB hab,
  3678.                       PSHUTDOWNDATA pShutdownData,
  3679.                       PLINKLIST pList)
  3680. {
  3681.     PSWBLOCK        pSwBlock   = NULL;         // Pointer to information returned
  3682.     ULONG           ul;
  3683.     WPObject        *pObj;
  3684.     BOOL            Append;
  3685.  
  3686.     // get all the tasklist entries into a buffer
  3687.     pSwBlock = winhQuerySwitchList(hab);
  3688.  
  3689.     // loop through all the tasklist entries
  3690.     for (ul = 0;
  3691.          ul < pSwBlock->cswentry;
  3692.          ul++)
  3693.     {
  3694.         // now we check which windows we add to the shutdown list
  3695.         ULONG uid;
  3696.         LONG lrc = xsdIsClosable(hab,
  3697.                                  &pShutdownData->SDConsts,
  3698.                                  &pSwBlock->aswentry[ul],
  3699.                                  &pObj,
  3700.                                  &uid);
  3701.         if (lrc >= 0)
  3702.         {
  3703.             // generally closeable:
  3704.             BOOL fSkip = FALSE;
  3705.  
  3706.             if (lrc == XSD_OTHER_OWNED)
  3707.                 // the program is owned by the current user, but is not a WPS object.
  3708.                 // Close this with shutdown and logoff, but
  3709.                 // with "Restart WPS", close it only if the
  3710.                 // user wants to have all sessions closed.
  3711.                 if (    (pShutdownData->sdParams.ulCloseMode == SHUT_RESTARTWPS)
  3712.                      && (!pShutdownData->sdParams.optWPSCloseWindows)
  3713.                    )
  3714.                     fSkip = TRUE;
  3715.  
  3716.             if (lrc == XSD_OTHER_FOREIGN)
  3717.                 // the program is not a
  3718.                 // WPS object, and it's not even owned by the
  3719.                 // current user. Close this with shutdown only;
  3720.                 // never close this with "restart desktop" or
  3721.                 // "logoff".
  3722.                 if (pShutdownData->sdParams.ulCloseMode != SHUT_SHUTDOWN)
  3723.                     fSkip = TRUE;
  3724.  
  3725.             if (!fSkip)
  3726.                 xsdAppendShutListItem(pShutdownData,
  3727.                                       pList,
  3728.                                       &pSwBlock->aswentry[ul].swctl,
  3729.                                       pObj,
  3730.                                       lrc);
  3731.         }
  3732.     }
  3733.  
  3734.     free(pSwBlock);
  3735. }
  3736.  
  3737. /*
  3738.  *@@ xsdUpdateListBox:
  3739.  *      this routine builds a new PSHUTITEM list from the
  3740.  *      pointer to the pointer of the first item (*ppliShutdownFirst)
  3741.  *      by setting its value to xsdBuildShutList's return value;
  3742.  *      it also fills the listbox in the "main" window, which
  3743.  *      is only visible in Debug mode.
  3744.  *      But even if it's invisible, the listbox is used for closing
  3745.  *      windows. Ugly, but nobody can see it. ;-)
  3746.  *      If *ppliShutdownFirst is != NULL the old shutlist is cleared
  3747.  *      also.
  3748.  *
  3749.  *      Runs on the Shutdown thread.
  3750.  *
  3751.  *@@changed V0.9.0 [umoeller]: adjusted for new linklist.c functions
  3752.  *@@changed V0.9.0 [umoeller]: PSHUTDOWNPARAMS added to prototype
  3753.  *@@changed V0.9.4 (2000-07-15) [umoeller]: PSHUTDOWNCONSTS added to prototype
  3754.  */
  3755.  
  3756. void xsdUpdateListBox(HAB hab,
  3757.                       PSHUTDOWNDATA pShutdownData,
  3758.                       HWND hwndListbox)
  3759. {
  3760.     PSHUTLISTITEM   pItem;
  3761.     CHAR            szTitle[1024];
  3762.  
  3763.     BOOL            fLocked = FALSE;
  3764.  
  3765.     TRY_QUIET(excpt1)
  3766.     {
  3767.         if (fLocked = !DosRequestMutexSem(pShutdownData->hmtxShutdown, 4000))
  3768.         {
  3769.             PLISTNODE pNode = 0;
  3770.             lstClear(&pShutdownData->llShutdown);
  3771.             xsdBuildShutList(hab,
  3772.                              pShutdownData,
  3773.                              &pShutdownData->llShutdown);
  3774.  
  3775.             // clear list box
  3776.             WinEnableWindowUpdate(hwndListbox, FALSE);
  3777.             WinSendMsg(hwndListbox, LM_DELETEALL, MPNULL, MPNULL);
  3778.  
  3779.             // and insert all list items as strings
  3780.             pNode = lstQueryFirstNode(&pShutdownData->llShutdown);
  3781.             while (pNode)
  3782.             {
  3783.                 pItem = pNode->pItemData;
  3784.                 xsdLongTitle(szTitle, pItem);
  3785.                 WinInsertLboxItem(hwndListbox, 0, szTitle);
  3786.                 pNode = pNode->pNext;
  3787.             }
  3788.             WinEnableWindowUpdate(hwndListbox, TRUE);
  3789.         }
  3790.     }
  3791.     CATCH(excpt1) { } END_CATCH();
  3792.  
  3793.     if (fLocked)
  3794.         DosReleaseMutexSem(pShutdownData->hmtxShutdown);
  3795. }
  3796.  
  3797. /*
  3798.  *@@ xsdUpdateClosingStatus:
  3799.  *      this gets called from fnwpShutdownThread to
  3800.  *      set the Shutdown status wnd text to "Closing xxx".
  3801.  *
  3802.  *      Runs on the Shutdown thread.
  3803.  */
  3804.  
  3805. VOID xsdUpdateClosingStatus(HWND hwndShutdownStatus,
  3806.                             PCSZ pcszProgTitle)   // in: window title from SHUTLISTITEM
  3807. {
  3808.     CHAR szTitle[300];
  3809.     strcpy(szTitle,
  3810.            cmnGetString(ID_SDSI_CLOSING)); // (cmnQueryNLSStrings())->pszSDClosing);
  3811.     strcat(szTitle, " \"");
  3812.     strcat(szTitle, pcszProgTitle);
  3813.     strcat(szTitle, "\"...");
  3814.     WinSetDlgItemText(hwndShutdownStatus, ID_SDDI_STATUS,
  3815.                       szTitle);
  3816.  
  3817.     WinSetActiveWindow(HWND_DESKTOP, hwndShutdownStatus);
  3818. }
  3819.  
  3820. /*
  3821.  *@@ xsdWaitForExceptions:
  3822.  *      checks for whether helpers/except.c is currently
  3823.  *      busy processing an exception and, if so, waits
  3824.  *      until that thread is done.
  3825.  *
  3826.  *      Gets called several times during fntShutdownThread
  3827.  *      because we don't want to lose the trap logs.
  3828.  *
  3829.  *@@added V0.9.13 (2001-06-19) [umoeller]
  3830.  */
  3831.  
  3832. VOID xsdWaitForExceptions(PSHUTDOWNDATA pShutdownData)
  3833. {
  3834.     // check the global variable exported from except.h,
  3835.     // which is > 0 if some exception is currently running
  3836.     if (G_ulExplainExceptionRunning)
  3837.     {
  3838.         ULONG ulSlept = 1;
  3839.  
  3840.         while (G_ulExplainExceptionRunning)
  3841.         {
  3842.             CHAR szTemp[500];
  3843.             sprintf(szTemp,
  3844.                     "Urgh, %d exception(s) running, waiting... (%d)",
  3845.                     G_ulExplainExceptionRunning,
  3846.                     ulSlept++);
  3847.             WinSetDlgItemText(pShutdownData->SDConsts.hwndShutdownStatus,
  3848.                               ID_SDDI_STATUS,
  3849.                               szTemp);
  3850.  
  3851.             // wait half a second
  3852.             winhSleep(500);
  3853.         }
  3854.  
  3855.         WinSetDlgItemText(pShutdownData->SDConsts.hwndShutdownStatus,
  3856.                           ID_SDDI_STATUS,
  3857.                           "OK");
  3858.     }
  3859. }
  3860.  
  3861. /*
  3862.  *@@ fncbSaveImmediate:
  3863.  *      callback for objForAllDirtyObjects to save
  3864.  *      the WPS.
  3865.  *
  3866.  *@@added V0.9.9 (2001-04-04) [umoeller]
  3867.  *@@changed V0.9.16 (2001-12-06) [umoeller]: now skipping saving objects from foreign desktops
  3868.  */
  3869.  
  3870. BOOL _Optlink fncbSaveImmediate(WPObject *pobjThis,
  3871.                                 ULONG ulIndex,
  3872.                                 ULONG cObjects,
  3873.                                 PVOID pvUser)
  3874. {
  3875.     BOOL    brc = FALSE;
  3876.     PSHUTDOWNDATA pShutdownData = (PSHUTDOWNDATA)pvUser;
  3877.  
  3878.     // update progress bar
  3879.     WinSendMsg(pShutdownData->hwndProgressBar,
  3880.                WM_UPDATEPROGRESSBAR,
  3881.                (MPARAM)ulIndex,
  3882.                (MPARAM)cObjects);
  3883.  
  3884.     TRY_QUIET(excpt1)
  3885.     {
  3886.         if (pobjThis == pShutdownData->SDConsts.pActiveDesktop)
  3887.                         // we already saved the desktop, so skip this
  3888.                         // V0.9.16 (2001-10-25) [umoeller]
  3889.             brc = TRUE;
  3890.         else if (cmnIsObjectFromForeignDesktop(pobjThis))
  3891.                         // never save objects which belong to
  3892.                         // a foreign desktop
  3893.                         // V0.9.16 (2001-12-06) [umoeller]
  3894.         {
  3895.             /* CHAR szFolderPath[CCHMAXPATH];
  3896.             _wpQueryFilename(_wpQueryFolder(pobjThis),
  3897.                              szFolderPath,
  3898.                              TRUE);
  3899.             cmnLog(__FILE__, __LINE__, __FUNCTION__,
  3900.                    "skipping save of object %s (class: %s) in folder %s",
  3901.                    _wpQueryTitle(pobjThis),
  3902.                    _somGetClassName(pobjThis),
  3903.                    szFolderPath);
  3904.             */
  3905.             brc = TRUE;
  3906.         }
  3907.         else
  3908.         {
  3909.             brc = _wpSaveImmediate(pobjThis);
  3910.             #ifdef DEBUG_SHUTDOWN
  3911.                 _PmpfF(("saved obj 0x%lX (%s, class %s)",
  3912.                                 pobjThis,
  3913.                                 _wpQueryTitle(pobjThis),
  3914.                                 _somGetClassName(pobjThis)));
  3915.             #endif
  3916.         }
  3917.     }
  3918.     CATCH(excpt1)
  3919.     {
  3920.         brc = FALSE;
  3921.     } END_CATCH();
  3922.  
  3923.     return brc;
  3924. }
  3925.  
  3926. /* ******************************************************************
  3927.  *
  3928.  *   Shutdown thread
  3929.  *
  3930.  ********************************************************************/
  3931.  
  3932. /*
  3933.  *@@ fntShutdownThread:
  3934.  *      this is the main shutdown thread which is created by
  3935.  *      xsdInitiateShutdown / xsdInitiateRestartWPS when shutdown is about
  3936.  *      to begin.
  3937.  *
  3938.  *      Parameters: this thread must be created using thrCreate
  3939.  *      (src/helpers/threads.c), so it is passed a pointer
  3940.  *      to a THREADINFO structure. In that structure you
  3941.  *      must set ulData to point to a SHUTDOWNPARAMS structure.
  3942.  *
  3943.  *      Note: if you're trying to understand what's going on here,
  3944.  *      I recommend rebuilding XFolder with DEBUG_SHUTDOWN
  3945.  *      #define'd (see include/setup.h for that). This will allow you
  3946.  *      to switch XShutdown into "Debug" mode by holding down
  3947.  *      the "Shift" key while selecting "Shutdown" from the
  3948.  *      Desktop's context menu.
  3949.  *
  3950.  *      Shutdown / Restart Desktop runs in the following phases:
  3951.  *
  3952.  *      1)  First, all necessary preparations are done, i.e. two
  3953.  *          windows are created (the status window with the progress
  3954.  *          bar and the "main" window, which is only visible in debug
  3955.  *          mode, but processes all the messages). These two windows
  3956.  *          daringly share the same msg proc (fnwpShutdownThread below),
  3957.  *          but receive different messages, so this shan't hurt.
  3958.  *
  3959.  *          After these windows have been created, fntShutdown will also
  3960.  *          create the Update thread (fntUpdateThread below).
  3961.  *          This Update thread is responsible for monitoring the
  3962.  *          task list; every time an item is closed (or even opened!),
  3963.  *          it will post a ID_SDMI_UPDATESHUTLIST command to fnwpShutdownThread,
  3964.  *          which will then start working again.
  3965.  *
  3966.  *      2)  fntShutdownThread then remains in a standard PM message
  3967.  *          loop until shutdown is cancelled by the user or all
  3968.  *          windows have been closed.
  3969.  *          In both cases, fnwpShutdownThread posts a WM_QUIT then.
  3970.  *
  3971.  *          The order of msg processing in fntShutdownThread / fnwpShutdownThread
  3972.  *          is the following:
  3973.  *
  3974.  *          a)  ID_SDMI_UPDATESHUTLIST will update the list of currently
  3975.  *              open windows (which is not touched by any other thread)
  3976.  *              by calling xsdUpdateListBox.
  3977.  *
  3978.  *              Unless we're in debug mode (where shutdown has to be
  3979.  *              started manually), the first time ID_SDMI_UPDATESHUTLIST
  3980.  *              is received, we will post ID_SDDI_BEGINSHUTDOWN (go to c)).
  3981.  *              Otherwise (subsequent calls), we post ID_SDMI_CLOSEITEM
  3982.  *              (go to d)).
  3983.  *
  3984.  *          b)  ID_SDDI_BEGINSHUTDOWN will begin processing the contents
  3985.  *              of the Shutdown folder and empty the trash can. After this
  3986.  *              is done, ID_SDMI_BEGINCLOSINGITEMS is posted.
  3987.  *
  3988.  *          c)  ID_SDMI_BEGINCLOSINGITEMS will prepare closing all windows
  3989.  *              by setting flagClosingItems to TRUE and then post the
  3990.  *              first ID_SDMI_CLOSEITEM.
  3991.  *
  3992.  *          d)  ID_SDMI_CLOSEITEM will now undertake the necessary
  3993.  *              actions for closing the first / next item on the list
  3994.  *              of items to close, that is, post WM_CLOSE to the window
  3995.  *              or kill the process or whatever.
  3996.  *              If no more items are left to close, we post
  3997.  *              ID_SDMI_PREPARESAVEWPS (go to g)).
  3998.  *              Otherwise, after this, the Shutdown thread is idle.
  3999.  *
  4000.  *          e)  When the window has actually closed, the Update thread
  4001.  *              realizes this because the task list will have changed.
  4002.  *              The next ID_SDMI_UPDATESHUTLIST will be posted by the
  4003.  *              Update thread then. Go back to b).
  4004.  *
  4005.  *          f)  ID_SDMI_PREPARESAVEWPS will save the state of all currently
  4006.  *              awake Desktop objects by using the list which was maintained
  4007.  *              by the Worker thread all the while during the whole WPS session.
  4008.  *
  4009.  *          g)  After this, ID_SDMI_FLUSHBUFFERS is posted, which will
  4010.  *              set fAllWindowsClosed to TRUE and post WM_QUIT, so that
  4011.  *              the PM message loop in fntShutdownThread will exit.
  4012.  *
  4013.  *      3)  Depending on whether fnwpShutdownThread set fAllWindowsClosed to
  4014.  *          TRUE, we will then actually restart the WPS or shut down the system
  4015.  *          or exit this thread (= shutdown cancelled), and the user may continue work.
  4016.  *
  4017.  *          Shutting down the system is done by calling xsdFinishShutdown,
  4018.  *          which will differentiate what needs to be done depending on
  4019.  *          what the user wants (new with V0.84).
  4020.  *          We will then either reboot the machine or run in an endless
  4021.  *          loop, if no reboot was desired, or call the functions for an
  4022.  *          APM 1.2 power-off in apm.c (V0.82).
  4023.  *
  4024.  *          When shutdown was cancelled by pressing the respective button,
  4025.  *          the Update thread is killed, all shutdown windows are closed,
  4026.  *          and then this thread also terminates.
  4027.  *
  4028.  *@@changed V0.9.0 [umoeller]: adjusted for new linklist.c functions
  4029.  *@@changed V0.9.0 [umoeller]: changed shutdown logging to stdio functions (fprintf etc.)
  4030.  *@@changed V0.9.0 [umoeller]: code has been re-ordered for semaphore safety.
  4031.  *@@changed V0.9.1 (99-12-10) [umoeller]: extracted auto-close list code to xsdLoadAutoCloseItems
  4032.  *@@changed V0.9.9 (2001-04-04) [umoeller]: moved all post-close stuff from fnwpShutdownThread here
  4033.  *@@changed V0.9.9 (2001-04-04) [umoeller]: rewrote "save Desktop objects" to use dirty list from object.c
  4034.  *@@changed V0.9.11 (2001-04-18) [umoeller]: fixed logoff
  4035.  *@@changed V0.9.12 (2001-04-29) [umoeller]: deferred update thread startup to fnwpShutdownThread; this fixes shutdown folder
  4036.  *@@changed V0.9.12 (2001-05-15) [umoeller]: now telling XPager to recover windows first
  4037.  *@@changed V0.9.12 (2001-05-29) [umoeller]: now broadcasting WM_SAVEAPPLICATION here
  4038.  *@@changed V0.9.12 (2001-05-29) [umoeller]: StartShutdownThread now uses THRF_PMMSGQUEUE so Wininitialize etc. has been removed here
  4039.  *@@changed V0.9.13 (2001-06-17) [umoeller]: no longer broadcasting WM_SAVEAPPLICATION, going back to old code
  4040.  *@@changed V0.9.13 (2001-06-19) [umoeller]: now pausing while exception handler is still running somewhere
  4041.  *@@changed V0.9.16 (2001-10-25) [umoeller]: couple of extra hacks for saving desktop
  4042.  *@@changed V0.9.19 (2002-04-24) [umoeller]: adjustments for new global G_ulShutdownState flag
  4043.  *@@changed V0.9.19 (2002-06-18) [umoeller]: misc optimizations
  4044.  *@@changed V0.9.19 (2002-06-18) [umoeller]: no longer recovering windows to current desktop for restart wps
  4045.  */
  4046.  
  4047. static void _Optlink fntShutdownThread(PTHREADINFO ptiMyself)
  4048. {
  4049.     /*************************************************
  4050.      *
  4051.      *      data setup:
  4052.      *
  4053.      *************************************************/
  4054.  
  4055.     PSZ             pszErrMsg = NULL;
  4056.     QMSG            qmsg;
  4057.     APIRET          arc;
  4058.     HAB             hab = ptiMyself->hab;
  4059.     PXFILE          LogFile = NULL;
  4060.  
  4061.     // allocate shutdown data V0.9.9 (2001-03-07) [umoeller]
  4062.     PSHUTDOWNDATA   pShutdownData;
  4063.     if (!(pShutdownData = (PSHUTDOWNDATA)malloc(sizeof(SHUTDOWNDATA))))
  4064.     {
  4065.         G_ulShutdownState = XSD_IDLE;
  4066.         return;
  4067.     }
  4068.  
  4069.     // set shutdown state to "running"
  4070.     G_ulShutdownState = XSD_INITIALIZING;
  4071.  
  4072.     // CLEAR ALL FIELDS -- this is essential!
  4073.     memset(pShutdownData, 0, sizeof(SHUTDOWNDATA));
  4074.  
  4075.     // get shutdown params from thread info
  4076.     memcpy(&pShutdownData->sdParams,
  4077.            (PSHUTDOWNPARAMS)ptiMyself->ulData,
  4078.            sizeof(SHUTDOWNPARAMS));
  4079.  
  4080.     xsdGetShutdownConsts(&pShutdownData->SDConsts);
  4081.  
  4082.     // copy anchor block so subfuncs can use it
  4083.     // V0.9.12 (2001-05-29) [umoeller]
  4084.     pShutdownData->habShutdownThread = hab;
  4085.  
  4086.     // set some global data for all the following
  4087.     pShutdownData->hmodResource = cmnQueryNLSModuleHandle(FALSE);
  4088.  
  4089.     WinCancelShutdown(ptiMyself->hmq, TRUE);
  4090.  
  4091.     // open shutdown log file for writing, if enabled
  4092.     if (pShutdownData->sdParams.optLog)
  4093.     {
  4094.         CHAR    szLogFileName[CCHMAXPATH];
  4095.         ULONG   cbFile = 0;
  4096.         sprintf(szLogFileName, "%c:\\%s", doshQueryBootDrive(), XFOLDER_SHUTDOWNLOG);
  4097.         if (arc = doshOpen(szLogFileName,
  4098.                            XOPEN_READWRITE_APPEND,        // not XOPEN_BINARY
  4099.                            &cbFile,
  4100.                            &LogFile))
  4101.             cmnLog(__FILE__, __LINE__, __FUNCTION__,
  4102.                    "Cannot create log file %s", szLogFileName);
  4103.  
  4104.         pShutdownData->ShutdownLogFile = LogFile;
  4105.     }
  4106.  
  4107.     if (LogFile)
  4108.     {
  4109.         // write log header
  4110.         /*
  4111.         DATETIME DT;
  4112.         DosGetDateTime(&DT);
  4113.         doshWriteLogEntry(LogFile,
  4114.                 "XWorkplace Shutdown Log -- Date: %04d-%02d-%02d, Time: %02d:%02d:%02d",
  4115.                 DT.year, DT.month, DT.day,
  4116.                 DT.hours, DT.minutes, DT.seconds);
  4117.         */
  4118.         doshWriteLogEntry(LogFile, "-----------------------------------------------------------\n");
  4119.         doshWriteLogEntry(LogFile, "XWorkplace version: %s", XFOLDER_VERSION);
  4120.         doshWriteLogEntry(LogFile, "Shutdown thread started, TID: 0x%lX",
  4121.                 thrQueryID(ptiMyself));
  4122.         doshWriteLogEntry(LogFile, "Settings: CloseMode %d, Confirm %s, Reboot %s, WPSCloseWnds %s, CloseVIOs %s, WarpCenterFirst %s, APMPowerOff %s",
  4123.                 pShutdownData->sdParams.ulCloseMode,
  4124.                 (pShutdownData->sdParams.optConfirm) ? "ON" : "OFF",
  4125.                 (pShutdownData->sdParams.optReboot) ? "ON" : "OFF",
  4126.                 (pShutdownData->sdParams.optWPSCloseWindows) ? "ON" : "OFF",
  4127.                 (pShutdownData->sdParams.optAutoCloseVIO) ? "ON" : "OFF",
  4128.                 (pShutdownData->sdParams.optWarpCenterFirst) ? "ON" : "OFF",
  4129.                 (pShutdownData->sdParams.optAPMPowerOff) ? "ON" : "OFF");
  4130.     }
  4131.  
  4132.     // raise our own priority; we will
  4133.     // still use the REGULAR class, but
  4134.     // with the maximum delta, so we can
  4135.     // get above nasty (DOS?) sessions
  4136.     DosSetPriority(PRTYS_THREAD,
  4137.                    PRTYC_REGULAR,
  4138.                    PRTYD_MAXIMUM, // priority delta
  4139.                    0);
  4140.  
  4141.     TRY_LOUD(excpt1)
  4142.     {
  4143.         SWCNTRL     swctl;
  4144.         HSWITCH     hswitch;
  4145.         ULONG       // ulKeyLength = 0,
  4146.                     ulAutoCloseItemsFound = 0;
  4147.         HPOINTER    hptrShutdown = WinLoadPointer(HWND_DESKTOP, pShutdownData->hmodResource,
  4148.                                                   ID_SDICON);
  4149.  
  4150.         // create an event semaphore which signals to the Update thread
  4151.         // that the Shutlist has been updated by fnwpShutdownThread
  4152.         DosCreateEventSem(NULL,         // unnamed
  4153.                           &pShutdownData->hevUpdated,
  4154.                           0,            // unshared
  4155.                           FALSE);       // not posted
  4156.  
  4157.         // create mutex semaphores for linked lists
  4158.         if (pShutdownData->hmtxShutdown == NULLHANDLE)
  4159.         {
  4160.             DosCreateMutexSem("\\sem32\\ShutdownList",
  4161.                               &pShutdownData->hmtxShutdown, 0, FALSE);     // unnamed, unowned
  4162.             DosCreateMutexSem("\\sem32\\SkippedList",
  4163.                               &pShutdownData->hmtxSkipped, 0, FALSE);      // unnamed, unowned
  4164.         }
  4165.  
  4166.         lstInit(&pShutdownData->llShutdown, TRUE);      // auto-free items
  4167.         lstInit(&pShutdownData->llSkipped, TRUE);       // auto-free items
  4168.         lstInit(&pShutdownData->llAutoClose, TRUE);     // auto-free items
  4169.  
  4170.         // check for auto-close items in OS2.INI
  4171.         // and build llAutoClose list accordingly
  4172.         doshWriteLogEntry(LogFile,
  4173.                __FUNCTION__ ": Getting auto-close items from OS2.INI...");
  4174.  
  4175.         ulAutoCloseItemsFound = xsdLoadAutoCloseItems(&pShutdownData->llAutoClose,
  4176.                                                       NULLHANDLE); // no list box
  4177.  
  4178.         doshWriteLogEntry(LogFile,
  4179.                "  Found %d auto-close items.", ulAutoCloseItemsFound);
  4180.  
  4181.         /*************************************************
  4182.          *
  4183.          *      shutdown windows setup:
  4184.          *
  4185.          *************************************************/
  4186.  
  4187.         doshWriteLogEntry(LogFile,
  4188.                "  Creating shutdown windows...");
  4189.  
  4190.         // setup main (debug) window; this is hidden
  4191.         // unless we're in debug mode
  4192.         pShutdownData->SDConsts.hwndMain
  4193.                 = cmnLoadDlg(NULLHANDLE,
  4194.                              fnwpShutdownThread,
  4195.                              ID_SDD_MAIN,
  4196.                              NULL);
  4197.         WinSetWindowPtr(pShutdownData->SDConsts.hwndMain,
  4198.                         QWL_USER,
  4199.                         pShutdownData); // V0.9.9 (2001-03-07) [umoeller]
  4200.         WinSendMsg(pShutdownData->SDConsts.hwndMain,
  4201.                    WM_SETICON,
  4202.                    (MPARAM)hptrShutdown,
  4203.                     NULL);
  4204.  
  4205.         doshWriteLogEntry(LogFile,
  4206.                "  Created main window (hwnd: 0x%lX)",
  4207.                pShutdownData->SDConsts.hwndMain);
  4208.         doshWriteLogEntry(LogFile,
  4209.                "  HAB: 0x%lX, HMQ: 0x%lX, pidWPS: 0x%lX, pidPM: 0x%lX",
  4210.                hab,
  4211.                ptiMyself->hmq,
  4212.                pShutdownData->SDConsts.pidWPS,
  4213.                pShutdownData->SDConsts.pidPM);
  4214.  
  4215.         pShutdownData->ulMaxItemCount = 0;
  4216.         pShutdownData->ulLastItemCount = -1;
  4217.  
  4218.         pShutdownData->hPOC = 0;
  4219.  
  4220.         pShutdownData->sidPM = 1;  // should always be this, I hope
  4221.  
  4222.         // add ourselves to the tasklist
  4223.         swctl.hwnd = pShutdownData->SDConsts.hwndMain;                  // window handle
  4224.         swctl.hwndIcon = hptrShutdown;               // icon handle
  4225.         swctl.hprog = NULLHANDLE;               // program handle
  4226.         swctl.idProcess = pShutdownData->SDConsts.pidWPS;               // PID
  4227.         swctl.idSession = 0;                    // SID
  4228.         swctl.uchVisibility = SWL_VISIBLE;      // visibility
  4229.         swctl.fbJump = SWL_JUMPABLE;            // jump indicator
  4230.         WinQueryWindowText(pShutdownData->SDConsts.hwndMain, sizeof(swctl.szSwtitle), (PSZ)&swctl.szSwtitle);
  4231.         swctl.bProgType = PROG_DEFAULT;         // program type
  4232.  
  4233.         hswitch = WinAddSwitchEntry(&swctl);
  4234.         WinQuerySwitchEntry(hswitch, &swctl);
  4235.         pShutdownData->sidWPS = swctl.idSession;   // get the "real" WPS SID
  4236.  
  4237.         // setup status window (always visible)
  4238.         pShutdownData->SDConsts.hwndShutdownStatus
  4239.                 = cmnLoadDlg(NULLHANDLE,
  4240.                              fnwpShutdownThread,
  4241.                              ID_SDD_STATUS,
  4242.                              NULL);
  4243.         WinSetWindowPtr(pShutdownData->SDConsts.hwndShutdownStatus,
  4244.                         QWL_USER,
  4245.                         pShutdownData); // V0.9.9 (2001-03-07) [umoeller]
  4246.         WinSendMsg(pShutdownData->SDConsts.hwndShutdownStatus,
  4247.                    WM_SETICON,
  4248.                    (MPARAM)hptrShutdown,
  4249.                    NULL);
  4250.  
  4251.         doshWriteLogEntry(LogFile,
  4252.                "  Created status window (hwnd: 0x%lX)",
  4253.                pShutdownData->SDConsts.hwndShutdownStatus);
  4254.  
  4255.         // subclass the static rectangle control in the dialog to make
  4256.         // it a progress bar
  4257.         pShutdownData->hwndProgressBar
  4258.             = WinWindowFromID(pShutdownData->SDConsts.hwndShutdownStatus,
  4259.                               ID_SDDI_PROGRESSBAR);
  4260.         ctlProgressBarFromStatic(pShutdownData->hwndProgressBar,
  4261.                                  PBA_ALIGNCENTER | PBA_BUTTONSTYLE);
  4262.  
  4263.         // set status window to top
  4264.         WinSetWindowPos(pShutdownData->SDConsts.hwndShutdownStatus,
  4265.                         HWND_TOP,
  4266.                         0, 0, 0, 0,
  4267.                         SWP_SHOW | SWP_ZORDER | SWP_ACTIVATE);
  4268.  
  4269.         // animate the traffic light
  4270.         xsdLoadAnimation(&G_sdAnim);
  4271.         ctlPrepareAnimation(WinWindowFromID(pShutdownData->SDConsts.hwndShutdownStatus,
  4272.                                             ID_SDDI_ICON),
  4273.                             XSD_ANIM_COUNT,
  4274.                             G_sdAnim.ahptr,
  4275.                             150,    // delay
  4276.                             TRUE);  // start now
  4277.  
  4278.         // create update thread (moved here V0.9.9 (2001-03-07) [umoeller])
  4279.         /* removed again; moved this down into fnwpShutdownThread
  4280.             it is now started after the shutdown folder has
  4281.             finished processing V0.9.12 (2001-04-29) [umoeller]
  4282.  
  4283.         if (thrQueryID(&G_tiUpdateThread) == NULLHANDLE)
  4284.         {
  4285.             thrCreate(&G_tiUpdateThread,
  4286.                       fntUpdateThread,
  4287.                       NULL, // running flag
  4288.                       "ShutdownUpdate",
  4289.                       THRF_PMMSGQUEUE,
  4290.                       (ULONG)pShutdownData);  // V0.9.9 (2001-03-07) [umoeller]
  4291.  
  4292.             doshWriteLogEntry(LogFile,
  4293.                    __FUNCTION__ ": Update thread started, tid: 0x%lX",
  4294.                    thrQueryID(&G_tiUpdateThread));
  4295.         }
  4296.         */
  4297.  
  4298.         if (pShutdownData->sdParams.optDebug)
  4299.         {
  4300.             // debug mode: show "main" window, which
  4301.             // is invisible otherwise
  4302.             winhCenterWindow(pShutdownData->SDConsts.hwndMain);
  4303.             WinShowWindow(pShutdownData->SDConsts.hwndMain, TRUE);
  4304.         }
  4305.  
  4306.         doshWriteLogEntry(LogFile,
  4307.                __FUNCTION__ ": Now entering shutdown message loop...");
  4308.  
  4309.         // tell XPager to recover all windows to the current screen
  4310.         // V0.9.12 (2001-05-15) [umoeller]
  4311.         if (pShutdownData->SDConsts.pKernelGlobals)
  4312.         {
  4313.             PXWPGLOBALSHARED pXwpGlobalShared;
  4314.  
  4315.             if (    (pXwpGlobalShared = pShutdownData->SDConsts.pKernelGlobals->pXwpGlobalShared)
  4316.                  && (pXwpGlobalShared->hwndDaemonObject)
  4317.                )
  4318.             {
  4319.                 BOOL fWPSOnly = FALSE;
  4320.                 // now, if we are doing a restart wps and not all
  4321.                 // sessions should be closed, we should still recover
  4322.                 // windows, but only those of the WPS process... so
  4323.                 // a flag has been added for that to XDM_RECOVERWINDOWS
  4324.                 // V0.9.20 (2002-08-10) [umoeller]
  4325.                 if (    (pShutdownData->sdParams.ulCloseMode != SHUT_SHUTDOWN)
  4326.                                 // not Desktop (1), not logoff (2)
  4327.                      && (!pShutdownData->sdParams.optWPSCloseWindows)
  4328.                    )
  4329.                     fWPSOnly = TRUE;
  4330.  
  4331.                 doshWriteLogEntry(LogFile,
  4332.                        __FUNCTION__ ": Recovering all XPager windows...");
  4333.  
  4334.                 WinSendMsg(pXwpGlobalShared->hwndDaemonObject,
  4335.                            XDM_RECOVERWINDOWS,
  4336.                            (MPARAM)fWPSOnly,
  4337.                            0);
  4338.             }
  4339.         }
  4340.  
  4341.         if (!pShutdownData->sdParams.optDebug)
  4342.         {
  4343.             // if we're not in debug mode, begin shutdown
  4344.             // automatically; ID_SDDI_BEGINSHUTDOWN will
  4345.             // first empty the trash can, process the
  4346.             // shutdown folder, and finally start closing
  4347.             // windows
  4348.             doshWriteLogEntry(LogFile, __FUNCTION__ ": Posting ID_SDDI_BEGINSHUTDOWN");
  4349.             WinPostMsg(pShutdownData->SDConsts.hwndMain,
  4350.                        WM_COMMAND,
  4351.                        MPFROM2SHORT(ID_SDDI_BEGINSHUTDOWN, 0),
  4352.                        MPNULL);
  4353.         }
  4354.  
  4355.         // if we're closing all windows,
  4356.         // broadcast WM_SAVEAPPLICATION to all frames which
  4357.         // are children of the desktop
  4358.         // V0.9.12 (2001-05-29) [umoeller]
  4359.         // V0.9.13 (2001-06-17) [umoeller]: nope, go back to doing this for each window
  4360.         /* if (    (0 == pShutdownData->sdParams.ulRestartWPS) // restart Desktop (1) or logoff (2)
  4361.              || (pShutdownData->sdParams.optWPSCloseWindows)
  4362.            )
  4363.         {
  4364.             doshWriteLogEntry(LogFile, __FUNCTION__ ": Broadcasting WM_SAVEAPPLICATION");
  4365.         } */
  4366.  
  4367.         // pShutdownData->ulStatus is still XSD_IDLE at this point
  4368.  
  4369.         /*************************************************
  4370.          *
  4371.          *      standard PM message loop:
  4372.          *          here we are closing the windows
  4373.          *
  4374.          *************************************************/
  4375.  
  4376.         // now enter the common message loop for the main (debug) and
  4377.         // status windows (fnwpShutdownThread); this will keep running
  4378.         // until closing all windows is complete or cancelled, upon
  4379.         // both of which fnwpShutdownThread will post WM_QUIT
  4380.         while (WinGetMsg(hab, &qmsg, NULLHANDLE, 0, 0))
  4381.             WinDispatchMsg(hab, &qmsg);
  4382.  
  4383.         doshWriteLogEntry(LogFile,
  4384.                __FUNCTION__ ": Done with message loop.");
  4385.  
  4386.         /*************************************************
  4387.          *
  4388.          *      done closing windows:
  4389.          *
  4390.          *************************************************/
  4391.  
  4392. // all the following has been moved here from fnwpShutdownThread
  4393. // with V0.9.9 (2001-04-04) [umoeller]
  4394.  
  4395.         // in any case,
  4396.         // close the Update thread to prevent it from interfering
  4397.         // with what we're doing now
  4398.         if (thrQueryID(&G_tiUpdateThread))
  4399.         {
  4400.             #ifdef DEBUG_SHUTDOWN
  4401.                 WinSetDlgItemText(G_hwndShutdownStatus, ID_SDDI_STATUS,
  4402.                                   "Waiting for the Update thread to end...");
  4403.             #endif
  4404.             doshWriteLogEntry(LogFile,
  4405.                    __FUNCTION__ ": Closing Update thread, tid: 0x%lX...",
  4406.                    thrQueryID(&G_tiUpdateThread));
  4407.  
  4408.             thrFree(&G_tiUpdateThread);  // close and wait
  4409.             doshWriteLogEntry(LogFile,
  4410.                    __FUNCTION__ ": Update thread closed.");
  4411.         }
  4412.  
  4413.         // check if shutdown was cancelled (XSD_CANCELLED)
  4414.         // or if we should proceed (XSD_ALLCLOSED_SAVING)
  4415.         if (G_ulShutdownState == XSD_ALLCLOSED_SAVING)
  4416.         {
  4417.             ULONG       cObjectsToSave = 0,
  4418.                         cObjectsSaved = 0;
  4419.             CHAR        szTitle[400];
  4420.             PSWBLOCK    psw;
  4421.             WPObject    *pWarpCenter;
  4422.  
  4423.             /*************************************************
  4424.              *
  4425.              *      close desktop and WarpCenter
  4426.              *
  4427.              *************************************************/
  4428.  
  4429.             // save the window list position and fonts
  4430.             // V0.9.16 (2002-01-13) [umoeller]
  4431.             // this doesn't work... apparently we must
  4432.             // be in the shell process for WinStoreWindowPos
  4433.             // to work correctly
  4434.             /* if (psw = winhQuerySwitchList(hab))
  4435.             {
  4436.                 CHAR sz[1000];
  4437.                 sprintf(sz,
  4438.                         "Storing window list 0x%lX",
  4439.                         psw->aswentry[0].swctl.hwnd);
  4440.                 winhDebugBox(NULLHANDLE,
  4441.                              "Shutdown thread",
  4442.                              sz);
  4443.                 // window list frame is always the first entry
  4444.                 // in the switch list
  4445.                 if (!WinStoreWindowPos("PM_Workplace:WindowListPos",
  4446.                                        "SavePos",
  4447.                                        psw->aswentry[0].swctl.hwnd))
  4448.                     cmnLog(__FILE__, __LINE__, __FUNCTION__,
  4449.                            "WinStoreWindowPos for tasklist failed");
  4450.                 free(psw);
  4451.             } */
  4452.  
  4453.             WinSetActiveWindow(HWND_DESKTOP,
  4454.                                pShutdownData->SDConsts.hwndShutdownStatus);
  4455.  
  4456.             // disable buttons in status window... we can't stop now!
  4457.             WinEnableControl(pShutdownData->SDConsts.hwndShutdownStatus,
  4458.                              ID_SDDI_CANCELSHUTDOWN,
  4459.                              FALSE);
  4460.             WinEnableControl(pShutdownData->SDConsts.hwndShutdownStatus,
  4461.                              ID_SDDI_SKIPAPP,
  4462.                              FALSE);
  4463.  
  4464.             // close Desktop window (which we excluded from
  4465.             // the regular SHUTLISTITEM list)
  4466.             doshWriteLogEntry(LogFile,
  4467.                               __FUNCTION__ ": Closing Desktop window");
  4468.             xsdUpdateClosingStatus(pShutdownData->SDConsts.hwndShutdownStatus,
  4469.                                    _wpQueryTitle(pShutdownData->SDConsts.pActiveDesktop));
  4470.  
  4471.             // sleep a little while... XCenter might have resized
  4472.             // the desktop, and this will hang otherwise
  4473.             // V0.9.9 (2001-04-04) [umoeller]
  4474.             winhSleep(300);
  4475.  
  4476.             if (pShutdownData->SDConsts.pActiveDesktop)
  4477.             {
  4478.                 CHAR szDesktop[CCHMAXPATH];
  4479.                 // set <WP_DESKTOP> ID on desktop; sometimes this gets
  4480.                 // lost during shutdown
  4481.                 // V0.9.16 (2001-10-25) [umoeller]
  4482.                 if (_wpQueryFilename(pShutdownData->SDConsts.pActiveDesktop,
  4483.                                      szDesktop,
  4484.                                      TRUE))
  4485.                 {
  4486.                     // save last active desktop in OS2.INI in case
  4487.                     // <WP_DESKTOP> gets broken so we can get the
  4488.                     // path in the new panic dialog; see
  4489.                     // initRepairDesktopIfBroken
  4490.                     // V0.9.16 (2001-10-25) [umoeller]
  4491.                     PrfWriteProfileString(HINI_USER,
  4492.                                           (PSZ)INIAPP_XWORKPLACE,
  4493.                                           (PSZ)INIKEY_LASTDESKTOPPATH,
  4494.                                           szDesktop);
  4495.                 }
  4496.  
  4497.                 _wpSetObjectID(pShutdownData->SDConsts.pActiveDesktop,
  4498.                                (PSZ)WPOBJID_DESKTOP); // "<WP_DESKTOP>",
  4499.  
  4500.                 _wpSaveImmediate(pShutdownData->SDConsts.pActiveDesktop);
  4501.                 _wpClose(pShutdownData->SDConsts.pActiveDesktop);
  4502.                 _wpWaitForClose(pShutdownData->SDConsts.pActiveDesktop,
  4503.                                 NULLHANDLE,     // all views
  4504.                                 0xFFFFFFFF,
  4505.                                 5*1000,     // timeout value
  4506.                                 TRUE);      // force close for new views
  4507.                             // added V0.9.4 (2000-07-11) [umoeller]
  4508.  
  4509.                 // give the desktop time to save icon positions
  4510.                 winhSleep(300); // V0.9.12 (2001-04-29) [umoeller]
  4511.             }
  4512.  
  4513.             // close WarpCenter next (V0.9.5, from V0.9.3)
  4514.             if (    (pWarpCenter = G_pAwakeWarpCenter)      // global variable (xfobj.c, kernel.h) V0.9.20 (2002-07-25) [umoeller]
  4515.                  && (somIsObj(pWarpCenter))
  4516.                )
  4517.             {
  4518.                 // WarpCenter still open?
  4519.                 if (_wpFindUseItem(pWarpCenter, USAGE_OPENVIEW, NULL))
  4520.                 {
  4521.                     // if open: close it
  4522.                     xsdUpdateClosingStatus(pShutdownData->SDConsts.hwndShutdownStatus,
  4523.                                            _wpQueryTitle(pWarpCenter));
  4524.                     doshWriteLogEntry(LogFile,
  4525.                            __FUNCTION__ ": Found open WarpCenter USEITEM, closing...");
  4526.  
  4527.                     _wpSaveImmediate(pWarpCenter);
  4528.                     // _wpClose(pWarpCenter);
  4529.                     WinPostMsg(pShutdownData->SDConsts.hwndOpenWarpCenter,
  4530.                                WM_COMMAND,
  4531.                                MPFROMSHORT(0x66F7),
  4532.                                     // "Close" menu item in WarpCenter context menu...
  4533.                                     // nothing else works right!
  4534.                                MPFROM2SHORT(CMDSRC_OTHER,
  4535.                                             FALSE));     // keyboard?!?
  4536.  
  4537.                     _wpWaitForClose(pWarpCenter,
  4538.                                     pShutdownData->SDConsts.hwndOpenWarpCenter,
  4539.                                     VIEW_ANY,
  4540.                                     SEM_INDEFINITE_WAIT,
  4541.                                     TRUE);
  4542.  
  4543.                     pShutdownData->SDConsts.hwndOpenWarpCenter = NULLHANDLE;
  4544.                 }
  4545.             }
  4546.  
  4547.             // if some thread is currently in an exception handler,
  4548.             // wait until the handler is done; otherwise the trap
  4549.             // log won't be written and we can't find out what
  4550.             // happened V0.9.13 (2001-06-19) [umoeller]
  4551.             xsdWaitForExceptions(pShutdownData);
  4552.  
  4553.             // set progress bar to the max
  4554.             WinSendMsg(pShutdownData->hwndProgressBar,
  4555.                        WM_UPDATEPROGRESSBAR,
  4556.                        (MPARAM)1,
  4557.                        (MPARAM)1);
  4558.  
  4559.             winhSleep(300);
  4560.  
  4561.             // now we need a blank screen so that it looks
  4562.             // as if we had closed all windows, even if we
  4563.             // haven't; we do this by creating a "fake
  4564.             // desktop", which is just an empty window w/out
  4565.             // title bar which takes up the whole screen and
  4566.             // has the color of the PM desktop
  4567.             if (    (pShutdownData->sdParams.ulCloseMode == SHUT_SHUTDOWN)
  4568.                  && (!(pShutdownData->sdParams.optDebug))
  4569.                )
  4570.                 winhCreateFakeDesktop(pShutdownData->SDConsts.hwndShutdownStatus);
  4571.  
  4572.             /*************************************************
  4573.              *
  4574.              *      save Desktop objects
  4575.              *
  4576.              *************************************************/
  4577.  
  4578.             cObjectsToSave = objQueryDirtyObjectsCount();
  4579.  
  4580.             sprintf(szTitle,
  4581.                     cmnGetString(ID_SDSI_SAVINGDESKTOP), // cmnQueryNLSStrings()->pszSDSavingDesktop,
  4582.                         // "Saving xxx awake Desktop objects..."
  4583.                     cObjectsToSave);
  4584.             WinSetDlgItemText(pShutdownData->SDConsts.hwndShutdownStatus,
  4585.                               ID_SDDI_STATUS,
  4586.                               szTitle);
  4587.  
  4588.             doshWriteLogEntry(LogFile,
  4589.                    __FUNCTION__ ": Saving %d awake Desktop objects...",
  4590.                    cObjectsToSave);
  4591.  
  4592.             // reset progress bar
  4593.             WinSendMsg(pShutdownData->hwndProgressBar,
  4594.                        WM_UPDATEPROGRESSBAR,
  4595.                        (MPARAM)0,
  4596.                        (MPARAM)cObjectsToSave);
  4597.  
  4598.             // if some thread is currently in an exception handler,
  4599.             // wait until the handler is done; otherwise the trap
  4600.             // log won't be written and we can't find out what
  4601.             // happened V0.9.13 (2001-06-19) [umoeller]
  4602.             xsdWaitForExceptions(pShutdownData);
  4603.  
  4604.             // finally, save WPS!!
  4605.  
  4606.             // now using proper "dirty" list V0.9.9 (2001-04-04) [umoeller]
  4607.             cObjectsSaved = objForAllDirtyObjects(fncbSaveImmediate,
  4608.                                                   pShutdownData);  // user param
  4609.  
  4610.             // have the WPS flush its buffers
  4611.             xsdFlushWPS2INI();  // added V0.9.0 (UM 99-10-22)
  4612.  
  4613.             // and wait a while
  4614.             winhSleep(500);
  4615.  
  4616.             // if some thread is currently in an exception handler,
  4617.             // wait until the handler is done; otherwise the trap
  4618.             // log won't be written and we can't find out what
  4619.             // happened V0.9.13 (2001-06-19) [umoeller]
  4620.             xsdWaitForExceptions(pShutdownData);
  4621.  
  4622.             // set progress bar to max
  4623.             WinSendMsg(pShutdownData->hwndProgressBar,
  4624.                        WM_UPDATEPROGRESSBAR,
  4625.                        (MPARAM)1,
  4626.                        (MPARAM)1);
  4627.  
  4628.             doshWriteLogEntry(LogFile,
  4629.                    __FUNCTION__ ": Done saving WPS, %d objects saved.",
  4630.                    cObjectsSaved);
  4631.  
  4632.             winhSleep(200);
  4633.  
  4634.             if (pShutdownData->sdParams.ulCloseMode != SHUT_SHUTDOWN)
  4635.             {
  4636.                 // "Restart Desktop" mode, or "logoff":
  4637.                 WinSetDlgItemText(pShutdownData->SDConsts.hwndShutdownStatus,
  4638.                                   ID_SDDI_STATUS,
  4639.                                   cmnGetString(ID_SDSI_RESTARTINGWPS)); // (cmnQueryNLSStrings())->pszSDRestartingWPS);
  4640.  
  4641.                 // reuse startup folder?
  4642.                 krnSetProcessStartupFolder(pShutdownData->sdParams.optWPSReuseStartupFolder);
  4643.             }
  4644.  
  4645.         } // end if (pShutdownData->ulStatus == XSD_ALLDONEOK)
  4646.  
  4647. // end moved code with V0.9.9 (2001-04-04) [umoeller]
  4648.  
  4649.     } // end TRY_LOUD(excpt1
  4650.     CATCH(excpt1)
  4651.     {
  4652.         // exception occured:
  4653.         krnUnlockGlobals();     // just to make sure
  4654.         // fExceptionOccured = TRUE;
  4655.  
  4656.         if (pszErrMsg == NULL)
  4657.         {
  4658.             // only report the first error, or otherwise we will
  4659.             // jam the system with msg boxes
  4660.             pszErrMsg = malloc(2000);
  4661.             if (pszErrMsg)
  4662.             {
  4663.                 strcpy(pszErrMsg, "An error occured in the XFolder Shutdown thread. "
  4664.                         "In the root directory of your boot drive, you will find a "
  4665.                         "file named XFLDTRAP.LOG, which contains debugging information. "
  4666.                         "If you had shutdown logging enabled, you will also find the "
  4667.                         "file XSHUTDWN.LOG there. If not, please enable shutdown "
  4668.                         "logging in the Desktop's settings notebook. "
  4669.                         "\n\nThe XShutdown procedure will be terminated now. We can "
  4670.                         "now also restart the Workplace Shell. This is recommended if "
  4671.                         "your Desktop has already been closed or if "
  4672.                         "the error occured during the saving of the INI files. In these "
  4673.                         "cases, please disable XShutdown and perform a regular OS/2 "
  4674.                         "shutdown to prevent loss of your WPS data."
  4675.                         "\n\nRestart the Workplace Shell now?");
  4676.                 krnPostThread1ObjectMsg(T1M_EXCEPTIONCAUGHT, (MPARAM)pszErrMsg,
  4677.                                         (MPARAM)1); // enforce Desktop restart
  4678.  
  4679.                 doshWriteLogEntry(LogFile,
  4680.                        "\n*** CRASH\n%s\n", pszErrMsg);
  4681.             }
  4682.         }
  4683.     } END_CATCH();
  4684.  
  4685.     /*
  4686.      * Cleanup:
  4687.      *
  4688.      */
  4689.  
  4690.     // we arrive here if
  4691.     //      a) fnwpShutdownThread successfully closed all windows;
  4692.     //         only in that case, fAllWindowsClosed is TRUE;
  4693.     //      b) shutdown was cancelled by the user;
  4694.     //      c) an exception occured.
  4695.     // In any of these cases, we need to clean up big time now.
  4696.  
  4697.     // close "main" window, but keep the status window for now
  4698.     WinDestroyWindow(pShutdownData->SDConsts.hwndMain);
  4699.  
  4700.     doshWriteLogEntry(LogFile,
  4701.            __FUNCTION__ ": Entering cleanup...");
  4702.  
  4703.     // check for whether we're owning semaphores;
  4704.     // if we do (e.g. after an exception), release them now
  4705.     if (pShutdownData->fShutdownSemOwned)
  4706.     {
  4707.         doshWriteLogEntry(LogFile, "  Releasing shutdown mutex");
  4708.         DosReleaseMutexSem(pShutdownData->hmtxShutdown);
  4709.         pShutdownData->fShutdownSemOwned = FALSE;
  4710.     }
  4711.     if (pShutdownData->fSkippedSemOwned)
  4712.     {
  4713.         doshWriteLogEntry(LogFile, "  Releasing skipped mutex");
  4714.         DosReleaseMutexSem(pShutdownData->hmtxSkipped);
  4715.         pShutdownData->fSkippedSemOwned = FALSE;
  4716.     }
  4717.  
  4718.     doshWriteLogEntry(LogFile, "  Done releasing semaphores.");
  4719.  
  4720.     // get rid of the Update thread;
  4721.     // this got closed by fnwpShutdownThread normally,
  4722.     // but with exceptions, this might not have happened
  4723.     if (thrQueryID(&G_tiUpdateThread))
  4724.     {
  4725.         doshWriteLogEntry(LogFile, "  Closing Update thread...");
  4726.         thrFree(&G_tiUpdateThread); // fixed V0.9.0
  4727.         doshWriteLogEntry(LogFile, "  Update thread closed.");
  4728.     }
  4729.  
  4730.     doshWriteLogEntry(LogFile, "  Closing semaphores...");
  4731.     DosCloseEventSem(pShutdownData->hevUpdated);
  4732.     if (pShutdownData->hmtxShutdown != NULLHANDLE)
  4733.     {
  4734.         if (arc = DosCloseMutexSem(pShutdownData->hmtxShutdown))
  4735.         {
  4736.             DosBeep(100, 1000);
  4737.             doshWriteLogEntry(LogFile, "    Error %d closing hmtxShutdown!",
  4738.                               arc);
  4739.         }
  4740.         pShutdownData->hmtxShutdown = NULLHANDLE;
  4741.     }
  4742.     if (pShutdownData->hmtxSkipped != NULLHANDLE)
  4743.     {
  4744.         if (arc = DosCloseMutexSem(pShutdownData->hmtxSkipped))
  4745.         {
  4746.             DosBeep(100, 1000);
  4747.             doshWriteLogEntry(LogFile, "    Error %d closing hmtxSkipped!",
  4748.                               arc);
  4749.         }
  4750.         pShutdownData->hmtxSkipped = NULLHANDLE;
  4751.     }
  4752.     doshWriteLogEntry(LogFile, "  Done closing semaphores.");
  4753.  
  4754.     doshWriteLogEntry(LogFile, "  Freeing lists...");
  4755.     TRY_LOUD(excpt1)
  4756.     {
  4757.         // destroy all global lists; this time, we need
  4758.         // no mutex semaphores, because the Update thread
  4759.         // is already down
  4760.         lstClear(&pShutdownData->llShutdown);
  4761.         lstClear(&pShutdownData->llSkipped);
  4762.     }
  4763.     CATCH(excpt1) {} END_CATCH();
  4764.     doshWriteLogEntry(LogFile, "  Done freeing lists.");
  4765.  
  4766.     /*
  4767.      * Restart Desktop or shutdown:
  4768.      *
  4769.      */
  4770.  
  4771.     if (G_ulShutdownState == XSD_ALLCLOSED_SAVING)
  4772.     {
  4773.         // happens only if shutdown was not cancelled;
  4774.         // this means that all windows have been successfully
  4775.         // closed, the WPS is saved, and we can actually shut
  4776.         // down the system
  4777.  
  4778.         G_ulShutdownState = XSD_SAVEDONE_FLUSHING;
  4779.             // V0.9.19 (2002-04-24) [umoeller]
  4780.  
  4781.         if (pShutdownData->sdParams.ulCloseMode != SHUT_SHUTDOWN) // restart Desktop (1) or logoff (2)
  4782.         {
  4783.             // here we will actually restart the WPS
  4784.             doshWriteLogEntry(LogFile, "Preparing Desktop restart...");
  4785.  
  4786.             ctlStopAnimation(WinWindowFromID(pShutdownData->SDConsts.hwndShutdownStatus, ID_SDDI_ICON));
  4787.             WinDestroyWindow(pShutdownData->SDConsts.hwndShutdownStatus);
  4788.             xsdFreeAnimation(&G_sdAnim);
  4789.  
  4790.             doshWriteLogEntry(LogFile, "Restarting WPS: Calling DosExit(), closing log.");
  4791.             doshClose(&LogFile);
  4792.             LogFile = NULL;
  4793.  
  4794.             xsdRestartWPS(hab,
  4795.                           (pShutdownData->sdParams.ulCloseMode == SHUT_LOGOFF));
  4796.                             // V0.9.11 (2001-04-18) [umoeller]
  4797.                 // this will not return, I think
  4798.         }
  4799.         else
  4800.         {
  4801.             // *** no restart Desktop:
  4802.             // call the termination routine, which
  4803.             // will do the rest
  4804.  
  4805.             xsdFinishShutdown(pShutdownData);
  4806.             // this will not return, except in debug mode
  4807.  
  4808.             if (pShutdownData->sdParams.optDebug)
  4809.                 // in debug mode, restart Desktop
  4810.                 pShutdownData->sdParams.ulCloseMode = SHUT_RESTARTWPS;
  4811.         }
  4812.     } // end if (fAllWindowsClosed)
  4813.  
  4814.     // the following code is only reached if
  4815.     // shutdown was cancelled...
  4816.  
  4817.     // close logfile
  4818.     if (LogFile)
  4819.     {
  4820.         doshWriteLogEntry(LogFile, "Reached cleanup, closing log.");
  4821.         doshClose(&LogFile);
  4822.         LogFile = NULL;
  4823.     }
  4824.  
  4825.     // moved this down, because we need a msg queue for restart Desktop
  4826.     // V0.9.3 (2000-04-26) [umoeller]
  4827.  
  4828.     WinDestroyWindow(pShutdownData->SDConsts.hwndShutdownStatus);
  4829.  
  4830.     free(pShutdownData);        // V0.9.9 (2001-03-07) [umoeller]
  4831.  
  4832.     // set the global flag for whether shutdown is
  4833.     // running to FALSE; this will re-enable the
  4834.     // items in the Desktop's context menu
  4835.     G_ulShutdownState = XSD_IDLE;
  4836.  
  4837.     // end of Shutdown thread
  4838.     // thread exits!
  4839. }
  4840.  
  4841. /*
  4842.  *@@ xsdCloseVIO:
  4843.  *      this gets called upon ID_SDMI_CLOSEVIO in
  4844.  *      fnwpShutdownThread when a VIO window is encountered.
  4845.  *      (To be precise, this gets called for all non-PM
  4846.  *      sessions, not just VIO windows.)
  4847.  *
  4848.  *      This function queries the list of auto-close
  4849.  *      items and closes the VIO window accordingly.
  4850.  *      If no corresponding item was found, we display
  4851.  *      a dialog, querying the user what to do with this.
  4852.  *
  4853.  *      Runs on the Shutdown thread.
  4854.  *
  4855.  *@@added V0.9.1 (99-12-10) [umoeller]
  4856.  *@@changed V0.9.19 (2002-05-23) [umoeller]: removed Ctrl+C option, which never worked
  4857.  */
  4858.  
  4859. VOID xsdCloseVIO(PSHUTDOWNDATA pShutdownData,
  4860.                  HWND hwndFrame)
  4861. {
  4862.     PSHUTLISTITEM   pItem;
  4863.     ULONG           ulReply;
  4864.     PAUTOCLOSELISTITEM pliAutoCloseFound = NULL; // fixed V0.9.0
  4865.     ULONG           ulSessionAction = 0;
  4866.                         // this will become one of the ACL_* flags
  4867.                         // if something is to be done with this session
  4868.  
  4869.     doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  4870.            "  ID_SDMI_CLOSEVIO, hwnd: 0x%lX; entering xsdCloseVIO",
  4871.            hwndFrame);
  4872.  
  4873.     // get VIO item to close
  4874.     if (pItem = xsdQueryCurrentItem(pShutdownData))
  4875.     {
  4876.         // valid item: go thru list of auto-close items
  4877.         // if this item is on there
  4878.         PLISTNODE   pAutoCloseNode = 0;
  4879.         xsdLongTitle(pShutdownData->szVioTitle, pItem);
  4880.         pShutdownData->VioItem = *pItem;
  4881.         doshWriteLogEntry(pShutdownData->ShutdownLogFile, "    xsdCloseVIO: VIO item: %s", pShutdownData->szVioTitle);
  4882.  
  4883.         // activate VIO window
  4884.         WinSetActiveWindow(HWND_DESKTOP, pShutdownData->VioItem.swctl.hwnd);
  4885.  
  4886.         // check if VIO window is on auto-close list
  4887.         pAutoCloseNode = lstQueryFirstNode(&pShutdownData->llAutoClose);
  4888.         while (pAutoCloseNode)
  4889.         {
  4890.             PAUTOCLOSELISTITEM pliThis = pAutoCloseNode->pItemData;
  4891.             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      Checking %s", pliThis->szItemName);
  4892.             // compare first characters
  4893.             if (!strnicmp(pShutdownData->VioItem.swctl.szSwtitle,
  4894.                           pliThis->szItemName,
  4895.                           strlen(pliThis->szItemName)))
  4896.             {
  4897.                 // item found:
  4898.                 doshWriteLogEntry(pShutdownData->ShutdownLogFile, "        Matching item found, auto-closing item");
  4899.                 pliAutoCloseFound = pliThis;
  4900.                 break;
  4901.             }
  4902.  
  4903.             pAutoCloseNode = pAutoCloseNode->pNext;
  4904.         }
  4905.  
  4906.         if (pliAutoCloseFound)
  4907.         {
  4908.             // item was found on auto-close list:
  4909.             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "    Found on auto-close list");
  4910.  
  4911.             // store this item's action for later
  4912.             ulSessionAction = pliAutoCloseFound->usAction;
  4913.         } // end if (pliAutoCloseFound)
  4914.         else
  4915.         {
  4916.             // not on auto-close list:
  4917.             if (pShutdownData->sdParams.optAutoCloseVIO)
  4918.             {
  4919.                 // auto-close enabled globally though:
  4920.                 doshWriteLogEntry(pShutdownData->ShutdownLogFile, "    Not found on auto-close list, auto-close is on:");
  4921.  
  4922.                 // "auto close VIOs" is on
  4923.                 if (pShutdownData->VioItem.swctl.idSession == 1)
  4924.                 {
  4925.                     // for some reason, DOS/Windows sessions always
  4926.                     // run in the Shell process, whose SID == 1
  4927.                     WinPostMsg((WinWindowFromID(pShutdownData->VioItem.swctl.hwnd, FID_SYSMENU)),
  4928.                                WM_SYSCOMMAND,
  4929.                                (MPARAM)SC_CLOSE, MPNULL);
  4930.                     doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      Posted SC_CLOSE to hwnd 0x%lX",
  4931.                            WinWindowFromID(pShutdownData->VioItem.swctl.hwnd, FID_SYSMENU));
  4932.                 }
  4933.                 else
  4934.                 {
  4935.                     // OS/2 windows: kill
  4936.                     DosKillProcess(DKP_PROCESS, pShutdownData->VioItem.swctl.idProcess);
  4937.                     doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      Killed pid 0x%lX",
  4938.                            pShutdownData->VioItem.swctl.idProcess);
  4939.                 }
  4940.             } // end if (psdParams->optAutoCloseVIO)
  4941.             else
  4942.             {
  4943.                 CHAR            szText[500];
  4944.  
  4945.                 // no auto-close: confirmation wnd
  4946.                 doshWriteLogEntry(pShutdownData->ShutdownLogFile, "    Not found on auto-close list, auto-close is off, query-action dlg:");
  4947.  
  4948.                 cmnSetDlgHelpPanel(ID_XFH_CLOSEVIO);
  4949.                 pShutdownData->SDConsts.hwndVioDlg
  4950.                     = cmnLoadDlg(pShutdownData->SDConsts.hwndShutdownStatus,
  4951.                                  cmn_fnwpDlgWithHelp,
  4952.                                  ID_SDD_CLOSEVIO,
  4953.                                  NULL);
  4954.  
  4955.                 // ID_SDDI_VDMAPPTEXT has "\"cannot be closed automatically";
  4956.                 // prefix session title
  4957.                 strcpy(szText, "\"");
  4958.                 strcat(szText, pShutdownData->VioItem.swctl.szSwtitle);
  4959.                 WinQueryDlgItemText(pShutdownData->SDConsts.hwndVioDlg, ID_SDDI_VDMAPPTEXT,
  4960.                                     100, &(szText[strlen(szText)]));
  4961.                 WinSetDlgItemText(pShutdownData->SDConsts.hwndVioDlg, ID_SDDI_VDMAPPTEXT,
  4962.                                   szText);
  4963.  
  4964.                 cmnSetControlsFont(pShutdownData->SDConsts.hwndVioDlg, 1, 5000);
  4965.                 winhCenterWindow(pShutdownData->SDConsts.hwndVioDlg);
  4966.                 ulReply = WinProcessDlg(pShutdownData->SDConsts.hwndVioDlg);
  4967.  
  4968.                 if (ulReply == DID_OK)
  4969.                 {
  4970.                     doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      'OK' pressed");
  4971.  
  4972.                     // "OK" button pressed: check the radio buttons
  4973.                     // for what to do with this session
  4974.                     if (winhIsDlgItemChecked(pShutdownData->SDConsts.hwndVioDlg, ID_XSDI_ACL_SKIP))
  4975.                     {
  4976.                         ulSessionAction = ACL_SKIP;
  4977.                         doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      xsdCloseVIO: 'Skip' selected");
  4978.                     }
  4979.                     else if (winhIsDlgItemChecked(pShutdownData->SDConsts.hwndVioDlg, ID_XSDI_ACL_WMCLOSE))
  4980.                     {
  4981.                         ulSessionAction = ACL_WMCLOSE;
  4982.                         doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      xsdCloseVIO: 'WM_CLOSE' selected");
  4983.                     }
  4984.                     else if (winhIsDlgItemChecked(pShutdownData->SDConsts.hwndVioDlg, ID_XSDI_ACL_KILLSESSION))
  4985.                     {
  4986.                         ulSessionAction = ACL_KILLSESSION;
  4987.                         doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      xsdCloseVIO: 'Kill' selected");
  4988.                     }
  4989.  
  4990.                     // "store item" checked?
  4991.                     if (ulSessionAction)
  4992.                         if (winhIsDlgItemChecked(pShutdownData->SDConsts.hwndVioDlg, ID_XSDI_ACL_STORE))
  4993.                         {
  4994.                             ULONG ulInvalid = 0;
  4995.                             // "store" checked:
  4996.                             // add item to list
  4997.                             PAUTOCLOSELISTITEM pliNew = malloc(sizeof(AUTOCLOSELISTITEM));
  4998.                             strncpy(pliNew->szItemName,
  4999.                                     pShutdownData->VioItem.swctl.szSwtitle,
  5000.                                     sizeof(pliNew->szItemName)-1);
  5001.                             pliNew->szItemName[99] = 0;
  5002.                             pliNew->usAction = ulSessionAction;
  5003.                             lstAppendItem(&pShutdownData->llAutoClose,
  5004.                                           pliNew);
  5005.  
  5006.                             // write list back to OS2.INI
  5007.                             ulInvalid = xsdWriteAutoCloseItems(&pShutdownData->llAutoClose);
  5008.                             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "         Updated auto-close list in OS2.INI, rc: %d",
  5009.                                         ulInvalid);
  5010.                         }
  5011.                 }
  5012.                 else if (ulReply == ID_SDDI_CANCELSHUTDOWN)
  5013.                 {
  5014.                     // "Cancel shutdown" pressed:
  5015.                     // pass to main window
  5016.                     WinPostMsg(pShutdownData->SDConsts.hwndMain, WM_COMMAND,
  5017.                                MPFROM2SHORT(ID_SDDI_CANCELSHUTDOWN, 0),
  5018.                                MPNULL);
  5019.                     doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      'Cancel shutdown' pressed");
  5020.                 }
  5021.                 // else: we could also get DID_CANCEL; this means
  5022.                 // that the dialog was closed because the Update
  5023.                 // thread determined that a session was closed
  5024.                 // manually, so we just do nothing...
  5025.  
  5026.                 WinDestroyWindow(pShutdownData->SDConsts.hwndVioDlg);
  5027.                 pShutdownData->SDConsts.hwndVioDlg = NULLHANDLE;
  5028.             } // end else (optAutoCloseVIO)
  5029.         }
  5030.  
  5031.         doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  5032.                           "      xsdCloseVIO: ulSessionAction is %d", ulSessionAction);
  5033.  
  5034.         // OK, let's see what to do with this session
  5035.         switch (ulSessionAction)
  5036.                     // this is 0 if nothing is to be done
  5037.         {
  5038.             case ACL_WMCLOSE:
  5039.                 WinPostMsg((WinWindowFromID(pShutdownData->VioItem.swctl.hwnd, FID_SYSMENU)),
  5040.                            WM_SYSCOMMAND,
  5041.                            (MPARAM)SC_CLOSE, MPNULL);
  5042.                 doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      xsdCloseVIO: Posted SC_CLOSE to sysmenu, hwnd: 0x%lX",
  5043.                        WinWindowFromID(pShutdownData->VioItem.swctl.hwnd, FID_SYSMENU));
  5044.             break;
  5045.  
  5046.             /* case ACL_CTRL_C:     removed V0.9.19 (2002-05-23) [umoeller]
  5047.                 DosSendSignalException(pShutdownData->VioItem.swctl.idProcess,
  5048.                                        XCPT_SIGNAL_INTR);
  5049.                 doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      xsdCloseVIO: Sent INTR signal to pid 0x%lX",
  5050.                        pShutdownData->VioItem.swctl.idProcess);
  5051.             break; */
  5052.  
  5053.             case ACL_KILLSESSION:
  5054.                 DosKillProcess(DKP_PROCESS, pShutdownData->VioItem.swctl.idProcess);
  5055.                 doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      xsdCloseVIO: Killed pid 0x%lX",
  5056.                        pShutdownData->VioItem.swctl.idProcess);
  5057.             break;
  5058.  
  5059.             case ACL_SKIP:
  5060.                 WinPostMsg(pShutdownData->SDConsts.hwndMain, WM_COMMAND,
  5061.                            MPFROM2SHORT(ID_SDDI_SKIPAPP, 0),
  5062.                            MPNULL);
  5063.                 doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      xsdCloseVIO: Posted ID_SDDI_SKIPAPP");
  5064.             break;
  5065.         }
  5066.     }
  5067.  
  5068.     doshWriteLogEntry(pShutdownData->ShutdownLogFile, "  Done with xsdCloseVIO");
  5069. }
  5070.  
  5071. /*
  5072.  *@@ CloseOneItem:
  5073.  *      implementation for ID_SDMI_CLOSEITEM in
  5074.  *      ID_SDMI_CLOSEITEM. Closes one item on
  5075.  *      the shutdown list, depending on the
  5076.  *      item's type.
  5077.  *
  5078.  *@@added V0.9.9 (2001-04-04) [umoeller]
  5079.  */
  5080.  
  5081. static VOID CloseOneItem(PSHUTDOWNDATA pShutdownData,
  5082.                          HWND hwndListbox,
  5083.                          PSHUTLISTITEM pItem)
  5084. {
  5085.     CHAR        szTitle[1024];
  5086.     USHORT      usItem;
  5087.  
  5088.     // compose string from item
  5089.     xsdLongTitle(szTitle, pItem);
  5090.  
  5091.     doshWriteLogEntry(pShutdownData->ShutdownLogFile, "    Item: %s", szTitle);
  5092.  
  5093.     // find string in the invisible list box
  5094.     usItem = (USHORT)WinSendMsg(hwndListbox,
  5095.                                 LM_SEARCHSTRING,
  5096.                                 MPFROM2SHORT(0, LIT_FIRST),
  5097.                                 (MPARAM)szTitle);
  5098.     // and select it
  5099.     if ((usItem != (USHORT)LIT_NONE))
  5100.         WinPostMsg(hwndListbox,
  5101.                    LM_SELECTITEM,
  5102.                    (MPARAM)usItem,
  5103.                    (MPARAM)TRUE);
  5104.  
  5105.     // update status window: "Closing xxx"
  5106.     xsdUpdateClosingStatus(pShutdownData->SDConsts.hwndShutdownStatus,
  5107.                            pItem->swctl.szSwtitle);
  5108.  
  5109.     // now check what kind of action needs to be done
  5110.     if (pItem->pObject)
  5111.     {
  5112.         // we have a WPS window
  5113.         // (cannot be WarpCenter, cannot be Desktop):
  5114.         _wpClose(pItem->pObject);
  5115.                     // WPObject::goes thru the list of USAGE_OPENVIEW
  5116.                     // useitems and sends WM_CLOSE to each of them
  5117.  
  5118.         doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  5119.                "      Open Desktop object, called wpClose(pObject)");
  5120.     }
  5121.     else if (pItem->swctl.hwnd)
  5122.     {
  5123.         // no WPS window: differentiate further
  5124.         doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  5125.                "      swctl.hwnd found: 0x%lX",
  5126.                pItem->swctl.hwnd);
  5127.  
  5128.         if (    (pItem->swctl.bProgType == PROG_VDM)
  5129.              || (pItem->swctl.bProgType == PROG_WINDOWEDVDM)
  5130.              || (pItem->swctl.bProgType == PROG_FULLSCREEN)
  5131.              || (pItem->swctl.bProgType == PROG_WINDOWABLEVIO)
  5132.              // || (pItem->swctl.bProgType == PROG_DEFAULT)
  5133.            )
  5134.         {
  5135.             // not a PM session: ask what to do (handled below)
  5136.             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      Seems to be VIO, swctl.bProgType: 0x%lX", pItem->swctl.bProgType);
  5137.             if (    (pShutdownData->SDConsts.hwndVioDlg == NULLHANDLE)
  5138.                  || (strcmp(szTitle, pShutdownData->szVioTitle) != 0)
  5139.                )
  5140.             {
  5141.                 // "Close VIO window" not currently open:
  5142.                 doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      Posting ID_SDMI_CLOSEVIO");
  5143.                 WinPostMsg(pShutdownData->SDConsts.hwndMain, WM_COMMAND,
  5144.                            MPFROM2SHORT(ID_SDMI_CLOSEVIO, 0),
  5145.                            MPNULL);
  5146.             }
  5147.             /// else do nothing
  5148.         }
  5149.         else
  5150.             // if (WinWindowFromID(pItem->swctl.hwnd, FID_SYSMENU))
  5151.             // removed V0.9.0 (UM 99-10-22)
  5152.         {
  5153.             // window has system menu: close PM application;
  5154.             // WM_SAVEAPPLICATION and WM_QUIT is what WinShutdown
  5155.             // does too for every message queue per process;
  5156.             // re-enabled this here per window V0.9.13 (2001-06-17) [umoeller]
  5157.             doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  5158.                    "      Posting WM_SAVEAPPLICATION to hwnd 0x%lX",
  5159.                    pItem->swctl.hwnd);
  5160.  
  5161.             WinPostMsg(pItem->swctl.hwnd,
  5162.                        WM_SAVEAPPLICATION,
  5163.                        MPNULL, MPNULL);
  5164.  
  5165.             doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  5166.                    "      Posting WM_QUIT to hwnd 0x%lX",
  5167.                    pItem->swctl.hwnd);
  5168.  
  5169.             WinPostMsg(pItem->swctl.hwnd,
  5170.                        WM_QUIT,
  5171.                        MPNULL, MPNULL);
  5172.         }
  5173.         /* else
  5174.         {
  5175.             // no system menu: try something more brutal
  5176.             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      Has no sys menu, posting WM_CLOSE to hwnd 0x%lX",
  5177.                         pItem->swctl.hwnd);
  5178.  
  5179.             WinPostMsg(pItem->swctl.hwnd,
  5180.                        WM_CLOSE,
  5181.                        MPNULL,
  5182.                        MPNULL);
  5183.         } */
  5184.     }
  5185.     else
  5186.     {
  5187.         doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  5188.                "      Helpless... leaving item alone, pid: 0x%lX",
  5189.                pItem->swctl.idProcess);
  5190.         // DosKillProcess(DKP_PROCESS, pItem->swctl.idProcess);
  5191.     }
  5192. }
  5193.  
  5194. /*
  5195.  *@@ fnwpShutdownThread:
  5196.  *      window procedure for both the main (debug) window and
  5197.  *      the status window; it receives messages from the Update
  5198.  *      threads, so that it can update the windows' contents
  5199.  *      accordingly; it also controls this thread by suspending
  5200.  *      or killing it, if necessary, and setting semaphores.
  5201.  *      Note that the main (debug) window with the listbox is only
  5202.  *      visible in debug mode (signalled to xfInitiateShutdown).
  5203.  *
  5204.  *      Runs on the Shutdown thread.
  5205.  *
  5206.  *@@changed V0.9.0 [umoeller]: adjusted for new linklist.c functions
  5207.  *@@changed V0.9.0 [umoeller]: fixed some inconsistensies in ID_SDMI_CLOSEVIO
  5208.  *@@changed V0.9.0 [umoeller]: changed shutdown logging to stdio functions (fprintf etc.)
  5209.  *@@changed V0.9.0 [umoeller]: changed "reuse Desktop startup folder" to use XWPGLOBALSHARED
  5210.  *@@changed V0.9.0 [umoeller]: added xsdFlushWPS2INI call
  5211.  *@@changed V0.9.1 (99-12-10) [umoeller]: extracted VIO code to xsdCloseVIO
  5212.  *@@changed V0.9.4 (2000-07-11) [umoeller]: added wpWaitForClose for Desktop
  5213.  *@@changed V0.9.4 (2000-07-15) [umoeller]: added special treatment for WarpCenter
  5214.  *@@changed V0.9.6 (2000-10-27) [umoeller]: fixed special treatment for WarpCenter
  5215.  *@@changed V0.9.7 (2000-12-08) [umoeller]: now taking WarpCenterFirst setting into account
  5216.  *@@changed V0.9.9 (2001-03-07) [umoeller]: now using all settings in SHUTDOWNDATA
  5217.  *@@changed V0.9.9 (2001-03-07) [umoeller]: fixed race condition on closing XCenter
  5218.  *@@changed V0.9.9 (2001-04-04) [umoeller]: extracted CloseOneItem
  5219.  *@@changed V0.9.9 (2001-04-04) [umoeller]: moved all post-close stuff to fntShutdownThread
  5220.  *@@changed V0.9.12 (2001-04-29) [umoeller]: now starting update thread after shutdown folder processing
  5221.  *@@changed V0.9.12 (2001-04-29) [umoeller]: now using new shutdown folder implementation
  5222.  *@@changed V0.9.16 (2001-10-22) [pr]: fixed bug trying to close the first switch list item twice
  5223.  *@@changed V0.9.19 (2002-06-18) [umoeller]: now running shutdown folder only for shutdown, not restart wps
  5224.  */
  5225.  
  5226. static MRESULT EXPENTRY fnwpShutdownThread(HWND hwndFrame, ULONG msg, MPARAM mp1, MPARAM mp2)
  5227. {
  5228.     MRESULT         mrc = MRFALSE;
  5229.  
  5230.     switch(msg)
  5231.     {
  5232.         // case WM_INITDLG:     // both removed V0.9.9 (2001-03-07) [umoeller]
  5233.         // case WM_CREATE:
  5234.  
  5235.         case WM_COMMAND:
  5236.         {
  5237.             PSHUTDOWNDATA   pShutdownData;
  5238.             HWND            hwndListbox;
  5239.  
  5240.             if (!(pShutdownData = (PSHUTDOWNDATA)WinQueryWindowPtr(hwndFrame,
  5241.                                                                    QWL_USER)))
  5242.                 break;
  5243.  
  5244.             hwndListbox = WinWindowFromID(pShutdownData->SDConsts.hwndMain,
  5245.                                           ID_SDDI_LISTBOX);
  5246.  
  5247.             switch (SHORT1FROMMP(mp1))
  5248.             {
  5249.                 /*
  5250.                  * ID_SDDI_BEGINSHUTDOWN:
  5251.                  *
  5252.                  */
  5253.  
  5254.                 case ID_SDDI_BEGINSHUTDOWN:
  5255.                 {
  5256.                     // this is either posted by the "Begin shutdown"
  5257.                     // button (in debug mode) or otherwise automatically
  5258.                     // after the first update initiated by the Update
  5259.                     // thread
  5260.  
  5261.                     // pShutdownData->ulStatus is still XSD_IDLE at this point
  5262.  
  5263.                     XFolder         *pShutdownFolder;
  5264.  
  5265.                     #ifdef DEBUG_SHUTDOWN
  5266.                         _Pmpf((" ---> ID_SDDI_BEGINSHUTDOWN"));
  5267.                     #endif
  5268.  
  5269.                     doshWriteLogEntry(pShutdownData->ShutdownLogFile, "  ID_SDDI_BEGINSHUTDOWN, hwnd: 0x%lX", hwndFrame);
  5270.  
  5271.                     WinShowWindow(pShutdownData->SDConsts.hwndShutdownStatus, TRUE);
  5272.  
  5273.                     // empty trash can?
  5274.                     if (    (pShutdownData->sdParams.optEmptyTrashCan)
  5275.                          && (cmnTrashCanReady())
  5276.                        )
  5277.                     {
  5278.                         APIRET arc = NO_ERROR;
  5279.                         WinSetDlgItemText(pShutdownData->SDConsts.hwndShutdownStatus, ID_SDDI_STATUS,
  5280.                                           cmnGetString(ID_XSSI_FOPS_EMPTYINGTRASHCAN)) ; // pszFopsEmptyingTrashCan
  5281.                         doshWriteLogEntry(pShutdownData->ShutdownLogFile, "    Emptying trash can...");
  5282.  
  5283.                         arc = cmnEmptyDefTrashCan(pShutdownData->habShutdownThread,
  5284.                                                             // synchronously
  5285.                                                   NULL,
  5286.                                                   NULLHANDLE);   // no confirm
  5287.                         if (arc == NO_ERROR)
  5288.                             // success:
  5289.                             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "    Done emptying trash can.");
  5290.                         else
  5291.                         {
  5292.                             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "    Emptying trash can failed, rc: %d.",
  5293.                                     arc);
  5294.                             if (cmnMessageBoxExt(pShutdownData->SDConsts.hwndShutdownStatus,
  5295.                                                  104, // "error"
  5296.                                                  NULL, 0,
  5297.                                                  189, // "empty failed"
  5298.                                                  MB_YESNO)
  5299.                                     != MBID_YES)
  5300.                             {
  5301.                                 // stop:
  5302.                                 WinPostMsg(pShutdownData->SDConsts.hwndMain, WM_COMMAND,
  5303.                                            MPFROM2SHORT(ID_SDDI_CANCELSHUTDOWN, 0),
  5304.                                            MPNULL);
  5305.  
  5306.                                 break;      // was missing V0.9.19 (2002-06-18) [umoeller]
  5307.                             }
  5308.                         }
  5309.                     }
  5310.  
  5311.                     // now run items in Shutdown folder
  5312.                     // but only if we're shutting down, not on restart wps
  5313.                     // V0.9.19 (2002-06-18) [umoeller]
  5314.                     if (    (pShutdownData->sdParams.ulCloseMode == SHUT_SHUTDOWN)
  5315.                                 // not restart Desktop (1), not logoff (2)
  5316.                          && (pShutdownFolder = _wpclsQueryFolder(_WPFolder,
  5317.                                                                  (PSZ)XFOLDER_SHUTDOWNID,
  5318.                                                                  TRUE))
  5319.                        )
  5320.                     {
  5321.                         doshWriteLogEntry(pShutdownData->ShutdownLogFile, "    Processing shutdown folder...");
  5322.  
  5323.                         // using new implementation V0.9.12 (2001-04-29) [umoeller]
  5324.                         _xwpStartFolderContents(pShutdownFolder,
  5325.                                                 0);         // wait mode
  5326.  
  5327.                         doshWriteLogEntry(pShutdownData->ShutdownLogFile, "    Started processing shutdown folder.");
  5328.                     }
  5329.  
  5330.                     // now build our shutlist V0.9.12 (2001-04-29) [umoeller]
  5331.                     xsdUpdateListBox(pShutdownData->habShutdownThread,
  5332.                                      pShutdownData,
  5333.                                      hwndListbox);
  5334.  
  5335.                     // create the Update thread now
  5336.                     // V0.9.12 (2001-04-28) [umoeller]
  5337.                     // moved this down here, we shouldn't start this
  5338.                     // before the shutdown folder has finished
  5339.                     // processing, or we'll close the windows we've
  5340.                     // started ourselves
  5341.                     if (thrQueryID(&G_tiUpdateThread) == NULLHANDLE)
  5342.                     {
  5343.                         thrCreate(&G_tiUpdateThread,
  5344.                                   fntUpdateThread,
  5345.                                   NULL, // running flag
  5346.                                   "ShutdownUpdate",
  5347.                                   THRF_PMMSGQUEUE | THRF_WAIT_EXPLICIT,
  5348.                                         // but wait explicit V0.9.12 (2001-04-29) [umoeller]
  5349.                                         // added msgq V0.9.16 (2002-01-13) [umoeller]
  5350.                                   (ULONG)pShutdownData);  // V0.9.9 (2001-03-07) [umoeller]
  5351.  
  5352.                         doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  5353.                                __FUNCTION__ ": Update thread started, tid: 0x%lX",
  5354.                                thrQueryID(&G_tiUpdateThread));
  5355.                     }
  5356.  
  5357.                     // set progress bar to the left
  5358.                     WinSendMsg(pShutdownData->hwndProgressBar,
  5359.                                WM_UPDATEPROGRESSBAR,
  5360.                                (MPARAM)0,
  5361.                                (MPARAM)1);
  5362.  
  5363.                     // close open WarpCenter first, if desired
  5364.                     // V0.9.7 (2000-12-08) [umoeller]
  5365.                     doshWriteLogEntry(pShutdownData->ShutdownLogFile, "  WarpCenter treatment:");
  5366.                     if (somIsObj(G_pAwakeWarpCenter))       // global variable (xfobj.c, kernel.h) V0.9.20 (2002-07-25) [umoeller]
  5367.                     {
  5368.                         if (pShutdownData->SDConsts.hwndOpenWarpCenter)
  5369.                         {
  5370.                             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      WarpCenter found, has HWND 0x%lX",
  5371.                                    pShutdownData->SDConsts.hwndOpenWarpCenter);
  5372.                             if (pShutdownData->sdParams.optWarpCenterFirst)
  5373.                             {
  5374.                                 doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      WarpCenterFirst is ON, posting WM_COMMAND 0x66F7");
  5375.                                 xsdUpdateClosingStatus(pShutdownData->SDConsts.hwndShutdownStatus,
  5376.                                                        "WarpCenter");
  5377.                                 WinPostMsg(pShutdownData->SDConsts.hwndOpenWarpCenter,
  5378.                                            WM_COMMAND,
  5379.                                            MPFROMSHORT(0x66F7),
  5380.                                                 // "Close" menu item in WarpCenter context menu...
  5381.                                                 // nothing else works right!
  5382.                                            MPFROM2SHORT(CMDSRC_OTHER,
  5383.                                                         FALSE));     // keyboard?!?
  5384.                                 winhSleep(400);
  5385.                                 pShutdownData->SDConsts.hwndOpenWarpCenter = NULLHANDLE;
  5386.                             }
  5387.                             else
  5388.                                 doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      WarpCenterFirst is OFF, skipping...");
  5389.                         }
  5390.                         else
  5391.                             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "      WarpCenter not found.");
  5392.                     }
  5393.  
  5394.                     // mark status as "closing windows now"
  5395.                     G_ulShutdownState = XSD_CLOSINGWINDOWS;
  5396.                     WinEnableControl(pShutdownData->SDConsts.hwndMain,
  5397.                                       ID_SDDI_BEGINSHUTDOWN,
  5398.                                       FALSE);
  5399.  
  5400.                     // V0.9.16 (2001-10-22) [pr]: ID_SDMI_UPDATESHUTLIST kicks this off
  5401.                     /* WinPostMsg(pShutdownData->SDConsts.hwndMain,
  5402.                                WM_COMMAND,
  5403.                                MPFROM2SHORT(ID_SDMI_CLOSEITEM, 0),
  5404.                                MPNULL); */
  5405.                 }
  5406.                 break;
  5407.  
  5408.                 /*
  5409.                  * ID_SDMI_CLOSEITEM:
  5410.                  *     this msg is posted first upon receiving
  5411.                  *     ID_SDDI_BEGINSHUTDOWN and subsequently for every
  5412.                  *     window that is to be closed; we only INITIATE
  5413.                  *     closing the window here by posting messages
  5414.                  *     or killing the window; we then rely on the
  5415.                  *     update thread to realize that the window has
  5416.                  *     actually been removed from the Tasklist. The
  5417.                  *     Update thread then posts ID_SDMI_UPDATESHUTLIST,
  5418.                  *     which will then in turn post another ID_SDMI_CLOSEITEM.
  5419.                  */
  5420.  
  5421.                 case ID_SDMI_CLOSEITEM:
  5422.                 {
  5423.                     PSHUTLISTITEM pItem;
  5424.  
  5425.                     doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  5426.                            "  ID_SDMI_CLOSEITEM");
  5427.  
  5428.                     // get task list item to close from linked list
  5429.                     if (pItem = xsdQueryCurrentItem(pShutdownData))
  5430.                     {
  5431.                         CloseOneItem(pShutdownData,
  5432.                                      hwndListbox,
  5433.                                      pItem);
  5434.                     } // end if (pItem)
  5435.                     else
  5436.                     {
  5437.                         // no more items left: enter phase 2 (save WPS)
  5438.                         doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  5439.                                "    All items closed. Posting WM_QUIT...");
  5440.  
  5441.                         G_ulShutdownState = XSD_ALLCLOSED_SAVING;
  5442.  
  5443.                         WinPostMsg(pShutdownData->SDConsts.hwndMain,
  5444.                                    WM_QUIT,     // V0.9.9 (2001-04-04) [umoeller]
  5445.                                    0,
  5446.                                    0);
  5447.                     }
  5448.                 }
  5449.                 break;
  5450.  
  5451.                 /*
  5452.                  * ID_SDDI_SKIPAPP:
  5453.                  *     comes from the "Skip" button
  5454.                  */
  5455.  
  5456.                 case ID_SDDI_SKIPAPP:
  5457.                 {
  5458.                     PSHUTLISTITEM   pItem,
  5459.                                     pSkipItem;
  5460.                     doshWriteLogEntry(pShutdownData->ShutdownLogFile, "  ID_SDDI_SKIPAPP, hwnd: 0x%lX", hwndFrame);
  5461.  
  5462.                     pItem = xsdQueryCurrentItem(pShutdownData);
  5463.                     if (pItem)
  5464.                     {
  5465.                         doshWriteLogEntry(pShutdownData->ShutdownLogFile, "    Adding %s to the list of skipped items",
  5466.                                pItem->swctl.szSwtitle);
  5467.  
  5468.                         if (pShutdownData->fSkippedSemOwned = !DosRequestMutexSem(pShutdownData->hmtxSkipped, 4000))
  5469.                         {
  5470.                             pSkipItem = malloc(sizeof(SHUTLISTITEM));
  5471.                             memcpy(pSkipItem, pItem, sizeof(SHUTLISTITEM));
  5472.  
  5473.                             lstAppendItem(&pShutdownData->llSkipped,
  5474.                                           pSkipItem);
  5475.                             DosReleaseMutexSem(pShutdownData->hmtxSkipped);
  5476.                             pShutdownData->fSkippedSemOwned = FALSE;
  5477.                         }
  5478.                     }
  5479.  
  5480.                     // shutdown still running
  5481.                     // (started and not all done and not cancelled)?
  5482.                     if (G_ulShutdownState == XSD_CLOSINGWINDOWS)
  5483.                         WinPostMsg(pShutdownData->SDConsts.hwndMain,
  5484.                                    WM_COMMAND,
  5485.                                    MPFROM2SHORT(ID_SDMI_UPDATEPROGRESSBAR, 0),
  5486.                                    MPNULL);
  5487.                 }
  5488.                 break;
  5489.  
  5490.                 /*
  5491.                  * ID_SDMI_CLOSEVIO:
  5492.                  *     this is posted by ID_SDMI_CLOSEITEM when
  5493.                  *     a non-PM session is encountered; we will now
  5494.                  *     either close this session automatically or
  5495.                  *     open up a confirmation dlg
  5496.                  */
  5497.  
  5498.                 case ID_SDMI_CLOSEVIO:
  5499.                     xsdCloseVIO(pShutdownData,
  5500.                                 hwndFrame);
  5501.                 break;
  5502.  
  5503.                 /*
  5504.                  * ID_SDMI_UPDATESHUTLIST:
  5505.                  *    this cmd comes from the Update thread when
  5506.                  *    the task list has changed. This happens when
  5507.                  *    1)    something was closed by this function
  5508.                  *    2)    the user has closed something
  5509.                  *    3)    and even if the user has OPENED something
  5510.                  *          new.
  5511.                  *    We will then rebuilt the pliShutdownFirst list and
  5512.                  *    continue closing items, if Shutdown is currently in progress
  5513.                  */
  5514.  
  5515.                 case ID_SDMI_UPDATESHUTLIST:
  5516.                 {
  5517.                     // SHUTDOWNCONSTS  SDConsts;
  5518.                     #ifdef DEBUG_SHUTDOWN
  5519.                         DosBeep(10000, 50);
  5520.                     #endif
  5521.  
  5522.                     doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  5523.                            "  ID_SDMI_UPDATESHUTLIST, hwnd: 0x%lX",
  5524.                            hwndFrame);
  5525.  
  5526.                     xsdUpdateListBox(pShutdownData->habShutdownThread,
  5527.                                      pShutdownData,
  5528.                                      hwndListbox);
  5529.                         // this updates the Shutdown linked list
  5530.                     DosPostEventSem(pShutdownData->hevUpdated);
  5531.                         // signal update to Update thread
  5532.  
  5533.                     doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  5534.                            "    Rebuilt shut list, %d items remaining",
  5535.                            xsdCountRemainingItems(pShutdownData));
  5536.  
  5537.                     if (pShutdownData->SDConsts.hwndVioDlg)
  5538.                     {
  5539.                         USHORT usItem;
  5540.                         // "Close VIO" confirmation window is open:
  5541.                         // check if the item that was to be closed
  5542.                         // is still in the listbox; if so, exit,
  5543.                         // if not, close confirmation window and
  5544.                         // continue
  5545.                         usItem = (USHORT)WinSendMsg(hwndListbox,
  5546.                                                     LM_SEARCHSTRING,
  5547.                                                     MPFROM2SHORT(0, LIT_FIRST),
  5548.                                                     (MPARAM)pShutdownData->szVioTitle);
  5549.  
  5550.                         if ((usItem != (USHORT)LIT_NONE))
  5551.                             break;
  5552.                         else
  5553.                         {
  5554.                             WinPostMsg(pShutdownData->SDConsts.hwndVioDlg,
  5555.                                        WM_CLOSE,
  5556.                                        MPNULL,
  5557.                                        MPNULL);
  5558.                             // this will result in a DID_CANCEL return code
  5559.                             // for WinProcessDlg in ID_SDMI_CLOSEVIO above
  5560.                             doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  5561.                                    "    Closed open VIO confirm dlg' dlg");
  5562.                         }
  5563.                     }
  5564.                     goto updateprogressbar;
  5565.                     // continue with update progress bar
  5566.                 }
  5567.  
  5568.                 /*
  5569.                  * ID_SDMI_UPDATEPROGRESSBAR:
  5570.                  *     well, update the progress bar in the
  5571.                  *     status window
  5572.                  */
  5573.  
  5574.                 case ID_SDMI_UPDATEPROGRESSBAR:
  5575.                 updateprogressbar:
  5576.                 {
  5577.                     ULONG           ulItemCount, ulMax, ulNow;
  5578.  
  5579.                     ulItemCount = xsdCountRemainingItems(pShutdownData);
  5580.                     if (ulItemCount > pShutdownData->ulMaxItemCount)
  5581.                     {
  5582.                         pShutdownData->ulMaxItemCount = ulItemCount;
  5583.                         pShutdownData->ulLastItemCount = -1; // enforce update
  5584.                     }
  5585.  
  5586.                     doshWriteLogEntry(pShutdownData->ShutdownLogFile, "  ID_SDMI_UPDATEPROGRESSBAR, hwnd: 0x%lX, remaining: %d, total: %d",
  5587.                            hwndFrame, ulItemCount, pShutdownData->ulMaxItemCount);
  5588.  
  5589.                     if ((ulItemCount) != pShutdownData->ulLastItemCount)
  5590.                     {
  5591.                         ulMax = pShutdownData->ulMaxItemCount;
  5592.                         ulNow = (ulMax - ulItemCount);
  5593.  
  5594.                         WinSendMsg(pShutdownData->hwndProgressBar,
  5595.                                    WM_UPDATEPROGRESSBAR,
  5596.                                    (MPARAM)ulNow,
  5597.                                    (MPARAM)(ulMax + 1));        // add one extra for desktop
  5598.                         pShutdownData->ulLastItemCount = (ulItemCount);
  5599.                     }
  5600.  
  5601.                     if (G_ulShutdownState == XSD_CLOSINGWINDOWS)
  5602.                         // if we're already in the process of shutting down, we will
  5603.                         // initiate closing the next item
  5604.                         WinPostMsg(pShutdownData->SDConsts.hwndMain,
  5605.                                    WM_COMMAND,
  5606.                                    MPFROM2SHORT(ID_SDMI_CLOSEITEM, 0),
  5607.                                    MPNULL);
  5608.                 }
  5609.                 break;
  5610.  
  5611.                 /*
  5612.                  * DID_CANCEL:
  5613.                  * ID_SDDI_CANCELSHUTDOWN:
  5614.                  *
  5615.                  */
  5616.  
  5617.                 case DID_CANCEL:
  5618.                 case ID_SDDI_CANCELSHUTDOWN:
  5619.                     // results from the "Cancel shutdown" buttons in both the
  5620.                     // main (debug) and the status window; we set a semaphore
  5621.                     // upon which the Update thread will terminate itself,
  5622.                     // and WM_QUIT is posted to the main (debug) window, so that
  5623.                     // the message loop in the main Shutdown thread function ends
  5624.                     if (winhIsDlgItemEnabled(pShutdownData->SDConsts.hwndShutdownStatus,
  5625.                                              ID_SDDI_CANCELSHUTDOWN))
  5626.                     {
  5627.                         // mark shutdown status as cancelled
  5628.                         G_ulShutdownState = XSD_CANCELLED;
  5629.  
  5630.                         doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  5631.                                 "  DID_CANCEL/ID_SDDI_CANCELSHUTDOWN, hwnd: 0x%lX");
  5632.  
  5633.                         /* if (pShutdownData->hPOC)
  5634.                             ((PPROCESSCONTENTINFO)pShutdownData->hPOC)->fCancelled = TRUE; */
  5635.                         WinEnableControl(pShutdownData->SDConsts.hwndShutdownStatus,
  5636.                                          ID_SDDI_CANCELSHUTDOWN,
  5637.                                          FALSE);
  5638.                         WinEnableControl(pShutdownData->SDConsts.hwndShutdownStatus,
  5639.                                          ID_SDDI_SKIPAPP,
  5640.                                          FALSE);
  5641.                         WinEnableControl(pShutdownData->SDConsts.hwndMain,
  5642.                                          ID_SDDI_BEGINSHUTDOWN,
  5643.                                          TRUE);
  5644.  
  5645.                         WinPostMsg(pShutdownData->SDConsts.hwndMain,
  5646.                                    WM_QUIT,     // V0.9.9 (2001-04-04) [umoeller]
  5647.                                    0,
  5648.                                    MPNULL);
  5649.                     }
  5650.                 break;
  5651.  
  5652.                 default:
  5653.                     mrc = WinDefDlgProc(hwndFrame, msg, mp1, mp2);
  5654.             } // end switch;
  5655.         }
  5656.         break;  // end case WM_COMMAND
  5657.  
  5658.         // other msgs: have them handled by the usual WC_FRAME wnd proc
  5659.         default:
  5660.            mrc = WinDefDlgProc(hwndFrame, msg, mp1, mp2);
  5661.         break;
  5662.     }
  5663.  
  5664.     return mrc;
  5665. }
  5666.  
  5667. /* ******************************************************************
  5668.  *
  5669.  *   here comes the "Finish" routines
  5670.  *
  5671.  ********************************************************************/
  5672.  
  5673. /*
  5674.  *  The following routines are called to finish shutdown
  5675.  *  after all windows have been closed and the system is
  5676.  *  to be shut down or APM power-off'ed or rebooted or
  5677.  *  whatever.
  5678.  *
  5679.  *  All of these routines run on the Shutdown thread.
  5680.  */
  5681.  
  5682. /*
  5683.  *@@ fncbUpdateINIStatus:
  5684.  *      this is a callback func for prfhSaveINIs for
  5685.  *      updating the progress bar.
  5686.  *
  5687.  *      Runs on the Shutdown thread.
  5688.  */
  5689.  
  5690. static MRESULT EXPENTRY fncbUpdateINIStatus(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  5691. {
  5692.     if (hwnd)
  5693.         WinSendMsg(hwnd, msg, mp1, mp2);
  5694.     return ((MPARAM)TRUE);
  5695. }
  5696.  
  5697. /*
  5698.  *@@ fncbINIError:
  5699.  *      callback func for prfhSaveINIs (/helpers/winh.c).
  5700.  *
  5701.  *      Runs on the Shutdown thread.
  5702.  */
  5703.  
  5704. static MRESULT EXPENTRY fncbSaveINIError(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  5705. {
  5706.     return ((MRESULT)cmnMessageBox(HWND_DESKTOP,
  5707.                                    "XShutdown: Error",
  5708.                                    (PSZ)mp1,     // error text
  5709.                                    NULLHANDLE, // no help
  5710.                                    (ULONG)mp2)   // MB_ABORTRETRYIGNORE or something
  5711.        );
  5712. }
  5713.  
  5714. /*
  5715.  *@@ xsd_fnSaveINIsProgress:
  5716.  *
  5717.  *@@added V0.9.5 (2000-08-13) [umoeller]
  5718.  */
  5719.  
  5720. BOOL _Optlink xsd_fnSaveINIsProgress(ULONG ulUser,
  5721.                                            // in: user param specified with
  5722.                                            // xprfCopyProfile and xprfSaveINIs
  5723.                                            // (progress bar HWND)
  5724.                                      ULONG ulProgressNow,
  5725.                                            // in: current progress
  5726.                                      ULONG ulProgressMax)
  5727.                                            // in: maximum progress
  5728. {
  5729.     HWND hwndProgress = (HWND)ulUser;
  5730.     if (hwndProgress)
  5731.         WinSendMsg(hwndProgress,
  5732.                    WM_UPDATEPROGRESSBAR,
  5733.                    (MPARAM)ulProgressNow,
  5734.                    (MPARAM)ulProgressMax);
  5735.     return TRUE;
  5736. }
  5737.  
  5738. /*
  5739.  *@@ xsdFinishShutdown:
  5740.  *      this is the generic routine called by
  5741.  *      fntShutdownThread after closing all windows
  5742.  *      is complete and the system is to be shut
  5743.  *      down, depending on the user settings.
  5744.  *
  5745.  *      This evaluates the current shutdown settings and
  5746.  *      calls xsdFinishStandardReboot, xsdFinishUserReboot,
  5747.  *      xsdFinishAPMPowerOff, or xsdFinishStandardMessage.
  5748.  *
  5749.  *      Note that this is only called for "real" shutdown.
  5750.  *      For "Restart Desktop", xsdRestartWPS is called instead.
  5751.  *
  5752.  *      Runs on the Shutdown thread.
  5753.  *
  5754.  *@@changed V0.9.3 (2000-05-22) [umoeller]: added reboot animation
  5755.  *@@changed V0.9.5 (2000-08-13) [umoeller]: now using new save-INI routines (xprfSaveINIs)
  5756.  *@@changed V0.9.12 (2001-05-12) [umoeller]: animations frequently didn't show up, fixed
  5757.  */
  5758.  
  5759. VOID xsdFinishShutdown(PSHUTDOWNDATA pShutdownData) // HAB hab)
  5760. {
  5761.     APIRET      arc = NO_ERROR;
  5762.     ULONG       ulSaveINIs = 0;
  5763.  
  5764. #ifndef __NOXSHUTDOWN__
  5765.     ulSaveINIs = cmnQuerySetting(sulSaveINIS);
  5766. #endif
  5767.  
  5768.     // change the mouse pointer to wait state
  5769.     winhSetWaitPointer();
  5770.  
  5771.     // enforce saving of INIs
  5772.     WinSetDlgItemText(pShutdownData->SDConsts.hwndShutdownStatus, ID_SDDI_STATUS,
  5773.                       cmnGetString(ID_SDSI_SAVINGPROFILES)) ; // pszSDSavingProfiles
  5774.  
  5775. #ifndef __NOXSHUTDOWN__
  5776.     switch (ulSaveINIs)
  5777.     {
  5778.         case 2:         // do nothing:
  5779.             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "Saving INIs has been disabled, skipping.");
  5780.         break;
  5781.  
  5782.         case 1:     // old method:
  5783.             doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  5784.                               "Saving INIs, old method (prfhSaveINIs)...");
  5785.             arc = prfhSaveINIs(pShutdownData->habShutdownThread,
  5786.                                NULL, // pShutdownData->ShutdownLogFile, @@todo
  5787.                                (PFNWP)fncbUpdateINIStatus,
  5788.                                    // callback function for updating the progress bar
  5789.                                pShutdownData->hwndProgressBar,
  5790.                                    // status window handle passed to callback
  5791.                                WM_UPDATEPROGRESSBAR,
  5792.                                    // message passed to callback
  5793.                                (PFNWP)fncbSaveINIError);
  5794.                                    // callback for errors
  5795.             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "Done with prfhSaveINIs.");
  5796.         break;
  5797.  
  5798.         default:    // includes 0, new method
  5799. #endif
  5800.             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "Saving INIs, new method (xprfSaveINIs)...");
  5801.  
  5802.             arc = xprfSaveINIs(pShutdownData->habShutdownThread,
  5803.                                xsd_fnSaveINIsProgress,
  5804.                                pShutdownData->hwndProgressBar);
  5805.             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "Done with xprfSaveINIs.");
  5806. #ifndef __NOXSHUTDOWN__
  5807.         break;
  5808.     }
  5809. #endif
  5810.  
  5811.     if (arc != NO_ERROR)
  5812.     {
  5813.         doshWriteLogEntry(pShutdownData->ShutdownLogFile, "--- Error %d was reported!", arc);
  5814.  
  5815.         // error occured: ask whether to restart the WPS
  5816.         if (cmnMessageBoxExt(pShutdownData->SDConsts.hwndShutdownStatus,
  5817.                              110,
  5818.                              NULL, 0,
  5819.                              111,
  5820.                              MB_YESNO)
  5821.                     == MBID_YES)
  5822.         {
  5823.             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "User requested to restart Desktop.");
  5824.             xsdRestartWPS(pShutdownData->habShutdownThread,
  5825.                           FALSE);
  5826.                     // doesn't return
  5827.         }
  5828.     }
  5829.  
  5830.     doshWriteLogEntry(pShutdownData->ShutdownLogFile, "Now preparing shutdown...");
  5831.  
  5832.     // always say "releasing filesystems"
  5833.     WinShowPointer(HWND_DESKTOP, FALSE);
  5834.     WinSetDlgItemText(pShutdownData->SDConsts.hwndShutdownStatus,
  5835.                       ID_SDDI_STATUS,
  5836.                       cmnGetString(ID_SDSI_FLUSHING)) ; // pszSDFlushing
  5837.  
  5838.     // here comes the settings-dependent part:
  5839.     // depending on what we are to do after shutdown,
  5840.     // we switch to different routines which handle
  5841.     // the rest.
  5842.     // I guess this is a better solution than putting
  5843.     // all this stuff in the same routine because after
  5844.     // DosShutdown(), even the swapper file is blocked,
  5845.     // and if the following code is in the swapper file,
  5846.     // it cannot be executed. From user reports, I suspect
  5847.     // this has happened on some memory-constrained
  5848.     // systems with XFolder < V0.84. So we better put
  5849.     // all the code together which will be used together.
  5850.  
  5851.     /* if (pShutdownData->sdParams.optAnimate)
  5852.         // hps for animation later
  5853.         // moved this here V0.9.12 (2001-05-12) [umoeller]
  5854.         hpsScreen = WinGetScreenPS(HWND_DESKTOP); */
  5855.  
  5856.     G_ulShutdownState = XSD_SAVEDONE_FLUSHING;
  5857.  
  5858.     if (pShutdownData->sdParams.optReboot)
  5859.     {
  5860.         // reboot:
  5861.         if (strlen(pShutdownData->sdParams.szRebootCommand) == 0)
  5862.             // no user reboot action:
  5863.             xsdFinishStandardReboot(pShutdownData);
  5864.         else
  5865.             // user reboot action:
  5866.             xsdFinishUserReboot(pShutdownData);
  5867.     }
  5868.     else if (pShutdownData->sdParams.optDebug)
  5869.     {
  5870.         // debug mode: just sleep a while
  5871.         DosSleep(2000);
  5872.     }
  5873.     else if (pShutdownData->sdParams.optAPMPowerOff)
  5874.     {
  5875.         // no reboot, but APM power off?
  5876.         xsdFinishAPMPowerOff(pShutdownData);
  5877.     }
  5878.     else
  5879.         // normal shutdown: show message
  5880.         xsdFinishStandardMessage(pShutdownData);
  5881.  
  5882.     // the xsdFinish* functions never return;
  5883.     // so we only get here in debug mode and
  5884.     // return
  5885. }
  5886.  
  5887. /*
  5888.  *@@ PowerOffAnim:
  5889.  *      calls anmPowerOff with the proper timings
  5890.  *      to display the cute power-off animation.
  5891.  *
  5892.  *@@added V0.9.7 (2000-12-13) [umoeller]
  5893.  */
  5894.  
  5895. static VOID PowerOffAnim(HPS hpsScreen)
  5896. {
  5897.     anmPowerOff(hpsScreen,
  5898.                 500, 800, 200, 300);
  5899. }
  5900.  
  5901. /*
  5902.  *@@ xsdFinishStandardMessage:
  5903.  *      this finishes the shutdown procedure,
  5904.  *      displaying the "Shutdown is complete..."
  5905.  *      window and halting the system.
  5906.  *
  5907.  *      Runs on the Shutdown thread.
  5908.  *
  5909.  *@@changed V0.9.12 (2001-05-12) [umoeller]: animations frequently didn't show up, fixed
  5910.  *@@changed V0.9.17 (2002-02-05) [pr]: fix text not displaying by making it a 2 stage message
  5911.  */
  5912.  
  5913. VOID xsdFinishStandardMessage(PSHUTDOWNDATA pShutdownData)
  5914. {
  5915.     ULONG flShutdown = 0;
  5916.     PSZ pszComplete = cmnGetString(ID_SDDI_COMPLETE);
  5917.     PSZ pszSwitchOff = cmnGetString(ID_SDDI_SWITCHOFF);
  5918.  
  5919.     HPS hpsScreen = WinGetScreenPS(HWND_DESKTOP);
  5920.  
  5921.     // setup Ctrl+Alt+Del message window; this needs to be done
  5922.     // before DosShutdown, because we won't be able to reach the
  5923.     // resource files after that
  5924.     HWND hwndCADMessage = WinLoadDlg(HWND_DESKTOP, NULLHANDLE,
  5925.                                      WinDefDlgProc,
  5926.                                      pShutdownData->hmodResource,
  5927.                                      ID_SDD_CAD,
  5928.                                      NULL);
  5929.     winhCenterWindow(hwndCADMessage);  // wnd is still invisible
  5930.  
  5931. #ifndef __NOXSHUTDOWN__
  5932.     flShutdown = cmnQuerySetting(sflXShutdown);
  5933. #endif
  5934.  
  5935.     if (pShutdownData->ShutdownLogFile)
  5936.     {
  5937.         doshWriteLogEntry(pShutdownData->ShutdownLogFile, "xsdFinishStandardMessage: Calling DosShutdown(0), closing log.");
  5938.         doshClose(&pShutdownData->ShutdownLogFile);
  5939.         pShutdownData->ShutdownLogFile = NULL;
  5940.     }
  5941.  
  5942.     if (flShutdown & XSD_ANIMATE_SHUTDOWN)
  5943.         // cute power-off animation
  5944.         PowerOffAnim(hpsScreen);
  5945.     else
  5946.         // only hide the status window if
  5947.         // animation is off, because otherwise
  5948.         // PM will repaint part of the animation
  5949.         WinShowWindow(pShutdownData->SDConsts.hwndShutdownStatus, FALSE);
  5950.  
  5951.     // now, this is fun:
  5952.     // here's a fine example of how to completely
  5953.     // block the system without ANY chance to escape.
  5954.     // -- show "Shutdown in progress..." window
  5955.     WinShowWindow(hwndCADMessage, TRUE);
  5956.     // -- make the CAD message system-modal
  5957.     WinSetSysModalWindow(HWND_DESKTOP, hwndCADMessage);
  5958.     // -- kill the tasklist (/helpers/winh.c)
  5959.     // so that Ctrl+Esc fails
  5960.     winhKillTasklist();
  5961.     // -- block all other WPS threads
  5962.     DosEnterCritSec();
  5963.     // -- block all file access
  5964.     DosShutdown(0); // V0.9.16 (2002-02-03) [pr]: moved this down
  5965.     // -- update the message
  5966.     WinSetDlgItemText(hwndCADMessage, ID_SDDI_PROGRESS1, pszComplete);
  5967.     WinSetDlgItemText(hwndCADMessage, ID_SDDI_PROGRESS2, pszSwitchOff);
  5968.     // -- and now loop forever!
  5969.     while (TRUE)
  5970.         DosSleep(10000);
  5971. }
  5972.  
  5973. /*
  5974.  *@@ xsdFinishStandardReboot:
  5975.  *      this finishes the shutdown procedure,
  5976.  *      rebooting the computer using the standard
  5977.  *      reboot procedure (DOS.SYS).
  5978.  *      There's no shutdown animation here.
  5979.  *
  5980.  *      Runs on the Shutdown thread.
  5981.  *
  5982.  *@@changed V0.9.3 (2000-05-22) [umoeller]: added reboot animation
  5983.  *@@changed V0.9.12 (2001-05-12) [umoeller]: animations frequently didn't show up, fixed
  5984.  *@@changed V0.9.16 (2002-01-05) [umoeller]: fixed hang on loading string resource
  5985.  */
  5986.  
  5987. VOID xsdFinishStandardReboot(PSHUTDOWNDATA pShutdownData)
  5988. {
  5989.     ULONG       flShutdown = 0;
  5990.     HFILE       hIOCTL;
  5991.     ULONG       ulAction;
  5992.     BOOL        fShowRebooting = TRUE;
  5993.     // load string resource before shutting down
  5994.     // V0.9.16 (2002-01-05) [umoeller]
  5995.     PSZ         pszRebooting = cmnGetString(ID_SDSI_REBOOTING);
  5996.     HPS         hpsScreen = WinGetScreenPS(HWND_DESKTOP);
  5997.  
  5998. #ifndef __NOXSHUTDOWN__
  5999.     flShutdown = cmnQuerySetting(sflXShutdown);
  6000. #endif
  6001.  
  6002.     // if (optReboot), open DOS.SYS; this
  6003.     // needs to be done before DosShutdown() also
  6004.     if (DosOpen("\\DEV\\DOS$", &hIOCTL, &ulAction, 0L,
  6005.                FILE_NORMAL,
  6006.                OPEN_ACTION_OPEN_IF_EXISTS,
  6007.                OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE,
  6008.                0L)
  6009.         != NO_ERROR)
  6010.     {
  6011.         winhDebugBox(HWND_DESKTOP, "XShutdown", "The DOS.SYS device driver could not be opened. "
  6012.                  "XShutdown will be unable to reboot your computer. "
  6013.                  "Please consult the XFolder Online Reference for a remedy of this problem.");
  6014.     }
  6015.  
  6016.     if (pShutdownData->ShutdownLogFile)
  6017.     {
  6018.         doshWriteLogEntry(pShutdownData->ShutdownLogFile, "xsdFinishStandardReboot: Opened DOS.SYS, hFile: 0x%lX", hIOCTL);
  6019.         doshWriteLogEntry(pShutdownData->ShutdownLogFile, "xsdFinishStandardReboot: Calling DosShutdown(0), closing log.");
  6020.         doshClose(&pShutdownData->ShutdownLogFile);
  6021.         pShutdownData->ShutdownLogFile = NULL;
  6022.     }
  6023.  
  6024.     if (flShutdown & XSD_ANIMATE_REBOOT)  // V0.9.3 (2000-05-22) [umoeller]
  6025.     {
  6026.         // cute power-off animation
  6027.         PowerOffAnim(hpsScreen);
  6028.         fShowRebooting = FALSE;
  6029.     }
  6030.  
  6031.     DosShutdown(0);
  6032.         // @@todo what to do if this fails?
  6033.  
  6034.     // say "Rebooting..." if we had no animation
  6035.     if (fShowRebooting)
  6036.     {
  6037.         WinSetDlgItemText(pShutdownData->SDConsts.hwndShutdownStatus, ID_SDDI_STATUS,
  6038.                           pszRebooting) ; // pszSDRebooting
  6039.         DosSleep(500);
  6040.     }
  6041.  
  6042.     // restart the machine via DOS.SYS (opened above)
  6043.     DosDevIOCtl(hIOCTL, 0xd5, 0xab, NULL, 0, NULL, NULL, 0, NULL);
  6044.  
  6045.     // don't know if this function returns, but
  6046.     // we better make sure we don't return from this
  6047.     // function
  6048.     while (TRUE)
  6049.         DosSleep(10000);
  6050. }
  6051.  
  6052. /*
  6053.  *@@ xsdFinishUserReboot:
  6054.  *      this finishes the shutdown procedure,
  6055.  *      rebooting the computer by starting a
  6056.  *      user reboot command.
  6057.  *      There's no shutdown animation here.
  6058.  *
  6059.  *      Runs on the Shutdown thread.
  6060.  *
  6061.  *@@changed V0.9.3 (2000-05-22) [umoeller]: added reboot animation
  6062.  *@@changed V0.9.12 (2001-05-12) [umoeller]: animations frequently didn't show up, fixed
  6063.  */
  6064.  
  6065. VOID xsdFinishUserReboot(PSHUTDOWNDATA pShutdownData)
  6066. {
  6067.     // user reboot item: in this case, we don't call
  6068.     // DosShutdown(), which is supposed to be done by
  6069.     // the user reboot command
  6070.     ULONG   flShutdown = 0;
  6071.     CHAR    szTemp[CCHMAXPATH];
  6072.     PID     pid;
  6073.     ULONG   sid;
  6074.     HPS hpsScreen = WinGetScreenPS(HWND_DESKTOP);
  6075.  
  6076. #ifndef __NOXSHUTDOWN__
  6077.     flShutdown = cmnQuerySetting(sflXShutdown);
  6078. #endif
  6079.  
  6080.     if (flShutdown & XSD_ANIMATE_REBOOT)        // V0.9.3 (2000-05-22) [umoeller]
  6081.         // cute power-off animation
  6082.         PowerOffAnim(hpsScreen);
  6083.     else
  6084.     {
  6085.         sprintf(szTemp,
  6086.                 cmnGetString(ID_SDSI_STARTING),  // pszStarting
  6087.                 pShutdownData->sdParams.szRebootCommand);
  6088.         WinSetDlgItemText(pShutdownData->SDConsts.hwndShutdownStatus, ID_SDDI_STATUS,
  6089.                           szTemp);
  6090.     }
  6091.  
  6092.     if (pShutdownData->ShutdownLogFile)
  6093.     {
  6094.         doshWriteLogEntry(pShutdownData->ShutdownLogFile, "Trying to start user reboot cmd: %s, closing log.",
  6095.                pShutdownData->sdParams.szRebootCommand);
  6096.         doshClose(&pShutdownData->ShutdownLogFile);
  6097.         pShutdownData->ShutdownLogFile = NULL;
  6098.     }
  6099.  
  6100.     sprintf(szTemp, "/c %s", pShutdownData->sdParams.szRebootCommand);
  6101.     if (doshQuickStartSession("cmd.exe",
  6102.                               szTemp,
  6103.                               FALSE, // background
  6104.                               SSF_CONTROL_INVISIBLE, // but auto-close
  6105.                               TRUE,  // wait flag
  6106.                               &sid,
  6107.                               &pid,
  6108.                               NULL)
  6109.                != NO_ERROR)
  6110.     {
  6111.         winhDebugBox(HWND_DESKTOP,
  6112.                      "XShutdown",
  6113.                      "The user-defined restart command failed. We will now restart the WPS.");
  6114.         xsdRestartWPS(pShutdownData->habShutdownThread,
  6115.                       FALSE);
  6116.     }
  6117.     else
  6118.         // no error:
  6119.         // we'll always get here, since the user reboot
  6120.         // is now taking place in a different process, so
  6121.         // we just stop here
  6122.         while (TRUE)
  6123.             DosSleep(10000);
  6124. }
  6125.  
  6126. /*
  6127.  *@@ xsdFinishAPMPowerOff:
  6128.  *      this finishes the shutdown procedure,
  6129.  *      using the functions in apm.c.
  6130.  *
  6131.  *      Runs on the Shutdown thread.
  6132.  *
  6133.  *@@changed V0.9.12 (2001-05-12) [umoeller]: animations frequently didn't show up, fixed
  6134.  */
  6135.  
  6136. VOID xsdFinishAPMPowerOff(PSHUTDOWNDATA pShutdownData)
  6137. {
  6138.     CHAR        szAPMError[500];
  6139.     ULONG       ulrcAPM = 0;
  6140.     ULONG       flShutdown = 0;
  6141.     HPS         hpsScreen = WinGetScreenPS(HWND_DESKTOP);
  6142.  
  6143. #ifndef __NOXSHUTDOWN__
  6144.     flShutdown = cmnQuerySetting(sflXShutdown);
  6145. #endif
  6146.  
  6147.     // prepare APM power off
  6148.     ulrcAPM = apmPreparePowerOff(szAPMError);
  6149.     doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  6150.                       "xsdFinishAPMPowerOff: apmPreparePowerOff returned 0x%lX",
  6151.                       ulrcAPM);
  6152.  
  6153.     if (ulrcAPM & APM_IGNORE)
  6154.     {
  6155.         // if this returns APM_IGNORE, we continue
  6156.         // with the regular shutdown w/out APM
  6157.         doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  6158.                           "APM_IGNORE, continuing with normal shutdown",
  6159.                           ulrcAPM);
  6160.  
  6161.         xsdFinishStandardMessage(pShutdownData);
  6162.         // this does not return
  6163.     }
  6164.     else if (ulrcAPM & APM_CANCEL)
  6165.     {
  6166.         // APM_CANCEL means cancel shutdown
  6167.         WinShowPointer(HWND_DESKTOP, TRUE);
  6168.         doshWriteLogEntry(pShutdownData->ShutdownLogFile,
  6169.                           "  APM error message: %s",
  6170.                           szAPMError);
  6171.  
  6172.         cmnMessageBox(HWND_DESKTOP,
  6173.                       "APM Error",
  6174.                       szAPMError,
  6175.                       NULLHANDLE, // no help
  6176.                       MB_CANCEL | MB_SYSTEMMODAL);
  6177.         // restart Desktop
  6178.         xsdRestartWPS(pShutdownData->habShutdownThread,
  6179.                       FALSE);
  6180.         // this does not return
  6181.     }
  6182.     // else: APM_OK means preparing went alright
  6183.  
  6184.     /* if (ulrcAPM & APM_DOSSHUTDOWN_0)
  6185.     {
  6186.         // shutdown request by apm.c:
  6187.         if (pShutdownData->ShutdownLogFile)
  6188.         {
  6189.             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "xsdFinishAPMPowerOff: Calling DosShutdown(0), closing log.");
  6190.             fclose(pShutdownData->ShutdownLogFile);
  6191.             pShutdownData->ShutdownLogFile = NULL;
  6192.         }
  6193.  
  6194.         DosShutdown(0);
  6195.     } */
  6196.     // if apmPreparePowerOff requested this,
  6197.     // do DosShutdown(1)
  6198.     if (ulrcAPM & APM_DOSSHUTDOWN_1)
  6199.     {
  6200.         if (pShutdownData->ShutdownLogFile)
  6201.         {
  6202.             doshWriteLogEntry(pShutdownData->ShutdownLogFile, "xsdFinishAPMPowerOff: Calling DosShutdown(1), closing log.");
  6203.             doshClose(&pShutdownData->ShutdownLogFile);
  6204.             pShutdownData->ShutdownLogFile = NULL;
  6205.         }
  6206.  
  6207.         DosShutdown(1);
  6208.     }
  6209.     // or if apmPreparePowerOff requested this,
  6210.     // do no DosShutdown()
  6211.  
  6212.     if (pShutdownData->ShutdownLogFile)
  6213.     {
  6214.         doshClose(&pShutdownData->ShutdownLogFile);
  6215.         pShutdownData->ShutdownLogFile = NULL;
  6216.     }
  6217.  
  6218.     if (flShutdown & XSD_ANIMATE_SHUTDOWN)
  6219.         // cute power-off animation
  6220.         PowerOffAnim(hpsScreen);
  6221.     else
  6222.         // only hide the status window if
  6223.         // animation is off, because otherwise
  6224.         // we get screen display errors
  6225.         // (hpsScreen...)
  6226.         WinShowWindow(pShutdownData->SDConsts.hwndShutdownStatus, FALSE);
  6227.  
  6228.     // if APM power-off was properly prepared
  6229.     // above, this flag is still TRUE; we
  6230.     // will now call the function which
  6231.     // actually turns the power off
  6232.     apmDoPowerOff(pShutdownData->sdParams.optAPMDelay);
  6233.     // we do _not_ return from that function
  6234. }
  6235.  
  6236. /* ******************************************************************
  6237.  *
  6238.  *   Update thread
  6239.  *
  6240.  ********************************************************************/
  6241.  
  6242. /*
  6243.  *@@ fntUpdateThread:
  6244.  *          this thread is responsible for monitoring the window list
  6245.  *          while XShutdown is running and windows are being closed.
  6246.  *
  6247.  *          It is created with a PM message queue from fntShutdown
  6248.  *          when shutdown is about to begin.
  6249.  *
  6250.  *          It builds an internal second PSHUTLISTITEM linked list
  6251.  *          from the PM window list every 100 ms and then compares
  6252.  *          it to the global pliShutdownFirst.
  6253.  *
  6254.  *          If they are different, this means that windows have been
  6255.  *          closed (or even maybe opened), so fnwpShutdownThread is posted
  6256.  *          ID_SDMI_UPDATESHUTLIST so that it can rebuild pliShutdownFirst
  6257.  *          and react accordingly, in most cases, close the next window.
  6258.  *
  6259.  *          This thread monitors its THREADINFO.fExit flag and exits if
  6260.  *          it is set to TRUE. See thrClose (threads.c) for how this works.
  6261.  *
  6262.  *          Global resources used by this thread:
  6263.  *          -- HEV hevUpdated: event semaphore posted by Shutdown thread
  6264.  *                             when it's done updating its shutitem list.
  6265.  *                             We wait for this semaphore after having
  6266.  *                             posted ID_SDMI_UPDATESHUTLIST.
  6267.  *          -- PLINKLIST pllShutdown: the global list of SHUTLISTITEMs
  6268.  *                                    which are left to be closed. This is
  6269.  *                                    also used by the Shutdown thread.
  6270.  *          -- HMTX hmtxShutdown: mutex semaphore for protecting pllShutdown.
  6271.  *
  6272.  *@@changed V0.9.0 [umoeller]: code has been re-ordered for semaphore safety.
  6273.  */
  6274.  
  6275. static void _Optlink fntUpdateThread(PTHREADINFO ptiMyself)
  6276. {
  6277.     PSZ             pszErrMsg = NULL;
  6278.  
  6279.     PSHUTDOWNDATA   pShutdownData = (PSHUTDOWNDATA)ptiMyself->ulData;
  6280.  
  6281.     BOOL            fLocked = FALSE;
  6282.     LINKLIST        llTestList;
  6283.  
  6284.     DosSetPriority(PRTYS_THREAD,
  6285.                    PRTYC_REGULAR,
  6286.                    +31,          // priority delta
  6287.                    0);           // this thread
  6288.  
  6289.  
  6290.     lstInit(&llTestList, TRUE);     // auto-free items
  6291.  
  6292.     TRY_LOUD(excpt1)
  6293.     {
  6294.         ULONG           ulShutItemCount = 0,
  6295.                         ulTestItemCount = 0;
  6296.         BOOL            fUpdated = FALSE;
  6297.  
  6298.         WinCancelShutdown(ptiMyself->hmq, TRUE);
  6299.  
  6300.         while (!G_tiUpdateThread.fExit)
  6301.         {
  6302.             ULONG ulDummy;
  6303.  
  6304.             // this is the first loop: we arrive here every time
  6305.             // the task list has changed */
  6306.             #ifdef DEBUG_SHUTDOWN
  6307.                 _Pmpf(( "UT: Waiting for update..." ));
  6308.             #endif
  6309.  
  6310.             DosResetEventSem(pShutdownData->hevUpdated, &ulDummy);
  6311.                         // V0.9.9 (2001-04-04) [umoeller]
  6312.  
  6313.             // have Shutdown thread update its list of items then
  6314.             WinPostMsg(pShutdownData->SDConsts.hwndMain, WM_COMMAND,
  6315.                        MPFROM2SHORT(ID_SDMI_UPDATESHUTLIST, 0),
  6316.                        MPNULL);
  6317.             fUpdated = FALSE;
  6318.  
  6319.             // shutdown thread is waiting for us to post the
  6320.             // "ready" semaphore, so do this now
  6321.             DosPostEventSem(ptiMyself->hevRunning);
  6322.  
  6323.             // now wait until Shutdown thread is done updating its
  6324.             // list; it then posts an event semaphore
  6325.             while (     (!fUpdated)
  6326.                     &&  (!G_tiUpdateThread.fExit)
  6327.                   )
  6328.             {
  6329.                 if (G_tiUpdateThread.fExit)
  6330.                 {
  6331.                     // we're supposed to exit:
  6332.                     fUpdated = TRUE;
  6333.                     #ifdef DEBUG_SHUTDOWN
  6334.                         _Pmpf(( "UT: Exit recognized" ));
  6335.                     #endif
  6336.                 }
  6337.                 else
  6338.                 {
  6339.                     ULONG   ulUpdate;
  6340.                     // query event semaphore post count
  6341.                     DosQueryEventSem(pShutdownData->hevUpdated, &ulUpdate);
  6342.                     fUpdated = (ulUpdate > 0);
  6343.                     #ifdef DEBUG_SHUTDOWN
  6344.                         _Pmpf(( "UT: update recognized" ));
  6345.                     #endif
  6346.                     DosSleep(100);
  6347.                 }
  6348.             } // while (!fUpdated);
  6349.  
  6350.             ulTestItemCount = 0;
  6351.             ulShutItemCount = 0;
  6352.  
  6353.             #ifdef DEBUG_SHUTDOWN
  6354.                 _Pmpf(( "UT: Waiting for task list change, loop 2..." ));
  6355.             #endif
  6356.  
  6357.             while (     (ulTestItemCount == ulShutItemCount)
  6358.                      && (!G_tiUpdateThread.fExit)
  6359.                   )
  6360.             {
  6361.                 // this is the second loop: we stay in here until the
  6362.                 // task list has changed; for monitoring this, we create
  6363.                 // a second task item list similar to the pliShutdownFirst
  6364.                 // list and compare the two
  6365.                 lstClear(&llTestList);
  6366.  
  6367.                 // create a test list for comparing the task list;
  6368.                 // this is our private list, so we need no mutex
  6369.                 // semaphore
  6370.                 xsdBuildShutList(ptiMyself->hab,
  6371.                                  pShutdownData,
  6372.                                  &llTestList);
  6373.  
  6374.                 // count items in the test list
  6375.                 ulTestItemCount = lstCountItems(&llTestList);
  6376.  
  6377.                 // count items in the list of the Shutdown thread;
  6378.                 // here we need a mutex semaphore, because the
  6379.                 // Shutdown thread might be working on this too
  6380.                 TRY_LOUD(excpt2)
  6381.                 {
  6382.                     if (fLocked = !DosRequestMutexSem(pShutdownData->hmtxShutdown, 4000))
  6383.                     {
  6384.                         ulShutItemCount = lstCountItems(&pShutdownData->llShutdown);
  6385.                         DosReleaseMutexSem(pShutdownData->hmtxShutdown);
  6386.                         fLocked = FALSE;
  6387.                     }
  6388.                 }
  6389.                 CATCH(excpt2) {} END_CATCH();
  6390.  
  6391.                 if (!G_tiUpdateThread.fExit)
  6392.                     DosSleep(100);
  6393.             } // end while; loop until either the Shutdown thread has set the
  6394.               // Exit flag or the list has changed
  6395.  
  6396.             #ifdef DEBUG_SHUTDOWN
  6397.                 _Pmpf(( "UT: Change or exit recognized" ));
  6398.             #endif
  6399.         }  // end while; loop until exit flag set
  6400.     } // end TRY_LOUD(excpt1)
  6401.     CATCH(excpt1)
  6402.     {
  6403.         // exception occured:
  6404.         // complain to the user
  6405.         if (pszErrMsg == NULL)
  6406.         {
  6407.             if (fLocked)
  6408.             {
  6409.                 DosReleaseMutexSem(pShutdownData->hmtxShutdown);
  6410.                 fLocked = FALSE;
  6411.             }
  6412.  
  6413.             // only report the first error, or otherwise we will
  6414.             // jam the system with msg boxes
  6415.             pszErrMsg = malloc(1000);
  6416.             if (pszErrMsg)
  6417.             {
  6418.                 strcpy(pszErrMsg, "An error occured in the XFolder Update thread. "
  6419.                         "In the root directory of your boot drive, you will find a "
  6420.                         "file named XFLDTRAP.LOG, which contains debugging information. "
  6421.                         "If you had shutdown logging enabled, you will also find the "
  6422.                         "file XSHUTDWN.LOG there. If not, please enable shutdown "
  6423.                         "logging in the Desktop's settings notebook. ");
  6424.                 krnPostThread1ObjectMsg(T1M_EXCEPTIONCAUGHT, (MPARAM)pszErrMsg,
  6425.                         (MPARAM)0); // don't enforce Desktop restart
  6426.  
  6427.                 doshWriteLogEntry(pShutdownData->ShutdownLogFile, "\n*** CRASH\n%s\n", pszErrMsg);
  6428.             }
  6429.         }
  6430.     } END_CATCH();
  6431.  
  6432.     // clean up
  6433.     #ifdef DEBUG_SHUTDOWN
  6434.         _Pmpf(( "UT: Exiting..." ));
  6435.     #endif
  6436.  
  6437.     if (fLocked)
  6438.     {
  6439.         // release our mutex semaphore
  6440.         DosReleaseMutexSem(pShutdownData->hmtxShutdown);
  6441.         fLocked = FALSE;
  6442.     }
  6443.  
  6444.     lstClear(&llTestList);
  6445.  
  6446.     #ifdef DEBUG_SHUTDOWN
  6447.         DosBeep(100, 100);
  6448.     #endif
  6449. }
  6450.  
  6451.  
  6452.