Post by José SilvaJoseph is only concerned in convincing me that this is not a good solution,
not in getting an answer for a simple question.
Yes. Because it is not a "simple" question. It is a question that does not have a valid
answer, and by asking it, you are requiring that impossible situations shall exist.
Post by José SilvaMeanwhile I think I encountered the answer, that stays here for some others
Use CreateProcess() instead of ShellExecute().
CreateProcess() always returns hProcess. Then, simply call
WaitForSingleObject(hProcess, INFINITE) - a function created by microsoft
specially for me that have this strange idea of waiting for applications to
close.
Note that CreateProcess can only execute .exe files; if you give it a .doc file, a .txt
file, a URL, etc., then it cannot cause the correct program to execute.
Furthermore, it still doesn't work right. For example, if you CreateProcess on
WinWord.exe, WinWord will discover that there is already another WinWord running, will use
DDE or automation to inform the already-running application to open up the document, and
then the process you just launched will kill itself. So you will get a notification that
the process terminated, but in fact the *document* you are editing *has not even been seen
by the user yet*. See what I mean about not being a "simple" answer. You are making
naive assumptions that simply do not hold up in real life, and expecting that somehow the
world is going to come into correspondence with your naive assumptions, which it will not
do.
So your solution cannot work. You are deluding yourself. Of course, I knew this solution
would not work, which is why I didn't propose it. How is it you think that ShellExecuteEx
knows to return NULL for the handle of the process, as described in the documentation?
Simple: the process exits before going into its message pump. It knows this because it is
also doing a WaitForInputIdle; if the created process enters input-idle mode, then it has
come up for the first time, and the hProcess is set to indicate the process handle
returned by CreateProcess. If the process terminates without achieving the input-idle
state, ShellExecuteEx sets the hProcess to NULL, because it knows the responsibility has
been handed off to an existing process whose handle it cannot find out.
But since you obviously need proof that you are wrong, I suggest you try the following
code. I used this as a simple little program called runword.
First, I ran Microsoft Word and created a little file called test.docx in that directory.
Then I exited Word.
Next I created a command shell, changed to the Debug directory for the project, and typed
runword
This launched Word with a blank document. I typed something into the document. Then I
launched another command shell, command shell 2, and typed
runword test.docx
The results are shown below.
You are wrong, and I am right, and the proof is easily demonstrated by looking at the
resulting output! The difference is that I already knew what was going to happen, and you
remain clueless and apparently wish to stay that way. Your code will not work, as this
example demonstrates beyond any shadow of a doubt. CreateProcess will not solve your
problem, because it is based on an erroneous assumption that I already knew would be
erroneous, and therefore I would not have wasted your time proposing a solution that
cannot possibly work. You apparently, having discovered a tiny piece of the solution and
not having understood either the implications of the solution you propose, have gone off
blindly thinking you have a solution. You don't.
=============================================================
int _tmain(int argc, _TCHAR* argv[])
{
STARTUPINFO startup = {sizeof(STARTUPINFO) } ;
PROCESS_INFORMATION pi;
TCHAR cmd[1024];
_tcscpy_s(cmd, _countof(cmd), _T("\"c:\\Program Files\\Microsoft
Office\\Office12\\winword.exe\""));
if(argc > 1)
{
_tcscat_s(cmd, _countof(cmd) - _tcslen(cmd), _T(" "));
_tcscat_s(cmd, _countof(cmd) - _tcslen(cmd), argv[1]);
}
BOOL result = CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startup,
&pi);
if(result)
{ /* started */
_tprintf(_T("%08u started \"%s\"\n"), GetCurrentProcessId(), cmd);
::WaitForSingleObject(pi.hProcess, INFINITE);
_tprintf(_T("%08u program exited\n"), GetCurrentProcessId());
::CloseHandle(pi.hProcess);
::CloseHandle(pi.hThread);
} /* started */
else
{ /* failed */
DWORD err = ::GetLastError();
_tprintf(_T("%08u failed to start \"%s\"\n"), GetCurrentProcessId(), cmd);
} /* failed */
return 0;
}
===========================================================
Command shell 1:
Microsoft Windows [Version 6.0.6001]
Copyright (c) 2006 Microsoft Corporation. All rights reserved.
C:\Users\flounder.KIRTLAND2>cd c:\tests\runword\debug
c:\tests\runword\debug>runword
00003544 started ""c:\Program Files\Microsoft Office\Office12\winword.exe""
===========================================================
Type something into the empty document
===========================================================
Command shell 2:
Copyright (c) 2006 Microsoft Corporation. All rights reserved.
C:\Users\flounder.KIRTLAND2>cd c:\tests\runword\debug
c:\tests\runword\debug>dir
Volume in drive C is Vista32
Volume Serial Number is 4025-0AC8
Directory of c:\tests\runword\debug
04/29/2009 02:19 PM <DIR> .
04/29/2009 02:19 PM <DIR> ..
04/29/2009 02:12 PM 40,960 runword.exe
04/29/2009 02:12 PM 326,836 runword.ilk
04/29/2009 02:12 PM 1,289,216 runword.pdb
04/29/2009 02:15 PM 11,123 test.docx
4 File(s) 1,668,135 bytes
2 Dir(s) 78,498,566,144 bytes free
c:\tests\runword\debug>runword test.docx
00007216 started ""c:\Program Files\Microsoft Office\Office12\winword.exe" test.docx"
00007216 program exited
c:\tests\runword\debug>
=====================================================
Note that although the process exited, test.docx IS STILL OPEN. In fact, I can now edit
it, make changes in it, and save it. So what you would write back upon process completion
is meaningless, because I have not had a chance to actually do any editing.
=====================================================
Close test.docx:
Nothing happens in command shell 1. The process is still running, so the WFSO is still
blocked.
====================================================
Close the document into which you had typed something. Note that this is the last
document that was open.
In command shell 1 you see:
00003544 program exited
c:\tests\runword\debug>
====================================================
Q.E.D.
joe
Post by José SilvaThanks for all.
Post by Joseph M. NewcomerSee below...
Post by José SilvaYou are sure, finished is not equivalent to process terminated, but "process
terminated" means document is saved. With that I mean when user closes all
instances of WinWord, I am sure that the file is already saved with all
modifications.
****
Note that I would never close Word, and it is therefore meaningless to wait for it to
close. It could be months. Seriously.
****
Post by José SilvaSo, if I launch an application that do not return hProcess, I need to do
1) Verify what executable or dll was launched (use FindExecutable()).
****
The problem is that you don't know if you find the executable if it is the
executable that
is working with your data. I could have nine other instances of some
program running. You
have no idea which one is yours. Note that if it was launched, you would get a non-NULL
hProcess, which still doesn't help you much. If it was already launched, you only know
that everyhing is saved if the process terminates; you have no idea if the process will
*ever* terminate.
****
Post by José Silva2) ??? (what I really need) Know the process id of the previously launched
application.
3) Wait for that application to close.
****
How many months do you expect to wait? Will you have a timeout after a year?
Note that if the user is shutting down, your program may be terminated before the program
whose termination you are waiting for.
The basic idea is flawed. You are making assumptions which cannot be valid; the *only*
thing you might have some confidence in is the fact that, in the unlikely event the
program closes, the processing of the document is complete. You cannot predicate the
success of your program in the trust that this will happen.
****
Post by José SilvaThe remainding considerations about how user uses Word, Powerpoint,... are
not important because my application is really blocked and if user wants to
continue he have to close the application (this behaviour would be described
in manuals, dialog boxes alerting of that, etc...). Soon users would
understand that for some applications they should really close them for
continuing using my application. In fact WinWord is like a modal dialog box,
that should be closed to continue using application.
****
It is a poor design. You would force me to exit Word just to satisfy your bad design?
That is unacceptable, and you will find serious resistance to the idea
once you deploy. My
successful use of Word should not be predicated on satisfying the bad
design of some other
program. Note also that blocking the main GUI thread of your app while waiting for some
other app to finish is beyond poor design, and is more to be pitied than
sanctioned. XP or
Vista will determine your program is non-responsive and ask the user if
your app should be
killed.
Your design is deeply flawed. You need to rethink what you are doing. It simply doesn't
make sense.
****
Post by José SilvaI am sure there is a solution for someone that is trying to use Document
Editor (for instance WinWord) as it was a modal dialog box (I open it, and
wait user to close it), and that is what I am asking for.
****
I don't even understand this sentence. WHo has a modal dialog box? How is it that I can
see it? I think you are trying to build a design that actively works against how both
WIndows and users work. As such, the design is doomed. Better to figure that out now,
before you waste time building something that cannot work and will merely create ill will
with the end users.
joe
*****
Post by José SilvaThanks.
Post by Joseph M. Newcomer"Viewer" implies "read-only". "Editor" has a different meaning.
You could watch for the local file to change, and based on that change,
could write them
back. But it is clear from the specification of ShellExecuteEx that you can never
reliably tell when the editor has "finished" with them. The notion that
"finished" is
equivalent to "process terminated" is where you are making your design
error. As is made
clear from the description of the hProcess member, there is NO
guaranteed
correlation
between the concept of process and the concept of viewing (or editing).
======================
You download a .doc file.
You launch and get a handle to the Word process.
You wait for the Word process to terminate.
In order to edit the document, I have to open three other Word files. I do so.
I save the updated document and close it.
I have three other Word files open. Word does not exit. Word may not exit, ever.
======================
The notion that people actually "exit" programs is an error, anyway! I
might close the
file but not exit Word. In fact, I right now have three open PowerPoint
presentations,
five open Word files and two open Excel spreadsheets. The versions of
PowerPoint, Word,
and Excel have been, literally, running for MONTHS. Perhaps when I
download the next set
of Windows updates, these programs will close as part of the reboot cycle.
But the bottom
line is that you are basing your decision on a non-credible premise,
that
(a) the viewer
is not already open and (b) having opened it to process a document, the
user will actually
*exit* the viewer upon completion of editing the document. Both of
these
are not
practical in the Real World. Your expectations are not reasonable, so implementing
something that can be satisified by a user meeting these unrealistic expectations is
unlikely to be successful. You have to think of a different approach.
For example, using
ReadDirectoryChangesW looking for the FILE_ACTION_MODIFIED event might
be
one approach,
although not the only one possible. Furthermore, it wouldn't make sense
to block your
program while waiting; all you really want is an asynchronous
notification
that the file
can be written back. This leads to the question of what happens if the
user simply does a
"Save" of some intermediate state while editing?
Note that you should not use the word "viewer" to describe something
that
can change the
contents of a file. There would be no need to write back a file that
was
merely being
examined.
joe
Post by José SilvaI get documents from a remote database, I copy them to the local machine,
then I open them with the associated viewer. When the viewer closes, I write
the file back to the database.
Do you think its a bad idea using the ShellExecute and waiting process to
close?? What other ideas you have to achieve this goal???
It is known that ShellExecute not always returns hProcess filled. This is
not a bug. This happens when ShellExecute does not launch a process. For
instance if you launch an html file and IE is already open, it creates a new
tab under IE and ShellExecute does not return hProcess.
As you suggest I had a bad idea if you have better ideas they are wellcome.
Best regards,
José Silva
Post by Joseph M. NewcomerSee below...
Post by José SilvaI am writing an application that launches the viewer for the file to be
opened and then waits this application to close.
****
That is almost certainly a Bad Idea. Why do you want to do this? It wil
hang the process
that launched it, making it exhibit seriously bad behavior as far as
the
user is
concerned. Don't do it this way.
****
Post by José SilvaI am launching application using ShellExecuteEx() then I use hProcess
returned in ShellExecute to wait for the application. It happens that some
applications does not return hProcess filled. However I want to wait for
that application to close.
*****
This does seem odd. If ShellExecuteEx returns, the handle should be
correct. This sounds
like a ShellExecute bug. Can you get a simple case that demonstrates it?
It should be
reported via the Connect website.
****
Post by José SilvaThe question is, how can I determine if application as closed for the
situations where ShellExecuteEx returns NULL on hProcess?
****
You can't. But I seriously suggest rethinking the approach. Blocking a
process for an
unbounded time is usually a Really Bad Idea under nearly all conditions.
joe
*****
Joseph M. Newcomer [MVP]
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Joseph M. Newcomer [MVP]
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Joseph M. Newcomer [MVP]
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Joseph M. Newcomer [MVP]
email: ***@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm