API 리소스

IT/개발공부 / / 2020. 9. 17. 22:12
728x90
반응형

프로그램은 코드와 데이터로 구성됩니다. 데이터는 프로그램의 처리 대상이며 코드는 데이터를 처리하는 수단입니다. 데이터의 의미를 확장하여 코드가 아닌 모든 것을 데이터라고 할 때 비트맵, 아이콘, 메뉴, 문자열 등 프로그램의 논리와 무관한 모든 것을이 데이터에 속합니다. 이런 리소스들은 별도의 편집기로 만들어져 컴파일시에 실행파일에 결합됩니다.

 

 

아이콘

리소스를 사용하기 위해서는 먼저 리소스 뷰에서 원하는 리소스를 추가하여야됩니다.

#include "resource.h"
int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrev, LPTSTR lpCmdLine, int nShowCmd)
{
   // 1. 윈도우 클래스 만들기
   WNDCLASS wc;
   wc.cbWndExtra = 0;
   wc.cbClsExtra = 0;
   wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
   wc.hCursor = LoadCursor(0, IDC_ARROW);
   wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1));
   
//--------------------------------------------------------------------------  
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   switch( msg ) 
   {
      case WM_LBUTTONDOWN:
      {
         HDC hdc = GetDC(hwnd);
         HICON hIcon = LoadIcon( GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON1));
         DrawIcon(hdc, 10, 10, hIcon);
         ReleaseDC(hwnd, hdc);
      }

윈도우 클래스 생성시 리소스에 추가한 나만의 아이콘을 등록할 수 있습니다. 이 기능은 윈도우 클래스 생성시 가능합니다.

 

커서

커서 또한 아이콘과 동일하게 리소스에 등록해 사용할 수 있으며, 이때 아래의 함수를 사용합니다.

LoadCursor(HINSTANCE hInst, LPCTSTR hCursor);

 

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{
   static HCURSOR h1 = LoadCursorFromFile(TEXT("C:\\windows\\cursors\\size1_i.cur"));
   static HCURSOR h2 = LoadCursorFromFile(TEXT("C:\\windows\\cursors\\size1_il.cur"));
   static RECT rc = { 100,100,300,300}; // 클라이언트 좌표.
   
   switch( msg )
   {
      case WM_SETCURSOR:
      {
         int code = LOWORD(lParam); // hit test code가 들어 있다.
         POINT pt;
         GetCursorPos(&pt); // 현재 커서의 위치(스크린 좌표)
         ScreenToClient( hwnd, &pt); // 스크린 좌표를 클라이 언트 좌표로
         
         // 클라이언트 안에서도 특정위치에서는 다른 커서를 사용하는 방법        
         if ( code == HTCLIENT && PtInRect( &rc, pt ) )
         {
            SetCursor( LoadCursor( 0, IDC_ARROW ) );
            return TRUE;
         }
//그외의 Client에서는 DefWindowProc이 변경해 줄것이다.
//----------------------------------------------------------

 

메뉴

윈도우에는 3가지 종류의 메뉴가 있습니다.

  • Main Menu
  • System Menu
  • Context Menu

Main Menu

메뉴는 윈도우즈용 프로그램이 제공하는 가장 표준적인 사용자 인터페이스이며 프로그램 전체 긴으을 총괄적으로 제공해 주는 중요한 기능을 가지고 있습니다.

 

메뉴도 기존 리소스들과 마찬가지로 리소스 편집기를 이용해서 생성됩니다. 그 이후 어떠한 메뉴가 클릭되었다는 사실을 인지하는 코드를 구성하면 됩니다.

 

메뉴 부착 방법

메인 메뉴를 프로그램에 연결하는 방법은 다양합니다.

[윈도우 클래스를 이용하는 방법]

wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);

 

[윈도우 생성 함수를 이용하는 방법]

CreateWindowEx(.... hMenu, ..., 0); // 10번째 파라미터로 메뉴의 핸들값을 필요로 합니다.

 

[API 함수를 사용하는 방법]

SetMenu(hwnd, hMenu)

이 방법은 메뉴를 동적으로 변경할 수 있습니다.

그 외 아래의 함수들을 통해 메뉴를 동적으로 변경할 수 있습니다.

[메인 메뉴의 핸들을 얻는 방법]

HMENU GetMenu(HWND hWnd)

 

[첫번째 인자의 서브 메뉴를 얻는 방법]

HMENU GetSubMenu(HMENU hMenu, int nPos);

 

[메뉴를 추가하는 방법]

BOOL AppendMenu(HMENU hMenu, UINT uFlags, UNIT uIDNewItem, LPCTSTR lpNewItem);

 

[메뉴를 삭제하는 방법]

BOOL DeleteMenu(HMENU hMenu, UINT uPosition, UINT uFlags);

 

int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrev, LPTSTR lpCmdLine, int nShowCmd)
{
   WNDCLASS wc;
   wc.cbWndExtra = 0;
   wc.cbClsExtra = 0;
   wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
   wc.hCursor = LoadCursor(0, IDC_ARROW);
   wc.hIcon = LoadIcon(0, IDI_APPLICATION);
   wc.hInstance = hInst;
   wc.lpfnWndProc = WndProc;
   wc.lpszClassName = TEXT("First");
   wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); //1)
   wc.style = 0;
   
   // 2. 등록(레지스트리에)
   RegisterClass(&wc);
   // 3. 윈도우 창 만들기
   HMENU hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU1));
   HWND hwnd = CreateWindowEx( 0, TEXT("first"), TEXT("Hello"),
   WS_OVERLAPPEDWINDOW, CW_USEDEFAULT , 0, CW_USEDEFAULT, 0, 0, hMenu, // 2) hInst, 0);
   
   //-----------------------------------------
   //3) 윈도우 생성 후...
   SetMenu(hwnd, hMenu);
   //------------------------------------------

위의 예제는 _tWinMain 함수에서 메뉴를 부착할 수 있는 3가지 방법으로 보여주고 있습니다.

보통 1번과 2번 방법을 사용합니다.

 

1번 방법은 윈도우 클래스에 붙이는 방법으로써 이를 통해 만들어지는 모든 윈도우들이 공통적인 메뉴를 갖게 되는 방법입니다.

 

2번 방법은 생성하고자 하는 윈도우 창에 메뉴를 부착하는 방법입니다.

 

메뉴를 동적으로 추가 삭제하는 방법

static HMENU hMenu = 0;
switch( msg )
{
   case WM_LBUTTONDOWN:
   if( hMenu == 0 )
   {      
      // 윈도우 메뉴의 핸들 얻기
      hMenu = GetMenu(hwnd);
      // 윈도우의 메뉴 부착 ... 0이므로 메뉴가 소멸됨..
      SetMenu(hwnd, 0);
   }
   return 0;
   
   case WM_RBUTTONDOWN:
   if( hMenu != 0 )
   {
      // 윈도우의 메뉴 부착... hMenu...
      SetMenu(hwnd, hMenu);
      hMenu = 0;
   }
   return 0;

위의 예제는 마우스 왼쪽 버튼 클릭시 메뉴가 사라지고 마우스 오른쪽 버튼 클릭시 메뉴가 생성됩니다.

 

System Menu

WS_SYSMENU 스타일을 가지는 윈도우의 캡션바에 있는 왼쪽 아이콘을 클릭하면 나옵니다. 아래의 함수를 사용하면 시스템 메뉴의 핸들을 얻거나 시스템 메뉴를 초기화 할 수 있습니다.

GetSystemMenu( hwnd, FALSE ); // 시스템 메뉴의 핸들을 리턴 한다.
GetSystemMenu( hwnd, TRUE); // 시스템 메뉴를 초기화 한다.

 

WM_SYSCOMMAND

사용자가 시스템 메뉴를 선택할 경우 WM_SYSCOMMAND 메시지가 발생합니다. WPARAM 에는 시스템 메뉴의 ID가 LPARAM에는 커서의 위치가 스크린 좌표로 들어 있습니다. WPARAM 의 하위 4비트는 시스템에 의해 내부적으로 사용되므로 사용자는 반드시 0xFFF0과 WPARAM를 AND연산해서 ID값을 조사해야 합니다.

case WM_SYSCOMMAND:
id = wParam & 0xFFF0; 

WM_SYSCOMMAND 메시지가 DefWindowProc으로 전달되면 미리정의된 작업을 수행하게 됩니다. 미리 정의된 System 명령에는 아래와 같은 것이 있습니다.

SC_CLOSE SC_CONTEXTHELP SC_DEFAULT SC_HOTKEY SC_HSCROLL SC_KEYMENU SC_MAXIMIZE SC_MINIMIZE SC_MONITORPOWER SC_MOUSEMENU SC_MOVE SC_NEXTWINDOW SC_PREVWINDOW SC_RESTORE SC_SCREENSAVE SC_SIZE SC_TASKLIST SC_VSCROLL

 

System Menu의 ID

사용자가 System Menu를 추가할 경우 다음을 주의 해야 합니다.

  • 기존의 시스템 메뉴의 ID가 0xF000~ 이후의 값을 사용하므로 사용자가 추가하는 ID값은 0x0010~0xEFF0 이어야합니다.
  • 하위 4비트는 System에 의해 사용되므로 16의 배수로 만들어야 합니다. #define WM_SYS_TOPMOST 0x0010

Context Menu

컨텍스트 메뉴란 클라이언트 영역에서 마우스 오른쪽 버튼을 클릭할 때 출력되는 메뉴를 말합니다.

case WM_CONTEXTMENU:
{
   HMENU hMenu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(IDR_MENU1));
   HMENU hSubMenu = GetSubMenu(hMenu, 1);
   POINT pt = { LOWORD(lParam), HIWORD(lParam) };
   // 스크린 좌표...
   TrackPopupMenu(hSubMenu, TPM_LEFTBUTTON, pt.x, pt.y, 0, hwnd, 0);
}

위의 예제는 마우스 오른쪽 버튼을 클릭하면 컨텍스트 메뉴가 출력되는 코드입니다.

 

728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기