【问题标题】:NSIS Get Product Version solution failingNSIS 获取产品版本解决方案失败
【发布时间】:2018-11-30 06:31:59
【问题描述】:

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

搜索了一段时间后,我看到了这个解决方案 Product version string from an exe - nsis ...但是在使其正常工作时遇到问题。

主要调用似乎有效......即

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"

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

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]"

此调用为 6 美元和 7 美元返回 0,0。然后当然解析失败了......

;;---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]"

...返回 0,0。

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

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

===以下请求已发布,这是我尝试过的许多变体中的最新版本...希望这将有助于澄清我在做什么===

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

【问题讨论】:

  • 请确认您的 NSIS 版本。 2.0b3 于 2003 年发布!如果你不能使用 NSIS v3(​​为什么?),至少使用 v2.51。
  • 你发布的代码和你喜欢的不一样。您应该发布您的完整代码,以便人们可以实际编译和测试您有问题的代码!
  • ...发布更多代码。你在哪里分配 5 美元?如果你不能发布一个完整的功能,我不会费心去调查这个。
  • 好的,将尝试发布我尝试过的最新版本...很多变化。使用 2.0b3 的原因是为了让解压缩时区独立而做了一个小编辑。我知道...可以将所有内容迁移到以后的 NSIS,但我认为这里的问题是调用返回 lplpBuffer ptr 的函数。
  • 在我的时区凌晨 3 点之后...感谢您到目前为止的快速响应,我肯定会在 6 小时左右后重新上线...请转至 cmets,谢谢

标签: nsis


【解决方案1】:

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

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

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

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

但我强烈建议您升级到更新的版本。至少 v2.51 才能获得所有安全修复。

【讨论】:

  • 谢谢...并且肯定会升级到 v2.51 以进行安全修复并减少其他意外。正如我所说,当安装程序构建在一个时区并部署在另一个时区时,我需要对 NSIS 进行一点调整以保存/恢复时区不变的文件时间戳。从常规 zip/exe 中提取文件时,我们需要与 WinZip 时间戳兼容。我们只是在安装程序中转换为 UTC 时间和从 UTC 时间转换,在 exec.c 和 script.cpp 中做了两个小改动。可以稍后发布另一个问题并链接到该问题。
  • 最后我按照承诺尝试将我的“datefixed”NSIS 更新到最新版本。见link ...谢谢@Anders
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-07
  • 1970-01-01
  • 2020-04-15
  • 2021-04-19
  • 2013-09-07
  • 2020-12-16
  • 1970-01-01
相关资源
最近更新 更多