Hi Internals,
Attached are details of a suggested patch for COM extension defect 37927 (http://bugs.php.net/bug.php?id=37927).
All comments welcome; good or bad.

Regards
   Andy

Andy Wharmby
IBM United Kingdom Limited
Winchester, England SO21 2JN
E-mail: [EMAIL PROTECTED]

_*COM Defect 37927*_

This defect actually reports issues with 2 different event sink interfaces, DwebBrowserEvents2 and DWebbrowserEvents. So taking each
one in turn:

*DWebBrowserEvents2::NewWindow2 Event  *
This event is documented at : http://msdn.microsoft.com/workshop/browser/webbrowser/reference/ifaces/dwebbrowserevents2/newwindow2.asp The defect details an issue with the NewWindow2 event handler but my testing has shown the exact same issue with NewWindows3 event too.

The problem here is that the user defined event handler is not getting called when the associated event occurs in IE and my investigations have shown this is due to a bug in the COM extension code. Examining the COM trace output with DebugView shows:

[4716] T=00001890
[4716]  PHP:IEEventSinker InvokeEx
[4716] T=00001890
[4716] -- Invoke: 251           newwindow2 [10] flags=00000001 args=2
[4716] T=00001890
[4716] alloc zval for arg 0 VT=00004009 << only one of two arguemets gets processed !!
[4716] T=00001890
[4716]  PHP:IEEventSinker InvokeEx  <<next event

So the event is reported but is only partially processed by the COM extension code; no attempt is made to call the event handler.

BTW. This COM trace in com_wrapper.c, which output using "OutputDebugString", is active in non-DEBBUG builds unlike all other uses in the PHP code base. I am not sure what the cost of these calls is but I would have expected such calls to be enabled in DEBUG builds only. Easily fixed and I will put together a fix unless anyone sees a need for this trace in non-DEBUG, i.e production builds.

Anyway the reason for the partial request processing is because the code is trapping in php_com_wrap_variant() when processing the input arguments for the "NewWindow2" (and NewWindow3) event. The NewWIndow2 event is defined on MSDN as follows:

void NewWindow2(IDispatch **&ppDisp, VARIANT_BOOL *&Cancel);

i.e a double indirect pointer to a IDispatch. However, this argument is defined for output. The VT_DISPATCH variant addressed has its type set but its value is NULL , i.e V_DISPATCH(<var addr>) == NULL . So when php_com_wrap_variant() attempts a call on the IDispatch interface to get type information and the PHP thread traps. Easily fixed by checking for a NULL IDispatch interface pointer prior to call.

Required patch to fix is here: http://www.pastebin.ca/329136

This fixes the problem of the event handler not being called in the first place. However any attempt by a NewWindow2/3 event handler to cancel the navigation, i.e by setting $cancel == TRUE, will still fail until the fix for defect 345764 is dropped (http://bugs.php.net/bug.php?id=34564). Frank is currently reviewing this fix.

*DWebBrowserEvents::NewWindow Event  *
This event is documented at : http://msdn.microsoft.com/workshop/browser/webbrowser/reference/ifaces/dwebbrowserevents/newwindow.asp.

However, the MSDN description does include the following warning:

"This interface is obsolete; use the DWebBrowserEvents2 interface instead. The DWebBrowserEvents2 interface provides more control over the WebBrowser control than the DWebBrowserEvents interface."

From my investigations I believe this interface has fallen into a state of disrepair and should not be used anymore. I can see no reason why anyone would need to use DWebBrowserEvents in preference to DWebBrowserEvents2; given that the minimum requirements, IE and Windows levels,
are the same in both cases.

During my investigation I found 2 problems which appear IE related and not issues in the COM extension itself:

(1) The interface defines NewWindow as an event that takes just 2 arguments. However it appears it actually now takes 6 !!.

The COM trace shows:
[7060] T=00001de4
[7060]  PHP:IEEventSinker InvokeEx
[7060] T=00001de4
[7060] -- Invoke: 107            newwindow [9] flags=00000001 args=6
[7060] T=00001de4
[7060] alloc zval for arg 0 VT=00000008
[7060] T=00001de4
[7060] alloc zval for arg 1 VT=00000003
[7060] T=00001de4
[7060] alloc zval for arg 2 VT=00000008
[7060] T=00001de4
[7060] alloc zval for arg 3 VT=0000400c
[7060] T=00001de4
[7060] alloc zval for arg 4 VT=00000008
[7060] T=00001de4
[7060] alloc zval for arg 5 VT=0000400b
[7060] T=00001de4
[7060] arguments processed, prepare to do some work
[7060] T=00001de4
[7060] function called ok

So defining the event handler as described on the MSDN site will result in unpredictable behaviour; certainly navigation will not be prevented
with the supplied testcase.

The 6th argument is of type VT_VOOL so I am guessing that's the "cancel" argument. By adding dummy arguments to the event handler as follows:

function NewWindow(&$dum1, $dum2, $dum3, $dum4, $dum5, &$Cancel) {
   $this->newWindowOpened = true;
   echo "NewWindow event was fired.\n";
   variant_set($Cancel,true);
   return;
 }

and with the fix for defect 345764 applied then the NewWindow event is fired the first time its tried and navigation is cancelled. However any subsequent attempt to open any link in a new window is also prevented even though not all attempts result in a NewWindow event being reported and occasionally I am unable to close down IE so perhaps my guess at what the 6th argument does is invalid!!. Everything is fine when DWebBrowserEvents2 interface is used.

(2) The supplied testcase defines the "OnQuit" event which is, according to MSDN, defined by the DWebBrowserEvents interface. Alas not !! Or at least not using IE Version 6. The actual event name appears to be "Quit" and not "OnQuit". Again here is the COM trace of the event reported using the supplied test case:

[6012]  PHP:IEEventSinker InvokeEx
[6012] T=00000ff0
[6012] -- Invoke: 103                 quit [4] flags=00000001 args=1
[6012] T=00000ff0
[6012] alloc zval for arg 0 VT=0000000b
[6012] T=00000ff0
[6012] arguments processed, prepare to do some work
[6012] T=00000ff0
[6012] failed to call func

This clearly shows the event is named "quit" and so the call to the any handler named "onQuit" fails. Modifying the testcase to define a method "Quit" and the user
defined method fires OK.















--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to