WM_GESTURE에서 PAN 입력 받기 (one/ two finger)

 

WM_GESTURE 메시지를 등록하여 이벤트를 처리할 경우

등록한 OnGesture 함수에 two finger pan의 발생은 들어오는데

One finger panOnGesture이벤트가 발생조차 되지 않는다

 

이때 모든 pan 동작에 대하여 메시지를 받을 수 있도록

WM_GESTURENOTIFY 메시지에서 Gesture를 설정해주어야 한다.

 



    switch (message)

    {

    case WM_GESTURENOTIFY:

        GESTURECONFIG gc = {0,GC_ALLGESTURES,0};

        BOOL bResult = SetGestureConfig(hWnd,0,1,&gc,sizeof(GESTURECONFIG));

           

        if(!bResult)

        {

            // an error

        }

        return DefWindowProc(hWnd, WM_GESTURENOTIFY, wParam, lParam);

    }

     

 

 

WM_GESUTRENOTIFY에서 SetGestureConfig를 이용하여 어떤 제스처에 대해서만 메시지를 받을지 설정하고 나면

해당하는 제스처가 발생했을 경우 WM_GESTURE 메시지를 받을 수 있다

 

SetGestureConfig 함수를 이용하여 설정하기 위해서는 CGestureConfig 객체를 인자로 넘겨주는데

CGestureConfig로 제스처 사용 여부를 설정하는 방법은 해당하는 제스처의 Enable 함수를 호출하면 된다

 

Ex)

Pan 동작에 대하여 메시지를 설정하려면

EnablePan() 함수를 호출하여 Pan 동작 사용시에는 EnablePan(TRUE), EnablePan(FALSE)의 값으로 설정해준다

 

Pan의 경우 여러가지 동작이 있는데

#define GC_PAN_WITH_SINGLE_FINGER_VERTICALLY        0x00000002

#define GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY      0x00000004

#define GC_PAN_WITH_GUTTER                          0x00000008

#define GC_PAN_WITH_INERTIA                         0x00000010

 

EnablePan함수에서 flagDefault는  

GC_PAN_WITH_GUTTER | GC_PAN_WITH_INERTIA 로 되어 있어서,

한 손가락에 대한 터치 제스처를 받기 위해서는  GC_PAN_WITH_SINGLE_FINGER_VERTICALLY | GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY 값도 flag 설정을 해주어야 한다

 

그래서 모든 Pan 동작을 받기 위하여

gestureConfig.EnablePan(TRUE, GC_PAN);

로 설정을 해주었다

 

WM_GESTURE 관한 내용

https://msdn.microsoft.com/en-us/library/windows/desktop/dd353243(v=vs.85).aspx

window 깜빡임 처리 - WM_ERASEBKGND와 WM_PAINT

Window는 뭔가 새로 그려야할 필요성 있을 때마다 WM_PAINT Message를 받습니다. OnPaint라는 이름으로 WM_PAINT에 대한 Handler Function이 보통 만들어지죠. System으로부터 WM_PAINT가 날아오는 상황은 다음과 같습니다.

    - 윈도우가 처음 생성되었을 때
    - 윈도우의 위치가 이동되었을 때 
    - 윈도우의 크기가 변경되었을 때(최소 및 최대화 포함)
    - 윈도우의 전체 또는 일부가 다른 윈도우에 가려져 있다가 나타날 때
    - 윈도우가 스크롤 될 때
    - UpdateWindow나 RedrawWindow 함수가 불렸을 때
    - InvalidateRect나 InvalidateRgn 함수가 불려서 다시 그려져야할 영역이 발생 한 후,
      Message Queue에 다른 처리할 Windows Message가 없을 때

그런데 WM_PAINT가 날아오기 '전'에 대부분 같이 따라오는 Message가 있습니다 WM_ERASEBKGND라는 것으로, Erase Background 라는 의미죠. 즉, 배경을 지워라.

Window의 기본 Message Procedure(DefWindowProc)는 사용자가 WM_ERASEBKGND를 받고도 아무 처리를 하지 않으면, WNDCLASS의 hbrBackground 맴버에 정의된 색상으로 배경을 지워버립니다. 깜빡이는 것은 아래 처럼 되기 때문에 발생하는 것이지요.

    1. WM_ERASEBKGND 받음
    2. 배경 지움
    3. WM_PAINT 받음
    4. Image 다시 그림

2까지가 '깜'이고 4까지 가면 '빡'이 됩니다. 깜빡 깜빡의 실체는 이것입니다.
손쉬운 처리는 WM_ERASEBKGND를 받았을 때, 배경을 안지우도록 하는 방법입니다. 보통 OnEraseBkgnd 정도의 이름을 갖게 되는 WM_ERASEBKGND Message Handler에서 0을 return 하면 됩니다.

    BOOL CAboutDlg::OnEraseBkgnd(CDC* pDC)
    {
        return 0;
    }

깜빡 거리는 것이 WM_PAINT Message Handler에서 그려주는 어떤 것이 아니라, 또 다른 Window인 '자식' Control이라면, Window Styles 중에 WS_CLIPCHILDREN Style을 '부모' Window에 먹여서 자식 Control에 의해 가려지는 영역은 그리기 대상에서 아예 제외시켜버리는 것이 일반적인 해결책입니다.

출처 : 데브피아 ( 박재민(MAXIST) )

 

인터넷에 연결 되어있는지 확인하는 API



InetIsOffline


BOOL InetIsOffline(
  DWORD dwFlags
);


Returns TRUE if the local system is not currently connected to the Internet. Returns FALSE if the local system is connected to the Internet or if no attempt has yet been made to connect to the Internet.

=================================================================================================



int InternetGetConnectedState()

{
DWORD dwConnectionTypes;
if(InternetGetConnectedState(&dwConnectionTypes, 0)) // 정상적으로 검사됨
{
   
if((dwConnectionTypes & INTERNET_CONNECTION_MODEM) != 0)
ShowMessage(
"Modem으로 인터넷 사용중...");
   
if((dwConnectionTypes & INTERNET_CONNECTION_LAN) != 0)
ShowMessage(
"LAN으로 인터넷 사용중...");
   
if((dwConnectionTypes & INTERNET_CONNECTION_PROXY) != 0)
ShowMessage(
"Proxy로 인터넷 사용중...");
   
if((dwConnectionTypes & INTERNET_CONNECTION_MODEM_BUSY) != 0)
ShowMessage(
"Modem을 다른 용도로 사용중");
   
if((dwConnectionTypes & INTERNET_RAS_INSTALLED) != 0)
ShowMessage(
"RAS가 설치되어 있음");
   
if((dwConnectionTypes & INTERNET_CONNECTION_OFFLINE) != 0)
ShowMessage(
"오프라인");
   
if((dwConnectionTypes & INTERNET_CONNECTION_CONFIGURED) != 0)
ShowMessage(
"인터넷 연결이 설정되었음");
}
else
   ShowMessage("검사할 수 없습니다");

return 0;

}

API _ 선, 박스, 도형 그리기

출처

http://blog.naver.com/PostView.nhn?blogId=eunbear1030&logNo=70033469547&redirect=Dlog&widgetTypeCall=true

]선(라인)그리기

MoveToEx와 LineTo라는 두 개의 함수를 쌍으로 사용

MoveToEx함수는 그리는 시작점으로 그리기 좌표를 이동시키는 기능

LineTo함수는 MoveToEx함수를 실행한 후에 그 위치부터 라인을 그리고자 할때 사용

 

BOOL MoveToEx( 
HDC hdc, // 디바이스 컨텍스트 핸들
int X, // 새로운 위치의 x좌표
int Y, // 새로운 위치의 y자표
LPPOINT lpPoint // 이전 위치 좌표
);

 

BOOL LineTo( 
HDC hdc, // 디바이스 핸들
int nXEnd, // 그리는 좌표 종점 x
int nYEnd // 그리는 좌표 종점 y
);

 

]박스 그리기

박스를 그리는 함수 중 중요한 함수는 2개

  1. Rectangle함수 - 일반적인 박스를 그리는 함수
  2. RoundRect 함수 - 모서리가 둥근 박스를 그리는 함수

BOOL Rectangle( 
HDC hdc, // 디바이스 컨텍스트 핸들 
int nLeftRect, // 좌측 x좌표
int nTopRect, // 상단 y좌표
int nRightRect, // 우측 x좌표
int nBottomRect //하단 y좌표
);

BOOL RoundRect( 
HDC hdc, // 디바이스 컨텍스트 핸들
int nLeftRect, // 좌측 x좌표
int nTopRect, // 상단  y좌표
int nRightRect, // 우측 x좌표
int nBottomRect, // 하단 y좌표
int nWidth, // 모서리의 가로측 지름
int nHeight // 모서리의 세로측 지름
); 

]다양한 원 그리기

  1. Ellipse함수 - 설정한 박스영역에 맞는 원을 그려줌
  2. Arc함수 - 설정된 영역에 그리기 시작좌표 (x,y)에서 종료지점 (x,y)까지 원호를 그려줌
  3. Chord함수 - 현을 그려줌
  4. Pie함수 - 부채꼴을 그려줌

BOOL Ellipse( 
HDC hdc, // handle to device context 
int nLeftRect, // 좌측 x좌표
int nTopRect, // 상단 y좌표
int nRightRect, // 우측 x좌표
int nBottomRect // 하단 y좌표

);

BOOL Arc( 
HDC hdc, // 디바이스 컨텍스 핸들 
int nLeftRect, // 좌측 x좌표
int nTopRect, // 상단 y좌표
int nRightRect, // 우측 x좌표
int nBottomRect, // 하단 y좌표
int nXRadial1, // 그리기를 시작하는 x지점
int nYRadial1, // 그리기를 시작하는 y지점
int nXRadial2, // 그리기를 종료하는 x지점
int nYRadial2 // 그리기를 종료하는 y지점
);

BOOL Chord( 
HDC hdc, // 디비이스 컨텍스 핸들
int nLeftRect, // 좌측 x좌표
int nTopRect, // 상단 y좌표
int nRightRect, // 우측 x좌표
int nBottomRect, //하단 y좌표 
int nXRadial1, // 그리기를 시작하는 x지점
int nYRadial1, // 그리기를 시작하는 y지점
int nXRadial2, // 그리기를 종료하는 x지점
int nYRadial2 // 그리기를 종료하는 y지점

);

BOOL Pie( 
HDC hdc, // 디비이스 컨텍스 핸들
int nLeftRect, // 좌측 x좌표
int nTopRect, // 상단 y좌표
int nRightRect, // 우측 x좌표
int nBottomRect, //하단 y좌표 
int nXRadial1, // 그리기를 시작하는 x지점
int nYRadial1, // 그리기를 시작하는 y지점
int nXRadial2, // 그리기를 종료하는 x지점
int nYRadial2 // 그리기를 종료하는 y지점

);


]다각형과 poly Line

다각형은 여러점을 연결하는 도형을 의미, Poly Line은 여러점에 직선을 연결한 것을 의미

 

Polygon함수 - 다각형을 그릴때 이용

Polyline함수 - Poly Line을 그릴때 이용

 

BOOL Polyline( 
HDC hdc, // 디바이스 컨텍스트 핸들
CONST POINT *lppt, // 그릴 좌표
int cPoints // 좌표의 수
); 
BOOL Polygon( 
HDC hdc, // 디바이스 컨텍스트 핸들
CONST POINT *lppt, // 그릴 좌표
int cPoints // 좌표의 수
); 

]베지어 곡선 그리기

베지어곡선은 설정해준 최소 3개의 점 사이로 곡선이 그려지는 것을 의미, PolyBezier함수를 이용

 

BOOL PolyBezier( 
HDC hdc, // 디바이스 컨텍스트 핸들
CONST POINT *lppt, // 그릴 좌표
int cPoints // 좌표의 수
); 

*` 소스 *

 

#include <windows.h>


LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static char szAppName[] = "DrawEx" ;
HWND        hwnd ;
MSG         msg ;
WNDCLASSEX  wndclass ;

 

wndclass.cbSize        = sizeof (wndclass) ;
wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc   = WndProc ;
wndclass.cbClsExtra    = 0 ;
wndclass.cbWndExtra    = 0 ;
wndclass.hInstance     = hInstance ;
wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName  = NULL ;
wndclass.lpszClassName = szAppName ;
wndclass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION) ;

 

RegisterClassEx (&wndclass) ;

 

hwnd = CreateWindow (szAppName,     
"기본그리기예제:DrawEx",   
WS_OVERLAPPEDWINDOW,  
CW_USEDEFAULT,        
CW_USEDEFAULT,        
CW_USEDEFAULT,        
CW_USEDEFAULT,        
NULL,                 
NULL,                 
hInstance,            
NULL) ;           

 

ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;

 

while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}

 

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
HDC         hdc ;
PAINTSTRUCT ps ;
RECT rect;
POINT prevpos;
POINT pline[6]={50,133,146,99,246,133,247,212,58,216,50,133};
POINT pgon[4]={308,120,440,118,380,212,308,120};

 

switch (iMsg)
{
case WM_CREATE :
return 0 ;

case WM_PAINT :
hdc = BeginPaint (hwnd, &ps) ;
GetClientRect(hwnd,&rect);
//박스 그리기
Rectangle(hdc,rect.left+10,rect.top+10,rect.right-10,rect.bottom-10);
//라운드 박스 그리기    
RoundRect(hdc,rect.left+20,rect.top+20,rect.right-20,rect.bottom-20,20,20);
//원 그리기
Ellipse(hdc,rect.left+30,rect.top+30,rect.right-30,rect.bottom-30);
Arc(hdc,0,0,100,100,50,0,100,50);
//직선 그리기
MoveToEx(hdc,rect.left+10,rect.top+10,&prevpos);
LineTo(hdc,rect.right-10,rect.bottom-10);
//베지어 곡선
PolyBezier(hdc,pline,4);
//폴리 라인
Polyline(hdc,pline,6);
//다각형
Polygon(hdc,pgon,4);
EndPaint (hwnd, &ps) ;
return 0 ;

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

return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}

 

*`출력 결과*

 


Win32 프로젝트를 빈프로젝트로 생성하여 DialogBox 띄우기

#include <Windows.h>

#include "resource.h"


BOOL CALLBACK MainDlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam);

HINSTANCE g_hInst;

HWND hDlgMain, hStatic;


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParma, int nCmdShow)

{

g_hInst = hInstance;


DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), HWND_DESKTOP, MainDlgProc);


return 0;

}


BOOL CALLBACK MainDlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)

{

switch(iMessage)

{

case WM_INITDIALOG:

//SetWindowPos(hDlg, HWND_TOP, 100, 100, 0,0,SWP_NOSIZE);

break;

case WM_COMMAND:

switch(LOWORD(wParam))

{

case IDOK:

case IDCANCEL:

EndDialog(hDlgMain, 0);

return TRUE;

}

return FALSE;

case WM_CLOSE:

PostQuitMessage(0);

return TRUE;

}


return FALSE;

}

활성화된 화면 캡쳐 ScreenCapture


HBITMAP ScreenCapture(HWND hWnd)

{


HDC hScrDC, hMemDC;

HBITMAP hBitmap;

RECT rt;


GetWindowRect(GetForegroundWindow(), &rt);

// GetWindowRect(GetActiveWindow(), &rt);


rt.left = max(0, rt.left);

rt.right = min(rt.right, GetSystemMetrics(SM_CXSCREEN));

rt.top = max(0, rt.top);

rt.bottom = min(rt.bottom, GetSystemMetrics(SM_CYSCREEN));


hScrDC=CreateDC("DISPLAY",NULL,NULL,NULL);


hMemDC = CreateCompatibleDC(hScrDC);


hBitmap = CreateCompatibleBitmap(hScrDC, rt.right-rt.left, rt.bottom-rt.top);


SelectObject(hMemDC, hBitmap);


BitBlt(hMemDC, 0, 0, rt.right-rt.left, rt.bottom-rt.top, hScrDC, rt.left, rt.top, SRCCOPY);


DeleteDC(hMemDC);

DeleteDC(hScrDC);

InvalidateRect(hWnd, NULL, TRUE);


return hBitmap;

}


==================================================================================================

위의 함수를 호출하여 사용한다

핫키를 등록하여 Ctrl + F4가 눌리면 화면 캡쳐!

WM_PAINT에서 캡쳐된 화면을 그려줌 

case WM_CREATE:

RegisterHotKey(hWnd, 0, MOD_CONTROL, VK_F4);

break;


case WM_HOTKEY:

hBit = ScreenCapture(hWnd); // CTRL +F4

return 0;


case WM_PAINT:

hdc = BeginPaint(hWnd, &ps);

if(hBit != NULL) 

{

hMemDC = CreateCompatibleDC(hdc);

SelectObject(hMemDC, hBit);

GetObject(hBit, sizeof(BITMAP), &bmp);

BitBlt(hdc, 0, 0, bmp.bmWidth, bmp.bmHeight, hMemDC, 0, 0, SRCCOPY);

DeleteDC(hMemDC);

}

EndPaint(hWnd, &ps);


return 0;


====================================================================================


[winapi] 파일 선택 다이얼로그 띄우기

- 함수 원형


BOOL fnBrowseFolder( HWND hWnd, const char *pTitle, char *pFolder, UINT nFlags )

{

LPMALLOC pMalloc;

LPITEMIDLIST pidl;

BROWSEINFO bi;


memset( &bi, 0, sizeof( BROWSEINFO ) );

bi.hwndOwner = hWnd;

bi.pidlRoot = NULL;

bi.pszDisplayName = NULL;

bi.lpszTitle = (char *)pTitle;

bi.ulFlags = nFlags;

bi.lpfn = NULL;

bi.lParam = 0;


pidl = SHBrowseForFolder( &bi );


if( pidl == NULL )

return FALSE;


SHGetPathFromIDList( pidl, pFolder );


if( SHGetMalloc( &pMalloc ) != NOERROR )

return FALSE;


pMalloc->Free(pidl);

pMalloc->Release();


return TRUE;

}


- 사용 시 

if( !fnBrowseFolder( hWnd, "디렉토리 또는 드라이브를 선택해주세요.",Path, BIF_RETURNONLYFSDIRS ) ) 

MessageBox(hWnd,"오류!",NULL,MB_OK);



Path에 선택한 파일 경로가 저장 된다.

[winapi]OWNER DRAW로 여러 버튼 그려주기

버튼 선택 후 클릭 상태 유지 &  다른 버튼 클릭 시 버튼 다시 그려줌 

InvalidateRect()는 WM_PAINT 뿐만 아니라 WM_DRAWITEM도 호출한당




case WM_DRAWITEM:

lpdis = (LPDRAWITEMSTRUCT)lParam;

memDC=CreateCompatibleDC(lpdis->hDC);


switch(lpdis->CtlID)

{

case IDC_BUTTON1:

if(lpdis->itemState & ODS_SELECTED || nDownTab == 1)

SelectObject(memDC, hBitmapDown[0]);

else

SelectObject(memDC, hBitmap[0]);

break;


case IDC_BUTTON2:

if(lpdis->itemState & ODS_SELECTED || nDownTab == 2)

SelectObject(memDC, hBitmapDown[1]);

else

SelectObject(memDC, hBitmap[1]);

break;

}

BitBlt(lpdis->hDC,0,0,150,140,memDC, 0,0,SRCCOPY);

DeleteDC(memDC);

break;




버튼 클릭 시 설정 해주는 부분

case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_BUTTON1:
// 다이얼로그 생성
InvalidateRect( hDlg, &rt, false ); 
nDownTab = 1;
break;

case IDC_BUTTON2:
// 다이얼로그 생성
InvalidateRect(hDlg,&rt, false ); 
if(nDownTab == 2)
break;
break;
}
break;

다이얼 로그 초기화 부분에서 버튼 크기의 RECT 설정 후 
버튼 누를때마다 버튼 부분 다시 그려줌 

SetRect(&rt,0,35,120,300);


HINSTANCE HWND 차이

===================================================================================================


HINSTANCE 핸들은 보통 실행되고 있는 Win32 프로그램이

메모리 상에 올라가 있는 시작 주소 값을 갖고 잇습니다.

보통은 0x00400000 이런식의 값을 가지고 있는데 저 값의

메모리 주소에 실행 모듈이 올라가 잇다는 것을 의미 하겠죠.

보통 리소스들을 로드 하는 함수들에서 이 핸들 값을 많이

참조하게 되는데 이 이유는 메모리 상에 올라가 있는 실행 모듈 들중

(exe, dll 등등.. ) hInstance 가 가르키는 주소에 올라가 있는 실행

모듈에서 그 리소스를 읽어 오라고 지정 해주는 것입니다.

이 외에 GetProcAddress() 같이 다른 DLL 에서 함수 주소를

얻어야 하는 경우에도 HMODULE ( Win32 에선 HINSTANCE 와

동일한 기능을 하고 같은 값이라고 보시면 됩니다.) 와 같이 메모리

상에 올라가 있는 어느 특정 모듈을 가르킬때 사용하게 됩니다.

그리고 그 변수를 글로벌로 잡는 경우가 있는데 그 이유는 그 변수를

여러 함수들에서 자주 사용하기 때문에 Win32의 구현 방식상 여러

함수에서 그 값을 읽어 와야 하고 그 값은 WinMain() 에서 한번 들어

오는 값이기 때문에 글로벌 변수에 넣어 두는것이죠...

물론 C++ 클래스로 MFC 처럼 하여 꼭 글로벌로 두지 않아도 되게 하는

방법도 있습니다만.. 어떤 방식이던 목적은 같습니다. 

참고하세요 ^^


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

 

HINSTANCE는 프로그램의 인스턴스 식별자(핸들)을 의미합니다.

간단히 말씀드리자면 실행파일 형태로 껍데기에 불과한 프로그램이 메모리에 실제로

구현된 실체를 뜻합니다.

따라서 만약에 프로그램을 여러개 실행시켰을 때 이들의 각각을 프로그램 인스턴스라고

 하고 실행되는 프로그램마다 고유한 값을 갖고

실행중인 프로그램들을 구분하기 위한 식별값으로 인스턴스 핸들을 이용합니다.

 

HWND는 프로그램의 윈도우 식별자(핸들)를 의미하는데 해당 프로그램의 윈도우들을

구분하기 위한 식별 값을 말합니다. 여기서 윈도우와 프로그램과는 차이가 있습니다.

윈도우 프로그래밍에서 하나의 프로그램에는 많은 윈도우들을 가질수 있기 때문입니다.

프로그램의 윈도우 핸들 중에서 대표적인 것이 부모 윈도우의 핸들입니다. 따라서 대부분의

윈도우 프로그래밍의 작업과정중 대부분은 이들 HWND 값을 통해 얻은 윈도우 핸들을

이용한다고 이해하시면 빠를꺼 같습니다. 창뿐만 아니라 여러가지 수많은 컨트롤 등도 모두

윈도우로 생성시에 핸들값을 소유하고 있는 존재이기 때문입니다.

------------------------------------------------------------------------------------

 

HINSTANCE는 프로그램의 핸들이 아니라, 프로그램 코드를 담고 있는 모듈에 대한 핸들이다. 즉, 프로그램이 수행되려면 프로그램 코드를 담고 있는 파일을 메모리의 특정 영역에 올려서 명령을 하나식 읽어가면서 수행할 수 있도록 준비해 놓아야 한다.

 

이렇게메모리에 올려진 프로그램 코드 덩어리를 윈도우에서 관리하기 위해서 일종의 고유 식별 번호를 부여하는데, 이것이 인스턴스 핸들, HINSTANCE이다. 기본적으로 프로세스를 실행하는 실행파일의 코드를 메모리에 올려놓은 모듈이 하나 있어야 하므로, 실행 파일의 모듈에 대한 인스턴스 핸들을 OS가 어플리케이션 WindMain의 인자로 넘겨주는 것이다.

 

한 프로세스가 여러개의 모듈을 로딩하여 프로그램을 실행하고 있다면 하나의 프로그램이 여러개의 인스턴스 핸들을 할당받아 쓰고 있을 수 있다.(물론 한 개의 모듈을 여러 프로세스가 공유하고 있을 수도 있다.) 대표적인 예가 바로 IE인데, 간단하게 DLL파일 한 개를 쓸 때마다 이 DLL 모듈에 대한 인스턴스 핸들이 한 개씩 생긴다고 보면 된다. 물론 DLL이 한번 로딩되면 다른 프로그램 사이에서 공유된다.

 

한 개의 프로그램에서 HINSTANCE가 한 개만 있는 것이 아니며, 또한 하나의 인스턴스 핸들이 한 개의 프로그램에만 종속되는 것이 아니므로 어떤 프로그램의 출력 대상을 지정하는 데에는 부적적하다는 점을 알 수 있다. 물론, 인스턴스 핸들은 애초부터 화면 출력을 고려햐여 만들어진 식별자는 아니며 단지 프로그램 코드 덩어리를 관리하기 위해 만들어진 리소스이다.

 

윈도우라는 OS에서 화면 출력을 위해 관리하는 리소스가 바로 HWND이다. MSN 메신저 등을 보면 알겠지만 하나의 프로그램이 하나의 창을 사용한다는 보장은 없다. 오히려 99.99%의 프로그램은 한 개 이상의 윈도우로 구성되어 있다. 한 프로그램의 윈도우가 겉보기에는 단일한 대상 영역으로 보일지라도 실제로는 구성요소별로 분리하여 별개의 윈도우로 만들어 각 윈도우는 자기 자신이 맡은 부분에 대한 화면 출력과 사용자 입력만을 담당한다. 자연히 하나의 프로그램에서 사용하는 HWND 타입의 개체 역시 1개 이상이 될 수 밖에 없으며, 이러한 상황에서 특정 위치에 특정한 동작을 수행하기 위해서는 HWND로 대상 영역을 구분할 수 밖에 없다.

 

------------------------------------------------------------------------------------

 

HWND와 HINSTANCE의 구조체 내용을 보시면 가지는 속성들이 전혀 다릅니다.

HWND는 윈도우 자체에 대한 정보를 가지는 것이고,
HINSTANCE는 현재 실행중인 인스턴스에 관한 정보를 가지고 있습니다.
인스턴스는 운영체제 전체에서 유일한 번호를 가지므로(실행중인 창들이라고 보면되죠)
HWND를 가지고 인스턴스를 구할순 없지만 HINSTANCE를 가지고 있으면
HWND에 관한 내용들을 구할수 있습니다.

메시지 박스 최상위로 뜨게

MessageBox(0,L"내가 맨 위야.",L"ㅋㅋ",MB_OK | MB_TOPMOST);