ネイティブdllまたはexeが何らかのフックを使用してC#から実行しているWin32API呼び出しをインターセプトしています。この特定のケースでは、user32.dllのDrawText()に興味があります。Win32APIでは次のように宣言されています。
INT WINAPI DrawTextW(HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags)
LPRECT構造体には、次のシグネチャがあります(Win32 APIでも)。
typedef struct tagRECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT LPRECT;
LONGは、32ビットシステムでの32ビット整数のtypedefです(64ビットシステムについてはわかりません。私は32ビットWindowsを使用しているため、現時点では関係ありません)。この構造体のメンバーにアクセスできるようにするために、C#コードで宣言しました...
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct RECT
{
public Int32 left;
public Int32 top;
public Int32 right;
public Int32 bottom;
}
...そしてこのRECT構造体を使用してP/Invokeの署名を書きました:
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
static extern IntPtr DrawText(IntPtr HDC, String str, Int32 count, ref RECT rect, UInt32 flags, IntPtr dtp);
構造体はC/C ++のような参照型ではなく、C#の値型であるため、ここではref修飾子が必要です。
ただし、rect.top rect.left
etcを使用すると、ほとんどの場合0が返されます。これが正しくないことはわかっています。しかし、数え切れないほどの時間をグーグルで調べて、さまざまなことを試した後、私はこの単純なものを機能させることができませんでした。
私が試したこと:
- RECTメンバーにさまざまなプリミティブを使用する(int、long、short、UInt32 ...)。実際、これが型の問題ではないことは明らかです。いずれにせよ、0ではなく文字化けした数字が表示されるはずだからです。
- ref修飾子を削除します。rect.leftは、その値ではなくrectへのポインターを正しく返すため、これも愚かです(絶望的な時間、絶望的な対策)。
unsafe
コードブロックを試しました。動作しませんでしたが、実装を間違えた可能性があります(何をしたか覚えていません)。このアプローチは、一般的にCOMとWin32でのトリッキーなポインターの状況のために予約されていますが、とにかく私の場合はやり過ぎです。[MarshallAs]
RECTのメンバーの前に追加してみました。違いはありませんでした。- 値をいじってみました
Pack
。変わりはない。
私は非常に簡単で簡単なものを見逃しているとかなり確信していますが、それが何であるかわかりません...
どんな助けでも大歓迎です。ありがとうございました。