cemu-project / Cemu

Cemu - Wii U emulator
https://cemu.info
Mozilla Public License 2.0
6.6k stars 506 forks source link

RDP support #1238

Open TcpLink-2024 opened 2 weeks ago

TcpLink-2024 commented 2 weeks ago

Your suggestion

Cemu crashes ( or hangs ) when launching games over RDP ( standard Microsoft desktop remote on almost every Windows ). Crashing ( or hanging ) is kinda not expected by user, because app itself with game list launched just fine. Of course developing OpenGL ( or Vulkan ) app that correctly runs over RDP may be too big of a project. But there's more simple solution - detect RDP in code and at least warn user or prohibit launch of game and post info about that in log.txt, so not crushing or hanging.

Also there's alternative approach ( which I use ) to smooth user experience, during launching game if there's RDP session, connect that session to console session ( that session got full access to videocard drivers etc ) and then user could after some timeout ( 5 - 10 seconds that required for Cemu to initialize OpenGL or Vulkan support ) reconnect to RDP session and play ( or debug in Visual Studio ) running game over RDP.

Connecting user remote session to console session requires Admin rights, so Cemu ( or Visual Studio ) should be launched with Admin rights for such approach. Alternative solution is before launching game, in case of remote session, launch ( fork ) small separate exe with admin rights in manifest that then asks User permission by UAC, that separate exe ( if permitted by user ) connects remote session to console session, and Cemu checks again if there's no remote session then continue launching game. In that scenario Cemu or Visual Studio doesn't require to be launched with Admin rights.

src\gui\MainWindow.cpp
#if BOOST_OS_WINDOWS
#include "WtsApi32.h"
#define exit(__c) ExitProcess(__c)
#else
#define exit(__c) _Exit(__c)
#endif

...

#if BOOST_OS_WINDOWS
void ConnectConsoleSessionIfRemoteSession()
{

    if (!GetSystemMetrics(SM_REMOTESESSION)) // detects if app running over remote desktop session
        return;

    PWTS_SESSION_INFO session; DWORD count;
    WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &session, &count);

    DWORD console = 0;
    for ( int i = 0; i < count; i ++ )
    {
        if (!wcscmp(session[i].pWinStationName, L"Console"))
        {
            console = session[i].SessionId;
            break;
        }
    }
    WTSFreeMemory(session);

    DWORD current = 0;

    LPWSTR buffer; DWORD size;
    WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSSessionId, &buffer, &size);
    current = buffer[0];
    WTSFreeMemory(buffer);

    WCHAR password[1]{};
    WTSConnectSession(current, console, password, TRUE); // if not admin no connection to console, but also no exception
}
#endif

void MainWindow::RequestLaunchGame(fs::path filePath, wxLaunchGameEvent::INITIATED_BY initiatedBy)
{
#if BOOST_OS_WINDOWS
    ConnectConsoleSessionIfRemoteSession();
#endif
    wxLaunchGameEvent evt(filePath, initiatedBy);
    wxPostEvent(g_mainFrame, evt);
}
...
src\gui\CMakeLists.txt
if(WIN32)
    target_link_libraries(CemuGui PRIVATE bthprops WtsApi32)
endif()