HBRUSH CreateSolidBrush(COLORREF crColor);
HBRUSH CreateHatchBrush(int fnStyle, COLORREF crColor);

위에는 그냥 단색의 브러쉬
아래는 색칠하는 스타일을 정할수 있다.
HS_BDIAGONAL : 좌하향 줄무늬
HS_CROSS 바둑판
HS_DIAGCROSS 좌하향 및 우하향
HS_FDIAGONAL 우하향
HS_HORIZONTAL 수평선
HS_VERTICAL 수직선

'Programming > Visual C++' 카테고리의 다른 글

그래픽3. PEN  (0) 2011.06.30
그래픽2. StockObject  (0) 2011.06.30
그래픽 1. GDI Object  (0) 2011.06.30
기타. SendMessage - Message 강제 호출  (0) 2011.06.30
타이머.  (0) 2011.06.29

HPEN CreatePen(int fnPenStyle,int nWidth,COLORREF crColor);

fnPenStyle은 점선이냐 실선이냐, 실선은 얼마나 할꺼냐의문제. 단, nWidth!=1, PS_SOLID가 자동으로 선택된다.

PS_SOLID
PS_DASH
PS_DOT
PS_DASHDOT
PS_DASHDOTDOT


nWidth는 굵기.
1이 기본값이고
2,3으로 하면 두꺼워진다. 0으로 하면 무조건 1 pixel의 두께.

crColor
선의 색상을 정한다. COLORREF형. RGB매크로 함수를 사용하면 된다.

다음은 예제

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass=TEXT("First");

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
 HWND hWnd;
 MSG Message;
 WNDCLASS WndClass;
 g_hInst=hInstance;

 WndClass.cbClsExtra = 0;
 WndClass.cbWndExtra = 0;
 WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
 WndClass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
 WndClass.hInstance = hInstance;
 WndClass.lpfnWndProc=WndProc;
 WndClass.lpszClassName=lpszClass;
 WndClass.lpszMenuName=NULL;
 WndClass.style = CS_HREDRAW|CS_VREDRAW;
 RegisterClass(&WndClass);

 hWnd = CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL);
 ShowWindow(hWnd,nCmdShow);

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

 return (int)Message.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
 HDC hdc;
 PAINTSTRUCT ps;
 HPEN MyPen, OldPen;

 switch(iMessage)
 {
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  MyPen=(HPEN)CreatePen(PS_SOLID,5,RGB(0,0,255));
  (HBRUSH)SelectObject(hdc,GetStockObject(GRAY_BRUSH));
  SelectObject(hdc,MyPen);
  Rectangle(hdc,50,50,300,200);
  DeleteObject(MyPen);
  EndPaint(hWnd,&ps);
  return 0;
 case WM_DESTROY : PostQuitMessage(0);
  return 0;
 }
 return (DefWindowProc(hWnd,iMessage,wParam,lParam));
}

여기서 한가지. CreatePen을 한경우에는 메모리를 할당해준것이기 때문에 DeleteObject를 해주어야한다.

'Programming > Visual C++' 카테고리의 다른 글

그래픽4. Brush  (0) 2011.06.30
그래픽2. StockObject  (0) 2011.06.30
그래픽 1. GDI Object  (0) 2011.06.30
기타. SendMessage - Message 강제 호출  (0) 2011.06.30
타이머.  (0) 2011.06.29

GDI에서 기본적으로 제공하는 Object.

HGDIOBJ GetStockObject(int fnObject);

BLACK_BRUSH
GRAY_BRUSH
NULL_BRUSH(투명)
WHITE_BRUSH
DKGRAY_BRUSH
LTGRAY_BRUSH
DC_BRUSH(색상 브러시, SetDCBrushColor로 색 설정)
BLACK_PEN
WHITE_PEN
NULL_PEN
DC_PEN(색상 펜, SetDCPenColor 함수로 설정)
ANSI_FIXED_FONT 고정폭 폰트
ANSI_VAR_FONT 가변폭 폰트
DEFAULT_PALETTE 시스템 기본 팔레트


사용 예

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass=TEXT("First");

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
 HWND hWnd;
 MSG Message;
 WNDCLASS WndClass;
 g_hInst=hInstance;

 WndClass.cbClsExtra = 0;
 WndClass.cbWndExtra = 0;
 WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
 WndClass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
 WndClass.hInstance = hInstance;
 WndClass.lpfnWndProc=WndProc;
 WndClass.lpszClassName=lpszClass;
 WndClass.lpszMenuName=NULL;
 WndClass.style = CS_HREDRAW|CS_VREDRAW;
 RegisterClass(&WndClass);

 hWnd = CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL);
 ShowWindow(hWnd,nCmdShow);

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

 return (int)Message.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
 HDC hdc;
 PAINTSTRUCT ps;
 HBRUSH MyBrush,OldBrush;

 switch(iMessage)
 {
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  (HBRUSH)SelectObject(hdc,GetStockObject(GRAY_BRUSH));
  Rectangle(hdc,50,50,300,200);
  EndPaint(hWnd,&ps);
  return 0;
 case WM_DESTROY : PostQuitMessage(0);
  return 0;
 }
 return (DefWindowProc(hWnd,iMessage,wParam,lParam));
}

'Programming > Visual C++' 카테고리의 다른 글

그래픽4. Brush  (0) 2011.06.30
그래픽3. PEN  (0) 2011.06.30
그래픽 1. GDI Object  (0) 2011.06.30
기타. SendMessage - Message 강제 호출  (0) 2011.06.30
타이머.  (0) 2011.06.29
GDI(Graphic Device Interface) Object. 화면, 프린터등의 모든 출력 장치를 제어하는 윈도우즈 핵심 모듈중 하나.
 EX) 펜, 브러시, 비트맵, 폰트 등.

DC가 일종의 GDI를 모아놓은 것.
사용자는 DC를 사용할때 적절한 Object를 선택해서 사용할수 있다.(적절한 펜, 브러쉬, 폰트 등)
만약 선택하지 않으면 알아서 Default로 선택되는 것들도 있다.

펜 HPEN 선을 그릴때 사용, (Default)검정색의 가는 실선
브러시 HBRUSH 면을 채울때 사용 (Default) 흰색
폰트 HFONT 문자 출력에 사용되는 글꼴(Default)시스템 글꼴
비트맵 HBITMAP 비트맵 이미지 (Default)없음
팔레트 HPALETTE 색상을 선택할수 있는 팔레트 (Default)없음


'Programming > Visual C++' 카테고리의 다른 글

그래픽3. PEN  (0) 2011.06.30
그래픽2. StockObject  (0) 2011.06.30
기타. SendMessage - Message 강제 호출  (0) 2011.06.30
타이머.  (0) 2011.06.29
기타. WM_CREATE  (0) 2011.06.29
LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam,LPARAM lParam);
강제로 메시지가 발생한것처럼 만든다.
Timer같은경우에도 함수 발생후 1초가 지나야 메시지가 발생하므로 그것을 강제로 하기위해서 필요하다.

case WM_CREATE:
SetTimer(hWnd,1,1000,NULL);
SendMessage(hWnd,WM_TIMER,1,0);

요롷게 해주면된다.

'Programming > Visual C++' 카테고리의 다른 글

그래픽2. StockObject  (0) 2011.06.30
그래픽 1. GDI Object  (0) 2011.06.30
타이머.  (0) 2011.06.29
기타. WM_CREATE  (0) 2011.06.29
입력5. 마우스  (0) 2011.06.29


LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
 HDC hdc;
 PAINTSTRUCT ps;
 SYSTEMTIME st;
 static TCHAR sTime[128];

 switch(iMessage)
 {
 case WM_CREATE:
  SetTimer(hWnd,1,1000,NULL);
  return 0;
 case WM_TIMER:
  GetLocalTime(&st);
  wsprintf(sTime,TEXT("지금 시간은 %d:%d:%d입니다."),st.wHour,st.wMinute,st.wSecond);
  InvalidateRect(hWnd,NULL,TRUE);
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  TextOut(hdc,100,100,sTime,lstrlen(sTime));
  EndPaint(hWnd,&ps);
  return 0;
 case WM_DESTROY:
  KillTimer(hWnd,1);
  PostQuitMessage(0);
  return 0;
 }
 return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

자, 여기서
UINT SetTimer(HWND hWnd,UINT nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc);
에 대해 알아보도록하자.

nIDEvent는 타이머의 번호를 지정한다.
uElapse는 타이머의 주기를 설정한다. 단위는 1/1000초. == 1초에 한번씩 타이머 메시지가 hWnd로 전달된다.
10000이면 10초에 한번씩 타이머 메시지가 발생한다.
TIMERPROC lpTimerFunc는 타이머 메시지가 발생할 때마다 호출될 함수를 지정. 사용하지 않을경우 NULL.

'Programming > Visual C++' 카테고리의 다른 글

그래픽 1. GDI Object  (0) 2011.06.30
기타. SendMessage - Message 강제 호출  (0) 2011.06.30
기타. WM_CREATE  (0) 2011.06.29
입력5. 마우스  (0) 2011.06.29
입력3. TranslateMessage  (0) 2011.06.29
WndProc에서 첫 번째로 처리하는 메시지로 윈도우가 처음 생성될 때 발생, 초기화에 이용.

'Programming > Visual C++' 카테고리의 다른 글

기타. SendMessage - Message 강제 호출  (0) 2011.06.30
타이머.  (0) 2011.06.29
입력5. 마우스  (0) 2011.06.29
입력3. TranslateMessage  (0) 2011.06.29
입력2. WM_KEYDOWN  (0) 2011.06.29
다음은 마우스 입력 메시지다. 직관적이라 잘 알수 있을듯.

WM_LBUTTONDOWN
WM_RBUTTONDOWN
WM_MBUTTONDOWN
WM_LBUTTONUP
WM_RBUTTONUP
WM_MBUTTONUP
WM_LBUTTONDBLCLK
WM_RBUTTONDBLCLK
WM_MBUTTONDBLCLK


 그리고 여기서 하나더, 마우스 메시지는 lParam의 상위 워드에 마우스 버튼이 눌러진, y좌표, 하위 워드에 x좌표를 가지며 좌표값을 검출해 내기 위해 HIWORD, LOWORD등의 매크로 함수를 사용한다. 즉 마우스 메시지가 발생한 위치의 조표는  (LOWORD(lParam),HIWORD(lParam))이 된다.

 또한 다중모니터의 경우 이 좌표값이 음수가 될수도 있다.

wParam에는 마우스 버튼의 상태와 키보드 조합키의 상태가 전달된다.

MK_CONTROL Ctrl버튼이 눌러져 있음
MK_LBUTTON 마우스 왼쪽버튼이 눌러져 있음.
MK_RBUTTON 마우스 오른쪽 버튼이 눌러져 있음.
MK_MBUTTON 마우스 중간버튼이 눌러져 있음.
MK_SHIFT Shift버튼이 눌러져 있음.

이외에도 마우스가 움직일때 전달되는 WM_MOUSEMOVE, 휠마우스 상태를 정해주는 WM_MOUSEWHEEL등이 있다.

'Programming > Visual C++' 카테고리의 다른 글

타이머.  (0) 2011.06.29
기타. WM_CREATE  (0) 2011.06.29
입력3. TranslateMessage  (0) 2011.06.29
입력2. WM_KEYDOWN  (0) 2011.06.29
입력1. WM_CHAR  (0) 2011.06.29
키보드에서 A라는 글자가 눌렀다 뗏을 경우.

발생하는 메시지는 순서대로
WM_KEYDOWN, WM_CHAR, WM_KEYUP이 발생한다.
하지만 사실 WM_CAHR는 사용자로부터 발생한것은 아니다. WM_KEYDOWN이 오면, 그값을 토대로 WM_CHAR를 발생시킨다. 이 발생시키는 것이 TranslateMessage다.
 이 TranslateMessage라는 놈은 많은 걸 보고 판단해서 WM_CHAR를 발생시킨다. 예를들어 눌렀을때의 Shift키라던가 Caps Lock라던가, 현재 운영체재의 언어설정이라던가 말이다.

'Programming > Visual C++' 카테고리의 다른 글

기타. WM_CREATE  (0) 2011.06.29
입력5. 마우스  (0) 2011.06.29
입력2. WM_KEYDOWN  (0) 2011.06.29
입력1. WM_CHAR  (0) 2011.06.29
출력5. MessageBox & MessageBeep  (0) 2011.06.28

WM_CHAR가 문자만 받는다면 WM_KEYDOWN은 문자이외에도 키보드가 눌리면 발생하는 이벤트 메시지다. 각각의 값은 다른데서 찾아보시고.
wParam값에 키보드가 눌러진 값이 반환이 된다.

다음은 WM_KEYDOWN의 예제이다.
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
 HDC hdc;
 PAINTSTRUCT ps;
 static int x=100;
 static int y=100;

 switch(iMessage)
 {
 case WM_KEYDOWN:
  switch(wParam)
  {
  case VK_LEFT:
   x-=8;
   break;
  case VK_RIGHT:
   x+=8;
   break;
  case VK_UP:
   y-=8;
   break;
  case VK_DOWN:
   y+=8;
   break;
  }
  InvalidateRect(hWnd,NULL,TRUE);
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  TextOut(hdc,x,y,TEXT("A"),lstrlen(TEXT("A")));
  EndPaint(hWnd,&ps);
  return 0;
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
  }
 return(DefWindowProc(hWnd,iMessage,wParam,lParam));
 }


그리고 다음 예제는 스페이스가 눌리면 A와 #이 토글되는 예제이다.
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
 HDC hdc;
 PAINTSTRUCT ps;
 static BOOL sp_in=FALSE;
 static int x=100;
 static int y=100;
 LPCTSTR a=TEXT("A");

 switch(iMessage)
 {
 case WM_KEYDOWN:
  switch(wParam)
  {
  case VK_LEFT:
   x-=8;
   break;
  case VK_RIGHT:
   x+=8;
   break;
  case VK_UP:
   y-=8;
   break;
  case VK_DOWN:
   y+=8;
   break;
  case VK_SPACE:
   sp_in=!sp_in;
   break;
  }
  InvalidateRect(hWnd,NULL,TRUE);
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  if(sp_in==FALSE)a=TEXT("A");
  else if(sp_in==TRUE) a=TEXT("#");
  TextOut(hdc,x,y,a,lstrlen(a));
  EndPaint(hWnd,&ps);
  return 0;
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
  }
 return(DefWindowProc(hWnd,iMessage,wParam,lParam));
 }

'Programming > Visual C++' 카테고리의 다른 글

입력5. 마우스  (0) 2011.06.29
입력3. TranslateMessage  (0) 2011.06.29
입력1. WM_CHAR  (0) 2011.06.29
출력5. MessageBox & MessageBeep  (0) 2011.06.28
출력4. 기타  (0) 2011.06.28

 일반적으로 도스에서 입력하는걸 생각해보자. 그러면 생각할것없이 키보드가 갖고 있는 고유의 값을 받아서 프로그램에서 문자로 해석해 모니터로 쏴주면 된다.
 그럼 윈도우에서는 어떠한가? 멀티테스킹이란 것으로 윈도우의 여러개의 창들이 있고 내가 실행하고 있는 프로그램중에서도 내가 원하는 위치에 글자를 출력해야 한다.
 이렇게 어디에 글자를 출력할것인지 선택하는걸 "포커스"라고 한다.
 키보드에서 입력받은 문자는 "활성화"된 프로그램의 CP부터 글자가 출력이 된다.(기본적으로)

 활성화를 "선택" 이라고 보면 되고 포커스를"집중"이라고 생각하면 쉽다.

자, 그럼 WM_CHAR의 활용을 보자.

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
 HDC hdc;
 PAINTSTRUCT ps;
 static TCHAR str[256];
 int len;

 switch(iMessage)
 {
 case WM_CHAR:
  len=lstrlen(str);
  str[len]=(TCHAR)wParam;
  str[len+1]=0;
  InvalidateRect(hWnd,NULL,FALSE);
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  TextOut(hdc,100,100,str,lstrlen(str));
  EndPaint(hWnd,&ps);
  return 0;
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 }
 return (DefWindowProc(hWnd,iMessage,wParam,lParam));
}


여기서 집중해야 할것은 음...
 case WM_CHAR:
  len=lstrlen(str);
  str[len]=(TCHAR)wParam;
  str[len+1]=0;
  InvalidateRect(hWnd,NULL,FALSE);
  return 0;

이정도면 충분할것 같군.

대충 해석을 해보자면, 정수형 len에 str의 현재 길이를 구한다.
가장 처음 상태에선 아무것도 없는 0이 반환이 되겠지?
그럼 str[0]에 wParam글자가 온다.
여기서 WM_CHAR메시지는 은 입력된 문자의 코드를 wParam으로 전달한다.

여담으로 lParam도 한번 보고 가자. WM_CHAR의 경우 lParam에는 비트별로
0~15비트에는 반복카운트,
16~23 스캔코드
24 : 오른쪽 Alt, 오른쪽 Ctrl등 101키에만 있는 확장키가 눌러졌을경우 1
25~28 : 미사용
29 : Alt키가 눌렸으면 1
30 : 메시지가 보내기전에 키가 눌러져 있었으면 1
31 : 키가 놓아지면 1, 눌러지면 0

자 여담은 여기서 마치도록 하고

  len=lstrlen(str);
  str[len]=(TCHAR)wParam;
  str[len+1]=0;

이걸 조금더 자세히 보자면,
str[0]에 글자가 들어가고 그다음 배열에 널을 넣어 문자의 종료를 알린다.
그리고 만약또다시 뭔가가 들어온다싶으면 lstrlen(str)==1 이되므로.
str[1]에 글자가 넣어진다. 그리고 str[2]에 널문자가 오게 되겠지.
한글자 한글자씩 문자를 넣고 널문자를 하나씩 미루는 형식으로 되어있다.

자, 여기서 끝내고 글자가 짠! 하고 나타나면 좋겠지만, 하나 부족한것이 있다면, 출력하는 코드가 보이지 않는다. 화면에 표시하는코드는? 아, WM_PAINT에 있군. 그렇다면 WM_PAINT를 호출하는 시점은?

1. 프로그램을 시작할때.
자, 프로그램을 시작할때 str은 비어있다. 아무리 글자를 쳐봐도 화면에 나오지 않는 이유가 그것이다.
호출하는 시점이 틀려먹었잖아. 그렇다면 또 언제 호출을 하지?

2. 화면을 다시 그릴때.
 화면을 다시 그릴땐 WM_PAINT에 저장되있는것이 다시 호출이 된다. 음.. 언제 다시 호출이 되지? 윈도우창이 가려지고 다시 나타날때 다시 그려진다.

자, 이 화면을 다시그리라는 명령을 해주는 함수가 있으니

  InvalidateRect(hWnd,NULL,FALSE);

요 함수다.
이 함수는 윈도우의 작업영역을 무효화 하여 운영체제가 WM_PAINT메시지를 다시 호출하도록 한다.
첫번째 hWnd는 그 대상이 된다. 뭐, 다른 윈도우를 대상으로 할 수도 있다.
그다음은 CONST RECT *lpRect인데. 무효화할 사각형을 지정한다. 이 값이 NULL값이면, 윈도우의 전영역이 무효화 된다. 하지만 NULL값으로 두면 그릴것이 많아질수록 속도가 느려질수 있는 단점이 있다.
세번째는 BOOL bErase로 무효화되기 전에 배경을 모두 지운후 다시 그릴 것인지 아니면 배경을 지우지 않고 그릴것인지를 지정한다. TRUE면 배경을 지운호 다시그리고, FALSE면 배경을 지우지 않고 다시 그린다.

'Programming > Visual C++' 카테고리의 다른 글

입력3. TranslateMessage  (0) 2011.06.29
입력2. WM_KEYDOWN  (0) 2011.06.29
출력5. MessageBox & MessageBeep  (0) 2011.06.28
출력4. 기타  (0) 2011.06.28
출력3. DrawText  (0) 2011.06.28
MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCation, UINT uType);
핸들값, 메시지 박스에 넣을 글자, 타이틀에 나올글자, 메시지 박스에 나타날 버튼의 종류

MB_ABORTRETRYIGNORE Abort, Retry Ignore 세개의 버튼이 나타난다.
MB_OK, OK버튼 하나만 나타난다.
MB_OKCANCEL, OK, CANCEL 두개의 버튼이 나타난다.
MB_RETRYCANCEL, Retry, Cancel 두개의 버튼이 나타난다.
MB_YESNO
MB_YESNOCANCEL

이것뿐아니라 아이콘또한 표시할 수 있다.
MB_ICONEXCLAMATION,MB_ICONWARNING.
MB_ICONINFORMATION,MB_ICONASTERISK.
MB_ICONQUESTION
MB_ICONSTOP, MB_ICONERROR,MB_ICONHAND

그리고 이 MessageBox의 리턴값은 사용자가 누른 버튼값을 되돌려준다.
IDABORT Abort 버튼을 눌렀다.
IDCANCEL
IDIGNORE
IDNO
IDOK
IDRETRY
IDYES

EX)
if(MessageBox(hWnd,Text("응? 뭐라고?"),TEXT("야!!"),MB_YESNO==IDYES){}
else{}

요롷게;



BOOL MessageBeep(UINT uType);
비프음을 내는 함수
0xffffffff  pc스피커를 통해 음을 낸다.
MB_ICONASTERISK Asterisk 비프음
MB_ICONEXCLAMATION Exclamation 비프음
MB_ICONQUESTION Question 비프음
MB_OK 시스템 디폴트 비프음.





'Programming > Visual C++' 카테고리의 다른 글

입력2. WM_KEYDOWN  (0) 2011.06.29
입력1. WM_CHAR  (0) 2011.06.29
출력4. 기타  (0) 2011.06.28
출력3. DrawText  (0) 2011.06.28
출력2. WM_Paint  (0) 2011.06.28
COLORREF Set Pixel(hdc, nXPos, nYPos, clrref)
지정한 좌표에 clrref색 하나의 점을 찍는다.

DWORD MoveToEX(hdc, x, y, lpPoint);
BOOL LineTo(hdc,xEnd,yEnd);

LineTo는 CP부터 지정한 좌표까지 선을 긋는다. 그리고 CP를 지정한 좌표로 업데이트한다. 따라서 LineTo를 계속 호출하면 연속된 선을 그을수 있다.
MoveToEx는 CP를 지정한 좌표로 이동시키고 필요한경우 이전 CP의 좌표를 lpPoint에 담는다. 필요하지 않을경우(현재수준에서는 계속해서) NULL값을 주면 된다.

Rectangle(hdc, nLeftRect,nTopRect,nRightRect,nBotomRect);
Ellipse(hdc, nLeftRect,nTopRect,nRightRect,nBottomRect);

Rectangle은 네모를
Ellipse는 동그라미를 그린다.
둘다 왼쪽 위x,y, 오른쪽 아래,x,y좌표 순서대로 입력하면 된다.

SetWindowText(HWND hWnd,LPCWSTR lpString);
윈도우 타이틀바에 표시할때 사용. 뭔가 문자열 테스트할때도 많이 사용한다.
이것또한 wsprintf문을 사용할수 있다.

'Programming > Visual C++' 카테고리의 다른 글

입력1. WM_CHAR  (0) 2011.06.29
출력5. MessageBox & MessageBeep  (0) 2011.06.28
출력3. DrawText  (0) 2011.06.28
출력2. WM_Paint  (0) 2011.06.28
출력1. TextOut  (0) 2011.06.28
TextOut에서 발전하면서도 디테일한 것을 만질수 있는 함수다.
int DrawText(HDC hDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat);

뭐 DC는 알테고 그 다음은 출력할 글자,
그 다음에 있는 nCount는 문자열 안에 있는 만자의 갯수를 나태내는 int형 변수다. 만약 이 것이 -1이면 DrawText는 마지막에 null 값을 가지는 포인터가 있는 것으로 가정하고 문자의 갯수는 자동으로 카운트 한다.
그다음은 Rect의 주소값. 즉, 글자가 들어갈 사각형을 표시해준다.
uFormat은 출력 형식인데,
DT_LEFT 수평 왼쪽정렬
DT_Right 수평 오른쪽 정렬
DT_CENTER 수평 중앙정렬
DT_BOTTOM 사각영역의 바닥에 문자열 출력
DT_VCENTER 사각영역의 수직 중앙에 문자열 출력
DT_WORDBREAK 사각영역의 오른쪽 끝에서 자동 개행
DT_SINGLELINE 한줄로 출력
DT_NOCLIP 사각영역의 경계를 벗어나도 문자열을 자르지않고 그대로 출력
등이 있다.

'Programming > Visual C++' 카테고리의 다른 글

출력5. MessageBox & MessageBeep  (0) 2011.06.28
출력4. 기타  (0) 2011.06.28
출력2. WM_Paint  (0) 2011.06.28
출력1. TextOut  (0) 2011.06.28
How to Programming by Unicode in windows programming - 3  (1) 2011.06.25

자, 이번엔 Paint에 대해서 알아보도록 하겠다.
dc의 경우엔 사실 Invalidate()가 자동적으로 이루어지지 않았다.(2010, windows7에서는 자동으로 되는듯 싶지만) WM_Paint를 사용하면 Uncover가 자동적으로 이루어진다. 음... 정확하진 않다.
일단 사용방법은.

 PAINTSTRUCT 구조체를 사용하는 방법이다.

자, 자세한 예제를 보면,
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;

switch(iMessage)
{
case WM_DESTROY:PostQuitMessage(0);return 0;
case WM_PAINT :
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc, 100,100,TEXT("Beautiful Korea"),15);
EndPaint(hWnd,&ps);
return 0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam);
}

자, 여기서 새로나온걸 보자면 PAINTSTRUCT 구조체와 BeginPaint, EndPaint다.
PAINTSTRUCT의 안을 들여다보면
typedef struct tagPAINTSTRUCT
{
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL flncUpdate;
BYTE rgbReserved[16];
} PAINTSTRUCT;

MSDN에서의 설명을 그냥 번역해보자면
hdc

A handle to the display DC to be used for painting.
그리기를 위해 사용될 DC를 표시할 핸들.

fErase

Indicates whether the background must be erased. This value is nonzero if the application should erase the background. The application is responsible for erasing the background if a window class is created without a background brush. For more information, see the description of the hbrBackground member of the WNDCLASS structure.
지시한다 배경이 지워져야만 할것인지 아닌지. 만약 이 어플이 배경을 지운다면 이 값은 0이 아니다. 만약 윈도우 클래스가 배경색 프러쉬없이 만들어진다면, 이 어플은 배경을 지울 책임이 있다. 뭔가 더 궁금하면 WNDCLASS구조체의 hbrBackground멤버 설명을 좀더 보면 이해가 될수도 있을껄?

rcPaint

A RECT structure that specifies the upper left and lower right corners of the rectangle in which the painting is requested, in device units relative to the upper-left corner of the client area.
그리기가 요청된 위 왼쪽, 아래, 오른쪽 코너들을 특정짓는 사각형(RECT) 구조. 디바이스 유닛에서는 클라이언트영역의 왼쪽위로 연결된다.

fRestore

Reserved; used internally by the system.
시스템 내부적으로 예약되어 있음. 건들지 마셈.

fIncUpdate

Reserved; used internally by the system.
시스템 내부적으로 예약되어 있음. 건들지 마셈.

rgbReserved

Reserved; used internally by the system.
시스템 내부적으로 예약되어 있음. 건들지 마셈.

 
자, 한마디로 말하자면, 알필요 없는 구조체네. 그저 BeginPaint를 사용하기 위한 전초전이라 생각해도 편할듯 싶다.
 
BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);
자, 그럼 이 코드를 보자면, BeginPaint다. 음.. GetDC, ReleaseDC와 마찬가지로
BeginPaint를 해주면, 반드시 EndPaint를 해줘야 한다.
자, 그리고 넘겨주는것에는 HWND와 LPPAINTSTRUCT. LP는 포인터를 의미한다. 따라서 저기 선언해 놓은 PAINTSTRUCT ps;의 주소값을 넘겨주면 된다.
 





















'Programming > Visual C++' 카테고리의 다른 글

출력4. 기타  (0) 2011.06.28
출력3. DrawText  (0) 2011.06.28
출력1. TextOut  (0) 2011.06.28
How to Programming by Unicode in windows programming - 3  (1) 2011.06.25
윈도우즈 프로그래밍에서 유니코드로 코딩법 2  (1) 2011.06.25
자, 이제 공부를 더 하기 위해서 음.. 뭔가에 대해서 깊숙히 들어가기 보단, 기록과 기억의 측면에서 포스팅을 해보기로 하자.
 이번에 공부할것은 출력. 몇일 전에 했던 LPCTSTR의 문자열 출력이 아닌 이상에야 뭐 그리 어려울건 없다. 따라서 윈도우즈 툴에서 출력하는 방법과 출력하는 함수들의 원형 및 사용방법을 익히면 될것이다.

시작해보자.

우선, 출력이라는 것에 있어서의 필요한것에 대해 알아보자, 일단 출력이란, 우리가 가장 간단하게 상상할수 있는 console style의 문자열이 있겠다. console style만 보더라도, 흰색글자에 검은색 바탕화면, 맨 왼쪽 위부터 출력이 차례대로 진행된다. 하지만 이거슨 도스시절의 이야기. 윈도우와 도스의 가장큰 차이점중 하나를 꼽으라면 뭐가 있을까? 일단 멀티테스킹이 있겠다. 그러면서 윈도우창이 바뀌고, 윈도우창이 움직일수도 있다.
 자, 그러면 두개의 프로그램을 실행중에 있는데 한나의 프로그램에서 출력하고 있던것은 다른 프로그램이 활성화가 된다면 비활성화가 된 프로그램과 같이 보이지 않아야하고 다시 그 프로그램을 활성화 시킨다면 다시 보여져야 한다.
 그리고 윈도우 창을 움직인다면 그 출력이 따라서 움직여야 할것이다.
 그리고 도스시절부터 있을수 있었던 이야기인, 함수의 원형에 무엇이 들어가야 하는가?에 대한 문제이다. 일단, 글자의 시작위치가 들어갈수 있겠다. 도스에서는 그냥저냥 첫줄부터 했지만, 윈도우에서는 어디서부터라도 글자나 그림의 위치가 실행이 가능하다. 글자의 크기, 폰트, 색깔, 등등등 여러가지가 있다. 음... 하지만 정작 생각을 해보면, 시작위치, 프로그램의 핸들만 알려주면 그냥 디폴트 정해주면 안되? 라고 해서 만든것이 DC(Device Context)다. 이 DC에 기타 여러가지의 기능들을 디폴트로 해놓든가 따로 수정을 해주면 알아서 해줄수 있도록 편하게 만들어 놓았다.

자, 그럼 간단한 코드를 보도록 하겠다.

LRESULT CALLBACK WndProc(HWND, hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc;

switch(iMessage)
{
case WM_DESTROY: PostQuitMessage(0);return 0;
case WM_LBUTTONDOWN:
hdc=GetDC(hWnd);
TextOut(hdc,100,100,Text("Beautiful Korea"),15);
ReleaseDC(hWnd,hdc);
return 0;  
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

자, 여기서 중요한건, HDC와 GetDC, TextOut, ReleaseDC
뭐, 다중요하네 ㅋㅋ

일단 HDC는 DC의 식별번호(Handle)를 담을수 있는 거고, GetDC는 hWnd를 GetDC 함수에 넘겨줘서 리턴값을 hdc로 대입한다. 핸들은 카테고리처럼 프로그램마다 지정되는거니까 :)
자, 그리고 TextOut을 보기전에 오선 ReleaseDC를 보자하면, 이거슨 생성자와 소멸자, 아니, new와 delete의 관계에 가깝다. 반드시 해줘야한다는 것이지.
 자, 그러면 Text Out을 보도록 하자, TextOut의 경우는
 TextOut(HDC hdc, int x, int y, LPCWSTR lpString, int c);
요롷게 된다. 맨처음은, dc를 사용할 핸들값이겠고, x,y는 출력할 xy의 좌표이다. 이 xy좌표의 원점. 즉, 0,0은 메뉴 부분(non-client area)를 제외한 가장 왼쪽 위부터 시작된다.따라서 오른쪽으로 1만큼 아래로 1만큼 움직이려면, 1, -1이 되는것이다.
 그리고 나오는 LPCWSTR은 물론 LPCTSTR도 사용할수 있으며 출력할 값을 나타낸다.
 그리고 그 뒤에오는 int c는 lpString의 최대길이를 나타낸다.
 만약 마지막의 이것을 쓰기 귀찮은 경우에는

void MyTextOut(HDC hdc, int x, int y, LPCTSTR Text)
{TextOut(hdc,x,y,Text,lstrlen(Text));}

이것과 같이 마지막을 lstrlen(Text)를 해줘서 없애고 MyTextOut이란 함수를 만들면 된다.


그리고 아래는 좌표에 따른 정렬방법.

SetTextAlign(HDC hdc, UINT align);

align::
TA_TOP 지정한 좌표가 상단 좌표
TA_BOTTOM  " 하단 좌표
TA_CENTER   " 중앙 좌표
TA_LEFT " 왼쪽 자좌표
TA_RIGHT " 오른쪽 좌표.
TAUPDATECP  지정한 좌표 대신CP(Current Position)를 사용하여 문자열 출력후에 CP를 저장하고 다음에 출력할 경우 그 CP 다음에 출력한다.
TA_NOUPDATECP CP를 사용하지 않고 지정한 좌표를 사용하며 CP를 변경하지 않는다.

보통 CP는 TA_LEFT|TA_TOP 에 Default로 있다가 어느 한 Text아웃이 발생하면 그 Text의 끝에 붙는다.
따라서 만약 이 CP를 옮기고 싶지 않을때는 TA_NOUPDATECP를 해주어야 한다.

그리고 중간에 변수를 넣을 경우에는 wsprintf나 sprintf를 사용해주면 된다.
wsprintf(LPWSTR, LPWSTR,...);
이것인데, 처음에는 LPWSTR은 버퍼.
그다음 LPWSTR은 버퍼에 넣을 서식이고, ... 는 인수값들이다.


How to Programming by Unicode in windows programming - 3

자, 이제 실전이다. 뭐, 다들 책이나 기본적인 윈도우즈 프레임 툴은 어떻게 짜는지 알것이다.

내가 배운것은

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCSTR lpszClass="First";

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
 HWND hWnd;
 MSG Message;
 WNDCLASS WndClass;
 g_hInst=hInstance;

 WndClass.cbClsExtra = 0;
 WndClass.cbWndExtra = 0;
 WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
 WndClass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
 WndClass.hInstance = hInstance;
 WndClass.lpfnWndProc=WndProc;
 WndClass.lpszClassName=lpszClass;
 WndClass.lpszMenuName=NULL;
 WndClass.style = CS_HREDRAW|CS_VREDRAW;
 RegisterClass(&WndClass);

 hWnd = CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL);
 ShowWindow(hWnd,nCmdShow);

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

 return (int)Message.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
 switch(iMessage)
 {
 case WM_DESTROY : PostQuitMessage(0);
  return 0;
 }
 return (DefWindowProc(hWnd,iMessage,wParam,lParam));
}

요코드다. 자, 그렇다면 유니코드를 해놓고 비주얼 스튜디오 2010에서 돌리면 어디가 에러가 나는가?
바로 hWnd=CreateWindow 요 줄에 있는 두번째 배개변수 lpszClass가 문제다. 왜냐하면 윈도우즈 함수에서는 분명히 유니코드를 이용하겠다고 했는데 이 lpszClass는 아직 유니코드가 아닌갑다. 그래서 나는 이 lpszClass의 유니코드명이 뭔지 한참이나 찾았으나 인터넷에는 도저히 나와있지 않다. 왜냐하면!! lpszClass는 내가 코드안에서 생성해준 변수명이잖아-_ -;;;;

자, 5번줄을 보면
LPCSTR lpszClass="First";
요게 있었어..
복습을 해보자.
LPCSTR은 Const하고 long pointer하고 str인것이다. 유니코드의 흔적조차 없다.
그러면 어떻게 해야할까?

그거야 바로 LPC와 STR사이에
W나 T를 넣어주면 된다. 다른 코드들과의 이식성을 위해 일부러 연습을 위해서라도 LPCTSTR을 사용해주기로 한다.
자, 이제 해결?!

5번줄만 바꿔서
LPCTSTR lpszClass="First";
자, 디버깅 해보자.

으악! 에러다. 에러다. 에러다. ㅠㅜㅠ 아 도대체 왜!!!
자, 읽어보자면
error C2440: '초기화 중' : 'const char [6]'에서 'LPCTSTR'(으)로 변환할 수 없습니다.
라고 뜬다.
즉슨, 그럼 "First" 가 5자리+NULL의 문자열 상수일테고 왼쪽은 LPCTSTR이다.
음.. LPCTSTR은 틀릴리가 없고, 그럼 const char [6]이 틀렸다는 건데.
일단 내가 짠것은 유니코드니 wchar_t const * != const char[6] 라는 소리겠지.
틀린말은 아니다, "First"는 분명한 문자열 상수고 그것을 다른 자료형에 넣을순 없는거니까.
자, 그러면 형변환이다!

자, 그럼 유니코드 안에서 LPCTSTR == wchar_t const * 이니까
LPCTSTR lpszClass == (wchar_t const *)"First";

라고 고 치고 해보자.... 와우!!! 디버깅 에러 없고, 컴파일 제대로 되..... 었지만 출력물이 이상하다. 무슨 이상한 한자하고 잡스러운게 많이 나온다. ㅠㅠㅠㅠㅠㅠ 앙데 ㅠㅠ

음... 이것의 이유는 찾아본 결과 일단, 강제 형변환에 있다. 일반적인 char 형과 유니코드의 공간 할당 크기가 다르고 이것을 강제적으로 형변환을 할때 그 할당공간 크기 차이의 빈자리를 쓰레기값이 들어가 쓰레기 글자가 나오게 되는 것이다.

 그래서 자연스레 형변환을 해주는 접두어가 있었으니 그거슨 바로 L이다.
 라이토는 아니고, 음... 정확히 찾아보진 못했지만. L이다.

 사용방법은. 그냥 일반 접두어처럼 사용하면 된다.
 
LPCTSTR lpszClass=L"First";

요롷게 하면 디버깅도 되고 컴파일도 되고 실행도 된다. 제대로 출력도 된다.
하지만 이렇게 하면 사실 LPCTSTR을 쓴 의미가 없어진다. 왜냐하면 이 L은 유니코드형으로의 형변환이다. 선택적 형변환을 하기 위해선 TEXT()함수를 사용해야한다. 이 TEXT한수를 사용할 경우엔 이것도 T와 마찬가지로 알아서 유니코드면 유니코드, 일반 ANSI면 일반 char로 알아서 변환한다.

다시 말해

LPCTSTR lpszClass=TEXT("First");

가 최종 답안이라는거지 :)
아.. 여기까지 달려오시느라 참 수고 많으셨고(다 읽었을리는 없겠지만)
최종 코드를 공개하겠다.(거창하진 않지만)

아래 코드로 컴파일 하여 실행한다면 유니코드든 멀티바이트든 에러없이 실행 된다:)

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass=TEXT("First");

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
 HWND hWnd;
 MSG Message;
 WNDCLASS WndClass;
 g_hInst=hInstance;

 WndClass.cbClsExtra = 0;
 WndClass.cbWndExtra = 0;
 WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
 WndClass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
 WndClass.hInstance = hInstance;
 WndClass.lpfnWndProc=WndProc;
 WndClass.lpszClassName=lpszClass;
 WndClass.lpszMenuName=NULL;
 WndClass.style = CS_HREDRAW|CS_VREDRAW;
 RegisterClass(&WndClass);

 hWnd = CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,(HMENU)NULL,hInstance,NULL);
 ShowWindow(hWnd,nCmdShow);
 
 //MessageBox(hWnd,L"하이",TEXT("Test"),NULL);

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

 return (int)Message.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
 switch(iMessage)
 {
 case WM_DESTROY : PostQuitMessage(0);
  return 0;
 }
 return (DefWindowProc(hWnd,iMessage,wParam,lParam));
}


How to Programming by Unicode in windows programming - 2

자, 저번시간에 멀티바이트와 유니코드의 차이를 알았아보았다. 사실 엄격히 말하면 유니코드 조차 멀티바이트긴 하지만 일반적으로 ASCII CODE를 멀티바이트, 유니코드를 유니코드라 한다.

그렇다면 아까의 그 비주얼 스튜디오 2010에서 유니코드로 윈도우즈 프로그래밍을 할수 있는 두번째 방법을 소개 하겠다. 개념은 그리 어렵지 않다.

 그저 멀티바이트 즉, ASCII CODE가 아닌  UNICODE를 사용하면된다.

하지만 방법은 막 어렵지는 않지만 간단하지만은 않다. 왜냐하면, 이 C++이 만들어 질땐 ASCII CODE를 전제로 만들어져 기본적인 명령어는 대부분 ASCII CODE를 기반으로 만들어 졌기때문에 그것을 요리해서 UNICODE도 사용할 수 있도록 변경해야 한다. 문자열이 들어가는 곳이라면 대부분의 코드를 손을 보아야한다. 따라서 ASCII CODE, 즉 일반적인 C에 적응되어 있는 분들은 문자열이 나온다면 긴장을 해야 할것이다.
물론, C++에서 막 문법을 떄고 오신분들이라면 우선 여기에 먼저 적응해지면 되긴 하겠지만 그래도 윈도우즈 프로그래밍에서는 char 가 직접적으로는 절대 안쓰인다고 생각해야한다.

 자, 그럼 어떤걸 쓰느냐?
char는 TCHAR로 사용한다. TCHAR의 정의를 보면
#ifdef UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif

만약, UNICODE를 사용한다면, wchar_t형의 TCHAR를 사용하고 유니코드가 아니면 그냥 char를 사용할께용. 이라는 뜻이다. 그렇다면 wchar_t는 무엇인가? 음... int는 정수형을 담기위한 자료 저장 범위를 지정하기 위한 "자료형"이다. 그렇다면 UNICODE를 위한 저장 크기를 제한한 자료형정도가 되겠다. 정확히 말하면 저거슨 unsigned short로 정의 되어있다.(for UTF-16)
 사실 일반 멀티바이트라면 char를 사용하고 유니코드라면 wchar_t의 자료형을 사용하면 된다. 하지만 xp이후 유니코드가 대세가 되어가고 있고 마소또한 유니코드를 권장하고 있다.

또 몇개의 자료형을 더 찾아보자면

TCHAR : char
LPSTR : char *
LPCSTR : const char*
LPWSTR : wchar_t*
LPCWSTR : const wchar_t*
LPCTSTR : const wchar_t * || const char*

이렇게 있겠는데 음.. 헝가리언 명명법이라고는 알고 있을란지... 아무튼 이름 붙이는 방법이다. 그 이름 붙이는 방법중 약어를 쓰는경우가 있는데 STR은 딱봐도 string이라는거 알겠고 다른 약어들을 대충 찾아본다면

W : Wide char (2바이트를 의미. 대충 유니코드따라잡기용 ASCII Code라 생각하면 됨)
T : unicode || ASCII
C : constant
LP : long pointer
STR : string자료형

그리고 이 유니코드를 지원하는 문자열함수도 따로 있으니 아래의 함수들을 이용하면 된다.
strlen lstrlen
strcpy lstrcpy
strcat lstrcat
strcmp lstrcmp
sprintf wsprintf


음.. 이제 코드만 짜보면 되겠구나 :)
자, 그렇다면 코드는... 다음 이시간에 계속!! 으흐흐흐흐
How to coding by UNICODE in Visual Studio 2010. 

이번학기에 비주얼 프로그래밍 수업을 들으면서..(사실은 뭐 그의 MFC수업이었지만)
기초적인 Windows API에 대해 '맛'을 봤었다.
사실, 이번학기 시작전에 WINDOWS API책을 살짝 훑어보고 시작한지라 공부를 하지 않고도 그럭저럭 학점이 잘 나오리라 생각한다.

하지만, 수업을 듣던중 가장 난감했던 것은. 바로 유니코드.
난 수업시간에 내 노트북을 갖고 다니면서 프로그래밍을 했다.
하지만 계속해서 유니코드때문에 막혔다. 첫번째 시간은 코드를 그대로 쳤으나 코드가 돌아가지 않았다.
아예 해결방법을 찾지못해 하루정도 내내 해결방안을 찾았던것 같다.

일단 해결방법 1
Alt + F7을 누르거나 메뉴에서 (프로젝트)- > (속성) 으로 들어가
왼쪽 프레임에서 (구성 속성) -> (일반)을 클릭하고
오른쪽 프레임에서 아래 문자집합 에 있는 (유니코드 문자 집합 사용)을 (멀티바이트 문자 집합 사용)으로 해준다면 왠만큼 프로그래밈이 이 전 비주얼 스튜디오 에서 코딩하는것 처럼 비슷하게 돌아간다.

하지만, 이건 약간 룰 위반이다.
우선 멀티바이트와 유니코드를 이해해야 한다.
멀티바이트를 이해하기 위해선 아스키 코드에 대해서도 알아야한다.
ASCII CODE란 만약 이걸 보는 이들은 아마도 알고 있겠지만,
컴퓨터는 문자를 인식하지 못한다. 1과 0으로 밖에 인식을 하지 못하기 때문에 인간은 그 문자를 일단 10진수 숫자와 16진수 숫자와 매치시켜 놓는다. 예를들어, 숫자가 73이면 16진수로는 0x4C고 문자는 L 이 된다. 
 이 모든걸 결정한 곳은 어느 말을 쓰는 나라 일까? 바로 미쿡. 따라서 모든 ASCII CODE는 영어로만 이루어져 있다. 사실 ASCII 라는 말은 American Standard Code for Information Interchange의 약자다. 미국 표준이란 소리지. 걔네들이 한국어나 따른 나라 언어 알게 뭐가 있었겠어?
 아무튼 그렇게 10진수와 16진수로 옮겨놓으면 2진수로 만드는건 뭐 식은죽을 그냥 앉아서 천천히 TV보면서 먹는 그런 느낌이 되어버렸지. 그리고
 부호를 포함한 1 Byte즉 8 bit의 2진수로 나타낼수 있는 수는 0000000 부터 1111111 까지. 즉 0부터 127까지다.
알파벳은 총 몇개? 어이어이 세지 말고 ㅋㅋㅋ 26개다. A~Z까지 26개고 음... 그래 대소문자 다 합쳐봐야 52개 에다가... 음.. 그래 숫자도 넣어두면 편하겠찌 그래서 숫자도 넣고. 음.. 또 뭐 없을까? 그래 따옴표하고 구두점하고 수학기호하고 뭐 그런것들좀 집어넣어서 채우다 채우다 좀 남아서 비트들을 활용하여 (그래픽 문자)도 모자라 (제어문자)까지 꽉꽉 채워 넣었다 .제어문자란 음.. DEL키라던가 Space라던가 ESC라던가 그런거 있잖아. 아 그런 공간 좀 남으면 한글이나 넣어줄것이지! 라고 말하고 싶지만 사실 인접 국가. 미국에서 자주사용되는 스폐인어 고유 글자조차 부호없는 1byte(ASCII CODE Extended)에 겨우 포함이 될 정도다.

 자, 이제 아스키코드란걸 조금은 이해를 하겠나? 음... ASCII CODE가 궁금하다면 http://ko.wikipedia.org/wiki/Ascii
위키피디아를 찾아보아도 좋음 :)


자, 이제 ASCII CODE란 걸 왠만큼 알았으니 멀티바이트로 넘어가 보자. 그럼 멀티 바이트란 무엇인가?
바로 이 ASCII CODE는 잘 해봐야 1Byte 인데 왜 싱글 바이트가 아닌 멀티 바이트인가?
 즉슨, 위 에서 언급했던대로 Signed 1byte안에는 only english다. 뭐, 숫자나 뭐그런거 말고 다른 나라의 언어는 없다는 이야기이다. 그리고 unsigned는 그외 프랑스, 스페인, 따깔, 더치어등 잉글리시와 비슷한 언어들만 확장형으로 넣어두고 나머지는 표그리기나 그림그리용으로 채워 넣었다.
 그럼 이제 비주얼스튜디오에서 멀티바이트로 하고 hello world 코딩을 해보자. 아, 영어말고 printf("헬로 월드"); 요롷게 당당하게 한국어로 해보자. 출력은 어떻게 나오는가? 한국어로 나오지 않는가?! 와우. 분명 ASCII CODE에는 영어 밖에 없다. 미국 표준이므로. 하지만 어떻게 한글이 나오지? 물론 개중에는 한글이 지원하지 않아 이상한 상형문자들이 나오는 경우가 있다. 그 이유는 나중에 점차점차 알아가도록 하고. 어찌되었든 한국어가 나온다. 그 이유가 멀티바이트에 있다. 이 문자를 인식할때 싱글바이트, 즉 1Byte로만 인식을 하면 영어만 인식을 한다. 왜냐? 1Byte안에 영어, 한국어, 중국어, 일본어 같은 것들을 모두 넣다보면 그 옛날 꼬물 컴퓨터를 쓸때 만들어진 표준으로써는 그당시 현실에 너무 안맞기 때문이다. 그렇게 몇년을 쓰다가 그걸 또 2Byte로 넘기기엔 표준이 송두리채 바뀌기가 쉽지 않았다. 따라서 하나의 대안을 제시한다.
1Byte를 두개 해서 문자를 표현하자고!!!
영어를 할땐 1Byte만 하면 되고 만약 영어이외의 한국어나 일어, 한자를 표현할때는 1Byte 여러개를 붙여 문자를 표현하기로 한다. 그 것이 ISO-2200(ISO-2200-KR, ISO-2200-JP, ISO-2200-CN) 에 정의 되어 있는 멀티바이트 문자열이다. 뭐 조금 자세히 들여다 본다면 그 1byte의 21-7E를 2개 이어붙여 94*94=8836개의 글자를 표현할수 있다. 좀더 자세히들어가 유닉스쪽 얘기를 한다면 유닉스에서는 그 표준이 약간다른데(EUC:Extended Unix Code로 EUC-KR, EUC-JP, EUC-CN으로 표기한다.) 두개의 바이트를 이어붙이는게 A1-FE 까지라는것을 제외하면 표현할수 있는 글자수도 같아 뭐 비슷비슷하게 사용할수 있다.

자, 이제 멀티바이트에 대해 약간이나마 감이 좀 잡히나? 간단히 말해 ASCII CODE 1Byte를 두개이상 붙여만들었기떄문에 멀티바이트라고 한다.


그렇다면 유니코드란 무엇인가?
ASCII는 영어일경우는 1Byte, 다른나라 언어는 +a를 하게된다. 그렇다면 어떤 일이 벌어지는가?
다른 나라 언어에 +a를 한다고 해도, 만약 한국어로 된 문장을 일본어로 해석하게 되면 어떻게 되겠는가? 이런 연유로 가끔씩 페이지를 돌아다닐때 홈페이지 전체가 상형문자로 덮혀있는 페이지를 발견하게 되는것이다. 즉, 글자가 깨진다고 하는것이다.

 자, 이것을 위해 유니코드가 태어났다. 이 American놈들의 지저분한 Standard를 꺠고 Universial한 Code를 만들어 냈다. 그것이 바로 유니코드다. 이 유니코드는 두개를 이어 붙이는게 아니라 처음부터 2Byte를 할당하여 파일 하나에 컴퓨터로 표현하는 세상 모든 문자를 담았다. 하지만 아직은 인터넷계의 주류를 담고 있는 영어에 뭔가 불리하지 않겠는가? 쓰지도 않을 일본어때문에 굳이 용량을 키우면 뭔가 좀 거시기 하지 않겠는가?라는 생각이 들어 이 유니코드도 3가지로 나눠져 있다. 그거슨 UTF-8, UTF-16, UTF-32 로 나눈다.
UTF-8이 그 ASCII CODE와 같이 8비트만을 이용한 글자. UTF-16은 16비트를 사용하고 UTF-32는 32비트를 사용하여 글자를 나타낸다. 하지만 이것은 말했듯이 ASCII CODE처럼 두개의 1 Byte를 이어붙이는 것이 아니라 순수하게 1byte면 1byte, 2byte면 2 byte를 사용한다. 그래서 인터넷보면 UTF-8 인터넷 주소만 이용 뭐 이런게 있는데 즉, 한글주소나 뭐그런거 다 빼고 영어만 쓰겠음. 뭐 그런거다.

자, 이렇게 ASCII CODE와 UNICODE는 그 근본적으로 차이가 있다. 따라서 개발자는 죽어나간다. 표준이 여러개라...

블로깅이 너무 길어 졌으므로 다음 내용은 다음 포스팅에 계~~ 속. (아마도 실질적인 첫, Windows Programming에서 기본적인 Windows Frame의 UNICODE 의 Code가 되지 않을까 싶다. 즉 방법2는 .... 다음 회에 계속 이라는 거지 ㅋㅋ)

'Programming > Visual C++' 카테고리의 다른 글

출력3. DrawText  (0) 2011.06.28
출력2. WM_Paint  (0) 2011.06.28
출력1. TextOut  (0) 2011.06.28
How to Programming by Unicode in windows programming - 3  (1) 2011.06.25
윈도우즈 프로그래밍에서 유니코드로 코딩법 2  (1) 2011.06.25

+ Recent posts