www.pudn.com > Irp-Files.rar > hexview.c


#include  
#include "hexview.h" 
 
#define xmalloc(s)		HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (s)) 
#define xfree(p)		HeapFree(GetProcessHeap(), 0, (p)) 
#define MAX(a, b) ((a) > (b) ? (a) : (b)) 
#define MIN(a, b) ((a) < (b) ? (a) : (b)) 
 
#define EM_TEXT 0 
#define EM_HEX_HIGH 1 
#define EM_HEX_LOW 2 
#define GWL_HEXINFO 0 
#define WM_MOUSEWHEEL 0x020A 
 
#define HV_COLOR_DEFAULT 0 
#define HV_COLOR_RED 1 
#define HV_COLOR_SBGRAY 2 
#define HV_COLOR_GREEN 3 
#define HV_COLOR_BLUE 4 
 
typedef struct _HV_PRINTFMT 
{ 
	BYTE x; 
	BYTE y; 
	BYTE color : 7; 
	BYTE highlight : 1; 
	BYTE len; 
	BYTE data[]; 
} HV_PRINTFMT, *PHV_PRINTFMT; 
 
typedef struct _HV_MODIFYLOG 
{ 
	int nLog; 
	int nBack; 
	int nMaxUndoLog; 
	int nMaxRedoLog; 
	PBYTE pLog; 
	PBYTE pLogBuf; 
	DWORD nLogBufLen; 
	DWORD nMaxLogBuf; 
	PBYTE pOrgBuf; 
	DWORD nOrgBufLen; 
} HV_MODIFYLOG, *PHV_MODIFYLOG; 
 
typedef struct _HEXVIEW 
{ 
	BOOL TextOnly; 
	BOOL ReadOnly; 
	BOOL NoCursor; 
	PBYTE Buffer; 
	DWORD Length; 
	DWORD BaseAddress; 
	ULONG SelStart; 
	ULONG SelEnd; 
	DWORD PageOffset; 
	DWORD PageLength; 
	DWORD PageMaxLength; 
	UINT LineWidth; 
	UINT AddressWidth; 
	UINT CharWidth; 
	UINT CharHeight; 
	DWORD EditMode; 
	int Cursor; 
	HV_MODIFYLOG hv_modl; 
	DWORD color[10]; 
} HEXVIEW, *PHEXVIEW; 
 
void *HV_MemSearchR(void *m1, size_t n1, void *m2, size_t n2) 
{ 
	unsigned char *s1 = m1; 
	unsigned char *s2 = m2; 
	size_t i, index[256]; 
 
	if (n1 < n2) 
		return NULL; 
 
	if (n2 == 0) 
		return m1; 
 
	for (i = 0; i < 256; i++) 
		index[i] = n2 + 1; 
 
	for (i = 0; i < n2; i++) 
		index[s2[i]] = n2 - i; 
 
	do 
	{ 
		for (i = 0; s1[i] == s2[i]; i++) 
		{ 
			if (i == n2 - 1) 
				return s1; 
		} 
 
		s1 += index[s1[n2]]; 
	} while (s1 + n2 <= (char *)m1 + n1); 
 
	return NULL; 
} 
 
void *HV_MemSearchL(void *m1, size_t n1, void *m2, size_t n2) 
{ 
	unsigned char *s1 = m1; 
	unsigned char *s2 = m2; 
	size_t i, index[256]; 
 
	if (n1 < n2) 
		return NULL; 
 
	if (n2 == 0) 
		return m1; 
 
	for (i = 0; i < 256; i++) 
		index[i] = n2 + 1; 
 
	for (i = n2 - 1; i >= 0; i--) 
		index[s2[i]] = n2 - i; 
 
	do 
	{ 
		for (i = n2 - 1; s1[i] == s2[i]; i--) 
		{ 
			if (i == 0) 
				return s1; 
		} 
 
		s1 -= index[*(s1 - 1)]; 
	} while (s1 >= (char *)m1 + n2); 
 
	return NULL; 
} 
 
int HV_InitModifyLog(PHV_MODIFYLOG hv_modl, PBYTE pOrgBuf, DWORD pOrgLen) 
{ 
	hv_modl->nLog = 0; 
	hv_modl->nBack = 0; 
	hv_modl->nMaxUndoLog = 0; 
	hv_modl->nMaxRedoLog = 0; 
	hv_modl->pOrgBuf = pOrgBuf; 
	hv_modl->nOrgBufLen = pOrgLen; 
	hv_modl->nMaxLogBuf = 0x200000; 
	hv_modl->nLogBufLen = 0x8000; 
	hv_modl->pLogBuf = VirtualAlloc(NULL, hv_modl->nMaxLogBuf, MEM_RESERVE, PAGE_READWRITE); 
	hv_modl->pLog = hv_modl->pLogBuf; 
 
	if (hv_modl->pLogBuf == NULL) 
		return -1; 
 
	VirtualAlloc(hv_modl->pLogBuf, hv_modl->nLogBufLen, MEM_COMMIT, PAGE_READWRITE); 
 
	return 0; 
} 
 
int HV_AddModifyLog(PHV_MODIFYLOG hv_modl, DWORD offset, DWORD length, PBYTE pData) 
{//* 
	int n; 
	PBYTE p; 
	DWORD l; 
 
	if (hv_modl->nLog < 0) 
	{ 
		hv_modl->nBack += -hv_modl->nLog; 
		hv_modl->nMaxUndoLog -= -hv_modl->nLog; 
		hv_modl->nLog = 0; 
	} 
 
	p = hv_modl->pLog; 
	n = hv_modl->nLog; 
 
	for (; n > 0; n--) 
		p += *(PDWORD)p + sizeof(DWORD) + sizeof(DWORD); 
 
	if (hv_modl->nLogBufLen - (p - hv_modl->pLogBuf) < length + sizeof(DWORD) + sizeof(DWORD)) 
	{ 
		l = MAX(0x8000, length + sizeof(DWORD) + sizeof(DWORD)); 
		l = (l + 0x7fff) & ~0x7fff; 
 
		if (hv_modl->nLogBufLen + l > hv_modl->nMaxLogBuf) 
			return -1; 
 
		hv_modl->nLogBufLen += l; 
		VirtualAlloc(hv_modl->pLogBuf, hv_modl->nLogBufLen, MEM_COMMIT, PAGE_READWRITE); 
	} 
 
	*((PDWORD)p)++ = length; 
	*((PDWORD)p)++ = offset; 
	memcpy(p, pData, length); 
 
	hv_modl->nLog++; 
	hv_modl->nMaxRedoLog = hv_modl->nLog;//*/ 
 
	return 0; 
} 
 
int HV_GetModifyData(PHV_MODIFYLOG hv_modl, DWORD nStart, PBYTE pBuffer, DWORD nSize) 
{ 
	int n, x; 
	PBYTE pUndoLog = hv_modl->pLog; 
	PBYTE pRedoLog = hv_modl->pLog; 
	DWORD off, len; 
	DWORD nEnd = nStart + nSize; 
 
	if (hv_modl->nLog > hv_modl->nMaxRedoLog || hv_modl->nLog < hv_modl->nMaxUndoLog) 
		return -1; 
 
	x = MIN(hv_modl->nOrgBufLen - nStart, nSize); 
	memcpy(pBuffer, hv_modl->pOrgBuf + nStart, x);		//拷贝原始数据 
 
	for (n = 0; n < hv_modl->nBack; n++) 
	{ 
		len = *((PDWORD)pUndoLog - 1); 
		off = *((PDWORD)pUndoLog - 2); 
		pUndoLog -= len + sizeof(DWORD) + sizeof(DWORD); 
 
		if (off >= nStart && off < nEnd) 
		{ 
			int l = MIN(len, nSize - (off - nStart)); 
			memcpy(pBuffer + (off - nStart), pUndoLog, l); 
		} 
		else if (off >= nStart && off <= nEnd) 
		{ 
			int l = MIN(nEnd - off, len); 
			memcpy(pBuffer + off - nStart, pUndoLog, l); 
		} 
	} 
 
	if (hv_modl->nLog >= 0) 
	{ 
		for (n = 0; n < hv_modl->nLog; n++) 
		{ 
			len = *((PDWORD)pRedoLog)++; 
			off = *((PDWORD)pRedoLog)++; 
 
			if (off >= nStart && off < nEnd) 
			{ 
				int l = MIN(len, nSize - (off - nStart)); 
				memcpy(pBuffer + (off - nStart), pRedoLog, l); 
			} 
			else if (off >= nStart && off <= nEnd) 
			{ 
				int l = MIN(nEnd - off, len); 
				memcpy(pBuffer + off - nStart, pRedoLog, l); 
			} 
 
			pRedoLog += len; 
		} 
	} 
	else 
	{ 
		for (n = 0; n > hv_modl->nLog; n--) 
		{ 
			len = *((PDWORD)pUndoLog - 1); 
			off = *((PDWORD)pUndoLog - 2); 
			pUndoLog -= len + sizeof(DWORD) + sizeof(DWORD); 
 
			if (off >= nStart && off < nEnd) 
			{ 
				int l = MIN(len, nSize - (off - nStart)); 
				memcpy(pBuffer + (off - nStart), pUndoLog, l); 
			} 
			else if (off >= nStart && off <= nEnd) 
			{ 
				int l = MIN(nEnd - off, len); 
				memcpy(pBuffer + off - nStart, pUndoLog, l); 
			} 
		} 
	} 
 
	return x;//*/ 
} 
 
void HV_ApplyModifyLog(PHV_MODIFYLOG hv_modl, PBYTE pNewBuffer) 
{ 
	int i, j; 
	PBYTE pUndoLog = hv_modl->pLog; 
	PBYTE pRedoLog = hv_modl->pLog; 
 
	if (pNewBuffer) 
	{ 
		memcpy(pNewBuffer, hv_modl->pOrgBuf, hv_modl->nOrgBufLen); 
		hv_modl->pOrgBuf = pNewBuffer; 
	} 
 
	if (hv_modl->nLog == 0 && hv_modl->nBack == 0) 
		return; 
 
	for (i = 0; i < hv_modl->nBack; i++) 
	{ 
		DWORD len = *((PDWORD)pUndoLog - 1); 
		DWORD off = *((PDWORD)pUndoLog - 2); 
 
		pUndoLog -= sizeof(DWORD) + sizeof(DWORD) + len; 
 
		for (j = 0; (DWORD)j < len; j++) 
			hv_modl->pOrgBuf[off + j] = pUndoLog[j]; 
	} 
 
	if (hv_modl->nLog >= 0) 
	{ 
		for (i = 0 ; i < hv_modl->nLog; i++) 
		{ 
			DWORD len = *((PDWORD)pRedoLog)++; 
			DWORD off = *((PDWORD)pRedoLog)++; 
 
			for (j = 0; (DWORD)j < len; j++) 
			{ 
				pUndoLog[j] = hv_modl->pOrgBuf[off + j]; 
				hv_modl->pOrgBuf[off + j] = pRedoLog[j]; 
			} 
 
			pUndoLog += len; 
			pRedoLog += len; 
			*((PDWORD)pUndoLog)++ = off; 
			*((PDWORD)pUndoLog)++ = len; 
		} 
	} 
	else 
	{ 
		for (i = 0 ; i > hv_modl->nLog; i--) 
		{ 
			DWORD len = *--((PDWORD)pUndoLog); 
			DWORD off = *--((PDWORD)pUndoLog); 
 
			pUndoLog -= len; 
			pRedoLog -= len; 
 
			for (j = 0; (DWORD)j < len; j++) 
			{ 
				pRedoLog[j] = hv_modl->pOrgBuf[off + j]; 
				hv_modl->pOrgBuf[off + j] = pUndoLog[j]; 
			} 
 
			*--((PDWORD)pRedoLog) = off; 
			*--((PDWORD)pRedoLog) = len; 
		} 
	} 
 
	hv_modl->pLog = pUndoLog; 
	hv_modl->nMaxRedoLog -= hv_modl->nLog; 
	hv_modl->nMaxUndoLog += -hv_modl->nLog; 
	hv_modl->nLog = 0; 
	hv_modl->nBack = 0; 
} 
 
int HV_DelModifyLog(PHV_MODIFYLOG hv_modl) 
{ 
	if (hv_modl->nLog < 0) 
	{ 
		PBYTE p = hv_modl->pLog; 
		int i, j; 
 
		for (i = hv_modl->nLog; i < 0; i++) 
		{ 
			DWORD len = *((PDWORD)p - 1); 
			DWORD off = *((PDWORD)p - 2); 
 
			p -= sizeof(DWORD) + sizeof(DWORD) + len; 
 
			for (j = len; j > 0; j--) 
				p[sizeof(DWORD) + sizeof(DWORD) + j] = p[j]; 
 
			*((PDWORD)p + 0) = len; 
			*((PDWORD)p + 1) = off; 
		} 
 
		hv_modl->pLog = p; 
		hv_modl->nMaxRedoLog = -hv_modl->nLog; 
		hv_modl->nMaxUndoLog -= hv_modl->nLog; 
		hv_modl->nLog = 0; 
	} 
	else 
	{ 
		hv_modl->nMaxRedoLog = hv_modl->nLog; 
	} 
 
	return 0; 
} 
 
void HV_FreeModifyLog(PHV_MODIFYLOG hv_modl) 
{ 
	hv_modl->nLog = 0; 
	hv_modl->nBack = 0; 
	hv_modl->nMaxUndoLog = 0; 
	hv_modl->nMaxRedoLog = 0; 
	hv_modl->pLog = NULL; 
	hv_modl->pOrgBuf = NULL; 
	hv_modl->nOrgBufLen = 0; 
	hv_modl->nMaxLogBuf = 0; 
	hv_modl->nLogBufLen = 0; 
	VirtualFree(hv_modl->pLogBuf, 0, MEM_RELEASE); 
	hv_modl->pLogBuf = NULL; 
} 
 
void HV_ResetModifyLog(PHV_MODIFYLOG hv_modl, PBYTE pOrgBuf, DWORD pOrgLen) 
{ 
	hv_modl->nLog = 0; 
	hv_modl->nBack = 0; 
	hv_modl->nMaxUndoLog = 0; 
	hv_modl->nMaxRedoLog = 0; 
	hv_modl->pOrgBuf = pOrgBuf; 
	hv_modl->nOrgBufLen = pOrgLen; 
} 
 
int HV_LogUndo(HWND hWnd, BOOL bTest) 
{ 
	PHEXVIEW p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
	NMHDR n; 
 
	if (p->hv_modl.nLog > p->hv_modl.nMaxUndoLog) 
	{ 
		if (bTest == TRUE) 
			return 1; 
		else 
		{ 
			p->hv_modl.nLog--; 
			RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); 
			n.code = HV_EN_CHANGE; 
			n.idFrom = GetDlgCtrlID(hWnd); 
			n.hwndFrom = hWnd; 
			SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); 
			return 1; 
		} 
	} 
 
	return 0; 
} 
 
int HV_LogRedo(HWND hWnd, BOOL bTest) 
{ 
	PHEXVIEW p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
	NMHDR n; 
 
	if (p->hv_modl.nLog < p->hv_modl.nMaxRedoLog) 
	{ 
		if (bTest == TRUE) 
			return 1; 
		else 
		{ 
			p->hv_modl.nLog++; 
			RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); 
			n.code = HV_EN_CHANGE; 
			n.idFrom = GetDlgCtrlID(hWnd); 
			n.hwndFrom = hWnd; 
			SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); 
			return 1; 
		} 
	} 
 
	return 0; 
} 
 
int HV_Compare(PBYTE s1, PBYTE s2, int n) 
{ 
	int i = n; 
 
	if (*s1 == *s2) 
	{ 
		while (--n && *++s1 == *++s2); 
		return i - n; 
	} 
	else 
	{ 
		while (--n && *++s1 != *++s2); 
		return n - i; 
	} 
} 
 
void HV_FormatForPrint(int lineWidth, int maxLine, DWORD startAddr, PVOID allModify, PBYTE data, 
					   DWORD selStart, DWORD selEnd, PBYTE output) 
{ 
	PHV_PRINTFMT hv_pfmt; 
	PBYTE buf = output; 
	BYTE text[64 * 32]; 
	int i, j, k, l, w, dlen; 
	BOOL bModify, bHighLight; 
 
	lineWidth = MAX(lineWidth, 1); 
	lineWidth = MIN(lineWidth, 32); 
	maxLine = MAX(maxLine, 1); 
	maxLine = MIN(maxLine, 64); 
 
	dlen = HV_GetModifyData(allModify, startAddr, text, lineWidth * maxLine); 
 
	maxLine = dlen / lineWidth; 
	maxLine += (dlen % lineWidth) == 0 ? 0 : 1; 
	w = lineWidth; 
 
	for (i = 0; i < maxLine; i++) 
	{ 
		hv_pfmt = (PHV_PRINTFMT)buf;				//输出地址 
		hv_pfmt->x = 1; 
		hv_pfmt->y = i; 
		hv_pfmt->color = HV_COLOR_ADDR; 
		hv_pfmt->highlight = 0; 
		hv_pfmt->len = 8; 
		buf += sizeof(HV_PRINTFMT); 
 
		for (l = 3; l >= 0; l--) 
		{ 
			*buf++ = "0123456789ABCDEF"[(startAddr >> (l * 8 + 4)) & 15]; 
			*buf++ = "0123456789ABCDEF"[(startAddr >> (l * 8 + 0)) & 15]; 
		} 
 
		if (i == maxLine - 1) 
		{ 
			if (dlen % lineWidth) 
				w = dlen % lineWidth; 
		} 
 
		for (j = 0; j < w; j += k) 
		{ 
			k = HV_Compare(data + startAddr + j, text + i * lineWidth + j, w - j); 
 
			if (k > 0) 
			{ 
				bModify = FALSE; 
			} 
			else 
			{ 
				bModify = TRUE; 
				k = -k; 
			} 
 
			bHighLight = FALSE; 
 
			if (selEnd != -1) 
			{ 
				if (j + startAddr < selStart) 
				{ 
					k = MIN((DWORD)k, selStart - (j + startAddr)); 
					bHighLight = FALSE; 
				} 
				else if ((DWORD)j + startAddr == selStart) 
				{ 
					k = MIN((DWORD)k, selEnd - (j + startAddr) + 1); 
					bHighLight = TRUE; 
				} 
				else if ((DWORD)j + startAddr <= selEnd) 
				{ 
					k = MIN((DWORD)k, selEnd - (j + startAddr) + 1); 
					bHighLight = TRUE; 
				} 
			} 
 
			hv_pfmt = (PHV_PRINTFMT)buf;				//输出十六进制 
			hv_pfmt->x = (1 + 8 + 1 + j * 3); 
			hv_pfmt->y = i; 
			hv_pfmt->color = bModify ? HV_COLOR_MODIFY : HV_COLOR_HEX; 
			hv_pfmt->highlight = bHighLight ? 1 : 0; 
			hv_pfmt->len = k * 3; 
			buf += sizeof(HV_PRINTFMT); 
 
			for (l = 0; l < k; l++) 
			{ 
				*buf++ = "0123456789ABCDEF"[(text[i * lineWidth + j + l] >> 4) & 15]; 
				*buf++ = "0123456789ABCDEF"[(text[i * lineWidth + j + l] >> 0) & 15]; 
				*buf++ = ' '; 
			} 
 
			if (j + k >= lineWidth - 1 || (bHighLight && j + startAddr + k == selEnd + 1)) 
			{ 
				hv_pfmt->len -= 1; 
				buf--; 
			} 
 
			hv_pfmt = (PHV_PRINTFMT)buf;				//输出文本 
			hv_pfmt->x = (1 + 8 + lineWidth * 3 + 4 + j); 
			hv_pfmt->y = i; 
			hv_pfmt->color = bModify ? HV_COLOR_MODIFY : HV_COLOR_TEXT; 
			hv_pfmt->highlight = bHighLight ? 1 : 0; 
			hv_pfmt->len = k; 
			buf += sizeof(HV_PRINTFMT) + hv_pfmt->len; 
 
			for (l = 0; l < k; l++) 
				hv_pfmt->data[l] = text[i * lineWidth + j + l] < 0x20 ? '.' : text[i * lineWidth + j + l]; 
		} 
 
		startAddr += lineWidth; 
	} 
 
	hv_pfmt = (PHV_PRINTFMT)buf;				//输出结束 
	hv_pfmt->x = 0; 
	hv_pfmt->y = 0; 
	hv_pfmt->color = 0; 
	hv_pfmt->len = 0; 
} 
 
VOID HV_PrintHexView(HDC hDC, PHEXVIEW pHex, DWORD nWidth, DWORD nHeight) 
{ 
	TCHAR HexTitle[] = " OFFSET   0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F "; 
	HFONT hFont, hOldFont; 
	HBRUSH hbr; 
	PHV_PRINTFMT hv_pfmt; 
	DWORD lastBgColor = -1, lastColor = -1; 
	UINT nCharWidth, nCharHeight; 
	PVOID fmt; 
	RECT rc; 
	LONG SelStart, SelEnd; 
 
	hFont = CreateFont(-12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Courier New"); 
	hOldFont = SelectObject(hDC, hFont); 
 
	nCharWidth = pHex->CharWidth; 
	nCharHeight = pHex->CharHeight; 
 
	rc.top = 0; 
	rc.left = 0; 
	rc.bottom = nHeight; 
	rc.right = nWidth; 
 
	hbr = CreateSolidBrush(pHex->color[HV_COLOR_BG0]); 
	FillRect(hDC, &rc, hbr); 
	DeleteObject(hbr); 
 
	SetBkColor(hDC, RGB(0, 255, 255)); 
	TextOut(hDC, nCharWidth, 0, HexTitle, 9 + pHex->LineWidth * 3); 
 
	fmt = VirtualAlloc(NULL, 0x5000, MEM_COMMIT, PAGE_READWRITE); 
 
	if (fmt == NULL)  
		return; 
 
	SelStart = MIN(pHex->SelStart, pHex->SelEnd); 
	SelEnd = MAX(pHex->SelStart, pHex->SelEnd); 
 
	HV_FormatForPrint(	pHex->LineWidth, 
						nHeight / nCharHeight - 1, 
						pHex->PageOffset, 
						&pHex->hv_modl, 
						pHex->Buffer, 
						SelStart, 
						SelEnd, 
						fmt); 
 
	do 
	{ 
		hv_pfmt = (PHV_PRINTFMT)fmt; 
		(PBYTE)fmt += sizeof(HV_PRINTFMT) + hv_pfmt->len; 
 
		if (hv_pfmt->len == 0) 
			break; 
 
		if (pHex->color[hv_pfmt->color] != lastColor) 
		{ 
			SetTextColor(hDC, pHex->color[hv_pfmt->color]); 
			lastColor = pHex->color[hv_pfmt->color]; 
		} 
 
		if (pHex->color[hv_pfmt->highlight] != lastBgColor) 
		{ 
			SetBkColor(hDC, pHex->color[hv_pfmt->highlight]); 
			lastBgColor = pHex->color[hv_pfmt->highlight]; 
		} 
 
		TextOut(	hDC, 
					hv_pfmt->x * nCharWidth, 
					hv_pfmt->y * nCharHeight + nCharHeight, 
					hv_pfmt->data, 
					hv_pfmt->len); 
	} while (1); 
 
	VirtualFree(fmt, 0, MEM_RELEASE); 
	SelectObject(hDC, hOldFont); 
	DeleteObject(hFont); 
} 
 
ULONG HV_GetCurrentCursor(PHEXVIEW pHex, short x, short y, PDWORD pEditMode) 
{ 
	UINT nCharWidth, nCharHeight; 
	int lenHex, lenAscii; 
	int bx, by, mx, my, middle; 
	DWORD dwEditMode; 
 
	nCharWidth = pHex->CharWidth; 
	nCharHeight = pHex->CharHeight; 
 
	bx = x / (int)nCharWidth; 
	by = y / (int)nCharHeight - 1; 
	bx -= pHex->AddressWidth * 2 + 2; 
 
	middle = pHex->LineWidth * 3 + 1; 
	lenHex = pHex->LineWidth * 3 - 1; 
	lenAscii = pHex->LineWidth; 
 
	mx = pHex->PageLength % pHex->LineWidth; 
	my = pHex->PageLength / pHex->LineWidth; 
	mx = pHex->LineWidth - mx; 
 
	if (by < 0) 
		by = 0; 
 
	if (by > my) 
		by = my; 
 
	if (mx != 0 && by == my) 
	{ 
		lenHex -= mx * 3; 
		lenAscii -= mx; 
	} 
 
	if (bx >= middle) 
	{ 
		bx -= middle + 2; 
 
		if (bx < 0) 
		{ 
			bx = 0; 
		} 
		else if (bx >= lenAscii) 
		{ 
			bx = lenAscii - 1; 
		} 
 
		dwEditMode = EM_TEXT; 
	} 
	else 
	{ 
		if (bx < 0) 
		{ 
			bx = 0; 
		} 
 
		if ((bx + 1) % 3 == 0) 
		{ 
			if (x % nCharWidth < nCharWidth / 2) 
			{ 
				bx--; 
			} 
			else 
			{ 
				bx++; 
			} 
		} 
 
		if (bx >= lenHex) 
		{ 
			bx = lenHex - 1; 
		} 
 
		if ((bx + 1) % 3 == 1) 
			dwEditMode = EM_HEX_HIGH; 
		else 
			dwEditMode = EM_HEX_LOW; 
 
		bx = (bx + 1) / 3; 
	} 
 
	if (pEditMode != NULL) 
		*pEditMode = dwEditMode; 
 
	return bx + by * pHex->LineWidth + pHex->PageOffset; 
} 
 
VOID HV_OnPaint(HWND hWnd) 
{ 
	UINT nWndWidth, nWndHeight; 
	HDC hDC, hMemDC; 
	HBITMAP hBitmap; 
	RECT rect; 
	PAINTSTRUCT ps; 
 
	GetClientRect(hWnd, &rect); 
	nWndWidth = rect.right - rect.left; 
	nWndHeight = rect.bottom - rect.top; 
 
	hDC = BeginPaint(hWnd, &ps); 
	hMemDC = CreateCompatibleDC(hDC); 
	hBitmap = CreateCompatibleBitmap(hDC, nWndWidth, nWndHeight); 
	SelectObject(hMemDC, hBitmap); 
 
	HV_PrintHexView(	hMemDC, 
						(PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO), 
						nWndWidth, 
						nWndHeight); 
 
	BitBlt(hDC, 0, 0, nWndWidth, nWndHeight, hMemDC, 0, 0, SRCCOPY); 
 
	DeleteDC(hMemDC); 
	DeleteObject(hBitmap); 
	EndPaint(hWnd, &ps); 
} 
 
int HV_MoveCursor(PHEXVIEW pHex, int lx, int ly) 
{ 
	if (lx != 0) 
	{ 
		switch (pHex->EditMode) 
		{ 
		case EM_TEXT: 
			pHex->Cursor += lx; 
			break; 
 
		case EM_HEX_HIGH: 
			if (lx > 0) 
			{ 
				pHex->EditMode = lx & 1 ? EM_HEX_LOW : EM_HEX_HIGH; 
				pHex->Cursor += lx / 2; 
			} 
			else 
			{ 
				pHex->EditMode = lx & 1 ? EM_HEX_LOW : EM_HEX_HIGH; 
				pHex->Cursor += (lx - 1) / 2; 
			} 
			break; 
 
		case EM_HEX_LOW: 
			if (lx > 0) 
			{ 
				pHex->EditMode = lx & 1 ? EM_HEX_HIGH : EM_HEX_LOW; 
				pHex->Cursor += (lx + 1) / 2; 
			} 
			else 
			{ 
				pHex->EditMode = lx & 1 ? EM_HEX_HIGH : EM_HEX_LOW; 
				pHex->Cursor += lx / 2; 
			} 
			break; 
		} 
	} 
 
	pHex->Cursor += ly * pHex->LineWidth; 
 
	if (pHex->Cursor >= (int)(pHex->Length)) 
	{ 
		pHex->Cursor = pHex->Length - 1; 
		pHex->EditMode = pHex->EditMode == EM_TEXT ? EM_TEXT : EM_HEX_LOW; 
	} 
	else if (pHex->Cursor < 0) 
	{ 
		pHex->Cursor = 0; 
		pHex->EditMode = pHex->EditMode == EM_TEXT ? EM_TEXT : EM_HEX_HIGH; 
	} 
 
	if (pHex->Cursor >= (int)(pHex->PageOffset + pHex->PageLength)) 
	{ 
		int n = pHex->Cursor / pHex->LineWidth; 
		n -= pHex->PageMaxLength / pHex->LineWidth - 1; 
		pHex->PageOffset = n * pHex->LineWidth; 
		pHex->PageLength = MIN(pHex->PageMaxLength, pHex->Length - pHex->PageOffset); 
		return n; 
	} 
	else if (pHex->Cursor < (int)pHex->PageOffset) 
	{ 
		int n = pHex->Cursor / pHex->LineWidth; 
		pHex->PageOffset = n * pHex->LineWidth; 
		pHex->PageLength = MIN(pHex->PageMaxLength, pHex->Length - pHex->PageOffset); 
		return n; 
	} 
 
	return -1; 
} 
 
VOID HV_UpdatePage(HWND hWnd, int n) 
{ 
	SCROLLINFO si; 
 
	if (n != -1) 
	{ 
		si.cbSize = sizeof(SCROLLINFO); 
		si.fMask = SIF_POS; 
		SetScrollPos(hWnd, SB_VERT, n, TRUE); 
	} 
 
	RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); 
} 
 
VOID HV_OnChar(HWND hWnd, WPARAM wParam) 
{ 
	char ch = (char)wParam, ch1; 
	PHEXVIEW pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
	DWORD off = pHex->Cursor; 
	int i; 
	NMHDR n; 
 
	if (pHex->EditMode == EM_TEXT) 
	{ 
		HV_AddModifyLog(&pHex->hv_modl, off, 1, &ch); 
		i = HV_MoveCursor(pHex, 1, 0); 
		HV_UpdatePage(hWnd, i); 
	} 
	else 
	{ 
		switch (ch = toupper(ch)) 
		{ 
		case '0': 
		case '1': 
		case '2': 
		case '3': 
		case '4': 
		case '5': 
		case '6': 
		case '7': 
		case '8': 
		case '9': 
			ch -= '0'; 
			break; 
		case 'A': 
		case 'B': 
		case 'C': 
		case 'D': 
		case 'E': 
		case 'F': 
			ch -= 'A' - 0x0a; 
			break; 
		default: 
			return; 
		} 
 
		HV_GetModifyData(&pHex->hv_modl, off, &ch1, 1); 
 
		if (pHex->EditMode != EM_HEX_HIGH) 
		{ 
			if (ch != (ch1 & 0x0f)) 
			{ 
				ch |= ch1 & 0xf0; 
				HV_AddModifyLog(&pHex->hv_modl, off, 1, &ch); 
			} 
		} 
		else 
		{ 
			ch <<= 4; 
			if (ch != (ch1 & 0xf0)) 
			{ 
				ch |= ch1 & 0x0f; 
				HV_AddModifyLog(&pHex->hv_modl, off, 1, &ch); 
			} 
		} 
 
		i = HV_MoveCursor(pHex, 1, 0); 
		HV_UpdatePage(hWnd, i); 
	} 
	RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); 
 
	n.code = HV_EN_CHANGE; 
	n.idFrom = GetDlgCtrlID(hWnd); 
	n.hwndFrom = hWnd; 
	SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); 
} 
 
VOID CALLBACK HV_TimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime) 
{ 
	int t, x, y, w, h; 
	HDC hDC; 
	PHEXVIEW pHex; 
 
	pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
 
	w = pHex->CharWidth; 
	h = pHex->CharHeight; 
 
	if (pHex->NoCursor == TRUE) 
		return; 
 
	t = pHex->Cursor - pHex->PageOffset; 
 
	if (t < 0 || t >= (int)pHex->PageLength) 
		return; 
 
	switch (pHex->EditMode) 
	{ 
	case EM_TEXT: 
		x = t % pHex->LineWidth; 
		x += pHex->AddressWidth * 2 + pHex->LineWidth * 3 + 3 + 2; 
		break; 
 
	case EM_HEX_HIGH: 
		x = t % pHex->LineWidth * 3; 
		x += pHex->AddressWidth * 2 + 2; 
		break; 
 
	case EM_HEX_LOW: 
		x = t % pHex->LineWidth * 3 + 1; 
		x += pHex->AddressWidth * 2 + 2; 
		break; 
	} 
 
	x *= pHex->CharWidth; 
	y = (t / pHex->LineWidth + 1) * pHex->CharHeight; 
 
	hDC = GetDC(hWnd); 
	BitBlt(hDC, x, y, w, h, NULL, 0, 0, DSTINVERT); 
	ReleaseDC(hWnd, hDC); 
} 
 
VOID HV_LButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam) 
{ 
	PHEXVIEW pHex; 
	ULONG i; 
	NMHDR n; 
 
	pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
	i = HV_GetCurrentCursor(pHex, LOWORD(lParam), HIWORD(lParam), &pHex->EditMode); 
 
	pHex->SelStart = i; 
	pHex->SelEnd = -1; 
	pHex->Cursor = i; 
	RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); 
 
	n.code = HV_EN_SELCHANGE; 
	n.idFrom = GetDlgCtrlID(hWnd); 
	n.hwndFrom = hWnd; 
	SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); 
} 
 
VOID HV_OnVscroll(HWND hWnd, WPARAM wParam, LPARAM lParam) 
{ 
	PHEXVIEW pHex; 
	int i; 
	SCROLLINFO si; 
 
	si.cbSize = sizeof(SCROLLINFO); 
	si.fMask = SIF_ALL; 
	GetScrollInfo(hWnd, SB_VERT, &si); 
 
	pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
 
	switch (LOWORD(wParam)) 
	{ 
	case SB_LINEUP: 
		i = si.nPos - 1; 
		break; 
	case SB_LINEDOWN: 
		i = si.nPos + 1; 
		break; 
	case SB_PAGEUP: 
		i = si.nPos - si.nPage; 
		break; 
	case SB_PAGEDOWN: 
		i = si.nPos + si.nPage; 
		break; 
	case SB_THUMBPOSITION: 
	case SB_THUMBTRACK: 
		i = HIWORD(wParam); 
		break; 
	default: 
		return; 
	} 
 
	i = MAX(i, si.nMin); 
	i = MIN(i, MAX(0, (int)(si.nMax - si.nPage + 1))); 
 
	pHex->PageOffset = pHex->LineWidth * i; 
	pHex->PageLength = MIN(pHex->Length - pHex->PageOffset, pHex->PageMaxLength); 
	SetScrollPos(hWnd, SB_VERT, i, TRUE); 
	RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); 
} 
 
VOID HV_OnKeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam) 
{ 
	PHEXVIEW pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
	int i; 
	NMHDR n; 
 
	if (pHex->NoCursor == TRUE) 
	{ 
		switch ((TCHAR)wParam) 
		{ 
		case VK_UP: 
			if (pHex->PageOffset > 0) 
				pHex->PageOffset -= pHex->LineWidth; 
			break; 
		case VK_DOWN: 
			if (pHex->PageLength >= pHex->LineWidth) 
				pHex->PageOffset += pHex->LineWidth; 
			break; 
		} 
		RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); 
	} 
	else 
	{ 
		switch ((TCHAR)wParam) 
		{ 
		case VK_UP: 
			i = HV_MoveCursor(pHex, 0, -1); 
			break; 
		case VK_DOWN: 
			i = HV_MoveCursor(pHex, 0, 1); 
			break; 
		case VK_LEFT: 
			i = HV_MoveCursor(pHex, -1, 0); 
			break; 
		case VK_RIGHT: 
			i = HV_MoveCursor(pHex, 1, 0); 
			break; 
		default: 
			return; 
		} 
 
		pHex->SelEnd = -1; 
		HV_UpdatePage(hWnd, i); 
 
		n.code = HV_EN_SELCHANGE; 
		n.idFrom = GetDlgCtrlID(hWnd); 
		n.hwndFrom = hWnd; 
		SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); 
	} 
} 
 
VOID HV_MouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam) 
{ 
	PHEXVIEW pHex; 
	ULONG i; 
	INT TopPos, BottomPos; 
	NMHDR n; 
 
	if (wParam & MK_LBUTTON) 
	{ 
		pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
		TopPos = pHex->CharHeight; 
		BottomPos = (pHex->PageMaxLength / pHex->LineWidth) * pHex->CharHeight; 
 
		if ((short)HIWORD(lParam) < TopPos) 
		{ 
			HV_OnVscroll(hWnd, SB_LINEUP, 0); 
			//SendMessage(hWnd, WM_MOUSEMOVE, wParam, lParam); 
		} 
 
		if ((short)HIWORD(lParam) >= BottomPos) 
		{ 
			HV_OnVscroll(hWnd, SB_LINEDOWN, 0); 
			//SendMessage(hWnd, WM_MOUSEMOVE, wParam, lParam); 
		} 
 
		i = HV_GetCurrentCursor(pHex, LOWORD(lParam), HIWORD(lParam), NULL); 
		pHex->SelEnd = i; 
		pHex->Cursor = i; 
		RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); 
 
		n.code = HV_EN_SELCHANGE; 
		n.idFrom = GetDlgCtrlID(hWnd); 
		n.hwndFrom = hWnd; 
		SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); 
	} 
} 
 
VOID HV_ResetSize(HWND hWnd) 
{ 
	HDC hDC; 
	HFONT hFont, hOldFont; 
	SIZE charSize; 
	RECT rect; 
	UINT nWndHeight; 
	PHEXVIEW pHex; 
	SCROLLINFO si; 
 
	pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
	hFont = CreateFont(-12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Courier New"); 
	hDC = GetDC(hWnd); 
	hOldFont = SelectObject(hDC, hFont); 
 
	GetTextExtentPoint32(hDC, "0", 1, &charSize); 
	pHex->CharWidth = charSize.cx; 
	pHex->CharHeight = charSize.cy; 
 
	SelectObject(hDC, hOldFont); 
	DeleteObject(hFont); 
	ReleaseDC(hWnd, hDC); 
 
	GetClientRect(hWnd, &rect); 
	nWndHeight = rect.bottom - rect.top; 
 
	pHex->PageMaxLength = (nWndHeight / pHex->CharHeight - 1) * pHex->LineWidth; 
	pHex->PageLength = MIN(pHex->Length - pHex->PageOffset, pHex->PageMaxLength); 
 
	si.cbSize = sizeof(SCROLLINFO); 
	si.fMask = SIF_ALL; 
	si.nMin = 0; 
	si.nMax = pHex->Length / pHex->LineWidth +  
		(pHex->Length % pHex->LineWidth == 0 ? 0 : 1); 
	si.nPage = pHex->PageMaxLength / pHex->LineWidth + 1; 
	si.nPos = 0; 
	SetScrollInfo(hWnd, SB_VERT, &si, TRUE); 
 
	if (pHex->Length > pHex->PageMaxLength) 
	{ 
		EnableScrollBar(hWnd, SB_VERT, ESB_ENABLE_BOTH); 
	} 
	else 
	{ 
		EnableScrollBar(hWnd, SB_VERT, ESB_DISABLE_BOTH); 
	} 
} 
 
int HV_FindText(HWND hWnd, PHV_FIND hv_find) 
{ 
	PBYTE p1, p2, pp; 
	DWORD i, n, count; 
	PHEXVIEW pHex = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
	NMHDR nm; 
 
	if (hv_find->nLen > 0x8000) 
		return -1; 
 
	if (pHex->Length == 0) 
		return -1; 
 
	if (hv_find->dwFlags & ~HV_FIND_MATCHCASE) 
	{ 
		n = MIN(pHex->Length, 0x10000); 
 
		p1 = VirtualAlloc(	NULL, 
							n + hv_find->nLen, 
							MEM_COMMIT, 
							PAGE_READWRITE); 
 
		if (p1 == NULL) 
			return -1; 
 
		p2 = p1 + n; 
		pp = hv_find->pMem; 
 
		for (i = 0; i < hv_find->nLen; i++) 
		{ 
			if (pp[i] >= 'a' && pp[i] <= 'z') 
				p2[i] = pp[i] - 'a' + 'A'; 
			else 
				p2[i] = pp[i]; 
		} 
	} 
	else 
	{ 
		n = MIN(pHex->Length, 0x10000); 
 
		p1 = VirtualAlloc(	NULL, 
							n, 
							MEM_COMMIT, 
							PAGE_READWRITE); 
 
		if (p1 == NULL) 
			return -1; 
 
		p2 = hv_find->pMem; 
	} 
 
 
	for (count = hv_find->cpMin;;) 
	{ 
		n = MIN(pHex->Length - count, 0x10000); 
		HV_GetModifyData(&pHex->hv_modl, count, p1, n); 
 
		if (hv_find->dwFlags & ~HV_FIND_MATCHCASE) 
		{ 
			for (i = 0; i < n; i++) 
			{ 
				if (p1[i] >= 'a' && p1[i] <= 'z') 
					p1[i] -= 'a' - 'A'; 
			} 
		} 
 
		pp = HV_MemSearchR(p1, n, p2, hv_find->nLen); 
 
		if (pp != NULL) 
		{ 
			n = pp - p1 + count; 
			pHex->SelStart = n; 
			pHex->SelEnd = n + hv_find->nLen - 1; 
			pHex->Cursor = n; 
 
			if (n >= pHex->PageOffset + pHex->PageLength) 
			{ 
				n /= pHex->LineWidth; 
				n -= pHex->PageMaxLength / pHex->LineWidth - 1; 
				pHex->PageOffset = n * pHex->LineWidth; 
				pHex->PageLength = MIN(pHex->PageMaxLength, pHex->Length - pHex->PageOffset); 
				HV_UpdatePage(hWnd, n); 
			} 
			else if (n < pHex->PageOffset) 
			{ 
				n /= pHex->LineWidth; 
				pHex->PageOffset = n * pHex->LineWidth; 
				pHex->PageLength = MIN(pHex->PageMaxLength, pHex->Length - pHex->PageOffset); 
				HV_UpdatePage(hWnd, n); 
			} 
 
			nm.code = HV_EN_SELCHANGE; 
			nm.idFrom = GetDlgCtrlID(hWnd); 
			nm.hwndFrom = hWnd; 
			SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&nm); 
			break; 
		} 
 
		if (pHex->Length - i > 0x10000) 
		{ 
			i += 0x10000 - hv_find->nLen; 
		} 
		else 
			break; 
	} 
 
	VirtualFree(p1, 0, MEM_RELEASE); 
 
	return 0; 
} 
 
LRESULT CALLBACK HV_HexViewProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
	PHEXVIEW p; 
	HGLOBAL hGlobal; 
	PBYTE pGlobal, pSource; 
	LONG i, SelLength, MemSize; 
	NMHDR n; 
 
	switch (uMsg) 
	{ 
	case WM_MOUSEMOVE: 
		HV_MouseMove(hWnd, wParam, lParam); 
		break; 
 
	case WM_LBUTTONDOWN: 
		SetCapture(hWnd); 
		SetFocus(hWnd); 
		HV_LButtonDown(hWnd, wParam, lParam); 
		break; 
 
	case WM_LBUTTONUP: 
		ReleaseCapture(); 
		break; 
 
	case WM_VSCROLL: 
		HV_OnVscroll(hWnd, wParam, lParam); 
		break; 
 
	case WM_MOUSEWHEEL: 
		if ((short)HIWORD(wParam) > 0) 
		{ 
			HV_OnVscroll(hWnd, SB_LINEUP, 0); 
		} 
		else 
		{ 
			HV_OnVscroll(hWnd, SB_LINEDOWN, 0); 
		} 
		break; 
 
	case WM_PAINT: 
		HV_OnPaint(hWnd); 
		break; 
 
	case WM_CHAR: 
		HV_OnChar(hWnd, wParam); 
		break; 
 
	case WM_KEYDOWN: 
		HV_OnKeyDown(hWnd, wParam, lParam); 
		break; 
 
	case WM_SETFOCUS: 
		SetTimer(hWnd, WM_TIMER, 500, HV_TimerProc); 
		break; 
 
	case WM_KILLFOCUS: 
		KillTimer(hWnd, WM_TIMER); 
		RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); 
		break; 
 
	case WM_SIZE: 
		HV_ResetSize(hWnd); 
		break; 
 
	case HV_SETHANDLE: 
		if ((ULONG)wParam < 512 * 1024 * 1024) 
		{ 
			p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
			p->Buffer = (LPSTR)lParam; 
			p->Length = (ULONG)wParam; 
			p->PageOffset = 0; 
			p->SelEnd = -1; 
			p->Cursor = 0; 
			p->EditMode = EM_HEX_HIGH; 
			HV_ResetModifyLog(&p->hv_modl, p->Buffer, p->Length); 
			HV_AddModifyLog(&p->hv_modl, 39, 3, "324"); 
			HV_AddModifyLog(&p->hv_modl, 41, 7, "abcdefg"); 
			HV_AddModifyLog(&p->hv_modl, 22, 14, "happy new year"); 
			p->hv_modl.nLog = 0; 
			HV_ResetSize(hWnd); 
			RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); 
 
			n.code = HV_EN_CHANGE; 
			n.idFrom = GetDlgCtrlID(hWnd); 
			n.hwndFrom = hWnd; 
			SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); 
			n.code = HV_EN_SELCHANGE; 
			SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); 
		} 
		break; 
 
	case HV_CANUNDO: 
		return HV_LogUndo(hWnd, TRUE); 
 
	case HV_CANREDO: 
		return HV_LogRedo(hWnd, TRUE); 
 
	case HV_UNDO: 
		return HV_LogUndo(hWnd, FALSE); 
 
	case HV_REDO: 
		return HV_LogRedo(hWnd, FALSE); 
 
	case HV_GETSEL: 
		p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
		*(DWORD *)wParam = p->SelStart; 
		*(DWORD *)lParam = p->SelEnd; 
		break; 
 
	case HV_SETSEL: 
		p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
		p->SelStart = (DWORD)wParam; 
		p->SelEnd = (DWORD)lParam; 
		RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); 
 
		n.code = HV_EN_SELCHANGE; 
		n.idFrom = GetDlgCtrlID(hWnd); 
		n.hwndFrom = hWnd; 
		SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); 
		break; 
 
	case HV_SELALL: 
		p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
		p->SelStart = 0; 
		p->SelEnd = p->Length; 
		p->Cursor = (p->Length << 1) - 1; 
		RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); 
 
		n.code = HV_EN_SELCHANGE; 
		n.idFrom = GetDlgCtrlID(hWnd); 
		n.hwndFrom = hWnd; 
		SendMessage(GetParent(hWnd), WM_NOTIFY, GetDlgCtrlID(hWnd), (LPARAM)&n); 
		break; 
 
	case HV_COPY: 
		p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
		SelLength = p->SelEnd - p->SelStart; 
		SelLength = MAX(SelLength, -SelLength) + 1; 
 
		hGlobal = GlobalAlloc(GHND | GMEM_SHARE, SelLength + 1); 
		if (hGlobal == NULL) 
			break; 
		pGlobal = GlobalLock(hGlobal); 
		pSource = p->Buffer + MIN(p->SelEnd, p->SelStart); 
		strncpy(pGlobal, pSource, SelLength); 
		GlobalUnlock(hGlobal); 
 
		OpenClipboard(hWnd); 
		EmptyClipboard(); 
		SetClipboardData(CF_TEXT, hGlobal); 
		CloseClipboard(); 
		break; 
 
	case HV_COPYHEX: 
		p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
		SelLength = p->SelEnd - p->SelStart; 
		SelLength = MAX(SelLength, -SelLength) + 1; 
		MemSize = SelLength * 3 + SelLength / 16; 
 
		hGlobal = GlobalAlloc(GHND | GMEM_SHARE, MemSize + 1); 
		if (hGlobal == NULL) 
			break; 
		pGlobal = GlobalLock(hGlobal); 
		pSource = p->Buffer + MIN(p->SelEnd, p->SelStart); 
 
		for (i = 0; i < SelLength;) 
		{ 
			*pGlobal++ = "0123456789ABCDEF"[pSource[i] >> 4]; 
			*pGlobal++ = "0123456789ABCDEF"[pSource[i] & 15]; 
			*pGlobal++ = ' '; 
 
			if (!(++i & 15)) 
			{ 
				*(pGlobal - 1) = '\r'; 
				*pGlobal++ = '\n'; 
			} 
		} 
		*pGlobal = '\0'; 
		GlobalUnlock(hGlobal); 
 
		OpenClipboard(hWnd); 
		EmptyClipboard(); 
		SetClipboardData(CF_TEXT, hGlobal); 
		CloseClipboard(); 
		break; 
 
	case HV_SETCOLOR: 
		if ((DWORD)wParam < 10) 
		{ 
			p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
			p->color[(DWORD)wParam] = lParam; 
			RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); 
		} 
		break; 
 
	case HV_APPLYMODIFY: 
		p = (PHEXVIEW)GetWindowLong(hWnd, GWL_HEXINFO); 
		HV_ApplyModifyLog(&p->hv_modl, (PBYTE)lParam); 
		if ((PBYTE)lParam != NULL) p->Buffer = (PBYTE)lParam; 
		RedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE); 
		break; 
 
	case HV_FINDTEXT: 
		HV_FindText(hWnd, (PHV_FIND)lParam); 
		break; 
 
	case WM_CREATE: 
		p = xmalloc(sizeof(HEXVIEW)); 
		p->NoCursor = FALSE; 
		p->ReadOnly = TRUE; 
		p->BaseAddress = 0; 
		p->PageOffset = 0; 
		p->Length = 0; 
		p->Buffer = NULL; 
		p->AddressWidth = 4; 
		p->LineWidth = 16; 
		p->SelStart = 0; 
		p->SelEnd = -1; 
		p->color[HV_COLOR_BG0] = RGB(255, 255, 255); 
		p->color[HV_COLOR_BG1] = RGB(192, 192, 192); 
		p->color[HV_COLOR_ADDR] = RGB(0, 0, 255); 
		p->color[HV_COLOR_HEX] = RGB(0, 0, 0); 
		p->color[HV_COLOR_TEXT] = RGB(0, 0, 0); 
		p->color[HV_COLOR_MODIFY] = RGB(255, 0, 0); 
		SetWindowLong(hWnd, GWL_HEXINFO, (LONG)p); 
		HV_ResetSize(hWnd); 
		HV_InitModifyLog(&p->hv_modl, p->Buffer, p->Length); 
		break; 
 
	case WM_DESTROY: 
		p = (void *)GetWindowLong(hWnd, GWL_HEXINFO); 
		HV_FreeModifyLog(&p->hv_modl); 
		xfree(p); 
		break; 
 
	default: 
		return DefWindowProc(hWnd, uMsg, wParam, lParam); 
	} 
 
	return 0; 
} 
 
BOOL InitHexViewClass(VOID) 
{ 
	LPSTR lpClass = "HexView"; 
	WNDCLASS wc; 
	HINSTANCE hInstance; 
 
	hInstance = GetModuleHandle(NULL); 
 
	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; 
	wc.lpfnWndProc		= (WNDPROC)HV_HexViewProc; 
	wc.cbClsExtra		= 0; 
	wc.cbWndExtra		= sizeof(void *); 
	wc.hInstance		= hInstance; 
	wc.hIcon			= NULL; 
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW); 
	wc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH); 
	wc.lpszMenuName		= NULL; 
	wc.lpszClassName	= lpClass; 
 
	if (!RegisterClass(&wc)) 
	{ 
		if (!GetClassInfo(hInstance, lpClass, &wc)) 
			return FALSE; 
		if (wc.lpfnWndProc != (WNDPROC)HV_HexViewProc) 
			return FALSE; 
	} 
 
	return TRUE; 
}