在 VC6 和其他 VS 版本中使用富文本编辑控件 5.0 的一种非常简单的方法
一个关于使用富文本编辑控件 5.0 的好技巧。
引言
Microsoft VC++ 6.0 只能构建使用 MFC 4.2 的富文本编辑控件 1.0 应用程序。我的朋友们总是问我如何在 VC6 项目中使用富文本编辑控件 2.0 或其他版本的富文本编辑控件。因此,这篇文章只是我尝试与大家分享信息的一点努力,可能对大家有所帮助。:)
本文将向您展示如何**直接**使用富文本编辑控件 v4.1(在 msftedit.dll 中为 RICHEDIT50W
)。
文章中所示方法的另一个优点是,我们可以获得基于富文本编辑控件 v4.1 的功能齐全的 CRichEditView
,而不仅仅是创建一个只包含**文本**功能的富文本编辑控件 v4.1。因为我们仍然使用 MFC,我们只是将基础富文本编辑控件从 1.0 替换为 4.1。因此,我们仍然可以从剪贴板 Ctrl+V 一个位图到我们的 CRichEditView
,仍然可以插入一个对象并使用 MFC 成员函数添加一些超链接文本。
背景
既然 Windows(R) 已经升级到版本 6.1,为什么我们只使用富文本编辑控件 1.0 或 2.0 呢?嗯……这里有一些可以让您**直接**使用富文本编辑控件 4.1(msftedit.dll)的方法。
原理
因为我们的 CMyAppView
是从 CRichEditView
派生的,所以我们可以在 VIEWRICH.CPP 中看到以下语句
CRichEditView::CRichEditView():
CCtrlView(_T("RICHEDIT"), //MFC hard-coded the ClassName ....
//here is the Key.
//Our goal is to REPLACE "RICHEDIT"
//to "RichEdit50W". And we can do this in our
//View Class' Constructor. You can get those
//codes under this segment :)
AFX_WS_DEFAULT_VIEW |
WS_HSCROLL | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL |
ES_MULTILINE | ES_NOHIDESEL | ES_SAVESEL | ES_SELECTIONBAR)
{
m_bSyncCharFormat = m_bSyncParaFormat = TRUE;
m_lpRichEditOle = NULL;
...
}
让我们深入了解一下。MFC 源代码告诉我们,CRichEditView
是从 CCtrlView
派生的,在 VIEWCORE.CPP 中,在 CCtrlView
的构造函数中,我们可以看到 CCtrlView
将类名“RICHEDIT
”从 CRichEditView
保存到 m_strClass
中,然后在 PreCreateWindow()
和 Create()
函数中使用这个成员 var
。代码如下所示
CCtrlView::CCtrlView(LPCTSTR lpszClass, DWORD dwStyle)
{
m_strClass = lpszClass;
//here, MFC save the ClassName given by
//CRichEditView's Constructor
m_dwDefaultStyle = dwStyle;
}
BOOL CCtrlView::PreCreateWindow(CREATESTRUCT& cs)
{
ASSERT(cs.lpszClass == NULL);
cs.lpszClass = m_strClass;//CCtrlView apply the ClassName to a
CREATESTRUCT here
...
return CView::PreCreateWindow(cs);
}
如我们所知,每个窗口最终都是由 CreateWindowEx()
API 创建的。'CREATESTRUCT& cs
' 只是从 CWnd::CreateEx()
传递过来的,用于告诉系统如何创建一个窗口。
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
// allow modification of several common create parameters
CREATESTRUCT cs;
cs.dwExStyle = dwExStyle;
cs.lpszClass = lpszClassName;
cs.lpszName = lpszWindowName;
cs.style = dwStyle;
cs.x = x;
cs.y = y;
cs.cx = nWidth;
cs.cy = nHeight;
cs.hwndParent = hWndParent;
cs.hMenu = nIDorHMenu;
cs.hInstance = AfxGetInstanceHandle();
cs.lpCreateParams = lpParam;
if (!PreCreateWindow(cs))//CCtrlView::PreCreateWindow() will be called here,
//and our New ClassName "RichEdit50W" has been already in cs
{
PostNcDestroy();
return FALSE;
}
AfxHookWindowCreate(this);
HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
// Our RichEdit v4.1(RICHEDIT50W) Ctrl
// has been created successfully!
...
}
如何使用这段代码?
这是一个由 MFC App Wiz 生成的非常典型的项目。CMyAppView
是从 CRichEditView
派生的视图类。
class CMyAppView : public CRichEditView
{
...
}
有两步。首先,将 'm_strClass=TEXT("RichEdit50W");
' 放入 CMyAppView
的构造函数中。它应该如下所示
CMyAppView::CMyAppView()
{
m_strClass=TEXT("RichEdit50W");
//Must be m_strClass, it is a member of CCtrlView
...
}
然后,将 'LoadLibrary(TEXT("msftedit.dll"));
' 放入 CMyApp
类的构造函数中。并且,必须初始化 OLE。完成后,它应该如下所示
CMyApp::CMyApp()
{
CoInitialize(NULL); //this must be called FIRST!
//m_hinstRE41 is a HINSTANCE type member var of CMyApp
m_hinstRE41=LoadLibrary(TEXT("msftedit.dll"));
//this DLL must be loaded.
...
}
CMyApp::~CMyApp()
{
if(m_hinstRE41)
FreeLibrary(m_hinstRE41);
}
CMyApp::InitInstance()
{
AfxOleInit(); //you don't want to miss this ....
AfxEnableControlContainer(); //and this ....
...
}
另一个重要提示
在 CMyAppView::OnDestroy
中,您应该看到
void CGreatTracerView::OnDestroy()
{
//CRichEditView::OnDestroy(); <------the MFC App Wiz put the codes here,
// but it shouldn't.
// Deactivate the item on destruction; this is important
// when a splitter view is being used.
COleClientItem* pActiveItem = GetDocument()->
GetInPlaceActiveItem(this); //If OnDestroy() were still up there,
//the app would CRASH here!
if (pActiveItem != NULL && pActiveItem->GetActiveView() == this)
{
pActiveItem->Deactivate();
ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
}
CRichEditView::OnDestroy();
// this codes should be here, so, everything is fine!
}
顺便说一下,我真的建议以 Unicode 方式构建项目。:)
历史
- 2010.2.6:第一个版本 - 1.0。
- 2010.2.7:版本 1.1 - 添加了更多介绍和原理部分。
- 2010.2.23:版本 1.2 - 纠正了版本错误;msftedit.dll 包含富文本编辑控件 v4.1(类名为
RICHEDIT50W
),而不是 v5.0。