Autor Beitrag
Peter18
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Fr 08.05.15 19:37 
Ein freundliches Hallo an alle,

wieder gibt es ein Problem mit LineCallBack. Ich bin nun dabei die Tapi in einem Objekt zu verpacken. Dabei tritt folgendes problem auf:
Die Reotine "LineCallBack" ist folgendermaßen deklariert:
ausblenden Delphi-Quelltext
1:
procedure LineCallBack( hDev, Msg, Cbi, P1, P2, P3 : DWord );  stdcall;					

Wenn ich "stdcall;" weglasse meckert er Aufrufkonventionen an.

ausblenden Delphi-Quelltext
1:
  R  := lineInitialize( @oLuh, HInstance, LineCallBack, PChar( 'Test' ), DC );					

So wird sie übergeben.

ausblenden Delphi-Quelltext
1:
  T_Tapi.SendCallInfo( A, E );					

Wird angemeckert.

Wie kann ich aber eine Ereignisroutine, die dem Objekt übergeben wurde aufrufen, um Informationen weiter zu geben?? Alle Versuche waren erfolglos. Hab da anscheinend noch ein Verständnisproblem, irgend wo ist vielleicht ein prinzipieller Fehler.

Grüße von der etwas sonnigen 16° warmen Nordsee

Peter
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: So 10.05.15 16:31 
So richtig verstanden habe ich es nicht, daher frage ich lieber einmal nach. der Prototyp der Callback-Routine ist als
ausblenden Delphi-Quelltext
1:
procedure LineCallBack( hDev, Msg, Cbi, P1, P2, P3 : DWord );  stdcall;					

deklariert, richtig? Und Du willst nun diesem Callback-Zeiger eine Methode einer Klasse übergeben?
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: So 10.05.15 17:53 
Hallo WasWeißDennIch,

Dank für die Antwort. Ich wolte das Ganze morgen etwas genauer formulieren. Heute nur die Kurzform, bin gleich außer Haus.

Das Problem ist nicht die TAPI an sich sondern, Pascal und die Konventionen. Das Ganze habe ich in Form1 als Testumgebung in Betrieb gehabt. Nun aber will ich die Schnittstelle in einem Objekt (TObject) verpacken. "LineCallBack" wird an die Tapi übergeben und von dort aufgerufen, wenn etwas zu berichten ist. Genau dann möchte ich, je nach Meldung, eine eigene Ereignisroutine aufrufen, die dem Objekt übergeben wurde.

Das Problem ist nun, entweder wird "LineCallBack" angemeckert oder ich komme nicht an die Ereignisroutinen heran. Ich habe verschiedene Varianten ausprobiert, aber nichts hat funktioniert. Mit Systemaufrufen komme ich ja inzwieschen einigermaßen zurecht, aber hier fehlt mir anscheinend noch das Verständnis der Zusammenhänge.

Falls das für einen Tipp reich wär es schön, sonst werde ich morgen Vormittag eine Beschreibung meiner Versuche und dei Fehlermeldungen liefern.

Grüße von der sonnigen Nordsee

Peter
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 10.05.15 18:22 
Kurze Antwort: Ohne Tricks gar nicht.

Lange Antwort:
Ein solcher Methodenzeiger besteht aus zwei Teilen, einem Code und einem Datenteil. Der Codeteil enthält die Sprungadresse, an der der Code der Methode zu finden ist. Dazu kommt, anders als bei einfachen Funktionen, noch der Datenteil, in dem der Zeiger auf das Objekt enthalten ist.
Der Code für die Methode ist für jedes Objekt im Speicher gleich, aber durch diese zusätzliche Information kann auf das konkrete Objekt zugegriffen werden.

Man muss also dafür sorgen, dass diese Information vorhanden ist, wenn aus der API der Callback aufgerufen wird.

Was ich in so einem Fall gemacht habe (und was Delphi auch intern macht) ist Speicher zu reservieren und dort die Objektreferenz zu hinterlegen und zusätzlich Code, der bei einem Rücksprung an diese Adresse den Datenzeiger benutzt um einen Methodenaufruf aus dem Callbackaufruf zu machen.

Wie ich dann herausgefunden habe als ich es so implementieren wollte, bietet Delphi dafür schon eine fertige Implementierung in Form von MakeObjectInstance an.
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Mo 11.05.15 11:22 
Hallo jaenicke,

Dank für die Antwort. Aber so ganz klar ist mir noch nicht was zu tun ist. Vielleicht liegt das daran, dass ich mich im Moment im Kreis drehe und kein Peilung hab.

In der Tapi.pas steht:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
type
...
...
// Änderung für Komponentenerstellung Allgemeine Callback Function

    TTAPICallback = procedure(hDevice, dwMessage: DWORD; dwInstance, dwParam1,
    dwParam2, dwParam3: DWORD_PTR) stdcall;
//  +++++++++++++++ !! +++++++++++++++++++++++++++++++++++++++++++++
  {TLineCallback = procedure(hDevice, dwMessage: DWORD; dwInstance, dwParam1,
    dwParam2, dwParam3: DWORD_PTR) stdcall;}

  TLineCallback = TTAPICallback;
  LINECALLBACK = TLineCallback;
  {$EXTERNALSYM LINECALLBACK}

Alle Versuche damit etwas anzufangen sind gescheitert. Entwerder wurde der Pointer auf "LineCallback" nicht akzeptiert oder es traten andere Fehler auf.

Doch wie muß ich diese Routine in meinem Objekt deklarieren, damit ich den Pointer darauf eintragen kann und an die Ereignisroutinen des Objektes heran komme? "MakeObjectInstance" ist in Delphi4 vorhanden. Warscheinlich denke ich im Moment noch zu sehr um die Ecke und dabei ist es vielleicht ganz einfach. Kannst Du mir ein kurzes Beispiel geben? Zumindest läst deine Antwort hoffen, dass es ohne Assembler zu lösen ist.

Grüße von der wolkigen und manchmal sonnigen Nordsee

Peter
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 11.05.15 11:32 
Das Beispiel habe ich doch verlinkt. Du übergibst die Methode einfach nicht direkt, sondern übergibst diese an MakeObjectInstance und bekommst davon den Pointer zurück, den du übergeben kannst.
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Mo 11.05.15 11:49 
Hallo jaenicke,

nochmals Dank für die schnelle Antwort.

Sorry, aber ich bin durch die Experementiererei im Moment etwas vernagelt. Ich habe es mir angesehen, aber habe ein Problem das richtig umzusetzen.

ausblenden Delphi-Quelltext
1:
2:
3:
procedure LineCallBack( hDev, Msg, Cbi, P1, P2, P3 : DWord );  stdcall;
...
PLineCallBack := MakeObjectInstance(LineCallBack);

Ist das so zu sehen? Oder
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure T_Tapi.LineCallBack( hDev, Msg, Cbi, P1, P2, P3 : DWord );  stdcall;
begin
...
  PStatus := MakeObjectInstance( oStatus );
  PStatus( S );
...


Grüße von der Nordsee

Peter
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 11.05.15 12:44 
ausblenden Delphi-Quelltext
1:
  R  := lineInitialize(@oLuh, HInstance, MakeObjectInstance(LineCallBack), PChar('Test'), DC);					
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Mo 11.05.15 13:16 
Hallo jaenicke,

Dank Dir. Die Probleme bleiben mir treu.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
private
...
    procedure LineCallBack( hDev, Msg, Cbi, P1, P2, P3 : DWord );

...
  R  := lineInitialize( @oLuh, HInstance, MakeObjectInstance(LineCallBack), PChar( 'Test' ), DC );

wird mit "Liste der Parameter ist unterschiedlich" quittiert. Und
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
private
...
    procedure LineCallBack( hDev, Msg, Cbi, P1, P2, P3 : DWord );   stdcall;

...
  R  := lineInitialize( @oLuh, HInstance, MakeObjectInstance(LineCallBack), PChar( 'Test' ), DC );

mit "unterschiedlichen Aufrufkonventionen"

Grüße von der Nordsee

Peter
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 11.05.15 20:48 
Ok, die vordefinierte Methode MakeObjectInstance funktioniert nur mit einem Callback vom Typ TWndMethod.
Du wirst diese also selbst für deinen Zweck implementieren müssen.
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Di 12.05.15 12:03 
Hallo jaenicke,

Dank für Deine Antwort. Ich habe allerdings keine Idee, wie das realisiert werden kann. Denn die Parameter sind sehr unterschiedlich:
ausblenden Delphi-Quelltext
1:
procedure LineCallBack( hDev, Msg, Cbi, P1, P2, P3 : DWord );					

und:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
type 
  TMessage = record

    Msg: Cardinal;
    case Integer of
      0: (
        WParam: Longint;
        LParam: Longint;
        Result: Longint);
      1: (
        WParamLo: Word;
        WParamHi: Word;
        LParamLo: Word;
        LParamHi: Word;
        ResultLo: Word;
        ResultHi: Word);

  end;


Aber ich hatte eine andere Idee. Sie wird zumindest compiliert. Ob sie auch funktioniert weiß ich noch nicht. Die Routine
ausblenden Delphi-Quelltext
1:
procedure WriteOnCall ( OC : T_Anruf );					

schreibt die Ereignisroutine in eine Globale Variable, die dann von "LineCallBack" verwendet wird.

Grüße von der noch bedeckten Nordsee

Peter
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Di 12.05.15 14:19 
Ein freundliches Hallo an alle,

Eine ganz einfache Lösung! Aus irgend einem Grund kann die "LineCallBack" nicht auf das Objekt zugreifen, auch wenn es benannt wird, was aber an anderen Stellen, wie einem Formular, möglich ist. Wird die Routine aber einer globalen Variablen zugewiesen, klappt das Ganze!

Grüße von der noch immer bedeckten Nordsee

Peter
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 12.05.15 14:42 
Wenn du aber mehrere Objekte hast, wird das so nicht mehr funktionieren.

Und wenn du ohnehin nicht mehrere Objekte hast, brauchst du auch keine Methode eines Objekts als Callback, sondern kannst das aktuelle Objekt einfach in der Unit unterhalb von implementation in einer Variable ablegen. Diese kannst du dann im Callback nutzen.
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Mi 13.05.15 11:36 
Hallo jaenicke,

ich verstehe Deine Antwort nicht so ganz!

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Wenn du aber mehrere Objekte hast, wird das so nicht mehr funktionieren.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
implementation

var
  iOnCall   : T_Anruf   ;       // Benachrichtigung bei Anruf
  iOnStatus : T_Status  ;       // Statusmeldungen
  iDebug    : Boolean   ;       // Debug-Flag
  iOnDebug  : T_DebugMsg;       // Debug-Message

Habe ich jetzt definiert. Wenn ich nun "T_Tapi = class(TObject)" mehrfach erzeuge, geht es nicht mehr? Heißt das die globalen Variablen enes Objektes werden nicht neu angelegt?

Grüße von der sonnigen Nordsee

Peter
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 13.05.15 13:02 
Die Variablen, die du gepostet hast, gehören ja nicht zu einem Objekt, sondern sind global.
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Mi 13.05.15 17:56 
Klar, aber das war nicht meine Frage!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 13.05.15 18:06 
Wenn du diese neu zuweist, dann passen die auch zu dem entsprechenden Objekt, aber eben auch nur zu diesem einen. Sprich ein zweites parallel erstelltes Objekt kann diese nicht ebenfalls nutzen.

Vielleicht habe ich dich aber auch nicht verstanden. :gruebel:
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Mi 13.05.15 18:30 
Hallo jaenicke,

wenn ich das richtig verstehe gehören die globalen Variablen zu einem Objekt. Wenn ich das Objekt noch einmal erzeuge, erhält das neue Objekt andere globale Variablen. Das wäre auch das, was ich erwartet habe.

Grüße von der Nordsee

Peter
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 13.05.15 18:47 
Nein, globale Variablen gibt es nur einmal. Zu einem Objekt gehört nur was in der Klasse unter private usw. deklariert ist.