Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Перенос кода для компиляции для 32-разрядной и 64-разрядной версии Microsoft Windows прост. Вам нужно выполнить только несколько простых правил для приведения указателей и использовать новые типы данных в коде. Ниже приведены правила для манипуляции указателем.
Не приводите указатели на int, long, ULONGили DWORD.
Если необходимо создать указатель для проверки некоторых битов, задания или очистки битов или управления его содержимым, используйте тип UINT_PTR или INT_PTR. Эти типы представляют собой целые типы, масштабируемые до размера указателя для 32-разрядных и 64-разрядных Windows (например, ULONG для 32-разрядных Windows и _int64 для 64-разрядных Windows). Например, предположим, что вы переносите следующий код:
ImageBase = (PVOID)((ULONG)ImageBase | 1);
В рамках процесса переноса код изменится следующим образом:
ImageBase = (PVOID)((ULONG_PTR)ImageBase | 1);
Используйте UINT_PTR и INT_PTR, если это необходимо (и если вы не уверены, требуются ли они, нет ничего плохого в их использовании на всякий случай). Не приводите указатели к типам ULONG, LONG, INT, UINTили DWORD.
Обратите внимание, что HANDLE определяется как void*, поэтому преобразование значения HANDLE в значение ULONG для тестирования, задания или очистки младших 2 битов ошибочно для 64-разрядной Windows.
Используйте функцию PtrToLong или PtrToUlong для усечения указателей.
Если необходимо усечь указатель на 32-разрядное значение, используйте функцию PtrToLong или PtrToUlong (определено в Basetsd.h). Эти функции отключают предупреждение усечения указателя в течение длительности вызова.
Тщательно используйте эти функции. После преобразования переменной указателя с помощью одной из этих функций никогда не используйте ее в качестве указателя снова. Эти функции усекают верхние 32 бита адреса, которые обычно необходимы для доступа к той памяти, на которую ссылается указатель. Использование этих функций без тщательного рассмотрения будет следствием хрупкого кода.
Будьте осторожны при использовании POINTER_32 значений в коде, который может быть скомпилирован как 64-разрядный код. Компилятор будет расширять знак указателя, когда он присваивается собственному указателю в 64-разрядном коде, и не расширять нулями.
Будьте осторожны при использовании POINTER_64 значений в коде, которые могут быть скомпилированы как 32-разрядный код. Компилятор будет подписывать указатель в 32-разрядном коде, а не нулевым расширением указателя.
Будьте осторожны с использованием параметров OUT.
Например, предположим, что у вас есть функция, определенная следующим образом:
void func( OUT PULONG *PointerToUlong );
Не вызывайте эту функцию следующим образом.
ULONG ul; PULONG lp; func((PULONG *)&ul); lp = (PULONG)ul;
Вместо этого используйте следующий вызов.
PULONG lp; func(&lp);
Приведение типа &ul к PULONG* предотвращает ошибку компилятора, но функция записывает 64-разрядное значение указателя в область памяти по адресу &ul. Этот код работает в 32-разрядной Windows, но приведет к повреждению данных в 64-разрядной Windows, которое будет трудно заметить и выявить. Главное: не хитрите с кодом на C — проще и прямолинейнее лучше.
Будьте осторожны с полиморфными интерфейсами.
Не создавайте функции, принимающие параметры DWORD для полиморфных данных. Если данные могут быть указателем или целочисленным значением, используйте тип UINT_PTR или PVOID.
Например, не создавайте функцию, которая принимает массив параметров исключения, типизированных как значения DWORD. Массив должен состоять из значений типа DWORD_PTR. Поэтому элементы массива могут содержать адреса или 32-разрядные целочисленные значения. (Общее правило заключается в том, что если исходный тип DWORD и должен быть шириной указателя, преобразуйте его в значение DWORD_PTR. Именно поэтому существуют соответствующие типы точности указателя.) Если у вас есть код, использующий DWORD, ULONGили другие 32-разрядные типы в полиморфном режиме (то есть, вы действительно хотите, чтобы параметр или элемент структуры держал адрес), используйте UINT_PTR вместо текущего типа.
Используйте новые функции класса окон.
Если у вас есть закрытые данные окна или класса, содержащие указатели, коду потребуется использовать следующие новые функции:
Эти функции можно использовать как в 32-разрядных, так и 64-разрядных Windows, но они необходимы для 64-разрядных Windows. Подготовьтесь к переходу с помощью этих функций.
Кроме того, необходимо получить доступ к указателям или дескрипторам в закрытых данных класса, используя новые функции в 64-разрядной версии Windows. Чтобы помочь в поиске этих случаев, следующие индексы не определены в Winuser.h во время 64-разрядной компиляции:
- GWL_WNDPROC
- GWL_HINSTANCE
- GWL_HWNDPARENT
- GWL_USERDATA
Вместо этого Winuser.h определяет следующие новые индексы:
- GWLP_WNDPROC
- GWLP_HINSTANCE
- GWLP_HWNDPARENT
- GWLP_USERDATA
- GWLP_ID
Например, следующий код не компилируется:
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)MyWndProc);
Его следует изменить следующим образом:
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc);
При настройке cbWndExtra член структуры WNDCLASS обязательно зарезервируйте достаточно места для указателей. Например, если в настоящее время резервируются байты размером sizeof(DWORD) для значения указателя, резервируйте sizeof(DWORD_PTR) байтов.
Получите доступ ко всем данным окна и класса с помощью FIELD_OFFSET.
Обычно доступ к данным окна осуществляется с помощью жестко закодированного смещения. Этот метод не переносится в 64-разрядную версию Windows. Чтобы сделать код переносимым, получите доступ к данным окна и класса с помощью макроса FIELD_OFFSET. Не предполагайте, что второй указатель имеет смещение 4.
Типы LPARAM, WPARAMи LRESULT изменяют свой размер в зависимости от платформы.
При компиляции 64-разрядного кода эти типы расширяются до 64 битов, так как обычно они содержат указатели или целые типы. Не смешивайте эти значения с DWORD, ULONG, UINT, INT, intили long значениями. Изучите, как вы используете эти типы, и убедитесь, что вы не сокращаете значения случайно.