Retrieve strong name of .NET assembly in Inno Setup

672 views Asked by At

I need to install these some DLL files to the GAC.

I use preprocessor to generate [Files] section entries for these DLLs. And I need to provide a value for the StrongAssemblyName parameter.

So question

  1. Can I automatically retrieve the StrongAssemblyName of a DLL from a Pascal Script?
  2. If not, can one create a dictionary so I could look up in the dictionary using the assembly name as key, and then have hardcoded value strings that would get used when automatically building up the line Source: path; DestDir

I would prefer the first solution, if possible.

1

There are 1 answers

0
Martin Prikryl On BEST ANSWER

I do not think, there's a native way to retrieve a strong name in Inno Setup Pascal Script.

But, you can use a simple PowerShell command to retrieve the strong name.

([Reflection.Assembly]::ReflectionOnlyLoadFrom('My.dll')).FullName

Combining these two questions:

you get a code like:

function GetAssemblyStrongName(FileName: string): string;
var
  TmpFileName: string;
  Args: string;
  StrongName: AnsiString;
  ResultCode: Integer;
begin
  TmpFileName := ExpandConstant('{tmp}') + '\strong_name.txt';
  Args :=
    Format('-ExecutionPolicy Unrestricted -Command "Set-Content -Path "%s" -NoNewline ' +
           '-Value ([Reflection.Assembly]::ReflectionOnlyLoadFrom(''%s'')).FullName"', [
           TmpFileName, FileName]);
  if (not Exec('powershell.exe', Args, '', SW_HIDE, ewWaitUntilTerminated, ResultCode)) or
     (ResultCode <> 0) or
     (not LoadStringFromFile(TmpFileName, StrongName)) then
  begin
    RaiseException(Format('Error retrieving strong name of "%s"', [FileName]));
  end;

  Result := StrongName;
  DeleteFile(TmpFileName);
end;

Though actually, you cannot use Pascal Scripting, as you need the strong name on compile-time, and the Pascal Scripting is executed on install-time only. In some cases, you can use a scripted constant, but it's not supported in the StrongAssemblyName parameter.

So again, you have to use a preprocessor.

The Pascal Script code translates to the preprocessor like:

#define GetAssemblyStrongName(FileName) \
  Local[0] = AddBackslash(GetEnv("TEMP")) + "strong_name.txt", \
  Local[1] = \
    "-ExecutionPolicy Unrestricted -Command """ + \
    "Set-Content -Path '" + Local[0] + "' -NoNewline -Value " + \
    "([Reflection.Assembly]::ReflectionOnlyLoadFrom('" + FileName + "')).FullName" + \
    """", \
  Exec("powershell.exe", Local[1], SourcePath, , SW_HIDE), \
  Local[2] = FileOpen(Local[0]), \
  Local[3] = FileRead(Local[2]), \
  FileClose(Local[2]), \
  DeleteFileNow(Local[0]), \
  Local[3]

You can use it in the StrongAssemblyName parameter like:

[Files]
Source: "My.dll"; DestDir: "{app}"; \
  StrongAssemblyName: "{#GetAssemblyStrongName('My.dll')}"

Which gets preprocessed to something like:

[Files]
Source: "My.dll"; DestDir: "{app}"; \
  StrongAssemblyName: "My, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2271ec4a3c56d0bf"

Though, as you generate the [Files] section completely by a preprocessor, your current code from your comment will now work, as the syntax, that you have used, actually calls GetAssemblyStrongName preprocessor macro and not GetAssemblyStrongName Pascal Script function.

Note that the macro above uses C-style strings, so it has to be outside the Pascal-style pragma directives:

; here

#pragma parseroption -p-

; not here

#pragma parseroption -p+

; or here