获取程序的版本信息 --- VB

VB编程 blackfeather

 

取自病毒防火墙里的代码,获取到启动项后,需要根据路径获取到程序的版本信息,后来网上找了一些代码都不能用,经过自己努力终于解决了问题,也发现了API示例里的问题所在。

大致需要3个函数GetFileVersionInfoSize,GetFileVersionInfo,VerQueryValue

API的解释为:

-------------------------------------------------------GetFileVersionInfoSize

【操作系统】
Win9X:Yes
WinNT:Yes
【说明】
  针对包含了版本资源的一个文件,判断容纳文件版本信息需要一个多大的缓冲区
【返回值】
  Long,容纳文件的版本资源所需的缓冲区长度。如文件不包含版本信息,则返回一个0值。会设置GetLastError
【其它】
  lpdwHandle参数在win32中已经放弃
【参数表】
  lptstrFilename -  String,包含了版本资源的一个文件的名字
  lpdwHandle -----  Long,在这个变量中载入0值

---------------------------------------------------------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------GetFileVersionInfo

【操作系统】
Win9X:Yes
WinNT:Yes
【说明】
  从支持版本标记的一个模块里获取文件版本信息
【返回值】
  Long,非零表示成功,零表示失败。会设置GetLastError
【其它】
  请看vb的api文本查看器中的声明:Declare Function
  (ByVal lptstrFilename As String, ByVal dwHandle As Long, ByVal dwLen As Long, lpData As
  Any) As Long
【参数表】
  lptstrFilename -  String,欲从中载入版本信息的一个文件的名字
  dwHandle -------  Long,win32中未用
  dwLen ----------  Long,由lpData参数指定的字节数组或缓冲区的大小。用GetFileVersionInfoSize函数判断要求的缓冲区长度有多大
  lpData ---------  Byte,指定一个字节缓冲区的第一个字节。该缓冲区用于装载文件的版本信息

---------------------------------------------------------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------VerQueryValue

【操作系统】
Win9X:Yes
WinNT:Yes
【说明】
  这个函数用于从版本资源中获取信息。调用这个函数前,必须先用GetFileVersionInfo函数获取版本资源信息。这个函数会检查资源信息,并将需要的数据复制到一个缓冲区里
【返回值】
  Long,TRUE(非零)表示成功,如请求的信息不存在,或pBlock不属于有效版本信息,那就返回一个零
【其它】
  从vb的api文本查看器复制的声明如下:
  (pBlock As Any, ByVal lpSubBlock As String, ByVal lplpBuffer As Long, puLen As Long) As
  Long
【参数表】
  pBlock ---------  Byte,指定一个内存块第一个字节的地址。这个内存块包含了由GetFileVersionInfo函数取回的版本数据信息
  lpSubBlock -----  String,下述值之一:
  "\"
  获取文件的VS_FIXEDFILEINFO结构
  "\VarFileInfo\Translation"
  获取文件的翻译表
  "\StringFileInfo\...."
  获取文件的字串信息。参考注解
  lplpBuffer -----  Long,指定一个Long变量的地址,该变量用于装载一个缓冲区的地址。请求的版本信息最终会装载到那个缓冲区里
  puLen ----------  Long,指定由lplpBuffer参数引用的数据值的长度,以字节为单位

---------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

流程为GetFileVersionInfoSize获取到文件信息的SIZE返回一个long,然后根据值调用GetFileVersionInfo将信息复制到一个缓冲区里,最后就是调用VerQueryValue从缓冲区中取得需要的信息,具体的看MSDN。

然后给了一个例子:

——————————————————————————————————————————————————————————————-

'Example Name: Determining the Cipher Strength of IE
'------------------------------------------------------------------------------
'
' Form Code
'
'------------------------------------------------------------------------------
Option Explicit
Private Type VS_FIXEDFILEINFO
   dwSignature As Long
   dwStrucVersion As Long
   dwFileVersionMS As Long
   dwFileVersionLS As Long
   dwProductVersionMS As Long
   dwProductVersionLS As Long
   dwFileFlagsMask As Long
   dwFileFlags As Long
   dwFileOS As Long
   dwFileType As Long
   dwFileSubtype As Long
   dwFileDateMS As Long
   dwFileDateLS As Long
End Type
Private Declare Function GetSystemDirectory Lib "kernel32" _
   Alias "GetSystemDirectoryA" _
  (ByVal lpBuffer As String, _
   ByVal nSize As Long) As Long
Private Declare Function GetFileVersionInfoSize Lib "version.dll" _
   Alias "GetFileVersionInfoSizeA" _
  (ByVal lptstrFilename As String, _
   lpdwHandle As Long) As Long
Private Declare Function GetFileVersionInfo Lib "version.dll" _
   Alias "GetFileVersionInfoA" _
  (ByVal lptstrFilename As String, _
   ByVal dwHandle As Long, _
   ByVal dwLen As Long, _
   lpData As Any) As Long
   
Private Declare Function VerQueryValue Lib "version.dll" _
   Alias "VerQueryValueA" _
  (pBlock As Any, _
   ByVal lpSubBlock As String, _
   FI As Any, _
   nVerSize As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" _
   Alias "RtlMoveMemory" _
  (Destination As Any, _
   Source As Any, _
   ByVal Length As Long)
   
Private Declare Function lstrcpyA Lib "kernel32" _
  (ByVal RetVal As String, _
   ByVal Ptr As Long) As Long
                        
Private Declare Function lstrlenA Lib "kernel32" _
  (ByVal Ptr As Any) As Long

Private Sub Command1_Click()
   Label1.Caption = GetIECypherVersion()
   
End Sub

Private Function GetIECypherVersion() As String
   Dim FI As VS_FIXEDFILEINFO
   Dim sBuffer() As Byte
   Dim nBufferSize As Long
   Dim lpBuffer As Long
   Dim nVerSize As Long
   Dim nUnused As Long
   Dim tmpVer As String
   Dim sBlock As String
   Dim sDLLFile As String
   Dim sSysPath As String
   
   sSysPath = GetSystemDir()
   If sSysPath > "" Then
     'set file that has the encryption level
     'info and call to get required size
      sDLLFile = sSysPath & "\schannel.dll"
      nBufferSize = GetFileVersionInfoSize(sDLLFile, nUnused)
      
      ReDim sBuffer(nBufferSize)
      
      If nBufferSize > 0 Then
      
        'get the version info
         Call GetFileVersionInfo(sDLLFile, 0&, nBufferSize, sBuffer(0))
         Call VerQueryValue(sBuffer(0), "\", lpBuffer, nVerSize)
         Call CopyMemory(FI, ByVal lpBuffer, Len(FI))
   
         If VerQueryValue(sBuffer(0), "\VarFileInfo\Translation", lpBuffer, nVerSize) Then
            
            If nVerSize Then
               tmpVer = GetPointerToString(lpBuffer, nVerSize)
               tmpVer = Right("0" & Hex(Asc(Mid(tmpVer, 2, 1))), 2) & _
                        Right("0" & Hex(Asc(Mid(tmpVer, 1, 1))), 2) & _
                        Right("0" & Hex(Asc(Mid(tmpVer, 4, 1))), 2) & _
                        Right("0" & Hex(Asc(Mid(tmpVer, 3, 1))), 2)
               sBlock = "\StringFileInfo\" & tmpVer & "\FileDescription"
               
              'Get predefined version resources
               If VerQueryValue(sBuffer(0), sBlock, lpBuffer, nVerSize) Then
               
                  If nVerSize Then
                  
                    'get the file description string
                     tmpVer = GetStrFromPtrA(lpBuffer)
                     
                    'File versions for 40 and 128-bit releases can
                    'be the same, so we have to do a string search
                    'to determine the encryption level. If the file
                    'description contains the line:
                    'PCT/SSL Security Provider (Export Version), its 40-bit.
                    'If it contains the line:
                    'PCT/SSL Security Provider (US and Canada Use Only), its 128-bit.
                    
                     Select Case InStr(1, tmpVer, "(US and Canada Use Only)", vbTextCompare)
                        Case 0:    GetIECypherVersion = "40-bit normal encryption"
                        Case Else: GetIECypherVersion = "128-bit strong encryption"
                     End Select
                     
                  End If  'If nVerSize
               End If  'If VerQueryValue
            End If  'If nVerSize
         End If  'If VerQueryValue
      
      Else
      
         GetIECypherVersion = "schannel.dll is not in the system folder."
      
      End If  'If nBufferSize
   End If  'If sSysPath
End Function

Private Function GetPointerToString(lpString As Long, nBytes As Long) As String
   Dim Buffer As String
   
   If nBytes Then
      Buffer = Space(nBytes)
      CopyMemory ByVal Buffer, ByVal lpString, nBytes
      GetPointerToString = Buffer
   End If
   
End Function

Private Function GetStrFromPtrA(ByVal lpszA As Long) As String
   GetStrFromPtrA = String$(lstrlenA(ByVal lpszA), 0)
   Call lstrcpyA(ByVal GetStrFromPtrA, ByVal lpszA)
   
End Function

Private Function GetSystemDir() As String
    Dim nSize As Long
    Dim tmp As String
    
    tmp = Space$(256)
    nSize = Len(tmp)
    Call GetSystemDirectory(tmp, nSize)
    
    GetSystemDir = TrimNull(tmp)
    
End Function

Private Function TrimNull(item As String)
    Dim pos As Integer
   
   'double check that there is a chr$(0) in the string
    pos = InStr(item, Chr$(0))
    If pos Then
          TrimNull = Left$(item, pos - 1)
    Else: TrimNull = item
    End If
  
End Function



————————————————————————————————————————————————————————————

但是运行后报错,停止在

 tmpVer = Right("0" & Hex(Asc(Mid(tmpVer, 2, 1))), 2) & _
                        Right("0" & Hex(Asc(Mid(tmpVer, 1, 1))), 2) & _
                        Right("0" & Hex(Asc(Mid(tmpVer, 4, 1))), 2) & _
                        Right("0" & Hex(Asc(Mid(tmpVer, 3, 1))), 2)
 

这里,大概看了一下,这里的目的是为了获取地址,temVer原始值是乱码,但是获取完后就是一串地址(谁知道微软搞什么飞机,地址都错位写。。。)。temVer是string型,这时候想到地址中如果有00存在,那么string将截止,对了,问题就在这里,string无法显示chr(0)字符。然后将temVer改成一个数组,然后重组,结果OK了。修改后为

         tmpVer = Right("0" & Hex(ssBuffer(1)), 2) & _
                    Right("0" & Hex(ssBuffer(0)), 2) & _
                    Right("0" & Hex(ssBuffer(3)), 2) & _
                    Right("0" & Hex(ssBuffer(2)), 2)

 

最后就是完整的获取文件版本信息的代码,因为是从程序里摘出来的,所以没有整理成工程,留着给大家自己动手吧。几个API和常量,API VIEW里都有

代码:

————————————————————————————————————————————————————————

'功能获取程序版本信息中的公司和文件描述
'参数strFileName是程序的完整路径,strCompanyName是公司信息,strDescription是文件描述
'那两个信息传递的地址,调用方法为
'dim strCom as string
'dim strDes as string
'GetFileVersion "c:\windows\notepad.exe",strCom,strDes     '获取windows记事本的信息
'debug.print strCom & strDes
Public Sub GetFileVersion(ByVal strFileName As String, ByRef strCompanyName As String, ByRef strDescription As String)   
Dim FI As VS_FIXEDFILEINFO
Dim nBufferSize As Long
Dim sBuffer() As Byte
Dim ssBuffer(3) As Byte
Dim lpBuffer As Long
Dim nVerSize As Long
Dim tmpVer As String
Dim tmpFD As String
Dim tmpCN As String
strCompanyName = vbNullString
strDescription = vbNullString
nBufferSize = GetFileVersionInfoSize(strFileName, 0)
If nBufferSize < 1 Then GoTo Err
ReDim sBuffer(nBufferSize)
GetFileVersionInfo strFileName, 0&, nBufferSize, sBuffer(0)
If VerQueryValue(sBuffer(0), "\VarFileInfo\Translation", lpBuffer, nVerSize) Then
     If nVerSize Then
           API_CopyMemory ssBuffer(0), ByVal lpBuffer, nVerSize
           tmpVer = Right("0" & Hex(ssBuffer(1)), 2) & _
                    Right("0" & Hex(ssBuffer(0)), 2) & _
                    Right("0" & Hex(ssBuffer(3)), 2) & _
                    Right("0" & Hex(ssBuffer(2)), 2)
           tmpFD = "\StringFileInfo\" & tmpVer & "\FileDescription"
           tmpCN = "\StringFileInfo\" & tmpVer & "\CompanyName"
           If VerQueryValue(sBuffer(0), tmpFD, lpBuffer, nVerSize) Then
                If nVerSize Then
                    strDescription = String$(lstrlenA(ByVal lpBuffer), 0)
                    lstrcpyA strDescription, ByVal lpBuffer
                End If  'If nVerSize
           End If 'If VerQueryValue
           If VerQueryValue(sBuffer(0), tmpCN, lpBuffer, nVerSize) Then
                If nVerSize Then
                    strCompanyName = String$(lstrlenA(ByVal lpBuffer), 0)
                    lstrcpyA strCompanyName, ByVal lpBuffer
                End If  'If nVerSize
           End If
     End If  'If nVerSize
End If
Err:
Erase sBuffer
Erase ssBuffer
End Sub

&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;

 

还是那句老话,大家玩好!!

 

 

评论列表:

发表评论: