-1

I am attempting to communicate with a generic HID device (not mouse or keyboard). Following Microsoft's documentation and some example code that I found, I have gotten to the point where I believe that I can begin communicating with the device. Unfortunately, writing to it does not work.

The following code gets to the point where things fail. Some cleanup code is missing or incomplete, but the code should be functional with the correct VID and PID. Note that the hardcoded 1 in the call to SetupDiEnumDeviceInterfaces is the index that my device is at on my computer.

#include <Windows.h>
#include <hidsdi.h>
#include <SetupAPI.h>
#include <cstdlib>
#include <cstdint>
std::uint16_t constexpr vid = /* My VID */;
std::uint16_t constexpr pid = /* My PID */;

int main(int argc, char* argv[])
{
    GUID hidGuid;
    HidD_GetHidGuid(&hidGuid);
    HDEVINFO info = SetupDiGetClassDevsA(&hidGuid, nullptr, nullptr,
        DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if (info == INVALID_HANDLE_VALUE)
        return 1;
    SP_DEVICE_INTERFACE_DATA data;
    data.cbSize = sizeof(data);
    if (!SetupDiEnumDeviceInterfaces(info, nullptr, &hidGuid, 1, &data))
        return 1;
    DWORD requiredSize;
    if (SetupDiGetDeviceInterfaceDetailA(info, &data, nullptr, 0,
        &requiredSize, nullptr) || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
        return 1;
    SP_DEVICE_INTERFACE_DETAIL_DATA_A* detailData =
        static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A*>(
            std::malloc(requiredSize));
    detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
    if (!SetupDiGetDeviceInterfaceDetailA(info, &data, detailData,
        requiredSize, nullptr, nullptr))
        return 1;
    SetupDiDestroyDeviceInfoList(info);
    HANDLE capsHandle = CreateFileA(detailData->DevicePath, 0,
        FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
        OPEN_EXISTING, 0, nullptr);
    if (capsHandle == INVALID_HANDLE_VALUE)
        return 1;
    HIDD_ATTRIBUTES attr;
    attr.Size = sizeof(attr);
    if (!HidD_GetAttributes(capsHandle, &attr))
        return 1;
    if (attr.VendorID != vid || attr.ProductID != pid)
        return 1;
    PHIDP_PREPARSED_DATA preparsedData;
    if (!HidD_GetPreparsedData(capsHandle, &preparsedData))
        return 1;
    CloseHandle(capsHandle);
    HIDP_CAPS caps;
    if (HidP_GetCaps(preparsedData, &caps) != HIDP_STATUS_SUCCESS)
        return 1;
    HidD_FreePreparsedData(preparsedData);
    std::uint8_t* inputBuffer =
        static_cast<std::uint8_t*>(std::malloc(caps.InputReportByteLength));
    std::uint8_t* outputBuffer =
        static_cast<std::uint8_t*>(std::malloc(caps.OutputReportByteLength));
    HANDLE hidHandle = CreateFileA(detailData->DevicePath,
        GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
        nullptr, OPEN_EXISTING, 0, nullptr);
    if (hidHandle == INVALID_HANDLE_VALUE)
        return 1;
    ZeroMemory(outputBuffer, caps.OutputReportByteLength);
    outputBuffer[0] = 11;
    outputBuffer[1] = 12;
    DWORD bytesWritten;
    if (!WriteFile(hidHandle, outputBuffer, caps.OutputReportByteLength,
        &bytesWritten, nullptr))
    {
        auto x = GetLastError();
        return 1;
    }
    return 0;
}

This runs as expected until the call to WriteFile. At that point if fails and x is assigned the value 87 (ERROR_INVALID_PARAMETER). Why would this be failing? All of the parameters seem correct to me.

Graznarak
  • 3,626
  • 4
  • 28
  • 47

1 Answers1

0

After communicating with the people who produce our device, I have found that the problem is that the output buffer is filled in wrong. The two bytes that are non-zero should be the bytes at indices 1 and 2, not the bytes at indices 0 and 1.

Graznarak
  • 3,626
  • 4
  • 28
  • 47