using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Text; using System.Runtime.InteropServices; using System.Windows.Forms; using System.Threading; using System.Diagnostics; using DTS.DASLib.Connection; using DTS.DASLib.Service; using DTS.DASLib.Connection.USBFramework; using DTS.DASLib.Communication; using DTS.DASLib.Command.SLICE; using DTS.DASLib.Command; using DTS.DASLib.DASResource; using DTS.DAS.Concepts; namespace DTS.DASLib.DASFactory { internal class HIDHandling: WindowsNotification { /// /// Timeout in milliseconds to connect an HID device /// public int ConnectHIDTimeout { get; set; } private IDeviceSetup deviceHandler { get; set; } #region Registry handling protected List RegKeys = new List(); protected void ReadRegKeys() { try { RegKeys.Clear(); ReadHIDRegKeys(); } catch(System.Exception) { // we don't care what is was, an empty list is fine } } protected void ReadHIDRegKeys() { // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\HID\VID_1CB9&PID_0003\6&29dd55fe&0&0000 //RegKeys.Clear(); var ourKey = Microsoft.Win32.Registry.LocalMachine; var ourName = @"SYSTEM\CurrentControlSet\Enum\HID\" + DTS_VENDOR_ID_STR + "&" + deviceHandler.GetProductIDString(); ourKey = ourKey.OpenSubKey(ourName); //if ourKey is null, this will throw an exception, but since nothing is done in the current //exception handler, the old code was just bypassing this code anyhow (when there's an exception) //6/8/2010 - dtm if (null != ourKey) { foreach (var subKey in ourKey.GetSubKeyNames()) { RegKeys.Add(subKey); } } } #endregion public HIDHandling(DASFactory _factory, UpdateFinishedEventHandler _SerialUpdateFinished, IDeviceSetup _deviceHandler) : base(_factory, _SerialUpdateFinished, _deviceHandler.GetGuid()) { deviceHandler = _deviceHandler; ReadRegKeys(); ConnectHIDTimeout = 1000; // 1000 ms } #region HID WinProc's protected override void NotificationDeviceArrived(ref System.Windows.Forms.Message m) { try { DTS.Utilities.Logging.APILogger.LogString("HIDArrived: A device has been connected"); // this can either be a HEADS or a SLICE device being connected // \\?\hid#vid_1cb9&pid_0002#6&29dd55fe&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} var bcdi = (DeviceManagementDeclarations.DEV_BROADCAST_DEVICEINTERFACE)Marshal.PtrToStructure(m.LParam, typeof(DeviceManagementDeclarations.DEV_BROADCAST_DEVICEINTERFACE)); var devNameArr = bcdi.dbcc_name.Split('#'); var foundKey = RegKeys.Find(delegate(String ss) { return ss == devNameArr[2]; }); if(foundKey != null) { SerialUpdateActionQueue.EnqueueConnect(); } else { ReadRegKeys(); } } catch(System.Exception ex) { DTS.Utilities.Logging.APILogger.LogString("HIDArrived caught an exception: " + ex.Message + " " + ex.StackTrace); MessageBox.Show("HIDArrived caught an exception: " + ex.Message + " " + ex.StackTrace, "Error"); } finally { DTS.Utilities.Logging.APILogger.LogString("HIDArrived: Exit"); } } protected override void NotificationDeviceRemoved(ref System.Windows.Forms.Message m) { try { DTS.Utilities.Logging.APILogger.LogString("HIDRemoved: A device has been disconnected"); //var bcdi2 = (DeviceManagementDeclarations.DEV_BROADCAST_DEVICEINTERFACE)Marshal.PtrToStructure(m.LParam, typeof(DeviceManagementDeclarations.DEV_BROADCAST_DEVICEINTERFACE)); SerialUpdateActionQueue.EnqueueDisconnect(); } catch(System.Exception ex) { DTS.Utilities.Logging.APILogger.LogString("HIDRemoved caught an exception: " + ex.Message + " " + ex.StackTrace); MessageBox.Show("HIDRemoved caught an exception: " + ex.Message + " " + ex.StackTrace, "Error"); } finally { DTS.Utilities.Logging.APILogger.LogString("HIDRemoved: Exit"); } } #endregion protected override void UpdateDisconnectedDevices() { ConnectNewDevices(new GetDeviceStrings(delegate() { return GetListOfConnectedHIDDevices(); }), new GetDeviceStrings(delegate() { return GetConnectedStrings(); }), new GetICommunication(delegate() { return deviceHandler.GetICommunication(); }), new GetIConnectedDevice(delegate(ICommunication comm) { return deviceHandler.GetIConnectedDevice(comm); }), deviceHandler.GetDASType(), deviceHandler, ConnectHIDTimeout); } protected override void UpdateConnectedDevices() { DisconnectRemovedDevices(new GetDeviceStrings(delegate() { return GetListOfConnectedHIDDevices(); }), new DASTypeFilter(delegate(ConnectedDevice dev) { return deviceHandler.IsCorrectType(dev); }), new ConnectedDevice2Communication(delegate(ConnectedDevice dev) { return deviceHandler.GetICommunication(dev); }), deviceHandler.GetDASType(), ConnectHIDTimeout); } #region Connection functions private List GetAllHIDDevices() { string[] AllHIDDevicePathNames = new string[128]; try { // Fill an array with the device path names of all attached HIDs. if(!MyDeviceManagement.FindDeviceFromGuid(deviceHandler.GetGuid(), ref AllHIDDevicePathNames)) { return null; } } catch { return null; } // loop thru the array and copy the new ones (that actually contain something) // over to the list newNames List newNames = new List(); for(int i = 0; i < AllHIDDevicePathNames.Length; i++) { if(string.IsNullOrEmpty(AllHIDDevicePathNames[i])) continue; // protect against windows giving us more than one of the same if(newNames.Find(delegate(String str) { return str.Equals(AllHIDDevicePathNames[i], StringComparison.OrdinalIgnoreCase); }) == null) { // no, we haven't added it yet so do it now newNames.Add(AllHIDDevicePathNames[i]); } } return newNames; } private int OpenDevicePath(string devicePath) { int devHandle; try { devHandle = FileIODeclarations.CreateFile(devicePath, 0, FileIODeclarations.FILE_SHARE_READ | FileIODeclarations.FILE_SHARE_WRITE, ref Security, FileIODeclarations.OPEN_EXISTING, 0, 0); } catch { return FileIODeclarations.INVALID_HANDLE_VALUE; } return devHandle; } private List FilterHIDDeviceList(List newNames, int vid, int pid) { if(newNames == null || newNames.Count == 0) { return null; } // now we have a list of new unique devices, make a new list containing only the ones that are of the right type List newRecorderNames = new List(); foreach(string devicePath in newNames) { try { int devHandle = OpenDevicePath(devicePath); if(devHandle == FileIODeclarations.INVALID_HANDLE_VALUE) { continue; } HIDevice deviceHID = new HIDevice(); // Set the Size property of DeviceAttributes to the number of bytes in the structure. deviceHID.DeviceAttributes.Size = Marshal.SizeOf(deviceHID.DeviceAttributes); int Result = HIDDeclarations.HidD_GetAttributes(devHandle, ref deviceHID.DeviceAttributes); if(Result == 0) { // There was a problem in retrieving the information. FileIODeclarations.CloseHandle(devHandle); continue; } // Find out if the device matches the one we're looking for. if(deviceHID.DeviceAttributes.VendorID != vid || deviceHID.DeviceAttributes.ProductID != pid) { // It's not a match, so close the handle. FileIODeclarations.CloseHandle(devHandle); continue; } // we don't need this handle anymore FileIODeclarations.CloseHandle(devHandle); // it's a new one newRecorderNames.Add(devicePath); } catch { // ignore it, try the next one } } return newRecorderNames; } private List GetListOfConnectedHIDDevices() { var newNames = GetAllHIDDevices(); if(newNames == null || newNames.Count == 0) { return null; } // now we have a list of new unique devices, make a new list containing only the ones that are of the right type List newRecorderNames; try { newRecorderNames = FilterHIDDeviceList(newNames, DTS_VENDOR_ID, deviceHandler.GetProductID()); } catch { return null; } return newRecorderNames; } #endregion /* #region HID update (not updated yet to separate callbacks) private bool UpdateConnectedHID() { bool devicesFound = false; try { DTS.Utilities.Logging.APILogger.LogString("UpdateConnectedHID: Enter"); // get a list of SLICE units currently connected thru HID var ConnectedHIDSlices = GetListOfConnectedHIDSlices(); devicesFound = (null != ConnectedHIDSlices && ConnectedHIDSlices.Count > 0); if(devicesFound) { // subtract the ones we already know about var NewHIDSlices = ConnectedHIDSlices.Except(GetConnectedStrings()); // add the new ones foreach(var devPath in NewHIDSlices) { var newHIDSlice = new HIDUSBSlice(); var newConnectedHIDSlice = new ConnectedHIDSlice(newHIDSlice); // try to connect it newHIDSlice.Connect(devPath, ConnectHIDCallback, new DeviceAndWaitTuple(newConnectedHIDSlice, null), ConnectHIDTimeout); } // now see if we have to remove any IEnumerable DevicesToRemove; lock(ConnectedDevicesLock) { DevicesToRemove = from dev in ConnectedDevices where !ConnectedHIDSlices.Contains(dev.dev.ConnectString) select dev; } // each one in this list must be disconnected foreach(var dev in DevicesToRemove) { // this is one of those places where we need to get to the ICommunication part ((dev.dev as IConnectedDAS).Comm as ICommunication).Disconnect(false, ConnectHIDCallback, new DeviceAndWaitTuple(dev, null), ConnectHIDTimeout); } } return devicesFound; } catch(System.Exception ex) { DTS.Utilities.Logging.APILogger.LogString(string.Format("DASFactory.UpdateConnectedHID: Exception {0} at {1}", ex.Message, ex.StackTrace)); MessageBox.Show(string.Format("DASFactory.UpdateConnectedHID: Exception {0} at {1}", ex.Message, ex.StackTrace)); return false; } finally { DTS.Utilities.Logging.APILogger.LogString("UpdateConnectedWinUSB: Exit"); } return devicesFound; } // this is our callback for both connect and disconnect private bool ConnectHIDCallback(ICommunicationReport report) { Debug.Assert(report.UserState is DeviceAndWaitTuple); var DeviceParameter = (report.UserState as DeviceAndWaitTuple).Device; var newHidUSB = DeviceParameter as ConnectedDevice; ConnectedDevice newDev; if(null != newHidUSB) { newDev = newHidUSB; } else { newDev = new ConnectedDevice(); newDev.dev = DeviceParameter as IConnectedDevice; newDev.dastype = ConnectedDevice.DASType.HID_SLICE; // assume not in update mode newDev.InUpdateMode = false; } if(report.Result == CommunicationResult.ConnectOK) { // fill the DASInfo var SliceInfoOK = sliceHandler.QueryInformation(newDev); // add it to our list lock(ConnectedDevicesLock) { ConnectedDevices.Add(newDev); } // notify our subscribers if(!SliceInfoOK) { factory.ReportFailed(); } else { factory.ReportArrived(); } } else if(report.Result == CommunicationResult.DisconnectOK) { // first dispose of it newDev.Dispose(); // remove it from our list lock(ConnectedDevicesLock) { ConnectedDevices.Remove(newDev); } // notify our subscribers factory.ReportRemoved(); } else { // first dispose of it newDev.Dispose(); factory.ReportFailed(); } return true; } #endregion */ } }