Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to solve "Need imported data reference" while building with runtime packages

To help us modularize a monolithic application, we are in the process of setting up packages for use in debug builds, while still compiling to a single exe for release builds.

One of our packages (EAUtils) contains a unit that is now producing [DCC Error] E2201 Need imported data reference ($G) to access 'SMsgDlgWarning' from unit 'SystemUtils'.

This happens when building the EAUtils package itself. I am not into building packages that depend on EAUtils yet. EAUtils only depends on rtl/vcl packages and a package I created for the Jedi WinApi units.

This is a result of the lines:

// 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;

More specifically this is a result of referencing SMsgDlgWarning, SMsgDlgError, SMsgDlgInformation and SMsgDlgConfirm, which are all declared in Vcl.Const.

Please note that this code compiles without error when we are building a single executable.

As a means of optimization, our include file does contain {$IMPORTEDDATA OFF} as this allows for faster access to (global) variables and constants. See http://hallvards.blogspot.com/2006/09/hack13-access-globals-faster.html.

According to the documentation on the error ( http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/devcommon/cm_package_varref_xml.html ) this is the cause and it says "To alleviate the problem, it is generally easiest to turn on the $IMPORTEDDATA switch and recompile the unit that produces the error."

So, I have set {$IMPORTEDDATA ON} in our include file and made doubly sure by setting the Use imported data references to true in the Delphi Compiler | Compiling | Debugging section of the project options.

Unfortunately, contrary to the documentation, this did not alleviate the problem. Even setting this compiler directive directly above the offending code and rebuilding the package did not remove the errors.

What else do I need to do to solve this E2201 error? Not sure, but it may be significant that SMsgDlgWarning and its friends are resource strings?

like image 535
Marjan Venema Avatar asked May 09 '12 08:05

Marjan Venema


1 Answers

The error message is, IMHO, misleading, it's Vcl.Consts which has been compiled with $G- and that's causing the problem. As a workaround, you can use something like this:

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;

Using a const array of string compiles, too (although it breaks localization):

const
  Captions: array[TMsgDlgType] of string = (SMsgDlgWarning, SMsgDlgError, SMsgDlgInformation, SMsgDlgConfirm, '');

or you could build your own package containing Vcl.* units, with {$G+} and use that instead of the standard vcl package. I prefer the first solution; the latter can potentially create more problems later with deployment (so-called "DLL hell").

like image 119
Ondrej Kelle Avatar answered Sep 18 '22 00:09

Ondrej Kelle