DllImport einer C-DLL von Burster

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 37 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    DllImport einer C-DLL von Burster

    Hallo
    Ich habe eine in C erstellte DLL von Burster um einen Drehmomentsensor auszulesen. Nun möchte ich einen Wrapper erstellen um die DLL aus vb.net anzusprechen. Bei einigen Funktionen funktioniert das schon recht gut, aber bei Funktionen mit einen Pointer auf ein Char-Array habe ich Mühe.

    Die Beschreibung der Funktion lautet:

    Quellcode

    1. Function bp8661_GetSerialNr& (ByVal portHandle&, ??serialNumber??)


    protHandle ist ein Integer und stellt kein Problem dar, aber die serialNumber ist wie folgt beschrieben:

    ??serialNumber??
    Control Name: SerialNumber
    Description: Serial number of the deviceVariable
    Type: char array (pointer on char array)Length: max. 20 chars + termination


    Ich habe dann anhand dieses Artikels folgenden Code ausprobiert:

    VB.NET-Quellcode

    1. <DllImport("bp8661.dll", CallingConvention:=CallingConvention.Cdecl, CharSet:=CharSet.Ansi, ExactSpelling:=True)>
    2. Public Shared Function bp8661_GetSerialNr(ByVal portHandle As Integer, ByVal serialNumber As IntPtr) As Integer
    3. End Function
    4. Public Shared Function bp8661_GetSerialNr(ByVal portHandle As Integer) As String
    5. Dim serialNumberPointer As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(IntPtr.Zero))
    6. bp8661_GetSerialNr(portHandle, serialNumberPointer)
    7. Dim p0 As IntPtr
    8. p0 = Marshal.ReadIntPtr(serialNumberPointer)
    9. Return Marshal.PtrToStringAnsi(p0)
    10. End Function


    Ich bekomme aber einen Fehler bei Aufruf der Funktion und zwar:
    System.AccessViolationException: "Es wurde versucht, im geschützten Speicher zu lesen oder zu schreiben. Dies ist häufig ein Hinweis darauf, dass anderer Speicher beschädigt ist."

    Kann mir jemand hier weiterhelfen?
    Viele Grüsse Roland
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @ElmarElefant

    Mal grob geschätzt. PortHandle dürfte ein IntPtr sein der ByVal zu übergeben ist. SerialNumber könntest As StringBuilder festlegen der per ByVal zu übergeben ist und evtl noch per <Out, MarshalAs(UnmanagedType.LPStr)> gemarshallt werden muss. Entsprechend musst die zu übergebende Variable noch dimensionieren. Dim strSerialNumber = New StringBuilder(21).

    Kannst ja mal ausprobieren. Ansonsten wäre der letzte Parameter als ByRef As IntPtr auszulegen. Per Marshal.Copy dann vom Pointer entsprechend in ein ByteArray umkopieren.
    Mfg -Franky-
    Ich habe noch ein wenig rumprobiert, und weiteres für mich nicht nachvollziehbares Verhalten festgestellt.

    Beispielsweise funktioniert der Aufruf der DLL-Funktion:
    Function bp8661_GetSplayValue& (ByVal portHandle&, splayValue!)

    VB.NET-Quellcode

    1. <DllImport("bp8661.dll", CallingConvention:=CallingConvention.Cdecl)>
    2. Public Shared Function bp8661_GetSplayValue(ByVal portHandle As Integer, ByRef splayValue As Single) As Integer
    3. End Function


    aber der Aufruf der Funktion
    Function bp8661_GetValues& (ByVal portHandle&, valueTorque!, valueSpeed!, valueAngle!, valuePower!, valueIncrement!)

    VB.NET-Quellcode

    1. <DllImport("bp8661.dll", CallingConvention:=CallingConvention.Cdecl)>
    2. Public Shared Function bp8661_GetValues(ByVal portHandle As Integer, ByRef valueTorque As Single, ByRef valueSpeed As Single, ByRef valueAngle As Single, ByRef valuePower As Single, ByRef valueIncrement As Single) As Integer
    3. End Function

    führt zum gleichen Fehler: System.AccessViolationException.
    @ElmarElefant Wie sieht denn die original C-Deklaration aus?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @-Franky- Byref war klar ein Fehler von mir. Ich habe beides ausprobiert. StringBuilder führt direkt auch zu dem bekannten Fehler. Und wenn ich IntPr als ByRef deklariere, funktioniert der Aufruf, ich bekomme aber den gleichen Fehler beim Aufruf von Marshal.ReadIntPtr(serialNumberPointer).

    Ich habe die DLL und di Dekl. soweit ich sie habe angehängt.
    Dateien
    • bp8661.dll

      (67,58 kB, 92 mal heruntergeladen, zuletzt: )
    • bp8661.7z

      (3,55 kB, 82 mal heruntergeladen, zuletzt: )
    @ElmarElefant Kann es sein, dass da noch eine weitere DLL dabei liegt: Instrsup.dll?
    Häng die mal mit an.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Das _VI_FUNC macht wohl aus dem Methodenaufruf nen __fastcall oder __stdcall (siehe github.com/rbmj/wpilib/blob/master/visa/visatype.h#L18 - das ist wohl die visatype.h, die in der in deinem Header verlinkten vpptype.h verlinkt wird, wenn mein Googeln stimmt). Entsprechend musst du die CallingConvention anpassen.
    @RodFromGermany
    Ich sehe keine solche Datei. Ich habe mal alle Dateien die ich vom Hersteller bekommen habe angefügt.

    @nafets
    Es ist so, dass ich mit C und DLLImport eigentlich nichts am Hut habe. Ich müsste einfach nur ein paar Funktionen dieser DLL nutzen können. Ich habe mal mit folgendem probiert:

    VB.NET-Quellcode

    1. <DllImport("bp8661.dll", CallingConvention:=CallingConvention.FastCall)>
    2. Public Shared Function bp8661_GetValues(ByVal portHandle As Integer, ByRef valueTorque As Single, ByRef valueSpeed As Single, ByRef valueAngle As Single, ByRef valuePower As Single, ByRef valueIncrement As Single) As Integer
    3. End Function


    und

    VB.NET-Quellcode

    1. <DllImport("bp8661.dll", CallingConvention:=CallingConvention.StdCall)>
    2. Public Shared Function bp8661_GetValues(ByVal portHandle As Integer, ByRef valueTorque As Single, ByRef valueSpeed As Single, ByRef valueAngle As Single, ByRef valuePower As Single, ByRef valueIncrement As Single) As Integer
    3. End Function


    Beides führt zu einem Fehler. Das Erste zu System.TypeLoadException: "Ungültige nicht verwaltete Aufrufkonvention ("stdcall", "cdecl" oder "thiscall" ist erforderlich)." Das Zweite zum gleichen Fehler wie vorher (System.AccessViolationException).
    Dateien
    • 8661.7z

      (1,08 MB, 84 mal heruntergeladen, zuletzt: )
    @-Franky-

    Ich habe folgendes probiert mit der 8661.dll

    VB.NET-Quellcode

    1. <DllImport("8661.dll", CallingConvention:=CallingConvention.StdCall)>
    2. Public Shared Function OpenInterface(ByVal comPort As Integer) As Integer
    3. End Function
    4. <DllImport("8661.dll", CallingConvention:=CallingConvention.StdCall)>
    5. Public Shared Function GetSerialNr(ByVal portHandle As Integer, <Out, MarshalAs(UnmanagedType.LPStr)> libVersion As System.Text.StringBuilder) As Integer
    6. End Function
    7. <DllImport("8661.dll", CallingConvention:=CallingConvention.StdCall)>
    8. Public Shared Function GetSerialNr(ByVal portHandle As Integer, ByRef serialNr As IntPtr) As Integer
    9. End Function


    Function openInterface funktioniert, GetSerialNr führt auch zur Ausnahme (System.AccessViolationException).
    Mal nen anderer Gedanke, den wir bisher noch nicht angeschaut haben: Läuft deine App als x86 oder x64, oder AnyCPU? Wenn du solche Aufrufe verwendest, ist es oft nötig, die Architektur explizit auf entweder x86 oder x64 festzulegen, damit man die Libraries nutzen kann.

    Ansonsten verwundert es mich, dass __fastcall-Aufrufe irgendwie nicht unterstützt werden, aber wenn das am Ende fastcalls sind und du von VB.NET aus keine fastcalls ausführen kannst, wird der Aufruf halt vmtl. auch nicht funktionieren, egal was du änderst.
    @ElmarElefant

    Aus Mangel eines entsprechenden Motors / Sensors kann man nur raten.
    Zunächst: Wenn ich mir in der bp8661.c die void main anschau, führst Du zuerst SetInterfaceConfiguration mit validen Werten aus. Return muss FUNCTION_OK sein. Danach OpenInterface mit entsprechendem "virtuellem?" Com Port wo wahrscheinlich Dein Motor/Sensor angeschlossen ist. Return sollte >= 0 (PortHandle) sein (erst dann kann man auch CloseInterface aufrufen). Ist dieser kleiner 0 dann ist da schon ein Fehler. Mehr kann ich dazu auch nicht sagen.
    Mfg -Franky-
    Sorry, irgendwo steht bei mir einer auf der Leitung.
    Egal, ob ich die DLLs im PostBuild kopieren lasse oder ob ich sie direkt nach Debug/Release kopiere, er findet die DLLs nicht.
    C#, VB dasselbe:
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany

    Kopiere die beiden DLLs einfach in irgendeinen Ordner und gib einfach hinter DLLImport den kompletten Pfad zur DLL mit an. Soweit ich das sehen kann, ruft die bp8661.dll die 8661.dll auf. Denke die bp8661.dll ist nur ein Wrapper für LabView. Deswegen sollte ein direkter Aufruf der 8661.dll auch funktionieren.
    Mfg -Franky-
    @-Franky- Dasselbe:

    Rufe ich die mit x64 auf, kommt klar der erwartete Fehler:

    Sehr sehr unklar.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    -Franky- schrieb:

    Nimm die 8661.dll
    Auch das habe ich hinter mir, dort wird gesagt, dass der Eintrittspunkt nicht gefunden wurde.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!