Using ShellExecute or CreateProcess caller lose its focus
-
I want to call an external application (created by me) using ShellExecute or CreateProcess. It is just an update application for the main app. The problem is, what ever I tried I failed to get window focus back to my main app when the process (update app) is terminated. I created a simple MFC/SDI app that calls window's notepad under "C:\windows\notepad.exe" which suffers from the same problem, just to show you what I mean. I need the parent window -which is the main app- to be disabled (like a modal dialog box behaviour) until the new app -update application- will finish its job. PS:If I do not disable the main window with EnableWindow(FALSE) I have paint corruption with windows XP and back when I move the update application. Here an example: http://www.filedropper.com/shellexecutecreateprocesstestapp[^]
sdancer75
> I need the parent window -which is the main app- to be disabled (like a modal dialog box behaviour) until the new app -update application- will finish its job. Did you try to hide or minimize the "parent window" instead?
-
> I need the parent window -which is the main app- to be disabled (like a modal dialog box behaviour) until the new app -update application- will finish its job. Did you try to hide or minimize the "parent window" instead?
-
When the external update process should also update the executable of your main application, that must be terminated before the new exe file can be copyied. So there is no need to get the focus back. A typical sequence for such a process:
- Ask the user if the update should be installed
- Perform closing tasks that are time consuming or require user interaction like closing open documents
- Start the update process
- Terminate your application
- The update process should check if there is a running instance of your application (after a short wait time) and terminate with an error if so
- The update process might restart your application
In another post you mentioned that you are using
WaitForSingleObject
to wait for the update process to be terminated. If you call that from within your main thread, your application's message loop is blocked so that paint events are not processed. If you don't want to update the executable itself and must wait for the external process to be finished start the process from within a worker thread where you can callWaitForSingleObject
without blocking the message loop. Use a global state variable indicating that the update is executing to disallow specific tasks of your application or just show a modal dialog that is closed automatically when the update has finished.Quote:
When the external update process should also update the executable of your main application, that must be terminated before the new exe file can be copyied. So there is no need to get the focus back.
I have managed this kind of problems with success so, dont bother with that.
Quote:
In another post you mentioned that you are using WaitForSingleObject to wait for the update process to be terminated. If you call that from within your main thread, your application's message loop is blocked so that paint events are not processed.
Thats correct. Windows Vista/Win7/Win8 does not have problems with paint events but XP they have. For that reason I want to disable the parent to avoid such kind of problems.
Quote:
If you don't want to update the executable itself and must wait for the external process to be finished start the process from within a worker thread where you can call WaitForSingleObject without blocking the message loop. Use a global state variable indicating that the update is executing to disallow specific tasks of your application or just show a modal dialog that is closed automatically when the update has finished.
I update the executables too, but I dont have problems with that. If you download the sample code, you will understand the focus problem i currently have.
sdancer75
-
sdancer75 wrote:
As you can see ... What ever I tried I had no success.
We cannot see anything, you need to show your code and explain where it goes wrong.
-
I posted a link in my 1st post with a sample MFC/SDI application that have all the code you need. http://www.filedropper.com/shellexecutecreateprocesstestapp[^]
sdancer75
But what is a problem for you to attach a piece of code to your post?
-
But what is a problem for you to attach a piece of code to your post?
Hi, No problem at all, I just gave all the code in the link. Anyway, I attach you the most important code from the sample app.
void CMainFrame::OnRunExternalApp() {
SHELLEXECUTEINFO lpExecInfo; PROCESS\_INFORMATION processInfo; DWORD dwExitCode; HANDLE hProcess = 0; BOOL bResult; LPTSTR strCmd; strCmd = \_T(""); //bResult = StartupApplicationWithShell (\_T("LiveUpdate.exe"), (LPTSTR)strCmd, GetSafeHwnd(), &hProcess); bResult = StartupApplicationWithProcess (\_T("C:\\\\Windows\\\\notepad.exe"), (LPTSTR)strCmd, &processInfo); EnableWindow(FALSE); if(bResult) { //(UINT)result > HINSTANCE\_ERROR) //ShowWindow( SW\_HIDE ); //ShowWindow( SW\_SHOWNOACTIVATE ); //WaitForSingleObject( hProcess, INFINITE ); WaitForSingleObject(processInfo.hProcess, INFINITE); //WaitForMultipleObjects(1, &processInfo.hThread, TRUE, INFINITE ); //if (!GetExitCodeProcess(hProcess, &dwExitCode)) { // AMLOGINFO(\_T("LiveUpdate is not terminated normally.")); //} if (!GetExitCodeProcess(processInfo.hProcess, &dwExitCode)) { //failed } CloseHandle( processInfo.hProcess ); CloseHandle( processInfo.hThread ); //CloseHandle(hProcess); } else { // failed } BringWindowToTop(); EnableWindow(TRUE); //UpdateWindow(); //::SetWindowPos( GetSafeHwnd(), HWND\_TOP, 0, 0, 0, 0, SWP\_NOMOVE | SWP\_NOSIZE | SWP\_SHOWWINDOW );
}
sdancer75
-
Hi, No problem at all, I just gave all the code in the link. Anyway, I attach you the most important code from the sample app.
void CMainFrame::OnRunExternalApp() {
SHELLEXECUTEINFO lpExecInfo; PROCESS\_INFORMATION processInfo; DWORD dwExitCode; HANDLE hProcess = 0; BOOL bResult; LPTSTR strCmd; strCmd = \_T(""); //bResult = StartupApplicationWithShell (\_T("LiveUpdate.exe"), (LPTSTR)strCmd, GetSafeHwnd(), &hProcess); bResult = StartupApplicationWithProcess (\_T("C:\\\\Windows\\\\notepad.exe"), (LPTSTR)strCmd, &processInfo); EnableWindow(FALSE); if(bResult) { //(UINT)result > HINSTANCE\_ERROR) //ShowWindow( SW\_HIDE ); //ShowWindow( SW\_SHOWNOACTIVATE ); //WaitForSingleObject( hProcess, INFINITE ); WaitForSingleObject(processInfo.hProcess, INFINITE); //WaitForMultipleObjects(1, &processInfo.hThread, TRUE, INFINITE ); //if (!GetExitCodeProcess(hProcess, &dwExitCode)) { // AMLOGINFO(\_T("LiveUpdate is not terminated normally.")); //} if (!GetExitCodeProcess(processInfo.hProcess, &dwExitCode)) { //failed } CloseHandle( processInfo.hProcess ); CloseHandle( processInfo.hThread ); //CloseHandle(hProcess); } else { // failed } BringWindowToTop(); EnableWindow(TRUE); //UpdateWindow(); //::SetWindowPos( GetSafeHwnd(), HWND\_TOP, 0, 0, 0, 0, SWP\_NOMOVE | SWP\_NOSIZE | SWP\_SHOWWINDOW );
}
sdancer75
-
-
Quote:
When the external update process should also update the executable of your main application, that must be terminated before the new exe file can be copyied. So there is no need to get the focus back.
I have managed this kind of problems with success so, dont bother with that.
Quote:
In another post you mentioned that you are using WaitForSingleObject to wait for the update process to be terminated. If you call that from within your main thread, your application's message loop is blocked so that paint events are not processed.
Thats correct. Windows Vista/Win7/Win8 does not have problems with paint events but XP they have. For that reason I want to disable the parent to avoid such kind of problems.
Quote:
If you don't want to update the executable itself and must wait for the external process to be finished start the process from within a worker thread where you can call WaitForSingleObject without blocking the message loop. Use a global state variable indicating that the update is executing to disallow specific tasks of your application or just show a modal dialog that is closed automatically when the update has finished.
I update the executables too, but I dont have problems with that. If you download the sample code, you will understand the focus problem i currently have.
sdancer75
My intention was to show you a solution that differs from your current implementation and pointing to the fact that you block the message loop. You must not call
WaitForSingleObject
from within your main thread to ensure that the window is repainted (e.g. when moving another window over the application window). That will solve the problem of paint corruption and might also solve your other problems. Overall I think I must shout: Don't use WaitForSingleObject from within your main GUI thread; especially with long wait times! I (like most others here) will not download a complete project and build it. Especially in this case where it must be tested with XP too. -
I will give it a try but as you may already see, I am using the bringWindowToTop without success. Thanx
sdancer75
Yes, I see. But try it in the following order: EnableWindow SetForegroundWindow SetActiveWindow BringWindowToTop
-
My intention was to show you a solution that differs from your current implementation and pointing to the fact that you block the message loop. You must not call
WaitForSingleObject
from within your main thread to ensure that the window is repainted (e.g. when moving another window over the application window). That will solve the problem of paint corruption and might also solve your other problems. Overall I think I must shout: Don't use WaitForSingleObject from within your main GUI thread; especially with long wait times! I (like most others here) will not download a complete project and build it. Especially in this case where it must be tested with XP too. -
No. That is similar (it can just wait for more events). Don't use any blocking wait (or more general: any function that may block for long intervals) from within the main GUI thread. As already suggested you might use a worker thread.
-
Yes, I see. But try it in the following order: EnableWindow SetForegroundWindow SetActiveWindow BringWindowToTop
-
No. That is similar (it can just wait for more events). Don't use any blocking wait (or more general: any function that may block for long intervals) from within the main GUI thread. As already suggested you might use a worker thread.
-
Yes, I see. But try it in the following order: EnableWindow SetForegroundWindow SetActiveWindow BringWindowToTop
One last thing. The EnableWindow(xxxx) do the mess in my situation. If I dont use this function I have to process the paint messages from the child window. In this case I think that
WaitForMultipleObjects
will do the job in the XP case. Do you agree with this guess ? .... or better i will give it a try right now.
sdancer75
-
The worker thread does not lock the main app as long as its active. I dont want this. I just want a modal like behaviour and not floating windows all around the desktop.
sdancer75
You can disable your app window and/or show a modal dialog while the worker thread is active and re-enable when it finishes. So the message loop is not blocked and repainting is ensured while the app itself is blocked. What do you mean by floating windows? There is no additional window.
-
You can disable your app window and/or show a modal dialog while the worker thread is active and re-enable when it finishes. So the message loop is not blocked and repainting is ensured while the app itself is blocked. What do you mean by floating windows? There is no additional window.
Quote:
You can disable your app window and/or show a modal dialog while the worker thread is active and re-enable when it finishes.
You mean a dummy dialog just to block to main app ?
Quote:
What do you mean by floating windows? There is no additional window.
I mean the two windows that will be active at the same time (main and child) and user will have the ability to work with the both of them.
sdancer75
-
Quote:
You can disable your app window and/or show a modal dialog while the worker thread is active and re-enable when it finishes.
You mean a dummy dialog just to block to main app ?
Quote:
What do you mean by floating windows? There is no additional window.
I mean the two windows that will be active at the same time (main and child) and user will have the ability to work with the both of them.
sdancer75
sdancer75 wrote:
You mean a dummy dialog just to block to main app ?
Yes. Or just disable the main window. The dialog can show something like "Please wait until the update is installed".
sdancer75 wrote:
I mean the two windows that will be active at the same time (main and child) and user will have the ability to work with the both of them.
When the app is blocked by disabling or a dialog it can't be moved by the user (the dialog may be moved). So when not using a dialog it is the same behaviour as with your current solution.
-
One last thing. The EnableWindow(xxxx) do the mess in my situation. If I dont use this function I have to process the paint messages from the child window. In this case I think that
WaitForMultipleObjects
will do the job in the XP case. Do you agree with this guess ? .... or better i will give it a try right now.
sdancer75
No, WFMO is the same as WFSO (just waiting for more than one object; however I don't see any additional one in your problem description). The usual way is move waiting in a worker thread to not block the main UI thread.
-
sdancer75 wrote:
You mean a dummy dialog just to block to main app ?
Yes. Or just disable the main window. The dialog can show something like "Please wait until the update is installed".
sdancer75 wrote:
I mean the two windows that will be active at the same time (main and child) and user will have the ability to work with the both of them.
When the app is blocked by disabling or a dialog it can't be moved by the user (the dialog may be moved). So when not using a dialog it is the same behaviour as with your current solution.