众所周知,MFC提供了一个非常强大的,但是又不太容易理解的编程模型叫做文档/视图结构。它的基本思想就是将数据的表现和数据的存在分开管理。MFC提供了很多现在的类来达成这个目标,通常,利用CFrameWnd,CView和CDocument这三个类,再利用CSingleDocTemplate的魔法将它们串联起来,就可以很容易的构建出一个单文档的Doc/View应用程序。
但是,随着互联网的发展,一切东西都跃然于网络上。我们能不能将文档/视图结构的应用程序做成一个酷酷的,可以用于网络发布的应用程序呢。比如说我们可以通过浏览器操作该应用程序。上面的框架界面嵌入到浏览器当中。嗯,一个很好的选择就是将该应用程序打造成ActiveX控件。下面开始介绍该魔法产生的过程:
首先,我们要考虑到该ActiveX控件可以会显示在Html页上做为浏览器的一个子窗口。而如果使用传统的CDocTemplate类将文档,视图相联系,则每当产生一个新的框架时,都会弹出一个具有框架窗口,达不到内嵌的目的,所以,改造CDocTemplate类是必须的。其中关键的几点是:
1、考虑到要嵌在OleControl当中,所以新产生的框架窗口将要以该OleControl作为父窗口。
2、考虑到作为内嵌的子窗口,而子窗口是不能具有菜单的,因此该控件不具有菜单。但是可以用下拉菜单来加以代替,当然,工具条也是可以的。
3、除了菜单外,大部分Doc/View的功能都将要保留。
第一步:我们从CSingleDocTemplate派生一个类,叫做CActiveDocTemplate.其中关键是要修改二个函数:CreateNewFrame和OpenDocumentFile函数。使得每当创那一个新的框架时,都会以外围的OleControl窗口作为父窗口。这两个函数改变如下:
CDocument* CActiveXDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bVerifyExists) {
SaveDocumentFile(); //保存当前文档
m_docFile=lpszPathName;
if(bVerifyExists) {
DWORD dwAttrib=GetFileAttributes(lpszPathName); //得到文档类型
if(dwAttrib==0xFFFFFFFF||
dwAttrib==FILE_ATTRIBUTE_DIRECTORY) //如果是目录的话
{
lpszPathName=NULL;
}
}
return CSingleDocTemplate::OpenDocumentFile(lpszPathName,TRUE);
}
CFrameWnd* CActiveXDocTemplate::CreateNewFrame(CDocument* pDoc,CFrameWnd* pOther) {
ASSERT(pOther==NULL);
ASSERT(m_pFrameClass!=NULL);
if(pDoc!=NULL)
ASSERT_VALID(pDoc); //检查对象的有效性
//创建一个框架和相应的文档连接起来
CCreateContext context;
context.m_pCurrentFrame=pOther;
context.m_pCurrentDoc=pDoc;
context.m_pNewViewClass=m_pViewClass;
context.m_pNewDocTemplate=this;
m_pFrameWnd=(CFrameWnd*)m_pFrameClass->CreateObject();
if(m_pFrameWnd==NULL) {
TRACE1("Warning: Dynamic create of frame %hs failed./n",
m_pFrameClass->m_lpszClassName);
return NULL;
}
ASSERT_KINDOF(CFrameWnd,m_pFrameWnd);
if(context.m_pNewViewClass==NULL)
TRACE0("Warning: creating frame with no default view./n");
ASSERT_KINDOF(CActiveXDocControl,m_pParentWnd);
if(!m_pFrameWnd->Create(NULL,"",WS_CHILD|WS_VISIBLE,CFrameWnd::rectDefault,m_pParentWnd,NULL,0,&context)) {
TRACE0("Warning: CDocTemplate couldn't create a frame./n");
return NULL;
}
return m_pFrameWnd;
}
第二步:从COleControl类派生一个CActiveXDocControl类,以改造COleControl类,使之在包含一个指向CActiveDocTemplate的指针。利用该指针,我们可以创建框架窗口,保存文档内容,以完成常规Doc/View应用程序应完成的功能。下面是改造后的CActiveXDocControl头文件的内容:
class CActiveXDocControl:public COleControl {
enum {WM_IDLEUPDATECMDUI=0x0363};
static BOOL m_bDocInitialized;
CActiveXDocTemplate* m_pDocTemplate;
CFrameWnd* m_pFrameWnd;
// SetInitialSize(100,100);
DECLARE_DYNAMIC(CActiveXDocControl)
protected:
void AddDocTemplate(CActiveXDocTemplate* pDocTemplate);
CDocTemplate* GetDocTemplate() {return m_pDocTemplate;}
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType,int cx,int cy);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnDestroy();
DECLARE_MESSAGE_MAP();
DECLARE_DISPATCH_MAP();
DECLARE_EVENT_MAP();
public:
CActiveXDocControl();
virtual ~CActiveXDocControl();
enum {
};
};
并且在控件类的构造函数中加入DocTemplate:
AddDocTemplate(new CActiveXDocTemplate(
RUNTIME_CLASS(CMy55Doc),
RUNTIME_CLASS(CMy55Frame),
RUNTIME_CLASS(CMy55View)
));
至此,基本框架都已经建立完成,剩下的步骤就是打造Doc/View应用程序了。
通过这几部,我们可以很容易的把现有的文档/视图结构的应用程序改造成可以在浏览器上显示的ActiveX控件。使得现有程序的功能大部分都保留下来,并且可以在网上进行发布,使得用户可以通过浏览器访问并且使用它。
下面是将上面的文档/视图应用程序改造后在浏览器中运行并操作的界面:
本文参考了msdn 上的Designing ActiveX Components with the MFC Document/View Model。