Running a program from a program

I have an application that minimizes itself and then launches another program with the ShellExecute command.  Is there any way I can find out when the second program is done so I can Restore the main window of the first app?  Please note that I have no access to the second app, so I can't have it send a message back.

Thanks for any help
Bob Z.
ZeinerRJAsked:
Who is Participating?
 
Answers2000Connect With a Mentor Commented:
MFC ? Win32 ?

From codeguru (http://www.codeguru.com)

(begin quote)

This article was contributed by Alan Chen.
This is a dll that exports a function called Wait(). Wait() is similiar with WinExec(). The difference is that Wait()

run an application and return until the application ends.

This project consists of 3 functions:

Wait()
Create a thread and wait for an event. Use pThreadEvent to identify if the called application ends. WaitForSingleObject()

pauses the application and waits for the called application to end.

_declspec(dllexport) BOOL Wait(CString szCmdLine)
{
    LPTHREADINFO pThreadInfo = new THREADINFO;
    CEvent *pThreadEvent = new CEvent(FALSE, TRUE);
    ASSERT_VALID(pThreadEvent);
    if(pThreadInfo)
    {
        pThreadInfo->pTermThreadEvent = pThreadEvent;
        pThreadInfo->strPathName = szCmdLine;

        AfxBeginThread(LaunchAndWait, pThreadInfo);
        WaitForSingleObject(pThreadEvent->m_hObject, INFINITE);
        return TRUE;
    }
    return FALSE;
}

LaunchAndWait()
Call LaunchApplication() to run the application and wait for an event.WaitForMultiObjects() wait for either the called application to end or the main process to end.

UINT LaunchAndWait(LPVOID pParam)
{
    LPTHREADINFO pThreadInfo = (LPTHREADINFO) pParam;
    PROCESS_INFORMATION stProcessInfo;
    if(LaunchApplication(pThreadInfo->strPathName, &stProcessInfo))
    {
        HANDLE hThreads[2];
        hThreads[0] = pThreadInfo->pTermThreadEvent->m_hObject;
        hThreads[1] = stProcessInfo.hProcess;
        DWORD dwIndex = WaitForMultipleObjects(2, hThreads, FALSE, INFINITE);
        CloseHandle(stProcessInfo.hThread);
        CloseHandle(stProcessInfo.hProcess);
        pThreadInfo->pTermThreadEvent->SetEvent();
        if(pThreadInfo)
            delete pThreadInfo;
    }
    else
        pThreadInfo->pTermThreadEvent->SetEvent();
    return 0;
}


LaunchApplication()
Call CreateProcess to run the application.

BOOL LaunchApplication(LPCTSTR pCmdLine, PROCESS_INFORMATION *pProcessInfo)
{
    STARTUPINFO stStartUpInfo;

    memset(&stStartUpInfo, 0, sizeof(STARTUPINFO));

    stStartUpInfo.cb = sizeof(STARTUPINFO);

    stStartUpInfo.dwFlags = STARTF_USESHOWWINDOW;
    stStartUpInfo.wShowWindow = SW_SHOWDEFAULT;

    return CreateProcess(NULL, (LPTSTR)pCmdLine, NULL, NULL, FALSE,
        NORMAL_PRIORITY_CLASS, NULL,
        NULL, &stStartUpInfo, pProcessInfo);
}

(end quote)

I believe there is a bug/feature - this won't work if the 2nd app is 16bit Windows or DOS.

You may also want to hide your app rather than just minimize it, otherwise the user can attempt to restore the app, and will be confused when it doesn't restore (because it won't respond to messages when "waiting").

You may also want to remove the "_declspec(dllexport)"
0
 
Answers2000Commented:
Ignore this comment of mine
--> You may also want to remove the "_declspec(dllexport)"

This is req'd I misread the code.
0
 
Answers2000Commented:
Arghhh!

Read it right first time!!  The _declspec is req'd if you are exporting the function from a DLL.  If you simply embed the code into your app, then you don't need it.  

So the original post was correct, and my 2:04PM comment is rubbish


0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
nietodCommented:
What you need to do is open a handle to the process with OpenProcess() and then wait on that handle with WaitForSingleObject().  When the process termiantes, WaitForSingleObject will return.  (You can do more fancy things if you want your application to "stay alive" while waiting, but that is the general idea.

The problem is that to use OpenProcess() you need the process's ID. Unfortunately you don't have the process's ID, you have its instance handle.  There is no way to convert to the ID that I know of.  I believe that is a security measure.  

To get around this, you could open the process with CreateProcess()  That way you can get the process's ID and use it to open a handle for the proccess.  However, CreateProcess needs the name and path of the executable to be run.  To get around this use FindExecutable().  This finds the executable that ShellExecute() would run for a specified file.
0
 
nietodCommented:
Answers2000, that's not really what he needs.  The root of the problem is that he doesn't have an executable file name to pass to CreateProcess() (or your procedure) and that ShellExecute() doesn't return the information needed to monitor the process started.
0
 
alexoCommented:
ZeinerRJ, the answer to your question is ShellExecuteEx().
See the documentation for the SHELLEXECUTEINFO structure.  Especially the hProcess
member.
0
 
nietodCommented:
Alex is that a handle to the process, as in a the return value of OpenProcess(), or is it the handle to the process's instance, as in the return value of ShellExecute()?  
0
 
alexoCommented:
The return value of ShellExecute() is totally useless bacause instance handles are only valid in the same address space.  Ergo, first option.
0
 
nietodCommented:
Right, I understand that.  That is why I thought it was necessary to find the EXE with FindExecurable() and then run it with CreateProcess(), so you can get a process handle.  

My question is:  "is the handle returned by ShellExecuteEx() really a process handle, or is it an instance handle?"  Since ShellExecute() returns an instance handle, then I would be surprised if ShellExecuteEx() returned a process handle instead.  
0
 
alexoCommented:
Process handle.
0
 
ZeinerRJAuthor Commented:
I thank everyone for their comments.  I should have mentioned that I was given a copy of MSVC 1.5 and am trying to learn some C++ on my own until I can take a class.  (D'Ohh!!!)

However, all the comments are interesting, and will certainly be of use.

Thanks again, and if anyone has any new ideas, let me know.

Bob Z.
0
 
alexoCommented:
Bob, next time please give us the full information so we can supply *correct* solutions.
My comments regarding ShellExecute() and ShellExecuteEx() are only valid for Win32.  Since MSVC 1.x generates Win16 code, you can only file them for future reference...
0
 
ZeinerRJAuthor Commented:
Sorry Alexo, when I posted, I was concentrating on the problem so much that I failed to give proper background info.  However, all I'm doing with 1.5 is trying to give myself a leg up  for when I'll get to take a class in a month or so.  At that time, I'll be using VC 5, or 6, so all these comments are indeed filed for future use.  You have not wasted your time!

Thanks again.
Bob Z.
0
 
nietodCommented:
Is this class in programing standard C++ or in windows?  A standard C++ (introductory) class will not cover anything like this.  It won't teach anything specific to windows or any other operating system.
0
 
alexoCommented:
Todd is right.  Better get familiar with virtual methods, multiple inheritance, operator overloading and other mumbo jumbo...
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.