From: <mar...@ar...> - 2007-07-26 11:21:32
|
Hi everyone, I tried to create a little GUI for a program which I wrote a while ago. It's only a little link filter. I have to give him an URL, he parses the website for given regular expressions and gives back a HTML file with all the links in it. Now the problem is that if i enter the URL and click on the Button to proceed, the program hangs for about 30 seconds before it goes on. Everything works fine. Only this "lag" is very disappointing. I can't find my mistake... If I do the same on the console, everything works instantly without hanging. I would be glad if someone could help me out. :) Here's the code: use LWP::UserAgent; use HTTP::Cookies::Mozilla; use Win32::GUI(); # Use of the Firefox Cookie file # For German Systems: Change the Docume~1 to Dokume~1 # I'm working on a better solution for this $kekse = HTTP::Cookies::Mozilla->new( 'file' => glob("C:/Docume~1/$ENV{'USERNAME'}/Anwendungsdaten/Mozilla/Firefox/Profiles/*.default/cookies.txt")); # Creation of the LWP Useragent with the Firefox Cookie file $ua = LWP::UserAgent->new; $ua->agent('Mozilla/5.0'); $ua->cookie_jar($kekse); # Creation of the GUI $main = Win32::GUI::Window->new( -name => 'Main', -width => $width = 295, -height => $height = 161, -maximizebox => 0, -resizable => 0, -text => 'Link Filter', ); $lblURL = $main->AddLabel( -name => 'lblURL', -width => 100, -height => 17, -align => 'left', -left => 4, -top => 4, -text => 'Bitte URL eingeben:', ); $tfURL = $main->AddTextfield( -name => 'tfURL', -width => 281, -height => 77, -align => 'left', -left => 4, -top => 20, -multiline => 1, ); $btGet = $main->AddButton( -name => 'btGet', -width => 279, -height => 33, -left => 5, -top => 100, -text => 'Get Them!', ); $desk = Win32::GUI::GetDesktopWindow(); $deskwidth = Win32::GUI::Width($desk); $deskheight = Win32::GUI::Height($desk); $deskx = ($deskwidth - $width) / 2; $desky = ($deskheight - $height) / 2; $main->Move($deskx, $desky); $main->Show(); Win32::GUI::Dialog(); sub Main_Terminate { return -1; } sub btGet_Click { # Copy the entered URL into a usable variable $url = $tfURL->Text; return -1; } # Get the content of the Website and save it into a temporary HTML file $ua->get($url, ':content_file' => 'temp.html'); open(EINGABE, "temp.html") || die("Fehler: Datei temp.html konnte nicht gefunden werden."); open(AUSGABE, ">links.html") || die("Fehler: konnte Datei rs.html nicht erstellen."); # Filter the links from the temporary file and write them into a new HTML file while($zeile = <EINGABE>) { if ($zeile =~ m/ENTER YOUR REGEXP HERE/) { $zeile =~ s/ENTER YOUR REGEXP HERE/AND HERE/; print AUSGABE "<a href=\"" . $zeile . "\">" . $zeile . "</a>" . "<br>"; } } close(EINGABE); close(AUSGABE); # Delete temporary file unlink "temp.html"; # Open the file which holds the filtered links `links.html`; |
From: Jason P. <jp...@un...> - 2007-07-26 13:45:05
|
This is not a GUI issue per se, as it is the fact that your routine runs synchronous, in the main thread of the application. To remove this lag = (and the delayed drawing of the window) you will need to do some looking = through the mail archives and find how to write this into a separate thread. -----Original Message----- From: per...@li... [mailto:per...@li...] On Behalf Of Marc N=FCrnberger Sent: Thursday, July 26, 2007 7:21 AM To: per...@li... Subject: [perl-win32-gui-users] Why is my GUI hanging? Hi everyone, I tried to create a little GUI for a program which I wrote a while ago. It's only a little link filter. I have to give him an URL, he parses the website for given regular expressions and gives back a HTML file with all the links in it. Now the problem is that if i enter the URL and click on the Button to proceed, the program hangs for about 30 seconds before it goes on. Everything works fine. Only this "lag" is very disappointing. I can't find my mistake... If I do the same on the console, everything works instantly without = hanging. I would be glad if someone could help me out. :) Here's the code: use LWP::UserAgent; use HTTP::Cookies::Mozilla; use Win32::GUI(); # Use of the Firefox Cookie file # For German Systems: Change the Docume~1 to Dokume~1 # I'm working on a better solution for this $kekse =3D HTTP::Cookies::Mozilla->new( 'file' =3D> glob("C:/Docume~1/$ENV{'USERNAME'}/Anwendungsdaten/Mozilla/Firefox/Profil= es/ *.default/cookies.txt")); # Creation of the LWP Useragent with the Firefox Cookie file $ua =3D LWP::UserAgent->new; $ua->agent('Mozilla/5.0'); $ua->cookie_jar($kekse); # Creation of the GUI $main =3D Win32::GUI::Window->new( -name =3D> 'Main', -width =3D> $width =3D 295, -height =3D> $height =3D 161, -maximizebox =3D> 0, -resizable =3D> 0, -text =3D> 'Link Filter', ); $lblURL =3D $main->AddLabel( -name =3D> 'lblURL', -width =3D> 100, -height =3D> 17, -align =3D> 'left', -left =3D> 4, -top =3D> 4, -text =3D> 'Bitte URL eingeben:', ); $tfURL =3D $main->AddTextfield( -name =3D> 'tfURL', -width =3D> 281, -height =3D> 77, -align =3D> 'left', -left =3D> 4, -top =3D> 20, -multiline =3D> 1, ); $btGet =3D $main->AddButton( -name =3D> 'btGet', -width =3D> 279, -height =3D> 33, -left =3D> 5, -top =3D> 100, -text =3D> 'Get Them!', ); $desk =3D Win32::GUI::GetDesktopWindow(); $deskwidth =3D Win32::GUI::Width($desk); $deskheight =3D Win32::GUI::Height($desk); $deskx =3D ($deskwidth - $width) / 2; $desky =3D ($deskheight - $height) / 2; $main->Move($deskx, $desky); $main->Show(); Win32::GUI::Dialog(); sub Main_Terminate { return -1; } sub btGet_Click { # Copy the entered URL into a usable variable $url =3D $tfURL->Text; return -1; } # Get the content of the Website and save it into a temporary HTML file $ua->get($url, ':content_file' =3D> 'temp.html'); open(EINGABE, "temp.html") || die("Fehler: Datei temp.html konnte nicht gefunden werden."); open(AUSGABE, ">links.html") || die("Fehler: konnte Datei rs.html nicht erstellen."); # Filter the links from the temporary file and write them into a new HTML file while($zeile =3D <EINGABE>) { if ($zeile =3D~ m/ENTER YOUR REGEXP HERE/) { $zeile =3D~ s/ENTER YOUR REGEXP HERE/AND HERE/; print AUSGABE "<a href=3D\"" . $zeile . "\">" . $zeile . "</a>" . "<br>"; } } close(EINGABE); close(AUSGABE); # Delete temporary file unlink "temp.html"; # Open the file which holds the filtered links `links.html`; -------------------------------------------------------------------------= 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 Per...@li... https://lists.sourceforge.net/lists/listinfo/perl-win32-gui-users http://perl-win32-gui.sourceforge.net/ --=20 No virus found in this incoming message. Checked by AVG Free Edition.=20 Version: 7.5.476 / Virus Database: 269.10.20/919 - Release Date: = 7/26/2007 9:56 AM |
From: <mar...@ar...> - 2007-07-26 19:06:27
|
Hi there, first of all thanks for your quick answers. Geoffrey Spear wrote: > I don't have a solution for your freezing problem, but you should be > able to replace "C:/Docume~1/$ENV{'USERNAME'}/Anwendungsdaten" with > "$ENV{'APPDATA'}" and have it work in any locale. I could do that, but because of the used glob() function I can't. Because C:\Documents and Settings\ contains whitespaces which glob() can't handle (as far as I read everywhere). It would end up with C:\Documents all the time. But I need the glob() here to get into the <random_number>.default Firefox profile folder. I did something "easier"... I rebuilt the GUI with another button which opens a file browser. Now I can select the cookie file on my own. ;) Jason Plum wrote: > This is not a GUI issue per se, as it is the fact that your routine > runs > synchronous, in the main thread of the application. To remove this lag > (and > the delayed drawing of the window) you will need to do some looking > through > the mail archives and find how to write this into a separate thread. Hmm... i will try to read me into this Thanks for your help. :) |
From: Robert M. <rob...@cp...> - 2007-07-26 19:55:19
|
On 26/07/07, Marc N=FCrnberger <mar...@ar...> wrote: > Hi there, > > first of all thanks for your quick answers. > > Geoffrey Spear wrote: > > I don't have a solution for your freezing problem, but you should be > > able to replace "C:/Docume~1/$ENV{'USERNAME'}/Anwendungsdaten" with > > "$ENV{'APPDATA'}" and have it work in any locale. > > I could do that, but because of the used glob() function I can't. > Because C:\Documents and Settings\ contains whitespaces which glob() > can't handle (as far as I read everywhere). It would end up with > C:\Documents all the time. > But I need the glob() here to get into the <random_number>.default > Firefox profile folder. > I did something "easier"... I rebuilt the GUI with another button which > opens a file browser. Now I can select the cookie file on my own. ;) #!perl -w use strict; use warnings; use Win32 qw(CSIDL_APPDATA); print Win32::GetShortPathName(Win32::GetFolderPath(CSIDL_APPDATA)), "\n"; __END__ That will get what you need, and work for all versions of Win32 from Win95 through Vista - $ENV{APPDATA} will only work from Win2K(?) onwards. > Jason Plum wrote: > > This is not a GUI issue per se, as it is the fact that your routine > > runs > > synchronous, in the main thread of the application. To remove this lag > > (and > > the delayed drawing of the window) you will need to do some looking > > through > > the mail archives and find how to write this into a separate thread. > > Hmm... i will try to read me into this > Thanks for your help. :) Looking at your original code, I'm not sure what you think the problem is. Presumably the delay is while the file is fetched from the remote site - you leave the GUI up, but it will be non-responsive. If you just want to dismiss the GUI, then add $main->Hide() after your Win32::GUI::Dialog(); line. Regards, Rob. |
From: <mar...@ar...> - 2007-07-26 20:45:10
|
Robert May wrote: > #!perl -w > use strict; > use warnings; > use Win32 qw(CSIDL_APPDATA); > > print Win32::GetShortPathName(Win32::GetFolderPath(CSIDL_APPDATA)), "\n"; > __END__ > > That will get what you need, and work for all versions of Win32 from > Win95 through Vista - $ENV{APPDATA} will only work from Win2K(?) > onwards. Thanks for that one! > Looking at your original code, I'm not sure what you think the problem > is. Presumably the delay is while the file is fetched from the remote > site - you leave the GUI up, but it will be non-responsive. If you > just want to dismiss the GUI, then add > $main->Hide() > after your Win32::GUI::Dialog(); line. > > Regards, > Rob. The problem is, that it would never take about 30 seconds to fetch that file. If I use a console based version of this program, it's finished in about 2-3 seconds. :) Regards, Marc |
From: <mar...@ar...> - 2007-07-26 21:27:11
|
Hmmmm... I found a strange behavior after adding some "debugging" prints. The delay occurs when the last command is executed. That `links.html` one. Everything works fine up to that point. But that's only the case when I use the GUI version. When using the console version that command runs without delay. Does somebody know why that occurs? Regards, Marc |
From: Robert M. <rob...@us...> - 2007-07-26 22:15:09
|
On 26/07/07, Marc N=FCrnberger <mar...@ar...> wrote: > Hmmmm... I found a strange behavior after adding some "debugging" prints. > The delay occurs when the last command is executed. That `links.html` > one. Everything works fine up to that point. But that's only the case > when I use the GUI version. When using the console version that command > runs without delay. Does somebody know why that occurs? I have no idea what might be causing that. I can't immediately see how Win32::GUI could be at fault, but I am never surprised. I , personally, wouldn't use back-ticks to launch my browser with a page. It's the wrong construct (it's designed to capture the stdout of a program into a perl variable), and relies on your windows box having particular registry entries - it certainly doesn't work for em here. I tried using system "start temp.html"; instead, and I see the delay you're taking about. I can get rid of the delay by doing undef $main; before making the system call (my code below). I'm afraid that I don't have time to look into this further right now. (but can you post back with the output of 'perl -v' and which windows OS you're using, and I'll try to look at it another time. As an aside, if you want to extract links from HTML pages, you'd do well to look HTML::LinkExtor, which is a full HTML parser designed to do just this - you'll find that using regexes is not going to give you the results you ant in the long term (for example you code won't work if a link is split across more than one line). The docs for HTML::LinkExtor have a nice example that shows how you can cope with large files without having to use the intermediate temporary file that you are using. Regards, Rob. #!perl -w #use strict; #use warnings; use LWP::UserAgent; use Win32::GUI(); # Creation of the LWP Useragent with the Firefox Cookie file my $ua =3D LWP::UserAgent->new; # Creation of the GUI my $main =3D Win32::GUI::Window->new( -title =3D> 'Link Filter', -size =3D> [295, 161], -maximizebox =3D> 0, -resizable =3D> 0, ); $main->AddLabel( -pos =3D> [4,4], -size =3D> [100,17], -text =3D> 'Bitte URL eingeben:', ); $main->AddTextfield( -name =3D> 'tfURL', -pos =3D> [4,20], -size =3D> [281, 77], -multiline =3D> 1, ); $main->AddButton( -name =3D> 'btGet', -pos =3D> [5, 100], -size =3D> [279,33], -text =3D> 'Get Them!', ); $main->Center(); $main->Show(); Win32::GUI::Dialog(); $main->Hide(); sub btGet_Click { return -1; } my $url =3D $main->tfURL->Text(); undef $main; # comment out this line to see the delay # Get the content of the Website and save it into a temporary HTML file $ua->get($url, ':content_file' =3D> 'temp.html'); system "start temp.html"; |
From: <mar...@ar...> - 2007-07-26 23:06:37
|
Hehe, thanks for the time you spent to look over things like that. I know that you have better things to do than teaching me how to code in perl. And I think that this mailing list isn't the right place to do so. As you might have guessed I'm not the most experienced programmer on earth. At the beginning I wrote this program for my own needs. To be honest, I wrote it for exactly one specific website. But a few people asked me if they could get a copy when I'm done. That was the reason for me to create a user-friendly GUI. Now it's time for me to read some books I think. ;) Just for the sake of completeness: I'm using Windows XP Professional SP2 with all the latest windows updates. 'perl -v' output: This is perl, v5.8.8 built for MSWin32-x86-multi-thread (with 50 registered patches, see perl -V for more detail) Copyright 1987-2006, Larry Wall Binary build 820 [274739] provided by ActiveState http://www.ActiveState.com Built Jan 23 2007 15:57:46 Robert May wrote: > > I have no idea what might be causing that. I can't immediately see > how Win32::GUI could be at fault, but I am never surprised. > > I , personally, wouldn't use back-ticks to launch my browser with a > page. It's the wrong construct (it's designed to capture the stdout > of a program into a perl variable), and relies on your windows box > having particular registry entries - it certainly doesn't work for em > here. > > I tried using > system "start temp.html"; > instead, and I see the delay you're taking about. I can get rid of > the delay by doing > undef $main; > before making the system call (my code below). I'm afraid that I > don't have time to look into this further right now. (but can you post > back with the output of 'perl -v' and which windows OS you're using, > and I'll try to look at it another time. > > As an aside, if you want to extract links from HTML pages, you'd do > well to look HTML::LinkExtor, which is a full HTML parser designed to > do just this - you'll find that using regexes is not going to give you > the results you ant in the long term (for example you code won't work > if a link is split across more than one line). The docs for > HTML::LinkExtor have a nice example that shows how you can cope with > large files without having to use the intermediate temporary file that > you are using. > > Regards, > Rob. > > #!perl -w > #use strict; > #use warnings; > > use LWP::UserAgent; > use Win32::GUI(); > > # Creation of the LWP Useragent with the Firefox Cookie file > my $ua = LWP::UserAgent->new; > > # Creation of the GUI > my $main = Win32::GUI::Window->new( > -title => 'Link Filter', > -size => [295, 161], > -maximizebox => 0, > -resizable => 0, > ); > > $main->AddLabel( > -pos => [4,4], > -size => [100,17], > -text => 'Bitte URL eingeben:', > ); > > $main->AddTextfield( > -name => 'tfURL', > -pos => [4,20], > -size => [281, 77], > -multiline => 1, > ); > > $main->AddButton( > -name => 'btGet', > -pos => [5, 100], > -size => [279,33], > -text => 'Get Them!', > ); > > $main->Center(); > $main->Show(); > Win32::GUI::Dialog(); > $main->Hide(); > > sub btGet_Click { > return -1; > } > > my $url = $main->tfURL->Text(); > undef $main; # comment out this line to see the delay > > # Get the content of the Website and save it into a temporary HTML file > $ua->get($url, ':content_file' => 'temp.html'); > > system "start temp.html"; |
From: Travis K. <kci...@ya...> - 2007-07-26 23:51:38
|
--- Robert May <rob...@us...> wrote: > I tried using > system "start temp.html"; > instead, and I see the delay you're taking about. I had a similar issue trying to launch a web browser using system "start ..." My workaround was to use a Win32::API call to ShellExecuteA Using your example: #!perl -w #use strict; #use warnings; use LWP::UserAgent; use Win32::GUI(); # Creation of the LWP Useragent # with the Firefox Cookie file my $ua = LWP::UserAgent->new; # Creation of the GUI my $main = Win32::GUI::Window->new( -title => 'Link Filter', -size => [295, 161], -maximizebox => 0, -resizable => 0, ); $main->AddLabel( -pos => [4,4], -size => [100,17], -text => 'Bitte URL eingeben:', ); $main->AddTextfield( -name => 'tfURL', -pos => [4,20], -size => [281, 77], -multiline => 1, ); $main->AddButton( -name => 'btGet', -pos => [5, 100], -size => [279,33], -text => 'Get Them!', ); $main->Center(); $main->Show(); Win32::GUI::Dialog(); $main->Hide(); sub btGet_Click { return -1; } sub open_browser { my $url=shift; use Win32::API; my $shell=Win32::API->new('shell32','ShellExecuteA','NNPNNN','N'); my $return=$shell->Call(0,0,$url,0,0,1); } my $url = $main->tfURL->Text(); $ua->get($url, ':content_file' => 'temp.html'); open_browser('temp.html'); ____________________________________________________________________________________ Get the free Yahoo! toolbar and rest assured with the added security of spyware protection. http://new.toolbar.yahoo.com/toolbar/features/norton/index.php |
From: Robert M. <rob...@us...> - 2007-07-28 14:11:21
|
On 26/07/07, Robert May <rob...@us...> wrote: > On 26/07/07, Marc N=FCrnberger <mar...@ar...> wrote: > > Hmmmm... I found a strange behavior after adding some "debugging" print= s. > > The delay occurs when the last command is executed. That `links.html` > > one. Everything works fine up to that point. But that's only the case > > when I use the GUI version. When using the console version that command > > runs without delay. Does somebody know why that occurs? > > I have no idea what might be causing that. I can't immediately see > how Win32::GUI could be at fault, but I am never surprised. OK, I think I can explain it now - and it looks like a problem with perl, and not Win32::GUI - I'll need do do a little bit more investigation, and if I'm right I'll work on a fix for perl. > I tried using > system "start temp.html"; > instead, and I see the delay you're taking about. I can get rid of > the delay by doing > undef $main; > before making the system call 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); I'll continue my investigation. Regards, Rob. [Jan, I don't know if you read all the messages to this list, but know you are subscribed - I'll follow-up to P5P with a report (and patch?)] |
From: Jan D. <ja...@ac...> - 2007-07-28 20:56:15
|
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); 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. 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. 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. Of course all bets are off if you have a start.exe/start.com on the PATH. > [Jan, I don't know if you read all the messages to this list, but know > you are subscribed - I'll follow-up to P5P with a report (and patch?)] I only browse the subject lines. Please CC me explicitly if you want to make sure I read a particular message. Cheers, -Jan |
From: Robert M. <rob...@us...> - 2007-07-28 23:34:27
|
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 <ja...@ac...> 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. |
From: Jan D. <ja...@ac...> - 2007-07-29 01:05:18
|
On Sat, 28 Jul 2007, Robert May wrote: > On 28/07/07, Jan Dubois <ja...@ac...> wrote: > > 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. Alright, I looked at the code again, and the real problem is: win32_msgwait() doesn't actually dispatch any messages; it only processes (via win32_async_check()) WM_TIMER and WM_USER messages sent to hwnd NULL. The whole reason for *not* running a message pump is to allow an embedding application to use PostThreadMessage() too. If we ran a message pump, we wouldn't know what to do with messages sent to hwnd NULL that we are not expecting. But given the problem you discovered with DDE initiation while waiting for system() to return, I think win32_async_check() needs to run a message pump. Given that the whole PostThreadMessage() mechanism is too brittle for GUI threads anyways (you cannot avoid losing messages), I doubt anyone is using it while also embedding Perl. While looking at this issue I noticed that even though we are using a message-only window on Windows 2000 and later, we are not actually expecting anybody else to dispatch the messages to a wndproc; we always try to snatch them out of the queue via PeekMessage(). So we still inherit the brittleness of the PostThreadMessage() mechanism. I'll see if I can come up with a patch for both issues some time later next week. Cheers, -Jan PS: Please let me know if you happen to know a mechanism to create a message-only window on 98/NT (a window that is not top-level and will not receive broadcast messages). If this were possible, then we could get rid of PostThreadMessage() completely. |
From: Robert M. <rob...@us...> - 2007-07-29 12:19:50
|
On 29/07/07, Jan Dubois <ja...@ac...> wrote: > On Sat, 28 Jul 2007, Robert May wrote: > > On 28/07/07, Jan Dubois <ja...@ac...> wrote: > > > 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. > > Alright, I looked at the code again, and the real problem is: > win32_msgwait() doesn't actually dispatch any messages; it only > processes (via win32_async_check()) WM_TIMER and WM_USER messages sent > to hwnd NULL. PeekMessage() will dispatch sent messages, (apparently) regardless of the filtering applied. Certainly on Win98 all I have to change to fix this particular DDE problem is to add QS_SENDMESSAGE to the MsgWaitForMultipleObjects() to get it to return if there is a sent message in the queue - even if I've called alarm(0); to make w32_hwnd_message not equal to INVALID_HANDLE_VALUE, so that we do the 'thread message only' PeekMessage, the DDE problem is gone. > The whole reason for *not* running a message pump is to allow an > embedding application to use PostThreadMessage() too. If we ran a > message pump, we wouldn't know what to do with messages sent to hwnd > NULL that we are not expecting. Right. But there are good reasons not to run a full message pump. For example, from a Win32::GUI point of view I really don't want win32_async_check to be dispatching keyboard messages for me - first, I may want to be using a message pump with more complexity that simply doing a TranslateMessage/DispatchMessage - I may want to dela with dialog messages (IsDialogMessage()) and accelerators (IsAcceleleratorMessage()). I think it would be very confusing if, for example, sleep() started behaving like this. > But given the problem you discovered with DDE initiation while waiting > for system() to return, I think win32_async_check() needs to run a > message pump. I think it's already doing enough. The DDE problem is that MsgWaitForMultipleObjects isn't returning for the *sent* WM_DDE_INITIATE message. > Given that the whole PostThreadMessage() mechanism is too > brittle for GUI threads anyways (you cannot avoid losing messages), I > doubt anyone is using it while also embedding Perl. I wouldn't bet on it. What we should do is put a call to CallMsgFilter() in any message pump loop we have that might pull thread messages off the queue, to give someone else a chance to see then, if they need to (See http://blogs.msdn.com/oldnewthing/archive/2005/04/28/412574.aspx for more info) > While looking at this issue I noticed that even though we are using a > message-only window on Windows 2000 and later, we are not actually > expecting anybody else to dispatch the messages to a wndproc; we always > try to snatch them out of the queue via PeekMessage(). So we still > inherit the brittleness of the PostThreadMessage() mechanism. This is a problem that I have on my list of things to look at. In particular, even if we're using a message-only window, someone else's message pump (e.g the one run by Win32::MsgBox, may pull our messages from the queue and translate/dispatch them. As we are not handling the messages in the window's wndproc, they never get processed. > I'll see if I can come up with a patch for both issues some time later > next week. Currently I'm leaning towards just adding QS_SENDMESSAGE to the MsgWaitForMultipleObjects() call - we'll need to do this anyway to solve the DDE problem, and I think it's a small enough change to propose for 5.10. I think anything else we do will be a much bigger change, and will probably have to wait for after that. I'll spent some more time thinking about this during the week. Should we move this discussion to P5P? > PS: Please let me know if you happen to know a mechanism to create a > message-only window on 98/NT (a window that is not top-level and > will not receive broadcast messages). If this were possible, then we > could get rid of PostThreadMessage() completely. I'm not aware of a way, but I'll do some research. I'm pretty sure that we don't wan ta real top-level window .... Regards, Rob. |
From: Robert M. <rob...@us...> - 2007-07-30 21:19:05
Attachments:
win32.c.patch
|
Re-post to the win32-gui-users list, without the zip attachment, so that it goes through. Rob. On 30/07/07, Robert May <rob...@us...> wrote: > > On 29/07/07, Jan Dubois <ja...@ac...> wrote: > > > The whole reason for *not* running a message pump is to allow an > > > embedding application to use PostThreadMessage() too. If we ran a > > > message pump, we wouldn't know what to do with messages sent to hwnd > > > NULL that we are not expecting. > > On 29/07/07, Robert May <rob...@us...> wrote: > > Right. But there are good reasons not to run a full message pump. > > For example, from a Win32::GUI point of view I really don't want > > win32_async_check to be dispatching keyboard messages for me - first, > > I may want to be using a message pump with more complexity that simply > > doing a TranslateMessage/DispatchMessage - I may want to dela with > > dialog messages (IsDialogMessage()) and accelerators > > (IsAcceleleratorMessage()). I think it would be very confusing if, > > for example, sleep() started behaving like this. > > Thinking about this further it would be worse than confusing - it > would potentially result in incorrect ordering of messages: > > Imagine I write XS with thin wrappers to GetMessage, TranslateMessage > and DispatchMessage, such that I could write perl code somthing like > this: > > while(my $msg = GetMessage()) { > TranslateMessage($msg); > DispatchMessage($msg); > } > > Now I can end up in win32_async check between any 2 perl calls, and > say I had just pulled a WM_KEYDOWN message. TranslateMessage pushes a > WM_CHAR message onto the top of the queue. If I end up in > win32_async_check between the TranslateMessage and DispatchMessage > calls, and it pumps keyboard messages, then the WM_CHAR will be > delivered before the WM_KEYDOWN. This would at best be confusing, and > more likely break applications. > > I think the approach that win32_async_check takes currently is almost OK. > > Attached is a patch to win32.c (against AS build 819). It implements > most of what I've talked about, plus a few other bits. > > Highlights: > > - QS_SENDMESSAGE added to wim32_msgwait to solve the DDE problem. > > - I've left QS_ALLMESSAGES in win32_msgwait, rather than using the > QS_POSTMESSAGE|QS_TIMER that we did in build 820 and blead, I think > it's better. > > - I've wrapped the PostMessage(.... PM_NOREMOVE) in win32_async check > in a while() loop, to ensure that all messages get marked read - I can > see occasions when there are multiple messages in the queue, and > win32_msgwait/win32_async_check spin a couple of time to mark them all > read, we now only get one loop. I've re-factored the function to move > the PeekMessage loop to the end, so that I don't have to have it and > the signal dispatch code twice. > added another PostMessage loop (this is now very similar to the patch > I proposed to solve the bug that caused use to change the QS_* flags > for build 820/bleed. > > - the message pump part of win32_async_check now re-posts WM_QUIT > messages (needed to play nicely with other message loops) > > - I've moved the message handling from win32_async_check to it's own > function: win32_process_messages(), which can process either thread or > window messages. > > - I've created a windows class for our message window, and made it's > window procedure call win32_process_messages(). win32_async_check() now > does a Translate/Dispatch message if we have a message window. This > means that if we have a message window we won't lose messages from > someone else's message loop. > > - I've added a hook procedure to handle the thread messages, if we > don't have a message window. win32_async_check calls it using > CallMsgFilter if it ever retrieves a thread message. This now means > that we won't lose any thread messages in other modal loops, so long > as those loops do a CallMsgFilter() - All Win32 OS modal loops do > this (including message boxes, menus, window-resizing/moving etc.); > we should encourage all other GUI packages (e.g. Tk, > Win32::GUI) to make this call at appropriate times. > > - The hook procedure passes thread messages that we might be > interested in to win32_process_message, and returns true if we process it; > it passes it along the hook chain if we don't process it. This allows someone > else using thread messages, in the case where we don't have a message > window, to call SetWindowsHookEx to install their own handler to catch > thread messages that we pull off the message queue. > > I think I've covered most bases. I can't run the test suite, as it > throws too many errors on Win98. I'll try to do it on Win2K in the > next couple of days. > > I also attach a couple of scripts that exhibit some of the > problems I was trying to eliminate. They are documented in the > scripts themselves. > > Still TODO: > - I need help getting some of the > PERL_IMPLICIT_CONTEXT/MULTIPLICITY/whatever ifdefs right. The context > passing is a bit complex, as we can't change the signature for the > window procedure callback to include a context, but I've coded a way > round this. > - I'd like to see us using registered messages rather than WM_USER_* > macros. This would avoid us ever clashing with someone else's message > numbers (this is only a potential problem for thread messages, not > when we have a message window) > > A lot of the complexity of the context passing could be removed if we > were to agree to take the hit of doing a dTHX; in > win32_process_message. We don't go in there very often (only for > alarms, kills and forks (and thread creation?). Perhaps the overhead > is worth the reduction in complexity? > > I will re-iterate: all that is actually needed to solve the original > DDE initialisation problem that started this discussion is to add > QS_SENDMESSAGE to the MsgWaitForMultipleObjects line in > win32_msgwait(). All the rest of this stuff would be 'nice to have' > so that Win32::GUI, Tk and other gui tookits can play nicely with perl > on Win32. > > I hope this is useful, > Regards, > Rob. > > -- Please update your address book with my new email address: ro...@th... |
From: Robert M. <rob...@us...> - 2007-07-31 21:23:26
|
On 30/07/07, Robert May <rob...@us...> wrote: > Attached is a patch to win32.c (against AS build 819). It implements > most of what I've talked about, plus a few other bits. It fails 2 of the fork() tests on bleed, and one under AS build 819. > A lot of the complexity of the context passing could be removed if we > were to agree to take the hit of doing a dTHX; in > win32_process_message. We don't go in there very often (only for > alarms, kills and forks (and thread creation?). Perhaps the overhead > is worth the reduction in complexity? On investigation it turns out that the dTHX; I was doing in win32_create_message_window() gives the context of the "parent" thread when forking. There are 2 ways to solve this - always pass the context into win32_create_message_window(), or do a dTHX; in win32_process_message. I've opted for the latter, as it simplifies the code a lot. We can always change this later. I'll post another version as soon as I've shown that it tests clean (hopefully tomorrow). > Still TODO: > - I'd like to see us using registered messages rather than WM_USER_* > macros. This would avoid us ever clashing with someone else's message > numbers (this is only a potential problem for thread messages, not > when we have a message window) Regards, Rob. |
From: Robert M. <ro...@th...> - 2007-08-01 22:19:04
Attachments:
win32.c.AP819.patch
win32.c.5.9.5.patch
|
On 31/07/07, Robert May <rob...@us...> wrote: > I'll post another version as soon as I've shown that it tests clean > (hopefully tomorrow). Attached patches implement the same functionality against AS build 819 and, probably more importantly, perl 9.5.9. Tests run without failures (well, the same failures as I get without the patch - see below). Jan - Would you like to comment on whether you think this is suitable? If so I'll take it to P5P, if not I'll only propose the simple change to the QS_ flags. I'd like to see something like this go in, as it'll make future development for Win32::GUI a whole load more robust. > > Still TODO/to think about: > > - I'd like to see us using registered messages rather than WM_USER_* > > macros. This would avoid us ever clashing with someone else's message > > numbers (this is only a potential problem for thread messages, not > > when we have a message window) Because we sometimes use thread messages, I think there should be better bounds checking within the handlers in win32_process_message(). For example we treat *any* message with value WM_USER_MESSAGE as ours, and blindly use the wParam value as an offset into the w32_pseudo_child_message_hwnds[] array. If someone else happened to pick this same message number for a thread message, and had a large number in wParam (a window handle for example), we'd end up trying to write beyond the end of the array. This might be the driver for me to implement the registered window messages, which would solve the problem. Regards, Rob. All test runs on win2000, showing results without and with the attached patches. (1) AS Build 819 Win2k: Failed Test Stat Wstat Total Fail Failed List of Failed ------------------------------------------------------------------------------- ../ext/IO/t/io_dup.t 6 4 66.67% 2-5 comp/multiline.t 6 2 33.33% 5-6 io/dup.t 26 6 23.08% 2-7 51 tests and 315 subtests skipped. Failed 3/997 test scripts, 99.70% okay. 12/118111 subtests failed, 99.99% okay. (2) AS Build 819 Win2k with patched win32.c Failed Test Stat Wstat Total Fail Failed List of Failed ------------------------------------------------------------------------------- ../ext/IO/t/io_dup.t 6 4 66.67% 2-5 comp/multiline.t 6 2 33.33% 5-6 io/dup.t 26 6 23.08% 2-7 51 tests and 315 subtests skipped. Failed 3/997 test scripts, 99.70% okay. 12/118111 subtests failed, 99.99% okay. (3) 5.9.5 Win2k: Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- ../ext/IO/t/io_dup.t 6 4 2-5 ../lib/Archive/Extract/t/01_Archive-Extra 255 65280 39 2 37 39 comp/multiline.t 6 2 5-6 io/dup.t 29 6 2-7 (1 subtest UNEXPECTEDLY SUCCEEDED), 55 tests and 728 subtests skipped. Failed 4/1457 test scripts. 14/183750 subtests failed. Files=1457, Tests=183750, 1022 wallclock secs ( 0.00 cusr + 0.00 csys = 0.00 CPU) Failed 4/1457 test programs. 14/183750 subtests failed. (4) 5.9.5 Win2k: Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- ../ext/IO/t/io_dup.t 6 4 2-5 ../lib/Archive/Extract/t/01_Archive-Extra 255 65280 39 2 37 39 comp/multiline.t 6 2 5-6 io/dup.t 29 6 2-7 (1 subtest UNEXPECTEDLY SUCCEEDED), 55 tests and 728 subtests skipped. Failed 4/1457 test scripts. 14/183750 subtests failed. Files=1457, Tests=183750, 987 wallclock secs ( 0.00 cusr + 0.00 csys = 0.00 CPU) Failed 4/1457 test programs. 14/183750 subtests failed. |
From: Jan D. <ja...@ac...> - 2007-08-01 23:06:10
|
On Wed, 01 Aug 2007, Robert May wrote: > On 31/07/07, Robert May <rob...@us...> wrote: > > I'll post another version as soon as I've shown that it tests clean > > (hopefully tomorrow). I don't quite get the list of test failures. Are you getting test failures from just compiling the ActivePerl sources with `nmake && nmake test`? That would be wrong. Running without test failures is a prerequisite for the releases. > Attached patches implement the same functionality against AS build 819 > and, probably more importantly, perl 9.5.9. > > Tests run without failures (well, the same failures as I get without > the patch - see below). > > Jan - Would you like to comment on whether you think this is suitable? > If so I'll take it to P5P, if not I'll only propose the simple > change to the QS_ flags. I'd like to see something like this go in, > as it'll make future development for Win32::GUI a whole load more > robust. I'll take a look at your patches once I get a little more time. I may not get around to it until the weekend though. I definitely think we want to get these changes into Perl 5.10. Unfortunately we just missed ActivePerl 822, which was already approved by QA this afternoon (there is no 821, except on HP-UX). Cheers, -Jan |
From: Robert M. <rob...@us...> - 2007-08-01 23:26:44
|
On 02/08/07, Jan Dubois <ja...@ac...> wrote: > On Wed, 01 Aug 2007, Robert May wrote: > > On 31/07/07, Robert May <rob...@us...> wrote: > > > I'll post another version as soon as I've shown that it tests clean > > > (hopefully tomorrow). > > I don't quite get the list of test failures. Are you getting test failures > from just compiling the ActivePerl sources with `nmake && nmake test`? Yes. VC6 (although using the .h files from a more recent SDK). Win2k. I don't build perl from source very often, but I don't think I've ever had a completely clean test run with either ActivePerl or the 'official' source. If you're interested I'll do a clean build from the 819 source tomorrow, and let you see the relevant bits of the test output. > That would be wrong. Running without test failures is a prerequisite > for the releases. OK - I'll investigate further too, but probably not until the weekend. > > Attached patches implement the same functionality against AS build 819 > > and, probably more importantly, perl 9.5.9. > > > > Tests run without failures (well, the same failures as I get without > > the patch - see below). > I'll take a look at your patches once I get a little more time. I may not > get around to it until the weekend though. No rush from my perspective. > Unfortunately we just missed ActivePerl 822, which was already approved > by QA this afternoon (there is no 821, except on HP-UX). I've not even caught up with 820 yet! Thanks for your input. Rob. |
From: Robert M. <ro...@th...> - 2007-08-02 13:43:18
|
On 02/08/07, Robert May <rob...@us...> wrote: > On 02/08/07, Jan Dubois <ja...@ac...> wrote: > > On Wed, 01 Aug 2007, Robert May wrote: > > > On 31/07/07, Robert May <rob...@us...> wrote: > > > > I'll post another version as soon as I've shown that it tests clean > > > > (hopefully tomorrow). > > > > I don't quite get the list of test failures. Are you getting test failures > > from just compiling the ActivePerl sources with `nmake && nmake test`? > > Yes. VC6 (although using the .h files from a more recent SDK). > Win2k. I don't build perl from source very often, but I don't think > I've ever had a completely clean test run with either ActivePerl or > the 'official' source. Turns out I had a broken type.exe on my path that caused lines like my $x = `type somefile`; to fail. Remove it, and I get a clean bill of health on the tests. That's that one solved. Regards, Rob. |