開発環境 Microsoft Visual Studio Express 2013 for Windows Desktop
実行環境 Microsoft Windows 8.1 (64bit)
プロジェクトの種類 Visual C++/Win32 プロジェクト
プロジェクト名 IECacheList
アプリケーションの種類 Windows アプリケーション
追加のオプション 空のプロジェクト、SDLチェック

IECacheList.cpp
#include <wchar.h>
#include <Windows.h>
#include <CommCtrl.h>
#include <VersionHelpers.h>
#include "resource.h"
 
#define SECT L"General"
 
class WaitCursor {
private:
	HCURSOR hPrev;
public:
	WaitCursor() {
		hPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
	}
	~WaitCursor() {
		SetCursor(hPrev);
	}
};
 
// 外部変数
HWND hList;
TCHAR szIniFile[MAX_PATH];
TCHAR szSizeMin[16];
TCHAR szExtension[256];
TCHAR szSaveDir[MAX_PATH];
TCHAR szContent[MAX_PATH];
 
// 関数プロトタイプ宣言
void GetIniFileName();
LPTSTR ThousandsSeparator(DWORD dw);
void Trace(LPCTSTR format, ...);
 
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
void UpdateData(HWND hDlg, BOOL bSave);
void OnInitDialog(HWND hDlg);
void OnDestroy(HWND hDlg);
void OnColumnClick(HWND hDlg, LPNMLISTVIEW plv);
void OnGetList(HWND hDlg);
BOOL CheckExt(LPCTSTR filename, LPCTSTR extension);
void OnSave(HWND hDlg);
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
 
//==============================================================================
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
	GetIniFileName();
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, DlgProc);
	return 0;
}
 
void GetIniFileName()
{
	TCHAR path[_MAX_PATH];
	TCHAR drive[_MAX_DRIVE];
	TCHAR dir[_MAX_DIR];
	TCHAR fname[_MAX_FNAME];
	TCHAR ext[_MAX_EXT];
 
	GetModuleFileName(NULL, path, _countof(path));
	_wsplitpath_s(path, drive, dir, fname, ext);
	_wmakepath_s(szIniFile, drive, dir, fname, L"ini");
}
 
LPTSTR ThousandsSeparator(DWORD dw)
{
	static TCHAR szResult[16];
	TCHAR szBuf[16];
 
	int nLen = swprintf_s(szBuf, L"%u", dw);
	int i = 0;
	for (int n = 0; n < nLen; n++) {
		szResult[i++] = szBuf[n];
		int nPlace = nLen - n;
		if (3 < nPlace && (nPlace % 3) == 1) szResult[i++] = L',';
	}
	szResult[i] = L'\0';
	return szResult;
}
 
void Trace(LPCTSTR format, ...)
{
	va_list arg_ptr;
	TCHAR buffer[256];
	int size;
 
	va_start(arg_ptr, format);
	size = _vsnwprintf_s(buffer, _TRUNCATE, format, arg_ptr);
	va_end(arg_ptr);
	OutputDebugString(buffer);
	if (size < 0) {
		OutputDebugString(L"...\n");
	}
}
 
//------------------------------------------------------------------------------
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	INT_PTR res = TRUE;	// メッセージを処理した
 
	switch (uMsg) {
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDOK:
			OnGetList(hDlg);
			break;
		case IDC_SAVE:
			OnSave(hDlg);
			break;
		case IDCANCEL:
			EndDialog(hDlg, IDCANCEL);
			break;
		}
		break;
	case WM_NOTIFY:
		switch (LOWORD(wParam)) {
		case IDC_LIST:
			LPNMLISTVIEW plv = (LPNMLISTVIEW)lParam;
			switch (plv->hdr.code) {
			case NM_CLICK:
				if (0 <= plv->iItem && 0 < plv->iSubItem) {
					BOOL fCheck = ListView_GetCheckState(hList, plv->iItem);
					ListView_SetCheckState(hList, plv->iItem, fCheck ? FALSE : TRUE);
				}
				break;
			case LVN_COLUMNCLICK:
				OnColumnClick(hDlg, plv);
				break;
			}
			break;
		}
		break;
	case WM_INITDIALOG:
		OnInitDialog(hDlg);
		break;
	case WM_CLOSE:
		EndDialog(hDlg, 0);
		break;
	case WM_DESTROY:
		OnDestroy(hDlg);
		break;
	default:
		res = FALSE;	// メッセージを処理しなかった
	}
	return res;
}
 
void UpdateData(HWND hDlg, BOOL bSave)
{
	if (bSave) {
		GetDlgItemText(hDlg, IDC_SIZE_MIN, szSizeMin, _countof(szSizeMin));
		GetDlgItemText(hDlg, IDC_EXTENSION, szExtension, _countof(szExtension));
		GetDlgItemText(hDlg, IDC_SAVE_DIR, szSaveDir, _countof(szSaveDir));
	}
	else {
		SetDlgItemText(hDlg, IDC_SIZE_MIN, szSizeMin);
		SetDlgItemText(hDlg, IDC_EXTENSION, szExtension);
		SetDlgItemText(hDlg, IDC_SAVE_DIR, szSaveDir);
	}
}
 
void OnInitDialog(HWND hDlg)
{
	int nX = GetPrivateProfileInt(SECT, L"X", 100, szIniFile);
	int nY = GetPrivateProfileInt(SECT, L"Y", 100, szIniFile);
	GetPrivateProfileString(SECT, L"SizeMin", L"", szSizeMin, _countof(szSizeMin), szIniFile);
	GetPrivateProfileString(SECT, L"Extension", L"", szExtension, _countof(szExtension), szIniFile);
	GetPrivateProfileString(SECT, L"SaveDir", L"", szSaveDir, _countof(szSaveDir), szIniFile);
 
	SetWindowPos(hDlg, HWND_TOP, nX, nY, 0, 0, SWP_NOSIZE);
	UpdateData(hDlg, FALSE);
	hList = GetDlgItem(hDlg, IDC_LIST);
 
	// リストビュー拡張スタイル
	DWORD dwExStyle = LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES;
	ListView_SetExtendedListViewStyleEx(hList, dwExStyle, dwExStyle);
 
	// 列情報
	struct {
		int fmt;
		int cx;
		LPTSTR pszText;
	} lvc[] = {
		{ LVCFMT_LEFT, 20, L"" },
		{ LVCFMT_LEFT, 300, L"名前" },
		{ LVCFMT_LEFT, 120, L"最終変更日時" },
		{ LVCFMT_RIGHT, 80, L"サイズ" },
	};
	LVCOLUMN col;
	col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
	for (int n = 0; n < _countof(lvc); n++) {
		col.fmt = lvc[n].fmt;
		col.cx = lvc[n].cx;
		col.pszText = lvc[n].pszText;
		col.iSubItem = n;
		ListView_InsertColumn(hList, n, &col);
	}
}
 
void OnDestroy(HWND hDlg)
{
	RECT rc;
	GetWindowRect(hDlg, &rc);
	UpdateData(hDlg, TRUE);
 
	TCHAR szBuf[16];
	swprintf_s(szBuf, L"%d", rc.left);
	WritePrivateProfileString(SECT, L"X", szBuf, szIniFile);
	swprintf_s(szBuf, L"%d", rc.top);
	WritePrivateProfileString(SECT, L"Y", szBuf, szIniFile);
	WritePrivateProfileString(SECT, L"SizeMin", szSizeMin, szIniFile);
	WritePrivateProfileString(SECT, L"Extension", szExtension, szIniFile);
	WritePrivateProfileString(SECT, L"SaveDir", szSaveDir, szIniFile);
}
 
void OnColumnClick(HWND hDlg, LPNMLISTVIEW plv)
{
	if (plv->iSubItem == 0) {
		int n = MessageBox(hDlg, L"はい\t全てチェック\nいいえ\t全てクリア", L"IECacheSave",
			MB_YESNOCANCEL | MB_ICONINFORMATION);
		if (n == IDCANCEL) return;
		BOOL fCheck = (n == IDYES);
		int nCount = ListView_GetItemCount(hList);
		for (int i = 0; i < nCount; i++) {
			ListView_SetCheckState(hList, i, fCheck);
		}
	}
	else {
		WaitCursor wait;
		ListView_SortItems(hList, CompareFunc, plv->iSubItem);
	}
}
 
void OnGetList(HWND hDlg)
{
	WaitCursor wait;
	TCHAR szBuf[MAX_PATH];
 
	TCHAR szExt[256];
	//	UpdateData(hDlg, TRUE);
	UINT nSizeMin = GetDlgItemInt(hDlg, IDC_SIZE_MIN, NULL, FALSE);
	GetDlgItemText(hDlg, IDC_EXTENSION, szExt, _countof(szExt));
 
	// インターネット一時ファイルの場所
	if (IsWindows8OrGreater()) {
		GetEnvironmentVariable(L"LOCALAPPDATA", szContent, _countof(szContent));
		wcscat_s(szContent, L"\\Microsoft\\Windows\\INetCache\\Low\\IE");
	}
	else if (IsWindowsVistaOrGreater()) {
		GetEnvironmentVariable(L"LOCALAPPDATA", szContent, _countof(szContent));
		wcscat_s(szContent, L"\\Microsoft\\Windows\\Temporary Internet Files\\Low\\Content.IE5");
	}
	else {
		GetEnvironmentVariable(L"USERPROFILE", szContent, _countof(szContent));
		wcscat_s(szContent, L"\\Local Settings\\Temporary Internet Files\\Content.IE5");
	}
 
	WIN32_FIND_DATA fdm;
	swprintf_s(szBuf, L"%s\\*", szContent);
	HANDLE hMain = FindFirstFile(szBuf, &fdm);
	if (hMain == INVALID_HANDLE_VALUE) return;
 
	// 行情報
	LVITEM item;
	item.iItem = 0;
	ListView_DeleteAllItems(hList);
 
	do {
		if ((fdm.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) continue;
		if (fdm.cFileName[0] == L'.') continue;
 
		WIN32_FIND_DATA fds;
		swprintf_s(szBuf, L"%s\\%s\\*", szContent, fdm.cFileName);
		HANDLE hSub = FindFirstFile(szBuf, &fds);
		do {
			if (fds.nFileSizeLow == 0) continue;
			if (fds.nFileSizeLow < nSizeMin) continue;
			if (CheckExt(fds.cFileName, szExt) == FALSE) continue;
 
			FILETIME lft;
			SYSTEMTIME st;
			FileTimeToLocalFileTime(&fds.ftLastWriteTime, &lft);
			FileTimeToSystemTime(&lft, &st);
			swprintf_s(szBuf, L"%04u/%02u/%02u %02u:%02u:%02u",
				st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
 
			item.mask = LVIF_TEXT | LVIF_PARAM;
			item.iSubItem = 0;
			item.pszText = fdm.cFileName;	// SubDir
			item.lParam = item.iItem;
			ListView_InsertItem(hList, &item);
 
			item.mask = LVIF_TEXT;
			item.iSubItem = 1;
			item.pszText = fds.cFileName;
			ListView_SetItem(hList, &item);
 
			item.iSubItem = 2;
			item.pszText = szBuf;
			ListView_SetItem(hList, &item);
 
			item.iSubItem = 3;
			item.pszText = ThousandsSeparator(fds.nFileSizeLow);
			ListView_SetItem(hList, &item);
 
			item.iItem++;
		} while (FindNextFile(hSub, &fds));
		FindClose(hSub);
	} while (FindNextFile(hMain, &fdm));
	FindClose(hMain);
 
	// 最終変更日時の降順でソート
	ListView_SortItems(hList, CompareFunc, 2);
 
	swprintf_s(szBuf, L"%d 件", item.iItem);
	SetDlgItemText(hDlg, IDC_MESSAGE, szBuf);
}
 
BOOL CheckExt(LPCTSTR filename, LPCTSTR extension)
{
	if (extension[0] == L'\0') return TRUE;
 
	TCHAR ext[_MAX_EXT];
	_wsplitpath_s(filename, NULL, 0, NULL, 0, NULL, 0, ext, _countof(ext));
	if (ext[0] != L'.') return FALSE;
	if (_wcsicmp(extension, ext + 1) == 0) return TRUE;
	return FALSE;
}
 
void OnSave(HWND hDlg)
{
	WaitCursor wait;
	UpdateData(hDlg, TRUE);
 
	TCHAR szNew[_MAX_PATH];
	swprintf_s(szNew, L"%s\\%c", szSaveDir, L'\0');
 
	int nCount = ListView_GetItemCount(hList);
	for (int i = 0; i < nCount; i++) {
		if (ListView_GetCheckState(hList, i)) {
			TCHAR szExist[_MAX_PATH];
			TCHAR szDir[_MAX_DIR];
			TCHAR szFName[_MAX_FNAME];
			ListView_GetItemText(hList, i, 0, szDir, _countof(szDir));
			ListView_GetItemText(hList, i, 1, szFName, _countof(szFName));
			swprintf_s(szExist, L"%s\\%s\\%s%c", szContent, szDir, szFName, L'\0');
			//			CopyFile(szExist, szNew, TRUE);
 
			SHFILEOPSTRUCT fo;
			fo.hwnd = hDlg;
			fo.wFunc = FO_COPY;
			fo.pFrom = szExist;
			fo.pTo = szNew;
			fo.fFlags = FOF_ALLOWUNDO;
			if (SHFileOperation(&fo)) break;
		}
	}
}
 
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	LVFINDINFO lvfi;
	lvfi.flags = LVFI_PARAM;
	lvfi.lParam = lParam1;
	int iItem1 = ListView_FindItem(hList, -1, &lvfi);
	lvfi.lParam = lParam2;
	int iItem2 = ListView_FindItem(hList, -1, &lvfi);
 
	TCHAR szBuf1[MAX_PATH];
	TCHAR szBuf2[MAX_PATH];
	ListView_GetItemText(hList, iItem1, lParamSort, szBuf1, _countof(szBuf1));
	ListView_GetItemText(hList, iItem2, lParamSort, szBuf2, _countof(szBuf2));
	switch (lParamSort) {
	case 1:	// 名前
		return _wcsicmp(szBuf1, szBuf2);
	case 2:	// 最終変更日時
		return -wcscmp(szBuf1, szBuf2);
	case 3:	// サイズ
		TCHAR szBuf3[16];
		TCHAR szBuf4[16];
		swprintf_s(szBuf3, L"%13s", szBuf1);
		swprintf_s(szBuf4, L"%13s", szBuf2);
		return -wcscmp(szBuf3, szBuf4);
	}
	return 0;
}
 

resource.h
#define IDD_DIALOG	100
 
#define IDC_STATIC	-1
#define IDC_LIST	1000
#define IDC_SIZE_MIN	1001
#define IDC_EXTENSION	1002
#define IDC_SAVE_DIR	1003
#define IDC_SAVE_REF	1004
#define IDC_MESSAGE	1005
//#define IDC_GET_LIST	1006
#define IDC_SAVE	1007
 

IECacheList.rc
// resource script
#include <Windows.h>
#include "resource.h"
 
IDD_DIALOG DIALOGEX 100, 100, 320, 290
STYLE WS_POPUPWINDOW | WS_MINIMIZEBOX
EXSTYLE WS_EX_APPWINDOW
CAPTION "IECacheList"
FONT 9, "MS Pゴシック"
BEGIN
CONTROL		"", IDC_LIST, "SysListView32", WS_BORDER | WS_TABSTOP | LVS_REPORT, 5, 5, 310, 200
LTEXT		"サイズ下限", IDC_STATIC, 5, 213, 40, 15
EDITTEXT	IDC_SIZE_MIN, 50, 211, 45, 13
LTEXT		"拡張子", IDC_STATIC, 5, 233, 40, 15
EDITTEXT	IDC_EXTENSION, 50, 231, 150, 13
LTEXT		"保存Dir", IDC_STATIC, 5, 253, 40, 15
EDITTEXT	IDC_SAVE_DIR, 50, 251, 150, 13
//	PUSHBUTTON	"参照",IDC_SAVE_REF, 200, 250, 30, 15
LTEXT		"", IDC_MESSAGE, 5, 273, 310, 15
PUSHBUTTON	"List(&L)", IDOK, 265, 210, 50, 15
PUSHBUTTON	"Copy(&C)", IDC_SAVE, 265, 230, 50, 15
END