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


FindFirstUrlCacheEntry: Obtain the Contents of the IE Cache
FindFirstUrlCacheEntry: Delete the IE Cache
CoCreateInstance: Delete the IE History Cache
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_FILE_NOT_FOUND As Long = 2
Public Const ERROR_ACCESS_DENIED As Long = 5
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 NORMAL_CACHE_ENTRY As Long = &H1
Public Const EDITED_CACHE_ENTRY As Long = &H8
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
                                                   COOKIE_CACHE_ENTRY Or _
                                                   URLHISTORY_CACHE_ENTRY Or _
                                                   TRACK_OFFLINE_CACHE_ENTRY Or _
                                                   TRACK_ONLINE_CACHE_ENTRY Or _
Public Type FILETIME
   dwLowDateTime As Long
   dwHighDateTime As Long
End Type

   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"
      .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 ..."
   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 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
              '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
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..


PayPal Link
Make payments with PayPal - it's fast, free and secure!


Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy


Hit Counter