StephaneLenclud@125: using System;
StephaneLenclud@126: using System.IO;
StephaneLenclud@125: using System.Collections.Generic;
StephaneLenclud@125: using System.Linq;
StephaneLenclud@125: using System.Text;
StephaneLenclud@125: using System.Threading.Tasks;
StephaneLenclud@125: using System.Diagnostics;
StephaneLenclud@125: using System.Runtime.InteropServices;
StephaneLenclud@125: using System.Windows.Forms;
StephaneLenclud@150: using Microsoft.Win32.SafeHandles;
StephaneLenclud@155: using System.ComponentModel;
StephaneLenclud@125: //
StephaneLenclud@125: using Hid = SharpLib.Hid;
StephaneLenclud@125: using SharpLib.Win32;
StephaneLenclud@125: 
StephaneLenclud@125: namespace SharpDisplayManager
StephaneLenclud@125: {
StephaneLenclud@138:     /// <summary>
StephaneLenclud@138:     /// Implement handling of HID input reports notably to be able to launch an application using the Green Start button from IR remotes.
StephaneLenclud@138:     /// </summary>
StephaneLenclud@131:     [System.ComponentModel.DesignerCategory("Code")]
StephaneLenclud@131:     public class MainFormHid : Form
StephaneLenclud@131:     {
StephaneLenclud@131:         [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SwitchToThisWindow")]
StephaneLenclud@131:         public static extern void SwitchToThisWindow([System.Runtime.InteropServices.InAttribute()] System.IntPtr hwnd, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] bool fUnknown);
StephaneLenclud@131:         //
StephaneLenclud@131:         public delegate void OnHidEventDelegate(object aSender, Hid.Event aHidEvent);
StephaneLenclud@126: 
StephaneLenclud@131:         /// <summary>
StephaneLenclud@131:         /// Use notably to handle green start key from IR remote control
StephaneLenclud@131:         /// </summary>
StephaneLenclud@131:         private Hid.Handler iHidHandler;
StephaneLenclud@126: 
StephaneLenclud@131:         /// <summary>
StephaneLenclud@131:         /// Register HID devices so that we receive corresponding WM_INPUT messages.
StephaneLenclud@131:         /// </summary>
StephaneLenclud@131:         protected void RegisterHidDevices()
StephaneLenclud@131:         {
StephaneLenclud@131:             // Register the input device to receive the commands from the
StephaneLenclud@131:             // remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp
StephaneLenclud@131:             // for the vendor defined usage page.
StephaneLenclud@128: 
StephaneLenclud@131:             RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[5];
StephaneLenclud@128: 
StephaneLenclud@131:             int i = 0;
StephaneLenclud@131:             rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.WindowsMediaCenterRemoteControl;
StephaneLenclud@131:             rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.WindowsMediaCenter.WindowsMediaCenterRemoteControl;
StephaneLenclud@131:             rid[i].dwFlags = Const.RIDEV_INPUTSINK;
StephaneLenclud@131:             rid[i].hwndTarget = Handle;
StephaneLenclud@128: 
StephaneLenclud@131:             i++;
StephaneLenclud@131:             rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.Consumer;
StephaneLenclud@131:             rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.Consumer.ConsumerControl;
StephaneLenclud@131:             rid[i].dwFlags = Const.RIDEV_INPUTSINK;
StephaneLenclud@131:             rid[i].hwndTarget = Handle;
StephaneLenclud@126: 
StephaneLenclud@131:             i++;
StephaneLenclud@131:             rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.Consumer;
StephaneLenclud@131:             rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.Consumer.Selection;
StephaneLenclud@131:             rid[i].dwFlags = Const.RIDEV_INPUTSINK;
StephaneLenclud@131:             rid[i].hwndTarget = Handle;
StephaneLenclud@125: 
StephaneLenclud@131:             i++;
StephaneLenclud@131:             rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
StephaneLenclud@131:             rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.SystemControl;
StephaneLenclud@131:             rid[i].dwFlags = Const.RIDEV_INPUTSINK;
StephaneLenclud@131:             rid[i].hwndTarget = Handle;
StephaneLenclud@125: 
StephaneLenclud@131:             i++;
StephaneLenclud@131:             rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
StephaneLenclud@131:             rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.GamePad;
StephaneLenclud@131:             rid[i].dwFlags = Const.RIDEV_INPUTSINK;
StephaneLenclud@131:             rid[i].hwndTarget = Handle;
StephaneLenclud@125: 
StephaneLenclud@131:             //i++;
StephaneLenclud@131:             //rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
StephaneLenclud@131:             //rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.Keyboard;
StephaneLenclud@131:             //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
StephaneLenclud@131:             //rid[i].hwndTarget = Handle;
StephaneLenclud@125: 
StephaneLenclud@131:             //i++;
StephaneLenclud@131:             //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls;
StephaneLenclud@131:             //rid[i].usUsage = (ushort)Hid.UsageCollection.GenericDesktop.Mouse;
StephaneLenclud@131:             //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
StephaneLenclud@131:             //rid[i].hwndTarget = aHWND;
StephaneLenclud@125: 
StephaneLenclud@125: 
StephaneLenclud@131:             iHidHandler = new SharpLib.Hid.Handler(rid);
StephaneLenclud@131:             if (!iHidHandler.IsRegistered)
StephaneLenclud@131:             {
StephaneLenclud@131:                 Debug.WriteLine("Failed to register raw input devices: " + Marshal.GetLastWin32Error().ToString());
StephaneLenclud@131:             }
StephaneLenclud@131:             iHidHandler.OnHidEvent += HandleHidEventThreadSafe;
StephaneLenclud@159: 
StephaneLenclud@131:         }
StephaneLenclud@125: 
StephaneLenclud@159: 
StephaneLenclud@159: 
StephaneLenclud@159: 
StephaneLenclud@131:         /// <summary>
StephaneLenclud@131:         /// Here we receive HID events from our HID library.
StephaneLenclud@131:         /// </summary>
StephaneLenclud@131:         /// <param name="aSender"></param>
StephaneLenclud@131:         /// <param name="aHidEvent"></param>
StephaneLenclud@131:         public void HandleHidEventThreadSafe(object aSender, SharpLib.Hid.Event aHidEvent)
StephaneLenclud@131:         {
StephaneLenclud@131:             if (aHidEvent.IsStray)
StephaneLenclud@131:             {
StephaneLenclud@131:                 //Stray event just ignore it
StephaneLenclud@131:                 return;
StephaneLenclud@131:             }
StephaneLenclud@125: 
StephaneLenclud@131:             if (this.InvokeRequired)
StephaneLenclud@131:             {
StephaneLenclud@131:                 //Not in the proper thread, invoke ourselves
StephaneLenclud@131:                 OnHidEventDelegate d = new OnHidEventDelegate(HandleHidEventThreadSafe);
StephaneLenclud@131:                 this.Invoke(d, new object[] { aSender, aHidEvent });
StephaneLenclud@131:             }
StephaneLenclud@131:             else
StephaneLenclud@131:             {
StephaneLenclud@150:                 if (aHidEvent.Usages.Count == 0)
StephaneLenclud@150:                 {
StephaneLenclud@150:                     //No usage, nothing to do then
StephaneLenclud@150:                     return;
StephaneLenclud@150:                 }
StephaneLenclud@150: 
StephaneLenclud@131:                 //We are in the proper thread
StephaneLenclud@150:                 if (aHidEvent.UsagePage == (ushort) Hid.UsagePage.WindowsMediaCenterRemoteControl)
StephaneLenclud@131:                 {
StephaneLenclud@150:                     switch (aHidEvent.Usages[0])
StephaneLenclud@131:                     {
StephaneLenclud@150:                         case (ushort)Hid.Usage.WindowsMediaCenterRemoteControl.GreenStart:
StephaneLenclud@150:                             HandleGreenStart();
StephaneLenclud@150:                             break;
StephaneLenclud@150:                         case (ushort)Hid.Usage.WindowsMediaCenterRemoteControl.Eject:
StephaneLenclud@150:                         case (ushort)Hid.Usage.WindowsMediaCenterRemoteControl.Ext2:
StephaneLenclud@150:                             HandleEject();
StephaneLenclud@150:                             break;
StephaneLenclud@131:                     }
StephaneLenclud@131:                 }
StephaneLenclud@152: 
StephaneLenclud@152:                 //Keep this for debug when only ThinkPad keyboard is available
StephaneLenclud@152:                 if (aHidEvent.UsagePage == (ushort)Hid.UsagePage.Consumer && aHidEvent.Usages[0] == (ushort)Hid.Usage.ConsumerControl.ThinkPadFullscreenMagnifier)
StephaneLenclud@152:                 {
StephaneLenclud@152:                     HandleEject();
StephaneLenclud@152:                 }
StephaneLenclud@152: 
StephaneLenclud@131:             }
StephaneLenclud@131:         }
StephaneLenclud@125: 
StephaneLenclud@151:         /// <summary>
StephaneLenclud@151:         /// 
StephaneLenclud@151:         /// </summary>
StephaneLenclud@155:         /// <param name="aPrefix"></param>
StephaneLenclud@155:         private void CheckLastError(string aPrefix)
StephaneLenclud@155:         {
StephaneLenclud@155:             string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
StephaneLenclud@155:             Debug.WriteLine(aPrefix + Marshal.GetLastWin32Error().ToString() + ": " + errorMessage);
StephaneLenclud@155:         }
StephaneLenclud@155: 
StephaneLenclud@155:         /// <summary>
StephaneLenclud@155:         /// 
StephaneLenclud@155:         /// </summary>
StephaneLenclud@151:         /// <param name="data"></param>
StephaneLenclud@151:         /// <returns></returns>
StephaneLenclud@151:         private IntPtr MarshalToPointer(object data)
StephaneLenclud@151:         {
StephaneLenclud@151:             IntPtr buf = Marshal.AllocHGlobal(
StephaneLenclud@151:                 Marshal.SizeOf(data));
StephaneLenclud@151:             Marshal.StructureToPtr(data,
StephaneLenclud@151:                 buf, false);
StephaneLenclud@151:             return buf;
StephaneLenclud@151:         }
StephaneLenclud@151: 
StephaneLenclud@151:         /// <summary>
StephaneLenclud@151:         /// 
StephaneLenclud@151:         /// </summary>
StephaneLenclud@151:         /// <returns></returns>
StephaneLenclud@152:         private SafeFileHandle OpenVolume(string aDriveName)
StephaneLenclud@150:         {
StephaneLenclud@152:             return Function.CreateFile("\\\\.\\" + aDriveName,
StephaneLenclud@150:                                SharpLib.Win32.FileAccess.GENERIC_READ,
StephaneLenclud@150:                                SharpLib.Win32.FileShare.FILE_SHARE_READ | SharpLib.Win32.FileShare.FILE_SHARE_WRITE,
StephaneLenclud@150:                                IntPtr.Zero,
StephaneLenclud@150:                                CreationDisposition.OPEN_EXISTING,
StephaneLenclud@150:                                0,
StephaneLenclud@150:                                IntPtr.Zero);
StephaneLenclud@150:         }
StephaneLenclud@150: 
StephaneLenclud@150:         /// <summary>
StephaneLenclud@150:         /// 
StephaneLenclud@150:         /// </summary>
StephaneLenclud@151:         /// <param name="aVolume"></param>
StephaneLenclud@151:         /// <returns></returns>
StephaneLenclud@151:         private bool LockVolume(SafeFileHandle aVolume)
StephaneLenclud@151:         {
StephaneLenclud@151:             //Hope that's doing what I think it does
StephaneLenclud@151:             IntPtr dwBytesReturned=new IntPtr();
StephaneLenclud@151:             //Should not be needed but I'm not sure how to pass NULL in there.
StephaneLenclud@151:             OVERLAPPED overlapped=new OVERLAPPED();
StephaneLenclud@151: 
StephaneLenclud@151:             int tries = 0;
StephaneLenclud@151:             const int KMaxTries = 100;
StephaneLenclud@151:             const int KSleepTime = 10;
StephaneLenclud@151:             bool success = false;
StephaneLenclud@151: 
StephaneLenclud@151:             while (!success && tries < KMaxTries)
StephaneLenclud@151:             {
StephaneLenclud@151:                 success = Function.DeviceIoControl(aVolume, Const.FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, dwBytesReturned, ref overlapped);
StephaneLenclud@151:                 System.Threading.Thread.Sleep(KSleepTime);
StephaneLenclud@151:                 tries++;
StephaneLenclud@151:             }
StephaneLenclud@151: 
StephaneLenclud@155:             CheckLastError("Lock volume: ");
StephaneLenclud@155: 
StephaneLenclud@151:             return success;
StephaneLenclud@151:         }
StephaneLenclud@151: 
StephaneLenclud@151:         /// <summary>
StephaneLenclud@151:         /// 
StephaneLenclud@151:         /// </summary>
StephaneLenclud@151:         /// <param name="aVolume"></param>
StephaneLenclud@151:         /// <returns></returns>
StephaneLenclud@151:         private bool DismountVolume(SafeFileHandle aVolume)
StephaneLenclud@151:         {
StephaneLenclud@151:             //Hope that's doing what I think it does
StephaneLenclud@151:             IntPtr dwBytesReturned = new IntPtr();
StephaneLenclud@151:             //Should not be needed but I'm not sure how to pass NULL in there.
StephaneLenclud@151:             OVERLAPPED overlapped=new OVERLAPPED();
StephaneLenclud@151: 
StephaneLenclud@155:             bool res = Function.DeviceIoControl(aVolume, Const.FSCTL_DISMOUNT_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, dwBytesReturned, ref overlapped);
StephaneLenclud@155:             CheckLastError("Dismount volume: ");
StephaneLenclud@155:             return res;
StephaneLenclud@151:         }
StephaneLenclud@151: 
StephaneLenclud@151: 
StephaneLenclud@151: 
StephaneLenclud@151:         /// <summary>
StephaneLenclud@151:         /// 
StephaneLenclud@151:         /// </summary>
StephaneLenclud@151:         /// <param name="aVolume"></param>
StephaneLenclud@151:         /// <param name="aPreventRemoval"></param>
StephaneLenclud@151:         /// <returns></returns>
StephaneLenclud@151:         private bool PreventRemovalOfVolume(SafeFileHandle aVolume, bool aPreventRemoval)
StephaneLenclud@151:         {
StephaneLenclud@151:             //Hope that's doing what I think it does
StephaneLenclud@151:             IntPtr dwBytesReturned = new IntPtr();
StephaneLenclud@151:             //Should not be needed but I'm not sure how to pass NULL in there.
StephaneLenclud@151:             OVERLAPPED overlapped = new OVERLAPPED();
StephaneLenclud@151:             //
StephaneLenclud@151:             PREVENT_MEDIA_REMOVAL preventMediaRemoval = new PREVENT_MEDIA_REMOVAL();
StephaneLenclud@151:             preventMediaRemoval.PreventMediaRemoval = Convert.ToByte(aPreventRemoval);
StephaneLenclud@151:             IntPtr preventMediaRemovalParam = MarshalToPointer(preventMediaRemoval);
StephaneLenclud@151: 
StephaneLenclud@151:             bool result = Function.DeviceIoControl(aVolume, Const.IOCTL_STORAGE_MEDIA_REMOVAL, preventMediaRemovalParam, Convert.ToUInt32(Marshal.SizeOf(preventMediaRemoval)), IntPtr.Zero, 0, dwBytesReturned, ref overlapped);
StephaneLenclud@155:             CheckLastError("Media removal: ");
StephaneLenclud@151:             Marshal.FreeHGlobal(preventMediaRemovalParam);
StephaneLenclud@151: 
StephaneLenclud@151:             return result;
StephaneLenclud@151:         }
StephaneLenclud@151: 
StephaneLenclud@151:         /// <summary>
StephaneLenclud@154:         /// Eject optical drive media opening the tray if any.
StephaneLenclud@151:         /// </summary>
StephaneLenclud@151:         /// <param name="aVolume"></param>
StephaneLenclud@151:         /// <returns></returns>
StephaneLenclud@154:         private bool MediaEject(SafeFileHandle aVolume)
StephaneLenclud@151:         {
StephaneLenclud@151:             //Hope that's doing what I think it does
StephaneLenclud@151:             IntPtr dwBytesReturned = new IntPtr();
StephaneLenclud@151:             //Should not be needed but I'm not sure how to pass NULL in there.
StephaneLenclud@151:             OVERLAPPED overlapped=new OVERLAPPED();
StephaneLenclud@151: 
StephaneLenclud@155:             bool res = Function.DeviceIoControl(aVolume, Const.IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, dwBytesReturned, ref overlapped);
StephaneLenclud@155:             CheckLastError("Media eject: ");
StephaneLenclud@155:             return res;
StephaneLenclud@151:         }
StephaneLenclud@151: 
StephaneLenclud@152:         /// <summary>
StephaneLenclud@154:         /// Close an optical drive tray.
StephaneLenclud@152:         /// </summary>
StephaneLenclud@152:         /// <param name="aVolume"></param>
StephaneLenclud@152:         /// <returns></returns>
StephaneLenclud@154:         private bool MediaLoad(SafeFileHandle aVolume)
StephaneLenclud@152:         {
StephaneLenclud@152:             //Hope that's doing what I think it does
StephaneLenclud@152:             IntPtr dwBytesReturned = new IntPtr();
StephaneLenclud@152:             //Should not be needed but I'm not sure how to pass NULL in there.
StephaneLenclud@152:             OVERLAPPED overlapped=new OVERLAPPED();
StephaneLenclud@152: 
StephaneLenclud@155:             bool res = Function.DeviceIoControl(aVolume, Const.IOCTL_STORAGE_LOAD_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, dwBytesReturned, ref overlapped);
StephaneLenclud@155:             CheckLastError("Media load: ");
StephaneLenclud@155:             return res;
StephaneLenclud@152:         }
StephaneLenclud@152: 
StephaneLenclud@154:         /// <summary>
StephaneLenclud@154:         /// 
StephaneLenclud@154:         /// </summary>
StephaneLenclud@154:         /// <param name="aVolume"></param>
StephaneLenclud@154:         /// <returns></returns>
StephaneLenclud@154:         private bool StorageCheckVerify(SafeFileHandle aVolume)
StephaneLenclud@154:         {
StephaneLenclud@154:             //Hope that's doing what I think it does
StephaneLenclud@154:             IntPtr dwBytesReturned = new IntPtr();
StephaneLenclud@154:             //Should not be needed but I'm not sure how to pass NULL in there.
StephaneLenclud@154:             OVERLAPPED overlapped = new OVERLAPPED();
StephaneLenclud@154: 
StephaneLenclud@154:             bool res = Function.DeviceIoControl(aVolume, Const.IOCTL_STORAGE_CHECK_VERIFY2, IntPtr.Zero, 0, IntPtr.Zero, 0, dwBytesReturned, ref overlapped);
StephaneLenclud@154: 
StephaneLenclud@155:             CheckLastError("Check verify: ");
StephaneLenclud@154: 
StephaneLenclud@154:             return res;
StephaneLenclud@154:         }        
StephaneLenclud@151:         
StephaneLenclud@151: 
StephaneLenclud@151: 
StephaneLenclud@151:         /// <summary>
StephaneLenclud@151:         /// Perform media ejection.
StephaneLenclud@151:         /// </summary>
StephaneLenclud@150:         private void HandleEject()
StephaneLenclud@150:         {
StephaneLenclud@153:             string drive = ((MainForm)this).OpticalDriveToEject();
StephaneLenclud@153:             if (drive.Length!=2)
StephaneLenclud@153:             {
StephaneLenclud@153:                 //Not a proper drive spec.
StephaneLenclud@153:                 //Probably 'None' selected.
StephaneLenclud@153:                 return;
StephaneLenclud@153:             }
StephaneLenclud@153: 
StephaneLenclud@153:             SafeFileHandle handle = OpenVolume(drive);
StephaneLenclud@151:             if (handle.IsInvalid)
StephaneLenclud@151:             {
StephaneLenclud@155:                 CheckLastError("ERROR: Failed to open volume: ");
StephaneLenclud@151:                 return;
StephaneLenclud@151:             }
StephaneLenclud@151: 
StephaneLenclud@151:             if (LockVolume(handle) && DismountVolume(handle))
StephaneLenclud@151:             {
StephaneLenclud@154:                 Debug.WriteLine("Volume was dismounted.");
StephaneLenclud@151: 
StephaneLenclud@152:                 if (PreventRemovalOfVolume(handle,false))
StephaneLenclud@151:                 {
StephaneLenclud@156:                     //StorageCheckVerify(handle);
StephaneLenclud@154: 
StephaneLenclud@156:                     DateTime before;
StephaneLenclud@156:                     before = DateTime.Now;
StephaneLenclud@156:                     bool ejectSuccess = MediaEject(handle);
StephaneLenclud@156:                     double ms = (DateTime.Now - before).TotalMilliseconds;
StephaneLenclud@156: 
StephaneLenclud@156:                     //We assume that if it take more than a certain time to for eject to execute it means we actually ejected.
StephaneLenclud@156:                     //If our eject completes too rapidly we assume the tray is already open and we will try to close it. 
StephaneLenclud@156:                     if (ejectSuccess && ms > 100)
StephaneLenclud@152:                     {
StephaneLenclud@154:                         Debug.WriteLine("Media was ejected");
StephaneLenclud@152:                     }
StephaneLenclud@154:                     else if (MediaLoad(handle))
StephaneLenclud@154:                     {
StephaneLenclud@154:                         Debug.WriteLine("Media was loaded");
StephaneLenclud@154:                     }                    
StephaneLenclud@151:                 }
StephaneLenclud@151:             }
StephaneLenclud@154:             else
StephaneLenclud@154:             {
StephaneLenclud@154:                 Debug.WriteLine("Volume lock or dismount failed.");
StephaneLenclud@154:             }
StephaneLenclud@154: 
StephaneLenclud@154:             //This is needed to make sure we can open the volume next time around
StephaneLenclud@154:             handle.Dispose();
StephaneLenclud@150:         }
StephaneLenclud@150: 
StephaneLenclud@150:         /// <summary>
StephaneLenclud@150:         /// 
StephaneLenclud@150:         /// </summary>
StephaneLenclud@150:         private void HandleGreenStart()
StephaneLenclud@150:         {
StephaneLenclud@150:             //First check if the process we want to launch already exists
StephaneLenclud@150:             string procName = Path.GetFileNameWithoutExtension(Properties.Settings.Default.StartFileName);
StephaneLenclud@150:             Process[] existingProcesses = Process.GetProcessesByName(procName);
StephaneLenclud@150:             if (existingProcesses == null || existingProcesses.Length == 0)
StephaneLenclud@150:             {
StephaneLenclud@150:                 // Process do not exists just try to launch it
StephaneLenclud@150:                 ProcessStartInfo start = new ProcessStartInfo();
StephaneLenclud@150:                 // Enter in the command line arguments, everything you would enter after the executable name itself
StephaneLenclud@150:                 //start.Arguments = arguments; 
StephaneLenclud@150:                 // Enter the executable to run, including the complete path
StephaneLenclud@150:                 start.FileName = Properties.Settings.Default.StartFileName;
StephaneLenclud@150:                 start.WindowStyle = ProcessWindowStyle.Normal;
StephaneLenclud@150:                 start.CreateNoWindow = true;
StephaneLenclud@150:                 start.UseShellExecute = true;
StephaneLenclud@150:                 // Run the external process & wait for it to finish
StephaneLenclud@150:                 Process proc = Process.Start(start);
StephaneLenclud@150: 
StephaneLenclud@150:                 //SL: We could have used that too
StephaneLenclud@150:                 //Shell32.Shell shell = new Shell32.Shell();
StephaneLenclud@150:                 //shell.ShellExecute(Properties.Settings.Default.StartFileName);
StephaneLenclud@150:             }
StephaneLenclud@150:             else
StephaneLenclud@150:             {
StephaneLenclud@150:                 //This won't work properly until we have a manifest that enables uiAccess.
StephaneLenclud@150:                 //However uiAccess just won't work with ClickOnce so we will have to use a different deployment system.
StephaneLenclud@150:                 SwitchToThisWindow(existingProcesses[0].MainWindowHandle, true);
StephaneLenclud@150:             }            
StephaneLenclud@150:         }
StephaneLenclud@167: 
StephaneLenclud@167: 
StephaneLenclud@131:         /// <summary>
StephaneLenclud@131:         /// We need to handle WM_INPUT.
StephaneLenclud@131:         /// </summary>
StephaneLenclud@131:         /// <param name="message"></param>
StephaneLenclud@131:         protected override void WndProc(ref Message message)
StephaneLenclud@131:         {
StephaneLenclud@131:             switch (message.Msg)
StephaneLenclud@131:             {
StephaneLenclud@131:                 case Const.WM_INPUT:
StephaneLenclud@131:                     //Returning zero means we processed that message.
StephaneLenclud@131:                     message.Result = new IntPtr(0);
StephaneLenclud@131:                     iHidHandler.ProcessInput(ref message);
StephaneLenclud@131:                     break;
StephaneLenclud@131:             }
StephaneLenclud@159: 
StephaneLenclud@167:             //Pass this on to base class.
StephaneLenclud@131:             base.WndProc(ref message);
StephaneLenclud@131:         }
StephaneLenclud@131:     }
StephaneLenclud@125: }