前置き
当記事は、前回の「C# ジェネリック(ジェネリクス)」の続編です。
ジェネリックを活用できそうな関数を紹介します。
概要
使用する関数は、WinAPIのひとつである「ReadProcessMemory()」です。
これは、特定のアドレスにあるメモリを読み取ります。
具体的には、以下の通りです。
[DllImport("kernel32.dll")]publicstaticexternintReadProcessMemory(IntPtrhProcess,IntPtrBaseAddress,byte[]Buffer,intsize,intBytesRead);読み取られた値は引数のbufferにbyteとして格納されます。
ここで、読み取られた値はアンマネージド型のいずれかであることが保証されます。
例えば、Int32(int)を読み取りたい時、
BitConverter.ToInt32(buffer,0);といちいち型別に関数を定義するのは面倒ですし、プログラムの保守性やメンテナンス性も最悪です。
読み取り先の値はintやfloat、double等のアンマネージド型ですね。
そうです。ジェネリックの出番です。
ジェネリック関数としてWrap
早速、関数をWrapしてみます。
理想は以下の様に簡単にすることです。
IntPtraddress=...intx=Read<int>(address);ソースコード:
publicstaticunsafeTRead<T>(IntPtrhProc,IntPtraddress)whereT:unmanaged{varsize=sizeof(T);byte[]buffer=newbyte[size];ReadProcessMemory(hProc,address,buffer,buffer.Length,0);Span<T>span=MemoryMarshal.Cast<byte,T>(buffer);returnspan[0];}解説:
制約はunmanagedです。
ここでは、読み取った値(byte[])をMemoryMarshal.Cast<TFrom, TTo>(byte[])を使用してキャストしています。byte[]はマネージ型であるため、アンマネージド型へのキャストには少し工夫が必要です。
それを代行してくれるのが、MemoryMarshal.Castです。
そして、返り値はSpan<T>として帰ってきます。Span<T> spanは配列であり、キャストした値を配列から取り出して返り値としています。
MSDN: 「Span 構造体」
MSDN: 「MemoryMarshal.Cast メソッド」