NSIS Get Product Version 解决方案失败

NSIS Get Product Version solution failing

我一直在尝试使用系统调用 GetFileVersionInfo 和 VerQueryValue 来获取 exe 的产品版本。我使用的是旧版 NSIS v2.0b3(许多脚本已经在使用,只是想做一点改动)。

找了一段时间后看到了这个解决方案 ...但在让它正常工作时遇到问题。

主调用似乎有效...即

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

...显示 $5 的合理 ptr。 下一个电话是出了问题的地方...

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

此呼叫 returns 0,0 为 6 美元和 7 美元。然后当然解析失败...

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

...returns 0,0.

我认为问题出在此处 $6 中的间接指针。 也就是说,$6 是类型 LPVOID *lplpBuffer ....所以我认为设置 $6 值的调用语法可能需要不同。

欢迎任何帮助...我尝试了一些变化但没有成功。

===根据发布的请求,这是我尝试过的许多变化中的最新变化...希望这将有助于阐明我在做什么===

Function GetDllProductVersion
; 
;  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 

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

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

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

    ;;---Now we get the VS_FIXEDFILEINFO structure using ....  will be lplpBuffer for it and  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 [=13=] 0 fail
    MessageBox MB_OK "VS_FIXEDFILEINFO returned as lplpBuffer=[] and PUINT=[]"

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

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

fail:
System::Free 

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

我无法解释为什么 System::Store 会崩溃,据记载即使在 v2.0b3 中也能正常工作。再者,您使用的是 15 年前的 beta 软件,因此您不能指望一切正常。可能与在 v2.23(11 年前)中修复的错误 #1620178 有关。

您的主要问题是 v2.0b3 不自动支持以 A 为后缀的函数名称(大多数 take/return 字符串的函数)。似乎在 v2.0b4 中添加了对此的支持。

您可以通过硬编码后缀来修改您发现兼容的代码:

Function GetDllProductVersion
Exch 
Push 
Push 
Exch 2
Push 
Push 
Push 
Push 
Push [=10=]
System::Call 'VERSION::GetFileVersionInfoSizeA(tr3,*i)i.r4'
System::Call '*(&i,t""r1,t""r2)i.r5' ; Set  and  to "" so they are empty if we fail
StrCmp  0 fail
StrCmp  0 fail
    System::Call 'VERSION::GetFileVersionInfoA(tr3,i,ir4,ir5)i.r0'
    StrCmp [=10=] 0 fail
    System::Call 'VERSION::VerQueryValueA(ir5,t"\",*i.r6,*i.r7)i.r0'
    StrCmp [=10=] 0 fail
    System::Call '*(i,i,i,i,i.r2,i.r1)'
fail:
System::Free 
Pop [=10=]
Pop 
Pop 
Pop 
Pop 
Pop 
Exch 
Exch
Exch 
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

但我强烈建议您升级到更新的版本。 v2.51 作为获得所有安全修复的最低要求。