10

我在 .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 函数中的 nil 并在必要时创建。但是我不知道为什么初始化对我不起作用。我在初始化中放了一条调试消息,当它作为 BPL 加载时它不会运行,但是如果我直接编译到我的 dUnit exe 中就会运行。有任何想法吗?德尔福2005。

4

4 回答 4

27

Darian 提醒我,我之前已经回答过这个问题

如果操作系统将 BPL 作为加载相关 EXE 的一部分加载,则不会调用所有初始化部分。相反,只有那些被程序中其他东西显式使用的单元中的部分才会被调用。

如果初始化部分中的代码注册了一个类,然后您只是间接引用该类,例如通过在列表中按名称查找它,那么单元的初始化部分可能不会被调用。将该单元添加到程序中的任何“使用”子句中应该可以解决该问题。

要解决此问题,您可以通过调用InitializePackageSysUtils 单元中的函数自己初始化包的单元。它需要一个模块句柄,您可以通过调用GetModuleHandleAPI 函数来获得它。该函数只会调用尚未初始化的单元的初始化部分。无论如何,这是我的观察。

如果你打电话InitializePackage,那么你也应该打电话FinalizePackage。当您的包被卸载时,将为所有自动初始化的单元调用终结部分。

如果操作系统没有自动加载您的包,那么您正在使用该LoadPackage功能加载它。它为您初始化所有包的单元,因此您无需调用InitializePackage自己。同样,UnloadPackage将为您完成一切。

于 2011-01-06T19:35:40.113 回答
3

在 Quality Central 中仅找到一个参考,但可能还有更多。包括 LoadPackage 引用的解决方法。

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

于 2011-01-06T19:25:13.327 回答
1

在某些情况下,并非 BPL 中的每个单元都必须被初始化。如果我不得不猜测,我会说这个 BPL 在加载时链接到您的程序,而不是稍后动态加载?尝试将您正在使用的设备的名称放入DPR 中程序的使用列表中。那应该解决它。

于 2011-01-06T19:18:59.163 回答
-1

你是如何加载 bpl 的?您是将其留给 Delphi 进行加载还是手动加载 bpl?如果您手动加载 bpl,您是将其加载为“直接”dll 还是使用 LoadPackage 将其加载为 delphi 包?我认为要么让 vcl 加载它(通过需要处理)或使用 LoadPackage 来让 vcl 运行初始化部分...

于 2011-01-06T19:17:46.820 回答