DaveB
DaveB

Reputation: 37

NSIS Get Product Version solution failing

I have been trying to use the system calls GetFileVersionInfo and VerQueryValue to get the product version of an exe. I am using a legacy NSIS v2.0b3 (lots of scripts already in use and just wanting to make one little change).

After searching for a while I saw this solution Product version string from an exe - nsis ...but am having problems getting it to work sensibly.

The main call seems to work... ie

System::Call 'VERSION::GetFileVersionInfo(tr3,i,ir4,ir5)i.r0'
MessageBox MB_OK "GetFileVersionInfo returned dwLen=[$4] and lpData=[$5] for the block of Version Info"

...shows a sensible ptr in $5. The next call is where things go wrong...

System::Call 'VERSION::VerQueryValue(ir5,t"\",*i.r6,*i.r7)i.r0'
StrCmp $0 0 fail
MessageBox MB_OK "VS_FIXEDFILEINFO returned as lplpBuffer=[$6] and PUINT=[$7]"

This call returns 0,0 for $6 and $7. And then of course the parsing fails...

;;---Parse buffer at $6 (lplp)
System::Call '*$6(i,i,i,i,i.r2,i.r1)'
MessageBox MB_OK "Read data from struct @$6: skip 4 ints then ints are dwProductVersionMS:[$2] dwProductVersionLS:[$1]"

...returns 0,0.

I'm thinking the problem is the indirect pointer in $6 here. That is, $6 is type LPVOID *lplpBuffer ....so I think the syntax of the call to set the value of $6 may need to be different.

Any help welcome... I tried some variations without success.

===Following request posted, here is the latest of many variations I have tried... hopefully that will help clarify what I am doing===

Function GetDllProductVersion
; https://stackoverflow.com/questions/34616470/nsis-get-product-version?rq=1
; https://stackoverflow.com/questions/38707235/product-version-string-from-an-exe-nsis slightly different System::Call's, but also later nsis not compatible

    ;;System::Store S   ;;;removed this and the matching Store L, as that crashes
    Pop $3

;;  System::Call 'VERSION::GetFileVersionInfoSize(tr3,*i)i.r4'
;;  MessageBox MB_OK "GetFileVersionInfoSize gets size [$4]"        ; cannot get a sensible answer, returns "error" in $4

    ;;---allocate block, address into $5
    StrCpy $4 0
    IntOp $4 $4 + 10000     ; set $4 to 10000
    System::Call '*(&i$4,t""r1,t""r2)i.r5' ; Set $1 and $2 to "" so they are empty if we fail
    MessageBox MB_OK "System::Call allocs [$4] bytes at addr [$5], next call GetFileVersionInfo"
    StrCmp $4 0 fail
    StrCmp $5 0 fail

    ;;---GetFileVersionInfo now-----
    System::Call 'VERSION::GetFileVersionInfo(tr3,i,ir4,ir5)i.r0'       ;; ir5 not isr5 ?? diff between solutions
    StrCmp $0 0 fail
    MessageBox MB_OK "GetFileVersionInfo returned dwLen=[$4] and lpData=[$5] for the block of Version Info"

    ;;---Now we get the VS_FIXEDFILEINFO structure using $5.... $6 will be lplpBuffer for it and $7 will be PUINT ptr to size of data in lplpBuffer
    System::Call 'VERSION::VerQueryValue(ir5,t"\",*i.r6,*i.r7)i.r0'     ;; using &i.r6 etc, not *i.r6 gives 0,0 no good, go back to *
    StrCmp $0 0 fail
    MessageBox MB_OK "VS_FIXEDFILEINFO returned as lplpBuffer=[$6] and PUINT=[$7]"

    ;;---Parse buffer at $6 (lplp)
    System::Call '**$6(i,i,i,i,i.r2,i.r1)'
    MessageBox MB_OK "Read data from struct @$6: skip 4 ints then ints are dwProductVersionMS:[$2] dwProductVersionLS:[$1]"

    ;;;or?????
    System::Call '**$6(i,i,i,i,&i.r2,&i.r1)'
    MessageBox MB_OK "Read data using & from struct @$6: skip 4 ints then ints are dwProductVersionMS:[$2] dwProductVersionLS:[$1]"

fail:
System::Free $5

    MessageBox MB_OK "After System::Free [$5]"
Push $1
Push $2
;;System::Store L       ;;;this crashes!!! so push and pop indiv registers used
FunctionEnd

Upvotes: 0

Views: 240

Answers (1)

Anders
Anders

Reputation: 101736

I can't explain why System::Store crashes, it is documented to work even in v2.0b3. Then again, you are using 15 year old beta software so you can't expect everything to work correctly. Could be related to bug #1620178 which was fixed in v2.23 (11 years ago).

Your main issue is that v2.0b3 does not automatically support function names suffixed with A (most functions that take/return a string). It seems like support for this was added in v2.0b4.

You can modify the code you found to be compatible by hardcoding the suffix:

Function GetDllProductVersion
Exch $3
Push $1
Push $2
Exch 2
Push $4
Push $5
Push $6
Push $7
Push $0
System::Call 'VERSION::GetFileVersionInfoSizeA(tr3,*i)i.r4'
System::Call '*(&i$4,t""r1,t""r2)i.r5' ; Set $1 and $2 to "" so they are empty if we fail
StrCmp $4 0 fail
StrCmp $5 0 fail
    System::Call 'VERSION::GetFileVersionInfoA(tr3,i,ir4,ir5)i.r0'
    StrCmp $0 0 fail
    System::Call 'VERSION::VerQueryValueA(ir5,t"\",*i.r6,*i.r7)i.r0'
    StrCmp $0 0 fail
    System::Call '*$6(i,i,i,i,i.r2,i.r1)'
fail:
System::Free $5
Pop $0
Pop $7
Pop $6
Pop $5
Pop $4
Pop $3
Exch $1
Exch
Exch $2
FunctionEnd


Section
!define DllName "c:\windows\system32\ComCtl32.dll"

Push "${DllName}"
Call GetDllProductVersion
Pop $R0
Pop $R1
IntOp $R2 $R0 / 0x00010000
IntOp $R3 $R0 & 0x0000FFFF
IntOp $R4 $R1 / 0x00010000
IntOp $R5 $R1 & 0x0000FFFF
DetailPrint 'ProdVer: $R2.$R3.$R4.$R5'
SectionEnd

but I would strongly recommend that you upgrade to a more recent version. v2.51 as a minimum to get all security fixes.

Upvotes: 0

Related Questions