Autor Beitrag
Stephan.Woebbeking
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Di 27.07.10 12:09 
Hallo *,

ich hoffe ich habe die richtige Kategorie erwischt, war mir nicht ganz sicher.

Mein Problem: Ich möchte/muss ich einem Projekt Geräte erkennen (resp. Dienste finden), die sich im Rahmen des bei Apple frei verfügbaren Bonjour Protokolls (soweit mir bekannt eine Ausprägung von ZeroConfig plus Dienstedefinition / Erkennung) im Netzwerk "anbieten". Jetzt gibt es dazu eine dll und ich habe auch eine .h, die grundsätzlich den Zugriff darauf erlaubt.

Leider fehlt mir völlig die Erfahrung, wie ich vorgehen kann um diese Anbindung zu erreichen. Vielleicht könnt ihr mir ja erst mal grundsätzlich weiterhelfen:

  1. Macht es überhaupt Sinn, die .h Datei Stück für Stück in Delphi zu formulieren? Oder gibt es dann Hindernisse, die ein Schlagen dieser Brücke verhindern?
  2. Gibt es einen Leitfaden, wie man die Elemente am sinnvollsten übersetzen kann? Was mache ich aus "const char *", wie formuliere ich einen Zeiger auf eine Funktion?
  3. Hat das vielleicht schon mal jemand gemacht und ich kann da aufsetzen, fertigen Code / Anwendungsmodell bekommen / kaufen?
  4. Warum gibt es eigentlich keine Möglichkeit, eine solche .dll direkt zu importieren und Delphi macht das automatisch? Oder gibt es dass? Ich hab den Import mal probiert, er bringt aber ziemlich umfangreiche Fehlermeldungen und will mir klarmachen, dass das so einfach nicht geht...
  5. Ich häng hier mal die Headerdatei an, evt. kann mir ja jemand sagen, ob die Umsetzung eher einfach oder eher unmöglich ist?

Herzlichen Dank schon mal im Voraus!
Stephan
Einloggen, um Attachments anzusehen!
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Di 27.07.10 14:07 
1) kannst du komplett 1:1 übersetzen
2) Leitfaden nicht dass ich wüsste. Gibt einfach zu jedem C++ Konstrukt etwas halbwegs gleichwertiges in Delphi.
const char* geht z.B. mit nem Array of Byte (NICHT array of Char! maximal noch Array of AnsiChar)
Pointer auf eine funktion:
type TMyFunction=function(foo:bar):foobar;
var x:TMyFunction;
@x:=Pointer(...);
3) Es gibt Konverter...Meist muss man das bezahlen. für die eine H-Datei lohnt es sich nicht.
4) Du kannst die importieren. Ist doch kein Problem: LoadLibrary(Pfadname)
Nur das Verwenden: Du musst natürlich Delphi sagen: Ich hab da eine Funktion in der DLL sowieso und die sieht so aus
5) Eher einfach

Wenn du kleinere Probleme hast: Fragen
Ansonsten: Jobbörse, für n paar Euro macht dir das jemand (Oder schreibst mir gleich ne PN ;-) )
Stephan.Woebbeking Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Mi 28.07.10 10:37 
Danke erstmal für die Aussagen zur Machbarkeit. Also mache ich mich auf den längeren Weg; ich hätte gedacht ich kann nicht der erste sein, der das umsetzt.

Eine erste Unit hab ich mal angefangen zu formulieren... (C-Quellen noch als Kommentare enthalten) Soll noch nicht vollständig sein, ich will erstmal nur grundsätzlich klären, wie das mit der Schnittstelle zu bauen ist.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
unit UnitBonjourBridge;

interface

{typedef void (DNSSD_API *DNSServiceBrowseReply)
    (
    DNSServiceRef                       sdRef,
    DNSServiceFlags                     flags,
    uint32_t                            interfaceIndex,
    DNSServiceErrorType                 errorCode,
    const char                          *serviceName,
    const char                          *regtype,
    const char                          *replyDomain,
    void                                *context
    );

type TMyFunction=function(foo:bar):foobar;}


type TDNSServiceBrowseReply = procedure(
  sdRef               : Array of Byte;
  flags               : Longword;
  interfaceIndex      : Longword;
  errorCode           : Longint;
  serviceName         : Array of Byte;
  regtype             : Array of Byte;
  replyDomain         : Array of Byte;
  context             : &Byte
of object;

{DNSServiceErrorType DNSSD_API DNSServiceBrowse
    (
    DNSServiceRef                       *sdRef,
    DNSServiceFlags                     flags,
    uint32_t                            interfaceIndex,
    const char                          *regtype,
    const char                          *domain,    /* may be NULL */
    DNSServiceBrowseReply               callBack,
    void                                *context    /* may be NULL */
    );
Longint}

// Importieren der Funktion aus einer externen DLL

function DNSServiceBrowse(
  sdRef               : Array of Byte;
  flags               : Longword {unsigned 32bit};
  interfaceIndex      : Longword;
  regtype             : Array of Byte;
  domain              : Array of Byte;
  callBack            : TDNSServiceBrowseReply
): Longint {signed 32bit}cdeclexternal 'dnsapi.dll';

implementation

end.


Das das Dingen kompilierbar ist, ist ja schon mal ein erster Erfolg. ;) Aber: natürlich stürtzt er mit einer Zugriffsverletzung ab...

Aufgerufen habe ich das so:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
class procedure TFormStart.DNSServiceBrowseReply( sdRef: array of Byte; flags,
  interfaceIndex: Longword; errorCode: Integer; serviceName, regtype,
  replyDomain: array of Byte; context: Byte);
begin
  FormEnterIP.Show;
end;
procedure TFormStart.BtnFindDeviceClick(Sender: TObject);
var
  ret: Longint;
  sdRef, serviceName, regtype, domain: Array of Byte;
  flags, interfaceIndex: Longword;
begin
  SetLength( sdRef, 20 );
  SetLength( serviceName, 60 );
  SetLength( regtype, 20 );
  SetLength( domain, 60 );
  flags := 0;
  interfaceIndex := 0;
  ret := DNSServiceBrowse( sdRef, flags, interfaceIndex, regtype, domain, DNSServiceBrowseReply );
  ret := ret + 1;
end;


Aber: natürlich hab ich gleich erstmal bei beiden Methoden Breakpoints gesetzt, die werden gar nicht angefahren, d.h. ich habe bereits vorher ein Problem, vermutlich irgendwas beim laden der dll?
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Mi 28.07.10 11:12 
da sind auf jeden fall ein paar fehler drin:
- TDNSServiceBrowseReply darf nicht "of object" sein.
- void* = Pointer
- DNSServiceRef usw. solltest du der Übersichtlichkeit halber auch in Delphi erstellen
- in dem Fall klappt hier KEIN array of Byte sonder eher ein PByte. Hier wird mal ein Original-Beispielaufruf gebraucht. Kann sein, dass es auch ein PAnsiChar ist.
- in der DNSServiceBrowse hast du den context param vergessen

Außerdem zum suchen solcher Fehler: Debuggen bis zur Zeile wo der Fehler kommt. Wenn nötig mit F8 starten. Dann begginnt der ganz am Anfang
Stephan.Woebbeking Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Mi 28.07.10 12:00 
- TDNSServiceBrowseReply darf nicht "of object" sein. ok
- void* = Pointer ok
- DNSServiceRef usw. solltest du der Übersichtlichkeit halber auch in Delphi erstellen Würde ich machen, sobald ich's echt brauche oder wenn ich das Prinzip hinbekommen habe muss ich eh refakturieren
- in dem Fall klappt hier KEIN array of Byte sonder eher ein PByte. Hier wird mal ein Original-Beispielaufruf gebraucht. Kann sein, dass es auch ein PAnsiChar ist. s.u.
- in der DNSServiceBrowse hast du den context param vergessen ooops.... :lol:

Original-Beispielaufruf aus Standard C-Code eines Kollegen der in C programmiert und das auch schon verwendet. Leider hat er wenig Ahnung von Delphi, daher hilft das bei der Umsetzung nur wenig. Hab an mehreren Stellen gelesen, dass Unicode in der dll wohl Probleme bereiten soll...:
ausblenden Quelltext
1:
DNSServiceBrowse(&sdRef1, 0, 0, "_firma._udp", "local", DnsSrvBrowseCallback, NULL);					


---Moderiert von user profile iconNarses: Beiträge zusammengefasst---

Nachdem ich das of object bei der Funktionsdefinition entfernt habe, bekomme ich (wieder) einen Compilerfehler:
ausblenden Quelltext
1:
[DCC Error] FStart.pas(83): E2009 Incompatible types: 'regular procedure and method pointer'					


ausblenden Delphi-Quelltext
1:
2:
  func := DNSServiceBrowseReply;
  ret := DNSServiceBrowse( sdRef, flags, interfaceIndex, regtype, domain, func, NIL );



Hab schon alles hinsichtlich "Self." oder "@" ausprobiert, was mir geläufig ist und irgendwie Sinn machen würde, aber ich komm nicht auf die richtige Variante. Logisch scheint mir aus der Methode einen Zeiger zu machen, das will mir wohl auch die Fehlermeldung suggerieren, oder? Aber die beste Idee dafür wäre doch "@"... Da bekomme ich dann aber eine "Variable required" um die Ohren...
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Mi 28.07.10 12:26 
Also möglicherweise so:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
function DNSServiceBrowse(
  var sdRef               : DNSServiceRef;
  flags               : Longword {unsigned 32bit};
  interfaceIndex      : Longword;
  regtype             : PAnsiChar;
  domain              : PAnsiChar;
  callBack            : TDNSServiceBrowseReply;
  context        :Pointer
): Longint {signed 32bit}cdeclexternal 'dnsapi.dll';


das cdecl könnte auch ein stdcall sein. das merkst du, wenn dein programm nach dem aufruf abstürzt.
wegen dem Typ des 1. Params brauche ich etwas mehr zu dem &sdRef1. Wie wird er deklariert und wie initialisiert. Welcher Typ ist es im Original? (also was ist DNSServiceRef)
EDIT: Lt. der HeaderDatei ist es ein Pointer auf ein Record.

und wegen dem of object vermute ich, dass du DNSServiceBrowseReply nicht als Funktion sondern in einem Objekt (z.b. das Formular mittels TFStart.DNSServiceBrowseReply(...)) deklariert hast
Stephan.Woebbeking Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Mi 28.07.10 15:39 
Das of object hatte ich tatsächlich absichtlich in der Form definiert. Ich bin eher in der Java Welt zuhause, da ist für mich alles Teil eines Objektes. Naja, habe ich also doch eine Unit-Prozedur draus gemacht...

Pointer auf record, Yep, das sehe ich auch so. Ich wollte erstmal einen Aufruf ohne Absturz hinbekommen, dann ist das die Ecke wo ich weitermache. Wenn ich statt pointer of record ein leeres byte array übergebe, kann doch höchstens ein Fehler aus der dll heraus folgen? Dann wüsste ich zumindest schon mal, dass mein Ruf dort ankommt. ;)

stdcall vs. cdecl das ist allerdings eine Nuss... So oder so stürzt mein Programm mit der Zugriffsverletzung ab (siehe oben). Und zwar bevor der Breakpoint beim Aufruf erreicht wird. Also folgere ich, dass es etwas während des Aufbaus der Verbindung zwischen kompiliertem Programm und der dynamischen dll ist...? Wie gesagt, egal ob stdcall oder cdecl, ich bekomme eine Zugriffsverletzung beim "begin" vor "Application.Initialize;", wenn ich den Aufruf rausnehme geht soweit erstmal alles, der Breakpoint beim Aufruf wird aber so oder so nicht erreicht...
Stephan.Woebbeking Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Mi 20.10.10 18:19 
Hallo,

ich würde das Thema gern nochmal aufgreifen, weil ich zwischenzeitlich andere Dinge hatte, das eigentlich Problem aber doch noch lösen muss...

Ich hab sogar zwischenzeitlich was hinbekommen, was zumindest ohne Zugriffsverletzungen läuft:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
procedure TFormStart.BtnFindDeviceClick(Sender: TObject);
var
  ret: Longint;
  serviceName, regtype, domain: Array of Byte;
  flags, interfaceIndex: Longword;
  func: TDNSServiceBrowseReply;
  s: String;
  a, lMax: Integer;
  sdref: Pointer;
begin
  SetLength( regtype, 20 );
  SetLength( domain, 60 );
  // Copy RegType to the array
  lMax := Length( STR_REGTYPE );
  lMax := Min( lMax, Length( regType ) );
  for a := 0 to lMax do
    regType[ a ] := Byte( STR_REGTYPE[ a + 1 ] );
  // Copy Domain to the array
  lMax := Length( STR_DOMAIN );
  lMax := Min( lMax, Length( domain ) );
  for a := 0 to lMax do
    domain[ a ] := Byte( STR_DOMAIN[ a + 1 ] );
  flags := 0;
  interfaceIndex := 0;
  func := @DNSServiceBrowseReply;
  ret := DNSServiceBrowse( sdRef, flags, interfaceIndex, @regtype, @domain, func, NIL );
  if ( ret < 0 ) then
    Application.MessageBox( PChar( 'Bonjour error: ' + IntToStr( ret ) ), PChar( 'Error' ) );
end;


Die Funktion habe ich separat definiert:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
function DNSServiceBrowse(
  var sdRef           : Pointer;
  flags               : Longword {unsigned 32bit};
  interfaceIndex      : Longword;
  regtype             : PAnsiChar;
  domain              : PAnsiChar;
  callBack            : TDNSServiceBrowseReply;
  context             : Pointer
): Longint {signed 32bit}stdcallexternal 'dnssd.dll';


Nun bekomme ich von der dll tatsächlich was zurück. Der Wert ist als "kDNSServiceErr_BadParam" bezeichnet. Die Parameter habe ich natürlich zig Mal überprüft. Könnte es sein, dass bei der Übergabe Dinge noch nicht stimmen und deshalb die Parameter (von denen ich überzeugt bin, dass sie korrekt sind) falsch in der dll ankommen?

Danke,
Stephan
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Mi 20.10.10 19:42 
Hatten wir uns oben nicht auf PAnsiChar geeiningt? Warum verwendest du dann keinen AnsiString und machst daraus dann einen PAnsiChar?
@foo auf ein dyn. Array geht nicht. wenn dann @foo[0]
Stephan.Woebbeking Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Do 21.10.10 12:22 
Ok, ja, hast du recht. Ich hab die Argumente als ansistring definiert und dann noch ein PAnsiChar( x ) reingebracht. Daraufhin bekomme ich jetzt auch als Ergebnis die 0 zurück - also kein Fehler mehr! :-)

Nun kenne ich leider die interne Logik der dll nicht, d.h. ich weiß nicht wirklich, welche Aufrufe logisch in welcher Folge Sinn machen. Aber ok, da kann ich nur experimentieren bzw. abschauen. Dabei muss ich ja weitere Routinen einbinden, z.B. diese hier:

ausblenden Delphi-Quelltext
1:
int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef);					


Dabei ist ja DNSServiceRef im Prinzip nur ein Pointer (auf einen record) hatten wir festgestellt, korrekt? D.h. für den Aufruf oben müsste ich einfach den Pointer übergeben.

Vorher hatten wir diese Funktion:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
function DNSServiceBrowse(
  var sdRef           : DNSServiceRef;
  flags               : Longword {unsigned 32bit};
  interfaceIndex      : Longword;
  regtype             : PAnsiChar;
  domain              : PAnsiChar;
  callBack            : TDNSServiceBrowseReply;
  context        :Pointer
): Longint {signed 32bit}cdeclexternal 'dnsapi.dll';


Die rufe ich einfach mit

ausblenden Delphi-Quelltext
1:
  ret := DNSServiceBrowse( sdRef, flags, interfaceIndex, PAnsiChar( regtype ), PAnsiChar( domain ), func, NIL );					


auf und das klappt ja auch. Wenn ich die Funktion von oben so in Delphi definiere:

ausblenden Delphi-Quelltext
1:
function DNSServiceProcessResult( sdRef: DNSServiceRef ): DNSServiceErrorType; stdcallexternal 'dnssd.dll';					


und dann per

ausblenden Delphi-Quelltext
1:
      ret := DNSServiceProcessResult( sdRef );					


rufe, bekomme ich eine Zugriffsverletzung, Versuch an Adresse 2 (!) zu lesen. Mein Verständnis wäre auch, dass der Aufruf anders sein müsste, weil ich ja in den Funktionen einmal den Paramter "DNSServiceRef sdRef" und einmal "DNSServiceRef *sdRef" habe und das ist ja durchaus ein Unterschied. Oder wird das bereits komplett durch das "var" "verdaut"?
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Do 21.10.10 17:37 
Wie du die Funktionen verwendest, steht in der Doku dazu (nehme ich mal an...) oder in Bsp Sourcen.
Wie ist denn DNSServiceProcessResult original definiert (im C-Header)?
Stephan.Woebbeking Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Di 02.11.10 15:55 
Die Funktion ist so definiert:

ausblenden Delphi-Quelltext
1:
DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef);					


Das führt schnell noch zu diesen beiden Definitionen:

ausblenden Delphi-Quelltext
1:
2:
typedef struct _DNSServiceRef_t *DNSServiceRef;
typedef struct _DNSRecordRef_t *DNSRecordRef;


Und weil ja die andere Funktion mit dem sdRef Parameter etwas anders aussieht:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
DNSServiceErrorType DNSSD_API DNSServiceBrowse
  (
  DNSServiceRef                       *sdRef,
    DNSServiceFlags                     flags,
    uint32_t                            interfaceIndex,
    const char                          *regtype,
    const char                          *domain,    /* may be NULL */
    DNSServiceBrowseReply               callBack,
    void                                *context    /* may be NULL */
    );


Also, dort ist ja das DNSServiceRef nur eine Referenz. Aber DNSServiceRef ist doch sowieso schon eine Referenz, oder? Also ein Zeiger auf einen Zeiger, damit ich den umbiegen kann, das ist ja ok, aber alle Kombinationen, die ich bisher ausprobiert habe, führen zu der oben beschriebenen Zugriffsverletzung...? Ich komm nicht darauf, wie ich den Aufruf noch umstellen kann? Irgendeine Idee für mich?

Stephan
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Di 02.11.10 16:55 
DNSServiceRef Sollte ein Pointer auf das Record sein.
Dann sollte es auch genau so laufen, wie in deinem letzten Post (mit den Aufrufen und deklarationen)
Stephan.Woebbeking Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Di 02.11.10 18:03 
Hmmm, that's noooo good. Weil ich immer noch Zugriffsverletzungen bekommen, zwar nicht mehr an Adresse 2, aber doch sind sie absolut konsequent. Ich hab den Eindruck, das Problem liegt irgendwo im Bereich der Aufrufe:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
  func: TDNSServiceBrowseReply;
...
begin
  func := DNSServiceBrowseReply;
  ret := DNSServiceBrowse( sdRef, flags, interfaceIndex, PAnsiChar( regtype ), PAnsiChar( domain ), func, NIL );
...
  ret := DNSServiceRefSockFD( sdRef );
...
  ret := DNSServiceProcessResult( sdRef );


Der letzte Aufruf wirft die Exception. Kann natürlich gut sein, dass die Funktion intern jetzt die Callback procedure rufen sollte und dort etwas schief läuft, kann das sein?

Stephan
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Di 02.11.10 18:32 
Dann debug das ganze dochmal...
BP setzen und zur Not im Assembler-Code in die DLL reinsteppen bis du die Stelle findest...
Stephan.Woebbeking Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Do 18.11.10 18:19 
Hallo, ich mal wieder... :D

Bin ein Stückchen weiter... Jetzt habe ich hier die Callback Funktion, die ich als nächstes brauche:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
typedef void (DNSSD_API *DNSServiceBrowseReply)
    (
    DNSServiceRef                       sdRef,
    DNSServiceFlags                     flags,
    uint32_t                            interfaceIndex,
    DNSServiceErrorType                 errorCode,
    const char                          *serviceName,
    const char                          *regtype,
    const char                          *replyDomain,
    void                                *context
    );


Ich bin auf diese Pascal-Form gekommen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure DNSServiceBrowseReply(
  sdRef               : DNSServiceRef;
  flags               : Longword;
  interfaceIndex      : Longword;
  errorCode           : Longint;
  serviceName, regtype, replyDomain         : PAnsiChar;
  var context             : Pointer
);


Wenn ich das so tue und die Prozedur auch implementiere, bekomme ich über die Felder "servicename, regtype, replyDomain" keine Daten zurück. Hab mal probiert, wenn ich alles statt mit "PAnsiChar" mit "array of Byte" anlege kommen tatsächlich Daten, aber wäre das ok? Ich mein, wie ist's richtig? "var" hab ich auch schon versucht, da es aber ja nicht unbedingt veränderliche Daten sind, macht das m.E. wenig Sinn?

Viele Grüße,
Stephan
Flamefire
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1207
Erhaltene Danke: 31

Win 10
Delphi 2009 Pro, C++ (Visual Studio)
BeitragVerfasst: Di 23.11.10 16:22 
Versuch mal hinter alle Funktionen (auch Callbacks) die mit der DLL zu tun haben das schlüsselwort "cdecl" zu setzen. Das war mal bei mir ein Problem.
Bei deiner Callback wäre mind. ein "stdcall" von Nöten (aber ich vermute es ist cdecl)
Stephan.Woebbeking Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Mi 01.12.10 12:52 
Ja, in der Tat bin ich mittlerweile soweit, dass ich ein paar Daten (den ersten Datensatz) zurück bekomme. Aber leider bekomme ich dann, wenn die Pascal Prozedur verlassen wird (end;) eine Zugriffsverletzung, da kann ich so gar nichts mit anfangen...

Hier ist die Prozedur:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
procedure TFormStart.MnuFindIPClick(Sender: TObject);
var
  ret: DNSServiceErrorType;
  sdref: DNSServiceRef;
begin
  ret := DNSServiceBrowse( sdRef, 00, PAnsiChar( STR_REGTYPE), PAnsiChar( STR_DOMAIN), DNSServiceBrowseReply, NIL );
  if ( ret < 0 ) then
    Application.MessageBox( PChar( 'Bonjour error on Browsing: ' + IntToStr( ret ) ), PChar( 'Error' ) )
  else begin
    ret := DNSServiceRefSockFD( sdRef );
    if ( ret < 0 ) then
      Application.MessageBox( PChar( 'Bonjour error on retrieving browse result: ' + IntToStr( ret ) ), PChar( 'Error' ) )
    else begin
      DNSServiceProcessResult( sdRef );
    end;
  end;
  sleep( 300 );
  Application.ProcessMessages;
  DNSServiceRefDeallocate( sdRef );
end;


Ich denke aber mittlerweile, dass dies Problem schon die Logik der dll-Aufrufe direkt betrifft. Ich habe eine funktionierende C Applikation, aber wirklich weiterhelfen tut mir das auch nicht; wenn ich das so umsetzen will, schließt sich mein Programm bei bestimmten Aufrufen ohne weitere Rückmeldung... :-( Dabei hab ich den Eindruck, dass ich ziemlich kurz vor einer Lösung stehe...

Stephan
Stephan.Woebbeking Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Di 07.12.10 18:27 
Hoi,

nach viel Probererei stelle ich nun doch fest, dass es stdcall sein muss, sonst kassiere ich Exceptions / Abstürze. Also, falls jemand dies nochmal braucht, im Prinzip bekomme ich jetzt aus der dll die richtigen Informationen und kann auch noch etwas Sourcen spendieren.

Ein einziges Problem hab ich aber erst noch: Ich rufe die Funktion DNSServiceRefSockFD() auf und erhalte eine Socket Nr. Damit gehe ich in die Funktion DNSServiceProcessResult() und extrahiere die Daten des Service. Das Ganze mache ich iterativ erneut, wunderbar. Beim dritten Mal sind keine Daten mehr da und DNSServiceProcessResult() blockiert, mein Program reagiert nicht mehr... Ich bekomme keine Info darüber, wie lange / häufig ich die Iteration durchlaufen soll. Hab das auch schon bei Apple angefragt, ist natürlich eine Bonjour-spezifische Frage. Falls ich die Antwort dazu finde, werde ich das Extrakt hier posten. Falls bis dahin noch jemand 'ne Info dazu hat: Immer her damit! ;)

Stephan
Stephan.Woebbeking Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 97



BeitragVerfasst: Mi 16.02.11 11:07 
Mittlerweile läuft das Dingen. Wenn jemand daran geht und eine einfach, mit Sicherheit noch nicht ausgereifte aber funktionsfähige Idee / Vorlage braucht, kann er dies gern verwenden. Falls weitere Fragen sind, kann ich darauf auch gern eingehen, da aber die Entwicklung weitergeht würde ich das gern erst dann tun, wenn es akut wird, dann bin ich selbst bereits weiter und kann (hoffentlich) eine bessere Antwort geben, als das heute der Fall ist:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
procedure TFormStart.MnuFindIPClick(Sender: TObject);
var
  ret: DNSServiceErrorType;
begin
  if NOT( performBonjour.Get ) then begin
    Logging.Info( 'Do Bonjour browsing' );
    FormDeviceList.deviceList.Clear;
    processThread1 := TProcessThread1.Create( True );
    ret := DNSServiceBrowse( processThread1.sdRef1, 00, PAnsiChar( STR_REGTYPE ), PAnsiChar( STR_DOMAIN ), DNSServiceBrowseReply, NIL );
    processThread1.Resume;
    performBonjour.Start;
    lastSock := -1;
    if ( ret < 0 ) then
      Logging.Error( 'Bonjour / DNSServiceBrowse: ' + IntToStr( ret ) )
    else begin
      Logging.Info( 'Initiating Bonjour processing' );
    end;
    FormDeviceList.doWait := True;
    FormDeviceList.ShowModal;
    if ( FormDeviceList.ModalResult = mrOk ) then begin
      receiver.Disconnect;
      ParseIPAddress( receiver.ip, FormDeviceList.deviceList.addresses[ FormDeviceList.selected ] );
    end;
  end;
end;
procedure TProcessThread1.Execute;
var
  ret: DNSServiceErrorType;
begin
  while Assigned( sdRef1 ) AND NOT( terminate )do begin
    ret := DNSServiceRefSockFD( sdRef1 );
    Logging.Info( #13#10 + IntToStr( ret ) );
    if ( ret >= 0 ) then begin
      DNSServiceProcessResult( sdRef1 );
      Logging.Info( 'Found device ' + device + ' at ' + ip );
      FormDeviceList.deviceList.devices.Add( device );
      FormDeviceList.deviceList.services.Add( service );
      FormDeviceList.deviceList.addresses.Add( ip );
    end;
    if ( ret < 0 ) then
      Logging.Error( 'Bonjour / DNSServiceRefSockFD (DoPerformBonjourTick): ' + IntToStr( ret ) )
  end;
  DNSServiceRefDeallocate( sdRef1 );
end;
procedure TFormStart.DoPerformBonjourTick;
begin
end;
procedure DNSServiceBrowseReply(
  sdRef               : DNSServiceRef;
  flags               : Longword;
  interfaceIndex      : Longword;
  errorCode           : Longint;
  serviceName, regtype, replyDomain         : PAnsiChar;
  context             : Pointer );
var
  ret: DNSServiceErrorType;
  sdref2: DNSServiceRef;
begin
  Logging.Info( 'Bonjour service identified: ' + IntToStr( interfaceIndex ) + '# ' + String( serviceName ) + ' ' + String( regtype ) + ' ' + String( replyDomain ) );
  ret := DNSServiceResolve( sdRef2, flags, interfaceIndex, serviceName, regtype, replyDomain, DNSServiceResolveReply, context );
  if ( ret < 0 ) then
    Logging.Error( 'Bonjour / DNSServiceResolve: ' + IntToStr( ret ) )
  else begin
    ret := DNSServiceRefSockFD( sdRef2 );
    if ( ret < 0 ) then
      Logging.Error( 'Bonjour / DNSServiceRefSockFD (DNSServiceResolve): ' + IntToStr( ret ) )
    else begin
      DNSServiceProcessResult( sdRef2 );
    end;
  end;
  DNSServiceRefDeallocate( sdRef2 );
end;

procedure DNSServiceResolveReply(
  sdRef               : DNSServiceRef;
  flags               : DNSServiceFlags;
  interfaceIndex      : Longword;
  errorCode           : DNSServiceErrorType;
  fullname            : PAnsiChar;
  hosttarget          : PAnsiChar;
  port                : Word;
  txtLen              : Word;
  txtRecord           : PAnsiChar;
  context             : Pointer );
var
  sdRef3: DNSServiceRef;
  ret: DNSServiceErrorType;
begin
  Logging.Info( 'Bonjour service resolved: ' + IntToStr( interfaceIndex ) + '# ' + String( fullname ) + ' ' + String( hosttarget ) + ' ' + IntToStr( port ) );
  Logging.Info( 'Text record: ' + String( txtRecord ) );

  processThread1.device := fullname;
  processThread1.service := hosttarget;
  ret := DNSServiceQueryRecord( sdRef3, 00, hosttarget, kDNSServiceType_A, kDNSServiceClass_IN, DNSServiceQueryRecordReply, NIL );
  if ( ret < 0 ) then
    Logging.Error( 'Bonjour / DNSServiceQueryRecord: ' + IntToStr( ret ) )
  else begin
    ret := DNSServiceRefSockFD( sdRef3 );
    if ( ret < 0 ) then
      Logging.Error( 'Bonjour / DNSServiceRefSockFD (DNSServiceQueryRecord): ' + IntToStr( ret ) )
    else begin
      DNSServiceProcessResult( sdRef3 );
    end;
  end;
  DNSServiceRefDeallocate( sdRef3 );
end;

procedure DNSServiceQueryRecordReply(
  DNSServiceRef       : DNSServiceRef;
  flags               : DNSServiceFlags;
  interfaceIndex      : Longword;
  errorCode           : DNSServiceErrorType;
  fullname            : PAnsiChar;
  rrtype              : Word;
  rrclass             : Word;
  rdlen               : Word;
  rdata               : PAnsiChar;
  ttl                 : Longword;
  context             : Pointer );
var
  line: String;
begin
  Logging.Info( 'Bonjour query: ' + IntToStr( interfaceIndex ) + '# ' + String( fullname ) + ' ' + IntToStr( rrtype ) + ' ' + IntToStr( rrclass ) + ' ' + IntToStr( rdlen ) + ' ' + IntToStr( ttl ) + ' ' + String( rdata ) );
  line := String( rdata );
  processThread1.ip := IntToStr( Integer( line[ 1 ] ) ) + '.' + IntToStr( Integer( line[ 2 ] ) ) + '.' + IntToStr( Integer( line[ 3 ] ) ) + '.' + IntToStr( Integer( line[ 4 ] ) );
  Logging.Info( processThread1.ip );
end;