Archive: Need another pair of eyes..


Need another pair of eyes..
I've been racking my brain for a couple days on this one function.

The purpose is to read the file info strings from an executable (or dll, ocx, etc). Not all executables have them, but if you right-click on an executable, select Properties, then click the Version tab (if it's there) you will see the information I am trying to retrieve.

Once fixed, I think it makes a good candidate for a NSIS Example wiki page..

Anyway, I'm messing with the stack and the System plugin and it is wreaking havoc on my program throwing spurious "invalid opcode" and "Access denied" (while reading a memory address). Can someone else take a look at this with me and help me figure it out?

I think the key to fixing the problem is near the "System::Call "*$4(&t$5 .r7)"" line. When I comment that out all my problems seem to disappear. What am I doing wrong? :mad:


Var PROGRAMINFO

; Call like this:
; !insertmacro GetInfoFromExeHeader "ProductName" "c:\programs\myexecutable.exe"
!macro GetInfoFromExeHeader DataType ProgramExe
Push ${DataType}
Push ${ProgramExe}
Call GetInfoFromExeHeader
Pop $PROGRAMINFO
!macroend

Function GetInfoFromExeHeader
; Valid Data Types:
; ProductName
; InternalName
; ProductVersion
; SpecialBuild
; PrivateBuild
; LegalCopyright
; LegalTrademarks
; Comments
; CompanyName
; FileVersion
; FileDescription

Exch $R0 ; path to EXE
IfFileExists $R0 +4 0
MessageBox MB_OK "$R0 doesn't exist! Please correct this."
Exch $R0 ; Put the path back on the stack
Return

Exch
Exch $R1 ; Data type

Push $1
Push $2
Push $3
Push $4
Push $5
Push $6
Push $7

StrCpy $1 "0"
StrCpy $3 "0"
StrCpy $7 ""
StrCpy $2 "0"

System::Call "version::GetFileVersionInfoSize(t '$R0', t /NUL) i .r2" ;returns size of version block in header
IntCmp $2 0 Done Done 0 ; $2 needs to be greater than 0
System::Call "version::GetFileVersionInfo(t '$R0', i 0, i r2, *i .r3) i .r1" ; returns 1 or 0 with r3 being the fileinfo struct
IntCmp $1 0 Done 0 0 ; $1 needs to be <> 0
System::Call "version::VerQueryValue(*i r3, t '\StringFileInfo\040904E4\$R1', *i .r4, *i .r5) i .r6"
IntCmp $6 0 Done 0 0 ; $6 needs to be <> 0
IntCmp $5 0 Done Done 0
;IntOp $5 $5 + 1
System::Call "*$4(&t$5 .r7)"

Done:
System::Free $R0
System::Free $R1
System::Free $1
System::Free $2
System::Free $3
System::Free $4
System::Free $5
System::Free $6

;SetPluginUnload "manual"
Push $7

Exch 9 ; put $7 on the bottom
Pop $7
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Pop $R0
Pop $R1
FunctionEnd


Documentation on the three version functions:

GetFileVersionInfoSize: http://msdn2.microsoft.com/en-us/library/ms647005.aspx

GetFileVersionInfo: http://msdn2.microsoft.com/en-us/library/ms647003.aspx

VerQueryValue: http://msdn2.microsoft.com/en-us/library/ms647464.aspx

-Steve.

Have you seen the MoreInfo plugin? It's so easy ;)

http://nsis.sourceforge.net/MoreInfo_plug-in


  1. File path may contain quotes, so it's better to use R0 instead of '$R0' when passing it to System::Call.
  2. /NUL is not a valid parameter. Either use n for NULL or pass a real pointer.
  3. You must allocate a buffer for GetFileVersionInfo with System::Alloc. You just passed it pointer to an integer which it fills and then some. That's corrupting the heap.
Once fixed, I think it makes a good candidate for a NSIS Example wiki page..
Everything makes a good candidate for that. Feel free to create Wiki pages with what you'd consider useful information.