How to get Hostname of each ip address in given input range - delphi

My question is how to get hostnames of all ip addresses which are betwwen given ip range. I know the function for getting hostnames from ip address but I just want to know how to get ip addresses from given range
Example:
input is given in two edixboxes in first '0.0.0.0' and in second '1.1.1.1' so I want all ip addresses between this range ...
I tried my best but it is too complex. Is there any function or command to get ip addresses between given range?
function IPAddrToName(IPAddr: string): string;
var
SockAddrIn: TSockAddrIn;
HostEnt: PHostEnt;
WSAData: TWSAData;
begin
WSAStartup($101, WSAData);
SockAddrIn.sin_addr.s_addr := inet_addr(PChar(IPAddr));
HostEnt := GetHostByAddr(#SockAddrIn.sin_addr.S_addr, 4, AF_INET);
if HostEnt<>nil then
begin
Result := StrPas(Hostent^.h_name)
end
else
begin
Result := '';
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Label1.Caption := IPAddrToName(Edit1.Text);
end;

Use inet_addr to convert the dotted text form of the IP address into an unsigned 32 bit integer. Do that for both addresses. And then loop from one to the other with a simple for loop.
var
ip, ip1, ip2: Cardinal;
....
ip1 := ntohl(inet_addr(PChar(edit1.Text)));
ip2 := ntohl(inet_addr(PChar(edit2.Text)));
for ip := min(ip1,ip2) to max(ip1,ip2) do
// use ip
I skipped any validation. You would not. Note also that inet_addr returns a value with network byte order. For the loop to work we must switch to host byte order.
This only really makes sense for ranges that span an entire subnet mask. For instance it makes sense to enumerate all addresses between 192.168.1.0 and 192.168.1.255. But it makes no sense at all to ask for all addresses between 1.0.0.0 and 1.1.1.1 as per the example in your question.
So I think you'll need to reconsider and think about iterating over all addresses in a network.
You also ask, in comments, how to convert from numeric form to dotted form. Use inet_ntoa for that.
var
addr: in_addr;
dottedAddr: string;
....
addr.S_addr := htonl(ip);
dottedAddr := inet_ntoa(addr);

Generating IP addresses is not that complicated. Just convert range bounds to 4 byte integers and iterate between bounds. Pay special attention to bytes order so integers was correctly converted to IP addreses.

Related

How to find out char code for a character of an Ansistring

In older versions of Delphi, like D7, you could do like ord(s[i]) where s was a string, but trying this with an AnsiString results in an exception (access violation).
P.S. I was w/delphi 7 for a long time.
Here are the steps to reproduce the error:
Create a new project and through a memo on the form (let it be memo1) than add the following code to the form create event handler:
procedure TForm1.FormCreate(Sender: TObject);
var u: ansistring;
begin
u := 'stringtest';
memo1.Lines.Add(inttostr(ord(u[2])));
end;
For me this code produces an AV.
It does work with an ansistring, but you cannot read past the end of it and you must make sure the string is initialized.
function CharCode(const S: ansistring; pos: integer): byte;
begin
if pos <= 0 then result:= 0
//else if s='' then Result:= 0 //unassigned string;
else if Length(s) < Pos then Result:= 0 //cannot read past the end.
else Result:= Ord(s[pos]);
end;
Note that if s='' is the same as asking if pointer(s) = nil. An empty string is really a nil pointer.
This is probably why you where getting an access violation.
If you want to force the ansistring to be a certain length you can use SetLength(MyAnsistring, NewLength);
The length of the (ansi)string is variable. That means it grows and shrinks as needed. If you read past the end of the string you may get an access violation.
Note that you don't have to get an AV, the RTL leaves a bit of slack in its allocation; it usually allocates a slightly bigger buffer than requested, this is due to performance and architectural reasons.
The other reason why you may not get an AV if reading past the end of a string is that your program may own both the string buffer and whatever happens to be right next to it.
For this reason it is a good idea to enable range checking in debug mode {$R+} it adds extra checks to protect against reading past the end of structures.
The difference between shortstring and (ansi)string
A short string has a fixed length and it lives on the stack.
A long string (ansi or wide) is a pointer to a record that gets allocated on the heap; it looks like this:
type
TStringRecord = record
CodePage: word;
ElementSize: word; //(1, 2 or 4)
ReferenceCount: integer;
Length: Integer;
StringData: array[1..length(s)] of char;
NullChar: char;
end;
The compiler hides all these details from you.
see: http://docwiki.embarcadero.com/RADStudio/Seattle/en/Internal_Data_Formats

Detect if string contains a float?

How can I detect if a string contains a float. For example: '0.004'
But without using StrToFloat because that function are slow but rather by iterating through chars.
function IsInteger(const S: String): Boolean;
var
P: PChar;
begin
P := PChar(S);
Result := True;
while not (P^ = #0) do
begin
case P^ of
'0'..'9': Inc(P);
else
Result := False;
Break;
end;
end;
end;
This will check if string is a positive integer but not a float..
I would use TryStrToFloat():
if TryStrToFloat(str, value, FormatSettings) then
....
If you are prepared to use the default system wide format settings then you can omit the final parameter:
if TryStrToFloat(str, value) then
....
Can you use a RegEx here? Something like:
([+-]?[0-9]+(?:\.[0-9]*)?)
The problem with this question is that saying "is too slow" doesn't tell much. What does the profiler tells to you? Do you have an informed idea about the input data? What about different notations, for example, 6.02e23?
If your input data is mostly noise, then using regular expressions (as answered here) may improve things but only as a first filter. You could then add a second step to actually obtain your number, as explained by David's answer.

Machine dependent results for OLE check of MSWord version

With this code to retrieve the version of the installed MS Word:
uses uses oleauto;
[...]
function TForm2.GetWordVersion:string;
const
wdDoNotSaveChanges = 0;
var
WordApp: OLEVariant;
WordVersion: variant;
begin
Try
WordApp := CreateOLEObject('Word.Application');
WordVersion := WordApp.version;
WordApp.Quit(wdDoNotSaveChanges);
except
on E: Exception do
begin
WordVersion := -1;
end;
End;
Result := wordversion;
end;
I get 140 on my machine, my colleague gets 14. Both are win7/Word2010 but I am in Italy he is in India.
Anyone knows about this?
Why different values?
Thanks
I'm guessing this is a decimal separator issue. Word returns the string '14.0' and then when you convert to integer the period is treated as a positional separator on one machine, and a decimal separator on another.
The solution is to stop converting to integer which I infer that you are doing in code that you have not shown.
I am inferring that from this comment:
I can convert it to string and use the first 2 chars.
Since the code in the question operates on strings, I conclude that other code, not shown in the question, is converting to integer.

Get length of record field of type array

I'm writing a wrapper for communication with an external binary API. The API uses PDUs (packed binary records) for communication. Strings are arrays of AnsiChar and are zero-terminated:
type
TSomePDU = packed record
//...
StringField: array[0..XYZ] of AnsiChar;
//...
end;
PSomePDU = ^TSomePDU;
I want to write a FillPDUString procedure that would accept a String and fill the char array, but I want to avoid keeping track of MaxLength wherever the procedure is used, so I need somehow to get the declared array size given a pointer to the field:
function GetMaxSize(const Field: array of AnsiChar): Integer;
begin
// ???
end;
//...
GetMaxSize(ARecord.StringField);
Is this possible?
If I understand you correctly, then you can use Delphi's Length function
Here's how to get the length:
function GetMaxSize(const Value: PSomePDU): Integer;
begin
Result := Length(Value.StringField);
end;
To obtain the number of elements that an array contains, use Length.
ElementCount := Length(ARecord.StringField);
Use low and high to obtain the bounds of any Delphi array.
MinIndex := low(ARecord.StringField);
MaxIndex := high(ARecord.StringField);
Using the latter approach, with low and high, allows you to avoid assuming that an array is 0-based.

What is the meaning of the internet connection statuses?

What is the meaning of the internet connection statuses?
I can't figure out which status represents a router, number 3?
What does 4 mean?
uses
WinInet;
const
MODEM = 1;
LAN = 2;
PROXY = 4;
BUSY = 8;
function GetConnectionKind(var strKind: string): Boolean;
var
flags: DWORD;
begin
strKind := '';
Result := InternetGetConnectedState(#flags, 0);
if Result then
begin
if (flags and MODEM) = MODEM then strKind := 'Modem';
if (flags and LAN) = LAN then strKind := 'LAN';
if (flags and PROXY) = PROXY then strKind := 'Proxy';
if (flags and BUSY) = BUSY then strKind := 'Modem Busy';
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
strKind: string;
begin
if GetConnectionKind(strKind) then
ShowMessage(strKind);
end;
[InternetGetConnectedState](http://msdn.microsoft.com/en-us/library/aa384702(VS.85%29.aspx) returns a bitmask in the first parameter that looks like this:
76543210 <-- bit numbers
|| ||||
|| |||+- INTERNET_CONNECTION_MODEM
|| ||+-- INTERNET_CONNECTION_LAN
|| |+--- INTERNET_CONNECTION_PROXY
|| +---- INTERNET_CONNECTION_MODEM_BUSY (No longer used)
|+------ INTERNET_CONNECTION_OFFLINE
+------- INTERNET_CONNECTION_CONFIGURED
If a given bit is set, the connection is of that type. So if bit nr. 2 is set, you're connected through a proxy.
Additionally, the function returns a TRUE/FALSE value, indicating whether you are connected to the internet.
The values you have in your code, 1, 2, 4, 8, corresponds to the decimal value of those bits, counting from the right.
Basically the code inspects each bit in turn, and sets the strKind variable to a text indicating the nature of the connection.
You're asking "which is router? 3?", and I assume you mean by that "how do I figure out that my connection is through a router?". I would assume this would be the same as the LAN connection, presumably the LAN has a bridge somewhere to access the internet through.
The codes 1, 2, 4, 8 represent bitmasks. I generally prefer to always use bitmasks in hex to avoid any confusion, its fairly easy to remember since the pattern continues in nibbles (the set of 4 binary bits).
HEX BINARY DEC
$01 00000001 1
$02 00000010 2
$04 00000100 4
$08 00001000 8
$10 00010000 16
$20 00100000 32
$40 01000000 64
$80 10000000 128
If you ever want to check two values at once, you can OR them together, for example $01 or $02 = $03 (binary 00000011). So a 3 would be BOTH a modem AND a lan.
A common practice to see if something is set or not, would be to AND it with the mask. for example, if my number is 3, and i "and" this with $02, then the result is $02 since the bit for both the mask AND the value were both set. If my number is 4 and I "and" this with $02, then the result is $00 since the bit for both the mask and the value were not set.
Of course this doesn't answer what I think your real question is. The router would be impossible to determine just by checking only this mask. This mask just tells you if your connected via a modem (aka Dialup) or a network adapter. The router would be beyond the network adapter, and would require further analysis of the network to accurately determine.
The constant values are flags which means two things: (1) you cannot have a "3" value and (2) you can have more than one value in the "flags" result. For example, for result 9 (1001 in binary) the first and last checks would be true.
For more info on the result meaning check the MSDN reference for InternetGetConnectedState.

Resources