Autor |
Beitrag |
Peter18
Beiträge: 489
Erhaltene Danke: 2
Delphi4
|
Verfasst: Mo 19.01.15 18:01
Ein freundliches Hallo an alle,
anscheinend habe ich bei den Pointern in Pascal irgend etwas noch nicht richtig verstanden. Experimente mit der CAPI liefern Ergebnisse, doch was ich sehe scheint nicht richtig zu sein. Die Funktion "CAPI_GET_MESSAGE" gibt einen Pointer auf die eigentliche Nachricht zurück. Im Kopfteil stehen Informationen wie Länge und Art der Nachricht. Vielleicht habe ich die Schnittstelle auch nicht richtig deklariert, so das der Pointer in die "Wüste" zeigt.
Die Deklaration der Schnittstelle:
Delphi-Quelltext 1: 2:
| Function CAPI_GET_MESSAGE ( D_AppID : Longint; Var lpCapiBuffer : Pointer ): DWord; stdcall; external 'Capi2032.dll'; |
Die Prozedur "CheckCall" wird von einem Timer gestartet:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| procedure TForm1.CheckCall( Sender: TObject ); var Buffer : Pointer; S : String;
begin Res := CAPI_GET_MESSAGE( AppID, Buffer );
S := ''; if Res = $01104 then S := ' Warteschlange leer'; if Res = $01102 then S := ' Command Error' ; if Res <> $01104 then NoMsg := false; if not NoMsg then begin Form1.Memo1.Lines.Add( 'CAPI_GET_MESSAGE' ); Form1.Memo1.Lines.Add( 'Res: ' + IntToHex( Res, 8 ) + S ); Form1.Memo1.Lines.Add( 'Buff: ' + IntToHex( Integer(Buffer), 8 ) ); Form1.Memo1.Lines.Add( '' ); if Res = $01104 then NoMsg := true; end; if Res = 0 then pLookAtMesssage( Buffer ); end; |
Die Prozedur "pLookAtMesssage" soll die Nachricht auswerten:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| procedure pLookAtMesssage( Buffer : Pointer ); var PBuffer : P_MessageHeader;
begin PBuffer := Buffer; Form1.Memo1.Lines.Add( 'Buffer:' ); Form1.Memo1.Lines.Add( 'Ptr: ' + IntToHex( Integer(Buffer), 8 ) ); Form1.Memo1.Lines.Add( 'Len: ' + IntToHex( PBuffer.Length, 8 ) ); Form1.Memo1.Lines.Add( 'AppId: ' + IntToHex( PBuffer.AppId, 8 ) ); Form1.Memo1.Lines.Add( 'Command: ' + IntToHex( PBuffer.Command, 8 ) ); Form1.Memo1.Lines.Add( 'Subcommand: ' + IntToHex( PBuffer.Subcommand, 8 ) ); Form1.Memo1.Lines.Add( 'MsgNr: ' + IntToHex( PBuffer.MsgNr, 8 ) ); Form1.Memo1.Lines.Add( '' ); end; |
Der Kopf ist folgendermaßen deklariert:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| Type MessageHeader = Record Length : DWord; AppId : DWord; Command : Byte ; Subcommand : Byte ; MsgNr : DWord; end;
Type P_MessageHeader = ^MessageHeader; |
"Subcommand" sollte einen Wert von $80 bis $83 haben,aber die Ergebnisse sehen so aus:
Zitat: | LISTEN_REQ
Res: 00000000
Msg: 00000000
CAPI_GET_MESSAGE
Res: 00000000
Buff: 0014E278
Buffer:
Ptr: 0014E278
Len: 0006000E
AppId: 00128105
Command: 00000001
Subcommand: 00000000
MsgNr: 00060000
CAPI_GET_MESSAGE
Res: 00001104 Warteschlange leer
Buff: 00000000
CAPI_GET_MESSAGE
Res: 00000000
Buff: 0014E278
Buffer:
Ptr: 0014E278
Len: 0006002F
AppId: 002B8202
Command: 00000001
Subcommand: 00000004
MsgNr: 80080001
CAPI_GET_MESSAGE
Res: 00001104 Warteschlange leer
Buff: 00000000
|
|
|
uall@ogc
Beiträge: 1826
Erhaltene Danke: 11
Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
|
Verfasst: Mo 19.01.15 22:49
Der Record wird wohl falsch sein, nimm mal einen "packed record".
Wenn lpCapiBuffer zurückgegeben wird, kannst du statt "var" besser "out" nehmen.
Ansonsten schau mal hier:
www.rueckerweb.net/isdncapi.html
kann auch sein dass TotalLength nur ein WORD (und kein DWORD ist), dann verschiebt sich alles und in deinem Beispiel ist die länge dann 0006, die AppId 002f002b und der Command 82.
Solltest da nochmal in den Spezifikationen nachschauen.
_________________ wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
|
|
Peter18
Beiträge: 489
Erhaltene Danke: 2
Delphi4
|
Verfasst: Di 20.01.15 16:09
Hallo Daniel,
danke für Deine Antwort! "packed record" scheint nicht notwendig zu sein, den beides funktioniert gleichermaßen, aber der Tipp mit "Word" statt "DWord" war gut. Da in der "CAPI-Beschreibung" nur Prozessorregister angegeben waren, habe ich anscheinend einen Fehler eingebaut. Nun sehe ich die richtigen Daten mit:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| Type MessageHeader = packed Record Length : Word; AppId : Word; Command : Byte; Subcommand : Byte; end; |
Der Link ist auch gut, den hab ich leider bei meiner Suche nicht gefunden. Wie die Rufnummer extrahiert wird scheint mir etwas umständlich, aber ich habe die Software noch nicht so weit studiert.
Meine Idee war einen Pointer mit dem Typen eines offenen Arrays auf die Nummer zu setzen und dann Byte für Byte zu lesen. Wenn er einem Pascal-String entspricht kann man ihn vielleicht direkt herauskopieren. Aber da ist wieder der "Pascal-Pointer" (C ist einfacher). Ich habe einen Typ mit offenen Array erstellt:
Delphi-Quelltext 1:
| Type Nr_Array = Array of Byte; |
Dann den Zeiger der darauf zeigt:
Delphi-Quelltext 1:
| Type P_Nr = ^Nr_Array; |
In der Procedure ist die Variable folgendermaßen deklariert:
Delphi-Quelltext
Wenn ich dann folgender maßen zugreife
Delphi-Quelltext 1: 2:
| PNr := @PConnectInd.CalledPartyNumber; S := IntToHex( PNr^[0], 2 ); |
erhalte ich einen Zugriffsfehler.
Ich hoffe auf einen Tipp, wo der Fehler liegt.
Grüße von der nebligen Nordsee (Ein Dichter liegt über dem Land)
Peter
|
|
WasWeißDennIch
Beiträge: 653
Erhaltene Danke: 160
|
Verfasst: Di 20.01.15 16:17
Für dynamische Arrays musst Du zunächst Speicher reservieren, das geht mit SetLength.
|
|
Peter18
Beiträge: 489
Erhaltene Danke: 2
Delphi4
|
Verfasst: Di 20.01.15 16:56
Hallo WasWeißDennIch,
auch Dir Dank für die Antwort! Aber auch da gibt es eine Zugriffsverletzung. Ich habe auch probiert den Pointer hoch zu zählen, Banane, Fehler. In der Hilfe steht zwar Addition auf Pointer ist möglich aber es gibt kein Beispiel, an dem ich mich orientieren könnte.
Grüße von der nebligen Nordsee
Peter
|
|
Peter18
Beiträge: 489
Erhaltene Danke: 2
Delphi4
|
Verfasst: Mi 21.01.15 17:15
Ein freundliches Hallo an alle,
schade keine weiteren Antworten, dann eine neue Pointerfrage und diese schließe ich ab. Der Teil funktioniert ja jetzt.
Grüße von der Nordsee
Peter
|
|
uall@ogc
Beiträge: 1826
Erhaltene Danke: 11
Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
|
Verfasst: Mi 21.01.15 21:26
Standardmäßig ist "packed record" und "record" nicht das gleiche, da ohne "packed" die Werte 4-Byte aligned werden.
Zum Testen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| type TTest = record B: Byte; c: DWord; end;
TTest2 = packed record B: Byte; c: DWord; end;
begin Caption := Format('%d %d', [SizeOf(TTest), SizeOf(TTest2)]); end; |
Es kann aber sein, dass du Code eingebunden hast, der das Alignment austellt, näheres findest du unter:
docs.embarcadero.com...alignfields_xml.html
Wobei "packed" = {$A1} entspricht und ohne Angabe ein {$A4} verwendet wird.
Wenn du also Structs von c++ uebersetzt bzw. von der WinAPI, nimm besser ein "packed record".
_________________ wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
|
|
SMO
Beiträge: 120
Erhaltene Danke: 18
D2005 Personal
|
Verfasst: Mo 16.02.15 18:50
Peter18 hat folgendes geschrieben : |
Die Prozedur "CheckCall" wird von einem Timer gestartet:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| procedure TForm1.CheckCall( Sender: TObject ); Form1.Memo1.Lines.Add( 'CAPI_GET_MESSAGE' ); if Res = 0 then pLookAtMesssage( Buffer ); end; | |
Da "CheckCall" eine Methode von Form1 ist, brauchst du Form1 nicht nochmal explizit anzugeben. Es wäre auch besser, in "pLookAtMesssage" nicht explizit auf Form1.Memo1 zuzugreifen. Denn das sind globale Abhängigkeiten, die man vermeiden möchte; außerdem müsstest du sämtliche Referenzen anpassen, falls du mal "Form1" oder "Memo1" umbenennst (und keine moderne Delphi-Version mit Refactoring hast, die die Bezeichner automatisch umbenennen kann). Etwas besser wäre also:
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:
| type PMessageHeader = ^TMessageHeader; TMessageHeader = packed record Length : Word; AppId : Word; Command : Byte; Subcommand : Byte; end;
procedure TForm1.CheckCall( Sender: TObject ); Memo1.Lines.Add( 'CAPI_GET_MESSAGE' ); if Res = 0 then pLookAtMesssage( Buffer; Memo1.Lines ); end;
procedure pLookAtMesssage( Buffer : PMessageHeader; InfoOutput: TStrings ); begin InfoOutput.Add( 'Buffer:' ); InfoOutput.Add( 'Ptr: ' + IntToHex( UIntPtr(Buffer), 8 ) ); InfoOutput.Add( 'Len: ' + IntToHex( Buffer.Length, 8 ) ); InfoOutput.Add( 'AppId: ' + IntToHex( Buffer.AppId, 8 ) ); InfoOutput.Add( 'Command: ' + IntToHex( Buffer.Command, 8 ) ); InfoOutput.Add( 'Subcommand: ' + IntToHex( Buffer.Subcommand, 8 ) ); InfoOutput.Add( 'MsgNr: ' + IntToHex( Buffer.MsgNr, 8 ) ); InfoOutput.Add( '' ); end; |
Den Sinn und Zweck von "packed" hat uall@ogc bereits erklärt.
Es fehlt noch der wichtige Unterschied zwischen Statischen und dynamischen Arrays.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| type Nr_Array = Array of Byte; P_Nr = ^Nr_Array;
var PNr : P_Nr; begin PNr := @PConnectInd.CalledPartyNumber; S := IntToHex( PNr^[0], 2 ); |
Natürlich klappt das so nicht! Dynamische Arrays, wie auch Strings, sind bereits implizite Pointer. Sie zeigen auf einen dynamisch allozierten Speicherbereich, der vor der Adresse, auf die gezeigt wird, noch Zusatzinfos wie Länge und Referenzcount enthält. An der Adresse von "PConnectInd.CalledPartyNumber" stehen diese Daten nicht, weil es sich eben nicht um einen Delphi-DynArray-Typ handelt. Man sollte also keine Pointer auf Strings und Dynamische Arrays casten, wenn man nicht genau weiß, was man macht.
Was du suchst, ist ein offenes statisches Array, oder einen Byte-Pointer.
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:
| var PNr : PByteArray; begin PNr := PByteArray(@PConnectInd.CalledPartyNumber); S := IntToHex( PNr[0], 2 );
type PNrArray = ^TNrArray; TNrArray = array [0..0] of Byte;
var PNr : PNrArray; begin PNr := PNrArray(@PConnectInd.CalledPartyNumber); S := IntToHex( PNr[0], 2 );
var PNr : PByte; begin PNr := PByte(@PConnectInd.CalledPartyNumber); S := IntToHex( PNr[0], 2 ); |
|
|
|