Looks like we have a solution for our bring to foreground problem.
authorStephaneLenclud
Wed, 18 Mar 2015 21:47:06 +0100
changeset 1299d5867ce966a
parent 128 2e0571e50ab3
child 130 c8d81bfa5fff
Looks like we have a solution for our bring to foreground problem.
Server/MainForm.Hid.cs
Server/SharpDisplayManager.csproj
     1.1 --- a/Server/MainForm.Hid.cs	Wed Mar 18 20:38:59 2015 +0100
     1.2 +++ b/Server/MainForm.Hid.cs	Wed Mar 18 21:47:06 2015 +0100
     1.3 @@ -14,22 +14,26 @@
     1.4  namespace SharpDisplayManager
     1.5  {
     1.6  	[System.ComponentModel.DesignerCategory("Code")]
     1.7 -	public class MainFormHid: Form
     1.8 +	public class MainFormHid : Form
     1.9  	{
    1.10  
    1.11  		[DllImport("USER32.DLL")]
    1.12  		public static extern bool SetForegroundWindow(IntPtr hWnd);
    1.13  
    1.14  		[DllImport("USER32.DLL")]
    1.15 -		public static extern bool BringWindowToTop(IntPtr hWnd);
    1.16 +		public static extern IntPtr GetForegroundWindow();
    1.17  
    1.18 -		[DllImport("USER32.DLL")]
    1.19 -		public static extern bool IsIconic(IntPtr hWnd);
    1.20 +		[System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "GetWindowThreadProcessId")]
    1.21 +		public static extern uint GetWindowThreadProcessId([System.Runtime.InteropServices.InAttribute()] System.IntPtr hWnd, System.IntPtr lpdwProcessId);
    1.22  
    1.23 -		[DllImport("USER32.DLL")]
    1.24 -		public static extern bool OpenIcon(IntPtr hWnd);
    1.25 +		[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "GetCurrentThreadId")]
    1.26 +		public static extern uint GetCurrentThreadId();
    1.27  
    1.28 +		[System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "AttachThreadInput")]
    1.29 +		[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
    1.30 +		public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] bool fAttach);
    1.31  
    1.32 +		//
    1.33  		public delegate void OnHidEventDelegate(object aSender, Hid.Event aHidEvent);
    1.34  
    1.35  		/// <summary>
    1.36 @@ -37,6 +41,9 @@
    1.37  		/// </summary>
    1.38  		private Hid.Handler iHidHandler;
    1.39  
    1.40 +		/// <summary>
    1.41 +		/// Register HID devices so that we receive corresponding WM_INPUT messages.
    1.42 +		/// </summary>
    1.43  		protected void RegisterHidDevices()
    1.44  		{
    1.45  			// Register the input device to receive the commands from the
    1.46 @@ -96,6 +103,11 @@
    1.47  			iHidHandler.OnHidEvent += HandleHidEventThreadSafe;
    1.48  		}
    1.49  
    1.50 +		/// <summary>
    1.51 +		/// Here we receive HID events from our HID library.
    1.52 +		/// </summary>
    1.53 +		/// <param name="aSender"></param>
    1.54 +		/// <param name="aHidEvent"></param>
    1.55  		public void HandleHidEventThreadSafe(object aSender, SharpLib.Hid.Event aHidEvent)
    1.56  		{
    1.57  			if (aHidEvent.IsStray)
    1.58 @@ -116,14 +128,13 @@
    1.59  				if (aHidEvent.Usages.Count > 0
    1.60  					&& aHidEvent.UsagePage == (ushort)Hid.UsagePage.WindowsMediaCenterRemoteControl
    1.61  					&& aHidEvent.Usages[0] == (ushort)Hid.Usage.WindowsMediaCenterRemoteControl.GreenStart)
    1.62 -					//&& aHidEvent.UsagePage == (ushort)Hid.UsagePage.Consumer
    1.63 -					//&& aHidEvent.Usages[0] == (ushort)Hid.Usage.ConsumerControl.ThinkPadFullscreenMagnifier)
    1.64 -
    1.65 +				//&& aHidEvent.UsagePage == (ushort)Hid.UsagePage.Consumer
    1.66 +				//&& aHidEvent.Usages[0] == (ushort)Hid.Usage.ConsumerControl.ThinkPadFullscreenMagnifier)
    1.67  				{
    1.68  					//First check if the process we want to launch already exists
    1.69  					string procName = Path.GetFileNameWithoutExtension(Properties.Settings.Default.StartFileName);
    1.70  					Process[] existingProcesses = Process.GetProcessesByName(procName);
    1.71 -					if (existingProcesses == null || existingProcesses.Length==0)
    1.72 +					if (existingProcesses == null || existingProcesses.Length == 0)
    1.73  					{
    1.74  						// Process do not exists just try to launch it
    1.75  						ProcessStartInfo start = new ProcessStartInfo();
    1.76 @@ -136,27 +147,68 @@
    1.77  						start.UseShellExecute = true;
    1.78  						// Run the external process & wait for it to finish
    1.79  						Process proc = Process.Start(start);
    1.80 -						
    1.81 +
    1.82  						//SL: We could have used that too
    1.83  						//Shell32.Shell shell = new Shell32.Shell();
    1.84  						//shell.ShellExecute(Properties.Settings.Default.StartFileName);
    1.85  					}
    1.86  					else
    1.87  					{
    1.88 -						BringWindowToTop(existingProcesses[0].MainWindowHandle);
    1.89 -						SetForegroundWindow(existingProcesses[0].MainWindowHandle);
    1.90 -						if (IsIconic(existingProcesses[0].MainWindowHandle))
    1.91 -						{
    1.92 -							OpenIcon(existingProcesses[0].MainWindowHandle);
    1.93 -						}
    1.94 -						BringWindowToTop(existingProcesses[0].MainWindowHandle);
    1.95 -						SetForegroundWindow(existingProcesses[0].MainWindowHandle);
    1.96 -					}			
    1.97 +						ForceForegroundWindow(existingProcesses[0].MainWindowHandle);
    1.98 +					}
    1.99  				}
   1.100  			}
   1.101  		}
   1.102  
   1.103 -		
   1.104 +
   1.105 +		/// <summary>
   1.106 +		/// For the Window with the given handle to the foreground no matter what.
   1.107 +		/// That works around flashing Window issues.
   1.108 +		/// As seen on http://www.asyncop.com/MTnPDirEnum.aspx?treeviewPath=[o]+Open-Source\WinModules\Infrastructure\SystemAPI.cpp
   1.109 +		/// </summary>
   1.110 +		/// <param name="hTo"></param>
   1.111 +		/// <returns></returns>
   1.112 +		IntPtr ForceForegroundWindow(IntPtr hTo)
   1.113 +		{
   1.114 +			if (hTo == IntPtr.Zero)
   1.115 +			{
   1.116 +				return IntPtr.Zero;
   1.117 +			}
   1.118 +			IntPtr hFrom = GetForegroundWindow();
   1.119 +
   1.120 +			if (hFrom != IntPtr.Zero)
   1.121 +			{
   1.122 +				SetForegroundWindow(hTo); 
   1.123 +				return IntPtr.Zero;
   1.124 +			}
   1.125 +			if (hTo == hFrom)
   1.126 +			{
   1.127 +				return IntPtr.Zero;
   1.128 +			}
   1.129 +
   1.130 +			uint pid = GetWindowThreadProcessId(hFrom, IntPtr.Zero);
   1.131 +			uint tid = GetCurrentThreadId();
   1.132 +			if (tid == pid)
   1.133 +			{
   1.134 +				SetForegroundWindow(hTo);
   1.135 +				return (hFrom);
   1.136 +			}
   1.137 +			if (pid != 0)
   1.138 +			{
   1.139 +				if (!AttachThreadInput(tid, pid, true))
   1.140 +				{
   1.141 +					return IntPtr.Zero;
   1.142 +				}
   1.143 +				SetForegroundWindow(hTo);
   1.144 +				AttachThreadInput(tid, pid, false);
   1.145 +			}
   1.146 +			return (hFrom);
   1.147 +		}
   1.148 +
   1.149 +		/// <summary>
   1.150 +		/// We need to handle WM_INPUT.
   1.151 +		/// </summary>
   1.152 +		/// <param name="message"></param>
   1.153  		protected override void WndProc(ref Message message)
   1.154  		{
   1.155  			switch (message.Msg)
     2.1 --- a/Server/SharpDisplayManager.csproj	Wed Mar 18 20:38:59 2015 +0100
     2.2 +++ b/Server/SharpDisplayManager.csproj	Wed Mar 18 21:47:06 2015 +0100
     2.3 @@ -31,7 +31,7 @@
     2.4      <CreateWebPageOnPublish>true</CreateWebPageOnPublish>
     2.5      <WebPage>index.htm</WebPage>
     2.6      <OpenBrowserOnPublish>false</OpenBrowserOnPublish>
     2.7 -    <ApplicationRevision>3</ApplicationRevision>
     2.8 +    <ApplicationRevision>4</ApplicationRevision>
     2.9      <ApplicationVersion>0.3.2.%2a</ApplicationVersion>
    2.10      <UseApplicationTrust>false</UseApplicationTrust>
    2.11      <CreateDesktopShortcut>true</CreateDesktopShortcut>