WinRT出来有3年了,用的人并不多,用C++来用它的人更是少。
照成这样不外乎Windows 8平台不给力,用户基数少,但是WinRT本身的难用也是一个方面的原因,首先WinRT的所谓大宇50ms的任务全部Async化,这对习惯了传统Win32桌面的程序员来说 —— 你在逗我玩呢。
现在我们来简单看看WinRT的Async模型。

实在没太多必要介绍那些理论知识,就像这种文章:
http://blogs.msdn.com/b/windowsappdev_cn/archive/2012/03/26/windows.aspx
或者这种文章:
http://blogs.msdn.com/b/windowsappdev_cn/archive/2012/04/30/winrt-await.aspx(深入探究 WinRT 和 await)
这些文章充满了浆糊和痛苦,就像MSDN写的函数声明介绍一样。

我希望屏幕前的你对微软的传统COM技术(进程内COM)有了解,知道ATL帷幔之下的COM原始情况,也就是我希望你曾经徒手从IUnknown开始,到QueryInteface,到AddRef、Release写过,然后使用DllGetClassObject来new这个实例,也就是你曾经有过不错的COM开发经验,对COM有较好的认识。
如果你不曾了解这些,这文章还是关了把,上面那2个的连接也许有一个适合你。
嗯,这篇文章是为我们传统的Win32桌面C++程序员准备的!

异步,对我们传统的Win32程序员来说。
不外乎:
SubmitTask
DoWork(new Thread)...
CallbackNotify
EndTask

也就是,我们跑的Task,必需要能同步\异步通知到它的所有者,并且把处理结果交过来。
那WinRT的异步,也不外乎这样。

来我们看代码,下面的代码,请建立控制台工程:

#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <string>
#include <iostream>
#include <memory>
#include <Windows.h>
#include <wrl.h>
#include <wrl\client.h>
#include <wrl\wrappers\corewrappers.h>
#include <roapi.h>
#include <windows.storage.h>
#include <windows.storage.streams.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Storage;
using namespace ABI::Windows::Storage::Streams;
int main()
{
RoInitialize(RO_INIT_MULTITHREADED);
ComPtr<IKnownFoldersStatics> pKnownFolders;
HRESULT hr = RoGetActivationFactory(HStringReference(RuntimeClass_Windows_Storage_KnownFolders).Get(),
IID_PPV_ARGS(pKnownFolders.GetAddressOf()));
ComPtr<IStorageFolder> pFolder;
pKnownFolders->get_VideosLibrary(&pFolder);
RoUninitialize();
getchar();
return 0;
}

好了,可以看到,我们拿到了用户的视频文件夹,从上面的代码大家可以发现,这些代码,头文件和using多生死,主函数真正有用的代码满打满算就 4行,是不是微软脑残?
恩对,是微软脑残,好了这个不说。

我们看到我们拿到了一个IStorageFolder接口实例,代码目前还算正常。
然后我们想在视频文件夹里面新建立一个文件,IStorageFolder提供了一个名为 CreateFileAsync的脑残方法,我们看看这个方法:

前面2个参数都正常,第三个是什么玩意儿?微软脑袋浆糊了?
好了这个不说,我们还是看下实际情况。

我们F12“转到定义”,然后我们可以看到,浆糊的定义是:

__FIAsyncOperation_1_Windows__CStorage__CStorageFile **operation

那这个浆糊的__FIAsyncOperation_1_Windows__CStorage__CStorageFile是什么鬼玩意儿?
我们再次转到定义:

#define __FIAsyncOperation_1_Windows__CStorage__CStorageFile ABI::Windows::Foundation::__FIAsyncOperation_1_Windows__CStorage__CStorageFile_t

这个操蛋的ABI::Windows::Foundation::__FIAsyncOperation_1_Windows__CStorage__CStorageFile_t又是什么?再次F12,原来就在上面:

typedef IAsyncOperation<ABI::Windows::Storage::StorageFile*> __FIAsyncOperation_1_Windows__CStorage__CStorageFile_t;

我们的三官总算正常了,这玩意儿是一个:IAsyncOperation <ABI::Windows::Storage::StorageFile*>
可你仔细看,不对不对,这东西不正常,还是没有三观。

首先WinRT是COM的模型,IAsyncOperation是一个COM接口对吧,为什么这个COM接口还有模板参数?微软辣条吃多了?
我们在IAsyncOperation上F12,就来到了一个让你脑袋浆糊的一片代码:

namespace ABI { namespace Windows { namespace Foundation {
template <>
struct __declspec(uuid("5e52f8ce-aced-5a42-95b4-f674dd84885e"))
IAsyncOperation<ABI::Windows::Storage::StorageFile*> : IAsyncOperation_impl<ABI::Windows::Foundation::Internal::AggregateType<ABI::Windows::Storage::StorageFile*, ABI::Windows::Storage::IStorageFile*>> {
static const wchar_t* z_get_rc_name_impl() {
return L"Windows.Foundation.IAsyncOperation`1<Windows.Storage.StorageFile>"; }
};

此时我们还是可以继续对着IAsyncOperation_impl按F12,但是还是不用先,先让我们的脑袋粘着。

也就是说,我们要使用CreateFileAsync,我们可以这样写:

    ComPtr<__FIAsyncOperation_1_Windows__CStorage__CStorageFile> pFile;pFolder->CreateFileAsync(HStringReference(L"123.mp4").Get(),CreationCollisionOption::CreationCollisionOption_ReplaceExisting,pFile.GetAddressOf());

或者直观一点:

    ComPtr<IAsyncOperation<ABI::Windows::Storage::StorageFile*>> pFile;pFolder->CreateFileAsync(HStringReference(L"123.mp4").Get(),CreationCollisionOption::CreationCollisionOption_ReplaceExisting,pFile.GetAddressOf());

但是大家是不是感觉很难受?十分十分难受?
难道我还要写一个AsyncOperationCompletedHandler类,来接受这个Async返回值?
真是微软脑残对吧?

我们仔细研究,可以看到:ComPtr<IAsyncOperation<ABI::Windows::Storage::StorageFile*>> pFile;
这个玩意儿,是个ComPtr,也就是IAsyncOperation<ABI::Windows::Storage::StorageFile*>这玩意儿,其实是个COM接口实例,是COM的话,那我们理论上可以这样:

    ComPtr<IUnknown> pUnk;pFolder->CreateFileAsync(HStringReference(L"123.mp4").Get(),CreationCollisionOption::CreationCollisionOption_ReplaceExisting,(__FIAsyncOperation_1_Windows__CStorage__CStorageFile**)pUnk.GetAddressOf());

我相信大家可能舒服了,就像泄了一样。

好,现在我们成功执行CreateFileAsync返回了一个pUnk,但是pUnk没用啊,我们必需拿到点什么。。。。
可能你会想,我进行pUnk->QueryInterface,给他一个IAsyncOperation?不不不,你做不到的,不信你可以试试:

哈哈,IAsyncOperation这接口连IID_IAsyncOperation都没有,我们仔细看看,我们可以发现,微软说IAsyncOperation接口继承来自IAsyncInfo,也就是说,这个pUnk应该是可以拿到IAsyncInfo的,而IAsyncInfo是没有模板参数(返回值)的,好,我们来QI试试:

    ComPtr<IAsyncInfo> pAsyncInfo;pUnk->QueryInterface(IID_PPV_ARGS(pAsyncInfo.GetAddressOf()));

我们成功拿到了pAsyncInfo,而IAsyncInfo能干啥呢?它能查询Async操作的返回值。。。
于是我们可以写一个类似C#的await:

    //awaitwhile (1){AsyncStatus asyncStatus;HRESULT hr = pAsyncInfo->get_Status(&asyncStatus);if (SUCCEEDED(hr) && (asyncStatus == AsyncStatus::Completed))break;SwitchToThread();}

这样我们就成功执行完成CreateFileAsync了,是不是很脑残?

好了我们回来这个IAsyncOperation。
通过上面,大家知道IAsyncOperation继承IAsyncInfo,扩展出来了几个方法:

public interface IAsyncOperation<TResult> : IAsyncInfo
{AsyncOperationCompletedHandler<TResult> Completed { get; set; }TResult GetResults();
}

浆糊总算解开了一点,可还是感觉不爽。
如果我们不使用IAsyncOperation、AsyncOperationCompletedHandler,就没有GetResult,拿不到返回的接口。
难道我们真得还是的写一个模板类实现AsyncOperationCompletedHandler?这也太脑残了。

这真是浆糊,但是我们要装逼,又不想用ComPtr<IAsyncOperation<ABI::Windows::Storage::StorageFile*>> pFile。
可不管咋样,我们知道,ComPtr<IUnknown> pUnk,这个里面,是肯定有IAsyncOperation的对吧,对吧,对吧?

回到上面那个浆糊的代码:

namespace ABI { namespace Windows { namespace Foundation {
template <>
struct __declspec(uuid("5e52f8ce-aced-5a42-95b4-f674dd84885e"))
IAsyncOperation<ABI::Windows::Storage::StorageFile*> : IAsyncOperation_impl<ABI::Windows::Foundation::Internal::AggregateType<ABI::Windows::Storage::StorageFile*, ABI::Windows::Storage::IStorageFile*>> {
static const wchar_t* z_get_rc_name_impl() {
return L"Windows.Foundation.IAsyncOperation`1<Windows.Storage.StorageFile>"; }
};

结构上面你看到了uuid,你可能想到了什么,没错,我们来尝试:

ComPtr<IAsyncOperation<ABI::Windows::Storage::StorageFile*>> pNewFile;
pUnk->QueryInterface(IID_PPV_ARGS(pNewFile.GetAddressOf()));

然后我们发现我们成功了,于是可以拿返回值了:

ComPtr<IStorageFile> pFile;
pNewFile->GetResults(pFile.GetAddressOf());

好,一切都很有趣,为什么没有IID_IAsyncOperation这个东西,我们却是可以进行IID_PPV_ARGS?我估计你想到了什么,我们把生成的exe拿来反汇编。。。

  PUSH EDXPUSH OFFSET ~1.__GUID_5e52f8ce_aced_5a42_95b4_f674dd84885ePUSH EAXMOV ECX,DWORD PTR DS:[EAX]CALL DWORD PTR DS:[ECX] -> QueryInterface

好吧,我们看到,这货给的IID,原来就是上面那个浆糊代码里面的IID啊,我们好像发现了什么奇怪的东西。
好了,现在我们可以对着IAsyncOperation_impl按F12了,我们来到了一个新的地方:

    template <class TResult>struct IAsyncOperation_impl : IInspectable{private:typedef typename Windows::Foundation::Internal::GetAbiType<TResult>::type     TResult_abi;typedef typename Windows::Foundation::Internal::GetLogicalType<TResult>::type TResult_logical;public:typedef TResult                                                                 TResult_complex;virtual HRESULT STDMETHODCALLTYPE put_Completed( IAsyncOperationCompletedHandler<TResult_logical> *handler) = 0;virtual HRESULT STDMETHODCALLTYPE get_Completed( IAsyncOperationCompletedHandler<TResult_logical> **handler) = 0;virtual HRESULT STDMETHODCALLTYPE GetResults(  TResult_abi *results) = 0;};

IInspectable是WinRT的标准根接口,是一个正常的COM对象,我们可以不需要太关注,可以吧IInspectable想象为IUnknown就行了。
也就是说,IAsyncOperation_impl是一个COM对象,怪不得他能IID_PPV_ARGS呢,来我们把浆糊删掉:

    template <class TResult>struct IAsyncOperation_impl : IInspectable{public:virtual HRESULT STDMETHODCALLTYPE put_Completed( IAsyncOperationCompletedHandler<TResult> *handler) = 0;virtual HRESULT STDMETHODCALLTYPE get_Completed( IAsyncOperationCompletedHandler<TResult> **handler) = 0;virtual HRESULT STDMETHODCALLTYPE GetResults(  TResult *results) = 0;};

哇,浆糊一下少了很多,世界开明了。
可能有人还在叫,那这个TResult是什么东西?来我们看上面的代码:

ComPtr<IStorageFile> pFile;
pNewFile->GetResults(pFile.GetAddressOf());

看出来了没?TResult返回了一个ComPtr,也就是,TResult就是一个IUnknown*。
好了我们知道既然是这样的,我们来做一下手术,我们在上面搞一个这样的接口声明:

MIDL_INTERFACE("5e52f8ce-aced-5a42-95b4-f674dd84885e")
IAsyncOperation_ : public IInspectable
{
public:virtual HRESULT STDMETHODCALLTYPE put_Completed( IUnknown *handler) = 0;virtual HRESULT STDMETHODCALLTYPE get_Completed( IUnknown **handler) = 0;virtual HRESULT STDMETHODCALLTYPE GetResults(  IUnknown **results) = 0;
};

然后写代码:

    /*ComPtr<IAsyncOperation<ABI::Windows::Storage::StorageFile*>> pNewFile;pUnk->QueryInterface(IID_PPV_ARGS(pNewFile.GetAddressOf()));ComPtr<IStorageFile> pFile;pNewFile->GetResults(pFile.GetAddressOf());*/ComPtr<IAsyncOperation_> pNewFile;pUnk->QueryInterface(IID_PPV_ARGS(pNewFile.GetAddressOf()));ComPtr<IUnknown> pTempFile;pNewFile->GetResults(pTempFile.GetAddressOf());ComPtr<IStorageFile> pFile;pTempFile->QueryInterface(IID_PPV_ARGS(pFile.GetAddressOf()));

卧槽,我们发现,我们不使用那个脑残的模板了,我们终于可以忽略那个浆糊的代码了。。。

来,这是全部的代码:

#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <string>
#include <iostream>
#include <memory>#include <Windows.h>#include <wrl.h>
#include <wrl\client.h>
#include <wrl\wrappers\corewrappers.h>#include <roapi.h>#include <windows.storage.h>
#include <windows.storage.streams.h>using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Storage;
using namespace ABI::Windows::Storage::Streams;MIDL_INTERFACE("5e52f8ce-aced-5a42-95b4-f674dd84885e")
IAsyncOperation_ : public IInspectable
{
public:virtual HRESULT STDMETHODCALLTYPE put_Completed( IUnknown *handler) = 0;virtual HRESULT STDMETHODCALLTYPE get_Completed( IUnknown **handler) = 0;virtual HRESULT STDMETHODCALLTYPE GetResults(  IUnknown **results) = 0;
};int main()
{RoInitialize(RO_INIT_MULTITHREADED);ComPtr<IKnownFoldersStatics> pKnownFolders;HRESULT hr = RoGetActivationFactory(HStringReference(RuntimeClass_Windows_Storage_KnownFolders).Get(),IID_PPV_ARGS(pKnownFolders.GetAddressOf()));ComPtr<IStorageFolder> pFolder;pKnownFolders->get_VideosLibrary(&pFolder);ComPtr<IUnknown> pUnk;pFolder->CreateFileAsync(HStringReference(L"123.mp4").Get(),CreationCollisionOption::CreationCollisionOption_ReplaceExisting,(__FIAsyncOperation_1_Windows__CStorage__CStorageFile**)pUnk.GetAddressOf());ComPtr<IAsyncInfo> pAsyncInfo;pUnk->QueryInterface(IID_PPV_ARGS(pAsyncInfo.GetAddressOf()));//awaitwhile (1){AsyncStatus asyncStatus;HRESULT hr = pAsyncInfo->get_Status(&asyncStatus);if (SUCCEEDED(hr) && (asyncStatus == AsyncStatus::Completed))break;SwitchToThread();}/*ComPtr<IAsyncOperation<ABI::Windows::Storage::StorageFile*>> pNewFile;pUnk->QueryInterface(IID_PPV_ARGS(pNewFile.GetAddressOf()));ComPtr<IStorageFile> pFile;pNewFile->GetResults(pFile.GetAddressOf());*/ComPtr<IAsyncOperation_> pNewFile;pUnk->QueryInterface(IID_PPV_ARGS(pNewFile.GetAddressOf()));ComPtr<IUnknown> pTempFile;pNewFile->GetResults(pTempFile.GetAddressOf());ComPtr<IStorageFile> pFile;pTempFile->QueryInterface(IID_PPV_ARGS(pFile.GetAddressOf()));printf("CreateFile Async OK.");RoUninitialize();getchar();return 0;
}

好了,我说了那么多,我估计你应该可以写一个类似C#的await函数了。。。
所以,你还是去用C#吧。

从传统COM简析WinRT的Async(使用WRL)相关推荐

  1. java 进阶笔记线程与并发之ForkJoinPool简析

    简介 ForkJoinPool是一个线程池,支持特有的的ForkJoinTask,对于ForkJoinTask任务,通过特定的for与join方法可以优化调度策略,提高效率. 使用 通常,我们继承使用 ...

  2. 基于libmad库的MP3解码简析

    基于libmad库的MP3解码简析  MAD (libmad)是一个开源的高精度 MPEG 音频解码库,支持 MPEG-1(Layer I, Layer II 和 LayerIII(也就是 MP3). ...

  3. ceph存储原理_Ceph存储引擎BlueStore简析

    前文我们创建了一个单节点的Ceph集群,并且创建了2个基于BlueStore的OSD.同时,为了便于学习,这两个OSD分别基于不同的布局,也就是一个OSD是基于3中不同的存储介质(这里是模拟的,并非真 ...

  4. Android Handler与Looper原理简析

    一直感觉自己简直就是一个弱智,最近越来越感觉是这样了,真的希望自己有一天能够认同自己,认同自己. 本文转载于:https://juejin.im/post/59083d7fda2f60005d14ef ...

  5. Linux内核引导简析

    bootsect.S.setup.S.head.S分析 收藏 2010-01-14 13:36:34 bootsect.S,系统引导程序,一般不超过512字节. 在PC系统结构中,线性地址0xA000 ...

  6. [2020-ECCV]PIPAL-a Large-Scale Image Quality Assessment Dataset for Perceptual Image Restoration论文简析

    [2020-ECCV] PIPAL: a Large-Scale Image Quality Assessment Dataset for Perceptual Image Restoration 论 ...

  7. [2021-ICCV] MUSIQ Multi-scale Image Quality Transformer 论文简析

    [2021-ICCV] MUSIQ: Multi-scale Image Quality Transformer 论文简析 论文:https://arxiv.org/abs/2108.05997 代码 ...

  8. php mysql 命令行模式_MySQL_MYSQL导入导出sql文件简析,一.MYSQL的命令行模式的设置- phpStudy...

    MYSQL导入导出sql文件简析 一.MYSQL的命令行模式的设置 桌面->我的电脑->属性->环境变量->新建-> PATH=":path\mysql\bin ...

  9. 反病毒软件技术简析与探索(2009年5月18日)

    <下文是本人大三时期的一篇课外小论文,是基于大量的对杀毒软件杀毒能力的实验结果而写,请勿转载,谢谢.> 摘  要 为什么即使有杀毒软件的保护,还是有那么多的计算机系统遭到病毒的侵袭呢?答案 ...

最新文章

  1. keyshot怎么批量渲染_提高Keyshot逼真渲染的小技巧
  2. AI 通过眼睛的反光度,来识别是否 Deepfake 换脸
  3. 因果AI诊断模型登上nature:模拟专业医师思维,诊断罕见疾病,超越SOTA算法
  4. 计算机丢失scecli,Server 2012 R2 SceCli 事件ID:1202( 0x534)解决方案
  5. 计算机组成原理 — CPU — 缓存访问
  6. pc端WINCE的安装包
  7. WinCE串口蓝牙的实现 .
  8. 每天拿起手机100次,使用7小时?iOS 12告诉你时间都去哪儿了
  9. 信息学奥赛一本通(2038:【例5.5】最大数位置)
  10. 计算机编程输入3个数排序,汇编语言 输入10个数排序并输出的实现
  11. 关于网站那些不得不说的小秘密
  12. python day 02
  13. java设计模式案例详解:观察者模式
  14. oracle批量更新之使用游标进行分批次更新的5种方式及速度比对
  15. acm 用java_acm竞赛中使用java是一种什么体验?
  16. 被问到最多的淘口令API调用方法
  17. 华三华为无线系列排障-----AP间无法实现自动漫游
  18. Google Map MarkerCluster 点聚合使用简介
  19. HashMap的fast-fail和ConcurrentHashMap的fail-safe实例
  20. 算法导论课后题和思考题 第3章

热门文章

  1. CSharp生成二维条码的步骤
  2. 进阶技术 - 如何实现跨进程传递大图?(腾讯面试题)
  3. 【PHP实例】使用GD2函数在图片上添加文字
  4. 从零开始免费搭建自己的博客(一)——本地搭建hexo框架
  5. 膨胀卷积神经网络_用膨胀的卷积神经网络生成钢琴音乐
  6. MongoError: Cannot use a session that has ended ---- NodeJs报错
  7. CCNU ACM 2016夏季集训·day1比赛
  8. 南网电费接口API文档分享
  9. arcgis中hgt格式的dem数据tiff转换
  10. 解决mysql 找不到 my.ini文件的问题