Closed emako closed 7 months ago
Will you share your code? I have run this under 32 and 64-bit, with Unicode character sets without problem.
uint nDev = 0;
Assert.That(GetRawInputDeviceList(null, ref nDev, (uint)Marshal.SizeOf(typeof(RAWINPUTDEVICELIST))), ResultIs.Not.Value(uint.MaxValue));
Assert.That(nDev, Is.GreaterThan(0));
RAWINPUTDEVICELIST[] devs = new RAWINPUTDEVICELIST[(int)nDev];
Assert.That(nDev = GetRawInputDeviceList(devs, ref nDev, (uint)Marshal.SizeOf(typeof(RAWINPUTDEVICELIST))), ResultIs.Not.Value(uint.MaxValue));
Assert.That(nDev, Is.GreaterThan(0));
for (int i = 0; i < nDev; i++)
{
uint sz = 0;
Assert.That(GetRawInputDeviceInfo(devs[i].hDevice, RIDI.RIDI_DEVICENAME, default, ref sz), ResultIs.Value(0));
SafeLPTSTR data = new((int)sz + 1);
Assert.That(GetRawInputDeviceInfo(devs[i].hDevice, RIDI.RIDI_DEVICENAME, data, ref sz), Is.GreaterThan(0));
TestContext.WriteLine($"{data}");
}
Sample codes here:
.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Vanara.PInvoke.Kernel32" Version="3.4.17" />
<PackageReference Include="Vanara.PInvoke.User32" Version="3.4.17" />
</ItemGroup>
</Project>
Program.cs
using System.Runtime.InteropServices;
using Vanara.PInvoke;
namespace ConsoleUser32;
internal class Program
{
static void Main()
{
EnumerateDevices();
}
internal static void EnumerateDevices()
{
uint deviceCount = 0;
int dwSize = Marshal.SizeOf(typeof(RawInputDeviceList));
if (User32.GetRawInputDeviceList(null, ref deviceCount, (uint)dwSize) == 0)
{
User32.RAWINPUTDEVICELIST[] pRawInputDeviceList = new User32.RAWINPUTDEVICELIST[deviceCount];
User32.GetRawInputDeviceList(pRawInputDeviceList, ref deviceCount, (uint)dwSize);
for (int i = 0; i < deviceCount; i++)
{
uint pcbSize = 0;
User32.RAWINPUTDEVICELIST rid = pRawInputDeviceList[i];
User32.GetRawInputDeviceInfo(rid.hDevice, (uint)RawInputDeviceInfo.RIDI_DEVICENAME, IntPtr.Zero, ref pcbSize);
if (pcbSize <= 0) continue;
// --------------------------------------
// All right
//nint pDataX = Marshal.AllocHGlobal((int)pcbSize);
//User32X.GetRawInputDeviceInfo((nint)rid.hDevice, RawInputDeviceInfo.RIDI_DEVICENAME, pDataX, ref pcbSize);
//string? deviceNameX = Marshal.PtrToStringAnsi(pDataX);
//Console.WriteLine(deviceNameX);
//Marshal.FreeHGlobal(pDataX);
// --------------------------------------
// --------------------------------------
// Application crash
nint pData = Marshal.AllocHGlobal((int)pcbSize);
User32.GetRawInputDeviceInfo(rid.hDevice, (uint)RawInputDeviceInfo.RIDI_DEVICENAME, pData, ref pcbSize);
string? deviceName = Marshal.PtrToStringAuto(pData);
Console.WriteLine(deviceName);
Marshal.FreeHGlobal(pData);
// --------------------------------------
}
}
}
}
file static class User32X
{
[DllImport("User32.dll", SetLastError = true)]
public static extern uint GetRawInputDeviceInfo(nint hDevice, RawInputDeviceInfo command, nint pData, ref uint size);
}
[StructLayout(LayoutKind.Sequential)]
file struct RawInputDeviceList
{
public nint Device;
public uint Type;
}
file enum RawInputDeviceInfo : uint
{
RIDI_DEVICENAME = 0x20000007,
RIDI_DEVICEINFO = 0x2000000b,
PREPARSEDDATA = 0x20000005
}
You have a small bug in the code due to an odd use by the API of a variable. The docs say:
For this (RIDI_DEVICENAME) uiCommand only, the value in pcbSize is the character count (not the byte count).
When calling Marshal.AllocHGlobal
with the resulting value from the first call, you need to adjust for character size. This could be done by multiplying pData
by Marshal.SystemDefaultCharSize
or by using the SafeLPTSTR
class in my sample code above. The DllImport
statement then still accounts for the API having both an Ansi and a Unicode implementation.
I ajust to nint pData = Marshal.AllocHGlobal((int)pcbSize * Marshal.SystemDefaultCharSize);
and it works.
Thank you
Error Code:
And then Marshal.PtrToStringAuto will get the error device name or some time will make application crash when in Chinese OS.
Like this issuse https://github.com/dahall/Vanara/issues/428
I use following code to fix it.
correct code: