为了帮助我们模块化整体式应用程序,我们正在设置用于调试版本的包,同时仍然编译为发布版本的单个exe。
我们的一个软件包(EAUtils(包含一个现在正在生产[DCC Error] E2201 Need imported data reference ($G) to access 'SMsgDlgWarning' from unit 'SystemUtils'
的单元。
在构建 EAUtils 包本身时会发生这种情况。我还不喜欢构建依赖于 EAUtils 的软件包。EAUtils 仅依赖于 rtl/vcl 软件包和我为 Jedi WinApi 单元创建的软件包。
这是以下行的结果:
// This is a TaskDialog override, with the same args as the old MessageDlg.
function TaskDialog(const aContent: string; const Icon: HICON = 0;
const Buttons: TTaskDialogCommonButtonFlags = TDCBF_OK_BUTTON): Integer;
const
Captions: array[TMsgDlgType] of Pointer = (@SMsgDlgWarning, @SMsgDlgError, @SMsgDlgInformation, @SMsgDlgConfirm, nil);
var
aMsgDlgType: TMsgDlgType;
aTitle: string;
begin
aMsgDlgType := TaskDialogIconToMsgDlgType(Icon);
if aMsgDlgType <> mtCustom then
aTitle := LoadResString(Captions[aMsgDlgType])
else
aTitle := Application.Title;
更具体地说,这是引用SMsgDlgWarning
、SMsgDlgError
、SMsgDlgInformation
和SMsgDlgConfirm
的结果,它们都在Vcl.Const
中声明。
请注意,当我们构建单个可执行文件时,此代码编译时没有错误。
作为一种优化手段,我们的包含文件确实包含{$IMPORTEDDATA OFF}
,因为这允许更快地访问(全局(变量和常量。请参阅 http://hallvards.blogspot.com/2006/09/hack13-access-globals-faster.html。
根据错误文档(http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/devcommon/cm_package_varref_xml.html(,这是原因,它说"为了缓解问题,通常最简单的方法是打开$IMPORTEDDATA开关并重新编译产生错误的单元。
因此,我在包含文件中设置了{$IMPORTEDDATA ON}
,并通过在项目选项的Delphi Compiler | Compiling | Debugging
部分中将Use imported data references
设置为 true 来加倍确保。
不幸的是,与文档相反,这并没有缓解问题。即使将此编译器指令直接设置在有问题的代码上方并重建包也无法消除错误。
我还需要做什么来解决此 E2201 错误?不确定,但 SMsgDlgWarning 及其好友是资源字符串可能很重要?
恕我直言,错误消息具有误导性,它是Vcl.Consts
这是用$G-
编译的,这导致了问题。作为解决方法,您可以使用如下方法:
function Captions(AType: TMsgDlgType): Pointer;
begin
Result := nil;
case AType of
TMsgDlgType.mtWarning:
Result := @SMsgDlgWarning;
TMsgDlgType.mtError:
Result := @SMsgDlgError;
TMsgDlgType.mtInformation:
Result := @SMsgDlgInformation;
TMsgDlgType.mtConfirmation:
Result := @SMsgDlgConfirm;
end;
end;
也使用字符串编译的 const 数组(尽管它破坏了本地化(:
const
Captions: array[TMsgDlgType] of string = (SMsgDlgWarning, SMsgDlgError, SMsgDlgInformation, SMsgDlgConfirm, '');
或者,您可以使用{$G+}
构建自己的包含 Vcl.* 单元的软件包,并使用它来代替标准的 vcl
软件包。我更喜欢第一种解决方案;后者可能会在以后的部署中产生更多问题(所谓的"DLL 地狱"(。