콘텐츠로 이동

MFC 응용 통합

MFC SDI/MDI 응용에서 CView 파생 클래스에 henc 를 통합하는 전형적인 패턴.

CEncView.h
#include "henc.h"
#include <gl/GL.h>
class CEncView : public CView
{
protected:
HGLRC m_hRC; // OpenGL 컨텍스트
HDC m_hDC; // 디바이스 컨텍스트
int m_view; // henc 뷰 핸들
bool m_inited;
public:
CEncView();
virtual ~CEncView();
protected:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
virtual void OnDraw(CDC* pDC);
DECLARE_MESSAGE_MAP()
};
CEncView.cpp
BEGIN_MESSAGE_MAP(CEncView, CView)
ON_WM_CREATE()
ON_WM_DESTROY()
ON_WM_SIZE()
ON_WM_LBUTTONDOWN()
ON_WM_ERASEBKGND()
END_MESSAGE_MAP()
int CEncView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1) return -1;
m_hDC = ::GetDC(m_hWnd);
// PIXELFORMATDESCRIPTOR 설정 + ChoosePixelFormat + SetPixelFormat 생략 (표준 OpenGL 셋업)
PIXELFORMATDESCRIPTOR pfd = {};
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
int pf = ChoosePixelFormat(m_hDC, &pfd);
SetPixelFormat(m_hDC, pf, &pfd);
m_hRC = wglCreateContext(m_hDC);
wglMakeCurrent(m_hDC, m_hRC);
// henc 초기화
if (hencInit() != 0) {
AfxMessageBox(_T("hencInit failed"));
return -1;
}
m_view = hencCreate();
hencSelect(m_view);
// 기본 셀 자동 로딩 (응용에 따라 메뉴에서 호출)
hencLoad("S57/KR4A4061.000");
hencSetCenter(m_view, 129.42, 35.10);
hencSetZoom(m_view, 12.0);
m_inited = true;
return 0;
}
void CEncView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
if (!m_inited || cx <= 0 || cy <= 0) return;
hencSetViewport(m_view, 0, 0, cx, cy);
Invalidate(FALSE); // 다음 OnDraw 트리거
}
void CEncView::OnDraw(CDC* /*pDC*/)
{
if (!m_inited) return;
wglMakeCurrent(m_hDC, m_hRC);
hencSelect(m_view);
hencClearBackground(m_view);
hencRender(m_view);
hencSwapBuffer(m_view);
}
// CView 가 자체 배경을 그리지 않도록
BOOL CEncView::OnEraseBkgnd(CDC* /*pDC*/) { return TRUE; }
void CEncView::OnLButtonDown(UINT nFlags, CPoint point)
{
if (!m_inited) { CView::OnLButtonDown(nFlags, point); return; }
// 클릭 위치 ± 8 px 영역 내에서 가장 가까운 S-57 객체를 픽킹
int objHandle = hencPickObj(m_view, point.x, point.y, 8);
if (objHandle >= 0) {
char buf[2048];
hencObjToString(objHandle, buf, sizeof(buf));
CString msg(buf);
AfxMessageBox(msg);
}
CView::OnLButtonDown(nFlags, point);
}
void CEncView::OnDestroy()
{
if (m_inited) {
hencDelete(m_view);
hencDeinit();
}
wglMakeCurrent(NULL, NULL);
if (m_hRC) wglDeleteContext(m_hRC);
if (m_hDC) ::ReleaseDC(m_hWnd, m_hDC);
CView::OnDestroy();
}
  • OnDraw 가 호출돼도 빈 화면: wglMakeCurrent 가 OnDraw 마다 호출되지 않으면 다른 컨텍스트가 현재 상태일 수 있다. 멀티 뷰·다이얼로그가 있으면 매번 명시적으로 컨텍스트 활성화.
  • OnSize 에서 뷰포트가 0×0: 최초 OnCreate 시점에 cx == 0인 경우가 있다. m_inited 플래그로 가드.
  • MFC OnEraseBkgnd 깜빡임: 반드시 OnEraseBkgnd 에서 TRUE 반환. 기본 동작은 흰 배경으로 채워 깜빡임 발생.
  • 객체 선택이 빈 결과: hencPickObj 의 검색 반경(px) 을 8~16 정도로 늘리거나, hencSelectObj 로 사각 영역 선택 사용.