We use Scintilla in MFC (why does everyone always talk about legacy projects when mentioning MFC). We have the Scintilla code in a DLL and then wrap Scintilla in class:
class DllClass CSciCtrl : public CWnd
{
DECLARE_DYNAMIC(CSciCtrl);
private:
static SciFnDirect m_pSciDirect;
static HMODULE m_hModScintilla;
HWND m_hWndScintilla;
sptr_t m_pSciData;
sptr_t SciCall(unsigned int iMessage, uptr_t wParam=0, sptr_t lParam=0) const
{
return m_pSciData ? m_pSciDirect(m_pSciData, iMessage, wParam, lParam) : 0;
}
sptr_t SciCallCatch(unsigned int iMessage, uptr_t wParam=0, sptr_t lParam=0);
int m_nLineNumberDigits; // number of digits in line number
// Construction
public:
CSciCtrl();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSciCtrl)
public:
//}}AFX_VIRTUAL
virtual BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, DWORD dwExStyle = 0, LPVOID lpParam = nullptr);
// Implementation (non-autogenerated functions)
public:
virtual ~CSciCtrl();
static bool InitScintilla(LPCTSTR szPath = nullptr);
static void UnloadScintilla();
... lots of methods for our use, then all the scintilla messages converted to calls...
};
The create call is:
// We create our scintilla control and save the handle in the standard window handle.
// This is basically the CreateEx call with fixed args omitted and rearranged so we
// can omit commonly unused arguments.
BOOL CSciCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID,
DWORD dwExStyle, LPVOID lpParam)
{
if (!m_hModScintilla && // has user failed to initialise?
!InitScintilla()) // try default locations
return FALSE;
BOOL bOK = CreateEx(dwExStyle, _T("Scintilla"), NULL, dwStyle, rect, pParentWnd, nID, lpParam);
if (bOK) // if all was OK we can now send messages to the window
{
ASSERT(::IsWindow(m_hWnd)); // moan if we failed
m_pSciDirect = (SciFnDirect)SendMessage(SCI_GETDIRECTFUNCTION); // get address to use
m_pSciData = SendMessage(SCI_GETDIRECTPOINTER); // get our instance data pointer
#ifdef _UNICODE
// Although it is tempting to run in UTF8 mode, there will be folks out there
// who depend on MBCS so that toolbars and buttons work. Until we enable UNICODE, if
// we run in UTF8 mode, things are OK for scripts and text written to text views, but not
// OK for any text that is displayed. So defer this until full UNICODE support.
// GPS, Aug 2014.
SetCodePage(SC_CP_UTF8); // Set UTF8 mode
#endif
// Direct Write is a better text technology that is available in Vista and later. BUT...
// Screen updates happen during frame flyback so if you are forcing updates in a script, the
// updates will occur more slowly. There are race condition problems when dragging a
// text view over another, resulting in overwrites. Use SC_TECHNOLOGY_DIRECTWRITEDC
// to fix this.
#ifdef SCI_USED2D
if (AfxGetMainWnd()->SendMessage(msgPrefOptions, ePO_UseD2D, -1))
#ifdef MFC_D2DSUPPORT
EnableD2DSupport();
if (IsD2DSupportEnabled())
#endif
SetTechnology(SC_TECHNOLOGY_DIRECTWRITEDC); // attempt to set direct write
if (GetTechnology() != SC_TECHNOLOGY_DEFAULT) // if using DirectWrite
{
SetBufferedDraw(false); // probably right
SetTwoPhaseDraw(false); // remove if screen corruption
}
#endif
SetFontQuality(SC_EFF_QUALITY_LCD_OPTIMIZED); // and best quality font
SetMarginWidthN(SCMARGIN_MARKER, ScaleDPIx(16)); // Make sure margin is correct size
}
return bOK;
}
This looks very similar to what you are doing. Despite the comments, we now run all our applications that use this with _UNICODE defined and take care of the conversion between MFC CString wide characters and the UTF-8 used in scintilla in the interface methods of the class.
We have used Scintilla in this way for many years and have had very few problems. We did struggle with D2D. For this code to work well we have SCI_USED2D defined and MFC_D2DSUPPORT is not defined (or do not define SCI_USED2D.
To use this in a view, we have code like:
int CTextView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMsgView::OnCreate(lpCreateStruct) == -1)
return -1;
// Note that you MUST not attempt to use m_Edit until Create has been
// called successfully.
if (!m_Edit.Create(WS_CHILD|WS_CLIPSIBLINGS|WS_VISIBLE|WS_TABSTOP, CRect(0, 0, 100, 100), this, 0))
return -1;
...
}
We also use Scintilla controls in dialogs and so on with very similar code.
Best,
Greg Smith