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

Reply via email to