'API'에 해당되는 글 14건

  1. 2010.03.11 메모리 비트맵
  2. 2010.02.13 메시지 기본원리
  3. 2010.02.10 프로세스
  4. 2010.02.09 ATOM
  5. 2010.02.03 리스트뷰
  6. 2010.02.02 WM_USER And WM_APP
  7. 2010.01.24 이벤트
  8. 2010.01.24 세마포어
  9. 2010.01.24 파일매핑 사용순서
  10. 2010.01.15 Hooking
메모리 DC

일반적으로 DC는 화면에 그래픽을 출력하기 위해 사용하지만,  프린터나 플로터 같은 출력 장치에 그래픽을 출력할 때

도 DC를 사용한다. 하지만 BitBIt함수를 이용하여 비트맵 블록을 전송하기 위해 화면 윈도우에서 얻어진 DC와 호환되는

메모리 DC를 사용하는 건 어떠한 출력 장치와도 연결되어 있지 않고, 순수히 메모리에 존재하는 DC이다.


메모리비트맵 - 화면에는 보이지 않고 메모리 상에만 존재 하는 비트맵



메모리 비트맵의 유용성

그래픽 데이터 저장

- 화면에서 얻어진 DC에 비트맵을 선택한 후 그림을 그리면 화면에도 그려지지만 비트맵에도 그려진다.
나중에 이 비트맵만 가지고 있으면, 이것을 다른 윈도우에 출력 할 수도 있고, 화면이 지워진 후에 이를 이용해 화면을 복원 할 수 도있다.

고속 그래픽 출력을 위한 버퍼

- 그림을 그리기 위해 그래픽을 함수를 호출하면 선과 원을 이용해 도형을 그린다고 하면 한장의 그림을 그리기 위해
여러번의 그래픽 함수가 호출되고 화면이 그려지는 과정이 드러나면서 화면이 깜빡거린다. 이런 경우에, 메모리 비트맵을 사용하면좋다. 메모리 DC를 만들고, 여기에 메모리 비트맵을 선택한다. 그런 다음 메모리 DC를 참조하여 여러가지 그래픽 작업을 수행하면 된다.

메모리 비트맵에는 그림이 그려지지만 아직까지 화면에 보이는 것은 아니다. 화면 구성이 끝나면, 메모리 비트맵블록을 화면의 DC로 전송한다. 비트맵을 블록 단위로 전송하는 것은 아주 고속으루 수행 되기 때문에, 깨끗한 출력 결과를 얻을수 있다.



CBitmap - 비트맵 데이터를 읽어오고 관리하는 기능을 한다.

CDC - 메모리 DC

CClientDC - 윈도우의 클라이언트 영역으로 한정되는 DC




윈도우즈는 비트맵을 곧바로 화면 DC로 출력하는 함수는 제공하지 않는다. 비트맵을 출력하는 함수라면 아마 다음과 같은 형태를 상상할 수 있을 것이다.
OutBitmap(hdc,x,y,비트맵 이름);

이런 함수가 있다면 무척 편리하게 비트맵을 출력할 수 있겠지만 안타깝게도 이런 함수는 없다. 왜냐하면 비트맵은 크기가 큰 데이터 덩어리이며 따라서 출력 속도가 형편없이 느리기 때문에 화면으로 곧바로 출력할 경우 여러 가지 꼴사나운 현상이 발생할 수 있기 때문이다. 게다가 다른 좋은 대안이 있기 때문에 직접 화면으로 출력하는 방법은 쓰지 않는다. 그 대안이 바로 여기서 논하고자 하는 메모리 DC이다.

 

메모리 DC란 화면 DC와 동일한 특성을 가지며 그 내부에 출력 표면을 가진 메모리 영역이다. 메모리에 있기는 하지만 화면 DC에서 사용할 수 있는 모든 출력을 메모리 DC에서도 할 수 있다. 선, 면, 원 등의 작도 함수는 물론 화면 DC에서는 불가능한 것까지도 가능하다. 그래서 메모리 DC에 먼저 그림을 그린 후 사용자 눈에 그려지는 과정은 보여주지 않고 메모리 DC에서 작업을 완료한 후 그 결과만 화면으로 고속 복사하는 방법을 많이 사용한다.

 

 

사용자 눈에 화면이 그려지는 과정을 보여주는 것은 그리 깔끔한 모양은 아니다. 여기서 우리가 하고자 하는 비트맵 출력을 위해서도 반드시 메모리 DC를 사용해야 한다. 비트맵도 일종의 GDI 오브젝트이지만 화면 DC에서는 선택할 수 없으며 메모리 DC만이 비트맵을 선택할 수 있다. 그래서 메모리 DC에서 먼저 비트맵을 읽어온 후 화면 DC로 복사하는 것이다. 메모리 DC를 만들 때는 다음 함수가 사용된다.

 

HDC CreateCompatibleDC( HDC hdc );

인수로 화면 DC의 핸들을 주면 이 화면 DC와 동일한 특성을 가지는 DC를 메모리에 만들어 그 핸들값을 리턴해 준다. 동일한 특성을 가진다(=호환된다)는 말은 사용하는 색상수, 색상면(plane)이 같다는 뜻이다. 호환되지 않는 DC끼리는 정보를 공유할 수 없기 때문에 화면 DC와 호환되는 메모리 DC를 만들어야 한다.

 

메모리 DC를 만든 후에는 비트맵을 읽어온 후 이 비트맵을 메모리 DC에 선택해 준다. 선택하는 방법은 여타의 GDI 오브젝트와 마찬가지로 SelectObject 함수를 사용하며 비트맵을 읽어올 때는 LoadBitmap 함수를 사용한다.

 

HBITMAP LoadBitmap( HINSTANCE hInstance, LPCTSTR lpBitmapName );

첫번째 인수는 비트맵 리소스를 가진 인스턴스의 핸들이며 두번째 인수는 비트맵 리소스의 이름이다. 읽어온 비트맵을 SelectObject 함수로 메모리 DC에 선택하면 메모리 DC의 표면에는 리소스에서 읽어온 비트맵이 그려져 있을 것이다.
이제 남은 일은 메모리 DC에 그려진 비트맵을 화면으로 복사하기만 하면 된다.


 

출처 : http://www.winapi.co.kr

참조 : visual c++ 완벽가이드 

'API & MFC > MFC & COM' 카테고리의 다른 글

COM이론2장  (0) 2010.03.13
COM이론(Component Object Model)  (0) 2010.03.12
SDK와 MFC  (0) 2010.03.11
프로퍼티시트 적용&도움말 지우기  (0) 2010.03.11
디버그모드 & 릴리즈모드  (0) 2010.03.10
Posted by 아몰라

 

RESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);


첫번째 인수(HWND hWnd) : 메시지를 받을 윈도우 핸들. 클래스로부터 여러 개의 윈도우가 만들어

졌을 때 어떤 윈도우로 전달된 메시지 인지를 구분해야 하므로 이 인수가 필요함.

두번째 인수(UINT iMessage) : Message ID이며 0x00 ~ 0x3FF 사이의 값이다. “WM_”으로 시작하는 상수로 정의 되어 있다.(전달된 메시지의 값)

WPARAM wParam, LPARAM lParam : 32비트 정수값이며 메시지의 추가 정보를 가진다.


메시지 큐


 

 

메시지는 시스템이나 사용자에 의해 발생한다.

키보드나 마우스 등의 사용자 입력 시 시스템은 이 입력에 대해 메시지를 발생시키며 또한

시스템 상황 변화를 통지하기 위해서도 메시지를 발생시킨다. 응용 프로그램도 윈도우간의

통신을 위해 메시지를 발생하며 특정 함수 호출에 의해 간접적으로 메시지가 발생하기도 한다.

윈도우즈라는 운영체제는 끊임없는 메시지의 생성과 처리를 무수히 반복하면서 실행되는

것 이므로 메시지는 윈도우즈 운영체제에서 중요하다고 할 수 있다.

메시지는 크게 메시지큐로 들어가는 (Queued)메시지와 큐에 들어가지 않고 곧바로

윈도우 프로시저로 보내지는 비큐(Non Queued)메시지로 구분된다.



 

윈도우 프로시져(Window Procedure) : 메시지를 처리하는 함수

 

- 윈도우 클래스당 하나씩 배정되며 메시지에 대응하는 방식을 정의하여 윈도우의 행동 양식을

   결정한다.

- 윈도우 클래스로부터 생성된 모든 윈도우의 메시지는 이 함수가 처리한다.

- 이름은 사용자가 마음대로 바꿀 수 있으나 일반적으로 WndProc이라는 이름을 사용한다.

- 4개의 인수를 가지며 정수값 하나를 리턴한다. 대부분 잘 처리했으면 0을 리턴하지만 어떤

   메시지는 처리 결과를 운영체제로 리턴하여 보고하는 경우도 있다.

Ex) WM_CREATE 는 초기화 과정에서 에러가 없으면 0을 리턴 에러가 발생했으면 -1을 리턴한다.

      WM_NCHITTEST  는 마우스가 윈도우의 어떤 부분에 있는지를 리턴한다.

  *WM_NCHITTEST : 윈도우에게 커서가 움직이거나 마우스버튼이 눌리거나 띄어졌을 때 메시지를 보낸다.



 




v  Window Procedure

모든 윈도우는 메시지를 처리하기 위해 메시지 처리 함수가 있어야 한다. 메시지 처리 함수의 모양은 아래 같다.

LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

윈도우 클래스를 만들때 메시지 처리함수의 주소를 등록한다.

v   Non-Queued Message

사용자가 윈도우를 만들기 위해 CreateWindowEx()함수를 호출하면 윈도우가 만들어 지고 윈도우가 만들어 졌다는 사실을 사용자에게 알리기 위해 WM_CREATE라는 메시지가 메시지 처리함수에 전달된다.(메시지 처리 함수가 호출된다.)

이때 WM_CREATE 메시지는 Message Queue 놓이지 않고 직접 Window Procedure 전달 되는 이를 non-Queued Message라고 한다.

입력 메시지(마우스 메세지, 키보드 메시지) 제외한 대부분의 메시지가 non-Queued Message 이다.

 

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {

switch( msg )     {

case WM_CREATE:

                           MessageBox( 0, "WM_CREATE도착", "", MB_OK);

                           return 0;

  

}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE , LPSTR lpCmdLine, int nShowCmd)

{

HWND hwnd = CreateWindowEx(…);

ShowWindow(hwnd, nShowCmd);






v  Queue Message

마우스나 키보드 메세지들은 직접 Window Procedure 전달되지 않고 메시지 Queue 놓이게 되는데 이를 Queue Message라고 한다. Queue 놓인 메시지를 처리하려면 반드시 사용자가 Queue 놓여 있는 메시지를 가져오는 메시지 루프가 필요하다.

MSG msg;

while ( GetMessage( &msg, 0, 0, 0 ) )  {

       TranslateMessage(&msg);

       DispatchMessage(&msg);

}

GetMessage() 메시지 Q WM_QUIT 메시지가 있을 경우에만 FALSE 리턴한다. 그래서 코드는 WM_QUIT메세지가 Q 들어 올때 까지는 무한 루프가 된다.

v   프로그램의 종료

사용자가 만든 윈도우가 파괴될 나오는 메시지는 WM_DESTROY 이다. 그러므로 사용자가 윈도우를 파괴 해도 프로그램은 계속 메시지 루프를 돌게 된다.( 하지만 윈도우는 파괴 되었다.- 모니터 화면에는 이상 아무 것도 없다.)

윈도우를 1 만든 경우 프로그램의 main 윈도우가 파괴 프로그램을 같이 종료 되게 하려면 WM_DESTROY 메시지에서 WM_QUIT메세지를 메시지 Q 넣는 작업을 해야 한다.

case WM_DESTROY:

       PostQuitMessage( 0 );             return 0;

v   처리하지 않은 메시지

메시지 처리 함수에서 발생된 메시지를 처리하지 않은 경우 반드시 아래 함수로 보내서 default 처리가 되게 해야 한다.

LRESULT CALLBACK DefWindowProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);









메시지 루프

 

- 사용자에 의해 입력된 메시지는 시스템 메시지 큐에 일단 저장되고 스레드 메시지 큐로 이동했다가 메시지 루프에 의해 해당 윈도우의 윈도우 프로시저로 보내져 처리된다.

 - 메시지는 최종 처리되기 직전까지 계속 큐에 유지되는데 이때 메시지는 다음과 같이 정의된 구조체의 형태로 존재한다.


Typedef struct tagMSG{HWND hwnd; UINT message; PARAM wParam; LPARAM lParam; WORD time; POINT pt;}MSG;


HWND
hWnd : 메시지를 받을 윈도우 핸들.

UINT iMessage : 전달된 메시지의 값

WPARAM wParam, LPARAM lParam : 메시지의 추가 정보를 가진다.

 

DWORD time : 메시지가 발생한 시간(time)

POINT pt : 발생시의 마우스 좌표(pt)

시간과 마우스 좌표는 모든 메시지들이 필요로 하는 정보가 아니므로 WndProc까지 전달되지 않는다.
필요할 경우 다음 두 함수를 사용하여 직접 조사해야 한다.

      ※ DWORD GetMessagePos(VOID) : 하위워드(LOWORD)x좌표, 상위워드(HIWORD)y좌표를 리턴한다.

      ※ LONG GetMessageTime(VOID) : 메시지 발생 시간을 부팅된 후 경과된 1/1000 단위로 리턴한다.


 

 - 메시지 루프는 메시지 큐에서 메시지를 꺼내 메시지 처리 함수로 보내는 일을 한다.

 - 보통 WinMain의 제일 끝부분에 위치하며 다음과 같이 그 형태가 정형화 되어 있다.


while(GetMessage(&Message,NULL,0,0)

{

     TranslateMessage(&Message);

     DispatchMessage(&Message);

}


- while문에 싸여져 있는데 이 루프는 프로그램이 끝날 때까지 계속반복된다.

    (메시지큐에 WM_QUIT[kwɪt]이라는 윈도우 메시지가 도착해 있으면 위의 반복문 조건속에 있는

     GetMessage함수는 FALSE값을 리턴하고 종료한다.)

      * WM_QUIT : PostQuitMessage 함수가 실행되면 발생하는 메시지

 

BOOL GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);

 

 - 스레드 메시지 큐에 대기중인 메시지를 꺼내 첫 번째 인수로 전달된 MSG 구조체에 복사한다.

 - 복사한 메시지를 큐에서 제거하고 TRUE리턴하며, 만약 큐에서 가져온 메시지가 WM_QUIT이면

    FALSE 리턴하여 메시지 루프를 탈출할 수 있다.

 

LPMSG lpMsg : MSG 구조체의 번지를 지정한다.

HWND hWnd : 현재 메시지를 큐에 올린 윈도우의 핸들값. 메시지를 처리해서 되돌려 줄때 필요하다.

UINT wMsgFilterMin : 회수된 메시지의 범위 중 최소값을 정수형태로 지정

UINT wMsgFilterMax : 회수된 메시지의 범위 중 최대값을 정수형태로 지정

 

*wMsgFilterMin : 첫번째 키보드 메시지인 WM_KEYFIRST 메시지 혹은 첫번째 마우스 메시지를 저장하는 WM_MOUSEFIRST 메시지 정수값을 저장한다.

*wMsgFilterMax : 마지막 키보드 메시지인 WM_KEYLAST 메시지 혹은 마지막 마우스 메시지를 저장하는 WM_MOUSELAST 메시지 정수값을 저장한다.

*wMsgFilterMin, wMsgFilterMax에 메시지의 범위를 지정하면 이 범위 내의 메시지만 가져온다.

*wMsgFilterMinwMsgFilterMax 인자의 값이 둘 다 0이면  GetMessage함수는 메시지 사용범위의  지정없이  모든 메시지를 돌려준다.

 

TranslateMessage


 
GetMessage 함수에 의해 큐로부터 가져온 메시지는 WM_QUIT가 아닌 한은 TranslateMessage 함수로 전달된다. 이 함수는 가상키 입력을 문자 입력(WM_CHAR)으로 바꾸는 역할을 하며 가상키 입력이 아닌 경우는 아무 처리도 하지 않는다.

* 컴퓨터의 가장 기본적인 입출력 장치는 아직까지는 키보드이다. 입력이 발생했을 경우 윈도우즈는 포커스를 가진 프로그램에게 키보드 메시지(WM_CHAR)를 보내주며 프로그램은 이 메시지를 받아 키보드 입력을 처리한다.(포커스(FOCUS)를 가진 프로그램이란 활성화되어 있는 윈도우를 말하며 한번에 오직 하나의 프로그램만 활성화 된다.멀티 태스킹 환경이라도 활성화될 수 있는 프로그램은 오직 하나밖에 없으며 활성화된 프로그램만 포커스를 가지고 키보드 입력을 받아들일 수 있다.


 

 DispatchMessage


메시지를
윈도우 프로시저로 보내 처리하도록 하는데 MSG 구조체의 hwnd 멤버를 보고 정확하게 목적 윈도우의 메시지 처리 함수로 배달한다. 윈도우 핸들로 부터 어떤 윈도우 프로시저에게 메시지를 전달할 것인가를 결정하는 중요한 일을 이 함수가 담당한다.




출처 - 선문비트 최강사님 도큐먼트

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

프로세스  (0) 2010.02.10
ATOM  (0) 2010.02.09
간단한 DLL 예제  (1) 2010.02.03
리스트뷰  (0) 2010.02.03
WM_USER And WM_APP  (0) 2010.02.02
Posted by 아몰라
정의  - 실행중인 프로그램 (파일이 실행되어 메모리에 적재되면 프로세스가 된다.)

내용 -  프로세스는 실행중인 프로그램이지만 작업의 주체는 아니다. 작업은 프로세스 내의 쓰레드가 담당한다.

프로세스는 각각 4GB의 주소 공간과 파일, 메모리, 스레드 등의 객체들을 소유하며 프로세스가 종료될 때 프로세스가 소유한 모든 자원은 운영체제의 의해 파괴된다. 모든 것은 프로세스의 의해 소유되며 스레드는 윈도우와 메시지 큐, 스택만 소유한다. 객체간의 소유 관계는 프로세스 > 스레드 > 윈도우 로 정리할 수  있다.



<프로세스 생성 함수> - WinExec, CreateProcess.

 

UINT WinExec (LPCSTR lpCmdLine, UINT uCmdShow)

한 프로그램에서 다른 프로그램을 실행하고자 할 때는 Win32 AP가 제공하는 프로세스 생성 함수를 사용한다. 프로세스를 생성하는 가장 간단한 함수는 WinExec이다

lpCmdLine

실행 시키고자 하는 프로그램의 이름, (완전 경로를 줄 수 있다.)

uCmdShow

실행 직 후 프로그램이 어떻게 보일지 지정.(기본 SW_SHOWNORMAL)

Ex)

UINT WinExec(“Notepad.exe”,SW_SHOWNORAML);

 

BOOL CreateProcess (LPCTSTR lpApplicationName, LPTSTR lpCmdLine,

LPSECURITY_ATTRIBUTES lpProcessAttributes,

LPSECURITY_ATTRIBUTES lpThreadAttributes,

BOOL bInheritHandles,  DWROD dwCreationFlags,

LPVOID lpEnvironment,  LPCTSTR lpCurrentDirectory,

LPSTARTUPINFO lpStartupInfo,

LPPROCESS_INFORMATION lpProcessInformation  );

프로세스를 생성하는 함수. 새로 만든 프로세스의 메인 윈도우가 어떻게 초기화될지 정하는 구조체인STARTUPINFO 구조체와 생성된 프로세스의 정보를 대입 받기 위한 구조체인 PROCESS_INFORMATION 구조체가 꼭 필요하다.[출처] [API] 프로세스|작성자 흡연토끼

à10개의 인수를 가지고 있는데 이 중 반드시 필요한 인수는 4가지 뿐이며 나머지는 NULL

줄 수 있다.

 

lpApplicationName

실행하고자 하는 프로세스 이름

lpCmdLine

명령행 인수를 지정한다.

bInheritHandles

상속 가능한 핸들에 대해 자식 프로세스에게 상속할지를 결정.(null)

lpStartupInfo

메인 윈도우의 초기화를 정하는 구조체.

lpProcessInformation

생성된 프로세스의 정보를 받기위한 구조체.

EX)

CreateProcess(NULL,”NotePad.exe”,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);






프로세스가 자기 자신을 종료하는 가장 간단하고 일반 적인 방법은 WM_CLOSE메시지를 보내거나 DestoryWindow로 메인윈도우를 파괴하는것이다. 이때 WM_DESTORY에서 PostQuitMessage를 호출하여 메시지 루프를 종료한다.

 

 

<프로세스 종료 함수>

 

- void ExitProcess(UNIT uExitCode);

 함수가 호출되면 프로세스는 정리 작업이 들어가고 즉각 종료된다.

 

     프로세스와 연결된 모든 DLL을 종료시키기 위해 각 DLL DllMain함수가 호출되며

        dll들은 스스로 정리 작업을 한다.

     열려진 모든 핸들을 닫는다.

     실행중인 모든 스레드를 종료한다.

     프로세스 커널 객체와 스레드 객체는 신호상태가 되며 이 객체를 기다리는 다른 프로세스는 대기상태를 해제한다.

     프로세스의 종료코드는 STILL_ACTIVE에서 ExitProcess가 지정한 종료값이 된다.

 

-BOOL TerminateProcess(HANDLE hProcess,UINT uExitCode);

 프로세스 외부에서 다른 프로세스를 종료하는 메소드, ExitProcess에 비해 종료 대상이 되는 프로세스의 핸들을 가지므로 자기 자신이 아닌 다른 프로세스를 강제로 종료 시킬 수 있다.

 

à TerminateProcess ExitProcess함수보다 더 위험하다. 이는 함수가 호출될 때는 동일한 작업이 수행되나 TerminateProcess는 연결된 DLL에게 종료 사실을 통지하지 않는다. 때문에 TerminateProcess함수로 강제로 프로세스를 종료한다면 정보를 잃어버리게 될 수 있다.


<프로세스 핸들>

윈도우즈는 GDI, USER, KERNEL의 세 가지 주요 DLL로 구성되어 있다. 각 모듈은 여러 종류의 객체를 관리하며 관리의 편의를 위해 핸들을 사용한다. 객체는 시스템 리소스를 나타내는 일종의 데이터 구조체이며 이 구조체들은 보통 덩치가 크기 때문에 좀 더 간단한 32비트 정수값의 핸들로 관리된다. 각 모듈별 객체에는 어떤 것들이 있고 특징은 어떤지 정리해보자.

모듈

객체

특징

USER

윈도우, 커서, 캐럿, 아이콘

한 오브젝트에 하나의 핸들. 시스템 전역적

GDI

, 브러시, 비트맵, 팔레트

한 오브젝트에 하나의 핸들. 프로세스 지역적

KERNEL

파일, 프로세스, 스레드, 이벤트

보안 적용. 프로세스 한정적


USER 객체 - ProA에서 윈도우를 만들고 핸들을 받으면 그 핸들을 ProB에게 전달하면 ProB는 윈도우 핸들을 사용하여 ProA가 만든 윈도우를 마음대로 만질수 있다.

GDI객체 - ProA에서 펜을 만들고 hPen 핸들을 발급받아서 ProB로 보냈다고해서 ProB가 이 펜을 사용할 수 없다. GDI 객체는 언제든지 원하는대로 생성할 수 있는데다 공유할 필요가 없기 때문에 프로세스 지역적이다.

커널객체 - 윈도우즈는 멀티 유저를 지원하는데 파일이나 프로그램 모두 소유자를 지정할 수 있고 소유자만 액세스 하도록 권한을 설정할 수 있다. 그래서 커널 객체를 만드는 CreateProcess, CreateFile, CreateMutex 등의 함수들은 모두 보안 속성을 인수로 가진다.

이런 보안상의 이유로 커널 객체는 프로세스 한정적이다.
(프로세스 한정적 - 한 프로세스가 만든 핸들은 다른 프로세스에서 곧바로 사용할 수 없되 대신 다른 프로세스가 같은 객체를 다시 오픈 하여 또 다른 핸들을 사용할 수 있다는 뜻이다.)

ProA가 ProC를 생성해서 ProC의 핸들을 받는다. 그리고 ProB에게 ProC의 핸들을 보내준다. 하지만 ProB는 ProC를 열 수 있는 권한이 아직 있는지 없는지 확인이 안되었기 때문에 사용못한다. ProB가 ProC를 액세스하고 싶다면 다음 함수로 프로세스의 ID로부터 프로세스 핸들을 다시 열어야 한다. 

ID
- 프로세스간의 구분을 위한 중복되지 않는 식별값일 뿐이며 ID로부터 직접 프로세스를 제어할 수는 없다. ID로부터 핸들을 발급받아야만 비로소 이 객체를 제어할 수 있다.

<프로세스의 핸들 얻는 함수>

 

HANDLE OpenProcess(DWORD dwDesiredAccess, BOOL blnheritHandle, DWORD dwProcessld)

dwDesiredAccess

Flag 접근

blnheritHandle

Flag 상속

dwProcessld

프로세스 identifier

 

<자기자신의 프로세스 핸들 얻는 함수>

HANDLE GetCurrentProcess (VOID);  : 필요한 인자는 없으며 자기자신의 프로세스 핸들 값을 반환한다.




<
프로세스 종료 상태를 구하는 함수>
                  
BOOL GetExitCodeProcess (HANDLE hProcess, LPWORD lpExitCode);

프로세스의 종료 상태를 구하는 인수로 프로세스의 핸들을 주면 이 프로세스의 종료 상태를 lpExitCode에 리턴 해준다.

hProcess

프로세스의 핸들

lpExitCode

DWORD의 포인터형. 프로세스의 상태코드가 넘어온다.        성공 1, 실패 0반환.

 

<사용 예>

static DWORD ProcID = 0;

static HANDLE hProc = 0;

 

switch (iMessage) {

           case WM_USER:

                     ProcID = wParam;

                     hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcID);

                     return 0;

           case WM_LBUTTONDOWN:

                     GetExitCodeProcess(hProc, &ExitCode);

           }



.[출처] [API] 프로세스|작성자 흡연토끼

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

메시지 기본원리  (0) 2010.02.13
ATOM  (0) 2010.02.09
간단한 DLL 예제  (1) 2010.02.03
리스트뷰  (0) 2010.02.03
WM_USER And WM_APP  (0) 2010.02.02
Posted by 아몰라
아톰에 대해서 알기전에 아톰테이블에 대해서 먼저 알아보자.

아톰 테이블이란?

- 시스템이 유지하는 문자열 테이블
- 아톰들을 저장하는 해쉬테이블

아톰테이블에 문자열을 보관하면 저장된 문자열을 대표하는 정수값을 돌려준다. 그 값이 아톰이다.


 아톰 테이블의 종류


로컬 아톰테이블

- 지역아톰테이블에 저장
- 테이블을 만든 응용 프로그램 내에세만 사용가능
- 함수명 AddAtom, GetAtomName 등등


글로벌 아톰테이블

- 전역아톰테이블에 저장
- 시스템의 모든 응용 프로그램이 같이 사용
- 함수명 GlobalAddAtom, GloabalGetAtomName 등등

아톰함수정리

ATOM GlobalAddAtom(LPCTSTR lpString)
 <문자열 추가>
첫 번째 인자: 추가 하고자 하는 문자열
반환 값 : 아톰테이블에 추가된 문자열의 아톰을 준다.


ATOM GlobalDeleteAtom(ATOM nAtom) <문자열삭제>
첫 번째 인자: 삭제 하고자 하는 아톰
반환 값:  성공시 0 , 실패시 nAtom



UINT GlobalGetAtomName(ATOM nAtom, LPTSTR lpBuffer, int nSize)
 <아톰값으로부터 문자열 추출>
첫번재 인자: 헤당 아톰
두번째 인자: 아톰에서 찾은 문자열을 담을 버퍼공간

세 번째 인자:
버퍼공간 사이즈
반환 값:  실패 시 0


ATOM GlobalFindAtom(LPCTSTR lpString)
<문자열로부터 아톰값을 구한다.>
 

첫 번째 인자: 해당 문자열
반환 값 : 실패 시 0



아톰의 사용용도

- 문자열을 '키'로 가지는 자료들을 관리 할 때
     중복문자열을 저장하지 않는다.(Add함수로 같은 문자열을 저장하면 참조카운트가 늘어난다 1,2,3....Delete 함수로 참조인수가 0이 될 때 시스템은 아톰테이블에서 문자열삭제한다.)


- 문자열을 통한 해쉬함수가 필요한 경우








'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

메시지 기본원리  (0) 2010.02.13
프로세스  (0) 2010.02.10
간단한 DLL 예제  (1) 2010.02.03
리스트뷰  (0) 2010.02.03
WM_USER And WM_APP  (0) 2010.02.02
Posted by 아몰라

리스트뷰 -  ListBox가 발전된 형태로  좀 더 깔끔하고 다양한 기능을 사용할 수 있다.




리스트뷰 함수정리

ListView_GetItemCount()  :  등록된 항목의 개수

ListView_InsertItem()  :  새 항목 등록

ListView_SetItem()  :  항목의 정보를 변경(이미지 등)

ListView_SetItemText()  :  항목의 문자열을 변경

ListView_DeleteItem()  :  지정한 항목을 삭제

ListView_DeleteAllItems()  :  전체 항목을 삭제

ListView_GetItemText()  :  지정한 항목의 문자열을 얻어옴

ListView_GetNextItem()  :  옵션에 해당하는 항목의 인덱스 반환

ListView_FindItem()  :  제시한 조건과 일치하는 항목의 인덱스 반환

ListView_SetItemState()  :  지정한 항목의 상태 변경(포커스 등)





LVCOLUMN 구조체  -  LVCOLUMN 구조체에 헤더의 정보를 채운 뒤 LVM_INSERTCOLUMN 메시지 전송

Typedef struct_LVCOLUMN{
UINT mask;  :사용될 멤버 값 설정
int fmt;  :문자열의 정렬방법과 이미지 사용여부
int cx;  :헤더의 폭
LPTSTR pszText;  :보여질 문자열
int cchTextMax;  :문자열의 크기
int iSubItem;  :연결될 항목
#if(_WIN32_IE>=0x0300)  :IE의 버전(구 버전 이미지 사용불가)
int iImage;  :보여질 이미지
int iOrder;  :헤더의 순서
#endif
}LVCOLUMN,FAR*LPLVCOLUMN;



LVITEM 구조체 -  LVITEM 구조체에 항 정보를 채운 뒤 LVM_INSERTITEM  메시지 전송

Typedef struct_LVITEM{
UINT mask;  :사용될 멤버 값 설정
int iItem;  :항목의 Index설정
int iSubItem;  :항목의 Colum Index설정
UINT state;  :항목의 상태(focus, 선택 등)
UINT stateMask;  :상태를 설정
LPTSTR pszText;  :문자열(실제 내용)
int cchTextMax;  :문자열 길이
int iImage;  :왼쪽에 보여질 이미지의 인덱스
LPARAM lParam;  :항목의 추가 저장공간
#if(_WIN32_IE>=0x0300)  : IE의 버전(구 버전 들여쓰기 사용불가)
int iIndent;  :들여쓰기
#endif
}LVCOLUMN,FAR*LPLVCOLUMN;


 
LVFINDINFO 구조체 - LVFINDINFO 구조체에 검색할 정보를 채운 뒤 LVM_FINDITEM 메시지 전송

typedef struct tagLVFINDINFOW {
UINT flags;  :
검색 형태를 지정하는 옵션
LPCWSTR psz;  :검색할 문자열
LPARAM lParam;  :검색할 32bit Data
POINT pt;  :검색할 좌표값
UINT vkDirection;  :검색할 방향
} LVFINDINFOW, FAR* LPFINDINFOW;




#include <windows.h>
#include <commctrl.h>
#define IDC_LISTVIEW 150
#define LVIF_TEXT 151


LVCOLUMN COL; //열 구조체
LVITEM LI;          //항목 구조체
HWND hList;


void OnInitCOL(HWND hWnd)
{
 hList = CreateWindow(WC_LISTVIEW,NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT, 150,18,240,60,hWnd,(HMENU)IDC_LISTVIEW,0,0);
 ListView_SetExtendedListViewStyle(hList,LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
//리스트뷰 스타일 초기화

 COL.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
 COL.fmt = LVCFMT_LEFT;
 
 COL.cx=80;
 COL.pszText="가";   
 COL.iSubItem=0;
 ListView_InsertColumn(hList,0,&COL);   

//첫번째 : 해당 리스트 핸들
//두번째 : 몇번째 열인지
//세번째 : 해당 열의 초기화상태
 
 COL.cx=80;
 COL.pszText="나";   
 COL.iSubItem=1;
 ListView_InsertColumn(hList,1,&COL);
 
 COL.cx=80;
 COL.pszText="다";  
 COL.iSubItem=2;
 ListView_InsertColumn(hList,2,&COL);
}


void OnInitITEM()
{
 LI.mask = LVIF_TEXT;
 LI.iItem = 1;         //행 (전체 화면 - 캡션포함)
 LI.iSubItem = 0;    //열
 LI.pszText = "1";  //문자열 값
 ListView_InsertItem(hList, &LI);
//초기화된 항목구조체 정보를 토대로 해당리스트에 삽입 

 ListView_SetItemText(hList, 0, 1, "2"); 
//첫번째: 해당 리스트 핸들
//두번째 : 행 (캡션 미 포함)
//세번째 : 열
//네번째 : 값
 ListView_SetItemText(hList, 0, 2, "3");
 
  
 LI.iItem = 2;
 LI.pszText = "4";
 ListView_InsertItem(hList, &LI);

 ListView_SetItemText(hList, 1, 1, "5");
 ListView_SetItemText(hList, 1, 2, "6");
 
 LI.iItem = 3;
 LI.pszText = "7";
 ListView_InsertItem(hList, &LI);

 ListView_SetItemText(hList, 2, 1, "8");
 ListView_SetItemText(hList, 2, 2, "9");
}



결과



'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

ATOM  (0) 2010.02.09
간단한 DLL 예제  (1) 2010.02.03
WM_USER And WM_APP  (0) 2010.02.02
레지스트리  (0) 2010.02.02
o/s의 role  (0) 2010.01.28
Posted by 아몰라
윈도우 시스템은, 메시지구동 시스템으로 모든 이벤트는 메세지의 발생에 의해서 처리된다.


#define MY_USER 1000 
이렇게 선언할 경우 이미 1000이라는 값은 시스템이 내부적으로 예약해서 사용하는 상수일 수 있다.
그래서 이러한 현상을 막는 방법으로 WM_USER와 같은 사용자가 정의 할 수 있는 상수공간을 마련해두었다.


설명 - 이 메시지는 실제로 정의되어 있는 시스템 메시지가 아니며 사용자 정의 메시지의 시작 범위를 지정하는 상수값이다. 메시지는 정수값 하나로 표현되는데 윈도우즈는 메시지의 범위를 다음과 같이 정의하고 있다.



<범위 설명>

0~WM_USER-1
운영체제가 정의하는 시스템 메시지. WM_PAINT, WM_TIMER 등의 메시지들이 모두 이 범위에 속한다.

WM_USER~WM_APP-1
윈도우 클래스가 정의하는 사용자 정의 메시지
WM_APP~0xBFFF
응용 프로그램이 정의하는 사용자 정의 메시지

0xC000~0XFFFF
문자열로 등록되는 메시지

0x10000~ 이후의 사용을 위해 예약된 영역이며 현재는 사용되지 않는다.


WM_USER

WM_USER는 한 윈도우 클래스를 위한 고유의 메시지를 정의하기 위한 상수값이며 이 범위 이후부터 윈도우 클래스의 사용자 정의 메시지를 만들 수 있다. 이 값은 0x400으로 정의되어 있으며 보통 WM_USER+n으로 사용자 정의 메시지를 정의한다. 이때 n은 1보다 큰 정수이며 사용자 정의 메시지간의 구분을 위해 사용된다. 여러 개의 사용자 정의 메시지가 필요하다면 WM_USER+1, WM_USER+2, WM_USER+3,... 식으로 계속 n을 증가시켜 가며 메시지를 정의할 수 있다. 윈도우즈는 WM_USER이후 0x8000까지 사용자 정의 메시지 영역으로 정의하고 있으므로 n은 최대 0x7c00까지 가능하다. WM_USER+n을 곧바로 사용할 수도 있으며 자주 사용할 경우 다음과 같이 매크로를 정의하여 별도의 메시지를 만들 수 있다.

#define WM_MYMESSAGE WM_USER+1

이렇게 매크로를 정의해 놓고 이후부터 WM_MYMESSAGE라는 명칭을 대신 사용하면 된다.

주의
- 표준 컨트롤 중 일부는 자신만의 사용자 정의 메시지를 정의하여 사용하고 있다. 따라서 WM_USER+n은 가급적이면 한 윈도우 클래스내에서만 정의하여 사용해야 하며 응용 프로그램간의 통신에는 사용하지 않는 것이 바람직하다.
- 표준 컨트롤을 서브클래싱했을 경우 함부로 WM_USER+n을 사용하면 표준 컨트롤 고유의 메시지와 충돌이 발생할 수 있다.



예제
 
다음 예제는 사용자 정의 메시지로 윈도우를 이동시킨다.

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        RECT wrt;
        TCHAR Mes[]="왼쪽 마우스 버튼을 누르면 이동합니다";

        switch(iMessage) {
        case WM_USER+1:
                GetWindowRect(hWnd,&wrt);
                wrt.left+=wParam;
                wrt.right+=wParam;
                wrt.top+=lParam;
                wrt.bottom+=lParam;
                MoveWindow(hWnd,wrt.left,wrt.top,wrt.right-wrt.left,wrt.bottom-wrt.top,TRUE);
                return 0;
        case WM_LBUTTONDOWN:
                SendMessage(hWnd,WM_USER+1,(WPARAM)-3,(LPARAM)5);
                return 0;
        case WM_PAINT:
                hdc=BeginPaint(hWnd, &ps);
                TextOut(hdc,10,10,Mes,lstrlen(Mes));
                EndPaint(hWnd, &ps);
                return 0;
        case WM_DESTROY:
                PostQuitMessage(0);
                return 0;
        }
        return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

이 예제에서 WM_USER+1은 윈도우를 이동하라는 뜻이며 wParam은 수평 이동 거리, lParam은 수직 이동 거리로 정의하였다. WM_USER+1을 받으면 이 인수들이 지정하는 거리만큼 윈도우를 이동시킨다.

WM_APP

#define WM_MYMESSAGE WM_APP+1

이렇게 매크로를 정의해 놓고 이후부터 WM_MYMESSAGE라는 명칭을 대신 사용하면 된다. WM_USER도 사용자 정의 메시지를 정의하는 용도로 사용되지만 표준 컨트롤중에 이미 WM_USER를 사용하는 컨트롤이 있으므로 중복될 위험성이 있다. 반면 WM_APP는 시스템이 전혀 이 영역을 사용하지 않고 있으므로 중복될 위험이 전혀 없으며 응용 프로그램간의 통신에 사용하기에 적합하다. 두 응용 프로그램의 약속에 의해 WM_APP+n 메시지를 정의하여 사용하면 된다.

WM_USER는 윈도우 클래스를 위한 사용자 정의 메시지이며 WM_APP는 응용 프로그램을 위한 사용자 정의 메시지라는 점이 다르다. 그러나 이 구분은 어디까지나 권장 사항일 뿐이지 강제 사항은 아니다. WM_USER를 응용 프로그램간의 통신에 사용하더라도 충돌이 없다는 확신만 있다면 가능하다. 다만 잠재적인 충돌 가능성이 있을 수 있다는 것을 고려할 때 바람직하지는 않다.

정리

이런 상황을 고려해 보자. MyApp에서 Con1이라는 커스텀 컨트롤을 사용하는데 이 컨트롤은 자신에게 변화가 있을 때 WM_USER+1이라는 통지 메시지를 부모 윈도우로 보내도록 되어 있다. 이런 상황에서 MyApp가 자신의 고유 용도로 WM_USER+1을 다시 정의한다면 메시지간의 충돌이 발생하게 된다. 이런 상황을 방지하기 위해 운영체제는 WM_USER를 내부적인 용도로 WM_APP를 응용 프로그램간의 통신에 사용하도록 권장하는 것이다. 하지만 WM_APP도 여전히 충돌이 발생할 가능성이 있으므로 좀 더 안전한 방법으로 메시지를 정의하고자 한다면 RegisterWindowMessage 함수로 문자열 메시지를 등록하여 사용하는 것이 좋다.


 

리턴값의 의미는 정해져 있다. 응용 프로그램이 의미를 정해서 사용할 수 있다. 이 메시지로 어떤 질문을 하고자할 때는 리턴값을 정의하며 그렇지 않을 경우는 통상 리턴값을 사용하지 않는다.



출처 http://www.winapi.co.kr/reference/Message/WM_USER.htm


'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

간단한 DLL 예제  (1) 2010.02.03
리스트뷰  (0) 2010.02.03
레지스트리  (0) 2010.02.02
o/s의 role  (0) 2010.01.28
파일매핑예제  (0) 2010.01.25
Posted by 아몰라


이벤트란 어떤 사건이 일어났음을 알리는 동기화 객체이다?

 

-       크리티컬섹션, 뮤텍스, 세마포어는 주로 공유자원을 보호하기 위해 사용되는 데 비해 이벤트는 그보다는 스레드간의 작업 순서나 시기를 조정하고 신호를 보내기 위해 사용한다.

 

 

이벤트는 윈도우의 메시지와 유사하다?

 

-       사용자가 키보드 누를 때 WM_KETDOWN 메시지를 윈도우 프로시저에게 보내 처리하게 하는 것처럼 정렬이나 다운로드가 끝났을 때 이벤트를 보내 관련된 다른 작업을 하도록 지시할 수 있다.

 

 

자동 리셋 이벤트

대기 상태가 종료되면 자동으로 비신호상태가 된다.

수동 리셋 이벤트

스레드가 비신호상태로 만들 때까지 신호상태를 유지한다.

 

 

이벤트 함수정리

 

이벤트생성함수

 

HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL blnitialState, LPCTSTR lpname);

 

lpEventAttributes

보안속성

bManualReset

TRUE이면 수동 리셋 이벤트 FALSE이면 자동 리셋 이벤트

blnitialState

TRUE이면 이벤트를 생성함과 동시에 신호상태로 만든다.

lpname

이름

세마포어와 마찬가지로 첫번째, 네번째인자는 프로세스동기화와 관련있다.

 

 

n  이벤트가 뮤텍스나 크리티컬섹션과 또 다른 점은 대기 함수를 사용하지 않고도 임의적으로 신호상태나 비신호상태를 설정할 수 있다는 점이다. 이때 쓰는 함수가 아래와 같다.

 

신호상태변경함수

 

BOOL SetEvent(HANDLE hEvent)

BOOL ResetEvent(HANDLE hEvent)

 

SetEvent

신호상태로 만든다.

ResetEvent

비신호상태로 만든다.

이런 상태변화가 대기중인 스레드에게는 일종의 신호로 전달된다.

 

 

 

자동 리셋 이벤트

 

       대기 상태를 풀 때 자동으로 이벤트를 비신호상태로 만든다는 뜻이다.

       여러 개의 스레드가 하나의 이벤트를 기다리고있을때 적합하지않다.

 

 

수동 리셋 이벤트

 

       대기 상태를 풀 때 신호 상태를 그대로 유지하고 ReSerEvent 함수로 일부러 비신호상태로 만들 때만 상태가 변경된다.

        여러 개의 스레드가 하나의 이벤트를 기다리고있을때 적합하다.



함수 사용 예제

 

HANDLE hEvent;

DWORD WINAPI ThreadSend(LPVOID temp)

{

             WaitForSingleObject(hEvent,INFINITE); //신호상태가 될때까지 무한정대기

             HDC hdc=GetDC(hWndMain);

             TextOut(hdc,210,100,"전송완료",8);

             ReleaseDC(hWndMain, hdc);

             return 0;

}

 

DWORD WINAPI ThreadSave(LPVOID temp)

{

             WaitForSingleObject(hEvent,INFINITE); //신호상태가 될때까지 무한정대기

             HDC hdc=GetDC(hWndMain);

             TextOut(hdc,110,100,"저장완료",8);

             ReleaseDC(hWndMain, hdc);

             return 0;

}

 

DWORD WINAPI ThreadCalc(LPVOID temp)

{

             HDC hdc=GetDC(hWndMain);

             for (int i=0;i<10;i++) {

                           TextOut(hdc,10,50,"계산중",6);

                           GdiFlush();

                           Sleep(300);

                           TextOut(hdc,10,50,"기다려",6);

                           GdiFlush();

                           Sleep(300);

             }

             TextOut(hdc,10,50,"계산완료",8);

             ReleaseDC(hWndMain, hdc);

             SetEvent(hEvent);   //신호상태로 바꿔줌

             return 0;

}

 

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

             HDC hdc;

             PAINTSTRUCT ps;

             DWORD ThreadID;

             TCHAR *Mes="마우스 왼쪽 버튼을 누르면 계산을 시작합니다";

 

             switch (iMessage) {

             case WM_CREATE:

                           hWndMain=hWnd;

                           hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);  //수동이벤트

                          

                           //hEvent=CreateEvent(NULL,FALSE,FALSE,NULL); // 자동 이벤트

                           return 0;

             case WM_LBUTTONDOWN:

                           InvalidateRect(hWnd,NULL,TRUE);

                           ResetEvent(hEvent);

                           CloseHandle(CreateThread(NULL, 0, ThreadCalc, NULL, 0, &ThreadID));

                           CloseHandle(CreateThread(NULL, 0, ThreadSave, NULL, 0, &ThreadID));

                           CloseHandle(CreateThread(NULL, 0, ThreadSend, NULL, 0, &ThreadID));

                           return 0;

             case WM_PAINT:

                           hdc=BeginPaint(hWnd, &ps);

                           TextOut(hdc,10,10,Mes,lstrlen(Mes));

                           EndPaint(hWnd, &ps);

                           return 0;

             case WM_DESTROY:

                           CloseHandle(hEvent);

                           PostQuitMessage(0);

                           return 0;

             }

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

 

WM_CREATE에서 이벤트 객체를 생성하는데 이 때 두 번째 인수로 TRUE를 지정하여 수동 리셋 이벤트가 되도록하였다.

 

가장 위 에 있는 계산스레드가 실행이되는데 계산이 완료되면 SetEvent함수를 호출하여 신호상태로 만든다.

신호상태로 바뀌어지면 대기하고있던 스레드들이 모두 실행 할 수 있다.

 

, 자동리셋은 같은 상황에서 계산스레드가 끝나고 다른 스레드가 실행되는데 그 스레드가 대기함수를 거치면서 신호를 비신호상태로 바꿔놓음으로서 다른 스레드들은 또 대기를 해야한다.



출처 - 윈도우즈 API 정복 , 한빛미디어

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

스레드의 함정  (0) 2010.01.25
스레드  (0) 2010.01.24
세마포어  (0) 2010.01.24
파일매핑 사용순서  (0) 2010.01.24
Dll이란?  (0) 2010.01.24
Posted by 아몰라

 

세마포어는 뮤텍스와 유사한 동기화 객체이다?

 

-      뮤텍스는 하나의 공유 자원을 보호하기 위해 사용하지만 세마포어는 제한된 일정 개수를 가지는 자원을 보호하고 관리한다.

 

 

세마포어는 사용가능한 자원의 개수를 카운트하는 동기화 객체이다?

        

-      유효자원이 0이면 즉 하나도 사용 할 수 없으면 세마포어는 비신호상태가 되며 1이상이면, 즉 하나라도 사용할 수 있으면 신호상태가 된다.

 

 

 

신호상태

스레드의 실행을 허가하는 상태이다.

신호상태의 동기화 객체를 가진 스레드는 계속 실행할 수 있다. (신호등의 파란불)

비신호상태

스레드의 실행을 허가하지 않은 상태이다.

신호상태가 될 때까지 스레드는 블록된다. (신호등의 빨간불)



세마포어 개념을 위한 예)

 

-      네트워크를 통해 프로그램을 다운받는 프로그램을 만든다.

 

n  동시에 여러 개의 자료를 다운로드 받는 것이 가능하기는 하지만 별로 효율적이지는 않다.

n  어차피 네트워크의 대역폭은 정해져 있는 것이므로 한꺼번에 다운로드 받는다고 해서 빨라지는 것도 아니고 그렇다고 순서대로 받는 것은 불편하다.

n  동시에 받되 최대 3개까지만 동시 다운로드가 가능하도록 하고싶다.

n  실제 다운로드 툴이나 웹 브라우저도 일정 개수까지만 동시 다운로드를 지원한다.

 

 

 

 

이경우 자원이란 다운로드 권한이라 표현할 수 있을 것이며 세마포어는 이 권한을 카운트 한다. 세마포어의 초기값을 3으로 설정하고 사용자의 요구가 있을 때마다 다운로드 스레드를 생성한다. 스레드에서는 WaitForSingleObject함수를 호출하여 자신이 사용할 수 있는 권한이 아직 남아 있는지 검사해 보고 가능하다면 다운로드 루프로 진입한다. 이때 대기 함수는 세마포어의 카운트를 1감소시켜 자원이 하나 줄어들었음을 기록한다.

 

두번째, 세번째 스레드가 다운로드를 시작하면 세마포어의 카운트는 0이 되며 비신호상태가 된다. 그러면 이후부터 생성되는 스레드는 다운로드 루프로 진입하지 못하고 자원이 사용가능해질 때 까지 대기하게 된다. 대기중에 첫번 째 스레드가 다운로드를 완료하면 세마포어를 풀 것이고 그러면 세마포어는 다시 1증가하여

신호상태가된다.

 

 

 

세마포어 함수정리

 

 

 

세마포어 생성함수

HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG llnitialCount, Long lMaximumCount, LPCTSTR lpName);

 

lpSemaphoreAttributes

보안속성

llnitialCount

초기값(최대사용개수에 대한 값)

lMaximumCount

최대사용개수(몇 개의 스레드를 실행시킬수 있나)

lpName

이름

첫번째 , 네번째 인자는 프로세스간의 동기화에 사용된다. 한 프로세스에서만 사용 할 시 NULL 값을 주면된다.

 

 

DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);

 

hHandle

하나의 동기화 객체가 신호상태가 되기를 기다린다.

dwMilliseconds

타임 아웃 시간

<dwMilliseconds>

1/1000초 단위로 지정하는데 이 시간이 경과하면 설사 동기화 객체가 비신호상태이더라도 즉시 리턴함으로써 무한 대기를 방지한다. 타임 아웃을 INFINITE로 짖어하면 신호상태가 될 때까지 무한정 대기한다.

 

 

 

WaitForSingleObject 리턴값

 

WAIT_OBJECT_0

hHandle 객체가 신호상태가 되었다.

WAIT_TIMEOUT

타임 아웃 시간이 경과하였다..

WAIT_ABANDONED

포기된 뮤텍스

 

 

 

세마포어의 카운트를 증가시켜주는 함수

 

BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount);

 

hSemaphore

자원을 반환할  세마포어

lReleaseCount

자신이 사용한 자원의 개수를 알려준다.

lpPreviousCount

이전 카운트를 리턴받기 위한 참조 인수

세번째 인자는 이 값에 관심이 없으면 NULL을 넘기면 된다.

 

함수 사용 예제

프로시저실행시

HANDLE hSem;

hsem = CreateSemaphore(NULL, 3, 3 , NULL);

 

마우스왼쪽버튼클릭시

HANDLE hThread;

hThread = CreateThread(NULL, 0, ThreadDownLoad, NULL, 0 , &ThreadID);

 

스레드 진입시

// 다운로드 화면표시 초기화

WaitForSingleObject(hSem, INFINITE);

// 다운로드 실행화면 표시

설명

-      같은 프로세스 내에서 사용할 것이므로 이름을 줄 필요는 없으며 보안 속성도 지정하지 않았다.

-      다운로드 가능 최대 개수는 3으로 설정했으며 처음부터 3개의 자원이 다 사용 가능하므로 초기값도 3이다.

-      왼쪽버튼클릭시 스레드가 생성되고 다운로드 실행화면이 표시된다. 네번째 클릭하게되면  해당 스레드는 WaitForSingleObject에서 대기하다가 어느 스레드가 종료되면 세마포어가 신호상태로되고 기다리던 스레드는 실행하게된다.



출처 - 윈도우즈 API 정복 , 한빛미디어

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

스레드  (0) 2010.01.24
이벤트  (0) 2010.01.24
파일매핑 사용순서  (0) 2010.01.24
Dll이란?  (0) 2010.01.24
파이프 추가내용  (0) 2010.01.20
Posted by 아몰라

 파일매핑 순서

1) CreateFile API로 파일을 연다.

2) CreateFileMapping API로 그 파일에 대한 파일 매핑 객체를 생성한다.

3) MapViewOfFile API로 파일 매핑 객체의 뷰를 생성한다.

 

HANDLE CreateFileMapping(                             //반환값: 객체 핸들 , 실패시 = INVALID_HANDLE_VALUE 반환

      HANDLE hFile,                                           //파일 핸들

      LPSECURITY_ATTIRBUTES lpAttrs,               //보안 속성

      DWORD flProtect,                                        //접근 허가 , 액세스 타입(PAGE_READONLY,

PAGE_READWRITE,PAGE_WRITECOPY)


      DWORD dwMaxSizeHigh,                            //매핑할 크기의 상위 32비트     , 둘다 0이면 전체파일

      DWORD dwMaxSizeLow,                            //매핑할 크기의 하위 32비트     , 둘다 0이면 전체파일

      LPCTSTR lpName);                                    //객체명 , 첫번째 인수를 NULL로 주었을때 다른 프로세스와
                                                                       동기화하기 위한 목적

 

뷰를 만들어 가상 주소 공간에 매핑! >>

매핑해서 파일 읽고 쓰려면 MapViewOfFile API로 '뷰'를 생성해야한다.

뷰는 실제 파일 내용이 매핑되는 가상 주소 영역.

 

LPVOID MapViewOfFile(                      //반환값: 맵핍항 프로그램상의 주소

      HANDLE hFileMapObj,                  //파일 매핑 객체 핸들 ,

      DWORD dwDesiredAccess,         //필요한 접근 제한 액세스 타입(FILE_MAP_WRITE,FILE_MAP_READ,FILE_
                                                     MAP_ALL_ACCESS,FILE_MAP_COPY)

      DWORD dwFileOfsHigh,              //뷰를 실행할 범위의 시작 오프셋 상위 32비트

      DWORD dwFileOfsLow,               //뷰를 실행할 범위의 시작 오프셋 하위 32비트

      SIZE_T dwBytesToMap);             //뷰를 실행할 범위의 크기

  

뷰의 메모리에서 범위를 지정하여 파일 갱신>>

 

BOOL FlushViewOfFile (                                   //반환값: 처리 성공 여부

      LPCVOID lpBaseAddr,                                //갱신할 영역 시작 주소

      DWORD dwNumberOfBytes);                        //갱신할 영역 크기

 

뷰 해제하기 >>

BOOL UnmapViewOfFil(                                    //반환값: 처리 성공 여부

      LPCVOID lpBaseAddr);                               //해체할 뷰의 시작주소

 

파일 매핑 객체 자체가 불 필요하게 될 경우엔 CloseHandle API로 닫기!!

 

 

이름붙은 파일 매핑 객체 핸들을 다른 프로세스에서 가져와 사용하기 >>

HANDLE OpenFileMapping(                               //반환값: 객체 핸들

      DWORD dwDesiredAccess,                         //필요한 접근 권한

      BOOL bInheritHandle,                                 //자식 프로세스에 상속할 것인가?

      LPCTSTR lpName);                                    //객체명  

[출처] 파일매핑|작성자 숙녀라면


'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

이벤트  (0) 2010.01.24
세마포어  (0) 2010.01.24
Dll이란?  (0) 2010.01.24
파이프 추가내용  (0) 2010.01.20
Hooking  (0) 2010.01.15
Posted by 아몰라
Hooking - 이미 작성되어 있는 코드의 특정 지점을 가로채서 동작 방식에 변화를 주는 일체의 기술


훅 프로시저 설치 함수
HHOOK SetWindowHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadld);

int idHook - 어떠한 이벤트에 대해서 후킹을 할것인가
HOOKPROC lpfn - 키보드 이벤트를 받을 훅 프로시저 명
HINSTANCE hMod - 누가 이 훅 체인을 등록할것인지
DWORD dwThreadld - 어느 스레드한테 후킹할것인가


LRESULT CALLBACK keyboardProc(int code, WPARAM wParam, LPARAM lParam);

code - 메시지를 어떤 처리를 할 것인가를 결정
wParam, lParam - 전달된 메시지에 대한 추가 정보

메시지를 훅 체인의 다음 훅 프로시저에게 전달해주는 함수
LRESULT CallNextHookEx(HHOOK hhk, int cCode, WPARAM, wParam, LPARAM, lParam);

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

Dll이란?  (0) 2010.01.24
파이프 추가내용  (0) 2010.01.20
서비스  (0) 2010.01.13
IPC란?  (0) 2010.01.12
동기화  (0) 2010.01.12
Posted by 아몰라
이전버튼 1 2 이전버튼