#前回
その1 導入編
導入編ということで、とりあえず理屈は置いておいてCOMを使ってみる、
ということを行いました。
今回は、COMが「特定の言語に依存しない」という点に着目して、
いろんな言語でCOMを呼び出してみたいと思います。
やることは前回と同じ、IEの起動です。
PHP
<?php
$ie = new COM("InternetExplorer.Application");
$ie->Visible = true;
?>
これだけです。
呼び出し方はVBSとほぼ同じですね。
PHPではCOMクラスが予め用意されているので、追加のパッケージ等は必要ありません。
http://php.net/manual/ja/class.com.php
Python
import win32com.client
ie = win32com.client.Dispatch("InternetExplorer.Application")
ie.Visible = True
こちらもほぼ同じです。
しかし、COM呼び出し機能はデフォルトでは入っていないので、追加でインストールする必要があります。
https://sourceforge.net/projects/pywin32/
C#
using SHDocVw;
namespace ComTestByCSharp
{
class Program
{
static void Main(string[] args)
{
InternetExplorer ie = new InternetExplorer();
ie.Visible = true;
}
}
}
SHDDocVw名前空間のクラス、インターフェースを使用するために
参照に「Microsoft Internet Controls」を追加する必要があります。
参照マネージャ=>COM=>タイプライブラリから追加できます。
タイプライブラリについて、マイクロソフトのドキュメントでそれらしいものが
見つけられなかったのですが、いろいろなところをググッた結果、
要するにCOMのインターフェース定義が書かれているファイルのことのようです。
これを用いることで、COMで公開されているインターフェースを
呼び出し側の「型」として使用できるようになるわけですね。
VBS, PHP, Pythonの実装例では文字列からオブジェクトを生成しているので、
このあたりの仕組みが異なるようです。
VB.NET
Imports SHDocVw
Module Module1
Sub Main()
Dim ie As InternetExplorer = New InternetExplorer
ie.Visible = True
End Sub
End Module
C#の兄弟言語、VB.NETでも実装方法は変わりません。
C++
#include "stdafx.h"
#include <atlbase.h>
#include <exdisp.h>
#import "C:\WINDOWS\system32\shdocvw.dll"
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
{
IWebBrowser2Ptr ie;
CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (VOID**)&ie);
ie->put_Visible(VARIANT_TRUE);
}
CoUninitialize();
return 0;
}
#importディレクティブを使用してタイプライブラリを読み込んでいます。
https://msdn.microsoft.com/ja-jp/library/8etzzkb6.aspx
これにより、C#やVB.NETと同様、固有のクラスやインターフェースが使えるようになるわけですね。
しかし、C#やVB.NETと比べるとコードがやや複雑です。
まず、COMを利用する前にCOMの初期化、利用後におよび初期化解除が必要です。
(CoInitialize(), CoUninitialize())
IWebBrowser2PtrはIWebBrowserインターフェースのスマートポインタです。
IWebBrowserを直接使用するのではなく、スマートポインタを使うようです。
(使わなくてもできるようですが、未調査)
また、CoUninitialize()はCOMのオブジェクトが未開放の状態で実行するとエラーになるので、
ローカルスコープを一段掘ることで、
CoUninitialize()呼び出しの前にIWebBrowser2Ptrが解放されるようにしています。
CoCreateInstance()で実際のオブジェクトを生成するわけですが、引数が多いです。
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms686615(v=vs.85).aspx
rclsid => クラスのID
pUnkOuter => とりあえずNULLで問題ないようです(未調査)
dwClsContext => とりあえずCLSCTX_LOCAL_SERVERで問題ないようです(未調査)
riid => インターフェースのID
*ppv => 生成されるオブジェクト
(戻り値はHRESULT型になっているので、オブジェクトは参照渡しで取ってくるようになっているようです)
第二、第三引数についてはよくわかっていませんが、
今後余裕があったらちゃんと調査するかもしれません。
よくわかっていないところが多くなってきましたね。
C++で特にわからないところが多いのは、よりCOMっぽい実装になっているからかと推測しています。
(他の言語ではうまくラップしているので見えていない部分をきちんと実装しないといけない)
今回の目的は「とりあえず使えること」ですので、難しいところは一旦スルーします。
まとめ
実装方法にいくつかのパターンがありましたが、
様々な言語で実装できることを確認できました。
次回
その3 COMコンポーネント実装
次回は、これまで「呼ぶ側」に着目していましたが、
いよいよ「呼ばれる側」を作ってみたいと思います。