0

I am writing code to consume WinRT API on Windows 10 using C++ WRL (i.e. without using either C++/CX or C++/CLI). I am using GetAppListEntriesAsync() from Package class to get names of UWP applications installed on a system. GetAppListEntriesAsync() calls a callback method asynchronously. I want to wait till all such asynchronous methods have finished. Unlike C++/CX WRL doesn't have any await keyword to wait on asynchronous tasks.

Details

The following code is used to get the list.

ComPtr<ABI::Windows::Foundation::__FIAsyncOperation_1___FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry_t> operation;
package3->GetAppListEntriesAsync(&operation);

package3 is pointer to type ABI::Windows::ApplicationModel::IPackage3:-

ComPtr<ABI::Windows::ApplicationModel::IPackage3> package3;

I invoke the asynchronous operation as follows.

operation->put_Completed(cb.Get())

Where cb holds reference to callback function that GetAppListEntriesAsync() calls asynchronously. (see update2)

There are several such asynchronous operations which are invoked. I want to run a piece of code which should run only after all such asynchronous callbacks have completed. C++/CX has await keyword for doing a wait on asynchronous tasks. How should I do the same using WRL C++? I tried using WaitForSingleObject() but it doesn't seem to work.

A very brute approach would be to keep checking status of every asynchronous operation in a while loop.

ComPtr<ABI::Windows::Foundation::IAsyncInfo> ai;
operation.As(&ai);
while (true) 
{
ai->get_Status(&status);
if (status == Started) 
{
continue;
}
else
{
break;
}
}

I am not sure if this is guaranteed to work, or whether if it will incur performance penalty. The COM apartment type for my code is APTTYPE_STA (note sure if this piece of information is relevant to the question; I wanted to set is to RO_INIT_MULTITHREADED but RoInitialize() fails, however WRL code seems to be working fine).

UPDATE 2:

Here is how cb (callback) is implemented.

    auto cb = wrl::Callback<ABI::Windows::Foundation::IAsyncOperationCompletedHandler<ABI::Windows::Foundation::Collections::__FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry_t *>>(
                    [](ABI::Windows::Foundation::__FIAsyncOperation_1___FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry_t * ppp, AsyncStatus status) -> HRESULT 
{
    <do something in callback>;
    SetEvent(threadCompleted.Get());
}

Trying to implement IAgileObject.

To make my callback implement IAgileObject I will have to use Implements<> WRL template class. so callback would be something like auto cb = Callback<Implements<IAgileObject,...>> but the problem is that IAsyncOperationCompletedHandler<ABI::Windows::Foundation::Collections::__FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry_t *> doesn't derive from IInspectable, hence using Implements on that :-

Callback<Implements<ABI::Windows::Foundation::IAsyncOperationCompletedHandler<ABI::Windows::Foundation::Collections::__FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry_t *>,IAgileObject>> gives the following error (Visual Studio 2017).

Error C2338 'I' has to derive from 'IWeakReference', 'IWeakReferenceSource' or 'IInspectable' AsyncTask c:\sw\tools\sdk\winsdk\win10\include\winrt\wrl\implements.h 413

Sahil Singh
  • 3,352
  • 39
  • 62
  • 1
    https://msdn.microsoft.com/en-us/library/hh973451.aspx – Hans Passant Aug 04 '17 at 22:58
  • Hi I tried the solution given on the link. **1.** created event object `Event threadCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS));` **2.** passed reference to callback handler, which does `SetEvent(threadCompleted.Get());` **3.** waited on it `WaitForSingleObjectEx(threadCompleted.Get(), INFINITE, FALSE);` The program is going into infinite hang, the callback is never called. Can it be because my COM appartment is STA, instead of MTA? – Sahil Singh Aug 05 '17 at 18:56
  • The apartment type seems to be the reason. I created a new where I was able to set the apartment type to MTA, and the code no longer hanged, but when I changed to STA, it did hang; – Sahil Singh Aug 05 '17 at 20:36
  • 1
    Make sure your callback responds to QueryInterface for IAgileObject. When an operation completes, it checks whether the callback is agile, and if it is, it calls it directly from the thread where it was completed. However, if the callback says E_NOINTERFACE for IAgileObject, it will then queue up the callback to the STA thread. The reason it hangs is that you block on your STA thread and the callback never gets called (even though it's queued up and waiting to be executed). – Sunius Aug 05 '17 at 21:58
  • @Sunius Implmenting `IAgileObject` may not be possible in my code. Please see **Update 2** above. – Sahil Singh Aug 06 '17 at 09:19
  • 1
    Ah, if you're using WRL::Callback, instead of IAgileObject, use FtmBase. It properly handles being in Implements<> template. – Sunius Aug 06 '17 at 18:49
  • @Sunius Actually the problem is that `__FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry_t ` cannot be used with implements. For now I have created a new thread for all WRL related processing, and in the new thread I am able to set apartment type as MTA, and `WaitForSingleObjectEx()` no longer stalls the whole program. – Sahil Singh Aug 07 '17 at 07:52
  • @Sunius You seem to have quite good knowledge about WRL. WRL/COM are very new concepts for me, I come from a LInux background. Is there a book which I can refer to? I would really like to study WRL in depth. I am reading `Mastering Windows 8 C++ App Development` right now, it has some sections on WRL, but it's not the main focus of the book. – Sahil Singh Aug 07 '17 at 07:55
  • 1
    Oops, looks like I forgot one crucial bit here. You also need to specify RuntimeClassFlags for this to work. It should be `Callback, IAsyncOperationCompletedHandler*>, FtmBase>>` As for WRL resources.. I just learned it by looking at code and trying to make it work. I don't know if there are any books out there that cover it. – Sunius Aug 07 '17 at 17:09
  • If you want to avoid WRL and just use "pure" C++, you can use the [C++/WinRT projection](http://moderncpp.com). – Peter Torr - MSFT Nov 04 '17 at 21:25

0 Answers0