[Win32] 1. 개요, HINSTANCE, Event객체

김성엽님의 블로그를 따라하고 있습니다.

API, SDK

  • API : OS 와 응용프로그램 사이에 운영체제가 제공한느 함수 집합체
  • SDK : Software Development Kit, 소프트웨어 개발 키트
    • 응용프로그램을 개발하기 위해서 필요한 프로그램 집합체

데스크톱 응용 프로그래밍

Win32 API 응용프로그래밍 을 Windows 데스크톱 응용프로그래밍이라고 한다.

응용프로그램은 어떻게 만들까?

  • Windows OS는 C 기반이라서 C언어, API 기반으로 응용프로그램을 개발하는 것이 기본.
  • 물론 다른언어로도 개발가능
  • '.Net 프레임워크', 'Java 프레임워크' 같은 추가 개발환경을 구성하면 좀더 쉽게 개발함
    • 이런 프레임워크는 버전이 중요함. 버전이 다르면 당연히 오류가 남.

초보개발자에서 벗어나기

  • 수학을 할줄 아는 사람이 계산기 두드리기 vs 그냥 모르는채 계산기 두드리기 하면 당연히 전자가 이김.
  • 그러니까 기초를 튼튼히 하는게 더 좋다(김성엽님 의견)

핸들(Handle)에 대해

운영체제와 리소스

  • 운영체제(OS) : 컴퓨터를 유저가 쉽게 제어할 수 있게해주는 소프트웨어
  • 리소스 : OS에 의해 관리되는 장치, 해당 장치를 사용하기 위해 필요한 정보들

응용프로그램은 컴퓨터 리소스에 접근을 해서 해당 작업을수행하게 된다.

응용프르로그램이 리소스에 직접 접근하면 위험하다.

  • OS가 작동불능이 될수 있기 때문에, OS의 리소스는 포인터로 못 가져온다.

핸들 : OS 에서 리소스를 안전히 관리하기위해 사용하는 주소

  • 이것을 API 함수를 이용하여 받거나 요청할 수 있다.

Win32 프로그램에서 핸들 값은 어떻게 저장할까?

  • HANDLE 자료형으로 저장 : unsigned int(32비트) 자료형 이다.
HCURSOR h_my_cursor = LoadeCursor(NULL, IDC_ARROW); // 커서 핸들 값 저장
HINCON h_my_icon = LoadIcon(NULL, IDI_APPLICATION); // 아이콘의 핸들 값 저장

HINSTANCE

H(Handle) + Instance
Instance Handle 을 저장할 때 사용.

  • 윈도우즈 운영체제에서 실행되는 프로그램을 구별하기위한 정수로 된 ID 값
  • 동일한 프로그램을 여러개 실행해도 같은 값임.

Process ID 와 다른 값이다.

  • Process ID : 메모리에 실행 가능한 상태로 재배열 된 실행코드(Process)를 구별하기 위한 값
  • Instance Handle 은 여러번 중복해서 가지게 되는 리소스(아이콘, 커서, 비트맵 등) 공유하기위해 나온 개념.
  • Process ID는 그냥 모든 프로세스를 개별적으로 구별하기 위한 값

Incetance Handle 값은 어떻게 얻누?

int WINAPI_WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdlLine, int nCmdShow)
{
  ...
  • WinMain 함수가 시작함수인데, hInstance 값이 전달된다.

hInstance 값을 잘 저장했다가 HINSTANCE형식의 값을 요구하는 API에 사용하면 됨.

HCURSOR LoadCursor(HINSTANCE hInstance, LPCWSTR lpCursorName);

Event 객체

서로 다른 스레드간 정보를 주고받거나 동기화할 때 사용하는 객체.

동기화(Synchorization)

  • 연대책임으로 함께 하는걸 동기화라고 함.
  • A값을 구한 사람이 다른 작업을 위해 B값을 구하는 자겁이 완료되기를 기다려주는 행위. 아무튼 이런느낌

Event 객체에 대하여

  • 여러 스레드를 사용할 때 동기화작업은 필수
  • 동기화작업을 쉽게하려할 때 사용하는 것이 Event 객체이다.
  • 이벤트 객체는 0,1(True or False) 상태를 기억할 수 있는 커널객체(Kernel Object)이다.

CreateEvent : 이벤트객체를 만드는 함수

Handle h_event_object = CreateEvent(NULL, TRUE, FALSE, NULL);

CreateEvent 함수는 아래와 같은 함수원형을 가지고 있음

HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,
		BOOL bManualReset, BOOl bInitialState, LPCSTR lpName);
  • lpEventAttributes
    • SECURITY_ATTRIBUTES 구조체로 선언된 변수의 주소 명시.
    • 이 구조체 속에 lpSecrityDescriptor에는 생성될 이벤트 객체 보안기술자(계정정보) 에 대해 명시하도록 되어있음
    • 로그인 된 사용자의 로그인 정보에 있는 ACL(Access Control List)를 적용하거나, 이벤트 객체에 생성한 프로세스의 ACL가져와 사용가능
      • ACL이 적용되는 객체에는 다른 사람이 해당 객체에 접근하는 것을 제한하거나 허락할 때 ACL을 변경하며 사용함.
    • 특별한 보안정책을 사용하지 않거나, 공부목적이면 그냥 NULL 쓰세용
  • bManualReset
    • TRUE라고 적으면 해당 객체가 조건에맞춰 FALSE 일때 까지 계속 TRUE.
    • FALSE라고 적으면 해당 객체가 조건에맞춰 TRUE 일때 까지 계속 TRUE.
  • bInitialState
    • 생성될 이벤트의 초기값을 설정함.
  • LPCTSTR IpName
    • 이벤트 객체에 사용될 이름을 명시한다.
    • 대소문자 구별함.
    • 만약 다른 스레드에서 "Tipsware"를 사용하는데 "Tipsware"로 생성하면 그 이벤트 객체들은 서로 공유하게 된다.
      Handle h_event_object = CreateEvent(NULL, TRUE, FALSE, L"Tipsware");
      • 이렇게 중복되서 생성되면 공유하지만, 먼저 생성된 이벤트의 정보가 우선시됨(새로만든 이벤트의 bManualReset, bInitialState에 적은 매개변수 값 무시)
      • 동일한 커널객체 형식에서만 값을 공유하기 때문에 이렇게 됨.
  • 함수의 반환 값
    • GetLastError()함수 : 이미 같은 lpName을 사용해서 이벤트객체가 공유중이라면 ERROR_ALREADY_EXISTS가 반환됨
    • Create가 실패되면 NULL값이 나온다.
    • 성공적인 이벤트생성을 확인하고싶거나, 공유되는 이벤트를 사용하기 싫으면 위의 GetLastError로 확인해보자.

이벤트객체 사용이 끝나면 꼭 제거해야함

  • CloaseHandle(h_event_object);

이벤트 객체 상태 설정하기

  • 이벤트객체의 상태값을 TRUE로 만들고 싶으면 SetEvent()
  • FALSE로 만들고싶으면 ResetEvent()
// 이름없는 이벤트 객체를 생성(수동해제, 초기값 FALSE)
HANDLE h_event_object = CreateEvent(NULL, TRUE, FALSE, NULL);

SetEvent(h_event_object); // 이 이벤트 객체의 상태값을 TRUE 상태로 변경한다.

CloseHandle(h_event_object); // 이벤트 객체의 사용을 중단

이벤트 객체의 상태 체크하기

  • 본 이벤트는 다수의 스레드간 작업시점을 동기화하려 사용하는 것임.
  • WaitForSingleObject() : 이벤트 객체의 상태값이 변경되는지 체크할 때 사용되는 함수
DWORD state = WaitForSingleObject(h_event_object, 5000); // 5000->5초
  • 이벤트가 변경되면 5초까지 안기다리고 바로 함수를 빠져나온다.
    • 변경되면 state 값에 WAIT_OBJECT_0 저장
    • 변경이 안되면 state 값에 WAIT_TIMEOUT
// 이벤트 객체 생성 (수동해제, 초기값 FALSE)
HANDLE h_event_object = CreateEvent(NULL, TRUE, FALSE, L"Tipsaware");

DWORD state = WaitForSingleObject(h_event_object,5000); 
if(WAIT_OBJECT_0 == state){
	// 5초 이내 상태가 변경된 경우
} else if(WAIT_TIMEOUT == state){
	// 5초 동안 상태가 변경되지 않아서 타임아웃이 발생함
}
CloseHandle(h_event_object); // 이벤트 객체의 사용을 중단.
  • 시간 제한 없이 기다리고싶으면 INFINITE 값을 사용하면됨
    DWORD state = WaitorSingleObjcet(h_event_object,INFINITE);

좋은 웹페이지 즐겨찾기