RegisterComDllメソッドを題材としていますが、一般的にリフレクションを使って動的にメソッドを呼び出す方法についての話と考えられます。

話の前に、RegisterComDllメソッドについて知りたい方はこちらを参照してください: ソース [Chris Walsh] via ソース [WMpoweruser] via ソース [ななふぉ]

さて本題、RegisterComDllでもなんでも良いのですが、その動的なメソッド呼び出しのコード、なんかいけてないと思うのです。

1
2
3
4
5
6
7
8
Assembly a = Assembly.Load(
  "Microsoft.Phone.InteropServices, Version=7.0.0.0, Culture=neutral, PublicKeyToken=24eec0d8c86cda1e");
Type comBridgeType = a.GetType(
  "Microsoft.Phone.InteropServices.ComBridge");
MethodInfo dynMethod = comBridgeType.GetMethod(
  "RegisterComDll", BindingFlags.Public | BindingFlags.Static);
dynMethod.Invoke(null,
  new object[] { "Assembly.dll", new Guid("SomeGuidHere") });

とりあえず、var使いましょう。少しはマシになりました。

1
2
3
4
5
6
7
8
var a = Assembly.Load(
  "Microsoft.Phone.InteropServices, Version=7.0.0.0, Culture=neutral, PublicKeyToken=24eec0d8c86cda1e");
var comBridgeType = a.GetType(
  "Microsoft.Phone.InteropServices.ComBridge");
var dynMethod = comBridgeType.GetMethod(
  "RegisterComDll", BindingFlags.Public | BindingFlags.Static);
dynMethod.Invoke(null,
  new object[] { "Assembly.dll", new Guid("SomeGuidHere") });

さて、メソッド呼出をデリゲート経由にしてやろうかと考えていたところ、Delegate.CreateDelegateにちょうどよいオーバーロードを見つけました。型名とメソッド名(文字列)を渡すとそいつを呼び出すデリゲートを作るというものです。Delegate.CreateDelegateはMethodInfoを渡すものばかりと思っていたら、文字列でメソッドを指定できるものがあったというわけです。

採用しました。

1
2
3
4
5
6
var a = Assembly.Load(
  "Microsoft.Phone.InteropServices, Version=7.0.0.0, Culture=neutral, PublicKeyToken=24eec0d8c86cda1e");
var comBridgeType = a.GetType(
  "Microsoft.Phone.InteropServices.ComBridge");
var registerComDll = (Func<string, Guid, uint>)Delegate.CreateDelegate(
  typeof(Func<string, Guid, uint>), comBridgeType, "RegisterComDll");

あとは、Delegate.CreateDelegateのところで、引数・戻り値のキャストの2度Func<…>を書かなければならないことをジェネリックでなんとかしてやるのもよいでしょう。

以下余談、戻り値がuintなのはごにょごにょして覗いてみたり、あるいは、dynMethod.Invokeの戻り値(object型)をデバッガで見たりした結果からです。そして、この値はいかにもHRESULTっぽい値です。となれば、当然Marshal.ThrowExceptionForHRを使おうと考えるわけです。

1
2
3
4
5
var ret = registerComDll(dllName, clsid);
if (ret >= 0x80000000)
{
    Marshal.ThrowExceptionForHR(unchecked((int)ret));
}

しかし、これはできませんでした。ThrowExceptionForHRメソッドには、SecurityCriticalAttributeが付いているので我々アプリ開発者の手には扱えないのです。Marshal.GetExceptionForHRも同様に駄目です。適当な例外クラスを作り、ret.ToString(“x”)を使ってメッセージ文字列を作るという程度でお茶を濁すしかないでしょう。


スポンサード リンク

この記事のカテゴリ

  • ⇒ RegisterComDllの呼び出し方を考える
  • ⇒ RegisterComDllの呼び出し方を考える