417 lines
20 KiB
C#
417 lines
20 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.Text;
|
|
using System.Runtime.InteropServices;
|
|
using System.Windows.Forms;
|
|
using DTS.Common.Utilities.Logging;
|
|
|
|
namespace DTS.Common.USBFramework
|
|
{
|
|
public class DeviceManagement : IDisposable
|
|
{
|
|
public void Dispose()
|
|
{
|
|
}
|
|
|
|
public bool DeviceNameMatch(Message m, string mydevicePathName)
|
|
{
|
|
// Purpose : Compares two device path names. Used to find out if the device name
|
|
// : of a recently attached or removed device matches the name of a
|
|
// : device the application is communicating with.
|
|
// Accepts : m - a WM_DEVICECHANGE message. A call to RegisterDeviceNotification
|
|
// : causes WM_DEVICECHANGE messages to be passed to an OnDeviceChange routine.
|
|
// : mydevicePathName - a device pathname returned by SetupDiGetDeviceInterfaceDetail
|
|
// : in an SP_DEVICE_INTERFACE_DETAIL_DATA structure.
|
|
// Returns : True if the names match, False if not.
|
|
|
|
var devBroadcastDeviceInterface = new DeviceManagementDeclarations.DEV_BROADCAST_DEVICEINTERFACE_1();
|
|
var devBroadcastHeader = new DeviceManagementDeclarations.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 != DeviceManagementDeclarations.DBT_DEVTYP_DEVICEINTERFACE) return false;
|
|
// 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 28 bytes
|
|
// in the other members of the structure and dividing by 2 because there are
|
|
// 2 bytes per character.
|
|
var stringSize = Convert.ToInt32((devBroadcastHeader.dbch_size - 28) / 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);
|
|
|
|
// Store the device name in a String.
|
|
var deviceNameString = new string(devBroadcastDeviceInterface.dbcc_name, 0, stringSize);
|
|
|
|
//Debug.WriteLine("Device Name = " + DeviceNameString);
|
|
//Debug.WriteLine("");
|
|
|
|
// Compare the name of the newly attached device with the name of the device
|
|
// the application is accessing (mydevicePathName).
|
|
// Set ignorecase True.
|
|
if (string.Compare(deviceNameString, mydevicePathName, true) == 0)
|
|
{
|
|
// The name matches.
|
|
return true;
|
|
}
|
|
|
|
// It's a different device.
|
|
return false;
|
|
}
|
|
|
|
public bool FindDeviceFromGuid(System.Guid myGuid, ref string[] devicePathName)
|
|
{
|
|
// Purpose : Uses SetupDi API functions to retrieve the device path name of an
|
|
// : attached device that belongs to an interface class.
|
|
// Accepts : myGuid - an interface class GUID.
|
|
// : devicePathName - a pointer to an array of strings that will contain
|
|
// : the device path names of attached devices.
|
|
// Returns : True if at least one device is found, False if not.
|
|
|
|
var lastDevice = false;
|
|
var bufferSize = 0;
|
|
var myDeviceInterfaceDetailData = new DeviceManagementDeclarations.SP_DEVICE_INTERFACE_DETAIL_DATA();
|
|
var myDeviceInterfaceData = new DeviceManagementDeclarations.SP_DEVICE_INTERFACE_DATA();
|
|
int result;
|
|
var detailDataBuffer = IntPtr.Zero;
|
|
|
|
// ***
|
|
// API function: SetupDiGetClassDevs
|
|
// Purpose:
|
|
// Retrieves a device information set for a specified group of devices.
|
|
// SetupDiEnumDeviceInterfaces uses the device information set.
|
|
// Accepts:
|
|
// An interface class GUID
|
|
// Null to retrieve information for all device instances
|
|
// An optional handle to a top-level window (unused here)
|
|
// Flags to limit the returned information to currently present devices
|
|
// and devices that expose interfaces in the class specified by the GUID.
|
|
// Returns:
|
|
// A handle to a device information set for the devices.
|
|
// ***
|
|
|
|
var deviceInfoSet = DeviceManagementDeclarations.SetupDiGetClassDevs(ref myGuid,
|
|
null,
|
|
0,
|
|
DeviceManagementDeclarations.DIGCF_PRESENT | DeviceManagementDeclarations.DIGCF_DEVICEINTERFACE);
|
|
|
|
var deviceFound = false;
|
|
var memberIndex = 0;
|
|
try
|
|
{
|
|
do
|
|
{
|
|
|
|
// Begin with 0 and increment through the device information set until
|
|
// no more devices are available.
|
|
|
|
// The cbSize element of the MyDeviceInterfaceData structure must be set to
|
|
// the structure's size in bytes.
|
|
// The size is 28 bytes for 32-bit code and 32 bits for 64-bit code.
|
|
|
|
myDeviceInterfaceData.cbSize = Marshal.SizeOf(myDeviceInterfaceData);
|
|
|
|
// ***
|
|
// API function:
|
|
// SetupDiEnumDeviceInterfaces()
|
|
// Purpose: Retrieves a handle to a SP_DEVICE_INTERFACE_DATA
|
|
// structure for a device.
|
|
// On return, MyDeviceInterfaceData contains the handle to a
|
|
// SP_DEVICE_INTERFACE_DATA structure for a detected device.
|
|
// Accepts:
|
|
// A DeviceInfoSet returned by SetupDiGetClassDevs.
|
|
// An interface class GUID.
|
|
// An index to specify a device in a device information set.
|
|
// A pointer to a handle to a SP_DEVICE_INTERFACE_DATA structure for a device.
|
|
// Returns:
|
|
// Non-zero on success, zero on True.
|
|
// ***
|
|
|
|
result = DeviceManagementDeclarations.SetupDiEnumDeviceInterfaces(deviceInfoSet,
|
|
IntPtr.Zero,
|
|
ref myGuid,
|
|
memberIndex,
|
|
ref myDeviceInterfaceData);
|
|
|
|
// Find out if a device information set was retrieved.
|
|
|
|
if (result == 0)
|
|
{
|
|
lastDevice = true;
|
|
}
|
|
else
|
|
{
|
|
// A device is present.
|
|
// ***
|
|
// API function:
|
|
// SetupDiGetDeviceInterfaceDetail()
|
|
// Purpose:
|
|
// Retrieves an SP_DEVICE_INTERFACE_DETAIL_DATA structure
|
|
// containing information about a device.
|
|
// To retrieve the information, call this function twice.
|
|
// The first time returns the size of the structure.
|
|
// The second time returns a pointer to the data.
|
|
// Accepts:
|
|
// A DeviceInfoSet returned by SetupDiGetClassDevs
|
|
// An SP_DEVICE_INTERFACE_DATA structure returned by SetupDiEnumDeviceInterfaces
|
|
// A pointer to an SP_DEVICE_INTERFACE_DETAIL_DATA structure to receive information
|
|
// about the specified interface.
|
|
// The size of the SP_DEVICE_INTERFACE_DETAIL_DATA structure.
|
|
// A pointer to a variable that will receive the returned required size of the
|
|
// SP_DEVICE_INTERFACE_DETAIL_DATA structure.
|
|
// A pointer to an SP_DEVINFO_DATA structure to receive information about the device.
|
|
// Returns:
|
|
// Non-zero on success, zero on failure.
|
|
// ***
|
|
|
|
DeviceManagementDeclarations.SetupDiGetDeviceInterfaceDetail(deviceInfoSet,
|
|
ref myDeviceInterfaceData,
|
|
IntPtr.Zero,
|
|
0,
|
|
ref bufferSize,
|
|
IntPtr.Zero);
|
|
|
|
// Store the structure's size.
|
|
myDeviceInterfaceDetailData.cbSize = Marshal.SizeOf(myDeviceInterfaceDetailData);
|
|
|
|
// Allocate memory for the MyDeviceInterfaceDetailData Structure using the returned buffer size.
|
|
detailDataBuffer = Marshal.AllocHGlobal(bufferSize);
|
|
|
|
// Store cbSize in the first 4 bytes of the array
|
|
if (IS64_BIT_PROCESS)
|
|
{
|
|
Marshal.WriteInt64(detailDataBuffer,
|
|
(IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8);
|
|
}
|
|
else
|
|
{
|
|
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.
|
|
DeviceManagementDeclarations.SetupDiGetDeviceInterfaceDetail(deviceInfoSet,
|
|
ref myDeviceInterfaceData,
|
|
detailDataBuffer,
|
|
bufferSize,
|
|
ref bufferSize,
|
|
IntPtr.Zero);
|
|
|
|
// Skip over cbsize (4 bytes) to get the address of the devicePathName.
|
|
var pdevicePathName = IS64_BIT_PROCESS ? new IntPtr(detailDataBuffer.ToInt64() + 4) : new IntPtr(detailDataBuffer.ToInt32() + 4);
|
|
|
|
// Get the String containing the devicePathName.
|
|
var singledevicePathName = Marshal.PtrToStringAuto(pdevicePathName);
|
|
devicePathName[memberIndex] = singledevicePathName;
|
|
|
|
// Free the memory allocated previously by AllocHGlobal.
|
|
Marshal.FreeHGlobal(detailDataBuffer);
|
|
detailDataBuffer = IntPtr.Zero;
|
|
deviceFound = true;
|
|
}
|
|
memberIndex++;
|
|
} while (!lastDevice);
|
|
}
|
|
finally
|
|
{
|
|
if (detailDataBuffer != IntPtr.Zero)
|
|
{
|
|
// Free the memory allocated previously by AllocHGlobal.
|
|
Marshal.FreeHGlobal(detailDataBuffer);
|
|
}
|
|
if (deviceInfoSet != IntPtr.Zero)
|
|
{
|
|
// ***
|
|
// API function
|
|
|
|
// summary
|
|
// Frees the memory reserved for the DeviceInfoSet returned by SetupDiGetClassDevs.
|
|
|
|
// parameters
|
|
// DeviceInfoSet returned by SetupDiGetClassDevs.
|
|
|
|
// returns
|
|
// True on success.
|
|
// ***
|
|
|
|
|
|
// Trim the array to the number of devices found.
|
|
|
|
// ***
|
|
// API function:
|
|
// SetupDiDestroyDeviceInfoList
|
|
// Purpose:
|
|
// Frees the memory reserved for the DeviceInfoSet returned by SetupDiGetClassDevs.
|
|
// Accepts:
|
|
// A DeviceInfoSet returned by SetupDiGetClassDevs.
|
|
// Returns:
|
|
// True on success, False on failure.
|
|
// ***
|
|
|
|
DeviceManagementDeclarations.SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
|
}
|
|
}
|
|
return deviceFound;
|
|
}
|
|
|
|
public bool RegisterForDeviceNotifications(IntPtr formHandle, Guid classGuid, ref IntPtr deviceNotificationHandle)
|
|
{
|
|
// Purpose : Request to receive a notification when a device is attached or removed.
|
|
// Accepts : devicePathName - a handle to a device.
|
|
// : formHandle - a handle to the window that will receive device events.
|
|
// : classGuid - an interface class GUID.
|
|
//
|
|
// Returns : True on success, False on failure.
|
|
|
|
// A DEV_BROADCAST_DEVICEINTERFACE header holds information about the request.
|
|
var dbdi = new DeviceManagementDeclarations.DEV_BROADCAST_DEVICEINTERFACE();
|
|
|
|
// Set the parameters in the DEV_BROADCAST_DEVICEINTERFACE structure.
|
|
// Set the size.
|
|
var size = Marshal.SizeOf(dbdi);
|
|
dbdi.dbcc_size = size;
|
|
|
|
// Request to receive notifications about a class of devices.
|
|
dbdi.dbcc_devicetype = DeviceManagementDeclarations.DBT_DEVTYP_DEVICEINTERFACE;
|
|
|
|
dbdi.dbcc_reserved = 0;
|
|
|
|
// Specify the interface class to receive notifications about.
|
|
dbdi.dbcc_classguid = classGuid;
|
|
|
|
dbdi.dbcc_name = "";
|
|
|
|
// Allocate memory for the buffer that holds the DEV_BROADCAST_DEVICEINTERFACE structure.
|
|
var buffer = Marshal.AllocHGlobal(size);
|
|
|
|
// Copy the DEV_BROADCAST_DEVICEINTERFACE structure to the buffer.
|
|
// Set fDeleteOld True to prevent memory leaks.
|
|
Marshal.StructureToPtr(dbdi, buffer, true);
|
|
|
|
// ***
|
|
// API function:
|
|
// RegisterDeviceNotification
|
|
// Purpose:
|
|
// Request to receive notification messages when a device in an interface class
|
|
// is attached or removed.
|
|
// Accepts:
|
|
// Aa handle to the window that will receive device events
|
|
// A pointer to a DEV_BROADCAST_DEVICEINTERFACE to specify the type of
|
|
// device to send notifications for,
|
|
// DEVICE_NOTIFY_WINDOW_HANDLE to indicate that Handle is a window handle.
|
|
// Returns:
|
|
// A device notification handle or NULL on failure.
|
|
// ***
|
|
|
|
deviceNotificationHandle = DeviceManagementDeclarations.RegisterDeviceNotification(formHandle,
|
|
buffer,
|
|
DeviceManagementDeclarations.DEVICE_NOTIFY_WINDOW_HANDLE);
|
|
|
|
// Marshal data from the unmanaged block DevBroadcastDeviceInterfaceBuffer to
|
|
// the managed object DevBroadcastDeviceInterface
|
|
//Marshal.PtrToStructure(buffer, dbdi);
|
|
|
|
// Free the memory allocated previously by AllocHGlobal.
|
|
Marshal.FreeHGlobal(buffer);
|
|
|
|
// Find out if RegisterDeviceNotification was successful.
|
|
if (IS64_BIT_PROCESS)
|
|
{
|
|
return deviceNotificationHandle.ToInt64() != IntPtr.Zero.ToInt64();
|
|
}
|
|
return deviceNotificationHandle.ToInt32() != IntPtr.Zero.ToInt32();
|
|
}
|
|
static readonly bool IS64_BIT_PROCESS = (IntPtr.Size == 8);
|
|
|
|
public void StopReceivingDeviceNotifications(IntPtr deviceNotificationHandle)
|
|
{
|
|
|
|
// Purpose : Requests to stop receiving notification messages when a device in an
|
|
// interface class is attached or removed.
|
|
// Accepts : deviceNotificationHandle - a handle returned previously by
|
|
// RegisterDeviceNotification
|
|
|
|
// ***
|
|
// API function: UnregisterDeviceNotification
|
|
// Purpose: Stop receiving notification messages.
|
|
// Accepts: a handle returned previously by RegisterDeviceNotification
|
|
// Returns: True on success, False on failure.
|
|
// ***
|
|
|
|
// Ignore failures.
|
|
DeviceManagementDeclarations.UnregisterDeviceNotification(deviceNotificationHandle);
|
|
}
|
|
|
|
public bool GetDeviceRegistryProperty(Guid myGuid)
|
|
{
|
|
const int maxDevLen = 1000;
|
|
// Create a HDEVINFO with all present devices.
|
|
var deviceInfoSet = DeviceManagementDeclarations.SetupDiGetClassDevs(ref myGuid, // null?
|
|
null, // Enumerator
|
|
0,
|
|
DeviceManagementDeclarations.DIGCF_PRESENT | DeviceManagementDeclarations.DIGCF_ALLCLASSES);
|
|
|
|
if ((int)deviceInfoSet == FileIODeclarations.INVALID_HANDLE_VALUE)
|
|
{
|
|
// Insert error handling here.
|
|
return false;
|
|
}
|
|
|
|
// Enumerate through all devices in Set.
|
|
DeviceManagementDeclarations.SP_DEVINFO_DATA deviceInfoData;
|
|
deviceInfoData.cbSize = Marshal.SizeOf(typeof(DeviceManagementDeclarations.SP_DEVINFO_DATA));
|
|
|
|
for (uint i = 0; DeviceManagementDeclarations.SetupDiEnumDeviceInfo(deviceInfoSet, i, out deviceInfoData); i++)
|
|
{
|
|
var deviceName = new StringBuilder(maxDevLen);
|
|
if (!DeviceManagementDeclarations.SetupDiGetDeviceRegistryPropertyA(deviceInfoSet,
|
|
deviceInfoData,
|
|
DeviceManagementDeclarations.SPDRP_DRIVER,
|
|
0,
|
|
deviceName,
|
|
maxDevLen,
|
|
IntPtr.Zero))
|
|
{
|
|
//incorrect device name:
|
|
DeviceManagementDeclarations.SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
|
deviceName = new StringBuilder("");
|
|
return false;
|
|
}
|
|
APILogger.Log(deviceName.ToString());
|
|
|
|
}
|
|
|
|
|
|
if (DeviceManagementDeclarations.GetLastError() != DeviceManagementDeclarations.NO_ERROR &&
|
|
DeviceManagementDeclarations.GetLastError() != DeviceManagementDeclarations.ERROR_NO_MORE_ITEMS)
|
|
{
|
|
try
|
|
{
|
|
var theGuid = Guid.Empty;
|
|
if (null != myGuid) { theGuid = myGuid; }
|
|
var w32 = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
|
|
APILogger.Log("GetDeviceRegistryProperty(", theGuid.ToString(), ") error - ", w32.Message);
|
|
}
|
|
catch { }
|
|
// Insert error handling here.
|
|
return false;
|
|
}
|
|
|
|
// Cleanup
|
|
DeviceManagementDeclarations.SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|