none
Zugriff auf "Other Version Information" bei MS Hotfixes RRS feed

  • Frage

  • Hallo,

    für die Betriebssystemhotfixes von Microsoft kann man unter den Eigenschaften bei "Other Version Information" spezielle Variablen und Werte sehen (z.B.: für welche Service Packs der Hotfix gedacht ist)

    Ich habe versucht auf diese Informationen mit einem FileVersionInfo Objekt zuzgreifen.

    Leider erhalte ich aber hier nur einen Teil der Werte.

    Gibt es eine Möglichkeit, über VB.Net alle Versionsinformationen zu erhalten?

    Interessant wären vorrangig die Werte der Variablen "Applies to" und "Installer Engine".

    Ich bedanke mich im Voraus für Vorschläge.

    Pomali

    Freitag, 6. August 2010 09:30

Antworten

  • Hallo,

    für die Betriebssystemhotfixes von Microsoft kann man unter den Eigenschaften bei "Other Version Information" spezielle Variablen und Werte sehen (z.B.: für welche Service Packs der Hotfix gedacht ist)

    das betrifft nur noch Hotfixes für Windows XP. Die Pakete für Vista/7 haben ein anderes Format und stellen diese Informationen nicht mehr über die Versionsinformationen zur Verfügung.

    Ich habe versucht auf diese Informationen mit einem FileVersionInfo Objekt zuzgreifen.

    Leider erhalte ich aber hier nur einen Teil der Werte.

    FileVersionInfo greift nur die allgemeinen Versionsinformationen ab, die jede Anwendungsdatei bzw. DLL bereitstellen sollte. Benutzerdefinierte Eigenschaften werden nicht berücksichtigt.

    Gibt es eine Möglichkeit, über VB.Net alle Versionsinformationen zu erhalten?

    Interessant wären vorrangig die Werte der Variablen "Applies to" und "Installer Engine".

    Du kannst die Versionsinformationen direkt via P/Invoke auslesen. Dafür benötigst Du die Funktionen GetFileVersionInfoSize, GetFileVersionInfo und VerQueryValue. Anbei ein schnell zusammengestricktes Beispiel ohne Anspruch auf Vollständigkeit und Fehlerfreiheit:

    Imports System.Runtime.InteropServices
    
    Public Class ExtendedFileVersionInfo
     Implements IDisposable
    
     Dim m_VersionInfo As IntPtr
     Dim m_Translation As String
    
     Public Sub New(ByVal fileName As String)
     If Not Me.GetVersionInfo(fileName) Then
      Throw New Exception("Unable to get file version information.")
     End If
     End Sub
    
     Private Function GetVersionInfo(ByVal filename As String) As Boolean
     Dim lOut As UInteger = 0
     Dim lSize As UInteger = 0
     Dim lVerInfo As IntPtr
    
     lSize = NativeMethods.GetFileVersionInfoSize(filename, lOut)
    
     lVerInfo = Runtime.InteropServices.Marshal.AllocHGlobal(CInt(lSize))
    
     If NativeMethods.GetFileVersionInfo(filename, lOut, lSize, lVerInfo) Then
    
      Dim lLen As UInteger
      Dim lSubBlock As IntPtr = Runtime.InteropServices.Marshal.AllocHGlobal(512)
    
      If NativeMethods.VerQueryValue(lVerInfo, "\VarFileInfo\Translation", lSubBlock, lLen) Then
      Dim lCount As Integer = lLen / 2
      Dim lCode(lCount - 1) As Short
    
      Marshal.Copy(lSubBlock, lCode, 0, lCount)
    
      m_Translation = String.Format("0{0:X}0{1:X}", lCode(0), lCode(1))
      End If
    
      m_VersionInfo = lVerInfo
    
      Return True
    
     Else
    
      Runtime.InteropServices.Marshal.FreeHGlobal(lVerInfo)
    
      Return False
     End If
     End Function
    
     Public Function GetString(ByVal name As String) As String
     Dim lLen As UInteger
     Dim lSubBlock As IntPtr = Marshal.AllocHGlobal(512)
     Dim lValue As String = ""
    
     If NativeMethods.VerQueryValue(m_VersionInfo, _
             String.Format("\StringFileInfo\{0}\{1}", _
                 m_Translation, _
                 name), _
             lSubBlock, _
             lLen) Then
    
      lValue = Marshal.PtrToStringAnsi(lSubBlock, lLen - 1)
    
     End If
    
     Return lValue
     End Function
    
     Private Class NativeMethods
     <dllimport("version.dll")> _
     Friend Shared Function GetFileVersionInfo(ByVal filename As String, _
                ByVal handle As UInteger, _
                ByVal len As UInteger, _
                ByVal buffer As IntPtr) As Boolean
     End Function
    
     <runtime.interopservices.dllimport("version.dll")> _
     Friend Shared Function GetFileVersionInfoSize(ByVal filename As String, _
                 ByRef handle As UInteger _
                  ) As UInteger
    
     End Function
    
     <runtime.interopservices.dllimport("version.dll")> _
     Friend Shared Function VerQueryValue(ByVal buffer As IntPtr, _
               ByVal subblock As String, _
               ByRef blockbuffer As IntPtr, _
               ByRef len As UInteger) As Boolean
    
     End Function
     End Class
    
     Private disposedValue As Boolean = False ' To detect redundant calls
    
     ' IDisposable
     Protected Overridable Sub Dispose(ByVal disposing As Boolean)
     If Not Me.disposedValue Then
      If m_VersionInfo <> IntPtr.Zero Then
      Marshal.FreeHGlobal(m_VersionInfo)
      m_VersionInfo = IntPtr.Zero
      End If
     End If
     Me.disposedValue = True
     End Sub
    
    #Region " IDisposable Support "
     ' This code added by Visual Basic to correctly implement the disposable pattern.
     Public Sub Dispose() Implements IDisposable.Dispose
     ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
     Dispose(True)
     GC.SuppressFinalize(Me)
     End Sub
    #End Region
    
    End Class
    
    ' Anwendung:
    
     Dim lInfo As New ExtendedFileVersionInfo("D:\WindowsXP-KB898461-x86-DEU.exe")
     Debug.Print("Applies To: " & lInfo.GetString("Applies To"))
     Debug.Print("Engine: " & lInfo.GetString("Installer Engine"))
    
     lInfo.Dispose()
    

    Thorsten Dörfler
    Microsoft MVP Visual Basic
    vb-faq.de
    • Bearbeitet Thorsten Dörfler Dienstag, 10. August 2010 14:01 Codekorrektur
    • Als Antwort markiert Pomali Dienstag, 10. August 2010 14:03
    Montag, 9. August 2010 20:33

Alle Antworten

  • Hallo,

    für die Betriebssystemhotfixes von Microsoft kann man unter den Eigenschaften bei "Other Version Information" spezielle Variablen und Werte sehen (z.B.: für welche Service Packs der Hotfix gedacht ist)

    das betrifft nur noch Hotfixes für Windows XP. Die Pakete für Vista/7 haben ein anderes Format und stellen diese Informationen nicht mehr über die Versionsinformationen zur Verfügung.

    Ich habe versucht auf diese Informationen mit einem FileVersionInfo Objekt zuzgreifen.

    Leider erhalte ich aber hier nur einen Teil der Werte.

    FileVersionInfo greift nur die allgemeinen Versionsinformationen ab, die jede Anwendungsdatei bzw. DLL bereitstellen sollte. Benutzerdefinierte Eigenschaften werden nicht berücksichtigt.

    Gibt es eine Möglichkeit, über VB.Net alle Versionsinformationen zu erhalten?

    Interessant wären vorrangig die Werte der Variablen "Applies to" und "Installer Engine".

    Du kannst die Versionsinformationen direkt via P/Invoke auslesen. Dafür benötigst Du die Funktionen GetFileVersionInfoSize, GetFileVersionInfo und VerQueryValue. Anbei ein schnell zusammengestricktes Beispiel ohne Anspruch auf Vollständigkeit und Fehlerfreiheit:

    Imports System.Runtime.InteropServices
    
    Public Class ExtendedFileVersionInfo
     Implements IDisposable
    
     Dim m_VersionInfo As IntPtr
     Dim m_Translation As String
    
     Public Sub New(ByVal fileName As String)
     If Not Me.GetVersionInfo(fileName) Then
      Throw New Exception("Unable to get file version information.")
     End If
     End Sub
    
     Private Function GetVersionInfo(ByVal filename As String) As Boolean
     Dim lOut As UInteger = 0
     Dim lSize As UInteger = 0
     Dim lVerInfo As IntPtr
    
     lSize = NativeMethods.GetFileVersionInfoSize(filename, lOut)
    
     lVerInfo = Runtime.InteropServices.Marshal.AllocHGlobal(CInt(lSize))
    
     If NativeMethods.GetFileVersionInfo(filename, lOut, lSize, lVerInfo) Then
    
      Dim lLen As UInteger
      Dim lSubBlock As IntPtr = Runtime.InteropServices.Marshal.AllocHGlobal(512)
    
      If NativeMethods.VerQueryValue(lVerInfo, "\VarFileInfo\Translation", lSubBlock, lLen) Then
      Dim lCount As Integer = lLen / 2
      Dim lCode(lCount - 1) As Short
    
      Marshal.Copy(lSubBlock, lCode, 0, lCount)
    
      m_Translation = String.Format("0{0:X}0{1:X}", lCode(0), lCode(1))
      End If
    
      m_VersionInfo = lVerInfo
    
      Return True
    
     Else
    
      Runtime.InteropServices.Marshal.FreeHGlobal(lVerInfo)
    
      Return False
     End If
     End Function
    
     Public Function GetString(ByVal name As String) As String
     Dim lLen As UInteger
     Dim lSubBlock As IntPtr = Marshal.AllocHGlobal(512)
     Dim lValue As String = ""
    
     If NativeMethods.VerQueryValue(m_VersionInfo, _
             String.Format("\StringFileInfo\{0}\{1}", _
                 m_Translation, _
                 name), _
             lSubBlock, _
             lLen) Then
    
      lValue = Marshal.PtrToStringAnsi(lSubBlock, lLen - 1)
    
     End If
    
     Return lValue
     End Function
    
     Private Class NativeMethods
     <dllimport("version.dll")> _
     Friend Shared Function GetFileVersionInfo(ByVal filename As String, _
                ByVal handle As UInteger, _
                ByVal len As UInteger, _
                ByVal buffer As IntPtr) As Boolean
     End Function
    
     <runtime.interopservices.dllimport("version.dll")> _
     Friend Shared Function GetFileVersionInfoSize(ByVal filename As String, _
                 ByRef handle As UInteger _
                  ) As UInteger
    
     End Function
    
     <runtime.interopservices.dllimport("version.dll")> _
     Friend Shared Function VerQueryValue(ByVal buffer As IntPtr, _
               ByVal subblock As String, _
               ByRef blockbuffer As IntPtr, _
               ByRef len As UInteger) As Boolean
    
     End Function
     End Class
    
     Private disposedValue As Boolean = False ' To detect redundant calls
    
     ' IDisposable
     Protected Overridable Sub Dispose(ByVal disposing As Boolean)
     If Not Me.disposedValue Then
      If m_VersionInfo <> IntPtr.Zero Then
      Marshal.FreeHGlobal(m_VersionInfo)
      m_VersionInfo = IntPtr.Zero
      End If
     End If
     Me.disposedValue = True
     End Sub
    
    #Region " IDisposable Support "
     ' This code added by Visual Basic to correctly implement the disposable pattern.
     Public Sub Dispose() Implements IDisposable.Dispose
     ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
     Dispose(True)
     GC.SuppressFinalize(Me)
     End Sub
    #End Region
    
    End Class
    
    ' Anwendung:
    
     Dim lInfo As New ExtendedFileVersionInfo("D:\WindowsXP-KB898461-x86-DEU.exe")
     Debug.Print("Applies To: " & lInfo.GetString("Applies To"))
     Debug.Print("Engine: " & lInfo.GetString("Installer Engine"))
    
     lInfo.Dispose()
    

    Thorsten Dörfler
    Microsoft MVP Visual Basic
    vb-faq.de
    • Bearbeitet Thorsten Dörfler Dienstag, 10. August 2010 14:01 Codekorrektur
    • Als Antwort markiert Pomali Dienstag, 10. August 2010 14:03
    Montag, 9. August 2010 20:33
  • Vielen Dank für die Antwort.

    Die Klasse liefert mir genau das, was ich benötige.

    Ich musste eine Kleinigkeit anpassen, da die Funktion Getstring sonst einen Überlauf produziert hat.

    In der Funktion Getstring bei dem Aufruf für VerQueryValue:

    If NativeMethods.VerQueryValue(m_VersionInfo, _
             String.Format("\StringFileInfo\{0}\{1}", _
                 m_Translation, _
                 name), _
             lSubBlock, _
             lLen) Then
    
      lValue = Marshal.PtrToStringAnsi(lSubBlock, lLen)
    
     End If
    

    Hier musste ich hinter der Variable ILen die -1 entfernen.

    Gab es für diese Ziffer einen Grund, der eventuelle Fehler abfangen sollte?

    Wenn die Ziffer keine Rolle spielt würde ich das Thema als beantwortet markieren und mich nochmals bedanken für die sehr gute Lösung.

    mfg

    Pomali

    Dienstag, 10. August 2010 13:35
  • Hallo,

    Ich musste eine Kleinigkeit anpassen, da die Funktion Getstring sonst einen Überlauf produziert hat.

    In der Funktion Getstring bei dem Aufruf für VerQueryValue:

    If NativeMethods.VerQueryValue(m_VersionInfo, _
         String.Format("\StringFileInfo\{0}\{1}", _
           m_Translation, _
           name), _
         lSubBlock, _
         lLen) Then
    
     lValue = Marshal.PtrToStringAnsi(lSubBlock, lLen)
    
     End If
     

    Hier musste ich hinter der Variable ILen die -1 entfernen.

    Gab es für diese Ziffer einen Grund, der eventuelle Fehler abfangen sollte?

    Mein Fehler. Die -1 gehört eigentlich eine Anweisung weiter:

    lValue = Marshal.PtrToStringAnsi(lSubBlock, lLen - 1)
    

    Sonst hängt das abschließende Null-Char noch dran.


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    vb-faq.de
    Dienstag, 10. August 2010 13:59
  • Alles klar.

    Das Thema ist damit beantwortet. Nochmals vielen Dank.

    Pomali

    Dienstag, 10. August 2010 14:03