| 
 | 
|  |   |  | |
|  |  |  | |
|  |  | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 
 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|  | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Visual Basic Internet Routines FindFirstUrlCacheEntry: Obtain the Contents of the IE Cache | |
| Posted: | Monday October 4, 1999 | 
| Updated: | Monday December 26, 2011 | 
| Applies to: | VB4-32, VB5, VB6 | 
| Developed with: | VB6, Windows NT4 | 
| OS restrictions: | Internet Explorer | 
| Author: | VBnet - Randy Birch | 
| Related: | FindFirstUrlCacheEntry: Obtain the Contents of the IE Cache FindFirstUrlCacheEntry: Delete the IE Cache CoCreateInstance: Delete the IE History Cache | 
| Prerequisites | 
| Internet Explorer for full functionality. Other browsers do not use the Windows Internet cache for local file storage . | 
|  | 
|  Here
         is the first entry in manipulating Windows' Internet cache - retrieving visited files and cookies using the FindFirst/FindNextUrlCacheEntry
         APIs.  Thanks go out to CCRP buddies Brad and Ramon for assistance on this routine. While, as VB developers, we are familiar with passing C structures as VB user-defined types to API methods, these structures usually contained all the data returned, and so were defined with strings of fixed-lengths. The URL cache APIs however are variable-size structures - each call will result in data types differing in size - so the application must allocate sufficient data space for the successful call prior to calling. This involves using LocalAlloc, LocalFree, as well as CopyMemory to set up pointers to the allocated memory space. To use the Find URL APIs, a call is made passing a type of 0 length. The call fails with ERROR_INSUFFICIENT_BUFFER, and the APIs dwBuffer member contains the size of the structure needed to retrieve the data. Memory is allocated to this buffer using LocalAlloc, and the pointer to this memory is passed in place of the structure (a non-typical use of UDT-based APIs to VB programmers). One the call succeeds, CopyMemory is used again to move the memory buffer into a VB user-defined type, and then the string information is extracted using lstrlenA and lstrcpyA. Finally the memory pointer is freed with LocalFree. This process is repeated for each cache entry while the handle to the Find method remains valid. Once the last entry has been retrieved, FindNextUrlCacheEntry returns 0, and the loop terminates. So what can you do with this info? First is the obvious experimentation to see how different URLs and cache items are categorized (i.e. what XXX_CACHE_ENTRY type they correspond to. Second is the ability to programmatically delete all or selected items from the cache (not demonstrated in this example). And finally, it provides the ability to extend this into a personal parental 'Net Nanny', whereby the visited links could be loaded to a list for viewing or saving to a file, providing a means to monitor your child's Internet activity. | 
| BAS Module Code | 
|   | 
| Place the following code into the general declarations area of a bas module: | 
|  | 
| Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public Const ERROR_CACHE_FIND_FAIL As Long = 0
Public Const ERROR_CACHE_FIND_SUCCESS As Long = 1
Public Const ERROR_FILE_NOT_FOUND As Long = 2
Public Const ERROR_ACCESS_DENIED As Long = 5
Public Const ERROR_INSUFFICIENT_BUFFER As Long = 122
Public Const MAX_PATH  As Long = 260
Public Const MAX_CACHE_ENTRY_INFO_SIZE As Long = 4096
Public Const LMEM_FIXED As Long = &H0
Public Const LMEM_ZEROINIT As Long = &H40
Public Const LPTR As Long = (LMEM_FIXED Or LMEM_ZEROINIT)
Public Const NORMAL_CACHE_ENTRY As Long = &H1
Public Const EDITED_CACHE_ENTRY As Long = &H8
Public Const TRACK_OFFLINE_CACHE_ENTRY As Long = &H10
Public Const TRACK_ONLINE_CACHE_ENTRY As Long = &H20
Public Const STICKY_CACHE_ENTRY As Long = &H40
Public Const SPARSE_CACHE_ENTRY As Long = &H10000
Public Const COOKIE_CACHE_ENTRY As Long = &H100000
Public Const URLHISTORY_CACHE_ENTRY As Long = &H200000
Public Const URLCACHE_FIND_DEFAULT_FILTER As Long = NORMAL_CACHE_ENTRY Or _
                                                   COOKIE_CACHE_ENTRY Or _
                                                   URLHISTORY_CACHE_ENTRY Or _
                                                   TRACK_OFFLINE_CACHE_ENTRY Or _
                                                   TRACK_ONLINE_CACHE_ENTRY Or _
                                                   STICKY_CACHE_ENTRY
Public Type FILETIME
   dwLowDateTime As Long
   dwHighDateTime As Long
End Type
Public Type INTERNET_CACHE_ENTRY_INFO
   dwStructSize As Long
   lpszSourceUrlName As Long
   lpszLocalFileName As Long
   CacheEntryType  As Long
   dwUseCount As Long
   dwHitRate As Long
   dwSizeLow As Long
   dwSizeHigh As Long
   LastModifiedTime As FILETIME
   ExpireTime As FILETIME
   LastAccessTime As FILETIME
   LastSyncTime As FILETIME
   lpHeaderInfo As Long
   dwHeaderInfoSize As Long
   lpszFileExtension As Long
   dwExemptDelta  As Long
End Type
Public Declare Function FindFirstUrlCacheEntry Lib "wininet" _
   Alias "FindFirstUrlCacheEntryA" _
  (ByVal lpszUrlSearchPattern As String, _
   lpFirstCacheEntryInfo As Any, _
   lpdwFirstCacheEntryInfoBufferSize As Long) As Long
Public Declare Function FindNextUrlCacheEntry Lib "wininet" _
   Alias "FindNextUrlCacheEntryA" _
  (ByVal hEnumHandle As Long, _
   lpNextCacheEntryInfo As Any, _
   lpdwNextCacheEntryInfoBufferSize As Long) As Long
Public Declare Function FindCloseUrlCache Lib "wininet" _
   (ByVal hEnumHandle As Long) As Long
   
Public Declare Sub CopyMemory Lib "kernel32" _
   Alias "RtlMoveMemory" _
   (pDest As Any, _
    pSource As Any, _
    ByVal dwLength As Long)
Public Declare Function lstrcpyA Lib "kernel32" _
  (ByVal RetVal As String, ByVal Ptr As Long) As Long
                        
Public Declare Function lstrlenA Lib "kernel32" _
  (ByVal Ptr As Any) As Long
  
Public Declare Function LocalAlloc Lib "kernel32" _
   (ByVal uFlags As Long, _
    ByVal uBytes As Long) As Long
    
Public Declare Function LocalFree Lib "kernel32" _
   (ByVal hMem As Long) As Long | 
| Form Code | 
|   | 
| To a form, add a combo (Combo1), an command button (Command1), a list (List1), a textbox (Text1) and a label (Label1). Add the following code: | 
|  | 
| Option Explicit
Private Sub Form_Load()
   With Combo1
      .AddItem "Normal Entry"
      .ItemData(.NewIndex) = &H1
      .AddItem "Edited Entry (IE5)"
      .ItemData(.NewIndex) = &H8
      .AddItem "Offline Entry"
      .ItemData(.NewIndex) = &H10
      .AddItem "Online Entry"
      .ItemData(.NewIndex) = &H20
      .AddItem "Stick Entry"
      .ItemData(.NewIndex) = &H40
      .AddItem "Sparse Entry (n/a)"
      .ItemData(.NewIndex) = &H10000
      .AddItem "Cookies"
      .ItemData(.NewIndex) = &H100000
      .AddItem "Visited History"
      .ItemData(.NewIndex) = &H200000
      .AddItem "Default Filter"
      .ItemData(.NewIndex) = URLCACHE_FIND_DEFAULT_FILTER
      .ListIndex = 0
   End With
   
End Sub
Private Sub Command1_Click()
   Dim numEntries As Long
   Dim cacheType As Long
   
   cacheType = Combo1.ItemData(Combo1.ListIndex)
   
   Label1.Caption = "Working ..."
   Label1.Refresh
   
   List1.Clear
   List1.Visible = False
   
   numEntries = GetCacheURLList(cacheType)
   
   List1.Visible = True
   Label1.Caption = Format$(numEntries, "###,###,###,##0") & "files found"
   
End Sub
Private Sub List1_Click()
   Text1.Text = List1.List(List1.ListIndex)
   
End Sub
Private Function GetCacheURLList(cacheType As Long) As Long
    
   Dim ICEI As INTERNET_CACHE_ENTRY_INFO
   Dim hFile As Long
   Dim cachefile As String
   Dim nCount As Long
   Dim dwBuffer As Long
   Dim pntrICE As Long
   
  'Like other APIs, calling FindFirstUrlCacheEntry or
  'FindNextUrlCacheEntry with an insufficient buffer will
  'cause the API to fail, and its dwBuffer points to the
  'correct size required for a successful call.
   dwBuffer = 0
   
  'Call to determine the required buffer size
   hFile = FindFirstUrlCacheEntry(vbNullString, ByVal 0, dwBuffer)
   
  'both conditions should be met by the first call
   If (hFile = ERROR_CACHE_FIND_FAIL) And _
      (Err.LastDllError = ERROR_INSUFFICIENT_BUFFER) Then
   
     'The INTERNET_CACHE_ENTRY_INFO data type is a
     'variable-length type. It is necessary to allocate
     'memory for the result of the call and pass the
     'pointer to this memory location to the API.
      pntrICE = LocalAlloc(LMEM_FIXED, dwBuffer)
        
     'allocation successful
      If pntrICE Then
         
        'set a Long pointer to the memory location
         CopyMemory ByVal pntrICE, dwBuffer, 4
         
        'and call the first find API again passing the
        'pointer to the allocated memory
         hFile = FindFirstUrlCacheEntry(vbNullString, ByVal pntrICE, dwBuffer)
       
        'hfile should = 1 (success)
         If hFile <> ERROR_CACHE_FIND_FAIL Then
         
           'now just loop through the cache
            Do
            
              'the pointer has been filled, so move the
              'data back into a ICEI structure
               CopyMemory ICEI, ByVal pntrICE, Len(ICEI)
            
              'CacheEntryType is a long representing the type of
              'entry returned, and should match our passed param.
               If (ICEI.CacheEntryType And cacheType) Then
               
                  'extract the string from the memory location
                  'pointed to by the lpszSourceUrlName member
                  'and add to a list
                   cachefile = GetStrFromPtrA(ICEI.lpszSourceUrlName)
                   List1.AddItem cachefile
                   nCount = nCount + 1
               
               End If
               
              'free the pointer and memory associated
              'with the last-retrieved file
               Call LocalFree(pntrICE)
               
              'and again repeat the procedure, this time calling
              'FindNextUrlCacheEntry with a buffer size set to 0.
              'This will cause the call to once again fail,
              'returning the required size as dwBuffer
               dwBuffer = 0
               Call FindNextUrlCacheEntry(hFile, ByVal 0, dwBuffer)
               
              'allocate and assign the memory to the pointer
               pntrICE = LocalAlloc(LMEM_FIXED, dwBuffer)
               CopyMemory ByVal pntrICE, dwBuffer, 4
               
           'and call again with the valid parameters.
           'If the call fails (no more data), the loop exits.
           'If the call is successful, the Do portion of the
           'loop is executed again, extracting the data from
           'the returned type
            Loop While FindNextUrlCacheEntry(hFile, ByVal pntrICE, dwBuffer)
  
         End If 'hFile
         
      End If 'pntrICE
   
   End If 'hFile
   
  'clean up by closing the find handle, as
  'well as calling LocalFree again to be safe
   Call LocalFree(pntrICE)
   Call FindCloseUrlCache(hFile)
   
   GetCacheURLList = nCount
   
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 | 
| Comments | 
| Save the project, run, select a cache type to view, and hit Get Cache. Note too that some defined cache types are not yet implemented in Windows, or have specific version requirements.. | 
|  | 
| 
 | 
|  | |||||
| 
 | |||||
|  | |||||
| 
            	
            	Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. | 
|  |