Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatically retrieve EXE file version to embed in NSIS installer metadata

I am attempting to remove one more step in my application's release process by automatically retrieving versioning info from my executable (in this case, a .NET application).

Up to this point, I have been able to get by with a limited knowledge of NSIS, but I am quickly learning that this is not enough.

Step 1: Declare version info in executable

In AssemblyInfo.cs, I declare [assembly: AssemblyVersion("1.0.0.1")]. This successfully makes the version info appear in the compiled executable (under "File version" and "Product version").

Step 2: Retrieve version info from executable

According to this article on "GetFileVersion", importing "FileFunc.nsh" allows you to retrieve version info from an executable.

Code used:

Section
    Var /GLOBAL version
    ${GetFileVersion} "C:\test.exe" $version
    ...
SectionEnd

Step 3: Verify contents of function call

Based on section 5.1.7 of the documentation, I should be able to print to the command line during compile time using the "!echo" command. The difference between printing the contents of a variable (or a constant, etc) still confuses me, so I have tried all four of these options:

!echo $version
!echo "$version"
!echo "${version}"
!echo ${version}

This results in:

$version (InstallScript.nsi:15)
$version (InstallScript.nsi:16)
${version} (InstallScript.nsi:17)
${version} (InstallScript.nsi:18)

Step 4: Declare the installer metadata

Based on section 4.8.3, I should be able to add installer metadata via VIProductVersion and VIAddVersionKey.

VIProductVersion $version 
VIAddVersionKey "FileVersion" "$version"

In the built installer, this adds the string "$version" into the specified fields.


Is there a ToString() equivalent in NSIS? How can I access a variable's contents? Does the print of the variable name mean that it has no contents? How can I verify that GetFileVersion is called correctly, executes correctly, and returns a value?

like image 320
user664939 Avatar asked Nov 18 '11 20:11

user664939


2 Answers

Edit: NSIS v3 now includes a !getdllversion preprocessor instruction, you only need the GetVersionLocal workaround if you are still using NSIS v2.

There are plans for a !getdllversionlocal in NSIS 2.47, for now you have to use this workaround:

outfile test.exe
requestexecutionlevel user

!macro GetVersionLocal file basedef
!verbose push
!verbose 1
!tempfile _GetVersionLocal_nsi
!tempfile _GetVersionLocal_exe
!appendfile "${_GetVersionLocal_nsi}" 'Outfile "${_GetVersionLocal_exe}"$\nRequestexecutionlevel user$\n'
!appendfile "${_GetVersionLocal_nsi}" 'Section$\n!define D "$"$\n!define N "${D}\n"$\n'
!appendfile "${_GetVersionLocal_nsi}" 'GetDLLVersion "${file}" $2 $4$\n'
!appendfile "${_GetVersionLocal_nsi}" 'IntOp $1 $2 / 0x00010000$\nIntOp $2 $2 & 0x0000FFFF$\n'
!appendfile "${_GetVersionLocal_nsi}" 'IntOp $3 $4 / 0x00010000$\nIntOp $4 $4 & 0x0000FFFF$\n'
!appendfile "${_GetVersionLocal_nsi}" 'FileOpen $0 "${_GetVersionLocal_nsi}" w$\nStrCpy $9 "${N}"$\n'
!appendfile "${_GetVersionLocal_nsi}" 'FileWrite $0 "!define ${basedef}1 $1$9"$\nFileWrite $0 "!define ${basedef}2 $2$9"$\n'
!appendfile "${_GetVersionLocal_nsi}" 'FileWrite $0 "!define ${basedef}3 $3$9"$\nFileWrite $0 "!define ${basedef}4 $4$9"$\n'
!appendfile "${_GetVersionLocal_nsi}" 'FileClose $0$\nSectionend$\n'
!system '"${NSISDIR}\makensis" -NOCD -NOCONFIG "${_GetVersionLocal_nsi}"' = 0
!system '"${_GetVersionLocal_exe}" /S' = 0
!delfile "${_GetVersionLocal_exe}"
!undef _GetVersionLocal_exe
!include "${_GetVersionLocal_nsi}"
!delfile "${_GetVersionLocal_nsi}"
!undef _GetVersionLocal_nsi
!verbose pop
!macroend

!insertmacro GetVersionLocal "$%windir%\Explorer.exe" MyVer_
VIProductVersion "${MyVer_1}.${MyVer_2}.${MyVer_3}.${MyVer_4}"
VIAddVersionKey "FileVersion" "${MyVer_1}.${MyVer_2}.${MyVer_3}.${MyVer_4}"

page instfiles
section
sectionend

This macro:

  1. Creates a temporary .nsi file
  2. Compiles the temporary .nsi to a temporary executable
  3. Runs the temporary .exe
  4. Deletes the two files (.nsi and .exe)
  5. Returns an array containing the version info of the specified executable.
like image 158
Anders Avatar answered Nov 09 '22 04:11

Anders


Updated information:

NSIS now includes !getdllversion command which does the same thing. Usage:

!getdllversion "$%windir%\explorer.exe" expv_
!echo "Explorer.exe version is ${expv_1}.${expv_2}.${expv_3}.${expv_4}"

UPDATE: !getdllversion command is a "Compile Time Command", it's different from the GetDLLVersion instruction. IMO it should have been named as !getdllversionlocal to prevent confusion, since it's similar to GetDLLVersionLocal instruction, not the GetDLLVersion

In the user manual included in NSIS 3.0a1 it says:

5.1.14 !getdllversion

localfilename define_basename

This is similar to GetDLLVersionLocal, only it stores the version number in defines and can therefore be used anywhere, not just inside functions and sections.

!getdllversion "$%windir%\explorer.exe" expv_
!echo "Explorer.exe version is ${expv_1}.${expv_2}.${expv_3}.${expv_4}"
like image 27
yclkvnc Avatar answered Nov 09 '22 06:11

yclkvnc