Инициализация модуля 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.

http://qc.embarcadero.com/wc/qcmain.aspx?d=61968

Не каждая единица в BPL обязательно будет инициализирована при определенных обстоятельствах. Если бы мне пришлось угадывать, я бы сказал, что этот BPL связан с вашей программой во время загрузки и не загружается динамически позже? Попробуйте ввести название используемого вами устройства в список использований программы в DPR. Это должно исправить это.

Как вы загружаете bpl? Вы оставляете это Delphi, чтобы сделать загрузку, или вы вручную загружаете bpl? Если вы загружаете bpl вручную, загружаете ли вы его как "прямую" dll или используете LoadPackage для загрузки его как пакета delphi? Я думаю, что для запуска разделов инициализации, выполняемых vcl, требуется либо позволить vcl загрузить его (посредством обработки по требованию), либо использовать LoadPackage...

Другие вопросы по тегам