1.Win32 API 프로그래밍 구조

#WinMain()

1)윈도우 구조체 설정, 등록

2)윈도우 생성과 출력

3)메시지 루프

: 프로그램이 종료될때까지

자신에게 보내진 메세지가 있는지 계속 확인하면서

받은 메세지가 있으면 전달함

 

#WndProc() 윈도우 프로시져

- 메시지 처리

- 메시지? => WM_xxx, CB_xxx, LM_xxx, PBM_xxx 등으로 모두 양의 값

 

윈도우 프로시져가 메세지를 처리하는 코드는 다음과 같다.

//프로시져의 메시지 처리 방식
switch(message)
{
	//각각의 메시지에 해당하는 처리
	case 메시지1:
    	break;
    case 메시지2:
    	break;
    case 메시지3:
    	break;
    
    //처리하지 않은 메시지에 대한 기본적인 처리
    default:
    	DefWndProc();
}

 

#메시지 전달과 처리 과정

 

-메시지 루프와 WndProc()

while( GetMessage(&msg, NULL, 0, 0))
//메시지를 큐를 검사하면서 해당 응용프로그램의 메세지가 있는지 체크한다
{
	TranslateMessage(&msg);//키보드 입력이 들어왔을때 어떤 문자가 눌렸는지 정보를 생성
    DispatchMessage(&msg);//메세지를 윈도우 프로시져에게 보내주고
    //윈도우 프로시져에게 처리되어 리턴된 값을 받아온다.
}

 

2. 프로젝트 생성, 문자집합

#멀티 바이트 문자 집합(MBCS)

- 1 ~ 2 Byte 크기의 문자 집합

(1 Byte로 표현할 수 없는 중국어, 일본어 등 지원)

- 영문과 한글 지원

- 일반 C함수는 MBCS 문자집합 사용

 

#유니코드 문자 집합

-2Byte로 전세계 언어를 표현하는 문자집합

-유니코드는 멀티바이트에 비해 메모리는

많이 차지하지만 처리속도는 더 빠름

-ASCII 코드 값의 일부는 유니코드와 같다. (문자, 숫자)

 

#문자 집합에 따른 데이터형 변환

-문자

TCHAR (ANSI,아스키) => CHAR(char)

TCHAR(Unicode) => WCHAR(wchar_t)

 

-문자열

LPTSTR(ANSI, 아스키) => LPSTR(char*)

LPTSTR(Unicode) => LPWSTR(wchar_t*)

 

-ANSI 문자열을 유니코드로 변환 매크로 함수, TEXT()

LPTSTR str = TEXT("문자열")

 

3. 윈도우 프로그래밍 기본 함수

#WinMain() 함수의 원형

#include<Windows.h>

#define WINAPI __stdcall

int WINAPI WinMain(HINSTANCE hInstance,
				   HINSTANCE hPrevInstance,
				   LPSTR IpCmdLine,
				   int nCmdShow){}

int APIENTRY _tWinMain() //Unicode 사용에 따라 달라지는 함수

- hInstance : 응용 프로그램 종류의 인스턴스 값

- hPrevInstance : 이전 인스턴스 값

- IpCmdLine : 프로그램 외부에서 내부로 값 설정

- nCmdShow : 윈도우 출력 형태에 관한 값

 

#WndProc() 함수의 원형

LRESULT CALLBACK WndProc(HWND hWnd,
	UINT message, WPARAM wParam,
	LPARAM lParam)
{
	return 0;
}

4. 윈도우 프로그래밍 WinMain() 작성 순서

 

#WinMain() 작성 순서 1단계, 구조체 설정

		WNDCLASSEX wcex;
	{
		wcex.cbSize = sizeof(WNDCLASSEX); //구조체의 크기
		wcex.style = CS_HREDRAW | CS_VREDRAW; //윈도우 이동 또는 크기가 가로세로 변할 때 윈도우 그리기
		wcex.lpfnWndProc = WndProc; //함수 포인터(호출하고자 하는 함수를 연결)
		wcex.cbClsExtra = 0; //여유분
		wcex.cbWndExtra = 0;
		wcex.hInstance = hInstance; //매개변수로 받은 인스턴스 값을 받음
		wcex.hIcon = LoadIcon(hInstance,
			MAKEINTRESOURCE(IDI_APPLICATION)); //아이콘
		//MAKEINTRESOURCE : 값을 양의 정수로 바꿔주는 매크로
		//IDI_APPLICATION : 기본 아이콘
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		//커서
		//IDC_ARROW : 기본 커서
		wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
		//배경
		//COLOR_WINDOW + 1 : 흰색
		wcex.lpszMenuName = NULL;
		//메뉴
		//NULL : 기본메뉴
		wcex.lpszClassName = (LPWSTR)"basic";
		//구조체를 OS에 등록할 때 이름
		wcex.hIconSm = LoadIcon(wcex.hInstance,
			MAKEINTRESOURCE(IDI_APPLICATION));
		//Sm(all)아이콘
	}

 

#WinMain() 작성 순서 2단계, 구조체 등록

	{
		RegisterClassEx(&wcex);
		//구조체 등록 매크로 함수, 매개 변수 : 구조체 주소
	}

 

#WinMain() 작성 순서 3단계, 윈도우 생성

	HWND hWnd;
	{
		hWnd = CreateWindow((LPCWSTR)"basic", (LPCWSTR)"HelloWorld",
			WS_OVERLAPPEDWINDOW,
			CW_USEDEFAULT,
			CW_USEDEFAULT,
			800, 600, NULL, NULL,
			hInstance, NULL);

		//#define CW_USEDEFAULT : 운영체제의 기본 위치값으로 설정
	}

 

#WinMain() 작성 순서 4단계, 윈도우 출력

	{
		ShowWindow(hWnd, nCmdShow);
		//윈도우 출력

		UpdateWindow(hWnd);
		//윈도우 업데이트

		//또는

		ShowWindow(hWnd, SW_SHOW);
		UpdateWindow(hWnd);
	}

 

#WinMain() 작성 순서 5단계, 메시지 루프

	{
		//# 메시지 루프를 구성하는 함수

		BOOL GetMessage(
			LPMSG lpMsg,
			HWND hWnd,
			UINT wMsgFilterMin,
			UINT wMsgFilterMax);
		//GetMessage()
		//메시지 큐에서 메시지를 가져오는 역할
		//WM_QUIT(완전히 프로그램을 빠져나갈때)가 발생할 때만 FALSE 리턴
		//그 외에는 TRUE 리턴


		BOOL TranslateMessage(const MSG * lpMsg);
		//문자 키 또는 키 입력에 대한 메시지 변환
		//WM_KEYDOWN => WM_CHAR


		LRESULT DispatchMessage(const MSG * lpMsg);
		//WndProc() 함수 호출
		//WndProc()가 종료될 때까지 대기
		//WndProc()로 메시지 전달

		//MSG 구조체
		typedef struct {
			HWND hwnd;
			UINT message; //메세지
			WPARAM wParam;//메시지와 함께 전달되는 정보
			LPARAM lParam;//메시지와 함께 전달되는 정보
			DWORD time;
			POINT pt;
		} MSG, *PMSG;

		//메시지 루프 전체 구조
		LPMSG msg;
		while (GetMessage(&msg, NULL, 0, 0))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

5. WndProc() 작성

# WndProc() 기본 메세지

-WM_PAINT

:최초 UpdateWindow() 함수에 의해 발생,

윈도우의 일부 영역을 새로 출력할 때 발생

 

-WM_DESTROY

:윈도우가 화면에서 사라진 후에 보내지는 메시지,

 메모리에서 제거되기 직전에 보내짐

 

# WndProc() 구성

LRESULT CALLBACK WndProc(HWND hWnd,
	UINT message, WPARAM wParam,
	LPARAM lParam)
{

	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps); //화면 그리기 준비

		EndPaint(hWnd, &ps); //화면 그리기 종료
		break;

	case WM_DESTROY:

		//메모리 해제에 대한 코드가 들어가는 곳//

		PostQuitMessage(0); //WM_QUIT 발생
		break;

	default:
		return DefWindowProc(hWnd, message,
			wParam, lParam);

		return 0;
	}

	return 0;

 

6. 자동 생성 (VS 2022 버전)

// Windows API_AUTO.cpp : 애플리케이션에 대한 진입점을 정의합니다.
//

#include "framework.h"
#include "Windows API_AUTO.h"

#define MAX_LOADSTRING 100

// 전역 변수:
HINSTANCE hInst;                                // 현재 인스턴스입니다.
WCHAR szTitle[MAX_LOADSTRING];                  // 제목 표시줄 텍스트입니다.
WCHAR szWindowClass[MAX_LOADSTRING];            // 기본 창 클래스 이름입니다.

// 이 코드 모듈에 포함된 함수의 선언을 전달합니다:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: 여기에 코드를 입력합니다.

    // 전역 문자열을 초기화합니다.
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_WINDOWSAPIAUTO, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // 애플리케이션 초기화를 수행합니다:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSAPIAUTO));

    MSG msg;

    // 기본 메시지 루프입니다:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  함수: MyRegisterClass()
//
//  용도: 창 클래스를 등록합니다.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWSAPIAUTO));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_WINDOWSAPIAUTO);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   함수: InitInstance(HINSTANCE, int)
//
//   용도: 인스턴스 핸들을 저장하고 주 창을 만듭니다.
//
//   주석:
//
//        이 함수를 통해 인스턴스 핸들을 전역 변수에 저장하고
//        주 프로그램 창을 만든 다음 표시합니다.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  함수: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  용도: 주 창의 메시지를 처리합니다.
//
//  WM_COMMAND  - 애플리케이션 메뉴를 처리합니다.
//  WM_PAINT    - 주 창을 그립니다.
//  WM_DESTROY  - 종료 메시지를 게시하고 반환합니다.
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // 메뉴 선택을 구문 분석합니다:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// 정보 대화 상자의 메시지 처리기입니다.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

#MyRegisterClass()

: 윈도우 구조체 설정 및 등록

 

#InitInstance()

: 윈도우 생성 및 출력

 

#About()

: 정보 대화 상자의 메시지 처리기, 애플리케이션 정보 같은 것들 표시

 

# HACCEL hAccelTable;

: 단축기에 대한 것

 

# LoadString()

: 문자열을 리소스를 다루기 위해, 문자열에 대한 아이디를 부여하고, 프로그램을 쓸 때

아이디를 이용해 문자열을 해당 배열에 복사한다.

아이디가 부여된 문자열, 그리고 그에 대한 값

솔루션 탐색기/리소스 파일/rc파일/String Table

경로에 저장 되어 있다.

 

위의 모든 내용은

유튜브 아워즈팜X나우캠퍼스, "Win32 API 2강. Win32 API 프로그래밍 구조",

'Win32 API' 카테고리의 다른 글

윈도우 프로그래밍 기초  (1) 2023.04.17

1. Win32 API 프로그래밍 개요

- Win32 API 프로그래밍이란?

윈도우 운영체제가 제공하는 함수를 이용한 C 언어 기반의 프로그래밍이다.

 

-프로그래밍 방식의 변화

윈도우 운영체제 이전

: 프로그래밍이 운영체제를 제어, 모든 프로그래밍을 프로그래머가 전담했다

키보드, 마우스 등을 직접 프로그래밍했다.

 

윈도우 운영체제 이후

:  키보드, 마우스 등이 운영체제에 드라이버의 형태로 모두 들어갔다,

운영체제가 응용 프로그램에 메시지를 보내줌으로써 모든 정보를 얻는다. 

 

2. 프로그래밍 구조 비교

-프로그래밍 형식의 변화

C: main()

=> WinMain() : 응용 프로그램 윈도우 생성

=> WinProc() : 메시지 처리

 

3. 윈도우 데이터형

윈도우의 데이터형은 아주 많다(MSDN에 검색하여 알 수 있다)

하지만 모든 데이터형을 외울 필요가 없고 자주 쓰이는 것들만 이번에 알아가보자.

윈도우의 데이터형은 기존 C의 데이터형을 윈도우 스타일로 재정의한 것이다.

데이터형 정의
BYTE typedef unsigned char BYTE;
BOOL typedef int BOOL;
CHAR typedef char CHAR;
COLORREF(색상을 저장하기 위한 데이터형) typedef DWORD COLORREF
DWORD typedef unsigned long DWORD
데이터형 정의
PVOID typedef void* PVOID;
HANDLE typedef PVOID HANDLE;
HDC typedef HANDLE HDC;
HGDIOBJ typedef HANDLE HGDIOBJ;
HINSTANCE typedef HANDLE HINSTANCE;
HWND typedef HANDLE HWND
LPVOID typedef void* LPVOID:
LPWORD typedef WORD* LPWORD;
데이터형 정의
LPSTR typedef CHAR* LPSTR;
LPWSTR typedef WCHAR *LPWSTR;
LPTSTR #ifdef UNICODE //유니코드를 사용하는 프로젝트에서...
     typedef LPWSTR LPTSTR;
#else //일반 아스키코드를 사용하는 프로젝트에서...
     typedef LPSTR LPTSTR;
#endif

TCHAR #ifdef UNICODE
    typedef WCHAR TCHAR;
#else
    typedef char TCHAR;
데이터형 정의
UINT typedef unsigned int UINT;
VOID #define VOID void
WINAPI #define WINAPI __stdcall
WORD typedef unsigned short WORD;
0 ~ 65535
WPARAM typedef UINT_PTR WPARAM;
UINT_PTR #if defined(_WIN64) //64비트 운영체제
    typedef unsigned __int64 UINT_PTR
#else
    typedef unsigned int UINT_PTR
LPARAM typedef LONG_PTR LPARAM;
LONG_PTR #if defined(_WIN64)
    typedef __int64 LONG_PTR;
#else
    typedef long LONG_PTR;
#endif

 

4. 인스턴스와 핸들

운영체제는 멀티 태스킹 운영체제이다.

같은 메모장에 다른 데이터가 들어가 있다.

이 응용 프로그램들을 운영체제는 어떻게 다루고 구분하는가?

=> 인스턴스(Instance)와 핸들(Handle)

 

-인스턴스와 핸들의 실체?

HINSTANCE, HWND => HANDLE이고

HANDLE => PVOID,

PVOID => void* : 4 바이트의 양의 정수값

 

#인스턴스란 무엇인가?

-응용프로그램의 아이디(절대 중복되지 않는다.)

-같은 종류의 프로그램은 같은 인스턴스를 가진다.

ex) 메모장의 인스턴스가 14745600이라면

메모장 창이 여러 개 켜져 있을 때 그것들의 인스턴스는 모두 14745600이다.

 

#핸들이란 무엇인가?

-운영체제에서 할당한 자원의 아이디

-같은 종류의 응용 프로그램이라 할지라도

창마다 다른 핸들을 가진다.

#공통점

1) 운영체제에서 할당하는 값

2) 중복되지 않는 값 => 아이디의 속성

 

#윈도우 프로그래밍에서 가장 중요한 핸들

앞에 H가 붙는 데이터형은 전부 핸들이다.

HWND, HDC, HPEN, HBRUSH 등 => void*

 

5. 헝가리안 표기법

#헝가리안 표기법이란 무엇인가?

변수, 함수명의 명명 규칙이다.

변수명만으로 용도 파악이 용이

 

#규칙

1)의미 있는 단어를 연결하고 첫 문자는 대문자로 사용한다

2)데이터형을 의미하는 접두사를 붙인다 ex) fCount, nNumber(i'n't)

데이터형 접두사
BOOL, bool b
char ch, c
int, short i, n
long l
float f
double d
배열 a
DWORD dw
문자열 sz, s, str
포인터 p
핸들 h
전역변수 g_
ex) g_nVariable
윈도우 메시지 msg

 

위의 모든 내용은

유튜브 아워즈팜X나우캠퍼스, "Win32 API 1강. Win32 API 프로그래밍 구조",

 

 

'Win32 API' 카테고리의 다른 글

Win32 API 프로그래밍 구조  (0) 2023.04.18

+ Recent posts