Search code examples
c++uwpprocessc++-winrt

Access is denied - UWP full trust process


I have a UWP C++/WinRT app and a C++/WinRT console application.


The UWP app uses the FullTrustProcessLauncher to launch the console application, and the console application is supposed to launch an arbitrary .exe file on the system, e.g. cmd.exe.


The whole code of the console application is here:

#include "pch.h"
#include <iostream>

int main()
{
    winrt::init_apartment();

    try
    {
        winrt::Windows::System::ProcessLauncher::RunToCompletionAsync(L"cmd.exe", L"").get();
    }
    catch (const winrt::hresult_error& err)
    {
        std::cout << winrt::to_string(err.message()) << std::endl;
    }

    std::cin.get();
}

and pch.h includes winrt/Windows.Foundation as well as winrt/Windows.System.h.


The UWP app can successfully launch the console application, but the console application seems unable to launch the .exe file, with E_ACCESSDENIED.


Am I wrong in thinking the console application should be able to launch arbitrary .exe files being a full-trust process?

If not, how can I fix the Access is denied error?


Solution

  • Not all Windows Runtime APIs are supported in the context of Win32 'classic' desktop apps as they are intended only for use in the "AppContainer" context of the Universal Windows Platform (UWP).

    For a Win32 desktop application, the best solution is to use ShellExecuteEx. This function handles User Account Control (UAC) elevation if needed where as CreateProcess will fail if the caller and the target aren't the same.

    // Get working directory from executable path.
    wchar_t szDirectory[MAX_PATH] = {};
    wcscpy_s( szDirectory, szExePath );
    PathRemoveFileSpec( szDirectory );
    
    SHELLEXECUTEINFOW info = {};
    info.cbSize = sizeof( info );
    info.lpVerb = L"open";
    info.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS;
    info.lpFile = szExePath;
    info.lpParameters = szExeArgs;
    info.lpDirectory = szDirectory;
    info.nShow = SW_SHOW;
    if( !ShellExecuteExW( &info ) )
        // Error
    

    At this point you check wait on the info.hProcess handle or just to check if the target program has finished.

    If you need the exit code, use:

    DWORD exitCode;
    GetExitCodeProcess( info.hProcess, &exitCode );
    

    Be sure to not leak the handle by calling CloseHandle( info.hProcess );. If you don't care about waiting or exit code, just don't use SEE_MASK_NOCLOSEPROCESS. If you want it to be fully asynchronous, don't use SEE_MASK_NOASYNC.