Как я могу вызвать GetWindowLongPtr и SetWindowLongPtr на 32-битных платформах?
Я хочу P/Invoke для GetWindowLongPtr и SetWindowLongPtr, и я вижу противоречивую информацию о них.
В некоторых источниках говорится, что на 32-разрядных платформах GetWindowLongPtr - это просто макрос препроцессора, который вызывает GetWindowLong, а GetWindowLongPtr не существует в качестве точки входа в user32.dll. Например:
- Запись pinvoke.net для SetWindowLongPtr имеет статический метод, который проверяет IntPtr.Size и затем вызывает либо SetWindowLong, либо SetWindowLongPtr, с комментарием о том, что "устаревшие ОС не поддерживают SetWindowLongPtr". Там нет объяснения того, что подразумевается под "устаревшими ОС".
- Ответ на Stackru гласит: "В 32-битных системах GetWindowLongPtr - это просто макрос C, который указывает на GetWindowLong".
Таким образом, эти источники, похоже, указывают на то, что точки входа * Ptr просто отсутствуют в версии user32.dll, которая поставляется, скажем, с 32-битной Windows 7.
Но я не вижу никаких признаков этого в документации MSDN. Согласно MSDN, SetWindowLongPtr заменяет SetWindowLong, просто и понятно. И в соответствии с разделом требований на странице SetWindowLongPtr, похоже, что SetWindowLongPtr был в user32.dll начиная с Windows 2000 (как для клиента, так и для сервера). Опять же, нет упоминаний о том, что в 32-битных ОС отсутствуют точки входа.
Я подозреваю, что истина где-то посередине: когда вы говорите компилятору C++ нацеливаться на более старые ОС (то есть компилировать что-то, что будет работать на Win9x и NT4), тогда файлы заголовков объявляют SetWindowLongPtr как макрос, который вызывает SetWindowLong, но точка входа, вероятно, существует в Windows 2000 и более поздних версиях, и вы получите ее напрямую (вместо макроса), если скажете компилятору нацелиться на эти платформы. Но это только предположение; У меня действительно нет ресурсов или ноу-хау, чтобы копаться и проверять это.
Также возможно, что целевая платформа играет роль - если вы компилируете свое приложение для платформы x86, вам не следует вызывать SetWindowLongPtr в 64-битной ОС. Опять же, я знаю достаточно, чтобы подумать над вопросом, но я не знаю, как найти ответ. MSDN, кажется, предполагает, что SetWindowLongPtr всегда корректен.
Может кто-нибудь сказать мне, безопасно ли просто P/Invoke для SetWindowLongPtr и покончить с этим? (Предположим, Windows 2000 и более поздние версии.) Будет ли P/Invoking для SetWindowLongPtr дать мне правильную точку входа:
- запустить приложение на платформе x86 в 32-битной ОС?
- запустить приложение на платформе x86 в 64-битной ОС?
- запустить приложение на платформе x64 в 64-битной ОС?
2 ответа
Я бы порекомендовал вам справиться с этим так, как 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);
- Откройте файл заголовка (на странице MSDN он указан как Winuser.h). Заголовки Win32 обычно находятся в
C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include
- Поиск всех экземпляров
SetWindowLongPtr
/GetWindowLongPtr
, - Обратите внимание, что когда
_WIN64
определяется, они являются функциями; когда это не так, они#define
быSetWindowLong
/GetWindowLong
,
Это подразумевает, что 32-битные ОС могут не иметь SetWindowLongPtr
/GetWindowLongPtr
как действительная функция, поэтому может показаться, что комментарий к pinvoke.net правильный.
Обновление (больше разъяснений по _WIN64):
_WIN64
определяется компилятором C/C++ при компиляции 64-битного кода (который будет работать только в 64-битной ОС). Так что это означает, что любой 64-битный код, использующий SetWindowLongPtr
/GetWindowLongPtr
будет использовать реальные функции, но любой 32-битный код, использующий их, будет использовать SetWindowLong
/GetWindowLong
вместо. Это включает в себя 32-битный код, работающий на 64-битной ОС.
Чтобы эмулировать такое же поведение в C#, я рекомендую проверить IntPtr.Size
как сделано pinvoke.net; это говорит вам, используете ли вы 32-битный или 64-битный код. (Помните, что 32-битный код может работать в 64-битной ОС). С помощью IntPtr.Size
в управляемом коде эмулирует то же поведение, что и _WIN64
делает для родного кода.