Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Type-Deklaration PF_INTERFACE_STATS (MSDN-PlattformSDK: RAS) (https://www.delphipraxis.net/48019-type-deklaration-pf_interface_stats-msdn-plattformsdk-ras.html)

x000x 19. Jun 2005 14:02


Type-Deklaration PF_INTERFACE_STATS (MSDN-PlattformSDK: RAS)
 
Hallo,

ich "spiele" etwas mit Packetfiltern (IPHLPAPI.DLL) herum und habe jetzt ein evtl. kleineres Problem.
Erstmal die Vorgeschichte:
Es gibt in der IPHLPAPI.DLL die function "PfGetInterfaceStatistics"
Delphi-Quellcode:
function  PfGetInterfaceStatistics(
           pInterface:      INTERFACE_HANDLE;
           ppfStats:        PPF_INTERFACE_STATS;
           pdwBufferSize:   PDWORD;
           fResetCounters:  BOOL): DWORD;
           stdcall; external IPHLPAPI name '_PfGetInterfaceStatistics@16';
die mir einen Zeiger auf ein Struktur "PF_INTERFACE_STATS" liefert. Laut MSDN ist diese so deklariert:
Delphi-Quellcode:
  ...
typedef struct _PF_INTERFACE_STATS {
  PVOID pvDriverContext;
  DWORD dwFlags;
  DWORD dwInDrops;
  DWORD dwOutDrops;
  PFFORWARD_ACTION eaInAction;
  PFFORWARD_ACTION eaOutAction;
  DWORD dwNumInFilters;
  DWORD dwNumOutFilters;
  DWORD dwFrag;
  DWORD dwSpoof;
  DWORD dwReserved1;
  DWORD dwReserved2;
  LARGE_INTEGER liSYN;
  LARGE_INTEGER liTotalLogged;
  DWORD dwLostLogEntries;
  PF_FILTER_STATS FilterInfo[1];
} PF_INTERFACE_STATS,
*PPF_INTERFACE_STATS;
  ...
Das ganze sollte in Delphi wohl so aussehen:
Delphi-Quellcode:
  ...
type
  _PF_FILTER_DESCRIPTOR  = packed record
     dwFilterFlags:      DWORD;
     dwRule:             DWORD;
     pfatType:           PFADDRESSTYPE;
     SrcAddr:            PByteArray;
     SrcMask:            PByteArray;
     DstAddr:            PByteArray;
     DstMask:            PByteArray;
     dwProtocol:         DWORD;
     fLateBound:         DWORD;
     wSrcPort:           Word;
     wDstPort:           Word;
     wSrcPortHighRange:  Word;
     wDstPortHighRange:  Word;
  end;
  PF_FILTER_DESCRIPTOR   = _PF_FILTER_DESCRIPTOR;
  PPF_FILTER_DESCRIPTOR  = ^PF_FILTER_DESCRIPTOR;

type
  _PF_FILTER_STATS       = packed record
     dwNumPacketsFiltered:DWORD;
     info:               PF_FILTER_DESCRIPTOR;
  end;
  PF_FILTER_STATS        = _PF_FILTER_STATS;
  PPF_FILTER_STATS       = ^PF_FILTER_STATS;

type
  _PF_INTERFACE_STATS    = packed record
     pvDriverContext:    Pointer;
     dwFlags:            DWORD;
     dwInDrops:          DWORD;
     dwOutDrops:         DWORD;
     eaInAction:         PFFORWARD_ACTION;
     eaOutAction:        PFFORWARD_ACTION;
     dwNumInFilters:     DWORD;
     dwNumOutFilters:    DWORD;
     dwFrag:             DWORD;
     dwSpoof:            DWORD;
     dwReserved1:        DWORD;
     dwReserved2:        DWORD;
     liSyn:              LARGE_INTEGER;
     liTotalLogged:      LARGE_INTEGER;
     dwLostLogEntries:   DWORD;
     // hier liegt mein Problem...
     FilterInfo:         Array[0..0] of PF_FILTER_STATS;
  end;
  PF_INTERFACE_STATS     = _PF_INTERFACE_STATS;
  PPF_INTERFACE_STATS    = ^PF_INTERFACE_STATS;
  ...
Die Funktion (PfGetInterfaceStatistics) ansicht tut auch das was sie soll, wenn ich z.B. die Anzahl der Output Filter
für ein Interface haben will, bekomme ich sie über:
Delphi-Quellcode:
...
var PStats : PPF_INTERFACE_STATS;
    ...
begin
    ...
    // Output Filter
    ShowMessage('dwNumOutFilter: ' + IntToStr(Stats^.dwNumOutFilters));
    // Hier liegt mein Problem
    ShowMessage('SrcPort: ' + IntToStr(Stats^.FilterInfo[0].info.wSrcPort));
end;
Der Code oben funktioniert, nur bekomme ich in FilterInfo nur die Infos über den ersten Filter, es sind aber mehrere
vorhanden!
Laut MSDN gibt es in Stats^.FilterInfo für jeden Filter ein Element. Wenn ich aber z.B. Stats^.FilterInfo[1].info.wSrcPort
abfrage, bekomme ich nur Müll. Ich vermute mal, dass es an der Deklaration des Typs liegt, denn wenn ich einfach
Delphi-Quellcode:
     ...
     dwLostLogEntries:   DWORD;
     // hier liegt mein Problem...
     // FilterInfo:         Array[0..0] of PF_FILTER_STATS;
     FilterInfo:         Array[0..15] of PF_FILTER_STATS;
  end;
  PF_INTERFACE_STATS     = _PF_INTERFACE_STATS;
  ...
definiere, stehen in Stats^.FilterInfo[1].*** die Informationen zum 2. Filter, in
.FilterInfo[2]
zum 3. usw.

Jetzt meine Frage:
Wie muss ich nun den Type deklarieren, um zur Laufzeit die Infos zu n Filter abzufragen?
Ein FilterInfo: Array[0..15] of PF_FILTER_STATS; würde mir ja auch nur die Infos der
ersten 16 Filter bringen, der User könnte aber mehr Filter anlegen.

Also schonmal vielen Dank für Eure Antwort(en) ...

scp 19. Jun 2005 14:10

Re: Type-Deklaration PF_INTERFACE_STATS (MSDN-PlattformSDK:
 
Die ursprüngliche Deklaration ist schon OK. Du solltest nur dynamisch mehr Speicher zuweisen, etwa so:
Delphi-Quellcode:
var
  THE_INTERFACE_STATS: PPF_INTERFACE_STATS;
begin
  GetMem(THE_INTERFACE_STATS, SizeOf(PF_INTERFACE_STATS) + 15*SizeOf(PF_FILTER_STATS));
  //...
  FreeMem(THE_INTERFACE_STATS);
end;

marabu 19. Jun 2005 15:34

Re: Type-Deklaration PF_INTERFACE_STATS (MSDN-PlattformSDK:
 
Die Speicherzuordnung sollte zweistufig erfolgen. Beim ersten Aufruf wird BufferSize mit SizeOf(PF_INTERFACE_STATS) initialisiert. Das Ergebnis des Aufrufs ist eine korrekte Initialisierung von Buffersize für den zweiten Aufruf. Der Zugriff auf die einzelnen Filter erfolgt dann einfach über Zeiger-Arithmetik.

Grüße vom marabu

x000x 19. Jun 2005 18:07

Re: Type-Deklaration PF_INTERFACE_STATS (MSDN-PlattformSDK:
 
Zitat:

Zitat von marabu
Die Speicherzuordnung sollte zweistufig erfolgen. Beim einem ersten Aufruf wird BufferSize mit SizeOf(PF_INTERFACE_STATS) initialisiert. Das Ergebnis des Aufrufs ist eine korrekte Initialisierung von Buffersize für den zweiten Aufruf.

Ok, dass hatte ich auch so verstanden. Trotzdem danke :wink:
Delphi-Quellcode:
procedure FltStats;
Type
   TFilter = Array[0..15] of PF_FILTER_STATS;
   PFilter = ^TFilter;
var bufSize : DWord;
    dwResult : DWord;
    ppfStats : PPF_INTERFACE_STATS;
    i       : Integer;
    Filter  : PFilter;
begin
   bufSize := SizeOf(PF_INTERFACE_STATS);
   GetMem(ppfStats, bufSize);
   try
      dwResult := PfGetInterfaceStatistics(hIf, ppfStats, @bufSize, false);
      case dwResult of
         ERROR_INSUFFICIENT_BUFFER :
            begin
               FreeMem(ppfStats);
               GetMem(ppfStats, bufSize);
               dwResult := PfGetInterfaceStatistics(hIf, ppfStats, @bufSize, false);
               if dwResult <> NO_ERROR then
                  Exit;
            end;
         ERROR_INVALID_HANDLE : Exit;
      end;
      Filter := @ppfStats^.filterinfo;
      for i:= 0 to Length(Filter^)-1 do
         ShowMessage( 'Filter (' + IntToStr(Succ(i)) + ')'#13#10 +
                      '  SourcePort: ' + IntToStr(Filter[i].info.wSrcPort) + #13#10+
                      '  DestinationPort: ' + IntToStr(Filter[i].info.wDstPort));
   finally
      FreeMem(ppfStats);
   end;
end;
Hier hab ich eigentlich nichts anderes gemacht, als wie im 1. Posting von mir. Die MessageBox
gibt mir jedenfalls für die Filter die auch existieren, die Korrekten Infos. Mein Problem ist
anscheinend genau das:
Zitat:

Zitat von marabu
Der Zugriff auf die einzelnen Filter erfolgt dann einfach über Zeiger-Arithmetik.

Hat jemand dafür eventuell ein Beispiel? Es reicht eine Zeile, z.B. wie komme ich an die Infos für den 2. Filter?
(Das muss doch auch irgendwie dynamisch gehen, also OHNE das ich vorher ein array mit fester länge definiere?!)

Robert Marquardt 19. Jun 2005 18:20

Re: Type-Deklaration PF_INTERFACE_STATS (MSDN-PlattformSDK:
 
Das ist ein bischen tricky. In C kann man am Ende eines Record ein Array der Laenge Null deklarieren.
Das nimmt dann keinen Platz im Record ein, sondern benennt den Bereich hinter dem Record.
In C liefert dann auch noch der Name eines Arrays den Zeiger auf das erste Element des Arrays.
InterfaceStats.FilterInfo ist also in C ein Zeiger hinter InterfaceStats.
Zeiger in C sind direkt mit dem Arrayindex zu benutzen. Da es keine Checks fuer Arrayzugriffe erfolgen,
kann man einfach die Elemente des FilterInfo-Arrays zugreifen. Wie viele es sind steht im Record.

Microsoft verwendet die Laenge 1 was keinerlei praktische Auswirkungen hat. Es erklaert nur das erste Element des FilterInfo-Arrays zum Teil des Records.

Wenn FilterInfo als array [0..0] deklariert ist, kann man auch in Delphi auf die FilteRInfo-Elemente zugreifen.
Man muss nur den Check der Arraygrenzen abschalten.

marabu 19. Jun 2005 18:34

Re: Type-Deklaration PF_INTERFACE_STATS (MSDN-PlattformSDK:
 
iMaxFilter musst du dir ausrechnen: Angeforderte Gesamtgröße - Größe der Struktur bis zum FilterInfo. Wenn du über Zeigerarithmetik zugreifst, dann spielen die Array-Grenzen keine Rolle.
Delphi-Quellcode:
var
  pf: ^PF_FILTER_INFO;
begin
  for i := 0 to iMaxFilter do begin
    ...
    Inc(pf);
  end;
end;
marabu

x000x 19. Jun 2005 19:42

Re: Type-Deklaration PF_INTERFACE_STATS (MSDN-PlattformSDK:
 
Ok,
dank dem Code-Schnippsel von marabu und der ausführlichen Erklärung von Robert habe ich folgende Lösung:
Delphi-Quellcode:
procedure FltStats;
var bufSize : DWord;
    dwResult : DWord;
    ppfStats : PPF_INTERFACE_STATS;
    i       : Integer;
    Filter  : ^PF_FILTER_STATS;
begin
   bufSize := SizeOf(PF_INTERFACE_STATS);
   GetMem(ppfStats, bufSize);
   try
      dwResult := PfGetInterfaceStatistics(hIf, ppfStats, @bufSize, false);
      case dwResult of
         ERROR_INSUFFICIENT_BUFFER :
            begin
               FreeMem(ppfStats);
               GetMem(ppfStats, bufSize);
               dwResult := PfGetInterfaceStatistics(hIf, ppfStats, @bufSize, false);
               if dwResult <> NO_ERROR then
                  Exit;
            end;
         ERROR_INVALID_HANDLE : Exit;
      end;
      Filter := @ppfStats^.filterinfo;
      for i := 0 to (ppfStats^.dwNumInFilters + ppfStats^.dwNumOutFilters) -1 do begin
         ShowMessage( 'Filter (' + IntToStr(Succ(i)) + ')'#13#10 +
                      '  SourcePort: ' + IntToStr(Integer(Filter^.info.wSrcPort)) + #13#10+
                      '  DestinationPort: ' + IntToStr(Filter^.info.wDstPort));
         Inc(Filter);
      end;
   finally
      FreeMem(ppfStats);
   end;
end;
Sollte oben doch noch was nicht so wirklich OK sein, wäre ich für Hinweise dankbar :)

Meine Frage wurde perfekt beantwortet und ich habe mal wieder ein Stück dazugelernt...

Thx..


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:02 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz