Типографская проблема в Windows 10 (DWORD и ULONG_PTR в WinAPI) - PullRequest
0 голосов
/ 03 декабря 2018

В Windows 7, компилятор VS2012

PostQueuedCompletionStatus(hCompletionPort, 0, (DWORD) pContext, &pOverlap->m_ol);

вышеуказанный вызов API работает нормально.

Но в компиляторе Windows 10 и VS2017 переменные-члены в структуре pContext не являютсядоступны.

Когда мы меняем значение с DWORD на ULONG_PTR, оно нормально работает в Windows 10

PostQueuedCompletionStatus(hCompletionPort, 0, (ULONG_PTR) pContext, &pOverlap->m_ol);

В чем причина такого поведения?

1 Ответ

0 голосов
/ 03 декабря 2018

Скорее всего, новая сборка отличается не только версией Windows, но вы также компилируете для 64-битной, тогда как ранее вы компилировали для 32-битной.

Обновление : OP уточнил, что обе сборки являются 64-битными, но это легко объяснить;см. ниже.

Это приведение к DWORD концептуально неверно даже в Windows 7/32 бит.Действительно, определение API требует ULONG_PTR, который является целым типом без знака, достаточно большим, чтобы содержать указатель без потери данных.Таким образом, это 32-битный тип при компиляции для 32-битных, 64-битных при компиляции для 64-битных.

Вместо этого вы приводите указатель к DWORD;DWORD всегда является 32-битным беззнаковым типом, поэтому при сборке для 32-битной Windows все идет гладко (указателям нужно не более 32-битной для того, чтобы с другой стороны они остались целыми), но в 64-битной Windows вы теряете 32-битную верхнюювашего указателя.

Теперь, это работает даже на 64-битной Windows 7 ;почему?

Как объяснено в комментариях, этот указатель исходит из кучи, и по умолчанию в Windows 7 куча начинает предоставлять память из «малой» части 64-битного адресного пространства;следовательно, если вы не потребляете много памяти, вы всегда будете получать адреса с старшими 32 битами в ноль, так что они выживут даже с отрубленными старшими 32 битами.

Этоизменено начиная с Windows 8 , поскольку ASLR (по умолчанию включается компоновщиком при сборке 64-битных исполняемых файлов) рандомизирует положение кучи в виртуальном адресном пространстве, что означает, что вы получите указатели с ненулевым верхним 32биты, которые будут сильно повреждены актерами на DWORD.

Короче говоря: исправьте ваш каст 1 и все будет работать нормально.Кроме того, в будущем всегда будьте осторожны с приведением указателя к целочисленному типу, который не заканчивается на _ptr или _PTR - есть хорошие шансы, что вы делаете ошибку.


Примечания

  1. Строго говоря, стандарт IIRC требует "прохождения" void *, чтобы эти приведения работали правильно, т.е.гарантируется только для void * (а может быть char *? Мне придется проверить стандарт), поэтому должно быть (ULONG_PTR)(LPVOID)pContext, если pContext уже не void *.Тем не менее, это Win32, я уверен, что он гарантированно будет работать даже без дополнительного приведения.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...