'MFC'에 해당되는 글 7건

  1. 2008.10.11 메모리 값으로 알아본 블록 상태
  2. 2008.10.11 함수의 호출 규약
  3. 2008.10.10 핸들의 이해
  4. 2008.08.19 2008 컴파일시 특정 경고 무시하기~
  5. 2008.08.09 폴더 찾아보기
  6. 2008.08.09 Dialog 엔터키와 ESC, 사망 방지 및 Alt + F4 종료 확인
  7. 2008.08.09 더블 버퍼링 하는 법 ( rome82 님의 글입니다. )

메모리 값으로 알아본 블록 상태


1) 0XCD, 0xCDCD, 0xCDCDCDCD
   - 초기화 되지 않은 heap 메모리
   - malloc() 또는 new로 객체가 생성되고 아직 Write한 적이 없는 상태

2) 0xFD, 0xFDFD, 0xFDFDFDFD
     - 요청한 블럭에 속하지 않는 위치에 존재하는 몇Bytes가량의 금지구역
   - 메모리 경계검사를 위해 삽입됨

3) 0xDD, 0xDDDD, 0xDDDDDDDD
   - free() 또는 delete로 객체를 Free한 상태
신고

함수의 호출 규약

일반적으로 함수의 호출 규약은
3가지 정도 존재할수 있는데
__fastcall을 제외 시키고 자주 쓰이는 2가지에 대해 알아보자.

1) __cdecl : 일반적인 호출 규약으로써, Caller (부모함수) 가 스택을 정리해줌 - 소스가 길어짐

2) __stdcall : 윈도우 API들의 호출 규약으로써, 스택을 스스로 정리 - 소스가 줄어듬

정도로 생각하면 됨,

아무것도 안쓰면 __cdecl 이 적용되고, CALLBACK, WINAPI 등으로 Define 되면 __stdcall 로 적용됨
신고

핸들의 이해



: 핸들이란 커널 오브젝트에 붙여진 32비트 고유 숫자이다, 다음과 같은 특징을 가진다.

1) 운영체제가 발급해주는 크기가 32비트 정수 : 연산하기 빠름

2) 같은 종류의 오브젝트끼리는 중복 될수 없다. (ex: HBRUSH 끼리 불가)

3) 실제값이 의미하는 바는 없음(몰라도됨).

비교) 주소값을 가지는 포인터와는 다름

신고

2008 컴파일시 특정 경고 무시하기~

다른 버전에서도 될거 같은데,..
stdafx.h 파일에다가

#pragma warning(disable:4996)
#pragma warning(disable:4244)

예를 들어 요렇게 하면

경고 번호 4996 번과 4244이 뜨지 않습니다. ㅋㅋ

신고

폴더 찾아보기

사용자 삽입 이미지



void COptionDialog::OnBnDirectoryAdd()  // 경로 추가 버튼
{

 //////////////////////////////////////////////////////////////////////////
 // 특정 폴더를 추가
 LPITEMIDLIST pidlBrowse;
 char tmp[MAX_PATH];
 CString edit;         // 경로가 저장되는 변수

 BROWSEINFO BRinfo;
 BRinfo.hwndOwner = GetSafeHwnd();    // 부모 윈도우의 핸들
 BRinfo.pidlRoot = NULL;          // 브라우징 할 루트 디렉토리
 BRinfo.pszDisplayName = tmp;     // 선택할 디렉토리가 저장될 버퍼
 BRinfo.lpszTitle = _T("디렉토리를 선택하세요"); // 출력 문자열
 BRinfo.ulFlags = BIF_RETURNONLYFSDIRS|BIF_NEWDIALOGSTYLE  ;  // 디렉토리 선택 옵션
 BRinfo.lpfn = NULL;              // 이벤트에 대한 사용자 정의 처리 함수
 BRinfo.lParam = 0;              // 처리 함수에 넘겨질 인수
 pidlBrowse = SHBrowseForFolder(&BRinfo);     // 다이얼로그를 띄운다.

 if(pidlBrowse != NULL)
 {
  SHGetPathFromIDList(pidlBrowse, tmp);  // 패스를 얻어온다.
  edit.Format(_T("%s"),tmp);
 }
 
 //////////////////////////////////////////////////////////////////////////
 // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
}

신고

Dialog 엔터키와 ESC, 사망 방지 및 Alt + F4 종료 확인

BOOL CDlg::PreTranslateMessage(MSG* pMsg)
{
int YesNo = 0 ;
  switch( pMsg->message )    /// 종료 키보드 메세지 리턴
 {
 case WM_KEYDOWN :
  if((pMsg->wParam == VK_ESCAPE) | (pMsg->wParam == VK_RETURN))
   return TRUE;
 
 case WM_SYSKEYDOWN :    // Alt + F4 메세지 처리
  if(pMsg->wParam == VK_F4)
   YesNo = AfxMessageBox(L" 종료 하시겠습니까? ", MB_YESNO, NULL);
  if (YesNo == IDYES )
  { 
   DestroyWindow();  
  }
  return TRUE;
 }

 return CDialog::PreTranslateMessage(pMsg);
}


다이얼로그에서 PreTranslateMessage 요거 재정의 하시고 위 코드 때려 넣으세요 ㅎㅎ
신고

더블 버퍼링 하는 법 ( rome82 님의 글입니다. )

<메모리 DC 부연설명>
메모리 DC 아직 개념이 잘 안되는것 같아서.. 다시 설명한다.

 화면에 0,0 좌표부터 100x200 크기의 사각형을 깜빡임없이 표시하려고 한다.

화면에서 처리할 데이터의 양이 많을 때 깜빡거리는 현상을 Flicker 라고 함.
이 Flicker 현상을 없애기 위해서(Flicker-Free 하기 위해서) 메모리 DC를 사용해서 고속전송함.
이러한 방법을 이중 버퍼 또는 더블 버퍼링이라고 함.

Flicker-Free 의 구현 내용은 간단함.
아무 기술없이 그냥 WM_PAINT 메시지내에서 CPaintDC를 받아서 사용한다.
예를 들어서 사각형을 그린다고 하면

   CRect rect(0, 0, 100, 200);
   dc.Rectangle(rect);

요렇게 한다.
하지만 저런 도형이 화면에 몇개 이상있고 창의 크기를 변경하거나 하는 작업을 하면
화면에 깜빡이게 된다.

요걸 메모리DC를 사용해서 구현하면 다음과 같다.

   ① CDC dcMem;
   ② CBitmap bmpDC;

   ③ dcMem.CreateCompatibleDC(pDC);
   ④ bmpDC.CreateCompatibleBitmap(pDC, 100, 100);
   ⑤ dcMem.SelectObject(&bmpDC);

1, 2번은 객체를 생성하는거고.. 3번은 dcMem 객체를 현재의 CPaintDC와 호환시켜주도록 하는것임.
2번과 4번에서 CBitmap 을 사용하는데 왜 사용하느냐.
뒤에 가서 설명하겠음.
4번에서 CreateCompatibleBitmap 함수의 인자중에서 100, 100 이 있는데.. 이건 비트맵 크기..
우리가 지금 할려고 하는거는 클라이언트 영역의 깜빡임을 없앨려고 하는 것임.
따라서 저기 100, 100 위치에는 클라이언트 영역의 width와 height가 들어가면 되겠음.

   CRect rcClient;
   GetClientRect(&rcClient);

저렇게 일단 해놓고. 사각형 그리는 함수를 쓴다.

   CRect rect(0, 0, 100, 200);
   dcMem.Rectangle(rect);

어떻게 변했나? 우리가 그릴려고 하는건 사각형인데. CPaintDC dc(this);에서 선언한 dc에다가
안그리고 메모리 DC(dcMem)에다가 그렸다.
그럼 메모리 dc의 0, 0 좌표에서 시작해서 크기가 100x200인 사각형이 그려졌다.
이건 아직 눈에 안보인다. 왜냐.. 메모리 dc에 그렸으니깐..
그럼.. 메모리 dc의 것을 끄집어 내서 화면에다가 그린다.

화면에 나타낼 DC는 뭐고.. WM_PAINT 메시지 안에서는 CPaintDC 사용하고..
그외 함수는 CClientDC 사용하고 Non-Client 영역에서는 CWindowDC 사용한다.
현재 우리는 WM_PAINT를 구현하고 있으니깐 CPaintDC를 사용한다.

   dc.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcMem, 0, 0, SRCCOPY);

이렇게 해주면 된다. 쭉 다 써보면..

<OnPaint(...) 함수>
   CPaintDC dc(this);
   CDC dcMem;
   CBitmap bmpDC;

   CRect rcClient;
   GetClientRect(&rcClient);

   dcMem.CreateCompatibleDC(pDC);
   bmpDC.CreateCompatibleBitmap(pDC, rcClient.Width(), rcClient.Height());
   dcMem.SelectObject(&bmpDC);

   CRect rect(0, 0, 100, 200);
   dcMem.Rectangle(rect);

   dc.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcMem, 0, 0, SRCCOPY);

굵은 거는 그냥 외워버려라.. 그리고 PatBlt 같은거 사용해서 한 예제는.. 참고해서 잘 생각해 보도록..
왜 그렇게 했는지..

정리해서 말하면 WM_PAINT 메시지가 호출될 필요성이 있을 때 WM_ERASEBKGND 메시지가 먼저 호출되고
WM_PAINT가 호출된다. 이때 WM_ERASEBKGND(함수는 OnEraseBkgnd) 는 화면의 가장 바닥(SDI 로 만들면
하얗게 보이는 부분)을 새로 그려준다.. 즉 다시 말하면 화면에 그림이든 글씨든 도형이든 뭐든
있으면 일단 모두 지운다.. 하얀색으로.. 그다음 WM_PAINT(함수는 OnPaint)를 호출해서 사용자가
그릴려고 하는 걸 다시 그려준다.

이 때 모두 지우고 다시 그리는 과정에서 깜빡임이 발생한다. 그래서 화면 지우는 것을 하지 않도록 한다.
그래서 OnEraseBkgnd 함수에서 그냥 return TRUE; 시켜줘버린다.
원래 리턴값은 뭐였나? return CView::OnEraseBkgnd(..) 였을꺼다.. 이 CView 클래스의 OnEraseBkgnd()
함수가 하얗게 지워준다. 그 작업을 하지 않고 그냥 return TRUE; 해버리면 CView::OnEraseBkgnd() 가 실행
되겠나? 안된다..

   BOOL CTestView::OnEraseBkgnd(..)
   {
      return TRUE;
      // return CView::OnEraseBkgnd(..);
   }

이렇다. 저렇게 된걸 C++ 에서 뭐라고 하나? 오버라이딩? 오버로드? 이거 모르면 C++ 부터 다시 공부해라.
일단 저렇게 하면 화면 싹다 지우는건 안하겠지? 그러면 화면 갱신을 어디서 해주노?
WM_ERASEBKGND 다음에 WM_PAINT가 호출되니깐 OnPaint안에서 사용자가 직접해줘야 겠지?
화면을 다 지워주는 작업을 말이다.. 화면 지우는건 그냥 클라이언트 영역 크기만큼 흰색으로 칠해주기만 하면
되잖아. 그래서 PatBlt 쓴다.
이렇게 허옇게 다 지우고 난 다음에 이제 그리고 싶은거 그려라..
단.. 메모리 DC(위에서는 dcMem 변수네..)에다가 다 그리고..
맨 마지막에 진짜 화면에다가 고속전송 BitBlt 해주면 된다.

OnEraseBkgnd 함수에서 return TRUE; 해주고 OnPaint 에서 배경지워주는 작업을 하지 않으면
클라이언트 영역이 뻥 뚤려서 나온다.

        


신고

티스토리 툴바