13

GetWindowLongPtrSetWindowLongPtrに P/Invoke したいのですが、それらに関する矛盾する情報が表示されます。

一部のソースによると、32 ビット プラットフォームでは、GetWindowLongPtr は GetWindowLong を呼び出す単なるプリプロセッサ マクロであり、GetWindowLongPtr は user32.dll のエントリ ポイントとして存在しません。例えば:

  • SetWindowLongPtrのpinvoke.net エントリには、IntPtr.Size をチェックしてから SetWindowLong または SetWindowLongPtr を呼び出す静的メソッドがあり、「レガシー OS は SetWindowLongPtr をサポートしていません」というコメントがあります。「レガシーOS」が何を意味するのかについての説明はありません。
  • StackOverflowに関する回答には、「32 ビット システムでは、GetWindowLongPtr は、GetWindowLong を指す単なる C マクロです」と記載されています。

したがって、これらのソースは、*Ptr エントリ ポイントが、たとえば 32 ビット Windows 7 に同梱されているバージョンの user32.dll には存在しないことを示しているようです。

しかし、MSDN のドキュメントにはこれに関する記述はありません。MSDN によると、 SetWindowLongPtr はSetWindowLongに取って代わり、単純明快です。また、 SetWindowLongPtr ページの要件セクションによると、SetWindowLongPtr は Windows 2000 以降 (クライアント エディションとサーバー エディションの両方) に user32.dll に含まれているようです。繰り返しになりますが、32 ビット OS で欠落しているエントリ ポイントについては言及されていません。

真実はその中間にあるのではないかと思います: C++ コンパイラに古い OS をターゲットにする (つまり、Win9x と NT4 で実行されるものをコンパイルする) ように指示すると、ヘッダー ファイルは SetWindowLongPtr を SetWindowLong を呼び出すマクロとして宣言しますが、エントリ ポイントはおそらく Windows 2000 以降に存在し、これらのプラットフォームをターゲットにするようにコンパイラに指示すると、(マクロではなく) 直接取得できます。しかし、それは単なる推測です。私はそれを掘り下げて検証するためのリソースやノウハウを本当に持っていません。

ターゲット プラットフォームが役割を果たす可能性もあります。x86 プラットフォーム用にアプリをコンパイルする場合は、64 ビット OS で SetWindowLongPtr を呼び出すべきではありません。繰り返しますが、私はその質問について考えるのに十分な知識を持っていますが、答えを見つける方法がわかりません. MSDN は、SetWindowLongPtr が常に正しいことを示唆しているようです。

単純に SetWindowLongPtr に P/Invoke を実行して、それを実行しても安全かどうか教えてもらえますか? (Windows 2000 以降を想定しています。) SetWindowLongPtr を P/Invoking すると、正しいエントリ ポイントが得られます。

  • 32 ビット OS で x86 プラットフォームを対象とするアプリを実行するとどうなりますか?
  • x86 プラットフォームを対象とするアプリを 64 ビット OS で実行するとどうなりますか?
  • x64 プラットフォームを対象とするアプリを 64 ビット OS で実行するとどうなりますか?
4

2 に答える 2

18

Windows フォームが内部的に行う方法でこれを処理することをお勧めします。

public static IntPtr GetWindowLong(HandleRef hWnd, int nIndex)
{
    if (IntPtr.Size == 4)
    {
        return GetWindowLong32(hWnd, nIndex);
    }
    return GetWindowLongPtr64(hWnd, nIndex);
}


[DllImport("user32.dll", EntryPoint="GetWindowLong", CharSet=CharSet.Auto)]
private static extern IntPtr GetWindowLong32(HandleRef hWnd, int nIndex);

[DllImport("user32.dll", EntryPoint="GetWindowLongPtr", CharSet=CharSet.Auto)]
private static extern IntPtr GetWindowLongPtr64(HandleRef hWnd, int nIndex);
于 2010-07-27T13:46:03.020 に答える
4
  1. ヘッダー ファイルを開きます (MSDN ページでは、これは Winuser.h としてリストされています)。通常、Win32 ヘッダーは次の場所にあります。C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include
  2. SetWindowLongPtr/のすべてのインスタンスを検索しますGetWindowLongPtr
  3. _WIN64が定義されている場合、それらは関数であることに注意してください。そうでない場合、それらは/#defineに変換されます。SetWindowLongGetWindowLong

これは、32 ビット OSには実際の機能としてSetWindowLongPtr/がない可能性があることを意味GetWindowLongPtrするため、pinvoke.net のコメントは正しいように見えます。

更新 (_WIN64 の詳細):

_WIN6464 ビット コード (64 ビット OS でのみ実行される) をコンパイルするときに、C/C++ コンパイラによって定義されます。つまり、SetWindowLongPtr/GetWindowLongPtrを使用する 64 ビット コードは実際の関数を使用しますが、それらを使用する 32 ビット コードは代わりにSetWindowLong/を使用します。GetWindowLongこれには、64 ビット OS で実行される 32 ビット コードが含まれます。

C# で同じ動作をエミュレートするには、IntPtr.Sizepinvoke.net によるチェックをお勧めします。これにより、実行しているコードが 32 ビットか 64 ビットかがわかります。(32 ビット コードは 64 ビット OS で実行できることに注意してください)。マネージ コードで使用すると、ネイティブ コードIntPtr.Sizeの場合と同じ動作がエミュレートされます。_WIN64

于 2010-07-27T13:01:18.447 に答える