finalization
всегда выполняется вызов HtmlHelp(HH_CLOSE_ALL)
, что может приводить к загрузке библиотеки HHCTRL.OCX
. Для обычного приложения это не страшно, просто теряется немного времени на загрузку-выгрузку библиотеки. Но если мы пишем DLL (например, COM-объект или плагин для другого приложения), то выполнение секции finalization
будет происходить внутри DllMain, и попытка загрузить HHCTRL.OCX
приведет либо к зависанию приложения, либо к ошибке Access Violation (в зависимости от версии Windows).
В статье MSDN вполне понятно написано, что можно и что нельзя делать в
DllMain
:
The entry-point function should perform only simple initialization or termination tasks. It must not call theНесмотря на это, вызовLoadLibrary
orLoadLibraryEx
function (or a function that calls these functions).
Similarly, the entry-point function must not call theFreeLibrary
function (or a function that calls FreeLibrary) during process termination.
LoadLibrary
и FreeLibrary
широко распространен в секциях initialization
и finalization
.
Обычно это работает, так как загрузчик Windows достаточно умен, и умеет обходить большинство создаваемых разработчиками приложений проблем. Но иногда, как в данном случае, не справляется.
О другой подобной ошибке можно почитать в статье How you might be loading a DLL during DLL_PROCESS_DETACH without even realizing it.
Эта же ошибка присутствует и в других модулях, сделанных на основе
HTMLHelpViewer
, например в описанном в статье Как использовать справку в программах Delphi модуле HTMLHelpViewerEx
.
С богатой историей ошибки можно ознакомится по ссылкам ниже:
Номер бага | Дата добавления | Описание |
---|---|---|
QC23172 | 06.01.2006 | Unload HTMLHelpViewer |
QC36810 | 20.11.2006 | HTMLHelpViewer hangs dll |
QC48983 | 13.07.2007 | HTMLHelpViewer causing problems in DLLs |
QC67463 | 02.10.2008 | On unload vcl bpl application stopped |
QC68973 | 15.11.2008 | Adding HTMLHelpViewer prevents Excel from shutting down |
QC78998 | 26.10.2009 | HTMLHelpViewer Initialization/Finalization bug |
QC89616 | 12.11.2010 | HTMLHelpViewer.pas bug in initialization finalization methods |
QC102083 | 24.12.2011 | HTMLHelpViewer.pas critical issue in initialization and finalization methods |
Исправление ошибки, сделанное в Update 4 для Delphi XE2, состоит из одной строчки кода:
--- Vcl.HtmlHelpViewer.pas_dxe2u3 +++ Vcl.HtmlHelpViewer.pas_dxe2u4 @@ -301,6 +301,7 @@ procedure THtmlHelpViewer.SoftShutDown; begin + if FInitialized then HtmlHelp(0, nil, HH_CLOSE_ALL, 0); end;
Решаем проблему в DLL
Если вы используете версию Delphi младше XE2, то просто скопируйте файл
HTMLHelpViewer.pas
из папки установки Delphi в папку с исходным кодом приложения, добавьте строку if FInitialized then
в процедуру THtmlHelpViewer.SoftShutDown
, как показано выше, и добавьте этот модуль в проект.
Решаем проблему в EXE
Описанная ошибка не страшна для приложения, так как загрузка-выгрузка
HHCTRL.OCX
выполняется в ходе обычного выполнения программы, когда загрузчик операционной системы свободен от блокировок.
Решать проблему в приложении может понадобиться, если вы загружаете DLL, собранную в Delphi с модулем
HTMLHelpViewer
, содержащим описанную ошибку, и у вас нет возможности исправить эту DLL.
В этом случае необходимо добиться, чтобы библиотека
HHCTRL.OCX
была загружена во время выгрузки проблемной DLL. Это можно сделать, добавив к проекту такой модуль:
unit VCLPatch; interface implementation uses Windows; var HtmlHelpModule: HModule; initialization HtmlHelpModule := LoadLibrary('hhctrl.ocx'); finalization FreeLibrary(HtmlHelpModule); end.Модуль нужно поместить в секцию
uses
проекта как можно раньше, чтобы библиотека HHCTRL.OCX
оставалась загруженной во время выгрузки проблемной DLL.
Об общих вопросах использования справки в Delphi можно почитать в уже упоминавшейся выше статье Как использовать справку в программах Delphi.
Комментариев нет:
Отправить комментарий