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

作成中。

参考
イメージの描画
ピクチャーオブジェクト
JPEG(ジェイペグ)やGIF(ジフ)を表示しよう^0^

ImgView.cpp
#include <tchar.h>
#include <Windows.h>
#include <shimgdata.h>
#include <string>
#include <vector>
#include "resource.h"
 
typedef std::vector<std::wstring> VecStr;
 
// 関数プロトタイプ宣言
ATOM			MyRegisterClass(HINSTANCE hInstance);
BOOL			InitInstance(HINSTANCE hInstance, int nCmdShow);
void			Trace(LPCTSTR ptcFormat, ...);
void			CreateFileList(LPCTSTR ptcPath);
LRESULT CALLBACK	WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int			OnCommand(HWND hWnd, WPARAM wParam);
void			OnEditPaste(HWND hWnd);
void			OnDropFiles(HWND hWnd, WPARAM wParam);
void			OnSizeAdjust(HWND hWnd, int iFlag);
void			OnPaint(HWND hWnd, HDC hdc, PAINTSTRUCT &ps);
void			OnTimer(HWND hWnd);
void			StopTimer(HWND hWnd);
int			GetImage(HWND hWnd);
 
// グローバル変数
TCHAR			g_atcClassName[] = _T("ImgView");
TCHAR			g_atcWindowName[] = _T("Image Viewer");
HINSTANCE		g_hInstance;
TCHAR			g_atcWorkDir[_MAX_PATH];
UINT_PTR		g_uiIDEvent = 0;
VecStr			g_vsFileName;
VecStr::size_type	g_posCurr = -1;
IShellImageDataFactory	*g_pShellImageDataFactory = NULL;
IShellImageData		*g_pShellImageData = NULL;
SIZE			g_sizeDest;
 
//==============================================================================
int APIENTRY _tWinMain(
	HINSTANCE	hInstance,
	HINSTANCE	hPrevInstance,
	LPTSTR		lpCmdLine,
	int		nCmdShow)
{
	MSG	msg;
	HACCEL	hAccelTable;
	LPTSTR	ptcCmdLine;
	LPTSTR	*argv;
	int	argc;
 
	ptcCmdLine = GetCommandLine();
	argv = CommandLineToArgvW(ptcCmdLine, &argc);
	if (2 <= argc) {
		CreateFileList(argv[1]);
	}
 
	MyRegisterClass(hInstance);
	if (InitInstance(hInstance, nCmdShow) == FALSE) {
		return 0;
	}
	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDR_MAINFRAME);
	while (GetMessage(&msg, NULL, 0, 0)) {
		if (TranslateAccelerator(msg.hwnd, hAccelTable, &msg) == 0) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return msg.wParam;
}
 
//------------------------------------------------------------------------------
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX	wcex;
 
	wcex.cbSize		= sizeof (WNDCLASSEX);
	wcex.style		= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon		= LoadIcon(NULL, IDI_APPLICATION);
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName	= NULL;
	wcex.lpszClassName	= g_atcClassName;
	wcex.hIconSm		= LoadIcon(NULL, IDI_APPLICATION);
	return RegisterClassEx(&wcex);
}
 
//------------------------------------------------------------------------------
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	HWND	hWnd;
 
	g_hInstance = hInstance;
	hWnd = CreateWindowEx(
		WS_EX_ACCEPTFILES,
		g_atcClassName,
		g_atcWindowName,
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, 0,
		CW_USEDEFAULT, 0,
		NULL, NULL,
		hInstance,
		NULL);
	if (hWnd == NULL) {
		return FALSE;
	}
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);
	return TRUE;
}
 
//------------------------------------------------------------------------------
void Trace(LPCTSTR ptcFormat, ...)
{
	va_list	args;
	TCHAR	atcBuf[512];
	int	iRet;
 
	va_start(args, ptcFormat);
	iRet = _vstprintf_s(atcBuf, ptcFormat, args);
	if (0 < iRet) {
		OutputDebugString(atcBuf);
	}
	va_end(args);
}
 
//------------------------------------------------------------------------------
void CreateFileList(LPCTSTR ptcPath)
{
	WIN32_FIND_DATA		wfd;
	TCHAR			atcWorkFName	[_MAX_FNAME];
	TCHAR			atcPath		[_MAX_PATH];
	TCHAR			atcDrive	[_MAX_DRIVE];
	TCHAR			atcDir		[_MAX_DIR];
	TCHAR			atcFName	[_MAX_FNAME];
	TCHAR			atcExt		[_MAX_EXT];
	HANDLE			hFindFile;
	DWORD			dwMask;
	VecStr::size_type	pos;
 
	g_vsFileName.clear();
	g_posCurr = -1;
 
	_tsplitpath_s(ptcPath, atcDrive, atcDir, atcFName, atcExt);
	_stprintf_s(g_atcWorkDir, _T("%s%s"), atcDrive, atcDir);
	_stprintf_s(atcWorkFName, _T("%s%s"), atcFName, atcExt);
	_stprintf_s(atcPath, _T("%s*.*"), g_atcWorkDir);
 
	hFindFile = FindFirstFile(atcPath, &wfd);
	dwMask = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN;
	pos = 0;
	do {
		Trace(_T("%s\n"), wfd.cFileName);
		if (wfd.dwFileAttributes & dwMask) {
			continue;
		}
		g_vsFileName.push_back(wfd.cFileName);
		if (_tcscmp(wfd.cFileName, atcWorkFName) == 0) {
			g_posCurr = pos;
		}
		pos++;
	} while (FindNextFile(hFindFile, &wfd));
	FindClose(hFindFile);
}
 
//------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT	ps;
	HDC		hdc;
 
	switch (uMsg) {
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		OnPaint(hWnd, hdc, ps);
		EndPaint(hWnd, &ps);
		break;
	case WM_TIMER:
		OnTimer(hWnd);
		break;
	case WM_COMMAND:
		if (OnCommand(hWnd, wParam)) {
			return DefWindowProc(hWnd, uMsg, wParam, lParam);
		}
		break;
	case WM_DROPFILES:
		OnDropFiles(hWnd, wParam);
		DragFinish((HDROP)wParam);
		break;
	case WM_CREATE:
		CoInitialize(NULL);
		CoCreateInstance(CLSID_ShellImageDataFactory, NULL, CLSCTX_INPROC_SERVER,
			IID_PPV_ARGS(&g_pShellImageDataFactory));
		GetImage(hWnd);
		break;
	case WM_DESTROY:
		StopTimer(hWnd);
		if (g_pShellImageDataFactory) {
			g_pShellImageDataFactory->Release();
		}
		CoUninitialize();
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
	}
	return 0;
}
 
//------------------------------------------------------------------------------
int OnCommand(HWND hWnd, WPARAM wParam)
{
	switch (LOWORD(wParam)) {
	case ID_RIGHT:
	case ID_DOWN:
		g_posCurr++;
		if (g_vsFileName.size() <= g_posCurr) {
			g_posCurr = 0;
		}
		break;
	case ID_LEFT:
	case ID_UP:
		if (g_posCurr <= 0) {
			g_posCurr = g_vsFileName.size();
		}
		g_posCurr--;
		break;
	case ID_ENTER:
		ShowWindow(hWnd, IsZoomed(hWnd) ? SW_SHOWNOACTIVATE : SW_MAXIMIZE);
		break;
	case ID_EDIT_PASTE:	// Ctrl+V
		OnEditPaste(hWnd);
		break;
	case ID_SIZE_ADJUST:	// 1
		OnSizeAdjust(hWnd, 1);
		break;
	case ID_SIZE_NORMAL:	// 2
		OnSizeAdjust(hWnd, 2);
		break;
	default:
		return 1;
	}
	GetImage(hWnd);
	InvalidateRect(hWnd, NULL, FALSE);	// ちらつき防止のため背景消去しない
	return 0;
}
 
//------------------------------------------------------------------------------
void OnEditPaste(HWND hWnd)
{
	HANDLE	hMem;
	LPTSTR	ptcFileName;
 
	if (IsClipboardFormatAvailable(CF_UNICODETEXT) == FALSE) {
		return;
	}
	if (OpenClipboard(hWnd) == FALSE) {
		return;
	}
	hMem = GetClipboardData(CF_UNICODETEXT);
	ptcFileName = (LPTSTR)GlobalLock(hMem);
 
	g_atcWorkDir[0] = _T('\0');
	g_vsFileName.clear();
	g_vsFileName.push_back(ptcFileName);
	g_posCurr = 0;
 
	GlobalUnlock(hMem);
	CloseClipboard();
}
 
//------------------------------------------------------------------------------
void OnDropFiles(HWND hWnd, WPARAM wParam)
{
	HDROP	hDrop;
	TCHAR	atcPath[_MAX_PATH];
 
	hDrop = (HDROP)wParam;
	DragQueryFile(hDrop, 0, atcPath, _countof(atcPath));
	CreateFileList(atcPath);
	GetImage(hWnd);
	InvalidateRect(hWnd, NULL, FALSE);	// ちらつき防止のため背景消去しない
}
 
//------------------------------------------------------------------------------
void OnSizeAdjust(HWND hWnd, int iFlag)
{
	SIZE	size;
	RECT	rc;
 
	if (g_pShellImageData == NULL) {
		return;
	}
	switch (iFlag) {
	case 1:	// Adjust
		size = g_sizeDest;
		break;
	case 2:	// Normal
		g_pShellImageData->GetSize(&size);
		break;
	}
	SetRect(&rc, 0, 0, size.cx, size.cy);
	AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW, FALSE, 0);
	SetWindowPos(hWnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
		SWP_NOZORDER | SWP_NOMOVE);
}
 
//------------------------------------------------------------------------------
void OnPaint(HWND hWnd, HDC hdc, PAINTSTRUCT &ps)
{
	SIZE		size;
	RECT		rcClt;
	RECT		rcSrc;
	RECT		rcDest;
	HBRUSH		hbr = (HBRUSH)(COLOR_WINDOW + 1);
 
	if (g_pShellImageData == NULL) {
		return;
	}
	g_pShellImageData->GetSize(&size);
	GetClientRect(hWnd, &rcClt);
 
	// 画像とクライアント領域のアスペクト比を比較し
	// アスペクト比を維持したままクライアント領域に収める
	if (size.cx < size.cy * rcClt.right / rcClt.bottom) {
		g_sizeDest.cx = rcClt.bottom * size.cx / size.cy;
		g_sizeDest.cy = rcClt.bottom;
	} else {
		g_sizeDest.cx = rcClt.right;
		g_sizeDest.cy = rcClt.right * size.cy / size.cx;
	}
	rcDest.left	= (rcClt.right - g_sizeDest.cx) / 2;
	rcDest.top	= (rcClt.bottom - g_sizeDest.cy) / 2;
	rcDest.right	= rcDest.left + g_sizeDest.cx;
	rcDest.bottom	= rcDest.top + g_sizeDest.cy;
 
	// 画像描画
	SetRect(&rcSrc, 0, 0, size.cx, size.cy);
	g_pShellImageData->Draw(hdc, &rcDest, &rcSrc);
 
	// 余白塗り潰し
	if (rcClt.left < rcDest.left) {
		SetRect(&rcSrc, rcClt.left, rcClt.top, rcDest.left, rcClt.bottom);
		FillRect(hdc, &rcSrc, hbr);
	}
	if (rcClt.top < rcDest.top) {
		SetRect(&rcSrc, rcClt.left, rcClt.top, rcClt.right, rcDest.top);
		FillRect(hdc, &rcSrc, hbr);
	}
	if (rcDest.right < rcClt.right) {
		SetRect(&rcSrc, rcDest.right, rcClt.top, rcClt.right, rcClt.bottom);
		FillRect(hdc, &rcSrc, hbr);
	}
	if (rcDest.bottom < rcClt.bottom) {
		SetRect(&rcSrc, rcClt.left, rcDest.bottom, rcClt.right, rcClt.bottom);
		FillRect(hdc, &rcSrc, hbr);
	}
}
 
//------------------------------------------------------------------------------
void OnTimer(HWND hWnd)
{
	ULONG	ulPage;
	ULONG	ulPages;
 
	g_pShellImageData->GetCurrentPage(&ulPage);
	g_pShellImageData->GetPageCount(&ulPages);
	if (ulPage < ulPages - 1) {
		g_pShellImageData->NextPage();
	} else {
		g_pShellImageData->SelectPage(0);
	}
	InvalidateRect(hWnd, NULL, FALSE);	// ちらつき防止のため背景消去しない
}
 
//------------------------------------------------------------------------------
// タイマー停止
void StopTimer(HWND hWnd)
{
	if (g_uiIDEvent != 0) {
		KillTimer(hWnd, g_uiIDEvent);
		g_uiIDEvent = 0;
	}
}
 
//------------------------------------------------------------------------------
int GetImage(HWND hWnd)
{
	TCHAR	atcPath[512];
	LPCTSTR	ptcFileName;
	DWORD	dwDelay;
	ULONG	ulPages;
	HRESULT	hr;
 
	StopTimer(hWnd);
	if (g_pShellImageData) {
		g_pShellImageData->Release();
		g_pShellImageData = NULL;
	}
 
	// タイトルバー
	if (g_posCurr == -1) {
		SetWindowText(hWnd, g_atcWindowName);
		return 1;
	}
	ptcFileName = g_vsFileName[g_posCurr].c_str();
	_stprintf_s(atcPath, _T("%s [%d/%d] - %s"),
		ptcFileName, g_posCurr + 1, g_vsFileName.size(), g_atcWindowName);
	SetWindowText(hWnd, atcPath);
 
	_stprintf_s(atcPath, _T("%s%s"), g_atcWorkDir, ptcFileName);
	hr = g_pShellImageDataFactory->CreateImageFromFile(atcPath, &g_pShellImageData);
	if (FAILED(hr)) {
		return -1;
	}
	hr = g_pShellImageData->Decode(SHIMGDEC_DEFAULT, 0, 0);
	if (FAILED(hr)) {
		return -1;
	}
 
	// アニメ
	hr = g_pShellImageData->IsAnimated();
	if (hr != S_OK) {
		return 0;
	}
	g_pShellImageData->GetDelay(&dwDelay);
	g_pShellImageData->GetPageCount(&ulPages);
	_stprintf_s(atcPath, _T("%s [%d/%d] Delay=%u Pages=%u - %s"),
		ptcFileName, g_posCurr + 1, g_vsFileName.size(), dwDelay, ulPages,
		g_atcWindowName);
	SetWindowText(hWnd, atcPath);
	g_uiIDEvent = SetTimer(hWnd, 1, dwDelay, NULL);
	return 0;
}
 

resource.h
#define ID_EDIT_PASTE	100
#define ID_SIZE_ADJUST	101
#define ID_SIZE_NORMAL	102
 
#define IDR_MAINFRAME	128
#define ID_ENTER	129
#define ID_LEFT		130
#define ID_UP		131
#define ID_RIGHT	132
#define ID_DOWN		133
 

ImgView.rc
// リソーススクリプト
 
#include <windows.h>
#include "resource.h"
 
//------------------------------------------------------------------------------
// アクセラレータ
IDR_MAINFRAME ACCELERATORS
BEGIN
	VK_RETURN,	ID_ENTER,	VIRTKEY			// 0x0D
	VK_LEFT,	ID_LEFT,	VIRTKEY			// 0x25
	VK_UP,		ID_UP,		VIRTKEY			// 0x26
	VK_RIGHT,	ID_RIGHT,	VIRTKEY			// 0x27
	VK_DOWN,	ID_DOWN,	VIRTKEY			// 0x28
	"V",		ID_EDIT_PASTE,	VIRTKEY, CONTROL
	"1",		ID_SIZE_ADJUST,	VIRTKEY
	"2",		ID_SIZE_NORMAL,	VIRTKEY
END
 
最終更新:2012年09月01日 16:43