Hatena::Groupmoz-addon

Ci.nsIZIGOROu

2008-02-08イケスカナイ

WebBrowser Controlには後からConnectObject()出来ない

| 03:41 |  WebBrowser Controlには後からConnectObject()出来ない - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  WebBrowser Controlには後からConnectObject()出来ない - Ci.nsIZIGOROu

IEってひょっとして生成前から仕込まないとダメなのかな?

var browser = WScript.CreateObject("InternetExplorer.Application");
WScript.ConnectObject(browser, "browser_");

これは接続出来ないって言われる。

WebBrowser Control, MSHTMLのイベント発火とJS側の状態

| 02:49 |  WebBrowser Control, MSHTMLのイベント発火とJS側の状態 - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  WebBrowser Control, MSHTMLのイベント発火とJS側の状態 - Ci.nsIZIGOROu

どの時点でIEのスクリプトに横槍出来るか試してみた。

はじめに

実験はIE7でやってます。IE6は捨ての方向で。

またWSHでやってます。ソース見れば分かると思うけど。

ソース


var browser = WScript.CreateObject("InternetExplorer.Application", "browser_");

var console = {
  log: function(msg) {
    WScript.StdErr.Write(msg + "\n");
  }
};

function browser_BeforeNavigate2(browser, url, flags, target, postdata, headers, cancel) {
  console.log("[event] BeforeNavigate2");
  console.log("ReadyState : " + browser.ReadyState);
  console.log("document -> " + typeof browser.Document);

  with({ window: browser.Document.parentWindow }) {
    console.log("window -> " + typeof window);
    console.log("eval -> " + typeof window.eval);
  }
}

function browser_DownloadBegin() {
  console.log("[event] DownloadBegin");
  console.log("ReadyState : " + browser.ReadyState);
  console.log("document -> " + typeof browser.Document);

  if (browser.ReadyState > 0 && typeof browser.Document == "object") {
    with({ window: browser.Document.parentWindow }) {
      console.log("window -> " + typeof window);
      console.log("eval -> " + typeof window.eval);
    }
  }
}

function browser_DownloadComplete() {
  console.log("[event] DownloadComplete");
  console.log("ReadyState : " + browser.ReadyState);
  console.log("document -> " + typeof browser.Document);

  with({ window: browser.Document.parentWindow }) {
    console.log("window -> " + typeof window);
    console.log("eval -> " + typeof window.eval);

    if (browser.ReadyState == 1 && typeof window == "object") {
      window.console = console;

      window.document.attachEvent("onreadystatechange", function(evt) {
        console.log("[event] onreadystatechange");
        console.log("ReadyState : " + browser.ReadyState);
        console.log("document -> " + typeof browser.Document);
        console.log("window -> " + typeof window);
        console.log("eval -> " + typeof window.eval);
      });

      window.attachEvent("onload", function(evt) {
        console.log("[event] onload");
        console.log("ReadyState : " + browser.ReadyState);
        console.log("document -> " + typeof browser.Document);
        console.log("window -> " + typeof window);
        console.log("eval -> " + typeof window.eval);
      });
    }
  }
}

function browser_WindowStateChanged(flags, validFlags) {
  console.log("[event] WindowStateChanged : " + flags);
  console.log("ReadyState : " + browser.ReadyState);
  console.log("document -> " + typeof browser.Document);
  
  if (browser.ReadyState > 0 && typeof browser.Document == "object") {
    with({ window: browser.Document.parentWindow }) {
      console.log("window -> " + typeof window);
      console.log("eval -> " + typeof window.eval);
    }
  }
}

function browser_NavigateComplete2(ie, url) {
  console.log("[event] NavigateComplete2");
  console.log("ReadyState : " + browser.ReadyState);
  console.log("document -> " + typeof browser.Document);

  with({ window: browser.Document.parentWindow }) {
    console.log("window -> " + typeof window);
    console.log("eval -> " + typeof window.eval);
  }
}

function browser_DocumentComplete(ie, url) {
  console.log("[event] DocumentComplete");
  console.log("ReadyState : " + browser.ReadyState);
  console.log("document -> " + typeof browser.Document);

  with({ window: browser.Document.parentWindow }) {
    console.log("window -> " + typeof window);
    console.log("eval -> " + typeof window.eval);
  }
}

function browser_OnQuit() {
  console.log("[event] OnQuit");
  browser = null;
}

browser.Visible = true;
browser.Navigate2("http://sample.art-code.org/ie.html");

while (true) {
  if (!browser) {
    break;
  }
  WScript.Sleep(1000);
}

console.log("End");

結果

実際の実行結果は貼り付けると縦長になるので、表組みにしてみた。

object event ReadyState Document window eval
WebBrowser DownloadBegin 1 unknown -- --
WebBrowser WindowStateChanged 1 unknown -- --
WebBrowser DownloadComplete 1 object object undefined
WebBrowser DownloadBegin 1 object object undefined
WebBrowser NavigateComplete2 1 object object undefined
WebBrowser WindowStateChanged 1 object object undefined
HTMLDocument onreadystatechange 3 object object undefined
WebBrowser DownloadComplate 3 object object object
HTMLDocument onreadystatechange 4 object object object
WebBrowser DocumentComplate 4 object object object
HTMLWindow onload 4 object object object

こんな感じの結果となる。見分けやすいように変更点があるところをボールドにしてみた。

IE7の場合は最も早くwindowオブジェクトが生成されるのが、

  • DownloadComplateイベントの発火時
  • ReadyStateが1の時

が成り立つ時のようだ。

それ以前はdocumentオブジェクト相当がunknownとなりアクセス出来ない。またevalは当分実行出来なくて、やはりDownloadCompleteイベントの発火時で、ReadyStateが3の時に実行出来る。これじゃ全然意味が無い。*1

まとめ

  • とりあえずInternetExplorer.Applicationをダイレクトで生成すればイベントに接続出来る
  • 肝はDownloadCompleteイベント
  • evalは当分使えない
  • Document, ReadyStateの値が状態をはかるのに参考となる

って所かな。

ちなみにこれが出来るとGreasemonkey的な枠組みを作ろうと思えば出来る*2し、予め任意のオブジェクトを用意しておくことも可能です。

但しvar宣言はeval相当*3が使えないとやれないので、d:id:amachangdocumentオブジェクトを差し替えるhackを予め仕込むとかは出来ない。

但し、DownloadComplete, ReadyState = 3のときに差し込めば、実際のDOMアクセス処理が走る前には適用出来ると思いますけど。

これは画面遷移が挟まったとしても有効です。

*1:但しsetTimeoutの時間指定を0とかにしたら実行出来るかもしれない

*2:但し、WSHの権限をもろに使えるようになるのでやることによっては相当危険

*3:setTimeout, execScriptも同等の事が出来るけど

2007-11-28

COMのイベント (1)

| 03:29 |  COMのイベント (1) - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  COMのイベント (1) - Ci.nsIZIGOROu

まずは最初に参考サイトから。

参考サイト

TLI.TLIApplicationのInvoke系メソッド

iriyak:JScript:メソッド名が予約語と衝突

var tliapp = new ActiveXObject("TLI.TLIApplication");
var fso = new ActiveXObject("Scripting.FileSystemObject");
var invokeId = tliapp.InvokeID(fso, "FileExists");
WScript.Echo(invokeId.toString(16));

こんなんでDISPIDが取れるみたい。これはDISPIDの取得だけだが、任意のメソッドコールを呼び出し方の指定をして行う事も可能。

var INVOKE_FUNC = 1;
var invokeId = 0x2720;
var ret = tliapp.InvokeHook(fso, invokeId, INVOKE_FUNC, "C:\\A.TXT");

IDispatch::Invoke()のwrapperみたいになってるみたいです。

これ結構突っ込んだ事まで出来そうな気がする。

COM Eventのメモ

mshtmlとかMicrosoft.XMLHttpRequestだっけ、とかとか。

JSから使われる前提の場合は、良くご存知の通りhandlerを参照で渡す事が可能で、

req.onreadystatechange = function(evt) {}

みたいな事が出来るんだけど、一般的なCOMオブジェクトはWSHからはこういう書き方は出来ない。

WScript.ConnectObject()しないとダメ。

このカラクリって、COMオブジェクト側で

  • handlerを持っておくアクセサ
  • handlerを呼び出すイベント関数

がどうも同名で定義されてるように思える。(OLE Viewer見る限りは)

参考リンクのjscriptで自作COMからイベントを発生させたいの話の流れを読む限りは、同名じゃないけどJScriptから渡されたFunctionオブジェクトとそれを呼び出すイベント関数の両方が定義されてるのが分かる。

2007-11-21

SAPI.SpVoiceで文字を喋らせる

| 02:33 |  SAPI.SpVoiceで文字を喋らせる - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  SAPI.SpVoiceで文字を喋らせる - Ci.nsIZIGOROu

まぁ、ネタなんだけども。

var spkr = new ActiveXObject("SAPI.SpVoice");
spkr.Speak("I'am zigorou.");
spkr.Speak("Z nipotan");

cscriptで実行してみると最初結構びっくりする。w

LisaLisa2011/12/30 19:24Thank God! Soomene with brains speaks!

kyopwkkjjgmkyopwkkjjgm2011/12/31 17:43BDhlUf <a href="http://ekyqbjsbttmw.com/">ekyqbjsbttmw</a>

nikykfcnhnikykfcnh2012/01/01 02:129r5tIN , [url=http://cdzftnvfmqrn.com/]cdzftnvfmqrn[/url], [link=http://trlsszrrvttb.com/]trlsszrrvttb[/link], http://ixdiupasdnzd.com/

fncdimdgzvfncdimdgzv2012/01/01 22:38xaRRyM <a href="http://pflwuryohxwz.com/">pflwuryohxwz</a>

lhpoarhlhpoarh2012/01/02 03:54ZB2AHF , [url=http://oukmjuujwjvb.com/]oukmjuujwjvb[/url], [link=http://frtndpmsbbzz.com/]frtndpmsbbzz[/link], http://bkugxojdcxfu.com/

2007-11-01風邪治らない

COMの列挙再び

| 04:38 |  COMの列挙再び - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  COMの列挙再び - Ci.nsIZIGOROu

幾つか方法がある。

WMIのWQLを使う

var locator = new ActiveXObject("WbemScripting.SWbemLocator");
var service = locator.ConnectServer(null, "root\\cimv2");
var rs = service.execQuery("SELECT * FROM Win32_ClassicCOMClassSetting WHERE ProgID <> NULL");

WScript.Echo(rs.count);

var rsEnum = new Enumerator(rs);

for (; !rsEnum.atEnd(); rsEnum.moveNext()) {
  WScript.Echo(rsEnum.item().ProgId);
}

ちなみにこの時取れるカラムは以下のとおり。

  • AppID
  • AutoConvertToClsid
  • AutoTreatAsClsid
  • Caption
  • ComponentId
  • Control
  • DefaultIcon
  • Description
  • InprocHandler
  • InprocHandler32
  • InprocServer
  • InprocServer32
  • Insertable
  • JavaClass
  • LocalServer
  • LocalServer32
  • LongDisplayName
  • ProgId
  • SettingID
  • ShortDisplayName
  • ThreadingModel
  • ToolBoxBitmap32
  • TreatAsClsid
  • TypeLibraryId
  • Version
  • VersionIndependentProgId

このカラム名も取得できます。

var pEnum = new Enumerator(rsEnum.item().Properties_);
for (; !pEnum.atEnd(); pEnum.moveNext()) {
  WScript.Echo(pEnum.item().name);
}

ただどういう訳か、一部列挙出来ない物があるみたい。

WMIのセキュリティ設定が云々っぽぃんだけど謎。

WMIからRegStdProvオブジェクトを使う

serviceの取得手順がちょっと違う。

// これ専用、Array.prototype.forEachがあればウマーなんだけどな
Enumerator.prototype.toArray = function() { 
  var result = []; 
  this.moveFirst(); 
  for (; !this.atEnd(); this.moveNext()) {
    result.push(this.item().name); 
  } 
  this.moveFirst(); 
  return result; 
};

var locator = new ActiveXObject("WbemScripting.SWbemLocator"); // [object SWbemLocator]
var service = locator.ConnectServer(null, "root\\default"); // [object SWbemServicesEx] 第二引数の値が違う
var srp = service.Get("StdRegProv"); // [object SWbemObjectEx]

// メソッド名列挙
var mEnum = new Enumerator(srp.Methods_);
WScript.Echo(mEnum.toArray().join(","));
// CreateKey,DeleteKey,EnumKey,EnumValues,DeleteValue,
// SetDWORDValue,GetDWORDValue,SetStringValue,GetStringValue,
// SetMultiStringValue,GetMultiStringValue,SetExpandedStringValue,
// GetExpandedStringValue,SetBinaryValue,GetBinaryValue,CheckAccess

var method = srp.Methods_.item("EnumKey"); // [object SWbemMethod]
var params = method.InParameters.SpawnInstance_(); // [object SWbemObjectEx]

// メソッドのパラメータ列挙
var pEnum = new Enumerator(params);
WScript.Echo(pEnum.toArray().join(","));
// hDefKey,sSubKeyName

params.hDefKey = 0x80000000; // HKEY_CLASSES_ROOTの値
params.sSubKeyName = "CLSID";

var rs = srp.execMethod_(method.name, params); // [object SWbemObjectEx]

WScript.Echo(rs.ReturnValue);
WScript.Echo(rs.sNames.toArray()); // これでCLSIDが全部列挙される

が、しかしWMIを使うとどうしても列挙出来ない奴がある。(MSWInsock.Winsockとか)

あとEnumerator使いまくると便利。

予めEnumerator, Array辺りはprototype拡張必要かも。

具体的には、

params.sSubKeyName = "MSWinsock.Winsock\\";

として実行するとCLSIDとかキー名が列挙出来てもいいはずなんだけど出来ない。

一方で、WScript.ShellのRegReadすると見事に取れる。

var wshell = new ActiveXObject("WScript.Shell"); 
WScript.Echo(wshell.RegRead("HKCR\\MSWinsock.Winsock\\CLSID\\"));
// {248DD896-BB45-11CF-9ABC-0080C7E7B78D}
WScript.Echo(wshell.RegRead("HKCR\\CLSID\\{248DD896-BB45-11CF-9ABC-0080C7E7B78D}\\VersionIndependentProgID\\"));
// MSWinsock.Winsock

なんでやねん!!!

ZIGOROuZIGOROu2007/11/03 04:15RegSrvc.Registry

ZIGOROuZIGOROu2007/11/03 04:29COMAdmin.COMAdminCatalog

ZIGOROuZIGOROu2007/11/03 04:32TxCTx.TransactionContextEx

ZIGOROuZIGOROu2007/11/03 04:47COMSVCSLibがあつそうだ

ZIGOROuZIGOROu2007/11/03 04:49COMCRFLibはパーサー用っぽぃな

ZIGOROuZIGOROu2007/11/03 04:51COMEXPSLibはメニューとかかな

2007-10-31歯が痛い

Scripting.Dictionaryを使って配列のunique化

| 02:48 |  Scripting.Dictionaryを使って配列のunique化 - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  Scripting.Dictionaryを使って配列のunique化 - Ci.nsIZIGOROu

と言うのを思いついた。

function unique(arr) {
  var dic = new ActiveXObject("Scripting.Dictionary");
  for (var i = 0, l = arr.length; i < l; i++) {
    if (!dic.Exists(arr[i])) {
      dic.Add(arr[i], 1);
    }
  }
  return new VBArray(dic.Keys()).toArray();
}

動作未確認だけど多分いけるはず。

ブラウザでも多分動く。

見事に動いた。オブジェクトでも大丈夫っぽぃ

amachangamachang2007/11/01 11:10mjd!!!

ZIGOROuZIGOROu2007/11/01 13:57mjdy

TurgutTurgut2012/09/28 19:53Cool! That's a clever way of loiokng at it!

nvzrukwcpnvzrukwcp2012/09/29 05:34bIJioN <a href="http://wuycwglojouk.com/">wuycwglojouk</a>

xnraegrkkzmxnraegrkkzm2012/09/30 01:23Qvo13X , [url=http://nqdqbukxjixj.com/]nqdqbukxjixj[/url], [link=http://lspccjofrgmj.com/]lspccjofrgmj[/link], http://fphzywlggdgu.com/

akxypzwakxypzw2012/09/30 11:44KGTQYH <a href="http://gbqzitkauedx.com/">gbqzitkauedx</a>

zxgdffzxgdff2012/10/02 03:04gU0Fv1 , [url=http://orutonljcxjs.com/]orutonljcxjs[/url], [link=http://ewbrjnuurbxk.com/]ewbrjnuurbxk[/link], http://exfrdbgkvwnu.com/