1. ホーム
  2. スクリプト・コラム
  3. vbs

VBSテクノロジーインサイダー。CreateObject関数の説明

2022-02-08 20:45:18

CreateObject関数で異なる文字列を渡すと、さまざまな強力なオブジェクトを作成できることが理解できなかった。そこで、UMUの「[UMU WSH チュートリアル](9) CreateObject プロセス」に出会い、CreateObject 関数が COM オブジェクトを作成し、第一引数が COM オブジェクトの ProgID であることに気がつきました。 プレーンなC言語でのCOM

で、プレーンCでCOMコンポーネントを書く方法を学びました。

COM(Component Object Model)は、レンガのように分厚い本が必要なほど複雑な概念で、C++やオブジェクト指向プログラミングの素養がないと理解するのは困難です。

もちろん、VBSerとしては、COMの原理や本質を理解する必要はない。ProgIDは、開発者がCOMオブジェクトにつける名前と考えることができ、CreateObject関数にCOMオブジェクトの名前を渡して、オブジェクトを作成することを伝えます。CreateObject 関数は、このオブジェクトへのポインタを返します。

例えば、VBでCOMコンポーネントを書いて、demon.twという名前をつけて、そのCOMコンポーネントを登録した後、CreateObject関数を使って作成することができます(もちろん、あなたもできますね)。

Set blog = CreateObject("demon.tw")
blog.Open 'Assuming my COM object implements the Open method

FileSystemObject、WScript.Shell、ADODB.Streamなどは、マイクロソフトが開発したシステムに付属するCOMオブジェクトの名前に過ぎません。

では、CreateObject関数はどのようにオブジェクトを生成するのでしょうか。OllyDbgで追っていくと、コアとなるコードはおおよそ4つのステップに分けることができる。

まず、CLSIDFromProgIDExを呼び出して、ProgIDから対応するCLSIDを取得します。もし対応するCLSIDが見つからない場合は、エラー "ActiveX part cannot create object" が報告されます。

例えば、WScript.ShellのCLSIDを取得するには、レジストリエディタを使用してHKEY_CLASSES_ROOT\WScript.ShellのCLSIDの値を見つけます。なお、[UMU WSH Tutorial](9) CreateObjectプロシージャでは、次のように記述されています。

1. CreateObject関数は、まずレジストリのHKEY_CLASSES_ROOTWScript.Shellの下にあるサブキーCurVerのデフォルト値をチェックし、その結果がWScript.Shell.1なので、最新バージョンはWScript.Shell.1であると認識します。

HKEY_CLASSES_ROOTWScript.Shell.1を読むと、その下にCLSIDというサブキーがあり、デフォルト値は{72C24DD5-D70A-438B-8A42-98424B88AFB8}であることがわかります。

これは間違いです。CreateObject関数(正確にはCLSIDFromProgIDEx関数の内部呼び出し)はまずレジストリのサブキーHKEY_CLASSES_ROOTWScript.ShellCLSIDが存在するかどうかをチェックし、サブキーさえ存在すれば、デフォルト値が空でもクラス識別子でなくても、もはやCLSIDサブキーが存在しない場合だけサブキーCurVerをチェックするのです。

次に、CoGetClassObject関数を呼び出して、IClassFactoryインターフェイスへのポインタを取得します。もし、取得できない場合は、エラー "ActiveX part cannot create object" または "Class does not support Automation operations "、あるいは、COM実装によっては、他のエラーメッセージが表示される可能性があります。

3番目のステップでは、IClassFactoryインターフェースのCreateInstanceメソッドを呼び出し、IUnknownインターフェースへのポインタを取得します。すべてのCOMはIUnknownインターフェイスをサポートしなければならないので、このステップでエラーが発生することはないはずです。

最後に、IUnknown インターフェースの QueryInterface メソッドを呼び出して、COM が IDispatch インターフェースをサポートしているかどうかを確認します。IDispatchインターフェースへのポインターを取得した場合は、VARIANT変数に値を代入できます。IDispatchインターフェースがサポートされていない場合は、エラー "Class does not support Automation operations" が発生し、実装によっては、他のエラーメッセージが発生する場合もあります。

VBSはどのオブジェクトを呼び出すことができるのか?あるいは、CreateObject関数の第1引数としてどの文字列を使用できるのでしょうか?この質問に対する答えは次回に。

VBSはCreateObject関数に飛び込む

今回は、COMの一部であるオブジェクト作成についてお話しますので、ここで多くを語ることはできません。COM に関する本もいくつかありますし、COM に関する他の UMU の記事、 "The ATL Experience", "A Short Note on Researching New WebBrowser-Based Applications", "Reasons to Learn ATL", "Several Conceptual Issues About COM" "Several Conceptual Issues about COM (2)"も見てみて下さい。代表的なオブジェクトは、WScript.Shell、Scripting.FileSystemObject、Scripting.FileSystemObject、Scripting.FileSystemObjectです。


早速、オブジェクトの生成処理を見てみると、Set objWSH = CreateObject( "WScript.Shell" )という文がありますね。

1. CreateObject関数は、まずレジストリのHKEY_CLASSES_ROOTWScript.Shell下のサブキーCurVerのデフォルト値をチェックし、その結果がWScript.Shell.1なので、最新バージョンがWScriptであることがわかる。

HKEY_CLASSES_ROOTWScript.Shell.1を読むと、その下にCLSIDというサブキーがあり、デフォルト値は{72C24DD5-D70A-438B-8A42-98424B88AFB8}であることがわかります。

HKEY_CLASSES_ROOTCLSID{72C24DD5-D70A-438B-8A42-98424B88AFB8} のサブキーInProcServer32のデフォルト値は、サービスプログラムが C:\WINDOWSsystem32wshom.ocx であることを表しています。

4は、スクリプトのCOMオブジェクトを呼び出すことができます、メソッドTypeLibでオブジェクトを使用する必要があります、HKEY_CLASSES_ROOTCLSID。\ TypeLibの初期値は{F935DC20-1CF0- 11D0-ADB9-00C04FD58A0B}、HKEY_CLASSES_ROOTTypeLibの初期値は{F935DC20-1CF0- 11D0-ADB9-00C04FD58A0B}1.00win32 のタイプライブラリとしてC:¥WINDOWS¥wshom.ocx¥が使用されることを示します。

スクリプトコールをサポートするCOMオブジェクトは、必ずIDispatchインターフェースを実装する必要があります。C:㊧WINDOWSsystem32wshom.ocx の "Resources - TYPELIB" で、各オブジェクトの先頭にある7つの関数 QueryInterface, AddRef, Release, GetTypeInfoCount, GetTypeInfo, GetIDsOfNames, Invoke はIUnknownインターフェースで、前3つが関数になっていることが確認できます。PEファイル中のTYPELIBリソースは、*.idlソースファイルをコンパイルしたバイナリデータであり、デコンパイルで戻すことができる。例えば、eXeScope で C:\WINDOWSsystem32³³wshom.ocx を開き、 "Resources - TYPELIB" を見ると、各インターフェース関数のパラメータや戻り値の定義が表示されるようになっています。

このように、VB開発環境は、オブジェクトの中にどんな関数があるのかを把握しています。ですから、オブジェクトの名前はわかっても、その中にどんな関数があるのかがわからない場合は、上記の方法で取得することができます。

xuejinglanさんがUMUに2007年3月31日(土) 11:40に質問しました "システムにどんなオブジェクトが存在し、そのオブジェクトに対してどんな関数が呼ばれているかを知るには?

オブジェクトの登録情報には、HKEY_CLASSES_ROOTCLSIDの下にサブキーがある場合があります。ControlはActiveXコントロール、Programmableは自動化をサポート、InsertableはOLEドキュメントコンテナに埋め込むことができることを意味します。Programmableがあるということは、自動化をサポートしているということで、IDispatchインターフェースをサポートしているので、スクリプト言語から利用することができる。しかし、この方法は古く、コンポーネントクラスの属性の代わりに、Implemented Categoriesサブキーの下にあるGUIDという形式のサブキーが使われるようになった。例えば、HKEY_CLASSES_ROOTCLSID {72C24DD5-D70A-438B-8A42-98424B88AFB8}Implemented Categories {40FC6ED5-2438-11CF-A3DB-080036F12502} では HKEY_CLASSES_ROOT}Component Categories {40FC6ED5-2438-11CF-A3DB-080036F12502} で409 string value are Automation Objects, which means ".XXXXXXXXXXXXXXXXXXXZXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Automation Objects "です。

"オートメーションオブジェクト"を見つけるには、OLE/COMオブジェクトの登録情報を表示するためのVSツール oleview.exe を使用すると、以下のようなインターフェイスで表示できます。

少しめまいがする人もいるかもしれませんが、要約すると、コンポーネントクラス {40FC6ED5-2438-11CF-A3DB-080036F12502} のオブジェクトを使用することです。(Automation Objects) は、スクリプトから呼び出すことができるようにサポートされています。

この後の作成プロセスは、スクリプトで考えるべきものではありませんが、COMの学習に興味がある方は勉強しておいた方が良い仕組みです。タイトル VBSテクニカルインサイダー CreateObject関数
作者 デーモン
リンク http://demon.tw/reverse/vbscript-internal-createobject.html