Search code examples
c++winapiconcurrencymanaged-c++shfileoperation

Exception in Concurrency task.then.wait affects further call of ::ShellExecuteEx()


Following logic is implemented to open a file by a "filename.extension" in a C++ application using managed-C++:

try
{
    CoInitialize(nullptr);
    auto task = Concurrency::create_task(Windows::Storage::StorageFile::GetFileFromPathAsync(filePath));
    // an excpetion is thrown in the next line
    Concurrency::task_status status = task.then([&](Windows::Storage::StorageFile^ file){
        if (file != nullptr)
        {
            concurrency::task<bool> launchFileOperation(Windows::System::Launcher::LaunchFileAsync(file));
            launchFileOperation.then([&](bool success)
            {
                if (!success)
                    return 0;
            }).wait();
        }
    }).wait();
}
catch (...)
{
    CoUninitialize(); // an exeption is catched
    return 0;
}

Since the above code throws an exception, we go further to an alternative file open approach via ::ShellExecuteEx

SHELLEXECUTEINFO exec_info = {0};
exec_info.cbSize = sizeof exec_info;
exec_info.fMask  = SEE_MASK_NOCLOSEPROCESS
                | SEE_MASK_DOENVSUBST;   

exec_info.fMask &= ~SEE_MASK_NOASYNC;
exec_info.lpVerb = "open";
exec_info.lpFile = full_path_str;
exec_info.nShow  = SW_SHOW;

bool result_b = ::ShellExecuteEx(&exec_info) ? true : false;

The ::ShellExecuteEx fails and ends up in Microsofts ppltasks.h _REPORT_PPLTASK_UNOBSERVED_EXCEPTION();.

::ShellExecuteEx works correctly if the managed-C++ Concurrency::create_task approach is removed.

Why does Concurrency::create_task affect the further call of ::ShellExecuteEx?

This issue appears only in release build.


Solution

  • Adding try/catch-blocks to the innermost .wait()-block solved the issue

    try {
    
       concurrency::task<bool> launchFileOperation(Windows::System::Launcher::LaunchFileAsync(file));
       launchFileOperation.then([&](bool success) {
          // logic
          }).wait();
    }
    catch (concurrency::invalid_operation& ex) 
    {
        ... 
    }
    catch (concurrency::task_canceled& ex) 
    {
        ...
    }