이미지 출력 예제에 대한 클래스화 진행 내용입니다.
1. PCH
#framework.h
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // 거의 사용되지 않는 내용을 Windows 헤더에서 제외합니다.
// Windows 헤더 파일
#include <windows.h>
// C 런타임 헤더 파일입니다.
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <windowsx.h>
#include <wincodec.h>
#include <commdlg.h>
#include <d2d1.h>
#pragma comment(lib, "D2D1.lib")
using namespace D2D1;
#define SetFRect(x, l, t, r, b){ x.left = (float)(l); x.top = (float)(t); x.right = (float)(r); x.bottom = (float)(b);}
#define SetFPos(pt, x_pos, y_pos){ pt.x = (FLOAT)x_pos; pt.y = (FLOAT)y_pos; }
template<class Interface>
inline void CustomRelease(Interface** ap_interface_object)
{
if (*ap_interface_object != NULL)
{
(*ap_interface_object)->Release();
(*ap_interface_object) = NULL;
}
}
// pch.h: 미리 컴파일된 헤더 파일입니다.
// 아래 나열된 파일은 한 번만 컴파일되었으며, 향후 빌드에 대한 빌드 성능을 향상합니다.
// 코드 컴파일 및 여러 코드 검색 기능을 포함하여 IntelliSense 성능에도 영향을 미칩니다.
// 그러나 여기에 나열된 파일은 빌드 간 업데이트되는 경우 모두 다시 컴파일됩니다.
// 여기에 자주 업데이트할 파일을 추가하지 마세요. 그러면 성능이 저하됩니다.
#ifndef PCH_H
#define PCH_H
// 여기에 미리 컴파일하려는 헤더 추가
#include "framework.h"
#endif //PCH_H
미리 컴파일된 헤더 파일입니다.
몇개의 define과 장치를 Release할 함수를 정의했습니다.
2. CustomWinApp.h
#ifndef _CustomWinApp_H_
#define _CustomWinApp_H_
#include "pch.h"
#include "resource.h"
class CustomWinApp
{
public:
CustomWinApp();
~CustomWinApp();
BOOL GetFileOpen(WCHAR* pszFileName, DWORD cchFileName);
HRESULT Initialize(HINSTANCE hInstance);
private:
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK s_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void OnPaint();
void OnCreate();
void OnTimer(UINT a_timer_id);
void OnDestroy();
int MakeD2D1_Bitmap(IWICBitmapFrameDecode* ap_image_frame,
ID2D1HwndRenderTarget* ap_target, ID2D1Bitmap** ap_bitmap);
int CustomLoadImage(ID2D1HwndRenderTarget* ap_target, ID2D1Bitmap** ap_bitmap);
void ResizeWindow(int, int);
void SetHandle(HWND hWnd)
{
m_hWnd = hWnd;
}
private:
HWND m_hWnd;
ID2D1Factory* m_pD2DFactory;
ID2D1HwndRenderTarget* m_pHwndRT;
ID2D1BitmapRenderTarget* m_pFrameComposeRT;
ID2D1Bitmap* m_bitmap;
D2D1_COLOR_F m_backgroundColor;
IWICBitmapDecoder* m_pDecoder; // 압축된 이미지를 해제할 객체
IWICBitmapFrameDecode* m_pFrame; // 특정 그림을 선택한 객체
IWICImagingFactory* m_pIWICFactory;
D2D1_RECT_F m_image_rect;
D2D1_POINT_2F m_center_pos;
float m_degree;
RECT client_rect;
RECT win_rect;
};
#endif
사용할 WindowApp의 선언부입니다.
3. CustomWinApp.cpp
#include "pch.h"
#include "CustomWinApp.h"
CustomWinApp::CustomWinApp()
: m_hWnd(NULL)
, m_pD2DFactory(NULL)
, m_pHwndRT(NULL)
, m_pFrameComposeRT(NULL)
, m_bitmap(NULL)
, m_pIWICFactory(NULL)
, m_pDecoder(NULL)
, m_degree(0.0f)
{
SetFRect(m_image_rect, 0, 0, 0, 0);
SetFPos(m_center_pos, 0, 0);
}
CustomWinApp::~CustomWinApp()
{
CustomRelease(&m_pD2DFactory);
CustomRelease(&m_pHwndRT);
CustomRelease(&m_pFrameComposeRT);
CustomRelease(&m_bitmap);
CustomRelease(&m_pDecoder);
CustomRelease(&m_pFrame);
CustomRelease(&m_pIWICFactory);
}
BOOL CustomWinApp::GetFileOpen(WCHAR* pszFileName, DWORD cchFileName)
{
pszFileName[0] = L'\0';
OPENFILENAME ofn;
RtlZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = m_hWnd;
ofn.lpstrFilter = L"All Files\0*.*\0\0";
ofn.lpstrFile = pszFileName;
ofn.nMaxFile = cchFileName;
ofn.lpstrTitle = L"Select an image to display...";
ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
// Display the Open dialog box.
return GetOpenFileName(&ofn);
}
int CustomWinApp::MakeD2D1_Bitmap(IWICBitmapFrameDecode* ap_image_frame,
ID2D1HwndRenderTarget* ap_target, ID2D1Bitmap** ap_bitmap)
{
IWICFormatConverter* p_converter;
int result = 0;
if (S_OK == m_pIWICFactory->CreateFormatConverter(&p_converter))
{
if (S_OK == p_converter->Initialize(ap_image_frame, GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom))
{
if (S_OK == ap_target->CreateBitmapFromWicBitmap(p_converter, NULL, ap_bitmap))
{
result = 1;
}
}
CustomRelease(&p_converter);
}
return result;
}
int CustomWinApp::CustomLoadImage(ID2D1HwndRenderTarget* ap_target, ID2D1Bitmap** ap_bitmap)
{
WCHAR szFileName[MAX_PATH];
int result = 0; // 그림 파일을 읽은 결과 값 (0이면 그림 읽기 실패, 1이면 그림 읽기 성공)
if (GetFileOpen(szFileName, ARRAYSIZE(szFileName)))
{
if (S_OK == m_pIWICFactory->CreateDecoderFromFilename(
szFileName,
NULL,
GENERIC_READ,
WICDecodeMetadataCacheOnDemand,
&m_pDecoder
))
{
if (S_OK == m_pDecoder->GetFrame(0, &m_pFrame))
{
result = MakeD2D1_Bitmap(m_pFrame, ap_target, ap_bitmap);
CustomRelease(&m_pFrame);
}
CustomRelease(&m_pDecoder);
}
}
return result;
}
LRESULT CustomWinApp::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_PAINT:
{
OnPaint();
return 0;
}
case WM_CREATE:
{
SetHandle(hWnd);
OnCreate();
return 0;
}
case WM_TIMER:
{
OnTimer(wParam);
return 0;
}
case WM_DESTROY:
OnDestroy();
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK CustomWinApp::s_WndProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
CustomWinApp* pThis = NULL;
LRESULT lRet = 0;
if (uMsg == WM_NCCREATE)
{
LPCREATESTRUCT pcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
pThis = reinterpret_cast<CustomWinApp*>(pcs->lpCreateParams);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
lRet = DefWindowProc(hWnd, uMsg, wParam, lParam);
}
else
{
pThis = reinterpret_cast<CustomWinApp*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
if (pThis)
{
lRet = pThis->WndProc(hWnd, uMsg, wParam, lParam);
}
else
{
lRet = DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
return lRet;
}
void CustomWinApp::ResizeWindow(int a_width, int a_height)
{
::GetClientRect(m_hWnd, &client_rect);
::GetWindowRect(m_hWnd, &win_rect);
SetWindowPos(
m_hWnd,
NULL,
0,
0,
win_rect.right - win_rect.left + a_width - client_rect.right,
win_rect.bottom - win_rect.top + a_height - client_rect.bottom,
SWP_NOMOVE
);
}
void CustomWinApp::OnPaint()
{
m_pHwndRT->BeginDraw();
m_pHwndRT->Clear(ColorF(0.0f, 0.8f, 1.0f));
if (m_bitmap != NULL)
{
m_pHwndRT->SetTransform(Matrix3x2F::Rotation(m_degree, m_center_pos));
m_pHwndRT->DrawBitmap(m_bitmap, &m_image_rect);
}
m_pHwndRT->EndDraw();
}
void CustomWinApp::OnCreate()
{
GetClientRect(m_hWnd, &client_rect);
m_pD2DFactory->CreateHwndRenderTarget(RenderTargetProperties(),
HwndRenderTargetProperties(m_hWnd, SizeU(client_rect.right, client_rect.bottom)),
&m_pHwndRT);
if (1 == CustomLoadImage(m_pHwndRT, &m_bitmap))
{
D2D1_SIZE_F image_size = m_bitmap->GetSize();
if (m_image_rect.right != image_size.width || m_image_rect.bottom != image_size.height)
{
m_pHwndRT->Resize(SizeU((UINT)image_size.width, (UINT)image_size.height));
ResizeWindow((UINT)image_size.width, (UINT)image_size.height);
SetFRect(m_image_rect, 0, 0, image_size.width, image_size.height);
SetFPos(m_center_pos, image_size.width / 2, image_size.height / 2);
}
SetTimer(m_hWnd, 1, 50, NULL);
}
}
void CustomWinApp::OnTimer(UINT a_timer_id)
{
if (a_timer_id == 1)
{
m_degree = m_degree + 0.5f;
if (m_degree >= 360)
{
m_degree = 0.0f;
}
InvalidateRect(m_hWnd, NULL, FALSE);
}
}
void CustomWinApp::OnDestroy()
{
KillTimer(m_hWnd, 1);
CustomRelease(&m_pHwndRT);
PostQuitMessage(0);
}
HRESULT CustomWinApp::Initialize(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = s_WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32STUDY));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = 0;
wcex.lpszClassName = TEXT("WIN32_STUDY");
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
HRESULT hr = (RegisterClassExW(&wcex) == 0) ? E_FAIL : S_OK;
if (SUCCEEDED(hr))
{
// Create D2D factory
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);
}
if (SUCCEEDED(hr))
{
// Create WIC factory
hr = CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&m_pIWICFactory));
}
if (SUCCEEDED(hr))
{
// Create window
m_hWnd = CreateWindow(
TEXT("WIN32_STUDY"),
TEXT("WIN32_STUDY_WINDOW"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
this);
hr = (m_hWnd == NULL) ? E_FAIL : S_OK;
}
if (SUCCEEDED(hr))
{
ShowWindow(m_hWnd, SW_SHOW);
UpdateWindow(m_hWnd);
}
else if (FAILED(hr) && m_hWnd != NULL)
{
DestroyWindow(m_hWnd);
}
return hr;
}
사용할 WindowApp의 정의부입니다.
4. 사용 예시
- 실행 시 File 선택
- 출력
5. 참조
Windows-classic-samples/Samples/Win7Samples/multimedia/wic/wicanimatedgif at main · microsoft/Windows-classic-samples
This repo contains samples that demonstrate the API used in Windows classic desktop applications. - microsoft/Windows-classic-samples
github.com
https://blog.naver.com/tipsware/221133045626
Win32 프로그램을 클래스화 하기 - 4단계
: Win32 프로그래밍 관련 전체 목차 http://blog.naver.com/tipsware/221059977193...
blog.naver.com
'Win32 API' 카테고리의 다른 글
18. Win32 API - Win32 클래스화(2 - 설명) (0) | 2024.03.27 |
---|---|
16. Win32 API - Direct2D (0) | 2024.03.16 |
15. Win32 API - GDI+ (0) | 2024.03.16 |
14. Win32 API - StockObject (0) | 2024.03.09 |
13. Win32 API - 윈도우 좌표 (0) | 2024.03.09 |