3

I have a .NET DLL. It can be registered by RegAsm .NET 3.5 and .NET 4.5.

I use this codes in my setup script:

[Run]
Filename: "{dotnet40}\RegAsm.exe"; Parameters: "my.dll"; WorkingDir: "{app}"; Flags: skipifdoesntexist; StatusMsg: "Registering Controls."
Filename: "{dotnet4064}\RegAsm.exe"; Parameters: "my.dll"; WorkingDir: "{app}"; Flags: skipifdoesntexist; StatusMsg: "Registering Controls."
Filename: "{dotnet20}\RegAsm.exe"; Parameters: "my.dll"; WorkingDir: "{app}"; Flags: skipifdoesntexist; StatusMsg: "Registering Controls."
Filename: "{dotnet2064}\RegAsm.exe"; Parameters: "my.dll"; WorkingDir: "{app}"; Flags: skipifdoesntexist; StatusMsg: "Registering Controls."
  • It works well if .NET 3.5 and .NET 4.5 is installed on the target machine
  • I have a function in my script to checking .net in InitializeSetup. So I know one of these versions are installed on the system: v3.5 v4 v4.5

But

we get error in some cases like this: if we have not .NET 3.5 on the target machine

I guess the error reason is:

{dotnet20}

.NET Framework version 2.0 root directory. {dotnet20} is equivalent to {dotnet2032} unless the install is running in 64-bit mode, in which case it is equivalent to {dotnet2064}.

An exception will be raised if an attempt is made to expand this constant on a system with no .NET Framework version 2.0 present.

My question is how can I handle and ignore this exception and prevent setup rollback:

Internal error: .Net Framework version 2.0 not found.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Ramin Bateni
  • 16,499
  • 9
  • 69
  • 98

1 Answers1

2

If you want to stick to the [Run] section and do not write this in a scripting code, then I think you don't have many options to choose from. An exception is raised whenever a constant cannot be expanded, and that is just this case. The only option I can think of is adding a Check function that will attempt to expand the constant in a protected try..except block and prevent the entry to be processed when an exception is raised. Something like follows (based on your code, shortened):

[Run]
Filename: "{dotnet20}\RegAsm.exe"; Parameters: "File.dll"; Check: RegAsmDotNet20Exists

[Code]
function RegAsmDotNet20Exists: Boolean;
begin
  try
    // process the entry only if the target binary could be found (and so the
    // folder constant could have been properly expanded)
    Result := FileExists(ExpandConstant('{dotnet20}\RegAsm.exe'));
  except
    // this is the fallback in case the folder constant could not be expanded,
    // or something unexpected happened when checking if the binary file to be
    // executed exists; in such case, don't process the entry
    Result := False;
  end;
end;

Another, quite cleaner and a bit safer option would be doing your assembly registration purely from [Code] section in some of the postinstall events. Even though you'd still need to catch exceptions when using those constants, you would get more control over that tool (e.g. you could get the exit code to obtain an error reason if that tool uses it).

TLama
  • 75,147
  • 17
  • 214
  • 392
  • Sidenote; beware that by default [`the debugger shows in the IDE an exception dialog`](http://stackoverflow.com/q/22039048/960757) regardless the exception is handled. – TLama Mar 08 '15 at 21:18
  • Note that it might not expand simply because .net did not create the apppath registry key. This is where Inno looks to get the path. Sometimes the key is missing and Inno fails with internal error. Even though .net is installed. – Andrew Truckle Jun 04 '22 at 04:56