友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
深入浅出MFC第2版(PDF格式)-第98部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
#0036 //{{AFX_MSG_MAP(CNewDoc)
#0037 // NOTE the ClassWizard will add and remove mapping macros here。
#0038 //}}AFX_MSG_MAP
#0039 END_MESSAGE_MAP()
#0040
#0041 /////////////////////////////////////////////////////////////////
#0042 // CNewDoc diagnostics
#0043
#0044 #ifdef _DEBUG
#0045 void CNewDoc::AssertValid() const
#0046 {
#0047 CDocument::AssertValid();
#0048 }
#0049
#0050 void CNewDoc::Dump(CDumpContext& dc) const
#0051 {
#0052 CDocument::Dump(dc);
#0053 }
#0054 #endif //_DEBUG
#0055
#0056 /////////////////////////////////////////////////////////////////
#0057 // CNewDoc serialization
#0058
#0059 void CNewDoc::Serialize(CArchive& ar)
#0060 {
#0061 if (ar。IsStoring())
#0062 {
738
…………………………………………………………Page 801……………………………………………………………
第 13 章 多重文件與多重顯示
#0063 // TODO: add storing code here
#0064 }
#0065 else
#0066 {
#0067 // TODO: add loading code here
#0068 }
#0069
#0070 // CEditView contains an edit control which handles all serialization
#0071 ((CEditView*)m_viewList。GetHead())…》SerializeRaw(ar);
#0072 }
#0073
#0074 //////////////////////////////////////////////////////////////
#0075 // CNewDoc mands
注:阴影中的这两行码(#0070 和#0071)不是ClassWizard 产生的,是我自己加的,提前与
你见面。稍后我会解释为什么加这两行。
新的 Document Template
然后,我应该为此新的文件类型产生一个Document Template,并把它加到系统所维护的
DocTemplate 串行中。注意,为了享受现成的文字编辑能力,我选择CEditView 做为与
此Document 搭配之View 类别。还有,由于CChildFrame 已经因为第一个文件类型
Graph 的三叉静态分裂而被我们改写了OnCreateClient 函数,已不再适用于这第二个文
件类型(NewDoc ),所以我决定直接采用CMDIChildWnd 做为NewDoc 文件类型的MDI
Child Frame 窗口:
#include 〃stdafx。h〃
#include 〃Graph。h〃
#include 〃MainFrm。h〃
#include 〃ChildFrm。h〃
#include 〃GraphDoc。h〃
#include 〃GraphView。h〃
#include 〃NewDoc。h〃
。。。
BOOL CGraphApp::InitInstance()
{
。。。
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_GRAPHTYPE;
RUNTIME_CLASS(CGraphDoc);
RUNTIME_CLASS(CChildFrame); // custom MDI child frame
739
…………………………………………………………Page 802……………………………………………………………
第篇 深入 MFC 程式設計
RUNTIME_CLASS(CGraphView));
AddDocTemplate(pDocTemplate);
pDocTemplate = new CMultiDocTemplate(
IDR_NEWTYPE;
RUNTIME_CLASS(CNewDoc);
RUNTIME_CLASS(CMDIChildWnd); // use directly
RUNTIME_CLASS(CEditView));
AddDocTemplate(pDocTemplate);
。。。
}
CMultiDocTemplate 的第一个参数(resource ID )也不能再延用Graph 文件类型所使用的
IDR_GRAPHTYPE 了。要知道,这个ID 值关系非常重大。我们得自行设计一套适用于
NewDoc 文件类型的UI 系统出来(包括菜单、工具栏、文件存取对话框的内容、文件
图标、窗口标题。。。)。
怎么做?第7章的深入讨论将在此开花结果!请务必回头复习复习「Document Template
的意义」一节,我将直接动作,不再多做说明。
新的 UI 系统
下面就是为了这新的 NewDoc 文件型态所对应的 UI 系统,新添的文件內容 (没有什么
好工具可以帮忙,一般文字编辑器的 copy/paste 最快):
// in RESOURCE。H
#define IDD_ABOUTBOX 100
#define IDR_MAINFRAME 128
#define IDR_GRAPHTYPE 129
#define IDR_NEWTYPE 130
。。。
// in GRAPH。RC
IDR NEWTYPE ICON
_ DISCARDABLE 〃resNewDoc。ico〃 // 此icon 需自行备妥
IDR NEWTYPE MENU
_ PRELOAD DISCARDABLE
BEGIN
POPUP 〃&File〃
BEGIN
740
…………………………………………………………Page 803……………………………………………………………
第 13 章 多重文件與多重顯示
MENUITEM 〃&NewtCtrl+N〃; ID_FILE_NEW
MENUITEM 〃&Open。。。tCtrl+O〃; ID_FILE_OPEN
MENUITEM 〃&Close〃; ID_FILE_CLOSE
MENUITEM 〃&SavetCtrl+S〃; ID_FILE_SAVE
MENUITEM 〃Save &As。。。〃; ID_FILE_SAVE_AS
MENUITEM SEPARATOR
MENUITEM 〃&Print。。。tCtrl+P〃; ID_FILE_PRINT
MENUITEM 〃Print Pre&view〃; ID_FILE_PRINT_PREVIEW
MENUITEM 〃P&rint Setup。。。〃; ID_FILE_PRINT_SETUP
MENUITEM SEPARATOR
MENUITEM 〃Recent File〃; ID_FILE_MRU_FILE1; GRAYED
MENUITEM SEPARATOR
MENUITEM 〃E&xit〃; ID_APP_EXIT
END
POPUP 〃&Edit〃
BEGIN
MENUITEM 〃&UndotCtrl+Z〃; ID_EDIT_UNDO
MENUITEM SEPARATOR
MENUITEM 〃Cu&ttCtrl+X〃; ID_EDIT_CUT
MENUITEM 〃&CopytCtrl+C〃; ID_EDIT_COPY
MENUITEM 〃&PastetCtrl+V〃; ID_EDIT_PASTE
END
POPUP 〃&View〃
BEGIN
MENUITEM 〃&Toolbar〃; ID_VIEW_TOOLBAR
MENUITEM 〃&Status Bar〃; ID_VIEW_STATUS_BAR
END
POPUP 〃&Window〃
BEGIN
MENUITEM 〃&New Window〃; ID_WINDOW_NEW
MENUITEM 〃&Cascade〃; ID_WINDOW_CASCADE
MENUITEM 〃&Tile〃; ID_WINDOW_TILE_HORZ
MENUITEM 〃&Arrange Icons〃; ID_WINDOW_ARRANGE
MENUITEM 〃S&plit〃; ID_WINDOW_SPLIT
END
POPUP 〃&Help〃
BEGIN
MENUITEM 〃&About Graph。。。〃; ID_APP_ABOUT
END
END
STRINGTABLE PRELOAD DISCARDABLE
BEGIN
IDR_MAINFRAME 〃Graph〃
IDR_GRAPHTYPE 〃GraphnGraphnGraphnGraph Files
(*。fig)n。FIGnGraph。DocumentnGraph Document〃
741
…………………………………………………………Page 804……………………………………………………………
第篇 深入 MFC 程式設計
IDR NEWTYPE
_ 〃NewDocnNewDocnNewDocnNewDoc Files
(*。txt)n。TXTnNewDoc。DocumentnNewDoc Document〃
END
新文件的文件读写动作
你大概还没有忘记,第7章最后曾经介绍过,当我们在AppWizard 中选择CEditView (而
不是CView)作为我们的View 类别基础时,AppWizard 会为我们在CMyDoc::Serialize
函数中放入这样的码:
void CMyDoc::Serialize(CArchive& ar)
{
// CEditView contains an edit control which handles all serialization
((CEditView*)m_viewList。GetHead())…》SerializeRaw(ar);
}
当你使用CEditView,编辑器窗口所承载的文字是放在Edit 控制组件自己的一个内存
区块中,而不是切割到Document 中。所以,文件的文件读写动作只要调用CEditView 的
SerializeRaw 函数即可。
为了这NewDoc 文件类型能够读写文件,我们也依样画葫芦地把上一段码阴影部份加到
Graph 程序新的Document 类别去:
void CNewDoc::Serialize(CArchive& ar)
{
if (ar。IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
// CEditView contains an edit control which handles all serialization
((CEditView*)m_viewList。GetHead())…》SerializeRaw(ar);
}
742
…………………………………………………………Page 805……………………………………………………………
第 13 章 多重文件與多重顯示
现在一切完备,重新编辑联结并执行。一开始,由于InitInstance 函数会自动为我们New
一个新文件,而Graph 程序不知道该New 哪一种文件类型才好,所以会给我们这样的
对话框:
往后每一次选按【File/New 】,都会出现上述对话框。
以下是我们打开Graph 文件和NewDoc 文件各一份的画面。注意,当active 窗口是
NewDoc 文件,工具栏上属于Graph 文件所用的最后三个按钮是不起作用的:
743
…………………………………………………………Page 806……………………………………………………………
第篇 深入 MFC 程式設計
以下是【Open 】对话框(用来开档)。注意,文件有。fig 和。txt 和*。* 三种选择:
这个新的Graph 版本放在书附光盘片的GRAPH2。13 目录中。
744
…………………………………………………………Page 807……………………………………………………………
14 MFC
第 章 多緒程式設計
14
第 章
MFC 多线程程序设计
Multi…threaded Programming in MFC
线程(thread ),是执行线程(thread of execution )的简单称呼。〃Thread〃 这个字的原意是「线」。
中文字里头的「线程」也有「线」的意思,所以我采用「线程」、「执行线程」这样的中文名
称。如果你曾经看过「多线」这个名词,其实就是本章所谓的「多线程」。
我曾经在第1章以三两个小节介绍Win32 环境下的进程与执行线程观念,并且以程序直接
调用CreateThread 的形式,示范了几个Win32 小例子。现在我要更进一步从操作系统
的层面谈谈执行线程的学理基础,然后带引各位看看MFC 对于「执行线程」支持了什么样
的类别。然后,实际写个MFC 多线程程序。
从操作系统层面看执行线程
书籍推荐:如果要从操作系统层面来了解执行线程,Matt Pietrek 的Windows 95 System
Programming SECRETS (Windows 95 系统程序设计大奥秘/侯俊杰译/旗标出版)无疑是
最佳知识来源。Matt 把操作系统核心模块(KERNEL32。DLL )中用来维护执行线程生存的
数据结构都挖掘出来,非常详尽。这是对执行线程的最基础认识,直达其灵魂深处。
745
…………………………………………………………Page 808……………………………………………………………
第篇 深入 MFC 程式設計
你已经知道,CreateThread 可以产生一个执行线程,而「线程」的本体就是CreateThread 第
3个参数所指定的一个函数(一般我们称之为「执行线程函数」)。这个函数将与目前的
「执行事实」同时并行,成为另一个「执行事实」。执行线程函数的执行期,也就是该执
行线程的生命期。
操作系统如何造成这种多任务并行的现象?执行线程对于操作系统的意义到底是什么?系统
如何维护许多个执行线程?执行线程与其父亲大人(进程)的关系如何维持?CPU 只有一
个,执行线程却有好几个,如何摆平优先权与排程问题?这些疑问都可以在下面各节中获
得答案。
三个观念:模块、进程、执行线程
试着回答这个问题:进程(process )是什么?给你一分钟时间。
z z z z z。。。
你的回答可能是:『一个可执行档执行起来,就是一个进程』。唔,也不能算错。但能
不能够有更具体的答案?再问你一个问题:模块(module )是什么?可能你的回答还是:
『一个可执行档执行起来,就是一个模块』。这也不能够算错。但是你明明知道,模块
不等于进程。KERNEL32 DLL 是一个模块,但不是一个进程;Scribble EXE 是一个模块,
也是一个进程。
我们需要更具体的资料,更精准的答案。
如果我们能够知道操作系统如何看待模块和进程,就能够给出具体的答案了。一段可执
行的程序(包括EXE 和DLL ),其程序代码、资料、资源被加载到内存中,由系统建
置一个数据结构来管理它,就是一个模块。这里所说的数据结构,名为Module Database
(MDB ),其实就是PE 格式中的PE 表头,你可以从WINNT。H 档中找到一个
IMAGE_NT_HEADER 结构,就是它。
746
…………………………………………………………Page 809……………………………………………………………
14 MFC
第 章 多緒程式設計
好,解释了模块,那么进程是什么?这就比较抽象一点了。这样说,进程就是一大堆拥
有权(ownership )的集合。进程拥有地址空间(由memory context 决定)、动态配置而
来的内存、文件、执行线程、一系列的模块。操作系统使用一个所谓的Process Database
(PDB )数据结构,来记录(管理)它所拥有的一切。
执行线程呢?执行线程是什么?进程主要表达「拥有权」的观念,执行线程则主要表达模块中
的程序代码的「执行事实」。系统也是以一个特定的数据结构(Thread Database,TDB )记
录执行线程的所有相关资料,包括执行线程区域储存空间(Thread Local Storage ,TLS )、讯
息队列、handle 表格、地址空间(Memory Context )等等等。
最初,进程是以一个执行线程(称为主执行线程,primary thread )做为开始。如果需要,行
程可以产生更多的执行线程(利用CreateThread),让CPU 在同一时间执行不同段落的
码。当然,我们都知道,在只有一颗CPU 的情况下,不可能真正有多任务的情况发生,
「多个执行线程同时工作」的幻觉主要是
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!