.NETおよびアンマネージコード
今日は、特別なMarshalクラスを使用して、アンマネージコードを操作する方法の1つを示します。 このクラスで定義されているメソッドのほとんどは、通常、マネージプログラミングモデルとアンマネージプログラミングモデルの間にインターフェイスを提供する必要がある開発者によって使用されます。
インタラクションマーシャリングは、呼び出し時にマネージメモリとアンマネージメモリ間で引数に渡されるデータとメソッドの戻り値を決定します。 相互作用マーシャリングは、CLRマーシャリングサービスによって実行される実行時プロセスです。
相互作用の構造全体を完全に説明したくありません。なぜなら、 これは記事のかなりの部分を占めるでしょう。 この記事では、特定の例との相互作用の原理について説明し、割り当てられたメモリの割り当て方法とクリア方法について説明します。
最初に、Cで記述された小さな構造の例を取り上げ、C#に対して同様の構造を作成する方法を見てください。
Cコード
struct test
{
struct innerstr
{
char str[300];
int Int;
int * in_pInt;
} in ;
char str[2][50];
int IntArr[10];
int * pInt;
innerstr* pStruct;
int * ptr;
};
* This source code was highlighted with Source Code Highlighter .
C#コード
[StructLayout(LayoutKind.Sequential)]
public struct Test
{
public Innerstr _in;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50 * 2)]
public char [] str;;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public int [] IntArr;
public IntPtr pInt;
public IntPtr pStruct;
public IntPtr ptr;
[StructLayout(LayoutKind.Sequential)]
public struct Innerstr
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 300)]
internal string str;
public int _Int;
public IntPtr in_pInt;
}
}
* This source code was highlighted with Source Code Highlighter .
ご覧のとおり、CのすべてのポインターがC#のIntPtr型に置き換えられました。 2次元配列-1次元で、同様の長さ。 そして、構造自体は[StructLayout]属性で署名されています。 SequentialパラメーターのLayoutKind値は、メンバーを表示順に強制的に配置するために使用されます。
配列の場合、そのタイプをUnmanagedType.ByValArrayとして指定し、正確なサイズをすぐに示す必要があります。 変数自体のサイズが異なる場合でも、送信中に必要なサイズに自動的に等しくなります。
アンマネージコードコール
Cコード
extern "C" __declspec(dllexport) int ExpFunc(test* s, bool message)
* This source code was highlighted with Source Code Highlighter .
C#コード:
[ return :MarshalAs(UnmanagedType.I4)]
[DllImport( "TestTkzDLL.dll" )]
public static extern int ExpFunc([In, Out] IntPtr c, [In] bool message);
* This source code was highlighted with Source Code Highlighter .
お気づきかもしれませんが、呼び出す前に、まずすべてのIntPtrを宣言する必要があります。 これを行うには、およそ次のコードを使用します。
Test test = new Test();
...
// => int* pInt
int _pInt = 2010; //
IntPtr _pInt_buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(_pInt)); //
Marshal.StructureToPtr(_pInt, _pInt_buffer, false ); //
test.pInt = _pInt_buffer; //
* This source code was highlighted with Source Code Highlighter .
同様に、innerstr * pStruct、および他のすべてのポインター。
Test.Innerstr inner2 = new Test.Innerstr();
IntPtr _pStruct_buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(inner2));
Marshal.StructureToPtr(inner2, _pStruct_buffer, false );
test.pStruct = _pStruct_buffer;
* This source code was highlighted with Source Code Highlighter .
それだけです、それはすべて簡単です。 これで、コードからメソッドを呼び出すことができます
/////////////////////////////////////// <br ?>
// ( , )
/////////////////////////////////////
IntPtr ptr1 = Marshal.AllocCoTaskMem(Marshal.SizeOf(test));
Marshal.StructureToPtr(test, ptr1, false );
int retInt = ExpFunc(ptr1, false ); //
test = (StartClass.Test)Marshal.PtrToStructure(ptr1, typeof (StartClass.Test)); ///
* This source code was highlighted with Source Code Highlighter .
この場合、構造全体を管理されていないメモリに転送し、この部分へのリンクを渡してから、Cで読み取りました。 refで渡すとこれはできませんが、巨大なref構造体が管理されていないメモリに転送できず、リンクを渡す方法が常に機能するという事実に出会いました
その後、メモリを消去することを忘れないでください。 マネージコードとは異なり、ガベージコレクターはアンマネージをクリーンアップできません。 したがって、
Marshal.FreeCoTaskMem(ptr);
呼び出す必要があります
Marshal.FreeCoTaskMem(ptr);
すべてのIntPtrリンク用
PS:後で追加されました... [StructLayout(LayoutKind.Sequential)]属性は、使用される文字テーブル、ANSIまたはUNICODEを指すこともできます。 これを行うには、[StructLayout(LayoutKind.Sequential、CharSet = CharSet.Ansi)]、[StructLayout(LayoutKind.Sequential、CharSet = CharSet.Unicode)]、または[StructLayout(LayoutKind.Sequential、CharSet = CharSet.Auto)]を記述します。 デフォルトはANSIです。
さて、これで終わりです。これで記事の最初の部分は終わりです。 次のパートでは、動的サイズを配列で使用する方法、多次元配列を1次元配列にすばやく変換する方法、およびその逆を行い、それらをアンマネージコードに転送する方法、マーシャリングを伴う透過的な作業のためのプログラマ向けの構造を整理する方法などについて説明します
更新しました
テストプロジェクトのソースを追加しました。 ダウンロードする