From: Robert M. <rm...@po...> - 2007-02-08 22:05:54
|
Waldemar Biernacki wrote: > Robert, > > thank you for your efforts and email, I'll try my best to clarify... Thank you. I can see the problem clearly. It's because you're destroying a window while in the middle of processing an event sent to it, and the code isn't expecting that, and so ends up trying to access some of the window's properties after they have been freed. I've got a solution to most of it, but there are a couple of areas where I'm not sure how to resolve it ... some more thought required, but I'll try to get a fix into the next release. For the record, here's the shortest example I can come up with that exhibits the problem: #!perl -w use strict; use warnings; use Win32::GUI(); my $mw; $mw = Win32::GUI::Window->new( -onKeyDown => sub { undef $mw; return -1; }, ); $mw->Show(); Win32::GUI::Dialog(); __END__ >>> The point is that in WindowsXP it works fine but in Widows 98 SP2 it >>> does not. >>> Windows' error screen points to USER32.DLL error. I concur that the problem only manifests itself on Win98, but that's just lucky. With various variations of the script I can get the error to appear in either User32.dll or Perl58.dll. Here's one way around the problem - I think this is pretty close to the behaviour of your current script (except for behaviour on clicking the 'close' button on the windows, which is somewhat unusual here, but I didn't know what you were expecting: #!perl -w use strict; use warnings; use Win32::GUI qw(VK_LEFT VK_RIGHT VK_RETURN); my @Window; makewindow(); $Window[0]->AddLabel( -pos => [4,20], -size => [150,150], -text => "HELP:\n\n". " Right=add window\n". " Left=close (only top) window\n". " Enter=switch windows", ); while(@Window) { Win32::GUI::Dialog(); pop @Window; } exit(1); sub makewindow { return if @Window > 4; push @Window, Win32::GUI::Window->new( -title => @Window ? "Item: " . @Window : "Main Window", -pos => [10+(@Window*202), 20], -size => [200, 200], -onKeyDown => \&keydown, ); $Window[-1]->Show(); return; } sub keydown { my ( $self, undef, $key ) = @_; if($key == VK_RIGHT) { makewindow(); } elsif($key == VK_LEFT) { return -1; } elsif($key == VK_RETURN) { for my $index (0 .. $#Window) { if($self == $Window[$index]) { $Window[++$index % @Window]->SetFocus(); } } } return 0; } __END__ Regards, Rob. |
From: Robert M. <rm...@po...> - 2007-02-09 21:52:45
|
Robert May wrote: > I can see the problem clearly. It's because you're > destroying a window while in the middle of processing an event sent to > it, and the code isn't expecting that, and so ends up trying to access > some of the window's properties after they have been freed. I've got a > solution to most of it, but there are a couple of areas where I'm not > sure how to resolve it ... some more thought required, but I'll try to > get a fix into the next release. > > For the record, here's the shortest example I can come up with that > exhibits the problem: > > #!perl -w > use strict; > use warnings; > > use Win32::GUI(); > > my $mw; > > $mw = Win32::GUI::Window->new( > -onKeyDown => sub { undef $mw; return -1; }, > ); > > $mw->Show(); > Win32::GUI::Dialog(); > __END__ Hackers, Would you expect the above sample to exit cleanly? The problem is that if we destroy a window during a callback, perlud gets freed before the callback returns; the code then has a non-NULL perlud pointer, that points into freed memory. The fact that this only exhibits a crash on Win98 is, I think, just luck. I've now got checks in place in all the places that I can see that we attempt to access perlud after a callback, and the crash appears to be fixed, but I'm left with one issue: return -1 results in us trying to exit the Dialog() loop using PostMessage(hwnd, WM_EXITLOOP, (WPARAM) -1, 0); but hwnd has already been destroyed, so the message never gets delivered. In the above example pressing a key causes the window to disappear, but leaves Dialog() spinning, and the script never finishes. I can change the PostMessage(..) to PostThreadMessage(GetCurrentThreadId(), WM_EXITLOOOP, (WPARAM) -1, 0); and all tests pass, and I haven't (yet) found a problem with it, but it feels like quite a fundamental change to me. Can anyone see a problem with it, or propose a better solution? Or should I not worry? Regards, Rob. |