Hatena::Groupmoz-addon

Ci.nsIZIGOROu

2008-02-07

JScriptのGlobalObj#CollectGarbage()メソッドで強制GC

| 00:50 |  JScriptのGlobalObj#CollectGarbage()メソッドで強制GC - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  JScriptのGlobalObj#CollectGarbage()メソッドで強制GC - Ci.nsIZIGOROu

前々からこのメソッドがあるのは知ってたんだけど、最近気になる記事を見かけたので実際に試してみた。

CollectGarbage()メソッドとは

SYSTEM32\jscript.dllをOLEViewで見ると分かるけど、Dispinterface GlobalObjで次のように定義されている。

[id(0x00000019)]
VARIANT CollectGarbage();

まぁ名前からしてどう見てもGCするぜって主張してる訳です、はい。

*1

で気になったフレーズ

CollectGarbageを使用してオブジェクトを強制的に破棄するためには 関数外で CollectGarbageを呼び出されければならないっぽい。 OfficeのActiveXだけかわからないが・・・ JScriptのCollectGarbage

そうなんだ、じゃあ試しにやってみよう。

共にタスクマネージャでcscript.exeのプロセスを監視(目視?)する事にします。

テスト1
for (var i = 0; i < 1000; i++) {
  (function() {
    var arr = [];
    for (var j = 0; j < 10000; j++)
      arr.push(j);

    WScript.StdOut.Write(".");
    WScript.Sleep(1000);
  })();

  WScript.Sleep(2000);
}
テスト2
for (var i = 0; i < 1000; i++) {
  (function() {
    var arr = [];
    for (var j = 0; j < 10000; j++)
      arr.push(j);

    WScript.StdOut.Write(".");
    WScript.Sleep(1000);
  })();

  this.CollectGarbage(); // ここがポイント
  WScript.Sleep(2000);
}
テスト3
for (var i = 0; i < 1000; i++) {
  (function() {
    var arr = [];
    for (var j = 0; j < 10000; j++)
      arr.push(j);

    WScript.StdOut.Write(".");
    WScript.Sleep(1000);
    this.CollectGarbage();
    WScript.Sleep(2000);
  })();
}
結果

テスト1は僕の環境ではだいたい6.7KB位でメモリ使用量が一定になった。

一方でテスト2は6.7KBと6.2KBで交互にメモリ使用量が表示される。

テスト3ではまだスコープを抜けてないからGCのしようが無いと思われ、テスト1と同じ結果となった。

おお、これは効果あるんじゃないすか?

ちなみに

WSHでは自分自身のプロセスIDが取りづらい*2ので、WMIを使ってプロセス特定しつつ使用メモリをプロットとかやりたかったんだけど、それは断念した。暇な時にきちんと追試したいと思う。

自分自身のプロセスIDが欲しい人は、MS系のScriptingの神である吉岡 照雄さんの作品のGetPID.VBSを参考にすると良いでしょう。

概略を言えば、

  • WshControllerでmshta等の「見えない」プロセスを作る
  • WMIからWin32_Processをmshtaのプロセスを条件としてselectする
  • 取れたレコードから親プロセスIDを取る→これが現在実行中のWSHのプロセスID

って手順になります。

うへぇー、めんどくさいw


WSHで無い機能を作る際って、WebBrowser Control立ち上げて機能の一部を拝借したりとか、今の例とか結構なりふり構わぬ実装が沢山あって色んな意味で面白い。

*1:関係ないけど、末尾に「はい」をつけて、amachangがdankogaiの真似をしてたけど、割と似てた

*2:相当トリッキーな仕組み

2008-01-13

KenelmKenelm2011/08/07 02:46Going to put this arctile to good use now.

vqinaxvxxvqinaxvxx2011/08/07 20:377cAcdf <a href="http://anuskuqjdqox.com/">anuskuqjdqox</a>

ftxjxvbiruyftxjxvbiruy2011/08/10 19:22WNbFZc <a href="http://nubbiomyulkb.com/">nubbiomyulkb</a>

rhwofaktyhrhwofaktyh2011/08/13 01:20kf1zYz , [url=http://piebgmllssdn.com/]piebgmllssdn[/url], [link=http://xnlowinfljwh.com/]xnlowinfljwh[/link], http://xvcupztstnur.com/

2007-12-06

Microsoft SOAP Toolkitを使ってJScriptでSOAP - 低レベルAPI (1) SoapConnector, SoapReader

| 19:48 |  Microsoft SOAP Toolkitを使ってJScriptでSOAP - 低レベルAPI (1) SoapConnector, SoapReader - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  Microsoft SOAP Toolkitを使ってJScriptでSOAP - 低レベルAPI (1) SoapConnector, SoapReader - Ci.nsIZIGOROu

低レベルAPIを使ったクライアント作成の流れ

低レベルAPIを使って自前でSoap Clientになりたい場合の流れは。

  1. HttpConnectorでInput/Outputストリームを準備する
    1. EndPointURLを明示的に指定
    2. SoapActionも明示的に指定
  2. HttpConnector.BeginMessage()
  3. SoapSerializerでリクエストデータを作る
    1. 最初にHttpConnector.InputStreamでSerializerを初期化
    2. 構造体は配列も自分で頑張って作らなきゃいけない *1
  4. HttpConnector.EndMessage() - この時点でリクエスト完了
  5. HttpConnector.OutputStreamでSoapReader.Init()する
  6. レスポンスデータはDOMで何とかする

って流れになる。

サンプル

var soapConnector = new ActiveXObject("MSSOAP.HttpConnector");
var soapSerializer = new ActiveXObject("MSSOAP.SoapSerializer");
var soapReader = new ActiveXObject("MSSOAP.SoapReader");

soapConnector.Property("EndPointURL") = "http://btonic.est.co.jp/Netdic/Netdicv10.asmx";
soapConnector.Property("SoapAction") = "http://btonic.est.co.jp/NetDic/NetDicV09/GetDicList";
soapConnector.Property("ProxyServer") = "localhost";
soapConnector.Property("ProxyPort") = 8000;

soapConnector.BeginMessage();
soapSerializer.Init(soapConnector.InputStream);

soapSerializer.startEnvelope("", "STANDARD");
soapSerializer.startBody();
soapSerializer.startElement("GetDicList", "http://schemas.xmlsoap.org/soap/envelope/", "", "SOAPSDK1");
soapSerializer.startElement("AuthTicket");
soapSerializer.endElement();
soapSerializer.endElement();
soapSerializer.endBody();
soapSerializer.endEnvelope();

soapConnector.EndMessage();

soapReader.Load(soapConnector.OutputStream);

var stream = new ActiveXObject("ADODB.Stream");
stream.Type = 2;
stream.Charset = "UTF-8";

stream.Open();
stream.WriteText(soapReader.DOM.xml);
stream.SaveToFile("result.xml");
stream.Close();

ADODB.StreamのSaveToFileは既にファイルが存在すると作ってくれないので、適宜消す事w

あと結果が見づらい場合はcygwinユーザーならば、

$ xmllint --noent --format result.xml

みたいにする。

これでとりあえずリクエストとレスポンスを低レベルで行う事は出来た。

まとめ

どう考えてもWSDL見て良しなにやってくれるwrapperが欲しい。

が作る気はしないw

*1:激しく面倒ww

smellmansmellman2007/12/07 20:58meadow付属のtelnetを勧めてる俺ってマニアックだよね><

ZIGOROuZIGOROu2007/12/09 01:17んなこたーないですw
ってありましたね、そういうの。

Emacs連携もあるですよ>mozrepl

2007-12-05本日3回目のアレですよ

Microsoft SOAP Toolkitを使ってJScriptでSOAP - 低レベルAPI (1) SoapSerializer

| 16:12 |  Microsoft SOAP Toolkitを使ってJScriptでSOAP -  低レベルAPI (1) SoapSerializer - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  Microsoft SOAP Toolkitを使ってJScriptでSOAP -  低レベルAPI (1) SoapSerializer - Ci.nsIZIGOROu

やっとここまで辿り付けた。。。

複合型を使う場合はどうしても低レベルAPIを使わなくてはならないので、その際リクエストデータを作る際に使うSoapSerializerの練習をしたかったのでした。

SoapSerializerはInit()メソッドでIStreamを実装したオブジェクトが必要で、通常SoapConnectorオブジェクトを使うんですが、ここでは単にどういうXMLを生成しているか確認する為にADODB.Streamを使います。

var soapSerializer = new ActiveXObject("MSSOAP.SoapSerializer");

var stream = new ActiveXObject("ADODB.Stream");
stream.Charset = "UTF-8";
stream.Open();

soapSerializer.Init(stream);
soapSerializer.startEnvelope("", "STANDARD");
soapSerializer.startBody();
soapSerializer.startElement("WS_Square_root", "http://www.kanetaka.net/namespace/default", "", "SOAPSDK1");
soapSerializer.startElement("MyInput", "", "", "");
soapSerializer.writeString(3);
soapSerializer.endElement();
soapSerializer.endElement();
soapSerializer.endBody();
soapSerializer.endEnvelope();
stream.Position = 0

WScript.Echo(stream.ReadText(-1));

出力結果は、

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>
    <SOAPSDK1:WS_Square_root xmlns:SOAPSDK1="http://www.kanetaka.net/namespace/default" SOAP-ENV:encodingStyle="">
      <MyInput SOAP-ENV:encodingStyle="">3</MyInput>
    </SOAPSDK1:WS_Square_root>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

なるほど。

とりあえず今日はここまで。

追記

  • 一部間違えてたので、ソースコード修正。 (2007-12-06T16:17:23+09:00)

ADODB.Streamを使った文字コードの取り扱い (2)

| 18:48 |  ADODB.Streamを使った文字コードの取り扱い (2) - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  ADODB.Streamを使った文字コードの取り扱い (2) - Ci.nsIZIGOROu

で次は文字コード変換。

これは簡単で、二つストリームを用意して、変換元文字コード、変換先文字コードをそれぞれ指定してから、CopyTo()メソッドで移せばOK。

var sjisStream = new ActiveXObject("ADODB.Stream");
var utf8Stream = new ActiveXObject("ADODB.Stream");

sjisStream.Charset = "Shift_JIS";
utf8Stream.Charset = "UTF-8";

sjisStream.Open();
sjisStream.LoadFromFile("C:\\path\\to\\sjis.txt");

utf8Stream.Open();
sjisStream.CopyTo(utf8Stream);
sjisStream.Close();

utf8Stream.SaveToFile("C:\\path\\to\\utf8.txt");
utf8Stream.Close();

こんな感じ。


ADODB.Streamを使った文字コードの取り扱い (1)

| 18:41 |  ADODB.Streamを使った文字コードの取り扱い (1) - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  ADODB.Streamを使った文字コードの取り扱い (1) - Ci.nsIZIGOROu

先人が激しく既出してる訳ですが、まだ未経験なので一からやる。

まず適当なディレクトリにutf-8, shift_jisなファイルをそれぞれ用意しておく。

utf-8なファイルはBOMはつけない事。

Shift_JIS, UTF-8なファイルをそれぞれCharsetを指定して読み込み標準出力へ書き込む

var s1 = new ActiveXObject("ADODB.Stream");
var s2 = new ActiveXObject("ADODB.Stream");

s1.Charset = "UTF-8";
s2.Charset = "Shift_JIS"

s1.Open();
s1.LoadFromFile("C:\\path\\to\\utf8.txt");
WScript.Echo(s1.ReadText(-1));
s1.Close();

s2.Open();
s2.LoadFromFile("C:\\path\\to\\sjis.txt");
WScript.Echo(s2.ReadText(-1));
s2.Close();

こんな感じでOK。

元の文字コードが何であれ、正しい文字コードで読み込んだ場合はWSHの場合はShift_JISで動作してるけど問題なく出力できる。

誤ったCharsetで読み込み標準出力に書き込む

var s1 = new ActiveXObject("ADODB.Stream");

s1.Charset = "UTF-8";

s1.Open();
s1.LoadFromFile("C:\\path\\to\\sjis.txt");
WScript.Echo(s1.ReadText(-1));
s1.Close();

これは何も出力されない。文字コード指定が間違えているから。


Microsoft SOAP Toolkitを使ってJScriptでSOAP - 基本編

| 16:14 |  Microsoft SOAP Toolkitを使ってJScriptでSOAP - 基本編 - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  Microsoft SOAP Toolkitを使ってJScriptでSOAP - 基本編 - Ci.nsIZIGOROu

ちょっとやりたい事があったから調べてみたよ。

ちなみにProgIDでMSSOAP.SoapClientとかがもし入ってない環境だったら、

からSDKをダウンロードしてインストールして下さい。

準備

とりあえず通信内容も見たいので、以下のようなPerlプログラムを作っておきました。

どんな物かはソース見て各自把握しよう。(ぇ

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dump qw(dump);
use HTTP::Proxy;
use HTTP::Proxy::BodyFilter::simple;

my $proxy = HTTP::Proxy->new(port => 1981);

my $body_filter = HTTP::Proxy::BodyFilter::simple->new(
    filter => sub {
        my ($self, $dataref, $message, $protocol, $buffer) = @_;

        print STDERR dump({
            data => $$dataref,
            message => $message,
            protocol => $protocol,
            buffer => $buffer
        });
    }
);

$proxy->push_filter(request => $body_filter, response => $body_filter);

$proxy->start;

これでよしなに本文はリクエスト・レスポンス共にdumpしてくれます。

今回試して見るサービス

にあるWSH版の奴を試す。

var soapClient = new ActiveXObject("MSSOAP.SoapClient");
// WSDLファイルで初期化する
soapClient.mssoapinit("http://ws.kanetaka.net/4dwsdl");
soapClient.ConnectorProperty("ProxyServer") = "localhost";
soapClient.ConnectorProperty("ProxyPort") = 1981; // 今、流行の年代らしいですw

WScript.Echo(soapClient.WS_Square_root(3));

事前にproxyサーバーを立ち上げておこう。

通信内容

リクエスト
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>
    <SOAPSDK1:WS_Square_root xmlns:SOAPSDK1="http://www.kanetaka.net/namespace/default">
      <MyInput>3</MyInput>
    </SOAPSDK1:WS_Square_root>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
レスポンス
<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <SOAP-ENV:Body>
    <ns1:WS_Square_rootResponse xmlns:ns1="http://www.kanetaka.net/namespace/default" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <Result xsi:type="xsd:float">1.73205080756887</Result>
    </ns1:WS_Square_rootResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

まとめ

とりあえず複合型が送受信データに含まれなければSoapClientだけで凄い簡単に出来る。

次回は複合型の場合について考える予定。

参考

RodriguezRodriguez2012/09/28 17:27That's not even 10 mnitues well spent!

mfojlkmfojlk2012/09/30 01:111vBeq3 , [url=http://uetxqsgbcept.com/]uetxqsgbcept[/url], [link=http://rrpikmmoyapg.com/]rrpikmmoyapg[/link], http://fdkbadzfioma.com/

mqrdvonxwkfmqrdvonxwkf2012/09/30 11:345z9xtm <a href="http://isztxmrmkykw.com/">isztxmrmkykw</a>

ysvqtuzfysvqtuzf2012/10/02 02:52jxjtOm , [url=http://yprzkgwjuvdg.com/]yprzkgwjuvdg[/url], [link=http://glnqmogpaeqw.com/]glnqmogpaeqw[/link], http://ahmjujlffyqc.com/

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オブジェクトとそれを呼び出すイベント関数の両方が定義されてるのが分かる。