1use std::{mem, ptr};
2use std::os::windows::io as win_io;
3use winapi::um::handleapi::*;
4use winapi::um::setupapi::*;
5use winapi::um::fileapi::*;
6use winapi::um::winnt::*;
7use winapi::um::winbase::*;
8use winapi::um::errhandlingapi::*;
9use winapi::shared::ntdef::HANDLE;
10use crate::*;
11
12#[derive(Debug)]
14pub struct Client {
15 pub(crate) device: HANDLE,
16}
17
18impl Client {
19 pub fn connect() -> Result<Client, Error> {
21 unsafe {
22 let mut error = Error::BusNotFound;
23
24 let mut member_index = 0;
25 let mut device_interface_data: SP_DEVICE_INTERFACE_DATA = mem::zeroed();
26 device_interface_data.cbSize = mem::size_of_val(&device_interface_data) as u32;
27
28 let mut detail_data_buffer = mem::MaybeUninit::<[u32; 0x300]>::uninit();
29
30 let device_info_set = SetupDiGetClassDevsW(
31 &bus::GUID_DEVINTERFACE,
32 ptr::null(),
33 ptr::null_mut(),
34 DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
35
36 if device_info_set == INVALID_HANDLE_VALUE {
37 return Err(Error::WinError(GetLastError()));
38 }
39
40 while SetupDiEnumDeviceInterfaces(
42 device_info_set,
43 ptr::null_mut(),
44 &bus::GUID_DEVINTERFACE,
45 member_index,
46 &mut device_interface_data) != 0
47 {
48 member_index += 1;
49
50 let detail_data_ptr = detail_data_buffer.as_mut_ptr() as PSP_DEVICE_INTERFACE_DETAIL_DATA_W;
53 *ptr::addr_of_mut!((*detail_data_ptr).cbSize) = mem::size_of::<SP_DEVICE_INTERFACE_DETAIL_DATA_W>() as u32;
54
55 let mut required_size = 0;
57 if SetupDiGetDeviceInterfaceDetailW(
58 device_info_set,
59 &mut device_interface_data,
60 detail_data_ptr,
61 mem::size_of_val(&detail_data_buffer) as u32,
62 &mut required_size,
63 ptr::null_mut()) == 0
64 {
65 error = Error::WinError(GetLastError());
66 continue;
67 }
68
69 let device_path = ptr::addr_of!((*detail_data_ptr).DevicePath) as *const u16;
71 let device = CreateFileW(
72 device_path,
73 GENERIC_READ | GENERIC_WRITE,
74 FILE_SHARE_READ | FILE_SHARE_WRITE,
75 ptr::null_mut(),
76 OPEN_EXISTING,
77 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED,
78 ptr::null_mut());
79
80 if device == INVALID_HANDLE_VALUE {
81 error = Error::BusAccessFailed(GetLastError());
82 continue;
83 }
84
85 let mut check_version = bus::CheckVersion::common();
86 if check_version.ioctl(device) {
87 SetupDiDestroyDeviceInfoList(device_info_set);
88 return Ok(Client { device })
89 }
90
91 CloseHandle(device);
93 error = Error::BusVersionMismatch;
94 }
95
96 SetupDiDestroyDeviceInfoList(device_info_set);
97 Err(error)
98 }
99 }
100
101 #[inline]
103 pub fn try_clone(&self) -> Result<Client, Error> {
104 unsafe {
105 let process_handle = (!0) as *mut _;
106 let mut target_handle = mem::MaybeUninit::uninit();
107 let success = DuplicateHandle(
108 process_handle, self.device,
109 process_handle, target_handle.as_mut_ptr(),
110 GENERIC_READ | GENERIC_WRITE, 0, DUPLICATE_SAME_ACCESS);
111 if success == 0 {
112 let err = GetLastError();
113 return Err(Error::WinError(err));
114 }
115 Ok(Client { device: target_handle.assume_init() })
116 }
117 }
118}
119
120unsafe impl Sync for Client {}
121unsafe impl Send for Client {}
122
123impl win_io::AsRawHandle for Client {
124 #[inline]
125 fn as_raw_handle(&self) -> HANDLE {
126 self.device
127 }
128}
129impl win_io::IntoRawHandle for Client {
130 #[inline]
131 fn into_raw_handle(self) -> HANDLE {
132 self.device
133 }
134}
135impl win_io::FromRawHandle for Client {
136 #[inline]
137 unsafe fn from_raw_handle(device: HANDLE) -> Client {
138 Client { device }
139 }
140}
141
142impl Drop for Client {
143 #[inline]
144 fn drop(&mut self) {
145 unsafe {
146 CloseHandle(self.device);
147 }
148 }
149}