diff options
author | Alexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com> | 2017-01-12 11:50:43 +0300 |
---|---|---|
committer | Alexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com> | 2017-01-12 11:50:43 +0300 |
commit | b805961692c60da23ee412eb6ae4ae6052d45b55 (patch) | |
tree | 07970e216ee448ee7107ae83a96a51ec321883e0 /FelLib | |
parent | b91d8b1cb2e3468b0235f8c9f63d635b0ebc23a1 (diff) |
Fixed detection bug and unhandled exception bug
Diffstat (limited to 'FelLib')
-rw-r--r-- | FelLib/Fel.cs | 735 | ||||
-rw-r--r-- | FelLib/WinUSBNet/API/DeviceManagement.cs | 627 |
2 files changed, 700 insertions, 662 deletions
diff --git a/FelLib/Fel.cs b/FelLib/Fel.cs index d6f51059..63fbee54 100644 --- a/FelLib/Fel.cs +++ b/FelLib/Fel.cs @@ -1,351 +1,384 @@ -using MadWizard.WinUSBNet; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; - -namespace com.clusterrr.FelLib -{ - public class Fel - { - public byte[] Fes1Bin; - public byte[] UBootBin; - - public enum CurrentAction { RunningCommand, ReadingMemory, WritingMemory } - public delegate void OnFelProgress(CurrentAction action, string command); - - USBDevice device = null; - byte inEndp = 0; - byte outEndp = 0; - const int ReadTimeout = 1000; - const int WriteTimeout = 1000; - public const int MaxBulkSize = 0x10000; - UInt16 vid, pid; - bool DramInitDone = false; - - const UInt32 cmdOffset = 0x604FF; - const UInt32 fes1_base_m = 0x2000; - const UInt32 dram_base = 0x40000000; - const UInt32 flash_mem_base = 0x43800000; - const UInt32 flash_mem_size = 0x20; - const UInt32 uboot_base_m = 0x47000000u; - const UInt32 sector_size = 0x20000; - const UInt32 uboot_base_f = 0x100000; - const UInt32 kernel_base_f = (sector_size * 0x30); - const UInt32 kernel_base_m = flash_mem_base; - const UInt32 kernel_max_size = (uboot_base_m - flash_mem_base); - const UInt32 kernel_max_flash_size = (sector_size * 0x20); - const string fastboot = "fastboot_test"; - - public static bool DeviceExists(UInt16 vid, UInt16 pid) - { - var fel = new Fel(); - try - { - fel.Open(vid, pid); - return true; - } - catch - { - return false; - } - finally - { - fel.Close(); - } - } - - public void Open(UInt16 vid, UInt16 pid) - { - this.vid = vid; - this.pid = pid; - Close(); - device = USBDevice.GetSingleDevice(vid, pid); - if (device == null) throw new FelException("Device not found"); - foreach (var pipe in device.Pipes) - { - if (pipe.IsIn) - inEndp = pipe.Address; - else - outEndp = pipe.Address; - } - device.Pipes[inEndp].Policy.PipeTransferTimeout = ReadTimeout; - device.Pipes[outEndp].Policy.PipeTransferTimeout = WriteTimeout; - //ClearInputBuffer(); - if (VerifyDevice().Board != 0x00166700) throw new FelException("Invalid board ID"); - } - public void Close() - { - if (device != null) - { - try - { - device.Pipes[inEndp].Abort(); - } - catch { } - try - { - device.Pipes[outEndp].Abort(); - } - catch - { - } - device.Dispose(); - device = null; - } - } - - public void ClearInputBuffer() - { - var dummyBuff = new byte[64]; - device.Pipes[inEndp].Policy.PipeTransferTimeout = 50; - try - { - while (true) device.Pipes[inEndp].Read(dummyBuff); - } - catch { } - device.Pipes[inEndp].Policy.PipeTransferTimeout = ReadTimeout; - } - - private void WriteToUSB(byte[] buffer) - { - device.Pipes[outEndp].Write(buffer); - } - - private int ReadFromUSB(byte[] buffer, int offset, int length) - { - return device.Pipes[inEndp].Read(buffer, offset, length); - } - private byte[] ReadFromUSB(UInt32 length) - { - var result = new byte[length]; - int pos = 0; - while (pos < length) - { - pos += ReadFromUSB(result, pos, (int)(length - pos)); - } - return result; - } - - private void FelWrite(byte[] buffer) - { - var req = new AWUSBRequest(); - req.Cmd = AWUSBRequest.RequestType.AW_USB_WRITE; - req.Len = (uint)buffer.Length; - WriteToUSB(req.Data); - WriteToUSB(buffer); - var resp = new AWUSBResponse(ReadFromUSB(13)); - if (resp.CswStatus != 0) throw new FelException("FEL write error"); - } - - private byte[] FelRead(UInt32 length) - { - var req = new AWUSBRequest(); - req.Cmd = AWUSBRequest.RequestType.AW_USB_READ; - req.Len = length; - WriteToUSB(req.Data); - - var result = ReadFromUSB(length); - var resp = new AWUSBResponse(ReadFromUSB(13)); - if (resp.CswStatus != 0) throw new FelException("FEL read error"); - return result; - } - - private void FelRequest(AWFELStandardRequest.RequestType command) - { - var req = new AWFELStandardRequest(); - req.Cmd = command; - FelWrite(req.Data); - } - - private void FelRequest(AWFELStandardRequest.RequestType command, UInt32 address, UInt32 length) - { - var req = new AWFELMessage(); - req.Cmd = command; - req.Address = address; - req.Len = length; - FelWrite(req.Data); - } - - public AWFELVerifyDeviceResponse VerifyDevice() - { - FelRequest(AWFELStandardRequest.RequestType.FEL_VERIFY_DEVICE); - byte[] resp; - try - { - resp = FelRead(32); - } - catch - { - resp = new byte[32]; - } - var status = new AWFELStatusResponse(FelRead(8)); - return new AWFELVerifyDeviceResponse(resp); - } - - public void WriteMemory(UInt32 address, byte[] buffer, OnFelProgress callback = null) - { - if (address >= dram_base) - InitDram(); - - UInt32 length = (UInt32)buffer.Length; - if (length != (length & ~((UInt32)3))) - { - length = (length + 3) & ~((UInt32)3); - var newBuffer = new byte[length]; - Array.Copy(buffer, 0, newBuffer, 0, buffer.Length); - buffer = newBuffer; - } - - int pos = 0; - while (pos < buffer.Length) - { - if (callback != null) callback(CurrentAction.WritingMemory, null); - var buf = new byte[Math.Min(buffer.Length - pos, MaxBulkSize)]; - Array.Copy(buffer, pos, buf, 0, buf.Length); - FelRequest(AWFELStandardRequest.RequestType.FEL_DOWNLOAD, (UInt32)(address + pos), (uint)buf.Length); - FelWrite(buf); - var status = new AWFELStatusResponse(FelRead(8)); - if (status.State != 0) throw new FelException("FEL write error"); - pos += buf.Length; - } - } - - private byte[] ReadMemory(UInt32 address, UInt32 length, OnFelProgress callback = null) - { - if (address >= dram_base) - InitDram(); - - length = (length + 3) & ~((UInt32)3); - - var result = new List<byte>(); - while (length > 0) - { - if (callback != null) callback(CurrentAction.ReadingMemory, null); - var l = Math.Min(length, MaxBulkSize); - FelRequest(AWFELStandardRequest.RequestType.FEL_UPLOAD, address, l); - var r = FelRead((UInt32)l); - result.AddRange(r); - var status = new AWFELStatusResponse(FelRead(8)); - if (status.State != 0) throw new FelException("FEL read error"); - length -= l; - address += l; - } - return result.ToArray(); - } - - public bool InitDram(bool force = false) - { - if (DramInitDone && !force) return true; - if (DramInitDone) return true; - const UInt32 testSize = 0x80; - if (Fes1Bin == null || Fes1Bin.Length < testSize) - throw new FelException("Can't init DRAM, incorrect Fes1 binary"); - var buf = ReadMemory((UInt32)(fes1_base_m + Fes1Bin.Length - testSize), testSize); - var buf2 = new byte[testSize]; - Array.Copy(Fes1Bin, Fes1Bin.Length - buf.Length, buf2, 0, testSize); - if (buf.SequenceEqual(buf2)) - { - return DramInitDone = true; - } - WriteMemory(fes1_base_m, Fes1Bin); - Exec(fes1_base_m); - Thread.Sleep(2000); - return DramInitDone = true; - } - - public byte[] ReadFlash(UInt32 address, UInt32 length, OnFelProgress callback = null) - { - var result = new List<byte>(); - while (((length + address % sector_size + sector_size - 1) / sector_size) > flash_mem_size) - { - var sectors = (length + address % sector_size + sector_size - 1) / sector_size - flash_mem_size; - var buf = ReadFlash(address, sectors * sector_size - address % sector_size, callback); - address += (uint)buf.Length; - length -= (uint)buf.Length; - result.AddRange(buf); - } - if (result.Count > 0) return result.ToArray(); - var command = string.Format("sunxi_flash phy_read {0:x} {1:x} {2:x};{3}", flash_mem_base, address / sector_size, (length + address % sector_size + sector_size - 1) / sector_size, fastboot); - RunUbootCmd(command, false, callback); - result.AddRange(ReadMemory(flash_mem_base + address % sector_size, length, callback)); - return result.ToArray(); - } - - public void WriteFlash(UInt32 address, byte[] buffer, OnFelProgress callback = null) - { - int length = buffer.Length; - int pos = 0; - if ((address % sector_size) != 0) - throw new FelException(string.Format("Invalid address to flash: 0x{0:X8}", address)); - if ((length % sector_size) != 0) - throw new FelException(string.Format("Invalid length to flash: 0x{0:X8}", length)); - byte[] newBuf; - while ((length / sector_size) > flash_mem_size) - { - var sectors = (length / sector_size) - flash_mem_size; - newBuf = new byte[sectors * sector_size]; - Array.Copy(buffer, pos, newBuf, 0, newBuf.Length); - WriteFlash(address, newBuf, callback); - address += (UInt32)newBuf.Length; - length -= newBuf.Length; - pos += newBuf.Length; - } - newBuf = new byte[length - pos]; - Array.Copy(buffer, pos, newBuf, 0, newBuf.Length); - WriteMemory(flash_mem_base, newBuf, callback); - var command = string.Format("sunxi_flash phy_write {0:x} {1:x} {2:x};{3}", flash_mem_base, address / sector_size, length / sector_size, fastboot); - RunUbootCmd(command, false, callback); - } - - public void Exec(UInt32 address) - { - FelRequest(AWFELStandardRequest.RequestType.FEL_RUN, address, 0); - var status = new AWFELStatusResponse(FelRead(8)); - if (status.State != 0) throw new FelException("FEL run error"); - } - - public void RunUbootCmd(string command, bool noreturn = false, OnFelProgress callback = null) - { - if (callback != null) callback(CurrentAction.RunningCommand, command); - const UInt32 testSize = 0x20; - if (UBootBin == null || UBootBin.Length < testSize) - throw new FelException("Can't init Uboot, incorrect Uboot binary"); - var buf = ReadMemory(uboot_base_m, testSize); - var buf2 = new byte[testSize]; - Array.Copy(UBootBin, 0, buf2, 0, testSize); - if (!buf.SequenceEqual(buf2)) - WriteMemory(uboot_base_m, UBootBin); - var cmdBuff = Encoding.ASCII.GetBytes(command + "\0"); - WriteMemory((uint)(uboot_base_m + cmdOffset), cmdBuff); - Exec((uint)uboot_base_m); - if (noreturn) return; - Close(); - for (int i = 0; i < 10; i++) - { - Thread.Sleep(1000); - if (callback != null) callback(CurrentAction.RunningCommand, command); - } - int errorCount = 0; - while (true) - { - try - { - Open(vid, pid); - break; - } - catch (Exception ex) - { - errorCount++; - if (errorCount >= 10) - { - Close(); - throw ex; - } - Thread.Sleep(2000); - } - } - } - } -} +using MadWizard.WinUSBNet;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+
+namespace com.clusterrr.FelLib
+{
+ public class Fel
+ {
+ public byte[] Fes1Bin;
+ public byte[] UBootBin;
+
+ public enum CurrentAction { RunningCommand, ReadingMemory, WritingMemory }
+ public delegate void OnFelProgress(CurrentAction action, string command);
+
+ USBDevice device = null;
+ byte inEndp = 0;
+ byte outEndp = 0;
+ const int ReadTimeout = 1000;
+ const int WriteTimeout = 1000;
+ public const int MaxBulkSize = 0x10000;
+ UInt16 vid, pid;
+ bool DramInitDone = false;
+
+ const UInt32 cmdOffset = 0x604FF;
+ const UInt32 fes1_base_m = 0x2000;
+ const UInt32 dram_base = 0x40000000;
+ const UInt32 flash_mem_base = 0x43800000;
+ const UInt32 flash_mem_size = 0x20;
+ const UInt32 uboot_base_m = 0x47000000u;
+ const UInt32 sector_size = 0x20000;
+ const UInt32 uboot_base_f = 0x100000;
+ const UInt32 kernel_base_f = (sector_size * 0x30);
+ const UInt32 kernel_base_m = flash_mem_base;
+ const UInt32 kernel_max_size = (uboot_base_m - flash_mem_base);
+ const UInt32 kernel_max_flash_size = (sector_size * 0x20);
+ const string fastboot = "fastboot_test";
+
+ public static bool DeviceExists(UInt16 vid, UInt16 pid)
+ {
+ var fel = new Fel();
+ try
+ {
+ fel.Open(vid, pid);
+#if DEBUG
+ DebugLog("Device detection successful");
+#endif
+ return true;
+ }
+ catch (Exception ex)
+ {
+#if DEBUG
+ DebugLog("Device detection error: " + ex.Message + ex.StackTrace);
+#endif
+ return false;
+ }
+ finally
+ {
+ fel.Close();
+ }
+ }
+
+ public void Open(UInt16 vid, UInt16 pid)
+ {
+ this.vid = vid;
+ this.pid = pid;
+ Close();
+#if DEBUG
+ DebugLog("Trying to open device...");
+#endif
+ device = USBDevice.GetSingleDevice(vid, pid);
+ if (device == null) throw new FelException("Device with such VID and PID not found");
+#if DEBUG
+ DebugLog("Checking USB endpoints...");
+#endif
+ foreach (var pipe in device.Pipes)
+ {
+ if (pipe.IsIn)
+ {
+ inEndp = pipe.Address;
+#if DEBUG
+ DebugLog("IN endpoint found: "+ inEndp);
+#endif
+ }
+ else
+ {
+ outEndp = pipe.Address;
+#if DEBUG
+ DebugLog("Out endpoint found: "+outEndp);
+#endif
+ }
+ }
+ device.Pipes[inEndp].Policy.PipeTransferTimeout = ReadTimeout;
+ device.Pipes[outEndp].Policy.PipeTransferTimeout = WriteTimeout;
+#if DEBUG
+ DebugLog("Trying to verify device");
+#endif
+ if (VerifyDevice().Board != 0x00166700) throw new FelException("Invalid board ID: " + VerifyDevice().Board);
+ }
+ public void Close()
+ {
+ if (device != null)
+ {
+ try
+ {
+ device.Pipes[inEndp].Abort();
+ }
+ catch { }
+ try
+ {
+ device.Pipes[outEndp].Abort();
+ }
+ catch
+ {
+ }
+ device.Dispose();
+ device = null;
+ }
+ }
+
+ private void WriteToUSB(byte[] buffer)
+ {
+#if DEBUG
+ DebugLog("-> " + BitConverter.ToString(buffer));
+#endif
+
+ device.Pipes[outEndp].Write(buffer);
+ }
+
+ private int ReadFromUSB(byte[] buffer, int offset, int length)
+ {
+ var data = device.Pipes[inEndp].Read(buffer, offset, length);
+#if DEBUG
+ DebugLog("<- " + BitConverter.ToString(buffer));
+#endif
+ return data;
+ }
+ private byte[] ReadFromUSB(UInt32 length)
+ {
+ var result = new byte[length];
+ int pos = 0;
+ while (pos < length)
+ {
+ pos += ReadFromUSB(result, pos, (int)(length - pos));
+ }
+ return result;
+ }
+
+ private void FelWrite(byte[] buffer)
+ {
+ var req = new AWUSBRequest();
+ req.Cmd = AWUSBRequest.RequestType.AW_USB_WRITE;
+ req.Len = (uint)buffer.Length;
+ WriteToUSB(req.Data);
+ WriteToUSB(buffer);
+ var resp = new AWUSBResponse(ReadFromUSB(13));
+ if (resp.CswStatus != 0) throw new FelException("FEL write error");
+ }
+
+ private byte[] FelRead(UInt32 length)
+ {
+ var req = new AWUSBRequest();
+ req.Cmd = AWUSBRequest.RequestType.AW_USB_READ;
+ req.Len = length;
+ WriteToUSB(req.Data);
+
+ var result = ReadFromUSB(length);
+ var resp = new AWUSBResponse(ReadFromUSB(13));
+ if (resp.CswStatus != 0) throw new FelException("FEL read error");
+ return result;
+ }
+
+ private void FelRequest(AWFELStandardRequest.RequestType command)
+ {
+ var req = new AWFELStandardRequest();
+ req.Cmd = command;
+ FelWrite(req.Data);
+ }
+
+ private void FelRequest(AWFELStandardRequest.RequestType command, UInt32 address, UInt32 length)
+ {
+ var req = new AWFELMessage();
+ req.Cmd = command;
+ req.Address = address;
+ req.Len = length;
+ FelWrite(req.Data);
+ }
+
+ public AWFELVerifyDeviceResponse VerifyDevice()
+ {
+ FelRequest(AWFELStandardRequest.RequestType.FEL_VERIFY_DEVICE);
+ byte[] resp;
+ try
+ {
+ resp = FelRead(32);
+ }
+ catch
+ {
+ resp = new byte[32];
+ }
+ var status = new AWFELStatusResponse(FelRead(8));
+ return new AWFELVerifyDeviceResponse(resp);
+ }
+
+ public void WriteMemory(UInt32 address, byte[] buffer, OnFelProgress callback = null)
+ {
+ if (address >= dram_base)
+ InitDram();
+
+ UInt32 length = (UInt32)buffer.Length;
+ if (length != (length & ~((UInt32)3)))
+ {
+ length = (length + 3) & ~((UInt32)3);
+ var newBuffer = new byte[length];
+ Array.Copy(buffer, 0, newBuffer, 0, buffer.Length);
+ buffer = newBuffer;
+ }
+
+ int pos = 0;
+ while (pos < buffer.Length)
+ {
+ if (callback != null) callback(CurrentAction.WritingMemory, null);
+ var buf = new byte[Math.Min(buffer.Length - pos, MaxBulkSize)];
+ Array.Copy(buffer, pos, buf, 0, buf.Length);
+ FelRequest(AWFELStandardRequest.RequestType.FEL_DOWNLOAD, (UInt32)(address + pos), (uint)buf.Length);
+ FelWrite(buf);
+ var status = new AWFELStatusResponse(FelRead(8));
+ if (status.State != 0) throw new FelException("FEL write error");
+ pos += buf.Length;
+ }
+ }
+
+ private byte[] ReadMemory(UInt32 address, UInt32 length, OnFelProgress callback = null)
+ {
+ if (address >= dram_base)
+ InitDram();
+
+ length = (length + 3) & ~((UInt32)3);
+
+ var result = new List<byte>();
+ while (length > 0)
+ {
+ if (callback != null) callback(CurrentAction.ReadingMemory, null);
+ var l = Math.Min(length, MaxBulkSize);
+ FelRequest(AWFELStandardRequest.RequestType.FEL_UPLOAD, address, l);
+ var r = FelRead((UInt32)l);
+ result.AddRange(r);
+ var status = new AWFELStatusResponse(FelRead(8));
+ if (status.State != 0) throw new FelException("FEL read error");
+ length -= l;
+ address += l;
+ }
+ return result.ToArray();
+ }
+
+ public bool InitDram(bool force = false)
+ {
+ if (DramInitDone && !force) return true;
+ if (DramInitDone) return true;
+ const UInt32 testSize = 0x80;
+ if (Fes1Bin == null || Fes1Bin.Length < testSize)
+ throw new FelException("Can't init DRAM, incorrect Fes1 binary");
+ var buf = ReadMemory((UInt32)(fes1_base_m + Fes1Bin.Length - testSize), testSize);
+ var buf2 = new byte[testSize];
+ Array.Copy(Fes1Bin, Fes1Bin.Length - buf.Length, buf2, 0, testSize);
+ if (buf.SequenceEqual(buf2))
+ {
+ return DramInitDone = true;
+ }
+ WriteMemory(fes1_base_m, Fes1Bin);
+ Exec(fes1_base_m);
+ Thread.Sleep(2000);
+ return DramInitDone = true;
+ }
+
+ public byte[] ReadFlash(UInt32 address, UInt32 length, OnFelProgress callback = null)
+ {
+ var result = new List<byte>();
+ while (((length + address % sector_size + sector_size - 1) / sector_size) > flash_mem_size)
+ {
+ var sectors = (length + address % sector_size + sector_size - 1) / sector_size - flash_mem_size;
+ var buf = ReadFlash(address, sectors * sector_size - address % sector_size, callback);
+ address += (uint)buf.Length;
+ length -= (uint)buf.Length;
+ result.AddRange(buf);
+ }
+ if (result.Count > 0) return result.ToArray();
+ var command = string.Format("sunxi_flash phy_read {0:x} {1:x} {2:x};{3}", flash_mem_base, address / sector_size, (length + address % sector_size + sector_size - 1) / sector_size, fastboot);
+ RunUbootCmd(command, false, callback);
+ result.AddRange(ReadMemory(flash_mem_base + address % sector_size, length, callback));
+ return result.ToArray();
+ }
+
+ public void WriteFlash(UInt32 address, byte[] buffer, OnFelProgress callback = null)
+ {
+ int length = buffer.Length;
+ int pos = 0;
+ if ((address % sector_size) != 0)
+ throw new FelException(string.Format("Invalid address to flash: 0x{0:X8}", address));
+ if ((length % sector_size) != 0)
+ throw new FelException(string.Format("Invalid length to flash: 0x{0:X8}", length));
+ byte[] newBuf;
+ while ((length / sector_size) > flash_mem_size)
+ {
+ var sectors = (length / sector_size) - flash_mem_size;
+ newBuf = new byte[sectors * sector_size];
+ Array.Copy(buffer, pos, newBuf, 0, newBuf.Length);
+ WriteFlash(address, newBuf, callback);
+ address += (UInt32)newBuf.Length;
+ length -= newBuf.Length;
+ pos += newBuf.Length;
+ }
+ newBuf = new byte[length - pos];
+ Array.Copy(buffer, pos, newBuf, 0, newBuf.Length);
+ WriteMemory(flash_mem_base, newBuf, callback);
+ var command = string.Format("sunxi_flash phy_write {0:x} {1:x} {2:x};{3}", flash_mem_base, address / sector_size, length / sector_size, fastboot);
+ RunUbootCmd(command, false, callback);
+ }
+
+ public void Exec(UInt32 address)
+ {
+ FelRequest(AWFELStandardRequest.RequestType.FEL_RUN, address, 0);
+ var status = new AWFELStatusResponse(FelRead(8));
+ if (status.State != 0) throw new FelException("FEL run error");
+ }
+
+ public void RunUbootCmd(string command, bool noreturn = false, OnFelProgress callback = null)
+ {
+ if (callback != null) callback(CurrentAction.RunningCommand, command);
+ const UInt32 testSize = 0x20;
+ if (UBootBin == null || UBootBin.Length < testSize)
+ throw new FelException("Can't init Uboot, incorrect Uboot binary");
+ var buf = ReadMemory(uboot_base_m, testSize);
+ var buf2 = new byte[testSize];
+ Array.Copy(UBootBin, 0, buf2, 0, testSize);
+ if (!buf.SequenceEqual(buf2))
+ WriteMemory(uboot_base_m, UBootBin);
+ var cmdBuff = Encoding.ASCII.GetBytes(command + "\0");
+ WriteMemory((uint)(uboot_base_m + cmdOffset), cmdBuff);
+ Exec((uint)uboot_base_m);
+ if (noreturn) return;
+ Close();
+ for (int i = 0; i < 10; i++)
+ {
+ Thread.Sleep(1000);
+ if (callback != null) callback(CurrentAction.RunningCommand, command);
+ }
+ int errorCount = 0;
+ while (true)
+ {
+ try
+ {
+ Open(vid, pid);
+ break;
+ }
+ catch (Exception ex)
+ {
+ errorCount++;
+ if (errorCount >= 10)
+ {
+ Close();
+ throw ex;
+ }
+ Thread.Sleep(2000);
+ }
+ }
+ }
+
+#if DEBUG
+ private static void DebugLog(string text)
+ {
+ Console.WriteLine(text);
+ try
+ {
+ File.AppendAllText("debug.txt", DateTime.Now + ": " + text + "\r\n");
+ }
+ catch { }
+ }
+#endif
+ }
+}
diff --git a/FelLib/WinUSBNet/API/DeviceManagement.cs b/FelLib/WinUSBNet/API/DeviceManagement.cs index 36a34e83..2d593cce 100644 --- a/FelLib/WinUSBNet/API/DeviceManagement.cs +++ b/FelLib/WinUSBNet/API/DeviceManagement.cs @@ -1,311 +1,316 @@ -/* WinUSBNet library - * (C) 2010 Thomas Bleeker (www.madwizard.org) - * - * Licensed under the MIT license, see license.txt or: - * http://www.opensource.org/licenses/mit-license.php - */ - -/* NOTE: Parts of the code in this file are based on the work of Jan Axelson - * See http://www.lvr.com/winusb.htm for more information - */ - -using System; -using System.Runtime.InteropServices; -using System.Collections.Generic; -using System.Windows.Forms; -using System.Text.RegularExpressions; - -namespace MadWizard.WinUSBNet.API -{ - /// <summary> - /// Routines for detecting devices and receiving device notifications. - /// </summary> - internal static partial class DeviceManagement - { - - // Get device name from notification message. - // Also checks checkGuid with the GUID from the message to check the notification - // is for a relevant device. Other messages might be received. - public static string GetNotifyMessageDeviceName(Message m, Guid checkGuid) - { - int stringSize; - - - DEV_BROADCAST_DEVICEINTERFACE_1 devBroadcastDeviceInterface = new DEV_BROADCAST_DEVICEINTERFACE_1(); - DEV_BROADCAST_HDR devBroadcastHeader = new DEV_BROADCAST_HDR(); - - // The LParam parameter of Message is a pointer to a DEV_BROADCAST_HDR structure. - - Marshal.PtrToStructure(m.LParam, devBroadcastHeader); - - if ((devBroadcastHeader.dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)) - { - // The dbch_devicetype parameter indicates that the event applies to a device interface. - // So the structure in LParam is actually a DEV_BROADCAST_INTERFACE structure, - // which begins with a DEV_BROADCAST_HDR. - - // Obtain the number of characters in dbch_name by subtracting the 32 bytes - // in the strucutre that are not part of dbch_name and dividing by 2 because there are - // 2 bytes per character. - - stringSize = System.Convert.ToInt32((devBroadcastHeader.dbch_size - 32) / 2); - - // The dbcc_name parameter of devBroadcastDeviceInterface contains the device name. - // Trim dbcc_name to match the size of the String. - - devBroadcastDeviceInterface.dbcc_name = new char[stringSize + 1]; - - // Marshal data from the unmanaged block pointed to by m.LParam - // to the managed object devBroadcastDeviceInterface. - - Marshal.PtrToStructure(m.LParam, devBroadcastDeviceInterface); - - // Check if message is for the GUID - if (devBroadcastDeviceInterface.dbcc_classguid != checkGuid) - return null; - - // Store the device name in a String. - string deviceNameString = new String(devBroadcastDeviceInterface.dbcc_name, 0, stringSize); - - return deviceNameString; - - } - return null; - } - - private static byte[] GetProperty(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, SPDRP property, out int regType) - { - uint requiredSize; - - if (!SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref deviceInfoData, property, IntPtr.Zero, IntPtr.Zero, 0, out requiredSize)) - { - if (Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER) - throw APIException.Win32("Failed to get buffer size for device registry property."); - } - - byte[] buffer = new byte[requiredSize]; - - if (!SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref deviceInfoData, property, out regType, buffer, (uint)buffer.Length, out requiredSize)) - throw APIException.Win32("Failed to get device registry property."); - - return buffer; - - - - } - - // todo: is the queried data always available, or should we check ERROR_INVALID_DATA? - private static string GetStringProperty(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, SPDRP property) - { - int regType; - byte[] buffer = GetProperty(deviceInfoSet, deviceInfoData, property, out regType); - if (regType != (int)RegTypes.REG_SZ) - throw new APIException("Invalid registry type returned for device property."); - - // sizof(char), 2 bytes, are removed to leave out the string terminator - return System.Text.Encoding.Unicode.GetString(buffer, 0, buffer.Length - sizeof(char)); - } - - private static string[] GetMultiStringProperty(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, SPDRP property) - { - int regType; - byte[] buffer = GetProperty(deviceInfoSet, deviceInfoData, property, out regType); - if (regType != (int)RegTypes.REG_MULTI_SZ) - throw new APIException("Invalid registry type returned for device property."); - - string fullString = System.Text.Encoding.Unicode.GetString(buffer); - - return fullString.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries); - - } - private static DeviceDetails GetDeviceDetails(string devicePath, IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData) - { - DeviceDetails details = new DeviceDetails(); - details.DevicePath = devicePath; - details.DeviceDescription = GetStringProperty(deviceInfoSet, deviceInfoData, SPDRP.SPDRP_DEVICEDESC); - details.Manufacturer = GetStringProperty(deviceInfoSet, deviceInfoData, SPDRP.SPDRP_MFG); - string[] hardwareIDs = GetMultiStringProperty(deviceInfoSet, deviceInfoData, SPDRP.SPDRP_HARDWAREID); - - Regex regex = new Regex("^USB\\\\VID_([0-9A-F]{4})&PID_([0-9A-F]{4})", RegexOptions.IgnoreCase); - bool foundVidPid = false; - foreach (string hardwareID in hardwareIDs) - { - Match match = regex.Match(hardwareID); - if (match.Success) - { - details.VID = ushort.Parse(match.Groups[1].Value, System.Globalization.NumberStyles.AllowHexSpecifier); - details.PID = ushort.Parse(match.Groups[2].Value, System.Globalization.NumberStyles.AllowHexSpecifier); - foundVidPid = true; - break; - } - } - - if (!foundVidPid) - throw new APIException("Failed to find VID and PID for USB device. No hardware ID could be parsed."); - - return details; - } - - - public static DeviceDetails[] FindDevices(UInt16 vid, UInt16 pid) - { - IntPtr deviceInfoSet = IntPtr.Zero; - List<DeviceDetails> deviceList = new List<DeviceDetails>(); - var guid = new Guid("{A5DCBF10-6530-11D2-901F-00C04FB951ED}"); // USB device - try - { - deviceInfoSet = SetupDiGetClassDevs(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, - DIGCF_PRESENT | DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES); - if (deviceInfoSet == FileIO.INVALID_HANDLE_VALUE) - throw APIException.Win32("Failed to enumerate devices."); - int memberIndex = 0; - while (true) - { - // Begin with 0 and increment through the device information set until - // no more devices are available. - SP_DEVICE_INTERFACE_DATA deviceInterfaceData = new SP_DEVICE_INTERFACE_DATA(); - - // The cbSize element of the deviceInterfaceData structure must be set to - // the structure's size in bytes. - // The size is 28 bytes for 32-bit code and 32 bytes for 64-bit code. - deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData); - - bool success; - - success = SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref guid, memberIndex, ref deviceInterfaceData); - - // Find out if a device information set was retrieved. - if (!success) - { - int lastError = Marshal.GetLastWin32Error(); - if (lastError == ERROR_NO_MORE_ITEMS) - break; - - throw APIException.Win32("Failed to get device interface."); - } - // A device is present. - - int bufferSize = 0; - - success = SetupDiGetDeviceInterfaceDetail - (deviceInfoSet, - ref deviceInterfaceData, - IntPtr.Zero, - 0, - ref bufferSize, - IntPtr.Zero); - - if (!success) - { - if (Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER) - throw APIException.Win32("Failed to get interface details buffer size."); - } - - IntPtr detailDataBuffer = IntPtr.Zero; - try - { - - // Allocate memory for the SP_DEVICE_INTERFACE_DETAIL_DATA structure using the returned buffer size. - detailDataBuffer = Marshal.AllocHGlobal(bufferSize); - - // Store cbSize in the first bytes of the array. The number of bytes varies with 32- and 64-bit systems. - - Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); - - // Call SetupDiGetDeviceInterfaceDetail again. - // This time, pass a pointer to DetailDataBuffer - // and the returned required buffer size. - - // build a DevInfo Data structure - SP_DEVINFO_DATA da = new SP_DEVINFO_DATA(); - da.cbSize = Marshal.SizeOf(da); - - - success = SetupDiGetDeviceInterfaceDetail - (deviceInfoSet, - ref deviceInterfaceData, - detailDataBuffer, - bufferSize, - ref bufferSize, - ref da); - - if (!success) - throw APIException.Win32("Failed to get device interface details."); - - - // Skip over cbsize (4 bytes) to get the address of the devicePathName. - - IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt64() + 4); - string pathName = Marshal.PtrToStringUni(pDevicePathName); - - // Get the String containing the devicePathName. - - DeviceDetails details = GetDeviceDetails(pathName, deviceInfoSet, da); - - if (details.VID == vid && details.PID == pid) - deviceList.Add(details); - } - finally - { - if (detailDataBuffer != IntPtr.Zero) - { - Marshal.FreeHGlobal(detailDataBuffer); - detailDataBuffer = IntPtr.Zero; - } - } - memberIndex++; - } - } - finally - { - if (deviceInfoSet != IntPtr.Zero && deviceInfoSet != FileIO.INVALID_HANDLE_VALUE) - { - SetupDiDestroyDeviceInfoList(deviceInfoSet); - } - } - return deviceList.ToArray(); - } - - - public static void RegisterForDeviceNotifications(IntPtr controlHandle, Guid classGuid, ref IntPtr deviceNotificationHandle) - { - - DEV_BROADCAST_DEVICEINTERFACE devBroadcastDeviceInterface = new DEV_BROADCAST_DEVICEINTERFACE(); - IntPtr devBroadcastDeviceInterfaceBuffer = IntPtr.Zero; - try - { - int size = Marshal.SizeOf(devBroadcastDeviceInterface); - devBroadcastDeviceInterface.dbcc_size = size; - - devBroadcastDeviceInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; - devBroadcastDeviceInterface.dbcc_reserved = 0; - devBroadcastDeviceInterface.dbcc_classguid = classGuid; - devBroadcastDeviceInterfaceBuffer = Marshal.AllocHGlobal(size); - - // Copy the DEV_BROADCAST_DEVICEINTERFACE structure to the buffer. - // Set fDeleteOld True to prevent memory leaks. - Marshal.StructureToPtr(devBroadcastDeviceInterface, devBroadcastDeviceInterfaceBuffer, true); - - deviceNotificationHandle = RegisterDeviceNotification(controlHandle, devBroadcastDeviceInterfaceBuffer, DEVICE_NOTIFY_WINDOW_HANDLE); - if (deviceNotificationHandle == IntPtr.Zero) - throw APIException.Win32("Failed to register device notification"); - - // Marshal data from the unmanaged block devBroadcastDeviceInterfaceBuffer to - // the managed object devBroadcastDeviceInterface - Marshal.PtrToStructure(devBroadcastDeviceInterfaceBuffer, devBroadcastDeviceInterface); - } - finally - { - // Free the memory allocated previously by AllocHGlobal. - if (devBroadcastDeviceInterfaceBuffer != IntPtr.Zero) - Marshal.FreeHGlobal(devBroadcastDeviceInterfaceBuffer); - } - } - - public static void StopDeviceDeviceNotifications(IntPtr deviceNotificationHandle) - { - if (!DeviceManagement.UnregisterDeviceNotification(deviceNotificationHandle)) - throw APIException.Win32("Failed to unregister device notification"); - } - } -} +/* WinUSBNet library
+ * (C) 2010 Thomas Bleeker (www.madwizard.org)
+ *
+ * Licensed under the MIT license, see license.txt or:
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+/* NOTE: Parts of the code in this file are based on the work of Jan Axelson
+ * See http://www.lvr.com/winusb.htm for more information
+ */
+
+using System;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Windows.Forms;
+using System.Text.RegularExpressions;
+
+namespace MadWizard.WinUSBNet.API
+{
+ /// <summary>
+ /// Routines for detecting devices and receiving device notifications.
+ /// </summary>
+ internal static partial class DeviceManagement
+ {
+
+ // Get device name from notification message.
+ // Also checks checkGuid with the GUID from the message to check the notification
+ // is for a relevant device. Other messages might be received.
+ public static string GetNotifyMessageDeviceName(Message m, Guid checkGuid)
+ {
+ int stringSize;
+
+
+ DEV_BROADCAST_DEVICEINTERFACE_1 devBroadcastDeviceInterface = new DEV_BROADCAST_DEVICEINTERFACE_1();
+ DEV_BROADCAST_HDR devBroadcastHeader = new DEV_BROADCAST_HDR();
+
+ // The LParam parameter of Message is a pointer to a DEV_BROADCAST_HDR structure.
+
+ Marshal.PtrToStructure(m.LParam, devBroadcastHeader);
+
+ if ((devBroadcastHeader.dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE))
+ {
+ // The dbch_devicetype parameter indicates that the event applies to a device interface.
+ // So the structure in LParam is actually a DEV_BROADCAST_INTERFACE structure,
+ // which begins with a DEV_BROADCAST_HDR.
+
+ // Obtain the number of characters in dbch_name by subtracting the 32 bytes
+ // in the strucutre that are not part of dbch_name and dividing by 2 because there are
+ // 2 bytes per character.
+
+ stringSize = System.Convert.ToInt32((devBroadcastHeader.dbch_size - 32) / 2);
+
+ // The dbcc_name parameter of devBroadcastDeviceInterface contains the device name.
+ // Trim dbcc_name to match the size of the String.
+
+ devBroadcastDeviceInterface.dbcc_name = new char[stringSize + 1];
+
+ // Marshal data from the unmanaged block pointed to by m.LParam
+ // to the managed object devBroadcastDeviceInterface.
+
+ Marshal.PtrToStructure(m.LParam, devBroadcastDeviceInterface);
+
+ // Check if message is for the GUID
+ if (devBroadcastDeviceInterface.dbcc_classguid != checkGuid)
+ return null;
+
+ // Store the device name in a String.
+ string deviceNameString = new String(devBroadcastDeviceInterface.dbcc_name, 0, stringSize);
+
+ return deviceNameString;
+
+ }
+ return null;
+ }
+
+ private static byte[] GetProperty(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, SPDRP property, out int regType)
+ {
+ uint requiredSize;
+
+ if (!SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref deviceInfoData, property, IntPtr.Zero, IntPtr.Zero, 0, out requiredSize))
+ {
+ if (Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER)
+ throw APIException.Win32("Failed to get buffer size for device registry property.");
+ }
+
+ byte[] buffer = new byte[requiredSize];
+
+ if (!SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref deviceInfoData, property, out regType, buffer, (uint)buffer.Length, out requiredSize))
+ throw APIException.Win32("Failed to get device registry property.");
+
+ return buffer;
+
+
+
+ }
+
+ // todo: is the queried data always available, or should we check ERROR_INVALID_DATA?
+ private static string GetStringProperty(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, SPDRP property)
+ {
+ int regType;
+ byte[] buffer = GetProperty(deviceInfoSet, deviceInfoData, property, out regType);
+ if (regType != (int)RegTypes.REG_SZ)
+ throw new APIException("Invalid registry type returned for device property.");
+
+ // sizof(char), 2 bytes, are removed to leave out the string terminator
+ return System.Text.Encoding.Unicode.GetString(buffer, 0, buffer.Length - sizeof(char));
+ }
+
+ private static string[] GetMultiStringProperty(IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData, SPDRP property)
+ {
+ int regType;
+ byte[] buffer = GetProperty(deviceInfoSet, deviceInfoData, property, out regType);
+ if (regType != (int)RegTypes.REG_MULTI_SZ)
+ throw new APIException("Invalid registry type returned for device property.");
+
+ string fullString = System.Text.Encoding.Unicode.GetString(buffer);
+
+ return fullString.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);
+
+ }
+ private static DeviceDetails GetDeviceDetails(string devicePath, IntPtr deviceInfoSet, SP_DEVINFO_DATA deviceInfoData)
+ {
+ DeviceDetails details = new DeviceDetails();
+ details.DevicePath = devicePath;
+ details.DeviceDescription = GetStringProperty(deviceInfoSet, deviceInfoData, SPDRP.SPDRP_DEVICEDESC);
+ details.Manufacturer = GetStringProperty(deviceInfoSet, deviceInfoData, SPDRP.SPDRP_MFG);
+ string[] hardwareIDs = GetMultiStringProperty(deviceInfoSet, deviceInfoData, SPDRP.SPDRP_HARDWAREID);
+
+ Regex regex = new Regex("^USB\\\\VID_([0-9A-F]{4})&PID_([0-9A-F]{4})", RegexOptions.IgnoreCase);
+ bool foundVidPid = false;
+ foreach (string hardwareID in hardwareIDs)
+ {
+ Match match = regex.Match(hardwareID);
+ if (match.Success)
+ {
+ details.VID = ushort.Parse(match.Groups[1].Value, System.Globalization.NumberStyles.AllowHexSpecifier);
+ details.PID = ushort.Parse(match.Groups[2].Value, System.Globalization.NumberStyles.AllowHexSpecifier);
+ foundVidPid = true;
+ break;
+ }
+ }
+
+ if (!foundVidPid)
+ throw new APIException("Failed to find VID and PID for USB device. No hardware ID could be parsed.");
+
+ return details;
+ }
+
+
+ public static DeviceDetails[] FindDevices(UInt16 vid, UInt16 pid)
+ {
+ IntPtr deviceInfoSet = IntPtr.Zero;
+ List<DeviceDetails> deviceList = new List<DeviceDetails>();
+ var guid = new Guid("{A5DCBF10-6530-11D2-901F-00C04FB951ED}"); // USB device
+ try
+ {
+ deviceInfoSet = SetupDiGetClassDevs(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero,
+ DIGCF_PRESENT | DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES);
+ if (deviceInfoSet == FileIO.INVALID_HANDLE_VALUE)
+ throw APIException.Win32("Failed to enumerate devices.");
+ int memberIndex = 0;
+ while (true)
+ {
+ // Begin with 0 and increment through the device information set until
+ // no more devices are available.
+ SP_DEVICE_INTERFACE_DATA deviceInterfaceData = new SP_DEVICE_INTERFACE_DATA();
+
+ // The cbSize element of the deviceInterfaceData structure must be set to
+ // the structure's size in bytes.
+ // The size is 28 bytes for 32-bit code and 32 bytes for 64-bit code.
+ deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData);
+
+ bool success;
+
+ success = SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref guid, memberIndex, ref deviceInterfaceData);
+
+ // Find out if a device information set was retrieved.
+ if (!success)
+ {
+ int lastError = Marshal.GetLastWin32Error();
+ if (lastError == ERROR_NO_MORE_ITEMS)
+ break;
+
+ throw APIException.Win32("Failed to get device interface.");
+ }
+ // A device is present.
+
+ int bufferSize = 0;
+
+ success = SetupDiGetDeviceInterfaceDetail
+ (deviceInfoSet,
+ ref deviceInterfaceData,
+ IntPtr.Zero,
+ 0,
+ ref bufferSize,
+ IntPtr.Zero);
+
+ if (!success)
+ {
+ if (Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER)
+ throw APIException.Win32("Failed to get interface details buffer size.");
+ }
+
+ IntPtr detailDataBuffer = IntPtr.Zero;
+ try
+ {
+
+ // Allocate memory for the SP_DEVICE_INTERFACE_DETAIL_DATA structure using the returned buffer size.
+ detailDataBuffer = Marshal.AllocHGlobal(bufferSize);
+
+ // Store cbSize in the first bytes of the array. The number of bytes varies with 32- and 64-bit systems.
+
+ Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8);
+
+ // Call SetupDiGetDeviceInterfaceDetail again.
+ // This time, pass a pointer to DetailDataBuffer
+ // and the returned required buffer size.
+
+ // build a DevInfo Data structure
+ SP_DEVINFO_DATA da = new SP_DEVINFO_DATA();
+ da.cbSize = Marshal.SizeOf(da);
+
+
+ success = SetupDiGetDeviceInterfaceDetail
+ (deviceInfoSet,
+ ref deviceInterfaceData,
+ detailDataBuffer,
+ bufferSize,
+ ref bufferSize,
+ ref da);
+
+ if (!success)
+ throw APIException.Win32("Failed to get device interface details.");
+
+
+ // Skip over cbsize (4 bytes) to get the address of the devicePathName.
+
+ IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt64() + 4);
+ string pathName = Marshal.PtrToStringUni(pDevicePathName);
+
+ // Get the String containing the devicePathName.
+ try
+ {
+ DeviceDetails details = GetDeviceDetails(pathName, deviceInfoSet, da);
+ if (details.VID == vid && details.PID == pid)
+ deviceList.Add(details);
+ }
+ catch (APIException)
+ {
+ continue;
+ }
+ }
+ finally
+ {
+ if (detailDataBuffer != IntPtr.Zero)
+ {
+ Marshal.FreeHGlobal(detailDataBuffer);
+ detailDataBuffer = IntPtr.Zero;
+ }
+ }
+ memberIndex++;
+ }
+ }
+ finally
+ {
+ if (deviceInfoSet != IntPtr.Zero && deviceInfoSet != FileIO.INVALID_HANDLE_VALUE)
+ {
+ SetupDiDestroyDeviceInfoList(deviceInfoSet);
+ }
+ }
+ return deviceList.ToArray();
+ }
+
+
+ public static void RegisterForDeviceNotifications(IntPtr controlHandle, Guid classGuid, ref IntPtr deviceNotificationHandle)
+ {
+
+ DEV_BROADCAST_DEVICEINTERFACE devBroadcastDeviceInterface = new DEV_BROADCAST_DEVICEINTERFACE();
+ IntPtr devBroadcastDeviceInterfaceBuffer = IntPtr.Zero;
+ try
+ {
+ int size = Marshal.SizeOf(devBroadcastDeviceInterface);
+ devBroadcastDeviceInterface.dbcc_size = size;
+
+ devBroadcastDeviceInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
+ devBroadcastDeviceInterface.dbcc_reserved = 0;
+ devBroadcastDeviceInterface.dbcc_classguid = classGuid;
+ devBroadcastDeviceInterfaceBuffer = Marshal.AllocHGlobal(size);
+
+ // Copy the DEV_BROADCAST_DEVICEINTERFACE structure to the buffer.
+ // Set fDeleteOld True to prevent memory leaks.
+ Marshal.StructureToPtr(devBroadcastDeviceInterface, devBroadcastDeviceInterfaceBuffer, true);
+
+ deviceNotificationHandle = RegisterDeviceNotification(controlHandle, devBroadcastDeviceInterfaceBuffer, DEVICE_NOTIFY_WINDOW_HANDLE);
+ if (deviceNotificationHandle == IntPtr.Zero)
+ throw APIException.Win32("Failed to register device notification");
+
+ // Marshal data from the unmanaged block devBroadcastDeviceInterfaceBuffer to
+ // the managed object devBroadcastDeviceInterface
+ Marshal.PtrToStructure(devBroadcastDeviceInterfaceBuffer, devBroadcastDeviceInterface);
+ }
+ finally
+ {
+ // Free the memory allocated previously by AllocHGlobal.
+ if (devBroadcastDeviceInterfaceBuffer != IntPtr.Zero)
+ Marshal.FreeHGlobal(devBroadcastDeviceInterfaceBuffer);
+ }
+ }
+
+ public static void StopDeviceDeviceNotifications(IntPtr deviceNotificationHandle)
+ {
+ if (!DeviceManagement.UnregisterDeviceNotification(deviceNotificationHandle))
+ throw APIException.Win32("Failed to unregister device notification");
+ }
+ }
+}
|