Конференция "WinAPI" » Получение текста ошибки при вызове LoadLibrary в сервисе
 
  • Гость (07.08.09 14:44) [0]
    Здравствуйте.

    Для саморазвития заинтересовался такой проблемой.
    Есть 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');



    А вот текст подавленного сообщения как получить - не понятно.
  • Palladin © (07.08.09 14:49) [1]
    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;
  • Гость (07.08.09 15:04) [2]

    > Palladin ©   (07.08.09 14:49) [1]

    Нет, ты не правильно понял.

    После вызова

    hDll := LoadLibrary('libpq.dll');

    if hDll = 0 then
     raise Exception.Create(SysErrorMessage(GetLastError));



    Будет два сообщения:
    В момент вызова LoadLibrary:
    Приложению не удалось запуститься, поскольку comerr32.dll не был найден. Повторная установка приложения может исправить эту проблему.
    И при получении GetLastError
    Не найден указанный модуль.

    Но в сервисе первую ошибку мы не увидим, только вторую, из которой вообше непонятно чего не хватает.
  • Palladin © (07.08.09 15:26) [3]
    Try
    Except
    on e:Exception do WriteLog(e.Message);
    End;

    или я еще чего то не понял?
  • Сергей М. © (07.08.09 15:41) [4]

    > Palladin ©   (07.08.09 15:26) [3]


    Он имеет ввиду, что в сообщении дельфийского исключения нет детальной инф-ции о конкретном отсутствующем модуле.
  • Медвежонок Пятачок © (07.08.09 16:34) [5]
    Будет два сообщения:
    В момент вызова LoadLibrary:
    Приложению не удалось запуститься, поскольку comerr32.dll не был найден. Повторная установка приложения может исправить эту проблему.


    Ни одного не будет.

    А либа у него не грузится потому что текущий каталог процесса сервиса это windows\system32, а не каталог где лежит exe сервиса
  • Гость (07.08.09 19:30) [6]

    > 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 19:32) [7]

    > Медвежонок Пятачок ©   (07.08.09 16:34) [5]

    У меня все загружается нормально, я искуственно создал такую ситуацию, и мне нужно чтобы в евентлоге был понятный текст ошибки, а не тот что можно получить с помощью GetLastError
  • Медвежонок Пятачок © (07.08.09 20:11) [8]
    ожидаемый понятный текст ошибки был не от лоадлайбрари, а от того, что загружаемая либа статически импортирует функции из дгругих либ
  • Leonid Troyanovsky © (10.08.09 14:13) [9]

    > Гость   (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:20) [10]

    > 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.
  • Гость (10.08.09 19:24) [11]

    > Медвежонок Пятачок ©   (07.08.09 20:11) [8]
    >
    > ожидаемый понятный текст ошибки был не от лоадлайбрари,
    > а от того, что загружаемая либа статически импортирует функции
    > из дгругих либ

    Да, я понимаю это. Вариант предложенный Leonid Troyanovsky тоже на дает информации какой именно модуль загрузить не удалось.

    Видимо тут поможет только извращение: перед вызовом loadlibrary, самостоятельно пробегать по таблице импорта загружаемой библиотеки и проверять все ли ей хватает для счастья. Но это уже лишнее, любопытство удовлетворил, спасибо)
 
Конференция "WinAPI" » Получение текста ошибки при вызове LoadLibrary в сервисе
Есть новые Нет новых   [134434   +28][b:0][p:0.002]