Delphi Loadlibrary возвращает 0 (LastErrorcde = 3221225616) Что это означает?

Мне нужно использовать стороннюю dll в нашем основном приложении. Когда я статически связываюсь с предоставленной DLL, она работает нормально, и я могу экспортировать функции DLL. Но мы не хотим, чтобы наше основное приложение зависело от этой DLL при запуске, поэтому я попытался динамически загрузить DLL, когда она мне нужна:

DLLHandle := LoadLibrary('3rdparty.dll');
ret := GetLastError();
if DLLHandle = 0 then
begin
  err := SysErrorMessage(ret);
  Writeln(err);
end //...

но не работает: функция LoadLibrary возвращает 0, а LastErrorcode - 3221225616. Поскольку я не знаю, что делаю неправильно, я попробовал то же самое (на том же компьютере), закодированный в c, и он работает: но что не это работает с delphi? : Я вызываю ту же функцию LoadLibrary на той же dll!

Когда я отслеживаю с помощью ProcMon, я вижу, что загружается сторонняя dll, а также загружаются зависимые и зависимые библиотеки сторонней dll. : Так windows наверняка находит DLL. Но где-то в процессе загрузки происходит сбой: когда я пытаюсь загрузить DLL с помощью LoadLibraryEX с помощью DONT_RESOLVE_DLL_REFERENCES или LOAD_LIBRARY_AS_DATAFILE, он также работает (но я не могу вызвать необходимые функции ...)

У меня нет идей: надеюсь, вы, ребята, можете мне еще помочь ...

спасибо в нареч. Кристоф


person user426722    schedule 20.08.2010    source источник


Ответы (5)


Это работает?

var
  SavedCW: word;

...

SavedCW := Get8087CW;
Set8087CW(SavedCW or $7);
DLLHandle := LoadLibrary('3rdparty.dll');
Set8087CW(SavedCW);
if DLLHandle = 0 then
begin
  ret := GetLastError();  
  err := SysErrorMessage(ret);
  Writeln(err);
end //...

Некоторое обсуждение:

Код ошибки 3221225616 при запросе Google кажется результатом неправильной операции с плавающей запятой. Теперь это кажется очень техническим; действительно, какое отношение загрузка библиотеки имеет к вычислениям с плавающей запятой? Управляющее слово с плавающей запятой (CW) - это битовое поле, в котором биты определяют, как процессор должен обрабатывать ошибки с плавающей запятой; на самом деле довольно часто с неожиданными ошибками с плавающей запятой можно справиться, изменив один из этих битов на 1 (что, кстати, является состоянием по умолчанию). В качестве другого примера см. этот мой вопрос, в котором я получаю совершенно неожиданный ошибка деления на ноль, которая устраняется установкой бита «div на ноль» управляющего слова в 1.

person Andreas Rejbrand    schedule 20.08.2010
comment
Спасибо за помощь, но, к сожалению, это не помогает. Я все время получаю result = 0 и errorcode = 3221225616 Все идеи приветствуются ... - person user426722; 21.08.2010
comment
Теперь я изменил 4 доллара (двоичные 100) на 7 долларов (двоичные 111). Это помогает? (Я подозреваю, что LSB вызывает беспокойство; в этом случае может быть достаточно сделать $ 1 (двоичный 001).) - person Andreas Rejbrand; 21.08.2010
comment
Да, тогда это работает, спасибо: я тоже пробовал с 5, а потом это тоже работает: я очень благодарен за оба ваших быстрых ответа, но я также хочу понять, что происходит: вы можете немного объяснить это мне или указать мне в правильном направлении, где я могу прочитать об этом? Большое спасибо Кристофу - person user426722; 21.08.2010
comment
Прочтите мою ссылку и ссылку Дэнни; это должно помочь вам понять. - person Craig Stuntz; 21.08.2010
comment
Кристоф: Биты управляющего слова с плавающей запятой управляют (среди прочего) тем, как FPU обрабатывает различные типы ошибок с плавающей запятой - деление на ноль, переполнение, недостаточное заполнение и т. Д. FPU может либо игнорировать ошибку, либо вызывать аппаратное исключение. Большинство RTL C / C ++ отключают исключения FP. Приложения Delphi устанавливают контрольное слово для включения определенных исключений FP. Вы можете отключить исключения FP по своему усмотрению, но тщательно подумайте о последствиях игнорирования ошибок, которые, по сути, указывают на то, что в вашем приложении работают неверные данные. - person dthorpe; 21.08.2010
comment
спасибо за всю вашу информацию: что я нахожу наиболее странным, так это то, что когда я статически связываю, это просто сработало: означает ли это, что fp cw отличается, когда приложение все еще загружается? - person user426722; 21.08.2010
comment
Для получения дополнительной информации: некоторое время назад я писал об аналогичной проблеме, анализируя флаги контрольного слова 8087: wiert.wordpress.com/2009/05/06/ - person Jeroen Wiert Pluimers; 21.08.2010
comment
Когда приложение загружается, библиотеки DLL загружаются очень скоро в процессе, скорее всего, до того, как Delphi RTL установит для управляющего слова 8087 значение, которое ему больше всего нравится. Библиотеки DLL, вероятно, ожидают, что контрольное слово 8087 будет значением операционной системы по умолчанию. - person Jeroen Wiert Pluimers; 21.08.2010

3221225616 = STATUS_FLOAT_INVALID_OPERATION. Мое дикое предположение состоит в том, что FPU CW отличается в ваших приложениях Delphi и C, и что инициализация вашей DLL чувствительна к этому.

person Craig Stuntz    schedule 20.08.2010

Возможно, связано: http://discuss.joelonsoftware.com/default.asp?joel.3.88583.15

Попробуйте использовать () в SafeLorary Delphi RTL вместо Win32 LoadLibrary. Эта функция сохраняет контрольное слово FP перед вызовом LoadLibrary и устанавливает его обратно на то, что нужно Delphi, после возврата LoadLibrary.

person dthorpe    schedule 20.08.2010

Я думаю, вам следует сообщить разработчикам 3rdparty.dll об ошибке в их DLL.

person Alex    schedule 21.08.2010

Я знаю, что это старый поток, но я только что столкнулся с той же проблемой с DLL, написанной на VB.

Это решение работает как для x86, так и для x64

var  ret:cardinal;
     em:TArithmeticExceptionMask;
begin
  result:= 1;
  If Lib <> 0 Then exit;     // already loaded
  em:=GetExceptionmask;
  SetExceptionmask(em+[exInvalidOp,exZeroDivide,exOverflow, exUnderflow]);
  Lib := LoadLibrary(DLLname);
  SetExceptionmask(em);
  ret := GetLastError;
  if ret<>0 then
    raise exception.create(SysErrorMessage(ret));
person Andy k    schedule 14.01.2016