Metro C++ 初体验

闲话少说,第一周几个问题:

  1 Metro下创建无焦点空间:

  设置属性 IsHitTestVisible=false;

  2 Metro C++加载DLL

  微软专门为Metro C++ 开放了一个新API : LoadPackageLiberary();

  之前必须将要dll文件添加到工程中(这个不用多说废话了吧,右键点项目名——添加现有项),右键点dll文件——属性,内容选择 是 。

  然后按照原来Win32方法LoadPackageLiberary,GetProcessAddress即可

  3 Metro读写文件

  Metro不是在随便位置都可以读写文件的,只开放了相应的读写位置。我只介绍在文档库读写文件的方法。

  最重要的是必须在package manifest中事先声明。每个项目管理器中都有一个manifest文件,双击打开,点击功能按钮,在功能列表中列出了你的程序需要提供的功能,也隐含着你需要被提供访问权限的位置,勾选你需要的权限很重要,否则在访问你不具备权限的位置时将引发异常。如果是想要在文档库中进行文件操作,还要事先声明,添加一个文件关联的声明,在该声明中添加你需要访问的文件类型。

  顺便多说一句,如果你申请了过多你不需要的权限,估计将来程序上传到App Store可能会出问题。

  4 Metro只允许在主线程做UI操作

  当多线程编程时,不要在自己创建的线程中进行Ui操作,那样将毫无用处。所以,要想办法通知主线程去做这件事。这里特别值得注意的是ThreadPoolTimer这个定时器的机制与Win32不同,它应该是采用的中断机制,因此在中断处理程序中也不能操作UI。

  5 使用CoreDispatcher进行线程间通信

  紧接上一条,如果想在线程间通信,直接使用事件可能会出问题,因为你无法保证该事件处理函数是在主线程还是子线程中执行。因此习惯了Windows Message机制的朋友,可以告诉你们一个非常振奋人心的消息:使用CoreDispatcher可以达到类似的效果,具体的方法还需要你们自己去学习,我简单说一句,你首先获得当前线程的CoreDispatcher:

  m_CoreDispatcher=Windows::UI::Core::CoreWindow::GetForCurrentThread()->Dispatcher,然后使用CoreDispatcher的Invoke或者InvokeAsyn方法向当前线程发送事件,保证该事件一定是主线程处理。

  具体方法,还是去学MSDN吧,我只提供一个思路。

  6 同步和异步调用:

  凡是名字中带有Asyn字样的方法都是可以进行异步操作方法,在C++中使用这种方法需要Concurrency空间中的task类。task类是一个模板类,提供两个重要的方法异步的then()和同步的get()。将异步方法的返回值强制转换为一个以该返回值类型为模板的task类实例,然后调用then或者get方法,才会真正执行该方法。具体的使用方法见MSDN。

  这里值得一提的是:

  1 then比较可靠,但是注意如果使用lamda表达式作为参数传递给then必须注意,如果要传递一个临时变量进入lamda表达式内部,必须小心它很可能在lamda表达式还未执行完成时已经失效(因为是异步执行,该临时变量作用域属于表达式外部)。

  2get非常不靠谱:

  我至今不知道为什么在执行get时经常会无故抛出异常,主要是std::exception异常,不过好在该异常不属于不可恢复异常,通常你可以在catch中对你的程序进行补救。因为get是连续执行一系列操作,可能前面几个操作执行成功而最后得到返回值时失败,这时你可以尝试自己执行得到返回值的操作。我有一个小窍门对待get抛出的异常,但是不值得推广,因为至今我并办法证实这种方法是否会造成恶劣影响。

  我会使用while不断执行get操作,并且捕获std::exception异常和Platform::Exception^异常,直到成功为止(当然必须是针对get抛出的莫名奇妙的异常,如果时由于你代码导致的异常,必须处理),至今为止我还未发生死循环的情况,不过请慎重对待。

  7 Lamda表达式

  这个东西在C++中比C#中复杂的多,它的一般形式是 [](Param0 param0,Param1 param1,...){}用它来取代一个事件处理函数

  delegate void MyEventHandler(Param0 param0,Param1 param1);

  void Func(Param0 param0,Param1 param1,...);

  ref new MyEventHandler(nullptr,Func);

  这其中还有许多变化,由于lamda表达式是非托管的,要想使用托管类实例的成员,就要在[]中将该实例的指针传入。同时还可以在[]中传入外部变量,效果等同于在函数内部使用全局变量。

  这一周收获非常多,先说这么多吧,脑子有点乱,想起来下次再谈


作者: iEditor    时间: 2012-8-31 17:54:31

 闲话少说,书归正传:

  1 Metro C++程序的入口点:

  C++开发的Metro程序有两种架构:Windows RT和Direct程序,这两种程序可以完美的进行交互,用一个不恰当的例子形容他们之间的关系应该就是 MFC和Win32 API程序之间的关系。Windows RT是将Windows API封装在了一组类库中,从用户角度来说它处于更高层次,当然受到的局限性也更大,它的入口点被封装在IDE(vs2011)自动生成的app类中,该类被manifest指定为入口点。而Direct程序更像是用Win32 API开发的窗口程序,它的入口点是我们熟悉的main()。我们首先要实现两个类分别继承于IFramworkView和IFramwordViewSource,然后在main函数中创建IFrameworkViewSource接口实例,用该实例作为参数调用静态方法CoreApplication::Run(),并在IFrameworkViewSource接口的CreateView方法中创建IframeworkView实例,并调用IFrameworkView接口实例相关的方法(由自己实现)启动程序。

  2 Metro UI:

  紧接上文,使用 Windows RT开发的应用程序其实就是.Net程序的变种,通过 XAML定义Ui布局,使用丰富的控件可以进行比较简便快捷的开发出绚丽夺目的软件。但是它同样具备一些缺点:对效率的要求比较低,不够灵活只能使用控件提供的功能,无法访问一些底层的API,对于有特定需求的开发者(系统级软件)无法访问底层的API。另外,对于习惯了直接使用Win32开发窗口程序的程序员来说不容易适应。相反,Direct程序就是对Win32窗口程序的一种延伸,你可以自由创建或者获得CoreWindow这种对象(类似于窗口句柄),并在CoreWindow上直接使用Direct函数绘制(取代Gdi和GDI+)。同时你还可以使用dispatcher/event传递消息(取代message机制)。使用WRT直接使用Com组建,以及一些列Windows为Metro保留或者重新开发的Win32 API。然而,Direct程序开发复杂,难度大,繁琐的API调用必定会延长开发周期,因此究竟如何选择还需要根据实际情况而定。

  对于我来说,我选择两者混用,在交互方面微软做的还是非常好的,基本是无缝对接。

  3 进程与UI(题外话):

  Windows程序通常分为两部分:进程和UI。当然,这么说非常不准确,事实上我想表达的意思其实是进程未必一定是要有UI的,即便没有UI程序依然也可以执行。因此,如果我们想真正弄懂Metro的机制,必须区分开进程与UI。特别值得一提的是,我们必须清楚地知道永远是进程驾驭UI,而非UI左右进程。这句话的意思并非是在UI中不能创建进程,而是说我们必须把进程作为程序的核心,我们需要UI的时候就去 创建,当UI不存在的时候,不意味进程就结束了,依然可以做我们想做的事,在需要的时候还可以再创建UI。当然,如果你只想开发一个WinRT程序,也未必要理解这些,就好像很多未曾深入研究的MFC程序员,它们觉得窗口就是和程序共存的(同生同灭),这个不难理解,因为窗口不是自己创建(微软帮你做了大部分工作)的,你要做的就是在UI中添代码,或许对你来有一种错觉就是现有UI后有进程。。。有了上面的一些不成熟的见解,我要引出的是几个类CoreApplication,CoreApplicationView,CoreWindow。这几个类表示的是什么?其实CoreApplication表示的就是进程,CoreWindow表示的是UI(类似于窗口句柄),CoreApplicaitonView就是将CoreWindow和CoreApplication联系起来的对象。对应到Windows窗口程序,CoreApplication就是表示执行main函数的一个进程,CoreWindow就是在这个进程中创建的一个窗口。由于Metro程序本质上就是一个拥有一个主窗口的全屏程序,因此需要使用CoreApplicationView将这个进程和一个主窗口绑定。通过CoreApplication::GetCurrentView获得当前进程的绑定关系CoreApplicationView,再通过CoreApplicationView::CoreWindow属性就可以找到绑定到当前进程的主窗口对象CoreWindow。

  4 WinRT UI 结构:

  承接上文,Metro程序的Ui其实都是基于一个全屏主窗口创建的。WinRT和MFC,WPF或者C#一样强化了UI而淡化了非UI部分,使得写程序看似就是一个在UI框架中填代码的操作,其实这么看也无可厚非,还能简化程序开发的难度。我们就看一看,到底使用 XAML创建的Ui是一个什么结构?这里首先要提到一个类Windows::UI::Xaml::Window。这个东西究竟是什么?从MSDN上看"A Window object is just surfacing information from CoreWindow, which in turn is referencing the window created by the system."这个我研究了很久,一直没明白,有几点是我感觉到值得特别注意的:

  1 )这个类有获取CoreWindow的方法,但是却找不到任何从CoreWindow获取Window的方法。

  2 )它属于Xaml空间

  3 )它与UIElement有关系,我们之前说了MetroUI都是基于一个CoreWindow上的,但是从CoreWIndow我并没有找到与UI有什么关系。

  通过以上几点我可以大胆推测:Window就是主窗口的CoreWindow的一个XAML表现形式,它将作为所有UIElment的父窗口。这样一来,CoreWindow就和UIElement挂钩了。之所以说它只表示主窗口的CoreWindow,是因为我们无法从任意的CoreWindow获得Window,而只能从一个Window类的静态属性Current得到唯一的Window对象,这只可能是主窗口的Window。

  通过不断地实验,我大致可以得出Metro的Ui结构,一个CoreApplication绑定一个CoreWindow,这个CoreWIndow作为所有UIElement的父控件的表现形式就是Window。Window的Content属性是Frame,一个Window对应n个Frame也就是软件可以有很多场景,每个frame绑定n个page,这个page也就是你当前页面下所有控件的父节点。你可以在一个场景中自由切换页面,也可以在Window下自由切换场景,这对游戏开发者有着非凡的意义。对于一般非游戏开发者,可能一个frame多个page的情况比较常见。

  5 page切换:

  使用frame的Navigate()函数或者GoBack(),GoForward()。后两个函数没什么可说的,像浏览器一样,可以根据你的切换历史,跳转到指定页面。值得一题的是Navigate函数,很奇怪,它的参数并不是指定页面对象的名字,反而是指定页面的类型名。我大胆推测一下吧,在Metro程序中我们没有显式的创建过页面,而系统自动创建了我们自定义的页面,和可能是我们每一个自定义的页面类型只会被创建唯一一个实例,而且我们并不是使用ref new来创建,而是通过navigate函数创建这唯一的实例,因此我们只要指定页面的类型就可以跳转到唯一的页面。不过这只是我的推测。


       转自:http://www.devdiv.com/forum.php?mod=viewthread&action=printable&tid=134196

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值