9.20(목) 실습-1

2007/10/10 20:00

1. 버튼 자식윈도우 만들기 ( 가칭 : MyButton )
[ more.. | less.. ]
// 자식( 버튼) 이 부모에게 보낼 때 사용할 통지 코드(메세지를 보내는 이유)를 설계
#define BTN_LCLICK    1
#define BTN_RCLICK    2
#define BTN_DISABLED    3
#define BTN_BTN_ENABLED    4

// 부모가 자식(버튼)을 만들어 놓고 보낼 때 사용할 메세지를 설계한다.
// 일반적으로 컨트롤당 수개~수십개가 설계된다.
#define BM_SETTHICK        WM_USER+10
#define BM_SETSTYLE        WM_USER+11

void Draw3dRect(HDC hdc, int x, int y, int xx, int yy, BOOL down, int width );
LRESULT CALLBACK BtnProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static BOOL bDown = FALSE;
    static int width, height;
    static int thick = 2;

    switch( msg )
    {   
        // 부모가 보낸 메세지 처리
    case BM_SETTHICK:
        thick = (int)wParam;    // 두께를 변경한다.
        InvalidateRect( hwnd, 0, FALSE );    // 다시 그린다.
        return 0;

    case WM_SIZE:
        width = LOWORD(lParam);
        height = HIWORD(lParam);
        InvalidateRect( hwnd, 0, TRUE );
        return 0;

    case WM_LBUTTONDOWN:
        bDown = TRUE;
        InvalidateRect( hwnd, 0, FALSE );
        SetCapture( hwnd );
        return 0;
    case WM_LBUTTONUP:
        if( GetCapture() == hwnd )
        {
            ReleaseCapture();

            bDown = FALSE;
            InvalidateRect( hwnd, 0, FALSE );

            // 자신이 눌려 졌다는 사실을 부모에게 알려준다.
            HWND hParent = GetParent( hwnd );    // 부모의 핸들 구하기
            UINT id         = GetDlgCtrlID( hwnd );    // 자신의 ID 구하기

            SendMessage( hParent, WM_COMMAND, MAKELONG( id, BTN_LCLICK ), //하위16:id 상위16:통지
                (LPARAM)hwnd );    // 자신의 핸들
        }
        return 0;

    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint( hwnd, &ps );

            // 이제 자식은 그림을 그리기 전에 DC를 부모에게 전달해서
            // 부모가 색상을 바꿀 수 있는 기회를 제공한다.
            HWND hParent = GetParent( hwnd );
            SendMessage( hParent, WM_CTLCOLORBTN, (WPARAM)hdc, (LPARAM)hwnd );
            // ------------------------------------------------------------
            // 이제 부모가 변경한 DC를 가지고 그림을 그린다.

            Draw3dRect( hdc, 0, 0, width, height, bDown, thick );
            char title[256];
            GetWindowText( hwnd, title, 256 );    // 부모가 지정한 캡션문자열을 얻는다.
            RECT rc = { 0, 0, width, height };

            if ( bDown == TRUE )        // 버튼이 눌린 경우
                OffsetRect( &rc, thick, thick );
            SetBkMode( hdc, TRANSPARENT );
            DrawText( hdc, title, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER );
            EndPaint( hwnd, &ps );
        }
        return 0;
    }
    return DefWindowProc( hwnd, msg, wParam, lParam);
}

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static HWND hBtn;

    switch( msg )
    {   
        // 자식이 자신의 색상을 변경하라고 부모에게 보내주는 메세지
    case WM_CTLCOLORBTN:
        {
            HDC hdc = (HDC)wParam;
            HWND h = (HWND)lParam;

            if( h == hBtn )    // 버튼이 여러 개일 경우.. 원하는 버튼인지 조사
            {
                SetTextColor( hdc, RGB( 255, 0, 0 ) );
                return 0;
            }
        }
        return 0;    //DefWindowProc( hwnd, msg, wParam, lParam );

    case WM_LBUTTONDOWN:
        {
            static int n = 1;
            ++n;
            // 자식(버튼)의 두께를 변경한다.
            SendMessage( hBtn, BM_SETTHICK, n, 0 );
        }
        return 0;

        // 자식(버튼)이 보내는 메세지 처리
    case WM_COMMAND:
        switch( LOWORD( wParam ) )
        {
        case 1:
            if( HIWORD(wParam) == BTN_LCLICK )    //통지 코드 조사
            {
                MessageBox( 0, "Click", "", MB_OK );
            }
            break;
        }
        return 0;
        // 자식( 버튼)이 보내는 메세지 처리
    case WM_CREATE:
        hBtn = CreateWindowEx( 0, "MyButton", "확인", WS_CHILD | WS_VISIBLE | WS_BORDER,
            10, 10, 100, 100, hwnd, (HMENU)1,
            GetModuleHandle(0), 0);
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc( hwnd, msg, wParam, lParam);
}

void Draw3dRect(HDC hdc, int x, int y, int xx, int yy, BOOL down, int width )
{
    COLORREF clrMain  = RGB(192,192,192),
        clrLight = RGB(255,255,255),
        clrDark  = RGB(128,128,128);

    HPEN hPen1, hPen2, hOldPen;
    HBRUSH hBrush, hOldBrush;    

    if(down)   
    {
        hPen2 = CreatePen(PS_SOLID,1,clrLight);
        hPen1 = CreatePen(PS_SOLID,1,clrDark);
    }
    else
    {
        hPen1 = CreatePen(PS_SOLID,1,clrLight);
        hPen2 = CreatePen(PS_SOLID,1,clrDark);
    } 
    hBrush =  CreateSolidBrush( clrMain );
    hOldPen = (HPEN)SelectObject(hdc, hPen1);
    hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); 

    Rectangle(hdc, x , y, xx+1, yy+1); 

    for(int i=0; i < width; i++)
    {
        SelectObject(hdc, hPen1);

        MoveToEx(hdc, xx - 1, y, 0 );
        LineTo(hdc, x, y);
        LineTo(hdc, x, yy - 1 ); 

        SelectObject(hdc, hPen2);

        MoveToEx(hdc, x, yy,0);
        LineTo(hdc, xx, yy);
        LineTo(hdc, xx, y); 

        x++; y++; xx--; yy--;
    }
    SelectObject(hdc, hOldPen);
    SelectObject(hdc, hOldBrush);

    DeleteObject(hPen1);
    DeleteObject(hPen2);
    DeleteObject(hBrush);
}

2. 메시지 박스에 static text 쓰기 ( 10초 지나면 자동으로 닫기 )
[ more.. | less.. ]
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static char sz[256] = "10 Seconds";
    switch( msg )
    {   
    case WM_CREATE:
        return 0;

    case WM_LBUTTONDOWN:
        SetTimer( hwnd, 1, 1000, 0 );
        MessageBox( hwnd, sz, "Test", MB_OKCANCEL );    //blocking....
        KillTimer( hwnd, 1 );

        return 0;

    case WM_TIMER:
        {
            HWND hBox = FindWindow( "#32770", "Test" );

            static int c = 10;
            --c;
            wsprintf( sz, "%d Seconds", c );

            // 메세지 박스의 Static Control의 내용을 변경한다.
            SetDlgItemText( hBox, 0x0000FFFF, sz );

            if( c == 0 )
            {
                // MessageBox를 닫는다. - 어떻게..??
                // 결국 MessageBox()는 모달 다이얼로그 이다.
                EndDialog( hBox, IDCANCEL );
            }
        }
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
}

3. Button Control Dll 로 만들어 보기 cpp
[ more.. | less.. ]
// button.cpp
#undef
UNICODE
#undef _UNICODE

#define DLL_SOURCE

#include <windows.h>
#include <tchar.h>
#include "button.h"

//////////////////
void Draw3dRect(HDC hdc, int x, int y, int xx, int yy,
                BOOL down, int width )
{
    COLORREF clrMain  = RGB(192,192,192),
        clrLight = RGB(255,255,255),
        clrDark  = RGB(128,128,128);

    HPEN hPen1, hPen2, hOldPen;
    HBRUSH hBrush, hOldBrush;    

    if(down)   
    {
        hPen2 = CreatePen(PS_SOLID,1,clrLight);
        hPen1 = CreatePen(PS_SOLID,1,clrDark);
    }
    else
    {
        hPen1 = CreatePen(PS_SOLID,1,clrLight);
        hPen2 = CreatePen(PS_SOLID,1,clrDark);
    } 
    hBrush =  CreateSolidBrush( clrMain );
    hOldPen = (HPEN)SelectObject(hdc, hPen1);
    hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); 

    Rectangle(hdc, x , y, xx+1, yy+1); 

    for(int i=0; i < width; i++)
    {
        SelectObject(hdc, hPen1);

        MoveToEx(hdc, xx - 1, y, 0 );
        LineTo(hdc, x, y);
        LineTo(hdc, x, yy - 1 ); 

        SelectObject(hdc, hPen2);

        MoveToEx(hdc, x, yy,0);
        LineTo(hdc, xx, yy);
        LineTo(hdc, xx, y); 

        x++; y++; xx--; yy--;
    }
    SelectObject(hdc, hOldPen);
    SelectObject(hdc, hOldBrush);

    DeleteObject(hPen1);
    DeleteObject(hPen2);
    DeleteObject(hBrush);
}

//////////////////////////

LRESULT CALLBACK BtnProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static BOOL bDown = FALSE;
    static int width, height;
    static int thick = 2;

    switch( msg )
    {   
        // 부모가 보낸 메세지 처리
    case BM_SETTHICK:
        thick = (int)wParam;    // 두께를 변경한다.
        InvalidateRect( hwnd, 0, FALSE );    // 다시 그린다.
        return 0;

    case WM_SIZE:
        width = LOWORD(lParam);
        height = HIWORD(lParam);
        InvalidateRect( hwnd, 0, TRUE );
        return 0;

    case WM_LBUTTONDOWN:
        bDown = TRUE;
        InvalidateRect( hwnd, 0, FALSE );
        SetCapture( hwnd );
        return 0;
    case WM_LBUTTONUP:
        if( GetCapture() == hwnd )
        {
            ReleaseCapture();

            bDown = FALSE;
            InvalidateRect( hwnd, 0, FALSE );

            // 자신이 눌려 졌다는 사실을 부모에게 알려준다.
            HWND hParent = GetParent( hwnd );    // 부모의 핸들 구하기
            UINT id         = GetDlgCtrlID( hwnd );    // 자신의 ID 구하기

            SendMessage( hParent, WM_COMMAND, MAKELONG( id, BTN_LCLICK ), //하위16:id 상위16:통지
                (LPARAM)hwnd );    // 자신의 핸들
        }
        return 0;

    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint( hwnd, &ps );

            // 이제 자식은 그림을 그리기 전에 DC를 부모에게 전달해서
            // 부모가 색상을 바꿀 수 있는 기회를 제공한다.
            HWND hParent = GetParent( hwnd );
            SendMessage( hParent, WM_CTLCOLORBTN, (WPARAM)hdc, (LPARAM)hwnd );
            // ------------------------------------------------------------
            // 이제 부모가 변경한 DC를 가지고 그림을 그린다.

            Draw3dRect( hdc, 0, 0, width, height, bDown, thick );
            char title[256];
            GetWindowText( hwnd, title, 256 );    // 부모가 지정한 캡션문자열을 얻는다.
            RECT rc = { 0, 0, width, height };

            if ( bDown == TRUE )        // 버튼이 눌린 경우
                OffsetRect( &rc, thick, thick );
            SetBkMode( hdc, TRANSPARENT );
            DrawText( hdc, title, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER );
            EndPaint( hwnd, &ps );
        }
        return 0;
    }
    return DefWindowProc( hwnd, msg, wParam, lParam);
}

void
InitButtonControl()
{
    ATOM atom;
    WNDCLASS wc;

    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hbrBackground= 0;
    wc.hCursor        = LoadCursor( 0, IDC_ARROW );
    wc.hIcon        = 0;//LoadIcon( 0, IDI_APPLICATION);
    wc.hInstance    = GetModuleHandle(0);
    wc.lpfnWndProc  = BtnProc;
    wc.lpszClassName= _T("mybutton");
    wc.lpszMenuName = 0;
    wc.style        = CS_GLOBALCLASS;    // dll 에서 윈도우 클래스를 등록할때 사용!!!
    atom = RegisterClass( &wc);
}

// 모든 DLL은 메모리에 Load될때 아래 함수가 호출된다.
BOOL WINAPI DllMain( HMODULE hDll, DWORD r, LPVOID how )
{
    if( r == DLL_PROCESS_ATTACH )
    {
        InitButtonControl();
    }
    return TRUE;
}

4. Button Control Dll 로 만들어 보기 .h
[ more.. | less.. ]

#ifdef DLL_SOURCE
#define DLLAPI    __declspec(dllexport)
#else
#define DLLAPI    __declspec(dllimport)
#endif

// 자식( 버튼) 이 부모에게 보낼 때 사용할 통지 코드(메세지를 보내는 이유)를 설계
#define BTN_LCLICK    1
#define BTN_RCLICK    2
#define BTN_DISABLED    3
#define BTN_BTN_ENABLED    4

// 부모가 자식(버튼)을 만들어 놓고 보낼 때 사용할 메세지를 설계한다.
// 일반적으로 컨트롤당 수개~수십개가 설계된다.
#define BM_SETTHICK        WM_USER+10
#define BM_SETSTYLE        WM_USER+11

#ifdef    __cplusplus
extern "C" {
#endif
    DLLAPI void InitButtonControl();
#ifdef __cplusplus
}
#endif

5. Button Dll 사용하기
[ more.. | less.. ]
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static HWND hBtn;
    switch( msg )
    {   
    case WM_COMMAND:
        switch( LOWORD( wParam ) )
        {
        case 1:
            if( HIWORD( wParam) == BTN_LCLICK )
                MessageBox( 0, "Click", "", MB_OK );
            break;
        }
        return 0;

    case WM_CREATE:
        InitButtonControl();
        hBtn = CreateWindowEx(
            0, "mybutton", "OK",
            WS_CHILD | WS_VISIBLE | WS_BORDER,
            10, 10, 100, 100, hwnd, (HMENU)1,
            GetModuleHandle(0), 0 );
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

Tags

API, 실습