Skip to content

Commit ab2c31d

Browse files
committed
Rework overlapped I/O to use newer APIs and allocate fewer events
1 parent f44b5a4 commit ab2c31d

File tree

1 file changed

+40
-30
lines changed

1 file changed

+40
-30
lines changed

WinUHid/WinUHid.cpp

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -56,22 +56,32 @@ size_t MultiSzWcsLen(PCWSTR MultiSzString)
5656
return len;
5757
}
5858

59-
BOOL DeviceIoControlInSync(HANDLE Handle, DWORD Ioctl, LPCVOID InBuffer, DWORD InBufferSize)
59+
BOOL DeviceIoControlInSync(HANDLE Handle, HANDLE OverlappedEvent, DWORD Ioctl, LPCVOID InBuffer, DWORD InBufferSize)
6060
{
6161
OVERLAPPED overlapped = {};
62+
Wrappers::Event privateEvent;
6263
DWORD bytesRead;
6364
BOOL ret;
6465

65-
Wrappers::Event overlappedEvent{ CreateEventW(NULL, FALSE, FALSE, NULL) };
66-
if (!overlappedEvent.IsValid()) {
67-
return FALSE;
66+
//
67+
// Use the caller's event if provided, otherwise create one for this operation
68+
//
69+
if (OverlappedEvent) {
70+
ResetEvent(OverlappedEvent);
71+
overlapped.hEvent = OverlappedEvent;
6872
}
73+
else {
74+
privateEvent.Attach(CreateEventW(NULL, TRUE, FALSE, NULL));
75+
if (!privateEvent.IsValid()) {
76+
return FALSE;
77+
}
6978

70-
overlapped.hEvent = overlappedEvent.Get();
79+
overlapped.hEvent = privateEvent.Get();
80+
}
7181

7282
ret = DeviceIoControl(Handle, Ioctl, const_cast<LPVOID>(InBuffer), InBufferSize, NULL, 0, &bytesRead, &overlapped);
7383
if (!ret && GetLastError() == ERROR_IO_PENDING) {
74-
ret = GetOverlappedResult(Handle, &overlapped, &bytesRead, TRUE);
84+
ret = GetOverlappedResultEx(Handle, &overlapped, &bytesRead, INFINITE, FALSE);
7585
}
7686

7787
return ret;
@@ -115,6 +125,11 @@ WINUHID_API PWINUHID_DEVICE WinUHidCreateDevice(PCWINUHID_DEVICE_CONFIG Config)
115125
return NULL;
116126
}
117127

128+
Wrappers::Event overlappedEvent{ CreateEventW(NULL, TRUE, FALSE, NULL) };
129+
if (!overlappedEvent.IsValid()) {
130+
return NULL;
131+
}
132+
118133
device = (PWINUHID_DEVICE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*device));
119134
if (!device) {
120135
SetLastError(ERROR_OUTOFMEMORY);
@@ -145,22 +160,22 @@ WINUHID_API PWINUHID_DEVICE WinUHidCreateDevice(PCWINUHID_DEVICE_CONFIG Config)
145160
devInfo.ProductID = Config->ProductID;
146161
devInfo.VersionNumber = Config->VersionNumber;
147162
devInfo.ContainerId = Config->ContainerId;
148-
if (!DeviceIoControlInSync(device->Handle, IOCTL_WINUHID_SET_DEVICE_INFO, &devInfo, sizeof(devInfo))) {
163+
if (!DeviceIoControlInSync(device->Handle, overlappedEvent.Get(), IOCTL_WINUHID_SET_DEVICE_INFO, &devInfo, sizeof(devInfo))) {
149164
goto Fail;
150165
}
151166

152167
//
153168
// Set the required report descriptor
154169
//
155-
if (!DeviceIoControlInSync(device->Handle, IOCTL_WINUHID_SET_REPORT_DESCRIPTOR, Config->ReportDescriptor, Config->ReportDescriptorLength)) {
170+
if (!DeviceIoControlInSync(device->Handle, overlappedEvent.Get(), IOCTL_WINUHID_SET_REPORT_DESCRIPTOR, Config->ReportDescriptor, Config->ReportDescriptorLength)) {
156171
goto Fail;
157172
}
158173

159174
//
160175
// Set the instance ID if one was provided
161176
//
162177
if (Config->InstanceID != NULL) {
163-
if (!DeviceIoControlInSync(device->Handle, IOCTL_WINUHID_SET_INSTANCE_ID, (LPVOID)Config->InstanceID, (DWORD)(wcslen(Config->InstanceID) + 1) * sizeof(WCHAR))) {
178+
if (!DeviceIoControlInSync(device->Handle, overlappedEvent.Get(), IOCTL_WINUHID_SET_INSTANCE_ID, (LPVOID)Config->InstanceID, (DWORD)(wcslen(Config->InstanceID) + 1) * sizeof(WCHAR))) {
164179
goto Fail;
165180
}
166181
}
@@ -169,15 +184,15 @@ WINUHID_API PWINUHID_DEVICE WinUHidCreateDevice(PCWINUHID_DEVICE_CONFIG Config)
169184
// Set additional hardware IDs if provided
170185
//
171186
if (Config->HardwareIDs != NULL) {
172-
if (!DeviceIoControlInSync(device->Handle, IOCTL_WINUHID_SET_HARDWARE_IDS, (LPVOID)Config->HardwareIDs, (DWORD)(MultiSzWcsLen(Config->HardwareIDs) + 1) * sizeof(WCHAR))) {
187+
if (!DeviceIoControlInSync(device->Handle, overlappedEvent.Get(), IOCTL_WINUHID_SET_HARDWARE_IDS, (LPVOID)Config->HardwareIDs, (DWORD)(MultiSzWcsLen(Config->HardwareIDs) + 1) * sizeof(WCHAR))) {
173188
goto Fail;
174189
}
175190
}
176191

177192
//
178193
// Finally, create the device
179194
//
180-
if (!DeviceIoControlInSync(device->Handle, IOCTL_WINUHID_CREATE_DEVICE, NULL, 0)) {
195+
if (!DeviceIoControlInSync(device->Handle, overlappedEvent.Get(), IOCTL_WINUHID_CREATE_DEVICE, NULL, 0)) {
181196
goto Fail;
182197
}
183198

@@ -199,7 +214,7 @@ WINUHID_API BOOL WinUHidSubmitInputReport(PWINUHID_DEVICE Device, LPCVOID Report
199214
return FALSE;
200215
}
201216

202-
Wrappers::Event overlappedEvent{ CreateEventW(NULL, FALSE, FALSE, NULL) };
217+
Wrappers::Event overlappedEvent{ CreateEventW(NULL, TRUE, FALSE, NULL) };
203218
if (!overlappedEvent.IsValid()) {
204219
return FALSE;
205220
}
@@ -208,7 +223,7 @@ WINUHID_API BOOL WinUHidSubmitInputReport(PWINUHID_DEVICE Device, LPCVOID Report
208223

209224
ret = WriteFile(Device->Handle, Report, ReportSize, &bytesWritten, &overlapped);
210225
if (!ret && GetLastError() == ERROR_IO_PENDING) {
211-
ret = GetOverlappedResult(Device->Handle, &overlapped, &bytesWritten, TRUE);
226+
ret = GetOverlappedResultEx(Device->Handle, &overlapped, &bytesWritten, INFINITE, FALSE);
212227
}
213228

214229
return ret;
@@ -260,7 +275,7 @@ WINUHID_API BOOL WinUHidStartDevice(PWINUHID_DEVICE Device, PWINUHID_EVENT_CALLB
260275
}
261276
}
262277

263-
if (!DeviceIoControlInSync(Device->Handle, IOCTL_WINUHID_START_DEVICE, NULL, 0)) {
278+
if (!DeviceIoControlInSync(Device->Handle, NULL, IOCTL_WINUHID_START_DEVICE, NULL, 0)) {
264279
//
265280
// Unwinding the event thread creation is relatively simple. We are not yet
266281
// in the Started state and we hold the device lock exclusively, so the
@@ -290,21 +305,18 @@ WINUHID_API BOOL WinUHidStartDevice(PWINUHID_DEVICE Device, PWINUHID_EVENT_CALLB
290305
WINUHID_API PCWINUHID_EVENT WinUHidPollEvent(PWINUHID_DEVICE Device, DWORD TimeoutMillis)
291306
{
292307
PWINUHID_EVENT event;
293-
OVERLAPPED overlapped = {};
294308
DWORD bufferSize;
295309

296310
if (Device == NULL) {
297311
SetLastError(ERROR_INVALID_PARAMETER);
298312
return NULL;
299313
}
300314

301-
Wrappers::Event overlappedEvent{ CreateEventW(NULL, FALSE, FALSE, NULL) };
315+
Wrappers::Event overlappedEvent{ CreateEventW(NULL, TRUE, FALSE, NULL) };
302316
if (!overlappedEvent.IsValid()) {
303317
return NULL;
304318
}
305319

306-
overlapped.hEvent = overlappedEvent.Get();
307-
308320
//
309321
// Acquire the device lock in shared mode to protect the state and event buffer size hints
310322
//
@@ -320,6 +332,7 @@ WINUHID_API PCWINUHID_EVENT WinUHidPollEvent(PWINUHID_DEVICE Device, DWORD Timeo
320332
BOOL ret;
321333
DWORD bytesWritten;
322334
PWINUHID_EVENT newEvent;
335+
OVERLAPPED overlapped;
323336

324337
//
325338
// If the device has been stopped, abort now
@@ -333,14 +346,18 @@ WINUHID_API PCWINUHID_EVENT WinUHidPollEvent(PWINUHID_DEVICE Device, DWORD Timeo
333346
//
334347
// Issue the asynchronous IOCTL
335348
//
349+
RtlZeroMemory(&overlapped, sizeof(overlapped));
350+
overlapped.hEvent = overlappedEvent.Get();
351+
ResetEvent(overlapped.hEvent);
336352
ret = DeviceIoControl(Device->Handle, IOCTL_WINUHID_GET_NEXT_EVENT, NULL, 0, event, bufferSize, &bytesWritten, &overlapped);
337353
ReleaseSRWLockShared(&Device->Lock);
338354

339355
if (!ret && GetLastError() == ERROR_IO_PENDING) {
340356
//
341357
// Wait for the IOCTL to complete or the timeout to expire
342358
//
343-
if (WaitForSingleObject(overlapped.hEvent, TimeoutMillis) != WAIT_OBJECT_0) {
359+
ret = GetOverlappedResultEx(Device->Handle, &overlapped, &bytesWritten, TimeoutMillis, FALSE);
360+
if (!ret && GetLastError() == WAIT_TIMEOUT) {
344361
//
345362
// If the timeout expired, we need to cancel the pending I/O and wait for completion.
346363
//
@@ -354,19 +371,12 @@ WINUHID_API PCWINUHID_EVENT WinUHidPollEvent(PWINUHID_DEVICE Device, DWORD Timeo
354371
// processing the request as if it didn't time out.
355372
//
356373
CancelIoEx(Device->Handle, &overlapped);
357-
WaitForSingleObject(overlapped.hEvent, INFINITE);
358-
ret = GetOverlappedResult(Device->Handle, &overlapped, &bytesWritten, FALSE);
374+
ret = GetOverlappedResultEx(Device->Handle, &overlapped, &bytesWritten, INFINITE, FALSE);
359375
if (!ret) {
360376
SetLastError(ERROR_TIMEOUT);
361377
goto Fail;
362378
}
363379
}
364-
else {
365-
//
366-
// Get the results of the asynchronous operation
367-
//
368-
ret = GetOverlappedResult(Device->Handle, &overlapped, &bytesWritten, FALSE);
369-
}
370380
}
371381

372382
if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
@@ -425,7 +435,7 @@ WINUHID_API PCWINUHID_EVENT WinUHidPollEvent(PWINUHID_DEVICE Device, DWORD Timeo
425435
readComplete.RequestId = event->RequestId;
426436
readComplete.Status = STATUS_NO_MEMORY;
427437
readComplete.DataLength = 0;
428-
DeviceIoControlInSync(Device->Handle, IOCTL_WINUHID_COMPLETE_READ_EVENT, &readComplete, sizeof(readComplete));
438+
DeviceIoControlInSync(Device->Handle, overlappedEvent.Get(), IOCTL_WINUHID_COMPLETE_READ_EVENT, &readComplete, sizeof(readComplete));
429439

430440
SetLastError(ERROR_OUTOFMEMORY);
431441
goto Fail;
@@ -450,7 +460,7 @@ WINUHID_API VOID WinUHidCompleteWriteEvent(PWINUHID_DEVICE Device, PCWINUHID_EVE
450460

451461
eventComplete.RequestId = Event->RequestId;
452462
eventComplete.Status = Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
453-
DeviceIoControlInSync(Device->Handle, IOCTL_WINUHID_COMPLETE_WRITE_EVENT, &eventComplete, sizeof(eventComplete));
463+
DeviceIoControlInSync(Device->Handle, NULL, IOCTL_WINUHID_COMPLETE_WRITE_EVENT, &eventComplete, sizeof(eventComplete));
454464

455465
HeapFree(GetProcessHeap(), 0, const_cast<PWINUHID_EVENT>(Event));
456466
}
@@ -487,7 +497,7 @@ WINUHID_API VOID WinUHidCompleteReadEvent(PWINUHID_DEVICE Device, PCWINUHID_EVEN
487497
eventComplete->DataLength = 0;
488498
}
489499

490-
DeviceIoControlInSync(Device->Handle, IOCTL_WINUHID_COMPLETE_READ_EVENT, eventComplete, FIELD_OFFSET(WINUHID_READ_EVENT_COMPLETE, Data) + eventComplete->DataLength);
500+
DeviceIoControlInSync(Device->Handle, NULL, IOCTL_WINUHID_COMPLETE_READ_EVENT, eventComplete, FIELD_OFFSET(WINUHID_READ_EVENT_COMPLETE, Data) + eventComplete->DataLength);
491501

492502
HeapFree(GetProcessHeap(), 0, const_cast<PWINUHID_EVENT>(Event));
493503
}

0 commit comments

Comments
 (0)