황동준님의 윈도우 32비트 프로그래밍 31~35

  윈도우 32비트 프로그래밍 31

안녕하세요…..돌팔이 황동준입니다……………

이번시간에는 저번시간에 만든 프로그램을 분석해 보겠습니다. 뭐 별로 그렇게 어려운 부분은
없을 겁니다.

case WM_CREATE :

    dwID = Open(hWnd);
    return 0;

MCI 장치를 여는 방법에는 차이가 없습니다.

case MM_MCINOTIFY :

이 메시지 처리하는 부분이 바꾸었군요. 이미 앞에서 원리는 설명 드렸을 겁니다. 메뉴
아이템중 Pause가 선택되었다면 플레이된 현재 위치를 얻어서 그 위치로 플레이 위치를 세팅하는 과정이 바로 아래 부분입니다.

    if(bPause)
    {
        SetCurrentPosition(hWnd,
dwID,
            MoveStartCurrentPosition(hWnd, dwID));
        bPause =
FALSE;

각 함수에 대한것은 아래 부분에서 설명 드리겠습니다.

    }
    else
        MoveStartPosition(hWnd,
dwID);

이 함수는 이미 웨이브 파일을 플레이할때 설명 드렸던 함수입니다. 기억 납니까?

    return 0;

case WM_COMMAND :

    switch(LOWORD(wParam))
    {
        case
100 :

            Play(hWnd,
dwID);
            break;

        case 200 :

            Pause(hWnd,
dwID);
            bPause = TRUE;
            break;

        case 300 :

            Play(hWnd,
dwID);
            break;

Resume이 선택되었을때 그냥 플레이하는 함수를 사용했습니다. 플레이될 위치를 지정했기
때문에 그 부분부터 플레이가 되죠.

        case 400 :

            Stop(hWnd,
dwID);
            break;
    }
    return 0;

case WM_DESTROY :

    Close(hWnd,
dwID);
    PostQuitMessage(0);
    return 0;

나머지 부분은 크게 다른점이 없습니다. 그러면 새롭게 나온 두 함수에 대해
알아봅시다.

DWORD MoveStartCurrentPosition(HWND hWnd, DWORD
dwID)
{

이 함수는 현재 플레이된 위치를 반환하는 역할을 합니다.

    MCI_STATUS_PARMS
mciStatusParms;
    MCIERROR mciError;

    mciStatusParms.dwItem =
MCI_STATUS_POSITION;
    mciError = mciSendCommand(dwID, MCI_STATUS,
MCI_STATUS_ITEM,
        (DWORD)&mciStatusParms);

위 구문은 이미 앞에서 예로 알아본 구문과 같죠?

    if(mciError)
        MessageBox(hWnd,
“Status Position Error!!”, “Error”, MB_OK);
    return
mciStatusParms.dwReturn;

현재 위치를 반환하고 있습니다.

}

void SetCurrentPosition(HWND hWnd, DWORD dwID,
DWORD dwPos)
{
    MCI_SEEK_PARMS mciSeekParms;
    MCIERROR
mciError;

    mciSeekParms.dwTo = dwPos;

파라미터로 지정되는 값을 dwTo에 저장하고 있습니다. 플레이될 위치를 지정하기 위한
과정입니다.

    mciError = mciSendCommand(dwID, MCI_SEEK,
MCI_TO, (DWORD)&mciSeekParms);

이것도 이미 설명드렸을 겁니다.

    if(mciError)
        MessageBox(hWnd, “Set
Length Format Error!!”, “Error”, MB_OK);
}

크게 어려운 점은 없을 겁니다. 그러면 이번에는 CD 플레이어를 어떻게 구현하는지 알아보도록
하겠습니다. 비록 간단한 CD 플레이어래도 기본적인 것들은 있어야 할 겁니다. 플레이, 중단, 임시중단, 다시 재생, 다음곡, 이전곡 등을
구현하면 되겠네요. 그러면 본격적으로 알아 봅시다.

우리가 앞에서 알아본 웨이브 파일, 미디 파일은 파일명을 지정해서 플레이 해주면 됐지만 CD
플레이어는 파일이 없습니다. 그렇죠? 그러기 때문에 MCI 장치 여는 과정이 조금 다릅니다. 우리는 장치를 열때 lpstrDeviceType에
장치 이름을 지정해 주었는데 CD 플레이어는 장치 이름으로 cdaudio를 지정해 주면 됩니다. 그리고 한 가지 작업을 더 했죠? 그것은
lpstrElementName에 파일 이름을 지정해 주었다는 것입니다. 그러나 CD 플레이어에서는 파일 이름을 지정하는 과정을 하지 않아도
됩니다. 당연한 얘기죠. 그리고 우리는 장치를 열기 위해서 mciSendCommand() 함수를 사용했을 겁니다. 그리고 이 함수의 세번째
파라미터로 MCI_OPEN_TYPE|MCI_OPEN_ELEMENT를 지정했는데 이 부분에서 MCI_OPEN_ELEMENT를 빼주고
MCI_OPEN_TYPE만 지정해 주면 됩니다. 왜냐하면 파일 이름이 없기 때문입니다. 그리고 해주어야 할 작업은 길이 단위를 세팅하는
작업입니다. 우리가 앞에서 알아본 웨이브 파일이나 미디 파일은 그 단위가 그렇게 중요한 문제가 되지 않았으나 CD 플레이어 같은 경우에는
중요합니다. 왜냐하면 다음곡을 플레이하거나 이전 곡을 플레이할 때이 단위로 이동해야 되기 때문이죠. 물론 이 단위는 트랙단위입니다. 역시 세팅할
때 사용하는 함수는 mciSendCommand() 함수입니다. 그리고 마지막 파라미터에 MCI_SET_PARMS라는 구조체 변수의 주소를 지정해
주어야 합니다.

typedef struct {
    DWORD
 dwCallback;
    DWORD  dwTimeFormat;
    DWORD  dwAudio;
}
MCI_SET_PARMS;

위 구조체 변수의 멤버중 dwTimeFormat에 MCI_FORMAT_TNSF라는 예약어를
지정해 주고 mciSendCommand() 함수를 사용하면 됩니다. 바로 아래 처럼 사용하면 되죠.

mciSetParms.dwTimeFormat =
MCI_FORMAT_TMSF;
mciError = mciSendCommand(dwID, MCI_SET,
MCI_SET_TIME_FORMAT,
    (DWORD)&mciSetParms);

이 부분까지 됐으면 그 다음부터는 미디 파일을 플레이할 때와 같습니다. 즉 잠시 중단했다가
다시 재생하는 부분의 처리 방식이 미디 파일 할 때와 같습니다. 즉 Resume() 기능을 Play()함수로 구현한다는 것입니다. 그러면 우리가
여기서 추가해서 알아볼 것은 바로 다음 곡의 플레이와 이전 곡의 플레이인데 구현의 원리는 간단합니다. 다음 곡 같은 경우는 먼저 Pause를
시키고 현재 트랙 번호를 얻어서 그 값을 증가시켜 위치를 옮기면 됩니다. 그리고 Play하면 되죠. 이전 곡 같은 경우는 감소시키면 되죠.
그런데 만약에 CD 음악이 총 10개의 음악으로 되어 있는데 하나를 증가시켜 트랙위치가 11이 된다면 어떤 일이 발생할까요? 위치를 세팅할 때
에러가 발생합니다. 그러면 간단하죠. 에러 체크하는 루틴에 현재 트랙위치로 고정하는 구문이 있으면 됩니다. 그러면 10번째 음악다음에 다음 곡을
선택해도 계속 10번째 음악이 나오는 거죠. 물론 이 부분은 여러분들이 나름대로 수정해서 구현하면 됩니다. 자 그러면 구체적인 구현의 방법을
봅시다. 현재 트랙번호를 얻는 과정을 할 때에 사용하는 구조체 변수는 앞에서 알아 본 MCI_STATUS_PARMS입니다. 이 구조체 멤버중
dwItem에 MCI_STAUS_CURRENT_TRACK을 지정하고 mciSendCommand() 함수를 사용하면 됩니다. 아래처럼 하면
되죠.

mciStatusParms.dwItem =
MCI_STATUS_CURRENT_TRACK;
mciError = mciSendCommand(dwID, MCI_STATUS,
MCI_STATUS_ITEM,
    (DWORD)&mciStatusParms);

에러가 발생하지 않고 성공적으로 되었다면 mciStatusParms.dwReturn에 현재
트랙이 저장됩니다. 우리는 이 값을 증가시키거나 감소시켜서 다음 곡으로 이동할 수도 있고 이전 곡으로 이동할 수도 있습니다.

이동이 됐으면 이 부분으로 플레이 위치를 세팅해 주어야 할겁니다. 이 부분은 이미 앞에서 다
한 부분입니다. 그러면 실제로 간단하게 CD 음악을 연주하는 프로그램을 만들어 봅시다.

MyMenu MENU
BEGIN
    POPUP
“&CD”
    BEGIN
        MENUITEM “&Play”, 100
        MENUITEM
“&Next”, 200
        MENUITEM “&Prev”, 300
        MENUITEM
“P&ause”, 400
        MENUITEM “&Resume”, 500
        MENUITEM
“&Stop”, 600
    END
END

#include <windows.h>
#include
<string.h>
#include <mmsystem.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);
DWORD Open(HWND hWnd);
void Play(HWND hWnd, DWORD dwID);
void
Stop(HWND hWnd, DWORD dwID);
void Pause(HWND hWnd, DWORD dwID);
void
Close(HWND hWnd, DWORD dwID);
void MoveStartPosition(HWND hWnd, DWORD
dwID);
DWORD MoveStartCurrentPosition(HWND hWnd, DWORD dwID);
void
SetCurrentPosition(HWND hWnd, DWORD dwID, DWORD dwPos);
void SetFormat(HWND
hWnd, DWORD dwID);
DWORD MoveNextTrack(HWND hWnd, DWORD dwID);
DWORD
MovePrevTrack(HWND hWnd, DWORD dwID);

int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
        static
char szAppName[] = “Multimedia Example”;
        HWND hWnd;
        MSG
msg;
        WNDCLASS WndClass;

        WndClass.style =
CS_HREDRAW|CS_VREDRAW;
        WndClass.lpfnWndProc =
WndProc;
        WndClass.cbClsExtra = 0;
        WndClass.cbWndExtra =
0;
        WndClass.hInstance = hInstance;
        WndClass.hIcon =
LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(NULL,
IDC_ARROW);
        WndClass.hbrBackground =
GetStockObject(WHITE_BRUSH);
        WndClass.lpszMenuName =
“MyMenu”;
        WndClass.lpszClassName =
szAppName;
        if(!RegisterClass(&WndClass))
                return
FALSE;

        hWnd =
CreateWindow(
                szAppName,
                szAppName,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL
        );

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

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

        return msg.wParam;
}

LRESULT CALLBACK
WndProc(HWND hWnd, UINT
message, WPARAM wParam, LPARAM lParam)
{
        static DWORD
dwID;
        static BOOL bPause, bNext, bPrev;

        switch(message)
        {
            case
WM_CREATE :

                dwID =
Open(hWnd);
                SetFormat(hWnd, dwID);
                return
0;

            case MM_MCINOTIFY :

                if(bPause)
                {
                    SetCurrentPosition(hWnd,
dwID,
                        MoveStartCurrentPosition(hWnd,
dwID));
                    bPause =
FALSE;
                }
                else
if(bNext)
                {
                    SetCurrentPosition(hWnd,
dwID,
                        MoveNextTrack(hWnd,
dwID));
                    bNext = FALSE;
                    Play(hWnd,
dwID);
                }
                else
if(bPrev)
                {
                    SetCurrentPosition(hWnd,
dwID,
                        MovePrevTrack(hWnd,
dwID));
                    bPrev = FALSE;
                    Play(hWnd,
dwID);
                }
                else
           

         MoveStartPosition(hWnd,
dwID);
                return 0;

            case WM_COMMAND :

                switch(LOWORD(wParam))
                {
                    case
100 :

                        Play(hWnd,
dwID);
                        break;

                    case 200 :

                        Pause(hWnd,
dwID);
                        bNext =
TRUE;
                        break;

                    case 300 :

                        Pause(hWnd,
dwID);
                        bPrev =
TRUE;
                        break;

                    case 400 :

                        Pause(hWnd,
dwID);
                        bPause =
TRUE;
                        break;

                    case 500 :

                        Play(hWnd,
dwID);
                        break;

                    case 600 :

                        Stop(hWnd,
dwID);
                        break;
                }
                return
0;

            case WM_DESTROY :

                Close(hWnd,
dwID);
                PostQuitMessage(0);
                return
0;
        }
        return DefWindowProc(hWnd, message, wParam,
lParam);
}

DWORD Open(HWND hWnd)
{
    MCI_OPEN_PARMS
mciOpenParms;
    MCIERROR mciError;

    mciOpenParms.lpstrDeviceType = “cdaudio”;

    mciError = mciSendCommand(NULL, MCI_OPEN,
MCI_OPEN_TYPE,
        (DWORD)&mciOpenParms);
    if(mciError)
        MessageBox(hWnd,
“Open Error!!”, “Error”, MB_OK);
    return mciOpenParms.wDeviceID;
}

void Play(HWND hWnd, DWORD
dwID)
{
    MCI_PLAY_PARMS mciPlayParms;
    MCIERROR mciError;

    mciPlayParms.dwCallback =
(DWORD)hWnd;
    mciError = mciSendCommand(dwID, MCI_PLAY,
MCI_NOTIFY,
        (DWORD)&mciPlayParms);
    if(mciError)
        MessageBox(hWnd,
“Play Error!!”, “Error”, MB_OK);
}

void Stop(HWND hWnd, DWORD
dwID)
{
    MCI_GENERIC_PARMS mciGenericParms;
    MCIERROR
mciError;

    mciError = mciSendCommand(dwID, MCI_STOP,
MCI_WAIT,
        (DWORD)&mciGenericParms);
    if(mciError)
        MessageBox(hWnd,
“Stop Error!!”, “Error”, MB_OK);
}

void Pause(HWND hWnd, DWORD
dwID)
{
    MCI_GENERIC_PARMS mciGenericParms;
    MCIERROR
mciError;

    mciError = mciSendCommand(dwID, MCI_PAUSE,
MCI_WAIT,
        (DWORD)&mciGenericParms);
    if(mciError)
        MessageBox(hWnd,
“Pause Error!!”, “Error”, MB_OK);
}

void Close(HWND hWnd, DWORD
dwID)
{
    MCI_GENERIC_PARMS mciGenericParms;
    MCIERROR
mciError;

    mciError = mciSendCommand(dwID, MCI_CLOSE,
MCI_WAIT,
        (DWORD)&mciGenericParms);
    if(mciError)
        MessageBox(hWnd,
“Resume Error!!”, “Error”, MB_OK);
}

void SetFormat(HWND hWnd, DWORD
dwID)
{
    MCI_SET_PARMS mciSetParms;
    MCIERROR mciError;

    mciSetParms.dwTimeFormat =
MCI_FORMAT_TMSF;
    mciError = mciSendCommand(dwID, MCI_SET,
MCI_SET_TIME_FORMAT,
        (DWORD)&mciSetParms);
    if(mciError)
        MessageBox(hWnd,
“Resume Error!!”, “Error”, MB_OK);
}

void MoveStartPosition(HWND hWnd, DWORD
dwID)
{
    MCI_SEEK_PARMS mciSeekParms;
    MCIERROR mciError;

    mciError = mciSendCommand(dwID, MCI_SEEK,
MCI_SEEK_TO_START,
        (DWORD)&mciSeekParms);
    if(mciError)
        MessageBox(hWnd,
“Set Length Format Error!!”, “Error”, MB_OK);
}

DWORD MoveStartCurrentPosition(HWND hWnd, DWORD
dwID)
{
    MCI_STATUS_PARMS mciStatusParms;
    MCIERROR mciError;

    mciStatusParms.dwItem =
MCI_STATUS_POSITION;
    mciError = mciSendCommand(dwID, MCI_STATUS,
MCI_STATUS_ITEM,
        (DWORD)&mciStatusParms);
    if(mciError)
        MessageBox(hWnd,
“Status Position Error!!”, “Error”, MB_OK);
    return
mciStatusParms.dwReturn;
}

void SetCurrentPosition(HWND hWnd, DWORD dwID,
DWORD dwPos)
{
    MCI_STATUS_PARMS mciStatusParms;
    MCI_SEEK_PARMS
mciSeekParms;
    MCIERROR mciError;

    mciSeekParms.dwTo = dwPos;
    mciError =
mciSendCommand(dwID, MCI_SEEK, MCI_TO,
(DWORD)&mciSeekParms);
    if(mciError)
    {
        mciStatusParms.dwItem
= MCI_STATUS_CURRENT_TRACK;
        mciError = mciSendCommand(dwID,
MCI_STATUS,
MCI_STATUS_ITEM,
            (DWORD)&mciStatusParms);
        if(mciError)
            MessageBox(hWnd,
“Status Position Error!!”, “Error”, MB_OK);
    }
}

DWORD MoveNextTrack(HWND hWnd, DWORD
dwID)
{
    MCI_STATUS_PARMS mciStatusParms;
    MCIERROR mciError;

    mciStatusParms.dwItem =
MCI_STATUS_CURRENT_TRACK;
    mciError = mciSendCommand(dwID, MCI_STATUS,
MCI_STATUS_ITEM,
        (DWORD)&mciStatusParms);
    if(mciError)
        MessageBox(hWnd,
“Status Position Error!!”, “Error”, MB_OK);
    return
++mciStatusParms.dwReturn;
}

DWORD MovePrevTrack(HWND hWnd, DWORD
dwID)
{
    MCI_STATUS_PARMS mciStatusParms;
    MCIERROR mciError;

    mciStatusParms.dwItem =
MCI_STATUS_CURRENT_TRACK;
    mciError = mciSendCommand(dwID, MCI_STATUS,
MCI_STATUS_ITEM,
        (DWORD)&mciStatusParms);
    if(mciError)
        MessageBox(hWnd,
“Status Position Error!!”, “Error”, MB_OK);
    return
–mciStatusParms.dwReturn;
}

오늘은 여기까지
끝~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

  윈도우 32비트 프로그래밍 32

안녕하세요……돌팔이 황동준입니다……………

이번시간에는 저번시간에 만든 CD 플레이어 프로그램을 분석해 보겠습니다.

case WM_CREATE :

    dwID = Open(hWnd);
    SetFormat(hWnd,
dwID);
    return 0;

윈도우가 생성될 때 MCI 장치를 열고 그 포맷을 트랙단위로 하겠다는 것을 명시해주는
구문입니다.

case MM_MCINOTIFY :

    if(bPause)
    {
        SetCurrentPosition(hWnd,
dwID,
            MoveStartCurrentPosition(hWnd, dwID));
        bPause =
FALSE;

이 부분은 이미 미디 파일을 플레이할 때 다루었을 겁니다.

    }
    else
if(bNext)
    {
        SetCurrentPosition(hWnd,
dwID,
            MoveNextTrack(hWnd, dwID));
        bNext =
FALSE;
        Play(hWnd, dwID);

다음 곡 플레이가 선택되었을 때 현재 플레이 위치를 다음 트랙으로 옮긴 후에 다시 플레이하는
것을 보여주고 있습니다.

    }
    else
if(bPrev)
    {
        SetCurrentPosition(hWnd,
dwID,
            MovePrevTrack(hWnd, dwID));
        bPrev =
FALSE;
        Play(hWnd, dwID);

이전 곡 플레이가 선택되었을 때 현재 플레이 위치를 이전 트랙으로 옮긴 후에 다시 플레이하는
것을 보여주고 있습니다.

    }
    else
        MoveStartPosition(hWnd,
dwID);
    return 0;

case WM_COMMAND :

    switch(LOWORD(wParam))
    {
        case
100 :

            Play(hWnd,
dwID);
            break;

        case 200 :

            Pause(hWnd, dwID);
            bNext
= TRUE;
            break;

다음곡 플레이가 선택되었을 때도 역시 Pause()함수를 이용해서 중단한 뒤 다음 곡 플레이
때문에 중단되었다는 것을 bNext변수를 이용해서 알려주고 있습니다.

        case 300 :

            Pause(hWnd, dwID);
            bPrev
= TRUE;
            break;

이전 곡 플레이가 선택되었을 때도 역시 Pause()함수를 이용해서 중단한 뒤 이전 곡
플레이때문에 중단되었다는 것을 bPrev변수를 이용해서 알려주고 있습니다.

        case 400 :

            Pause(hWnd,
dwID);
            bPause = TRUE;
            break;

        case 500 :

            Play(hWnd,
dwID);
            break;

        case 600 :

            Stop(hWnd,
dwID);
            break;
    }
    return 0;

case WM_DESTROY :

    Close(hWnd,
dwID);
    PostQuitMessage(0);
    return 0;

나머지 부분은 크게 달라진 점이 없을 겁니다. 그러면 MCI 장치를 여는 Open() 함수를
보도록 합시다.

DWORD Open(HWND hWnd)
{
    MCI_OPEN_PARMS
mciOpenParms;
    MCIERROR mciError;

    mciOpenParms.lpstrDeviceType = “cdaudio”;

    mciError = mciSendCommand(NULL, MCI_OPEN,
MCI_OPEN_TYPE,
        (DWORD)&mciOpenParms);

세번째 파라미터에 MCI_OPEN_ELEMENT라는 예약어가 없죠? 파일을 읽어서 플레이하는
것이 아니기 때문입니다.

    if(mciError)
        MessageBox(hWnd, “Open
Error!!”, “Error”, MB_OK);
    return mciOpenParms.wDeviceID;
}

void SetFormat(HWND hWnd, DWORD
dwID)
{
    MCI_SET_PARMS mciSetParms;
    MCIERROR mciError;

    mciSetParms.dwTimeFormat =
MCI_FORMAT_TMSF;
    mciError = mciSendCommand(dwID, MCI_SET,
MCI_SET_TIME_FORMAT,
        (DWORD)&mciSetParms);

트랙단위로 길이 단위를 사용하겠다는 것을 지정해주고 있습니다. 이미 앞에서
설명드렸습니다.

    if(mciError)
        MessageBox(hWnd,
“Resume Error!!”, “Error”, MB_OK);
}

void SetCurrentPosition(HWND hWnd, DWORD dwID,
DWORD dwPos)
{
    MCI_STATUS_PARMS mciStatusParms;
    MCI_SEEK_PARMS
mciSeekParms;
    MCIERROR mciError;

    mciSeekParms.dwTo = dwPos;
    mciError =
mciSendCommand(dwID, MCI_SEEK, MCI_TO,
(DWORD)&mciSeekParms);
    if(mciError)
    {
        mciStatusParms.dwItem
= MCI_STATUS_CURRENT_TRACK;
        mciError = mciSendCommand(dwID,
MCI_STATUS,
MCI_STATUS_ITEM,
            (DWORD)&mciStatusParms);
        if(mciError)
            MessageBox(hWnd,
“Status Position Error!!”, “Error”, MB_OK);
    }

에러가 발생된다는 것은 그 트랙의 범위에 벗어난다는 의미이므로 이럴 때 그냥 현재 트랙의
노래를 플레이하기 위해서 위와 같이 구현했습니다.

}

DWORD MoveNextTrack(HWND hWnd, DWORD dwID)
{

이 함수는 다음 트랙번호를 얻는 역할을 합니다.

    MCI_STATUS_PARMS
mciStatusParms;
    MCIERROR mciError;

    mciStatusParms.dwItem =
MCI_STATUS_CURRENT_TRACK;
    mciError = mciSendCommand(dwID, MCI_STATUS,
MCI_STATUS_ITEM,
        (DWORD)&mciStatusParms);

현재 트랙번호를 얻는 구문입니다.

    if(mciError)
        MessageBox(hWnd,
“Status Position Error!!”, “Error”, MB_OK);
    return
++mciStatusParms.dwReturn;

트랙번호를 증가해서 값을 리턴하고 있습니다.

}

DWORD MovePrevTrack(HWND hWnd, DWORD dwID)
{

이 함수는 다음 트랙번호를 얻는 역할을 합니다.

    MCI_STATUS_PARMS
mciStatusParms;
    MCIERROR mciError;

    mciStatusParms.dwItem =
MCI_STATUS_CURRENT_TRACK;
    mciError = mciSendCommand(dwID, MCI_STATUS,
MCI_STATUS_ITEM,
        (DWORD)&mciStatusParms);

현재 트랙번호를 얻는 구문입니다.

    if(mciError)
        MessageBox(hWnd,
“Status Position Error!!”, “Error”, MB_OK);
    return
–mciStatusParms.dwReturn;

트랙번호를 감소해서 값을 리턴하고 있습니다.

}

자 그렇게 크게 어려운 점은 없죠? 그러면 이번에는 멀티미디어 관련 마지막인 확장자가
avi인 파일을 어떻게 플레이하는지 알아 보겠습니다. 여러분들이 앞에서 알아본 것들 중에서 이 부분이 가장 어려울거라고 생각들 수도 있으나 사실
이 부분이 제일 쉽습니다. 간단하게 함수 하나로 모든 기능을 가진 avi 플레이어를 구현할 수 있거든요. 우리가 앞에서 알아본 프로그램은 전부
mmsystem.h라는 헤더파일을 포함시켰고 또 컴파일할 때도 winmm.lib 파일을 같이 묶어서 컴파일했을 겁니다. 그러나 우리가 이제
알아볼 avi 파일을 플레이할 때에는 이 헤더 파일과 라이브러리 파일이 필요 없습니다. 대신 다른 헤더 파일과 라이브러리 파일이 필요합니다.
필요한 헤더 파일은 vfw.h라는 헤더 파일이고 필요한 라이브러리 파일은vfw32.lib입니다. vfw가 뭐의 약자인지 아십니까? 바로
Video For Windows의 약자입니다. 이게 뭔지는 굳이 제가 설명 드리지 않더라도 알겠죠?

함수 하나로 플레이할수 있다고 했는데 과연 그 함수가 뭘까요?

HWND VFWAPIV MCIWndCreate(HWND hwndParent,
HINSTANCE hInstance,
    DWORD dwStyle,LPCSTR szFile);

바로 위 함수 하나로 avi를 플레이할 수 있는 조그만 윈도우를 만들 수 있습니다. 첫번째
파라미터에 현재 윈도우의 핸들을 지정해야 하고 두번째 파라미터에는 인스턴스 핸들, 세번째 파라미터는 이 윈도우의 속성을 지정해줄 수 있는데 보통
NULL을 지정하면 기본 속성을 사용하겠다는 것을 의미합니다. 마지막 파라미터는 플레이할 avi 파일이름을 지정하면 됩니다. 만약에 NULL로
지정하면 파일을 직접 찾아서 플레이할 수 있게 됩니다.

위 함수를 이용해서 윈도우를 생성하고 나면 나중에 프로그램 종료시 윈도우를 제거해 주어야
합니다. 이때에는 아래 함수를 이용해서 하면 됩니다.

void MCIWndDestroy(HWND hwnd);

그러면 이 두함수를 이용해서 구현한 간단하고 뛰어난 avi 플레이어를 만들어 봅시다.

#include <windows.h>
#include
<string.h>
#include <vfw.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);
HINSTANCE hInst;

int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
        static
char szAppName[] = “Multimedia Example”;
        HWND hWnd;
        MSG
msg;
        WNDCLASS WndClass;

        WndClass.style =
CS_HREDRAW|CS_VREDRAW;
        WndClass.lpfnWndProc =
WndProc;
        WndClass.cbClsExtra = 0;
        WndClass.cbWndExtra =
0;
        WndClass.hInstance = hInstance;
        WndClass.hIcon =
LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(NULL,
IDC_ARROW);
        WndClass.hbrBackground =
GetStockObject(WHITE_BRUSH);
        WndClass.lpszMenuName =
“MyMenu”;
        WndClass.lpszClassName =
szAppName;
        if(!RegisterClass(&WndClass))
                return
FALSE;

        hWnd =
CreateWindow(
                szAppName,
                szAppName,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL
        );

        hInst = hInstance;

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

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

        return msg.wParam;
}

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

        switch(message)
        {
            case
WM_CREATE :

                hAviWnd =
MCIWndCreate(
                    hWnd,
                    hInst,
                    NULL,
                    “d:test.avi”
                );
                return
0;

            case WM_DESTROY :

                MCIWndDestroy(hAviWnd);
                PostQuitMessage(0);
                return
0;
        }
        return DefWindowProc(hWnd, message, wParam,
lParam);
}

정말로 간단하죠? 이 소스를 보신 분은 정말 이 프로그램이 avi 파일을 플레이할 수 있는지
의문이 생길 수도 있을 겁니다. 직접 코딩해서 컴파일 해보시기 바랍니다. 간단하게 만들었지만 정말 대단하다는 것을 느낄 겁니다. 그러면
구체적으로 소스를 보도록 하겠습니다.

#include <vfw.h>

프로그램 상단에 위 헤더 파일을 포함시켜 줘야 합니다. 물론 컴파일할 때에는
vfw32.lib 파일을 묶어서 해줘야 하구요.

HWND hAviWnd;

조그마하게 생성되는 avi 플레이어 윈도우의 핸들을 얻기 위해서 위 변수를
선언했습니다.

switch(message)
{
    case WM_CREATE :

        hAviWnd =
MCIWndCreate(
            hWnd,
            hInst,
            NULL,
            “d:test.avi”
        );
        return
0;

윈도우가 생성될때 avi 플레이어 윈도우를 생성하는 구문입니다.

    case WM_DESTROY :

        MCIWndDestroy(hAviWnd);

윈도우가 종료될때 avi 플레이어 윈도우를 없애는 구문입니다.

        PostQuitMessage(0);
        return
0;
}

오늘은 여기까지
끝~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

  윈도우 32비트 프로그래밍 33

안녕하세요……….돌팔이 황동준입니다………

이번시간에는 폰트에 대해 알아보겠습니다. 윈도우즈 95에서 제공하는 제공하는 트루타입 폰트를
다루는 것은 그렇게 어렵지 않습니다. 보통 어떤 프로그램이든지 보면 프로그램에서 사용하는 폰트를 사용자가 선택할 수 있는 기능이 있는데 이
기능을 구현할 때에는 윈도우즈에서 기본적으로 제공하는 폰트 선택 대화 상자를 이용해서 합니다. 그러나 우리는 지금 이 대화상자를 이용하지 않고
직접 함수를 이용해서 원하는 폰트를 선택하는 방법에 대해 알아보고자 합니다. 대화 상자를 가지고 선택하는 방법은 뒤의 인터페이스 부분에서
설명드리도록 하겠습니다.

전반적으로 구현하는 방법은 간단합니다. 먼저 폰트의 핸들을 의미하는 HFONT 변수를 선언한
뒤에 폰트를 생성하는 함수를 이용해서 원하는 폰트를 생성합니다. 물론 이 함수의 리턴값은 HFONT형이 됩니다. 그리고 우리가 앞에서 자주
사용한 SelectObject() 함수를 이용해서 이 폰트를 사용하겠다는 것을 명시해주고 출력하면 바로 생성한 폰트로 문자를 출력할 수
있습니다. 원리는 상당히 간단하죠.

그러면 폰트를 생성하는 함수를 보도록 합시다.

HFONT CreateFont(
    int  nHeight,
    int
 nWidth,
    int  nEscapement,
    int  nOrientation,
    int
 fnWeight,
    DWORD  fdwItalic,
    DWORD  fdwUnderline,
    DWORD
 fdwStrikeOut,
    DWORD  fdwCharSet,
    DWORD
 fdwOutputPrecision,
    DWORD  fdwClipPrecision,
    DWORD
 fdwQuality,
    DWORD  fdwPitchAndFamily,
    LPCTSTR  lpszFace
   );
  

상당히 복잡하죠? 그러면 각 파라미터에 대해 알아 봅시다.
먼저 nHeight와
nWidth는 글자의 크기를 의미하는 것입니다. 만약에 nWidth가 0이라면 nHeight크기에 적합한 폭의 글자가 생성됩니다.
nEscapement는 폰트의 출력 각도를 의미하는 것입니다. 보통 0의 값을 가져 가로로 출력하죠. 만약에 세로로 출력하고자 한다면 900으로
지정하면 됩니다. nOrientation은 베이스 라인의 각도를 의미합니다. fnWeight은 글자의 진한 정도를 의미하는데 이 값으로 지정할수
있는 예약어는 다음과 같습니다.

예약어         진한정도
FW_DONTCARE     0
FW_THIN
        100
FW_EXTRALIGHT   200
FW_LIGHT        300
FW_NORMAL
      400
FW_MEDIUM       500
FW_SEMIBOLD     600
FW_BOLD
        700
FW_EXTRABOLD    800
FW_HEAVY        900

fdwItalic은 이탤릭체를 사용할것인지 지정하는것인데 이값이 1이면 사용하겠다는 것을
의미하고 0이면 사용하지 않겠다는 것을 의미하는 것입니다.

fdwUnderline은 밑줄이 그어진 글자를 출력할때 사용하는 파라미터인데 이 값이 1이면
밑줄을 치고 0이면 밑줄을 치지 않습니다.

fdwStrikeOut은 글자의 가운데에 선이 그어진 형태를 지정할때 사용하는데 이 값이
1이면 선을 긋고 1이 아니면 선을 긋지 않습니다.

fdwCharSet은 문자세트를 지정할때 사용하는데 이 파라미터에 지정될수 있는 예약어는
다음과 같습니다.

ANSI_CHARSET
UNICODE_CHARSET
SYMBOL_CHARSET
SHIFTJIS_CHARSET
HANGEUL_CHARSET
CHINESEBIG5_CHARSET
OEM_CHARSET

fdwOutputPrecision은 정밀도를 지정하는 것인데 이 파라미터에 지정될수 있는
예약어는 다음과 같습니다.

OUT_DEFAULT_PRECIS
OUT_STRING_PRECIS
OUT_CHARACTER_PRECIS
OUT_STROKE_PRECIS
OUT_TT_PRECIS
OUT_DEVICE_PRECIS
OUT_RASTER_PRECIS
OUT_TT_ONLY_PRECIS
OUT_OUTLINE_PRECIS

fdwClipPrecision은 클리핑 정밀도를 지정할때 사용하는데 이 파라미터에 지정될 수
있는 예약어는 다음과 같습니다.

CLIP_DEFAULT_PRECIS
CLIP_CHARACTER_PRECIS
CLIP_STROKE_PRECIS
CLIP_MASK
CLIP_LH_ANGLES
CLIP_TT_ALWAYS
CLIP_EMBEDDED

fdwQuality은 역시 정밀도를 지정하는 것인데 이 파라미터에 지정될수 있는 예약어는
다음과 같습니다.

DEFAULT_QUALITY
DRAFT_QUALITY
PROOF_QUALITY

fdwPitchAndFamily은 글자의 피치를 지정하는 것인데 이 파라미터에 지정될수 있는
예약어는 다음과 같습니다.

DEFAULT_PITCH
FIXED_PITCH
VARIABLE_PITCH

FF_DECORATIVE
FF_DONTCARE
FF_MODERN
FF_ROMAN
FF_SCRIPT
FF_SWISS

lpszFace은 구체적인 글자의 폰트 이름을 지정해 주면 됩니다. 이 폰트 이름에는 다음과
같은 것들이 오면 됩니다.

Arial
Arial Bold
Arial Bold Italic
Arial
Italic
Comic Sans MS
Courier
Courier New
Courier New Bold
Courier
New Bold Italic
Courier New Italic
Modern
MS Sans Serif
MS
Serif
Roman
Script
Small Fonts
Symbol
Times New Roman
Times
New Roman Bold
Times New Roman Bold Italic
Times New Roman Italic

아마 여러분들도 이 폰트 이름을 본적이 있을 겁니다. 바로 윈도우즈에 설치되어 있는 폰트의
이름이죠. 자 그러면 실제로 폰트를 생성해서 그 폰트를 이용해서 출력하는 프로그램을 만들어 봅시다.

MyMenu MENU
BEGIN
    POPUP
“&Font”
    BEGIN
        MENUITEM “&Ms Sans Serif”,
100
        MENUITEM “&Roman”, 200
        MENUITEM “&Symbol”,
300
    END
END

#include <windows.h>
#include
<string.h>
#include <stdio.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);
HFONT SelectMyFont(int nIndex);

int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
        static
char szAppName[] = “Font Example”;
        HWND hWnd;
        MSG
msg;
        WNDCLASS WndClass;

        WndClass.style =
CS_HREDRAW|CS_VREDRAW;
        WndClass.lpfnWndProc =
WndProc;
        WndClass.cbClsExtra = 0;
        WndClass.cbWndExtra =
0;
        WndClass.hInstance = hInstance;
        WndClass.hIcon =
LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(NULL,
IDC_ARROW);
        WndClass.hbrBackground =
GetStockObject(WHITE_BRUSH);
        WndClass.lpszMenuName =
“MyMenu”;
        WndClass.lpszClassName =
szAppName;
        if(!RegisterClass(&WndClass))
                return
FALSE;

        hWnd =
CreateWindow(
                szAppName,
                szAppName,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL
        );

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

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

        return msg.wParam;
}

LRESULT CALLBACK
WndProc(HWND hWnd, UINT
message, WPARAM wParam, LPARAM lParam)
{
        HDC
hDC;
        PAINTSTRUCT ps;
        static HFONT hFont;
        LPSTR
szFontTest = “This is Font Test.”;

        switch(message)
        {
            case
WM_PAINT :

                hDC = BeginPaint(hWnd,
&ps);
                SelectObject(hDC,
hFont);
                TextOut(hDC, 50, 50, szFontTest,
strlen(szFontTest));
                DeleteObject(hFont);
                EndPaint(hWnd,
&ps);
                return 0;

            case WM_COMMAND :

                switch(LOWORD(wParam))
                {
                    case
100 :

                        hFont =
SelectMyFont(0);
                        InvalidateRect(hWnd, NULL,
TRUE);
                        break;

                    case 200 :

                        hFont =
SelectMyFont(1);
                        InvalidateRect(hWnd, NULL,
TRUE);
                        break;

                    case 300 :

                        hFont =
SelectMyFont(2);
                        InvalidateRect(hWnd, NULL,
TRUE);
                        break;
                }
                return
0;

            case WM_DESTROY :

                PostQuitMessage(0);
                return
0;
        }
        return DefWindowProc(hWnd, message, wParam,
lParam);
}

HFONT SelectMyFont(int nIndex)
{
    HFONT
hFont;

    if(nIndex == 0)
    {
        hFont =
CreateFont(
            20, 0,
            0,
0,
            FW_NORMAL,
            1, 0,
0,
            ANSI_CHARSET,
            OUT_DEFAULT_PRECIS,
            CLIP_DEFAULT_PRECIS,
            DEFAULT_QUALITY,
            DEFAULT_PITCH,
            “MS
Sans Serif”
        );
    }
    else if(nIndex ==
1)
    {
        hFont = CreateFont(
            20,
0,
            0, 0,
            FW_NORMAL,
            1, 1,
0,
            ANSI_CHARSET,
            OUT_DEFAULT_PRECIS,
            CLIP_DEFAULT_PRECIS,
            DEFAULT_QUALITY,
            DEFAULT_PITCH,
            “Roman”
      

  );
    }
    else if(nIndex ==
2)
    {
        hFont = CreateFont(
            20,
0,
            0, 0,
            FW_NORMAL,
            1, 1,
1,
            ANSI_CHARSET,
            OUT_DEFAULT_PRECIS,
            CLIP_DEFAULT_PRECIS,
            DEFAULT_QUALITY,
            DEFAULT_PITCH,
            “Symbol”
        );
    }
    return
hFont;
}

뭐 그렇게 새로운 것은 없군요. 어떤 메뉴 아이템을 선택했는냐에 따라서 해당 문자열을 그
폰트로 출력하는 프로그램입니다. 간단하죠. InvalidateRect()함수만 이해한다면 크게 문제되는 점은 없을 겁니다. 그러면 프로그램을
하나 더 만들어 보죠. 이것도 위 프로그램과 크게 다른 점은 없습니다. 여러분들이 한번 보시기 바랍니다. 이 정도는 이해 할 수
있겠죠?

 

  윈도우 32비트 프로그래밍 34

MyMenu MENU
BEGIN
    POPUP
“&Font”
    BEGIN
        POPUP
“&Size”
        BEGIN
            MENUITEM “20”,
100
            MENUITEM “30”, 200
            MENUITEM “40”,
300
            MENUITEM “50”, 400
        END
        POPUP
“&Weight”
        BEGIN
            MENUITEM “&Light”,
500
            MENUITEM “&Normal”, 600
            MENUITEM
“&Bold”, 700
        END
        MENUITEM “&UnderLine”,
800
        MENUITEM “Strike&Out”, 900
        MENUITEM
SEPARATOR
        MENUITEM “S&elect”, 1000
    END
END

#include <windows.h>
#include
<string.h>
#include <stdio.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);
HFONT SelectMyFont(int nSize, int nWeight, DWORD dwUnderLine, DWORD
dwStrike);

int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
        static
char szAppName[] = “Font Example”;
        HWND hWnd;
        MSG
msg;
        WNDCLASS WndClass;

        WndClass.style =
CS_HREDRAW|CS_VREDRAW;
        WndClass.lpfnWndProc =
WndProc;
        WndClass.cbClsExtra = 0;
        WndClass.cbWndExtra =
0;
        WndClass.hInstance = hInstance;
        WndClass.hIcon =
LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(NULL,
IDC_ARROW);
        WndClass.hbrBackground =
GetStockObject(WHITE_BRUSH);
        WndClass.lpszMenuName =
“MyMenu”;
        WndClass.lpszClassName =
szAppName;
        if(!RegisterClass(&WndClass))
                return
FALSE;

        hWnd =
CreateWindow(
                szAppName,
                szAppName,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL
        );

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

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

        return msg.wParam;
}

LRESULT CALLBACK
WndProc(HWND hWnd, UINT
message, WPARAM wParam, LPARAM lParam)
{
        HDC
hDC;
        PAINTSTRUCT ps;
        HMENU hMenu;
        static HFONT
hFont;
        static int nSize, nWeight;
        static DWORD
dwUnderLine, dwStrike;
        static BOOL bUnderLine,
bStrike;
        LPSTR szFontTest = “This is Font Test.”;

        switch(message)
        {
            case
WM_PAINT :

                hDC = BeginPaint(hWnd,
&ps);
                SelectObject(hDC,
hFont);
                TextOut(hDC, 50, 50, szFontTest,
strlen(szFontTest));
                DeleteObject(hFont);
                EndPaint(hWnd,
&ps);
                return 0;

            case WM_COMMAND :

                switch(LOWORD(wParam))
                {
                    case
100 :

                        hMenu =
GetMenu(hWnd);
                        CheckMenuItem(hMenu, 100,
MF_CHECKED);
                        CheckMenuItem(hMenu, 200,
MF_UNCHECKED);
                        CheckMenuItem(hMenu, 300,
MF_UNCHECKED);
                        CheckMenuItem(hMenu, 400,
MF_UNCHECKED);
                        nSize =
20;
                        break;

                    case 200 :

                        hMenu =
GetMenu(hWnd);
                        CheckMenuItem(hMenu, 100,
MF_UNCHECKED);
                        CheckMenuItem(hMenu, 200,
MF_CHECKED);
                        CheckMenuItem(hMenu, 300,
MF_UNCHECKED);
                        CheckMenuItem(hMenu, 400,
MF_UNCHECKED);
                        nSize =
30;
                        break;

                    case 300 :

                        hMenu =
GetMenu(hWnd);
                        CheckMenuItem(hMenu, 100,
MF_UNCHECKED);
                        CheckMenuItem(hMenu, 200,
MF_UNCHECKED);
                        CheckMenuItem(hMenu, 300,
MF_CHECKED);
                        CheckMenuItem(hMenu, 400,
MF_UNCHECKED);
                        nSize =
40;
                        break;

                    case 400 :

                        hMenu =
GetMenu(hWnd);
                        CheckMenuItem(hMenu, 100,
MF_UNCHECKED);
                        CheckMenuItem(hMenu, 200,
MF_UNCHECKED);
                        CheckMenuItem(hMenu, 300,
MF_UNCHECKED);
                        CheckMenuItem(hMenu, 400,
MF_CHECKED);
                        nSize =
50;
                        break;

                    case 500 :

                        hMenu =
GetMenu(hWnd);
                        CheckMenuItem(hMenu, 500,
MF_CHECKED);
                        CheckMenuItem(hMenu, 600,
MF_UNCHECKED);
                        CheckMenuItem(hMenu, 700,
MF_UNCHECKED);
                        nWeight =
FW_LIGHT;
                        break;

                    case 600 :

                        hMenu =
GetMenu(hWnd);
                        CheckMenuItem(hMenu, 500,
MF_UNCHECKED);
                        CheckMenuItem(hMenu, 600,
MF_CHECKED);
                        CheckMenuItem(hMenu, 700,
MF_UNCHECKED);
                        nWeight =
FW_NORMAL;
                        break;

                    case 700 :

                        hMenu =
GetMenu(hWnd);
                        CheckMenuItem(hMenu, 500,
MF_UNCHECKED);
                        CheckMenuItem(hMenu, 600,
MF_UNCHECKED);
                        CheckMenuItem(hMenu, 700,
MF_CHECKED);
                        nWeight =
FW_BOLD;
                        break;

                    case 800 :

                        hMenu =
GetMenu(hWnd);
                        if(!bUnderLine)
                        {
                            CheckMenuItem(hMenu,
800, MF_CHECKED);
                            dwUnderLine =
1;
                        }
                        else
                        {
                            CheckMenuItem(hMenu,
800, MF_UNCHECKED);
                            dwUnderLine =
0;
                        }
                        bUnderLine =
!bUnderLine;
                        break;

                    case 900 :

                        hMenu =
GetMenu(hWnd);
                        if(!bStrike)
                        {
                            CheckMenuItem(hMenu,
900, MF_CHECKED);
                            dwStrike =
1;
                        }
                        else
                        {
                            CheckMenuItem(hMenu,
900, MF_UNCHECKED);
                            dwStrike =
0;
                        }
                        bStrike =
!bStrike;
                        break;

                    case 1000 :

                        hFont = SelectMyFont(nSize,
nWeight,
dwUnderLine,
                            dwStrike);
                        InvalidateRect(hWnd,
NULL,
TRUE);
                        break;
                }
                return
0;

            case WM_DESTROY :

                PostQuitMessage(0);
                return
0;
        }
        return DefWindowProc(hWnd, message, wParam,
lParam);
}

HFONT SelectMyFont(int nSize, int nWeight, DWORD
dwUnderLine, DWORD dwStrike)
{
    HFONT hFont;

    hFont = CreateFont(
        nSize,
0,
        0, 0,
        nWeight,
        1,
dwUnderLine,
        dwStrike,
        ANSI_CHARSET,
        OUT_DEFAULT_PRECIS,
        CLIP_DEFAULT_PRECIS,
        DEFAULT_QUALITY,
        DEFAULT_PITCH,
        “Roman”
    );
    return
hFont;
}

오늘은 여기까지
끝~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

  윈도우 32비트 프로그래밍 35

안녕하세요……….돌팔이 황동준입니다…………….

이번 시간부터는 파일과 디렉토리를 다루어 보도록 하겠습니다. 모든 운영체제를 처음 배울 때
바로 나오는 것이 바로 이 파일과 디렉토리에 관련된 것이라는 것을 여러분들은 잘 알 것입니다. 그만큼 가장 기본이 되는 거죠. 실제로 프로그램을
작성할 때 가장 많이 사용하는 것이 구조체와 문자열 다루기, 그리고 바로 이 파일 입출력인데 윈도우즈에서도 파일 입출력이나, 디렉토리 다루는
것은 상당히 중요합니다. 왜냐하면  프로그램을 만들고 실제로 인스톨하는 프로그램이나 언인스톨 프로그램을 만들 때 이것에 대한 이해가 없다면
구현을 하지 못하기 때문이죠. 하긴 요즘에는 인스톨이나 언인스톨 프로그램을 직접 만들지 않고 툴을 이용해서 구현하는 경우가 많기 때문에 필요하지
않을 수도 있습니다. 그러나 개성있는 프로그램을 만들기 위해서는 어느 정도 알아두면 좋을거라는 생각도 드는군요. 그러면 먼저 파일 입출력부터
알아 보겠습니다.

아마 비트맵 부분을 설명드릴 때 이미 파일 입출력 부분을 제가 설명 드렸을 겁니다. 먼저 그
방법을 다시 복습해 보도록 하겠습니다. 먼저 파일을 생성하는 방법부터 알아 봅시다.

HFILE _lcreat(
    LPCSTR
 lpszFileName,
    int  fnAttribute
   );   

위 함수를 이용해서 파일을 생성할 수 있는데 첫번째 파라미터에 생성될 파일이름을 지정하면
됩니다. 그리고 두번째 파라미터에 다음과 같은 값을 지정하여 그 속성을 정의할 수 있습니다.

0       일반적인 파일을 생성합니다.
1       읽기 전용 파일을
생성합니다.
2       히든 파일을 생성합니다.
4       시스템 파일을 생성합니다.

파일을 생성하는 과정은 파일에 어떠한 정보를 쓸 때 사용하는 것입니다. 먼저 생성한 후에
파일을 열고 쓰면 되죠. 만약에 파일에서 어떠한 정보를 읽어야 한다면 생성하는 과정을 할 필요는 없습니다. 그냥 파일을 열면 되는 거죠. 그러면
파일을 어떻게 여는지 알아 봅시다.

HFILE _lopen(
    LPCSTR
 lpszFileName,
    int  fnOpenMode
   );   

위 함수를 이용해서 존재하는 파일을 열 수 있습니다. 첫번째 파라미터로 열 파일 이름을
지정해 주면 되고 두번쩨 파라미터에는 파일 접근 방식을 예약어로 지정해주면 됩니다. 이 예약어로는 다음과 같은 것들이 올 수 있습니다.

OF_READ             읽기 전용으로 파일을
엽니다.
OF_READWRITE        읽기 쓰기 전용으로 파일을 엽니다.
OF_WRITE            쓰기 전용으로
파일을 엽니다.
OF_SHARE_COMPAT     동시에 여러 프로그램에서 이 파일을 열수 있도록
합니다.
OF_SHARE_DENY_READ  다른 프로그램이 이 파일을 읽을수 있는 것을
금지시킵니다.
OF_SHARE_DENY_WRITE 다른 프로그램이 이 파일에 쓰는 것을
금지시킵니다.
OF_SHARE_EXCLUSIVE  다른 프로그램이 이 파일을 읽고 쓰는 것을 금지시킵니다.

파일을 여는 과정을 알았으니 파일을 닫는 방법도 알아 봅시다. 파일을 열어서 읽거나 쓰는
과정이 끝나면 파일을 닫아 주어야 하는데 이때에는 아래 함수를 이용해서 하면 됩니다.

HFILE _lclose(
    HFILE  hFile
   );

첫번째 파라미터로 파일을 연 핸들을 지정해 주면 됩니다. 자 그러면 실제로 읽거나 쓸 때
어떤 함수를 이용해서 할 수 있는지 봅시다.

UINT _lread(
    HFILE  hFile,
    LPVOID
 lpBuffer,
    UINT  cbRead
   );   

파일에서 어떠한 정보를 읽어오고자 할 때에는 위 함수를 이용해서 하면 됩니다. 첫번째
파라미터에 파일을 열었을 때 얻은 파일 핸들을 지정하면 되고 두번째 파라미터에 정보를 저장할 버퍼를 세번째 파라미터에 버퍼 크기를 지정하면
됩니다.

UINT _lwrite(
    HFILE  hFile,
    LPCSTR
 lpBuffer,
    UINT  cbWrite
   );

파일에 정보를 기록할 때에는 위 함수를 이용해서 하면 됩니다. 첫번째 파라미터는 역시 파일의
핸들을 지정하면 되고 두번째 파라미터는 정보를 세번재 파라미터에는 정보의 크기를 지정해 주면 됩니다.

이미 앞에서 해본 것들이라서 그렇게 크게 어려운 점은 없을 겁니다. 그러면 이것을 이용한
실제 프로그램을 만들어 봅시다.

MyMenu MENU
BEGIN
    POPUP
“&File”
    BEGIN
        MENUITEM “&Save”,
100
        MENUITEM “&Load”, 200
    END
END

#include <windows.h>
#include
<string.h>
#include <stdio.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);
void SaveProc(void);
void LoadProc(void);
char
GetHeader(void);
LPSTR GetData(void);

typedef struct tagMYFILE
{
    char
cHeader;
    char szData[80];
} MYFILE;

MYFILE MyFile;

int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
        static
char szAppName[] = “File & Directory Example”;
        HWND
hWnd;
        MSG msg;
        WNDCLASS WndClass;

        WndClass.style =
CS_HREDRAW|CS_VREDRAW;
        WndClass.lpfnWndProc =
WndProc;
        WndClass.cbClsExtra = 0;
        WndClass.cbWndExtra =
0;
        WndClass.hInstance = hInstance;
        WndClass.hIcon =
LoadIcon(NULL, IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(NULL,
IDC_ARROW);
        WndClass.hbrBackground =
GetStockObject(WHITE_BRUSH);
        WndClass.lpszMenuName =
“MyMenu”;
        WndClass.lpszClassName =
szAppName;
        if(!RegisterClass(&WndClass))
                return
FALSE;

        hWnd =
CreateWindow(
                szAppName,
                szAppName,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL
        );

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

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

        return msg.wParam;
}

LRESULT CALLBACK
WndProc(HWND hWnd, UINT
message, WPARAM wParam, LPARAM lParam)
{
        HDC
hDC;
        PAINTSTRUCT ps;

        static char cHeader;
        static char
szData[80];

        switch(message)
        {
            case
WM_CREATE :

                cHeader = '
';
                return 0;

            case WM_PAINT :

                hDC = BeginPaint(hWnd,
&ps);
                TextOut(hDC, 100, 100, &cHeader,
1);
                TextOut(hDC, 100, 150, szData,
strlen(szData));
                EndPaint(hWnd,
&ps);
                return 0;

            case WM_COMMAND :

                switch(LOWORD(wParam))
                {
                    case
100 :

                        SaveProc();
                        break;

                    case 200 :

                        LoadProc();
                        cHeader
= GetHeader();
                        strcpy(szData,
GetData());
                        InvalidateRect(hWnd, NULL,
FALSE);
                        break;
                }
                return
0;

            case WM_DESTROY :

                PostQuitMessage(0);
                return
0;
        }
        return DefWindowProc(hWnd, message, wParam,
lParam);
}

void SaveProc(void)
{
    HFILE
hFile;
    MYFILE tmpMyFile;

    tmpMyFile.cHeader =
'A';
    strcpy(tmpMyFile.szData, “This is File Data”);

    _lcreat(“e:test.txt”, 0);
    hFile =
_lopen(“e:test.txt”, OF_WRITE);
    _lwrite(hFile, (char *)&tmpMyFile,
sizeof(MYFILE));
    _lclose(hFile);
}

void LoadProc(void)
{
    HFILE hFile;

    hFile = _lopen(“e:test.txt”,
OF_READ);
    _lread(hFile, (MYFILE *)&MyFile,
sizeof(MYFILE));
    _lclose(hFile);
}

char GetHeader(void)
{
    return
MyFile.cHeader;
}

LPSTR GetData(void)
{
    return
MyFile.szData;
}

위 프로그램은 하나의 구조체를 만든 후에 그 구조체 맴버 변수에 값을 채운 후에 그 구조체의
크기만큼 통채로 파일에 기록한 후에 다시 그 구조체의 크기만큼 정보를 읽어오는 기능을 가지고 있습니다. 그러면 소스를 보도록 합시다. 소스를
보면 제가 만든 함수 네 개가 눈에 띄는데 각각 어떤 역할을 하는지 봅시다.

void SaveProc(void)
{

이 함수는 구조체 멤버에 값을 채워 넣은 뒤에 그 정조를 파일에 저장하는 역할을
합니다.

    HFILE hFile;

파일을 열고 쓰기 위해서 위 변수를 선언했습니다.

    MYFILE tmpMyFile;

    tmpMyFile.cHeader =
'A';
    strcpy(tmpMyFile.szData, “This is File Data”);

구조체 변수에 값을 채워넣고 있는 구문입니다.

    _lcreat(“e:test.txt”, 0);

파일에 쓰기 위헤서 먼저 파일을 생성하고 있습니다.

    hFile = _lopen(“e:test.txt”, OF_WRITE);

파일을 열고 있습니다.

    _lwrite(hFile, (char *)&tmpMyFile,
sizeof(MYFILE));
    _lclose(hFile);

파일에 정보를 기록한후에 파일을 닫는 구문입니다.

}

void LoadProc(void)
{

이 함수는 파일에서 정보를 가져오는 역할을 합니다.

    HFILE hFile;

    hFile = _lopen(“e:test.txt”,
OF_READ);
    _lread(hFile, (MYFILE *)&MyFile,
sizeof(MYFILE));
    _lclose(hFile);

역시 파일을 연후에 정보를 가져오고 닫는 과정을 보여 주고 있습니다.

}

char GetHeader(void)
{
    return
MyFile.cHeader;
}

LPSTR GetData(void)
{
    return
MyFile.szData;
}

위 두함수는 가져온 정보를 분리해서 그 값을 리턴해주는 역할을 합니다. 그렇게 어려운 부분은
없죠? 이미 앞 부분에서 잘 이해한 분은 쉬울 겁니다.

오늘은 여기까지
끝~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

zemna

Programmer/Web/Mobile/Desktop

You may also like...

Leave a Reply