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