Visual Studio 2013 — реализовать небольшую C DLL для взаимодействия между нашим кодом C ++ и RawInput

Прочитав эту статью переполнения стека,
SlimDX: Joystick.Poll () завершается успешно на отключенном геймпаде

мы решили полностью отказаться от Windows 7 DirectInput и перейти на Windows 7 RawInput. Нам нужно реализовать небольшую C DLL для взаимодействия между моим C ++ кодом и RawInput.

My sample C++ source code is,
// Adapters.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"#include "Adapters.h"
extern "C" {
#include "hidsdi.h"}

#define MAX_GAMEPADS 32

static TCHAR *deviceNames[MAX_GAMEPADS];
static HANDLE deviceHandles[MAX_GAMEPADS];
static UINT devicesActive;#define CHECK(exp)      { if(!(exp)) goto Error; }
#define SAFE_FREE(p)    { if(p) { HeapFree(hHeap, 0, p); (p) = NULL; } }

static BOOL ReadDeviceName(int index, HANDLE handle)
{
UINT size = 0;
UINT result = GetRawInputDeviceInfo(handle,
RIDI_DEVICENAME, NULL, &size);
if (result != 0) {
result = GetLastError();
return false;
}

deviceNames[index] = (TCHAR *)HeapAlloc(GetProcessHeap(), 0, size * sizeof(TCHAR));
result = GetRawInputDeviceInfo(handle,
RIDI_DEVICENAME, deviceNames[index], &size);
if (result < 0) {
result = GetLastError();
HeapFree(GetProcessHeap(), 0, deviceNames[index]);
deviceHandles[index] = NULL;
deviceNames[index] = NULL;
return false;
}

deviceHandles[index] = handle;
return TRUE;
}static BOOL ReadDeviceInfo(int index, HANDLE handle)
{
// May be a gamepad
RID_DEVICE_INFO *info;

UINT size = 0; // sizeof(RID_DEVICE_INFO);
UINT result = GetRawInputDeviceInfo(handle, RIDI_DEVICEINFO,
NULL, &size);

info = (RID_DEVICE_INFO *) HeapAlloc(GetProcessHeap(), 0, size);

result = GetRawInputDeviceInfo(handle, RIDI_DEVICEINFO,
info, &size);

if (result != (UINT)-1) {
if (info->hid.usUsagePage == 1 &&
(info->hid.usUsage == 4 || info->hid.usUsage == 5))  {
// It is a gamepad!!!

HeapFree(GetProcessHeap(), 0, info);
return ReadDeviceName(index, handle);;
}
} else {
result = (UINT) GetLastError();
}
HeapFree(GetProcessHeap(), 0, info);
return FALSE;
}

static int FindIndex(HANDLE handle)
{
for(int i = 0; i < MAX_GAMEPADS; i++)
if (deviceHandles[i] == handle)
return i;

return -1;
}

ADAPTERS_API int InitialiseGamepads(HWND handle)
{
RAWINPUTDEVICE devices[2];

devices[0].usUsagePage = 1;
devices[0].usUsage = 4; // Joystick
devices[0].dwFlags = 0 ;
devices[0].hwndTarget = handle;
devices[1].usUsagePage = 1;
devices[1].usUsage = 5;
devices[1].dwFlags = 0 ;
devices[1].hwndTarget = handle;

bool result = RegisterRawInputDevices(devices, 2, sizeof(RAWINPUTDEVICE));
if (! result) {
DWORD error = GetLastError();
return 0;
}

UINT numdevices;
GetRawInputDeviceList(NULL, &numdevices, sizeof(RAWINPUTDEVICELIST));
RAWINPUTDEVICELIST *list = (RAWINPUTDEVICELIST *) HeapAlloc(GetProcessHeap(), 0,
numdevices * sizeof(RAWINPUTDEVICELIST));
GetRawInputDeviceList(list, &numdevices, sizeof(RAWINPUTDEVICELIST));

for(UINT i = 0; i < numdevices; i++) {
if (list[i].dwType == RIM_TYPEHID) {
if (ReadDeviceInfo(devicesActive, list[i].hDevice))
devicesActive++;
}

}

return devicesActive;
}

ADAPTERS_API TCHAR *GetDevicePath(int index)
{
if (index < 0 || index >= MAX_GAMEPADS)
return NULL;

return deviceNames[index];
}ADAPTERS_API int PollDeviceChange()
{
// Read device list
UINT numdevices;
GetRawInputDeviceList(NULL, &numdevices, sizeof(RAWINPUTDEVICELIST));
RAWINPUTDEVICELIST *list = (RAWINPUTDEVICELIST *) HeapAlloc(GetProcessHeap(), 0,
numdevices * sizeof(RAWINPUTDEVICELIST));
GetRawInputDeviceList(list, &numdevices, sizeof(RAWINPUTDEVICELIST));

BOOL found[MAX_GAMEPADS];
for(int i = 0; i < MAX_GAMEPADS; i++)
found[i] = FALSE;

for(UINT i = 0; i < numdevices; i++) {
if (list[i].dwType == RIM_TYPEHID) {
int index = FindIndex(list[i].hDevice);

if (index >= 0)
found[index] = true;
else {
// Find empty slot. Only process one change at a time, to simplify
// interface to managed code
for(int j = 0; j < MAX_GAMEPADS; j++)
if (! deviceNames[j]) {
if (ReadDeviceInfo(j, list[i].hDevice))
return j;
}
}
}
}

for(int i = 0; i < MAX_GAMEPADS; i++) {
if (deviceNames[i] && ! found[i]) {
// Missing device
deviceHandles[i] = NULL;
HeapFree(GetProcessHeap(), 0, deviceNames[i]);
deviceNames[i] = NULL;
return i;
}
}

return -1;
}

static void ParseRawInput(PRAWINPUT pRawInput,
unsigned char *buttons, int *x, int *y)
{
PHIDP_PREPARSED_DATA pPreparsedData;
HIDP_CAPS            Caps;
PHIDP_BUTTON_CAPS    pButtonCaps;
PHIDP_VALUE_CAPS     pValueCaps;
USHORT               capsLength;
UINT                 bufferSize;
HANDLE               hHeap;
ULONG                i, usageLength, value;

pPreparsedData = NULL;
pButtonCaps    = NULL;
pValueCaps     = NULL;
PUSAGE usages = NULL;
hHeap          = GetProcessHeap();

//
// Get the preparsed data block
//

CHECK( GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, NULL, &bufferSize) == 0 );
CHECK( pPreparsedData = (PHIDP_PREPARSED_DATA)HeapAlloc(hHeap, 0, bufferSize) );
CHECK( (int)GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, pPreparsedData, &bufferSize) >= 0 );

//
// Get the joystick's capabilities
//

// Button caps
CHECK( HidP_GetCaps(pPreparsedData, &Caps) == HIDP_STATUS_SUCCESS )
CHECK( pButtonCaps = (PHIDP_BUTTON_CAPS)HeapAlloc(hHeap, 0, sizeof(HIDP_BUTTON_CAPS) * Caps.NumberInputButtonCaps) );

capsLength = Caps.NumberInputButtonCaps;
CHECK( HidP_GetButtonCaps(HidP_Input, pButtonCaps, &capsLength, pPreparsedData) == HIDP_STATUS_SUCCESS )
int g_NumberOfButtons = pButtonCaps->Range.UsageMax - pButtonCaps->Range.UsageMin + 1;

// Value caps
CHECK( pValueCaps = (PHIDP_VALUE_CAPS)HeapAlloc(hHeap, 0, sizeof(HIDP_VALUE_CAPS) * Caps.NumberInputValueCaps) );
capsLength = Caps.NumberInputValueCaps;
CHECK( HidP_GetValueCaps(HidP_Input, pValueCaps, &capsLength, pPreparsedData) == HIDP_STATUS_SUCCESS )

//
// Get the pressed buttons - only length required to tell if any are pressed
//

usageLength = HidP_MaxUsageListLength(HidP_Input, pButtonCaps->UsagePage, pPreparsedData);
usages = (PUSAGE)HeapAlloc(hHeap, 0, usageLength * sizeof(USAGE));
CHECK(
HidP_GetUsages(
HidP_Input, pButtonCaps->UsagePage, 0, usages, &usageLength, pPreparsedData,
(PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid
) == HIDP_STATUS_SUCCESS );

*buttons = (usageLength > 0);

//
// Get the state of discrete-valued-controls
//

for(i = 0; i < Caps.NumberInputValueCaps; i++)
{
CHECK(
HidP_GetUsageValue(
HidP_Input, pValueCaps[i].UsagePage, 0, pValueCaps[i].Range.UsageMin, &value, pPreparsedData,
(PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid
) == HIDP_STATUS_SUCCESS );

switch(pValueCaps[i].Range.UsageMin)
{
case 0x30:  // X-axis
*x = (LONG)value - 128;
break;

case 0x31:  // Y-axis
*y = (LONG)value - 128;
break;

}
}

//
// Clean up
//

Error:
SAFE_FREE(pPreparsedData);
SAFE_FREE(pButtonCaps);
SAFE_FREE(pValueCaps);
SAFE_FREE(usages);
}

ADAPTERS_API int ProcessInput(HANDLE wParam, HANDLE lParam, unsigned char *buttons, int *x, int *y)
{
UINT      bufferSize;

GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &bufferSize, sizeof(RAWINPUTHEADER));

PRAWINPUT pRawInput = (PRAWINPUT)HeapAlloc(GetProcessHeap(), 0, bufferSize);
if(!pRawInput)
return -1;

GetRawInputData((HRAWINPUT)lParam, RID_INPUT, pRawInput, &bufferSize, sizeof(RAWINPUTHEADER));
int index = FindIndex(pRawInput->header.hDevice);

if (index < 0) {
for(int j = 0; j < MAX_GAMEPADS; j++)
if (! deviceNames[j]) {
if (ReadDeviceName(j, pRawInput->header.hDevice)) {
index = j;
break;
}
}
}

ParseRawInput(pRawInput, buttons, x, y);

HeapFree(GetProcessHeap(), 0, pRawInput);return index;
}

После безуспешной компиляции приведенного выше примера кода C ++ и попытки связать его в проекте Microsoft Visual Studio 2013 DLL я получил несколько ошибок компоновщика, которые относятся к функциям библиотеки hdi C. Это очень озадачивает, пытаясь выяснить причину, когда я с трудом помню, как добавил hdi.lib и его путь к зависимостям компоновщика проекта Microsoft Visual Studio 2013 DLL. Может ли проблема быть напрямую связана с нашей внешней связью с «hdisdi.h» в файле adapter.cpp? Также, пожалуйста, укажите точные включаемые файлы и правильные библиотеки компоновщика, которые нам нужны для создания проекта Microsoft Visual Studio 2013 DLL под названием Adapter?

0

Решение

В WDK 7, также известном как Windows 7 Raw Input HID API, заголовки, поставляемые с WDK, не совместимы с заголовками, которые поставляются с Visual Studio.

USB HID API для Windows

Привет,

В прошлом году я немного поработал с USB HID-устройствами, и меня немного расстроила сложность связи с ними с помощью Windows HID API (hid.dll). Лучше всего я могу определить, что заголовки и библиотеки импорта для hid.dll не существуют в Platform SDK, а существуют только в Windows Driver Kit (WDK). Раньше можно было загрузить WDK и добавить в Visual Studio его include \ и lib \ paths, а также иметь возможность #include и связываться с hid.lib, и все это будет работать нормально. Однако, похоже, ситуация изменилась с выходом WDK 7.0.0.0. В WDK 7 заголовки, поставляемые с WDK, не совместимы с заголовками, которые поставляются с Visual Studio.

Тогда кажется, что остается выбор: либо попросите проект Visual Studio игнорировать стандартные пути включения и использовать вместо этого пути WDK, либо создайте DLL-оболочку, используя WDK, и свяжите ее с этим в приложении (созданном с использованием Visual Studio и Платформа SDK). Я сделал последнее и создал HIDAPI (hidapi.dll). HIDAPI — это оболочка для системных вызовов hidsdi.h, созданная с использованием WDK. Любой исполняемый файл Windows может ссылаться на hidapi.dll, не беспокоясь о платформе SDK. Он обеспечивает чистый интерфейс, подходящий для того, что нужно делать разработчикам приложений для связи с USB HID-устройствами.

Я сделал это в прошлом году, но, наконец, нашел способ разместить его на GitHub и закончить простую веб-страницу, которую я только что выложил для нее сегодня.

Чтобы было ясно, это разработано, чтобы использоваться из приложений C и C ++, работающих на Windows. Я хотел бы реализовать это также в Linux, предоставляя переносимый интерфейс для устройств HID.

Веб-сайт для проекта расположен по адресу:
http://www.signal11.us/oss/hidapi/

Пожалуйста, проверьте это и дайте мне знать, если это полезно для вас.

Алан.


Я боролся с этим весь день сегодня. Тем не менее, есть возможное решение этого:

HIDAPI можно скачать с GitHub. Zip-файл доступен на странице загрузки. Чтобы получить последнюю версию транка (если у вас установлен git, выполните следующее:
git clone git: //github.com/signal11/hidapi.git
Инструкции по сборке

Окна:
Создайте файл .sln в каталоге windows / с помощью Visual Studio.

Linux:
Перейдите в каталог linux / и запустите make.

Mac OS X:
Перейдите в каталог mac / и запустите make.

Чтобы построить тестовый графический интерфейс:
В Windows создайте файл .sln в каталоге hidtest /. Обязательно сначала настройте внешние компоненты (Fox Toolkit), как описано в README.txt.
В Linux и Mac запустите make из каталога hidtest /. Обязательно сначала установите fox-toolkit, как описано в README.txt

0

Другие решения

Доброе утро, мой ответ на этот вопрос переполнения стека — прочитать и применить следующие URL-адреса:

https://forum.pjrc.com/threads/24049-windows-dll-for-rawhid

Проблема с заголовками WDK (Windows Driver Kit) и VC ++

https://social.msdn.microsoft.com/Forums/vstudio/en-US/522a7180-c6aa-439f-963f-0ed10d49a239/how-do-i-use-wdk-with-visual-studio-2008?forum= vcgeneral

Спасибо и счастливых праздников.

-1

По вопросам рекламы [email protected]