-
Здравствуйте. Для саморазвития заинтересовался такой проблемой. Есть dll (libpq.dll), которая требует другие библиотеки (commerr32.dll). Если commerr32.dll отсутствует, то при вызове LoadLibrary('libpq.dll') появится messagebox:
---------------------------
Form1: testDatabases.exe - Не удалось найти компонент
---------------------------
Приложению не удалось запуститься, поскольку comerr32.dll не был найден. Повторная установка приложения может исправить эту проблему.
---------------------------
ОК
---------------------------
В GUI приложении все хорошо, и пользователю понятно чего не хватает. Но в сервисе сообщения не будет, а хотелось бы его вывести в лог. В общем интересуют вопросы: 1. Как подавить это сообщение? 2. Как получить его текст? Подавить сообщение получилось так:
SetErrorMode(SEM_FAILCRITICALERRORS);
hDll := LoadLibrary('libpq.dll');
А вот текст подавленного сообщения как получить - не понятно.
-
Function vtSysErrorString(p_nLastErrorValue:Integer):String; Begin SetLength(Result,10*1024); SetLength(Result,FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, Nil, p_nLastErrorValue, 0, @Result[1], 10*1024, Nil )); End;
-
> Palladin © (07.08.09 14:49) [1]
Нет, ты не правильно понял. После вызова
hDll := LoadLibrary('libpq.dll');
if hDll = 0 then
raise Exception.Create(SysErrorMessage(GetLastError));
Будет два сообщения: В момент вызова LoadLibrary: Приложению не удалось запуститься, поскольку comerr32.dll не был найден. Повторная установка приложения может исправить эту проблему.И при получении GetLastError Не найден указанный модуль.Но в сервисе первую ошибку мы не увидим, только вторую, из которой вообше непонятно чего не хватает.
-
Try Except on e:Exception do WriteLog(e.Message); End;
или я еще чего то не понял?
-
> Palladin © (07.08.09 15:26) [3]
Он имеет ввиду, что в сообщении дельфийского исключения нет детальной инф-ции о конкретном отсутствующем модуле.
-
Будет два сообщения: В момент вызова LoadLibrary: Приложению не удалось запуститься, поскольку comerr32.dll не был найден. Повторная установка приложения может исправить эту проблему.
Ни одного не будет.
А либа у него не грузится потому что текущий каталог процесса сервиса это windows\system32, а не каталог где лежит exe сервиса
-
> Palladin © (07.08.09 15:26) [3]
LoadLibrary не генерирует исключения Из MSDN: Remarks
To enable or disable error messages displayed by the loader during DLL loads, use the SetErrorMode function. Сообщение которое выскакивает при невозможности загрузки библиотеки можно погасить, если вызвать перед LoadLibrary SetErrorMode(SEM_FAILCRITICALERRORS); см. SafeLoadLibrary из SysUtils Но как получить его текст мне не понятно. Возможно есть какой-то механизм, чтобы Windows вызывала CallBack функцию при возникновении таких ошибок..
-
> Медвежонок Пятачок © (07.08.09 16:34) [5]
У меня все загружается нормально, я искуственно создал такую ситуацию, и мне нужно чтобы в евентлоге был понятный текст ошибки, а не тот что можно получить с помощью GetLastError
-
ожидаемый понятный текст ошибки был не от лоадлайбрари, а от того, что загружаемая либа статически импортирует функции из дгругих либ
-
> Гость (07.08.09 19:32) [7]
> У меня все загружается нормально, я искуственно создал такую > ситуацию, и мне нужно чтобы в евентлоге был понятный текст > ошибки, а не тот что можно получить с помощью GetLastError
По коду ошибки можно получить ее описание хоть по Numerical List of Error Codes, т.е. писать это в лог нет обязательно. Узнать больше подробностей можно так:
function SysErrorMessageEx(ErrorCode: Longint): string;
var
Len: Integer;
Buffer: array [0..4095] of Char;
begin
Len := FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM or
FORMAT_MESSAGE_IGNORE_INSERTS,
nil,
ErrorCode,
0,
Buffer,
SizeOf(Buffer),
nil);
SetString(Result, Buffer, Len);
if (Len = 0) then
Result := Format(rserrfmtmsgerr, [SysErrorMessage(GetLastError)]);
Result := Format(rserrfmtmsg, [ErrorCode, Result]);
end;
Но, для подстановки в текст возможных параметров (до 4, AFAIK) потребуется гораздо больше усилий. Поэтому проще, IMHO, писать в лог все те значения, которые будут полезны для анализа причины катастрофы. Например:
var
hdll: THandle;
oldmode: UINT;
fname: String;
..
oldmode := SetErrorMode(SEM_FAILCRITICALERRORS);
fname := ..;
hdll := LoadLibrary(PChar(fname));
if (hdll = 0) then
WriteMessageToLog( Format('Loading library %s error: %s',
[fname, SysErrorMessageEx(GetLastError)]));
SetErrorMode(oldmode);
..
-
> Leonid Troyanovsky © (10.08.09 14:13) [9] > function SysErrorMessageEx(ErrorCode: Longint): string;
Поправлюсь: resourcestring
rserrfmtmsg = 'Code: %d. Message: %s';
rserrfmtmsgerr = 'Formating message error! %s';
function SysErrorMessageEx(ErrorCode: Longint): string;
var
Len: Integer;
Buffer: array [0..4095] of Char;
begin
Len := FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM or
FORMAT_MESSAGE_IGNORE_INSERTS,
nil,
ErrorCode,
0,
Buffer,
SizeOf(Buffer),
nil);
if (Len = 0) then
Result := Format(rserrfmtmsgerr, [SysErrorMessage(GetLastError)]);
else
SetString(Result, Buffer, Len);
Result := Format(rserrfmtmsg, [ErrorCode, Result]);
end;
sorry. -- Regards, LVT.
-
> Медвежонок Пятачок © (07.08.09 20:11) [8] > > ожидаемый понятный текст ошибки был не от лоадлайбрари, > а от того, что загружаемая либа статически импортирует функции > из дгругих либ
Да, я понимаю это. Вариант предложенный Leonid Troyanovsky тоже на дает информации какой именно модуль загрузить не удалось.
Видимо тут поможет только извращение: перед вызовом loadlibrary, самостоятельно пробегать по таблице импорта загружаемой библиотеки и проверять все ли ей хватает для счастья. Но это уже лишнее, любопытство удовлетворил, спасибо)
|