<LRESULT와 CALLBACK의 데이터형에 관해>

 윈도우 프로시져를 보면 LRESULT와 CALLBACK이라는 데이터형이 있습니다. 책에서 보면 LRESULT는 윈도우 프로시저에서 반환되는 데이터형이고 CALLBACK은 FAR PASCAL을 재정의한 것으로 콜백루틴이나 프로시저에서 사용한다고 나와 있더군요. LRESULT는 윈도우 프로시저에서 반환되는 데이터형이라고 하는데 무엇을 반환하는 것인지 궁금합니다. 또한 CALLBACK에서는 FAR PASCAL형이 무엇이고 콜백루틴은 무엇을 말하는 것인지, 혹시 운영체제가 필요에 의해 호출하는 것을 말하는지 사용예를 통해 자세하게 설명해 주세요.

 먼저 LRESULT에 대해 말해 보면 LRESULT는 비주얼 C++에서 다음과 같이 선언돼 있습니다.

#define LRESULT LONG

 즉 LRESULT는 long 변수의 다른 이름일 뿐입니다. long이라는 리턴값을 쓰지 않고 굳이 LRESULT라고 재선언한 것은 이 값이 리턴값임을 좀더 명확히 나타내기 위한 프로그래머의 의도라 생각하면 됩니다. 결국 LRESULT로 반환되는 값은 long값이라 생각하면 되는데 그렇다고 해서 꼭 숫자일 필요는 없습니다. long은 4 바이트 변수이므로 LRESULT에 포인터를 캐스팅해서 반환해도 무관합니다. 포인터 역시 4바이트의 변수일 뿐이니까요. 대부분의 윈도우 프로그램에서는 LRESULT 값으로 객체의 포인터를 반환하는 것을 자주 볼 수 있을 겁니다.

 CALLBACK은 FAR PASCAL의 다른 이름입니다. FAR라는 것은 원거리 포인터임을 나타내는 것이고 PASCAL이라는 것은 함수 호출규약을 나타내는 것입니다. 프로그래밍 내에서 함수호출이라는 것은 그 함수의 시작포인터로 점프하는 것을 의미하고, 또 윈도우에서는 가상 메모리 주소를 사용하므로 대부분의 함수 진입부가 원거리 포인터라는 뜻입니다.

 하지만 윈도우 95이상에서는 원거리 포인터와 근거리 포인터의 구분이 없으므로 FAR라는 것은 무시해도 상관없습니다. PASCAL 호출규약이라는 것은 함수를 호출할 때 넘겨지는 인자가 스택에 어떠한 순서로 쌓일지에 대한 약속입니다. C에서는 인자를 왼쪽에서부터 오른쪽으로 차례로 인자 값을 스택에 넣어 넘겨주고 함수에 진입하면 이와는 반대순서로 스택에서 그 값을 받아와 사용합니다. 하지만 C++에서는 이와 반대의 순서로 스택에 인자를 넣어 사용하게 됩니다. 또한 PASCAL 호출규약은 함수를 호출하면 이전에 사용되던 변수의 값 ax, bx, cx 등의 값을 먼저 스택에 넣어두었다가 함수가 리턴되기 전에 이 값을 복원시켜주지만 C에서는 함수를 호출하기 전 이러한 일들을 하고 함수가 끝나서 이전의 스텝으로 돌아오면 그제서야 변수값을 복원하는 일을 합니다.

 이러한 것이 바로 FAR PASCAL이 의미하는 것이고 이것을 CALLBACK이라고 선언해 사용하는 것은 이 함수가 콜백함수로 사용됨을 프로그래머가 명시하기 위한 것입니다. 즉 자신이 짠 이 함수는 윈도우에서 CALLBACK되어 불리어지는 함수라는 것을 자신이나, 다른 사람이 봐서 금방 알 수 있도록 이렇게 이름 붙여놓은 것입니다. 이 두 가지 모두 사용 용도를 명확히 하는 역할을 할 뿐 다른 것과의 차이점은 없는데, 이렇게 사용하는 이유는 윈도우 프로그램의 크기가 예전에 비해 무척 커져가고 작업도 여러 사람이 같이 하는 경우가 많아 서로의 의도를 다른 사람에게 명확하게 설명하고자 하는 제작자의 의도가 들어있다고 보면 됩니다.

 

<MDI에서 Child View Handle 구하는 방법>

MDI로 프로그램을 만들고 있는데 두 개의 창을 띄우고 각각의 뷰의 핸들을 알고 싶은데 방법을 모르겠습니다.

MDI에서 현재 떠있는 뷰의 핸들을 구하는 방법은 다음과 같이 여러 가지일 수 있습니다.

[1] CWinApp의 포인터를 구한다.
[2] 현재의 도큐먼트 템플릿으로부터 CDocument의 리스트에 접근한다.
[3] 현재 묶여있는 도큐먼트 리스트로부터 차례로 도큐먼트 포인터를 얻는다.
[4] 각각의 도큐먼트에는 하나 이상의 뷰가 존재하므로 이를 구한다.

CMainFrame::GetViewPtr()
{
     // CWinApp의 포인터를 구한다.
     CTestApp* pApp = (CAddApp*)AfxGetApp();
     // 현재의 도큐먼트 템플릿으로부터 도큐먼트 리스트에서 첫째 도큐먼트의 위치를 구한다.
     POSITION pos = pApp->m_pDocTemplate->GetFirstDocPosition();
     CTestDoc* pDoc;

     CTestView* pView;
     POSITION posView;
     while( pos != NULL ) {
          // GetNextDoc()을 수행하며 도큐먼트 리스트에서 도큐먼트 포인터를 구한다.
          pDoc = (CAddDoc*)pApp->m_pDocTemplate->GetNextDoc( pos );
          // 구해진 도큐먼트 포인터에서 현재 도큐먼트와 연관돼 있는 뷰 포인터를 구한다.
          // 하나의 도큐먼트에 하나의 뷰가 존재한다고 가정
          posView = pDoc->GetFirstViewPosition();
          pView = (CAddView*)pDoc->GetNextView( posView );
     }
}

 이와 같다면 현재 떠 있는 창의 뷰 포인터를 모두 얻을 수 있을 겁니다. 앞에서 GetNextDoc()은 현재(리스트의 위치)의 도큐먼트 포인터를 반환한 후에 pos값을 다음 도큐먼트 포인터의 위치로 바꿉니다. 따라서 마지막 도큐먼트 포인터를 반환한 후에는 더 이상 없으므로 pos 값을 NULL로 설정합니다. 그러면 루프를 빠져나오게 되고 현재 떠있는 모든 도큐먼트와 그에 따른 뷰 포인터 및 핸들을 구할 수가 있습니다.

 

<I/O 포트 제어법>

C에서 사용하는 inport, outport 명령을 비주얼 C++에서 구현하는방법을 알고 싶습니다. 방법을 알려주세요.

<conio.h>를 보면 _inp(), _inpw(), _inpd(), _outp(), _outpw(), _outpd() 라는 라이브러리 함수가 있는데, 이를 이용하면 비주얼 C++에서 해당 포트 데이터를 읽거나 해당포트에 데이터를 쓸 수 있습니다. _inp() 는 1바이트의 데이터를 포트로부터 가져오는 것이고, _inpw() 는 2바이트, _inpd() 는 4바이트의 데이터를 가져오는 함수들입니다. _outp() 계열의 함수는 해당 바이트만큼 해당 포트에 쓰기(Write)를 하는 것입니다.

BYTE byteData = _inp( 0x3f8 );

 이와 같다면 0x3f8(COM1 address)번지에서 1바이트의 데이터를 가져오는 것이고,

_outp( 0x3f8, byteData );

이와 같다면 0x3f8 번지에 1바이트의 데이터를 쓰게 됩니다.

 

<타이틀 바에 비트맵 입히기>

타이틀 바를 제가 만든 비트맵 그림으로 예쁘게 바꾸고 싶은데 어떻게 해야 하는지 궁금합니다. 이와 함께 최소화나 최대화, 닫기 버튼도 비트맵으로 바꾸고 싶은데 어떻게 해야 합니까?

 캡션 바를 없애고 그 부분을 위치 값과 비트맵 버튼 등을 이용해 닫기, 최소화, 최대화 버튼들을 만들어 줍니다. 다이얼로그를 움직일 때 일정 위치에서 마우스가 될 때 움직이게 하면 됩니다. 쉽게 말하면 캡션 바를 만들어 주는 셈이지요. 그리고 캡션 바의 주 기능인 잡고 움직이는 것은 다음에서 소개하는 소스(3부분)를 참고하기 바랍니다. 다이얼로그 아무 곳이나 잡아도 창을 움직일 수 있는 소스입니다.

void CDragDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
     CDialog::OnLButtonDown(nFlags, point);
     // fake windows into thinking your clicking on the caption, does not
     // maximizeon double click
     PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x, point.y));
}


     // Generated message map function
     //{{AFX_MSG(CDragDlgDlg)
     virtual BOOL OnInitDialog();
     afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
     afx_msg void OnPaint();
     afx_msg HCURSOR OnQueryDragIcon();
     afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
     //}}AFX_MSG

     afx_msg UINT OnNcHitTest( CPoint point );  // <- 여기에 추가

     DECLARE_MESSAGE_MAP();


UINT CDragDlg::OnNcHitTest(CPoint point);
{
     UINT nHitTest = CDialog::OnNcHitTest( point );
     // also fake windows out, but this maximizes the window
     // when you double click on it.
     return (nHitTest == HTCLIENT) ? HTCAPTION : nHitTest;
}

 

<글자크기 변경>

비주얼 C++에서 다이얼로그 박스 등에서 스태틱(Static) 텍스트나 버튼 등의 캡션에 사용되는 글자의 크기를 바꾸고 싶습니다. 그리고 가능하면 폰트도 바꾸고 싶구요. 방법을 알려주세요.

 먼저 CFont형 멤버 변수가 있어야 합니다. 다이얼로그의 멤버 변수로 CFont m_font;를 OnInitDialog() 핸들러에서 다음과 같이 폰트를 초기화하고 스태틱(혹은 버튼)과 연관된 컨트롤 변수(m_ctlStatic)에 SetFont(...) 함수를 이용해 폰트를 지정합니다. CreateFont(...) 함수에 대해서는 MSDN을 참고하기 바랍니다.

m_font.CreateFont(30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "궁서체");
m_ctlStatic.SetFont(&m_font);

 

- the end of this article -