// Unicode文字セット
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
#include "resource.h"
#define CLASS_NAME _T("WinHexDmp")
#define WINDOW_NAME _T("WinHexDmp")
#define COL_LINE 16 // 列数/ライン
#define LINE_HEIGHT 16 // ラインの高さ
// 関数プロトタイプ宣言
void itoh(int value, char *string, int count);
void Trace(LPCTSTR format, ...);
int OpenMemMapFile(HWND hWnd);
void CloseMemMapFile(void);
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void OnPaint(HWND hWnd);
void OnVScroll(HWND hWnd, WPARAM wParam, LPARAM lParam);
void OnMouseWheel(HWND hWnd, WPARAM wParam, LPARAM lParam);
BOOL OnCommand(HWND hWnd, WPARAM wParam);
void OnSize(HWND hWnd, WPARAM wParam, LPARAM lParam);
void OnDropFiles(HWND hWnd, WPARAM wParam);
void OnCreate(HWND hWnd);
void OnDestroy(void);
void NewDocument(HWND hWnd);
// 外部変数構造体
static struct {
SCROLLINFO siVert;
HFONT hFont;
TCHAR szPath[MAX_PATH];
HANDLE hFile;
HANDLE hMap;
LPBYTE pBaseAddr;
DWORD dwFileSize;
} g;
//==============================================================================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcx;
HWND hWnd;
HACCEL hAccelTable;
MSG msg;
LPTSTR pszCmdLine;
LPTSTR *argv;
int argc;
// コマンド引数の取得
pszCmdLine = GetCommandLine();
argv = CommandLineToArgvW(pszCmdLine, &argc);
if (2 <= argc) {
_tcscpy_s(g.szPath, argv[1]);
}
// ウィンドウクラスの登録
ZeroMemory(&wcx, sizeof (WNDCLASSEX));
wcx.cbSize = sizeof (WNDCLASSEX);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = WindowProc;
wcx.hInstance = hInstance;
wcx.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcx.lpszClassName = CLASS_NAME;
if (RegisterClassEx(&wcx) == 0) {
return 0;
}
// ウィンドウの作成
hWnd = CreateWindowEx(
WS_EX_ACCEPTFILES, // Drag & Drop
CLASS_NAME, WINDOW_NAME,
WS_OVERLAPPEDWINDOW | WS_VSCROLL,
CW_USEDEFAULT, 0,
800, 600,
NULL, NULL, hInstance, NULL);
if (hWnd == NULL) {
return 0;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// メッセージループ
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_MAINFRAME));
while (GetMessage(&msg, NULL, 0, 0)) {
if (TranslateAccelerator(msg.hwnd, hAccelTable, &msg) == 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
CloseMemMapFile();
return msg.wParam;
}
//------------------------------------------------------------------------------
void itoh(int value, char *string, int count)
{
static const char hex[] = "0123456789abcdef";
while (count--) {
*string++ = hex[(value >> (count << 2)) & 0xf];
}
}
//------------------------------------------------------------------------------
void Trace(LPCTSTR format, ...)
{
va_list arg_ptr;
TCHAR buffer[256];
int size;
va_start(arg_ptr, format);
size = _vsntprintf_s(buffer, _TRUNCATE, format, arg_ptr);
va_end(arg_ptr);
OutputDebugString(buffer);
if (size < 0) {
OutputDebugString(_T("...\n"));
}
}
//------------------------------------------------------------------------------
int OpenMemMapFile(HWND hWnd)
{
CloseMemMapFile();
g.hFile = CreateFile(g.szPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (g.hFile == INVALID_HANDLE_VALUE) {
MessageBox(hWnd, _T("CreateFileに失敗しました"), NULL, MB_OK);
return -1;
}
g.hMap = CreateFileMapping(g.hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (g.hMap == NULL) {
MessageBox(hWnd, _T("CreateFileMappingに失敗しました"), NULL, MB_OK);
return -1;
}
g.pBaseAddr = (LPBYTE)MapViewOfFile(g.hMap, FILE_MAP_READ, 0, 0, 0);
if (g.pBaseAddr == NULL) {
MessageBox(hWnd, _T("MapViewOfFileに失敗しました"), NULL, MB_OK);
return -1;
}
g.dwFileSize = GetFileSize(g.hFile, NULL); // GetFileSizeEx
if (g.dwFileSize == INVALID_FILE_SIZE) {
g.dwFileSize = 0; // INVALID_FILE_SIZEを取り扱うのは好ましくない
MessageBox(hWnd, _T("GetFileSizeに失敗しました"), NULL, MB_OK);
return -1;
}
return 0;
}
//------------------------------------------------------------------------------
void CloseMemMapFile(void)
{
BOOL br;
g.dwFileSize = 0;
if (g.pBaseAddr) {
br = UnmapViewOfFile(g.pBaseAddr);
g.pBaseAddr = NULL;
}
if (g.hMap) {
br = CloseHandle(g.hMap);
g.hMap = NULL;
}
if (g.hFile) {
br = CloseHandle(g.hFile);
g.hFile = NULL;
}
}
//==============================================================================
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_PAINT:
OnPaint(hWnd);
return 0;
case WM_VSCROLL:
OnVScroll(hWnd, wParam, lParam);
return 0;
case WM_MOUSEWHEEL:
OnMouseWheel(hWnd, wParam, lParam);
return 0;
case WM_COMMAND:
if (OnCommand(hWnd, wParam)) {
return 0;
}
break;
case WM_SIZE:
OnSize(hWnd, wParam, lParam);
return 0;
case WM_DROPFILES:
OnDropFiles(hWnd, wParam);
DragFinish((HDROP)wParam);
return 0;
case WM_CREATE:
OnCreate(hWnd);
return 0;
case WM_DESTROY:
OnDestroy();
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
//------------------------------------------------------------------------------
void OnPaint(HWND hWnd)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
if (g.dwFileSize == 0) goto Exit;
RECT rc;
GetClientRect(hWnd, &rc);
HGDIOBJ hFontOld = SelectObject(hdc, g.hFont);
DWORD dwRowStart = ps.rcPaint.top / LINE_HEIGHT; // 描画開始行
DWORD dwRowEnd = (ps.rcPaint.bottom + LINE_HEIGHT - 1) / LINE_HEIGHT; // 描画終了行
Trace(_T("OnPaint %u, %u\n"), dwRowStart, dwRowEnd);
for (DWORD dwRow = dwRowStart; dwRow < dwRowEnd; dwRow++) {
DWORD dwAddr = COL_LINE * (g.siVert.nPos + dwRow); // 行先頭アドレス
DWORD dwColNum = g.dwFileSize - dwAddr; // 列数
if (COL_LINE < dwColNum) dwColNum = COL_LINE;
if (dwColNum == 0) break;
char szLine[80];
strcpy_s(szLine,
" | - - - | ");
// "HHHHHHHH:HH HH HH HH-HH HH HH HH-HH HH HH HH-HH HH HH HH:XXXXXXXXXXXXXXXX"
itoh(dwAddr, szLine, 8);
for (DWORD dwCol = 0; dwCol < dwColNum; dwCol++) {
BYTE byChar = g.pBaseAddr[dwAddr + dwCol];
// 16進表記
itoh(byChar, szLine + 9 + dwCol * 3, 2);
// 文字
if (isprint(byChar) == 0) {
byChar = '.';
}
szLine[57 + dwCol] = byChar;
}
TextOutA(hdc, 0, LINE_HEIGHT * dwRow, szLine, strlen(szLine));
if (dwColNum < COL_LINE) break;
}
SelectObject(hdc, hFontOld);
Exit:
EndPaint(hWnd, &ps);
}
//------------------------------------------------------------------------------
void OnVScroll(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
SCROLLINFO si;
int nPos;
int nPosMax;
nPos = g.siVert.nPos;
nPosMax = g.siVert.nMax - g.siVert.nPage + 1;
switch (LOWORD(wParam)) {
case SB_LINEUP: // 0
nPos -= 1;
break;
case SB_LINEDOWN: // 1
nPos += 1;
break;
case SB_PAGEUP: // 2
nPos -= g.siVert.nPage;
break;
case SB_PAGEDOWN: // 3
nPos += g.siVert.nPage;
break;
case SB_THUMBTRACK: // 5
si.cbSize = sizeof si;
si.fMask = SIF_TRACKPOS;
if (GetScrollInfo(hWnd, SB_VERT, &si) != 0) {
nPos = si.nTrackPos;
}
break;
case SB_TOP: // 6
nPos = 0;
break;
case SB_BOTTOM: // 7
nPos = nPosMax;
break;
}
nPos = min(nPos, nPosMax);
nPos = max(nPos, 0);
if (nPos == g.siVert.nPos) {
return;
}
ScrollWindowEx(hWnd, 0, LINE_HEIGHT * (g.siVert.nPos - nPos),
NULL, NULL, NULL, NULL, SW_INVALIDATE | SW_ERASE);
g.siVert.nPos = nPos;
SetScrollInfo(hWnd, SB_VERT, &g.siVert, TRUE);
UpdateWindow(hWnd);
// InvalidateRect(hWnd, NULL, TRUE);
}
//------------------------------------------------------------------------------
void OnMouseWheel(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
short zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
int nScrollCode;
if (0 < zDelta) {
nScrollCode = SB_LINEUP;
} else {
nScrollCode = SB_LINEDOWN;
}
SendMessage(hWnd, WM_VSCROLL, nScrollCode, (LPARAM)NULL);
}
//------------------------------------------------------------------------------
BOOL OnCommand(HWND hWnd, WPARAM wParam)
{
int nScrollCode;
switch (LOWORD(wParam)) {
case ID_ESC:
DestroyWindow(hWnd);
return TRUE;
case ID_PAGEUP:
nScrollCode = SB_PAGEUP;
break;
case ID_PAGEDOWN:
nScrollCode = SB_PAGEDOWN;
break;
case ID_END:
nScrollCode = SB_BOTTOM;
break;
case ID_HOME:
nScrollCode = SB_TOP;
break;
case ID_UP:
nScrollCode = SB_LINEUP;
break;
case ID_DOWN:
nScrollCode = SB_LINEDOWN;
break;
default:
return FALSE;
}
SendMessage(hWnd, WM_VSCROLL, nScrollCode, (LPARAM)NULL);
return TRUE;
}
//------------------------------------------------------------------------------
void OnSize(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
WORD wHeight = HIWORD(lParam);
int nPosMax;
switch (wParam) {
case SIZE_MAXHIDE:
case SIZE_MINIMIZED:
return;
}
// スクロール情報の更新
g.siVert.nPage = wHeight / LINE_HEIGHT;
nPosMax = g.siVert.nMax - g.siVert.nPage + 1;
if (nPosMax < 0) {
nPosMax = 0;
}
if (nPosMax < g.siVert.nPos) {
g.siVert.nPos = nPosMax;
}
SetScrollInfo(hWnd, SB_VERT, &g.siVert, TRUE);
}
//------------------------------------------------------------------------------
void OnDropFiles(HWND hWnd, WPARAM wParam)
{
HDROP hDrop = (HDROP)wParam;
UINT ur;
ur = DragQueryFile(hDrop, 0, g.szPath, _countof(g.szPath));
NewDocument(hWnd);
InvalidateRect(hWnd, NULL, TRUE);
}
//------------------------------------------------------------------------------
void OnCreate(HWND hWnd)
{
LOGFONT lf;
// スクロール情報の初期化
ZeroMemory(&g.siVert, sizeof g.siVert);
g.siVert.cbSize = sizeof g.siVert;
g.siVert.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_DISABLENOSCROLL;
SetScrollInfo(hWnd, SB_VERT, &g.siVert, FALSE);
// フォントの作成
ZeroMemory(&lf, sizeof lf);
lf.lfHeight = -LINE_HEIGHT;
_tcscpy_s(lf.lfFaceName, _T("MS ゴシック"));
g.hFont = CreateFontIndirect(&lf);
if (g.szPath[0]) {
NewDocument(hWnd);
}
}
//------------------------------------------------------------------------------
void OnDestroy(void)
{
DeleteObject(g.hFont);
}
//------------------------------------------------------------------------------
void NewDocument(HWND hWnd)
{
TCHAR szTitle[280];
RECT rc;
int nRowNum; // 行数
OpenMemMapFile(hWnd);
// タイトルの更新
_stprintf_s(szTitle, _T("%s - %s"), g.szPath, WINDOW_NAME);
SetWindowText(hWnd, szTitle);
GetClientRect(hWnd, &rc);
nRowNum = (g.dwFileSize + COL_LINE - 1) / COL_LINE;
// スクロール情報の更新
g.siVert.nMin = 0;
g.siVert.nMax = nRowNum - 1;
g.siVert.nPage = rc.bottom / LINE_HEIGHT;
g.siVert.nPos = 0;
SetScrollInfo(hWnd, SB_VERT, &g.siVert, TRUE);
}