Delphi XE2: вызов WinAPI EnumResourceNames вызывает нарушение прав доступа на платформе Win64 - PullRequest
5 голосов
/ 12 января 2012

Запуск следующего кода на платформе Delphi XE2 Win32 работает.Однако тот же код, скомпилированный на платформе win64, вызовет нарушение прав доступа в «EnumRCDataProc» при запуске в режиме отладки:

procedure TForm2.Button1Click(Sender: TObject);
  function EnumRCDataProc(hModule: THandle; lpszType, lpszName: PChar; lParam:
      NativeInt): Boolean; stdcall;
  begin
    TStrings(lParam).Add(lpszName);
    Result := True;
  end;

var k: NativeInt;
    L: TStringList;
    H: THandle;
begin
  H := LoadPackage('resource.bpl');
  L := TStringList.Create;
  try
    EnumResourceNames(H, RT_RCDATA, @EnumRCDataProc, NativeInt(L));
    ShowMessage(L.Text);
  finally
    L.Free;
    UnloadPackage(H);
  end;
end;

При отладке кода в Delphi XE2 IDE на платформе Win64 я обнаружил значение hModuleв EnumRCDataProc не совпадает с переменной H. Я подозреваю, что это может быть что-то не так с параметрами, которые я создал для EnumRCDataProc.Однако я не могу понять, как.Есть идеи?

1 Ответ

5 голосов
/ 12 января 2012

Проблема в том, что вы сделали EnumRCDataProc локальной процедурой.Вы должны переместить его за пределы метода.

function EnumRCDataProc(hModule: HMODULE; lpszType, lpszName: PChar; lParam:
    NativeInt): BOOL; stdcall;
begin
  TStrings(lParam).Add(lpszName);
  Result := True;
end;

procedure TForm2.Button1Click(Sender: TObject);
var k: NativeInt;
    L: TStringList;
    H: HMODULE;
begin
  H := LoadPackage('resource.bpl');
  L := TStringList.Create;
  try
    EnumResourceNames(H, RT_RCDATA, @EnumRCDataProc, NativeInt(L));
    ShowMessage(L.Text);
  finally
    L.Free;
    UnloadPackage(H);
  end;
end;

При первой проверке я ожидал, что компилятор выдаст ошибку с вашим кодом:

E2094 Локальная процедура / функция 'Обратный вызов'присваивается переменной процедуры

Но это не так.Я покопался немного глубже и обнаружил, что параметр обратного вызова для EnumResourceNames объявлен как тип Pointer.Если бы перевод заголовка объявил это как типизированный параметр обратного вызова, то вышеприведенное сообщение об ошибке действительно было бы отправлено.На мой взгляд, перевод заголовка плох в этом отношении.Кажется, очень мало чего можно добиться, отказавшись от безопасности системы типов.

Тот факт, что ваш код работает в 32-битном коде, является просто счастливым совпадением, основанным на деталях реализации.Ваша удача заканчивается на 64 бит.Опять же, если бы система проверки типов была включена, компилятор мог бы сразу сказать вам, что было не так.

Некоторые другие комментарии:

  1. В EnumRCDataProc есть пара неверныхТипы в своем объявлении: hModule должен иметь тип HMODULE, а результат функции должен быть BOOL.
  2. LoadPackage - довольно тяжелый подход к получению дескриптора модуля.Я предпочел бы видеть LoadLibraryEx с опциями LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE и LOAD_LIBRARY_AS_IMAGE_RESOURCE.
...