目录
修改CFirstMFCApp::InitInstance()
修改CFirstMFCApp::InitInstance()(二)
修改CFirstMFCView::OnInitialUpdate()
对**WebRuntime**的技术目标而言,SDI以及基于对话框的应用程序结构并不合适,所以我们只考虑MDI(多文档)以及MDT(多顶层窗口)架构的MFC应用。本文是基础篇,是创建MFC互联网工程的入门指南,开发者只需按照指定的步骤操作即可,普通开发者完成本文的步骤应该在3-5分钟左右的时间。
创建MFC工程
开发环境
我们建议的开发环境是Visual Studio 2019。
准备工作
下载 (点击)WebRuntime运行时支撑包, 下载之后,将二进制包解压缩,找到MFCPlus子文件夹。
创建一个MDI或者MDT类型的MFC工程
为了行文方便,我们预设工程的名字为FirstMFCApp,是MDI类型的MDI工程:
(创建新MFC工程)
工程的App类为CFirstMFCApp:
(App类:CFirstMFCApp)
工程的View类为 CFirstMFCView:
(工程的View类:CFirstMFCView,是一个CFormView类)
其他方面都是默认的选项。
复制MFCPlus文件夹
将**MFCPlus**文件夹复制到刚刚生成的工程文件夹,这一步替换了新工程的pch,h以及pch.cpp文件,事实上相当于在已有的pch,h以及pch.cpp文件之中分别添加
#include "WebRuntimeApp.h"
(pch,h中增加如上一行代码)
以及
#include "WebRuntimeApp.cpp"
(pch,cpp中增加如上一行代码)
复制工作相当于给所创建的MFC工程同时增加了一组C++源文件以及一个mfcapp.manifest文件。
修改App类的基类
将CFirstMFCApp的基类修改为CWebRuntimeApp:
class CFirstMFCApp : public CWebRuntimeApp
修改 CMainFrame类的基类(MDT工程没有这一步)
将CMainFrame的基类修改为:
class CMainFrame : public CWebMDIFrameWnd
同时在MainFrm.cpp文件中修改如下部分:
IMPLEMENT_DYNAMIC(CMainFrame, CWebMDIFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CWebMDIFrameWnd)
(注意以上宏之中的CWebMDIFrameWnd部分)
修改CFirstMFCApp::InitInstance()
这一步MDI、MDT工程类型都需要。在这个函数开始部分增加如下代码:
BOOL CFirstMFCApp::InitInstance()
{
m_mapDOMObj[_T("main_panel")] = RUNTIME_CLASS(CFirstMFCView);
if (!InitApp())
return false;
// InitCommonControlsEx() is required on Windows XP if an application
注意如下一行:
m_mapDOMObj[_T("main_panel")] = RUNTIME_CLASS(CFirstMFCView);
事实上这里建立了一个字符串与CView类之间的一个“映射”,可以包含多个类似的行,这个映射为以后扩展Web DOM奠定基础,也就是说,每一个映射里面的“字符串名字”,将体现为一个新的Web页面元素类型。
这里添加的代码对MDI、MDT工程类型都需要。如果您创建的工程是MDT类型的工程,需要在CFirstMFCApp::InitInstance()函数体之中将如下代码块删除:
// create main MDI Frame window
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))
{
delete pMainFrame;
return FALSE;
}
m_pMainWnd = pMainFrame;
// call DragAcceptFiles only if there's a suffix
// In an MDI app, this should occur immediately after setting m_pMainWnd
// Enable drag/drop open
m_pMainWnd->DragAcceptFiles();
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Enable DDE Execute open
EnableShellOpen();
RegisterShellFileTypes(TRUE);
// Dispatch commands specified on the command line. Will return FALSE if
// app was launched with /RegServer, /Register, /Unregserver or /Unregister.
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The main window has been initialized, so show and update it
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
(MDT工程之中,如上的代码块直接删除)
相当于执行完
m_pDocTemplate = pDocTemplate;
AddDocTemplate(pDocTemplate);
函数直接返回“TRUE”。
修改CFirstMFCApp::InitInstance()(二)
如果创建的是MDI工程,那么需要在CFirstMFCApp::InitInstance()中找到如下一行代码:
EnableTaskbarInteraction();
将这一行替换为如下代码块:
EnableTaskbarInteraction();
return TRUE;
}
BOOL CFirstMFCApp::CreateCosmosApp(CWebPageImpl* pWebPageImpl, CBrowserImpl* pBrowserImpl, CString strObjID, CString strAppData)
{
替换之后,CFirstMFCApp::InitInstance()被分裂成两个函数,需要在CFirstMFCApp的类之中声明一个“虚函数”:
class CFirstMFCApp : public CWebRuntimeApp
{
public:
CMFCApp() noexcept;
// Overrides
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
// Implementation
UINT m_nAppLook;
BOOL m_bHiColorIcons;
virtual void PreLoadState();
virtual void LoadCustomState();
virtual void SaveCustomState();
//针对MDI类型的应用,需要重载CWebRuntimeApp的虚函数:
virtual BOOL CreateCosmosApp
(
CWebPageImpl* pWebPageImpl,
CBrowserImpl* pBrowserImpl,
CString strObjID,
CString strAppData
);
afx_msg void OnAppAbout();
DECLARE_MESSAGE_MAP()
};
(注意增加的函数:CreateCosmosApp,
这个函数由CWebRuntimeApp提供,这里重载)
修改CFirstMFCView::OnInitialUpdate()
由于CFirstMFCView是CFormView,其OnInitialUpdate()需要如下修改:
void CMFCApplication1View::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
//以下代码只针对CFormView派生类:
if (m_pDocument)
{
theApp.SetFrameInfo(m_hWnd);
}
}
文档序列化支持
按照如下代码重载序列化支持函数:
// CFirstMFCAppDoc serialization
void CFirstMFCAppDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << theApp.GetDocTemplateID(this);
// TODO: add storing code here
}
else
{
ar >> theApp.m_strCreatingDOCID;
// TODO: add loading code here
}
}
打开资源面板,修改ID为“IDR_FirstMFCAppTYPE”的“字符串表资源”:
修改后字符串值如下:这里“*.xxx”为MFC程序支持的文档的扩展名(由于Visual Studio 应用程序向导的Bug,生成的资源有问题)
FirstMFCApp\nFirstMFCApp\nFirstMFCApp\nFirstMFCApp files\n.xxx\nFirstMFCApp.Document\nFirstMFCApp.Document
到现在为止我们完成了MFC工程支持WebRuntime的代码修改部分。
修改工程的Manifest配置
由于需要支持现代浏览器的全部功能,需要修改工程的Manifest配置,有如下两个方法。
方法一:
打开工程配置,直接修改Debug、Release模式的Manifest配置,其中MfcApp.manifest文件由**MFCPlus**提供,需要复制到创建工程的源文件文件夹:
(修改Debug、Release编译模式的manifest配置)
方法二:
可以导入工程的属性表文件MFCApp.props,步骤如下:
第一步:按如下图操作打开工程的属性管理工具箱:
第二步:在属性管理工具箱之中选择目标工程,右键操作鼠标打开快捷菜单,选择添加已存在的工程属性项:
第三步:选择MfcApp.props,完成操作。
完成以上步骤之后,我们完成了支持**WebRuntime**的全部工作。
已有MFC工程的迁移
对已存在的MFC工程(MDI、MDT类型的工程,其他类型的可以联系我们),由于设计者的很多MFC类对象是自己定义的,所以其基础类环节与我们这里的示范有一些差异,开发者可以按照如上步骤,依据自己的设计思路做适当调整,即可完整支持**WebRuntime**。
可供参考的迁移步骤如下(对新创建的工程依然适用):
-
将App类的基类由“CWinAppEx”替换为“CWebRuntimeApp”,对MDI应用类型,在工程级别,将“CMDIFrameWndEx”替换为“CWebMDIFrameWnd”,如下图所示:
-
参考本文之中针对InitInstance()的修改部分修改目标工程App类的InitInstance()函数;
-
按照本文之中介绍MFCPlus的部分将必要的代码复制到目标工程的源文件文件夹;
-
按照本文介绍的方式处理CFormView的派生类(重载OnInitialUpdate函数);
-
按照本文介绍的方式处理文档序列化。
-
按照本文介绍的方式调整目标工程的Manifest配置;
以上步骤当然也适合新创建的MFC工程。
编译您的代码
将创建的工程编译,注意我们只支持x64编译,也就是说,我们只支持64位Windows应用。将**WebRuntime二进制包**复制到编译之后的输出目录,即exe文件所在的文件夹。关于如何运行编译之后的程序,我们会在其他博文之中详细的解释,这里只介绍如何创建、迁移这类工程。
Sample
WebRuntime源代码之中,包含两个例子****,一个是MFCApplication1(MDI),另外一个是TheUniverse(MDT),开发者可以看例子源代码,在二进制包里面包含例子的编译版本以及相关的Web页面,可以直接运行。
技术支持
有问题的朋友,可以微信联系: