2017-08-11 126 views
1

this question相关,我试图实现一个使用WinRT API设置桌面墙纸的过程。为了模仿C#中的await功能,我使用了TTask.Futurelink),如herehere所述。德尔福 - 使用TTask.Future异步调用WinRT API

我的实现看起来是这样的:

class procedure TUtilityWin.SetWallpaper(AFileName: String); 
var 
    lStorageFile: IStorageFile; 
    liao_storagefile: IAsyncOperation_1__IStorageFile; 
    lFutureTask: IFuture<IAsyncOperation_1__IStorageFile>; 
begin 
    //WinRT Implementation 
    if TUserProfile_UserProfilePersonalizationSettings.IsSupported then 
    begin 
    lFutureTask:=TTask.Future<IAsyncOperation_1__IStorageFile>(
          function: IAsyncOperation_1__IStorageFile 
          begin 
          Result:=TStorageFile.GetFileFromPathAsync(HSTRING(AFileName)); 
          end); 
    liao_storagefile:=lFutureTask.Value; 
    lStorageFile:=liao_storagefile.GetResults; 
    TUserProfile_UserProfilePersonalizationSettings.Current.TrySetWallpaperImageAsync(lStorageFile); 
    end; 
end; 

按我的理解,当我试图让lFutureTask.Value,应用程序挂起当前线程,直到lFutureTask完成(如果没有的话),然后提供的价值。但是,当我运行该应用程序时,出现错误消息:EOleException with message 'A method was called at an unexpected time'。休息是在这条线上:lStorageFile:=liao_storagefile.GetResults;

我是TTask以及WinRT API的新手 - 所以我确定我缺少一些非常基本的东西。将不胜感激任何指针什么会导致这一点,或者我可以做什么不同来解决这个问题。提前致谢。

+0

我可能会误解,但'IAsyncOperation_1__IStorageFile'似乎已经代表一个异步操作,您可能会嵌套它们。尝试省略'IFutureTask'并使用'IAsyncOperation_1__IStorageFile'的'Completed'事件。 – nil

回答

0

我看了一下你的问题中链接的Delphi文档,AFAICT ITaskIFuture只代表在单独的线程上执行的方法(我称之为“委托任务”)。似乎没有任何支持异步任务(我称之为“Promise Tasks”)。 IAsyncOperation<T>是代表异步任务的WinRT类型,因此存在您遇到的问题。特别是,似乎没有任何德尔福支持在他们的“任务”上注册延续。

所以,除非有一些Delphi支持非线程的Future/Promise,否则你将不得不阻止一个线程。

目前,您的代码正在启动一个线程任务,只有启动的异步操作(GetFileFromPathAsync)。线程任务是而不是等待异步操作完成(IAsyncOperation<T>.Completed),以便任务在开始操作后立即完成,然后外部代码在操作没有结果时调用GetResult,导致异常。

因此,要解决这个问题,您需要一种方法来让线程化任务阻塞,直到异步操作完成。由于WinRT类型纯粹是异步的(不支持同步),并且由于Delphi类型是纯同步的(不支持异步),所以你必须自己搭桥。最好的解决方案可能是Delphi的等效的ManualResetEvent。

像这样的东西应该工作:

class procedure TUtilityWin.SetWallpaper(AFileName: String); 
var 
    lStorageFile: IStorageFile; 
    lFutureTask: IFuture<IStorageFile>; 
begin 
    if TUserProfile_UserProfilePersonalizationSettings.IsSupported then 
    begin 
    lFutureTask:=TTask.Future<IStorageFile>(
     function: IStorageFile 
     var 
      liao_storagefile: IAsyncOperation_1__IStorageFile; 
      mre: ManualResetEvent; 
      result: IStorageFile; 
     begin 
      mre:= // Create ManualResetEvent 
      liao_storagefile:=TStorageFile.GetFileFromPathAsync(HSTRING(AFileName)); 
      liao_storagefile.Completed... // Add handler that will set `result` and then set the ManualResetEvent 
      mre.Wait(); // Wait for the ManualResetEvent to be set 
      Result:=result; 
     end); 
    liao_storagefile:=lFutureTask.Value; 
    lStorageFile:=liao_storagefile.GetResults; 
    TUserProfile_UserProfilePersonalizationSettings.Current.TrySetWallpaperImageAsync(lStorageFile); 
    end; 
end; 

对不起,我不知道德尔福,但希望这会给你一个大方向。