(書きかけ)
.NET Framework は、100% マネージドコードだけで何でもやろうとは思っていなくて、 プラットフォーム依存のネイティブコード呼び出し機能も持っています。 このような機能を、P/Invoke(Platform Invoke: プラットフォーム呼び出し)と呼びます。
.NET Framework が標準で持つライブラリはかなり高機能でいろいろなものがそろっていますが、 OS に深く食い込むような部分はどうしても P/Invoke が必要になってきます。
また、過去に C/C++ で書かれたような資産を生かすためにも P/Invoke が利用されます。 (この用途の場合、P/Invoke 以外に、C++/CLI を使うという選択肢もあります。)
C++/CLI (sp_unsafe.htmlから移す)
DllImport
ComImport
用語
thunk, stab: 関数呼び出し用のつなぎ役
RCW (Runtime Callable Wrapper): .NET から COM を呼ぶためのラッパー。thunk の COM 版。
CCW (COM Callable Wrapper): RCW の逆。.NET クラスを COM として公開。
Marshaling: managed な型 → native な型への変換
thunk とか RCW が内部でやってくれてる。
(.NET Framework に組み込まれてる機能)
extern キーワード(キーワードページにも追加)
以下のコード、コンパイルするためには 「参照の追加」→「COM」→「Microsoft XML, v6.0」
var doc = new MSXML2.DOMDocument60Class(); doc.load("sample.xml"); var elem = doc.documentElement; var items = elem.getElementsByTagName("Item"); foreach (var item in items.Cast<MSXML2.IXMLDOMElement>()) { var name = item.getAttribute("Name") as string; var val = item.getAttribute("Value") as string; Console.WriteLine("{0} = {1}", name, val); }
<?xml version="1.0" encoding="utf-8" ?> <Sample> <Item Name="a" Value="1"/> <Item Name="b" Value="2"/> <Item Name="c" Value="3"/> <Item Name="d" Value="4"/> </Sample>
a = 1 b = 2 c = 3 d = 4
#include "stdafx.h" #import <msxml6.dll> typedef MSXML2::IXMLDOMDocument3Ptr IDocument; typedef MSXML2::IXMLDOMNodeListPtr INodeListPtr; typedef MSXML2::IXMLDOMNodePtr INodePtr; typedef MSXML2::IXMLDOMElementPtr IElementPtr; int _tmain(int argc, _TCHAR* argv[]) { // COMライブラリの初期化 CoInitialize(NULL); { // ドキュメントのインスタンスを作成 IDocument pDoc; pDoc.CreateInstance( __uuidof(MSXML2::DOMDocument60) ); pDoc->async = VARIANT_FALSE; // XMLファイルのロード pDoc->load("sample.xml"); // Item ノードを取得 IElementPtr pElem = pDoc->GetdocumentElement(); INodeListPtr plItem = pElem->getElementsByTagName("Item"); // Item ノードの Name と Value を表示 for(int i=0; i<plItem->Getlength(); i++) { IElementPtr peItem = plItem->Getitem(i); BSTR name = peItem->getAttribute("Name").bstrVal; BSTR val = peItem->getAttribute("Value").bstrVal; wprintf(L"%s = %s\n", name, val); } } // COMライブラリの終了処理 CoUninitialize(); return 0; }
// DOMDocument60Class Type t = Type.GetTypeFromCLSID( new Guid("88D96A05-F192-11D4-A65F-0040963251E5")); var doc = Activator.CreateInstance(t); t.InvokeMember("load", BindingFlags.InvokeMethod, null, doc, new object[] { "sample.xml" } ); var elem = t.InvokeMember("documentElement", BindingFlags.GetProperty, null, doc, new object[0]); var items = elem.GetType().InvokeMember("getElementsByTagName", BindingFlags.InvokeMethod, null, elem, new object[] { "Item" }) as IEnumerable; foreach (var item in items) { var name = item.GetType().InvokeMember("getAttribute", BindingFlags.InvokeMethod, null, item, new object[] { "Name" }) as string; var val = item.GetType().InvokeMember("getAttribute", BindingFlags.InvokeMethod, null, item, new object[] { "Value" }) as string; Console.WriteLine("{0} = {1}", name, val); }
Ver. 4.0
// DOMDocument60Class Type t = Type.GetTypeFromCLSID( new Guid("88D96A05-F192-11D4-A65F-0040963251E5")); dynamic doc = Activator.CreateInstance(t); doc.load("sample.xml"); dynamic elem = doc.documentElement(); dynamic items = elem.getElementsByTagName("Item"); foreach (dynamic item in items) { var name = item.getAttribute("Name") as string; var val = item.getAttribute("Value") as string; Console.WriteLine("{0} = {1}", name, val); }