0
votes

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://stackguides.com/questions/34616470/nsis-get-product-version?rq=1
; https://stackguides.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
1
Please confirm your NSIS version. 2.0b3 was released in 2003! If you can't use NSIS v3 (why?), at least use v2.51. - Anders
The code you posted is not the same as the thing you liked to. You should post your complete code so that people can actually compile and test your problematic code! - Anders
...post more code. Where do you allocate $5? I'm not going to bother investigating this if you can't post a complete function. - Anders
OK, will try to post latest version I tried... lots of variations. Reason for using 2.0b3 is a small edit was made to get unzips timezone independent. I know... could migrate everything to a later NSIS, but I think the problem here is the calling of the function returned the lplpBuffer ptr. - DaveB
After 3am in my timezone... thanks for quick responses so far and I will certainly be back online in 6 hours or so... look fwd to comments, thanks - DaveB

1 Answers

0
votes

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.