2024-08-03 21:19:08 +02:00
unit Setup. DotNetFunc;
2020-02-22 16:52:57 +01:00
{
Inno Setup
Copyright ( C) 1 9 9 7 - 2 0 2 0 Jordan Russell
Portions by Martijn Laan
For conditions of distribution and use, see LICENSE. TXT.
. NET functions
Fusion code based on LibFusion. pas by RemObject Software
License:
// LibFusion.pas
// copyright (c) 2009 by RemObjects Software
//
// Uses InnoSetup License
Also see https: //docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/fusion
https: //docs.microsoft.com/en-us/windows/win32/sbscs/side-by-side-assembly-api
IsDotNetInstalled code based on http: //www.kynosarges.de/DotNetVersion.html by Cristoph Nahr
License:
2023-08-06 08:48:34 +02:00
// I’ m placing this small bit of code in the public domain, so you may embed it in your own
2020-02-22 16:52:57 +01:00
// projects, modify and redistribute it as you see fit.
Also see https: //docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed
}
interface
uses
2024-08-04 19:59:25 +02:00
Ole2, SysUtils, Windows, Shared. CommonFunc, Shared. DotNetVersion;
2020-02-22 16:52:57 +01:00
type
IAssemblyCache = class( Ole2. IUnknown)
function UninstallAssembly( dwFlags: Integer ; pszAssemblyName: PWideChar ; pvReserved: Integer ; var pulDisposition: Integer ) : Integer ; virtual ; stdcall ; abstract ;
function QueryAssemblyInfo( dwFlags: Integer ; pszAssemblyName: PWideChar ; pAsmInfo: Integer ) : Integer ; virtual ; stdcall ; abstract ;
function CreateAssemblyCacheItem( dwFlags: Integer ; pvReserved: Integer ; var ppAsmItem: Integer ; pszAssemblyName: PWideChar ) : Integer ; virtual ; stdcall ; abstract ;
function CreateAssemblyScavenger( var ppAsmScavenger: Pointer ) : Integer ; virtual ; stdcall ; abstract ;
function InstallAssembly( dwFlags: Integer ; pszManifestFilePath: PWideChar ; pvReserved: Integer ) : Integer ; virtual ; stdcall ; abstract ;
end ;
TAssemblyCacheInfo = class
private
fDll: THandle;
fCache: IAssemblyCache;
public
constructor Create( const RegView: TRegView) ;
destructor Destroy; override ;
property Cache: IAssemblyCache read FCache;
procedure InstallAssembly( const FileName: string ) ;
procedure UninstallAssembly( const StrongAssemblyName: string ) ; // Full name! in 'AssemblyName, version=1.0.0.0, culture=neutral, publickeytoken=abcdef123456' format
end ;
TDotNetBaseVersion = ( netbase11, netbase20, netbase40, netbaseHighestKnown) ;
function GetDotNetInstallRoot( const RegView: TRegView) : String ;
function GetDotNetVersionInstallRoot( const RegView: TRegView; const Version: TDotNetBaseVersion) : String ;
function IsDotNetInstalled( const RegView: TRegView; const MinVersion: TDotNetVersion; const MinServicePack: DWORD) : Boolean ;
implementation
uses
2024-08-06 19:12:28 +02:00
Setup. InstFunc, PathFunc;
2020-02-22 16:52:57 +01:00
var
DotNetRoot: array [ TRegView] of String ;
DotNetVersionRoot: array [ TRegView, TDotNetBaseVersion] of String ;
{ GetDotNet(Version)InstallRoot }
function GetDotNetInstallRoot( const RegView: TRegView) : String ;
var
K: HKEY;
begin
if DotNetRoot[ RegView] = '' then begin
if RegOpenKeyExView( RegView, HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\.NETFramework' , 0 , KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
RegQueryStringValue( K, 'InstallRoot' , DotNetRoot[ RegView] ) ;
RegCloseKey( K) ;
end ;
if DotNetRoot[ RegView] = '' then
InternalError( '.NET Framework not found' ) ;
end ;
Result : = DotNetRoot[ RegView] ;
end ;
function GetDotNetVersionInstallRoot( const RegView: TRegView; const Version: TDotNetBaseVersion) : String ;
const
VersionStrings: array [ TDotNetBaseVersion] of String = ( '1.1' , '2.0' , '4.0' , '' ) ;
var
K: HKEY;
begin
if DotNetVersionRoot[ RegView, Version] = '' then begin
GetDotNetInstallRoot( RegView) ;
if ( Version in [ netbase40, netbaseHighestKnown] ) and ( RegOpenKeyExView( RegView, HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\.NETFramework\Policy\v4.0' , 0 , KEY_QUERY_VALUE, K) = ERROR_SUCCESS) then begin
DotNetVersionRoot[ RegView, Version] : = AddBackslash( DotNetRoot[ RegView] ) + 'v4.0.30319' ;
RegCloseKey( K) ;
end else if ( Version in [ netbase20, netbaseHighestKnown] ) and ( RegOpenKeyExView( RegView, HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\.NETFramework\Policy\v2.0' , 0 , KEY_QUERY_VALUE, K) = ERROR_SUCCESS) then begin
DotNetVersionRoot[ RegView, Version] : = AddBackslash( DotNetRoot[ RegView] ) + 'v2.0.50727' ;
RegCloseKey( K) ;
end else if ( Version in [ netbase11, netbaseHighestKnown] ) and ( RegOpenKeyExView( RegView, HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\.NETFramework\Policy\v1.1' , 0 , KEY_QUERY_VALUE, K) = ERROR_SUCCESS) then begin
DotNetVersionRoot[ RegView, Version] : = AddBackslash( DotNetRoot[ RegView] ) + 'v1.1.4322' ;
RegCloseKey( K) ;
end ;
if DotNetVersionRoot[ RegView, Version] = '' then begin
if Version < > netbaseHighestKnown then
InternalError( Format( '.NET Framework version %s not found' , [ VersionStrings[ Version] ] ) )
else
InternalError( '.NET Framework not found' ) ;
end ;
end ;
Result : = DotNetVersionRoot[ RegView, Version] ;
end ;
{ TAssemblyCacheInfo }
constructor TAssemblyCacheInfo. Create( const RegView: TRegView) ;
type
TCreateAssemblyCache = function ( var ppAsmCache: IAssemblyCache; dwReserved: Integer ) : Integer ; stdcall ;
var
FileName: string ;
Proc: TCreateAssemblyCache;
begin
inherited Create;
FileName : = AddBackslash( GetDotNetVersionInstallRoot( RegView, netbaseHighestKnown) ) + 'Fusion.dll' ;
fDll : = SafeLoadLibrary( PChar( FileName) , SEM_NOOPENFILEERRORBOX) ;
if fDll = 0 then
InternalError( Format( 'Failed to load .NET Framework DLL "%s"' , [ FileName] ) ) ;
Proc : = GetProcAddress( fDll, 'CreateAssemblyCache' ) ;
if not Assigned( Proc) then
InternalError( 'Failed to get address of .NET Framework CreateAssemblyCache function' ) ;
Proc( fCache, 0 ) ;
if fCache = nil then
InternalError( '.NET Framework CreateAssemblyCache function failed' ) ;
end ;
destructor TAssemblyCacheInfo. Destroy;
begin
if fCache < > nil then
fCache. Release;
fCache : = nil ;
FreeLibrary( fDll) ;
inherited Destroy;
end ;
procedure TAssemblyCacheInfo. InstallAssembly( const FileName: string ) ;
const
IASSEMBLYCACHE_INSTALL_FLAG_FORCE_REFRESH = 2 ;
var
lOleString: PWideChar ;
OleResult: HRESULT;
begin
lOleString : = StringToOleStr( FileName) ;
try
OleResult : = fCache. InstallAssembly( IASSEMBLYCACHE_INSTALL_FLAG_FORCE_REFRESH, lOleString, 0 ) ;
if Failed( OleResult) then
RaiseOleError( 'InstallAssembly' , OleResult) ;
finally
SysFreeString( lOleString) ;
end ;
end ;
procedure TAssemblyCacheInfo. UninstallAssembly(
const StrongAssemblyName: string ) ;
var
lOleString: PWideChar ;
OleResult: HRESULT;
begin
lOleString : = StringToOleStr( StrongAssemblyName) ;
try
OleResult : = fCache. UninstallAssembly( 0 , lOleString, 0 , Integer( nil ^ ) ) ;
if Failed( OleResult) then
RaiseOleError( 'UninstallAssembly' , OleResult) ;
finally
SysFreeString( lOleString) ;
end ;
end ;
{ IsDotNetDetected }
function IsDotNetInstalled( const RegView: TRegView; const MinVersion: TDotNetVersion; const MinServicePack: DWORD) : Boolean ;
function GetVersionString( const Version: TDotNetVersion) : String ;
begin
case Version of
net11: Result : = 'v1.1' ;
net20: Result : = 'v2.0' ;
net30: Result : = 'v3.0' ;
net35: Result : = 'v3.5' ;
net4Client: Result : = 'v4\Client' ;
net4Full: Result : = 'v4\Full' ;
net45: Result : = 'v4.5' ;
net451: Result : = 'v4.5.1' ;
net452: Result : = 'v4.5.2' ;
net46: Result : = 'v4.6' ;
net461: Result : = 'v4.6.1' ;
net462: Result : = 'v4.6.2' ;
net47: Result : = 'v4.7' ;
net471: Result : = 'v4.7.1' ;
net472: Result : = 'v4.7.2' ;
net48: Result : = 'v4.8' ;
2023-08-06 08:48:34 +02:00
net481: Result : = 'v4.8.1' ;
2020-02-22 16:52:57 +01:00
else
InternalError( 'IsDotNetDetected: Invalid Version' ) ;
end ;
end ;
function QueryDWord( const SubKey, ValueName: String ; var Value: DWORD) : Boolean ;
var
K: HKEY;
Typ, Size: DWORD;
begin
if RegOpenKeyExView( RegView, HKEY_LOCAL_MACHINE, PChar( SubKey) , 0 , KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
Size : = SizeOf( Value) ;
Result : = ( RegQueryValueEx( K, PChar( ValueName) , nil , @ Typ, @ Value, @ Size) = ERROR_SUCCESS) and ( Typ = REG_DWORD) ;
RegCloseKey( K) ;
end else
Result : = False ;
end ;
var
VersionString, VersionKey, SubKey: String ;
Install, InstalledRelease, InstalledServicePack, RequiredRelease: DWORD;
Success: Boolean ;
begin
VersionString : = GetVersionString( MinVersion) ;
RequiredRelease : = 0 ;
// .NET 1.1 and 2.0 embed release number in version key
if VersionString = 'v1.1' then
VersionKey : = 'v1.1.4322'
else if VersionString = 'v2.0' then
VersionKey : = 'v2.0.50727'
else begin
// .NET 4.5 and newer install as update to .NET 4.0 Full
if Pos( 'v4.' , VersionString) = 1 then begin
VersionKey : = 'v4\Full' ;
if VersionString = 'v4.5' then
RequiredRelease : = 3 7 8 3 8 9
else if VersionString = 'v4.5.1' then
RequiredRelease : = 3 7 8 6 7 5 // 378758 on Windows 8 and older
else if VersionString = 'v4.5.2' then
RequiredRelease : = 3 7 9 8 9 3
else if VersionString = 'v4.6' then
RequiredRelease : = 3 9 3 2 9 5 // 393297 on Windows 8.1 and older
else if VersionString = 'v4.6.1' then
RequiredRelease : = 3 9 4 2 5 4 // 394271 before Win10 November Update
else if VersionString = 'v4.6.2' then
RequiredRelease : = 3 9 4 8 0 2 // 394806 before Win10 Anniversary Update
else if VersionString = 'v4.7' then
RequiredRelease : = 4 6 0 7 9 8 // 460805 before Win10 Creators Update
else if VersionString = 'v4.7.1' then
RequiredRelease : = 4 6 1 3 0 8 // 461310 before Win10 Fall Creators Update
else if VersionString = 'v4.7.2' then
RequiredRelease : = 4 6 1 8 0 8 // 461814 before Win10 April 2018 Update
else if VersionString = 'v4.8' then
RequiredRelease : = 5 2 8 0 4 0 // 528049 before Win10 May 2019 Update
2023-08-06 08:48:34 +02:00
else if VersionString = 'v4.8.1' then
RequiredRelease : = 5 3 3 3 2 0 // 533325 before Win11 2022 Update
2020-02-22 16:52:57 +01:00
else
InternalError( 'IsDotNetDetected: Invalid VersionString' ) ;
end else
2020-03-14 19:58:19 +01:00
VersionKey : = VersionString;
2020-02-22 16:52:57 +01:00
end ;
SubKey : = 'SOFTWARE\Microsoft\NET Framework Setup\NDP\' + VersionKey;
if Pos( 'v3.0' , VersionString) = 1 then
Success : = QueryDWord( SubKey + '\Setup' , 'InstallSuccess' , Install)
else
Success : = QueryDWord( SubKey, 'Install' , Install) ;
if Success and ( Install = 1 ) then begin
if Pos( 'v4' , VersionString) = 1 then
Success : = QueryDWord( SubKey, 'Servicing' , InstalledServicePack)
else
Success : = QueryDWord( SubKey, 'SP' , InstalledServicePack) ;
if Success and ( InstalledServicePack > = MinServicePack) then begin
if RequiredRelease > 0 then
Success : = QueryDWord( SubKey, 'Release' , InstalledRelease) and ( InstalledRelease > = RequiredRelease) ;
Result : = Success;
end else
Result : = False ;
end else
Result : = False ;
end ;
end .