From: csaba at alum dot mit dot edu Operating system: Win XP Pro PHP version: 5.2.5 PHP Bug Type: COM related Bug description: variant_set with IE leads to hang
Description: ------------ If an event sink is set on IE, and then a new window is created by that IE (by clicking on a link with target=_blank, say), then NewWindow2 fires. By replacing the first argument to NewWindow2 (via set_variant) it is possible to identify the pending new ie and to assign a sink, $sink2, to it). The problem is that the $sink2->ie is somehow corrupted to such an extent that trying to access anything on it hangs ie badly. There is a 2nd less severe but still significant problem: If the bug causing 2 lines just above the print "\n"; in BeforeNavigate2 are commented out, then the PHP code will terminate if either instance of IE is closed. However, there is also an error genereated at the same time (the specific error varies, but I suspect that it has to do with cleanup of the COM objects). Reproduce code: --------------- <?php // set_variant bug testing $aES = array(); // global array of IE event sinks $newIEpage = "<body " . "onload='document.links[0].click()'>" . "<a target=_blank " . "href='http://google.com'>Goog</a></body>"; $ie = new COM("InternetExplorer.Application"); sink_ie($ie); $ie->visible = true; $ie->Navigate2("about:blank"); while ($ie->ReadyState<4) com_message_pump(200); $ie->Navigate2("javascript:\"$newIEpage\""); $ie->document->title = "variant_set Launcher"; $keepLooping = true; while ($keepLooping) com_message_pump(200); print "Exiting"; class mysink { public $ie = null; // reqd for evt sink to function function __construct($ie) { $this->ie = $ie; } public function BeforeNavigate2 ( $ie, $url, $flags, $targetFrameName, $postData, $headers, &$cancel) { print __FUNCTION__ . ": " . typename($ie) . ", "; print $ie->hwnd . ", rs: " . $ie->ReadyState; print "; " . $url . "\n"; global $aES; print " Sink count: " . sizeof($aES); print ", this->ie: "; print typename($this->ie) . ", "; // produces bug print $this->ie->hwnd; // produces bug print "\n"; } public function NewWindow2 (&$newIe, $cancel) { $ie = new COM("InternetExplorer.Application"); print "NewWindow2: "; variant_set($newIe, $ie); $sink2 = sink_ie($ie); print $sink2->ie->hwnd . "\n"; } public function DownloadComplete() { print __FUNCTION__ . "\n"; } public function DocumentComplete($dom, $url) { print __FUNCTION__ . ": $url\n"; } public function onQuit() { print "Quitting\n"; $GLOBALS['keepLooping'] = false; } } function typename($objCOM) { // similar to typename in vbscript if (empty($objCOM)) return "no COM object"; if (gettype($objCOM)!="object") return "not a COM object"; ob_start(); com_print_typeinfo($objCOM); $typeInfo = ob_get_contents(); ob_end_clean(); $pattern = "/^\\s*class (.*) \\{/"; if (!($matchCnt = preg_match($pattern, $typeInfo, $aMatch))) return "Not found"; return "COM:" . $aMatch[1]; } function sink_ie($ie) { // sink $ie, and add to global array of sinks global $aES; com_event_sink ($ie, $aES[] = $sink = new mysink($ie), "DWebBrowserEvents2"); return $sink; } ?> Expected result: ---------------- This is PHP CLI code. When run from the cmd prompt, I expect two instances of IE to come up (they do), and for the cmd prompt to display the navigation progress. Now I could see that $sink2->ie becomes obsolete somehow (even though its hwnd is the same as the hwnd that comes into BeforeNavigate2), but what seems really wrong is to get a hang upon trying to do anything with that variable in BeforeNavigate2 (either $this->ie or $aES[sizeof($aES)-1]->ie) Actual result: -------------- If the included script is run as is, then typename($this->ie) causes a hang. If it is commented out, $this->ie->hwnd causes a hang. If both of these statements (the two lines before the last print statement in BeforeNavigate2) are commented out, then both IE pages will load OK (ie. the main bug goes away), and there will only be issues when the php code shuts down on account of one of the two IE's being closed. A note about the code: While it may appear somewhat convoluted, the point of the original code was to track navigation progress within ie, and this works fine. However, when (simulated) clicking on a link causes the browser to open a new window, then navigation tracking must continue with a new ie, and the way to get ahold of that ie is with the NewWindow2 or NewWindow3 event, and I used the former. Two things need to happen in NewWindow2. The first is that the first argument to the event handler needs to be set to an uninitiated, fresh IE. The second is that this new IE needs to be sinked. Because we're in an event handler, globals are not so good, but since event sinks require a reference to their COM object, the sink gets an IE variable. The variable is not superfluous: if you make NewWindow2's final line be $sink2->ie = null; the 2nd event handler won't function. $aES is not required in the script, but it is useful in broader schemes where one cannot be sure whether the particular IE is already sunk (and hence one iterates through it, looking at the handles of the associated IEs. Csaba Gabor from Vienna -- Edit bug report at http://bugs.php.net/?id=43838&edit=1 -- Try a CVS snapshot (PHP 4.4): http://bugs.php.net/fix.php?id=43838&r=trysnapshot44 Try a CVS snapshot (PHP 5.2): http://bugs.php.net/fix.php?id=43838&r=trysnapshot52 Try a CVS snapshot (PHP 5.3): http://bugs.php.net/fix.php?id=43838&r=trysnapshot53 Try a CVS snapshot (PHP 6.0): http://bugs.php.net/fix.php?id=43838&r=trysnapshot60 Fixed in CVS: http://bugs.php.net/fix.php?id=43838&r=fixedcvs Fixed in release: http://bugs.php.net/fix.php?id=43838&r=alreadyfixed Need backtrace: http://bugs.php.net/fix.php?id=43838&r=needtrace Need Reproduce Script: http://bugs.php.net/fix.php?id=43838&r=needscript Try newer version: http://bugs.php.net/fix.php?id=43838&r=oldversion Not developer issue: http://bugs.php.net/fix.php?id=43838&r=support Expected behavior: http://bugs.php.net/fix.php?id=43838&r=notwrong Not enough info: http://bugs.php.net/fix.php?id=43838&r=notenoughinfo Submitted twice: http://bugs.php.net/fix.php?id=43838&r=submittedtwice register_globals: http://bugs.php.net/fix.php?id=43838&r=globals PHP 3 support discontinued: http://bugs.php.net/fix.php?id=43838&r=php3 Daylight Savings: http://bugs.php.net/fix.php?id=43838&r=dst IIS Stability: http://bugs.php.net/fix.php?id=43838&r=isapi Install GNU Sed: http://bugs.php.net/fix.php?id=43838&r=gnused Floating point limitations: http://bugs.php.net/fix.php?id=43838&r=float No Zend Extensions: http://bugs.php.net/fix.php?id=43838&r=nozend MySQL Configuration Error: http://bugs.php.net/fix.php?id=43838&r=mysqlcfg