Solved

Terminate app after creating a new process

Posted on 2000-05-17
8
301 Views
Last Modified: 2013-11-20
Greetings experts,

I have an MFC program running on hundreds of machines in a factory. I want to add the capability for the program to automatically update itself when a new version comes out. The program is running off the local system hard disk as opposed to off a server. However, all machines can access a disk on a remote server.

When a certain event occurs I want the program to go out to this server and see if a new version of itself is out there. If so, this program will spawn a new program and then kill itself. This new program will copy the updated version of the other program to the local disk, start it ip and then kill itself. Voila, I will have updated the entire factory. Or so I hope.

Here, in 2 lines of code or less is what I am trying to do:

if( CreateProcess( NULL, "AnApp.exe", ..., &StartupInfo, &ProcInfo ) )
     AfxGetApp()->m_pMainWnd->SendMessage( WM_CLOSE );

The results are:

The destructor of my app's document class is called, but not the ExitInstance() function of the app. Also, if running in VC++ debug environment the debug program doesn't close until I close the app that was spawned (I'm actually using CALC.EXE for testing purposes). Then when the app closes, my debug log reports memory leaks.

Is there a problem with how I am closing my application (that is what CWinApp::OnAppExit() does), and/or is there some option in CreateProcess() that I need to make sure is properly set? Or is there a completely different and better way to do this?

Thanks much for your time,
NC
0
Comment
Question by:nchenkin
  • 3
  • 2
  • 2
  • +1
8 Comments
 

Accepted Solution

by:
raschalk earned 250 total points
ID: 2819347
Hi nchenkin
Here is a solution that solves your problem!
Ive implemented three methods in my View class in an SDI app to startup and shutdown applications at will. It has worked great for me. The key method is SafeTerminateProcess() which is described in MSDN or in one of the windows developers journals.

Let me know if you have any questions or problems. Ill be glad to help you get through to a solution for your particular application.

--Rudy

1.
In your header file declare the following:

BOOL Util_SafeTerminateProcess(HANDLE hProcess, UINT uExitCode);
void Util_StartMyApplication();
void Util_KillMyApplication();      
STARTUPINFO MyAppsi;
PROCESS_INFORMATION MyApppi;
BOOL MyApplicationIsRunning;

In Your .cpp file add the following functions:

1.

//This method starts an application using create process
void MySDIAppView::Util_StartMyApplication()
{
      
      static int started = 0;
      
      if (started == 0)
      {
            
            
            memset(&MyApppi, 0, sizeof(MyApppi));
            memset(&wicsi, 0, sizeof(MyAppsi));
            MyAppsi.cb = sizeof(MyAppsi);
            MyAppsi.dwFlags = STARTF_USESHOWWINDOW;
            MyAppsi.wShowWindow = SW_MINIMIZE;
            CreateProcess(0, "MyApp.exe", 0 , 0, 0, 0, 0, 0, &MyAppsi, &MyApppi);
            
            started++;
      }
    WaitForInputIdle(MyApppi.hProcess , 10000);
      
      MyApplicationIsRunning = TRUE;
}

2.

//This method will shutdown an application started by  //MySDIAppView::Util_StartMyApplication()
void MySDIAppView::Util_KillMyApplication()
{
  if (MyApplicationIsRunning)
   {
     if (Util_SafeTerminateProcess(MyApppi.hProcess, 0xDEADBEEF))
      {
        DWORD dwT, dwP;
                  
        GetExitCodeProcess(MyApppi.hProcess, &dwP);
        GetExitCodeThread(MyApppi.hThread, &dwT);
                  
      if (dwT != 0xDEADBEEF)
      {
         //handle error here
                              
      }
               if (dwT != dwP)
      {
      //handle error code here                  
      }

       }
      CloseHandle(MyApppi.hProcess);
      CloseHandle(MyApppi.hThread);
   }
            
   MyApplicationIsRunning = FALSE;
            
  }
}

3.

//this is a generic method described in MSDN (??) for killing a process.
// There is a writeup of how it uses a remote thread to infiltrate the app
//targeted to be shutdown and forces it to shutdown.
BOOL MySDIAppView::Util_SafeTerminateProcess(HANDLE hProcess, UINT uExitCode)
{
   //#define STRICT
   DWORD dwTID, dwCode, dwErr = 0;


     HANDLE hProcessDup = INVALID_HANDLE_VALUE;
     HANDLE hRT = NULL;
     HINSTANCE hKernel = GetModuleHandle("Kernel32");
     BOOL bSuccess = FALSE;

     BOOL bDup = DuplicateHandle(GetCurrentProcess(),
                                 hProcess,
                                 GetCurrentProcess(),
                                 &hProcessDup,
                                 PROCESS_ALL_ACCESS,
                                 FALSE,
                                 0);

     // Detect the special case where the process is
     // already dead...
     if ( GetExitCodeProcess((bDup) ? hProcessDup : hProcess, &dwCode) &&
          (dwCode == STILL_ACTIVE) )
     {
         FARPROC pfnExitProc;
           
         pfnExitProc = GetProcAddress(hKernel, "ExitProcess");

         hRT = CreateRemoteThread((bDup) ? hProcessDup : hProcess,
                                  NULL,
                                  0,
                                  (LPTHREAD_START_ROUTINE)pfnExitProc,
                                  (PVOID)uExitCode, 0, &dwTID);

         if ( hRT == NULL )
             dwErr = GetLastError();
     }
     else
     {
         dwErr = ERROR_PROCESS_ABORTED;
     }


     if ( hRT )
     {
         // Must wait process to terminate to
         // guarantee that it has exited...
         WaitForSingleObject((bDup) ? hProcessDup : hProcess,
                             INFINITE);

         CloseHandle(hRT);
         bSuccess = TRUE;
     }

     if ( bDup )
         CloseHandle(hProcessDup);

     if ( !bSuccess )
         SetLastError(dwErr);

     return bSuccess;
}
0
 
LVL 3

Expert Comment

by:mnewton022700
ID: 2819351
You could use ShellExecute instead of CreateProcess. Like this:

    if ((int)::ShellExecute(NULL, NULL, "Calc.exe", NULL, NULL, SW_SHOWNORMAL) > 32)
    {
        ::AfxGetApp()->m_pMainWnd->SendMessage(WM_CLOSE);
    }
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2819539
send a WM_QUIT instead of WM_CLOSE

0
 

Author Comment

by:nchenkin
ID: 2821813
Thanks experts,

One of my guys is looking into your solutions right now and we will get back to you shortly.

We appreciate it,
NC
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:nchenkin
ID: 2823335
raschalk,

Thanks for your information. But you say that you have an:

"SDI app to startup and shutdown applications at will"

But what we want is for an application to startup another application and then to cleanly shutdown ITSELF. It is NOT going to shutdown the app that it started.

How do we go about this?

The other suggestion didn't seem to work.

Thanks,
NC
0
 

Expert Comment

by:raschalk
ID: 2823692
Hi nchenkin,

If you want to shut down your own application you should post a WM_CLOSE message. Rather than my  giving you a garbled account of how to go about it, here is the procedure I have followed in the past. out of MSDN:


32-Bit Processes (and 16-Bit Processes under Windows 95)
Under Win32, the operating system promises to clean up resources owned by a process when it shuts down. This does not, however, mean that the process itself has had the opportunity to do any final flushes of information to disk, any final communication over a remote connection, nor does it mean that the process' DLL's will have the opportunity to execute their PROCESS_DETACH code. This is why it is generally preferable to avoid terminating an application under Windows 95 and Windows NT.

If you absolutely must shut down a process, follow these steps:

1.
Post a WM_CLOSE to all Top-Level windows owned by the process that you want to shut down. Many Windows applications respond to this message by shutting down.

2.
Use WaitForSingleObject() to wait for the handle of the process. Make sure you wait with a timeout value, because there are many situations in which the WM_CLOSE will not shut down the application. Remember to make the timeout long enough (either with WaitForSingleObject(), or with SendMessageTimeout()) so that a user can respond to any dialog boxes that were created in response to the WM_CLOSE message.

3.
If the return value is WAIT_OBJECT_0, then the application closed itself down cleanly. If the return value is WAIT_TIMEOUT, then you must use TerminateProcess() to shutdown the application. NOTE: If you are getting a return value from WaitForSingleObject() other then WAIT_OBJECT_0 or WAIT_TIMEOUT, use GetLastError() to determine the cause.

By following these steps, you give the application the best possible chance to shutdown cleanly (aside from IPC or user-intervention).
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2823877
Your problem is that you did a SendMessage rather than a PostMessage.

Also, try WM_QUIT instead of WM_CLOSE.  

WM_CLOSE applies to a window - and your app may be written in a way so that closing the main window doesn't shut down the app.

WM_QUIT applies to the application (when single threaded).

NOTE: If multithreaded, you may need to take some extra action to terminate other threads, but that is something you should be doing already when you shut down.

0
 

Author Comment

by:nchenkin
ID: 2835240
raschalk,

For some reason I wasn't notified by E-mail that you had responded to my comment.

Thanks, here's the points.

Ronslow,

Thanks for your further input as well. I appreciate it. We seem to have things working now.

NC
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now