Hatena::Groupmoz-addon

Ci.nsIZIGOROu

2007-10-17うーむ

TLI.TLIApplication (2)

| 04:51 |  TLI.TLIApplication (2) - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  TLI.TLIApplication (2) - Ci.nsIZIGOROu

もうすぐ寝るけど、ちょっとやっちゃったから少しだけ。

明日追記する。

定数の列挙

TypeLibにひもづく定数はWSFの<reference>要素でGlobalオブジェクトにまるっとコピーされるんだけども、大規模なWSHを使ったアプリを作る場合はどうしても不向き。

と言う訳でやっぱり定数の列挙したいなーと。


TypeLib Information Library*1に注目してる一番大きな要因が定数なんですよね。

手順としては、

  1. InterfaceInfo.Parent (TypeLibInfoインターフェースを実装したオブジェクト)
    1. TypeLibInfo.Constants (Constantsインターフェースを実装したオブジェクト)
      1. Constants.Count (Enumの数)
      2. Constants.Item(i) (ConstantInfoインターフェースを実装したオブジェクト、定数グループを表す)
        1. ConstantInfo.Count (定数の数)
        2. ConstantInfo.Item(i) (Constant)
          1. Constant.Members.Count (Memberの数)
          2. Constant.Members.Item(i) (MemberInfoインターフェースを実装したオブジェクト)
            1. MemberInfo.Name (定数名)
            2. MemberInfo.Value (定数値)

って感じで取れる

WScript.Echo(iinfo.Parent.Constants.Item(1).Members.Item(1).Name);                                                                                    
// tliErrNoCurrentTypelib
WScript.Echo(iinfo.Parent.Constants.Item(1).Members.Item(1).Value);                  
// -2147220991

MemberInfoは今回は定数を表現してたけど、それがメソッドだったり色々する訳です。


TLI.TLIApplication (1)

| 03:15 |  TLI.TLIApplication (1) - Ci.nsIZIGOROu を含むブックマーク はてなブックマーク -  TLI.TLIApplication (1) - Ci.nsIZIGOROu

これはシリーズ連載予定。

ちなみにTLI.TLIApplicationは今だとVisual Studio ExpressionVisual Studio 2005 Express Edition*2をインストールすると入ってる。

追記1 (2007-10-19T14:35:13+09:00)

えーと、Visual Studio 2005 Express Editionのことだと思われ、 Expression Studio (Design/Blend/...)は別の製品で、ちょと恥ずかしくて まぎらわしい間違いなので、訂正した方がよいかもです...。

OutlookとOutlook Expressの関係と同じと考えると忘れにくいかもしれませ ん...。

と同僚のkaorunさんから突っ込まれたので直しました。

間違いを突っ込まれたら素直に直すのが最近の良い子の例です。(w

kaorunさん、ありがとうございました。

オブジェクトのインターフェースの実装状況を調べる

var ctrl = WScript.CreateObject("ScriptControl");
ctrl.Language = "VBScript";
ctrl.AddCode("Function xTypeName(x): xTypeName = TypeName(x): End Function");
var TypeName = function(x) { return ctrl.Run("xTypeName", x); };

var tliapp = WScript.CreateObject("TLI.TLIApplication");
WScript.Echo(TypeName(tliapp)); // TLIApplication
var iinfo = tliapp.InterfaceInfoFromObject(tliapp);
WScript.Echo(TypeName(iinfo)); // InterfaceInfo
WScript.Echo(iinfo.Name); // _TLIApplication
WScript.Echo(iinfo.GUID); // {8B21775D-717D-11CE-AB5B-D41203C10000}
WScript.Echo(iinfo.ImpliedInterfaces.Count); // 1 つまり直接implementsしてるinterfaceが1個

// iinfo.ImpliedInterfaces.Item(1)は再びInterfaceInfoが返って来る。

WScript.Echo(iinfo.ImpliedInterfaces.Item(1).Name); // IDispatch
WScript.Echo(iinfo.ImpliedInterfaces.Item(1).ImpliedInterfaces.Count); // 1 まぁ当たり前

WScript.Echo(iinfo.ImpliedInterfaces.Item(1).ImpliedInterfaces.Item(1).Name); // IUnknown

と言う訳で、

  1. InterfaceInfo.Name
  2. InterfaceInfo.ImpliedInterfaces.Count() > 0
  3. InterfaceInfo.ImpliedInterfaces.Item(i) [1 <= i <= Count]

を再帰的にやれば良い。

って事で特定のInterfaceを実装しているかどうかは、次のようなコードで問題ない。

var tliapp = WScript.CreateObject("TLI.TLIApplication");

function isImplemented(obj, iface) {
  try {
    // WScript.Echo("TypeName: " + TypeName(obj));
    var iinfo = tliapp.InterfaceInfoFromObject(obj);
  }
  catch (e) { // リテラルとかを突っ込むとエラー発生
    return false;
  }

  return (function (iinfo, iface) {
    // WScript.Echo("iinfo: " + iinfo.Name + ", iface: " + iface);

    if (iinfo.Name == iface) {
      return true;
    }

    if (iinfo.ImpliedInterfaces.Count > 0) {
      var i;
      var cnt = iinfo.ImpliedInterfaces.Count;

      for (i = 1; i <= cnt; i++) {
        if (arguments.callee(iinfo.ImpliedInterfaces.Item(i), iface)) {
          return true;
        }
      }

      return false;
    }
    else {
      return false;
    }
  })(iinfo, iface);
}

VBScriptのTypeNameの結果とInterface名 (追記1: 2007-10-18T03:26:22+09:00)

概ね同じような値が返って来る。さっきのisImplementedのデバッグ出力のコメントアウト部分を外して、IUnknownと色々比較してみる。

Object
isImplemented({}, "IUnknown");                                                                                                         
// TypeName: JScriptTypeInfo
// iinfo: JScriptTypeInfo, iface: IUnknown
// iinfo: IDispatch, iface: IUnknown
// iinfo: IUnknown, iface: IUnknown
TLI.TLIApplication
isImplemented(tliapp, "IUnknown");                                                                                                     
// TypeName: TLIApplication
// iinfo: _TLIApplication, iface: IUnknown
// iinfo: IDispatch, iface: IUnknown
// iinfo: IUnknown, iface: IUnknown
ScriptControl
var ctrl = WScript.CreateObject("ScriptControl");

isImplemented(ctrl, "IUnknown");                                                                                                       
// TypeName: ScriptControl
// iinfo: IScriptControl, iface: IUnknown
// iinfo: IDispatch, iface: IUnknown
// iinfo: IUnknown, iface: IUnknown
Scripting.FileSystemObject
var fso = new ActiveXObject("Scripting.FileSystemObject");

isImplemented(fso, "IUnknown");                                                                                                        
// TypeName: FileSystemObject
// iinfo: IFileSystem3, iface: IUnknown
// iinfo: IDispatch, iface: IUnknown
// iinfo: IUnknown, iface: IUnknow

なるほどねぇ。

作ったオブジェクトが含まれるTypeLibをOLEViewから探す時 (追記2: 2007-10-18T03:43:02+09:00)

InterfaceInfo.Parent.HelpStringがOLEViewのTypeLibの見出しと大体一致してるみたい。

function getTypeLibName(progID) { 
  return tliapp.InterfaceInfoFromObject(new ActiveXObject(progID)).Parent.HelpString;
}

のようにしておいて、

getTypeLibName("InternetExplorer.Application");                                                                                        
// Microsoft Internet Controls
getTypeLibName("MSXML");                                                                                                               
// Microsoft XML, v3.0
getTypeLibName("ScriptControl");                                                                                                       
// Microsoft Script Control 1.0
getTypeLibName("Scripting.FileSystemObject");                                                                                          
// Microsoft Scripting Runtime
getTypeLibName("TLI.TLIApplication");
// TypeLib Information
getTypeLibName("MSWinsock.Winsock");                                                                                                   
Microsoft Winsock Control 6.0 (SP6)

まぁ、ActiveXObject作っちゃうのがアレげですけどw

*1:このTLI.TLIApplicationの事ね。

*2:なんか無料版の奴ね

MugMug2007/10/21 00:23すみません、返信が遅れました。(最近ブログ更新サボっていて、前向きなコメントを頂くとは想定外でした…)
私の場合は、ECMAScript(JavaScript,JScript)のコードをライブラリ化してまとめてインクルードでき、かつ多段(プロトタイプ)継承とプライベートメンバ・メソッドな「クラス(ユーザー定義オブジェクト)」を作る。
また、ライブラリ化の方針としては、ECMAScript準拠の部分と環境依存部分を別"クラス"や別"パッケージ"または"サブクラス"に分けて、なるだけ様々な環境で動作できるようにしています。
WSHでもそれらは動くのですが、せっかくスクリプト言語なのでCUIの対話形式での実行環境を作ってみましたのです。
(似てるのかな…?)スミマセン今はとりあえず返信させて頂こうかと思いましたので、後々内容を読ませていただきますね。

ZIGOROuZIGOROu2007/10/21 05:17おお、コメントありがとうございます。

> ライブラリ化してまとめてインクルードでき

この辺りは僕はScriptControlでやろうと思っています。
ただScriptControlはまだ挙動がいまいちわかってない部分があるんですよねぇ。

> かつ多段(プロトタイプ)継承

これはちょっとこの言葉だけだと想像出来ないかも。。。

僕も対話形式のConsoleは作ってるんですけど、まだライブラリ化の方針まで固まってません。ScriptXは使おうと思ってますけど。

MugMug2007/10/22 21:40いろいろとActiveXとか使ってますねー。いったいどこで仕様とか調べるのでしょう…??
後々参考にさせていただくかも知れません。

>> かつ多段(プロトタイプ)継承
JAVAなんかはクラスベースの継承だけれど、ECMAScriptはプロトタイプベースの継承ですよね。ただ、関数を使ったユーザー定義オブジェクトの場合、継承のシステムはユーザーが用意しなければならないはずです。
私の場合は、クラスライクな継承を何段も(サブクラスのサブクラスのサブクラスの…)できるようにしたのでこのように書かせていただきました。ただし、やはり多重継承はできませんでした。その代わり、"クラス"に1つ(static)なプロパティも継承させることにしました。

こっそり、こんなことやってます。

ZIGOROuZIGOROu2007/10/23 22:00> いろいろとActiveXとか使ってますねー。いったいどこで仕様とか調べるのでしょう…??

どこだろ、、、OleViewとかですかね?w
http://del.icio.us/zigorou でその手のブクマが流れてると思います。

で、継承云々の話ですけど、そもそも継承を積極的に使うべきかって辺りでJavaScriptのprototypeベースはそこまで要らない気がするんですよねぇ。

基本は普通にprototypeにベースとなる"オブジェクト"を突っ込んであげるだけで事足りると僕は考えていて、それ以上に拡張したいならmixinすればいいと考えてます。

型チェックってよりメソッド名で実装してるかしてないかみたいな。

takuya_1sttakuya_1st2007/10/29 12:00私のコードで使えるものがあればぜひ

ZIGOROuZIGOROu2007/10/31 00:58> id:takuya_1stさん
そう仰って頂けるのは恐縮です><