Search code examples
c#visual-studio-2010winapitask-switching

VisualStudio debugging required for window switching


A bit of background on what I am making first. It is a C# based launcher program which allows easy switching between the main home theatre media players (in my case, Plex, MediaPortal and Kodi), so that they can all be used for their individual merits (Plex for downloaded content, MediaPortal for TV recordings and live TV, and Kodi for everything else, usually streaming).
These applications are suspended using pssuspend which means they can all stay open at once, which is great for slow computers.

Users press a button (on their remote) to switch back to the launcher to choose another application.

I am almost at a usable version but I have had an issue for a while that I've narrowed down.

If my launcher switches into an application (using the methods mentioned below), I cannot switch back to my launchers process.

This only happens when:

  • VisualStudio is not debugging or the "Visual Studio hosting process" (the vshost version of the process) is not running.
  • Keyboard / remote input has been applied to the application being switched to
    • ie: if I down move anywhere to the application switched to I can go back to the launcher fine, but as soon as I press anything else within the application I can't switch out.
  • Switching out of an application that was switched to, not into it from the launcher.

At all other times, everything works as expected.

To switch, I am currently using SwitchToThisWindow(IntPtr hWnd, bool fAltTab) (from http://www.pinvoke.net/default.aspx/user32/SwitchToThisWindow.html). I have also used Microsoft.VisualBasic.Interaction.AppActivate (from http://msdn.microsoft.com/en-us/library/x9784w8e(v=vs.100).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1).

Both of these have the same results.

Things I have confirmed are NOT related to the issue:

  • pssuspend: if I run without suspending the application before switching back to the launcher, the same thing happens
  • Operating system and computer: I have the same issue occurring across 3 computers, my Windows 8 install and two Windows 7 installs
  • the listener to return to the home-screen: this is using UDP broadcast from EventGhost and does everything else that needs to be done such as updating the interface on the launcher, just doesn't switch to the launcher
  • compiling on the local machine: I initially thought this helped, but it was just because of the above situation. A version compiled on my Windows 8 machine works fine on Windows 7 as long as that vshost process is open. I have not tried on any other systems.
    • running as administrator did not have an effect

Something that shouldn't be an issue but should be noted just in case, is that the frontend of the launcher is all using CefSharp (CEF is an integrated version of the Chrome browser). Although the issue was occurring before this was added.

My Potential thoughts:

  • Because of things mentioned in AppActivate, I realised the UIPermission level may matter, however setting it manually to full trust doesn't make any change.
    I also realised in VisualStudio, the properties for "Security" is set to use "OneClick Security" settings and is on "This is a full trust application" option. This makes sense to me as the debugger would give it these elevated permissions, but presumably this should work without debugging running.

Some code of my app switching in context:

[DllImport("user32.dll", SetLastError = true)]
static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);

static Process currentProcess = Process.GetCurrentProcess();  
public static void SwitchToApplication(Process toSwitchTo)
{
    SwitchProcess(toSwitchTo);
}

public static void SwitchToLauncher()
{
    FrontendBridge.GetInstance().Reset();
    SwitchProcess(Process.GetCurrentProcess());
    Taskbar.Hide();
}

private static void SwitchProcess(Process toSwitchTo)
{
    if (currentProcess == toSwitchTo)
        return;

    if (toSwitchTo.MainWindowHandle != IntPtr.Zero)
    {
        SwitchToThisWindow(toSwitchTo.MainWindowHandle,true);
    }
    currentProcess = toSwitchTo;
}

Hopefully someone has some ideas or has had a similar issue in the past.
Please let me know if you need any additional information or bits of source code.


Solution

  • So I managed to fix this.

    It turns out the issue isn't due to any of my code surrounding those API calls, or the applications that were being switched to themselves.

    The breakthrough answer was from here:
    http://www.codeproject.com/Tips/76427/How-to-bring-window-to-top-with-SetForegroundWindo

    This explained how when debugging you are allowed to set foreground window, but without debugging the window must be the last one to get keyboard input or else it won't have focus.

    The solution was for code to hold the alt key to have windows allow my program to set the foreground window, then SetForegroundWindow or SwitchToThisWindow (I had better results with this one when switching to something that may not be open yet) could be used.

    I found an example of someone using this code here:
    http://csharpapprentice.blogspot.co.nz/2013/03/ok-ok-its-c.html