пятница, 23 октября 2009 г.

Компьютеру надо верить.

Скачал как-то я 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 попросту невозможно.

1 комментарий:

Анонимный комментирует...

Очень познавательная статья получилась! Респект автору! :)