Hi to all. I'm trying to use hidapi.dll,if needed i'll post a sources or link to authors page.
Here's what i've have in my dll:

      #define HID_API_EXPORT __declspec(dllexport)
      #define HID_API_CALL

...

int  HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length);
...

and this is the part in c#:

[DllImport("hidapi.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
    public static extern unsafe int hid_write(IntPtr device, StringBuilder data, uint length);
[DllImport("hidapi.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
    public static extern unsafe int hid_get_serial_number_string(IntPtr dev, StringBuilder stringt, uint maxlen);           
    ...

Byte[] buf = new Byte[256];
buf[0] = 0x3F;
buf[1] = 7;
buf[2] = Convert.ToByte('L');
buf[3] = Convert.ToByte('E');
buf[4] = Convert.ToByte('D');
buf[5] = Convert.ToByte(' ');
buf[6] = Convert.ToByte('O');
buf[7] = Convert.ToByte('N');
buf[8] = Convert.ToByte('!');
...
// this is the first attempt to send data,with changes in dllimport function to accept pointer,not working
IntPtr ptrHandle = Marshal.AllocHGlobal(Marshal.SizeOf(handle));
IntPtr intPtr = Marshal.AllocHGlobal(9);
Marshal.Copy(buf, 0, intPtr, 9);

StringBuilder ms = new StringBuilder(255);
// this returns serial as expected, pointer to handler is ok
hid_get_serial_number_string(ptrHandle, ms, 255);

// this is the second attempt to send data using stringbuilder, with changes in dllimport, not working
// and third attempt to send data using string instead of stringbuilder, not working.
string send_string = System.Text.Encoding.UTF8.GetString(buf, 0, 9);
StringBuilder outBuf = new StringBuilder(send_string.Length);
outBuf.Append(send_string);
//this returns -1, error on writeFile as i understand
res = hid_write(ptrHandle, outBuf/*intPtr*/ /*send_string*/, 9);

Marshal.FreeHGlobal(intPtr);

as i mentioned in code, it seems i can correctly connect to the device, get the serial, but i can't
write to it. there is no problems on the device side, because a've tested hidapi from primitive cpp app and works great with sending very same buf (0x3F,7,LED ON!), so the problems is in c# marshalling related code i assume. sorry for the messy code, but it's better to post all variants i've tryed. what am i doing wrong and what is the correct code to pass string to const char*? on the other side is MSP430 MCU configured as usb datapipe.

Recommended Answers

All 5 Replies

have you tried adding the .dll as an a reference add a using statment add the namespace to your app? That way intellisense can tell you where your synatax is wrong.

a can't add dll as reference, visual studio complaining about non-COM object. the only way to add dll is through the dllimport. i've tryed this library in java app using jni and then wrote a gui on cpp cli and lib works perfectly everywhere,but c#. i've checked the values passed to dll, length of the byte array is ok, values in byte array is ok too, handle is non null and holds right values. so all arguments are right, but WriteFile inside hid_write returns false. getlasterror... returns nothing.

hid_write(hid_device *device, const unsigned char *data, size_t length);
the 2nd parameter is an unsigned char pointer, ie pointer to a byte array.
Have you tried using a byte array to send you data rather than a string?

i thought if i nedd pointer i must pass pointer, or string, that will be automaticly transformed to pointer by framework, as i understand... i've try pass byte array directly with no luck, hid_write returned error and app hangs.

This is all work in progress, code crashes sometimes but it is good starting point:

HIDAPI.cs

using System;
using System.Text;
using System.Runtime.InteropServices;

/*
 * HIDAPI documentatioin
 * http://www.signal11.us/oss/hidapi/hidapi/doxygen/html/group__API.html
 * 
 * https://github.com/rfb/HIDMacros
 *  
 * USB Made Simple
 * http://www.usbmadesimple.co.uk/ums_5.htm
 * 
 * http://www.circuitsathome.com/communicating-arduino-with-hid-devices-part-1
 * http://www.instructables.com/id/USB-Wii-Classic-Controller/step5/USB-HID-Reports-and-Report-Descriptors/
 * 
 * Platform Invoke Tutorial
 * http://msdn.microsoft.com/en-us/library/aa288468%28v=vs.71%29.aspx#pinvoke_defaultmarshaling
 * 
 * Calling Win32 DLLs in C# with P/Invoke
 * http://msdn.microsoft.com/en-us/magazine/cc164123.aspx
 */
namespace hidapi
{
    /*
    struct hid_device_info
    {
        // Platform-specific device path
        char *path;
        // Device Vendor ID
        unsigned short vendor_id;
        // Device Product ID
        unsigned short product_id;
        // Serial Number
        wchar_t *serial_number;
        // Manufacturer String
        wchar_t *manufacturer_string;
        // Product string
        wchar_t *product_string;

        // Pointer to the next device
        struct hid_device_info *next;
    };

     */
    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
    public class hidDeviceInfo 
    { 
        public String path;
        public UInt16 vendorId;
        public UInt16 productId;
        public String serialNumber; 
        public String manufacturerString;
        public String productString;
        [MarshalAs(UnmanagedType.LPStruct)]
        public hidDeviceInfo next; 
    }

    sealed public class HIDAPI
    {
        private HIDAPI ()
        {
        }
        /*
         * Platform Invoke Data Types
         * http://msdn.microsoft.com/en-us/library/ac7ay120.aspx
         * 
         * Marshaling Classes, Structures, and Unions
         * http://msdn.microsoft.com/en-us/library/eshywdt7.aspx
         * 
         * Marshalling IntPtr
         * http://stackoverflow.com/questions/17549123/c-sharp-performance-using-unsafe-pointers-instead-of-intptr-and-marshal
         */

        [DllImport("libhidapi-0.dll", EntryPoint="hid_init")] public static extern
            int hidInit(); // done
        [DllImport("libhidapi-0.dll", EntryPoint="hid_exit")] public static extern
            int hidExit(); // done
        [DllImport("libhidapi-0.dll", EntryPoint="hid_enumerate")] [return: MarshalAs(UnmanagedType.LPStruct)] public static extern
            hidDeviceInfo hidEnumerate(UInt16 vendorId, UInt16 productId); // done
        [DllImport("libhidapi-0.dll", EntryPoint="hid_free_enumeration")] public static extern
            void hidFreeEnumeration([In, MarshalAs(UnmanagedType.LPStruct)] hidDeviceInfo devs); // done
        [DllImport("libhidapi-0.dll", EntryPoint="hid_open", CharSet=CharSet.Auto)] public static extern
            IntPtr hidOpen(UInt16 vendorId, UInt16 productId, String serialNumber); // done
        [DllImport("libhidapi-0.dll", EntryPoint="hid_open_path", CharSet=CharSet.Auto)] public static extern
            IntPtr hidOpenPath(string path); // const char *
        [DllImport("libhidapi-0.dll", EntryPoint="hid_write")] public static extern
            int hidWrite(IntPtr device, [In] byte[] data, int length);
        [DllImport("libhidapi-0.dll", EntryPoint="hid_read_timeout")] public static extern
            int hidReadTimeout(IntPtr device, [Out] String data, int length, int milliseconds);
//      int hidReadTimeout(IntPtr device, [Out] byte[] data, int length, int milliseconds);
        [DllImport("libhidapi-0.dll", EntryPoint="hid_read")] public static extern
            int hidRead(IntPtr device, [Out] byte[] data, int length);
        [DllImport("libhidapi-0.dll", EntryPoint="hid_set_nonblocking")] public static extern
            int hidSetNonblocking(IntPtr device, int nonBlock); // done
        [DllImport("libhidapi-0.dll", EntryPoint="hid_send_feature_report")] public static extern
            int hidSendFeatureReport(IntPtr device, [In] byte[] data, int length);
        [DllImport("libhidapi-0.dll", EntryPoint="hid_get_feature_report")] public static extern
            int hidGetFeatureReport(IntPtr device, [Out] String data, int length);
//      int hidGetFeatureReport(IntPtr device, StringBuilder data, int length);
//      int hidGetFeatureReport(IntPtr device, [Out] byte[] data, int length);
        [DllImport("libhidapi-0.dll", EntryPoint="hid_close")] public static extern
            void hidClose(IntPtr device); // done
        [DllImport("libhidapi-0.dll", EntryPoint="hid_get_manufacturer_string", CharSet=CharSet.Auto)] public static extern
            int hidGetManufacturerString(IntPtr device, [Out] String str, int maxLen); // done
        [DllImport("libhidapi-0.dll", EntryPoint="hid_get_product_string", CharSet=CharSet.Auto)] public static extern
            int hidGetProductString(IntPtr device, [Out] String str, int maxLen); // done
        [DllImport("libhidapi-0.dll", EntryPoint="hid_get_serial_number_string", CharSet=CharSet.Auto)] public static extern
            int hidGetSerialNumberString(IntPtr device, [Out] String str, int maxLen); // done
        [DllImport("libhidapi-0.dll", EntryPoint="hid_get_indexed_string", CharSet=CharSet.Auto)] public static extern
            int hidGetIndexedString(IntPtr device, int stringIndex, [Out] String str, int maxLen); // done
        [DllImport("libhidapi-0.dll", EntryPoint="hid_error", CharSet=CharSet.Auto)] public static extern
            String hidError(IntPtr device); // done

    }
}

Program.cs

using System;
using System.Text;
using hidapi;

namespace usbhid
{
    class MainClass
    {
        public static void Main (string[] args)
        {
            int res = -1;

            HIDAPI.hidInit ();
            Console.WriteLine ("hidInit");

            IntPtr device = HIDAPI.hidOpen(0x0402, 0x0402, null);
            Console.WriteLine ("hidOpen");
            if (device != null)
            {
                Console.WriteLine ("success");

                // Initializes buffer and appends something to the end so the whole
                // buffer is passed to the unmanaged side.
                StringBuilder buffer = new StringBuilder(100);
                buffer.Append((char)0);
                buffer.Append('*', buffer.Capacity - 8);

                String strBuffer = buffer.ToString();
                int size = strBuffer.Length;

                res = HIDAPI.hidGetManufacturerString (device, strBuffer, size);
                if (res == 0) 
                {
                    // Remove nulls and filler char from string
                    strBuffer = strBuffer.TrimEnd (new char[] { (char)0, '*' });
                    Console.WriteLine ("manufacturer: '"+strBuffer+"'");
                }
                else
                {
                    Console.WriteLine ("Couldn't get manufacturer string");
                }

                strBuffer = buffer.ToString();
                res = HIDAPI.hidGetProductString(device, strBuffer, size);
                if (res == 0) 
                {
                    strBuffer = strBuffer.TrimEnd (new char[] { (char)0, '*' });
                    Console.WriteLine ("product: '"+strBuffer+"'");
                }
                else
                {
                    Console.WriteLine ("Couldn't get product string");
                }

                strBuffer = buffer.ToString();
                res = HIDAPI.hidGetSerialNumberString (device, strBuffer, size);
                if (res == 0) 
                {
                    strBuffer = strBuffer.TrimEnd (new char[] { (char)0, '*' });
                    Console.WriteLine ("serial number: '"+strBuffer+"'");
                }
                else
                {
                    Console.WriteLine ("Couldn't get serial number string");
                }

                strBuffer = buffer.ToString();
                res = HIDAPI.hidGetIndexedString (device, 10, strBuffer, size);
                if (res == 0) 
                {
                    strBuffer = strBuffer.TrimEnd (new char[] { (char)0, '*' });
                    Console.WriteLine ("indexed string 10: '"+strBuffer+"'");
                }
                else
                {
                    Console.WriteLine ("Couldn't get indexed string string");
                    String strError = HIDAPI.hidError (device);
                    Console.WriteLine ("Error: '"+strError+"'");
                }
            }

//          byte[] report = new byte[1000];
//          report [0] = 0;
//          int reportLength = 600;
//          res = HIDAPI.hidGetFeatureReport (device, report, reportLength);
            char reportId = (char)0x00;
            StringBuilder report = new StringBuilder(1000);
            report.Append(reportId);
            report.Append('*', report.Capacity - 8);
            String reportBuffer = report.ToString();
            int reportLength = reportBuffer.Length;
//          res = HIDAPI.hidGetFeatureReport (device, reportBuffer, reportLength);
//          if (res == 0)
//          {
//              Console.WriteLine ("hidGetFeatureReport");
//          }
//          else
//          {
//              Console.WriteLine ("could not read report with ID = "+reportId);
//              String strError = HIDAPI.hidError (device);
//              Console.WriteLine ("Error: '"+strError+"'");
//          }

            reportId = (char)0x01;
            report = new StringBuilder(1000);
            report.Append(reportId);
            report.Append('*', report.Capacity - 8);
            reportBuffer = report.ToString();
            reportLength = reportBuffer.Length;
            res = HIDAPI.hidReadTimeout(device, reportBuffer, reportLength, 500);
            if (res == 0)
            {
                Console.WriteLine ("hidReadTimeout");
            }
            else
            {
                Console.WriteLine ("could not read report with ID = "+reportId);
                String strError = HIDAPI.hidError (device);
                Console.WriteLine ("Error: '"+strError+"'");
            }

            HIDAPI.hidClose (device);
            Console.WriteLine ("hidClose");

//          device = HIDAPI.hidOpenPath("\\\\?\\hid#vid_0402&pid_0402#6&28a68c1a&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}");
//          Console.WriteLine ("hidOpenPath");
//          if(device != null)
//              Console.WriteLine ("success");
//
//          HIDAPI.hidClose (device);
//          Console.WriteLine ("hidClose");

            HIDAPI.hidExit ();
            Console.WriteLine ("hidExit");
        }
    }
}

I'm not sure how to format and pretty print code.

Hope this helps.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.