Rilevare IP (Delphi XE)

di MrCamarium il
13 risposte
Per conoscere l'IP assegnato in rete usavo questo codice che giravo sotto Delphi 7:
function getIPs: Tstrings;
type
  TaPInAddr = array[0..10] of PInAddr;
  PaPInAddr = ^TaPInAddr;
var
  phe: PHostEnt;
  pptr: PaPInAddr;
  Buffer: array[0..63] of Char;
  I: Integer;
  GInitData: TWSAData;
begin
  WSAStartup($101, GInitData);
  Result := TstringList.Create;
  Result.Clear;
  GetHostName(Buffer, SizeOf(Buffer));
  phe := GetHostByName(buffer);
  if phe = nil then Exit;
  pPtr := PaPInAddr(phe^.h_addr_list);
  I    := 0;
  while pPtr^[I] <> nil do
  begin
    Result.Add(inet_ntoa(pptr^[I]^));
    Inc(I);
  end;
  WSACleanup;
end;
adesso che uso Delphi XE mi da questo errore:
[DCC Error] ip_mio.pas(41): E2010 Incompatible types: 'PAnsiChar' and 'array[0..63] of Char'

13 Risposte

  • MrCamarium ha scritto:


    Per conoscere l'IP assegnato in rete usavo questo codice che giravo sotto Delphi 7 [...]
    adesso che uso Delphi XE mi da questo errore:
    [DCC Error] ip_mio.pas(41): E2010 Incompatible types: 'PAnsiChar' and 'array[0..63] of Char'
    A partire da Delphi 2009, le stringhe non sono più ANSI bensì Unicode!

    Ne consegue che nell'invocazione di determinate API sarebbe meglio utilizzarne la versione compatibile con questo standard, mentre per le API che utilizzano ancora lo standard di decodifica ANSI, occorre usare il tipo giusto di stringhe e di caratteri.

    Se vuoi approfondire l'argomento, c'è un white paper che spiega tutto ciò che va conosciuto.

    Nel caso in esame qui, credo basti dichiarare l'array così:
    array[0..63] of AnsiChar


    Ciao!
  • Grazie sei sempre molto gentile!
    Ho fatto la dovuta modifica ma mi da un errore di incompatibilità a questa riga:
    while pPtr^[I] <> nil do
    l'errore è:
    [DCC Error] ip_mio.pas(46): E2008 Incompatible types
  • Se non ricordo male la libreria Indy ha già qualcosa che con il minimo sforzo riesce a darti IP del client dove lavori, in questo modo ti liberi dalle varie API e lasci il lavoro sporco alla libreria.
    Nick.
  • Se sei in una rete, tipo a casa dietro un router, credo che si riesca a vedere solo l'IP locale però.
  • Nicola ha scritto:


    Se non ricordo male la libreria Indy ha già qualcosa che con il minimo sforzo riesce a darti IP del client dove lavori, in questo modo ti liberi dalle varie API e lasci il lavoro sporco alla libreria.
    Nick.
    Si è vero con questo codice.
    procedure TForm1.FormCreate(Sender: TObject);
    var
      ids: TidIpWatch;
    begin
     ids := TidIpWatch.Create;
     Label2.Caption := 'IP:' + ids.LocalIP;
     ids.Free;
    end;
    Ma come dicevi tu da solo l'IP locale.
  • Cercherò un'altra soluzione per avere L'IP pubblico ma mi piacerebbe far funzionare questo codice:
    function getIPs: Tstrings;
    type
      TaPInAddr = array[0..63] of AnsiChar;
      PaPInAddr = ^TaPInAddr;
    var
      phe: PHostEnt;
      pptr: PaPInAddr;
      Buffer: array[0..63] of AnsiChar;
      I: Integer;
      GInitData: TWSAData;
    begin
      WSAStartup($101, GInitData);
      Result := TstringList.Create;
      Result.Clear;
      GetHostName(Buffer, SizeOf(Buffer));
      phe := GetHostByName(buffer);
      if phe = nil then Exit;
      pPtr := PaPInAddr(phe^.h_addr_list);
      I    := 0;
      while pPtr^[I] <> nil do
      begin
        Result.Add(inet_ntoa(pptr^[I]^));
        Inc(I);
      end;
      WSACleanup;
    end;
    Al momento mi da questo errore:
    [DCC Error] ip_mio.pas(46): E2008 Incompatible types
  • MrCamarium ha scritto:


    Al momento mi da questo errore:
    [DCC Error] ip_mio.pas(46): E2008 Incompatible types
    Hai provato a verificare di che tipo sono quelle variabili?
    Hai provato a cercare documentazione su ciò che fa la funzione e quali parametri si aspetta?
    Hai provato a capire quello che fa il codice in quel frangente e a cosa servono le istruzioni?

    Alzare le mani a ogni errore senza approfondire un minimo vuole dire di fatto delegare ad altri l'analisi del problema, le ricerche annesse e connesse, la formulazione di una soluzione.

    Siamo qui a dare una mano, non a fare consulenza.
  • MrCamarium ha scritto:


    
    function getIPs: Tstrings;
    type
      TaPInAddr = array[0..63] of AnsiChar;
      PaPInAddr = ^TaPInAddr;
    var
      phe: PHostEnt;
      pptr: PaPInAddr;
      Buffer: array[0..63] of AnsiChar;
      I: Integer;
      GInitData: TWSAData;
    begin
      WSAStartup($101, GInitData);
      Result := TstringList.Create;
      Result.Clear;
      GetHostName(Buffer, SizeOf(Buffer));
      phe := GetHostByName(buffer);
      if phe = nil then Exit;
      pPtr := PaPInAddr(phe^.h_addr_list);
      I    := 0;
      while pPtr^[I] <> nil do
      begin
        Result.Add(inet_ntoa(pptr^[I]^));
        Inc(I);
      end;
      WSACleanup;
    end;
    Al momento mi da questo errore:
    [DCC Error] ip_mio.pas(46): E2008 Incompatible types
    Così ad occhio l'errore è all'inizio del ciclo While, dove cerchi di ciclare dentro un puntatore di un puntatore ad un array di char, dunque il "Nil" non va bene, un "Null" dovrebbe risolvere il tuo errore, ma questo è solo l'inizio, credo che quel quadruplo puntatore nel result.add ti farà impazzire ... e non poco.... cmq la soluzione è cambiare la dichiarazione in pptr: TInAddr, poi io personalmente cambierei anche buffer da 63 a 255.

    PS: Spero di non aver scritto qualche cavolata, appena ho tempo accendo il pc e provo....
    Un saluto
    Nick
  • Grazie del tuo intervento. Apportando le modifiche da te suggerite sulla riga:
    Result.Add(inet_ntoa(pptr^[I]^));
    mi da questo errore:
    [DCC Error] ip_mio.pas(48): E2017 Pointer type required
  • Io uso questa per l'IP della macchina, per quello esterno devi interrogare un sito che ti restituisce il tuo indirizzo verso l'esterno:
     Function GetIPAddress : String;
         type pu_long     = ^u_long;
          var varTWSAData : TWSAData;
              varPHostEnt : PHostEnt;
              varTInAddr  : TInAddr;
              namebuf     : Array[0..255] of ansichar;
        begin
              If WSAStartup($101,varTWSAData) <> 0
                 Then Begin
                      Result := '';
                      End
                 Else Begin
                      gethostname(namebuf,sizeof(namebuf));
                      varPHostEnt := gethostbyname(namebuf);
                      varTInAddr.S_addr := u_long(pu_long(varPHostEnt^.h_addr_list^)^);
                      Result := inet_ntoa(varTInAddr);
                      End;
              WSACleanup;
        end;
  • Perfetto grazie, rispetto al codice che avevo questo è più semplice e funzionale.
  • MrCamarium ha scritto:


    Perfetto grazie, rispetto al codice che avevo questo è più semplice e funzionale.
    mmm Non vorrei dire una cavolata, ma a me sembra lo stesso, senza lista e con le chiamate giuste....
    Nick.
  • Eh sì
Devi accedere o registrarti per scrivere nel forum
13 risposte