.NET2.0 C#Interop:C#からCOMコードを呼び出す方法
質問
前回の開発環境では、COMオブジェクトのメソッドを呼び出して、COMと簡単にやり取りすることができました。元のコードをC#スタイルのコードに変換します(元の言語をマスクするため):
public static void SpawnIEWithSource(String szSourceHTML)
{
OleVariant ie; //IWebBrowser2
OleVariant ie = new InternetExplorer();
ie.Navigate2("about:blank");
OleVariant webDocument = ie.Document;
webDocument.Write(szSourceHTML);
webDocument.close;
ie.Visible = True;
}
今、マネージコードからCOMとの相互運用を試みる退屈で苦痛なプロセスを開始します。
PInvoke.netには既に IWebBrower2の翻訳が含まれています。これは:
[ComImport,
DefaultMember("Name"),
Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch),
SuppressUnmanagedCodeSecurity]
public interface IWebBrowser2
{
[DispId(500)]
void Navigate2([In] ref object URL, [In] ref object Flags, [In] ref object TargetFrameName, [In] ref object PostData, [In] ref object Headers);
object Document { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xcb)] get; }
}
COMクラスを作成しました:
[ComImport]
[Guid("0002DF01-0000-0000-C000-000000000046")]
public class InternetExplorer
{
}
これで、実際のC#トランザクションの時間です:
public static void SpawnIEWithSource(String szHtml)
{
PInvoke.ShellDocView.IWebBrowser2 ie;
ie = (PInvoke.ShellDocView.IWebBrowser2)new PInvoke.ShellDocView.InternetExplorer();
//Navigate to about:blank to initialize the browser
object o = System.Reflection.Missing.Value;
String url = @"about:blank";
ie.Navigate2(ref url, ref o, ref o, ref o, ref o);
//stuff contents into the document
object webDocument = ie.Document;
//webDocument.Write(szHtml);
//webDocument.Close();
ie.Visible = true;
}
注意深い読者は、IWebBrowser2.Documentが遅延バインディングのIDispatchであることに気付きます。 私たちとお客様のマシンに.NET 2.0を搭載したVisual Studio 2005を使用しています。
では、あるレベルでは遅延バインディングのIDispatchのみをサポートするオブジェクトのメソッドを呼び出す.NET 2.0メソッドは何ですか?
C#からIDispatchを使用するためにStack Overflowをすばやく検索すると、この投稿が表示されます .NETでは、欲しいものを言うことはできません。
では、C#.NET 2.0からCOMを使用できますか?
問題は、C#/。NETで使用したい承認済みのデザインパターンがあることです。一時ファイルを使用せずに、アウトオブプロセスでInternet Explorerを起動し、HTMLコンテンツを提供する必要があります。
拒否されたデザインアイデアは、WinFormでInternet Explorerをホストしています。
許容される代替手段は、システムに登録されたWebブラウザーを起動し、一時ファイルを使用せずにHTMLを表示することです。
つまずきのブロックは、.NETの世界でCOMオブジェクトを使用し続けています。特定の問題には、C#4.0を必要とせずにIDispatchの遅延バインディング呼び出しを実行することが含まれます。 (つまり、.NET 2.0の使用中)
解決 2
.NETで呼び出されるレイトバインドIDispatchは比較的簡単ですが、piss-poor:
public static void SpawnIEWithSource(String szHtml)
{
// Get the class type and instantiate Internet Explorer.
Type ieType = Type.GetTypeFromProgID("InternetExplorer.Application");
object ie = Activator.CreateInstance(ieType);
//Navigate to the blank page in order to make sure the Document exists
//ie.Navigate2("about:blank");
Object[] parameters = new Object[1];
parameters[0] = @"about:blank";
ie.GetType().InvokeMember("Navigate2", BindingFlags.InvokeMethod | BindingFlags.IgnoreCase, null, ie, parameters);
//Get the Document object now that it exists
//Object document = ie.Document;
object document = ie.GetType().InvokeMember("Document", BindingFlags.GetProperty | BindingFlags.IgnoreCase, null, ie, null);
//document.Write(szSourceHTML);
parameters = new Object[1];
parameters[0] = szHtml;
document.GetType().InvokeMember("Write", BindingFlags.InvokeMethod | BindingFlags.IgnoreCase, null, document, parameters);
//document.Close()
document.GetType().InvokeMember("Close", BindingFlags.InvokeMethod | BindingFlags.IgnoreCase, null, document, null);
//ie.Visible = true;
parameters = new Object[1];
parameters[0] = true;
ie.GetType().InvokeMember("Visible", BindingFlags.SetProperty | BindingFlags.IgnoreCase, null, ie, parameters);
}
元々は<!> quot; C#4.0 <!> quotまでは不可能だったと言っていた、参照されているSOの質問。 .NET 2.0で可能なことを示すために修正されました。
他のヒント
更新:質問の更新に基づいて、質問に関連しなくなった回答の部分を削除しました。ただし、他の読者がwinformsアプリでHTMLを迅速かつダーティに生成する方法を探していて、インプロセスIEを必要としない場合は、以下を残します。
可能なシナリオ1:最終的な目標は、エンドユーザーにHTMLを表示し、Windowsフォームを使用することです
System.Windows.Forms.WebBrowser
は、手動で実装しようとしているインターフェイスの骨の折れるほど簡単な.NETラッパーです。取得するには、そのオブジェクトのインスタンスをツールバー(<!> quot; Web Browser <!> quot; <!> quot; All Windows Forms <!> quot;セクションの下にリストされている)からフォームにドラッグアンドドロップします。 。次に、適切なイベントハンドラーで:
webBrowser1.Navigate("about:blank");
webBrowser1.Document.Write("<html><body>Hello World</body></html>");
テストアプリでは、これは私たち全員が恐怖と嫌悪を覚えた忘れられないメッセージを正しく表示しました。
リンク先の投稿の回答は実際には間違っています。通常、.NetのIDispatchベースのオブジェクトを扱うのは非常に簡単です。基本的に、次の3つの手順を実行します。
IDispatchインターフェイスとして公開されるほとんどのオートメーションオブジェクト(おそらく90%を超える)には、非スクリプト型のCOMクライアントが使用できる他のインターフェイスがあります(IDispatchインターフェイスは、実際にはIDispatchまたはオブジェクトから派生した完全なCOMインターフェイスです) 1つ以上の他のIUnknown派生インターフェイスをサポートします)。この場合、適切なCOMインターフェイス定義をインポートし、オブジェクトを適切なインターフェイスにキャストするだけです。キャストは、カバーの下でQueryInterfaceを呼び出し、必要なインターフェイスへのラップされた参照を返します。
これは、上記で示したシナリオで使用する手法です。 IEオートメーションオブジェクトから返されるDocumentオブジェクトは、IHTMLDocument、IHTMLDocument2、IHTMLDocument3、IHTMLDocument4、およびIHTMLDocument5インターフェイスをサポートしています(使用しているIEのバージョンによって異なります)。適切なインターフェイスにキャストしてから、適切なメソッドを呼び出す必要があります。例:
IHTMLDocument2 htmlDoc = (IHTMLDocument2)webDocument;
htmlDoc.Write(htmlString);
htmlDoc.Close();
まれに、オートメーションオブジェクトが代替インターフェイスをサポートしない場合。次に、VB.Netを使用してそのインターフェイスをラップする必要があります。 Option Strictをoffに設定すると(ラッパークラスのみ)、VBの遅延バインド呼び出しのサポートを使用して、適切なIDispatchメソッドを単純に呼び出すことができます。まれに、異常な引数タイプがある場合、呼び出しを少し調整する必要があるかもしれませんが、一般に、VBではそれを行うことができます! C#v4 VBに動的に追加された場合でも、レイトバウンドCOM呼び出しのサポートが大幅に改善される可能性があります。
何らかの理由でVBを使用してオートメーションインターフェイスをラップできない場合、リフレクションを使用してC#から必要な呼び出しを行うことができます。このオプションは基本的に使用されるべきではないため、詳細は説明しませんが、ここでは Officeに関する小さな例を示します。自動化。
この記事を参照: http://www.codeproject.com/KB/cs/IELateBindingAutowod.aspx
Internet Explorer Late Binding Automation によってyincekara
Microsoft.mshtmlおよびshdocvwに依存せずに、遅延バインディングを使用するInternet Explorerオートメーションサンプルコード。
htmlDoc.write(htmlString); 変更
[Guid("332C4425-26CB-11D0-B483-00C04FD90119")]
[ComImport]
[TypeLibType((short)4160)]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
internal interface IHTMLDocument2
{
[DispId(1054)]
void write([MarshalAs(UnmanagedType.BStr)] string psArray);
//void write([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] object[] psarray);