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

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

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

이번시간에는 저번시간에 알아본 함수들을 이용해서 프로그램을 하나 만들어 보겠습니다.

자 그러면 전체적인 프로그램을 보도록 합시다. 아래는 리소스 파일입니다.

#include <windows.h>

MyMenu MENU
BEGIN
    POPUP
“&Wave”
    BEGIN
        MENUITEM “&Play”,
100
        MENUITEM “P&ause”, 200
        MENUITEM “&Resume”,
300
        MENUITEM “&Stop”, 400
    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
Resume(HWND hWnd, DWORD dwID);
void Close(HWND hWnd, DWORD dwID);
void
MoveStartPosition(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;

        switch(message)
        {
            case
WM_CREATE :

                dwID =
Open(hWnd);
                return 0;

            case MM_MCINOTIFY :

                MoveStartPosition(hWnd,
dwID);
                return 0;

            case WM_COMMAND :

                switch(LOWORD(wParam))
                {
                    case
100 :

                        Play(hWnd,
dwID);
                        break;

                    case 200 :

                        Pause(hWnd,
dwID);
                        break;

                    case 300 :

                        Resume(hWnd,
dwID);
                        break;

                    case 400 :

                        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 =
“waveaudio”;
    mciOpenParms.lpstrElementName = “d:test.wav”;

    mciError = mciSendCommand(NULL, MCI_OPEN,
MCI_OPEN_TYPE|MCI_OPEN_ELEMENT,
        (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 Resume(HWND hWnd, DWORD
dwID)
{
    MCI_GENERIC_PARMS mciGenericParms;
    MCIERROR
mciError;

    mciError = mciSendCommand(dwID, MCI_RESUME,
MCI_WAIT,
        (DWORD)&mciGenericParms);
    if(mciError)
        MessageBox(hWnd,
“Resume 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 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);
}

어떻게 돌아가는지 짐작이 갑니까? 별로 어렵지 않죠? 에러 처리하는 부분만 새롭지 크게
어려운 점은 없을 겁니다. 이부분은 다음 시간에 설명 드리도록 하겠습니다.

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

 

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

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

이번시간에는 저번시간에 본 프로그램을 분석해 보겠습니다. 그리고 플레이하는 또 다른 방법도
알아 보겠습니다.

먼저 저번시간에 만들어본 소스를 보도록 합시다.

case WM_CREATE :

    dwID = Open(hWnd);
    return 0;

윈도우가 생성되었을때에 Open()이라는 함수에 의해서 장치의 아이디를 얻는 과정을 보여
주고 있습니다.

case MM_MCINOTIFY :

    MoveStartPosition(hWnd, dwID);
    return
0;

이 메시지는 언제 발생됩니까? MCI_PLAY라는 파라미터를 지정해서 사용한
mciSendCommand() 함수를 보면 세번째 파라미터를 MCI_NOTIFY라고 지정했을 겁니다. 그렇죠? 이것에 의해서 연주가 끝나거나
중단되면 바로 위 메시지가 발생됩니다. 플레이가 끝나면 플레이 시작 위치를 처음으로 옮기는 역할을 하는것이 위
MoveStartPosition()함수입니다.

case WM_COMMAND :

    switch(LOWORD(wParam))
    {
        case
100 :

            Play(hWnd,
dwID);
            break;

플레이를 하는 구문입니다.

        case 200 :

            Pause(hWnd,
dwID);
            break;

잠시 중단하게 하는 구문입니다.

        case 300 :

            Resume(hWnd,
dwID);
            break;

다시 플레이하는 구문입니다.

        case 400 :

            Stop(hWnd,
dwID);
            break;

플레이를 중단하는 구문입니다.

    }
    return 0;

case WM_DESTROY :

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

프로그램이 종료되면 MCI 장치를 닫는다는 것을 보여 주고 있습니다.

자 그러면 구체적으로 제가 만든 함수들을 보도록 합시다.

DWORD Open(HWND hWnd)
{

이 함수는 MCI 장치를 여는 역할을 하는 함수입니다.

    MCI_OPEN_PARMS mciOpenParms;

장치를 열기 위해서는 위 구조체 변수가 필요하다고 이미 설명 드렸을 겁니다.

    MCIERROR mciError;

장치가 제대로 열렸는지 확인하기 위해서 위 MCIERROR이라는 변수를 선언한
것입니다.

    mciOpenParms.lpstrDeviceType = “waveaudio”;

확장자가 wav인 파일을 열기 위해서 디바이스 타입능 waveaudio라고 지정해준
것입니다.

    mciOpenParms.lpstrElementName =
“d:test.wav”;

플레이할 파일의 이름을 지정해 주고 있습니다.

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

실제로 MCI 장치를 여는 과정을 보여 주고 있습니다. 특별한 부분은 없는 것
같군요.

    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;

구조체 멤버중 dwCallback에 윈도우의 핸들을 지정해 주고 있습니다.

    mciError = mciSendCommand(dwID, MCI_PLAY,
MCI_NOTIFY,
        (DWORD)&mciPlayParms);

이 구조체를 이용해서 플레이하는 과정을 보여주고 있습니다. 세번째 파라미터에 쓰인
MCI_NOTIFY에 의해서 플레이가 끝나면 윈도우에 MM_MCINOTIFY메시지를 보내 줍니다.

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

플레이가 안되면 에러 메시지를 출력하기 위한 구문입니다.

}

void Stop(HWND hWnd, DWORD dwID)
{

이 함수는 플레이를 중지하는 역할을 합니다. 이 함수에 의해서 플레이가 중지 되도 윈도우에
MM_MCINOTIFY메시지를 보냅니다.

    MCI_GENERIC_PARMS mciGenericParms;

중지하기 위해서 사용할 함수의 파라미터에 위 구조체 변수가 필요합니다.

    MCIERROR mciError;

에러를 체크하기 위한 변수입니다.

    mciError = mciSendCommand(dwID, MCI_STOP,
MCI_WAIT,
        (DWORD)&mciGenericParms);

중지를 하는 과정입니다. 세번째 파라미터에 MCI_WAIT가 지정된다는 것을 기억하시기
바랍니다. 그냥 NULL로 지정해도 아마 같은 결과가 나올 겁니다.

    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 Resume(HWND hWnd, DWORD dwID)
{

이 함수는 잠시 중지된 것을 다시 플레이하는 역할을 하고 있습니다. 물론 중지된 곳부터 다시
플레이됩니다.

    MCI_GENERIC_PARMS
mciGenericParms;
    MCIERROR mciError;

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

사용방법이 같죠?

}

void Close(HWND hWnd, DWORD dwID)
{

이 함수는 MCI 장치를 닫는 역할을 합니다.

    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 MoveStartPosition(HWND hWnd, DWORD
dwID)
{

이 함수는 플레이 될 위치를 처음으로 옮기는 역할을 합니다.

    MCI_SEEK_PARMS mciSeekParms;

위치를 바꾸기 위해서는 위 구조채 변수를 사용한다고 설명 드렸을 겁니다.

    MCIERROR mciError;

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

두번째 파라미터의 MCI_SEEK가 위치를 옮기겠다는 의미이고 세번째 파라미터에 쓰인
MCI_SEEK_TO_START가 처음 부분으로 옮긴다는 의미입니다.

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

별로 크게 어려운 부분은 없죠? 그러면 확장자가 wav인 파일을 플레이하는 다른 방법을 알아
봅시다. 참 방법이 다양하죠?

이 방법은 문자열을 이용해서 하는 방법인데 상당히 간단합니다. 역시 커다란 과정은 같습니다.
MCI 장치를 열고 플레이하고 나중에 닫고 뭐 그런 과정이죠.

우리는 앞에서 mciSendCommand()라는 함수를 이용해서 위의 모든 과정을 처리했는데
이번에는 mciSendString()이라는 함수를 이용해서 위의 모든 과정을 처리할 것입니다.

MCIERROR mciSendString(
    LPCTSTR
 lpszCommand,
    LPTSTR  lpszReturnString,
    UINT
 cchReturn,
    HANDLE  hwndCallback
   );

첫번째 파라미터는 정의된 특별한 문자열을 지정해주면 되는데 이 부분에 어떻게 지정하느냐에
따라 MCI 장치를 열기도 하고 플레이하기도 합니다. 두번째 파라미터는 이 함수를 사용하고 나서 리턴되는 문자열을 저장할 버퍼를 의미하고 세
번째 파라미터는 버퍼의 크기 마지막 파라미터는 윈도우의 핸들을 지정하면 됩니다.

자 그러면 위 함수의 첫번째 파라미터에 어떤 문자열을 지정해서 어떤 작업을 하는지 알아
봅시다.

먼저 MCI 장치를 여는 방법부터 봅시다. MCI 장치를 열기 이해서는 open이라는
문자열을 이용해서 할 수 있습니다. 물론 이 문자열만으로는 불가능하죠. MCI 장치가 어떤 형태이고 또 어떤 파일인지도 같이 지정해 주어야 할
겁니다.

예를들어 볼까요?

open d:test.wav type waveaudio alias wavefile

open 다음에 오는 것이 바로 플레이할 파일 이름입니다. 그리고 파일 타입이 어떤 것인지
지정해 주어야 하는데 이때 type이라는 문자열 다음에 그 타입을 지정해 주면 됩니다. 확장자가 wav이니 waveaudio라고 지정해 준
것입니다. 앞에서 한 것과 같죠? 그 다음에 보면 alias라는 문자열이 있는데 이 문자열 다음에 오는 문자열이 우리가 앞에서 알아본 장치
아이디와 같은 역할을 합니다. 무슨 말인지 알겠습니까? 위 예를 보면 앞으로 우리는 wavefile이라는 문자열을 이 장치의 아이디로
사용하겠다는 의미입니다.

자 그러면 여는 방법을 알았으니 닫는 방법도 알아 봅시다. 닫을 때에는 close라는
문자열을 사용하면 됩니다. close 다음에는 닫을 장치의 아이디를 나타내는 문자열을 지정해 주면 됩니다.

플레이할 때에는 어떤 문자열을 사용할까요? 짐작이 가죠? 바로 play라는 문자열을
사용합니다. 역시 play 다음에 장치 아이디를 의미하는 문자열이 오고 그 다음에 notify라는 문자열이 옵니다. 이 문자열은 어디서 많이
보지 않았습니까? 잘 기억이 나지 않으면 앞 부분을 보세요. 아마 MCI_NOTIFY가 보일겁니다. 물론 그 역할도 같습니다. 플레이가 끝났을때
윈도우에 MM_MCINOTIFY 메시지를 보냅니다. 플레이를 중지할 때에는 stop이라는 문자열을 사용하고 잠시 중단할 때에는 pause 다시
플레이할 때에는 resume이라는 문자열을 사용합니다. 물론 장치 아이디를 의미하는 문자열과 같이 쓰입니다.

그러면 실제로 문자열을 이용해서 플레이하는 프로그램을 작성해
봅시다.

 

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

아래는 리소스 파일입니다.

#include <windows.h>

MyMenu MENU
BEGIN
    POPUP
“&Wave”
    BEGIN
        MENUITEM “&Play”,
100
        MENUITEM “P&ause”, 200
        MENUITEM “&Resume”,
300
        MENUITEM “&Stop”, 400
    END
END

아래는 프로그램 파일입니다.

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

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);
char* Open(HWND hWnd);
void Play(HWND hWnd, char *str);
void
Stop(HWND hWnd, char *str);
void Pause(HWND hWnd, char *str);
void
Resume(HWND hWnd, char *str);
void Close(HWND hWnd, char *str);

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 char szID[80];

        switch(message)
        {
            case
WM_CREATE :

                strcpy(szID,
Open(hWnd));
                return 0;

            case MM_MCINOTIFY :

                Close(hWnd,
szID);
                strcpy(szID, Open(hWnd));
                return
0;

            case WM_COMMAND :

                switch(LOWORD(wParam))
                {
                    case
100 :

                        Play(hWnd,
szID);
                        break;

                    case 200 :

                        Pause(hWnd,
szID);
                        break;

                    case 300 :

                        Resume(hWnd,
szID);
                        break;

                    case 400 :

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

            case WM_DESTROY :

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

char* Open(HWND hWnd)
{
    MCIERROR
mciError;
    static char szReturn[80];

 mciError = mciSendString(“open d:test.wav type
waveaudio alias wavefile”,
        szReturn, 80,
hWnd);
    if(mciError)
        MessageBox(hWnd, “Open Error!!”, “Error”,
MB_OK);
    return “wavefile”;
}

void Play(HWND hWnd, char
*str)
{
    MCIERROR mciError;
    static char szReturn[80],
szString[80];

    sprintf(szString, “play %s notify”,
str);
    mciError = mciSendString(szString, szReturn, 80,
hWnd);
    if(mciError)
        MessageBox(hWnd, “Play Error!!”, “Error”,
MB_OK);
}

void Stop(HWND hWnd, char
*str)
{
    MCIERROR mciError;
    static char szReturn[80],
szString[80];

    sprintf(szString, “stop %s”,
str);
    mciError = mciSendString(szString, szReturn, 80,
hWnd);
    if(mciError)
        MessageBox(hWnd, “Stop Error!!”, “Error”,
MB_OK);
}

void Pause(HWND hWnd, char
*str)
{
    MCIERROR mciError;
    static char szReturn[80],
szString[80];

    sprintf(szString, “pause %s”,
str);
    mciError = mciSendString(szString, szReturn, 80,
hWnd);
    if(mciError)
        MessageBox(hWnd, “Pause Error!!”, “Error”,
MB_OK);
}

void Resume(HWND hWnd, char
*str)
{
    MCIERROR mciError;
    static char szReturn[80],
szString[80];

    sprintf(szString, “resume %s”,
str);
    mciError = mciSendString(szString, szReturn, 80,
hWnd);
    if(mciError)
        MessageBox(hWnd, “Resume Error!!”,
“Error”, MB_OK);
}

void Close(HWND hWnd, char
*str)
{
    MCIERROR mciError;
    static char szReturn[80],
szString[80];

    sprintf(szString, “close %s”,
str);
    mciError = mciSendString(szString, szReturn, 80,
hWnd);
    if(mciError)
        MessageBox(hWnd, “Resume Error!!”,
“Error”, MB_OK);
}

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

 

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

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

이번시간에는 확장자가 mid인 미디 파일을 어떻게 플레이하는지 알아 보겠습니다. 아마 머리가
좋으신 분은 이미 어떻게 구현하는지 짐작을 하고 있을 겁니다.

이곳도 역시 mciSendCommand()함수와 mciSendString()함수 두가지
방법을 이용해서 구현할 수 있습니다. 먼저 저번시간에 알아본 mciSendString()함수를 이용해서 구현하는 방법을 알아 봅시다.

아주 간단합니다. 위에서 사용했던 MCI 장치 이름인 waveaudio 대신에
sequencer 를 사용하면 되는 것입니다. 이 sequencer를 어디서 본 것 같죠? 멀티미디어 처음 부분에서 system.ini 파일을
설명드렸을 때 언급했을 겁니다. 이 문자열이 바로 미디 장치를 의미하는 것입니다. 자 그러면 이것을 이용해서 프로그램을 만들어 봅시다.

#include <windows.h>

MyMenu MENU
BEGIN
    POPUP
“&Midi”
    BEGIN
        MENUITEM “&Play”,
100
        MENUITEM “&Stop”, 200
    END
END

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

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);
char* Open(HWND hWnd);
void Play(HWND hWnd, char *str);
void
Stop(HWND hWnd, char *str);
void Close(HWND hWnd, char *str);

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 char szID[80];

        switch(message)
        {
            case
WM_CREATE :

                strcpy(szID,
Open(hWnd));
                return 0;

            case MM_MCINOTIFY :

                Close(hWnd,
szID);
                strcpy(szID, Open(hWnd));
                return
0;

            case WM_COMMAND :

                switch(LOWORD(wParam))
                {
                    case
100 :

                        Play(hWnd,
szID);
                        break;

                    case 200 :

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

            case WM_DESTROY :

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

char* Open(HWND hWnd)
{
    MCIERROR
mciError;
    static char szReturn[80];

  mciError = mciSendString(“open d:test.mid type
sequencer alias midifile”,
        szReturn, 80,
hWnd);
    if(mciError)
        MessageBox(hWnd, “Open Error!!”, “Error”,
MB_OK);
    return “midifile”;
}

void Play(HWND hWnd, char
*str)
{
    MCIERROR mciError;
    static char szReturn[80],
szString[80];

    sprintf(szString, “play %s notify”,
str);
    mciError = mciSendString(szString, szReturn, 80,
hWnd);
    if(mciError)
        MessageBox(hWnd, “Play Error!!”, “Error”,
MB_OK);
}

void Stop(HWND hWnd, char
*str)
{
    MCIERROR mciError;
    static char szReturn[80],
szString[80];

    sprintf(szString, “stop %s”,
str);
    mciError = mciSendString(szString, szReturn, 80,
hWnd);
    if(mciError)
        MessageBox(hWnd, “Stop Error!!”, “Error”,
MB_OK);
}

void Close(HWND hWnd, char
*str)
{
    MCIERROR mciError;
    static char szReturn[80],
szString[80];

    sprintf(szString, “close %s”,
str);
    mciError = mciSendString(szString, szReturn, 80,
hWnd);
    if(mciError)
        MessageBox(hWnd, “Resume Error!!”,
“Error”, MB_OK);
}

전체적으로 웨이브 파일을 플레이할 때와 크게 달라진 점은 없을 겁니다. 그런데 한 가지
이상한 점이 있죠? 바로 잠시중단하는 경우와 다시 플레이하는 기능이 위 프로그램에서 빠져 있습니다. 왜 그럴까요? 우리는 파일을 플레이했을 때
잠시 중단하는 명령어인 pause라는 것을 사용했을 겁니다. 그런데 문제는 이 미디 파일을 플레이할 때 pause문자열을 사용해서 잠시 중단하면
바로 MM_MCINOTIFY 메시지가 발생되는 것입니다. 이 메시지는 stop문자열을 사용해서 정지를 하거나 플레이가 끝났을 때 발생되는
메시지인데 pause 문자열에 의해서 이 메시지가 발생되는 resume 메시지 처리가 정상적으로 되지 않는다는 것입니다. 그렇기 때문에 이
기능을 위 프로그램에서 뺀 것입니다. 대신 이 기능을 추가한 것을 mciSendCommand() 함수를 이용해서 만들어 볼 것입니다.

자 그러면 또 달라진 점을 보도록 하죠.

case MM_MCINOTIFY :

    Close(hWnd, szID);
    strcpy(szID,
Open(hWnd));
    return 0;

바로 위 메시지 처리 부분입니다. 웨이브 파일을 플레이했을 때 발생되는
MM_MCINOTIFY 메시지 처리 부분과 다르죠? 장치를 닫아주고 다시 열어 주어야 다시 플레이를 선택했을 때 바로 플레이가
가능해집니다.

이제 MCI 장치를 여는 Open()함수를 보도록 합시다.

char* Open(HWND hWnd)
{
    MCIERROR
mciError;
    static char szReturn[80];

  mciError = mciSendString(“open d:test.mid type
sequencer alias midifile”,
        szReturn, 80, hWnd);

함수의 사용방법은 같습니다. 단 waveaudio라는 장치 이름대신에 미디 파일을 의미하는
sequencer를 사용했습니다.

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

에러 처리부분은 변한게 없구요.

    return “midifile”;
}

그 외에는 다른점이 없죠?

자 그러면 이번에는 PAUSE기능과 RESUME기능이 있는 미디 플레이를 구현해 봅시다.
이것을 구현할 때 우리는 미디 파일을 플레이해주는 mciSendCommand()함수를 이용해서 구현할 것입니다. 이 함수의 사용방법을 다시 한번
상기 해 보십시요. 생각 납니까? 잘 나지 않으면 조금 앞 부분을 다시 보기 바랍니다. 다시 설명 드리지 않을테니까요.

전체적인 원리는 간단합니다. MCI_STOP을 사용해서 정지를 시키던 MCI_PAUSE를
이용해서 정지를 시키던지 MM_MCINOTIFY메시지가 발생되니 어느 것에 의해서 이 메시지가 발생되었는지 구분시켜 주어야 합니다. 그래야 각각
처리를 할테니까요. 이 문제는 변수 하나로 간단하게 해결할 수 있습니다. 그래서 만약에 MCI_STOP에의해서 정지가 된거면 우리가 웨이브
파일을 mciSendCommand()함수로 구현할 때와 마찬가지로 플레이될 위치를 처음으로 옮겨주면 되고 그렇지 않고 MCI_PAUSE에 의해서
발생되었다면 현재 플레이된 위치를 얻어서 그 위치로 다시 세팅해주면 됩니다. 그리고 만약에 사용자가 resume을 선택한다면
MCI_RESUME을 이용해서 다시 플레이하는것이 아니라 MCI_PLAY를 이용해서 플레이 해주면 되는 것입니다.

플레이될 위치를 처음으로 옮기는 방법은 앞에서 알아 보았으니 생략하고 현재 플레이되고 있는
위치와 또 세팅하는 방법을 알아 보도록 합시다.

우리는 앞에서 mciSendCommand()함수를 사용할때 마지막 파라미터에 특수한 구조체
변수의 주소를 지정해 주었는데 현재 플레이된 곳의 위치를 얻고자 할때에도 특수한 구조체 변수의 주소를 지정해 주어야 합니다. 이 때 사용하는
구조체가 바로 MCI_STATUS_PARMS입니다.

typedef struct {
    DWORD
 dwCallback;
    DWORD  dwReturn;
    DWORD  dwItem;
    DWORD
 dwTrack;
} MCI_STATUS_PARMS;

멤버중 dwItem에 MCI_STATUS_POSITION이라는 예약어를 지정해준 다음에
mciSendCommand() 함수를 사용하면 됩니다.

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

바로 위와 같이 사용하면 됩니다. 두번째 파라미터에  MCI_STATUS를 지정하고 세번째
파라미터에  MCI_STATUS_ITEM을 지정하면 됩니다.

위와 같이 사용하면 구조체 멤버중 dwReturn에 그 위치가 저장되니 이 값을 얻으면 바로
그 값이 위치가 되는 것입니다.

그러면 이번에는 플레이될 위치를 세팅하는 방법을 알아 봅시다. 그런데 이것은 이미 낯이
익을지도 모르겠습니다. 이미 앞에서 비슷한 것을 알아 보았거든요. 바로 플레이될 위치를 처음으로 옮길 때 사용했던 MCI_SEEK을 이용해서
합니다. 이것을 이용해서 mciSendCommand()함수를 사용할 때에 MCI_SEEK_PARMS이라는 구조체 변수의 주소가 필요했던 것이
기억날 겁니다.

이 구조체 멤버중 dwTo에 옮길 곳을 지정해 주고 mciSendCommand()함수의 세
번째 파라미터에 MCI_TO를 지정해서 사용해주면 지정해준 곳을 옮길 수 있습니다.

그러면 이것을 이용한 실제적인 프로그램을 보도록
합시다.

 

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

#include <windows.h>

MyMenu MENU
BEGIN
    POPUP
“&Midi”
    BEGIN
        MENUITEM “&Play”,
100
        MENUITEM “P&ause”, 200
        MENUITEM “&Resume”,
300
        MENUITEM “&Stop”, 400
    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);

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;

        switch(message)
        {
            case
WM_CREATE :

                dwID =
Open(hWnd);
                return 0;

            case MM_MCINOTIFY :

                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;

                    case 400 :

                        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 =
“sequencer”;
    mciOpenParms.lpstrElementName = “d:test.mid”;

    mciError = mciSendCommand(NULL, MCI_OPEN,
MCI_OPEN_TYPE|MCI_OPEN_ELEMENT,
        (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 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_SEEK_PARMS mciSeekParms;
    MCIERROR
mciError;

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

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

zemna

Programmer/Web/Mobile/Desktop

You may also like...

Leave a Reply