On Sat, 28 Jul 2007, Robert May wrote:
> Here's what happens - the call to system, or using backticks, makes a
> request to the OS to find the program associated with *.html files,
> launch it (if it isn't already running) and ask it to open the html
> file.
>
> As part of the process of finding out if there is already a running
> program of the right type the OS may attempt (depending on the program
> and it's associated registry values) to use a technique called DDE -
> if it does try this mechanism, the in broadcasts a WM_DDE_INITIATE
> message to every top-level window in the system, and waits for each
> one to reply.  In this case we have a top-level window ($main), and so
> the system sends this message to our top level window, but because we
> are not in a message loop we never respond, and the system has to wait
> for a timeout (typically about 30 seconds).
>
> The code in perl behind the system call  *should* be handling
> WM_DDE_INITIATE messages, but is not (at least not in the version of
> perl you are running)
>
> There are 2 ways that I can see to resolve this for now.
> (1) As I already suggested do 'undef $main' before making the shell
> call - this destroys our window so we no longer have a top level
> window.
> (2) Use ShellExecute, which spins its own internal message loop until
> the DDE initialisation is complete.  Something like this:
>  $main->ShellExecute("", "temp.html", "", "", SW_SHOW);

On 28/07/07, Jan Dubois <[EMAIL PROTECTED]> wrote:
> This does not sound plausible to me:  system("start foo.html") will
> end up calling CreateProcess() on command.com/cmd.exe because start
> is an intrinsic shell command and will not be found on the PATH.

On Win98 it's not a shell buit-in, it's a command called start.exe.
I'm not sure this affects things though.

> CreateProcess() will return and not wait for command.com/cmd.exe to
> initialize.  Upon return win32_spawnvp() will call win32_msgwait(),
> which should continue to pump the message loop until the external
> process ends.

That's what's supposed to happen, but in AS build 819 on win98 (that's
all I have access to this weekend), I have to change the flags to
MsgWaitForMultipleObjects from QS_ALLEVENTS to
QS_ALLEVENTS|QS_SENDMESSAGE to get it to pump the sent WM_DDE_INITIATE
message.

Further to this, in bleed and AS build 820 we changed the flags to
MsgWaitForMultipleObjects from QS_ALLEVENTS to
QS_POSTMESSAGE|QS_TIMER.  This won't have improved things.

Here's what I think happens:

(1) the 'system' call results in a new process being started (either
start.exe or cmd.exe depending on OS).  The new process is not
initialised by the time CreateProcess returns.

(2) When CreateProcess returns win32_spawnvp calls into win32_msgwait
to wait for the external command to finish.

(3) the external command (whether start.exe or cmd.exe's builtin)
passes what it has been asked to start - in this case something.html -
to ShellExeculte() which in turn looks up the class key for .html in
the registry.  There it finds a ddeexec key, and so starts a DDE
conversation.  The first part of the DDE conversation is to broadcast
a WM_DDE_INITIATE message to all top-level windows (As far as I can
tell this is done with something like
SendMessageTimeout(HWND_BROADCAST, ..... ))

(4) If our process has a top level window, then that top level window
is sent a WM_DDE_INITIATE message by the new external process, but
win32_msgwait() is not pumping sent messages, and so our process does
not respond, and there is a delay while the external process times out
waiting for us.

The worst thing about this is that if we are in a long-running
"system" call, and have a top-level window, then we will cause delays
to *any* other DDE communications.  Try running this:

#!perl -w
use strict;
use warnings;
use Win32::GUI();

my $mw = Win32::GUI::Window->new;

system "notepad.exe";

And while notepad is still open, double-click an html file on your
desktop - you'll get a 30 second delay before your browser shows the
page.

> But even if it didn't, the "start" command is just a commandline
> interface to the ShellExecuteEx() function called from cmd.exe,
> so it wouldn't be any different from your solution (2) above.

It is different.  ShellExecute spins a message-loop in the thread from
which it is called.  In the case of using the start command the
ShellExecuteEx() is called in the context on the newly created
process, and spins a message loop in the newly started thread.  In my
example the call to ShellExecute() is in the perl process, and so
spins it's message loop within the perl main thread, which is where we
need a message loop to pump the received  WM_DDE_INITIATE message.

I'm at a bit of a disadvantage not having a Win2K machine to hand to
check this thoroughly (I'll try to do that on Monday or Tuesday).
I'm not sure that I entirely understand the implication of adding
QS_SENDMESSAGE to win32_msgwait.  I think it only affects
cross-process and cross-thread sent messages (as all intra-process
sent messages get dispatched directly to the windproc for the window).

Regards,
Rob.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
Perl-Win32-GUI-Users mailing list
Perl-Win32-GUI-Users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/perl-win32-gui-users
http://perl-win32-gui.sourceforge.net/

Reply via email to