D-Bus DLL richtig einbinden (Datentypen)

  • VB.NET
  • .NET (FX) 4.0

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von KSE.

    D-Bus DLL richtig einbinden (Datentypen)

    Hallo zusammen,

    ich habe eine DLL und weiß nicht genau, wie ich mit den Datentypen korrekt umgehen muss ...
    Kann mir hierbei jemand helfen?

    Das Bild zeigt, wie die Funktion aufgebaut ist.

    Ich habe es jetzt mal so probiert:

    VB.NET-Quellcode

    1. Public Declare Function dbusSendFrame Lib "DBusDrv.dll" (ByVal portHandle As Integer, _
    2. ByVal targetAddress As Integer, _
    3. ByVal messageData As IntPtr, _
    4. ByRef messageDataSize As Integer) As Integer
    5. Private Sub Button12_Click(sender As Object, e As EventArgs) Handles btnSendFrame.Click
    6.  
    7. Dim porthandle As Integer = CInt(TextBox16.Text)
    8. Dim managedArray(2) As Integer
    9. managedArray(0) = &H51 'Identifier
    10. managedArray(1) = &H60 'Identifier
    11. managedArray(2) = &H4 '&H200096B
    12. Dim pinnedArray As GCHandle = GCHandle.Alloc(managedArray, GCHandleType.Pinned)
    13. Dim pnt As IntPtr = pinnedArray.AddrOfPinnedObject()
    14. ' PortHandle|Target Address|Message Data|Message DataSize
    15. Dim res As Integer = dbusSendFrame(porthandle, &H10, pnt, 3)
    16. pinnedArray.Free()
    17. End Sub



    Ich bekomme darauf hin einen Fehler von der DLL, dass ein ungültiger Parameter an die Funktion der DLL gesendet wurde.
    Bilder
    • dbusSendFrame.jpg

      227,02 kB, 800×600, 168 mal angesehen
    Gruß von der KSE

    ks-entwicklung.de
    @KSE Zur Datenkommunikation mit unmanaged DLLs gugst Du hier. Im 2. Post wird die Übergabe von Strukturen behandelt.
    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!
    Muss ich das Array dann in eine Struktur packen, so etwas ?


    VB.NET-Quellcode

    1. Public Declare Function dbusSendFrame Lib "DBusDrv.dll" (ByVal portHandle As Integer, _
    2. ByVal targetAddress As Integer, _
    3. ByVal messageData As IntPtr, _
    4. ByRef messageDataSize As Integer) As Integer
    5. <StructLayout(LayoutKind.Sequential)> Structure VDBusSendFrame
    6. <MarshalAs(UnmanagedType.ByValArray, SizeConst:=3)> Dim MessageData() As Byte
    7. End Structure
    8. Private Sub Button12_Click(sender As Object, e As EventArgs) Handles btnSendFrame.Click
    9. Dim porthandle As Integer = CInt(TextBox16.Text)
    10. Dim Sendfrm As New VDBusSendFrame
    11. Sendfrm.MessageData = {&H51, &H60, &H4}
    12. Dim ptr As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(Sendfrm))
    13. Marshal.StructureToPtr(Sendfrm, ptr, False)
    14. System.Threading.Thread.Sleep(100)
    15. Dim err As Integer = dbusSendFrame(porthandle, &H10, ptr, 3)
    16. 'Sendfrm = Marshal.PtrToStructure(ptr, GetType(VDBusSendFrame))
    17. End Sub
    Gruß von der KSE

    ks-entwicklung.de

    KSE schrieb:

    Muss ich
    Jou.
    Mach es maöl ganz genau wie im Beispiel.
    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!
    So dann ?(

    VB.NET-Quellcode

    1. Public Declare Function dbusSendFrame Lib "DBusDrv.dll" (ByVal portHandle As VDBusPortHandle, _
    2. ByVal targetAddress As Integer, _
    3. ByVal messageData As IntPtr, _
    4. ByRef messageDataSize As Integer) As Integer
    5. <StructLayout(LayoutKind.Sequential)> _
    6. Public Structure VDBusSendFrame
    7. <MarshalAs(UnmanagedType.ByValArray, SizeConst:=3)> Dim MessageData() As Byte
    8.  
    9. Public Sub New(xx As Boolean)
    10. MessageData = New Byte(3) {}
    11. End Sub
    12. End Structure
    13. Private Sub Button12_Click(sender As Object, e As EventArgs) Handles btnSendFrame.Click
    14. Dim porthandle As Integer = CInt(TextBox16.Text)
    15. Dim porth As VDBusPortHandle
    16. porth.VDBusPortHandle = CInt(TextBox16.Text)
    17. Dim Sendfrm As New VDBusSendFrame(True)
    18. Sendfrm.MessageData = {&H51, &H60, &H4}
    19. Dim ptr As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(Sendfrm))
    20. Marshal.StructureToPtr(Sendfrm, ptr, True)
    21. Dim success As Integer = dbusSendFrame(porth, &H10, ptr, 3)
    22. Dim sendfrm2 As VDBusSendFrame = CType(Marshal.PtrToStructure(ptr, GetType(VDBusSendFrame)), VDBusSendFrame)
    23. Marshal.FreeHGlobal(ptr)
    24. End Sub
    Gruß von der KSE

    ks-entwicklung.de

    KSE schrieb:

    VB.NET-Quellcode

    1. Dim porthandle As Integer = CInt(TextBox16.Text)
    Mach da mal ein NumericUpDown draus.

    KSE schrieb:

    VB.NET-Quellcode

    1. Dim sendfrm2 As VDBusSendFrame = CType(Marshal.PtrToStructure(ptr, GetType(VDBusSendFrame)), VDBusSendFrame)
    ist nicht nötig, wenn Du keine Daten aus der DLL in dieser Struktur zurückbekommst.
    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!

    KSE schrieb:

    den Fehler
    Du hast da 2 Strukturen drin.
    Ich denke mal, dass VDBusPortHandle den Fehler generieret.
    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!
    Also der Fehler kommt jetzt nicht mehr. Ich hatte bei der Funktion dbusSendFrame bei messageDataSize byRef geschrieben, anstatt byVal ...
    Die Einstellung wird trotzdem nicht gesetzt ...

    Edit: Es wird eine Einstellung gesetzt nur nicht die richtige.. Vielleicht hat es was mit zu tun, dass ich bei sendfrm2 nur die zwei von drei zurück bekomme. Vielleicht werden dann auch nur zwei gesendet???
    Gruß von der KSE

    ks-entwicklung.de

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „KSE“ ()

    @KSE Da stimmen wohl die Parameter immer noch nicht. :/
    Hast Du einen C++-Demo-Code?
    Wenn Du es kannst, schreib ein CLI (managed C++-Programm) und mach dort einen einfachen unmanaged Call.
    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!
    Meiner Meinung nach müsste die Signatur so aussehen:

    Visual Basic-Quellcode

    1. <DllImport("DBusDrv.dll")> _
    2. Public Shared Function dbusSendFrame(ByVal portHandle As IntPtr, ByVal targetAddress As Integer, ByVal messageData As IntPtr, ByVal messageDataSize As Integer) As Integer
    3. End Function

    Das sind laut unmanaged-Deklaration alles ByValue-Parameter. Auf dem Bild steht auch noch was von einer Callback-Funktion - die muss korrekt deklariert sein und deren Delegat darf nicht vom GC eingesammelt werden. Wahrscheinlich muss die irgendwo anders (vorher?) festgelegt werden.

    Edit: Ok, das mit ByVal hat sich offenbar erledigt, wie ich grad gelesen habe.

    Ist das Porthandle wirklich der Wert aus einer Textbox? Das sollte eher das Ergebnis eines erfolgreichen Aufrufs an eine Funktion sein, die den Port öffnet. Das Array musst du nicht selbst pinnen - das macht der Marshaller normalerweise von alleine. In diesem Fall würde ich die Daten manuell in den unverwalteten Speicher kopieren (Marshal.AllocHGlobal + Marshal.Copy) und dem Code die Adresse des unverwalteten Blocks geben.
    Gruß
    hal2000
    Hallo RodFromGermany u. hal2000,

    mit folgendem Code hat es funktioniert. Eigentlich gar nicht so kompliziert, wenn man sich mal damit auseinander setzt. Danke an euch zwei, hat mir viel geholfen!

    Damit keine Fehler kommen, musste ich aber im Projekt->Debuggen Systemeinges Codedebugging aktivieren ?( ( durch rumspielen darauf gestoßen...)
    Kann mir jemand sagen, was sich genau hinter der Einstellung verbirgt???


    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Declare Function dbusSendFrame Lib "DBusDrv.dll" (ByVal portHandle As VDBusPortHandle, _
    2. ByVal targetAddress As Integer, _
    3. ByVal messageData As IntPtr, _
    4. ByVal messageDataSize As Integer) As Integer
    5. Private Sub SendMessage(ByVal Message As Integer, ByVal ByteCount As Integer)
    6. Dim ptr As IntPtr
    7. If SendingMessage = True Then Exit Sub
    8. SendingMessage = True
    9.  
    10. Dim porth As VDBusPortHandle
    11. porth.VDBusPortHandle = _PortHandle
    12.  
    13. ptr = Marshal.AllocHGlobal(Message)
    14. Marshal.WriteIntPtr(ptr, Message)
    15.  
    16. Dim success As Integer = dbusSendFrame(porth, &H10, ptr, ByteCount)
    17. Marshal.FreeHGlobal(ptr)
    18. SendingMessage = False
    19. End Sub

    Gruß von der KSE

    ks-entwicklung.de

    KSE schrieb:

    Projekt->Debuggen Systemeinges Codedebugging aktivieren
    In welchem Kontext kommt bei Dir dieser Menüpunkt?
    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!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RodFromGermany“ ()

    KSE schrieb:

    Systemeinges Codedebugging

    ...bedeutet, dass du nicht nur deinen eigenen Code debuggst, sondern auch nativen Code. Wenn diese Einstellung aktiv ist, kannst du z.B. den Stack (Fenster "Aufrufliste") auch nachverfolgen, wenn sich die Ausführung gerade in der DBusDrv.dll befindet. Passende Debugsymbole vorausgesetzt kannst du alles debuggen, was nativ auf dem Prozessor läuft, also auch Windows selbst. Mit Visual Studio geht das aber nur in engen Grenzen - WinDbg ist dafür besser geeignet.

    Auch wenn dein Code funktioniert, ist er nicht wirklich sinnvoll. Du forderst mit AllocHGlobal "Message" Bytes an Speicher an, schreibst dann aber nur 4 bzw. 8 (IntPtr.Size). Das geht sogar in die Hose, wenn "Message" nur den Wert 1 hat - dann schreibt er 4 Byte und du kassierst eine Exception. Fordere also genau das an, was du wirklich brauchst - nicht mehr, nicht weniger. Was ist denn überhaupt eine "Message"? ist das wirklich nur ein Integer oder ein Zeiger auf eine Struktur?
    Gruß
    hal2000

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „hal2000“ ()

    @hal2000: Danke für deine ausführliche Antwort!!!
    Ich sende zum einen den Hexwert &H8851, der dafür zuständig ist, dass Messwerte an das Programm gesendet werden und zum anderen &H18051. Dabei ist 5180 die Adresse und 1 die Flanke, um den Messmodus zu aktivieren.
    So wie du schreibst, wird das auch der Grund sein, wieso sich das Programm aufhängt. Das geht sogar soweit, wenn Systemeigenes Codedebugging nicht aktiviert ist, dass sich das Programm beim Einlesen der Messwerte komplett abschießt, ohne eine Exception zu schmeißen...
    Gruß von der KSE

    ks-entwicklung.de

    hal2000 schrieb:

    sondern auch nativen Code.
    Sorry, mein Studio ist englisch, da heißt es Enable unmanaged code debugging.
    @KSE Hast Du die Quellen dieser DLL?
    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!
    @KSE das DLL-Projekt dieser DLL. Ohne diese kannst Du nämlich da nicht rein-debuggen, da geht nur Step Over (F10), nicht aber Step Into (F11).
    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!
    Ok - da die nachricht offensichtlich aus einzelnen Bytes besteht, gibt es keinen Grund, das in einen Integer zu verpacken. Hier mein Vorschlag:

    VB.NET-Quellcode

    1. Private Sub SendMessage(ByVal Message() As Byte)
    2. Dim ptr As IntPtr
    3. If SendingMessage = True Then Exit Sub
    4. SendingMessage = True
    5. Dim porth As VDBusPortHandle
    6. porth.VDBusPortHandle = _PortHandle
    7. ptr = Marshal.AllocHGlobal(Message.Length)
    8. Marshal.Copy(Message, 0, ptr, Message.Length)
    9. Dim success As Integer = dbusSendFrame(porth, &H10, ptr, Message.Length)
    10. Marshal.FreeHGlobal(ptr)
    11. SendingMessage = False
    12. End Sub


    ...mit Message = New New Byte() {&H51, &H88} bzw. {&H51, &H80, &H1}.

    Ich hoffe mal, dass die Variable "SendingMessage" nicht dazu dient, Multithreading zu synchronisieren. Das wäre ein weiterer Grund dafür, dass sich das Programm ggf. aufhängt.

    RodFromGermany schrieb:

    da heißt es Enable unmanaged code debugging

    ...was den Sachverhalt auch treffender beschreibt - keine Ahnung warum MS das mit "systemeigen" übersetzt hat.
    Gruß
    hal2000