DLLImport AccessViolationException bei USB API



  • Halli Hallo,

    habe folgendes Problem und komme leider überhaupt nicht mehr weiter:

    Um mit meinem uC zu kommunizieren benutze ich die USB Xpress API von SiLabs. Da ich die eigentliche Software jedoch in C# schreibe möchte ich die Funktionen via DLLImport einfügen. Hier mal der Kopf mit den wesentlichsten Funktionen - sollte soweit eigentlich alles korrekt sein!

    // Function gets the available number of devices
            [DllImport("SiUSBXp.dll", CallingConvention = CallingConvention.StdCall)]  
            public static extern int SI_GetNumDevices(out UInt32 devCount);
            // C++ prototype:        SI_STATUS WINAPI SI_GetNumDevices(LPDWORD lpdwNumDevices);
    
            // Function gets the serial of the chosen device
            [DllImport("SiUSBXp.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int SI_GetProductString(UInt32 devNum, [In, Out] char[] devString, long flags); 
            // C++ prototype:       SI_STATUS WINAPI SI_GetProductString(DWORD dwDeviceNum,LPVOID lpvDeviceString,DWORD dwFlags);
            // Flags should be set to 0x00 --> SI_RETURN_SERIAL_NUMBER
    
            // Function opens connection to the device and  and returns Handle for subsequent access
            [DllImport("SiUSBXp.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int SI_Open(UInt32 devNum, out IntPtr devHandle);
            // C++ prototype:       SI_STATUS WINAPI SI_Open(DWORD dwDevice,HANDLE* cyHandle); 
    
            // Function closes the connection to the device --> sets the value of the Handle to INVALID_HANDLE_VALUE = 0x01
            [DllImport("SiUSBXp.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int SI_Close(IntPtr devHandle);
            // C++ prototype:       SI_STATUS WINAPI SI_Close(HANDLE cyHandle);
    
            // Functions writes the content from the Buffer to the device
            [DllImport("SiUSBXp.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int SI_Write(IntPtr devHandle, byte[] inputBuffer, UInt32 size, out UInt32 bytesWritten); // this function needs the HAND
            // C++ prototype:       SI_STATUS WINAPI SI_Write(HANDLE cyHandle,LPVOID lpBuffer,DWORD dwBytesToWrite,LPDWORD lpdwBytesWritten,OVERLAPPED* o = NULL);
    

    Das Aufrufen der funktionen im Code funktioniert soweit auch, um das HANDLE darzustellen habe ich einen IntPtr benutzt.
    Nur leider habe ich bei der Funktion SI_Write ein Problem -> Wenn ich hier ein 10 Byte großes Array senden will meckert er mich an mit einer AccessViolationException. Aber hier erstmal der Code ( das unrelevante vorher habe ich rausgeschmissen ):

    IntPtr devHandle = new IntPtr();        // Handle for the device
                status = SI_Open(devNum,out devHandle);
                if (status != 0)
                {
                    Console.WriteLine("Error opening the device!\n");
                    Console.ReadKey();
                    return;
                }
                UInt32 bytesWritten = 0;
                byte[] writeBuffer = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
                UInt32 size = 10;
                status = SI_Write(devHandle, writeBuffer, size,out bytesWritten);
    

    Am IntPtr sollte es eigentlich nicht liegen, da wenn ich z.B. direkt SI_Close aufrufe er das korrekt ausführt.
    An size und bytesWritten liegt es denk ich auch nicht. Nur sehe ich nicht den Fehler den er bei dem writeBuffer hat. Ich hab mal bisschen rumgespielt und wenn ich z.B. writeBuffer mit dem Schlüsselwort out übergeb sendet er auch wie gewollt Daten an den uC ( diese kommen allerdings total verdreht dort an ) - Aber is ja auch eigentlich Schwachsinn das Array mit out nochma zu übergeben.

    Hab leider keine Ideen mehr wie ich das fixen könnte...vielleicht hat ja einer von euch nen genialen Einfall.
    Viele Dank schon mal!

    Viele Grüße

    Tobi



  • Okay hab das Problem selber in den Griff bekommen - sofern es mal von Interesse hier die Lösung -->
    eine Überladene Variante der Write Funktion erwartet noch einen Pointer am Schluss:

    // Functions writes the content from the Buffer to the device
            [DllImport("SiUSBXp.dll", CallingConvention = CallingConvention.StdCall)]
            static extern int SI_Write(IntPtr devHandle, byte[] Buffer, UInt32 NumBytesToWrite, out UInt32 NumBytesWritten, IntPtr o);
            // C++ prototype:       SI_STATUS WINAPI SI_Write(HANDLE cyHandle,LPVOID lpBuffer,DWORD dwBytesToWrite,LPDWORD lpdwBytesWritten,OVERLAPPED* o = NULL);
    

    Wenn ich also am Schluss noch einen IntPtr.Zero übergeb geht es...sieht dann so aus:

    UInt32 bytesWritten = 0;
                byte[] writeBuffer = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
                UInt32 size = 10;
    
                status = SI_Write(devHandle, writeBuffer, size, out bytesWritten,IntPtr.Zero);
    


  • Ja, das ist auch keine Überladung, sondern nur eine Funktion mit optionalem Parameter (in deinem C++ Prototyp das OVERLAPPED* o = NULL ). Das könntest du auch als Default-belegten Parameter in deiner C#-Funktion festlegen.



  • CStoll schrieb:

    Das könntest du auch als Default-belegten Parameter in deiner C#-Funktion festlegen.

    Lieber nicht. Der Default-Parameter wird fest in den Code eingebaut, der die Funktion aufruft. Das führt zu unschnen Ereignissen, wenn man den Wert des Default-Parameters ändert, aber den aufrufenden Code nicht neu gegenkompiliert 😉


Log in to reply