.netinno-setup.net-assemblypascalscriptstrongname

Retrieve strong name of .NET assembly in Inno Setup


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.


Solution

  • 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