본문 바로가기

Win32 API

17. Win32 API - Win32 클래스화(1 - 전체 코드)

이미지 출력 예제에 대한 클래스화 진행 내용입니다.

 

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 선택

Image File 선택

 

  • 출력

이미지 출력

 

5. 참조

https://github.com/microsoft/Windows-classic-samples/tree/main/Samples/Win7Samples/multimedia/wic/wicanimatedgif

 

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