MSIE Cache History Retrieval
;------------------------------------------------------------------------------------------------------------------------------------------
;
; MSIE Cache history retrieval.
;
;------------------------------------------------------------------------------------------------------------------------------------------
; DLL calls and Binary handling code thanks to Guido 04/03.
; Misc modifications, sorting and HTML code by Crypt 04/03.
;------------------------------------------------------------------------------------------------------------------------------------------
; (c)20100225. Detlev Dalitz. Code rewritten and expanded.
;------------------------------------------------------------------------------------------------------------------------------------------

BoxOpen ("Processing History", "")
WinPlace (100, 100, 900, 250, "")

strFileOut = ShortCutDir ("Local Settings") : "\Temp\Cache.History.htm"
strListUrls = ""

strSearchTarget = ""         ; Search all content entries in the cache.
;strSearchTarget = "cookie:"  ; Search cookie entries in the cache.
;strSearchTarget = "visited:" ; Search URL history entries in the cache.

;blnUseMilliSecond = @FALSE
blnUseMilliSecond = @TRUE


; Load DLL's.
hdlWinInet  = DllLoad (DirWindows (1) : "WININET.DLL")
hdlKernel32 = DllLoad (DirWindows (1) : "KERNEL32.DLL")

; Constants.
ERROR_CACHE_FIND_FAIL     = 0
ERROR_INVALID_PARAMETER   = 87
ERROR_INSUFFICIENT_BUFFER = 122
ERROR_NO_MORE_ITEMS       = 259

; Binary Buffers.
hdlST = BinaryAlloc (16) ; Buffer to hold structure. ST = SYSTEMTIME Structure.

lpcbCacheEntryInfo = BinaryAlloc (4) ; Binary buffer to hold structure size (number of TCHARs copied to the buffer).
BinaryEodSet (lpcbCacheEntryInfo, 4)
BinaryPoke4 (lpcbCacheEntryInfo, 0, 1) ; Needs to be set to value 1 as start size for later DLLCalls.

intICEISizeMax = 0
hdlICEI = BinaryAlloc (intICEISizeMax) ; Binary buffer to hold structure. ICEI = INTERNET_CACHE_ENTRY_INFO Structure.


; Find first entry.

; Allocate a growing buffer as needed.
intResult = DllCall (hdlWinInet, long : "FindFirstUrlCacheEntryA", lpnull, lpnull, lpbinary : lpcbCacheEntryInfo)
intICEISize = BinaryPeek4 (lpcbCacheEntryInfo, 0)
If intICEISize > intICEISizeMax
   intICEISizeMax = intICEISize
   hdlICEI = BinaryFree (hdlICEI)
   hdlICEI = BinaryAlloc (intICEISizeMax) ; Binary buffer to hold structure.
   BinaryEodSet (hdlICEI, intICEISizeMax)
   ptrICEI = IntControl (42, hdlICEI, 0, 0, 0) ; Get pointer to binary buffer.
EndIf
BinaryPoke4 (lpcbCacheEntryInfo, 0, intICEISizeMax)

; Second call to get entry.
hdlFind = DllCall (hdlWinInet, long : "FindFirstUrlCacheEntryA", lpstr : strSearchTarget, lpbinary : hdlICEI, lpbinary : lpcbCacheEntryInfo)

If hdlFind != ERROR_CACHE_FIND_FAIL

   lpszSourceUrlName = BinaryPeek4 (hdlICEI, 4) ; URL pointer lpszSourceUrlName.
   strUrl = BinaryPeekStr (hdlICEI, lpszSourceUrlName - ptrICEI, intICEISizeMax)
   ptrFileTime = ptrICEI + 48 ; LastAccess FILETIME pointer

   ; Last access.
   DllCall (hdlKernel32, long : "FileTimeToSystemTime", long : ptrFileTime, lpbinary : hdlST)
   strYmdHms = BinaryPeek2 (hdlST, 0)                    ; Year.
   strYmdHms = strYmdHms : ":" : BinaryPeek2 (hdlST, 2)  ; Month.
   strYmdHms = strYmdHms : ":" : BinaryPeek2 (hdlST, 6)  ; Day.
   strYmdHms = strYmdHms : ":" : BinaryPeek2 (hdlST, 8)  ; Hour.
   strYmdHms = strYmdHms : ":" : BinaryPeek2 (hdlST, 10) ; Minute.
   strYmdHms = strYmdHms : ":" : BinaryPeek2 (hdlST, 12) ; Second.
   strYmdHms = TimeAdd (strYmdHms, "0:0:0:0:0:0") ; Make valid datetime string.
   If blnUseMilliSecond Then strYmdHms = strYmdHms : ":" : StrFixLeft (BinaryPeek2 (hdlST, 14), "0", 3) ; Millisecond.

   strListUrls = strYmdHms : @TAB : strUrl
   BoxText (strUrl : @LF : strYmdHms)

   While @TRUE
      ; Find next entries.

      ; Allocate a growing buffer as needed.
      intResult = DllCall (hdlWinInet, long : "FindNextUrlCacheEntryA", long : hdlFind, lpnull, lpbinary : lpcbCacheEntryInfo)
      intICEISize = BinaryPeek4 (lpcbCacheEntryInfo, 0)
      If intICEISize > intICEISizeMax
         intICEISizeMax = intICEISize
         hdlICEI = BinaryFree (hdlICEI)
         hdlICEI = BinaryAlloc (intICEISizeMax) ; Binary buffer to hold structure.
         BinaryEodSet (hdlICEI, intICEISizeMax)
         ptrICEI = IntControl (42, hdlICEI, 0, 0, 0) ; Get pointer to binary buffer.
      EndIf
      BinaryPoke4 (lpcbCacheEntryInfo, 0, intICEISizeMax)

      ; Second Call to get entry.
      hdlFind = DllCall (hdlWinInet, long : "FindNextUrlCacheEntryA", long : hdlFind, lpbinary : hdlICEI, lpbinary : lpcbCacheEntryInfo)
      If hdlFind == ERROR_CACHE_FIND_FAIL
         intLastError = DllLastError ()
         If intLastError == ERROR_NO_MORE_ITEMS Then Break
         Pause ("Error", IntControl (1004, 0, 0, 0, 0) : @LF : "FindNextUrlCacheEntry" : @LF : "LastError = " : intLastError)
      EndIf

      lpszSourceUrlName = BinaryPeek4 (hdlICEI, 4) ; URL pointer lpszSourceUrlName
      strUrl = BinaryPeekStr (hdlICEI, lpszSourceUrlName - ptrICEI, intICEISizeMax)
      ptrFileTime = ptrICEI + 48 ; Pointer to LastAccess FILETIME.

      ; Last access.
      DllCall (hdlKernel32, long : "FileTimeToSystemTime", long : ptrFileTime, lpbinary : hdlST)
      strYmdHms = BinaryPeek2 (hdlST, 0)                    ; Year.
      strYmdHms = strYmdHms : ":" : BinaryPeek2 (hdlST, 2)  ; Month.
      strYmdHms = strYmdHms : ":" : BinaryPeek2 (hdlST, 6)  ; Day.
      strYmdHms = strYmdHms : ":" : BinaryPeek2 (hdlST, 8)  ; Hour.
      strYmdHms = strYmdHms : ":" : BinaryPeek2 (hdlST, 10) ; Minute.
      strYmdHms = strYmdHms : ":" : BinaryPeek2 (hdlST, 12) ; Second.
      strYmdHms = TimeAdd (strYmdHms, "0:0:0:0:0:0") ; Make valid datetime string.
      If blnUseMilliSecond Then strYmdHms = strYmdHms : ":" : StrFixLeft (BinaryPeek2 (hdlST, 14), "0", 3) ; Millisecond.

      strListUrls = strListUrls : @LF : strYmdHms : @TAB : strUrl
      BoxText (strYmdHms : @LF : strUrl)
   EndWhile
EndIf

; Release binary buffers.
lpcbCacheEntryInfo = BinaryFree (lpcbCacheEntryInfo)
hdlICEI = BinaryFree (hdlICEI)
hdlST = BinaryFree (hdlST)

; Release DLL's.
hdlWinInet  = DllFree (hdlWinInet)
hdlKernel32 = DllFree (hdlKernel32)

;------------------------------------------------------------------------------------------------------------------------------------------
; Generate HTML file.

BoxTitle ("Processing Urls")
BoxText ("Please wait, sorting entries ...")
strListUrls = ItemSort (strListUrls, @LF)
intCount = ItemCount (strListUrls, @LF)

BoxTitle ("Processing HTML")
BoxText ("Please wait, generating HTML ...")

hdlFW = FileOpen (strFileOut, "WRITE")
FileWrite (hdlFW, '<HTML>')
FileWrite (hdlFW, '<HEAD>')
FileWrite (hdlFW, '<STYLE TYPE="text/css"><!-- body {font-family:Verdana;} table {table-layout:auto; border:solid 1px silver; border-collapse:collapse;} th {border: solid 1px silver; padding:3px; text-align:left; font-size:smaller;} td {border: solid 1px silver; padding:3px; font-size:smaller;} caption {font-weight:bold; text-align:left; caption-side:top;} --></STYLE>')
FileWrite (hdlFW, '</HEAD>')
FileWrite (hdlFW, '<BODY>')
FileWrite (hdlFW, '<TABLE>')
FileWrite (hdlFW, '<CAPTION>MSIE History Cache</CAPTION>')
FileWrite (hdlFW, '<THEAD><TR><TH>DateTime</TH><TH>Type</TH><TH>URL</TH></TR></THEAD>')
FileWrite (hdlFW, '<TBODY>')
strTableRowMask = '<TR><TD>{1}</TD><TD>{2}</TD><TD><A HREF="{3}">{3}</A></TD></TR>'

For intI = 1 To intCount
   strItem = ItemExtract (intI, strListUrls, @LF)
   strDate = ItemExtract (1, strItem, @TAB)
   strUrl  = ItemExtract (2, strItem, @TAB)
   strType = ""
   strProt = ""
   If StrIndexNC (strUrl, "Cookie", 1, @FWDSCAN) == 1 Then strProt = "http://"

   If ItemCount (strUrl,"@") > 1
      strType = ItemExtract (1, strUrl, "@")
      strUrl  = ItemExtract (2, strUrl, "@")
   EndIf

   strTableRow = StrReplace (strTableRowMask, "{1}", strDate)
   strTableRow = StrReplace (strTableRow, "{2}", strType)
   strTableRow = StrReplace (strTableRow, "{3}", strProt : strUrl)

   FileWrite (hdlFW, strTableRow)
Next

FileWrite (hdlFW, '</TBODY></TABLE></BODY></HTML>')

hdlFW = FileClose (hdlFW)

Run (strFileOut, "")

:CANCEL
BoxShut ()
Exit
;------------------------------------------------------------------------------------------------------------------------------------------
;   Example output.
;
;   MSIE History Cache
;   DateTime            Type              URL
;   2010:02:15:00:31:12 Cookie:testuser   http://groups.google.de/
;   2010:02:15:08:24:15 Cookie:testuser   http://openoffice.org/
;   2010:02:15:19:35:34 Cookie:testuser   http://activestate.com/
;   2010:02:17:21:21:23 Cookie:testuser   http://pdfforge.org/
;   2010:02:25:17:50:50 Visited: Testuser http://webboard.winbatch.com/wbisadll/wbpx.isa/~winware/read?217017,3
;   2010:02:25:17:51:23 Visited: Testuser http://webboard.winbatch.com/wbisadll/wbpx.isa/~winware/read?217017,3e
;   2010:02:25:17:56:38 Cookie:testuser   http://social.microsoft.com/
;   2010:02:25:17:56:55                   http://msdn.microsoft.com/en-us/library/aa342502(VS.85).aspx
;   2010:02:25:17:56:55                   http://msdn.microsoft.com/en-us/library/ms536433(VS.85).aspx
;   2010:02:25:17:56:57 Cookie:testuser   http://asp.net/
;   2010:02:25:17:56:57                   http://weblogs.asp.net/favicon.ico
;   2010:02:25:17:56:57 Visited: Testuser http://weblogs.asp.net/bleroy/archive/2008/01/29/getting-absolute-coordinates-from-a-dom-element.aspx
;------------------------------------------------------------------------------------------------------------------------------------------