Lazarus

Programming => General => Topic started by: shonay on June 20, 2019, 05:06:00 pm

Title: Get IP address in Lazarus Pascal
Post by: shonay on June 20, 2019, 05:06:00 pm
HI i want to ask u a question ,

Hw do i get the IP address in Pascal , i followed this http://www.cplusplus.com/forum/windows/57900/

Now my code looks like this below :

Code: Pascal  [Select]
  1. function myIPAddress() : String ;
  2. var
  3.    pSession    : HINTERNET;
  4.    hFile       : HINTERNET;
  5.    Size: DWORD;
  6.    buffer: array[1..1024] of byte;
  7.    bytesRead: DWORD;
  8. begin
  9.      pSession := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  10.      hFile := InternetOpenUrlA(pSession,'https://bitinvestor1987.000webhostapp.com/checkip.php',nil,0,INTERNET_FLAG_RELOAD,0);
  11.      InternetReadFile(hFile,@buffer,SizeOf(buffer),bytesRead);
  12.      buffer[Size];
  13. end;
  14.  

What did i Miss
Title: Re: Get IP address in Lazarus Pascal
Post by: Thaddy on June 20, 2019, 05:35:28 pm
If it is your exposed ip you can simply use ip.thaddy.com which returns a string, not a full html page. Up since ~2000.
The response can be used immediately as a Pascal Ansistring.

I have more options, including redirects.

Using the wininet api is not a very good idea.
Title: Re: Get IP address in Lazarus Pascal
Post by: shonay on June 20, 2019, 05:38:17 pm
yea same same

Shows error around this area : buffer[Size];
Title: Re: Get IP address in Lazarus Pascal
Post by: Thaddy on June 20, 2019, 05:40:33 pm
Then you have to show some more code. You made mistakes.
(E.g. count from zero not one....)
Title: Re: Get IP address in Lazarus Pascal
Post by: shonay on June 20, 2019, 05:45:55 pm
Full code looks like this  :


Code: Pascal  [Select]
  1.  
  2. program computername;
  3.  
  4. {$mode objfpc}{$H+}
  5.  
  6. uses
  7.   {$IFDEF UNIX}{$IFDEF UseCThreads}
  8.   cthreads,
  9.   {$ENDIF}{$ENDIF}
  10.   Classes , Windows , Wininet
  11.   { you can add units after this };
  12.  
  13. //http://www.delphibasics.info/home/delphibasicssnippets/getcomputername
  14.  
  15. function myComputerName():String;
  16. var
  17. ComputerName: Array [0 .. 256] of char;
  18. Size: DWORD;
  19. begin
  20.      Size := 256;
  21.      GetComputerName(ComputerName, Size);
  22.      Result := ComputerName;
  23. end;
  24.  
  25. function myIPAddress() : String ;
  26. var
  27.    pSession    : HINTERNET;
  28.    hFile       : HINTERNET;
  29.    Size: DWORD;
  30.    buffer: array[1..1024] of byte;
  31.    bytesRead: DWORD;
  32. begin
  33.      pSession := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  34.      hFile := InternetOpenUrlA(pSession,'http://ip.thaddy.com/',nil,0,INTERNET_FLAG_RELOAD,0);
  35.      InternetReadFile(hFile,@buffer,SizeOf(buffer),bytesRead);
  36.      buffer[Size];
  37. end;
  38.  
  39. begin
  40.      Writeln('My computers name is : ',myComputerName());
  41.      Writeln('My computers IP is  : ',myIPAddress());
  42.      ReadLn();
  43. end.
  44.  
  45.  
Title: Re: Get IP address in Lazarus Pascal
Post by: rvk on June 20, 2019, 05:46:19 pm
What did i Miss
The original code says this:
Code: [Select]
buffer[rSize] = '\0';You just did:
Code: Pascal  [Select]
  1. buffer[Size];

Didn't you get an error on that line ????
ALWAYS show errors you get.

And you don't put the buffer into result.

You could do something like this:
Code: Pascal  [Select]
  1. function myIPAddress(): string;
  2. var
  3.   pSession: HINTERNET;
  4.   hFile: HINTERNET;
  5.   buffer: array[0..1023] of char; // make this an char-array
  6.   bytesRead: DWORD;
  7. begin
  8.   Result := 'error';
  9.   pSession := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  10.   hFile := InternetOpenUrlA(pSession, 'http://ip.thaddy.com/', nil, 0, INTERNET_FLAG_RELOAD, 0);
  11.   if InternetReadFile(hFile, @buffer, SizeOf(buffer), bytesRead) then // don't forget to check for error
  12.   begin
  13.     buffer[bytesRead] := #0; // set the last char in the string to #0
  14.     Result := Buffer; // put the buffer in result
  15.   end;
  16. end;

Although I would do it something like this:
Code: Pascal  [Select]
  1. function myIPAddress: string;
  2. var
  3.   pSession: HINTERNET;
  4.   hFile: HINTERNET;
  5.   bytesRead: DWORD;
  6.   TempIP: string;
  7. begin
  8.   Result := 'error';
  9.   SetLength(TempIP, 1024);
  10.   pSession := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  11.   hFile := InternetOpenUrlA(pSession, 'http://ip.thaddy.com/', nil, 0, INTERNET_FLAG_RELOAD, 0);
  12.   if InternetReadFile(hFile, PChar(TempIP), 1024, bytesRead) then
  13.   begin
  14.     SetLength(TempIP, bytesRead);
  15.     Result := TempIP;
  16.   end;
  17. end;

Also... you can search the forum for some better versions.
Title: Re: Get IP address in Lazarus Pascal
Post by: Thaddy on June 20, 2019, 05:51:03 pm
Rik, you have more patience than I have, thank you!
Title: Re: Get IP address in Lazarus Pascal
Post by: shonay on June 20, 2019, 06:00:53 pm
Thanks everyone its fine now. :)
Title: Re: Get IP address in Lazarus Pascal
Post by: Remy Lebeau on June 21, 2019, 08:51:19 pm
Code: [Select]
  buffer: array[0..1023] of char; // make this an char-array

That is a bit of wasted space, considering an IPv4 address is 15 chars max, and an IPv6 address is 39 chars max.  Also, I would use AnsiChar instead of Char, since the website actually sends ASCII text, and also to avoid breaking the code in the future if Char is ever set to WideChar (via {$ModeSwitch UNICODESTRINGS} or {$Mode DelphiUnicode}).

Code: [Select]
    buffer[bytesRead] := #0; // set the last char in the string to #0
    Result := Buffer; // put the buffer in result

I wouldn't even bother with the null terminator, I would use SetString() instead.

And don't forget about cleanup to avoid resource leaks!

Code: Pascal  [Select]
  1. function myIPAddress(): string;
  2. var
  3.   pSession: HINTERNET;
  4.   hFile: HINTERNET;
  5.   buffer: array[0..45] of AnsiChar;
  6.   bytesRead: DWORD;
  7.   myIP: AnsiString;
  8. begin
  9.   Result := 'error';
  10.   pSession := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  11.   if pSession = 0 then Exit;
  12.   try
  13.     hFile := InternetOpenUrlA(pSession, 'http://ip.thaddy.com/', nil, 0, INTERNET_FLAG_RELOAD, 0);
  14.     if hFile = 0 then Exit;
  15.     try
  16.       if InternetReadFile(hFile, @buffer, SizeOf(buffer), bytesRead) then
  17.       begin
  18.         SetString(myIP, buffer, bytesRead);
  19.         Result := string(myIP);
  20.       end;
  21.     finally
  22.       InternetCloseHandle(hFile);
  23.     end;
  24.   finally
  25.     InternetCloseHandle(pSession);
  26.   end;
  27. end;
  28. [code]
Title: Re: Get IP address in Lazarus Pascal
Post by: rvk on June 21, 2019, 09:27:57 pm
Code: [Select]
  buffer: array[0..1023] of char; // make this an char-array

That is a bit of wasted space, considering an IPv4 address is 15 chars max, and an IPv6 address is 39 chars max.  Also, I would use AnsiChar instead of Char, since the website actually sends ASCII text, and also to avoid breaking the code in the future if Char is ever set to WideChar (via {$ModeSwitch UNICODESTRINGS} or {$Mode DelphiUnicode}).

Code: [Select]
    buffer[bytesRead] := #0; // set the last char in the string to #0
    Result := Buffer; // put the buffer in result

I wouldn't even bother with the null terminator, I would use SetString() instead.
Yeah, that wasn't my code. TS asked about translating C++ cide wich used 1024 bytes array and put a null as terminator in the array. So I just showed how to translate.

My code used a string with setlength to reserve bytes before calling InternetReadFile.

And indeed, cleanup was not done correctly in the given code.

Also the reason I mentioned some better alternatives which can also be found here on the forum. Your code can now be counted among them  8-)