컴파일러에게 NT시스템이란걸 알려줘야 하지 않을까~
컴파일러에게 NT시스템이란걸 알려줘야 하지 않을까~
more..
2. DC의 생성을 클래스화 해보기
more..
3. 키상태 조사하기
more..
4. MouseMessage(WM_MOUSELEAVE를 위해선 TRACKMOUSEENVET를 설정해줘야 한다!!!)
more..
5. SendInput 으로 입력 스트림에 키보드 입력을 넣어보자.
more..
- 윈도우가 종료 하기 바로 전에 해야 할일은 주로 WM_CLOSE 메시지 에서 처리한다.!!
- 일반적으로 마우스 메시지는, 메시지가 발생할 당시 커서의 아래 있는 윈도우에게 전달된다. 하지만 SetCapture()함수를 사용하므로서 이런 행동을 변경 할 수 있다.
- 특정 윈도우가 SetCapture() 함수를 사용해서 마우스를 캡쳐할 경우, 모든 마우스 메시지는 마우스를 캡쳐한 윈도우에게로 전달된다.
2. 마우스 캡쳐하기
- 마우스 캡쳐는 아래의 3가지 경우에 해지된다.
1) RealeaseCapture() 를 호출 한 경우
2) 다른 윈도우가 마우스를 캡쳐한 경우
3) 사용자가 다른 스레드가 만든 윈도우를 클릭 한 경우
- 마우스 캡쳐가 해지될 경우, 캡쳐를 잃은 윈도우에 WM_CAPTURECHANGED 메시지가 전달된다.
이 때 lParam에는 새롭게 마우스를 캡쳐 한 윈도우의 핸들이 들어 있다.
3. 마우스가 캡쳐 되어 있을 경우 WM_NCHITTEST, WM_SETCURSOR 메시지는 발생되지 않는다.
4. 예제 코드( 다른 윈도우 캡쳐하기 )
more..
- 어디를 기준으로 보냐에 따라서 스크린 좌표계, 윈도우 좌표계, 클라이언트 좌표계로 나눌수 있다.
- 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 );
}
- 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;
}
- 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)
또한 프로그램은 ValidateRect()를 호출함으로써 클라이언트 영역의 임의 직사각형 영역을 유효화할 수도 있다. 만약 이 호출의 결과로 무효 영역 전체가 유효화된다면, 메시지 큐에 현재 저장되어 있는 WM_PAINT 메시지는 제거된다.
- WM_KEYDOWN, WM_CHAR 메시지 ( 제프리 : 990p 메시지Q 꺼내오기)
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 가 되는 것이다.
- 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
1. Sent messages
2. Posted messages
3. Input (hardware) messages and system internal events
4. Sent messages (again)
- WM_PAINT는 중복되었을때 무효영역의 합해진 크기를 지니게 된다. PAINTSTRUCT에 저장 넘어감.
1. SendMessage( 우선적으로 처리하게 한다.)
2. SendMesageNotify( 리턴을 기달리지 않는다. 그러면서 우선적으로 처리하게 된다. )
 
// 계산기의 Hwnd를 얻어 일반용으로 만든다.
{
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
{
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);
}
- CreateWindow : OS가 윈도우를 관리할 때 가지고 있는 구조체를 가지고 윈도우를 표현한다.
- ShowWindow는 이 구조체의 위치를 Handle로 받아 표시한다.
- Handle Table
- 이 구조체에 접근할 수 있는 함수는
- SetWindowLong, SetWindowLongPtr( 32 or 64bit 호환 ), GetWindowLong, GetWindowLongPtr
- 윈도우는 눈에 보이는 구조체 일뿐 이라고 할 수 있다. ( WND32 구조체 )
- 등록된 윈도우 클래스로 부터 여러개의 윈도우를 만들수 있는데 윈도우클래스 관리구조체에 여분의 메모리를 추가 하여 사용자가 사용할 수 있다.
- Console App : 콘솔창을 생성한다. main, 콘솔(/SUBSYSTEM:CONSOLE)
- GUI App : 윈도우창을 생성. WinMain,Windows (/SUBSYSTEM:WINDOWS)
- Net App : CLR을 동작한다.
- Linker 옵션의 Subsytem차이 일 뿐이다.
- #pragma comment( linker, "[옵션]" )
- WhatExe ( EXE의 종류를 파악한다. )
more..
 
 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이 많아서-_-.. )
- 구조체의 크기는 조건에 따라 달라지므로 구조체에서 크기를 저장하는 변수를 가지고 있다.
- OS는 HANDLE 번호를 만들어서 리턴해준다.
- HWND : 윈도우 번호
- HPEN : 펜 번호
- HBRUSH : 브러시 번호
4. 윈도우 만들기 GUI 윈도우 생성!!
- 모든 윈도우는 윈도우 클래스로 부터 만들어진다.
- 배경색, 아이콘, 이름, 윈도우틀(클래스).. 이 필요하다.
- 윈도우 클래스를 시스템에 등록한다.
- 등록된 클래스로 윈도우를 생성한다.
- 윈도우를 보여준다.
- 미리 가져다 쓸수 있는 등록된 클래스가 40~50개가 있다.(button, edit...)
- OS는 윈도우클래스모음 List를 가지고 이를 관리한다. 65536개를 관리 가능하다.
- API함수의 대부분은 핸들만 알고 있다면 윈도우를 조작가능 하다. ex) MoveWindow, Setmenu...
- 핸들을 얻을 수 있는 함수들. ex) FindWindow, WindowFromPoint
- 예제 코드 ( 계산기 자식 윈도우 )
more..
- 예제코드 ( 계산기 자식윈도우 숨기기 )
more..
- 
UNICODE
- 초기 한 글자를 1Byte(256) 라서 문자를 표현하는데에 한계가 있었다.
 - So, 한 글자를 2Byte(65536) 으로 문자를 표현 했지만 메모리를 너무 잡아먹는다.
 - So, 영어권 : 1Byte, 다른나라 : 2Byte 로 정해 해결하였다.
 - UNICODE : 모든 글자에 고유한 번호를 지정하였다.
 - 
매크로기반 코드가 나오게 되는 이유 : (tchar.h에 정의된 것)
- Strlen은 null 하나만 있어도 길이를 구해주기 때문에 제대로 문자열의 길이를 구하지 못한다. null 두개 일때의 길이를 구하는 함수는 wcslen이 있다.
 
 - WBCS는 네트워크에 용량이 많아지는 단점이 있다.
 - DBCS 는 모든 나라 말을 표현 하지 못한다. 영어 + 그 지역의 언어만 표현한다.
 - 이를 해결하기 위해 UTF=> 한글+영어+일본어.. 호환을 해주게 된다.
 - UTF는 각 언어에 1byte,2byte,3byte,4byte 를 할당하여 표현한다.
 
 - 
정적 라이브러리
- 잘 만들어 놓은 함수 -> obj -> lib 으로 만들기 위해선 링크만 해주면 된다.
 - static Library(정적 라이브러리)는 오브젝트(obj)파일의 집합이라 할 수 있다.
 - lib를 만들때의 주의 점은 name mangling으로 호출규약이 c와cpp가 다르므로 extern "C"로 만들 함수를 감싸주는 것이 필요하다.
 - lib의 특징은 exe의 기계어 코드가 포함되어 실행파일로 만들어지므로 exe만 배포하여 프로그램을 실행 할 수 있다는데에 있다.
 - 
단점은 lib가 중복되어 배포될 수 있다는 점이다.(메모리 낭비) 또한, Update 할때 마다 프로그램을 다시 Build 해줘야 하는 단점이 있다.
 
 - 
DLL(PE포맷)
- 배포시 lib(type), dll, .h 를 같이 동봉해야 한다.
 - .edata : 정보를 누출해야 다른 실행파일에서 접근 할수 있으므로 import 해줘야 한다.
 - edata는 제공하는 함수에 대한 정보들이 있다. export, import를 구현해야 한다.
 - lib => object lib은 함수의 기계어 코드가 포함되어 있어서 파일의 크기가 크지만,
 - 
lib => type lib은 링크 정보만을 가지고 있다.
 
 - 
라이브러리를 추가하는 2가지 방법
- 소스 : pragma comment( lib, "라이브러리" )
 - 설정: 프로젝트설정->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 개발자가 막아놨다. -_-..
 
