Search code examples
c#windowswinformsremote-desktoprdp

Why ,when executing mstsc.exe (remote desktop) from c# , the process HasExited = true and doesnt have MainWindowHandle


My main goal is to open remote desktop and release it back when the remote session is ended. I am tryng to host Mstsc.exe in winform application , so I will manage the closing of the process and send release command to the remote PC. this can be done by batch file:

for /f "skip=1 tokens=3" %%s in ('query user %USERNAME%') do (  %windir%\System32\tscon.exe %%s /dest:console)

The c# code:

[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

Add the cratential of the remote PC

        Process p = Process.Start(Environment.ExpandEnvironmentVariables(@"C:\Windows\system32\cmdkey.exe "), string.Format(" /generic:TERMSRV/{0} /user:{1} /pass:{2}", host, userName, password));

Open remote desktop:

        Process mainP = Process.Start(@"C:\Windows\system32\mstsc.exe ", (" /v " + host));
        mainP.Exited += P_Exited;
        while (mainP.MainWindowHandle ==null || mainP.MainWindowHandle == IntPtr.Zero)
        {
            Thread.Sleep(20);
            //mainP.Refresh();

        }
        Console.WriteLine(mainP.MainWindowHandle);
        SetParent(mainP.MainWindowHandle, panel1.Handle);

MainWindowHandle is always zero , If I refresh the process I get exceptions. mainP.HasExited is true altought mstsc is open. How can I get MainWindowHandle of MSTSC.exe ?

Thanks


Solution

  • The Remote Desktop client seems to be implemented in such a way that, when launched using command-line arguments, it will process the arguments, start a separate process (if the arguments are valid) and then terminate the original process.

    This means that you will need a Process instance that represents the new process in order to get the handle to its main window.

    Adding to your original code:

    Process mainP = Process.Start(@"C:\Windows\system32\mstsc.exe ", (" /v " + "CLSERVER"));
    mainP.WaitForExit();
    mainP.Dispose();
    Process otherP;
    while ((otherP = Process.GetProcessesByName("mstsc").FirstOrDefault()) == null) {
        Thread.Sleep(20);
    }
    otherP.Exited += P_Exited;
    while (otherP.MainWindowHandle == IntPtr.Zero) {
        Thread.Sleep(20);
    }
    Console.WriteLine(otherP.MainWindowHandle);
    SetParent(otherP.MainWindowHandle, panel1.Handle);
    

    I was able to successfully get the handle when using the above code, however it does not account for multiple instances of mstsc.exe - if you need to distinguish between them, you will need to examine the processes more closely (maybe look at MainWindowTitle?).