2011년9월28일_winAPI_대화상자_컨트롤과의 통신
● 일반 컨트롤과 대화상자의 차일드 컨트롤의 차이점
에디트 컨트롤을 생성하는 코드는 아래와 같고,
9번째 인자로 컨트롤의 ID(여기서는 0)를 넣고 컨트롤이 생성이 되고 생성된 컨트롤을 다룰 수 있는 핸들이 반환된다.
그런데 대화상자를 생성하는 코드를 보면,
두 번째 인자로 다이얼로그의 ID를 넣고 대화상자를 생성한 뒤에,
EndDialog( )로 대화상자를 닫아야 블로킹이 풀리고 EndDialog()의 두 번째 인자가 전달되어 리턴된다.
여기서 잘 보면 대화상자 내부의 컨트롤들의 ID와 핸들은 관여하지 않는다는 것을 알 수 있다.
(대화상자는 컨트롤 종합선물세트(컨테이너)이니까 일일이 핸들을 반환하거나 인자로 넣기 곤란하겠지..)
대화상자 내부의 컨트롤들(차일드 컨트롤)의 값을 읽고 쓰려면 그 컨트롤의 핸들이 필요하다.
( malloc()로 할당받은 메모리를 엑세스하려면 가리키는 포인터가 필요하듯이 핸들이 필요함.)
● 차일드 컨트롤의 ID를 입력하여 핸들을 얻어내는 함수 GetDlgItem()
HWND GetDlgItem(HWND hDlg, // 대화상자의 핸들 (소속)
int nlDDlgItem); // 핸들을 얻고자 하는 컨트롤의 ID |
아래와 같이 리소스를 만들 때 대화상자내의 차일드 컨트롤들의 ID도 정할 수 있으니,
엑세스 하고 (핸들을 얻고) 싶은 컨트롤의 ID를 두 번째 인자로 넣으면 그 컨트롤을 엑세스할 수 있는 핸들이 리턴된다.
● 차일드 컨트롤의 핸들을 입력하여 ID를 알아내는 함수 GetDlgCtrlID()
int GetDlgCtrlID(HWND hwndCtl); // 컨트롤의 핸들 –> 컨트롤의 ID |
이 함수는 좀 생뚱맞게 핸들로 ID를 알아낸다. 사용빈도가 별로 높지 않으니 있다는 것만 알아두자.
이런 변환은 어디서 많이 본 것 같은데 TCP/IP소켓 프로그래밍에서 32bit주소와 도메인, dotted주소 변환과 비슷하다.
왜 ID와 핸들을 따로 두어 프로그래머들을 귀찮게 하는가?
일단 컨트롤은 윈도우이며 따라서 윈도우를 관리하기 위해서는 핸들이 필요하다.
그런데 핸들이라는 것은 그 특성상 운영체제가 일방적으로 발급하는 것이기 때문에 번호의 연속성이 없으며,
그러다 보니 반복적인 처리에는 사용할 수 없다는 문제가 있다.
그래서 연속성을 가질 수 있고 사용자가 직접 번호를 지정할 수 있는 ID가 필요한 것이다.
ID는 연속적이라 for루프로 반복작업이 가능하고 CheckRadioButton( )로 라디오버튼의 그룹범위 지정도 가능하다.
● 대화상자 –> 차일드 컨트롤 메시지전송
대화상자가 차일드 컨트롤을 프로그래밍하는 주된 방법은 SendMessage( )로 메시지를 보내는 것인데,
이 함수는 대상 윈도우의 핸들을 요구한다. SendMessage( )의 첫 번째 인자로 윈도우의 핸들을 넣는데 여기에 엑세스하고 싶은 차일드 컨트롤의 핸들을 넣는다. 그래서 GetDlgItem( )로 핸들을 알아내 SendMessage( )의 인자로 넘겨준다.
SendMessage(GetDlgItem(hDlg, 컨트롤의 ID),… ); |
이렇게 사용하면 번거로우니 아래와 같은 함수를 사용하여,
LONG SendDlgItemMessage(HWND hDlg, // 대화상자의 핸들
int nID, // 메시지를 받을 컨트롤의 ID UINT Msg, // 메시지 WPARAM wParam, // 파라미터 w (이건 그 때 그 때 달라요~) LPARAM lParam); // 파라미터 l (이건 그 때 그 때 달라요~) |
알고 있는 (resouce.h에 등록된) 차일드 컨트롤의 ID와 소속된 대화상자의 핸들을 사용하여 한 번에 해결한다.
이 함수는 GetDlgItem( )와 SendMessage( )를 호출하는 레퍼함수라고 할 수 있다.
(레퍼함수는 printf( )처럼 다른 함수를 호출하는 함수)
● 대화상자 <-> 컨트롤간 문자열 교환
UINT GetDlgItemText(HWND hDlg, // 대화상자 윈도우 핸들
int nID, // 엑세스할 컨트롤의 ID LPTSTR lpString, // 문자열을 담을 버퍼 int nMaxCoutn); // 문자열길이 |
GetDlgItemText( )는 컨트롤로부터 문자열을 읽어와 버퍼에 저장하는 함수이고,
fgets( )와 비슷하게 읽어 올 문자수를 지정할 수 있다.
BOOL SetDlgItemText(HWND hDlg, // 대화상자 윈도우 핸들
int nID, // 엑세스할 컨트롤의 ID LPCTSTR lpString); // 쓸 문자열 |
SetDlgItemText( )는 컨트롤에 문자열을 쓰는 함수이다.
● 대화상자 <-> 컨트롤간 정수 교환
UINT GetDlgItemInt(HWND hDlg, // 대화상자 윈도우 핸들
int nID, // 엑세스할 컨트롤의 ID BOOL *lpTranslated, // 에러 검사할 필요없으면 NULL BOOL bSigned); // TRUE = 부호있는 정수, FALSE = 부호없는 정수 리턴 |
GetDlgItemInt( )는 컨트롤로부터 정수값을 읽어와 리턴하는 함수이다.
변환의 성공 여부를 리턴받기 위한 포인터 변수. 정수로 변환하지 못할 문자열이면 이 변수로 FALSE가 리턴된다.
성공 여부를 조사할 필요가 없으면 NULL로 줄 수 있다. - 참조URL: http://winapi.co.kr
BOOL SetDlgItemInt(HWND hDlg, // 대화상자 윈도우 핸들
int nID, // 엑세스할 컨트롤의 ID UINT uValue, // 컨트롤에 대입할 정수값 BOOL bSigned); // TRUE = 부호있는 정수, FALSE = 부호없는 정수 리턴 |
SetDlgItemInt( )는 컨트롤에 정수값을 대입하는 함수이다.
● 대화상자내의 에디트 컨트롤의 정수값을 기억하는 예제
대화상자가 생성되면 WM_INITDIALOG메세지가 발생하여 OnInitDialog( )가 호출된다.
SetDlgItemInt( )로 에디트박스(ID는 IDC_EDIT1)에 변수Age에 저장된 값을 부호를 없애고 기록한다.
(Age는 전역변수, DATA영역 –> heap영역)
※ 초기화 되지 않은 전역변수는 BSS영역에 배치되나 DATA가 맘에 들어서! DATA영역.
GetDlgItemInt( )는 에디트박스(ID는 IDC_EDIT1)로부터 부호없는 정수값을 에러검사하지 않고 읽어와 리턴하여 Age에 저장한다.
(heap영역 –> DATA영역)
heap영역은 실행 중에 생성과 소멸을 반복한다. 대화상자가 생성되면 자리가 확보되고 대화상자가 소멸되면 모두 사라진다.
※ 실제 heap영역에 윈도우(컨트롤)의 데이터가 있는지 확인은 하지 않았으나 heap영역이외에 적재될 곳이 없다고 생각함.
<실행결과>
어제 작성한 About예제코드에 상기의 코드들을 삽입하고 전역변수 Age를 선언하고 에디트리소스를 추가한 뒤에,
ID는 디폴트로 두고 실행하면 Age는 전역변수니 초기값이 0이다.
이 값이 마우스 왼쪽클릭하여 대화상자 생성 후 바로 기록되니 왼쪽 스크린샷과 같이 0이 출력된다.
에디트박스를 클릭하여 숫자를 300으로 수정하고 OK버튼을 클릭하여 대화상자를 닫으면,
아무 것도 없는 공허한 부모윈도우가 다시 보이고, 이 상태로 종료하지 말고 차분하게 마우스왼쪽클릭하면,
대화상자가 생성되고 DATA영역에 저장된
● 대화상자 <-> 컨트롤간 논리값 교환
'내장형하드웨어 > 일일보고서' 카테고리의 다른 글
2011년9월28일_pcap_이더넷구조체를 가리키는 구조체포인터를 사용하여 캡쳐한 패킷의 헤더를 추출하자. (2) | 2011.09.29 |
---|---|
2011년9월28일_winAPI_대화상자_컨트롤과의 통신 (0) | 2011.09.29 |
2011년9월27일_pcap_패킷 캡쳐 라이브러리를 사용하여 FTP서버에 로그인시 송신되는 패킷을 캡쳐해보자. (2) | 2011.09.28 |
2011년9월27일_winAPI_대화상자이론, 모달형 대화상자 예제, 대화상자기반의 프로그램(Dialog Base) (0) | 2011.09.27 |
2011년9월26일_pcap_패킷 캡쳐 라이브러리를 사용하여 랜카드이름을 알아보자. (0) | 2011.09.26 |