/***************************************************************************
 *                                                                         *
 *   WGSSVC.C                                                              *
 *                                                                         *
 *   Copyright (c) 1988-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   Main executable for running WGS as a service under NT.                *
 *   It emulates WG.BAT runs WGSINT, WGSMSX, etc than tells SCM to         *
 *   to start WGSERVER as a service.  When WGSERVER exits it runs          *
 *   CLEANUP and/or timed events in necessary and based on WGSERVER exit   *
 *   code restarts it or terminates itself                                 *
 *                                                                         *
 *                                                - I. Minkin 5/21/96      *
 *                                                                         *
 ***************************************************************************/

#include <windows.h>
#include "gcomm.h"
#include "wgsmsgs.h"
#include "elogapi.h"
#include "svcnames.h"

#define WINSTA_ALLACCESS   (WINSTA_ACCESSCLIPBOARD|   \
                            WINSTA_ACCESSGLOBALATOMS| \
                            WINSTA_CREATEDESKTOP|     \
                            WINSTA_ENUMDESKTOPS|      \
                            WINSTA_ENUMERATE|         \
                            WINSTA_EXITWINDOWS|       \
                            WINSTA_READATTRIBUTES|    \
                            WINSTA_READSCREEN|        \
                            WINSTA_WRITEATTRIBUTES)

#define DESKTOP_ALLACCESS  (DESKTOP_CREATEMENU|       \
                            DESKTOP_CREATEWINDOW|     \
                            DESKTOP_ENUMERATE|        \
                            DESKTOP_HOOKCONTROL|      \
                            DESKTOP_JOURNALPLAYBACK|  \
                            DESKTOP_JOURNALRECORD|    \
                            DESKTOP_READOBJECTS|      \
                            DESKTOP_SWITCHDESKTOP|    \
                            DESKTOP_WRITEOBJECTS)

static SERVICE_STATUS_HANDLE hStatusHandle=NULL;  // service control handle
static HANDLE hActiveEvent=NULL;             // service is active
static ULONG winapiErr=NO_ERROR;             // Win32 API error
static ULONG appErr=NO_ERROR;                // application error
static GBOOL fAllowStop=TRUE;                // allow to stop the service

static VOID serviceMain(INT argc,CHAR *argv[]);
static ULONG stopWGSMain(SC_HANDLE hMainServ);
static ULONG startWGSMain(SC_HANDLE hMainServ);
static ULONG runApp(const CHAR *pPath,const CHAR *pCmdLine,INT *appExitCode);
static VOID WINAPI serviceControl(DWORD ctrlCode);
static GBOOL reportStatusToSCM(ULONG currentState,ULONG win32ExitCode,
                               ULONG appExitCode);
static GBOOL askToContinue(VOID);

static DWORD WINAPI reportProgressToSCM(VOID *pInfo);
static VOID runReportTh(HANDLE *hThread,HANDLE *hEvent);
static VOID stopReportTh(HANDLE hThread,HANDLE hEvent);

static HANDLE createExitCodeFile(VOID);
static GBOOL getWGSExitCode(HANDLE hFileMap,ULONG *exitCode);

static VOID CALLBACK timeMsgBoxTimerProc(HWND hWnd,UINT msg,UINT idEvent,
                                         DWORD time);
static INT WINAPI timeMessageBox(HWND hWnd,LPCTSTR text,LPCTSTR caption,
                                 UINT style,INT timeout);


INT WINAPI
WinMain(
HINSTANCE hInstance,               // handle of current instance
HINSTANCE hPrevInstance,           // handle of previous instance
LPSTR pCmdLine,                    // pointer to command line
INT nCmdShow)                      // show state of window
{
     CHAR *pTmp;
     CHAR tmpPath[2048];
     SERVICE_TABLE_ENTRY dispatchTable[]={
          { SSTARTNAME, (LPSERVICE_MAIN_FUNCTION)serviceMain },
          { NULL, NULL }
     };

     (VOID)hPrevInstance;
     (VOID)pCmdLine;
     (VOID)nCmdShow;
     if (isWinNT()) {
          GetModuleFileName(hInstance,tmpPath,sizeof(tmpPath));
          if ((pTmp=strrchr(tmpPath,'\\')) != NULL
           || (pTmp=strrchr(tmpPath,'/')) != NULL) {
               *pTmp='\0';
               chdir(tmpPath);
          }
          elogSetServName(SSTARTNAME);
          elogSetServDispName(SSTARTDISPNAME);
          if (!StartServiceCtrlDispatcher(dispatchTable)) {
               elogAPIError("StartServiceCtrlDispatcher failed.");
          }
     }
     return(0);
}

static VOID
serviceMain(                       // service main function
INT argc,
CHAR *argv[])
{
     const CHAR *pInsertStg[2];
     SC_HANDLE hMainServ=NULL;
     SC_HANDLE hSCManager=NULL;
     SERVICE_STATUS ssStatus;
     HANDLE hTh;
     HANDLE hEv;
     HDESK hDesk=NULL;
     HWINSTA hWinSta=NULL;
     HANDLE hFileMap=NULL;
     CHAR curPath[2048];
     GBOOL fStarted=FALSE;
     GBOOL fShortStartup=FALSE;
     CHAR cmdLine[512];
     ULONG wgsExitCode;
     INT appExitCode;
     const CHAR *startupApp="wgsysup.exe";
     const CHAR *cleanupApp="wgsysdn.exe";

__try {
     (VOID)argc;
     (VOID)argv;
     hActiveEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
     hStatusHandle=RegisterServiceCtrlHandler(SSTARTNAME,serviceControl);
     if (hStatusHandle == NULL) {
          elogAPIError("RegisterServiceCtrlHandler failed");
          winapiErr=GetLastError();
          return;
     }
     if (!reportStatusToSCM(SERVICE_START_PENDING,NO_ERROR,NO_ERROR)) {
          elogAPIError("reportStatusToSCMgr failed");
          winapiErr=GetLastError();
          return;
     }
     if ((hSCManager=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS)) == NULL) {
          elogAPIError("OpenSCManager failed");
          winapiErr=GetLastError();
          return;
     }
     if ((hMainServ=OpenService(hSCManager,SMAINNAME,SERVICE_ALL_ACCESS))
                                                                      == NULL) {
          elogAPIError("OpenService failed");
          winapiErr=GetLastError();
          return;
     }
     if ((hFileMap=createExitCodeFile()) == NULL) {
          elogAPIError("createExitCodeFile failed");
          winapiErr=GetLastError();
          return;
     }
     reportStatusToSCM(SERVICE_RUNNING,NO_ERROR,NO_ERROR);
     Sleep(2000);                  // helps SCM to update our status
     pInsertStg[0]=SSTARTDISPNAME;
     elogStatus(ELOG_SERVICE_STARTED,pInsertStg,1);
     fStarted=TRUE;
     GetCurrentDirectory(sizeof(curPath),curPath);
     if ((appErr=stopWGSMain(hMainServ)) != NO_ERROR) {
          return;
     }
     while (WaitForSingleObject(hActiveEvent,0) == WAIT_TIMEOUT) {
          fAllowStop=FALSE;
          reportStatusToSCM(SERVICE_RUNNING,NO_ERROR,NO_ERROR);
          if (fShortStartup) {
               sprintf(cmdLine,"%s NO",startupApp);
               if ((appErr=runApp(curPath,cmdLine,&appExitCode)) != NO_ERROR) {
                    return;
               }
               else if (appExitCode != 0) {
                    appErr=ELOG_FAILEDTORUN&(~SEV_MASK);
                    return;
               }
          }
          else {
               fShortStartup=TRUE;
               sprintf(cmdLine,"%s YES",startupApp);
               if ((appErr=runApp(curPath,cmdLine,&appExitCode)) != NO_ERROR) {
                    return;
               }
               else if (appExitCode != 0) {
                    appErr=ELOG_FAILEDTORUN&(~SEV_MASK);
                    return;
               }
          }
          if ((appErr=startWGSMain(hMainServ)) != NO_ERROR) {
               return;
          }
          fAllowStop=TRUE;
          reportStatusToSCM(SERVICE_RUNNING,NO_ERROR,NO_ERROR);
          SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_LOWEST);
          while (WaitForSingleObject(hActiveEvent,1000) == WAIT_TIMEOUT) {
               if (!QueryServiceStatus(hMainServ,&ssStatus)) {
                    elogAPIError("QueryServiceStatus failed");
                    winapiErr=GetLastError();
                    return;
               }
               if (ssStatus.dwCurrentState == SERVICE_STOPPED) {
                    SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_NORMAL);
                    if (getWGSExitCode(hFileMap,&wgsExitCode) == FALSE) {
                         pInsertStg[0]="Failed to get WGSERVER exit code";
                         elogStatus(ELOG_GENERICERROR,pInsertStg,1);
                         return;
                    }
                    if (wgsExitCode == SMAIN_FAILEDTOSTART) {
                         appErr=SMAIN_FAILEDTOSTART;
                         return;
                    }
                    if (wgsExitCode == 99) {  // GP
                         // HACK those "random" ExitCode checks will be simplified
                         // after review of WGSYSUP/WGSYSDN
                         if (askToContinue()) {
                              fShortStartup=FALSE;
                              break;    // do not run cleanup stuff if GP
                         }
                         else {
                              return;
                         }
                    }
                    sprintf(cmdLine,"%s %d",cleanupApp,wgsExitCode);
                    fAllowStop=FALSE;
                    reportStatusToSCM(SERVICE_RUNNING,NO_ERROR,NO_ERROR);
                    runApp(curPath,cmdLine,NULL);
                    fAllowStop=TRUE;
                    reportStatusToSCM(SERVICE_RUNNING,NO_ERROR,NO_ERROR);
                    if (wgsExitCode == 1
                     || wgsExitCode == 8) {
                         // operator shutdown or remote shutdown
                         return;
                    }
                    if (wgsExitCode == 70
                     || wgsExitCode == 80
                     || wgsExitCode == 90) {
                         // various flavors of catastro
                         if (askToContinue()) {
                              fShortStartup=FALSE;
                         }
                         else {
                              return;
                         }
                    }
                    break;
               }
          }
          if (WaitForSingleObject(hActiveEvent,0) == WAIT_OBJECT_0) {
               SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_NORMAL);
               ResetEvent(hActiveEvent);
               runReportTh(&hTh,&hEv);
               stopWGSMain(hMainServ);
               sprintf(cmdLine,"%s %d",cleanupApp,1); // emulate operator shutdown
               runApp(curPath,cmdLine,NULL);
               stopReportTh(hTh,hEv);
               SetEvent(hActiveEvent);
          }
     }
} __finally {
     reportStatusToSCM(SERVICE_STOP_PENDING,NO_ERROR,NO_ERROR);
     if (WaitForSingleObject(hActiveEvent,0) == WAIT_OBJECT_0) {
     // if Event is signaled we got here through a normal shutdown
     // so we reset appErr to avoid false alarms
          appErr=NO_ERROR;
     }
     if (hFileMap) {
          CloseHandle(hFileMap);
     }
     if (hWinSta) {
          CloseWindowStation(hWinSta);
     }
     if (hDesk) {
          CloseDesktop(hDesk);
     }
     if (hMainServ) {
          runReportTh(&hTh,&hEv);
          stopWGSMain(hMainServ);
          CloseServiceHandle(hMainServ);
          stopReportTh(hTh,hEv);
     }
     if (hSCManager) {
          CloseServiceHandle(hSCManager);
     }
     if (hActiveEvent) {
          CloseHandle(hActiveEvent);
     }
     pInsertStg[0]=SSTARTDISPNAME;
     if (fStarted) {
          elogStatus(ELOG_SERVICE_STOPPED,pInsertStg,1);
     }
     else {
          elogStatus(ELOG_SERVICE_FAILEDTOSTART,pInsertStg,1);
     }
     reportStatusToSCM(SERVICE_STOPPED,winapiErr,appErr);
     }
}

static ULONG                       //   return NO_ERROR or error code
stopWGSMain(                       // make sure WGSMain is not running
SC_HANDLE hMainServ)               //   handle to WGSMain service
{
     ULONG curTime;
     GBOOL fOk=TRUE;
     SERVICE_STATUS ssStatus;
     const CHAR *pInsertStg[2];

     if (!QueryServiceStatus(hMainServ,&ssStatus)) {
          elogAPIError("QueryServiceStatus failed");
          fOk=FALSE;
     }
     if (fOk && ssStatus.dwCurrentState == SERVICE_STOPPED) {
          return(NO_ERROR);
     }
     if (fOk && !ControlService(hMainServ,SERVICE_CONTROL_STOP,&ssStatus )) {
          elogAPIError("ControlService \"STOP\" failed");
          fOk=FALSE;
     }
     if (fOk && ssStatus.dwCurrentState != SERVICE_STOPPED) {
          if (WaitForSingleObject(hActiveEvent,0) != WAIT_TIMEOUT) {
               reportStatusToSCM(SERVICE_STOP_PENDING,NO_ERROR,NO_ERROR);
          }
          Sleep(2000);
          fOk=FALSE;
          // wiat 5 min. for WGSMain service to stop
          for (curTime=GetTickCount() ; (GetTickCount()-curTime) < 300000L ; ) {
               if (!QueryServiceStatus(hMainServ,&ssStatus)) {
                    elogAPIError("QueryServiceStatus failed");
                    break;
               }
               if (ssStatus.dwCurrentState == SERVICE_STOP_PENDING) {
                    if (WaitForSingleObject(hActiveEvent,0) != WAIT_TIMEOUT) {
                         reportStatusToSCM(SERVICE_STOP_PENDING,NO_ERROR,NO_ERROR);
                    }
                    Sleep(2000);
               }
               else if (ssStatus.dwCurrentState == SERVICE_STOPPED) {
                    fOk=TRUE;
                    break;
               }
               else {
                    break;
               }
          }
     }
     if (fOk && ssStatus.dwCurrentState == SERVICE_STOPPED) {
          return(NO_ERROR);
     }
     pInsertStg[0]=SSTARTDISPNAME;
     pInsertStg[1]=SMAINDISPNAME;
     elogStatus(ELOG_SERVICE_CANNOTSTOP,pInsertStg,2);
     return(ELOG_SERVICE_CANNOTSTOP&(~SEV_MASK));
}

static ULONG                       //   return NO_ERROR or error code
startWGSMain(                      // starts WGSMain
SC_HANDLE hMainServ)               //   handle to WGSMain service
{
     GBOOL fOk=FALSE;
     SERVICE_STATUS ssStatus;
     const CHAR *pInsertStg[2];

     if (!StartService(hMainServ,0,NULL)) {
          elogAPIError("StartService failed");
     }
     else {
          Sleep(2000);
          if (!QueryServiceStatus(hMainServ,&ssStatus)) {
               elogAPIError("QueryServiceStatus failed");
          }
          else {
               if (ssStatus.dwCurrentState != SERVICE_STOPPED) {
                    fOk=TRUE;
               }
          }
     }
     if (!fOk) {
          pInsertStg[0]=SSTARTDISPNAME;
          pInsertStg[1]=SMAINDISPNAME;
          elogStatus(ELOG_SERVICE_CANNOTSTART,pInsertStg,2);
          return(ELOG_SERVICE_CANNOTSTART&(~SEV_MASK));
     }
     return(NO_ERROR);
}

static ULONG                       //   return NO_ERROR or error code
runApp(                            // runs application
const CHAR *pPath,                 //   current path
const CHAR *pCmdLine,              //   application to run
INT *appExitCode)                  //   application exit code
{
     STARTUPINFO startInfo;
     PROCESS_INFORMATION procInfo;
     CHAR curExe[2048];
     CHAR msgBuf[512];
     DWORD exitCode;
     GBOOL fDone;
     GBOOL fOk=FALSE;
     const CHAR *pInsertStg[2];
     HANDLE hWaitFor[2];
     HANDLE hTh;
     HANDLE hEv;

     strcpy(curExe,pPath);
     stlcat(curExe,"\\",sizeof(curExe));
     stlcat(curExe,(CHAR *)pCmdLine,sizeof(curExe));
     memset(&startInfo,0,sizeof(STARTUPINFO));
     startInfo.cb=sizeof(STARTUPINFO);
     if (!CreateProcess(NULL,                // programm name
                         curExe,              // command line string
                         NULL,                // process security attributes
                         NULL,                // thread security attributes
                         TRUE,                // handle inheritance flag
                         CREATE_NEW_CONSOLE|
                         CREATE_NEW_PROCESS_GROUP|
                         CREATE_DEFAULT_ERROR_MODE, // creation flags
                         NULL,                // new environment block
                         pPath,               // current directory name
                         &startInfo,          // STARTUPINFO
                         &procInfo)) {        // PROCESS_INFORMATION
          elogAPIError("CreateProcess failed");
     }
     else {
          // we can not receive STOP while we are here because
          // we disable it before we got here.
          // however the code that handles it is left in case we want
          // to reenable it in the future
          // also this code works if user is trying to SHUTDOWN
          hWaitFor[0]=hActiveEvent;
          hWaitFor[1]=procInfo.hProcess;
          for (fDone=FALSE ; !fDone ; ) {
               switch(WaitForMultipleObjects(2,hWaitFor,FALSE,300000)) {
               case WAIT_TIMEOUT:
                    pInsertStg[0]=pCmdLine;
                    elogStatus(ELOG_APPISRUNNING,pInsertStg,1);
                    break;
               case WAIT_OBJECT_0:
               case WAIT_ABANDONED_0:
                    runReportTh(&hTh,&hEv);
                    sprintf(msgBuf,"%s is currently running! "
                              "Do you want to terminate it?",pCmdLine);
                    if (MessageBox(NULL,msgBuf,SSTARTDISPNAME,
                         MB_DEFAULT_DESKTOP_ONLY|MB_ICONSTOP|MB_OKCANCEL)
                                                                 == IDOK) {
                         TerminateProcess(procInfo.hProcess,0);
                         stopReportTh(hTh,hEv);
                         fDone=TRUE;
                    }
                    else {
                         stopReportTh(hTh,hEv);
                         reportStatusToSCM(SERVICE_RUNNING,NO_ERROR,NO_ERROR);
                         ResetEvent(hActiveEvent);
                    }
                    break;
               default:
                    fDone=fOk=TRUE;
                    break;
               }
          }
          GetExitCodeProcess(procInfo.hProcess,&exitCode);
          CloseHandle(procInfo.hProcess);
          CloseHandle(procInfo.hThread);
     }
     pInsertStg[0]=SSTARTDISPNAME;
     pInsertStg[1]=pCmdLine;
     if (fOk) {
          if (appExitCode) {
               *appExitCode=(INT)exitCode;
          }
          elogStatus(ELOG_RUNOK,pInsertStg,2);
          return(NO_ERROR);
     }
     else {
          elogStatus(ELOG_FAILEDTORUN,pInsertStg,2);
          return(ELOG_FAILEDTORUN&(~SEV_MASK));
     }
}

static VOID WINAPI
serviceControl(                    // service control function
DWORD ctrlCode)                    //   control code
{
     switch(ctrlCode) {
//     case SERVICE_CONTROL_SHUTDOWN:
     case SERVICE_CONTROL_STOP:
          SetEvent(hActiveEvent);
          reportStatusToSCM(SERVICE_STOP_PENDING,NO_ERROR,NO_ERROR);
          break;
     default:
          reportStatusToSCM(SERVICE_RUNNING,NO_ERROR,NO_ERROR);
          break;

     }
}

static GBOOL                       //   return TRUE - Ok
reportStatusToSCM(                 // reports service status to SCM
ULONG currentState,                //   state to report
ULONG win32ExitCode,               //   Win32 API error code
ULONG appExitCode)                 //   application error code
{
     SERVICE_STATUS ssStatus;
     static DWORD checkPoint=1;
     GBOOL fResult;

     ssStatus.dwControlsAccepted=0;
     if (currentState != SERVICE_START_PENDING
      && currentState != SERVICE_STOP_PENDING
      && fAllowStop) {
          ssStatus.dwControlsAccepted|=SERVICE_ACCEPT_STOP;
     }
     ssStatus.dwCurrentState=currentState;
     if (appExitCode == NO_ERROR) {
          ssStatus.dwWin32ExitCode=win32ExitCode;
     }
     else {
          ssStatus.dwWin32ExitCode=ERROR_SERVICE_SPECIFIC_ERROR;
     }
     ssStatus.dwServiceSpecificExitCode=appExitCode;
     ssStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
     if (currentState == SERVICE_RUNNING || currentState == SERVICE_STOPPED) {
          ssStatus.dwCheckPoint=0;
          ssStatus.dwWaitHint=0;
     }
     else {
          ssStatus.dwCheckPoint=checkPoint++;
          ssStatus.dwWaitHint=30000;
     }
     if (!(fResult=SetServiceStatus(hStatusHandle,&ssStatus))) {
          elogAPIError("SetServiceStatus Failed");
     }
     return(fResult);
}

static DWORD WINAPI                //   return code
reportProgressToSCM(               // notify SCM of our progress
VOID *pInfo)                       //   argument
{
     HANDLE hEvent=(HANDLE)pInfo;

     while (WaitForSingleObject(hEvent,2000) == WAIT_TIMEOUT) {
          reportStatusToSCM(SERVICE_STOP_PENDING,NO_ERROR,NO_ERROR);
     }
     return(0);
}

VOID
runReportTh(                       // creates thread to notify SCN
HANDLE *hThread,                   //   thread handle
HANDLE *hEvent)                    //   event handle
{
     DWORD thID;

     *hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
     *hThread=CreateThread(NULL,0,reportProgressToSCM,(LPVOID)(*hEvent),0,&thID);
     SetThreadPriority(*hThread,THREAD_PRIORITY_LOWEST);
}

VOID
stopReportTh(                      // terminates notification thread
HANDLE hThread,                    //   thread handle
HANDLE hEvent)                     //   event handle
{
     DWORD exitCode;

     if (hThread != NULL && GetExitCodeThread(hThread,&exitCode)
      && exitCode == STILL_ACTIVE) {
          SetEvent(hEvent);
          SetThreadPriority(hThread,THREAD_PRIORITY_HIGHEST);
          WaitForSingleObject(hThread,1000);
          CloseHandle(hThread);
          CloseHandle(hEvent);
     }
}

static GBOOL                       //   return TRUE-user wants to continue
askToContinue(VOID)                // ask if continue after GP/catastro
{
     GBOOL retVal;
     GBOOL fOnDefaultDesktop=FALSE;
     HDESK hDesk=NULL;
     HDESK hCurDesk;
     HWINSTA hCurWinSta;
     HWINSTA hWinSta;
     CHAR *mbCaption=SVR_FULL " Failure!";
     CHAR *mbText="The server will attempt to auto restart itself in 30 seconds.  "
                  "Click on OK to restart it immediately or CANCEL to abort the restart.";

     hCurWinSta=GetProcessWindowStation();
     hCurDesk=GetThreadDesktop(GetCurrentThreadId());
     if ((hWinSta=OpenWindowStation("WinSta0",TRUE,WINSTA_ALLACCESS)) == NULL) {
          elogAPIError("OpenWindowStation failed");
     }
     else if (!SetProcessWindowStation(hWinSta)) {
          elogAPIError("SetProcessWindowStation failed");
     }
     else if ((hDesk=OpenInputDesktop(0,FALSE,DESKTOP_ALLACCESS)) == NULL) {
          elogAPIError("OpenDesktop failed");
     }
     else if (!SetThreadDesktop(hDesk)) {
          elogAPIError("SetThreadDesktop failed");
     }
     else {
          fOnDefaultDesktop=TRUE;
     }
     if (fOnDefaultDesktop) {
          if (timeMessageBox(NULL,mbText,mbCaption,MB_ICONQUESTION|MB_OKCANCEL,30000) == IDOK) {
               retVal=TRUE;
          }
          else {
               retVal=FALSE;
          }
     }
     else {
          Sleep(30000);
          retVal=TRUE;
     }
     if (!SetProcessWindowStation(hCurWinSta)) {
          elogAPIError("SetProcessWindowStation(hCurWinSta) failed");
     }
     if (!SetThreadDesktop(hCurDesk)) {
          elogAPIError("SetThreadDesktop(hCurDesk) failed");
     }
     if (hDesk) {
          CloseDesktop(hDesk);
     }
     if (hWinSta) {
          CloseWindowStation(hWinSta);
     }
     return(retVal);
}

static HANDLE                      //   handle to memory mapped file
createExitCodeFile(VOID)           // create memopy mapped file for WGS
{                                  // to communicate exit code
     SECURITY_ATTRIBUTES sa;
     SECURITY_DESCRIPTOR *pSD;
     HANDLE hFile;

     pSD=(PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH);
     if (pSD == NULL) {
          return(NULL);
     }
     if (!InitializeSecurityDescriptor(pSD,SECURITY_DESCRIPTOR_REVISION)) {
          return(NULL);
     }
     // Add a NULL disc. ACL to the security descriptor.
     if (!SetSecurityDescriptorDacl(pSD,TRUE,(PACL)NULL,FALSE)) {
          return(NULL);
     }
     sa.nLength=sizeof(SECURITY_ATTRIBUTES);
     sa.lpSecurityDescriptor=pSD;
     sa.bInheritHandle=FALSE;
     hFile=CreateFileMapping((HANDLE)0xFFFFFFFF,&sa,PAGE_READWRITE,0,
                             sizeof(WGSEXITCODE),EXITCODE_FILENAME);
     return(hFile);
}

static GBOOL
getWGSExitCode(
HANDLE hFileMap,
ULONG *exitCode)
{
     WGSEXITCODE *wec;
     GBOOL retVal=FALSE;

     *exitCode=0;
     wec=(WGSEXITCODE *)MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,sizeof(WGSEXITCODE));
     if (wec == NULL) {
          elogAPIError("MapViewOfFile failed.");
          return(retVal);
     }
     if ((GetTickCount()-wec->timeTag) < 60000) {
          *exitCode=wec->exitCode;
          retVal=TRUE;
     }
     UnmapViewOfFile(wec);
     return(retVal);
}

////////////////////////////////////////////////////////////////////////////////

static VOID CALLBACK
timeMsgBoxTimerProc(
HWND hWnd,
UINT msg,
UINT idEvent,
DWORD time)
{
     (VOID)hWnd;
     (VOID)msg;
     (VOID)idEvent;
     (VOID)time;
     EndDialog(GetActiveWindow(),IDOK);
}


static INT WINAPI
timeMessageBox(
HWND hWnd,
LPCTSTR text,
LPCTSTR caption,
UINT style,
INT timeout) {

     INT result,timerID;

     timerID=SetTimer(NULL,0,timeout,(TIMERPROC)timeMsgBoxTimerProc);
     result=MessageBox(hWnd,text,caption,style);
     KillTimer(NULL,timerID);
     return(result);
}
