Autor |
Beitrag |
Borsty
Hält's aus hier
Beiträge: 3
|
Verfasst: Sa 06.09.08 16:38
Moinsen, ich hätte da ma 'n Problem ^^
Ich schreib zZ an einem Progrämmchen zum überwachen und steuern von Gameservern auf Source-Engine Basis (HL2,CSS,etc)
(Durch Zufall) bin ich dann vor kurzem auf eine Bibliothek direkt von Valve (von denen ist HL2 usw ^^) gestoßen um die dedizierten Server direkt anzusprechen. Geliefert wird eine .dll inkl. Hifle und Header datei für C/C++. ( Link)
Eigentlich sollte es ja kein Problem sein das ganze für Delphi verwendbar zu machen, allerdings bin ich da auf was gestoßen womit ich (noch) nichts anfangen kann
Folgendes:
Quelltext 1:
| typedef(WINAPI* SSQ_CALLBACK)(DWORD type,PSSQ_REPLY_UNION reply); |
"SSQ_CALLBACK" ist ein "typedef union":
Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| typedef union { PSSQ_BATCH_REPLY batch_reply; char* log_reply; PSSQ_RULES_REPLY rules_reply; char* rcon_reply; BOOL log_notify; } SSQ_REPLY_UNION, *PSSQ_REPLY_UNION; |
"SSQ_CALLBACK" wird auch später in einer Funktion als Parameter erwartet.
Im Anhang mal der gesamte header und mein bisheriger Versuch für Delphi (Der soweit auch funktioniert, nur halt alles was im zusammenhang mit diesem SSQ_CALLBACK ist funktioniert nicht :/).
Einloggen, um Attachments anzusehen!
|
|
Borsty 
Hält's aus hier
Beiträge: 3
|
Verfasst: Mo 08.09.08 14:23
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mo 08.09.08 19:04
Kannst Du bitte mal schauen, ob Du die Offsets der einzelnen Felder in C (und das Sizeof des Datentyps) rausbekommst? Daraus sollte sich das ganze Rekonstruieren lassen ...
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
tommie-lie
      
Beiträge: 4373
Ubuntu 7.10 "Gutsy Gibbon"
|
Verfasst: Di 09.09.08 12:04
Hm, sehe ich den Wald aufgrund von Übermüdung vor lauter Bäumen nicht, oder ist Quelltext 1:
| typedef(WINAPI* SSQ_CALLBACK)(DWORD type,PSSQ_REPLY_UNION reply); | nicht vielmehr eine (Art) Deklaration eines Funktionszeigertyps als eines unions? Dann wäre die Pascal-Version davon mit meinen eingerosteten Delphi-Kenntnissen vermutlich sowas wie
Delphi-Quelltext 1:
| type SSQ_CALLBACK: function(DWORD type; PSSQ_REPLY_UNION reply): ??? | Den Rückgabetyp der Funktion kann ich gerade nicht bestimmen, normalerweise kenne ich WINAPI als __stdcall, hier scheint da entweder noch ein Typ mit reindefiniert worden zu sein, oder das ist kein valides C++. Je nach Belegung von WINAPI und Standardkonformität des ursprünglichen Compilers tut's dann auch ein procedure.
_________________ Your computer is designed to become slower and more unreliable over time, so you have to upgrade. But if you'd like some false hope, I can tell you how to defragment your disk. - Dilbert
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Di 09.09.08 12:39
tommie-lie hat folgendes geschrieben: | Hm, sehe ich den Wald aufgrund von Übermüdung vor lauter Bäumen nicht, oder ist Quelltext 1:
| typedef(WINAPI* SSQ_CALLBACK)(DWORD type,PSSQ_REPLY_UNION reply); | nicht vielmehr eine (Art) Deklaration eines Funktionszeigertyps als eines unions? Dann wäre die Pascal-Version davon mit meinen eingerosteten Delphi-Kenntnissen vermutlich sowas wie
Delphi-Quelltext 1:
| type SSQ_CALLBACK: function(DWORD type; PSSQ_REPLY_UNION reply): ??? | Den Rückgabetyp der Funktion kann ich gerade nicht bestimmen, normalerweise kenne ich WINAPI als __stdcall, hier scheint da entweder noch ein Typ mit reindefiniert worden zu sein, oder das ist kein valides C++. |
Ich kann dich schon mal beruhigen ... das ist valides C++
tommie-lie hat folgendes geschrieben: | Je nach Belegung von WINAPI und Standardkonformität des ursprünglichen Compilers tut's dann auch ein procedure. |
Jain ... Wenn dich der Rückgabewert nicht interessiert schon, sobald da aber was anderes als void für den Typ steht, IST es bei korrekter Übersetzung eine Function.
Übersetzen wir mal per Hand:
C#-Quelltext 1:
| typedef(WINAPI* SSQ_CALLBACK)(DWORD type,PSSQ_REPLY_UNION reply); |
typedef --> type
Erste Klammer:
WINAPI --> stdcall
* SSQ_CALLBACK --> Funktionszeiger, Typname SSQ_CALLBACK
Parameter:
DWORD type --> _type: DWORD;
PSSQ_REPLY_UNION reply --> reply: PSSQ_REPLY_UNION;
Setzt man das also zusammen:
Delphi-Quelltext 1:
| type SSQ_CALLBACK: procedure(_type: DWORD; reply: PSSQ_REPLY_UNION); stdcall; |
Bzgl. der Union mal die genannten Werte ermittelt?
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
tommie-lie
      
Beiträge: 4373
Ubuntu 7.10 "Gutsy Gibbon"
|
Verfasst: Di 09.09.08 13:12
BenBE hat folgendes geschrieben: | Ich kann dich schon mal beruhigen ... das ist valides C++  |
Hrmpf *patsch*
Nein, isses nicht, aber es ist valides ISO-C99. In C++ kannst du keine Funktionen ohne Rückgabetyp deklarieren (Ausnahmen siehe unten). In C ist es implizit int. War mir auch neu, aber ich habe nie viel mit ISO/ANSI-C gemacht, daß ich da so fit für solche Feinheiten bin. Das erklärt allerdings, warum einige Hempels in C++ main(void)(sic!) schreiben...
Aber C++ isses trotzdem nich
BenBE hat folgendes geschrieben: | tommie-lie hat folgendes geschrieben: | Je nach Belegung von WINAPI und Standardkonformität des ursprünglichen Compilers tut's dann auch ein procedure. |
Jain ... Wenn dich der Rückgabewert nicht interessiert schon, sobald da aber was anderes als void für den Typ steht, IST es bei korrekter Übersetzung eine Function. |
Ja, das weiß ich. Deswegen schrob ich "je nach Belegung von WINAPI". Enthält WINAPI keinen Typ, so ist es invalides C++ (oder aber valides C, siehe oben), steht da void, ist es eine procedure, steht da int oder sonstwas, ist es eine function.
Bei gängigen Belegungen von WINAPI ist der Code nur valid, wenn es C-Code sein soll, also ist es automatisch int, also ist es eine function SSQ_CALLBACK(...): Integer; (mit Vorsicht zu genießen, int ist garantiert mindestens 16 bit groß, normalerweise 32, auf IA64 64bit (auf x86-64 lustigerweise nicht/nicht immer), das mit den Delphi-Typen, die feste Größen vorschreiben, zu übersetzen, kann nach Hinten losgehen.)
<advocacy>
ISO-C++ Standard, 7.0.1 hat folgendes geschrieben: | Only in function declarations for constructors, destructors, and type conversions can the decl-specifier-seq be omitted.7 |
Die Fußnote auf selbiger Seite hat folgendes geschrieben: | The “implicit int” rule of C is no longer supported. |
</advocacy>
_________________ Your computer is designed to become slower and more unreliable over time, so you have to upgrade. But if you'd like some false hope, I can tell you how to defragment your disk. - Dilbert
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Di 09.09.08 13:31
Man brauch (wenn man den Rückgabewert nicht benötigt) in seiner Delphi-Übersetzung diesen nicht beachten. Das Ergebnis wird bei stdcall nämlich in EAX zurückgegeben, wo Delphi von Haus aus davon ausgeht, dass das nach einem Prozeduraufruf undefiniert ist...
Ansonsten geb ich tommie-lie Recht. (Wobei die ISOs hab ich auch nicht immer im Kopf).
@tommie-lie: Ansonsten die Übersetzung aber soweit korrekt?
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
tommie-lie
      
Beiträge: 4373
Ubuntu 7.10 "Gutsy Gibbon"
|
Verfasst: Di 09.09.08 14:23
BenBE hat folgendes geschrieben: | Ansonsten geb ich tommie-lie Recht. (Wobei die ISOs hab ich auch nicht immer im Kopf). |
Göttin bewahre, im Kopf habe ich die Zitate auch nicht, du hast mich verunsichert, deshalb habe ich nachgeschlagen
BenBE hat folgendes geschrieben: | @tommie-lie: Ansonsten die Übersetzung aber soweit korrekt? |
Ich hatte mir nur das aus der Frage angeschaut, aber beim Drüberschauen fällt folgendes auf:
Quelltext 1: 2: 3: 4:
| #define SSQ_GS_TIMEOUT 1<<0 #define SSQ_LOG_TIMEOUT 1<<1 #define SSQ_MS_TIMEOUT 1<<2 #define SSQ_RCON_TIMEOUT 1<<3 |
wird zu
Delphi-Quelltext 1: 2: 3: 4: 5:
| const SSQ_GS_TIMEOUT = 1; SSQ_LOG_TIMEOUT = 2; SSQ_MS_TIMEOUT = 4; SSQ_RCON_TIMEOUT = 8; | und nicht zu 0, 1, 2 und 3.
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| enum { SSQ_USA_EAST = 0, SSQ_USA_WEST, SSQ_SOUTH_AMERICA, SSQ_EUROPE, SSQ_ASIA, SSQ_AUSTRALIA, SSQ_MIDDLE_EAST, SSQ_AFRICA, SSQ_WORLD = 255 }; | Werte in enums, die nicht explizit festgelegt werden, haben immer einen um 1 erhöhten Wert als der vorher in der Liste stehende, also ist
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| SSQ_USA_EAST = 0; SSQ_USA_WEST = 1; SSQ_SOUTH_AMERICA = 3; SSQ_EUROPE = 7; SSQ_ASIA = 15; SSQ_AUSTRALIA = 31; SSQ_MIDDLE_EAST = 63; SSQ_AFRICA = 127; SSQ_WORLD = 255; | falsch, richtig wäre 0, 1, 2, 3, ..., 7, 255 hat. Das gleiche gilt für die anderen enums, die als Konstanten übersetzt wurden (warum eigentlich nicht als Delphi-enum übersetzen?).
Bei Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| SSQ_INFO_REPLY = record version: Char; hostname: Array[0..255] of Char; map: Array[0..31] of Char; game_directory: Array[0..31] of Char; game_description: Array[0..255] of Char; app_id: SmallInt; num_players: Char; max_players: Char; num_of_bots: Char; dedicated: Char; os: Char; password: Char; secure: Char; game_version: Array[0..31] of Char; end; | lassen sich die Typen für version, app_id, num_players, max_players und num_of_bots wohl besser durch einen ShortInt übersetzen. Anstatt arrays of Char sind ShortStrings ( hostname: String[256];) wahrscheinlich handlicher. Und für die restlichen Chars dürfte ein Byte oder ShortInt auch besser passen (eigentlich ByteBool, aber ich kenne die genaue Semantik dieses Typs in Delphi nicht mehr, möglicherweise entstehen unliebsame "-1 == True != True == 1"-Probleme).
Ähnliches gilt für die Records SSQ_PLAYER_ITEM und SSQ_PLAYER_REPLY. Weiterhin an allen Records das Schlüsselwort packed nicht vergessen. Die ganzen vars in den Funktionsdeklarationen haben da nichts zu suchen, im C-Header stehen da weder Pointer, noch nur in C++ existierende Referenzen, also nix var, sondern by-value!
Mehr fällt mir erstmal nicht auf.
_________________ Your computer is designed to become slower and more unreliable over time, so you have to upgrade. But if you'd like some false hope, I can tell you how to defragment your disk. - Dilbert
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Di 09.09.08 14:54
tommie-lie hat folgendes geschrieben: | Bei Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| SSQ_INFO_REPLY = record version: Char; hostname: Array[0..255] of Char; map: Array[0..31] of Char; game_directory: Array[0..31] of Char; game_description: Array[0..255] of Char; app_id: SmallInt; num_players: Char; max_players: Char; num_of_bots: Char; dedicated: Char; os: Char; password: Char; secure: Char; game_version: Array[0..31] of Char; end; | lassen sich die Typen für version, app_id, num_players, max_players und num_of_bots wohl besser durch einen ShortInt übersetzen. Anstatt arrays of Char sind ShortStrings (hostname: String[256];) wahrscheinlich handlicher. |
Aber falsch  Bei Shortstrings in Delphi ist das erste Byte die Längenangabe, diese ist in char-Arrays bei C nicht vorhanden. Daher ist die Übersetzung mit Array of char schon korrekt. Kann in Delphi genauso wie ein normaler String behandelt werden (bis auf einige kleine Ausnahmen).
tommie-lie hat folgendes geschrieben: | Und für die restlichen Chars dürfte ein Byte oder ShortInt auch besser passen (eigentlich ByteBool, aber ich kenne die genaue Semantik dieses Typs in Delphi nicht mehr, möglicherweise entstehen unliebsame "-1 == True != True == 1"-Probleme). |
Nur wenn man True = 1 ausgeht. Die Semantik in Delphi für ByteBool ist wie bei C: =0 --> false, !=0 --> True.
tommie-lie hat folgendes geschrieben: | Ähnliches gilt für die Records SSQ_PLAYER_ITEM und SSQ_PLAYER_REPLY. Weiterhin an allen Records das Schlüsselwort packed nicht vergessen. Die ganzen vars in den Funktionsdeklarationen haben da nichts zu suchen, im C-Header stehen da weder Pointer, noch nur in C++ existierende Referenzen, also nix var, sondern by-value! |
Maximal const darf ergänzt werden ...
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Borsty 
Hält's aus hier
Beiträge: 3
|
Verfasst: Mi 10.09.08 11:06
Hmm
Quelltext 1:
| typedef(WINAPI* SSQ_CALLBACK)(DWORD type,PSSQ_REPLY_UNION reply); |
Hab mir die Doku mal angeguckt und da gibts als Rückgabewert einen BOOL also von daher denk ich mal:
Delphi-Quelltext 1:
| SSQ_CALLBACK = function( typ: DWORD; reply: PSSQ_REPLY_UNION ):BOOL; StdCall; |
Bzgl. der union hatte ich noch kein Glück.
Das mit den enums ist mir im nachhinein auch aufgefallen, trotzdem danke ^^
'var' in den Funktionsdefinitionen wurden durch 'const' ersetzt.
|
|
|