UIntPtrのZero値
以前の日記で紹介したWindowsXPによるゴーストウインドウを抑制する方法だが、Windows2000上でコードを実行した際に例外が投げられていることに気が付いた。
public static void DisableProcessWindowsGhostingImpl() { int hmod = LoadLibrary("User32"); UIntPtr funcaddr = GetProcAddress(hmod, "DisableProcessWindowsGhosting"); if (!funcaddr.Equals(0)) { DisableProcessWindowsGhosting(); } FreeLibrary(hmod); } [DllImport("User32")] public extern static void DisableProcessWindowsGhosting();
内容としてはGetProcAddressで"DisableProcessWindowsGhosting"という名前のWinAPIの関数へのポインタを取得できたならば、同名で定義されている関数をコールするだけのものだが、Windows2000で実行すると、同O/Sには実装されていないはずの関数を呼ぼうとしてSystem.EntryPointNotFoundExceptionがスローされるのだ。
実はこのコード、最初に日記を書いた時から変更されている。これまた過去の日記になるが、64ビット時代で、P/Invokeコードを64ビットプラットホームでも正しく動作するように、GetProcAddressの定義を変えているのだ。
- 対策前
[DllImport("kernel32", CharSet = CharSet.Ansi)] public extern static int GetProcAddress(int hModule, string lpProcName);
- 対策後
[DllImport("kernel32", CharSet = CharSet.Ansi)] public extern static UIntPtr GetProcAddress(IntPtr hModule, string lpProcName);
64ビットプラットホームへの移行の指針としてはintの型をint32に限定しないことが必要なため、対策後のようにUIntPtrで関数ポインタの戻り値を受けているのだが、そうすると
UIntPtr funcaddr = GetProcAddress(hmod, "DisableProcessWindowsGhosting");
の戻り値は0に相当する値が戻ってきているはずなのだが
(!funcaddr.Equals(0))
この式が真になってしまうのである。なんでやねん、と突っ込みを入れたくなったが、こんなときはMSDNということで調べてみるとUIntPtr構造体にはこんなフィールドが定義されていた。
public static readonly UIntPtr Zero
... 最初からこれ使え、ということなのね....
public static void DisableProcessWindowsGhostingImpl() { int hmod = LoadLibrary("User32"); UIntPtr funcaddr = GetProcAddress(hmod, "DisableProcessWindowsGhosting"); if ( funcaddr!= null && funcaddr != UIntPtr.Zero ) { DisableProcessWindowsGhosting(); } FreeLibrary(hmod); }
どうやらもう一度P/Invokeコードの見直しを行う必要があるようだ。orz ....