Jump to content
Sign in to follow this  
Zinthose

SlowInfoCache w/ AutoIt3

Recommended Posts

Zinthose

Add & Remove Programs

If you open this little control panel applet you will find that Microsoft tracks some interesting data. What kind? Well, Locate AutoIt in the list and I'll show you. (I'm assuming you DO have it installed)

Once you select a software package from the list, you are presented with the following additional information.

  • Size
  • Used
  • Last Used On

post-34674-1209668712_thumb.gif

I don't know about you but to be able to query this data to see how much a workstation uses an application seems pretty useful to me. But were? How, dose windows track this?

Documentation on this subject is sparse at best but I was able to dig up enough crumbs to make a cookie. :)

Well, the data is stored in the registry at 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Management\ARPCache'. This directory is a mirror image of the Uninstall directory at 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'. That is except for the data in which we seek. Look in 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Management\ARPCache\AutoItv3' and you will find 'SlowInfoCache'. 'SlowInfoCache' is a REG_Binary value of 552 bytes in length. There is no Microsoft documentation on this so don't bother looking.

post-34674-1209669155_thumb.gif

Here is my code I through together to parse this data. If I did something that you feel is inefficient or or otherwise easily done another better way, please let me know. I'm still learning the syntax. =)

;App Management
#include <String.au3>
#Include <Memory.au3>
#include <Date.au3>

Dim $Example

$Example = _SlowInfoCache('AutoItv3')

#region  ### MAIN ###
    Func _SlowInfoCache($Uninstall_Title = '*') ;Return 

        Local Const $HKey  = "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Management\ARPCache"
        Local Const $VName = "SlowInfoCache"
        
        Local $j = 0
        Local $i = 0
        
        Local $Temp
        
        #region tyedef struct SIZE_INT64
            $Size_Struct = 'int64'
            
            $Size_INT64 = DllStructCreate($Size_Struct)
        #endregion
        
        #region tyedef struct SIZE_CHAR
            $Size_Struct = 'char Size[8]'
            
            $Size_CHAR = DllStructCreate($Size_Struct)
        #endregion

        #region typedef struct FILETIME
            $LastUsed_Struc  = "uint dwLowDateTime;"
            $LastUsed_Struc &= "uint dwHighDateTime"
            
            $LastUsed = DllStructCreate($LastUsed_Struc)
        #endregion

    ;~  #region typedef struct SYSTEMTIME
    ;~      $SystemTime_Struc  = 'short wYear;'
    ;~      $SystemTime_Struc &= 'short wMonth;'
    ;~      $SystemTime_Struc &= 'short wDayOfWeek;'
    ;~      $SystemTime_Struc &= 'short wDay;'
    ;~      $SystemTime_Struc &= 'short wHour;'
    ;~      $SystemTime_Struc &= 'short wMinute;'
    ;~      $SystemTime_Struc &= 'short wSecond;'
    ;~      $SystemTime_Struc &= 'short wMilliseconds'
    ;~      
    ;~      $SystemTime = DllStructCreate($SystemTime_Struc)
    ;~  #endregion
        
    ;~  #region typedef struct SlowInfoCache [DLL]
    ;~      $SlowInfoCache_Struc  = "uint cLen;"            ; size of the SlowInfoCache (552 bytes)
    ;~      $SlowInfoCache_Struc &= "uint Flag;"            ; unknown
    ;~      $SlowInfoCache_Struc &= "uint64 Size;"          ; program size in bytes
    ;~      $SlowInfoCache_Struc &= "uint64 LastUsed;"      ; API-style FILETIME
    ;~      $SlowInfoCache_Struc &= "uint Frequency;"       ; 0-2 = rarely; 3-9 = occassionaly; 10+ = frequently
    ;~      $SlowInfoCache_Struc &= "char Path[524]"        ; remaining 524 bytes (max path of 260 + null) in unicode
    ;~  #endregion
    ;~  
        #region typedef struct SlowInfoCache
            Local $SlowInfoCache_cLen       ;As DWORD       ; size of the SlowInfoCache (552 bytes)
            Local $SlowInfoCache_HasName    ;As LongBool    ; unknown
            Local $SlowInfoCache_Size       ;As Int64       ; program size in bytes
            Local $SlowInfoCache_LastUsed   ;As TFileTime       ; API-style FILETIME
            Local $SlowInfoCache_Frequency  ;As Integer     ; 0-2 = rarely; 3-9 = occassionaly; 10+ = frequently
            Local $SlowInfoCache_Path       ;As String      ; remaining 524 bytes (max path of 260 + null) in unicode
        #endregion

        #region If a uninstall title in undefined, we enumerate all the applications
            If $Uninstall_Title = '*' Then
                While True
                    $i += 1
                    $Uninstall_Title = RegEnumKey($HKey, $i)
                    If @error <> 0 then ExitLoop
                    $Temp[$i] = _SlowInfoCache($Uninstall_Title)
                WEnd
                Return $Temp
            EndIf
        #endregion
        
        $RawData = RegRead($HKey & '\' & $Uninstall_Title, $VName)

        #region Extract DataSets
            $SlowInfoCache_cLen         = StringMid($RawData, 1, 8)
            $SlowInfoCache_Flag         = StringMid($RawData, 9, 8)
            $SlowInfoCache_Size         = StringMid($RawData, 17, 16)
            $SlowInfoCache_LastUsed     = StringMid($RawData, 33, 16)
            $SlowInfoCache_Frequency    = StringMid($RawData, 49, 8)
            $SlowInfoCache_Path         = StringMid($RawData, 57)
        #endregion
        
        #region Correct the Bit-Order
            $SlowInfoCache_cLen         = FixBitOrder($SlowInfoCache_cLen)
            $SlowInfoCache_Flag         = FixBitOrder($SlowInfoCache_Flag)
            $SlowInfoCache_LastUsed     = FixBitOrder($SlowInfoCache_LastUsed, 8)
            $SlowInfoCache_Frequency    = FixBitOrder($SlowInfoCache_Frequency)
            $SlowInfoCache_Path         = FixBitOrder($SlowInfoCache_Path, 4)
        #endregion
        
        
        #region Convert Size hex string to int64
            
            ;** Things get tricky here..
            ;** Basically the $SlowInfoCache_Size value is a int64 value trapped in a hex string value and we need to fix that.
            ;** The only method that I have reliably got to work is a windows API memory move operation (AKA: Mystical Stuff).
            
            ;** Pump the string value into a DLL Struc to prep for conversion
            For $i = 1 to StringLen($SlowInfoCache_Size) Step 2
                $Temp = StringMid($SlowInfoCache_Size, $i, 2)   ;** Step 1: Get a Byte with of hex data.                
                $Temp = Dec($Temp)                              ;** Step 2: Convert the Hex value to a Decimal
                $Temp = Chr($Temp)                              ;** Step 3: Convert the Decimal Value into an Ascii character.
                $j += 1
                DllStructSetData($Size_CHAR, 1, $Temp, $j)      ;** Step 4: Add Ascii character to the type Structure we will use to convert the data
            Next
            
            ;** Magically transform the charactor array of $SlowInfoCache_Size into an int64 value.  (P.S. 'Dec' function fails due to a 32bit limitations)
            _MemMoveMemory(DllStructGetPtr($Size_CHAR), DllStructGetPtr($Size_INT64), 8)
            
            ;  POOOOF!!!
            
            ;** Sometimes magic backfires
            If @error Then
                MsgBox(0, "", 'Magic spell "_MemMoveMemory", backfired!! : ' & @error)
                Exit 0x0F00
            EndIf
            
            ;** It worked!!  /Cheer Magic
            $SlowInfoCache_Size = DllStructGetData($Size_INT64, 1)
            
            #region CleanUp
                $Size_INT64 = 0
                $Size_CHAR = 0
                $Temp = 0
            #endregion
            
        #endregion
        
        #region Create LastUsed FILETIME Structure
            
            DllStructSetData($LastUsed, 1, Dec(StringMid($SlowInfoCache_LastUsed, 1, 8)))
            DllStructSetData($LastUsed, 2, Dec(StringMid($SlowInfoCache_LastUsed, 9, 8)))
            
            $SlowInfoCache_LastUsed = _Date_Time_FileTimeToStr($LastUsed)
            
        #endregion

        #region Convert to human readable
            $SlowInfoCache_cLen         = Dec($SlowInfoCache_cLen)
            $SlowInfoCache_Flag         = Dec($SlowInfoCache_Flag)
            $SlowInfoCache_Frequency    = Dec($SlowInfoCache_Frequency)
            $SlowInfoCache_Path         = HexToUnicode($SlowInfoCache_Path)
        #endregion
        
        #region Return Array of data
            Dim $SlowInfoCache[7] 
            
            $SlowInfoCache[0] = $Uninstall_Title
            $SlowInfoCache[1] = $SlowInfoCache_cLen
            $SlowInfoCache[2] = $SlowInfoCache_Flag
            $SlowInfoCache[3] = $SlowInfoCache_Size
            $SlowInfoCache[4] = $SlowInfoCache_LastUsed
            $SlowInfoCache[5] = $SlowInfoCache_Frequency
            $SlowInfoCache[6] = $SlowInfoCache_Path
            
            Return $SlowInfoCache
        #endregion
        
    EndFunc
#endregion

#region Support Functions

    Func Debug($Message, $Title = '!NOT DEFINED : ')
        If Not @Compiled Then ConsoleWrite('!' & $Title & $Message & @CRLF)
    EndFunc
    
    Func Err($Code, $Description = 'NOT_DEFINED', $Fatal = False)
        Local $XML_Output
        ;** Print Error Data to error IO Stream
        
        ;** <ERROR Fatal="True">
            If $Fatal Then
                $XML_Output = '<ERROR Fatal="True">'
            Else
                $XML_Output = '<ERROR>'
            EndIf
            
        #cs** 
                <ReturnCode>$Code</ReturnCode>
                <Description>$Descriptiomn</Description>
                <Fatal>$Fatal</Fatal>
            </ERROR>
        #ce
            $XML_Output &= @CRLF & @TAB & '<ReturnCode>' & $Code & '</ReturnCode>' & @CRLF & @TAB & '<Description>' & $Description & '</Description>' & @CRLF & '</ERROR>' & @CRLF
        
        ;** Print XML data to Error IO Stream
            ConsoleWriteError($XML_Output)
        
        ;** If this is a fatal error then we terminate the script
            If $Fatal Then
                Exit $Code
            EndIf
        
        ;** Return the Error Code so the calling procedure can take the appropriate action
            Return $Code
    EndFunc
    
    Func HexToUnicode($Data)
        Local $Unicode = ""
        For $i = 1 to StringLen($Data) Step 4
            
            $Value = Dec(StringMid($Data, $i, 4))
            
            If $Value = 0 Then Return $Unicode
            
            $Unicode &= ChrW($Value)
        Next
        
        Return $Unicode
        
    EndFunc
    
    Func FixBitOrder($Data, $Bits = -1)
        Local $Shifted = ""
        Local $Temp
        
        If $Bits = -1 Then $Bits = StringLen($Data)
        
        For $i = 1 to StringLen($Data) Step $Bits
            $Temp = ""
            For $j = 0 to $Bits -1 Step 2
                $Temp = StringMid($Data,$j + $i, 2) & $Temp
            Next
            $Shifted &= $Temp
        Next
        
        Return $Shifted
        
    EndFunc
#endregion

It's a kinda work in progress. Enjoy!! :(


--- TTFN

Share this post


Link to post
Share on other sites
Zinthose

Added Example...

;App Management
#include <String.au3>
#Include <Memory.au3>
#include <Date.au3>

Dim $Example
Dim $Message

$Example = _SlowInfoCache('AutoItv3')

$Message  = 'Uninstall Name:' & @TAB & $Example[0] & @CRLF
$Message &= '           Len:' & @TAB & $Example[1] & @CRLF
$Message &= '      Has Name:' & @TAB & $Example[2] & @CRLF
$Message &= ' Size in Bytes:' & @TAB & $Example[3] & @CRLF
$Message &= '     Last Used:' & @TAB & $Example[4] & @CRLF
$Message &= '     Frequency:' & @TAB & $Example[5] & @CRLF
$Message &= '          Path:' & @TAB & $Example[6] & @CRLF

MsgBox(0, "SlowInfoCache - Example", $Message)

#region  ### MAIN ###
    Func _SlowInfoCache($Uninstall_Title = '*') ;Return 

        Local Const $HKey  = "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Management\ARPCache"
        Local Const $VName = "SlowInfoCache"
        
        Local $j = 0
        Local $i = 0
        
        Local $Temp
        
        #region tyedef struct SIZE_INT64
            $Size_Struct = 'int64'
            
            $Size_INT64 = DllStructCreate($Size_Struct)
        #endregion
        
        #region tyedef struct SIZE_CHAR
            $Size_Struct = 'char Size[8]'
            
            $Size_CHAR = DllStructCreate($Size_Struct)
        #endregion

        #region typedef struct FILETIME
            $LastUsed_Struc  = "uint dwLowDateTime;"
            $LastUsed_Struc &= "uint dwHighDateTime"
            
            $LastUsed = DllStructCreate($LastUsed_Struc)
        #endregion

    ;~  #region typedef struct SYSTEMTIME
    ;~      $SystemTime_Struc  = 'short wYear;'
    ;~      $SystemTime_Struc &= 'short wMonth;'
    ;~      $SystemTime_Struc &= 'short wDayOfWeek;'
    ;~      $SystemTime_Struc &= 'short wDay;'
    ;~      $SystemTime_Struc &= 'short wHour;'
    ;~      $SystemTime_Struc &= 'short wMinute;'
    ;~      $SystemTime_Struc &= 'short wSecond;'
    ;~      $SystemTime_Struc &= 'short wMilliseconds'
    ;~      
    ;~      $SystemTime = DllStructCreate($SystemTime_Struc)
    ;~  #endregion
        
    ;~  #region typedef struct SlowInfoCache [DLL]
    ;~      $SlowInfoCache_Struc  = "uint cLen;"            ; size of the SlowInfoCache (552 bytes)
    ;~      $SlowInfoCache_Struc &= "uint Flag;"            ; unknown
    ;~      $SlowInfoCache_Struc &= "uint64 Size;"          ; program size in bytes
    ;~      $SlowInfoCache_Struc &= "uint64 LastUsed;"      ; API-style FILETIME
    ;~      $SlowInfoCache_Struc &= "uint Frequency;"       ; 0-2 = rarely; 3-9 = occassionaly; 10+ = frequently
    ;~      $SlowInfoCache_Struc &= "char Path[524]"        ; remaining 524 bytes (max path of 260 + null) in unicode
    ;~  #endregion
    ;~  
        #region typedef struct SlowInfoCache
            Local $SlowInfoCache_cLen       ;As DWORD       ; size of the SlowInfoCache (552 bytes)
            Local $SlowInfoCache_HasName    ;As LongBool    ; unknown
            Local $SlowInfoCache_Size       ;As Int64       ; program size in bytes
            Local $SlowInfoCache_LastUsed   ;As TFileTime       ; API-style FILETIME
            Local $SlowInfoCache_Frequency  ;As Integer     ; 0-2 = rarely; 3-9 = occassionaly; 10+ = frequently
            Local $SlowInfoCache_Path       ;As String      ; remaining 524 bytes (max path of 260 + null) in unicode
        #endregion

        #region If a uninstall title in undefined, we enumerate all the applications
            If $Uninstall_Title = '*' Then
                While True
                    $i += 1
                    $Uninstall_Title = RegEnumKey($HKey, $i)
                    If @error <> 0 then ExitLoop
                    $Temp[$i] = _SlowInfoCache($Uninstall_Title)
                WEnd
                Return $Temp
            EndIf
        #endregion
        
        $RawData = RegRead($HKey & '\' & $Uninstall_Title, $VName)

        #region Extract DataSets
            $SlowInfoCache_cLen         = StringMid($RawData, 1, 8)
            $SlowInfoCache_Flag         = StringMid($RawData, 9, 8)
            $SlowInfoCache_Size         = StringMid($RawData, 17, 16)
            $SlowInfoCache_LastUsed     = StringMid($RawData, 33, 16)
            $SlowInfoCache_Frequency    = StringMid($RawData, 49, 8)
            $SlowInfoCache_Path         = StringMid($RawData, 57)
        #endregion
        
        #region Correct the Bit-Order
            $SlowInfoCache_cLen         = FixBitOrder($SlowInfoCache_cLen)
            $SlowInfoCache_Flag         = FixBitOrder($SlowInfoCache_Flag)
            $SlowInfoCache_LastUsed     = FixBitOrder($SlowInfoCache_LastUsed, 8)
            $SlowInfoCache_Frequency    = FixBitOrder($SlowInfoCache_Frequency)
            $SlowInfoCache_Path         = FixBitOrder($SlowInfoCache_Path, 4)
        #endregion
        
        
        #region Convert Size hex string to int64
            
            ;** Things get tricky here..
            ;** Basically the $SlowInfoCache_Size value is a int64 value trapped in a hex string value and we need to fix that.
            ;** The only method that I have reliably got to work is a windows API memory move operation (AKA: Mystical Stuff).
            
            ;** Pump the string value into a DLL Struc to prep for conversion
            For $i = 1 to StringLen($SlowInfoCache_Size) Step 2
                $Temp = StringMid($SlowInfoCache_Size, $i, 2)   ;** Step 1: Get a Byte with of hex data.                
                $Temp = Dec($Temp)                              ;** Step 2: Convert the Hex value to a Decimal
                $Temp = Chr($Temp)                              ;** Step 3: Convert the Decimal Value into an Ascii character.
                $j += 1
                DllStructSetData($Size_CHAR, 1, $Temp, $j)      ;** Step 4: Add Ascii character to the type Structure we will use to convert the data
            Next
            
            ;** Magically transform the charactor array of $SlowInfoCache_Size into an int64 value.  (P.S. 'Dec' function fails due to a 32bit limitations)
            _MemMoveMemory(DllStructGetPtr($Size_CHAR), DllStructGetPtr($Size_INT64), 8)
            
            ;  POOOOF!!!
            
            ;** Sometimes magic backfires
            If @error Then
                MsgBox(0, "", 'Magic spell "_MemMoveMemory", backfired!! : ' & @error)
                Exit 0x0F00
            EndIf
            
            ;** It worked!!  /Cheer Magic
            $SlowInfoCache_Size = DllStructGetData($Size_INT64, 1)
            
            #region CleanUp
                $Size_INT64 = 0
                $Size_CHAR = 0
                $Temp = 0
            #endregion
            
        #endregion
        
        #region Create LastUsed FILETIME Structure
            
            DllStructSetData($LastUsed, 1, Dec(StringMid($SlowInfoCache_LastUsed, 1, 8)))
            DllStructSetData($LastUsed, 2, Dec(StringMid($SlowInfoCache_LastUsed, 9, 8)))
            
            $SlowInfoCache_LastUsed = _Date_Time_FileTimeToStr($LastUsed)
            
        #endregion

        #region Convert to human readable
            $SlowInfoCache_cLen         = Dec($SlowInfoCache_cLen)
            $SlowInfoCache_Flag         = Dec($SlowInfoCache_Flag)
            $SlowInfoCache_Frequency    = Dec($SlowInfoCache_Frequency)
            $SlowInfoCache_Path         = HexToUnicode($SlowInfoCache_Path)
        #endregion
        
        #region Return Array of data
            Dim $SlowInfoCache[7] 
            
            $SlowInfoCache[0] = $Uninstall_Title
            $SlowInfoCache[1] = $SlowInfoCache_cLen
            $SlowInfoCache[2] = $SlowInfoCache_Flag
            $SlowInfoCache[3] = $SlowInfoCache_Size
            $SlowInfoCache[4] = $SlowInfoCache_LastUsed
            $SlowInfoCache[5] = $SlowInfoCache_Frequency
            $SlowInfoCache[6] = $SlowInfoCache_Path
            
            Return $SlowInfoCache
        #endregion
        
    EndFunc
#endregion

#region Support Functions

    Func Debug($Message, $Title = '!NOT DEFINED : ')
        If Not @Compiled Then ConsoleWrite('!' & $Title & $Message & @CRLF)
    EndFunc
    
    Func Err($Code, $Description = 'NOT_DEFINED', $Fatal = False)
        Local $XML_Output
        ;** Print Error Data to error IO Stream
        
        ;** <ERROR Fatal="True">
            If $Fatal Then
                $XML_Output = '<ERROR Fatal="True">'
            Else
                $XML_Output = '<ERROR>'
            EndIf
            
        #cs** 
                <ReturnCode>$Code</ReturnCode>
                <Description>$Descriptiomn</Description>
                <Fatal>$Fatal</Fatal>
            </ERROR>
        #ce
            $XML_Output &= @CRLF & @TAB & '<ReturnCode>' & $Code & '</ReturnCode>' & @CRLF & @TAB & '<Description>' & $Description & '</Description>' & @CRLF & '</ERROR>' & @CRLF
        
        ;** Print XML data to Error IO Stream
            ConsoleWriteError($XML_Output)
        
        ;** If this is a fatal error then we terminate the script
            If $Fatal Then
                Exit $Code
            EndIf
        
        ;** Return the Error Code so the calling procedure can take the appropriate action
            Return $Code
    EndFunc
    
    Func HexToUnicode($Data)
        Local $Unicode = ""
        For $i = 1 to StringLen($Data) Step 4
            
            $Value = Dec(StringMid($Data, $i, 4))
            
            If $Value = 0 Then Return $Unicode
            
            $Unicode &= ChrW($Value)
        Next
        
        Return $Unicode
        
    EndFunc
    
    Func FixBitOrder($Data, $Bits = -1)
        Local $Shifted = ""
        Local $Temp
        
        If $Bits = -1 Then $Bits = StringLen($Data)
        
        For $i = 1 to StringLen($Data) Step $Bits
            $Temp = ""
            For $j = 0 to $Bits -1 Step 2
                $Temp = StringMid($Data,$j + $i, 2) & $Temp
            Next
            $Shifted &= $Temp
        Next
        
        Return $Shifted
        
    EndFunc
#endregion

--- TTFN

Share this post


Link to post
Share on other sites
martin

Add & Remove Programs

If you open this little control panel applet you will find that Microsoft tracks some interesting data. What kind? Well, Locate AutoIt in the list and I'll show you. (I'm assuming you DO have it installed)

Once you select a software package from the list, you are presented with the following additional information.

  • Size
  • Used
  • Last Used On

post-34674-1209668712_thumb.gif

I don't know about you but to be able to query this data to see how much a workstation uses an application seems pretty useful to me. But were? How, dose windows track this?

Documentation on this subject is sparse at best but I was able to dig up enough crumbs to make a cookie. :)

Well, the data is stored in the registry at 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Management\ARPCache'. This directory is a mirror image of the Uninstall directory at 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'. That is except for the data in which we seek. Look in 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Management\ARPCache\AutoItv3' and you will find 'SlowInfoCache'. 'SlowInfoCache' is a REG_Binary value of 552 bytes in length. There is no Microsoft documentation on this so don't bother looking.

post-34674-1209669155_thumb.gif

Here is my code I through together to parse this data. If I did something that you feel is inefficient or or otherwise easily done another better way, please let me know. I'm still learning the syntax. =)

;App Management
#include <String.au3>
#Include <Memory.au3>
#include <Date.au3>

Dim $Example

$Example = _SlowInfoCache('AutoItv3')

#region  ### MAIN ###
    Func _SlowInfoCache($Uninstall_Title = '*') ;Return 

        Local Const $HKey  = "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Management\ARPCache"
        Local Const $VName = "SlowInfoCache"
        
        Local $j = 0
        Local $i = 0
        
        Local $Temp
        
        #region tyedef struct SIZE_INT64
            $Size_Struct = 'int64'
            
            $Size_INT64 = DllStructCreate($Size_Struct)
        #endregion
        
        #region tyedef struct SIZE_CHAR
            $Size_Struct = 'char Size[8]'
            
            $Size_CHAR = DllStructCreate($Size_Struct)
        #endregion

        #region typedef struct FILETIME
            $LastUsed_Struc  = "uint dwLowDateTime;"
            $LastUsed_Struc &= "uint dwHighDateTime"
            
            $LastUsed = DllStructCreate($LastUsed_Struc)
        #endregion

    ;~  #region typedef struct SYSTEMTIME
    ;~      $SystemTime_Struc  = 'short wYear;'
    ;~      $SystemTime_Struc &= 'short wMonth;'
    ;~      $SystemTime_Struc &= 'short wDayOfWeek;'
    ;~      $SystemTime_Struc &= 'short wDay;'
    ;~      $SystemTime_Struc &= 'short wHour;'
    ;~      $SystemTime_Struc &= 'short wMinute;'
    ;~      $SystemTime_Struc &= 'short wSecond;'
    ;~      $SystemTime_Struc &= 'short wMilliseconds'
    ;~      
    ;~      $SystemTime = DllStructCreate($SystemTime_Struc)
    ;~  #endregion
        
    ;~  #region typedef struct SlowInfoCache [DLL]
    ;~      $SlowInfoCache_Struc  = "uint cLen;"            ; size of the SlowInfoCache (552 bytes)
    ;~      $SlowInfoCache_Struc &= "uint Flag;"            ; unknown
    ;~      $SlowInfoCache_Struc &= "uint64 Size;"          ; program size in bytes
    ;~      $SlowInfoCache_Struc &= "uint64 LastUsed;"      ; API-style FILETIME
    ;~      $SlowInfoCache_Struc &= "uint Frequency;"       ; 0-2 = rarely; 3-9 = occassionaly; 10+ = frequently
    ;~      $SlowInfoCache_Struc &= "char Path[524]"        ; remaining 524 bytes (max path of 260 + null) in unicode
    ;~  #endregion
    ;~  
        #region typedef struct SlowInfoCache
            Local $SlowInfoCache_cLen       ;As DWORD       ; size of the SlowInfoCache (552 bytes)
            Local $SlowInfoCache_HasName    ;As LongBool    ; unknown
            Local $SlowInfoCache_Size       ;As Int64       ; program size in bytes
            Local $SlowInfoCache_LastUsed   ;As TFileTime       ; API-style FILETIME
            Local $SlowInfoCache_Frequency  ;As Integer     ; 0-2 = rarely; 3-9 = occassionaly; 10+ = frequently
            Local $SlowInfoCache_Path       ;As String      ; remaining 524 bytes (max path of 260 + null) in unicode
        #endregion

        #region If a uninstall title in undefined, we enumerate all the applications
            If $Uninstall_Title = '*' Then
                While True
                    $i += 1
                    $Uninstall_Title = RegEnumKey($HKey, $i)
                    If @error <> 0 then ExitLoop
                    $Temp[$i] = _SlowInfoCache($Uninstall_Title)
                WEnd
                Return $Temp
            EndIf
        #endregion
        
        $RawData = RegRead($HKey & '\' & $Uninstall_Title, $VName)

        #region Extract DataSets
            $SlowInfoCache_cLen         = StringMid($RawData, 1, 8)
            $SlowInfoCache_Flag         = StringMid($RawData, 9, 8)
            $SlowInfoCache_Size         = StringMid($RawData, 17, 16)
            $SlowInfoCache_LastUsed     = StringMid($RawData, 33, 16)
            $SlowInfoCache_Frequency    = StringMid($RawData, 49, 8)
            $SlowInfoCache_Path         = StringMid($RawData, 57)
        #endregion
        
        #region Correct the Bit-Order
            $SlowInfoCache_cLen         = FixBitOrder($SlowInfoCache_cLen)
            $SlowInfoCache_Flag         = FixBitOrder($SlowInfoCache_Flag)
            $SlowInfoCache_LastUsed     = FixBitOrder($SlowInfoCache_LastUsed, 8)
            $SlowInfoCache_Frequency    = FixBitOrder($SlowInfoCache_Frequency)
            $SlowInfoCache_Path         = FixBitOrder($SlowInfoCache_Path, 4)
        #endregion
        
        
        #region Convert Size hex string to int64
            
            ;** Things get tricky here..
            ;** Basically the $SlowInfoCache_Size value is a int64 value trapped in a hex string value and we need to fix that.
            ;** The only method that I have reliably got to work is a windows API memory move operation (AKA: Mystical Stuff).
            
            ;** Pump the string value into a DLL Struc to prep for conversion
            For $i = 1 to StringLen($SlowInfoCache_Size) Step 2
                $Temp = StringMid($SlowInfoCache_Size, $i, 2)   ;** Step 1: Get a Byte with of hex data.                
                $Temp = Dec($Temp)                              ;** Step 2: Convert the Hex value to a Decimal
                $Temp = Chr($Temp)                              ;** Step 3: Convert the Decimal Value into an Ascii character.
                $j += 1
                DllStructSetData($Size_CHAR, 1, $Temp, $j)      ;** Step 4: Add Ascii character to the type Structure we will use to convert the data
            Next
            
            ;** Magically transform the charactor array of $SlowInfoCache_Size into an int64 value.  (P.S. 'Dec' function fails due to a 32bit limitations)
            _MemMoveMemory(DllStructGetPtr($Size_CHAR), DllStructGetPtr($Size_INT64), 8)
            
            ;  POOOOF!!!
            
            ;** Sometimes magic backfires
            If @error Then
                MsgBox(0, "", 'Magic spell "_MemMoveMemory", backfired!! : ' & @error)
                Exit 0x0F00
            EndIf
            
            ;** It worked!!  /Cheer Magic
            $SlowInfoCache_Size = DllStructGetData($Size_INT64, 1)
            
            #region CleanUp
                $Size_INT64 = 0
                $Size_CHAR = 0
                $Temp = 0
            #endregion
            
        #endregion
        
        #region Create LastUsed FILETIME Structure
            
            DllStructSetData($LastUsed, 1, Dec(StringMid($SlowInfoCache_LastUsed, 1, 8)))
            DllStructSetData($LastUsed, 2, Dec(StringMid($SlowInfoCache_LastUsed, 9, 8)))
            
            $SlowInfoCache_LastUsed = _Date_Time_FileTimeToStr($LastUsed)
            
        #endregion

        #region Convert to human readable
            $SlowInfoCache_cLen         = Dec($SlowInfoCache_cLen)
            $SlowInfoCache_Flag         = Dec($SlowInfoCache_Flag)
            $SlowInfoCache_Frequency    = Dec($SlowInfoCache_Frequency)
            $SlowInfoCache_Path         = HexToUnicode($SlowInfoCache_Path)
        #endregion
        
        #region Return Array of data
            Dim $SlowInfoCache[7] 
            
            $SlowInfoCache[0] = $Uninstall_Title
            $SlowInfoCache[1] = $SlowInfoCache_cLen
            $SlowInfoCache[2] = $SlowInfoCache_Flag
            $SlowInfoCache[3] = $SlowInfoCache_Size
            $SlowInfoCache[4] = $SlowInfoCache_LastUsed
            $SlowInfoCache[5] = $SlowInfoCache_Frequency
            $SlowInfoCache[6] = $SlowInfoCache_Path
            
            Return $SlowInfoCache
        #endregion
        
    EndFunc
#endregion

#region Support Functions

    Func Debug($Message, $Title = '!NOT DEFINED : ')
        If Not @Compiled Then ConsoleWrite('!' & $Title & $Message & @CRLF)
    EndFunc
    
    Func Err($Code, $Description = 'NOT_DEFINED', $Fatal = False)
        Local $XML_Output
        ;** Print Error Data to error IO Stream
        
        ;** <ERROR Fatal="True">
            If $Fatal Then
                $XML_Output = '<ERROR Fatal="True">'
            Else
                $XML_Output = '<ERROR>'
            EndIf
            
        #cs** 
                <ReturnCode>$Code</ReturnCode>
                <Description>$Descriptiomn</Description>
                <Fatal>$Fatal</Fatal>
            </ERROR>
        #ce
            $XML_Output &= @CRLF & @TAB & '<ReturnCode>' & $Code & '</ReturnCode>' & @CRLF & @TAB & '<Description>' & $Description & '</Description>' & @CRLF & '</ERROR>' & @CRLF
        
        ;** Print XML data to Error IO Stream
            ConsoleWriteError($XML_Output)
        
        ;** If this is a fatal error then we terminate the script
            If $Fatal Then
                Exit $Code
            EndIf
        
        ;** Return the Error Code so the calling procedure can take the appropriate action
            Return $Code
    EndFunc
    
    Func HexToUnicode($Data)
        Local $Unicode = ""
        For $i = 1 to StringLen($Data) Step 4
            
            $Value = Dec(StringMid($Data, $i, 4))
            
            If $Value = 0 Then Return $Unicode
            
            $Unicode &= ChrW($Value)
        Next
        
        Return $Unicode
        
    EndFunc
    
    Func FixBitOrder($Data, $Bits = -1)
        Local $Shifted = ""
        Local $Temp
        
        If $Bits = -1 Then $Bits = StringLen($Data)
        
        For $i = 1 to StringLen($Data) Step $Bits
            $Temp = ""
            For $j = 0 to $Bits -1 Step 2
                $Temp = StringMid($Data,$j + $i, 2) & $Temp
            Next
            $Shifted &= $Temp
        Next
        
        Return $Shifted
        
    EndFunc
#endregion

It's a kinda work in progress. Enjoy!! :(

Welcome to the AutoIt Forums.

Very nice script.

It looks like "LastUsed" is actually "Installed". What do you think?


Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites
Zinthose

Welcome to the AutoIt Forums.

Very nice script.

It looks like "LastUsed" is actually "Installed". What do you think?

Actually Last Used is the last time you executed the application. Microsoft dose allot of guessing and it isn't 100% accurate. I verified it dose indeed change when I close and reopen the application when the clock is set for a different day.


--- TTFN

Share this post


Link to post
Share on other sites
JamesDover

Excellent Program very interesting how it works. Do you know how it rates programs like Office for ARPCache frequency of use. Like does it rate it by time used or the amount of times opened.

Share this post


Link to post
Share on other sites
Zinthose

Excellent Program very interesting how it works. Do you know how it rates programs like Office for ARPCache frequency of use. Like does it rate it by time used or the amount of times opened.

There is still some mystery involved but here is what I know.

  • Only Applications listed in the [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall] registry are monitored
  • Positive detections are triggered when a shortcut from that application is executed from the start menu / programs / desktop (this is still a mystery)
  • The count is tracked for 30 days. (The location of the 30 day timer is not yet know)

If you needed to track a particular program that is not listed in the uninstall path. You can manually create an entry and windows will start tracking it.

Edited by Zinthose

--- TTFN

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×