Dropping the probe I built there for reference, if anyone's curious about how I've made sure I'm not breaking things :grinning: ``` /* deck_writefile_probe.c * Build (MinGW): x86_64-w64-mingw32-gcc deck_writefile_probe.c -o deck_writefile_probe.exe -lhid -lsetupapi * Run on the Windows partition with the Elgato Stream Deck software CLOSED. * Decides 1024 (option A, Wine padding is the bug) vs 1023 (option B, stall has another cause). */ #include <windows.h> #include <setupapi.h> #include <hidsdi.h> #include <stdio.h> #define DECK_VID 0x0FD9 #define DECK_PID 0x0063 /* Stream Deck Mini */ int main(void) { GUID hidGuid; HidD_GetHidGuid(&hidGuid); HDEVINFO devInfo = SetupDiGetClassDevsW(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (devInfo == INVALID_HANDLE_VALUE) { printf("SetupDiGetClassDevs failed\n"); return 1; } SP_DEVICE_INTERFACE_DATA ifData = { .cbSize = sizeof(ifData) }; HANDLE deck = INVALID_HANDLE_VALUE; USHORT outLen = 0; for (DWORD i = 0; SetupDiEnumDeviceInterfaces(devInfo, NULL, &hidGuid, i, &ifData); i++) { DWORD need = 0; SetupDiGetDeviceInterfaceDetailW(devInfo, &ifData, NULL, 0, &need, NULL); SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = malloc(need); if (!detail) continue; detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); if (!SetupDiGetDeviceInterfaceDetailW(devInfo, &ifData, detail, need, NULL, NULL)) { free(detail); continue; } HANDLE h = CreateFileW(detail->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); free(detail); if (h == INVALID_HANDLE_VALUE) continue; HIDD_ATTRIBUTES attrs = { .Size = sizeof(attrs) }; if (HidD_GetAttributes(h, &attrs) && attrs.VendorID == DECK_VID && attrs.ProductID == DECK_PID) { PHIDP_PREPARSED_DATA pp = NULL; if (HidD_GetPreparsedData(h, &pp)) { HIDP_CAPS caps; if (HidP_GetCaps(pp, &caps) == HIDP_STATUS_SUCCESS) outLen = caps.OutputReportByteLength; HidD_FreePreparsedData(pp); } deck = h; break; } CloseHandle(h); } SetupDiDestroyDeviceInfoList(devInfo); if (deck == INVALID_HANDLE_VALUE) { printf("Stream Deck Mini (VID %04X PID %04X) not found\n", DECK_VID, DECK_PID); return 1; } printf("OutputReportByteLength = %u\n", outLen); if (outLen == 0) outLen = 1024; /* Build a numbered output report: byte[0] = report id 0x02, rest benign. */ BYTE *buf = calloc(1, outLen); if (!buf) { CloseHandle(deck); return 1; } buf[0] = 0x02; /* numbered report id */ /* byte[1]=command, byte[2]=page index (0), byte[5]=key index - shape per Mini HID; * exact image payload is irrelevant: we only read back the WriteFile count. */ DWORD written = 0; SetLastError(0); BOOL ok = WriteFile(deck, buf, outLen, &written, NULL); DWORD err = GetLastError(); printf("WriteFile ok=%d written=%lu lastError=%lu\n", ok, written, err); if (ok && written == outLen) printf("VERDICT: RETURNED %u (== OutputReportByteLength) -> option (A): Wine padding=1 is the bug, drop-padding is correct.\n", (unsigned)outLen); else if (ok && written == (DWORD)(outLen - 1)) printf("VERDICT: RETURNED %u (== OutputReportByteLength-1) -> option (B): Deck stall is NOT the return count; reinvestigate.\n", (unsigned)(outLen - 1)); else printf("VERDICT: inconclusive (ok=%d written=%lu err=%lu) - ensure Stream Deck software is closed.\n", ok, written, err); free(buf); CloseHandle(deck); return 0; } ``` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11204#note_143683