badcel / hidapi.net Goto Github PK
View Code? Open in Web Editor NEWA modern cross platform C# binding for HIDAPI
Home Page: https://badcel.github.io/HidApi.Net/
License: MIT License
A modern cross platform C# binding for HIDAPI
Home Page: https://badcel.github.io/HidApi.Net/
License: MIT License
Make library native aot friendly (starting with dotnet 8?).
Dotnet8: Do not reference SourceLink as it is included and enabled by default in the sdk: https://github.com/dotnet/sourcelink/releases/tag/8.0.0
while (controller.isConnected)
{
try
{
var data = controller.HidDevice.Read(32);
Thread.Sleep(1);
}
catch (HidException)
{
controller.isConnected = false;
}
}
after long time running, Internal CLR error. occurred.
Fatal error. Internal CLR error. (0x80131506)
at HidApi.Device.Read(Int32)
at ControllerSDK.hardware.HidManager._readDataFromDevice(System.Object)
at System.Threading.Thread.StartCallback()
.net version: 8.0.101 and 6.0.321 BOTH Tried
Enable higher AnalysisMode To detect more problems in the code.
Update to support HidApi 0.14.0: https://github.com/libusb/hidapi/releases/tag/hidapi-0.14.0
Fedora package is on its way: https://bodhi.fedoraproject.org/updates/FEDORA-2023-b7f5ad25f5
I had that my application crashed during transfers with the exception mentioned in the issue #84. The strange thing was that the crash did not always happen at the same time.
I did a lot of changes to my code that calls the hidapi library to eliminate various possible issues. Also I modified my code that read and write calls are only made from the same thread.
After a while I came to the conclusion, that the error occurs when the runtime dicovers issue with memory corruption. This happens independently to the currently running code.
After digging into the issue by using the code directly from the repository I've found out that the issue was caused by reading the manufacturer, serial number and product identifier when I opened the device. If I removed the reading of these three strings the applicaton worked stable. So I had a close look at these read methods.
The definiton in the hidapi library for these string reading functions look like this:
int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen);
The maxlen parameter description is: The length of the buffer in multiples of wchar_t.
In the library currently a buffer gets allocated by the WCharTString class. The buffer is actually correctly doubled the size of the provided maxmal string length to be able to contain wide chars. The problem is that the value passed to the maxlen parameter is the length of the buffer and not the number of wchars the buffer was created for. This causes that the library asumes that the buffer is larger than it is and probably writes to memory behind the allocated space.
The solution is to add a parameter "maxLength" to the methods like "GetManufacturerString" in the NativeMethods.cs file. This parameter can than be passed to the invoked call instead of the invalid "buffer.Length" (see below). In the Device.cs the number of allowed characters "maxLength" need then to be passed to the changed methods.
Old:
`
public static int GetManufacturerString(DeviceSafeHandle device, ReadOnlySpan buffer)
{
return GetManufacturerString(device, ref MemoryMarshal.GetReference(buffer), (nuint) buffer.Length);
}
public static int GetProductString(DeviceSafeHandle device, ReadOnlySpan<byte> buffer)
{
return GetProductString(device, ref MemoryMarshal.GetReference(buffer), (nuint) buffer.Length);
}
public static int GetSerialNumberString(DeviceSafeHandle device, ReadOnlySpan<byte> buffer)
{
return GetSerialNumberString(device, ref MemoryMarshal.GetReference(buffer), (nuint) buffer.Length);
}
public static int GetIndexedString(DeviceSafeHandle device, int index, ReadOnlySpan<byte> buffer)
{
return GetIndexedString(device, index, ref MemoryMarshal.GetReference(buffer), (nuint) buffer.Length);
}
`
New:
`
public static int GetManufacturerString(DeviceSafeHandle device, ReadOnlySpan buffer, int maxLength)
{
return GetManufacturerString(device, ref MemoryMarshal.GetReference(buffer), (nuint) maxLength);
}
public static int GetProductString(DeviceSafeHandle device, ReadOnlySpan<byte> buffer, int maxLength)
{
return GetProductString(device, ref MemoryMarshal.GetReference(buffer), (nuint) maxLength);
}
public static int GetSerialNumberString(DeviceSafeHandle device, ReadOnlySpan<byte> buffer, int maxLength)
{
return GetSerialNumberString(device, ref MemoryMarshal.GetReference(buffer), (nuint) maxLength);
}
public static int GetIndexedString(DeviceSafeHandle device, int index, ReadOnlySpan<byte> buffer, int maxLength)
{
return GetIndexedString(device, index, ref MemoryMarshal.GetReference(buffer), (nuint) maxLength);
}
`
The string that is returned by this methods (after fixing the issue) contains a lot of '\0' characters (probably the hidapi sets the full memory area to '\0'). Maybe it would be nice if these '\0' are removed with something like .Trim('\0') before the string is returned.
As workaround I found ot that I could read the string s from the DeviceInfo by the method "GetDeviceInfo". That worked without issues.
Use library import attribute instead of DllImport
.
Supports custom string marshaling.
what to do?
It would be good to provide a generic example like the hidapi project hidtest utility. You can ignore the test device portion (0x04d8:0x003f).
https://github.com/libusb/hidapi/blob/master/hidtest/test.c
Currently several UTF32 strings are read from the hid api. To do so the length of the string must be calculated which is done manually in UTF32 class.
Verify if there is a method inside dotnet which can do this automatically. For comparison there is MemoryMarshal.CreateReadOnlySpanFromNullTerminated for UTF8 available.
The same is needed for Unicode (16 bit wide encodings).
Do not put all possible HidApi binary names into a list of available binaries in "NativeMethods.cs" but initialize the list depending on the current platform.
Currently during runtime the operating system is checked for several string operations to decide how to decode a pointer of w_char_t
data as the size of w_char_t
is different between Linux / Mac and Windows.
It is possible to include runtime assemblies in nuget which are separted by runtime and only used during runtime. If the build process would generate a private DLL containing the code for a specific platform to read w_char_t
data the operating system check would not need to happen during runtime but while loading the nuget the correct assembly with the correct code would be loaded and no check would need to happen.
See:
Provide support for a NET Standard 2.0
Allow co to set version suffix to automatically create preview packages.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.