Event-Übergabe an C Sharp mittels DLL

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
jlazarus
Beiträge: 10
Registriert: Mi 3. Apr 2024, 10:52

Event-Übergabe an C Sharp mittels DLL

Beitrag von jlazarus »

Hallo und guten Tag,
gleich vorab, bin neu hier und auch nur Hobby-Programmierer.
Ich nutze Lazarus 2.0.0 (2019-02-03) FPC-Version 3.0.4
Ich habe erfolgreich ein kleines Programm am Laufen, mit welchem ich über die freie Bibliothek 5dPO (SdpoSerial) eine serielle Schnittstelle auslese und diese kontinuierlich reinlaufenden Daten in z.B. ein Stringlist schreibe.

Procedure TFormSettings.ProcessInputDataBahn1(RX:String);
begin
myListe.Add(RX);
end;

procedure TFormSettings.SdpoSerial1RxData(Sender: TObject);
begin
ProcessInputData(SdpoSerial1.SynSer.RecvString(50));
end;

Das funktioniert in einer abgeschlossenen Lazarus-Form.

Jetzt habe ich in C Sharp 2019 ebenfalls ein Programm am Laufen, mit welchem ich eine Serielle Schnittstelle auslesen möchte.
Mit den in C# verfügbaren Möglichkeiten, das Auslesen zu Konfigurieren, komme ich aber nicht zum gleichen guten Ergebnis, wie in Lazarus.
Deshalb möchte ich die Funktion in Lazarus nutzen und dieses als DLL in C# einbinden.
Grundsätzlich habe ich schon eine in Lazarus erstellte DLL in C# erfolgreich eingebunden.
Aber eben nicht mit einem event sondern nur mit fester Parameterübergabe.
Für die Eventübernahme fehlt mir das Programmierwissen.
Wie kann ich das programmieren und SdpoSerial1RxData als event senden/empfangen? Kann mir da jemand helfen?

Besten Dank vorab, Jürgen

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1650
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Event-Übergabe an C Sharp mittels DLL

Beitrag von fliegermichl »

Das lässt sich über eine Callback Routine lösen.

Code: Alles auswählen

// def.inc
type
 TMyCallback = procedure(x : char); stdcall;
 
//dll
{$i def.inc}
procedure doRead(cb : TMyCallback);
var c : char;
begin
 c := doReadSerial;
 cb(c);
end;

exports doRead;
Aus dem C# Programm kann nun die Procedure doRead aufgerufen werden.

jlazarus
Beiträge: 10
Registriert: Mi 3. Apr 2024, 10:52

Re: Event-Übergabe an C Sharp mittels DLL

Beitrag von jlazarus »

Irgenwas mache ich falsch bzw. habe ich nicht verstanden.

Bekomme in C# folgende Meldung:
"Der als Zeichenfolge übergebene Zeiger, darf sich nicht im unteren 64 KB-Speicher des Adressbereichs für den Prozess befinden"

Hier mein Code in Lazarus:

Code: Alles auswählen

type
  TMyCallback = Procedure(cRx: String); stdcall;

function SdpoSerialRxData(): string;
begin
  Result := oComPort.SynSer.RecvString(50);
end;

procedure RxString(cRX: TMyCallBack);
var c: String;
begin
  c := SdpoSerialRxData();
  cRx(c);
END;

exports RxString;

Und das habe ich in C#:

Code: Alles auswählen

        public delegate bool FPtr(string value);
        [DllImport(".\\lib\\SeriellDLL.dll", EntryPoint = "RxString", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        public extern static string RxString(FPtr cb);

        private void Button1_Click(object sender, EventArgs e)
        {

            FPtr cb = new FPtr(DoSomething);
            RxString(cb);
        }

        public bool DoSomething(string value)
        {
            listBox1.Items.Add(value);
            return true;
        }
Jürgen
Zuletzt geändert von m.fuchs am Mi 3. Apr 2024, 14:18, insgesamt 1-mal geändert.
Grund: Highlighter hinzugefügt

Benutzeravatar
theo
Beiträge: 10921
Registriert: Mo 11. Sep 2006, 19:01

Re: Event-Übergabe an C Sharp mittels DLL

Beitrag von theo »

fliegermichl hat geschrieben: Mi 3. Apr 2024, 12:05 Das lässt sich über eine Callback Routine lösen.
Dein Beispiel kapiere ich nicht so ganz.
Wofür brauchst du hier überhaupt ein Callback? Mann kann ja c (wieso eig. char?) direkt zurückgeben.
Sinnvoller wäre doch, erst eine Callbackfunktion global zu registrieren um sie dann bei Bedarf aufzurufen und nicht in der von aussen aufgerufenen Funktion.

Oder sehe ich das falsch?

@jlazarus: Ich habe wirklich nicht viel Ahnung von CSharp, aber String als Parametertyp geht wahrscheinlich nicht.
Nimm PChar.

jlazarus
Beiträge: 10
Registriert: Mi 3. Apr 2024, 10:52

Re: Event-Übergabe an C Sharp mittels DLL

Beitrag von jlazarus »

@theo
Hab PChar probiert.
Ist aber dasselbe Ergebnis.
Klappt leider nicht.

Benutzeravatar
theo
Beiträge: 10921
Registriert: Mo 11. Sep 2006, 19:01

Re: Event-Übergabe an C Sharp mittels DLL

Beitrag von theo »

Wie gesagt, von C# habe ich kaum Ahnung, aber..

public extern static string RxString(FPtr cb);

..schaut schon mal suspekt aus. Eine Procedure hat keinen Rückgabewert (hier string)

jlazarus
Beiträge: 10
Registriert: Mi 3. Apr 2024, 10:52

Re: Event-Übergabe an C Sharp mittels DLL

Beitrag von jlazarus »

Du hast recht.

Habs geändert in:
public extern static void RxString(FPtr cb);

Jetzt empfange ich zumindest EIN Datenpaket.
Die Schnittstelle empfängt aber fortlaufend Daten.
Die kommen nicht rein.

Ich hab leider keine Ahnung, ob das Problem auf Lazarus- oder C#-Seite liegt.

Benutzeravatar
theo
Beiträge: 10921
Registriert: Mo 11. Sep 2006, 19:01

Re: Event-Übergabe an C Sharp mittels DLL

Beitrag von theo »

Willst du nicht lieber Synapse Synaser verwenden?
https://wiki.freepascal.org/Hardware_Ac ... munication
http://synapse.ararat.cz/doc/help/synas ... erial.html

Soweit ich sehe, ist SdpoSerial GUI-/Ereignisorientiert und das passt für eine DLL sowieso nicht.

jlazarus
Beiträge: 10
Registriert: Mi 3. Apr 2024, 10:52

Re: Event-Übergabe an C Sharp mittels DLL

Beitrag von jlazarus »

Hallo theo.
Im Moment komme ich leider nicht dazu, Synapse Synaser auszuprobieren.
Es ist aber auch so, dass ich 5Dpo SdpoSerial schon eine ganze Weile mit Lazarus im Einsatz habe und genau das Ergebnis habe, dass ich brauche.
Ich glaube sogar, dass ich damals Synaser probiert habe, aber damit nicht so zufrieden war.

Ich suche also erstmal weiter nach einer Lösung, SdpoSerial aus Lazarus mit C# zu verbinden.

Jürgen

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1650
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Event-Übergabe an C Sharp mittels DLL

Beitrag von fliegermichl »

Mein Beispiel war etwas unglücklich.

Die Idee war, daß die Routine in der DLL solange läuft, bis eine Abbruchbedingung eintritt.
In der Zwischenzeit sendet sie jedes empfangene Byte bzw. Char an die Callback Routine.

jlazarus
Beiträge: 10
Registriert: Mi 3. Apr 2024, 10:52

Re: Event-Übergabe an C Sharp mittels DLL

Beitrag von jlazarus »

theo hat geschrieben: Do 4. Apr 2024, 10:47 Willst du nicht lieber Synapse Synaser verwenden?
https://wiki.freepascal.org/Hardware_Ac ... munication
http://synapse.ararat.cz/doc/help/synas ... erial.html

Soweit ich sehe, ist SdpoSerial GUI-/Ereignisorientiert und das passt für eine DLL sowieso nicht.
Ich sehe im ReadMe von SdpoSerial folgendes:
"TSdpoSerial allows asynchronous communication using a serial port based on Synaser. Works in Linux and Windows."

Letztendlich ist es so, dass oComPort.SynSer.RecvString(50) fortlaufend StringPakete bis zum Timout 50 empfängt.
Und diese Pakete möchte ich fortlaufend ausgeben und in C# empfangen.

Mit einem Paket klappt es ja, aber fortlaufend eben nicht.
Aus meiner Sicht macht das reine Synaser auch nichts anderes.

Benutzeravatar
theo
Beiträge: 10921
Registriert: Mo 11. Sep 2006, 19:01

Re: Event-Übergabe an C Sharp mittels DLL

Beitrag von theo »

jlazarus hat geschrieben: Fr 5. Apr 2024, 10:37 Ich sehe im ReadMe von SdpoSerial folgendes:
"TSdpoSerial allows asynchronous communication using a serial port based on Synaser. Works in Linux and Windows."
Genau. Und deshalb sollte es mit Synaser alleine auch gehen, ohne die für eine DLL unnötigen bis störenden GUI Abhängigkeiten.
jlazarus hat geschrieben: Fr 5. Apr 2024, 10:37 Letztendlich ist es so, dass oComPort.SynSer.RecvString(50) fortlaufend StringPakete bis zum Timout 50 empfängt.
Das funktioniert nicht so, kann man in der Synaser Doku nachlesen. Der wartet im Prinzip "timeout" lang auf ein CRLF und gibt dann den String davor zurück.
http://synapse.ararat.cz/doc/help/synas ... Recvstring

Du musst sowieso in einen Loop gehen.
https://wiki.freepascal.org/Hardware_Access#Synaser

Aber ganz ehrlich, ich würde versuchen das in C# zu lösen, wenn du das schon verwenden willst. Das ist doch Krampf, dafür extra eine DLL zu basteln.

schoschy
Beiträge: 56
Registriert: Di 18. Okt 2022, 15:46

Re: Event-Übergabe an C Sharp mittels DLL

Beitrag von schoschy »

Ich arbeite bei Seriellen Port gerne mit Synaser

zu beachten ist die Art der Verbindung - Nur Rx, Tx und Gnd, oder auch Steuersignale:

Code: Alles auswählen

SerPort: TBlockSerial;
---  //spontan 
SerPort.CTS
SerPort.DSR
SerPort.RING
SerPort.CARRIER
abholen der Bytes
der LastError ändert sich, wenn kein byte in buffer ist.

Code: Alles auswählen

 if SerPort.WaitingData > 0 then
  begin
      ByteReceived(SerPort.RecvByte(0));
      while SerPort.LastError = 0 do
        ByteReceived(SerPort.RecvByte(0));
  end; 
 
Ich arbeite mit Bytes, und werf alles in ein TBytes, was ich benötige.
Wenn dann das abschließende kommt, kann das TBytes in einen String umbegoben werden.
Bsp:

Code: Alles auswählen

TEncoding.Ansi.GetAnsiString(RxBytes)
kannst auch den Char aus den Bytes direkt machen und an einen string anhängen, gibt viele möglichkeiten, ist nur wichtig, dass in ByteReceived Byte für Byte eingeworfen wird, bis der Buffer leer ist, oder ein anderer Error auf TBlockSerial aufkommt. Daher sind die Steuerzeichen der spec für dich das ausschlaggebende, zum übergeben und anschließendem leeren des Buffers.

Das ist eine kleine Hilfestellung aus dem grauen heraus.
Ich kann dir sagen, dass es in C# genauso funktioniert, da kenne ich aber keine Components, oder ähnliches.

jlazarus
Beiträge: 10
Registriert: Mi 3. Apr 2024, 10:52

Re: Event-Übergabe an C Sharp mittels DLL

Beitrag von jlazarus »

Ich komme momentan nur sporadisch mal zum Thema zurück,
aber eine Frage drängt sich mir auf.

Ist es nicht eigentlich egal, ob ich einen kompletten String einsammle oder die Bytes nachträglich zusammensetzte.
Das war doch nicht mein Ursprungsproblem.

Mir geht es darum, auf diese Ereignisse über die DLL in C# zu reagieren.
In C# habe ich bisher keine Komponente gefunden, die das gleiche Ergebnis der Schnittstellendaten zurück gibt.
In Synaser, oder eben SdpoSerial kann ich besser konfigurieren und es kommt ein jahrelang erprobtes Ergebnis raus.

Alle Komponenten und Versuche, die ich mit C# bisher unternommen habe, schaffen das nicht.
Deshalb hatte ich die Idee, Lazarus zu nutzen und eine eigene DLL zu bauen.
Ich hoffe immernoch, die Ereignisse durch die DLL schleusen zu können.
Aber wie Anfangs geschrieben, ich bin Hobby-Programmierer und vielleicht wünsche ich mir da was, was nicht machbar ist.
Ein Dankeschön schon mal an Alle, die mir hier helfen wollen und schon geholfen haben.

Jürgen

schoschy
Beiträge: 56
Registriert: Di 18. Okt 2022, 15:46

Re: Event-Übergabe an C Sharp mittels DLL

Beitrag von schoschy »

Auf google gibt man irgend etwas mit serial, port ,class und c# ein (oder alle auf einmal) und hat direkt 4 treffer von MS selbst.
Beispiel ist plausibel, oder die Vervollständigung von MS einfach mal auf das Objekt werfen und schauen was IS dir sonst so bietet.

Edit: es geht also mit MS, hab hier auch kurz eine solution aufgemacht, Beispiel macht was es vorgibt.

Antworten