Retrieving version info data

Windows specific forum
User avatar
Frontier
User
User
Posts: 74
Joined: Thu Dec 22, 2005 2:43 pm
Location: Chios, Greece
Contact:

Retrieving version info data

Post by Frontier »

Hello,

I am using the following code under Windows 2000 and my program crashes upon startup. The code is not mine, it was posted in the forum.

Code: Select all

;=====================================================================
;Test Version for reading out FileVersionInfo Block
;Special: Read out ALL Information that is contained in the InfoBlock
;not just the official values - all languages
;---------------------------------------------------------------------
;Date: March 17th 2007 - Beta Version - stillt needs to be tested.
;Author: Mike Doran
;Written in PB 4.02 / Windows XP Pro SP2
;=====================================================================

; Modified as a procedure by Manos S. Pappas

Procedure.s GetVersionInfo (File$, Getinfo$)
  info$=""
  If FileSize (File$) > 0
    zero = 10
    If OpenLibrary (1, "version.dll")
      length = CallFunction (1, "GetFileVersionInfoSizeA", File$, @zero)
      If length
        *mem1 = AllocateMemory (length)
        If *mem1
          result = CallFunction (1, "GetFileVersionInfoA", File$, 0, length, *mem1)
          If result
            
            
            lpSubBlock$ = "\\VarFileInfo\\Translation"
            Result1      = CallFunction(1,"VerQueryValueA",*mem1,lpSubBlock$,@lplpBuffer,@puLen)
            If Result1
              CPLI$  = RSet(Hex(PeekW(lplpBuffer)),4,"0")+RSet(Hex(PeekW(lplpBuffer+2)),4,"0")
              ;MessageRequester("Info",CPLI$,0)   ; LanguageCode ID
              Result1 = CallFunction(1,"VerLanguageNameA",PeekW(lplpBuffer),@szLang$,nSize)
            EndIf
            
            
            infobuffer = 0
            infolen = 0
            ;Language must be specified in order to work: !!!
            Getinfo$ = "\\StringFileInfo\\"+CPLI$+"\\" + Getinfo$
            result = CallFunction (1, "VerQueryValueA", *mem1, Getinfo$, @infobuffer, @infolen)
            If result
              info$ = PeekS(infobuffer)
            EndIf
          EndIf
          FreeMemory (*mem1)
        EndIf
      EndIf
      CloseLibrary (1)
    EndIf
  EndIf 
  ProcedureReturn info$
EndProcedure

Procedure.s PEVersionInfo(FileName.s)
;-===== Reading FileVesionInfo Block =======
FileName$=FileName
ItemCount = 0 ;Needed for formating / to see how many strings were found in the search
InitFlag = 0
If FileSize(FileName$)>0
  If OpenLibrary(1,"Version.dll")
    dwLen = CallFunction(1,"GetFileVersionInfoSizeA",FileName$,@lpdwHandle)
    ;SetGadgetText(#String_55,StrU(dwLen,#Word))
    If dwLen>0 ; Length of FileVersionInfoBlock must be greater than zero
      *pBlock=AllocateMemory(dwLen) ;Allocate buffer memory for FileVersionInfoBlock
      If *pBlock>0
        result = CallFunction(1,"GetFileVersionInfoA",FileName$,0,dwLen,*pBlock)
        If result ; if successful continue and start the search
          Gesamt$ = ""
          BCount = 0
          ;----- Begin Loop Length of VersionInfoBlock --------
          For I = 0 To dwLen-1
            Byte.C = PeekC(*pBlock+I)
            If Byte = 0
              
              BCount +1
              
              If BCount >2  ;Two consecutive ZeroBytes = StringEnd ------------
                
                If Len(AddString$)>1
                  ;----- End VersionInfoBlock ----
                  If AddString$ = "VarFileInfo" ; Detecting End of InfoBlock
                    Break
                    ;---- Begin VersionInfoBlock ----
                  ElseIf AddString$ = "StringFileInfo" ; Detect Start of FileInfo
                    Gesamt$ = ""  ;Begin of FileVersionBlock
                    ItemCount = 0:InitFlag =1
                  Else
                    Gesamt$+AddString$+Chr(10) ; Adding FoundString to Gesamt$
                    If InitFlag
                      ItemCount+1 ; Increase found string counter by 1 after new string found
                      Even +1
                      ;MessageRequester("ItemCount",Str(Itemcount)+" - "+Addstring$,0)
                    EndIf 
                  EndIf
                  
                  AddString$ = "" ; resetting ADDString after its been added to Gesamt$
                  BCount = 0    ; Resetting ZeroByte Counter
                Else
                  
                  AddString$ = "" ;Resetting AddString when length was smaller than 1
                  BCount = 0     ; Resetting ZeroByte Counter
                EndIf   
              EndIf
            ElseIf Byte <32 And Byte > 0 ;Allow only valid characters in AddString
              AddString$ = ""; Resetting AddString after invalid Character found
              BCount=0     ;Resetting ZeroByte Counter
            Else
              AddString$ +Chr(Byte) ;Adding character to AddString
              BCount = 0           ; Resetting ZeroByte counter
            EndIf
        Next I ;========Loop End ===================
          
        EndIf   
        FreeMemory(*pBlock) ; Free allocated memory block
      EndIf
    EndIf
    CloseLibrary(1)
  EndIf         
EndIf


;-==== Formating Output-String - Showing Result in Total$ =========
Total$ = ""
For I = 2 To ItemCount ;Step 2
  Field$ = StringField(Gesamt$,I,Chr(10))
  If Field$
    Value$ = GetVersionInfo(FileName$, Field$)
    If Len(Value$) >0
      Add$ =Field$+": "+Value$
      If Not FindString(Total$,Add$,1)
        Total$+Field$+": "+Value$+Chr(10)
      EndIf
    EndIf 
  EndIf
Next I

ProcedureReturn Total$
EndProcedure
I cannot find something wrong in the code, yet upon startup the application crashes (only on Windows 2000) with an error that "the memory cannot be "written" " at a particular address.

Any ideas what might be wrong? I am trying to retrieve the application version information data from its resource (inside the executable), while the executable is running.

Thank you very much in advance.
ebs
Enthusiast
Enthusiast
Posts: 563
Joined: Fri Apr 25, 2003 11:08 pm

Post by ebs »

Frontier,

Here is the code I use to get file version information. Most of it was found in the forum.
I have two procedures - one that returns a version string ("x.x.x.x") and one that puts the version into two long variables, so you can do mathematical comparisons.

Regards,
Eric

Code: Select all

;- get version of specified file as string
Procedure.s GetFileVersionString(FileSpec.s)
  dummy.l
  *Buffer
  BufferLen.l
  
  VerBuffer.VS_FIXEDFILEINFO
  VerPointer.l
  VerBufferLen.l
  
  FileVersion.s
  
  If OpenLibrary(0, "version.dll")
    *GFI_Size = GetFunction(0, "GetFileVersionInfoSizeA")
    *GFI_Info = GetFunction(0, "GetFileVersionInfoA")
    *GFI_Value = GetFunction(0, "VerQueryValueA")
    
    If *GFI_Size And *GFI_Info And *GFI_Value
      ; get size of version information buffer
      BufferLen = CallFunctionFast(*GFI_Size, FileSpec, @dummy)
      If BufferLen
        ; allocate buffer and get version information
        *Buffer = AllocateMemory(BufferLen)
        CallFunctionFast(*GFI_Info, FileSpec, 0, BufferLen, *Buffer)
        ; find file version and copy into structure
        CallFunctionFast(*GFI_Value, *Buffer, "\", @VerPointer, @VerBufferLen)
        CopyMemory(VerPointer, VerBuffer, VerBufferLen)
        ; build file version string "x.x.x.x"
        FileVersion = Str((VerBuffer\dwFileVersionMS & $FFFF0000) >> 16) + "." + Str(VerBuffer\dwFileVersionMS & $0000FFFF) + "." + Str((VerBuffer\dwFileVersionLS & $FFFF0000) >> 16) + "." + Str(VerBuffer\dwFileVersionLS & $0000FFFF)
      EndIf
    EndIf
    CloseLibrary(0)
  EndIf
  
  ; return file version string
  ProcedureReturn FileVersion
EndProcedure

;- get version of specified file as MS/LS values
Procedure GetFileVersion(FileSpec.s, *FileVerMS, *FileVerLS)
  dummy.l
  *Buffer
  BufferLen.l
  
  VerBuffer.VS_FIXEDFILEINFO
  VerPointer.l
  VerBufferLen.l
  
  If OpenLibrary(0, "version.dll")
    *GFI_Size = GetFunction(0, "GetFileVersionInfoSizeA")
    *GFI_Info = GetFunction(0, "GetFileVersionInfoA")
    *GFI_Value = GetFunction(0, "VerQueryValueA")
    
    If *GFI_Size And *GFI_Info And *GFI_Value
      ; get size of version information buffer
      BufferLen = CallFunctionFast(*GFI_Size, FileSpec, @dummy)
      If BufferLen
        ; allocate buffer and get version information
        *Buffer = AllocateMemory(BufferLen)
        CallFunctionFast(*GFI_Info, FileSpec, 0, BufferLen, *Buffer)
        ; find file version and copy into structure
        CallFunctionFast(*GFI_Value, *Buffer, "\", @VerPointer, @VerBufferLen)
        CopyMemory(VerPointer, VerBuffer, VerBufferLen)
        ; copy file version into MS/LS variables
        CopyMemory(@VerBuffer\dwFileVersionMS, *FileVerMS, 4)
        CopyMemory(@VerBuffer\dwFileVersionLS, *FileVerLS, 4)
      EndIf
    EndIf
    CloseLibrary(0)
  EndIf 
EndProcedure
Post Reply