Server/FormMain.Hid.cs
author Stephane Lenclud
Thu, 18 Aug 2016 20:14:30 +0200
changeset 242 0a956121c273
parent 238 c92587ddabcd
child 245 448e6a616c22
permissions -rw-r--r--
Weird signing crap.
StephaneLenclud@125
     1
using System;
StephaneLenclud@126
     2
using System.IO;
StephaneLenclud@125
     3
using System.Collections.Generic;
StephaneLenclud@125
     4
using System.Linq;
StephaneLenclud@125
     5
using System.Text;
StephaneLenclud@125
     6
using System.Threading.Tasks;
StephaneLenclud@125
     7
using System.Diagnostics;
StephaneLenclud@125
     8
using System.Runtime.InteropServices;
StephaneLenclud@125
     9
using System.Windows.Forms;
StephaneLenclud@150
    10
using Microsoft.Win32.SafeHandles;
StephaneLenclud@155
    11
using System.ComponentModel;
StephaneLenclud@125
    12
//
StephaneLenclud@125
    13
using Hid = SharpLib.Hid;
StephaneLenclud@125
    14
using SharpLib.Win32;
StephaneLenclud@125
    15
StephaneLenclud@125
    16
namespace SharpDisplayManager
StephaneLenclud@125
    17
{
StephaneLenclud@138
    18
    /// <summary>
StephaneLenclud@138
    19
    /// Implement handling of HID input reports notably to be able to launch an application using the Green Start button from IR remotes.
StephaneLenclud@138
    20
    /// </summary>
StephaneLenclud@131
    21
    [System.ComponentModel.DesignerCategory("Code")]
StephaneLenclud@226
    22
    public class FormMainHid : Form
StephaneLenclud@131
    23
    {
StephaneLenclud@131
    24
        [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SwitchToThisWindow")]
StephaneLenclud@131
    25
        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
    26
        //
StephaneLenclud@131
    27
        public delegate void OnHidEventDelegate(object aSender, Hid.Event aHidEvent);
StephaneLenclud@126
    28
StephaneLenclud@131
    29
        /// <summary>
StephaneLenclud@131
    30
        /// Use notably to handle green start key from IR remote control
StephaneLenclud@131
    31
        /// </summary>
StephaneLenclud@131
    32
        private Hid.Handler iHidHandler;
StephaneLenclud@126
    33
StephaneLenclud@131
    34
        /// <summary>
StephaneLenclud@131
    35
        /// Register HID devices so that we receive corresponding WM_INPUT messages.
StephaneLenclud@131
    36
        /// </summary>
StephaneLenclud@131
    37
        protected void RegisterHidDevices()
StephaneLenclud@131
    38
        {
StephaneLenclud@131
    39
            // Register the input device to receive the commands from the
StephaneLenclud@131
    40
            // remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp
StephaneLenclud@131
    41
            // for the vendor defined usage page.
StephaneLenclud@128
    42
StephaneLenclud@241
    43
            RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[6];
StephaneLenclud@128
    44
StephaneLenclud@131
    45
            int i = 0;
StephaneLenclud@131
    46
            rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.WindowsMediaCenterRemoteControl;
StephaneLenclud@131
    47
            rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.WindowsMediaCenter.WindowsMediaCenterRemoteControl;
StephaneLenclud@233
    48
            rid[i].dwFlags = RawInputDeviceFlags.RIDEV_INPUTSINK;
StephaneLenclud@131
    49
            rid[i].hwndTarget = Handle;
StephaneLenclud@128
    50
StephaneLenclud@131
    51
            i++;
StephaneLenclud@131
    52
            rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.Consumer;
StephaneLenclud@131
    53
            rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.Consumer.ConsumerControl;
StephaneLenclud@233
    54
            rid[i].dwFlags = RawInputDeviceFlags.RIDEV_INPUTSINK;
StephaneLenclud@131
    55
            rid[i].hwndTarget = Handle;
StephaneLenclud@126
    56
StephaneLenclud@131
    57
            i++;
StephaneLenclud@131
    58
            rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.Consumer;
StephaneLenclud@131
    59
            rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.Consumer.Selection;
StephaneLenclud@233
    60
            rid[i].dwFlags = RawInputDeviceFlags.RIDEV_INPUTSINK;
StephaneLenclud@131
    61
            rid[i].hwndTarget = Handle;
StephaneLenclud@125
    62
StephaneLenclud@131
    63
            i++;
StephaneLenclud@131
    64
            rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
StephaneLenclud@131
    65
            rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.SystemControl;
StephaneLenclud@233
    66
            rid[i].dwFlags = RawInputDeviceFlags.RIDEV_INPUTSINK;
StephaneLenclud@131
    67
            rid[i].hwndTarget = Handle;
StephaneLenclud@125
    68
StephaneLenclud@131
    69
            i++;
StephaneLenclud@131
    70
            rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
StephaneLenclud@131
    71
            rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.GamePad;
StephaneLenclud@233
    72
            rid[i].dwFlags = RawInputDeviceFlags.RIDEV_INPUTSINK;
StephaneLenclud@131
    73
            rid[i].hwndTarget = Handle;
StephaneLenclud@125
    74
StephaneLenclud@241
    75
            i++;
StephaneLenclud@241
    76
            rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
StephaneLenclud@241
    77
            rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.Keyboard;
StephaneLenclud@241
    78
            rid[i].dwFlags = RawInputDeviceFlags.RIDEV_INPUTSINK;
StephaneLenclud@241
    79
            rid[i].hwndTarget = Handle;
StephaneLenclud@241
    80
StephaneLenclud@131
    81
            //i++;
StephaneLenclud@131
    82
            //rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
StephaneLenclud@131
    83
            //rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.Keyboard;
StephaneLenclud@131
    84
            //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
StephaneLenclud@131
    85
            //rid[i].hwndTarget = Handle;
StephaneLenclud@125
    86
StephaneLenclud@131
    87
            //i++;
StephaneLenclud@131
    88
            //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls;
StephaneLenclud@131
    89
            //rid[i].usUsage = (ushort)Hid.UsageCollection.GenericDesktop.Mouse;
StephaneLenclud@131
    90
            //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
StephaneLenclud@131
    91
            //rid[i].hwndTarget = aHWND;
StephaneLenclud@125
    92
StephaneLenclud@125
    93
StephaneLenclud@131
    94
            iHidHandler = new SharpLib.Hid.Handler(rid);
StephaneLenclud@131
    95
            if (!iHidHandler.IsRegistered)
StephaneLenclud@131
    96
            {
StephaneLenclud@131
    97
                Debug.WriteLine("Failed to register raw input devices: " + Marshal.GetLastWin32Error().ToString());
StephaneLenclud@131
    98
            }
StephaneLenclud@131
    99
            iHidHandler.OnHidEvent += HandleHidEventThreadSafe;
StephaneLenclud@159
   100
StephaneLenclud@131
   101
        }
StephaneLenclud@125
   102
StephaneLenclud@159
   103
StephaneLenclud@159
   104
StephaneLenclud@159
   105
StephaneLenclud@131
   106
        /// <summary>
StephaneLenclud@131
   107
        /// Here we receive HID events from our HID library.
StephaneLenclud@131
   108
        /// </summary>
StephaneLenclud@131
   109
        /// <param name="aSender"></param>
StephaneLenclud@131
   110
        /// <param name="aHidEvent"></param>
StephaneLenclud@131
   111
        public void HandleHidEventThreadSafe(object aSender, SharpLib.Hid.Event aHidEvent)
StephaneLenclud@131
   112
        {
StephaneLenclud@241
   113
            if (aHidEvent.IsStray || !aHidEvent.IsValid)
StephaneLenclud@131
   114
            {
StephaneLenclud@131
   115
                //Stray event just ignore it
StephaneLenclud@131
   116
                return;
StephaneLenclud@131
   117
            }
StephaneLenclud@125
   118
StephaneLenclud@131
   119
            if (this.InvokeRequired)
StephaneLenclud@131
   120
            {
StephaneLenclud@131
   121
                //Not in the proper thread, invoke ourselves
StephaneLenclud@131
   122
                OnHidEventDelegate d = new OnHidEventDelegate(HandleHidEventThreadSafe);
StephaneLenclud@131
   123
                this.Invoke(d, new object[] { aSender, aHidEvent });
StephaneLenclud@131
   124
            }
StephaneLenclud@131
   125
            else
StephaneLenclud@131
   126
            {
StephaneLenclud@241
   127
                if (aHidEvent.IsGeneric)
StephaneLenclud@150
   128
                {
StephaneLenclud@241
   129
                    if (aHidEvent.Usages.Count == 0)
StephaneLenclud@241
   130
                    {
StephaneLenclud@241
   131
                        //No usage, nothing to do then
StephaneLenclud@241
   132
                        return;
StephaneLenclud@241
   133
                    }
StephaneLenclud@150
   134
StephaneLenclud@241
   135
                    //We are in the proper thread
StephaneLenclud@241
   136
                    if (aHidEvent.UsagePage == (ushort) Hid.UsagePage.WindowsMediaCenterRemoteControl)
StephaneLenclud@241
   137
                    {
StephaneLenclud@241
   138
                        //Trigger events as needed
StephaneLenclud@241
   139
                        EventHidWindowsMediaCenter e = new EventHidWindowsMediaCenter
StephaneLenclud@241
   140
                        {
StephaneLenclud@241
   141
                            Usage = (Hid.Usage.WindowsMediaCenterRemoteControl) aHidEvent.Usages[0]
StephaneLenclud@241
   142
                        };
StephaneLenclud@241
   143
                        Properties.Settings.Default.EarManager.TriggerEvent(e);
StephaneLenclud@238
   144
StephaneLenclud@241
   145
                        //Old legacy hard coded stuff
StephaneLenclud@241
   146
                        //TODO: remove it
StephaneLenclud@241
   147
                        switch (aHidEvent.Usages[0])
StephaneLenclud@241
   148
                        {
StephaneLenclud@241
   149
                            case (ushort) Hid.Usage.WindowsMediaCenterRemoteControl.GreenStart:
StephaneLenclud@241
   150
                                HandleGreenStart();
StephaneLenclud@241
   151
                                break;
StephaneLenclud@241
   152
                            case (ushort) Hid.Usage.WindowsMediaCenterRemoteControl.Eject:
StephaneLenclud@241
   153
                            case (ushort) Hid.Usage.WindowsMediaCenterRemoteControl.Ext2:
StephaneLenclud@241
   154
                                HandleEject();
StephaneLenclud@241
   155
                                break;
StephaneLenclud@241
   156
                        }
StephaneLenclud@241
   157
                    }
StephaneLenclud@241
   158
                    else if (aHidEvent.UsagePage == (ushort) Hid.UsagePage.Consumer)
StephaneLenclud@131
   159
                    {
StephaneLenclud@241
   160
                        //Trigger matching events if any
StephaneLenclud@241
   161
                        EventHidConsumerControl e = new EventHidConsumerControl
StephaneLenclud@241
   162
                        {
StephaneLenclud@241
   163
                            Usage = (Hid.Usage.ConsumerControl) aHidEvent.Usages[0]
StephaneLenclud@241
   164
                        };
StephaneLenclud@241
   165
                        Properties.Settings.Default.EarManager.TriggerEvent(e);
StephaneLenclud@241
   166
StephaneLenclud@241
   167
                        //Keep this for debug when only ThinkPad keyboard is available
StephaneLenclud@241
   168
                        //if (aHidEvent.Usages[0] == (ushort)Hid.Usage.ConsumerControl.ThinkPadFullscreenMagnifier)
StephaneLenclud@241
   169
                        //{
StephaneLenclud@241
   170
                        //    HandleEject();
StephaneLenclud@241
   171
                        //}
StephaneLenclud@131
   172
                    }
StephaneLenclud@131
   173
                }
StephaneLenclud@241
   174
                else if (aHidEvent.IsKeyboard)
StephaneLenclud@237
   175
                {
StephaneLenclud@241
   176
                    //Trigger matching events if any
StephaneLenclud@241
   177
                    EventHidKeyboard e = new EventHidKeyboard
StephaneLenclud@241
   178
                    {
StephaneLenclud@241
   179
                        Key = aHidEvent.VirtualKey,
StephaneLenclud@241
   180
                        IsKeyUp = aHidEvent.IsButtonUp,
StephaneLenclud@241
   181
                        HasModifierAlt = aHidEvent.HasModifierAlt,
StephaneLenclud@241
   182
                        HasModifierControl = aHidEvent.HasModifierControl,
StephaneLenclud@241
   183
                        HasModifierShift = aHidEvent.HasModifierShift,
StephaneLenclud@241
   184
                        HasModifierWindows = aHidEvent.HasModifierWindows,
StephaneLenclud@241
   185
                    };
StephaneLenclud@238
   186
                    Properties.Settings.Default.EarManager.TriggerEvent(e);
StephaneLenclud@241
   187
                }                
StephaneLenclud@152
   188
StephaneLenclud@131
   189
            }
StephaneLenclud@131
   190
        }
StephaneLenclud@125
   191
StephaneLenclud@151
   192
        /// <summary>
StephaneLenclud@151
   193
        /// 
StephaneLenclud@151
   194
        /// </summary>
StephaneLenclud@155
   195
        /// <param name="aPrefix"></param>
StephaneLenclud@155
   196
        private void CheckLastError(string aPrefix)
StephaneLenclud@155
   197
        {
StephaneLenclud@155
   198
            string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
StephaneLenclud@155
   199
            Debug.WriteLine(aPrefix + Marshal.GetLastWin32Error().ToString() + ": " + errorMessage);
StephaneLenclud@155
   200
        }
StephaneLenclud@155
   201
StephaneLenclud@155
   202
        /// <summary>
StephaneLenclud@155
   203
        /// 
StephaneLenclud@155
   204
        /// </summary>
StephaneLenclud@151
   205
        /// <param name="data"></param>
StephaneLenclud@151
   206
        /// <returns></returns>
StephaneLenclud@151
   207
        private IntPtr MarshalToPointer(object data)
StephaneLenclud@151
   208
        {
StephaneLenclud@151
   209
            IntPtr buf = Marshal.AllocHGlobal(
StephaneLenclud@151
   210
                Marshal.SizeOf(data));
StephaneLenclud@151
   211
            Marshal.StructureToPtr(data,
StephaneLenclud@151
   212
                buf, false);
StephaneLenclud@151
   213
            return buf;
StephaneLenclud@151
   214
        }
StephaneLenclud@151
   215
StephaneLenclud@151
   216
        /// <summary>
StephaneLenclud@151
   217
        /// 
StephaneLenclud@151
   218
        /// </summary>
StephaneLenclud@151
   219
        /// <returns></returns>
StephaneLenclud@152
   220
        private SafeFileHandle OpenVolume(string aDriveName)
StephaneLenclud@150
   221
        {
StephaneLenclud@152
   222
            return Function.CreateFile("\\\\.\\" + aDriveName,
StephaneLenclud@150
   223
                               SharpLib.Win32.FileAccess.GENERIC_READ,
StephaneLenclud@150
   224
                               SharpLib.Win32.FileShare.FILE_SHARE_READ | SharpLib.Win32.FileShare.FILE_SHARE_WRITE,
StephaneLenclud@150
   225
                               IntPtr.Zero,
StephaneLenclud@150
   226
                               CreationDisposition.OPEN_EXISTING,
StephaneLenclud@150
   227
                               0,
StephaneLenclud@150
   228
                               IntPtr.Zero);
StephaneLenclud@150
   229
        }
StephaneLenclud@150
   230
StephaneLenclud@150
   231
        /// <summary>
StephaneLenclud@150
   232
        /// 
StephaneLenclud@150
   233
        /// </summary>
StephaneLenclud@151
   234
        /// <param name="aVolume"></param>
StephaneLenclud@151
   235
        /// <returns></returns>
StephaneLenclud@151
   236
        private bool LockVolume(SafeFileHandle aVolume)
StephaneLenclud@151
   237
        {
StephaneLenclud@151
   238
            //Hope that's doing what I think it does
StephaneLenclud@151
   239
            IntPtr dwBytesReturned=new IntPtr();
StephaneLenclud@151
   240
            //Should not be needed but I'm not sure how to pass NULL in there.
StephaneLenclud@151
   241
            OVERLAPPED overlapped=new OVERLAPPED();
StephaneLenclud@151
   242
StephaneLenclud@151
   243
            int tries = 0;
StephaneLenclud@151
   244
            const int KMaxTries = 100;
StephaneLenclud@151
   245
            const int KSleepTime = 10;
StephaneLenclud@151
   246
            bool success = false;
StephaneLenclud@151
   247
StephaneLenclud@151
   248
            while (!success && tries < KMaxTries)
StephaneLenclud@151
   249
            {
StephaneLenclud@151
   250
                success = Function.DeviceIoControl(aVolume, Const.FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, dwBytesReturned, ref overlapped);
StephaneLenclud@151
   251
                System.Threading.Thread.Sleep(KSleepTime);
StephaneLenclud@151
   252
                tries++;
StephaneLenclud@151
   253
            }
StephaneLenclud@151
   254
StephaneLenclud@155
   255
            CheckLastError("Lock volume: ");
StephaneLenclud@155
   256
StephaneLenclud@151
   257
            return success;
StephaneLenclud@151
   258
        }
StephaneLenclud@151
   259
StephaneLenclud@151
   260
        /// <summary>
StephaneLenclud@151
   261
        /// 
StephaneLenclud@151
   262
        /// </summary>
StephaneLenclud@151
   263
        /// <param name="aVolume"></param>
StephaneLenclud@151
   264
        /// <returns></returns>
StephaneLenclud@151
   265
        private bool DismountVolume(SafeFileHandle aVolume)
StephaneLenclud@151
   266
        {
StephaneLenclud@151
   267
            //Hope that's doing what I think it does
StephaneLenclud@151
   268
            IntPtr dwBytesReturned = new IntPtr();
StephaneLenclud@151
   269
            //Should not be needed but I'm not sure how to pass NULL in there.
StephaneLenclud@151
   270
            OVERLAPPED overlapped=new OVERLAPPED();
StephaneLenclud@151
   271
StephaneLenclud@155
   272
            bool res = Function.DeviceIoControl(aVolume, Const.FSCTL_DISMOUNT_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, dwBytesReturned, ref overlapped);
StephaneLenclud@155
   273
            CheckLastError("Dismount volume: ");
StephaneLenclud@155
   274
            return res;
StephaneLenclud@151
   275
        }
StephaneLenclud@151
   276
StephaneLenclud@151
   277
StephaneLenclud@151
   278
StephaneLenclud@151
   279
        /// <summary>
StephaneLenclud@151
   280
        /// 
StephaneLenclud@151
   281
        /// </summary>
StephaneLenclud@151
   282
        /// <param name="aVolume"></param>
StephaneLenclud@151
   283
        /// <param name="aPreventRemoval"></param>
StephaneLenclud@151
   284
        /// <returns></returns>
StephaneLenclud@151
   285
        private bool PreventRemovalOfVolume(SafeFileHandle aVolume, bool aPreventRemoval)
StephaneLenclud@151
   286
        {
StephaneLenclud@151
   287
            //Hope that's doing what I think it does
StephaneLenclud@151
   288
            IntPtr dwBytesReturned = new IntPtr();
StephaneLenclud@151
   289
            //Should not be needed but I'm not sure how to pass NULL in there.
StephaneLenclud@151
   290
            OVERLAPPED overlapped = new OVERLAPPED();
StephaneLenclud@151
   291
            //
StephaneLenclud@151
   292
            PREVENT_MEDIA_REMOVAL preventMediaRemoval = new PREVENT_MEDIA_REMOVAL();
StephaneLenclud@151
   293
            preventMediaRemoval.PreventMediaRemoval = Convert.ToByte(aPreventRemoval);
StephaneLenclud@151
   294
            IntPtr preventMediaRemovalParam = MarshalToPointer(preventMediaRemoval);
StephaneLenclud@151
   295
StephaneLenclud@151
   296
            bool result = Function.DeviceIoControl(aVolume, Const.IOCTL_STORAGE_MEDIA_REMOVAL, preventMediaRemovalParam, Convert.ToUInt32(Marshal.SizeOf(preventMediaRemoval)), IntPtr.Zero, 0, dwBytesReturned, ref overlapped);
StephaneLenclud@155
   297
            CheckLastError("Media removal: ");
StephaneLenclud@151
   298
            Marshal.FreeHGlobal(preventMediaRemovalParam);
StephaneLenclud@151
   299
StephaneLenclud@151
   300
            return result;
StephaneLenclud@151
   301
        }
StephaneLenclud@151
   302
StephaneLenclud@151
   303
        /// <summary>
StephaneLenclud@154
   304
        /// Eject optical drive media opening the tray if any.
StephaneLenclud@151
   305
        /// </summary>
StephaneLenclud@151
   306
        /// <param name="aVolume"></param>
StephaneLenclud@151
   307
        /// <returns></returns>
StephaneLenclud@154
   308
        private bool MediaEject(SafeFileHandle aVolume)
StephaneLenclud@151
   309
        {
StephaneLenclud@151
   310
            //Hope that's doing what I think it does
StephaneLenclud@151
   311
            IntPtr dwBytesReturned = new IntPtr();
StephaneLenclud@151
   312
            //Should not be needed but I'm not sure how to pass NULL in there.
StephaneLenclud@151
   313
            OVERLAPPED overlapped=new OVERLAPPED();
StephaneLenclud@151
   314
StephaneLenclud@155
   315
            bool res = Function.DeviceIoControl(aVolume, Const.IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, dwBytesReturned, ref overlapped);
StephaneLenclud@155
   316
            CheckLastError("Media eject: ");
StephaneLenclud@155
   317
            return res;
StephaneLenclud@151
   318
        }
StephaneLenclud@151
   319
StephaneLenclud@152
   320
        /// <summary>
StephaneLenclud@154
   321
        /// Close an optical drive tray.
StephaneLenclud@152
   322
        /// </summary>
StephaneLenclud@152
   323
        /// <param name="aVolume"></param>
StephaneLenclud@152
   324
        /// <returns></returns>
StephaneLenclud@154
   325
        private bool MediaLoad(SafeFileHandle aVolume)
StephaneLenclud@152
   326
        {
StephaneLenclud@152
   327
            //Hope that's doing what I think it does
StephaneLenclud@152
   328
            IntPtr dwBytesReturned = new IntPtr();
StephaneLenclud@152
   329
            //Should not be needed but I'm not sure how to pass NULL in there.
StephaneLenclud@152
   330
            OVERLAPPED overlapped=new OVERLAPPED();
StephaneLenclud@152
   331
StephaneLenclud@155
   332
            bool res = Function.DeviceIoControl(aVolume, Const.IOCTL_STORAGE_LOAD_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, dwBytesReturned, ref overlapped);
StephaneLenclud@155
   333
            CheckLastError("Media load: ");
StephaneLenclud@155
   334
            return res;
StephaneLenclud@152
   335
        }
StephaneLenclud@152
   336
StephaneLenclud@154
   337
        /// <summary>
StephaneLenclud@154
   338
        /// 
StephaneLenclud@154
   339
        /// </summary>
StephaneLenclud@154
   340
        /// <param name="aVolume"></param>
StephaneLenclud@154
   341
        /// <returns></returns>
StephaneLenclud@154
   342
        private bool StorageCheckVerify(SafeFileHandle aVolume)
StephaneLenclud@154
   343
        {
StephaneLenclud@154
   344
            //Hope that's doing what I think it does
StephaneLenclud@154
   345
            IntPtr dwBytesReturned = new IntPtr();
StephaneLenclud@154
   346
            //Should not be needed but I'm not sure how to pass NULL in there.
StephaneLenclud@154
   347
            OVERLAPPED overlapped = new OVERLAPPED();
StephaneLenclud@154
   348
StephaneLenclud@154
   349
            bool res = Function.DeviceIoControl(aVolume, Const.IOCTL_STORAGE_CHECK_VERIFY2, IntPtr.Zero, 0, IntPtr.Zero, 0, dwBytesReturned, ref overlapped);
StephaneLenclud@154
   350
StephaneLenclud@155
   351
            CheckLastError("Check verify: ");
StephaneLenclud@154
   352
StephaneLenclud@154
   353
            return res;
StephaneLenclud@154
   354
        }        
StephaneLenclud@151
   355
        
StephaneLenclud@151
   356
StephaneLenclud@151
   357
StephaneLenclud@151
   358
        /// <summary>
StephaneLenclud@151
   359
        /// Perform media ejection.
StephaneLenclud@151
   360
        /// </summary>
StephaneLenclud@150
   361
        private void HandleEject()
StephaneLenclud@150
   362
        {
StephaneLenclud@226
   363
            string drive = ((FormMain)this).OpticalDriveToEject();
StephaneLenclud@153
   364
            if (drive.Length!=2)
StephaneLenclud@153
   365
            {
StephaneLenclud@153
   366
                //Not a proper drive spec.
StephaneLenclud@153
   367
                //Probably 'None' selected.
StephaneLenclud@153
   368
                return;
StephaneLenclud@153
   369
            }
StephaneLenclud@153
   370
StephaneLenclud@153
   371
            SafeFileHandle handle = OpenVolume(drive);
StephaneLenclud@151
   372
            if (handle.IsInvalid)
StephaneLenclud@151
   373
            {
StephaneLenclud@155
   374
                CheckLastError("ERROR: Failed to open volume: ");
StephaneLenclud@151
   375
                return;
StephaneLenclud@151
   376
            }
StephaneLenclud@151
   377
StephaneLenclud@151
   378
            if (LockVolume(handle) && DismountVolume(handle))
StephaneLenclud@151
   379
            {
StephaneLenclud@154
   380
                Debug.WriteLine("Volume was dismounted.");
StephaneLenclud@151
   381
StephaneLenclud@152
   382
                if (PreventRemovalOfVolume(handle,false))
StephaneLenclud@151
   383
                {
StephaneLenclud@156
   384
                    //StorageCheckVerify(handle);
StephaneLenclud@154
   385
StephaneLenclud@156
   386
                    DateTime before;
StephaneLenclud@156
   387
                    before = DateTime.Now;
StephaneLenclud@156
   388
                    bool ejectSuccess = MediaEject(handle);
StephaneLenclud@156
   389
                    double ms = (DateTime.Now - before).TotalMilliseconds;
StephaneLenclud@156
   390
StephaneLenclud@156
   391
                    //We assume that if it take more than a certain time to for eject to execute it means we actually ejected.
StephaneLenclud@156
   392
                    //If our eject completes too rapidly we assume the tray is already open and we will try to close it. 
StephaneLenclud@156
   393
                    if (ejectSuccess && ms > 100)
StephaneLenclud@152
   394
                    {
StephaneLenclud@154
   395
                        Debug.WriteLine("Media was ejected");
StephaneLenclud@152
   396
                    }
StephaneLenclud@154
   397
                    else if (MediaLoad(handle))
StephaneLenclud@154
   398
                    {
StephaneLenclud@154
   399
                        Debug.WriteLine("Media was loaded");
StephaneLenclud@154
   400
                    }                    
StephaneLenclud@151
   401
                }
StephaneLenclud@151
   402
            }
StephaneLenclud@154
   403
            else
StephaneLenclud@154
   404
            {
StephaneLenclud@154
   405
                Debug.WriteLine("Volume lock or dismount failed.");
StephaneLenclud@154
   406
            }
StephaneLenclud@154
   407
StephaneLenclud@154
   408
            //This is needed to make sure we can open the volume next time around
StephaneLenclud@154
   409
            handle.Dispose();
StephaneLenclud@150
   410
        }
StephaneLenclud@150
   411
StephaneLenclud@150
   412
        /// <summary>
StephaneLenclud@150
   413
        /// 
StephaneLenclud@150
   414
        /// </summary>
StephaneLenclud@150
   415
        private void HandleGreenStart()
StephaneLenclud@150
   416
        {
StephaneLenclud@150
   417
            //First check if the process we want to launch already exists
StephaneLenclud@150
   418
            string procName = Path.GetFileNameWithoutExtension(Properties.Settings.Default.StartFileName);
StephaneLenclud@150
   419
            Process[] existingProcesses = Process.GetProcessesByName(procName);
StephaneLenclud@150
   420
            if (existingProcesses == null || existingProcesses.Length == 0)
StephaneLenclud@150
   421
            {
StephaneLenclud@150
   422
                // Process do not exists just try to launch it
StephaneLenclud@150
   423
                ProcessStartInfo start = new ProcessStartInfo();
StephaneLenclud@150
   424
                // Enter in the command line arguments, everything you would enter after the executable name itself
StephaneLenclud@150
   425
                //start.Arguments = arguments; 
StephaneLenclud@150
   426
                // Enter the executable to run, including the complete path
StephaneLenclud@150
   427
                start.FileName = Properties.Settings.Default.StartFileName;
StephaneLenclud@150
   428
                start.WindowStyle = ProcessWindowStyle.Normal;
StephaneLenclud@150
   429
                start.CreateNoWindow = true;
StephaneLenclud@150
   430
                start.UseShellExecute = true;
StephaneLenclud@150
   431
                // Run the external process & wait for it to finish
StephaneLenclud@150
   432
                Process proc = Process.Start(start);
StephaneLenclud@150
   433
StephaneLenclud@150
   434
                //SL: We could have used that too
StephaneLenclud@150
   435
                //Shell32.Shell shell = new Shell32.Shell();
StephaneLenclud@150
   436
                //shell.ShellExecute(Properties.Settings.Default.StartFileName);
StephaneLenclud@150
   437
            }
StephaneLenclud@150
   438
            else
StephaneLenclud@150
   439
            {
StephaneLenclud@150
   440
                //This won't work properly until we have a manifest that enables uiAccess.
StephaneLenclud@150
   441
                //However uiAccess just won't work with ClickOnce so we will have to use a different deployment system.
StephaneLenclud@150
   442
                SwitchToThisWindow(existingProcesses[0].MainWindowHandle, true);
StephaneLenclud@150
   443
            }            
StephaneLenclud@150
   444
        }
StephaneLenclud@167
   445
StephaneLenclud@167
   446
StephaneLenclud@131
   447
        /// <summary>
StephaneLenclud@131
   448
        /// We need to handle WM_INPUT.
StephaneLenclud@131
   449
        /// </summary>
StephaneLenclud@131
   450
        /// <param name="message"></param>
StephaneLenclud@131
   451
        protected override void WndProc(ref Message message)
StephaneLenclud@131
   452
        {
StephaneLenclud@131
   453
            switch (message.Msg)
StephaneLenclud@131
   454
            {
StephaneLenclud@131
   455
                case Const.WM_INPUT:
StephaneLenclud@131
   456
                    //Returning zero means we processed that message.
StephaneLenclud@131
   457
                    message.Result = new IntPtr(0);
StephaneLenclud@131
   458
                    iHidHandler.ProcessInput(ref message);
StephaneLenclud@131
   459
                    break;
StephaneLenclud@131
   460
            }
StephaneLenclud@159
   461
StephaneLenclud@167
   462
            //Pass this on to base class.
StephaneLenclud@131
   463
            base.WndProc(ref message);
StephaneLenclud@131
   464
        }
StephaneLenclud@131
   465
    }
StephaneLenclud@125
   466
}