MFC Application Integration
A canonical pattern for embedding henc into an MFC SDI / MDI application via a CView subclass.
Header / members
Section titled “Header / members”#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()};Message map + OnCreate (henc init)
Section titled “Message map + OnCreate (henc init)”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;}OnSize: viewport sync
Section titled “OnSize: viewport sync”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: per-frame render
Section titled “OnDraw: per-frame render”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; }OnLButtonDown: object picking
Section titled “OnLButtonDown: object picking”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);}OnDestroy: teardown
Section titled “OnDestroy: teardown”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();}Common pitfalls
Section titled “Common pitfalls”- OnDraw fires but the view is blank: another context may be current. Re-call
wglMakeCurrentat 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
TRUEfromOnEraseBkgnd: the MFC default paints a white background. - Empty pick result: increase the pick radius (8 → 16 px) or use hencSelectObj with a rectangle.
Related API
Section titled “Related API”- Lifecycle: hencInit / hencCreate / hencSelect / hencDelete / hencDeinit
- Rendering: hencSetViewport / hencClearBackground / hencRender / hencSwapBuffer
- Picking: hencPickObj / hencSelectObj / hencObjToString