`
9alexking
  • 浏览: 8527 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

从Win8回顾微软平台的各种技术

阅读更多

我安装好Win8 CTP后做的第一件事情就是用调试器研究Win8各个组件的协作关系从我半天的研究结果看来, Win8真是一个让我爱不释手的产品. Win8里面涉及到的很多技术正好也是我的兴趣所在这篇文章简单回顾一下这些技术的变迁优缺点和对Win8的影响.

注意下面提到的对Win8的分析是基于公开的Win8 CTP来做的相信Win8面世的时候这些技术和细节都会发生重大改变所以这篇文章不具备实践上的指导价值.

COM -Common Object Model 通用组件模型

COM是上个世纪中期设计出来的伟大产品. COM旨在解决软件复用的问题COM以前大家都是用代码级别的复用常见的就是C/C++的库无论是原代码库还是lib都是需要编译后才能重用的. COM使得技术人员可以在二进制上进行复用Win95, OLE32Office95系列开始, COM就是微软平台上的一个技术基石无论是DirectX API, 还是最常见的剪贴板以及后来.NET Frameworkhost接口都离不开COM. 但任何伟大的产品都有局限的一面. COM在局限性在下面一些地方

STA/MTA/NTA等等线程模型过于复杂

线程模型特别是STA, 设计的目的是方便使用者COM的线程模型严重依赖于太多系统组件比如Win32 Message, RPCWindows系统服务使得程序员需要熟悉和了解太多系统知识才可以正确地使用线程模型否则用STA导致死锁简直就是家常便饭.

开发工具没有提供足够支持

COMVisual Studio 6.0的关系就如同现在CLR2/VS2005, CLR3.5/VS2008CLR4/VS2010的关系一样铁使用COM开发当时的选择要么是VB6, 要么用ATL. 这两者都有天生的局限. VB6适合企业开发特别是当时流行的MIS系统数据库系统这样的CS应用但是VB6不够灵活而且VB6里面由于缺少多线程支持无法用MTA的模型. ATL功能强大足够灵活但是使用起来特别复杂每次实现一个接口都要做一大堆C++的仪式性工作比如实现多重继承定义新的模板使用大量的C神经再粗大的程序员都经不起这样用C++.

无止境地扩充到DCOM, COM+, DTC, MSMQ以及后来的.NET Remoting/WCF, 使得最后的复杂度无法控制

为了更好地适应企业级别的开发, COM被进一步延伸和演化成了DCOMCOM+. 所谓"企业级别", 其实是指对安全性和可伸缩性的更高要求经典的COM是一个进程内模型无法让不同的代码运行在不同的帐号下的因为同一个进程只能启在唯一的帐号下虽然通过impersonate等方法可以适当地解决问题但是为了让安全模型更为全面正确的做法是让不同的接口实现能够跨越进程甚至跨越机器等安全边界运行要能够赋予不同的接口不同的安全级别能够和域帐号集成支持不同等级的加密等等.远程通用组件模型也就是DCOM就这样诞生了读者可以尝试运行以下dcomcnfg.exe这个工具展开一些节点看看属性页就能体会到DCOM的功能是多么让人眼花缭乱了对于可伸缩性微软更上一层楼DCOM的基础上加入了对象池和新的同步模型做成了COM+. 风靡十年的ASP, 就是运行在COM+框架下的最好例子更让人叹为观止的是微软把DTCMSMQ的设计也和COM+模型绑定起来陌生的读者可能不了解DTC是个多么nb的东西简单说DTC是可以让程序员一行代码都不用写就让SQL ServerOracle的数据库操作运行在同一个事务边界里面可以想象MSSQL Server刚进入市场的时候微软推出这样的功能对于抢占Oracle的市场份额有多么重要. DTCCOM+当时成为了很多大公司的标准配置以至于后来设计.NET RemotingWCF的时候都还是要考虑对DTC的支持这些强大而且复杂的功能让本来就复杂的COM更加恐怖这样的复杂度虽然也体现了当时的市场需求但由于缺乏配套的开发工具新的开发语言和更优美的抽象使得这条路最后越走越窄.

.NET Framework/CLR

在我眼中, CLR的各方面简直是无可挑剔的但可能正是因为CLR太好了让微软从2003年开始unmamanged world的投资就不大了.

为了争取企业客户全力推广CLR是最正确的做法毕竟绝大多数的程序员一辈子都是和数据库UI代码打交道你总不能让他们一辈子都用C去管理内容创建窗口句柄吧. CLR的性能也很有竞争力与之对应的编程语言和开发工具也非常给力每个新版本都带来长足进步但是这些再好也无法掩饰一个悖论要用用C#写出性能可以和C++一个数量级的程序不是不可能而是花费的代价往往比直接用C++写更大这里面有很多原因比如系统最底层的API还是unmanaged通过CLRinterop的性能损失无法忽略比如用C#的话程序员的控制力很弱从工具和语言层面上很难对性能精雕细作一不注意就box/unbox比如JIT编译器为了实现自己的安全模型和异常处理每次访问成员函数的都是都要生成代码确认this指针是否为空这个世界上还是有很多程序是需要对性能做严格控制的CLR高速发展的几年中对应的系统平台, Win32 API, C++开发工具只有完善性的改善并没有重大突破这个问题对Windows平台本身影响不大但如果寄希望于在移动设备上大家都指着C#来开发就有点天方夜谭了这样的失衡使得微软在移动设备和消费者产品这两个严重需要unmanaged和系统投入的领域缓慢发展了很长时间.

WPF

在我看来, WPF是一个设计得很美的产品. WPF解决了传统Win32 UI程序的四大局限. 1) Win32的绘图是由各自Window元素独立控制基于GDI. WPF引入了rendering thread来提高性能优化算法借用GPU加速. 2) Win32依赖于GDI Object, 在开发复杂窗口程序的时候很容易就遭遇资源泄露和资源不足比如早期的淘宝旺旺开到几十个窗口的时候程序就会出问题所以淘宝针对这个问题使用了统一控制台合并多个窗口到标签页的方法来解决WPF只有最外面的窗口使用了Win32 WindowGDI, 内部的元素都是抽象成了WPF自己的元素不额外占用Win32 GDI资源的. 3) Win32窗体程序严重依赖Windows Message模型这要求程序员对系统知识有深入的了解而且Win32 API并不是非常利于使用比如要进行UI threadWorker thread之间的通信往往需要和SendMessage这样的API打交道WPF引入了Dispatcher类和BeginInvoke方法把这些复杂问题抽象了加上CLR提供了更方便高效的开发环境使用WPF是很愉快的工作. 4) Win32缺乏数据设计和代码三者之间的模式抽象这三者在WPF中对应了数据绑定, XAML文件以及后台代码WPF中可以更直观地使用各种模式比如MVCMVVM. 这些都体现了WPF设计上的优美.

再优美的东西都还是有局限性的. WPF的问题在于过多的模式和对CLR过度的依赖了解WPF框架的人都知道就一个简单的dependent property, 就把设计模式这本书里面的模式用掉一大半了分析WPF框架代码的话简直就是看一本设计模式的百科全书我曾经统计过关于mouse click这样一个event回调, WPF里面有7种不同的实现方法分别各有好处旨在解决不同问题在这样高度灵活的背后牺牲的是程序性能无论是五花八门的模式还是最常用的数据绑定背后的主力都是CLRreflection. 过度依赖于reflection导致WPF程序规模一大性能上就出问题就算再怎么优化也总找不到原生Win32程序那般流利的感脚使用reflection也体现了对CLR的依赖所以前面CLR的局限性也适用于WPF.

微软产品的互操作性

微软的产品线虽又长又多但是各个产品之间一定是能够互操作的比如C#可以和C++互相调用任何语言开发的程序都可以嵌入Browser Control来借用IE的功能. Office暴露了VBA接口通过VBScript都能够自动化Office程序各种管理工具无论是Explorer还是MMC, 都暴露了编程接口可以让程序员添加自己的功能我见过客户用ASP.NET在后台用VBScript生成Excel表格然后把表格嵌入在 IE浏览器中再使用JavaScript来帮助客户编辑最后提交回MSSQL数据库做完成报销功能的完善的互操作性充分保护了用户的投资使得客户对微软平台用一次就上瘾几乎没有不可能完成的任务仔细分析其实这些互操作有一个共性都是把暴露COM接口作为内部实现原理这个做法导致了三个局限性首先是牵涉到了前面提到的COM的复杂度其次是潜在的性能损耗最后是在具体开发的时候都需要一些仪式性的工作来引入或者定义COM接口使得开发过程不够自然流畅CLRCOM互操作的调用栈里面, CLRRCW, CCW, 安全处理列集拷贝等等耗费的时间带来的性能开销简直是可以到了肉眼可察觉的地步(听硬盘的声音和看任务管理器里面CPU的波动).

Win8

在讨论完这些技术背后的故事后再看看为啥我就对Win8爱不释手了.

Win8引入了Windows Runtime, 简称WinRT. WinRT是一个操作系统模块运行在用户态介于Win32的上层和应用程序的下层目的在于提供更高效友好的开发接口供Win8的程序员使用. WinRT在二进制模型上基本就是照搬了经典的COM. WinRTCLR互不依赖, WinRT可以被CLR使用. WinRT通过C/C++实现效率高是一个方面更重要的时Win8引入了projection的概念就是可以把WinRTAPI用最直接最高效的方法提供给上层的编程语言调用这个语言可以是C#, C或者JavaScript.

对于第一次接触Projection的朋友可以把Projection认为是一种新的Windows API模型传统的操作系统API, 要么是暴露DLL的方法要么是通过COM接口无论是哪一种CLR中调用的时候都有不小的开销使用这些传统API的效率比调用一个C#自己的方法效率差了多个数量级根本的原因在于CLR的安全模型内存模型和传统的unmanaged模型不兼容所以跨越边界的调用需要额外的代码来处理Projection提供的模型是在提供新功能的同时还针不同编程模型和语言提供了最利于它们调用的方法这样就主动避免了不同模型之间为了互相兼容导致的开销也使得程序员写代码的时候非常自然流畅调用的时候根本感觉不到和调用本地函数的区别当然能够实现这一点也是得益于CLR, C#语言和VS开发工具这十年的长足发展举个例子, C# 5.0中引入了await关键字, WinRT中引入了async operation. Projection技术把C#中的await语句转换为WinRT async operation的调用而且这个调用直接从managed code直接跳到unmanaged code, 中间没有任何冗余也不需要CLR Engine的介入进一步的信息可以参考Build大会关于WinRT的多个演讲后面的callstack也提供了直观的例子.

前面提到了COM的局限性在于一个轻量的二进制模型被硬生生的扩展成一个无所不能的框架. WinRT取其精华去其糟粕借用了COM的轻便舍弃了复杂性在扩展性上依托于上层的编程语言和工具. WinRT通过projection的技术解决了传统互操作性效率不高使用不方便的问题以前的路线是希望所有的产品和技术最后都统一到CLR上来现在修正为底层模型通过WinRTC来实现然后把这一层高效的组件无缝提供给上层的开发技术比如CLR来使用这个转变重新重视unmanaged层面的二进制模型归纳为, unmanaged模型的优势在于执行效率高可以通吃所有场景缺点在于开发和使用成本也高. CLR的优势在于开发成本低缺点在于无法通吃各种需求现在微软自己用unmanaged来做WinRT, 然后把WinRT提供给上层语言这两者就可以取长补短了.

有了WinRT, 有了unmanaged的回归再加上微软开发工具和C#语言的长足发展前面介绍的各种技术在Win8里面就相得益彰了. Metro是如何修复WPF的缺陷就显而易见了: Win8metro程序继续使用WPF中引入的rendering模型和XAML, 但是在control的基础设计和实现上CLR转移到了C, 然后通过WinRT来暴露给使用者至于使用的灵活性比如要不要实现数据绑定就看上层使用者自己的选择了.

附录

下面是我研究过程中看到的一些Win8callstack. 基于这些callstack和我以往的经验才写了上面的文章.

Stack1:

Windows_UI_Immersive!`Windows::Internal::CMessageDialog::ShowAsync'::`50'::<lambda_32D66FEFF293CE6B>::<lambda_32D66FEFF293CE6B>

Windows_UI_Immersive!Windows::Internal::CMessageDialog::ShowAsync+0x1a0

image08ee0000!DomainNeutralILStubClass.IL_STUB_CLRtoCOM()+0x8c

application1!Application1.MainPage+<button_Click>d__0.MoveNext()+0xcd

application1!Application1.MainPage.button_Click(System.Object, Windows.UI.Xaml.RoutedEventArgs)+0x80

stack2:

combase!CComActivator::DoCreateInstance+0x121

combase!CoCreateInstanceEx+0x51

combase!CoCreateInstance+0x65

Windows_UI_Immersive!Windows::Internal::CPopupWindowImpl::_TryToUnregisterForIHMNotifications+0x3b

Windows_UI_Immersive!Windows::Internal::CPopupWindowImpl::_HideWindow+0x31

Windows_UI_Immersive!Windows::Internal::CPopupWindowImpl::HideWindow+0x9

Windows_UI_Immersive!Windows::Internal::CPopupWindowImpl::DestroyWindow+0x24

Windows_UI_Immersive!Windows::Internal::CPopupWindow::Destroy+0x57

Windows_UI_Immersive!Windows::Internal::CClosePopupCommandHandler::Invoke+0xe 0x73

Windows_UI_Immersive!Windows::Internal::CPopupWindowImpl::_OnButtonPress+0xc0

Windows_UI_Immersive!Windows::Internal::CPopupWindowImpl::OnMessage+0x18b

DUI70!DirectUI::NativeHWNDHost::WndProc+0x73

USER32!InternalCallWinProc+0x23

USER32!UserCallWinProcCheckWow+0x100

USER32!DispatchMessageWorker+0x3d4

USER32!DispatchMessageW+0x10

Windows_UI_Immersive!SHProcessMessagesUntilEventsEx+0xe2

Windows_UI_Immersive!Windows::Internal::PopupWindowOperation::Show+0x103

Stack3:

Windows_UI_Xaml!HWWalk::RenderChildren+0x7a

Windows_UI_Xaml!HWWalk::RenderContentAndChildren+0x2d1

Windows_UI_Xaml!HWWalk::Render+0x61e

Windows_UI_Xaml!HWWalk::RenderChildren+0x7a

Windows_UI_Xaml!HWWalk::RenderRoot+0x1c4

Windows_UI_Xaml!CCoreServices::NWDrawTree+0x698

Windows_UI_Xaml!CCoreServices::NWDraw+0x1d6

Windows_UI_Xaml!CRenderTarget::Draw+0x13

Windows_UI_Xaml!CWindowRenderTarget::Draw+0x40

Windows_UI_Xaml!CXcpBrowserHost::OnTick+0x88

Windows_UI_Xaml!CXcpDispatcher::Tick+0x184

Windows_UI_Xaml!CXcpDispatcher::OnReentrancyProtectedWindowMessage+0x133

Windows_UI_Xaml!CXcpDispatcher::ProcessMessage+0xa4

Windows_UI_Xaml!CXcpDispatcher::WindowProc+0x69

USER32!InternalCallWinProc+0x23

USER32!UserCallWinProcCheckWow+0x100

USER32!DispatchMessageWorker+0x3d4

USER32!DispatchMessageW+0x10

windows_ui!Windows::UI::Core::CDispatcher::ProcessMessage+0xc7

windows_ui!Windows::UI::Core::CDispatcher::ProcessEvents+0x6c

Windows_UI_Xaml!CJupiterWindow::RunCoreWindowMessageLoop+0x3b

Windows_UI_Xaml!CJupiterControl::RunMessageLoop+0x1d

Windows_UI_Xaml!CJupiterControlLight::RunMessageLoop+0x8

Windows_UI_Xaml!DirectUI::DXamlCore::RunMessageLoop+0x15

Windows_UI_Xaml!DirectUI::ViewProvider::Run+0x11

twinapi!Windows::ApplicationModel::Core::CoreApplicationView::ViewProviderThreadProc+0x27

分享到:
评论

相关推荐

    回顾微软30年 Win1到Win10是如何发展演变的.doc编程资料

    回顾微软30年 Win1到Win10是如何发展演变的.doc

    C#微软培训资料

    1.3 C#语言的特点.8 1.4 小 结 .11 第二章 运行环境 全面了解.NET.12 2.1 .NET 结构.12 2.2 公用语言运行时环境与公用语言规范.13 2.3 开 发 工 具 .17 2.4 小 结 .19 第三章 编写第一个应用程序 .20 ...

    windowsnt 技术内幕

    回顾微软Windows NT域 回顾Windows NT域委托关系 回顾Windows NT目录服务 创建一个高效的Windows NT目录服务结构 决定所需的域控制器的数量 理解在地理上怎样安排域控制器 理解域控制器的大小和速度 计算所需的主域...

    windows 10 安装和使用中5个常见问题

    把XP、WIN7、WIN10都安装了一遍,短暂的回顾了”微软系统历史” 吐槽:系统崩溃,手头没有安装光盘,顶着太阳跑附近里买了张Win7盘,光驱挑盘不读,换了2次都告吹。只能把箱底的XP找了出来,心想只要能进系统就用U盘...

    资源管理革命:Library

    如何有效管理资源,是一本好书。 Windows 7发布在即,大家的尝鲜情绪高涨,关于win7相对于vista/XP下UI的变化, 大家想说的一定...本文简要回顾库的发展历程,阐述库的 优点与应用,同时反思大家使用计算机的行为习惯。

    wpf完全教程1-4章

    Windows Presentation Foundation (WPF) 是.NET Framework 3.0 的关键组件,是支持下一代视窗应用程序表现层编程的平台,也是微软新发布的Vista操作系统的三大核心开发库之一,主要负责图形显示。本书是针对那些对...

    WPF揭秘 第四章 wpf 开发

    Windows Presentation Foundation (WPF) 是.NET Framework 3.0 的关键组件,是支持下一代视窗应用程序表现层编程的平台,也是微软新发布的Vista操作系统的三大核心开发库之一,主要负责图形显示。本书是针对那些对...

    WPF揭秘 第二章 wpf 开发

    Windows Presentation Foundation (WPF) 是.NET Framework 3.0 的关键组件,是支持下一代视窗应用程序表现层编程的平台,也是微软新发布的Vista操作系统的三大核心开发库之一,主要负责图形显示。本书是针对那些对...

    WPF揭秘 第三章 wpf 开发

    Windows Presentation Foundation (WPF) 是.NET Framework 3.0 的关键组件,是支持下一代视窗应用程序表现层编程的平台,也是微软新发布的Vista操作系统的三大核心开发库之一,主要负责图形显示。本书是针对那些对...

    WPF揭秘 第一章 wpf 开发

    Windows Presentation Foundation (WPF) 是.NET Framework 3.0 的关键组件,是支持下一代视窗应用程序表现层编程的平台,也是微软新发布的Vista操作系统的三大核心开发库之一,主要负责图形显示。本书是针对那些对...

    Thinking in Java 中文第四版+习题答案

    A.2 微软的解决方案 A.3.1 @dll.import引导命令 A.3.2 com.ms.win32包 A.3.3 汇集 A.3.4 编写回调函数 A.3.5 其他J/Direct特性 A.4 本原接口(RNI) A.4.1 RNI总结 A.5 Java/COM集成 A.5.1 COM基础 A.5.2 MS Java/...

    Think in Java(中文版)chm格式

    A.2 微软的解决方案 A.3 J/Direct A.3.1 @dll.import引导命令 A.3.2 com.ms.win32包 A.3.3 汇集 A.3.4 编写回调函数 A.3.5 其他J/Direct特性 A.4 本原接口(RNI) A.4.1 RNI总结 A.5 Java/COM集成 A.5.1 ...

    Java初学者入门教学

    A.2 微软的解决方案 A.3 J/Direct A.3.1 @dll.import引导命令 A.3.2 com.ms.win32包 A.3.3 汇集 A.3.4 编写回调函数 A.3.5 其他J/Direct特性 A.4 本原接口(RNI) A.4.1 RNI总结 A.5 Java/COM集成 A.5.1 COM基础 A....

    JAVA_Thinking in Java

    A.2 微软的解决方案 A.3 J/Direct A.3.1 @dll.import引导命令 A.3.2 com.ms.win32包 A.3.3 汇集 A.3.4 编写回调函数 A.3.5 其他J/Direct特性 A.4 本原接口(RNI) A.4.1 RNI总结 A.5 Java/COM集成 A.5.1 COM基础 A....

    ThinkInJava

    A.2 微软的解决方案 A.3 J/Direct A.3.1 @dll.import引导命令 A.3.2 com.ms.win32包 A.3.3 汇集 A.3.4 编写回调函数 A.3.5 其他J/Direct特性 A.4 本原接口(RNI) A.4.1 RNI总结 A.5 Java/COM集成 A.5.1 COM基础 A....

    java 编程入门思考

    A.2 微软的解决方案 A.3 J/Direct A.3.1 @dll.import引导命令 A.3.2 com.ms.win32包 A.3.3 汇集 A.3.4 编写回调函数 A.3.5 其他J/Direct特性 A.4 本原接口(RNI) A.4.1 RNI总结 A.5 Java/COM集成 A.5.1 COM基础 A....

    thinkinjava

    A.2 微软的解决方案 A.3 J/Direct A.3.1 @dll.import引导命令 A.3.2 com.ms.win32包 A.3.3 汇集 A.3.4 编写回调函数 A.3.5 其他J/Direct特性 A.4 本原接口(RNI) A.4.1 RNI总结 A.5 Java/COM集成 A.5.1 COM基础 A....

    Thinking in Java简体中文(全)

    A.2 微软的解决方案 A.3 J/Direct A.3.1 @dll.import引导命令 A.3.2 com.ms.win32包 A.3.3 汇集 A.3.4 编写回调函数 A.3.5 其他J/Direct特性 A.4 本原接口(RNI) A.4.1 RNI总结 A.5 Java/COM集成 A.5.1 COM基础 A....

    java联想(中文)

    A.2 微软的解决方案 A.3 J/Direct A.3.1 @dll.import引导命令 A.3.2 com.ms.win32包 A.3.3 汇集 A.3.4 编写回调函数 A.3.5 其他J/Direct特性 A.4 本原接口(RNI) A.4.1 RNI总结 A.5 Java/COM集成 A.5.1 COM基础 A....

    Thinking in Java(中文版 由yyc,spirit整理).chm

    A.2 微软的解决方案 A.3 J/Direct A.3.1 @dll.import引导命令 A.3.2 com.ms.win32包 A.3.3 汇集 A.3.4 编写回调函数 A.3.5 其他J/Direct特性 A.4 本原接口(RNI) A.4.1 RNI总结 A.5 Java/COM集成 A.5.1 COM基础 A....

Global site tag (gtag.js) - Google Analytics