#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;
}