==[[C# Win32 API および DLL の利用]]==[[C Sharp]] | [[Visual Studio]] | {{category [[Category:Win32API}}]]
このページからメモ
*http://msdn.microsoft.com/en-us/magazine/cc301501.aspx
===概要===
====どのようにして DLL や Win32 API の関数を [[C# ]] から呼び出すか====
=====やりたいことは・・・=====
*(char*) が戻り値の場合、どのように取得する?
*GetWindowRectやEnumWindowsで、構造体や、コールバック関数をどのように指定する?GetWindowRectやEnum[[Windows]]で、構造体や、コールバック関数をどのように指定する?
=====方法の概要=====
*[[.NETの利点の一つに、言語非依存があり、書いたクラスを他の言語でも使用できることがある。NET]]の利点の一つに、言語非依存があり、書いたクラスを他の言語でも使用できることがある。*しかし、アンマネージの DLL へは [[.NET ]] のオブジェクトを 構造体や char* や関数ポインタへ変換(マーシャリング)する必要がある
*マーシャリングは大きなトピックだが、それほど多くを学ぶ必要はない。
===[[C# ]] から DLL 関数を呼び出すには=======まず、Cまず、[[C#]]では、DLLImportを行う。====
*[http://msdn.microsoft.com/en-us/library/ms633546%28VS.85%29.aspx SetWindowText]
using System.Runtime.InteropServicesInteropSer[[vi]]ces; // DLL Import
class Win32Api
}
*[[C# ]] では、DLLImportを利用して、コンパイラにどこにラッパー関数とバンドルするエントリーポイントが存在するのかを伝える
*例ではWin32としているが、クラス名は任意であり、ネームスペースに置くことも可能
<blockquote>ライブラリとして作成しておけば、任意の [[C# ]] プロジェクトから利用可能</blockquote>
====LPTSTRに対応するLPTST[[R]]に対応する====
*上記 SetWindwText を呼び出してみる
====なぜこのようなことができるのか? - デフォルトのマーシャリング型====
*コンパイラは user32.dll を探して、SetWindwText を認識しており呼び出し前に自動的に string を LPTSTRLPTST[[R]](TCHARTCHA[[R]]*)に変換する。*すべての [[C# ]] 型は、デフォルトのマーシャリング型を持っている(string は LPTSTR)ためこのようなことが可能。
=====しかし string はそのままでは出力パラメータとして使用できない=====
*入力パラメータとしては、上記のようにstringを使用できるが、出力パラメータとしてこれは使用できない(GetWindowTextで試してみるとよい)。
*なぜなら string は 変更不可(インミュータブル)だから。
<blockquote>出力パラメータとして LPTSTR LPTST[[R]] を使用する場合、StringBuilder を利用する</blockquote>
=====例(GetWindowText)=====
*[http://msdn.microsoft.com/en-us/library/ms633520%28VS.85%29.aspx GetWindowText]
using System.Text; // String Builder
using System.Runtime.InteropServicesInteropSer[[vi]]ces; // DLL Import
class Win32Api
[[File:0294_get_window_text01.jpg]]
<blockquote>StringBuilderのデフォルトのマーシャリング型も LPTSTR だが、GetWindowsText だが、Get[[Windows]]Text は内容を変更できる</blockquote>
====フォルトのマーシャリング型が希望の型でない場合====
====構造体を定義====
[StructLayout(LayoutKind.Sequential)]
public struct RECT[[R]]ECT
{
public int left;
{
[DllImport("User32.Dll", EntryPoint="GetWindowRect")]
public static extern int GetWindowRectGetWindow[[R]]ect(int hwnd, ref RECT [[R]]ECT rc);
}
*呼び出し元
private void button4_Click(object sender, EventArgs e)
{
RECT [[R]]ECT rc = new RECT[[R]]ECT();
int hwnd = (int)this.Handle;
Win32Api.GetWindowRectGetWindow[[R]]ect(hwnd, ref rc);
string msg = String.Format("top={0}, left={1}, right={2}, bottom={3}."
[[File:0293_get_window_rect01.jpg]]
<blockquote>ref を使うとCLRは、関数がオブジェクトを変更できるように参照として渡すを使うとCL[[R]]は、関数がオブジェクトを変更できるように参照として渡す(無名のスタックコピーではなく)。</blockquote>
====クラスを構造体として渡す====
*上記のRECTが構造体ではなく、クラスの場合、以下のようにすればよい上記の[[R]]ECTが構造体ではなく、クラスの場合、以下のようにすればよい
[DllImport("user32.dll")]
public static extern int
GetWindowRectGetWindow[[R]]ect(int hwnd,
[MarshalAs(UnmanagedType.LPStruct)] RECT rc);
====[[C# ]] に構造体が用意されている場合もある====*[[C# ]] では、ひとつのことを実現するのに多数のやり方がある*System.Drawing に既に Rectangle [[R]]ectangle 構造体が用意されており、Wn32 API のRECTにマーシャリングするすべを心得ているの[[R]]ECTにマーシャリングするすべを心得ている
using System.Drawing; // Rectangle [[R]]ectangle
class Win32Api
{
[DllImport("User32.Dll", EntryPoint = "GetWindowRect")]
public static extern int GetWindowRectGetWindow[[R]]ect(int hwnd, ref Rectangle [[R]]ectangle rc);
}
====そもそもWin32 APIを利用する必要もない====
*上記のAPIは、コントロールのプロパティを利用すれば実現できる
=====GetWindowRect GetWindow[[R]]ect ===== Rectangle [[R]]ectangle r = mywnd.DisplayRectangleDisplay[[R]]ectangle;
=====Get/SetWindowText=====
mywnd.Text = "Window Text";
[DllImport("User32.Dll")]
public static extern int EnumWindowsEnum[[Windows]](EnumWindowCB cb, int lparm);
}
{
Win32Api.EnumWindowCB cb = new Win32Api.EnumWindowCB(MyEnumWindowCB);
Win32Api.EnumWindowsEnum[[Windows]](cb, 0);
}
=====結果=====
====ポインタを使う====
*EnumWindows Enum[[Windows]] においては、lparam で渡したポインターをコールバック関数で得ることができた。
*.Netでは、IntPtr 、GCHandle を使ってラップする。
<blockquote>Free メソッドを呼び出すのを忘れないこと! [[C#]]では、時々自分でメモリを開放しなければならない!</blockquote>
=====ラッパークラス側=====
using System.Runtime.InteropServicesInteropSer[[vi]]ces;
public delegate bool EnumWindowCB2(int hwnd, IntPtr lparm);
[DllImport("User32.Dll", EntryPoint = "EnumWindows")]
public static extern int EnumWindows2Enum[[Windows]]2(EnumWindowCB2 cb, IntPtr lparm);
=====呼び出し側=====
GCHandle gch = GCHandle.Alloc(ewi);
Win32Api.EnumWindowCB2 cb = new Win32Api.EnumWindowCB2(MyEnumWindowCB2);
Win32Api.EnumWindows2Enum[[Windows]]2(cb, (IntPtr)gch);
gch.Free();
}