Jeremy White wrote:
Question: is this a bug? The only alternate behaviour I can come up
with is that SetEvent(), rather than setting the NEM flag, should
check it and bail out if it is not set (with a warning?). [The
current behaviour is useful if you are sub-classing a control, and do
not know which method a user of the control will want to use.]
Surely running both NEM and OEM code for the same event is a bug? In
other words, a successful NEM call still causes the OEM logic to be run.
If you happen to have an sub that matches, then you get two events being
processed for a single event. See the code below for a better explanation:)
Well, you could certainly argue that it is a bug, but I don't really
know what the thinking was when this was originally written. There's
certainly an option -eventmodel => 'both', which explicitly allows this
(i.e. sets both the OEM and NEM flag).
As I see the logic in DoEvents (psudeo-code):
PerlResult = 1;
// NEM event
if((perlud->dwPlStyle & PERLWIN32GUI_NEM) && (perlud->dwEventMask &
iEventId)) {
PerlResult = 0;
PerlResult = NEM_CALLBACK;
.....
}
// OEM Event
if (PerlResult == 1 && (perlud->dwPlStyle & PERLWIN32GUI_OEM) &&
perlud->szWindowName != NULL) {
PerlResult = 0;
if there is a function called main::perlud->szWindowName_EventName {
PerlResult = OEM_CALLBACK;
......
}
}
This says do the NEM event if the NEM flag is set and there's a coderef
set for the event. Then do the OEM Event if:
- Either there was no NEM event, or the NEM event returned 1
- And the OEM flag is set
- And the window has a name
- And the correctly name callback function exists
So in my last analysis I missed the 3rd way not to get the OEM event
fired: returning 1 from the NEM handler.
I personally don't see anything wrong with this logic, so long as you
believe that returning 1 from an event handler means 'pass the event to
the next handler', regardless of whether this is another event handler,
or defwindowproc. Although I note that DoHook doesn't implement such
logic if you have multiple hooks for the same event.
So, we come back to whether the SetEvent logic is right. Currently
SetEvent replaces any NEM coderef for the event passed, or creates one
if there wasn't one there before, and ensures that the NEM flag is set.
As in my previous email, the only alternative I see is to get SetEvent
to choke if the NEM flag is not set.
I take back my position on not wanting to change this: having looked at
my code I use hooks rather than SetEvent, in order not to interfer with
what the user of my sub-classes intends. I am, thus, indifferent on
making such a change, although I might argue that if you only want NEM,
then you need to indicate that when you create the object. Do you have
an alternative on what you think would be correct behaviour?
Regards,
Rob.