Skip to content

MFC Application Integration

A canonical pattern for embedding henc into an MFC SDI / MDI application via a CView subclass.

CEncView.h
#include "henc.h"
#include <gl/GL.h>
class CEncView : public CView
{
protected:
HGLRC m_hRC; // OpenGL context
HDC m_hDC; // device context
int m_view; // henc view handle
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);
// Standard PIXELFORMATDESCRIPTOR + ChoosePixelFormat + SetPixelFormat
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 init
if (hencInit() != 0) {
AfxMessageBox(_T("hencInit failed"));
return -1;
}
m_view = hencCreate();
hencSelect(m_view);
// Default cell - load via a menu in a real app
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);
}
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);
}
// Suppress CView's own background paint (avoids flicker)
BOOL CEncView::OnEraseBkgnd(CDC* /*pDC*/) { return TRUE; }
void CEncView::OnLButtonDown(UINT nFlags, CPoint point)
{
if (!m_inited) { CView::OnLButtonDown(nFlags, point); return; }
// Pick the closest S-57 object within ±8 px of the click
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 fires but the view is blank: another context may be current. Re-call wglMakeCurrent at the start of OnDraw in apps with multiple views/dialogs.
  • OnSize reports 0×0: can happen on initial OnCreate. Guard with m_inited.
  • Flicker: must return TRUE from OnEraseBkgnd: the MFC default paints a white background.
  • Empty pick result: increase the pick radius (8 → 16 px) or use hencSelectObj with a rectangle.