如何在 Pascal 中获取 IP 地址

How to get IP address in Pascal

我在尝试查看 IP 地址并在消息框中显示时遇到这两个错误

错误看起来像这样

[dcc32 Error] Unit1.pas(38): E2010 Incompatible types: 'PAnsiChar' and 'PWideChar' => Error1

[dcc32 Error] Unit1.pas(40): E2010 Incompatible types: 'string' and 'array[1..1024] of Byte' => Error2

我可以在 C/C++ 中做到这一点,但我想在 Delphi

中尝试一些新的东西

我的源代码是这样的

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Wininet, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
  var
    hInet: HINTERNET;
    hFile: HINTERNET;
    buffer: array[1..1024] of byte;
    bytesRead: DWORD;
    url : String;

begin
  url := 'https://icanhazip.com';
  hInet := InternetOpen(PChar(application.title),INTERNET_OPEN_TYPE_PRECONFIG,nil,nil,0);
  hFile := InternetOpenUrlA(hInet, PChar(url), nil, 0, 0, 0); //Error 1
  InternetReadFile(hFile,@buffer,SizeOf(buffer),bytesRead); // Error 2
  showmessage(buffer);

end;

end.

请问我做错了什么?

编辑

好的,InternetOpenUrl 成功了,但是,它仍然在 showmessage(buffer)

上给我错误

代码现在看起来像这样

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Wininet, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
  var
    hInet: HINTERNET;
    hFile: HINTERNET;
    buffer: array[1..1024] of byte;
    bytesRead: DWORD;
    url : String;

begin
  url := 'https://icanhazip.com';
  hInet := InternetOpen(PChar(application.title),INTERNET_OPEN_TYPE_PRECONFIG,nil,nil,0);
  hFile := InternetOpenUrl(hInet, PChar(url), nil, 0, 0, 0);
  InternetReadFile(hFile,@buffer,SizeOf(buffer),bytesRead);
  showmessage(buffer);

end;

end.

编辑2

我的代码现在看起来像这样

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Wininet, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
  var
    hInet: HINTERNET;
    hFile: HINTERNET;
    buffer: String;
    bytesRead: DWORD;
    url : String;
    szMessage : String;
    i : integer;


begin
  //url := 'https://icanhazip.com';
  hInet := InternetOpen(PChar(application.title),INTERNET_OPEN_TYPE_PRECONFIG,nil,nil,0);
  hFile := InternetOpenUrl(hInet, PChar('https://icanhazip.com'), nil, 0, 0, 0);
  InternetReadFile(hFile,@buffer,SizeOf(buffer),bytesRead);

  //showmessage(buffer);
  Label1.Caption := buffer;

end;

end.

第一个错误发生是因为您调用了函数的 AnsiChar 版本。

使用 InternetOpenUrl 代替 InternetOpenUrlA

第二个发生在您预期的下面一行。 ShowMessage 需要 string 而不是 array of byte

编辑: 要从要传递给 ShowMessage 的字节数组中获取字符串,您需要知道发送字节的编码。假设是 UTF-8,转换可以简单地完成:

ShowMessage(TEncoding.UTF8.GetString(Slice(buffer, bytesRead)))

编辑 2: 好的,对于 XE8,您需要做更多的工作。

procedure TForm1.Button1Click(Sender: TObject);
  var
    hInet: HINTERNET;
    hFile: HINTERNET;
    buffer: TBytes;
    bytesRead: DWORD;
    url : String;

begin
  url := 'https://icanhazip.com';
  hInet := InternetOpen(PChar(application.title),INTERNET_OPEN_TYPE_PRECONFIG,nil,nil,0);
  hFile := InternetOpenUrl(hInet, PChar(url), nil, 0, 0, 0);
  SetLength(buffer, 1024);
  InternetReadFile(hFile,@buffer[0],Length(buffer),bytesRead);
  showmessage(TEncoding.UTF8.GetString(buffer, 0, bytesRead));    
end;

在 C/C++ 中,您通常使用以 NUL 结尾的字符串 - 并自己分配存储空间来保存该字符串。这就是您在代码中使用 BYTE 数组所做的。

在 Delphi 中,string 是原生类型,而不仅仅是指向 NUL 终止字符数据的指针。

根据您提供的错误消息,错误发生在调用 ShowMessage 时,而不是调用 InternetReadFile 时。

您需要将字符串变量传递给 ShowMessage。

你可以试试这个:

var
  szMessage: String;
  i: Integer;

  SetLength(szMessage, bytesread);
  for i =1 to bytesread do
    szMessage[i]:=buffer[i-1];
  ShowMessage(szMessage);

有一些方法可以更紧凑地完成此操作,但作为最近从 C++ 转向主要使用 Delphi 的人,我认为以这种方式查看操作有助于理解两种语言之间的差异.