none
Überführen von DLL-Callback von VBA (Excel) in VB RRS feed

  • Frage

  • Hallo zusammen,

    ich versuche ein Programm, das vor langer Zeit in Excel VBA geschrieben wurde in ein eigenständiges Programm in Visual Studio Express zu überführen (als VB-Programm) - viel mit Hilfe von Google. Allerdings bin ich inzwischen an einem Punkt, an dem ich euer Expertenwissen brauche :). Das Problem, das ich habe ist, dass Funktionen aus einer DLL von einem Drittanbieter importiert werden, auf die ich keinen Einfluss habe. Einer wichtigen Funktion (TC_StartTimer) wird eine Callback-Funktion aus dem VB-Code übergeben. Früher war das mit AddressOf realisiert, aber jetzt kriege ich das nicht hin. Meine bisherige Suche hat mit auf Delegate-Funktionen gebracht, aber ich bin offenbar zu doof, dass ich das hinkriege, weil bei der Übergabe des Callbacks auch immer der Aufrufwert (Time) mit angegeben werden muss, den ich aber nicht habe, weil der aus der DLL kommt. Auch die Änderung von ByVal Callback zu ByRef hat nichts gebracht. Die Hauptklasse ist eine Windows-Form, die Klasse Connection habe ich aus einem Modul in Excel kopiert und als Klasse eingefügt, damit ich die Funktionen nutzen kann. Das Modul Measurement habe ich als Modul belassen. 

    Hier mal der Code:

    Public Class Form1
        Public Shared Conn As Connection
                
                ... das ist die Hauptklasse, eine Windows-Form Form1 ...
    End Class
    

    Public Class Connection
    
                Private Declare Function TC_StartTimer Lib "fremdeDLL.dll" (ByVal Handle As Integer, ByVal Interval As Integer, ByVal Callback As Integer) As Integer
                
                Dim H As Object
                
                Public Sub StartTimer(ByRef Callback As Integer, ByVal Interval As Integer)
            Dim Result As Integer
    
            Result = TC_StartTimer(H, Interval, Callback)
            If Result < 0 Then
                Call RaiseError("Connection.StartTimer", Result)
            End If
        End Sub
    
    End Class
    

    Module Measurement
                Public Function TimerFunc(ByVal Time As Integer) As Integer
                            ... Verarbeiten von Time ...
                            ... Ausgeben von TimerFunc als Integer ...
                End Function
                
                Public Sub Start()
                            ...
                            Call Form1.Conn.StartTimer(AddressOf TimerFunc, GlobalMeasInterval * 1000)
                End Sub
    End Module
    

    Ich hoffe mein (versuchtes) Minimalbeispiel hilft euch weiter zu verstehen, was ich meine. Danke euch vielmals.

    Viele Grüße

    Marius

    Donnerstag, 26. März 2020 15:29

Antworten

  • Hi,

    konnte es jetzt nach ewiger Suche lösen. Danke an alle (vor allem Peter). Die Delegate Funktion musste in die Connection Klasse und dann alle Referenzen geändert werden. Und da ich es nicht leiden kann, wenn die Lösungen in Foren nicht gepostet werden, hier noch meine Lösung:

    Public Class Connection
    
                Private Declare Function TC_StartTimer Lib "fremdeDLL.dll" (ByVal Handle As Integer, ByVal Interval As Integer, ByVal Callback As CallBackFunc) As Integer
                
    Delegate Function CallBackFunc(ByVal time as Integer) as Integer
    
                Dim H As Object
                
                Public Sub StartTimer(ByRef Callback As CallBackFunc, ByVal Interval As Integer)
            Dim Result As Integer
    
            Result = TC_StartTimer(H, Interval, Callback)
            If Result < 0 Then
                Call RaiseError("Connection.StartTimer", Result)
            End If
        End Sub
    
    End Class
    Module Measurement
                Public Function TimerFunc(ByVal Time As Integer) As Integer
                            ... Verarbeiten von Time ...
                            ... Ausgeben von TimerFunc als Integer ...
                End Function
                
                Public Sub Start()
                            ...
                            Call Form1.Conn.StartTimer(AddressOf TimerFunc, GlobalMeasInterval * 1000)
                End Sub
    End Module

    • Als Antwort markiert Marius0815 Montag, 30. März 2020 15:11
    • Bearbeitet Marius0815 Mittwoch, 22. April 2020 18:24
    Montag, 30. März 2020 15:11

Alle Antworten

  • Hi Markus,
    in der Deklaration ist der CallBack-Parameter als Integer (4 Byte) deklariert. Damit kannst Du keinen CallBack organisieren. Wenn du es stabil organisieren willst, dann solltest du über einen Wrapper in VB6 nachdenken, der alle Funktionalitäten kapselt und dann als COM-Objekt im VB.NET genutzt wird.

    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Donnerstag, 26. März 2020 15:41
  • Hallo Peter,

    vielen Dank. Habe ich das richtig verstanden, dass so ein Wrapper eine zusätzliche DLL ist, in der alle Funktionen enthalten sind, die ich zum Aufrufen des TC_StartTimer aus der externen DLL benötige? Den müsste ich aber dann mit VB6 erstellen, richtig? Weil das habe ich nicht zur Verfügung :( 

    Gibt es eine Möglichkeit, das mit Visual Studio zu realisieren (oder Excel VBA)? Oder gäbe es noch eine Möglichkeit, das anders zu machen? Ich habe da auch was mit Delegaten gefunden, das hat bei mir aber bisher nicht funktioniert. Bin leider kein Programmierer, habe nur Spaß daran und mache das für die Arbeit. 

    Viele Grüße, Marius

    Freitag, 27. März 2020 06:29
  • Hi,

    konnte es jetzt nach ewiger Suche lösen. Danke an alle (vor allem Peter). Die Delegate Funktion musste in die Connection Klasse und dann alle Referenzen geändert werden. Und da ich es nicht leiden kann, wenn die Lösungen in Foren nicht gepostet werden, hier noch meine Lösung:

    Public Class Connection
    
                Private Declare Function TC_StartTimer Lib "fremdeDLL.dll" (ByVal Handle As Integer, ByVal Interval As Integer, ByVal Callback As CallBackFunc) As Integer
                
    Delegate Function CallBackFunc(ByVal time as Integer) as Integer
    
                Dim H As Object
                
                Public Sub StartTimer(ByRef Callback As CallBackFunc, ByVal Interval As Integer)
            Dim Result As Integer
    
            Result = TC_StartTimer(H, Interval, Callback)
            If Result < 0 Then
                Call RaiseError("Connection.StartTimer", Result)
            End If
        End Sub
    
    End Class
    Module Measurement
                Public Function TimerFunc(ByVal Time As Integer) As Integer
                            ... Verarbeiten von Time ...
                            ... Ausgeben von TimerFunc als Integer ...
                End Function
                
                Public Sub Start()
                            ...
                            Call Form1.Conn.StartTimer(AddressOf TimerFunc, GlobalMeasInterval * 1000)
                End Sub
    End Module

    • Als Antwort markiert Marius0815 Montag, 30. März 2020 15:11
    • Bearbeitet Marius0815 Mittwoch, 22. April 2020 18:24
    Montag, 30. März 2020 15:11