What's New for MFC Developers?
By Anson Tsao and Walter Sullivan
翻译:依栏望海( [email protected] )
【译者:因为时间关系,俺在一些省略了一些细节的翻译,不过俺还是都点到了。有兴趣的朋友
可以继续做。大家可以随意转载,但请不要修改本文内任何文字。如果可以的话,转载时请用
mail通知俺。谢谢!有任何想和俺交流的更是欢迎之至!15:29 2002-1-8】
MFC和ATL已经有三年没有大的更新了。在Microsoft.NET的强大宣传下,MFC和C++开发者感到被抛弃了。
不过,不用担心——在即将到来的Visual Studio.NET中,Visual C++的开发者不仅得到一个和服务器
端开发全面而紧密的崭新的IDE,大大改良的C++编译器,MFC和ATL也得到了新的重要特性。有一个清晰
消息就是MFC依然会是在所有windows平台上,拥有众多客户程序,最好最悠久的framework。在这篇文章里,
我们将带你纵览这些可以用在您的MFC程序上的新的特性。
·使用新的MFC DLL (MFC70.DLL),不再兼容MFC42.DLL,但你的源程序依然保持兼容性(消息映射更加类
型安全,所以可能导致某些代码违例)。
·MFC和ATL更加结合紧密了,一些通用的类如CString可以同时被两个库使用。
·头文件与新的Platform SDK同步,支持2k和XP中的新UI特性,如主题(themes),manifest resources,
Active Accessibility和新的通用对话框。
·增加了不少UI的类,包括支持DHTML的对话框和支持扩展BITMAP的CImage。
·新的工具类可以在MFC和ATL中使用,比如正则表达式,计数器和安全。
·MFC应用程序有力地支持web Services。ATL服务器类编写Web Services和应用程序。
·使用新的OLE DB特性使得高效率地访问数据库从来就没有像现在这样容易。
·STL被更新
一体化MFC和ATL
能否在ATL中使用CString,或者在大型的MFC中使用ATL实现COM对象?哈,现在可以了。在MFC 7。0中
有不少的工具类可以在ATL和MFC之间共享:CString,CPoint,CRect,CSize和CImage。而且,ATL可以在
无需MFC支持的情况下使用。
CString被完全改写了,现在基于模板类CStringT<>。它支持各种字符类型(char, wchar_t, TCHAR)和
建立在CRT的基础上。你还可以在CString中自行管理内存的分配。
【译者:比如
typedef struct my_chr {
unsigned int a;
unsigned int b;
unsigned int c;
} MY_CHR;
CStringT
1<my_chr> My_Str;
2...
3】
4
5
6
7
8MFC7.0增加了一个新的字符串类叫CFixedStringT<>。这种定长字符串提供一种用户定义长度的方法,在耗尽
9内在的空间前无需额外的内存。CFixedStringT被用于基于栈的变量或联合容器中的元素时,效率非常高。
10它显著地减少了基于堆的分配。
11【译者:这里俺也糊涂了,呵呵,请各位指正。原文如下:
12CFixedStringT's are very efficient when used as stack-based variables or as keys in associative
13containers, dramatically reducing the number of heap-based allocations.
14】
15
16
17
18
19下面的例子创建一个有1024个字符的实例:
20
21
22
23
24// allocating 1024 character internal buffer
25CFixedStringT< CString, 1024 > string;
26
27
28
29
30
31
32
33新的UI特性及升级
34MFC7.0提供DHTML对话框支持,有一套DHTML编辑器类,新的图形API(GDI+),更新了对BITMAP支持(CImage),
35添加一个通用对话框包装类(CLinkCtrl),更新控件和对话框支持2k和XP,增强了ActiveX control容器和提高了
36消息映射的类型安全。让我们逐一看看吧。
37
38
39
40
41
42DHTML对话框及DHTML编辑器类
43DHTML对话框把丰富多彩的HTML用户界面带到桌面应用程序上来。现在你的桌面App拥有时髦的图形界面和一般
44web应用程序没有的爽快的交互性。MFC7.0提供了CDHtmlDialog和CMultiPageDHtmlDialog来支持DHTML。DHTML
45对话框可以从资源文件或任何有效的URL中显示HTML页面。如果你曾用过CHtmlView,就知道获取和设置HTML元素
46需要通过IHTMLDocument2对象,而且处理HTML的事件是非常痛苦的事。CDHtmlDialog极大地简化了这种交互,使
47用一套类似DDX的扩展宏和DHTML事件映射。DDX_DHtml_宏和传统的DDX_宏同样在DoDataExchange函数中使用。它
48允许获取和设置各种HTML元素的属性。例如,DDX_DHtml_CheckBox绑定复选框的值,DDX_DHtml_ElementInnerHtml
49设置和获取某个元素的HTML。绑定一个HTML元素到DDX需要这个元素有的一个'id='的属性,就像下面的代码所示:
50
51
52
53
54<html><body>
55Filename: <span id="filename"></span><br/>
56<input accesskey="r" id="readonly" type="checkbox"/>
57<u>R</u>ead-only
58</body></html>
59void CPropertiesDlg::DoDataExchange(CDataExchange* pDX) {
60CDHtmlDialog::DoDataExchange(pDX);
61//{{AFX_DATA_MAP(CPropertiesDlg)
62//}}AFX_DATA_MAP
63DDX_DHtml_ElementInnerText(pDX, _T("filename"), m_strFileName);
64DDX_DHtml_CheckBox(pDX, _T("readonly"), m_nReadOnly); }
65To respond to HTML control events, you have to define a DHTML event map:
66
67
68
69
70BEGIN_DHTML_EVENT_MAP(CDHtmlExploreDlg)
71DHTML_EVENT_ONCLICK(_T("browse"), OnBrowse)
72DHTML_EVENT_CLASS(DISPID_HTMLELEMENTEVENTS_ONMOUSEOVER,
73T("hotElement"), OnMouseOverElement)
74END_DHTML_EVENT_MAP()
75
76
77
78
79
80这些事件映射类似MFC的样式,包括DECLARE_DHTML_EVENT_MAP的定义和在BEGIN_DHTML_EVENT_MAP与END_DHTML_EVENT_MAP
81之间的定义。
82CMultiPageDHtmlDialog适合导向和属性页有关的对话框。它可以在一个对话框中装载多个页面并且使用内在事件映射
83响应事件。
84这个新版本还提供了所见即所得(WYSIWYG)的DHTML编辑器。这意味着在你的程序中调整一个HTML元素并不比调整
85一个文本控件困难。类似MFC6.0对于rich edit控件的支持,MFC7.0提供了CHtmlEditCtrl,还有类似的文档视图
86类:CHtmlEditView/CHtmlEditDoc。但你仍然需要自行调整UI元素,如字体、风格、颜色、等等。
87
88
89
90
91
92GDI+
93GDI+ 是一个新的图形子系统,提供一整套图形API渲染2D图象,图片和文字。它是.NET中唯一的API,但在C++中,
94它补充了GDI的渲染能力。
95通过GDI+可以获得:更强的2D制图,alpha通道支持,通用坐标转换和浮点支持,还有渐变笔刷,cardinal splines,
96scalable regions和新的编程模式。
97GDI+以C风格的API形式发布,虽然一套C++类将其包装,但不被MFC支持而是在.NET中使用。使用GDI+,使用gdiplus.h
98并且链接gdiplus.lib。还必须在使用前初始化这个库。GDI+是XP的一部分,如要在98、me、nt4.0和2k上使用就要拷贝
99GdiPlus.DLL到相应的目录。
100GDI+使用了与GDI不同的编程模型。在GDI+中必须在每次画图命令中传入笔或刷子。图形元素不在和笔与栓子一起工作;
101勾勒边框和填充被分开成不同的函数来实现(如DrawRectangle和FillRectangle)。下面的例子演示画一个矩形
102(3.5 英寸 × 4.4 英寸)。
103
104
105
106
107
108using namespace Gdiplus;
109void CMyView::OnDraw( CDC* theDC )
110{
111Graphics graphics( *theDC );
112Pen pen( Color( 128, 255, 0, 0 ), 2.0 ); // Alpha value set
113// Realworld units
114graphics.SetPageUnit( UnitInch );
115// Floating point coordinates
116graphics.DrawRectangle( &pen, RectF( 0.0F, 0.0F, 3.5F, 4.4F ));
117}
118
119
120
121
122
123用CImage管理Bitmap
124期待已久的Bitmap支持终于在这个版本实现了。CImage可以读取和存储JPEG、GIF、BMP和PNG格式的图形文档。
125但是一些函数不被旧系统支持(如95),还有一些函数在不同的os上的具体实现不一样。CImage可以在MFC和
126ATL中使用。它也包装了DIB的功能,可以直接操作象素点。让我们来看看CImage提供了什么吧:
127
128
129
130
131·Alpha象素点混和透明和半透明效果
132
133
134
135
136·PlgBlt可以随意的映射一个矩形到一个并行四边形
137
138
139
140
141·TransparentBlt可以根据一种指定的颜色进行透明操作
142
143
144
145
146·MaskBlt可以混和两张图片到一个输出设备上
147
148
149
150
151·CImage::GetDC可以直接向一幅bitmap画图。
152
153
154
155
156下面给出一个例子:
157
158
159
160
161CImage image;
162Image.Load( "test.gif" );
163CBitmap* pBitmap = CBitmap::FromHandle( image.m_hBitmap );
164
165
166
167
168
169CLinkCtrl通用对话框类
170CLinkCtrl包装了SYSLINK控件,可以轻松地在windows上放置超链接,但只在XP上使用。它支持一个或多个
171超链接,你可以在OnNotify中处理NM_CLICK和NM_RETURN消息响应点击事件。
172
173
174
175
176
177对2k和XP的支持
178所有的通用控件,CCheckListbox,文件处理和打印都被更新以支持2k和XP。CWnd的方法也被更新以支持
179新的特性如分层窗口(layered windows)和活动窗口(animated windows)。CListView在XP中支持平铺风格。
180MFC7.0支持XP的主题(themes)。
181CWnd现在支持Active Accessibility。
182新的CPrintDialogEx更新了打印对话框。
183
184
185
186
187
188增强的ActiveX容器
189MFC7.0和ATL支持无窗口的ActiveX,并且容器可以被改写。现在MFC也享受和Visual Basic一样的容器优化。
190现在你可以改写COleControlSite以增加属于自己的容器行为。
191
192
193
194
195
196类型安全的消息映射
197MFC7.0加强了对消息处理函数返回值的校验。比如在OK中返回void而不是LRESULT的话,编译器会认为是一个
198错误。
199
200
201
202
203
204应有尽有的工具类
205新的工具类有:正则表达式类(regular expression class)、64位日期时间函数、集合模板类、安全类、
206包装CryptoAPI的函数和类、支持计数的宏和线程池支持。我们会在后面一一简要介绍。
207
208
209
210
211
212正则表达式类(regular expression class)
213这个模板类用于字符串的查询和比较,同时支持MBCS和Unicode。一共有两个模板类:CAtlRegExp和
214CAtlReMatchContext。
215下面给出一个例子:
216CAtlRegExp<> re; // using the default character trait
217re.Parse( "ab.d" );
218CAtlReMatchContext mc;
219re.Match( "abcd", &mc ); // returns TRUE, successful match
220re.Match( "bbcd", &mc ); // returns FALSE, no match
221
222
223
224
225
22664位日期时间函数
227你的代码也许不会有千年问题,但标准的C运行库会在2038年1月18号19:14:07后出错。而新的64位日期时间函数
228可以坚持到3000年12月31号。
229CTime、CTimeSpan和C运行库都被更新支持__int64数据类型,包括CTimeSpan::GetDays64,
230CTimeSpan::GetTotalHours64, CTimeSpan::GetHours64, CTimeSpan::Serialize64,
231CTime::GetTime64,和CTime::Serialize64;还有_ctime64, _wctime64, _ftime64, _futime64, _gmtime64,
232_localtime64, _time64, _utime64, _wutime64; _findfirst64, _wfindfirst64, _findnext64, _wfindnext64;
233and _stat64,和_wstat64。
234
235
236
237
238
239ATL的集合类和矩阵类
240ATL7.0提供五个新的集合类:AtlArray,CAtlList,CAtlMap,CRBMap,和CRBMultiMap。它们可以更好的支持
241非标准的数据类型。使用一些可以描述元素品质的类,这些类描述元素如何被拷贝,移动,比较清除。
242有CAutoPtrElementTraits, CAutoVectorPtrElementTraits, CComQIPtrElementTraits, CStringElementTraits,
243等等。这些ATL集合类不支持序列化。使用它们要同时指定元素类型和描述元素的品质:
244
245
246
247
248CRBMap< CString, CStringElementTraits<cstring>,
249CAutoPtr<cmyobject>, CAutoPtrElementTraits<cmyobject> >;
250这里定义了一个字典,映射CString给CMyObject的自动指针。CMyObject的元素会在集合类销毁时自动销毁。
251
252
253
254
255
256
257
258安全类
259安全类包装了NT所有的安全机制。ATL7.0包装了:
260
261
262
263
264·访问控制列表(CAcl)
265
266
267
268
269·任意访问控制列表(CDacl)
270
271
272
273
274·系统访问控制列表()
275
276
277
278
279·SID安全标识(CSid)
280
281
282
283
284·访问节点(CAccessToken)
285
286
287
288
289·访问结点组(CTokenGroups)
290
291
292
293
294·访问结点许可(CTokenPrivileges)
295
296
297
298
299·安全描述(CSecurityDesc)
300
301
302
303
304·安全属性(CSecurityAttributes)
305
306
307
308
309·一些全局函数
310
311
312
313
314不幸的是ATL 7.0不提供高级的安全模型,你仍然需要深入了解win32的安全机制。
315
316
317
318
319
320Cryptographic类
321Cryptographic类包装了win32的CryptoAPI,提供加密、解码、散列、数字签名和密匙管理。
322
323
324
325
326
327
328
329That's it! If you don't want to use C++ attributes, there are corresponding classes and macros
330that you can use instead. You should also be aware that setting counters to specific values is
331generally safe without having to worry about thread synchronization, but performing calculations
332on the counters, such as incrementing or decrementing, requires the use of atomic operations
333such as InterlockedIncrement or synchronization using critical sections.
334
335
336
337
338性能测试(Performance Counters)
339在你的程序中使用性能测试,需要实现三种类对象:性能监测管理对象,性能对象和性能测试器。
340下面演示怎样定义性能监测管理对象:
341
342
343
344
345[ perfmon( name="MyApplication", register=true )]
346class CMyApplicationPerfMon
347{
348};
349
350
351
352
353然后可以使用性能测试器:
354
355
356
357
358void SetCounter( ULONG value )
359{
360if ( g_pStatsObject )
361g_pStatsObject->SampleCounter = value;
362}
363
364
365
366
367使用它们不必担心线程同步的问题,但是测试器需要原子操作,如InterlockedIncrement或synchronization。
368
369
370
371
372
373
374
375线程池
376MFC 7.0线程池是基于NT I/O Completion Port。CThreadPool是一个支持工作线程的模板类。
377当一个线程可以工作时,你的工作线程的执行函数会被调用。工作线程的查询和执行遵循FIFO(先入先
378出)原则。使用线程池必须:
379
380
381
382
383·一次一个线程地初始化
384
385
386
387
388·逐一执行在请求队列中的线程
389
390
391
392
393·一次一个线程地销毁
394
395
396
397
398·在工作线程类中声明一个RequestType typedef,它会在执行时被处理
399
400
401
402
403RequestType是一个不透明的类型,不能大于sizeof(ULONG_PTR)(即,x86 PC上的32位),所以你不可以
404使用类的实例或大的原始类型(如浮点)。
405下面是一个示例:
406
407
408
409
410class CMyWorker
411{
412public:
413typedef CMyData* RequestType;
414BOOL Initialize( void* initParam );
415void Execute( CMyData* request, void* initParam, OVERLAPPED* pOverlapped );
416void Terminate( void* initParam );
417};
418
419
420
421
422下面是怎样在线程池初始化和查询一个任务:
423
424
425
426
427CThreadPool< CMyWorker > threadPool;
428
429threadPool.Initialize();
430threadPool.QueueRequest( new CMyData());
431threadPool.Shutdown( 1000L );
432
433
434
435
436
437Web服务,Web应用程序和Network类
438MFC7.0支持Web服务程序,编写Web服务和使用ATL服务器类编写Web应用程序。在下面的段落里,我们将
439演示访问Web服务和调用服务的方法。还将解释如何生成HTML和把它写入IStream,怎样使用HTTP客户端和
440怎样用MFC发mail。
441
442
443
444
445
446To call the methods exposed by the Web Service, simply instantiate an instance of the proxy
447class and call its methods, just like a native C++ class!
448
449
450
451
452#include "myservice.h"
453???
454MyService::CMyService service;
455HRESULT hr = Service.MyMethod( CComBSTR( L"A Parameter" ));
456
457
458
459
460在MFC中支持Web服务
461和DCOM不一样,Web服务容易透过防火墙访问,提供了一种真正的宽松的连接。使用Web服务不会比用#import
462来的困难。使用命令行程序SProxy.exe就可以生成访问Web服务的C++客户端代码。生成的proxy类包含所有
463你需要的一切。下面是个例子:
464
465
466
467
468sproxy /out:myservice.h
469http://myserver/myservice.dll?Handler=GenMyServiceWSDL
470
471
472
473
474调用Web服务的方法,你只要初始化这个proxy类并直接调用其方法即可,就像普通的C++类:
475
476
477
478
479#include "myservice.h"
480...
481MyService::CMyService service;
482HRESULT hr = Service.MyMethod( CComBSTR( L"A Parameter" ));
483
484
485
486
487
488HTML生成器
489CHtmlGen类和模板CHtmlGenBase<>支持该功能。CHtmlGen把一个完全的HTML写入IStream。使用它
490只要用一个IStream初始化之并调用相应的方法即可。
491
492
493
494
495CHtmlGen out;
496out.initialize( aStream );
497out.html();
498out.head();
499out.title( "Test HTML" );
500out.headEnd();
501out.body();
502out.a( " http://www.microsoft.com ", "Microsoft" );
503out.bodyEnd();
504out.htmlEnd();
505
506
507
508
509
510HTTP客户
511CAtlHttpClient是一个轻量级的HTTP客户类,可以发出请求并获得回应。它支持代理和各种验证
512(当前,支持Basic和NTLM)。CAtlHttpClient会同步发出请求,所以最好放置在多线程中。
513
514
515
516
517CAtlHttpClient client;
518client.Navigate( _T( http://www.microsoft.com ));
519CString contentType;
520client.GetHeaderValue(_T("Content-Type"), contentType );
521BYTE* pBody = client.GetBody();
522
523
524
525
526CBasicAuthObject和CNTLMAuthObject支持验证。下面是一个范例:
527
528
529
530
531CNTLMAuthObject ntlmAuth;
532client.AddAuthObject( _T("NTLM"), &ntlmAuth );
533
534
535
536
537
538
539
540SMTP支持MIME编码消息支持
541SMTP支持使你无需其他的mail客户端支持。CSMTPConnection直接连接一个SMTP服务器并
542发送MIME编码的mail。CMimeMessage更可以在mail上加附件、原始数据和其他MIME编码
543的消息。这个示例演示如何构造MIME消息:
544
545
546
547
548CMimeMessage message;
549message.SetSender( _T(" [email protected] " ));
550message.AddReceipient( receipient );
551message.SetSubject( _T("A test message" ));
552message.AddText( _T("This is a test message"));
553CSMTPConnection connection;
554connection.Connect( someSMTPServer );
555connection.SendMessage( message );
556
557
558
559
560
561高效地OLE DB数据库访问
562【译者:这段废话真多,总之就是比以前编程更容易了。不过,DB总是比较复杂的,短短
563的一段也说明不了什么问题。偷懒不翻译了 :)】
564
565
566
567
568
569更新的STL
570添加的hash_map,hash_multimap和hash_set类基于新的hash-table-based扩展类。
571它们类似于std::map,std::multimap和std::set,但有着非常不一样的性能特性。
572Hash-table-based比binary tree-based在查找方面快得多。和map与set不同,hash
573类不是有序的。
574新版的STL也消除了basic_string著名的多线程问题。不再使用计数器,而已严格地
575用拷贝来实现。
576最后,STL有了更好的DLL支持。再也不是本地静态数据成员了。
577
578
579
580
581
582
583
584Conclusion
585Visual Studio .NET is a giant step forward for enhancing programmer
586productivity, and the Microsoft .NET initiative will likely change the
587programming landscape in the coming years. With this release of Visual C++,
588MFC 7.0 has been updated to live in this new world of Web Services, while
589gaining better C++ standard compliance, full integration with ATL, and numerous
590enhancements to UI and utility classes. Best of all, these new features can be
591added to your existing MFC applications.
592
593
594
595
596
597总结
598MFC得到了更好地接近了C++标准,完全地和ATL结合,在UI和工具方面大大增强。
599最好的还是这些新特性可以加入到已存在的代码中。
600
601
602
603
604
605关于作者:
606
607
608
609
610Anson Tsao有12年的行业经验,从事大型的Windows和C++的开发,最近加入
611Microsoft Visual C++ Libraries小组。
612
613
614
615
616Walter Sullivan已经在Microsoft工作了11年,他的所有时间几乎都花在
617Visual C++ product小组上面。他现在领导Microsoft C++ Class Libraries
618程序管理的工作。
619
620
621
622
623About Translator
624Just a C++ fans. :) Call me Kamp. I care code performance before, and now care
625the performance of a certain project as a whole.</cmyobject></cmyobject></cstring></my_chr>