6

为了帮助我们模块化单体应用程序,我们正在设置用于调试构建的软件包,同时仍编译为单个 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,它们都在 中声明。SMsgDlgInformationSMsgDlgConfirmVcl.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}在我们的包含文件中进行了设置,并通过在项目选项部分中将设置Use imported data references为 true 来确保。Delphi Compiler | Compiling | Debugging

不幸的是,与文档相反,这并没有缓解问题。即使直接在有问题的代码上方设置此编译器指令并重新构建包也不能消除错误。

我还需要做什么来解决这个 E2201 错误?不确定,但 SMsgDlgWarning 及其朋友是资源字符串可能很重要?

4

1 回答 1

9

错误消息是,恕我直言,误导,它是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, '');

或者您可以构建自己的包含 Vcl.* 单元的包,使用{$G+}并使用它而不是标准vcl包。我更喜欢第一种解决方案;后者可能会在以后的部署中产生更多问题(所谓的“DLL 地狱”)。

于 2012-05-09T09:52:54.437 回答