Преобразование указателей 16:16


Время от времени может возникать нужда преобразовывать указатели 16:16 в 32-разрядные указатели. Функции GetVDMPointer32W и WOWGetVDMPointer выполняют эту задачу до конца. Вызовите GetVDMPointer32W из 16-разрядного кода и WOWGetVDMPointer из 32-разрядного кода, чтобы преобразовать указатели 16:16 в 32-разрядные указатели. Кроме того, функции GlobalFix, GlobalUnfix, GlobalWire и GlobalUnwire должны также вызываться из 16-разрядного кода. Дополнительную информацию об этих функциях, см. в документации SDK 16-разрядных Windows.

Windows Me/98/95: Если Вы используете функцию GetVDMPointer32W или WOWGetVDMPointer и влияете на указатель 16:16, представляющий перемещаемый блок диспетчера памяти глобальных данных, то важно, чтобы Вы сначала вызывали функцию GlobalFix или GlobalWire для части сегмента указателя. Если Вы этого не сделаете, то 16-разрядный диспетчер памяти глобальных данных может переместить этот блок в ходе, когда ваш процесс выполняет 32-разрядный код. Если это случится, то линейный адрес, возвращаемый функцией GetVDMPointer32W или WOWGetVDMPointer станет недопустимым. Отлаженная версия системы генерирует предупреждения, о вызовах функции GetVDMPointer32W для незакрепленных сегментов.

Функция WOWGetVDMPointerFix подобна WOWGetVDMPointer, но гарантирует то, что указанная память не будет перемещаться уплотнителем (компактором) памяти глобальных данных до тех пор, пока не будет вызвана функция WOWGetVDMPointerUnfix. В случае необходимости, WOWGetVDMPointerFix выполняет подразумеваемую операцию GlobalFix на селекторе. Если селектор назначен как неподвижный блок, или если он не от диспетчера памяти глобальных данных, никаких специальных действий не предпринимается. Вы должны использовать эту функцию вместо того, чтобы вызывать отдельно GlobalFix, потому что ее легче и быстрее использовать, чем вызывать  и функцию GlobalFix, и функцию WOWGetVDMPointer.

Функция WOWGdtVDMPointerUnfix получает адрес 16:16 и отменяет воздействие WOWGetVDMPointerFix на сегменте (часть смещения игнорируется). Эта функция должна вызываться только тогда, когда линейный адрес больше не нужен, чтобы избежать фрагментации. Она работает быстрее, чем функция GlobalUnfix и правильно обрабатывает (то есть, игнорирует) селекторы, которые не от 16-разрядного диспетчера памяти глобальных данных.

Пока Вы выполняете 32-разрядный код, вызываемый через унифицированный "переходник ", 16-разрядная сторона "переходника" полностью блокирована до тех пор, пока Вы не возвратите значение или не уступите. Поэтому, в большинстве случаев, Вы не должны закреплять или связывать память. Поэтому, функция WOWGetVDMPointerFix идентична функции WOWGetVDMPointer (она не вызывает GlobalFix), а WOWGetVDMPointerUnfix не имеет никакого воздействия в cрeде Windows NT.

Если Вы планируете использовать только Windows NT, а ваш 32-разрядный код приводит к системе обмена сообщениями (при помощи вызова функции такой как SendMessage, BroadcastSystemMessage, GetMessage, PeekMesrage, MessageBox или DialogBox), Вы должны вызвать или GlobalFix, или GlobalWire раньше срока на 16-разрядной стороне или обновить ваши 32-разаядные указатели после того, как уступающая вызов функция завершила работу при помощи вызова функции WOWGetVDMPointer.

Если Вы планируете использовать обе платформы, то есть два способа, которые Вы можете использовать. Самый легкий способ состоит в том, чтобы на 16-разрядной стороне "переходника " сначала закрепить все сегменты в памяти, используя функции GlobalFix или GlobalWire. В 32-разрядном коде, используется функция WOWGetVDMPointer, а не GOWGetVDMPointerFix, потому что сегменты уже закреплены в памяти. После возвращения 32-разрядного кода, вызовите GlobalFix * или GlobalUnwire в 16-разрядном коде. Это гарантирует то, что ваши 32-разряднле указатели остаются допустимыми, независимо от платформы, даже тогда, когда 16-разрядный менеджер памяти глобальных данных уплотняет глобальную кучу. Недостаток этого подхода состоит в том, что много сегментов может быть оставлено закрепленными в памяти на длительный период времени, потенциально служащих причиной нехватки памяти из-за ее фрагментации.

* Примечание переводчика: видимо здесь должен быть вызов функции GlobalUnFix, так как сегменты памяти уже закреплены предыдущим вызовом GlobalFix. Но Microsoft виднее - проверил по 3-м выпускам MSDN и все как в тесте.

 Самый эффективный способ, который к тому же воздействует на обе платформы, требует, чтобы Вы использовали функцию WOWGetVDMPointerFix и WOWGetVDMPointerUnfix. В среде Windows NT, 32-разрядные указатели могут все еще оказывать влияние на !6-разрядные перемещения памяти, если 32-разрядный код приводит и системе обмена сообщениями. После каждого вызова, который может привести к системе передачи сообщений, ваши 32-разрядные указатели сбрасываются, используя функцию WOWGetVDMPointerUnfix. Если Вы продолжаете использовать указатель, повторите первоначальный вызов функции WOWGetVDMPointerFix, чтобы обновить указатель. Недостаток этого подхода состоит в том, что он не может использоваться, если вызванная функция, которая приводит к системе обмена сообщениями, использует 32-разрядные указатели, которые Вы предусматриваете после приведения к этой системе. Если Вы не можете определить, будет ли эта проблема, должен быть выбран первый метод, как более безопасный.

Назад в оглавление
На главную страницу темы
Перевод 25.10.2007 16:35 ©Copyright V. Sokovikov
Hosted by uCoz