I have a very frustrating bug in an application I am working on. The routine is supposed to do something in one window, and then return focus to the other at the end of the method, but when I started to use a large data set the other day, the focus stopped returning at the end. I stepped through the code one line at a time, and the errors stopped. so, i figure its a timing issue of some kind. I trace through until i find what i suspect is the culprit. A call to ShellExecute(...), that terminates an image editor i use. (http://msdn.microsoft.com/en-us/library/bb762153(VS.85).aspx)
Now, if I step past this call, and then continue to run the program, everything works fine, but if I just run past this line, the error occurs. how can this be? I have a call to SetFocus() at the very end of this method. should开发者_如何学Pythonnt the program hit this no matter what?
This is all so very frustrating...
First thing that should be clear is that Win32 API calls that are related to windows/messages/focus and etc. do not depend on timing. Every thread has its own window/messaging subsystem, there's no race conditions here.
What you describe is something else. You actually launch another process (application), which runs concurrently with yours.
Note that ShellExecute
is an asynchronous function. It returns immediately after creating the process, and from now on your application and the process you've created run concurrently.
Now, since only one window in the system may have a focus at a time - it's very likely that the process you've created just steals the focus from you. In order to avoid this - you should first wait for that process to finish working, and only then restore the focus to your window and continue working.
For this you have to obtain the handle of the created process, and call a Win32 waiting function on it. ShellExecute
doesn't return you the handle of the created process. However ShellExecuteEx
- does.
BTW it also allows you to launch a process with instruction for it not to show the UI, if this is what you want.
You should write it like this:
SHELLEXECUTEINFO sei;
memset(&sei, 0, sizeof(sei));
sei.cbSize = sizeof(sei);
sei.fMask = SEE_MASK_NOCLOSEPROCESS;
sei.lpFile = L"notepad.exe";
sei.nShow = SW_SHOWNORMAL; // or SW_HIDE if you don't want to show it
if (ShellExecuteEx(&sei))
{
// wait for completion
WaitForSingleObject(sei.hProcess, INFINITE);
CloseHandle(sei.hProcess);
}
This should be helpful
P.S. Of course you should close the handle of the created process. That is, CloseHandle
must be called after WaitForSingleObject
.
As you say, the problem sounds like one of timing.
I'm not familiar with the ShellExecute function, but from the page you linked:
"Because ShellExecute can delegate execution to Shell extensions (data sources, context menu handlers, verb implementations) that are activated using Component Object Model (COM), COM should be initialized before ShellExecute is called. Some Shell extensions require the COM single-threaded apartment (STA) type."
Maybe that's related?
精彩评论