Evaluate preprocessor macro on run time in Inno Se

2019-01-27 01:39发布

问题:

I'm using an Inno Setup #define directive to define all of the information about a software package in my installer and then other directives to extract portions of that string. So for example, using the following, PartNumber(Package1) will return 05414.

#define Package1 "05414 - My Package"
#define PartNumber(str Package) Copy(Package, 1, 5)

I'm using this approach in scripts and code and it works fine. However, I've got a situation where it would be convenient to programmatically generate the string and I'm having trouble getting it to work. For example, I'd like to do something like the following.

procedure Foo(Package: String);
var
  PartNumber: String;
begin
  PartNumber:= ExpandConstant(Format('{#PartNumber(%s)}', [Package]));
end;

procedure Bar();
begin
   Foo(ExpandConstant('{#Package1)}')); 
end;

The Package argument to Foo is correct, but I get a compiler error saying

[ISPP] No argument for format '%'".

It seems that it doesn't like the # in the string on the PartNumber line. Even including a # in a normal string gives an "unterminated preprocessor directive" error, so I think it's interpreting the # as a precision specifier or something.

Is there a way to make it treat # as part of the text so that I can programmatically expand this constant? If not, if there some other way I can achieve this?

回答1:

This cannot work.

The PartNumber is a preprocessor function/macro. It's evaluated on compile time. It does not exist on run time.


You can, of course, implement an equivalent Pascal Script function:

function PartNumberPascal(Package: string): string;
begin
  Result := Copy(Package, 1, 5);
end;

procedure Foo(Package: String);
var
  PartNumber: String;
begin
  PartNumber := PartNumberPascal(Package);
end;

What probably confuses you, is this call:

Foo(ExpandConstant('{#Package1}')); 

It may give you an impression that the ExpandConstant function expands the Package1 preprocessor define.

It does not!

The {#...} syntax (contrary to the {...}) is not a constant. It's an inline preprocessor directive call, where, when no directive is explicitly specified, the emit is implied. So the {#Package1} is the same as {#emit Package1}. And as every preprocessor construct, it's evaluated on compile time.

If you add SaveToFile preprocessor function call to the end of the script:

procedure Bar();
begin
  Foo(ExpandConstant('{#Package1}')); 
end;

#expr SaveToFile(AddBackslash(SourcePath) + "Preprocessed.iss")

And after compilation, check, what the Preprocessed.iss is like. You will see:

procedure Bar();
begin
  Foo(ExpandConstant('05414 - My Package')); 
end;

The Package1 is expanded to its value. But the ExpandConstant is still there, and hence it's totally useless! (there are no constants in the '05414 - My Package')

This would have the same effect:

procedure Bar();
begin
  Foo('{#Package1}'); 
end;


标签: inno-setup