Подтвердить что ты не робот

Как подключиться к GetWindowLongPtr и SetWindowLongPtr на 32-битных платформах?

Я хочу, чтобы P/Invoke на GetWindowLongPtr и SetWindowLongPtr, и я вижу противоречивую информацию о них.

Некоторые источники говорят, что на 32-битных платформах GetWindowLongPtr - это просто макрос препроцессора, который вызывает GetWindowLong, а GetWindowLongPtr не существует как точка входа в user32.dll. Например:

  • Запись pinvoke.net для SetWindowLongPtr имеет статический метод, который проверяет IntPtr.Size, а затем вызывает SetWindowLong или SetWindowLongPtr, с комментарием говоря, что "устаревшие ОС не поддерживают SetWindowLongPtr". Там нет объяснения того, что подразумевается под "устаревшими ОС".
  • Ответ qaru.site/info/125588/... гласит: "В 32-битных системах GetWindowLongPtr - это просто макрос C, который указывает на GetWindowLong".

Таким образом, эти источники, похоже, указывают, что точки входа * Ptr просто отсутствуют в версии user32.dll, которая поставляется, скажем, с 32-разрядной Windows 7.

Но я не вижу никаких признаков этого в документации MSDN. Согласно MSDN, SetWindowLongPtr заменяет SetWindowLong, простым и простым. И в соответствии с разделом требований SetWindowLongPtr страница, похоже, что SetWindowLongPtr находится в user32.dll с Windows 2000 (как клиентские, так и серверные версии). Опять же, упоминание о точках входа отсутствует в 32-битных операционных системах.

Я подозреваю, что истина находится где-то посередине: когда вы сообщаете компилятору С++ ориентироваться на более старые ОС (т.е. компилировать что-то, что будет работать на Win9x и NT4), тогда файлы заголовков объявляют SetWindowLongPtr как макрос, который вызывает SetWindowLong, но точка входа, вероятно, существует в Windows 2000 и более поздних версиях, и вы получите ее напрямую (вместо макроса), если вы сообщите компилятору о таргетинге на эти платформы. Но это просто догадка; У меня действительно нет ресурсов или ноу-хау, чтобы заглянуть и проверить его.

Также возможно, что целевая платформа играет роль - если вы скомпилируете свое приложение для платформы x86, вы не должны вызывать SetWindowLongPtr в 64-битной ОС. Опять же, я знаю достаточно, чтобы подумать об этом, но я не знаю, как найти ответ. MSDN, похоже, предполагает, что SetWindowLongPtr всегда корректен.

Может ли кто-нибудь сказать мне, безопасно ли просто P/Invoke to SetWindowLongPtr и делать с ним? (Предположим, что Windows 2000 и более поздние версии.) Будет ли P/Invoking to SetWindowLongPtr дать мне правильную точку входа:

  • если я запускаю приложение, ориентирующее платформу x86 на 32-разрядную ОС?
  • если я запускаю приложение, ориентирующее платформу x86 на 64-разрядную ОС?
  • Если я запускаю приложение, ориентированное на платформу x64 на 64-разрядной ОС?
4b9b3361

Ответ 1

Я бы порекомендовал вам иметь дело с тем, как Windows Forms делает это внутри:

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);

Ответ 2

  • Откройте файл заголовка (на странице MSDN это указано как Winuser.h). Заголовки Win32 обычно находятся в C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include
  • Искать все экземпляры SetWindowLongPtr/GetWindowLongPtr.
  • Обратите внимание, что когда _WIN64 определено, они являются функциями; если это не так, они #define 'd до SetWindowLong/GetWindowLong.

Это означает, что 32-разрядные операционные системы могут не иметь SetWindowLongPtr/GetWindowLongPtr как действительную функцию, поэтому, похоже, что комментарий на pinvoke.net верен.

Обновление (уточнение на _WIN64):

_WIN64 определяется компилятором C/С++ при компиляции 64-битного кода (который будет работать только в 64-разрядной ОС). Таким образом, это означает, что любой 64-разрядный код с использованием SetWindowLongPtr/GetWindowLongPtr будет использовать фактические функции, но любой 32-разрядный код, использующий их, будет использовать SetWindowLong/GetWindowLong. Это включает 32-разрядный код, работающий в 64-разрядной ОС.

Чтобы эмулировать такое же поведение в С#, я рекомендую проверить IntPtr.Size, как это сделано pinvoke.net; который сообщает вам, используете ли вы 32-разрядный или 64-разрядный код. (Помните, что 32-разрядный код может работать на 64-разрядной ОС). Использование IntPtr.Size в управляемом коде эмулирует то же поведение, что и _WIN64 для собственного кода.