Topic 4.4

DotNET

Working with .NET Applications

When the .NET Framework is being installed on a computer the .NET installer writes registry keys when installation is successful. You can test whether the .NET Framework 4.5 or later is installed by checking the registry key HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full for a DWORD value named Release. The existence of this key indicates that the .NET Framework 4.5 or later has been installed on that computer.

.NET applications are not fully yet supported in PortableApps.com Launcher. Although you may use the methods outlined here to get any .NET program to be portable.
With the PA.c Launcher that I'm currently developing I have eliminated the need to use the custom.nsh file to check for .NET. You can visit the GitHub project page here which will take you to the features section of the read me file for more information.
.NET Values

Below is a chart that shows the version number's corresponding DWORD value in the Release key. See below this chart for an example on how to use this in action. I will do my best to try and keep this page up-to-date with the latest values but you can visit this page for an updated list if the version you need isn't listed here.

Take special notice how there are two rows for 4.7, 4.6.2, 4.6.1, and 4.6. These versions require you to check for both values as the operating systems vary.
Version Operating System Value of Release
4.7 Windows 10 Creator's Update 460798
4.7 All except Windows 10 Creator's Update 460805
4.6.2 Windows 10 Anniversary Update 394802
4.6.2 All except Windows 10 Anniversary Update 394806
4.6.1 Windows 10 November Update 394254
4.6.1 All except Windows 10 November Update 394271
4.6 Windows 10 393295
4.6 All except Windows 10 393297
4.5.2 All 379893
4.5.1 Windows 8.1 or Windows Server 2012 R2 378675
4.5.1 Windows 8 and Wiindows 7 378758
4.5 All 378389
Example

Here's an example on how to use the above values in your custom.nsh. I'd recommend putting this snippet of code inside ${Segment.OnInit} as this will execute before anything else happens; this way it checks for .NET before any files get copied or registry changes take place.

;=#
;= Define the registry key we're looking for.
!define DOTNET			`SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full`

${Segment.OnInit} ;= Remember to use this within this Segment.
	ClearErrors ;= Clear any errors we may have encountered before hand.
	ReadRegDWORD $0 HKLM `${DOTNET}` `Release` ;= Read the value of Release.
	IfErrors +3 ;= If there is an error than there is no .NET installed so we jump 3 lines down which lands on MessageBox.
	IntCmp $0 394806 +5 0 +5	;= Compares the value for v4.6.2 if it matches then we jump 5 lines and avoids the MessageBox
	IntCmp $0 394802 +4 0 +4	;= Remember to check for Windows 10's value aswell as the above line won't.
	MessageBox MB_ICONSTOP|MB_TOPMOST `You must have v4.6.2 or greater of the .NET Framework installed. Launcher aborting!` ;= If the check failed then we alert the user the required version wasn't found.
	Call Unload ;= We call the Unload function here because we failed the .NET check.
	Quit ;= Closes the Launcher
!macroend

Alternatively you can use this function I wrote below. They are both the same thing however the only difference between the two is that the first one makes use of LogicLib.nsh and the second one doesn't require LogicLib.nsh at all. They both should work out-of-the-box without having to check the registry. This is a better alternative to the two functions I wrote before. All that you need to know is the .NET version number. As it is written right now it only checks for 4.5 to 4.7.

I haven't fully tested this function so if you run into problems with one of them let me know and I'll do my best to help. You can see this function working in action with SharpDevelop Portable.

Like I said above I will do my best to try and keep this function up-to-date but if you need a version that this function isn't checking for, let me know so I can revise it and update this page.
;=#
;= Copy and paste this code somewhere above ${SegmentFile} in your custom.nsh file.
Function dotNETCheck
	!define CheckDOTNET "!insertmacro _CheckDOTNET"
	!macro _CheckDOTNET _RESULT _VALUE
		Push `${_VALUE}`
		Call dotNETCheck
		Pop ${_RESULT}
	!macroend
	Exch $1
	Push $0
	Push $1
	
	${If} $1 == "4.7"
		StrCpy $R1 460798
	${ElseIf} $1 == "4.6.2"
		StrCpy $R1 394802
	${ElseIf} $1 == "4.6.1"
		StrCpy $R1 394254
	${ElseIf} $1 == "4.6"
		StrCpy $R1 393295
	${ElseIf} $1 == "4.5.2"
		StrCpy $R1 379893
	${ElseIf} $1 == "4.5.1"
		StrCpy $R1 378675
	${ElseIf} $1 == "4.5"
		StrCpy $R1 378389
	${Else}
		Goto dotNET_FALSE
	${EndIf}
	
	ReadRegDWORD $R0 HKLM `SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full` `Release`
	IfErrors dotNET_FALSE
	
	IntCmp $R0 $R1 dotNET_TRUE dotNET_FALSE
	
	dotNET_TRUE:
	StrCpy $0 true
	Goto dotNET_END
	
	dotNET_FALSE:
	StrCpy $0 false
	SetErrors
	
	dotNET_END:	
	Pop $1
	Exch $0
FunctionEnd

;=#
;= USAGE
;=#
;= ${CheckDOTNET} $0 "Version Number"
; $0 Will hold true if the version of .NET is installed.
; If $0 is false then the error flag is set.
${Segment.OnInit} ;= Remember to use this within this Segment.
	${CheckDOTNET} $0 "4.5"
	IfErrors 0 +4 ;= If there is no errors then jump 4 lines down.
	MessageBox MB_ICONSTOP|MB_TOPMOST `You must have v4.5 or greater of the .NET Framework installed. Launcher aborting!` ;= If the check failed then we alert the user the required version wasn't found.
	Call Unload ;= We call the Unload function here because we failed the .NET check.
	Quit ;= Closes the Launcher
!macroend

You can take this one step further and even extend the PortableApps.comLauncher.nsi file with the following code snippet so you don't have to do this in the custom.nsh file.

ClearErrors
!searchparse /noerrors /file ${PACKAGE}\App\AppInfo\appinfo.ini `UsesDotNetVersion=` dotNET_Version ``
!ifdef dotNET_Version
	!if ! ${dotNET_Version} == ""
		${CheckDOTNET} $0 "${dotNET_Version}"
		IfErrors 0 +4
		MessageBox MB_ICONSTOP|MB_TOPMOST `You must have v${dotNET_Version} or greater of the .NET Framework installed. Launcher aborting!`
		Call Unload
		Quit
		StrCmpS $0 true 0 -3
	!else
		!error "The key 'UsesDotNetVersion' in AppInfo.ini is set but has no value! If this PAF does not require the .NET Framework please omit this key entirely."
	!endif
!endif

Okay, so first this snippet of code will check the AppInfo.ini file for a key (UsesDotNetVersion) for it's value which should be the required version number. If the key exists it will set a !define (${dotNET_Version}) to whatever the key's value is. Afterwhich it'll call the function to check the host PC to see if .NET is even installed and if so what version the PC is compatible with. The function uses IntCmp to see if ${dotNET_Version} and the value found in the registry are a match.

$0 will hold true if the host PC meets the requirements otherwise $0 will be set to false and an error flag is set which is checked for. If any errors occur when launching the portable application it will alert the users of the required .NET version the system needs, calls Unload and quits. If when compiling the portable application and the compiler finds the key UsesDotNetVersion and it's empty, the compiler will stop immediately with an error message saying if the PAF does not require the .NET Framework to omit the key entirely.