// Copyright © 2006-2010 Travis Robinson. All rights reserved.
//
// website: http://sourceforge.net/projects/libusbdotnet
// e-mail: libusbdotnet@gmail.com
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or
// visit www.gnu.org.
//
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using LibUsbDotNet.Internal;
using LibUsbDotNet.Internal.UsbRegex;
using LibUsbDotNet.Main;
using Microsoft.Win32;
namespace LibUsbDotNet.WinUsb
{
/// WinUsb specific members for device registry settings.
///
public class WinUsbRegistry : UsbRegistry
{
private bool mIsDeviceIDParsed;
private string mDeviceID;
// Parsed out of the device ID
private byte mInterfaceID;
private ushort mVid;
private ushort mPid;
///
/// Gets a list of WinUSB device paths for the specified interface guid.
///
/// The DeviceInterfaceGUID to search for.
/// A list of device paths associated with the .
/// True of one or more device paths was found.
///
/// Each device path string in the represents a seperate WinUSB device (interface).
///
///
public static bool GetDevicePathList(Guid deviceInterfaceGuid, out List devicePathList)
{
devicePathList = new List();
int devicePathIndex = 0;
SetupApi.SP_DEVICE_INTERFACE_DATA interfaceData = SetupApi.SP_DEVICE_INTERFACE_DATA.Empty;
SetupApi.DeviceInterfaceDetailHelper detailHelper;
IntPtr deviceInfo = SetupApi.SetupDiGetClassDevs(ref deviceInterfaceGuid, null, IntPtr.Zero, SetupApi.DICFG.PRESENT | SetupApi.DICFG.DEVICEINTERFACE);
if (deviceInfo != IntPtr.Zero)
{
while ((SetupApi.SetupDiEnumDeviceInterfaces(deviceInfo, null, ref deviceInterfaceGuid, devicePathIndex, ref interfaceData)))
{
int length = 1024;
detailHelper = new SetupApi.DeviceInterfaceDetailHelper(length);
bool bResult = SetupApi.SetupDiGetDeviceInterfaceDetail(deviceInfo, ref interfaceData, detailHelper.Handle, length, out length, null);
if (bResult) devicePathList.Add(detailHelper.DevicePath);
devicePathIndex++;
}
}
if (devicePathIndex == 0)
UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "GetDevicePathList", typeof(SetupApi));
if (deviceInfo != IntPtr.Zero)
SetupApi.SetupDiDestroyDeviceInfoList(deviceInfo);
return (devicePathIndex > 0);
}
///
/// Gets a list of classes for the specified interface guid.
///
/// The DeviceInterfaceGUID to search for.
/// A list of device paths associated with the .
/// True of one or more device paths was found.
///
/// Each in the represents a seperate WinUSB device (interface).
///
public static bool GetWinUsbRegistryList(Guid deviceInterfaceGuid, out List deviceRegistryList)
{
deviceRegistryList = new List();
int devicePathIndex = 0;
SetupApi.SP_DEVICE_INTERFACE_DATA interfaceData = SetupApi.SP_DEVICE_INTERFACE_DATA.Empty;
SetupApi.DeviceInterfaceDetailHelper detailHelper;
SetupApi.SP_DEVINFO_DATA devInfoData = SetupApi.SP_DEVINFO_DATA.Empty;
// [1]
IntPtr deviceInfo = SetupApi.SetupDiGetClassDevs(ref deviceInterfaceGuid, null, IntPtr.Zero, SetupApi.DICFG.PRESENT | SetupApi.DICFG.DEVICEINTERFACE);
if (deviceInfo != IntPtr.Zero)
{
while ((SetupApi.SetupDiEnumDeviceInterfaces(deviceInfo, null, ref deviceInterfaceGuid, devicePathIndex, ref interfaceData)))
{
int length = 1024;
detailHelper = new SetupApi.DeviceInterfaceDetailHelper(length);
bool bResult = SetupApi.SetupDiGetDeviceInterfaceDetail(deviceInfo, ref interfaceData, detailHelper.Handle, length, out length, ref devInfoData);
if (bResult)
{
WinUsbRegistry regInfo = new WinUsbRegistry();
SetupApi.getSPDRPProperties(deviceInfo, ref devInfoData, regInfo.mDeviceProperties);
// Use the actual winusb device path for SYMBOLIC_NAME_KEY. This will be used to open the device.
regInfo.mDeviceProperties.Add(SYMBOLIC_NAME_KEY, detailHelper.DevicePath);
//Debug.WriteLine(detailHelper.DevicePath);
regInfo.mDeviceInterfaceGuids = new Guid[] { deviceInterfaceGuid };
StringBuilder sbDeviceID=new StringBuilder(1024);
if (SetupApi.CM_Get_Device_ID(devInfoData.DevInst,sbDeviceID,sbDeviceID.Capacity,0)==SetupApi.CR.SUCCESS)
{
regInfo.mDeviceProperties[DEVICE_ID_KEY] = sbDeviceID.ToString();
}
deviceRegistryList.Add(regInfo);
}
devicePathIndex++;
}
}
if (devicePathIndex == 0)
UsbError.Error(ErrorCode.Win32Error, Marshal.GetLastWin32Error(), "GetDevicePathList", typeof(SetupApi));
if (deviceInfo != IntPtr.Zero)
SetupApi.SetupDiDestroyDeviceInfoList(deviceInfo);
return (devicePathIndex > 0);
}
internal WinUsbRegistry() { }
///
/// Gets a list of available LibUsb devices.
///
public static List DeviceList
{
get
{
List deviceList = new List();
SetupApi.EnumClassDevs(null, SetupApi.DICFG.ALLCLASSES | SetupApi.DICFG.PRESENT, WinUsbRegistryCallBack, deviceList);
return deviceList;
}
}
///
/// Gets a collection of DeviceInterfaceGuids that are associated with this WinUSB device.
///
public override Guid[] DeviceInterfaceGuids
{
get
{
return mDeviceInterfaceGuids;
}
}
///
/// Check this value to determine if the usb device is still connected to the bus and ready to open.
///
///
/// Uses the symbolic name as a unique id to determine if this device instance is still attached.
///
/// An exception is thrown if the property is null or empty.
public override bool IsAlive
{
get
{
if (String.IsNullOrEmpty(SymbolicName)) throw new UsbException(this, "A symbolic name is required for this property.");
List deviceList = DeviceList;
foreach (WinUsbRegistry registry in deviceList)
{
if (String.IsNullOrEmpty(registry.SymbolicName)) continue;
if (registry.SymbolicName == SymbolicName)
return true;
}
return false;
}
}
///
/// Opens the USB device for communucation.
///
/// Return a new instance of the class.
/// If the device fails to open a null refrence is return. For extended error
/// information use the .
///
public override UsbDevice Device
{
get
{
WinUsbDevice winUsbDevice;
Open(out winUsbDevice);
return winUsbDevice;
}
}
private void parseDeviceID()
{
if (mIsDeviceIDParsed) return;
mIsDeviceIDParsed = true;
byte bTemp;
ushort uTemp;
MatchCollection matches = RegHardwareID.GlobalInstance.Matches(DeviceID);
foreach (Match match in matches)
{
foreach (NamedGroup namedGroup in RegHardwareID.NAMED_GROUPS)
{
Group g = match.Groups[namedGroup.GroupNumber];
if (g.Success)
{
switch ((RegHardwareID.ENamedGroups)namedGroup.GroupNumber)
{
case RegHardwareID.ENamedGroups.Vid:
if (ushort.TryParse(g.Value, NumberStyles.HexNumber, null, out uTemp))
{
mVid = uTemp;
break;
}
break;
case RegHardwareID.ENamedGroups.Pid:
if (ushort.TryParse(g.Value, NumberStyles.HexNumber, null, out uTemp))
{
mPid = uTemp;
break;
}
break;
case RegHardwareID.ENamedGroups.Rev:
break;
case RegHardwareID.ENamedGroups.MI:
if (Byte.TryParse(g.Value, NumberStyles.HexNumber, null, out bTemp))
{
mInterfaceID = bTemp;
break;
}
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
}
}
///
/// Gets the device instance id.
///
///
/// For more information on device instance ids, see the CM_Get_Device_ID Function at MSDN.
///
public string DeviceID
{
get
{
if (ReferenceEquals(mDeviceID,null))
{
object oDeviceID;
if (mDeviceProperties.TryGetValue(DEVICE_ID_KEY, out oDeviceID))
{
mDeviceID = oDeviceID.ToString();
}
else
{
mDeviceID = string.Empty;
}
}
return mDeviceID;
}
}
///
/// VendorID
///
/// This value is parsed out of the field.
public override int Vid
{
get
{
parseDeviceID();
return mVid;
}
}
///
/// ProductID
///
/// This value is parsed out of the field.
public override int Pid
{
get
{
parseDeviceID();
return mPid;
}
}
///
/// Gets the interface ID this WinUSB device (interface) is associated with.
///
/// This value is parsed out of the field.
public byte InterfaceID
{
get
{
parseDeviceID();
return (byte) mInterfaceID;
}
}
///
/// Opens the USB device for communucation.
///
/// The newly created UsbDevice.
/// True on success.
public override bool Open(out UsbDevice usbDevice)
{
usbDevice = null;
WinUsbDevice winUsbDevice;
bool bSuccess = Open(out winUsbDevice);
if (bSuccess)
usbDevice = winUsbDevice;
return bSuccess;
}
///
/// Opens the USB device for communucation.
///
/// Returns an opened WinUsb device on success, null on failure.
/// True on success.
public bool Open(out WinUsbDevice usbDevice)
{
usbDevice = null;
if (String.IsNullOrEmpty(SymbolicName)) return false;
if (WinUsbDevice.Open(SymbolicName, out usbDevice))
{
usbDevice.mUsbRegistry = this;
return true;
}
return false;
}
/*
private static bool WinUsbRegistryCallBack(IntPtr deviceInfoSet,
int deviceIndex,
ref SetupApi.SP_DEVINFO_DATA deviceInfoData,
object classEnumeratorCallbackParam1)
{
List deviceList = (List) classEnumeratorCallbackParam1;
RegistryValueKind propertyType;
byte[] propBuffer = new byte[256];
int requiredSize;
bool isNew = true;
bool bSuccess;
bSuccess = SetupApi.SetupDiGetCustomDeviceProperty(deviceInfoSet,
ref deviceInfoData,
DEVICE_INTERFACE_GUIDS,
SetupApi.DICUSTOMDEVPROP.NONE,
out propertyType,
propBuffer,
propBuffer.Length,
out requiredSize);
if (bSuccess)
{
string[] devInterfaceGuids = GetAsStringArray(propBuffer, requiredSize);
foreach (String devInterfaceGuid in devInterfaceGuids)
{
Guid g = new Guid(devInterfaceGuid);
List devicePaths;
if (SetupApi.GetDevicePathList(g, out devicePaths))
{
foreach (string devicePath in devicePaths)
{
WinUsbRegistry regInfo = new WinUsbRegistry();
SetupApi.getSPDRPProperties(deviceInfoSet, ref deviceInfoData, regInfo.mDeviceProperties);
// Use the actual winusb device path for SYMBOLIC_NAME_KEY. This will be used to open the device.
regInfo.mDeviceProperties.Add(SYMBOLIC_NAME_KEY, devicePath);
regInfo.mDeviceInterfaceGuids = new Guid[] { g };
// Don't add duplicate devices (with the same device path)
WinUsbRegistry foundRegistry=null;
foreach (WinUsbRegistry usbRegistry in deviceList)
{
if (usbRegistry.SymbolicName == regInfo.SymbolicName)
{
foundRegistry = usbRegistry;
break;
}
}
if (foundRegistry == null)
deviceList.Add(regInfo);
else
{
if (isNew)
{
deviceList.Remove(foundRegistry);
deviceList.Add(regInfo);
}
else
{
// If the device path already exists, add this compatible guid
// to the foundRegstry guid list.
List newGuidList = new List(foundRegistry.mDeviceInterfaceGuids);
if (!newGuidList.Contains(g))
{
newGuidList.Add(g);
foundRegistry.mDeviceInterfaceGuids = newGuidList.ToArray();
}
}
}
isNew = false;
}
}
}
}
return false;
}
*/
private static bool WinUsbRegistryCallBack(IntPtr deviceInfoSet,
int deviceIndex,
ref SetupApi.SP_DEVINFO_DATA deviceInfoData,
object classEnumeratorCallbackParam1)
{
List deviceList = (List)classEnumeratorCallbackParam1;
RegistryValueKind propertyType;
byte[] propBuffer = new byte[256];
int requiredSize;
bool bSuccess;
bSuccess = SetupApi.SetupDiGetCustomDeviceProperty(deviceInfoSet,
ref deviceInfoData,
DEVICE_INTERFACE_GUIDS,
SetupApi.DICUSTOMDEVPROP.NONE,
out propertyType,
propBuffer,
propBuffer.Length,
out requiredSize);
if (bSuccess)
{
string[] devInterfaceGuids = GetAsStringArray(propBuffer, requiredSize);
foreach (String devInterfaceGuid in devInterfaceGuids)
{
Guid g = new Guid(devInterfaceGuid);
List tempList;
if (GetWinUsbRegistryList(g, out tempList))
{
foreach (WinUsbRegistry regInfo in tempList)
{
// Don't add duplicate devices (with the same device path)
WinUsbRegistry foundRegistry = null;
foreach (WinUsbRegistry usbRegistry in deviceList)
{
if (usbRegistry.SymbolicName == regInfo.SymbolicName)
{
foundRegistry = usbRegistry;
break;
}
}
if (foundRegistry == null)
deviceList.Add(regInfo);
else
{
// If the device path already exists, add this compatible guid
// to the foundRegstry guid list.
List newGuidList = new List(foundRegistry.mDeviceInterfaceGuids);
if (!newGuidList.Contains(g))
{
newGuidList.Add(g);
foundRegistry.mDeviceInterfaceGuids = newGuidList.ToArray();
}
}
}
}
}
}
return false;
}
}
}