8$ Definitions Public Structure SP_DEVICE_INTERFACE_DATA Dim cbSize As Int32 Dim InterfaceClassGuid As Guid Dim Flags As Int32 Dim Reserved As IntPtr End Structure _ Shared Function Set
Trang 1In some cases, such as when looking for a HID-class device with a specific Ven-dor ID and Product ID, the application may need to request more information before deciding whether a retrieved device interface is the desired one
8$ Definitions
Public Structure SP_DEVICE_INTERFACE_DATA
Dim cbSize As Int32
Dim InterfaceClassGuid As Guid
Dim Flags As Int32
Dim Reserved As IntPtr
End Structure
<DllImport("setupapi.dll", SetLastError:=True)> _
Shared Function SetupDiEnumDeviceInterfaces _
(ByVal DeviceInfoSet As IntPtr, _
ByVal DeviceInfoData As IntPtr, _
ByRef InterfaceClassGuid As System.Guid, _
ByVal MemberIndex As Int32, _
ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA) _
As Boolean
End Function
Use
Dim memberIndex As Int32 = 0
Dim MyDeviceInterfaceData As SP_DEVICE_INTERFACE_DATA
Dim success As Boolean
MyDeviceInterfaceData.cbSize = Marshal.SizeOf(MyDeviceInterfaceData)
success = SetupDiEnumDeviceInterfaces _
(deviceInfoSet, _
IntPtr.Zero, _
myGuid, _
memberIndex, _
MyDeviceInterfaceData)
Trang 28% Definitions
internal struct SP_DEVICE_INTERFACE_DATA
{
internal Int32 cbSize;
internal Guid InterfaceClassGuid;
internal Int32 Flags;
internal IntPtr Reserved;
}
[DllImport("setupapi.dll", SetLastError = true)]
internal static extern Boolean SetupDiEnumDeviceInterfaces
(IntPtr DeviceInfoSet,
IntPtr DeviceInfoData,
ref System.Guid InterfaceClassGuid,
Int32 MemberIndex,
ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
Use
Int32 memberIndex = 0;
MyDeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA();
Boolean success = false;
MyDeviceInterfaceData.cbSize = = Marshal.SizeOf( MyDeviceInterfaceData );
success = SetupDiEnumDeviceInterfaces
(deviceInfoSet,
IntPtr.Zero,
ref myGuid,
memberIndex,
ref MyDeviceInterfaceData);
&GVCKNU
In the SP_DEVICE_INTERFACE_DATA structure, the cbSize parameter is the size of the structure in bytes The Marshal.SizeOf method returns the struc-ture’s size
The myGuid and deviceInfoSet parameters are values retrieved previously The DeviceInfoData parameter can be a pointer to an SP_DEVINFO_DATA struc-ture that limits the search to a particular device instance or a null pointer The memberIndex parameter is an index to a structure in the deviceInfoSet array
T h e My D e v i c e I n t e r f a c e D a t a p a r a m e t e r i s a p o i n t e r t o t h e
Trang 3structure identifies a device interface of the requested type The function returns true on success
4GSWGUVKPIC5VTWEVWTGYKVJVJG&GXKEG2CVJ0COG
The SetupDiGetDeviceInterfaceDetail function returns a structure that
con-t a i n s a d e v i c e p a con-t h n a m e f o r a d e v i c e i n con-t e r f a c e i d e n con-t i f i e d i n a n SP_DEVICE_INTERFACE_DATA structure
When calling this function for the first time, you don’t know the size in bytes of the DeviceInterfaceDetailData structure to pass in the DeviceInterfaceDetail-DataSize parameter Yet the function won’t return the structure unless the func-tion call passes the correct size The solufunc-tion is to call the funcfunc-tion twice The
first time, GetLastError returns the error The data area passed to a system call is
too small, but the RequiredSize parameter contains the correct value for
Device-InterfaceDetailDataSize The second call passes the returned size value, and the function returns the structure
The code below doesn’t pass a structure for the DeviceInterfaceDetailData parameter Instead, the code reserves a generic buffer, passes a pointer to the buffer, and extracts the device path name directly from the buffer The code thus doesn’t require a structure declaration, but I’ve included one to show the contents of the returned buffer
8$ Definitions
Public Structure SP_DEVICE_INTERFACE_DETAIL_DATA
Dim cbSize As Int32
Dim DevicePath As String
End Structure
<DllImport("setupapi.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Shared Function SetupDiGetDeviceInterfaceDetail _
(ByVal DeviceInfoSet As IntPtr, _
ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA, _
ByVal DeviceInterfaceDetailData As IntPtr, _
ByVal DeviceInterfaceDetailDataSize As Int32, _
ByRef RequiredSize As Int32, _
ByVal DeviceInfoData As IntPtr) _
As Boolean
End Function
Trang 4Dim bufferSize As Int32
Dim detailDataBuffer As IntPtr
Dim success As Boolean
success = SetupDiGetDeviceInterfaceDetail _
(deviceInfoSet, _
MyDeviceInterfaceData, _
IntPtr.Zero, _
0, _
bufferSize, _
IntPtr.Zero)
detailDataBuffer = Marshal.AllocHGlobal(bufferSize)
Marshal.WriteInt32 _
(detailDataBuffer,
ConvertToInt32(IIf((IntPtr.Size = 4), 4 + Marshal.SystemDefaultCharSize, 8))) success = SetupDiGetDeviceInterfaceDetail _
(deviceInfoSet, _
MyDeviceInterfaceData, _
detailDataBuffer, _
bufferSize, _
bufferSize, _
IntPtr.Zero)
8% Definitions
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
internal Int32 cbSize;
internal String DevicePath;
}
[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern Boolean SetupDiGetDeviceInterfaceDetail
(IntPtr DeviceInfoSet,
ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
IntPtr DeviceInterfaceDetailData,
Int32 DeviceInterfaceDetailDataSize,
ref Int32 RequiredSize,
Trang 5Int32 bufferSize = 0;
IntPtr detailDataBuffer;
Boolean success = false;
success = SetupDiGetDeviceInterfaceDetail
(deviceInfoSet,
ref MyDeviceInterfaceData,
IntPtr.Zero,
0,
ref bufferSize,
IntPtr.Zero);
detailDataBuffer = Marshal.AllocHGlobal( bufferSize );
Marshal.WriteInt32
(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); success = SetupDiGetDeviceInterfaceDetail
(deviceInfoSet,
ref MyDeviceInterfaceData,
detailDataBuffer,
bufferSize,
ref bufferSize,
IntPtr.Zero);
&GVCKNU
After calling SetupDiGetDeviceInterfaceDetail, bufferSize contains the value to pass in the DeviceInterfaceDetailDataSize parameter in the next call But before calling the function again, the code needs to take care of a few things
The second function call returns a pointer (detailDataBuffer) to an SP_DEVICE_INTERFACE_DETAIL_DATA structure in unmanaged mem-ory The Marshal.AllocGlobal method uses the returned bufferSize value to allocate memory for the structure
The cbSize member of the structure passed in detailDataBuffer equals four bytes for cbSize plus the width of one character for the device path name (which is empty when passed to the function) The Marshal.WriteInt32 method copies the cbSize value into the first member of detailDataBuffer The IIf function (Visual Basic) or “?” conditional operator (Visual C#) selects the correct value for 32- and 64-bit systems
Trang 6The second call to SetupDiGetDeviceInterfaceDetail passes the pointer to detailDataBuffer and sets the deviceInterfaceDetailDataSize parameter equal to the bufferSize value returned previously in RequiredSize
When the function returns after the second call, detailDataBuffer points to a structure containing a device path name
'ZVTCEVKPIVJG&GXKEG2CVJ0COG
In detailDataBuffer, the first four bytes are the cbSize member The string con-taining the device path name begins at the fifth byte
8$ Dim devicePathName As String = ""
Dim pDevicePathName As IntPtr = New IntPtr(detailDataBuffer.ToInt32 + 4)
devicePathName = Marshal.PtrToStringAuto(pDevicePathName)
Marshal.FreeHGlobal(detailDataBuffer)
8% String devicePathName = "";
IntPtr pDevicePathName = new IntPtr( detailDataBuffer.ToInt32() + 4 );
devicePathName = Marshal.PtrToStringAuto(pDevicePathName);
Marshal.FreeHGlobal(detailDataBuffer);
&GVCKNU
The pDevicePathName variable points to the string in the buffer The Mar-shal.PtrToString method retrieves the string from the buffer When finished with the buffer, Marshal.FreeHGlobal frees the memory previously allocated for the buffer
%NQUKPI%QOOWPKECVKQPU
When finished using the DeviceInfoSet returned by SetupDiGetClassDevs, the application should call SetupDiDestroyDeviceInfoList to free resources
8$ Definitions
<DllImport("setupapi.dll", SetLastError:=True)> _
Shared Function SetupDiDestroyDeviceInfoList _
(ByVal DeviceInfoSet As IntPtr) _
Trang 7SetupDiDestroyDeviceInfoList (deviceInfoSet)
8% Definitions
[DllImport("setupapi.dll", SetLastError = true)]
internal static extern Int32 SetupDiDestroyDeviceInfoList
(IntPtr DeviceInfoSet);
Use
SetupDiDestroyDeviceInfoList( deviceInfoSet );
1DVCKPKPIC*CPFNG
An application can use a retrieved device path name to obtain a handle that enables communicating with the device Table 10-2 shows API functions related to requesting a handle
4GSWGUVKPIC%QOOWPKECVKQPU*CPFNG
After retrieving a device path name, an application is ready to open communi-cations with the device The CreateFile function requests a handle to an object, which can be a file or another resource managed by a driver that supports han-dle-based operations For example, applications can request a handle to use in exchanging reports with HID-class devices For devices that use the WinUSB driver, CreateFile obtains a handle the application uses to obtain a WinUSB device handle for accessing a device
The call to CreateFile can pass a SECURITY_ATTRIBUTES structure that can limit access to the handle or IntPtr.Zero if the function doesn’t need to limit access
Table 10-2: Applications can use CreateFile to request a handle to a device and CloseHandle to free the resources used by a handle.
#2+(WPEVKQP & 2WTRQUG
CloseHandle kernel32 Free resources reserved by CreateFile To close handles
for the SafeHandle and derived classes, use the Close method, which calls CloseHandle internally.
CreateFile kernel32 Retrieve a handle for communicating with a device.
Trang 88$ Definitions
Friend Const FILE_ATTRIBUTE_NORMAL As Int32 = &H80
Friend Const FILE_FLAG_OVERLAPPED As Int32 = &H40000000
Friend Const FILE_SHARE_READ As Int32 = 1
Friend Const FILE_SHARE_WRITE As Int32 = 2
Friend Const GENERIC_READ As UInt32 = &H80000000UL
Friend Const GENERIC_WRITE As UInt32 = &H40000000
Friend Const OPEN_EXISTING As Int32 = 3
<DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Shared Function CreateFile _
(ByVal lpFileName As String, _
ByVal dwDesiredAccess As UInt32, _
ByVal dwShareMode As Int32, _
ByVal lpSecurityAttributes As IntPtr, _
ByVal dwCreationDisposition As Int32, _
ByVal dwFlagsAndAttributes As Int32, _
ByVal hTemplateFile As Int32) _
As SafeFileHandle
End Function
Use
Dim deviceHandle As SafeFileHandle
deviceHandle = CreateFile _
(devicePathName, _
GENERIC_WRITE Or GENERIC_READ, _
FILE_SHARE_READ Or FILE_SHARE_WRITE, _
IntPtr.Zero, _
OPEN_EXISTING, _
FILE_ATTRIBUTE_NORMAL Or FILE_FLAG_OVERLAPPED, _
0)
8% Definitions
internal const Int32 FILE_ATTRIBUTE_NORMAL = 0X80;
internal const Int32 FILE_FLAG_OVERLAPPED = 0X40000000;
internal const Int32 FILE_SHARE_READ = 1;
internal const Int32 FILE_SHARE_WRITE = 2;
internal const UInt32 GENERIC_READ = 0X80000000;
internal const UInt32 GENERIC_WRITE = 0X40000000;
internal const Int32 OPEN_EXISTING = 3;
Trang 9[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern SafeFileHandle CreateFile
(String lpFileName,
UInt32 dwDesiredAccess,
Int32 dwShareMode,
IntPtr lpSecurityAttributes,
Int32 dwCreationDisposition,
Int32 dwFlagsAndAttributes,
Int32 hTemplateFile);
Use
internal SafeFileHandle deviceHandle;
deviceHandle = CreateFile
(devicePathName,
(GENERIC_WRITE | GENERIC_READ),
FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
0);
&GVCKNU
The function passes a pointer to the devicePathName string returned by Setup-DiGetDeviceInterfaceDetail The dwDesiredAccess parameter requests read/write access to the device The dwShareMode parameter allows other pro-cesses to access the device while the handle is open The lpSecurityAttributes parameter is a null pointer (or a pointer to a SECURITY_ATTRIBUTES structure) The dwCreationDisposition parameter must be OPEN_EXISTING for devices For use with the WinUSB driver, the dwFlagsAndAttributes
param-e t param-e r m u s t u s param-e F I L E _ F L A G _ O V E R L A P P E D T h param-e FILE_ATTRIBUTE_NORMAL attribute indicates that no other attributes such as hidden, read-only, or encrypted are set The example passes zero for the unused hTemplate parameter The function returns a SafeFileHandle object
%NQUKPIVJG*CPFNG
When finished communicating with a device, the application should free the resources reserved by CreateFile
8$ deviceHandle.Close()
Trang 108% deviceHandle.Close();
&GVCKNU
SafeFileHandle objects support the Close method, which marks the handle for releasing and freeing resources The method calls the CloseHandle API func-tion internally
&GVGEVKPI#VVCEJOGPVCPF4GOQXCN
Many applications find it useful to know when a device has been attached or removed On detecting when a device is attached, the application can begin communicating with the device On detecting when a device has been removed, the application can stop attempting to communicate until detecting reattach-ment Windows provides device-notification functions for this purpose
#DQWV&GXKEG0QVKHKECVKQPU
To request to be informed when a device is attached or removed, an applica-tion’s form can register to receive notification messages for devices in a device interface class The operating system passes WM_DEVICECHANGE mes-sages to the form’s WndProc method (called WindowProc in C) An application can override WndProc in a form’s base class with a method that processes the messages and then passes them to the base class’s WndProc method (The code below shows how to do this.) Each notification contains a device path name that the application can use to identify the device that the notification applies
to Table 10-3 lists the API functions used in registering for device notifications The example that follows shows how to use the functions
4GIKUVGTKPIHQT&GXKEG0QVKHKECVKQPU
Applications use the RegisterDeviceNotification function to request to receive notification messages The function requires a handle for the window or service
t h a t w i l l r e c e i v e t h e n o t i f i c a t i o n s , a p o i n t e r t o a DEV_BROADCAST_DEVICEINTERFACE structure that holds information about the request, and flags to indicate whether the handle is for a window or service
In the DEV_BROADCAST_DEVICEINTERFACE structure passed to
Regis-t e r D e v i c e No Regis-t i f i c a Regis-t i o n , Regis-t h e d b c c _ d e v i c e Regis-t y p e m e m b e r i s s e Regis-t Regis-t o