Скачал как-то я 64-битную версию Windows7 c
Technet, чтобы проверить работоспособность своих приложений. Признаюсь: за рутиной никак не доходили руки почитать про особенности 64-х разрядных систем, поэтому в этих вопросах я плаваю основательно, и наличие огромных граблей в работе программы меня совсем не удивило. Будь я
титаном, непременно бы догадался о причинах появления этого садового инструмента. А я в начале впал в ступор, потом не верил своим глазам, и лишь потом взял чашечку кофе и начал просветлятся. Но обо всем по порядку.
Есть у меня модуль, которые проверяет цифровые подписи драйверов. Обычный такой среднестатистический модуль килобайт на 50. В общем, ничего примечательного. Тестекйз этого модуля под win64 падал в разных местах с удивительными для меня эффектами. Подробное изучение происходящего привело меня к причине ошибочного поведения - функции FileExists(). Она никак не хотела видеть модули, находящиеся в системном каталоге windows\system32\drivers. Причем, если скопировать, например, из отладчика путь к модулю C:\Windows\System32\drivers\acpi.sys и выполнить его в командной строке - все работает. Из программы - фигвам. Первое, что приходит в голову, это то, что глючит рабочая лошадка - FileExists. Тут же были испробованы альтернативные способы добраться до файлов, но результат был стабилен и одинаков - такого драйвера в каталоге нет. Да и эксперименты с параметрами функции показали, что проблема только с системными каталогами. Тут я вспомнил слова одного моего товарища: "Компьютеру надо верить!" Если он говорит, что нет файла значит его там действительно нет. А то, что FAR видит этот файл - так это проблемы FAR-а. Далее я легким движением руки программно получил список содержимого каталога C:\Windows\System32\drivers\ и пришел к выводу, что передо мной на самом деле каталог C:\Windows\SysWOW64\drivers\. Там действительно файла acpi.sys нет - налицо транспарентная подмена системных папок, что в новых поколениях Windows на каждом шагу. В качестве дальнейшего источника просветления я выбрал MSDN, где нашел
статейку и
нужные функции. Так родился скупой, как мужская слеза, код:
function DisableRedirection(
out Value: Pointer): Boolean;
const
DIS_ALIAS = 'Wow64DisableWow64FsRedirection';
type
TDisableRedirectionFunc =
function(OldValue: Pointer): Boolean; stdcall;
var
DisRedir: TDisableRedirectionFunc;
begin
@DisRedir := GetProcAddress(GetModuleHandle(kernel32), DIS_ALIAS);
if Assigned(DisRedir)
then
Result := DisRedir(@Value)
else
Result := False;
end;
function EnableRedirection(Value: Pointer): Boolean;
const
REVERT_ALIAS = 'Wow64RevertWow64FsRedirection';
type
TRevertRedirectionFunc =
function(OldValue: Pointer): Boolean; stdcall;
var
RevRedir: TRevertRedirectionFunc;
begin
@RevRedir := GetProcAddress(GetModuleHandle(kernel32), REVERT_ALIAS);
if Assigned(RevRedir)
then
Result := RevRedir(@Value)
else
Result := False;
end;
Ну и напоследок несколько комментариев:
- Использовать эти подпорки следует с осторожностью и четко понимая, зачем это нужно. Выключив подмену, вы отрезаете себе путь к загрузке любой системной 32-х разрядной библиотеки.
- Как видно из документации, управление редиректом осуществляется только в вызывающем потоке. Этим можно воспользоваться.
- 64-х разрядного компилятора мы ждем 3-ий год. Видимо, известная поговорка опять сработала. Пока что придется довольствоваться WOW- песочницей. Про FreePascal на нынешнем этапе жизненного пути я думать боюсь.
- В каталоге system32 лежат 64-х разрядные компоненты, в SysWOW64 - 32-х разрядные. Изрядная путаница в названиях не должна смущать настоящего windows-разработчика. Путаница - это священная традиция, без которой создание программ под windows попросту невозможно.