Чтение из скрытого устройства чтения в работнике BackgroundService, .net 8C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Чтение из скрытого устройства чтения в работнике BackgroundService, .net 8

Сообщение Anonymous »

Я пытаюсь прочитать данные из HID Reader с определенным идентификатором поставщика и идентификатором продукта в фоновой службе .net C#. Я смог успешно зарегистрировать устройство, но не смог прочитать считывающее устройство при считывании карты. Похоже, что ProcessRawInput никогда не вызывается.
Читатель эмулирует клавиатуру. Так что я могу провести карту и прочитать номер карты в блокноте. Итак, ридер и карта работают. Вот мой код.

Код: Выделить всё

namespace HIDReaderService
{
public class Worker : BackgroundService
{
private readonly ILogger _logger;
private IntPtr _messageOnlyWindowHandle = IntPtr.Zero;
private const ushort VENDOR_ID = 0xFFFF; //input vendor id of attached keyboard/reader
private const ushort PRODUCT_ID = 0xFF; //input product id of attached keyboard/reader

private delegate IntPtr WindowProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
private WindowProcDelegate _windowProcDelegate;

public Worker(ILogger logger)
{
_logger = logger;
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Starting HID reader service...");

_windowProcDelegate = new WindowProcDelegate(WindowProc);
_messageOnlyWindowHandle = CreateMessageOnlyWindow();
if (_messageOnlyWindowHandle == IntPtr.Zero)
{
_logger.LogError("Failed to create message-only window.");
return;
}
else
{
_logger.LogInformation("Message-only window created successfully.");
}

// Register the HID devices
if (!RegisterHIDDevice(_messageOnlyWindowHandle))
{
_logger.LogError("Failed to register HID device.");
return;
}

_logger.LogInformation("Listening for HID device input...");

var messageLoopThread = new Thread(MessageLoop);
messageLoopThread.Start();

while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(100);
}
}
// Define a delegate matching the signature of the window procedure
private delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

// Update CreateMessageOnlyWindow method
private IntPtr CreateMessageOnlyWindow()
{
// Create a delegate instance for the Window Procedure
WndProcDelegate wndProcDelegate = new WndProcDelegate(WindowProc);

// Define and register the window class
var wndClass = new WNDCLASS
{
// Convert delegate to function pointer
lpfnWndProc = Marshal.GetFunctionPointerForDelegate(wndProcDelegate),
hInstance = Marshal.GetHINSTANCE(typeof(Program).Module),
lpszClassName = "MessageOnlyWindow"
};

ushort classAtom = RegisterClass(ref wndClass);
if (classAtom == 0)
{
int error = Marshal.GetLastWin32Error();
_logger.LogError($"Failed to register window class. Error: {error}");
return IntPtr.Zero;
}

// Create the message-only window
IntPtr hWnd = CreateWindowEx(0, "MessageOnlyWindow", "Message Only Window",
0, 0, 0, 0, 0, HWND_MESSAGE, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

if (hWnd == IntPtr.Zero)
{
int error = Marshal.GetLastWin32Error();
_logger.LogError($"Failed to create message-only window.  Error: {error}");
return IntPtr.Zero;
}

_logger.LogInformation("Message-only window created successfully.");
RegisterHIDDevice(hWnd);
return hWnd;
}

// Window Procedure method
private IntPtr WindowProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
// Log every message that arrives in WindowProc to confirm message reception
_logger.LogInformation($"WindowProc received message: {msg}");

// Check if we received the expected WM_INPUT message
if (msg == WM_INPUT)
{
_logger.LogInformation("WM_INPUT message received.");
ProcessRawInput(lParam);
}

return DefWindowProc(hWnd, msg, wParam, lParam);
}

private bool RegisterHIDDevice(IntPtr hWnd)
{
var rid = new RAWINPUTDEVICE[1];

rid[0].UsagePage = 0x01;  // Generic Desktop Controls
rid[0].Usage = 0x06;      // Keyboard
rid[0].Flags = RIDEV_INPUTSINK;
rid[0].Target = hWnd;

bool result = RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(typeof(RAWINPUTDEVICE)));
if (!result)
{
int errorCode = Marshal.GetLastWin32Error();
_logger.LogError($"RegisterRawInputDevices failed.  Error Code: {errorCode}");
}
else
{
_logger.LogInformation("HID device registered successfully.");
}

return result;
}

private void MessageLoop()
{
MSG msg;
while (GetMessage(out msg, IntPtr.Zero, 0, 0))
{
_logger.LogInformation($"Received message: {msg.message}");
TranslateMessage(ref msg);
DispatchMessage(ref msg);
}
}

private void ProcessRawInput(IntPtr lParam)
{
uint dwSize = 0;
GetRawInputData(lParam, RID_INPUT, IntPtr.Zero, ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER)));
IntPtr buffer = Marshal.AllocHGlobal((int)dwSize);

try
{
if (GetRawInputData(lParam, RID_INPUT, buffer, ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER))) == dwSize)
{
var raw = (RAWINPUT)Marshal.PtrToStructure(buffer, typeof(RAWINPUT));
if (raw.header.dwType == RIM_TYPEKEYBOARD)
{
_logger.LogInformation($"RawInput Keyboard Event: VKey={raw.keyboard.VKey}, Message={raw.keyboard.Message}");
if (raw.keyboard.Message == WM_KEYDOWN && raw.keyboard.VKey == VK_RETURN)
{
_logger.LogInformation("Enter key pressed!");
// Handle enter key, e.g., launch a browser
Process.Start("notepad");
}
}
}
} finally
{
Marshal.FreeHGlobal(buffer);
}
}

private void GetDeviceInfo(IntPtr hDevice, out ushort vendorId, out ushort productId)
{
uint size = 0;
GetRawInputDeviceInfo(hDevice, RIDI_DEVICENAME, IntPtr.Zero, ref size);
if (size == 0)
{
vendorId = productId = 0;
return;
}

var nameBuffer = Marshal.AllocHGlobal((int)size);
try
{
if (GetRawInputDeviceInfo(hDevice, RIDI_DEVICENAME, nameBuffer, ref size) >  0)
{
var deviceName = Marshal.PtrToStringAnsi(nameBuffer);
if (deviceName != null)
{
_logger.LogInformation($"Device name:  {deviceName}");

var vidIndex = deviceName.IndexOf("VID_") + 4;
var pidIndex = deviceName.IndexOf("PID_") + 4;

vendorId = Convert.ToUInt16(deviceName.Substring(vidIndex, 4), 16);
productId = Convert.ToUInt16(deviceName.Substring(pidIndex, 4), 16);
return;
}
}
} finally
{
Marshal.FreeHGlobal(nameBuffer);
}

vendorId = productId = 0;
}

private const int WM_KEYDOWN = 0x100;
private const int WM_INPUT = 0x00FF;
private const uint RID_INPUT = 0x10000003;
private const uint RIM_TYPEKEYBOARD = 1;
private const uint VK_RETURN = 0x0D;
private const int RIDEV_INPUTSINK = 0x00000100;
private const uint RIDI_DEVICENAME = 0x20000007;
private static readonly IntPtr HWND_MESSAGE = new IntPtr(-3);

[DllImport("user32.dll")]
private static extern bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevices, uint uiNumDevices, uint cbSize);

[DllImport("user32.dll")]
private static extern uint GetRawInputData(IntPtr hRawInput, uint uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader);

[DllImport("user32.dll")]
private static extern uint GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize);

[DllImport("user32.dll")]
private static extern IntPtr CreateWindowEx(int exStyle, string lpClassName, string lpWindowName, int dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam);

[DllImport("user32.dll", SetLastError = true)]
private static extern ushort RegisterClass(ref WNDCLASS lpWndClass);

[DllImport("user32.dll")]
private static extern bool GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);

[DllImport("user32.dll")]
private static extern bool TranslateMessage(ref MSG lpMsg);

[DllImport("user32.dll")]
private static extern IntPtr DispatchMessage(ref MSG lpMsg);

[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, IntPtr wParam,  IntPtr lParam);

[StructLayout(LayoutKind.Sequential)]
private struct WNDCLASS
{
public int style;
public IntPtr lpfnWndProc;
public int cbClsExtra;
public int cbWndExtra;
public IntPtr hInstance;
public IntPtr hIcon;
public IntPtr hCursor;
public IntPtr hbrBackground;
public string lpszMenuName;
public string lpszClassName;
}

[StructLayout(LayoutKind.Sequential)]
private struct MSG
{
public IntPtr hWnd;
public uint message;
public IntPtr wParam;
public IntPtr lParam;
public uint time;
public POINT pt;
}

[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}

[StructLayout(LayoutKind.Sequential)]
private struct RAWINPUTHEADER
{
public uint dwType;
public uint dwSize;
public IntPtr hDevice;
public IntPtr wParam;
}

[StructLayout(LayoutKind.Explicit)]
private struct RAWINPUT
{
[FieldOffset(0)]
public RAWINPUTHEADER header;
[FieldOffset(16)]
public RAWKEYBOARD keyboard;
}

[StructLayout(LayoutKind.Sequential)]
private struct RAWKEYBOARD
{
public ushort MakeCode;
public ushort Flags;
public ushort Reserved;
public ushort VKey;
public uint Message;
public uint ExtraInformation;
}

[StructLayout(LayoutKind.Sequential)]
public struct RAWINPUTDEVICE
{
public ushort UsagePage;
public ushort Usage;
public int Flags;
public IntPtr Target;
}
}
}
В целях тестирования можно использовать идентификатор продукта любого производителя подключенной клавиатуры.

Подробнее здесь: https://stackoverflow.com/questions/791 ... rker-net-8
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Чтение из скрытого устройства чтения в работнике BackgroundService, .NET 8
    Anonymous » » в форуме C#
    0 Ответы
    13 Просмотры
    Последнее сообщение Anonymous
  • Чтение из скрытого устройства чтения в работнике BackgroundService, .NET 8
    Anonymous » » в форуме C#
    0 Ответы
    15 Просмотры
    Последнее сообщение Anonymous
  • Как очистить/очистить объект AsyncLocal в BackgroundService(Microsoft.Hosting.Extensions.BackgroundService)?
    Anonymous » » в форуме C#
    0 Ответы
    81 Просмотры
    Последнее сообщение Anonymous
  • Celery возвращает неверную информацию о текущих задачах в одном работнике
    Anonymous » » в форуме Python
    0 Ответы
    12 Просмотры
    Последнее сообщение Anonymous
  • Http http timeout только в работнике
    Anonymous » » в форуме Android
    0 Ответы
    36 Просмотры
    Последнее сообщение Anonymous

Вернуться в «C#»