KOR세상

[카테고리:] 소프트웨어 개발

  • 파일 해시섬 프로그램 소스코드

    파일 해시섬 프로그램 소개 페이지

    WndProcs.h

    #ifndef _WNDPROCS_H_
    #define _WNDPROCS_H_
    #include <Windows.h>
    #include <gdiplus.h>
    #include <commctrl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    #include <wincrypt.h>
    #include <bcrypt.h>
    #include <iostream>
    #include <vector>
    #pragma comment(lib, "Gdiplus.lib")
    #pragma comment(lib, "comctl32.lib")
    #pragma comment(lib, "advapi32.lib")
    #pragma comment(lib, "bcrypt.lib")
    #pragma comment(linker, "/SUBSYSTEM:WINDOWS")
    #define IDC_PROGRESSBAR 100
    #define IDC_FILEPATHBT 101
    #define IDC_CRC32BT 102
    #define IDC_MD5BT 103
    #define IDC_SHA1BT 104
    #define IDC_SHA256BT 105
    #define IDC_SHA512BT 106
    #define IDC_CHECKBT 107
    #define IDC_HASHCOMPAREBT 108
    #define MD5BUFSIZE 1024
    #define MD5LEN 16
    #define SHA1BUFSIZE 32768
    #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
    #define SHA256BUFSIZE 65536
    #define SHA512BUFSIZE 65536
    
    using namespace Gdiplus;
    
    extern HINSTANCE g_hInstance;
    extern ULONG_PTR gdiplusToken;
    extern Image* pImage;
    
    extern HWND hFilePathLabelWnd, hFilePathEditWnd, hFilePathButtonWnd;
    extern HWND hHashInputLabelWnd, hHashCompareInputWnd, hHashCheckButtonWnd;
    extern HWND hCrc32LabelWnd, hCrc32CopyButtonWnd, hCrc32TextEditWnd;
    extern HWND hMd5LabelWnd, hMd5CopyButtonWnd, hMd5TextEditWnd;
    extern HWND hSha1LabelWnd, hSha1CopyButtonWnd, hSha1TextEditWnd;
    extern HWND hSha256LabelWnd, hSha256CopyButtonWnd, hSha256TextEditWnd;
    extern HWND hSha512LabelWnd, hSha512CopyButtonWnd, hSha512TextEditWnd;
    extern HWND hOkButtonWnd;
    extern HWND hProgressbarWnd;
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
    #endif

    WinMain.cpp

    #include "WndProcs.h"
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
    
    LPCTSTR lpszWndClass = TEXT("파일 해시섬 프로그램 Ver 2.0 - 공식배포처 https://korworld.kr");
    HINSTANCE g_hInstance;
    ULONG_PTR gdiplusToken;
    Image* pImage = NULL;
    
    int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpszCmdParam, _In_ int nCmdShow)
    {
    	GdiplusStartupInput gdiplusStartupInput;
    	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    
    	HWND hWnd;
    	MSG Message;
    	WNDCLASSEX WndClassEx;
    
    	g_hInstance = hInstance;
    
    	WndClassEx.cbSize = sizeof(WndClassEx); // 구조체 크기를 RegisterClass로 전달하기 위한 멤버이며 보통 값은 자기 자신의 크기를 넘겨주면 됨
    	WndClassEx.cbClsExtra = 0; // 윈도우 클래스 레벨에서 추가적인 여분 메모리 할당용. 보안상 이슈로 거의 사용되지 않고 0으로 두는 경우가 많음
    	WndClassEx.cbWndExtra = 0; // 윈도우 인스턴스마다 추가적으로 할당할 여분의 메모리 할당용. 각 윈도우별로 별도 할당되고 윈도우별로 특별한 데이터를 저정하기 위한 예약된 메모리 공간. 이쪽도 그렇게 잘 사용되지는 않음. 프로젝트 규모가 크거나 할때는 어느정도 쓰이나 규모가 작거나 복잡도가 낮은경우에는 거의 쓰일 일이 없음
    	WndClassEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    	WndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
    	WndClassEx.hIcon = LoadIcon(NULL, NULL);
    	WndClassEx.hIconSm = LoadIcon(NULL, NULL);
    	WndClassEx.hInstance = hInstance;
    	WndClassEx.lpfnWndProc = WndProc;
    	WndClassEx.lpszClassName = lpszWndClass;
    	WndClassEx.lpszMenuName = NULL;
    	WndClassEx.style = CS_VREDRAW | CS_HREDRAW;
    	RegisterClassEx(&WndClassEx);
    
    	hWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME, lpszWndClass, lpszWndClass, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,
    		CW_USEDEFAULT, CW_USEDEFAULT, 1280, 720, 
    		NULL, (HMENU)NULL, g_hInstance, NULL);
    
    	ShowWindow(hWnd, nCmdShow);
    	UpdateWindow(hWnd);
    
    	while (TRUE)
    	{
    		if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE))
    		{
    			if (Message.message == WM_QUIT)
    			{
    				break;
    			}
    			else
    			{
    				TranslateMessage(&Message);
    				DispatchMessage(&Message);
    			}
    		}
    		else
    		{
    			WaitMessage();
    		}
    	}
    
    	GdiplusShutdown(gdiplusToken);
    
    	return (int)Message.wParam;
    }

    WndProc.cpp

    #include "WndProcs.h"
    
    /// CRC32를 포함 각종 파일 해시섬 로직들은 AI(구글 제미나이)에 의해 작성되어진 코드 입니다
    /// 일부 AI에 의한 오류나 윈도우 UI환경에 맞추는 부분정도만 직접 진행하였으므로
    /// 제가 전부 이해하고 있는 상태가 아닙니다
    /// 따라서 파일 해시섬 로직에 대한 궁금증에 대해서는 아쉽지만 AI에 문의해 주시기 바랍니다
    
    /// CRC32 파일 해시섬 함수들 형선언 시작
    void makeCRCtable(unsigned long *, unsigned long);
    unsigned long calcCRC(const unsigned char *, signed long, unsigned long, unsigned long *);
    LPCWSTR getFileCrc(FILE* s);
    /// CRC32 파일 해시섬 함수들 형선언 끝
    
    // 윈도우 핸들러
    HWND hFilePathLabelWnd, hFilePathEditWnd, hFilePathButtonWnd;
    HWND hHashInputLabelWnd, hHashCompareInputWnd, hHashCheckButtonWnd;
    HWND hCrc32LabelWnd, hCrc32CopyButtonWnd, hCrc32TextEditWnd;
    HWND hMd5LabelWnd, hMd5CopyButtonWnd, hMd5TextEditWnd;
    HWND hSha1LabelWnd, hSha1CopyButtonWnd, hSha1TextEditWnd;
    HWND hSha256LabelWnd, hSha256CopyButtonWnd, hSha256TextEditWnd;
    HWND hSha512LabelWnd, hSha512CopyButtonWnd, hSha512TextEditWnd;
    HWND hOkButtonWnd;
    HWND hProgressbarWnd;
    
    // 파일 처리
    OPENFILENAME OpenFileName;
    
    // 프로그레스바 윈도우 진행도 0 ~ 100
    int progressStatus = 0;
    
    // 파일 경로 및 파일 이름+확장자
    TCHAR lpstrFile[MAX_PATH] = TEXT("");
    TCHAR lpstrFileTitle[MAX_PATH] = TEXT("");
    
    // 파일 해시섬 문자열 전역 변수
    wchar_t hashBuffer[256] = L"";
    wchar_t crc32ResultBuffer[256] = L"";
    wchar_t md5ResultBuffer[256] = L"";
    wchar_t sha1ResultBuffer[256] = L"";
    wchar_t sha256ResultBuffer[256] = L"";
    wchar_t sha512ResultBuffer[256] = L"";
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
    {
    	PAINTSTRUCT PaintStruct;
    
    	HDC hdc;
    
    	HDROP hDropFile = (HDROP)wParam;
    
    	wchar_t dragFileName[MAX_PATH];
    	wchar_t dragFileExt[MAX_PATH];
    	
    	// CRC32 해시 관련 변수
    	FILE *in;
    	char tempFilePath[256];
    	errno_t err;
    	
    
    	// MD5 해시 관련 변수
    	HANDLE hFile = INVALID_HANDLE_VALUE;
    	HCRYPTPROV hCryptProv = 0;
    	HCRYPTHASH hMd5Hash = 0;
    	BYTE rgbMd5File[MD5BUFSIZE];
    	DWORD cbRead = 0;
    	BYTE rgbMd5Hash[MD5LEN];
    	DWORD cbHash = 0;
    
    	// SHA-1 해시 관련 변수
    	NTSTATUS functionStatus = NULL;
    	BCRYPT_ALG_HANDLE hAlg = NULL;
    	BCRYPT_HASH_HANDLE hSha1Hash = NULL;
    	DWORD cbData = 0, cbSha1Hash = 0, cbSha1HashObject = 0;
    	PBYTE pbHashObject = NULL;
    	PBYTE pbHash = NULL;
    
    	// SHA-256 해시 관련 변수
    	BCRYPT_HASH_HANDLE hSha256Hash = NULL;
    	DWORD cbSha256Hash = 0, cbSha256HashObject = 0;
    	BYTE sha256Buffer[SHA256BUFSIZE];
    
    	// SHA-512 해시 관련 변수
    	BCRYPT_HASH_HANDLE hSha512Hash = NULL;
    	DWORD cbSha512Hash = 0, cbSha512HashObject = 0;
    	BYTE sha512Buffer[SHA512BUFSIZE];
    
    	switch (iMessage)
    	{
    		case WM_CREATE: // 프로그램 실행시 윈도우 생성과 동시에 처리되는 로직
    		{
    			DragAcceptFiles(hWnd, TRUE); // 드래그앤 드롭 파일 입력 허용
    			OpenFileName.lStructSize = sizeof(OpenFileName);
    			OpenFileName.hwndOwner = hWnd;
    			OpenFileName.lpstrFilter = TEXT("모든 파일\0*.*\0");
    			OpenFileName.nMaxFile = MAX_PATH;
    			OpenFileName.nMaxFileTitle = MAX_PATH;
    
    			// GDI+로 불러올 이미지 파일 위치
    			pImage = new Image(L"bg.png");
    
    			INITCOMMONCONTROLSEX icex;
    			icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    			icex.dwICC = ICC_PROGRESS_CLASS;
    			InitCommonControlsEx(&icex);
    
    			// 자식 윈도우 컨트롤들 그리기 및 배치
    			hFilePathLabelWnd = CreateWindowEx(NULL, TEXT("STATIC"), TEXT("파일 경로"), WS_CHILD | WS_VISIBLE | SS_CENTER | SS_CENTERIMAGE,
    				10, 5, 100, 25, hWnd, (HMENU)-1, g_hInstance, NULL);
    			hFilePathEditWnd = CreateWindowEx(WS_EX_STATICEDGE, TEXT("EDIT"), TEXT("파일을 드래그앤 드롭으로 프로그램에 올려놓아도 자동으로 경로를 입력받습니다"), WS_CHILD | WS_VISIBLE | WS_BORDER | ES_READONLY | SS_CENTER,
    				10, 35, 1130, 25, hWnd, (HMENU)-1, g_hInstance, NULL);
    			hFilePathButtonWnd = CreateWindowEx(WS_EX_STATICEDGE, TEXT("BUTTON"), TEXT("파일선택"), WS_CHILD | WS_VISIBLE | WS_BORDER,
    				1150, 35, 100, 25, hWnd, (HMENU)IDC_FILEPATHBT, g_hInstance, NULL);
    
    			hHashInputLabelWnd = CreateWindowEx(NULL, TEXT("STATIC"), TEXT("비교할 해시값을 아래에 입력해주세요"), WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE,
    				10, 100, 300, 25, hWnd, (HMENU)-1, g_hInstance, NULL);
    			hHashCompareInputWnd = CreateWindowEx(WS_EX_STATICEDGE, TEXT("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER,
    				10, 130, 1130, 25, hWnd, (HMENU)-1, g_hInstance, NULL);
    			hHashCheckButtonWnd = CreateWindowEx(WS_EX_STATICEDGE, TEXT("BUTTON"), TEXT("해시 값 비교"), WS_CHILD | WS_VISIBLE | WS_BORDER | WS_DISABLED,
    				1150, 130, 100, 25, hWnd, (HMENU)IDC_HASHCOMPAREBT, g_hInstance, NULL);
    
    			hCrc32LabelWnd = CreateWindowEx(NULL, TEXT("STATIC"), TEXT("CRC32"), WS_CHILD | WS_VISIBLE | SS_CENTER | SS_CENTERIMAGE,
    				10, 180, 100, 25, hWnd, (HMENU)-1, g_hInstance, NULL);
    			hCrc32CopyButtonWnd = CreateWindowEx(NULL, TEXT("BUTTON"), TEXT("CRC32 해시 값 복사"), WS_CHILD | WS_VISIBLE | SS_CENTER | WS_DISABLED,
    				130, 180, 175, 25, hWnd, (HMENU)IDC_CRC32BT, g_hInstance, NULL);
    			hCrc32TextEditWnd = CreateWindowEx(WS_EX_STATICEDGE, TEXT("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_READONLY,
    				10, 210, 1240, 25, hWnd, (HMENU)-1, g_hInstance, NULL);
    
    			hMd5LabelWnd = CreateWindowEx(NULL, TEXT("STATIC"), TEXT("MD5"), WS_CHILD | WS_VISIBLE | SS_CENTER | SS_CENTERIMAGE,
    				10, 260, 100, 25, hWnd, (HMENU)-1, g_hInstance, NULL);
    			hMd5CopyButtonWnd = CreateWindowEx(NULL, TEXT("BUTTON"), TEXT("MD5 해시 값 복사"), WS_CHILD | WS_VISIBLE | SS_CENTER | WS_DISABLED,
    				130, 260, 175, 25, hWnd, (HMENU)IDC_MD5BT, g_hInstance, NULL);
    			hMd5TextEditWnd = CreateWindowEx(WS_EX_STATICEDGE, TEXT("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_READONLY,
    				10, 290, 1240, 25, hWnd, (HMENU)-1, g_hInstance, NULL);
    
    			hSha1LabelWnd = CreateWindowEx(NULL, TEXT("STATIC"), TEXT("SHA-1"), WS_CHILD | WS_VISIBLE | SS_CENTER | SS_CENTERIMAGE,
    				10, 340, 100, 25, hWnd, (HMENU)-1, g_hInstance, NULL);
    			hSha1CopyButtonWnd = CreateWindowEx(NULL, TEXT("BUTTON"), TEXT("SHA-1 해시 값 복사"), WS_CHILD | WS_VISIBLE | SS_CENTER | WS_DISABLED,
    				130, 340, 175, 25, hWnd, (HMENU)IDC_SHA1BT, g_hInstance, NULL);
    			hSha1TextEditWnd = CreateWindowEx(WS_EX_STATICEDGE, TEXT("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_READONLY,
    				10, 370, 1240, 25, hWnd, (HMENU)-1, g_hInstance, NULL);
    
    			hSha256LabelWnd = CreateWindowEx(NULL, TEXT("STATIC"), TEXT("SHA-256"), WS_CHILD | WS_VISIBLE | SS_CENTER | SS_CENTERIMAGE,
    				10, 420, 100, 25, hWnd, (HMENU)-1, g_hInstance, NULL);
    			hSha256CopyButtonWnd = CreateWindowEx(NULL, TEXT("BUTTON"), TEXT("SHA-256 해시 값 복사"), WS_CHILD | WS_VISIBLE | SS_CENTER | WS_DISABLED,
    				130, 420, 175, 25, hWnd, (HMENU)IDC_SHA256BT, g_hInstance, NULL);
    			hSha256TextEditWnd = CreateWindowEx(WS_EX_STATICEDGE, TEXT("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_READONLY,
    				10, 450, 1240, 25, hWnd, (HMENU)-1, g_hInstance, NULL);
    
    			hSha512LabelWnd = CreateWindowEx(NULL, TEXT("STATIC"), TEXT("SHA-512"), WS_CHILD | WS_VISIBLE | SS_CENTER | SS_CENTERIMAGE,
    				10, 500, 100, 25, hWnd, (HMENU)-1, g_hInstance, NULL);
    			hSha512CopyButtonWnd = CreateWindowEx(NULL, TEXT("BUTTON"), TEXT("SHA-512 해시 값 복사"), WS_CHILD | WS_VISIBLE | SS_CENTER | WS_DISABLED,
    				130, 500, 175, 25, hWnd, (HMENU)IDC_SHA512BT, g_hInstance, NULL);
    			hSha512TextEditWnd = CreateWindowEx(WS_EX_STATICEDGE, TEXT("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_READONLY,
    				10, 530, 1240, 25, hWnd, (HMENU)-1, g_hInstance, NULL);
    
    			hOkButtonWnd = CreateWindowEx(WS_EX_STATICEDGE, TEXT("BUTTON"), TEXT("파일 해시섬 확인"), WS_CHILD | WS_VISIBLE | WS_BORDER | WS_DISABLED,
    				1050, 640, 200, 25, hWnd, (HMENU)IDC_CHECKBT, g_hInstance, NULL);
    
    			hProgressbarWnd = CreateWindowEx(NULL, PROGRESS_CLASS, (LPCWSTR)NULL, WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
    				0, 670, 1280, 15, hWnd, (HMENU)IDC_PROGRESSBAR, g_hInstance, NULL);
    
    			SendMessage(hProgressbarWnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
    			SendMessage(hProgressbarWnd, PBM_SETPOS, 0, 0);
    			SendMessage(hProgressbarWnd, PBM_SETSTEP, (WPARAM)1, 0);
    			return 0;
    		}
    		case WM_PAINT: // 윈도우 그리기 처리 로직
    		{
    			hdc = BeginPaint(hWnd, &PaintStruct);
    			Graphics graphics(hdc);
    			graphics.DrawImage(pImage, 0, 0, 1280, 720);
    			EndPaint(hWnd, &PaintStruct);
    			return 0;
    		}
    		case WM_DROPFILES: // 파일 드래그 온 드롭시 실행될 로직
    		{
    			DragQueryFile(hDropFile, 0, lpstrFile, MAX_PATH);
    			_wsplitpath_s(lpstrFile, NULL, NULL, NULL, NULL, dragFileName, MAX_PATH, dragFileExt, MAX_PATH);
    			wcscat_s(dragFileName, MAX_PATH, dragFileExt);
    			ZeroMemory(lpstrFileTitle, sizeof(lpstrFileTitle));
    			wcscat_s(lpstrFileTitle, MAX_PATH, dragFileName);
    			SetWindowText(hFilePathEditWnd, lpstrFile);
    			EnableWindow(hOkButtonWnd, TRUE);
    			EnableWindow(hCrc32CopyButtonWnd, FALSE);
    			EnableWindow(hMd5CopyButtonWnd, FALSE);
    			EnableWindow(hSha1CopyButtonWnd, FALSE);
    			EnableWindow(hSha256CopyButtonWnd, FALSE);
    			EnableWindow(hSha512CopyButtonWnd, FALSE);
    			EnableWindow(hHashCheckButtonWnd, FALSE);
    			DragFinish(hDropFile);
    			SetForegroundWindow(hWnd);
    			return 0;
    		}
    		case WM_COMMAND: // 컨트롤 입력 처리 로직
    		{
    			switch (LOWORD(wParam))
    			{
    			case IDC_FILEPATHBT: // 파일 열기 버튼 로직
    				if (HIWORD(wParam) == BN_CLICKED)
    				{
    					memset(&OpenFileName, 0, sizeof(OPENFILENAME));
    					OpenFileName.lStructSize = sizeof(OPENFILENAME);
    					OpenFileName.hwndOwner = hWnd;
    					OpenFileName.lpstrFilter = TEXT("모든 파일\0*.*\0");
    					OpenFileName.nMaxFile = MAX_PATH;
    					OpenFileName.lpstrFile = lpstrFile;
    					OpenFileName.nMaxFileTitle = MAX_PATH;
    					OpenFileName.lpstrFileTitle = lpstrFileTitle;
    					if (GetOpenFileName(&OpenFileName) != 0)
    					{
    						SetWindowText(hFilePathEditWnd, lpstrFile);
    						EnableWindow(hOkButtonWnd, TRUE);
    						EnableWindow(hCrc32CopyButtonWnd, FALSE);
    						EnableWindow(hMd5CopyButtonWnd, FALSE);
    						EnableWindow(hSha1CopyButtonWnd, FALSE);
    						EnableWindow(hSha256CopyButtonWnd, FALSE);
    						EnableWindow(hSha512CopyButtonWnd, FALSE);
    						EnableWindow(hHashCheckButtonWnd, FALSE);
    					}
    				}
    				break;
    			case IDC_CRC32BT: // CRC32 해시 값 복사 버튼 로직
    				if (HIWORD(wParam) == BN_CLICKED)
    				{
    					SendMessage(hCrc32TextEditWnd, EM_SETSEL, 0, -1);
    					SendMessage(hCrc32TextEditWnd, WM_COPY, 0, 0);
    					MessageBox(hWnd, TEXT("CRC32 해시 값이 클립보드에 복사되었습니다\n복사된 값을 붙여 넣으려면 Ctrl + V키를 누르거나 마우스 오른쪽으로 메뉴를 호출 한뒤에 \'붙여넣기\'로 값을 붙여넣기 할수 있습니다"), TEXT("알림"), MB_OK);
    				}
    				break;
    			case IDC_MD5BT: // MD5 해시 값 복사 버튼 로직
    				if (HIWORD(wParam) == BN_CLICKED)
    				{
    					SendMessage(hMd5TextEditWnd, EM_SETSEL, 0, -1);
    					SendMessage(hMd5TextEditWnd, WM_COPY, 0, 0);
    					MessageBox(hWnd, TEXT("MD5 해시 값이 클립보드에 복사되었습니다\n복사된 값을 붙여 넣으려면 Ctrl + V키를 누르거나 마우스 오른쪽으로 메뉴를 호출 한뒤에 \'붙여넣기\'로 값을 붙여넣기 할수 있습니다"), TEXT("알림"), MB_OK);
    				}
    				break;
    			case IDC_SHA1BT: // SHA-1 해시 값 복사 버튼 로직
    				if (HIWORD(wParam) == BN_CLICKED)
    				{
    					SendMessage(hSha1TextEditWnd, EM_SETSEL, 0, -1);
    					SendMessage(hSha1TextEditWnd, WM_COPY, 0, 0);
    					MessageBox(hWnd, TEXT("SHA-1 해시 값이 클립보드에 복사되었습니다\n복사된 값을 붙여 넣으려면 Ctrl + V키를 누르거나 마우스 오른쪽으로 메뉴를 호출 한뒤에 \'붙여넣기\'로 값을 붙여넣기 할수 있습니다"), TEXT("알림"), MB_OK);
    				}
    				break;
    			case IDC_SHA256BT: // SHA-256 해시 값 복사 버튼 로직
    				if (HIWORD(wParam) == BN_CLICKED)
    				{
    					SendMessage(hSha256TextEditWnd, EM_SETSEL, 0, -1);
    					SendMessage(hSha256TextEditWnd, WM_COPY, 0, 0);
    					MessageBox(hWnd, TEXT("SHA-256 해시 값이 클립보드에 복사되었습니다\n복사된 값을 붙여 넣으려면 Ctrl + V키를 누르거나 마우스 오른쪽으로 메뉴를 호출 한뒤에 \'붙여넣기\'로 값을 붙여넣기 할수 있습니다"), TEXT("알림"), MB_OK);
    				}
    				break;
    			case IDC_SHA512BT: // SHA-256 해시 값 복사 버튼 로직
    				if (HIWORD(wParam) == BN_CLICKED)
    				{
    					SendMessage(hSha512TextEditWnd, EM_SETSEL, 0, -1);
    					SendMessage(hSha512TextEditWnd, WM_COPY, 0, 0);
    					MessageBox(hWnd, TEXT("SHA-512 해시 값이 클립보드에 복사되었습니다\n복사된 값을 붙여 넣으려면 Ctrl + V키를 누르거나 마우스 오른쪽으로 메뉴를 호출 한뒤에 \'붙여넣기\'로 값을 붙여넣기 할수 있습니다"), TEXT("알림"), MB_OK);
    				}
    				break;
    			case IDC_CHECKBT: // SHA-512 해시 값 복사 버튼 로직
    				if (HIWORD(wParam) == BN_CLICKED)
    				{
    					SendMessage(hProgressbarWnd, PBM_SETPOS, 0, 0);
    					progressStatus = 0;
    					// CRC32 처리 로직 시작
    					WideCharToMultiByte(CP_ACP, 0, lpstrFile, -1, tempFilePath, sizeof(tempFilePath), NULL, NULL);
    					err = fopen_s(&in, tempFilePath, "rb");
    					if (err != 0)
    					{
    						MessageBox(hWnd, TEXT("지정된 파일이 없습니다. 파일을 선택 한후에 해시섬 확인을 진행해 주세요"), TEXT("경고"), MB_OK | MB_ICONWARNING);
    						break;
    					}
    					if (progressStatus < 20)
    					{
    						for (int i = 0; i < 20; i++)
    						{
    							SendMessage(hProgressbarWnd, PBM_STEPIT, 0, 0);
    							progressStatus++;
    						}
    					}
    					wcscpy_s(crc32ResultBuffer, getFileCrc(in));
    					SetWindowText(hCrc32TextEditWnd, crc32ResultBuffer);
    					// MD5 처리 로직 시작
    					hFile = CreateFile(lpstrFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
    					functionStatus = CryptAcquireContext(&hCryptProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
    					functionStatus = CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hMd5Hash);
    					while (ReadFile(hFile, rgbMd5File, MD5BUFSIZE, &cbRead, NULL) && cbRead > 0)
    					{
    						if (!CryptHashData(hMd5Hash, rgbMd5File, cbRead, 0))
    						{
    							CryptDestroyHash(hMd5Hash);
    							CryptReleaseContext(hCryptProv, 0);
    							CloseHandle(hFile);
    						}
    					}
    					cbHash = MD5LEN;
    					if (CryptGetHashParam(hMd5Hash, HP_HASHVAL, rgbMd5Hash, &cbHash, 0))
    					{
    						for (DWORD i = 0; i < cbHash; i++)
    						{
    							swprintf_s(md5ResultBuffer, 256, L"%s%02x", md5ResultBuffer, rgbMd5Hash[i]);
    							if (progressStatus < 40)
    							{
    								SendMessage(hProgressbarWnd, PBM_STEPIT, 0, 0);
    								progressStatus++;
    							}
    						}
    					}
    					CryptDestroyHash(hMd5Hash);
    					CryptReleaseContext(hCryptProv, 0);
    					CloseHandle(hFile);
    					SetWindowText(hMd5TextEditWnd, md5ResultBuffer);
    					// SHA-1 처리 로직 시작
    					functionStatus = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA1_ALGORITHM, NULL, 0);
    					functionStatus = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbSha1HashObject, sizeof(DWORD), &cbData, 0);
    					pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbSha1HashObject);
    					functionStatus = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbSha1Hash, sizeof(DWORD), &cbData, 0);
    					pbHash = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbSha1Hash);
    					functionStatus = BCryptCreateHash(hAlg, &hSha1Hash, pbHashObject, cbSha1HashObject, NULL, 0, 0);
    					hFile = CreateFile(lpstrFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    					BYTE sha1Buffer[1024 * 4];
    					DWORD byteRead = 0;
    					while (ReadFile(hFile, sha1Buffer, sizeof(sha1Buffer), &byteRead, NULL) && byteRead > 0)
    					{
    						functionStatus = BCryptHashData(hSha1Hash, sha1Buffer, byteRead, 0);
    					}
    					functionStatus = BCryptFinishHash(hSha1Hash, pbHash, cbSha1Hash, 0);
    					for (DWORD i = 0; i < cbSha1Hash; i++)
    					{
    						swprintf_s(sha1ResultBuffer, 256, L"%s%02x", sha1ResultBuffer, pbHash[i]);
    						if (progressStatus < 60)
    						{
    							SendMessage(hProgressbarWnd, PBM_STEPIT, 0, 0);
    							progressStatus++;
    						}
    					}
    					CloseHandle(hFile);
    					SetWindowText(hSha1TextEditWnd, sha1ResultBuffer);
    					// SHA-256 처리 로직 시작
    					hAlg = NULL;
    					cbData = 0;
    					pbHashObject = NULL;
    					pbHash = NULL;
    					functionStatus = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM, NULL, 0);
    					functionStatus = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbSha256HashObject, sizeof(DWORD), &cbData, 0);
    					pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbSha256HashObject);
    					functionStatus = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbSha256Hash, sizeof(DWORD), &cbData, 0);
    					pbHash = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbSha256Hash);
    					functionStatus = BCryptCreateHash(hAlg, &hSha256Hash, pbHashObject, cbSha256HashObject, NULL, 0, 0);
    					hFile = CreateFile(lpstrFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    					byteRead = 0;
    					while (ReadFile(hFile, sha256Buffer, SHA256BUFSIZE, &byteRead, NULL) && byteRead > 0)
    					{
    						functionStatus = BCryptHashData(hSha256Hash, sha256Buffer, byteRead, 0);
    					}
    					functionStatus = BCryptFinishHash(hSha256Hash, pbHash, cbSha256Hash, 0);
    					for (DWORD i = 0; i < cbSha256Hash; i++)
    					{
    						swprintf_s(sha256ResultBuffer, 256, L"%s%02x", sha256ResultBuffer, pbHash[i]);
    						if (progressStatus < 80)
    						{
    							SendMessage(hProgressbarWnd, PBM_STEPIT, 0, 0);
    							progressStatus++;
    						}
    					}
    					CloseHandle(hFile);
    					SetWindowText(hSha256TextEditWnd, sha256ResultBuffer);
    					// SHA-512 처리 로직 시작
    					hAlg = NULL;
    					cbData = 0;
    					pbHashObject = NULL;
    					pbHash = NULL;
    					functionStatus = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA512_ALGORITHM, NULL, 0);
    					functionStatus = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbSha512HashObject, sizeof(DWORD), &cbData, 0);
    					pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbSha512HashObject);
    					functionStatus = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbSha512Hash, sizeof(DWORD), &cbData, 0);
    					pbHash = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbSha512Hash);
    					functionStatus = BCryptCreateHash(hAlg, &hSha512Hash, pbHashObject, cbSha512HashObject, NULL, 0, 0);
    					hFile = CreateFile(lpstrFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    					byteRead = 0;
    					while (ReadFile(hFile, sha512Buffer, SHA512BUFSIZE, &byteRead, NULL) && byteRead > 0)
    					{
    						functionStatus = BCryptHashData(hSha512Hash, sha512Buffer, byteRead, 0);
    					}
    					functionStatus = BCryptFinishHash(hSha512Hash, pbHash, cbSha512Hash, 0);
    					for (DWORD i = 0; i < cbSha512Hash; i++)
    					{
    						swprintf_s(sha512ResultBuffer, 256, L"%s%02x", sha512ResultBuffer, pbHash[i]);
    						if (progressStatus < 100)
    						{
    							SendMessage(hProgressbarWnd, PBM_STEPIT, 0, 0);
    							progressStatus++;
    						}
    					}
    					CloseHandle(hFile);
    					SetWindowText(hSha512TextEditWnd, sha512ResultBuffer);
    					// 해시 값 출력 처리 완료 후 처리
    					if (progressStatus < 100)
    					{
    						for (int i = 0; i < (100 - progressStatus); i++)
    						{
    							SendMessage(hProgressbarWnd, PBM_STEPIT, 0, 0);
    						}
    					}
    					SendMessage(hProgressbarWnd, PBM_SETPOS, 100, 0);
    					wmemset(crc32ResultBuffer, 0, 256);
    					wmemset(md5ResultBuffer, 0, 256);
    					wmemset(sha1ResultBuffer, 0, 256);
    					wmemset(sha256ResultBuffer, 0, 256);
    					wmemset(sha512ResultBuffer, 0, 256);
    					EnableWindow(hCrc32CopyButtonWnd, TRUE);
    					EnableWindow(hMd5CopyButtonWnd, TRUE);
    					EnableWindow(hSha1CopyButtonWnd, TRUE);
    					EnableWindow(hSha256CopyButtonWnd, TRUE);
    					EnableWindow(hSha512CopyButtonWnd, TRUE);
    					EnableWindow(hHashCheckButtonWnd, TRUE);
    				}
    				break;
    			case IDC_HASHCOMPAREBT: // 해시 값 비교 버튼 로직
    				if (HIWORD(wParam) == BN_CLICKED)
    				{
    					TCHAR messageText[MAX_PATH];
    					int hashTextLength = GetWindowTextLength(hHashCompareInputWnd) + 1;
    					int crc32TextLength = GetWindowTextLength(hCrc32TextEditWnd) + 1;
    					int md5TextLength = GetWindowTextLength(hMd5TextEditWnd) + 1;
    					int sha1TextLength = GetWindowTextLength(hSha1TextEditWnd) + 1;
    					int sha256TextLength = GetWindowTextLength(hSha256TextEditWnd) + 1;
    					int sha512TextLength = GetWindowTextLength(hSha512TextEditWnd) + 1;
    					GetWindowText(hHashCompareInputWnd, hashBuffer, hashTextLength);
    					GetWindowText(hCrc32TextEditWnd, crc32ResultBuffer, crc32TextLength);
    					GetWindowText(hMd5TextEditWnd, md5ResultBuffer, md5TextLength);
    					GetWindowText(hSha1TextEditWnd, sha1ResultBuffer, sha1TextLength);
    					GetWindowText(hSha256TextEditWnd, sha256ResultBuffer, sha256TextLength);
    					GetWindowText(hSha512TextEditWnd, sha512ResultBuffer, sha512TextLength);
    
    					if (wcscmp(hashBuffer, crc32ResultBuffer) == 0)
    					{
    						wsprintf(messageText, TEXT("%s 파일에 CRC32해시 값 %ls 와 일치합니다"), lpstrFileTitle, crc32ResultBuffer);
    						MessageBox(hWnd, messageText, TEXT("일치하는 해시 값이 있습니다"), MB_OK);
    					}
    					else if (wcscmp(hashBuffer, md5ResultBuffer) == 0)
    					{
    						wsprintf(messageText, TEXT("%s 파일에 MD5해시 값 %s 와 일치합니다"), lpstrFileTitle, md5ResultBuffer);
    						MessageBox(hWnd, messageText, TEXT("일치하는 해시 값이 있습니다"), MB_OK);
    					}
    					else if (wcscmp(hashBuffer, sha1ResultBuffer) == 0)
    					{
    						wsprintf(messageText, TEXT("%s 파일에 SHA-1해시 값 %s 와 일치합니다"), lpstrFileTitle, sha1ResultBuffer);
    						MessageBox(hWnd, messageText, TEXT("일치하는 해시 값이 있습니다"), MB_OK);
    					}
    					else if (wcscmp(hashBuffer, sha256ResultBuffer) == 0)
    					{
    						wsprintf(messageText, TEXT("%s 파일에 SHA-256해시 값 %s 와 일치합니다"), lpstrFileTitle, sha256ResultBuffer);
    						MessageBox(hWnd, messageText, TEXT("일치하는 해시 값이 있습니다"), MB_OK);
    					}
    					else if (wcscmp(hashBuffer, sha512ResultBuffer) == 0)
    					{
    						wsprintf(messageText, TEXT("%s 파일에 SHA-512해시 값 %s 와 일치합니다"), lpstrFileTitle, sha512ResultBuffer);
    						MessageBox(hWnd, messageText, TEXT("일치하는 해시 값이 있습니다"), MB_OK);
    					}
    					else
    					{
    						MessageBox(hWnd, TEXT("일치하는 해시값이 없습니다"), TEXT("일치하는 해시값이 없습니다"), MB_OK);
    					}
    					wmemset(hashBuffer, 0, 256);
    					wmemset(crc32ResultBuffer, 0, 256);
    					wmemset(md5ResultBuffer, 0, 256);
    					wmemset(sha1ResultBuffer, 0, 256);
    					wmemset(sha256ResultBuffer, 0, 256);
    					wmemset(sha512ResultBuffer, 0, 256);
    				}
    				break;
    			}
    			return 0;
    		}
    		case WM_DESTROY: // 윈도우 종료시 실행될 로직
    		{// !!!메모리 누수 방지를 위해 메모리 릴리즈 처리를 반드시 해줄것
    			delete pImage;
    			PostQuitMessage(0);
    			return 0;
    		}
    	}
    
    	return DefWindowProc(hWnd, iMessage, wParam, lParam);
    }
    
    /// CRC32 파일 해시섬 함수들 시작
    void Crc32Table(unsigned long* table, unsigned long id)
    {
    	unsigned long i, j, k;
    
    	for (i = 0; i < 256; ++i)
    	{
    		k = i;
    		for (j = 0; j < 8; ++j)
    		{
    			if (k & 1) k = (k >> 1) ^ id;
    			else k >>= 1;
    		}
    		table[i] = k;
    	}
    }
    
    unsigned long calcCrc(const unsigned char* mem, signed long size, unsigned long CRC, unsigned long* table)
    {
    	CRC = ~CRC;
    
    	while (size--)
    	{
    		CRC = table[(CRC ^ *(mem++)) & 0xff] ^ (CRC >> 8);
    	}
    
    	return ~CRC;
    }
    
    LPCWSTR getFileCrc(FILE* s)
    {
    	unsigned char buf[32768];
    	unsigned long CRC = 0;
    	unsigned long table[256];
    	size_t len;
    	wchar_t buffer[256];
    
    	Crc32Table(table, 0xEDB88320);
    
    	while ((len = fread(buf, 1, sizeof(buf), s)) != NULL)
    	{
    		CRC = calcCrc(buf, (unsigned long)len, CRC, table);
    	}
    	_ultow_s(CRC, buffer, sizeof(buffer) / sizeof(wchar_t), 16);
    
    	return buffer;
    }
    /// CRC32 파일 해시섬 함수들 끝
  • 파일 해시섬 프로그램 File Hashsum Program

    파일의 해시섬을 구할수 있는 프로그램 입니다

    CRC32부터 좀더 무결성이 높은 SHA-512까지 동시에 확인이 가능합니다

    2.0 버전 기준 지원 해시 목록

    • CRC32
    • MD5
    • SHA-1
    • SHA-256
    • SHA-512

    배경 이미지를 원하는 걸로 커스터마이즈 가능합니다

    지원되는 포맷은 png 입니다

    바꾸고자 하는 png 이미지 파일을 bg.png로 이름을 변경 한후 exe파일과 같은 위치에 넣어준뒤에 프로그램을 종료하고 재시작 하면 반영이 됩니다

    권장 이미지 사이즈 비율은 16:9 입니다(권장 해상도 1280×720)

    사용하고자 하는 이미지가 16:9 비율이 아닐시 프로그램에서 이미지를 강제로 16:9비율로 표시합니다

    버전 로그

    2026년 5월 15일 1.0 버전

    • 최초 출시

    2026년 5월 19일 2.0 버전

    • 해시 값 비교 기능 추가
  • Win32API 기본 윈도우 만들기

    WndProc.h

    #ifndef _WNDPROCS_H_
    #define _WNDPROCS_H_
    #endif
    #include <Windows.h>
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);

    WinMain.cpp

    #include "WndProcs.h"
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
    
    LPCTSTR lpszWndClass = TEXT("파일 체크섬 프로그램");
    HINSTANCE g_hInstance;
    
    int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpszCmdParam, _In_ int nCmdShow)
    {
    	HWND hWnd;
    	MSG Message;
    	WNDCLASSEX WndClassEx;
    
    	g_hInstance = hInstance;
    
    	WndClassEx.cbSize = sizeof(WndClassEx); // 구조체 크기를 RegisterClass로 전달하기 위한 멤버이며 보통 값은 자기 자신의 크기를 넘겨주면 됨
    	WndClassEx.cbClsExtra = 0; // 윈도우 클래스 레벨에서 추가적인 여분 메모리 할당용. 보안상 이슈로 거의 사용되지 않고 0으로 두는 경우가 많음
    	WndClassEx.cbWndExtra = 0; // 윈도우 인스턴스마다 추가적으로 할당할 여분의 메모리 할당용. 각 윈도우별로 별도 할당되고 윈도우별로 특별한 데이터를 저정하기 위한 예약된 메모리 공간. 이쪽도 그렇게 잘 사용되지는 않음. 프로젝트 규모가 크거나 할때는 어느정도 쓰이나 규모가 작거나 복잡도가 낮은경우에는 거의 쓰일 일이 없음
    	WndClassEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    	WndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
    	WndClassEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    	WndClassEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    	WndClassEx.hInstance = hInstance;
    	WndClassEx.lpfnWndProc = WndProc;
    	WndClassEx.lpszClassName = lpszWndClass;
    	WndClassEx.lpszMenuName = NULL;
    	WndClassEx.style = CS_VREDRAW | CS_HREDRAW;
    	RegisterClassEx(&WndClassEx);
    
    	hWnd = CreateWindowEx(0, lpszWndClass, lpszWndClass, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, (HMENU)NULL, g_hInstance, NULL);
    	ShowWindow(hWnd, nCmdShow);
    
    	while (TRUE)
    	{
    		if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE))
    		{
    			if (Message.message == WM_QUIT)
    			{
    				break;
    			}
    			else
    			{
    				TranslateMessage(&Message);
    				DispatchMessage(&Message);
    			}
    		}
    		else
    		{
    			WaitMessage();
    		}
    	}
    
    	return (int)Message.wParam;
    }

    WndProc.cpp

    #include "WndProcs.h"
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
    {
    	HDC hdc;
    	PAINTSTRUCT PaintStruct;
    
    	OPENFILENAME OpenFileName;
    
    	switch (iMessage)
    	{
    	case WM_CREATE:
    		DragAcceptFiles(hWnd, TRUE);
    		OpenFileName.lStructSize = sizeof(OpenFileName);
    		OpenFileName.hwndOwner = hWnd;
    		OpenFileName.lpstrFilter = TEXT("모든 파일\0*.*\0");
    		OpenFileName.nMaxFile = MAX_PATH;
    		OpenFileName.nMaxFileTitle = MAX_PATH;
    		return 0;
    	case WM_PAINT:
    		hdc = BeginPaint(hWnd, &PaintStruct);
    		EndPaint(hWnd, &PaintStruct);
    		return 0;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0;
    	}
    
    	return DefWindowProc(hWnd, iMessage, wParam, lParam);
    }