9.17(월) 이론-4( 종료과정이해 )

from Study/API 2007/10/10 16:15 view 16851
1. 종료과정 이해하기


- 윈도우가 종료 하기 바로 전에 해야 할일은 주로 WM_CLOSE 메시지 에서 처리한다.!!
Tag | ,
1. 마우스 캡쳐

- 일반적으로 마우스 메시지는, 메시지가 발생할 당시 커서의 아래 있는 윈도우에게 전달된다. 하지만 SetCapture()함수를 사용하므로서 이런 행동을 변경 할 수 있다.
- 특정 윈도우가 SetCapture() 함수를 사용해서 마우스를 캡쳐할 경우, 모든 마우스 메시지는 마우스를 캡쳐한 윈도우에게로 전달된다.

2. 마우스 캡쳐하기
- 마우스 캡쳐는 아래의 3가지 경우에 해지된다.
  1) RealeaseCapture() 를 호출 한 경우
  2) 다른 윈도우가 마우스를 캡쳐한 경우
  3) 사용자가 다른 스레드가 만든 윈도우를 클릭 한 경우
- 마우스 캡쳐가 해지될 경우, 캡쳐를 잃은 윈도우에 WM_CAPTURECHANGED 메시지가 전달된다.
이 때 lParam에는 새롭게 마우스를 캡쳐 한 윈도우의 핸들이 들어 있다.

3. 마우스가 캡쳐 되어 있을 경우 WM_NCHITTEST, WM_SETCURSOR 메시지는 발생되지 않는다.
4. 예제 코드( 다른 윈도우 캡쳐하기 )

more..




1. 마우스 좌표
- 어디를  기준으로 보냐에 따라서 스크린 좌표계, 윈도우 좌표계, 클라이언트 좌표계로 나눌수 있다.

- ClinetToScreen | ScreenToClient ( 두개 외에 나머지 함수 만들기 )
void
WindowToScreen(HWND hwnd, POINT* Point)
{
      RECT Rect;
      GetWindowRect( hwnd, &Rect );
      Point->x = Point->x + Rect.left;
      Point->y = Point->y + Rect.top;
}
void ScreenToWindow(HWND hwnd, POINT* Point)
{
      RECT Rect;
      GetWindowRect( hwnd, &Rect );
      Point->x = Point->x - Rect.left;
      Point->y = Point->y - Rect.top;
}
void WindowToClient(HWND hwnd, POINT* Point)
{
      WindowToScreen( hwnd, Point );
      ScreenToClient( hwnd, Point );
}
void ClientToWindow(HWND hwnd, POINT* Point)
{
      ClientToScreen( hwnd, Point );
      ScreenToWindow( hwnd, Point );
}
Tag | ,

9.17(월) 이론-2(WM_NCHITTEST)

from Study/API 2007/10/10 15:47 view 18233
1. WM_NCHITTEST

- Cursor가 움직이거나 마우스 버튼을 누르거나 놓을 때, System은 커서 아래 있는 윈도우(마우스를 캡쳐한 경우 캡쳐한 윈도우)에게 WM_NCHITTEST 메시지를 보낸다.(sent)
- 이때 대부분 윈도우 프로시저는 이 메세지를 직접 처리 하지 않고 DefWindowProc으로 보내는데 DefWindowProc는 커서의 좌표를 조사해서 커서가 현재 윈도우의 어느 부분에 커서가 있는지 나타내는
Hit Test Code 를 리턴한다.
- WM_NCHITTEST의 결과로 얻어진 HitTestCode가 다음 메시지를 결정하는데 사용된다.

- 예제 코드( Control키를 누른 상태에서 클라이언트 영역에서 마우스의 왼쪽 버튼을 누르면 윈도우를 이동 )
    // WM_NCHITTEST 를 처리하는 방법
    case WM_NCHITTEST:
        {
            // 1. 먼저 DefWindowProc()으로 전달해서 hit test code를 얻는다.
            int code = DefWindowProc( hwnd, msg, wParam, lParam );

            // 2. code를 조작한다.
            if( code == HTCLIENT && GetKeyState( VK_CONTROL ) < 0 )
                code = HTCAPTION;

            // 3. code를 리턴한다. - 다음 메세지는 이 리턴값에 의해 결정된다.
            return code;
        }

Tag | ,

9.17(월) 이론-1

from Study/API 2007/10/10 15:22 view 24999
1.  WinMain() : 윈도우 클래스를 등록,생성

- CreateWindowEx() 는 WM_CREATE메세지를 발생시킨다. 이때 이 메세지를 처리를 먼저하고 HANDLE값을 반환한다.
- DestroyWindow()는 WM_DESTROY를 발생하며 윈도우를 파괴시킨다.
- 비Q메시지는 API함수 호출시 주로 발생하며 메세지 처리 함수에 직접 전달한다.
- 입력 메시지(마우스 메세지, 키보드 메세지)를 제외한 대부분의 메시지가 non-queued Message 이다.


- SendInput을 통하여 마우스, 키보드 드라이버에서 SHIQ로 가상으로 키를 넣을 수 있다.(화상키보드)
- 키보드 : 활성화된 윈도우에 메시지를 입력한다. Raw가 담당..
- 스레드당 한개 씩 메세지 Q를 갖는다. GetMessage를 통해서 메시지를 끄집어 낸다.
- DispatchMessage는 WndProc에 메시지를 전달해주는 역할을 한다.

- WM_PAINT
 => GetMessage does not remove WM_PAINT messages from the queue. The messages remain in the queue until processed. 참고(페졸드책:108page)
 윈도우 프로시저가 WM_PAINT 메시지를 처리하면서 BeginPaint()를 호출하면, 클라이언트 영역 전체는 유효화된다.
 또한 프로그램은 ValidateRect()를 호출함으로써 클라이언트 영역의 임의 직사각형 영역을 유효화할 수도 있다. 만약 이 호출의 결과로 무효 영역 전체가 유효화된다면, 메시지 큐에 현재 저장되어 있는 WM_PAINT 메시지는 제거된다.

- WM_KEYDOWN, WM_CHAR 메시지 ( 제프리 : 990p 메시지Q 꺼내오기)
1. QS_SENDMESSAGE 플래그가 설정되어 있으면 해당 메시지를 적절한 윈도우 프로시저로 보낸다. 이 작업 후에 함수는 리턴 하지 않고 계속 다음 메시지를 기다린다.
 2. POST 메시지 큐에 메시지가 있으면 인자로 전달된 MSG 구조체에 해당 메시지 정보를 복사한 후 리턴한다.
 3. QS_QUIT 플래그가 설정되어 있으면 WM_QUIT 메시지를 리턴하고, QS_QUIT 플래그를 제거한다.
 4. 하드웨어 입력 큐에 메시지(WM_KEYDOWN, WM_LBUTTONDOWN, …)가 있다면 MSG 구조체에 해당 메시지 정보를 복사한 후 리턴한다.
 5. QS_PAINT 플래그가 설정되어 있으면 WM_PAINT 메시지를 리턴한다.
 6. QS_TIMER 플래그가 설정되어 있으면 WM_TIMER 를 리턴한다.

WM_KEYDOWN, WM_CHAR, WM_KEYUP 의 처리 순서도 위의 알고리즘을 통하면 쉽게 이해할 수 있다. 기본적으로 사용자가 키보드를 눌렀다 떼게 되면 WM_KEYDOWN, WM_KEYUP 이 하드웨어 입력 메시지 큐에 추가된다.
WM_KEYDOWN 이 TranslateMessage 를 통하면 적절한 형태의 WM_CHAR 메시지가 PostMesage 로 큐에 추가된다. 물론 이 과정에서 WM_CHAR 가 WM_KEYUP 보다 늦게 추가되었지만 위의 알고리즘의 우선순위 판정에 의해서 다음 번 처리되는 메시지는 WM_CHAR 가 되는 것이다.


2. 사용자 정의 메시지

- SendMessage : 동기 메시지 전달(Non-Queue) GetMessage에서 리턴하지 않는다??
- PostMessage : 비동기 메시지 전달( 리턴값을 받을수 없다. ) 메시지를 보낸후에 대기하지 않는다.

- 0x000~0x03FF    : 미리 정의 메시지
- 0x0400~0x7FFF  : Control Message            WM_USER+a
- 0x8000~0xBFFF  : Application Message      WM_APP+a
- 0xC000~0xFFFF : Register Window Message()
- 0x10000~          : Reserved 보호되는 영역

- WPARAM => UINT : 16비트 시절 2바이트로 word였다. 지금은 4바이트
- LPARAM => ULONG

3. 메시지 Q 모양
- 우선순위 GetMessage Remark 참고

1. Sent messages
2. Posted messages
3. Input (hardware) messages and system internal events
4. Sent messages (again)
5. WM_PAINT messages
6. WM_TIMER messages

- WM_PAINT는 중복되었을때 무효영역의 합해진 크기를 지니게 된다. PAINTSTRUCT에 저장 넘어감.

1. SendMessage( 우선적으로 처리하게 한다.)
2. SendMesageNotify( 리턴을 기달리지 않는다. 그러면서 우선적으로 처리하게 된다. )





 

Tag | ,

9.17(월) 실습

from Study/API 2007/10/10 14:18 view 19490
// 1. 메세지 전달.
// 계산기의 Hwnd를 얻어 일반용으로 만든다.
int main()
{
    HWND hwnd = FindWindow( 0, "계산기" );
    if( hwnd == 0 )
    {
        printf( "계산기를먼저 실행\n");
        return 0;
    }
    SendMessage( hwnd, WM_COMMAND, 305, 0 );
}
// 계산기의 Hwnd를 얻어 윈도우를 닫는다.
int main()
{
    HWND hwnd = FindWindow( 0, "계산기" );

    if ( hwnd == 0 )
    {
        printf( " B를 먼저 실행.\n" );
        return 0;
    }
    //---------------------------
    int result = 0;
    result = SendMessage( hwnd, WM_CLOSE, 10, 20 );

    printf( "결과 : %d\n", result );
}


// 2. WM_CLOSE 와 WM_NCHITTEST

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch( msg )
    {   
    case WM_CLOSE:
        {
            UINT ret = MessageBox( hwnd, "정말 종료?", "확인", MB_YESNO );

            if( ret == IDYES )
            {
                // 죽인다.. 또는 DefWindowProc()로 보내도 된다.
                DestroyWindow( hwnd );
            }
        }
        return 0;

    // WM_NCHITTEST 를 처리하는 방법
    case WM_NCHITTEST:
        {
            // 1. 먼저 DefWindowProc()으로 전달해서 hit test code를 얻는다.
            int code = DefWindowProc( hwnd, msg, wParam, lParam );

            // 2. code를 조작한다. Ctrl 누르고 끌면 창이 이동.
            if( code == HTCLIENT && GetKeyState( VK_CONTROL ) < 0 )
                code = HTCAPTION;

            // 3. code를 리턴한다. - 다음 메세지는 이 리턴값에 의해 결정된다.
            return code;
        }

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

9.13(목) 이론-3

from Study/API 2007/10/10 14:12 view 19744
1. Window Object

- CreateWindow : OS가 윈도우를 관리할 때 가지고 있는 구조체를 가지고 윈도우를 표현한다.
- ShowWindow는 이 구조체의 위치를 Handle로 받아 표시한다.
- Handle Table
- 이 구조체에 접근할 수 있는 함수는
- SetWindowLong, SetWindowLongPtr( 32 or 64bit 호환 ), GetWindowLong, GetWindowLongPtr


- 윈도우는 눈에 보이는 구조체 일뿐 이라고 할 수 있다. ( WND32 구조체 )

- 등록된 윈도우 클래스로 부터 여러개의 윈도우를 만들수 있는데 윈도우클래스 관리구조체에 여분의 메모리를 추가 하여 사용자가 사용할 수 있다.
Tag | ,

9.13(목) 이론-2

from Study/API 2007/10/10 13:45 view 18263
1. EXE의 종류
   
- Console App : 콘솔창을 생성한다. main, 콘솔(/SUBSYSTEM:CONSOLE)
- GUI App : 윈도우창을 생성.           WinMain,Windows (/SUBSYSTEM:WINDOWS)
- Net App : CLR을 동작한다.

- Linker 옵션의 Subsytem차이 일 뿐이다.
- #pragma comment( linker, "[옵션]" )

- WhatExe ( EXE의 종류를 파악한다. )

more..




 

2. Data Type

P Pointer를 나타낸다. ( ex : PPOINT -> POINT* )
LP 32비트 Code에서는 P와 완전히 같다. WIN32에서 PSTR과 LPSTR은 같은 코드.
T,_t T는 DBCS와 UNICODE Type을 동시에 지원하기 위한 매크로이다.(TCHAR->char,wchar_t)
W UNICODE Type이다.
C const를 의미한다.
STR 문자열을 나타낸다.( ex : PSTR->char*)
H H로 시작하는 대부분의 Type은 핸들형 Type을 나타낸다.( ex : HWND, HPEN, HBRUSH )

- 윈도우 구조체의 크기를 얻는 이유( Window Version이 많아서-_-.. )
- 구조체의 크기는 조건에 따라 달라지므로 구조체에서 크기를 저장하는 변수를 가지고 있다.


3. HANDLE 개념 : 객체를 가리키는 번호, 32bit 정수(long), 고유의 번호를 가진다.

- OS는 HANDLE 번호를 만들어서 리턴해준다.
- HWND : 윈도우 번호
- HPEN : 펜 번호
- HBRUSH : 브러시 번호

4. 윈도우 만들기 GUI 윈도우 생성!!

- 모든 윈도우는 윈도우 클래스로 부터 만들어진다.

- 배경색, 아이콘, 이름, 윈도우틀(클래스).. 이 필요하다.
- 윈도우 클래스를 시스템에 등록한다.
- 등록된 클래스로 윈도우를 생성한다.
- 윈도우를 보여준다.

- 미리 가져다 쓸수 있는 등록된 클래스가 40~50개가 있다.(button, edit...)
- OS는 윈도우클래스모음 List를 가지고 이를 관리한다. 65536개를 관리 가능하다.


5. 윈도우 핸들

- API함수의 대부분은 핸들만 알고 있다면 윈도우를 조작가능 하다. ex) MoveWindow, Setmenu...
- 핸들을 얻을 수 있는 함수들.  ex) FindWindow, WindowFromPoint
- 예제 코드 ( 계산기 자식 윈도우 )

more..


- 예제코드 ( 계산기 자식윈도우 숨기기 )

more..


Tag | ,

9.13(목) 이론-1

from Study/API 2007/10/10 12:06 view 17871
  1. UNICODE
    1. 초기 한 글자를 1Byte(256) 라서 문자를 표현하는데에 한계가 있었다.
    2. So, 한 글자를 2Byte(65536) 으로 문자를 표현 했지만 메모리를 너무 잡아먹는다.
    3. So, 영어권 : 1Byte, 다른나라 : 2Byte 로 정해 해결하였다.
    4. UNICODE : 모든 글자에 고유한 번호를 지정하였다.
    5. 매크로기반 코드가 나오게 되는 이유 : (tchar.h에 정의된 것)
      1. Strlen은 null 하나만 있어도 길이를 구해주기 때문에 제대로 문자열의 길이를 구하지 못한다. null 두개 일때의 길이를 구하는 함수는 wcslen이 있다.
    6. WBCS는 네트워크에 용량이 많아지는 단점이 있다.
    7. DBCS 는 모든 나라 말을 표현 하지 못한다. 영어 + 그 지역의 언어만 표현한다.
    8. 이를 해결하기 위해 UTF=> 한글+영어+일본어.. 호환을 해주게 된다.
    9. UTF는 각 언어에 1byte,2byte,3byte,4byte 를 할당하여 표현한다.

  2. 정적 라이브러리
    1. 잘 만들어 놓은 함수 -> obj -> lib 으로 만들기 위해선 링크만 해주면 된다.
    2. static Library(정적 라이브러리)는 오브젝트(obj)파일의 집합이라 할 수 있다.
    3. lib를 만들때의 주의 점은 name mangling으로 호출규약이 c와cpp가 다르므로 extern "C"로 만들 함수를 감싸주는 것이 필요하다.
    4. lib의 특징은 exe의 기계어 코드가 포함되어 실행파일로 만들어지므로 exe만 배포하여 프로그램을 실행 할 수 있다는데에 있다.
    5. 단점은 lib가 중복되어 배포될 수 있다는 점이다.(메모리 낭비) 또한, Update 할때 마다 프로그램을 다시 Build 해줘야 하는 단점이 있다.

  3. DLL(PE포맷)
    1. 배포시 lib(type), dll, .h 를 같이 동봉해야 한다.
    2. .edata : 정보를 누출해야 다른 실행파일에서 접근 할수 있으므로 import 해줘야 한다.
    3. edata는 제공하는 함수에 대한 정보들이 있다. export, import를 구현해야 한다.
    4. lib => object lib은 함수의 기계어 코드가 포함되어 있어서 파일의 크기가 크지만,
    5. lib => type lib은 링크 정보만을 가지고 있다.

  4. 라이브러리를 추가하는 2가지 방법
    1. 소스 : pragma comment( lib, "라이브러리" )
    2. 설정: 프로젝트설정->Linker->Input->Additional depends(추가 종속성)

      5. 다른 윈도우의 HWND에  DestroyWindow( hwnd ); 가 먹히지 않는 이유.

MSDN 에서는 이문제를 한줄로 표현 해놓았는데
"A thread cannot use DestroyWindow to destroy a window created by a different thread"
"스레드간의 WM_DESTROY 메세지 보내는 것을 허용하지 않는다."  란다.-_-..
GetLastError 로 확인 해보면 ERROR_ACCESS_DENIED( 접근 금지 ) 에러코드가 생성된다.
이 문장을 본 한 블로거는 이런 표현을 썻다. 왓 더~ 헬~
"WHAT THE...!?! I have words for that that are inappropriate for this blog. I need a good chunk of lye for cleaning of the mouth."
출처 : http://cubicspot.blogspot.com/2005_03_01_archive.html
아무튼 위대한 MS의 Windows 개발자가 막아놨다. -_-..


 

Tag | ,

9.13(목) 실습-3(UNICODE)

from Study/API 2007/10/10 11:33 view 18892
// 1. STL에서 사용
typedef
basic_string<char>        string;
typedef basic_string<wchar_t> wstring; int _tmain()
{
    string s;
    basic_string<char> s1 = "hello";
    basic_string<wchar_t> s2 = L"ABCD";
}

// 2. MBCS- > WBCS
int _tmain()
{
    char s[] = "ABCD가나다라";

    // 먼저 s를 wide character로 변경할 때 필요한 버퍼의 크기를 계산한다.
    size_t    sz = MultiByteToWideChar( CP_ACP, 0, s, strlen(s), 0, 0 );

    //이제 버퍼를 할당해서 사용한다.
    wchar_t* s2 = new wchar_t[sz];

    // DBCS(MBCS) -> wideChar 로 변환

    MultiByteToWideChar( CP_ACP,    // 문자열 종류( CP_ACP : ANSI 표준 문자열 )
                         0,
                         s,
                         strlen(s),
                         s2, 10 );

    setlocale( LC_ALL, "Korean" );
    wprintf( s2 );    // wide char를 출력하는 printf, C++의 wcout
    cout << endl;

    delete[] s2;
}

// 3.UNICODE
int _tmain()
{
    TCHAR s[] = _T("ABCD가나다라");

    cout << sizeof(s) << endl;
    cout << _tcslen(s) << endl;
}

// 4. UNICODE 매크로
// 매크로
#define UNICODE

#ifdef UNICODE
typedef wchar_t        TCHAR;
#define _T(x)        L##x    // ## : Token paste 두 Token을 붙인다.
#define TEXT(x)        _T(x)
#define _TEXT(x)    _T(x)
#define _tcslen        wcslen
#define _tmain        wmain

#else
typedef char        TCHAR;
#define _T(x)        x
#define _tcslen        strlen
#define _tmain        main

#endif

int _tmain(int argc, TCHAR* argv)
{
    TCHAR s[] = "ABCD가나다라";

    cout << sizeof( s ) << endl;
    cout << _tcslen(s)    << endl;
}

// 4. WBCS( 2바이트로 인식 )
int main()
{
    wchar_t s[] = L"ABCD가나다라";

    cout << sizeof(s) << endl;    // 18 (null 문자도 2byte )

    cout << strlen((char*)s) << endl;

    cout << wcslen(s) << endl;
}
// 5. DBCS
int main()
{
    char s[] = "ABCD가나다라";

    cout << sizeof(s) << endl;    // ?

    char* p = s;

    while(*p)
    {
        cout << p << endl;

        // p = p + 1;    // 단순 포인터 연산을 사용한 경우

        p = CharNext(p);    // DBCS 관련함수를 통해서 다음 글자 얻기
    }
    return 0;
}
Tag | ,

9.13(목) 실습-2

from Study/API 2007/10/10 11:31 view 17593
// 1. 각종 FindWindow 활용
int
main()
{
    HWND h = FindWindow( 0, "계산기" );    // 열려 있는 메뉴의 핸들을 얻는다.

    PostMessage( h, WM_QUIT, 0, 0 );

    //DestroyWindow( h ); // 안된다.이유는 이론편에..
}

int main()
{
    while( 1 )
    {
        Sleep(3000);

        HWND h = FindWindow( "#32768", 0 );    // 열려 있는 메뉴의 핸들을 얻는다.
      ShowWindow( h, SW_HIDE );
    }
}

int main()
{
    //HWND hwnd = FindWindow(
    //    0,            // 윈도우 클래스 이름
    //    "계산기" );    // 캡션바 내용

    // progman 은 바탕화면 이다.
    HWND hwnd = FindWindow( "Shell_TrayWnd", 0 ); // taskbar의 핸들을 얻음.
       
    if ( hwnd == 0 )
    {
        cout << "계산기를 먼저 실행하세요." << endl;
        return 0;
    }
    // -----------------------------
    HRGN h = CreateEllipticRgn( 0, 0, 300, 300 );
    SetWindowRgn( hwnd, h, TRUE );

    //SetMenu( hwnd, 0 );

    //if( IsWindowVisible( hwnd ) )
    //    ShowWindow( hwnd, SW_HIDE );
    //else
    //    ShowWindow( hwnd, SW_SHOW );
}

// 2. DLL 만들어보기


// Dll 소스
 //a.c

#include <stdio.h>    // 이 안에 wchar_t 가 typedef되어 있다.
#define DLLSOURCE
#include "a.h"    //    DLL 헤더

void PutStringA( const char* s )
{
    printf(s);
}
void PutStringW( const wchar_t* s )
{
    wprintf(s);
}
 //a.h

// DLL 내의 모든 함수의 선언을 제공한다.

// 이헤더는 DLL의 제작자가 사용할 때는 각 함수가 export 되도록 한다.
//  DLL 사용자가 사용할 때는 import  되도록 한다.

// 결국 MFC에서 등장하는 AFX_EXT_CLASS의 개념도  아래 DLLAPI의 개념과 완전 동일하다.

 

#ifdef DLLSOURCE

#define DLLAPI __declspec(dllexport)

#else

#define DLLAPI __declspec(dllimport)

#endif

 

#ifdef __cplusplus

extern "C"{

#endif

                  DLLAPI void PutStringA( const char* s );

                  DLLAPI void PutStringW( const wchar_t* s );

#ifdef __cplusplus

}

#endif

 

// UNICODE 매크로에따라서함수를결정할수있는매크로를제공한다.

#ifdef UNICODE

#define PutString    PutStringW

 

#else

#define PutString    PutStringA

#endif

// 1. C/C++ 을모두지원하기위해__cplusplus 사용

// 2. export/import 를위한C++ 지시어를알아야한다.

////////////////////////////////////////////////////////////////////////////////
// DLL을 사용하는 방법

#include "a.h"                                // 1. 헤더 include
#pragma comment(lib, "MyDll.lib")    // 2. lib를 링커에게 알려준다.

int main()
{
    PutStringA("hello");
    PutStringW(L"World\n");
}


Tag | ,