{"id":498,"date":"2009-02-17T20:19:47","date_gmt":"2009-02-17T20:19:47","guid":{"rendered":"http:\/\/dalelane.co.uk\/blog\/?p=498"},"modified":"2009-02-17T20:20:26","modified_gmt":"2009-02-17T20:20:26","slug":"programmatically-getting-last-visited-page-from-pocket-internet-explorer","status":"publish","type":"post","link":"https:\/\/dalelane.co.uk\/blog\/?p=498","title":{"rendered":"Programmatically getting last visited page from Pocket Internet Explorer"},"content":{"rendered":"<p>I wrote earlier about my hack for <a href=\"http:\/\/dalelane.co.uk\/blog\/?p=479\">syncing my browsing between my computer and mobile<\/a>.<\/p>\n<p>One of the most fiddly bits of implementing this was how to get the last visited page from Pocket Internet Explorer on my phone. In case this is useful to anyone, here is a quick description of how I did it. <\/p>\n<p>I wrote the code to get the last visited page in C++. I couldn&#8217;t find any way to access the browser, or the address bar, programmatically. <\/p>\n<p>The closest I could find is a set of <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa917828.aspx\" target=\"_blank\">Windows Internet Services API<\/a> calls which let you have direct access to the browser cache used by Pocket Internet Explorer.<\/p>\n<p><em>I wrote the code for Pocket Internet Explorer on Windows Mobile, but to the best of my knowledge it should work on regular Internet Explorer. I&#8217;ve not tried it because, let&#8217;s be honest, who uses Internet Explorer? \ud83d\ude09 <\/em><\/p>\n<p>The approach was to use <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa917700.aspx\" target=\"_blank\">FindFirstUrlCacheEntryEx<\/a> and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa917923.aspx\" target=\"_blank\">FindNextUrlCacheEntryEx<\/a> to enumerate through the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa919337.aspx\" target=\"_blank\">INTERNET_CACHE_ENTRY_INFO<\/a> entries in the Internet cache. <\/p>\n<p>Each INTERNET_CACHE_ENTRY_INFO item stores (amongst other information) the URL it was downloaded from, and the time the cache item was last accessed. <\/p>\n<p>So I find the last page the user has visited by enumerating through the cache, and store the URL for the cache item with the latest last-accessed time.<\/p>\n<p><!--more--><strong>Interesting snippets from the code<\/strong><\/p>\n<p>First step &#8211; prepare somewhere to store each Internet cache item while we look at it.<\/p>\n<pre style=\"overflow: scroll; font-size: 1.1em; border: thin solid silver; background-color: #eeeeee; padding: 0.8em\">DWORD MAX_CACHE_ENTRY_SIZE = 2048;\r\nDWORD dwEntrySize = MAX_CACHE_ENTRY_SIZE;\r\nLPINTERNET_CACHE_ENTRY_INFO lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO) new char[dwEntrySize];\r\nlpCacheEntry->dwStructSize = dwEntrySize;<\/pre>\n<p>Start the enumerating of the items by getting the first entry from the cache.<\/p>\n<p>I use FindFirstUrlCacheEntryEx rather than FindFirstUrlCacheEntry as it gives the ability to filter the cache items we want to look at. <\/p>\n<p>I filter for URLHISTORY_CACHE_ENTRY so that I don&#8217;t have to go through all the cookies, and cached scripts and images.<\/p>\n<pre style=\"overflow: scroll; font-size: 1.1em; border: thin solid silver; background-color: #eeeeee; padding: 0.8em\">HANDLE hCacheDir = FindFirstUrlCacheEntryEx(NULL,\r\n                                            0, \r\n                                            URLHISTORY_CACHE_ENTRY,\r\n                                            0,\r\n                                            lpCacheEntry,\r\n                                            &dwEntrySize,\r\n                                            NULL, \r\n                                            NULL, \r\n                                            NULL);<\/pre>\n<p>If this returns ERROR_INSUFFICIENT_BUFFER, then I prepare more space for the cache entry (the <code>dwEntrySize<\/code> value returned tells you how much space is required) and try again.<\/p>\n<p>We need a space to store the time the item was last accessed, and the URL it was downloaded from.<\/p>\n<pre style=\"overflow: scroll; font-size: 1.1em; border: thin solid silver; background-color: #eeeeee; padding: 0.8em\">FILETIME lastTime = lpCacheEntry->LastAccessTime;\r\nLPWSTR lastAccessedUrl = new TCHAR[lstrlen(lpCacheEntry->lpszSourceUrlName) + 1];\r\nlstrcpy(lastAccessedUrl, lpCacheEntry->lpszSourceUrlName);\r\nlastAccessedUrl[lstrlen(lpCacheEntry->lpszSourceUrlName)] = '\\0';<\/pre>\n<p>We&#8217;re now ready to start enumerating through all of the items in the Internet cache.<\/p>\n<pre style=\"overflow: scroll; font-size: 1.1em; border: thin solid silver; background-color: #eeeeee; padding: 0.8em\">FindNextUrlCacheEntryEx(hCacheDir, \r\n                        lpCacheEntry,\r\n                        &dwEntrySize,\r\n                        NULL,\r\n                        NULL,\r\n                        NULL);<\/pre>\n<p>The space to allocate for the cache entries need to be handled as before &#8211; allocate <code>MAX_CACHE_ENTRY_SIZE<\/code> space to start with, then increase it as needed if we get <code>ERROR_INSUFFICIENT_BUFFER<\/code> back.<\/p>\n<p>For each item in the Internet cache, we get the last accessed time and compare it with the latest one. If it is later, we replace the URL and timestamp we have for the latest visited page.<\/p>\n<pre style=\"overflow: scroll; font-size: 1.1em; border: thin solid silver; background-color: #eeeeee; padding: 0.8em\">FILETIME nextTime = lpCacheEntry->LastAccessTime;\r\n\r\nif (CompareFileTime(&nextTime, &lastTime) == 1)\r\n{\r\n    lastTime = lpCacheEntry->LastAccessTime;\r\n    lastAccessedUrl = new TCHAR[lstrlen(lpCacheEntry->lpszSourceUrlName) + 1];\r\n    lstrcpy(lastAccessedUrl, lpCacheEntry->lpszSourceUrlName);\r\n    lastAccessedUrl[lstrlen(lpCacheEntry->lpszSourceUrlName)] = '\\0';\r\n}<\/pre>\n<p>And you keep calling <code>FindNextUrlCacheEntryEx<\/code> until it returns a <code>ERROR_NO_MORE_ITEMS<\/code> error.<\/p>\n<p>Other than that, it&#8217;s just cleaning up really. <\/p>\n<p>You need to <code>delete (lpCacheEntry);<\/code> after you finish looking at each Internet cache item, and close the Internet cache when you&#8217;ve finished everything using <code>FindCloseUrlCache(hCacheDir);<\/code>.<\/p>\n<p>There are probably a few bugs hiding in there, but it seems to do the trick.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wrote earlier about my hack for syncing my browsing between my computer and mobile. One of the most fiddly bits of implementing this was how to get the last visited page from Pocket Internet Explorer on my phone. In case this is useful to anyone, here is a quick description of how I did [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[336,334,335,333,46,170,332],"class_list":["post-498","post","type-post","status-publish","format-standard","hentry","category-code","tag-cpp","tag-findfirsturlcacheentry","tag-findnexturlcacheentryex","tag-internet-explorer","tag-mobile","tag-pocket-internet-explorer","tag-windows"],"_links":{"self":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/498","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=498"}],"version-history":[{"count":0,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/498\/revisions"}],"wp:attachment":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=498"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=498"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=498"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}