none
XPSP3+IE8でwindow.open後に再読込みが発生しエラーとなる RRS feed

  • 質問

  • 表題の件ですが、以下の現象について質問させてください。

    [環境]
    OS:Windows XP SP3 もしくは Windows Vista Business SP2
    IE:8

    [現象と発生手順]
    メール末尾のサンプルスクリプト(現象発生部分を抜粋)を参照ください。
    1.parent.htmlを開き「子画面を開く」ボタンを押下する
    2.child.htmlが開き、「initchild」のダイアログが表示されるので、「OK」ボタンを押下する
    3.再度「initchild」のダイアログが表示される 
     →なぜかchild.htmlが再ロードされてしまう
    4.openerオブジェクトがnullのエラーが表示され停止する

    [補足説明]
    処理の内容としては、子ウィンドウから親ウィンドウのxmlノードにアクセスし、
    clonenodeした途端に、子ウィンドウが再ロードされてしまいます。

    [その他特記事項]
    ・IE7およびIE6では同現象が発生しません(エラーが発生しない)
    ・IE8においても以下のTabProcGrowthのレジストリ(新規ウィンドウを開く際、新しくプロセスを作らない)
     をあてると発生しなくなります
     [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Main]
      "TabProcGrowth"=dword:00000001

    [質問]
    IE8の動作に起因した問題と思い、本フォーラムに質問させていただきました。
    原因および解決策についてご教授いただきたくお願いいたします。
     

    [サンプルスクリプト]

    parent.html
    ------------------------------------------------
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <meta http-equiv="Expires" CONTENT="-1"/>
    <meta http-equiv="Content-Script-Type" content="text/javascript"/>
    <script type="text/javascript" src="parent.js" charset="UTF-8"></script>
    <title>親ウインドウ</title>
    </head>
    <body onload="initParent()">
    <form id="form1" name="form1">
     <input id="button1" name="button1" type="button" onClick="window.open('child.html', 'child', 'width=200,height=100,menubar=no,scrollbars=no,toolbar=no, top=200, left=100')" value="子画面を開く">
    </form>
    </body>
    </html>
    ------------------------------------------------
    
    child.html
    ------------------------------------------------
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <meta http-equiv="Expires" CONTENT="-1"/>
    <meta http-equiv="Content-Script-Type" content="text/javascript"/>
    <script type="text/javascript" src="child.js" charset="UTF-8"></script>
    <title>子ウインドウ</title>
    </head>
    <body onload="initchild()">
    <form id="form2" name="form2">
     <input id="button1" name="button1" type="button" value="孫画面を開く">
    </form>
    </body>
    </html>
    ------------------------------------------------
    

     

    parent.js
    ----------------------------------------------------------------
    var AX_MSXML = "MSXML2.DOMDocument";
    var g_xml;
    
    function initParent()
    {
    
    	alert("initparent");
    	g_xml=new ActiveXObject(AX_MSXML);
    	g_xml.async=false;
    	g_xml.load("param.xml");
    	
    }
    ----------------------------------------------------------------
    
    child.js
    ----------------------------------------------------------------
    var AX_MSXML = "MSXML2.DOMDocument";
    var g_childxml;
    
    function initchild()
    {
    	alert("initchild");
    	g_childxml = new ActiveXObject(AX_MSXML);
    	g_childxml.async=false;
    	g_childxml.documentElement = opener.g_xml.documentElement.cloneNode( true );
    	
    	var i;
    	i = 100;	//デバッガ停止用ステップ
    
    }
    ----------------------------------------------------------------
    
    param.xml
    ------------------------------------------------------
    <?xml version="1.0" encoding="UTF-8"?>
    <Param>
    	<aaa>test1</aaa>
    	<bbb>test2</bbb>
    </Param>
    ------------------------------------------------------
    2010年5月25日 7:09

回答

  • 先にも書いたように、文字列経由にすることで、うまくいきませんか?(XMLオブジェクトの生成元は子側で!)
    この方法であれば、初期構築以降の操作も動作するはずなのですが。

    g_childxml.documentElement = opener.g_xml.documentElement.cloneNode( true );

    g_childxml.loadXML( opener.g_xml.xml);

    それでもダメなら、documentElementはかなり特殊な要素なはずで、そのCloneのみがダメなのであって、他の要素のClone&insertは動く可能性も少なくないと思っています。

    色々試してみませんか?(すでに調査済みならすみません)

    • 回答の候補に設定 山本春海 2010年6月8日 6:55
    • 回答としてマーク nb2000 2010年6月8日 14:20
    2010年6月1日 17:11

すべての返信

  • 再現しませんでした(´・ω・`)

    当方の環境は、XP SP3&IE8とWin7&IE8です。
    TabProcGrowthを設定していないことは確認しました。
    (親ウィンドウと子ウィンドウが別プロセスで動作していることも確認しています)
    (ネットワークはローカルイントラネットだったり、インターネットゾーン&保護モードだったり)

    再現しないとは、
    3.再度「initchild」のダイアログが表示される
    →なぜかchild.htmlが再ロードされてしまう
    4.openerオブジェクトがnullのエラーが表示され停止する
    の両方ともになります。

    nb2000さんの環境ではTabProcGrowthを設定した場合、3番、4番両方とも再現しなくなるということでしょうか?
    しかし、原因不明の再ロードが発生してしまうと、openerがnullになるのはどうしようもなさそうですね。

    なので、再ロードが走る条件とタイミングを調査していきたい。
    「cloneNodeした途端」とは、
    opener.g_xml.documentElement.cloneNode( true );
    を変形して
    var o = opener;
    o = o.g_xml;
    o = o.documentElement;
    o = o.cloneNode(ture); ←このメソッドを呼び出したタイミングで同期ブロックされて、このメソッドが完了する前にchild.htmlのinitchildが呼び出されopenerがnullとなった

    と解釈しましたがよいでしょうか?


    やはり、onloadイベント以外で(マウスクリックなど)上記のメソッドを呼び出したとしても再現するのでしょうか?
    実際のコードはjQueryの$()のタイミングだったりするとかありますか?
    少しだけ遅らせてみると動作が変わったりしませんかね?
    setTimeout(function(){
    g_childxml.documentElement = opener.g_xml.documentElement.cloneNode( true );
    }, 1000);

    質問ばかりですみません。
    2010年5月26日 15:18
  • (´・ω・`)さん


    返信どうもありがとうございます。
    情報を提供いただける方に限って再現しなく残念です。

    取り急ぎ、質問に回答させていただきます。


    >nb2000さんの環境ではTabProcGrowthを設定した場合、3番、4番両方とも再現しなくなるということでしょうか?
      →そうです。TabProcGrowthを設定した場合は、3,4いずれも発生しません。

    >←このメソッドを呼び出したタイミングで同期ブロックされて、このメソッドが完了する前にchild.htmlの initchildが呼び出されopener
    >がnullとなった
    >と解釈しましたがよいでしょうか?
    →試してみたら違いました。(解析能力低く申し訳ありません)
    上記までは、うまくいきました
    次にg_childxml.documentElement にoを代入する時点でchild.htmlのinitchildが呼び出されopenerがnullとなりました。

    >やはり、onloadイベント以外で(マウスクリックなど)上記のメソッドを呼び出したとしても再現するのでしょうか?
      →再現しました。ボタンのonclickイベントで試してみました。

    >実際のコードはjQueryの$()のタイミングだったりするとかありますか?
    →ほとんど実際のコードに近いです。恥ずかしながら、jQueryなどのライブラリは使用しておりません。

    >少しだけ遅らせてみると動作が変わったりしませんかね?
    →1000msecと5000msecで試してみましたが、現象は変わりませんでした。

    2010年5月27日 6:06
  • (´・ω・`)さん

    いただいたご質問をもとにこちらでももう少し深堀してみます。
    上記返信で何かお気づきの点などありましたら、返信お願いいたします。
    2010年5月27日 6:11
  • 再現しました(`・ω・´)

    こちらでは、アクセス違反例外(0xc0000005)が発生しました。
    (この部分はさっくり削って確認しちゃっていました。申し訳ないです。一番疑うべき箇所だったのに。。。)

    nb2000さんの環境ではクラッシュして自動回復か何かのために再ロードが行われたのでしょうかね。

    WinDbgの出力は以下になりました。

    (2508.2548): Access violation - code c0000005 (!!! second chance !!!)
    eax=068e3a68 ebx=06ae0120 ecx=068e3a68 edx=00000002 esi=068e3a68 edi=00000000
    eip=5b7cb614 esp=0238d278 ebp=0238d284 iopl=0 nv up ei pl nz na po nc
    cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
    msxml3!Document::setRoot+0x13:
    5b7cb614 f6430b1f test byte ptr [ebx+0Bh],1Fh ds:0023:06ae012b=??
    
    STACK_TEXT:
    0238d284 5b7dd793 06ae0120 0238d638 5b8509ac msxml3!Document::setRoot+0x13
    0238d2dc 5b7dcac4 068e4700 057da3a4 0238d638 msxml3!DOMDocumentWrapper::putref_documentElement+0x92
    0238d2f8 5b7bd847 068e4700 00000028 0238d324 msxml3!DOMDocumentWrapper::_invoke+0x90
    0238d430 5b7bdb93 068e4700 00000000 00000028 msxml3!_dispatchImpl::InvokeHelper+0x109
    0238d46c 5b7dd2c9 5b8509ac 068e4700 00000028 msxml3!_dispatchImpl::Invoke+0x5e
    

     

    そんなことよりも回避策ですが、
    子ウィンドウでXMLオブジェクトを作成させるのではなく、親ウィンドウで作成すればいけませんかね。こちらではいけているようです。

    parent.jsに追加
    --------------------------------------------------------------
    function getXMLObject(){
    	var xml = new ActiveXObject(AX_MSXML);
    	xml.async = false;
    	return xml;
    }
    -------------------------------------------------------------
    
    child.js
    ----------------------------------------------------------------
    //	g_childxml = new ActiveXObject(AX_MSXML);
    //	g_childxml.async=false; //これらをやめて
    	g_childxml = opener.getXMLObject(); //親に作成させる。
    //	getXMLObject = opener.getXMLObject; //孫画面でさらに作成したい場合
    ----------------------------------------------------------------

    ただし、初期の構築はこれでよいとしてもその後のXML操作にオブジェクトを引数にしたい場合、
    それらも親に作成させる必要があるかもしれません。

     

    そのほかには、XMLオブジェクトがよく分かっていませんが、オブジェクトツリー構築手段として、
    オブジェクト経由がダメなようなので、
    文字列経由にすると問題がなくなる可能性があるとも思っています。

    • 回答の候補に設定 山本春海 2010年6月4日 5:08
    2010年5月27日 16:28
  • (`・ω・´)さん


    返信ありがとうございます。

    教えていただいた方法(親ウィンドウでオブジェクト作成)だと該当箇所はエラーが出なくなりました。
    ただ、予想されている通り他の箇所ではやはりエラーが発生します。

    どうも、親ウィンドウで作成したオブジェクトと子ウィンドウで作成したオブジェクトの
    間での操作がエラーとなるようですね。

    1点教えてください。以下のように考える理由をは何でしょうか?
    >ただし、初期の構築はこれでよいとしてもその後のXML操作にオブジェクトを引数にしたい場合、
    >それらも親に作成させる必要があるかもしれません。

    2010年5月28日 4:33
  • >1点教えてください。以下のように考える理由をは何でしょうか
    良い質問ですね(キリッ (と言って見る)。
    理由の1つ目は単純にこれまでの動作を見てそうだろうなと思っただけです。
    2つ目は「親に作成させる必要がある」というのはIEでは良くあることだと思っているからです。

    nb2000さんのTabProcGrowthで再現しなくなったという書き込みと手元の再現内容から
    プロセス単位かそれに類する単位で管理している「何か」(例えばポインタとか)があり、
    本来想定していない操作により管理外ものもが取り込まれたんだと思いました。
    事実、親ウィンドウに生成させると動作するようになりました。
    エラーの事象についても不正なポインタ読み出しとなっておりいかにもな感じです。
    (ebx+0Bhって言うのはメンバ変数なのでは?そうだとしたらメソッドへの影響が大きいかなと。しかもDocumentオブジェクト。←この辺は勘違いなのであしからず)
    実は今回と同様の設計をしている場合(オブジェクトを丸ごと取り込む系)、
    同様の問題が他のActiveXコントロールにも言えると考えていますが、何かありますかね?

    それとは別に、IEでは、関数がどのウィンドウで定義されたかによって、
    その関数内で生成されたオブジェクトの所属先が決まるというのは
    私にとってなじみ深い問題だったというのもあります。
    (例えば親と子で(true == true)がfalseになったり、子を閉じると子で生成したオブジェクトへのアクセスは親では不可となったり、.constructorが親子間で一致しなかったり、typeofが誤動作したり)
    このようにIEの場合組み込みオブジェクト(FunctionやNumberとか)は、
    windowオブジェクト単位で紐づいており、場合によって親に作成させる必要があるケースがありました。
    今回のものは、それがプロセス単位に変わっただけだと思いました。

    というようなことを、もやっと考えてなんとなく方向付けのためのレスをしただけなので、
    別な何かを期待していたらすみません。
    2010年5月28日 18:15
  • 補足です。同一のコードでしたが、こちらの環境では以下となりました。

    Win7 64bit&IE8 32bit →エラー: プロシージャの呼び出し、または引数が不正です。とエラー出力。
    Win7 64bit&IE8 64bit →エラー: プロシージャの呼び出し、または引数が不正です。とエラー出力。

    Win7とVistaは同じような動きをすると思って未確認だったんですが、
    どうやら異なっているようですね(少なくともnb2000さんの環境とは)。

    落ちる環境はWinXP SP3&IE8で確認していました。

    他に確認された方いらっしゃいましたら教えてください。

    2010年5月30日 15:19
  • (`・ω・´)さん

    回答ありがとうございます。
    また、返信が遅くなり申し訳ありません。

    Web関連は専門外で、内部の動作がいまいち想像しにくいため、
    少ししつこく質問してしまいました。
    丁寧にご回答いただきありがとうございます。

    本件、もうこれ以上の情報は集まらなさそうですが、2,3日程度(投稿から1週間)様子を見た後、
    closeさせていただきます。よろしくお願いいたします。

    色々とありがとうございました。
    重ねて御礼申し上げます。

    2010年5月30日 15:32
  • 先にも書いたように、文字列経由にすることで、うまくいきませんか?(XMLオブジェクトの生成元は子側で!)
    この方法であれば、初期構築以降の操作も動作するはずなのですが。

    g_childxml.documentElement = opener.g_xml.documentElement.cloneNode( true );

    g_childxml.loadXML( opener.g_xml.xml);

    それでもダメなら、documentElementはかなり特殊な要素なはずで、そのCloneのみがダメなのであって、他の要素のClone&insertは動く可能性も少なくないと思っています。

    色々試してみませんか?(すでに調査済みならすみません)

    • 回答の候補に設定 山本春海 2010年6月8日 6:55
    • 回答としてマーク nb2000 2010年6月8日 14:20
    2010年6月1日 17:11
  • (`・ω・´)さん

    引き続き有効な情報ありがとうございます。
    また、返信遅くなり申し訳ありません。

    結論から言いますと、ご指示いただいた方法で問題なく動作するようになりました。

    文字列経由だと問題(例外)が発生しないことは確認できていたため、
    xmlのノードを解析し、コピーする処理を実装しなければと思っておりましたが、
    loadXMLを使用すること(ご指示いただいた方法)でいとも簡単に解決できました。

    最後まで助言ありがとうございました。
    上記、回答として本件closeさせていただきます。

    2010年6月8日 14:20