Инициализация модуля Delphi не всегда вызывается - PullRequest
9 голосов
/ 06 января 2011

У меня есть блок внутри .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 ]

24 голосов
/ 06 января 2011

Дариан напоминает мне, что Я уже отвечал на это :

Если операционная система загружает BPL как часть загрузки соответствующего EXE-файла, будут вызваны не все разделы инициализации. Вместо этого вызываются только разделы из модулей, которые явно используются чем-то другим в программе.

Если код в разделе инициализации регистрирует класс, и тогда вы только косвенно ссылаетесь на этот класс, скажем, ища его по имени в списке, то раздел инициализации модуля может не вызываться. Добавление этого модуля к любому условию «использования» в вашей программе должно решить эту проблему.

Чтобы обойти эту проблему, вы можете самостоятельно инициализировать модули пакета, вызвав функцию InitializePackage в модуле SysUtils. Требуется дескриптор модуля, который можно получить, вызвав функцию API GetModuleHandle. Эта функция будет вызывать только разделы инициализации модулей, которые еще не были инициализированы. Во всяком случае, это мое наблюдение.

Если вы звоните InitializePackage, то вам также следует позвонить FinalizePackage. Когда ваш пакет будет выгружен, разделы финализации будут вызваны для всех модулей, которые были автоматически инициализированы.

Если ОС не автоматически загружает ваш пакет, то вы загружаете его с помощью функции LoadPackage. Он инициализирует все модули пакета для вас, поэтому вам не нужно звонить InitializePackage самостоятельно. Аналогично, UnloadPackage завершит все для вас.

3 голосов
/ 06 января 2011

В Quality Central найдена только одна ссылка, но может быть и больше.Включает обходной путь, на который ссылается LoadPackage.

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

1 голос
/ 06 января 2011

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

0 голосов
/ 06 января 2011

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

...