OperationTypeInfoとSystem.__ComObject
Friendlyのマニアックな機能にOperationTypeInfoというものがあります。
僕以外に知っている人は、世界に10人いないでしょうねw
OperationTypeInfo - 株式会社Codeer (コーディア)
例えば、こんなクラスを操作するとして、
class Parent { int data; } class Child : Parent { //同名の変数が存在する int data; //オーバーロードされた関数が存在する public void Test(Form form) { //...処理 } public void Test(Control control) { //...処理 } }
普通に書くと
//子供しか取れない int data = child.data; //例外発生 //どっちのメソッドか分からない child.Test(null);
で、これに対応するためにOperationTypeInfoがあります。操作時の型と引数の型を確定させるのです。Asyncと同じく、引数のどこかに混ぜてください。
あ、propertyとかfieldの場合も()つけて渡せばOKです。これもマニアックな話ですねw
//対象クラスを指定 int data = child.data(new OperationTypeInfo(typeof(Parent).FullName); //対象クラスと引数を指定 child.Test(new OperationTypeInfo(typeof(Parent).FullName, typeof(Form).FullName);
System.__ComObjectにも利用
対象プロセス内のオブジェクトを操作するときにCOMのオブジェクトが混ざっていることがあります。COMのオブジェクトは型が確定しているものもありますが、大部分はGetType()をするとSystem.__ComObjectというクラスが取得されます。Friendlyは対象プロセス内ではリフレクションを元に処理を実行するので、これでは本当に操作したい型が取れずにエラーになってしまいます。ココでもOperationTypeInfoが役に立ちます。
例えば、WebBrowserを使っているこんなFormがあって
using System.Windows.Forms; namespace ComTarget { public partial class MainForm : Form { public MainForm() { InitializeComponent(); var web = new WebBrowser(); web.Dock = DockStyle.Fill; Controls.Add(web); } } }
Friendlyで操作すると
var app = new WindowsAppFriend(Process.Start(Target.Path)); var web = app.Type().System.Windows.Forms.Application.OpenForms[0].Controls[0]; web.Url = new Uri("http://www.codeer.co.jp/"); while ((WebBrowserReadyState)web.ReadyState != WebBrowserReadyState.Complete) { Thread.Sleep(10); } var iframeWindow = web.Document.Window; //COMアクセス //IHTMLWindow2は操作できるが・・・ var iframeWindowCom = iframeWindow.DomWindow; var sel = iframeWindowCom.document.selection; //これは失敗する //IHTMLSelectionObjectはGetType()でSystem.__ComObjectを返すので操作できない var type = sel.type;
こんな時でも、OperationTypeInfoを使えば、目的の操作を実行することができます。
var type = sel.type(new OperationTypeInfo(typeof(IHTMLSelectionObject).FullName));
まあ、DLLインジェクションを使った方が早いですけどね
書き方難しいのは、普通に実装してDLLインジェクションした方がいいですね。その関数呼び出すだけなら簡単な書き方なので。
[TestMethod] public void Test() { var app = new WindowsAppFriend(Process.Start(Target.Path)); WindowsAppExpander.LoadAssembly(app, GetType().Assembly); var web = app.Type().System.Windows.Forms.Application.OpenForms[0].Controls[0]; web.Url = new Uri("http://www.codeer.co.jp/"); while ((WebBrowserReadyState)web.ReadyState != WebBrowserReadyState.Complete) { Thread.Sleep(10); } //面倒な処理は相手プロセスに挿入して実行すればよい app.Type(GetType()).Func(web); } static void Func(WebBrowser web) { var iframeWindow = web.Document.Window; var iframeWindowCom = (IHTMLWindow2)iframeWindow.DomWindow; var sel = iframeWindowCom.document.selection; var type = sel.type; }
次回へ続く
なんで今さらこんなマニアックな話を出したかというと、実は次回へのフリだったのです。
と言うわけで次回へ続く・・・