Приложение Delphi связывается с программой, которая иногда завершается сбоем - поставщик обвиняет мое приложение Delphi - PullRequest
4 голосов
/ 25 июня 2009

Я написал Delphi DLL, которая связывается со сторонней программой через COM. Некоторые пользователи сообщают, что иногда происходит сбой сторонней программы. Другие, использующие программное обеспечение таким же образом, никогда не сталкивались с авариями. Когда происходит сбой, сторонняя программа просто становится недоступной в моем приложении DLL.

Поставщик клянется, что это проблема с тем, как кодируется DLL Delphi, хотя он не видел исходного кода и не может сказать, что делает DLL, чтобы вызвать сбой, но они знают, что это «что-то» .

Помимо того, что я считаю, что сторонняя программа не должна аварийно завершать работу из-за незначительной проблемы в моей DLL, давайте предположим, что в моей DLL есть что-то, что требует исправления.

Как я могу определить, как это может вызывать мое приложение? У кого-нибудь есть опыт общения через COM с такой сверхчувствительной программой, как эта? Есть ли некоторые общие вещи, которые нужно искать, которые могут привести к сбою сторонней программы?

Ответы [ 6 ]

4 голосов
/ 25 июня 2009

Посмотрите на Quality Central для отчета 58409.

Речь идет о маске FPU и Dll.

Чтобы объяснить это вкратце:

Настройки маски FPU определяют, как обрабатываются исключения с плавающей запятой.

Если у вас есть, например, Applicaion_A (кодированный кем-то еще), который загружает Dll_A (также кодированный кем-то еще) и Dll_B (кодированный вами), а ваш Dll меняет маску FPU, то это изменение действительно для Application_A и Dll_A также.

Давайте сделаем пример: Например, вы установили WinZIP, SubVersion и т. Д., Который регистрирует дополнительные функции в проводнике Windows (всплывающее меню при щелчке правой кнопкой мыши), и теперь вы вызываете TOpenDialog из вашего application.exe, тогда эти дополнительные функции могут поставить под угрозу ваши настройки FPU.

Надеюсь, это поможет. (Дополнительный совет: возьмите Sysinternal, чтобы увидеть, какие DLL загружаются вашим приложением)

4 голосов
/ 25 июня 2009
  1. Сделайте клиента счастливым.
  2. Не думайте, что это не ваша dll, это может быть. Даже если « Другие, использующие программное обеспечение идентичным образом, никогда не сталкивались с сбоем », возможно, что с другими данными это делает разные вещи…
  3. Я бы посоветовал вам настроить запись в текстовый файл в «специальной» диагностической версии.
  4. Записывайте все, ваши параметры, ваши исключения и шаги, которые вы проходите. Может быть, даже начало и конец каждой функции и любой другой строки.

Вот как это может выглядеть ...

Loaded DLL
Started MyFunction1 with parameters: 1,4,hello
   1
   2
   ...
   500
Ended MyFunction1

чтобы сделать это, я бы настроил несколько функций (в их собственном модуле):

// opens a text file (fixed name), and appends to it.
function InitializeLog; 

// closes the file
function CloseLog;      

//add a log line.
function Log(message:string='', startNewFunction:boolean:False); 

вы бы назвали это так:

function MyFunction1(Integer,Integer,String);
begin
  try
    Log('Loaded DLL');

    //use inttostr and do some string concats to get the params
    Log('Started MyFunction1 with parameters: 1,4,hello',true); 

    //Then every other line:
    Log; 
    //this would increment a global variable FuncLine:Integer
    //and write it to the file.    

  except
    On E:Exception (Log('***'+E.Message));
  end;
end;

Что-то вроде этого должно иметь {$ DEFINE} для включения этих функций ведения журнала, чтобы включить / отключить ведение журнала диагностики.

Это также может быть полезно.

3 голосов
/ 25 июня 2009

Рассматривали ли вы использовать MadExcept ? Если вы поймете ошибку в интерфейсных методах, вы можете либо зарегистрировать стек вызовов, либо показать пользователю диалог и вернуть стандартный EOleSysError обратно в вызывающий exe.

Примерно так:

  except
    on e: Exception do
    begin
      MadExcept.HandleException();

      raise EOleSysError.Create('InitializeObject Failed',
        ErrorNumberToHResult(1 + CODE_BASE), 1);
    end;

Если приложение зависает, но не выдает исключение и вы можете увидеть, что происходит, с помощью утилиты MadExcept madTraceProcess. Это позволит вам сгенерировать стек вызовов для работающего приложения. Ваша dll не будет в основном потоке, но вы сможете увидеть свой стек вызовов. Это хороший способ узнать, действительно ли ваша dll что-то делает, когда происходит зависание.

У меня есть COM dll, который взаимодействует с exe, который не использует MadExcept, и этот подход хорошо сработал для меня.

2 голосов
/ 26 июня 2009

Я не знаю, как работает madExcept и т. Д., Но я часто использую jclDebug.pas + JclHookExcept.pas (из библиотеки JEDI JCL). Это делает хук Windows API, поэтому он перехватывает все (!) Исключения, даже если вы делаете что-то вроде этого:

try
  raise exception.create('test');
except
  //eat exception
end;

Обычно вы не видите это исключение, потому что оно "съедено" ... Но с помощью ловушки вы получите все исключения. Например: я однажды получил «катастрофический сбой» в Midas.dll, и через ловушку я увидел ошибку «потеря соединения с базой данных» в dll перед этим исключением, поэтому я знал, что произошло. (btw: JclHookExcept.pas = hook, jclDebug.pas = strack trace).

Теперь я вижу, что JclHookExcept.pas также имеет процедуру "JclHookExceptionsInModule", поэтому вы можете принудительно (?) Перехватывать все исключения из определенной библиотеки ...

Демонстрационный код:

procedure AnyExceptionNotify(ExceptObj: TObject; ExceptAddr: Pointer; OSException: Boolean);
begin
  //log exception
end;

initialization
  // Start Exception tracking
  JclStartExceptionTracking;
  JclTrackExceptionsFromLibraries;
  JclStackTrackingOptions := [stStack, stRawMode, stAllModules];
  // Assign notification procedure for hooked RaiseException API call. This
  // allows being notified of any exception
  JclAddExceptNotifier(AnyExceptionNotify);
2 голосов
/ 25 июня 2009

Если я правильно понял ситуацию, к сожалению, вы ничего не сможете сделать на своей стороне, если ваша DLL не падает, а вызываемая сторонняя программа просто перестает отвечать на запросы. Сбой в их коде, но вызван только вашей DLL, вызывающей его. Журнал отладки действительно должен быть сделан в их приложении.
Что вы можете сделать, это записать все вызовы, которые ваша DLL делает с этой сторонней программой, с параметрами и некоторой контекстной информацией.
Затем, глядя на последний след до аварии, вы можете получить некоторую информацию ...

2 голосов
/ 25 июня 2009

Если их программа вылетает, когда вы используете опубликованный интерфейс, я уверен, что с этим что-то не так. Доказать это совсем другое.

Можете ли вы надежно продублировать проблему с помощью небольшого приложения Delphi, которое вы можете передать продавцу? Видя воспроизводимый сбой, можно убедить их в том, что им нужно исправить. По крайней мере, это может помочь определить, что, по их мнению, вы делаете «неправильно», и подсказать, как это сделать «правильно».

Вы также можете попытаться продублировать ошибку, используя C # или даже VBScript.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...