본문 바로가기

Application Programming Interface/Windows API

갈아만든 Windows API - #1. 도스와는 많이 다른 윈도우 프로그램

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

- #1. 도스와는 많이 다른 윈도우 프로그램 –

 Windows 프로그래밍은 도스에서 하던 것과는 다릅니다. 그것도 심하게. 확연히. 도스와 Windows의 가장 근본적인 차이는 바로 Multi-Tasking! 여러 프로그램이 동시에 실행된다는 것이죠.

 제가 공부하면서 느꼈던 Windows 프로그래밍은 위와 같다고나 할까요?
도스 프로그래밍에서 자주 등장하는 공통된 내용이 "내가 직접 루프 구문 돌려서 배열 처리하는 거"였다면,
윈도우 프로그래밍에서는 "항상 긴장하고 있다가 어디서 튀어나올 지 모르는 탁구공(=메시지)을 받아 쳐야 하는" 것 같습니다.
매우 길어지고 많아진 온갖 파라미터들은 말할 것도 없죠. 후덜덜……

/* winmain.c */
#include <windows.h>

HINSTANCE g_hInstance;
TCHAR szClassName[] = TEXT("TAPITO WinAPI Example");
TCHAR szWindowName[] = TEXT("TAPITO Windows API Example #1");

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    HWND hWnd;
    MSG msg;
    WNDCLASS WndClass;

    g_hInstance = hInstance;

    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;
    WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hInstance = hInstance;
    WndClass.lpfnWndProc = WndProc;
    WndClass.lpszClassName = szClassName;
    WndClass.lpszMenuName = NULL;
    WndClass.style = CS_HREDRAW | CS_VREDRAW;

    RegisterClass(&WndClass);

    hWnd = CreateWindow(
        szClassName,
        szWindowName,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        (HWND)NULL,
        (HMENU)NULL,
        hInstance,
        (LPVOID)NULL
        );

    ShowWindow(hWnd, nShowCmd);

    while(GetMessage(&msg, (HWND)NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
    LRESULT ret;

    switch(uMessage)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        ret = 0;
        break;

    default:
        ret = DefWindowProc(hWnd, uMessage, wParam, lParam);
        break;
    }

    return ret;
}

1. WinMain

원형

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);

설명

도스의 main함수처럼 윈도우 프로그램의 진입점입니다.

매개변수

hInstance[IN]

실행되기 위하여 메모리로 올라온 기계어 덩어리를 나타내는 고유 번호입니다. 창이 아닌 명령어 덩어리 그 자체를 식별한다는 것에서 윈도우 핸들(HWND)과는 다르죠. 예를 들어 메모장 프로그램(notepad.exe)을 여러 개 띄운다면 각각의 창에 부여되는 핸들은 다 다르지만 notepad.exe라는 프로그램 자체에 부여된 핸들은 일정하다는 겁니다. 개념적인 이미지로 표현하면 아래와 같습니다.

보시는 바와 같이 NOTEPAD.EXE는 아이콘과 커서, 이미지로 구성된 "리소스"와 텍스트의 입/출력 및 UI를 담당하는 기계어 부분으로 나뉘어 있을 거란 말이죠.

이 명령 덩어리들이 실행되기 위해 메모리로 올라와 한 자리를 차지한다면? 운영체제에서는 이 덩어리에 ID를 부여합니다. 그리고 창이 계속 늘어나도 프로그램은 notepad.exe로 동일하니까 hInstance 또한 같은 기계어 덩어리를 참조하게 될 것입니다. 실제로 Spy++로 확인해 본 결과도 그렇습니다.

hPrevInstance [IN]

이건 Win16 API에서 쓰던 거라 지금은 항상 NULL이며 무시한다고 합니다. 옛날에는 메모리의 크기가 작았기 때문에 이 프로그램이 실행되기 직전의 윈도우하고 메모리를 공유하기 위해 쓰던 매개변수라고 합니다.

lpCmdLine [IN]

main 함수에서 argv와 같은 겁니다.

nShowCmd [IN]

열게 될 창의 크기가 지정됩니다.

상수 명

SW_HIDE

창을 완전히 숨깁니다.

SW_MAXIMIZE

지정된 창을 최대화합니다.

SW_MINIMIZE

지정된 창을 최소화합니다.

SW_RESTORE

원래 크기로 창을 엽니다. SW_SHOW와 다른 점은 창이 이미 최소화/최대화 되어 있더라도 이를 원래 크기로 복원한다는 것입니다.

SW_SHOW

창이 유지하던 있는 크기와 위치 그대로 화면에 보입니다.

SW_SHOWMAXIMIZED

창을 활성화하고 최대화합니다.

SW_SHOWMINIMIZED

창을 활성화하고 최소화합니다.

SW_SHOWMINNOACTIVE

대상 창을 최소화하지만 포커스는 두지 않습니다.

SW_SHOWNA

대상 창에 포커스를 안 둔다는 것 외에는 SW_SHOW와 동일합니다.

SW_SHOW_NOACTIVATE

가장 최근 변경된 크기와 위치로 창을 보여주되 포커스는 두지 않습니다.

SW_SHOWNORMAL

창을 활성화하고 원래의 크기와 위치로 복원시킵니다.

(응용프로그램이 처음 실행될 때 이 속성이 부여됩니다.)