開発環境 Microsoft Visual C++ 2010 Express (SP1)
実行環境 Microsoft Windows XP Home Edition (SP3)
プロジェクトの種類 Win32 プロジェクト
プロジェクト名 ImgView2
アプリケーションの種類 Windows アプリケーション
追加のオプション 空のプロジェクト
文字セット Unicode

画像表示(エクスプローラの並び順)

ImgView2.cpp
// Unicode
#include <Windows.h>
#include <CommCtrl.h>
#include <shimgdata.h>
#include <stdio.h>
#include <string>
#include <vector>
#include "resource.h"
 
using namespace std;
 
#define WIDTH(rect) ((rect).right - (rect).left)
#define HEIGHT(rect) ((rect).bottom - (rect).top)
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
#define APP_NAME TEXT("ImgView2")
 
typedef vector<wstring> VecStr;
 
// 関数プロトタイプ宣言
void CreateFileList(LPCTSTR pszPath);
BOOL GetFileList(HWND hExplorer, LPCTSTR pszFileName);
BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam);
BOOL IsImgFile(LPCTSTR pszPath);
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL OnCommand(HWND hWnd, WPARAM wParam);
void OnDelete(HWND hWnd);
void OnDropFiles(HWND hWnd, WPARAM wParam);
void OnSizeNormal(HWND hWnd);
void OnSizeAdjust(HWND hWnd);
void OnExecute(void);
void OnPaint(HWND hWnd);
void GetImage(HWND hWnd);
BOOL MyGetFileTime(LPSYSTEMTIME pSystemTime, LPCTSTR pszFileName);
 
// 外部変数構造体
static struct {
	TCHAR szBaseDir[MAX_PATH];		// 基準ディレクトリ
	VecStr vsFileName;			// ファイル名配列
	VecStr::size_type idxCurr;		// 現在の位置
	IShellImageDataFactory *pImgDatFac;	// 画像データファクトリ
	IShellImageData *pImgDat;		// 画像データ
	SIZE sizeImg;				// 画像サイズ
	SIZE sizeDst;				// 出力サイズ
	HWND hListView;				// エクスプローラのリストビュー
} g;
 
//==============================================================================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
{
	// プログラム引数
	LPTSTR pszCmdLine = GetCommandLine();
	int argc;
	LPTSTR *argv = CommandLineToArgvW(pszCmdLine, &argc);
	if (2 <= argc) {
		CreateFileList(argv[1]);
	}
 
	// ウィンドウクラスの登録
	WNDCLASSEX wcx;
	ZeroMemory(&wcx, sizeof wcx);
	wcx.cbSize		= sizeof wcx;
	wcx.style		= CS_HREDRAW | CS_VREDRAW;
	wcx.lpfnWndProc		= WndProc;
	wcx.hInstance		= hInstance;
	wcx.hCursor		= LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
	wcx.hbrBackground	= (HBRUSH)(COLOR_WINDOW + 1);
	wcx.lpszClassName	= APP_NAME;
	if (RegisterClassEx(&wcx) == 0) {
		return 0;
	}
 
	// ウィンドウの作成
	HWND hWnd = CreateWindowEx(
		WS_EX_ACCEPTFILES,
		APP_NAME, APP_NAME,
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, 0,
		CW_USEDEFAULT, 0,
		NULL, NULL, hInstance, NULL);
	if (hWnd == NULL) {
		return 0;
	}
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);
 
	// メッセージループ
	MSG msg;
	HACCEL hAccTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_MAIN));
	while (GetMessage(&msg, NULL, 0, 0)) {
		if (TranslateAccelerator(msg.hwnd, hAccTable, &msg) == 0) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return msg.wParam;
}
 
//------------------------------------------------------------------------------
void CreateFileList(LPCTSTR pszPath)
{
	TCHAR szDrive	[_MAX_DRIVE];
	TCHAR szDir	[_MAX_DIR];
	TCHAR szFName	[_MAX_FNAME];
	TCHAR szExt	[_MAX_EXT];
	TCHAR szFileName[_MAX_PATH];
 
	g.vsFileName.clear();
	g.idxCurr = -1;
 
	errno_t er = _wsplitpath_s(pszPath, szDrive, szDir, szFName, szExt);
	swprintf_s(g.szBaseDir, L"%s%s", szDrive, szDir);
	swprintf_s(szFileName, L"%s%s", szFName, szExt);
 
	HWND hExplorer = NULL;
	while (hExplorer = FindWindowEx(NULL, hExplorer, L"ExploreWClass", NULL)) {
		GetFileList(hExplorer, szFileName);
		if (0 <= g.idxCurr) {
			break;
		}
	}
	if (g.idxCurr == -1) {
		g.vsFileName.clear();
		g.vsFileName.push_back(pszPath);
		g.idxCurr = 0;
	}
}
 
//------------------------------------------------------------------------------
BOOL GetFileList(HWND hExplorer, LPCTSTR pszFileName)
{
	// リストビュー
	g.hListView = NULL;
	BOOL br = EnumChildWindows(hExplorer, EnumWindowsProc, 0);
	if (g.hListView == NULL) return FALSE;
 
	// 対象となるリストビューのプロセスハンドルを得る
	DWORD dwProcId = 0;
	GetWindowThreadProcessId(g.hListView, &dwProcId);
	HANDLE hProc = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
		FALSE, dwProcId);
	if (hProc == NULL) return FALSE;
 
	// 他プロセス空間にメモリを確保
	LPTSTR pbuf = (LPTSTR)VirtualAllocEx(hProc, NULL, MAX_PATH,
		MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
	LPLVITEM plvi = (LPLVITEM)VirtualAllocEx(hProc, NULL, sizeof (LVITEM),
		MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
 
	// 行数
	int nRowNum = ListView_GetItemCount(g.hListView);
	VecStr::size_type idx = 0;
 
	// ListView_GetItemText
	LVITEM lvi;
	ZeroMemory(&lvi, sizeof (LVITEM));
	lvi.iSubItem	= 0;
	lvi.mask	= LVIF_TEXT;
	lvi.pszText	= pbuf;
	lvi.cchTextMax	= MAX_PATH;
	for (int nRow = 0; nRow < nRowNum; nRow++) {
		lvi.iItem = nRow;
		WriteProcessMemory(hProc, plvi, &lvi, sizeof (LVITEM), NULL);
		BOOL br = SendMessage(g.hListView, LVM_GETITEM, 0, (LPARAM)plvi);
		if (br) {
			TCHAR szText[MAX_PATH];
			ReadProcessMemory(hProc, pbuf, szText, MAX_PATH, NULL);
			if (IsImgFile(szText)) {
				g.vsFileName.push_back(szText);
				if (wcscmp(szText, pszFileName) == 0) {
					g.idxCurr = idx;
				}
				idx++;
			}
		}
	}
 
	VirtualFreeEx(hProc, plvi, 0, MEM_RELEASE);
	VirtualFreeEx(hProc, pbuf, 0, MEM_RELEASE);
	CloseHandle(hProc);
	return TRUE;
}
 
//------------------------------------------------------------------------------
BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
	TCHAR szBuf[256];
 
	int nr = GetClassName(hWnd, szBuf, _countof(szBuf));
	if (wcscmp(szBuf, WC_LISTVIEW) == 0) {	// L"SysListView32"
		g.hListView = hWnd;
		return FALSE;	// 打ち切り
	}
	BOOL br = EnumChildWindows(hWnd, EnumWindowsProc, lParam);
	return TRUE;	// 続行
}
 
//------------------------------------------------------------------------------
BOOL IsImgFile(LPCTSTR pszPath)
{
	static LPCTSTR ext[] = {L".jpg", L".jpeg", L".gif", L".png"};
	TCHAR szExt[_MAX_EXT];
 
	_wsplitpath_s(pszPath, NULL, 0, NULL, 0, NULL, 0, szExt, _MAX_EXT);
	for (int n = 0; n < _countof(ext); n++) {
		if (_wcsicmp(ext[n], szExt) == 0) {
			return TRUE;
		}
	}
	return FALSE;
}
 
//==============================================================================
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg) {
	case WM_PAINT:
		OnPaint(hWnd);
		return 0;
	case WM_COMMAND:
		if (OnCommand(hWnd, wParam)) {
			return 0;
		}
		break;
	case WM_DROPFILES:
		OnDropFiles(hWnd, wParam);
		DragFinish((HDROP)wParam);
		return 0;
	case WM_CREATE:
		CoInitialize(NULL);
		CoCreateInstance(CLSID_ShellImageDataFactory, NULL, CLSCTX_INPROC_SERVER,
			IID_PPV_ARGS(&g.pImgDatFac));
		GetImage(hWnd);
		return 0;
	case WM_DESTROY:
		SAFE_RELEASE(g.pImgDat);
		SAFE_RELEASE(g.pImgDatFac);
		CoUninitialize();
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
 
//------------------------------------------------------------------------------
BOOL OnCommand(HWND hWnd, WPARAM wParam)
{
	switch (LOWORD(wParam)) {
	case ID_RIGHT:
	case ID_DOWN:
		g.idxCurr++;
		if (g.vsFileName.size() <= g.idxCurr) {
			g.idxCurr = 0;
		}
		break;
	case ID_LEFT:
	case ID_UP:
		if (g.idxCurr <= 0) {
			g.idxCurr = g.vsFileName.size();
		}
		g.idxCurr--;
		break;
	case ID_ENTER:
		ShowWindow(hWnd, IsZoomed(hWnd) ? SW_SHOWNOACTIVATE : SW_MAXIMIZE);
		break;
	case ID_SIZE_NORMAL:
		OnSizeNormal(hWnd);
		// あえてスルー
	case ID_SIZE_ADJUST:
		OnSizeAdjust(hWnd);
		break;
	case ID_EXECUTE:
		OnExecute();
		break;
	case ID_DELETE:
		OnDelete(hWnd);
		break;
	case ID_ESCAPE:
		DestroyWindow(hWnd);
		return TRUE;
	default:
		return FALSE;
	}
	GetImage(hWnd);
	InvalidateRect(hWnd, NULL, FALSE);	// ちらつき防止のため背景消去しない
	return TRUE;
}
 
//------------------------------------------------------------------------------
void OnDelete(HWND hWnd)
{
	if (g.vsFileName.empty()) return;
 
	TCHAR szPath[MAX_PATH];	// '\0'2つで終わる要あり
	swprintf_s(szPath, L"%s%s%c", g.szBaseDir, g.vsFileName[g.idxCurr].c_str(), L'\0');
 
	SHFILEOPSTRUCT fo;
	ZeroMemory(&fo, sizeof fo);
	fo.hwnd		= hWnd;
	fo.wFunc	= FO_DELETE;
	fo.pFrom	= szPath;
	fo.fFlags	= FOF_ALLOWUNDO;
	SHFileOperation(&fo);
}
 
//------------------------------------------------------------------------------
void OnDropFiles(HWND hWnd, WPARAM wParam)
{
	HDROP	hDrop;
	TCHAR	szPath[MAX_PATH];
 
	hDrop = (HDROP)wParam;
	DragQueryFile(hDrop, 0, szPath, _countof(szPath));
	CreateFileList(szPath);
	GetImage(hWnd);
	InvalidateRect(hWnd, NULL, FALSE);	// ちらつき防止のため背景消去しない
}
 
//------------------------------------------------------------------------------
void OnSizeNormal(HWND hWnd)
{
	if (g.pImgDat == NULL) return;
 
	g.sizeDst = g.sizeImg;
 
	RECT rcWorkArea;// タスクバーを除くデスクトップ領域
	RECT rcWnd;	// ウィンドウ領域
	RECT rcClt;	// クライアント領域
	SIZE size;	// ウィンドウ領域とクライアント領域の差分
	SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
	GetWindowRect(hWnd, &rcWnd);
	GetClientRect(hWnd, &rcClt);
	size.cx = WIDTH(rcWnd) - WIDTH(rcClt);
	size.cy = HEIGHT(rcWnd) - HEIGHT(rcClt);
 
	// デスクトップ領域からはみ出す場合、ウィンドウを左上方向に移動する
	if (rcWorkArea.right < rcWnd.left + g.sizeDst.cx + size.cx) {
		rcWnd.left = 0;
	}
	if (rcWorkArea.bottom < rcWnd.top + g.sizeDst.cy + size.cy) {
		rcWnd.top = 0;
	}
 
	// 最大クライアント領域に収める
	if (rcWorkArea.right - size.cx < g.sizeDst.cx) {
		g.sizeDst.cx = rcWorkArea.right - size.cx;
	}
	if (rcWorkArea.bottom - size.cy < g.sizeDst.cy) {
		g.sizeDst.cy = rcWorkArea.bottom - size.cy;
	}
 
	// アスペクト比の調整
	if (g.sizeImg.cx < g.sizeImg.cy * g.sizeDst.cx / g.sizeDst.cy) {
		g.sizeDst.cx = g.sizeDst.cy * g.sizeImg.cx / g.sizeImg.cy;
	} else {
		g.sizeDst.cy = g.sizeDst.cx * g.sizeImg.cy / g.sizeImg.cx;
	}
 
	// ウィンドウ位置のセット
	rcWnd.right = g.sizeDst.cx + size.cx;
	rcWnd.bottom = g.sizeDst.cy + size.cy;
	SetWindowPos(hWnd, NULL, rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom, SWP_NOZORDER);
}
 
//------------------------------------------------------------------------------
void OnSizeAdjust(HWND hWnd)
{
	if (g.pImgDat == NULL) return;
 
	RECT rc;
	SetRect(&rc, 0, 0, g.sizeDst.cx, g.sizeDst.cy);
	AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW, FALSE, 0);
	SetWindowPos(hWnd, NULL, 0, 0, WIDTH(rc), HEIGHT(rc), SWP_NOZORDER | SWP_NOMOVE);
}
 
//------------------------------------------------------------------------------
void OnExecute(void)
{
	if (g.vsFileName.empty()) return;
 
	TCHAR szFile[MAX_PATH];
	TCHAR szParams[MAX_PATH];
	GetModuleFileName(NULL, szFile, MAX_PATH);
	swprintf_s(szParams, L"\"%s%s\"", g.szBaseDir, g.vsFileName[g.idxCurr].c_str());
 
	SHELLEXECUTEINFO ei;
	ZeroMemory(&ei, sizeof ei);
	ei.cbSize	= sizeof ei;
	ei.nShow	= SW_SHOWNORMAL;
	ei.fMask	= SEE_MASK_NOCLOSEPROCESS;
	ei.lpFile	= szFile;
	ei.lpParameters	= szParams;
	ShellExecuteEx(&ei);
}
 
//------------------------------------------------------------------------------
void OnPaint(HWND hWnd)
{
	PAINTSTRUCT ps;
	HDC hdc = BeginPaint(hWnd, &ps);
	if (g.pImgDat == NULL) goto Exit;
 
	RECT rcClt;
	GetClientRect(hWnd, &rcClt);
 
	// 画像とクライアント領域のアスペクト比を比較し
	// アスペクト比を維持したままクライアント領域に収める
	if (g.sizeImg.cx < g.sizeImg.cy * rcClt.right / rcClt.bottom) {
		g.sizeDst.cx = rcClt.bottom * g.sizeImg.cx / g.sizeImg.cy;
		g.sizeDst.cy = rcClt.bottom;
	} else {
		g.sizeDst.cx = rcClt.right;
		g.sizeDst.cy = rcClt.right * g.sizeImg.cy / g.sizeImg.cx;
	}
 
	RECT rcDst;
	rcDst.left	= (rcClt.right - g.sizeDst.cx) / 2;
	rcDst.top	= (rcClt.bottom - g.sizeDst.cy) / 2;
	rcDst.right	= rcDst.left + g.sizeDst.cx;
	rcDst.bottom	= rcDst.top + g.sizeDst.cy;
 
	// 画像描画
	RECT rcTmp;
	SetRect(&rcTmp, 0, 0, g.sizeImg.cx, g.sizeImg.cy);
	g.pImgDat->Draw(hdc, &rcDst, &rcTmp);
 
	// 余白塗り潰し
	HBRUSH hbr = (HBRUSH)(COLOR_WINDOW + 1);
	if (rcClt.left < rcDst.left) {
		CopyRect(&rcTmp, &rcClt);
		rcTmp.right = rcDst.left;
		FillRect(hdc, &rcTmp, hbr);
	}
	if (rcClt.top < rcDst.top) {
		CopyRect(&rcTmp, &rcClt);
		rcTmp.bottom = rcDst.top;
		FillRect(hdc, &rcTmp, hbr);
	}
	if (rcDst.right < rcClt.right) {
		CopyRect(&rcTmp, &rcClt);
		rcTmp.left = rcDst.right;
		FillRect(hdc, &rcTmp, hbr);
	}
	if (rcDst.bottom < rcClt.bottom) {
		CopyRect(&rcTmp, &rcClt);
		rcTmp.top = rcDst.bottom;
		FillRect(hdc, &rcTmp, hbr);
	}
Exit:
	EndPaint(hWnd, &ps);
}
 
//------------------------------------------------------------------------------
void GetImage(HWND hWnd)
{
	SAFE_RELEASE(g.pImgDat);
	if (g.vsFileName.empty()) {
		SetWindowText(hWnd, APP_NAME);
		return;
	}
 
	// 画像ファイルの読み込み
	TCHAR szBuf[512];
	LPCTSTR pszFileName = g.vsFileName[g.idxCurr].c_str();
	swprintf_s(szBuf, L"%s%s", g.szBaseDir, pszFileName);
	HRESULT hr = g.pImgDatFac->CreateImageFromFile(szBuf, &g.pImgDat);
	if (SUCCEEDED(hr)) {
		hr = g.pImgDat->Decode(SHIMGDEC_DEFAULT, 0, 0);
	}
	if (SUCCEEDED(hr)) {
		hr = g.pImgDat->GetSize(&g.sizeImg);
	}
	if (FAILED(hr) || g.sizeImg.cx <= 0 || g.sizeImg.cy <= 0) {
		SAFE_RELEASE(g.pImgDat);
		g.sizeImg.cx = g.sizeImg.cy = 0;
	}
 
	// ファイル更新日時の取得
	SYSTEMTIME st;
	MyGetFileTime(&st, szBuf);
 
	// タイトルバー
	swprintf_s(szBuf, L"%s [%d/%d] %d/%02d/%02d %02d:%02d:%02d (%dx%d) - %s",
		pszFileName, g.idxCurr + 1, g.vsFileName.size(),
		st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond,
		g.sizeImg.cx, g.sizeImg.cy, APP_NAME);
	SetWindowText(hWnd, szBuf);
}
 
//------------------------------------------------------------------------------
BOOL MyGetFileTime(LPSYSTEMTIME pSystemTime, LPCTSTR pszFileName)
{
	HANDLE hFile = CreateFile(pszFileName, GENERIC_READ, 0, NULL,
		OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		return FALSE;
	}
 
	FILETIME ftCreation;
	FILETIME ftLocal;
	GetFileTime(hFile, &ftCreation, NULL, NULL);
	FileTimeToLocalFileTime(&ftCreation, &ftLocal);
	FileTimeToSystemTime(&ftLocal, pSystemTime);
 
	CloseHandle(hFile);
	return TRUE;
}
 

resource.h
#define ID_SIZE_ADJUST	100
#define ID_SIZE_NORMAL	101
#define ID_EXECUTE	102
 
#define IDR_MAIN	128
#define ID_ENTER	129
#define ID_ESCAPE	130
#define ID_LEFT		131
#define ID_UP		132
#define ID_RIGHT	133
#define ID_DOWN		134
#define ID_DELETE	135
 

ImgView2.rc
// resource script
#include <windows.h>
#include "resource.h"
 
// アクセラレータ
IDR_MAIN ACCELERATORS
BEGIN
	VK_RETURN,	ID_ENTER,	VIRTKEY		// 0x0D
	VK_ESCAPE,	ID_ESCAPE,	VIRTKEY		// 0x1B
	VK_LEFT,	ID_LEFT,	VIRTKEY		// 0x25
	VK_UP,		ID_UP,		VIRTKEY		// 0x26
	VK_RIGHT,	ID_RIGHT,	VIRTKEY		// 0x27
	VK_DOWN,	ID_DOWN,	VIRTKEY		// 0x28
	VK_DELETE,	ID_DELETE,	VIRTKEY		// 0x2E
	"1",		ID_SIZE_ADJUST,	VIRTKEY		// 0x31
	VK_NUMPAD1,	ID_SIZE_ADJUST,	VIRTKEY		// 0x61
	"2",		ID_SIZE_NORMAL,	VIRTKEY		// 0x32
	VK_NUMPAD2,	ID_SIZE_NORMAL,	VIRTKEY		// 0x62
	"3",		ID_EXECUTE,	VIRTKEY		// 0x33
	VK_NUMPAD3,	ID_EXECUTE,	VIRTKEY		// 0x63
END
 
最終更新:2012年11月24日 21:03