Инициализация модуля Delphi не всегда вызывается
У меня есть модуль внутри.bpl, и мне нужен список строк для новой функции, которую я написал. Я хочу, чтобы список строк сохранялся на протяжении всего жизненного цикла приложения, чтобы каждый вызов мог основываться на том, что обнаружил предыдущий вызов.
Поэтому он объявлен глобально в модуле, и я инициализирую его в разделе "Инициализация", например:
var
ProductLookup : TStrings;
...
function foo : boolean;
begin
result := (ProductLookup.IndexOfName('bar') >=0); //blow up here. It's nil. Why?
end;
....
initialization
ProductLookup := TStringList.Create; // This should get run, but doesn't.
finalization
FreeAndNil(ProductLookup);
end.
Когда я его проверил, все было хорошо. Но когда он запускался из основного приложения, я был взорван с нарушением прав доступа, потому что список строк был нулевым. Так что теперь я прибегаю к проверке на nil в функции foo и создаю при необходимости. Но я в недоумении, почему инициализация не работает для меня. Я помещаю сообщение об отладке прямо в инициализацию, и оно не запускается, когда он загружается как BPL, но запускается, если я компилирую прямо в свой dUnit exe. Есть идеи? Delphi2005.
4 ответа
Дариан напоминает мне, что я отвечал на это раньше:
Если операционная система загружает BPL как часть загрузки соответствующего EXE-файла, будут вызваны не все разделы инициализации. Вместо этого вызываются только разделы из модулей, которые явно используются чем-то другим в программе.
Если код в разделе инициализации регистрирует класс, а затем вы только косвенно ссылаетесь на этот класс, скажем, ища его по имени в списке, то раздел инициализации модуля может не вызываться. Добавление этого модуля к любому условию "использования" в вашей программе должно решить эту проблему.
Чтобы обойти эту проблему, вы можете самостоятельно инициализировать модули пакета, вызвав
InitializePackage
функция в блоке SysUtils. Требуется дескриптор модуля, который вы можете получить, вызвавGetModuleHandle
API-функция. Эта функция будет вызывать только разделы инициализации модулей, которые еще не были инициализированы. Во всяком случае, это мое наблюдение.Если вы позвоните
InitializePackage
тогда вам также следует позвонитьFinalizePackage
, Когда ваш пакет будет выгружен, разделы финализации будут вызваны для всех модулей, которые были автоматически инициализированы.Если ОС не загружает ваш пакет автоматически, вы загружаете его с
LoadPackage
функция. Он инициализирует все модули пакета для вас, поэтому вам не нужно звонитьInitializePackage
сам. Точно так же,UnloadPackage
завершит все для вас.
Только нашел одну ссылку в Quality Central, но может быть больше. Включает обходной путь, на который ссылается LoadPackage.
Не каждая единица в BPL обязательно будет инициализирована при определенных обстоятельствах. Если бы мне пришлось угадывать, я бы сказал, что этот BPL связан с вашей программой во время загрузки и не загружается динамически позже? Попробуйте ввести название используемого вами устройства в список использований программы в DPR. Это должно исправить это.
Как вы загружаете bpl? Вы оставляете это Delphi, чтобы сделать загрузку, или вы вручную загружаете bpl? Если вы загружаете bpl вручную, загружаете ли вы его как "прямую" dll или используете LoadPackage для загрузки его как пакета delphi? Я думаю, что для запуска разделов инициализации, выполняемых vcl, требуется либо позволить vcl загрузить его (посредством обработки по требованию), либо использовать LoadPackage...