Created
August 13, 2008 08:55
-
-
Save atifaziz/5216 to your computer and use it in GitHub Desktop.
iecache
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Copyright (c) 2005 Atif Aziz. All rights reserved. | |
// | |
// Author(s): | |
// | |
// Atif Aziz, http://www.raboof.com | |
// | |
// This program is free software; you can redistribute it and/or modify it | |
// under the terms of the New BSD License, a copy of which should have | |
// been delivered along with this distribution. | |
// | |
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | |
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
// | |
#include "stdafx.h" | |
#pragma comment(lib, "wininet") | |
#pragma comment(lib, "shlwapi") | |
using namespace std; | |
///////////////////////////////////////////////////////////////////////////// | |
// | |
// Globals | |
// | |
TCHAR g_executableName[MAX_PATH]; | |
///////////////////////////////////////////////////////////////////////////// | |
// | |
// Macros | |
// | |
#define DIM(a) (sizeof(a) / sizeof((a)[0])) | |
///////////////////////////////////////////////////////////////////////////// | |
// | |
// Prototypes | |
// | |
static void Help(const int argsLength, LPCTSTR args[]); | |
static void List(const int argsLength, LPCTSTR args[]); | |
static bool ListCallback(LPINTERNET_CACHE_ENTRY_INFO entry); | |
static bool ListVerboseCallback(LPINTERNET_CACHE_ENTRY_INFO entry); | |
static void ListCookies(const int argsLength, LPCTSTR args[]); | |
static bool ListCookieCallback(LPINTERNET_CACHE_ENTRY_INFO entry); | |
static void OnError(DWORD error); | |
static SIZE_T FormatLongUniversalTime(const FILETIME* const universalFileTime, LPTSTR outputString, SIZE_T outputStringSize); | |
///////////////////////////////////////////////////////////////////////////// | |
// | |
// Allocates a block of memory, by default, on the process heap. | |
// | |
template <class P> | |
inline P WHeapAlloc | |
( | |
P& p, | |
SIZE_T size = 0, | |
DWORD options = HEAP_ZERO_MEMORY, | |
HANDLE heap = ::GetProcessHeap() | |
) | |
{ | |
if (0 == size) size = sizeof(*p); | |
return (p = static_cast<P>(::HeapAlloc(heap, options, size))); | |
} | |
inline void* WHeapAlloc | |
( | |
void*& p, | |
SIZE_T size = 0, | |
DWORD options = HEAP_ZERO_MEMORY, | |
HANDLE heap = ::GetProcessHeap() | |
) | |
{ | |
return (p = ::HeapAlloc(heap, options, size)); | |
} | |
///////////////////////////////////////////////////////////////////////////// | |
// | |
// Frees a block of memory allocated on a heap using HeapAlloc. By default, | |
// the process heap is used. Unlike HeapFree, NULL pointers are ignored. | |
// | |
template <class P> | |
inline BOOL WHeapFree | |
( | |
P& p, | |
DWORD options = 0, | |
HANDLE heap = ::GetProcessHeap() | |
) | |
{ | |
if (NULL == p) return TRUE; | |
BOOL succeeded = ::HeapFree(heap, options, p); | |
p = NULL; | |
_ASSERTE(succeeded); | |
return succeeded; | |
} | |
///////////////////////////////////////////////////////////////////////////// | |
// | |
// Command-line parser | |
// | |
template<class Handler> | |
class CommandLineParser : public Handler | |
{ | |
public: | |
CommandLineParser() {} | |
bool Parse(int argumentsLength, LPCTSTR arguments[]) | |
{ | |
for (int i = 0; i < argumentsLength; i++) | |
{ | |
LPCTSTR argument = arguments[i]; | |
if (argument[0] == _T('-') || | |
argument[0] == _T('/')) | |
{ | |
const bool isLastArgument = (i + 1) == argumentsLength ; | |
LPCTSTR nextArgument = isLastArgument ? NULL : arguments[i + 1]; | |
if (!Handler::HandleOption(argument + 1, nextArgument)) | |
return false; | |
if (!nextArgument) | |
i++; | |
} | |
else | |
{ | |
if (!Handler::HandleUnnamed(argument)) | |
return false; | |
} | |
} | |
return Handler::EndOfParse(); | |
} | |
private: | |
CommandLineParser(const CommandLineParser&); | |
CommandLineParser& operator=(const CommandLineParser&); | |
}; | |
///////////////////////////////////////////////////////////////////////////// | |
// | |
// Command-line handler. | |
// | |
class CommandLineHandler | |
{ | |
private: | |
bool m_verbose; | |
public: | |
CommandLineHandler() : | |
m_verbose(false) {} | |
bool Verbose() const { return m_verbose; } | |
bool HandleUnnamed(LPCTSTR unnamed) | |
{ | |
_ASSERT(unnamed); | |
cerr << _T("Invalid argument: ") << unnamed << endl; | |
return false; | |
} | |
bool HandleOption(LPCTSTR option, LPCTSTR& argument) | |
{ | |
_ASSERT(option); | |
if (IsOption(option, _T("verbose"))) | |
{ | |
m_verbose = true; | |
} | |
else | |
{ | |
cerr << _T("Invalid option: ") << option << endl; | |
return false; | |
} | |
return true; | |
} | |
bool EndOfParse() | |
{ | |
return true; | |
} | |
private: | |
static bool IsOption(LPCTSTR test, LPCTSTR option) | |
{ | |
return CSTR_EQUAL == CompareString(LOCALE_INVARIANT, 0, test, -1, option, -1); | |
} | |
#pragma warning (push) | |
#pragma warning(disable: 4822/* local class member function does not have a body */) | |
CommandLineHandler(const CommandLineHandler&); | |
CommandLineHandler& operator=(const CommandLineHandler&); | |
#pragma warning (pop) | |
}; | |
///////////////////////////////////////////////////////////////////////////// | |
// | |
// Application entry-point. | |
// | |
int _tmain(int argsLength, LPCTSTR args[]) | |
{ | |
#ifdef _DEBUG | |
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | | |
_CRTDBG_CHECK_ALWAYS_DF /* Check memory at every (de)allocation */ | | |
_CRTDBG_LEAK_CHECK_DF /* Automatic leak checking and reporting at program exit */); | |
#endif | |
// | |
// Discover the executable name (without path and extension). | |
// | |
StringCchCopy(g_executableName, DIM(g_executableName), args[0]); | |
PathStripPath(g_executableName); | |
PathRemoveExtension(g_executableName); | |
args++; argsLength--; | |
// | |
// Nothing told to do? Hint on trying help. | |
// | |
if (0 == argsLength) | |
{ | |
cout << _T("Try '") << g_executableName << _T(" help' for usage.") << endl; | |
return 0; | |
} | |
// | |
// What's the command? | |
// | |
LPCTSTR command = args[0]; | |
args++; argsLength--; | |
if (0 == _tcscmp(_T("help"), command)) | |
{ | |
Help(argsLength, args); | |
return 0; | |
} | |
else if (0 == _tcscmp(_T("list"), command)) | |
{ | |
List(argsLength, args); | |
return 0; | |
} | |
else if (0 == _tcscmp(_T("cookies"), command)) | |
{ | |
ListCookies(argsLength, args); | |
return 0; | |
} | |
else | |
{ | |
// | |
// Invalid command. | |
// | |
cerr << _T("'") << command << _T("' is not a command. ") | |
<< _T("See '") << g_executableName << _T(" help' for usage.") << endl; | |
return -1; | |
} | |
return 0; | |
} | |
///////////////////////////////////////////////////////////////////////////// | |
// | |
// Enumerates all entries in the Inernet client cache to a callback. | |
// | |
template<class T> | |
void EnumInternetCache(T& callback) | |
{ | |
HANDLE enumeration = NULL; | |
DWORD entryCapacity = 0; | |
DWORD entrySize = 0; | |
LPINTERNET_CACHE_ENTRY_INFO entry = NULL; | |
DWORD error; | |
bool proceed = false; | |
do | |
{ | |
do | |
{ | |
if (entrySize > entryCapacity) | |
{ | |
WHeapFree(entry); | |
entryCapacity = 0; | |
if (!WHeapAlloc(entry, entrySize)) | |
{ | |
error = ERROR_OUTOFMEMORY; | |
break; | |
} | |
entryCapacity = entrySize; | |
} | |
bool succeeded; | |
if (NULL == enumeration) | |
{ | |
enumeration = FindFirstUrlCacheEntry(NULL, entry, &entrySize); | |
succeeded = NULL != enumeration; | |
} | |
else | |
{ | |
succeeded = FALSE != FindNextUrlCacheEntry(enumeration, entry, &entrySize); | |
} | |
error = succeeded ? ERROR_SUCCESS : GetLastError(); | |
} | |
while (ERROR_INSUFFICIENT_BUFFER == error); | |
if (ERROR_SUCCESS == error) | |
proceed = callback(entry); | |
} | |
while (ERROR_NO_MORE_ITEMS != error && proceed); | |
WHeapFree(entry); | |
if (ERROR_SUCCESS != error && | |
ERROR_NO_MORE_ITEMS != error) | |
OnError(error); | |
if (NULL != enumeration) | |
FindCloseUrlCache(enumeration); | |
} | |
///////////////////////////////////////////////////////////////////////////// | |
// | |
// Lists all entries (excluding cookies and visited URLs) in the Inernet | |
// client cache. | |
// | |
void List(const int argsLength, LPCTSTR args[]) | |
{ | |
_ASSERTE(argsLength >= 0); | |
_ASSERTE(0 == argsLength || args); | |
CommandLineParser<CommandLineHandler> parser; | |
if (!parser.Parse(argsLength, args)) | |
exit(-1); | |
if (parser.Verbose()) | |
EnumInternetCache(ListVerboseCallback); | |
else | |
EnumInternetCache(ListCallback); | |
} | |
bool ListCallback(LPINTERNET_CACHE_ENTRY_INFO entry) | |
{ | |
_ASSERTE(entry); | |
if (0 == (entry->CacheEntryType & (URLHISTORY_CACHE_ENTRY | COOKIE_CACHE_ENTRY))) | |
{ | |
cout << entry->lpszSourceUrlName << endl; | |
} | |
return true; | |
} | |
bool ListVerboseCallback(LPINTERNET_CACHE_ENTRY_INFO entry) | |
{ | |
_ASSERTE(entry); | |
if (0 == (entry->CacheEntryType & (URLHISTORY_CACHE_ENTRY | COOKIE_CACHE_ENTRY))) | |
{ | |
cout << _T("URL : ") << entry->lpszSourceUrlName << endl; | |
cout << _T("Local file : ") << entry->lpszLocalFileName << endl; | |
cout << _T("Use count : ") << entry->dwUseCount << endl; | |
cout << _T("Hit rate : ") << entry->dwHitRate << endl; | |
ULARGE_INTEGER size; | |
size.LowPart = entry->dwSizeLow; | |
size.HighPart = entry->dwSizeHigh; | |
cout << _T("Byte size : ") << size.QuadPart << endl; | |
TCHAR timeString[100]; | |
FormatLongUniversalTime(&entry->LastAccessTime, timeString, DIM(timeString)); | |
cout << _T("Accessed : ") << timeString << endl; | |
FormatLongUniversalTime(&entry->LastModifiedTime, timeString, DIM(timeString)); | |
cout << _T("Modified : ") << timeString << endl; | |
FormatLongUniversalTime(&entry->LastSyncTime, timeString, DIM(timeString)); | |
cout << _T("Synchronized: ") << timeString << endl; | |
cout << _T("Expiration : "); | |
if (0 == entry->ExpireTime.dwHighDateTime && | |
0 == entry->ExpireTime.dwLowDateTime) | |
{ | |
cout << _T("N/A"); | |
} | |
else | |
{ | |
FormatLongUniversalTime(&entry->ExpireTime, timeString, DIM(timeString)); | |
cout << timeString; | |
} | |
cout << endl; | |
if (entry->dwHeaderInfoSize > 0) | |
{ | |
cout << endl; | |
cout << (LPCSTR) entry->lpHeaderInfo << endl; | |
} | |
cout << _T("---------------------------------------") << endl; | |
} | |
return true; | |
} | |
///////////////////////////////////////////////////////////////////////////// | |
// | |
// Lists all cookies in the Inernet client cache. | |
// | |
void ListCookies(const int argsLength, LPCTSTR args[]) | |
{ | |
_ASSERTE(0 == argsLength || args); | |
_ASSERTE(argsLength >= 0); | |
EnumInternetCache(ListCookieCallback); | |
} | |
bool ListCookieCallback(LPINTERNET_CACHE_ENTRY_INFO entry) | |
{ | |
_ASSERTE(entry); | |
if (COOKIE_CACHE_ENTRY == (entry->CacheEntryType & COOKIE_CACHE_ENTRY)) | |
{ | |
cout << entry->lpszSourceUrlName << endl; | |
} | |
return true; | |
} | |
///////////////////////////////////////////////////////////////////////////// | |
// | |
// Displays an error message and then ends the application! | |
// | |
void OnError(DWORD error) | |
{ | |
// | |
// Get and display the error message corresponding to the error code. | |
// | |
LPTSTR message = NULL; | |
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | |
NULL, error, 0, | |
reinterpret_cast<LPTSTR>(&message), 0, NULL); | |
cerr << endl << error << _T(": "); | |
if (message) | |
{ | |
cerr << message << endl; | |
LocalFree(message); | |
} | |
else | |
{ | |
cerr << _T("(No description available for this error code)\n"); | |
} | |
exit(error); | |
} | |
///////////////////////////////////////////////////////////////////////////// | |
// | |
// Display usage help | |
// | |
void Help(const int argsLength, LPCTSTR args[]) | |
{ | |
_ASSERTE(0 == argsLength || args); | |
_ASSERTE(argsLength >= 0); | |
cout << _T("Usage: ") << g_executableName << _T(" help | list | cookies"); | |
} | |
///////////////////////////////////////////////////////////////////////////// | |
// | |
// Formats UTC time using the long date and time patterns from user locale. | |
// | |
SIZE_T FormatLongUniversalTime(const FILETIME* const universalFileTime, LPTSTR outputString, SIZE_T outputStringSize) | |
{ | |
_ASSERTE(universalFileTime); | |
_ASSERTE(outputString); | |
_ASSERTE(outputStringSize >= 0); | |
if (outputStringSize == 0) | |
return 0; | |
*outputString = 0; | |
// | |
// Convert FILETIME in UTC to SYSTEMTIME UTC and then to SYSTEMTIME in local | |
// time. Next, use components of SYSTEMTIME to load the corresponding | |
// components of the CRT tm structure. The tm structure allows us the use | |
// of strftime for date/time formatting. | |
// | |
SYSTEMTIME localSystemTime; | |
FileTimeToSystemTime(universalFileTime, &localSystemTime); | |
SystemTimeToTzSpecificLocalTime(NULL, &localSystemTime, &localSystemTime); | |
// | |
// Format using long date pattern followed by the long time pattern. | |
// | |
SIZE_T dateLength = GetDateFormat(LOCALE_USER_DEFAULT, | |
LOCALE_USE_CP_ACP | DATE_LONGDATE, &localSystemTime, /* lpFormat = */ NULL, | |
outputString, static_cast<int>(outputStringSize)); | |
LPTSTR timeString = outputString + dateLength; | |
SIZE_T timeStringSize = outputStringSize - dateLength; | |
SIZE_T timeLength = GetTimeFormat(LOCALE_USER_DEFAULT, | |
LOCALE_USE_CP_ACP, &localSystemTime, /* lpFormat = */ NULL, | |
timeString, static_cast<int>(outputStringSize)); | |
// | |
// Add a separation space between the date and time if both components are | |
// present in the output. | |
// | |
// NOTE! Lengths returns by GetDateFormat and GetTimeFormat include the | |
// null terminator so one of these has to be adjusted because the output | |
// string only contains one terminator. | |
// | |
if (dateLength > 0 && timeLength > 0) | |
outputString[dateLength - 1] = ' '; | |
return (0 == dateLength + timeLength) ? 0 : (dateLength + timeLength - 1); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// stdafx.h : include file for standard system include files, | |
// or project specific include files that are used frequently, but | |
// are changed infrequently | |
// | |
#pragma once | |
#include <iostream> | |
#include <iomanip> | |
#include <tchar.h> | |
#include <crtdbg.h> | |
#define WIN32_LEAN_AND_MEAN | |
#include <windows.h> | |
#include <wininet.h> | |
#include <shlwapi.h> | |
#include <strsafe.h> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment